19#include <SDL2/SDL_vulkan.h>
37#include "common/config.h"
41#include "zeroerr/assert.h"
46#include <assimp/mesh.h>
47#include <assimp/matrix3x3.h>
48#include <assimp/matrix4x4.h>
49#include <assimp/vector3.h>
50#include <glm/gtc/matrix_transform.hpp>
52#include "graphics/shaders/color_frag_spv.inc"
53#include "graphics/shaders/color_vert_spv.inc"
54#include "graphics/shaders/decal_box_frag_spv.inc"
55#include "graphics/shaders/decal_box_vert_spv.inc"
56#include "graphics/shaders/lit2d_frag_spv.inc"
57#include "graphics/shaders/lit2d_vert_spv.inc"
58#include "graphics/shaders/mesh3d_clustered_frag_spv.inc"
59#include "graphics/shaders/mesh3d_clustered_vert_spv.inc"
60#include "graphics/shaders/mesh3d_frag_spv.inc"
61#include "graphics/shaders/mesh3d_gbuffer_alpha_frag_spv.inc"
62#include "graphics/shaders/mesh3d_gbuffer_frag_spv.inc"
63#include "graphics/shaders/mesh3d_gbuffer_skin_alpha_frag_spv.inc"
64#include "graphics/shaders/mesh3d_gbuffer_skin_frag_spv.inc"
65#include "graphics/shaders/mesh3d_gbuffer_skin_vert_spv.inc"
66#include "graphics/shaders/mesh3d_gbuffer_vert_spv.inc"
67#include "graphics/shaders/mesh3d_gpudriven_frag_spv.inc"
68#include "graphics/shaders/mesh3d_gpudriven_vert_spv.inc"
69#include "graphics/shaders/mesh3d_hair_frag_spv.inc"
70#include "graphics/shaders/mesh3d_hair_vert_spv.inc"
71#include "graphics/shaders/mesh3d_shadow_alpha_frag_spv.inc"
72#include "graphics/shaders/mesh3d_shadow_alpha_vert_spv.inc"
73#include "graphics/shaders/mesh3d_shadow_frag_spv.inc"
74#include "graphics/shaders/mesh3d_shadow_skin_alpha_frag_spv.inc"
75#include "graphics/shaders/mesh3d_shadow_skin_vert_spv.inc"
76#include "graphics/shaders/mesh3d_shadow_vert_spv.inc"
77#include "graphics/shaders/mesh3d_vert_spv.inc"
78#include "graphics/shaders/particle_distortion_frag_spv.inc"
79#include "graphics/shaders/primitive3d_frag_spv.inc"
80#include "graphics/shaders/primitive3d_vert_spv.inc"
81#include "graphics/shaders/resolve_vis_frag_spv.inc"
82#include "graphics/shaders/resolve_vis_vert_spv.inc"
83#include "graphics/shaders/scene_tonemap_frag_spv.inc"
84#include "graphics/shaders/textured_frag_spv.inc"
85#include "graphics/shaders/textured_opaque_frag_spv.inc"
86#include "graphics/shaders/textured_vert_spv.inc"
93vk::Pipeline createPrimitive3DPipeline(vkb::Device &
device,
const vkb::BuiltRenderPass &renderPass,
98 const vk::CullModeFlags cullFlags =
100 ? vk::CullModeFlagBits::eBack
102 std::vector<vk::PipelineColorBlendAttachmentState> attachments(1, makeBlendAttachment(
blend));
103 vk::PipelineColorBlendStateCreateInfo blending{};
104 blending.attachmentCount = 1;
105 blending.pAttachments = attachments.data();
106 return device.createPipeline()
107 .useClassicPipeline(embeddedSpirv(primitive3d_vert_spv), embeddedSpirv(primitive3d_frag_spv))
108 .setPipelineLayout(
layout)
109 .setVertexInputState(vkb::VertexInputStateBuilder()
110 .addInputBinding<Primitive3DVertex>()
111 .addAttributeDescription<Primitive3DVertex>())
112 .setDynamicStatesViewportScissor()
113 .setRasterizer(vk::PolygonMode::eFill,
false,
false, 1.f, cullFlags, vk::FrontFace::eCounterClockwise)
114 .setDepthStencil(depthTest, depthWrite, depthTest ? vk::CompareOp::eLessOrEqual : vk::
CompareOp::eAlways)
115 .setMultisampler(false, samples)
116 .setColorBlending(blending)
123void Graphics::destroyPresentGraphicsPipelines() {
124 auto destroyPipe = [&](vk::Pipeline &
p) {
130 destroyPipe(pipeline);
131 destroyPipe(solidAlphaPipeline);
132 destroyPipe(additiveSolidPipeline);
133 destroyPipe(premultipliedSolidPipeline);
134 destroyPipe(multiplySolidPipeline);
135 destroyPipe(texPipeline);
136 destroyPipe(additiveTexPipeline);
137 destroyPipe(premultipliedTexPipeline);
138 destroyPipe(multiplyTexPipeline);
139 destroyPipe(opaqueTexPipeline);
140 destroyPipe(particleDistortionPipeline);
141 destroyPipe(sceneTonemapPipeline);
142 destroyPipe(lit2dPipeline);
143 destroyPipe(lit2dAdditivePipeline);
144 destroyPipe(lit2dPremultipliedPipeline);
145 destroyPipe(lit2dMultiplyPipeline);
146 destroyPipe(lit2dOpaquePipeline);
147 destroyPipe(gpuParticleAlphaPipeline_);
148 destroyPipe(gpuParticleAdditivePipeline_);
149 destroyPipe(gpuParticlePremultipliedPipeline_);
150 destroyPipe(gpuParticleMultiplyPipeline_);
151 destroyPipe(gpuParticleOpaquePipeline_);
152 for (
auto &
g : ownedGpuShaders) {
153 if (!
g ||
g->isMesh3D)
continue;
154 destroyPipe(
g->swapchainPipeline);
155 destroyPipe(
g->swapchainOpaquePipeline);
158 device->destroyRenderPass(renderpass);
161 presentAttachmentFormat_ = vk::Format::eUndefined;
163 scenePassPipelineTarget = vk::RenderPass{};
166void Graphics::createSwapchainAndPipeline() {
170 presentRecording = {};
172 presentModel.destroy();
173 presentModel = vkb::Present{};
175 vkb::SwapchainBuilder swapchainBuilder =
device.createSwapchain();
179 applyPreferredSwapchainFormats(swapchainBuilder);
181 swapchainBuilder.set_desired_present_mode(vk::PresentModeKHR::eMailbox);
182 swapchainBuilder.add_fallback_present_mode(vk::PresentModeKHR::eFifo);
184 swapchainBuilder.set_desired_present_mode(vk::PresentModeKHR::eImmediate);
185 swapchainBuilder.add_fallback_present_mode(vk::PresentModeKHR::eMailbox);
186 swapchainBuilder.add_fallback_present_mode(vk::PresentModeKHR::eFifo);
189 swapchainBuilder.add_image_usage_flags(vk::ImageUsageFlagBits::eTransferSrc);
190 auto swapRet = swapchainBuilder.set_old_swapchain(swapchain).build();
193 if (swapchain.image_format != selectedSurfaceFormat_.format) {
196 selectedSurfaceFormat_ = {swapchain.image_format, vk::ColorSpaceKHR::eSrgbNonlinear};
200 StartupStage stage(
" vulkan: depth image");
201 depthImage = vkb::DepthStencilImage{
device, swapchain.extent.width, swapchain.extent.height, depthFormat};
206 if (renderpass && presentAttachmentFormat_ == vk::Format::eUndefined)
207 presentAttachmentFormat_ = swapchain.image_format;
208 if (renderpass && presentAttachmentFormat_ != swapchain.image_format)
209 destroyPresentGraphicsPipelines();
212 vkb::RenderPassBuilder rpBuilder{
device};
214 rpBuilder.addPresentAttachment(swapchain.image_format, vk::AttachmentLoadOp::eClear)
215 .addDepthAttachment(depthFormat, vk::AttachmentLoadOp::eClear,
216 vk::AttachmentStoreOp::eDontCare)
217 .addSubpass(vkb::SubpassBuilder()
218 .addAttachmentRef(0, vk::ImageLayout::eColorAttachmentOptimal)
219 .setDepthStencilAttachment(
220 1, vk::ImageLayout::eDepthStencilAttachmentOptimal))
221 .addDependency(VK_SUBPASS_EXTERNAL, 0,
222 vk::PipelineStageFlagBits::eColorAttachmentOutput |
223 vk::PipelineStageFlagBits::eEarlyFragmentTests,
224 vk::PipelineStageFlagBits::eColorAttachmentOutput |
225 vk::PipelineStageFlagBits::eEarlyFragmentTests,
227 vk::AccessFlagBits::eColorAttachmentRead |
228 vk::AccessFlagBits::eColorAttachmentWrite |
229 vk::AccessFlagBits::eDepthStencilAttachmentWrite)
231 presentAttachmentFormat_ = swapchain.image_format;
235 if (!pipelineLayout) pipelineLayout = createPipelineLayout(device);
249 if (!texPipeline && texSetLayout) {
250 auto vert = embeddedSpirv(textured_vert_spv);
251 auto frag = embeddedSpirv(textured_frag_spv);
252 texPipeline = createTexturedStylePipeline(
vert,
frag, renderpass, texPipelineLayout);
253 additiveTexPipeline = createTexturedStylePipeline(
vert,
frag, renderpass, texPipelineLayout,
255 premultipliedTexPipeline = createTexturedStylePipeline(
257 multiplyTexPipeline = createTexturedStylePipeline(
vert,
frag, renderpass, texPipelineLayout,
259 opaqueTexPipeline = createTexturedStylePipeline(
vert,
frag, renderpass, texPipelineLayout,
261 particleDistortionPipeline = createTexturedStylePipeline(
262 vert, embeddedSpirv(particle_distortion_frag_spv), renderpass, texPipelineLayout,
264 sceneTonemapPipeline = createTexturedStylePipeline(
265 vert, embeddedSpirv(scene_tonemap_frag_spv), renderpass, texPipelineLayout,
267 if (lit2dPipelineLayout) {
268 auto lvert = embeddedSpirv(lit2d_vert_spv);
269 auto lfrag = embeddedSpirv(lit2d_frag_spv);
270 lit2dPipeline = createTexturedStylePipeline(lvert, lfrag, renderpass, lit2dPipelineLayout);
271 lit2dAdditivePipeline =
272 createTexturedStylePipeline(lvert, lfrag, renderpass, lit2dPipelineLayout,
BlendMode::Additive);
273 lit2dPremultipliedPipeline =
275 lit2dMultiplyPipeline =
276 createTexturedStylePipeline(lvert, lfrag, renderpass, lit2dPipelineLayout,
BlendMode::Multiply);
277 lit2dOpaquePipeline =
278 createTexturedStylePipeline(lvert, lfrag, renderpass, lit2dPipelineLayout,
BlendMode::Opaque);
280 rebuildGpuParticleDrawPipelines(renderpass);
281 for (
auto &
shader : ownedShaders) {
283 auto *gpu =
static_cast<GpuShader *
>(
shader->gpuHandle);
284 if (gpu->isMesh3D || gpu->swapchainPipeline)
continue;
285 gpu->swapchainPipeline = createTexturedStylePipeline(
286 shader->vertexSpirv(),
shader->fragmentSpirv(), renderpass, shaderPipelineLayout);
287 gpu->swapchainOpaquePipeline = createTexturedStylePipeline(
288 shader->vertexSpirv(),
shader->fragmentSpirv(), renderpass, shaderPipelineLayout,
297 if (!scenePassPipelineTarget && !mesh3dPipeline) {
298 scenePassPipelineTarget = vk::RenderPass(renderpass);
299 scenePassPipelineSamples = vk::SampleCountFlagBits::e1;
302 presentModel =
device.createPresent(swapchain).build(renderpass, depthImage.imageView());
308 presentModel.synchronous_frames =
false;
309 ensurePresentCaptureHook();
310 swapchainDirty =
false;
313void Graphics::createTexturedPipeline() {
314 if (texPipeline)
return;
317 vkb::DescriptorSetLayoutBuilder layoutBuilder;
318 texSetLayoutUnique = layoutBuilder
319 .image(0, vk::DescriptorType::eCombinedImageSampler,
320 vk::ShaderStageFlagBits::eFragment, 1)
321 .image(1, vk::DescriptorType::eCombinedImageSampler,
322 vk::ShaderStageFlagBits::eFragment, 1)
323 .image(2, vk::DescriptorType::eCombinedImageSampler,
324 vk::ShaderStageFlagBits::eFragment, 1)
325 .image(3, vk::DescriptorType::eCombinedImageSampler,
326 vk::ShaderStageFlagBits::eFragment, 1)
327 .image(4, vk::DescriptorType::eCombinedImageSampler,
328 vk::ShaderStageFlagBits::eFragment, 1)
329 .createUnique(
device.instance);
330 texSetLayout = *texSetLayoutUnique;
332 vk::DescriptorPoolSize poolSizes[] = {
333 {vk::DescriptorType::eCombinedImageSampler, 8192},
334 {vk::DescriptorType::eUniformBuffer, 2048},
338 {vk::DescriptorType::eUniformBufferDynamic, 4096},
339 {vk::DescriptorType::eStorageBuffer, 16384},
341 vk::DescriptorPoolCreateInfo poolInfo{};
342 poolInfo.flags = vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet;
343 poolInfo.maxSets = 8192;
344 poolInfo.poolSizeCount = 4;
345 poolInfo.pPoolSizes = poolSizes;
346 descriptorPool =
device->createDescriptorPool(poolInfo);
348 texPipelineLayout = createPipelineLayout(device, texSetLayout);
350 pushConstantRange(vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment,
352 shaderPipelineLayout = createPipelineLayout(device, texSetLayout, &pcr);
355 auto vert = embeddedSpirv(textured_vert_spv);
356 auto frag = embeddedSpirv(textured_frag_spv);
357 texPipeline = createTexturedStylePipeline(
vert,
frag, renderpass, texPipelineLayout);
358 additiveTexPipeline = createTexturedStylePipeline(
vert,
frag, renderpass, texPipelineLayout,
360 premultipliedTexPipeline = createTexturedStylePipeline(
362 multiplyTexPipeline = createTexturedStylePipeline(
vert,
frag, renderpass, texPipelineLayout,
364 opaqueTexPipeline = createTexturedStylePipeline(
vert,
frag, renderpass, texPipelineLayout,
366 particleDistortionPipeline = createTexturedStylePipeline(
367 vert, embeddedSpirv(particle_distortion_frag_spv), renderpass, texPipelineLayout,
369 sceneTonemapPipeline = createTexturedStylePipeline(
370 vert, embeddedSpirv(scene_tonemap_frag_spv), renderpass, texPipelineLayout,
373 createLit2DPipeline();
374 createGpuParticlePipelines();
377vk::Pipeline Graphics::createTexturedStylePipeline(
const std::vector<uint32_t> &
vert,
378 const std::vector<uint32_t> &
frag,
379 const vkb::BuiltRenderPass &rp,
381 vk::SampleCountFlagBits samples) {
382 ShaderModulePair modules(device,
vert,
frag);
387 std::vector<vk::PipelineColorBlendAttachmentState> attachments(1,
388 makeBlendAttachment(mode));
389 vk::PipelineColorBlendStateCreateInfo cbs{};
390 cbs.logicOpEnable =
false;
391 cbs.attachmentCount = 1;
392 cbs.pAttachments = attachments.data();
393 return device.createPipeline()
394 .useClassicPipeline(modules.vert, modules.frag)
395 .setPipelineLayout(
layout)
396 .setVertexInputState(vkb::VertexInputStateBuilder()
397 .addInputBinding<TexturedVertex>()
398 .addAttributeDescription<TexturedVertex>())
399 .setDynamicStatesViewportScissor()
400 .setRasterizer(vk::PolygonMode::eFill,
false,
false, 1.0f,
401 vk::CullModeFlagBits::eNone, vk::FrontFace::eCounterClockwise)
402 .setDepthStencil(
false,
false)
403 .setMultisampler(
false, samples)
404 .setColorBlending(cbs)
408 return device.createPipeline()
409 .useClassicPipeline(modules.vert, modules.frag)
410 .setPipelineLayout(
layout)
411 .setVertexInputState(vkb::VertexInputStateBuilder()
412 .addInputBinding<TexturedVertex>()
413 .addAttributeDescription<TexturedVertex>())
414 .setDynamicStatesViewportScissor()
415 .setRasterizer(vk::PolygonMode::eFill,
false,
false, 1.0f,
416 vk::CullModeFlagBits::eNone, vk::FrontFace::eCounterClockwise)
417 .setDepthStencil(
false,
false)
418 .setMultisampler(
false, samples)
423 return device.createPipeline()
424 .useClassicPipeline(modules.vert, modules.frag)
425 .setPipelineLayout(
layout)
426 .setVertexInputState(vkb::VertexInputStateBuilder()
427 .addInputBinding<TexturedVertex>()
428 .addAttributeDescription<TexturedVertex>())
429 .setDynamicStatesViewportScissor()
430 .setRasterizer(vk::PolygonMode::eFill,
false,
false, 1.0f, vk::CullModeFlagBits::eNone,
431 vk::FrontFace::eCounterClockwise)
432 .setDepthStencil(
false,
false)
433 .setMultisampler(
false, samples)
438void Graphics::createLit2DPipeline() {
439 if (lit2dPipeline)
return;
441 vkb::DescriptorSetLayoutBuilder layoutBuilder;
442 lit2dSetLayoutUnique =
444 .image(0, vk::DescriptorType::eCombinedImageSampler, vk::ShaderStageFlagBits::eFragment, 1)
445 .image(1, vk::DescriptorType::eCombinedImageSampler, vk::ShaderStageFlagBits::eFragment, 1)
446 .buffer(2, vk::DescriptorType::eUniformBuffer, vk::ShaderStageFlagBits::eFragment, 1)
447 .createUnique(
device.instance);
448 lit2dSetLayout = *lit2dSetLayoutUnique;
450 lit2dPipelineLayout = createPipelineLayout(device, lit2dSetLayout);
454 offscreenLighting2dUbo.allocate(frameToken(), device, vk::BufferUsageFlagBits::eUniformBuffer,
455 sizeof(Lighting2DUBO),
456 vk::MemoryPropertyFlagBits::eHostVisible |
457 vk::MemoryPropertyFlagBits::eHostCoherent);
459 auto vert = embeddedSpirv(lit2d_vert_spv);
460 auto frag = embeddedSpirv(lit2d_frag_spv);
461 lit2dPipeline = createTexturedStylePipeline(
vert,
frag, renderpass, lit2dPipelineLayout);
462 lit2dAdditivePipeline =
464 lit2dPremultipliedPipeline =
466 lit2dMultiplyPipeline =
471vk::Pipeline Graphics::selectLit2DPipeline(
BlendMode blend,
bool offscreen,
bool hdr)
const {
472 auto pick = [](
BlendMode mode, vk::Pipeline alpha, vk::Pipeline additive, vk::Pipeline premultiplied,
473 vk::Pipeline multiply, vk::Pipeline opaque) -> vk::Pipeline {
480 default:
return alpha;
484 if ((offscreen && hdr) || (!offscreen && presentComposeActive_)) {
486 pick(
blend, hdrOffscreenLitPipeline, hdrOffscreenLitAdditivePipeline, hdrOffscreenLitPremultipliedPipeline,
487 hdrOffscreenLitMultiplyPipeline, hdrOffscreenLitOpaquePipeline);
488 if (pipe)
return pipe;
491 return pick(
blend, offscreenLitPipeline, offscreenLitAdditivePipeline, offscreenLitPremultipliedPipeline,
492 offscreenLitMultiplyPipeline, offscreenLitOpaquePipeline);
494 return pick(
blend, lit2dPipeline, lit2dAdditivePipeline, lit2dPremultipliedPipeline, lit2dMultiplyPipeline,
495 lit2dOpaquePipeline);
498void Graphics::createMesh3DPipeline() {
499 if (mesh3dPipeline)
return;
503 vkb::DescriptorSetLayoutBuilder layoutBuilder;
504 mesh3dSetLayoutUnique =
505 layoutBuilder.buffer(21, vk::DescriptorType::eStorageBuffer, vk::ShaderStageFlagBits::eVertex, 1)
506 .buffer(0, vk::DescriptorType::eUniformBufferDynamic,
507 vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment, 1)
508 .image(1, vk::DescriptorType::eCombinedImageSampler,
509 vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment, 1)
510 .image(2, vk::DescriptorType::eCombinedImageSampler, vk::ShaderStageFlagBits::eFragment, 1)
511 .image(3, vk::DescriptorType::eCombinedImageSampler, vk::ShaderStageFlagBits::eFragment, 1)
512 .buffer(4, vk::DescriptorType::eUniformBufferDynamic, vk::ShaderStageFlagBits::eFragment, 1)
513 .image(5, vk::DescriptorType::eCombinedImageSampler, vk::ShaderStageFlagBits::eFragment, 1)
514 .image(6, vk::DescriptorType::eCombinedImageSampler,
515 vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment, 1)
516 .image(7, vk::DescriptorType::eCombinedImageSampler, vk::ShaderStageFlagBits::eFragment, 1)
517 .image(8, vk::DescriptorType::eCombinedImageSampler, vk::ShaderStageFlagBits::eFragment, 1)
518 .image(9, vk::DescriptorType::eCombinedImageSampler, vk::ShaderStageFlagBits::eFragment, 1)
519 .image(10, vk::DescriptorType::eCombinedImageSampler, vk::ShaderStageFlagBits::eFragment, 1)
520 .image(16, vk::DescriptorType::eCombinedImageSampler, vk::ShaderStageFlagBits::eFragment, 1)
521 .image(17, vk::DescriptorType::eCombinedImageSampler, vk::ShaderStageFlagBits::eFragment, 1)
522 .image(18, vk::DescriptorType::eCombinedImageSampler, vk::ShaderStageFlagBits::eFragment, 1)
523 .image(20, vk::DescriptorType::eCombinedImageSampler, vk::ShaderStageFlagBits::eFragment, 1)
524 .createUnique(
device.instance);
525 mesh3dSetLayout = *mesh3dSetLayoutUnique;
527 vkb::DescriptorSetLayoutBuilder skinLayoutBuilder;
528 skinPassSetLayoutUnique =
529 skinLayoutBuilder.buffer(2, vk::DescriptorType::eStorageBuffer, vk::ShaderStageFlagBits::eVertex, 1)
530 .buffer(0, vk::DescriptorType::eUniformBufferDynamic,
531 vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment, 1)
532 .image(1, vk::DescriptorType::eCombinedImageSampler, vk::ShaderStageFlagBits::eFragment, 1)
533 .createUnique(
device.instance);
534 skinPassSetLayout = *skinPassSetLayoutUnique;
535 skinPassPipelineLayout = createPipelineLayout(device, skinPassSetLayout);
537 mesh3dPipelineLayout = createPipelineLayout(device, mesh3dSetLayout);
539 pushConstantRange(vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment,
541 mesh3dShaderPipelineLayout = createPipelineLayout(device, mesh3dSetLayout, &pcr);
545 mesh3dFrameSlots.clear();
547 auto vert = embeddedSpirv(mesh3d_vert_spv);
548 auto frag = embeddedSpirv(mesh3d_frag_spv);
550 createMesh3DStylePipeline(
vert,
frag, mesh3dPipelineLayout, renderpass,
551 vk::SampleCountFlagBits::e1);
552 mesh3dTransparentPipeline =
553 createMesh3DHairPipeline(
vert,
frag, mesh3dPipelineLayout, renderpass,
554 vk::SampleCountFlagBits::e1);
555 for (
int blendValue = 0; blendValue < 5; ++blendValue) {
557 for (
int depthValue = 0; depthValue < 2; ++depthValue) {
558 for (
int doubleValue = 0; doubleValue < 2; ++doubleValue) {
559 const size_t index = mesh3dPipelineIndex(
blend, depthValue != 0, doubleValue != 0);
560 mesh3dSurfacePipelines[
index] = createMesh3DStylePipeline(
561 vert,
frag, mesh3dPipelineLayout, renderpass, vk::SampleCountFlagBits::e1,
562 blend, depthValue != 0, doubleValue != 0);
568void Graphics::createMesh3DClusteredPipeline() {
569 if (mesh3dClusteredPipeline)
return;
571 vkb::DescriptorSetLayoutBuilder layoutBuilder;
572 mesh3dClusteredSetLayoutUnique =
574 .buffer(0, vk::DescriptorType::eUniformBufferDynamic,
575 vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment, 1)
576 .image(1, vk::DescriptorType::eCombinedImageSampler, vk::ShaderStageFlagBits::eFragment, 1)
577 .image(2, vk::DescriptorType::eCombinedImageSampler, vk::ShaderStageFlagBits::eFragment, 1)
578 .image(3, vk::DescriptorType::eCombinedImageSampler, vk::ShaderStageFlagBits::eFragment, 1)
579 .buffer(4, vk::DescriptorType::eStorageBuffer, vk::ShaderStageFlagBits::eFragment, 1)
580 .buffer(5, vk::DescriptorType::eStorageBuffer, vk::ShaderStageFlagBits::eFragment, 1)
581 .buffer(6, vk::DescriptorType::eStorageBuffer, vk::ShaderStageFlagBits::eFragment, 1)
582 .buffer(7, vk::DescriptorType::eUniformBufferDynamic, vk::ShaderStageFlagBits::eFragment, 1)
583 .image(8, vk::DescriptorType::eCombinedImageSampler, vk::ShaderStageFlagBits::eFragment, 1)
584 .image(9, vk::DescriptorType::eCombinedImageSampler, vk::ShaderStageFlagBits::eFragment, 1)
585 .image(10, vk::DescriptorType::eCombinedImageSampler, vk::ShaderStageFlagBits::eFragment, 1)
586 .image(11, vk::DescriptorType::eCombinedImageSampler, vk::ShaderStageFlagBits::eFragment, 1)
587 .image(12, vk::DescriptorType::eCombinedImageSampler, vk::ShaderStageFlagBits::eFragment, 1)
588 .image(18, vk::DescriptorType::eCombinedImageSampler, vk::ShaderStageFlagBits::eFragment, 1)
589 .image(19, vk::DescriptorType::eCombinedImageSampler, vk::ShaderStageFlagBits::eFragment, 1)
590 .image(20, vk::DescriptorType::eCombinedImageSampler, vk::ShaderStageFlagBits::eFragment, 1)
591 .createUnique(
device.instance);
592 mesh3dClusteredSetLayout = *mesh3dClusteredSetLayoutUnique;
594 mesh3dClusteredPipelineLayout = createPipelineLayout(device, mesh3dClusteredSetLayout);
596 mesh3dClusteredFrameSlots.clear();
598 auto vert = embeddedSpirv(mesh3d_clustered_vert_spv);
599 auto frag = embeddedSpirv(mesh3d_clustered_frag_spv);
600 mesh3dClusteredPipeline =
601 createMesh3DStylePipeline(
vert,
frag, mesh3dClusteredPipelineLayout, renderpass,
602 vk::SampleCountFlagBits::e1);
605void Graphics::destroyShadowResources() {
606 resetDeferredFrameGraphs();
607 destroyPipeline(device, shadowPipeline);
608 destroyPipeline(device, shadowSingleSidedPipeline);
609 destroyPipelineLayout(device, shadowPipelineLayout);
610 destroyPipeline(device, shadowAlphaPipeline);
611 destroyPipeline(device, shadowAlphaSingleSidedPipeline);
612 destroyPipeline(device, shadowSkinPipeline);
613 destroyPipeline(device, shadowSkinSingleSidedPipeline);
614 destroyPipeline(device, shadowSkinAlphaPipeline);
615 destroyPipeline(device, shadowSkinAlphaSingleSidedPipeline);
616 destroyPipelineLayout(device, shadowAlphaPipelineLayout);
617 for (
auto &slot : shadowMaps) {
619 if (slot.framebuffers[i]) {
620 device->destroyFramebuffer(slot.framebuffers[i]);
621 slot.framebuffers[i] = vk::Framebuffer{};
627 device->destroySampler(shadowSampler);
628 shadowSampler = vkb::DepthSampler{};
630 if (shadowRawSampler) {
631 device->destroySampler(shadowRawSampler);
632 shadowRawSampler =
nullptr;
634 if (shadowRenderPass) {
635 device->destroyRenderPass(shadowRenderPass);
636 shadowRenderPass = {};
638 shadowPassCascade = -1;
639 shadowPassDraws.clear();
640 shadowPendingMask = 0;
641 for (
auto &
d : shadowCascadeDraws)
d.
clear();
644void Graphics::destroyGBufferResources() {
645 resetDeferredFrameGraphs();
646 gbufferPassActive =
false;
647 gbufferPending =
false;
648 gbufferPassDraws.clear();
649 for (
auto &slot : gbufferSlots) {
650 slot.normalTex.gpuHandle =
nullptr;
651 slot.depthColorTex.gpuHandle =
nullptr;
652 slot.albedoTex.gpuHandle =
nullptr;
653 slot.pbrParamsTex.gpuHandle =
nullptr;
654 slot.emissiveTex.gpuHandle =
nullptr;
655 slot.visIDTex.gpuHandle =
nullptr;
656 slot.visBaryTex.gpuHandle =
nullptr;
657 slot.depthTex.gpuHandle =
nullptr;
658 if (slot.framebuffer) {
659 device->destroyFramebuffer(slot.framebuffer);
660 slot.framebuffer = vk::Framebuffer{};
662 if (slot.visFramebuffer) {
663 device->destroyFramebuffer(slot.visFramebuffer);
664 slot.visFramebuffer = vk::Framebuffer{};
666 destroySampler(device, slot.normalGpu.sampler);
667 destroySampler(device, slot.depthColorGpu.sampler);
668 destroySampler(device, slot.albedoGpu.sampler);
669 destroySampler(device, slot.pbrParamsGpu.sampler);
670 destroySampler(device, slot.emissiveGpu.sampler);
671 destroySampler(device, slot.visIDGpu.sampler);
672 destroySampler(device, slot.visBaryGpu.sampler);
673 destroySampler(device, slot.depthGpu.sampler);
675 gbufferSlots.clear();
677 destroyPipeline(device, gbufferPipeline);
678 destroyPipeline(device, gbufferAlphaPipeline);
679 destroyPipeline(device, gbufferSkinPipeline);
680 destroyPipeline(device, gbufferSkinAlphaPipeline);
681 destroyPipeline(device, gbufferVisPipeline);
682 destroyPipeline(device, gbufferVgVisPipeline);
683 destroyPipelineLayout(device, gbufferPipelineLayout);
684 if (gbufferRenderPass) {
685 device->destroyRenderPass(gbufferRenderPass);
686 gbufferRenderPass = {};
688 if (gbufferVisRenderPass) {
689 device->destroyRenderPass(gbufferVisRenderPass);
690 gbufferVisRenderPass = {};
697void Graphics::destroySceneColorResources() {
698 sceneColorPassOpen =
false;
699 sceneColorHistoryValid =
false;
701 destroyDeferredLightingResources();
702 for (
auto &slot : sceneColorSlots) {
703 slot.colorTex.gpuHandle =
nullptr;
704 if (slot.framebuffer) {
705 device->destroyFramebuffer(slot.framebuffer);
706 slot.framebuffer = vk::Framebuffer{};
708 destroySampler(device, slot.colorGpu.sampler);
710 sceneColorSlots.clear();
712 if (sceneColorRenderPass) {
713 device->destroyRenderPass(sceneColorRenderPass);
714 sceneColorRenderPass = {};
716 if (sceneColorResumeRenderPass) {
717 device->destroyRenderPass(sceneColorResumeRenderPass);
718 sceneColorResumeRenderPass = vk::RenderPass{};
721 sceneColorHeight = 0;
722 sceneColorFormat = vk::Format::eUndefined;
723 sceneColorSamples = vk::SampleCountFlagBits::e1;
726void Graphics::createUiColorResources(
int uiW,
int uiH) {
727 if (uiW <= 0 || uiH <= 0)
return;
731 const vk::Format colorFmt = vk::Format::eR16G16B16A16Sfloat;
733 const vk::SampleCountFlags supported =
734 device.physical_device.properties.limits.framebufferColorSampleCounts;
735 const vk::SampleCountFlagBits samples =
736 (supported & vk::SampleCountFlagBits::e4) ? vk::SampleCountFlagBits::e4
737 : vk::SampleCountFlagBits::e1;
743 if (samples != vk::SampleCountFlagBits::e1) {
746 .addColorAttachment(colorFmt, vk::AttachmentLoadOp::eClear,
747 vk::AttachmentStoreOp::eDontCare, samples)
748 .addResolveColorAttachment(colorFmt, vk::AttachmentLoadOp::eDontCare)
749 .addSubpass(vkb::SubpassBuilder()
750 .addAttachmentRef(0, vk::ImageLayout::eColorAttachmentOptimal)
751 .addResolveAttachment(1, vk::ImageLayout::eColorAttachmentOptimal))
752 .addExternalShaderReadDependencies()
757 .addSampledColorAttachment(colorFmt)
758 .addSubpass(vkb::SubpassBuilder()
759 .addAttachmentRef(0, vk::ImageLayout::eColorAttachmentOptimal))
760 .addExternalShaderReadDependencies()
766 uiColorSamples = samples;
768 if (!texSetLayout || !descriptorPool)
return;
769 if (!uiTexturePipeline) {
770 const auto vert = embeddedSpirv(textured_vert_spv);
771 const auto frag = embeddedSpirv(textured_frag_spv);
772 const auto opaqueFrag = embeddedSpirv(textured_opaque_frag_spv);
773 uiTexturePipeline = createTexturedStylePipeline(
vert,
frag, uiRenderPass,
776 uiTextureOpaquePipeline = createTexturedStylePipeline(
781 if (!uiColorSlots.empty() && uiColorWidth == uiW && uiColorHeight == uiH &&
782 uiColorFormat == colorFmt && uiColorSamples == samples)
784 destroyUiColorTargets();
788 uiColorFormat = colorFmt;
789 uiColorSamples = samples;
790 const uint32_t
w = uint32_t(uiW);
791 const uint32_t
h = uint32_t(uiH);
792 const bool msaa = samples != vk::SampleCountFlagBits::e1;
794 uiColorSlots.resize(kAsyncResourceCopies);
795 for (
auto &slot : uiColorSlots) {
796 slot.color =
device.createColorTarget(
w,
h, colorFmt);
797 if (msaa) slot.msaaColor =
device.createColorTarget(
w,
h, colorFmt, samples);
799 auto uiPass = uiRenderPass;
801 for (
auto &slot : uiColorSlots) {
803 slot.framebuffer = uiPass.createFramebuffer(
804 device,
w,
h, {slot.msaaColor.asAttachment(), slot.color.asAttachment()});
806 slot.framebuffer = uiPass.createFramebuffer(device,
w,
h, {slot.color.asAttachment()});
810 auto makeSampleTex = [&](GpuTexture &gpu,
Texture &tex, vk::ImageView
view) {
811 vkb::SamplerBuilder sb;
812 gpu.sampler = sb.magFilter(vk::Filter::eLinear)
813 .minFilter(vk::Filter::eLinear)
814 .addressModeU(vk::SamplerAddressMode::eClampToEdge)
815 .addressModeV(vk::SamplerAddressMode::eClampToEdge)
817 auto sets = vkb::DescriptorSetBuilder()
818 .layout(texSetLayout)
819 .build(
device.instance, descriptorPool);
820 gpu.descriptorSet = vkb::BoundSet{sets[0]};
823 gpu.viewOverride =
view;
824 writeCombinedImageDescriptor(&gpu);
827 tex.pixelWidth =
width;
829 tex.gpuHandle = &gpu;
831 for (
auto &slot : uiColorSlots)
832 makeSampleTex(slot.colorGpu, slot.colorTex, slot.
color.imageView());
835void Graphics::destroyUiColorTargets() {
837 for (
auto &slot : uiColorSlots) {
838 slot.colorTex.gpuHandle =
nullptr;
839 if (slot.framebuffer) {
840 device->destroyFramebuffer(slot.framebuffer);
841 slot.framebuffer = vk::Framebuffer{};
843 destroySampler(device, slot.colorGpu.sampler);
845 uiColorSlots.clear();
848 uiColorFormat = vk::Format::eUndefined;
852void Graphics::destroyUiColorResources() {
853 destroyUiColorTargets();
854 if (uiTexturePipeline) {
855 device->destroyPipeline(uiTexturePipeline);
856 uiTexturePipeline =
nullptr;
858 if (uiTextureOpaquePipeline) {
859 device->destroyPipeline(uiTextureOpaquePipeline);
860 uiTextureOpaquePipeline =
nullptr;
863 device->destroyRenderPass(uiRenderPass);
868void Graphics::queueUiResolve() {
869 auto *slot = currentUiColorSlot();
870 if (!slot || !slot->colorTex.gpuHandle)
return;
875 TexturedBatch resolve{&slot->colorTex,
nullptr,
nullptr,
BlendMode::Alpha, Batcher{}};
876 resolve.batch.addTexturedRect(0.f, 0.f,
float(uiColorWidth),
float(uiColorHeight),
877 Color(1.f, 1.f, 1.f, 1.f), 0.f, 0.f, 1.f, 1.f);
878 pendingUiResolve = std::move(resolve);
881bool Graphics::renderUiOverlayPass() {
884 createUiColorResources(
int(swapchain.extent.width),
int(swapchain.extent.height));
885 auto *slot = currentUiColorSlot();
886 if (!slot || !uiRenderPass || !slot->framebuffer)
return false;
888 auto &cb = currentPresentCb();
889 const bool msaa = uiColorSamples != vk::SampleCountFlagBits::e1;
890 std::array<vk::ClearValue, 2> clears{};
891 clears[0].color = vk::ClearColorValue(std::array<float, 4>{0.f, 0.f, 0.f, 0.f});
892 clears[1].color = vk::ClearColorValue(std::array<float, 4>{0.f, 0.f, 0.f, 0.f});
893 vk::RenderPassBeginInfo rpBegin{};
894 rpBegin.renderPass = uiRenderPass;
895 rpBegin.framebuffer = slot->framebuffer;
896 rpBegin.renderArea = vk::Rect2D{{0, 0}, {uint32_t(uiColorWidth), uint32_t(uiColorHeight)}};
897 rpBegin.clearValueCount = msaa ? 2 : 1;
898 rpBegin.pClearValues = clears.data();
900 slot->color.beginColorAttachment();
901 if (msaa) slot->msaaColor.beginColorAttachment();
902 cb.beginRenderPass(rpBegin, vk::SubpassContents::eInline);
904 VkCommandBuffer raw =
static_cast<VkCommandBuffer
>(cb);
908 slot->color.endSampledLayout();
914void Graphics::createGBufferResources(
int gbufW,
int gbufH) {
915 if (gbufW <= 0 || gbufH <= 0)
return;
916 if (!gbufferSlots.empty() && gbufferWidth == gbufW && gbufferHeight == gbufH && gbufferPipeline)
918 destroyGBufferResources();
920 gbufferWidth = gbufW;
921 gbufferHeight = gbufH;
922 const uint32_t
w = uint32_t(gbufW);
923 const uint32_t
h = uint32_t(gbufH);
924 const vk::Format colorFmt = pickGBufferColorFormat(device);
925 const vk::Format depthFmt = vk::Format::eD32Sfloat;
926 const vk::Format visIDFmt = vk::Format::eR32G32Uint;
927 const vk::Format visBaryFmt = vk::Format::eR16G16Sfloat;
929 gbufferSlots.resize(kAsyncResourceCopies);
930 for (
auto &slot : gbufferSlots) {
931 slot.normal =
device.createColorTarget(
w,
h, colorFmt);
932 slot.depthColor =
device.createColorTarget(
w,
h, colorFmt);
933 slot.albedo =
device.createColorTarget(
w,
h, colorFmt);
934 slot.pbrParams =
device.createColorTarget(
w,
h, colorFmt);
935 slot.emissive =
device.createColorTarget(
w,
h, colorFmt);
936 slot.visID =
device.createColorTarget(
w,
h, visIDFmt);
937 slot.visBary =
device.createColorTarget(
w,
h, visBaryFmt);
938 slot.depth =
device.createDepthTarget(
w,
h, depthFmt,
true);
943 .addSampledColorAttachment(colorFmt)
944 .addSampledColorAttachment(colorFmt)
945 .addSampledColorAttachment(colorFmt)
946 .addSampledColorAttachment(colorFmt)
947 .addSampledColorAttachment(colorFmt)
948 .addSampledDepthAttachment(depthFmt)
949 .addSubpass(vkb::SubpassBuilder()
950 .addAttachmentRef(0, vk::ImageLayout::eColorAttachmentOptimal)
951 .addAttachmentRef(1, vk::ImageLayout::eColorAttachmentOptimal)
952 .addAttachmentRef(2, vk::ImageLayout::eColorAttachmentOptimal)
953 .addAttachmentRef(3, vk::ImageLayout::eColorAttachmentOptimal)
954 .addAttachmentRef(4, vk::ImageLayout::eColorAttachmentOptimal)
955 .setDepthStencilAttachment(5, vk::ImageLayout::eDepthStencilAttachmentOptimal))
959 .addDependency(0, VK_SUBPASS_EXTERNAL,
960 vk::PipelineStageFlagBits::eColorAttachmentOutput |
961 vk::PipelineStageFlagBits::eEarlyFragmentTests |
962 vk::PipelineStageFlagBits::eLateFragmentTests,
963 vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eFragmentShader,
964 vk::AccessFlagBits::eColorAttachmentWrite | vk::AccessFlagBits::eDepthStencilAttachmentWrite,
965 vk::AccessFlagBits::eShaderRead)
967 gbufferRenderPass = gbufferPass;
969 for (
auto &slot : gbufferSlots) {
970 slot.framebuffer = gbufferPass.createFramebuffer(
972 {slot.normal.asAttachment(), slot.depthColor.asAttachment(), slot.albedo.asAttachment(),
973 slot.pbrParams.asAttachment(), slot.emissive.asAttachment(), slot.depth.asAttachment()});
976 auto layoutBuilder =
device.createPipelineLayout();
977 if (texSetLayout) layoutBuilder.set(texSetLayout);
978 gbufferPipelineLayout =
980 .push<GBufferPush>(vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment)
983 std::vector<uint32_t>
vert(mesh3d_gbuffer_vert_spv,
984 mesh3d_gbuffer_vert_spv + mesh3d_gbuffer_vert_spv_count);
985 std::vector<uint32_t>
frag(mesh3d_gbuffer_frag_spv,
986 mesh3d_gbuffer_frag_spv + mesh3d_gbuffer_frag_spv_count);
987 vk::ShaderModule vertModule = vkb::PipelineBuilder::createShaderModule(
device.instance,
vert);
988 vk::ShaderModule fragModule = vkb::PipelineBuilder::createShaderModule(
device.instance,
frag);
991 .useClassicPipeline(vertModule, fragModule)
992 .setPipelineLayout(gbufferPipelineLayout)
993 .setVertexInputState(
994 vkb::VertexInputStateBuilder().addInputBinding<MeshVertex>().addAttributeDescription<MeshVertex>())
995 .setDynamicStatesViewportScissor()
996 .setRasterizer(vk::PolygonMode::eFill,
false,
false, 1.0f, vk::CullModeFlagBits::eNone,
997 vk::FrontFace::eClockwise)
998 .setColorAttachmentCount(5)
1000 device->destroyShaderModule(vertModule);
1001 device->destroyShaderModule(fragModule);
1005 vk::ShaderModule alphaVertModule =
1006 vkb::PipelineBuilder::createShaderModule(
device.instance,
vert);
1007 std::vector<uint32_t> alphaFrag(mesh3d_gbuffer_alpha_frag_spv,
1008 mesh3d_gbuffer_alpha_frag_spv +
1009 mesh3d_gbuffer_alpha_frag_spv_count);
1010 vk::ShaderModule alphaFragModule =
1011 vkb::PipelineBuilder::createShaderModule(
device.instance, alphaFrag);
1012 gbufferAlphaPipeline =
1014 .useClassicPipeline(alphaVertModule, alphaFragModule)
1015 .setPipelineLayout(gbufferPipelineLayout)
1016 .setVertexInputState(
1017 vkb::VertexInputStateBuilder().addInputBinding<MeshVertex>().addAttributeDescription<MeshVertex>())
1018 .setDynamicStatesViewportScissor()
1019 .setRasterizer(vk::PolygonMode::eFill,
false,
false, 1.0f, vk::CullModeFlagBits::eNone,
1020 vk::FrontFace::eClockwise)
1021 .setColorAttachmentCount(5)
1022 .build(gbufferPass);
1023 device->destroyShaderModule(alphaVertModule);
1024 device->destroyShaderModule(alphaFragModule);
1026 auto skinVert = embeddedSpirv(mesh3d_gbuffer_skin_vert_spv);
1027 auto skinFrag = embeddedSpirv(mesh3d_gbuffer_skin_frag_spv);
1028 gbufferSkinPipeline =
1030 .useClassicPipeline(skinVert, skinFrag)
1031 .setPipelineLayout(skinPassPipelineLayout)
1032 .setVertexInputState(
1033 vkb::VertexInputStateBuilder().addInputBinding<MeshVertex>().addAttributeDescription<MeshVertex>())
1034 .setDynamicStatesViewportScissor()
1035 .setRasterizer(vk::PolygonMode::eFill,
false,
false, 1.0f, vk::CullModeFlagBits::eNone,
1036 vk::FrontFace::eClockwise)
1037 .setColorAttachmentCount(5)
1038 .build(gbufferPass);
1039 auto skinAlphaFrag = embeddedSpirv(mesh3d_gbuffer_skin_alpha_frag_spv);
1040 gbufferSkinAlphaPipeline =
1042 .useClassicPipeline(skinVert, skinAlphaFrag)
1043 .setPipelineLayout(skinPassPipelineLayout)
1044 .setVertexInputState(
1045 vkb::VertexInputStateBuilder().addInputBinding<MeshVertex>().addAttributeDescription<MeshVertex>())
1046 .setDynamicStatesViewportScissor()
1047 .setRasterizer(vk::PolygonMode::eFill,
false,
false, 1.0f, vk::CullModeFlagBits::eNone,
1048 vk::FrontFace::eClockwise)
1049 .setColorAttachmentCount(5)
1050 .build(gbufferPass);
1052 auto makeSampleTex = [&](GpuTexture &gpu,
Texture &tex, vk::ImageView
view) {
1053 vkb::SamplerBuilder sb;
1054 gpu.sampler = sb.nearestClamp().build(device);
1055 auto sets = vkb::DescriptorSetBuilder()
1056 .layout(texSetLayout)
1057 .build(
device.instance, descriptorPool);
1058 gpu.descriptorSet = vkb::BoundSet{sets[0]};
1061 gpu.viewOverride =
view;
1062 writeCombinedImageDescriptor(&gpu);
1065 tex.pixelWidth = gbufW;
1066 tex.pixelHeight = gbufH;
1067 tex.gpuHandle = &gpu;
1069 for (
auto &slot : gbufferSlots) {
1070 makeSampleTex(slot.normalGpu, slot.normalTex, slot.normal.imageView());
1071 makeSampleTex(slot.depthColorGpu, slot.depthColorTex, slot.depthColor.imageView());
1072 makeSampleTex(slot.albedoGpu, slot.albedoTex, slot.albedo.imageView());
1073 makeSampleTex(slot.pbrParamsGpu, slot.pbrParamsTex, slot.pbrParams.imageView());
1074 makeSampleTex(slot.emissiveGpu, slot.emissiveTex, slot.emissive.imageView());
1075 makeSampleTex(slot.visIDGpu, slot.visIDTex, slot.visID.imageView());
1076 makeSampleTex(slot.visBaryGpu, slot.visBaryTex, slot.visBary.imageView());
1077 makeSampleTex(slot.depthGpu, slot.depthTex, slot.depth.imageView());
1079 createGpuDrivenVisResources(gbufW, gbufH);
1082void Graphics::ensureDecalUnitBox() {
1083 if (decalUnitBox)
return;
1086 const float h = 0.5f;
1087 const std::vector<glm::vec3>
pos = {
1089 {-
h, -
h,
h}, {
h, -
h,
h}, {
h,
h,
h}, {-
h,
h,
h},
1091 {
h, -
h, -
h}, {-
h, -
h, -
h}, {-
h,
h, -
h}, {
h,
h, -
h},
1093 {
h, -
h,
h}, {
h, -
h, -
h}, {
h,
h, -
h}, {
h,
h,
h},
1095 {-
h, -
h, -
h}, {-
h, -
h,
h}, {-
h,
h,
h}, {-
h,
h, -
h},
1097 {-
h,
h,
h}, {
h,
h,
h}, {
h,
h, -
h}, {-
h,
h, -
h},
1099 {-
h, -
h, -
h}, {
h, -
h, -
h}, {
h, -
h,
h}, {-
h, -
h,
h},
1101 const std::vector<glm::vec3> nrm = {
1102 {0, 0, 1}, {0, 0, 1}, {0, 0, 1}, {0, 0, 1},
1103 {0, 0, -1}, {0, 0, -1}, {0, 0, -1}, {0, 0, -1},
1104 {1, 0, 0}, {1, 0, 0}, {1, 0, 0}, {1, 0, 0},
1105 {-1, 0, 0}, {-1, 0, 0}, {-1, 0, 0}, {-1, 0, 0},
1106 {0, 1, 0}, {0, 1, 0}, {0, 1, 0}, {0, 1, 0},
1107 {0, -1, 0}, {0, -1, 0}, {0, -1, 0}, {0, -1, 0},
1109 const std::vector<glm::vec2>
uv = {
1110 {0, 0}, {1, 0}, {1, 1}, {0, 1},
1111 {0, 0}, {1, 0}, {1, 1}, {0, 1},
1112 {0, 0}, {1, 0}, {1, 1}, {0, 1},
1113 {0, 0}, {1, 0}, {1, 1}, {0, 1},
1114 {0, 0}, {1, 0}, {1, 1}, {0, 1},
1115 {0, 0}, {1, 0}, {1, 1}, {0, 1},
1117 const std::vector<uint32_t>
idx = {
1118 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7,
1119 8, 9, 10, 8, 10, 11, 12, 13, 14, 12, 14, 15,
1120 16, 17, 18, 16, 18, 19, 20, 21, 22, 20, 22, 23,
1122 std::vector<float> posF, nrmF, uvF;
1123 posF.reserve(
pos.size() * 3);
1124 nrmF.reserve(nrm.size() * 3);
1125 uvF.reserve(
uv.size() * 2);
1126 for (
const auto &
p :
pos) posF.insert(posF.
end(), {
p.x,
p.y,
p.z});
1127 for (
const auto &
n : nrm) nrmF.insert(nrmF.
end(), {
n.x,
n.y,
n.z});
1128 for (
const auto &
t :
uv) uvF.insert(uvF.
end(), {
t.x,
t.y});
1134void Graphics::createDecalResources(
int decalW,
int decalH) {
1135 if (decalW <= 0 || decalH <= 0)
return;
1136 if (!decalSlots.empty() && decalWidth == decalW && decalHeight == decalH && decalPipeline)
1138 destroyDecalResources();
1140 decalWidth = decalW;
1141 decalHeight = decalH;
1142 const uint32_t
w = uint32_t(decalW);
1143 const uint32_t
h = uint32_t(decalH);
1144 const vk::Format colorFmt = pickGBufferColorFormat(device);
1146 decalSlots.resize(kAsyncResourceCopies);
1147 for (
auto &slot : decalSlots) {
1148 slot.albedo =
device.createColorTarget(
w,
h, colorFmt);
1149 slot.normal =
device.createColorTarget(
w,
h, colorFmt);
1150 slot.params =
device.createColorTarget(
w,
h, colorFmt);
1151 slot.cameraUbo.allocate(frameToken(), device, vk::BufferUsageFlagBits::eUniformBuffer,
1152 sizeof(DecalCameraUBO), kHostVisibleCoherent);
1156 device.createRenderPass()
1157 .addSampledColorAttachment(colorFmt)
1158 .addSampledColorAttachment(colorFmt)
1159 .addSampledColorAttachment(colorFmt)
1160 .addSubpass(vkb::SubpassBuilder()
1161 .addAttachmentRef(0, vk::ImageLayout::eColorAttachmentOptimal)
1162 .addAttachmentRef(1, vk::ImageLayout::eColorAttachmentOptimal)
1163 .addAttachmentRef(2, vk::ImageLayout::eColorAttachmentOptimal))
1164 .addExternalShaderReadDependencies()
1166 decalRenderPass = decalPass;
1168 for (
auto &slot : decalSlots) {
1169 slot.framebuffer = decalPass.createFramebuffer(
1171 {slot.albedo.asAttachment(), slot.normal.asAttachment(), slot.params.asAttachment()});
1174 vkb::DescriptorSetLayoutBuilder layoutBuilder;
1175 decalSetLayoutUnique =
1177 .image(0, vk::DescriptorType::eCombinedImageSampler,
1178 vk::ShaderStageFlagBits::eFragment, 1)
1179 .image(1, vk::DescriptorType::eCombinedImageSampler,
1180 vk::ShaderStageFlagBits::eFragment, 1)
1181 .image(2, vk::DescriptorType::eCombinedImageSampler,
1182 vk::ShaderStageFlagBits::eFragment, 1)
1183 .image(3, vk::DescriptorType::eCombinedImageSampler,
1184 vk::ShaderStageFlagBits::eFragment, 1)
1185 .image(4, vk::DescriptorType::eCombinedImageSampler,
1186 vk::ShaderStageFlagBits::eFragment, 1)
1187 .buffer(5, vk::DescriptorType::eUniformBuffer,
1188 vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment, 1)
1189 .createUnique(
device.instance);
1190 decalSetLayout = *decalSetLayoutUnique;
1191 const vk::PushConstantRange decalPushRange{
1192 vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment, 0,
1193 uint32_t(
sizeof(DecalInstanceData))};
1194 decalPipelineLayout =
device.createPipelineLayout()
1195 .set(decalSetLayout)
1196 .push(vk::ShaderStageFlagBits::eVertex |
1197 vk::ShaderStageFlagBits::eFragment,
1198 decalPushRange.size, decalPushRange.offset)
1201 std::vector<uint32_t>
vert(decal_box_vert_spv, decal_box_vert_spv + decal_box_vert_spv_count);
1202 std::vector<uint32_t>
frag(decal_box_frag_spv, decal_box_frag_spv + decal_box_frag_spv_count);
1203 vk::ShaderModule vertModule = vkb::PipelineBuilder::createShaderModule(
device.instance,
vert);
1204 vk::ShaderModule fragModule = vkb::PipelineBuilder::createShaderModule(
device.instance,
frag);
1208 decalPipeline =
device.createPipeline()
1209 .useClassicPipeline(vertModule, fragModule)
1210 .setPipelineLayout(decalPipelineLayout)
1211 .setDynamicStatesViewportScissor()
1212 .setRasterizer(vk::PolygonMode::eFill,
false,
false, 1.0f,
1213 vk::CullModeFlagBits::eNone, vk::FrontFace::eClockwise)
1214 .setMultisampler(
false, vk::SampleCountFlagBits::e1)
1215 .setDepthStencil(
false,
false, vk::CompareOp::eAlways)
1216 .setAlphaBlending(3)
1218 device->destroyShaderModule(vertModule);
1219 device->destroyShaderModule(fragModule);
1221 auto makeSampleTex = [&](GpuTexture &gpu,
Texture &tex, vk::ImageView
view) {
1222 vkb::SamplerBuilder sb;
1223 gpu.sampler = sb.nearestClamp().build(device);
1224 auto sets = vkb::DescriptorSetBuilder()
1225 .layout(texSetLayout)
1226 .build(
device.instance, descriptorPool);
1227 gpu.descriptorSet = vkb::BoundSet{sets[0]};
1229 gpu.height = decalH;
1230 gpu.viewOverride =
view;
1231 writeCombinedImageDescriptor(&gpu);
1233 tex.height = decalH;
1234 tex.pixelWidth = decalW;
1235 tex.pixelHeight = decalH;
1236 tex.gpuHandle = &gpu;
1238 for (
auto &slot : decalSlots) {
1239 makeSampleTex(slot.albedoGpu, slot.albedoTex, slot.albedo.imageView());
1240 makeSampleTex(slot.normalGpu, slot.normalTex, slot.normal.imageView());
1241 makeSampleTex(slot.paramsGpu, slot.paramsTex, slot.params.imageView());
1245void Graphics::destroyDecalResources() {
1246 decalPassActive =
false;
1247 decalPending =
false;
1248 decalPassDraws.clear();
1249 for (
auto &slot : decalSlots) {
1250 slot.albedoTex.gpuHandle =
nullptr;
1251 slot.normalTex.gpuHandle =
nullptr;
1252 slot.paramsTex.gpuHandle =
nullptr;
1253 if (slot.framebuffer) {
1254 device->destroyFramebuffer(slot.framebuffer);
1255 slot.framebuffer = vk::Framebuffer{};
1257 destroySampler(device, slot.albedoGpu.sampler);
1258 destroySampler(device, slot.normalGpu.sampler);
1259 destroySampler(device, slot.paramsGpu.sampler);
1260 slot.cameraUbo.release();
1264 destroyPipeline(device, decalPipeline);
1265 destroyPipelineLayout(device, decalPipelineLayout);
1266 if (decalSetLayoutUnique) decalSetLayoutUnique.reset();
1267 if (decalRenderPass) {
1268 device->destroyRenderPass(decalRenderPass);
1269 decalRenderPass = {};
1275vkb::BoundSet Graphics::decalSetFor(DecalSlot &slot, GpuTexture *
albedo, GpuTexture *
normal,
1277 GpuTexture *gbNormal) {
1278 ASSERT(
albedo !=
nullptr);
1279 ASSERT(
normal !=
nullptr);
1280 ASSERT(
params !=
nullptr);
1281 ASSERT(
depth !=
nullptr);
1282 ASSERT(gbNormal !=
nullptr);
1284 auto it = slot.sets.find(
key);
1285 if (it != slot.sets.end())
return it->second;
1287 auto sets = vkb::DescriptorSetBuilder()
1288 .layout(decalSetLayout)
1289 .build(
device.instance, descriptorPool);
1290 vkb::UnboundSet unbound{sets.front()};
1291 vkb::DescriptorSetUpdater updater(1, 5, 0);
1292 updater.beginDescriptorSet(unbound)
1293 .beginImages(0, 0, vk::DescriptorType::eCombinedImageSampler)
1294 .image(vkb::SampledImage::forLaterSample(
albedo->sampler,
albedo->imageView()))
1295 .beginImages(1, 0, vk::DescriptorType::eCombinedImageSampler)
1296 .image(vkb::SampledImage::forLaterSample(
normal->sampler,
normal->imageView()))
1297 .beginImages(2, 0, vk::DescriptorType::eCombinedImageSampler)
1298 .image(vkb::SampledImage::forLaterSample(
params->sampler,
params->imageView()))
1299 .beginImages(3, 0, vk::DescriptorType::eCombinedImageSampler)
1300 .image(vkb::SampledImage::forLaterSample(
depth->sampler,
depth->imageView()))
1301 .beginImages(4, 0, vk::DescriptorType::eCombinedImageSampler)
1302 .image(vkb::SampledImage::forLaterSample(gbNormal->sampler, gbNormal->imageView()))
1303 .beginBuffers(5, 0, vk::DescriptorType::eUniformBuffer)
1304 .buffer(slot.cameraUbo.buffer, 0, slot.cameraUbo.size)
1305 .update(
device.instance);
1307 vkb::BoundSet bound = std::move(unbound).publish();
1308 slot.sets.emplace(
key, bound);
1312void Graphics::createSceneColorResources(
int sceneW,
int sceneH) {
1313 if (sceneW <= 0 || sceneH <= 0)
return;
1314 if (!texSetLayout || !descriptorPool)
return;
1316 const vk::Format colorFmt = vk::Format::eR16G16B16A16Sfloat;
1319 const int desired = featureMsaa ?
msaaSamples : 0;
1320 if (desired != appliedMsaa) appliedMsaa = desired;
1321 const vk::SampleCountFlagBits samples = sampleCountFlagFor(clampMsaaSamples(appliedMsaa));
1323 if (!sceneColorSlots.empty() && sceneColorWidth == sceneW && sceneColorHeight == sceneH &&
1324 sceneColorFormat == colorFmt && sceneColorSamples == samples && sceneColorRenderPass)
1326 destroySceneColorResources();
1328 sceneColorWidth = sceneW;
1329 sceneColorHeight = sceneH;
1330 sceneColorFormat = colorFmt;
1331 sceneColorSamples = samples;
1332 const uint32_t
w = uint32_t(sceneW);
1333 const uint32_t
h = uint32_t(sceneH);
1334 const vk::Format depthFmt = depthFormat;
1335 const bool msaa = samples != vk::SampleCountFlagBits::e1;
1337 sceneColorSlots.resize(kAsyncResourceCopies);
1338 for (
auto &slot : sceneColorSlots) {
1339 slot.color =
device.createColorTarget(
w,
h, colorFmt);
1341 slot.msaaColor =
device.createColorTarget(
w,
h, colorFmt, samples);
1342 slot.depth =
device.createDepthTarget(
w,
h, depthFmt,
false, samples);
1344 slot.depth =
device.createDepthTarget(
w,
h, depthFmt,
false);
1352 sceneColorRenderPass =
1353 device.createRenderPass()
1354 .addColorAttachment(colorFmt, vk::AttachmentLoadOp::eClear,
1355 vk::AttachmentStoreOp::eDontCare, samples)
1356 .addResolveColorAttachment(colorFmt, vk::AttachmentLoadOp::eDontCare)
1357 .addDepthAttachment(depthFmt, vk::AttachmentLoadOp::eClear,
1358 vk::AttachmentStoreOp::eDontCare, samples)
1359 .addSubpass(vkb::SubpassBuilder()
1360 .addAttachmentRef(0, vk::ImageLayout::eColorAttachmentOptimal)
1361 .addResolveAttachment(1, vk::ImageLayout::eColorAttachmentOptimal)
1362 .setDepthStencilAttachment(
1363 2, vk::ImageLayout::eDepthStencilAttachmentOptimal))
1364 .addExternalShaderReadDependencies()
1367 sceneColorRenderPass =
1368 device.createRenderPass()
1369 .addSampledColorAttachment(colorFmt)
1370 .addDepthAttachment(depthFmt, vk::AttachmentLoadOp::eClear,
1371 vk::AttachmentStoreOp::eStore)
1372 .addSubpass(vkb::SubpassBuilder()
1373 .addAttachmentRef(0, vk::ImageLayout::eColorAttachmentOptimal)
1374 .setDepthStencilAttachment(
1375 1, vk::ImageLayout::eDepthStencilAttachmentOptimal))
1376 .addExternalShaderReadDependencies()
1379 std::array<vk::AttachmentDescription, 2> attachments{};
1380 attachments[0] = vk::AttachmentDescription()
1381 .setFormat(colorFmt)
1382 .setSamples(vk::SampleCountFlagBits::e1)
1383 .setLoadOp(vk::AttachmentLoadOp::eLoad)
1384 .setStoreOp(vk::AttachmentStoreOp::eStore)
1385 .setStencilLoadOp(vk::AttachmentLoadOp::eDontCare)
1386 .setStencilStoreOp(vk::AttachmentStoreOp::eDontCare)
1387 .setInitialLayout(vk::ImageLayout::eColorAttachmentOptimal)
1388 .setFinalLayout(vk::ImageLayout::eShaderReadOnlyOptimal);
1389 attachments[1] = vk::AttachmentDescription()
1390 .setFormat(depthFmt)
1391 .setSamples(vk::SampleCountFlagBits::e1)
1392 .setLoadOp(vk::AttachmentLoadOp::eLoad)
1393 .setStoreOp(vk::AttachmentStoreOp::eStore)
1394 .setStencilLoadOp(vk::AttachmentLoadOp::eDontCare)
1395 .setStencilStoreOp(vk::AttachmentStoreOp::eDontCare)
1396 .setInitialLayout(vk::ImageLayout::eDepthStencilAttachmentOptimal)
1397 .setFinalLayout(vk::ImageLayout::eDepthStencilAttachmentOptimal);
1398 const vk::AttachmentReference colorRef{0, vk::ImageLayout::eColorAttachmentOptimal};
1399 const vk::AttachmentReference depthRef{1, vk::ImageLayout::eDepthStencilAttachmentOptimal};
1400 const vk::SubpassDescription subpass =
1401 vk::SubpassDescription()
1402 .setPipelineBindPoint(vk::PipelineBindPoint::eGraphics)
1403 .setColorAttachmentCount(1)
1404 .setPColorAttachments(&colorRef)
1405 .setPDepthStencilAttachment(&depthRef);
1406 std::array<vk::SubpassDependency, 2> dependencies{};
1407 dependencies[0] = vk::SubpassDependency()
1408 .setSrcSubpass(VK_SUBPASS_EXTERNAL)
1410 .setSrcStageMask(vk::PipelineStageFlagBits::eTransfer)
1411 .setDstStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput |
1412 vk::PipelineStageFlagBits::eEarlyFragmentTests)
1413 .setSrcAccessMask(vk::AccessFlagBits::eTransferRead)
1414 .setDstAccessMask(vk::AccessFlagBits::eColorAttachmentWrite |
1415 vk::AccessFlagBits::eDepthStencilAttachmentRead);
1416 dependencies[1] = vk::SubpassDependency()
1418 .setDstSubpass(VK_SUBPASS_EXTERNAL)
1419 .setSrcStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput)
1420 .setDstStageMask(vk::PipelineStageFlagBits::eFragmentShader)
1421 .setSrcAccessMask(vk::AccessFlagBits::eColorAttachmentWrite)
1422 .setDstAccessMask(vk::AccessFlagBits::eShaderRead);
1423 const vk::RenderPassCreateInfo resumeInfo =
1424 vk::RenderPassCreateInfo()
1425 .setAttachmentCount(
static_cast<uint32_t
>(attachments.size()))
1426 .setPAttachments(attachments.data())
1428 .setPSubpasses(&subpass)
1429 .setDependencyCount(
static_cast<uint32_t
>(dependencies.size()))
1430 .setPDependencies(dependencies.data());
1431 sceneColorResumeRenderPass =
device->createRenderPass(resumeInfo);
1433 auto scenePass = sceneColorRenderPass;
1435 for (
auto &slot : sceneColorSlots) {
1437 slot.framebuffer = scenePass.createFramebuffer(
1439 {slot.msaaColor.asAttachment(), slot.color.asAttachment(), slot.depth.asAttachment()});
1441 slot.framebuffer = scenePass.createFramebuffer(
1442 device,
w,
h, {slot.color.asAttachment(), slot.depth.asAttachment()});
1446 auto makeSampleTex = [&](GpuTexture &gpu,
Texture &tex, vk::ImageView
view) {
1447 vkb::SamplerBuilder sb;
1448 gpu.sampler = sb.magFilter(vk::Filter::eLinear)
1449 .minFilter(vk::Filter::eLinear)
1450 .addressModeU(vk::SamplerAddressMode::eClampToEdge)
1451 .addressModeV(vk::SamplerAddressMode::eClampToEdge)
1453 auto sets = vkb::DescriptorSetBuilder()
1454 .layout(texSetLayout)
1455 .build(
device.instance, descriptorPool);
1456 gpu.descriptorSet = vkb::BoundSet{sets[0]};
1459 gpu.viewOverride =
view;
1460 writeCombinedImageDescriptor(&gpu);
1463 tex.pixelWidth =
width;
1464 tex.pixelHeight =
height;
1465 tex.gpuHandle = &gpu;
1467 for (
auto &slot : sceneColorSlots) makeSampleTex(slot.colorGpu, slot.colorTex, slot.
color.imageView());
1471 createDeferredLightingPipeline();
1474bool Graphics::beginSceneColorRenderPass() {
1475 auto *slot = currentSceneColorSlot();
1476 if (!slot || !sceneColorRenderPass || !slot->framebuffer)
return false;
1477 auto &cb = currentPresentCb();
1478 const bool msaa = sceneColorSamples != vk::SampleCountFlagBits::e1;
1481 std::array<vk::ClearValue, 3> clears{};
1482 clears[0].color = vk::ClearColorValue(
1483 std::array<float, 4>{clearColor.r, clearColor.g, clearColor.b, 1.f});
1484 clears[1].color = vk::ClearColorValue(
1485 std::array<float, 4>{clearColor.r, clearColor.g, clearColor.b, 1.f});
1486 clears[2].depthStencil = vk::ClearDepthStencilValue{1.0f, 0};
1487 vk::RenderPassBeginInfo rpBegin{};
1488 rpBegin.renderPass = sceneColorRenderPass;
1489 rpBegin.framebuffer = slot->framebuffer;
1490 rpBegin.renderArea =
1491 vk::Rect2D{{0, 0}, {uint32_t(sceneColorWidth), uint32_t(sceneColorHeight)}};
1492 rpBegin.clearValueCount = uint32_t(clears.size());
1493 rpBegin.pClearValues = clears.data();
1494 slot->msaaColor.beginColorAttachment();
1495 slot->color.beginColorAttachment();
1496 slot->depth.beginDepthAttachment();
1497 cb.beginRenderPass(rpBegin, vk::SubpassContents::eInline);
1499 std::array<vk::ClearValue, 2> clears{};
1500 clears[0].color = vk::ClearColorValue(
1501 std::array<float, 4>{clearColor.r, clearColor.g, clearColor.b, 1.f});
1502 clears[1].depthStencil = vk::ClearDepthStencilValue{1.0f, 0};
1503 vk::RenderPassBeginInfo rpBegin{};
1504 rpBegin.renderPass = sceneColorRenderPass;
1505 rpBegin.framebuffer = slot->framebuffer;
1506 rpBegin.renderArea =
1507 vk::Rect2D{{0, 0}, {uint32_t(sceneColorWidth), uint32_t(sceneColorHeight)}};
1508 rpBegin.clearValueCount = uint32_t(clears.size());
1509 rpBegin.pClearValues = clears.data();
1510 slot->color.beginColorAttachment();
1511 slot->depth.beginDepthAttachment();
1512 cb.beginRenderPass(rpBegin, vk::SubpassContents::eInline);
1514 sceneColorPassOpen =
true;
1518void Graphics::endSceneColorRenderPass() {
1519 if (!sceneColorPassOpen)
return;
1520 auto &cb = currentPresentCb();
1522 sceneColorPassOpen =
false;
1523 if (
auto *slot = currentSceneColorSlot()) {
1524 slot->color.endSampledLayout();
1525 completedSceneColorSlot = currentFrameSlot() % sceneColorSlots.size();
1526 sceneColorHistoryValid =
true;
1530int Graphics::clampMsaaSamples(
int requested)
const {
1531 if (requested <= 1)
return 0;
1532 vk::SampleCountFlags supported =
1533 device.physical_device.properties.limits.framebufferColorSampleCounts &
1534 device.physical_device.properties.limits.framebufferDepthSampleCounts;
1535 const int candidates[3] = {8, 4, 2};
1536 for (
int c : candidates) {
1537 if (requested >=
c && (supported & sampleCountFlagFor(
c)))
return c;
1539 for (
int c : candidates) {
1540 if (supported & sampleCountFlagFor(
c))
return c;
1545void Graphics::ensureScenePassPipelines(
const vkb::BuiltRenderPass &
target,
1546 vk::SampleCountFlagBits samples) {
1547 createMesh3DPipeline();
1548 const vk::RenderPass targetHandle = vk::RenderPass(
target);
1549 if (targetHandle == scenePassPipelineTarget && samples == scenePassPipelineSamples)
return;
1551 destroyPbrResources();
1553 destroyPipeline(device, mesh3dPipeline);
1554 destroyPipeline(device, mesh3dTransparentPipeline);
1555 for (
auto &pipeline : mesh3dSurfacePipelines) destroyPipeline(
device, pipeline);
1556 destroyPipeline(device, mesh3dClusteredPipeline);
1557 destroyPipeline(device, mesh3dGpuDrivenPipeline);
1558 destroyPipeline(device, resolveVisPipeline);
1559 destroyPipeline(device, voxelRectPipeline);
1560 for (
auto &pipeline : primitive3DPipelines) destroyPipeline(
device, pipeline);
1562 mesh3dPipeline = createMesh3DStylePipeline(embeddedSpirv(mesh3d_vert_spv),
1563 embeddedSpirv(mesh3d_frag_spv),
1564 mesh3dPipelineLayout,
target, samples);
1565 mesh3dTransparentPipeline =
1566 createMesh3DHairPipeline(embeddedSpirv(mesh3d_vert_spv),
1567 embeddedSpirv(mesh3d_frag_spv), mesh3dPipelineLayout,
1569 for (
int blendValue = 0; blendValue < 5; ++blendValue) {
1571 for (
int depthValue = 0; depthValue < 2; ++depthValue) {
1572 for (
int doubleValue = 0; doubleValue < 2; ++doubleValue) {
1573 const size_t index = mesh3dPipelineIndex(
blend, depthValue != 0, doubleValue != 0);
1574 mesh3dSurfacePipelines[
index] = createMesh3DStylePipeline(
1575 embeddedSpirv(mesh3d_vert_spv), embeddedSpirv(mesh3d_frag_spv),
1576 mesh3dPipelineLayout,
target, samples,
blend, depthValue != 0,
1581 if (mesh3dGpuDrivenPipelineLayout) {
1582 mesh3dGpuDrivenPipeline =
1583 createMesh3DStylePipeline(embeddedSpirv(mesh3d_gpudriven_vert_spv),
1584 embeddedSpirv(mesh3d_gpudriven_frag_spv),
1585 mesh3dGpuDrivenPipelineLayout,
target, samples);
1586 createResolveVisPipeline(
target, samples);
1588 if (mesh3dClusteredPipelineLayout) {
1589 mesh3dClusteredPipeline =
1590 createMesh3DStylePipeline(embeddedSpirv(mesh3d_clustered_vert_spv),
1591 embeddedSpirv(mesh3d_clustered_frag_spv),
1592 mesh3dClusteredPipelineLayout,
target, samples);
1594 if (voxelRectPipelineLayout)
1595 voxelRectPipeline = buildVoxelRectPipeline(
target, samples);
1596 rebuildPrimitive3DPipelines(
target, samples);
1598 for (
auto &
g : ownedGpuShaders) {
1599 if (!
g->isMesh3D)
continue;
1600 destroyPipeline(device,
g->mesh3dPipeline);
1601 destroyPipeline(device,
g->mesh3dXrayPipeline);
1602 g->mesh3dXrayPipeline =
nullptr;
1603 if (!
g->owner)
continue;
1606 createMesh3DHairPipeline(
g->owner->vertexSpirv(),
g->owner->fragmentSpirv(),
1607 g->pipelineLayout,
target, samples);
1609 g->mesh3dPipeline = createMesh3DStylePipeline(
1610 g->owner->vertexSpirv(),
g->owner->fragmentSpirv(),
g->pipelineLayout,
target, samples,
1611 g->owner->meshBlend,
g->owner->meshDepthWrite,
g->owner->meshDoubleSided,
g->owner->meshRasterState());
1612 g->mesh3dXrayPipeline =
1613 createMesh3DXrayPipeline(
g->owner->vertexSpirv(),
g->owner->fragmentSpirv(),
1614 g->pipelineLayout,
target, samples);
1618 scenePassPipelineTarget = targetHandle;
1619 scenePassPipelineSamples = samples;
1623 return static_cast<size_t>(
depth) * 15u +
static_cast<size_t>(
blend) * 3u +
static_cast<size_t>(cull);
1626void Graphics::rebuildPrimitive3DPipelines(
const vkb::BuiltRenderPass &
target, vk::SampleCountFlagBits samples) {
1627 buildPrimitive3DPipelines(
target, samples, primitive3DPipelines);
1630void Graphics::buildPrimitive3DPipelines(
const vkb::BuiltRenderPass &
target, vk::SampleCountFlagBits samples,
1631 std::array<vk::Pipeline, kPrimitive3DPipelineVariants> &pipelines) {
1632 for (
auto &pipeline : pipelines) destroyPipeline(
device, pipeline);
1633 for (
int depthValue = 0; depthValue < 3; ++depthValue) {
1634 for (
int blendValue = 0; blendValue < 5; ++blendValue) {
1635 for (
int cullValue = 0; cullValue < 3; ++cullValue) {
1639 pipelines[primitive3DPipelineIndex(
depth,
blend, cull)] =
1640 createPrimitive3DPipeline(device,
target, pipelineLayout,
depth,
blend, cull, samples);
1646void Graphics::queueSceneColorResolve() {
1649 if (!src || !src->gpuHandle)
return;
1653 const bool reflectionPasses =
1656 if (reflectionPasses) {
1657 auto *slot = currentSceneColorSlot();
1660 if (slot && snapshot) {
1661 auto &cb = currentPresentCb();
1662 slot->color.setLayout(cb, vk::ImageLayout::eTransferSrcOptimal);
1663 snapshot->colorImage().setLayout(cb, vk::ImageLayout::eTransferDstOptimal);
1664 vk::ImageCopy region{};
1665 region.srcSubresource = {vk::ImageAspectFlagBits::eColor, 0, 0, 1};
1666 region.dstSubresource = {vk::ImageAspectFlagBits::eColor, 0, 0, 1};
1667 region.extent = vk::Extent3D{uint32_t(src->getWidth()),
1668 uint32_t(src->getHeight()), 1};
1669 cb.copyImage(slot->color.image(), vk::ImageLayout::eTransferSrcOptimal,
1670 snapshot->colorImage().image(), vk::ImageLayout::eTransferDstOptimal,
1672 slot->color.setLayout(cb, vk::ImageLayout::eShaderReadOnlyOptimal);
1673 snapshot->colorImage().setLayout(cb, vk::ImageLayout::eShaderReadOnlyOptimal);
1674 src = snapshot->getTexture();
1677 pendingSceneResolveSource = src;
1680void Graphics::materializeSceneColorResolve() {
1681 Texture *src = pendingSceneResolveSource;
1682 pendingSceneResolveSource =
nullptr;
1683 if (!src || !src->gpuHandle)
return;
1684 auto savedSolid = std::move(solidBatches);
1685 auto savedTextured = std::move(texturedBatches);
1686 auto savedLit = std::move(litBatches);
1687 auto savedSpans = std::move(overlaySpans);
1688 auto savedEngineSpans = std::move(engine3DSpans);
1689 auto savedUiResolve = std::move(pendingUiResolve);
1690 solidBatches.clear();
1691 texturedBatches.clear();
1693 overlaySpans.clear();
1694 engine3DSpans.clear();
1699 if (postProcessed) {
1706 const bool attachmentEncodesSrgb =
1707 !composeLinear && (swapchain.image_format == vk::Format::eB8G8R8A8Srgb ||
1708 swapchain.image_format == vk::Format::eR8G8B8A8Srgb);
1709 TexturedBatch resolve{postProcessed,
nullptr,
nullptr,
BlendMode::Opaque, Batcher{}};
1722 resolve.batch.addTexturedRect(0.f, 0.f,
float(
width),
float(
height),
tint, 0.f, 0.f, 1.f, 1.f);
1723 pendingSceneResolve = std::move(resolve);
1725 solidBatches = std::move(savedSolid);
1726 texturedBatches = std::move(savedTextured);
1727 litBatches = std::move(savedLit);
1728 overlaySpans = std::move(savedSpans);
1729 engine3DSpans = std::move(savedEngineSpans);
1730 pendingUiResolve = std::move(savedUiResolve);
1733void Graphics::createShadowResources() {
1734 if (!shadowMaps.empty())
return;
1739 shadowMaps.resize(kAsyncResourceCopies);
1740 for (
auto &slot : shadowMaps)
1743 vkb::SamplerBuilder sb;
1747 shadowSampler = sb.linearClamp().compareEnable(VK_TRUE).compareOp(vk::CompareOp::eLess).buildDepthPcf(device);
1748 vkb::SamplerBuilder rawBuilder;
1749 shadowRawSampler = rawBuilder.magFilter(vk::Filter::eNearest)
1750 .minFilter(vk::Filter::eNearest)
1751 .addressModeU(vk::SamplerAddressMode::eClampToEdge)
1752 .addressModeV(vk::SamplerAddressMode::eClampToEdge)
1756 device.createRenderPass()
1757 .addSampledDepthAttachment(vk::Format::eD32Sfloat)
1759 vkb::SubpassBuilder().setDepthStencilAttachment(0, vk::ImageLayout::eDepthStencilAttachmentOptimal))
1763 0, VK_SUBPASS_EXTERNAL,
1764 vk::PipelineStageFlagBits::eColorAttachmentOutput | vk::PipelineStageFlagBits::eEarlyFragmentTests |
1765 vk::PipelineStageFlagBits::eLateFragmentTests,
1766 vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eFragmentShader,
1767 vk::AccessFlagBits::eColorAttachmentWrite | vk::AccessFlagBits::eDepthStencilAttachmentWrite,
1768 vk::AccessFlagBits::eShaderRead)
1770 shadowRenderPass = shadowPass;
1772 for (
auto& slot : shadowMaps) {
1773 for (uint32_t i = 0; i < layers; ++i) {
1774 slot.framebuffers[i] =
1775 shadowPass.createFramebuffer(device,
size,
size, {slot.image.layerAttachment(i)});
1779 shadowPipelineLayout =
1780 device.createPipelineLayout()
1781 .push<glm::mat4>(vk::ShaderStageFlagBits::eVertex)
1784 std::vector<uint32_t>
vert(mesh3d_shadow_vert_spv,
1785 mesh3d_shadow_vert_spv + mesh3d_shadow_vert_spv_count);
1786 std::vector<uint32_t>
frag(mesh3d_shadow_frag_spv,
1787 mesh3d_shadow_frag_spv + mesh3d_shadow_frag_spv_count);
1788 vk::ShaderModule vertModule = vkb::PipelineBuilder::createShaderModule(
device.instance,
vert);
1789 vk::ShaderModule fragModule = vkb::PipelineBuilder::createShaderModule(
device.instance,
frag);
1792 .useClassicPipeline(vertModule, fragModule)
1793 .setPipelineLayout(shadowPipelineLayout)
1794 .setVertexInputState(vkb::VertexInputStateBuilder()
1795 .addInputBinding<MeshVertex>()
1796 .addAttributeDescription<MeshVertex>())
1797 .setDynamicStatesViewportScissor()
1801 .setRasterizer(vk::PolygonMode::eFill,
false,
false, 1.0f, vk::CullModeFlagBits::eNone,
1802 vk::FrontFace::eClockwise)
1803 .setDepthBias(0.0f, 0.5f)
1805 shadowSingleSidedPipeline =
1807 .useClassicPipeline(vertModule, fragModule)
1808 .setPipelineLayout(shadowPipelineLayout)
1809 .setVertexInputState(vkb::VertexInputStateBuilder()
1810 .addInputBinding<MeshVertex>()
1811 .addAttributeDescription<MeshVertex>())
1812 .setDynamicStatesViewportScissor()
1813 .setRasterizer(vk::PolygonMode::eFill,
false,
false, 1.0f, vk::CullModeFlagBits::eBack,
1814 vk::FrontFace::eClockwise)
1815 .setDepthBias(0.0f, 0.5f)
1817 device->destroyShaderModule(vertModule);
1818 device->destroyShaderModule(fragModule);
1823 shadowAlphaPipelineLayout =
device.createPipelineLayout()
1825 .push<ShadowAlphaPush>(vk::ShaderStageFlagBits::eVertex |
1826 vk::ShaderStageFlagBits::eFragment)
1828 std::vector<uint32_t> alphaVert(mesh3d_shadow_alpha_vert_spv,
1829 mesh3d_shadow_alpha_vert_spv +
1830 mesh3d_shadow_alpha_vert_spv_count);
1831 std::vector<uint32_t> alphaFrag(mesh3d_shadow_alpha_frag_spv,
1832 mesh3d_shadow_alpha_frag_spv +
1833 mesh3d_shadow_alpha_frag_spv_count);
1834 vk::ShaderModule alphaVertModule =
1835 vkb::PipelineBuilder::createShaderModule(
device.instance, alphaVert);
1836 vk::ShaderModule alphaFragModule =
1837 vkb::PipelineBuilder::createShaderModule(
device.instance, alphaFrag);
1838 shadowAlphaPipeline =
1840 .useClassicPipeline(alphaVertModule, alphaFragModule)
1841 .setPipelineLayout(shadowAlphaPipelineLayout)
1842 .setVertexInputState(vkb::VertexInputStateBuilder()
1843 .addInputBinding<MeshVertex>()
1844 .addAttributeDescription<MeshVertex>())
1845 .setDynamicStatesViewportScissor()
1846 .setRasterizer(vk::PolygonMode::eFill,
false,
false, 1.0f, vk::CullModeFlagBits::eNone,
1847 vk::FrontFace::eClockwise)
1848 .setDepthBias(0.0f, 0.5f)
1850 shadowAlphaSingleSidedPipeline =
1852 .useClassicPipeline(alphaVertModule, alphaFragModule)
1853 .setPipelineLayout(shadowAlphaPipelineLayout)
1854 .setVertexInputState(vkb::VertexInputStateBuilder()
1855 .addInputBinding<MeshVertex>()
1856 .addAttributeDescription<MeshVertex>())
1857 .setDynamicStatesViewportScissor()
1858 .setRasterizer(vk::PolygonMode::eFill,
false,
false, 1.0f, vk::CullModeFlagBits::eBack,
1859 vk::FrontFace::eClockwise)
1860 .setDepthBias(0.0f, 0.5f)
1862 device->destroyShaderModule(alphaVertModule);
1863 device->destroyShaderModule(alphaFragModule);
1865 auto skinVert = embeddedSpirv(mesh3d_shadow_skin_vert_spv);
1866 shadowSkinPipeline =
device.createPipeline()
1867 .useClassicPipeline(skinVert,
frag)
1868 .setPipelineLayout(skinPassPipelineLayout)
1869 .setVertexInputState(vkb::VertexInputStateBuilder()
1870 .addInputBinding<MeshVertex>()
1871 .addAttributeDescription<MeshVertex>())
1872 .setDynamicStatesViewportScissor()
1873 .setRasterizer(vk::PolygonMode::eFill,
false,
false, 1.0f,
1874 vk::CullModeFlagBits::eNone,
1875 vk::FrontFace::eClockwise)
1876 .setDepthBias(0.0f, 0.5f)
1878 shadowSkinSingleSidedPipeline =
device.createPipeline()
1879 .useClassicPipeline(skinVert,
frag)
1880 .setPipelineLayout(skinPassPipelineLayout)
1881 .setVertexInputState(vkb::VertexInputStateBuilder()
1882 .addInputBinding<MeshVertex>()
1883 .addAttributeDescription<MeshVertex>())
1884 .setDynamicStatesViewportScissor()
1885 .setRasterizer(vk::PolygonMode::eFill,
false,
false, 1.0f,
1886 vk::CullModeFlagBits::eBack,
1887 vk::FrontFace::eClockwise)
1888 .setDepthBias(0.0f, 0.5f)
1890 auto skinAlphaFrag = embeddedSpirv(mesh3d_shadow_skin_alpha_frag_spv);
1891 shadowSkinAlphaPipeline =
device.createPipeline()
1892 .useClassicPipeline(skinVert, skinAlphaFrag)
1893 .setPipelineLayout(skinPassPipelineLayout)
1894 .setVertexInputState(vkb::VertexInputStateBuilder()
1895 .addInputBinding<MeshVertex>()
1896 .addAttributeDescription<MeshVertex>())
1897 .setDynamicStatesViewportScissor()
1898 .setRasterizer(vk::PolygonMode::eFill,
false,
false, 1.0f,
1899 vk::CullModeFlagBits::eNone,
1900 vk::FrontFace::eClockwise)
1901 .setDepthBias(0.0f, 0.5f)
1903 shadowSkinAlphaSingleSidedPipeline =
device.createPipeline()
1904 .useClassicPipeline(skinVert, skinAlphaFrag)
1905 .setPipelineLayout(skinPassPipelineLayout)
1906 .setVertexInputState(vkb::VertexInputStateBuilder()
1907 .addInputBinding<MeshVertex>()
1908 .addAttributeDescription<MeshVertex>())
1909 .setDynamicStatesViewportScissor()
1910 .setRasterizer(vk::PolygonMode::eFill,
false,
false, 1.0f,
1911 vk::CullModeFlagBits::eBack,
1912 vk::FrontFace::eClockwise)
1913 .setDepthBias(0.0f, 0.5f)
1918 vkb::executeImmediately(
device.instance, uploadPool,
device.getQueue(vkb::QueueType::graphics),
1919 [&](vk::CommandBuffer cb) {
1920 vk::ClearValue clear{};
1921 clear.depthStencil = vk::ClearDepthStencilValue{1.0f, 0};
1922 for (
auto &slot : shadowMaps) {
1923 slot.image.beginDepthAttachment();
1925 vk::RenderPassBeginInfo rpBegin{};
1926 rpBegin.renderPass = shadowRenderPass;
1927 rpBegin.framebuffer = slot.framebuffers[
c];
1928 rpBegin.renderArea = vk::Rect2D{{0, 0}, {
size,
size}};
1929 rpBegin.clearValueCount = 1;
1930 rpBegin.pClearValues = &
clear;
1931 cb.beginRenderPass(rpBegin, vk::SubpassContents::eInline);
1934 slot.image.endSampledLayout();
1939void Graphics::ensureClusteredBuffers(
size_t lightsBytes,
size_t tableBytes,
size_t indicesBytes) {
1940 auto &st = currentClusteredStorage();
1941 auto ensure = [&](vkb::GenericBuffer &buf,
size_t &cap,
size_t need) {
1942 if (need == 0) need = 4;
1943 if (cap >= need && buf.buffer)
return;
1946 size_t alloc = std::max(need, cap ? cap * 2 : need);
1947 buf.allocate(frameToken(),
device, vk::BufferUsageFlagBits::eStorageBuffer, vk::DeviceSize(alloc),
1948 vk::MemoryPropertyFlagBits::eHostVisible |
1949 vk::MemoryPropertyFlagBits::eHostCoherent);
1952 ensure(st.lightsBuf, st.lightsCap, lightsBytes);
1953 ensure(st.tableBuf, st.tableCap, tableBytes);
1954 ensure(st.indicesBuf, st.indicesCap, indicesBytes);
1957 currentMesh3dClusteredFrameSlots().sets.clear();
1960void Graphics::uploadClusteredLighting(
const ClusteredLightingUpload &upload) {
1961 const size_t lightsBytes =
1963 const size_t tableBytes =
1964 std::max(
size_t(1), upload.clusterTable.size()) *
sizeof(ClusterTableEntry);
1965 const size_t indicesBytes =
1966 std::max(
size_t(1), upload.lightIndices.size()) *
sizeof(uint32_t);
1967 ensureClusteredBuffers(lightsBytes, tableBytes, indicesBytes);
1969 auto &st = currentClusteredStorage();
1970 if (!upload.lights.empty())
1971 st.lightsBuf.updateLocal(frameToken(), upload.lights.data(),
1975 st.lightsBuf.updateLocal(frameToken(), &zero,
sizeof(zero));
1977 st.tableBuf.updateLocal(frameToken(), upload.clusterTable.data(),
1978 upload.clusterTable.size() *
sizeof(ClusterTableEntry));
1979 st.indicesBuf.updateLocal(frameToken(), upload.lightIndices.data(),
1980 upload.lightIndices.size() *
sizeof(uint32_t));
1984 mesh3dClusteredActive = upload.
active;
1985 mesh3dClustered = upload;
1987 createMesh3DClusteredPipeline();
1988 uploadClusteredLighting(upload);
1993 mesh3dClusteredActive =
active;
1994 if (
active) createMesh3DClusteredPipeline();
1997void Graphics::ensureMesh3dStrides() {
1998 if (mesh3dUboStride != 0)
return;
1999 const uint32_t align = std::max(
2000 1u, uint32_t(
device.physical_device.properties.limits.minUniformBufferOffsetAlignment));
2001 mesh3dUboStride = alignUpValue(uint32_t(
sizeof(
Mesh3DUBO)), align);
2002 shadowUboStride = alignUpValue(uint32_t(
sizeof(
ShadowUBO)), align);
2003 mesh3dClusteredUboStride = alignUpValue(uint32_t(
sizeof(
Mesh3DClusteredUBO)), align);
2006void Graphics::ensureMesh3dRing(Mesh3dFrameSlots &fslots) {
2007 ensureMesh3dStrides();
2008 const size_t want = std::max<size_t>(2048, fslots.lastDrawCount + 512);
2009 if (fslots.uboRing.buffer && fslots.capacity >= want)
return;
2010 const size_t cap = std::max(want, fslots.capacity * 2);
2013 fslots.uboRing.release();
2014 fslots.uboRing.allocate(frameToken(),
device, vk::BufferUsageFlagBits::eUniformBuffer,
2015 vk::DeviceSize(cap) * mesh3dUboStride, kHostVisibleCoherent);
2016 fslots.shadowRing.release();
2017 fslots.shadowRing.allocate(frameToken(),
device, vk::BufferUsageFlagBits::eUniformBuffer,
2018 vk::DeviceSize(cap) * shadowUboStride, kHostVisibleCoherent);
2019 fslots.capacity = cap;
2020 fslots.sets.clear();
2021 fslots.skinSets.clear();
2024void Graphics::ensureMesh3dClusteredRing(Mesh3dClusteredFrameSlots &fslots) {
2025 ensureMesh3dStrides();
2026 const size_t want = std::max<size_t>(2048, fslots.lastDrawCount + 512);
2027 if (fslots.uboRing.buffer && fslots.capacity >= want)
return;
2028 const size_t cap = std::max(want, fslots.capacity * 2);
2029 fslots.uboRing.release();
2030 fslots.uboRing.allocate(frameToken(),
device, vk::BufferUsageFlagBits::eUniformBuffer,
2031 vk::DeviceSize(cap) * mesh3dClusteredUboStride, kHostVisibleCoherent);
2032 fslots.shadowRing.release();
2033 fslots.shadowRing.allocate(frameToken(),
device, vk::BufferUsageFlagBits::eUniformBuffer,
2034 vk::DeviceSize(cap) * shadowUboStride, kHostVisibleCoherent);
2035 fslots.capacity = cap;
2036 fslots.sets.clear();
2039vkb::BoundSet Graphics::mesh3dClusteredSetFor(GpuTexture *gpuTex, GpuTexture *normalTex,
2040 GpuTexture *envTex, GpuTexture *heightTex,
2041 GpuTexture *decalAlbedo, GpuTexture *decalNormal,
2042 GpuTexture *decalParams,
2043 Mesh3dClusteredFrameSlots &fslots) {
2044 ASSERT(gpuTex !=
nullptr);
2045 ASSERT(normalTex !=
nullptr);
2046 ASSERT(envTex !=
nullptr);
2047 ASSERT(heightTex !=
nullptr);
2048 ASSERT(decalAlbedo !=
nullptr);
2049 ASSERT(decalNormal !=
nullptr);
2050 ASSERT(decalParams !=
nullptr);
2051 ASSERT(currentShadowArrayView());
2052 ASSERT(fslots.uboRing.buffer);
2053 ASSERT(fslots.shadowRing.buffer);
2055 auto probeTexture = [&](
int index) -> GpuTexture * {
2056 if (
index < mesh3dReflectionProbes.count) {
2057 Texture *texture = mesh3dReflectionProbes.probes[
index].cubemap;
2058 if (texture && texture->gpuHandle) {
2059 auto *gpu =
static_cast<GpuTexture *
>(texture->gpuHandle);
2060 if (gpu->isCube)
return gpu;
2063 return static_cast<GpuTexture *
>(defaultEnvCubemap->gpuHandle);
2065 GpuTexture *probe0 = probeTexture(0);
2066 GpuTexture *probe1 = probeTexture(1);
2067 Mesh3dSetKey
key{gpuTex, normalTex, envTex, probe0, probe1, heightTex,
nullptr,
nullptr,
2068 decalAlbedo, decalNormal, decalParams};
2069 auto it = fslots.sets.find(
key);
2070 if (it != fslots.sets.end())
return it->second;
2072 vk::DescriptorSetAllocateInfo alloc{};
2073 alloc.descriptorPool = descriptorPool;
2074 alloc.descriptorSetCount = 1;
2075 alloc.pSetLayouts = &mesh3dClusteredSetLayout;
2076 vkb::UnboundSet unbound{
device->allocateDescriptorSets(alloc).front()};
2078 auto &st = currentClusteredStorage();
2079 vkb::DescriptorSetUpdater updater(17, 17, 0);
2080 updater.beginDescriptorSet(unbound)
2081 .beginBuffers(0, 0, vk::DescriptorType::eUniformBufferDynamic)
2082 .buffer(fslots.uboRing.buffer, 0,
sizeof(Mesh3DClusteredUBO))
2083 .beginImages(1, 0, vk::DescriptorType::eCombinedImageSampler)
2084 .image(vkb::SampledImage::forLaterSample(gpuTex->sampler, gpuTex->imageView()))
2085 .beginImages(2, 0, vk::DescriptorType::eCombinedImageSampler)
2086 .image(vkb::SampledImage::forLaterSample(normalTex->sampler, normalTex->imageView()))
2087 .beginImages(3, 0, vk::DescriptorType::eCombinedImageSampler)
2088 .image(vkb::SampledImage::forLaterSample(envTex->sampler, envTex->imageView()))
2089 .beginBuffers(4, 0, vk::DescriptorType::eStorageBuffer)
2090 .buffer(st.lightsBuf.buffer, 0, vk::DeviceSize(st.lightsCap))
2091 .beginBuffers(5, 0, vk::DescriptorType::eStorageBuffer)
2092 .buffer(st.tableBuf.buffer, 0, vk::DeviceSize(st.tableCap))
2093 .beginBuffers(6, 0, vk::DescriptorType::eStorageBuffer)
2094 .buffer(st.indicesBuf.buffer, 0, vk::DeviceSize(st.indicesCap))
2095 .beginBuffers(7, 0, vk::DescriptorType::eUniformBufferDynamic)
2096 .buffer(fslots.shadowRing.buffer, 0,
sizeof(ShadowUBO))
2097 .beginImages(8, 0, vk::DescriptorType::eCombinedImageSampler)
2098 .image(vkb::SampledImage::forLaterSample(shadowSampler, currentShadowArrayView()))
2099 .beginImages(9, 0, vk::DescriptorType::eCombinedImageSampler)
2100 .image(vkb::SampledImage::forLaterSample(heightTex->sampler, heightTex->imageView()))
2101 .beginImages(10, 0, vk::DescriptorType::eCombinedImageSampler)
2102 .image(vkb::SampledImage::forLaterSample(decalAlbedo->sampler, decalAlbedo->imageView()))
2103 .beginImages(11, 0, vk::DescriptorType::eCombinedImageSampler)
2104 .image(vkb::SampledImage::forLaterSample(decalNormal->sampler, decalNormal->imageView()))
2105 .beginImages(12, 0, vk::DescriptorType::eCombinedImageSampler)
2106 .image(vkb::SampledImage::forLaterSample(decalParams->sampler, decalParams->imageView()))
2107 .beginImages(18, 0, vk::DescriptorType::eCombinedImageSampler)
2108 .image(vkb::SampledImage::forLaterSample(probe0->sampler, probe0->imageView()))
2109 .beginImages(19, 0, vk::DescriptorType::eCombinedImageSampler)
2110 .image(vkb::SampledImage::forLaterSample(probe1->sampler, probe1->imageView()))
2111 .beginImages(20, 0, vk::DescriptorType::eCombinedImageSampler)
2112 .image(vkb::SampledImage::forLaterSample(shadowRawSampler, currentShadowArrayView()))
2113 .update(
device.instance);
2115 vkb::BoundSet bound = std::move(unbound).publish();
2116 fslots.sets.emplace(
key, bound);
2124vk::Pipeline Graphics::createMesh3DHairPipeline(
const std::vector<uint32_t> &
vert,
2125 const std::vector<uint32_t> &
frag,
2126 vk::PipelineLayout
layout,
2127 const vkb::BuiltRenderPass &rp,
2128 vk::SampleCountFlagBits samples) {
2129 vk::ShaderModule vertModule = vkb::PipelineBuilder::createShaderModule(
device.instance,
vert);
2130 vk::ShaderModule fragModule = vkb::PipelineBuilder::createShaderModule(
device.instance,
frag);
2133 .useClassicPipeline(vertModule, fragModule)
2134 .setPipelineLayout(
layout)
2135 .setVertexInputState(vkb::VertexInputStateBuilder()
2136 .addInputBinding<MeshVertex>()
2137 .addAttributeDescription<MeshVertex>())
2138 .setDynamicStatesViewportScissor()
2139 .setRasterizer(vk::PolygonMode::eFill,
false,
false, 1.0f, vk::CullModeFlagBits::eNone,
2140 vk::FrontFace::eClockwise)
2141 .setDepthBias(-1.5f, -1.0f)
2142 .setMultisampler(
false, samples)
2143 .setDepthStencil(
true,
false, vk::CompareOp::eLess)
2144 .setAlphaBlending(1)
2146 device->destroyShaderModule(vertModule);
2147 device->destroyShaderModule(fragModule);
2151vk::Pipeline Graphics::createMesh3DXrayPipeline(
const std::vector<uint32_t> &
vert,
2152 const std::vector<uint32_t> &
frag,
2153 vk::PipelineLayout
layout,
2154 const vkb::BuiltRenderPass &rp,
2155 vk::SampleCountFlagBits samples) {
2156 vk::ShaderModule vertModule = vkb::PipelineBuilder::createShaderModule(
device.instance,
vert);
2157 vk::ShaderModule fragModule = vkb::PipelineBuilder::createShaderModule(
device.instance,
frag);
2160 .useClassicPipeline(vertModule, fragModule)
2161 .setPipelineLayout(
layout)
2162 .setVertexInputState(vkb::VertexInputStateBuilder()
2163 .addInputBinding<MeshVertex>()
2164 .addAttributeDescription<MeshVertex>())
2165 .setDynamicStatesViewportScissor()
2166 .setRasterizer(vk::PolygonMode::eFill,
false,
false, 1.0f, vk::CullModeFlagBits::eNone,
2167 vk::FrontFace::eClockwise)
2168 .setMultisampler(
false, samples)
2171 .setDepthStencil(
false,
false, vk::CompareOp::eLess)
2172 .setAlphaBlending(1)
2173 .setColorAttachmentCount(1)
2175 device->destroyShaderModule(vertModule);
2176 device->destroyShaderModule(fragModule);
graphics::Texture * albedo
virtual Texture * getTexture()=0
Sampleable color buffer; screen Canvas returns nullptr.
Texture * prepareFinalSceneTexture(Texture *scene, Texture *motion=nullptr)
Build the shared linear-HDR AA, DOF, bloom, and exposure result for final ACES. @lifetime Returned te...
float displayPaperWhiteNits_
virtual void setMesh3DClusteredActive(bool active)=0
Cheap per-draw toggle for the already-uploaded clustered light table. Unlike setMesh3DClusteredLighti...
virtual bool isDisplayHdrActive() const
True when the live swapchain is scRGB or HDR10.
virtual void setMesh3DClusteredLighting(const ClusteredLightingUpload &upload)=0
Enable clustered forward path for subsequent default mesh draws (SSBO light lists)....
void * presentOverlayUser_
SceneToneMapping
Final display mapping; None preserves linear color, Aces uses the fitted curve, and Filmic uses Rec....
std::unique_ptr< RenderControl > renderControl_
DisplayColorSpace activeDisplayColorSpace_
PresentOverlayFn presentOverlayFn_
DisplayColorSpace
Color space actually selected for the live swapchain.
Texture * takeFinalSceneTexture()
Consume and clear the per-frame HDR scene resolve override. @lifetime Returned texture is borrowed an...
Canvas * pipelineReflectionComposite(int width, int height)
Return a reusable HDR target for composing screen-space lighting. @lifetime Returned canvas is Graphi...
static constexpr uint32_t kPushConstantBytes
GPU texture created via Graphics::newTexture. Owns GPU resources through an opaque backend handle.
float getScenePhotographicVignette() const override
Read the current render-thread photographic vignette.
Texture * getSceneColorTexture() override
Returns the scene color texture.
friend class OffscreenCanvas
Mesh * newMeshFromArrays(const float *posXYZ, const float *nrmXYZ, const float *uvST, int vertexCount, const uint32_t *indices, int indexCount) override
Creates a mesh from arrays. @ownership Caller deletes unless documented otherwise.
SceneToneMapping getSceneToneMapping() const override
Returns the scene tone mapping.
void initGpuTiming()
Creates the GPU timestamp query pool; call after device init.
void clear(std::optional< Color > color, std::optional< int > stencil, std::optional< double > depth) override
Clears .
std::vector< ParamSpec > params
Color sceneResolveTint(bool aces, ActiveColorSpace space, bool attachmentEncodesSrgb, float paperWhiteNits, float peakNits) noexcept
Build the Color tint used by the final scene present resolve.
ActiveColorSpace
Active present color encoding after swapchain selection.
Color sceneComposeTint(bool aces, float paperWhiteNits, float peakNits) noexcept
Build the Color tint for tonemapping into a linear HDR compose target.
vk::Pipeline createSolidColorPipeline(vkb::Device &device, const vkb::BuiltRenderPass &renderPass, vk::PipelineLayout layout, BlendMode mode)
Internal synchronous pipeline factory; caller destroys the returned Vulkan pipeline.
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...
Light3DGpu ClusteredLightGpu
eve::BlendMode BlendMode
Compatibility alias for the shared 2D blend mode.
PrimitiveDepthMode
Depth behavior of one 3D primitive.
CompareOp
CompareOp public API.
CPU-built clustered lighting upload for one frame/camera. Point lights are clustered; directional lig...
static constexpr int kMapSize
static constexpr int kTotalLayers
Per-frame / per-draw CSM + local-spot constants (std140).
Mesh3DClusteredUBO public API.