14bool VulkanRenderer::CreateDescriptorSetLayout() {
16 VkDescriptorSetLayoutBinding samplerBinding{};
17 samplerBinding.binding = 0;
18 samplerBinding.descriptorType =
19 VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
20 samplerBinding.descriptorCount = 1;
21 samplerBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
22 samplerBinding.pImmutableSamplers =
nullptr;
24 VkDescriptorSetLayoutCreateInfo layoutInfo{};
26 VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
27 layoutInfo.bindingCount = 1;
28 layoutInfo.pBindings = &samplerBinding;
30 if (vkCreateDescriptorSetLayout(device, &layoutInfo,
nullptr,
31 &descriptorSetLayout) != VK_SUCCESS)
35 VkDescriptorSetLayoutBinding boneUBOBinding{};
36 boneUBOBinding.binding = 0;
37 boneUBOBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
38 boneUBOBinding.descriptorCount = 1;
39 boneUBOBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
40 boneUBOBinding.pImmutableSamplers =
nullptr;
42 VkDescriptorSetLayoutCreateInfo boneLayoutInfo{};
43 boneLayoutInfo.sType =
44 VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
45 boneLayoutInfo.bindingCount = 1;
46 boneLayoutInfo.pBindings = &boneUBOBinding;
48 if (vkCreateDescriptorSetLayout(device, &boneLayoutInfo,
nullptr,
49 &boneDescriptorSetLayout) != VK_SUCCESS)
53 VkDescriptorSetLayoutBinding lightUBOBinding{};
54 lightUBOBinding.binding = 0;
55 lightUBOBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
56 lightUBOBinding.descriptorCount = 1;
57 lightUBOBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
58 lightUBOBinding.pImmutableSamplers =
nullptr;
60 VkDescriptorSetLayoutCreateInfo lightUBOLayoutInfo{};
61 lightUBOLayoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
62 lightUBOLayoutInfo.bindingCount = 1;
63 lightUBOLayoutInfo.pBindings = &lightUBOBinding;
65 if (vkCreateDescriptorSetLayout(device, &lightUBOLayoutInfo,
nullptr,
66 &m_lightUBODescriptorSetLayout) != VK_SUCCESS)
71 std::array<VkDescriptorSetLayoutBinding, 2> shadowSamplerBindings{};
72 shadowSamplerBindings[0].binding = 0;
73 shadowSamplerBindings[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
74 shadowSamplerBindings[0].descriptorCount = 1;
75 shadowSamplerBindings[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
76 shadowSamplerBindings[0].pImmutableSamplers =
nullptr;
78 shadowSamplerBindings[1].binding = 1;
79 shadowSamplerBindings[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
80 shadowSamplerBindings[1].descriptorCount = 1;
81 shadowSamplerBindings[1].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
82 shadowSamplerBindings[1].pImmutableSamplers =
nullptr;
84 VkDescriptorSetLayoutCreateInfo shadowSamplerLayoutInfo{};
85 shadowSamplerLayoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
86 shadowSamplerLayoutInfo.bindingCount =
static_cast<uint32_t
>(shadowSamplerBindings.size());
87 shadowSamplerLayoutInfo.pBindings = shadowSamplerBindings.data();
89 if (vkCreateDescriptorSetLayout(device, &shadowSamplerLayoutInfo,
nullptr,
90 &m_shadowSamplerDescriptorSetLayout) != VK_SUCCESS)
98bool VulkanRenderer::CreateDescriptorPool() {
100 static_cast<uint32_t
>(swapChainImages.size());
103 static constexpr uint32_t MAX_TEXTURES = 1024;
104 uint32_t totalSets = imageCount * MAX_TEXTURES;
106 VkDescriptorPoolSize poolSize{};
107 poolSize.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
108 poolSize.descriptorCount = totalSets;
110 VkDescriptorPoolCreateInfo poolInfo{};
111 poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
112 poolInfo.poolSizeCount = 1;
113 poolInfo.pPoolSizes = &poolSize;
114 poolInfo.maxSets = totalSets;
116 if (vkCreateDescriptorPool(device, &poolInfo,
nullptr,
117 &descriptorPool) != VK_SUCCESS)
125bool VulkanRenderer::AllocateDescriptorSets() {
126 uint32_t imageCount =
127 static_cast<uint32_t
>(swapChainImages.size());
129 std::vector<VkDescriptorSetLayout> layouts(imageCount,
130 descriptorSetLayout);
132 VkDescriptorSetAllocateInfo allocInfo{};
133 allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
134 allocInfo.descriptorPool = descriptorPool;
135 allocInfo.descriptorSetCount = imageCount;
136 allocInfo.pSetLayouts = layouts.data();
138 descriptorSets.resize(imageCount);
139 if (vkAllocateDescriptorSets(device, &allocInfo,
140 descriptorSets.data()) != VK_SUCCESS)
148bool VulkanRenderer::CreateDefaultTexture() {
151 uint32_t whitePixel = 0xFFFFFFFF;
152 m_defaultTexture =
new VulkanTexture(device, physicalDevice, commands,
154 if (!m_defaultTexture->LoadFromMemory(&whitePixel, 1, 1,
156 delete m_defaultTexture;
157 m_defaultTexture =
nullptr;
162 WriteTextureDescriptors(m_defaultTexture);
166 for (
size_t i = 0; i < descriptorSets.size(); i++) {
167 VkDescriptorImageInfo imageInfo{};
168 imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
169 imageInfo.imageView = m_defaultTexture->GetImageView();
170 imageInfo.sampler = m_defaultTexture->GetSampler();
172 VkWriteDescriptorSet descriptorWrite{};
173 descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
174 descriptorWrite.dstSet = descriptorSets[i];
175 descriptorWrite.dstBinding = 0;
176 descriptorWrite.dstArrayElement = 0;
177 descriptorWrite.descriptorType =
178 VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
179 descriptorWrite.descriptorCount = 1;
180 descriptorWrite.pImageInfo = &imageInfo;
182 vkUpdateDescriptorSets(device, 1, &descriptorWrite, 0,
nullptr);
184 m_textureDescriptorsWritten =
true;
191void VulkanRenderer::WriteTextureDescriptors(
VulkanTexture* texture) {
192 if (!texture || texture->GetImageView() == VK_NULL_HANDLE ||
193 texture->GetSampler() == VK_NULL_HANDLE)
196 uint32_t imageCount =
static_cast<uint32_t
>(swapChainImages.size());
199 std::vector<VkDescriptorSetLayout> layouts(imageCount, descriptorSetLayout);
201 VkDescriptorSetAllocateInfo allocInfo{};
202 allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
203 allocInfo.descriptorPool = descriptorPool;
204 allocInfo.descriptorSetCount = imageCount;
205 allocInfo.pSetLayouts = layouts.data();
207 std::vector<VkDescriptorSet> sets(imageCount);
208 if (vkAllocateDescriptorSets(device, &allocInfo, sets.data()) != VK_SUCCESS) {
209 SLEAK_ERROR(
"VulkanRenderer: Failed to allocate descriptor sets for texture");
214 for (
size_t i = 0; i < sets.size(); i++) {
215 VkDescriptorImageInfo imageInfo{};
216 imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
217 imageInfo.imageView = texture->GetImageView();
218 imageInfo.sampler = texture->GetSampler();
220 VkWriteDescriptorSet descriptorWrite{};
221 descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
222 descriptorWrite.dstSet = sets[i];
223 descriptorWrite.dstBinding = 0;
224 descriptorWrite.dstArrayElement = 0;
225 descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
226 descriptorWrite.descriptorCount = 1;
227 descriptorWrite.pImageInfo = &imageInfo;
229 vkUpdateDescriptorSets(device, 1, &descriptorWrite, 0,
nullptr);
232 texture->SetDescriptorSets(std::move(sets));
237 if (!device || !instance || !graphicsQueue)
243 VkRenderPass imguiRenderPass = VK_NULL_HANDLE;
244 if (m_gbufferResourcesCreated &&
m_deferredEnabled && m_bloomCompositeRenderPass != VK_NULL_HANDLE) {
245 imguiRenderPass = m_bloomCompositeRenderPass;
246 }
else if (m_gbufferResourcesCreated &&
m_deferredEnabled && m_forwardRenderPass != VK_NULL_HANDLE) {
247 imguiRenderPass = m_forwardRenderPass;
249 imguiRenderPass = renderPass;
252 if (!imguiRenderPass)
256 VkDescriptorPoolSize poolSizes[] = {
257 {VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 64},
258 {VK_DESCRIPTOR_TYPE_SAMPLER, IMGUI_IMPL_VULKAN_MINIMUM_SAMPLER_POOL_SIZE},
261 VkDescriptorPoolCreateInfo poolInfo{};
262 poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
263 poolInfo.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
264 poolInfo.maxSets = 64 + IMGUI_IMPL_VULKAN_MINIMUM_SAMPLER_POOL_SIZE;
265 poolInfo.poolSizeCount = 2;
266 poolInfo.pPoolSizes = poolSizes;
268 if (vkCreateDescriptorPool(device, &poolInfo,
nullptr,
269 &imguiDescriptorPool) != VK_SUCCESS) {
270 SLEAK_ERROR(
"Failed to create ImGUI descriptor pool!");
274 IMGUI_CHECKVERSION();
275 ImGui::CreateContext();
276 ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
277 ImGui::StyleColorsDark();
279 if (!ImGui_ImplSDL3_InitForVulkan(sdlWindow->GetSDLWindow()))
282 ImGui_ImplVulkan_InitInfo initInfo{};
283 initInfo.Instance = instance;
284 initInfo.PhysicalDevice = physicalDevice;
285 initInfo.Device = device;
286 initInfo.QueueFamily = QueueIDs.GraphicsIndex;
287 initInfo.Queue = graphicsQueue;
288 initInfo.DescriptorPool = imguiDescriptorPool;
289 initInfo.MinImageCount = 2;
290 initInfo.ImageCount =
291 static_cast<uint32_t
>(swapChainImages.size());
292 initInfo.PipelineInfoMain.MSAASamples = (m_gbufferResourcesCreated &&
m_deferredEnabled)
293 ? VK_SAMPLE_COUNT_1_BIT : m_msaaSamples;
294 initInfo.PipelineInfoMain.RenderPass = imguiRenderPass;
295 initInfo.PipelineInfoMain.Subpass = 0;
297 if (!ImGui_ImplVulkan_Init(&initInfo))
305bool VulkanRenderer::CreateBoneUBOResources() {
306 if (m_boneUBOCreated)
return true;
308 static constexpr uint32_t
MAX_BONES = 256;
309 static constexpr VkDeviceSize boneUBOSize =
MAX_BONES * 64;
312 for (uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) {
313 VkBufferCreateInfo bufferInfo{};
314 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
315 bufferInfo.size = boneUBOSize;
316 bufferInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
317 bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
319 if (vkCreateBuffer(device, &bufferInfo,
nullptr, &boneUBOBuffers[i]) != VK_SUCCESS) {
324 VkMemoryRequirements memReqs;
325 vkGetBufferMemoryRequirements(device, boneUBOBuffers[i], &memReqs);
327 VkMemoryAllocateInfo allocInfo{};
328 allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
329 allocInfo.allocationSize = memReqs.size;
330 allocInfo.memoryTypeIndex = FindMemoryType(memReqs.memoryTypeBits,
331 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
333 if (vkAllocateMemory(device, &allocInfo,
nullptr, &boneUBOMemory[i]) != VK_SUCCESS) {
334 SLEAK_ERROR(
"Failed to allocate bone UBO memory!");
338 vkBindBufferMemory(device, boneUBOBuffers[i], boneUBOMemory[i], 0);
339 vkMapMemory(device, boneUBOMemory[i], 0, boneUBOSize, 0, &boneUBOMapped[i]);
342 auto* matrices =
static_cast<float*
>(boneUBOMapped[i]);
343 for (uint32_t b = 0; b <
MAX_BONES; ++b) {
345 for (
int c = 0; c < 16; ++c)
346 matrices[b * 16 + c] = (c % 5 == 0) ? 1.0f : 0.0f;
351 VkDescriptorPoolSize poolSize{};
352 poolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
353 poolSize.descriptorCount = MAX_FRAMES_IN_FLIGHT;
355 VkDescriptorPoolCreateInfo poolInfo{};
356 poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
357 poolInfo.poolSizeCount = 1;
358 poolInfo.pPoolSizes = &poolSize;
359 poolInfo.maxSets = MAX_FRAMES_IN_FLIGHT;
361 if (vkCreateDescriptorPool(device, &poolInfo,
nullptr, &boneDescriptorPool) != VK_SUCCESS) {
362 SLEAK_ERROR(
"Failed to create bone descriptor pool!");
367 std::array<VkDescriptorSetLayout, MAX_FRAMES_IN_FLIGHT> layouts;
368 layouts.fill(boneDescriptorSetLayout);
370 VkDescriptorSetAllocateInfo dsAllocInfo{};
371 dsAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
372 dsAllocInfo.descriptorPool = boneDescriptorPool;
373 dsAllocInfo.descriptorSetCount = MAX_FRAMES_IN_FLIGHT;
374 dsAllocInfo.pSetLayouts = layouts.data();
376 if (vkAllocateDescriptorSets(device, &dsAllocInfo, boneDescriptorSets.data()) != VK_SUCCESS) {
377 SLEAK_ERROR(
"Failed to allocate bone descriptor sets!");
382 for (uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) {
383 VkDescriptorBufferInfo bufInfo{};
384 bufInfo.buffer = boneUBOBuffers[i];
386 bufInfo.range = boneUBOSize;
388 VkWriteDescriptorSet descriptorWrite{};
389 descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
390 descriptorWrite.dstSet = boneDescriptorSets[i];
391 descriptorWrite.dstBinding = 0;
392 descriptorWrite.dstArrayElement = 0;
393 descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
394 descriptorWrite.descriptorCount = 1;
395 descriptorWrite.pBufferInfo = &bufInfo;
397 vkUpdateDescriptorSets(device, 1, &descriptorWrite, 0,
nullptr);
400 m_boneUBOCreated =
true;
401 SLEAK_INFO(
"VulkanRenderer: Bone UBO resources created ({} bytes per frame)", boneUBOSize);
407void VulkanRenderer::CleanupBoneUBOResources() {
408 if (!m_boneUBOCreated)
return;
410 for (uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) {
411 if (boneUBOMapped[i]) {
412 vkUnmapMemory(device, boneUBOMemory[i]);
413 boneUBOMapped[i] =
nullptr;
415 if (boneUBOBuffers[i]) {
416 vkDestroyBuffer(device, boneUBOBuffers[i],
nullptr);
417 boneUBOBuffers[i] = VK_NULL_HANDLE;
419 if (boneUBOMemory[i]) {
420 vkFreeMemory(device, boneUBOMemory[i],
nullptr);
421 boneUBOMemory[i] = VK_NULL_HANDLE;
424 if (boneDescriptorPool) {
425 vkDestroyDescriptorPool(device, boneDescriptorPool,
nullptr);
426 boneDescriptorPool = VK_NULL_HANDLE;
428 m_boneUBOCreated =
false;
433 if (!bFrameStarted)
return;
437 if (!m_boneUBOCreated) {
438 if (!CreateBoneUBOResources())
return;
447 uint32_t size =
static_cast<uint32_t
>(vkBuf->GetSize());
448 static constexpr uint32_t MAX_BONE_UBO_SIZE = 256 * 64;
449 if (size > MAX_BONE_UBO_SIZE) size = MAX_BONE_UBO_SIZE;
453 memcpy(boneUBOMapped[currentFrame], data, size);
460 VkPipelineLayout boneBindLayout = (m_inGeometryPass && m_gbufferGeomLayout != VK_NULL_HANDLE)
461 ? m_gbufferGeomLayout : pipelineLay;
462 vkCmdBindDescriptorSets(command, VK_PIPELINE_BIND_POINT_GRAPHICS,
463 boneBindLayout, 1, 1,
464 &boneDescriptorSets[currentFrame],
471bool VulkanRenderer::CreatePBRMaterialResources() {
472 if (m_pbrMaterialResourcesCreated)
return true;
475 std::array<VkDescriptorSetLayoutBinding, 7> bindings{};
476 for (uint32_t i = 0; i < 6; ++i) {
477 bindings[i].binding = i;
478 bindings[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
479 bindings[i].descriptorCount = 1;
480 bindings[i].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
482 bindings[6].binding = 6;
483 bindings[6].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
484 bindings[6].descriptorCount = 1;
485 bindings[6].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
487 VkDescriptorSetLayoutCreateInfo dslInfo{};
488 dslInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
489 dslInfo.bindingCount = 7;
490 dslInfo.pBindings = bindings.data();
491 if (vkCreateDescriptorSetLayout(device, &dslInfo,
nullptr, &m_pbrMaterialDSL) != VK_SUCCESS) {
492 SLEAK_ERROR(
"PBR: Failed to create PBR material DSL!");
497 std::array<VkDescriptorPoolSize, 2> poolSizes{};
498 poolSizes[0].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
499 poolSizes[0].descriptorCount = 6 * PBR_SET_COUNT;
500 poolSizes[1].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
501 poolSizes[1].descriptorCount = 1 * PBR_SET_COUNT;
503 VkDescriptorPoolCreateInfo poolInfo{};
504 poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
505 poolInfo.poolSizeCount =
static_cast<uint32_t
>(poolSizes.size());
506 poolInfo.pPoolSizes = poolSizes.data();
507 poolInfo.maxSets = PBR_SET_COUNT;
508 if (vkCreateDescriptorPool(device, &poolInfo,
nullptr, &m_pbrMaterialPool) != VK_SUCCESS) {
509 SLEAK_ERROR(
"PBR: Failed to create PBR material pool!");
514 std::array<VkDescriptorSetLayout, PBR_SET_COUNT> layouts;
515 layouts.fill(m_pbrMaterialDSL);
516 VkDescriptorSetAllocateInfo allocInfo{};
517 allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
518 allocInfo.descriptorPool = m_pbrMaterialPool;
519 allocInfo.descriptorSetCount = PBR_SET_COUNT;
520 allocInfo.pSetLayouts = layouts.data();
521 if (vkAllocateDescriptorSets(device, &allocInfo, m_pbrMaterialSets.data()) != VK_SUCCESS) {
522 SLEAK_ERROR(
"PBR: Failed to allocate PBR material descriptor sets!");
527 VkPhysicalDeviceProperties props{};
528 vkGetPhysicalDeviceProperties(physicalDevice, &props);
529 VkDeviceSize minAlign = props.limits.minUniformBufferOffsetAlignment;
530 VkDeviceSize stride =
sizeof(PBRMaterialParams);
532 stride = ((stride + minAlign - 1) / minAlign) * minAlign;
533 m_pbrMaterialUBOStride = stride;
534 const VkDeviceSize uboSize = stride * PBR_SETS_PER_FRAME;
535 for (uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) {
536 VkBufferCreateInfo bufInfo{};
537 bufInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
538 bufInfo.size = uboSize;
539 bufInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
540 bufInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
541 if (vkCreateBuffer(device, &bufInfo,
nullptr, &m_pbrMaterialCBBuffers[i]) != VK_SUCCESS) {
542 SLEAK_ERROR(
"PBR: Failed to create material UBO buffer {}!", i);
546 VkMemoryRequirements memReqs;
547 vkGetBufferMemoryRequirements(device, m_pbrMaterialCBBuffers[i], &memReqs);
548 VkMemoryAllocateInfo memInfo{};
549 memInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
550 memInfo.allocationSize = memReqs.size;
551 memInfo.memoryTypeIndex = FindMemoryType(memReqs.memoryTypeBits,
552 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
553 if (vkAllocateMemory(device, &memInfo,
nullptr, &m_pbrMaterialCBMemory[i]) != VK_SUCCESS) {
554 SLEAK_ERROR(
"PBR: Failed to allocate material UBO memory {}!", i);
557 vkBindBufferMemory(device, m_pbrMaterialCBBuffers[i], m_pbrMaterialCBMemory[i], 0);
558 vkMapMemory(device, m_pbrMaterialCBMemory[i], 0, uboSize, 0, &m_pbrMaterialCBMapped[i]);
564 std::array<VkDescriptorSetLayout, 4> geomSetLayouts = {
566 boneDescriptorSetLayout,
567 m_lightUBODescriptorSetLayout,
568 m_shadowSamplerDescriptorSetLayout
570 VkPushConstantRange pcRange{};
571 pcRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
575 VkPipelineLayoutCreateInfo layoutInfo{};
576 layoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
577 layoutInfo.setLayoutCount =
static_cast<uint32_t
>(geomSetLayouts.size());
578 layoutInfo.pSetLayouts = geomSetLayouts.data();
579 layoutInfo.pushConstantRangeCount = 1;
580 layoutInfo.pPushConstantRanges = &pcRange;
581 if (vkCreatePipelineLayout(device, &layoutInfo,
nullptr, &m_gbufferGeomLayout) != VK_SUCCESS) {
582 SLEAK_ERROR(
"PBR: Failed to create GBuffer geometry pipeline layout!");
586 m_pbrMaterialResourcesCreated =
true;
587 SLEAK_INFO(
"VulkanRenderer: PBR material resources created");
593 if (!bFrameStarted || !m_pbrMaterialResourcesCreated || !material)
return;
596 vkCmdBindPipeline(command, VK_PIPELINE_BIND_POINT_GRAPHICS, m_gbufferPipeline);
597 m_activeCustomFormat = 0;
601 uint32_t slot = m_pbrMaterialSlot[currentFrame];
602 if (slot >= PBR_SETS_PER_FRAME) slot = PBR_SETS_PER_FRAME - 1;
603 const uint32_t setIdx = currentFrame * PBR_SETS_PER_FRAME + slot;
604 const VkDeviceSize uboOffset = slot * m_pbrMaterialUBOStride;
607 PBRMaterialParams params{};
609 params.albedoFactorR = dc.GetR() / 255.0f;
610 params.albedoFactorG = dc.GetG() / 255.0f;
611 params.albedoFactorB = dc.GetB() / 255.0f;
612 params.albedoFactorA = material->
GetOpacity();
615 params.aoFactor = material->
GetAO();
618 params.emissiveR = ec.GetR() / 255.0f;
619 params.emissiveG = ec.GetG() / 255.0f;
620 params.emissiveB = ec.GetB() / 255.0f;
623 params.tilingX = tiling.GetX();
624 params.tilingY = tiling.GetY();
626 params.offsetX = offset.GetX();
627 params.offsetY = offset.GetY();
634 if (m_pbrMaterialCBMapped[currentFrame])
635 memcpy(
static_cast<char*
>(m_pbrMaterialCBMapped[currentFrame]) + uboOffset,
636 ¶ms,
sizeof(params));
639 auto resolveView = [&](
Texture* tex) -> VkImageView {
641 if (!vt && m_defaultTexture) vt = m_defaultTexture;
642 return vt ? vt->GetImageView() : VK_NULL_HANDLE;
644 auto resolveSampler = [&](
Texture* tex) -> VkSampler {
646 if (!vt && m_defaultTexture) vt = m_defaultTexture;
647 return vt ? vt->GetSampler() : VK_NULL_HANDLE;
659 std::array<VkDescriptorImageInfo, 6> imageInfos{};
660 for (uint32_t i = 0; i < 6; ++i) {
661 imageInfos[i].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
662 imageInfos[i].imageView = resolveView(textures[i]);
663 imageInfos[i].sampler = resolveSampler(textures[i]);
666 VkDescriptorBufferInfo bufInfo{};
667 bufInfo.buffer = m_pbrMaterialCBBuffers[currentFrame];
668 bufInfo.offset = uboOffset;
669 bufInfo.range =
sizeof(PBRMaterialParams);
671 std::array<VkWriteDescriptorSet, 7> writes{};
672 for (uint32_t i = 0; i < 6; ++i) {
673 writes[i].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
674 writes[i].dstSet = m_pbrMaterialSets[setIdx];
675 writes[i].dstBinding = i;
676 writes[i].dstArrayElement = 0;
677 writes[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
678 writes[i].descriptorCount = 1;
679 writes[i].pImageInfo = &imageInfos[i];
681 writes[6].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
682 writes[6].dstSet = m_pbrMaterialSets[setIdx];
683 writes[6].dstBinding = 6;
684 writes[6].dstArrayElement = 0;
685 writes[6].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
686 writes[6].descriptorCount = 1;
687 writes[6].pBufferInfo = &bufInfo;
689 vkUpdateDescriptorSets(device, 7, writes.data(), 0,
nullptr);
691 vkCmdBindDescriptorSets(command, VK_PIPELINE_BIND_POINT_GRAPHICS,
692 m_gbufferGeomLayout, 0, 1,
693 &m_pbrMaterialSets[setIdx], 0,
nullptr);
696 m_pbrMaterialSlot[currentFrame] = slot + 1;
#define SLEAK_RETURN_ERR(...)
Math::Color GetEmissiveColor() const
Texture * GetRoughnessTexture() const
Texture * GetMetallicTexture() const
bool HasNormalTexture() const
Texture * GetNormalTexture() const
Texture * GetDiffuseTexture() const
bool HasEmissiveTexture() const
bool HasAOTexture() const
Texture * GetEmissiveTexture() const
bool HasRoughnessTexture() const
Math::Vector2D GetTiling() const
Math::Color GetDiffuseColor() const
Math::Vector2D GetOffset() const
Texture * GetAOTexture() const
float GetNormalIntensity() const
float GetRoughness() const
float GetMetallic() const
float GetEmissiveIntensity() const
bool HasMetallicTexture() const
VMA-backed Vulkan buffer with staging uploads, batched copies, and a size-bucketed recycling pool.
void * GetData() override
virtual bool CreateImGUI() override
Initializes ImGui and its Vulkan backend against the active render pass.
virtual void BindPBRMaterial(Sleak::Material *material) override
Writes a material's textures and params into its ring slot and binds it at set 0.
virtual void BindBoneBuffer(RefPtr< BufferBase > buffer) override
Copies bone matrices into the current frame's UBO and binds its descriptor set.
Vulkan 2D texture: image + view + sampler, with per-swapchain-image descriptor sets.
Backend-facing rendering layer shared by the four graphics backends.
Root namespace for everything the engine exposes.
static constexpr int MAX_BONES