24#include <glm/gtc/matrix_transform.hpp>
26#include <BS_tracy_thread_pool.hpp>
38#include <vulkan/vulkan_core.h>
54 #define COMPUTE_SHADER_NAME(name) "Output/Placeholder.comp.spv"
55 #define COMPUTE_GUARD() return;
56 #define GRAPHICS_GUARD() return;
57#elif defined(COMPUTE_DEBUG)
58 #define COMPUTE_SHADER_NAME(name) name
59 #define COMPUTE_GUARD()
60 #define GRAPHICS_GUARD() return;
62 #define COMPUTE_SHADER_NAME(name) name
63 #define COMPUTE_GUARD()
64 #define GRAPHICS_GUARD()
79 renderingDataManager = std::make_unique<RenderingDataManager>(engine, context);
83 initializeFrameIndices();
88 createDispatchBuffer();
89 createPlaceholderBuffer();
90 createPlaceholderUniformBuffer();
91 createCounterBuffer();
92 createObjectIDsBuffer();
93 createObjectCullingDataBuffer();
94 createObjectMeshletDataBuffer();
95 createMeshUnpackingDataBuffer();
98 createPrimitiveCullingResources();
99 createBinningAllocatorResources();
100 createMeshletUnpackingResources();
101 createMeshletCullingResources();
102 createPrepareDrawResources();
107 createMeshletUnpackingDispatcherResources();
108 createMeshletCullingDispatcherResources();
111 createHiZGenerationResources();
112 createHiZSPDResources();
120 VkCommandPoolCreateInfo commandPoolCreateInfo{
121 .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
123 .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
124 .queueFamilyIndex = context->getVkGraphicsQueueFamilyIndex()
126 PLOG_THROW_FN_VK( vkCreateCommandPool(
127 context->getVkDevice(), &commandPoolCreateInfo,
nullptr, &vkGraphicsCommandPool
134 VkCommandPoolCreateInfo commandPoolCreateInfo{
135 .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
137 .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
138 .queueFamilyIndex = context->getVkTransferQueueFamilyIndex()
140 PLOG_THROW_FN_VK( vkCreateCommandPool(
141 context->getVkDevice(), &commandPoolCreateInfo,
nullptr, &vkTransferCommandPool
148 std::array<VkDescriptorPoolSize, 3u> descriptorPoolSizes{};
150 descriptorPoolSizes.at( 0 ) = {
151 .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
156 descriptorPoolSizes.at( 1 ) = { .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
159 descriptorPoolSizes.at( 2 ) = {
160 .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
169 VkDescriptorPoolCreateInfo descriptorPoolCreateInfo{
170 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
175 .poolSizeCount =
static_cast<uint32_t
>( descriptorPoolSizes.size() ),
176 .pPoolSizes = descriptorPoolSizes.data()
180 context->getVkDevice(), &descriptorPoolCreateInfo,
nullptr, &descriptorPool,
"Main"
193 renderFinishedSemaphores.resize( headset->getSwapchainRenderTargets().size() );
194 for (
auto & sem : renderFinishedSemaphores )
196 VkSemaphoreCreateInfo semInfo{ VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO };
197 vkCreateSemaphore( context->getVkDevice(), &semInfo,
nullptr, &sem );
218#if !defined(HEADLESS) && !defined(COMPUTE_DEBUG)
219 #define MESH_STAGE VK_SHADER_STAGE_MESH_BIT_EXT
220 #define VERTEX_STAGE VK_SHADER_STAGE_VERTEX_BIT
222 #define MESH_STAGE VK_SHADER_STAGE_VERTEX_BIT
223 #define VERTEX_STAGE VK_SHADER_STAGE_VERTEX_BIT
227 constexpr VkShaderStageFlags MESH_AND_VERTEX_STAGE =
MESH_STAGE | VK_SHADER_STAGE_VERTEX_BIT;
258 VkDescriptorSetLayoutBindingFlagsCreateInfo bindingFlagsInfo{
259 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO,
260 .bindingCount =
static_cast<uint32_t
>( builder.getFlags().size() ),
261 .pBindingFlags = builder.getFlags().data()
265 VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo{
266 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
267 .pNext = &bindingFlagsInfo,
269 .bindingCount =
static_cast<uint32_t
>( builder.getBindings().size() ),
270 .pBindings = builder.getBindings().data()
274 &descriptorSetLayoutCreateInfo,
284#if !defined(HEADLESS) && !defined(COMPUTE_DEBUG)
286 VkPushConstantRange pushConstantRange{ .stageFlags = VK_SHADER_STAGE_MESH_BIT_EXT |
287 VK_SHADER_STAGE_FRAGMENT_BIT,
297 VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{
298 .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
299 .setLayoutCount = 1u,
301#if !defined(HEADLESS) && !defined(COMPUTE_DEBUG)
302 .pushConstantRangeCount =
static_cast<uint32_t
>(
pushConstants.size() ),
305 .pushConstantRangeCount = 0,
306 .pPushConstantRanges =
nullptr
311 &pipelineLayoutCreateInfo,
327 PLOGI <<
"RenderingDataManager buffer creation complete:";
328 PLOGI <<
" Vertex buffer: "
330 PLOGI <<
" Meshlet buffer: "
332 PLOGI <<
" Triangle buffer: "
334 PLOGI <<
" Primitive render data buffer: "
342 for ( uint32_t eyeIndex = 0u; eyeIndex <
renderProcesses.size(); eyeIndex++ )
346 PLOGI <<
"Creating RenderProcess " << eyeIndex;
349 context->getUniformBufferOffsetAlignment(),
369 VkVertexInputBindingDescription vertexInputBindingDescription{
370 .binding = 0u, .stride =
sizeof(
Vertex ), .inputRate = VK_VERTEX_INPUT_RATE_VERTEX
373 VkVertexInputAttributeDescription vertexInputAttributePosition{
376 .format = VK_FORMAT_R32G32B32_SFLOAT,
377 .offset = offsetof(
Vertex, position )
380 VkVertexInputAttributeDescription vertexInputAttributeNormal{
383 .format = VK_FORMAT_R32G32B32_SFLOAT,
384 .offset = offsetof(
Vertex, normal ),
387 VkVertexInputAttributeDescription vertexInputAttributeTextureCoordinate{
390 .format = VK_FORMAT_R32G32_SFLOAT,
391 .offset = offsetof(
Vertex, textureCoordinate )
399 const std::vector<PipelineNames> pipelinesToCreate = {
414 VkExtent2D eyeResolution =
headset->getEyeResolution(0);
416 static_cast<float>(eyeResolution.width),
417 static_cast<float>(eyeResolution.height)
419 PLOGI <<
"Mesh shader screen resolution: " << eyeResolution.width <<
"x" << eyeResolution.height;
428#if !defined(HEADLESS) && !defined(COMPUTE_DEBUG)
431 context->getMultisampleCount(),
437 { vertexInputAttributePosition,
438 vertexInputAttributeNormal,
439 vertexInputAttributeTextureCoordinate },
446 context->getMultisampleCount(),
471 VkExtent2D eyeResolution =
headset->getEyeResolution(0);
473 static_cast<float>(eyeResolution.width),
474 static_cast<float>(eyeResolution.height)
478 const std::vector<PipelineNames> pipelinesToCreate = {
494#if !defined(HEADLESS) && !defined(COMPUTE_DEBUG)
497 context->getMultisampleCount(),
501 depthOnlyFragPath.string(),
535 VkCommandBuffer commandBuffer =
renderProcesses[i]->getGraphicsCommandBuffer();
537 TracyVkCtx tracyContext = TracyVkContext(
538 context->getVkPhysicalDevice(),
544 std::stringstream contextNameStream{};
545 contextNameStream <<
"Vulkan Context " << i;
546 std::string contextName = contextNameStream.str();
548 TracyVkContextName( tracyContext, contextName.c_str(), contextName.size() );
550 tracyVkContext.push_back( tracyContext );
560 PLOGI <<
"Populating staging buffers with initial data for all frames";
564 PLOGD <<
"Engine is null, skipping GPU buffer initialization (test mode)";
572 renderProcess->updateSSBO(
this );
573 renderProcess->updateMeshletDataBuffer();
574 renderProcess->updateMeshRenderingData();
576 renderProcess->uploadSSBOStagingBuffer();
577 renderProcess->uploadMeshRenderingStagingData();
585 std::vector<VkBufferMemoryBarrier2> barriers{};
588 VkCommandBuffer transferCommandBuffer =
renderProcesses[frameIndex]->getTransferCommandBuffer();
593 PLOG_RETURN_FN_VK( vkResetCommandBuffer( transferCommandBuffer, 0u ) )
595 VkCommandBufferBeginInfo commandBufferBeginInfo{ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
596 PLOG_RETURN_FN_VK( vkBeginCommandBuffer( transferCommandBuffer, &commandBufferBeginInfo ) )
606 VkBufferCopy copyRegion{};
607 copyRegion.srcOffset = copyObject.copyObject.srcOffset;
608 copyRegion.dstOffset = copyObject.copyObject.dstOffset;
609 copyRegion.size = copyObject.copyObject.size;
610 if (copyObject.copyObject.size == 0)
612 PLOGW <<
"Trying to copy copy object of size 0. Skipping copy command";
616 transferCommandBuffer,
617 copyObject.copyObject.sourceBuffer,
618 copyObject.copyObject.destinationBuffer,
625 VkMemoryBarrier2 copyBarrier{ .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER_2,
626 .srcStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT,
627 .srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT,
628 .dstStageMask = VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT,
629 .dstAccessMask = VK_ACCESS_2_NONE };
631 VkDependencyInfo copyDep{
632 .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
633 .memoryBarrierCount = 1,
634 .pMemoryBarriers = ©Barrier,
636 vkCmdPipelineBarrier2( transferCommandBuffer, ©Dep );
641 std::vector<VkBufferMemoryBarrier2> releaseBarriers;
644 VkBufferMemoryBarrier2 rel = {
645 .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2,
646 .srcStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT,
647 .srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT,
648 .dstStageMask = VK_PIPELINE_STAGE_2_NONE,
649 .dstAccessMask = VK_ACCESS_2_NONE,
650 .srcQueueFamilyIndex =
context->getVkTransferQueueFamilyIndex(),
651 .dstQueueFamilyIndex =
context->getVkGraphicsQueueFamilyIndex(),
652 .buffer = obj.copyObject.destinationBuffer,
654 .size = VK_WHOLE_SIZE,
656 releaseBarriers.push_back( rel );
658 if ( !releaseBarriers.empty() )
660 VkDependencyInfo dep{
661 .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
662 .bufferMemoryBarrierCount =
static_cast<uint32_t
>( releaseBarriers.size() ),
663 .pBufferMemoryBarriers = releaseBarriers.data(),
665 vkCmdPipelineBarrier2( transferCommandBuffer, &dep );
668 if ( !barriers.empty() )
670 VkDependencyInfo dependencyInfo{
671 .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
672 .bufferMemoryBarrierCount =
static_cast<uint32_t
>( barriers.size() ),
673 .pBufferMemoryBarriers = barriers.data(),
675 vkCmdPipelineBarrier2( transferCommandBuffer, &dependencyInfo );
680 VkMemoryBarrier2 memoryBarrier{ .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER_2,
681 .srcStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT,
682 .srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT,
683 .dstStageMask = VK_PIPELINE_STAGE_2_NONE,
684 .dstAccessMask = 0 };
686 VkDependencyInfo dependencyInfo{
687 .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
688 .memoryBarrierCount = 1,
689 .pMemoryBarriers = &memoryBarrier,
691 vkCmdPipelineBarrier2( transferCommandBuffer, &dependencyInfo );
694 vkEndCommandBuffer( transferCommandBuffer );
716 PLOGI <<
"Culling freeze " << ( freeze ?
"enabled" :
"disabled" );
735 PLOG_RETURN_FN_VK( vkResetCommandBuffer( transferCommandBuffer, 0u ) )
737 constexpr VkCommandBufferBeginInfo commandBufferBeginInfo{
738 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO
740 PLOG_RETURN_FN_VK( vkBeginCommandBuffer( transferCommandBuffer, &commandBufferBeginInfo ) )
752 VkBufferCopy copyRegion{};
753 copyRegion.srcOffset = copyObject.copyObject.srcOffset;
754 copyRegion.dstOffset = copyObject.copyObject.dstOffset;
755 copyRegion.size = copyObject.copyObject.size;
756 if (copyRegion.size == 0)
758 PLOGW <<
"Trying to upload a copy buffer with size 0. Skipping copy command";
762 transferCommandBuffer,
763 copyObject.copyObject.sourceBuffer,
764 copyObject.copyObject.destinationBuffer,
773 VkMemoryBarrier2 copyBarrier{ .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER_2,
774 .srcStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT,
775 .srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT,
776 .dstStageMask = VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT,
777 .dstAccessMask = VK_ACCESS_2_NONE };
779 VkDependencyInfo copyDep{
780 .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
781 .memoryBarrierCount = 1,
782 .pMemoryBarriers = ©Barrier,
784 vkCmdPipelineBarrier2( transferCommandBuffer, ©Dep );
788 std::vector<VkBufferMemoryBarrier2> releaseBarriers;
792 VkBufferMemoryBarrier2 rel = {
793 .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2,
794 .srcStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT,
795 .srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT,
796 .dstStageMask = VK_PIPELINE_STAGE_2_NONE,
797 .dstAccessMask = VK_ACCESS_2_NONE,
798 .srcQueueFamilyIndex =
context->getVkTransferQueueFamilyIndex(),
799 .dstQueueFamilyIndex =
context->getVkGraphicsQueueFamilyIndex(),
800 .buffer = obj.copyObject.destinationBuffer,
802 .size = VK_WHOLE_SIZE,
804 releaseBarriers.push_back( rel );
807 VkDependencyInfo releaseDep{
808 .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
809 .bufferMemoryBarrierCount =
static_cast<uint32_t
>( releaseBarriers.size() ),
810 .pBufferMemoryBarriers = releaseBarriers.data(),
812 vkCmdPipelineBarrier2( transferCommandBuffer, &releaseDep );
826 PLOGI <<
"Recording texture transfer command for texture: " << texture->getDescriptorIndex();
827 texture->createDataUploadCommand( transferCommandBuffer,
this );
837 renderProcessPtr->addTexturesToUpload( { texture }, texture->getDescriptorIndex() );
846 PLOG_RETURN_FN_VK( vkEndCommandBuffer( transferCommandBuffer ) )
851 PLOGV <<
"Swap chain image index: " << swapChainImageIndex <<
" currentFrame: " <<
currentFrame;
857 std::vector<VkBufferMemoryBarrier2> acquireBarriers{};
858 std::vector<BufferCopyObject> copyObjects{};
860 for (
const auto & [releaseBarrier, acquireBarrier, copyObject] :
syncCopyObjects )
862 acquireBarriers.push_back( acquireBarrier );
863 copyObjects.push_back( copyObject );
871 if ( !acquireBarriers.empty() )
873 VkDependencyInfo acquireDependency{
874 .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
875 .bufferMemoryBarrierCount =
static_cast<uint32_t
>( acquireBarriers.size() ),
876 .pBufferMemoryBarriers = acquireBarriers.data(),
893 "Texture Layout Transitions",
899 VkImageMemoryBarrier2 imageBarrier{ .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
901 .srcStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT,
902 .srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT,
903 .dstStageMask = VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT,
904 .dstAccessMask = VK_ACCESS_2_SHADER_READ_BIT,
905 .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
906 .newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
907 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
908 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
909 .image = texture->getVkImage(),
910 .subresourceRange = { .aspectMask =
911 VK_IMAGE_ASPECT_COLOR_BIT,
917 VkDependencyInfo depInfo{
918 .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
920 .imageMemoryBarrierCount = 1u,
921 .pImageMemoryBarriers = &imageBarrier,
999 VkMemoryBarrier2 fillBarrier{
1000 .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER_2,
1001 .srcStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT,
1002 .srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT,
1003 .dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
1004 .dstAccessMask = VK_ACCESS_2_SHADER_READ_BIT | VK_ACCESS_2_SHADER_WRITE_BIT
1006 VkDependencyInfo fillDep{
1007 .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
1008 .memoryBarrierCount = 1,
1009 .pMemoryBarriers = &fillBarrier
1026 const uint32_t eyeIndex = currentRenderProcess->
getEyeIndex();
1027 const glm::mat4 viewMatrix =
headset->getEyeViewMatrix(eyeIndex);
1028 const glm::mat4 projMatrix =
headset->getEyeProjectionMatrix(eyeIndex);
1029 const VkExtent2D resolution =
headset->getEyeResolution(eyeIndex);
1032 const glm::mat4 invView = glm::inverse(viewMatrix);
1033 const glm::vec3 cameraPosition = glm::vec3(invView[3]);
1036 constexpr float nearPlane = 0.01f;
1043 static_cast<float>(resolution.width),
1044 static_cast<float>(resolution.height),
1053 VS_LOG_ONCE(
LogLOD,
Warning,
"[DIAG] LOD Config: cameraPos=({:.2f},{:.2f},{:.2f}) proj11={:.4f} nearPlane={} screenSize={}x{} errorThreshold=1.0",
1054 cameraPosition.x, cameraPosition.y, cameraPosition.z,
1055 projMatrix[1][1], nearPlane, resolution.width, resolution.height);
1066 struct CullingPushConstants {
1067 uint32_t primitiveCount;
1068 uint32_t cullingPass;
1069 } pushData = { primitiveCount, 0 };
1073 PLOGI <<
"Starting Pass 1 culling with " << primitiveCount <<
" primitives";
1076 if ( primitiveCount > 0 )
1082 PLOGI <<
"Barrier: Primitive Culling -> Binning Allocator";
1095 const uint32_t maxBinningWorkItems = primitiveCount + clusterCount;
1098 static uint32_t lodDiagFrameCounter = 0;
1099 if (++lodDiagFrameCounter >= 60) {
1100 lodDiagFrameCounter = 0;
1101 VS_LOG(
LogLOD,
Warning,
"[DIAG] Renderer: primitiveCount={} clusterCount={} hasLodData={} clusterGroupCount={}",
1111 PLOGI <<
"Starting binning allocator with max " << primitiveCount <<
" primitives + " << clusterCount <<
" LOD clusters";
1112 if ( maxBinningWorkItems > 0 )
1118 PLOGI <<
"Barrier: Binning Allocator -> Meshlet Unpacking Dispatcher";
1121 VkMemoryBarrier2 binningBarrier{
1122 .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER_2,
1123 .srcStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
1124 .srcAccessMask = VK_ACCESS_2_SHADER_WRITE_BIT,
1125 .dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
1126 .dstAccessMask = VK_ACCESS_2_SHADER_READ_BIT
1128 VkDependencyInfo binningDep{
1129 .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
1130 .memoryBarrierCount = 1,
1131 .pMemoryBarriers = &binningBarrier
1136 PLOGI <<
"Meshlet Unpacking Dispatcher";
1143 PLOGI <<
"Barrier: Meshlet Unpacking Dispatcher -> Meshlet Unpacking";
1153 PLOGI <<
"Meshlet Unpacking (V2)";
1166 VkMemoryBarrier2 memBarrier{
1167 .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER_2,
1168 .srcStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
1169 .srcAccessMask = VK_ACCESS_2_SHADER_WRITE_BIT,
1170 .dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
1171 .dstAccessMask = VK_ACCESS_2_SHADER_READ_BIT
1173 VkDependencyInfo depInfo{
1174 .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
1175 .memoryBarrierCount = 1,
1176 .pMemoryBarriers = &memBarrier
1194 const uint32_t objectCount =
engine->getRenderableSceneObjectCount();
1195 PLOGI <<
"[COMPUTE_DEBUG] Compute pipeline completed for " << objectCount <<
" objects";
1196 PLOGI <<
"[COMPUTE_DEBUG] To read back buffer values, wait for GPU completion and use ComputeDebug::readbackBuffer()";
1201#if !defined(HEADLESS) && !defined(COMPUTE_DEBUG)
1207 "Compute-Graphics Barriers",
1211 VkBufferMemoryBarrier2 visibleBarrier{ VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2 };
1212 visibleBarrier.srcStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT;
1213 visibleBarrier.srcAccessMask = VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT;
1214 visibleBarrier.dstStageMask = VK_PIPELINE_STAGE_2_MESH_SHADER_BIT_EXT;
1215 visibleBarrier.dstAccessMask = VK_ACCESS_2_SHADER_STORAGE_READ_BIT;
1216 visibleBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
1217 visibleBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
1218 visibleBarrier.buffer =
1220 visibleBarrier.offset = 0;
1221 visibleBarrier.size = VK_WHOLE_SIZE;
1224 VkBufferMemoryBarrier2 indirectBarrier{ VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2 };
1225 indirectBarrier.srcStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT;
1226 indirectBarrier.srcAccessMask = VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT;
1227 indirectBarrier.dstStageMask = VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT;
1228 indirectBarrier.dstAccessMask = VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT;
1229 indirectBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
1230 indirectBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
1232 indirectBarrier.offset = 0;
1233 indirectBarrier.size = VK_WHOLE_SIZE;
1236 VkBufferMemoryBarrier2 vsIndirectBarrier{ VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2 };
1237 vsIndirectBarrier.srcStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT;
1238 vsIndirectBarrier.srcAccessMask = VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT;
1239 vsIndirectBarrier.dstStageMask = VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT;
1240 vsIndirectBarrier.dstAccessMask = VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT;
1241 vsIndirectBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
1242 vsIndirectBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
1244 vsIndirectBarrier.offset = 0;
1245 vsIndirectBarrier.size = VK_WHOLE_SIZE;
1248 VkBufferMemoryBarrier2 vsCountBarrier{ VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2 };
1249 vsCountBarrier.srcStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT;
1250 vsCountBarrier.srcAccessMask = VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT;
1251 vsCountBarrier.dstStageMask = VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT;
1252 vsCountBarrier.dstAccessMask = VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT;
1253 vsCountBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
1254 vsCountBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
1256 vsCountBarrier.offset = 0;
1257 vsCountBarrier.size = VK_WHOLE_SIZE;
1260 VkBufferMemoryBarrier2 vsInstancedDrawBarrier{ VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2 };
1261 vsInstancedDrawBarrier.srcStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT;
1262 vsInstancedDrawBarrier.srcAccessMask = VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT;
1263 vsInstancedDrawBarrier.dstStageMask = VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT;
1264 vsInstancedDrawBarrier.dstAccessMask = VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT;
1265 vsInstancedDrawBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
1266 vsInstancedDrawBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
1268 vsInstancedDrawBarrier.offset = 0;
1269 vsInstancedDrawBarrier.size = VK_WHOLE_SIZE;
1272 VkBufferMemoryBarrier2 vsInstancedCountBarrier{ VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2 };
1273 vsInstancedCountBarrier.srcStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT;
1274 vsInstancedCountBarrier.srcAccessMask = VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT;
1275 vsInstancedCountBarrier.dstStageMask = VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT;
1276 vsInstancedCountBarrier.dstAccessMask = VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT;
1277 vsInstancedCountBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
1278 vsInstancedCountBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
1280 vsInstancedCountBarrier.offset = 0;
1281 vsInstancedCountBarrier.size = VK_WHOLE_SIZE;
1283 VkBufferMemoryBarrier2 barriers[] = { visibleBarrier, indirectBarrier, vsIndirectBarrier, vsCountBarrier, vsInstancedDrawBarrier, vsInstancedCountBarrier };
1285 VkDependencyInfo depInfo{ VK_STRUCTURE_TYPE_DEPENDENCY_INFO };
1286 depInfo.bufferMemoryBarrierCount = 6;
1287 depInfo.pBufferMemoryBarriers = barriers;
1437 PLOGI <<
"Submitting initial transfers for all frames in flight";
1453 PLOGI <<
"Submitting initial transfer for frame " << frameIndex <<
" signaling value "
1457 VkResult result = builder
1462 if (result != VK_SUCCESS)
1464 PLOGE <<
"Failed to submit initial transfer for frame " << frameIndex;
1488 PLOGI <<
"All initial transfers submitted.";
1526 VK_PIPELINE_STAGE_2_TRANSFER_BIT
1533 VkResult result = builder
1538 if (result != VK_SUCCESS)
1558 if ( binarySemaphore == VK_NULL_HANDLE )
1560 PLOGE <<
"Invalid render finished semaphore";
1568#if !defined(HEADLESS) && !defined(COMPUTE_DEBUG)
1571 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_2_TASK_SHADER_BIT_EXT |
1572 VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_2_TRANSFER_BIT
1580 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT
1586 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT |
1587 VK_PIPELINE_STAGE_2_TRANSFER_BIT
1592 if ( mirrorAcquireSemaphore != VK_NULL_HANDLE )
1594 builder.
waitForBinary(mirrorAcquireSemaphore, VK_PIPELINE_STAGE_2_TRANSFER_BIT);
1606 if ( mirrorAcquireSemaphore != VK_NULL_HANDLE )
1613 if (result != VK_SUCCESS)
1648 std::vector<VkCommandBuffer> commandBuffers;
1651 commandBuffers.push_back( renderProcess->getGraphicsCommandBuffer() );
1653 return commandBuffers;
1670 destroyTracyContexts();
1777 vkDestroySemaphore(
context->getVkDevice(), sem,
nullptr );
1795 VkCommandBuffer initialImageTransition =
1798 std::vector<VkImageMemoryBarrier2> swapchainImageBarriers;
1800 for (
const auto & renderTarget :
headset->getSwapchainRenderTargets() )
1802 VkImageMemoryBarrier2 swapchainImageMemoryBarrier{
1803 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
1804 .srcStageMask = VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT,
1806 .dstStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT,
1807 .dstAccessMask = VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT,
1808 .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
1809 .newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
1810 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
1811 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
1812 .image = renderTarget.image,
1813 .subresourceRange{ .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
1816 .baseArrayLayer = 0u,
1817 .layerCount =
headset->getEyeCount() }
1819 swapchainImageBarriers.push_back( swapchainImageMemoryBarrier );
1822 VkDependencyInfo dependencyInfo{
1823 .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
1824 .dependencyFlags = 0,
1825 .imageMemoryBarrierCount =
static_cast<uint32_t
>( swapchainImageBarriers.size() ),
1826 .pImageMemoryBarriers = swapchainImageBarriers.data(),
1829 vkCmdPipelineBarrier2( initialImageTransition, &dependencyInfo );
1834 initialImageTransition
1858 uint64_t minFrameForValidSignal = (currentValue + stageCount - 1) / stageCount;
1862 PLOGI <<
"Timeline sync after pause: advancing frame counter from "
1864 <<
" (timeline at " << currentValue <<
")";
1874 PLOGI <<
"Timeline sync after pause: no adjustment needed (frame "
1894 auto now = std::chrono::steady_clock::now();
1895 auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now -
lastFrameStartTime_);
1896 PLOGI <<
"[FRAME_TIME] Frame start - elapsed since last frame: " << elapsed.count() <<
"ms";
1902 PLOGI <<
"[FRAME_TIME] Stall detected (" << elapsed.count() <<
"ms > "
1910 vkDeviceWaitIdle(
context->getVkDevice());
1911 PLOGI <<
"[FRAME_TIME] GPU sync completed after stall";
1925 auto now = std::chrono::steady_clock::now();
1926 return std::chrono::duration_cast<std::chrono::milliseconds>(now -
lastFrameStartTime_).count();
1951 void Renderer::destroyTracyContexts()
1955 PLOGI <<
"Cleaning up " << tracyVkContext.size() <<
" Tracy Vulkan contexts";
1957 for ( TracyVkCtx ctx : tracyVkContext )
1959 if ( ctx ==
nullptr )
1964 PLOGI <<
"Destroying Tracy context: " <<
static_cast<void *
>( ctx );
1965 TracyVkDestroy( ctx );
1966 PLOGI <<
"Tracy context destroyed";
1969 tracyVkContext.clear();
1970 PLOGI <<
"Tracy contexts cleanup complete";
1973 void Renderer::setupTracy(
const std::vector<TracyVkCtx> & tracyVulkanContext )
1975 if ( !tracyVkContext.empty() )
1977 destroyTracyContexts();
1979 tracyVkContext = tracyVulkanContext;
1982 void Renderer::resetTracyContexts()
1985 PLOGI <<
"Resetting Tracy Vulkan contexts for state transition";
1988 destroyTracyContexts();
1993 VkCommandBuffer commandBuffer =
renderProcesses[i]->getGraphicsCommandBuffer();
1995 TracyVkCtx tracyContext = TracyVkContext(
1996 context->getVkPhysicalDevice(),
2002 std::stringstream contextNameStream{};
2003 contextNameStream <<
"Vulkan Context " << i;
2004 std::string contextName = contextNameStream.str();
2006 TracyVkContextName( tracyContext, contextName.c_str(), contextName.size() );
2008 tracyVkContext.push_back( tracyContext );
2011 PLOGI <<
"Tracy contexts reset complete, created " << tracyVkContext.size() <<
" contexts";
2017 const std::string & meshShader,
2018 const std::string & fragShader,
2022 PLOGI <<
"Trying to find existing pipeline for mesh shader: " << meshShader
2023 <<
" frag shader: " << fragShader;
2029 PLOGI <<
"Found existing pipeline at " << i <<
"!";
2030 return static_cast<int>( i );
2033 PLOGI <<
"No existing pipeline!";
2053 throw std::runtime_error(
"No object for object unpacking compute pass found!" );
2060 throw std::runtime_error(
"No object for meshlet unpacking compute pass found!" );
2067 throw std::runtime_error(
"No object for meshlet culling compute pass found!" );
2074 throw std::runtime_error(
"No object for meshlet culling compute pass found!" );
2081 throw std::runtime_error(
"No object for draw preparation compute pass found!" );
2088 throw std::runtime_error(
"No VS binning allocator compute pass found!" );
2095 throw std::runtime_error(
"No VS instance unpacking compute pass found!" );
2102 throw std::runtime_error(
"No VS prepare draw compute pass found!" );
2109 std::vector<VkDescriptorSetLayoutBinding> computeLayoutBindings =
2111 #if !defined(HEADLESS)
2137 VkDescriptorSetLayoutCreateInfo computeLayoutCreateInfo = {
2138 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
2139 .bindingCount =
static_cast<uint32_t
>( computeLayoutBindings.size() ),
2140 .pBindings = computeLayoutBindings.data()
2144 VkPushConstantRange pushConstantRange{
2145 .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
2147 .size = 2 *
sizeof( uint32_t )
2150 VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {
2151 .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
2154 .setLayoutCount = 1u,
2155 .pSetLayouts =
nullptr,
2156 .pushConstantRangeCount = 1u,
2157 .pPushConstantRanges = &pushConstantRange,
2165 &pipelineLayoutCreateInfo,
2166 &computeLayoutCreateInfo,
2167 shaderPath.string(),
2170 delete specialization;
2177 std::vector<VkDescriptorSetLayoutBinding> computeLayoutBindings =
2179 #if !defined(HEADLESS)
2188 VkDescriptorSetLayoutCreateInfo computeLayoutCreateInfo = {
2189 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
2190 .bindingCount =
static_cast<uint32_t
>( computeLayoutBindings.size() ),
2191 .pBindings = computeLayoutBindings.data()
2194 VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {
2195 .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
2198 .setLayoutCount = 1u,
2199 .pSetLayouts =
nullptr,
2200 .pushConstantRangeCount = 0,
2201 .pPushConstantRanges =
nullptr,
2209 &pipelineLayoutCreateInfo,
2210 &computeLayoutCreateInfo,
2211 shaderPath.string(),
2214 delete specialization;
2221 std::vector<VkDescriptorSetLayoutBinding> computeLayoutBindings =
2223 #if !defined(HEADLESS)
2230 VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{
2231 .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
2232 .setLayoutCount = 1u,
2233 .pSetLayouts =
nullptr,
2236 VkDescriptorSetLayoutCreateInfo computeLayoutCreateInfo{
2237 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
2238 .bindingCount =
static_cast<uint32_t
>( computeLayoutBindings.size() ),
2239 .pBindings = computeLayoutBindings.data(),
2247 &pipelineLayoutCreateInfo,
2248 &computeLayoutCreateInfo,
2249 shaderName.string(),
2252 delete specialization;
2259 std::vector<VkDescriptorSetLayoutBinding> computeLayoutBindings =
2261#if !defined(HEADLESS)
2267 VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{
2268 .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
2269 .setLayoutCount = 1u,
2270 .pSetLayouts =
nullptr,
2273 VkDescriptorSetLayoutCreateInfo computeLayoutCreateInfo{
2274 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
2275 .bindingCount =
static_cast<uint32_t
>( computeLayoutBindings.size() ),
2276 .pBindings = computeLayoutBindings.data(),
2284 &pipelineLayoutCreateInfo,
2285 &computeLayoutCreateInfo,
2286 shaderName.string(),
2289 delete specialization;
2295 std::vector<VkDescriptorSetLayoutBinding> computeLayoutBindings =
2297#if !defined(HEADLESS)
2306 VkDescriptorSetLayoutCreateInfo computeLayoutCreateInfo = {
2307 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
2308 .bindingCount =
static_cast<uint32_t
>( computeLayoutBindings.size() ),
2309 .pBindings = computeLayoutBindings.data()
2312 VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {
2313 .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
2316 .setLayoutCount = 1u,
2317 .pSetLayouts =
nullptr,
2318 .pushConstantRangeCount = 0,
2319 .pPushConstantRanges =
nullptr,
2328 &pipelineLayoutCreateInfo,
2329 &computeLayoutCreateInfo,
2330 shaderName.string(),
2333 delete specialization;
2339 VkDevice device =
context->getVkDevice();
2342 std::vector<VkDescriptorSetLayoutBinding> computeLayoutBindings =
2344#if !defined(HEADLESS)
2353 VkDescriptorSetLayoutCreateInfo computeSetLayoutInfo{
2354 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
2355 .bindingCount =
static_cast<uint32_t
>( computeLayoutBindings.size() ),
2356 .pBindings = computeLayoutBindings.data()
2360 VkPipelineLayoutCreateInfo computePipelineLayoutInfo{
2361 .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
2362 .setLayoutCount = 1,
2363 .pSetLayouts =
nullptr,
2364 .pushConstantRangeCount = 0,
2365 .pPushConstantRanges =
nullptr
2372 &computePipelineLayoutInfo,
2373 &computeSetLayoutInfo,
2377 delete specialization;
2384 std::vector<VkDescriptorSetLayoutBinding> prepareBindings =
2386 #if !defined(HEADLESS)
2392 VkDescriptorSetLayoutCreateInfo prepareLayoutInfo{
2393 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
2394 .bindingCount =
static_cast<uint32_t
>( prepareBindings.size() ),
2395 .pBindings = prepareBindings.data()
2398 VkPipelineLayoutCreateInfo pipelineLayoutInfo{ .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
2399 .setLayoutCount = 1,
2400 .pSetLayouts =
nullptr};
2407 &pipelineLayoutInfo,
2409 shaderName.string(),
2412 delete specialization;
2423 std::vector<VkDescriptorSetLayoutBinding> hiZBindings =
2425#if !defined(HEADLESS)
2432 VkDescriptorSetLayoutCreateInfo hiZLayoutInfo{
2433 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
2434 .bindingCount =
static_cast<uint32_t
>( hiZBindings.size() ),
2435 .pBindings = hiZBindings.data()
2439 VkPushConstantRange pushConstantRange{
2440 .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
2442 .size = 4 *
sizeof( uint32_t )
2445 VkPipelineLayoutCreateInfo pipelineLayoutInfo{
2446 .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
2447 .setLayoutCount = 1,
2448 .pSetLayouts =
nullptr,
2449 .pushConstantRangeCount = 1,
2450 .pPushConstantRanges = &pushConstantRange
2458 &pipelineLayoutInfo,
2460 shaderName.string(),
2463 delete specialization;
2465 PLOGI <<
"Hi-Z generation compute pass created";
2474 PLOGW <<
"Hi-Z generation compute pass not available, skipping descriptor set creation";
2479 const VkExtent2D eyeResolution =
headset->getEyeResolution(0);
2480 const uint32_t mipLevels =
static_cast<uint32_t
>(
2481 std::floor(std::log2(std::max(eyeResolution.width, eyeResolution.height)))) + 1;
2484 PLOGW <<
"Hi-Z pyramid has 0 mip levels, skipping descriptor set creation";
2489 std::array<VkDescriptorPoolSize, 2u> poolSizes{};
2491 .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
2495 .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
2499 VkDescriptorPoolCreateInfo poolInfo{
2500 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
2502 .poolSizeCount =
static_cast<uint32_t
>(poolSizes.size()),
2503 .pPoolSizes = poolSizes.data()
2514 for (uint32_t mip = 0; mip < mipLevels; mip++)
2516 VkDescriptorSetAllocateInfo allocInfo{
2517 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
2519 .descriptorSetCount = 1,
2520 .pSetLayouts = &layout
2523 VkResult result = vkAllocateDescriptorSets(
2526 if (result != VK_SUCCESS)
2528 PLOGE <<
"Failed to allocate Hi-Z descriptor set for frame " << frame <<
" mip " << mip;
2536 PLOGI <<
"Created Hi-Z mip descriptor sets: " << mipLevels <<
" mips x " <<
MAX_FRAMES_IN_FLIGHT <<
" frames";
2548 for (uint32_t mip = 0; mip < mipLevels; mip++)
2551 VkDescriptorImageInfo srcTextureInfo{};
2552 VkDescriptorImageInfo srcDepthMSInfo{};
2553 VkDescriptorImageInfo dstMipInfo{};
2561 .sampler =
headset->getHiZSampler(),
2563 .imageLayout = VK_IMAGE_LAYOUT_GENERAL
2570 .sampler =
headset->getHiZSampler(),
2572 .imageLayout = VK_IMAGE_LAYOUT_GENERAL
2578 .sampler =
headset->getHiZSampler(),
2579 .imageView =
headset->getDepthBufferView(),
2580 .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
2585 .sampler = VK_NULL_HANDLE,
2587 .imageLayout = VK_IMAGE_LAYOUT_GENERAL
2609 constexpr VkDeviceSize atomicBufferSize =
sizeof(uint32_t) * 6;
2612 VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
2613 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT
2623#if !defined(HEADLESS)
2631 VkDescriptorSetLayoutCreateInfo spdLayoutInfo{
2632 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
2633 .bindingCount =
static_cast<uint32_t
>(spdBindings.size()),
2634 .pBindings = spdBindings.data()
2638 VkPushConstantRange pushConstantRange{
2639 .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
2641 .size =
sizeof(uint32_t) * 2 +
sizeof(int32_t) * 2 +
sizeof(uint32_t)
2644 VkPipelineLayoutCreateInfo pipelineLayoutInfo{
2645 .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
2646 .setLayoutCount = 1,
2647 .pSetLayouts =
nullptr,
2648 .pushConstantRangeCount = 1,
2649 .pPushConstantRanges = &pushConstantRange
2657 &pipelineLayoutInfo,
2659 shaderName.string(),
2662 delete specialization;
2664 PLOGI <<
"Hi-Z SPD compute pass created";
2673 PLOGW <<
"Hi-Z SPD compute pass not available, skipping descriptor set creation";
2680 std::array<VkDescriptorPoolSize, 3u> poolSizes{};
2682 .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
2686 .type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
2690 .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
2694 VkDescriptorPoolCreateInfo poolInfo{
2695 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
2697 .poolSizeCount =
static_cast<uint32_t
>(poolSizes.size()),
2698 .pPoolSizes = poolSizes.data()
2701 VkDescriptorPool spdDescriptorPool = VK_NULL_HANDLE;
2703 context->getVkDevice(), &poolInfo,
nullptr, &spdDescriptorPool,
"Hi-Z SPD"
2710 VkDescriptorSetAllocateInfo allocInfo{
2711 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
2712 .descriptorPool = spdDescriptorPool,
2713 .descriptorSetCount = 1,
2714 .pSetLayouts = &layout
2717 VkResult result = vkAllocateDescriptorSets(
2720 if (result != VK_SUCCESS)
2722 PLOGE <<
"Failed to allocate Hi-Z SPD descriptor set for frame " << frame;
2742 VkDescriptorImageInfo depthMSInfo{
2743 .sampler =
headset->getHiZSampler(),
2744 .imageView =
headset->getDepthBufferView(),
2745 .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
2749 std::array<VkDescriptorImageInfo, 12> dstMipInfos{};
2750 for (uint32_t mip = 0; mip < 12; mip++)
2752 if (mip < mipLevels)
2754 dstMipInfos[mip] = {
2755 .sampler = VK_NULL_HANDLE,
2757 .imageLayout = VK_IMAGE_LAYOUT_GENERAL
2763 dstMipInfos[mip] = {
2764 .sampler = VK_NULL_HANDLE,
2766 .imageLayout = VK_IMAGE_LAYOUT_GENERAL
2772 VkDescriptorImageInfo dst5Info{
2773 .sampler = VK_NULL_HANDLE,
2775 .imageLayout = VK_IMAGE_LAYOUT_GENERAL
2782 std::array<VkWriteDescriptorSet, 4> writes{};
2785 .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
2788 .dstArrayElement = 0,
2789 .descriptorCount = 1,
2790 .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
2791 .pImageInfo = &depthMSInfo
2795 .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
2798 .dstArrayElement = 0,
2799 .descriptorCount = 12,
2800 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
2801 .pImageInfo = dstMipInfos.data()
2805 .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
2808 .dstArrayElement = 0,
2809 .descriptorCount = 1,
2810 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
2811 .pImageInfo = &dst5Info
2815 .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
2818 .dstArrayElement = 0,
2819 .descriptorCount = 1,
2820 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
2821 .pBufferInfo = &atomicBufferInfo
2824 vkUpdateDescriptorSets(
context->getVkDevice(),
static_cast<uint32_t
>(writes.size()), writes.data(), 0,
nullptr);
2838 const VkExtent2D hiZExtent = currentRenderProcess->
getHiZExtent();
2843 VkMemoryBarrier2 depthBarrier{
2844 .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER_2,
2845 .srcStageMask = VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT,
2846 .srcAccessMask = VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
2847 .dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
2848 .dstAccessMask = VK_ACCESS_2_SHADER_READ_BIT
2850 VkDependencyInfo depInfo{VK_STRUCTURE_TYPE_DEPENDENCY_INFO};
2851 depInfo.memoryBarrierCount = 1;
2852 depInfo.pMemoryBarriers = &depthBarrier;
2853 vkCmdPipelineBarrier2(commandBuffer, &depInfo);
2858 VkImageMemoryBarrier2 hiZBarrier{
2859 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
2860 .srcStageMask = VK_PIPELINE_STAGE_2_NONE,
2861 .srcAccessMask = VK_ACCESS_2_NONE,
2862 .dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
2863 .dstAccessMask = VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT,
2864 .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
2865 .newLayout = VK_IMAGE_LAYOUT_GENERAL,
2866 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
2867 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
2869 .subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, mipLevels, 0, 2}
2871 VkDependencyInfo depInfo{VK_STRUCTURE_TYPE_DEPENDENCY_INFO};
2872 depInfo.imageMemoryBarrierCount = 1;
2873 depInfo.pImageMemoryBarriers = &hiZBarrier;
2874 vkCmdPipelineBarrier2(commandBuffer, &depInfo);
2879 vkCmdBindDescriptorSets(
2881 VK_PIPELINE_BIND_POINT_COMPUTE,
2889 uint32_t dispatchX = (hiZExtent.width + 63) / 64;
2890 uint32_t dispatchY = (hiZExtent.height + 63) / 64;
2891 uint32_t numWorkGroups = dispatchX * dispatchY;
2894 struct SPDPushConstants {
2896 uint32_t numWorkGroups;
2897 int32_t workGroupOffsetX;
2898 int32_t workGroupOffsetY;
2899 uint32_t sampleCount;
2911 VK_SHADER_STAGE_COMPUTE_BIT,
2913 sizeof(SPDPushConstants),
2918 vkCmdDispatch(commandBuffer, dispatchX, dispatchY, 2);
2922 VkImageMemoryBarrier2 finalBarrier{
2923 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
2924 .srcStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
2925 .srcAccessMask = VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT,
2926 .dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
2927 .dstAccessMask = VK_ACCESS_2_SHADER_READ_BIT,
2928 .oldLayout = VK_IMAGE_LAYOUT_GENERAL,
2929 .newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
2930 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
2931 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
2933 .subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, mipLevels, 0, 2}
2935 VkDependencyInfo depInfo{VK_STRUCTURE_TYPE_DEPENDENCY_INFO};
2936 depInfo.imageMemoryBarrierCount = 1;
2937 depInfo.pImageMemoryBarriers = &finalBarrier;
2938 vkCmdPipelineBarrier2(commandBuffer, &depInfo);
2969 PLOGW <<
"Hi-Z generation compute pass not created, skipping Hi-Z generation";
2979 const VkExtent2D hiZExtent = currentRenderProcess->
getHiZExtent();
2989 VkImageMemoryBarrier2 hiZBarrier{
2990 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
2991 .srcStageMask = VK_PIPELINE_STAGE_2_NONE,
2992 .srcAccessMask = VK_ACCESS_2_NONE,
2993 .dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
2994 .dstAccessMask = VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT,
2995 .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
2996 .newLayout = VK_IMAGE_LAYOUT_GENERAL,
2997 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
2998 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
3000 .subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, mipLevels, 0, 2 }
3003 VkDependencyInfo depInfo{ VK_STRUCTURE_TYPE_DEPENDENCY_INFO };
3004 depInfo.imageMemoryBarrierCount = 1;
3005 depInfo.pImageMemoryBarriers = &hiZBarrier;
3006 vkCmdPipelineBarrier2( commandBuffer, &depInfo );
3016 uint32_t srcWidth = hiZExtent.width;
3017 uint32_t srcHeight = hiZExtent.height;
3019 for (uint32_t mip = 0; mip < mipLevels; mip++)
3024 uint32_t dstWidth = (mip == 0) ? srcWidth : std::max(1u, srcWidth >> 1);
3025 uint32_t dstHeight = (mip == 0) ? srcHeight : std::max(1u, srcHeight >> 1);
3028 struct HiZPushConstants {
3032 uint32_t sampleCount;
3043 VK_SHADER_STAGE_COMPUTE_BIT,
3045 sizeof(HiZPushConstants),
3050 vkCmdBindDescriptorSets(
3052 VK_PIPELINE_BIND_POINT_COMPUTE,
3060 uint32_t groupsX = (dstWidth + 7) / 8;
3061 uint32_t groupsY = (dstHeight + 7) / 8;
3062 uint32_t groupsZ = 2;
3064 vkCmdDispatch( commandBuffer, groupsX, groupsY, groupsZ );
3067 if (mip < mipLevels - 1)
3069 VkImageMemoryBarrier2 mipBarrier{
3070 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
3071 .srcStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
3072 .srcAccessMask = VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT,
3073 .dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
3074 .dstAccessMask = VK_ACCESS_2_SHADER_SAMPLED_READ_BIT,
3075 .oldLayout = VK_IMAGE_LAYOUT_GENERAL,
3076 .newLayout = VK_IMAGE_LAYOUT_GENERAL,
3077 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
3078 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
3080 .subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, mip, 1, 0, 2 }
3083 VkDependencyInfo depInfo{ VK_STRUCTURE_TYPE_DEPENDENCY_INFO };
3084 depInfo.imageMemoryBarrierCount = 1;
3085 depInfo.pImageMemoryBarriers = &mipBarrier;
3086 vkCmdPipelineBarrier2( commandBuffer, &depInfo );
3090 srcWidth = dstWidth;
3091 srcHeight = dstHeight;
3096 VkImageMemoryBarrier2 finalBarrier{
3097 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
3098 .srcStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
3099 .srcAccessMask = VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT,
3100 .dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
3101 .dstAccessMask = VK_ACCESS_2_SHADER_SAMPLED_READ_BIT,
3102 .oldLayout = VK_IMAGE_LAYOUT_GENERAL,
3103 .newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
3104 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
3105 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
3107 .subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, mipLevels, 0, 2 }
3110 VkDependencyInfo depInfo{ VK_STRUCTURE_TYPE_DEPENDENCY_INFO };
3111 depInfo.imageMemoryBarrierCount = 1;
3112 depInfo.pImageMemoryBarriers = &finalBarrier;
3113 vkCmdPipelineBarrier2( commandBuffer, &depInfo );
3126 PLOGI <<
"[VS_PATH] Creating vertex shader path pipeline resources";
3130 VkVertexInputBindingDescription vertexBindingDesc{
3133 .inputRate = VK_VERTEX_INPUT_RATE_VERTEX
3137 std::array<VkVertexInputAttributeDescription, 5> vertexAttrDescs = {{
3138 {.location = 0, .binding = 0, .format = VK_FORMAT_R32G32B32A32_SFLOAT, .offset = 0},
3139 {.location = 1, .binding = 0, .format = VK_FORMAT_R32G32B32A32_SFLOAT, .offset = 16},
3140 {.location = 2, .binding = 0, .format = VK_FORMAT_R32G32B32A32_SFLOAT, .offset = 32},
3141 {.location = 3, .binding = 0, .format = VK_FORMAT_R32G32_SFLOAT, .offset = 48},
3142 {.location = 4, .binding = 0, .format = VK_FORMAT_R32G32_SFLOAT, .offset = 56}
3145 VkPipelineVertexInputStateCreateInfo vertexInputState{
3146 .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
3147 .vertexBindingDescriptionCount = 1,
3148 .pVertexBindingDescriptions = &vertexBindingDesc,
3149 .vertexAttributeDescriptionCount =
static_cast<uint32_t
>(vertexAttrDescs.size()),
3150 .pVertexAttributeDescriptions = vertexAttrDescs.data()
3153 VkPipelineInputAssemblyStateCreateInfo inputAssemblyState{
3154 .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
3155 .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
3156 .primitiveRestartEnable = VK_FALSE
3162 VertexShader shader(
context->getVkDevice(), shaderDir /
"Placeholder.vert.spv", shaderDir /
"triangle_movable_normals.frag.spv");
3164 std::array<VkPipelineShaderStageCreateInfo, 2> shaderStages = {{
3166 .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
3167 .stage = VK_SHADER_STAGE_VERTEX_BIT,
3172 .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
3173 .stage = VK_SHADER_STAGE_FRAGMENT_BIT,
3179 VkPipelineViewportStateCreateInfo viewportState{
3180 .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
3185 VkPipelineRasterizationStateCreateInfo rasterizationState{
3186 .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
3187 .polygonMode = VK_POLYGON_MODE_FILL,
3188 .cullMode = VK_CULL_MODE_NONE,
3189 .frontFace = VK_FRONT_FACE_CLOCKWISE,
3193 VkPipelineMultisampleStateCreateInfo multisampleState{
3194 .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
3195 .rasterizationSamples =
context->getMultisampleCount()
3198 VkPipelineDepthStencilStateCreateInfo depthStencilState{
3199 .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
3200 .depthTestEnable = VK_TRUE,
3201 .depthWriteEnable = VK_TRUE,
3202 .depthCompareOp = VK_COMPARE_OP_GREATER
3205 VkPipelineColorBlendAttachmentState colorBlendAttachment{
3206 .blendEnable = VK_FALSE,
3207 .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
3208 VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT
3211 VkPipelineColorBlendStateCreateInfo colorBlendState{
3212 .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
3213 .attachmentCount = 1,
3214 .pAttachments = &colorBlendAttachment
3217 std::array<VkDynamicState, 2> dynamicStates = {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR};
3218 VkPipelineDynamicStateCreateInfo dynamicState{
3219 .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
3220 .dynamicStateCount =
static_cast<uint32_t
>(dynamicStates.size()),
3221 .pDynamicStates = dynamicStates.data()
3225 constexpr VkFormat colorFormat = VK_FORMAT_R8G8B8A8_SRGB;
3226 constexpr VkFormat depthFormat = VK_FORMAT_D32_SFLOAT;
3227 VkPipelineRenderingCreateInfo pipelineRenderingInfo{
3228 .sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO,
3230 .colorAttachmentCount = 1,
3231 .pColorAttachmentFormats = &colorFormat,
3232 .depthAttachmentFormat = depthFormat,
3235 VkGraphicsPipelineCreateInfo pipelineCreateInfo{
3236 .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
3237 .pNext = &pipelineRenderingInfo,
3238 .stageCount =
static_cast<uint32_t
>(shaderStages.size()),
3239 .pStages = shaderStages.data(),
3240 .pVertexInputState = &vertexInputState,
3241 .pInputAssemblyState = &inputAssemblyState,
3242 .pViewportState = &viewportState,
3243 .pRasterizationState = &rasterizationState,
3244 .pMultisampleState = &multisampleState,
3245 .pDepthStencilState = &depthStencilState,
3246 .pColorBlendState = &colorBlendState,
3247 .pDynamicState = &dynamicState,
3249 .renderPass = VK_NULL_HANDLE
3252 VkResult result = vkCreateGraphicsPipelines(
3256 &pipelineCreateInfo,
3261 if (result != VK_SUCCESS) {
3262 PLOGE <<
"[VS_PATH] Failed to create vertex shader pipeline: " << result;
3266 PLOGI <<
"[VS_PATH] Vertex shader pipeline created successfully";
3275 VertexShader depthOnlyShader(
context->getVkDevice(), shaderDir /
"Placeholder.vert.spv", shaderDir /
"depth_only.frag.spv");
3277 std::array<VkPipelineShaderStageCreateInfo, 2> depthOnlyShaderStages = {{
3279 .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
3280 .stage = VK_SHADER_STAGE_VERTEX_BIT,
3285 .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
3286 .stage = VK_SHADER_STAGE_FRAGMENT_BIT,
3293 VkPipelineColorBlendStateCreateInfo depthOnlyColorBlendState{
3294 .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
3295 .attachmentCount = 0,
3296 .pAttachments =
nullptr
3299 VkPipelineRenderingCreateInfo depthOnlyRenderingInfo{
3300 .sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO,
3302 .colorAttachmentCount = 0,
3303 .pColorAttachmentFormats =
nullptr,
3304 .depthAttachmentFormat = depthFormat,
3307 VkGraphicsPipelineCreateInfo depthOnlyPipelineCreateInfo{
3308 .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
3309 .pNext = &depthOnlyRenderingInfo,
3310 .stageCount =
static_cast<uint32_t
>(depthOnlyShaderStages.size()),
3311 .pStages = depthOnlyShaderStages.data(),
3312 .pVertexInputState = &vertexInputState,
3313 .pInputAssemblyState = &inputAssemblyState,
3314 .pViewportState = &viewportState,
3315 .pRasterizationState = &rasterizationState,
3316 .pMultisampleState = &multisampleState,
3317 .pDepthStencilState = &depthStencilState,
3318 .pColorBlendState = &depthOnlyColorBlendState,
3319 .pDynamicState = &dynamicState,
3321 .renderPass = VK_NULL_HANDLE
3324 VkResult depthOnlyResult = vkCreateGraphicsPipelines(
3328 &depthOnlyPipelineCreateInfo,
3333 if (depthOnlyResult != VK_SUCCESS) {
3334 PLOGE <<
"[VS_PATH] Failed to create depth-only VS pipeline: " << depthOnlyResult;
3337 PLOGI <<
"[VS_PATH] Depth-only VS pipeline created successfully";
3350 PLOGI <<
"[VS_INSTANCED] VS instanced drawing disabled, skipping compute pipeline creation";
3354 PLOGI <<
"[VS_INSTANCED] Creating VS instanced drawing compute pipelines";
3358 std::vector<VkDescriptorSetLayoutBinding> computeLayoutBindings =
3360 #if !defined(HEADLESS)
3370 VkDescriptorSetLayoutCreateInfo computeLayoutCreateInfo = {
3371 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
3372 .bindingCount =
static_cast<uint32_t
>( computeLayoutBindings.size() ),
3373 .pBindings = computeLayoutBindings.data()
3376 VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {
3377 .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
3380 .setLayoutCount = 1u,
3381 .pSetLayouts =
nullptr,
3382 .pushConstantRangeCount = 0,
3383 .pPushConstantRanges =
nullptr,
3392 &pipelineLayoutCreateInfo,
3393 &computeLayoutCreateInfo,
3394 shaderPath.string(),
3397 delete specialization;
3398 PLOGI <<
"[VS_INSTANCED] Created VS Binning Allocator compute pass";
3403 std::vector<VkDescriptorSetLayoutBinding> computeLayoutBindings =
3405 #if !defined(HEADLESS)
3412 VkDescriptorSetLayoutCreateInfo computeLayoutCreateInfo = {
3413 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
3414 .bindingCount =
static_cast<uint32_t
>( computeLayoutBindings.size() ),
3415 .pBindings = computeLayoutBindings.data()
3418 VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {
3419 .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
3422 .setLayoutCount = 1u,
3423 .pSetLayouts =
nullptr,
3424 .pushConstantRangeCount = 0,
3425 .pPushConstantRanges =
nullptr,
3434 &pipelineLayoutCreateInfo,
3435 &computeLayoutCreateInfo,
3436 shaderPath.string(),
3439 delete specialization;
3440 PLOGI <<
"[VS_INSTANCED] Created VS Instance Unpacking compute pass";
3445 std::vector<VkDescriptorSetLayoutBinding> computeLayoutBindings =
3447 #if !defined(HEADLESS)
3455 VkDescriptorSetLayoutCreateInfo computeLayoutCreateInfo = {
3456 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
3457 .bindingCount =
static_cast<uint32_t
>( computeLayoutBindings.size() ),
3458 .pBindings = computeLayoutBindings.data()
3462 VkPushConstantRange pushConstantRange{
3463 .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
3465 .size =
sizeof( uint32_t )
3468 VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {
3469 .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
3472 .setLayoutCount = 1u,
3473 .pSetLayouts =
nullptr,
3474 .pushConstantRangeCount = 1,
3475 .pPushConstantRanges = &pushConstantRange,
3484 &pipelineLayoutCreateInfo,
3485 &computeLayoutCreateInfo,
3486 shaderPath.string(),
3489 delete specialization;
3490 PLOGI <<
"[VS_INSTANCED] Created VS Prepare Draw compute pass";
3493 PLOGI <<
"[VS_INSTANCED] All VS instanced drawing compute passes created successfully";
3520 if (primitiveCount == 0 || uniqueGeoCount == 0) {
3531 VkMemoryBarrier2 fillBarrier{
3532 .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER_2,
3533 .srcStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT,
3534 .srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT,
3535 .dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
3536 .dstAccessMask = VK_ACCESS_2_SHADER_READ_BIT | VK_ACCESS_2_SHADER_WRITE_BIT
3538 VkDependencyInfo fillDep{ VK_STRUCTURE_TYPE_DEPENDENCY_INFO };
3539 fillDep.memoryBarrierCount = 1;
3540 fillDep.pMemoryBarriers = &fillBarrier;
3541 vkCmdPipelineBarrier2( commandBuffer, &fillDep );
3553 vkCmdDispatch( commandBuffer, ( primitiveCount + threadCount - 1 ) / threadCount, 1, 1 );
3558 VkMemoryBarrier2 barrier{
3559 .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER_2,
3560 .srcStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
3561 .srcAccessMask = VK_ACCESS_2_SHADER_WRITE_BIT,
3562 .dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
3563 .dstAccessMask = VK_ACCESS_2_SHADER_READ_BIT
3565 VkDependencyInfo depInfo{ VK_STRUCTURE_TYPE_DEPENDENCY_INFO };
3566 depInfo.memoryBarrierCount = 1;
3567 depInfo.pMemoryBarriers = &barrier;
3568 vkCmdPipelineBarrier2( commandBuffer, &depInfo );
3579 vkCmdDispatch( commandBuffer, ( primitiveCount + threadCount - 1 ) / threadCount, 1, 1 );
3584 VkMemoryBarrier2 barrier{
3585 .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER_2,
3586 .srcStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
3587 .srcAccessMask = VK_ACCESS_2_SHADER_WRITE_BIT,
3588 .dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT,
3589 .dstAccessMask = VK_ACCESS_2_SHADER_READ_BIT
3591 VkDependencyInfo depInfo{ VK_STRUCTURE_TYPE_DEPENDENCY_INFO };
3592 depInfo.memoryBarrierCount = 1;
3593 depInfo.pMemoryBarriers = &barrier;
3594 vkCmdPipelineBarrier2( commandBuffer, &depInfo );
3607 vkCmdPushConstants2( commandBuffer, &pushConstantsInfo );
3609 vkCmdDispatch( commandBuffer, ( uniqueGeoCount + threadCount - 1 ) / threadCount, 1, 1 );
3614 VkMemoryBarrier2 barrier{
3615 .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER_2,
3616 .srcStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
3617 .srcAccessMask = VK_ACCESS_2_SHADER_WRITE_BIT,
3618 .dstStageMask = VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT,
3619 .dstAccessMask = VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT
3621 VkDependencyInfo depInfo{ VK_STRUCTURE_TYPE_DEPENDENCY_INFO };
3622 depInfo.memoryBarrierCount = 1;
3623 depInfo.pMemoryBarriers = &barrier;
3624 vkCmdPipelineBarrier2( commandBuffer, &depInfo );
3627 PLOGI <<
"[VS_INSTANCED] Dispatched VS instanced drawing pipeline for " << uniqueGeoCount <<
" geometry types";
3632 PLOGI <<
"[VS_DIAG] recordVertexShaderDraws: hasVSPath="
3639 <<
", vsGraphicsPipeline_=" << (
vsGraphicsPipeline_ != VK_NULL_HANDLE ?
"valid" :
"NULL");
3645 PLOGI <<
"[VS_DIAG] EARLY EXIT: no single-meshlet geometry";
3652 PLOGI <<
"[VS_DIAG] Passed all checks, proceeding with VS draw recording";
3666 VkDeviceSize offsets[] = { 0 };
3667 PLOGI <<
"[VS_DIAG] Binding vertex buffer: handle=" << (
void*)vertexBuffers[0]
3669 vkCmdBindVertexBuffers(commandBuffer, 0, 1, vertexBuffers, offsets);
3673 PLOGI <<
"[VS_DIAG] Binding index buffer: handle=" << (
void*)indexBuffer
3675 vkCmdBindIndexBuffer(commandBuffer, indexBuffer, 0, VK_INDEX_TYPE_UINT32);
3679 vkCmdBindDescriptorSets(
3681 VK_PIPELINE_BIND_POINT_GRAPHICS,
3706 PLOGI <<
"[VS_DIAG] VS Instanced path: maxDrawCount=" << maxDrawCount;
3707 if (maxDrawCount > 0) {
3710 PLOGI <<
"[VS_BUFFER_DEBUG] Eye " << currentRenderProcess->
getEyeIndex() <<
" Draw call using:"
3711 <<
" vsDrawCountBuffer=" << (
void*)drawCountBuffer
3712 <<
" vsDrawCommandsBuffer=" << (
void*)drawCmdBuffer;
3713 PLOGI <<
"[VS_DIAG] CALLING vkCmdDrawIndexedIndirectCount (instanced path)"
3714 <<
" drawCmdBuffer=" << (
void*)drawCmdBuffer
3715 <<
" drawCountBuffer=" << (
void*)drawCountBuffer
3716 <<
" stride=" <<
sizeof(VkDrawIndexedIndirectCommand);
3717 vkCmdDrawIndexedIndirectCount(
3724 sizeof(VkDrawIndexedIndirectCommand)
3730 PLOGI <<
"[VS_DIAG] VS Legacy path: maxDrawCount=" << maxDrawCount;
3731 if (maxDrawCount > 0) {
3732 PLOGI <<
"[VS_DIAG] CALLING vkCmdDrawIndexedIndirectCount (legacy path)";
3733 vkCmdDrawIndexedIndirectCount(
3740 sizeof(VkDrawIndexedIndirectCommand)
3770 VkDeviceSize offsets[] = { 0 };
3771 vkCmdBindVertexBuffers(commandBuffer, 0, 1, vertexBuffers, offsets);
3775 vkCmdBindIndexBuffer(commandBuffer, indexBuffer, 0, VK_INDEX_TYPE_UINT32);
3779 vkCmdBindDescriptorSets(
3781 VK_PIPELINE_BIND_POINT_GRAPHICS,
3793 if (maxDrawCount > 0) {
3796 vkCmdDrawIndexedIndirectCount(
3803 sizeof(VkDrawIndexedIndirectCommand)
3808 if (maxDrawCount > 0) {
3809 vkCmdDrawIndexedIndirectCount(
3816 sizeof(VkDrawIndexedIndirectCommand)
3854 VkMemoryBarrier2 hiZReadBarrier{
3855 .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER_2,
3856 .srcStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
3857 .srcAccessMask = VK_ACCESS_2_SHADER_WRITE_BIT,
3858 .dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
3859 .dstAccessMask = VK_ACCESS_2_SHADER_READ_BIT
3861 VkDependencyInfo depInfo{ VK_STRUCTURE_TYPE_DEPENDENCY_INFO };
3862 depInfo.memoryBarrierCount = 1;
3863 depInfo.pMemoryBarriers = &hiZReadBarrier;
3864 vkCmdPipelineBarrier2( commandBuffer, &depInfo );
3874 VkMemoryBarrier2 computeToTransferBarrier{
3875 .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER_2,
3876 .srcStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
3877 .srcAccessMask = VK_ACCESS_2_SHADER_WRITE_BIT,
3878 .dstStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT,
3879 .dstAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT
3881 VkDependencyInfo preFillDep{ VK_STRUCTURE_TYPE_DEPENDENCY_INFO };
3882 preFillDep.memoryBarrierCount = 1;
3883 preFillDep.pMemoryBarriers = &computeToTransferBarrier;
3884 vkCmdPipelineBarrier2( commandBuffer, &preFillDep );
3889 VkMemoryBarrier2 fillBarrier{
3890 .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER_2,
3891 .srcStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT,
3892 .srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT,
3893 .dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
3894 .dstAccessMask = VK_ACCESS_2_SHADER_READ_BIT | VK_ACCESS_2_SHADER_WRITE_BIT
3896 VkDependencyInfo fillDep{ VK_STRUCTURE_TYPE_DEPENDENCY_INFO };
3897 fillDep.memoryBarrierCount = 1;
3898 fillDep.pMemoryBarriers = &fillBarrier;
3899 vkCmdPipelineBarrier2( commandBuffer, &fillDep );
3910 struct CullingPushConstants {
3911 uint32_t primitiveCount;
3912 uint32_t cullingPass;
3913 } pushData = { primitiveCount, 1 };
3918 vkCmdPushConstants2( commandBuffer, &pushConstantsInfo );
3922 if ( primitiveCount > 0 )
3924 vkCmdDispatch( commandBuffer, ( primitiveCount + threadCount - 1 ) / threadCount, 1, 1 );
3930 VkMemoryBarrier2 cullBarrier{
3931 .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER_2,
3932 .srcStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
3933 .srcAccessMask = VK_ACCESS_2_SHADER_WRITE_BIT,
3934 .dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
3935 .dstAccessMask = VK_ACCESS_2_SHADER_READ_BIT
3937 VkDependencyInfo depInfo{ VK_STRUCTURE_TYPE_DEPENDENCY_INFO };
3938 depInfo.memoryBarrierCount = 1;
3939 depInfo.pMemoryBarriers = &cullBarrier;
3940 vkCmdPipelineBarrier2( commandBuffer, &depInfo );
3953 if ( primitiveCount > 0 )
3955 vkCmdDispatch( commandBuffer, ( primitiveCount + threadCount - 1 ) / threadCount, 1, 1 );
3961 VkMemoryBarrier2 binningBarrier{
3962 .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER_2,
3963 .srcStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
3964 .srcAccessMask = VK_ACCESS_2_SHADER_WRITE_BIT,
3965 .dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
3966 .dstAccessMask = VK_ACCESS_2_SHADER_READ_BIT
3968 VkDependencyInfo depInfo{ VK_STRUCTURE_TYPE_DEPENDENCY_INFO };
3969 depInfo.memoryBarrierCount = 1;
3970 depInfo.pMemoryBarriers = &binningBarrier;
3971 vkCmdPipelineBarrier2( commandBuffer, &depInfo );
3979 vkCmdDispatch( commandBuffer, 1, 1, 1 );
3986 vkCmdPipelineBarrier2( commandBuffer, &dependencyInfo );
3999 VkMemoryBarrier2 memBarrier{
4000 .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER_2,
4001 .srcStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
4002 .srcAccessMask = VK_ACCESS_2_SHADER_WRITE_BIT,
4003 .dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
4004 .dstAccessMask = VK_ACCESS_2_SHADER_READ_BIT
4006 VkDependencyInfo depInfo{ VK_STRUCTURE_TYPE_DEPENDENCY_INFO };
4007 depInfo.memoryBarrierCount = 1;
4008 depInfo.pMemoryBarriers = &memBarrier;
4009 vkCmdPipelineBarrier2( commandBuffer, &depInfo );
4017 vkCmdDispatch( commandBuffer, 1, 1, 1 );
4022 VkBufferMemoryBarrier2 visibleBarrier{ VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2 };
4023 visibleBarrier.srcStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT;
4024 visibleBarrier.srcAccessMask = VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT;
4025 visibleBarrier.dstStageMask = VK_PIPELINE_STAGE_2_MESH_SHADER_BIT_EXT;
4026 visibleBarrier.dstAccessMask = VK_ACCESS_2_SHADER_STORAGE_READ_BIT;
4027 visibleBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
4028 visibleBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
4030 visibleBarrier.offset = 0;
4031 visibleBarrier.size = VK_WHOLE_SIZE;
4033 VkBufferMemoryBarrier2 indirectBarrier{ VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2 };
4034 indirectBarrier.srcStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT;
4035 indirectBarrier.srcAccessMask = VK_ACCESS_2_SHADER_STORAGE_WRITE_BIT;
4036 indirectBarrier.dstStageMask = VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT;
4037 indirectBarrier.dstAccessMask = VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT;
4038 indirectBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
4039 indirectBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
4041 indirectBarrier.offset = 0;
4042 indirectBarrier.size = VK_WHOLE_SIZE;
4044 VkBufferMemoryBarrier2 barriers[] = { visibleBarrier, indirectBarrier };
4045 VkDependencyInfo depInfo{ VK_STRUCTURE_TYPE_DEPENDENCY_INFO };
4046 depInfo.bufferMemoryBarrierCount = 2;
4047 depInfo.pBufferMemoryBarriers = barriers;
4048 vkCmdPipelineBarrier2( commandBuffer, &depInfo );
4070 const VkExtent2D extent =
headset->getEyeResolution( 0u );
4077 VkImageMemoryBarrier2 colorBarrier{
4078 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
4079 .srcStageMask = VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT,
4080 .srcAccessMask = VK_ACCESS_2_NONE,
4081 .dstStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT,
4082 .dstAccessMask = VK_ACCESS_2_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT,
4083 .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
4084 .newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
4085 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
4086 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
4087 .image =
headset->getColorBufferImage(),
4088 .subresourceRange = {
4089 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
4092 .baseArrayLayer = 0,
4097 VkImageMemoryBarrier2 depthBarrier{
4098 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
4099 .srcStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
4100 .srcAccessMask = VK_ACCESS_2_SHADER_READ_BIT,
4101 .dstStageMask = VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT,
4102 .dstAccessMask = VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
4103 .oldLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
4104 .newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
4105 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
4106 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
4107 .image =
headset->getDepthBufferImage(),
4108 .subresourceRange = {
4109 .aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT,
4112 .baseArrayLayer = 0,
4119 VkImageMemoryBarrier2 swapchainBarrier{
4120 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
4121 .srcStageMask = VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT,
4122 .srcAccessMask = VK_ACCESS_2_NONE,
4123 .dstStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT,
4124 .dstAccessMask = VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT,
4125 .oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
4126 .newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
4127 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
4128 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
4129 .image = renderTarget->
image,
4130 .subresourceRange = {
4131 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
4134 .baseArrayLayer = 0,
4139 std::array<VkImageMemoryBarrier2, 3> barriers = { colorBarrier, depthBarrier, swapchainBarrier };
4140 VkDependencyInfo dependencyInfo{
4141 .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
4142 .imageMemoryBarrierCount =
static_cast<uint32_t
>( barriers.size() ),
4143 .pImageMemoryBarriers = barriers.data()
4145 vkCmdPipelineBarrier2( commandBuffer, &dependencyInfo );
4151 VkClearValue clearColor = { .color = { .float32 = { 0.0f, 0.0f, 0.0f, 1.0f } } };
4152 VkRenderingAttachmentInfo colorAttachment{
4153 .sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
4154 .imageView =
headset->getColorBufferView(),
4155 .imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
4156 .resolveMode = VK_RESOLVE_MODE_AVERAGE_BIT,
4157 .resolveImageView = renderTarget->
imageView,
4158 .resolveImageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
4159 .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
4160 .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
4161 .clearValue = clearColor,
4164 VkClearValue clearDepth = { .depthStencil = { .depth = 0.0f, .stencil = 0 } };
4165 VkRenderingAttachmentInfo depthAttachment{
4166 .sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
4167 .imageView =
headset->getDepthBufferView(),
4168 .imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
4169 .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
4170 .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
4171 .clearValue = clearDepth,
4174 VkRenderingInfo renderingInfo{
4175 .sType = VK_STRUCTURE_TYPE_RENDERING_INFO,
4176 .renderArea = { .offset = {0, 0}, .extent = extent },
4179 .colorAttachmentCount = 1,
4180 .pColorAttachments = &colorAttachment,
4181 .pDepthAttachment = &depthAttachment,
4184 vkCmdBeginRendering( commandBuffer, &renderingInfo );
4187 VkViewport viewport{
4188 .x = 0.0f, .y = 0.0f,
4189 .width =
static_cast<float>( extent.width ),
4190 .height =
static_cast<float>( extent.height ),
4191 .minDepth = 0.0f, .maxDepth = 1.0f
4193 vkCmdSetViewport( commandBuffer, 0, 1, &viewport );
4195 VkRect2D scissor{ .offset = {0, 0}, .extent = extent };
4196 vkCmdSetScissor( commandBuffer, 0, 1, &scissor );
4200 vkCmdBindDescriptorSets(
4201 commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
4210 for ( uint32_t pipelineIndex = 0; pipelineIndex <
graphicsPipelines.size(); pipelineIndex++ )
4212 if ( pipelineIndex != 0 )
4214 VkConditionalRenderingBeginInfoEXT conditionalRenderingBeginInfo = {
4215 .sType = VK_STRUCTURE_TYPE_CONDITIONAL_RENDERING_BEGIN_INFO_EXT,
4217 .offset = pipelineIndex *
sizeof( VkDrawMeshTasksIndirectCommandEXT ) +
4218 offsetof( VkDrawMeshTasksIndirectCommandEXT, groupCountX ),
4222 commandBuffer, &conditionalRenderingBeginInfo
4231 VK_SHADER_STAGE_MESH_BIT_EXT | VK_SHADER_STAGE_FRAGMENT_BIT,
4238 pipelineIndex *
sizeof( VkDrawMeshTasksIndirectCommandEXT ),
4240 sizeof( VkDrawMeshTasksIndirectCommandEXT )
4243 if ( pipelineIndex != 0 )
4249 vkCmdEndRendering( commandBuffer );
4265 std::future<void> futureUpdatePerObjectSSBO =
4267 [¤tRenderProcess, &thisRenderer]() ->
void
4269 currentRenderProcess->
updateSSBO( thisRenderer );
4273 std::future<void> futureMeshData =
4275 [¤tRenderProcess]() ->
void
4281 std::future<void> futureUpdateViewMatrix =
4289 std::future<void> futureUpdateFragmentTime =
4291 [¤tRenderProcess, time]() ->
void
4297 std::future<void> futureUpdateObjectMeshletData =
4299 [¤tRenderProcess]() ->
void
4307 futureUpdatePerObjectSSBO.get();
4308 futureUpdateObjectMeshletData.get();
4309 futureMeshData.get();
4310 futureUpdateViewMatrix.get();
4311 futureUpdateFragmentTime.get();
4336 VkCommandBufferBeginInfo commandBufferBeginInfo{ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
4337 PLOG_RETURN_FN_VK( vkBeginCommandBuffer(
4348 "Swapchain Image Barrier",
4352 VkImageMemoryBarrier2 imageBarrierToAttachment = {};
4353 imageBarrierToAttachment.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2;
4358 imageBarrierToAttachment.srcStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT;
4359 imageBarrierToAttachment.srcAccessMask = VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT;
4360 imageBarrierToAttachment.dstStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT;
4361 imageBarrierToAttachment.dstAccessMask = VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT;
4362 imageBarrierToAttachment.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
4363 imageBarrierToAttachment.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
4364 imageBarrierToAttachment.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
4365 imageBarrierToAttachment.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
4366 imageBarrierToAttachment.image =
headset->getSwapchainImage( swapChainImageIndex );
4367 imageBarrierToAttachment.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 2 };
4369 VkDependencyInfo dependencyInfo{ VK_STRUCTURE_TYPE_DEPENDENCY_INFO };
4370 dependencyInfo.imageMemoryBarrierCount = 1;
4371 dependencyInfo.pImageMemoryBarriers = &imageBarrierToAttachment;
4386 const VkExtent2D extent =
headset->getEyeResolution( 0u );
4393 VkImageMemoryBarrier2 depthBarrier{
4394 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
4395 .srcStageMask = VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT,
4396 .srcAccessMask = VK_ACCESS_2_NONE,
4397 .dstStageMask = VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT,
4398 .dstAccessMask = VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
4399 .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
4400 .newLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
4401 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
4402 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
4403 .image =
headset->getDepthBufferImage(),
4404 .subresourceRange = {
4405 .aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT,
4408 .baseArrayLayer = 0,
4413 VkDependencyInfo dependencyInfo{
4414 .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
4415 .imageMemoryBarrierCount = 1,
4416 .pImageMemoryBarriers = &depthBarrier
4418 vkCmdPipelineBarrier2( commandBuffer, &dependencyInfo );
4422 VkClearValue clearDepth = { .depthStencil = { .depth = 0.0f, .stencil = 0 } };
4423 VkRenderingAttachmentInfo depthAttachment{
4424 .sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
4425 .imageView =
headset->getDepthBufferView(),
4426 .imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
4427 .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
4428 .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
4429 .clearValue = clearDepth,
4432 VkRenderingInfo renderingInfo{
4433 .sType = VK_STRUCTURE_TYPE_RENDERING_INFO,
4434 .renderArea = { .offset = {0, 0}, .extent = extent },
4437 .colorAttachmentCount = 0,
4438 .pColorAttachments =
nullptr,
4439 .pDepthAttachment = &depthAttachment,
4442 vkCmdBeginRendering( commandBuffer, &renderingInfo );
4445 VkViewport viewport{
4446 .x = 0.0f, .y = 0.0f,
4447 .width =
static_cast<float>( extent.width ),
4448 .height =
static_cast<float>( extent.height ),
4449 .minDepth = 0.0f, .maxDepth = 1.0f
4451 vkCmdSetViewport( commandBuffer, 0, 1, &viewport );
4453 VkRect2D scissor{ .offset = {0, 0}, .extent = extent };
4454 vkCmdSetScissor( commandBuffer, 0, 1, &scissor );
4458 vkCmdBindDescriptorSets(
4459 commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
4469 if ( pipelineIndex != 0 )
4471 VkConditionalRenderingBeginInfoEXT conditionalRenderingBeginInfo = {
4472 .sType = VK_STRUCTURE_TYPE_CONDITIONAL_RENDERING_BEGIN_INFO_EXT,
4474 .offset = pipelineIndex *
sizeof( VkDrawMeshTasksIndirectCommandEXT ) +
4475 offsetof( VkDrawMeshTasksIndirectCommandEXT, groupCountX ),
4479 commandBuffer, &conditionalRenderingBeginInfo
4488 VK_SHADER_STAGE_MESH_BIT_EXT | VK_SHADER_STAGE_FRAGMENT_BIT,
4495 pipelineIndex *
sizeof( VkDrawMeshTasksIndirectCommandEXT ),
4497 sizeof( VkDrawMeshTasksIndirectCommandEXT )
4500 if ( pipelineIndex != 0 )
4506 vkCmdEndRendering( commandBuffer );
4512 VkImageMemoryBarrier2 depthToReadBarrier{
4513 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
4514 .srcStageMask = VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT,
4515 .srcAccessMask = VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
4516 .dstStageMask = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
4517 .dstAccessMask = VK_ACCESS_2_SHADER_SAMPLED_READ_BIT,
4518 .oldLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
4519 .newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
4520 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
4521 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
4522 .image =
headset->getDepthBufferImage(),
4523 .subresourceRange = {
4524 .aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT,
4527 .baseArrayLayer = 0,
4532 VkDependencyInfo depInfo{ VK_STRUCTURE_TYPE_DEPENDENCY_INFO };
4533 depInfo.imageMemoryBarrierCount = 1;
4534 depInfo.pImageMemoryBarriers = &depthToReadBarrier;
4535 vkCmdPipelineBarrier2( commandBuffer, &depInfo );
4554 VkImageMemoryBarrier2 barrier{ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2 };
4555 barrier.pNext =
nullptr;
4557 barrier.srcStageMask = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT;
4558 barrier.srcAccessMask = VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT;
4560 barrier.dstStageMask = VK_PIPELINE_STAGE_2_BLIT_BIT | VK_PIPELINE_STAGE_2_COPY_BIT;
4561 barrier.dstAccessMask = VK_ACCESS_2_TRANSFER_READ_BIT;
4563 barrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
4564 barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
4565 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
4566 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
4567 barrier.image =
headset->getSwapchainImage( swapChainImageIndex );
4569 barrier.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 2 };
4571 VkDependencyInfo dependencyInfo{ VK_STRUCTURE_TYPE_DEPENDENCY_INFO };
4572 dependencyInfo.pNext =
nullptr;
4573 dependencyInfo.dependencyFlags = 0;
4574 dependencyInfo.memoryBarrierCount = 0;
4575 dependencyInfo.pMemoryBarriers =
nullptr;
4576 dependencyInfo.bufferMemoryBarrierCount = 0;
4577 dependencyInfo.pBufferMemoryBarriers =
nullptr;
4578 dependencyInfo.imageMemoryBarrierCount = 1;
4579 dependencyInfo.pImageMemoryBarriers = &barrier;
4591 constexpr VkDeviceSize size =
sizeof( VkDrawMeshTasksIndirectCommandEXT );
4592 dispatchBuffer->create( size, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT );
4599 constexpr VkDeviceSize size =
sizeof(uint32_t);
4600 placeholderBuffer->create( size, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT );
4607 constexpr VkDeviceSize size =
sizeof(uint32_t);
4614 constexpr VkDeviceSize size =
sizeof(uint32_t);
4615 counterBuffer->create(size, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT );
4622 constexpr VkDeviceSize size = 4096 *
sizeof(uint32_t);
4623 objectIDsBuffer->create(size, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
4630 constexpr VkDeviceSize size = 4096 * 32;
4631 objectCullingDataBuffer->create(size, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
4638 constexpr VkDeviceSize size = 4096 * 16;
4639 objectMeshletDataBuffer->create(size, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
4646 constexpr VkDeviceSize size = 4096 *
sizeof(uint32_t);
4647 meshUnpackingDataBuffer->create(size, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
4692 bool anyRecreated =
false;
4693 constexpr VkMemoryPropertyFlags deviceLocal = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
4694 constexpr VkBufferUsageFlags storageUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
4695 constexpr VkBufferUsageFlags storageTransferUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
4699 const VkDeviceSize meshUnpackingSize = primitiveCount *
sizeof(uint32_t);
4703 const VkDeviceSize objectIDsSize = primitiveCount *
sizeof(uint32_t);
4704 anyRecreated |=
objectIDsBuffer->ensureSize(objectIDsSize, storageTransferUsage, deviceLocal);
4707 const VkDeviceSize cullingDataSize = primitiveCount * 32;
4711 const VkDeviceSize meshletDataSize = primitiveCount * 16;
4716 if (renderProcess) {
4717 anyRecreated |= renderProcess->ensureBufferSizes(primitiveCount);
4722 PLOGI <<
"Renderer: Output buffers resized for " << primitiveCount <<
" primitives";
4725 return anyRecreated;
4731 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
4732 VK_ACCESS_2_SHADER_WRITE_BIT,
4733 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
4734 VK_ACCESS_2_SHADER_READ_BIT,
4743 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
4744 VK_ACCESS_2_SHADER_WRITE_BIT,
4745 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
4746 VK_ACCESS_2_SHADER_READ_BIT,
4751 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
4752 VK_ACCESS_2_SHADER_WRITE_BIT,
4753 VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT,
4754 VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT,
4766 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
4767 VK_ACCESS_2_SHADER_WRITE_BIT,
4768 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
4769 VK_ACCESS_2_SHADER_READ_BIT,
4784 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
4785 VK_ACCESS_2_SHADER_WRITE_BIT,
4786 VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT,
4787 VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT,
4802 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
4803 VK_ACCESS_2_SHADER_WRITE_BIT,
4804 VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT,
4805 VK_ACCESS_2_SHADER_READ_BIT,
4816 VkBufferMemoryBarrier2 barrier{ VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2 };
4817 barrier.srcStageMask = VK_PIPELINE_STAGE_2_CLEAR_BIT | VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT;
4818 barrier.srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT | VK_ACCESS_2_SHADER_STORAGE_READ_BIT;
4819 barrier.dstStageMask = VK_PIPELINE_STAGE_2_CLEAR_BIT;
4820 barrier.dstAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT;
4821 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
4822 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
4825 barrier.size = VK_WHOLE_SIZE;
4827 VkDependencyInfo depInfo{ VK_STRUCTURE_TYPE_DEPENDENCY_INFO };
4828 depInfo.bufferMemoryBarrierCount = 1;
4829 depInfo.pBufferMemoryBarriers = &barrier;
4841 VkBufferMemoryBarrier2 barrier{ VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2 };
4842 barrier.srcStageMask = VK_PIPELINE_STAGE_2_CLEAR_BIT | VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT;
4843 barrier.srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT | VK_ACCESS_2_SHADER_STORAGE_READ_BIT;
4844 barrier.dstStageMask = VK_PIPELINE_STAGE_2_CLEAR_BIT;
4845 barrier.dstAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT;
4846 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
4847 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
4850 barrier.size = VK_WHOLE_SIZE;
4852 VkDependencyInfo depInfo{ VK_STRUCTURE_TYPE_DEPENDENCY_INFO };
4853 depInfo.bufferMemoryBarrierCount = 1;
4854 depInfo.pBufferMemoryBarriers = &barrier;
4871 pipelineIndex = it->second;
4889 using namespace std::filesystem;
4892 switch ( pipelineName )
4896 .meshShaderPath = shaderDir /
"triangle.mesh.spv",
4897 .fragmentShaderPath = shaderDir /
"triangle_flat.frag.spv"
4902 .meshShaderPath = shaderDir /
"triangle.mesh.spv",
4903 .fragmentShaderPath = shaderDir /
"triangle.frag.spv"
4908 .meshShaderPath = shaderDir /
"triangle.mesh.spv",
4909 .fragmentShaderPath = shaderDir /
"triangle_movable_full.frag.spv"
4914 .meshShaderPath = shaderDir /
"triangle.mesh.spv",
4915 .fragmentShaderPath = shaderDir /
"triangle_movable_normals.frag.spv"
4920 .meshShaderPath = shaderDir /
"triangle.mesh.spv",
4921 .fragmentShaderPath = shaderDir /
"triangle_movable_l0.frag.spv"
4926 .meshShaderPath = shaderDir /
"triangle.mesh.spv",
4927 .fragmentShaderPath = shaderDir /
"triangle_movable_l1.frag.spv"
4932 .meshShaderPath = shaderDir /
"triangle.mesh.spv",
4933 .fragmentShaderPath = shaderDir /
"triangle_movable_l2.frag.spv"
4938 .meshShaderPath = shaderDir /
"triangle.mesh.spv",
4939 .fragmentShaderPath = shaderDir /
"triangle_movable.frag.spv"
4944 .meshShaderPath = shaderDir /
"triangle.mesh.spv",
4945 .fragmentShaderPath = shaderDir /
"triangle_static_lightmap.frag.spv"
4949 PLOGW <<
"Unknown PipelineNames enum: " <<
static_cast<int>(pipelineName) <<
", returning NORMALS_SHADER config";
4951 .meshShaderPath = shaderDir /
"triangle.mesh.spv",
4952 .fragmentShaderPath = shaderDir /
"triangle_movable_normals.frag.spv"
::EngineCore::LogCategory LogLOD("LogLOD", ::EngineCore::LogVerbosity::Info, ::EngineCore::LogVerbosity::Verbose)
#define VS_LOG_ONCE(Category, Verbosity, Format,...)
Log once - only logs the first time this line is executed.
#define VS_LOG(Category, Verbosity, Format,...)
Log a message with category and verbosity.
#define COMPUTE_SHADER_NAME(name)
Mode-specific macros for compute shader loading and execution guards.
constexpr uint32_t MAX_PIPELINES
constexpr uint32_t MAX_MESHLETS_PER_BIN
constexpr int MAX_FRAMES_IN_FLIGHT
constexpr uint32_t MAX_TEXTURE_COUNT
#define TRACY_ZONE_SCOPED_NAMED_D(stream_expr)
#define TRACY_ZONE_SCOPED_FUNCTION
#define TRACY_VK_ZONE_C(vk_context, cmd_buffer, name, color)
#define TRACY_VK_COLLECT(vk_context, cmd_buffer)
#define TRACY_ZONE_SCOPED_NAMED(name)
The application context is the core class which stores the basic openxr and vulkan objects.
The compute pass stores all resources which belong to a compute pipeline.
uint32_t getThreadCount() const
Gets the amount of threads this compute shader is running on on the GPU.
void bindDescriptorSets(VkCommandBuffer commandBuffer, uint32_t frameInFlightIndex)
Binds the descriptor set of a frame in flight.
VkPushConstantsInfo createPushConstantsInfo(uint32_t size, const void *pValues) const
Used to create preconfigured push constants where you only pass in the size of the push constant and ...
ComputePipeline * getComputePipeline()
Getter for the raw compute pipeline.
Wrapper for shader specialization data for compute pipelines. This usually only stores the thread cou...
void bind(VkCommandBuffer commandBuffer)
Binds this pipeline to an arbitrary command buffer.
std::vector< VkDescriptorSetLayoutBinding > build()
DescriptorSetLayoutBuilder & addStorageBuffer(uint32_t binding, VkShaderStageFlags stageFlags)
DescriptorSetLayoutBuilder & addCombinedImageSampler(uint32_t binding, VkShaderStageFlags stageFlags)
DescriptorSetLayoutBuilder & addUniformBuffer(uint32_t binding, VkShaderStageFlags stageFlags)
DescriptorSetLayoutBuilder & addStorageImageArray(uint32_t binding, uint32_t count, VkShaderStageFlags stageFlags)
DescriptorSetLayoutBuilder & addStorageImage(uint32_t binding, VkShaderStageFlags stageFlags)
The Descriptor set updater is used to create a list of descriptor set writes which are executed with ...
void update(VkDevice device) const
Updates the bindings on a descriptor sets.
DescriptorSetUpdater & addCombinedImageSampler(uint32_t binding, const VkDescriptorImageInfo *pImageInfo)
Adds a combined image sampler to the chain of updates.
DescriptorSetUpdater & addStorageImage(uint32_t binding, const VkDescriptorImageInfo *pImageInfo)
Adds a storage image to the chain of updates.
Specialization data for mesh shaders - provides screen resolution for small triangle culling.
static constexpr ConstexprPath engineShaders()
Path to engine shaders @lsp_source_path Engine/shaders.
Fluent builder for queue submissions with timeline and binary semaphores.
VkResult submit(VkQueue queue, VkFence fence=VK_NULL_HANDLE)
Builds and submits to the specified queue.
QueueSubmitBuilder & waitForResourceReuse(PipelineStage stage, VkPipelineStageFlags2 waitStages)
Convenience: wait for resource reuse (frames-in-flight pattern)
QueueSubmitBuilder & withCommandBuffer(VkCommandBuffer cmdBuffer)
Adds a command buffer to be executed.
QueueSubmitBuilder & signalBinary(VkSemaphore semaphore)
Signals a binary semaphore at completion (for present)
QueueSubmitBuilder & waitForBinary(VkSemaphore semaphore, VkPipelineStageFlags2 waitStages)
Adds a binary semaphore wait (for swapchain acquire, etc.)
QueueSubmitBuilder & waitForPrevious(PipelineStage stage, VkPipelineStageFlags2 waitStages)
Convenience: wait for previous frame's stage.
QueueSubmitBuilder & signalStage(PipelineStage stage)
Signals the timeline semaphore at a specific stage.
QueueSubmitBuilder & waitForCurrent(PipelineStage stage, VkPipelineStageFlags2 waitStages)
Convenience: wait for same frame's earlier stage.
The render process class consolidates all the resources that needs to be duplicated for each frame th...
void processTextureUpload()
const VulkanBuffer & getMeshletCounterBuffer() const
VkCommandBuffer & getGraphicsCommandBuffer()
const VulkanBuffer & getIndirectDrawBuffer() const
void updateComputeObjectCullingDescriptorSets(VkImageView previousFrameHiZView=VK_NULL_HANDLE) const
Updates object culling descriptor sets.
const VulkanBuffer & getPipelineCountersBuffer() const
void updateFrustumUBOData(const Headset *headset)
void updateEyeViewProjectionMatrices(const Headset *headset)
writes a view projection matrix to an eye
void updateMeshletDataBuffer()
const VulkanBuffer & getVSDrawCommandsBuffer() const
VkImageView getHiZPyramidFullView() const
void updateMeshRenderingData()
uint32_t getHiZMipLevels() const
const VulkanBuffer & getCullingFailedCounterBuffer() const
VkFence & getGraphicsCompleteFence()
VulkanStagedBufferSyncObjects uploadLodConfigBuffer()
Upload LOD config buffer to GPU.
const VulkanBuffer & getVSIndirectDrawCountBuffer() const
const VulkanBuffer & getLodClusterSurvivorCountBuffer() const
VkImageView getHiZPyramidMipView(uint32_t mipLevel) const
void updateLodConfig(const glm::vec3 &cameraPosition, const glm::mat4 &projMatrix, float nearPlane, float screenWidth, float screenHeight, float errorThresholdPixels=1.0f, bool ditherEnabled=true)
Update LOD configuration with camera and screen info Call this once per frame before dispatching prim...
void updateHiZViewProjectionData(const Headset *headset)
Updates Hi-Z view-projection data for occlusion culling Must be called after updateEyeViewProjectionM...
bool getTransferFenceSubmitted() const
VulkanBuffer & getBinnedVisibleMeshletIndexBuffer()
void setGraphicsFenceSubmitted(bool isSubmitted)
const VulkanBuffer & getVSGeometryCountersBuffer() const
VkDescriptorSet getGraphicsDescriptorSet() const
VkExtent2D getHiZExtent() const
void updateSSBO(const Renderer *renderer)
VkFence & getTransferCompleteFence()
const VulkanBuffer & getVSVisibleCountBuffer() const
VkImage getHiZPyramidImage() const
const VulkanBuffer & getVSDrawCountBuffer() const
VkCommandBuffer & getTransferCommandBuffer()
void updateFragmentTime(float time)
Sets the time value for time based fragment shader effects.
void setTransferFenceSubmitted(bool isSubmitted)
VkSemaphore getMirrorViewImageSemaphore() const
const VulkanBuffer & getPipelineBinOffsetsBuffer() const
void cleanupStagingBuffer()
uint32_t getEyeIndex() const
const VulkanBuffer & getVSIndirectDrawBuffer() const
Legacy VS path buffer getters (backwards compatibility)
std::optional< VulkanBuffer > meshUnpackingDataBuffer
DispatcherComputePass & getMeshletUnpackingDispatchComputePass()
void restartRenderCommandBuffers() const
Resets the command buffers of the active frame and begins a new write.
ComputePass & getMeshletUnpackingComputePass()
void createMeshletUnpackingResources()
std::vector< RenderProcess * > renderProcesses
The render processes.
void createHiZMipDescriptorSets()
std::optional< ComputePass > hiZGenerationComputePass
VkDependencyInfo getObjectCullingToMeshletUnpackingDispatchBarriers(Vulkan::BarrierBundle &bundle) const
ComputePass & getObjectCullingComputePass()
VkCommandPool getTransferCommandPool() const
gets the command pool used for recording data transfer at the beginning of a frame
int64_t getFrameElapsedMs() const
Gets the elapsed time since markFrameStart() was called. Used to check if the current frame has taken...
void updateHiZSPDDescriptorSets(uint32_t frameIndex)
std::optional< ComputePass > vsPrepareDrawComputePass_
void createObjectIDsBuffer()
void createPlaceholderBuffer()
Creates a buffer which can be used anywhere and holds one single 32 bit integer.
std::optional< ComputePass > hiZSPDComputePass
std::unordered_map< PipelineNames, GraphicsPipeline * > pipelinesByName
void initializeXrSwapchainFormats()
bool freezeCulling_
When true, culling data (frustum planes, Hi-Z VP) is frozen for debugging.
bool ensureOutputBufferSizes(uint32_t primitiveCount)
Ensures output buffers are sized to handle the given primitive count. Called by RenderingDataManager ...
void createObjectMeshletDataBuffer()
static constexpr std::chrono::milliseconds STALL_THRESHOLD_MS
Threshold for considering a frame as "stalled" (1 second)
std::optional< ComputePass > binningAllocatorComputePass
Stage 1: Binning allocator.
VkPipeline vsGraphicsPipeline_
VkDependencyInfo getMeshletCullingToPrepareDrawBarriers()
const VulkanBuffer & getObjectCullingDataBuffer() const
VkDescriptorSetLayout graphicsDescriptorSetLayout
RenderProcess * getCurrentRenderProcess() const
Gets the render process of the current frame.
std::unique_ptr< TimelineSynchronizer > timelineSynchronizer_
const VulkanBuffer & getObjectMeshletDataBuffer() const
uint64_t getTimelineSemaphoreValue() const
void recordVertexShaderDraws(size_t swapChainImageIndex) const
void setFreezeCulling(bool freeze)
Freezes culling data (frustum planes, Hi-Z view-projection)
void markFrameStart()
Marks the start of a new frame for stall detection. Call this at the beginning of each render frame.
std::optional< ComputePass > drawPreparationComputePass
std::vector< VulkanStagedBufferSyncObjects > syncCopyObjects
std::unordered_map< GraphicsPipeline *, uint32_t > pipelineIndices
const VulkanBuffer & getCounterBuffer() const
void updateViewMatrix()
Requests an update of the current render processes view matrix. The matrix is pulled from the headset...
void recordXrSwapchainImageFinishedWritingBarrier(uint32_t swapChainImageIndex) const
VkDependencyInfo getMeshletCullingDispatchToMeshletCullingBarriers()
VkPipelineLayout graphicsPipelineLayout
void renderToXr(size_t swapChainImageIndex, float time)
void resetMeshletCullingDispatchBuffers()
std::optional< VulkanBuffer > hiZSPDAtomicBuffer
bool useVertexShaderPath_
VkPipelineLayout computeObjectCullingPipelineLayout
The pipeline layout.
void initializeGpuBuffers() const
ComputePass & getMeshletCullingComputePass()
const VulkanBuffer & getPlaceholderUniformBuffer() const
const TimelineSynchronizer & getTimelineSynchronizer() const
Gets the timeline synchronizer for managing frame synchronization.
void initializeFrameIndices()
BS_tracy::tracy_thread_pool< BS_tracy::tp::none > updateThreadPool
void createVertexShaderPathResources()
void createHiZSPDResources()
VkCommandBuffer getCurrentRenderingCommandBuffer() const
DispatcherComputePass & getMeshletCullingDispatchComputePass()
const std::vector< GraphicsPipeline * > & getGraphicsPipelines() const
Gets the list of all graphics pipelines.
void createHiZGenerationResources()
std::optional< VulkanBuffer > objectMeshletDataBuffer
void recordTransfer(float time)
void submitGraphics(uint32_t swapChainImageIndex, VkSemaphore mirrorAcquireSemaphore=VK_NULL_HANDLE)
void cleanup()
Cleans up all resources of the renderer.
void createPlaceholderUniformBuffer()
VkCommandPool vkGraphicsCommandPool
The graphics and present command pool.
void createCounterBuffer()
void recordPass2RenderPass(size_t swapChainImageIndex)
Records the Pass 2 render pass using dynamic rendering Uses VK_ATTACHMENT_LOAD_OP_LOAD to preserve Pa...
std::vector< VkPushConstantRange > pushConstants
void recordVSInstancedDrawingPipeline()
std::vector< GraphicsPipeline * > graphicsPipelines
The pipelines.
VkSemaphore getTimelineSemaphore() const
Getter for the main timeline renderer semaphore.
void recordVertexShaderDrawsDepthOnly(size_t swapChainImageIndex) const
std::optional< VulkanBuffer > objectCullingDataBuffer
VkCommandPool vkTransferCommandPool
The transfer command pool for all commands submitted to the transfer queue.
void createHiZSPDDescriptorSets()
std::unique_ptr< RenderingDataManager > renderingDataManager
VkCommandBuffer getCurrentTransferCommandBuffer() const
Gets the current frame in flight and retrieves the transfer command buffer.
const VulkanBuffer & getDispatchBuffer() const
std::chrono::steady_clock::time_point lastFrameStartTime_
Time when the last frame started, for stall detection.
~Renderer()
cleans up the object
VkPipeline vsDepthOnlyPipeline_
VkDependencyInfo getMeshletUnpackingDispatchToMeshletUnpackingBarriers(Vulkan::BarrierBundle &bundle) const
Renderer(ApplicationContext *context=nullptr, Headset *headset=nullptr, const Engine *engine=nullptr)
Constructor.
std::optional< ComputePass > objectCullingComputePass
The descriptor set layout.
void resetMeshletUnpackingDispatchBuffers()
std::optional< VulkanBuffer > counterBuffer
void updateHiZMipDescriptorSets(uint32_t frameIndex)
void createPrepareDrawResources()
VkCommandPool getGraphicsCommandPool() const
gets the graphics command pool
void uploadFrameData(float time)
void prepareTransferSubmission(uint32_t frameIndex) const
VkSemaphore getCurrentPresentableSemaphore(uint32_t swapchainImageIndex) const
void createObjectCullingDataBuffer()
void createVSInstancedDrawingResources()
const std::unique_ptr< RenderingDataManager > & getRenderingDataManager() const
Getter for the rendering data manager.
std::optional< ComputePass > vsBinningAllocatorComputePass_
void advanceFrameIndices()
advances the frame indices for the next frame in flight
void createMeshletCullingDispatcherResources()
Creates the compute pipeline for the meshlet culling stage. This should only be called after the mesh...
VkPipelineLayout prepareDrawsComputePipelineLayout
VkDescriptorPool hiZDescriptorPool
uint64_t renderedFrameCounter
void allocateDescriptors()
allocates the first batch of mesh data to the shaders
std::optional< VulkanBuffer > objectIDsBuffer
ComputePass & getDrawPreparationComputePass()
int findExistingPipeline(const std::string &meshShader, const std::string &fragShader, const PipelineMaterialPayload &pipelineData) const
Searches for the first existing pipeline which has the same vertex and fragment shader.
void createPrimitiveCullingResources()
const VulkanBuffer & getObjectIDsBuffer() const
const VulkanBuffer & getMeshUnpackingDataBuffer() const
std::array< VkDescriptorSet, MAX_FRAMES_IN_FLIGHT > hiZSPDDescriptorSets
bool shouldSkipMirrorView()
Checks if mirror view should be skipped this frame.
const VulkanBuffer & getPlaceholderBuffer() const
std::vector< GraphicsPipeline * > depthOnlyGraphicsPipelines
ComputePass & getVSPrepareDrawComputePass()
static constexpr int SKIP_FRAMES_AFTER_STALL
Number of frames to skip after detecting a stall (covers all swapchain images)
VkDescriptorPool descriptorPool
The descriptor pool for all descriptors of the renderer.
bool getPipelineIndex(GraphicsPipeline *pipeline, uint32_t &pipelineIndex) const
Gets the index of a pipeline.
void getCurrentTracyVkContext() const
void createDispatchBuffer()
std::optional< VulkanBuffer > placeholderBuffer
std::optional< DispatcherComputePass > meshletCullingDispatchComputePass
std::optional< VulkanBuffer > dispatchBuffer
void createMeshUnpackingDataBuffer()
std::vector< VkSemaphore > renderFinishedSemaphores
void createBinningAllocatorResources()
void syncTimelineAfterPause()
Synchronizes the frame counter with the timeline semaphore after pausing.
std::optional< DispatcherComputePass > meshletUnpackingDispatchComputePass
ComputePass & getVSInstanceUnpackingComputePass()
void recordHiZGenerationSPD()
void recordPass2Culling(size_t swapChainImageIndex)
Records Pass 2 of two-pass occlusion culling Re-tests objects that failed Pass 1 Hi-Z against the new...
std::optional< VulkanBuffer > placeholderUniformBuffer
std::optional< ComputePass > vsInstanceUnpackingComputePass_
VkSemaphore getCurrentMirrorViewSemaphore() const
std::array< std::array< VkDescriptorSet, MAX_HIZ_MIP_LEVELS >, MAX_FRAMES_IN_FLIGHT > hiZMipDescriptorSets
void submitInitialTransfers()
ComputePass & getVSBinningAllocatorComputePass()
void createMeshletUnpackingDispatcherResources()
Creates the complete pipeline for the meshlet unpacker. This should only be called after the buffer h...
ComputePass & getBinningAllocatorComputePass()
void recordXrSwapchainImageWritableBarrier(uint32_t swapChainImageIndex) const
int skipMirrorFramesRemaining_
bool isInStallRecovery() const
Checks if we're currently in stall recovery mode. During stall recovery, extra GPU synchronization sh...
ApplicationContext * context
static PipelineConfig getPipelineConfig(PipelineNames pipelineName)
Gets the static configuration for a given pipeline type Returns shader paths and pipeline data for th...
bool useVSInstancedDrawing_
void updateCpuRenderResources(float time)
Updates all data for gpu frame buffers.
std::vector< VkCommandBuffer > getGraphicsCommandBuffers() const
Gets all graphics command buffers from all owned EngineCore::RenderProcess.
VkDependencyInfo getMeshletUnpackingToMeshletCullingDispatchBarriers(Vulkan::BarrierBundle &bundle)
std::optional< ComputePass > meshletUnpackingComputePass
std::optional< ComputePass > meshletCullingComputePass
void recordRenderPass(size_t swapChainImageIndex)
void createMeshletCullingResources()
void recordHiZGeneration()
Records the Hi-Z pyramid generation compute pass Should be called after the render pass completes.
Centralized timeline semaphore management for the rendering pipeline.
RAII wrapper for Vulkan buffer and device memory.
VkBuffer getBuffer() const
void destroyShaders(VkDevice device) override
VkShaderModule getFragmentShader() const
VkShaderModule getVertexShader() const
static VkResult createPipelineLayout(VkDevice device, const VkPipelineLayoutCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkPipelineLayout *pPipelineLayout, const std::string &name)
static void endSingleTimeCommands(VkDevice device, VkQueue graphicsQueue, VkCommandPool commandPool, VkCommandBuffer commandBuffer)
static std::string strIsValid(void *object)
static void setObjectName(VkDevice device, VulkanObjectType objectHandle, const std::string &name)
static VkDescriptorBufferInfo fullBufferInfo(VkBuffer buffer)
static VkResult createDescriptorPool(VkDevice device, const VkDescriptorPoolCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDescriptorPool *pDescriptorPool, const std::string &name)
static const VulkanFunctions & getFunctions()
static VkResult createDescriptorSetLayout(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDescriptorSetLayout *pSetLayout, const std::string &name)
static VkCommandBuffer beginSingleTimeCommands(VkDevice device, VkCommandPool commandPool)
VkDependencyInfo getDependencyInfo() const
void addComputeBufferBarrier(VkPipelineStageFlags2 srcStageMask, VkAccessFlags2 srcAccessMask, VkPipelineStageFlags2 dstStageMask, VkAccessFlags2 dstAccessMask, const EngineCore::VulkanBuffer &buffer)
constexpr uint32_t Turquoise
constexpr uint32_t Orange
@ MATERIAL_DYNAMIC_TEXTURES
@ MESHLET_TO_OBJECT_MAP_BUFFER
@ MATERIAL_STATIC_LIGHTMAP
@ MATERIAL_DIFFUSE_FLAT_COLOR
@ MESHLET_TRIANGLES_BUFFER
@ BINNED_VISIBLE_MESHLET_INDEX_BUFFER
@ MATERIAL_MOVABLE_DIFFUSE
@ MATERIAL_DIFFUSE_SHADER
@ MESHLET_CULLING_DISPATCH_COUNTER
@ MESHLET_CULLING_DISPATCH_BUFFER
@ MESHLET_CULLING_INDICES
@ MESHLET_CULLING_BINNED_RENDERING
@ MESHLET_CULLING_FRUSTUM_PLANES
@ MESHLET_UNPACKING_DISPATCH_COUNTER
@ MESHLET_UNPACKING_DISPATCH_BUFFER
@ MESHLET_UNPACKING_DISPATCH_LOD_COUNTER
@ UNPACKING_SURVIVOR_COUNT
@ PREPARE_DRAW_MESHLET_COUNTER
@ PREPARE_DRAW_INDIRECT_DRAW
@ BINNING_PIPELINE_COUNTERS
@ BINNING_PRIMITIVE_MESHLET_DATA
@ BINNING_CULLING_SURVIVORS
@ PRIMITIVE_INSTANCE_CULLING_DATA
@ PRIMITIVE_CULLING_FRUSTUM_PLANES
@ PRIMITIVE_CULLING_FAILED_COUNTER
@ PRIMITIVE_CULLING_FAILED
@ PRIMITIVE_PER_OBJECT_DATA
@ PRIMITIVE_CULLING_COUNTER
@ PRIMITIVE_MESH_GEOMETRY_DATA
@ PRIMITIVE_MESH_UNPACKING_DATA
@ PRIMITIVE_SINGLE_MESHLET_GEO
@ PRIMITIVE_VS_INDIRECT_COUNT
@ PRIMITIVE_VS_INDIRECT_DRAW
@ VS_BINNING_VISIBLE_COUNT
@ VS_BINNING_VISIBLE_INSTANCES
@ VS_BINNING_GEOMETRY_COUNTERS
@ VS_BINNING_INSTANCE_CULLING_DATA
@ VS_BINNING_MESH_GEOMETRY_DATA
@ VS_UNPACKING_ALLOCATIONS
@ VS_UNPACKING_VISIBLE_COUNT
@ VS_UNPACKING_INSTANCE_IDS
@ VS_PREPARE_SINGLE_MESHLET_GEO
@ VS_PREPARE_GEOMETRY_COUNTERS
@ VS_PREPARE_INDIRECT_DRAWS
Log category system implementation.
constexpr uint32_t PIPELINE_STAGE_COUNT
@ Warning
Potential issue.
Static configuration for a graphics pipeline Defines which shaders to use for a given PipelineNames e...
std::filesystem::path fragmentShaderPath
PipelineMaterialPayload pipelineData
std::filesystem::path meshShaderPath
A render target which contains all resources to access the rendered image.
Used to tell the pipeline which objects are shaded with which shader.
The fundamental building block of all meshes in this engine.
PFN_vkCmdEndConditionalRenderingEXT vkCmdEndConditionalRenderingEXT
PFN_vkCmdDrawMeshTasksIndirectEXT vkCmdDrawMeshTasksIndirectEXT
PFN_vkCmdBeginConditionalRenderingEXT vkCmdBeginConditionalRenderingEXT