ps_quad_mask.glsl (6331B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 /// This shader applies a (rounded) rectangle mask to the content of the framebuffer. 6 7 #include ps_quad,ellipse 8 9 varying highp vec4 vClipLocalPos; 10 11 #ifdef WR_FEATURE_FAST_PATH 12 flat varying highp vec4 v_clip_radii; 13 flat varying highp vec2 v_clip_size; 14 #else 15 flat varying highp vec4 vClipCenter_Radius_TL; 16 flat varying highp vec4 vClipCenter_Radius_TR; 17 flat varying highp vec4 vClipCenter_Radius_BR; 18 flat varying highp vec4 vClipCenter_Radius_BL; 19 // We pack 4 vec3 clip planes into 3 vec4 to save a varying slot. 20 flat varying highp vec4 vClipPlane_A; 21 flat varying highp vec4 vClipPlane_B; 22 flat varying highp vec4 vClipPlane_C; 23 #endif 24 flat varying highp vec2 vClipMode; 25 26 #ifdef WR_VERTEX_SHADER 27 28 PER_INSTANCE in ivec4 aClipData; 29 30 #define CLIP_SPACE_RASTER 0 31 #define CLIP_SPACE_PRIMITIVE 1 32 33 struct Clip { 34 RectWithEndpoint rect; 35 #ifdef WR_FEATURE_FAST_PATH 36 vec4 radii; 37 #else 38 vec4 radii_top; 39 vec4 radii_bottom; 40 #endif 41 float mode; 42 int space; 43 }; 44 45 Clip fetch_clip(int index) { 46 Clip clip; 47 48 clip.space = aClipData.z; 49 50 #ifdef WR_FEATURE_FAST_PATH 51 vec4 texels[3] = fetch_from_gpu_buffer_3f(index); 52 clip.rect = RectWithEndpoint(texels[0].xy, texels[0].zw); 53 clip.radii = texels[1]; 54 clip.mode = texels[2].x; 55 #else 56 vec4 texels[4] = fetch_from_gpu_buffer_4f(index); 57 clip.rect = RectWithEndpoint(texels[0].xy, texels[0].zw); 58 clip.radii_top = texels[1]; 59 clip.radii_bottom = texels[2]; 60 clip.mode = texels[3].x; 61 #endif 62 63 return clip; 64 } 65 66 void pattern_vertex(PrimitiveInfo prim_info) { 67 68 Clip clip = fetch_clip(aClipData.y); 69 Transform clip_transform = fetch_transform(aClipData.x); 70 71 vClipLocalPos = clip_transform.m * vec4(prim_info.local_pos, 0.0, 1.0); 72 73 #ifndef WR_FEATURE_FAST_PATH 74 if (clip.space == CLIP_SPACE_RASTER) { 75 vTransformBounds = vec4(clip.rect.p0, clip.rect.p1); 76 } else { 77 RectWithEndpoint xf_bounds = RectWithEndpoint( 78 max(clip.rect.p0, prim_info.local_clip_rect.p0), 79 min(clip.rect.p1, prim_info.local_clip_rect.p1) 80 ); 81 vTransformBounds = vec4(xf_bounds.p0, xf_bounds.p1); 82 } 83 #endif 84 85 vClipMode.x = clip.mode; 86 87 #ifdef WR_FEATURE_FAST_PATH 88 // If the radii are uniform, we can use a simpler 2d signed distance 89 // function to get a rounded rect clip. 90 vec2 half_size = 0.5 * (clip.rect.p1 - clip.rect.p0); 91 // Center the position in the box. 92 vClipLocalPos.xy -= (half_size + clip.rect.p0) * vClipLocalPos.w; 93 v_clip_size = half_size; 94 v_clip_radii = clip.radii; 95 #else 96 vec2 r_tl = clip.radii_top.xy; 97 vec2 r_tr = clip.radii_top.zw; 98 vec2 r_br = clip.radii_bottom.zw; 99 vec2 r_bl = clip.radii_bottom.xy; 100 101 vClipCenter_Radius_TL = vec4(clip.rect.p0 + r_tl, 102 inverse_radii_squared(r_tl)); 103 104 vClipCenter_Radius_TR = vec4(clip.rect.p1.x - r_tr.x, 105 clip.rect.p0.y + r_tr.y, 106 inverse_radii_squared(r_tr)); 107 108 vClipCenter_Radius_BR = vec4(clip.rect.p1 - r_br, 109 inverse_radii_squared(r_br)); 110 111 vClipCenter_Radius_BL = vec4(clip.rect.p0.x + r_bl.x, 112 clip.rect.p1.y - r_bl.y, 113 inverse_radii_squared(r_bl)); 114 115 // We need to know the half-spaces of the corners separate from the center 116 // and radius. We compute a point that falls on the diagonal (which is just 117 // an inner vertex pushed out along one axis, but not on both) to get the 118 // plane offset of the half-space. We also compute the direction vector of 119 // the half-space, which is a perpendicular vertex (-y,x) of the vector of 120 // the diagonal. We leave the scales of the vectors unchanged. 121 vec2 n_tl = -r_tl.yx; 122 vec2 n_tr = vec2(r_tr.y, -r_tr.x); 123 vec2 n_br = r_br.yx; 124 vec2 n_bl = vec2(-r_bl.y, r_bl.x); 125 vec3 tl = vec3(n_tl, 126 dot(n_tl, vec2(clip.rect.p0.x, clip.rect.p0.y + r_tl.y))); 127 vec3 tr = vec3(n_tr, 128 dot(n_tr, vec2(clip.rect.p1.x - r_tr.x, clip.rect.p0.y))); 129 vec3 br = vec3(n_br, 130 dot(n_br, vec2(clip.rect.p1.x, clip.rect.p1.y - r_br.y))); 131 vec3 bl = vec3(n_bl, 132 dot(n_bl, vec2(clip.rect.p0.x + r_bl.x, clip.rect.p1.y))); 133 134 vClipPlane_A = vec4(tl.x, tl.y, tl.z, tr.x); 135 vClipPlane_B = vec4(tr.y, tr.z, br.x, br.y); 136 vClipPlane_C = vec4(br.z, bl.x, bl.y, bl.z); 137 #endif 138 139 } 140 #endif 141 142 #ifdef WR_FRAGMENT_SHADER 143 144 #ifdef WR_FEATURE_FAST_PATH 145 // See https://www.shadertoy.com/view/4llXD7 146 // Notes: 147 // * pos is centered in the origin (so 0,0 is the center of the box). 148 // * The border radii must not be larger than half_box_size. 149 float sd_round_box(in vec2 pos, in vec2 half_box_size, in vec4 radii) { 150 radii.xy = (pos.x > 0.0) ? radii.xy : radii.zw; 151 radii.x = (pos.y > 0.0) ? radii.x : radii.y; 152 vec2 q = abs(pos) - half_box_size + radii.x; 153 return min(max(q.x, q.y), 0.0) + length(max(q, 0.0)) - radii.x; 154 } 155 #endif 156 157 vec4 pattern_fragment(vec4 _base_color) { 158 vec2 clip_local_pos = vClipLocalPos.xy / vClipLocalPos.w; 159 float aa_range = compute_aa_range(clip_local_pos); 160 161 #ifdef WR_FEATURE_FAST_PATH 162 float dist = sd_round_box(clip_local_pos, v_clip_size, v_clip_radii); 163 #else 164 vec3 plane_tl = vec3(vClipPlane_A.x, vClipPlane_A.y, vClipPlane_A.z); 165 vec3 plane_tr = vec3(vClipPlane_A.w, vClipPlane_B.x, vClipPlane_B.y); 166 vec3 plane_br = vec3(vClipPlane_B.z, vClipPlane_B.w, vClipPlane_C.x); 167 vec3 plane_bl = vec3(vClipPlane_C.y, vClipPlane_C.z, vClipPlane_C.w); 168 169 float dist = distance_to_rounded_rect( 170 clip_local_pos, 171 plane_tl, 172 vClipCenter_Radius_TL, 173 plane_tr, 174 vClipCenter_Radius_TR, 175 plane_br, 176 vClipCenter_Radius_BR, 177 plane_bl, 178 vClipCenter_Radius_BL, 179 vTransformBounds 180 ); 181 #endif 182 183 // Compute AA for the given dist and range. 184 float alpha = distance_aa(aa_range, dist); 185 186 // Select alpha or inverse alpha depending on clip in/out. 187 float final_alpha = mix(alpha, 1.0 - alpha, vClipMode.x); 188 189 return vec4(final_alpha); 190 } 191 #endif