From 3a04d5adfeb83010ee35fb33614d85f2e94163af Mon Sep 17 00:00:00 2001 From: lawnjelly Date: Mon, 6 Nov 2023 14:31:53 +0000 Subject: [PATCH] GLES2 / GLES3 - Use gl_FragColor temporary On some hardware, modifying gl_FragColor multiple times can cause large performance drops. This PR writes to a standard temporary variable instead, and copies across to gl_FragColor once only at the end of the fragment shader. This could potentially lead to large gains in performance on affected hardware. --- drivers/gles2/shaders/effect_blur.glsl | 20 ++++++++++++----- drivers/gles2/shaders/scene.glsl | 31 +++++++++++++++++--------- drivers/gles2/shaders/tonemap.glsl | 6 ++--- 3 files changed, 37 insertions(+), 20 deletions(-) diff --git a/drivers/gles2/shaders/effect_blur.glsl b/drivers/gles2/shaders/effect_blur.glsl index 3fb34be5f..220da2127 100644 --- a/drivers/gles2/shaders/effect_blur.glsl +++ b/drivers/gles2/shaders/effect_blur.glsl @@ -126,6 +126,13 @@ uniform float camera_z_far; uniform float camera_z_near; void main() { + // Instead of writing directly to gl_FragColor, + // we use an intermediate, and only write + // to gl_FragColor ONCE at the end of the shader. + // This is because some hardware can have huge + // slowdown if you modify gl_FragColor multiple times. + vec4 frag_color; + #ifdef GLOW_GAUSSIAN_HORIZONTAL vec2 pix_size = pixel_size; pix_size *= 0.5; //reading from larger buffer, so use more samples @@ -164,7 +171,7 @@ void main() { #endif //USE_GLOW_HIGH_QUALITY color *= glow_strength; - gl_FragColor = color; + frag_color = color; #endif //GLOW_GAUSSIAN_HORIZONTAL #ifdef GLOW_GAUSSIAN_VERTICAL @@ -174,7 +181,7 @@ void main() { color += texture2DLod(source_color, uv_interp + vec2(0.0, -1.0) * pixel_size, lod) * 0.233062; color += texture2DLod(source_color, uv_interp + vec2(0.0, -2.0) * pixel_size, lod) * 0.122581; color *= glow_strength; - gl_FragColor = color; + frag_color = color; #endif #ifndef USE_GLES_OVER_GL @@ -280,7 +287,7 @@ void main() { color_accum /= k_accum; } - gl_FragColor = color_accum; ///k_accum; + frag_color = color_accum; ///k_accum; #endif @@ -330,16 +337,17 @@ void main() { color_accum.a = max(color_accum.a, sqrt(max_accum)); - gl_FragColor = color_accum; + frag_color = color_accum; #endif #ifdef GLOW_FIRST_PASS - float luminance = max(gl_FragColor.r, max(gl_FragColor.g, gl_FragColor.b)); + float luminance = max(frag_color.r, max(frag_color.g, frag_color.b)); float feedback = max(smoothstep(glow_hdr_threshold, glow_hdr_threshold + glow_hdr_scale, luminance), glow_bloom); - gl_FragColor = min(gl_FragColor * feedback, vec4(luminance_cap)); + frag_color = min(frag_color * feedback, vec4(luminance_cap)); #endif + gl_FragColor = frag_color; } diff --git a/drivers/gles2/shaders/scene.glsl b/drivers/gles2/shaders/scene.glsl index 3f35603b8..59a8d43ba 100644 --- a/drivers/gles2/shaders/scene.glsl +++ b/drivers/gles2/shaders/scene.glsl @@ -2236,11 +2236,18 @@ FRAGMENT_SHADER_CODE #endif // !USE_SHADOW_TO_OPACITY + // Instead of writing directly to gl_FragColor, + // we use an intermediate, and only write + // to gl_FragColor ONCE at the end of the shader. + // This is because some hardware can have huge + // slowdown if you modify gl_FragColor multiple times. + vec4 frag_color; + #ifndef RENDER_DEPTH #ifdef SHADELESS - gl_FragColor = vec4(albedo, alpha); + frag_color = vec4(albedo, alpha); #else ambient_light *= albedo; @@ -2255,13 +2262,13 @@ FRAGMENT_SHADER_CODE diffuse_light *= 1.0 - metallic; ambient_light *= 1.0 - metallic; - gl_FragColor = vec4(ambient_light + diffuse_light + specular_light, alpha); + frag_color = vec4(ambient_light + diffuse_light + specular_light, alpha); //add emission if in base pass #ifdef BASE_PASS - gl_FragColor.rgb += emission; + frag_color.rgb += emission; #endif - // gl_FragColor = vec4(normal, 1.0); + // frag_color = vec4(normal, 1.0); //apply fog #if defined(FOG_DEPTH_ENABLED) || defined(FOG_HEIGHT_ENABLED) @@ -2269,9 +2276,9 @@ FRAGMENT_SHADER_CODE #if defined(USE_VERTEX_LIGHTING) #if defined(BASE_PASS) - gl_FragColor.rgb = mix(gl_FragColor.rgb, fog_interp.rgb, fog_interp.a); + frag_color.rgb = mix(frag_color.rgb, fog_interp.rgb, fog_interp.a); #else - gl_FragColor.rgb *= (1.0 - fog_interp.a); + frag_color.rgb *= (1.0 - fog_interp.a); #endif // BASE_PASS #else //pixel based fog @@ -2292,7 +2299,7 @@ FRAGMENT_SHADER_CODE fog_amount = pow(fog_z, fog_depth_curve) * fog_color_base.a; if (fog_transmit_enabled) { - vec3 total_light = gl_FragColor.rgb; + vec3 total_light = frag_color.rgb; float transmit = pow(fog_z, fog_transmit_curve); fog_color = mix(max(total_light, fog_color), fog_color, transmit); } @@ -2307,9 +2314,9 @@ FRAGMENT_SHADER_CODE #endif #if defined(BASE_PASS) - gl_FragColor.rgb = mix(gl_FragColor.rgb, fog_color, fog_amount); + frag_color.rgb = mix(frag_color.rgb, fog_color, fog_amount); #else - gl_FragColor.rgb *= (1.0 - fog_amount); + frag_color.rgb *= (1.0 - fog_amount); #endif // BASE_PASS #endif //use vertex lit @@ -2320,7 +2327,7 @@ FRAGMENT_SHADER_CODE #ifdef OUTPUT_LINEAR // sRGB -> linear - gl_FragColor.rgb = mix(pow((gl_FragColor.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)), gl_FragColor.rgb * (1.0 / 12.92), vec3(lessThan(gl_FragColor.rgb, vec3(0.04045)))); + frag_color.rgb = mix(pow((frag_color.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)), frag_color.rgb * (1.0 / 12.92), vec3(lessThan(frag_color.rgb, vec3(0.04045)))); #endif #else // not RENDER_DEPTH @@ -2330,8 +2337,10 @@ FRAGMENT_SHADER_CODE highp float depth = ((position_interp.z / position_interp.w) + 1.0) * 0.5 + 0.0; // bias highp vec4 comp = fract(depth * vec4(255.0 * 255.0 * 255.0, 255.0 * 255.0, 255.0, 1.0)); comp -= comp.xxyz * vec4(0.0, 1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0); - gl_FragColor = comp; + frag_color = comp; #endif #endif + + gl_FragColor = frag_color; } diff --git a/drivers/gles2/shaders/tonemap.glsl b/drivers/gles2/shaders/tonemap.glsl index 089984874..cdd453546 100644 --- a/drivers/gles2/shaders/tonemap.glsl +++ b/drivers/gles2/shaders/tonemap.glsl @@ -378,9 +378,9 @@ void main() { color.rgb = apply_color_correction(color.rgb, color_correction); #endif - gl_FragColor = color; - #ifdef DISABLE_ALPHA - gl_FragColor.a = 1.0; + color.a = 1.0; #endif + + gl_FragColor = color; }