From 797327eecdaf8d7597f9358bb9957cb3e08a8ef9 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 10 Sep 2018 00:27:16 -0700 Subject: [PATCH] GPU: Handle bad fog params as large signed vals. From tests, it seems they're just treated as valid exponents. Using 65535 since that's the range of depth, can't think of a game using a larger value for a fog parameter, probably never even this large. --- GPU/Common/ShaderUniforms.cpp | 22 ++++++++-------------- GPU/Common/SoftwareTransformCommon.cpp | 18 +++++++----------- GPU/Directx9/ShaderManagerDX9.cpp | 22 ++++++++-------------- GPU/GLES/ShaderManagerGLES.cpp | 24 +++++++++--------------- GPU/Software/TransformUnit.cpp | 15 +++++++++++++-- 5 files changed, 45 insertions(+), 56 deletions(-) diff --git a/GPU/Common/ShaderUniforms.cpp b/GPU/Common/ShaderUniforms.cpp index 21aee1ec1..e2dee45c2 100644 --- a/GPU/Common/ShaderUniforms.cpp +++ b/GPU/Common/ShaderUniforms.cpp @@ -1,4 +1,5 @@ #include +#include #include "ShaderUniforms.h" #include "base/display.h" @@ -119,22 +120,15 @@ void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool flipView getFloat24(gstate.fog1), getFloat24(gstate.fog2), }; - if (my_isinf(fogcoef[1])) { - // not really sure what a sensible value might be. - fogcoef[1] = fogcoef[1] < 0.0f ? -10000.0f : 10000.0f; - } else if (my_isnan(fogcoef[1])) { - // Workaround for https://github.com/hrydgard/ppsspp/issues/5384#issuecomment-38365988 - // Just put the fog far away at a large finite distance. - // Infinities and NaNs are rather unpredictable in shaders on many GPUs - // so it's best to just make it a sane calculation. - fogcoef[0] = 100000.0f; - fogcoef[1] = 1.0f; + // The PSP just ignores infnan here (ignoring IEEE), so take it down to a valid float. + // Workaround for https://github.com/hrydgard/ppsspp/issues/5384#issuecomment-38365988 + if (my_isnanorinf(fogcoef[0])) { + // Not really sure what a sensible value might be, but let's try 64k. + fogcoef[0] = std::signbit(fogcoef[0]) ? -65535.0f : 65535.0f; } -#ifndef MOBILE_DEVICE - else if (my_isnanorinf(fogcoef[1]) || my_isnanorinf(fogcoef[0])) { - ERROR_LOG_REPORT_ONCE(fognan, G3D, "Unhandled fog NaN/INF combo: %f %f", fogcoef[0], fogcoef[1]); + if (my_isnanorinf(fogcoef[1])) { + fogcoef[1] = std::signbit(fogcoef[1]) ? -65535.0f : 65535.0f; } -#endif CopyFloat2(ub->fogCoef, fogcoef); } diff --git a/GPU/Common/SoftwareTransformCommon.cpp b/GPU/Common/SoftwareTransformCommon.cpp index 93385d8aa..fc943993b 100644 --- a/GPU/Common/SoftwareTransformCommon.cpp +++ b/GPU/Common/SoftwareTransformCommon.cpp @@ -15,6 +15,7 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. +#include #include "math/math_util.h" #include "gfx_es2/gpu_features.h" @@ -181,18 +182,13 @@ void SoftwareTransform( Lighter lighter(vertType); float fog_end = getFloat24(gstate.fog1); float fog_slope = getFloat24(gstate.fog2); - // Same fixup as in ShaderManager.cpp - if (my_isinf(fog_slope)) { - // not really sure what a sensible value might be. - fog_slope = fog_slope < 0.0f ? -10000.0f : 10000.0f; + // Same fixup as in ShaderManagerGLES.cpp + if (my_isnanorinf(fog_end)) { + // Not really sure what a sensible value might be, but let's try 64k. + fog_end = std::signbit(fog_end) ? -65535.0f : 65535.0f; } - if (my_isnan(fog_slope)) { - // Workaround for https://github.com/hrydgard/ppsspp/issues/5384#issuecomment-38365988 - // Just put the fog far away at a large finite distance. - // Infinities and NaNs are rather unpredictable in shaders on many GPUs - // so it's best to just make it a sane calculation. - fog_end = 100000.0f; - fog_slope = 1.0f; + if (my_isnanorinf(fog_slope)) { + fog_slope = std::signbit(fog_slope) ? -65535.0f : 65535.0f; } int colorIndOffset = 0; diff --git a/GPU/Directx9/ShaderManagerDX9.cpp b/GPU/Directx9/ShaderManagerDX9.cpp index e91aa3e60..a10e56603 100644 --- a/GPU/Directx9/ShaderManagerDX9.cpp +++ b/GPU/Directx9/ShaderManagerDX9.cpp @@ -19,6 +19,7 @@ #define SHADERLOG #endif +#include #include #include "gfx/d3d9_shader.h" #include "base/logging.h" @@ -364,22 +365,15 @@ void ShaderManagerDX9::VSUpdateUniforms(u64 dirtyUniforms) { getFloat24(gstate.fog1), getFloat24(gstate.fog2), }; - if (my_isinf(fogcoef[1])) { - // not really sure what a sensible value might be. - fogcoef[1] = fogcoef[1] < 0.0f ? -10000.0f : 10000.0f; - } else if (my_isnan(fogcoef[1])) { - // Workaround for https://github.com/hrydgard/ppsspp/issues/5384#issuecomment-38365988 - // Just put the fog far away at a large finite distance. - // Infinities and NaNs are rather unpredictable in shaders on many GPUs - // so it's best to just make it a sane calculation. - fogcoef[0] = 100000.0f; - fogcoef[1] = 1.0f; + // The PSP just ignores infnan here (ignoring IEEE), so take it down to a valid float. + // Workaround for https://github.com/hrydgard/ppsspp/issues/5384#issuecomment-38365988 + if (my_isnanorinf(fogcoef[0])) { + // Not really sure what a sensible value might be, but let's try 64k. + fogcoef[0] = std::signbit(fogcoef[0]) ? -65535.0f : 65535.0f; } -#ifndef MOBILE_DEVICE - else if (my_isnanorinf(fogcoef[1]) || my_isnanorinf(fogcoef[0])) { - ERROR_LOG_REPORT_ONCE(fognan, G3D, "Unhandled fog NaN/INF combo: %f %f", fogcoef[0], fogcoef[1]); + if (my_isnanorinf(fogcoef[1])) { + fogcoef[1] = std::signbit(fogcoef[1]) ? -65535.0f : 65535.0f; } -#endif VSSetFloatArray(CONST_VS_FOGCOEF, fogcoef, 2); } // TODO: Could even set all bones in one go if they're all dirty. diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index 703b823cb..484819332 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -19,8 +19,9 @@ #include "Common/CommonWindows.h" #endif -#include +#include #include +#include #include "math/dataconv.h" #include "base/logging.h" @@ -383,22 +384,15 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid) { getFloat24(gstate.fog1), getFloat24(gstate.fog2), }; - if (my_isinf(fogcoef[1])) { - // not really sure what a sensible value might be. - fogcoef[1] = fogcoef[1] < 0.0f ? -10000.0f : 10000.0f; - } else if (my_isnan(fogcoef[1])) { - // Workaround for https://github.com/hrydgard/ppsspp/issues/5384#issuecomment-38365988 - // Just put the fog far away at a large finite distance. - // Infinities and NaNs are rather unpredictable in shaders on many GPUs - // so it's best to just make it a sane calculation. - fogcoef[0] = 100000.0f; - fogcoef[1] = 1.0f; + // The PSP just ignores infnan here (ignoring IEEE), so take it down to a valid float. + // Workaround for https://github.com/hrydgard/ppsspp/issues/5384#issuecomment-38365988 + if (my_isnanorinf(fogcoef[0])) { + // Not really sure what a sensible value might be, but let's try 64k. + fogcoef[0] = std::signbit(fogcoef[0]) ? -65535.0f : 65535.0f; } -#ifndef MOBILE_DEVICE - else if (my_isnanorinf(fogcoef[1]) || my_isnanorinf(fogcoef[0])) { - ERROR_LOG_REPORT_ONCE(fognan, G3D, "Unhandled fog NaN/INF combo: %f %f", fogcoef[0], fogcoef[1]); + if (my_isnanorinf(fogcoef[1])) { + fogcoef[1] = std::signbit(fogcoef[1]) ? -65535.0f : 65535.0f; } -#endif render_->SetUniformF(&u_fogcoef, 2, fogcoef); } diff --git a/GPU/Software/TransformUnit.cpp b/GPU/Software/TransformUnit.cpp index 1d9eef5a1..e31d062de 100644 --- a/GPU/Software/TransformUnit.cpp +++ b/GPU/Software/TransformUnit.cpp @@ -15,6 +15,8 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. +#include +#include "math/math_util.h" #include "Common/MemoryUtil.h" #include "Core/Config.h" #include "GPU/GPUState.h" @@ -216,8 +218,17 @@ VertexData TransformUnit::ReadVertex(VertexReader& vreader) ModelCoords viewpos = TransformUnit::WorldToView(vertex.worldpos); vertex.clippos = ClipCoords(TransformUnit::ViewToClip(viewpos)); if (gstate.isFogEnabled()) { - // TODO: Validate inf/nan. - vertex.fogdepth = (viewpos.z + getFloat24(gstate.fog1)) * getFloat24(gstate.fog2); + float fog_end = getFloat24(gstate.fog1); + float fog_slope = getFloat24(gstate.fog2); + // Same fixup as in ShaderManagerGLES.cpp + if (my_isnanorinf(fog_end)) { + // Not really sure what a sensible value might be, but let's try 64k. + fog_end = std::signbit(fog_end) ? -65535.0f : 65535.0f; + } + if (my_isnanorinf(fog_slope)) { + fog_slope = std::signbit(fog_slope) ? -65535.0f : 65535.0f; + } + vertex.fogdepth = (viewpos.z + fog_end) * fog_slope; } else { vertex.fogdepth = 1.0f; }