From 78eb1829d8343dac7398d52a9e13ad0874dad184 Mon Sep 17 00:00:00 2001 From: Flyinghead Date: Thu, 14 Nov 2019 22:10:40 +0100 Subject: [PATCH] gles2: calculate fog depth in vertex shader in case highp not supported Mali-400/450 don't support highp floats in the fragment shader. This causes overflows when computing fog density in some game scenes. To work around that, calculate fog density in vertex shader and use interpolation. vulkan,gl: Get rid of extra_depth_scale in fragment shader by integrating it in fog density --- core/rend/gl4/gl4.h | 5 --- core/rend/gl4/gles.cpp | 9 ++---- core/rend/gles/gles.cpp | 55 ++++++++++++++++++++------------ core/rend/gles/gles.h | 8 ++--- core/rend/vulkan/drawer.h | 25 +++++++-------- core/rend/vulkan/oit_pipeline.h | 1 - core/rend/vulkan/oit_shaders.cpp | 3 +- core/rend/vulkan/shaders.cpp | 3 +- core/rend/vulkan/shaders.h | 1 - 9 files changed, 52 insertions(+), 58 deletions(-) diff --git a/core/rend/gl4/gl4.h b/core/rend/gl4/gl4.h index 126e81c39..8e8908843 100755 --- a/core/rend/gl4/gl4.h +++ b/core/rend/gl4/gl4.h @@ -8,7 +8,6 @@ struct gl4PipelineShader { GLuint program; - GLuint extra_depth_scale; GLuint pp_ClipTest,cp_AlphaTestValue; GLuint sp_FOG_COL_RAM,sp_FOG_COL_VERT,sp_FOG_DENSITY; GLuint shade_scale_factor; @@ -225,7 +224,6 @@ void gl4SetupModvolVBO(); extern struct gl4ShaderUniforms_t { float PT_ALPHA; - float extra_depth_scale; float fog_den_float; float ps_FOG_COL_RAM[3]; float ps_FOG_COL_VERT[3]; @@ -250,9 +248,6 @@ extern struct gl4ShaderUniforms_t if (s->cp_AlphaTestValue!=-1) glUniform1f(s->cp_AlphaTestValue,PT_ALPHA); - if (s->extra_depth_scale != -1) - glUniform1f(s->extra_depth_scale, extra_depth_scale); - if (s->sp_FOG_DENSITY!=-1) glUniform1f( s->sp_FOG_DENSITY,fog_den_float); diff --git a/core/rend/gl4/gles.cpp b/core/rend/gl4/gles.cpp index e7094d638..6ed40fd23 100644 --- a/core/rend/gl4/gles.cpp +++ b/core/rend/gl4/gles.cpp @@ -120,7 +120,6 @@ uniform int shading_instr[2]; uniform int fog_control[2]; #endif -uniform highp float extra_depth_scale; /* Vertex input*/ INTERPOLATION in lowp vec4 vtx_base; INTERPOLATION in lowp vec4 vtx_offs; @@ -131,7 +130,7 @@ INTERPOLATION in lowp vec4 vtx_offs1; lowp float fog_mode2(highp float w) { - highp float z = clamp(w * extra_depth_scale * sp_FOG_DENSITY, 1.0, 255.9999); + highp float z = clamp(w * sp_FOG_DENSITY, 1.0, 255.9999); highp float exp = floor(log2(z)); highp float m = z * 16.0 / pow(2.0, exp) - 16.0; float idx = floor(m) + exp * 16.0 + 0.5; @@ -421,8 +420,6 @@ bool gl4CompilePipelineShader( gl4PipelineShader* s, const char *pixel_source /* glUniform1i(gu, 1); //get the uniform locations - s->extra_depth_scale = glGetUniformLocation(s->program, "extra_depth_scale"); - s->pp_ClipTest = glGetUniformLocation(s->program, "pp_ClipTest"); s->sp_FOG_DENSITY = glGetUniformLocation(s->program, "sp_FOG_DENSITY"); @@ -670,8 +667,6 @@ static bool RenderFrame() } resize(rendering_width, rendering_height); - gl4ShaderUniforms.extra_depth_scale = settings.rend.ExtraDepthScale; - //DEBUG_LOG(RENDERER, "scale: %f, %f, %f, %f", gl4ShaderUniforms.scale_coefs[0], gl4ShaderUniforms.scale_coefs[1], gl4ShaderUniforms.scale_coefs[2], gl4ShaderUniforms.scale_coefs[3]); //VERT and RAM fog color constants @@ -689,7 +684,7 @@ static bool RenderFrame() u8* fog_density=(u8*)&FOG_DENSITY; float fog_den_mant=fog_density[1]/128.0f; //bit 7 -> x. bit, so [6:0] -> fraction -> /128 s32 fog_den_exp=(s8)fog_density[0]; - gl4ShaderUniforms.fog_den_float=fog_den_mant*powf(2.0f,fog_den_exp); + gl4ShaderUniforms.fog_den_float = fog_den_mant * powf(2.0f,fog_den_exp) * settings.rend.ExtraDepthScale; gl4ShaderUniforms.fog_clamp_min[0] = ((pvrrc.fog_clamp_min >> 16) & 0xFF) / 255.0f; gl4ShaderUniforms.fog_clamp_min[1] = ((pvrrc.fog_clamp_min >> 8) & 0xFF) / 255.0f; diff --git a/core/rend/gles/gles.cpp b/core/rend/gles/gles.cpp index de264ec9a..d0c32cb43 100644 --- a/core/rend/gles/gles.cpp +++ b/core/rend/gles/gles.cpp @@ -57,9 +57,10 @@ const char* VertexShaderSource = R"( #endif /* Vertex constants*/ -uniform highp vec4 scale; uniform highp vec4 depth_scale; uniform highp mat4 normal_matrix; +uniform highp float sp_FOG_DENSITY; + /* Vertex input */ in highp vec4 in_pos; in lowp vec4 in_base; @@ -69,6 +70,9 @@ in mediump vec2 in_uv; INTERPOLATION out lowp vec4 vtx_base; INTERPOLATION out lowp vec4 vtx_offs; out mediump vec2 vtx_uv; +#if TARGET_GL == GLES2 + out highp float fog_depth; +#endif void main() { vtx_base = in_base; @@ -86,7 +90,8 @@ void main() #if TARGET_GL != GLES2 vpos.z = vpos.w; #else - vpos.z = depth_scale.x + depth_scale.y * vpos.w; + fog_depth = vpos.z * sp_FOG_DENSITY; + vpos.z = depth_scale.x + depth_scale.y * vpos.w; #endif vpos.xy *= vpos.w; gl_Position = vpos; @@ -136,7 +141,6 @@ out highp vec4 FragColor; #define FOG_CHANNEL a #endif - #if TARGET_GL == GL3 || TARGET_GL == GLES3 #if pp_Gouraud == 0 #define INTERPOLATION flat @@ -157,18 +161,24 @@ uniform sampler2D tex,fog_table; uniform lowp float trilinear_alpha; uniform lowp vec4 fog_clamp_min; uniform lowp vec4 fog_clamp_max; -uniform highp float extra_depth_scale; /* Vertex input*/ INTERPOLATION in lowp vec4 vtx_base; INTERPOLATION in lowp vec4 vtx_offs; in mediump vec2 vtx_uv; +#if TARGET_GL == GLES2 + in highp float fog_depth; +#endif lowp float fog_mode2(highp float w) { - highp float z = clamp(w * extra_depth_scale * sp_FOG_DENSITY, 1.0, 255.9999); - highp float exp = floor(log2(z)); +#if TARGET_GL == GLES2 + highp float z = clamp(fog_depth, 1.0, 255.9999); +#else + highp float z = clamp(w * sp_FOG_DENSITY, 1.0, 255.9999); +#endif + mediump float exp = floor(log2(z)); highp float m = z * 16.0 / pow(2.0, exp) - 16.0; - lowp float idx = floor(m) + exp * 16.0 + 0.5; + mediump float idx = floor(m) + exp * 16.0 + 0.5; highp vec4 fog_coef = texture(fog_table, vec2(idx / 128.0, 0.75 - (m - floor(m)) / 2.0)); return fog_coef.FOG_CHANNEL; } @@ -432,7 +442,7 @@ void do_swap_automation() static void gl_delete_shaders() { - for (auto it : gl.shaders) + for (const auto& it : gl.shaders) { if (it.second.program != 0) glcache.DeleteProgram(it.second.program); @@ -505,6 +515,10 @@ void findGLVersion() gl.fog_image_format = GL_ALPHA; } } + GLint ranges[2]; + GLint precision; + glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_HIGH_FLOAT, ranges, &precision); + gl.highp_float_supported = (ranges[0] != 0 || ranges[1] != 0) && precision != 0; } struct ShaderUniforms_t ShaderUniforms; @@ -639,14 +653,16 @@ bool CompilePipelineShader( PipelineShader* s) { char vshader[8192]; - sprintf(vshader, VertexShaderSource, gl.glsl_version_header, gl.gl_version, s->pp_Gouraud); + int rc = sprintf(vshader, VertexShaderSource, gl.glsl_version_header, gl.gl_version, s->pp_Gouraud); + verify(rc + 1 <= sizeof(vshader)); char pshader[8192]; - sprintf(pshader,PixelPipelineShader, gl.glsl_version_header, gl.gl_version, + rc = sprintf(pshader,PixelPipelineShader, gl.glsl_version_header, gl.gl_version, s->cp_AlphaTest,s->pp_ClipTestMode,s->pp_UseAlpha, s->pp_Texture,s->pp_IgnoreTexA,s->pp_ShadInstr,s->pp_Offset,s->pp_FogCtrl, s->pp_Gouraud, s->pp_BumpMap, s->fog_clamping, s->trilinear); + verify(rc + 1 <= sizeof(pshader)); s->program=gl_CompileAndLink(vshader, pshader); @@ -658,7 +674,6 @@ bool CompilePipelineShader( PipelineShader* s) //get the uniform locations s->depth_scale = glGetUniformLocation(s->program, "depth_scale"); - s->extra_depth_scale = glGetUniformLocation(s->program, "extra_depth_scale"); s->pp_ClipTest = glGetUniformLocation(s->program, "pp_ClipTest"); @@ -863,14 +878,14 @@ void UpdateFogTexture(u8 *fog_table, GLenum texture_slot, GLint fog_image_format if (fogTextureId == 0) { fogTextureId = glcache.GenTexture(); - glcache.BindTexture(GL_TEXTURE_2D, fogTextureId); - glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glcache.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glBindTexture(GL_TEXTURE_2D, fogTextureId); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } else - glcache.BindTexture(GL_TEXTURE_2D, fogTextureId); + glBindTexture(GL_TEXTURE_2D, fogTextureId); u8 temp_tex_buffer[256]; MakeFogTexture(temp_tex_buffer); @@ -1023,8 +1038,6 @@ bool RenderFrame() ShaderUniforms.depth_coefs[2] = 0; ShaderUniforms.depth_coefs[3] = 0; - ShaderUniforms.extra_depth_scale = settings.rend.ExtraDepthScale; - //VERT and RAM fog color constants u8* fog_colvert_bgra = (u8*)&FOG_COL_VERT; u8* fog_colram_bgra = (u8*)&FOG_COL_RAM; @@ -1040,7 +1053,7 @@ bool RenderFrame() u8* fog_density = (u8*)&FOG_DENSITY; float fog_den_mant = fog_density[1] / 128.0f; //bit 7 -> x. bit, so [6:0] -> fraction -> /128 s32 fog_den_exp = (s8)fog_density[0]; - ShaderUniforms.fog_den_float = fog_den_mant * powf(2.0f, fog_den_exp); + ShaderUniforms.fog_den_float = fog_den_mant * powf(2.0f, fog_den_exp) * settings.rend.ExtraDepthScale; ShaderUniforms.fog_clamp_min[0] = ((pvrrc.fog_clamp_min >> 16) & 0xFF) / 255.0f; ShaderUniforms.fog_clamp_min[1] = ((pvrrc.fog_clamp_min >> 8) & 0xFF) / 255.0f; @@ -1065,7 +1078,7 @@ bool RenderFrame() ShaderUniforms.PT_ALPHA=(PT_ALPHA_REF&0xFF)/255.0f; - for (auto& it : gl.shaders) + for (const auto& it : gl.shaders) { glcache.UseProgram(it.second.program); ShaderUniforms.Set(&it.second); diff --git a/core/rend/gles/gles.h b/core/rend/gles/gles.h index 38b8dd4f3..06f7cbcaa 100755 --- a/core/rend/gles/gles.h +++ b/core/rend/gles/gles.h @@ -30,7 +30,6 @@ struct PipelineShader GLuint program; GLuint depth_scale; - GLuint extra_depth_scale; GLuint pp_ClipTest,cp_AlphaTestValue; GLuint sp_FOG_COL_RAM,sp_FOG_COL_VERT,sp_FOG_DENSITY; GLuint trilinear_alpha; @@ -101,6 +100,7 @@ struct gl_ctx GLenum index_type; bool GL_OES_packed_depth_stencil_supported; bool GL_OES_depth24_supported; + bool highp_float_supported; size_t get_index_size() { return index_type == GL_UNSIGNED_INT ? sizeof(u32) : sizeof(u16); } }; @@ -159,7 +159,6 @@ extern struct ShaderUniforms_t { float PT_ALPHA; float depth_coefs[4]; - float extra_depth_scale; float fog_den_float; float ps_FOG_COL_RAM[3]; float ps_FOG_COL_VERT[3]; @@ -168,7 +167,7 @@ extern struct ShaderUniforms_t float fog_clamp_max[4]; glm::mat4 normal_mat; - void Set(PipelineShader* s) + void Set(const PipelineShader* s) { if (s->cp_AlphaTestValue!=-1) glUniform1f(s->cp_AlphaTestValue,PT_ALPHA); @@ -176,9 +175,6 @@ extern struct ShaderUniforms_t if (s->depth_scale!=-1) glUniform4fv( s->depth_scale, 1, depth_coefs); - if (s->extra_depth_scale != -1) - glUniform1f(s->extra_depth_scale, extra_depth_scale); - if (s->sp_FOG_DENSITY!=-1) glUniform1f( s->sp_FOG_DENSITY,fog_den_float); diff --git a/core/rend/vulkan/drawer.h b/core/rend/vulkan/drawer.h index 10ef26a1e..6e3e23f25 100644 --- a/core/rend/vulkan/drawer.h +++ b/core/rend/vulkan/drawer.h @@ -55,24 +55,23 @@ protected: T MakeFragmentUniforms() { T fragUniforms; - fragUniforms.extra_depth_scale = settings.rend.ExtraDepthScale; //VERT and RAM fog color constants - u8* fog_colvert_bgra=(u8*)&FOG_COL_VERT; - u8* fog_colram_bgra=(u8*)&FOG_COL_RAM; - fragUniforms.sp_FOG_COL_VERT[0]=fog_colvert_bgra[2]/255.0f; - fragUniforms.sp_FOG_COL_VERT[1]=fog_colvert_bgra[1]/255.0f; - fragUniforms.sp_FOG_COL_VERT[2]=fog_colvert_bgra[0]/255.0f; + u8* fog_colvert_bgra = (u8*)&FOG_COL_VERT; + u8* fog_colram_bgra = (u8*)&FOG_COL_RAM; + fragUniforms.sp_FOG_COL_VERT[0] = fog_colvert_bgra[2] / 255.0f; + fragUniforms.sp_FOG_COL_VERT[1] = fog_colvert_bgra[1] / 255.0f; + fragUniforms.sp_FOG_COL_VERT[2] = fog_colvert_bgra[0] / 255.0f; - fragUniforms.sp_FOG_COL_RAM[0]=fog_colram_bgra [2]/255.0f; - fragUniforms.sp_FOG_COL_RAM[1]=fog_colram_bgra [1]/255.0f; - fragUniforms.sp_FOG_COL_RAM[2]=fog_colram_bgra [0]/255.0f; + fragUniforms.sp_FOG_COL_RAM[0] = fog_colram_bgra[2] / 255.0f; + fragUniforms.sp_FOG_COL_RAM[1] = fog_colram_bgra[1] / 255.0f; + fragUniforms.sp_FOG_COL_RAM[2] = fog_colram_bgra[0] / 255.0f; //Fog density constant - u8* fog_density=(u8*)&FOG_DENSITY; - float fog_den_mant=fog_density[1]/128.0f; //bit 7 -> x. bit, so [6:0] -> fraction -> /128 - s32 fog_den_exp=(s8)fog_density[0]; - fragUniforms.sp_FOG_DENSITY = fog_den_mant * powf(2.0f, fog_den_exp); + u8* fog_density = (u8*)&FOG_DENSITY; + float fog_den_mant = fog_density[1] / 128.0f; //bit 7 -> x. bit, so [6:0] -> fraction -> /128 + s32 fog_den_exp = (s8)fog_density[0]; + fragUniforms.sp_FOG_DENSITY = fog_den_mant * powf(2.0f, fog_den_exp) * settings.rend.ExtraDepthScale; fragUniforms.colorClampMin[0] = ((pvrrc.fog_clamp_min >> 16) & 0xFF) / 255.0f; fragUniforms.colorClampMin[1] = ((pvrrc.fog_clamp_min >> 8) & 0xFF) / 255.0f; diff --git a/core/rend/vulkan/oit_pipeline.h b/core/rend/vulkan/oit_pipeline.h index e20be8a83..a65b930b7 100644 --- a/core/rend/vulkan/oit_pipeline.h +++ b/core/rend/vulkan/oit_pipeline.h @@ -46,7 +46,6 @@ public: float sp_FOG_COL_VERT[4]; // same comment float cp_AlphaTestValue; float sp_FOG_DENSITY; - float extra_depth_scale; float shade_scale_factor; // new for OIT }; diff --git a/core/rend/vulkan/oit_shaders.cpp b/core/rend/vulkan/oit_shaders.cpp index a578a54f5..fe9223740 100644 --- a/core/rend/vulkan/oit_shaders.cpp +++ b/core/rend/vulkan/oit_shaders.cpp @@ -85,7 +85,6 @@ layout (std140, set = 0, binding = 1) uniform FragmentShaderUniforms vec4 sp_FOG_COL_VERT; float cp_AlphaTestValue; float sp_FOG_DENSITY; - float extra_depth_scale; float shade_scale_factor; } uniformBuffer; @@ -312,7 +311,7 @@ layout (set = 0, binding = 2) uniform sampler2D fog_table; float fog_mode2(float w) { - float z = clamp(w * uniformBuffer.extra_depth_scale * uniformBuffer.sp_FOG_DENSITY, 1.0, 255.9999); + float z = clamp(w * uniformBuffer.sp_FOG_DENSITY, 1.0, 255.9999); float exp = floor(log2(z)); float m = z * 16.0 / pow(2.0, exp) - 16.0; float idx = floor(m) + exp * 16.0 + 0.5; diff --git a/core/rend/vulkan/shaders.cpp b/core/rend/vulkan/shaders.cpp index 87896c62f..7afa4a127 100644 --- a/core/rend/vulkan/shaders.cpp +++ b/core/rend/vulkan/shaders.cpp @@ -104,7 +104,6 @@ layout (std140, set = 0, binding = 1) uniform FragmentShaderUniforms vec4 sp_FOG_COL_VERT; float cp_AlphaTestValue; float sp_FOG_DENSITY; - float extra_depth_scale; } uniformBuffer; layout (push_constant) uniform pushBlock @@ -127,7 +126,7 @@ layout (set = 0, binding = 2) uniform sampler2D fog_table; float fog_mode2(float w) { - float z = clamp(w * uniformBuffer.extra_depth_scale * uniformBuffer.sp_FOG_DENSITY, 1.0, 255.9999); + float z = clamp(w * uniformBuffer.sp_FOG_DENSITY, 1.0, 255.9999); float exp = floor(log2(z)); float m = z * 16.0 / pow(2.0, exp) - 16.0; float idx = floor(m) + exp * 16.0 + 0.5; diff --git a/core/rend/vulkan/shaders.h b/core/rend/vulkan/shaders.h index 03034c236..f43b9a771 100644 --- a/core/rend/vulkan/shaders.h +++ b/core/rend/vulkan/shaders.h @@ -70,7 +70,6 @@ struct FragmentShaderUniforms float sp_FOG_COL_VERT[4]; // same comment float cp_AlphaTestValue; float sp_FOG_DENSITY; - float extra_depth_scale; }; class ShaderManager