Bug 1688323 - refactor WR gradient shaders with gradient_shared. r=gw
authorLee Salzman <lsalzman@mozilla.com>
Sun, 24 Jan 2021 19:51:18 +0000 (7 months ago)
changeset 564398 63534c66d7b813bf04d9753d942f59984c05b8a9
parent 564397 515a66b2e43c37875972ffce20383108712c31fa
child 564399 3d8ed4244d2309d5e8159137a966bbecffee1c8b
push id38138
push userdluca@mozilla.com
push dateSun, 24 Jan 2021 21:50:58 +0000 (7 months ago)
treeherdermozilla-central@63534c66d7b8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgw
bugs1688323
milestone86.0a1
first release with
nightly linux32
63534c66d7b8 / 86.0a1 / 20210124215058 / files
nightly linux64
63534c66d7b8 / 86.0a1 / 20210124215058 / files
nightly mac
63534c66d7b8 / 86.0a1 / 20210124215058 / files
nightly win32
63534c66d7b8 / 86.0a1 / 20210124215058 / files
nightly win64
63534c66d7b8 / 86.0a1 / 20210124215058 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1688323 - refactor WR gradient shaders with gradient_shared. r=gw Differential Revision: https://phabricator.services.mozilla.com/D102813
gfx/wr/webrender/res/brush_conic_gradient.glsl
gfx/wr/webrender/res/brush_linear_gradient.glsl
gfx/wr/webrender/res/brush_radial_gradient.glsl
gfx/wr/webrender/res/gradient_shared.glsl
gfx/wr/webrender/res/prim_shared.glsl
--- a/gfx/wr/webrender/res/brush_conic_gradient.glsl
+++ b/gfx/wr/webrender/res/brush_conic_gradient.glsl
@@ -1,37 +1,21 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #define VECS_PER_SPECIFIC_BRUSH 2
 
-#include shared,prim_shared,brush
-
-flat varying HIGHP_FS_ADDRESS int  v_gradient_address;
+#include shared,prim_shared,brush,gradient_shared
 
 flat varying vec2 v_center;
 flat varying float v_start_offset;
 flat varying float v_offset_scale;
 flat varying float v_angle;
 
-// Size of the gradient pattern's rectangle, used to compute horizontal and vertical
-// repetitions. Not to be confused with another kind of repetition of the pattern
-// which happens along the gradient stops.
-flat varying vec2 v_repeated_size;
-// Repetition along the gradient stops.
-flat varying float v_gradient_repeat;
-
-varying vec2 v_pos;
-
-#ifdef WR_FEATURE_ALPHA_PASS
-varying vec2 v_local_pos;
-flat varying vec2 v_tile_repeat;
-#endif
-
 #define PI                  3.141592653589793
 
 #ifdef WR_VERTEX_SHADER
 
 struct ConicGradient {
     vec2 center_point;
     vec2 start_end_offset;
     float angle;
@@ -59,86 +43,53 @@ void brush_vs(
     int specific_resource_address,
     mat4 transform,
     PictureTask pic_task,
     int brush_flags,
     vec4 texel_rect
 ) {
     ConicGradient gradient = fetch_gradient(prim_address);
 
-    if ((brush_flags & BRUSH_FLAG_SEGMENT_RELATIVE) != 0) {
-        v_pos = (vi.local_pos - segment_rect.p0) / segment_rect.size;
-        v_pos = v_pos * (texel_rect.zw - texel_rect.xy) + texel_rect.xy;
-        v_pos = v_pos * local_rect.size;
-    } else {
-        v_pos = vi.local_pos - local_rect.p0;
-    }
+    write_gradient_vertex(
+        vi,
+        local_rect,
+        segment_rect,
+        prim_user_data,
+        brush_flags,
+        texel_rect,
+        gradient.extend_mode,
+        gradient.stretch_size
+    );
 
     v_center = gradient.center_point;
     v_angle = PI / 2.0 - gradient.angle;
     v_start_offset = gradient.start_end_offset.x;
     if (gradient.start_end_offset.x != gradient.start_end_offset.y) {
       // Store 1/scale where scale = end_offset - start_offset
       v_offset_scale = 1.0 / (gradient.start_end_offset.y - gradient.start_end_offset.x);
     } else {
       // If scale = 0, we can't get its reciprocal. Instead, just use a zero scale.
       v_offset_scale = 0.0;
     }
-
-    vec2 tile_repeat = local_rect.size / gradient.stretch_size;
-    v_repeated_size = gradient.stretch_size;
-
-    // Normalize UV to 0..1 scale.
-    v_pos /= v_repeated_size;
-
-    v_gradient_address = prim_user_data.x;
-
-    // Whether to repeat the gradient along the line instead of clamping.
-    v_gradient_repeat = float(gradient.extend_mode != EXTEND_MODE_CLAMP);
-
-#ifdef WR_FEATURE_ALPHA_PASS
-    v_tile_repeat = tile_repeat;
-    v_local_pos = vi.local_pos;
-#endif
 }
 #endif
 
 #ifdef WR_FRAGMENT_SHADER
 Fragment brush_fs() {
-
-#ifdef WR_FEATURE_ALPHA_PASS
-    // Handle top and left inflated edges (see brush_image).
-    vec2 local_pos = max(v_pos, vec2(0.0));
-
-    // Apply potential horizontal and vertical repetitions.
-    vec2 pos = fract(local_pos);
-
-    // Handle bottom and right inflated edges (see brush_image).
-    if (local_pos.x >= v_tile_repeat.x) {
-        pos.x = 1.0;
-    }
-    if (local_pos.y >= v_tile_repeat.y) {
-        pos.y = 1.0;
-    }
-#else
-    // Apply potential horizontal and vertical repetitions.
-    vec2 pos = fract(v_pos);
-#endif
+    vec2 pos = compute_gradient_pos();
 
     // Rescale UV to actual repetition size. This can't be done in the vertex
     // shader due to the use of atan() below.
     pos *= v_repeated_size;
 
     vec2 current_dir = pos - v_center;
     float current_angle = atan(current_dir.y, current_dir.x) + v_angle;
     float offset = (fract(current_angle / (2.0 * PI)) - v_start_offset) * v_offset_scale;
 
-    vec4 color = sample_gradient(v_gradient_address,
-                                 offset,
-                                 v_gradient_repeat);
+    vec4 color = sample_gradient(offset);
 
 #ifdef WR_FEATURE_ALPHA_PASS
     color *= init_transform_fs(v_local_pos);
 #endif
 
     return Fragment(color);
 }
 #endif
--- a/gfx/wr/webrender/res/brush_linear_gradient.glsl
+++ b/gfx/wr/webrender/res/brush_linear_gradient.glsl
@@ -1,29 +1,18 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #define VECS_PER_SPECIFIC_BRUSH 2
 
-#include shared,prim_shared,brush
-
-flat varying HIGHP_FS_ADDRESS int v_gradient_address;
+#include shared,prim_shared,brush,gradient_shared
 
 flat varying vec2 v_start_point;
 flat varying vec2 v_scale_dir;
-// Repetition along the gradient stops.
-flat varying float v_gradient_repeat;
-
-varying vec2 v_pos;
-
-#ifdef WR_FEATURE_ALPHA_PASS
-varying vec2 v_local_pos;
-flat varying vec2 v_tile_repeat;
-#endif
 
 #ifdef WR_VERTEX_SHADER
 
 struct Gradient {
     vec4 start_end_point;
     int extend_mode;
     vec2 stretch_size;
 };
@@ -46,82 +35,47 @@ void brush_vs(
     int specific_resource_address,
     mat4 transform,
     PictureTask pic_task,
     int brush_flags,
     vec4 texel_rect
 ) {
     Gradient gradient = fetch_gradient(prim_address);
 
-    if ((brush_flags & BRUSH_FLAG_SEGMENT_RELATIVE) != 0) {
-        v_pos = (vi.local_pos - segment_rect.p0) / segment_rect.size;
-        v_pos = v_pos * (texel_rect.zw - texel_rect.xy) + texel_rect.xy;
-        v_pos = v_pos * local_rect.size;
-    } else {
-        v_pos = vi.local_pos - local_rect.p0;
-    }
+    write_gradient_vertex(
+        vi,
+        local_rect,
+        segment_rect,
+        prim_user_data,
+        brush_flags,
+        texel_rect,
+        gradient.extend_mode,
+        gradient.stretch_size
+    );
 
     vec2 start_point = gradient.start_end_point.xy;
     vec2 end_point = gradient.start_end_point.zw;
     vec2 dir = end_point - start_point;
 
     v_start_point = start_point;
     v_scale_dir = dir / dot(dir, dir);
 
-    vec2 tile_repeat = local_rect.size / gradient.stretch_size;
-
-    // Size of the gradient pattern's rectangle, used to compute horizontal and vertical
-    // repetitions. Not to be confused with another kind of repetition of the pattern
-    // which happens along the gradient stops.
-    vec2 repeated_size = gradient.stretch_size;
-
     // Normalize UV and offsets to 0..1 scale.
-    v_pos /= repeated_size;
-    v_start_point /= repeated_size;
-    v_scale_dir *= repeated_size;
-
-    v_gradient_address = prim_user_data.x;
-
-    // Whether to repeat the gradient along the line instead of clamping.
-    v_gradient_repeat = float(gradient.extend_mode != EXTEND_MODE_CLAMP);
-
-#ifdef WR_FEATURE_ALPHA_PASS
-    v_tile_repeat = tile_repeat;
-    v_local_pos = vi.local_pos;
-#endif
+    v_start_point /= v_repeated_size;
+    v_scale_dir *= v_repeated_size;
 }
 #endif
 
 #ifdef WR_FRAGMENT_SHADER
 Fragment brush_fs() {
-
-#ifdef WR_FEATURE_ALPHA_PASS
-    // Handle top and left inflated edges (see brush_image).
-    vec2 local_pos = max(v_pos, vec2(0.0));
-
-    // Apply potential horizontal and vertical repetitions.
-    vec2 pos = fract(local_pos);
-
-    // Handle bottom and right inflated edges (see brush_image).
-    if (local_pos.x >= v_tile_repeat.x) {
-        pos.x = 1.0;
-    }
-    if (local_pos.y >= v_tile_repeat.y) {
-        pos.y = 1.0;
-    }
-#else
-    // Apply potential horizontal and vertical repetitions.
-    vec2 pos = fract(v_pos);
-#endif
+    vec2 pos = compute_gradient_pos();
 
     float offset = dot(pos - v_start_point, v_scale_dir);
 
-    vec4 color = sample_gradient(v_gradient_address,
-                                 offset,
-                                 v_gradient_repeat);
+    vec4 color = sample_gradient(offset);
 
 #ifdef WR_FEATURE_ALPHA_PASS
     color *= init_transform_fs(v_local_pos);
 #endif
 
     return Fragment(color);
 }
 #endif
--- a/gfx/wr/webrender/res/brush_radial_gradient.glsl
+++ b/gfx/wr/webrender/res/brush_radial_gradient.glsl
@@ -1,32 +1,20 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #define VECS_PER_SPECIFIC_BRUSH 2
 
-#include shared,prim_shared,brush
-
-flat varying HIGHP_FS_ADDRESS int v_gradient_address;
+#include shared,prim_shared,brush,gradient_shared
 
 flat varying vec2 v_center;
 flat varying float v_start_radius;
 flat varying float v_radius_scale;
 
-flat varying vec2 v_repeated_size;
-flat varying float v_gradient_repeat;
-
-varying vec2 v_pos;
-
-#ifdef WR_FEATURE_ALPHA_PASS
-varying vec2 v_local_pos;
-flat varying vec2 v_tile_repeat;
-#endif
-
 #ifdef WR_VERTEX_SHADER
 
 struct RadialGradient {
     vec4 center_start_end_radius;
     float ratio_xy;
     int extend_mode;
     vec2 stretch_size;
 };
@@ -50,90 +38,57 @@ void brush_vs(
     int specific_resource_address,
     mat4 transform,
     PictureTask pic_task,
     int brush_flags,
     vec4 texel_rect
 ) {
     RadialGradient gradient = fetch_radial_gradient(prim_address);
 
-    if ((brush_flags & BRUSH_FLAG_SEGMENT_RELATIVE) != 0) {
-        v_pos = (vi.local_pos - segment_rect.p0) / segment_rect.size;
-        v_pos = v_pos * (texel_rect.zw - texel_rect.xy) + texel_rect.xy;
-        v_pos = v_pos * local_rect.size;
-    } else {
-        v_pos = vi.local_pos - local_rect.p0;
-    }
+    write_gradient_vertex(
+        vi,
+        local_rect,
+        segment_rect,
+        prim_user_data,
+        brush_flags,
+        texel_rect,
+        gradient.extend_mode,
+        gradient.stretch_size
+    );
 
     v_center = gradient.center_start_end_radius.xy;
     v_start_radius = gradient.center_start_end_radius.z;
     if (gradient.center_start_end_radius.z != gradient.center_start_end_radius.w) {
       // Store 1/rd where rd = end_radius - start_radius
       v_radius_scale = 1.0 / (gradient.center_start_end_radius.w - gradient.center_start_end_radius.z);
     } else {
       // If rd = 0, we can't get its reciprocal. Instead, just use a zero scale.
       v_radius_scale = 0.0;
     }
 
     // Transform all coordinates by the y scale so the
     // fragment shader can work with circles
-    vec2 tile_repeat = local_rect.size / gradient.stretch_size;
-    v_pos.y *= gradient.ratio_xy;
     v_center.y *= gradient.ratio_xy;
-    v_repeated_size = gradient.stretch_size;
     v_repeated_size.y *=  gradient.ratio_xy;
-
-    // Normalize UV to 0..1 scale.
-    v_pos /= v_repeated_size;
-
-    v_gradient_address = prim_user_data.x;
-
-    // Whether to repeat the gradient instead of clamping.
-    v_gradient_repeat = float(gradient.extend_mode != EXTEND_MODE_CLAMP);
-
-#ifdef WR_FEATURE_ALPHA_PASS
-    v_tile_repeat = tile_repeat.xy;
-    v_local_pos = vi.local_pos;
-#endif
 }
 #endif
 
 #ifdef WR_FRAGMENT_SHADER
 Fragment brush_fs() {
-
-#ifdef WR_FEATURE_ALPHA_PASS
-    // Handle top and left inflated edges (see brush_image).
-    vec2 local_pos = max(v_pos, vec2(0.0));
-
-    // Apply potential horizontal and vertical repetitions.
-    vec2 pos = fract(local_pos);
-
-    // Handle bottom and right inflated edges (see brush_image).
-    if (local_pos.x >= v_tile_repeat.x) {
-        pos.x = 1.0;
-    }
-    if (local_pos.y >= v_tile_repeat.y) {
-        pos.y = 1.0;
-    }
-#else
-    // Apply potential horizontal and vertical repetitions.
-    vec2 pos = fract(v_pos);
-#endif
+    vec2 pos = compute_gradient_pos();
 
     // Rescale UV to actual repetition size. This can't be done in the vertex
     // shader due to the use of length() below.
     pos *= v_repeated_size;
 
     // Solve for t in length(pd) = v_start_radius + t * rd
     vec2 pd = pos - v_center;
     float offset = (length(pd) - v_start_radius) * v_radius_scale;
 
-    vec4 color = sample_gradient(v_gradient_address,
-                                 offset,
-                                 v_gradient_repeat);
+    vec4 color = sample_gradient(offset);
 
 #ifdef WR_FEATURE_ALPHA_PASS
     color *= init_transform_fs(v_local_pos);
 #endif
 
     return Fragment(color);
 }
 #endif
new file mode 100644
--- /dev/null
+++ b/gfx/wr/webrender/res/gradient_shared.glsl
@@ -0,0 +1,127 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+flat varying HIGHP_FS_ADDRESS int v_gradient_address;
+
+// Size of the gradient pattern's rectangle, used to compute horizontal and vertical
+// repetitions. Not to be confused with another kind of repetition of the pattern
+// which happens along the gradient stops.
+flat varying vec2 v_repeated_size;
+// Repetition along the gradient stops.
+flat varying float v_gradient_repeat;
+
+varying vec2 v_pos;
+
+#ifdef WR_FEATURE_ALPHA_PASS
+varying vec2 v_local_pos;
+flat varying vec2 v_tile_repeat;
+#endif
+
+#ifdef WR_VERTEX_SHADER
+void write_gradient_vertex(
+    VertexInfo vi,
+    RectWithSize local_rect,
+    RectWithSize segment_rect,
+    ivec4 prim_user_data,
+    int brush_flags,
+    vec4 texel_rect,
+    int extend_mode,
+    vec2 stretch_size
+) {
+    if ((brush_flags & BRUSH_FLAG_SEGMENT_RELATIVE) != 0) {
+        v_pos = (vi.local_pos - segment_rect.p0) / segment_rect.size;
+        v_pos = v_pos * (texel_rect.zw - texel_rect.xy) + texel_rect.xy;
+        v_pos = v_pos * local_rect.size;
+    } else {
+        v_pos = vi.local_pos - local_rect.p0;
+    }
+
+    vec2 tile_repeat = local_rect.size / stretch_size;
+    v_repeated_size = stretch_size;
+
+    // Normalize UV to 0..1 scale.
+    v_pos /= v_repeated_size;
+
+    v_gradient_address = prim_user_data.x;
+
+    // Whether to repeat the gradient along the line instead of clamping.
+    v_gradient_repeat = float(extend_mode != EXTEND_MODE_CLAMP);
+
+#ifdef WR_FEATURE_ALPHA_PASS
+    v_tile_repeat = tile_repeat;
+    v_local_pos = vi.local_pos;
+#endif
+}
+#endif //WR_VERTEX_SHADER
+
+#ifdef WR_FRAGMENT_SHADER
+vec2 compute_gradient_pos() {
+#ifdef WR_FEATURE_ALPHA_PASS
+    // Handle top and left inflated edges (see brush_image).
+    vec2 local_pos = max(v_pos, vec2(0.0));
+
+    // Apply potential horizontal and vertical repetitions.
+    vec2 pos = fract(local_pos);
+
+    // Handle bottom and right inflated edges (see brush_image).
+    if (local_pos.x >= v_tile_repeat.x) {
+        pos.x = 1.0;
+    }
+    if (local_pos.y >= v_tile_repeat.y) {
+        pos.y = 1.0;
+    }
+    return pos;
+#else
+    // Apply potential horizontal and vertical repetitions.
+    return fract(v_pos);
+#endif
+}
+
+#ifdef WR_FEATURE_DITHERING
+vec4 dither(vec4 color) {
+    const int matrix_mask = 7;
+
+    ivec2 pos = ivec2(gl_FragCoord.xy) & ivec2(matrix_mask);
+    float noise_normalized = (texelFetch(sDither, pos, 0).r * 255.0 + 0.5) / 64.0;
+    float noise = (noise_normalized - 0.5) / 256.0; // scale down to the unit length
+
+    return color + vec4(noise, noise, noise, 0);
+}
+#else
+vec4 dither(vec4 color) {
+    return color;
+}
+#endif //WR_FEATURE_DITHERING
+
+vec4 sample_gradient(float offset) {
+    // Modulo the offset if the gradient repeats.
+    float x = offset - floor(offset) * v_gradient_repeat;
+
+    // Calculate the color entry index to use for this offset:
+    //     offsets < 0 use the first color entry, 0
+    //     offsets from [0, 1) use the color entries in the range of [1, N-1)
+    //     offsets >= 1 use the last color entry, N-1
+    //     so transform the range [0, 1) -> [1, N-1)
+
+    // TODO(gw): In the future we might consider making the size of the
+    // LUT vary based on number / distribution of stops in the gradient.
+    // Ensure we don't fetch outside the valid range of the LUT.
+    const float GRADIENT_ENTRIES = 128.0;
+    x = clamp(1.0 + x * GRADIENT_ENTRIES, 0.0, 1.0 + GRADIENT_ENTRIES);
+
+    // Calculate the texel to index into the gradient color entries:
+    //     floor(x) is the gradient color entry index
+    //     fract(x) is the linear filtering factor between start and end
+    float entry_index = floor(x);
+    float entry_fract = x - entry_index;
+
+    // Fetch the start and end color. There is a [start, end] color per entry.
+    vec4 texels[2] = fetch_from_gpu_cache_2(v_gradient_address + 2 * int(entry_index));
+
+    // Finally interpolate and apply dithering
+    return dither(mix(texels[0], texels[1], entry_fract));
+}
+
+#endif //WR_FRAGMENT_SHADER
+
--- a/gfx/wr/webrender/res/prim_shared.glsl
+++ b/gfx/wr/webrender/res/prim_shared.glsl
@@ -276,54 +276,9 @@ float do_clip() {
     if (!all(bvec4(left, right))) {
         return 0.0;
     }
     // finally, the slow path - fetch the mask value from an image
     return texelFetch(sClipMask, ivec2(mask_uv), 0).r;
 #endif
 }
 
-#ifdef WR_FEATURE_DITHERING
-vec4 dither(vec4 color) {
-    const int matrix_mask = 7;
-
-    ivec2 pos = ivec2(gl_FragCoord.xy) & ivec2(matrix_mask);
-    float noise_normalized = (texelFetch(sDither, pos, 0).r * 255.0 + 0.5) / 64.0;
-    float noise = (noise_normalized - 0.5) / 256.0; // scale down to the unit length
-
-    return color + vec4(noise, noise, noise, 0);
-}
-#else
-vec4 dither(vec4 color) {
-    return color;
-}
-#endif //WR_FEATURE_DITHERING
-
-vec4 sample_gradient(HIGHP_FS_ADDRESS int address, float offset, float gradient_repeat) {
-    // Modulo the offset if the gradient repeats.
-    float x = offset - floor(offset) * gradient_repeat;
-
-    // Calculate the color entry index to use for this offset:
-    //     offsets < 0 use the first color entry, 0
-    //     offsets from [0, 1) use the color entries in the range of [1, N-1)
-    //     offsets >= 1 use the last color entry, N-1
-    //     so transform the range [0, 1) -> [1, N-1)
-
-    // TODO(gw): In the future we might consider making the size of the
-    // LUT vary based on number / distribution of stops in the gradient.
-    // Ensure we don't fetch outside the valid range of the LUT.
-    const float GRADIENT_ENTRIES = 128.0;
-    x = clamp(1.0 + x * GRADIENT_ENTRIES, 0.0, 1.0 + GRADIENT_ENTRIES);
-
-    // Calculate the texel to index into the gradient color entries:
-    //     floor(x) is the gradient color entry index
-    //     fract(x) is the linear filtering factor between start and end
-    float entry_index = floor(x);
-    float entry_fract = x - entry_index;
-
-    // Fetch the start and end color. There is a [start, end] color per entry.
-    vec4 texels[2] = fetch_from_gpu_cache_2(address + 2 * int(entry_index));
-
-    // Finally interpolate and apply dithering
-    return dither(mix(texels[0], texels[1], entry_fract));
-}
-
 #endif //WR_FRAGMENT_SHADER