From c7f6724f7efc0b8477245b3199bbb1500d93000f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 23 Oct 2019 00:18:30 +0200 Subject: [PATCH] Detect sprite drawing (1:1 texture mapping), run a simpler function without the triangle state tracking. This will allow further simplification and specialization. --- GPU/GPU.vcxproj | 1 + GPU/Software/Clipper.cpp | 33 +++++++++++++++++++++++ GPU/Software/Rasterizer.cpp | 48 ++++++++++++++++++++++++++++++++++ GPU/Software/Rasterizer.h | 1 + GPU/Software/TransformUnit.cpp | 21 +++++++++++++++ 5 files changed, 104 insertions(+) diff --git a/GPU/GPU.vcxproj b/GPU/GPU.vcxproj index 53903c75c1..44da128934 100644 --- a/GPU/GPU.vcxproj +++ b/GPU/GPU.vcxproj @@ -197,6 +197,7 @@ MultiThreadedDebug Common/DbgNew.h ProgramDatabase + false true diff --git a/GPU/Software/Clipper.cpp b/GPU/Software/Clipper.cpp index 746896c431..b3fe40949e 100644 --- a/GPU/Software/Clipper.cpp +++ b/GPU/Software/Clipper.cpp @@ -184,6 +184,39 @@ void ProcessRect(const VertexData& v0, const VertexData& v1) ProcessTriangle(*topleft, *bottomleft, *bottomright, buf[3]); } else { // through mode handling + + // Check for simple case: No depth, alpha != 0 testing only, no blend, texture mapping 1:1 etc. + // Also check for scissor rectangle etc. + // That is, state commonly used in PSX games and ports like Darkstalker. + // In that case we can call DrawPSXSprite. + int xdiff = v1.screenpos.x - v0.screenpos.x; + int ydiff = v1.screenpos.y - v0.screenpos.y; + int udiff = (v1.texturecoords.x - v0.texturecoords.x) * 16.0f; + int vdiff = (v1.texturecoords.y - v0.texturecoords.y) * 16.0f; + bool coord_check = + (xdiff == udiff /* || xdiff == -udiff*/) && + (ydiff == vdiff /* || ydiff == -vdiff*/); + // TODO: The U/V mirror support is off by one somehow. Predecrement? + + /* + bool state_check = + !gstate.isModeClear() && + !gstate.isFogEnabled() && + gstate.isTextureMapEnabled() && + !gstate.isDepthTestEnabled() && + !gstate.isStencilTestEnabled(); + bool alpha_check = + gstate.getAlphaTestFunction() == GEComparison::GE_COMP_GREATER && + gstate.getAlphaTestMask() == 0xFF && + gstate.getAlphaTestRef() == 0; + */ + bool state_check = !gstate.isModeClear(); + bool alpha_check = true; + if ((coord_check || !gstate.isTextureMapEnabled()) && state_check && alpha_check) { + Rasterizer::DrawPSXSprite(v0, v1); + return; + } + VertexData buf[4]; buf[0].screenpos = ScreenCoords(v0.screenpos.x, v0.screenpos.y, v1.screenpos.z); buf[0].texturecoords = v0.texturecoords; diff --git a/GPU/Software/Rasterizer.cpp b/GPU/Software/Rasterizer.cpp index 5db77b9407..88841eeced 100644 --- a/GPU/Software/Rasterizer.cpp +++ b/GPU/Software/Rasterizer.cpp @@ -1287,6 +1287,54 @@ void DrawTriangleSlice( } } +void DrawPSXSprite(const VertexData& v0, const VertexData& v1) { + u8 *texptr = nullptr; + + GETextureFormat texfmt = gstate.getTextureFormat(); + u32 texaddr = gstate.getTextureAddress(0); + int texbufw = GetTextureBufw(0, texaddr, texfmt); + if (Memory::IsValidAddress(texaddr)) + texptr = Memory::GetPointerUnchecked(texaddr); + + ScreenCoords pprime(v0.screenpos.x, v0.screenpos.y, 0); + Sampler::Funcs sampler = Sampler::GetFuncs(); + + DrawingCoords pos0 = TransformUnit::ScreenToDrawing(v0.screenpos); + DrawingCoords pos1 = TransformUnit::ScreenToDrawing(v1.screenpos); + + int z = pos0.z; + float fog = 1.0f; + + if (gstate.isTextureMapEnabled()) { + // 1:1 (but with mirror support) texture mapping! + int s = v0.texturecoords.x; + int t = v0.texturecoords.y; + int ds = v1.texturecoords.x > v0.texturecoords.x ? 1 : -1; + int dt = v1.texturecoords.y > v0.texturecoords.y ? 1 : -1; + for (int y = pos0.y; y < pos1.y; y++) { + s = v0.texturecoords.x; + for (int x = pos0.x; x < pos1.x; x++) { + Vec4 prim_color = v0.color0; + Vec4 tex_color = Vec4::FromRGBA(sampler.nearest(s, t, texptr, texbufw, 0)); + prim_color = GetTextureFunctionOutput(prim_color, tex_color); + DrawingCoords pos(x, y, z); + DrawSinglePixel(pos, (u16)z, fog, prim_color); + s += ds; + } + t += dt; + } + } + else { + for (int y = pos0.y; y < pos1.y; y++) { + for (int x = pos0.x; x < pos1.x; x++) { + Vec4 prim_color = v0.color0; + DrawingCoords pos(x, y, z); + DrawSinglePixel(pos, (u16)z, fog, prim_color); + } + } + } +} + // Draws triangle, vertices specified in counter-clockwise direction void DrawTriangle(const VertexData& v0, const VertexData& v1, const VertexData& v2) { diff --git a/GPU/Software/Rasterizer.h b/GPU/Software/Rasterizer.h index 53d44e8af0..076a0421a5 100644 --- a/GPU/Software/Rasterizer.h +++ b/GPU/Software/Rasterizer.h @@ -27,6 +27,7 @@ namespace Rasterizer { void DrawTriangle(const VertexData& v0, const VertexData& v1, const VertexData& v2); void DrawPoint(const VertexData &v0); void DrawLine(const VertexData &v0, const VertexData &v1); +void DrawPSXSprite(const VertexData &v0, const VertexData &v1); void ClearRectangle(const VertexData &v0, const VertexData &v1); bool GetCurrentStencilbuffer(GPUDebugBuffer &buffer); diff --git a/GPU/Software/TransformUnit.cpp b/GPU/Software/TransformUnit.cpp index 2848ce600f..82a8497684 100644 --- a/GPU/Software/TransformUnit.cpp +++ b/GPU/Software/TransformUnit.cpp @@ -470,6 +470,27 @@ void TransformUnit::SubmitPrimitive(void* vertices, void* indices, GEPrimitiveTy data[2].color0 == data[3].color0) { // It's a rectangle! Clipper::ProcessRect(data[0], data[3]); + break; + } + // There's the other vertex order too... + if (data[0].screenpos.x == data[2].screenpos.x && + data[0].screenpos.y == data[1].screenpos.y && + data[1].screenpos.x == data[3].screenpos.x && + data[2].screenpos.y == data[3].screenpos.y && + data[2].screenpos.y > data[0].screenpos.y && // Avoid rotation handling + data[1].screenpos.x > data[0].screenpos.x && + data[0].texturecoords.x == data[2].texturecoords.x && + data[0].texturecoords.y == data[1].texturecoords.y && + data[1].texturecoords.x == data[3].texturecoords.x && + data[2].texturecoords.y == data[3].texturecoords.y && + data[2].texturecoords.y > data[0].texturecoords.y && + data[1].texturecoords.x > data[0].texturecoords.x && + data[0].color0 == data[1].color0 && + data[1].color0 == data[2].color0 && + data[2].color0 == data[3].color0) { + // It's a rectangle! + Clipper::ProcessRect(data[0], data[3]); + break; } }