From 75ff3e44e69079aa31c83b4a8bf16ffa746fca2f Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 11 Jan 2022 00:00:03 -0800 Subject: [PATCH 1/4] softgpu: Move texture addresses to prim state. --- GPU/Software/Rasterizer.cpp | 74 ++++++++++------------------ GPU/Software/Rasterizer.h | 4 ++ GPU/Software/RasterizerRectangle.cpp | 7 +-- GPU/Software/TransformUnit.cpp | 7 +-- 4 files changed, 35 insertions(+), 57 deletions(-) diff --git a/GPU/Software/Rasterizer.cpp b/GPU/Software/Rasterizer.cpp index 3c61b5c93b..84315c7450 100644 --- a/GPU/Software/Rasterizer.cpp +++ b/GPU/Software/Rasterizer.cpp @@ -102,6 +102,27 @@ static inline Vec4 Interpolate(const float &c0, const float &c1, const fl return Interpolate(c0, c1, c2, w0.Cast(), w1.Cast(), w2.Cast(), wsum_recip); } +void ComputeRasterizerState(RasterizerState *state) { + ComputePixelFuncID(&state->pixelID); + ComputeSamplerID(&state->samplerID); + state->drawPixel = Rasterizer::GetSingleFunc(state->pixelID); + state->linear = Sampler::GetLinearFunc(state->samplerID); + state->nearest = Sampler::GetNearestFunc(state->samplerID); + + int maxTexLevel = state->samplerID.hasAnyMips ? gstate.getTextureMaxLevel() : 0; + if (gstate.isTextureMapEnabled() && !state->pixelID.clearMode) { + GETextureFormat texfmt = state->samplerID.TexFmt(); + for (int i = 0; i <= maxTexLevel; i++) { + u32 texaddr = gstate.getTextureAddress(i); + state->texbufw[i] = GetTextureBufw(i, texaddr, texfmt); + if (Memory::IsValidAddress(texaddr)) + state->texptr[i] = Memory::GetPointerUnchecked(texaddr); + else + state->texptr[i] = nullptr; + } + } +} + static inline u8 ClampFogDepth(float fogdepth) { union FloatBits { float f; @@ -478,7 +499,7 @@ Vec3 AlphaBlendingResult(const PixelFuncID &pixelID, const Vec4 &sourc } } -static inline Vec4IntResult SOFTRAST_CALL ApplyTexturing(float s, float t, int x, int y, Vec4IntArg prim_color, u8 *texptr[], int texbufw[], int texlevel, int frac_texlevel, bool bilinear, const RasterizerState &state) { +static inline Vec4IntResult SOFTRAST_CALL ApplyTexturing(float s, float t, int x, int y, Vec4IntArg prim_color, u8 *const texptr[], const int texbufw[], int texlevel, int frac_texlevel, bool bilinear, const RasterizerState &state) { const u8 **tptr0 = const_cast(&texptr[texlevel]); const int *bufw0 = &texbufw[texlevel]; @@ -488,7 +509,7 @@ static inline Vec4IntResult SOFTRAST_CALL ApplyTexturing(float s, float t, int x return state.linear(s, t, x, y, prim_color, tptr0, bufw0, texlevel, frac_texlevel); } -static inline Vec4IntResult SOFTRAST_CALL ApplyTexturingSingle(float s, float t, int x, int y, Vec4IntArg prim_color, u8 *texptr[], int texbufw[], int texlevel, int frac_texlevel, bool bilinear, const RasterizerState &state) { +static inline Vec4IntResult SOFTRAST_CALL ApplyTexturingSingle(float s, float t, int x, int y, Vec4IntArg prim_color, u8 *const texptr[], const int texbufw[], int texlevel, int frac_texlevel, bool bilinear, const RasterizerState &state) { return ApplyTexturing(s, t, ((x & 15) + 1) / 2, ((y & 15) + 1) / 2, prim_color, texptr, texbufw, texlevel, frac_texlevel, bilinear, state); } @@ -555,7 +576,7 @@ static inline void CalculateSamplingParams(const float ds, const float dt, const } } -static inline void ApplyTexturing(const RasterizerState &state, Vec4 *prim_color, const Vec4 &mask, const Vec4 &s, const Vec4 &t, int maxTexLevel, u8 *texptr[], int texbufw[], int x, int y) { +static inline void ApplyTexturing(const RasterizerState &state, Vec4 *prim_color, const Vec4 &mask, const Vec4 &s, const Vec4 &t, int maxTexLevel, u8 *const texptr[], const int texbufw[], int x, int y) { float ds = s[1] - s[0]; float dt = t[2] - t[0]; @@ -750,23 +771,7 @@ void DrawTriangleSlice( Vec4 bias2 = Vec4::AssignToAll(IsRightSideOrFlatBottomLine(v2.screenpos.xy(), v0.screenpos.xy(), v1.screenpos.xy()) ? -1 : 0); const PixelFuncID &pixelID = state.pixelID; - - int texbufw[8]{}; - int maxTexLevel = state.samplerID.hasAnyMips ? gstate.getTextureMaxLevel() : 0; - u8 *texptr[8]{}; - - if (gstate.isTextureMapEnabled() && !clearMode) { - GETextureFormat texfmt = state.samplerID.TexFmt(); - for (int i = 0; i <= maxTexLevel; i++) { - u32 texaddr = gstate.getTextureAddress(i); - texbufw[i] = GetTextureBufw(i, texaddr, texfmt); - if (Memory::IsValidAddress(texaddr)) - texptr[i] = Memory::GetPointerUnchecked(texaddr); - else - texptr[i] = 0; - } - } TriangleEdge e0; TriangleEdge e1; @@ -872,7 +877,7 @@ void DrawTriangleSlice( GetTextureCoordinates(v0, v1, v2, w0, w1, w2, wsum_recip, s, t); } - ApplyTexturing(state, prim_color, mask, s, t, maxTexLevel, texptr, texbufw, curX, curY); + ApplyTexturing(state, prim_color, mask, s, t, maxTexLevel, state.texptr, state.texbufw, curX, curY); } if (!clearMode) { @@ -1029,20 +1034,7 @@ void DrawPoint(const VertexData &v0, const RasterizerState &state) { auto &samplerID = state.samplerID; if (gstate.isTextureMapEnabled() && !pixelID.clearMode) { - int texbufw[8] = {0}; - int maxTexLevel = samplerID.hasAnyMips ? gstate.getTextureMaxLevel() : 0; - u8 *texptr[8] = {NULL}; - - GETextureFormat texfmt = samplerID.TexFmt(); - for (int i = 0; i <= maxTexLevel; i++) { - u32 texaddr = gstate.getTextureAddress(i); - texbufw[i] = GetTextureBufw(i, texaddr, texfmt); - if (Memory::IsValidAddress(texaddr)) - texptr[i] = Memory::GetPointerUnchecked(texaddr); - else - texptr[i] = 0; - } float s = v0.texturecoords.s(); float t = v0.texturecoords.t(); @@ -1059,7 +1051,7 @@ void DrawPoint(const VertexData &v0, const RasterizerState &state) { bool bilinear; CalculateSamplingParams(0.0f, 0.0f, maxTexLevel, texLevel, texLevelFrac, bilinear); PROFILE_THIS_SCOPE("sampler"); - prim_color = ApplyTexturingSingle(s, t, pos.x, pos.y, ToVec4IntArg(prim_color), texptr, texbufw, texLevel, texLevelFrac, bilinear, state); + prim_color = ApplyTexturingSingle(s, t, pos.x, pos.y, ToVec4IntArg(prim_color), state.texptr, state.texbufw, texLevel, texLevelFrac, bilinear, state); } if (!pixelID.clearMode) @@ -1312,19 +1304,7 @@ void DrawLine(const VertexData &v0, const VertexData &v1, const RasterizerState scissorBR.x += 15; scissorBR.y += 15; - int texbufw[8] = {0}; - int maxTexLevel = state.samplerID.hasAnyMips ? gstate.getTextureMaxLevel() : 0; - u8 *texptr[8] = {NULL}; - - if (gstate.isTextureMapEnabled() && !state.pixelID.clearMode) { - GETextureFormat texfmt = state.samplerID.TexFmt(); - for (int i = 0; i <= maxTexLevel; i++) { - u32 texaddr = gstate.getTextureAddress(i); - texbufw[i] = GetTextureBufw(i, texaddr, texfmt); - texptr[i] = Memory::GetPointer(texaddr); - } - } auto &pixelID = state.pixelID; auto &samplerID = state.samplerID; @@ -1401,7 +1381,7 @@ void DrawLine(const VertexData &v0, const VertexData &v1, const RasterizerState } PROFILE_THIS_SCOPE("sampler"); - prim_color = ApplyTexturingSingle(s, t, x, y, ToVec4IntArg(prim_color), texptr, texbufw, texLevel, texLevelFrac, texBilinear, state); + prim_color = ApplyTexturingSingle(s, t, x, y, ToVec4IntArg(prim_color), state.texptr, state.texbufw, texLevel, texLevelFrac, texBilinear, state); } if (!pixelID.clearMode) diff --git a/GPU/Software/Rasterizer.h b/GPU/Software/Rasterizer.h index 696d619daa..59e2d390c9 100644 --- a/GPU/Software/Rasterizer.h +++ b/GPU/Software/Rasterizer.h @@ -38,8 +38,12 @@ struct RasterizerState { SingleFunc drawPixel; Sampler::LinearFunc linear; Sampler::NearestFunc nearest; + int texbufw[8]{}; + u8 *texptr[8]{}; }; +void ComputeRasterizerState(RasterizerState *state); + // Draws a triangle if its vertices are specified in counter-clockwise order void DrawTriangle(const VertexData &v0, const VertexData &v1, const VertexData &v2, const RasterizerState &state); void DrawPoint(const VertexData &v0, const RasterizerState &state); diff --git a/GPU/Software/RasterizerRectangle.cpp b/GPU/Software/RasterizerRectangle.cpp index 7b140463c3..795674c5e1 100644 --- a/GPU/Software/RasterizerRectangle.cpp +++ b/GPU/Software/RasterizerRectangle.cpp @@ -78,13 +78,10 @@ static inline Vec4IntResult SOFTRAST_CALL ModulateRGBA(Vec4IntArg prim_in, Vec4I } void DrawSprite(const VertexData &v0, const VertexData &v1, const RasterizerState &state) { - const u8 *texptr = nullptr; + const u8 *texptr = state.texptr[0]; GETextureFormat texfmt = state.samplerID.TexFmt(); - u32 texaddr = gstate.getTextureAddress(0); - int texbufw = GetTextureBufw(0, texaddr, texfmt); - if (Memory::IsValidAddress(texaddr)) - texptr = Memory::GetPointerUnchecked(texaddr); + int texbufw = state.texbufw[0]; ScreenCoords pprime(v0.screenpos.x, v0.screenpos.y, 0); Sampler::FetchFunc fetchFunc = Sampler::GetFetchFunc(state.samplerID); diff --git a/GPU/Software/TransformUnit.cpp b/GPU/Software/TransformUnit.cpp index ef711785a7..0c490c2057 100644 --- a/GPU/Software/TransformUnit.cpp +++ b/GPU/Software/TransformUnit.cpp @@ -27,6 +27,7 @@ #include "GPU/Common/DrawEngineCommon.h" #include "GPU/Common/VertexDecoderCommon.h" #include "GPU/Common/SplineCommon.h" +#include "GPU/Common/TextureDecoder.h" #include "GPU/Debugger/Debugger.h" #include "GPU/Software/Clipper.h" #include "GPU/Software/FuncId.h" @@ -342,11 +343,7 @@ void TransformUnit::SubmitPrimitive(void* vertices, void* indices, GEPrimitiveTy // then resolve the indices. This lets us avoid transforming shared vertices twice. Rasterizer::RasterizerState state; - ComputePixelFuncID(&state.pixelID); - ComputeSamplerID(&state.samplerID); - state.drawPixel = Rasterizer::GetSingleFunc(state.pixelID); - state.linear = Sampler::GetLinearFunc(state.samplerID); - state.nearest = Sampler::GetNearestFunc(state.samplerID); + ComputeRasterizerState(&state); bool outside_range_flag = false; switch (prim_type) { From d06f17d27b3827feb360f056249041b44c08f1f3 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 11 Jan 2022 00:07:24 -0800 Subject: [PATCH 2/4] softgpu: Move tex filter setting check to state. --- GPU/Software/Rasterizer.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/GPU/Software/Rasterizer.cpp b/GPU/Software/Rasterizer.cpp index 84315c7450..22e86b1fbe 100644 --- a/GPU/Software/Rasterizer.cpp +++ b/GPU/Software/Rasterizer.cpp @@ -109,6 +109,13 @@ void ComputeRasterizerState(RasterizerState *state) { state->linear = Sampler::GetLinearFunc(state->samplerID); state->nearest = Sampler::GetNearestFunc(state->samplerID); + // Since the definitions are the same, just force this setting using the func pointer. + if (g_Config.iTexFiltering == TEX_FILTER_FORCE_LINEAR) { + state->nearest = state->linear; + } else if (g_Config.iTexFiltering == TEX_FILTER_FORCE_NEAREST) { + state->linear = state->nearest; + } + int maxTexLevel = state->samplerID.hasAnyMips ? gstate.getTextureMaxLevel() : 0; if (gstate.isTextureMapEnabled() && !state->pixelID.clearMode) { GETextureFormat texfmt = state->samplerID.TexFmt(); @@ -567,13 +574,10 @@ static inline void CalculateSamplingParams(const float ds, const float dt, const levelFrac = 0; } - if (g_Config.iTexFiltering == TEX_FILTER_FORCE_LINEAR) { - filt = true; - } else if (g_Config.iTexFiltering == TEX_FILTER_FORCE_NEAREST) { - filt = false; - } else { - filt = detail > 0 ? gstate.isMinifyFilteringEnabled() : gstate.isMagnifyFilteringEnabled(); - } + if (detail > 0) + filt = gstate.isMinifyFilteringEnabled(); + else + filt = gstate.isMagnifyFilteringEnabled(); } static inline void ApplyTexturing(const RasterizerState &state, Vec4 *prim_color, const Vec4 &mask, const Vec4 &s, const Vec4 &t, int maxTexLevel, u8 *const texptr[], const int texbufw[], int x, int y) { From d962fb35d33a71f5355fe4e9b76183d3b51b42ef Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 11 Jan 2022 19:42:40 -0800 Subject: [PATCH 3/4] softgpu: Centralize more prim drawing state. --- GPU/Software/Rasterizer.cpp | 99 +++++++++++++++------------- GPU/Software/Rasterizer.h | 16 +++++ GPU/Software/RasterizerRectangle.cpp | 12 ++-- 3 files changed, 74 insertions(+), 53 deletions(-) diff --git a/GPU/Software/Rasterizer.cpp b/GPU/Software/Rasterizer.cpp index 22e86b1fbe..7e2d94071a 100644 --- a/GPU/Software/Rasterizer.cpp +++ b/GPU/Software/Rasterizer.cpp @@ -116,10 +116,12 @@ void ComputeRasterizerState(RasterizerState *state) { state->linear = state->nearest; } - int maxTexLevel = state->samplerID.hasAnyMips ? gstate.getTextureMaxLevel() : 0; - if (gstate.isTextureMapEnabled() && !state->pixelID.clearMode) { + state->maxTexLevel = state->samplerID.hasAnyMips ? gstate.getTextureMaxLevel() : 0; + state->enableTextures = gstate.isTextureMapEnabled(); + + if (state->enableTextures && !state->pixelID.clearMode) { GETextureFormat texfmt = state->samplerID.TexFmt(); - for (int i = 0; i <= maxTexLevel; i++) { + for (uint8_t i = 0; i <= state->maxTexLevel; i++) { u32 texaddr = gstate.getTextureAddress(i); state->texbufw[i] = GetTextureBufw(i, texaddr, texfmt); if (Memory::IsValidAddress(texaddr)) @@ -128,6 +130,14 @@ void ComputeRasterizerState(RasterizerState *state) { state->texptr[i] = nullptr; } } + + state->texLevelMode = gstate.getTexLevelMode(); + state->texLevelOffset = (int8_t)gstate.getTexLevelOffset16(); + state->shadeGouraud = gstate.getShadeMode() == GE_SHADE_GOURAUD; + state->throughMode = gstate.isModeThrough(); + state->mipFilt = gstate.isMipmapFilteringEnabled(); + state->minFilt = gstate.isMinifyFilteringEnabled(); + state->magFilt = gstate.isMagnifyFilteringEnabled(); } static inline u8 ClampFogDepth(float fogdepth) { @@ -506,9 +516,9 @@ Vec3 AlphaBlendingResult(const PixelFuncID &pixelID, const Vec4 &sourc } } -static inline Vec4IntResult SOFTRAST_CALL ApplyTexturing(float s, float t, int x, int y, Vec4IntArg prim_color, u8 *const texptr[], const int texbufw[], int texlevel, int frac_texlevel, bool bilinear, const RasterizerState &state) { - const u8 **tptr0 = const_cast(&texptr[texlevel]); - const int *bufw0 = &texbufw[texlevel]; +static inline Vec4IntResult SOFTRAST_CALL ApplyTexturing(float s, float t, int x, int y, Vec4IntArg prim_color, int texlevel, int frac_texlevel, bool bilinear, const RasterizerState &state) { + const u8 **tptr0 = const_cast(&state.texptr[texlevel]); + const int *bufw0 = &state.texbufw[texlevel]; if (!bilinear) { return state.nearest(s, t, x, y, prim_color, tptr0, bufw0, texlevel, frac_texlevel); @@ -516,8 +526,8 @@ static inline Vec4IntResult SOFTRAST_CALL ApplyTexturing(float s, float t, int x return state.linear(s, t, x, y, prim_color, tptr0, bufw0, texlevel, frac_texlevel); } -static inline Vec4IntResult SOFTRAST_CALL ApplyTexturingSingle(float s, float t, int x, int y, Vec4IntArg prim_color, u8 *const texptr[], const int texbufw[], int texlevel, int frac_texlevel, bool bilinear, const RasterizerState &state) { - return ApplyTexturing(s, t, ((x & 15) + 1) / 2, ((y & 15) + 1) / 2, prim_color, texptr, texbufw, texlevel, frac_texlevel, bilinear, state); +static inline Vec4IntResult SOFTRAST_CALL ApplyTexturingSingle(float s, float t, int x, int y, Vec4IntArg prim_color, int texlevel, int frac_texlevel, bool bilinear, const RasterizerState &state) { + return ApplyTexturing(s, t, ((x & 15) + 1) / 2, ((y & 15) + 1) / 2, prim_color, texlevel, frac_texlevel, bilinear, state); } // Produces a signed 1.27.4 value. @@ -535,13 +545,13 @@ static int TexLog2(float delta) { return useful - 127 * 16; } -static inline void CalculateSamplingParams(const float ds, const float dt, const int maxTexLevel, int &level, int &levelFrac, bool &filt) { - const int width = gstate.getTextureWidth(0); - const int height = gstate.getTextureHeight(0); +static inline void CalculateSamplingParams(const float ds, const float dt, const RasterizerState &state, int &level, int &levelFrac, bool &filt) { + const int width = 1 << state.samplerID.width0Shift; + const int height = 1 << state.samplerID.height0Shift; // With 8 bits of fraction (because texslope can be fairly precise.) int detail; - switch (gstate.getTexLevelMode()) { + switch (state.TexLevelMode()) { case GE_TEXLEVEL_MODE_AUTO: detail = TexLog2(std::max(ds * width, dt * height)); break; @@ -556,13 +566,13 @@ static inline void CalculateSamplingParams(const float ds, const float dt, const break; } - // Add in the bias (used in all modes), expanding to 8 bits of fraction. - detail += gstate.getTexLevelOffset16(); + // Add in the bias (used in all modes), with 4 bits of fraction. + detail += state.texLevelOffset; - if (detail > 0 && maxTexLevel > 0) { - bool mipFilt = gstate.isMipmapFilteringEnabled(); + if (detail > 0 && state.maxTexLevel > 0) { + bool mipFilt = state.mipFilt; - int level8 = std::min(detail, maxTexLevel * 16); + int level8 = std::min(detail, state.maxTexLevel * 16); if (!mipFilt) { // Round up at 1.5. level8 += 8; @@ -575,24 +585,24 @@ static inline void CalculateSamplingParams(const float ds, const float dt, const } if (detail > 0) - filt = gstate.isMinifyFilteringEnabled(); + filt = state.minFilt; else - filt = gstate.isMagnifyFilteringEnabled(); + filt = state.magFilt; } -static inline void ApplyTexturing(const RasterizerState &state, Vec4 *prim_color, const Vec4 &mask, const Vec4 &s, const Vec4 &t, int maxTexLevel, u8 *const texptr[], const int texbufw[], int x, int y) { +static inline void ApplyTexturing(const RasterizerState &state, Vec4 *prim_color, const Vec4 &mask, const Vec4 &s, const Vec4 &t, int x, int y) { float ds = s[1] - s[0]; float dt = t[2] - t[0]; int level; int levelFrac; bool bilinear; - CalculateSamplingParams(ds, dt, maxTexLevel, level, levelFrac, bilinear); + CalculateSamplingParams(ds, dt, state, level, levelFrac, bilinear); PROFILE_THIS_SCOPE("sampler"); for (int i = 0; i < 4; ++i) { if (mask[i] >= 0) - prim_color[i] = ApplyTexturing(s[i], t[i], ((x & 15) + 1) / 2, ((y & 15) + 1) / 2, ToVec4IntArg(prim_color[i]), texptr, texbufw, level, levelFrac, bilinear, state); + prim_color[i] = ApplyTexturing(s[i], t[i], ((x & 15) + 1) / 2, ((y & 15) + 1) / 2, ToVec4IntArg(prim_color[i]), level, levelFrac, bilinear, state); } } @@ -775,7 +785,6 @@ void DrawTriangleSlice( Vec4 bias2 = Vec4::AssignToAll(IsRightSideOrFlatBottomLine(v2.screenpos.xy(), v0.screenpos.xy(), v1.screenpos.xy()) ? -1 : 0); const PixelFuncID &pixelID = state.pixelID; - int maxTexLevel = state.samplerID.hasAnyMips ? gstate.getTextureMaxLevel() : 0; TriangleEdge e0; TriangleEdge e1; @@ -791,7 +800,7 @@ void DrawTriangleSlice( // All the z values are the same, no interpolation required. // This is common, and when we interpolate, we lose accuracy. const bool flatZ = v0.screenpos.z == v1.screenpos.z && v0.screenpos.z == v2.screenpos.z; - const bool flatColorAll = clearMode || gstate.getShadeMode() != GE_SHADE_GOURAUD; + const bool flatColorAll = clearMode || !state.shadeGouraud; const bool flatColor0 = flatColorAll || (v0.color0 == v1.color0 && v0.color0 == v2.color0); const bool flatColor1 = flatColorAll || (v0.color1 == v1.color1 && v0.color1 == v2.color1); const bool noFog = clearMode || !pixelID.applyFog || (v0.fogdepth >= 1.0f && v1.fogdepth >= 1.0f && v2.fogdepth >= 1.0f); @@ -867,21 +876,21 @@ void DrawTriangleSlice( } } - if (gstate.isTextureMapEnabled() && !clearMode) { + if (state.enableTextures && !clearMode) { Vec4 s, t; - if (gstate.isModeThrough()) { + if (state.throughMode) { s = Interpolate(v0.texturecoords.s(), v1.texturecoords.s(), v2.texturecoords.s(), w0, w1, w2, wsum_recip); t = Interpolate(v0.texturecoords.t(), v1.texturecoords.t(), v2.texturecoords.t(), w0, w1, w2, wsum_recip); // For levels > 0, mipmapping is always based on level 0. Simpler to scale first. - s *= 1.0f / (float)gstate.getTextureWidth(0); - t *= 1.0f / (float)gstate.getTextureHeight(0); + s *= 1.0f / (float)(1 << state.samplerID.width0Shift); + t *= 1.0f / (float)(1 << state.samplerID.height0Shift); } else { // Texture coordinate interpolation must definitely be perspective-correct. GetTextureCoordinates(v0, v1, v2, w0, w1, w2, wsum_recip, s, t); } - ApplyTexturing(state, prim_color, mask, s, t, maxTexLevel, state.texptr, state.texbufw, curX, curY); + ApplyTexturing(state, prim_color, mask, s, t, curX, curY); } if (!clearMode) { @@ -1037,14 +1046,12 @@ void DrawPoint(const VertexData &v0, const RasterizerState &state) { auto &pixelID = state.pixelID; auto &samplerID = state.samplerID; - if (gstate.isTextureMapEnabled() && !pixelID.clearMode) { - int maxTexLevel = samplerID.hasAnyMips ? gstate.getTextureMaxLevel() : 0; - + if (state.enableTextures && !pixelID.clearMode) { float s = v0.texturecoords.s(); float t = v0.texturecoords.t(); - if (gstate.isModeThrough()) { - s *= 1.0f / (float)gstate.getTextureWidth(0); - t *= 1.0f / (float)gstate.getTextureHeight(0); + if (state.throughMode) { + s *= 1.0f / (float)(1 << state.samplerID.width0Shift); + t *= 1.0f / (float)(1 << state.samplerID.height0Shift); } else { // Texture coordinate interpolation must definitely be perspective-correct. GetTextureCoordinates(v0, v0, 0.0f, s, t); @@ -1053,9 +1060,9 @@ void DrawPoint(const VertexData &v0, const RasterizerState &state) { int texLevel; int texLevelFrac; bool bilinear; - CalculateSamplingParams(0.0f, 0.0f, maxTexLevel, texLevel, texLevelFrac, bilinear); + CalculateSamplingParams(0.0f, 0.0f, state, texLevel, texLevelFrac, bilinear); PROFILE_THIS_SCOPE("sampler"); - prim_color = ApplyTexturingSingle(s, t, pos.x, pos.y, ToVec4IntArg(prim_color), state.texptr, state.texbufw, texLevel, texLevelFrac, bilinear, state); + prim_color = ApplyTexturingSingle(s, t, pos.x, pos.y, ToVec4IntArg(prim_color), texLevel, texLevelFrac, bilinear, state); } if (!pixelID.clearMode) @@ -1308,8 +1315,6 @@ void DrawLine(const VertexData &v0, const VertexData &v1, const RasterizerState scissorBR.x += 15; scissorBR.y += 15; - int maxTexLevel = state.samplerID.hasAnyMips ? gstate.getTextureMaxLevel() : 0; - auto &pixelID = state.pixelID; auto &samplerID = state.samplerID; @@ -1349,17 +1354,17 @@ void DrawLine(const VertexData &v0, const VertexData &v1, const RasterizerState prim_color.a() = 0x7F; } - if (gstate.isTextureMapEnabled() && !pixelID.clearMode) { + if (state.enableTextures && !pixelID.clearMode) { float s, s1; float t, t1; - if (gstate.isModeThrough()) { + if (state.throughMode) { Vec2 tc = (v0.texturecoords * (float)(steps - i) + v1.texturecoords * (float)i) / steps1; Vec2 tc1 = (v0.texturecoords * (float)(steps - i - 1) + v1.texturecoords * (float)(i + 1)) / steps1; - s = tc.s() * (1.0f / (float)gstate.getTextureWidth(0)); - s1 = tc1.s() * (1.0f / (float)gstate.getTextureWidth(0)); - t = tc.t() * (1.0f / (float)gstate.getTextureHeight(0)); - t1 = tc1.t() * (1.0f / (float)gstate.getTextureHeight(0)); + s = tc.s() * (1.0f / (float)(1 << state.samplerID.width0Shift)); + s1 = tc1.s() * (1.0f / (float)(1 << state.samplerID.width0Shift)); + t = tc.t() * (1.0f / (float)(1 << state.samplerID.height0Shift)); + t1 = tc1.t() * (1.0f / (float)(1 << state.samplerID.height0Shift)); } else { // Texture coordinate interpolation must definitely be perspective-correct. GetTextureCoordinates(v0, v1, (float)(steps - i) / steps1, s, t); @@ -1373,7 +1378,7 @@ void DrawLine(const VertexData &v0, const VertexData &v1, const RasterizerState int texLevel; int texLevelFrac; bool texBilinear; - CalculateSamplingParams(ds, dt, maxTexLevel, texLevel, texLevelFrac, texBilinear); + CalculateSamplingParams(ds, dt, state, texLevel, texLevelFrac, texBilinear); if (gstate.isAntiAliasEnabled()) { // TODO: This is a niave and wrong implementation. @@ -1385,7 +1390,7 @@ void DrawLine(const VertexData &v0, const VertexData &v1, const RasterizerState } PROFILE_THIS_SCOPE("sampler"); - prim_color = ApplyTexturingSingle(s, t, x, y, ToVec4IntArg(prim_color), state.texptr, state.texbufw, texLevel, texLevelFrac, texBilinear, state); + prim_color = ApplyTexturingSingle(s, t, x, y, ToVec4IntArg(prim_color), texLevel, texLevelFrac, texBilinear, state); } if (!pixelID.clearMode) diff --git a/GPU/Software/Rasterizer.h b/GPU/Software/Rasterizer.h index 59e2d390c9..2a1478351c 100644 --- a/GPU/Software/Rasterizer.h +++ b/GPU/Software/Rasterizer.h @@ -40,6 +40,22 @@ struct RasterizerState { Sampler::NearestFunc nearest; int texbufw[8]{}; u8 *texptr[8]{}; + + struct { + uint8_t maxTexLevel : 3; + bool enableTextures : 1; + uint8_t texLevelMode : 2; + bool shadeGouraud : 1; + bool throughMode : 1; + int8_t texLevelOffset : 8; + bool mipFilt : 1; + bool minFilt : 1; + bool magFilt : 1; + }; + + GETexLevelMode TexLevelMode() const { + return GETexLevelMode(texLevelMode); + } }; void ComputeRasterizerState(RasterizerState *state); diff --git a/GPU/Software/RasterizerRectangle.cpp b/GPU/Software/RasterizerRectangle.cpp index 795674c5e1..889c6531e1 100644 --- a/GPU/Software/RasterizerRectangle.cpp +++ b/GPU/Software/RasterizerRectangle.cpp @@ -102,7 +102,7 @@ void DrawSprite(const VertexData &v0, const VertexData &v1, const RasterizerStat constexpr int MIN_LINES_PER_THREAD = 32; - if (gstate.isTextureMapEnabled()) { + if (state.enableTextures) { // 1:1 (but with mirror support) texture mapping! int s_start = v0.texturecoords.x; int t_start = v0.texturecoords.y; @@ -184,10 +184,10 @@ void DrawSprite(const VertexData &v0, const VertexData &v1, const RasterizerStat int xoff = ((v0.screenpos.x & 15) + 1) / 2; int yoff = ((v0.screenpos.y & 15) + 1) / 2; - float dsf = ds * (1.0f / (float)gstate.getTextureWidth(0)); - float dtf = dt * (1.0f / (float)gstate.getTextureHeight(0)); - float sf_start = s_start * (1.0f / (float)gstate.getTextureWidth(0)); - float tf_start = t_start * (1.0f / (float)gstate.getTextureHeight(0)); + float dsf = ds * (1.0f / (float)(1 << state.samplerID.width0Shift)); + float dtf = dt * (1.0f / (float)(1 << state.samplerID.height0Shift)); + float sf_start = s_start * (1.0f / (float)(1 << state.samplerID.width0Shift)); + float tf_start = t_start * (1.0f / (float)(1 << state.samplerID.height0Shift)); ParallelRangeLoop(&g_threadManager, [=](int y1, int y2) { float t = tf_start + (y1 - pos0.y) * dtf; @@ -291,7 +291,7 @@ bool RectangleFastPath(const VertexData &v0, const VertexData &v1, const Rasteri // We already have a fast path for clear in ClearRectangle. bool state_check = !state.pixelID.clearMode && NoClampOrWrap(v0.texturecoords) && NoClampOrWrap(v1.texturecoords); // TODO: No mipmap levels? Might be a font at level 1... - if ((coord_check || !gstate.isTextureMapEnabled()) && orient_check && state_check) { + if ((coord_check || !state.enableTextures) && orient_check && state_check) { Rasterizer::DrawSprite(v0, v1, state); return true; } From 6839aac109849d4ab8c6a225dd2d58a89070c8e7 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 11 Jan 2022 21:23:29 -0800 Subject: [PATCH 4/4] Debugger: Cache list PC for softgpu tagging. Still slow, but improved. --- GPU/Software/Rasterizer.cpp | 38 +++++++++++----------------- GPU/Software/Rasterizer.h | 4 +++ GPU/Software/RasterizerRectangle.cpp | 7 ++--- 3 files changed, 21 insertions(+), 28 deletions(-) diff --git a/GPU/Software/Rasterizer.cpp b/GPU/Software/Rasterizer.cpp index 7e2d94071a..ce9f90ae44 100644 --- a/GPU/Software/Rasterizer.cpp +++ b/GPU/Software/Rasterizer.cpp @@ -138,6 +138,13 @@ void ComputeRasterizerState(RasterizerState *state) { state->mipFilt = gstate.isMipmapFilteringEnabled(); state->minFilt = gstate.isMinifyFilteringEnabled(); state->magFilt = gstate.isMagnifyFilteringEnabled(); + +#if defined(SOFTGPU_MEMORY_TAGGING_DETAILED) || defined(SOFTGPU_MEMORY_TAGGING_BASIC) + DisplayList currentList{}; + if (gpuDebug) + gpuDebug->GetCurrentDisplayList(currentList); + state->listPC = currentList.pc; +#endif } static inline u8 ClampFogDepth(float fogdepth) { @@ -807,11 +814,8 @@ void DrawTriangleSlice( #if defined(SOFTGPU_MEMORY_TAGGING_DETAILED) || defined(SOFTGPU_MEMORY_TAGGING_BASIC) uint32_t bpp = pixelID.FBFormat() == GE_FORMAT_8888 ? 4 : 2; - DisplayList currentList{}; - if (gpuDebug) - gpuDebug->GetCurrentDisplayList(currentList); - std::string tag = StringFromFormat("DisplayListT_%08x", currentList.pc); - std::string ztag = StringFromFormat("DisplayListTZ_%08x", currentList.pc); + std::string tag = StringFromFormat("DisplayListT_%08x", state.listPC); + std::string ztag = StringFromFormat("DisplayListTZ_%08x", state.listPC); #endif for (int64_t curY = minY; curY <= maxY; curY += 32, @@ -1083,16 +1087,13 @@ void DrawPoint(const VertexData &v0, const RasterizerState &state) { #if defined(SOFTGPU_MEMORY_TAGGING_DETAILED) || defined(SOFTGPU_MEMORY_TAGGING_BASIC) uint32_t bpp = pixelID.FBFormat() == GE_FORMAT_8888 ? 4 : 2; - DisplayList currentList{}; - if (gpuDebug) - gpuDebug->GetCurrentDisplayList(currentList); - std::string tag = StringFromFormat("DisplayListP_%08x", currentList.pc); + std::string tag = StringFromFormat("DisplayListP_%08x", state.listPC); uint32_t row = gstate.getFrameBufAddress() + p.y * gstate.FrameBufStride() * bpp; NotifyMemInfo(MemBlockFlags::WRITE, row + p.x * bpp, bpp, tag.c_str(), tag.size()); if (pixelID.depthWrite) { - std::string ztag = StringFromFormat("DisplayListPZ_%08x", currentList.pc); + std::string ztag = StringFromFormat("DisplayListPZ_%08x", state.listPC); row = gstate.getDepthBufAddress() + p.y * gstate.DepthBufStride() * 2; NotifyMemInfo(MemBlockFlags::WRITE, row + p.x * 2, 2, ztag.c_str(), ztag.size()); } @@ -1123,12 +1124,6 @@ void ClearRectangle(const VertexData &v0, const VertexData &v1, const Rasterizer if (w <= 0) return; -#if defined(SOFTGPU_MEMORY_TAGGING_DETAILED) || defined(SOFTGPU_MEMORY_TAGGING_BASIC) - DisplayList currentList{}; - if (gpuDebug) - gpuDebug->GetCurrentDisplayList(currentList); -#endif - if (pixelID.DepthClear()) { const u16 z = v1.screenpos.z; const int stride = gstate.DepthBufStride(); @@ -1154,7 +1149,7 @@ void ClearRectangle(const VertexData &v0, const VertexData &v1, const Rasterizer } #if defined(SOFTGPU_MEMORY_TAGGING_DETAILED) || defined(SOFTGPU_MEMORY_TAGGING_BASIC) - std::string tag = StringFromFormat("DisplayListXZ_%08x", currentList.pc); + std::string tag = StringFromFormat("DisplayListXZ_%08x", state.listPC); for (int y = pprime.y; y < pend.y; ++y) { uint32_t row = gstate.getDepthBufAddress() + y * gstate.DepthBufStride() * 2; NotifyMemInfo(MemBlockFlags::WRITE, row + pprime.x * 2, w * 2, tag.c_str(), tag.size()); @@ -1275,7 +1270,7 @@ void ClearRectangle(const VertexData &v0, const VertexData &v1, const Rasterizer #if defined(SOFTGPU_MEMORY_TAGGING_DETAILED) || defined(SOFTGPU_MEMORY_TAGGING_BASIC) if (keepOldMask != 0xFFFFFFFF) { uint32_t bpp = pixelID.FBFormat() == GE_FORMAT_8888 ? 4 : 2; - std::string tag = StringFromFormat("DisplayListX_%08x", currentList.pc); + std::string tag = StringFromFormat("DisplayListX_%08x", state.listPC); for (int y = pprime.y; y < pend.y; ++y) { uint32_t row = gstate.getFrameBufAddress() + y * gstate.FrameBufStride() * bpp; NotifyMemInfo(MemBlockFlags::WRITE, row + pprime.x * bpp, w * bpp, tag.c_str(), tag.size()); @@ -1319,11 +1314,8 @@ void DrawLine(const VertexData &v0, const VertexData &v1, const RasterizerState auto &samplerID = state.samplerID; #if defined(SOFTGPU_MEMORY_TAGGING_DETAILED) || defined(SOFTGPU_MEMORY_TAGGING_BASIC) - DisplayList currentList{}; - if (gpuDebug) - gpuDebug->GetCurrentDisplayList(currentList); - std::string tag = StringFromFormat("DisplayListL_%08x", currentList.pc); - std::string ztag = StringFromFormat("DisplayListLZ_%08x", currentList.pc); + std::string tag = StringFromFormat("DisplayListL_%08x", state.listPC); + std::string ztag = StringFromFormat("DisplayListLZ_%08x", state.listPC); #endif double x = a.x > b.x ? a.x - 1 : a.x; diff --git a/GPU/Software/Rasterizer.h b/GPU/Software/Rasterizer.h index 2a1478351c..0223f39959 100644 --- a/GPU/Software/Rasterizer.h +++ b/GPU/Software/Rasterizer.h @@ -53,6 +53,10 @@ struct RasterizerState { bool magFilt : 1; }; +#if defined(SOFTGPU_MEMORY_TAGGING_DETAILED) || defined(SOFTGPU_MEMORY_TAGGING_BASIC) + uint32_t listPC; +#endif + GETexLevelMode TexLevelMode() const { return GETexLevelMode(texLevelMode); } diff --git a/GPU/Software/RasterizerRectangle.cpp b/GPU/Software/RasterizerRectangle.cpp index 889c6531e1..af02589094 100644 --- a/GPU/Software/RasterizerRectangle.cpp +++ b/GPU/Software/RasterizerRectangle.cpp @@ -249,11 +249,8 @@ void DrawSprite(const VertexData &v0, const VertexData &v1, const RasterizerStat #if defined(SOFTGPU_MEMORY_TAGGING_BASIC) || defined(SOFTGPU_MEMORY_TAGGING_DETAILED) uint32_t bpp = pixelID.FBFormat() == GE_FORMAT_8888 ? 4 : 2; - DisplayList currentList{}; - if (gpuDebug) - gpuDebug->GetCurrentDisplayList(currentList); - std::string tag = StringFromFormat("DisplayListR_%08x", currentList.pc); - std::string ztag = StringFromFormat("DisplayListRZ_%08x", currentList.pc); + std::string tag = StringFromFormat("DisplayListR_%08x", state.listPC); + std::string ztag = StringFromFormat("DisplayListRZ_%08x", state.listPC); for (int y = pos0.y; y < pos1.y; y++) { uint32_t row = gstate.getFrameBufAddress() + y * gstate.FrameBufStride() * bpp;