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() {
126 m_gbufferShader =
new VulkanShader(device);
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() {
253 VulkanShader* sh =
new VulkanShader(device);
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() {
443 m_lightingShader =
new VulkanShader(device);
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 if (m_pbrMaterialResourcesCreated) {
1074 for (uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) {
1075 if (m_pbrMaterialCBMapped[i]) {
1076 vkUnmapMemory(device, m_pbrMaterialCBMemory[i]);
1077 m_pbrMaterialCBMapped[i] =
nullptr;
1079 if (m_pbrMaterialCBBuffers[i]) {
1080 vkDestroyBuffer(device, m_pbrMaterialCBBuffers[i],
nullptr);
1081 m_pbrMaterialCBBuffers[i] = VK_NULL_HANDLE;
1083 if (m_pbrMaterialCBMemory[i]) {
1084 vkFreeMemory(device, m_pbrMaterialCBMemory[i],
nullptr);
1085 m_pbrMaterialCBMemory[i] = VK_NULL_HANDLE;
1088 m_pbrMaterialResourcesCreated =
false;
1090 if (m_pbrMaterialPool) {
1091 vkDestroyDescriptorPool(device, m_pbrMaterialPool,
nullptr);
1092 m_pbrMaterialPool = VK_NULL_HANDLE;
1094 if (m_pbrMaterialDSL) {
1095 vkDestroyDescriptorSetLayout(device, m_pbrMaterialDSL,
nullptr);
1096 m_pbrMaterialDSL = VK_NULL_HANDLE;
1098 if (m_gbufferGeomLayout) {
1099 vkDestroyPipelineLayout(device, m_gbufferGeomLayout,
nullptr);
1100 m_gbufferGeomLayout = VK_NULL_HANDLE;
1104 CleanupIBLResources();
1107 CleanupSSAOResources();
1108 CleanupSSRResources();
1109 CleanupBloomResources();
1111 m_gbufferResourcesCreated =
false;
1112 m_inGeometryPass =
false;
1113 m_inForwardTransparentPass =
false;
1119 if (!bFrameStarted || !m_gbufferResourcesCreated)
return;
1120 vkCmdBindPipeline(command, VK_PIPELINE_BIND_POINT_GRAPHICS, m_gbufferPipeline);
1125 m_activeCustomFormat = 0;
1130 if (!bFrameStarted || !m_gbufferResourcesCreated)
return;
1134 vkCmdEndRenderPass(command);
1135 m_inGeometryPass =
false;
1136 m_activeCustomFormat = 0;
1143 UpdateGBufferDescriptors();
1146 VkClearValue clearVal{};
1147 clearVal.color = {0.0f, 0.0f, 0.0f, 1.0f};
1149 VkRenderPassBeginInfo rpBegin{};
1150 rpBegin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
1151 rpBegin.renderPass = m_lightingRenderPass;
1152 rpBegin.framebuffer = m_lightingFramebuffers[CurrentFrameIndex];
1153 rpBegin.renderArea.offset = {0, 0};
1154 rpBegin.renderArea.extent = scExtent;
1155 rpBegin.clearValueCount = 1;
1156 rpBegin.pClearValues = &clearVal;
1158 vkCmdBeginRenderPass(command, &rpBegin, VK_SUBPASS_CONTENTS_INLINE);
1161 VkViewport viewport{};
1164 viewport.width =
static_cast<float>(scExtent.width);
1165 viewport.height =
static_cast<float>(scExtent.height);
1166 viewport.minDepth = 0.0f;
1167 viewport.maxDepth = 1.0f;
1168 vkCmdSetViewport(command, 0, 1, &viewport);
1171 scissor.offset = {0, 0};
1172 scissor.extent = scExtent;
1173 vkCmdSetScissor(command, 0, 1, &scissor);
1176 vkCmdBindPipeline(command, VK_PIPELINE_BIND_POINT_GRAPHICS, m_lightingPipeline);
1183 VkDescriptorSet lightingSets[4] = {
1184 m_gbufferSamplerSets[currentFrame],
1185 m_deferredCBSets[currentFrame],
1186 m_lightUBODescriptorSets[currentFrame],
1187 m_iblSets[currentFrame]
1189 vkCmdBindDescriptorSets(command, VK_PIPELINE_BIND_POINT_GRAPHICS,
1190 m_lightingPipelineLayout, 0, 4,
1191 lightingSets, 0,
nullptr);
1194 vkCmdDraw(command, 3, 1, 0, 0);
1197 vkCmdEndRenderPass(command);
1200 VkImageMemoryBarrier depthBarrier{};
1201 depthBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
1202 depthBarrier.oldLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
1203 depthBarrier.newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
1204 depthBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
1205 depthBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
1206 depthBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
1207 depthBarrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
1208 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
1209 depthBarrier.image = depthImage;
1210 depthBarrier.subresourceRange = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1};
1212 vkCmdPipelineBarrier(command,
1213 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
1214 VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
1215 0, 0,
nullptr, 0,
nullptr, 1, &depthBarrier);
1220 if (!bFrameStarted || !m_gbufferResourcesCreated)
return;
1222 VkRenderPassBeginInfo rpBegin{};
1223 rpBegin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
1224 rpBegin.renderPass = m_forwardRenderPass;
1225 rpBegin.framebuffer = m_forwardFramebuffers[CurrentFrameIndex];
1226 rpBegin.renderArea.offset = {0, 0};
1227 rpBegin.renderArea.extent = scExtent;
1228 rpBegin.clearValueCount = 0;
1230 vkCmdBeginRenderPass(command, &rpBegin, VK_SUBPASS_CONTENTS_INLINE);
1232 VkViewport viewport{};
1235 viewport.width =
static_cast<float>(scExtent.width);
1236 viewport.height =
static_cast<float>(scExtent.height);
1237 viewport.minDepth = 0.0f;
1238 viewport.maxDepth = 1.0f;
1239 vkCmdSetViewport(command, 0, 1, &viewport);
1242 scissor.offset = {0, 0};
1243 scissor.extent = scExtent;
1244 vkCmdSetScissor(command, 0, 1, &scissor);
1248 vkCmdBindPipeline(command, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
1251 if (m_textureDescriptorsWritten && CurrentFrameIndex < descriptorSets.size()) {
1252 vkCmdBindDescriptorSets(command, VK_PIPELINE_BIND_POINT_GRAPHICS,
1254 &descriptorSets[CurrentFrameIndex], 0,
nullptr);
1256 if (m_boneUBOCreated) {
1257 vkCmdBindDescriptorSets(command, VK_PIPELINE_BIND_POINT_GRAPHICS,
1259 &boneDescriptorSets[currentFrame], 0,
nullptr);
1261 if (m_lightUBOCreated) {
1262 vkCmdBindDescriptorSets(command, VK_PIPELINE_BIND_POINT_GRAPHICS,
1264 &m_lightUBODescriptorSets[currentFrame], 0,
nullptr);
1265 vkCmdBindDescriptorSets(command, VK_PIPELINE_BIND_POINT_GRAPHICS,
1267 &m_shadowSamplerDescriptorSets[currentFrame], 0,
nullptr);
1270 m_inForwardTransparentPass =
true;
1271 m_forwardPassOpen =
true;
1272 m_activeCustomFormat = 0;
1277 m_inForwardTransparentPass =
false;
1283 if (!m_deferredCBCreated || !data)
return;
1284 uint32_t copySize = std::min(size,
static_cast<uint32_t
>(
sizeof(DeferredCBData)));
1285 memcpy(m_deferredCBMapped[currentFrame], data, copySize);
1290 memcpy(m_cachedView, &V(0, 0),
sizeof(m_cachedView));
1291 memcpy(m_cachedProjection, &P(0, 0),
sizeof(m_cachedProjection));
1295 if (copySize >=
sizeof(m_cachedInvViewProj))
1296 memcpy(m_cachedInvViewProj, data,
sizeof(m_cachedInvViewProj));
1302 if (m_taaResourcesCreated &&
m_taaEnabled && scExtent.width > 0) {
1303 const uint32_t haltonIdx =
static_cast<uint32_t
>((m_taaFrameIdx % 8) + 1);
1304 m_taaJitter[0] = (
HaltonSeq(haltonIdx, 2) - 0.5f) /
static_cast<float>(scExtent.width);
1305 m_taaJitter[1] = (
HaltonSeq(haltonIdx, 3) - 0.5f) /
static_cast<float>(scExtent.height);
1307 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
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.