diff --git a/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilder.cpp b/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilder.cpp index 32c20ac2..c3e15fe7 100644 --- a/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilder.cpp +++ b/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramBuilder.cpp @@ -255,7 +255,8 @@ public: ss << "#version " << Utils::to_string(_glinfo.majorVersion) << Utils::to_string(_glinfo.minorVersion) << "0 es " << std::endl; ss << "# define IN in" << std::endl << "# define OUT out" << std::endl; if (_glinfo.noPerspective) { - ss << "#extension GL_NV_shader_noperspective_interpolation : enable" << std::endl; + ss << "#extension GL_NV_shader_noperspective_interpolation : enable" << std::endl + << "noperspective OUT highp float vZCoord;" << std::endl; } m_part = ss.str(); } @@ -489,12 +490,16 @@ public: " gl_ClipDistance[0] = gl_Position.w - gl_Position.z; \n" ; } else if (config.generalEmulation.enableClipping != 0) { - // Move the near plane towards the camera. - // It helps to avoid issues with near-plane clipping in games, which do not use it. - // Z must be scaled back in fragment shader. - m_part = - " gl_Position.z /= 8.0; \n" - ; + + if (config.generalEmulation.enableFragmentDepthWrite != 0 && _glinfo.noPerspective) { + m_part = " vZCoord = gl_Position.z / gl_Position.w; \n"; + m_part += " gl_Position.z = 0.0; \n"; + } else { + // Move the near plane towards the camera. + // It helps to avoid issues with near-plane clipping in games, which do not use it. + // Z must be scaled back in fragment shader. + m_part = " gl_Position.z /= 8.0; \n"; + } } m_part += " gl_Position.zw *= vec2(uClipRatio); \n" @@ -1172,6 +1177,14 @@ public: "highp float writeDepth();\n"; ; } + if (_glinfo.isGLESX && _glinfo.noPerspective) { + m_part = + "noperspective IN highp float vZCoord; \n" + "uniform lowp float uPolygonOffset; \n" + + m_part + ; + } + } }; @@ -1918,10 +1931,17 @@ public: "{ \n" ; if (_glinfo.isGLESX && config.generalEmulation.enableClipping != 0) { - m_part += - " highp float FragDepth = (uDepthSource != 0) ? uPrimDepth : \n" - " clamp(8.0 * (gl_FragCoord.z * 2.0 - 1.0) * uDepthScale.s + uDepthScale.t, 0.0, 1.0); \n" - ; + if (_glinfo.noPerspective) { + m_part += + " highp float FragDepth = (uDepthSource != 0) ? uPrimDepth : \n" + " clamp((vZCoord - uPolygonOffset) * uDepthScale.s + uDepthScale.t, 0.0, 1.0); \n" + ; + } else { + m_part += + " highp float FragDepth = (uDepthSource != 0) ? uPrimDepth : \n" + " clamp(8.0 * (gl_FragCoord.z * 2.0 - 1.0) * uDepthScale.s + uDepthScale.t, 0.0, 1.0); \n" + ; + } } else { m_part += " highp float FragDepth = (uDepthSource != 0) ? uPrimDepth : \n" @@ -1938,13 +1958,24 @@ public: ; } else { if (_glinfo.isGLESX && config.generalEmulation.enableClipping != 0) { - m_part = - "highp float writeDepth() \n" - "{ \n" - " if (uDepthSource != 0) return uPrimDepth; \n" - " return clamp(8.0 * (gl_FragCoord.z * 2.0 - 1.0) * uDepthScale.s + uDepthScale.t, 0.0, 1.0); \n" - "} \n" - ; + if (_glinfo.noPerspective) { + m_part = + "highp float writeDepth() \n" + "{ \n" + " if (uDepthSource != 0) return uPrimDepth; \n" + " return clamp((vZCoord - uPolygonOffset) * uDepthScale.s + uDepthScale.t, 0.0, 1.0); \n" + "} \n" + ; + } else { + m_part = + "highp float writeDepth() \n" + "{ \n" + " if (uDepthSource != 0) return uPrimDepth; \n" + " return clamp(8.0 * (gl_FragCoord.z * 2.0 - 1.0) * uDepthScale.s + uDepthScale.t, 0.0, 1.0); \n" + "} \n" + ; + } + } else { m_part = "highp float writeDepth() \n" diff --git a/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramUniformFactory.cpp b/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramUniformFactory.cpp index a31ea131..9088fcd1 100644 --- a/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramUniformFactory.cpp +++ b/src/Graphics/OpenGLContext/GLSL/glsl_CombinerProgramUniformFactory.cpp @@ -725,6 +725,23 @@ private: fUniform uClipRatio; }; +class UPolygonOffset : public UniformGroup +{ +public: + UPolygonOffset(GLuint _program) { + LocateUniform(uPolygonOffset); + } + + void update(bool _force) override + { + f32 offset = gfxContext.isEnabled(graphics::enable::POLYGON_OFFSET_FILL) ? 0.003f : 0.0f; + uPolygonOffset.set(offset, _force); + } + +private: + fUniform uPolygonOffset; +}; + class UScreenCoordsScale : public UniformGroup { public: @@ -1114,6 +1131,10 @@ void CombinerProgramUniformFactory::buildUniforms(GLuint _program, config.frameBufferEmulation.N64DepthCompare != Config::dcDisable) _uniforms.emplace_back(new URenderTarget(_program)); + if (m_glInfo.isGLESX && m_glInfo.noPerspective) { + _uniforms.emplace_back(new UPolygonOffset(_program)); + } + _uniforms.emplace_back(new UClipRatio(_program)); _uniforms.emplace_back(new UScreenCoordsScale(_program));