From f424bf73ae5f514d3f82bcf1d64c4d63dcdfdf09 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Sun, 14 Dec 2014 20:59:21 +0100 Subject: [PATCH] GLES: Implement a custom modulo function for PowerVR. Fixes blockiness, see #7153 and #7150 --- GPU/GLES/FragmentShaderGenerator.cpp | 19 ++++++++++++++----- GPU/GLES/VertexShaderGenerator.cpp | 7 +++++-- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/GPU/GLES/FragmentShaderGenerator.cpp b/GPU/GLES/FragmentShaderGenerator.cpp index 330fbb229a..6ffd9fdb4a 100644 --- a/GPU/GLES/FragmentShaderGenerator.cpp +++ b/GPU/GLES/FragmentShaderGenerator.cpp @@ -487,6 +487,7 @@ void GenerateFragmentShader(char *buffer) { const char *texture = "texture2D"; const char *texelFetch = NULL; bool highpFog = false; + bool highpTexcoord = false; bool bitwiseOps = false; #if defined(USING_GLES2) @@ -511,7 +512,8 @@ void GenerateFragmentShader(char *buffer) { // PowerVR needs highp to do the fog in MHU correctly. // Others don't, and some can't handle highp in the fragment shader. highpFog = gl_extensions.gpuVendor == GPU_VENDOR_POWERVR; - + highpTexcoord = highpFog; + // GL_NV_shader_framebuffer_fetch available on mobile platform and ES 2.0 only but not desktop if (gl_extensions.NV_shader_framebuffer_fetch) { WRITE(p, "#extension GL_NV_shader_framebuffer_fetch : require\n"); @@ -635,9 +637,9 @@ void GenerateFragmentShader(char *buffer) { } if (doTexture) { if (doTextureProjection) - WRITE(p, "%s mediump vec3 v_texcoord;\n", varying); + WRITE(p, "%s %s vec3 v_texcoord;\n", varying, highpTexcoord ? "highp" : "mediump"); else - WRITE(p, "%s mediump vec2 v_texcoord;\n", varying); + WRITE(p, "%s %s vec2 v_texcoord;\n", varying, highpTexcoord ? "highp" : "mediump"); } if (!g_Config.bFragmentTestCache) { @@ -668,6 +670,11 @@ void GenerateFragmentShader(char *buffer) { WRITE(p, "out vec4 fragColor0;\n"); } + // PowerVR needs a custom modulo function. For some reason, this has far higher precision than the builtin one. + if (gl_extensions.gpuVendor == GPU_VENDOR_POWERVR && gstate_c.needShaderTexClamp) { + WRITE(p, "float mymod(float a, float b) { return a - b * floor(a / b); }\n"); + } + WRITE(p, "void main() {\n"); if (gstate.isModeClear()) { @@ -700,15 +707,17 @@ void GenerateFragmentShader(char *buffer) { vcoord = "1.0 - " + vcoord; } + std::string modulo = gl_extensions.gpuVendor == GPU_VENDOR_POWERVR ? "mymod" : "mod"; + if (gstate.isTexCoordClampedS()) { ucoord = "clamp(" + ucoord + ", u_texclamp.z, u_texclamp.x - u_texclamp.z)"; } else { - ucoord = "mod(" + ucoord + ", u_texclamp.x)"; + ucoord = modulo + "(" + ucoord + ", u_texclamp.x)"; } if (gstate.isTexCoordClampedT()) { vcoord = "clamp(" + vcoord + ", u_texclamp.w, u_texclamp.y - u_texclamp.w)"; } else { - vcoord = "mod(" + vcoord + ", u_texclamp.y)"; + vcoord = modulo + "(" + vcoord + ", u_texclamp.y)"; } if (textureAtOffset) { ucoord = "(" + ucoord + " + u_texclampoff.x)"; diff --git a/GPU/GLES/VertexShaderGenerator.cpp b/GPU/GLES/VertexShaderGenerator.cpp index 68b3ab6139..e8f1d6841f 100644 --- a/GPU/GLES/VertexShaderGenerator.cpp +++ b/GPU/GLES/VertexShaderGenerator.cpp @@ -163,6 +163,7 @@ void GenerateVertexShader(int prim, u32 vertType, char *buffer, bool useHWTransf const char *attribute = "attribute"; const char * const * boneWeightDecl = boneWeightAttrDecl; bool highpFog = false; + bool highpTexcoord = false; #if defined(USING_GLES2) // Let's wait until we have a real use for this. @@ -178,6 +179,8 @@ void GenerateVertexShader(int prim, u32 vertType, char *buffer, bool useHWTransf // PowerVR needs highp to do the fog in MHU correctly. // Others don't, and some can't handle highp in the fragment shader. highpFog = gl_extensions.gpuVendor == GPU_VENDOR_POWERVR; + highpTexcoord = gl_extensions.gpuVendor == GPU_VENDOR_POWERVR; + #elif !defined(FORCE_OPENGL_2_0) if (gl_extensions.VersionGEThan(3, 3, 0)) { glslES30 = true; @@ -339,9 +342,9 @@ void GenerateVertexShader(int prim, u32 vertType, char *buffer, bool useHWTransf } if (doTexture) { if (doTextureProjection) - WRITE(p, "%s mediump vec3 v_texcoord;\n", varying); + WRITE(p, "%s %s vec3 v_texcoord;\n", varying, highpTexcoord ? "highp" : "mediump"); else - WRITE(p, "%s mediump vec2 v_texcoord;\n", varying); + WRITE(p, "%s %s vec2 v_texcoord;\n", varying, highpTexcoord ? "highp" : "mediump"); }