From d314efbf008c0e1a94330d05c326add500a8467e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 24 Oct 2019 23:52:55 +0200 Subject: [PATCH 1/2] More specialization work. --- GPU/Software/Clipper.cpp | 2 +- GPU/Software/Rasterizer.cpp | 100 +++++++++++++++++++++++++++--------- GPU/Software/Rasterizer.h | 2 +- 3 files changed, 77 insertions(+), 27 deletions(-) diff --git a/GPU/Software/Clipper.cpp b/GPU/Software/Clipper.cpp index be9acb8c19..548d9e3dfd 100644 --- a/GPU/Software/Clipper.cpp +++ b/GPU/Software/Clipper.cpp @@ -208,7 +208,7 @@ void ProcessRect(const VertexData& v0, const VertexData& v1) bool state_check = !gstate.isModeClear(); bool alpha_check = true; if ((coord_check || !gstate.isTextureMapEnabled()) && state_check && alpha_check) { - Rasterizer::DrawPSXSprite(v0, v1); + Rasterizer::DrawSprite(v0, v1); return; } diff --git a/GPU/Software/Rasterizer.cpp b/GPU/Software/Rasterizer.cpp index cd90f89fac..72f4958c61 100644 --- a/GPU/Software/Rasterizer.cpp +++ b/GPU/Software/Rasterizer.cpp @@ -1287,19 +1287,51 @@ void DrawTriangleSlice( } } -// Slow but can handle all input. -void SafeScanline(int s, int ds, int t, int x1, int x2, int y, int z, const u8 *texptr, int texbufw, Sampler::Funcs &sampler, Vec4 v0_color) { - for (int x = x1; x < x2; x++) { - Vec4 prim_color = v0_color; - 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, 1.0f, prim_color); - s += ds; + +// Through mode, with the specific Darkstalker settings. +inline void DrawSinglePixelFast(const DrawingCoords &p, const Vec4 &color_in) { + Vec4 prim_color = color_in.Clamp(0, 255); + if (gstate.isAlphaTestEnabled()) + if (!AlphaTestPassed(prim_color.a())) + return; + + const u32 old_color = GetPixelColor(p.x, p.y); + u32 new_color; + + u8 stencil = GetPixelStencil(p.x, p.y); + + // Dithering happens before the logic op and regardless of framebuffer format or clear mode. + // We do it while alpha blending because it happens before clamping. + if (gstate.isAlphaBlendEnabled()) { + const Vec4 dst = Vec4::FromRGBA(old_color); + Vec3 blended = AlphaBlendingResult(prim_color, dst); + if (gstate.isDitherEnabled()) { + blended += Vec3::AssignToAll(gstate.getDitherValue(p.x, p.y)); + } + + // ToRGB() always automatically clamps. + new_color = blended.ToRGB(); + new_color |= stencil << 24; + } else { + if (gstate.isDitherEnabled()) { + // We'll discard alpha anyway. + prim_color += Vec4::AssignToAll(gstate.getDitherValue(p.x, p.y)); + } + +#if defined(_M_SSE) + new_color = Vec3(prim_color.ivec).ToRGB(); + new_color |= stencil << 24; +#else + new_color = Vec4(prim_color.r(), prim_color.g(), prim_color.b(), stencil).ToRGBA(); +#endif } + + new_color = (new_color & ~gstate.getColorMask()) | (old_color & gstate.getColorMask()); + SetPixelColor(p.x, p.y, new_color); } -void DrawPSXSprite(const VertexData& v0, const VertexData& v1) { + +void DrawSprite(const VertexData& v0, const VertexData& v1) { const u8 *texptr = nullptr; GETextureFormat texfmt = gstate.getTextureFormat(); @@ -1309,7 +1341,7 @@ void DrawPSXSprite(const VertexData& v0, const VertexData& v1) { texptr = Memory::GetPointerUnchecked(texaddr); ScreenCoords pprime(v0.screenpos.x, v0.screenpos.y, 0); - Sampler::Funcs sampler = Sampler::GetFuncs(); + Sampler::NearestFunc nearestFunc = Sampler::GetNearestFunc(); // Looks at gstate. DrawingCoords pos0 = TransformUnit::ScreenToDrawing(v0.screenpos); DrawingCoords pos1 = TransformUnit::ScreenToDrawing(v1.screenpos); @@ -1347,21 +1379,39 @@ void DrawPSXSprite(const VertexData& v0, const VertexData& v1) { pos0.y = scissorTL.y; } - int t = t_start; - for (int y = pos0.y; y < pos1.y; y++) { - int s = s_start; - SafeScanline(s, ds, t, pos0.x, pos1.x, y, z, texptr, texbufw, sampler, v0.color0); - /* - 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; + if (!gstate.isStencilTestEnabled() && + !gstate.isDepthTestEnabled() && + !gstate.isLogicOpEnabled() && + !gstate.isColorTestEnabled()) { + int t = t_start; + for (int y = pos0.y; y < pos1.y; y++) { + int s = s_start; + // Not really that fast but faster than triangle. + for (int x = pos0.x; x < pos1.x; x++) { + Vec4 prim_color = v0.color0; + Vec4 tex_color = Vec4::FromRGBA(nearestFunc(s, t, texptr, texbufw, 0)); + prim_color = GetTextureFunctionOutput(prim_color, tex_color); + DrawingCoords pos(x, y, z); + DrawSinglePixelFast(pos, prim_color); + s += ds; + } + t += dt; + } + } else { + int t = t_start; + for (int y = pos0.y; y < pos1.y; y++) { + int s = s_start; + // Not really that fast but faster than triangle. + for (int x = pos0.x; x < pos1.x; x++) { + Vec4 prim_color = v0.color0; + Vec4 tex_color = Vec4::FromRGBA(nearestFunc(s, t, texptr, texbufw, 0)); + prim_color = GetTextureFunctionOutput(prim_color, tex_color); + DrawingCoords pos(x, y, z); + DrawSinglePixel(pos, (u16)z, 1.0f, prim_color); + s += ds; + } + t += dt; } - */ - t += dt; } } else { if (pos1.x > scissorBR.x) pos1.x = scissorBR.x; diff --git a/GPU/Software/Rasterizer.h b/GPU/Software/Rasterizer.h index 076a0421a5..df3075e3a0 100644 --- a/GPU/Software/Rasterizer.h +++ b/GPU/Software/Rasterizer.h @@ -27,7 +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 DrawSprite(const VertexData &v0, const VertexData &v1); void ClearRectangle(const VertexData &v0, const VertexData &v1); bool GetCurrentStencilbuffer(GPUDebugBuffer &buffer); From 7087f1b55e37cae62f2556b480f5429e1476d9d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 25 Oct 2019 00:14:58 +0200 Subject: [PATCH 2/2] Further specialization. --- GPU/Software/Rasterizer.cpp | 83 ++++++++++++++++++++++--------------- 1 file changed, 50 insertions(+), 33 deletions(-) diff --git a/GPU/Software/Rasterizer.cpp b/GPU/Software/Rasterizer.cpp index 72f4958c61..c2d9b84a14 100644 --- a/GPU/Software/Rasterizer.cpp +++ b/GPU/Software/Rasterizer.cpp @@ -1289,47 +1289,56 @@ void DrawTriangleSlice( // Through mode, with the specific Darkstalker settings. -inline void DrawSinglePixelFast(const DrawingCoords &p, const Vec4 &color_in) { - Vec4 prim_color = color_in.Clamp(0, 255); - if (gstate.isAlphaTestEnabled()) - if (!AlphaTestPassed(prim_color.a())) - return; +inline void DrawSinglePixel5551(const DrawingCoords &p, const Vec4 &color_in) { + Vec4 prim_color = color_in; + if (prim_color.a() == 0) + return; const u32 old_color = GetPixelColor(p.x, p.y); u32 new_color; u8 stencil = GetPixelStencil(p.x, p.y); - // Dithering happens before the logic op and regardless of framebuffer format or clear mode. - // We do it while alpha blending because it happens before clamping. - if (gstate.isAlphaBlendEnabled()) { - const Vec4 dst = Vec4::FromRGBA(old_color); - Vec3 blended = AlphaBlendingResult(prim_color, dst); - if (gstate.isDitherEnabled()) { - blended += Vec3::AssignToAll(gstate.getDitherValue(p.x, p.y)); - } - - // ToRGB() always automatically clamps. - new_color = blended.ToRGB(); - new_color |= stencil << 24; - } else { - if (gstate.isDitherEnabled()) { - // We'll discard alpha anyway. - prim_color += Vec4::AssignToAll(gstate.getDitherValue(p.x, p.y)); - } - -#if defined(_M_SSE) - new_color = Vec3(prim_color.ivec).ToRGB(); - new_color |= stencil << 24; -#else - new_color = Vec4(prim_color.r(), prim_color.g(), prim_color.b(), stencil).ToRGBA(); -#endif - } + const Vec4 dst = Vec4::FromRGBA(old_color); + Vec3 blended = AlphaBlendingResult(prim_color, dst); + // ToRGB() always automatically clamps. + new_color = blended.ToRGB(); + new_color |= stencil << 24; new_color = (new_color & ~gstate.getColorMask()) | (old_color & gstate.getColorMask()); SetPixelColor(p.x, p.y, new_color); } +static inline Vec4 ModulateRGBA(const Vec4& prim_color, const Vec4& texcolor) { + Vec3 out_rgb; + int out_a; + +#if defined(_M_SSE) + // We can be accurate up to 24 bit integers, should be enough. + const __m128 p = _mm_cvtepi32_ps(prim_color.ivec); + const __m128 t = _mm_cvtepi32_ps(texcolor.ivec); + const __m128 b = _mm_mul_ps(p, t); + if (gstate.isColorDoublingEnabled()) { + // We double right here, only for modulate. Other tex funcs do not color double. + const __m128 doubleColor = _mm_setr_ps(2.0f / 255.0f, 2.0f / 255.0f, 2.0f / 255.0f, 1.0f / 255.0f); + out_rgb.ivec = _mm_cvtps_epi32(_mm_mul_ps(b, doubleColor)); + } else { + out_rgb.ivec = _mm_cvtps_epi32(_mm_mul_ps(b, _mm_set_ps1(1.0f / 255.0f))); + } + return Vec4(out_rgb.ivec); +#else + if (gstate.isColorDoublingEnabled()) { + out_rgb = (prim_color.rgb() * texcolor.rgb() * 2) / 255; + } else { + out_rgb = prim_color.rgb() * texcolor.rgb() / 255; + } + out_a = (rgba) ? (prim_color.a() * texcolor.a() / 255) : prim_color.a(); +#endif + + return Vec4(out_rgb.r(), out_rgb.g(), out_rgb.b(), out_a); + +} + void DrawSprite(const VertexData& v0, const VertexData& v1) { const u8 *texptr = nullptr; @@ -1382,7 +1391,15 @@ void DrawSprite(const VertexData& v0, const VertexData& v1) { if (!gstate.isStencilTestEnabled() && !gstate.isDepthTestEnabled() && !gstate.isLogicOpEnabled() && - !gstate.isColorTestEnabled()) { + !gstate.isColorTestEnabled() && + !gstate.isDitherEnabled() && + gstate.isAlphaTestEnabled() && + gstate.getAlphaTestRef() == 0 && + gstate.getAlphaTestMask() == 0xFF && + gstate.isAlphaBlendEnabled() && + gstate.isTextureAlphaUsed() && + gstate.getTextureFunction() == GE_TEXFUNC_MODULATE && + gstate.FrameBufFormat() == GE_FORMAT_5551) { int t = t_start; for (int y = pos0.y; y < pos1.y; y++) { int s = s_start; @@ -1390,9 +1407,9 @@ void DrawSprite(const VertexData& v0, const VertexData& v1) { for (int x = pos0.x; x < pos1.x; x++) { Vec4 prim_color = v0.color0; Vec4 tex_color = Vec4::FromRGBA(nearestFunc(s, t, texptr, texbufw, 0)); - prim_color = GetTextureFunctionOutput(prim_color, tex_color); + prim_color = ModulateRGBA(prim_color, tex_color); DrawingCoords pos(x, y, z); - DrawSinglePixelFast(pos, prim_color); + DrawSinglePixel5551(pos, prim_color); s += ds; } t += dt;