18const VkFormat VulkanRenderer::m_gbufferFormats[VulkanRenderer::GBUFFER_COUNT] = {
19 VK_FORMAT_R8G8B8A8_UNORM,
20 VK_FORMAT_R16G16B16A16_SFLOAT,
21 VK_FORMAT_R16G16B16A16_SFLOAT,
25bool VulkanRenderer::CreateGBufferRenderPass() {
27 VkAttachmentDescription colorAtts[GBUFFER_COUNT] = {};
28 VkAttachmentReference colorRefs[GBUFFER_COUNT] = {};
30 for (uint32_t i = 0; i < GBUFFER_COUNT; ++i) {
31 colorAtts[i].format = m_gbufferFormats[i];
32 colorAtts[i].samples = VK_SAMPLE_COUNT_1_BIT;
33 colorAtts[i].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
34 colorAtts[i].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
35 colorAtts[i].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
36 colorAtts[i].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
37 colorAtts[i].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
38 colorAtts[i].finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
40 colorRefs[i].attachment = i;
41 colorRefs[i].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
45 VkAttachmentDescription depthAtt{};
46 depthAtt.format = depthFormat;
47 depthAtt.samples = VK_SAMPLE_COUNT_1_BIT;
48 depthAtt.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
49 depthAtt.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
50 depthAtt.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
51 depthAtt.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
52 depthAtt.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
53 depthAtt.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
55 VkAttachmentReference depthRef{};
56 depthRef.attachment = GBUFFER_COUNT;
57 depthRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
59 VkSubpassDescription subpass{};
60 subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
61 subpass.colorAttachmentCount = GBUFFER_COUNT;
62 subpass.pColorAttachments = colorRefs;
63 subpass.pDepthStencilAttachment = &depthRef;
68 std::array<VkSubpassDependency, 2> deps{};
70 deps[0].srcSubpass = VK_SUBPASS_EXTERNAL;
71 deps[0].dstSubpass = 0;
72 deps[0].srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
73 deps[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
74 VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
75 deps[0].srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;
76 deps[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
77 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
78 deps[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
80 deps[1].srcSubpass = 0;
81 deps[1].dstSubpass = VK_SUBPASS_EXTERNAL;
82 deps[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
83 VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
84 deps[1].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
85 deps[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
86 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
87 deps[1].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
88 deps[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
90 std::array<VkAttachmentDescription, GBUFFER_COUNT + 1> attachments;
91 for (uint32_t i = 0; i < GBUFFER_COUNT; ++i) attachments[i] = colorAtts[i];
92 attachments[GBUFFER_COUNT] = depthAtt;
94 VkRenderPassCreateInfo rpInfo{};
95 rpInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
96 rpInfo.attachmentCount =
static_cast<uint32_t
>(attachments.size());
97 rpInfo.pAttachments = attachments.data();
98 rpInfo.subpassCount = 1;
99 rpInfo.pSubpasses = &subpass;
100 rpInfo.dependencyCount =
static_cast<uint32_t
>(deps.size());
101 rpInfo.pDependencies = deps.data();
103 return vkCreateRenderPass(device, &rpInfo,
nullptr, &m_gbufferRenderPass) == VK_SUCCESS;
107bool VulkanRenderer::CreateGBufferFramebuffer() {
108 std::array<VkImageView, GBUFFER_COUNT + 1> views;
109 for (uint32_t i = 0; i < GBUFFER_COUNT; ++i) views[i] = m_gbufferViews[i];
110 views[GBUFFER_COUNT] = depthImageView;
112 VkFramebufferCreateInfo fbInfo{};
113 fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
114 fbInfo.renderPass = m_gbufferRenderPass;
115 fbInfo.attachmentCount =
static_cast<uint32_t
>(views.size());
116 fbInfo.pAttachments = views.data();
117 fbInfo.width = scExtent.width;
118 fbInfo.height = scExtent.height;
121 return vkCreateFramebuffer(device, &fbInfo,
nullptr, &m_gbufferFramebuffer) == VK_SUCCESS;
125bool VulkanRenderer::CreateGBufferPipeline() {
127 if (!m_gbufferShader->compile(
"assets/shaders/gbuffer.vert.spv",
128 "assets/shaders/gbuffer.frag.spv")) {
129 SLEAK_ERROR(
"GBuffer: Failed to compile gbuffer shaders!");
130 delete m_gbufferShader;
131 m_gbufferShader =
nullptr;
135 VkPipelineShaderStageCreateInfo shaderStages[] = {
136 m_gbufferShader->GetVertexInfo(),
137 m_gbufferShader->GetFragInfo()
141 std::vector<VkDynamicState> dynamicStates = {
142 VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR};
143 VkPipelineDynamicStateCreateInfo dynamicState{};
144 dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
145 dynamicState.dynamicStateCount =
static_cast<uint32_t
>(dynamicStates.size());
146 dynamicState.pDynamicStates = dynamicStates.data();
149 VkVertexInputBindingDescription bindingDesc{};
150 bindingDesc.binding = 0;
151 bindingDesc.stride =
sizeof(
Vertex);
152 bindingDesc.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
154 std::array<VkVertexInputAttributeDescription, 7> attrDescs{};
155 attrDescs[0] = {0, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(Vertex, px)};
156 attrDescs[1] = {1, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(Vertex, nx)};
157 attrDescs[2] = {2, 0, VK_FORMAT_R32G32B32A32_SFLOAT, offsetof(Vertex, tx)};
158 attrDescs[3] = {3, 0, VK_FORMAT_R32G32B32A32_SFLOAT, offsetof(Vertex, r)};
159 attrDescs[4] = {4, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(Vertex, u)};
160 attrDescs[5] = {5, 0, VK_FORMAT_R32G32B32A32_SINT, offsetof(Vertex, boneIDs)};
161 attrDescs[6] = {6, 0, VK_FORMAT_R32G32B32A32_SFLOAT, offsetof(Vertex, boneWeights)};
163 VkPipelineVertexInputStateCreateInfo vertexInputInfo{};
164 vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
165 vertexInputInfo.vertexBindingDescriptionCount = 1;
166 vertexInputInfo.pVertexBindingDescriptions = &bindingDesc;
167 vertexInputInfo.vertexAttributeDescriptionCount =
static_cast<uint32_t
>(attrDescs.size());
168 vertexInputInfo.pVertexAttributeDescriptions = attrDescs.data();
170 VkPipelineInputAssemblyStateCreateInfo inputAssembly{};
171 inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
172 inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
173 inputAssembly.primitiveRestartEnable = VK_FALSE;
175 VkPipelineViewportStateCreateInfo viewportState{};
176 viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
177 viewportState.viewportCount = 1;
178 viewportState.scissorCount = 1;
180 VkPipelineRasterizationStateCreateInfo rasterizer{};
181 rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
182 rasterizer.depthClampEnable = VK_FALSE;
183 rasterizer.rasterizerDiscardEnable = VK_FALSE;
184 rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
185 rasterizer.lineWidth = 1.0f;
186 rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
187 rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
188 rasterizer.depthBiasEnable = VK_FALSE;
190 VkPipelineMultisampleStateCreateInfo msaa{};
191 msaa.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
192 msaa.sampleShadingEnable = VK_FALSE;
193 msaa.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
195 VkPipelineDepthStencilStateCreateInfo depthStencil{};
196 depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
197 depthStencil.depthTestEnable = VK_TRUE;
198 depthStencil.depthWriteEnable = VK_TRUE;
199 depthStencil.depthCompareOp = VK_COMPARE_OP_LESS;
200 depthStencil.depthBoundsTestEnable = VK_FALSE;
201 depthStencil.stencilTestEnable = VK_FALSE;
204 VkPipelineColorBlendAttachmentState opaqueBlend{};
205 opaqueBlend.blendEnable = VK_FALSE;
206 opaqueBlend.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
207 VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
209 std::array<VkPipelineColorBlendAttachmentState, GBUFFER_COUNT> colorBlendAtts;
210 colorBlendAtts.fill(opaqueBlend);
212 VkPipelineColorBlendStateCreateInfo colorBlendInfo{};
213 colorBlendInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
214 colorBlendInfo.logicOpEnable = VK_FALSE;
215 colorBlendInfo.attachmentCount =
static_cast<uint32_t
>(colorBlendAtts.size());
216 colorBlendInfo.pAttachments = colorBlendAtts.data();
219 m_gbufferPipelineLayout = m_gbufferGeomLayout;
221 VkGraphicsPipelineCreateInfo pipelineInfo{};
222 pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
223 pipelineInfo.stageCount = 2;
224 pipelineInfo.pStages = shaderStages;
225 pipelineInfo.pVertexInputState = &vertexInputInfo;
226 pipelineInfo.pInputAssemblyState = &inputAssembly;
227 pipelineInfo.pViewportState = &viewportState;
228 pipelineInfo.pRasterizationState = &rasterizer;
229 pipelineInfo.pMultisampleState = &msaa;
230 pipelineInfo.pDepthStencilState = &depthStencil;
231 pipelineInfo.pColorBlendState = &colorBlendInfo;
232 pipelineInfo.pDynamicState = &dynamicState;
233 pipelineInfo.layout = m_gbufferPipelineLayout;
234 pipelineInfo.renderPass = m_gbufferRenderPass;
235 pipelineInfo.subpass = 0;
236 pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
237 pipelineInfo.basePipelineIndex = -1;
239 VkResult result = vkCreateGraphicsPipelines(
240 device, VK_NULL_HANDLE, 1, &pipelineInfo,
nullptr, &m_gbufferPipeline);
241 if (result != VK_SUCCESS) {
242 SLEAK_ERROR(
"GBuffer: Failed to create GBuffer pipeline!");
246 SLEAK_INFO(
"VulkanRenderer: GBuffer pipeline created");
251bool VulkanRenderer::CreateSkinnedGbufferPipeline() {
254 if (!sh->compile(
"assets/shaders/skinned_shader.vert.spv",
255 "assets/shaders/gbuffer.frag.spv")) {
256 SLEAK_ERROR(
"GBuffer: Failed to compile skinned gbuffer shaders!");
261 VkPipelineShaderStageCreateInfo stages[] = {
262 sh->GetVertexInfo(), sh->GetFragInfo()
265 std::vector<VkDynamicState> dynStates = {
266 VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR};
267 VkPipelineDynamicStateCreateInfo dynState{};
268 dynState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
269 dynState.dynamicStateCount =
static_cast<uint32_t
>(dynStates.size());
270 dynState.pDynamicStates = dynStates.data();
273 VkVertexInputBindingDescription bindDesc{};
274 bindDesc.binding = 0;
275 bindDesc.stride =
sizeof(
Vertex);
276 bindDesc.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
278 std::array<VkVertexInputAttributeDescription, 7> attrs{};
279 attrs[0] = {0, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(Vertex, px)};
280 attrs[1] = {1, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(Vertex, nx)};
281 attrs[2] = {2, 0, VK_FORMAT_R32G32B32A32_SFLOAT, offsetof(Vertex, tx)};
282 attrs[3] = {3, 0, VK_FORMAT_R32G32B32A32_SFLOAT, offsetof(Vertex, r)};
283 attrs[4] = {4, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(Vertex, u)};
284 attrs[5] = {5, 0, VK_FORMAT_R32G32B32A32_SINT, offsetof(Vertex, boneIDs)};
285 attrs[6] = {6, 0, VK_FORMAT_R32G32B32A32_SFLOAT, offsetof(Vertex, boneWeights)};
287 VkPipelineVertexInputStateCreateInfo vi{};
288 vi.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
289 vi.vertexBindingDescriptionCount = 1;
290 vi.pVertexBindingDescriptions = &bindDesc;
291 vi.vertexAttributeDescriptionCount =
static_cast<uint32_t
>(attrs.size());
292 vi.pVertexAttributeDescriptions = attrs.data();
294 VkPipelineInputAssemblyStateCreateInfo ia{};
295 ia.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
296 ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
298 VkPipelineViewportStateCreateInfo vps{};
299 vps.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
300 vps.viewportCount = 1;
301 vps.scissorCount = 1;
303 VkPipelineRasterizationStateCreateInfo rast{};
304 rast.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
305 rast.polygonMode = VK_POLYGON_MODE_FILL;
306 rast.lineWidth = 1.0f;
307 rast.cullMode = VK_CULL_MODE_BACK_BIT;
308 rast.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
310 VkPipelineMultisampleStateCreateInfo ms{};
311 ms.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
312 ms.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
314 VkPipelineDepthStencilStateCreateInfo ds{};
315 ds.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
316 ds.depthTestEnable = VK_TRUE;
317 ds.depthWriteEnable = VK_TRUE;
318 ds.depthCompareOp = VK_COMPARE_OP_LESS;
320 VkPipelineColorBlendAttachmentState opaqueBlend{};
321 opaqueBlend.blendEnable = VK_FALSE;
322 opaqueBlend.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
323 VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
325 std::array<VkPipelineColorBlendAttachmentState, GBUFFER_COUNT> blendAtts;
326 blendAtts.fill(opaqueBlend);
328 VkPipelineColorBlendStateCreateInfo cb{};
329 cb.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
330 cb.attachmentCount =
static_cast<uint32_t
>(blendAtts.size());
331 cb.pAttachments = blendAtts.data();
333 VkGraphicsPipelineCreateInfo pi{};
334 pi.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
337 pi.pVertexInputState = &vi;
338 pi.pInputAssemblyState = &ia;
339 pi.pViewportState = &vps;
340 pi.pRasterizationState = &rast;
341 pi.pMultisampleState = &ms;
342 pi.pDepthStencilState = &ds;
343 pi.pColorBlendState = &cb;
344 pi.pDynamicState = &dynState;
345 pi.layout = m_gbufferGeomLayout;
346 pi.renderPass = m_gbufferRenderPass;
348 pi.basePipelineHandle = VK_NULL_HANDLE;
349 pi.basePipelineIndex = -1;
351 VkResult res = vkCreateGraphicsPipelines(
352 device, VK_NULL_HANDLE, 1, &pi,
nullptr, &m_skinnedGbufferPipeline);
354 if (res != VK_SUCCESS) {
355 SLEAK_ERROR(
"GBuffer: Failed to create skinned GBuffer pipeline!");
359 SLEAK_INFO(
"VulkanRenderer: Skinned GBuffer pipeline created");
364bool VulkanRenderer::CreateLightingRenderPass() {
365 VkAttachmentDescription colorAtt{};
368 colorAtt.format = m_hdrSceneFormat;
369 colorAtt.samples = VK_SAMPLE_COUNT_1_BIT;
370 colorAtt.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
371 colorAtt.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
372 colorAtt.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
373 colorAtt.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
374 colorAtt.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
375 colorAtt.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
377 VkAttachmentReference colorRef{};
378 colorRef.attachment = 0;
379 colorRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
381 VkSubpassDescription subpass{};
382 subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
383 subpass.colorAttachmentCount = 1;
384 subpass.pColorAttachments = &colorRef;
386 std::array<VkSubpassDependency, 2> deps{};
387 deps[0].srcSubpass = VK_SUBPASS_EXTERNAL;
388 deps[0].dstSubpass = 0;
389 deps[0].srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
390 deps[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
391 deps[0].srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
392 deps[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
393 deps[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
395 deps[1].srcSubpass = 0;
396 deps[1].dstSubpass = VK_SUBPASS_EXTERNAL;
397 deps[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
398 deps[1].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
399 deps[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
400 deps[1].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
401 deps[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
403 VkRenderPassCreateInfo rpInfo{};
404 rpInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
405 rpInfo.attachmentCount = 1;
406 rpInfo.pAttachments = &colorAtt;
407 rpInfo.subpassCount = 1;
408 rpInfo.pSubpasses = &subpass;
409 rpInfo.dependencyCount =
static_cast<uint32_t
>(deps.size());
410 rpInfo.pDependencies = deps.data();
412 return vkCreateRenderPass(device, &rpInfo,
nullptr, &m_lightingRenderPass) == VK_SUCCESS;
416bool VulkanRenderer::CreateLightingFramebuffers() {
417 if (m_hdrSceneView == VK_NULL_HANDLE) {
418 SLEAK_ERROR(
"GBuffer: HDR scene image view is null when creating lighting framebuffers!");
422 VkFramebufferCreateInfo fbInfo{};
423 fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
424 fbInfo.renderPass = m_lightingRenderPass;
425 fbInfo.attachmentCount = 1;
426 fbInfo.pAttachments = &m_hdrSceneView;
427 fbInfo.width = scExtent.width;
428 fbInfo.height = scExtent.height;
431 m_lightingFramebuffers.resize(swapChainImageViews.size());
432 for (
size_t i = 0; i < swapChainImageViews.size(); ++i) {
433 if (vkCreateFramebuffer(device, &fbInfo,
nullptr, &m_lightingFramebuffers[i]) != VK_SUCCESS) {
434 SLEAK_ERROR(
"GBuffer: Failed to create lighting framebuffer {}!", i);
442bool VulkanRenderer::CreateLightingPipeline() {
444 if (!m_lightingShader->compile(
"assets/shaders/lighting_pass.vert.spv",
445 "assets/shaders/lighting_pass.frag.spv")) {
446 SLEAK_ERROR(
"GBuffer: Failed to compile lighting pass shaders!");
447 delete m_lightingShader;
448 m_lightingShader =
nullptr;
452 VkPipelineShaderStageCreateInfo shaderStages[] = {
453 m_lightingShader->GetVertexInfo(),
454 m_lightingShader->GetFragInfo()
458 VkPipelineVertexInputStateCreateInfo vertexInputInfo{};
459 vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
461 VkPipelineInputAssemblyStateCreateInfo inputAssembly{};
462 inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
463 inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
464 inputAssembly.primitiveRestartEnable = VK_FALSE;
466 std::vector<VkDynamicState> dynamicStates = {
467 VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR};
468 VkPipelineDynamicStateCreateInfo dynamicState{};
469 dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
470 dynamicState.dynamicStateCount =
static_cast<uint32_t
>(dynamicStates.size());
471 dynamicState.pDynamicStates = dynamicStates.data();
473 VkPipelineViewportStateCreateInfo viewportState{};
474 viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
475 viewportState.viewportCount = 1;
476 viewportState.scissorCount = 1;
478 VkPipelineRasterizationStateCreateInfo rasterizer{};
479 rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
480 rasterizer.depthClampEnable = VK_FALSE;
481 rasterizer.rasterizerDiscardEnable = VK_FALSE;
482 rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
483 rasterizer.lineWidth = 1.0f;
484 rasterizer.cullMode = VK_CULL_MODE_NONE;
485 rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
486 rasterizer.depthBiasEnable = VK_FALSE;
488 VkPipelineMultisampleStateCreateInfo msaa{};
489 msaa.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
490 msaa.sampleShadingEnable = VK_FALSE;
491 msaa.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
494 VkPipelineDepthStencilStateCreateInfo depthStencil{};
495 depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
496 depthStencil.depthTestEnable = VK_FALSE;
497 depthStencil.depthWriteEnable = VK_FALSE;
498 depthStencil.stencilTestEnable = VK_FALSE;
500 VkPipelineColorBlendAttachmentState colorBlendAtt{};
501 colorBlendAtt.blendEnable = VK_FALSE;
502 colorBlendAtt.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
503 VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
505 VkPipelineColorBlendStateCreateInfo colorBlendInfo{};
506 colorBlendInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
507 colorBlendInfo.logicOpEnable = VK_FALSE;
508 colorBlendInfo.attachmentCount = 1;
509 colorBlendInfo.pAttachments = &colorBlendAtt;
516 std::array<VkDescriptorSetLayout, 4> setLayouts = {
519 m_lightUBODescriptorSetLayout,
523 VkPipelineLayoutCreateInfo layoutInfo{};
524 layoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
525 layoutInfo.setLayoutCount =
static_cast<uint32_t
>(setLayouts.size());
526 layoutInfo.pSetLayouts = setLayouts.data();
528 if (vkCreatePipelineLayout(device, &layoutInfo,
nullptr, &m_lightingPipelineLayout) != VK_SUCCESS) {
529 SLEAK_ERROR(
"GBuffer: Failed to create lighting pipeline layout!");
533 VkGraphicsPipelineCreateInfo pipelineInfo{};
534 pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
535 pipelineInfo.stageCount = 2;
536 pipelineInfo.pStages = shaderStages;
537 pipelineInfo.pVertexInputState = &vertexInputInfo;
538 pipelineInfo.pInputAssemblyState = &inputAssembly;
539 pipelineInfo.pViewportState = &viewportState;
540 pipelineInfo.pRasterizationState = &rasterizer;
541 pipelineInfo.pMultisampleState = &msaa;
542 pipelineInfo.pDepthStencilState = &depthStencil;
543 pipelineInfo.pColorBlendState = &colorBlendInfo;
544 pipelineInfo.pDynamicState = &dynamicState;
545 pipelineInfo.layout = m_lightingPipelineLayout;
546 pipelineInfo.renderPass = m_lightingRenderPass;
547 pipelineInfo.subpass = 0;
548 pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
549 pipelineInfo.basePipelineIndex = -1;
551 VkResult result = vkCreateGraphicsPipelines(
552 device, VK_NULL_HANDLE, 1, &pipelineInfo,
nullptr, &m_lightingPipeline);
553 if (result != VK_SUCCESS) {
554 SLEAK_ERROR(
"GBuffer: Failed to create lighting pipeline!");
558 SLEAK_INFO(
"VulkanRenderer: Lighting pass pipeline created");
563bool VulkanRenderer::CreateForwardRenderPass() {
564 VkAttachmentDescription colorAtt{};
565 colorAtt.format = m_hdrSceneFormat;
566 colorAtt.samples = VK_SAMPLE_COUNT_1_BIT;
567 colorAtt.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
568 colorAtt.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
569 colorAtt.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
570 colorAtt.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
571 colorAtt.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
572 colorAtt.finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
574 VkAttachmentDescription depthAtt{};
575 depthAtt.format = depthFormat;
576 depthAtt.samples = VK_SAMPLE_COUNT_1_BIT;
577 depthAtt.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
578 depthAtt.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
579 depthAtt.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
580 depthAtt.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
581 depthAtt.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
582 depthAtt.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
584 VkAttachmentReference colorRef{};
585 colorRef.attachment = 0;
586 colorRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
588 VkAttachmentReference depthRef{};
589 depthRef.attachment = 1;
590 depthRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
592 VkSubpassDescription subpass{};
593 subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
594 subpass.colorAttachmentCount = 1;
595 subpass.pColorAttachments = &colorRef;
596 subpass.pDepthStencilAttachment = &depthRef;
598 VkSubpassDependency dep{};
599 dep.srcSubpass = VK_SUBPASS_EXTERNAL;
601 dep.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
602 dep.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
603 VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
604 dep.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
605 dep.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
606 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
608 std::array<VkAttachmentDescription, 2> attachments = {colorAtt, depthAtt};
610 VkRenderPassCreateInfo rpInfo{};
611 rpInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
612 rpInfo.attachmentCount =
static_cast<uint32_t
>(attachments.size());
613 rpInfo.pAttachments = attachments.data();
614 rpInfo.subpassCount = 1;
615 rpInfo.pSubpasses = &subpass;
616 rpInfo.dependencyCount = 1;
617 rpInfo.pDependencies = &dep;
619 return vkCreateRenderPass(device, &rpInfo,
nullptr, &m_forwardRenderPass) == VK_SUCCESS;
623bool VulkanRenderer::CreateForwardFramebuffers() {
624 if (m_hdrSceneView == VK_NULL_HANDLE) {
625 SLEAK_ERROR(
"GBuffer: HDR scene image view is null when creating forward framebuffers!");
629 m_forwardFramebuffers.resize(swapChainImageViews.size());
631 for (
size_t i = 0; i < swapChainImageViews.size(); ++i) {
632 std::array<VkImageView, 2> views = {m_hdrSceneView, depthImageView};
634 VkFramebufferCreateInfo fbInfo{};
635 fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
636 fbInfo.renderPass = m_forwardRenderPass;
637 fbInfo.attachmentCount =
static_cast<uint32_t
>(views.size());
638 fbInfo.pAttachments = views.data();
639 fbInfo.width = scExtent.width;
640 fbInfo.height = scExtent.height;
643 if (vkCreateFramebuffer(device, &fbInfo,
nullptr, &m_forwardFramebuffers[i]) != VK_SUCCESS) {
644 SLEAK_ERROR(
"GBuffer: Failed to create forward framebuffer {}!", i);
652bool VulkanRenderer::CreateGBufferDescriptorSets() {
654 VkSamplerCreateInfo samplerInfo{};
655 samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
656 samplerInfo.magFilter = VK_FILTER_NEAREST;
657 samplerInfo.minFilter = VK_FILTER_NEAREST;
658 samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
659 samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
660 samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
661 samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
662 samplerInfo.minLod = 0.0f;
663 samplerInfo.maxLod = 1.0f;
665 if (vkCreateSampler(device, &samplerInfo,
nullptr, &m_gbufferSampler) != VK_SUCCESS) {
666 SLEAK_ERROR(
"GBuffer: Failed to create gbuffer sampler!");
671 VkSamplerCreateInfo depthSamplerInfo{};
672 depthSamplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
673 depthSamplerInfo.magFilter = VK_FILTER_NEAREST;
674 depthSamplerInfo.minFilter = VK_FILTER_NEAREST;
675 depthSamplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
676 depthSamplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
677 depthSamplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
678 depthSamplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
679 depthSamplerInfo.minLod = 0.0f;
680 depthSamplerInfo.maxLod = 1.0f;
682 if (vkCreateSampler(device, &depthSamplerInfo,
nullptr, &m_depthSampler) != VK_SUCCESS) {
683 SLEAK_ERROR(
"GBuffer: Failed to create depth sampler!");
693 std::array<VkDescriptorSetLayoutBinding, 7> bindings{};
694 for (uint32_t b = 0; b < 7; ++b) {
695 bindings[b].binding = b;
696 bindings[b].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
697 bindings[b].descriptorCount = 1;
698 bindings[b].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
701 VkDescriptorSetLayoutCreateInfo dslInfo{};
702 dslInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
703 dslInfo.bindingCount =
static_cast<uint32_t
>(bindings.size());
704 dslInfo.pBindings = bindings.data();
706 if (vkCreateDescriptorSetLayout(device, &dslInfo,
nullptr, &m_gbufferSamplerDSL) != VK_SUCCESS) {
707 SLEAK_ERROR(
"GBuffer: Failed to create gbuffer sampler DSL!");
712 VkDescriptorPoolSize poolSize{};
713 poolSize.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
714 poolSize.descriptorCount = 7 * MAX_FRAMES_IN_FLIGHT;
716 VkDescriptorPoolCreateInfo poolInfo{};
717 poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
718 poolInfo.poolSizeCount = 1;
719 poolInfo.pPoolSizes = &poolSize;
720 poolInfo.maxSets = MAX_FRAMES_IN_FLIGHT;
722 if (vkCreateDescriptorPool(device, &poolInfo,
nullptr, &m_gbufferSamplerPool) != VK_SUCCESS) {
723 SLEAK_ERROR(
"GBuffer: Failed to create gbuffer sampler pool!");
727 std::array<VkDescriptorSetLayout, MAX_FRAMES_IN_FLIGHT> layouts;
728 layouts.fill(m_gbufferSamplerDSL);
730 VkDescriptorSetAllocateInfo allocInfo{};
731 allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
732 allocInfo.descriptorPool = m_gbufferSamplerPool;
733 allocInfo.descriptorSetCount = MAX_FRAMES_IN_FLIGHT;
734 allocInfo.pSetLayouts = layouts.data();
736 if (vkAllocateDescriptorSets(device, &allocInfo, m_gbufferSamplerSets.data()) != VK_SUCCESS) {
737 SLEAK_ERROR(
"GBuffer: Failed to allocate gbuffer sampler descriptor sets!");
743 for (uint32_t f = 0; f < MAX_FRAMES_IN_FLIGHT; ++f) {
744 uint32_t saved = currentFrame;
746 UpdateGBufferDescriptors();
747 currentFrame = saved;
754void VulkanRenderer::UpdateGBufferDescriptors() {
759 uint32_t f = currentFrame;
760 std::array<VkDescriptorImageInfo, 7> imageInfos{};
763 for (uint32_t i = 0; i < GBUFFER_COUNT; ++i) {
764 imageInfos[i].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
765 imageInfos[i].imageView = m_gbufferViews[i];
766 imageInfos[i].sampler = m_gbufferSampler;
770 imageInfos[3].imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
771 imageInfos[3].imageView = depthImageView;
772 imageInfos[3].sampler = m_depthSampler;
778 if (m_shadowImageView) {
779 imageInfos[4].imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
780 imageInfos[4].imageView = m_shadowImageView;
781 imageInfos[4].sampler = m_shadowSampler ? m_shadowSampler
782 : (m_defaultTexture ? m_defaultTexture->GetSampler() : VK_NULL_HANDLE);
783 }
else if (m_defaultTexture) {
784 imageInfos[4].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
785 imageInfos[4].imageView = m_defaultTexture->GetImageView();
786 imageInfos[4].sampler = m_defaultTexture->GetSampler();
790 if (m_shadowImageView) {
791 imageInfos[5].imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
792 imageInfos[5].imageView = m_shadowImageView;
793 imageInfos[5].sampler = m_shadowRawSampler ? m_shadowRawSampler
794 : (m_defaultTexture ? m_defaultTexture->GetSampler() : VK_NULL_HANDLE);
795 }
else if (m_defaultTexture) {
796 imageInfos[5].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
797 imageInfos[5].imageView = m_defaultTexture->GetImageView();
798 imageInfos[5].sampler = m_defaultTexture->GetSampler();
803 if (m_ssaoBlurView != VK_NULL_HANDLE && m_ssaoSampler != VK_NULL_HANDLE) {
804 imageInfos[6].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
805 imageInfos[6].imageView = m_ssaoBlurView;
806 imageInfos[6].sampler = m_ssaoSampler;
807 }
else if (m_defaultTexture) {
808 imageInfos[6].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
809 imageInfos[6].imageView = m_defaultTexture->GetImageView();
810 imageInfos[6].sampler = m_defaultTexture->GetSampler();
813 std::array<VkWriteDescriptorSet, 7> writes{};
814 for (uint32_t b = 0; b < 7; ++b) {
815 writes[b].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
816 writes[b].dstSet = m_gbufferSamplerSets[f];
817 writes[b].dstBinding = b;
818 writes[b].dstArrayElement = 0;
819 writes[b].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
820 writes[b].descriptorCount = 1;
821 writes[b].pImageInfo = &imageInfos[b];
823 vkUpdateDescriptorSets(device,
static_cast<uint32_t
>(writes.size()),
824 writes.data(), 0,
nullptr);
828bool VulkanRenderer::CreateDeferredCBResources() {
829 if (m_deferredCBCreated)
return true;
831 static constexpr VkDeviceSize uboSize =
sizeof(DeferredCBData);
834 for (uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) {
835 VkBufferCreateInfo bufInfo{};
836 bufInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
837 bufInfo.size = uboSize;
838 bufInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
839 bufInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
841 if (vkCreateBuffer(device, &bufInfo,
nullptr, &m_deferredCBBuffers[i]) != VK_SUCCESS) {
842 SLEAK_ERROR(
"GBuffer: Failed to create deferred CB buffer!");
846 VkMemoryRequirements memReqs;
847 vkGetBufferMemoryRequirements(device, m_deferredCBBuffers[i], &memReqs);
849 VkMemoryAllocateInfo allocInfo{};
850 allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
851 allocInfo.allocationSize = memReqs.size;
852 allocInfo.memoryTypeIndex = FindMemoryType(memReqs.memoryTypeBits,
853 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
855 if (vkAllocateMemory(device, &allocInfo,
nullptr, &m_deferredCBMemory[i]) != VK_SUCCESS) {
856 SLEAK_ERROR(
"GBuffer: Failed to allocate deferred CB memory!");
860 vkBindBufferMemory(device, m_deferredCBBuffers[i], m_deferredCBMemory[i], 0);
861 vkMapMemory(device, m_deferredCBMemory[i], 0, uboSize, 0, &m_deferredCBMapped[i]);
862 memset(m_deferredCBMapped[i], 0, uboSize);
866 VkDescriptorSetLayoutBinding uboBinding{};
867 uboBinding.binding = 0;
868 uboBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
869 uboBinding.descriptorCount = 1;
870 uboBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
872 VkDescriptorSetLayoutCreateInfo dslInfo{};
873 dslInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
874 dslInfo.bindingCount = 1;
875 dslInfo.pBindings = &uboBinding;
877 if (vkCreateDescriptorSetLayout(device, &dslInfo,
nullptr, &m_deferredCBDSL) != VK_SUCCESS) {
878 SLEAK_ERROR(
"GBuffer: Failed to create deferred CB DSL!");
882 VkDescriptorPoolSize poolSize{};
883 poolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
884 poolSize.descriptorCount = MAX_FRAMES_IN_FLIGHT;
886 VkDescriptorPoolCreateInfo poolInfo{};
887 poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
888 poolInfo.poolSizeCount = 1;
889 poolInfo.pPoolSizes = &poolSize;
890 poolInfo.maxSets = MAX_FRAMES_IN_FLIGHT;
892 if (vkCreateDescriptorPool(device, &poolInfo,
nullptr, &m_deferredCBPool) != VK_SUCCESS) {
893 SLEAK_ERROR(
"GBuffer: Failed to create deferred CB pool!");
897 std::array<VkDescriptorSetLayout, MAX_FRAMES_IN_FLIGHT> layouts;
898 layouts.fill(m_deferredCBDSL);
900 VkDescriptorSetAllocateInfo dsAllocInfo{};
901 dsAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
902 dsAllocInfo.descriptorPool = m_deferredCBPool;
903 dsAllocInfo.descriptorSetCount = MAX_FRAMES_IN_FLIGHT;
904 dsAllocInfo.pSetLayouts = layouts.data();
906 if (vkAllocateDescriptorSets(device, &dsAllocInfo, m_deferredCBSets.data()) != VK_SUCCESS) {
907 SLEAK_ERROR(
"GBuffer: Failed to allocate deferred CB descriptor sets!");
911 for (uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) {
912 VkDescriptorBufferInfo bufInfo{};
913 bufInfo.buffer = m_deferredCBBuffers[i];
915 bufInfo.range = uboSize;
917 VkWriteDescriptorSet write{};
918 write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
919 write.dstSet = m_deferredCBSets[i];
920 write.dstBinding = 0;
921 write.dstArrayElement = 0;
922 write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
923 write.descriptorCount = 1;
924 write.pBufferInfo = &bufInfo;
926 vkUpdateDescriptorSets(device, 1, &write, 0,
nullptr);
929 m_deferredCBCreated =
true;
934void VulkanRenderer::CleanupGBufferResources() {
935 if (!m_gbufferResourcesCreated)
return;
941 SLEAK_WARN(
"CleanupGBufferResources called while frame recording is active — forcing device idle");
942 vkDeviceWaitIdle(device);
943 bFrameStarted =
false;
947 if (m_gbufferPipeline) {
948 vkDestroyPipeline(device, m_gbufferPipeline,
nullptr);
949 m_gbufferPipeline = VK_NULL_HANDLE;
953 DestroyCustomFormatPipelines();
954 if (m_skinnedGbufferPipeline) {
955 vkDestroyPipeline(device, m_skinnedGbufferPipeline,
nullptr);
956 m_skinnedGbufferPipeline = VK_NULL_HANDLE;
959 m_gbufferPipelineLayout = VK_NULL_HANDLE;
960 delete m_gbufferShader;
961 m_gbufferShader =
nullptr;
964 if (m_lightingPipeline) {
965 vkDestroyPipeline(device, m_lightingPipeline,
nullptr);
966 m_lightingPipeline = VK_NULL_HANDLE;
968 if (m_lightingPipelineLayout) {
969 vkDestroyPipelineLayout(device, m_lightingPipelineLayout,
nullptr);
970 m_lightingPipelineLayout = VK_NULL_HANDLE;
972 delete m_lightingShader;
973 m_lightingShader =
nullptr;
976 for (
auto& fb : m_lightingFramebuffers) {
977 if (fb) vkDestroyFramebuffer(device, fb,
nullptr);
979 m_lightingFramebuffers.clear();
982 if (m_lightingRenderPass) {
983 vkDestroyRenderPass(device, m_lightingRenderPass,
nullptr);
984 m_lightingRenderPass = VK_NULL_HANDLE;
988 if (m_gbufferFramebuffer) {
989 vkDestroyFramebuffer(device, m_gbufferFramebuffer,
nullptr);
990 m_gbufferFramebuffer = VK_NULL_HANDLE;
994 if (m_gbufferRenderPass) {
995 vkDestroyRenderPass(device, m_gbufferRenderPass,
nullptr);
996 m_gbufferRenderPass = VK_NULL_HANDLE;
1000 for (
auto& fb : m_forwardFramebuffers) {
1001 if (fb) vkDestroyFramebuffer(device, fb,
nullptr);
1003 m_forwardFramebuffers.clear();
1006 if (m_forwardRenderPass) {
1007 vkDestroyRenderPass(device, m_forwardRenderPass,
nullptr);
1008 m_forwardRenderPass = VK_NULL_HANDLE;
1012 if (m_gbufferSamplerPool) {
1013 vkDestroyDescriptorPool(device, m_gbufferSamplerPool,
nullptr);
1014 m_gbufferSamplerPool = VK_NULL_HANDLE;
1016 if (m_gbufferSamplerDSL) {
1017 vkDestroyDescriptorSetLayout(device, m_gbufferSamplerDSL,
nullptr);
1018 m_gbufferSamplerDSL = VK_NULL_HANDLE;
1020 if (m_gbufferSampler) {
1021 vkDestroySampler(device, m_gbufferSampler,
nullptr);
1022 m_gbufferSampler = VK_NULL_HANDLE;
1024 if (m_depthSampler) {
1025 vkDestroySampler(device, m_depthSampler,
nullptr);
1026 m_depthSampler = VK_NULL_HANDLE;
1030 if (m_deferredCBCreated) {
1031 for (uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) {
1032 if (m_deferredCBMapped[i]) {
1033 vkUnmapMemory(device, m_deferredCBMemory[i]);
1034 m_deferredCBMapped[i] =
nullptr;
1036 if (m_deferredCBBuffers[i]) {
1037 vkDestroyBuffer(device, m_deferredCBBuffers[i],
nullptr);
1038 m_deferredCBBuffers[i] = VK_NULL_HANDLE;
1040 if (m_deferredCBMemory[i]) {
1041 vkFreeMemory(device, m_deferredCBMemory[i],
nullptr);
1042 m_deferredCBMemory[i] = VK_NULL_HANDLE;
1045 m_deferredCBCreated =
false;
1047 if (m_deferredCBPool) {
1048 vkDestroyDescriptorPool(device, m_deferredCBPool,
nullptr);
1049 m_deferredCBPool = VK_NULL_HANDLE;
1051 if (m_deferredCBDSL) {
1052 vkDestroyDescriptorSetLayout(device, m_deferredCBDSL,
nullptr);
1053 m_deferredCBDSL = VK_NULL_HANDLE;
1057 for (uint32_t i = 0; i < GBUFFER_COUNT; ++i) {
1058 if (m_gbufferViews[i]) {
1059 vkDestroyImageView(device, m_gbufferViews[i],
nullptr);
1060 m_gbufferViews[i] = VK_NULL_HANDLE;
1062 if (m_gbufferImages[i]) {
1063 vkDestroyImage(device, m_gbufferImages[i],
nullptr);
1064 m_gbufferImages[i] = VK_NULL_HANDLE;
1066 if (m_gbufferMemory[i]) {
1067 vkFreeMemory(device, m_gbufferMemory[i],
nullptr);
1068 m_gbufferMemory[i] = VK_NULL_HANDLE;
1073 DestroyPBRMaterialChunks();
1074 m_pbrMaterialResourcesCreated =
false;
1075 if (m_pbrMaterialDSL) {
1076 vkDestroyDescriptorSetLayout(device, m_pbrMaterialDSL,
nullptr);
1077 m_pbrMaterialDSL = VK_NULL_HANDLE;
1079 if (m_gbufferGeomLayout) {
1080 vkDestroyPipelineLayout(device, m_gbufferGeomLayout,
nullptr);
1081 m_gbufferGeomLayout = VK_NULL_HANDLE;
1085 CleanupIBLResources();
1088 CleanupSSAOResources();
1089 CleanupSSRResources();
1090 CleanupBloomResources();
1092 m_gbufferResourcesCreated =
false;
1093 m_inGeometryPass =
false;
1094 m_inForwardTransparentPass =
false;
1100 if (!bFrameStarted || !m_gbufferResourcesCreated)
return;
1101 vkCmdBindPipeline(command, VK_PIPELINE_BIND_POINT_GRAPHICS, m_gbufferPipeline);
1106 m_activeCustomFormat = 0;
1111 if (!bFrameStarted || !m_gbufferResourcesCreated)
return;
1115 vkCmdEndRenderPass(command);
1116 m_inGeometryPass =
false;
1117 m_activeCustomFormat = 0;
1124 UpdateGBufferDescriptors();
1127 VkClearValue clearVal{};
1128 clearVal.color = {0.0f, 0.0f, 0.0f, 1.0f};
1130 VkRenderPassBeginInfo rpBegin{};
1131 rpBegin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
1132 rpBegin.renderPass = m_lightingRenderPass;
1133 rpBegin.framebuffer = m_lightingFramebuffers[CurrentFrameIndex];
1134 rpBegin.renderArea.offset = {0, 0};
1135 rpBegin.renderArea.extent = scExtent;
1136 rpBegin.clearValueCount = 1;
1137 rpBegin.pClearValues = &clearVal;
1139 vkCmdBeginRenderPass(command, &rpBegin, VK_SUBPASS_CONTENTS_INLINE);
1142 VkViewport viewport{};
1145 viewport.width =
static_cast<float>(scExtent.width);
1146 viewport.height =
static_cast<float>(scExtent.height);
1147 viewport.minDepth = 0.0f;
1148 viewport.maxDepth = 1.0f;
1149 vkCmdSetViewport(command, 0, 1, &viewport);
1152 scissor.offset = {0, 0};
1153 scissor.extent = scExtent;
1154 vkCmdSetScissor(command, 0, 1, &scissor);
1157 vkCmdBindPipeline(command, VK_PIPELINE_BIND_POINT_GRAPHICS, m_lightingPipeline);
1164 VkDescriptorSet lightingSets[4] = {
1165 m_gbufferSamplerSets[currentFrame],
1166 m_deferredCBSets[currentFrame],
1167 m_lightUBODescriptorSets[currentFrame],
1168 m_iblSets[currentFrame]
1170 vkCmdBindDescriptorSets(command, VK_PIPELINE_BIND_POINT_GRAPHICS,
1171 m_lightingPipelineLayout, 0, 4,
1172 lightingSets, 0,
nullptr);
1175 vkCmdDraw(command, 3, 1, 0, 0);
1178 vkCmdEndRenderPass(command);
1181 VkImageMemoryBarrier depthBarrier{};
1182 depthBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
1183 depthBarrier.oldLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
1184 depthBarrier.newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
1185 depthBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
1186 depthBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
1187 depthBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
1188 depthBarrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
1189 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
1190 depthBarrier.image = depthImage;
1191 depthBarrier.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1};
1193 vkCmdPipelineBarrier(command,
1194 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
1195 VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
1196 0, 0,
nullptr, 0,
nullptr, 1, &depthBarrier);
1201 if (!bFrameStarted || !m_gbufferResourcesCreated)
return;
1203 VkRenderPassBeginInfo rpBegin{};
1204 rpBegin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
1205 rpBegin.renderPass = m_forwardRenderPass;
1206 rpBegin.framebuffer = m_forwardFramebuffers[CurrentFrameIndex];
1207 rpBegin.renderArea.offset = {0, 0};
1208 rpBegin.renderArea.extent = scExtent;
1209 rpBegin.clearValueCount = 0;
1211 vkCmdBeginRenderPass(command, &rpBegin, VK_SUBPASS_CONTENTS_INLINE);
1213 VkViewport viewport{};
1216 viewport.width =
static_cast<float>(scExtent.width);
1217 viewport.height =
static_cast<float>(scExtent.height);
1218 viewport.minDepth = 0.0f;
1219 viewport.maxDepth = 1.0f;
1220 vkCmdSetViewport(command, 0, 1, &viewport);
1223 scissor.offset = {0, 0};
1224 scissor.extent = scExtent;
1225 vkCmdSetScissor(command, 0, 1, &scissor);
1229 vkCmdBindPipeline(command, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
1232 if (m_textureDescriptorsWritten && CurrentFrameIndex < descriptorSets.size()) {
1233 vkCmdBindDescriptorSets(command, VK_PIPELINE_BIND_POINT_GRAPHICS,
1235 &descriptorSets[CurrentFrameIndex], 0,
nullptr);
1237 if (m_boneUBOCreated) {
1238 vkCmdBindDescriptorSets(command, VK_PIPELINE_BIND_POINT_GRAPHICS,
1240 &boneDescriptorSets[currentFrame], 0,
nullptr);
1242 if (m_lightUBOCreated) {
1243 vkCmdBindDescriptorSets(command, VK_PIPELINE_BIND_POINT_GRAPHICS,
1245 &m_lightUBODescriptorSets[currentFrame], 0,
nullptr);
1246 vkCmdBindDescriptorSets(command, VK_PIPELINE_BIND_POINT_GRAPHICS,
1248 &m_shadowSamplerDescriptorSets[currentFrame], 0,
nullptr);
1251 m_inForwardTransparentPass =
true;
1252 m_forwardPassOpen =
true;
1253 m_activeCustomFormat = 0;
1258 m_inForwardTransparentPass =
false;
1264 if (!m_deferredCBCreated || !data)
return;
1265 uint32_t copySize = std::min(size,
static_cast<uint32_t
>(
sizeof(DeferredCBData)));
1266 memcpy(m_deferredCBMapped[currentFrame], data, copySize);
1271 memcpy(m_cachedView, &V(0, 0),
sizeof(m_cachedView));
1272 memcpy(m_cachedProjection, &P(0, 0),
sizeof(m_cachedProjection));
1276 if (copySize >=
sizeof(m_cachedInvViewProj))
1277 memcpy(m_cachedInvViewProj, data,
sizeof(m_cachedInvViewProj));
1283 if (m_taaResourcesCreated &&
m_taaEnabled && scExtent.width > 0) {
1284 const uint32_t haltonIdx =
static_cast<uint32_t
>((m_taaFrameIdx % 8) + 1);
1285 m_taaJitter[0] = (
HaltonSeq(haltonIdx, 2) - 0.5f) /
static_cast<float>(scExtent.width);
1286 m_taaJitter[1] = (
HaltonSeq(haltonIdx, 3) - 0.5f) /
static_cast<float>(scExtent.height);
1288 m_taaJitter[0] = m_taaJitter[1] = 0.0f;
static const Math::Matrix4 & GetMainProjectionMatrix()
static const Math::Matrix4 & GetMainViewMatrix()
virtual void ExecuteDeferredLightingPass() override
Runs the deferred lighting pass, reading the GBuffer and writing the HDR scene image.
virtual void EndForwardTransparentPass() override
Marks the forward transparent pass ended; EndRender closes the actual render pass.
virtual void UpdateDeferredCB(const void *data, uint32_t size) override
Copies deferred CB data into the current frame's UBO and snapshots the camera matrices.
virtual void BeginForwardTransparentPass() override
Begins the forward transparent render pass over the HDR scene image.
virtual void BindGBufferShader() override
VulkanShader(VkDevice dev)
Matrix< float, 4, 4 > Matrix4
Backend-facing rendering layer shared by the four graphics backends.
float HaltonSeq(int index, int base)
Halton low-discrepancy sequence value for TAA sub-pixel jitter.
Root namespace for everything the engine exposes.