diff --git a/GPU/Common/DrawEngineCommon.cpp b/GPU/Common/DrawEngineCommon.cpp index 495b206515..46742e79b7 100644 --- a/GPU/Common/DrawEngineCommon.cpp +++ b/GPU/Common/DrawEngineCommon.cpp @@ -244,7 +244,7 @@ void DrawEngineCommon::DispatchSubmitImm(GEPrimitiveType prim, TransformedVertex // // It does the simplest and safest test possible: If all points of a bbox is outside a single of // our clipping planes, we reject the box. Tighter bounds would be desirable but would take more calculations. -bool DrawEngineCommon::TestBoundingBox(const void* control_points, int vertexCount, u32 vertType, int *bytesRead) { +bool DrawEngineCommon::TestBoundingBox(const void* control_points, int vertexCount, u32 vertType) { SimpleVertex *corners = (SimpleVertex *)(decoded + 65536 * 12); float *verts = (float *)(decoded + 65536 * 18); @@ -252,19 +252,16 @@ bool DrawEngineCommon::TestBoundingBox(const void* control_points, int vertexCou // and a large vertex format. if ((vertType & 0xFFFFFF) == GE_VTYPE_POS_FLOAT) { verts = (float *)control_points; - *bytesRead = 3 * sizeof(float) * vertexCount; } else if ((vertType & 0xFFFFFF) == GE_VTYPE_POS_8BIT) { const s8 *vtx = (const s8 *)control_points; for (int i = 0; i < vertexCount * 3; i++) { verts[i] = vtx[i] * (1.0f / 128.0f); } - *bytesRead = 3 * sizeof(s8) * vertexCount; } else if ((vertType & 0xFFFFFF) == GE_VTYPE_POS_16BIT) { const s16 *vtx = (const s16*)control_points; for (int i = 0; i < vertexCount * 3; i++) { verts[i] = vtx[i] * (1.0f / 32768.0f); } - *bytesRead = 3 * sizeof(s16) * vertexCount; } else { // Simplify away bones and morph before proceeding u8 *temp_buffer = decoded + 65536 * 24; @@ -275,7 +272,6 @@ bool DrawEngineCommon::TestBoundingBox(const void* control_points, int vertexCou verts[i * 3 + 1] = corners[i].pos.y; verts[i * 3 + 2] = corners[i].pos.z; } - *bytesRead = vertexSize * vertexCount; } Plane planes[6]; diff --git a/GPU/Common/DrawEngineCommon.h b/GPU/Common/DrawEngineCommon.h index 8fc0382a29..7a6ba863fd 100644 --- a/GPU/Common/DrawEngineCommon.h +++ b/GPU/Common/DrawEngineCommon.h @@ -92,7 +92,7 @@ public: virtual void DispatchSubmitImm(GEPrimitiveType prim, TransformedVertex *buffer, int vertexCount, int cullMode, bool continuation); - bool TestBoundingBox(const void* control_points, int vertexCount, u32 vertType, int *bytesRead); + bool TestBoundingBox(const void* control_points, int vertexCount, u32 vertType); void SubmitPrim(const void *verts, const void *inds, GEPrimitiveType prim, int vertexCount, u32 vertTypeID, int cullMode, int *bytesRead); template diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index 7a6b3fea88..35d91df78a 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -2153,13 +2153,17 @@ void GPUCommon::Execute_Spline(u32 op, u32 diff) { void GPUCommon::Execute_BoundingBox(u32 op, u32 diff) { // Just resetting, nothing to check bounds for. - const u32 count = op & 0xFFFFFF; + const u32 count = op & 0xFFFF; if (count == 0) { currentList->bboxResult = false; return; } - if (((count & 7) == 0) && count <= 64) { // Sanity check - const void *control_points = Memory::GetPointer(gstate_c.vertexAddr); + + VertexDecoder *dec = drawEngineCommon_->GetVertexDecoder(gstate.vertType); + int bytesRead = dec->VertexSize() * count; + + if (Memory::IsValidRange(gstate_c.vertexAddr, bytesRead)) { + const void *control_points = Memory::GetPointerUnchecked(gstate_c.vertexAddr); if (!control_points) { ERROR_LOG_REPORT_ONCE(boundingbox, G3D, "Invalid verts in bounding box check"); currentList->bboxResult = true; @@ -2174,8 +2178,17 @@ void GPUCommon::Execute_BoundingBox(u32 op, u32 diff) { } // Test if the bounding box is within the drawing region. - int bytesRead; - currentList->bboxResult = drawEngineCommon_->TestBoundingBox(control_points, count, gstate.vertType, &bytesRead); + // The PSP only seems to vary the result based on a single range of 0x100. + if (count > 0x200) { + // The second to last set of 0x100 is checked (even for odd counts.) + size_t skipSize = (count - 0x200) * dec->VertexSize(); + currentList->bboxResult = drawEngineCommon_->TestBoundingBox((const uint8_t *)control_points + skipSize, 0x100, gstate.vertType); + } else if (count > 0x100) { + int checkSize = count - 0x100; + currentList->bboxResult = drawEngineCommon_->TestBoundingBox(control_points, checkSize, gstate.vertType); + } else { + currentList->bboxResult = drawEngineCommon_->TestBoundingBox(control_points, count, gstate.vertType); + } AdvanceVerts(gstate.vertType, count, bytesRead); } else { ERROR_LOG_REPORT_ONCE(boundingbox, G3D, "Bad bounding box data: %06x", count);