From 4fb7e43af86c21fe1c3f75de068960effb79428b Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 23 Apr 2017 10:39:58 -0700 Subject: [PATCH] SoftGPU: Grab 4 S/T coords in non-through too. --- GPU/Math3D.h | 6 ++ GPU/Software/Rasterizer.cpp | 157 +++++++++++++++++++----------------- 2 files changed, 88 insertions(+), 75 deletions(-) diff --git a/GPU/Math3D.h b/GPU/Math3D.h index 1b62a35b31..53c7a1e8a0 100644 --- a/GPU/Math3D.h +++ b/GPU/Math3D.h @@ -634,6 +634,12 @@ public: return Vec4(VecClamp(x, l, h), VecClamp(y, l, h), VecClamp(z, l, h), VecClamp(w, l, h)); } + Vec4 Reciprocal() const + { + const T one = 1.0f; + return Vec4(one / x, one / y, one / z, one / w); + } + // Only implemented for T=float float Length() const; void SetLength(const float l); diff --git a/GPU/Software/Rasterizer.cpp b/GPU/Software/Rasterizer.cpp index 708c71529d..35d0dcebe2 100644 --- a/GPU/Software/Rasterizer.cpp +++ b/GPU/Software/Rasterizer.cpp @@ -58,6 +58,62 @@ static inline int orient2dIncY(int dX01) return -dX01; } +// Only OK on x64 where our stack is aligned +#if defined(_M_SSE) && !defined(_M_IX86) +static inline __m128 Interpolate(const __m128 &c0, const __m128 &c1, const __m128 &c2, int w0, int w1, int w2, float wsum) { + __m128 v = _mm_mul_ps(c0, _mm_cvtepi32_ps(_mm_set1_epi32(w0))); + v = _mm_add_ps(v, _mm_mul_ps(c1, _mm_cvtepi32_ps(_mm_set1_epi32(w1)))); + v = _mm_add_ps(v, _mm_mul_ps(c2, _mm_cvtepi32_ps(_mm_set1_epi32(w2)))); + return _mm_mul_ps(v, _mm_set_ps1(wsum)); +} + +static inline __m128i Interpolate(const __m128i &c0, const __m128i &c1, const __m128i &c2, int w0, int w1, int w2, float wsum) { + return _mm_cvtps_epi32(Interpolate(_mm_cvtepi32_ps(c0), _mm_cvtepi32_ps(c1), _mm_cvtepi32_ps(c2), w0, w1, w2, wsum)); +} +#endif + +// NOTE: When not casting color0 and color1 to float vectors, this code suffers from severe overflow issues. +// Not sure if that should be regarded as a bug or if casting to float is a valid fix. + +static inline Vec4 Interpolate(const Vec4 &c0, const Vec4 &c1, const Vec4 &c2, int w0, int w1, int w2, float wsum) { +#if defined(_M_SSE) && !defined(_M_IX86) + return Vec4(Interpolate(c0.ivec, c1.ivec, c2.ivec, w0, w1, w2, wsum)); +#else + return ((c0.Cast() * w0 + c1.Cast() * w1 + c2.Cast() * w2) * wsum).Cast(); +#endif +} + +static inline Vec3 Interpolate(const Vec3 &c0, const Vec3 &c1, const Vec3 &c2, int w0, int w1, int w2, float wsum) { +#if defined(_M_SSE) && !defined(_M_IX86) + return Vec3(Interpolate(c0.ivec, c1.ivec, c2.ivec, w0, w1, w2, wsum)); +#else + return ((c0.Cast() * w0 + c1.Cast() * w1 + c2.Cast() * w2) * wsum).Cast(); +#endif +} + +static inline Vec2 Interpolate(const Vec2 &c0, const Vec2 &c1, const Vec2 &c2, int w0, int w1, int w2, float wsum) { +#if defined(_M_SSE) && !defined(_M_IX86) + return Vec2(Interpolate(c0.vec, c1.vec, c2.vec, w0, w1, w2, wsum)); +#else + return (c0 * w0 + c1 * w1 + c2 * w2) * wsum; +#endif +} + +static inline Vec4 Interpolate(const float &c0, const float &c1, const float &c2, const Vec4 &w0, const Vec4 &w1, const Vec4 &w2, const Vec4 &wsum_recip) { +#if defined(_M_SSE) && !defined(_M_IX86) + __m128 v = _mm_mul_ps(w0.vec, _mm_set1_ps(c0)); + v = _mm_add_ps(v, _mm_mul_ps(w1.vec, _mm_set1_ps(c1))); + v = _mm_add_ps(v, _mm_mul_ps(w2.vec, _mm_set1_ps(c2))); + return _mm_mul_ps(v, wsum_recip.vec); +#else + return (w0 * c0 + w1 * c1 + w2 * c2) * wsum_recip; +#endif +} + +static inline Vec4 Interpolate(const float &c0, const float &c1, const float &c2, const Vec4 &w0, const Vec4 &w1, const Vec4 &w2, const Vec4 &wsum_recip) { + return Interpolate(c0, c1, c2, w0.Cast(), w1.Cast(), w2.Cast(), wsum_recip); +} + template static inline int GetPixelDataOffset(unsigned int row_pitch_bytes, unsigned int u, unsigned int v) { @@ -212,7 +268,7 @@ static inline void GetTexelCoordinatesThroughQuad(int level, int s, int t, int * } } -static inline void GetTextureCoordinates(const VertexData& v0, const VertexData& v1, const VertexData& v2, int w0, int w1, int w2, float& s, float& t) +static inline void GetTextureCoordinates(const VertexData& v0, const VertexData& v1, const VertexData& v2, const Vec4 &w0, const Vec4 &w1, const Vec4 &w2, const Vec4 &wsum_recip, Vec4 &s, Vec4 &t) { switch (gstate.getUVGenMode()) { case GE_TEXMAP_TEXTURE_COORDS: @@ -224,30 +280,34 @@ static inline void GetTextureCoordinates(const VertexData& v0, const VertexData& float q0 = 1.f / v0.clippos.w; float q1 = 1.f / v1.clippos.w; float q2 = 1.f / v2.clippos.w; - float q_recip = 1.0f / (q0 * w0 + q1 * w1 + q2 * w2); - s = (v0.texturecoords.s() * q0 * w0 + v1.texturecoords.s() * q1 * w1 + v2.texturecoords.s() * q2 * w2) * q_recip; - t = (v0.texturecoords.t() * q0 * w0 + v1.texturecoords.t() * q1 * w1 + v2.texturecoords.t() * q2 * w2) * q_recip; + Vec4 wq0 = w0.Cast() * q0; + Vec4 wq1 = w1.Cast() * q1; + Vec4 wq2 = w2.Cast() * q2; + + Vec4 q_recip = (wq0 + wq1 + wq2).Reciprocal(); + s = Interpolate(v0.texturecoords.s(), v1.texturecoords.s(), v2.texturecoords.s(), wq0, wq1, wq2, q_recip); + t = Interpolate(v0.texturecoords.t(), v1.texturecoords.t(), v2.texturecoords.t(), wq0, wq1, wq2, q_recip); } break; case GE_TEXMAP_TEXTURE_MATRIX: - { + for (int i = 0; i < 4; ++i) { // projection mapping, TODO: Move this code to TransformUnit! Vec3 source; switch (gstate.getUVProjMode()) { case GE_PROJMAP_POSITION: - source = (v0.modelpos * w0 + v1.modelpos * w1 + v2.modelpos * w2) / (w0 + w1 + w2); + source = (v0.modelpos * w0[i] + v1.modelpos * w1[i] + v2.modelpos * w2[i]) * wsum_recip[i]; break; case GE_PROJMAP_UV: - source = Vec3f((v0.texturecoords * w0 + v1.texturecoords * w1 + v2.texturecoords * w2) / (w0 + w1 + w2), 0.0f); + source = Vec3f((v0.texturecoords * w0[i] + v1.texturecoords * w1[i] + v2.texturecoords * w2[i]) * wsum_recip[i], 0.0f); break; case GE_PROJMAP_NORMALIZED_NORMAL: - source = (v0.normal.Normalized() * w0 + v1.normal.Normalized() * w1 + v2.normal.Normalized() * w2) / (w0 + w1 + w2); + source = (v0.normal.Normalized() * w0[i] + v1.normal.Normalized() * w1[i] + v2.normal.Normalized() * w2[i]) * wsum_recip[i]; break; case GE_PROJMAP_NORMAL: - source = (v0.normal * w0 + v1.normal * w1 + v2.normal * w2) / (w0 + w1 + w2); + source = (v0.normal * w0[i] + v1.normal * w1[i] + v2.normal * w2[i]) * wsum_recip[i]; break; default: @@ -258,12 +318,14 @@ static inline void GetTextureCoordinates(const VertexData& v0, const VertexData& Mat3x3 tgen(gstate.tgenMatrix); Vec3 stq = tgen * source + Vec3(gstate.tgenMatrix[9], gstate.tgenMatrix[10], gstate.tgenMatrix[11]); float z_recip = 1.0f / stq.z; - s = stq.x * z_recip; - t = stq.y * z_recip; + s[i] = stq.x * z_recip; + t[i] = stq.y * z_recip; } break; default: ERROR_LOG_REPORT(G3D, "Software: Unsupported texture mapping mode %x!", gstate.getUVGenMode()); + s = Vec4::AssignToAll(0.0f); + t = Vec4::AssignToAll(0.0f); break; } } @@ -1139,58 +1201,6 @@ inline void ApplyTexturing(Vec4 &prim_color, float s, float t, int maxTexLe prim_color = GetTextureFunctionOutput(prim_color, texcolor); } -// Only OK on x64 where our stack is aligned -#if defined(_M_SSE) && !defined(_M_IX86) -static inline __m128 Interpolate(const __m128 &c0, const __m128 &c1, const __m128 &c2, int w0, int w1, int w2, float wsum) { - __m128 v = _mm_mul_ps(c0, _mm_cvtepi32_ps(_mm_set1_epi32(w0))); - v = _mm_add_ps(v, _mm_mul_ps(c1, _mm_cvtepi32_ps(_mm_set1_epi32(w1)))); - v = _mm_add_ps(v, _mm_mul_ps(c2, _mm_cvtepi32_ps(_mm_set1_epi32(w2)))); - return _mm_mul_ps(v, _mm_set_ps1(wsum)); -} - -static inline __m128i Interpolate(const __m128i &c0, const __m128i &c1, const __m128i &c2, int w0, int w1, int w2, float wsum) { - return _mm_cvtps_epi32(Interpolate(_mm_cvtepi32_ps(c0), _mm_cvtepi32_ps(c1), _mm_cvtepi32_ps(c2), w0, w1, w2, wsum)); -} -#endif - -// NOTE: When not casting color0 and color1 to float vectors, this code suffers from severe overflow issues. -// Not sure if that should be regarded as a bug or if casting to float is a valid fix. - -static inline Vec4 Interpolate(const Vec4 &c0, const Vec4 &c1, const Vec4 &c2, int w0, int w1, int w2, float wsum) { -#if defined(_M_SSE) && !defined(_M_IX86) - return Vec4(Interpolate(c0.ivec, c1.ivec, c2.ivec, w0, w1, w2, wsum)); -#else - return ((c0.Cast() * w0 + c1.Cast() * w1 + c2.Cast() * w2) * wsum).Cast(); -#endif -} - -static inline Vec3 Interpolate(const Vec3 &c0, const Vec3 &c1, const Vec3 &c2, int w0, int w1, int w2, float wsum) { -#if defined(_M_SSE) && !defined(_M_IX86) - return Vec3(Interpolate(c0.ivec, c1.ivec, c2.ivec, w0, w1, w2, wsum)); -#else - return ((c0.Cast() * w0 + c1.Cast() * w1 + c2.Cast() * w2) * wsum).Cast(); -#endif -} - -static inline Vec2 Interpolate(const Vec2 &c0, const Vec2 &c1, const Vec2 &c2, int w0, int w1, int w2, float wsum) { -#if defined(_M_SSE) && !defined(_M_IX86) - return Vec2(Interpolate(c0.vec, c1.vec, c2.vec, w0, w1, w2, wsum)); -#else - return (c0 * w0 + c1 * w1 + c2 * w2) * wsum; -#endif -} - -static inline Vec4 Interpolate(const float &c0, const float &c1, const float &c2, const Vec4 &w0, const Vec4 &w1, const Vec4 &w2, const Vec4 &wsum_recip) { -#if defined(_M_SSE) && !defined(_M_IX86) - __m128 v = _mm_mul_ps(_mm_cvtepi32_ps(w0.ivec), _mm_set1_ps(c0)); - v = _mm_add_ps(v, _mm_mul_ps(_mm_cvtepi32_ps(w1.ivec), _mm_set1_ps(c1))); - v = _mm_add_ps(v, _mm_mul_ps(_mm_cvtepi32_ps(w2.ivec), _mm_set1_ps(c2))); - return _mm_mul_ps(v, wsum_recip.vec); -#else - return (w0.Cast() * c0 + w1.Cast() * c1 + w2.Cast() * c2) * wsum_recip; -#endif -} - struct TriangleEdge { Vec4 Start(const ScreenCoords &v0, const ScreenCoords &v1, const ScreenCoords &origin); inline Vec4 StepX(const Vec4 &w); @@ -1306,8 +1316,7 @@ void DrawTriangleSlice( // If p is on or inside all edges, render pixel Vec4 mask = (w0 + bias0) | (w1 + bias1) | (w2 + bias2); if (mask.x >= 0 || mask.y >= 0 || mask.z >= 0 || mask.w >= 0) { - Vec4 wsum = (w0 + w1 + w2).Cast(); - Vec4 wsum_recip(1.0f / wsum.x, 1.0f / wsum.y, 1.0f / wsum.z, 1.0f / wsum.w); + Vec4 wsum_recip = (w0 + w1 + w2).Cast().Reciprocal(); Vec4 prim_color[4]; Vec3 sec_color[4]; @@ -1325,19 +1334,17 @@ void DrawTriangleSlice( } if (gstate.isTextureMapEnabled() && !clearMode) { + Vec4 s, t; if (gstate.isModeThrough()) { - Vec4 s = Interpolate(v0.texturecoords.s(), v1.texturecoords.s(), v2.texturecoords.s(), w0, w1, w2, wsum_recip); - Vec4 t = Interpolate(v0.texturecoords.t(), v1.texturecoords.t(), v2.texturecoords.t(), w0, w1, w2, wsum_recip); - for (int i = 0; i < 4; ++i) { - ApplyTexturing(prim_color[i], s[i], t[i], maxTexLevel, magFilt, texptr, texbufwidthbytes); - } + 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); } else { // Texture coordinate interpolation must definitely be perspective-correct. - for (int i = 0; i < 4; ++i) { - float s = 0, t = 0; - GetTextureCoordinates(v0, v1, v2, w0[i], w1[i], w2[i], s, t); - ApplyTexturing(prim_color[i], s, t, maxTexLevel, magFilt, texptr, texbufwidthbytes); - } + GetTextureCoordinates(v0, v1, v2, w0, w1, w2, wsum_recip, s, t); + } + + for (int i = 0; i < 4; ++i) { + ApplyTexturing(prim_color[i], s[i], t[i], maxTexLevel, magFilt, texptr, texbufwidthbytes); } }