A texture that fits in the GE's 8 KB texture cache keeps what was first
read until TEXFLUSH, across primitives and draws, so a later self-textured
draw doesn't see an earlier one's writes (gpu/probe exp174: three passes
over a 16x16 4444 buffer differ in 177 pixels with and without a flush
between them, both now exact). FF Type-0's (NPJH50443) blur; two of its
PSP replays become exact.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Pixels past the framebuffer's stride land at the start of the next row,
which another binning task may be drawing, so the result raced. Tokimeki
Memorial (NPJH50127) blurs a 128 wide buffer under a full screen scissor;
its PSP replay is now exact (gpu/probe exp166).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The GE samples through its texture cache, so a primitive that textures from
its own render target mostly reads the old contents (geprobe exp81, exp159,
exp160). Give each such primitive a snapshot, refreshing only the rows the
previous one drew.
3rd Birthday (ULUS10567) bloom becomes exact on PSP replays, Burnout
Dominator's glare 93% -> 98% and Ridge Racer's blur 40% -> 94% of pixels.
The remaining differences are rows where the cache's lazily loaded 8-row
blocks already see the primitive's own writes.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
With vertices far apart in the 4096 pixel screen space the cross product
overflowed 32 bits, flipping its sign, so both windings of a large triangle
were dropped (gpu/probe exp132: the PSP draws it).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A triangle with collinear vertices lights no pixels on the PSP, even when its
edge runs through pixel centers (gpu/probe exp118, through and transform
mode). The binner only dropped them when all x or all y were equal, so
degenerate strip triangles drew lines of pixels along shared edges. Fixes
the last differences in two frame dumps (Issue 15129, ULUS10041).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- 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) <noreply@anthropic.com>
- The block transfer overlap check passed the stride in pixels where bytes
are expected, so it only covered part of the rectangle.
- A selfrender/selfdepth flush in UpdateState dropped the current draw's
pending writes and reads, so later transfers didn't wait for it.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A code space clear frees the functions the current state points to, but
the state was kept as long as the GE registers didn't change. Track the
clear generations and recompute, also when a compile during the state
computation clears the caches.
Also skip the binner flush for compiles on builds without the software
JIT, where Compile() does nothing.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Might be some other ways, like doing this directly in a vertex reader.
Also am thinking about doing things regarding UVs or positions.
Flags not yet used, keeping separate for perf checks.
When we flush we mark all pending writes zero, but we rely on this being
set to detect self-render.
TRANSFORM_ALL was wrong as well, sometimes clearing BINNER_RANGE.
Even if X is not equal, if all Y are equal, we can still skip.
This seems to happen more often than I expected with far away objects.
Skipping here avoids filling up the queue.
This generally detects overlap more accurately using a dirty rectangles
approach. Also detects render to self much more accurately, including
with depth.
Some games (i.e. VC3) benefit from an early drain, since they get more
done while processing more verts. Others finish the draw quickly, and
then cause significant overhead in queueing new threads.
This attempts to balance the two, and improves Call of Duty and Blade
Dancer.