From 839bc1fc8753e5df9bcca35d1411b735e79568da Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 31 Mar 2023 23:51:04 -0700 Subject: [PATCH 1/3] headless: Fix screenshot failure. Needs to output to the collected output for it to actually show as a failure. --- headless/HeadlessHost.cpp | 12 +++++++++--- headless/HeadlessHost.h | 2 ++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/headless/HeadlessHost.cpp b/headless/HeadlessHost.cpp index 7a88ca5bb3..b68f4ce094 100644 --- a/headless/HeadlessHost.cpp +++ b/headless/HeadlessHost.cpp @@ -42,14 +42,20 @@ void HeadlessHost::SendDebugScreenshot(const u8 *pixbuf, u32 w, u32 h) { ScreenshotComparer comparer(pixels, FRAME_STRIDE, FRAME_WIDTH, FRAME_HEIGHT); double errors = comparer.Compare(comparisonScreenshot_); if (errors < 0) - SendDebugOutput(comparer.GetError() + "\n"); + SendAndCollectOutput(comparer.GetError() + "\n"); if (errors > maxScreenshotError_) - SendDebugOutput(StringFromFormat("Screenshot MSE: %f\n", errors)); + SendAndCollectOutput(StringFromFormat("Screenshot MSE: %f\n", errors)); if (errors > maxScreenshotError_ && writeFailureScreenshot_) { if (comparer.SaveActualBitmap(Path("__testfailure.bmp"))) - SendDebugOutput("Actual output written to: __testfailure.bmp\n"); + SendAndCollectOutput("Actual output written to: __testfailure.bmp\n"); comparer.SaveVisualComparisonPNG(Path("__testcompare.png")); } } + +void HeadlessHost::SendAndCollectOutput(const std::string &output) { + SendDebugOutput(output); + if (PSP_CoreParameter().collectDebugOutput) + *PSP_CoreParameter().collectDebugOutput += output; +} diff --git a/headless/HeadlessHost.h b/headless/HeadlessHost.h index a40c8ff191..9f61bf08b3 100644 --- a/headless/HeadlessHost.h +++ b/headless/HeadlessHost.h @@ -62,6 +62,8 @@ public: virtual void SwapBuffers() {} protected: + void SendAndCollectOutput(const std::string &output); + Path comparisonScreenshot_; double maxScreenshotError_ = 0.0; std::string debugOutputBuffer_; From 2c5b0999e88d24010df5a5073e6dd2e374b89670 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 31 Mar 2023 23:52:23 -0700 Subject: [PATCH 2/3] softgpu: Make debug-only optim more consistent. Of course it doesn't matter when optimizations are enabled in any compiler that can build PPSSPP... --- GPU/Software/RasterizerRectangle.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/GPU/Software/RasterizerRectangle.cpp b/GPU/Software/RasterizerRectangle.cpp index a7e5c43eac..ebc9563cd4 100644 --- a/GPU/Software/RasterizerRectangle.cpp +++ b/GPU/Software/RasterizerRectangle.cpp @@ -101,7 +101,6 @@ template static inline void DrawSinglePixel(u16 *pixel, const u32 color_in) { u32 new_color; // Because of this check, we only support src.a / 1-src.a blending. - // We take advantage of short circuiting by checking the constant (template) value first. if (!alphaBlend || (color_in >> 24) == 255) { new_color = color_in & 0xFFFFFF; } else { @@ -142,7 +141,7 @@ template static inline void DrawSinglePixel32(u32 *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 || !alphaBlend) { + if (!alphaBlend || (color_in >> 24) == 255) { new_color = color_in & 0xFFFFFF; } else { const u32 old_color = *pixel; From a88b8a14f66691a321a441b4080d34ca0287b172 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 31 Mar 2023 23:53:37 -0700 Subject: [PATCH 3/3] softgpu: Fix over-optimization of alpha test. When alpha blend is off, was previously skipping the alpha test if only it was enabled. See #17213. --- GPU/Software/RasterizerRectangle.cpp | 37 ++++++++++++++++------------ 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/GPU/Software/RasterizerRectangle.cpp b/GPU/Software/RasterizerRectangle.cpp index ebc9563cd4..db14c3306e 100644 --- a/GPU/Software/RasterizerRectangle.cpp +++ b/GPU/Software/RasterizerRectangle.cpp @@ -230,7 +230,7 @@ static inline Vec4IntResult SOFTRAST_CALL ModulateRGBA(Vec4IntArg prim_in, Vec4I return ToVec4IntResult(out); } -template +template static void DrawSpriteTex(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]; @@ -244,7 +244,7 @@ static void DrawSpriteTex(const DrawingCoords &pos0, const DrawingCoords &pos1, for (int x = pos0.x; x < pos1.x; x++) { Vec4 tex_color = fetchFunc(s, t, texptr, texbufw, 0, state.samplerID); if (isWhite) { - if (!alphaBlend || tex_color.a() != 0) { + if (!alphaTestZero || tex_color.a() != 0) { u32 tex_color32 = tex_color.ToRGBA(); if (fmt == GE_FORMAT_8888) DrawSinglePixel32(pixel32, tex_color32); @@ -254,7 +254,7 @@ static void DrawSpriteTex(const DrawingCoords &pos0, const DrawingCoords &pos1, } else { Vec4 prim_color = c0; prim_color = Vec4(ModulateRGBA(ToVec4IntArg(prim_color), ToVec4IntArg(tex_color), state.samplerID)); - if (!alphaBlend || prim_color.a() > 0) { + if (!alphaTestZero || prim_color.a() > 0) { if (fmt == GE_FORMAT_8888) DrawSinglePixel32(pixel32, prim_color.ToRGBA()); else @@ -271,20 +271,20 @@ static void DrawSpriteTex(const DrawingCoords &pos0, const DrawingCoords &pos1, } } -template +template static void DrawSpriteTex(const DrawingCoords &pos0, const DrawingCoords &pos1, int s_start, int t_start, int ds, int dt, u32 color0, const RasterizerState &state, Sampler::FetchFunc fetchFunc) { switch (state.pixelID.FBFormat()) { case GE_FORMAT_565: - DrawSpriteTex(pos0, pos1, s_start, t_start, ds, dt, color0, state, fetchFunc); + DrawSpriteTex(pos0, pos1, s_start, t_start, ds, dt, color0, state, fetchFunc); break; case GE_FORMAT_5551: - DrawSpriteTex(pos0, pos1, s_start, t_start, ds, dt, color0, state, fetchFunc); + DrawSpriteTex(pos0, pos1, s_start, t_start, ds, dt, color0, state, fetchFunc); break; case GE_FORMAT_4444: - DrawSpriteTex(pos0, pos1, s_start, t_start, ds, dt, color0, state, fetchFunc); + DrawSpriteTex(pos0, pos1, s_start, t_start, ds, dt, color0, state, fetchFunc); break; case GE_FORMAT_8888: - DrawSpriteTex(pos0, pos1, s_start, t_start, ds, dt, color0, state, fetchFunc); + DrawSpriteTex(pos0, pos1, s_start, t_start, ds, dt, color0, state, fetchFunc); break; default: // Invalid, don't draw anything... @@ -292,6 +292,17 @@ static void DrawSpriteTex(const DrawingCoords &pos0, const DrawingCoords &pos1, } } +template +static inline void DrawSpriteTex(const DrawingCoords &pos0, const DrawingCoords &pos1, int s_start, int t_start, int ds, int dt, u32 color0, const RasterizerState &state, Sampler::FetchFunc fetchFunc) { + // Standard alpha blending implies skipping alpha zero. + if (state.pixelID.alphaBlend) + DrawSpriteTex(pos0, pos1, s_start, t_start, ds, dt, color0, state, fetchFunc); + else if (state.pixelID.AlphaTestFunc() != GE_COMP_ALWAYS) + DrawSpriteTex(pos0, pos1, s_start, t_start, ds, dt, color0, state, fetchFunc); + else + DrawSpriteTex(pos0, pos1, s_start, t_start, ds, dt, color0, state, fetchFunc); +} + template static void DrawSpriteNoTex(const DrawingCoords &pos0, const DrawingCoords &pos1, u32 color0, const RasterizerState &state) { if (alphaBlend && Vec4::FromRGBA(color0).a() == 0) @@ -392,15 +403,9 @@ void DrawSprite(const VertexData &v0, const VertexData &v1, const BinCoords &ran if (UseDrawSinglePixel(pixelID) && (samplerID.TexFunc() == GE_TEXFUNC_MODULATE || samplerID.TexFunc() == GE_TEXFUNC_REPLACE) && samplerID.useTextureAlpha) { if (isWhite || samplerID.TexFunc() == GE_TEXFUNC_REPLACE) { - if (pixelID.alphaBlend) - DrawSpriteTex(pos0, pos1, s_start, t_start, ds, dt, v1.color0, state, fetchFunc); - else - DrawSpriteTex(pos0, pos1, s_start, t_start, ds, dt, v1.color0, state, fetchFunc); + DrawSpriteTex(pos0, pos1, s_start, t_start, ds, dt, v1.color0, state, fetchFunc); } else { - if (pixelID.alphaBlend) - DrawSpriteTex(pos0, pos1, s_start, t_start, ds, dt, v1.color0, state, fetchFunc); - else - DrawSpriteTex(pos0, pos1, s_start, t_start, ds, dt, v1.color0, state, fetchFunc); + DrawSpriteTex(pos0, pos1, s_start, t_start, ds, dt, v1.color0, state, fetchFunc); } } else { float dsf = ds * (1.0f / (float)(1 << state.samplerID.width0Shift));