mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-14 15:00:30 +02:00
Merge pull request #22430 from hrydgard/light-exponent
GPU: Saturate the lighting pow's exponent below 512, as the GE does
This commit is contained in:
7 files changed
+28
-15
No files matched your search
@@ -223,7 +223,7 @@ void LightUpdateUniforms(UB_VS_Lights *ub, uint64_t dirtyUniforms) {
|
||||
Uint8x3ToFloat4(ub->materialDiffuse, gstate.materialdiffuse);
|
||||
}
|
||||
if (dirtyUniforms & DIRTY_MATSPECULAR) {
|
||||
Uint8x3ToFloat4_Alpha(ub->materialSpecular, gstate.materialspecular, std::max(0.0f, PSPSpecularCoef(getFloat24(gstate.materialspecularcoef))));
|
||||
Uint8x3ToFloat4_Alpha(ub->materialSpecular, gstate.materialspecular, std::max(0.0f, PSPLightExponent(getFloat24(gstate.materialspecularcoef))));
|
||||
}
|
||||
if (dirtyUniforms & DIRTY_MATEMISSIVE) {
|
||||
// We're not touching the fourth f32 here, because we store an u32 of control bits in it.
|
||||
@@ -243,7 +243,7 @@ void LightUpdateUniforms(UB_VS_Lights *ub, uint64_t dirtyUniforms) {
|
||||
// ldir is only used for spotlights. Prenormalize it.
|
||||
ExpandFloat24x3ToFloat4AndNormalize(ub->ldir[i], &gstate.ldir[i * 3]);
|
||||
ExpandFloat24x3ToFloat4(ub->latt[i], &gstate.latt[i * 3]);
|
||||
float lightAngle_spotCoef[2] = { getFloat24(gstate.lcutoff[i]), getFloat24(gstate.lconv[i]) };
|
||||
float lightAngle_spotCoef[2] = { getFloat24(gstate.lcutoff[i]), PSPLightExponent(getFloat24(gstate.lconv[i])) };
|
||||
CopyFloat2To4(ub->lightAngle_SpotCoef[i], lightAngle_spotCoef);
|
||||
Uint8x3ToFloat4(ub->lightAmbient[i], gstate.lcolor[i * 3]);
|
||||
Uint8x3ToFloat4(ub->lightDiffuse[i], gstate.lcolor[i * 3 + 1]);
|
||||
|
||||
@@ -40,14 +40,14 @@ Lighter::Lighter(int vertType) {
|
||||
materialDiffuse.a = 1.0f;
|
||||
materialSpecular.GetFromRGB(gstate.materialspecular);
|
||||
materialSpecular.a = 1.0f;
|
||||
specCoef_ = PSPSpecularCoef(getFloat24(gstate.materialspecularcoef));
|
||||
specCoef_ = PSPLightExponent(getFloat24(gstate.materialspecularcoef));
|
||||
viewDir_ = PSPViewDirection(gstate.viewMatrix);
|
||||
bool hasColor = (vertType & GE_VTYPE_COL_MASK) != 0;
|
||||
materialUpdate_ = hasColor ? (gstate.materialupdate & 7) : 0;
|
||||
|
||||
for (int l = 0; l < 4; l++) {
|
||||
lcutoff[l] = getFloat24(gstate.lcutoff[l]);
|
||||
lconv[l] = getFloat24(gstate.lconv[l]);
|
||||
lconv[l] = PSPLightExponent(getFloat24(gstate.lconv[l]));
|
||||
int i = l * 3;
|
||||
if (gstate.isLightChanEnabled(l)) {
|
||||
lpos[l] = Vec3fFromGE(&gstate.lpos[i]);
|
||||
|
||||
@@ -81,8 +81,15 @@ inline float PSPLightPow(float x, float e) {
|
||||
return y;
|
||||
}
|
||||
|
||||
// The GE only uses the top 4 bits of the specular coefficient's mantissa.
|
||||
inline float PSPSpecularCoef(float e) {
|
||||
// The exponent of the GE's lighting pow (specular and spot): the top 4 bits of the mantissa, truncated, and
|
||||
// saturated below 512, so 512 and up, infinity and NaN all act as 496 (gpu/probe exp221-223).
|
||||
inline float PSPLightExponent(float e) {
|
||||
if (std::isnan(e)) {
|
||||
return std::signbit(e) ? 0.0f : 496.0f;
|
||||
}
|
||||
if (e >= 512.0f) {
|
||||
return 496.0f;
|
||||
}
|
||||
u32 bits;
|
||||
memcpy(&bits, &e, sizeof(bits));
|
||||
bits &= 0xFFF80000;
|
||||
|
||||
@@ -440,7 +440,8 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
|
||||
// pow is close enough.
|
||||
WRITE(p, "float pspPow(float x, float e) {\n");
|
||||
if (compat.bitwiseOps) {
|
||||
WRITE(p, " float t = max(e, 0.0) * float(floatBitsToInt(max(x, 1e-30)) - 0x3F800000) + 1065353216.0;\n");
|
||||
// 1065353216 is 1.0's bits. Not written in hex: HLSL makes 0x3F800000 a uint, and the subtraction wraps.
|
||||
WRITE(p, " float t = max(e, 0.0) * float(floatBitsToInt(max(x, 1e-30)) - 1065353216) + 1065353216.0;\n");
|
||||
WRITE(p, " return x > 0.0 || e <= 0.0 ? intBitsToFloat(int(max(t, 0.0))) : 0.0;\n");
|
||||
} else {
|
||||
WRITE(p, " return e <= 0.0 ? 1.0 : pow(max(x, 0.0), e);\n");
|
||||
|
||||
@@ -550,7 +550,7 @@ void LinkedShader::UpdateUniforms(const ShaderID &vsid, const ShaderLanguageDesc
|
||||
SetColorUniform3(render_, &u_matemissive, gstate.materialemissive);
|
||||
}
|
||||
if (dirty & DIRTY_MATSPECULAR) {
|
||||
SetColorUniform3ExtraFloat(render_, &u_matspecular, gstate.materialspecular, PSPSpecularCoef(getFloat24(gstate.materialspecularcoef)));
|
||||
SetColorUniform3ExtraFloat(render_, &u_matspecular, gstate.materialspecular, PSPLightExponent(getFloat24(gstate.materialspecularcoef)));
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
@@ -564,7 +564,7 @@ void LinkedShader::UpdateUniforms(const ShaderID &vsid, const ShaderLanguageDesc
|
||||
if (u_lightdir[i] != -1) SetFloat24Uniform3Normalized(render_, &u_lightdir[i], &gstate.ldir[i * 3]);
|
||||
if (u_lightatt[i] != -1) SetFloat24Uniform3(render_, &u_lightatt[i], &gstate.latt[i * 3]);
|
||||
if (u_lightangle_spotCoef[i] != -1) {
|
||||
float lightangle_spotCoef[2] = { getFloat24(gstate.lcutoff[i]), getFloat24(gstate.lconv[i]) };
|
||||
float lightangle_spotCoef[2] = { getFloat24(gstate.lcutoff[i]), PSPLightExponent(getFloat24(gstate.lconv[i])) };
|
||||
SetFloatUniform2(render_, &u_lightangle_spotCoef[i], lightangle_spotCoef);
|
||||
}
|
||||
if (u_lightambient[i] != -1) SetColorUniform3(render_, &u_lightambient[i], gstate.lcolor[i * 3]);
|
||||
|
||||
@@ -141,11 +141,9 @@ void ComputeState(State *state, bool hasColor0) {
|
||||
if (std::isnan(lstate.spotCutoff) && std::signbit(lstate.spotCutoff))
|
||||
lstate.spotCutoff = 0.0f;
|
||||
|
||||
lstate.spotExp = getFloat24(gstate.lconv[light]);
|
||||
lstate.spotExp = PSPLightExponent(getFloat24(gstate.lconv[light]));
|
||||
if (lstate.spotExp <= 0.0f)
|
||||
lstate.spotExp = 0.0f;
|
||||
else if (std::isnan(lstate.spotExp))
|
||||
lstate.spotExp = std::signbit(lstate.spotExp) ? 0.0f : INFINITY;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,11 +179,9 @@ void ComputeState(State *state, bool hasColor0) {
|
||||
}
|
||||
|
||||
if (anyDiffuse || anySpecular) {
|
||||
state->specularExp = PSPSpecularCoef(gstate.getMaterialSpecularCoef());
|
||||
state->specularExp = PSPLightExponent(gstate.getMaterialSpecularCoef());
|
||||
if (state->specularExp <= 0.0f)
|
||||
state->specularExp = 0.0f;
|
||||
else if (std::isnan(state->specularExp))
|
||||
state->specularExp = std::signbit(state->specularExp) ? 0.0f : INFINITY;
|
||||
}
|
||||
|
||||
state->baseAmbientColorFactor = LightColorFactor(gstate.getAmbientRGBA(), ones);
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#include "GPU/Common/TransformCommon.h"
|
||||
#include "GPU/Software/GEMath.h"
|
||||
|
||||
#include "unittest/UnitTest.h"
|
||||
@@ -166,6 +167,14 @@ static bool TestGELightPow() {
|
||||
// multiply gives 0x3DA64400, and flooring 0x3F69FFFC (one step lower in the 8-bit factor, exp102).
|
||||
EXPECT_EQ_HEX(ToBits(GELightPow(FromBits(0x3DC22200), 1.0625f)), 0x3DA64420U);
|
||||
EXPECT_EQ_HEX(ToBits(GELightPow(FromBits(0x3F35E500), 0.296875f)), 0x3F6A0000U);
|
||||
// The exponent keeps 5 significant bits, truncated, and saturates below 512 (exp221-223).
|
||||
EXPECT_EQ_FLOAT(PSPLightExponent(127.0f), 124.0f);
|
||||
EXPECT_EQ_FLOAT(PSPLightExponent(150.0f), 144.0f);
|
||||
EXPECT_EQ_FLOAT(PSPLightExponent(511.0f), 496.0f);
|
||||
EXPECT_EQ_FLOAT(PSPLightExponent(512.0f), 496.0f);
|
||||
EXPECT_EQ_FLOAT(PSPLightExponent(INFINITY), 496.0f);
|
||||
EXPECT_EQ_FLOAT(PSPLightExponent(NAN), 496.0f);
|
||||
EXPECT_EQ_FLOAT(PSPLightExponent(-2.0f), -2.0f);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user