From 59fb374c3835d306adad0acb8de9c1687891a63a Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 16 Apr 2023 10:15:42 -0700 Subject: [PATCH 1/5] softgpu: Small optimization to clut updates. --- GPU/Software/BinManager.cpp | 5 +++-- GPU/Software/BinManager.h | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/GPU/Software/BinManager.cpp b/GPU/Software/BinManager.cpp index e8ce567fb2..68d95a156c 100644 --- a/GPU/Software/BinManager.cpp +++ b/GPU/Software/BinManager.cpp @@ -368,8 +368,9 @@ void BinManager::UpdateClut(const void *src) { PROFILE_THIS_SCOPE("bin_clut"); if (cluts_.Full()) Flush("cluts"); - clutIndex_ = (uint16_t)cluts_.Push(BinClut()); - memcpy(cluts_[clutIndex_].readable, src, sizeof(BinClut)); + BinClut &clut = cluts_.PeekPush(); + memcpy(clut.readable, src, sizeof(BinClut)); + clutIndex_ = (uint16_t)cluts_.PushPeeked(); } void BinManager::AddTriangle(const VertexData &v0, const VertexData &v1, const VertexData &v2) { diff --git a/GPU/Software/BinManager.h b/GPU/Software/BinManager.h index 53db6435c2..a361ca414a 100644 --- a/GPU/Software/BinManager.h +++ b/GPU/Software/BinManager.h @@ -117,11 +117,12 @@ struct BinQueue { return items_[tail_]; } - void PushPeeked() { + size_t PushPeeked() { size_t i = tail_++; if (i + 1 == N) tail_ -= N; size_++; + return i; } size_t Size() const { From b5206df04ffedda86798a5574ecff6ebb43fe7dd Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 16 Apr 2023 10:16:32 -0700 Subject: [PATCH 2/5] softgpu: Calc worldnormal a bit less often. This is clearer anyway. --- GPU/Software/Lighting.cpp | 9 +++++++-- GPU/Software/Lighting.h | 2 ++ GPU/Software/TransformUnit.cpp | 11 ++++------- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/GPU/Software/Lighting.cpp b/GPU/Software/Lighting.cpp index e970fc9696..64a906844a 100644 --- a/GPU/Software/Lighting.cpp +++ b/GPU/Software/Lighting.cpp @@ -86,6 +86,7 @@ void ComputeState(State *state, bool hasColor0) { bool anyAmbient = false; bool anyDiffuse = false; bool anySpecular = false; + bool anyDirectional = false; for (int light = 0; light < 4; ++light) { auto &lstate = state->lights[light]; lstate.enabled = gstate.isLightChanEnabled(light); @@ -112,10 +113,12 @@ void ComputeState(State *state, bool hasColor0) { } lstate.pos = GetLightVec(gstate.lpos, light); - if (lstate.directional) + if (lstate.directional) { lstate.pos.NormalizeOr001(); - else + anyDirectional = true; + } else { lstate.att = GetLightVec(gstate.latt, light); + } if (lstate.spot) { lstate.spotDir = GetLightVec(gstate.ldir, light); @@ -174,6 +177,8 @@ void ComputeState(State *state, bool hasColor0) { state->baseAmbientColorFactor = LightColorFactor(gstate.getAmbientRGBA(), ones); state->setColor1 = gstate.isUsingSecondaryColor() && anySpecular; state->addColor1 = !gstate.isUsingSecondaryColor() && anySpecular; + state->usesWorldPos = anyDirectional; + state->usesWorldNormal = gstate.getUVGenMode() == GE_TEXMAP_ENVIRONMENT_MAP || anyDiffuse || anySpecular; } static inline float GenerateLightCoord(VertexData &vertex, const WorldCoords &worldnormal, int light) { diff --git a/GPU/Software/Lighting.h b/GPU/Software/Lighting.h index 9a89d2fa9f..c875aae08b 100644 --- a/GPU/Software/Lighting.h +++ b/GPU/Software/Lighting.h @@ -60,6 +60,8 @@ struct State { bool colorForSpecular : 1; bool setColor1 : 1; bool addColor1 : 1; + bool usesWorldPos : 1; + bool usesWorldNormal : 1; }; }; diff --git a/GPU/Software/TransformUnit.cpp b/GPU/Software/TransformUnit.cpp index f17f12cf19..da8469779a 100644 --- a/GPU/Software/TransformUnit.cpp +++ b/GPU/Software/TransformUnit.cpp @@ -273,12 +273,9 @@ void ComputeTransformState(TransformState *state, const VertexReader &vreader) { bool canSkipWorldPos = true; if (state->enableLighting) { Lighting::ComputeState(&state->lightingState, vreader.hasColor0()); - for (int i = 0; i < 4; ++i) { - if (!state->lightingState.lights[i].enabled) - continue; - if (!state->lightingState.lights[i].directional) - canSkipWorldPos = false; - } + canSkipWorldPos = !state->lightingState.usesWorldPos; + } else { + state->lightingState.usesWorldNormal = state->uvGenMode == GE_TEXMAP_ENVIRONMENT_MAP; } float world[16]; @@ -412,7 +409,7 @@ ClipVertexData TransformUnit::ReadVertex(const VertexReader &vreader, const Tran vertex.v.clipw = vertex.clippos.w; Vec3 worldnormal; - if (state.enableLighting || state.uvGenMode == GE_TEXMAP_ENVIRONMENT_MAP) { + if (state.lightingState.usesWorldNormal) { worldnormal = TransformUnit::ModelToWorldNormal(normal); worldnormal.NormalizeOr001(); } From 2868495cf89e09a148a1562b711e8a719fa250db Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 16 Apr 2023 10:54:25 -0700 Subject: [PATCH 3/5] softgpu: Use SSE for lighting ceil if available. Tiny optimization, helps only a little. --- GPU/Software/Lighting.cpp | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/GPU/Software/Lighting.cpp b/GPU/Software/Lighting.cpp index 64a906844a..0ae32d9994 100644 --- a/GPU/Software/Lighting.cpp +++ b/GPU/Software/Lighting.cpp @@ -197,6 +197,25 @@ void GenerateLightST(VertexData &vertex, const WorldCoords &worldnormal) { vertex.texturecoords.t() = GenerateLightCoord(vertex, worldnormal, gstate.getUVLS1()); } +#if defined(_M_SSE) +#if defined(__GNUC__) || defined(__clang__) || defined(__INTEL_COMPILER) +[[gnu::target("sse4.1")]] +#endif +static inline int LightCeilSSE4(float f) { + __m128 v = _mm_set_ss(f); + // This isn't terribly fast, but seems to be better than calling ceilf(). + return _mm_cvt_ss2si(_mm_ceil_ss(v, v)); +} +#endif + +static inline int LightCeil(float f) { +#if defined(_M_SSE) + if (cpu_info.bSSE4_1) + return LightCeilSSE4(f); +#endif + return (int)ceilf(f); +} + void Process(VertexData &vertex, const WorldCoords &worldpos, const WorldCoords &worldnormal, const State &state) { // Lighting blending rounds using the half offset method (like alpha blend.) const Vec4 ones = Vec4::AssignToAll(1); @@ -250,7 +269,7 @@ void Process(VertexData &vertex, const WorldCoords &worldpos, const WorldCoords // ambient lighting if (lstate.ambient) { - int attspot = (int)ceilf(256 * 2 * att * spot + 1); + int attspot = (int)LightCeil(256 * 2 * att * spot + 1); if (attspot > 512) attspot = 512; Vec4 lambient = (mac * lstate.ambientColorFactor * attspot) / (1024 * 512); @@ -267,7 +286,7 @@ void Process(VertexData &vertex, const WorldCoords &worldpos, const WorldCoords } if (lstate.diffuse && diffuse_factor > 0.0f) { - int diffuse_attspot = (int)ceilf(256 * 2 * att * spot * diffuse_factor + 1); + int diffuse_attspot = (int)LightCeil(256 * 2 * att * spot * diffuse_factor + 1); if (diffuse_attspot > 512) diffuse_attspot = 512; Vec4 mdc = state.colorForDiffuse ? colorFactor : state.material.diffuseColorFactor; @@ -282,7 +301,7 @@ void Process(VertexData &vertex, const WorldCoords &worldpos, const WorldCoords specular_factor = pspLightPow(specular_factor, state.specularExp); if (specular_factor > 0.0f) { - int specular_attspot = (int)ceilf(256 * 2 * att * spot * specular_factor + 1); + int specular_attspot = (int)LightCeil(256 * 2 * att * spot * specular_factor + 1); if (specular_attspot > 512) specular_attspot = 512; From 860fc176d8aa90487b50c32e85e31f6958687ad5 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 16 Apr 2023 11:58:30 -0700 Subject: [PATCH 4/5] softgpu: Use more SSE in lighting. --- GPU/Software/Lighting.cpp | 51 +++++++++++++++++++++++++++++++-------- 1 file changed, 41 insertions(+), 10 deletions(-) diff --git a/GPU/Software/Lighting.cpp b/GPU/Software/Lighting.cpp index 0ae32d9994..8c0aba529e 100644 --- a/GPU/Software/Lighting.cpp +++ b/GPU/Software/Lighting.cpp @@ -206,6 +206,17 @@ static inline int LightCeilSSE4(float f) { // This isn't terribly fast, but seems to be better than calling ceilf(). return _mm_cvt_ss2si(_mm_ceil_ss(v, v)); } + +#if defined(__GNUC__) || defined(__clang__) || defined(__INTEL_COMPILER) +[[gnu::target("sse4.1")]] +#endif +static inline __m128i LightColorScaleBy512SSE4(__m128i factor, __m128i color, __m128i scale) { + // We can use 16-bit multiply here (faster than 32-bit multiply) since our top bits are zero. + __m128i result18 = _mm_madd_epi16(factor, color); + // But now with 18 bits, we need a full multiply. + __m128i multiplied = _mm_mullo_epi32(result18, scale); + return _mm_srai_epi32(multiplied, 19); +} #endif static inline int LightCeil(float f) { @@ -216,6 +227,25 @@ static inline int LightCeil(float f) { return (int)ceilf(f); } +static Vec4 LightColorScaleBy512(const Vec4 &factor, const Vec4 &color, int scale) { + // We multiply s9 * s9 * s9, resulting in s27, then shift off 19 to get 8-bit. + // The reason all factors are s9 is to account for rounding. + // Also note that all values are positive, so can be treated as unsigned. +#if defined(_M_SSE) && !PPSSPP_ARCH(X86) + if (cpu_info.bSSE4_1) + return LightColorScaleBy512SSE4(factor.ivec, color.ivec, _mm_set1_epi32(scale)); +#endif + return (factor * color * scale) / (1024 * 512); +} + +static inline void LightColorSum(Vec4 &sum, const Vec4 &src) { +#if defined(_M_SSE) && !PPSSPP_ARCH(X86) + sum.ivec = _mm_add_epi32(sum.ivec, src.ivec); +#else + sum += src; +#endif +} + void Process(VertexData &vertex, const WorldCoords &worldpos, const WorldCoords &worldnormal, const State &state) { // Lighting blending rounds using the half offset method (like alpha blend.) const Vec4 ones = Vec4::AssignToAll(1); @@ -272,8 +302,8 @@ void Process(VertexData &vertex, const WorldCoords &worldpos, const WorldCoords int attspot = (int)LightCeil(256 * 2 * att * spot + 1); if (attspot > 512) attspot = 512; - Vec4 lambient = (mac * lstate.ambientColorFactor * attspot) / (1024 * 512); - final_color += lambient; + Vec4 lambient = LightColorScaleBy512(lstate.ambientColorFactor, mac, attspot); + LightColorSum(final_color, lambient); } // diffuse lighting @@ -290,8 +320,8 @@ void Process(VertexData &vertex, const WorldCoords &worldpos, const WorldCoords if (diffuse_attspot > 512) diffuse_attspot = 512; Vec4 mdc = state.colorForDiffuse ? colorFactor : state.material.diffuseColorFactor; - Vec4 ldiffuse = (lstate.diffuseColorFactor * mdc * diffuse_attspot) / (1024 * 512); - final_color += ldiffuse; + Vec4 ldiffuse = LightColorScaleBy512(lstate.diffuseColorFactor, mdc, diffuse_attspot); + LightColorSum(final_color, ldiffuse); } if (lstate.specular && diffuse_factor >= 0.0f) { @@ -306,19 +336,20 @@ void Process(VertexData &vertex, const WorldCoords &worldpos, const WorldCoords specular_attspot = 512; Vec4 msc = state.colorForSpecular ? colorFactor : state.material.specularColorFactor; - Vec4 lspecular = (lstate.specularColorFactor * msc * specular_attspot) / (1024 * 512); - specular_color += lspecular; + Vec4 lspecular = LightColorScaleBy512(lstate.specularColorFactor, msc, specular_attspot); + LightColorSum(specular_color, lspecular); } } } + // Note: these are all naturally clamped by ToRGBA/toRGB. if (state.setColor1) { - vertex.color0 = final_color.Clamp(0, 255).ToRGBA(); - vertex.color1 = specular_color.Clamp(0, 255).rgb().ToRGB(); + vertex.color0 = final_color.ToRGBA(); + vertex.color1 = specular_color.rgb().ToRGB(); } else if (state.addColor1) { - vertex.color0 = (final_color + specular_color).Clamp(0, 255).ToRGBA(); + vertex.color0 = (final_color + specular_color).ToRGBA(); } else { - vertex.color0 = final_color.Clamp(0, 255).ToRGBA(); + vertex.color0 = final_color.ToRGBA(); } } From 0490ad00397fc86bf025816a7eab7eafb604aca6 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 16 Apr 2023 13:09:56 -0700 Subject: [PATCH 5/5] softgpu: Add NEON variants as well. --- GPU/Software/Lighting.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/GPU/Software/Lighting.cpp b/GPU/Software/Lighting.cpp index 8c0aba529e..1709db4889 100644 --- a/GPU/Software/Lighting.cpp +++ b/GPU/Software/Lighting.cpp @@ -223,6 +223,8 @@ static inline int LightCeil(float f) { #if defined(_M_SSE) if (cpu_info.bSSE4_1) return LightCeilSSE4(f); +#elif PPSSPP_ARCH(ARM64_NEON) + return vcvtps_s32_f32(f); #endif return (int)ceilf(f); } @@ -234,6 +236,9 @@ static Vec4 LightColorScaleBy512(const Vec4 &factor, const Vec4 & #if defined(_M_SSE) && !PPSSPP_ARCH(X86) if (cpu_info.bSSE4_1) return LightColorScaleBy512SSE4(factor.ivec, color.ivec, _mm_set1_epi32(scale)); +#elif PPSSPP_ARCH(ARM64_NEON) + int32x4_t multiplied = vmulq_n_s32(vmulq_s32(factor.ivec, color.ivec), scale); + return vshrq_n_s32(multiplied, 19); #endif return (factor * color * scale) / (1024 * 512); } @@ -241,6 +246,8 @@ static Vec4 LightColorScaleBy512(const Vec4 &factor, const Vec4 & static inline void LightColorSum(Vec4 &sum, const Vec4 &src) { #if defined(_M_SSE) && !PPSSPP_ARCH(X86) sum.ivec = _mm_add_epi32(sum.ivec, src.ivec); +#elif PPSSPP_ARCH(ARM64_NEON) + sum.ivec = vaddq_s32(sum.ivec, src.ivec); #else sum += src; #endif