diff --git a/GPU/Common/DepthRaster.h b/GPU/Common/DepthRaster.h index 2253dddd75..189748bb47 100644 --- a/GPU/Common/DepthRaster.h +++ b/GPU/Common/DepthRaster.h @@ -34,7 +34,6 @@ struct DepthDraw { bool cullEnabled; int cullMode; DepthScissor scissor; - bool through; int vertexOffset; int indexOffset; int vertexCount; diff --git a/GPU/Common/DrawEngineCommon.cpp b/GPU/Common/DrawEngineCommon.cpp index 7e833d22ad..3544b2a225 100644 --- a/GPU/Common/DrawEngineCommon.cpp +++ b/GPU/Common/DrawEngineCommon.cpp @@ -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); diff --git a/GPU/Common/DrawEngineCommon.h b/GPU/Common/DrawEngineCommon.h index e013556ea7..e25d3662a2 100644 --- a/GPU/Common/DrawEngineCommon.h +++ b/GPU/Common/DrawEngineCommon.h @@ -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 depthDraws_; }; diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 0ecfbdfd96..0d2e781664 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -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(); } } diff --git a/GPU/Common/FramebufferManagerCommon.h b/GPU/Common/FramebufferManagerCommon.h index 37a71d751b..ee9cd6481c 100644 --- a/GPU/Common/FramebufferManagerCommon.h +++ b/GPU/Common/FramebufferManagerCommon.h @@ -306,13 +306,14 @@ public: void DestroyFramebuf(VirtualFramebuffer *v); VirtualFramebuffer *DoSetRenderFrameBuffer(FramebufferHeuristicParams ¶ms, 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; } } diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index da5a483336..25635b8148 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -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); } diff --git a/GPU/GPUCommonHW.cpp b/GPU/GPUCommonHW.cpp index 276412f345..03df3acfba 100644 --- a/GPU/GPUCommonHW.cpp +++ b/GPU/GPUCommonHW.cpp @@ -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, diff --git a/GPU/GPUCommonHW.h b/GPU/GPUCommonHW.h index 3703053385..07e4002fb2 100644 --- a/GPU/GPUCommonHW.h +++ b/GPU/GPUCommonHW.h @@ -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;