prim_shared.glsl (8449B)
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 #include rect,render_task,transform,image_source 6 7 #define EXTEND_MODE_CLAMP 0 8 #define EXTEND_MODE_REPEAT 1 9 10 #define SUBPX_DIR_NONE 0 11 #define SUBPX_DIR_HORIZONTAL 1 12 #define SUBPX_DIR_VERTICAL 2 13 14 #define RASTER_LOCAL 0 15 #define RASTER_SCREEN 1 16 17 uniform sampler2D sClipMask; 18 19 #ifndef SWGL_CLIP_MASK 20 // TODO: convert back to RectWithEndpoint if driver issues are resolved, if ever. 21 flat varying mediump vec4 vClipMaskUvBounds; 22 varying highp vec2 vClipMaskUv; 23 #endif 24 25 #ifdef WR_VERTEX_SHADER 26 27 #define COLOR_MODE_ALPHA 0 28 #define COLOR_MODE_SUBPX_DUAL_SOURCE 1 29 #define COLOR_MODE_BITMAP_SHADOW 2 30 #define COLOR_MODE_COLOR_BITMAP 3 31 #define COLOR_MODE_IMAGE 4 32 #define COLOR_MODE_MULTIPLY_DUAL_SOURCE 5 33 34 uniform HIGHP_SAMPLER_FLOAT sampler2D sPrimitiveHeadersF; 35 uniform HIGHP_SAMPLER_FLOAT isampler2D sPrimitiveHeadersI; 36 37 // Instanced attributes 38 PER_INSTANCE in ivec4 aData; 39 40 #define VECS_PER_PRIM_HEADER_F 2U 41 #define VECS_PER_PRIM_HEADER_I 2U 42 43 struct Instance 44 { 45 int prim_header_address; 46 int clip_address; 47 int segment_index; 48 int flags; 49 int resource_address; 50 int brush_kind; 51 }; 52 53 Instance decode_instance_attributes() { 54 Instance instance; 55 56 instance.prim_header_address = aData.x; 57 instance.clip_address = aData.y; 58 instance.segment_index = aData.z & 0xffff; 59 instance.flags = aData.z >> 16; 60 instance.resource_address = aData.w & 0xffffff; 61 instance.brush_kind = aData.w >> 24; 62 63 return instance; 64 } 65 66 struct PrimitiveHeader { 67 RectWithEndpoint local_rect; 68 RectWithEndpoint local_clip_rect; 69 float z; 70 int specific_prim_address; 71 int transform_id; 72 int picture_task_address; 73 ivec4 user_data; 74 }; 75 76 PrimitiveHeader fetch_prim_header(int index) { 77 PrimitiveHeader ph; 78 79 ivec2 uv_f = get_fetch_uv(index, VECS_PER_PRIM_HEADER_F); 80 vec4 local_rect = TEXEL_FETCH(sPrimitiveHeadersF, uv_f, 0, ivec2(0, 0)); 81 vec4 local_clip_rect = TEXEL_FETCH(sPrimitiveHeadersF, uv_f, 0, ivec2(1, 0)); 82 ph.local_rect = RectWithEndpoint(local_rect.xy, local_rect.zw); 83 ph.local_clip_rect = RectWithEndpoint(local_clip_rect.xy, local_clip_rect.zw); 84 85 ivec2 uv_i = get_fetch_uv(index, VECS_PER_PRIM_HEADER_I); 86 ivec4 data0 = TEXEL_FETCH(sPrimitiveHeadersI, uv_i, 0, ivec2(0, 0)); 87 ivec4 data1 = TEXEL_FETCH(sPrimitiveHeadersI, uv_i, 0, ivec2(1, 0)); 88 ph.z = float(data0.x); 89 ph.specific_prim_address = data0.y; 90 ph.transform_id = data0.z; 91 ph.picture_task_address = data0.w; 92 ph.user_data = data1; 93 94 return ph; 95 } 96 97 struct VertexInfo { 98 vec2 local_pos; 99 vec4 world_pos; 100 }; 101 102 VertexInfo write_vertex(vec2 local_pos, 103 RectWithEndpoint local_clip_rect, 104 float z, 105 Transform transform, 106 PictureTask task) { 107 // Clamp to the two local clip rects. 108 vec2 clamped_local_pos = rect_clamp(local_clip_rect, local_pos); 109 110 // Transform the current vertex to world space. 111 vec4 world_pos = transform.m * vec4(clamped_local_pos, 0.0, 1.0); 112 113 // Convert the world positions to device pixel space. 114 vec2 device_pos = world_pos.xy * task.device_pixel_scale; 115 116 // Apply offsets for the render task to get correct screen location. 117 vec2 final_offset = -task.content_origin + task.task_rect.p0; 118 119 gl_Position = uTransform * vec4(device_pos + final_offset * world_pos.w, z * world_pos.w, world_pos.w); 120 121 VertexInfo vi = VertexInfo( 122 clamped_local_pos, 123 world_pos 124 ); 125 126 return vi; 127 } 128 129 RectWithEndpoint clip_and_init_antialiasing(RectWithEndpoint segment_rect, 130 RectWithEndpoint prim_rect, 131 RectWithEndpoint clip_rect, 132 int edge_flags, 133 float z, 134 Transform transform, 135 PictureTask task) { 136 #ifdef SWGL_ANTIALIAS 137 // Check if the bounds are smaller than the unmodified segment rect. If so, 138 // it is safe to enable AA on those edges. 139 bvec4 clipped = bvec4(greaterThan(clip_rect.p0, segment_rect.p0), 140 lessThan(clip_rect.p1, segment_rect.p1)); 141 swgl_antiAlias(edge_flags | (clipped.x ? 1 : 0) | (clipped.y ? 2 : 0) | 142 (clipped.z ? 4 : 0) | (clipped.w ? 8 : 0)); 143 #endif 144 145 segment_rect.p0 = clamp(segment_rect.p0, clip_rect.p0, clip_rect.p1); 146 segment_rect.p1 = clamp(segment_rect.p1, clip_rect.p0, clip_rect.p1); 147 148 #ifndef SWGL_ANTIALIAS 149 prim_rect.p0 = clamp(prim_rect.p0, clip_rect.p0, clip_rect.p1); 150 prim_rect.p1 = clamp(prim_rect.p1, clip_rect.p0, clip_rect.p1); 151 152 // Select between the segment and prim edges based on edge mask. 153 // We must perform the bitwise-and for each component individually, as a 154 // vector bitwise-and followed by conversion to bvec4 causes shader 155 // compilation crashes on some Adreno devices. See bug 1715746. 156 bvec4 clip_edge_mask = bvec4(bool(edge_flags & 1), bool(edge_flags & 2), bool(edge_flags & 4), bool(edge_flags & 8)); 157 rectangle_aa_vertex(mix( 158 vec4(vec2(-1e16), vec2(1e16)), 159 vec4(segment_rect.p0, segment_rect.p1), 160 clip_edge_mask 161 )); 162 163 // As this is a transform shader, extrude by 2 (local space) pixels 164 // in each direction. This gives enough space around the edge to 165 // apply distance anti-aliasing. Technically, it: 166 // (a) slightly over-estimates the number of required pixels in the simple case. 167 // (b) might not provide enough edge in edge case perspective projections. 168 // However, it's fast and simple. If / when we ever run into issues, we 169 // can do some math on the projection matrix to work out a variable 170 // amount to extrude. 171 172 // Only extrude along edges where we are going to apply AA. 173 float extrude_amount = 2.0; 174 vec4 extrude_distance = mix(vec4(0.0), vec4(extrude_amount), clip_edge_mask); 175 segment_rect.p0 -= extrude_distance.xy; 176 segment_rect.p1 += extrude_distance.zw; 177 #endif 178 179 return segment_rect; 180 } 181 182 void write_clip(vec4 world_pos, ClipArea area, PictureTask task) { 183 #ifdef SWGL_CLIP_MASK 184 swgl_clipMask( 185 sClipMask, 186 (task.task_rect.p0 - task.content_origin) - (area.task_rect.p0 - area.screen_origin), 187 area.task_rect.p0, 188 rect_size(area.task_rect) 189 ); 190 #else 191 vec2 uv = world_pos.xy * area.device_pixel_scale + 192 world_pos.w * (area.task_rect.p0 - area.screen_origin); 193 vClipMaskUvBounds = vec4( 194 area.task_rect.p0, 195 area.task_rect.p1 196 ); 197 vClipMaskUv = uv; 198 #endif 199 } 200 201 // Read the exta image data containing the homogeneous screen space coordinates 202 // of the corners, interpolate between them, and return real screen space UV. 203 vec2 get_image_quad_uv(int address, vec2 f) { 204 ImageSourceExtra extra_data = fetch_image_source_extra(address); 205 vec4 x = mix(extra_data.st_tl, extra_data.st_tr, f.x); 206 vec4 y = mix(extra_data.st_bl, extra_data.st_br, f.x); 207 vec4 z = mix(x, y, f.y); 208 return z.xy / z.w; 209 } 210 #endif //WR_VERTEX_SHADER 211 212 #ifdef WR_FRAGMENT_SHADER 213 214 struct Fragment { 215 vec4 color; 216 #ifdef WR_FEATURE_DUAL_SOURCE_BLENDING 217 vec4 blend; 218 #endif 219 }; 220 221 float do_clip() { 222 #ifdef SWGL_CLIP_MASK 223 // SWGL relies on builtin clip-mask support to do this more efficiently, 224 // so no clipping is required here. 225 return 1.0; 226 #else 227 // check for the dummy bounds, which are given to the opaque objects 228 if (vClipMaskUvBounds.xy == vClipMaskUvBounds.zw) { 229 return 1.0; 230 } 231 // anything outside of the mask is considered transparent 232 //Note: we assume gl_FragCoord.w == interpolated(1 / vClipMaskUv.w) 233 vec2 mask_uv = vClipMaskUv * gl_FragCoord.w; 234 bvec2 left = lessThanEqual(vClipMaskUvBounds.xy, mask_uv); // inclusive 235 bvec2 right = greaterThan(vClipMaskUvBounds.zw, mask_uv); // non-inclusive 236 // bail out if the pixel is outside the valid bounds 237 if (!all(bvec4(left, right))) { 238 return 0.0; 239 } 240 // finally, the slow path - fetch the mask value from an image 241 return texelFetch(sClipMask, ivec2(mask_uv), 0).r; 242 #endif 243 } 244 245 #endif //WR_FRAGMENT_SHADER