Don't forget to update the vertex addr even when culling 2D draws

Fixes #20454
This commit is contained in:
Henrik Rydgård
2025-06-06 17:53:33 +02:00
parent 4c8aae50b2
commit 9d1f8a2575
3 changed files with 19 additions and 17 deletions
+11 -13
View File
@@ -527,25 +527,21 @@ bool DrawEngineCommon::TestBoundingBoxFast(const void *vdata, int vertexCount, c
// 2D bounding box test against scissor. No indexing yet.
// Only supports non-indexed draws with float positions.
bool DrawEngineCommon::TestBoundingBoxThrough(const void *vdata, int vertexCount, const VertexDecoder *dec, u32 vertType) {
bool DrawEngineCommon::TestBoundingBoxThrough(const void *vdata, int vertexCount, const VertexDecoder *dec, u32 vertType, int *bytesRead) {
// Grab temp buffer space from large offsets in decoded_. Not exactly safe for large draws.
if (vertexCount > 16) {
return true;
}
float *verts = (float *)(decoded_ + 65536 * 18);
// Although this may lead to drawing that shouldn't happen, the viewport is more complex on VR.
// Let's always say objects are within bounds.
if (gstate_c.Use(GPU_USE_VIRTUAL_REALITY))
return true;
// Try to skip NormalizeVertices if it's pure positions. No need to bother with a vertex decoder
// and a large vertex format.
u8 *temp_buffer = decoded_ + 65536 * 24;
// Simple, most common case.
int stride = dec->VertexSize();
int offset = dec->posoff;
const int stride = dec->VertexSize();
const int posOffset = dec->posoff;
*bytesRead = stride * vertexCount;
bool allOutsideLeft = true;
bool allOutsideTop = true;
@@ -559,10 +555,11 @@ bool DrawEngineCommon::TestBoundingBoxThrough(const void *vdata, int vertexCount
switch (vertType & GE_VTYPE_POS_MASK) {
case GE_VTYPE_POS_FLOAT:
{
// TODO: This can be SIMD'd, with some trickery.
for (int i = 0; i < vertexCount; i++) {
float *pos = (float*)((const u8 *)vdata + stride * i + offset);
float x = pos[0];
float y = pos[1];
const float *pos = (const float*)((const u8 *)vdata + stride * i + posOffset);
const float x = pos[0];
const float y = pos[1];
if (x >= left) {
allOutsideLeft = false;
}
@@ -582,8 +579,9 @@ bool DrawEngineCommon::TestBoundingBoxThrough(const void *vdata, int vertexCount
return true;
}
default:
// Shouldn't end up here with the checks outside this function.
_dbg_assert_(false);
return false;
return true;
}
}
+1 -1
View File
@@ -104,7 +104,7 @@ public:
// This is a less accurate version of TestBoundingBox, but faster. Can have more false positives.
// Doesn't support indexing.
bool TestBoundingBoxFast(const void *control_points, int vertexCount, const VertexDecoder *dec, u32 vertType);
bool TestBoundingBoxThrough(const void *vdata, int vertexCount, const VertexDecoder *dec, u32 vertType);
bool TestBoundingBoxThrough(const void *vdata, int vertexCount, const VertexDecoder *dec, u32 vertType, int *bytesRead);
void FlushPartialDecode() {
DecodeVerts(dec_, decoded_);
+7 -3
View File
@@ -1000,7 +1000,6 @@ void GPUCommonHW::Execute_Prim(u32 op, u32 diff) {
canExtend = false;
}
int bytesRead = 0;
gstate_c.UpdateUVScaleOffset();
// cull mode
@@ -1011,11 +1010,14 @@ void GPUCommonHW::Execute_Prim(u32 op, u32 diff) {
// Through mode early-out for simple float 2D draws, like in Fate Extra CCC (very beneficial there due to avoiding texture loads)
if ((vertexType & (GE_VTYPE_THROUGH_MASK | GE_VTYPE_POS_MASK | GE_VTYPE_IDX_MASK)) == (GE_VTYPE_THROUGH_MASK | GE_VTYPE_POS_FLOAT | GE_VTYPE_IDX_NONE)) {
if (!drawEngineCommon_->TestBoundingBoxThrough(verts, count, decoder, vertexType)) {
int bytesRead = 0;
if (!drawEngineCommon_->TestBoundingBoxThrough(verts, count, decoder, vertexType, &bytesRead)) {
gpuStats.numCulledDraws++;
int cycles = vertexCost_ * count;
gpuStats.vertexGPUCycles += cycles;
cyclesExecuted += cycles;
// NOTE! We still have to advance vertex pointers!
gstate_c.vertexAddr += bytesRead; // We know from the above check that it's not an indexed draw.
return;
}
}
@@ -1044,6 +1046,8 @@ void GPUCommonHW::Execute_Prim(u32 op, u32 diff) {
}
}
int bytesRead = 0;
// If the first one in a batch passes, let's assume the whole batch passes.
// Cuts down on checking, while not losing that much efficiency.
bool onePassed = false;
@@ -1357,7 +1361,7 @@ void GPUCommonHW::Execute_Bezier(u32 op, u32 diff) {
gstate_c.submitType = SubmitType::DRAW;
// After drawing, we advance pointers - see SubmitPrim which does the same.
int count = surface.num_points_u * surface.num_points_v;
const int count = surface.num_points_u * surface.num_points_v;
AdvanceVerts(gstate.vertType, count, bytesRead);
}