From 6004d4a4596106056d1fbccfe00f66fa2348a2cb Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 10 Sep 2022 13:28:35 -0700 Subject: [PATCH 1/5] softgpu: Refactor duplicate rectangle compat check. This just moves the logic to a single place for changes. --- GPU/Software/RasterizerRectangle.cpp | 52 ++++++++++++---------------- GPU/Software/SoftGpu.cpp | 2 +- 2 files changed, 23 insertions(+), 31 deletions(-) diff --git a/GPU/Software/RasterizerRectangle.cpp b/GPU/Software/RasterizerRectangle.cpp index f25be97f64bd..7408b1558b40 100644 --- a/GPU/Software/RasterizerRectangle.cpp +++ b/GPU/Software/RasterizerRectangle.cpp @@ -321,26 +321,32 @@ bool RectangleFastPath(const VertexData &v0, const VertexData &v1, BinManager &b return false; } +static bool AreCoordsRectangleCompatible(const RasterizerState &state, const VertexData &data0, const VertexData &data1) { + if (!(data1.color0 == data0.color0)) + return false; + if (!(data1.screenpos.z == data0.screenpos.z)) { + // Sometimes, we don't actually care about z. + if (state.pixelID.depthWrite || state.pixelID.DepthTestFunc() != GE_COMP_ALWAYS) + return false; + } + if (!state.throughMode) { + if (!state.throughMode && !(data1.color1 == data0.color1)) + return false; + // Do we have to think about perspective correction or slope mip level? + if (state.enableTextures && data1.clippos.w != data0.clippos.w) + return false; + if (state.pixelID.applyFog && data1.fogdepth != data0.fogdepth) + return false; + } + return true; +} + bool DetectRectangleFromStrip(const RasterizerState &state, const VertexData data[4], int *tlIndex, int *brIndex) { // Color and Z must be flat. Also find the TL and BR meanwhile. int tl = 0, br = 0; for (int i = 1; i < 4; ++i) { - if (!(data[i].color0 == data[0].color0)) + if (!AreCoordsRectangleCompatible(state, data[i], data[0])) return false; - if (!(data[i].screenpos.z == data[0].screenpos.z)) { - // Sometimes, we don't actually care about z. - if (state.pixelID.depthWrite || state.pixelID.DepthTestFunc() != GE_COMP_ALWAYS) - return false; - } - if (!state.throughMode) { - if (!state.throughMode && !(data[i].color1 == data[0].color1)) - return false; - // Do we have to think about perspective correction or slope mip level? - if (state.enableTextures && data[i].clippos.w != data[0].clippos.w) - return false; - if (state.pixelID.applyFog && data[i].fogdepth != data[0].fogdepth) - return false; - } if (data[i].screenpos.x <= data[tl].screenpos.x && data[i].screenpos.y <= data[tl].screenpos.y) tl = i; @@ -394,22 +400,8 @@ bool DetectRectangleFromStrip(const RasterizerState &state, const VertexData dat bool DetectRectangleFromFan(const RasterizerState &state, const VertexData *data, int c, int *tlIndex, int *brIndex) { // Color and Z must be flat. for (int i = 1; i < c; ++i) { - if (!(data[i].color0 == data[0].color0)) + if (!AreCoordsRectangleCompatible(state, data[i], data[0])) return false; - if (!(data[i].screenpos.z == data[0].screenpos.z)) { - // Sometimes, we don't actually care about z. - if (state.pixelID.depthWrite || state.pixelID.DepthTestFunc() != GE_COMP_ALWAYS) - return false; - } - if (!state.throughMode) { - if (!state.throughMode && !(data[i].color1 == data[0].color1)) - return false; - // Do we have to think about perspective correction or slope mip level? - if (state.enableTextures && data[i].clippos.w != data[0].clippos.w) - return false; - if (state.pixelID.applyFog && data[i].fogdepth != data[0].fogdepth) - return false; - } } // Check for the common case: a single TL-TR-BR-BL. diff --git a/GPU/Software/SoftGpu.cpp b/GPU/Software/SoftGpu.cpp index a6fc160af38e..18cdb0b31463 100644 --- a/GPU/Software/SoftGpu.cpp +++ b/GPU/Software/SoftGpu.cpp @@ -838,7 +838,7 @@ void SoftGPU::Execute_Prim(u32 op, u32 diff) { return; } - const void *verts = Memory::GetPointer(gstate_c.vertexAddr); + const void *verts = Memory::GetPointerUnchecked(gstate_c.vertexAddr); const void *indices = NULL; if ((gstate.vertType & GE_VTYPE_IDX_MASK) != GE_VTYPE_IDX_NONE) { if (!Memory::IsValidAddress(gstate_c.indexAddr)) { From e7d49cd7d0087fb9a423f3e16491f6f973c34f32 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 10 Sep 2022 13:29:40 -0700 Subject: [PATCH 2/5] softgpu: Allow almost flat rectangles to go fast. Improves transform rectangles used in Chains of Olympus, for example on the title screen. --- GPU/Software/RasterizerRectangle.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/GPU/Software/RasterizerRectangle.cpp b/GPU/Software/RasterizerRectangle.cpp index 7408b1558b40..79162dc607ad 100644 --- a/GPU/Software/RasterizerRectangle.cpp +++ b/GPU/Software/RasterizerRectangle.cpp @@ -333,10 +333,18 @@ static bool AreCoordsRectangleCompatible(const RasterizerState &state, const Ver if (!state.throughMode && !(data1.color1 == data0.color1)) return false; // Do we have to think about perspective correction or slope mip level? - if (state.enableTextures && data1.clippos.w != data0.clippos.w) - return false; - if (state.pixelID.applyFog && data1.fogdepth != data0.fogdepth) - return false; + if (state.enableTextures && data1.clippos.w != data0.clippos.w) { + // If the w is off by less than a factor of 1/512, it should be safe to treat as a rectangle. + static constexpr float halftexel = 0.5f / 512.0f; + if (data1.clippos.w - halftexel > data0.clippos.w || data1.clippos.w + halftexel < data0.clippos.w) + return false; + } + if (state.pixelID.applyFog && data1.fogdepth != data0.fogdepth) { + // Similar to w, this only matters if they're farther apart than 1/255. + static constexpr float foghalfstep = 0.5f / 255.0f; + if (data1.fogdepth - foghalfstep > data0.fogdepth || data1.fogdepth + foghalfstep < data0.fogdepth) + return false; + } } return true; } From 2505ae28589c80d27ca3d7d3e04b9b5c4ce2ce7c Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 10 Sep 2022 13:36:01 -0700 Subject: [PATCH 3/5] GE Debugger: Fix logging of texture size. --- GPU/GeDisasm.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/GeDisasm.cpp b/GPU/GeDisasm.cpp index b30218b44a08..a645b5bc2bec 100644 --- a/GPU/GeDisasm.cpp +++ b/GPU/GeDisasm.cpp @@ -605,7 +605,7 @@ void GeDisassembleOp(u32 pc, u32 op, u32 prev, char *buffer, int bufsize) { { int w = 1 << (data & 0xf); int h = 1 << ((data>>8) & 0xf); - if ((data & ~0x0F0F) && w <= 512 && h <= 512) + if ((data & ~0x0F0F) == 0 && w <= 512 && h <= 512) snprintf(buffer, bufsize, "Texture size %d: %dx%d", cmd - GE_CMD_TEXSIZE0, w, h); else snprintf(buffer, bufsize, "Texture size %d: %dx%d (extra %06x)", cmd - GE_CMD_TEXSIZE0, w, h, data); From 13ca08b2357e8dec7ffa79d04116dd842e623d1c Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 10 Sep 2022 14:56:13 -0700 Subject: [PATCH 4/5] softgpu: Avoid over-aggressive rect conversion. The TL and BR have to match between UVs and pos, not enough for UV to be in order. This was causing an artifact on Chains of Olympus' title. --- GPU/Software/RasterizerRectangle.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/GPU/Software/RasterizerRectangle.cpp b/GPU/Software/RasterizerRectangle.cpp index 79162dc607ad..f3ba20840a4c 100644 --- a/GPU/Software/RasterizerRectangle.cpp +++ b/GPU/Software/RasterizerRectangle.cpp @@ -435,7 +435,9 @@ bool DetectRectangleFromFan(const RasterizerState &state, const VertexData *data if (textl.x == texbl.x && textr.x == texbr.x && textl.y == textr.y && texbl.y == texbr.y) { // Okay, the texture is also good, but let's avoid rotation issues. - return textl.y < texbr.y && textl.x < texbr.x; + const auto &postl = data[*tlIndex].screenpos; + const auto &posbr = data[*brIndex].screenpos; + return textl.y < texbr.y && postl.y < posbr.y && textl.x < texbr.x && postl.x < posbr.x; } } } From f5f5c9ea8775d5e73a163098e9df17cec2df6556 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 10 Sep 2022 14:58:27 -0700 Subject: [PATCH 5/5] softgpu: Avoid calling unordered coords tl/br. These are just corners, we don't know if they're top or not at this point. --- GPU/Software/RasterizerRectangle.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/GPU/Software/RasterizerRectangle.cpp b/GPU/Software/RasterizerRectangle.cpp index f3ba20840a4c..f30ae1c128ef 100644 --- a/GPU/Software/RasterizerRectangle.cpp +++ b/GPU/Software/RasterizerRectangle.cpp @@ -414,14 +414,14 @@ bool DetectRectangleFromFan(const RasterizerState &state, const VertexData *data // Check for the common case: a single TL-TR-BR-BL. if (c == 4) { - const auto &tl = data[0].screenpos, &tr = data[1].screenpos; - const auto &bl = data[3].screenpos, &br = data[2].screenpos; - if (tl.x == bl.x && tr.x == br.x && tl.y == tr.y && bl.y == br.y) { + const auto &pos0 = data[0].screenpos, &pos1 = data[1].screenpos; + const auto &pos2 = data[2].screenpos, &pos3 = data[3].screenpos; + if (pos0.x == pos3.x && pos1.x == pos2.x && pos0.y == pos1.y && pos3.y == pos2.y) { // Looking like yes. Set TL/BR based on y order first... - *tlIndex = tl.y > bl.y ? 2 : 0; - *brIndex = tl.y > bl.y ? 0 : 2; + *tlIndex = pos0.y > pos3.y ? 2 : 0; + *brIndex = pos0.y > pos3.y ? 0 : 2; // And if it's horizontally flipped, trade to the actual TL/BR. - if (tl.x > tr.x) { + if (pos0.x > pos1.x) { *tlIndex ^= 1; *brIndex ^= 1; }