mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-08-31 09:45:24 +02:00
Expand did `height += ((int)base - (int)newBase) / (stride * bpp)`. The right operand is unsigned, so when newBase was above base the negative difference converted to ~4 billion before the division and height wrapped. After that, HasPendingWrite()'s `start >= base + height * strideBytes` early-out was taken for every query, so the binner stopped noticing that a draw textures from the framebuffer it's writing - skipping the flush and leaving maxTasks_ high, which makes a self-sampling draw depend on which worker thread got there first. Reachable without exotic state: scissor changes mark BINNER_RANGE dirty without forcing a flush, so drawing with the scissor top at y=0 and then moving it down is enough. Handle both directions explicitly instead. ClearDirty was missing the bounds clamp its twin MarkDirty has. start is masked to [0, 2047] but bytes isn't bounded - IsVRAMAddress accepts the whole mirrored 8MB window - so a large guest framebuffer near the top of VRAM runs the loop off the end of vramDirty_[2048] and writes into whatever follows it. Only active with frameskip enabled, but then it runs every flip. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vd8ntC2brCUtCrDJMqLbs8
To get to 100% compatibility, we will need a software renderer as there are games out there that do tricks that can't really be faked in a sensible way. Useful for homebrew too that mix sw and accel rendering.