11/*
22* Vulkan Example - Compute shader culling and LOD using indirect rendering
33*
4- * Copyright (C) 2016-2023 by Sascha Willems - www.saschawillems.de
4+ * Copyright (C) 2016-2025 by Sascha Willems - www.saschawillems.de
55*
66* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
77*
1414
1515// Total number of objects (^3) in the scene
1616#if defined(__ANDROID__)
17- # define OBJECT_COUNT 32
17+ constexpr auto OBJECT_COUNT 32 ;
1818#else
19- # define OBJECT_COUNT 64
19+ constexpr auto OBJECT_COUNT = 64 ;
2020#endif
2121
22- # define MAX_LOD_LEVEL 5
22+ constexpr auto MAX_LOD_LEVEL = 5 ;
2323
2424class VulkanExample : public VulkanExampleBase
2525{
@@ -31,8 +31,8 @@ class VulkanExample : public VulkanExampleBase
3131
3232 // Per-instance data block
3333 struct InstanceData {
34- glm::vec3 pos;
35- float scale;
34+ glm::vec3 pos{ 0 . 0f } ;
35+ float scale{ 1 . 0f } ;
3636 };
3737
3838 // Contains the instanced data
@@ -61,13 +61,10 @@ class VulkanExample : public VulkanExampleBase
6161 vks::Buffer scene;
6262 } uniformData;
6363
64- struct {
65- VkPipeline plants;
66- } pipelines;
67-
68- VkPipelineLayout pipelineLayout;
69- VkDescriptorSet descriptorSet;
70- VkDescriptorSetLayout descriptorSetLayout;
64+ VkPipelineLayout pipelineLayout{ VK_NULL_HANDLE };
65+ VkPipeline pipeline{ VK_NULL_HANDLE };
66+ VkDescriptorSetLayout descriptorSetLayout{ VK_NULL_HANDLE };
67+ VkDescriptorSet descriptorSet{ VK_NULL_HANDLE };
7168
7269 // Resources for the compute part of the example
7370 struct {
@@ -81,7 +78,7 @@ class VulkanExample : public VulkanExampleBase
8178 VkDescriptorSet descriptorSet; // Compute shader bindings
8279 VkPipelineLayout pipelineLayout; // Layout of the compute pipeline
8380 VkPipeline pipeline; // Compute pipeline for updating particle positions
84- } compute;
81+ } compute{} ;
8582
8683 // View frustum for culling invisible objects
8784 vks::Frustum frustum;
@@ -101,7 +98,7 @@ class VulkanExample : public VulkanExampleBase
10198 ~VulkanExample ()
10299 {
103100 if (device) {
104- vkDestroyPipeline (device, pipelines. plants , nullptr );
101+ vkDestroyPipeline (device, pipeline , nullptr );
105102 vkDestroyPipelineLayout (device, pipelineLayout, nullptr );
106103 vkDestroyDescriptorSetLayout (device, descriptorSetLayout, nullptr );
107104 instanceBuffer.destroy ();
@@ -124,13 +121,15 @@ class VulkanExample : public VulkanExampleBase
124121 if (deviceFeatures.multiDrawIndirect ) {
125122 enabledFeatures.multiDrawIndirect = VK_TRUE;
126123 }
124+ // This is required for for using firstInstance
125+ enabledFeatures.drawIndirectFirstInstance = VK_TRUE;
127126 }
128127
129128 void buildCommandBuffers ()
130129 {
131130 VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo ();
132131
133- VkClearValue clearValues[2 ];
132+ VkClearValue clearValues[2 ]{} ;
134133 clearValues[0 ].color = { { 0 .18f , 0 .27f , 0 .5f , 0 .0f } };
135134 clearValues[1 ].depthStencil = { 1 .0f , 0 };
136135
@@ -186,7 +185,7 @@ class VulkanExample : public VulkanExampleBase
186185 vkCmdBindDescriptorSets (drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0 , 1 , &descriptorSet, 0 , NULL );
187186
188187 // Mesh containing the LODs
189- vkCmdBindPipeline (drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines. plants );
188+ vkCmdBindPipeline (drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline );
190189 vkCmdBindVertexBuffers (drawCmdBuffers[i], 0 , 1 , &lodModel.vertices .buffer , offsets);
191190 vkCmdBindVertexBuffers (drawCmdBuffers[i], 1 , 1 , &instanceBuffer.buffer , offsets);
192191
@@ -400,6 +399,7 @@ class VulkanExample : public VulkanExampleBase
400399 inputState.vertexBindingDescriptionCount = static_cast <uint32_t >(bindingDescriptions.size ());
401400 inputState.vertexAttributeDescriptionCount = static_cast <uint32_t >(attributeDescriptions.size ());
402401
402+ // Indirect (and instanced) pipeline
403403 VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = vks::initializers::pipelineInputAssemblyStateCreateInfo (VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0 , VK_FALSE);
404404 VkPipelineRasterizationStateCreateInfo rasterizationState = vks::initializers::pipelineRasterizationStateCreateInfo (VK_POLYGON_MODE_FILL, VK_CULL_MODE_BACK_BIT, VK_FRONT_FACE_COUNTER_CLOCKWISE, 0 );
405405 VkPipelineColorBlendAttachmentState blendAttachmentState = vks::initializers::pipelineColorBlendAttachmentState (0xf , VK_FALSE);
@@ -409,9 +409,11 @@ class VulkanExample : public VulkanExampleBase
409409 VkPipelineMultisampleStateCreateInfo multisampleState = vks::initializers::pipelineMultisampleStateCreateInfo (VK_SAMPLE_COUNT_1_BIT, 0 );
410410 std::vector<VkDynamicState> dynamicStateEnables = {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR};
411411 VkPipelineDynamicStateCreateInfo dynamicState = vks::initializers::pipelineDynamicStateCreateInfo (dynamicStateEnables);
412- std::array<VkPipelineShaderStageCreateInfo, 2 > shaderStages;
413-
414412 VkGraphicsPipelineCreateInfo pipelineCreateInfo = vks::initializers::pipelineCreateInfo (pipelineLayout, renderPass);
413+ std::array<VkPipelineShaderStageCreateInfo, 2 > shaderStages = {
414+ loadShader (getShadersPath () + " computecullandlod/indirectdraw.vert.spv" , VK_SHADER_STAGE_VERTEX_BIT),
415+ loadShader (getShadersPath () + " computecullandlod/indirectdraw.frag.spv" , VK_SHADER_STAGE_FRAGMENT_BIT)
416+ };
415417 pipelineCreateInfo.pVertexInputState = &inputState;
416418 pipelineCreateInfo.pInputAssemblyState = &inputAssemblyState;
417419 pipelineCreateInfo.pRasterizationState = &rasterizationState;
@@ -422,11 +424,7 @@ class VulkanExample : public VulkanExampleBase
422424 pipelineCreateInfo.pDynamicState = &dynamicState;
423425 pipelineCreateInfo.stageCount = static_cast <uint32_t >(shaderStages.size ());
424426 pipelineCreateInfo.pStages = shaderStages.data ();
425-
426- // Indirect (and instanced) pipeline for the plants
427- shaderStages[0 ] = loadShader (getShadersPath () + " computecullandlod/indirectdraw.vert.spv" , VK_SHADER_STAGE_VERTEX_BIT);
428- shaderStages[1 ] = loadShader (getShadersPath () + " computecullandlod/indirectdraw.frag.spv" , VK_SHADER_STAGE_FRAGMENT_BIT);
429- VK_CHECK_RESULT (vkCreateGraphicsPipelines (device, pipelineCache, 1 , &pipelineCreateInfo, nullptr , &pipelines.plants ));
427+ VK_CHECK_RESULT (vkCreateGraphicsPipelines (device, pipelineCache, 1 , &pipelineCreateInfo, nullptr , &pipeline));
430428 }
431429
432430 void prepareBuffers ()
@@ -555,7 +553,7 @@ class VulkanExample : public VulkanExampleBase
555553 uint32_t n = 0 ;
556554 for (auto node : lodModel.nodes )
557555 {
558- LOD lod;
556+ LOD lod{} ;
559557 lod.firstIndex = node->mesh ->primitives [0 ]->firstIndex ; // First index for this LOD
560558 lod.indexCount = node->mesh ->primitives [0 ]->indexCount ; // Index count for this LOD
561559 lod.distance = 5 .0f + n * 5 .0f ; // Starting distance (to viewer) for this LOD
@@ -675,7 +673,7 @@ class VulkanExample : public VulkanExampleBase
675673 &compute.lodLevelsBuffers .descriptor )
676674 };
677675
678- vkUpdateDescriptorSets (device, static_cast <uint32_t >(computeWriteDescriptorSets.size ()), computeWriteDescriptorSets.data (), 0 , NULL );
676+ vkUpdateDescriptorSets (device, static_cast <uint32_t >(computeWriteDescriptorSets.size ()), computeWriteDescriptorSets.data (), 0 , nullptr );
679677
680678 // Create pipeline
681679 VkComputePipelineCreateInfo computePipelineCreateInfo = vks::initializers::computePipelineCreateInfo (compute.pipelineLayout , 0 );
@@ -689,7 +687,7 @@ class VulkanExample : public VulkanExampleBase
689687
690688 uint32_t specializationData = static_cast <uint32_t >(lodModel.nodes .size ()) - 1 ;
691689
692- VkSpecializationInfo specializationInfo;
690+ VkSpecializationInfo specializationInfo{} ;
693691 specializationInfo.mapEntryCount = 1 ;
694692 specializationInfo.pMapEntries = &specializationEntry;
695693 specializationInfo.dataSize = sizeof (specializationData);
0 commit comments