ps_quad.glsl (12622B)
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 /// The common infrastructure for ps_quad_* shaders. 6 /// 7 /// # Memory layout 8 /// 9 /// The diagram below shows the the various pieces of data fectched in the vertex shader: 10 /// 11 ///```ascii 12 /// (int gpu buffer) 13 /// +------------------+ 14 /// |Int header (ivec4)| (float gpu buffer) 15 /// (instance-step vertex attr) | | +-----------+ 16 /// +-----------------------------+ | x: transform id +--> | Transform | 17 /// | Quad instance (uvec4) | +--> | y: z id | +-----------+ 18 /// | | | | zw: pattern data | 19 /// | x: int prim address +---+ +------------------+ (float gpu buffer) 20 /// | y: float prim address +--------------------------> +-------------------+--------------+-+-+ 21 /// | z: quad flags | (float gpu buffer) | Quad Prim | Quad Segment | | | 22 /// | edge flags | +--------------------+ | | | | | 23 /// | part index | | Picture task | | bounds | rect | | | 24 /// | segment index | | | | clip | uv rect | | | 25 /// | w: picture task address +--> | task rect | | pattern transform | | | | 26 /// +-----------------------------+ | device pixel scale | | color | | | | 27 /// | content origin | +-------------------+--------------+-+-+ 28 /// +--------------------+ 29 /// 30 /// To use the quad infrastructure, a shader must define the following entry 31 /// points in the corresponding shader stages: 32 /// - void pattern_vertex(PrimitiveInfo prim) 33 /// - vec4 pattern_fragment(vec4 base_color) 34 ///``` 35 36 #define WR_FEATURE_TEXTURE_2D 37 38 #include shared,rect,transform,render_task,gpu_buffer 39 40 flat varying mediump vec4 v_color; 41 // z: is_mask 42 // w: has edge flags 43 // x,y are avaible for patterns to use. 44 flat varying lowp ivec4 v_flags; 45 #define v_flags_is_mask v_flags.z 46 #define v_flags_has_edge_mask v_flags.w 47 48 49 #ifndef SWGL_ANTIALIAS 50 varying highp vec2 vLocalPos; 51 #endif 52 53 #ifdef WR_VERTEX_SHADER 54 55 #define EDGE_AA_LEFT 1 56 #define EDGE_AA_TOP 2 57 #define EDGE_AA_RIGHT 4 58 #define EDGE_AA_BOTTOM 8 59 60 #define PART_CENTER 0 61 #define PART_LEFT 1 62 #define PART_TOP 2 63 #define PART_RIGHT 3 64 #define PART_BOTTOM 4 65 #define PART_ALL 5 66 67 #define QF_IS_OPAQUE 1 68 #define QF_APPLY_DEVICE_CLIP 2 69 #define QF_IGNORE_DEVICE_SCALE 4 70 #define QF_USE_AA_SEGMENTS 8 71 #define QF_IS_MASK 16 72 73 #define INVALID_SEGMENT_INDEX 0xff 74 75 #define AA_PIXEL_RADIUS 2.0 76 77 PER_INSTANCE in ivec4 aData; 78 79 struct QuadSegment { 80 RectWithEndpoint rect; 81 RectWithEndpoint uv_rect; 82 }; 83 84 struct PrimitiveInfo { 85 vec2 local_pos; 86 87 RectWithEndpoint local_prim_rect; 88 RectWithEndpoint local_clip_rect; 89 90 QuadSegment segment; 91 92 int edge_flags; 93 int quad_flags; 94 ivec2 pattern_input; 95 }; 96 97 struct QuadPrimitive { 98 RectWithEndpoint bounds; 99 RectWithEndpoint clip; 100 RectWithEndpoint uv_rect; 101 vec4 pattern_scale_offset; 102 vec4 color; 103 }; 104 105 QuadSegment fetch_segment(int base, int index) { 106 QuadSegment seg; 107 108 vec4 texels[2] = fetch_from_gpu_buffer_2f(base + 5 + index * 2); 109 110 seg.rect = RectWithEndpoint(texels[0].xy, texels[0].zw); 111 seg.uv_rect = RectWithEndpoint(texels[1].xy, texels[1].zw); 112 113 return seg; 114 } 115 116 QuadPrimitive fetch_primitive(int index) { 117 QuadPrimitive prim; 118 119 vec4 texels[5] = fetch_from_gpu_buffer_5f(index); 120 121 prim.bounds = RectWithEndpoint(texels[0].xy, texels[0].zw); 122 prim.clip = RectWithEndpoint(texels[1].xy, texels[1].zw); 123 prim.uv_rect = RectWithEndpoint(texels[2].xy, texels[2].zw); 124 prim.pattern_scale_offset = texels[3]; 125 prim.color = texels[4]; 126 127 return prim; 128 } 129 130 struct QuadHeader { 131 int transform_id; 132 int z_id; 133 ivec2 pattern_input; 134 }; 135 136 QuadHeader fetch_header(int address) { 137 ivec4 header = fetch_from_gpu_buffer_1i(address); 138 139 QuadHeader qh = QuadHeader( 140 header.x, 141 header.y, 142 header.zw 143 ); 144 145 return qh; 146 } 147 148 struct QuadInstance { 149 // x 150 int prim_address_i; 151 152 // y 153 int prim_address_f; 154 155 // z 156 int quad_flags; 157 int edge_flags; 158 int part_index; 159 int segment_index; 160 161 // w 162 int picture_task_address; 163 }; 164 165 QuadInstance decode_instance() { 166 QuadInstance qi = QuadInstance( 167 aData.x, 168 169 aData.y, 170 171 (aData.z >> 24) & 0xff, 172 (aData.z >> 16) & 0xff, 173 (aData.z >> 8) & 0xff, 174 (aData.z >> 0) & 0xff, 175 176 aData.w 177 ); 178 179 return qi; 180 } 181 182 struct VertexInfo { 183 vec2 local_pos; 184 }; 185 186 VertexInfo write_vertex(vec2 local_pos, 187 float z, 188 Transform transform, 189 vec2 content_origin, 190 RectWithEndpoint task_rect, 191 float device_pixel_scale, 192 int quad_flags) { 193 VertexInfo vi; 194 195 // Transform the current vertex to world space. 196 vec4 world_pos = transform.m * vec4(local_pos, 0.0, 1.0); 197 198 // Convert the world positions to device pixel space. 199 vec2 device_pos = world_pos.xy * device_pixel_scale; 200 201 if ((quad_flags & QF_APPLY_DEVICE_CLIP) != 0) { 202 RectWithEndpoint device_clip_rect = RectWithEndpoint( 203 content_origin, 204 content_origin + task_rect.p1 - task_rect.p0 205 ); 206 207 // Clip to task rect 208 device_pos = rect_clamp(device_clip_rect, device_pos); 209 210 vi.local_pos = (transform.inv_m * vec4(device_pos / device_pixel_scale, 0.0, 1.0)).xy; 211 } else { 212 vi.local_pos = local_pos; 213 } 214 215 // Apply offsets for the render task to get correct screen location. 216 vec2 final_offset = -content_origin + task_rect.p0; 217 218 gl_Position = uTransform * vec4(device_pos + final_offset * world_pos.w, z * world_pos.w, world_pos.w); 219 220 return vi; 221 } 222 223 float edge_aa_offset(int edge, int flags) { 224 return ((flags & edge) != 0) ? AA_PIXEL_RADIUS : 0.0; 225 } 226 227 void pattern_vertex(PrimitiveInfo prim); 228 229 vec2 scale_offset_map_point(vec4 scale_offset, vec2 p) { 230 return p * scale_offset.xy + scale_offset.zw; 231 } 232 233 RectWithEndpoint scale_offset_map_rect(vec4 scale_offset, RectWithEndpoint r) { 234 vec2 p0 = scale_offset_map_point(scale_offset, r.p0); 235 vec2 p1 = scale_offset_map_point(scale_offset, r.p1); 236 return RectWithEndpoint( 237 min(p0, p1), 238 max(p0, p1) 239 ); 240 } 241 242 PrimitiveInfo quad_primive_info(void) { 243 QuadInstance qi = decode_instance(); 244 245 QuadHeader qh = fetch_header(qi.prim_address_i); 246 Transform transform = fetch_transform(qh.transform_id); 247 PictureTask task = fetch_picture_task(qi.picture_task_address); 248 QuadPrimitive prim = fetch_primitive(qi.prim_address_f); 249 float z = float(qh.z_id); 250 251 QuadSegment seg; 252 if (qi.segment_index == INVALID_SEGMENT_INDEX) { 253 seg.rect = prim.bounds; 254 seg.uv_rect = prim.uv_rect; 255 } else { 256 seg = fetch_segment(qi.prim_address_f, qi.segment_index); 257 } 258 259 // The local space rect that we will draw, which is effectively: 260 // - The tile within the primitive we will draw 261 // - Intersected with any local-space clip rect(s) 262 // - Expanded for AA edges where appropriate 263 RectWithEndpoint local_coverage_rect = seg.rect; 264 265 // Apply local clip rect 266 local_coverage_rect.p0 = max(local_coverage_rect.p0, prim.clip.p0); 267 local_coverage_rect.p1 = min(local_coverage_rect.p1, prim.clip.p1); 268 local_coverage_rect.p1 = max(local_coverage_rect.p0, local_coverage_rect.p1); 269 270 switch (qi.part_index) { 271 case PART_LEFT: 272 local_coverage_rect.p1.x = local_coverage_rect.p0.x + AA_PIXEL_RADIUS; 273 #ifdef SWGL_ANTIALIAS 274 swgl_antiAlias(EDGE_AA_LEFT); 275 #else 276 local_coverage_rect.p0.x -= AA_PIXEL_RADIUS; 277 local_coverage_rect.p0.y -= AA_PIXEL_RADIUS; 278 local_coverage_rect.p1.y += AA_PIXEL_RADIUS; 279 #endif 280 break; 281 case PART_TOP: 282 local_coverage_rect.p0.x = local_coverage_rect.p0.x + AA_PIXEL_RADIUS; 283 local_coverage_rect.p1.x = local_coverage_rect.p1.x - AA_PIXEL_RADIUS; 284 local_coverage_rect.p1.y = local_coverage_rect.p0.y + AA_PIXEL_RADIUS; 285 #ifdef SWGL_ANTIALIAS 286 swgl_antiAlias(EDGE_AA_TOP); 287 #else 288 local_coverage_rect.p0.y -= AA_PIXEL_RADIUS; 289 #endif 290 break; 291 case PART_RIGHT: 292 local_coverage_rect.p0.x = local_coverage_rect.p1.x - AA_PIXEL_RADIUS; 293 #ifdef SWGL_ANTIALIAS 294 swgl_antiAlias(EDGE_AA_RIGHT); 295 #else 296 local_coverage_rect.p1.x += AA_PIXEL_RADIUS; 297 local_coverage_rect.p0.y -= AA_PIXEL_RADIUS; 298 local_coverage_rect.p1.y += AA_PIXEL_RADIUS; 299 #endif 300 break; 301 case PART_BOTTOM: 302 local_coverage_rect.p0.x = local_coverage_rect.p0.x + AA_PIXEL_RADIUS; 303 local_coverage_rect.p1.x = local_coverage_rect.p1.x - AA_PIXEL_RADIUS; 304 local_coverage_rect.p0.y = local_coverage_rect.p1.y - AA_PIXEL_RADIUS; 305 #ifdef SWGL_ANTIALIAS 306 swgl_antiAlias(EDGE_AA_BOTTOM); 307 #else 308 local_coverage_rect.p1.y += AA_PIXEL_RADIUS; 309 #endif 310 break; 311 case PART_CENTER: 312 local_coverage_rect.p0.x += edge_aa_offset(EDGE_AA_LEFT, qi.edge_flags); 313 local_coverage_rect.p1.x -= edge_aa_offset(EDGE_AA_RIGHT, qi.edge_flags); 314 local_coverage_rect.p0.y += edge_aa_offset(EDGE_AA_TOP, qi.edge_flags); 315 local_coverage_rect.p1.y -= edge_aa_offset(EDGE_AA_BOTTOM, qi.edge_flags); 316 break; 317 case PART_ALL: 318 default: 319 #ifdef SWGL_ANTIALIAS 320 swgl_antiAlias(qi.edge_flags); 321 #else 322 local_coverage_rect.p0.x -= edge_aa_offset(EDGE_AA_LEFT, qi.edge_flags); 323 local_coverage_rect.p1.x += edge_aa_offset(EDGE_AA_RIGHT, qi.edge_flags); 324 local_coverage_rect.p0.y -= edge_aa_offset(EDGE_AA_TOP, qi.edge_flags); 325 local_coverage_rect.p1.y += edge_aa_offset(EDGE_AA_BOTTOM, qi.edge_flags); 326 #endif 327 break; 328 } 329 330 vec2 local_pos = mix(local_coverage_rect.p0, local_coverage_rect.p1, aPosition); 331 332 float device_pixel_scale = task.device_pixel_scale; 333 if ((qi.quad_flags & QF_IGNORE_DEVICE_SCALE) != 0) { 334 device_pixel_scale = 1.0f; 335 } 336 337 VertexInfo vi = write_vertex( 338 local_pos, 339 z, 340 transform, 341 task.content_origin, 342 task.task_rect, 343 device_pixel_scale, 344 qi.quad_flags 345 ); 346 347 v_color = prim.color; 348 349 vec4 pattern_tx = prim.pattern_scale_offset; 350 seg.rect = scale_offset_map_rect(pattern_tx, seg.rect); 351 352 return PrimitiveInfo( 353 scale_offset_map_point(pattern_tx, vi.local_pos), 354 scale_offset_map_rect(pattern_tx, prim.bounds), 355 scale_offset_map_rect(pattern_tx, prim.clip), 356 seg, 357 qi.edge_flags, 358 qi.quad_flags, 359 qh.pattern_input 360 ); 361 } 362 363 void antialiasing_vertex(PrimitiveInfo prim) { 364 #ifndef SWGL_ANTIALIAS 365 // This does the setup that is required for init_tranform_vs. 366 RectWithEndpoint xf_bounds = RectWithEndpoint( 367 max(prim.local_prim_rect.p0, prim.local_clip_rect.p0), 368 min(prim.local_prim_rect.p1, prim.local_clip_rect.p1) 369 ); 370 vTransformBounds = vec4(xf_bounds.p0, xf_bounds.p1); 371 372 vLocalPos = prim.local_pos; 373 374 if (prim.edge_flags == 0) { 375 v_flags_has_edge_mask = 0; 376 } else { 377 v_flags_has_edge_mask = 1; 378 } 379 #endif 380 } 381 382 void main() { 383 PrimitiveInfo prim = quad_primive_info(); 384 385 if ((prim.quad_flags & QF_IS_MASK) != 0) { 386 v_flags_is_mask = 1; 387 } else { 388 v_flags_is_mask = 0; 389 } 390 391 antialiasing_vertex(prim); 392 pattern_vertex(prim); 393 } 394 #endif 395 396 #ifdef WR_FRAGMENT_SHADER 397 vec4 pattern_fragment(vec4 base_color); 398 399 float antialiasing_fragment() { 400 float alpha = 1.0; 401 #ifndef SWGL_ANTIALIAS 402 if (v_flags_has_edge_mask != 0) { 403 alpha = rectangle_aa_fragment(vLocalPos); 404 } 405 #endif 406 return alpha; 407 } 408 409 void main() { 410 vec4 base_color = v_color; 411 base_color *= antialiasing_fragment(); 412 vec4 output_color = pattern_fragment(base_color); 413 414 if (v_flags_is_mask != 0) { 415 output_color = output_color.rrrr; 416 } 417 418 oFragColor = output_color; 419 } 420 421 #endif