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:
parent
ddc3b530c7
commit
d12cd4d74d
7 changed files with 251 additions and 54 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -60,6 +60,13 @@ ADD_STAT(lightmap)
|
|||
return out;
|
||||
}
|
||||
|
||||
ADD_STAT(levelmesh)
|
||||
{
|
||||
FString out;
|
||||
out.Format("Sides=%d, flats=%d", level.levelMesh->LastFrameStats.SidesUpdated, level.levelMesh->LastFrameStats.FlatsUpdated);
|
||||
return out;
|
||||
}
|
||||
|
||||
CCMD(dumplevelmesh)
|
||||
{
|
||||
if (!RequireLevelMesh()) return;
|
||||
|
|
@ -172,16 +179,35 @@ DoomLevelMesh::DoomLevelMesh(FLevelLocals& doomMap)
|
|||
Mesh.MaxNodes = std::max(Collision->get_nodes().size() * 2, (size_t)10000);
|
||||
|
||||
UploadPortals();
|
||||
|
||||
SortDrawLists();
|
||||
}
|
||||
|
||||
void DoomLevelMesh::BeginFrame(FLevelLocals& doomMap)
|
||||
{
|
||||
LastFrameStats = CurFrameStats;
|
||||
CurFrameStats = Stats();
|
||||
|
||||
// To do: we don't need to always do this. UpdateLevelMesh should tell us when polyobjs move.
|
||||
for (side_t* side : PolySides)
|
||||
{
|
||||
UpdateSide(doomMap, side->Index());
|
||||
UpdateSide(side->Index());
|
||||
}
|
||||
|
||||
for (int sideIndex : SideUpdateList)
|
||||
{
|
||||
CreateSide(doomMap, sideIndex);
|
||||
Sides[sideIndex].InUpdateList = false;
|
||||
}
|
||||
SideUpdateList.Clear();
|
||||
|
||||
for (int flatIndex : FlatUpdateList)
|
||||
{
|
||||
CreateFlat(doomMap, flatIndex);
|
||||
Flats[flatIndex].InUpdateList = false;
|
||||
}
|
||||
FlatUpdateList.Clear();
|
||||
|
||||
CreateLights(doomMap);
|
||||
UpdateWallPortals();
|
||||
}
|
||||
|
|
@ -366,7 +392,7 @@ void DoomLevelMesh::CreateSurfaces(FLevelLocals& doomMap)
|
|||
continue;
|
||||
}
|
||||
|
||||
UpdateSide(doomMap, i);
|
||||
CreateSide(doomMap, i);
|
||||
}
|
||||
|
||||
// Create surfaces for all flats
|
||||
|
|
@ -375,7 +401,7 @@ void DoomLevelMesh::CreateSurfaces(FLevelLocals& doomMap)
|
|||
sector_t* sector = &doomMap.sectors[i];
|
||||
if (sector->subsectorcount == 0 || sector->subsectors[0]->flags & SSECF_POLYORG)
|
||||
continue;
|
||||
UpdateFlat(doomMap, i);
|
||||
CreateFlat(doomMap, i);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -394,15 +420,12 @@ void DoomLevelMesh::FreeSide(FLevelLocals& doomMap, unsigned int sideIndex)
|
|||
Sides[sideIndex].FirstSurface = -1;
|
||||
|
||||
for (auto& geo : Sides[sideIndex].Geometries)
|
||||
{
|
||||
FreeGeometry(geo.VertexStart, geo.VertexCount, geo.IndexStart, geo.IndexCount);
|
||||
if (!geo.IsPortal)
|
||||
RemoveRange(DrawList[geo.PipelineID], { geo.IndexStart, geo.IndexStart + geo.IndexCount });
|
||||
else
|
||||
RemoveRange(PortalList[geo.PipelineID], { geo.IndexStart, geo.IndexStart + geo.IndexCount });
|
||||
}
|
||||
Sides[sideIndex].Geometries.Clear();
|
||||
|
||||
RemoveFromDrawList(Sides[sideIndex].DrawRanges);
|
||||
Sides[sideIndex].DrawRanges.Clear();
|
||||
|
||||
for (auto& uni : Sides[sideIndex].Uniforms)
|
||||
FreeUniforms(uni.Start, uni.Count);
|
||||
Sides[sideIndex].Uniforms.Clear();
|
||||
|
|
@ -425,15 +448,12 @@ void DoomLevelMesh::FreeFlat(FLevelLocals& doomMap, unsigned int sectorIndex)
|
|||
Flats[sectorIndex].FirstSurface = -1;
|
||||
|
||||
for (auto& geo : Flats[sectorIndex].Geometries)
|
||||
{
|
||||
FreeGeometry(geo.VertexStart, geo.VertexCount, geo.IndexStart, geo.IndexCount);
|
||||
if (!geo.IsPortal)
|
||||
RemoveRange(DrawList[geo.PipelineID], { geo.IndexStart, geo.IndexStart + geo.IndexCount });
|
||||
else
|
||||
RemoveRange(PortalList[geo.PipelineID], { geo.IndexStart, geo.IndexStart + geo.IndexCount });
|
||||
}
|
||||
Flats[sectorIndex].Geometries.Clear();
|
||||
|
||||
RemoveFromDrawList(Flats[sectorIndex].DrawRanges);
|
||||
Flats[sectorIndex].DrawRanges.Clear();
|
||||
|
||||
for (auto& uni : Flats[sectorIndex].Uniforms)
|
||||
FreeUniforms(uni.Start, uni.Count);
|
||||
Flats[sectorIndex].Uniforms.Clear();
|
||||
|
|
@ -441,51 +461,51 @@ void DoomLevelMesh::FreeFlat(FLevelLocals& doomMap, unsigned int sectorIndex)
|
|||
|
||||
void DoomLevelMesh::FloorHeightChanged(struct sector_t* sector)
|
||||
{
|
||||
UpdateFlat(level, sector->Index());
|
||||
UpdateFlat(sector->Index());
|
||||
for (line_t* line : sector->Lines)
|
||||
{
|
||||
if (line->sidedef[0])
|
||||
UpdateSide(level, line->sidedef[0]->Index());
|
||||
UpdateSide(line->sidedef[0]->Index());
|
||||
if (line->sidedef[1])
|
||||
UpdateSide(level, line->sidedef[1]->Index());
|
||||
UpdateSide(line->sidedef[1]->Index());
|
||||
}
|
||||
}
|
||||
|
||||
void DoomLevelMesh::CeilingHeightChanged(struct sector_t* sector)
|
||||
{
|
||||
UpdateFlat(level, sector->Index());
|
||||
UpdateFlat(sector->Index());
|
||||
for (line_t* line : sector->Lines)
|
||||
{
|
||||
if (line->sidedef[0])
|
||||
UpdateSide(level, line->sidedef[0]->Index());
|
||||
UpdateSide(line->sidedef[0]->Index());
|
||||
if (line->sidedef[1])
|
||||
UpdateSide(level, line->sidedef[1]->Index());
|
||||
UpdateSide(line->sidedef[1]->Index());
|
||||
}
|
||||
}
|
||||
|
||||
void DoomLevelMesh::MidTex3DHeightChanged(struct sector_t* sector)
|
||||
{
|
||||
// UpdateFlat(level, sector->Index());
|
||||
// UpdateFlat(sector->Index());
|
||||
}
|
||||
|
||||
void DoomLevelMesh::FloorTextureChanged(struct sector_t* sector)
|
||||
{
|
||||
UpdateFlat(level, sector->Index());
|
||||
UpdateFlat(sector->Index());
|
||||
}
|
||||
|
||||
void DoomLevelMesh::CeilingTextureChanged(struct sector_t* sector)
|
||||
{
|
||||
UpdateFlat(level, sector->Index());
|
||||
UpdateFlat(sector->Index());
|
||||
}
|
||||
|
||||
void DoomLevelMesh::SectorChangedOther(struct sector_t* sector)
|
||||
{
|
||||
UpdateFlat(level, sector->Index());
|
||||
UpdateFlat(sector->Index());
|
||||
}
|
||||
|
||||
void DoomLevelMesh::SideTextureChanged(struct side_t* side, int section)
|
||||
{
|
||||
UpdateSide(level, side->Index());
|
||||
UpdateSide(side->Index());
|
||||
}
|
||||
|
||||
void DoomLevelMesh::SectorLightChanged(struct sector_t* sector)
|
||||
|
|
@ -495,9 +515,9 @@ void DoomLevelMesh::SectorLightChanged(struct sector_t* sector)
|
|||
for (line_t* line : sector->Lines)
|
||||
{
|
||||
if (line->frontsector == sector && line->sidedef[0])
|
||||
UpdateSide(level, line->sidedef[0]->Index());
|
||||
UpdateSide(line->sidedef[0]->Index());
|
||||
else if (line->sidedef[1])
|
||||
UpdateSide(level, line->sidedef[1]->Index());
|
||||
UpdateSide(line->sidedef[1]->Index());
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
|
@ -510,8 +530,28 @@ void DoomLevelMesh::SectorLightThinkerDestroyed(struct sector_t* sector, class D
|
|||
{
|
||||
}
|
||||
|
||||
void DoomLevelMesh::UpdateSide(FLevelLocals& doomMap, unsigned int sideIndex)
|
||||
void DoomLevelMesh::UpdateSide(unsigned int sideIndex)
|
||||
{
|
||||
if (!Sides[sideIndex].InUpdateList)
|
||||
{
|
||||
SideUpdateList.Push(sideIndex);
|
||||
Sides[sideIndex].InUpdateList = true;
|
||||
}
|
||||
}
|
||||
|
||||
void DoomLevelMesh::UpdateFlat(unsigned int sectorIndex)
|
||||
{
|
||||
if (!Flats[sectorIndex].InUpdateList)
|
||||
{
|
||||
FlatUpdateList.Push(sectorIndex);
|
||||
Flats[sectorIndex].InUpdateList = true;
|
||||
}
|
||||
}
|
||||
|
||||
void DoomLevelMesh::CreateSide(FLevelLocals& doomMap, unsigned int sideIndex)
|
||||
{
|
||||
CurFrameStats.SidesUpdated++;
|
||||
|
||||
FreeSide(doomMap, sideIndex);
|
||||
|
||||
side_t* side = &doomMap.sides[sideIndex];
|
||||
|
|
@ -576,8 +616,10 @@ void DoomLevelMesh::UpdateSide(FLevelLocals& doomMap, unsigned int sideIndex)
|
|||
*/
|
||||
}
|
||||
|
||||
void DoomLevelMesh::UpdateFlat(FLevelLocals& doomMap, unsigned int sectorIndex)
|
||||
void DoomLevelMesh::CreateFlat(FLevelLocals& doomMap, unsigned int sectorIndex)
|
||||
{
|
||||
CurFrameStats.FlatsUpdated++;
|
||||
|
||||
FreeFlat(doomMap, sectorIndex);
|
||||
|
||||
sector_t* sector = &doomMap.sectors[sectorIndex];
|
||||
|
|
@ -751,15 +793,121 @@ void DoomLevelMesh::CreateWallSurface(side_t* side, HWWallDispatcher& disp, Mesh
|
|||
Sides[sideIndex].Geometries.Push({ ginfo, pipelineID, sinfo.Surface->IsSky });
|
||||
Sides[sideIndex].Uniforms.Push(uinfo);
|
||||
|
||||
if (!sinfo.Surface->IsSky)
|
||||
{
|
||||
AddRange(DrawList[pipelineID], { ginfo.IndexStart, ginfo.IndexStart + ginfo.IndexCount });
|
||||
}
|
||||
AddToDrawList(Sides[sideIndex].DrawRanges, pipelineID, ginfo.IndexStart, ginfo.IndexCount, sinfo.Surface->IsSky);
|
||||
}
|
||||
}
|
||||
|
||||
void DoomLevelMesh::AddToDrawList(TArray<DrawRangeInfo>& drawRanges, int pipelineID, int indexStart, int indexCount, bool isPortal)
|
||||
{
|
||||
// Remember the location if we have to remove it again
|
||||
DrawRangeInfo info;
|
||||
info.DrawIndexStart = RemoveRange(FreeLists.DrawIndex, indexCount);
|
||||
info.DrawIndexCount = indexCount;
|
||||
info.IsPortal = isPortal;
|
||||
info.PipelineID = pipelineID;
|
||||
drawRanges.Push(info);
|
||||
|
||||
// Copy the indexes over from the unsorted index list
|
||||
memcpy(&Mesh.DrawIndexes[info.DrawIndexStart], &Mesh.Indexes[indexStart], indexCount * sizeof(uint32_t));
|
||||
AddRange(UploadRanges.DrawIndex, { info.DrawIndexStart, info.DrawIndexStart + indexCount });
|
||||
|
||||
// Add to the draw lists
|
||||
if (!isPortal)
|
||||
{
|
||||
AddRange(DrawList[pipelineID], { info.DrawIndexStart, info.DrawIndexStart + indexCount });
|
||||
}
|
||||
else
|
||||
{
|
||||
AddRange(PortalList[pipelineID], { info.DrawIndexStart, info.DrawIndexStart + indexCount });
|
||||
}
|
||||
}
|
||||
|
||||
void DoomLevelMesh::RemoveFromDrawList(const TArray<DrawRangeInfo>& drawRanges)
|
||||
{
|
||||
for (const DrawRangeInfo& info : drawRanges)
|
||||
{
|
||||
int start = info.DrawIndexStart;
|
||||
int end = info.DrawIndexStart + info.DrawIndexCount;
|
||||
|
||||
if (!info.IsPortal)
|
||||
RemoveRange(DrawList[info.PipelineID], { start, end });
|
||||
else
|
||||
RemoveRange(PortalList[info.PipelineID], { start, end });
|
||||
|
||||
AddRange(FreeLists.DrawIndex, { start, end });
|
||||
}
|
||||
}
|
||||
|
||||
void DoomLevelMesh::SortDrawLists()
|
||||
{
|
||||
std::unordered_map<int, TArray<DrawRangeInfo*>> sortedDrawList;
|
||||
std::unordered_map<int, TArray<DrawRangeInfo*>> sortedPortalList;
|
||||
|
||||
for (auto& side : Sides)
|
||||
{
|
||||
for (auto& range : side.DrawRanges)
|
||||
{
|
||||
AddRange(PortalList[pipelineID], { ginfo.IndexStart, ginfo.IndexStart + ginfo.IndexCount });
|
||||
if (!range.IsPortal)
|
||||
sortedDrawList[range.PipelineID].Push(&range);
|
||||
else
|
||||
sortedPortalList[range.PipelineID].Push(&range);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& flat : Flats)
|
||||
{
|
||||
for (auto& range : flat.DrawRanges)
|
||||
{
|
||||
if (!range.IsPortal)
|
||||
sortedDrawList[range.PipelineID].Push(&range);
|
||||
else
|
||||
sortedPortalList[range.PipelineID].Push(&range);
|
||||
}
|
||||
}
|
||||
|
||||
TArray<uint32_t> indexes;
|
||||
|
||||
DrawList.clear();
|
||||
for (auto& it : sortedDrawList)
|
||||
{
|
||||
auto& list = DrawList[it.first];
|
||||
int listStart = indexes.Size();
|
||||
for (DrawRangeInfo* range : it.second)
|
||||
{
|
||||
int sortedStart = indexes.Size();
|
||||
int start = range->DrawIndexStart;
|
||||
int count = range->DrawIndexCount;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
indexes.Push(Mesh.DrawIndexes[start + i]);
|
||||
}
|
||||
range->DrawIndexStart = sortedStart;
|
||||
}
|
||||
int listEnd = indexes.Size();
|
||||
list.Push({ listStart, listEnd });
|
||||
}
|
||||
|
||||
PortalList.clear();
|
||||
for (auto& it : sortedPortalList)
|
||||
{
|
||||
auto& list = PortalList[it.first];
|
||||
int listStart = indexes.Size();
|
||||
for (DrawRangeInfo* range : it.second)
|
||||
{
|
||||
int sortedStart = indexes.Size();
|
||||
int start = range->DrawIndexStart;
|
||||
int count = range->DrawIndexCount;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
indexes.Push(Mesh.DrawIndexes[start + i]);
|
||||
}
|
||||
range->DrawIndexStart = sortedStart;
|
||||
}
|
||||
int listEnd = indexes.Size();
|
||||
list.Push({ listStart, listEnd });
|
||||
}
|
||||
|
||||
memcpy(Mesh.DrawIndexes.Data(), indexes.Data(), indexes.Size() * sizeof(uint32_t));
|
||||
}
|
||||
|
||||
int DoomLevelMesh::AddSurfaceToTile(const DoomSurfaceInfo& info, const LevelMeshSurface& surf, uint16_t sampleDimension, bool alwaysUpdate)
|
||||
|
|
@ -897,15 +1045,6 @@ void DoomLevelMesh::CreateFlatSurface(HWFlatDispatcher& disp, MeshBuilder& state
|
|||
Flats[sectorIndex].Geometries.Push({ ginfo, pipelineID, isSky });
|
||||
Flats[sectorIndex].Uniforms.Push(uinfo);
|
||||
|
||||
if (!isSky)
|
||||
{
|
||||
AddRange(DrawList[pipelineID], { ginfo.IndexStart, ginfo.IndexStart + ginfo.IndexCount });
|
||||
}
|
||||
else
|
||||
{
|
||||
AddRange(PortalList[pipelineID], { ginfo.IndexStart, ginfo.IndexStart + ginfo.IndexCount });
|
||||
}
|
||||
|
||||
int* surfaceIndexes = &Mesh.SurfaceIndexes[ginfo.IndexStart / 3];
|
||||
|
||||
*uinfo.Uniforms = *uniforms;
|
||||
|
|
@ -1019,6 +1158,8 @@ void DoomLevelMesh::CreateFlatSurface(HWFlatDispatcher& disp, MeshBuilder& state
|
|||
|
||||
SetSubsectorLightmap(sinfo.Index);
|
||||
}
|
||||
|
||||
AddToDrawList(Flats[sectorIndex].DrawRanges, pipelineID, ginfo.IndexStart, ginfo.IndexCount, isSky);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -50,6 +50,14 @@ struct GeometryFreeInfo
|
|||
bool IsPortal = false;
|
||||
};
|
||||
|
||||
struct DrawRangeInfo
|
||||
{
|
||||
int PipelineID = 0;
|
||||
bool IsPortal = false;
|
||||
int DrawIndexStart = 0;
|
||||
int DrawIndexCount = 0;
|
||||
};
|
||||
|
||||
struct SideSurfaceBlock
|
||||
{
|
||||
int FirstSurface = -1;
|
||||
|
|
@ -57,6 +65,8 @@ struct SideSurfaceBlock
|
|||
TArray<UniformsAllocInfo> Uniforms;
|
||||
TArray<HWWall> WallPortals;
|
||||
bool InSidePortalsList = false;
|
||||
TArray<DrawRangeInfo> DrawRanges;
|
||||
bool InUpdateList = false;
|
||||
};
|
||||
|
||||
struct FlatSurfaceBlock
|
||||
|
|
@ -64,6 +74,8 @@ struct FlatSurfaceBlock
|
|||
int FirstSurface = -1;
|
||||
TArray<GeometryFreeInfo> Geometries;
|
||||
TArray<UniformsAllocInfo> Uniforms;
|
||||
TArray<DrawRangeInfo> DrawRanges;
|
||||
bool InUpdateList = false;
|
||||
};
|
||||
|
||||
class DoomLevelMesh : public LevelMesh, public UpdateLevelMesh
|
||||
|
|
@ -105,12 +117,22 @@ public:
|
|||
DoomSurfaceInfos.Resize(limits.MaxSurfaces);
|
||||
}
|
||||
|
||||
struct Stats
|
||||
{
|
||||
int FlatsUpdated = 0;
|
||||
int SidesUpdated = 0;
|
||||
};
|
||||
Stats LastFrameStats, CurFrameStats;
|
||||
|
||||
private:
|
||||
void CreateSurfaces(FLevelLocals& doomMap);
|
||||
void CreateLightList(FLevelLocals& doomMap, int surfaceIndex);
|
||||
|
||||
void UpdateSide(FLevelLocals& doomMap, unsigned int sideIndex);
|
||||
void UpdateFlat(FLevelLocals& doomMap, unsigned int sectorIndex);
|
||||
void UpdateSide(unsigned int sideIndex);
|
||||
void UpdateFlat(unsigned int sectorIndex);
|
||||
|
||||
void CreateSide(FLevelLocals& doomMap, unsigned int sideIndex);
|
||||
void CreateFlat(FLevelLocals& doomMap, unsigned int sectorIndex);
|
||||
|
||||
void FreeSide(FLevelLocals& doomMap, unsigned int sideIndex);
|
||||
void FreeFlat(FLevelLocals& doomMap, unsigned int sectorIndex);
|
||||
|
|
@ -133,6 +155,10 @@ private:
|
|||
|
||||
int GetLightIndex(FDynamicLight* light, int portalgroup);
|
||||
|
||||
void AddToDrawList(TArray<DrawRangeInfo>& drawRanges, int pipelineID, int indexStart, int indexCount, bool isPortal);
|
||||
void RemoveFromDrawList(const TArray<DrawRangeInfo>& drawRanges);
|
||||
void SortDrawLists();
|
||||
|
||||
TArray<DoomSurfaceInfo> DoomSurfaceInfos;
|
||||
TArray<std::unique_ptr<DoomSurfaceInfo* []>> PolyDoomSurfaceInfos;
|
||||
|
||||
|
|
@ -140,6 +166,9 @@ private:
|
|||
TArray<FlatSurfaceBlock> Flats;
|
||||
TArray<side_t*> PolySides;
|
||||
|
||||
TArray<int> SideUpdateList;
|
||||
TArray<int> FlatUpdateList;
|
||||
|
||||
std::map<LightmapTileBinding, int> bindings;
|
||||
MeshBuilder state;
|
||||
bool LightsCreated = false;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue