Actually queue up depth draws

This commit is contained in:
Henrik Rydgård
2024-12-28 22:55:56 +01:00
parent 4ef3ac474a
commit aec17d8829
8 changed files with 84 additions and 17 deletions
-1
View File
@@ -34,7 +34,6 @@ struct DepthDraw {
bool cullEnabled;
int cullMode;
DepthScissor scissor;
bool through;
int vertexOffset;
int indexOffset;
int vertexCount;
+35 -9
View File
@@ -932,7 +932,7 @@ Mat4F32 ComputeFinalProjMatrix() {
return m;
}
static bool CalculateDepthDraw(DepthDraw *draw, GEPrimitiveType prim, int vertexCount) {
bool DrawEngineCommon::CalculateDepthDraw(DepthDraw *draw, GEPrimitiveType prim, int vertexCount) {
switch (prim) {
case GE_PRIM_INVALID:
case GE_PRIM_KEEP_PREVIOUS:
@@ -978,8 +978,13 @@ static bool CalculateDepthDraw(DepthDraw *draw, GEPrimitiveType prim, int vertex
_dbg_assert_(gstate.isDepthWriteEnabled());
}
draw->vertexOffset = 0;
draw->indexOffset = 0;
if (depthVertexCount_ + vertexCount >= DEPTH_INDEXBUFFER_SIZE) {
// Can't add more.
return false;
}
draw->vertexOffset = depthVertexCount_;
draw->indexOffset = depthIndexCount_;
draw->vertexCount = vertexCount;
draw->cullEnabled = gstate.isCullEnabled();
draw->cullMode = gstate.getCullMode();
@@ -1028,8 +1033,11 @@ void DrawEngineCommon::DepthRasterTransform(GEPrimitiveType prim, VertexDecoder
// Copy indices.
memcpy(depthIndices_ + draw.indexOffset, decIndex_, sizeof(uint16_t) * vertexCount);
// FUTURE SPLIT --- The above will always run on the main thread. The below can be split across workers.
ExecuteDepthDraw(draw);
// Commit
depthIndexCount_ += vertexCount;
depthVertexCount_ += numDec;
depthDraws_.push_back(draw);
}
void DrawEngineCommon::DepthRasterPredecoded(GEPrimitiveType prim, const void *inVerts, int numDecoded, VertexDecoder *dec, int vertexCount) {
@@ -1060,8 +1068,22 @@ void DrawEngineCommon::DepthRasterPredecoded(GEPrimitiveType prim, const void *i
// Copy indices.
memcpy(depthIndices_ + draw.indexOffset, decIndex_, sizeof(uint16_t) * vertexCount);
// FUTURE SPLIT --- The above will always run on the main thread. The below can be split across workers.
ExecuteDepthDraw(draw);
// Commit
depthIndexCount_ += vertexCount;
depthVertexCount_ += numDecoded;
depthDraws_.push_back(draw);
}
void DrawEngineCommon::FlushQueuedDepth() {
for (const auto &draw : depthDraws_) {
ExecuteDepthDraw(draw);
}
// Reset queue
depthIndexCount_ = 0;
depthVertexCount_ = 0;
depthDraws_.clear();
}
void DrawEngineCommon::ExecuteDepthDraw(const DepthDraw &draw) {
@@ -1070,12 +1092,16 @@ void DrawEngineCommon::ExecuteDepthDraw(const DepthDraw &draw) {
float *tz = (float *)(depthScreenVerts_ + DEPTH_SCREENVERTS_COMPONENT_COUNT * 2);
int outVertCount = 0;
const float *vertices = depthTransformed_ + 4 * draw.vertexOffset;
const uint16_t *indices = depthIndices_ + draw.indexOffset;
switch (draw.prim) {
case GE_PRIM_RECTANGLES:
outVertCount = DepthRasterClipIndexedRectangles(tx, ty, tz, depthTransformed_ + 4 * draw.vertexOffset, depthIndices_ + draw.indexOffset, draw);
outVertCount = DepthRasterClipIndexedRectangles(tx, ty, tz, vertices, indices, draw);
break;
case GE_PRIM_TRIANGLES:
outVertCount = DepthRasterClipIndexedTriangles(tx, ty, tz, depthTransformed_ + 4 * draw.vertexOffset, depthIndices_ + draw.indexOffset, draw);
outVertCount = DepthRasterClipIndexedTriangles(tx, ty, tz, vertices, indices, draw);
break;
default:
_dbg_assert_(false);
+8
View File
@@ -164,6 +164,8 @@ public:
return decoded_ + 12 * 65536;
}
void FlushQueuedDepth();
protected:
virtual bool UpdateUseHWTessellation(bool enabled) const { return enabled; }
void UpdatePlanes();
@@ -178,6 +180,7 @@ protected:
void DepthRasterTransform(GEPrimitiveType prim, VertexDecoder *dec, uint32_t vertTypeID, int vertexCount);
void DepthRasterPredecoded(GEPrimitiveType prim, const void *inVerts, int numDecoded, VertexDecoder *dec, int vertexCount);
void ExecuteDepthDraw(const DepthDraw &draw);
bool CalculateDepthDraw(DepthDraw *draw, GEPrimitiveType prim, int vertexCount);
static inline int IndexSize(u32 vtype) {
const u32 indexType = (vtype & GE_VTYPE_IDX_MASK);
@@ -360,4 +363,9 @@ protected:
float *depthTransformed_ = nullptr;
int *depthScreenVerts_ = nullptr;
uint16_t *depthIndices_ = nullptr;
// Queue
int depthVertexCount_ = 0;
int depthIndexCount_ = 0;
std::vector<DepthDraw> depthDraws_;
};
+3 -1
View File
@@ -3240,6 +3240,7 @@ void FramebufferManagerCommon::ReadFramebufferToMemory(VirtualFramebuffer *vfb,
}
void FramebufferManagerCommon::FlushBeforeCopy() {
drawEngine_->FlushQueuedDepth();
// Flush anything not yet drawn before blitting, downloading, or uploading.
// This might be a stalled list, or unflushed before a block transfer, etc.
// Only bother if any draws are pending.
@@ -3247,7 +3248,8 @@ void FramebufferManagerCommon::FlushBeforeCopy() {
// TODO: It's really bad that we are calling SetRenderFramebuffer here with
// all the irrelevant state checking it'll use to decide what to do. Should
// do something more focused here.
SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason);
bool changed;
SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason, &changed);
drawEngine_->Flush();
}
}
+3 -1
View File
@@ -306,13 +306,14 @@ public:
void DestroyFramebuf(VirtualFramebuffer *v);
VirtualFramebuffer *DoSetRenderFrameBuffer(FramebufferHeuristicParams &params, u32 skipDrawReason);
VirtualFramebuffer *SetRenderFrameBuffer(bool framebufChanged, int skipDrawReason) {
VirtualFramebuffer *SetRenderFrameBuffer(bool framebufChanged, int skipDrawReason, bool *changed) {
// Inlining this part since it's so frequent.
if (!framebufChanged && currentRenderVfb_) {
currentRenderVfb_->last_frame_render = gpuStats.numFlips;
currentRenderVfb_->dirtyAfterDisplay = true;
if (!skipDrawReason)
currentRenderVfb_->reallyDirtyAfterDisplay = true;
*changed = false;
return currentRenderVfb_;
} else {
// This is so that we will be able to drive DoSetRenderFramebuffer with inputs
@@ -322,6 +323,7 @@ public:
VirtualFramebuffer *vfb = DoSetRenderFrameBuffer(inputs, skipDrawReason);
_dbg_assert_msg_(vfb, "DoSetRenderFramebuffer must return a valid framebuffer.");
_dbg_assert_msg_(currentRenderVfb_, "DoSetRenderFramebuffer must set a valid framebuffer.");
*changed = true;
return vfb;
}
}
+4 -2
View File
@@ -1311,8 +1311,10 @@ void GPUCommon::FlushImm() {
gstate_c.UpdateUVScaleOffset();
VirtualFramebuffer *vfb = nullptr;
if (framebufferManager_)
vfb = framebufferManager_->SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason);
if (framebufferManager_) {
bool changed;
vfb = framebufferManager_->SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason, &changed);
}
if (vfb) {
CheckDepthUsage(vfb);
}
+28 -3
View File
@@ -531,6 +531,7 @@ void GPUCommonHW::PreExecuteOp(u32 op, u32 diff) {
}
void GPUCommonHW::CopyDisplayToOutput(bool reallyDirty) {
drawEngineCommon_->FlushQueuedDepth();
// Flush anything left over.
drawEngineCommon_->Flush();
@@ -949,11 +950,16 @@ void GPUCommonHW::Execute_Prim(u32 op, u32 diff) {
}
// This also makes skipping drawing very effective.
VirtualFramebuffer *vfb = framebufferManager_->SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason);
bool changed;
VirtualFramebuffer *vfb = framebufferManager_->SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason, &changed);
if (blueToAlpha) {
vfb->usageFlags |= FB_USAGE_BLUE_TO_ALPHA;
}
if (changed) {
drawEngineCommon_->FlushQueuedDepth();
}
if (gstate_c.dirty & DIRTY_VERTEXSHADER_STATE) {
vertexCost_ = EstimatePerVertexCost();
}
@@ -1273,7 +1279,11 @@ void GPUCommonHW::Execute_Bezier(u32 op, u32 diff) {
gstate_c.framebufFormat = gstate.FrameBufFormat();
// This also make skipping drawing very effective.
VirtualFramebuffer *vfb = framebufferManager_->SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason);
bool changed;
VirtualFramebuffer *vfb = framebufferManager_->SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason, &changed);
if (changed) {
drawEngineCommon_->FlushQueuedDepth();
}
if (gstate_c.skipDrawReason & (SKIPDRAW_SKIPFRAME | SKIPDRAW_NON_DISPLAYED_FB)) {
// TODO: Should this eat some cycles? Probably yes. Not sure if important.
return;
@@ -1345,7 +1355,11 @@ void GPUCommonHW::Execute_Spline(u32 op, u32 diff) {
gstate_c.framebufFormat = gstate.FrameBufFormat();
// This also make skipping drawing very effective.
VirtualFramebuffer *vfb = framebufferManager_->SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason);
bool changed;
VirtualFramebuffer *vfb = framebufferManager_->SetRenderFrameBuffer(gstate_c.IsDirty(DIRTY_FRAMEBUF), gstate_c.skipDrawReason, &changed);
if (changed) {
drawEngineCommon_->FlushQueuedDepth();
}
if (gstate_c.skipDrawReason & (SKIPDRAW_SKIPFRAME | SKIPDRAW_NON_DISPLAYED_FB)) {
// TODO: Should this eat some cycles? Probably yes. Not sure if important.
return;
@@ -1415,6 +1429,7 @@ void GPUCommonHW::Execute_Spline(u32 op, u32 diff) {
}
void GPUCommonHW::Execute_BlockTransferStart(u32 op, u32 diff) {
drawEngineCommon_->FlushQueuedDepth();
Flush();
PROFILE_THIS_SCOPE("block"); // don't include the flush in the profile, would be misleading.
@@ -1763,6 +1778,16 @@ void GPUCommonHW::Execute_TexFlush(u32 op, u32 diff) {
framebufferManager_->DiscardFramebufferCopy();
}
u32 GPUCommonHW::DrawSync(int mode) {
drawEngineCommon_->FlushQueuedDepth();
return GPUCommon::DrawSync(mode);
}
int GPUCommonHW::ListSync(int listid, int mode) {
drawEngineCommon_->FlushQueuedDepth();
return GPUCommon::ListSync(listid, mode);
}
size_t GPUCommonHW::FormatGPUStatsCommon(char *buffer, size_t size) {
float vertexAverageCycles = gpuStats.numVertsSubmitted > 0 ? (float)gpuStats.vertexGPUCycles / (float)gpuStats.numVertsSubmitted : 0.0f;
return snprintf(buffer, size,
+3
View File
@@ -42,6 +42,9 @@ public:
void SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format) override;
void InvalidateCache(u32 addr, int size, GPUInvalidationType type) override;
u32 DrawSync(int mode) override;
int ListSync(int listid, int mode) override;
bool FramebufferDirty() override;
bool FramebufferReallyDirty() override;