1
1
/*
2
2
* Vulkan Example - Compute shader culling and LOD using indirect rendering
3
3
*
4
- * Copyright (C) 2016-2023 by Sascha Willems - www.saschawillems.de
4
+ * Copyright (C) 2016-2025 by Sascha Willems - www.saschawillems.de
5
5
*
6
6
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
7
7
*
14
14
15
15
// Total number of objects (^3) in the scene
16
16
#if defined(__ANDROID__)
17
- # define OBJECT_COUNT 32
17
+ constexpr auto OBJECT_COUNT 32 ;
18
18
#else
19
- # define OBJECT_COUNT 64
19
+ constexpr auto OBJECT_COUNT = 64 ;
20
20
#endif
21
21
22
- # define MAX_LOD_LEVEL 5
22
+ constexpr auto MAX_LOD_LEVEL = 5 ;
23
23
24
24
class VulkanExample : public VulkanExampleBase
25
25
{
@@ -31,8 +31,8 @@ class VulkanExample : public VulkanExampleBase
31
31
32
32
// Per-instance data block
33
33
struct InstanceData {
34
- glm::vec3 pos;
35
- float scale;
34
+ glm::vec3 pos{ 0 . 0f } ;
35
+ float scale{ 1 . 0f } ;
36
36
};
37
37
38
38
// Contains the instanced data
@@ -61,13 +61,10 @@ class VulkanExample : public VulkanExampleBase
61
61
vks::Buffer scene;
62
62
} uniformData;
63
63
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 };
71
68
72
69
// Resources for the compute part of the example
73
70
struct {
@@ -81,7 +78,7 @@ class VulkanExample : public VulkanExampleBase
81
78
VkDescriptorSet descriptorSet; // Compute shader bindings
82
79
VkPipelineLayout pipelineLayout; // Layout of the compute pipeline
83
80
VkPipeline pipeline; // Compute pipeline for updating particle positions
84
- } compute;
81
+ } compute{} ;
85
82
86
83
// View frustum for culling invisible objects
87
84
vks::Frustum frustum;
@@ -101,7 +98,7 @@ class VulkanExample : public VulkanExampleBase
101
98
~VulkanExample ()
102
99
{
103
100
if (device) {
104
- vkDestroyPipeline (device, pipelines. plants , nullptr );
101
+ vkDestroyPipeline (device, pipeline , nullptr );
105
102
vkDestroyPipelineLayout (device, pipelineLayout, nullptr );
106
103
vkDestroyDescriptorSetLayout (device, descriptorSetLayout, nullptr );
107
104
instanceBuffer.destroy ();
@@ -124,13 +121,15 @@ class VulkanExample : public VulkanExampleBase
124
121
if (deviceFeatures.multiDrawIndirect ) {
125
122
enabledFeatures.multiDrawIndirect = VK_TRUE;
126
123
}
124
+ // This is required for for using firstInstance
125
+ enabledFeatures.drawIndirectFirstInstance = VK_TRUE;
127
126
}
128
127
129
128
void buildCommandBuffers ()
130
129
{
131
130
VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo ();
132
131
133
- VkClearValue clearValues[2 ];
132
+ VkClearValue clearValues[2 ]{} ;
134
133
clearValues[0 ].color = { { 0 .18f , 0 .27f , 0 .5f , 0 .0f } };
135
134
clearValues[1 ].depthStencil = { 1 .0f , 0 };
136
135
@@ -186,7 +185,7 @@ class VulkanExample : public VulkanExampleBase
186
185
vkCmdBindDescriptorSets (drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0 , 1 , &descriptorSet, 0 , NULL );
187
186
188
187
// 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 );
190
189
vkCmdBindVertexBuffers (drawCmdBuffers[i], 0 , 1 , &lodModel.vertices .buffer , offsets);
191
190
vkCmdBindVertexBuffers (drawCmdBuffers[i], 1 , 1 , &instanceBuffer.buffer , offsets);
192
191
@@ -400,6 +399,7 @@ class VulkanExample : public VulkanExampleBase
400
399
inputState.vertexBindingDescriptionCount = static_cast <uint32_t >(bindingDescriptions.size ());
401
400
inputState.vertexAttributeDescriptionCount = static_cast <uint32_t >(attributeDescriptions.size ());
402
401
402
+ // Indirect (and instanced) pipeline
403
403
VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = vks::initializers::pipelineInputAssemblyStateCreateInfo (VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, 0 , VK_FALSE);
404
404
VkPipelineRasterizationStateCreateInfo rasterizationState = vks::initializers::pipelineRasterizationStateCreateInfo (VK_POLYGON_MODE_FILL, VK_CULL_MODE_BACK_BIT, VK_FRONT_FACE_COUNTER_CLOCKWISE, 0 );
405
405
VkPipelineColorBlendAttachmentState blendAttachmentState = vks::initializers::pipelineColorBlendAttachmentState (0xf , VK_FALSE);
@@ -409,9 +409,11 @@ class VulkanExample : public VulkanExampleBase
409
409
VkPipelineMultisampleStateCreateInfo multisampleState = vks::initializers::pipelineMultisampleStateCreateInfo (VK_SAMPLE_COUNT_1_BIT, 0 );
410
410
std::vector<VkDynamicState> dynamicStateEnables = {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR};
411
411
VkPipelineDynamicStateCreateInfo dynamicState = vks::initializers::pipelineDynamicStateCreateInfo (dynamicStateEnables);
412
- std::array<VkPipelineShaderStageCreateInfo, 2 > shaderStages;
413
-
414
412
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
+ };
415
417
pipelineCreateInfo.pVertexInputState = &inputState;
416
418
pipelineCreateInfo.pInputAssemblyState = &inputAssemblyState;
417
419
pipelineCreateInfo.pRasterizationState = &rasterizationState;
@@ -422,11 +424,7 @@ class VulkanExample : public VulkanExampleBase
422
424
pipelineCreateInfo.pDynamicState = &dynamicState;
423
425
pipelineCreateInfo.stageCount = static_cast <uint32_t >(shaderStages.size ());
424
426
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));
430
428
}
431
429
432
430
void prepareBuffers ()
@@ -555,7 +553,7 @@ class VulkanExample : public VulkanExampleBase
555
553
uint32_t n = 0 ;
556
554
for (auto node : lodModel.nodes )
557
555
{
558
- LOD lod;
556
+ LOD lod{} ;
559
557
lod.firstIndex = node->mesh ->primitives [0 ]->firstIndex ; // First index for this LOD
560
558
lod.indexCount = node->mesh ->primitives [0 ]->indexCount ; // Index count for this LOD
561
559
lod.distance = 5 .0f + n * 5 .0f ; // Starting distance (to viewer) for this LOD
@@ -675,7 +673,7 @@ class VulkanExample : public VulkanExampleBase
675
673
&compute.lodLevelsBuffers .descriptor )
676
674
};
677
675
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 );
679
677
680
678
// Create pipeline
681
679
VkComputePipelineCreateInfo computePipelineCreateInfo = vks::initializers::computePipelineCreateInfo (compute.pipelineLayout , 0 );
@@ -689,7 +687,7 @@ class VulkanExample : public VulkanExampleBase
689
687
690
688
uint32_t specializationData = static_cast <uint32_t >(lodModel.nodes .size ()) - 1 ;
691
689
692
- VkSpecializationInfo specializationInfo;
690
+ VkSpecializationInfo specializationInfo{} ;
693
691
specializationInfo.mapEntryCount = 1 ;
694
692
specializationInfo.pMapEntries = &specializationEntry;
695
693
specializationInfo.dataSize = sizeof (specializationData);
0 commit comments