From 4615f96f98f7706ec8df18e65c1ea439bb45bf04 Mon Sep 17 00:00:00 2001 From: Glenn Watson Date: Tue, 18 Oct 2016 13:45:34 +1000 Subject: [PATCH 1/4] Switch primitives to be stored in SoA style in vertex textures. The primary goals of this patch are: (1) Store primitives in SoA style. This makes some passes, such as culling primitives much faster due to better cache coherency. (2) Store primitives in flat arrays, for direct upload to GPU. This reduces the amount of redundant copying on the CPU during frame construction. (3) Decouple primitive information from geometry instances. This allows us to improve occlusion culling, by submitting segments of primitives without any extra CPU overhead of copying primitive data. (4) Allow incremental updates of the GPU SoA arrays during scrolling and zoom. This isn't implemented yet, but the framework is in place and will allow significant backend/compositor thread improvements during scrolling and zoom frames. There's also a number of other changes that have been rolled in to this patch since it made sense to fix them at the same time. In particular: * Blend/composite batches are stored as ints, avoiding CPU float packing overhead. * Border segment rectangles are calculated in the vertex shader rather than CPU. * Gradient colors use vertex shader interpolators for axis aligned gradients, reducing FS overhead. * Removed separate Text/TextRun shader types, resulting in better batching and fewer draw calls. * Angle gradients support arbitrary stop count in primitive data. * Removed some unused interpolators from the border shader. * Axis aligned gradient segments are calculated in vertex shader, reducing CPU overhead. * Reduced size of packed image structure - UV type is stored in sign of UV field. * Reduced size of packed glyph structure - color stored per run, rect calculated from UVs. * Moved some utility types from tiling.rs to util.rs. * Remove clip cases from batch enum, store needs_clipping flag in batch key. --- webrender/res/clip_shared.glsl | 3 +- webrender/res/prim_shared.glsl | 517 +++--- webrender/res/ps_angle_gradient.vs.glsl | 20 +- webrender/res/ps_blend.vs.glsl | 6 +- webrender/res/ps_border.glsl | 6 +- webrender/res/ps_border.vs.glsl | 214 ++- webrender/res/ps_box_shadow.vs.glsl | 10 +- webrender/res/ps_composite.vs.glsl | 10 +- webrender/res/ps_gradient_clip.fs.glsl | 2 +- webrender/res/ps_gradient_clip.glsl | 4 +- webrender/res/ps_gradient_clip.vs.glsl | 70 +- webrender/res/ps_image.vs.glsl | 29 +- webrender/res/ps_image_clip.glsl | 1 + webrender/res/ps_image_clip.vs.glsl | 37 +- webrender/res/ps_rectangle.vs.glsl | 13 +- webrender/res/ps_rectangle_clip.vs.glsl | 22 +- webrender/res/ps_text_run.vs.glsl | 24 +- webrender/src/device.rs | 38 +- webrender/src/frame.rs | 3 +- webrender/src/gpu_store.rs | 93 + webrender/src/internal_types.rs | 5 + webrender/src/lib.rs | 2 + webrender/src/prim_store.rs | 924 ++++++++++ webrender/src/renderer.rs | 158 +- webrender/src/tiling.rs | 2247 +++++------------------ webrender/src/util.rs | 113 ++ 26 files changed, 2309 insertions(+), 2262 deletions(-) create mode 100644 webrender/src/gpu_store.rs create mode 100644 webrender/src/prim_store.rs 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..fd2c998a8d 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); - vLocalPos = vi.local_clamped_pos; - vLocalRect = image.info.local_rect; + VertexInfo vi = write_vertex(prim.local_rect, + prim.local_clip_rect, + prim.layer, + prim.tile); + vLocalRect = prim.local_rect; + vLocalPos = vi.local_clamped_pos - vi.local_rect.p0; #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..23f4c8dfe4 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, @@ -810,6 +810,17 @@ impl Device { TextureId(0), TextureId(0), TextureId(0), + TextureId(0), + TextureId(0), + TextureId(0), + TextureId(0), + TextureId(0), + TextureId(0), + TextureId(0), + TextureId(0), + TextureId(0), + TextureId(0), + TextureId(0), ], bound_program: ProgramId(0), bound_vao: VAOId(0), @@ -1323,6 +1334,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..b3ed0129c9 --- /dev/null +++ b/webrender/src/prim_store.rs @@ -0,0 +1,924 @@ +/* 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, 0.0, 0.0, 0.0], + }, + 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, 0.0, 0.0, 0.0], + }, + 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.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()); + } + (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.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()); + 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, 0.0, 0.0], + }); + } + } 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, 0.0, 0.0], + }); + } + } + + 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..b1ba541e1a 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_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 || + prim_metadata.clip_index.is_some(); + let needs_clipping = prim_metadata.clip_index.is_some(); + 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)] @@ -1796,8 +770,12 @@ impl AlphaBatchKey { 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 +789,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 +853,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 +897,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 +907,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 +921,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 +941,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 +954,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 +995,6 @@ struct TileRange { } struct StackingContext { - index: StackingContextIndex, pipeline_id: PipelineId, local_transform: Matrix4D, local_rect: Rect, @@ -2257,49 +1088,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 +1108,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 +1126,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 +1286,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 +1327,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 +1340,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 +1371,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 +1414,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 +1463,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 +1486,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 +1526,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 +1586,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 +1645,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 +1664,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 +1679,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 +1697,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 +1799,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 +1889,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 +1916,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 +1963,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 +1983,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 +2003,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 +2030,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 +2062,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 +2158,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 +2205,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..00875491fa 100644 --- a/webrender/src/util.rs +++ b/webrender/src/util.rs @@ -209,3 +209,116 @@ 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 + }; + +/* + 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 +} From f51ae5030b6681b17e34020e7b6ae7777d1c5b38 Mon Sep 17 00:00:00 2001 From: Glenn Watson Date: Thu, 20 Oct 2016 12:02:37 +1000 Subject: [PATCH 2/4] Address some review comments. --- webrender/src/device.rs | 19 +------------------ webrender/src/prim_store.rs | 32 +++++++++++++++----------------- webrender/src/util.rs | 4 ++++ 3 files changed, 20 insertions(+), 35 deletions(-) diff --git a/webrender/src/device.rs b/webrender/src/device.rs index 23f4c8dfe4..240f338f8b 100644 --- a/webrender/src/device.rs +++ b/webrender/src/device.rs @@ -804,24 +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), - TextureId(0), - TextureId(0), - TextureId(0), - TextureId(0), - TextureId(0), - TextureId(0), - 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), diff --git a/webrender/src/prim_store.rs b/webrender/src/prim_store.rs index b3ed0129c9..7a305f7df7 100644 --- a/webrender/src/prim_store.rs +++ b/webrender/src/prim_store.rs @@ -263,7 +263,7 @@ impl Clip { Clip { rect: ClipRect { rect: rect, - padding: [0.0, 0.0, 0.0, 0.0], + padding: [0.0; 4], }, top_left: ClipCorner::invalid(rect), top_right: ClipCorner::invalid(rect), @@ -276,7 +276,7 @@ impl Clip { Clip { rect: ClipRect { rect: rect, - padding: [0.0, 0.0, 0.0, 0.0], + padding: [0.0; 4], }, top_left: ClipCorner::uniform(Rect::new(Point2D::new(rect.origin.x, rect.origin.y), @@ -509,11 +509,11 @@ impl PrimitiveStore { 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.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_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! @@ -523,11 +523,11 @@ impl PrimitiveStore { // 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.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_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) => {} @@ -693,9 +693,7 @@ impl PrimitiveStore { match uv_kind { TextureCoordKind::Normalized => {} - TextureCoordKind::Pixel => { - uv1.x = -uv1.x; - } + TextureCoordKind::Pixel => uv1.x = -uv1.x, } let image_gpu = self.gpu_data32.get_mut(metadata.gpu_prim_index); @@ -721,7 +719,7 @@ impl PrimitiveStore { *dest = GpuBlock32::from(GradientStop { offset: 1.0 - src.offset, color: src.color, - padding: [0.0, 0.0, 0.0], + padding: [0.0; 3], }); } } else { @@ -729,7 +727,7 @@ impl PrimitiveStore { *dest = GpuBlock32::from(GradientStop { offset: src.offset, color: src.color, - padding: [0.0, 0.0, 0.0], + padding: [0.0; 3], }); } } diff --git a/webrender/src/util.rs b/webrender/src/util.rs index 00875491fa..4d3dfa7b09 100644 --- a/webrender/src/util.rs +++ b/webrender/src/util.rs @@ -235,6 +235,10 @@ impl TransformedRect { 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 => { From 5908f8ccf55d8e2877b23a6ea07fae5ab134b939 Mon Sep 17 00:00:00 2001 From: Glenn Watson Date: Thu, 20 Oct 2016 12:58:44 +1000 Subject: [PATCH 3/4] Fix image_clip shader in b.html --- webrender/res/ps_image_clip.vs.glsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webrender/res/ps_image_clip.vs.glsl b/webrender/res/ps_image_clip.vs.glsl index fd2c998a8d..cac9591d94 100644 --- a/webrender/res/ps_image_clip.vs.glsl +++ b/webrender/res/ps_image_clip.vs.glsl @@ -20,7 +20,7 @@ void main(void) { prim.layer, prim.tile); vLocalRect = prim.local_rect; - vLocalPos = vi.local_clamped_pos - vi.local_rect.p0; + vLocalPos = vi.local_clamped_pos; #endif Clip clip = fetch_clip(prim.clip_index); From f112cf6df513ec05204987051c3a76c682cce2ba Mon Sep 17 00:00:00 2001 From: Glenn Watson Date: Fri, 21 Oct 2016 08:04:21 +1000 Subject: [PATCH 4/4] Address review comments. --- webrender/src/tiling.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/webrender/src/tiling.rs b/webrender/src/tiling.rs index b1ba541e1a..b139df04e9 100644 --- a/webrender/src/tiling.rs +++ b/webrender/src/tiling.rs @@ -346,10 +346,10 @@ impl AlphaBatcher { let layer = &ctx.layer_store[sc_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_metadata.is_opaque || - prim_metadata.clip_index.is_some(); - let needs_clipping = prim_metadata.clip_index.is_some(); + needs_clipping; let flags = AlphaBatchKeyFlags::new(transform_kind, needs_blending, needs_clipping); @@ -766,6 +766,8 @@ impl AlphaBatchKey { } } +// FIXME(gw): Change these to use the bitflags!() + #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] struct AlphaBatchKeyFlags(u8);