Split masked from opaque in the level mesh draw lists

This commit is contained in:
dpjudas 2024-09-01 22:44:25 +02:00
commit 4666fa6241
7 changed files with 73 additions and 127 deletions

View file

@ -67,6 +67,15 @@ struct LevelMeshLimits
int MaxIndexes = 0;
};
enum class LevelMeshDrawType
{
Opaque,
Masked,
Portal,
Translucent,
NumDrawTypes
};
class LevelMesh
{
public:
@ -234,8 +243,7 @@ public:
std::unique_ptr<TriangleMeshShape> Collision;
// Draw index ranges for rendering the level mesh, grouped by pipeline
std::unordered_map<int, TArray<MeshBufferRange>> DrawList;
std::unordered_map<int, TArray<MeshBufferRange>> PortalList;
std::unordered_map<int, TArray<MeshBufferRange>> DrawList[(int)LevelMeshDrawType::NumDrawTypes];
// Lightmap atlas
int LMTextureCount = 0;

View file

@ -16,6 +16,7 @@ struct FColormap;
class IBuffer;
struct HWViewpointUniforms;
struct FDynLightData;
enum class LevelMeshDrawType;
enum EClearTarget
{
@ -697,8 +698,7 @@ public:
}
// Draw level mesh
virtual void DrawLevelMeshSurfaces(bool noFragmentShader) { }
virtual void DrawLevelMeshPortals(bool noFragmentShader) { }
virtual void DrawLevelMesh(LevelMeshDrawType drawType, bool noFragmentShader) { }
virtual int GetNextQueryIndex() { return 0; }
virtual void BeginQuery() { }
virtual void EndQuery() { }

View file

@ -845,40 +845,21 @@ void VkRenderState::ApplyLevelMesh()
mCommandBuffer->bindIndexBuffer(fb->GetLevelMesh()->GetDrawIndexBuffer()->buffer, 0, VK_INDEX_TYPE_UINT32);
}
void VkRenderState::DrawLevelMeshSurfaces(bool noFragmentShader)
void VkRenderState::DrawLevelMesh(LevelMeshDrawType drawType, bool noFragmentShader)
{
ApplyLevelMesh();
auto mesh = fb->GetLevelMesh()->GetMesh();
for (auto& it : mesh->DrawList)
for (auto& it : mesh->DrawList[(int)drawType])
{
int pipelineID = it.first;
const VkPipelineKey& key = fb->GetLevelMeshPipelineKey(pipelineID);
if (ApplyLevelMeshPipeline(mCommandBuffer, key, noFragmentShader))
{
for (MeshBufferRange& range : it.second)
{
mCommandBuffer->drawIndexed(range.End - range.Start, 1, range.Start, 0, 0);
}
}
}
}
void VkRenderState::DrawLevelMeshPortals(bool noFragmentShader)
{
ApplyLevelMesh();
ApplyLevelMeshPipeline(mCommandBuffer, key, noFragmentShader);
auto mesh = fb->GetLevelMesh()->GetMesh();
for (auto& it : mesh->PortalList)
{
int pipelineID = it.first;
const VkPipelineKey& key = fb->GetLevelMeshPipelineKey(pipelineID);
if (ApplyLevelMeshPipeline(mCommandBuffer, key, noFragmentShader))
for (MeshBufferRange& range : it.second)
{
for (MeshBufferRange& range : it.second)
{
mCommandBuffer->drawIndexed(range.End - range.Start, 1, range.Start, 0, 0);
}
mCommandBuffer->drawIndexed(range.End - range.Start, 1, range.Start, 0, 0);
}
}
}
@ -915,11 +896,8 @@ void VkRenderState::GetQueryResults(int queryStart, int queryCount, TArray<bool>
}
}
bool VkRenderState::ApplyLevelMeshPipeline(VulkanCommandBuffer* cmdbuffer, VkPipelineKey pipelineKey, bool noFragmentShader)
void VkRenderState::ApplyLevelMeshPipeline(VulkanCommandBuffer* cmdbuffer, VkPipelineKey pipelineKey, bool noFragmentShader)
{
if (noFragmentShader && pipelineKey.ShaderKey.AlphaTest)
return false;
pipelineKey.ShaderKey.NoFragmentShader = noFragmentShader;
pipelineKey.DepthTest = mDepthTest;
pipelineKey.DepthWrite = mDepthTest && mDepthWrite;
@ -951,8 +929,6 @@ bool VkRenderState::ApplyLevelMeshPipeline(VulkanCommandBuffer* cmdbuffer, VkPip
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);
return true;
}
/////////////////////////////////////////////////////////////////////////////

View file

@ -57,8 +57,7 @@ public:
void ResetVertices() override;
// Draw level mesh
void DrawLevelMeshSurfaces(bool noFragmentShader) override;
void DrawLevelMeshPortals(bool noFragmentShader) override;
void DrawLevelMesh(LevelMeshDrawType drawType, bool noFragmentShader) override;
int GetNextQueryIndex() override;
void BeginQuery() override;
void EndQuery() override;
@ -89,7 +88,7 @@ protected:
void WaitForStreamBuffers();
void ApplyLevelMesh();
bool ApplyLevelMeshPipeline(VulkanCommandBuffer* cmdbuffer, VkPipelineKey pipelineKey, bool noFragmentShader);
void ApplyLevelMeshPipeline(VulkanCommandBuffer* cmdbuffer, VkPipelineKey pipelineKey, bool noFragmentShader);
VulkanRenderDevice* fb = nullptr;

View file

@ -594,7 +594,7 @@ void DoomLevelMesh::CreateSide(FLevelLocals& doomMap, unsigned int sideIndex)
state.EnableTexture(true);
state.EnableBrightmap(true);
state.AlphaFunc(Alpha_GEqual, 0.f);
CreateWallSurface(side, disp, state, result.list, false, true, sideIndex);
CreateWallSurface(side, disp, state, result.list, back ? LevelMeshDrawType::Masked : LevelMeshDrawType::Opaque, true, sideIndex);
if (result.portals.Size() != 0 && !Sides[sideIndex].InSidePortalsList)
{
@ -608,13 +608,13 @@ void DoomLevelMesh::CreateSide(FLevelLocals& doomMap, unsigned int sideIndex)
Sides[sideIndex].WallPortals.Push(portal);
}
CreateWallSurface(side, disp, state, result.portals, true, false, sideIndex);
CreateWallSurface(side, disp, state, result.portals, LevelMeshDrawType::Portal, false, sideIndex);
/*
// final pass: translucent stuff
state.AlphaFunc(Alpha_GEqual, gl_mask_sprite_threshold);
state.SetRenderStyle(STYLE_Translucent);
CreateWallSurface(side, disp, state, result.translucent, false, true, sideIndex);
CreateWallSurface(side, disp, state, result.translucent, LevelMeshDrawType::Translucent, true, sideIndex);
state.AlphaFunc(Alpha_GEqual, 0.f);
state.SetRenderStyle(STYLE_Normal);
*/
@ -641,27 +641,27 @@ void DoomLevelMesh::CreateFlat(FLevelLocals& doomMap, unsigned int sectorIndex)
state.ClearDepthBias();
state.EnableTexture(true);
state.EnableBrightmap(true);
CreateFlatSurface(disp, state, result.list, false, false, sectorIndex);
CreateFlatSurface(disp, state, result.list, LevelMeshDrawType::Opaque, false, sectorIndex);
CreateFlatSurface(disp, state, result.portals, true, false, sectorIndex);
CreateFlatSurface(disp, state, result.portals, LevelMeshDrawType::Portal, false, sectorIndex);
// final pass: translucent stuff
state.AlphaFunc(Alpha_GEqual, gl_mask_sprite_threshold);
state.SetRenderStyle(STYLE_Translucent);
CreateFlatSurface(disp, state, result.translucentborder, false, true, sectorIndex);
CreateFlatSurface(disp, state, result.translucentborder, LevelMeshDrawType::Translucent, true, sectorIndex);
state.SetDepthMask(false);
CreateFlatSurface(disp, state, result.translucent, false, true, sectorIndex);
CreateFlatSurface(disp, state, result.translucent, LevelMeshDrawType::Translucent, true, sectorIndex);
state.AlphaFunc(Alpha_GEqual, 0.f);
state.SetDepthMask(true);
state.SetRenderStyle(STYLE_Normal);
}
}
void DoomLevelMesh::CreateWallSurface(side_t* side, HWWallDispatcher& disp, MeshBuilder& state, TArray<HWWall>& list, bool isPortal, bool translucent, unsigned int sideIndex)
void DoomLevelMesh::CreateWallSurface(side_t* side, HWWallDispatcher& disp, MeshBuilder& state, TArray<HWWall>& list, LevelMeshDrawType drawType, bool translucent, unsigned int sideIndex)
{
for (HWWall& wallpart : list)
{
if (isPortal)
if (drawType == LevelMeshDrawType::Portal)
{
state.SetEffect(EFF_PORTAL);
state.EnableTexture(false);
@ -784,8 +784,8 @@ void DoomLevelMesh::CreateWallSurface(side_t* side, HWWallDispatcher& disp, Mesh
sinfo.Surface->MeshLocation.NumElements = ginfo.IndexCount;
sinfo.Surface->Plane = FVector4(N.X, N.Y, 0.0f, v1 | N);
sinfo.Surface->Texture = wallpart.texture;
sinfo.Surface->PortalIndex = isPortal ? linePortals[side->linedef->Index()] : 0;
sinfo.Surface->IsSky = isPortal ? (wallpart.portaltype == PORTALTYPE_SKY || wallpart.portaltype == PORTALTYPE_SKYBOX || wallpart.portaltype == PORTALTYPE_HORIZON) : false;
sinfo.Surface->PortalIndex = (drawType == LevelMeshDrawType::Portal) ? linePortals[side->linedef->Index()] : 0;
sinfo.Surface->IsSky = (drawType == LevelMeshDrawType::Portal) ? (wallpart.portaltype == PORTALTYPE_SKY || wallpart.portaltype == PORTALTYPE_SKYBOX || wallpart.portaltype == PORTALTYPE_HORIZON) : false;
sinfo.Surface->Bounds = GetBoundsFromSurface(*sinfo.Surface);
sinfo.Surface->LightmapTileIndex = disp.Level->lightmaps ? AddSurfaceToTile(info, *sinfo.Surface, sampleDimension, !!(side->sector->Flags & SECF_LM_DYNAMIC)) : -1;
@ -794,20 +794,20 @@ void DoomLevelMesh::CreateWallSurface(side_t* side, HWWallDispatcher& disp, Mesh
for (int i = ginfo.IndexStart / 3, end = (ginfo.IndexStart + ginfo.IndexCount) / 3; i < end; i++)
Mesh.SurfaceIndexes[i] = sinfo.Index;
Sides[sideIndex].Geometries.Push({ ginfo, pipelineID, sinfo.Surface->IsSky });
Sides[sideIndex].Geometries.Push(ginfo);
Sides[sideIndex].Uniforms.Push(uinfo);
AddToDrawList(Sides[sideIndex].DrawRanges, pipelineID, ginfo.IndexStart, ginfo.IndexCount, isPortal);
AddToDrawList(Sides[sideIndex].DrawRanges, pipelineID, ginfo.IndexStart, ginfo.IndexCount, drawType);
}
}
void DoomLevelMesh::AddToDrawList(TArray<DrawRangeInfo>& drawRanges, int pipelineID, int indexStart, int indexCount, bool isPortal)
void DoomLevelMesh::AddToDrawList(TArray<DrawRangeInfo>& drawRanges, int pipelineID, int indexStart, int indexCount, LevelMeshDrawType drawType)
{
// 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.DrawType = drawType;
info.PipelineID = pipelineID;
drawRanges.Push(info);
@ -816,14 +816,7 @@ void DoomLevelMesh::AddToDrawList(TArray<DrawRangeInfo>& drawRanges, int pipelin
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 });
}
AddRange(DrawList[(int)drawType][pipelineID], { info.DrawIndexStart, info.DrawIndexStart + indexCount });
}
void DoomLevelMesh::RemoveFromDrawList(const TArray<DrawRangeInfo>& drawRanges)
@ -833,28 +826,20 @@ void DoomLevelMesh::RemoveFromDrawList(const TArray<DrawRangeInfo>& 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 });
RemoveRange(DrawList[(int)info.DrawType][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;
std::unordered_map<int, TArray<DrawRangeInfo*>> sortedDrawList[(int)LevelMeshDrawType::NumDrawTypes];
for (auto& side : Sides)
{
for (auto& range : side.DrawRanges)
{
if (!range.IsPortal)
sortedDrawList[range.PipelineID].Push(&range);
else
sortedPortalList[range.PipelineID].Push(&range);
sortedDrawList[(int)range.DrawType][range.PipelineID].Push(&range);
}
}
@ -862,53 +847,33 @@ void DoomLevelMesh::SortDrawLists()
{
for (auto& range : flat.DrawRanges)
{
if (!range.IsPortal)
sortedDrawList[range.PipelineID].Push(&range);
else
sortedPortalList[range.PipelineID].Push(&range);
sortedDrawList[(int)range.DrawType][range.PipelineID].Push(&range);
}
}
TArray<uint32_t> indexes;
DrawList.clear();
for (auto& it : sortedDrawList)
for (int drawType = 0; drawType < (int)LevelMeshDrawType::NumDrawTypes; drawType++)
{
auto& list = DrawList[it.first];
int listStart = indexes.Size();
for (DrawRangeInfo* range : it.second)
DrawList[drawType].clear();
for (auto& it : sortedDrawList[drawType])
{
int sortedStart = indexes.Size();
int start = range->DrawIndexStart;
int count = range->DrawIndexCount;
for (int i = 0; i < count; i++)
auto& list = DrawList[drawType][it.first];
int listStart = indexes.Size();
for (DrawRangeInfo* range : it.second)
{
indexes.Push(Mesh.DrawIndexes[start + i]);
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;
}
range->DrawIndexStart = sortedStart;
int listEnd = indexes.Size();
list.Push({ listStart, listEnd });
}
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));
@ -978,7 +943,7 @@ int DoomLevelMesh::GetSampleDimension(uint16_t sampleDimension)
return sampleDimension;
}
void DoomLevelMesh::CreateFlatSurface(HWFlatDispatcher& disp, MeshBuilder& state, TArray<HWFlat>& list, bool isSky, bool translucent, unsigned int sectorIndex)
void DoomLevelMesh::CreateFlatSurface(HWFlatDispatcher& disp, MeshBuilder& state, TArray<HWFlat>& list, LevelMeshDrawType drawType, bool translucent, unsigned int sectorIndex)
{
for (HWFlat& flatpart : list)
{
@ -986,7 +951,7 @@ void DoomLevelMesh::CreateFlatSurface(HWFlatDispatcher& disp, MeshBuilder& state
state.mVertices.Clear();
state.mIndexes.Clear();
if (isSky)
if (drawType == LevelMeshDrawType::Portal)
{
state.SetEffect(EFF_PORTAL);
state.EnableTexture(false);
@ -1046,7 +1011,7 @@ void DoomLevelMesh::CreateFlatSurface(HWFlatDispatcher& disp, MeshBuilder& state
GeometryAllocInfo ginfo = AllocGeometry(numVertices, numIndexes);
UniformsAllocInfo uinfo = AllocUniforms(1);
Flats[sectorIndex].Geometries.Push({ ginfo, pipelineID, isSky });
Flats[sectorIndex].Geometries.Push(ginfo);
Flats[sectorIndex].Uniforms.Push(uinfo);
int* surfaceIndexes = &Mesh.SurfaceIndexes[ginfo.IndexStart / 3];
@ -1078,7 +1043,7 @@ void DoomLevelMesh::CreateFlatSurface(HWFlatDispatcher& disp, MeshBuilder& state
surf.Texture = flatpart.texture;
surf.PipelineID = pipelineID;
surf.PortalIndex = sectorPortals[flatpart.ceiling][flatpart.sector->Index()];
surf.IsSky = isSky;
surf.IsSky = (drawType == LevelMeshDrawType::Portal);
auto plane = info.ControlSector ? info.ControlSector->GetSecPlane(!flatpart.ceiling) : flatpart.sector->GetSecPlane(flatpart.ceiling);
surf.Plane = FVector4((float)plane.Normal().X, (float)plane.Normal().Y, (float)plane.Normal().Z, -(float)plane.D);
@ -1102,7 +1067,7 @@ void DoomLevelMesh::CreateFlatSurface(HWFlatDispatcher& disp, MeshBuilder& state
{
auto& vt = sub->firstline[end - 1 - i].v1;
FVector3 pt((float)vt->fX(), (float)vt->fY(), isSky ? skyZ : (float)plane.ZatPoint(vt));
FVector3 pt((float)vt->fX(), (float)vt->fY(), (drawType == LevelMeshDrawType::Portal) ? skyZ : (float)plane.ZatPoint(vt));
FVector4 uv = textureMatrix * FVector4(pt.X * (1.0f / 64.0f), pt.Y * (-1.0f / 64.0f), 0.0f, 1.0f);
FFlatVertex ffv;
@ -1163,7 +1128,7 @@ void DoomLevelMesh::CreateFlatSurface(HWFlatDispatcher& disp, MeshBuilder& state
SetSubsectorLightmap(sinfo.Index);
}
AddToDrawList(Flats[sectorIndex].DrawRanges, pipelineID, ginfo.IndexStart, ginfo.IndexCount, isSky);
AddToDrawList(Flats[sectorIndex].DrawRanges, pipelineID, ginfo.IndexStart, ginfo.IndexCount, drawType);
}
}

View file

@ -32,28 +32,24 @@ struct DoomSurfaceInfo
struct GeometryFreeInfo
{
GeometryFreeInfo(const GeometryAllocInfo& ginfo, int pipelineID, bool isPortal)
GeometryFreeInfo(const GeometryAllocInfo& ginfo)
{
VertexStart = ginfo.VertexStart;
VertexCount = ginfo.VertexCount;
IndexStart = ginfo.IndexStart;
IndexCount = ginfo.IndexCount;
PipelineID = pipelineID;
IsPortal = isPortal;
}
int VertexStart = 0;
int VertexCount = 0;
int IndexStart = 0;
int IndexCount = 0;
int PipelineID = 0;
bool IsPortal = false;
};
struct DrawRangeInfo
{
int PipelineID = 0;
bool IsPortal = false;
LevelMeshDrawType DrawType = {};
int DrawIndexStart = 0;
int DrawIndexCount = 0;
};
@ -143,8 +139,8 @@ private:
void SetSubsectorLightmap(int surfaceIndex);
void SetSideLightmap(int surfaceIndex);
void CreateWallSurface(side_t* side, HWWallDispatcher& disp, MeshBuilder& state, TArray<HWWall>& list, bool isPortal, bool translucent, unsigned int sectorIndex);
void CreateFlatSurface(HWFlatDispatcher& disp, MeshBuilder& state, TArray<HWFlat>& list, bool isSky, bool translucent, unsigned int sectorIndex);
void CreateWallSurface(side_t* side, HWWallDispatcher& disp, MeshBuilder& state, TArray<HWWall>& list, LevelMeshDrawType drawType, bool translucent, unsigned int sectorIndex);
void CreateFlatSurface(HWFlatDispatcher& disp, MeshBuilder& state, TArray<HWFlat>& list, LevelMeshDrawType drawType, bool translucent, unsigned int sectorIndex);
BBox GetBoundsFromSurface(const LevelMeshSurface& surface) const;
@ -156,7 +152,7 @@ private:
int GetLightIndex(FDynamicLight* light, int portalgroup);
void AddToDrawList(TArray<DrawRangeInfo>& drawRanges, int pipelineID, int indexStart, int indexCount, bool isPortal);
void AddToDrawList(TArray<DrawRangeInfo>& drawRanges, int pipelineID, int indexStart, int indexCount, LevelMeshDrawType drawType);
void RemoveFromDrawList(const TArray<DrawRangeInfo>& drawRanges);
void SortDrawLists();

View file

@ -432,11 +432,12 @@ void HWDrawInfo::CreateScene(bool drawpsprites, FRenderState& state)
// draw level into depth buffer
state.SetColorMask(false);
state.SetCulling(Cull_CW);
state.DrawLevelMeshSurfaces(true);
state.DrawLevelMesh(LevelMeshDrawType::Opaque, true);
state.DrawLevelMesh(LevelMeshDrawType::Masked, false); // To do: properly mark wall top/bottom as opaque so we don't need this
if (gl_portals)
{
state.SetDepthBias(1, 128);
state.DrawLevelMeshPortals(true);
state.DrawLevelMesh(LevelMeshDrawType::Portal, true);
state.SetDepthBias(0, 0);
}
@ -462,11 +463,12 @@ void HWDrawInfo::CreateScene(bool drawpsprites, FRenderState& state)
int queryEnd = state.GetNextQueryIndex();
// draw opaque level so the GPU has something to do while we examine the query results
state.DrawLevelMeshSurfaces(false);
state.DrawLevelMesh(LevelMeshDrawType::Opaque, false);
//state.DrawLevelMesh(LevelMeshDrawType::Masked, false);
if (!gl_portals)
{
state.SetDepthBias(1, 128);
state.DrawLevelMeshPortals(false);
state.DrawLevelMesh(LevelMeshDrawType::Portal, false);
state.SetDepthBias(0, 0);
}
state.SetCulling(Cull_None);