@@ -601,6 +601,39 @@ namespace Renderer
601601 _device->TransitionImageLayout (commandBuffer, image, range.aspectMask , VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL , VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL , 1 , 1 );
602602 }
603603
604+ namespace
605+ {
606+ const char * DescriptorSetSlotToString (u32 slot)
607+ {
608+ switch (slot)
609+ {
610+ case DescriptorSetSlot::DEBUG : return " DEBUG" ;
611+ case DescriptorSetSlot::GLOBAL : return " GLOBAL" ;
612+ case DescriptorSetSlot::LIGHT : return " LIGHT" ;
613+ case DescriptorSetSlot::TERRAIN : return " TERRAIN" ;
614+ case DescriptorSetSlot::MODEL : return " MODEL" ;
615+ case DescriptorSetSlot::PER_PASS : return " PER_PASS" ;
616+ case DescriptorSetSlot::PER_DRAW : return " PER_DRAW" ;
617+ default : return " UNKNOWN" ;
618+ }
619+ }
620+ }
621+
622+ void RendererVK::ValidateBoundDescriptorSets (CommandListID commandListID, const char * opName)
623+ {
624+ u8 mask = _commandListHandler->GetUnboundDescriptorSets (commandListID);
625+ if (mask == 0 )
626+ return ;
627+
628+ for (u32 slot = 0 ; slot < 8 ; slot++)
629+ {
630+ if ((mask & (1u << slot)) == 0 )
631+ continue ;
632+
633+ NC_LOG_CRITICAL (" {} called with descriptor set slot {} ({}) statically used by the bound pipeline but never bound on this command list" , opName, slot, DescriptorSetSlotToString (slot));
634+ }
635+ }
636+
604637 void RendererVK::Draw (CommandListID commandListID, u32 numVertices, u32 numInstances, u32 vertexOffset, u32 instanceOffset)
605638 {
606639 VkCommandBuffer commandBuffer = _commandListHandler->GetCommandBuffer (commandListID);
@@ -609,6 +642,7 @@ namespace Renderer
609642 {
610643 NC_LOG_CRITICAL (" You tried to draw without first calling BeginPipeline!" );
611644 }
645+ ValidateBoundDescriptorSets (commandListID, " vkCmdDraw" );
612646
613647 vkCmdDraw (commandBuffer, numVertices, numInstances, vertexOffset, instanceOffset);
614648 }
@@ -621,6 +655,7 @@ namespace Renderer
621655 {
622656 NC_LOG_CRITICAL (" You tried to draw without first calling BeginPipeline!" );
623657 }
658+ ValidateBoundDescriptorSets (commandListID, " vkCmdDrawIndirect" );
624659
625660 VkBuffer vkArgumentBuffer = _bufferHandler->GetBuffer (argumentBuffer);
626661
@@ -635,6 +670,7 @@ namespace Renderer
635670 {
636671 NC_LOG_CRITICAL (" You tried to draw without first calling BeginPipeline!" );
637672 }
673+ ValidateBoundDescriptorSets (commandListID, " vkCmdDrawIndirectCount" );
638674
639675 VkBuffer vkArgumentBuffer = _bufferHandler->GetBuffer (argumentBuffer);
640676 VkBuffer vkDrawCountBuffer = _bufferHandler->GetBuffer (drawCountBuffer);
@@ -650,6 +686,7 @@ namespace Renderer
650686 {
651687 NC_LOG_CRITICAL (" You tried to draw without first calling BeginPipeline!" );
652688 }
689+ ValidateBoundDescriptorSets (commandListID, " vkCmdDrawIndexed" );
653690
654691 vkCmdDrawIndexed (commandBuffer, numIndices, numInstances, indexOffset, vertexOffset, instanceOffset);
655692 }
@@ -662,6 +699,7 @@ namespace Renderer
662699 {
663700 NC_LOG_CRITICAL (" You tried to draw without first calling BeginPipeline!" );
664701 }
702+ ValidateBoundDescriptorSets (commandListID, " vkCmdDrawIndexedIndirect" );
665703
666704 VkBuffer vkArgumentBuffer = _bufferHandler->GetBuffer (argumentBuffer);
667705
@@ -676,6 +714,7 @@ namespace Renderer
676714 {
677715 NC_LOG_CRITICAL (" You tried to draw without first calling BeginPipeline!" );
678716 }
717+ ValidateBoundDescriptorSets (commandListID, " vkCmdDrawIndexedIndirectCount" );
679718
680719 VkBuffer vkArgumentBuffer = _bufferHandler->GetBuffer (argumentBuffer);
681720 VkBuffer vkDrawCountBuffer = _bufferHandler->GetBuffer (drawCountBuffer);
@@ -687,6 +726,8 @@ namespace Renderer
687726 {
688727 VkCommandBuffer commandBuffer = _commandListHandler->GetCommandBuffer (commandListID);
689728
729+ ValidateBoundDescriptorSets (commandListID, " vkCmdDispatch" );
730+
690731 vkCmdDispatch (commandBuffer, threadGroupCountX, threadGroupCountY, threadGroupCountZ);
691732 }
692733
@@ -695,6 +736,8 @@ namespace Renderer
695736 VkCommandBuffer commandBuffer = _commandListHandler->GetCommandBuffer (commandListID);
696737 VkBuffer vkArgumentBuffer = _bufferHandler->GetBuffer (argumentBuffer);
697738
739+ ValidateBoundDescriptorSets (commandListID, " vkCmdDispatchIndirect" );
740+
698741 vkCmdDispatchIndirect (commandBuffer, vkArgumentBuffer, argumentBufferOffset);
699742 }
700743
@@ -1174,6 +1217,7 @@ namespace Renderer
11741217 vkCmdBindPipeline (commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS , pipeline);
11751218
11761219 _commandListHandler->SetBoundGraphicsPipeline (commandListID, pipelineID);
1220+ _commandListHandler->SetUnboundDescriptorSets (commandListID, _pipelineHandler->GetUsedDescriptorSetMask (pipelineID));
11771221 }
11781222
11791223 void RendererVK::EndPipeline (CommandListID commandListID, GraphicsPipelineID pipelineID)
@@ -1194,6 +1238,7 @@ namespace Renderer
11941238
11951239 VkCommandBuffer commandBuffer = _commandListHandler->GetCommandBuffer (commandListID);
11961240 _commandListHandler->SetBoundGraphicsPipeline (commandListID, GraphicsPipelineID::Invalid ());
1241+ _commandListHandler->SetUnboundDescriptorSets (commandListID, 0 );
11971242 }
11981243
11991244 void RendererVK::BeginPipeline (CommandListID commandListID, ComputePipelineID pipelineID)
@@ -1217,6 +1262,7 @@ namespace Renderer
12171262 vkCmdBindPipeline (commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE , pipeline);
12181263
12191264 _commandListHandler->SetBoundComputePipeline (commandListID, pipelineID);
1265+ _commandListHandler->SetUnboundDescriptorSets (commandListID, _pipelineHandler->GetUsedDescriptorSetMask (pipelineID));
12201266 }
12211267
12221268 void RendererVK::EndPipeline (CommandListID commandListID, ComputePipelineID pipelineID)
@@ -1236,6 +1282,7 @@ namespace Renderer
12361282 vkCmdBindPipeline (commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE , pipeline);
12371283
12381284 _commandListHandler->SetBoundComputePipeline (commandListID, ComputePipelineID::Invalid ());
1285+ _commandListHandler->SetUnboundDescriptorSets (commandListID, 0 );
12391286 }
12401287
12411288 void RendererVK::BeginTimeQuery (CommandListID commandListID, TimeQueryID timeQueryID)
@@ -1420,6 +1467,11 @@ namespace Renderer
14201467
14211468 // Bind descriptor set
14221469 vkCmdBindDescriptorSets (commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS , pipelineLayout, slot, 1 , &vkDescriptorSet, 0 , nullptr );
1470+
1471+ // Clear this slot from the "still required to be bound" mask
1472+ u8 mask = _commandListHandler->GetUnboundDescriptorSets (commandListID);
1473+ mask &= ~static_cast <u8 >(1u << slot);
1474+ _commandListHandler->SetUnboundDescriptorSets (commandListID, mask);
14231475 }
14241476 else if (computePipelineID != ComputePipelineID::Invalid ())
14251477 {
@@ -1438,6 +1490,11 @@ namespace Renderer
14381490
14391491 // Bind descriptor set
14401492 vkCmdBindDescriptorSets (commandBuffer, VK_PIPELINE_BIND_POINT_COMPUTE , pipelineLayout, slot, 1 , &vkDescriptorSet, 0 , nullptr );
1493+
1494+ // Clear this slot from the "still required to be bound" mask
1495+ u8 mask = _commandListHandler->GetUnboundDescriptorSets (commandListID);
1496+ mask &= ~static_cast <u8 >(1u << slot);
1497+ _commandListHandler->SetUnboundDescriptorSets (commandListID, mask);
14411498 }
14421499 }
14431500
0 commit comments