[Bf-blender-cvs] [71e30028240] master: Workbench: Depth Of Field: Optimisation

Clément Foucault noreply at git.blender.org
Fri Jan 25 15:13:38 CET 2019


Commit: 71e30028240798d4ec34ee380191058b9313902b
Author: Clément Foucault
Date:   Thu Jan 24 22:01:03 2019 +0100
Branches: master
https://developer.blender.org/rB71e30028240798d4ec34ee380191058b9313902b

Workbench: Depth Of Field: Optimisation

- Compute samples positions on CPU.
- Use 3x3 Box blur instead of 2x2.
- Implement bokeh parameters.

With this commit, dof performance is almost negligeable.
The quality is a bit lower than before but can be improve. Also now big
Circle of confusion are supported (up to 200px).
Cost is ~1.25ms on AMD Vega with a 2560p viewport than full HD and
pretty shallow depth of field.

Coc downsampling and dilation is not used anymore for now (commented).

===================================================================

M	source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl
M	source/blender/draw/engines/workbench/workbench_data.c
M	source/blender/draw/engines/workbench/workbench_deferred.c
M	source/blender/draw/engines/workbench/workbench_effect_dof.c
M	source/blender/draw/engines/workbench/workbench_private.h

===================================================================

diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl
index 08eb22d01c3..fb1a3ae120e 100644
--- a/source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl
+++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl
@@ -20,23 +20,12 @@ uniform sampler2D blurTex;
 #define dof_distance        dofParams.y
 #define dof_invsensorsize   dofParams.z
 
-#define NUM_SAMPLES 25
-
-#define THRESHOLD 1.0
 #define M_PI       3.1415926535897932        /* pi */
 
-const float GOLDEN_ANGLE = 2.39996323;
-const float MAX_BLUR_SIZE = 20.0;
-const float RAD_SCALE = 2.0; // Smaller = nicer blur, larger = faster
-const float MAX_COC_SIZE = 40.0;
-
 float max_v4(vec4 v) { return max(max(v.x, v.y), max(v.z, v.w)); }
 
 #define weighted_sum(a, b, c, d, e, e_sum) ((a) * e.x + (b) * e.y + (c) * e.z + (d) * e.w) / max(1e-6, e_sum);
 
-#define encode_signed_coc(coc) (((coc) / MAX_COC_SIZE) * 0.5 + 0.5);
-#define decode_signed_coc(coc) (((coc) * 2.0 - 1.0) * MAX_COC_SIZE);
-
 /* divide by sensor size to get the normalized size */
 #define calculate_coc(zdepth) (dof_aperturesize * (dof_distance / zdepth - 1.0) * dof_invsensorsize)
 
@@ -44,8 +33,11 @@ float max_v4(vec4 v) { return max(max(v.x, v.y), max(v.z, v.w)); }
 		? (nearFar.x  * nearFar.y) / (z * (nearFar.x - nearFar.y) + nearFar.y) \
 		: (z * 2.0 - 1.0) * nearFar.y)
 
+
+const float MAX_COC_SIZE = 100.0;
 vec2 encode_coc(float near, float far) { return vec2(near, far) / MAX_COC_SIZE; }
 float decode_coc(vec2 cocs) { return max(cocs.x, cocs.y) * MAX_COC_SIZE; }
+float decode_signed_coc(vec2 cocs) { return ((cocs.x > cocs.y) ? cocs.x : -cocs.y) * MAX_COC_SIZE; }
 
 /**
  * ----------------- STEP 0 ------------------
@@ -59,7 +51,7 @@ layout(location = 1) out vec2 normalizedCoc;
 void main()
 {
 	/* Half Res pass */
-	vec2 uv = (floor(gl_FragCoord.xy) * 2.0 + 0.5) * invertedViewportSize; 
+	vec2 uv = (floor(gl_FragCoord.xy) * 2.0 + 0.5) * invertedViewportSize;
 
 	ivec4 texel = ivec4(gl_FragCoord.xyxy) * 2 + ivec4(0, 0, 1, 1);
 
@@ -150,24 +142,24 @@ void main()
 	vec2 texel_size = 1.0 / vec2(textureSize(inputCocTex, 0));
 	vec2 uv = gl_FragCoord.xy * texel_size;
 #ifdef DILATE_VERTICAL
-	// vec2 cocs1 = texture(inputCocTex, uv + texel_size * vec2(-3, 0)).rg;
+	vec2 cocs1 = texture(inputCocTex, uv + texel_size * vec2(-3, 0)).rg;
 	vec2 cocs2 = texture(inputCocTex, uv + texel_size * vec2(-2, 0)).rg;
 	vec2 cocs3 = texture(inputCocTex, uv + texel_size * vec2(-1, 0)).rg;
 	vec2 cocs4 = texture(inputCocTex, uv + texel_size * vec2( 0, 0)).rg;
 	vec2 cocs5 = texture(inputCocTex, uv + texel_size * vec2( 1, 0)).rg;
 	vec2 cocs6 = texture(inputCocTex, uv + texel_size * vec2( 2, 0)).rg;
-	// vec2 cocs7 = texture(inputCocTex, uv + texel_size * vec2( 3, 0)).rg;
+	vec2 cocs7 = texture(inputCocTex, uv + texel_size * vec2( 3, 0)).rg;
 #else /* DILATE_HORIZONTAL */
-	// vec2 cocs1 = texture(inputCocTex, uv + texel_size * vec2(0, -3)).rg;
+	vec2 cocs1 = texture(inputCocTex, uv + texel_size * vec2(0, -3)).rg;
 	vec2 cocs2 = texture(inputCocTex, uv + texel_size * vec2(0, -2)).rg;
 	vec2 cocs3 = texture(inputCocTex, uv + texel_size * vec2(0, -1)).rg;
 	vec2 cocs4 = texture(inputCocTex, uv + texel_size * vec2(0,  0)).rg;
 	vec2 cocs5 = texture(inputCocTex, uv + texel_size * vec2(0,  1)).rg;
 	vec2 cocs6 = texture(inputCocTex, uv + texel_size * vec2(0,  2)).rg;
-	// vec2 cocs7 = texture(inputCocTex, uv + texel_size * vec2(0,  3)).rg;
+	vec2 cocs7 = texture(inputCocTex, uv + texel_size * vec2(0,  3)).rg;
 #endif
-	dilatedCoc = max(max(cocs3, cocs4), max(max(cocs5, cocs6), cocs2));
-	// dilatedCoc = max(max(max(cocs1, cocs2), max(cocs3, cocs4)), max(max(cocs5, cocs6), cocs7));
+	// dilatedCoc = max(max(cocs3, cocs4), max(max(cocs5, cocs6), cocs2));
+	dilatedCoc = max(max(max(cocs1, cocs2), max(cocs3, cocs4)), max(max(cocs5, cocs6), cocs7));
 }
 #endif
 
@@ -179,16 +171,24 @@ void main()
 #ifdef BLUR1
 layout(location = 0) out vec4 blurColor;
 
+#define NUM_SAMPLES 49
+
+/* keep in sync with GlobalsUboStorage */
+layout(std140) uniform dofSamplesBlock {
+	vec4 samples[NUM_SAMPLES];
+};
+
+#if 0 /* Spilar sampling. Better but slower */
 void main()
 {
 	/* Half Res pass */
-	vec2 uv = gl_FragCoord.xy * invertedViewportSize * 2.0; 
+	vec2 uv = gl_FragCoord.xy * invertedViewportSize * 2.0;
 
 	vec2 size = vec2(textureSize(halfResColorTex, 0).xy);
 	ivec2 texel = ivec2(uv * size);
 
-	vec3 color = texelFetch(halfResColorTex, texel, 0).rgb;
-	float coc = decode_coc(texelFetch(inputCocTex, texel, 0).rg);
+	vec4 color = texelFetch(halfResColorTex, texel, 0);
+	float coc = decode_signed_coc(texelFetch(inputCocTex, texel, 0).rg);
 
 	/* TODO Ensure alignement */
 	vec2 max_radii = texture(maxCocTilesTex, (0.5 + floor(gl_FragCoord.xy / 8.0)) / vec2(textureSize(maxCocTilesTex, 0))).rg;
@@ -196,28 +196,56 @@ void main()
 
 	float center_coc = coc;
 	float tot = 1.0;
-	float radius = RAD_SCALE;
 
-	for (float ang = 0.0; radius < MAX_BLUR_SIZE && radius < max_radius; ang += GOLDEN_ANGLE) {
-		vec2 tc = uv + vec2(cos(ang), sin(ang)) * invertedViewportSize * radius;
+	for (int i = 0; i < NUM_SAMPLES; ++i) {
+		vec2 tc = uv + samples[i].xy * invertedViewportSize * max_radius;
 
-		vec3 samp = texture(halfResColorTex, tc).rgb;
-
-		coc = decode_coc(texture(inputCocTex, tc).rg);
+		vec4 samp = texture(halfResColorTex, tc);
+		coc = decode_signed_coc(texture(inputCocTex, tc).rg);
 		if (coc > center_coc) {
 			coc = clamp(abs(coc), 0.0, abs(center_coc) * 2.0);
 		}
-
+		float radius = max_radius * float(i + 1) / float(NUM_SAMPLES);
 		float m = smoothstep(radius - 0.5, radius + 0.5, abs(coc));
 		color += mix(color / tot, samp, m);
 		tot += 1.0;
-		radius += RAD_SCALE / radius;
 	}
 
-	blurColor.rgb = color / tot;
-	blurColor.a = 1.0;
+	blurColor = color / tot;
+}
+#else
+void main()
+{
+	/* Half Res pass */
+	vec2 uv = gl_FragCoord.xy * invertedViewportSize * 2.0;
+
+	vec2 size = vec2(textureSize(halfResColorTex, 0).xy);
+	ivec2 texel = ivec2(uv * size);
+
+	float coc = decode_coc(texelFetch(inputCocTex, texel, 0).rg);
+	float tot = max(0.5, coc);
+
+	vec4 color = texelFetch(halfResColorTex, texel, 0);
+	color *= tot;
+
+	float max_radius = coc;
+	for (int i = 0; i < NUM_SAMPLES; ++i) {
+		vec2 tc = uv + samples[i].xy * invertedViewportSize * max_radius;
+
+		vec4 samp = texture(halfResColorTex, tc);
+
+		coc = decode_coc(texture(inputCocTex, tc).rg);
+
+		float radius = samples[i].z * max_radius;
+		coc *= smoothstep(radius - 0.5, radius + 0.5, coc);
+		color += samp * coc;
+		tot += coc;
+	}
+
+	blurColor = color / tot;
 }
 #endif
+#endif
 
 /**
  * ----------------- STEP 3 ------------------
@@ -229,16 +257,24 @@ out vec4 finalColor;
 void main()
 {
 	/* Half Res pass */
-	vec2 pixel_size = vec2(1.0, 1.0) / vec2(textureSize(blurTex, 0).xy);
+	vec2 pixel_size = 1.0 / vec2(textureSize(blurTex, 0).xy);
 	vec2 uv = gl_FragCoord.xy * pixel_size.xy; 
-	vec2 max_radii = texture(inputCocTex, uv).rg;
-	/* Scale filter  */
-	float rad = min(max(max_radii.x, max_radii.y) * MAX_COC_SIZE, 4.0) * 0.25;
-	finalColor  = texture(blurTex, uv + pixel_size * vec2(-0.5, -0.5) * rad);
-	finalColor += texture(blurTex, uv + pixel_size * vec2(-0.5,  1.5) * rad);
-	finalColor += texture(blurTex, uv + pixel_size * vec2( 1.5, -0.5) * rad);
-	finalColor += texture(blurTex, uv + pixel_size * vec2( 1.5,  1.5) * rad);
-	finalColor *= 0.25;
+	float coc = decode_coc(texture(inputCocTex, uv).rg);
+	/* Only use this filter if coc is > 9.0
+	 * since this filter is not weighted by CoC
+	 * and can bleed a bit. */
+	float rad = clamp(coc - 9.0, 0.0, 1.0);
+	rad *= 1.5; /* If not, it's a gaussian filter. */
+	finalColor  = texture(blurTex, uv + pixel_size * vec2(-1.0, -1.0) * rad);
+	finalColor += texture(blurTex, uv + pixel_size * vec2(-1.0,  0.0) * rad);
+	finalColor += texture(blurTex, uv + pixel_size * vec2(-1.0,  1.0) * rad);
+	finalColor += texture(blurTex, uv + pixel_size * vec2( 0.0, -1.0) * rad);
+	finalColor += texture(blurTex, uv + pixel_size * vec2( 0.0,  0.0) * rad);
+	finalColor += texture(blurTex, uv + pixel_size * vec2( 0.0,  1.0) * rad);
+	finalColor += texture(blurTex, uv + pixel_size * vec2( 1.0, -1.0) * rad);
+	finalColor += texture(blurTex, uv + pixel_size * vec2( 1.0,  0.0) * rad);
+	finalColor += texture(blurTex, uv + pixel_size * vec2( 1.0,  1.0) * rad);
+	finalColor *= 1.0 / 9.0;
 }
 #endif
 
@@ -252,7 +288,7 @@ void main()
 {
 	/* Fullscreen pass */
 	vec2 pixel_size = 0.5 / vec2(textureSize(halfResColorTex, 0).xy);
-	vec2 uv = gl_FragCoord.xy * pixel_size; 
+	vec2 uv = gl_FragCoord.xy * pixel_size;
 
 	/* TODO MAKE SURE TO ALIGN SAMPLE POSITION TO AVOID OFFSET IN THE BOKEH */
 	float depth = texelFetch(sceneDepthTex, ivec2(gl_FragCoord.xy), 0).r;
diff --git a/source/blender/draw/engines/workbench/workbench_data.c b/source/blender/draw/engines/workbench/workbench_data.c
index 2fdec4cf8fc..22a8f51c23c 100644
--- a/source/blender/draw/engines/workbench/workbench_data.c
+++ b/source/blender/draw/engines/workbench/workbench_data.c
@@ -217,5 +217,6 @@ void workbench_private_data_free(WORKBENCH_PrivateData *wpd)
 {
 	BLI_ghash_free(wpd->material_hash, NULL, MEM_freeN);
 	DRW_UBO_FREE_SAFE(wpd->world_ubo);
+	DRW_UBO_FREE_SAFE(wpd->dof_ubo);
 	GPU_BATCH_DISCARD_SAFE(wpd->world_clip_planes_batch);
 }
diff --git a/source/blender/draw/engines/workbench/workbench_deferred.c b/source/blender/draw/engines/workbench/workbench_deferred.c
index d1e32ea42d9..0a17907a12d 100644
--- a/source/blender/draw/engines/workbench/workbench_deferred.c
+++ b/source/blender/draw/engines/workbench/workbench_deferred.c
@@ -1112,6 +1112,7 @@ void workbench_deferred_draw_finish(WORKBENCH_Data *vedata)
 	WORKBENCH_StorageList *stl = vedata->stl;
 	WORKBENCH_PrivateData *wpd = stl->g_data;
 
+	/* XXX TODO(fclem) do not discard UBOS after drawing! Store them per viewport. */
 	workbench_private_data_free(wpd);
 	workbench_volume_smoke_textures_free(wpd);
 }
diff --git a/source/blender/draw/engines/workbench/workbench_effect_dof.c b/source/blender/draw/engines/workbench/workbench_effect_dof.c
index 85213a7460c..b74a77bf891 100644
--- a/source/blender/dra

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list