Implement drawing HWWall portals using the level mesh and occlusion queries
This commit is contained in:
parent
47f17b1c03
commit
86ac07f2f8
11 changed files with 141 additions and 32 deletions
|
|
@ -691,9 +691,10 @@ public:
|
|||
// Draw level mesh
|
||||
virtual void DrawLevelMeshDepthPass() { }
|
||||
virtual void DrawLevelMeshOpaquePass() { }
|
||||
virtual int GetNextQueryIndex() { return 0; }
|
||||
virtual void BeginQuery() { }
|
||||
virtual void EndQuery() { }
|
||||
virtual void GetQueryResults(TArray<bool>& results) { }
|
||||
virtual void GetQueryResults(int start, int count, TArray<bool>& results) { }
|
||||
|
||||
friend class Mesh;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -105,6 +105,10 @@ VkRSBuffers::VkRSBuffers(VulkanRenderDevice* fb)
|
|||
.Create(fb->GetDevice());
|
||||
|
||||
Fogballbuffer.Data = Fogballbuffer.UBO->Map(0, Fogballbuffer.UBO->size);
|
||||
|
||||
OcclusionQuery.QueryPool = QueryPoolBuilder()
|
||||
.QueryType(VK_QUERY_TYPE_OCCLUSION, OcclusionQuery.MaxQueries)
|
||||
.Create(fb->GetDevice());
|
||||
}
|
||||
|
||||
VkRSBuffers::~VkRSBuffers()
|
||||
|
|
|
|||
|
|
@ -61,6 +61,13 @@ public:
|
|||
|
||||
std::unique_ptr<VkMatrixBufferWriter> MatrixBuffer;
|
||||
std::unique_ptr<VkSurfaceUniformsBufferWriter> SurfaceUniformsBuffer;
|
||||
|
||||
struct
|
||||
{
|
||||
const int MaxQueries = 64000;
|
||||
std::unique_ptr<VulkanQueryPool> QueryPool;
|
||||
int NextIndex = 0;
|
||||
} OcclusionQuery;
|
||||
};
|
||||
|
||||
class VkStreamBuffer
|
||||
|
|
|
|||
|
|
@ -740,8 +740,9 @@ void VkRenderState::BeginFrame()
|
|||
mRSBuffers->Lightbuffer.UploadIndex = 0;
|
||||
mRSBuffers->Bonebuffer.UploadIndex = 0;
|
||||
mRSBuffers->Fogballbuffer.UploadIndex = 0;
|
||||
mRSBuffers->OcclusionQuery.NextIndex = 0;
|
||||
|
||||
mNextOcclusionQueryIndex = 0;
|
||||
fb->GetCommands()->GetDrawCommands()->resetQueryPool(mRSBuffers->OcclusionQuery.QueryPool.get(), 0, mRSBuffers->OcclusionQuery.MaxQueries);
|
||||
}
|
||||
|
||||
void VkRenderState::EndRenderPass()
|
||||
|
|
@ -862,12 +863,14 @@ void VkRenderState::DrawLevelMeshDepthPass()
|
|||
pipelineKey.ShaderKey.NoFragmentShader = true;
|
||||
DrawLevelMeshRange(mCommandBuffer, pipelineKey, range.Start, range.Count);
|
||||
}
|
||||
/*
|
||||
for (LevelSubmeshDrawRange& range : submesh->PortalList)
|
||||
{
|
||||
VkPipelineKey pipelineKey = fb->GetLevelMeshPipelineKey(range.PipelineID);
|
||||
pipelineKey.ShaderKey.NoFragmentShader = true;
|
||||
DrawLevelMeshRange(mCommandBuffer, pipelineKey, range.Start, range.Count);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void VkRenderState::DrawLevelMeshOpaquePass()
|
||||
|
|
@ -883,18 +886,34 @@ void VkRenderState::DrawLevelMeshOpaquePass()
|
|||
|
||||
void VkRenderState::BeginQuery()
|
||||
{
|
||||
// mCommandBuffer->beginQuery(mNextOcclusionQueryIndex++);
|
||||
mCommandBuffer->beginQuery(mRSBuffers->OcclusionQuery.QueryPool.get(), mRSBuffers->OcclusionQuery.NextIndex++, 0);
|
||||
}
|
||||
|
||||
void VkRenderState::EndQuery()
|
||||
{
|
||||
// mCommandBuffer->endQuery(mNextOcclusionQueryIndex - 1);
|
||||
mCommandBuffer->endQuery(mRSBuffers->OcclusionQuery.QueryPool.get(), mRSBuffers->OcclusionQuery.NextIndex - 1);
|
||||
}
|
||||
|
||||
void VkRenderState::GetQueryResults(TArray<bool>& results)
|
||||
int VkRenderState::GetNextQueryIndex()
|
||||
{
|
||||
//vkGetQueryPoolResults(fb->GetDevice()->device, ...)
|
||||
results.Clear();
|
||||
return mRSBuffers->OcclusionQuery.NextIndex;
|
||||
}
|
||||
|
||||
void VkRenderState::GetQueryResults(int queryStart, int queryCount, TArray<bool>& results)
|
||||
{
|
||||
fb->GetCommands()->FlushCommands(false);
|
||||
|
||||
mQueryResultsBuffer.Resize(queryCount);
|
||||
VkResult result = vkGetQueryPoolResults(fb->GetDevice()->device, mRSBuffers->OcclusionQuery.QueryPool->pool, queryStart, queryCount, mQueryResultsBuffer.Size() * sizeof(uint32_t), mQueryResultsBuffer.Data(), sizeof(uint32_t), VK_QUERY_RESULT_WAIT_BIT);
|
||||
CheckVulkanError(result, "Could not query occlusion query results");
|
||||
if (result == VK_NOT_READY)
|
||||
VulkanError("Occlusion query results returned VK_NOT_READY!");
|
||||
|
||||
results.Resize(queryCount);
|
||||
for (int i = 0; i < queryCount; i++)
|
||||
{
|
||||
results[i] = mQueryResultsBuffer[i] != 0;
|
||||
}
|
||||
}
|
||||
|
||||
void VkRenderState::DrawLevelMeshRange(VulkanCommandBuffer* cmdbuffer, const VkPipelineKey& pipelineKey, int start, int count)
|
||||
|
|
|
|||
|
|
@ -59,9 +59,10 @@ public:
|
|||
// Draw level mesh
|
||||
void DrawLevelMeshDepthPass() override;
|
||||
void DrawLevelMeshOpaquePass() override;
|
||||
int GetNextQueryIndex() override;
|
||||
void BeginQuery() override;
|
||||
void EndQuery() override;
|
||||
void GetQueryResults(TArray<bool>& results) override;
|
||||
void GetQueryResults(int start, int count, TArray<bool>& results) override;
|
||||
|
||||
// Worker threads
|
||||
void FlushCommands() override { EndRenderPass(); }
|
||||
|
|
@ -119,8 +120,6 @@ protected:
|
|||
int mColorMask = 15;
|
||||
int mCullMode = 0;
|
||||
|
||||
int mNextOcclusionQueryIndex = 0;
|
||||
|
||||
PushConstants mPushConstants = {};
|
||||
|
||||
uint32_t mLastViewpointOffset = 0xffffffff;
|
||||
|
|
@ -150,6 +149,8 @@ protected:
|
|||
VkSampleCountFlagBits Samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
int DrawBuffers = 1;
|
||||
} mRenderTarget;
|
||||
|
||||
TArray<uint32_t> mQueryResultsBuffer;
|
||||
};
|
||||
|
||||
class VkRenderStateMolten : public VkRenderState
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ void DoomLevelSubmesh::UpdateDynamic(FLevelLocals& doomMap, int lightmapStartInd
|
|||
void DoomLevelSubmesh::Reset()
|
||||
{
|
||||
Surfaces.Clear();
|
||||
WallPortals.Clear();
|
||||
MeshVertices.Clear();
|
||||
MeshElements.Clear();
|
||||
MeshSurfaceIndexes.Clear();
|
||||
|
|
@ -168,6 +169,11 @@ void DoomLevelSubmesh::CreateStaticSurfaces(FLevelLocals& doomMap)
|
|||
surf.PipelineID = pipelineID;
|
||||
Surfaces.Push(surf);
|
||||
}
|
||||
|
||||
for (const HWWall& portal : result.portals)
|
||||
{
|
||||
WallPortals.Push(portal);
|
||||
}
|
||||
}
|
||||
|
||||
// Create surfaces for all flats
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "hw_levelmesh.h"
|
||||
#include "scene/hw_drawstructs.h"
|
||||
#include "tarray.h"
|
||||
#include "vectors.h"
|
||||
#include "r_defs.h"
|
||||
|
|
@ -14,16 +15,6 @@ typedef dp::rect_pack::RectPacker<int> RectPacker;
|
|||
struct FLevelLocals;
|
||||
struct FPolyObj;
|
||||
|
||||
enum DoomLevelMeshSurfaceType
|
||||
{
|
||||
ST_NONE,
|
||||
ST_MIDDLESIDE,
|
||||
ST_UPPERSIDE,
|
||||
ST_LOWERSIDE,
|
||||
ST_CEILING,
|
||||
ST_FLOOR
|
||||
};
|
||||
|
||||
struct DoomLevelMeshSurface : public LevelMeshSurface
|
||||
{
|
||||
DoomLevelMeshSurfaceType Type = ST_NONE;
|
||||
|
|
@ -58,6 +49,8 @@ public:
|
|||
|
||||
TArray<std::unique_ptr<DoomLevelMeshSurface*[]>> PolyLMSurfaces;
|
||||
|
||||
TArray<HWWall> WallPortals;
|
||||
|
||||
private:
|
||||
void Reset();
|
||||
void BuildSectorGroups(const FLevelLocals& doomMap);
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
#include "hw_renderstate.h"
|
||||
#include "hw_drawinfo.h"
|
||||
#include "hw_drawcontext.h"
|
||||
#include "hw_walldispatcher.h"
|
||||
#include "po_man.h"
|
||||
#include "models.h"
|
||||
#include "hw_clock.h"
|
||||
|
|
@ -403,21 +404,59 @@ void HWDrawInfo::CreateScene(bool drawpsprites, FRenderState& state)
|
|||
|
||||
if (gl_levelmesh)
|
||||
{
|
||||
// To do:
|
||||
// 1) draw level into depth buffer
|
||||
// 2) use occlusion queries on all portals in level to decide which are visible
|
||||
// 3) draw opaque level so the GPU has something to do while we examine the query results
|
||||
// 4) retrieve the query results and use them to fill the portal manager with portals
|
||||
//
|
||||
// Give the DrawInfo the viewpoint in fixed point because that's what the nodes are.
|
||||
viewx = FLOAT2FIXED(Viewpoint.Pos.X);
|
||||
viewy = FLOAT2FIXED(Viewpoint.Pos.Y);
|
||||
|
||||
validcount++; // used for processing sidedefs only once by the renderer.
|
||||
|
||||
auto& wallPortals = static_cast<DoomLevelSubmesh*>(level.levelMesh->StaticMesh.get())->WallPortals;
|
||||
|
||||
// draw level into depth buffer
|
||||
state.DrawLevelMeshDepthPass();
|
||||
// for (HWWall& wall : PortalWalls) { state.BeginQuery(); wall.Draw(state); state.EndQuery(); }
|
||||
// for (HWFlat& flat : PortalFlats) { state.BeginQuery(); flat.Draw(state); state.EndQuery(); }
|
||||
|
||||
// use occlusion queries on all portals in level to decide which are visible
|
||||
int queryStart = state.GetNextQueryIndex();
|
||||
state.SetColorMask(false);
|
||||
state.SetDepthMask(false);
|
||||
state.EnableTexture(false);
|
||||
state.SetEffect(EFF_FOGBOUNDARY);
|
||||
state.AlphaFunc(Alpha_GEqual, 0.f);
|
||||
for (HWWall& wall : wallPortals)
|
||||
{
|
||||
state.BeginQuery();
|
||||
|
||||
wall.MakeVertices(state, false);
|
||||
wall.RenderWall(state, HWWall::RWF_BLANK);
|
||||
wall.vertcount = 0;
|
||||
|
||||
state.EndQuery();
|
||||
}
|
||||
state.SetEffect(EFF_NONE);
|
||||
state.EnableTexture(true);
|
||||
state.SetColorMask(true);
|
||||
state.SetDepthMask(true);
|
||||
int queryEnd = state.GetNextQueryIndex();
|
||||
|
||||
// draw opaque level so the GPU has something to do while we examine the query results
|
||||
state.DrawLevelMeshOpaquePass();
|
||||
state.GetQueryResults(QueryResultsBuffer);
|
||||
|
||||
// retrieve the query results and use them to fill the portal manager with portals
|
||||
state.GetQueryResults(queryStart, queryEnd - queryStart, QueryResultsBuffer);
|
||||
for (unsigned int i = 0, count = QueryResultsBuffer.Size(); i < count; i++)
|
||||
{
|
||||
bool portalVisible = QueryResultsBuffer[i];
|
||||
if (portalVisible)
|
||||
{
|
||||
PutWallPortal(wallPortals[i], state);
|
||||
}
|
||||
}
|
||||
|
||||
// Process all the sprites on the current portal's back side which touch the portal.
|
||||
if (mCurrentPortal != nullptr) mCurrentPortal->RenderAttached(this, state);
|
||||
|
||||
if (drawpsprites)
|
||||
PreparePlayerSprites(Viewpoint.sector, in_area, state);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -447,6 +486,34 @@ void HWDrawInfo::CreateScene(bool drawpsprites, FRenderState& state)
|
|||
|
||||
}
|
||||
|
||||
void HWDrawInfo::PutWallPortal(HWWall wall, FRenderState& state)
|
||||
{
|
||||
HWWallDispatcher ddi(this);
|
||||
|
||||
int portaltype = wall.portaltype;
|
||||
int portalplane = wall.portalplane;
|
||||
|
||||
HWSkyInfo skyinfo;
|
||||
if (portaltype == PORTALTYPE_SKY)
|
||||
{
|
||||
skyinfo.init(this, wall.frontsector->sky, wall.Colormap.FadeColor);
|
||||
wall.sky = &skyinfo;
|
||||
}
|
||||
else if (portaltype == PORTALTYPE_SECTORSTACK)
|
||||
{
|
||||
if (screen->instack[1 - portalplane])
|
||||
return;
|
||||
}
|
||||
else if (portaltype == PORTALTYPE_PLANEMIRROR)
|
||||
{
|
||||
auto vpz = Viewpoint.Pos.Z;
|
||||
if ((portalplane == sector_t::ceiling && vpz > wall.frontsector->ceilingplane.fD()) || (portalplane == sector_t::floor && vpz < -wall.frontsector->floorplane.fD()))
|
||||
return;
|
||||
wall.planemirror = (portalplane == sector_t::ceiling) ? &wall.frontsector->ceilingplane : &wall.frontsector->floorplane;
|
||||
}
|
||||
wall.PutPortal(&ddi, state, portaltype, portalplane);
|
||||
}
|
||||
|
||||
void HWDrawInfo::UpdateLightmaps()
|
||||
{
|
||||
if (!outer && VisibleSurfaces.Size() < unsigned(lm_background_updates))
|
||||
|
|
@ -850,7 +917,7 @@ void HWDrawInfo::DrawScene(int drawmode, FRenderState& state)
|
|||
}
|
||||
|
||||
state.SetDepthMask(true);
|
||||
if (!gl_no_skyclear) drawctx->portalState.RenderFirstSkyPortal(recursion, this, state);
|
||||
if (!gl_no_skyclear && !gl_levelmesh) drawctx->portalState.RenderFirstSkyPortal(recursion, this, state);
|
||||
|
||||
RenderScene(state);
|
||||
|
||||
|
|
|
|||
|
|
@ -262,6 +262,7 @@ public:
|
|||
|
||||
void DrawScene(int drawmode, FRenderState& state);
|
||||
void CreateScene(bool drawpsprites, FRenderState& state);
|
||||
void PutWallPortal(HWWall wall, FRenderState& state);
|
||||
void RenderScene(FRenderState &state);
|
||||
void RenderTranslucent(FRenderState &state);
|
||||
void RenderPortal(HWPortal *p, FRenderState &state, bool usestencil);
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@
|
|||
#include "renderstyle.h"
|
||||
#include "textures.h"
|
||||
#include "r_data/colormaps.h"
|
||||
#include "doom_levelmesh.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4244)
|
||||
|
|
@ -33,6 +32,7 @@ struct HWDecal;
|
|||
struct FSection;
|
||||
enum area_t : int;
|
||||
class HWDrawContext;
|
||||
class DoomLevelMeshSurface;
|
||||
|
||||
enum HWRenderStyle
|
||||
{
|
||||
|
|
@ -67,6 +67,16 @@ enum PortalTypes
|
|||
PORTALTYPE_LINETOLINE,
|
||||
};
|
||||
|
||||
enum DoomLevelMeshSurfaceType
|
||||
{
|
||||
ST_NONE,
|
||||
ST_MIDDLESIDE,
|
||||
ST_UPPERSIDE,
|
||||
ST_LOWERSIDE,
|
||||
ST_CEILING,
|
||||
ST_FLOOR
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// One sector plane, still in fixed point
|
||||
|
|
|
|||
|
|
@ -126,9 +126,9 @@ void HWWall::SkyPlane(HWWallDispatcher *di, FRenderState& state, sector_t *secto
|
|||
{
|
||||
HWSkyInfo skyinfo;
|
||||
skyinfo.init(di->di, sector->sky, Colormap.FadeColor);
|
||||
ptype = PORTALTYPE_SKY;
|
||||
sky = &skyinfo;
|
||||
}
|
||||
ptype = PORTALTYPE_SKY;
|
||||
PutPortal(di, state, ptype, plane);
|
||||
}
|
||||
else if (sportal != nullptr)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue