Added path for devices that don't support multiDrawIndirect, resource cleanup on destruction
This commit is contained in:
parent
3dea031e2c
commit
067d474796
3 changed files with 37 additions and 9 deletions
|
|
@ -118,7 +118,7 @@ Shows the use of instancing for rendering many copies of the same mesh using dif
|
||||||
## [Indirect drawing](indirectdraw/)
|
## [Indirect drawing](indirectdraw/)
|
||||||
<img src="./screenshots/indirectdraw.jpg" height="96px" align="right">
|
<img src="./screenshots/indirectdraw.jpg" height="96px" align="right">
|
||||||
|
|
||||||
This example renders thousands of instanced objects with different geometries using only one single indirect draw call. Unlike direct drawing function, indirect drawing functions take their draw commands from a buffer object containing information like index cound, index offset and number of instances to draw.
|
This example renders thousands of instanced objects with different geometries using only one single indirect draw call (if ```multiDrawIndirect``` is supported). Unlike direct drawing function, indirect drawing functions take their draw commands from a buffer object containing information like index cound, index offset and number of instances to draw.
|
||||||
|
|
||||||
Shows how to generate and render such an indirect draw command buffer that is staged to the device. Indirect draw buffers are the base for generating and updating draw commands on the GPU using shaders.
|
Shows how to generate and render such an indirect draw command buffer that is staged to the device. Indirect draw buffers are the base for generating and updating draw commands on the GPU using shaders.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,7 @@
|
||||||
Issue multiple instanced draws for different meshes in one single draw call using indirect draw commands.
|
Issue multiple instanced draws for different meshes in one single draw call using indirect draw commands.
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
The example requires a GPU that supports the [`multiDrawIndirect`](http://vulkan.gpuinfo.org/listreports.php?feature=multiDrawIndirect) feature. If this feature is not available, the `drawCount` parameter for the `vkCmdDrawIndexedIndirect` call must be 1.
|
If the [`multiDrawIndirect`](http://vulkan.gpuinfo.org/listreports.php?feature=multiDrawIndirect) feature is supported, only one draw call is issued for the plants. If this feature is not available multiple indirect draw commands are used. ***Note:*** When issuing many draw counts also make sure to stay within the limitations of [`maxDrawIndirectCount`](http://vulkan.gpuinfo.org/listreports.php?limit=maxDrawIndirectCount).
|
||||||
When issuing many draw counts also make sure to stay within the limitations of [`maxDrawIndirectCount`](http://vulkan.gpuinfo.org/listreports.php?limit=maxDrawIndirectCount).
|
|
||||||
|
|
||||||
## Description
|
## Description
|
||||||
|
|
||||||
|
|
@ -74,7 +73,7 @@ vulkanDevice->copyBuffer(&stagingBuffer, &indirectCommandsBuffer, queue);
|
||||||
To use a buffer for indirect draw commands you need to specify the ```VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT``` usage flag at creation time. As the buffer is never again changed on the host side we stage it to the GPU to maximize performance.
|
To use a buffer for indirect draw commands you need to specify the ```VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT``` usage flag at creation time. As the buffer is never again changed on the host side we stage it to the GPU to maximize performance.
|
||||||
|
|
||||||
### Rendering
|
### Rendering
|
||||||
Issuing the actual indirect draw command is pretty straightforward:
|
If the [`multiDrawIndirect`](http://vulkan.gpuinfo.org/listreports.php?feature=multiDrawIndirect) is supported, we can issue all indirect draws with one single draw call:
|
||||||
```cpp
|
```cpp
|
||||||
void buildCommandBuffers()
|
void buildCommandBuffers()
|
||||||
{
|
{
|
||||||
|
|
@ -97,5 +96,14 @@ for (auto indirectCmd : indirectCommands)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If the GPU does not support ```multiDrawIndirect``` we have to issue the indirect draw commands one-by-one using a buffer offset instead:
|
||||||
|
```cpp
|
||||||
|
for (auto j = 0; j < indirectCommands.size(); j++)
|
||||||
|
{
|
||||||
|
vkCmdDrawIndexedIndirect(drawCmdBuffers[i], indirectCommandsBuffer.buffer, j * sizeof(VkDrawIndexedIndirectCommand), 1, sizeof(VkDrawIndexedIndirectCommand));
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### Acknowledgements
|
### Acknowledgements
|
||||||
- Plant and foliage models by [Hugues Muller](http://www.yughues-folio.com/)
|
- Plant and foliage models by [Hugues Muller](http://www.yughues-folio.com/)
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ public:
|
||||||
} meshes;
|
} meshes;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
vkTools::VulkanTexture colorMap;
|
vkTools::VulkanTexture plants;
|
||||||
vkTools::VulkanTexture ground;
|
vkTools::VulkanTexture ground;
|
||||||
} textures;
|
} textures;
|
||||||
|
|
||||||
|
|
@ -136,10 +136,14 @@ public:
|
||||||
{
|
{
|
||||||
vkDestroyPipeline(device, pipelines.plants, nullptr);
|
vkDestroyPipeline(device, pipelines.plants, nullptr);
|
||||||
vkDestroyPipeline(device, pipelines.ground, nullptr);
|
vkDestroyPipeline(device, pipelines.ground, nullptr);
|
||||||
|
vkDestroyPipeline(device, pipelines.skysphere, nullptr);
|
||||||
vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
|
vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
|
||||||
vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);
|
vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);
|
||||||
vkMeshLoader::freeMeshBufferResources(device, &meshes.plants);
|
vkMeshLoader::freeMeshBufferResources(device, &meshes.plants);
|
||||||
textureLoader->destroyTexture(textures.colorMap);
|
vkMeshLoader::freeMeshBufferResources(device, &meshes.ground);
|
||||||
|
vkMeshLoader::freeMeshBufferResources(device, &meshes.skysphere);
|
||||||
|
textureLoader->destroyTexture(textures.plants);
|
||||||
|
textureLoader->destroyTexture(textures.ground);
|
||||||
instanceBuffer.destroy();
|
instanceBuffer.destroy();
|
||||||
indirectCommandsBuffer.destroy();
|
indirectCommandsBuffer.destroy();
|
||||||
uniformData.scene.destroy();
|
uniformData.scene.destroy();
|
||||||
|
|
@ -197,9 +201,21 @@ public:
|
||||||
|
|
||||||
vkCmdBindIndexBuffer(drawCmdBuffers[i], meshes.plants.indices.buf, 0, VK_INDEX_TYPE_UINT32);
|
vkCmdBindIndexBuffer(drawCmdBuffers[i], meshes.plants.indices.buf, 0, VK_INDEX_TYPE_UINT32);
|
||||||
|
|
||||||
|
// If the multi draw feature is supported:
|
||||||
// One draw call for an arbitrary number of ojects
|
// One draw call for an arbitrary number of ojects
|
||||||
// Index offsets and instance count are taken from the indirect buffer
|
// Index offsets and instance count are taken from the indirect buffer
|
||||||
|
if (vulkanDevice->features.multiDrawIndirect)
|
||||||
|
{
|
||||||
vkCmdDrawIndexedIndirect(drawCmdBuffers[i], indirectCommandsBuffer.buffer, 0, indirectDrawCount, sizeof(VkDrawIndexedIndirectCommand));
|
vkCmdDrawIndexedIndirect(drawCmdBuffers[i], indirectCommandsBuffer.buffer, 0, indirectDrawCount, sizeof(VkDrawIndexedIndirectCommand));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// If multi draw is not available, we must issue separate draw commands
|
||||||
|
for (auto j = 0; j < indirectCommands.size(); j++)
|
||||||
|
{
|
||||||
|
vkCmdDrawIndexedIndirect(drawCmdBuffers[i], indirectCommandsBuffer.buffer, j * sizeof(VkDrawIndexedIndirectCommand), 1, sizeof(VkDrawIndexedIndirectCommand));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Ground
|
// Ground
|
||||||
vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.ground);
|
vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.ground);
|
||||||
|
|
@ -224,7 +240,7 @@ public:
|
||||||
loadMesh(getAssetPath() + "models/plane_circle.dae", &meshes.ground, vertexLayout, PLANT_RADIUS + 1.0f);
|
loadMesh(getAssetPath() + "models/plane_circle.dae", &meshes.ground, vertexLayout, PLANT_RADIUS + 1.0f);
|
||||||
loadMesh(getAssetPath() + "models/skysphere.dae", &meshes.skysphere, vertexLayout, 512.0f);
|
loadMesh(getAssetPath() + "models/skysphere.dae", &meshes.skysphere, vertexLayout, 512.0f);
|
||||||
|
|
||||||
textureLoader->loadTextureArray(getAssetPath() + "textures/texturearray_plants_bc3.ktx", VK_FORMAT_BC3_UNORM_BLOCK, &textures.colorMap);
|
textureLoader->loadTextureArray(getAssetPath() + "textures/texturearray_plants_bc3.ktx", VK_FORMAT_BC3_UNORM_BLOCK, &textures.plants);
|
||||||
textureLoader->loadTexture(getAssetPath() + "textures/ground_dry_bc3.ktx", VK_FORMAT_BC3_UNORM_BLOCK, &textures.ground);
|
textureLoader->loadTexture(getAssetPath() + "textures/ground_dry_bc3.ktx", VK_FORMAT_BC3_UNORM_BLOCK, &textures.ground);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -394,7 +410,7 @@ public:
|
||||||
descriptorSet,
|
descriptorSet,
|
||||||
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||||
1,
|
1,
|
||||||
&textures.colorMap.descriptor),
|
&textures.plants.descriptor),
|
||||||
// Binding 2: Ground texture combined
|
// Binding 2: Ground texture combined
|
||||||
vkTools::initializers::writeDescriptorSet(
|
vkTools::initializers::writeDescriptorSet(
|
||||||
descriptorSet,
|
descriptorSet,
|
||||||
|
|
@ -653,6 +669,10 @@ public:
|
||||||
virtual void getOverlayText(VulkanTextOverlay *textOverlay)
|
virtual void getOverlayText(VulkanTextOverlay *textOverlay)
|
||||||
{
|
{
|
||||||
textOverlay->addText(std::to_string(objectCount) + " objects", 5.0f, 85.0f, VulkanTextOverlay::alignLeft);
|
textOverlay->addText(std::to_string(objectCount) + " objects", 5.0f, 85.0f, VulkanTextOverlay::alignLeft);
|
||||||
|
if (!vulkanDevice->features.multiDrawIndirect)
|
||||||
|
{
|
||||||
|
textOverlay->addText("multiDrawIndirect not supported", 5.0f, 105.0f, VulkanTextOverlay::alignLeft);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue