diff --git a/GPU/Software/Rasterizer.cpp b/GPU/Software/Rasterizer.cpp index 689ce9743f..c2357f32a0 100644 --- a/GPU/Software/Rasterizer.cpp +++ b/GPU/Software/Rasterizer.cpp @@ -115,53 +115,6 @@ static inline u8 ClampFogDepth(float fogdepth) { return mantissa >> (16 + 126 - exp); } -static inline int ClampUV(int v, int height) { - if (v >= height - 1) - return height - 1; - else if (v < 0) - return 0; - return v; -} - -static inline int WrapUV(int v, int height) { - return v & (height - 1); -} - -template -static inline void ApplyTexelClamp(int out_u[N], int out_v[N], const int u[N], const int v[N], int width, int height) { - if (gstate.isTexCoordClampedS()) { - for (int i = 0; i < N; ++i) { - out_u[i] = ClampUV(u[i], width); - } - } else { - for (int i = 0; i < N; ++i) { - out_u[i] = WrapUV(u[i], width); - } - } - if (gstate.isTexCoordClampedT()) { - for (int i = 0; i < N; ++i) { - out_v[i] = ClampUV(v[i], height); - } - } else { - for (int i = 0; i < N; ++i) { - out_v[i] = WrapUV(v[i], height); - } - } -} - -static inline void GetTexelCoordinates(int level, float s, float t, int &out_u, int &out_v, int x, int y) { - int width = gstate.getTextureWidth(level); - int height = gstate.getTextureHeight(level); - - int base_u = (int)(s * width * 256.0f) + 12 - x; - int base_v = (int)(t * height * 256.0f) + 12 - y; - - base_u >>= 8; - base_v >>= 8; - - ApplyTexelClamp<1>(&out_u, &out_v, &base_u, &base_v, width, height); -} - static inline void GetTextureCoordinates(const VertexData& v0, const VertexData& v1, const float p, float &s, float &t) { // All UV gen modes, by the time they get here, behave the same. @@ -518,35 +471,19 @@ Vec3 AlphaBlendingResult(const PixelFuncID &pixelID, const Vec4 &sourc } template -static inline Vec4IntResult SOFTRAST_CALL ApplyTexturing(Sampler::Funcs sampler, Vec4IntArg prim_color, float s, float t, int texlevel, int frac_texlevel, bool bilinear, u8 *texptr[], int texbufw[], int x, int y) { - Vec4 texcolor0; +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, Sampler::Funcs sampler) { const u8 **tptr0 = const_cast(&texptr[mayHaveMipLevels ? texlevel : 0]); const int *bufw0 = &texbufw[mayHaveMipLevels ? texlevel : 0]; if (!bilinear) { - int u[8] = { 0 }, v[8] = { 0 }; // 1.27.4 fixed point - - // Nearest filtering only. Round texcoords. - GetTexelCoordinates(mayHaveMipLevels ? texlevel : 0, s, t, u[0], v[0], x, y); - if (mayHaveMipLevels && frac_texlevel) { - GetTexelCoordinates(texlevel + 1, s, t, u[1], v[1], x, y); - } - - texcolor0 = Vec4(sampler.nearest(u[0], v[0], tptr0[0], bufw0[0], mayHaveMipLevels ? texlevel : 0)); - if (mayHaveMipLevels && frac_texlevel) { - Vec4 texcolor1 = Vec4(sampler.nearest(u[1], v[1], tptr0[1], bufw0[1], texlevel + 1)); - texcolor0 = (texcolor1 * frac_texlevel + texcolor0 * (16 - frac_texlevel)) / 16; - } - - return GetTextureFunctionOutput(prim_color, ToVec4IntArg(texcolor0)); + return sampler.nearest(s, t, x, y, prim_color, tptr0, bufw0, mayHaveMipLevels ? texlevel : 0, mayHaveMipLevels ? frac_texlevel : 0); } - return sampler.linear(s, t, x, y, prim_color, tptr0, bufw0, mayHaveMipLevels ? texlevel : 0, mayHaveMipLevels ? frac_texlevel : 0); } template -static inline Vec4IntResult SOFTRAST_CALL ApplyTexturingSingle(Sampler::Funcs sampler, Vec4IntArg prim_color, float s, float t, int texlevel, int frac_texlevel, bool bilinear, u8 *texptr[], int texbufw[], int x, int y) { - return ApplyTexturing(sampler, prim_color, s, t, texlevel, frac_texlevel, bilinear, texptr, texbufw, ((x & 15) + 1) / 2, ((y & 15) + 1) / 2); +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, Sampler::Funcs sampler) { + return ApplyTexturing(s, t, ((x & 15) + 1) / 2, ((y & 15) + 1) / 2, prim_color, texptr, texbufw, texlevel, frac_texlevel, bilinear, sampler); } // Produces a signed 1.27.4 value. @@ -626,7 +563,7 @@ static inline void ApplyTexturing(Sampler::Funcs sampler, Vec4 *prim_color, CalculateSamplingParams(ds, dt, maxTexLevel, level, levelFrac, bilinear); for (int i = 0; i < 4; ++i) { - prim_color[i] = ApplyTexturing(sampler, ToVec4IntArg(prim_color[i]), s[i], t[i], level, levelFrac, bilinear, texptr, texbufw, ((x & 15) + 1) / 2, ((y & 15) + 1) / 2); + 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, sampler); } } @@ -978,7 +915,7 @@ void DrawPoint(const VertexData &v0) int texLevelFrac; bool bilinear; CalculateSamplingParams(0.0f, 0.0f, maxTexLevel, texLevel, texLevelFrac, bilinear); - prim_color = ApplyTexturingSingle(sampler, ToVec4IntArg(prim_color), s, t, texLevel, texLevelFrac, bilinear, texptr, texbufw, pos.x, pos.y); + prim_color = ApplyTexturingSingle(s, t, pos.x, pos.y, ToVec4IntArg(prim_color), texptr, texbufw, texLevel, texLevelFrac, bilinear, sampler); } if (!pixelID.clearMode) @@ -1275,7 +1212,7 @@ void DrawLine(const VertexData &v0, const VertexData &v1) texBilinear = true; } - prim_color = ApplyTexturingSingle(sampler, ToVec4IntArg(prim_color), s, t, texLevel, texLevelFrac, texBilinear, texptr, texbufw, x, y); + prim_color = ApplyTexturingSingle(s, t, x, y, ToVec4IntArg(prim_color), texptr, texbufw, texLevel, texLevelFrac, texBilinear, sampler); } if (!pixelID.clearMode) diff --git a/GPU/Software/Sampler.cpp b/GPU/Software/Sampler.cpp index e0df2a67c3..11485aba51 100644 --- a/GPU/Software/Sampler.cpp +++ b/GPU/Software/Sampler.cpp @@ -39,7 +39,7 @@ extern u32 clut[4096]; namespace Sampler { -static Vec4IntResult SOFTRAST_CALL SampleNearest(int u, int v, const u8 *tptr, int bufw, int level); +static Vec4IntResult SOFTRAST_CALL SampleNearest(float s, float t, int x, int y, Vec4IntArg prim_color, const u8 **tptr, const int *bufw, int level, int levelFrac); static Vec4IntResult SOFTRAST_CALL SampleLinear(float s, float t, int x, int y, Vec4IntArg prim_color, const u8 **tptr, const int *bufw, int level, int levelFrac); static Vec4IntResult SOFTRAST_CALL SampleFetch(int u, int v, const u8 *tptr, int bufw, int level); @@ -379,16 +379,6 @@ inline static Nearest4 SOFTRAST_CALL SampleNearest(const int u[N], const int v[N } } -static Vec4IntResult SOFTRAST_CALL SampleNearest(int u, int v, const u8 *tptr, int bufw, int level) { - Nearest4 c = SampleNearest<1>(&u, &v, tptr, bufw, level); - return ToVec4IntResult(Vec4::FromRGBA(c.v[0])); -} - -static Vec4IntResult SOFTRAST_CALL SampleFetch(int u, int v, const u8 *tptr, int bufw, int level) { - Nearest4 c = SampleNearest<1>(&u, &v, tptr, bufw, level); - return ToVec4IntResult(Vec4::FromRGBA(c.v[0])); -} - static inline int ClampUV(int v, int height) { if (v >= height - 1) return height - 1; @@ -401,6 +391,63 @@ static inline int WrapUV(int v, int height) { return v & (height - 1); } +template +static inline void ApplyTexelClamp(int out_u[N], int out_v[N], const int u[N], const int v[N], int width, int height) { + if (gstate.isTexCoordClampedS()) { + for (int i = 0; i < N; ++i) { + out_u[i] = ClampUV(u[i], width); + } + } else { + for (int i = 0; i < N; ++i) { + out_u[i] = WrapUV(u[i], width); + } + } + if (gstate.isTexCoordClampedT()) { + for (int i = 0; i < N; ++i) { + out_v[i] = ClampUV(v[i], height); + } + } else { + for (int i = 0; i < N; ++i) { + out_v[i] = WrapUV(v[i], height); + } + } +} + +static inline void GetTexelCoordinates(int level, float s, float t, int &out_u, int &out_v, int x, int y) { + int width = gstate.getTextureWidth(level); + int height = gstate.getTextureHeight(level); + + int base_u = (int)(s * width * 256.0f) + 12 - x; + int base_v = (int)(t * height * 256.0f) + 12 - y; + + base_u >>= 8; + base_v >>= 8; + + ApplyTexelClamp<1>(&out_u, &out_v, &base_u, &base_v, width, height); +} + +static Vec4IntResult SOFTRAST_CALL SampleNearest(float s, float t, int x, int y, Vec4IntArg prim_color, const u8 **tptr, const int *bufw, int level, int levelFrac) { + int u, v; + + // Nearest filtering only. Round texcoords. + GetTexelCoordinates(level, s, t, u, v, x, y); + Vec4 c0 = Vec4::FromRGBA(SampleNearest<1>(&u, &v, tptr[0], bufw[0], level).v[0]); + + if (levelFrac) { + GetTexelCoordinates(level + 1, s, t, u, v, x, y); + Vec4 c1 = Vec4::FromRGBA(SampleNearest<1>(&u, &v, tptr[1], bufw[1], level + 1).v[0]); + + c0 = (c1 * levelFrac + c0 * (16 - levelFrac)) / 16; + } + + return GetTextureFunctionOutput(prim_color, ToVec4IntArg(c0)); +} + +static Vec4IntResult SOFTRAST_CALL SampleFetch(int u, int v, const u8 *tptr, int bufw, int level) { + Nearest4 c = SampleNearest<1>(&u, &v, tptr, bufw, level); + return ToVec4IntResult(Vec4::FromRGBA(c.v[0])); +} + static inline Vec4IntResult SOFTRAST_CALL ApplyTexelClampQuad(bool clamp, Vec4IntArg vec, int width) { Vec4 result = vec; #ifdef _M_SSE diff --git a/GPU/Software/Sampler.h b/GPU/Software/Sampler.h index 3386640513..126d345e4e 100644 --- a/GPU/Software/Sampler.h +++ b/GPU/Software/Sampler.h @@ -36,7 +36,7 @@ namespace Sampler { typedef Rasterizer::Vec4IntResult(SOFTRAST_CALL *FetchFunc)(int u, int v, const u8 *tptr, int bufw, int level); FetchFunc GetFetchFunc(SamplerID id); -typedef Rasterizer::Vec4IntResult (SOFTRAST_CALL *NearestFunc)(int u, int v, const u8 *tptr, int bufw, int level); +typedef Rasterizer::Vec4IntResult (SOFTRAST_CALL *NearestFunc)(float s, float t, int x, int y, Rasterizer::Vec4IntArg prim_color, const u8 **tptr, const int *bufw, int level, int levelFrac); NearestFunc GetNearestFunc(SamplerID id); typedef Rasterizer::Vec4IntResult (SOFTRAST_CALL *LinearFunc)(float s, float t, int x, int y, Rasterizer::Vec4IntArg prim_color, const u8 **tptr, const int *bufw, int level, int levelFrac); diff --git a/GPU/Software/SamplerX86.cpp b/GPU/Software/SamplerX86.cpp index 7fd6066237..3470daff4e 100644 --- a/GPU/Software/SamplerX86.cpp +++ b/GPU/Software/SamplerX86.cpp @@ -34,11 +34,7 @@ extern u32 clut[4096]; namespace Sampler { FetchFunc SamplerJitCache::CompileFetch(const SamplerID &id) { - // TODO: Make these different. - return CompileNearest(id); -} - -NearestFunc SamplerJitCache::CompileNearest(const SamplerID &id) { + _assert_msg_(id.fetch && !id.linear, "Only fetch should be set on sampler id"); regCache_.SetupABI({ RegCache::GEN_ARG_U, RegCache::GEN_ARG_V, @@ -103,14 +99,18 @@ NearestFunc SamplerJitCache::CompileNearest(const SamplerID &id) { regCache_.Reset(true); EndWrite(); - return (NearestFunc)start; + return (FetchFunc)start; } -alignas(16) static const float by256[4] = { 1.0f / 256.0f, 1.0f / 256.0f, 1.0f / 256.0f, 1.0f / 256.0f, }; -alignas(16) static const float ones[4] = { 1.0f, 1.0f, 1.0f, 1.0f, }; +NearestFunc SamplerJitCache::CompileNearest(const SamplerID &id) { + _assert_msg_(!id.fetch && !id.linear, "Fetch and linear should be cleared on sampler id"); + + // TODO: Actual implementation with new args. + return nullptr; +} LinearFunc SamplerJitCache::CompileLinear(const SamplerID &id) { - _assert_msg_(id.linear, "Linear should be set on sampler id"); + _assert_msg_(id.linear && !id.fetch, "Only linear should be set on sampler id"); BeginWrite(); Describe("Init");