Selaa lähdekoodia

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.
lawnjelly 1 vuosi sitten
vanhempi
commit
ed3d029f5d

+ 14 - 6
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;
 }

+ 20 - 11
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;
 }

+ 3 - 3
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;
 }

+ 3 - 1
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;
 }

+ 8 - 1
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

+ 3 - 3
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;
 }