载入中...
搜索中...
未找到
Graphics.h
浏览该文件的文档.
1#pragma once
2#include <array>
3#include <atomic>
4#include <cstdint>
5#include <glm/ext/vector_uint4_sized.hpp>
6#include <glm/mat4x4.hpp>
7#include <glm/vec2.hpp>
8#include <glm/vec3.hpp>
9#include <glm/vec4.hpp>
10#include <map>
11#include <memory>
12#include <optional>
13#include <unordered_map>
14#include <vector>
15#include "common/Capability.h"
16#include "common/Export.h"
17#include "common/GpuTimer.h"
18#include "graphics/Batcher.h"
20#include "graphics/Graphics.h"
21#include "graphics/Light.h"
22#include "graphics/Mesh.h"
23#include "graphics/PbrSurface.h"
26#include "graphics/Shader.h"
27#include "graphics/Shadow.h"
28#include "graphics/Texture.h"
32#include "vkbuilder.hpp"
33#include "vkbuilder/framegraph.hpp"
34
35namespace eve::graphics::vulkan {
36
37class OffscreenCanvas;
38
39#if defined(VKB_ENABLE_VMA)
41class VmaAllocatorOwner {
42public:
44 VmaAllocatorOwner() = default;
46 ~VmaAllocatorOwner();
47 VmaAllocatorOwner(const VmaAllocatorOwner &) = delete;
48 VmaAllocatorOwner &operator=(const VmaAllocatorOwner &) = delete;
49
51 void create(const vkb::Instance &instance, const vkb::PhysicalDevice &physicalDevice,
52 vkb::Device &device);
53
54private:
55 VmaAllocator allocator_ = VK_NULL_HANDLE;
56};
57#endif
58
61 glm::vec2 pos;
62 glm::vec4 color;
63
65 static vk::VertexInputBindingDescription getBindingDescription(uint32_t binding) {
66 vk::VertexInputBindingDescription b{};
67 b.binding = binding;
68 b.stride = sizeof(ColorVertex);
69 b.inputRate = vk::VertexInputRate::eVertex;
70 return b;
71 }
73 static std::vector<vk::VertexInputAttributeDescription> getAttributeDescription(uint32_t binding) {
74 return {
75 {0, binding, vk::Format::eR32G32Sfloat, offsetof(ColorVertex, pos)},
76 {1, binding, vk::Format::eR32G32B32A32Sfloat, offsetof(ColorVertex, color)},
77 };
78 }
79};
80
83 glm::vec4 clipPosition;
84 glm::vec4 color;
85
87 static vk::VertexInputBindingDescription getBindingDescription(uint32_t binding) {
88 return {binding, sizeof(Primitive3DVertex), vk::VertexInputRate::eVertex};
89 }
91 static std::vector<vk::VertexInputAttributeDescription> getAttributeDescription(uint32_t binding) {
92 return {{0, binding, vk::Format::eR32G32B32A32Sfloat, offsetof(Primitive3DVertex, clipPosition)},
93 {1, binding, vk::Format::eR32G32B32A32Sfloat, offsetof(Primitive3DVertex, color)}};
94 }
95};
96
99 glm::vec2 pos;
100 glm::vec4 color;
101 glm::vec2 uv;
102
104 static vk::VertexInputBindingDescription getBindingDescription(uint32_t binding) {
105 vk::VertexInputBindingDescription b{};
106 b.binding = binding;
107 b.stride = sizeof(TexturedVertex);
108 b.inputRate = vk::VertexInputRate::eVertex;
109 return b;
110 }
112 static std::vector<vk::VertexInputAttributeDescription> getAttributeDescription(uint32_t binding) {
113 return {
114 {0, binding, vk::Format::eR32G32Sfloat, offsetof(TexturedVertex, pos)},
115 {1, binding, vk::Format::eR32G32B32A32Sfloat, offsetof(TexturedVertex, color)},
116 {2, binding, vk::Format::eR32G32Sfloat, offsetof(TexturedVertex, uv)},
117 };
118 }
119};
120
123 Texture *texture = nullptr;
124 float x = 0.f;
125 float y = 0.f;
126 float w = 0.f;
127 float h = 0.f;
128 float u0 = 0.f;
129 float v0 = 0.f;
130 float u1 = 1.f;
131 float v1 = 1.f;
132 Color tint{1.f, 1.f, 1.f, 1.f};
133 float clipX = 0.f;
134 float clipY = 0.f;
135 float clipW = 0.f;
136 float clipH = 0.f;
137 bool opaque = false;
138};
139
142 glm::vec3 pos;
143 glm::vec3 normal;
144 glm::vec2 uv;
145 glm::u16vec4 joints{0};
146 glm::vec4 weights{0.f};
147 glm::vec4 color{1.f};
148 // Optional imported tangent basis; w=0 explicitly denotes an absent stream.
149 glm::vec4 tangent{0.f};
150
152 static vk::VertexInputBindingDescription getBindingDescription(uint32_t binding) {
153 vk::VertexInputBindingDescription b{};
154 b.binding = binding;
155 b.stride = sizeof(MeshVertex);
156 b.inputRate = vk::VertexInputRate::eVertex;
157 return b;
158 }
160 static std::vector<vk::VertexInputAttributeDescription> getAttributeDescription(uint32_t binding) {
161 return {
162 {0, binding, vk::Format::eR32G32B32Sfloat, offsetof(MeshVertex, pos)},
163 {1, binding, vk::Format::eR32G32B32Sfloat, offsetof(MeshVertex, normal)},
164 {2, binding, vk::Format::eR32G32Sfloat, offsetof(MeshVertex, uv)},
165 {3, binding, vk::Format::eR16G16B16A16Uint, offsetof(MeshVertex, joints)},
166 {4, binding, vk::Format::eR32G32B32A32Sfloat, offsetof(MeshVertex, weights)},
167 {5, binding, vk::Format::eR32G32B32A32Sfloat, offsetof(MeshVertex, color)},
168 {6, binding, vk::Format::eR32G32B32A32Sfloat, offsetof(MeshVertex, tangent)},
169 };
170 }
171};
172
174struct Mesh3DUBO {
175 // Layout prefix matches legacy custom Mesh3D shaders (toon etc.).
176 glm::mat4 mvp{1.f};
177 glm::mat4 model{1.f};
178 glm::vec4 lightDir{0.4f, 1.f, 0.3f, 0.f}; // xyz = primary dir; w = lightCount
179 glm::vec4 lightColor{1.f, 1.f, 1.f, 0.f}; // rgb = primary color; w = envIntensity (IBL)
180 glm::vec4 tint{1.f, 1.f, 1.f, 1.f};
181 glm::vec4 cameraPos{0.f, 0.f, 3.f, 0.45f}; // xyz = eye; w = roughness
182 glm::vec4 ambient{0.12f, 0.12f, 0.14f, 0.f}; // rgb = ambient; w = metallic
184 // Appended: custom shaders that only read the prefix stay valid (buffer may be larger).
185 glm::vec4 texBomb{4.f, 0.f, 1.f, 0.f}; // x=cellScale, y=strength (0=off), z=rotAmount
186 glm::vec4 parallax{0.f, 8.f, 32.f, 0.f}; // x=scale (0=off), y=minLayers, z=maxLayers
187 glm::mat4 view{1.f}; // camera view (CSM / view-space depth)
188 glm::vec4 clipInfo{0.1f, 100.f, 0.f, 0.f}; // x=near, y=far (linear depth in scene color A)
189 // Dynamic cloud shadows on ground. cloud.x=strength (0=off), y=world cell size,
190 // z=time, w=unused; cloudWind.xy=wind velocity (world/s), z=coverage, w=detail.
191 glm::vec4 cloud{0.f, 1.5f, 0.f, 0.f};
192 glm::vec4 cloudWind{4.f, 0.f, 0.55f, 0.5f};
193 glm::vec4 virtualTexture{0.f}; // enabled, pageCountX, pageCountY, border/extent
194 glm::vec4 virtualAtlas{0.f}; // slotsX, slotsY
195 // GPU-driven only: x = bindless env cubemap slot, y = envIntensity.
196 // Appended after the legacy prefix so legacy shaders are unaffected.
197 glm::vec4 bindlessEnv{0.f, 0.f, 0.f, 0.f};
198 glm::vec4 envProbeCenter{0.f};
199 glm::vec4 envProbeExtent{0.f};
200 glm::vec4 skinInfo{0.f};
203 glm::vec4 diffuseProbeSh[9]{};
204 glm::vec4 diffuseProbeInfo{0.f}; // x = enabled
208 glm::vec4 diffuseVolumeInfo{0.f}; // x = probe count
209 glm::vec4 lodFade{1.f, 0.f, 0.f, 0.f}; // coverage, complementary pattern, enabled
210};
211
214 glm::mat4 mvp{1.f};
215 glm::mat4 model{1.f};
216 glm::vec4 clip{0.f};
217 glm::vec4 skinInfo{0.f};
218};
219static_assert(sizeof(SkinPassUBO) == 160, "SkinPassUBO must match std140 shaders");
220
223 glm::mat4 invViewProj{1.f};
224 glm::mat4 view{1.f};
225 glm::vec4 lightDir{0.4f, 1.f, 0.3f, 0.f};
226 glm::vec4 lightColor{1.f, 1.f, 1.f, 0.f};
227 glm::vec4 cameraPos{0.f, 0.f, 3.f, 0.f};
228 glm::vec4 ambient{0.12f, 0.12f, 0.14f, 0.f};
229 glm::vec4 gridInfo{16.f, 9.f, 24.f, 0.f};
230 glm::vec4 clipInfo{0.1f, 100.f, 1.f, 1.f};
231};
232static_assert(sizeof(DeferredLightingUBO) == 224, "DeferredLightingUBO must match std140 shader");
233
236 glm::mat4 mvp{1.f};
237 glm::mat4 model{1.f};
238 glm::mat4 view{1.f};
239 glm::vec4 lightDir{0.4f, 1.f, 0.3f, 0.f};
240 glm::vec4 lightColor{1.f, 1.f, 1.f, 0.f}; // rgb = primary; w = envIntensity
241 glm::vec4 tint{1.f, 1.f, 1.f, 1.f};
242 glm::vec4 cameraPos{0.f, 0.f, 3.f, 0.45f};
243 glm::vec4 ambient{0.12f, 0.12f, 0.14f, 0.f};
244 glm::vec4 gridInfo{16.f, 9.f, 24.f, 0.f};
245 glm::vec4 clipInfo{0.1f, 100.f, 1.f, 1.f};
246 glm::vec4 texBomb{4.f, 0.f, 1.f, 0.f}; // x=cellScale, y=strength (0=off), z=rotAmount
247 glm::vec4 parallax{0.f, 8.f, 32.f, 0.f}; // x=scale (0=off), y=minLayers, z=maxLayers
248 glm::vec4 virtualTexture{0.f};
249 glm::vec4 virtualAtlas{0.f};
250 glm::vec4 envProbeCenter{0.f};
251 glm::vec4 envProbeExtent{0.f};
254};
255
258 vkb::TextureImage2D image;
259 vkb::GenericImage arrayImage;
260 vkb::TextureImageCube cubeImage;
261 bool isCube = false;
262 bool isArray = false;
263 bool isVolume = false;
264 bool isHDR = false;
265 vk::UniqueDeviceMemory rawCubeMemory;
266 vk::UniqueImage rawCubeImage;
267 vk::UniqueImageView rawCubeView;
268 vk::Sampler sampler;
269 vkb::BoundSet descriptorSet;
270 vk::ImageView viewOverride{};
271 int width = 0;
272 int height = 0;
273 uint32_t mipLevels = 1;
278
280 vk::ImageView imageView() const {
281 if (viewOverride) return viewOverride;
282 if (rawCubeView) return *rawCubeView;
283 if (isArray || isVolume) return arrayImage.imageView();
284 return isCube ? cubeImage.imageView() : image.imageView();
285 }
286};
287
289struct GpuMesh {
294 static constexpr size_t kDynamicVertexCopies = 3;
295 vkb::HostVertexBuffer vertices;
296 vkb::GenericBuffer indices;
297 std::array<vkb::HostVertexBuffer, kDynamicVertexCopies> dynVertices;
298 std::array<vkb::GenericBuffer, kDynamicVertexCopies> dynIndices;
301 std::vector<uint32_t> cpuIndices;
303 uint64_t dynamicWriteCount = 0;
304 bool dynamic = false;
305 uint32_t vertexCount = 0;
306 uint32_t indexCount = 0;
307 vk::IndexType indexType = vk::IndexType::eUint32;
312};
313
318 void operator()(MeshShaderResources *resources) const noexcept;
319};
320
322struct GpuShader {
323 vk::Pipeline swapchainPipeline;
324 vk::Pipeline offscreenPipeline;
329 vk::Pipeline mesh3dPipeline;
330 vk::Pipeline mesh3dXrayPipeline;
333 vk::PipelineLayout pipelineLayout;
334 vk::DescriptorSet resourceSet;
335 std::unique_ptr<MeshShaderResources, MeshShaderResourcesDeleter> resources;
336 bool isMesh3D = false;
337 bool isHair3D = false;
338 Shader *owner = nullptr;
339};
340
343public:
344 // Keep the base draw(Drawable*, mat4) overload visible alongside the
345 // canvas composite overloads below.
347
351 ~Graphics() override;
352
353 // ---- GPU frame timing (eve::service::IGpuTimer) ----------------------
355 void initGpuTiming();
357 void writeGpuTimestampBegin();
359 void writeGpuTimestampEnd();
361 void readGpuFrameTiming();
362
364 bool gpuTimingAvailable() const override;
366 float gpuFrameMs() const override;
367
369 std::string getBackendName() const override;
371 bool supportsRuntimeGlslCompilation() const override;
372
374 void initWithWindow(void *nativeWindow) override;
376 void initHeadless(int width, int height) override;
378 bool isHeadless() const override { return headless_; }
380 void present() override;
382 void requestSurfaceRecreate() override { surfaceNeedsRecreate = true; }
384 void onNativeWindowDestroyed() override;
386 void setScreenReadbackEnabled(bool enabled) override {
390 ensurePresentCaptureHook();
391 }
393 void setVSync(bool enabled) override {
394 if (vsyncEnabled == enabled) return;
398 markSwapchainDirty();
399 }
401 void setMsaaSamples(int samples) override {
402 const int raw = samples > 1 ? samples : 0;
403 if (raw == msaaSamples) return;
406 }
408 int getMsaaSamples() const override { return msaaSamples; }
410 void setViewportSize(int width, int height, int pixelwidth, int pixelheight) override;
411
412 // ---- GPU-driven rendering (stage 0: bindless + resource tables) ----
413
415 const GpuDrivenCaps &gpuDrivenCaps() const { return gpuDrivenCaps_; }
416
418 const RayTracingCaps& rayTracingCapsRef() const { return rayTracingCaps_; }
420 RayTracingCaps rayTracingCaps() const override { return rayTracingCaps_; }
422 bool supportsRayTracing() const override { return rayTracingCaps_.rayTracingAvailable(); }
423
425 FrameArena &currentFrameArena();
426
428 uint32_t materialTableGetOrCreate(eve::graphics::Material *material);
429
431 void syncMaterialTable();
432
434 uint32_t bindlessSlot2D(const GpuTexture *tex) const {
435 return tex ? tex->bindlessIndex2D : kInvalidBindlessSlot;
436 }
438 uint32_t bindlessSlotCube(const GpuTexture *tex) const {
439 return tex ? tex->bindlessIndexCube : kInvalidBindlessSlot;
440 }
442 bool supportsGpuDriven3D() const override {
443 return gpuDrivenCaps_.gpuDrivenAvailable();
444 }
446 bool supportsDeferredLighting() const override { return true; }
448 void drawDeferredLighting() override;
450 bool gpuDrivenEnabled() const override {
451 return gpuDrivenEnabled_ && gpuDrivenCaps_.gpuDrivenAvailable();
452 }
454 void gpuDrivenSetEnabled(bool enabled) override { gpuDrivenEnabled_ = enabled; }
456 uint32_t gpuDrivenMeshRecord(Mesh *mesh) override;
460 return materialTableGetOrCreate(material);
461 }
463 bool gpuDrivenMaterialUsable(Material *material) override;
465 [[nodiscard]] Result<void> gpuDrivenReleaseMaterialRecord(Material *material) override;
467 uint32_t gpuDrivenReflectionProbeSlot(Texture *cubemap) override;
470 bool gpuDrivenSubmitOpaque(const GpuInstance *instances, uint32_t instanceCount) override;
472 GpuResidentSubmitStatus gpuDrivenSubmitResident(const GpuResidentInstanceBatch &batch) override;
475 Texture *getSceneLinearDepthTexture() override;
476
478 bool supportsGpuParticles() const override { return initialized && !headless_; }
480 bool canSubmitGpuParticles() const override;
482 GpuParticleHandle createGpuParticleEmitter(std::uint32_t capacity) override;
484 void releaseGpuParticleEmitter(GpuParticleHandle handle) override;
486 void resetGpuParticleEmitter(GpuParticleHandle handle) override;
489 bool updateGpuParticleEmitter(GpuParticleHandle handle, const GpuParticleUpdate &update,
490 const GpuParticleSpawn *spawns,
491 std::uint32_t spawnCount) override;
494 bool drawGpuParticleEmitter(GpuParticleHandle handle,
495 const GpuParticleDraw &draw) override;
497 GpuParticleStats getGpuParticleStats(GpuParticleHandle handle) const override;
499 uint32_t debugBindlessIndex(Texture *tex) const;
501 uint32_t debugMeshRecordIndex(Mesh *mesh) const;
503 uint32_t debugLastGpuDrivenDrawCount() const { return lastGpuDrivenDrawCount_; }
505 void waitForSharedGpuResources();
507 bool gpuDrivenCullEnabled() const {
508 return gpuDrivenEnabled_ && gpuDrivenCaps_.gpuDrivenCullAvailable();
509 }
511 bool gpuDrivenScenePassPending() const { return gpuDrivenScenePassPending_; }
513 bool gpuDrivenCullBegin(const GpuInstance *instances, uint32_t instanceCount);
515 void gpuDrivenCullEmit(const glm::mat4 &viewProj, const glm::vec3 &eye, float fovYDeg,
516 float nearZ, float farZ);
518 void gpuDrivenOpenScenePass();
520 void gpuDrivenDrawOpaque();
522 bool gpuDrivenResolveWanted() const override;
524 void gpuDrivenRecordVisPass() override;
526 void gpuDrivenResolve() override;
528 uint32_t gpuDrivenVgUpload(const GpuVgAssetUpload &asset) override;
530 uint32_t gpuDrivenVgAssetId(Mesh *mesh) const override;
532 bool gpuDrivenVgAttachToMesh(Mesh *mesh, uint32_t vgAssetId) override;
534 bool gpuDrivenVgSetInstance(uint32_t vgAssetId, const glm::mat4 &model,
535 uint32_t materialId) override;
537 void gpuDrivenVgComputeSection(const glm::mat4 &viewProj, const glm::vec3 &eye,
538 float fovYDeg, float nearZ, float farZ) override;
540 uint32_t debugGpuDrivenVgVisibleCount() const;
542 uint32_t debugGpuDrivenVisibleCount() const;
544 uint32_t debugGpuDrivenCulledDrawCount() const;
545
547 void drawSolidRect(float x, float y, float w, float h, const Color &color,
548 BlendMode blend = BlendMode::Alpha) override;
550 void drawPrimitiveCanvas(const PrimitiveCanvas2D &canvas) override;
552 void drawSolidRectRotated(float cx, float cy, float w, float h, float degrees,
553 const Color &color,
554 BlendMode blend = BlendMode::Alpha) override;
556 void pushValidationScope() override {}
558 void popValidationScope() override {}
560 Texture *newTexture(int width, int height, const uint8_t *rgba, bool repeatU = false,
561 bool repeatV = false) override;
563 Texture *newTexture(int width, int height, const uint8_t *rgba,
564 const TextureCreateInfo &info) override;
566 [[nodiscard]] Result<Texture *> newTextureMipChain(uint32_t width, uint32_t height, uint32_t levels,
567 std::span<const uint8_t> rgba) override;
569 [[nodiscard]] Result<Texture *> newTextureArrayRgba16f(uint32_t width, uint32_t height, uint32_t layers,
570 std::span<const uint16_t> rgbaHalf) override;
572 [[nodiscard]] Result<Texture *> newTexture3DRgba8(uint32_t width, uint32_t height, uint32_t depth,
573 std::span<const uint8_t> rgba) override;
575 Texture *newCubemap(int faceSize, const uint8_t *rgbaFaces) override;
577 Texture *newCubemap(int faceSize, const uint8_t *rgbaFaces,
578 const TextureCreateInfo &info) override;
581 Texture *newHDRCubemap(int faceSize) override;
584 bool copyHDRCanvasToCubemapFace(Canvas *source, Texture *cubemap, int face) override;
586 bool copyHDRCanvasesToCubemap(Canvas *const *sources, int faceCount,
587 Texture *cubemap) override;
590 bool filterHDRReflectionCubemap(Texture *cubemap, int sampleCount = 64) override;
592 Texture *newTexture(image::ImageData *data) override;
594 Texture *newTexture(image::ImageData *data, const TextureCreateInfo &info) override;
596 [[nodiscard]] ResultRef<Texture> newSharedTexture(image::ImageData *data, const std::string &contentKey) override;
598 void setTextureSampler(Texture *texture, const TextureSampler &sampler) override;
600 float getMaxAnisotropy() const override;
602 Texture *newTextureFromFile(const std::string &filename) override;
604 bool reloadTextureFromFile(const std::string &filename) override;
606 bool uploadDeferredFileTexture(Texture *texture, image::ImageData *data) override;
608 bool releaseTexture(Texture *texture) override;
610 bool updateTexture(Texture *texture, int width, int height,
611 const uint8_t *rgba) override;
613 eve::Result<void> updateTextureFromResidentRgba8(Texture* texture, const GpuResidentBufferView& source, int width,
614 int height) override;
616 eve::Result<void> updateTextureRegion(Texture *texture, int x, int y, int width,
617 int height, std::span<const std::uint8_t> rgba,
618 std::size_t bytesPerRow = 0) override;
620 eve::Result<void> updateTextureRegions(
621 Texture *texture, std::span<const TextureRegionUpload> regions) override;
623 bool replaceTexturePixels(Texture *tex, image::ImageData *data);
625 bool replaceTexturePixelsRGBA(Texture *tex, int w, int h, const uint8_t *rgba);
627 void drawTexturedRect(Texture *texture, float x, float y, float w, float h, const Color &color) override;
629 void drawTexturedRectShader(Texture *texture, Shader *shader, float x, float y, float w, float h,
630 const Color &color) override;
632 void drawTexturedRectUV(Texture *texture, float x, float y, float w, float h, float u0, float v0,
633 float u1, float v1, const Color &color) override;
635 void drawTexturedRectShaderUV(Texture *texture, Shader *shader, float x, float y, float w,
636 float h, float u0, float v0, float u1, float v1,
637 const Color &color, bool rotatedUV = false,
638 BlendMode blend = BlendMode::Alpha) override;
640 void drawTexturedRectShaderUVRotated(Texture *texture, Shader *shader, float cx, float cy,
641 float w, float h, float degrees, float u0, float v0,
642 float u1, float v1, const Color &color,
643 bool rotatedUV = false,
644 BlendMode blend = BlendMode::Alpha) override;
646 void drawTexturedRectShaderDepth(Texture *color, Texture *depth, Shader *shader, float x, float y,
647 float w, float h, const Color &tint) override;
649 void drawTexturedRectShaderDepthMotion(Texture *color, Texture *depth, Texture *motion,
650 Shader *shader, float x, float y, float w, float h,
651 const Color &tint) override;
653 void drawTexturedRectShader4(Texture *color, Texture *depth, Texture *motion, Texture *extra,
654 Shader *shader, float x, float y, float w, float h,
655 const Color &tint) override;
657 void drawTexturedRectShader5(Texture *color, Texture *depth, Texture *motion, Texture *extra,
658 Texture *specular, Shader *shader, float x, float y, float w,
659 float h, const Color &tint) override;
661 SceneColorDistortionStatus drawSceneColorDistortionUVRotated(
662 Texture *displacement, float cx, float cy, float w, float h, float degrees, float u0,
663 float v0, float u1, float v1, float strengthPixels, float opacity,
664 bool rotatedUV = false) override;
666 void drawTexturedRectLitUV(Texture *albedo, Texture *normal, float x, float y, float w, float h, float u0, float v0,
667 float u1, float v1, const Color &color, BlendMode blend = BlendMode::Alpha) override;
669 void drawTexturedRectLitUVRotated(Texture *albedo, Texture *normal, float cx, float cy, float w, float h,
670 float degrees, float u0, float v0, float u1, float v1, const Color &color,
671 BlendMode blend = BlendMode::Alpha) override;
673 void setLighting2D(const Lighting2DUBO &ubo) override;
675 Shader *newShaderFromSpv(const std::vector<uint32_t> &vertSpv,
676 const std::vector<uint32_t> &fragSpv) override;
678 Shader *newShaderFromSpvFile(const std::string &vertPath, const std::string &fragPath) override;
680 Shader *newShader(const std::string &vertGlsl, const std::string &fragGlsl) override;
682 Shader *newMeshShaderFromSpv(const std::vector<uint32_t> &vertSpv,
683 const std::vector<uint32_t> &fragSpv) override;
685 Shader *newMeshShaderFromWgsl(const std::string &vertWgsl,
686 const std::string &fragWgsl) override;
688 Shader *newShaderFromWgsl(const std::string &vertWgsl,
689 const std::string &fragWgsl) override;
691 [[nodiscard]] Result<void> replaceShaderFromSpv(
692 Shader &shader, const std::vector<uint32_t> &vertSpv,
693 const std::vector<uint32_t> &fragSpv) override;
695 [[nodiscard]] Result<void> replaceMeshShaderResources(Shader &shader, const std::vector<uint32_t> &vertSpv,
696 const std::vector<uint32_t> &fragSpv,
697 const ShaderResourceInputs &resources) override;
699 [[nodiscard]] Result<void> replaceShaderFromWgsl(
700 Shader &shader, const std::string &vertWgsl,
701 const std::string &fragWgsl) override;
703 [[nodiscard]] Result<void> replaceShaderFromGlsl(
704 Shader &shader, const std::string &vertGlsl,
705 const std::string &fragGlsl) override;
707 Shader *newMeshShader(const std::string &vertGlsl, const std::string &fragGlsl) override;
709 Shader *newHairShaderFromSpv(const std::vector<uint32_t> &vertSpv,
710 const std::vector<uint32_t> &fragSpv) override;
712 Shader *newHairShaderFromWgsl(const std::string &vertWgsl,
713 const std::string &fragWgsl) override;
715 bool releaseShader(Shader *shader) override;
717 eve::Result<void> configureMeshShaderSurface(Shader &shader, BlendMode blend, bool depthWrite,
718 bool doubleSided) override;
720 eve::Result<void> configureMeshShaderRaster(Shader &shader, const MeshShaderRasterState &state) override;
722 Mesh *newMeshFromAssimp(const ::aiMesh &mesh) override;
724 Mesh *newMeshFromAssimp(const ::aiMesh &mesh, const aiMatrix4x4 &worldTransform) override;
726 Mesh *newMeshFromArrays(const float *posXYZ, const float *nrmXYZ, const float *uvST,
727 int vertexCount, const uint32_t *indices, int indexCount) override;
735 Mesh *newMeshFromArraysColored(const float *posXYZ, const float *nrmXYZ, const float *uvST,
736 const float *colorRGBA, int vertexCount,
737 const uint32_t *indices, int indexCount) override;
739 [[nodiscard]] std::optional<eve::graphics::MeshBackendDescriptor> describeMesh(Mesh *mesh) const override;
740 bool bakeMeshMorph(Mesh *mesh) override;
742 bool updateMeshVertices(Mesh *mesh, const float *posXYZ, const float *nrmXYZ, const float *uvST,
743 int vertexCount, const uint32_t *indices, int indexCount) override;
745 bool setMeshSkinningData(Mesh *mesh, const uint16_t *joints4, const float *weights4,
746 int vertexCount) override;
748 Mesh *newMeshSphere(int slices = 32, int stacks = 16) override;
750 Mesh *newMeshCylinder(int slices = 32, int stacks = 1, bool caps = true) override;
752 bool releaseMesh(Mesh *mesh) override;
754 void begin3DFrame() override;
756 void begin3DFrameToCanvas(Canvas *canvas) override;
758 void end3DFrameToCanvas() override;
760 void drawPrimitiveScene(const PrimitiveSceneCanvas3D &canvas) override;
762 float getLastOffscreen3DGpuDurationMs() const override {
763 return lastOffscreen3DGpuDurationMs;
764 }
766 void setMesh3DViewProj(const glm::mat4 &viewProj) override;
768 void setMesh3DView(const glm::mat4 &view) override;
770 void setMesh3DClip(float nearZ, float farZ) override;
772 Texture *getSceneColorTexture() override;
774 image::ImageData *renderEntityIdMask(
775 const std::vector<eve::graphics::Graphics::EntityIdDraw> &draws, const glm::mat4 &viewProj,
776 int width, int height) override;
778 image::ImageData *readGBufferToImageData(const std::string &name) override;
780 image::ImageData *readDecalLayerToImageData(const std::string &attachment) override;
782 void drawMesh(Mesh *mesh, const glm::mat4 &model, Texture *texture, const Color &tint) override;
784 void drawMeshShader(Mesh *mesh, const glm::mat4 &model, Texture *texture, const Color &tint,
785 Shader *shader) override;
787 [[nodiscard]] Result<void> drawMeshShaderInstances(Mesh &mesh, Shader &shader, const glm::mat4 &model,
788 const Color &tint, std::uint32_t first,
789 std::uint32_t count) override;
791 void drawVoxelFaceInstances(const uint32_t *packed, int count, float originX, float originY, float originZ,
792 const std::string &faceDir, Texture *atlas, int tilesPerRow = 16,
793 const uint32_t *ao = nullptr) override;
795 void setMesh3DNormalTexture(Texture *normal) override;
797 void setMesh3DPackedNormalMask(bool enabled) override;
799 void setMesh3DHeightTexture(Texture *height) override;
801 void setMesh3DVirtualTexture(bool enabled, int pageCountX, int pageCountY,
802 int atlasSlotsX, int atlasSlotsY,
803 float borderFraction) override;
805 void setMesh3DSceneDepth(Texture *depth) override;
807 void setMesh3DSceneColor(Texture *color) override;
809 [[nodiscard]] Mesh3DSceneColorCaptureStatus captureMesh3DSceneColor() override;
811 void setMesh3DMaterial(float metallic, float roughness) override;
813 [[nodiscard]] Result<void> setMesh3DPbrSurface(const PbrSurface* surface) override;
815 void setMesh3DSurface(SurfaceMode mode, BlendMode blend, bool depthWrite,
816 bool doubleSided, float alphaCutoff,
817 const std::string &alphaTechnique = "cutoff") override;
819 void setMesh3DTexCellBomb(float cellScale, float strength, float rotAmount = 1.f) override;
821 void setMesh3DParallax(float scale, float minLayers = 8.f, float maxLayers = 32.f) override;
823 void setMesh3DLodDither(float weight, bool reverse, bool enabled) override;
825 void setMesh3DLighting(const Lighting3DPack &pack) override;
827 void setCloudShadows(float strength, float worldCell, float time, float windSpeed, float windAngle, float coverage,
828 float detail) override;
830 void setMesh3DClusteredLighting(const ClusteredLightingUpload &upload) override;
832 void setMesh3DClusteredActive(bool active) override;
834 void setMesh3DSSAO(float intensity) override { (void)intensity; }
836 void setMesh3DLight(const glm::vec3 &dir, const glm::vec3 &color) override;
838 void setMesh3DCameraPos(const glm::vec3 &eye) override;
840 void setMesh3DEnv(Texture *cube, float intensity) override;
842 void setMesh3DEnvProbe(const glm::vec3 &center, const glm::vec3 &extent) override;
844 void setMesh3DReflectionProbes(const ReflectionProbeUpload &upload) override;
846 [[nodiscard]] Result<void> setSceneToneMapping(SceneToneMapping mode) override;
848 SceneToneMapping getSceneToneMapping() const override { return sceneToneMapping_; }
850 [[nodiscard]] Result<void> setDisplayOutputMode(DisplayOutputMode mode) override;
852 [[nodiscard]] Result<void> setDisplayHdrCalibration(float paperWhiteNits, float peakNits) override;
854 [[nodiscard]] Result<DisplayOutputSupport> queryDisplayOutputSupport() const override;
856 [[nodiscard]] Result<void> setScenePhotographicVignette(float intensity) override;
858 float getScenePhotographicVignette() const override { return scenePhotographicVignette_; }
860 void setSceneExposure(float exposure) override { sceneExposure = std::max(exposure, 0.f); }
862 float getSceneExposure() const override { return sceneExposure; }
864 void setSceneColorFilter(const glm::vec3& color) override {
865 sceneColorFilter = glm::max(color, glm::vec3(0.f));
866 }
868 glm::vec3 getSceneColorFilter() const override { return sceneColorFilter; }
870 void setSceneLiftGammaGain(const glm::vec3& lift, const glm::vec3& inverseGamma,
871 const glm::vec3& gain) override {
872 sceneLift = lift;
873 sceneInverseGamma = glm::max(inverseGamma, glm::vec3(0.001F));
874 sceneGain = gain;
875 }
877 glm::vec3 getSceneLift() const override { return sceneLift; }
879 glm::vec3 getSceneInverseGamma() const override { return sceneInverseGamma; }
881 glm::vec3 getSceneGain() const override { return sceneGain; }
883 void setSceneTransitionFx(float vignette, float vignetteSmoothness,
884 float lensDistortion, float lensScale) override {
885 sceneTransitionVignette = std::clamp(vignette, 0.0F, 1.0F);
886 sceneTransitionVignetteSmoothness = std::clamp(vignetteSmoothness, 0.01F, 1.0F);
887 sceneTransitionLensDistortion = std::clamp(lensDistortion, 0.0F, 1.0F);
888 sceneTransitionLensScale = std::clamp(lensScale, 0.01F, 5.0F);
889 }
891 float getSceneTransitionVignette() const override { return sceneTransitionVignette; }
893 float getSceneTransitionVignetteSmoothness() const override { return sceneTransitionVignetteSmoothness; }
895 float getSceneTransitionLensDistortion() const override { return sceneTransitionLensDistortion; }
897 float getSceneTransitionLensScale() const override { return sceneTransitionLensScale; }
899 void setSceneAutoExposure(bool enabled, float minEV, float maxEV) override {
900 sceneAutoExposure = enabled;
901 sceneAutoExposureMinEV = minEV;
902 sceneAutoExposureMaxEV = maxEV;
903 }
905 bool getSceneAutoExposure() const override { return sceneAutoExposure; }
907 float getSceneAutoExposureMinEV() const override { return sceneAutoExposureMinEV; }
909 float getSceneAutoExposureMaxEV() const override { return sceneAutoExposureMaxEV; }
911 void setSceneBloom(float intensity, float threshold) override {
912 sceneBloomIntensity = intensity;
913 sceneBloomThreshold = threshold;
914 }
916 float getSceneBloomIntensity() const override { return sceneBloomIntensity; }
918 float getSceneBloomThreshold() const override { return sceneBloomThreshold; }
920 void setSceneDepthOfField(float focusDistance, float maxBlurPx, float focusRange, float nearZ,
921 float farZ) override {
922 sceneDofFocusDistance = focusDistance;
923 sceneDofMaxBlurPx = maxBlurPx;
924 sceneDofFocusRange = focusRange;
925 sceneDofNearZ = nearZ;
926 sceneDofFarZ = farZ;
927 }
929 float getSceneDofFocusDistance() const override { return sceneDofFocusDistance; }
931 float getSceneDofMaxBlur() const override { return sceneDofMaxBlurPx; }
933 float getSceneDofFocusRange() const override { return sceneDofFocusRange; }
935 float getSceneDofNearZ() const override { return sceneDofNearZ; }
937 float getSceneDofFarZ() const override { return sceneDofFarZ; }
939 void setMesh3DShadows(const ShadowUpload &upload) override;
941 void setMesh3DShadowReceive(bool receive) override;
943 void setMesh3DSkinInfluenceLimit(SkinInfluenceLimit count) override;
945 void beginShadowPass(int cascadeIndex) override;
947 void drawMeshShadow(Mesh *mesh, const glm::mat4 &lightMVP, bool doubleSided = true) override;
949 void drawMeshShadowAlpha(Mesh *mesh, const glm::mat4 &lightMVP, Texture *albedo = nullptr,
950 bool doubleSided = true, float lodWeight = 1.f,
951 bool lodFadeReverse = false, bool lodDither = false) override;
953 void endShadowPass() override;
954
956 void beginGBufferPass(int width, int height) override;
958 void drawMeshGBuffer(Mesh *mesh, const glm::mat4 &mvp, const glm::mat4 &model, float nearZ,
959 float farZ, Texture *albedo = nullptr, float tintR = 1.f, float tintG = 1.f,
960 float tintB = 1.f, float motionX = 0.f, float motionY = 0.f,
961 float roughness = 0.45f, float metallic = 0.f) override;
963 void drawMeshGBufferAlpha(Mesh *mesh, const glm::mat4 &mvp, const glm::mat4 &model, float nearZ,
964 float farZ, Texture *albedo = nullptr, float tintR = 1.f,
965 float tintG = 1.f, float tintB = 1.f, float motionX = 0.f,
966 float motionY = 0.f, float roughness = 0.45f,
967 float metallic = 0.f) override;
969 void endGBufferPass() override;
970
972 bool supportsDecal() const override { return true; }
974 void beginDecalPass(int width, int height) override;
976 void setDecalCamera(const glm::mat4 &viewProj, float nearZ, float farZ) override;
978 void drawDecal(const glm::mat4 &model, Texture *albedo, Texture *normal, Texture *params,
979 const float uvRect[4], float fade, float normalStrength, float roughnessStrength,
980 float metalStrength, float emissiveStrength, int blendMode = 0,
981 int projectionMode = 0, float blendSharpness = 4.f,
982 float parallaxScale = 0.f, float parallaxMinLayers = 8.f,
983 float parallaxMaxLayers = 24.f, float edgeFadeWidth = 0.06f) override;
985 void endDecalPass() override;
986
988 Canvas *newCanvas(int width, int height) override;
991 Canvas *newHDRCanvas(int width, int height) override;
993 void setCanvas(Canvas *canvas) override;
995 bool isCanvasActive() const override;
997 Canvas *getCanvas() const override;
998
1000 Texture *getTexture() override;
1002 image::ImageData *newImageData() override;
1003
1005 void draw(eve::graphics::Graphics *gfx, const glm::mat4 &matrix) const override;
1007 void draw(Canvas *C, const glm::mat4 &matrix) const override;
1009 void clear(std::optional<Color> color, std::optional<int> stencil, std::optional<double> depth) override;
1011 Color getPixel(int x, int y) override;
1012
1014 vkb::Device &getDevice() { return device; }
1016 vk::CommandPool getUploadPool() const { return uploadPool; }
1022 bool canRecordPostSceneGpuWork() const { return bool(presentRecording) && !sceneColorPassOpen; }
1027 vk::CommandBuffer& postSceneCommandBuffer() { return currentPresentCb(); }
1029 vk::DescriptorSetLayout getTexSetLayout() const { return texSetLayout; }
1031 vk::DescriptorPool getDescriptorPool() const { return descriptorPool; }
1033 const vkb::BuiltRenderPass &getOffscreenRenderPass(bool hdr = false) const {
1034 return hdr ? hdrOffscreenRenderPass : offscreenRenderPass;
1035 }
1037 const vkb::BuiltRenderPass &getOffscreen3DRenderPass(bool hdr = false) {
1038 return hdr ? hdrOffscreen3DRenderPass : offscreen3DRenderPass;
1039 }
1041 vk::Format getDepthFormat() const { return depthFormat; }
1043 vk::RenderPass getSwapchainRenderPass() const { return renderpass; }
1045 vk::RenderPass getUiMsaaRenderPass() const { return uiRenderPass; }
1047 vk::SampleCountFlagBits getUiMsaaSamples() const { return uiColorSamples; }
1051 createUiColorResources(int(swapchain.extent.width), int(swapchain.extent.height));
1052 }
1065 void drawUiTextureRects(void* commandBuffer, const std::vector<UiTextureDraw>& draws, std::size_t bufferOffset = 0);
1067 vkb::Instance &getInstance() { return inst; }
1069 vkb::Swapchain &getSwapchain() { return swapchain; }
1071 void *getSdlWindow() const { return sdlWindow; }
1073 uint32_t getSwapchainImageCount() const { return swapchain.image_count; }
1074
1075 friend class OffscreenCanvas;
1076
1078 struct LitBatch {
1079 Texture *albedo = nullptr;
1080 Texture *normal = nullptr;
1081 BlendMode blend = BlendMode::Alpha;
1083 };
1084
1085private:
1086 void drawMeshShaderRange(Mesh *mesh, const glm::mat4 &model, Texture *texture, const Color &tint, Shader *shader,
1087 std::uint32_t first, std::uint32_t count);
1088 struct GpuParticleDrawRequest;
1089 struct GpuParticleResource;
1090
1091 struct Mesh3dFrameSlots;
1092 struct Mesh3dClusteredFrameSlots;
1093 struct DecalSlot;
1094 struct DecalSetKey;
1095 struct DecalSetKeyHash;
1096 struct GBufferSlot;
1097 void createSwapchainAndPipeline();
1098 void applyPreferredSwapchainFormats(vkb::SwapchainBuilder &builder);
1099 void createTexturedPipeline();
1100 void createLit2DPipeline();
1101 void createGpuParticlePipelines();
1102 void destroyGpuParticleResources();
1103 void recordGpuParticleCompute(vk::CommandBuffer cb);
1104 void drawGpuParticleRequest(vk::CommandBuffer cb, const GpuParticleDrawRequest& request);
1105 struct PbrResources;
1106 static void deletePbrResources(PbrResources* resources);
1107 std::unique_ptr<PbrResources, void (*)(PbrResources*)> pbrResources_{nullptr, &deletePbrResources};
1108 std::optional<PbrSurface> pbrSurface_;
1109 void destroyPbrResources();
1110 void drawPbrMesh(Mesh* mesh, const glm::mat4& model, const Color& tint);
1111 void createMesh3DPipeline();
1112 void createMesh3DClusteredPipeline();
1113 void createDeferredLightingPipeline();
1114 void destroyDeferredLightingResources();
1115 void createVoxelRectPipeline();
1116 vk::Pipeline buildVoxelRectPipeline(const vkb::BuiltRenderPass &rp,
1117 vk::SampleCountFlagBits samples);
1118 void destroyVoxelRectResources();
1119 void ensureVoxelUnitQuad();
1120 vkb::BoundSet voxelRectSetFor(GpuTexture *gpuTex);
1121 void createShadowResources();
1122 void destroyShadowResources();
1123 void createGBufferResources(int width, int height);
1124 void destroyGBufferResources();
1125 void createDecalResources(int width, int height);
1126 void destroyDecalResources();
1127 void recordDecalPass();
1128 void recordDecalPassInto(vk::CommandBuffer cb, DecalSlot &slot, GBufferSlot &gslot);
1129 void ensureDecalUnitBox();
1130 void ensureDecalPlaceholders();
1131 vkb::BoundSet decalSetFor(DecalSlot &slot, GpuTexture *albedo, GpuTexture *normal,
1133 DecalSlot *currentDecalSlot();
1134 void createSceneColorResources(int width, int height);
1135 void destroySceneColorResources();
1136 void createUiColorResources(int width, int height);
1137 void destroyUiColorTargets();
1138 void destroyUiColorResources();
1139 void queueUiResolve();
1141 bool renderUiOverlayPass();
1143 void recordDeferredFrameGraph();
1144 void dropPendingOffscreenPasses();
1146 bool beginSwapchainRenderPass();
1148 void beginSwapchainColorPass();
1149 bool beginSceneColorRenderPass();
1150 void endSceneColorRenderPass();
1151 void ensureOffscreen3DResources();
1152 void destroyOffscreen3DResources();
1153 void queueSceneColorResolve();
1154 void materializeSceneColorResolve();
1155 void ensureClusteredBuffers(size_t lightsBytes, size_t tableBytes, size_t indicesBytes);
1156 void uploadClusteredLighting(const ClusteredLightingUpload &upload);
1157 void ensureMesh3dStrides();
1158 void ensureMesh3dRing(Mesh3dFrameSlots &fslots);
1159 size_t uploadSkinPalette(Mesh* mesh, Mesh3dFrameSlots& fslots);
1160 vk::DescriptorSet skinPassSetFor(GpuTexture *albedo, Mesh3dFrameSlots &fslots);
1161 bool prepareSkinPass(Mesh *mesh, Texture *albedo, const glm::mat4 &mvp,
1162 const glm::mat4 &model, const glm::vec4 &clip,
1163 vk::DescriptorSet &set, uint32_t &uboOffset);
1164 void ensureMesh3dClusteredRing(Mesh3dClusteredFrameSlots &fslots);
1165 vkb::BoundSet mesh3dClusteredSetFor(GpuTexture *gpuTex, GpuTexture *normalTex,
1166 GpuTexture *envTex, GpuTexture *heightTex,
1167 GpuTexture *decalAlbedo, GpuTexture *decalNormal,
1168 GpuTexture *decalParams,
1169 Mesh3dClusteredFrameSlots &fslots);
1170 void ensureOffscreenPipelines();
1171 void ensureHdrOffscreenPipelines();
1172 void ensureShaderOffscreenPipeline(Shader *shader);
1173 void ensureShaderHdrOffscreenPipeline(Shader *shader);
1175 void destroyPresentGraphicsPipelines();
1177 void rebuildGpuParticleDrawPipelines(const vkb::BuiltRenderPass &target);
1179 void ensureHdrGpuParticleDrawPipelines();
1181 void ensurePresentComposeResources(int width, int height);
1182 void destroyPresentComposeResources();
1183 struct PresentComposeSlot;
1191 PresentComposeSlot *currentPresentComposeSlot();
1193 bool beginPresentComposePass();
1194 void endPresentComposePass();
1196 void encodePresentComposeToSwapchain(vk::CommandBuffer cb);
1197 vk::Pipeline createTexturedStylePipeline(const std::vector<uint32_t> &vert, const std::vector<uint32_t> &frag,
1198 const vkb::BuiltRenderPass &rp, vk::PipelineLayout layout,
1199 BlendMode mode = BlendMode::Alpha,
1200 vk::SampleCountFlagBits samples = vk::SampleCountFlagBits::e1);
1201 vk::Pipeline createMesh3DStylePipeline(const std::vector<uint32_t> &vert, const std::vector<uint32_t> &frag,
1202 vk::PipelineLayout layout, const vkb::BuiltRenderPass &rp,
1203 vk::SampleCountFlagBits samples, BlendMode blend = BlendMode::Opaque,
1204 bool depthWrite = true, bool doubleSided = true,
1205 const MeshShaderRasterState &raster = {});
1206 eve::Result<void> rebuildMeshShaderSurface(Shader &shader, BlendMode blend, bool depthWrite, bool doubleSided,
1207 const MeshShaderRasterState &raster);
1208 static constexpr size_t kMesh3DPipelineVariants = 20;
1209 static size_t mesh3dPipelineIndex(BlendMode blend, bool depthWrite, bool doubleSided);
1210 static constexpr size_t kPrimitive3DPipelineVariants = 45;
1211 static size_t primitive3DPipelineIndex(PrimitiveDepthMode depth, BlendMode blend, PrimitiveCullMode cull);
1213 vk::Pipeline createMesh3DXrayPipeline(const std::vector<uint32_t> &vert,
1214 const std::vector<uint32_t> &frag,
1215 vk::PipelineLayout layout,
1216 const vkb::BuiltRenderPass &rp,
1217 vk::SampleCountFlagBits samples);
1218 vk::Pipeline createMesh3DHairPipeline(const std::vector<uint32_t> &vert,
1219 const std::vector<uint32_t> &frag,
1220 vk::PipelineLayout layout,
1221 const vkb::BuiltRenderPass &rp,
1222 vk::SampleCountFlagBits samples);
1224 void ensureScenePassPipelines(const vkb::BuiltRenderPass &target,
1225 vk::SampleCountFlagBits samples);
1226 void rebuildPrimitive3DPipelines(const vkb::BuiltRenderPass &target, vk::SampleCountFlagBits samples);
1227 void buildPrimitive3DPipelines(const vkb::BuiltRenderPass &target, vk::SampleCountFlagBits samples,
1228 std::array<vk::Pipeline, kPrimitive3DPipelineVariants> &pipelines);
1230 int clampMsaaSamples(int requested) const;
1232 const vkb::BuiltRenderPass &activeScenePass() const {
1233 return sceneColorRenderPass ? sceneColorRenderPass : renderpass;
1234 }
1236 vk::SampleCountFlagBits activeSceneSamples() const {
1237 return sceneColorRenderPass ? sceneColorSamples : vk::SampleCountFlagBits::e1;
1238 }
1239 void destroySwapchainResources();
1240 void flushBatch();
1241 void flushToSwapchain();
1242 void flushToOffscreen(OffscreenCanvas *canvas);
1243 void abortOpen3DFrame();
1244 void noteSolidOverlay(uint32_t batchIndex);
1245 void noteTexturedOverlay(Texture *tex, uint32_t batchIndex);
1246 void noteLitOverlay(uint32_t batchIndex);
1247 void clear2DBatches();
1248 void drawLitBatches(vk::CommandBuffer cb, int viewW, int viewH, std::vector<LitBatch> &batches,
1249 std::vector<vkb::HostVertexBuffer> &texBufs, size_t &texBufIndex, bool offscreen,
1250 bool hdr = false);
1251 vkb::BoundSet lit2dSetFor(GpuTexture *albedo, GpuTexture *normal, bool offscreen);
1252 vkb::BoundSet post2SetFor(GpuTexture *color, GpuTexture *depth,
1253 GpuTexture *motion = nullptr, GpuTexture *extra = nullptr,
1254 GpuTexture *specular = nullptr);
1255 void ensureFlatNormalTexture();
1257 void ensureReadbackSlots();
1259 bool recordSwapchainReadback(vk::CommandBuffer cb);
1261 void syncReadbackCpu();
1263 void destroyReadbackResources();
1264 void ensurePresentCaptureHook();
1265 vkb::BoundSet mesh3dSetFor(GpuTexture *gpuTex, GpuTexture *normalTex, GpuTexture *envTex,
1266 GpuTexture *heightTex, GpuTexture *depthTex, GpuTexture *sceneColorTex,
1267 GpuTexture *decalAlbedo, GpuTexture *decalNormal,
1268 GpuTexture *decalParams, Mesh3dFrameSlots &fslots);
1269 void ensureDefaultEnvCubemap();
1270 void ensureFlatNormalTexture3D();
1271 void ensureFlatHeightTexture3D();
1272 vk::Sampler createVkSampler(const TextureSampler &sampler, uint32_t mipLevels) const;
1273 void writeCombinedImageDescriptor(GpuTexture *gpu);
1280 void createInstanceAndDevice(const std::vector<const char *> &instanceExtensions,
1281 void *nativeWindow, vk::SurfaceKHR *surfaceOut);
1283 bool rebuildSwapchainIfNeeded();
1285 bool beginPresentCommandBuffer();
1286
1287 bool initialized = false;
1288 bool headless_ = false;
1289 bool hasPresentedFrame = false;
1290 float maxSamplerAnisotropy = 1.f;
1291 std::vector<uint8_t> lastFrameRgba;
1292 // Persistent host-visible staging buffers for swapchain readback. The copy
1293 // is recorded into the present command buffer (no extra submit / no
1294 // per-frame GPU wait), and each present frame slot owns one slot so a
1295 // staging buffer is only reused after that slot's fence has signaled.
1296 struct ScreenReadbackSlot {
1297 vkb::GenericBuffer staging;
1298 void *mapped = nullptr;
1299 };
1300 std::vector<ScreenReadbackSlot> screenReadbackSlots;
1301 size_t screenReadbackBytes = 0;
1302 size_t readbackWriteSlot = 0;
1303 bool readbackReady = false; // at least one copy submitted
1304 bool readbackCpuSynced = false; // newest copy already converted to lastFrameRgba
1305 bool readbackBgra = false; // swapchain format of the newest captured frame
1306 Canvas *activeCanvas = nullptr;
1307 bool swapchainDirty = false;
1308 void markSwapchainDirty() override { swapchainDirty = true; }
1309 // Set from the SDL event-watch thread on Android foreground; consumed on
1310 // the render thread inside flushToSwapchain().
1311 std::atomic<bool> surfaceNeedsRecreate{false};
1312 void recreateSurfaceForResume();
1313 // False while the native window is mid-(re)creation / rotation (Android),
1314 // when touching the swapchain or presenting would crash the GPU driver.
1315 bool isRenderSurfaceReady() const;
1316 // Returns true only once the drawable size has been non-zero and identical
1317 // across consecutive frames, i.e. the surface has settled after a
1318 // rotation/resume and is safe to (re)build a swapchain against.
1319 bool isRenderSurfaceStable();
1320 int pendingSurfaceW = 0;
1321 int pendingSurfaceH = 0;
1322 int surfaceStableFrames = 0;
1323 void *sdlWindow = nullptr;
1324 vk::SurfaceKHR surface;
1325
1326 vkb::Instance inst;
1327#if defined(VKB_ENABLE_VMA)
1328 // Declared before Device and all GPU resources so reverse member
1329 // destruction keeps the allocator alive until every buffer is gone.
1330 VmaAllocatorOwner vmaAllocatorOwner_;
1331#endif
1332 vkb::Device device;
1333 vkb::Swapchain swapchain;
1334 vkb::BuiltRenderPass renderpass;
1335
1336 vk::Pipeline pipeline;
1337 vk::PipelineLayout pipelineLayout;
1338 vk::Pipeline solidAlphaPipeline; // alpha-blended solid (BlendMode::Alpha)
1339 vk::Pipeline additiveSolidPipeline; // additive solid (BlendMode::Additive)
1340 vk::Pipeline premultipliedSolidPipeline;
1341 vk::Pipeline multiplySolidPipeline;
1342
1343 vk::DescriptorSetLayout texSetLayout;
1344 vk::UniqueDescriptorSetLayout texSetLayoutUnique;
1345 vk::DescriptorPool descriptorPool;
1346 vk::Pipeline texPipeline;
1347 vk::Pipeline additiveTexPipeline;
1348 vk::Pipeline premultipliedTexPipeline;
1349 vk::Pipeline multiplyTexPipeline;
1350 vk::Pipeline opaqueTexPipeline;
1351 vk::Pipeline particleDistortionPipeline;
1352 vk::Pipeline sceneTonemapPipeline;
1354 vk::Format presentAttachmentFormat_ = vk::Format::eUndefined;
1355 SceneToneMapping sceneToneMapping_ = SceneToneMapping::Aces;
1356 vk::SurfaceFormatKHR selectedSurfaceFormat_{vk::Format::eB8G8R8A8Unorm,
1357 vk::ColorSpaceKHR::eSrgbNonlinear};
1358 float sceneExposure = 1.f;
1359 glm::vec3 sceneColorFilter{1.f};
1360 glm::vec3 sceneLift{0.f};
1361 glm::vec3 sceneInverseGamma{1.f};
1362 glm::vec3 sceneGain{1.f};
1363 float scenePhotographicVignette_ = 0.0F;
1364 float sceneTransitionVignette = 0.0F;
1365 float sceneTransitionVignetteSmoothness = 0.2F;
1366 float sceneTransitionLensDistortion = 0.0F;
1367 float sceneTransitionLensScale = 1.0F;
1368 bool sceneAutoExposure = false;
1369 float sceneAutoExposureMinEV = -8.f;
1370 float sceneAutoExposureMaxEV = 8.f;
1371 float sceneBloomIntensity = 0.f;
1372 float sceneBloomThreshold = 1.f;
1373 float sceneDofFocusDistance = 0.f;
1374 float sceneDofMaxBlurPx = 0.f;
1375 float sceneDofFocusRange = 8.f;
1376 float sceneDofNearZ = 0.1f;
1377 float sceneDofFarZ = 100.f;
1378 vk::PipelineLayout texPipelineLayout;
1379 vk::PipelineLayout shaderPipelineLayout; // tex set + push constants
1380 vk::CommandPool uploadPool;
1381
1382 vkb::BuiltRenderPass offscreenRenderPass;
1383 vkb::BuiltRenderPass hdrOffscreenRenderPass;
1384 vk::Pipeline offscreenSolidPipeline;
1385 vk::Pipeline offscreenSolidAlphaPipeline;
1386 vk::Pipeline offscreenAdditiveSolidPipeline;
1387 vk::Pipeline offscreenPremultipliedSolidPipeline;
1388 vk::Pipeline offscreenMultiplySolidPipeline;
1389 vk::Pipeline offscreenTexPipeline;
1390 vk::Pipeline offscreenAdditiveTexPipeline;
1391 vk::Pipeline offscreenPremultipliedTexPipeline;
1392 vk::Pipeline offscreenMultiplyTexPipeline;
1393 vk::Pipeline offscreenOpaqueTexPipeline;
1394 vk::Pipeline hdrOffscreenTexPipeline;
1395 vk::Pipeline hdrOffscreenOpaqueTexPipeline;
1396 vk::Pipeline hdrOffscreenAdditiveTexPipeline;
1397 vk::Pipeline hdrOffscreenPremultipliedTexPipeline;
1398 vk::Pipeline hdrOffscreenMultiplyTexPipeline;
1399 vk::Pipeline hdrOffscreenSolidPipeline;
1400 vk::Pipeline hdrOffscreenSolidAlphaPipeline;
1401 vk::Pipeline hdrOffscreenAdditiveSolidPipeline;
1402 vk::Pipeline hdrOffscreenPremultipliedSolidPipeline;
1403 vk::Pipeline hdrOffscreenMultiplySolidPipeline;
1404 vk::Pipeline hdrOffscreenLitPipeline;
1405 vk::Pipeline hdrOffscreenLitAdditivePipeline;
1406 vk::Pipeline hdrOffscreenLitPremultipliedPipeline;
1407 vk::Pipeline hdrOffscreenLitMultiplyPipeline;
1408 vk::Pipeline hdrOffscreenLitOpaquePipeline;
1409 vk::Pipeline hdrOffscreenTonemapPipeline;
1410 vk::Pipeline hdrOffscreenParticleDistortionPipeline;
1411 vk::Pipeline hdrGpuParticleAlphaPipeline_{};
1412 vk::Pipeline hdrGpuParticleAdditivePipeline_{};
1413 vk::Pipeline hdrGpuParticlePremultipliedPipeline_{};
1414 vk::Pipeline hdrGpuParticleMultiplyPipeline_{};
1415 vk::Pipeline hdrGpuParticleOpaquePipeline_{};
1416 bool presentComposeActive_ = false;
1417
1418 vk::DescriptorSetLayout mesh3dSetLayout;
1419 vk::UniqueDescriptorSetLayout mesh3dSetLayoutUnique;
1420 vk::PipelineLayout mesh3dPipelineLayout;
1421 vk::PipelineLayout mesh3dShaderPipelineLayout; // + push constants for custom mesh shaders
1422 vk::Pipeline mesh3dPipeline;
1423 vk::Pipeline mesh3dTransparentPipeline;
1424 std::array<vk::Pipeline, kMesh3DPipelineVariants> mesh3dSurfacePipelines{};
1425 std::array<vk::Pipeline, kPrimitive3DPipelineVariants> primitive3DPipelines{};
1426 std::array<vk::Pipeline, kPrimitive3DPipelineVariants> offscreenPrimitive3DPipelines{};
1427 std::array<vk::Pipeline, kPrimitive3DPipelineVariants> hdrOffscreenPrimitive3DPipelines{};
1428 std::vector<vkb::HostVertexBuffer> offscreenPrimitive3DBufs;
1429 std::size_t offscreenPrimitive3DDrawIndex = 0;
1430 // One UBO (+ per-texture descriptor sets) per draw in the current 3D frame.
1431 // Avoids vkUpdateDescriptorSets on a set already bound in a recording /
1432 // executable command buffer (which invalidates the CB).
1433 struct Mesh3dSetKey {
1434 GpuTexture *albedo = nullptr;
1435 GpuTexture *normal = nullptr;
1436 GpuTexture *env = nullptr;
1437 GpuTexture *reflectionProbe0 = nullptr;
1438 GpuTexture *reflectionProbe1 = nullptr;
1439 GpuTexture *height = nullptr;
1440 GpuTexture *depth = nullptr;
1441 GpuTexture *sceneColor = nullptr;
1442 GpuTexture *decalAlbedo = nullptr;
1443 GpuTexture *decalNormal = nullptr;
1444 GpuTexture *decalParams = nullptr;
1445 size_t paletteSlot = 0;
1447 bool operator==(const Mesh3dSetKey &o) const {
1448 return albedo == o.albedo && normal == o.normal && env == o.env && reflectionProbe0 == o.reflectionProbe0 &&
1449 reflectionProbe1 == o.reflectionProbe1 && height == o.height && depth == o.depth &&
1450 sceneColor == o.sceneColor && decalAlbedo == o.decalAlbedo && decalNormal == o.decalNormal &&
1451 decalParams == o.decalParams && paletteSlot == o.paletteSlot;
1452 }
1453 };
1454 struct Mesh3dSetKeyHash {
1456 size_t operator()(const Mesh3dSetKey &k) const {
1457 return std::hash<GpuTexture*>()(k.albedo) ^ (std::hash<GpuTexture*>()(k.normal) << 1) ^
1458 (std::hash<GpuTexture*>()(k.env) << 2) ^ (std::hash<GpuTexture*>()(k.height) << 3) ^
1459 (std::hash<GpuTexture*>()(k.reflectionProbe0) << 8) ^
1460 (std::hash<GpuTexture*>()(k.reflectionProbe1) << 9) ^ (std::hash<GpuTexture*>()(k.depth) << 4) ^
1461 (std::hash<GpuTexture*>()(k.sceneColor) << 10) ^ (std::hash<GpuTexture*>()(k.decalAlbedo) << 5) ^
1462 (std::hash<GpuTexture*>()(k.decalNormal) << 6) ^ (std::hash<GpuTexture*>()(k.decalParams) << 7) ^
1463 k.paletteSlot;
1464 }
1465 };
1466 // Per-frame-slot UBO rings, keyed by Present::frames_in_flight so a frame
1467 // never overwrites a UBO that an in-flight frame is still reading.
1468 // Per-draw data is written at dynamic offsets into the ring and the same
1469 // descriptor set (cached per texture combination) is re-bound with a new
1470 // offset, so descriptor-pool usage is bounded by texture count instead of
1471 // growing with draw count.
1472 struct Mesh3dFrameSlots {
1473 vkb::GenericBuffer uboRing; // capacity * mesh3dUboStride bytes
1474 vkb::GenericBuffer shadowRing; // capacity * shadowUboStride bytes
1475 size_t capacity = 0; // per-draw slot count the rings hold
1476 size_t drawIndex = 0;
1477 size_t lastDrawCount = 0;
1478 std::unordered_map<Mesh3dSetKey, vkb::BoundSet, Mesh3dSetKeyHash> sets;
1479 std::map<std::pair<size_t, GpuTexture*>, vkb::BoundSet> skinSets;
1480 std::vector<vkb::GenericBuffer> palettes;
1481 size_t activePalette = 0;
1482 };
1483 std::vector<Mesh3dFrameSlots> mesh3dFrameSlots;
1484 Texture *whiteTexture = nullptr;
1485 Texture *defaultExtrasArray = nullptr;
1486 Texture *defaultColorsArray = nullptr;
1487 Texture *defaultVertexArray = nullptr;
1488 Texture *defaultMotionArray = nullptr;
1489 Texture *defaultVegetationFadeNoise = nullptr;
1491 Texture *defaultBindlessCube = nullptr;
1492 Texture *flatNormalTexture3D = nullptr;
1493 Texture *flatHeightTexture3D = nullptr;
1494 Texture *defaultEnvCubemap = nullptr;
1495 Texture *mesh3dNormalTexture = nullptr;
1496 Texture *mesh3dHeightTexture = nullptr;
1497 Texture *mesh3dEnvTexture = nullptr;
1498 Texture *mesh3dSceneDepthTexture = nullptr;
1499 Texture *mesh3dSceneColorTexture = nullptr;
1500 float mesh3dEnvIntensity = 0.f;
1501 glm::vec3 mesh3dEnvProbeCenter{0.f};
1502 glm::vec3 mesh3dEnvProbeExtent{0.f};
1503 ReflectionProbeUpload mesh3dReflectionProbes{};
1504 float mesh3dMetallic = 0.f;
1505 float mesh3dRoughness = 0.45f;
1506 SurfaceMode mesh3dSurfaceMode = SurfaceMode::Opaque;
1507 BlendMode mesh3dSurfaceBlend = BlendMode::Alpha;
1508 bool mesh3dSurfaceDepthWrite = false;
1509 bool mesh3dSurfaceDoubleSided = false;
1510 float mesh3dAlphaCutoff = 0.5f;
1511 std::string mesh3dAlphaTechnique = "cutoff";
1512 glm::vec4 mesh3dLodFade{1.f, 0.f, 0.f, 0.f};
1513 float mesh3dTexBombScale = 4.f;
1514 float mesh3dTexBombStrength = 0.f;
1515 float mesh3dTexBombRot = 1.f;
1516 float mesh3dParallaxScale = 0.f;
1517 float mesh3dParallaxMinLayers = 8.f;
1518 float mesh3dParallaxMaxLayers = 32.f;
1519 glm::vec4 mesh3dVirtualTexture{0.f};
1520 glm::vec4 mesh3dVirtualAtlas{0.f};
1521 Lighting3DPack mesh3dLighting{};
1522 ShadowUpload mesh3dShadows{};
1523 bool mesh3dShadowReceive = true;
1524 int mesh3dSkinInfluenceLimit = 4;
1525
1526 // Clustered forward (separate set layout / pipeline; default PBR only).
1527 bool mesh3dClusteredActive = false;
1528 ClusteredLightingUpload mesh3dClustered{};
1529 vk::DescriptorSetLayout mesh3dClusteredSetLayout;
1530 vk::UniqueDescriptorSetLayout mesh3dClusteredSetLayoutUnique;
1531 vk::PipelineLayout mesh3dClusteredPipelineLayout;
1532 vk::Pipeline mesh3dClusteredPipeline;
1533 // Per-frame clustered storage (lights / cluster table / light indices),
1534 // multi-buffered so an in-flight frame's forward pass never reads storage
1535 // that the next frame is overwriting.
1536 struct ClusteredStorage {
1537 vkb::GenericBuffer lightsBuf;
1538 vkb::GenericBuffer tableBuf;
1539 vkb::GenericBuffer indicesBuf;
1540 size_t lightsCap = 0;
1541 size_t tableCap = 0;
1542 size_t indicesCap = 0;
1543 };
1544 std::vector<ClusteredStorage> clusteredStorages; // per swapchain frame slot
1545 struct Mesh3dClusteredFrameSlots {
1546 vkb::GenericBuffer uboRing; // capacity * mesh3dClusteredUboStride bytes
1547 vkb::GenericBuffer shadowRing; // capacity * shadowUboStride bytes
1548 size_t capacity = 0;
1549 size_t drawIndex = 0;
1550 size_t lastDrawCount = 0;
1551 std::unordered_map<Mesh3dSetKey, vkb::BoundSet, Mesh3dSetKeyHash> sets;
1552 };
1553 std::vector<Mesh3dClusteredFrameSlots> mesh3dClusteredFrameSlots;
1554
1556 uint32_t mesh3dUboStride = 0;
1557 uint32_t shadowUboStride = 0;
1558 uint32_t mesh3dClusteredUboStride = 0;
1560 vk::Pipeline lastMesh3dPipeline = nullptr;
1561 vk::Pipeline lastMesh3dClusteredPipeline = nullptr;
1562
1563 // Ping-pong copies so frame N+1 can write while frame N still samples.
1564 static constexpr uint32_t kAsyncResourceCopies = 2;
1565
1566 // ---- GPU-driven (stage 0): bindless set + per-frame arena + tables ----
1567 GpuDrivenCaps gpuDrivenCaps_{};
1568 RayTracingCaps rayTracingCaps_{};
1569 std::vector<FrameArena> frameArenas_;
1570
1571 vk::UniqueDescriptorSetLayout bindlessSetLayoutUnique_{};
1572 vk::DescriptorSetLayout bindlessSetLayout_ = nullptr;
1573 vk::DescriptorPool bindlessPool_ = nullptr;
1574 // One bindless set per frame-in-flight slot. A frame rewrites only the set
1575 // belonging to its own slot, and only AFTER acquireForFrame() has waited
1576 // that slot's fence; pending command buffers therefore never observe a
1577 // descriptor set being rewritten (VUID-vkUpdateDescriptorSets-None-03047).
1578 // The texture arrays (bindings 0/1) are mirrored into every set at
1579 // registration time so any slot can sample any registered texture.
1580 std::vector<vk::DescriptorSet> bindlessSets_;
1581 std::vector<GpuTexture *> bindlessTextures2D_;
1582 std::vector<uint32_t> bindlessFree2D_;
1583 std::vector<GpuTexture *> bindlessCubemaps_;
1584 std::vector<uint32_t> bindlessFreeCube_;
1585
1586 vkb::GenericBuffer meshTableBuffer_;
1587 std::vector<GpuMeshRecord> meshTableRecords_;
1589 std::vector<GpuMesh *> meshRecordOwners_;
1590 uint32_t meshTableCapacity_ = 0;
1591
1592 vkb::GenericBuffer materialTableBuffer_;
1593 std::vector<GpuMaterialRecord> materialTableRecords_;
1594 std::vector<uint32_t> materialTableFree_;
1595 std::unordered_map<const Material *, uint32_t> materialTableIndex_;
1596 uint32_t materialTableCapacity_ = 0;
1597
1598 uint32_t registerBindlessTexture2D(GpuTexture *tex);
1599 uint32_t registerBindlessTextureCube(GpuTexture *tex);
1600 void unregisterBindlessTexture(GpuTexture *tex);
1601 uint32_t registerMeshRecord(GpuMesh *gpu, const std::vector<MeshVertex> *vertices = nullptr,
1602 const std::vector<uint32_t> *indices = nullptr);
1603 void syncMeshTable();
1604 GpuMaterialRecord buildMaterialRecord(Material *material);
1605 void createBindlessSet();
1607 vk::DescriptorSet bindlessSetForFrame() const;
1608
1609 // ---- GPU-driven (stage 3): pooled vertices + visibility buffer ----
1611 struct GpuVertexPool {
1612 vkb::GenericBuffer positions; // vec4 per vertex (16B; w unused)
1613 vkb::GenericBuffer normals; // vec4 per vertex
1614 vkb::GenericBuffer uvs; // vec2 per vertex (8B)
1615 vkb::GenericBuffer indices; // uint32 (u16 meshes converted)
1616 uint32_t vertexCount = 0;
1617 uint32_t indexCount = 0;
1618 };
1619 GpuVertexPool gpuVertexPool_;
1620 void ensureGpuVertexPool();
1621 void growGpuVertexPool(uint32_t needVertices, uint32_t needIndices);
1623 void bindGpuVertexPoolBindless();
1624 void appendGpuMeshToPool(GpuMesh &gpu, const std::vector<MeshVertex> *vertices = nullptr,
1625 const std::vector<uint32_t> *indices = nullptr);
1626
1627 // ---- GPU-driven (stage 3): virtual geometry ----
1628 static constexpr uint32_t kMaxVgAssets = 64;
1629 static constexpr uint32_t kMaxVgClusters = 65536;
1630 struct VgGpuBuffers {
1631 vkb::GenericBuffer positions; // float xyz stream (growable)
1632 vkb::GenericBuffer triangles; // u32 global triangle stream
1633 vkb::GenericBuffer clusters; // GpuVgCluster (4 x uvec4)
1634 vkb::GenericBuffer clusterAssets; // u32 per cluster -> asset id
1635 vkb::GenericBuffer visible; // kAsyncResourceCopies x (counter + ids)
1636 vkb::GenericBuffer indirect; // kAsyncResourceCopies x VkDrawIndirectCommand
1637 vkb::GenericBuffer assetMaterials; // kAsyncResourceCopies x u32 per asset
1638 vkb::GenericBuffer assetModels; // kAsyncResourceCopies x mat4 per asset
1639 };
1640 VgGpuBuffers vgGpu_;
1641 uint32_t vgClusterCount_ = 0; // total clusters across uploaded assets
1642 uint32_t vgAssetCount_ = 0;
1643 uint32_t vgVertexCount_ = 0; // global position-stream vertices
1644 uint32_t vgTriangleCount_ = 0; // global triangle-stream indices
1645 uint32_t vgLastVisible_ = 0;
1646 bool vgAnyThisFrame_ = false;
1647 ComputePass vgCullPass_;
1648 vk::Pipeline gbufferVgVisPipeline = nullptr;
1649 void ensureVgBuffers();
1650 void growVgBuffers(uint32_t needClusters, uint32_t needVertices, uint32_t needTriangles);
1652 void bindVgPoolBindless();
1654 void bindVgFrameBindless(vk::DescriptorSet bindless, size_t slot);
1656 void recordVgCull();
1658 void drawVgClusters(vk::CommandBuffer cb);
1659
1660 // ---- GPU-driven (stage 1): opaque forward path ----
1661 bool gpuDrivenEnabled_ = false;
1662 uint32_t lastGpuDrivenDrawCount_ = 0;
1663 vk::PipelineLayout mesh3dGpuDrivenPipelineLayout = nullptr;
1664 vk::Pipeline mesh3dGpuDrivenPipeline = nullptr;
1665 vk::Pipeline resolveVisPipeline = nullptr;
1666 // Phase C: Hybrid clustered deferred lighting (fullscreen into scene color).
1667 vk::DescriptorSetLayout deferredLightingSetLayout{};
1668 vk::UniqueDescriptorSetLayout deferredLightingSetLayoutUnique;
1669 vk::PipelineLayout deferredLightingPipelineLayout{};
1670 vk::Pipeline deferredLightingPipeline{};
1671 vkb::GenericBuffer deferredLightingUbo{};
1672 vk::DescriptorSet deferredLightingSet{};
1673 vk::Sampler deferredLightingSampler{};
1674 void createMesh3DGpuDrivenPipeline();
1676 struct GpuDrivenFrameSet0 {
1677 vk::DescriptorSet set;
1678 uint32_t uboOffset = 0;
1679 uint32_t shadowOffset = 0;
1680 };
1681 GpuDrivenFrameSet0 gpuDrivenFrameSet0();
1682 void createResolveVisPipeline(const vkb::BuiltRenderPass &rp,
1683 vk::SampleCountFlagBits samples);
1685 void initGpuDrivenResources();
1687 void createGpuDrivenVisResources(int width, int height);
1688
1689 // ---- GPU-driven (stage 2): HZB + GPU cull ----
1690 struct GpuDrivenCullSlot {
1691 vkb::GenericBuffer visibleFlags; // uint32 per instance (GPU-written)
1692 vkb::GenericBuffer compacted; // GpuInstance per instance (GPU-written)
1693 vkb::GenericBuffer indirect; // GpuIndirectCommand per bucket (GPU-written)
1694 vkb::GenericBuffer indirectNI; // VkDrawIndirectCommand per bucket (non-indexed)
1695 vkb::GenericBuffer bucketCounters; // uint32 per bucket (GPU atomic, CPU-reset)
1696 vkb::GenericBuffer hzb; // header + R32F mip chain (GPU-written)
1697 vkb::GenericBuffer cullParams; // GpuCullParams UBO (CPU-written)
1698 };
1699 std::vector<GpuDrivenCullSlot> gpuDrivenCullSlots_;
1700 vkb::GenericBuffer gpuDrivenCullParamsPlaceholder_; // valid UBO target at set creation
1701 int gpuDrivenCullWidth = 0;
1702 int gpuDrivenCullHeight = 0;
1703 uint32_t gpuDrivenCullMaxMip = 0;
1704 vk::PipelineLayout gpuDrivenComputeLayout = nullptr;
1705 vk::DescriptorSetLayout gpuDrivenComputeEmptyLayout_ = nullptr;
1706 ComputePass hzbBuildPass_;
1707 ComputePass cullPass_;
1708 ComputePass emitPass_;
1709 bool gpuDrivenCullReady_ = false;
1710 bool gpuDrivenScenePassPending_ = false;
1711 // Per-frame CPU metadata for the cull chain (uploaded to the frame arena).
1712 std::vector<uint32_t> gpuDrivenBucketIds_;
1713 std::vector<uint32_t> gpuDrivenBucketOffsets_;
1714 std::vector<uint32_t> gpuDrivenBucketMeshIds_;
1715 uint32_t gpuDrivenBucketCount_ = 0;
1716 uint32_t gpuDrivenCullInstanceCount_ = 0;
1717 uint32_t gpuDrivenLastCullSlot_ = 0;
1718 FrameArena::Alloc gpuDrivenInstAlloc_{};
1719 FrameArena::Alloc gpuDrivenBucketIdAlloc_{};
1720 FrameArena::Alloc gpuDrivenBucketOffAlloc_{};
1721 void ensureGpuDrivenCullResources(int width, int height);
1722 void recordGpuDrivenHzbBuild();
1723 void gpuDrivenRecordComputeSection(const glm::mat4 &viewProj, const glm::vec3 &eye,
1724 float fovYDeg, float nearZ, float farZ);
1725 void destroyGpuDrivenCullResources();
1726 GpuDrivenCullSlot &currentGpuDrivenCullSlot();
1727 GpuDrivenCullSlot &gpuDrivenCullSlot(uint32_t frameSlot);
1728
1729 // CSM shadow map (3 cascade layers), one array per in-flight slot.
1730 struct ShadowMapSlot {
1731 vkb::DepthArrayImage image;
1732 vk::Framebuffer framebuffers[ShadowConfig::kTotalLayers]{};
1733 };
1734 std::vector<ShadowMapSlot> shadowMaps;
1735 vkb::DepthSampler shadowSampler{};
1736 vk::Sampler shadowRawSampler{};
1737 vkb::BuiltRenderPass shadowRenderPass{};
1738 vk::PipelineLayout shadowPipelineLayout{};
1739 vk::Pipeline shadowPipeline{};
1740 vk::Pipeline shadowSingleSidedPipeline{};
1741 vk::PipelineLayout shadowAlphaPipelineLayout{};
1742 vk::Pipeline shadowAlphaPipeline{};
1743 vk::Pipeline shadowAlphaSingleSidedPipeline{};
1744 vk::PipelineLayout skinPassPipelineLayout{};
1745 vk::DescriptorSetLayout skinPassSetLayout{};
1746 vk::UniqueDescriptorSetLayout skinPassSetLayoutUnique;
1747 vk::Pipeline shadowSkinPipeline{};
1748 vk::Pipeline shadowSkinSingleSidedPipeline{};
1749 vk::Pipeline shadowSkinAlphaPipeline{};
1750 vk::Pipeline shadowSkinAlphaSingleSidedPipeline{};
1751 int shadowPassCascade = -1;
1752 struct ShadowDraw {
1753 Mesh *mesh = nullptr;
1754 glm::mat4 mvp{1.f};
1755 Texture *albedo = nullptr;
1756 bool alphaTest = false; // use the alpha-cutout shadow pipeline
1757 bool doubleSided = true;
1758 glm::vec4 lodFade{1.f, 0.f, 0.f, 0.f};
1759 vk::DescriptorSet skinSet{};
1760 uint32_t skinUboOffset = 0;
1761 };
1762 struct ShadowAlphaPush {
1763 glm::mat4 mvp{1.f};
1764 glm::vec4 lodFade{1.f, 0.f, 0.f, 0.f};
1765 };
1766 std::vector<ShadowDraw> shadowPassDraws;
1767 std::vector<ShadowDraw> shadowCascadeDraws[ShadowConfig::kTotalLayers];
1768 uint32_t shadowPendingMask = 0;
1769 ShadowMapSlot &currentShadowMap();
1770 vk::ImageView currentShadowArrayView();
1771
1772 // Screen-space G-buffer (normal / linear-depth / albedo + HW depth).
1773 struct GBufferPush {
1774 glm::mat4 mvp{1.f};
1775 glm::vec4 modelR0{1.f, 0.f, 0.f, 0.f};
1776 glm::vec4 modelR1{0.f, 1.f, 0.f, 0.f};
1777 glm::vec4 modelR2{0.f, 0.f, 1.f, 0.f};
1778 glm::vec4 clip{0.1f, 100.f, 0.f, 0.f};
1779 };
1780 static_assert(sizeof(GBufferPush) == 128, "GBuffer push constants must be 128 bytes");
1781 struct GBufferDraw {
1782 Mesh *mesh = nullptr;
1783 Texture *albedo = nullptr;
1784 GBufferPush push{};
1785 bool alphaTest = false; // use the alpha-cutout gbuffer pipeline
1786 vk::DescriptorSet skinSet{};
1787 uint32_t skinUboOffset = 0;
1788 };
1789 struct GBufferSlot {
1790 vkb::ColorTarget normal;
1791 vkb::ColorTarget depthColor;
1792 vkb::ColorTarget albedo;
1793 vkb::ColorTarget pbrParams; // RGBA8: metallic, roughness, occlusion, specularFactor
1794 vkb::ColorTarget emissive; // RGB emissive (A unused)
1795 vkb::ColorTarget visID; // R32G32UI: x = instance, y = pooled index offset
1796 vkb::ColorTarget visBary; // R16G16F: barycentric (u, v)
1797 vkb::DepthTarget depth;
1798 vk::Framebuffer framebuffer{};
1799 vk::Framebuffer visFramebuffer{};
1800 GpuTexture normalGpu{};
1801 GpuTexture depthColorGpu{};
1802 GpuTexture albedoGpu{};
1803 GpuTexture pbrParamsGpu{};
1804 GpuTexture emissiveGpu{};
1805 GpuTexture visIDGpu{};
1806 GpuTexture visBaryGpu{};
1807 GpuTexture depthGpu{};
1808 Texture normalTex{};
1809 Texture depthColorTex{};
1810 Texture albedoTex{};
1811 Texture pbrParamsTex{};
1812 Texture emissiveTex{};
1813 Texture visIDTex{};
1814 Texture visBaryTex{};
1815 Texture depthTex{};
1816 };
1817 int gbufferWidth = 0;
1818 int gbufferHeight = 0;
1819 std::vector<GBufferSlot> gbufferSlots;
1820 vkb::BuiltRenderPass gbufferRenderPass{};
1821 vkb::BuiltRenderPass gbufferVisRenderPass{};
1822 vk::PipelineLayout gbufferPipelineLayout{};
1823 vk::Pipeline gbufferPipeline{};
1824 vk::Pipeline gbufferAlphaPipeline{};
1825 vk::Pipeline gbufferSkinPipeline{};
1826 vk::Pipeline gbufferSkinAlphaPipeline{};
1827 vk::Pipeline gbufferVisPipeline = nullptr;
1828 bool gbufferPassActive = false;
1829 bool gbufferPending = false;
1830 std::vector<GBufferDraw> gbufferPassDraws;
1831 GBufferSlot *currentGBufferSlot();
1832
1833 // Screen-space decal layer: box-projected decals write albedo/normal/params
1834 // targets after the G-buffer; mesh3d.frag samples them before lighting.
1836 struct DecalInstanceData {
1837 glm::mat4 model{1.f};
1838 glm::vec4 uvRect{0.f, 0.f, 1.f, 1.f};
1839 glm::vec4 fadeParams{1.f, 0.f, 0.f, 0.f}; // fade, normalStrength, roughStrength, metalStrength
1840 glm::vec4 extraParams{0.f, 0.f, 0.f, 0.f}; // emissive, blendMode, projectionMode, sharpness
1841 glm::vec4 surfaceParams{0.f, 8.f, 24.f, 0.06f}; // POM scale/min/max, edge fade width
1842 };
1843 static_assert(sizeof(DecalInstanceData) == 128, "DecalInstanceData must be 128 bytes");
1844 struct DecalCameraUBO {
1845 glm::mat4 viewProj{1.f};
1846 glm::mat4 invViewProj{1.f};
1847 glm::vec4 nearFarTexel{0.1f, 100.f, 0.f, 0.f}; // x=near, y=far, z=1/w, w=1/h
1848 };
1850 static constexpr size_t kMaxDecalInstances = 512;
1851 struct DecalDraw {
1852 glm::mat4 model{1.f};
1853 Texture *albedo = nullptr;
1854 Texture *normal = nullptr;
1855 Texture *params = nullptr;
1856 float uvRect[4] = {0.f, 0.f, 1.f, 1.f};
1857 float fade = 1.f;
1858 float normalStrength = 0.f;
1859 float roughnessStrength = 0.f;
1860 float metalStrength = 0.f;
1861 float emissiveStrength = 0.f;
1862 int blendMode = 0; // 0 = premultiplied over, 1 = additive (emissive)
1863 int projectionMode = 0; // 0 = planar, 1 = local triplanar, 2 = spherical, 3 = world-aligned
1864 float blendSharpness = 4.f;
1865 float parallaxScale = 0.f;
1866 float parallaxMinLayers = 8.f;
1867 float parallaxMaxLayers = 24.f;
1868 float edgeFadeWidth = 0.06f;
1869 };
1870 struct DecalSetKey {
1871 GpuTexture *albedo = nullptr;
1872 GpuTexture *normal = nullptr;
1873 GpuTexture *params = nullptr;
1874 GpuTexture *depth = nullptr;
1875 GpuTexture *gbNormal = nullptr;
1877 bool operator==(const DecalSetKey &o) const {
1878 return albedo == o.albedo && normal == o.normal && params == o.params &&
1879 depth == o.depth && gbNormal == o.gbNormal;
1880 }
1881 };
1882 struct DecalSetKeyHash {
1884 size_t operator()(const DecalSetKey &k) const {
1885 return std::hash<GpuTexture *>()(k.albedo) ^
1886 (std::hash<GpuTexture *>()(k.normal) << 1) ^
1887 (std::hash<GpuTexture *>()(k.params) << 2) ^
1888 (std::hash<GpuTexture *>()(k.depth) << 3) ^
1889 (std::hash<GpuTexture *>()(k.gbNormal) << 4);
1890 }
1891 };
1892 struct DecalSlot {
1893 vkb::ColorTarget albedo;
1894 vkb::ColorTarget normal;
1895 vkb::ColorTarget params;
1896 vk::Framebuffer framebuffer{};
1897 GpuTexture albedoGpu{};
1898 GpuTexture normalGpu{};
1899 GpuTexture paramsGpu{};
1900 Texture albedoTex{};
1901 Texture normalTex{};
1902 Texture paramsTex{};
1903 vkb::GenericBuffer cameraUbo; // capacity 1 per frame slot
1904 std::unordered_map<DecalSetKey, vkb::BoundSet, DecalSetKeyHash> sets;
1905 };
1906 int decalWidth = 0;
1907 int decalHeight = 0;
1908 std::vector<DecalSlot> decalSlots;
1909 vkb::BuiltRenderPass decalRenderPass{};
1910 vk::DescriptorSetLayout decalSetLayout;
1911 vk::UniqueDescriptorSetLayout decalSetLayoutUnique;
1912 vk::PipelineLayout decalPipelineLayout{};
1913 vk::Pipeline decalPipeline{};
1914 bool decalPassActive = false;
1915 bool decalPending = false;
1918 bool decalLayerFresh = false;
1919 std::vector<DecalDraw> decalPassDraws;
1920 vk::Pipeline lastDecalPipeline = nullptr;
1921 Mesh *decalUnitBox = nullptr;
1923 Texture *decalFlatAlbedo = nullptr;
1924 Texture *decalFlatNormal = nullptr;
1925 Texture *decalFlatParams = nullptr;
1926 glm::mat4 decalViewProj{1.f};
1927 float decalNear = 0.1f;
1928 float decalFar = 100.f;
1929 // One FrameGraph per in-flight slot for the deferred passes: the 3 CSM
1930 // shadow cascades + the G-buffer fill are declarative passes in one layer,
1931 // recorded concurrently on JobSystem workers. Each graph's command buffer
1932 // is only reused two frames later — by then the present slot fence (waited
1933 // in Present::begin) guarantees the previous graph submit has completed
1934 // (same queue, submitted before the present command buffer). The graphs
1935 // import the engine-owned shadow array + ColorTarget images; the engine
1936 // keeps ownership so readback / entity-ID rendering / postFX wrappers keep
1937 // working unchanged.
1938 std::array<std::unique_ptr<vkb::FrameGraph>, kAsyncResourceCopies> deferredFrameGraphs_;
1939 vkb::FrameGraph *currentDeferredFrameGraph();
1941 bool deferredGraphRecorded_ = false;
1942 size_t deferredGraphRecordedSlot_ = 0;
1944 void buildDeferredFrameGraphs();
1949 void resetDeferredFrameGraphs();
1951 void recordShadowCascadePass(vkb::FrameGraphPassContext &ctx, int cascade);
1953 void recordGBufferPassDraws(vkb::FrameGraphPassContext &ctx);
1954
1955 struct SceneColorSlot {
1956 vkb::ColorTarget msaaColor;
1957 vkb::ColorTarget color;
1958 vkb::DepthTarget depth;
1959 vk::Framebuffer framebuffer{};
1960 GpuTexture colorGpu{};
1961 Texture colorTex{};
1962 };
1963 int sceneColorWidth = 0;
1964 int sceneColorHeight = 0;
1965 vk::Format sceneColorFormat = vk::Format::eUndefined;
1966 vk::SampleCountFlagBits sceneColorSamples = vk::SampleCountFlagBits::e1;
1967 std::vector<SceneColorSlot> sceneColorSlots;
1968 size_t completedSceneColorSlot = 0;
1969 bool sceneColorHistoryValid = false;
1970 vkb::BuiltRenderPass sceneColorRenderPass{};
1971 vk::RenderPass sceneColorResumeRenderPass{};
1972 bool sceneColorPassOpen = false;
1973 vk::RenderPass scenePassPipelineTarget = vk::RenderPass{};
1974 vk::SampleCountFlagBits scenePassPipelineSamples = vk::SampleCountFlagBits::e1;
1975 int appliedMsaa = -1;
1976 SceneColorSlot *currentSceneColorSlot();
1977
1978 // Offscreen 3D render-to-canvas (color + D32 depth) used for planar
1979 // reflection / render targets. Rendered on a dedicated command buffer and
1980 // submitted directly to the graphics queue (no swapchain / present).
1981 vkb::BuiltRenderPass offscreen3DRenderPass{};
1982 vkb::BuiltRenderPass hdrOffscreen3DRenderPass{};
1983 vk::Pipeline offscreen3DMeshPipeline = nullptr;
1984 vk::Pipeline hdrOffscreen3DMeshPipeline = nullptr;
1985 std::array<vk::Pipeline, kMesh3DPipelineVariants> offscreen3DSurfacePipelines{};
1986 std::array<vk::Pipeline, kMesh3DPipelineVariants> hdrOffscreen3DSurfacePipelines{};
1987 vk::UniqueDescriptorSetLayout reflectionProbeFilterSetLayout;
1988 vk::UniquePipelineLayout reflectionProbeFilterPipelineLayout;
1989 ComputePass reflectionProbeFilterPass;
1990 vk::CommandPool offscreen3DPool = nullptr;
1991 vk::CommandBuffer offscreen3DCB = nullptr;
1992 vk::Fence offscreen3DFence = nullptr;
1993 vk::QueryPool offscreen3DTimestampQueryPool = nullptr;
1994 float offscreen3DTimestampPeriodNs = 0.f;
1995 float lastOffscreen3DGpuDurationMs = 0.f;
1996 bool offscreen3DPassOpen = false;
1997 bool offscreen3DHDRActive = false;
1998 OffscreenCanvas *offscreen3DCanvas = nullptr;
1999
2000 // Dedicated 4x-MSAA color target for the UI overlay (ImGui), resolved to a
2001 // single-sample texture that is composited as the top-most fullscreen quad.
2002 struct UiColorSlot {
2003 vkb::ColorTarget msaaColor;
2004 vkb::ColorTarget color;
2005 vk::Framebuffer framebuffer{};
2006 GpuTexture colorGpu{};
2007 Texture colorTex{};
2008 };
2009 int uiColorWidth = 0;
2010 int uiColorHeight = 0;
2011 vk::Format uiColorFormat = vk::Format::eUndefined;
2012 vk::SampleCountFlagBits uiColorSamples = vk::SampleCountFlagBits::e1;
2013 std::vector<UiColorSlot> uiColorSlots;
2014 vkb::BuiltRenderPass uiRenderPass{};
2015 vk::Pipeline uiTexturePipeline{};
2016 vk::Pipeline uiTextureOpaquePipeline{};
2017 UiColorSlot *currentUiColorSlot();
2018
2019 // Linear HDR compose target: scene + overlays blend in paper-white-relative
2020 // display-linear space, then a single fullscreen tonemap encodes to the
2021 // HDR10/scRGB swapchain.
2022 struct PresentComposeSlot {
2023 vkb::ColorTarget color;
2024 vk::Framebuffer framebuffer{};
2025 GpuTexture colorGpu{};
2026 Texture colorTex{};
2027 };
2028 int presentComposeWidth = 0;
2029 int presentComposeHeight = 0;
2030 std::vector<PresentComposeSlot> presentComposeSlots;
2031
2032 vkb::Present presentModel;
2033 vkb::RecordingCmd presentRecording;
2034 vkb::InRenderPass swapchainPass;
2035 vkb::DepthStencilImage depthImage;
2036 vk::Format depthFormat = vk::Format::eD32Sfloat;
2037
2038 // GPU timestamp queries (one pool of 2: [0]=frame begin, [1]=frame end).
2039 vk::QueryPool gpuQueryPool_{};
2040 float timestampPeriod_ = 1.f;
2041 bool gpuTimingReady_ = false;
2042 float gpuFrameMs_ = 0.f;
2043
2044 struct SolidBatch {
2045 BlendMode blend = BlendMode::Alpha;
2046 Batcher batch;
2047 };
2048 std::vector<SolidBatch> solidBatches;
2049 struct TexturedBatch {
2051 enum class Effect { Default, SceneColorDistortion, DisplayEncode };
2052 Texture *texture = nullptr;
2053 Texture *depth = nullptr;
2054 Shader *shader = nullptr;
2055 BlendMode blend = BlendMode::Alpha;
2056 Batcher batch;
2057 Effect effect = Effect::Default;
2058 Texture *motion = nullptr;
2059 Texture *extra = nullptr;
2060 Texture *specular = nullptr;
2061 };
2062 std::vector<TexturedBatch> texturedBatches;
2063
2064 std::vector<LitBatch> litBatches;
2065
2066 enum class OverlayKind : uint8_t { Solid, Textured, Lit, GpuParticles };
2067 struct OverlaySpan {
2068 OverlayKind kind = OverlayKind::Solid;
2069 uint32_t index = 0;
2070 uint32_t vertBegin = 0;
2071 uint32_t vertCount = 0;
2072 };
2073 std::vector<OverlaySpan> overlaySpans;
2074 std::vector<OverlaySpan> engine3DSpans;
2075 std::optional<TexturedBatch> pendingSceneResolve;
2076 Texture *pendingSceneResolveSource = nullptr;
2077 std::optional<TexturedBatch> pendingUiResolve;
2078 bool sceneColorComposited = false;
2079
2080 struct GpuParticleDrawRequest {
2082 GpuParticleDraw draw;
2083 };
2084 std::unordered_map<GpuParticleHandle, GpuParticleResource*> gpuParticles_;
2085 std::vector<GpuParticleDrawRequest> gpuParticleDraws_;
2086 GpuParticleHandle nextGpuParticleHandle_ = 1;
2087 vk::DescriptorSetLayout gpuParticleComputeSetLayout_{};
2088 vk::DescriptorSetLayout gpuParticleDrawSetLayout_{};
2089 vk::DescriptorSetLayout gpuParticleSortSetLayout_{};
2090 vk::PipelineLayout gpuParticleComputeLayout_{};
2091 vk::PipelineLayout gpuParticleDrawLayout_{};
2092 vk::PipelineLayout gpuParticleSortLayout_{};
2093 vk::Pipeline gpuParticleComputePipeline_{};
2094 vk::Pipeline gpuParticleSortPipeline_{};
2095 vk::Pipeline gpuParticleAlphaPipeline_{};
2096 vk::Pipeline gpuParticleAdditivePipeline_{};
2097 vk::Pipeline gpuParticlePremultipliedPipeline_{};
2098 vk::Pipeline gpuParticleMultiplyPipeline_{};
2099 vk::Pipeline gpuParticleOpaquePipeline_{};
2100
2101 // Persistent host-visible vertex buffers for 2D batching, reused across
2102 // frames. GenericBuffer now owns the Vulkan handles.
2103 struct Frame2DBuffers {
2104 std::vector<vkb::HostVertexBuffer> solidBufs;
2105 std::vector<vkb::HostVertexBuffer> texBufs;
2106 std::vector<vkb::HostVertexBuffer> uiTexBufs;
2107 std::vector<vkb::HostVertexBuffer> primitive3DBufs;
2108 std::size_t primitive3DDrawIndex = 0;
2109 };
2110 std::vector<Frame2DBuffers> frame2dBuffers; // per swapchain frame slot
2111 Frame2DBuffers offscreenBuffers; // synchronous offscreen path
2112
2113 vk::DescriptorSetLayout lit2dSetLayout;
2114 vk::UniqueDescriptorSetLayout lit2dSetLayoutUnique;
2115 vk::PipelineLayout lit2dPipelineLayout;
2116 vk::Pipeline lit2dPipeline;
2117 vk::Pipeline lit2dAdditivePipeline;
2118 vk::Pipeline lit2dPremultipliedPipeline;
2119 vk::Pipeline lit2dMultiplyPipeline;
2120 vk::Pipeline lit2dOpaquePipeline;
2121 vk::Pipeline offscreenLitPipeline;
2122 vk::Pipeline offscreenLitAdditivePipeline;
2123 vk::Pipeline offscreenLitPremultipliedPipeline;
2124 vk::Pipeline offscreenLitMultiplyPipeline;
2125 vk::Pipeline offscreenLitOpaquePipeline;
2127 vk::Pipeline selectLit2DPipeline(BlendMode blend, bool offscreen, bool hdr = false) const;
2128 std::vector<vkb::GenericBuffer> lighting2dUboSlots; // per swapchain frame slot
2129 vkb::GenericBuffer offscreenLighting2dUbo; // synchronous offscreen path
2130 Lighting2DUBO lighting2dFrame{};
2131 struct LitSetKey {
2132 GpuTexture *albedo = nullptr;
2133 GpuTexture *normal = nullptr;
2135 bool operator==(const LitSetKey &o) const {
2136 return albedo == o.albedo && normal == o.normal;
2137 }
2138 };
2139 struct LitSetKeyHash {
2141 size_t operator()(const LitSetKey &k) const {
2142 return std::hash<void *>()(k.albedo) ^ (std::hash<void *>()(k.normal) << 1);
2143 }
2144 };
2145 struct PostSetKey {
2146 GpuTexture *color = nullptr;
2147 GpuTexture *depth = nullptr;
2148 GpuTexture *motion = nullptr;
2149 GpuTexture *extra = nullptr;
2150 GpuTexture *specular = nullptr;
2152 bool operator==(const PostSetKey &o) const {
2153 return color == o.color && depth == o.depth && motion == o.motion && extra == o.extra &&
2154 specular == o.specular;
2155 }
2156 };
2157 struct PostSetKeyHash {
2159 size_t operator()(const PostSetKey &k) const {
2160 return std::hash<void *>()(k.color) ^ (std::hash<void *>()(k.depth) << 1) ^
2161 (std::hash<void *>()(k.motion) << 2) ^
2162 (std::hash<void *>()(k.extra) << 3) ^
2163 (std::hash<void *>()(k.specular) << 4);
2164 }
2165 };
2166 std::vector<std::unordered_map<LitSetKey, vkb::BoundSet, LitSetKeyHash>> lit2dSets;
2167 std::unordered_map<LitSetKey, vkb::BoundSet, LitSetKeyHash> offscreenLit2dSets;
2168 std::unordered_map<PostSetKey, vkb::BoundSet, PostSetKeyHash> post2Sets;
2169 Texture *flatNormalTexture = nullptr;
2170
2171 Color clearColor{0.1f, 0.1f, 0.12f, 1.0f};
2172 bool hasPendingClear = true;
2173
2174 std::vector<std::unique_ptr<Texture>> ownedTextures;
2175 std::vector<std::unique_ptr<GpuTexture>> ownedGpuTextures;
2177 std::unordered_map<std::string, Texture *> texturesByPath;
2178 std::unordered_map<std::string, Texture *> sharedTexturesByContent;
2179 std::vector<std::unique_ptr<Mesh>> ownedMeshes;
2180 std::vector<std::unique_ptr<GpuMesh>> ownedGpuMeshes;
2181 std::vector<std::unique_ptr<Shader>> ownedShaders;
2182 std::vector<std::unique_ptr<GpuShader>> ownedGpuShaders;
2183 std::vector<std::unique_ptr<eve::graphics::Canvas>> ownedCanvases;
2184
2185 bool swapchainPassOpen = false;
2186 bool flushingSwapchain_ = false;
2187 Mesh3DUBO mesh3dFrameUbo{};
2188
2189 // Instanced voxel face rectangles (packed uint32 instances).
2190 struct VoxelRectPC {
2191 glm::mat4 viewProj{1.f};
2192 glm::vec4 chunkOrigin{0.f}; // xyz = origin, w = faceDir
2193 glm::vec4 atlasInfo{16.f, 0.f, 0.f, 0.f};
2194 glm::vec4 tint{1.f};
2195 };
2196 vk::DescriptorSetLayout voxelRectSetLayout{};
2197 vk::UniqueDescriptorSetLayout voxelRectSetLayoutUnique;
2198 vk::PipelineLayout voxelRectPipelineLayout{};
2199 vk::Pipeline voxelRectPipeline{};
2200 vkb::GenericBuffer voxelUnitQuadVerts;
2201 vkb::GenericBuffer voxelUnitQuadIndices;
2202 bool voxelUnitQuadReady = false;
2203 std::unordered_map<GpuTexture *, vkb::BoundSet> voxelRectSets;
2204 // Grow-only instance buffer pool (reset index each begin3DFrame), per
2205 // swapchain frame slot for async safety.
2206 struct VoxelInstanceSlot {
2207 vkb::GenericBuffer buffer;
2208 size_t capacityBytes = 0;
2209 vkb::GenericBuffer aoBuffer;
2210 size_t aoCapacityBytes = 0;
2211 };
2212 struct VoxelInstanceFrame {
2213 std::vector<VoxelInstanceSlot> slots;
2214 size_t drawIndex = 0;
2215 };
2216 std::vector<VoxelInstanceFrame> voxelInstanceFrames; // per swapchain frame slot
2217
2218 Frame2DBuffers &currentFrame2DBuffers();
2219 Mesh3dFrameSlots &currentMesh3dFrameSlots();
2220 Mesh3dClusteredFrameSlots &currentMesh3dClusteredFrameSlots();
2221 vkb::GenericBuffer &currentLighting2dUbo();
2222 std::unordered_map<LitSetKey, vkb::BoundSet, LitSetKeyHash> &currentLit2dSets();
2223 ClusteredStorage &currentClusteredStorage();
2224 VoxelInstanceFrame &currentVoxelInstanceFrame();
2225 uint32_t frameSlotCount() const;
2226 size_t currentFrameSlot() const;
2227 vk::CommandBuffer &currentPresentCb();
2228 vkb::FrameSlot frameToken() const;
2229 void invalidateTextureBindings();
2230};
2231
2232} // namespace eve::graphics::vulkan
LogicalId target
bool & active
float w
Definition AnimClip.cpp:738
float y
Definition AnimClip.cpp:738
float x
Definition AnimClip.cpp:738
std::vector< BuildingInstanceSnapshot > instances
float normalStrength
float cx
Definition CardTypes.cpp:33
float cy
Definition CardTypes.cpp:34
float degrees
Definition CardTypes.cpp:35
graphics::Texture * albedo
#define EVENGINE_API_BACKENDS
Definition Export.h:108
std::string layout
std::uint32_t vertexCount
std::uint32_t indexCount
const GltfImportRequest & request
vkb::Device & device
vk::ShaderModule vert
vk::ShaderModule frag
std::uint32_t spawnCount
std::uint32_t instanceCount
std::uint32_t capacity
vk::UniqueSampler sampler
vk::UniqueImage image
glm::vec4 clip
glm::vec4 tint
glm::mat4 mvp
std::vector< std::uint32_t > indices
std::vector< float > normals
std::vector< float > positions
std::int32_t first
float blend
int h
std::uint32_t height
std::uint32_t width
TokenKind kind
std::array< float, 3 > scale
std::string name
MeleePoint3 b
Definition MeleeHit.cpp:41
std::vector< TriangleRef > triangles
MeshVfxBatchedDraw draw
float roughness
bool doubleSided
Texture * normal
float alphaCutoff
float metallic
std::vector< std::weak_ptr< DeviceBytes > > resources
Definition OnnxGpgpu.cpp:55
std::unique_ptr< gpgpu::GpuBuffer > buffer
Definition OnnxGpgpu.cpp:26
std::unique_ptr< ParticleEffect > effect
eve::action::ActionVfxBinding binding
std::vector< Point > vertices
PrimitiveHandle handle
int detail
bool lodFadeReverse
glm::vec3 eye
Mesh * mesh
float lodWeight
glm::mat4 viewProj
Shader * shader
glm::mat4 view
glm::mat4 model
Material * material
Color clearColor
bool repeatV
bool repeatU
LocalPageCacheEntry slots[ShadowConfig::kLocalSlots]
std::uint32_t count
float opacity
bool visible
int caps
Definition TreeMesh.cpp:162
V3 dir
Definition TreeMesh.cpp:150
uint32_t index
const UnitySourceAsset & source
std::uint32_t depth
Move-only operation result carrying either a value or Status.
Definition Result.h:155
Accumulates solid / textured quads in logical (Y-down) coordinates. Used by RenderSystem; not a publi...
Definition Batcher.h:24
Canvas public API.
Definition Canvas.h:17
virtual void draw(Drawable *drawable, const glm::mat4 &m)
Draws .
virtual void setVSync(bool enabled)
Prefer uncapped present (IMMEDIATE/MAILBOX) when false, vsync (MAILBOX/FIFO) when true....
Definition Graphics.h:1528
virtual void setMsaaSamples(int samples)
Hardware MSAA sample count for the 3D scene color pass (0 disables, then 2/4/8 are used when the devi...
Definition Graphics.h:1541
SceneToneMapping
Final display mapping; None preserves linear color, Aces uses the fitted curve, and Filmic uses Rec....
Definition Graphics.h:1325
Mesh3DSceneColorCaptureStatus
Observable result of requesting a same-frame mesh SceneColor snapshot.
Definition Graphics.h:1168
virtual void setScreenReadbackEnabled(bool enabled)
When true, each present copies the swapchain to a CPU buffer for getPixel/newImageData....
Definition Graphics.h:1502
Packages shading method + surface parameters into one attachable asset.
Definition Material.h:35
GPU mesh handle (+ optional CPU morph targets).
Definition Mesh.h:25
Frame-local Skia-style recorder for 2D line primitives.
Frame-local scene recorder for 3D line primitives.
Custom GPU program.
Definition Shader.h:39
GPU texture created via Graphics::newTexture. Owns GPU resources through an opaque backend handle.
Definition Texture.h:18
Per-frame GPU allocation arena (host-visible coherent).
Definition FrameArena.h:18
EVENGINE_API_BACKENDS public API.
Definition Graphics.h:342
float getSceneAutoExposureMinEV() const override
Returns the scene auto exposure min ev.
Definition Graphics.h:907
float getSceneDofFocusRange() const override
Returns the scene dof focus range.
Definition Graphics.h:933
bool supportsGpuParticles() const override
Supports gpu particles.
Definition Graphics.h:478
vkb::Instance & getInstance()
Returns the instance.
Definition Graphics.h:1067
float getSceneBloomThreshold() const override
Returns the scene bloom threshold.
Definition Graphics.h:918
uint32_t bindlessSlot2D(const GpuTexture *tex) const
Bindless slot 2 d.
Definition Graphics.h:434
bool gpuDrivenCullEnabled() const
Stage 2 cull is live for this frame (GPU-written commands).
Definition Graphics.h:507
bool supportsRayTracing() const override
Supports ray tracing.
Definition Graphics.h:422
float getSceneTransitionVignette() const override
Returns the scene transition vignette.
Definition Graphics.h:891
float getSceneBloomIntensity() const override
Returns the scene bloom intensity.
Definition Graphics.h:916
float getSceneTransitionLensScale() const override
Returns the scene transition lens scale.
Definition Graphics.h:897
float getSceneDofFarZ() const override
Returns the scene dof far z.
Definition Graphics.h:937
void setSceneColorFilter(const glm::vec3 &color) override
Sets the scene color filter.
Definition Graphics.h:864
Result< void > drawMeshShaderInstances(Mesh &mesh, Shader &shader, const glm::mat4 &model, const Color &tint, std::uint32_t first, std::uint32_t count) override
Draws mesh shader instances.
int getMsaaSamples() const override
Returns the msaa samples.
Definition Graphics.h:408
bool supportsGpuDriven3D() const override
Supports gpu driven 3 d.
Definition Graphics.h:442
void pushValidationScope() override
Pushes validation scope.
Definition Graphics.h:556
const RayTracingCaps & rayTracingCapsRef() const
Hardware ray-tracing capabilities probed at device creation.
Definition Graphics.h:418
float getSceneAutoExposureMaxEV() const override
Returns the scene auto exposure max ev.
Definition Graphics.h:909
float getScenePhotographicVignette() const override
Read the current render-thread photographic vignette.
Definition Graphics.h:858
float getSceneExposure() const override
Returns the scene exposure.
Definition Graphics.h:862
glm::vec3 getSceneGain() const override
Returns the scene gain.
Definition Graphics.h:881
uint32_t gpuDrivenMaterialRecord(Material *material) override
Gpu driven material record.
Definition Graphics.h:458
uint32_t debugLastGpuDrivenDrawCount() const
Indirect draws emitted by the last successful GPU-driven submit.
Definition Graphics.h:503
uint32_t getSwapchainImageCount() const
Returns the swapchain image count.
Definition Graphics.h:1073
float getSceneDofNearZ() const override
Returns the scene dof near z.
Definition Graphics.h:935
RayTracingCaps rayTracingCaps() const override
Ray tracing caps.
Definition Graphics.h:420
void setSceneLiftGammaGain(const glm::vec3 &lift, const glm::vec3 &inverseGamma, const glm::vec3 &gain) override
Sets the scene lift gamma gain.
Definition Graphics.h:870
glm::vec3 getSceneLift() const override
Returns the scene lift.
Definition Graphics.h:877
bool supportsDeferredLighting() const override
Supports deferred lighting.
Definition Graphics.h:446
void setMsaaSamples(int samples) override
Sets the msaa samples.
Definition Graphics.h:401
bool supportsDecal() const override
Supports decal.
Definition Graphics.h:972
glm::vec3 getSceneColorFilter() const override
Returns the scene color filter.
Definition Graphics.h:868
float getSceneDofFocusDistance() const override
Returns the scene dof focus distance.
Definition Graphics.h:929
vk::CommandPool getUploadPool() const
Returns the upload pool.
Definition Graphics.h:1016
glm::vec3 getSceneInverseGamma() const override
Returns the scene inverse gamma.
Definition Graphics.h:879
void setMesh3DSSAO(float intensity) override
Sets the mesh 3 dssao.
Definition Graphics.h:834
vk::RenderPass getUiMsaaRenderPass() const
Returns the ui msaa render pass.
Definition Graphics.h:1045
float getSceneTransitionVignetteSmoothness() const override
Returns the scene transition vignette smoothness.
Definition Graphics.h:893
void setScreenReadbackEnabled(bool enabled) override
Sets the screen readback enabled.
Definition Graphics.h:386
const vkb::BuiltRenderPass & getOffscreenRenderPass(bool hdr=false) const
Returns the offscreen render pass.
Definition Graphics.h:1033
const GpuDrivenCaps & gpuDrivenCaps() const
Capabilities probed at device creation; empty when unavailable.
Definition Graphics.h:415
void setSceneDepthOfField(float focusDistance, float maxBlurPx, float focusRange, float nearZ, float farZ) override
Sets the scene depth of field.
Definition Graphics.h:920
float getSceneDofMaxBlur() const override
Returns the scene dof max blur.
Definition Graphics.h:931
bool canRecordPostSceneGpuWork() const
True when the present command buffer is open and the scene-color pass has ended, so post-scene GPU wo...
Definition Graphics.h:1022
void setSceneExposure(float exposure) override
Sets the scene exposure.
Definition Graphics.h:860
float getSceneTransitionLensDistortion() const override
Returns the scene transition lens distortion.
Definition Graphics.h:895
vk::DescriptorSetLayout getTexSetLayout() const
Returns the tex set layout.
Definition Graphics.h:1029
const vkb::BuiltRenderPass & getOffscreen3DRenderPass(bool hdr=false)
Returns the offscreen 3 d render pass.
Definition Graphics.h:1037
Graphics()
Starts asynchronous VkInstance creation (overlaps later window init).
vk::RenderPass getSwapchainRenderPass() const
Returns the swapchain render pass.
Definition Graphics.h:1043
void popValidationScope() override
Pops validation scope.
Definition Graphics.h:558
vkb::Swapchain & getSwapchain()
Returns the swapchain.
Definition Graphics.h:1069
void ensureUiColorResources()
Create the UI MSAA render pass (once) and its color targets for ImGui init.
Definition Graphics.h:1049
float getLastOffscreen3DGpuDurationMs() const override
Returns the last offscreen 3 d gpu duration ms.
Definition Graphics.h:762
SceneToneMapping getSceneToneMapping() const override
Returns the scene tone mapping.
Definition Graphics.h:848
bool gpuDrivenEnabled() const override
Gpu driven enabled.
Definition Graphics.h:450
bool getSceneAutoExposure() const override
Returns the scene auto exposure.
Definition Graphics.h:905
void setSceneBloom(float intensity, float threshold) override
Sets the scene bloom.
Definition Graphics.h:911
vk::CommandBuffer & postSceneCommandBuffer()
Borrow the open present command buffer for post-scene recording.
Definition Graphics.h:1027
void setVSync(bool enabled) override
Sets the v sync.
Definition Graphics.h:393
bool gpuDrivenScenePassPending() const
Scene color pass is deferred until after the compute cull section.
Definition Graphics.h:511
uint32_t bindlessSlotCube(const GpuTexture *tex) const
Bindless slot cube.
Definition Graphics.h:438
void gpuDrivenSetEnabled(bool enabled) override
Gpu driven set enabled.
Definition Graphics.h:454
vkb::Device & getDevice()
Returns the device.
Definition Graphics.h:1014
vk::Format getDepthFormat() const
Returns the depth format.
Definition Graphics.h:1041
void requestSurfaceRecreate() override
Request surface recreate.
Definition Graphics.h:382
void * getSdlWindow() const
Returns the sdl window.
Definition Graphics.h:1071
void setSceneTransitionFx(float vignette, float vignetteSmoothness, float lensDistortion, float lensScale) override
Sets the scene transition fx.
Definition Graphics.h:883
vk::DescriptorPool getDescriptorPool() const
Returns the descriptor pool.
Definition Graphics.h:1031
bool isHeadless() const override
True when headless.
Definition Graphics.h:378
vk::SampleCountFlagBits getUiMsaaSamples() const
Sample count the UI MSAA pass runs with (matches getUiMsaaRenderPass).
Definition Graphics.h:1047
void setSceneAutoExposure(bool enabled, float minEV, float maxEV) override
Sets the scene auto exposure.
Definition Graphics.h:899
OffscreenCanvas public API.
Definition Canvas.h:15
Represents raw pixel data.
Definition ImageData.h:38
Reads the GPU frame timing captured by the renderer via Vulkan timestamp queries. Providers: eve::gra...
Definition GpuTimer.h:17
std::vector< ParamSpec > params
EffectInstance Effect
Backward-compatible name for the runtime instance type.
constexpr uint32_t kInvalidBindlessSlot
Definition GpuDriven.h:22
eve::graphics::GpuMaterialRecord GpuMaterialRecord
Definition GpuDriven.h:16
std::uint64_t GpuParticleHandle
Opaque backend-owned GPU particle emitter handle.
SurfaceMode
How a 3D surface contributes to depth and color passes.
Definition SurfaceMode.h:6
PrimitiveCullMode
Face culling used by filled 3D primitives.
eve::Color Color
RGBA color used by every graphics draw call. Lives inside eve::graphics so including a graphics heade...
Definition Color.h:13
constexpr GpuParticleHandle kInvalidGpuParticleHandle
Invalid GPU particle handle returned when the backend cannot allocate the resource.
SkinInfluenceLimit
Number of strongest vertex influences retained by GPU skinning.
Definition IGraphics3D.h:19
PrimitiveDepthMode
Depth behavior of one 3D primitive.
GpuResidentSubmitStatus
Structured result for direct resident-instance submission.
BlendMode
Render-neutral 2D blend mode shared by graphics-facing modules.
Definition RenderTypes.h:11
glm::vec4 Color
Render-neutral RGBA color shared by graphics-facing modules.
Definition RenderTypes.h:8
bool enabled
Transient backend buffer slice shared between sibling GPU modules. @ownership Non-owning; nativeHandl...
CPU-built clustered lighting upload for one frame/camera. Point lights are clustered; directional lig...
Per-instance GPU record (std430). Mirrors GLSL GpuInstance.
GPU mesh table record (std430). Mirrors GLSL GpuMeshRecord.
Parameters for rendering a resident GPU particle emitter.
GPU particle state uploaded only for newly spawned particles.
Delayed non-blocking counters from a resident GPU emitter.
Parameters for one resident GPU simulation step.
Direct-render description for a GPU-authored array of GpuInstance records. @ownership buckets and buf...
Neutral GPU upload for one virtual-geometry asset. Raw arrays so the graphics module does not depend ...
GPU light packing for mesh3d / PBR (std140-friendly).
Definition Light.h:161
Lighting2DUBO public API.
Definition Light.h:53
Lighting3DPack public API.
Definition Light.h:172
static constexpr int kMaxLights
Definition Light.h:173
static constexpr int kMaxDiffuseVolumeProbes
Definition Light.h:179
Value snapshot of custom mesh rasterization state, independent of blending/culling.
Owning material parameter snapshot; texture pointers remain borrowed. Base color/metallic/roughness c...
Definition PbrSurface.h:218
Hardware ray-tracing capabilities probed once at Vulkan device creation.
ReflectionProbeUpload public API.
Definition IGraphics3D.h:26
Inputs for descriptor set 1 of a resource mesh program.
ShadowUpload public API.
Definition Shadow.h:54
Options for Graphics::newTexture / newCubemap. When generateMipmaps is true and sampler....
Sampler state for a Texture (filter, wrap, mip LOD, anisotropy). Defaults match historical engine beh...
ColorVertex public API.
Definition Graphics.h:60
static vk::VertexInputBindingDescription getBindingDescription(uint32_t binding)
Returns the binding description.
Definition Graphics.h:65
static std::vector< vk::VertexInputAttributeDescription > getAttributeDescription(uint32_t binding)
Returns the attribute description.
Definition Graphics.h:73
DeferredLightingUBO public API.
Definition Graphics.h:222
Capabilities required for the GPU-driven path. All must be true for gpuDrivenAvailable()....
Definition GpuDriven.h:31
GpuMesh public API.
Definition Graphics.h:289
vkb::HostVertexBuffer vertices
Definition Graphics.h:295
static constexpr size_t kDynamicVertexCopies
Ring copies for per-frame updated meshes (skin/morph/sprite stack). Writing the next copy never races...
Definition Graphics.h:294
uint32_t gpuRecordIndex
Index into the GPU mesh table (GpuMeshRecord).
Definition Graphics.h:309
uint64_t dynamicWriteCount
Number of dynamic updates; ring slot = count % kDynamicVertexCopies.
Definition Graphics.h:303
std::array< vkb::GenericBuffer, kDynamicVertexCopies > dynIndices
Definition Graphics.h:298
GpuMeshRecord record
CPU-side record for this mesh (bounds/ranges); uploaded by registerMeshRecord.
Definition Graphics.h:311
vkb::GenericBuffer indices
Definition Graphics.h:296
std::array< vkb::HostVertexBuffer, kDynamicVertexCopies > dynVertices
Definition Graphics.h:297
std::vector< uint32_t > cpuIndices
CPU index copy for dynamic meshes (also normalizes 16-bit static indices to 32-bit ring buffers).
Definition Graphics.h:301
GpuShader public API.
Definition Graphics.h:322
vk::Pipeline hdrOffscreenOpaquePipeline
Definition Graphics.h:328
vk::Pipeline mesh3dHdrOffscreenPipeline
Definition Graphics.h:332
vk::PipelineLayout pipelineLayout
Definition Graphics.h:333
std::unique_ptr< MeshShaderResources, MeshShaderResourcesDeleter > resources
Definition Graphics.h:335
vk::DescriptorSet resourceSet
Definition Graphics.h:334
GpuTexture public API.
Definition Graphics.h:257
vkb::TextureImage2D image
Definition Graphics.h:258
uint32_t bindlessIndex2D
Bindless texture-array slot (stage 0 GPU-driven path).
Definition Graphics.h:276
vk::UniqueImageView rawCubeView
Definition Graphics.h:267
vk::ImageView imageView() const
Image view.
Definition Graphics.h:280
vkb::TextureImageCube cubeImage
Definition Graphics.h:260
vk::UniqueDeviceMemory rawCubeMemory
Definition Graphics.h:265
Mesh3DClusteredUBO public API.
Definition Graphics.h:235
glm::vec4 reflectionProbeExtent[ReflectionProbeUpload::kMaxProbes]
Definition Graphics.h:253
glm::vec4 reflectionProbeCenter[ReflectionProbeUpload::kMaxProbes]
Definition Graphics.h:252
Mesh3DUBO public API.
Definition Graphics.h:174
glm::vec4 reflectionProbeExtent[ReflectionProbeUpload::kMaxProbes]
Definition Graphics.h:202
glm::vec4 diffuseVolumePosition[Lighting3DPack::kMaxDiffuseVolumeProbes]
Definition Graphics.h:205
Light3DGpu lights[Lighting3DPack::kMaxLights]
Definition Graphics.h:183
glm::vec4 reflectionProbeCenter[ReflectionProbeUpload::kMaxProbes]
Definition Graphics.h:201
glm::vec4 diffuseVolumeExtent[Lighting3DPack::kMaxDiffuseVolumeProbes]
Definition Graphics.h:206
glm::vec4 diffuseVolumeSh[Lighting3DPack::kMaxDiffuseVolumeProbes *9]
Definition Graphics.h:207
MeshShaderResourcesDeleter public API.
Definition Graphics.h:316
void operator()(MeshShaderResources *resources) const noexcept
Operator .
MeshVertex public API.
Definition Graphics.h:141
static std::vector< vk::VertexInputAttributeDescription > getAttributeDescription(uint32_t binding)
Returns the attribute description.
Definition Graphics.h:160
static vk::VertexInputBindingDescription getBindingDescription(uint32_t binding)
Returns the binding description.
Definition Graphics.h:152
Clip-space vertex emitted by the backend-neutral primitive tessellator.
Definition Graphics.h:82
static std::vector< vk::VertexInputAttributeDescription > getAttributeDescription(uint32_t binding)
Returns the attribute description.
Definition Graphics.h:91
static vk::VertexInputBindingDescription getBindingDescription(uint32_t binding)
Returns the binding description.
Definition Graphics.h:87
SkinPassUBO public API.
Definition Graphics.h:213
TexturedVertex public API.
Definition Graphics.h:98
static std::vector< vk::VertexInputAttributeDescription > getAttributeDescription(uint32_t binding)
Returns the attribute description.
Definition Graphics.h:112
static vk::VertexInputBindingDescription getBindingDescription(uint32_t binding)
Returns the binding description.
Definition Graphics.h:104
Backend-internal textured rectangle queued by a UI presenter.
Definition Graphics.h:122
glm::mat4 invViewProj
glm::uvec4 info
glm::vec4 color