partial depth pre-pass with some hacky heuristics

This commit is contained in:
myT 2023-07-02 00:23:02 +02:00
parent fadbea4b2c
commit a60693ae65
5 changed files with 111 additions and 56 deletions

View File

@ -243,6 +243,11 @@ struct IndexBuffer : BufferBase
memcpy(idx, &tess.indexes[0], tess.numIndexes * sizeof(uint32_t));
}
uint32_t* GetCurrentAddress()
{
return mapped + batchFirst + batchCount;
}
HBuffer buffer = RHI_MAKE_NULL_HANDLE();
uint32_t* mapped = NULL;
};
@ -306,7 +311,7 @@ struct World
void EndFrame();
void Begin();
void End();
void DrawPrePass();
void DrawPrePass(const drawSceneViewCommand_t& cmd);
void BeginBatch(const shader_t* shader, bool hasStaticGeo);
void EndBatch();
void EndSkyBatch();
@ -339,14 +344,11 @@ struct World
};
};
#if defined(ZPP)
// Z pre-pass
HRootSignature zppRootSignature;
HDescriptorTable zppDescriptorTable;
HPipeline zppPipeline; // @TODO: 1 per cull type
GeometryBuffer zppIndexBuffer;
HPipeline zppPipeline;
GeometryBuffer zppVertexBuffer;
#endif
// shared
BufferFamily::Id boundVertexBuffers;

View File

@ -21,6 +21,9 @@ along with Challenge Quake 3. If not, see <https://www.gnu.org/licenses/>.
// Gameplay Rendering Pipeline - world/3D rendering
//#define ENABLE_GUI
#include "grp_local.h"
#include "../client/cl_imgui.h"
namespace zpp
@ -66,13 +69,20 @@ struct FogPixelRC
#pragma pack(pop)
static bool drawPrePass = false;
static bool drawPrePass = true;
static bool drawDynamic = true;
static bool drawTransparents = true;
static bool drawFog = true;
static bool drawSky = true;
static bool drawClouds = true;
static bool forceDynamic = false;
static int zppMaxTriangleCount = 64;
static float zppMinRadiusOverZ = 0.5f;
static int zppDrawnTriangleCount = 0;
static const uint32_t zppMaxVertexCount = 1 << 20;
static const uint32_t zppMaxIndexCount = 8 * zppMaxVertexCount;
static uint32_t zppIndices[zppMaxIndexCount];
static bool HasStaticGeo(const drawSurf_t* drawSurf, const shader_t* shader)
@ -144,7 +154,6 @@ void World::Init()
if(grp.firstInit)
{
#if defined(ZPP)
//
// depth pre-pass
//
@ -161,40 +170,35 @@ void World::Init()
zppDescriptorTable = CreateDescriptorTable(DescriptorTableDesc("Z pre-pass", zppRootSignature));
}
{
// we could handle all 3 cull mode modes and alpha testing, but we do a partial pre-pass
// it wouldn't make sense going any further instead of trying a visibility buffer approach
GraphicsPipelineDesc desc("Z pre-pass", zppRootSignature);
desc.vertexShader = ShaderByteCode(zpp::g_vs);
desc.pixelShader = ShaderByteCode(zpp::g_ps);
desc.vertexLayout.AddAttribute(0, ShaderSemantic::Position, DataType::Float32, 4, 0);
desc.vertexLayout.AddAttribute(0, ShaderSemantic::Position, DataType::Float32, 3, 0);
desc.depthStencil.depthComparison = ComparisonFunction::GreaterEqual;
desc.depthStencil.depthStencilFormat = TextureFormat::Depth32_Float;
desc.depthStencil.enableDepthTest = true;
desc.depthStencil.enableDepthWrites = true;
desc.rasterizer.cullMode = CT_FRONT_SIDED; // need 1 PSO per cull mode...
desc.rasterizer.cullMode = CT_FRONT_SIDED;
zppPipeline = CreateGraphicsPipeline(desc);
}
{
const uint32_t maxVertexCount = 1 << 20;
const uint32_t maxIndexCount = 8 * maxVertexCount;
zppVertexBuffer.Init(maxVertexCount, 16);
zppIndexBuffer.Init(maxIndexCount, sizeof(Index));
zppVertexBuffer.Init(zppMaxVertexCount, 3 * sizeof(float));
{
BufferDesc desc("depth pre-pass vertex", zppVertexBuffer.byteCount, ResourceStates::VertexBufferBit);
zppVertexBuffer.buffer = CreateBuffer(desc);
}
{
BufferDesc desc("depth pre-pass index", zppIndexBuffer.byteCount, ResourceStates::IndexBufferBit);
zppIndexBuffer.buffer = CreateBuffer(desc);
}
}
#endif
//
// dynamic (streamed) geometry
//
for(uint32_t f = 0; f < FrameCount; ++f)
{
// the doubled index count is for the depth pre-pass
const int MaxDynamicVertexCount = 256 << 10;
const int MaxDynamicIndexCount = MaxDynamicVertexCount * 8;
const int MaxDynamicIndexCount = MaxDynamicVertexCount * 8 * 2;
GeometryBuffers& db = dynBuffers[f];
db.vertexBuffers.Create(va("dynamic #%d", f + 1), MemoryUsage::Upload, MaxDynamicVertexCount);
db.indexBuffer.Create(va("dynamic #%d", f + 1), MemoryUsage::Upload, MaxDynamicIndexCount);
@ -407,22 +411,55 @@ void World::End()
grp.renderMode = RenderMode::None;
}
void World::DrawPrePass()
void World::DrawPrePass(const drawSceneViewCommand_t& cmd)
{
#if defined(ZPP)
if(!drawPrePass ||
tr.world == NULL ||
zppIndexBuffer.batchCount == 0 ||
zppVertexBuffer.batchCount == 0)
if(!drawPrePass || tr.world == NULL)
{
return;
}
GeometryBuffers& db = dynBuffers[GetFrameIndex()];
const uint32_t firstIndex = db.indexBuffer.batchFirst;
uint32_t* indices = db.indexBuffer.GetCurrentAddress();
int fullIndexCount = 0;
// we can't do a single draw because some world surfaces could be referenced by animated entities
const int surfCount = cmd.numDrawSurfs;
const drawSurf_t* drawSurf = cmd.drawSurfs;
for(int ds = 0; ds < surfCount; ++ds, ++drawSurf)
{
int entityNum = 0;
const shader_t* shader = NULL;
R_DecomposeSort(drawSurf->sort, &entityNum, &shader);
const int surfIndexCount = drawSurf->zppIndexCount;
if(surfIndexCount <= 0 ||
entityNum != ENTITYNUM_WORLD ||
surfIndexCount > zppMaxTriangleCount * 3 ||
drawSurf->radiusOverZ < zppMinRadiusOverZ)
{
continue;
}
if(!db.indexBuffer.CanAdd(surfIndexCount))
{
Q_assert(!"Dynamic buffer too small!");
break;
}
memcpy(indices, zppIndices + drawSurf->zppFirstIndex, surfIndexCount * sizeof(uint32_t));
fullIndexCount += surfIndexCount;
indices += surfIndexCount;
db.indexBuffer.EndBatch(surfIndexCount);
}
zppDrawnTriangleCount = fullIndexCount;
if(fullIndexCount <= 0)
{
return;
}
SCOPED_RENDER_PASS("Depth Pre-Pass", 0.75f, 0.75f, 0.375f);
// @TODO: evaluate later whether binding the color target here is OK?
CmdBindRenderTargets(0, NULL, &depthTexture);
CmdBindRootSignature(zppRootSignature);
CmdBindPipeline(zppPipeline);
CmdBindDescriptorTable(zppRootSignature, zppDescriptorTable);
@ -431,14 +468,11 @@ void World::DrawPrePass()
memcpy(vertexRC.modelViewMatrix, backEnd.viewParms.world.modelMatrix, sizeof(vertexRC.modelViewMatrix));
memcpy(vertexRC.projectionMatrix, backEnd.viewParms.projectionMatrix, sizeof(vertexRC.projectionMatrix));
CmdSetRootConstants(zppRootSignature, ShaderStage::Vertex, &vertexRC);
CmdBindPipeline(zppPipeline);
CmdBindIndexBuffer(zppIndexBuffer.buffer, indexType, 0);
const uint32_t vertexStride = 4 * sizeof(float);
const uint32_t vertexStride = 3 * sizeof(float);
CmdBindVertexBuffers(1, &zppVertexBuffer.buffer, &vertexStride, NULL);
CmdDrawIndexed(zppIndexBuffer.batchCount, 0, 0);
boundVertexBuffers = BufferFamily::PrePass;
boundIndexBuffer = BufferFamily::PrePass;
#endif
BindIndexBuffer(false);
CmdDrawIndexed(fullIndexCount, firstIndex, 0);
}
void World::BeginBatch(const shader_t* shader, bool hasStaticGeo)
@ -616,7 +650,7 @@ void World::RestartBatch()
void World::DrawGUI()
{
#if defined(_DEBUG)
#if defined(ENABLE_GUI)
if(tr.world == NULL)
{
return;
@ -640,6 +674,8 @@ void World::DrawGUI()
if(ImGui::Begin("World", &active, ImGuiWindowFlags_AlwaysAutoResize))
{
ImGui::Checkbox("Depth Pre-Pass", &drawPrePass);
ImGui::SliderInt("Pre-pass Max Triangles", &zppMaxTriangleCount, 1, 256);
ImGui::SliderFloat("Pre-pass Min Radius", &zppMinRadiusOverZ, 1.0f / 256.0f, 256.0f / 256.0f);
ImGui::Checkbox("Draw Dynamic", &drawDynamic);
ImGui::Checkbox("Draw Transparents", &drawTransparents);
ImGui::Checkbox("Draw Fog", &drawFog);
@ -649,6 +685,7 @@ void World::DrawGUI()
ImGui::Text("PSO count: %d", (int)grp.psoCount);
ImGui::Text("PSO changes: %d", psoChangeCount);
ImGui::Text("ZPP triangles: %d", zppDrawnTriangleCount);
#if 0
vec3_t axis[3];
@ -676,15 +713,11 @@ void World::DrawGUI()
void World::ProcessWorld(world_t& world)
{
#if defined(ZPP)
{
zppVertexBuffer.batchFirst = 0;
zppIndexBuffer.batchFirst = 0;
zppVertexBuffer.batchCount = 0;
zppIndexBuffer.batchCount = 0;
float* vtx = (float*)BeginBufferUpload(zppVertexBuffer.buffer);
Index* idx = (Index*)BeginBufferUpload(zppIndexBuffer.buffer);
int firstVertex = 0;
int firstIndex = 0;
@ -692,7 +725,10 @@ void World::ProcessWorld(world_t& world)
{
msurface_t* const surf = &world.surfaces[s];
if(surf->shader->numStages == 0 ||
surf->shader->isDynamic)
surf->shader->isDynamic ||
!surf->shader->isOpaque ||
surf->shader->isAlphaTestedOpaque ||
surf->shader->cullType != CT_FRONT_SIDED)
{
continue;
}
@ -707,25 +743,26 @@ void World::ProcessWorld(world_t& world)
{
continue;
}
if(firstVertex + surfVertexCount >= zppVertexBuffer.totalCount ||
firstIndex + surfIndexCount >= zppIndexBuffer.totalCount)
if(firstVertex + surfVertexCount >= zppVertexBuffer.totalCount)
{
break;
}
for(int v = 0; v < tess.numVertexes; ++v)
for(int v = 0; v < surfVertexCount; ++v)
{
*vtx++ = tess.xyz[v][0];
*vtx++ = tess.xyz[v][1];
*vtx++ = tess.xyz[v][2];
*vtx++ = 1.0f;
}
for(int i = 0; i < tess.numIndexes; ++i)
uint32_t* idx = zppIndices + firstIndex;
for(int i = 0; i < surfIndexCount; ++i)
{
*idx++ = tess.indexes[i] + firstVertex;
}
surf->zppFirstIndex = firstIndex;
surf->zppIndexCount = surfIndexCount;
firstVertex += surfVertexCount;
firstIndex += surfIndexCount;
tess.numVertexes = 0;
@ -733,14 +770,10 @@ void World::ProcessWorld(world_t& world)
}
EndBufferUpload(zppVertexBuffer.buffer);
EndBufferUpload(zppIndexBuffer.buffer);
zppVertexBuffer.batchCount = firstVertex;
zppIndexBuffer.batchCount = firstIndex;
zppVertexBuffer.batchFirst = 0;
zppIndexBuffer.batchFirst = 0;
}
#endif
statChunkCount = 1; // index 0 is invalid
statIndexCount = 0;
@ -852,6 +885,11 @@ void World::DrawSceneView(const drawSceneViewCommand_t& cmd)
boundVertexBuffers = BufferFamily::Invalid;
boundIndexBuffer = BufferFamily::Invalid;
// the index buffer is also used for the Z pre-pass
GeometryBuffers& db = dynBuffers[GetFrameIndex()];
db.vertexBuffers.BeginUpload();
db.indexBuffer.BeginUpload();
// portals get the chance to write to depth and color before everyone else
{
const shader_t* shader = NULL;
@ -859,7 +897,7 @@ void World::DrawSceneView(const drawSceneViewCommand_t& cmd)
R_DecomposeSort(cmd.drawSurfs->shaderSort, &entityNum, &shader);
if(shader->sort != SS_PORTAL)
{
DrawPrePass();
DrawPrePass(cmd);
}
}
@ -882,10 +920,6 @@ void World::DrawSceneView(const drawSceneViewCommand_t& cmd)
bool oldHasStaticGeo = false;
backEnd.currentEntity = &tr.worldEntity;
GeometryBuffers& db = dynBuffers[GetFrameIndex()];
db.vertexBuffers.BeginUpload();
db.indexBuffer.BeginUpload();
int ds;
const drawSurf_t* drawSurf;
for(ds = 0, drawSurf = drawSurfs; ds < surfCount; ++ds, ++drawSurf)

View File

@ -536,6 +536,9 @@ struct drawSurf_t {
int shaderNum; // unsorted shader index, for when we need to do fix-ups
float greyscale; // how monochrome to draw all the stages
int staticGeoChunk;
int zppFirstIndex;
int zppIndexCount;
float radiusOverZ;
};
void R_TessellateSurface( const surfaceType_t* surfType );
@ -695,6 +698,8 @@ struct msurface_t {
const shader_t* shader;
int fogIndex;
int staticGeoChunk;
int zppFirstIndex;
int zppIndexCount;
const surfaceType_t* data; // any of srf*_t
};
@ -1113,7 +1118,7 @@ void R_AddMD3Surfaces( trRefEntity_t *e );
void R_AddPolygonSurfaces();
void R_AddDrawSurf( const surfaceType_t* surface, const shader_t* shader, int fogIndex, int staticGeoChunk = 0 );
void R_AddDrawSurf(const surfaceType_t* surface, const shader_t* shader, int fogIndex, int staticGeoChunk = 0, int zppFirstIndex = 0, int zppIndexCount = 0, float radiusOverZ = 666.0f );
void R_AddLitSurf( const surfaceType_t* surface, const shader_t* shader, int fogIndex );
uint64_t R_ComposeSort( int entityNum, const shader_t* shader, int staticGeoChunk );
void R_DecomposeSort( uint64_t sort, int* entityNum, const shader_t** shader );

View File

@ -1280,7 +1280,7 @@ static float SurfGreyscaleAmount( const shader_t* shader )
}
void R_AddDrawSurf( const surfaceType_t* surface, const shader_t* shader, int fogIndex, int staticGeoChunk )
void R_AddDrawSurf( const surfaceType_t* surface, const shader_t* shader, int fogIndex, int staticGeoChunk, int zppFirstIndex, int zppIndexCount, float radiusOverZ )
{
if (tr.refdef.numDrawSurfs >= MAX_DRAWSURFS)
return;
@ -1292,6 +1292,9 @@ void R_AddDrawSurf( const surfaceType_t* surface, const shader_t* shader, int fo
drawSurf->shaderNum = shader->index;
drawSurf->greyscale = SurfGreyscaleAmount( shader );
drawSurf->staticGeoChunk = staticGeoChunk;
drawSurf->zppFirstIndex = zppFirstIndex;
drawSurf->zppIndexCount = zppIndexCount;
drawSurf->radiusOverZ = radiusOverZ;
}

View File

@ -199,7 +199,18 @@ static void R_AddWorldSurface( msurface_t* surf )
surf->vcVisible = tr.viewCount;
R_AddDrawSurf( surf->data, surf->shader, surf->fogIndex, surf->staticGeoChunk );
float radiusOverZ = 666.0f;
if ( *surf->data == SF_GRID ) {
const srfGridMesh_t* const grid = (const srfGridMesh_t*)surf->data;
const float dist = Distance( grid->localOrigin, tr.refdef.vieworg );
radiusOverZ = grid->meshRadius / max( dist, 0.001f );
} else if ( *surf->data == SF_TRIANGLES ) {
const srfTriangles_t* const triangles = (const srfTriangles_t*)surf->data;
const float dist = Distance( triangles->localOrigin, tr.refdef.vieworg );
radiusOverZ = triangles->radius / max( dist, 0.001f );
}
R_AddDrawSurf( surf->data, surf->shader, surf->fogIndex, surf->staticGeoChunk, surf->zppFirstIndex, surf->zppIndexCount, radiusOverZ );
}