diff options
Diffstat (limited to 'gfx/wr/webrender/res/brush.glsl')
-rw-r--r-- | gfx/wr/webrender/res/brush.glsl | 256 |
1 files changed, 256 insertions, 0 deletions
diff --git a/gfx/wr/webrender/res/brush.glsl b/gfx/wr/webrender/res/brush.glsl new file mode 100644 index 0000000000..48b2286012 --- /dev/null +++ b/gfx/wr/webrender/res/brush.glsl @@ -0,0 +1,256 @@ +/* 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/. */ + +/// # Brush vertex shaders memory layout +/// +/// The overall memory layout is the same for all brush shaders. +/// +/// The vertex shader receives a minimal amount of data from vertex attributes (packed into a single +/// ivec4 per instance) and the rest is fetched from various uniform samplers using offsets decoded +/// from the vertex attributes. +/// +/// The diagram below shows the the various pieces of data fectched in the vertex shader: +/// +///```ascii +/// (sPrimitiveHeadersI) +/// (VBO) +-----------------------+ +/// +----------------------------+ +----------------------------> | Int header | +/// | Instance vertex attributes | | (sPrimitiveHeadersF) | | +/// | | | +---------------------+ | z | +/// | x: prim_header_address +-------+---> | Float header | | specific_address +-----+ +/// | y: picture_task_address +---------+ | | | transform_address +---+ | +/// | clip_address +-----+ | | local_rect | | user_data | | | +/// | z: flags | | | | local_clip_rect | +-----------------------+ | | +/// | segment_index | | | +---------------------+ | | +/// | w: resource_address +--+ | | | | +/// +----------------------------+ | | | (sGpuCache) | | +/// | | | (sGpuCache) +------------+ | | +/// | | | +---------------+ | Transform | <--------+ | +/// (sGpuCache) | | +-> | Picture task | +------------+ | +/// +-------------+ | | | | | +/// | Resource | <---+ | | ... | | +/// | | | +---------------+ +--------------------------------+ +/// | | | | +/// +-------------+ | (sGpuCache) v (sGpuCache) +/// | +---------------+ +--------------+---------------+-+-+ +/// +-----> | Clip area | | Brush data | Segment data | | | +/// | | | | | | | +/// | ... | | ... | ... | | | ... +/// +---------------+ +--------------+---------------+-+-+ +///``` +/// +/// - Segment data address is obtained by combining the address stored in the int header and the +/// segment index decoded from the vertex attributes. +/// - Resource data is optional, some brush types (such as images) store some extra data there while +/// other brush types don't use it. +/// + +#if (defined(WR_FEATURE_ALPHA_PASS) || defined(WR_FEATURE_ANTIALIASING)) && !defined(SWGL_ANTIALIAS) +varying vec2 v_local_pos; +#endif + +#ifdef WR_VERTEX_SHADER + +void brush_vs( + VertexInfo vi, + int prim_address, + RectWithEndpoint local_rect, + RectWithEndpoint segment_rect, + ivec4 prim_user_data, + int specific_resource_address, + mat4 transform, + PictureTask pic_task, + int brush_flags, + vec4 segment_data +); + +// Forward-declare the text vertex shader entry point which is currently +// different from other brushes. +void text_shader_main( + Instance instance, + PrimitiveHeader ph, + Transform transform, + PictureTask task, + ClipArea clip_area +); + +#define VECS_PER_SEGMENT 2 + +#define BRUSH_FLAG_PERSPECTIVE_INTERPOLATION 1 +#define BRUSH_FLAG_SEGMENT_RELATIVE 2 +#define BRUSH_FLAG_SEGMENT_REPEAT_X 4 +#define BRUSH_FLAG_SEGMENT_REPEAT_Y 8 +#define BRUSH_FLAG_SEGMENT_REPEAT_X_ROUND 16 +#define BRUSH_FLAG_SEGMENT_REPEAT_Y_ROUND 32 +#define BRUSH_FLAG_SEGMENT_NINEPATCH_MIDDLE 64 +#define BRUSH_FLAG_TEXEL_RECT 128 +#define BRUSH_FLAG_FORCE_AA 256 + +#define INVALID_SEGMENT_INDEX 0xffff + +void brush_shader_main_vs( + Instance instance, + PrimitiveHeader ph, + Transform transform, + PictureTask pic_task, + ClipArea clip_area +) { + int edge_flags = (instance.flags >> 12) & 0xf; + int brush_flags = instance.flags & 0xfff; + + // Fetch the segment of this brush primitive we are drawing. + vec4 segment_data; + RectWithEndpoint segment_rect; + if (instance.segment_index == INVALID_SEGMENT_INDEX) { + segment_rect = ph.local_rect; + segment_data = vec4(0.0); + } else { + int segment_address = ph.specific_prim_address + + VECS_PER_SPECIFIC_BRUSH + + instance.segment_index * VECS_PER_SEGMENT; + + vec4[2] segment_info = fetch_from_gpu_cache_2(segment_address); + segment_rect = RectWithEndpoint(segment_info[0].xy, segment_info[0].zw); + segment_rect.p0 += ph.local_rect.p0; + segment_rect.p1 += ph.local_rect.p0; + segment_data = segment_info[1]; + } + + // Most of the time this is the segment rect, but when doing the edge AA + // it is inflated. + RectWithEndpoint adjusted_segment_rect = segment_rect; + + bool antialiased = !transform.is_axis_aligned || ((brush_flags & BRUSH_FLAG_FORCE_AA) != 0); + + // Write the normal vertex information out. + if (antialiased) { + adjusted_segment_rect = clip_and_init_antialiasing( + segment_rect, + ph.local_rect, + ph.local_clip_rect, + edge_flags, + ph.z, + transform, + pic_task + ); + + // The clip was taken into account in clip_and_init_antialiasing, remove + // it so that it doesn't interfere with the aa. + ph.local_clip_rect.p0 = vec2(-1.0e16); + ph.local_clip_rect.p1 = vec2(1.0e16); + } else { + // The common case for most CSS content. + + // TODO(gw): transform bounds may be referenced by + // the fragment shader when running in + // the alpha pass, even on non-transformed + // items. For now, just ensure it has no + // effect. We can tidy this up as we move + // more items to be brush shaders. +#if defined(WR_FEATURE_ALPHA_PASS) && !defined(SWGL_ANTIALIAS) + init_transform_vs(vec4(vec2(-1.0e16), vec2(1.0e16))); +#endif + } + + // Select the corner of the local rect that we are processing. + vec2 local_pos = mix(adjusted_segment_rect.p0, adjusted_segment_rect.p1, aPosition.xy); + + VertexInfo vi = write_vertex( + local_pos, + ph.local_clip_rect, + ph.z, + transform, + pic_task + ); + + // For brush instances in the alpha pass, always write + // out clip information. + // TODO(gw): It's possible that we might want alpha + // shaders that don't clip in the future, + // but it's reasonable to assume that one + // implies the other, for now. + // SW-WR may decay some requests for alpha-pass shaders to + // the opaque version if only the clip-mask is required. In + // that case the opaque vertex shader must still write out + // the clip information, which is cheap to do for SWGL. +#if defined(WR_FEATURE_ALPHA_PASS) || defined(SWGL_CLIP_MASK) + write_clip( + vi.world_pos, + clip_area, + pic_task + ); +#endif + + // Run the specific brush VS code to write interpolators. + brush_vs( + vi, + ph.specific_prim_address, + ph.local_rect, + segment_rect, + ph.user_data, + instance.resource_address, + transform.m, + pic_task, + brush_flags, + segment_data + ); + +#if (defined(WR_FEATURE_ALPHA_PASS) || defined(WR_FEATURE_ANTIALIASING)) && !defined(SWGL_ANTIALIAS) + v_local_pos = vi.local_pos; +#endif +} + +#ifndef WR_VERTEX_SHADER_MAIN_FUNCTION +// If the entry-point was not overridden before including the brush shader, +// use the default one. +#define WR_VERTEX_SHADER_MAIN_FUNCTION brush_shader_main_vs +#endif + +void main(void) { + + Instance instance = decode_instance_attributes(); + PrimitiveHeader ph = fetch_prim_header(instance.prim_header_address); + Transform transform = fetch_transform(ph.transform_id); + PictureTask task = fetch_picture_task(instance.picture_task_address); + ClipArea clip_area = fetch_clip_area(instance.clip_address); + + WR_VERTEX_SHADER_MAIN_FUNCTION(instance, ph, transform, task, clip_area); +} + +#endif // WR_VERTEX_SHADER + +#ifdef WR_FRAGMENT_SHADER + +float antialias_brush() { +#if (defined(WR_FEATURE_ALPHA_PASS) || defined(WR_FEATURE_ANTIALIASING)) && !defined(SWGL_ANTIALIAS) + return init_transform_fs(v_local_pos); +#else + return 1.0; +#endif +} + +Fragment brush_fs(); + +void main(void) { +#ifdef WR_FEATURE_DEBUG_OVERDRAW + oFragColor = WR_DEBUG_OVERDRAW_COLOR; +#else + + Fragment frag = brush_fs(); + +#ifdef WR_FEATURE_ALPHA_PASS + // Apply the clip mask + float clip_alpha = do_clip(); + + frag.color *= clip_alpha; + + #ifdef WR_FEATURE_DUAL_SOURCE_BLENDING + oFragBlend = frag.blend * clip_alpha; + #endif +#endif + + write_output(frag.color); +#endif +} +#endif |