From 36b393f2cd111e31163dc2f9e65e9a1c99130312 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 22 Dec 2024 18:21:40 +0100 Subject: [PATCH 1/3] Enable depth raster for Armored Core: Silent line See #17597. Also improve some comments. --- assets/compat.ini | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/assets/compat.ini b/assets/compat.ini index 7a92401f4b..5142e67d16 100644 --- a/assets/compat.ini +++ b/assets/compat.ini @@ -1636,7 +1636,7 @@ ULJM05216 = true NPJH50181 = true [SoftwareRasterDepth] -# Midnight Club: LA Remix +# Midnight Club: LA Remix (see #18625) ULUS10383 = true ULES01144 = true ULJS00180 = true @@ -1644,13 +1644,13 @@ ULJS00267 = true ULJM05904 = true NPJH50440 = true -# Syphon Filter - Dark Mirror +# Syphon Filter - Dark Mirror (light flares, see #10229) UCES00310 = true UCUS98641 = true UCUS98656 = true UCUS98656 = true # Demo -# Syphon Filter - Logan's Shadow +# Syphon Filter - Logan's Shadow (light flares, see #10229) UCUS98606 = true UCES00710 = true NPUG80173 = true @@ -1663,7 +1663,7 @@ SYPH04036 = true # Prototype? NPUG80114 = true NPEG00004 = true -# Wipeout Pure +# Wipeout Pure (see #13344, sun lens flare) UCUS98612 = true UCJS10007 = true UCES00001 = true @@ -1675,7 +1675,14 @@ UCES01184 = true UCUS98668 = true UCJP00174 = true +# Armored Core: Silent Line (see #17597) +ULJM05552 = true +UCAS40289 = true +NPUH10025 = true +NPEH00047 = true + [ReadbackDepth] +# Obsolete, SoftwareRasterDepth is a far better solution. [BlockTransferDepth] # Iron Man - see issue #16530 From 8e747dc948e728523c331840a3e55d768715eeb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 22 Dec 2024 18:53:10 +0100 Subject: [PATCH 2/3] CrossSIMD: Add a multiply-as-16bit function to Vec4S32. This can be implemented quickly on SSE2. --- Common/Math/CrossSIMD.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Common/Math/CrossSIMD.h b/Common/Math/CrossSIMD.h index 4f0c48cbe2..89f0acf979 100644 --- a/Common/Math/CrossSIMD.h +++ b/Common/Math/CrossSIMD.h @@ -45,6 +45,17 @@ struct Vec4S32 { }; } + // Reads 16 bits from both operands, produces a 32-bit result per lane. + // On SSE2, much faster than _mm_mullo_epi32_SSE2. + // On NEON though, it'll read the full 32 bits, so beware. + // See https://fgiesen.wordpress.com/2016/04/03/sse-mind-the-gap/. + Vec4S32 MulAsS16(Vec4S32 other) const { + // Note that we only need to mask one of the inputs, so we get zeroes - multiplying + // by zero is zero, so it doesn't matter what the upper halfword of each 32-bit word is + // in the other register. + return Vec4S32{ _mm_madd_epi16(v, _mm_and_si128(other.v, _mm_set1_epi32(0x0000FFFF))) }; + } + Vec4S32 operator +(Vec4S32 other) const { return Vec4S32{ _mm_add_epi32(v, other.v) }; } Vec4S32 operator -(Vec4S32 other) const { return Vec4S32{ _mm_sub_epi32(v, other.v) }; } Vec4S32 operator |(Vec4S32 other) const { return Vec4S32{ _mm_or_si128(v, other.v) }; } @@ -222,6 +233,9 @@ struct Vec4S32 { return Vec4S32{ vcombine_s32(lowerSwapped, upper) }; }; + // Warning: Unlike on x86, this is a full 32-bit multiplication. + Vec4S32 MulAsS16(Vec4S32 other) const { return Vec4S32{ vmulq_s32(v, other.v) }; } + Vec4S32 operator +(Vec4S32 other) const { return Vec4S32{ vaddq_s32(v, other.v) }; } Vec4S32 operator -(Vec4S32 other) const { return Vec4S32{ vsubq_s32(v, other.v) }; } Vec4S32 operator *(Vec4S32 other) const { return Vec4S32{ vmulq_s32(v, other.v) }; } @@ -269,6 +283,7 @@ struct Vec4F32 { Vec4F32 operator *(float f) const { return Vec4F32{ vmulq_f32(v, vdupq_n_f32(f)) }; } Vec4F32 Mul(float f) const { return Vec4F32{ vmulq_f32(v, vdupq_n_f32(f)) }; } + Vec4F32 Recip() { float32x4_t recip = vrecpeq_f32(v); // Use a couple Newton-Raphson steps to refine the estimate. From b39a09e87b9cff1cb649028614dee9406270b4af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 22 Dec 2024 19:23:39 +0100 Subject: [PATCH 3/3] Specialize DepthRasterTriangle for the comparison modes using templating. --- GPU/Common/DepthRaster.cpp | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/GPU/Common/DepthRaster.cpp b/GPU/Common/DepthRaster.cpp index cfddf524c8..4f000c884b 100644 --- a/GPU/Common/DepthRaster.cpp +++ b/GPU/Common/DepthRaster.cpp @@ -60,9 +60,13 @@ void DepthRasterRect(uint16_t *dest, int stride, int x1, int y1, int x2, int y2, ptr += 8; w -= 8; } + // Non-simd trailer. + while (w > 0) { + *ptr++ = depthValue; + w--; + } } break; - // TODO: Trailer default: // TODO break; @@ -111,7 +115,8 @@ constexpr int MIN_TRI_AREA = 10; // Adapted from Intel's depth rasterizer example. // Started with the scalar version, will SIMD-ify later. // x1/y1 etc are the scissor rect. -TriangleResult DepthRasterTriangle(uint16_t *depthBuf, int stride, int x1, int y1, int x2, int y2, const int *tx, const int *ty, const float *tz, ZCompareMode compareMode) { +template +TriangleResult DepthRasterTriangle(uint16_t *depthBuf, int stride, int x1, int y1, int x2, int y2, const int *tx, const int *ty, const float *tz) { int tileStartX = x1; int tileEndX = x2; @@ -190,7 +195,7 @@ TriangleResult DepthRasterTriangle(uint16_t *depthBuf, int stride, int x1, int y Vec4U16 shortZ = Vec4U16::FromVec4F32(zs); - // TODO: Lift this switch out of the inner loop, or even out of the function with templating. + // This switch is on a templated constant, so should collapse away. switch (compareMode) { case ZCompareMode::Greater: // To implement the greater/greater-than comparison, we can combine mask and max. @@ -479,9 +484,25 @@ void DepthRasterScreenVerts(uint16_t *depth, int depthStride, GEPrimitiveType pr case GE_PRIM_TRIANGLES: { int stats[4]{}; - for (int i = 0; i < count; i += 3) { - TriangleResult result = DepthRasterTriangle(depth, depthStride, x1, y1, x2, y2, &tx[i], &ty[i], &tz[i], comp); - stats[(int)result]++; + switch (comp) { + case ZCompareMode::Greater: + for (int i = 0; i < count; i += 3) { + TriangleResult result = DepthRasterTriangle(depth, depthStride, x1, y1, x2, y2, &tx[i], &ty[i], &tz[i]); + stats[(int)result]++; + } + break; + case ZCompareMode::Less: + for (int i = 0; i < count; i += 3) { + TriangleResult result = DepthRasterTriangle(depth, depthStride, x1, y1, x2, y2, &tx[i], &ty[i], &tz[i]); + stats[(int)result]++; + } + break; + case ZCompareMode::Always: + for (int i = 0; i < count; i += 3) { + TriangleResult result = DepthRasterTriangle(depth, depthStride, x1, y1, x2, y2, &tx[i], &ty[i], &tz[i]); + stats[(int)result]++; + } + break; } gpuStats.numDepthRasterBackface += stats[(int)TriangleResult::Backface]; gpuStats.numDepthRasterNoPixels += stats[(int)TriangleResult::NoPixels];