From 264a81913dd866c954e94f0b0f8cd42ca69adda9 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 6 Dec 2022 06:11:38 -0800 Subject: [PATCH 1/4] softgpu: Avoid checking UVs for sprites w/o tex. --- GPU/Software/RasterizerRectangle.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/GPU/Software/RasterizerRectangle.cpp b/GPU/Software/RasterizerRectangle.cpp index d81c0fd403..0263e06433 100644 --- a/GPU/Software/RasterizerRectangle.cpp +++ b/GPU/Software/RasterizerRectangle.cpp @@ -349,16 +349,18 @@ bool RectangleFastPath(const VertexData &v0, const VertexData &v1, BinManager &b int ydiff = v1.screenpos.y - v0.screenpos.y; int udiff = (v1.texturecoords.x - v0.texturecoords.x) * (float)SCREEN_SCALE_FACTOR; int vdiff = (v1.texturecoords.y - v0.texturecoords.y) * (float)SCREEN_SCALE_FACTOR; - bool coord_check = - (xdiff == udiff || xdiff == -udiff) && - (ydiff == vdiff || ydiff == -vdiff); // Currently only works for TL/BR, which is the most common but not required. bool orient_check = xdiff >= 0 && ydiff >= 0; // We already have a fast path for clear in ClearRectangle. - bool state_check = state.throughMode && !state.pixelID.clearMode && !state.samplerID.hasAnyMips && NoClampOrWrap(state, v0.texturecoords.uv()) && NoClampOrWrap(state, v1.texturecoords.uv()); + bool state_check = state.throughMode && !state.pixelID.clearMode && !state.samplerID.hasAnyMips && !state.textureProj; + bool coord_check = true; + if (state.enableTextures) { + state_check = state_check && NoClampOrWrap(state, v0.texturecoords.uv()) && NoClampOrWrap(state, v1.texturecoords.uv()); + coord_check = (xdiff == udiff || xdiff == -udiff) && (ydiff == vdiff || ydiff == -vdiff); + } // This doesn't work well with offset drawing, see #15876. Through never has a subpixel offset. bool subpixel_check = ((v0.screenpos.x | v0.screenpos.y | v1.screenpos.x | v1.screenpos.y) & 0xF) == 0; - if ((coord_check || !state.enableTextures) && orient_check && state_check && subpixel_check) { + if (coord_check && orient_check && state_check && subpixel_check) { binner.AddSprite(v0, v1); return true; } From c291bd78ef2fd290590d2c7ca1f74db99b720cff Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 6 Dec 2022 06:26:02 -0800 Subject: [PATCH 2/4] softgpu: Use a template for 5551 fast path. Just refactoring here, should be the same. --- GPU/Software/RasterizerRectangle.cpp | 88 +++++++++++++++------------- 1 file changed, 47 insertions(+), 41 deletions(-) diff --git a/GPU/Software/RasterizerRectangle.cpp b/GPU/Software/RasterizerRectangle.cpp index 0263e06433..ecbb851645 100644 --- a/GPU/Software/RasterizerRectangle.cpp +++ b/GPU/Software/RasterizerRectangle.cpp @@ -156,6 +156,50 @@ static inline Vec4IntResult SOFTRAST_CALL ModulateRGBA(Vec4IntArg prim_in, Vec4I return ToVec4IntResult(out); } +template +static void DrawSpriteTex5551(const DrawingCoords &pos0, const DrawingCoords &pos1, int s_start, int t_start, int ds, int dt, u32 color0, const RasterizerState &state, Sampler::FetchFunc fetchFunc) { + const u8 *texptr = state.texptr[0]; + uint16_t texbufw = state.texbufw[0]; + + int t = t_start; + const Vec4 c0 = Vec4::FromRGBA(color0); + for (int y = pos0.y; y < pos1.y; y++) { + int s = s_start; + u16 *pixel = fb.Get16Ptr(pos0.x, y, state.pixelID.cached.framebufStride); + for (int x = pos0.x; x < pos1.x; x++) { + Vec4 tex_color = fetchFunc(s, t, texptr, texbufw, 0, state.samplerID); + if (isWhite) { + u32 tex_color32 = Vec4(tex_color).ToRGBA(); + if (tex_color32 & 0xFF000000) { + DrawSinglePixel5551(pixel, tex_color32); + } + } else { + Vec4 prim_color = c0; + prim_color = Vec4(ModulateRGBA(ToVec4IntArg(prim_color), ToVec4IntArg(tex_color), state.samplerID)); + if (prim_color.a() > 0) { + DrawSinglePixel5551(pixel, prim_color.ToRGBA()); + } + } + s += ds; + pixel++; + } + t += dt; + } +} + +static void DrawSpriteNoTex5551(const DrawingCoords &pos0, const DrawingCoords &pos1, u32 color0, const RasterizerState &state) { + if (Vec4::FromRGBA(color0).a() == 0) + return; + + for (int y = pos0.y; y < pos1.y; y++) { + u16 *pixel = fb.Get16Ptr(pos0.x, y, state.pixelID.cached.framebufStride); + for (int x = pos0.x; x < pos1.x; x++) { + DrawSinglePixel5551(pixel, color0); + pixel++; + } + } +} + void DrawSprite(const VertexData &v0, const VertexData &v1, const BinCoords &range, const RasterizerState &state) { const u8 *texptr = state.texptr[0]; @@ -213,38 +257,9 @@ void DrawSprite(const VertexData &v0, const VertexData &v1, const BinCoords &ran if (UseDrawSinglePixel5551(pixelID) && samplerID.TexFunc() == GE_TEXFUNC_MODULATE && samplerID.useTextureAlpha) { if (isWhite) { - int t = t_start; - for (int y = pos0.y; y < pos1.y; y++) { - int s = s_start; - u16 *pixel = fb.Get16Ptr(pos0.x, y, pixelID.cached.framebufStride); - for (int x = pos0.x; x < pos1.x; x++) { - u32 tex_color = Vec4(fetchFunc(s, t, texptr, texbufw, 0, state.samplerID)).ToRGBA(); - if (tex_color & 0xFF000000) { - DrawSinglePixel5551(pixel, tex_color); - } - s += ds; - pixel++; - } - t += dt; - } + DrawSpriteTex5551(pos0, pos1, s_start, t_start, ds, dt, v1.color0, state, fetchFunc); } else { - int t = t_start; - const Vec4 c0 = Vec4::FromRGBA(v1.color0); - for (int y = pos0.y; y < pos1.y; y++) { - int s = s_start; - u16 *pixel = fb.Get16Ptr(pos0.x, y, pixelID.cached.framebufStride); - for (int x = pos0.x; x < pos1.x; x++) { - Vec4 prim_color = c0; - Vec4 tex_color = fetchFunc(s, t, texptr, texbufw, 0, state.samplerID); - prim_color = Vec4(ModulateRGBA(ToVec4IntArg(prim_color), ToVec4IntArg(tex_color), state.samplerID)); - if (prim_color.a() > 0) { - DrawSinglePixel5551(pixel, prim_color.ToRGBA()); - } - s += ds; - pixel++; - } - t += dt; - } + DrawSpriteTex5551(pos0, pos1, s_start, t_start, ds, dt, v1.color0, state, fetchFunc); } } else { float dsf = ds * (1.0f / (float)(1 << state.samplerID.width0Shift)); @@ -287,16 +302,7 @@ void DrawSprite(const VertexData &v0, const VertexData &v1, const BinCoords &ran if (pos0.x < scissorTL.x) pos0.x = scissorTL.x; if (pos0.y < scissorTL.y) pos0.y = scissorTL.y; if (UseDrawSinglePixel5551(pixelID)) { - if (Vec4::FromRGBA(v1.color0).a() == 0) - return; - - for (int y = pos0.y; y < pos1.y; y++) { - u16 *pixel = fb.Get16Ptr(pos0.x, y, pixelID.cached.framebufStride); - for (int x = pos0.x; x < pos1.x; x++) { - DrawSinglePixel5551(pixel, v1.color0); - pixel++; - } - } + DrawSpriteNoTex5551(pos0, pos1, v1.color0, state); } else if (pixelID.earlyZChecks) { const Vec4 prim_color = Vec4::FromRGBA(v1.color0); for (int y = pos0.y; y < pos1.y; y++) { From 60c129c52f9ee9c1924ff2d7e4ab34a7b552e1bd Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 6 Dec 2022 06:31:30 -0800 Subject: [PATCH 3/4] softgpu: Use no-modulate fast path for REPLACE. --- GPU/Software/RasterizerRectangle.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GPU/Software/RasterizerRectangle.cpp b/GPU/Software/RasterizerRectangle.cpp index ecbb851645..c8cdcd0149 100644 --- a/GPU/Software/RasterizerRectangle.cpp +++ b/GPU/Software/RasterizerRectangle.cpp @@ -255,8 +255,8 @@ void DrawSprite(const VertexData &v0, const VertexData &v1, const BinCoords &ran pos0.y = scissorTL.y; } - if (UseDrawSinglePixel5551(pixelID) && samplerID.TexFunc() == GE_TEXFUNC_MODULATE && samplerID.useTextureAlpha) { - if (isWhite) { + if (UseDrawSinglePixel5551(pixelID) && (samplerID.TexFunc() == GE_TEXFUNC_MODULATE || samplerID.TexFunc() == GE_TEXFUNC_REPLACE) && samplerID.useTextureAlpha) { + if (isWhite || samplerID.TexFunc() == GE_TEXFUNC_REPLACE) { DrawSpriteTex5551(pos0, pos1, s_start, t_start, ds, dt, v1.color0, state, fetchFunc); } else { DrawSpriteTex5551(pos0, pos1, s_start, t_start, ds, dt, v1.color0, state, fetchFunc); From 51fa931e46ae53cee903ea1f3fab1ffba9beadca Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 6 Dec 2022 06:37:51 -0800 Subject: [PATCH 4/4] softgpu: Allow no alpha blend in 5551 fast path. --- GPU/Software/RasterizerRectangle.cpp | 45 ++++++++++++++++++---------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/GPU/Software/RasterizerRectangle.cpp b/GPU/Software/RasterizerRectangle.cpp index c8cdcd0149..d42f685e2d 100644 --- a/GPU/Software/RasterizerRectangle.cpp +++ b/GPU/Software/RasterizerRectangle.cpp @@ -72,10 +72,11 @@ static uint32_t StandardAlphaBlend(uint32_t source, uint32_t dst) { } // Through mode, with the specific Darkstalker settings. +template inline void DrawSinglePixel5551(u16 *pixel, const u32 color_in) { u32 new_color; // Because of this check, we only support src.a / 1-src.a blending. - if ((color_in >> 24) == 255) { + if ((color_in >> 24) == 255 || !alphaBlend) { new_color = color_in & 0xFFFFFF; } else { const u32 old_color = RGBA5551ToRGBA8888(*pixel); @@ -113,13 +114,15 @@ bool UseDrawSinglePixel5551(const PixelFuncID &pixelID) { return false; if (!AlphaTestIsNeedless(pixelID) || pixelID.DepthTestFunc() != GE_COMP_ALWAYS) return false; - if (pixelID.FBFormat() != GE_FORMAT_5551 || !pixelID.alphaBlend) + if (pixelID.FBFormat() != GE_FORMAT_5551) return false; // We skip blending when alpha = FF, so we can't allow other blend modes. - if (pixelID.AlphaBlendEq() != GE_BLENDMODE_MUL_AND_ADD || pixelID.AlphaBlendSrc() != PixelBlendFactor::SRCALPHA) - return false; - if (pixelID.AlphaBlendDst() != PixelBlendFactor::INVSRCALPHA) - return false; + if (pixelID.alphaBlend) { + if (pixelID.AlphaBlendEq() != GE_BLENDMODE_MUL_AND_ADD || pixelID.AlphaBlendSrc() != PixelBlendFactor::SRCALPHA) + return false; + if (pixelID.AlphaBlendDst() != PixelBlendFactor::INVSRCALPHA) + return false; + } if (pixelID.dithering || pixelID.applyLogicOp || pixelID.applyColorWriteMask) return false; @@ -156,7 +159,7 @@ static inline Vec4IntResult SOFTRAST_CALL ModulateRGBA(Vec4IntArg prim_in, Vec4I return ToVec4IntResult(out); } -template +template static void DrawSpriteTex5551(const DrawingCoords &pos0, const DrawingCoords &pos1, int s_start, int t_start, int ds, int dt, u32 color0, const RasterizerState &state, Sampler::FetchFunc fetchFunc) { const u8 *texptr = state.texptr[0]; uint16_t texbufw = state.texbufw[0]; @@ -170,14 +173,14 @@ static void DrawSpriteTex5551(const DrawingCoords &pos0, const DrawingCoords &po Vec4 tex_color = fetchFunc(s, t, texptr, texbufw, 0, state.samplerID); if (isWhite) { u32 tex_color32 = Vec4(tex_color).ToRGBA(); - if (tex_color32 & 0xFF000000) { - DrawSinglePixel5551(pixel, tex_color32); + if (!alphaBlend || tex_color32 & 0xFF000000) { + DrawSinglePixel5551(pixel, tex_color32); } } else { Vec4 prim_color = c0; prim_color = Vec4(ModulateRGBA(ToVec4IntArg(prim_color), ToVec4IntArg(tex_color), state.samplerID)); - if (prim_color.a() > 0) { - DrawSinglePixel5551(pixel, prim_color.ToRGBA()); + if (!alphaBlend || prim_color.a() > 0) { + DrawSinglePixel5551(pixel, prim_color.ToRGBA()); } } s += ds; @@ -187,14 +190,15 @@ static void DrawSpriteTex5551(const DrawingCoords &pos0, const DrawingCoords &po } } +template static void DrawSpriteNoTex5551(const DrawingCoords &pos0, const DrawingCoords &pos1, u32 color0, const RasterizerState &state) { - if (Vec4::FromRGBA(color0).a() == 0) + if (alphaBlend && Vec4::FromRGBA(color0).a() == 0) return; for (int y = pos0.y; y < pos1.y; y++) { u16 *pixel = fb.Get16Ptr(pos0.x, y, state.pixelID.cached.framebufStride); for (int x = pos0.x; x < pos1.x; x++) { - DrawSinglePixel5551(pixel, color0); + DrawSinglePixel5551(pixel, color0); pixel++; } } @@ -257,9 +261,15 @@ void DrawSprite(const VertexData &v0, const VertexData &v1, const BinCoords &ran if (UseDrawSinglePixel5551(pixelID) && (samplerID.TexFunc() == GE_TEXFUNC_MODULATE || samplerID.TexFunc() == GE_TEXFUNC_REPLACE) && samplerID.useTextureAlpha) { if (isWhite || samplerID.TexFunc() == GE_TEXFUNC_REPLACE) { - DrawSpriteTex5551(pos0, pos1, s_start, t_start, ds, dt, v1.color0, state, fetchFunc); + if (pixelID.alphaBlend) + DrawSpriteTex5551(pos0, pos1, s_start, t_start, ds, dt, v1.color0, state, fetchFunc); + else + DrawSpriteTex5551(pos0, pos1, s_start, t_start, ds, dt, v1.color0, state, fetchFunc); } else { - DrawSpriteTex5551(pos0, pos1, s_start, t_start, ds, dt, v1.color0, state, fetchFunc); + if (pixelID.alphaBlend) + DrawSpriteTex5551(pos0, pos1, s_start, t_start, ds, dt, v1.color0, state, fetchFunc); + else + DrawSpriteTex5551(pos0, pos1, s_start, t_start, ds, dt, v1.color0, state, fetchFunc); } } else { float dsf = ds * (1.0f / (float)(1 << state.samplerID.width0Shift)); @@ -302,7 +312,10 @@ void DrawSprite(const VertexData &v0, const VertexData &v1, const BinCoords &ran if (pos0.x < scissorTL.x) pos0.x = scissorTL.x; if (pos0.y < scissorTL.y) pos0.y = scissorTL.y; if (UseDrawSinglePixel5551(pixelID)) { - DrawSpriteNoTex5551(pos0, pos1, v1.color0, state); + if (pixelID.alphaBlend) + DrawSpriteNoTex5551(pos0, pos1, v1.color0, state); + else + DrawSpriteNoTex5551(pos0, pos1, v1.color0, state); } else if (pixelID.earlyZChecks) { const Vec4 prim_color = Vec4::FromRGBA(v1.color0); for (int y = pos0.y; y < pos1.y; y++) {