diff --git a/webrender/res/clip_shared.glsl b/webrender/res/clip_shared.glsl index 772ff050e0..314f79d604 100644 --- a/webrender/res/clip_shared.glsl +++ b/webrender/res/clip_shared.glsl @@ -1,3 +1,4 @@ +#line 1 /* 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/. */ @@ -7,7 +8,7 @@ flat varying vec4 vClipRadius; #ifdef WR_VERTEX_SHADER void write_clip(Clip clip) { - vClipRect = vec4(clip.rect.xy, clip.rect.xy + clip.rect.zw); + vClipRect = vec4(clip.rect.rect.xy, clip.rect.rect.xy + clip.rect.rect.zw); vClipRadius = vec4(clip.top_left.outer_inner_radius.x, clip.top_right.outer_inner_radius.x, clip.bottom_right.outer_inner_radius.x, diff --git a/webrender/res/prim_shared.glsl b/webrender/res/prim_shared.glsl index df62c0fe77..a91a7cd27f 100644 --- a/webrender/res/prim_shared.glsl +++ b/webrender/res/prim_shared.glsl @@ -3,42 +3,79 @@ * 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/. */ -#define PST_TOP_LEFT uint(0) -#define PST_TOP_RIGHT uint(1) -#define PST_BOTTOM_LEFT uint(2) -#define PST_BOTTOM_RIGHT uint(3) -#define PST_TOP uint(4) -#define PST_LEFT uint(5) -#define PST_BOTTOM uint(6) -#define PST_RIGHT uint(7) +#define PST_TOP_LEFT 0 +#define PST_TOP 1 +#define PST_TOP_RIGHT 2 +#define PST_RIGHT 3 +#define PST_BOTTOM_RIGHT 4 +#define PST_BOTTOM 5 +#define PST_BOTTOM_LEFT 6 +#define PST_LEFT 7 + +#define BORDER_LEFT 0 +#define BORDER_TOP 1 +#define BORDER_RIGHT 2 +#define BORDER_BOTTOM 3 #define UV_NORMALIZED uint(0) #define UV_PIXEL uint(1) // Border styles as defined in webrender_traits/types.rs -#define BORDER_STYLE_NONE uint(0) -#define BORDER_STYLE_SOLID uint(1) -#define BORDER_STYLE_DOUBLE uint(2) -#define BORDER_STYLE_DOTTED uint(3) -#define BORDER_STYLE_DASHED uint(4) -#define BORDER_STYLE_HIDDEN uint(5) -#define BORDER_STYLE_GROOVE uint(6) -#define BORDER_STYLE_RIDGE uint(7) -#define BORDER_STYLE_INSET uint(8) -#define BORDER_STYLE_OUTSET uint(9) +#define BORDER_STYLE_NONE 0 +#define BORDER_STYLE_SOLID 1 +#define BORDER_STYLE_DOUBLE 2 +#define BORDER_STYLE_DOTTED 3 +#define BORDER_STYLE_DASHED 4 +#define BORDER_STYLE_HIDDEN 5 +#define BORDER_STYLE_GROOVE 6 +#define BORDER_STYLE_RIDGE 7 +#define BORDER_STYLE_INSET 8 +#define BORDER_STYLE_OUTSET 9 #define MAX_STOPS_PER_ANGLE_GRADIENT 8 #ifdef WR_VERTEX_SHADER -#define VECS_PER_LAYER 13 -#define LAYERS_PER_ROW (WR_MAX_VERTEX_TEXTURE_WIDTH / VECS_PER_LAYER) +#define VECS_PER_LAYER 13 +#define VECS_PER_TILE 2 +#define VECS_PER_PRIM_GEOM 2 -#define VECS_PER_TILE 2 -#define TILES_PER_ROW (WR_MAX_VERTEX_TEXTURE_WIDTH / VECS_PER_TILE) +#define GRADIENT_HORIZONTAL 0 +#define GRADIENT_VERTICAL 1 +#define GRADIENT_ROTATED 2 uniform sampler2D sLayers; uniform sampler2D sRenderTasks; +uniform sampler2D sPrimGeometry; +uniform sampler2D sClips; + +uniform sampler2D sData16; +uniform sampler2D sData32; +uniform sampler2D sData64; +uniform sampler2D sData128; + +ivec2 get_fetch_uv(int index, int vecs_per_item) { + int items_per_row = WR_MAX_VERTEX_TEXTURE_WIDTH / vecs_per_item; + int y = index / items_per_row; + int x = vecs_per_item * (index % items_per_row); + return ivec2(x, y); +} + +ivec2 get_fetch_uv_1(int index) { + return get_fetch_uv(index, 1); +} + +ivec2 get_fetch_uv_2(int index) { + return get_fetch_uv(index, 2); +} + +ivec2 get_fetch_uv_4(int index) { + return get_fetch_uv(index, 4); +} + +ivec2 get_fetch_uv_8(int index) { + return get_fetch_uv(index, 8); +} struct Layer { mat4 transform; @@ -48,7 +85,7 @@ struct Layer { }; layout(std140) uniform Data { - vec4 data[WR_MAX_UBO_VECTORS]; + ivec4 int_data[WR_MAX_UBO_VECTORS]; }; Layer fetch_layer(int index) { @@ -58,11 +95,9 @@ Layer fetch_layer(int index) { // This is required because trying to use an offset // of more than 8 texels doesn't work on some versions // of OSX. - int y = index / LAYERS_PER_ROW; - int x = VECS_PER_LAYER * (index % LAYERS_PER_ROW); - - ivec2 uv0 = ivec2(x + 0, y); - ivec2 uv1 = ivec2(x + 8, y); + ivec2 uv = get_fetch_uv(index, VECS_PER_LAYER); + ivec2 uv0 = ivec2(uv.x + 0, uv.y); + ivec2 uv1 = ivec2(uv.x + 8, uv.y); layer.transform[0] = texelFetchOffset(sLayers, uv0, 0, ivec2(0, 0)); layer.transform[1] = texelFetchOffset(sLayers, uv0, 0, ivec2(1, 0)); @@ -92,10 +127,7 @@ struct Tile { Tile fetch_tile(int index) { Tile tile; - int y = index / TILES_PER_ROW; - int x = VECS_PER_TILE * (index % TILES_PER_ROW); - - ivec2 uv = ivec2(x + 0, y); + ivec2 uv = get_fetch_uv(index, VECS_PER_TILE); tile.actual_rect = texelFetchOffset(sRenderTasks, uv, 0, ivec2(0, 0)); tile.target_rect = texelFetchOffset(sRenderTasks, uv, 0, ivec2(1, 0)); @@ -103,20 +135,172 @@ Tile fetch_tile(int index) { return tile; } -struct PrimitiveInfo { - vec4 layer_tile; +struct Gradient { + vec4 start_end_point; + vec4 kind; +}; + +Gradient fetch_gradient(int index) { + Gradient gradient; + + ivec2 uv = get_fetch_uv_2(index); + + gradient.start_end_point = texelFetchOffset(sData32, uv, 0, ivec2(0, 0)); + gradient.kind = texelFetchOffset(sData32, uv, 0, ivec2(1, 0)); + + return gradient; +} + +struct GradientStop { + vec4 color; + vec4 offset; +}; + +GradientStop fetch_gradient_stop(int index) { + GradientStop stop; + + ivec2 uv = get_fetch_uv_2(index); + + stop.color = texelFetchOffset(sData32, uv, 0, ivec2(0, 0)); + stop.offset = texelFetchOffset(sData32, uv, 0, ivec2(1, 0)); + + return stop; +} + +struct Glyph { + vec4 offset; + vec4 uv_rect; +}; + +Glyph fetch_glyph(int index) { + Glyph glyph; + + ivec2 uv = get_fetch_uv_2(index); + + glyph.offset = texelFetchOffset(sData32, uv, 0, ivec2(0, 0)); + glyph.uv_rect = texelFetchOffset(sData32, uv, 0, ivec2(1, 0)); + + return glyph; +} + +struct Border { + vec4 style; + vec4 widths; + vec4 colors[4]; + vec4 radii[2]; +}; + +Border fetch_border(int index) { + Border border; + + ivec2 uv = get_fetch_uv_8(index); + + border.style = texelFetchOffset(sData128, uv, 0, ivec2(0, 0)); + border.widths = texelFetchOffset(sData128, uv, 0, ivec2(1, 0)); + border.colors[0] = texelFetchOffset(sData128, uv, 0, ivec2(2, 0)); + border.colors[1] = texelFetchOffset(sData128, uv, 0, ivec2(3, 0)); + border.colors[2] = texelFetchOffset(sData128, uv, 0, ivec2(4, 0)); + border.colors[3] = texelFetchOffset(sData128, uv, 0, ivec2(5, 0)); + border.radii[0] = texelFetchOffset(sData128, uv, 0, ivec2(6, 0)); + border.radii[1] = texelFetchOffset(sData128, uv, 0, ivec2(7, 0)); + + return border; +} + +vec4 fetch_instance_geometry(int index) { + ivec2 uv = get_fetch_uv_1(index); + + vec4 rect = texelFetchOffset(sData16, uv, 0, ivec2(0, 0)); + + return rect; +} + +struct PrimitiveGeometry { + vec4 local_rect; vec4 local_clip_rect; +}; + +PrimitiveGeometry fetch_prim_geometry(int index) { + PrimitiveGeometry pg; + + ivec2 uv = get_fetch_uv(index, VECS_PER_PRIM_GEOM); + + pg.local_rect = texelFetchOffset(sPrimGeometry, uv, 0, ivec2(0, 0)); + pg.local_clip_rect = texelFetchOffset(sPrimGeometry, uv, 0, ivec2(1, 0)); + + return pg; +} + +struct PrimitiveInstance { + int global_prim_index; + int specific_prim_index; + int render_task_index; + int layer_index; + int clip_address; + ivec3 user_data; +}; + +PrimitiveInstance fetch_instance(int index) { + PrimitiveInstance pi; + + int offset = index * 2; + + ivec4 data0 = int_data[offset + 0]; + ivec4 data1 = int_data[offset + 1]; + + pi.global_prim_index = data0.x; + pi.specific_prim_index = data0.y; + pi.render_task_index = data0.z; + pi.layer_index = data0.w; + pi.clip_address = data1.x; + pi.user_data = data1.yzw; + + return pi; +} + +struct Primitive { + Layer layer; + Tile tile; vec4 local_rect; + vec4 local_clip_rect; + int prim_index; + int clip_index; + ivec3 user_data; +}; + +Primitive load_primitive(int index) { + Primitive prim; + + PrimitiveInstance pi = fetch_instance(index); + + prim.layer = fetch_layer(pi.layer_index); + prim.tile = fetch_tile(pi.render_task_index); + + PrimitiveGeometry pg = fetch_prim_geometry(pi.global_prim_index); + prim.local_rect = pg.local_rect; + prim.local_clip_rect = pg.local_clip_rect; + + prim.prim_index = pi.specific_prim_index; + prim.user_data = pi.user_data; + prim.clip_index = pi.clip_address; + + return prim; +} + +struct ClipRect { + vec4 rect; + vec4 dummy; }; -PrimitiveInfo unpack_prim_info(int offset) { - PrimitiveInfo info; +ClipRect fetch_clip_rect(int index) { + ClipRect rect; + + ivec2 uv = get_fetch_uv_2(index); - info.layer_tile = data[offset + 0]; - info.local_clip_rect = data[offset + 1]; - info.local_rect = data[offset + 2]; + rect.rect = texelFetchOffset(sData32, uv, 0, ivec2(0, 0)); + rect.dummy = texelFetchOffset(sData32, uv, 0, ivec2(1, 0)); - return info; + return rect; } struct ClipCorner { @@ -124,31 +308,33 @@ struct ClipCorner { vec4 outer_inner_radius; }; -ClipCorner unpack_clip_corner(int offset) { +ClipCorner fetch_clip_corner(int index) { ClipCorner corner; - corner.rect = data[offset + 0]; - corner.outer_inner_radius = data[offset + 1]; + ivec2 uv = get_fetch_uv_2(index); + + corner.rect = texelFetchOffset(sData32, uv, 0, ivec2(0, 0)); + corner.outer_inner_radius = texelFetchOffset(sData32, uv, 0, ivec2(1, 0)); return corner; } struct Clip { - vec4 rect; + ClipRect rect; ClipCorner top_left; ClipCorner top_right; ClipCorner bottom_left; ClipCorner bottom_right; }; -Clip unpack_clip(int offset) { +Clip fetch_clip(int index) { Clip clip; - clip.rect = data[offset + 0]; - clip.top_left = unpack_clip_corner(offset + 1); - clip.top_right = unpack_clip_corner(offset + 3); - clip.bottom_left = unpack_clip_corner(offset + 5); - clip.bottom_right = unpack_clip_corner(offset + 7); + clip.rect = fetch_clip_rect(index + 0); + clip.top_left = fetch_clip_corner(index + 1); + clip.top_right = fetch_clip_corner(index + 2); + clip.bottom_left = fetch_clip_corner(index + 3); + clip.bottom_right = fetch_clip_corner(index + 4); return clip; } @@ -197,17 +383,17 @@ struct VertexInfo { vec2 global_clamped_pos; }; -VertexInfo write_vertex(PrimitiveInfo info) { - Layer layer = fetch_layer(int(info.layer_tile.x)); - Tile tile = fetch_tile(int(info.layer_tile.y)); - - vec2 p0 = floor(0.5 + info.local_rect.xy * uDevicePixelRatio) / uDevicePixelRatio; - vec2 p1 = floor(0.5 + (info.local_rect.xy + info.local_rect.zw) * uDevicePixelRatio) / uDevicePixelRatio; +VertexInfo write_vertex(vec4 instance_rect, + vec4 local_clip_rect, + Layer layer, + Tile tile) { + vec2 p0 = floor(0.5 + instance_rect.xy * uDevicePixelRatio) / uDevicePixelRatio; + vec2 p1 = floor(0.5 + (instance_rect.xy + instance_rect.zw) * uDevicePixelRatio) / uDevicePixelRatio; vec2 local_pos = mix(p0, p1, aPosition.xy); - vec2 cp0 = floor(0.5 + info.local_clip_rect.xy * uDevicePixelRatio) / uDevicePixelRatio; - vec2 cp1 = floor(0.5 + (info.local_clip_rect.xy + info.local_clip_rect.zw) * uDevicePixelRatio) / uDevicePixelRatio; + vec2 cp0 = floor(0.5 + local_clip_rect.xy * uDevicePixelRatio) / uDevicePixelRatio; + vec2 cp1 = floor(0.5 + (local_clip_rect.xy + local_clip_rect.zw) * uDevicePixelRatio) / uDevicePixelRatio; local_pos = clamp(local_pos, cp0, cp1); local_pos = clamp(local_pos, @@ -239,12 +425,12 @@ struct TransformVertexInfo { vec4 clipped_local_rect; }; -TransformVertexInfo write_transform_vertex(PrimitiveInfo info) { - Layer layer = fetch_layer(int(info.layer_tile.x)); - Tile tile = fetch_tile(int(info.layer_tile.y)); - - vec2 lp0 = info.local_rect.xy; - vec2 lp1 = info.local_rect.xy + info.local_rect.zw; +TransformVertexInfo write_transform_vertex(vec4 instance_rect, + vec4 local_clip_rect, + Layer layer, + Tile tile) { + vec2 lp0 = instance_rect.xy; + vec2 lp1 = instance_rect.xy + instance_rect.zw; lp0 = clamp(lp0, layer.local_clip_rect.xy, @@ -295,241 +481,90 @@ TransformVertexInfo write_transform_vertex(PrimitiveInfo info) { } struct Rectangle { - PrimitiveInfo info; vec4 color; }; Rectangle fetch_rectangle(int index) { Rectangle rect; - int offset = index * 4; + ivec2 uv = get_fetch_uv_1(index); - rect.info = unpack_prim_info(offset); - rect.color = data[offset + 3]; + rect.color = texelFetchOffset(sData16, uv, 0, ivec2(0, 0)); return rect; } -struct RectangleClip { - PrimitiveInfo info; - vec4 color; - Clip clip; -}; - -RectangleClip fetch_rectangle_clip(int index) { - RectangleClip rect; - - int offset = index * 13; - - rect.info = unpack_prim_info(offset); - rect.color = data[offset + 3]; - rect.clip = unpack_clip(offset + 4); - - return rect; -} - -struct Glyph { - PrimitiveInfo info; - vec4 color; - vec4 uv_rect; -}; - -Glyph fetch_glyph(int index) { - Glyph glyph; - - int offset = index * 5; - - glyph.info = unpack_prim_info(offset); - glyph.color = data[offset + 3]; - glyph.uv_rect = data[offset + 4]; - - return glyph; -} - -struct TextRunGlyph { - vec4 local_rect; - vec4 uv_rect; -}; - struct TextRun { - PrimitiveInfo info; vec4 color; - TextRunGlyph glyphs[WR_GLYPHS_PER_TEXT_RUN]; }; -PrimitiveInfo fetch_text_run_glyph(int index, out vec4 color, out vec4 uv_rect) { - int offset = 20 * (index / WR_GLYPHS_PER_TEXT_RUN); - int glyph_index = index % WR_GLYPHS_PER_TEXT_RUN; - int glyph_offset = offset + 4 + 2 * glyph_index; +TextRun fetch_text_run(int index) { + TextRun text; - PrimitiveInfo info; - info.layer_tile = data[offset + 0]; - info.local_clip_rect = data[offset + 1]; - info.local_rect = data[glyph_offset + 0]; + ivec2 uv = get_fetch_uv_1(index); - color = data[offset + 3]; - uv_rect = data[glyph_offset + 1]; + text.color = texelFetchOffset(sData16, uv, 0, ivec2(0, 0)); - return info; + return text; } struct Image { - PrimitiveInfo info; vec4 st_rect; // Location of the image texture in the texture atlas. vec4 stretch_size_and_tile_spacing; // Size of the actual image and amount of space between // tiled instances of this image. - vec4 uvkind; // Type of texture coordinates. + bool has_pixel_coords; }; Image fetch_image(int index) { Image image; - int offset = index * 6; - - image.info = unpack_prim_info(offset); - image.st_rect = data[offset + 3]; - image.stretch_size_and_tile_spacing = data[offset + 4]; - image.uvkind = data[offset + 5]; - - return image; -} - -struct ImageClip { - PrimitiveInfo info; - vec4 st_rect; // Location of the image texture in the texture atlas. - vec4 stretch_size_and_tile_spacing; // Size of the actual image and amount of space between - // tiled instances of this image. - vec4 uvkind; // Type of texture coordinates. - Clip clip; -}; - -ImageClip fetch_image_clip(int index) { - ImageClip image; + ivec2 uv = get_fetch_uv_2(index); - int offset = index * 15; + image.st_rect = texelFetchOffset(sData32, uv, 0, ivec2(0, 0)); + image.stretch_size_and_tile_spacing = texelFetchOffset(sData32, uv, 0, ivec2(1, 0)); - image.info = unpack_prim_info(offset); - image.st_rect = data[offset + 3]; - image.stretch_size_and_tile_spacing = data[offset + 4]; - image.uvkind = data[offset + 5]; - image.clip = unpack_clip(offset + 6); + image.has_pixel_coords = image.st_rect.z < 0.0; + image.st_rect.z = abs(image.st_rect.z); return image; } -struct Border { - PrimitiveInfo info; - vec4 verticalColor; - vec4 horizontalColor; - vec4 radii; - vec4 border_style_trbl; - vec4 part; -}; - -Border fetch_border(int index) { - Border border; - - int offset = index * 8; - - border.info = unpack_prim_info(offset); - border.verticalColor = data[offset + 3]; - border.horizontalColor = data[offset + 4]; - border.radii = data[offset + 5]; - border.border_style_trbl = data[offset + 6]; - border.part = data[offset + 7]; - - return border; -} - struct BoxShadow { - PrimitiveInfo info; + vec4 src_rect; + vec4 bs_rect; vec4 color; vec4 border_radii_blur_radius_inverted; - vec4 bs_rect; - vec4 src_rect; }; BoxShadow fetch_boxshadow(int index) { BoxShadow bs; - int offset = index * 7; + ivec2 uv = get_fetch_uv_4(index); - bs.info = unpack_prim_info(offset); - bs.color = data[offset + 3]; - bs.border_radii_blur_radius_inverted = data[offset + 4]; - bs.bs_rect = data[offset + 5]; - bs.src_rect = data[offset + 6]; + bs.src_rect = texelFetchOffset(sData64, uv, 0, ivec2(0, 0)); + bs.bs_rect = texelFetchOffset(sData64, uv, 0, ivec2(1, 0)); + bs.color = texelFetchOffset(sData64, uv, 0, ivec2(2, 0)); + bs.border_radii_blur_radius_inverted = texelFetchOffset(sData64, uv, 0, ivec2(3, 0)); return bs; } -struct AlignedGradient { - PrimitiveInfo info; - vec4 color0; - vec4 color1; - vec4 dir; - Clip clip; -}; - -AlignedGradient fetch_aligned_gradient(int index) { - AlignedGradient gradient; - - int offset = index * 15; - - gradient.info = unpack_prim_info(offset); - gradient.color0 = data[offset + 3]; - gradient.color1 = data[offset + 4]; - gradient.dir = data[offset + 5]; - gradient.clip = unpack_clip(offset + 6); - - return gradient; -} - -struct AngleGradient { - PrimitiveInfo info; - vec4 start_end_point; - vec4 stop_count; - vec4 colors[MAX_STOPS_PER_ANGLE_GRADIENT]; - vec4 offsets[MAX_STOPS_PER_ANGLE_GRADIENT/4]; -}; - -AngleGradient fetch_angle_gradient(int index) { - AngleGradient gradient; - - int offset = index * 15; - - gradient.info = unpack_prim_info(offset); - gradient.start_end_point = data[offset + 3]; - gradient.stop_count = data[offset + 4]; - - for (int i=0 ; i < MAX_STOPS_PER_ANGLE_GRADIENT ; ++i) { - gradient.colors[i] = data[offset + 5 + i]; - } - - for (int i=0 ; i < MAX_STOPS_PER_ANGLE_GRADIENT/4 ; ++i) { - gradient.offsets[i] = data[offset + 5 + MAX_STOPS_PER_ANGLE_GRADIENT + i]; - } - - return gradient; -} - struct Blend { - vec4 src_id_target_id_opacity; + ivec4 src_id_target_id_opacity; }; Blend fetch_blend(int index) { Blend blend; int offset = index * 1; - - blend.src_id_target_id_opacity = data[offset + 0]; + blend.src_id_target_id_opacity = int_data[offset + 0]; return blend; } struct Composite { - vec4 src0_src1_target_id; - vec4 info_amount; + ivec4 src0_src1_target_id; + ivec4 info_amount; }; Composite fetch_composite(int index) { @@ -537,8 +572,8 @@ Composite fetch_composite(int index) { int offset = index * 2; - composite.src0_src1_target_id = data[offset + 0]; - composite.info_amount = data[offset + 1]; + composite.src0_src1_target_id = int_data[offset + 0]; + composite.info_amount = int_data[offset + 1]; return composite; } diff --git a/webrender/res/ps_angle_gradient.vs.glsl b/webrender/res/ps_angle_gradient.vs.glsl index 716997d95e..eda47f8b21 100644 --- a/webrender/res/ps_angle_gradient.vs.glsl +++ b/webrender/res/ps_angle_gradient.vs.glsl @@ -4,10 +4,15 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ void main(void) { - AngleGradient gradient = fetch_angle_gradient(gl_InstanceID); - VertexInfo vi = write_vertex(gradient.info); + Primitive prim = load_primitive(gl_InstanceID); + Gradient gradient = fetch_gradient(prim.prim_index); - vStopCount = int(gradient.stop_count.x); + VertexInfo vi = write_vertex(prim.local_rect, + prim.local_clip_rect, + prim.layer, + prim.tile); + + vStopCount = int(prim.user_data.y); vPos = vi.local_clamped_pos; // Snap the start/end points to device pixel units. @@ -19,8 +24,11 @@ void main(void) { vStartPoint = floor(0.5 + gradient.start_end_point.xy * uDevicePixelRatio) / uDevicePixelRatio; vEndPoint = floor(0.5 + gradient.start_end_point.zw * uDevicePixelRatio) / uDevicePixelRatio; - for (int i=0 ; i < int(gradient.stop_count.x) ; ++i) { - vColors[i] = gradient.colors[i]; - vOffsets[i] = gradient.offsets[i]; + int stop_index = int(prim.user_data.x); + + for (int i=0 ; i < vStopCount ; ++i) { + GradientStop stop = fetch_gradient_stop(stop_index + i); + vColors[i] = stop.color; + vOffsets[i/4][i%4] = stop.offset.x; } } diff --git a/webrender/res/ps_blend.vs.glsl b/webrender/res/ps_blend.vs.glsl index 05d46860d9..7dc2b9e383 100644 --- a/webrender/res/ps_blend.vs.glsl +++ b/webrender/res/ps_blend.vs.glsl @@ -5,8 +5,8 @@ void main(void) { Blend blend = fetch_blend(gl_InstanceID); - Tile src = fetch_tile(int(blend.src_id_target_id_opacity.x)); - Tile dest = fetch_tile(int(blend.src_id_target_id_opacity.y)); + Tile src = fetch_tile(blend.src_id_target_id_opacity.x); + Tile dest = fetch_tile(blend.src_id_target_id_opacity.y); vec2 local_pos = mix(vec2(dest.target_rect.xy), vec2(dest.target_rect.xy + dest.target_rect.zw), @@ -15,7 +15,7 @@ void main(void) { vec2 st0 = vec2(src.target_rect.xy) / 2048.0; vec2 st1 = vec2(src.target_rect.xy + src.target_rect.zw) / 2048.0; vUv = mix(st0, st1, aPosition.xy); - vBrightnessOpacity = blend.src_id_target_id_opacity.zw; + vBrightnessOpacity = blend.src_id_target_id_opacity.zw / 65535.0; gl_Position = uTransform * vec4(local_pos, 0, 1); } diff --git a/webrender/res/ps_border.glsl b/webrender/res/ps_border.glsl index d46b72eed4..0047041205 100644 --- a/webrender/res/ps_border.glsl +++ b/webrender/res/ps_border.glsl @@ -13,8 +13,8 @@ flat varying vec4 vLocalRect; // The rect of the border (x, y, w, h) in local sp // for corners, this is the beginning of the corner. // For the lines, this is the top left of the line. flat varying vec2 vRefPoint; -flat varying uint vBorderStyle; -flat varying uint vBorderPart; // Which part of the border we're drawing. +flat varying int vBorderStyle; +flat varying int vBorderPart; // Which part of the border we're drawing. flat varying vec4 vPieceRect; @@ -28,6 +28,4 @@ varying vec2 vLocalPos; // The clamped position in local space. // These two are interpolated varying float vDistanceFromMixLine; // This is the distance from the line where two colors // meet in border corners. -varying vec2 vDevicePos; // The clamped position in device space. -flat varying vec4 vBorders; // the rect of the border in (x, y, width, height) form #endif diff --git a/webrender/res/ps_border.vs.glsl b/webrender/res/ps_border.vs.glsl index 4d9e035ec7..b20fc11662 100644 --- a/webrender/res/ps_border.vs.glsl +++ b/webrender/res/ps_border.vs.glsl @@ -3,101 +3,205 @@ * 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/. */ -float get_border_style(Border a_border, uint a_edge) { - switch (a_edge) { - case PST_TOP: - case PST_TOP_LEFT: - return a_border.border_style_trbl.x; - case PST_BOTTOM_LEFT: - case PST_LEFT: - return a_border.border_style_trbl.z; - case PST_BOTTOM_RIGHT: - case PST_BOTTOM: - return a_border.border_style_trbl.w; - case PST_TOP_RIGHT: - case PST_RIGHT: - return a_border.border_style_trbl.y; - } -} - void main(void) { - Border border = fetch_border(gl_InstanceID); + Primitive prim = load_primitive(gl_InstanceID); + Border border = fetch_border(prim.prim_index); + + vec2 tl_outer = prim.local_rect.xy; + vec2 tl_inner = tl_outer + vec2(max(border.radii[0].x, border.widths.x), + max(border.radii[0].y, border.widths.y)); + + vec2 tr_outer = vec2(prim.local_rect.x + prim.local_rect.z, + prim.local_rect.y); + vec2 tr_inner = tr_outer + vec2(-max(border.radii[0].z, border.widths.z), + max(border.radii[0].w, border.widths.y)); + + vec2 br_outer = vec2(prim.local_rect.x + prim.local_rect.z, + prim.local_rect.y + prim.local_rect.w); + vec2 br_inner = br_outer - vec2(max(border.radii[1].x, border.widths.z), + max(border.radii[1].y, border.widths.w)); + + vec2 bl_outer = vec2(prim.local_rect.x, + prim.local_rect.y + prim.local_rect.w); + vec2 bl_inner = bl_outer + vec2(max(border.radii[1].z, border.widths.x), + -max(border.radii[1].w, border.widths.w)); + + vec4 segment_rect; + switch (prim.user_data.x) { + case PST_TOP_LEFT: + segment_rect = vec4(tl_outer, tl_inner - tl_outer); + break; + case PST_TOP_RIGHT: + segment_rect = vec4(tr_inner.x, + tr_outer.y, + tr_outer.x - tr_inner.x, + tr_inner.y - tr_outer.y); + break; + case PST_BOTTOM_RIGHT: + segment_rect = vec4(br_inner, br_outer - br_inner); + break; + case PST_BOTTOM_LEFT: + segment_rect = vec4(bl_outer.x, + bl_inner.y, + bl_inner.x - bl_outer.x, + bl_outer.y - bl_inner.y); + break; + case PST_LEFT: + segment_rect = vec4(tl_outer.x, + tl_inner.y, + border.widths.x, + bl_inner.y - tl_inner.y); + break; + case PST_RIGHT: + segment_rect = vec4(tr_outer.x - border.widths.z, + tr_inner.y, + border.widths.z, + br_inner.y - tr_inner.y); + break; + case PST_BOTTOM: + segment_rect = vec4(bl_inner.x, + bl_outer.y - border.widths.w, + br_inner.x - bl_inner.x, + border.widths.w); + break; + case PST_TOP: + segment_rect = vec4(tl_inner.x, + tl_outer.y, + tr_inner.x - tl_inner.x, + border.widths.y); + break; + } + #ifdef WR_FEATURE_TRANSFORM - TransformVertexInfo vi = write_transform_vertex(border.info); + TransformVertexInfo vi = write_transform_vertex(segment_rect, + prim.local_clip_rect, + prim.layer, + prim.tile); vLocalPos = vi.local_pos; // Local space vLocalRect = vi.clipped_local_rect; #else - VertexInfo vi = write_vertex(border.info); + VertexInfo vi = write_vertex(segment_rect, + prim.local_clip_rect, + prim.layer, + prim.tile); vLocalPos = vi.local_clamped_pos.xy; // Local space - vLocalRect = border.info.local_rect; + vLocalRect = prim.local_rect; #endif - // This is what was currently sent. - vVerticalColor = border.verticalColor; - vHorizontalColor = border.horizontalColor; + float x0, y0, x1, y1; + int sub_part = prim.user_data.x; - // Just our boring radius position. - vRadii = border.radii; + switch (sub_part) { + case PST_LEFT: + vBorderStyle = int(border.style.x); + vHorizontalColor = border.colors[BORDER_LEFT]; + vVerticalColor = border.colors[BORDER_LEFT]; + vRadii = vec4(0.0); + break; + case PST_TOP_LEFT: + vBorderStyle = int(border.style.x); + vHorizontalColor = border.colors[BORDER_LEFT]; + vVerticalColor = border.colors[BORDER_TOP]; + vRadii = vec4(border.radii[0].xy, + border.radii[0].xy - border.widths.xy); + break; + case PST_TOP: + vBorderStyle = int(border.style.y); + vHorizontalColor = border.colors[BORDER_TOP]; + vVerticalColor = border.colors[BORDER_TOP]; + vRadii = vec4(0.0); + break; + case PST_TOP_RIGHT: + vBorderStyle = int(border.style.y); + vHorizontalColor = border.colors[BORDER_TOP]; + vVerticalColor = border.colors[BORDER_RIGHT]; + vRadii = vec4(border.radii[0].zw, + border.radii[0].zw - border.widths.zy); + break; + case PST_RIGHT: + vBorderStyle = int(border.style.z); + vHorizontalColor = border.colors[BORDER_RIGHT]; + vVerticalColor = border.colors[BORDER_RIGHT]; + vRadii = vec4(0.0); + break; + case PST_BOTTOM_RIGHT: + vBorderStyle = int(border.style.z); + vHorizontalColor = border.colors[BORDER_BOTTOM]; + vVerticalColor = border.colors[BORDER_RIGHT]; + vRadii = vec4(border.radii[1].xy, + border.radii[1].xy - border.widths.zw); + break; + case PST_BOTTOM: + vBorderStyle = int(border.style.w); + vHorizontalColor = border.colors[BORDER_BOTTOM]; + vVerticalColor = border.colors[BORDER_BOTTOM]; + vRadii = vec4(0.0); + break; + case PST_BOTTOM_LEFT: + vBorderStyle = int(border.style.w); + vHorizontalColor = border.colors[BORDER_BOTTOM]; + vVerticalColor = border.colors[BORDER_LEFT]; + vRadii = vec4(border.radii[1].zw, + border.radii[1].zw - border.widths.xw); + break; + } - float x0, y0, x1, y1; - vBorderPart = uint(border.part.x); - switch (vBorderPart) { + switch (sub_part) { // These are the layer tile part PrimitivePart as uploaded by the tiling.rs case PST_TOP_LEFT: - x0 = border.info.local_rect.x; - y0 = border.info.local_rect.y; + x0 = segment_rect.x; + y0 = segment_rect.y; // These are width / heights - x1 = border.info.local_rect.x + border.info.local_rect.z; - y1 = border.info.local_rect.y + border.info.local_rect.w; + x1 = segment_rect.x + segment_rect.z; + y1 = segment_rect.y + segment_rect.w; // The radius here is the border-radius. This is 0, so vRefPoint will // just be the top left (x,y) corner. vRefPoint = vec2(x0, y0) + vRadii.xy; break; case PST_TOP_RIGHT: - x0 = border.info.local_rect.x + border.info.local_rect.z; - y0 = border.info.local_rect.y; - x1 = border.info.local_rect.x; - y1 = border.info.local_rect.y + border.info.local_rect.w; + x0 = segment_rect.x + segment_rect.z; + y0 = segment_rect.y; + x1 = segment_rect.x; + y1 = segment_rect.y + segment_rect.w; vRefPoint = vec2(x0, y0) + vec2(-vRadii.x, vRadii.y); break; case PST_BOTTOM_LEFT: - x0 = border.info.local_rect.x; - y0 = border.info.local_rect.y + border.info.local_rect.w; - x1 = border.info.local_rect.x + border.info.local_rect.z; - y1 = border.info.local_rect.y; + x0 = segment_rect.x; + y0 = segment_rect.y + segment_rect.w; + x1 = segment_rect.x + segment_rect.z; + y1 = segment_rect.y; vRefPoint = vec2(x0, y0) + vec2(vRadii.x, -vRadii.y); break; case PST_BOTTOM_RIGHT: - x0 = border.info.local_rect.x; - y0 = border.info.local_rect.y; - x1 = border.info.local_rect.x + border.info.local_rect.z; - y1 = border.info.local_rect.y + border.info.local_rect.w; + x0 = segment_rect.x; + y0 = segment_rect.y; + x1 = segment_rect.x + segment_rect.z; + y1 = segment_rect.y + segment_rect.w; vRefPoint = vec2(x1, y1) + vec2(-vRadii.x, -vRadii.y); break; case PST_TOP: case PST_LEFT: case PST_BOTTOM: case PST_RIGHT: - vRefPoint = border.info.local_rect.xy; - x0 = border.info.local_rect.x; - y0 = border.info.local_rect.y; - x1 = border.info.local_rect.x + border.info.local_rect.z; - y1 = border.info.local_rect.y + border.info.local_rect.w; + vRefPoint = segment_rect.xy; + x0 = segment_rect.x; + y0 = segment_rect.y; + x1 = segment_rect.x + segment_rect.z; + y1 = segment_rect.y + segment_rect.w; break; } - vBorderStyle = uint(get_border_style(border, vBorderPart)); - // y1 - y0 is the height of the corner / line // x1 - x0 is the width of the corner / line. float width = x1 - x0; float height = y1 - y0; + vBorderPart = sub_part; vPieceRect = vec4(x0, y0, width, height); // The fragment shader needs to calculate the distance from the bisecting line @@ -109,11 +213,5 @@ void main(void) { #else vDistanceFromMixLine = (vi.local_clamped_pos.x - x0) * height - (vi.local_clamped_pos.y - y0) * width; - - // These are in device space - vDevicePos = vi.global_clamped_pos; - - // These are in device space - vBorders = border.info.local_rect * uDevicePixelRatio; #endif } diff --git a/webrender/res/ps_box_shadow.vs.glsl b/webrender/res/ps_box_shadow.vs.glsl index e501548f87..e863ab0a8f 100644 --- a/webrender/res/ps_box_shadow.vs.glsl +++ b/webrender/res/ps_box_shadow.vs.glsl @@ -4,8 +4,14 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ void main(void) { - BoxShadow bs = fetch_boxshadow(gl_InstanceID); - VertexInfo vi = write_vertex(bs.info); + Primitive prim = load_primitive(gl_InstanceID); + BoxShadow bs = fetch_boxshadow(prim.prim_index); + vec4 segment_rect = fetch_instance_geometry(prim.user_data.x + prim.user_data.y); + + VertexInfo vi = write_vertex(segment_rect, + prim.local_clip_rect, + prim.layer, + prim.tile); vPos = vi.local_clamped_pos; vColor = bs.color; diff --git a/webrender/res/ps_composite.vs.glsl b/webrender/res/ps_composite.vs.glsl index 115a7532be..3d2beadaf5 100644 --- a/webrender/res/ps_composite.vs.glsl +++ b/webrender/res/ps_composite.vs.glsl @@ -5,9 +5,9 @@ void main(void) { Composite composite = fetch_composite(gl_InstanceID); - Tile src0 = fetch_tile(int(composite.src0_src1_target_id.x)); - Tile src1 = fetch_tile(int(composite.src0_src1_target_id.y)); - Tile dest = fetch_tile(int(composite.src0_src1_target_id.z)); + Tile src0 = fetch_tile(composite.src0_src1_target_id.x); + Tile src1 = fetch_tile(composite.src0_src1_target_id.y); + Tile dest = fetch_tile(composite.src0_src1_target_id.z); vec2 local_pos = mix(vec2(dest.target_rect.xy), vec2(dest.target_rect.xy + dest.target_rect.zw), @@ -21,8 +21,8 @@ void main(void) { st1 = vec2(src1.target_rect.xy + src1.target_rect.zw) / 2048.0; vUv1 = mix(st0, st1, aPosition.xy); - vInfo = ivec2(composite.info_amount.xy); - vAmount = composite.info_amount.z; + vInfo = composite.info_amount.xy; + vAmount = composite.info_amount.z / 65535.0; gl_Position = uTransform * vec4(local_pos, 0, 1); } diff --git a/webrender/res/ps_gradient_clip.fs.glsl b/webrender/res/ps_gradient_clip.fs.glsl index f22194261c..b36e93083b 100644 --- a/webrender/res/ps_gradient_clip.fs.glsl +++ b/webrender/res/ps_gradient_clip.fs.glsl @@ -12,7 +12,7 @@ void main(void) { #endif alpha = min(alpha, do_clip(local_pos)); - oFragColor = mix(vColor0, vColor1, vF) * vec4(1, 1, 1, alpha); + oFragColor = vColor * vec4(1, 1, 1, alpha); #ifdef WR_FEATURE_TRANSFORM oFragColor.a *= alpha; diff --git a/webrender/res/ps_gradient_clip.glsl b/webrender/res/ps_gradient_clip.glsl index 160d506ce9..e1d1845363 100644 --- a/webrender/res/ps_gradient_clip.glsl +++ b/webrender/res/ps_gradient_clip.glsl @@ -2,9 +2,7 @@ * 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/. */ -flat varying vec4 vColor0; -flat varying vec4 vColor1; -varying float vF; +varying vec4 vColor; #ifdef WR_FEATURE_TRANSFORM varying vec3 vLocalPos; diff --git a/webrender/res/ps_gradient_clip.vs.glsl b/webrender/res/ps_gradient_clip.vs.glsl index e4bbeaf843..e24c9837e9 100644 --- a/webrender/res/ps_gradient_clip.vs.glsl +++ b/webrender/res/ps_gradient_clip.vs.glsl @@ -3,34 +3,70 @@ * 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/. */ -#define DIR_HORIZONTAL uint(0) -#define DIR_VERTICAL uint(1) - void main(void) { - AlignedGradient gradient = fetch_aligned_gradient(gl_InstanceID); + Primitive prim = load_primitive(gl_InstanceID); + Gradient gradient = fetch_gradient(prim.prim_index); + + int stop_index = prim.user_data.x + prim.user_data.y; + GradientStop g0 = fetch_gradient_stop(stop_index + 0); + GradientStop g1 = fetch_gradient_stop(stop_index + 1); + + vec4 segment_rect; + switch (int(gradient.kind.x)) { + case GRADIENT_HORIZONTAL: + float x0 = mix(gradient.start_end_point.x, + gradient.start_end_point.z, + g0.offset.x); + float x1 = mix(gradient.start_end_point.x, + gradient.start_end_point.z, + g1.offset.x); + segment_rect.yw = prim.local_rect.yw; + segment_rect.x = x0; + segment_rect.z = x1 - x0; + break; + case GRADIENT_VERTICAL: + float y0 = mix(gradient.start_end_point.y, + gradient.start_end_point.w, + g0.offset.x); + float y1 = mix(gradient.start_end_point.y, + gradient.start_end_point.w, + g1.offset.x); + segment_rect.xz = prim.local_rect.xz; + segment_rect.y = y0; + segment_rect.w = y1 - y0; + break; + } #ifdef WR_FEATURE_TRANSFORM - TransformVertexInfo vi = write_transform_vertex(gradient.info); + TransformVertexInfo vi = write_transform_vertex(segment_rect, + prim.local_clip_rect, + prim.layer, + prim.tile); vLocalRect = vi.clipped_local_rect; vLocalPos = vi.local_pos; - vec2 f = (vi.local_pos.xy - gradient.info.local_rect.xy) / gradient.info.local_rect.zw; + vec2 f = (vi.local_pos.xy - prim.local_rect.xy) / prim.local_rect.zw; #else - VertexInfo vi = write_vertex(gradient.info); - vec2 f = (vi.local_clamped_pos - gradient.info.local_rect.xy) / gradient.info.local_rect.zw; + VertexInfo vi = write_vertex(segment_rect, + prim.local_clip_rect, + prim.layer, + prim.tile); + + vec2 f = (vi.local_clamped_pos - segment_rect.xy) / segment_rect.zw; vPos = vi.local_clamped_pos; #endif - switch (uint(gradient.dir.x)) { - case DIR_HORIZONTAL: - vF = f.x; + switch (int(gradient.kind.x)) { + case GRADIENT_HORIZONTAL: + vColor = mix(g0.color, g1.color, f.x); break; - case DIR_VERTICAL: - vF = f.y; + case GRADIENT_VERTICAL: + vColor = mix(g0.color, g1.color, f.y); + break; + case GRADIENT_ROTATED: + vColor = vec4(1.0, 0.0, 1.0, 1.0); break; } - write_clip(gradient.clip); - - vColor0 = gradient.color0; - vColor1 = gradient.color1; + Clip clip = fetch_clip(prim.clip_index); + write_clip(clip); } diff --git a/webrender/res/ps_image.vs.glsl b/webrender/res/ps_image.vs.glsl index 1f5a997b0a..cb0500583a 100644 --- a/webrender/res/ps_image.vs.glsl +++ b/webrender/res/ps_image.vs.glsl @@ -4,16 +4,21 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ void main(void) { - Image image = fetch_image(gl_InstanceID); + Primitive prim = load_primitive(gl_InstanceID); + Image image = fetch_image(prim.prim_index); #ifdef WR_FEATURE_TRANSFORM - TransformVertexInfo vi = write_transform_vertex(image.info); + TransformVertexInfo vi = write_transform_vertex(prim.local_rect, + prim.local_clip_rect, + prim.layer, + prim.tile); vLocalRect = vi.clipped_local_rect; vLocalPos = vi.local_pos; - vStretchSize = image.stretch_size_and_tile_spacing.xy; #else - VertexInfo vi = write_vertex(image.info); - vStretchSize = image.stretch_size_and_tile_spacing.xy; + VertexInfo vi = write_vertex(prim.local_rect, + prim.local_clip_rect, + prim.layer, + prim.tile); vLocalPos = vi.local_clamped_pos - vi.local_rect.p0; #endif @@ -21,18 +26,14 @@ void main(void) { vec2 st0 = image.st_rect.xy; vec2 st1 = image.st_rect.zw; - switch (uint(image.uvkind.x)) { - case UV_NORMALIZED: - break; - case UV_PIXEL: { - vec2 texture_size = vec2(textureSize(sDiffuse, 0)); - st0 /= texture_size; - st1 /= texture_size; - } - break; + if (image.has_pixel_coords) { + vec2 texture_size = vec2(textureSize(sDiffuse, 0)); + st0 /= texture_size; + st1 /= texture_size; } vTextureSize = st1 - st0; vTextureOffset = st0; vTileSpacing = image.stretch_size_and_tile_spacing.zw; + vStretchSize = image.stretch_size_and_tile_spacing.xy; } diff --git a/webrender/res/ps_image_clip.glsl b/webrender/res/ps_image_clip.glsl index 02c4ff7850..20c0343182 100644 --- a/webrender/res/ps_image_clip.glsl +++ b/webrender/res/ps_image_clip.glsl @@ -1,3 +1,4 @@ +#line 1 /* 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/. */ diff --git a/webrender/res/ps_image_clip.vs.glsl b/webrender/res/ps_image_clip.vs.glsl index 6a12546ee1..cac9591d94 100644 --- a/webrender/res/ps_image_clip.vs.glsl +++ b/webrender/res/ps_image_clip.vs.glsl @@ -4,35 +4,40 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ void main(void) { - ImageClip image = fetch_image_clip(gl_InstanceID); + Primitive prim = load_primitive(gl_InstanceID); + Image image = fetch_image(prim.prim_index); #ifdef WR_FEATURE_TRANSFORM - TransformVertexInfo vi = write_transform_vertex(image.info); + TransformVertexInfo vi = write_transform_vertex(prim.local_rect, + prim.local_clip_rect, + prim.layer, + prim.tile); + vLocalRect = vi.clipped_local_rect; vLocalPos = vi.local_pos; #else - VertexInfo vi = write_vertex(image.info); + VertexInfo vi = write_vertex(prim.local_rect, + prim.local_clip_rect, + prim.layer, + prim.tile); + vLocalRect = prim.local_rect; vLocalPos = vi.local_clamped_pos; - vLocalRect = image.info.local_rect; #endif - write_clip(image.clip); + Clip clip = fetch_clip(prim.clip_index); + write_clip(clip); + // vUv will contain how many times this image has wrapped around the image size. vec2 st0 = image.st_rect.xy; vec2 st1 = image.st_rect.zw; - switch (uint(image.uvkind.x)) { - case UV_NORMALIZED: - break; - case UV_PIXEL: { - vec2 texture_size = vec2(textureSize(sDiffuse, 0)); - st0 /= texture_size; - st1 /= texture_size; - } - break; + if (image.has_pixel_coords) { + vec2 texture_size = vec2(textureSize(sDiffuse, 0)); + st0 /= texture_size; + st1 /= texture_size; } vTextureSize = st1 - st0; vTextureOffset = st0; - vStretchSize = image.stretch_size_and_tile_spacing.xy; vTileSpacing = image.stretch_size_and_tile_spacing.zw; + vStretchSize = image.stretch_size_and_tile_spacing.xy; } diff --git a/webrender/res/ps_rectangle.vs.glsl b/webrender/res/ps_rectangle.vs.glsl index ba5ccbb69d..0c886b6fc4 100644 --- a/webrender/res/ps_rectangle.vs.glsl +++ b/webrender/res/ps_rectangle.vs.glsl @@ -4,13 +4,20 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ void main(void) { - Rectangle rect = fetch_rectangle(gl_InstanceID); + Primitive prim = load_primitive(gl_InstanceID); + Rectangle rect = fetch_rectangle(prim.prim_index); vColor = rect.color; #ifdef WR_FEATURE_TRANSFORM - TransformVertexInfo vi = write_transform_vertex(rect.info); + TransformVertexInfo vi = write_transform_vertex(prim.local_rect, + prim.local_clip_rect, + prim.layer, + prim.tile); vLocalRect = vi.clipped_local_rect; vLocalPos = vi.local_pos; #else - write_vertex(rect.info); + write_vertex(prim.local_rect, + prim.local_clip_rect, + prim.layer, + prim.tile); #endif } diff --git a/webrender/res/ps_rectangle_clip.vs.glsl b/webrender/res/ps_rectangle_clip.vs.glsl index 90bb0ee4f5..7f58e82902 100644 --- a/webrender/res/ps_rectangle_clip.vs.glsl +++ b/webrender/res/ps_rectangle_clip.vs.glsl @@ -4,18 +4,24 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ void main(void) { - RectangleClip rect = fetch_rectangle_clip(gl_InstanceID); - + Primitive prim = load_primitive(gl_InstanceID); + Rectangle rect = fetch_rectangle(prim.prim_index); + vColor = rect.color; #ifdef WR_FEATURE_TRANSFORM - TransformVertexInfo vi = write_transform_vertex(rect.info); - vPos = vi.local_pos; + TransformVertexInfo vi = write_transform_vertex(prim.local_rect, + prim.local_clip_rect, + prim.layer, + prim.tile); vLocalRect = vi.clipped_local_rect; + vPos = vi.local_pos; #else - VertexInfo vi = write_vertex(rect.info); + VertexInfo vi = write_vertex(prim.local_rect, + prim.local_clip_rect, + prim.layer, + prim.tile); vPos = vi.local_clamped_pos; #endif - write_clip(rect.clip); - - vColor = rect.color; + Clip clip = fetch_clip(prim.clip_index); + write_clip(clip); } diff --git a/webrender/res/ps_text_run.vs.glsl b/webrender/res/ps_text_run.vs.glsl index 1c229d6f37..c296073f04 100644 --- a/webrender/res/ps_text_run.vs.glsl +++ b/webrender/res/ps_text_run.vs.glsl @@ -4,23 +4,31 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ void main(void) { - vec4 color, uv_rect; - PrimitiveInfo info = fetch_text_run_glyph(gl_InstanceID, color, uv_rect); + Primitive prim = load_primitive(gl_InstanceID); + TextRun text = fetch_text_run(prim.prim_index); + Glyph glyph = fetch_glyph(prim.user_data.x + prim.user_data.y); + vec4 local_rect = vec4(glyph.offset.xy, (glyph.uv_rect.zw - glyph.uv_rect.xy) / uDevicePixelRatio); #ifdef WR_FEATURE_TRANSFORM - TransformVertexInfo vi = write_transform_vertex(info); + TransformVertexInfo vi = write_transform_vertex(local_rect, + prim.local_clip_rect, + prim.layer, + prim.tile); vLocalRect = vi.clipped_local_rect; vLocalPos = vi.local_pos; - vec2 f = (vi.local_pos.xy - info.local_rect.xy) / info.local_rect.zw; + vec2 f = (vi.local_pos.xy - prim.local_rect.xy) / prim.local_rect.zw; #else - VertexInfo vi = write_vertex(info); + VertexInfo vi = write_vertex(local_rect, + prim.local_clip_rect, + prim.layer, + prim.tile); vec2 f = (vi.local_clamped_pos - vi.local_rect.p0) / (vi.local_rect.p1 - vi.local_rect.p0); #endif vec2 texture_size = vec2(textureSize(sDiffuse, 0)); - vec2 st0 = uv_rect.xy / texture_size; - vec2 st1 = uv_rect.zw / texture_size; + vec2 st0 = glyph.uv_rect.xy / texture_size; + vec2 st1 = glyph.uv_rect.zw / texture_size; - vColor = color; + vColor = text.color; vUv = mix(st0, st1, f); } diff --git a/webrender/src/device.rs b/webrender/src/device.rs index dac4ab3700..240f338f8b 100644 --- a/webrender/src/device.rs +++ b/webrender/src/device.rs @@ -760,7 +760,7 @@ impl FileWatcherThread { pub struct Device { // device state - bound_textures: [TextureId; 5], + bound_textures: [TextureId; 16], bound_program: ProgramId, bound_vao: VAOId, bound_fbo: FBOId, @@ -804,13 +804,7 @@ impl Device { device_pixel_ratio: device_pixel_ratio, inside_frame: false, - bound_textures: [ - TextureId(0), - TextureId(0), - TextureId(0), - TextureId(0), - TextureId(0), - ], + bound_textures: [ TextureId(0); 16 ], bound_program: ProgramId(0), bound_vao: VAOId(0), bound_fbo: FBOId(0), @@ -1323,6 +1317,31 @@ impl Device { if u_tasks != -1 { gl::uniform_1i(u_tasks, TextureSampler::RenderTasks as i32); } + + let u_prim_geom = gl::get_uniform_location(program.id, "sPrimGeometry"); + if u_prim_geom != -1 { + gl::uniform_1i(u_prim_geom, TextureSampler::Geometry as i32); + } + + let u_data16 = gl::get_uniform_location(program.id, "sData16"); + if u_data16 != -1 { + gl::uniform_1i(u_data16, TextureSampler::Data16 as i32); + } + + let u_data32 = gl::get_uniform_location(program.id, "sData32"); + if u_data32 != -1 { + gl::uniform_1i(u_data32, TextureSampler::Data32 as i32); + } + + let u_data64 = gl::get_uniform_location(program.id, "sData64"); + if u_data64 != -1 { + gl::uniform_1i(u_data64, TextureSampler::Data64 as i32); + } + + let u_data128 = gl::get_uniform_location(program.id, "sData128"); + if u_data128 != -1 { + gl::uniform_1i(u_data128, TextureSampler::Data128 as i32); + } } } } diff --git a/webrender/src/frame.rs b/webrender/src/frame.rs index 79af006dcc..2833340dc1 100644 --- a/webrender/src/frame.rs +++ b/webrender/src/frame.rs @@ -11,11 +11,12 @@ use internal_types::{CompositionOp}; use internal_types::{LowLevelFilterOp}; use internal_types::{RendererFrame}; use layer::{Layer, ScrollingState}; +use prim_store::Clip; use resource_cache::ResourceCache; use scene::{SceneStackingContext, ScenePipeline, Scene, SceneItem, SpecificSceneItem}; use std::collections::{HashMap, HashSet}; use std::hash::BuildHasherDefault; -use tiling::{Clip, FrameBuilder, FrameBuilderConfig, InsideTest, PrimitiveFlags}; +use tiling::{FrameBuilder, FrameBuilderConfig, InsideTest, PrimitiveFlags}; use util::MatrixHelpers; use webrender_traits::{AuxiliaryLists, PipelineId, Epoch, ScrollPolicy, ScrollLayerId}; use webrender_traits::{ColorF, StackingContext, FilterOp, MixBlendMode}; diff --git a/webrender/src/gpu_store.rs b/webrender/src/gpu_store.rs new file mode 100644 index 0000000000..78cc0802fa --- /dev/null +++ b/webrender/src/gpu_store.rs @@ -0,0 +1,93 @@ +/* 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/. */ + +use renderer::MAX_VERTEX_TEXTURE_WIDTH; +use std::mem; + +#[derive(Debug, Copy, Clone)] +pub struct GpuStoreAddress(pub i32); + +pub struct GpuStore { + data: Vec, + // TODO(gw): Could store this intrusively inside + // the data array free slots. + //free_list: Vec, +} + +impl GpuStore { + pub fn new() -> GpuStore { + GpuStore { + data: Vec::new(), + //free_list: Vec::new(), + } + } + + pub fn push(&mut self, data: E) -> GpuStoreAddress where T: From { + let address = GpuStoreAddress(self.data.len() as i32); + self.data.push(T::from(data)); + address + } + + // TODO(gw): Change this to do incremental updates, which means + // there is no need to copy all this data during every scroll! + pub fn build(&self) -> Vec { + let item_size = mem::size_of::(); + debug_assert!(item_size % 16 == 0); + let vecs_per_item = item_size / 16; + let items_per_row = MAX_VERTEX_TEXTURE_WIDTH / vecs_per_item; + + let mut items = self.data.clone(); + + // Extend the data array to be a multiple of the row size. + // This ensures memory safety when the array is passed to + // OpenGL to upload to the GPU. + while items.len() % items_per_row != 0 { + items.push(T::default()); + } + + items + } + + pub fn alloc(&mut self, count: usize) -> GpuStoreAddress { + let address = self.get_next_address(); + + for _ in 0..count { + self.data.push(T::default()); + } + + address + } + + pub fn get_next_address(&self) -> GpuStoreAddress { + GpuStoreAddress(self.data.len() as i32) + } + + pub fn get(&mut self, address: GpuStoreAddress) -> &T { + &self.data[address.0 as usize] + } + + pub fn get_mut(&mut self, address: GpuStoreAddress) -> &mut T { + &mut self.data[address.0 as usize] + } + + pub fn get_slice_mut(&mut self, + address: GpuStoreAddress, + count: usize) -> &mut [T] { + let offset = address.0 as usize; + &mut self.data[offset..offset + count] + } + + // TODO(gw): Implement incremental updates of + // GPU backed data, and support freelist for removing + // dynamic items. + + /* + pub fn free(&mut self, address: GpuStoreAddress) { + + } + + pub fn update(&mut self, address: GpuStoreAddress, data: T) { + + }*/ +} diff --git a/webrender/src/internal_types.rs b/webrender/src/internal_types.rs index 98737839a5..5168ee7fd8 100644 --- a/webrender/src/internal_types.rs +++ b/webrender/src/internal_types.rs @@ -197,8 +197,13 @@ pub enum TextureSampler { Color, Mask, Cache, + Data16, + Data32, + Data64, + Data128, Layers, RenderTasks, + Geometry, } pub enum VertexAttribute { diff --git a/webrender/src/lib.rs b/webrender/src/lib.rs index 84d33c875d..e9b82f5901 100644 --- a/webrender/src/lib.rs +++ b/webrender/src/lib.rs @@ -55,8 +55,10 @@ mod device; mod frame; mod freelist; mod geometry; +mod gpu_store; mod internal_types; mod layer; +mod prim_store; mod profiler; mod record; mod render_backend; diff --git a/webrender/src/prim_store.rs b/webrender/src/prim_store.rs new file mode 100644 index 0000000000..7a305f7df7 --- /dev/null +++ b/webrender/src/prim_store.rs @@ -0,0 +1,922 @@ +/* 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/. */ + +use app_units::Au; +use device::TextureId; +use euclid::{Point2D, Matrix4D, Rect, Size2D}; +use frame::FrameId; +use gpu_store::{GpuStore, GpuStoreAddress}; +use internal_types::{DevicePixel, Glyph}; +use renderer::BLUR_INFLATION_FACTOR; +use resource_cache::ResourceCache; +use resource_list::ResourceList; +use std::mem; +use std::usize; +use util::TransformedRect; +use webrender_traits::{AuxiliaryLists, ColorF, ImageKey, ImageRendering, WebGLContextId}; +use webrender_traits::{FontKey, ItemRange, ComplexClipRegion, GlyphKey}; + +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] +pub struct SpecificPrimitiveIndex(pub usize); + +impl SpecificPrimitiveIndex { + pub fn invalid() -> SpecificPrimitiveIndex { + SpecificPrimitiveIndex(usize::MAX) + } +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] +pub struct PrimitiveIndex(pub usize); + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub enum PrimitiveKind { + Rectangle, + TextRun, + Image, + Border, + Gradient, + BoxShadow, +} + +#[derive(Debug, Clone)] +pub struct PrimitiveGeometry { + pub local_rect: Rect, + pub local_clip_rect: Rect, +} + +// TODO(gw): Pack the fields here better! +#[derive(Debug)] +pub struct PrimitiveMetadata { + pub is_opaque: bool, + pub need_to_build_cache: bool, + pub color_texture_id: TextureId, + pub clip_index: Option, + pub prim_kind: PrimitiveKind, + pub cpu_prim_index: SpecificPrimitiveIndex, + pub gpu_prim_index: GpuStoreAddress, + pub gpu_data_address: GpuStoreAddress, + pub gpu_data_count: i32, +} + +#[derive(Debug, Clone, Copy)] +pub enum TextureCoordKind { + Normalized = 0, + Pixel, +} + +#[derive(Debug, Clone)] +pub struct RectanglePrimitive { + pub color: ColorF, +} + +#[derive(Debug)] +pub enum ImagePrimitiveKind { + Image(ImageKey, ImageRendering, Size2D, Size2D), + WebGL(WebGLContextId), +} + +#[derive(Debug)] +pub struct ImagePrimitiveCpu { + pub kind: ImagePrimitiveKind, +} + +#[derive(Debug, Clone)] +pub struct ImagePrimitiveGpu { + pub uv0: Point2D, + pub uv1: Point2D, + pub stretch_size: Size2D, + pub tile_spacing: Size2D, +} + +#[derive(Debug, Clone)] +pub struct BorderPrimitiveCpu { + pub inner_rect: Rect, +} + +#[derive(Debug, Clone)] +pub struct BorderPrimitiveGpu { + pub style: [f32; 4], + pub widths: [f32; 4], + pub colors: [ColorF; 4], + pub radii: [Size2D; 4], +} + +#[derive(Debug, Clone)] +pub struct BoxShadowPrimitive { + pub src_rect: Rect, + pub bs_rect: Rect, + pub color: ColorF, + pub border_radii: Point2D, + pub blur_radius: f32, + pub inverted: f32, +} + +#[repr(u32)] +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub enum GradientType { + Horizontal, + Vertical, + Rotated, +} + +#[derive(Debug, Clone)] +pub struct GradientStop { + pub color: ColorF, + pub offset: f32, + pub padding: [f32; 3], +} + +#[derive(Debug, Clone)] +pub struct GradientPrimitiveGpu { + pub start_point: Point2D, + pub end_point: Point2D, + pub kind: f32, + pub padding: [f32; 3], +} + +#[derive(Debug)] +pub struct GradientPrimitiveCpu { + pub stops_range: ItemRange, + pub kind: GradientType, + pub reverse_stops: bool, +} + +#[derive(Debug, Clone)] +pub struct InstanceRect { + pub rect: Rect, +} + +#[derive(Debug, Clone)] +pub struct TextRunPrimitiveGpu { + pub color: ColorF, +} + +#[derive(Debug, Clone)] +pub struct TextRunPrimitiveCpu { + pub font_key: FontKey, + pub font_size: Au, + pub blur_radius: Au, + pub glyph_range: ItemRange, +} + +#[derive(Debug, Clone)] +pub struct GlyphPrimitive { + pub offset: Point2D, + pub padding: Point2D, + pub uv0: Point2D, + pub uv1: Point2D, +} + +#[derive(Debug, Clone)] +pub struct ClipRect { + pub rect: Rect, + pub padding: [f32; 4], +} + +#[derive(Debug, Clone)] +pub struct ClipCorner { + pub rect: Rect, + pub outer_radius_x: f32, + pub outer_radius_y: f32, + pub inner_radius_x: f32, + pub inner_radius_y: f32, +} + +impl ClipCorner { + pub fn invalid(rect: Rect) -> ClipCorner { + ClipCorner { + rect: rect, + outer_radius_x: 0.0, + outer_radius_y: 0.0, + inner_radius_x: 0.0, + inner_radius_y: 0.0, + } + } + + pub fn uniform(rect: Rect, outer_radius: f32, inner_radius: f32) -> ClipCorner { + ClipCorner { + rect: rect, + outer_radius_x: outer_radius, + outer_radius_y: outer_radius, + inner_radius_x: inner_radius, + inner_radius_y: inner_radius, + } + } +} + +#[derive(Debug, Clone)] +pub struct Clip { + pub rect: ClipRect, + pub top_left: ClipCorner, + pub top_right: ClipCorner, + pub bottom_left: ClipCorner, + pub bottom_right: ClipCorner, +} + +impl Clip { + pub fn from_clip_region(clip: &ComplexClipRegion) -> Clip { + Clip { + rect: ClipRect { + rect: clip.rect, + padding: [0.0, 0.0, 0.0, 0.0], + }, + top_left: ClipCorner { + rect: Rect::new(Point2D::new(clip.rect.origin.x, clip.rect.origin.y), + Size2D::new(clip.radii.top_left.width, clip.radii.top_left.height)), + outer_radius_x: clip.radii.top_left.width, + outer_radius_y: clip.radii.top_left.height, + inner_radius_x: 0.0, + inner_radius_y: 0.0, + }, + top_right: ClipCorner { + rect: Rect::new(Point2D::new(clip.rect.origin.x + clip.rect.size.width - clip.radii.top_right.width, + clip.rect.origin.y), + Size2D::new(clip.radii.top_right.width, clip.radii.top_right.height)), + outer_radius_x: clip.radii.top_right.width, + outer_radius_y: clip.radii.top_right.height, + inner_radius_x: 0.0, + inner_radius_y: 0.0, + }, + bottom_left: ClipCorner { + rect: Rect::new(Point2D::new(clip.rect.origin.x, + clip.rect.origin.y + clip.rect.size.height - clip.radii.bottom_left.height), + Size2D::new(clip.radii.bottom_left.width, clip.radii.bottom_left.height)), + outer_radius_x: clip.radii.bottom_left.width, + outer_radius_y: clip.radii.bottom_left.height, + inner_radius_x: 0.0, + inner_radius_y: 0.0, + }, + bottom_right: ClipCorner { + rect: Rect::new(Point2D::new(clip.rect.origin.x + clip.rect.size.width - clip.radii.bottom_right.width, + clip.rect.origin.y + clip.rect.size.height - clip.radii.bottom_right.height), + Size2D::new(clip.radii.bottom_right.width, clip.radii.bottom_right.height)), + outer_radius_x: clip.radii.bottom_right.width, + outer_radius_y: clip.radii.bottom_right.height, + inner_radius_x: 0.0, + inner_radius_y: 0.0, + }, + } + } + + pub fn invalid(rect: Rect) -> Clip { + Clip { + rect: ClipRect { + rect: rect, + padding: [0.0; 4], + }, + top_left: ClipCorner::invalid(rect), + top_right: ClipCorner::invalid(rect), + bottom_left: ClipCorner::invalid(rect), + bottom_right: ClipCorner::invalid(rect), + } + } + + pub fn uniform(rect: Rect, radius: f32) -> Clip { + Clip { + rect: ClipRect { + rect: rect, + padding: [0.0; 4], + }, + top_left: ClipCorner::uniform(Rect::new(Point2D::new(rect.origin.x, + rect.origin.y), + Size2D::new(radius, radius)), + radius, + 0.0), + top_right: ClipCorner::uniform(Rect::new(Point2D::new(rect.origin.x + rect.size.width - radius, + rect.origin.y), + Size2D::new(radius, radius)), + radius, + 0.0), + bottom_left: ClipCorner::uniform(Rect::new(Point2D::new(rect.origin.x, + rect.origin.y + rect.size.height - radius), + Size2D::new(radius, radius)), + radius, + 0.0), + bottom_right: ClipCorner::uniform(Rect::new(Point2D::new(rect.origin.x + rect.size.width - radius, + rect.origin.y + rect.size.height - radius), + Size2D::new(radius, radius)), + radius, + 0.0), + } + } +} + +#[derive(Debug)] +pub enum PrimitiveContainer { + Rectangle(RectanglePrimitive), + TextRun(TextRunPrimitiveCpu, TextRunPrimitiveGpu), + Image(ImagePrimitiveCpu), + Border(BorderPrimitiveCpu, BorderPrimitiveGpu), + Gradient(GradientPrimitiveCpu, GradientPrimitiveGpu), + BoxShadow(BoxShadowPrimitive, Vec>), +} + +pub struct PrimitiveStore { + // CPU side information only + pub cpu_bounding_rects: Vec>>, + pub cpu_text_runs: Vec, + pub cpu_images: Vec, + pub cpu_gradients: Vec, + pub cpu_metadata: Vec, + pub cpu_borders: Vec, + + // Gets uploaded directly to GPU via vertex texture + pub gpu_geometry: GpuStore, + pub gpu_data16: GpuStore, + pub gpu_data32: GpuStore, + pub gpu_data64: GpuStore, + pub gpu_data128: GpuStore, +} + +impl PrimitiveStore { + pub fn new() -> PrimitiveStore { + PrimitiveStore { + cpu_metadata: Vec::new(), + cpu_bounding_rects: Vec::new(), + cpu_text_runs: Vec::new(), + cpu_images: Vec::new(), + cpu_gradients: Vec::new(), + cpu_borders: Vec::new(), + gpu_geometry: GpuStore::new(), + gpu_data16: GpuStore::new(), + gpu_data32: GpuStore::new(), + gpu_data64: GpuStore::new(), + gpu_data128: GpuStore::new(), + } + } + + pub fn add_primitive(&mut self, + rect: &Rect, + clip_rect: &Rect, + clip: Option>, + container: PrimitiveContainer) -> PrimitiveIndex { + let prim_index = self.cpu_metadata.len(); + + self.cpu_bounding_rects.push(None); + + self.gpu_geometry.push(PrimitiveGeometry { + local_rect: *rect, + local_clip_rect: *clip_rect, + }); + + let mut clip_index = None; + if let Some(clip) = clip { + // TODO(gw): This is slightly inefficient. It + // pushes default data on when we already have + // the data we need to push on available now. + let gpu_address = self.gpu_data32.alloc(5); + let clip_data = self.gpu_data32.get_slice_mut(gpu_address, 5); + clip_data[0] = GpuBlock32::from(clip.rect.clone()); + clip_data[1] = GpuBlock32::from(clip.top_left.clone()); + clip_data[2] = GpuBlock32::from(clip.top_right.clone()); + clip_data[3] = GpuBlock32::from(clip.bottom_left.clone()); + clip_data[4] = GpuBlock32::from(clip.bottom_right.clone()); + clip_index = Some(gpu_address); + } + + let metadata = match container { + PrimitiveContainer::Rectangle(rect) => { + let is_opaque = rect.color.a == 1.0; + let gpu_address = self.gpu_data16.push(rect); + + let metadata = PrimitiveMetadata { + is_opaque: is_opaque, + need_to_build_cache: false, + color_texture_id: TextureId(0), + clip_index: clip_index, + prim_kind: PrimitiveKind::Rectangle, + cpu_prim_index: SpecificPrimitiveIndex::invalid(), + gpu_prim_index: gpu_address, + gpu_data_address: GpuStoreAddress(0), + gpu_data_count: 0, + }; + + metadata + } + PrimitiveContainer::TextRun(text_cpu, text_gpu) => { + let gpu_address = self.gpu_data16.push(text_gpu); + let gpu_glyphs_address = self.gpu_data32.alloc(text_cpu.glyph_range.length); + + let metadata = PrimitiveMetadata { + is_opaque: false, + need_to_build_cache: true, + color_texture_id: TextureId(0), + clip_index: clip_index, + prim_kind: PrimitiveKind::TextRun, + cpu_prim_index: SpecificPrimitiveIndex(self.cpu_text_runs.len()), + gpu_prim_index: gpu_address, + gpu_data_address: gpu_glyphs_address, + gpu_data_count: text_cpu.glyph_range.length as i32, + }; + + self.cpu_text_runs.push(text_cpu); + metadata + } + PrimitiveContainer::Image(image_cpu) => { + let gpu_address = self.gpu_data32.alloc(1); + + let metadata = PrimitiveMetadata { + is_opaque: false, + need_to_build_cache: true, + color_texture_id: TextureId(0), + clip_index: clip_index, + prim_kind: PrimitiveKind::Image, + cpu_prim_index: SpecificPrimitiveIndex(self.cpu_images.len()), + gpu_prim_index: gpu_address, + gpu_data_address: GpuStoreAddress(0), + gpu_data_count: 0, + }; + + self.cpu_images.push(image_cpu); + metadata + } + PrimitiveContainer::Border(border_cpu, border_gpu) => { + let gpu_address = self.gpu_data128.push(border_gpu); + + let metadata = PrimitiveMetadata { + is_opaque: false, + need_to_build_cache: false, + color_texture_id: TextureId(0), + clip_index: clip_index, + prim_kind: PrimitiveKind::Border, + cpu_prim_index: SpecificPrimitiveIndex(self.cpu_borders.len()), + gpu_prim_index: gpu_address, + gpu_data_address: GpuStoreAddress(0), + gpu_data_count: 0, + }; + + self.cpu_borders.push(border_cpu); + metadata + } + PrimitiveContainer::Gradient(gradient_cpu, gradient_gpu) => { + let gpu_address = self.gpu_data32.push(gradient_gpu); + let gpu_stops_address = self.gpu_data32.alloc(gradient_cpu.stops_range.length); + + let metadata = PrimitiveMetadata { + is_opaque: false, + need_to_build_cache: true, + color_texture_id: TextureId(0), + clip_index: clip_index, + prim_kind: PrimitiveKind::Gradient, + cpu_prim_index: SpecificPrimitiveIndex(self.cpu_gradients.len()), + gpu_prim_index: gpu_address, + gpu_data_address: gpu_stops_address, + gpu_data_count: gradient_cpu.stops_range.length as i32, + }; + + self.cpu_gradients.push(gradient_cpu); + metadata + } + PrimitiveContainer::BoxShadow(box_shadow, instance_rects) => { + let gpu_prim_address = self.gpu_data64.push(box_shadow); + let gpu_data_address = self.gpu_data16.get_next_address(); + + let metadata = PrimitiveMetadata { + is_opaque: false, + need_to_build_cache: false, + color_texture_id: TextureId(0), + clip_index: clip_index, + prim_kind: PrimitiveKind::BoxShadow, + cpu_prim_index: SpecificPrimitiveIndex::invalid(), + gpu_prim_index: gpu_prim_address, + gpu_data_address: gpu_data_address, + gpu_data_count: instance_rects.len() as i32, + }; + + for rect in instance_rects { + self.gpu_data16.push(InstanceRect { + rect: rect, + }); + } + + metadata + } + }; + + self.cpu_metadata.push(metadata); + + PrimitiveIndex(prim_index) + } + + pub fn get_bounding_rect(&self, index: PrimitiveIndex) -> &Option> { + &self.cpu_bounding_rects[index.0] + } + + pub fn set_complex_clip(&mut self, index: PrimitiveIndex, clip: Option) { + let metadata = &mut self.cpu_metadata[index.0]; + + match (metadata.clip_index, clip) { + (Some(clip_index), Some(clip)) => { + let clip_data = self.gpu_data32.get_slice_mut(clip_index, 5); + clip_data[0] = GpuBlock32::from(clip.rect); + clip_data[1] = GpuBlock32::from(clip.top_left); + clip_data[2] = GpuBlock32::from(clip.top_right); + clip_data[3] = GpuBlock32::from(clip.bottom_left); + clip_data[4] = GpuBlock32::from(clip.bottom_right); + } + (Some(..), None) => { + // TODO(gw): Add to clip free list! + metadata.clip_index = None; + } + (None, Some(clip)) => { + // TODO(gw): Pull from clip free list! + let gpu_address = self.gpu_data32.alloc(5); + let clip_data = self.gpu_data32.get_slice_mut(gpu_address, 5); + clip_data[0] = GpuBlock32::from(clip.rect); + clip_data[1] = GpuBlock32::from(clip.top_left); + clip_data[2] = GpuBlock32::from(clip.top_right); + clip_data[3] = GpuBlock32::from(clip.bottom_left); + clip_data[4] = GpuBlock32::from(clip.bottom_right); + metadata.clip_index = Some(gpu_address); + } + (None, None) => {} + } + } + + pub fn get_metadata(&self, index: PrimitiveIndex) -> &PrimitiveMetadata { + &self.cpu_metadata[index.0] + } + + pub fn prim_count(&self) -> usize { + self.cpu_metadata.len() + } + + pub fn build_resource_list(&mut self, + index: PrimitiveIndex, + resource_list: &mut ResourceList, + auxiliary_lists: &AuxiliaryLists) -> bool { + let metadata = &self.cpu_metadata[index.0]; + + match metadata.prim_kind { + PrimitiveKind::Rectangle | + PrimitiveKind::Border | + PrimitiveKind::Gradient | + PrimitiveKind::BoxShadow => {} + + PrimitiveKind::TextRun => { + let text = &self.cpu_text_runs[metadata.cpu_prim_index.0]; + let glyphs = auxiliary_lists.glyph_instances(&text.glyph_range); + for glyph in glyphs { + let glyph = Glyph::new(text.font_size, text.blur_radius, glyph.index); + resource_list.add_glyph(text.font_key, glyph); + } + } + PrimitiveKind::Image => { + let image = &self.cpu_images[metadata.cpu_prim_index.0]; + match image.kind { + ImagePrimitiveKind::Image(image_key, image_rendering, _, _) => { + resource_list.add_image(image_key, image_rendering); + } + ImagePrimitiveKind::WebGL(..) => {} + } + } + } + + self.cpu_metadata[index.0].need_to_build_cache + } + + pub fn build_bounding_rect(&mut self, + prim_index: PrimitiveIndex, + screen_rect: &Rect, + layer_transform: &Matrix4D, + layer_combined_local_clip_rect: &Rect, + device_pixel_ratio: f32) -> bool { + let mut bounding_rect = None; + let mut visible = false; + let geom = &self.gpu_geometry.get(GpuStoreAddress(prim_index.0 as i32)); + + match geom.local_rect + .intersection(&geom.local_clip_rect) + .and_then(|rect| rect.intersection(layer_combined_local_clip_rect)) { + Some(local_rect) => { + let xf_rect = TransformedRect::new(&local_rect, + layer_transform, + device_pixel_ratio); + if xf_rect.bounding_rect + .intersects(screen_rect) { + bounding_rect = Some(xf_rect.bounding_rect); + visible = true; + } + } + None => {} + }; + + self.cpu_bounding_rects[prim_index.0] = bounding_rect; + visible + } + + pub fn prepare_prim_for_render(&mut self, + prim_index: PrimitiveIndex, + resource_cache: &ResourceCache, + frame_id: FrameId, + device_pixel_ratio: f32, + auxiliary_lists: &AuxiliaryLists) -> bool { + let metadata = &mut self.cpu_metadata[prim_index.0]; + debug_assert!(metadata.need_to_build_cache); + metadata.need_to_build_cache = false; + + match metadata.prim_kind { + PrimitiveKind::TextRun => { + let text = &self.cpu_text_runs[metadata.cpu_prim_index.0]; + debug_assert!(metadata.gpu_data_count == text.glyph_range.length as i32); + let dest_glyphs = self.gpu_data32.get_slice_mut(metadata.gpu_data_address, + text.glyph_range.length); + let src_glyphs = auxiliary_lists.glyph_instances(&text.glyph_range); + let mut glyph_key = GlyphKey::new(text.font_key, + text.font_size, + text.blur_radius, + src_glyphs[0].index); + let blur_offset = text.blur_radius.to_f32_px() * + (BLUR_INFLATION_FACTOR as f32) / 2.0; + let mut local_rect = Rect::zero(); + let mut actual_glyph_count = 0; + + for src in src_glyphs { + glyph_key.index = src.index; + + let image_info = match resource_cache.get_glyph(&glyph_key, frame_id) { + None => continue, + Some(image_info) => image_info, + }; + + debug_assert!(metadata.color_texture_id == TextureId(0) || + metadata.color_texture_id == image_info.texture_id); + metadata.color_texture_id = image_info.texture_id; + + let x = src.x + image_info.user_data.x0 as f32 / device_pixel_ratio - + blur_offset; + let y = src.y - image_info.user_data.y0 as f32 / device_pixel_ratio - + blur_offset; + + let width = image_info.requested_rect.size.width as f32 / + device_pixel_ratio; + let height = image_info.requested_rect.size.height as f32 / + device_pixel_ratio; + + let local_glyph_rect = Rect::new(Point2D::new(x, y), + Size2D::new(width, height)); + local_rect = local_rect.union(&local_glyph_rect); + + dest_glyphs[actual_glyph_count] = GpuBlock32::from(GlyphPrimitive { + offset: local_glyph_rect.origin, + uv0: Point2D::new(image_info.pixel_rect.top_left.x.0 as f32, + image_info.pixel_rect.top_left.y.0 as f32), + uv1: Point2D::new(image_info.pixel_rect.bottom_right.x.0 as f32, + image_info.pixel_rect.bottom_right.y.0 as f32), + padding: Point2D::zero(), + }); + + actual_glyph_count += 1; + } + + metadata.gpu_data_count = actual_glyph_count as i32; + self.gpu_geometry.get_mut(GpuStoreAddress(prim_index.0 as i32)).local_rect = local_rect; + true + } + PrimitiveKind::Image => { + let image_cpu = &self.cpu_images[metadata.cpu_prim_index.0]; + let geom = self.gpu_geometry.get(GpuStoreAddress(prim_index.0 as i32)); + + let ImageInfo { + color_texture_id: texture_id, + uv0, + mut uv1, + stretch_size, + tile_spacing, + uv_kind, + is_opaque, + } = image_cpu.image_info(resource_cache, frame_id); + + metadata.color_texture_id = texture_id; + metadata.is_opaque = is_opaque; + + match uv_kind { + TextureCoordKind::Normalized => {} + TextureCoordKind::Pixel => uv1.x = -uv1.x, + } + + let image_gpu = self.gpu_data32.get_mut(metadata.gpu_prim_index); + *image_gpu = GpuBlock32::from(ImagePrimitiveGpu { + uv0: uv0, + uv1: uv1, + stretch_size: stretch_size.unwrap_or(geom.local_rect.size), + tile_spacing: tile_spacing, + }); + + false + } + PrimitiveKind::Gradient => { + let gradient = &self.cpu_gradients[metadata.cpu_prim_index.0]; + let src_stops = auxiliary_lists.gradient_stops(&gradient.stops_range); + + debug_assert!(metadata.gpu_data_count == gradient.stops_range.length as i32); + let dest_stops = self.gpu_data32.get_slice_mut(metadata.gpu_data_address, + gradient.stops_range.length); + + if gradient.reverse_stops { + for (src, dest) in src_stops.iter().rev().zip(dest_stops.iter_mut()) { + *dest = GpuBlock32::from(GradientStop { + offset: 1.0 - src.offset, + color: src.color, + padding: [0.0; 3], + }); + } + } else { + for (src, dest) in src_stops.iter().zip(dest_stops.iter_mut()) { + *dest = GpuBlock32::from(GradientStop { + offset: src.offset, + color: src.color, + padding: [0.0; 3], + }); + } + } + + false + } + _ => unreachable!(), + } + } +} + +#[derive(Clone)] +pub struct GpuBlock16 { + data: [f32; 4], +} + +impl Default for GpuBlock16 { + fn default() -> GpuBlock16 { + GpuBlock16 { + data: unsafe { mem::uninitialized() } + } + } +} + +impl From for GpuBlock16 { + fn from(data: TextRunPrimitiveGpu) -> GpuBlock16 { + unsafe { + mem::transmute::(data) + } + } +} + +impl From for GpuBlock16 { + fn from(data: RectanglePrimitive) -> GpuBlock16 { + unsafe { + mem::transmute::(data) + } + } +} + +impl From for GpuBlock16 { + fn from(data: InstanceRect) -> GpuBlock16 { + unsafe { + mem::transmute::(data) + } + } +} + +#[derive(Clone)] +pub struct GpuBlock32 { + data: [f32; 8], +} + +impl Default for GpuBlock32 { + fn default() -> GpuBlock32 { + GpuBlock32 { + data: unsafe { mem::uninitialized() } + } + } +} + +impl From for GpuBlock32 { + fn from(data: GradientPrimitiveGpu) -> GpuBlock32 { + unsafe { + mem::transmute::(data) + } + } +} + +impl From for GpuBlock32 { + fn from(data: GradientStop) -> GpuBlock32 { + unsafe { + mem::transmute::(data) + } + } +} + +impl From for GpuBlock32 { + fn from(data: GlyphPrimitive) -> GpuBlock32 { + unsafe { + mem::transmute::(data) + } + } +} + +impl From for GpuBlock32 { + fn from(data: ImagePrimitiveGpu) -> GpuBlock32 { + unsafe { + mem::transmute::(data) + } + } +} + +impl From for GpuBlock32 { + fn from(data: ClipRect) -> GpuBlock32 { + unsafe { + mem::transmute::(data) + } + } +} + +impl From for GpuBlock32 { + fn from(data: ClipCorner) -> GpuBlock32 { + unsafe { + mem::transmute::(data) + } + } +} + +#[derive(Clone)] +pub struct GpuBlock64 { + data: [f32; 16], +} + +impl Default for GpuBlock64 { + fn default() -> GpuBlock64 { + GpuBlock64 { + data: unsafe { mem::uninitialized() } + } + } +} + +impl From for GpuBlock64 { + fn from(data: BoxShadowPrimitive) -> GpuBlock64 { + unsafe { + mem::transmute::(data) + } + } +} + +#[derive(Clone)] +pub struct GpuBlock128 { + data: [f32; 32], +} + +impl Default for GpuBlock128 { + fn default() -> GpuBlock128 { + GpuBlock128 { + data: unsafe { mem::uninitialized() } + } + } +} + +impl From for GpuBlock128 { + fn from(data: BorderPrimitiveGpu) -> GpuBlock128 { + unsafe { + mem::transmute::(data) + } + } +} + +struct ImageInfo { + color_texture_id: TextureId, + uv0: Point2D, + uv1: Point2D, + stretch_size: Option>, + uv_kind: TextureCoordKind, + tile_spacing: Size2D, + is_opaque: bool, +} + +impl ImagePrimitiveCpu { + fn image_info(&self, resource_cache: &ResourceCache, frame_id: FrameId) -> ImageInfo { + match self.kind { + ImagePrimitiveKind::Image(image_key, image_rendering, stretch_size, tile_spacing) => { + let info = resource_cache.get_image(image_key, image_rendering, frame_id); + ImageInfo { + color_texture_id: info.texture_id, + uv0: Point2D::new(info.pixel_rect.top_left.x.0 as f32, + info.pixel_rect.top_left.y.0 as f32), + uv1: Point2D::new(info.pixel_rect.bottom_right.x.0 as f32, + info.pixel_rect.bottom_right.y.0 as f32), + stretch_size: Some(stretch_size), + uv_kind: TextureCoordKind::Pixel, + tile_spacing: tile_spacing, + is_opaque: info.is_opaque, + } + } + ImagePrimitiveKind::WebGL(context_id) => { + ImageInfo { + color_texture_id: resource_cache.get_webgl_texture(&context_id), + uv0: Point2D::new(0.0, 1.0), + uv1: Point2D::new(1.0, 0.0), + stretch_size: None, + uv_kind: TextureCoordKind::Normalized, + tile_spacing: Size2D::zero(), + is_opaque: false, + } + } + } + } +} diff --git a/webrender/src/renderer.rs b/webrender/src/renderer.rs index a56b061dd4..3f8fe0b401 100644 --- a/webrender/src/renderer.rs +++ b/webrender/src/renderer.rs @@ -35,9 +35,10 @@ use std::sync::{Arc, Mutex}; use std::sync::mpsc::{channel, Receiver, Sender}; use std::thread; use texture_cache::{BorderType, TextureCache, TextureInsertOp}; -use tiling::{self, Frame, FrameBuilderConfig, GLYPHS_PER_TEXT_RUN, PrimitiveBatchData}; -use tiling::{TransformedRectKind, RenderTarget, ClearTile}; +use tiling::{self, Frame, FrameBuilderConfig, PrimitiveBatchData}; +use tiling::{RenderTarget, ClearTile}; use time::precise_time_ns; +use util::TransformedRectKind; use webrender_traits::{ColorF, Epoch, PipelineId, RenderNotifier, RenderDispatcher}; use webrender_traits::{ImageFormat, RenderApiSender, RendererKind}; @@ -70,9 +71,8 @@ const GPU_TAG_PRIM_BLEND: GpuProfileTag = GpuProfileTag { label: "Blend", color: // Magenta const GPU_TAG_PRIM_COMPOSITE: GpuProfileTag = GpuProfileTag { label: "Composite", color: ColorF { r: 1.0, g: 0.0, b: 1.0, a: 1.0 } }; -// Blue / dark blue -const GPU_TAG_PRIM_TEXT: GpuProfileTag = GpuProfileTag { label: "Text", color: ColorF { r: 0.0, g: 0.0, b: 1.0, a: 1.0 } }; -const GPU_TAG_PRIM_TEXT_RUN: GpuProfileTag = GpuProfileTag { label: "TextRun", color: ColorF { r: 0.0, g: 0.0, b: 0.7, a: 1.0 } }; +// Blue +const GPU_TAG_PRIM_TEXT_RUN: GpuProfileTag = GpuProfileTag { label: "TextRun", color: ColorF { r: 0.0, g: 0.0, b: 1.0, a: 1.0 } }; // Yellow / dark yellow const GPU_TAG_PRIM_ALIGNED_GRADIENT: GpuProfileTag = GpuProfileTag { label: "AlignedGradient", color: ColorF { r: 1.0, g: 1.0, b: 0.0, a: 1.0 } }; @@ -100,6 +100,10 @@ impl VertexDataTexture { fn init(&mut self, device: &mut Device, data: &mut Vec) { + if data.is_empty() { + return; + } + let item_size = mem::size_of::(); debug_assert!(item_size % 16 == 0); let vecs_per_item = item_size / 16; @@ -259,10 +263,8 @@ fn create_prim_shader(name: &'static str, max_ubo_vectors: usize, features: &[&'static str]) -> ProgramId { let mut prefix = format!("#define WR_MAX_UBO_VECTORS {}\n\ - #define WR_GLYPHS_PER_TEXT_RUN {}\n #define WR_MAX_VERTEX_TEXTURE_WIDTH {}\n", max_ubo_vectors, - GLYPHS_PER_TEXT_RUN, MAX_VERTEX_TEXTURE_WIDTH); for feature in features { @@ -322,13 +324,12 @@ pub struct Renderer { u_direction: UniformLocation, ps_rectangle: PrimitiveShader, - ps_text: PrimitiveShader, ps_text_run: PrimitiveShader, ps_image: PrimitiveShader, ps_border: PrimitiveShader, - ps_box_shadow: PrimitiveShader, ps_aligned_gradient: PrimitiveShader, ps_angle_gradient: PrimitiveShader, + ps_box_shadow: PrimitiveShader, ps_rectangle_clip: PrimitiveShader, ps_image_clip: PrimitiveShader, @@ -361,6 +362,11 @@ pub struct Renderer { layer_texture: VertexDataTexture, render_task_texture: VertexDataTexture, + prim_geom_texture: VertexDataTexture, + data16_texture: VertexDataTexture, + data32_texture: VertexDataTexture, + data64_texture: VertexDataTexture, + data128_texture: VertexDataTexture, pipeline_epoch_map: HashMap>, /// Used to dispatch functions to the main thread's event loop. /// Required to allow GLContext sharing in some implementations like WGL. @@ -410,68 +416,54 @@ impl Renderer { let max_ubo_size = gl::get_integer_v(gl::MAX_UNIFORM_BLOCK_SIZE) as usize; let max_ubo_vectors = max_ubo_size / 16; - let max_prim_rectangles = get_ubo_max_len::(max_ubo_size); - let max_prim_rectangles_clip = get_ubo_max_len::(max_ubo_size); - let max_prim_texts = get_ubo_max_len::(max_ubo_size); - let max_prim_text_runs = get_ubo_max_len::(max_ubo_size); - let max_prim_images = get_ubo_max_len::(max_ubo_size); - let max_prim_images_clip = get_ubo_max_len::(max_ubo_size); - let max_prim_borders = get_ubo_max_len::(max_ubo_size); - let max_prim_box_shadows = get_ubo_max_len::(max_ubo_size); + let max_prim_instances = get_ubo_max_len::(max_ubo_size); let max_prim_blends = get_ubo_max_len::(max_ubo_size); let max_prim_composites = get_ubo_max_len::(max_ubo_size); - let max_prim_aligned_gradients = get_ubo_max_len::(max_ubo_size); - let max_prim_angle_gradients = get_ubo_max_len::(max_ubo_size); let ps_rectangle = PrimitiveShader::new("ps_rectangle", max_ubo_vectors, - max_prim_rectangles, + max_prim_instances, &mut device, options.precache_shaders); - let ps_rectangle_clip = PrimitiveShader::new("ps_rectangle_clip", - max_ubo_vectors, - max_prim_rectangles_clip, - &mut device, - options.precache_shaders); - let ps_text = PrimitiveShader::new("ps_text", - max_ubo_vectors, - max_prim_texts, - &mut device, - options.precache_shaders); let ps_text_run = PrimitiveShader::new("ps_text_run", max_ubo_vectors, - max_prim_text_runs, + max_prim_instances, &mut device, options.precache_shaders); let ps_image = PrimitiveShader::new("ps_image", max_ubo_vectors, - max_prim_images, + max_prim_instances, &mut device, options.precache_shaders); + let ps_border = PrimitiveShader::new("ps_border", + max_ubo_vectors, + max_prim_instances, + &mut device, + options.precache_shaders); + let ps_rectangle_clip = PrimitiveShader::new("ps_rectangle_clip", + max_ubo_vectors, + max_prim_instances, + &mut device, + options.precache_shaders); let ps_image_clip = PrimitiveShader::new("ps_image_clip", max_ubo_vectors, - max_prim_images_clip, + max_prim_instances, &mut device, options.precache_shaders); - let ps_border = PrimitiveShader::new("ps_border", - max_ubo_vectors, - max_prim_borders, - &mut device, - options.precache_shaders); let ps_box_shadow = PrimitiveShader::new("ps_box_shadow", max_ubo_vectors, - max_prim_box_shadows, + max_prim_instances, &mut device, options.precache_shaders); let ps_aligned_gradient = PrimitiveShader::new("ps_gradient_clip", max_ubo_vectors, - max_prim_aligned_gradients, + max_prim_instances, &mut device, options.precache_shaders); let ps_angle_gradient = PrimitiveShader::new("ps_angle_gradient", max_ubo_vectors, - max_prim_angle_gradients, + max_prim_instances, &mut device, options.precache_shaders); @@ -553,6 +545,12 @@ impl Renderer { let layer_texture = VertexDataTexture::new(&mut device); let render_task_texture = VertexDataTexture::new(&mut device); + let prim_geom_texture = VertexDataTexture::new(&mut device); + + let data16_texture = VertexDataTexture::new(&mut device); + let data32_texture = VertexDataTexture::new(&mut device); + let data64_texture = VertexDataTexture::new(&mut device); + let data128_texture = VertexDataTexture::new(&mut device); let x0 = 0.0; let y0 = 0.0; @@ -629,17 +627,16 @@ impl Renderer { blur_program_id: blur_program_id, tile_clear_shader: tile_clear_shader, ps_rectangle: ps_rectangle, - ps_rectangle_clip: ps_rectangle_clip, - ps_image_clip: ps_image_clip, - ps_text: ps_text, ps_text_run: ps_text_run, ps_image: ps_image, ps_border: ps_border, + ps_rectangle_clip: ps_rectangle_clip, + ps_image_clip: ps_image_clip, ps_box_shadow: ps_box_shadow, + ps_angle_gradient: ps_angle_gradient, + ps_aligned_gradient: ps_aligned_gradient, ps_blend: ps_blend, ps_composite: ps_composite, - ps_aligned_gradient: ps_aligned_gradient, - ps_angle_gradient: ps_angle_gradient, max_clear_tiles: max_clear_tiles, max_prim_blends: max_prim_blends, max_prim_composites: max_prim_composites, @@ -660,6 +657,11 @@ impl Renderer { quad_vao_id: quad_vao_id, layer_texture: layer_texture, render_task_texture: render_task_texture, + prim_geom_texture: prim_geom_texture, + data16_texture: data16_texture, + data32_texture: data32_texture, + data64_texture: data64_texture, + data128_texture: data128_texture, pipeline_epoch_map: HashMap::with_hasher(Default::default()), main_thread_dispatcher: main_thread_dispatcher }; @@ -1426,8 +1428,13 @@ impl Renderer { } } &PrimitiveBatchData::Rectangles(ref ubo_data) => { - self.gpu_profile.add_marker(GPU_TAG_PRIM_RECT); - let (shader, max_prim_items) = self.ps_rectangle.get(&mut self.device, batch.transform_kind); + let (shader, max_prim_items) = if batch.has_complex_clip { + self.gpu_profile.add_marker(GPU_TAG_PRIM_RECT_CLIP); + self.ps_rectangle_clip.get(&mut self.device, batch.transform_kind) + } else { + self.gpu_profile.add_marker(GPU_TAG_PRIM_RECT); + self.ps_rectangle.get(&mut self.device, batch.transform_kind) + }; self.draw_ubo_batch(ubo_data, shader, 1, @@ -1435,37 +1442,20 @@ impl Renderer { max_prim_items, &projection); } - &PrimitiveBatchData::RectanglesClip(ref ubo_data) => { - self.gpu_profile.add_marker(GPU_TAG_PRIM_RECT_CLIP); - let (shader, max_prim_items) = self.ps_rectangle_clip.get(&mut self.device, batch.transform_kind); - self.draw_ubo_batch(ubo_data, - shader, - 1, - batch.color_texture_id, - max_prim_items, - &projection); - - } &PrimitiveBatchData::Image(ref ubo_data) => { - self.gpu_profile.add_marker(GPU_TAG_PRIM_IMAGE); - let (shader, max_prim_items) = self.ps_image.get(&mut self.device, batch.transform_kind); - self.draw_ubo_batch(ubo_data, - shader, - 1, - batch.color_texture_id, - max_prim_items, - &projection); - } - &PrimitiveBatchData::ImageClip(ref ubo_data) => { - self.gpu_profile.add_marker(GPU_TAG_PRIM_IMAGE_CLIP); - let (shader, max_prim_items) = self.ps_image_clip.get(&mut self.device, batch.transform_kind); + let (shader, max_prim_items) = if batch.has_complex_clip { + self.gpu_profile.add_marker(GPU_TAG_PRIM_IMAGE_CLIP); + self.ps_image_clip.get(&mut self.device, batch.transform_kind) + } else { + self.gpu_profile.add_marker(GPU_TAG_PRIM_IMAGE); + self.ps_image.get(&mut self.device, batch.transform_kind) + }; self.draw_ubo_batch(ubo_data, shader, 1, batch.color_texture_id, max_prim_items, &projection); - } &PrimitiveBatchData::Borders(ref ubo_data) => { self.gpu_profile.add_marker(GPU_TAG_PRIM_BORDER); @@ -1478,7 +1468,7 @@ impl Renderer { &projection); } - &PrimitiveBatchData::BoxShadows(ref ubo_data) => { + &PrimitiveBatchData::BoxShadow(ref ubo_data) => { self.gpu_profile.add_marker(GPU_TAG_PRIM_BOX_SHADOW); let (shader, max_prim_items) = self.ps_box_shadow.get(&mut self.device, batch.transform_kind); self.draw_ubo_batch(ubo_data, @@ -1489,22 +1479,12 @@ impl Renderer { &projection); } - &PrimitiveBatchData::Text(ref ubo_data) => { - self.gpu_profile.add_marker(GPU_TAG_PRIM_TEXT); - let (shader, max_prim_items) = self.ps_text.get(&mut self.device, batch.transform_kind); - self.draw_ubo_batch(ubo_data, - shader, - 1, - batch.color_texture_id, - max_prim_items, - &projection); - } &PrimitiveBatchData::TextRun(ref ubo_data) => { self.gpu_profile.add_marker(GPU_TAG_PRIM_TEXT_RUN); let (shader, max_prim_items) = self.ps_text_run.get(&mut self.device, batch.transform_kind); self.draw_ubo_batch(ubo_data, shader, - GLYPHS_PER_TEXT_RUN, + 1, batch.color_texture_id, max_prim_items, &projection); @@ -1594,9 +1574,19 @@ impl Renderer { self.layer_texture.init(&mut self.device, &mut frame.layer_texture_data); self.render_task_texture.init(&mut self.device, &mut frame.render_task_data); + self.data16_texture.init(&mut self.device, &mut frame.gpu_data16); + self.data32_texture.init(&mut self.device, &mut frame.gpu_data32); + self.data64_texture.init(&mut self.device, &mut frame.gpu_data64); + self.data128_texture.init(&mut self.device, &mut frame.gpu_data128); + self.prim_geom_texture.init(&mut self.device, &mut frame.gpu_geometry); self.device.bind_texture(TextureSampler::Layers, self.layer_texture.id); self.device.bind_texture(TextureSampler::RenderTasks, self.render_task_texture.id); + self.device.bind_texture(TextureSampler::Geometry, self.prim_geom_texture.id); + self.device.bind_texture(TextureSampler::Data16, self.data16_texture.id); + self.device.bind_texture(TextureSampler::Data32, self.data32_texture.id); + self.device.bind_texture(TextureSampler::Data64, self.data64_texture.id); + self.device.bind_texture(TextureSampler::Data128, self.data128_texture.id); for (phase_index, phase) in frame.phases.iter().enumerate() { let mut render_target_index = 0; diff --git a/webrender/src/tiling.rs b/webrender/src/tiling.rs index c07ef4acfc..b139df04e9 100644 --- a/webrender/src/tiling.rs +++ b/webrender/src/tiling.rs @@ -2,17 +2,24 @@ * 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/. */ -use app_units::{Au}; +use app_units::Au; use batch_builder::{BorderSideHelpers, BoxShadowMetrics}; use device::{TextureId}; use euclid::{Point2D, Point4D, Rect, Matrix4D, Size2D}; use fnv::FnvHasher; use frame::FrameId; -use internal_types::{Glyph, DevicePixel, CompositionOp}; +use gpu_store::GpuStoreAddress; +use internal_types::{DevicePixel, CompositionOp}; use internal_types::{ANGLE_FLOAT_TO_FIXED, LowLevelFilterOp}; use layer::Layer; +use prim_store::{PrimitiveGeometry, RectanglePrimitive, PrimitiveContainer}; +use prim_store::{BorderPrimitiveCpu, BorderPrimitiveGpu, BoxShadowPrimitive}; +use prim_store::{Clip, ImagePrimitiveCpu, ImagePrimitiveKind}; +use prim_store::{PrimitiveKind, PrimitiveIndex, PrimitiveMetadata}; +use prim_store::{GradientPrimitiveCpu, GradientPrimitiveGpu, GradientType}; +use prim_store::{TextRunPrimitiveGpu, TextRunPrimitiveCpu}; +use prim_store::{PrimitiveStore, GpuBlock16, GpuBlock32, GpuBlock64, GpuBlock128}; use profiler::FrameProfileCounters; -use renderer::{BLUR_INFLATION_FACTOR}; use resource_cache::ResourceCache; use resource_list::ResourceList; use std::cmp; @@ -21,19 +28,194 @@ use std::f32; use std::mem; use std::hash::{BuildHasherDefault}; use std::sync::atomic::{AtomicUsize, Ordering}; +use std::usize; use texture_cache::TexturePage; -use util::{self, rect_from_points, rect_from_points_f, MatrixHelpers, subtract_rect}; -use webrender_traits::{ColorF, FontKey, GlyphKey, ImageKey, ImageRendering, ComplexClipRegion}; -use webrender_traits::{BorderDisplayItem, BorderStyle, ItemRange, AuxiliaryLists, BorderRadius, BorderSide}; +use util::{self, rect_from_points, MatrixHelpers, rect_from_points_f}; +use util::{TransformedRect, TransformedRectKind, subtract_rect, pack_as_float}; +use webrender_traits::{ColorF, FontKey, ImageKey, ImageRendering, ComplexClipRegion}; +use webrender_traits::{BorderDisplayItem, BorderStyle, ItemRange, AuxiliaryLists, BorderSide}; use webrender_traits::{BoxShadowClipMode, PipelineId, ScrollLayerId, WebGLContextId}; -pub const GLYPHS_PER_TEXT_RUN: usize = 8; -pub const ELEMENTS_PER_BORDER: usize = 8; - const ALPHA_BATCHERS_PER_RENDER_TARGET: usize = 4; const MIN_TASKS_PER_ALPHA_BATCHER: usize = 64; const FLOATS_PER_RENDER_TASK_INFO: usize = 8; +trait AlphaBatchHelpers { + fn get_batch_info(&self, metadata: &PrimitiveMetadata) -> (AlphaBatchKind, TextureId); + fn prim_affects_tile(&self, + prim_index: PrimitiveIndex, + tile_rect: &Rect, + transform: &Matrix4D, + device_pixel_ratio: f32) -> bool; + fn add_prim_to_batch(&self, + prim_index: PrimitiveIndex, + batch: &mut PrimitiveBatch, + layer_index: StackingContextIndex, + task_id: i32, + transform_kind: TransformedRectKind, + needs_blending: bool); +} + +impl AlphaBatchHelpers for PrimitiveStore { + fn get_batch_info(&self, metadata: &PrimitiveMetadata) -> (AlphaBatchKind, TextureId) { + let batch_kind = match metadata.prim_kind { + PrimitiveKind::Border => AlphaBatchKind::Border, + PrimitiveKind::BoxShadow => AlphaBatchKind::BoxShadow, + PrimitiveKind::Image => AlphaBatchKind::Image, + PrimitiveKind::Rectangle => AlphaBatchKind::Rectangle, + PrimitiveKind::TextRun => AlphaBatchKind::TextRun, + PrimitiveKind::Gradient => { + let gradient = &self.cpu_gradients[metadata.cpu_prim_index.0]; + match gradient.kind { + GradientType::Horizontal | GradientType::Vertical => { + AlphaBatchKind::AlignedGradient + } + GradientType::Rotated => { + AlphaBatchKind::AngleGradient + } + } + } + }; + + (batch_kind, metadata.color_texture_id) + } + + // Optional narrow phase intersection test, depending on primitive type. + fn prim_affects_tile(&self, + prim_index: PrimitiveIndex, + tile_rect: &Rect, + transform: &Matrix4D, + device_pixel_ratio: f32) -> bool { + let metadata = self.get_metadata(prim_index); + + match metadata.prim_kind { + PrimitiveKind::Rectangle | + PrimitiveKind::TextRun | + PrimitiveKind::Image | + PrimitiveKind::Gradient | + PrimitiveKind::BoxShadow => true, + + PrimitiveKind::Border => { + let border = &self.cpu_borders[metadata.cpu_prim_index.0]; + let inner_rect = TransformedRect::new(&border.inner_rect, + transform, + device_pixel_ratio); + + !inner_rect.bounding_rect.contains_rect(tile_rect) + } + } + } + + fn add_prim_to_batch(&self, + prim_index: PrimitiveIndex, + batch: &mut PrimitiveBatch, + layer_index: StackingContextIndex, + task_id: i32, + transform_kind: TransformedRectKind, + needs_blending: bool) { + debug_assert!(transform_kind == batch.transform_kind); + debug_assert!(needs_blending == batch.blending_enabled); + + let metadata = self.get_metadata(prim_index); + let layer_index = layer_index.0 as i32; + let global_prim_id = prim_index.0 as i32; + let prim_address = metadata.gpu_prim_index; + let clip_address = metadata.clip_index.unwrap_or(GpuStoreAddress(0)); + + match &mut batch.data { + &mut PrimitiveBatchData::Blend(..) | + &mut PrimitiveBatchData::Composite(..) => unreachable!(), + + &mut PrimitiveBatchData::Rectangles(ref mut data) => { + data.push(PrimitiveInstance { + task_id: task_id, + layer_index: layer_index, + global_prim_id: global_prim_id, + prim_address: prim_address, + clip_address: clip_address, + user_data: [0, 0, 0], + }); + } + &mut PrimitiveBatchData::TextRun(ref mut data) => { + let metadata = self.get_metadata(prim_index); + + for glyph_index in 0..metadata.gpu_data_count { + data.push(PrimitiveInstance { + task_id: task_id, + layer_index: layer_index, + global_prim_id: global_prim_id, + prim_address: prim_address, + clip_address: clip_address, + user_data: [ metadata.gpu_data_address.0, glyph_index, 0 ], + }); + } + } + &mut PrimitiveBatchData::Image(ref mut data) => { + data.push(PrimitiveInstance { + task_id: task_id, + layer_index: layer_index, + global_prim_id: global_prim_id, + prim_address: prim_address, + clip_address: clip_address, + user_data: [ 0, 0, 0 ], + }); + } + &mut PrimitiveBatchData::Borders(ref mut data) => { + for border_segment in 0..8 { + data.push(PrimitiveInstance { + task_id: task_id, + layer_index: layer_index, + global_prim_id: global_prim_id, + prim_address: prim_address, + clip_address: clip_address, + user_data: [ border_segment, 0, 0 ], + }); + } + } + &mut PrimitiveBatchData::AlignedGradient(ref mut data) => { + let metadata = self.get_metadata(prim_index); + + for part_index in 0..(metadata.gpu_data_count - 1) { + data.push(PrimitiveInstance { + task_id: task_id, + layer_index: layer_index, + global_prim_id: global_prim_id, + prim_address: prim_address, + clip_address: clip_address, + user_data: [ metadata.gpu_data_address.0, part_index, 0 ], + }); + } + } + &mut PrimitiveBatchData::AngleGradient(ref mut data) => { + let metadata = self.get_metadata(prim_index); + + data.push(PrimitiveInstance { + task_id: task_id, + layer_index: layer_index, + global_prim_id: global_prim_id, + prim_address: prim_address, + clip_address: clip_address, + user_data: [ metadata.gpu_data_address.0, metadata.gpu_data_count, 0 ], + }); + } + &mut PrimitiveBatchData::BoxShadow(ref mut data) => { + let metadata = self.get_metadata(prim_index); + + for rect_index in 0..metadata.gpu_data_count { + data.push(PrimitiveInstance { + task_id: task_id, + layer_index: layer_index, + global_prim_id: global_prim_id, + prim_address: prim_address, + clip_address: clip_address, + user_data: [ metadata.gpu_data_address.0, rect_index, 0 ], + }); + } + } + } + } +} + #[derive(Debug)] struct ScrollbarPrimitive { scroll_layer_id: ScrollLayerId, @@ -41,24 +223,6 @@ struct ScrollbarPrimitive { border_radius: f32, } -#[inline(always)] -fn pack_as_float(value: u32) -> f32 { - value as f32 + 0.5 -} - -trait PackRectAsFloat { - fn pack_as_float(&self) -> Rect; -} - -impl PackRectAsFloat for Rect { - fn pack_as_float(&self) -> Rect { - Rect::new(Point2D::new(self.origin.x.0 as f32, - self.origin.y.0 as f32), - Size2D::new(self.size.width.0 as f32, - self.size.height.0 as f32)) - } -} - enum PrimitiveRunCmd { PushStackingContext(StackingContextIndex), PrimitiveRun(PrimitiveIndex, usize), @@ -71,14 +235,6 @@ pub enum PrimitiveFlags { Scrollbar(ScrollLayerId, f32) } -#[repr(u32)] -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -pub enum GradientType { - Horizontal, - Vertical, - Rotated, -} - #[derive(Debug, Copy, Clone)] struct RenderTaskIndex(usize); @@ -135,6 +291,15 @@ impl Default for RenderTaskData { } } +impl Default for PrimitiveGeometry { + fn default() -> PrimitiveGeometry { + PrimitiveGeometry { + local_rect: unsafe { mem::uninitialized() }, + local_clip_rect: unsafe { mem::uninitialized() }, + } + } +} + struct AlphaBatchTask { task_id: RenderTaskId, items: Vec, @@ -163,7 +328,7 @@ impl AlphaBatcher { let mut batches: Vec<(AlphaBatchKey, PrimitiveBatch)> = vec![]; for task in &mut self.tasks { let task_index = render_tasks.get_task_index(&task.task_id); - let task_index = pack_as_float(task_index.0 as u32); + let task_index = task_index.0 as i32; let mut existing_batch_index = 0; let items = mem::replace(&mut task.items, vec![]); @@ -179,14 +344,17 @@ impl AlphaBatcher { AlphaRenderItem::Primitive(sc_index, prim_index) => { // See if this task fits into the tile UBO let layer = &ctx.layer_store[sc_index.0]; - let prim = &ctx.prim_store[prim_index.0]; + let prim_metadata = ctx.prim_store.get_metadata(prim_index); let transform_kind = layer.xf_rect.as_ref().unwrap().kind; + let needs_clipping = prim_metadata.clip_index.is_some(); let needs_blending = transform_kind == TransformedRectKind::Complex || - !prim.is_opaque(ctx.resource_cache, ctx.frame_id); - let batch_kind = prim.batch_kind(); - let color_texture_id = prim.color_texture_id(ctx.resource_cache, - ctx.frame_id); - let flags = AlphaBatchKeyFlags::new(transform_kind, needs_blending); + !prim_metadata.is_opaque || + needs_clipping; + let flags = AlphaBatchKeyFlags::new(transform_kind, + needs_blending, + needs_clipping); + let (batch_kind, color_texture_id) = ctx.prim_store + .get_batch_info(prim_metadata); batch_key = AlphaBatchKey::primitive(batch_kind, flags, color_texture_id); @@ -208,9 +376,14 @@ impl AlphaBatcher { } AlphaRenderItem::Primitive(_, prim_index) => { // See if this task fits into the tile UBO - PrimitiveBatch::new(&ctx.prim_store[prim_index.0], + let prim_metadata = ctx.prim_store.get_metadata(prim_index); + let (batch_kind, color_texture_id) = ctx.prim_store + .get_batch_info(prim_metadata); + PrimitiveBatch::new(batch_kind, batch_key.flags.transform_kind(), - batch_key.flags.needs_blending()) + batch_key.flags.needs_blending(), + batch_key.flags.needs_clipping(), + color_texture_id) } }; batches.push((batch_key, new_batch)) @@ -237,21 +410,12 @@ impl AlphaBatcher { debug_assert!(ok) } AlphaRenderItem::Primitive(sc_index, prim_index) => { - let prim = &ctx.prim_store[prim_index.0]; - let ok = prim.add_to_batch(batch, - sc_index, - task_index, - batch_key.flags.transform_kind(), - batch_key.flags.needs_blending()); - debug_assert!(ok); - - let color_texture_id = prim.color_texture_id(ctx.resource_cache, - ctx.frame_id); - if color_texture_id != TextureId(0) && - batch.color_texture_id != color_texture_id { - debug_assert!(batch.color_texture_id == TextureId(0)); - batch.color_texture_id = color_texture_id - } + ctx.prim_store.add_prim_to_batch(prim_index, + batch, + sc_index, + task_index, + batch_key.flags.transform_kind(), + batch_key.flags.needs_blending()); } } } @@ -263,9 +427,7 @@ impl AlphaBatcher { struct RenderTargetContext<'a> { layer_store: &'a Vec, - prim_store: &'a Vec, - resource_cache: &'a ResourceCache, - frame_id: FrameId, + prim_store: &'a PrimitiveStore, render_task_id_counter: AtomicUsize, } @@ -539,7 +701,6 @@ impl RenderTask { pub const SCREEN_TILE_SIZE: i32 = 64; pub const RENDERABLE_CACHE_SIZE: DevicePixel = DevicePixel(2048); -const MAX_STOPS_PER_ANGLE_GRADIENT: usize = 8; #[derive(Debug, Clone)] pub struct DebugRect { @@ -548,1205 +709,18 @@ pub struct DebugRect { pub rect: Rect, } -#[derive(Debug, Clone, Copy, Eq, PartialEq)] -#[repr(u8)] -pub enum TransformedRectKind { - AxisAligned = 0, - Complex = 1, -} - -#[derive(Debug, Clone)] -pub struct TransformedRect { - local_rect: Rect, - pub bounding_rect: Rect, - vertices: [Point4D; 4], - kind: TransformedRectKind, -} - -impl TransformedRect { - pub fn new(rect: &Rect, - transform: &Matrix4D, - device_pixel_ratio: f32) -> TransformedRect { - - let kind = if transform.can_losslessly_transform_and_perspective_project_a_2d_rect() { - TransformedRectKind::AxisAligned - } else { - TransformedRectKind::Complex - }; - -/* - match kind { - TransformedRectKind::AxisAligned => { - let v0 = transform.transform_point(&rect.origin); - let v1 = transform.transform_point(&rect.top_right()); - let v2 = transform.transform_point(&rect.bottom_left()); - let v3 = transform.transform_point(&rect.bottom_right()); - - let screen_min_dp = Point2D::new(DevicePixel((v0.x * device_pixel_ratio).floor() as i32), - DevicePixel((v0.y * device_pixel_ratio).floor() as i32)); - let screen_max_dp = Point2D::new(DevicePixel((v3.x * device_pixel_ratio).ceil() as i32), - DevicePixel((v3.y * device_pixel_ratio).ceil() as i32)); - - let screen_rect_dp = Rect::new(screen_min_dp, Size2D::new(screen_max_dp.x - screen_min_dp.x, - screen_max_dp.y - screen_min_dp.y)); - - TransformedRect { - local_rect: *rect, - vertices: [ - Point4D::new(v0.x, v0.y, 0.0, 1.0), - Point4D::new(v1.x, v1.y, 0.0, 1.0), - Point4D::new(v2.x, v2.y, 0.0, 1.0), - Point4D::new(v3.x, v3.y, 0.0, 1.0), - ], - bounding_rect: screen_rect_dp, - kind: kind, - } - } - TransformedRectKind::Complex => { - */ - let vertices = [ - transform.transform_point4d(&Point4D::new(rect.origin.x, - rect.origin.y, - 0.0, - 1.0)), - transform.transform_point4d(&Point4D::new(rect.bottom_left().x, - rect.bottom_left().y, - 0.0, - 1.0)), - transform.transform_point4d(&Point4D::new(rect.bottom_right().x, - rect.bottom_right().y, - 0.0, - 1.0)), - transform.transform_point4d(&Point4D::new(rect.top_right().x, - rect.top_right().y, - 0.0, - 1.0)), - ]; - - - let mut screen_min : Point2D = Point2D::new(10000000.0, 10000000.0); - let mut screen_max : Point2D = Point2D::new(-10000000.0, -10000000.0); - - for vertex in &vertices { - let inv_w = 1.0 / vertex.w; - let vx = vertex.x * inv_w; - let vy = vertex.y * inv_w; - screen_min.x = screen_min.x.min(vx); - screen_min.y = screen_min.y.min(vy); - screen_max.x = screen_max.x.max(vx); - screen_max.y = screen_max.y.max(vy); - } - - let screen_min_dp = Point2D::new(DevicePixel((screen_min.x * device_pixel_ratio).floor() as i32), - DevicePixel((screen_min.y * device_pixel_ratio).floor() as i32)); - let screen_max_dp = Point2D::new(DevicePixel((screen_max.x * device_pixel_ratio).ceil() as i32), - DevicePixel((screen_max.y * device_pixel_ratio).ceil() as i32)); - - let screen_rect_dp = Rect::new(screen_min_dp, Size2D::new(screen_max_dp.x - screen_min_dp.x, - screen_max_dp.y - screen_min_dp.y)); - - TransformedRect { - local_rect: *rect, - vertices: vertices, - bounding_rect: screen_rect_dp, - kind: kind, - } - /* - } - }*/ - } -} - -#[derive(Debug)] -struct RectanglePrimitive { - color: ColorF, -} - -#[derive(Debug)] -struct TextPrimitiveCache { - color_texture_id: TextureId, - glyph: Option, -} - -impl TextPrimitiveCache { - fn new() -> TextPrimitiveCache { - TextPrimitiveCache { - color_texture_id: TextureId(0), - glyph: None, - } - } -} - -#[derive(Debug)] -struct TextRunPrimitiveCache { - color_texture_id: TextureId, - glyphs: Option, -} - -impl TextRunPrimitiveCache { - fn new() -> TextRunPrimitiveCache { - TextRunPrimitiveCache { - color_texture_id: TextureId(0), - glyphs: None, - } - } -} - -#[derive(Debug)] -struct TextPrimitive { - color: ColorF, - font_key: FontKey, - size: Au, - blur_radius: Au, - glyph_index: u32, - cache: Option, -} - -#[derive(Debug)] -struct TextRunPrimitive { - color: ColorF, - font_key: FontKey, - size: Au, - blur_radius: Au, - glyph_range: ItemRange, - cache: Option, -} - -#[derive(Debug)] -struct BoxShadowPrimitiveCache { - elements: Vec, -} - -#[derive(Debug)] -struct BoxShadowPrimitive { - src_rect: Rect, - bs_rect: Rect, - color: ColorF, - blur_radius: f32, - spread_radius: f32, - border_radius: f32, - clip_mode: BoxShadowClipMode, - cache: Option, -} - -#[derive(Debug)] -struct BorderPrimitiveCache { - elements: [PackedBorderPrimitive; ELEMENTS_PER_BORDER], -} - -#[derive(Debug)] -struct BorderPrimitive { - tl_outer: Point2D, - tl_inner: Point2D, - tr_outer: Point2D, - tr_inner: Point2D, - bl_outer: Point2D, - bl_inner: Point2D, - br_outer: Point2D, - br_inner: Point2D, - left_width: f32, - top_width: f32, - right_width: f32, - bottom_width: f32, - radius: BorderRadius, - left_color: ColorF, - top_color: ColorF, - right_color: ColorF, - bottom_color: ColorF, - left_style: BorderStyle, - top_style: BorderStyle, - right_style: BorderStyle, - bottom_style: BorderStyle, - cache: Option>, -} - -impl BorderPrimitive { - fn pack_style(&self) -> [f32; 4] { - [ - pack_as_float(self.top_style as u32), - pack_as_float(self.right_style as u32), - pack_as_float(self.bottom_style as u32), - pack_as_float(self.left_style as u32), - ] - } -} - -#[derive(Debug)] -enum ImagePrimitiveKind { - Image(ImageKey, ImageRendering, Size2D, Size2D), - WebGL(WebGLContextId), -} - -#[derive(Debug)] -enum ImagePrimitiveCache { - Normal(PackedImagePrimitive), - Clip(PackedImagePrimitiveClip), -} - -#[derive(Debug)] -struct ImagePrimitive { - kind: ImagePrimitiveKind, - cache: Option, -} - -#[derive(Debug)] -enum GradientPrimitiveCache { - Aligned(Vec), - Angle(PackedAngleGradientPrimitive), -} - -#[derive(Debug)] -struct GradientPrimitive { - stops_range: ItemRange, - kind: GradientType, - start_point: Point2D, - end_point: Point2D, - cache: Option, -} - -#[derive(Debug)] -enum PrimitiveDetails { - Rectangle(RectanglePrimitive), - Text(TextPrimitive), - TextRun(TextRunPrimitive), - Image(ImagePrimitive), - Border(BorderPrimitive), - Gradient(GradientPrimitive), - BoxShadow(BoxShadowPrimitive), -} - #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] #[repr(u8)] enum AlphaBatchKind { Composite = 0, - Blend = 1, - Rectangle = 2, - RectangleClip = 3, - Text = 4, - TextRun = 5, - Image = 6, - ImageClip = 7, - Border = 8, - AlignedGradient = 9, - AngleGradient = 10, - BoxShadow = 11, -} - -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] -pub struct PrimitiveIndex(usize); - -#[derive(Debug)] -struct Primitive { - rect: Rect, - local_clip_rect: Rect, - complex_clip: Option>, - bounding_rect: Option>, - details: PrimitiveDetails, -} - -impl Primitive { - fn is_opaque(&self, resource_cache: &ResourceCache, frame_id: FrameId) -> bool { - if self.complex_clip.is_some() { - return false; - } - - match self.details { - PrimitiveDetails::Rectangle(ref primitive) => primitive.color.a == 1.0, - PrimitiveDetails::Image(ImagePrimitive { - kind: ImagePrimitiveKind::Image(image_key, image_rendering, _, tile_spacing), - .. - }) => { - tile_spacing.width == 0.0 && tile_spacing.height == 0.0 && - resource_cache.get_image(image_key, image_rendering, frame_id).is_opaque - } - _ => false, - } - } - - fn prepare_for_render(&mut self, - screen_rect: &Rect, - layer_index: StackingContextIndex, - layer_transform: &Matrix4D, - layer_combined_local_clip_rect: &Rect, - resource_cache: &ResourceCache, - frame_id: FrameId, - device_pixel_ratio: f32, - auxiliary_lists: &AuxiliaryLists) { - let layer_index = pack_as_float(layer_index.0 as u32); - - match self.details { - PrimitiveDetails::Rectangle(..) => { - // not cached by build_resource_list - unreachable!() - } - PrimitiveDetails::BoxShadow(ref mut shadow) => { - let mut rects = Vec::new(); - let inverted = match shadow.clip_mode { - BoxShadowClipMode::None | BoxShadowClipMode::Outset => { - subtract_rect(&self.rect, &shadow.src_rect, &mut rects); - 0.0 - } - BoxShadowClipMode::Inset => { - subtract_rect(&self.rect, &shadow.bs_rect, &mut rects); - 1.0 - } - }; - - let mut elements = Vec::new(); - for rect in rects { - elements.push(PackedBoxShadowPrimitive { - common: PackedPrimitiveInfo { - padding: [0, 0], - task_id: 0.0, - layer_index: layer_index, - local_clip_rect: self.local_clip_rect, - local_rect: rect, - }, - color: shadow.color, - - border_radii: Point2D::new(shadow.border_radius, - shadow.border_radius), - blur_radius: shadow.blur_radius, - inverted: inverted, - bs_rect: shadow.bs_rect, - src_rect: shadow.src_rect, - }); - } - - shadow.cache = Some(BoxShadowPrimitiveCache { - elements: elements, - }); - } - PrimitiveDetails::Image(ref mut image) => { - let ImageInfo { - color_texture_id: texture_id, - uv0, - uv1, - stretch_size, - tile_spacing, - uv_kind, - } = image.image_info(resource_cache, frame_id); - - match self.complex_clip { - Some(ref complex_clip) => { - let element = PackedImagePrimitiveClip { - common: PackedPrimitiveInfo { - padding: [0, 0], - task_id: 0.0, - layer_index: layer_index, - local_clip_rect: self.local_clip_rect, - local_rect: self.rect, - }, - uv0: uv0, - uv1: uv1, - stretch_size: stretch_size.unwrap_or(self.rect.size), - tile_spacing: tile_spacing, - uv_kind: pack_as_float(uv_kind as u32), - texture_id: texture_id, - padding: [0, 0], - clip: complex_clip.as_ref().clone(), - }; - - image.cache = Some(ImagePrimitiveCache::Clip(element)); - } - None => { - let element = PackedImagePrimitive { - common: PackedPrimitiveInfo { - padding: [0, 0], - task_id: 0.0, - layer_index: layer_index, - local_clip_rect: self.local_clip_rect, - local_rect: self.rect, - }, - uv0: uv0, - uv1: uv1, - stretch_size: stretch_size.unwrap_or(self.rect.size), - tile_spacing: tile_spacing, - uv_kind: pack_as_float(uv_kind as u32), - texture_id: texture_id, - padding: [0, 0], - }; - - image.cache = Some(ImagePrimitiveCache::Normal(element)); - } - } - } - PrimitiveDetails::Gradient(ref mut gradient) => { - match gradient.kind { - GradientType::Horizontal | GradientType::Vertical => { - let stops = auxiliary_lists.gradient_stops(&gradient.stops_range); - let mut pieces = Vec::new(); - for i in 0..(stops.len() - 1) { - let (prev_stop, next_stop) = (&stops[i], &stops[i + 1]); - let piece_origin; - let piece_size; - match gradient.kind { - GradientType::Horizontal => { - let prev_x = util::lerp(gradient.start_point.x, - gradient.end_point.x, - prev_stop.offset); - let next_x = util::lerp(gradient.start_point.x, - gradient.end_point.x, - next_stop.offset); - piece_origin = Point2D::new(prev_x, self.rect.origin.y); - piece_size = Size2D::new(next_x - prev_x, - self.rect.size.height); - } - GradientType::Vertical => { - let prev_y = util::lerp(gradient.start_point.y, - gradient.end_point.y, - prev_stop.offset); - let next_y = util::lerp(gradient.start_point.y, - gradient.end_point.y, - next_stop.offset); - piece_origin = Point2D::new(self.rect.origin.x, prev_y); - piece_size = Size2D::new(self.rect.size.width, next_y - prev_y); - } - GradientType::Rotated => unreachable!(), - } - - let piece_rect = Rect::new(piece_origin, piece_size); - let mut clip = Clip::invalid(piece_rect); - - if let Some(ref prim_clip) = self.complex_clip { - if i == 0 { - clip.top_left.outer_radius_x = prim_clip.top_left - .outer_radius_x; - clip.top_left.outer_radius_y = prim_clip.top_left - .outer_radius_y; - - match gradient.kind { - GradientType::Horizontal => { - clip.bottom_left.outer_radius_x = - prim_clip.bottom_left.outer_radius_x; - clip.bottom_left.outer_radius_y = - prim_clip.bottom_left.outer_radius_y; - } - GradientType::Vertical => { - clip.top_right.outer_radius_x = - prim_clip.top_right.outer_radius_x; - clip.top_right.outer_radius_y = - prim_clip.top_right.outer_radius_y; - } - GradientType::Rotated => unreachable!(), - } - } - - if i == stops.len() - 2 { - clip.bottom_right.outer_radius_x = prim_clip.bottom_right - .outer_radius_x; - clip.bottom_right.outer_radius_y = prim_clip.bottom_right - .outer_radius_y; - - match gradient.kind { - GradientType::Horizontal => { - clip.top_right.outer_radius_x = - prim_clip.top_right.outer_radius_x; - clip.top_right.outer_radius_y = - prim_clip.top_right.outer_radius_y; - } - GradientType::Vertical => { - clip.bottom_left.outer_radius_x = - prim_clip.bottom_left.outer_radius_x; - clip.bottom_left.outer_radius_y = - prim_clip.bottom_left.outer_radius_y; - } - GradientType::Rotated => unreachable!(), - } - } - } - - pieces.push(PackedAlignedGradientPrimitive { - common: PackedPrimitiveInfo { - padding: [0, 0], - task_id: 0.0, - layer_index: layer_index, - local_clip_rect: self.local_clip_rect, - local_rect: piece_rect, - }, - color0: prev_stop.color, - color1: next_stop.color, - padding: [0, 0, 0], - kind: pack_as_float(gradient.kind as u32), - clip: clip, - }); - } - - gradient.cache = Some(GradientPrimitiveCache::Aligned(pieces)); - } - GradientType::Rotated => { - let src_stops = auxiliary_lists.gradient_stops(&gradient.stops_range); - if src_stops.len() > MAX_STOPS_PER_ANGLE_GRADIENT { - println!("TODO: Angle gradients with > {} stops", - MAX_STOPS_PER_ANGLE_GRADIENT); - return; - } - - let mut stops: [f32; MAX_STOPS_PER_ANGLE_GRADIENT] = unsafe { - mem::uninitialized() - }; - let mut colors: [ColorF; MAX_STOPS_PER_ANGLE_GRADIENT] = unsafe { - mem::uninitialized() - }; - - let sx = gradient.start_point.x; - let ex = gradient.end_point.x; - - let (sp, ep) = if sx > ex { - for (stop_index, stop) in src_stops.iter().rev().enumerate() { - stops[stop_index] = 1.0 - stop.offset; - colors[stop_index] = stop.color; - } - - (gradient.end_point, gradient.start_point) - } else { - for (stop_index, stop) in src_stops.iter().enumerate() { - stops[stop_index] = stop.offset; - colors[stop_index] = stop.color; - } - - (gradient.start_point, gradient.end_point) - }; - - let packed_prim = PackedAngleGradientPrimitive { - common: PackedPrimitiveInfo { - padding: [0, 0], - task_id: 0.0, - layer_index: layer_index, - local_clip_rect: self.local_clip_rect, - local_rect: self.rect, - }, - padding: [0, 0, 0], - start_point: sp, - end_point: ep, - stop_count: pack_as_float(src_stops.len() as u32), - stops: stops, - colors: colors, - }; - - gradient.cache = Some(GradientPrimitiveCache::Angle(packed_prim)); - } - } - } - PrimitiveDetails::Border(ref mut border) => { - let inner_radius = BorderRadius { - top_left: Size2D::new(border.radius.top_left.width - border.left_width, - border.radius.top_left.height - border.top_width), - top_right: Size2D::new(border.radius.top_right.width - border.right_width, - border.radius.top_right.height - border.top_width), - bottom_left: - Size2D::new(border.radius.bottom_left.width - border.left_width, - border.radius.bottom_left.height - border.bottom_width), - bottom_right: - Size2D::new(border.radius.bottom_right.width - border.right_width, - border.radius.bottom_right.height - border.bottom_width), - }; - - border.cache = Some(Box::new(BorderPrimitiveCache { - elements: [ - PackedBorderPrimitive { - common: PackedPrimitiveInfo { - padding: [0, 0], - task_id: 0.0, - layer_index: layer_index, - local_clip_rect: self.local_clip_rect, - local_rect: rect_from_points_f(border.tl_outer.x, - border.tl_outer.y, - border.tl_inner.x, - border.tl_inner.y), - }, - vertical_color: border.top_color, - horizontal_color: border.left_color, - outer_radius_x: border.radius.top_left.width, - outer_radius_y: border.radius.top_left.height, - inner_radius_x: inner_radius.top_left.width, - inner_radius_y: inner_radius.top_left.height, - style: border.pack_style(), - part: [pack_as_float(PrimitivePart::TopLeft as u32), 0.0, 0.0, 0.0], - }, - PackedBorderPrimitive { - common: PackedPrimitiveInfo { - padding: [0, 0], - task_id: 0.0, - layer_index: layer_index, - local_clip_rect: self.local_clip_rect, - local_rect: rect_from_points_f(border.tr_inner.x, - border.tr_outer.y, - border.tr_outer.x, - border.tr_inner.y), - }, - vertical_color: border.right_color, - horizontal_color: border.top_color, - outer_radius_x: border.radius.top_right.width, - outer_radius_y: border.radius.top_right.height, - inner_radius_x: inner_radius.top_right.width, - inner_radius_y: inner_radius.top_right.height, - style: border.pack_style(), - part: [pack_as_float(PrimitivePart::TopRight as u32), 0.0, 0.0, 0.0], - }, - PackedBorderPrimitive { - common: PackedPrimitiveInfo { - padding: [0, 0], - task_id: 0.0, - layer_index: layer_index, - local_clip_rect: self.local_clip_rect, - local_rect: rect_from_points_f(border.bl_outer.x, - border.bl_inner.y, - border.bl_inner.x, - border.bl_outer.y), - }, - vertical_color: border.left_color, - horizontal_color: border.bottom_color, - outer_radius_x: border.radius.bottom_left.width, - outer_radius_y: border.radius.bottom_left.height, - inner_radius_x: inner_radius.bottom_left.width, - inner_radius_y: inner_radius.bottom_left.height, - style: border.pack_style(), - part: [pack_as_float(PrimitivePart::BottomLeft as u32), 0.0, 0.0, 0.0], - }, - PackedBorderPrimitive { - common: PackedPrimitiveInfo { - padding: [0, 0], - task_id: 0.0, - layer_index: layer_index, - local_clip_rect: self.local_clip_rect, - local_rect: rect_from_points_f(border.br_inner.x, - border.br_inner.y, - border.br_outer.x, - border.br_outer.y), - }, - vertical_color: border.right_color, - horizontal_color: border.bottom_color, - outer_radius_x: border.radius.bottom_right.width, - outer_radius_y: border.radius.bottom_right.height, - inner_radius_x: inner_radius.bottom_right.width, - inner_radius_y: inner_radius.bottom_right.height, - style: border.pack_style(), - part: [pack_as_float(PrimitivePart::BottomRight as u32), 0.0, 0.0, 0.0], - }, - PackedBorderPrimitive { - common: PackedPrimitiveInfo { - padding: [0, 0], - task_id: 0.0, - layer_index: layer_index, - local_clip_rect: self.local_clip_rect, - local_rect: rect_from_points_f(border.tl_outer.x, - border.tl_inner.y, - border.tl_outer.x + border.left_width, - border.bl_inner.y), - }, - vertical_color: border.left_color, - horizontal_color: border.left_color, - outer_radius_x: 0.0, - outer_radius_y: 0.0, - inner_radius_x: 0.0, - inner_radius_y: 0.0, - style: border.pack_style(), - part: [pack_as_float(PrimitivePart::Left as u32), 0.0, 0.0, 0.0], - }, - PackedBorderPrimitive { - common: PackedPrimitiveInfo { - padding: [0, 0], - task_id: 0.0, - layer_index: layer_index, - local_clip_rect: self.local_clip_rect, - local_rect: rect_from_points_f(border.tr_outer.x - border.right_width, - border.tr_inner.y, - border.br_outer.x, - border.br_inner.y), - }, - vertical_color: border.right_color, - horizontal_color: border.right_color, - outer_radius_x: 0.0, - outer_radius_y: 0.0, - inner_radius_x: 0.0, - inner_radius_y: 0.0, - style: border.pack_style(), - part: [pack_as_float(PrimitivePart::Right as u32), 0.0, 0.0, 0.0], - }, - PackedBorderPrimitive { - common: PackedPrimitiveInfo { - padding: [0, 0], - task_id: 0.0, - layer_index: layer_index, - local_clip_rect: self.local_clip_rect, - local_rect: rect_from_points_f(border.tl_inner.x, - border.tl_outer.y, - border.tr_inner.x, - border.tr_outer.y + border.top_width), - }, - vertical_color: border.top_color, - horizontal_color: border.top_color, - outer_radius_x: 0.0, - outer_radius_y: 0.0, - inner_radius_x: 0.0, - inner_radius_y: 0.0, - style: border.pack_style(), - part: [pack_as_float(PrimitivePart::Top as u32), 0.0, 0.0, 0.0], - }, - PackedBorderPrimitive { - common: PackedPrimitiveInfo { - padding: [0, 0], - task_id: 0.0, - layer_index: layer_index, - local_clip_rect: self.local_clip_rect, - local_rect: rect_from_points_f(border.bl_inner.x, - border.bl_outer.y - border.bottom_width, - border.br_inner.x, - border.br_outer.y), - }, - vertical_color: border.bottom_color, - horizontal_color: border.bottom_color, - outer_radius_x: 0.0, - outer_radius_y: 0.0, - inner_radius_x: 0.0, - inner_radius_y: 0.0, - style: border.pack_style(), - part: [pack_as_float(PrimitivePart::Bottom as u32), 0.0, 0.0, 0.0], - }, - ], - })); - } - PrimitiveDetails::Text(ref mut text) => { - let mut cache = TextPrimitiveCache::new(); - let glyph_range = ItemRange { - start: text.glyph_index as usize, - length: 1, - }; - let glyph = auxiliary_lists.glyph_instances(&glyph_range)[0]; - let glyph_key = GlyphKey::new(text.font_key, - text.size, - text.blur_radius, - glyph.index); - let blur_offset = text.blur_radius.to_f32_px() * - (BLUR_INFLATION_FACTOR as f32) / 2.0; - - let image_info = match resource_cache.get_glyph(&glyph_key, frame_id) { - None => return, - Some(image_info) => image_info, - }; - - debug_assert!(cache.color_texture_id == TextureId(0) || - cache.color_texture_id == image_info.texture_id); - cache.color_texture_id = image_info.texture_id; - - let x = glyph.x + image_info.user_data.x0 as f32 / device_pixel_ratio - - blur_offset; - let y = glyph.y - image_info.user_data.y0 as f32 / device_pixel_ratio - - blur_offset; - - let width = image_info.requested_rect.size.width as f32 / device_pixel_ratio; - let height = image_info.requested_rect.size.height as f32 / device_pixel_ratio; - - self.rect = Rect::new(Point2D::new(x, y), Size2D::new(width, height)); - cache.glyph = Some(PackedGlyphPrimitive { - common: PackedPrimitiveInfo { - padding: [0, 0], - task_id: 0.0, - layer_index: layer_index, - local_clip_rect: self.local_clip_rect, - local_rect: self.rect, - }, - color: text.color, - uv0: Point2D::new(image_info.pixel_rect.top_left.x.0 as f32, - image_info.pixel_rect.top_left.y.0 as f32), - uv1: Point2D::new(image_info.pixel_rect.bottom_right.x.0 as f32, - image_info.pixel_rect.bottom_right.y.0 as f32), - }); - - text.cache = Some(cache); - } - PrimitiveDetails::TextRun(ref mut text_run) => { - debug_assert!(text_run.cache.is_none()); - let mut cache = TextRunPrimitiveCache::new(); - - let src_glyphs = auxiliary_lists.glyph_instances(&text_run.glyph_range); - let mut glyph_key = GlyphKey::new(text_run.font_key, - text_run.size, - text_run.blur_radius, - src_glyphs[0].index); - let blur_offset = text_run.blur_radius.to_f32_px() * - (BLUR_INFLATION_FACTOR as f32) / 2.0; - - let mut glyphs: [PackedTextRunGlyph; GLYPHS_PER_TEXT_RUN] = unsafe { - mem::zeroed() - }; - - self.rect = Rect::zero(); - for (glyph_index, glyph) in src_glyphs.iter().enumerate() { - glyph_key.index = glyph.index; - - let image_info = match resource_cache.get_glyph(&glyph_key, frame_id) { - None => continue, - Some(image_info) => image_info, - }; - - debug_assert!(cache.color_texture_id == TextureId(0) || - cache.color_texture_id == image_info.texture_id); - cache.color_texture_id = image_info.texture_id; - - let x = glyph.x + image_info.user_data.x0 as f32 / device_pixel_ratio - - blur_offset; - let y = glyph.y - image_info.user_data.y0 as f32 / device_pixel_ratio - - blur_offset; - - let width = image_info.requested_rect.size.width as f32 / - device_pixel_ratio; - let height = image_info.requested_rect.size.height as f32 / - device_pixel_ratio; - - let local_glyph_rect = Rect::new(Point2D::new(x, y), - Size2D::new(width, height)); - self.rect = self.rect.union(&local_glyph_rect); - - glyphs[glyph_index] = PackedTextRunGlyph { - local_rect: local_glyph_rect, - uv0: Point2D::new(image_info.pixel_rect.top_left.x.0 as f32, - image_info.pixel_rect.top_left.y.0 as f32), - uv1: Point2D::new(image_info.pixel_rect.bottom_right.x.0 as f32, - image_info.pixel_rect.bottom_right.y.0 as f32), - } - } - - cache.glyphs = Some(PackedTextRunPrimitive { - common: PackedPrimitiveInfo { - padding: [0, 0], - task_id: 0.0, - layer_index: layer_index, - local_clip_rect: self.local_clip_rect, - local_rect: self.rect, - }, - color: text_run.color, - glyphs: glyphs, - }); - - text_run.cache = Some(cache); - } - } - - self.rebuild_bounding_rect(screen_rect, - layer_transform, - layer_combined_local_clip_rect, - device_pixel_ratio); - } - - fn build_resource_list(&mut self, - resource_list: &mut ResourceList, - auxiliary_lists: &AuxiliaryLists) -> bool { - match self.details { - PrimitiveDetails::Rectangle(..) => false, - PrimitiveDetails::BoxShadow(ref details) => { - details.cache.is_none() - } - PrimitiveDetails::Gradient(ref details) => { - details.cache.is_none() - } - PrimitiveDetails::Border(ref details) => { - details.cache.is_none() - } - PrimitiveDetails::Image(ref details) => { - match details.kind { - ImagePrimitiveKind::Image(image_key, image_rendering, _, _) => { - resource_list.add_image(image_key, image_rendering); - } - ImagePrimitiveKind::WebGL(..) => {} - } - details.cache.is_none() - } - PrimitiveDetails::Text(ref details) => { - let glyphs = auxiliary_lists.glyph_instances(&ItemRange { - start: details.glyph_index as usize, - length: 1, - }); - for glyph in glyphs { - let glyph = Glyph::new(details.size, details.blur_radius, glyph.index); - resource_list.add_glyph(details.font_key, glyph); - } - details.cache.is_none() - } - PrimitiveDetails::TextRun(ref details) => { - let glyphs = auxiliary_lists.glyph_instances(&details.glyph_range); - for glyph in glyphs { - let glyph = Glyph::new(details.size, details.blur_radius, glyph.index); - resource_list.add_glyph(details.font_key, glyph); - } - details.cache.is_none() - } - } - } - - // Optional narrow phase intersection test, depending on primitive type. - fn affects_tile(&self, - tile_rect: &Rect, - transform: &Matrix4D, - device_pixel_ratio: f32) -> bool { - match self.details { - PrimitiveDetails::Rectangle(..) => true, - PrimitiveDetails::Text(..) => true, - PrimitiveDetails::TextRun(..) => true, - PrimitiveDetails::Image(..) => true, - PrimitiveDetails::Gradient(..) => true, - PrimitiveDetails::BoxShadow(..) => true, - PrimitiveDetails::Border(ref border) => { - let inner_rect = rect_from_points_f(border.tl_inner.x.max(border.bl_inner.x), - border.tl_inner.y.max(border.tr_inner.y), - border.tr_inner.x.min(border.br_inner.x), - border.bl_inner.y.min(border.br_inner.y)); - let inner_rect = TransformedRect::new(&inner_rect, transform, device_pixel_ratio); - - !inner_rect.bounding_rect.contains_rect(tile_rect) - } - } - } - - fn add_to_batch(&self, - batch: &mut PrimitiveBatch, - layer_index: StackingContextIndex, - task_id: f32, - transform_kind: TransformedRectKind, - needs_blending: bool) -> bool { - if transform_kind != batch.transform_kind || - needs_blending != batch.blending_enabled { - return false - } - - let layer_index = pack_as_float(layer_index.0 as u32); - - match (&mut batch.data, &self.details) { - (&mut PrimitiveBatchData::Blend(..), _) => return false, - (&mut PrimitiveBatchData::Composite(..), _) => return false, - (&mut PrimitiveBatchData::Rectangles(ref mut data), - &PrimitiveDetails::Rectangle(ref rectangle)) => { - if self.complex_clip.is_some() { - return false; - } - data.push(PackedRectanglePrimitive { - common: PackedPrimitiveInfo { - padding: [0, 0], - task_id: task_id, - layer_index: layer_index, - local_clip_rect: self.local_clip_rect, - local_rect: self.rect, - }, - color: rectangle.color, - }); - } - (&mut PrimitiveBatchData::Rectangles(..), _) => return false, - (&mut PrimitiveBatchData::RectanglesClip(ref mut data), - &PrimitiveDetails::Rectangle(ref rectangle)) => { - if self.complex_clip.is_none() { - return false; - } - data.push(PackedRectanglePrimitiveClip { - common: PackedPrimitiveInfo { - padding: [0, 0], - task_id: task_id, - layer_index: layer_index, - local_clip_rect: self.local_clip_rect, - local_rect: self.rect, - }, - color: rectangle.color, - clip: *self.complex_clip.as_ref().unwrap().clone(), - }); - } - (&mut PrimitiveBatchData::RectanglesClip(..), _) => return false, - (&mut PrimitiveBatchData::Image(ref mut data), - &PrimitiveDetails::Image(ref image)) => { - let cache = image.cache.as_ref().expect("No image cache!"); - - match cache { - &ImagePrimitiveCache::Normal(ref element) => { - if batch.color_texture_id != TextureId(0) && element.texture_id != batch.color_texture_id { - return false - } - - let mut element = element.clone(); - element.common.task_id = task_id; - data.push(element); - } - &ImagePrimitiveCache::Clip(..) => return false, - } - - } - (&mut PrimitiveBatchData::Image(..), _) => return false, - (&mut PrimitiveBatchData::ImageClip(ref mut data), - &PrimitiveDetails::Image(ref image)) => { - let cache = image.cache.as_ref().expect("No image cache!"); - - match cache { - &ImagePrimitiveCache::Normal(..) => return false, - &ImagePrimitiveCache::Clip(ref element) => { - if batch.color_texture_id != TextureId(0) && element.texture_id != batch.color_texture_id { - return false - } - - let mut element = element.clone(); - element.common.task_id = task_id; - data.push(element); - } - } - } - (&mut PrimitiveBatchData::ImageClip(..), _) => return false, - (&mut PrimitiveBatchData::Borders(ref mut data), - &PrimitiveDetails::Border(ref border)) => { - let cache = border.cache.as_ref().expect("No cache for border present!"); - - for element in &cache.elements { - let mut element = element.clone(); - element.common.task_id = task_id; - data.push(element); - } - } - (&mut PrimitiveBatchData::Borders(..), _) => return false, - (&mut PrimitiveBatchData::AlignedGradient(ref mut data), - &PrimitiveDetails::Gradient(ref gradient)) => { - match gradient.cache { - Some(GradientPrimitiveCache::Aligned(ref pieces)) => { - for piece in pieces { - let mut piece = piece.clone(); - piece.common.task_id = task_id; - data.push(piece); - } - } - Some(GradientPrimitiveCache::Angle(..)) | None => return false, - } - } - (&mut PrimitiveBatchData::AlignedGradient(..), _) => return false, - (&mut PrimitiveBatchData::AngleGradient(ref mut data), - &PrimitiveDetails::Gradient(ref gradient)) => { - match gradient.cache { - Some(GradientPrimitiveCache::Angle(ref piece)) => { - let mut piece = piece.clone(); - piece.common.task_id = task_id; - data.push(piece); - } - Some(GradientPrimitiveCache::Aligned(..)) | None => return false, - } - } - (&mut PrimitiveBatchData::AngleGradient(..), _) => return false, - (&mut PrimitiveBatchData::BoxShadows(ref mut data), - &PrimitiveDetails::BoxShadow(ref shadow)) => { - let cache = shadow.cache.as_ref().expect("No cache for box shadow present!"); - - for element in &cache.elements { - let mut element = element.clone(); - element.common.task_id = task_id; - data.push(element); - } - } - (&mut PrimitiveBatchData::BoxShadows(..), _) => return false, - (&mut PrimitiveBatchData::Text(ref mut data), - &PrimitiveDetails::Text(ref text)) => { - let cache = match text.cache.as_ref() { - None => { - // This can happen if the resource cache failed to rasterize a glyph, - // perhaps because the font doesn't contain that glyph. In this case, - // render nothing (successfully). - return true - } - Some(cache) => cache, - }; - - if batch.color_texture_id != TextureId(0) && - cache.color_texture_id != batch.color_texture_id { - return false; - } - - batch.color_texture_id = cache.color_texture_id; - - for glyph in &cache.glyph { - let mut glyph = glyph.clone(); - glyph.common.task_id = task_id; - data.push(glyph); - } - } - (&mut PrimitiveBatchData::Text(..), _) => return false, - (&mut PrimitiveBatchData::TextRun(ref mut data), - &PrimitiveDetails::TextRun(ref text)) => { - let cache = text.cache.as_ref().expect("No cache for text run present!"); - - if batch.color_texture_id != TextureId(0) && - cache.color_texture_id != batch.color_texture_id { - return false; - } - - for glyphs in &cache.glyphs { - let mut glyphs = glyphs.clone(); - glyphs.common.task_id = task_id; - data.push(glyphs); - } - } - (&mut PrimitiveBatchData::TextRun(..), _) => return false, - } - - true - } - - fn rebuild_bounding_rect(&mut self, - screen_rect: &Rect, - layer_transform: &Matrix4D, - layer_combined_local_clip_rect: &Rect, - device_pixel_ratio: f32) { - self.bounding_rect = None; - - let local_rect; - match self.rect - .intersection(&self.local_clip_rect) - .and_then(|rect| rect.intersection(layer_combined_local_clip_rect)) { - Some(rect) => local_rect = rect, - None => return, - }; - - let xf_rect = TransformedRect::new(&local_rect, layer_transform, device_pixel_ratio); - if !xf_rect.bounding_rect.intersects(screen_rect) { - return - } - - self.bounding_rect = Some(xf_rect.bounding_rect) - } - - fn batch_kind(&self) -> AlphaBatchKind { - match (&self.details, &self.complex_clip) { - (&PrimitiveDetails::Rectangle(_), &None) => AlphaBatchKind::Rectangle, - (&PrimitiveDetails::Rectangle(_), &Some(_)) => AlphaBatchKind::RectangleClip, - (&PrimitiveDetails::Text(_), _) => AlphaBatchKind::Text, - (&PrimitiveDetails::TextRun(_), _) => AlphaBatchKind::TextRun, - (&PrimitiveDetails::Image(_), &None) => AlphaBatchKind::Image, - (&PrimitiveDetails::Image(_), &Some(_)) => AlphaBatchKind::ImageClip, - (&PrimitiveDetails::Border(_), _) => AlphaBatchKind::Border, - (&PrimitiveDetails::Gradient(ref gradient), _) => { - match gradient.kind { - GradientType::Horizontal | GradientType::Vertical => AlphaBatchKind::AlignedGradient, - GradientType::Rotated => AlphaBatchKind::AngleGradient, - } - } - (&PrimitiveDetails::BoxShadow(_), _) => AlphaBatchKind::BoxShadow, - } - } - - fn color_texture_id(&self, resource_cache: &ResourceCache, frame_id: FrameId) -> TextureId { - match self.details { - PrimitiveDetails::Rectangle(_) | - PrimitiveDetails::Border(_) | - PrimitiveDetails::Gradient(_) | - PrimitiveDetails::BoxShadow(_) => TextureId(0), - PrimitiveDetails::Text(ref text) => { - match text.cache { - Some(ref cache) => cache.color_texture_id, - None => TextureId(0), - } - } - PrimitiveDetails::TextRun(ref text_run) => { - match text_run.cache { - Some(ref cache) => cache.color_texture_id, - None => TextureId(0), - } - } - PrimitiveDetails::Image(ref image) => { - image.image_info(resource_cache, frame_id).color_texture_id - } - } - } + Blend, + Rectangle, + TextRun, + Image, + Border, + AlignedGradient, + AngleGradient, + BoxShadow, } #[derive(Copy, Clone, Debug)] @@ -1792,12 +766,18 @@ impl AlphaBatchKey { } } +// FIXME(gw): Change these to use the bitflags!() + #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] struct AlphaBatchKeyFlags(u8); impl AlphaBatchKeyFlags { - fn new(transform_kind: TransformedRectKind, needs_blending: bool) -> AlphaBatchKeyFlags { - AlphaBatchKeyFlags(((transform_kind as u8) << 1) | (needs_blending as u8)) + fn new(transform_kind: TransformedRectKind, + needs_blending: bool, + needs_clipping: bool) -> AlphaBatchKeyFlags { + AlphaBatchKeyFlags( ((needs_clipping as u8) << 2) | + ((transform_kind as u8) << 1) | + ((needs_blending as u8) << 0) ) } fn transform_kind(&self) -> TransformedRectKind { @@ -1811,160 +791,37 @@ impl AlphaBatchKeyFlags { fn needs_blending(&self) -> bool { (self.0 & 1) != 0 } -} -#[repr(u32)] -#[derive(Debug, Copy, Clone)] -enum PrimitivePart { - TopLeft, - TopRight, - BottomLeft, - BottomRight, - Top, - Left, - Bottom, - Right, + fn needs_clipping(&self) -> bool { + (self.0 & 4) != 0 + } } // All Packed Primitives below must be 16 byte aligned. #[derive(Debug, Clone)] -pub struct PackedPrimitiveInfo { - layer_index: f32, - task_id: f32, - padding: [u32; 2], - local_clip_rect: Rect, - local_rect: Rect, -} - -#[derive(Debug, Clone)] -pub struct PackedRectanglePrimitiveClip { - common: PackedPrimitiveInfo, - color: ColorF, - clip: Clip, -} - -#[derive(Debug, Clone)] -pub struct PackedRectanglePrimitive { - common: PackedPrimitiveInfo, - color: ColorF, -} - -#[derive(Debug, Clone)] -pub struct PackedGlyphPrimitive { - common: PackedPrimitiveInfo, - color: ColorF, - uv0: Point2D, - uv1: Point2D, -} - -#[derive(Debug, Clone)] -#[repr(C)] -pub struct PackedTextRunPrimitive { - common: PackedPrimitiveInfo, - color: ColorF, - glyphs: [PackedTextRunGlyph; GLYPHS_PER_TEXT_RUN], -} - -#[derive(Debug, Copy, Clone)] -#[repr(C)] -pub struct PackedTextRunGlyph { - local_rect: Rect, - uv0: Point2D, - uv1: Point2D, -} - -#[derive(Debug, Clone, Copy)] -pub enum TextureCoordKind { - Normalized = 0, - Pixel, -} - -#[derive(Debug, Clone)] -pub struct PackedImagePrimitive { - common: PackedPrimitiveInfo, - uv0: Point2D, - uv1: Point2D, - stretch_size: Size2D, - tile_spacing: Size2D, - uv_kind: f32, - texture_id: TextureId, - padding: [u32; 2], -} - -#[derive(Debug, Clone)] -pub struct PackedImagePrimitiveClip { - common: PackedPrimitiveInfo, - uv0: Point2D, - uv1: Point2D, - stretch_size: Size2D, - tile_spacing: Size2D, - uv_kind: f32, - texture_id: TextureId, - padding: [u32; 2], - clip: Clip, -} - -#[derive(Debug, Clone)] -pub struct PackedAlignedGradientPrimitive { - common: PackedPrimitiveInfo, - color0: ColorF, - color1: ColorF, - kind: f32, - padding: [u32; 3], - clip: Clip, -} - -// TODO(gw): Angle gradient only support 8 stops due -// to limits of interpolators. FIXME! -#[derive(Debug, Clone)] -pub struct PackedAngleGradientPrimitive { - common: PackedPrimitiveInfo, - start_point: Point2D, - end_point: Point2D, - stop_count: f32, - padding: [u32; 3], - colors: [ColorF; MAX_STOPS_PER_ANGLE_GRADIENT], - stops: [f32; MAX_STOPS_PER_ANGLE_GRADIENT], -} - -#[derive(Debug, Clone)] -pub struct PackedBorderPrimitive { - common: PackedPrimitiveInfo, - vertical_color: ColorF, - horizontal_color: ColorF, - outer_radius_x: f32, - outer_radius_y: f32, - inner_radius_x: f32, - inner_radius_y: f32, - style: [f32; 4], - part: [f32; 4], -} - -#[derive(Debug, Clone)] -pub struct PackedBoxShadowPrimitive { - common: PackedPrimitiveInfo, - color: ColorF, - border_radii: Point2D, - blur_radius: f32, - inverted: f32, - bs_rect: Rect, - src_rect: Rect, +pub struct PrimitiveInstance { + global_prim_id: i32, + prim_address: GpuStoreAddress, + task_id: i32, + layer_index: i32, + clip_address: GpuStoreAddress, + user_data: [i32; 3], } #[derive(Debug, Clone)] pub struct PackedBlendPrimitive { - src_task_id: f32, - target_task_id: f32, - brightness: f32, - opacity: f32, + src_task_id: i32, + target_task_id: i32, + brightness: i32, + opacity: i32, } #[derive(Debug, Copy, Clone)] struct PackedCompositeInfo { - kind: f32, - op: f32, - amount: f32, - padding: f32, + kind: i32, + op: i32, + amount: i32, + padding: i32, } impl PackedCompositeInfo { @@ -1998,42 +855,40 @@ impl PackedCompositeInfo { }; PackedCompositeInfo { - kind: pack_as_float(kind), - op: pack_as_float(op), - amount: amount, - padding: 0.0, + kind: kind, + op: op as i32, + amount: (amount * 65536.0).round() as i32, + padding: 0, } } } #[derive(Debug)] pub struct PackedCompositePrimitive { - src0_task_id: f32, - src1_task_id: f32, - target_task_id: f32, - padding: f32, + src0_task_id: i32, + src1_task_id: i32, + target_task_id: i32, + padding: i32, info: PackedCompositeInfo, } #[derive(Debug)] pub enum PrimitiveBatchData { - Rectangles(Vec), - RectanglesClip(Vec), - Borders(Vec), - BoxShadows(Vec), - Text(Vec), - TextRun(Vec), - Image(Vec), - ImageClip(Vec), + Rectangles(Vec), + TextRun(Vec), + Image(Vec), + Borders(Vec), + AlignedGradient(Vec), + AngleGradient(Vec), + BoxShadow(Vec), Blend(Vec), Composite(Vec), - AlignedGradient(Vec), - AngleGradient(Vec), } #[derive(Debug)] pub struct PrimitiveBatch { pub transform_kind: TransformedRectKind, + pub has_complex_clip: bool, pub color_texture_id: TextureId, // TODO(gw): Expand to sampler array to handle all glyphs! pub blending_enabled: bool, pub data: PrimitiveBatchData, @@ -2044,6 +899,7 @@ impl PrimitiveBatch { PrimitiveBatch { color_texture_id: TextureId(0), transform_kind: TransformedRectKind::AxisAligned, + has_complex_clip: false, blending_enabled: true, data: PrimitiveBatchData::Blend(Vec::new()), } @@ -2053,6 +909,7 @@ impl PrimitiveBatch { PrimitiveBatch { color_texture_id: TextureId(0), transform_kind: TransformedRectKind::AxisAligned, + has_complex_clip: false, blending_enabled: true, data: PrimitiveBatchData::Composite(Vec::new()), } @@ -2066,10 +923,10 @@ impl PrimitiveBatch { match &mut self.data { &mut PrimitiveBatchData::Blend(ref mut ubo_data) => { ubo_data.push(PackedBlendPrimitive { - src_task_id: pack_as_float(src_rect_index.0 as u32), - target_task_id: pack_as_float(target_rect_index.0 as u32), - opacity: opacity, - brightness: brightness, + src_task_id: src_rect_index.0 as i32, + target_task_id: target_rect_index.0 as i32, + opacity: (opacity * 65535.0).round() as i32, + brightness: (brightness * 65535.0).round() as i32, }); true @@ -2086,10 +943,10 @@ impl PrimitiveBatch { match &mut self.data { &mut PrimitiveBatchData::Composite(ref mut ubo_data) => { ubo_data.push(PackedCompositePrimitive { - src0_task_id: pack_as_float(rect0_index.0 as u32), - src1_task_id: pack_as_float(rect1_index.0 as u32), - target_task_id: pack_as_float(target_rect_index.0 as u32), - padding: 0.0, + src0_task_id: rect0_index.0 as i32, + src1_task_id: rect1_index.0 as i32, + target_task_id: target_rect_index.0 as i32, + padding: 0, info: info, }); @@ -2099,50 +956,27 @@ impl PrimitiveBatch { } } - fn new(prim: &Primitive, + fn new(batch_kind: AlphaBatchKind, transform_kind: TransformedRectKind, - blending_enabled: bool) -> PrimitiveBatch { - let data = match prim.details { - PrimitiveDetails::Rectangle(..) => { - match prim.complex_clip { - Some(..) => PrimitiveBatchData::RectanglesClip(Vec::new()), - None => PrimitiveBatchData::Rectangles(Vec::new()), - } - } - PrimitiveDetails::Border(..) => { - PrimitiveBatchData::Borders(Vec::new()) - } - PrimitiveDetails::BoxShadow(..) => { - PrimitiveBatchData::BoxShadows(Vec::new()) - } - PrimitiveDetails::Text(..) => { - PrimitiveBatchData::Text(Vec::new()) - } - PrimitiveDetails::TextRun(..) => { - PrimitiveBatchData::TextRun(Vec::new()) - } - PrimitiveDetails::Image(..) => { - match prim.complex_clip { - Some(..) => PrimitiveBatchData::ImageClip(Vec::new()), - None => PrimitiveBatchData::Image(Vec::new()), - } - } - PrimitiveDetails::Gradient(ref details) => { - match details.kind { - GradientType::Rotated => { - PrimitiveBatchData::AngleGradient(Vec::new()) - } - GradientType::Horizontal | GradientType::Vertical => { - PrimitiveBatchData::AlignedGradient(Vec::new()) - } - } - } + blending_enabled: bool, + has_complex_clip: bool, + color_texture_id: TextureId) -> PrimitiveBatch { + let data = match batch_kind { + AlphaBatchKind::Rectangle => PrimitiveBatchData::Rectangles(Vec::new()), + AlphaBatchKind::TextRun => PrimitiveBatchData::TextRun(Vec::new()), + AlphaBatchKind::Image => PrimitiveBatchData::Image(Vec::new()), + AlphaBatchKind::Border => PrimitiveBatchData::Borders(Vec::new()), + AlphaBatchKind::AlignedGradient => PrimitiveBatchData::AlignedGradient(Vec::new()), + AlphaBatchKind::AngleGradient => PrimitiveBatchData::AngleGradient(Vec::new()), + AlphaBatchKind::BoxShadow => PrimitiveBatchData::BoxShadow(Vec::new()), + AlphaBatchKind::Blend | AlphaBatchKind::Composite => unreachable!(), }; PrimitiveBatch { - color_texture_id: TextureId(0), + color_texture_id: color_texture_id, transform_kind: transform_kind, blending_enabled: blending_enabled, + has_complex_clip: has_complex_clip, data: data, } } @@ -2163,7 +997,6 @@ struct TileRange { } struct StackingContext { - index: StackingContextIndex, pipeline_id: PipelineId, local_transform: Matrix4D, local_rect: Rect, @@ -2257,49 +1090,6 @@ impl StackingContext { } } -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -struct ClipIndex(usize); - -#[derive(Debug, Clone)] -pub struct ClipCorner { - rect: Rect, - outer_radius_x: f32, - outer_radius_y: f32, - inner_radius_x: f32, - inner_radius_y: f32, -} - -impl ClipCorner { - fn invalid(rect: Rect) -> ClipCorner { - ClipCorner { - rect: rect, - outer_radius_x: 0.0, - outer_radius_y: 0.0, - inner_radius_x: 0.0, - inner_radius_y: 0.0, - } - } - - fn uniform(rect: Rect, outer_radius: f32, inner_radius: f32) -> ClipCorner { - ClipCorner { - rect: rect, - outer_radius_x: outer_radius, - outer_radius_y: outer_radius, - inner_radius_x: inner_radius, - inner_radius_y: inner_radius, - } - } -} - -#[derive(Debug, Clone)] -pub struct Clip { - rect: Rect, - top_left: ClipCorner, - top_right: ClipCorner, - bottom_left: ClipCorner, - bottom_right: ClipCorner, -} - #[derive(Debug, Clone)] pub struct ClearTile { pub rect: Rect, @@ -2320,7 +1110,7 @@ impl FrameBuilderConfig { pub struct FrameBuilder { screen_rect: Rect, - prim_store: Vec, + prim_store: PrimitiveStore, cmds: Vec, device_pixel_ratio: f32, debug: bool, @@ -2338,87 +1128,14 @@ pub struct Frame { pub phases: Vec, pub clear_tiles: Vec, pub profile_counters: FrameProfileCounters, + pub layer_texture_data: Vec, pub render_task_data: Vec, -} - -impl Clip { - pub fn from_clip_region(clip: &ComplexClipRegion) -> Clip { - Clip { - rect: clip.rect, - top_left: ClipCorner { - rect: Rect::new(Point2D::new(clip.rect.origin.x, clip.rect.origin.y), - Size2D::new(clip.radii.top_left.width, clip.radii.top_left.height)), - outer_radius_x: clip.radii.top_left.width, - outer_radius_y: clip.radii.top_left.height, - inner_radius_x: 0.0, - inner_radius_y: 0.0, - }, - top_right: ClipCorner { - rect: Rect::new(Point2D::new(clip.rect.origin.x + clip.rect.size.width - clip.radii.top_right.width, - clip.rect.origin.y), - Size2D::new(clip.radii.top_right.width, clip.radii.top_right.height)), - outer_radius_x: clip.radii.top_right.width, - outer_radius_y: clip.radii.top_right.height, - inner_radius_x: 0.0, - inner_radius_y: 0.0, - }, - bottom_left: ClipCorner { - rect: Rect::new(Point2D::new(clip.rect.origin.x, - clip.rect.origin.y + clip.rect.size.height - clip.radii.bottom_left.height), - Size2D::new(clip.radii.bottom_left.width, clip.radii.bottom_left.height)), - outer_radius_x: clip.radii.bottom_left.width, - outer_radius_y: clip.radii.bottom_left.height, - inner_radius_x: 0.0, - inner_radius_y: 0.0, - }, - bottom_right: ClipCorner { - rect: Rect::new(Point2D::new(clip.rect.origin.x + clip.rect.size.width - clip.radii.bottom_right.width, - clip.rect.origin.y + clip.rect.size.height - clip.radii.bottom_right.height), - Size2D::new(clip.radii.bottom_right.width, clip.radii.bottom_right.height)), - outer_radius_x: clip.radii.bottom_right.width, - outer_radius_y: clip.radii.bottom_right.height, - inner_radius_x: 0.0, - inner_radius_y: 0.0, - }, - } - } - - fn invalid(rect: Rect) -> Clip { - Clip { - rect: rect, - top_left: ClipCorner::invalid(rect), - top_right: ClipCorner::invalid(rect), - bottom_left: ClipCorner::invalid(rect), - bottom_right: ClipCorner::invalid(rect), - } - } - - pub fn uniform(rect: Rect, radius: f32) -> Clip { - Clip { - rect: rect, - top_left: ClipCorner::uniform(Rect::new(Point2D::new(rect.origin.x, - rect.origin.y), - Size2D::new(radius, radius)), - radius, - 0.0), - top_right: ClipCorner::uniform(Rect::new(Point2D::new(rect.origin.x + rect.size.width - radius, - rect.origin.y), - Size2D::new(radius, radius)), - radius, - 0.0), - bottom_left: ClipCorner::uniform(Rect::new(Point2D::new(rect.origin.x, - rect.origin.y + rect.size.height - radius), - Size2D::new(radius, radius)), - radius, - 0.0), - bottom_right: ClipCorner::uniform(Rect::new(Point2D::new(rect.origin.x + rect.size.width - radius, - rect.origin.y + rect.size.height - radius), - Size2D::new(radius, radius)), - radius, - 0.0), - } - } + pub gpu_data16: Vec, + pub gpu_data32: Vec, + pub gpu_data64: Vec, + pub gpu_data128: Vec, + pub gpu_geometry: Vec, } #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] @@ -2571,12 +1288,14 @@ impl ScreenTile { // any occlusion culling! if self.is_simple { let layer = &ctx.layer_store[sc_index.0]; - let prim = &ctx.prim_store[prim_index.0]; + + let prim_metadata = ctx.prim_store.get_metadata(prim_index); + let prim_bounding_rect = ctx.prim_store.get_bounding_rect(prim_index); if layer.xf_rect.as_ref().unwrap().kind == TransformedRectKind::AxisAligned && - prim.complex_clip.is_none() && - prim.is_opaque(ctx.resource_cache, ctx.frame_id) && - prim.bounding_rect.as_ref().unwrap().contains_rect(&self.rect) { + prim_metadata.clip_index.is_none() && + prim_metadata.is_opaque && + prim_bounding_rect.as_ref().unwrap().contains_rect(&self.rect) { current_task.as_alpha_batch().items.clear(); } } @@ -2610,7 +1329,7 @@ impl FrameBuilder { FrameBuilder { screen_rect: Rect::new(Point2D::zero(), viewport_size), layer_store: Vec::new(), - prim_store: Vec::new(), + prim_store: PrimitiveStore::new(), cmds: Vec::new(), device_pixel_ratio: device_pixel_ratio, debug: debug, @@ -2623,16 +1342,11 @@ impl FrameBuilder { rect: &Rect, clip_rect: &Rect, clip: Option>, - details: PrimitiveDetails) -> PrimitiveIndex { - let prim = Primitive { - rect: *rect, - complex_clip: clip, - local_clip_rect: *clip_rect, - details: details, - bounding_rect: None, - }; - let prim_index = PrimitiveIndex(self.prim_store.len()); - self.prim_store.push(prim); + container: PrimitiveContainer) -> PrimitiveIndex { + let prim_index = self.prim_store.add_primitive(rect, + clip_rect, + clip, + container); match self.cmds.last_mut().unwrap() { &mut PrimitiveRunCmd::PrimitiveRun(_run_prim_index, ref mut count) => { @@ -2659,7 +1373,6 @@ impl FrameBuilder { let sc_index = StackingContextIndex(self.layer_store.len()); let sc = StackingContext { - index: sc_index, local_rect: rect, local_transform: transform, scroll_layer_id: scroll_layer_id, @@ -2703,7 +1416,7 @@ impl FrameBuilder { let prim_index = self.add_primitive(rect, clip_rect, clip, - PrimitiveDetails::Rectangle(prim)); + PrimitiveContainer::Rectangle(prim)); match flags { PrimitiveFlags::None => {} @@ -2752,6 +1465,12 @@ impl FrameBuilder { return; } + // These colors are used during inset/outset scaling. + let left_color = left.border_color(1.0, 2.0/3.0, 0.3, 0.7); + let top_color = top.border_color(1.0, 2.0/3.0, 0.3, 0.7); + let right_color = right.border_color(2.0/3.0, 1.0, 0.7, 0.3); + let bottom_color = bottom.border_color(2.0/3.0, 1.0, 0.7, 0.3); + let tl_outer = Point2D::new(rect.origin.x, rect.origin.y); let tl_inner = tl_outer + Point2D::new(radius.top_left.width.max(left.width), radius.top_left.height.max(top.width)); @@ -2769,41 +1488,36 @@ impl FrameBuilder { let br_inner = br_outer - Point2D::new(radius.bottom_right.width.max(right.width), radius.bottom_right.height.max(bottom.width)); - // These colors are used during inset/outset scaling. - let left_color = left.border_color(1.0, 2.0/3.0, 0.3, 0.7); - let top_color = top.border_color(1.0, 2.0/3.0, 0.3, 0.7); - let right_color = right.border_color(2.0/3.0, 1.0, 0.7, 0.3); - let bottom_color = bottom.border_color(2.0/3.0, 1.0, 0.7, 0.3); + let inner_rect = rect_from_points_f(tl_inner.x.max(bl_inner.x), + tl_inner.y.max(tr_inner.y), + tr_inner.x.min(br_inner.x), + bl_inner.y.min(br_inner.y)); + + let prim_cpu = BorderPrimitiveCpu { + inner_rect: inner_rect, + }; - let prim = BorderPrimitive { - tl_outer: tl_outer, - tl_inner: tl_inner, - tr_outer: tr_outer, - tr_inner: tr_inner, - bl_outer: bl_outer, - bl_inner: bl_inner, - br_outer: br_outer, - br_inner: br_inner, - radius: radius.clone(), - left_width: left.width, - top_width: top.width, - bottom_width: bottom.width, - right_width: right.width, - left_color: left_color, - top_color: top_color, - bottom_color: bottom_color, - right_color: right_color, - left_style: left.style, - top_style: top.style, - right_style: right.style, - bottom_style: bottom.style, - cache: None, + let prim_gpu = BorderPrimitiveGpu { + colors: [ left_color, top_color, right_color, bottom_color ], + widths: [ left.width, top.width, right.width, bottom.width ], + style: [ + pack_as_float(left.style as u32), + pack_as_float(top.style as u32), + pack_as_float(right.style as u32), + pack_as_float(bottom.style as u32), + ], + radii: [ + radius.top_left, + radius.top_right, + radius.bottom_right, + radius.bottom_left, + ], }; self.add_primitive(&rect, clip_rect, clip, - PrimitiveDetails::Border(prim)); + PrimitiveContainer::Border(prim_cpu, prim_gpu)); } pub fn add_gradient(&mut self, @@ -2814,43 +1528,47 @@ impl FrameBuilder { end_point: Point2D, stops: ItemRange) { // Fast paths for axis-aligned gradients: - if start_point.x == end_point.x { - let prim = GradientPrimitive { - stops_range: stops, - kind: GradientType::Vertical, - start_point: start_point, - end_point: end_point, - cache: None, - }; - self.add_primitive(&rect, - clip_rect, - clip, - PrimitiveDetails::Gradient(prim)); + let mut reverse_stops = false; + let kind = if start_point.x == end_point.x { + GradientType::Vertical } else if start_point.y == end_point.y { - let prim = GradientPrimitive { - stops_range: stops, - kind: GradientType::Horizontal, - start_point: start_point, - end_point: end_point, - cache: None, - }; - self.add_primitive(&rect, - clip_rect, - clip, - PrimitiveDetails::Gradient(prim)); + GradientType::Horizontal } else { - let prim = GradientPrimitive { - stops_range: stops, - kind: GradientType::Rotated, - start_point: start_point, - end_point: end_point, - cache: None, - }; - self.add_primitive(&rect, - clip_rect, - clip, - PrimitiveDetails::Gradient(prim)); - } + reverse_stops = start_point.x > end_point.x; + GradientType::Rotated + }; + + let gradient_cpu = GradientPrimitiveCpu { + stops_range: stops, + kind: kind, + reverse_stops: reverse_stops, + }; + + // To get reftests exactly matching with reverse start/end + // points, it's necessary to reverse the gradient + // line in some cases. + let (sp, ep) = if reverse_stops { + (end_point, start_point) + } else { + (start_point, end_point) + }; + + // TODO(gw): The gradient shader only has a clip variant + // right now. So add an invalid clip if none is provided. + // Remove this when a non-clip gradient shader is added. + let clip = Some(clip.unwrap_or(Box::new(Clip::invalid(rect)))); + + let gradient_gpu = GradientPrimitiveGpu { + start_point: sp, + end_point: ep, + padding: [0.0, 0.0, 0.0], + kind: pack_as_float(kind as u32), + }; + + self.add_primitive(&rect, + clip_rect, + clip, + PrimitiveContainer::Gradient(gradient_cpu, gradient_gpu)); } pub fn add_text(&mut self, @@ -2870,38 +1588,30 @@ impl FrameBuilder { return } - let text_run_count = glyph_range.length / GLYPHS_PER_TEXT_RUN; - let text_count = glyph_range.length % GLYPHS_PER_TEXT_RUN; + let text_run_count = (glyph_range.length + 7) / 8; + for run_index in 0..text_run_count { + let start = run_index * 8; + let end = cmp::min(start + 8, glyph_range.length); + let sub_range = ItemRange { + start: glyph_range.start + start, + length: end - start, + }; - for text_run_index in 0..text_run_count { - let prim = TextRunPrimitive { - color: *color, + let prim_cpu = TextRunPrimitiveCpu { font_key: font_key, - size: size, + font_size: size, blur_radius: blur_radius, - glyph_range: ItemRange { - start: glyph_range.start + (text_run_index * GLYPHS_PER_TEXT_RUN), - length: GLYPHS_PER_TEXT_RUN, - }, - cache: None, + glyph_range: sub_range, }; - self.add_primitive(&rect, clip_rect, clip.clone(), PrimitiveDetails::TextRun(prim)); - } - - for text_index in 0..text_count { - let prim = TextPrimitive { + let prim_gpu = TextRunPrimitiveGpu { color: *color, - font_key: font_key, - size: size, - blur_radius: blur_radius, - glyph_index: (glyph_range.start + - text_run_count * GLYPHS_PER_TEXT_RUN + - text_index) as u32, - cache: None, }; - self.add_primitive(&rect, clip_rect, clip.clone(), PrimitiveDetails::Text(prim)); + self.add_primitive(&rect, + clip_rect, + clip.clone(), + PrimitiveContainer::TextRun(prim_cpu, prim_gpu)); } } @@ -2937,14 +1647,17 @@ impl FrameBuilder { border_radius, blur_radius); - let prim_rect = match clip_mode { + let mut instance_rects = Vec::new(); + let (prim_rect, inverted) = match clip_mode { BoxShadowClipMode::Outset | BoxShadowClipMode::None => { - Rect::new(metrics.tl_outer, - Size2D::new(metrics.br_outer.x - metrics.tl_outer.x, - metrics.br_outer.y - metrics.tl_outer.y)) + let prim_rect = Rect::new(metrics.tl_outer, Size2D::new(metrics.br_outer.x - metrics.tl_outer.x, + metrics.br_outer.y - metrics.tl_outer.y)); + subtract_rect(&prim_rect, box_bounds, &mut instance_rects); + (prim_rect, 0.0) } BoxShadowClipMode::Inset => { - *box_bounds + subtract_rect(box_bounds, &bs_rect, &mut instance_rects); + (*box_bounds, 1.0) } }; @@ -2953,16 +1666,14 @@ impl FrameBuilder { bs_rect: bs_rect, color: *color, blur_radius: blur_radius, - spread_radius: spread_radius, - border_radius: border_radius, - clip_mode: clip_mode, - cache: None, + border_radii: Point2D::new(border_radius, border_radius), + inverted: inverted, }; self.add_primitive(&prim_rect, clip_rect, clip, - PrimitiveDetails::BoxShadow(prim)); + PrimitiveContainer::BoxShadow(prim, instance_rects)); } pub fn add_webgl_rectangle(&mut self, @@ -2970,15 +1681,14 @@ impl FrameBuilder { clip_rect: &Rect, clip: Option>, context_id: WebGLContextId) { - let prim = ImagePrimitive { + let prim_cpu = ImagePrimitiveCpu { kind: ImagePrimitiveKind::WebGL(context_id), - cache: None, }; self.add_primitive(&rect, clip_rect, clip, - PrimitiveDetails::Image(prim)); + PrimitiveContainer::Image(prim_cpu)); } pub fn add_image(&mut self, @@ -2989,18 +1699,17 @@ impl FrameBuilder { tile_spacing: &Size2D, image_key: ImageKey, image_rendering: ImageRendering) { - let prim = ImagePrimitive { + let prim_cpu = ImagePrimitiveCpu { kind: ImagePrimitiveKind::Image(image_key, image_rendering, stretch_size.clone(), tile_spacing.clone()), - cache: None, }; self.add_primitive(&rect, clip_rect, clip, - PrimitiveDetails::Image(prim)); + PrimitiveContainer::Image(prim_cpu)); } fn cull_layers(&mut self, @@ -3092,15 +1801,16 @@ impl FrameBuilder { for i in 0..prim_count { let prim_index = PrimitiveIndex(prim_index.0 + i); - let prim = &mut self.prim_store[prim_index.0]; - prim.rebuild_bounding_rect(screen_rect, - &packed_layer.transform, - &packed_layer.local_clip_rect, - self.device_pixel_ratio); - if prim.bounding_rect.is_some() { + if self.prim_store.build_bounding_rect(prim_index, + screen_rect, + &packed_layer.transform, + &packed_layer.local_clip_rect, + self.device_pixel_ratio) { profile_counters.visible_primitives.inc(); - if prim.build_resource_list(resource_list, auxiliary_lists) { + if self.prim_store.build_resource_list(prim_index, + resource_list, + auxiliary_lists) { layer.prims_to_prepare.push(prim_index) } } @@ -3181,9 +1891,7 @@ impl FrameBuilder { for i in 0..prim_count { let prim_index = PrimitiveIndex(first_prim_index.0 + i); - let prim = &self.prim_store[prim_index.0]; - - if let Some(ref p_rect) = prim.bounding_rect { + if let &Some(p_rect) = self.prim_store.get_bounding_rect(prim_index) { // TODO(gw): Ensure that certain primitives (such as background-image) only get // assigned to tiles where their containing layer intersects with. // Does this cause any problems / demonstrate other bugs? @@ -3210,9 +1918,10 @@ impl FrameBuilder { // TODO(gw): Support narrow phase for 3d transform elements! if xf_rect.kind == TransformedRectKind::Complex || - prim.affects_tile(&tile.rect, - &packed_layer.transform, - self.device_pixel_ratio) { + self.prim_store.prim_affects_tile(prim_index, + &tile.rect, + &packed_layer.transform, + self.device_pixel_ratio) { tile.push_primitive(prim_index); } } @@ -3256,15 +1965,17 @@ impl FrameBuilder { .expect("No auxiliary lists?!"); for prim_index in layer.prims_to_prepare.drain(..) { - let prim = &mut self.prim_store[prim_index.0]; - prim.prepare_for_render(screen_rect, - layer.index, - &packed_layer.transform, - &packed_layer.local_clip_rect, - resource_cache, - frame_id, - self.device_pixel_ratio, - auxiliary_lists); + if self.prim_store.prepare_prim_for_render(prim_index, + resource_cache, + frame_id, + self.device_pixel_ratio, + auxiliary_lists) { + self.prim_store.build_bounding_rect(prim_index, + screen_rect, + &packed_layer.transform, + &packed_layer.local_clip_rect, + self.device_pixel_ratio); + } } } } @@ -3274,13 +1985,14 @@ impl FrameBuilder { let distance_from_edge = 8.0; for scrollbar_prim in &self.scrollbar_prims { - let prim = &mut self.prim_store[scrollbar_prim.prim_index.0]; + let mut geom = (*self.prim_store.gpu_geometry.get(GpuStoreAddress(scrollbar_prim.prim_index.0 as i32))).clone(); let scroll_layer = &layer_map[&scrollbar_prim.scroll_layer_id]; let scrollable_distance = scroll_layer.content_size.height - scroll_layer.local_viewport_rect.size.height; if scrollable_distance <= 0.0 { - prim.local_clip_rect.size = Size2D::zero(); + geom.local_clip_rect.size = Size2D::zero(); + *self.prim_store.gpu_geometry.get_mut(GpuStoreAddress(scrollbar_prim.prim_index.0 as i32)) = geom; continue; } @@ -3293,23 +2005,24 @@ impl FrameBuilder { let max_y = scroll_layer.local_viewport_rect.origin.y + scroll_layer.local_viewport_rect.size.height - scroll_layer.scrolling.offset.y - - prim.rect.size.height - + geom.local_rect.size.height - distance_from_edge; - prim.rect.origin.x = scroll_layer.local_viewport_rect.origin.x + - scroll_layer.local_viewport_rect.size.width - - prim.rect.size.width - - distance_from_edge; + geom.local_rect.origin.x = scroll_layer.local_viewport_rect.origin.x + + scroll_layer.local_viewport_rect.size.width - + geom.local_rect.size.width - + distance_from_edge; - prim.rect.origin.y = util::lerp(min_y, max_y, f); - prim.local_clip_rect = prim.rect; + geom.local_rect.origin.y = util::lerp(min_y, max_y, f); + geom.local_clip_rect = geom.local_rect; if scrollbar_prim.border_radius == 0.0 { - prim.complex_clip = None; + self.prim_store.set_complex_clip(scrollbar_prim.prim_index, None); } else { - prim.complex_clip = Some(Box::new(Clip::uniform(prim.rect, - scrollbar_prim.border_radius))); + let clip = Clip::uniform(geom.local_rect, scrollbar_prim.border_radius); + self.prim_store.set_complex_clip(scrollbar_prim.prim_index, Some(clip)); } + *self.prim_store.gpu_geometry.get_mut(GpuStoreAddress(scrollbar_prim.prim_index.0 as i32)) = geom; } } @@ -3319,7 +2032,7 @@ impl FrameBuilder { pipeline_auxiliary_lists: &HashMap>, layer_map: &HashMap>) -> Frame { let mut profile_counters = FrameProfileCounters::new(); - profile_counters.total_primitives.set(self.prim_store.len()); + profile_counters.total_primitives.set(self.prim_store.prim_count()); let screen_rect = Rect::new(Point2D::zero(), Size2D::new(DevicePixel::new(self.screen_rect.size.width as f32, self.device_pixel_ratio), @@ -3351,8 +2064,6 @@ impl FrameBuilder { let ctx = RenderTargetContext { layer_store: &self.layer_store, prim_store: &self.prim_store, - resource_cache: resource_cache, - frame_id: frame_id, // This doesn't need to be atomic right now (all the screen tiles are // compiled on a single thread). However, in the future each of the @@ -3449,6 +2160,11 @@ impl FrameBuilder { RENDERABLE_CACHE_SIZE.0 as f32), layer_texture_data: self.packed_layers.clone(), render_task_data: render_tasks.render_task_data, + gpu_data16: self.prim_store.gpu_data16.build(), + gpu_data32: self.prim_store.gpu_data32.build(), + gpu_data64: self.prim_store.gpu_data64.build(), + gpu_data128: self.prim_store.gpu_data128.build(), + gpu_geometry: self.prim_store.gpu_geometry.build(), } } @@ -3491,42 +2207,3 @@ impl InsideTest for ComplexClipRegion { clip.radii.bottom_right.height >= self.radii.bottom_right.height - delta_bottom } } - -struct ImageInfo { - color_texture_id: TextureId, - uv0: Point2D, - uv1: Point2D, - stretch_size: Option>, - uv_kind: TextureCoordKind, - tile_spacing: Size2D, -} - -impl ImagePrimitive { - fn image_info(&self, resource_cache: &ResourceCache, frame_id: FrameId) -> ImageInfo { - match self.kind { - ImagePrimitiveKind::Image(image_key, image_rendering, stretch_size, tile_spacing) => { - let info = resource_cache.get_image(image_key, image_rendering, frame_id); - ImageInfo { - color_texture_id: info.texture_id, - uv0: Point2D::new(info.pixel_rect.top_left.x.0 as f32, - info.pixel_rect.top_left.y.0 as f32), - uv1: Point2D::new(info.pixel_rect.bottom_right.x.0 as f32, - info.pixel_rect.bottom_right.y.0 as f32), - stretch_size: Some(stretch_size), - uv_kind: TextureCoordKind::Pixel, - tile_spacing: tile_spacing, - } - } - ImagePrimitiveKind::WebGL(context_id) => { - ImageInfo { - color_texture_id: resource_cache.get_webgl_texture(&context_id), - uv0: Point2D::new(0.0, 1.0), - uv1: Point2D::new(1.0, 0.0), - stretch_size: None, - uv_kind: TextureCoordKind::Normalized, - tile_spacing: Size2D::zero(), - } - } - } - } -} diff --git a/webrender/src/util.rs b/webrender/src/util.rs index 3874426f68..4d3dfa7b09 100644 --- a/webrender/src/util.rs +++ b/webrender/src/util.rs @@ -209,3 +209,120 @@ pub fn subtract_rect(rect: &Rect, } } } +#[derive(Debug, Clone, Copy, Eq, PartialEq)] +#[repr(u8)] +pub enum TransformedRectKind { + AxisAligned = 0, + Complex = 1, +} + +#[derive(Debug, Clone)] +pub struct TransformedRect { + pub local_rect: Rect, + pub bounding_rect: Rect, + pub vertices: [Point4D; 4], + pub kind: TransformedRectKind, +} + +impl TransformedRect { + pub fn new(rect: &Rect, + transform: &Matrix4D, + device_pixel_ratio: f32) -> TransformedRect { + + let kind = if transform.can_losslessly_transform_and_perspective_project_a_2d_rect() { + TransformedRectKind::AxisAligned + } else { + TransformedRectKind::Complex + }; + + // FIXME(gw): This code is meant to be a fast path for simple transforms. + // However, it fails on transforms that translate Z but result in an + // axis aligned rect. + +/* + match kind { + TransformedRectKind::AxisAligned => { + let v0 = transform.transform_point(&rect.origin); + let v1 = transform.transform_point(&rect.top_right()); + let v2 = transform.transform_point(&rect.bottom_left()); + let v3 = transform.transform_point(&rect.bottom_right()); + + let screen_min_dp = Point2D::new(DevicePixel((v0.x * device_pixel_ratio).floor() as i32), + DevicePixel((v0.y * device_pixel_ratio).floor() as i32)); + let screen_max_dp = Point2D::new(DevicePixel((v3.x * device_pixel_ratio).ceil() as i32), + DevicePixel((v3.y * device_pixel_ratio).ceil() as i32)); + + let screen_rect_dp = Rect::new(screen_min_dp, Size2D::new(screen_max_dp.x - screen_min_dp.x, + screen_max_dp.y - screen_min_dp.y)); + + TransformedRect { + local_rect: *rect, + vertices: [ + Point4D::new(v0.x, v0.y, 0.0, 1.0), + Point4D::new(v1.x, v1.y, 0.0, 1.0), + Point4D::new(v2.x, v2.y, 0.0, 1.0), + Point4D::new(v3.x, v3.y, 0.0, 1.0), + ], + bounding_rect: screen_rect_dp, + kind: kind, + } + } + TransformedRectKind::Complex => { + */ + let vertices = [ + transform.transform_point4d(&Point4D::new(rect.origin.x, + rect.origin.y, + 0.0, + 1.0)), + transform.transform_point4d(&Point4D::new(rect.bottom_left().x, + rect.bottom_left().y, + 0.0, + 1.0)), + transform.transform_point4d(&Point4D::new(rect.bottom_right().x, + rect.bottom_right().y, + 0.0, + 1.0)), + transform.transform_point4d(&Point4D::new(rect.top_right().x, + rect.top_right().y, + 0.0, + 1.0)), + ]; + + + let mut screen_min : Point2D = Point2D::new(10000000.0, 10000000.0); + let mut screen_max : Point2D = Point2D::new(-10000000.0, -10000000.0); + + for vertex in &vertices { + let inv_w = 1.0 / vertex.w; + let vx = vertex.x * inv_w; + let vy = vertex.y * inv_w; + screen_min.x = screen_min.x.min(vx); + screen_min.y = screen_min.y.min(vy); + screen_max.x = screen_max.x.max(vx); + screen_max.y = screen_max.y.max(vy); + } + + let screen_min_dp = Point2D::new(DevicePixel((screen_min.x * device_pixel_ratio).floor() as i32), + DevicePixel((screen_min.y * device_pixel_ratio).floor() as i32)); + let screen_max_dp = Point2D::new(DevicePixel((screen_max.x * device_pixel_ratio).ceil() as i32), + DevicePixel((screen_max.y * device_pixel_ratio).ceil() as i32)); + + let screen_rect_dp = Rect::new(screen_min_dp, Size2D::new(screen_max_dp.x - screen_min_dp.x, + screen_max_dp.y - screen_min_dp.y)); + + TransformedRect { + local_rect: *rect, + vertices: vertices, + bounding_rect: screen_rect_dp, + kind: kind, + } + /* + } + }*/ + } +} + +#[inline(always)] +pub fn pack_as_float(value: u32) -> f32 { + value as f32 + 0.5 +}