From ed3d029f5d4ea99da9340573bb52d7f46a56514f 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 ++--- drivers/gles3/shaders/effect_blur.glsl | 4 +++- drivers/gles3/shaders/scene.glsl | 9 +++++++- drivers/gles3/shaders/tonemap.glsl | 6 ++--- 6 files changed, 51 insertions(+), 25 deletions(-) diff --git a/drivers/gles2/shaders/effect_blur.glsl b/drivers/gles2/shaders/effect_blur.glsl index 51fe0774e60..231e2d33035 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 @@ -329,16 +336,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 961940c2610..4e4ba8631de 100644 --- a/drivers/gles2/shaders/scene.glsl +++ b/drivers/gles2/shaders/scene.glsl @@ -2380,11 +2380,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; @@ -2399,13 +2406,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) @@ -2413,9 +2420,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 @@ -2436,7 +2443,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); } @@ -2451,9 +2458,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 @@ -2464,7 +2471,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 @@ -2474,8 +2481,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 ed1b95040af..52d927b6370 100644 --- a/drivers/gles2/shaders/tonemap.glsl +++ b/drivers/gles2/shaders/tonemap.glsl @@ -376,9 +376,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; } diff --git a/drivers/gles3/shaders/effect_blur.glsl b/drivers/gles3/shaders/effect_blur.glsl index 7936d2d42b5..a118db20c00 100644 --- a/drivers/gles3/shaders/effect_blur.glsl +++ b/drivers/gles3/shaders/effect_blur.glsl @@ -41,7 +41,8 @@ uniform sampler2D source_ssao; //texunit:1 uniform float lod; uniform vec2 pixel_size; -layout(location = 0) out vec4 frag_color; +layout(location = 0) out vec4 frag_color_final; +vec4 frag_color; #ifdef SSAO_MERGE @@ -315,4 +316,5 @@ void main() { frag_color = vec4(mix(color.rgb, color.rgb * mix(ssao_color.rgb, vec3(1.0), ssao), color.a), 1.0); #endif + frag_color_final = frag_color; } diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index a4d35a79b96..7d6de8e76e6 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -911,7 +911,8 @@ uniform highp sampler2D screen_texture; // texunit:-8 #endif -layout(location = 0) out vec4 frag_color; +layout(location = 0) out vec4 frag_color_final; +vec4 frag_color; #ifdef USE_MULTIPLE_RENDER_TARGETS //ubershader-skip @@ -2447,6 +2448,12 @@ FRAGMENT_SHADER_CODE #endif //ubershader-runtime #endif //SHADELESS //ubershader-runtime + // Write to the final output once and only once. + // Use a temporary in the rest of the shader. + // This is for drivers that have a performance drop + // when the output is read during the shader. + frag_color_final = frag_color; + #endif //USE_MULTIPLE_RENDER_TARGETS //ubershader-runtime #endif //RENDER_DEPTH //ubershader-runtime diff --git a/drivers/gles3/shaders/tonemap.glsl b/drivers/gles3/shaders/tonemap.glsl index f6f93a32a10..bdf0bd8d21f 100644 --- a/drivers/gles3/shaders/tonemap.glsl +++ b/drivers/gles3/shaders/tonemap.glsl @@ -507,9 +507,9 @@ void main() { color.rgb += screen_space_dither(gl_FragCoord.xy); #endif - frag_color = color; - #ifdef DISABLE_ALPHA - frag_color.a = 1.0; + color.a = 1.0; #endif + + frag_color = color; }