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.
This commit is contained in:
lawnjelly 2023-11-06 14:31:53 +00:00
parent 23c142afe7
commit ed3d029f5d
6 changed files with 51 additions and 25 deletions

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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

View file

@ -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;
}