mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-01 14:58:14 +00:00
SoftGPU: Fix bin queue bookkeeping and dependency tracking
- Flush() on an empty queue now trims the state and CLUT rings, since its callers flush because one is full and push right after. - BinQueue::Full() uses >=, so an overshoot can't go unnoticed. - IsExactSelfRender compares against the target the queued draws were binned for, not gstate, which already has the next one during a flush. - A depth test without depth writes marks the depth buffer as read. - The DarkStalkers untextured sprite recomputes the binner state around it. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
1 parent
74553bfa1a
commit
9d3022642b
3 files changed
+29
-6
No files matched your search
@@ -209,6 +209,7 @@ void BinManager::UpdateState() {
|
||||
const bool hadDepth = pendingWrites_[1].base != 0;
|
||||
|
||||
if (HasDirty(SoftDirty::BINNER_RANGE)) {
|
||||
drawTargetAddr_ = gstate.getFrameBufAddress();
|
||||
DrawingCoords scissorTL(gstate.getScissorX1(), gstate.getScissorY1());
|
||||
DrawingCoords scissorBR(std::min(gstate.getScissorX2(), gstate.getRegionX2()), std::min(gstate.getScissorY2(), gstate.getRegionY2()));
|
||||
ScreenCoords screenScissorTL = TransformUnit::DrawingToScreen(scissorTL, 0);
|
||||
@@ -292,14 +293,14 @@ bool BinManager::HasTextureWrite(const RasterizerState &state) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BinManager::IsExactSelfRender(const Rasterizer::RasterizerState &state, const BinItem &item) {
|
||||
bool BinManager::IsExactSelfRender(const Rasterizer::RasterizerState &state, const BinItem &item) const {
|
||||
if (item.type != BinItemType::SPRITE && item.type != BinItemType::RECT)
|
||||
return false;
|
||||
if (state.textureProj || state.maxTexLevel > 0)
|
||||
return false;
|
||||
|
||||
// Only possible if the texture is 1:1.
|
||||
if ((state.texaddr[0] & 0x0F1FFFFF) != (gstate.getFrameBufAddress() & 0x0F1FFFFF))
|
||||
if ((state.texaddr[0] & 0x0F1FFFFF) != (drawTargetAddr_ & 0x0F1FFFFF))
|
||||
return false;
|
||||
int bufferPixelWidth = BufferFormatBytesPerPixel(state.pixelID.FBFormat());
|
||||
int texturePixelWidth = textureBitsPerPixel[state.samplerID.texfmt] / 8;
|
||||
@@ -361,8 +362,13 @@ void BinManager::MarkPendingWrites(const Rasterizer::RasterizerState &state) {
|
||||
constexpr uint32_t mirrorMask = 0x041FFFFF;
|
||||
const uint32_t bpp = state.pixelID.FBFormat() == GE_FORMAT_8888 ? 4 : 2;
|
||||
pendingWrites_[0].Expand(gstate.getFrameBufAddress() & mirrorMask, bpp, gstate.FrameBufStride(), scissorTL, scissorBR);
|
||||
if (state.pixelID.depthWrite)
|
||||
if (state.pixelID.depthWrite) {
|
||||
pendingWrites_[1].Expand(gstate.getDepthBufAddress() & mirrorMask, 2, gstate.DepthBufStride(), scissorTL, scissorBR);
|
||||
} else if (gstate.isDepthTestEnabled() && !gstate.isModeClear()) {
|
||||
// Testing without writing still reads the depth buffer, so a transfer into it has to wait.
|
||||
const uint32_t depthAddr = gstate.getDepthBufAddress() & mirrorMask;
|
||||
pendingReads_[depthAddr].Expand(depthAddr, 2, gstate.DepthBufStride(), scissorTL, scissorBR);
|
||||
}
|
||||
}
|
||||
|
||||
inline void BinDirtyRange::Expand(uint32_t newBase, uint32_t bpp, uint32_t stride, const DrawingCoords &tl, const DrawingCoords &br) {
|
||||
@@ -584,8 +590,17 @@ void BinManager::Drain(bool flushing) {
|
||||
}
|
||||
|
||||
void BinManager::Flush(const char *reason) {
|
||||
if (queueRange_.x1 == 0x7FFFFFFF)
|
||||
if (queueRange_.x1 == 0x7FFFFFFF) {
|
||||
// Nothing queued, so nothing refers to the older states and CLUTs. Trim them anyway: callers
|
||||
// flush because one of these rings is full, and push into it right after.
|
||||
while (states_.Size() > 1) {
|
||||
states_.SkipNext();
|
||||
}
|
||||
while (cluts_.Size() > 1) {
|
||||
cluts_.SkipNext();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
double st = 0.0;
|
||||
const bool collectDebugStats = g_coreCollectDebugStats;
|
||||
|
||||
@@ -132,7 +132,7 @@ struct BinQueue {
|
||||
}
|
||||
|
||||
bool Full() const {
|
||||
return size_ == N - 1;
|
||||
return size_ >= N - 1;
|
||||
}
|
||||
|
||||
bool NearFull() const {
|
||||
@@ -278,13 +278,16 @@ private:
|
||||
const char *slowestFlushReason_ = nullptr;
|
||||
double slowestFlushTime_ = 0.0;
|
||||
int lastFlipstats_ = 0;
|
||||
// The framebuffer the queued draws render to. A framebuffer change flushes first, so it's one for all
|
||||
// of them, and during that flush gstate already has the new one.
|
||||
u32 drawTargetAddr_ = 0;
|
||||
int enqueues_ = 0;
|
||||
int mostThreads_ = 0;
|
||||
|
||||
void MarkPendingReads(const Rasterizer::RasterizerState &state);
|
||||
void MarkPendingWrites(const Rasterizer::RasterizerState &state);
|
||||
bool HasTextureWrite(const Rasterizer::RasterizerState &state);
|
||||
static bool IsExactSelfRender(const Rasterizer::RasterizerState &state, const BinItem &item);
|
||||
bool IsExactSelfRender(const Rasterizer::RasterizerState &state, const BinItem &item) const;
|
||||
void OptimizePendingStates(uint16_t first, uint16_t last);
|
||||
BinCoords Scissor(BinCoords range);
|
||||
BinCoords Range(const VertexData &v0, const VertexData &v1, const VertexData &v2);
|
||||
|
||||
@@ -506,11 +506,16 @@ bool RectangleFastPath(const VertexData &v0, const VertexData &v1, BinManager &b
|
||||
if (g_needsClearAfterDialog) {
|
||||
g_needsClearAfterDialog = false;
|
||||
// Afterwards, we also need to clear the actual destination. Can do a fast rectfill.
|
||||
// The binner's state was computed with texturing on, so recompute it around the sprite.
|
||||
const SoftDirty texDirty = SoftDirty::SAMPLER_BASIC | SoftDirty::SAMPLER_TEXLIST | SoftDirty::RAST_TEX | SoftDirty::BINNER_OVERLAP;
|
||||
gstate.textureMapEnable &= ~1;
|
||||
binner.SetDirty(texDirty);
|
||||
binner.UpdateState();
|
||||
VertexData newV1 = v1;
|
||||
newV1.color0 = 0xFF000000;
|
||||
binner.AddSprite(v0, newV1);
|
||||
gstate.textureMapEnable |= 1;
|
||||
binner.SetDirty(texDirty);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
|
||||
Reference in new issue
Block a user