Sort initial draw lists by pipeline

Fix applying pipeline state too often for scattered draw ranges
Delay updating sides and sectors until frame start to allow the playsim to mark surfaces dirty multiple times
This commit is contained in:
Magnus Norddahl 2024-08-28 19:53:12 +02:00
commit d12cd4d74d
7 changed files with 251 additions and 54 deletions

View file

@ -167,10 +167,13 @@ public:
Mesh.Indexes.Resize(limits.MaxIndexes);
Mesh.SurfaceIndexes.Resize(limits.MaxIndexes / 3 + 1);
Mesh.DrawIndexes.Resize(limits.MaxIndexes);
FreeLists.Vertex.Clear(); FreeLists.Vertex.Push({ 0, limits.MaxVertices });
FreeLists.Index.Clear(); FreeLists.Index.Push({ 0, limits.MaxIndexes });
FreeLists.Uniforms.Clear(); FreeLists.Uniforms.Push({ 0, limits.MaxUniforms });
FreeLists.Surface.Clear(); FreeLists.Surface.Push({ 0, limits.MaxSurfaces });
FreeLists.DrawIndex.Clear(); FreeLists.DrawIndex.Push({ 0, limits.MaxIndexes });
}
// Data placed in GPU buffers
@ -194,6 +197,9 @@ public:
TArray<int> SurfaceIndexes;
int IndexCount = 0; // Index range filled with data
// Indexes sorted by pipeline
TArray<uint32_t> DrawIndexes;
// GPU buffer size for collision nodes
int MaxNodes = 0;
} Mesh;
@ -211,6 +217,7 @@ public:
TArray<MeshBufferRange> Portals;
TArray<MeshBufferRange> Light;
TArray<MeshBufferRange> LightIndex;
TArray<MeshBufferRange> DrawIndex;
} UploadRanges;
// Ranges in mesh currently not in use
@ -220,6 +227,7 @@ public:
TArray<MeshBufferRange> Index;
TArray<MeshBufferRange> Uniforms;
TArray<MeshBufferRange> Surface;
TArray<MeshBufferRange> DrawIndex;
} FreeLists;
// Data structure for doing mesh traces on the CPU

View file

@ -57,6 +57,7 @@ void VkLevelMesh::Reset()
deletelist->Add(std::move(PortalBuffer));
deletelist->Add(std::move(LightBuffer));
deletelist->Add(std::move(LightIndexBuffer));
deletelist->Add(std::move(DrawIndexBuffer));
deletelist->Add(std::move(DynamicBLAS.ScratchBuffer));
deletelist->Add(std::move(DynamicBLAS.AccelStructBuffer));
deletelist->Add(std::move(DynamicBLAS.AccelStruct));
@ -197,6 +198,12 @@ void VkLevelMesh::CreateBuffers()
.DebugName("IndexBuffer")
.Create(fb->GetDevice());
DrawIndexBuffer = BufferBuilder()
.Usage(VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT)
.Size((size_t)Mesh->Mesh.DrawIndexes.Size() * sizeof(uint32_t))
.DebugName("DrawIndexBuffer")
.Create(fb->GetDevice());
NodeBuffer = BufferBuilder()
.Usage(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT)
.Size(sizeof(CollisionNodeBufferHeader) + Mesh->Mesh.MaxNodes * sizeof(CollisionNode))
@ -440,6 +447,7 @@ void VkLevelMeshUploader::Upload()
UploadRanges(Mesh->Mesh->UploadRanges.Index, Mesh->Mesh->Mesh.Indexes.Data(), Mesh->IndexBuffer.get());
UploadRanges(Mesh->Mesh->UploadRanges.SurfaceIndex, Mesh->Mesh->Mesh.SurfaceIndexes.Data(), Mesh->SurfaceIndexBuffer.get());
UploadRanges(Mesh->Mesh->UploadRanges.LightIndex, Mesh->Mesh->Mesh.LightIndexes.Data(), Mesh->LightIndexBuffer.get());
UploadRanges(Mesh->Mesh->UploadRanges.DrawIndex, Mesh->Mesh->Mesh.DrawIndexes.Data(), Mesh->DrawIndexBuffer.get());
UploadSurfaces();
UploadUniforms();
UploadPortals();
@ -471,6 +479,7 @@ void VkLevelMeshUploader::ClearRanges()
Mesh->Mesh->UploadRanges.Portals.clear();
Mesh->Mesh->UploadRanges.Light.clear();
Mesh->Mesh->UploadRanges.LightIndex.clear();
Mesh->Mesh->UploadRanges.DrawIndex.clear();
}
void VkLevelMeshUploader::BeginTransfer(size_t transferBufferSize)
@ -681,5 +690,6 @@ size_t VkLevelMeshUploader::GetTransferSize()
for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.Portals) transferBufferSize += range.Count() * sizeof(PortalInfo);
for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.LightIndex) transferBufferSize += range.Count() * sizeof(int32_t);
for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.Light) transferBufferSize += range.Count() * sizeof(LightInfo);
for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.DrawIndex) transferBufferSize += range.Count() * sizeof(uint32_t);
return transferBufferSize;
}

View file

@ -83,6 +83,7 @@ public:
VulkanBuffer* GetPortalBuffer() { return PortalBuffer.get(); }
VulkanBuffer* GetLightBuffer() { return LightBuffer.get(); }
VulkanBuffer* GetLightIndexBuffer() { return LightIndexBuffer.get(); }
VulkanBuffer* GetDrawIndexBuffer() { return DrawIndexBuffer.get(); }
LevelMesh* GetMesh() { return Mesh; }
@ -122,6 +123,7 @@ private:
std::unique_ptr<VulkanBuffer> PortalBuffer;
std::unique_ptr<VulkanBuffer> LightBuffer;
std::unique_ptr<VulkanBuffer> LightIndexBuffer;
std::unique_ptr<VulkanBuffer> DrawIndexBuffer;
std::unique_ptr<VulkanBuffer> NodeBuffer;

View file

@ -842,7 +842,7 @@ void VkRenderState::ApplyLevelMesh()
VkBuffer vertexBuffers[2] = { fb->GetLevelMesh()->GetVertexBuffer()->buffer, fb->GetLevelMesh()->GetUniformIndexBuffer()->buffer };
VkDeviceSize vertexBufferOffsets[] = { 0, 0 };
mCommandBuffer->bindVertexBuffers(0, 2, vertexBuffers, vertexBufferOffsets);
mCommandBuffer->bindIndexBuffer(fb->GetLevelMesh()->GetIndexBuffer()->buffer, 0, VK_INDEX_TYPE_UINT32);
mCommandBuffer->bindIndexBuffer(fb->GetLevelMesh()->GetDrawIndexBuffer()->buffer, 0, VK_INDEX_TYPE_UINT32);
}
void VkRenderState::DrawLevelMeshSurfaces(bool noFragmentShader)
@ -854,9 +854,12 @@ void VkRenderState::DrawLevelMeshSurfaces(bool noFragmentShader)
{
int pipelineID = it.first;
const VkPipelineKey& key = fb->GetLevelMeshPipelineKey(pipelineID);
for (MeshBufferRange& range : it.second)
if (ApplyLevelMeshPipeline(mCommandBuffer, key, noFragmentShader))
{
DrawLevelMeshRange(mCommandBuffer, key, range.Start, range.End - range.Start, noFragmentShader);
for (MeshBufferRange& range : it.second)
{
mCommandBuffer->drawIndexed(range.End - range.Start, 1, range.Start, 0, 0);
}
}
}
}
@ -870,9 +873,12 @@ void VkRenderState::DrawLevelMeshPortals(bool noFragmentShader)
{
int pipelineID = it.first;
const VkPipelineKey& key = fb->GetLevelMeshPipelineKey(pipelineID);
for (MeshBufferRange& range : it.second)
if (ApplyLevelMeshPipeline(mCommandBuffer, key, noFragmentShader))
{
DrawLevelMeshRange(mCommandBuffer, key, range.Start, range.End - range.Start, noFragmentShader);
for (MeshBufferRange& range : it.second)
{
mCommandBuffer->drawIndexed(range.End - range.Start, 1, range.Start, 0, 0);
}
}
}
}
@ -909,10 +915,10 @@ void VkRenderState::GetQueryResults(int queryStart, int queryCount, TArray<bool>
}
}
void VkRenderState::DrawLevelMeshRange(VulkanCommandBuffer* cmdbuffer, VkPipelineKey pipelineKey, int start, int count, bool noFragmentShader)
bool VkRenderState::ApplyLevelMeshPipeline(VulkanCommandBuffer* cmdbuffer, VkPipelineKey pipelineKey, bool noFragmentShader)
{
if (noFragmentShader && pipelineKey.ShaderKey.AlphaTest)
return;
return false;
pipelineKey.ShaderKey.NoFragmentShader = noFragmentShader;
pipelineKey.DepthTest = mDepthTest;
@ -945,7 +951,8 @@ void VkRenderState::DrawLevelMeshRange(VulkanCommandBuffer* cmdbuffer, VkPipelin
cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 1, descriptors->GetLevelMeshSet(), 4, offsets);
cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 2, descriptors->GetBindlessSet());
cmdbuffer->pushConstants(layout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, (uint32_t)sizeof(PushConstants), &pushConstants);
cmdbuffer->drawIndexed(count, 1, start, 0, 0);
return true;
}
/////////////////////////////////////////////////////////////////////////////

View file

@ -89,7 +89,7 @@ protected:
void WaitForStreamBuffers();
void ApplyLevelMesh();
void DrawLevelMeshRange(VulkanCommandBuffer* cmdbuffer, VkPipelineKey pipelineKey, int start, int count, bool noFragmentShader);
bool ApplyLevelMeshPipeline(VulkanCommandBuffer* cmdbuffer, VkPipelineKey pipelineKey, bool noFragmentShader);
VulkanRenderDevice* fb = nullptr;