Ranges in buffers are so fun!

This commit is contained in:
Magnus Norddahl 2024-08-11 20:39:45 +02:00
commit 766b558119
4 changed files with 116 additions and 66 deletions

View file

@ -42,7 +42,7 @@ void LevelMesh::AddEmptyMesh()
for (int i = 0; i < 3 * 4; i++)
Mesh.Indexes.Push(i);
MarkAllDirty();
UploadAll();
}
LevelMeshSurface* LevelMesh::Trace(const FVector3& start, FVector3 direction, float maxDist)
@ -111,7 +111,7 @@ LevelMeshTileStats LevelMesh::GatherTilePixelStats()
void LevelMesh::UpdateCollision()
{
Collision = std::make_unique<TriangleMeshShape>(Mesh.Vertices.Data(), Mesh.Vertices.Size(), Mesh.Indexes.Data(), Mesh.Indexes.Size());
MarkCollisionDirty();
UploadCollision();
}
struct LevelMeshPlaneGroup

View file

@ -48,6 +48,8 @@ struct MeshBufferRange
{
int Offset = 0;
int Size = 0;
bool operator<(const MeshBufferRange& other) const { return Offset < other.Offset; }
};
class LevelMesh
@ -83,7 +85,11 @@ public:
info.Vertices = &Mesh.Vertices[info.VertexStart];
info.UniformIndexes = &Mesh.UniformIndexes[info.VertexStart];
info.Indexes = &Mesh.Indexes[info.IndexStart];
// To do: mark range as dirty
AddRange(UploadRanges.Vertex, { info.VertexStart, info.VertexCount });
AddRange(UploadRanges.UniformIndexes, { info.VertexStart, info.VertexCount });
AddRange(UploadRanges.Index, { info.IndexStart, info.IndexCount });
return info;
}
@ -96,27 +102,33 @@ public:
Mesh.Materials.Resize(info.Start + count);
info.Uniforms = &Mesh.Uniforms[info.Start];
info.Materials = &Mesh.Materials[info.Start];
// To do: mark range as dirty
AddRange(UploadRanges.Uniforms, { info.Start, info.Count });
return info;
}
void FreeGeometry(int vertexStart, int vertexCount, int indexStart, int indexCount)
{
// Convert triangles to degenerates
for (int i = 0; i < indexCount; i++)
Mesh.Indexes[indexStart + i] = 0;
// To do: add to a free list
// To do: mark range as dirty
AddRange(UploadRanges.Index, { indexStart, indexCount });
AddRange(FreeLists.Vertex, { vertexStart, vertexCount });
AddRange(FreeLists.Index, { indexStart, indexCount });
}
void FreeUniforms(int start, int count)
{
// To do: add to a free list
AddRange(FreeLists.Uniforms, { start, count });
}
void FreeSurface(unsigned int surfaceIndex)
{
// To do: remove the surface from the surface tile, if attached
// To do: add to a free list
AddRange(FreeLists.Surface, { (int)surfaceIndex, 1 });
}
struct
@ -161,7 +173,15 @@ public:
TArray<MeshBufferRange> Portals;
TArray<MeshBufferRange> Light;
TArray<MeshBufferRange> LightIndex;
} DirtyRanges;
} UploadRanges;
struct
{
TArray<MeshBufferRange> Vertex;
TArray<MeshBufferRange> Index;
TArray<MeshBufferRange> Uniforms;
TArray<MeshBufferRange> Surface;
} FreeLists;
std::unique_ptr<TriangleMeshShape> Collision;
@ -186,38 +206,68 @@ public:
void AddEmptyMesh();
void MarkAllDirty()
void UploadAll()
{
DirtyRanges.Vertex.Clear();
DirtyRanges.Vertex.Push({ 0, (int)Mesh.Vertices.Size() });
DirtyRanges.Index.Clear();
DirtyRanges.Index.Push({ 0, (int)Mesh.Indexes.Size() });
DirtyRanges.SurfaceIndex.Clear();
DirtyRanges.SurfaceIndex.Push({ 0, (int)Mesh.SurfaceIndexes.Size() });
DirtyRanges.Surface.Clear();
DirtyRanges.Surface.Push({ 0, GetSurfaceCount() });
DirtyRanges.UniformIndexes.Clear();
DirtyRanges.UniformIndexes.Push({ 0, (int)Mesh.UniformIndexes.Size() });
DirtyRanges.Uniforms.Clear();
DirtyRanges.Uniforms.Push({ 0, (int)Mesh.Uniforms.Size() });
DirtyRanges.Portals.Clear();
DirtyRanges.Portals.Push({ 0, (int)Portals.Size() });
DirtyRanges.Light.Clear();
DirtyRanges.Light.Push({ 0, (int)Mesh.Lights.Size() });
DirtyRanges.LightIndex.Clear();
DirtyRanges.LightIndex.Push({ 0, (int)Mesh.LightIndexes.Size() });
UploadRanges.Vertex.Clear();
UploadRanges.Vertex.Push({ 0, (int)Mesh.Vertices.Size() });
UploadRanges.Index.Clear();
UploadRanges.Index.Push({ 0, (int)Mesh.Indexes.Size() });
UploadRanges.SurfaceIndex.Clear();
UploadRanges.SurfaceIndex.Push({ 0, (int)Mesh.SurfaceIndexes.Size() });
UploadRanges.Surface.Clear();
UploadRanges.Surface.Push({ 0, GetSurfaceCount() });
UploadRanges.UniformIndexes.Clear();
UploadRanges.UniformIndexes.Push({ 0, (int)Mesh.UniformIndexes.Size() });
UploadRanges.Uniforms.Clear();
UploadRanges.Uniforms.Push({ 0, (int)Mesh.Uniforms.Size() });
UploadRanges.Portals.Clear();
UploadRanges.Portals.Push({ 0, (int)Portals.Size() });
UploadRanges.Light.Clear();
UploadRanges.Light.Push({ 0, (int)Mesh.Lights.Size() });
UploadRanges.LightIndex.Clear();
UploadRanges.LightIndex.Push({ 0, (int)Mesh.LightIndexes.Size() });
}
void MarkCollisionDirty()
void UploadCollision()
{
DirtyRanges.Node.Clear();
UploadRanges.Node.Clear();
if (Collision)
DirtyRanges.Node.Push({ 0, (int)Collision->get_nodes().size() });
UploadRanges.Node.Push({ 0, (int)Collision->get_nodes().size() });
}
void MarkDynamicDirty()
void UploadDynamic()
{
DirtyRanges.Index.Push({ Mesh.DynamicIndexStart, (int)(Mesh.Indexes.Size() - Mesh.DynamicIndexStart) });
UploadRanges.Index.Push({ Mesh.DynamicIndexStart, (int)(Mesh.Indexes.Size() - Mesh.DynamicIndexStart) });
}
void AddRange(TArray<MeshBufferRange>& ranges, MeshBufferRange range)
{
auto right = std::lower_bound(ranges.begin(), ranges.end(), range);
bool leftExists = right != ranges.begin();
bool rightExists = right != ranges.end();
auto left = right;
if (leftExists)
--left;
if (leftExists && rightExists && left->Offset + left->Size == range.Offset && right->Offset == range.Offset + range.Size) // ####[--]####
{
left->Size += range.Size + right->Size;
ranges.Delete(right - ranges.begin());
}
else if (leftExists && left->Offset + left->Size == range.Offset) // ####[--] ####
{
left->Size += range.Size;
}
else if (rightExists && right->Offset == range.Offset + range.Size) // #### [--]####
{
right->Offset -= range.Size;
}
else // ##### [--] ####
{
ranges.Insert(right - ranges.begin(), range);
}
}
};

View file

@ -448,11 +448,11 @@ void VkLevelMeshUploader::Upload()
BeginTransfer(transferBufferSize);
UploadNodes();
UploadRanges(Mesh->Mesh->DirtyRanges.Vertex, Mesh->Mesh->Mesh.Vertices.Data(), Mesh->VertexBuffer.get());
UploadRanges(Mesh->Mesh->DirtyRanges.UniformIndexes, Mesh->Mesh->Mesh.UniformIndexes.Data(), Mesh->UniformIndexBuffer.get());
UploadRanges(Mesh->Mesh->DirtyRanges.Index, Mesh->Mesh->Mesh.Indexes.Data(), Mesh->IndexBuffer.get());
UploadRanges(Mesh->Mesh->DirtyRanges.SurfaceIndex, Mesh->Mesh->Mesh.SurfaceIndexes.Data(), Mesh->SurfaceIndexBuffer.get());
UploadRanges(Mesh->Mesh->DirtyRanges.LightIndex, Mesh->Mesh->Mesh.LightIndexes.Data(), Mesh->LightIndexBuffer.get());
UploadRanges(Mesh->Mesh->UploadRanges.Vertex, Mesh->Mesh->Mesh.Vertices.Data(), Mesh->VertexBuffer.get());
UploadRanges(Mesh->Mesh->UploadRanges.UniformIndexes, Mesh->Mesh->Mesh.UniformIndexes.Data(), Mesh->UniformIndexBuffer.get());
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());
UploadSurfaces();
UploadUniforms();
UploadPortals();
@ -474,16 +474,16 @@ void VkLevelMeshUploader::Upload()
void VkLevelMeshUploader::ClearRanges()
{
Mesh->Mesh->DirtyRanges.Vertex.clear();
Mesh->Mesh->DirtyRanges.Index.clear();
Mesh->Mesh->DirtyRanges.Node.clear();
Mesh->Mesh->DirtyRanges.SurfaceIndex.clear();
Mesh->Mesh->DirtyRanges.Surface.clear();
Mesh->Mesh->DirtyRanges.UniformIndexes.clear();
Mesh->Mesh->DirtyRanges.Uniforms.clear();
Mesh->Mesh->DirtyRanges.Portals.clear();
Mesh->Mesh->DirtyRanges.Light.clear();
Mesh->Mesh->DirtyRanges.LightIndex.clear();
Mesh->Mesh->UploadRanges.Vertex.clear();
Mesh->Mesh->UploadRanges.Index.clear();
Mesh->Mesh->UploadRanges.Node.clear();
Mesh->Mesh->UploadRanges.SurfaceIndex.clear();
Mesh->Mesh->UploadRanges.Surface.clear();
Mesh->Mesh->UploadRanges.UniformIndexes.clear();
Mesh->Mesh->UploadRanges.Uniforms.clear();
Mesh->Mesh->UploadRanges.Portals.clear();
Mesh->Mesh->UploadRanges.Light.clear();
Mesh->Mesh->UploadRanges.LightIndex.clear();
}
void VkLevelMeshUploader::BeginTransfer(size_t transferBufferSize)
@ -515,7 +515,7 @@ void VkLevelMeshUploader::UploadNodes()
return;
// Always update the header struct of the collision storage buffer block if something changed
if (Mesh->Mesh->DirtyRanges.Node.Size() > 0)
if (Mesh->Mesh->UploadRanges.Node.Size() > 0)
{
CollisionNodeBufferHeader nodesHeader;
nodesHeader.root = Mesh->Mesh->Collision->get_root();
@ -527,7 +527,7 @@ void VkLevelMeshUploader::UploadNodes()
}
// Copy collision nodes
for (const MeshBufferRange& range : Mesh->Mesh->DirtyRanges.Node)
for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.Node)
{
const auto& srcnodes = Mesh->Mesh->Collision->get_nodes();
CollisionNode* nodes = (CollisionNode*)(data + datapos);
@ -565,7 +565,7 @@ void VkLevelMeshUploader::UploadRanges(const TArray<MeshBufferRange>& ranges, co
void VkLevelMeshUploader::UploadSurfaces()
{
for (const MeshBufferRange& range : Mesh->Mesh->DirtyRanges.Surface)
for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.Surface)
{
SurfaceInfo* surfaces = (SurfaceInfo*)(data + datapos);
for (int j = 0, count = range.Size; j < count; j++)
@ -601,7 +601,7 @@ void VkLevelMeshUploader::UploadSurfaces()
void VkLevelMeshUploader::UploadUniforms()
{
for (const MeshBufferRange& range : Mesh->Mesh->DirtyRanges.Uniforms)
for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.Uniforms)
{
for (int j = 0, count = range.Size; j < count; j++)
{
@ -630,7 +630,7 @@ void VkLevelMeshUploader::UploadUniforms()
void VkLevelMeshUploader::UploadPortals()
{
for (const MeshBufferRange& range : Mesh->Mesh->DirtyRanges.Portals)
for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.Portals)
{
PortalInfo* portals = (PortalInfo*)(data + datapos);
for (int i = 0, count = range.Size; i < count; i++)
@ -650,7 +650,7 @@ void VkLevelMeshUploader::UploadPortals()
void VkLevelMeshUploader::UploadLights()
{
for (const MeshBufferRange& range : Mesh->Mesh->DirtyRanges.Light)
for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.Light)
{
LightInfo* lights = (LightInfo*)(data + datapos);
for (int i = 0, count = range.Size; i < count; i++)
@ -682,17 +682,17 @@ size_t VkLevelMeshUploader::GetTransferSize()
size_t transferBufferSize = 0;
if (!Mesh->useRayQuery)
{
if (Mesh->Mesh->DirtyRanges.Node.Size() > 0) transferBufferSize += sizeof(CollisionNodeBufferHeader) + sizeof(CollisionNode);
for (const MeshBufferRange& range : Mesh->Mesh->DirtyRanges.Node) transferBufferSize += range.Size * sizeof(CollisionNode);
if (Mesh->Mesh->UploadRanges.Node.Size() > 0) transferBufferSize += sizeof(CollisionNodeBufferHeader) + sizeof(CollisionNode);
for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.Node) transferBufferSize += range.Size * sizeof(CollisionNode);
}
for (const MeshBufferRange& range : Mesh->Mesh->DirtyRanges.Vertex) transferBufferSize += range.Size * sizeof(FFlatVertex);
for (const MeshBufferRange& range : Mesh->Mesh->DirtyRanges.UniformIndexes) transferBufferSize += range.Size * sizeof(int);
for (const MeshBufferRange& range : Mesh->Mesh->DirtyRanges.Index) transferBufferSize += range.Size * sizeof(uint32_t);
for (const MeshBufferRange& range : Mesh->Mesh->DirtyRanges.SurfaceIndex) transferBufferSize += range.Size * sizeof(int);
for (const MeshBufferRange& range : Mesh->Mesh->DirtyRanges.Surface) transferBufferSize += range.Size * sizeof(SurfaceInfo);
for (const MeshBufferRange& range : Mesh->Mesh->DirtyRanges.Uniforms) transferBufferSize += range.Size * sizeof(SurfaceUniforms);
for (const MeshBufferRange& range : Mesh->Mesh->DirtyRanges.Portals) transferBufferSize += range.Size * sizeof(PortalInfo);
for (const MeshBufferRange& range : Mesh->Mesh->DirtyRanges.LightIndex) transferBufferSize += range.Size * sizeof(int32_t);
for (const MeshBufferRange& range : Mesh->Mesh->DirtyRanges.Light) transferBufferSize += range.Size * sizeof(LightInfo);
for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.Vertex) transferBufferSize += range.Size * sizeof(FFlatVertex);
for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.UniformIndexes) transferBufferSize += range.Size * sizeof(int);
for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.Index) transferBufferSize += range.Size * sizeof(uint32_t);
for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.SurfaceIndex) transferBufferSize += range.Size * sizeof(int);
for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.Surface) transferBufferSize += range.Size * sizeof(SurfaceInfo);
for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.Uniforms) transferBufferSize += range.Size * sizeof(SurfaceUniforms);
for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.Portals) transferBufferSize += range.Size * sizeof(PortalInfo);
for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.LightIndex) transferBufferSize += range.Size * sizeof(int32_t);
for (const MeshBufferRange& range : Mesh->Mesh->UploadRanges.Light) transferBufferSize += range.Size * sizeof(LightInfo);
return transferBufferSize;
}

View file

@ -178,7 +178,7 @@ DoomLevelMesh::DoomLevelMesh(FLevelLocals& doomMap)
Mesh.MaxLights = 100'000;
Mesh.MaxLightIndexes = 4 * 1024 * 1024;
MarkAllDirty();
UploadAll();
}
void DoomLevelMesh::CreateLights(FLevelLocals& doomMap)