feat: draw meshes with instanced multi-draw indirect

This commit is contained in:
2026-10-19 00:45:25 +02:00
parent 997844eaa7
commit 92c1daf396
19 changed files with 556 additions and 250 deletions
+34 -96
View File
@@ -8,7 +8,6 @@
#include <destrum/Graphics/GfxDevice.h>
#include <destrum/Graphics/RenderResources.h>
#include <destrum/Graphics/Caches/MeshCache.h>
#include <destrum/Graphics/Frustum.h>
#include <destrum/Graphics/Util.h>
#include "volk.h"
@@ -119,10 +118,9 @@ void MeshPipeline::drawDepthPrepass(
VkCommandBuffer cmd,
VkExtent2D renderExtent,
const RenderResources& resources,
const Camera& camera,
const GPUBuffer& sceneDataBuffer,
const std::vector<MeshDrawCommand>& drawCommands,
const std::vector<std::size_t>& sortedDrawCommands)
const IndirectDrawList& drawList,
const IndirectDrawList::View& view)
{
if (!m_depthPrepassPipeline)
{
@@ -134,20 +132,18 @@ void MeshPipeline::drawDepthPrepass(
*m_depthPrepassPipeline,
renderExtent,
resources,
camera,
sceneDataBuffer,
drawCommands,
sortedDrawCommands);
drawList,
view);
}
void MeshPipeline::draw(
VkCommandBuffer cmd,
VkExtent2D renderExtent,
const RenderResources& resources,
const Camera& camera,
const GPUBuffer& sceneDataBuffer,
const std::vector<MeshDrawCommand>& drawCommands,
const std::vector<std::size_t>& sortedDrawCommands)
const IndirectDrawList& drawList,
const IndirectDrawList::View& view)
{
if (!m_pipeline)
{
@@ -159,10 +155,9 @@ void MeshPipeline::draw(
*m_pipeline,
renderExtent,
resources,
camera,
sceneDataBuffer,
drawCommands,
sortedDrawCommands);
drawList,
view);
}
void MeshPipeline::drawMeshes(
@@ -170,13 +165,10 @@ void MeshPipeline::drawMeshes(
const Pipeline& pipeline,
VkExtent2D renderExtent,
const RenderResources& resources,
const Camera& camera,
const GPUBuffer& sceneDataBuffer,
const std::vector<MeshDrawCommand>& drawCommands,
const std::vector<std::size_t>& sortedDrawCommands)
const IndirectDrawList& drawList,
const IndirectDrawList::View& view)
{
const MeshCache& meshCache = resources.meshes();
pipeline.bind(cmd);
resources.bindBindlessDescSet(cmd, m_pipelineLayout);
@@ -204,86 +196,32 @@ void MeshPipeline::drawMeshes(
m_renderWireframe ? VK_POLYGON_MODE_LINE : VK_POLYGON_MODE_FILL
);
MeshID prevMeshId = NULL_MESH_ID;
int actualDrawCalls = 0;
const auto frustum = edge::createFrustumFromCamera(camera);
const auto drawOne = [&](const MeshDrawCommand& dc)
{
if (!edge::isInFrustum(frustum, dc.worldBoundingSphere))
{
return;
}
++actualDrawCalls;
const auto& mesh = meshCache.getMesh(dc.meshId);
const std::string& meshKey = meshCache.getMeshKey(dc.meshId);
vkutil::cmdBeginLabelFormatted(
cmd,
vkutil::labelColors::draw,
"%s [mesh %zu, material %u%s]",
meshKey.empty() ? "Mesh" : meshKey.c_str(),
dc.meshId,
dc.materialId,
dc.skinnedMesh != nullptr ? ", skinned" : "");
if (dc.meshId != prevMeshId)
{
prevMeshId = dc.meshId;
vkCmdBindIndexBuffer(
cmd,
mesh.indexBuffer.buffer,
0,
VK_INDEX_TYPE_UINT32
);
}
assert(dc.materialId != NULL_MATERIAL_ID);
const auto pushConstants = PushConstants{
.transform = dc.transformMatrix,
.sceneDataBuffer = sceneDataBuffer.address,
.vertexBuffer =
dc.skinnedMesh != nullptr
? dc.skinnedMesh->skinnedVertexBuffer.address
: mesh.vertexBuffer.address,
.materialId = dc.materialId,
.padding = 0,
};
vkCmdPushConstants(
cmd,
m_pipelineLayout,
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
0,
sizeof(PushConstants),
&pushConstants
);
vkCmdDrawIndexed(cmd, mesh.numIndices, 1, 0, 0, 0);
vkutil::cmdEndLabel(cmd);
// The same for every draw, per-draw data (transform, material, vertex buffer)
// lives in the instance buffer and is looked up with gl_InstanceIndex
const auto pushConstants = PushConstants{
.sceneDataBuffer = sceneDataBuffer.address,
.instanceBuffer = drawList.getInstanceBufferAddress(),
};
if (!sortedDrawCommands.empty())
{
for (std::size_t drawIndex : sortedDrawCommands)
{
assert(drawIndex < drawCommands.size());
drawOne(drawCommands[drawIndex]);
}
}
else
{
for (const MeshDrawCommand& dc : drawCommands)
{
drawOne(dc);
}
}
vkCmdPushConstants(
cmd,
m_pipelineLayout,
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
0,
sizeof(PushConstants),
&pushConstants
);
vkutil::cmdBeginLabelFormatted(
cmd,
vkutil::labelColors::draw,
"%u indirect draws, %u instances",
view.commandCount,
view.instanceCount);
drawList.draw(cmd, resources.meshes().getIndexBuffer(), view);
vkutil::cmdEndLabel(cmd);
}
void MeshPipeline::cleanup(VkDevice device)