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