15bool VulkanRenderer::CreateShadowResources() {
17 VkImageCreateInfo imageInfo{};
18 imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
19 imageInfo.imageType = VK_IMAGE_TYPE_2D;
21 imageInfo.mipLevels = 1;
22 imageInfo.arrayLayers = 1;
23 imageInfo.format = VK_FORMAT_D32_SFLOAT;
24 imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
25 imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
26 imageInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT |
27 VK_IMAGE_USAGE_SAMPLED_BIT;
28 imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
29 imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
31 if (vkCreateImage(device, &imageInfo,
nullptr, &m_shadowImage) != VK_SUCCESS) {
36 VkMemoryRequirements memReqs;
37 vkGetImageMemoryRequirements(device, m_shadowImage, &memReqs);
39 VkMemoryAllocateInfo allocInfo{};
40 allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
41 allocInfo.allocationSize = memReqs.size;
42 allocInfo.memoryTypeIndex = FindMemoryType(memReqs.memoryTypeBits,
43 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
45 if (vkAllocateMemory(device, &allocInfo,
nullptr, &m_shadowImageMemory) != VK_SUCCESS) {
46 SLEAK_ERROR(
"Failed to allocate shadow map memory!");
50 vkBindImageMemory(device, m_shadowImage, m_shadowImageMemory, 0);
53 VkImageViewCreateInfo viewInfo{};
54 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
55 viewInfo.image = m_shadowImage;
56 viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
57 viewInfo.format = VK_FORMAT_D32_SFLOAT;
58 viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
59 viewInfo.subresourceRange.baseMipLevel = 0;
60 viewInfo.subresourceRange.levelCount = 1;
61 viewInfo.subresourceRange.baseArrayLayer = 0;
62 viewInfo.subresourceRange.layerCount = 1;
64 if (vkCreateImageView(device, &viewInfo,
nullptr, &m_shadowImageView) != VK_SUCCESS) {
65 SLEAK_ERROR(
"Failed to create shadow map image view!");
70 VkSamplerCreateInfo samplerInfo{};
71 samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
72 samplerInfo.magFilter = VK_FILTER_LINEAR;
73 samplerInfo.minFilter = VK_FILTER_LINEAR;
74 samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST;
75 samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
76 samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
77 samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
78 samplerInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
79 samplerInfo.compareEnable = VK_TRUE;
80 samplerInfo.compareOp = VK_COMPARE_OP_LESS;
81 samplerInfo.minLod = 0.0f;
82 samplerInfo.maxLod = 1.0f;
83 samplerInfo.anisotropyEnable = VK_FALSE;
85 if (vkCreateSampler(device, &samplerInfo,
nullptr, &m_shadowSampler) != VK_SUCCESS) {
86 SLEAK_ERROR(
"Failed to create shadow map sampler!");
93 VkSamplerCreateInfo rawSamplerInfo = samplerInfo;
94 rawSamplerInfo.compareEnable = VK_FALSE;
95 rawSamplerInfo.magFilter = VK_FILTER_NEAREST;
96 rawSamplerInfo.minFilter = VK_FILTER_NEAREST;
98 if (vkCreateSampler(device, &rawSamplerInfo,
nullptr, &m_shadowRawSampler) != VK_SUCCESS) {
99 SLEAK_ERROR(
"Failed to create shadow map raw sampler!");
104 VkAttachmentDescription depthAttachment{};
105 depthAttachment.format = VK_FORMAT_D32_SFLOAT;
106 depthAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
107 depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
108 depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
109 depthAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
110 depthAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
111 depthAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
112 depthAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
114 VkAttachmentReference depthRef{};
115 depthRef.attachment = 0;
116 depthRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
118 VkSubpassDescription subpass{};
119 subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
120 subpass.colorAttachmentCount = 0;
121 subpass.pDepthStencilAttachment = &depthRef;
124 std::array<VkSubpassDependency, 2> dependencies{};
126 dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL;
127 dependencies[0].dstSubpass = 0;
128 dependencies[0].srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
129 dependencies[0].dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
130 dependencies[0].srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
131 dependencies[0].dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
132 dependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
134 dependencies[1].srcSubpass = 0;
135 dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL;
136 dependencies[1].srcStageMask = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
137 dependencies[1].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
138 dependencies[1].srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
139 dependencies[1].dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
140 dependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
142 VkRenderPassCreateInfo renderPassInfo{};
143 renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
144 renderPassInfo.attachmentCount = 1;
145 renderPassInfo.pAttachments = &depthAttachment;
146 renderPassInfo.subpassCount = 1;
147 renderPassInfo.pSubpasses = &subpass;
148 renderPassInfo.dependencyCount =
static_cast<uint32_t
>(dependencies.size());
149 renderPassInfo.pDependencies = dependencies.data();
151 if (vkCreateRenderPass(device, &renderPassInfo,
nullptr, &m_shadowRenderPass) != VK_SUCCESS) {
152 SLEAK_ERROR(
"Failed to create shadow render pass!");
157 VkFramebufferCreateInfo fbInfo{};
158 fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
159 fbInfo.renderPass = m_shadowRenderPass;
160 fbInfo.attachmentCount = 1;
161 fbInfo.pAttachments = &m_shadowImageView;
166 if (vkCreateFramebuffer(device, &fbInfo,
nullptr, &m_shadowFramebuffer) != VK_SUCCESS) {
167 SLEAK_ERROR(
"Failed to create shadow framebuffer!");
176 VkCommandBufferAllocateInfo cmdAllocInfo{};
177 cmdAllocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
178 cmdAllocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
179 cmdAllocInfo.commandPool = commands;
180 cmdAllocInfo.commandBufferCount = 1;
182 VkCommandBuffer cmdBuf;
183 vkAllocateCommandBuffers(device, &cmdAllocInfo, &cmdBuf);
185 VkCommandBufferBeginInfo cmdBeginInfo{};
186 cmdBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
187 cmdBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
188 vkBeginCommandBuffer(cmdBuf, &cmdBeginInfo);
190 VkImageMemoryBarrier barrier{};
191 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
192 barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
193 barrier.newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
194 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
195 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
196 barrier.image = m_shadowImage;
197 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
198 barrier.subresourceRange.baseMipLevel = 0;
199 barrier.subresourceRange.levelCount = 1;
200 barrier.subresourceRange.baseArrayLayer = 0;
201 barrier.subresourceRange.layerCount = 1;
202 barrier.srcAccessMask = 0;
203 barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
205 vkCmdPipelineBarrier(cmdBuf,
206 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
207 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
208 0, 0,
nullptr, 0,
nullptr, 1, &barrier);
210 vkEndCommandBuffer(cmdBuf);
212 VkSubmitInfo layoutSubmit{};
213 layoutSubmit.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
214 layoutSubmit.commandBufferCount = 1;
215 layoutSubmit.pCommandBuffers = &cmdBuf;
217 VkFenceCreateInfo layoutFenceInfo{};
218 layoutFenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
220 vkCreateFence(device, &layoutFenceInfo,
nullptr, &layoutFence);
221 vkQueueSubmit(graphicsQueue, 1, &layoutSubmit, layoutFence);
222 vkWaitForFences(device, 1, &layoutFence, VK_TRUE, UINT64_MAX);
223 vkDestroyFence(device, layoutFence,
nullptr);
224 vkFreeCommandBuffers(device, commands, 1, &cmdBuf);
228 if (!CreateShadowPipeline()) {
236 if (m_lightUBOCreated && m_shadowImageView && m_shadowSampler && m_shadowRawSampler) {
237 for (uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) {
239 VkDescriptorImageInfo compareInfo{};
240 compareInfo.imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
241 compareInfo.imageView = m_shadowImageView;
242 compareInfo.sampler = m_shadowSampler;
244 VkDescriptorImageInfo rawInfo{};
245 rawInfo.imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
246 rawInfo.imageView = m_shadowImageView;
247 rawInfo.sampler = m_shadowRawSampler;
249 std::array<VkWriteDescriptorSet, 2> writes{};
250 writes[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
251 writes[0].dstSet = m_shadowSamplerDescriptorSets[i];
252 writes[0].dstBinding = 0;
253 writes[0].dstArrayElement = 0;
254 writes[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
255 writes[0].descriptorCount = 1;
256 writes[0].pImageInfo = &compareInfo;
258 writes[1] = writes[0];
259 writes[1].dstBinding = 1;
260 writes[1].pImageInfo = &rawInfo;
262 vkUpdateDescriptorSets(device,
static_cast<uint32_t
>(writes.size()),
263 writes.data(), 0,
nullptr);
268 SLEAK_INFO(
"VulkanRenderer: Shadow mapping resources created ({}x{} shadow map)",
274bool VulkanRenderer::CreateShadowPipeline() {
275 m_shadowShader =
new VulkanShader(device);
276 if (!m_shadowShader->compileVertexOnly(
"assets/shaders/shadow_depth.vert.spv")) {
277 SLEAK_ERROR(
"VulkanRenderer: Failed to compile shadow depth shader");
278 delete m_shadowShader;
279 m_shadowShader =
nullptr;
284 VkPipelineShaderStageCreateInfo shaderStage = m_shadowShader->GetVertexInfo();
286 std::vector<VkDynamicState> dynamicStates = {
287 VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR};
289 VkPipelineDynamicStateCreateInfo dynamicState{};
290 dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
291 dynamicState.dynamicStateCount =
static_cast<uint32_t
>(dynamicStates.size());
292 dynamicState.pDynamicStates = dynamicStates.data();
295 VkVertexInputBindingDescription bindingDescription{};
296 bindingDescription.binding = 0;
297 bindingDescription.stride =
sizeof(
Vertex);
298 bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
300 std::array<VkVertexInputAttributeDescription, 7> attributeDescs{};
301 attributeDescs[0] = {0, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(
Vertex, px)};
302 attributeDescs[1] = {1, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(
Vertex, nx)};
303 attributeDescs[2] = {2, 0, VK_FORMAT_R32G32B32A32_SFLOAT, offsetof(
Vertex, tx)};
304 attributeDescs[3] = {3, 0, VK_FORMAT_R32G32B32A32_SFLOAT, offsetof(
Vertex, r)};
305 attributeDescs[4] = {4, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(
Vertex, u)};
306 attributeDescs[5] = {5, 0, VK_FORMAT_R32G32B32A32_SINT, offsetof(
Vertex, boneIDs)};
307 attributeDescs[6] = {6, 0, VK_FORMAT_R32G32B32A32_SFLOAT, offsetof(
Vertex, boneWeights)};
309 VkPipelineVertexInputStateCreateInfo vertexInputInfo{};
310 vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
311 vertexInputInfo.vertexBindingDescriptionCount = 1;
312 vertexInputInfo.pVertexBindingDescriptions = &bindingDescription;
313 vertexInputInfo.vertexAttributeDescriptionCount =
314 static_cast<uint32_t
>(attributeDescs.size());
315 vertexInputInfo.pVertexAttributeDescriptions = attributeDescs.data();
317 VkPipelineInputAssemblyStateCreateInfo inputAssembly{};
318 inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
319 inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
320 inputAssembly.primitiveRestartEnable = VK_FALSE;
322 VkPipelineViewportStateCreateInfo viewportState{};
323 viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
324 viewportState.viewportCount = 1;
325 viewportState.scissorCount = 1;
327 VkPipelineRasterizationStateCreateInfo rasterizer{};
328 rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
329 rasterizer.depthClampEnable = VK_FALSE;
330 rasterizer.rasterizerDiscardEnable = VK_FALSE;
331 rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
332 rasterizer.lineWidth = 1.0f;
333 rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
334 rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
335 rasterizer.depthBiasEnable = VK_TRUE;
336 rasterizer.depthBiasConstantFactor = 1.25f;
337 rasterizer.depthBiasSlopeFactor = 1.75f;
338 rasterizer.depthBiasClamp = 0.0f;
340 VkPipelineMultisampleStateCreateInfo msaa{};
341 msaa.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
342 msaa.sampleShadingEnable = VK_FALSE;
343 msaa.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
345 VkPipelineDepthStencilStateCreateInfo depthStencil{};
346 depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
347 depthStencil.depthTestEnable = VK_TRUE;
348 depthStencil.depthWriteEnable = VK_TRUE;
349 depthStencil.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL;
350 depthStencil.depthBoundsTestEnable = VK_FALSE;
351 depthStencil.stencilTestEnable = VK_FALSE;
354 VkPipelineColorBlendStateCreateInfo colorBlendInfo{};
355 colorBlendInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
356 colorBlendInfo.logicOpEnable = VK_FALSE;
357 colorBlendInfo.attachmentCount = 0;
359 VkGraphicsPipelineCreateInfo pipelineInfo{};
360 pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
361 pipelineInfo.stageCount = 1;
362 pipelineInfo.pStages = &shaderStage;
363 pipelineInfo.pVertexInputState = &vertexInputInfo;
364 pipelineInfo.pInputAssemblyState = &inputAssembly;
365 pipelineInfo.pViewportState = &viewportState;
366 pipelineInfo.pRasterizationState = &rasterizer;
367 pipelineInfo.pMultisampleState = &msaa;
368 pipelineInfo.pDepthStencilState = &depthStencil;
369 pipelineInfo.pColorBlendState = &colorBlendInfo;
370 pipelineInfo.pDynamicState = &dynamicState;
371 pipelineInfo.layout = pipelineLay;
372 pipelineInfo.renderPass = m_shadowRenderPass;
373 pipelineInfo.subpass = 0;
374 pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
375 pipelineInfo.basePipelineIndex = -1;
377 VkResult result = vkCreateGraphicsPipelines(
378 device, VK_NULL_HANDLE, 1, &pipelineInfo,
nullptr, &m_shadowPipeline);
379 if (result != VK_SUCCESS) {
380 SLEAK_ERROR(
"VulkanRenderer: Failed to create shadow pipeline!");
384 SLEAK_INFO(
"VulkanRenderer: Shadow pipeline created successfully");
389bool VulkanRenderer::CreateShadowLightUBOResources() {
390 static constexpr VkDeviceSize uboSize =
sizeof(ShadowLightUBO);
393 for (uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) {
394 VkBufferCreateInfo bufferInfo{};
395 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
396 bufferInfo.size = uboSize;
397 bufferInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
398 bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
400 if (vkCreateBuffer(device, &bufferInfo,
nullptr, &m_lightUBOBuffers[i]) != VK_SUCCESS) {
405 VkMemoryRequirements memReqs;
406 vkGetBufferMemoryRequirements(device, m_lightUBOBuffers[i], &memReqs);
408 VkMemoryAllocateInfo allocInfo{};
409 allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
410 allocInfo.allocationSize = memReqs.size;
411 allocInfo.memoryTypeIndex = FindMemoryType(memReqs.memoryTypeBits,
412 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
414 if (vkAllocateMemory(device, &allocInfo,
nullptr, &m_lightUBOMemory[i]) != VK_SUCCESS) {
415 SLEAK_ERROR(
"Failed to allocate light UBO memory!");
419 vkBindBufferMemory(device, m_lightUBOBuffers[i], m_lightUBOMemory[i], 0);
420 vkMapMemory(device, m_lightUBOMemory[i], 0, uboSize, 0, &m_lightUBOMapped[i]);
421 memset(m_lightUBOMapped[i], 0, uboSize);
426 std::array<VkDescriptorPoolSize, 2> poolSizes{};
427 poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
428 poolSizes[0].descriptorCount = MAX_FRAMES_IN_FLIGHT;
429 poolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
430 poolSizes[1].descriptorCount = MAX_FRAMES_IN_FLIGHT * 2;
432 VkDescriptorPoolCreateInfo poolInfo{};
433 poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
434 poolInfo.poolSizeCount =
static_cast<uint32_t
>(poolSizes.size());
435 poolInfo.pPoolSizes = poolSizes.data();
436 poolInfo.maxSets = MAX_FRAMES_IN_FLIGHT * 2;
438 if (vkCreateDescriptorPool(device, &poolInfo,
nullptr, &m_lightUBODescriptorPool) != VK_SUCCESS) {
439 SLEAK_ERROR(
"Failed to create light UBO descriptor pool!");
444 std::array<VkDescriptorSetLayout, MAX_FRAMES_IN_FLIGHT> uboLayouts;
445 uboLayouts.fill(m_lightUBODescriptorSetLayout);
447 VkDescriptorSetAllocateInfo uboAllocInfo{};
448 uboAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
449 uboAllocInfo.descriptorPool = m_lightUBODescriptorPool;
450 uboAllocInfo.descriptorSetCount = MAX_FRAMES_IN_FLIGHT;
451 uboAllocInfo.pSetLayouts = uboLayouts.data();
453 if (vkAllocateDescriptorSets(device, &uboAllocInfo, m_lightUBODescriptorSets.data()) != VK_SUCCESS) {
454 SLEAK_ERROR(
"Failed to allocate light UBO descriptor sets!");
459 for (uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) {
460 VkDescriptorBufferInfo bufInfo{};
461 bufInfo.buffer = m_lightUBOBuffers[i];
463 bufInfo.range = uboSize;
465 VkWriteDescriptorSet write{};
466 write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
467 write.dstSet = m_lightUBODescriptorSets[i];
468 write.dstBinding = 0;
469 write.dstArrayElement = 0;
470 write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
471 write.descriptorCount = 1;
472 write.pBufferInfo = &bufInfo;
474 vkUpdateDescriptorSets(device, 1, &write, 0,
nullptr);
478 std::array<VkDescriptorSetLayout, MAX_FRAMES_IN_FLIGHT> samplerLayouts;
479 samplerLayouts.fill(m_shadowSamplerDescriptorSetLayout);
481 VkDescriptorSetAllocateInfo samplerAllocInfo{};
482 samplerAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
483 samplerAllocInfo.descriptorPool = m_lightUBODescriptorPool;
484 samplerAllocInfo.descriptorSetCount = MAX_FRAMES_IN_FLIGHT;
485 samplerAllocInfo.pSetLayouts = samplerLayouts.data();
487 if (vkAllocateDescriptorSets(device, &samplerAllocInfo, m_shadowSamplerDescriptorSets.data()) != VK_SUCCESS) {
488 SLEAK_ERROR(
"Failed to allocate shadow sampler descriptor sets!");
496 if (m_defaultTexture) {
497 for (uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) {
498 VkDescriptorImageInfo imageInfo{};
499 imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
500 imageInfo.imageView = m_defaultTexture->GetImageView();
501 imageInfo.sampler = m_defaultTexture->GetSampler();
503 std::array<VkWriteDescriptorSet, 2> writes{};
504 writes[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
505 writes[0].dstSet = m_shadowSamplerDescriptorSets[i];
506 writes[0].dstBinding = 0;
507 writes[0].dstArrayElement = 0;
508 writes[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
509 writes[0].descriptorCount = 1;
510 writes[0].pImageInfo = &imageInfo;
512 writes[1] = writes[0];
513 writes[1].dstBinding = 1;
515 vkUpdateDescriptorSets(device,
static_cast<uint32_t
>(writes.size()),
516 writes.data(), 0,
nullptr);
520 m_lightUBOCreated =
true;
521 SLEAK_INFO(
"VulkanRenderer: Light UBO and shadow sampler resources created");
526void VulkanRenderer::CleanupShadowResources() {
527 if (m_shadowPipeline) {
528 vkDestroyPipeline(device, m_shadowPipeline,
nullptr);
529 m_shadowPipeline = VK_NULL_HANDLE;
531 delete m_shadowShader;
532 m_shadowShader =
nullptr;
534 if (m_shadowFramebuffer) {
535 vkDestroyFramebuffer(device, m_shadowFramebuffer,
nullptr);
536 m_shadowFramebuffer = VK_NULL_HANDLE;
538 if (m_shadowRenderPass) {
539 vkDestroyRenderPass(device, m_shadowRenderPass,
nullptr);
540 m_shadowRenderPass = VK_NULL_HANDLE;
542 if (m_shadowSampler) {
543 vkDestroySampler(device, m_shadowSampler,
nullptr);
544 m_shadowSampler = VK_NULL_HANDLE;
546 if (m_shadowRawSampler) {
547 vkDestroySampler(device, m_shadowRawSampler,
nullptr);
548 m_shadowRawSampler = VK_NULL_HANDLE;
550 if (m_shadowImageView) {
551 vkDestroyImageView(device, m_shadowImageView,
nullptr);
552 m_shadowImageView = VK_NULL_HANDLE;
555 vkDestroyImage(device, m_shadowImage,
nullptr);
556 m_shadowImage = VK_NULL_HANDLE;
558 if (m_shadowImageMemory) {
559 vkFreeMemory(device, m_shadowImageMemory,
nullptr);
560 m_shadowImageMemory = VK_NULL_HANDLE;
564 if (m_lightUBOCreated) {
565 for (uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) {
566 if (m_lightUBOMapped[i]) {
567 vkUnmapMemory(device, m_lightUBOMemory[i]);
568 m_lightUBOMapped[i] =
nullptr;
570 if (m_lightUBOBuffers[i]) {
571 vkDestroyBuffer(device, m_lightUBOBuffers[i],
nullptr);
572 m_lightUBOBuffers[i] = VK_NULL_HANDLE;
574 if (m_lightUBOMemory[i]) {
575 vkFreeMemory(device, m_lightUBOMemory[i],
nullptr);
576 m_lightUBOMemory[i] = VK_NULL_HANDLE;
579 m_lightUBOCreated =
false;
582 if (m_lightUBODescriptorPool) {
583 vkDestroyDescriptorPool(device, m_lightUBODescriptorPool,
nullptr);
584 m_lightUBODescriptorPool = VK_NULL_HANDLE;
592 m_shadowPassActive =
true;
593 m_shadowPCCacheValid =
false;
598 m_shadowPassActive =
false;
603 if (!m_lightUBOCreated || !data)
return;
604 uint32_t copySize = std::min(size,
static_cast<uint32_t
>(
sizeof(
ShadowLightUBO)));
605 memcpy(m_lightUBOMapped[currentFrame], data, copySize);
616 memcpy(m_pendingLightVP, lightVP,
sizeof(m_pendingLightVP));
617 m_hasPendingLightVP =
true;
uint32_t m_shadowMapResolution
bool m_shadowResourcesCreated
void SetLightVP(const float *lightVP) override
Stages the light view-projection matrix for commit at the next BeginRender.
virtual void BeginShadowPass() override
Marks the shadow pass active and invalidates the push constant cache.
virtual void EndShadowPass() override
Marks the shadow pass inactive.
void UpdateShadowLightUBO(const void *data, uint32_t size) override
Copies light and shadow data into the current frame's mapped UBO.
Backend-facing rendering layer shared by the four graphics backends.
Root namespace for everything the engine exposes.
Shadow-pass UBO: light/shadow parameters, fog, and extra fill lights (set 2, binding 0).