Bug 1470125 - Update webrender to commit cdfaaeb5f74e416f39af1081c9a676c752d23896. r=Gankro

Includes regenerated webrender_ffi_generated.h header.

MozReview-Commit-ID: I3lvkCH5IGz

--HG--
extra : rebase_source : 654102de6773960af67069e7e4c2b27474d9a04c
This commit is contained in:
Kartikaya Gupta 2018-06-28 11:48:27 -04:00
Родитель b2e0ee9be4
Коммит 5a3f051406
47 изменённых файлов: 1481 добавлений и 1257 удалений

Просмотреть файл

@ -27,12 +27,12 @@ cfg-if = "0.1.2"
euclid = "0.17.3" euclid = "0.17.3"
fxhash = "0.2.1" fxhash = "0.2.1"
gleam = "0.5" gleam = "0.5"
image = { optional = true, version = "0.18" } image = { optional = true, version = "0.19" }
lazy_static = "1" lazy_static = "1"
log = "0.4" log = "0.4"
num-traits = "0.1.43" num-traits = "0.1.43"
plane-split = "0.9.1" plane-split = "0.9.1"
png = { optional = true, version = "0.11" } png = { optional = true, version = "0.12" }
rayon = "1" rayon = "1"
ron = { optional = true, version = "0.1.7" } ron = { optional = true, version = "0.1.7" }
serde = { optional = true, version = "1.0", features = ["serde_derive"] } serde = { optional = true, version = "1.0", features = ["serde_derive"] }

Просмотреть файл

@ -16,7 +16,6 @@ void brush_vs(
vec4 segment_data vec4 segment_data
); );
#define VECS_PER_BRUSH_PRIM 2
#define VECS_PER_SEGMENT 2 #define VECS_PER_SEGMENT 2
#define BRUSH_FLAG_PERSPECTIVE_INTERPOLATION 1 #define BRUSH_FLAG_PERSPECTIVE_INTERPOLATION 1
@ -24,76 +23,19 @@ void brush_vs(
#define BRUSH_FLAG_SEGMENT_REPEAT_X 4 #define BRUSH_FLAG_SEGMENT_REPEAT_X 4
#define BRUSH_FLAG_SEGMENT_REPEAT_Y 8 #define BRUSH_FLAG_SEGMENT_REPEAT_Y 8
//Note: these have to match `gpu_types` constants
#define INT_BITS (31)
#define CLIP_CHAIN_RECT_BITS (22)
#define SEGMENT_BITS (INT_BITS - CLIP_CHAIN_RECT_BITS)
#define EDGE_FLAG_BITS (4)
#define BRUSH_FLAG_BITS (4)
#define CLIP_SCROLL_INDEX_BITS (INT_BITS - EDGE_FLAG_BITS - BRUSH_FLAG_BITS)
struct BrushInstance {
int picture_address;
int prim_address;
int clip_chain_rect_index;
int scroll_node_id;
int clip_address;
int z;
int segment_index;
int edge_mask;
int flags;
ivec3 user_data;
};
BrushInstance load_brush() {
BrushInstance bi;
bi.picture_address = aData0.x & 0xffff;
bi.clip_address = aData0.x >> 16;
bi.prim_address = aData0.y;
bi.clip_chain_rect_index = aData0.z & ((1 << CLIP_CHAIN_RECT_BITS) - 1);
bi.segment_index = aData0.z >> CLIP_CHAIN_RECT_BITS;
bi.z = aData0.w;
bi.scroll_node_id = aData1.x & ((1 << CLIP_SCROLL_INDEX_BITS) - 1);
bi.edge_mask = (aData1.x >> CLIP_SCROLL_INDEX_BITS) & 0xf;
bi.flags = (aData1.x >> (CLIP_SCROLL_INDEX_BITS + EDGE_FLAG_BITS)) & 0xf;
bi.user_data = aData1.yzw;
return bi;
}
struct BrushPrimitive {
RectWithSize local_rect;
RectWithSize local_clip_rect;
};
BrushPrimitive fetch_brush_primitive(int address, int clip_chain_rect_index) {
vec4 data[2] = fetch_from_resource_cache_2(address);
RectWithSize clip_chain_rect = fetch_clip_chain_rect(clip_chain_rect_index);
RectWithSize brush_clip_rect = RectWithSize(data[1].xy, data[1].zw);
RectWithSize clip_rect = intersect_rects(clip_chain_rect, brush_clip_rect);
BrushPrimitive prim = BrushPrimitive(RectWithSize(data[0].xy, data[0].zw), clip_rect);
return prim;
}
void main(void) { void main(void) {
// Load the brush instance from vertex attributes. // Load the brush instance from vertex attributes.
BrushInstance brush = load_brush(); int prim_header_address = aData.x;
int clip_address = aData.y;
// Load the geometry for this brush. For now, this is simply the int segment_index = aData.z & 0xffff;
// local rect of the primitive. In the future, this will support int edge_flags = (aData.z >> 16) & 0xff;
// loading segment rects, and other rect formats (glyphs). int brush_flags = (aData.z >> 24) & 0xff;
BrushPrimitive brush_prim = PrimitiveHeader ph = fetch_prim_header(prim_header_address);
fetch_brush_primitive(brush.prim_address, brush.clip_chain_rect_index);
// Fetch the segment of this brush primitive we are drawing. // Fetch the segment of this brush primitive we are drawing.
int segment_address = brush.prim_address + int segment_address = ph.specific_prim_address +
VECS_PER_BRUSH_PRIM +
VECS_PER_SPECIFIC_BRUSH + VECS_PER_SPECIFIC_BRUSH +
brush.segment_index * VECS_PER_SEGMENT; segment_index * VECS_PER_SEGMENT;
vec4[2] segment_data = fetch_from_resource_cache_2(segment_address); vec4[2] segment_data = fetch_from_resource_cache_2(segment_address);
RectWithSize local_segment_rect = RectWithSize(segment_data[0].xy, segment_data[0].zw); RectWithSize local_segment_rect = RectWithSize(segment_data[0].xy, segment_data[0].zw);
@ -101,20 +43,20 @@ void main(void) {
VertexInfo vi; VertexInfo vi;
// Fetch the dynamic picture that we are drawing on. // Fetch the dynamic picture that we are drawing on.
PictureTask pic_task = fetch_picture_task(brush.picture_address); PictureTask pic_task = fetch_picture_task(ph.render_task_index);
ClipArea clip_area = fetch_clip_area(brush.clip_address); ClipArea clip_area = fetch_clip_area(clip_address);
ClipScrollNode scroll_node = fetch_clip_scroll_node(brush.scroll_node_id); Transform transform = fetch_transform(ph.transform_id);
// Write the normal vertex information out. // Write the normal vertex information out.
if (scroll_node.is_axis_aligned) { if (transform.is_axis_aligned) {
vi = write_vertex( vi = write_vertex(
local_segment_rect, local_segment_rect,
brush_prim.local_clip_rect, ph.local_clip_rect,
float(brush.z), ph.z,
scroll_node, transform,
pic_task, pic_task,
brush_prim.local_rect ph.local_rect
); );
// TODO(gw): transform bounds may be referenced by // TODO(gw): transform bounds may be referenced by
@ -127,16 +69,16 @@ void main(void) {
init_transform_vs(vec4(vec2(-1000000.0), vec2(1000000.0))); init_transform_vs(vec4(vec2(-1000000.0), vec2(1000000.0)));
#endif #endif
} else { } else {
bvec4 edge_mask = notEqual(brush.edge_mask & ivec4(1, 2, 4, 8), ivec4(0)); bvec4 edge_mask = notEqual(edge_flags & ivec4(1, 2, 4, 8), ivec4(0));
bool do_perspective_interpolation = (brush.flags & BRUSH_FLAG_PERSPECTIVE_INTERPOLATION) != 0; bool do_perspective_interpolation = (brush_flags & BRUSH_FLAG_PERSPECTIVE_INTERPOLATION) != 0;
vi = write_transform_vertex( vi = write_transform_vertex(
local_segment_rect, local_segment_rect,
brush_prim.local_rect, ph.local_rect,
brush_prim.local_clip_rect, ph.local_clip_rect,
mix(vec4(0.0), vec4(1.0), edge_mask), mix(vec4(0.0), vec4(1.0), edge_mask),
float(brush.z), ph.z,
scroll_node, transform,
pic_task, pic_task,
do_perspective_interpolation do_perspective_interpolation
); );
@ -158,13 +100,13 @@ void main(void) {
// Run the specific brush VS code to write interpolators. // Run the specific brush VS code to write interpolators.
brush_vs( brush_vs(
vi, vi,
brush.prim_address + VECS_PER_BRUSH_PRIM, ph.specific_prim_address,
brush_prim.local_rect, ph.local_rect,
local_segment_rect, local_segment_rect,
brush.user_data, ph.user_data,
scroll_node.transform, transform.m,
pic_task, pic_task,
brush.flags, brush_flags,
segment_data[1] segment_data[1]
); );
} }

Просмотреть файл

@ -49,11 +49,16 @@ void brush_vs(
mat4 transform, mat4 transform,
PictureTask pic_task, PictureTask pic_task,
int brush_flags, int brush_flags,
vec4 unused vec4 texel_rect
) { ) {
Gradient gradient = fetch_gradient(prim_address); Gradient gradient = fetch_gradient(prim_address);
vPos = vi.local_pos - local_rect.p0; if ((brush_flags & BRUSH_FLAG_SEGMENT_RELATIVE) != 0) {
vPos = (vi.local_pos - segment_rect.p0) / segment_rect.size;
vPos = vPos * (texel_rect.zw - texel_rect.xy) + texel_rect.xy;
} else {
vPos = vi.local_pos - local_rect.p0;
}
vec2 start_point = gradient.start_end_point.xy; vec2 start_point = gradient.start_end_point.xy;
vec2 end_point = gradient.start_end_point.zw; vec2 end_point = gradient.start_end_point.zw;

Просмотреть файл

@ -49,11 +49,16 @@ void brush_vs(
mat4 transform, mat4 transform,
PictureTask pic_task, PictureTask pic_task,
int brush_flags, int brush_flags,
vec4 unused vec4 texel_rect
) { ) {
RadialGradient gradient = fetch_radial_gradient(prim_address); RadialGradient gradient = fetch_radial_gradient(prim_address);
vPos = vi.local_pos - local_rect.p0; if ((brush_flags & BRUSH_FLAG_SEGMENT_RELATIVE) != 0) {
vPos = (vi.local_pos - segment_rect.p0) / segment_rect.size;
vPos = vPos * (texel_rect.zw - texel_rect.xy) + texel_rect.xy;
} else {
vPos = vi.local_pos - local_rect.p0;
}
vCenter = gradient.center_start_end_radius.xy; vCenter = gradient.center_start_end_radius.xy;
vStartRadius = gradient.center_start_end_radius.z; vStartRadius = gradient.center_start_end_radius.z;

Просмотреть файл

@ -1,88 +0,0 @@
/* 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/. */
#ifdef WR_VERTEX_SHADER
#define VECS_PER_CLIP_SCROLL_NODE 9
uniform HIGHP_SAMPLER_FLOAT sampler2D sClipScrollNodes;
struct ClipScrollNode {
mat4 transform;
mat4 inv_transform;
bool is_axis_aligned;
};
ClipScrollNode fetch_clip_scroll_node(int index) {
ClipScrollNode node;
// Create a UV base coord for each 8 texels.
// This is required because trying to use an offset
// of more than 8 texels doesn't work on some versions
// of OSX.
ivec2 uv = get_fetch_uv(index, VECS_PER_CLIP_SCROLL_NODE);
ivec2 uv0 = ivec2(uv.x + 0, uv.y);
ivec2 uv1 = ivec2(uv.x + 8, uv.y);
node.transform[0] = TEXEL_FETCH(sClipScrollNodes, uv0, 0, ivec2(0, 0));
node.transform[1] = TEXEL_FETCH(sClipScrollNodes, uv0, 0, ivec2(1, 0));
node.transform[2] = TEXEL_FETCH(sClipScrollNodes, uv0, 0, ivec2(2, 0));
node.transform[3] = TEXEL_FETCH(sClipScrollNodes, uv0, 0, ivec2(3, 0));
node.inv_transform[0] = TEXEL_FETCH(sClipScrollNodes, uv0, 0, ivec2(4, 0));
node.inv_transform[1] = TEXEL_FETCH(sClipScrollNodes, uv0, 0, ivec2(5, 0));
node.inv_transform[2] = TEXEL_FETCH(sClipScrollNodes, uv0, 0, ivec2(6, 0));
node.inv_transform[3] = TEXEL_FETCH(sClipScrollNodes, uv0, 0, ivec2(7, 0));
vec4 misc = TEXEL_FETCH(sClipScrollNodes, uv1, 0, ivec2(0, 0));
node.is_axis_aligned = misc.x == 0.0;
return node;
}
// Return the intersection of the plane (set up by "normal" and "point")
// with the ray (set up by "ray_origin" and "ray_dir"),
// writing the resulting scaler into "t".
bool ray_plane(vec3 normal, vec3 pt, vec3 ray_origin, vec3 ray_dir, out float t)
{
float denom = dot(normal, ray_dir);
if (abs(denom) > 1e-6) {
vec3 d = pt - ray_origin;
t = dot(d, normal) / denom;
return t >= 0.0;
}
return false;
}
// Apply the inverse transform "inv_transform"
// to the reference point "ref" in CSS space,
// producing a local point on a ClipScrollNode plane,
// set by a base point "a" and a normal "n".
vec4 untransform(vec2 ref, vec3 n, vec3 a, mat4 inv_transform) {
vec3 p = vec3(ref, -10000.0);
vec3 d = vec3(0, 0, 1.0);
float t = 0.0;
// get an intersection of the ClipScrollNode plane with Z axis vector,
// originated from the "ref" point
ray_plane(n, a, p, d, t);
float z = p.z + d.z * t; // Z of the visible point on the ClipScrollNode
vec4 r = inv_transform * vec4(ref, z, 1.0);
return r;
}
// Given a CSS space position, transform it back into the ClipScrollNode space.
vec4 get_node_pos(vec2 pos, ClipScrollNode node) {
// get a point on the scroll node plane
vec4 ah = node.transform * vec4(0.0, 0.0, 0.0, 1.0);
vec3 a = ah.xyz / ah.w;
// get the normal to the scroll node plane
vec3 n = transpose(mat3(node.inv_transform)) * vec3(0.0, 0.0, 1.0);
return untransform(pos, n, a, node.inv_transform);
}
#endif //WR_VERTEX_SHADER

Просмотреть файл

@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include rect,clip_scroll,render_task,resource_cache,snap,transform #include rect,render_task,resource_cache,snap,transform
#ifdef WR_VERTEX_SHADER #ifdef WR_VERTEX_SHADER
@ -19,7 +19,7 @@ in ivec4 aClipDataResourceAddress;
struct ClipMaskInstance { struct ClipMaskInstance {
int render_task_address; int render_task_address;
int scroll_node_id; int transform_id;
int segment; int segment;
ivec2 clip_data_address; ivec2 clip_data_address;
ivec2 resource_address; ivec2 resource_address;
@ -29,7 +29,7 @@ ClipMaskInstance fetch_clip_item() {
ClipMaskInstance cmi; ClipMaskInstance cmi;
cmi.render_task_address = aClipRenderTaskAddress; cmi.render_task_address = aClipRenderTaskAddress;
cmi.scroll_node_id = aScrollNodeId; cmi.transform_id = aScrollNodeId;
cmi.segment = aClipSegment; cmi.segment = aClipSegment;
cmi.clip_data_address = aClipDataResourceAddress.xy; cmi.clip_data_address = aClipDataResourceAddress.xy;
cmi.resource_address = aClipDataResourceAddress.zw; cmi.resource_address = aClipDataResourceAddress.zw;
@ -51,20 +51,20 @@ RectWithSize intersect_rect(RectWithSize a, RectWithSize b) {
// The transformed vertex function that always covers the whole clip area, // The transformed vertex function that always covers the whole clip area,
// which is the intersection of all clip instances of a given primitive // which is the intersection of all clip instances of a given primitive
ClipVertexInfo write_clip_tile_vertex(RectWithSize local_clip_rect, ClipVertexInfo write_clip_tile_vertex(RectWithSize local_clip_rect,
ClipScrollNode scroll_node, Transform transform,
ClipArea area) { ClipArea area) {
vec2 device_pos = area.screen_origin + aPosition.xy * area.common_data.task_rect.size; vec2 device_pos = area.screen_origin + aPosition.xy * area.common_data.task_rect.size;
vec2 actual_pos = device_pos; vec2 actual_pos = device_pos;
if (scroll_node.is_axis_aligned) { if (transform.is_axis_aligned) {
vec4 snap_positions = compute_snap_positions( vec4 snap_positions = compute_snap_positions(
scroll_node.transform, transform.m,
local_clip_rect local_clip_rect
); );
vec2 snap_offsets = compute_snap_offset_impl( vec2 snap_offsets = compute_snap_offset_impl(
device_pos, device_pos,
scroll_node.transform, transform.m,
local_clip_rect, local_clip_rect,
RectWithSize(snap_positions.xy, snap_positions.zw - snap_positions.xy), RectWithSize(snap_positions.xy, snap_positions.zw - snap_positions.xy),
snap_positions, snap_positions,
@ -81,7 +81,7 @@ ClipVertexInfo write_clip_tile_vertex(RectWithSize local_clip_rect,
if (area.local_space) { if (area.local_space) {
node_pos = vec4(actual_pos / uDevicePixelRatio, 0.0, 1.0); node_pos = vec4(actual_pos / uDevicePixelRatio, 0.0, 1.0);
} else { } else {
node_pos = get_node_pos(actual_pos / uDevicePixelRatio, scroll_node); node_pos = get_node_pos(actual_pos / uDevicePixelRatio, transform);
} }
// compute the point position inside the scroll node, in CSS space // compute the point position inside the scroll node, in CSS space

Просмотреть файл

@ -41,12 +41,12 @@ BoxShadowData fetch_data(ivec2 address) {
void main(void) { void main(void) {
ClipMaskInstance cmi = fetch_clip_item(); ClipMaskInstance cmi = fetch_clip_item();
ClipArea area = fetch_clip_area(cmi.render_task_address); ClipArea area = fetch_clip_area(cmi.render_task_address);
ClipScrollNode scroll_node = fetch_clip_scroll_node(cmi.scroll_node_id); Transform transform = fetch_transform(cmi.transform_id);
BoxShadowData bs_data = fetch_data(cmi.clip_data_address); BoxShadowData bs_data = fetch_data(cmi.clip_data_address);
ImageResource res = fetch_image_resource_direct(cmi.resource_address); ImageResource res = fetch_image_resource_direct(cmi.resource_address);
ClipVertexInfo vi = write_clip_tile_vertex(bs_data.dest_rect, ClipVertexInfo vi = write_clip_tile_vertex(bs_data.dest_rect,
scroll_node, transform,
area); area);
vLayer = res.layer; vLayer = res.layer;

Просмотреть файл

@ -26,13 +26,13 @@ ImageMaskData fetch_mask_data(ivec2 address) {
void main(void) { void main(void) {
ClipMaskInstance cmi = fetch_clip_item(); ClipMaskInstance cmi = fetch_clip_item();
ClipArea area = fetch_clip_area(cmi.render_task_address); ClipArea area = fetch_clip_area(cmi.render_task_address);
ClipScrollNode scroll_node = fetch_clip_scroll_node(cmi.scroll_node_id); Transform transform = fetch_transform(cmi.transform_id);
ImageMaskData mask = fetch_mask_data(cmi.clip_data_address); ImageMaskData mask = fetch_mask_data(cmi.clip_data_address);
RectWithSize local_rect = mask.local_rect; RectWithSize local_rect = mask.local_rect;
ImageResource res = fetch_image_resource_direct(cmi.resource_address); ImageResource res = fetch_image_resource_direct(cmi.resource_address);
ClipVertexInfo vi = write_clip_tile_vertex(local_rect, ClipVertexInfo vi = write_clip_tile_vertex(local_rect,
scroll_node, transform,
area); area);
vPos = vi.local_pos; vPos = vi.local_pos;

Просмотреть файл

@ -43,11 +43,11 @@ LineDecorationData fetch_data(ivec2 address) {
void main(void) { void main(void) {
ClipMaskInstance cmi = fetch_clip_item(); ClipMaskInstance cmi = fetch_clip_item();
ClipArea area = fetch_clip_area(cmi.render_task_address); ClipArea area = fetch_clip_area(cmi.render_task_address);
ClipScrollNode scroll_node = fetch_clip_scroll_node(cmi.scroll_node_id); Transform transform = fetch_transform(cmi.transform_id);
LineDecorationData data = fetch_data(cmi.clip_data_address); LineDecorationData data = fetch_data(cmi.clip_data_address);
ClipVertexInfo vi = write_clip_tile_vertex(data.local_rect, ClipVertexInfo vi = write_clip_tile_vertex(data.local_rect,
scroll_node, transform,
area); area);

Просмотреть файл

@ -60,11 +60,11 @@ ClipData fetch_clip(ivec2 address) {
void main(void) { void main(void) {
ClipMaskInstance cmi = fetch_clip_item(); ClipMaskInstance cmi = fetch_clip_item();
ClipArea area = fetch_clip_area(cmi.render_task_address); ClipArea area = fetch_clip_area(cmi.render_task_address);
ClipScrollNode scroll_node = fetch_clip_scroll_node(cmi.scroll_node_id); Transform transform = fetch_transform(cmi.transform_id);
ClipData clip = fetch_clip(cmi.clip_data_address); ClipData clip = fetch_clip(cmi.clip_data_address);
RectWithSize local_rect = clip.rect.rect; RectWithSize local_rect = clip.rect.rect;
ClipVertexInfo vi = write_clip_tile_vertex(local_rect, scroll_node, area); ClipVertexInfo vi = write_clip_tile_vertex(local_rect, transform, area);
vPos = vi.local_pos; vPos = vi.local_pos;
vClipMode = clip.rect.mode.x; vClipMode = clip.rect.mode.x;

Просмотреть файл

@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include rect,clip_scroll,render_task,resource_cache,snap,transform #include rect,render_task,resource_cache,snap,transform
#define EXTEND_MODE_CLAMP 0 #define EXTEND_MODE_CLAMP 0
#define EXTEND_MODE_REPEAT 1 #define EXTEND_MODE_REPEAT 1
@ -32,11 +32,6 @@ varying vec3 vClipMaskUv;
#ifdef WR_VERTEX_SHADER #ifdef WR_VERTEX_SHADER
#define VECS_PER_LOCAL_CLIP_RECT 1
#define VECS_PER_PRIM_HEADER 2
#define VECS_PER_TEXT_RUN 3
#define VECS_PER_GRADIENT_STOP 2
#define COLOR_MODE_FROM_PASS 0 #define COLOR_MODE_FROM_PASS 0
#define COLOR_MODE_ALPHA 1 #define COLOR_MODE_ALPHA 1
#define COLOR_MODE_SUBPX_CONST_COLOR 2 #define COLOR_MODE_SUBPX_CONST_COLOR 2
@ -47,16 +42,46 @@ varying vec3 vClipMaskUv;
#define COLOR_MODE_BITMAP 7 #define COLOR_MODE_BITMAP 7
#define COLOR_MODE_COLOR_BITMAP 8 #define COLOR_MODE_COLOR_BITMAP 8
uniform HIGHP_SAMPLER_FLOAT sampler2D sLocalClipRects; uniform HIGHP_SAMPLER_FLOAT sampler2D sPrimitiveHeadersF;
uniform HIGHP_SAMPLER_FLOAT isampler2D sPrimitiveHeadersI;
// Instanced attributes // Instanced attributes
in ivec4 aData0; in ivec4 aData;
in ivec4 aData1;
RectWithSize fetch_clip_chain_rect(int index) { #define VECS_PER_PRIM_HEADER_F 2
ivec2 uv = get_fetch_uv(index, VECS_PER_LOCAL_CLIP_RECT); #define VECS_PER_PRIM_HEADER_I 2
vec4 rect = TEXEL_FETCH(sLocalClipRects, uv, 0, ivec2(0, 0));
return RectWithSize(rect.xy, rect.zw); struct PrimitiveHeader {
RectWithSize local_rect;
RectWithSize local_clip_rect;
float z;
int specific_prim_address;
int render_task_index;
int clip_task_index;
int transform_id;
ivec3 user_data;
};
PrimitiveHeader fetch_prim_header(int index) {
PrimitiveHeader ph;
ivec2 uv_f = get_fetch_uv(index, VECS_PER_PRIM_HEADER_F);
vec4 local_rect = TEXEL_FETCH(sPrimitiveHeadersF, uv_f, 0, ivec2(0, 0));
vec4 local_clip_rect = TEXEL_FETCH(sPrimitiveHeadersF, uv_f, 0, ivec2(1, 0));
ph.local_rect = RectWithSize(local_rect.xy, local_rect.zw);
ph.local_clip_rect = RectWithSize(local_clip_rect.xy, local_clip_rect.zw);
ivec2 uv_i = get_fetch_uv(index, VECS_PER_PRIM_HEADER_I);
ivec4 data0 = TEXEL_FETCH(sPrimitiveHeadersI, uv_i, 0, ivec2(0, 0));
ivec4 data1 = TEXEL_FETCH(sPrimitiveHeadersI, uv_i, 0, ivec2(1, 0));
ph.z = float(data0.x);
ph.render_task_index = data0.y;
ph.specific_prim_address = data0.z;
ph.clip_task_index = data0.w;
ph.transform_id = data1.x;
ph.user_data = data1.yzw;
return ph;
} }
struct VertexInfo { struct VertexInfo {
@ -69,7 +94,7 @@ struct VertexInfo {
VertexInfo write_vertex(RectWithSize instance_rect, VertexInfo write_vertex(RectWithSize instance_rect,
RectWithSize local_clip_rect, RectWithSize local_clip_rect,
float z, float z,
ClipScrollNode scroll_node, Transform transform,
PictureTask task, PictureTask task,
RectWithSize snap_rect) { RectWithSize snap_rect) {
@ -82,13 +107,13 @@ VertexInfo write_vertex(RectWithSize instance_rect,
/// Compute the snapping offset. /// Compute the snapping offset.
vec2 snap_offset = compute_snap_offset( vec2 snap_offset = compute_snap_offset(
clamped_local_pos, clamped_local_pos,
scroll_node.transform, transform.m,
snap_rect, snap_rect,
vec2(0.5) vec2(0.5)
); );
// Transform the current vertex to world space. // Transform the current vertex to world space.
vec4 world_pos = scroll_node.transform * vec4(clamped_local_pos, 0.0, 1.0); vec4 world_pos = transform.m * vec4(clamped_local_pos, 0.0, 1.0);
// Convert the world positions to device pixel space. // Convert the world positions to device pixel space.
vec2 device_pos = world_pos.xy / world_pos.w * uDevicePixelRatio; vec2 device_pos = world_pos.xy / world_pos.w * uDevicePixelRatio;
@ -135,7 +160,7 @@ VertexInfo write_transform_vertex(RectWithSize local_segment_rect,
RectWithSize local_clip_rect, RectWithSize local_clip_rect,
vec4 clip_edge_mask, vec4 clip_edge_mask,
float z, float z,
ClipScrollNode scroll_node, Transform transform,
PictureTask task, PictureTask task,
bool do_perspective_interpolation) { bool do_perspective_interpolation) {
// Calculate a clip rect from local_rect + local clip // Calculate a clip rect from local_rect + local clip
@ -168,7 +193,7 @@ VertexInfo write_transform_vertex(RectWithSize local_segment_rect,
vec2 local_pos = local_segment_rect.p0 + local_segment_rect.size * aPosition.xy; vec2 local_pos = local_segment_rect.p0 + local_segment_rect.size * aPosition.xy;
// Transform the current vertex to the world cpace. // Transform the current vertex to the world cpace.
vec4 world_pos = scroll_node.transform * vec4(local_pos, 0.0, 1.0); vec4 world_pos = transform.m * vec4(local_pos, 0.0, 1.0);
// Convert the world positions to device pixel space. // Convert the world positions to device pixel space.
vec2 device_pos = world_pos.xy / world_pos.w * uDevicePixelRatio; vec2 device_pos = world_pos.xy / world_pos.w * uDevicePixelRatio;

Просмотреть файл

@ -44,10 +44,10 @@ struct SplitCompositeInstance {
SplitCompositeInstance fetch_composite_instance() { SplitCompositeInstance fetch_composite_instance() {
SplitCompositeInstance ci; SplitCompositeInstance ci;
ci.render_task_index = aData0.x; ci.render_task_index = aData.x;
ci.src_task_index = aData0.y; ci.src_task_index = aData.y;
ci.polygons_address = aData0.z; ci.polygons_address = aData.z;
ci.z = float(aData0.w); ci.z = float(aData.w);
return ci; return ci;
} }

Просмотреть файл

@ -15,6 +15,8 @@ varying vec4 vUvClip;
#ifdef WR_VERTEX_SHADER #ifdef WR_VERTEX_SHADER
#define VECS_PER_TEXT_RUN 3
struct Glyph { struct Glyph {
vec2 offset; vec2 offset;
}; };
@ -57,94 +59,16 @@ TextRun fetch_text_run(int address) {
return TextRun(data[0], data[1], data[2].xy); return TextRun(data[0], data[1], data[2].xy);
} }
struct PrimitiveInstance {
int prim_address;
int specific_prim_address;
int render_task_index;
int clip_task_index;
int scroll_node_id;
int clip_chain_rect_index;
int z;
int user_data0;
int user_data1;
int user_data2;
};
PrimitiveInstance fetch_prim_instance() {
PrimitiveInstance pi;
pi.prim_address = aData0.x;
pi.specific_prim_address = pi.prim_address + VECS_PER_PRIM_HEADER;
pi.render_task_index = aData0.y % 0x10000;
pi.clip_task_index = aData0.y / 0x10000;
pi.clip_chain_rect_index = aData0.z;
pi.scroll_node_id = aData0.w;
pi.z = aData1.x;
pi.user_data0 = aData1.y;
pi.user_data1 = aData1.z;
pi.user_data2 = aData1.w;
return pi;
}
struct Primitive {
ClipScrollNode scroll_node;
ClipArea clip_area;
PictureTask task;
RectWithSize local_rect;
RectWithSize local_clip_rect;
int specific_prim_address;
int user_data0;
int user_data1;
int user_data2;
float z;
};
struct PrimitiveGeometry {
RectWithSize local_rect;
RectWithSize local_clip_rect;
};
PrimitiveGeometry fetch_primitive_geometry(int address) {
vec4 geom[2] = fetch_from_resource_cache_2(address);
return PrimitiveGeometry(RectWithSize(geom[0].xy, geom[0].zw),
RectWithSize(geom[1].xy, geom[1].zw));
}
Primitive load_primitive() {
PrimitiveInstance pi = fetch_prim_instance();
Primitive prim;
prim.scroll_node = fetch_clip_scroll_node(pi.scroll_node_id);
prim.clip_area = fetch_clip_area(pi.clip_task_index);
prim.task = fetch_picture_task(pi.render_task_index);
RectWithSize clip_chain_rect = fetch_clip_chain_rect(pi.clip_chain_rect_index);
PrimitiveGeometry geom = fetch_primitive_geometry(pi.prim_address);
prim.local_rect = geom.local_rect;
prim.local_clip_rect = intersect_rects(clip_chain_rect, geom.local_clip_rect);
prim.specific_prim_address = pi.specific_prim_address;
prim.user_data0 = pi.user_data0;
prim.user_data1 = pi.user_data1;
prim.user_data2 = pi.user_data2;
prim.z = float(pi.z);
return prim;
}
VertexInfo write_text_vertex(vec2 clamped_local_pos, VertexInfo write_text_vertex(vec2 clamped_local_pos,
RectWithSize local_clip_rect, RectWithSize local_clip_rect,
float z, float z,
ClipScrollNode scroll_node, Transform transform,
PictureTask task, PictureTask task,
vec2 text_offset, vec2 text_offset,
RectWithSize snap_rect, RectWithSize snap_rect,
vec2 snap_bias) { vec2 snap_bias) {
// Transform the current vertex to world space. // Transform the current vertex to world space.
vec4 world_pos = scroll_node.transform * vec4(clamped_local_pos, 0.0, 1.0); vec4 world_pos = transform.m * vec4(clamped_local_pos, 0.0, 1.0);
// Convert the world positions to device pixel space. // Convert the world positions to device pixel space.
float device_scale = uDevicePixelRatio / world_pos.w; float device_scale = uDevicePixelRatio / world_pos.w;
@ -159,13 +83,13 @@ VertexInfo write_text_vertex(vec2 clamped_local_pos,
bool remove_subpx_offset = true; bool remove_subpx_offset = true;
#else #else
// Compute the snapping offset only if the scroll node transform is axis-aligned. // Compute the snapping offset only if the scroll node transform is axis-aligned.
bool remove_subpx_offset = scroll_node.is_axis_aligned; bool remove_subpx_offset = transform.is_axis_aligned;
#endif #endif
if (remove_subpx_offset) { if (remove_subpx_offset) {
// Ensure the transformed text offset does not contain a subpixel translation // Ensure the transformed text offset does not contain a subpixel translation
// such that glyph snapping is stable for equivalent glyph subpixel positions. // such that glyph snapping is stable for equivalent glyph subpixel positions.
vec2 world_text_offset = mat2(scroll_node.transform) * text_offset; vec2 world_text_offset = mat2(transform.m) * text_offset;
vec2 device_text_pos = (scroll_node.transform[3].xy + world_text_offset) * device_scale; vec2 device_text_pos = (transform.m[3].xy + world_text_offset) * device_scale;
final_pos += floor(device_text_pos + 0.5) - device_text_pos; final_pos += floor(device_text_pos + 0.5) - device_text_pos;
#ifdef WR_FEATURE_GLYPH_TRANSFORM #ifdef WR_FEATURE_GLYPH_TRANSFORM
@ -177,7 +101,7 @@ VertexInfo write_text_vertex(vec2 clamped_local_pos,
#else #else
// The transformed text offset has already been snapped, so remove it from the transform // The transformed text offset has already been snapped, so remove it from the transform
// when snapping the glyph. // when snapping the glyph.
mat4 snap_transform = scroll_node.transform; mat4 snap_transform = transform.m;
snap_transform[3].xy = -world_text_offset; snap_transform[3].xy = -world_text_offset;
final_pos += compute_snap_offset( final_pos += compute_snap_offset(
clamped_local_pos, clamped_local_pos,
@ -201,31 +125,37 @@ VertexInfo write_text_vertex(vec2 clamped_local_pos,
} }
void main(void) { void main(void) {
Primitive prim = load_primitive(); int prim_header_address = aData.x;
TextRun text = fetch_text_run(prim.specific_prim_address); int glyph_index = aData.y;
int resource_address = aData.z;
int subpx_dir = aData.w >> 16;
int color_mode = aData.w & 0xffff;
int glyph_index = prim.user_data0; PrimitiveHeader ph = fetch_prim_header(prim_header_address);
int resource_address = prim.user_data1;
int subpx_dir = prim.user_data2 >> 16; Transform transform = fetch_transform(ph.transform_id);
int color_mode = prim.user_data2 & 0xffff; ClipArea clip_area = fetch_clip_area(ph.clip_task_index);
PictureTask task = fetch_picture_task(ph.render_task_index);
TextRun text = fetch_text_run(ph.specific_prim_address);
if (color_mode == COLOR_MODE_FROM_PASS) { if (color_mode == COLOR_MODE_FROM_PASS) {
color_mode = uMode; color_mode = uMode;
} }
Glyph glyph = fetch_glyph(prim.specific_prim_address, glyph_index); Glyph glyph = fetch_glyph(ph.specific_prim_address, glyph_index);
GlyphResource res = fetch_glyph_resource(resource_address); GlyphResource res = fetch_glyph_resource(resource_address);
#ifdef WR_FEATURE_GLYPH_TRANSFORM #ifdef WR_FEATURE_GLYPH_TRANSFORM
// Transform from local space to glyph space. // Transform from local space to glyph space.
mat2 transform = mat2(prim.scroll_node.transform) * uDevicePixelRatio; mat2 glyph_transform = mat2(transform.m) * uDevicePixelRatio;
// Compute the glyph rect in glyph space. // Compute the glyph rect in glyph space.
RectWithSize glyph_rect = RectWithSize(res.offset + transform * (text.offset + glyph.offset), RectWithSize glyph_rect = RectWithSize(res.offset + glyph_transform * (text.offset + glyph.offset),
res.uv_rect.zw - res.uv_rect.xy); res.uv_rect.zw - res.uv_rect.xy);
// Transform the glyph rect back to local space. // Transform the glyph rect back to local space.
mat2 inv = inverse(transform); mat2 inv = inverse(glyph_transform);
RectWithSize local_rect = transform_rect(glyph_rect, inv); RectWithSize local_rect = transform_rect(glyph_rect, inv);
// Select the corner of the glyph's local space rect that we are processing. // Select the corner of the glyph's local space rect that we are processing.
@ -234,9 +164,9 @@ void main(void) {
// If the glyph's local rect would fit inside the local clip rect, then select a corner from // If the glyph's local rect would fit inside the local clip rect, then select a corner from
// the device space glyph rect to reduce overdraw of clipped pixels in the fragment shader. // the device space glyph rect to reduce overdraw of clipped pixels in the fragment shader.
// Otherwise, fall back to clamping the glyph's local rect to the local clip rect. // Otherwise, fall back to clamping the glyph's local rect to the local clip rect.
local_pos = rect_inside_rect(local_rect, prim.local_clip_rect) ? local_pos = rect_inside_rect(local_rect, ph.local_clip_rect) ?
inv * (glyph_rect.p0 + glyph_rect.size * aPosition.xy) : inv * (glyph_rect.p0 + glyph_rect.size * aPosition.xy) :
clamp_rect(local_pos, prim.local_clip_rect); clamp_rect(local_pos, ph.local_clip_rect);
#else #else
// Scale from glyph space to local space. // Scale from glyph space to local space.
float scale = res.scale / uDevicePixelRatio; float scale = res.scale / uDevicePixelRatio;
@ -249,7 +179,7 @@ void main(void) {
vec2 local_pos = glyph_rect.p0 + glyph_rect.size * aPosition.xy; vec2 local_pos = glyph_rect.p0 + glyph_rect.size * aPosition.xy;
// Clamp to the local clip rect. // Clamp to the local clip rect.
local_pos = clamp_rect(local_pos, prim.local_clip_rect); local_pos = clamp_rect(local_pos, ph.local_clip_rect);
#endif #endif
vec2 snap_bias; vec2 snap_bias;
@ -278,22 +208,22 @@ void main(void) {
} }
VertexInfo vi = write_text_vertex(local_pos, VertexInfo vi = write_text_vertex(local_pos,
prim.local_clip_rect, ph.local_clip_rect,
prim.z, ph.z,
prim.scroll_node, transform,
prim.task, task,
text.offset, text.offset,
glyph_rect, glyph_rect,
snap_bias); snap_bias);
#ifdef WR_FEATURE_GLYPH_TRANSFORM #ifdef WR_FEATURE_GLYPH_TRANSFORM
vec2 f = (transform * vi.local_pos - glyph_rect.p0) / glyph_rect.size; vec2 f = (glyph_transform * vi.local_pos - glyph_rect.p0) / glyph_rect.size;
vUvClip = vec4(f, 1.0 - f); vUvClip = vec4(f, 1.0 - f);
#else #else
vec2 f = (vi.local_pos - glyph_rect.p0) / glyph_rect.size; vec2 f = (vi.local_pos - glyph_rect.p0) / glyph_rect.size;
#endif #endif
write_clip(vi.screen_pos, prim.clip_area); write_clip(vi.screen_pos, clip_area);
switch (color_mode) { switch (color_mode) {
case COLOR_MODE_ALPHA: case COLOR_MODE_ALPHA:

Просмотреть файл

@ -8,7 +8,7 @@ vec4 compute_snap_positions(mat4 transform, RectWithSize snap_rect) {
// Ensure that the snap rect is at *least* one device pixel in size. // Ensure that the snap rect is at *least* one device pixel in size.
// TODO(gw): It's not clear to me that this is "correct". Specifically, // TODO(gw): It's not clear to me that this is "correct". Specifically,
// how should it interact with sub-pixel snap rects when there // how should it interact with sub-pixel snap rects when there
// is a scroll_node transform with scale present? But it does fix // is a transform with scale present? But it does fix
// the test cases we have in Servo that are failing without it // the test cases we have in Servo that are failing without it
// and seem better than not having this at all. // and seem better than not having this at all.
snap_rect.size = max(snap_rect.size, vec2(1.0 / uDevicePixelRatio)); snap_rect.size = max(snap_rect.size, vec2(1.0 / uDevicePixelRatio));
@ -41,7 +41,7 @@ vec2 compute_snap_offset_impl(
} }
// Compute a snapping offset in world space (adjusted to pixel ratio), // Compute a snapping offset in world space (adjusted to pixel ratio),
// given local position on the scroll_node and a snap rectangle. // given local position on the transform and a snap rectangle.
vec2 compute_snap_offset(vec2 local_pos, vec2 compute_snap_offset(vec2 local_pos,
mat4 transform, mat4 transform,
RectWithSize snap_rect, RectWithSize snap_rect,

Просмотреть файл

@ -6,10 +6,89 @@ flat varying vec4 vTransformBounds;
#ifdef WR_VERTEX_SHADER #ifdef WR_VERTEX_SHADER
#define VECS_PER_TRANSFORM 8
uniform HIGHP_SAMPLER_FLOAT sampler2D sTransformPalette;
void init_transform_vs(vec4 local_bounds) { void init_transform_vs(vec4 local_bounds) {
vTransformBounds = local_bounds; vTransformBounds = local_bounds;
} }
struct Transform {
mat4 m;
mat4 inv_m;
bool is_axis_aligned;
};
Transform fetch_transform(int id) {
Transform transform;
transform.is_axis_aligned = (id >> 24) == 0;
int index = id & 0x00ffffff;
// Create a UV base coord for each 8 texels.
// This is required because trying to use an offset
// of more than 8 texels doesn't work on some versions
// of OSX.
ivec2 uv = get_fetch_uv(index, VECS_PER_TRANSFORM);
ivec2 uv0 = ivec2(uv.x + 0, uv.y);
transform.m[0] = TEXEL_FETCH(sTransformPalette, uv0, 0, ivec2(0, 0));
transform.m[1] = TEXEL_FETCH(sTransformPalette, uv0, 0, ivec2(1, 0));
transform.m[2] = TEXEL_FETCH(sTransformPalette, uv0, 0, ivec2(2, 0));
transform.m[3] = TEXEL_FETCH(sTransformPalette, uv0, 0, ivec2(3, 0));
transform.inv_m[0] = TEXEL_FETCH(sTransformPalette, uv0, 0, ivec2(4, 0));
transform.inv_m[1] = TEXEL_FETCH(sTransformPalette, uv0, 0, ivec2(5, 0));
transform.inv_m[2] = TEXEL_FETCH(sTransformPalette, uv0, 0, ivec2(6, 0));
transform.inv_m[3] = TEXEL_FETCH(sTransformPalette, uv0, 0, ivec2(7, 0));
return transform;
}
// Return the intersection of the plane (set up by "normal" and "point")
// with the ray (set up by "ray_origin" and "ray_dir"),
// writing the resulting scaler into "t".
bool ray_plane(vec3 normal, vec3 pt, vec3 ray_origin, vec3 ray_dir, out float t)
{
float denom = dot(normal, ray_dir);
if (abs(denom) > 1e-6) {
vec3 d = pt - ray_origin;
t = dot(d, normal) / denom;
return t >= 0.0;
}
return false;
}
// Apply the inverse transform "inv_transform"
// to the reference point "ref" in CSS space,
// producing a local point on a Transform plane,
// set by a base point "a" and a normal "n".
vec4 untransform(vec2 ref, vec3 n, vec3 a, mat4 inv_transform) {
vec3 p = vec3(ref, -10000.0);
vec3 d = vec3(0, 0, 1.0);
float t = 0.0;
// get an intersection of the Transform plane with Z axis vector,
// originated from the "ref" point
ray_plane(n, a, p, d, t);
float z = p.z + d.z * t; // Z of the visible point on the Transform
vec4 r = inv_transform * vec4(ref, z, 1.0);
return r;
}
// Given a CSS space position, transform it back into the Transform space.
vec4 get_node_pos(vec2 pos, Transform transform) {
// get a point on the scroll node plane
vec4 ah = transform.m * vec4(0.0, 0.0, 0.0, 1.0);
vec3 a = ah.xyz / ah.w;
// get the normal to the scroll node plane
vec3 n = transpose(mat3(transform.inv_m)) * vec3(0.0, 0.0, 1.0);
return untransform(pos, n, a, transform.inv_m);
}
#endif //WR_VERTEX_SHADER #endif //WR_VERTEX_SHADER
#ifdef WR_FRAGMENT_SHADER #ifdef WR_FRAGMENT_SHADER

Просмотреть файл

@ -11,10 +11,10 @@ use clip_scroll_tree::{CoordinateSystemId};
use euclid::{TypedTransform3D, vec3}; use euclid::{TypedTransform3D, vec3};
use glyph_rasterizer::GlyphFormat; use glyph_rasterizer::GlyphFormat;
use gpu_cache::{GpuCache, GpuCacheHandle, GpuCacheAddress}; use gpu_cache::{GpuCache, GpuCacheHandle, GpuCacheAddress};
use gpu_types::{BrushFlags, BrushInstance, ClipChainRectIndex}; use gpu_types::{BrushFlags, BrushInstance, PrimitiveHeaders};
use gpu_types::{ClipMaskInstance, ClipScrollNodeIndex, SplitCompositeInstance}; use gpu_types::{ClipMaskInstance, SplitCompositeInstance};
use gpu_types::{PrimitiveInstance, RasterizationSpace, GlyphInstance, ZBufferId}; use gpu_types::{PrimitiveInstance, RasterizationSpace, GlyphInstance};
use gpu_types::ZBufferIdGenerator; use gpu_types::{PrimitiveHeader, PrimitiveHeaderIndex, TransformPaletteId, TransformPalette};
use internal_types::{FastHashMap, SavedTargetIndex, SourceTexture}; use internal_types::{FastHashMap, SavedTargetIndex, SourceTexture};
use picture::{PictureCompositeMode, PicturePrimitive, PictureSurface}; use picture::{PictureCompositeMode, PicturePrimitive, PictureSurface};
use plane_split::{BspSplitter, Polygon, Splitter}; use plane_split::{BspSplitter, Polygon, Splitter};
@ -29,7 +29,7 @@ use resource_cache::{CacheItem, GlyphFetchResult, ImageRequest, ResourceCache};
use scene::FilterOpHelpers; use scene::FilterOpHelpers;
use std::{usize, f32, i32}; use std::{usize, f32, i32};
use tiling::{RenderTargetContext}; use tiling::{RenderTargetContext};
use util::{MatrixHelpers, TransformedRectKind}; use util::{TransformedRectKind};
// Special sentinel value recognized by the shader. It is considered to be // Special sentinel value recognized by the shader. It is considered to be
// a dummy task that doesn't mask out anything. // a dummy task that doesn't mask out anything.
@ -455,7 +455,7 @@ impl AlphaBatchBuilder {
gpu_cache: &mut GpuCache, gpu_cache: &mut GpuCache,
render_tasks: &RenderTaskTree, render_tasks: &RenderTaskTree,
deferred_resolves: &mut Vec<DeferredResolve>, deferred_resolves: &mut Vec<DeferredResolve>,
z_generator: &mut ZBufferIdGenerator, prim_headers: &mut PrimitiveHeaders,
) { ) {
let task_address = render_tasks.get_task_address(task_id); let task_address = render_tasks.get_task_address(task_id);
@ -476,10 +476,10 @@ impl AlphaBatchBuilder {
// Add each run in this picture to the batch. // Add each run in this picture to the batch.
for run in &pic.runs { for run in &pic.runs {
let scroll_node = &ctx.clip_scroll_tree.nodes[run.clip_and_scroll.scroll_node_id.0]; let scroll_node = &ctx.clip_scroll_tree.nodes[run.clip_and_scroll.scroll_node_id.0];
let scroll_id = scroll_node.node_data_index; let transform_id = ctx.transforms.get_id(scroll_node.transform_index);
self.add_run_to_batch( self.add_run_to_batch(
run, run,
scroll_id, transform_id,
ctx, ctx,
gpu_cache, gpu_cache,
render_tasks, render_tasks,
@ -488,7 +488,7 @@ impl AlphaBatchBuilder {
deferred_resolves, deferred_resolves,
&mut splitter, &mut splitter,
content_origin, content_origin,
z_generator, prim_headers,
); );
} }
@ -526,7 +526,7 @@ impl AlphaBatchBuilder {
task_address, task_address,
source_task_address, source_task_address,
gpu_address, gpu_address,
z_generator.next(), prim_headers.z_generator.next(),
); );
batch.push(PrimitiveInstance::from(instance)); batch.push(PrimitiveInstance::from(instance));
@ -539,7 +539,7 @@ impl AlphaBatchBuilder {
fn add_run_to_batch( fn add_run_to_batch(
&mut self, &mut self,
run: &PrimitiveRun, run: &PrimitiveRun,
scroll_id: ClipScrollNodeIndex, transform_id: TransformPaletteId,
ctx: &RenderTargetContext, ctx: &RenderTargetContext,
gpu_cache: &mut GpuCache, gpu_cache: &mut GpuCache,
render_tasks: &RenderTaskTree, render_tasks: &RenderTaskTree,
@ -548,7 +548,7 @@ impl AlphaBatchBuilder {
deferred_resolves: &mut Vec<DeferredResolve>, deferred_resolves: &mut Vec<DeferredResolve>,
splitter: &mut BspSplitter<f64, WorldPixel>, splitter: &mut BspSplitter<f64, WorldPixel>,
content_origin: DeviceIntPoint, content_origin: DeviceIntPoint,
z_generator: &mut ZBufferIdGenerator, prim_headers: &mut PrimitiveHeaders,
) { ) {
for i in 0 .. run.count { for i in 0 .. run.count {
let prim_index = PrimitiveIndex(run.base_prim_index.0 + i); let prim_index = PrimitiveIndex(run.base_prim_index.0 + i);
@ -556,8 +556,7 @@ impl AlphaBatchBuilder {
if metadata.screen_rect.is_some() { if metadata.screen_rect.is_some() {
self.add_prim_to_batch( self.add_prim_to_batch(
metadata.clip_chain_rect_index, transform_id,
scroll_id,
prim_index, prim_index,
ctx, ctx,
gpu_cache, gpu_cache,
@ -567,7 +566,7 @@ impl AlphaBatchBuilder {
deferred_resolves, deferred_resolves,
splitter, splitter,
content_origin, content_origin,
z_generator, prim_headers,
); );
} }
} }
@ -579,8 +578,7 @@ impl AlphaBatchBuilder {
// in that picture are being drawn into the same target. // in that picture are being drawn into the same target.
fn add_prim_to_batch( fn add_prim_to_batch(
&mut self, &mut self,
clip_chain_rect_index: ClipChainRectIndex, transform_id: TransformPaletteId,
scroll_id: ClipScrollNodeIndex,
prim_index: PrimitiveIndex, prim_index: PrimitiveIndex,
ctx: &RenderTargetContext, ctx: &RenderTargetContext,
gpu_cache: &mut GpuCache, gpu_cache: &mut GpuCache,
@ -590,18 +588,16 @@ impl AlphaBatchBuilder {
deferred_resolves: &mut Vec<DeferredResolve>, deferred_resolves: &mut Vec<DeferredResolve>,
splitter: &mut BspSplitter<f64, WorldPixel>, splitter: &mut BspSplitter<f64, WorldPixel>,
content_origin: DeviceIntPoint, content_origin: DeviceIntPoint,
z_generator: &mut ZBufferIdGenerator, prim_headers: &mut PrimitiveHeaders,
) { ) {
let z = z_generator.next();
let prim_metadata = ctx.prim_store.get_metadata(prim_index); let prim_metadata = ctx.prim_store.get_metadata(prim_index);
#[cfg(debug_assertions)] //TODO: why is this needed? #[cfg(debug_assertions)] //TODO: why is this needed?
debug_assert_eq!(prim_metadata.prepared_frame_id, render_tasks.frame_id()); debug_assert_eq!(prim_metadata.prepared_frame_id, render_tasks.frame_id());
let scroll_node = &ctx.node_data[scroll_id.0 as usize];
// TODO(gw): Calculating this for every primitive is a bit // TODO(gw): Calculating this for every primitive is a bit
// wasteful. We should probably cache this in // wasteful. We should probably cache this in
// the scroll node... // the scroll node...
let transform_kind = scroll_node.transform.transform_kind(); let transform_kind = transform_id.transform_kind();
let screen_rect = prim_metadata.screen_rect.expect("bug"); let screen_rect = prim_metadata.screen_rect.expect("bug");
let task_relative_bounding_rect = DeviceIntRect::new( let task_relative_bounding_rect = DeviceIntRect::new(
@ -648,6 +644,15 @@ impl AlphaBatchBuilder {
BlendMode::None BlendMode::None
}; };
let prim_header = PrimitiveHeader {
local_rect: prim_metadata.local_rect,
local_clip_rect: prim_metadata.combined_local_clip_rect,
task_address,
specific_prim_address: prim_cache_address,
clip_task_address,
transform_id,
};
match prim_metadata.prim_kind { match prim_metadata.prim_kind {
PrimitiveKind::Brush => { PrimitiveKind::Brush => {
let brush = &ctx.prim_store.cpu_brushes[prim_metadata.cpu_prim_index.0]; let brush = &ctx.prim_store.cpu_brushes[prim_metadata.cpu_prim_index.0];
@ -701,23 +706,19 @@ impl AlphaBatchBuilder {
textures, textures,
); );
let batch = self.batch_list.get_suitable_batch(key, &task_relative_bounding_rect); let batch = self.batch_list.get_suitable_batch(key, &task_relative_bounding_rect);
let prim_header_index = prim_headers.push(&prim_header, [
uv_rect_address.as_int(),
(ShaderColorMode::ColorBitmap as i32) << 16 |
RasterizationSpace::Screen as i32,
0,
]);
let instance = BrushInstance { let instance = BrushInstance {
picture_address: task_address, prim_header_index,
prim_address: prim_cache_address,
clip_chain_rect_index,
scroll_id,
clip_task_address,
z,
segment_index: 0, segment_index: 0,
edge_flags: EdgeAaSegmentMask::empty(), edge_flags: EdgeAaSegmentMask::empty(),
brush_flags: BrushFlags::empty(), brush_flags: BrushFlags::empty(),
user_data: [ clip_task_address,
uv_rect_address.as_int(),
(ShaderColorMode::ColorBitmap as i32) << 16 |
RasterizationSpace::Screen as i32,
0,
],
}; };
batch.push(PrimitiveInstance::from(instance)); batch.push(PrimitiveInstance::from(instance));
false false
@ -727,7 +728,7 @@ impl AlphaBatchBuilder {
} }
} }
} }
FilterOp::DropShadow(..) => { FilterOp::DropShadow(offset, ..) => {
// Draw an instance of the shadow first, following by the content. // Draw an instance of the shadow first, following by the content.
// Both the shadow and the content get drawn as a brush image. // Both the shadow and the content get drawn as a brush image.
@ -768,33 +769,44 @@ impl AlphaBatchBuilder {
// Get the GPU cache address of the extra data handle. // Get the GPU cache address of the extra data handle.
let shadow_prim_address = gpu_cache.get_address(&picture.extra_gpu_data_handle); let shadow_prim_address = gpu_cache.get_address(&picture.extra_gpu_data_handle);
let content_prim_header_index = prim_headers.push(&prim_header, [
content_uv_rect_address,
(ShaderColorMode::ColorBitmap as i32) << 16 |
RasterizationSpace::Screen as i32,
0,
]);
let shadow_rect = prim_metadata.local_rect.translate(&offset);
let shadow_clip_rect = prim_metadata.local_clip_rect.translate(&offset);
let shadow_prim_header = PrimitiveHeader {
local_rect: shadow_rect,
local_clip_rect: shadow_clip_rect,
specific_prim_address: shadow_prim_address,
..prim_header
};
let shadow_prim_header_index = prim_headers.push(&shadow_prim_header, [
shadow_uv_rect_address,
(ShaderColorMode::Alpha as i32) << 16 |
RasterizationSpace::Screen as i32,
0,
]);
let shadow_instance = BrushInstance { let shadow_instance = BrushInstance {
picture_address: task_address, prim_header_index: shadow_prim_header_index,
prim_address: shadow_prim_address,
clip_chain_rect_index,
scroll_id,
clip_task_address, clip_task_address,
z,
segment_index: 0, segment_index: 0,
edge_flags: EdgeAaSegmentMask::empty(), edge_flags: EdgeAaSegmentMask::empty(),
brush_flags: BrushFlags::empty(), brush_flags: BrushFlags::empty(),
user_data: [
shadow_uv_rect_address,
(ShaderColorMode::Alpha as i32) << 16 |
RasterizationSpace::Screen as i32,
0,
],
}; };
let content_instance = BrushInstance { let content_instance = BrushInstance {
prim_address: prim_cache_address, prim_header_index: content_prim_header_index,
user_data: [ clip_task_address,
content_uv_rect_address, segment_index: 0,
(ShaderColorMode::ColorBitmap as i32) << 16 | edge_flags: EdgeAaSegmentMask::empty(),
RasterizationSpace::Screen as i32, brush_flags: BrushFlags::empty(),
0,
],
..shadow_instance
}; };
self.batch_list self.batch_list
@ -856,22 +868,18 @@ impl AlphaBatchBuilder {
let cache_task_id = surface.resolve_render_task_id(); let cache_task_id = surface.resolve_render_task_id();
let cache_task_address = render_tasks.get_task_address(cache_task_id); let cache_task_address = render_tasks.get_task_address(cache_task_id);
let prim_header_index = prim_headers.push(&prim_header, [
cache_task_address.0 as i32,
filter_mode,
user_data,
]);
let instance = BrushInstance { let instance = BrushInstance {
picture_address: task_address, prim_header_index,
prim_address: prim_cache_address,
clip_chain_rect_index,
scroll_id,
clip_task_address, clip_task_address,
z,
segment_index: 0, segment_index: 0,
edge_flags: EdgeAaSegmentMask::empty(), edge_flags: EdgeAaSegmentMask::empty(),
brush_flags: BrushFlags::empty(), brush_flags: BrushFlags::empty(),
user_data: [
cache_task_address.0 as i32,
filter_mode,
user_data,
],
}; };
let batch = self.batch_list.get_suitable_batch(key, &task_relative_bounding_rect); let batch = self.batch_list.get_suitable_batch(key, &task_relative_bounding_rect);
@ -907,22 +915,18 @@ impl AlphaBatchBuilder {
let batch = self.batch_list.get_suitable_batch(key, &task_relative_bounding_rect); let batch = self.batch_list.get_suitable_batch(key, &task_relative_bounding_rect);
let backdrop_task_address = render_tasks.get_task_address(backdrop_id); let backdrop_task_address = render_tasks.get_task_address(backdrop_id);
let source_task_address = render_tasks.get_task_address(cache_task_id); let source_task_address = render_tasks.get_task_address(cache_task_id);
let prim_header_index = prim_headers.push(&prim_header, [
mode as u32 as i32,
backdrop_task_address.0 as i32,
source_task_address.0 as i32,
]);
let instance = BrushInstance { let instance = BrushInstance {
picture_address: task_address, prim_header_index,
prim_address: prim_cache_address,
clip_chain_rect_index,
scroll_id,
clip_task_address, clip_task_address,
z,
segment_index: 0, segment_index: 0,
edge_flags: EdgeAaSegmentMask::empty(), edge_flags: EdgeAaSegmentMask::empty(),
brush_flags: BrushFlags::empty(), brush_flags: BrushFlags::empty(),
user_data: [
mode as u32 as i32,
backdrop_task_address.0 as i32,
source_task_address.0 as i32,
],
}; };
batch.push(PrimitiveInstance::from(instance)); batch.push(PrimitiveInstance::from(instance));
@ -950,23 +954,19 @@ impl AlphaBatchBuilder {
let uv_rect_address = render_tasks[cache_task_id] let uv_rect_address = render_tasks[cache_task_id]
.get_texture_address(gpu_cache) .get_texture_address(gpu_cache)
.as_int(); .as_int();
let prim_header_index = prim_headers.push(&prim_header, [
uv_rect_address,
(ShaderColorMode::ColorBitmap as i32) << 16 |
RasterizationSpace::Screen as i32,
0,
]);
let instance = BrushInstance { let instance = BrushInstance {
picture_address: task_address, prim_header_index,
prim_address: prim_cache_address,
clip_chain_rect_index,
scroll_id,
clip_task_address, clip_task_address,
z,
segment_index: 0, segment_index: 0,
edge_flags: EdgeAaSegmentMask::empty(), edge_flags: EdgeAaSegmentMask::empty(),
brush_flags: BrushFlags::empty(), brush_flags: BrushFlags::empty(),
user_data: [
uv_rect_address,
(ShaderColorMode::ColorBitmap as i32) << 16 |
RasterizationSpace::Screen as i32,
0,
],
}; };
batch.push(PrimitiveInstance::from(instance)); batch.push(PrimitiveInstance::from(instance));
false false
@ -986,7 +986,7 @@ impl AlphaBatchBuilder {
gpu_cache, gpu_cache,
render_tasks, render_tasks,
deferred_resolves, deferred_resolves,
z_generator, prim_headers,
); );
} }
} }
@ -999,18 +999,21 @@ impl AlphaBatchBuilder {
request.with_tile(tile.tile_offset), request.with_tile(tile.tile_offset),
) { ) {
let prim_cache_address = gpu_cache.get_address(&tile.handle); let prim_cache_address = gpu_cache.get_address(&tile.handle);
let prim_header = PrimitiveHeader {
specific_prim_address: prim_cache_address,
local_rect: tile.local_rect,
local_clip_rect: tile.local_clip_rect,
..prim_header
};
let prim_header_index = prim_headers.push(&prim_header, user_data);
self.add_image_tile_to_batch( self.add_image_tile_to_batch(
batch_kind, batch_kind,
specified_blend_mode, specified_blend_mode,
textures, textures,
clip_chain_rect_index, prim_header_index,
clip_task_address, clip_task_address,
&task_relative_bounding_rect, &task_relative_bounding_rect,
prim_cache_address,
scroll_id,
task_address,
z,
user_data,
tile.edge_flags tile.edge_flags
); );
} }
@ -1023,13 +1026,11 @@ impl AlphaBatchBuilder {
BrushBatchKind::LinearGradient, BrushBatchKind::LinearGradient,
specified_blend_mode, specified_blend_mode,
&task_relative_bounding_rect, &task_relative_bounding_rect,
clip_chain_rect_index,
scroll_id,
task_address,
clip_task_address, clip_task_address,
z,
gpu_cache, gpu_cache,
&mut self.batch_list, &mut self.batch_list,
&prim_header,
prim_headers,
); );
} }
BrushKind::RadialGradient { ref stops_handle, ref visible_tiles, .. } if !visible_tiles.is_empty() => { BrushKind::RadialGradient { ref stops_handle, ref visible_tiles, .. } if !visible_tiles.is_empty() => {
@ -1039,13 +1040,11 @@ impl AlphaBatchBuilder {
BrushBatchKind::RadialGradient, BrushBatchKind::RadialGradient,
specified_blend_mode, specified_blend_mode,
&task_relative_bounding_rect, &task_relative_bounding_rect,
clip_chain_rect_index,
scroll_id,
task_address,
clip_task_address, clip_task_address,
z,
gpu_cache, gpu_cache,
&mut self.batch_list, &mut self.batch_list,
&prim_header,
prim_headers,
); );
} }
_ => { _ => {
@ -1054,6 +1053,8 @@ impl AlphaBatchBuilder {
gpu_cache, gpu_cache,
deferred_resolves, deferred_resolves,
) { ) {
let prim_header_index = prim_headers.push(&prim_header, user_data);
self.add_brush_to_batch( self.add_brush_to_batch(
brush, brush,
prim_metadata, prim_metadata,
@ -1061,16 +1062,11 @@ impl AlphaBatchBuilder {
specified_blend_mode, specified_blend_mode,
non_segmented_blend_mode, non_segmented_blend_mode,
textures, textures,
clip_chain_rect_index, prim_header_index,
clip_task_address, clip_task_address,
&task_relative_bounding_rect, &task_relative_bounding_rect,
prim_cache_address,
scroll_id,
task_address,
transform_kind, transform_kind,
z,
render_tasks, render_tasks,
user_data,
); );
} }
} }
@ -1080,17 +1076,13 @@ impl AlphaBatchBuilder {
let text_cpu = let text_cpu =
&ctx.prim_store.cpu_text_runs[prim_metadata.cpu_prim_index.0]; &ctx.prim_store.cpu_text_runs[prim_metadata.cpu_prim_index.0];
let font = text_cpu.get_font( let subpx_dir = text_cpu.used_font.get_subpx_dir();
ctx.device_pixel_scale,
scroll_node.transform,
);
let subpx_dir = font.get_subpx_dir();
let glyph_fetch_buffer = &mut self.glyph_fetch_buffer; let glyph_fetch_buffer = &mut self.glyph_fetch_buffer;
let batch_list = &mut self.batch_list; let batch_list = &mut self.batch_list;
ctx.resource_cache.fetch_glyphs( ctx.resource_cache.fetch_glyphs(
font, text_cpu.used_font.clone(),
&text_cpu.glyph_keys, &text_cpu.glyph_keys,
glyph_fetch_buffer, glyph_fetch_buffer,
gpu_cache, gpu_cache,
@ -1117,7 +1109,7 @@ impl AlphaBatchBuilder {
let (blend_mode, color_mode) = match glyph_format { let (blend_mode, color_mode) = match glyph_format {
GlyphFormat::Subpixel | GlyphFormat::Subpixel |
GlyphFormat::TransformedSubpixel => { GlyphFormat::TransformedSubpixel => {
if text_cpu.font.bg_color.a != 0 { if text_cpu.used_font.bg_color.a != 0 {
( (
BlendMode::SubpixelWithBgColor, BlendMode::SubpixelWithBgColor,
ShaderColorMode::FromRenderPassMode, ShaderColorMode::FromRenderPassMode,
@ -1129,7 +1121,7 @@ impl AlphaBatchBuilder {
) )
} else { } else {
( (
BlendMode::SubpixelConstantTextColor(text_cpu.font.color.into()), BlendMode::SubpixelConstantTextColor(text_cpu.used_font.color.into()),
ShaderColorMode::SubpixelConstantTextColor, ShaderColorMode::SubpixelConstantTextColor,
) )
} }
@ -1155,15 +1147,11 @@ impl AlphaBatchBuilder {
} }
}; };
let prim_header_index = prim_headers.push(&prim_header, [0; 3]);
let key = BatchKey::new(kind, blend_mode, textures); let key = BatchKey::new(kind, blend_mode, textures);
let batch = batch_list.get_suitable_batch(key, &task_relative_bounding_rect); let batch = batch_list.get_suitable_batch(key, &task_relative_bounding_rect);
let base_instance = GlyphInstance::new( let base_instance = GlyphInstance::new(
prim_cache_address, prim_header_index,
task_address,
clip_task_address,
clip_chain_rect_index,
scroll_id,
z,
); );
for glyph in glyphs { for glyph in glyphs {
@ -1185,27 +1173,17 @@ impl AlphaBatchBuilder {
batch_kind: BrushBatchKind, batch_kind: BrushBatchKind,
blend_mode: BlendMode, blend_mode: BlendMode,
textures: BatchTextures, textures: BatchTextures,
clip_chain_rect_index: ClipChainRectIndex, prim_header_index: PrimitiveHeaderIndex,
clip_task_address: RenderTaskAddress, clip_task_address: RenderTaskAddress,
task_relative_bounding_rect: &DeviceIntRect, task_relative_bounding_rect: &DeviceIntRect,
prim_cache_address: GpuCacheAddress,
scroll_id: ClipScrollNodeIndex,
task_address: RenderTaskAddress,
z: ZBufferId,
user_data: [i32; 3],
edge_flags: EdgeAaSegmentMask, edge_flags: EdgeAaSegmentMask,
) { ) {
let base_instance = BrushInstance { let base_instance = BrushInstance {
picture_address: task_address, prim_header_index,
prim_address: prim_cache_address,
clip_chain_rect_index,
scroll_id,
clip_task_address, clip_task_address,
z,
segment_index: 0, segment_index: 0,
edge_flags, edge_flags,
brush_flags: BrushFlags::PERSPECTIVE_INTERPOLATION, brush_flags: BrushFlags::PERSPECTIVE_INTERPOLATION,
user_data,
}; };
self.batch_list.add_bounding_rect(task_relative_bounding_rect); self.batch_list.add_bounding_rect(task_relative_bounding_rect);
@ -1227,28 +1205,18 @@ impl AlphaBatchBuilder {
alpha_blend_mode: BlendMode, alpha_blend_mode: BlendMode,
non_segmented_blend_mode: BlendMode, non_segmented_blend_mode: BlendMode,
textures: BatchTextures, textures: BatchTextures,
clip_chain_rect_index: ClipChainRectIndex, prim_header_index: PrimitiveHeaderIndex,
clip_task_address: RenderTaskAddress, clip_task_address: RenderTaskAddress,
task_relative_bounding_rect: &DeviceIntRect, task_relative_bounding_rect: &DeviceIntRect,
prim_cache_address: GpuCacheAddress,
scroll_id: ClipScrollNodeIndex,
task_address: RenderTaskAddress,
transform_kind: TransformedRectKind, transform_kind: TransformedRectKind,
z: ZBufferId,
render_tasks: &RenderTaskTree, render_tasks: &RenderTaskTree,
user_data: [i32; 3],
) { ) {
let base_instance = BrushInstance { let base_instance = BrushInstance {
picture_address: task_address, prim_header_index,
prim_address: prim_cache_address,
clip_chain_rect_index,
scroll_id,
clip_task_address, clip_task_address,
z,
segment_index: 0, segment_index: 0,
edge_flags: EdgeAaSegmentMask::all(), edge_flags: EdgeAaSegmentMask::all(),
brush_flags: BrushFlags::PERSPECTIVE_INTERPOLATION, brush_flags: BrushFlags::PERSPECTIVE_INTERPOLATION,
user_data,
}; };
self.batch_list.add_bounding_rect(task_relative_bounding_rect); self.batch_list.add_bounding_rect(task_relative_bounding_rect);
@ -1326,13 +1294,11 @@ fn add_gradient_tiles(
kind: BrushBatchKind, kind: BrushBatchKind,
blend_mode: BlendMode, blend_mode: BlendMode,
task_relative_bounding_rect: &DeviceIntRect, task_relative_bounding_rect: &DeviceIntRect,
clip_chain_rect_index: ClipChainRectIndex,
scroll_id: ClipScrollNodeIndex,
task_address: RenderTaskAddress,
clip_task_address: RenderTaskAddress, clip_task_address: RenderTaskAddress,
z: ZBufferId,
gpu_cache: &GpuCache, gpu_cache: &GpuCache,
batch_list: &mut BatchList, batch_list: &mut BatchList,
base_prim_header: &PrimitiveHeader,
prim_headers: &mut PrimitiveHeaders,
) { ) {
batch_list.add_bounding_rect(task_relative_bounding_rect); batch_list.add_bounding_rect(task_relative_bounding_rect);
let batch = batch_list.get_suitable_batch( let batch = batch_list.get_suitable_batch(
@ -1346,24 +1312,22 @@ fn add_gradient_tiles(
let user_data = [stops_handle.as_int(gpu_cache), 0, 0]; let user_data = [stops_handle.as_int(gpu_cache), 0, 0];
let base_instance = BrushInstance {
picture_address: task_address,
prim_address: GpuCacheAddress::invalid(),
clip_chain_rect_index,
scroll_id,
clip_task_address,
z,
segment_index: 0,
edge_flags: EdgeAaSegmentMask::all(),
brush_flags: BrushFlags::PERSPECTIVE_INTERPOLATION,
user_data,
};
for tile in visible_tiles { for tile in visible_tiles {
let prim_header = PrimitiveHeader {
specific_prim_address: gpu_cache.get_address(&tile.handle),
local_rect: tile.local_rect,
local_clip_rect: tile.local_clip_rect,
..*base_prim_header
};
let prim_header_index = prim_headers.push(&prim_header, user_data);
batch.push(PrimitiveInstance::from( batch.push(PrimitiveInstance::from(
BrushInstance { BrushInstance {
prim_address: gpu_cache.get_address(&tile.handle), prim_header_index,
..base_instance clip_task_address,
segment_index: 0,
edge_flags: EdgeAaSegmentMask::all(),
brush_flags: BrushFlags::PERSPECTIVE_INTERPOLATION,
} }
)); ));
} }
@ -1783,7 +1747,7 @@ impl ClipBatcher {
) { ) {
let instance = ClipMaskInstance { let instance = ClipMaskInstance {
render_task_address: task_address, render_task_address: task_address,
scroll_node_data_index: ClipScrollNodeIndex(0), transform_id: TransformPaletteId::identity(),
segment: 0, segment: 0,
clip_data_address, clip_data_address,
resource_address: GpuCacheAddress::invalid(), resource_address: GpuCacheAddress::invalid(),
@ -1800,12 +1764,13 @@ impl ClipBatcher {
resource_cache: &ResourceCache, resource_cache: &ResourceCache,
gpu_cache: &GpuCache, gpu_cache: &GpuCache,
clip_store: &ClipStore, clip_store: &ClipStore,
transforms: &TransformPalette,
) { ) {
let mut coordinate_system_id = coordinate_system_id; let mut coordinate_system_id = coordinate_system_id;
for work_item in clips.iter() { for work_item in clips.iter() {
let instance = ClipMaskInstance { let instance = ClipMaskInstance {
render_task_address: task_address, render_task_address: task_address,
scroll_node_data_index: work_item.scroll_node_data_index, transform_id: transforms.get_id(work_item.transform_index),
segment: 0, segment: 0,
clip_data_address: GpuCacheAddress::invalid(), clip_data_address: GpuCacheAddress::invalid(),
resource_address: GpuCacheAddress::invalid(), resource_address: GpuCacheAddress::invalid(),

Просмотреть файл

@ -7,11 +7,11 @@ use api::{ImageRendering, LayoutRect, LayoutSize, LayoutPoint, LayoutVector2D, L
use api::{BoxShadowClipMode, LayoutToWorldScale, LineOrientation, LineStyle}; use api::{BoxShadowClipMode, LayoutToWorldScale, LineOrientation, LineStyle};
use border::{ensure_no_corner_overlap}; use border::{ensure_no_corner_overlap};
use box_shadow::{BLUR_SAMPLE_SCALE, BoxShadowClipSource, BoxShadowCacheKey}; use box_shadow::{BLUR_SAMPLE_SCALE, BoxShadowClipSource, BoxShadowCacheKey};
use clip_scroll_tree::{ClipChainIndex, CoordinateSystemId}; use clip_scroll_tree::{ClipChainIndex, CoordinateSystemId, TransformIndex};
use ellipse::Ellipse; use ellipse::Ellipse;
use freelist::{FreeList, FreeListHandle, WeakFreeListHandle}; use freelist::{FreeList, FreeListHandle, WeakFreeListHandle};
use gpu_cache::{GpuCache, GpuCacheHandle, ToGpuBlocks}; use gpu_cache::{GpuCache, GpuCacheHandle, ToGpuBlocks};
use gpu_types::{BoxShadowStretchMode, ClipScrollNodeIndex}; use gpu_types::{BoxShadowStretchMode};
use prim_store::{ClipData, ImageMaskData}; use prim_store::{ClipData, ImageMaskData};
use render_task::to_cache_size; use render_task::to_cache_size;
use resource_cache::{ImageRequest, ResourceCache}; use resource_cache::{ImageRequest, ResourceCache};
@ -625,7 +625,7 @@ impl Iterator for ClipChainNodeIter {
#[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))] #[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct ClipWorkItem { pub struct ClipWorkItem {
pub scroll_node_data_index: ClipScrollNodeIndex, pub transform_index: TransformIndex,
pub clip_sources: ClipSourcesWeakHandle, pub clip_sources: ClipSourcesWeakHandle,
pub coordinate_system_id: CoordinateSystemId, pub coordinate_system_id: CoordinateSystemId,
} }

Просмотреть файл

@ -7,10 +7,10 @@ use api::{LayoutVector2D, LayoutTransform, PipelineId, PropertyBinding};
use api::{ScrollClamping, ScrollLocation, ScrollSensitivity, StickyOffsetBounds}; use api::{ScrollClamping, ScrollLocation, ScrollSensitivity, StickyOffsetBounds};
use clip::{ClipChain, ClipChainNode, ClipSourcesHandle, ClipStore, ClipWorkItem}; use clip::{ClipChain, ClipChainNode, ClipSourcesHandle, ClipStore, ClipWorkItem};
use clip_scroll_tree::{ClipChainIndex, ClipScrollNodeIndex, CoordinateSystemId}; use clip_scroll_tree::{ClipChainIndex, ClipScrollNodeIndex, CoordinateSystemId};
use clip_scroll_tree::TransformUpdateState; use clip_scroll_tree::{TransformUpdateState, TransformIndex};
use euclid::SideOffsets2D; use euclid::SideOffsets2D;
use gpu_cache::GpuCache; use gpu_cache::GpuCache;
use gpu_types::{ClipScrollNodeIndex as GPUClipScrollNodeIndex, ClipScrollNodeData}; use gpu_types::{TransformData, TransformPalette};
use resource_cache::ResourceCache; use resource_cache::ResourceCache;
use scene::SceneProperties; use scene::SceneProperties;
use util::{LayoutToWorldFastTransform, LayoutFastTransform}; use util::{LayoutToWorldFastTransform, LayoutFastTransform};
@ -46,9 +46,26 @@ impl StickyFrameInfo {
} }
#[derive(Debug)] #[derive(Debug)]
pub enum NodeType { pub enum SpatialNodeKind {
/// A special kind of node that adjusts its position based on the position
/// of its parent node and a given set of sticky positioning offset bounds.
/// Sticky positioned is described in the CSS Positioned Layout Module Level 3 here:
/// https://www.w3.org/TR/css-position-3/#sticky-pos
StickyFrame(StickyFrameInfo),
/// Transforms it's content, but doesn't clip it. Can also be adjusted
/// by scroll events or setting scroll offsets.
ScrollFrame(ScrollFrameInfo),
/// A reference frame establishes a new coordinate space in the tree. /// A reference frame establishes a new coordinate space in the tree.
ReferenceFrame(ReferenceFrameInfo), ReferenceFrame(ReferenceFrameInfo),
}
#[derive(Debug)]
pub enum NodeType {
Spatial {
kind: SpatialNodeKind,
},
/// Other nodes just do clipping, but no transformation. /// Other nodes just do clipping, but no transformation.
Clip { Clip {
@ -61,16 +78,6 @@ pub enum NodeType {
clip_chain_node: Option<ClipChainNode>, clip_chain_node: Option<ClipChainNode>,
}, },
/// Transforms it's content, but doesn't clip it. Can also be adjusted
/// by scroll events or setting scroll offsets.
ScrollFrame(ScrollFrameInfo),
/// A special kind of node that adjusts its position based on the position
/// of its parent node and a given set of sticky positioning offset bounds.
/// Sticky positioned is described in the CSS Positioned Layout Module Level 3 here:
/// https://www.w3.org/TR/css-position-3/#sticky-pos
StickyFrame(StickyFrameInfo),
/// An empty node, used to pad the ClipScrollTree's array of nodes so that /// An empty node, used to pad the ClipScrollTree's array of nodes so that
/// we can immediately use each assigned ClipScrollNodeIndex. After display /// we can immediately use each assigned ClipScrollNodeIndex. After display
/// list flattening this node type should never be used. /// list flattening this node type should never be used.
@ -80,7 +87,7 @@ pub enum NodeType {
impl NodeType { impl NodeType {
fn is_reference_frame(&self) -> bool { fn is_reference_frame(&self) -> bool {
match *self { match *self {
NodeType::ReferenceFrame(_) => true, NodeType::Spatial { kind: SpatialNodeKind::ReferenceFrame(_), .. } => true,
_ => false, _ => false,
} }
} }
@ -126,16 +133,18 @@ pub struct ClipScrollNode {
/// reference frame transforms. /// reference frame transforms.
pub coordinate_system_relative_transform: LayoutFastTransform, pub coordinate_system_relative_transform: LayoutFastTransform,
/// A linear ID / index of this clip-scroll node. Used as a reference to /// The index of the spatial node that provides positioning information for this node.
/// pass to shaders, to allow them to fetch a given clip-scroll node. /// For reference frames, scroll and sticky frames it is a unique identfier.
pub node_data_index: GPUClipScrollNodeIndex, /// For clip nodes, this is the nearest ancestor spatial node.
pub transform_index: TransformIndex,
} }
impl ClipScrollNode { impl ClipScrollNode {
pub fn new( pub fn new(
pipeline_id: PipelineId, pipeline_id: PipelineId,
parent_index: Option<ClipScrollNodeIndex>, parent_index: Option<ClipScrollNodeIndex>,
node_type: NodeType node_type: NodeType,
transform_index: TransformIndex,
) -> Self { ) -> Self {
ClipScrollNode { ClipScrollNode {
world_viewport_transform: LayoutToWorldFastTransform::identity(), world_viewport_transform: LayoutToWorldFastTransform::identity(),
@ -148,12 +157,17 @@ impl ClipScrollNode {
invertible: true, invertible: true,
coordinate_system_id: CoordinateSystemId(0), coordinate_system_id: CoordinateSystemId(0),
coordinate_system_relative_transform: LayoutFastTransform::identity(), coordinate_system_relative_transform: LayoutFastTransform::identity(),
node_data_index: GPUClipScrollNodeIndex(0), transform_index,
} }
} }
pub fn empty() -> ClipScrollNode { pub fn empty() -> ClipScrollNode {
Self::new(PipelineId::dummy(), None, NodeType::Empty) Self::new(
PipelineId::dummy(),
None,
NodeType::Empty,
TransformIndex(0),
)
} }
pub fn new_scroll_frame( pub fn new_scroll_frame(
@ -163,18 +177,26 @@ impl ClipScrollNode {
frame_rect: &LayoutRect, frame_rect: &LayoutRect,
content_size: &LayoutSize, content_size: &LayoutSize,
scroll_sensitivity: ScrollSensitivity, scroll_sensitivity: ScrollSensitivity,
transform_index: TransformIndex,
) -> Self { ) -> Self {
let node_type = NodeType::ScrollFrame(ScrollFrameInfo::new( let node_type = NodeType::Spatial {
*frame_rect, kind: SpatialNodeKind::ScrollFrame(ScrollFrameInfo::new(
scroll_sensitivity, *frame_rect,
LayoutSize::new( scroll_sensitivity,
(content_size.width - frame_rect.size.width).max(0.0), LayoutSize::new(
(content_size.height - frame_rect.size.height).max(0.0) (content_size.width - frame_rect.size.width).max(0.0),
), (content_size.height - frame_rect.size.height).max(0.0)
external_id, ),
)); external_id,
)),
};
Self::new(pipeline_id, Some(parent_index), node_type) Self::new(
pipeline_id,
Some(parent_index),
node_type,
transform_index,
)
} }
pub fn new_reference_frame( pub fn new_reference_frame(
@ -183,6 +205,7 @@ impl ClipScrollNode {
source_perspective: Option<LayoutTransform>, source_perspective: Option<LayoutTransform>,
origin_in_parent_reference_frame: LayoutVector2D, origin_in_parent_reference_frame: LayoutVector2D,
pipeline_id: PipelineId, pipeline_id: PipelineId,
transform_index: TransformIndex,
) -> Self { ) -> Self {
let identity = LayoutTransform::identity(); let identity = LayoutTransform::identity();
let source_perspective = source_perspective.map_or_else( let source_perspective = source_perspective.map_or_else(
@ -194,16 +217,31 @@ impl ClipScrollNode {
origin_in_parent_reference_frame, origin_in_parent_reference_frame,
invertible: true, invertible: true,
}; };
Self::new(pipeline_id, parent_index, NodeType::ReferenceFrame(info)) Self::new(
pipeline_id,
parent_index,
NodeType::Spatial {
kind: SpatialNodeKind::ReferenceFrame(info),
},
transform_index,
)
} }
pub fn new_sticky_frame( pub fn new_sticky_frame(
parent_index: ClipScrollNodeIndex, parent_index: ClipScrollNodeIndex,
sticky_frame_info: StickyFrameInfo, sticky_frame_info: StickyFrameInfo,
pipeline_id: PipelineId, pipeline_id: PipelineId,
transform_index: TransformIndex,
) -> Self { ) -> Self {
let node_type = NodeType::StickyFrame(sticky_frame_info); let node_type = NodeType::Spatial {
Self::new(pipeline_id, Some(parent_index), node_type) kind: SpatialNodeKind::StickyFrame(sticky_frame_info),
};
Self::new(
pipeline_id,
Some(parent_index),
node_type,
transform_index,
)
} }
@ -213,7 +251,7 @@ impl ClipScrollNode {
pub fn apply_old_scrolling_state(&mut self, old_scroll_info: &ScrollFrameInfo) { pub fn apply_old_scrolling_state(&mut self, old_scroll_info: &ScrollFrameInfo) {
match self.node_type { match self.node_type {
NodeType::ScrollFrame(ref mut scrolling) => { NodeType::Spatial { kind: SpatialNodeKind::ScrollFrame(ref mut scrolling), .. } => {
*scrolling = scrolling.combine_with_old_scroll_info(old_scroll_info); *scrolling = scrolling.combine_with_old_scroll_info(old_scroll_info);
} }
_ if old_scroll_info.offset != LayoutVector2D::zero() => { _ if old_scroll_info.offset != LayoutVector2D::zero() => {
@ -229,7 +267,7 @@ impl ClipScrollNode {
let scrollable_height = scrollable_size.height; let scrollable_height = scrollable_size.height;
let scrolling = match self.node_type { let scrolling = match self.node_type {
NodeType::ScrollFrame(ref mut scrolling) => scrolling, NodeType::Spatial { kind: SpatialNodeKind::ScrollFrame(ref mut scrolling), .. } => scrolling,
_ => { _ => {
warn!("Tried to scroll a non-scroll node."); warn!("Tried to scroll a non-scroll node.");
return false; return false;
@ -265,29 +303,32 @@ impl ClipScrollNode {
self.world_viewport_transform = LayoutToWorldFastTransform::identity(); self.world_viewport_transform = LayoutToWorldFastTransform::identity();
} }
pub fn push_gpu_node_data(&mut self, node_data: &mut Vec<ClipScrollNodeData>) { pub fn push_gpu_data(
if !self.invertible { &mut self,
node_data.push(ClipScrollNodeData::invalid()); transform_palette: &mut TransformPalette,
return; ) {
} if let NodeType::Spatial { .. } = self.node_type {
if !self.invertible {
let inv_transform = match self.world_content_transform.inverse() { transform_palette.set(self.transform_index, TransformData::invalid());
Some(inverted) => inverted.to_transform(),
None => {
node_data.push(ClipScrollNodeData::invalid());
return; return;
} }
};
let data = ClipScrollNodeData { let inv_transform = match self.world_content_transform.inverse() {
transform: self.world_content_transform.into(), Some(inverted) => inverted.to_transform(),
inv_transform, None => {
transform_kind: self.transform_kind as u32 as f32, transform_palette.set(self.transform_index, TransformData::invalid());
padding: [0.0; 3], return;
}; }
};
// Write the data that will be made available to the GPU for this node. let data = TransformData {
node_data.push(data); transform: self.world_content_transform.into(),
inv_transform,
};
// Write the data that will be made available to the GPU for this node.
transform_palette.set(self.transform_index, data);
}
} }
pub fn update( pub fn update(
@ -320,7 +361,7 @@ impl ClipScrollNode {
// For non-reference-frames we assume that they will produce only additional // For non-reference-frames we assume that they will produce only additional
// translations which should be invertible. // translations which should be invertible.
match self.node_type { match self.node_type {
NodeType::ReferenceFrame(info) if !info.invertible => { NodeType::Spatial { kind: SpatialNodeKind::ReferenceFrame(info), .. } if !info.invertible => {
self.mark_uninvertible(); self.mark_uninvertible();
return; return;
} }
@ -347,7 +388,7 @@ impl ClipScrollNode {
clip_chains: &mut [ClipChain], clip_chains: &mut [ClipChain],
) { ) {
let (clip_sources_handle, clip_chain_index, stored_clip_chain_node) = match self.node_type { let (clip_sources_handle, clip_chain_index, stored_clip_chain_node) = match self.node_type {
NodeType::Clip { ref handle, clip_chain_index, ref mut clip_chain_node } => NodeType::Clip { ref handle, clip_chain_index, ref mut clip_chain_node, .. } =>
(handle, clip_chain_index, clip_chain_node), (handle, clip_chain_index, clip_chain_node),
_ => { _ => {
self.invertible = true; self.invertible = true;
@ -378,7 +419,7 @@ impl ClipScrollNode {
let new_node = ClipChainNode { let new_node = ClipChainNode {
work_item: ClipWorkItem { work_item: ClipWorkItem {
scroll_node_data_index: self.node_data_index, transform_index: self.transform_index,
clip_sources: clip_sources_handle.weak(), clip_sources: clip_sources_handle.weak(),
coordinate_system_id: state.current_coordinate_system_id, coordinate_system_id: state.current_coordinate_system_id,
}, },
@ -442,9 +483,8 @@ impl ClipScrollNode {
self.coordinate_system_relative_transform = self.coordinate_system_relative_transform =
state.coordinate_system_relative_transform.offset(added_offset); state.coordinate_system_relative_transform.offset(added_offset);
match self.node_type { if let NodeType::Spatial { kind: SpatialNodeKind::StickyFrame(ref mut info), .. } = self.node_type {
NodeType::StickyFrame(ref mut info) => info.current_offset = sticky_offset, info.current_offset = sticky_offset;
_ => {},
} }
self.coordinate_system_id = state.current_coordinate_system_id; self.coordinate_system_id = state.current_coordinate_system_id;
@ -457,7 +497,7 @@ impl ClipScrollNode {
scene_properties: &SceneProperties, scene_properties: &SceneProperties,
) { ) {
let info = match self.node_type { let info = match self.node_type {
NodeType::ReferenceFrame(ref mut info) => info, NodeType::Spatial { kind: SpatialNodeKind::ReferenceFrame(ref mut info), .. } => info,
_ => unreachable!("Called update_transform_for_reference_frame on non-ReferenceFrame"), _ => unreachable!("Called update_transform_for_reference_frame on non-ReferenceFrame"),
}; };
@ -505,7 +545,7 @@ impl ClipScrollNode {
viewport_rect: &LayoutRect, viewport_rect: &LayoutRect,
) -> LayoutVector2D { ) -> LayoutVector2D {
let info = match self.node_type { let info = match self.node_type {
NodeType::StickyFrame(ref info) => info, NodeType::Spatial { kind: SpatialNodeKind::StickyFrame(ref info), .. } => info,
_ => return LayoutVector2D::zero(), _ => return LayoutVector2D::zero(),
}; };
@ -619,45 +659,48 @@ impl ClipScrollNode {
// between us and the parent reference frame. If we are a reference frame, // between us and the parent reference frame. If we are a reference frame,
// we need to reset both these values. // we need to reset both these values.
match self.node_type { match self.node_type {
NodeType::ReferenceFrame(ref info) => { NodeType::Spatial { ref kind, .. } => {
state.parent_reference_frame_transform = self.world_viewport_transform; match *kind {
state.parent_accumulated_scroll_offset = LayoutVector2D::zero(); SpatialNodeKind::StickyFrame(ref info) => {
state.coordinate_system_relative_transform = // We don't translate the combined rect by the sticky offset, because sticky
self.coordinate_system_relative_transform.clone(); // offsets actually adjust the node position itself, whereas scroll offsets
let translation = -info.origin_in_parent_reference_frame; // only apply to contents inside the node.
state.nearest_scrolling_ancestor_viewport = state.parent_accumulated_scroll_offset =
state.nearest_scrolling_ancestor_viewport info.current_offset + state.parent_accumulated_scroll_offset;
.translate(&translation); }
SpatialNodeKind::ScrollFrame(ref scrolling) => {
state.parent_accumulated_scroll_offset =
scrolling.offset + state.parent_accumulated_scroll_offset;
state.nearest_scrolling_ancestor_offset = scrolling.offset;
state.nearest_scrolling_ancestor_viewport = scrolling.viewport_rect;
}
SpatialNodeKind::ReferenceFrame(ref info) => {
state.parent_reference_frame_transform = self.world_viewport_transform;
state.parent_accumulated_scroll_offset = LayoutVector2D::zero();
state.coordinate_system_relative_transform =
self.coordinate_system_relative_transform.clone();
let translation = -info.origin_in_parent_reference_frame;
state.nearest_scrolling_ancestor_viewport =
state.nearest_scrolling_ancestor_viewport
.translate(&translation);
}
}
} }
NodeType::Clip{ .. } => { } NodeType::Clip{ .. } => { }
NodeType::ScrollFrame(ref scrolling) => {
state.parent_accumulated_scroll_offset =
scrolling.offset + state.parent_accumulated_scroll_offset;
state.nearest_scrolling_ancestor_offset = scrolling.offset;
state.nearest_scrolling_ancestor_viewport = scrolling.viewport_rect;
}
NodeType::StickyFrame(ref info) => {
// We don't translate the combined rect by the sticky offset, because sticky
// offsets actually adjust the node position itself, whereas scroll offsets
// only apply to contents inside the node.
state.parent_accumulated_scroll_offset =
info.current_offset + state.parent_accumulated_scroll_offset;
}
NodeType::Empty => unreachable!("Empty node remaining in ClipScrollTree."), NodeType::Empty => unreachable!("Empty node remaining in ClipScrollTree."),
} }
} }
pub fn scrollable_size(&self) -> LayoutSize { pub fn scrollable_size(&self) -> LayoutSize {
match self.node_type { match self.node_type {
NodeType:: ScrollFrame(state) => state.scrollable_size, NodeType::Spatial { kind: SpatialNodeKind::ScrollFrame(state), .. } => state.scrollable_size,
_ => LayoutSize::zero(), _ => LayoutSize::zero(),
} }
} }
pub fn scroll(&mut self, scroll_location: ScrollLocation) -> bool { pub fn scroll(&mut self, scroll_location: ScrollLocation) -> bool {
let scrolling = match self.node_type { let scrolling = match self.node_type {
NodeType::ScrollFrame(ref mut scrolling) => scrolling, NodeType::Spatial { kind: SpatialNodeKind::ScrollFrame(ref mut scrolling), .. } => scrolling,
_ => return false, _ => return false,
}; };
@ -707,14 +750,14 @@ impl ClipScrollNode {
pub fn scroll_offset(&self) -> LayoutVector2D { pub fn scroll_offset(&self) -> LayoutVector2D {
match self.node_type { match self.node_type {
NodeType::ScrollFrame(ref scrolling) => scrolling.offset, NodeType::Spatial { kind: SpatialNodeKind::ScrollFrame(ref scrolling), .. } => scrolling.offset,
_ => LayoutVector2D::zero(), _ => LayoutVector2D::zero(),
} }
} }
pub fn matches_external_id(&self, external_id: ExternalScrollId) -> bool { pub fn matches_external_id(&self, external_id: ExternalScrollId) -> bool {
match self.node_type { match self.node_type {
NodeType::ScrollFrame(info) if info.external_id == Some(external_id) => true, NodeType::Spatial { kind: SpatialNodeKind::ScrollFrame(info), .. } if info.external_id == Some(external_id) => true,
_ => false, _ => false,
} }
} }

Просмотреть файл

@ -4,11 +4,11 @@
use api::{DeviceIntRect, DevicePixelScale, ExternalScrollId, LayoutPoint, LayoutRect, LayoutVector2D}; use api::{DeviceIntRect, DevicePixelScale, ExternalScrollId, LayoutPoint, LayoutRect, LayoutVector2D};
use api::{PipelineId, ScrollClamping, ScrollLocation, ScrollNodeState}; use api::{PipelineId, ScrollClamping, ScrollLocation, ScrollNodeState};
use api::WorldPoint; use api::{LayoutSize, LayoutTransform, PropertyBinding, ScrollSensitivity, WorldPoint};
use clip::{ClipChain, ClipSourcesHandle, ClipStore}; use clip::{ClipChain, ClipSourcesHandle, ClipStore};
use clip_scroll_node::{ClipScrollNode, NodeType, ScrollFrameInfo, StickyFrameInfo}; use clip_scroll_node::{ClipScrollNode, NodeType, SpatialNodeKind, ScrollFrameInfo, StickyFrameInfo};
use gpu_cache::GpuCache; use gpu_cache::GpuCache;
use gpu_types::{ClipScrollNodeIndex as GPUClipScrollNodeIndex, ClipScrollNodeData}; use gpu_types::TransformPalette;
use internal_types::{FastHashMap, FastHashSet}; use internal_types::{FastHashMap, FastHashSet};
use print_tree::{PrintTree, PrintTreePrinter}; use print_tree::{PrintTree, PrintTreePrinter};
use resource_cache::ResourceCache; use resource_cache::ResourceCache;
@ -29,6 +29,15 @@ pub struct CoordinateSystemId(pub u32);
#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)] #[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)]
pub struct ClipScrollNodeIndex(pub usize); pub struct ClipScrollNodeIndex(pub usize);
// Used to index the smaller subset of nodes in the CST that define
// new transform / positioning.
// TODO(gw): In the future if we split the CST into a positioning and
// clipping tree, this can be tidied up a bit.
#[derive(Copy, Debug, Clone, PartialEq)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct TransformIndex(pub u32);
const ROOT_REFERENCE_FRAME_INDEX: ClipScrollNodeIndex = ClipScrollNodeIndex(0); const ROOT_REFERENCE_FRAME_INDEX: ClipScrollNodeIndex = ClipScrollNodeIndex(0);
const TOPMOST_SCROLL_NODE_INDEX: ClipScrollNodeIndex = ClipScrollNodeIndex(1); const TOPMOST_SCROLL_NODE_INDEX: ClipScrollNodeIndex = ClipScrollNodeIndex(1);
@ -70,14 +79,13 @@ pub struct ClipScrollTree {
pub pending_scroll_offsets: FastHashMap<ExternalScrollId, (LayoutPoint, ScrollClamping)>, pub pending_scroll_offsets: FastHashMap<ExternalScrollId, (LayoutPoint, ScrollClamping)>,
/// The current frame id, used for giving a unique id to all new dynamically
/// added frames and clips. The ClipScrollTree increments this by one every
/// time a new dynamic frame is created.
current_new_node_item: u64,
/// A set of pipelines which should be discarded the next time this /// A set of pipelines which should be discarded the next time this
/// tree is drained. /// tree is drained.
pub pipelines_to_discard: FastHashSet<PipelineId>, pub pipelines_to_discard: FastHashSet<PipelineId>,
/// The number of nodes in the CST that are spatial. Currently, this is all
/// nodes that are not clip nodes.
spatial_node_count: usize,
} }
#[derive(Clone)] #[derive(Clone)]
@ -112,8 +120,8 @@ impl ClipScrollTree {
clip_chains_descriptors: Vec::new(), clip_chains_descriptors: Vec::new(),
clip_chains: vec![ClipChain::empty(&DeviceIntRect::zero())], clip_chains: vec![ClipChain::empty(&DeviceIntRect::zero())],
pending_scroll_offsets: FastHashMap::default(), pending_scroll_offsets: FastHashMap::default(),
current_new_node_item: 1,
pipelines_to_discard: FastHashSet::default(), pipelines_to_discard: FastHashSet::default(),
spatial_node_count: 0,
} }
} }
@ -136,7 +144,7 @@ impl ClipScrollTree {
pub fn get_scroll_node_state(&self) -> Vec<ScrollNodeState> { pub fn get_scroll_node_state(&self) -> Vec<ScrollNodeState> {
let mut result = vec![]; let mut result = vec![];
for node in &self.nodes { for node in &self.nodes {
if let NodeType::ScrollFrame(info) = node.node_type { if let NodeType::Spatial { kind: SpatialNodeKind::ScrollFrame(info), .. } = node.node_type {
if let Some(id) = info.external_id { if let Some(id) = info.external_id {
result.push(ScrollNodeState { id, scroll_offset: info.offset }) result.push(ScrollNodeState { id, scroll_offset: info.offset })
} }
@ -146,8 +154,6 @@ impl ClipScrollTree {
} }
pub fn drain(&mut self) -> ScrollStates { pub fn drain(&mut self) -> ScrollStates {
self.current_new_node_item = 1;
let mut scroll_states = FastHashMap::default(); let mut scroll_states = FastHashMap::default();
for old_node in &mut self.nodes.drain(..) { for old_node in &mut self.nodes.drain(..) {
if self.pipelines_to_discard.contains(&old_node.pipeline_id) { if self.pipelines_to_discard.contains(&old_node.pipeline_id) {
@ -155,13 +161,14 @@ impl ClipScrollTree {
} }
match old_node.node_type { match old_node.node_type {
NodeType::ScrollFrame(info) if info.external_id.is_some() => { NodeType::Spatial { kind: SpatialNodeKind::ScrollFrame(info), .. } if info.external_id.is_some() => {
scroll_states.insert(info.external_id.unwrap(), info); scroll_states.insert(info.external_id.unwrap(), info);
} }
_ => {} _ => {}
} }
} }
self.spatial_node_count = 0;
self.pipelines_to_discard.clear(); self.pipelines_to_discard.clear();
self.clip_chains = vec![ClipChain::empty(&DeviceIntRect::zero())]; self.clip_chains = vec![ClipChain::empty(&DeviceIntRect::zero())];
self.clip_chains_descriptors.clear(); self.clip_chains_descriptors.clear();
@ -195,7 +202,7 @@ impl ClipScrollTree {
let node = &self.nodes[index.0]; let node = &self.nodes[index.0];
match node.node_type { match node.node_type {
NodeType::ScrollFrame(state) if state.sensitive_to_input_events() => index, NodeType::Spatial { kind: SpatialNodeKind::ScrollFrame(state), .. } if state.sensitive_to_input_events() => index,
_ => self.find_nearest_scrolling_ancestor(node.parent) _ => self.find_nearest_scrolling_ancestor(node.parent)
} }
} }
@ -220,40 +227,41 @@ impl ClipScrollTree {
resource_cache: &mut ResourceCache, resource_cache: &mut ResourceCache,
gpu_cache: &mut GpuCache, gpu_cache: &mut GpuCache,
pan: WorldPoint, pan: WorldPoint,
node_data: &mut Vec<ClipScrollNodeData>,
scene_properties: &SceneProperties, scene_properties: &SceneProperties,
) { ) -> TransformPalette {
if self.nodes.is_empty() { let mut transform_palette = TransformPalette::new(self.spatial_node_count);
return;
if !self.nodes.is_empty() {
self.clip_chains[0] = ClipChain::empty(screen_rect);
let root_reference_frame_index = self.root_reference_frame_index();
let mut state = TransformUpdateState {
parent_reference_frame_transform: LayoutVector2D::new(pan.x, pan.y).into(),
parent_accumulated_scroll_offset: LayoutVector2D::zero(),
nearest_scrolling_ancestor_offset: LayoutVector2D::zero(),
nearest_scrolling_ancestor_viewport: LayoutRect::zero(),
parent_clip_chain_index: ClipChainIndex(0),
current_coordinate_system_id: CoordinateSystemId::root(),
coordinate_system_relative_transform: LayoutFastTransform::identity(),
invertible: true,
};
let mut next_coordinate_system_id = state.current_coordinate_system_id.next();
self.update_node(
root_reference_frame_index,
&mut state,
&mut next_coordinate_system_id,
device_pixel_scale,
clip_store,
resource_cache,
gpu_cache,
&mut transform_palette,
scene_properties,
);
self.build_clip_chains(screen_rect);
} }
self.clip_chains[0] = ClipChain::empty(screen_rect); transform_palette
let root_reference_frame_index = self.root_reference_frame_index();
let mut state = TransformUpdateState {
parent_reference_frame_transform: LayoutVector2D::new(pan.x, pan.y).into(),
parent_accumulated_scroll_offset: LayoutVector2D::zero(),
nearest_scrolling_ancestor_offset: LayoutVector2D::zero(),
nearest_scrolling_ancestor_viewport: LayoutRect::zero(),
parent_clip_chain_index: ClipChainIndex(0),
current_coordinate_system_id: CoordinateSystemId::root(),
coordinate_system_relative_transform: LayoutFastTransform::identity(),
invertible: true,
};
let mut next_coordinate_system_id = state.current_coordinate_system_id.next();
self.update_node(
root_reference_frame_index,
&mut state,
&mut next_coordinate_system_id,
device_pixel_scale,
clip_store,
resource_cache,
gpu_cache,
node_data,
scene_properties,
);
self.build_clip_chains(screen_rect);
} }
fn update_node( fn update_node(
@ -265,7 +273,7 @@ impl ClipScrollTree {
clip_store: &mut ClipStore, clip_store: &mut ClipStore,
resource_cache: &mut ResourceCache, resource_cache: &mut ResourceCache,
gpu_cache: &mut GpuCache, gpu_cache: &mut GpuCache,
gpu_node_data: &mut Vec<ClipScrollNodeData>, transform_palette: &mut TransformPalette,
scene_properties: &SceneProperties, scene_properties: &SceneProperties,
) { ) {
// TODO(gw): This is an ugly borrow check workaround to clone these. // TODO(gw): This is an ugly borrow check workaround to clone these.
@ -277,9 +285,6 @@ impl ClipScrollTree {
None => return, None => return,
}; };
// We set this early so that we can use it to populate the ClipChain.
node.node_data_index = GPUClipScrollNodeIndex(gpu_node_data.len() as u32);
node.update( node.update(
&mut state, &mut state,
next_coordinate_system_id, next_coordinate_system_id,
@ -291,7 +296,7 @@ impl ClipScrollTree {
&mut self.clip_chains, &mut self.clip_chains,
); );
node.push_gpu_node_data(gpu_node_data); node.push_gpu_data(transform_palette);
if node.children.is_empty() { if node.children.is_empty() {
return; return;
@ -310,7 +315,7 @@ impl ClipScrollTree {
clip_store, clip_store,
resource_cache, resource_cache,
gpu_cache, gpu_cache,
gpu_node_data, transform_palette,
scene_properties, scene_properties,
); );
} }
@ -346,7 +351,7 @@ impl ClipScrollTree {
pub fn finalize_and_apply_pending_scroll_offsets(&mut self, old_states: ScrollStates) { pub fn finalize_and_apply_pending_scroll_offsets(&mut self, old_states: ScrollStates) {
for node in &mut self.nodes { for node in &mut self.nodes {
let external_id = match node.node_type { let external_id = match node.node_type {
NodeType::ScrollFrame(ScrollFrameInfo { external_id: Some(id), ..} ) => id, NodeType::Spatial { kind: SpatialNodeKind::ScrollFrame(ScrollFrameInfo { external_id: Some(id), ..} ), .. } => id,
_ => continue, _ => continue,
}; };
@ -360,6 +365,13 @@ impl ClipScrollTree {
} }
} }
// Generate the next valid TransformIndex for the CST.
fn next_transform_index(&mut self) -> TransformIndex {
let transform_index = TransformIndex(self.spatial_node_count as u32);
self.spatial_node_count += 1;
transform_index
}
pub fn add_clip_node( pub fn add_clip_node(
&mut self, &mut self,
index: ClipScrollNodeIndex, index: ClipScrollNodeIndex,
@ -368,12 +380,65 @@ impl ClipScrollTree {
pipeline_id: PipelineId, pipeline_id: PipelineId,
) -> ClipChainIndex { ) -> ClipChainIndex {
let clip_chain_index = self.allocate_clip_chain(); let clip_chain_index = self.allocate_clip_chain();
let node_type = NodeType::Clip { handle, clip_chain_index, clip_chain_node: None }; let transform_index = self.nodes[parent_index.0].transform_index;
let node = ClipScrollNode::new(pipeline_id, Some(parent_index), node_type);
let node_type = NodeType::Clip {
handle,
clip_chain_index,
clip_chain_node: None,
};
let node = ClipScrollNode::new(
pipeline_id,
Some(parent_index),
node_type,
transform_index,
);
self.add_node(node, index); self.add_node(node, index);
clip_chain_index clip_chain_index
} }
pub fn add_scroll_frame(
&mut self,
index: ClipScrollNodeIndex,
parent_index: ClipScrollNodeIndex,
external_id: Option<ExternalScrollId>,
pipeline_id: PipelineId,
frame_rect: &LayoutRect,
content_size: &LayoutSize,
scroll_sensitivity: ScrollSensitivity,
) {
let node = ClipScrollNode::new_scroll_frame(
pipeline_id,
parent_index,
external_id,
frame_rect,
content_size,
scroll_sensitivity,
self.next_transform_index(),
);
self.add_node(node, index);
}
pub fn add_reference_frame(
&mut self,
index: ClipScrollNodeIndex,
parent_index: Option<ClipScrollNodeIndex>,
source_transform: Option<PropertyBinding<LayoutTransform>>,
source_perspective: Option<LayoutTransform>,
origin_in_parent_reference_frame: LayoutVector2D,
pipeline_id: PipelineId,
) {
let node = ClipScrollNode::new_reference_frame(
parent_index,
source_transform,
source_perspective,
origin_in_parent_reference_frame,
pipeline_id,
self.next_transform_index(),
);
self.add_node(node, index);
}
pub fn add_sticky_frame( pub fn add_sticky_frame(
&mut self, &mut self,
index: ClipScrollNodeIndex, index: ClipScrollNodeIndex,
@ -381,7 +446,12 @@ impl ClipScrollTree {
sticky_frame_info: StickyFrameInfo, sticky_frame_info: StickyFrameInfo,
pipeline_id: PipelineId, pipeline_id: PipelineId,
) { ) {
let node = ClipScrollNode::new_sticky_frame(parent_index, sticky_frame_info, pipeline_id); let node = ClipScrollNode::new_sticky_frame(
parent_index,
sticky_frame_info,
pipeline_id,
self.next_transform_index(),
);
self.add_node(node, index); self.add_node(node, index);
} }
@ -436,6 +506,26 @@ impl ClipScrollTree {
) { ) {
let node = &self.nodes[index.0]; let node = &self.nodes[index.0];
match node.node_type { match node.node_type {
NodeType::Spatial { ref kind, .. } => {
match *kind {
SpatialNodeKind::StickyFrame(ref sticky_frame_info) => {
pt.new_level(format!("StickyFrame"));
pt.add_item(format!("index: {:?}", index));
pt.add_item(format!("sticky info: {:?}", sticky_frame_info));
}
SpatialNodeKind::ScrollFrame(scrolling_info) => {
pt.new_level(format!("ScrollFrame"));
pt.add_item(format!("index: {:?}", index));
pt.add_item(format!("viewport: {:?}", scrolling_info.viewport_rect));
pt.add_item(format!("scrollable_size: {:?}", scrolling_info.scrollable_size));
pt.add_item(format!("scroll offset: {:?}", scrolling_info.offset));
}
SpatialNodeKind::ReferenceFrame(ref info) => {
pt.new_level(format!("ReferenceFrame {:?}", info.resolved_transform));
pt.add_item(format!("index: {:?}", index));
}
}
}
NodeType::Clip { ref handle, .. } => { NodeType::Clip { ref handle, .. } => {
pt.new_level("Clip".to_owned()); pt.new_level("Clip".to_owned());
@ -447,22 +537,6 @@ impl ClipScrollTree {
} }
pt.end_level(); pt.end_level();
} }
NodeType::ReferenceFrame(ref info) => {
pt.new_level(format!("ReferenceFrame {:?}", info.resolved_transform));
pt.add_item(format!("index: {:?}", index));
}
NodeType::ScrollFrame(scrolling_info) => {
pt.new_level(format!("ScrollFrame"));
pt.add_item(format!("index: {:?}", index));
pt.add_item(format!("viewport: {:?}", scrolling_info.viewport_rect));
pt.add_item(format!("scrollable_size: {:?}", scrolling_info.scrollable_size));
pt.add_item(format!("scroll offset: {:?}", scrolling_info.offset));
}
NodeType::StickyFrame(ref sticky_frame_info) => {
pt.new_level(format!("StickyFrame"));
pt.add_item(format!("index: {:?}", index));
pt.add_item(format!("sticky info: {:?}", sticky_frame_info));
}
NodeType::Empty => unreachable!("Empty node remaining in ClipScrollTree."), NodeType::Empty => unreachable!("Empty node remaining in ClipScrollTree."),
} }

Просмотреть файл

@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use super::shader_source; use super::super::shader_source;
use api::{ColorF, ImageFormat}; use api::{ColorF, ImageFormat};
use api::{DeviceIntPoint, DeviceIntRect, DeviceUintRect, DeviceUintSize}; use api::{DeviceIntPoint, DeviceIntRect, DeviceUintRect, DeviceUintSize};
use api::TextureTarget; use api::TextureTarget;
@ -2234,6 +2234,11 @@ impl Device {
external: gl::RGBA, external: gl::RGBA,
pixel_type: gl::FLOAT, pixel_type: gl::FLOAT,
}, },
ImageFormat::RGBAI32 => FormatDesc {
internal: gl::RGBA32I as _,
external: gl::RGBA_INTEGER,
pixel_type: gl::INT,
},
ImageFormat::RG8 => FormatDesc { ImageFormat::RG8 => FormatDesc {
internal: gl::RG8 as _, internal: gl::RG8 as _,
external: gl::RG, external: gl::RG,
@ -2360,6 +2365,7 @@ impl<'a> UploadTarget<'a> {
ImageFormat::BGRA8 => (self.bgra_format, 4, gl::UNSIGNED_BYTE), ImageFormat::BGRA8 => (self.bgra_format, 4, gl::UNSIGNED_BYTE),
ImageFormat::RG8 => (gl::RG, 2, gl::UNSIGNED_BYTE), ImageFormat::RG8 => (gl::RG, 2, gl::UNSIGNED_BYTE),
ImageFormat::RGBAF32 => (gl::RGBA, 16, gl::FLOAT), ImageFormat::RGBAF32 => (gl::RGBA, 16, gl::FLOAT),
ImageFormat::RGBAI32 => (gl::RGBA_INTEGER, 16, gl::INT),
}; };
let row_length = match chunk.stride { let row_length = match chunk.stride {

Просмотреть файл

@ -0,0 +1,7 @@
/* 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/. */
mod gl;
pub use self::gl::*;

Просмотреть файл

@ -14,10 +14,10 @@ use api::{PropertyBinding, ReferenceFrame, RepeatMode, ScrollFrameDisplayItem, S
use api::{Shadow, SpecificDisplayItem, StackingContext, StickyFrameDisplayItem, TexelRect}; use api::{Shadow, SpecificDisplayItem, StackingContext, StickyFrameDisplayItem, TexelRect};
use api::{TransformStyle, YuvColorSpace, YuvData}; use api::{TransformStyle, YuvColorSpace, YuvData};
use clip::{ClipRegion, ClipSource, ClipSources, ClipStore}; use clip::{ClipRegion, ClipSource, ClipSources, ClipStore};
use clip_scroll_node::{ClipScrollNode, NodeType, StickyFrameInfo}; use clip_scroll_node::{NodeType, SpatialNodeKind, StickyFrameInfo};
use clip_scroll_tree::{ClipChainIndex, ClipScrollNodeIndex, ClipScrollTree}; use clip_scroll_tree::{ClipChainIndex, ClipScrollNodeIndex, ClipScrollTree};
use euclid::{SideOffsets2D, vec2}; use euclid::vec2;
use frame_builder::{FrameBuilder, FrameBuilderConfig}; use frame_builder::{ChasePrimitive, FrameBuilder, FrameBuilderConfig};
use glyph_rasterizer::FontInstance; use glyph_rasterizer::FontInstance;
use gpu_cache::GpuCacheHandle; use gpu_cache::GpuCacheHandle;
use gpu_types::BrushFlags; use gpu_types::BrushFlags;
@ -628,8 +628,7 @@ impl<'a> DisplayListFlattener<'a> {
); );
} }
SpecificDisplayItem::Gradient(ref info) => { SpecificDisplayItem::Gradient(ref info) => {
self.add_gradient( let brush_kind = self.create_brush_kind_for_gradient(
clip_and_scroll,
&prim_info, &prim_info,
info.gradient.start_point, info.gradient.start_point,
info.gradient.end_point, info.gradient.end_point,
@ -638,10 +637,11 @@ impl<'a> DisplayListFlattener<'a> {
info.tile_size, info.tile_size,
info.tile_spacing, info.tile_spacing,
); );
let prim = PrimitiveContainer::Brush(BrushPrimitive::new(brush_kind, None));
self.add_primitive(clip_and_scroll, &prim_info, Vec::new(), prim);
} }
SpecificDisplayItem::RadialGradient(ref info) => { SpecificDisplayItem::RadialGradient(ref info) => {
self.add_radial_gradient( let brush_kind = self.create_brush_kind_for_radial_gradient(
clip_and_scroll,
&prim_info, &prim_info,
info.gradient.center, info.gradient.center,
info.gradient.start_offset * info.gradient.radius.width, info.gradient.start_offset * info.gradient.radius.width,
@ -652,6 +652,8 @@ impl<'a> DisplayListFlattener<'a> {
info.tile_size, info.tile_size,
info.tile_spacing, info.tile_spacing,
); );
let prim = PrimitiveContainer::Brush(BrushPrimitive::new(brush_kind, None));
self.add_primitive(clip_and_scroll, &prim_info, Vec::new(), prim);
} }
SpecificDisplayItem::BoxShadow(ref box_shadow_info) => { SpecificDisplayItem::BoxShadow(ref box_shadow_info) => {
let bounds = box_shadow_info let bounds = box_shadow_info
@ -875,6 +877,10 @@ impl<'a> DisplayListFlattener<'a> {
if container.is_visible() { if container.is_visible() {
let prim_index = self.create_primitive(info, clip_sources, container); let prim_index = self.create_primitive(info, clip_sources, container);
if cfg!(debug_assertions) && ChasePrimitive::LocalRect(info.rect) == self.config.chase_primitive {
println!("Chasing {:?}", prim_index);
self.prim_store.chase_id = Some(prim_index);
}
self.add_primitive_to_hit_testing_list(info, clip_and_scroll); self.add_primitive_to_hit_testing_list(info, clip_and_scroll);
self.add_primitive_to_draw_list(prim_index, clip_and_scroll); self.add_primitive_to_draw_list(prim_index, clip_and_scroll);
} }
@ -1197,14 +1203,15 @@ impl<'a> DisplayListFlattener<'a> {
origin_in_parent_reference_frame: LayoutVector2D, origin_in_parent_reference_frame: LayoutVector2D,
) -> ClipScrollNodeIndex { ) -> ClipScrollNodeIndex {
let index = self.id_to_index_mapper.get_node_index(reference_frame_id); let index = self.id_to_index_mapper.get_node_index(reference_frame_id);
let node = ClipScrollNode::new_reference_frame( let parent_index = parent_id.map(|id| self.id_to_index_mapper.get_node_index(id));
parent_id.map(|id| self.id_to_index_mapper.get_node_index(id)), self.clip_scroll_tree.add_reference_frame(
index,
parent_index,
source_transform, source_transform,
source_perspective, source_perspective,
origin_in_parent_reference_frame, origin_in_parent_reference_frame,
pipeline_id, pipeline_id,
); );
self.clip_scroll_tree.add_node(node, index);
self.reference_frame_stack.push((reference_frame_id, index)); self.reference_frame_stack.push((reference_frame_id, index));
match parent_id { match parent_id {
@ -1227,7 +1234,7 @@ impl<'a> DisplayListFlattener<'a> {
let viewport_offset = (inner_rect.origin.to_vector().to_f32() / device_pixel_scale).round(); let viewport_offset = (inner_rect.origin.to_vector().to_f32() / device_pixel_scale).round();
let root_id = self.clip_scroll_tree.root_reference_frame_index(); let root_id = self.clip_scroll_tree.root_reference_frame_index();
let root_node = &mut self.clip_scroll_tree.nodes[root_id.0]; let root_node = &mut self.clip_scroll_tree.nodes[root_id.0];
if let NodeType::ReferenceFrame(ref mut info) = root_node.node_type { if let NodeType::Spatial { kind: SpatialNodeKind::ReferenceFrame(ref mut info), .. } = root_node.node_type {
info.resolved_transform = info.resolved_transform =
LayoutVector2D::new(viewport_offset.x, viewport_offset.y).into(); LayoutVector2D::new(viewport_offset.x, viewport_offset.y).into();
} }
@ -1290,16 +1297,15 @@ impl<'a> DisplayListFlattener<'a> {
scroll_sensitivity: ScrollSensitivity, scroll_sensitivity: ScrollSensitivity,
) -> ClipScrollNodeIndex { ) -> ClipScrollNodeIndex {
let node_index = self.id_to_index_mapper.get_node_index(new_node_id); let node_index = self.id_to_index_mapper.get_node_index(new_node_id);
let node = ClipScrollNode::new_scroll_frame( self.clip_scroll_tree.add_scroll_frame(
pipeline_id, node_index,
self.id_to_index_mapper.get_node_index(parent_id), self.id_to_index_mapper.get_node_index(parent_id),
external_id, external_id,
pipeline_id,
frame_rect, frame_rect,
content_size, content_size,
scroll_sensitivity, scroll_sensitivity,
); );
self.clip_scroll_tree.add_node(node, node_index);
self.id_to_index_mapper.map_to_parent_clip_chain(new_node_id, &parent_id); self.id_to_index_mapper.map_to_parent_clip_chain(new_node_id, &parent_id);
node_index node_index
} }
@ -1492,51 +1498,6 @@ impl<'a> DisplayListFlattener<'a> {
gradient_stops: ItemRange<GradientStop>, gradient_stops: ItemRange<GradientStop>,
) { ) {
let rect = info.rect; let rect = info.rect;
let create_segments = |outset: SideOffsets2D<f32>| {
// Calculate the modified rect as specific by border-image-outset
let origin = LayoutPoint::new(rect.origin.x - outset.left, rect.origin.y - outset.top);
let size = LayoutSize::new(
rect.size.width + outset.left + outset.right,
rect.size.height + outset.top + outset.bottom,
);
let rect = LayoutRect::new(origin, size);
let tl_outer = LayoutPoint::new(rect.origin.x, rect.origin.y);
let tl_inner = tl_outer + vec2(border_item.widths.left, border_item.widths.top);
let tr_outer = LayoutPoint::new(rect.origin.x + rect.size.width, rect.origin.y);
let tr_inner = tr_outer + vec2(-border_item.widths.right, border_item.widths.top);
let bl_outer = LayoutPoint::new(rect.origin.x, rect.origin.y + rect.size.height);
let bl_inner = bl_outer + vec2(border_item.widths.left, -border_item.widths.bottom);
let br_outer = LayoutPoint::new(
rect.origin.x + rect.size.width,
rect.origin.y + rect.size.height,
);
let br_inner = br_outer - vec2(border_item.widths.right, border_item.widths.bottom);
// Build the list of gradient segments
vec![
// Top left
LayoutRect::from_floats(tl_outer.x, tl_outer.y, tl_inner.x, tl_inner.y),
// Top right
LayoutRect::from_floats(tr_inner.x, tr_outer.y, tr_outer.x, tr_inner.y),
// Bottom right
LayoutRect::from_floats(br_inner.x, br_inner.y, br_outer.x, br_outer.y),
// Bottom left
LayoutRect::from_floats(bl_outer.x, bl_inner.y, bl_inner.x, bl_outer.y),
// Top
LayoutRect::from_floats(tl_inner.x, tl_outer.y, tr_inner.x, tl_inner.y),
// Bottom
LayoutRect::from_floats(bl_inner.x, bl_inner.y, br_inner.x, bl_outer.y),
// Left
LayoutRect::from_floats(tl_outer.x, tl_inner.y, tl_inner.x, bl_inner.y),
// Right
LayoutRect::from_floats(tr_inner.x, tr_inner.y, br_outer.x, br_inner.y),
]
};
match border_item.details { match border_item.details {
BorderDetails::NinePatch(ref border) => { BorderDetails::NinePatch(ref border) => {
// Calculate the modified rect as specific by border-image-outset // Calculate the modified rect as specific by border-image-outset
@ -1701,70 +1662,55 @@ impl<'a> DisplayListFlattener<'a> {
clip_mask_kind: BrushClipMaskKind::Unknown, clip_mask_kind: BrushClipMaskKind::Unknown,
}; };
let prim = PrimitiveContainer::Brush(match border.source { let brush_kind = match border.source {
NinePatchBorderSource::Image(image_key) => { NinePatchBorderSource::Image(image_key) => {
let source = BorderSource::Image(ImageRequest { BrushKind::Border {
key: image_key, source: BorderSource::Image(ImageRequest {
rendering: ImageRendering::Auto, key: image_key,
tile: None, rendering: ImageRendering::Auto,
}); tile: None,
})
BrushPrimitive::new( }
BrushKind::Border { }
source NinePatchBorderSource::Gradient(gradient) => {
}, self.create_brush_kind_for_gradient(
Some(descriptor), &info,
gradient.start_point,
gradient.end_point,
gradient_stops,
gradient.extend_mode,
LayoutSize::new(border.height as f32, border.width as f32),
LayoutSize::zero(),
) )
} }
}); NinePatchBorderSource::RadialGradient(gradient) => {
self.create_brush_kind_for_radial_gradient(
&info,
gradient.center,
gradient.start_offset * gradient.radius.width,
gradient.end_offset * gradient.radius.width,
gradient.radius.width / gradient.radius.height,
gradient_stops,
gradient.extend_mode,
LayoutSize::new(border.height as f32, border.width as f32),
LayoutSize::zero(),
)
}
};
let prim = PrimitiveContainer::Brush(
BrushPrimitive::new(brush_kind, Some(descriptor))
);
self.add_primitive(clip_and_scroll, info, Vec::new(), prim); self.add_primitive(clip_and_scroll, info, Vec::new(), prim);
} }
BorderDetails::Normal(ref border) => { BorderDetails::Normal(ref border) => {
self.add_normal_border(info, border, &border_item.widths, clip_and_scroll); self.add_normal_border(info, border, &border_item.widths, clip_and_scroll);
} }
BorderDetails::Gradient(ref border) => for segment in create_segments(border.outset) {
let segment_rel = segment.origin - rect.origin;
let mut info = info.clone();
info.rect = segment;
self.add_gradient(
clip_and_scroll,
&info,
border.gradient.start_point - segment_rel,
border.gradient.end_point - segment_rel,
gradient_stops,
border.gradient.extend_mode,
segment.size,
LayoutSize::zero(),
);
},
BorderDetails::RadialGradient(ref border) => {
for segment in create_segments(border.outset) {
let segment_rel = segment.origin - rect.origin;
let mut info = info.clone();
info.rect = segment;
self.add_radial_gradient(
clip_and_scroll,
&info,
border.gradient.center - segment_rel,
border.gradient.start_offset * border.gradient.radius.width,
border.gradient.end_offset * border.gradient.radius.width,
border.gradient.radius.width / border.gradient.radius.height,
gradient_stops,
border.gradient.extend_mode,
segment.size,
LayoutSize::zero(),
);
}
}
} }
} }
pub fn add_gradient( pub fn create_brush_kind_for_gradient(
&mut self, &mut self,
clip_and_scroll: ScrollNodeAndClipChain,
info: &LayoutPrimitiveInfo, info: &LayoutPrimitiveInfo,
start_point: LayoutPoint, start_point: LayoutPoint,
end_point: LayoutPoint, end_point: LayoutPoint,
@ -1772,13 +1718,9 @@ impl<'a> DisplayListFlattener<'a> {
extend_mode: ExtendMode, extend_mode: ExtendMode,
stretch_size: LayoutSize, stretch_size: LayoutSize,
mut tile_spacing: LayoutSize, mut tile_spacing: LayoutSize,
) { ) -> BrushKind {
let mut prim_rect = info.rect; let mut prim_rect = info.rect;
simplify_repeated_primitive(&stretch_size, &mut tile_spacing, &mut prim_rect); simplify_repeated_primitive(&stretch_size, &mut tile_spacing, &mut prim_rect);
let info = LayoutPrimitiveInfo {
rect: prim_rect,
.. *info
};
// Try to ensure that if the gradient is specified in reverse, then so long as the stops // Try to ensure that if the gradient is specified in reverse, then so long as the stops
// are also supplied in reverse that the rendered result will be equivalent. To do this, // are also supplied in reverse that the rendered result will be equivalent. To do this,
@ -1798,29 +1740,21 @@ impl<'a> DisplayListFlattener<'a> {
(start_point, end_point) (start_point, end_point)
}; };
let prim = BrushPrimitive::new( BrushKind::LinearGradient {
BrushKind::LinearGradient { stops_range: stops,
stops_range: stops, extend_mode,
extend_mode, reverse_stops,
reverse_stops, start_point: sp,
start_point: sp, end_point: ep,
end_point: ep, stops_handle: GpuCacheHandle::new(),
stops_handle: GpuCacheHandle::new(), stretch_size,
stretch_size, tile_spacing,
tile_spacing, visible_tiles: Vec::new(),
visible_tiles: Vec::new(), }
},
None,
);
let prim = PrimitiveContainer::Brush(prim);
self.add_primitive(clip_and_scroll, &info, Vec::new(), prim);
} }
pub fn add_radial_gradient( pub fn create_brush_kind_for_radial_gradient(
&mut self, &mut self,
clip_and_scroll: ScrollNodeAndClipChain,
info: &LayoutPrimitiveInfo, info: &LayoutPrimitiveInfo,
center: LayoutPoint, center: LayoutPoint,
start_radius: f32, start_radius: f32,
@ -1830,36 +1764,22 @@ impl<'a> DisplayListFlattener<'a> {
extend_mode: ExtendMode, extend_mode: ExtendMode,
stretch_size: LayoutSize, stretch_size: LayoutSize,
mut tile_spacing: LayoutSize, mut tile_spacing: LayoutSize,
) { ) -> BrushKind {
let mut prim_rect = info.rect; let mut prim_rect = info.rect;
simplify_repeated_primitive(&stretch_size, &mut tile_spacing, &mut prim_rect); simplify_repeated_primitive(&stretch_size, &mut tile_spacing, &mut prim_rect);
let info = LayoutPrimitiveInfo {
rect: prim_rect,
.. *info
};
let prim = BrushPrimitive::new( BrushKind::RadialGradient {
BrushKind::RadialGradient { stops_range: stops,
stops_range: stops, extend_mode,
extend_mode, center,
center, start_radius,
start_radius, end_radius,
end_radius, ratio_xy,
ratio_xy, stops_handle: GpuCacheHandle::new(),
stops_handle: GpuCacheHandle::new(), stretch_size,
stretch_size, tile_spacing,
tile_spacing, visible_tiles: Vec::new(),
visible_tiles: Vec::new(), }
},
None,
);
self.add_primitive(
clip_and_scroll,
&info,
Vec::new(),
PrimitiveContainer::Brush(prim),
);
} }
pub fn add_text( pub fn add_text(

Просмотреть файл

@ -4,13 +4,13 @@
use api::{BuiltDisplayList, ColorF, DeviceIntPoint, DeviceIntRect, DevicePixelScale}; use api::{BuiltDisplayList, ColorF, DeviceIntPoint, DeviceIntRect, DevicePixelScale};
use api::{DeviceUintPoint, DeviceUintRect, DeviceUintSize, DocumentLayer, FontRenderMode}; use api::{DeviceUintPoint, DeviceUintRect, DeviceUintSize, DocumentLayer, FontRenderMode};
use api::{LayoutRect, LayoutSize, PipelineId, WorldPoint}; use api::{LayoutPoint, LayoutRect, LayoutSize, PipelineId, WorldPoint};
use clip::{ClipChain, ClipStore}; use clip::{ClipChain, ClipStore};
use clip_scroll_node::{ClipScrollNode}; use clip_scroll_node::{ClipScrollNode};
use clip_scroll_tree::{ClipScrollNodeIndex, ClipScrollTree}; use clip_scroll_tree::{ClipScrollNodeIndex, ClipScrollTree};
use display_list_flattener::{DisplayListFlattener}; use display_list_flattener::{DisplayListFlattener};
use gpu_cache::GpuCache; use gpu_cache::GpuCache;
use gpu_types::{ClipChainRectIndex, ClipScrollNodeData, UvRectKind}; use gpu_types::{PrimitiveHeaders, TransformData, UvRectKind};
use hit_test::{HitTester, HitTestingRun}; use hit_test::{HitTester, HitTestingRun};
use internal_types::{FastHashMap}; use internal_types::{FastHashMap};
use picture::PictureSurface; use picture::PictureSurface;
@ -24,7 +24,22 @@ use std::{mem, f32};
use std::sync::Arc; use std::sync::Arc;
use tiling::{Frame, RenderPass, RenderPassKind, RenderTargetContext}; use tiling::{Frame, RenderPass, RenderPassKind, RenderTargetContext};
use tiling::{ScrollbarPrimitive, SpecialRenderPasses}; use tiling::{ScrollbarPrimitive, SpecialRenderPasses};
use util::{self, MaxRect, WorldToLayoutFastTransform}; use util::{self, WorldToLayoutFastTransform};
#[derive(Clone, Copy, Debug, PartialEq)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub enum ChasePrimitive {
Nothing,
LocalRect(LayoutRect),
}
impl Default for ChasePrimitive {
fn default() -> Self {
ChasePrimitive::Nothing
}
}
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
#[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "capture", derive(Serialize))]
@ -34,6 +49,7 @@ pub struct FrameBuilderConfig {
pub default_font_render_mode: FontRenderMode, pub default_font_render_mode: FontRenderMode,
pub dual_source_blending_is_supported: bool, pub dual_source_blending_is_supported: bool,
pub dual_source_blending_is_enabled: bool, pub dual_source_blending_is_enabled: bool,
pub chase_primitive: ChasePrimitive,
} }
/// A builder structure for `tiling::Frame` /// A builder structure for `tiling::Frame`
@ -56,14 +72,14 @@ pub struct FrameBuildingContext<'a> {
pub pipelines: &'a FastHashMap<PipelineId, Arc<ScenePipeline>>, pub pipelines: &'a FastHashMap<PipelineId, Arc<ScenePipeline>>,
pub screen_rect: DeviceIntRect, pub screen_rect: DeviceIntRect,
pub clip_scroll_tree: &'a ClipScrollTree, pub clip_scroll_tree: &'a ClipScrollTree,
pub node_data: &'a [ClipScrollNodeData], pub transforms: &'a [TransformData],
pub max_local_clip: LayoutRect,
} }
pub struct FrameBuildingState<'a> { pub struct FrameBuildingState<'a> {
pub render_tasks: &'a mut RenderTaskTree, pub render_tasks: &'a mut RenderTaskTree,
pub profile_counters: &'a mut FrameProfileCounters, pub profile_counters: &'a mut FrameProfileCounters,
pub clip_store: &'a mut ClipStore, pub clip_store: &'a mut ClipStore,
pub local_clip_rects: &'a mut Vec<LayoutRect>,
pub resource_cache: &'a mut ResourceCache, pub resource_cache: &'a mut ResourceCache,
pub gpu_cache: &'a mut GpuCache, pub gpu_cache: &'a mut GpuCache,
pub special_render_passes: &'a mut SpecialRenderPasses, pub special_render_passes: &'a mut SpecialRenderPasses,
@ -99,19 +115,19 @@ impl PictureState {
pub struct PrimitiveRunContext<'a> { pub struct PrimitiveRunContext<'a> {
pub clip_chain: &'a ClipChain, pub clip_chain: &'a ClipChain,
pub scroll_node: &'a ClipScrollNode, pub scroll_node: &'a ClipScrollNode,
pub clip_chain_rect_index: ClipChainRectIndex, pub local_clip_rect: LayoutRect,
} }
impl<'a> PrimitiveRunContext<'a> { impl<'a> PrimitiveRunContext<'a> {
pub fn new( pub fn new(
clip_chain: &'a ClipChain, clip_chain: &'a ClipChain,
scroll_node: &'a ClipScrollNode, scroll_node: &'a ClipScrollNode,
clip_chain_rect_index: ClipChainRectIndex, local_clip_rect: LayoutRect,
) -> Self { ) -> Self {
PrimitiveRunContext { PrimitiveRunContext {
clip_chain, clip_chain,
scroll_node, scroll_node,
clip_chain_rect_index, local_clip_rect,
} }
} }
} }
@ -132,6 +148,7 @@ impl FrameBuilder {
default_font_render_mode: FontRenderMode::Mono, default_font_render_mode: FontRenderMode::Mono,
dual_source_blending_is_enabled: true, dual_source_blending_is_enabled: true,
dual_source_blending_is_supported: false, dual_source_blending_is_supported: false,
chase_primitive: ChasePrimitive::Nothing,
}, },
} }
} }
@ -169,8 +186,7 @@ impl FrameBuilder {
profile_counters: &mut FrameProfileCounters, profile_counters: &mut FrameProfileCounters,
device_pixel_scale: DevicePixelScale, device_pixel_scale: DevicePixelScale,
scene_properties: &SceneProperties, scene_properties: &SceneProperties,
local_clip_rects: &mut Vec<LayoutRect>, transforms: &[TransformData],
node_data: &[ClipScrollNodeData],
) -> Option<RenderTaskId> { ) -> Option<RenderTaskId> {
profile_scope!("cull"); profile_scope!("cull");
@ -187,6 +203,8 @@ impl FrameBuilder {
.expect("No display list?") .expect("No display list?")
.display_list; .display_list;
const MAX_CLIP_COORD: f32 = 1.0e9;
let frame_context = FrameBuildingContext { let frame_context = FrameBuildingContext {
scene_id: self.scene_id, scene_id: self.scene_id,
device_pixel_scale, device_pixel_scale,
@ -194,14 +212,17 @@ impl FrameBuilder {
pipelines, pipelines,
screen_rect: self.screen_rect.to_i32(), screen_rect: self.screen_rect.to_i32(),
clip_scroll_tree, clip_scroll_tree,
node_data, transforms,
max_local_clip: LayoutRect::new(
LayoutPoint::new(-MAX_CLIP_COORD, -MAX_CLIP_COORD),
LayoutSize::new(2.0 * MAX_CLIP_COORD, 2.0 * MAX_CLIP_COORD),
),
}; };
let mut frame_state = FrameBuildingState { let mut frame_state = FrameBuildingState {
render_tasks, render_tasks,
profile_counters, profile_counters,
clip_store: &mut self.clip_store, clip_store: &mut self.clip_store,
local_clip_rects,
resource_cache, resource_cache,
gpu_cache, gpu_cache,
special_render_passes, special_render_passes,
@ -301,20 +322,13 @@ impl FrameBuilder {
resource_cache.begin_frame(frame_id); resource_cache.begin_frame(frame_id);
gpu_cache.begin_frame(); gpu_cache.begin_frame();
let mut node_data = Vec::with_capacity(clip_scroll_tree.nodes.len()); let transform_palette = clip_scroll_tree.update_tree(
let total_prim_runs =
self.prim_store.pictures.iter().fold(1, |count, pic| count + pic.runs.len());
let mut clip_chain_local_clip_rects = Vec::with_capacity(total_prim_runs);
clip_chain_local_clip_rects.push(LayoutRect::max_rect());
clip_scroll_tree.update_tree(
&self.screen_rect.to_i32(), &self.screen_rect.to_i32(),
device_pixel_scale, device_pixel_scale,
&mut self.clip_store, &mut self.clip_store,
resource_cache, resource_cache,
gpu_cache, gpu_cache,
pan, pan,
&mut node_data,
scene_properties, scene_properties,
); );
@ -335,8 +349,7 @@ impl FrameBuilder {
&mut profile_counters, &mut profile_counters,
device_pixel_scale, device_pixel_scale,
scene_properties, scene_properties,
&mut clip_chain_local_clip_rects, &transform_palette.transforms,
&node_data,
); );
resource_cache.block_until_all_resources_added(gpu_cache, resource_cache.block_until_all_resources_added(gpu_cache,
@ -369,6 +382,7 @@ impl FrameBuilder {
let mut deferred_resolves = vec![]; let mut deferred_resolves = vec![];
let mut has_texture_cache_tasks = false; let mut has_texture_cache_tasks = false;
let mut prim_headers = PrimitiveHeaders::new();
let use_dual_source_blending = self.config.dual_source_blending_is_enabled && let use_dual_source_blending = self.config.dual_source_blending_is_enabled &&
self.config.dual_source_blending_is_supported; self.config.dual_source_blending_is_supported;
@ -379,7 +393,7 @@ impl FrameBuilder {
resource_cache, resource_cache,
clip_scroll_tree, clip_scroll_tree,
use_dual_source_blending, use_dual_source_blending,
node_data: &node_data, transforms: &transform_palette,
}; };
pass.build( pass.build(
@ -388,6 +402,7 @@ impl FrameBuilder {
&mut render_tasks, &mut render_tasks,
&mut deferred_resolves, &mut deferred_resolves,
&self.clip_store, &self.clip_store,
&mut prim_headers,
); );
if let RenderPassKind::OffScreen { ref texture_cache, .. } = pass.kind { if let RenderPassKind::OffScreen { ref texture_cache, .. } = pass.kind {
@ -409,13 +424,13 @@ impl FrameBuilder {
layer, layer,
profile_counters, profile_counters,
passes, passes,
node_data, transform_palette: transform_palette.transforms,
clip_chain_local_clip_rects,
render_tasks, render_tasks,
deferred_resolves, deferred_resolves,
gpu_cache_frame_id, gpu_cache_frame_id,
has_been_rendered: false, has_been_rendered: false,
has_texture_cache_tasks, has_texture_cache_tasks,
prim_headers,
} }
} }

Просмотреть файл

@ -2,29 +2,25 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use api::{DevicePoint, DeviceSize, DeviceRect, LayoutToWorldTransform}; use api::{DevicePoint, DeviceSize, DeviceRect, LayoutRect, LayoutToWorldTransform};
use api::{PremultipliedColorF, WorldToLayoutTransform}; use api::{PremultipliedColorF, WorldToLayoutTransform};
use clip_scroll_tree::TransformIndex;
use gpu_cache::{GpuCacheAddress, GpuDataRequest}; use gpu_cache::{GpuCacheAddress, GpuDataRequest};
use prim_store::{VECS_PER_SEGMENT, EdgeAaSegmentMask}; use prim_store::{EdgeAaSegmentMask};
use render_task::RenderTaskAddress; use render_task::RenderTaskAddress;
use renderer::MAX_VERTEX_TEXTURE_WIDTH; use util::{MatrixHelpers, TransformedRectKind};
// Contains type that must exactly match the same structures declared in GLSL. // Contains type that must exactly match the same structures declared in GLSL.
const INT_BITS: usize = 31; //TODO: convert to unsigned
const CLIP_CHAIN_RECT_BITS: usize = 22;
const SEGMENT_BITS: usize = INT_BITS - CLIP_CHAIN_RECT_BITS;
// The guard ensures (at compile time) that the designated number of bits cover
// the maximum supported segment count for the texture width.
const _SEGMENT_GUARD: usize = (1 << SEGMENT_BITS) * VECS_PER_SEGMENT - MAX_VERTEX_TEXTURE_WIDTH;
const EDGE_FLAG_BITS: usize = 4;
const BRUSH_FLAG_BITS: usize = 4;
const CLIP_SCROLL_INDEX_BITS: usize = INT_BITS - EDGE_FLAG_BITS - BRUSH_FLAG_BITS;
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
#[repr(C)] #[repr(C)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct ZBufferId(i32); pub struct ZBufferId(i32);
#[derive(Debug)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct ZBufferIdGenerator { pub struct ZBufferIdGenerator {
next: i32, next: i32,
} }
@ -119,7 +115,7 @@ pub struct BorderInstance {
#[repr(C)] #[repr(C)]
pub struct ClipMaskInstance { pub struct ClipMaskInstance {
pub render_task_address: RenderTaskAddress, pub render_task_address: RenderTaskAddress,
pub scroll_node_data_index: ClipScrollNodeIndex, pub transform_id: TransformPaletteId,
pub segment: i32, pub segment: i32,
pub clip_data_address: GpuCacheAddress, pub clip_data_address: GpuCacheAddress,
pub resource_address: GpuCacheAddress, pub resource_address: GpuCacheAddress,
@ -135,50 +131,124 @@ pub struct ClipMaskBorderCornerDotDash {
pub dot_dash_data: [f32; 8], pub dot_dash_data: [f32; 8],
} }
// 32 bytes per instance should be enough for anyone! // 16 bytes per instance should be enough for anyone!
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
#[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))] #[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct PrimitiveInstance { pub struct PrimitiveInstance {
data: [i32; 8], data: [i32; 4],
}
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct PrimitiveHeaderIndex(pub i32);
#[derive(Debug)]
#[repr(C)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct PrimitiveHeaders {
// The integer-type headers for a primitive.
pub headers_int: Vec<PrimitiveHeaderI>,
// The float-type headers for a primitive.
pub headers_float: Vec<PrimitiveHeaderF>,
// Used to generated a unique z-buffer value per primitive.
pub z_generator: ZBufferIdGenerator,
}
impl PrimitiveHeaders {
pub fn new() -> PrimitiveHeaders {
PrimitiveHeaders {
headers_int: Vec::new(),
headers_float: Vec::new(),
z_generator: ZBufferIdGenerator::new(),
}
}
// Add a new primitive header.
pub fn push(
&mut self,
prim_header: &PrimitiveHeader,
user_data: [i32; 3],
) -> PrimitiveHeaderIndex {
debug_assert_eq!(self.headers_int.len(), self.headers_float.len());
let id = self.headers_float.len();
self.headers_float.push(PrimitiveHeaderF {
local_rect: prim_header.local_rect,
local_clip_rect: prim_header.local_clip_rect,
});
self.headers_int.push(PrimitiveHeaderI {
z: self.z_generator.next(),
task_address: prim_header.task_address,
specific_prim_address: prim_header.specific_prim_address.as_int(),
clip_task_address: prim_header.clip_task_address,
transform_id: prim_header.transform_id,
user_data,
});
PrimitiveHeaderIndex(id as i32)
}
}
// This is a convenience type used to make it easier to pass
// the common parts around during batching.
pub struct PrimitiveHeader {
pub local_rect: LayoutRect,
pub local_clip_rect: LayoutRect,
pub task_address: RenderTaskAddress,
pub specific_prim_address: GpuCacheAddress,
pub clip_task_address: RenderTaskAddress,
pub transform_id: TransformPaletteId,
}
// f32 parts of a primitive header
#[derive(Debug)]
#[repr(C)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct PrimitiveHeaderF {
pub local_rect: LayoutRect,
pub local_clip_rect: LayoutRect,
}
// i32 parts of a primitive header
// TODO(gw): Compress parts of these down to u16
#[derive(Debug)]
#[repr(C)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct PrimitiveHeaderI {
pub z: ZBufferId,
pub task_address: RenderTaskAddress,
pub specific_prim_address: i32,
pub clip_task_address: RenderTaskAddress,
pub transform_id: TransformPaletteId,
pub user_data: [i32; 3],
} }
pub struct GlyphInstance { pub struct GlyphInstance {
pub specific_prim_address: GpuCacheAddress, pub prim_header_index: PrimitiveHeaderIndex,
pub task_address: RenderTaskAddress,
pub clip_task_address: RenderTaskAddress,
pub clip_chain_rect_index: ClipChainRectIndex,
pub scroll_id: ClipScrollNodeIndex,
pub z: ZBufferId,
} }
impl GlyphInstance { impl GlyphInstance {
pub fn new( pub fn new(
specific_prim_address: GpuCacheAddress, prim_header_index: PrimitiveHeaderIndex,
task_address: RenderTaskAddress,
clip_task_address: RenderTaskAddress,
clip_chain_rect_index: ClipChainRectIndex,
scroll_id: ClipScrollNodeIndex,
z: ZBufferId,
) -> Self { ) -> Self {
GlyphInstance { GlyphInstance {
specific_prim_address, prim_header_index,
task_address,
clip_task_address,
clip_chain_rect_index,
scroll_id,
z,
} }
} }
// TODO(gw): Some of these fields can be moved to the primitive
// header since they are constant, and some can be
// compressed to a smaller size.
pub fn build(&self, data0: i32, data1: i32, data2: i32) -> PrimitiveInstance { pub fn build(&self, data0: i32, data1: i32, data2: i32) -> PrimitiveInstance {
PrimitiveInstance { PrimitiveInstance {
data: [ data: [
self.specific_prim_address.as_int(), self.prim_header_index.0 as i32,
self.task_address.0 as i32 | (self.clip_task_address.0 as i32) << 16,
self.clip_chain_rect_index.0 as i32,
self.scroll_id.0 as i32,
self.z.0,
data0, data0,
data1, data1,
data2, data2,
@ -218,10 +288,6 @@ impl From<SplitCompositeInstance> for PrimitiveInstance {
instance.src_task_address.0 as i32, instance.src_task_address.0 as i32,
instance.polygons_address.as_int(), instance.polygons_address.as_int(),
instance.z.0, instance.z.0,
0,
0,
0,
0,
], ],
} }
} }
@ -243,80 +309,141 @@ bitflags! {
} }
} }
// TODO(gw): While we are converting things over, we // TODO(gw): Some of these fields can be moved to the primitive
// need to have the instance be the same // header since they are constant, and some can be
// size as an old PrimitiveInstance. In the // compressed to a smaller size.
// future, we can compress this vertex
// format a lot - e.g. z, render task
// addresses etc can reasonably become
// a u16 type.
#[repr(C)] #[repr(C)]
pub struct BrushInstance { pub struct BrushInstance {
pub picture_address: RenderTaskAddress, pub prim_header_index: PrimitiveHeaderIndex,
pub prim_address: GpuCacheAddress,
pub clip_chain_rect_index: ClipChainRectIndex,
pub scroll_id: ClipScrollNodeIndex,
pub clip_task_address: RenderTaskAddress, pub clip_task_address: RenderTaskAddress,
pub z: ZBufferId,
pub segment_index: i32, pub segment_index: i32,
pub edge_flags: EdgeAaSegmentMask, pub edge_flags: EdgeAaSegmentMask,
pub brush_flags: BrushFlags, pub brush_flags: BrushFlags,
pub user_data: [i32; 3],
} }
impl From<BrushInstance> for PrimitiveInstance { impl From<BrushInstance> for PrimitiveInstance {
fn from(instance: BrushInstance) -> Self { fn from(instance: BrushInstance) -> Self {
debug_assert_eq!(0, instance.clip_chain_rect_index.0 >> CLIP_CHAIN_RECT_BITS);
debug_assert_eq!(0, instance.scroll_id.0 >> CLIP_SCROLL_INDEX_BITS);
debug_assert_eq!(0, instance.segment_index >> SEGMENT_BITS);
PrimitiveInstance { PrimitiveInstance {
data: [ data: [
instance.picture_address.0 as i32 | (instance.clip_task_address.0 as i32) << 16, instance.prim_header_index.0,
instance.prim_address.as_int(), instance.clip_task_address.0 as i32,
instance.clip_chain_rect_index.0 as i32 | (instance.segment_index << CLIP_CHAIN_RECT_BITS), instance.segment_index |
instance.z.0, ((instance.edge_flags.bits() as i32) << 16) |
instance.scroll_id.0 as i32 | ((instance.brush_flags.bits() as i32) << 24),
((instance.edge_flags.bits() as i32) << CLIP_SCROLL_INDEX_BITS) | 0,
((instance.brush_flags.bits() as i32) << (CLIP_SCROLL_INDEX_BITS + EDGE_FLAG_BITS)),
instance.user_data[0],
instance.user_data[1],
instance.user_data[2],
] ]
} }
} }
} }
// Represents the information about a transform palette
// entry that is passed to shaders. It includes an index
// into the transform palette, and a set of flags. The
// only flag currently used determines whether the
// transform is axis-aligned (and this should have
// pixel snapping applied).
#[derive(Copy, Debug, Clone, PartialEq)] #[derive(Copy, Debug, Clone, PartialEq)]
#[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))] #[cfg_attr(feature = "replay", derive(Deserialize))]
#[repr(C)] #[repr(C)]
pub struct ClipScrollNodeIndex(pub u32); pub struct TransformPaletteId(pub u32);
#[derive(Debug)] impl TransformPaletteId {
#[cfg_attr(feature = "capture", derive(Serialize))] // Get the palette ID for an identity transform.
#[cfg_attr(feature = "replay", derive(Deserialize))] pub fn identity() -> TransformPaletteId {
#[repr(C)] TransformPaletteId(0)
pub struct ClipScrollNodeData { }
pub transform: LayoutToWorldTransform,
pub inv_transform: WorldToLayoutTransform,
pub transform_kind: f32,
pub padding: [f32; 3],
}
impl ClipScrollNodeData { // Extract the transform kind from the id.
pub fn invalid() -> Self { pub fn transform_kind(&self) -> TransformedRectKind {
ClipScrollNodeData { if (self.0 >> 24) == 0 {
transform: LayoutToWorldTransform::identity(), TransformedRectKind::AxisAligned
inv_transform: WorldToLayoutTransform::identity(), } else {
transform_kind: 0.0, TransformedRectKind::Complex
padding: [0.0; 3],
} }
} }
} }
#[derive(Copy, Debug, Clone, PartialEq)] // The GPU data payload for a transform palette entry.
#[derive(Debug)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[repr(C)] #[repr(C)]
pub struct ClipChainRectIndex(pub usize); pub struct TransformData {
pub transform: LayoutToWorldTransform,
pub inv_transform: WorldToLayoutTransform,
}
impl TransformData {
pub fn invalid() -> Self {
TransformData {
transform: LayoutToWorldTransform::identity(),
inv_transform: WorldToLayoutTransform::identity(),
}
}
}
// Extra data stored about each transform palette entry.
pub struct TransformMetadata {
pub transform_kind: TransformedRectKind,
}
// Stores a contiguous list of TransformData structs, that
// are ready for upload to the GPU.
// TODO(gw): For now, this only stores the complete local
// to world transform for each spatial node. In
// the future, the transform palette will support
// specifying a coordinate system that the transform
// should be relative to.
pub struct TransformPalette {
pub transforms: Vec<TransformData>,
metadata: Vec<TransformMetadata>,
}
impl TransformPalette {
pub fn new(spatial_node_count: usize) -> TransformPalette {
TransformPalette {
transforms: Vec::with_capacity(spatial_node_count),
metadata: Vec::with_capacity(spatial_node_count),
}
}
// Set the local -> world transform for a given spatial
// node in the transform palette.
pub fn set(
&mut self,
index: TransformIndex,
data: TransformData,
) {
let index = index.0 as usize;
// Pad the vectors out if they are not long enough to
// account for this index. This can occur, for instance,
// when we stop recursing down the CST due to encountering
// a node with an invalid transform.
while index >= self.transforms.len() {
self.transforms.push(TransformData::invalid());
self.metadata.push(TransformMetadata {
transform_kind: TransformedRectKind::AxisAligned,
});
}
// Store the transform itself, along with metadata about it.
self.metadata[index] = TransformMetadata {
transform_kind: data.transform.transform_kind(),
};
self.transforms[index] = data;
}
// Get a transform palette id for the given spatial node.
// TODO(gw): In the future, it will be possible to specify
// a coordinate system id here, to allow retrieving
// transforms in the local space of a given spatial node.
pub fn get_id(&self, index: TransformIndex) -> TransformPaletteId {
let transform_kind = self.metadata[index.0 as usize].transform_kind as u32;
TransformPaletteId(index.0 | (transform_kind << 24))
}
}
// Texture cache resources can be either a simple rect, or define // Texture cache resources can be either a simple rect, or define
// a polygon within a rect by specifying a UV coordinate for each // a polygon within a rect by specifying a UV coordinate for each

Просмотреть файл

@ -182,6 +182,7 @@ pub extern crate webrender_api;
#[doc(hidden)] #[doc(hidden)]
pub use device::{build_shader_strings, ReadPixelsFormat, UploadMethod, VertexUsageHint}; pub use device::{build_shader_strings, ReadPixelsFormat, UploadMethod, VertexUsageHint};
pub use device::{ProgramBinary, ProgramCache, ProgramCacheObserver, ProgramSources}; pub use device::{ProgramBinary, ProgramCache, ProgramCacheObserver, ProgramSources};
pub use frame_builder::ChasePrimitive;
pub use renderer::{AsyncPropertySampler, CpuProfile, DebugFlags, OutputImageHandler, RendererKind}; pub use renderer::{AsyncPropertySampler, CpuProfile, DebugFlags, OutputImageHandler, RendererKind};
pub use renderer::{ExternalImage, ExternalImageHandler, ExternalImageSource, GpuProfile}; pub use renderer::{ExternalImage, ExternalImageHandler, ExternalImageSource, GpuProfile};
pub use renderer::{GraphicsApi, GraphicsApiInfo, PipelineInfo, Renderer, RendererOptions}; pub use renderer::{GraphicsApi, GraphicsApiInfo, PipelineInfo, Renderer, RendererOptions};

Просмотреть файл

@ -276,7 +276,7 @@ impl PicturePrimitive {
self.can_draw_directly_to_parent_surface() self.can_draw_directly_to_parent_surface()
} }
pub fn prepare_for_render_inner( pub fn prepare_for_render(
&mut self, &mut self,
prim_index: PrimitiveIndex, prim_index: PrimitiveIndex,
prim_metadata: &mut PrimitiveMetadata, prim_metadata: &mut PrimitiveMetadata,
@ -489,16 +489,9 @@ impl PicturePrimitive {
// that writes a brush primitive header. // that writes a brush primitive header.
// Basic brush primitive header is (see end of prepare_prim_for_render_inner in prim_store.rs) // Basic brush primitive header is (see end of prepare_prim_for_render_inner in prim_store.rs)
// local_rect
// clip_rect
// [brush specific data] // [brush specific data]
// [segment_rect, segment data] // [segment_rect, segment data]
let shadow_rect = prim_metadata.local_rect.translate(&offset); let shadow_rect = prim_metadata.local_rect.translate(&offset);
let shadow_clip_rect = prim_metadata.local_clip_rect.translate(&offset);
// local_rect, clip_rect
request.push(shadow_rect);
request.push(shadow_clip_rect);
// ImageBrush colors // ImageBrush colors
request.push(color.premultiplied()); request.push(color.premultiplied());
@ -592,27 +585,6 @@ impl PicturePrimitive {
} }
} }
} }
pub fn prepare_for_render(
&mut self,
prim_index: PrimitiveIndex,
prim_metadata: &mut PrimitiveMetadata,
prim_run_context: &PrimitiveRunContext,
pic_state_for_children: PictureState,
pic_state: &mut PictureState,
frame_context: &FrameBuildingContext,
frame_state: &mut FrameBuildingState,
) {
self.prepare_for_render_inner(
prim_index,
prim_metadata,
prim_run_context,
pic_state_for_children,
pic_state,
frame_context,
frame_state,
);
}
} }
// Calculate a single screen-space UV for a picture. // Calculate a single screen-space UV for a picture.

Просмотреть файл

@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use api::{AlphaType, BorderRadius, BoxShadowClipMode, BuiltDisplayList, ClipMode, ColorF, ComplexClipRegion}; use api::{AlphaType, BorderRadius, BoxShadowClipMode, BuiltDisplayList, ClipMode, ColorF};
use api::{DeviceIntRect, DeviceIntSize, DevicePixelScale, Epoch, ExtendMode}; use api::{DeviceIntRect, DeviceIntSize, DevicePixelScale, Epoch, ExtendMode};
use api::{FilterOp, GlyphInstance, GradientStop, ImageKey, ImageRendering, ItemRange, ItemTag, TileOffset}; use api::{FilterOp, GlyphInstance, GradientStop, ImageKey, ImageRendering, ItemRange, ItemTag, TileOffset};
use api::{GlyphRasterSpace, LayoutPoint, LayoutRect, LayoutSize, LayoutToWorldTransform, LayoutVector2D}; use api::{GlyphRasterSpace, LayoutPoint, LayoutRect, LayoutSize, LayoutToWorldTransform, LayoutVector2D};
@ -20,7 +20,7 @@ use frame_builder::PrimitiveRunContext;
use glyph_rasterizer::{FontInstance, FontTransform, GlyphKey, FONT_SIZE_LIMIT}; use glyph_rasterizer::{FontInstance, FontTransform, GlyphKey, FONT_SIZE_LIMIT};
use gpu_cache::{GpuBlockData, GpuCache, GpuCacheAddress, GpuCacheHandle, GpuDataRequest, use gpu_cache::{GpuBlockData, GpuCache, GpuCacheAddress, GpuCacheHandle, GpuDataRequest,
ToGpuBlocks}; ToGpuBlocks};
use gpu_types::{BrushFlags, ClipChainRectIndex}; use gpu_types::BrushFlags;
use image::{for_each_tile, for_each_repetition}; use image::{for_each_tile, for_each_repetition};
use picture::{PictureCompositeMode, PictureId, PicturePrimitive}; use picture::{PictureCompositeMode, PictureId, PicturePrimitive};
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
@ -50,7 +50,7 @@ impl ScrollNodeAndClipChain {
pub fn new( pub fn new(
scroll_node_id: ClipScrollNodeIndex, scroll_node_id: ClipScrollNodeIndex,
clip_chain_index: ClipChainIndex clip_chain_index: ClipChainIndex
) -> ScrollNodeAndClipChain { ) -> Self {
ScrollNodeAndClipChain { scroll_node_id, clip_chain_index } ScrollNodeAndClipChain { scroll_node_id, clip_chain_index }
} }
} }
@ -62,6 +62,17 @@ pub struct PrimitiveRun {
pub clip_and_scroll: ScrollNodeAndClipChain, pub clip_and_scroll: ScrollNodeAndClipChain,
} }
impl PrimitiveRun {
pub fn is_chasing(&self, index: Option<PrimitiveIndex>) -> bool {
match index {
Some(id) if cfg!(debug_assertions) => {
self.base_prim_index <= id && id.0 < self.base_prim_index.0 + self.count
}
_ => false,
}
}
}
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct PrimitiveOpacity { pub struct PrimitiveOpacity {
pub is_opaque: bool, pub is_opaque: bool,
@ -174,7 +185,11 @@ pub struct PrimitiveMetadata {
// storing them here. // storing them here.
pub local_rect: LayoutRect, pub local_rect: LayoutRect,
pub local_clip_rect: LayoutRect, pub local_clip_rect: LayoutRect,
pub clip_chain_rect_index: ClipChainRectIndex,
// The current combined local clip for this primitive, from
// the primitive local clip above and the current clip chain.
pub combined_local_clip_rect: LayoutRect,
pub is_backface_visible: bool, pub is_backface_visible: bool,
pub screen_rect: Option<ScreenRect>, pub screen_rect: Option<ScreenRect>,
@ -234,11 +249,15 @@ pub struct VisibleImageTile {
pub tile_offset: TileOffset, pub tile_offset: TileOffset,
pub handle: GpuCacheHandle, pub handle: GpuCacheHandle,
pub edge_flags: EdgeAaSegmentMask, pub edge_flags: EdgeAaSegmentMask,
pub local_rect: LayoutRect,
pub local_clip_rect: LayoutRect,
} }
#[derive(Debug)] #[derive(Debug)]
pub struct VisibleGradientTile { pub struct VisibleGradientTile {
pub handle: GpuCacheHandle, pub handle: GpuCacheHandle,
pub local_rect: LayoutRect,
pub local_clip_rect: LayoutRect,
} }
#[derive(Debug)] #[derive(Debug)]
@ -418,14 +437,14 @@ impl BrushPrimitive {
pub fn new( pub fn new(
kind: BrushKind, kind: BrushKind,
segment_desc: Option<BrushSegmentDescriptor>, segment_desc: Option<BrushSegmentDescriptor>,
) -> BrushPrimitive { ) -> Self {
BrushPrimitive { BrushPrimitive {
kind, kind,
segment_desc, segment_desc,
} }
} }
pub fn new_picture(pic_index: PictureIndex) -> BrushPrimitive { pub fn new_picture(pic_index: PictureIndex) -> Self {
BrushPrimitive { BrushPrimitive {
kind: BrushKind::Picture { kind: BrushKind::Picture {
pic_index, pic_index,
@ -719,7 +738,6 @@ impl<'a> GradientGpuBlockBuilder<'a> {
self.fill_colors(cur_idx, GRADIENT_DATA_TABLE_END, &PremultipliedColorF::WHITE, &cur_color, &mut entries); self.fill_colors(cur_idx, GRADIENT_DATA_TABLE_END, &PremultipliedColorF::WHITE, &cur_color, &mut entries);
} }
// Fill in the last entry with the last color stop // Fill in the last entry with the last color stop
self.fill_colors( self.fill_colors(
GRADIENT_DATA_LAST_STOP, GRADIENT_DATA_LAST_STOP,
@ -739,12 +757,12 @@ impl<'a> GradientGpuBlockBuilder<'a> {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct TextRunPrimitiveCpu { pub struct TextRunPrimitiveCpu {
pub font: FontInstance, pub specified_font: FontInstance,
pub used_font: FontInstance,
pub offset: LayoutVector2D, pub offset: LayoutVector2D,
pub glyph_range: ItemRange<GlyphInstance>, pub glyph_range: ItemRange<GlyphInstance>,
pub glyph_keys: Vec<GlyphKey>, pub glyph_keys: Vec<GlyphKey>,
pub glyph_gpu_blocks: Vec<GpuBlockData>, pub glyph_gpu_blocks: Vec<GpuBlockData>,
pub glyph_transform: (DevicePixelScale, FontTransform),
pub shadow: bool, pub shadow: bool,
pub glyph_raster_space: GlyphRasterSpace, pub glyph_raster_space: GlyphRasterSpace,
} }
@ -759,60 +777,97 @@ impl TextRunPrimitiveCpu {
glyph_raster_space: GlyphRasterSpace, glyph_raster_space: GlyphRasterSpace,
) -> Self { ) -> Self {
TextRunPrimitiveCpu { TextRunPrimitiveCpu {
font, specified_font: font.clone(),
used_font: font,
offset, offset,
glyph_range, glyph_range,
glyph_keys, glyph_keys,
glyph_gpu_blocks: Vec::new(), glyph_gpu_blocks: Vec::new(),
glyph_transform: (DevicePixelScale::new(1.0), FontTransform::identity()),
shadow, shadow,
glyph_raster_space, glyph_raster_space,
} }
} }
pub fn get_font( pub fn update_font_instance(
&self, &mut self,
device_pixel_scale: DevicePixelScale, device_pixel_scale: DevicePixelScale,
transform: LayoutToWorldTransform, transform: &LayoutToWorldTransform,
) -> FontInstance { allow_subpixel_aa: bool,
let mut font = self.font.clone(); ) -> bool {
font.size = font.size.scale_by(device_pixel_scale.0); // Get the current font size in device pixels
let device_font_size = self.specified_font.size.scale_by(device_pixel_scale.0);
// Determine if rasterizing glyphs in local or screen space.
// Only support transforms that can be coerced to simple 2D transforms. // Only support transforms that can be coerced to simple 2D transforms.
if transform.has_perspective_component() || let transform_glyphs = if transform.has_perspective_component() ||
!transform.has_2d_inverse() || !transform.has_2d_inverse() ||
// Font sizes larger than the limit need to be scaled, thus can't use subpixels. // Font sizes larger than the limit need to be scaled, thus can't use subpixels.
transform.exceeds_2d_scale(FONT_SIZE_LIMIT / font.size.to_f64_px()) || transform.exceeds_2d_scale(FONT_SIZE_LIMIT / device_font_size.to_f64_px()) ||
// Otherwise, ensure the font is rasterized in screen-space. // Otherwise, ensure the font is rasterized in screen-space.
self.glyph_raster_space != GlyphRasterSpace::Screen { self.glyph_raster_space != GlyphRasterSpace::Screen {
font.disable_subpixel_aa(); false
font.disable_subpixel_position();
} else { } else {
true
};
// Get the font transform matrix (skew / scale) from the complete transform.
let font_transform = if transform_glyphs {
// Quantize the transform to minimize thrashing of the glyph cache. // Quantize the transform to minimize thrashing of the glyph cache.
font.transform = FontTransform::from(&transform).quantize(); FontTransform::from(transform).quantize()
} else {
FontTransform::identity()
};
// If the transform or device size is different, then the caller of
// this method needs to know to rebuild the glyphs.
let cache_dirty =
self.used_font.transform != font_transform ||
self.used_font.size != device_font_size;
// Construct used font instance from the specified font instance
self.used_font = FontInstance {
transform: font_transform,
size: device_font_size,
..self.specified_font.clone()
};
// If subpixel AA is disabled due to the backing surface the glyphs
// are being drawn onto, disable it (unless we are using the
// specifial subpixel mode that estimates background color).
if !allow_subpixel_aa && self.specified_font.bg_color.a == 0 {
self.used_font.disable_subpixel_aa();
} }
font
// If using local space glyphs, we don't want subpixel AA
// or positioning.
if !transform_glyphs {
self.used_font.disable_subpixel_aa();
self.used_font.disable_subpixel_position();
}
cache_dirty
} }
fn prepare_for_render( fn prepare_for_render(
&mut self, &mut self,
device_pixel_scale: DevicePixelScale, device_pixel_scale: DevicePixelScale,
transform: LayoutToWorldTransform, transform: &LayoutToWorldTransform,
allow_subpixel_aa: bool, allow_subpixel_aa: bool,
display_list: &BuiltDisplayList, display_list: &BuiltDisplayList,
frame_building_state: &mut FrameBuildingState, frame_building_state: &mut FrameBuildingState,
) { ) {
if !allow_subpixel_aa && self.font.bg_color.a == 0 { let cache_dirty = self.update_font_instance(
self.font.disable_subpixel_aa(); device_pixel_scale,
} transform,
allow_subpixel_aa,
let font = self.get_font(device_pixel_scale, transform); );
// Cache the glyph positions, if not in the cache already. // Cache the glyph positions, if not in the cache already.
// TODO(gw): In the future, remove `glyph_instances` // TODO(gw): In the future, remove `glyph_instances`
// completely, and just reference the glyphs // completely, and just reference the glyphs
// directly from the display list. // directly from the display list.
if self.glyph_keys.is_empty() || self.glyph_transform != (device_pixel_scale, font.transform) { if self.glyph_keys.is_empty() || cache_dirty {
let subpx_dir = font.get_subpx_dir(); let subpx_dir = self.used_font.get_subpx_dir();
let src_glyphs = display_list.get(self.glyph_range); let src_glyphs = display_list.get(self.glyph_range);
// TODO(gw): If we support chunks() on AuxIter // TODO(gw): If we support chunks() on AuxIter
@ -820,7 +875,7 @@ impl TextRunPrimitiveCpu {
// be much simpler... // be much simpler...
let mut gpu_block = [0.0; 4]; let mut gpu_block = [0.0; 4];
for (i, src) in src_glyphs.enumerate() { for (i, src) in src_glyphs.enumerate() {
let world_offset = font.transform.transform(&src.point); let world_offset = self.used_font.transform.transform(&src.point);
let device_offset = device_pixel_scale.transform_point(&world_offset); let device_offset = device_pixel_scale.transform_point(&world_offset);
let key = GlyphKey::new(src.index, device_offset, subpx_dir); let key = GlyphKey::new(src.index, device_offset, subpx_dir);
self.glyph_keys.push(key); self.glyph_keys.push(key);
@ -842,12 +897,10 @@ impl TextRunPrimitiveCpu {
if (self.glyph_keys.len() & 1) != 0 { if (self.glyph_keys.len() & 1) != 0 {
self.glyph_gpu_blocks.push(gpu_block.into()); self.glyph_gpu_blocks.push(gpu_block.into());
} }
self.glyph_transform = (device_pixel_scale, font.transform);
} }
frame_building_state.resource_cache frame_building_state.resource_cache
.request_glyphs(font, .request_glyphs(self.used_font.clone(),
&self.glyph_keys, &self.glyph_keys,
frame_building_state.gpu_cache, frame_building_state.gpu_cache,
frame_building_state.render_tasks, frame_building_state.render_tasks,
@ -855,9 +908,9 @@ impl TextRunPrimitiveCpu {
} }
fn write_gpu_blocks(&self, request: &mut GpuDataRequest) { fn write_gpu_blocks(&self, request: &mut GpuDataRequest) {
request.push(ColorF::from(self.font.color).premultiplied()); request.push(ColorF::from(self.used_font.color).premultiplied());
// this is the only case where we need to provide plain color to GPU // this is the only case where we need to provide plain color to GPU
let bg_color = ColorF::from(self.font.bg_color); let bg_color = ColorF::from(self.used_font.bg_color);
request.push([bg_color.r, bg_color.g, bg_color.b, 1.0]); request.push([bg_color.r, bg_color.g, bg_color.b, 1.0]);
request.push([ request.push([
self.offset.x, self.offset.x,
@ -1071,7 +1124,7 @@ impl PrimitiveContainer {
pub fn is_visible(&self) -> bool { pub fn is_visible(&self) -> bool {
match *self { match *self {
PrimitiveContainer::TextRun(ref info) => { PrimitiveContainer::TextRun(ref info) => {
info.font.color.a > 0 info.specified_font.color.a > 0
} }
PrimitiveContainer::Brush(ref brush) => { PrimitiveContainer::Brush(ref brush) => {
match brush.kind { match brush.kind {
@ -1100,7 +1153,7 @@ impl PrimitiveContainer {
PrimitiveContainer::TextRun(ref info) => { PrimitiveContainer::TextRun(ref info) => {
let mut font = FontInstance { let mut font = FontInstance {
color: shadow.color.into(), color: shadow.color.into(),
..info.font.clone() ..info.specified_font.clone()
}; };
if shadow.blur_radius > 0.0 { if shadow.blur_radius > 0.0 {
font.disable_subpixel_aa(); font.disable_subpixel_aa();
@ -1146,6 +1199,9 @@ pub struct PrimitiveStore {
pub pictures: Vec<PicturePrimitive>, pub pictures: Vec<PicturePrimitive>,
next_picture_id: u64, next_picture_id: u64,
/// A primitive index to chase through debugging.
pub chase_id: Option<PrimitiveIndex>,
} }
impl PrimitiveStore { impl PrimitiveStore {
@ -1157,6 +1213,8 @@ impl PrimitiveStore {
pictures: Vec::new(), pictures: Vec::new(),
next_picture_id: 0, next_picture_id: 0,
chase_id: None,
} }
} }
@ -1168,6 +1226,8 @@ impl PrimitiveStore {
pictures: recycle_vec(self.pictures), pictures: recycle_vec(self.pictures),
next_picture_id: self.next_picture_id, next_picture_id: self.next_picture_id,
chase_id: self.chase_id,
} }
} }
@ -1213,7 +1273,7 @@ impl PrimitiveStore {
clip_task_id: None, clip_task_id: None,
local_rect: *local_rect, local_rect: *local_rect,
local_clip_rect: *local_clip_rect, local_clip_rect: *local_clip_rect,
clip_chain_rect_index: ClipChainRectIndex(0), combined_local_clip_rect: *local_clip_rect,
is_backface_visible, is_backface_visible,
screen_rect: None, screen_rect: None,
tag, tag,
@ -1495,7 +1555,7 @@ impl PrimitiveStore {
let transform = prim_run_context.scroll_node.world_content_transform.into(); let transform = prim_run_context.scroll_node.world_content_transform.into();
text.prepare_for_render( text.prepare_for_render(
frame_context.device_pixel_scale, frame_context.device_pixel_scale,
transform, &transform,
pic_context.allow_subpixel_aa, pic_context.allow_subpixel_aa,
pic_context.display_list, pic_context.display_list,
frame_state, frame_state,
@ -1644,7 +1704,9 @@ impl PrimitiveStore {
// Tighten the clip rect because decomposing the repeated image can // Tighten the clip rect because decomposing the repeated image can
// produce primitives that are partially covering the original image // produce primitives that are partially covering the original image
// rect and we want to clip these extra parts out. // rect and we want to clip these extra parts out.
let tight_clip_rect = metadata.local_clip_rect.intersection(&metadata.local_rect).unwrap(); let tight_clip_rect = metadata
.combined_local_clip_rect
.intersection(&metadata.local_rect).unwrap();
let visible_rect = compute_conservative_visible_rect( let visible_rect = compute_conservative_visible_rect(
prim_run_context, prim_run_context,
@ -1684,8 +1746,6 @@ impl PrimitiveStore {
let mut handle = GpuCacheHandle::new(); let mut handle = GpuCacheHandle::new();
if let Some(mut request) = frame_state.gpu_cache.request(&mut handle) { if let Some(mut request) = frame_state.gpu_cache.request(&mut handle) {
request.push(*tile_rect);
request.push(tight_clip_rect);
request.push(ColorF::new(1.0, 1.0, 1.0, opacity_binding.current).premultiplied()); request.push(ColorF::new(1.0, 1.0, 1.0, opacity_binding.current).premultiplied());
request.push(PremultipliedColorF::WHITE); request.push(PremultipliedColorF::WHITE);
request.push([tile_rect.size.width, tile_rect.size.height, 0.0, 0.0]); request.push([tile_rect.size.width, tile_rect.size.height, 0.0, 0.0]);
@ -1696,6 +1756,8 @@ impl PrimitiveStore {
tile_offset, tile_offset,
handle, handle,
edge_flags: tile_flags & edge_flags, edge_flags: tile_flags & edge_flags,
local_rect: *tile_rect,
local_clip_rect: tight_clip_rect,
}); });
} }
); );
@ -1789,9 +1851,7 @@ impl PrimitiveStore {
prim_run_context, prim_run_context,
frame_context, frame_context,
frame_state, frame_state,
&mut |rect, clip_rect, mut request| { &mut |rect, mut request| {
request.push(*rect);
request.push(*clip_rect);
request.push([ request.push([
center.x, center.x,
center.y, center.y,
@ -1841,9 +1901,7 @@ impl PrimitiveStore {
prim_run_context, prim_run_context,
frame_context, frame_context,
frame_state, frame_state,
&mut |rect, clip_rect, mut request| { &mut |rect, mut request| {
request.push(*rect);
request.push(*clip_rect);
request.push([ request.push([
start_point.x, start_point.x,
start_point.y, start_point.y,
@ -1895,10 +1953,6 @@ impl PrimitiveStore {
// Mark this GPU resource as required for this frame. // Mark this GPU resource as required for this frame.
if let Some(mut request) = frame_state.gpu_cache.request(&mut metadata.gpu_location) { if let Some(mut request) = frame_state.gpu_cache.request(&mut metadata.gpu_location) {
// has to match VECS_PER_BRUSH_PRIM
request.push(metadata.local_rect);
request.push(metadata.local_clip_rect);
match metadata.prim_kind { match metadata.prim_kind {
PrimitiveKind::TextRun => { PrimitiveKind::TextRun => {
let text = &self.cpu_text_runs[metadata.cpu_prim_index.0]; let text = &self.cpu_text_runs[metadata.cpu_prim_index.0];
@ -2042,11 +2096,11 @@ impl PrimitiveStore {
// node and the primitive, we need to get the clip rect in the // node and the primitive, we need to get the clip rect in the
// local space of the primitive, in order to generate correct // local space of the primitive, in order to generate correct
// local segments. // local segments.
let local_clip_rect = if clip_item.scroll_node_data_index == prim_run_context.scroll_node.node_data_index { let local_clip_rect = if clip_item.transform_index == prim_run_context.scroll_node.transform_index {
local_clip_rect local_clip_rect
} else { } else {
let clip_transform = frame_context let clip_transform = frame_context
.node_data[clip_item.scroll_node_data_index.0 as usize] .transforms[clip_item.transform_index.0 as usize]
.transform; .transform;
let prim_transform = &prim_run_context.scroll_node.world_content_transform; let prim_transform = &prim_run_context.scroll_node.world_content_transform;
let relative_transform = prim_transform let relative_transform = prim_transform
@ -2193,12 +2247,19 @@ impl PrimitiveStore {
frame_context: &FrameBuildingContext, frame_context: &FrameBuildingContext,
frame_state: &mut FrameBuildingState, frame_state: &mut FrameBuildingState,
) -> bool { ) -> bool {
if cfg!(debug_assertions) && Some(prim_index) == self.chase_id {
println!("\tupdating clip task with screen rect {:?}", prim_screen_rect);
}
// Reset clips from previous frames since we may clip differently each frame. // Reset clips from previous frames since we may clip differently each frame.
self.reset_clip_task(prim_index); self.reset_clip_task(prim_index);
let prim_screen_rect = match prim_screen_rect.intersection(&frame_context.screen_rect) { let prim_screen_rect = match prim_screen_rect.intersection(&frame_context.screen_rect) {
Some(rect) => rect, Some(rect) => rect,
None => { None => {
if cfg!(debug_assertions) && Some(prim_index) == self.chase_id {
println!("\tculled by the intersection with frame rect {:?}",
frame_context.screen_rect);
}
self.cpu_metadata[prim_index.0].screen_rect = None; self.cpu_metadata[prim_index.0].screen_rect = None;
return false; return false;
} }
@ -2207,6 +2268,9 @@ impl PrimitiveStore {
let mut combined_outer_rect = let mut combined_outer_rect =
prim_screen_rect.intersection(&prim_run_context.clip_chain.combined_outer_screen_rect); prim_screen_rect.intersection(&prim_run_context.clip_chain.combined_outer_screen_rect);
let clip_chain = prim_run_context.clip_chain.nodes.clone(); let clip_chain = prim_run_context.clip_chain.nodes.clone();
if cfg!(debug_assertions) && Some(prim_index) == self.chase_id {
println!("\tbase combined outer rect {:?}", combined_outer_rect);
}
let prim_coordinate_system_id = prim_run_context.scroll_node.coordinate_system_id; let prim_coordinate_system_id = prim_run_context.scroll_node.coordinate_system_id;
let transform = &prim_run_context.scroll_node.world_content_transform; let transform = &prim_run_context.scroll_node.world_content_transform;
@ -2228,10 +2292,13 @@ impl PrimitiveStore {
if let Some(outer) = screen_outer_rect { if let Some(outer) = screen_outer_rect {
combined_outer_rect = combined_outer_rect.and_then(|r| r.intersection(&outer)); combined_outer_rect = combined_outer_rect.and_then(|r| r.intersection(&outer));
} }
if cfg!(debug_assertions) && Some(prim_index) == self.chase_id {
println!("\tfound extra clip with screen bounds {:?}", screen_outer_rect);
}
Arc::new(ClipChainNode { Arc::new(ClipChainNode {
work_item: ClipWorkItem { work_item: ClipWorkItem {
scroll_node_data_index: prim_run_context.scroll_node.node_data_index, transform_index: prim_run_context.scroll_node.transform_index,
clip_sources: clip_sources.weak(), clip_sources: clip_sources.weak(),
coordinate_system_id: prim_coordinate_system_id, coordinate_system_id: prim_coordinate_system_id,
}, },
@ -2251,6 +2318,9 @@ impl PrimitiveStore {
let combined_outer_rect = match combined_outer_rect { let combined_outer_rect = match combined_outer_rect {
Some(rect) if !rect.is_empty() => rect, Some(rect) if !rect.is_empty() => rect,
_ => { _ => {
if cfg!(debug_assertions) && Some(prim_index) == self.chase_id {
println!("\tculled by the empty combined screen rect");
}
self.cpu_metadata[prim_index.0].screen_rect = None; self.cpu_metadata[prim_index.0].screen_rect = None;
return false; return false;
} }
@ -2274,12 +2344,18 @@ impl PrimitiveStore {
// If we don't have any clips from other coordinate systems, the local clip // If we don't have any clips from other coordinate systems, the local clip
// calculated from the clip chain should be sufficient to ensure proper clipping. // calculated from the clip chain should be sufficient to ensure proper clipping.
if !has_clips_from_other_coordinate_systems { if !has_clips_from_other_coordinate_systems {
if cfg!(debug_assertions) && Some(prim_index) == self.chase_id {
println!("\tneed no task: all clips are within the coordinate system");
}
return true; return true;
} }
// If we have filtered all clips and the screen rect isn't any smaller, we can just // If we have filtered all clips and the screen rect isn't any smaller, we can just
// skip masking entirely. // skip masking entirely.
if combined_outer_rect == prim_screen_rect { if combined_outer_rect == prim_screen_rect {
if cfg!(debug_assertions) && Some(prim_index) == self.chase_id {
println!("\tneed no task: combined rect is not smaller");
}
return true; return true;
} }
// Otherwise we create an empty mask, but with an empty inner rect to avoid further // Otherwise we create an empty mask, but with an empty inner rect to avoid further
@ -2288,7 +2364,10 @@ impl PrimitiveStore {
} }
if combined_inner_rect.contains_rect(&prim_screen_rect) { if combined_inner_rect.contains_rect(&prim_screen_rect) {
return true; if cfg!(debug_assertions) && Some(prim_index) == self.chase_id {
println!("\tneed no task: contained within the clip inner rect");
}
return true;
} }
// First try to render this primitive's mask using optimized brush rendering. // First try to render this primitive's mask using optimized brush rendering.
@ -2302,6 +2381,9 @@ impl PrimitiveStore {
frame_context, frame_context,
frame_state, frame_state,
) { ) {
if cfg!(debug_assertions) && Some(prim_index) == self.chase_id {
println!("\tsegment tasks have been created for clipping");
}
return true; return true;
} }
@ -2316,6 +2398,10 @@ impl PrimitiveStore {
); );
let clip_task_id = frame_state.render_tasks.add(clip_task); let clip_task_id = frame_state.render_tasks.add(clip_task);
if cfg!(debug_assertions) && Some(prim_index) == self.chase_id {
println!("\tcreated task {:?} with combined outer rect {:?}",
clip_task_id, combined_outer_rect);
}
self.cpu_metadata[prim_index.0].clip_task_id = Some(clip_task_id); self.cpu_metadata[prim_index.0].clip_task_id = Some(clip_task_id);
pic_state.tasks.push(clip_task_id); pic_state.tasks.push(clip_task_id);
@ -2341,6 +2427,9 @@ impl PrimitiveStore {
if !metadata.is_backface_visible && if !metadata.is_backface_visible &&
prim_run_context.scroll_node.world_content_transform.is_backface_visible() { prim_run_context.scroll_node.world_content_transform.is_backface_visible() {
if cfg!(debug_assertions) && Some(prim_index) == self.chase_id {
println!("\tculled for not having visible back faces");
}
return None; return None;
} }
@ -2358,6 +2447,9 @@ impl PrimitiveStore {
let pic = &mut self.pictures[pic_index.0]; let pic = &mut self.pictures[pic_index.0];
if !pic.resolve_scene_properties(frame_context.scene_properties) { if !pic.resolve_scene_properties(frame_context.scene_properties) {
if cfg!(debug_assertions) && Some(prim_index) == self.chase_id {
println!("\tculled for carrying an invisible composite filter");
}
return None; return None;
} }
@ -2429,7 +2521,9 @@ impl PrimitiveStore {
let metadata = &mut self.cpu_metadata[prim_index.0]; let metadata = &mut self.cpu_metadata[prim_index.0];
if metadata.local_rect.size.width <= 0.0 || if metadata.local_rect.size.width <= 0.0 ||
metadata.local_rect.size.height <= 0.0 { metadata.local_rect.size.height <= 0.0 {
//warn!("invalid primitive rect {:?}", metadata.local_rect); if cfg!(debug_assertions) && Some(prim_index) == self.chase_id {
println!("\tculled for zero local rectangle");
}
return None; return None;
} }
@ -2441,14 +2535,33 @@ impl PrimitiveStore {
// taken into account. // taken into account.
let local_rect = metadata.local_rect let local_rect = metadata.local_rect
.inflate(pic_context.inflation_factor, pic_context.inflation_factor) .inflate(pic_context.inflation_factor, pic_context.inflation_factor)
.intersection(&metadata.local_clip_rect)?; .intersection(&metadata.local_clip_rect);
let local_rect = match local_rect {
Some(local_rect) => local_rect,
None => {
if cfg!(debug_assertions) && Some(prim_index) == self.chase_id {
println!("\tculled for being out of the local clip rectangle: {:?}",
metadata.local_clip_rect);
}
return None
}
};
let unclipped = calculate_screen_bounding_rect( let unclipped = match calculate_screen_bounding_rect(
&prim_run_context.scroll_node.world_content_transform, &prim_run_context.scroll_node.world_content_transform,
&local_rect, &local_rect,
frame_context.device_pixel_scale, frame_context.device_pixel_scale,
None, //TODO: inflate `frame_context.screen_rect` appropriately None, //TODO: inflate `frame_context.screen_rect` appropriately
)?; ) {
Some(rect) => rect,
None => {
if cfg!(debug_assertions) && Some(prim_index) == self.chase_id {
println!("\tculled for being behind the near plane of transform: {:?}",
prim_run_context.scroll_node.world_content_transform);
}
return None
}
};
let clipped = unclipped let clipped = unclipped
.intersection(&prim_run_context.clip_chain.combined_outer_screen_rect)?; .intersection(&prim_run_context.clip_chain.combined_outer_screen_rect)?;
@ -2457,7 +2570,11 @@ impl PrimitiveStore {
clipped, clipped,
unclipped, unclipped,
}); });
metadata.clip_chain_rect_index = prim_run_context.clip_chain_rect_index;
metadata.combined_local_clip_rect = prim_run_context
.local_clip_rect
.intersection(&metadata.local_clip_rect)
.unwrap_or(LayoutRect::zero());
(local_rect, unclipped) (local_rect, unclipped)
}; };
@ -2480,6 +2597,10 @@ impl PrimitiveStore {
return None; return None;
} }
if cfg!(debug_assertions) && Some(prim_index) == self.chase_id {
println!("\tconsidered visible and ready with local rect {:?}", local_rect);
}
self.prepare_prim_for_render_inner( self.prepare_prim_for_render_inner(
prim_index, prim_index,
prim_run_context, prim_run_context,
@ -2514,6 +2635,10 @@ impl PrimitiveStore {
}; };
for run in &pic_context.prim_runs { for run in &pic_context.prim_runs {
if run.is_chasing(self.chase_id) {
println!("\tpreparing a run of length {} in pipeline {:?}",
run.count, pic_context.pipeline_id);
}
// TODO(gw): Perhaps we can restructure this to not need to create // TODO(gw): Perhaps we can restructure this to not need to create
// a new primitive context for every run (if the hash // a new primitive context for every run (if the hash
// lookups ever show up in a profile). // lookups ever show up in a profile).
@ -2531,12 +2656,16 @@ impl PrimitiveStore {
pic_state.has_non_root_coord_system |= clip_chain.has_non_root_coord_system; pic_state.has_non_root_coord_system |= clip_chain.has_non_root_coord_system;
if !scroll_node.invertible { if !scroll_node.invertible {
debug!("{:?} {:?}: position not invertible", run.base_prim_index, pic_context.pipeline_id); if run.is_chasing(self.chase_id) {
println!("\tculled for the scroll node transform being invertible");
}
continue; continue;
} }
if clip_chain.combined_outer_screen_rect.is_empty() { if clip_chain.combined_outer_screen_rect.is_empty() {
debug!("{:?} {:?}: clipped out", run.base_prim_index, pic_context.pipeline_id); if run.is_chasing(self.chase_id) {
println!("\tculled for out of screen bounds");
}
continue; continue;
} }
@ -2565,19 +2694,16 @@ impl PrimitiveStore {
None None
}; };
let clip_chain_rect_index = match clip_chain_rect { let local_clip_chain_rect = match clip_chain_rect {
Some(rect) if rect.is_empty() => continue, Some(rect) if rect.is_empty() => continue,
Some(rect) => { Some(rect) => rect,
frame_state.local_clip_rects.push(rect); None => frame_context.max_local_clip,
ClipChainRectIndex(frame_state.local_clip_rects.len() - 1)
}
None => ClipChainRectIndex(0), // This is no clipping.
}; };
let child_prim_run_context = PrimitiveRunContext::new( let child_prim_run_context = PrimitiveRunContext::new(
clip_chain, clip_chain,
scroll_node, scroll_node,
clip_chain_rect_index, local_clip_chain_rect,
); );
for i in 0 .. run.count { for i in 0 .. run.count {
@ -2611,6 +2737,12 @@ impl PrimitiveStore {
result.local_rect_in_original_parent_space = result.local_rect_in_original_parent_space =
result.local_rect_in_original_parent_space.union(&bounds); result.local_rect_in_original_parent_space.union(&bounds);
} }
if let Some(ref matrix) = parent_relative_transform {
let bounds = matrix.transform_rect(&prim_local_rect);
result.local_rect_in_actual_parent_space =
result.local_rect_in_actual_parent_space.union(&bounds);
}
} }
} }
} }
@ -2646,14 +2778,16 @@ fn decompose_repeated_primitive(
prim_run_context: &PrimitiveRunContext, prim_run_context: &PrimitiveRunContext,
frame_context: &FrameBuildingContext, frame_context: &FrameBuildingContext,
frame_state: &mut FrameBuildingState, frame_state: &mut FrameBuildingState,
callback: &mut FnMut(&LayoutRect, &LayoutRect, GpuDataRequest), callback: &mut FnMut(&LayoutRect, GpuDataRequest),
) { ) {
visible_tiles.clear(); visible_tiles.clear();
// Tighten the clip rect because decomposing the repeated image can // Tighten the clip rect because decomposing the repeated image can
// produce primitives that are partially covering the original image // produce primitives that are partially covering the original image
// rect and we want to clip these extra parts out. // rect and we want to clip these extra parts out.
let tight_clip_rect = metadata.local_clip_rect.intersection(&metadata.local_rect).unwrap(); let tight_clip_rect = metadata
.combined_local_clip_rect
.intersection(&metadata.local_rect).unwrap();
let visible_rect = compute_conservative_visible_rect( let visible_rect = compute_conservative_visible_rect(
prim_run_context, prim_run_context,
@ -2669,16 +2803,19 @@ fn decompose_repeated_primitive(
&mut |origin, _| { &mut |origin, _| {
let mut handle = GpuCacheHandle::new(); let mut handle = GpuCacheHandle::new();
let rect = LayoutRect {
origin: *origin,
size: *stretch_size,
};
if let Some(request) = frame_state.gpu_cache.request(&mut handle) { if let Some(request) = frame_state.gpu_cache.request(&mut handle) {
let rect = LayoutRect { callback(&rect, request);
origin: *origin,
size: *stretch_size,
};
callback(&rect, &tight_clip_rect, request);
} }
visible_tiles.push(VisibleGradientTile { handle }); visible_tiles.push(VisibleGradientTile {
local_rect: rect,
local_clip_rect: tight_clip_rect,
handle
});
} }
); );
@ -2725,31 +2862,6 @@ fn edge_flags_for_tile_spacing(tile_spacing: &LayoutSize) -> EdgeAaSegmentMask {
flags flags
} }
//Test for one clip region contains another
trait InsideTest<T> {
fn might_contain(&self, clip: &T) -> bool;
}
impl InsideTest<ComplexClipRegion> for ComplexClipRegion {
// Returns true if clip is inside self, can return false negative
fn might_contain(&self, clip: &ComplexClipRegion) -> bool {
let delta_left = clip.rect.origin.x - self.rect.origin.x;
let delta_top = clip.rect.origin.y - self.rect.origin.y;
let delta_right = self.rect.max_x() - clip.rect.max_x();
let delta_bottom = self.rect.max_y() - clip.rect.max_y();
delta_left >= 0f32 && delta_top >= 0f32 && delta_right >= 0f32 && delta_bottom >= 0f32 &&
clip.radii.top_left.width >= self.radii.top_left.width - delta_left &&
clip.radii.top_left.height >= self.radii.top_left.height - delta_top &&
clip.radii.top_right.width >= self.radii.top_right.width - delta_right &&
clip.radii.top_right.height >= self.radii.top_right.height - delta_top &&
clip.radii.bottom_left.width >= self.radii.bottom_left.width - delta_left &&
clip.radii.bottom_left.height >= self.radii.bottom_left.height - delta_bottom &&
clip.radii.bottom_right.width >= self.radii.bottom_right.width - delta_right &&
clip.radii.bottom_right.height >= self.radii.bottom_right.height - delta_bottom
}
}
fn convert_clip_chain_to_clip_vector( fn convert_clip_chain_to_clip_vector(
clip_chain_nodes: ClipChainNodeRef, clip_chain_nodes: ClipChainNodeRef,
extra_clip: ClipChainNodeRef, extra_clip: ClipChainNodeRef,

Просмотреть файл

@ -1063,6 +1063,7 @@ impl RenderBackend {
debug_assert!(op.render || !op.composite); debug_assert!(op.render || !op.composite);
let mut render_time = None;
if op.render && doc.has_pixels() { if op.render && doc.has_pixels() {
profile_scope!("generate frame"); profile_scope!("generate frame");
@ -1071,6 +1072,7 @@ impl RenderBackend {
// borrow ck hack for profile_counters // borrow ck hack for profile_counters
let (pending_update, rendered_document) = { let (pending_update, rendered_document) = {
let _timer = profile_counters.total_time.timer(); let _timer = profile_counters.total_time.timer();
let render_start_time = precise_time_ns();
let rendered_document = doc.render( let rendered_document = doc.render(
&mut self.resource_cache, &mut self.resource_cache,
@ -1085,6 +1087,8 @@ impl RenderBackend {
let msg = ResultMsg::UpdateGpuCache(self.gpu_cache.extract_updates()); let msg = ResultMsg::UpdateGpuCache(self.gpu_cache.extract_updates());
self.result_tx.send(msg).unwrap(); self.result_tx.send(msg).unwrap();
render_time = Some(precise_time_ns() - render_start_time);
let pending_update = self.resource_cache.pending_updates(); let pending_update = self.resource_cache.pending_updates();
(pending_update, rendered_document) (pending_update, rendered_document)
}; };
@ -1111,7 +1115,7 @@ impl RenderBackend {
} }
if transaction_msg.generate_frame { if transaction_msg.generate_frame {
self.notifier.new_frame_ready(document_id, op.scroll, op.composite); self.notifier.new_frame_ready(document_id, op.scroll, op.composite, render_time);
} }
} }
@ -1410,7 +1414,7 @@ impl RenderBackend {
self.result_tx.send(msg_publish).unwrap(); self.result_tx.send(msg_publish).unwrap();
profile_counters.reset(); profile_counters.reset();
self.notifier.new_frame_ready(id, false, true); self.notifier.new_frame_ready(id, false, true, None);
self.documents.insert(id, doc); self.documents.insert(id, doc);
} }
} }

Просмотреть файл

@ -26,7 +26,7 @@ use device::{FileWatcherHandler, ShaderError, TextureFilter,
VertexUsageHint, VAO, VBO, CustomVAO}; VertexUsageHint, VAO, VBO, CustomVAO};
use device::{ProgramCache, ReadPixelsFormat}; use device::{ProgramCache, ReadPixelsFormat};
use euclid::{rect, Transform3D}; use euclid::{rect, Transform3D};
use frame_builder::FrameBuilderConfig; use frame_builder::{ChasePrimitive, FrameBuilderConfig};
use gleam::gl; use gleam::gl;
use glyph_rasterizer::{GlyphFormat, GlyphRasterizer}; use glyph_rasterizer::{GlyphFormat, GlyphRasterizer};
use gpu_cache::{GpuBlockData, GpuCacheUpdate, GpuCacheUpdateList}; use gpu_cache::{GpuBlockData, GpuCacheUpdate, GpuCacheUpdateList};
@ -270,14 +270,15 @@ pub(crate) enum TextureSampler {
CacheA8, CacheA8,
CacheRGBA8, CacheRGBA8,
ResourceCache, ResourceCache,
ClipScrollNodes, TransformPalette,
RenderTasks, RenderTasks,
Dither, Dither,
// A special sampler that is bound to the A8 output of // A special sampler that is bound to the A8 output of
// the *first* pass. Items rendered in this target are // the *first* pass. Items rendered in this target are
// available as inputs to tasks in any subsequent pass. // available as inputs to tasks in any subsequent pass.
SharedCacheA8, SharedCacheA8,
LocalClipRects PrimitiveHeadersF,
PrimitiveHeadersI,
} }
impl TextureSampler { impl TextureSampler {
@ -302,11 +303,12 @@ impl Into<TextureSlot> for TextureSampler {
TextureSampler::CacheA8 => TextureSlot(3), TextureSampler::CacheA8 => TextureSlot(3),
TextureSampler::CacheRGBA8 => TextureSlot(4), TextureSampler::CacheRGBA8 => TextureSlot(4),
TextureSampler::ResourceCache => TextureSlot(5), TextureSampler::ResourceCache => TextureSlot(5),
TextureSampler::ClipScrollNodes => TextureSlot(6), TextureSampler::TransformPalette => TextureSlot(6),
TextureSampler::RenderTasks => TextureSlot(7), TextureSampler::RenderTasks => TextureSlot(7),
TextureSampler::Dither => TextureSlot(8), TextureSampler::Dither => TextureSlot(8),
TextureSampler::SharedCacheA8 => TextureSlot(9), TextureSampler::SharedCacheA8 => TextureSlot(9),
TextureSampler::LocalClipRects => TextureSlot(10), TextureSampler::PrimitiveHeadersF => TextureSlot(10),
TextureSampler::PrimitiveHeadersI => TextureSlot(11),
} }
} }
} }
@ -330,12 +332,7 @@ pub(crate) mod desc {
], ],
instance_attributes: &[ instance_attributes: &[
VertexAttribute { VertexAttribute {
name: "aData0", name: "aData",
count: 4,
kind: VertexAttributeKind::I32,
},
VertexAttribute {
name: "aData1",
count: 4, count: 4,
kind: VertexAttributeKind::I32, kind: VertexAttributeKind::I32,
}, },
@ -1215,8 +1212,14 @@ struct VertexDataTexture {
} }
impl VertexDataTexture { impl VertexDataTexture {
fn new(device: &mut Device) -> VertexDataTexture { fn new(
let texture = device.create_texture(TextureTarget::Default, ImageFormat::RGBAF32); device: &mut Device,
format: ImageFormat,
) -> VertexDataTexture {
let texture = device.create_texture(
TextureTarget::Default,
format,
);
let pbo = device.create_pbo(); let pbo = device.create_pbo();
VertexDataTexture { texture, pbo } VertexDataTexture { texture, pbo }
@ -1369,8 +1372,9 @@ pub struct Renderer {
pub gpu_profile: GpuProfiler<GpuProfileTag>, pub gpu_profile: GpuProfiler<GpuProfileTag>,
vaos: RendererVAOs, vaos: RendererVAOs,
node_data_texture: VertexDataTexture, prim_header_f_texture: VertexDataTexture,
local_clip_rects_texture: VertexDataTexture, prim_header_i_texture: VertexDataTexture,
transforms_texture: VertexDataTexture,
render_task_texture: VertexDataTexture, render_task_texture: VertexDataTexture,
gpu_cache_texture: CacheTexture, gpu_cache_texture: CacheTexture,
@ -1629,9 +1633,10 @@ impl Renderer {
let texture_resolver = SourceTextureResolver::new(&mut device); let texture_resolver = SourceTextureResolver::new(&mut device);
let node_data_texture = VertexDataTexture::new(&mut device); let prim_header_f_texture = VertexDataTexture::new(&mut device, ImageFormat::RGBAF32);
let local_clip_rects_texture = VertexDataTexture::new(&mut device); let prim_header_i_texture = VertexDataTexture::new(&mut device, ImageFormat::RGBAI32);
let render_task_texture = VertexDataTexture::new(&mut device); let transforms_texture = VertexDataTexture::new(&mut device, ImageFormat::RGBAF32);
let render_task_texture = VertexDataTexture::new(&mut device, ImageFormat::RGBAF32);
let gpu_cache_texture = CacheTexture::new( let gpu_cache_texture = CacheTexture::new(
&mut device, &mut device,
@ -1653,6 +1658,7 @@ impl Renderer {
default_font_render_mode, default_font_render_mode,
dual_source_blending_is_enabled: true, dual_source_blending_is_enabled: true,
dual_source_blending_is_supported: ext_dual_source_blending, dual_source_blending_is_supported: ext_dual_source_blending,
chase_primitive: options.chase_primitive,
}; };
let device_pixel_ratio = options.device_pixel_ratio; let device_pixel_ratio = options.device_pixel_ratio;
@ -1784,8 +1790,9 @@ impl Renderer {
dash_and_dot_vao, dash_and_dot_vao,
border_vao, border_vao,
}, },
node_data_texture, transforms_texture,
local_clip_rects_texture, prim_header_i_texture,
prim_header_f_texture,
render_task_texture, render_task_texture,
pipeline_info: PipelineInfo::default(), pipeline_info: PipelineInfo::default(),
dither_matrix_texture, dither_matrix_texture,
@ -3533,16 +3540,31 @@ impl Renderer {
let _timer = self.gpu_profile.start_timer(GPU_TAG_SETUP_DATA); let _timer = self.gpu_profile.start_timer(GPU_TAG_SETUP_DATA);
self.device.set_device_pixel_ratio(frame.device_pixel_ratio); self.device.set_device_pixel_ratio(frame.device_pixel_ratio);
self.node_data_texture.update(&mut self.device, &mut frame.node_data); self.prim_header_f_texture.update(
self.device.bind_texture(TextureSampler::ClipScrollNodes, &self.node_data_texture.texture);
self.local_clip_rects_texture.update(
&mut self.device, &mut self.device,
&mut frame.clip_chain_local_clip_rects &mut frame.prim_headers.headers_float,
); );
self.device.bind_texture( self.device.bind_texture(
TextureSampler::LocalClipRects, TextureSampler::PrimitiveHeadersF,
&self.local_clip_rects_texture.texture &self.prim_header_f_texture.texture,
);
self.prim_header_i_texture.update(
&mut self.device,
&mut frame.prim_headers.headers_int,
);
self.device.bind_texture(
TextureSampler::PrimitiveHeadersI,
&self.prim_header_i_texture.texture,
);
self.transforms_texture.update(
&mut self.device,
&mut frame.transform_palette,
);
self.device.bind_texture(
TextureSampler::TransformPalette,
&self.transforms_texture.texture,
); );
self.render_task_texture self.render_task_texture
@ -3929,8 +3951,9 @@ impl Renderer {
if let Some(dither_matrix_texture) = self.dither_matrix_texture { if let Some(dither_matrix_texture) = self.dither_matrix_texture {
self.device.delete_texture(dither_matrix_texture); self.device.delete_texture(dither_matrix_texture);
} }
self.node_data_texture.deinit(&mut self.device); self.transforms_texture.deinit(&mut self.device);
self.local_clip_rects_texture.deinit(&mut self.device); self.prim_header_f_texture.deinit(&mut self.device);
self.prim_header_i_texture.deinit(&mut self.device);
self.render_task_texture.deinit(&mut self.device); self.render_task_texture.deinit(&mut self.device);
self.device.delete_pbo(self.texture_cache_upload_pbo); self.device.delete_pbo(self.texture_cache_upload_pbo);
self.texture_resolver.deinit(&mut self.device); self.texture_resolver.deinit(&mut self.device);
@ -4017,11 +4040,11 @@ pub trait SceneBuilderHooks {
/// and before it processes anything. /// and before it processes anything.
fn register(&self); fn register(&self);
/// This is called before each scene swap occurs. /// This is called before each scene swap occurs.
fn pre_scene_swap(&self); fn pre_scene_swap(&self, scenebuild_time: u64);
/// This is called after each scene swap occurs. The PipelineInfo contains /// This is called after each scene swap occurs. The PipelineInfo contains
/// the updated epochs and pipelines removed in the new scene compared to /// the updated epochs and pipelines removed in the new scene compared to
/// the old scene. /// the old scene.
fn post_scene_swap(&self, info: PipelineInfo); fn post_scene_swap(&self, info: PipelineInfo, sceneswap_time: u64);
/// This is called after a resource update operation on the scene builder /// This is called after a resource update operation on the scene builder
/// thread, in the case where resource updates were applied without a scene /// thread, in the case where resource updates were applied without a scene
/// build. /// build.
@ -4078,6 +4101,7 @@ pub struct RendererOptions {
pub disable_dual_source_blending: bool, pub disable_dual_source_blending: bool,
pub scene_builder_hooks: Option<Box<SceneBuilderHooks + Send>>, pub scene_builder_hooks: Option<Box<SceneBuilderHooks + Send>>,
pub sampler: Option<Box<AsyncPropertySampler + Send>>, pub sampler: Option<Box<AsyncPropertySampler + Send>>,
pub chase_primitive: ChasePrimitive,
} }
impl Default for RendererOptions { impl Default for RendererOptions {
@ -4111,6 +4135,7 @@ impl Default for RendererOptions {
disable_dual_source_blending: false, disable_dual_source_blending: false,
scene_builder_hooks: None, scene_builder_hooks: None,
sampler: None, sampler: None,
chase_primitive: ChasePrimitive::Nothing,
} }
} }
} }

Просмотреть файл

@ -641,13 +641,20 @@ impl ResourceCache {
return return
}; };
if !self.pending_image_requests.insert(request) {
return
}
// If we are tiling, then we need to confirm the dirty rect intersects
// the tile before leaving the request in the pending queue.
//
// We can start a worker thread rasterizing right now, if: // We can start a worker thread rasterizing right now, if:
// - The image is a blob. // - The image is a blob.
// - The blob hasn't already been requested this frame. // - The blob hasn't already been requested this frame.
if self.pending_image_requests.insert(request) && template.data.is_blob() { if template.data.is_blob() || dirty_rect.is_some() {
let (offset, size) = match template.tiling { let (offset, size) = match request.tile {
Some(tile_size) => { Some(tile_offset) => {
let tile_offset = request.tile.unwrap(); let tile_size = template.tiling.unwrap();
let actual_size = compute_tile_size( let actual_size = compute_tile_size(
&template.descriptor, &template.descriptor,
tile_size, tile_size,
@ -671,17 +678,19 @@ impl ResourceCache {
None => (DevicePoint::zero(), template.descriptor.size), None => (DevicePoint::zero(), template.descriptor.size),
}; };
if let Some(ref mut renderer) = self.blob_image_renderer { if template.data.is_blob() {
renderer.request( if let Some(ref mut renderer) = self.blob_image_renderer {
&self.resources, renderer.request(
request.into(), &self.resources,
&BlobImageDescriptor { request.into(),
size, &BlobImageDescriptor {
offset, size,
format: template.descriptor.format, offset,
}, format: template.descriptor.format,
dirty_rect, },
); dirty_rect,
);
}
} }
} }
} }
@ -923,6 +932,8 @@ impl ResourceCache {
} }
fn update_texture_cache(&mut self, gpu_cache: &mut GpuCache) { fn update_texture_cache(&mut self, gpu_cache: &mut GpuCache) {
let mut keys_to_clear_dirty_rect = FastHashSet::default();
for request in self.pending_image_requests.drain() { for request in self.pending_image_requests.drain() {
let image_template = self.resources.image_templates.get_mut(request.key).unwrap(); let image_template = self.resources.image_templates.get_mut(request.key).unwrap();
debug_assert!(image_template.data.uses_texture_cache()); debug_assert!(image_template.data.uses_texture_cache());
@ -963,23 +974,24 @@ impl ResourceCache {
let entry = self.cached_images.get_mut(&request).as_mut().unwrap(); let entry = self.cached_images.get_mut(&request).as_mut().unwrap();
let mut descriptor = image_template.descriptor.clone(); let mut descriptor = image_template.descriptor.clone();
//TODO: erasing the dirty rectangle here is incorrect for tiled images, let local_dirty_rect;
// since other tile requests may follow that depend on it
let mut local_dirty_rect = image_template.dirty_rect.take();
if let Some(tile) = request.tile { if let Some(tile) = request.tile {
let tile_size = image_template.tiling.unwrap(); let tile_size = image_template.tiling.unwrap();
let clipped_tile_size = compute_tile_size(&descriptor, tile_size, tile); let clipped_tile_size = compute_tile_size(&descriptor, tile_size, tile);
if let Some(ref mut rect) = local_dirty_rect { local_dirty_rect = if let Some(ref rect) = image_template.dirty_rect {
match intersect_for_tile(*rect, clipped_tile_size, tile_size, tile) { keys_to_clear_dirty_rect.insert(request.key.clone());
Some(intersection) => *rect = intersection,
None => { // We should either have a dirty rect, or we are re-uploading where the dirty
// if re-uploaded, the dirty rect is ignored anyway // rect is ignored anyway.
debug_assert!(self.texture_cache.needs_upload(&entry.texture_cache_handle)) let intersection = intersect_for_tile(*rect, clipped_tile_size, tile_size, tile);
} debug_assert!(intersection.is_some() ||
} self.texture_cache.needs_upload(&entry.texture_cache_handle));
} intersection
} else {
None
};
// The tiled image could be stored on the CPU as one large image or be // The tiled image could be stored on the CPU as one large image or be
// already broken up into tiles. This affects the way we compute the stride // already broken up into tiles. This affects the way we compute the stride
@ -995,6 +1007,8 @@ impl ResourceCache {
} }
descriptor.size = clipped_tile_size; descriptor.size = clipped_tile_size;
} else {
local_dirty_rect = image_template.dirty_rect.take();
} }
let filter = match request.rendering { let filter = match request.rendering {
@ -1036,6 +1050,11 @@ impl ResourceCache {
UvRectKind::Rect, UvRectKind::Rect,
); );
} }
for key in keys_to_clear_dirty_rect.drain() {
let image_template = self.resources.image_templates.get_mut(key).unwrap();
image_template.dirty_rect.take();
}
} }
pub fn end_frame(&mut self) { pub fn end_frame(&mut self) {

Просмотреть файл

@ -13,6 +13,7 @@ use render_backend::DocumentView;
use renderer::{PipelineInfo, SceneBuilderHooks}; use renderer::{PipelineInfo, SceneBuilderHooks};
use scene::Scene; use scene::Scene;
use std::sync::mpsc::{channel, Receiver, Sender}; use std::sync::mpsc::{channel, Receiver, Sender};
use time::precise_time_ns;
// Message from render backend to scene builder. // Message from render backend to scene builder.
pub enum SceneBuilderRequest { pub enum SceneBuilderRequest {
@ -137,6 +138,7 @@ impl SceneBuilder {
frame_ops, frame_ops,
render, render,
} => { } => {
let scenebuild_start_time = precise_time_ns();
let built_scene = scene.map(|request|{ let built_scene = scene.map(|request|{
build_scene(&self.config, request) build_scene(&self.config, request)
}); });
@ -156,13 +158,15 @@ impl SceneBuilder {
}; };
let (tx, rx) = channel(); let (tx, rx) = channel();
hooks.pre_scene_swap(); let scenebuild_time = precise_time_ns() - scenebuild_start_time;
hooks.pre_scene_swap(scenebuild_time);
(Some(info), Some(tx), Some(rx)) (Some(info), Some(tx), Some(rx))
} }
_ => (None, None, None), _ => (None, None, None),
}; };
let sceneswap_start_time = precise_time_ns();
let has_resources_updates = !resource_updates.is_empty(); let has_resources_updates = !resource_updates.is_empty();
self.tx.send(SceneBuilderResult::Transaction { self.tx.send(SceneBuilderResult::Transaction {
document_id, document_id,
@ -178,7 +182,8 @@ impl SceneBuilder {
if let Some(pipeline_info) = pipeline_info { if let Some(pipeline_info) = pipeline_info {
// Block until the swap is done, then invoke the hook. // Block until the swap is done, then invoke the hook.
let swap_result = result_rx.unwrap().recv(); let swap_result = result_rx.unwrap().recv();
self.hooks.as_ref().unwrap().post_scene_swap(pipeline_info); let sceneswap_time = precise_time_ns() - sceneswap_start_time;
self.hooks.as_ref().unwrap().post_scene_swap(pipeline_info, sceneswap_time);
// Once the hook is done, allow the RB thread to resume // Once the hook is done, allow the RB thread to resume
match swap_result { match swap_result {
Ok(SceneSwapResult::Complete(resume_tx)) => { Ok(SceneSwapResult::Complete(resume_tx)) => {

Просмотреть файл

@ -351,11 +351,12 @@ fn create_prim_shader(
("sDither", TextureSampler::Dither), ("sDither", TextureSampler::Dither),
("sCacheA8", TextureSampler::CacheA8), ("sCacheA8", TextureSampler::CacheA8),
("sCacheRGBA8", TextureSampler::CacheRGBA8), ("sCacheRGBA8", TextureSampler::CacheRGBA8),
("sClipScrollNodes", TextureSampler::ClipScrollNodes), ("sTransformPalette", TextureSampler::TransformPalette),
("sRenderTasks", TextureSampler::RenderTasks), ("sRenderTasks", TextureSampler::RenderTasks),
("sResourceCache", TextureSampler::ResourceCache), ("sResourceCache", TextureSampler::ResourceCache),
("sSharedCacheA8", TextureSampler::SharedCacheA8), ("sSharedCacheA8", TextureSampler::SharedCacheA8),
("sLocalClipRects", TextureSampler::LocalClipRects), ("sPrimitiveHeadersF", TextureSampler::PrimitiveHeadersF),
("sPrimitiveHeadersI", TextureSampler::PrimitiveHeadersI),
], ],
); );
} }
@ -379,11 +380,12 @@ fn create_clip_shader(name: &'static str, device: &mut Device) -> Result<Program
program, program,
&[ &[
("sColor0", TextureSampler::Color0), ("sColor0", TextureSampler::Color0),
("sClipScrollNodes", TextureSampler::ClipScrollNodes), ("sTransformPalette", TextureSampler::TransformPalette),
("sRenderTasks", TextureSampler::RenderTasks), ("sRenderTasks", TextureSampler::RenderTasks),
("sResourceCache", TextureSampler::ResourceCache), ("sResourceCache", TextureSampler::ResourceCache),
("sSharedCacheA8", TextureSampler::SharedCacheA8), ("sSharedCacheA8", TextureSampler::SharedCacheA8),
("sLocalClipRects", TextureSampler::LocalClipRects), ("sPrimitiveHeadersF", TextureSampler::PrimitiveHeadersF),
("sPrimitiveHeadersI", TextureSampler::PrimitiveHeadersI),
], ],
); );
} }

Просмотреть файл

@ -501,6 +501,7 @@ impl TextureCache {
(ImageFormat::BGRA8, TextureFilter::Nearest) => &mut self.array_rgba8_nearest, (ImageFormat::BGRA8, TextureFilter::Nearest) => &mut self.array_rgba8_nearest,
(ImageFormat::RGBAF32, _) | (ImageFormat::RGBAF32, _) |
(ImageFormat::RG8, _) | (ImageFormat::RG8, _) |
(ImageFormat::RGBAI32, _) |
(ImageFormat::R8, TextureFilter::Nearest) | (ImageFormat::R8, TextureFilter::Nearest) |
(ImageFormat::R8, TextureFilter::Trilinear) | (ImageFormat::R8, TextureFilter::Trilinear) |
(ImageFormat::BGRA8, TextureFilter::Trilinear) => unreachable!(), (ImageFormat::BGRA8, TextureFilter::Trilinear) => unreachable!(),
@ -725,6 +726,7 @@ impl TextureCache {
(ImageFormat::BGRA8, TextureFilter::Linear) => &mut self.array_rgba8_linear, (ImageFormat::BGRA8, TextureFilter::Linear) => &mut self.array_rgba8_linear,
(ImageFormat::BGRA8, TextureFilter::Nearest) => &mut self.array_rgba8_nearest, (ImageFormat::BGRA8, TextureFilter::Nearest) => &mut self.array_rgba8_nearest,
(ImageFormat::RGBAF32, _) | (ImageFormat::RGBAF32, _) |
(ImageFormat::RGBAI32, _) |
(ImageFormat::R8, TextureFilter::Nearest) | (ImageFormat::R8, TextureFilter::Nearest) |
(ImageFormat::R8, TextureFilter::Trilinear) | (ImageFormat::R8, TextureFilter::Trilinear) |
(ImageFormat::BGRA8, TextureFilter::Trilinear) | (ImageFormat::BGRA8, TextureFilter::Trilinear) |

Просмотреть файл

@ -12,8 +12,7 @@ use device::{FrameId, Texture};
#[cfg(feature = "pathfinder")] #[cfg(feature = "pathfinder")]
use euclid::{TypedPoint2D, TypedVector2D}; use euclid::{TypedPoint2D, TypedVector2D};
use gpu_cache::{GpuCache}; use gpu_cache::{GpuCache};
use gpu_types::{BorderInstance, BlurDirection, BlurInstance}; use gpu_types::{BorderInstance, BlurDirection, BlurInstance, PrimitiveHeaders, TransformData, TransformPalette};
use gpu_types::{ClipScrollNodeData, ZBufferIdGenerator};
use internal_types::{FastHashMap, SavedTargetIndex, SourceTexture}; use internal_types::{FastHashMap, SavedTargetIndex, SourceTexture};
#[cfg(feature = "pathfinder")] #[cfg(feature = "pathfinder")]
use pathfinder_partitioner::mesh::Mesh; use pathfinder_partitioner::mesh::Mesh;
@ -48,7 +47,7 @@ pub struct RenderTargetContext<'a, 'rc> {
pub resource_cache: &'rc mut ResourceCache, pub resource_cache: &'rc mut ResourceCache,
pub clip_scroll_tree: &'a ClipScrollTree, pub clip_scroll_tree: &'a ClipScrollTree,
pub use_dual_source_blending: bool, pub use_dual_source_blending: bool,
pub node_data: &'a [ClipScrollNodeData], pub transforms: &'a TransformPalette,
} }
#[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "capture", derive(Serialize))]
@ -103,6 +102,7 @@ pub trait RenderTarget {
_gpu_cache: &mut GpuCache, _gpu_cache: &mut GpuCache,
_render_tasks: &mut RenderTaskTree, _render_tasks: &mut RenderTaskTree,
_deferred_resolves: &mut Vec<DeferredResolve>, _deferred_resolves: &mut Vec<DeferredResolve>,
_prim_headers: &mut PrimitiveHeaders,
) { ) {
} }
// TODO(gw): It's a bit odd that we need the deferred resolves and mutable // TODO(gw): It's a bit odd that we need the deferred resolves and mutable
@ -166,12 +166,19 @@ impl<T: RenderTarget> RenderTargetList<T> {
render_tasks: &mut RenderTaskTree, render_tasks: &mut RenderTaskTree,
deferred_resolves: &mut Vec<DeferredResolve>, deferred_resolves: &mut Vec<DeferredResolve>,
saved_index: Option<SavedTargetIndex>, saved_index: Option<SavedTargetIndex>,
prim_headers: &mut PrimitiveHeaders,
) { ) {
debug_assert_eq!(None, self.saved_index); debug_assert_eq!(None, self.saved_index);
self.saved_index = saved_index; self.saved_index = saved_index;
for target in &mut self.targets { for target in &mut self.targets {
target.build(ctx, gpu_cache, render_tasks, deferred_resolves); target.build(
ctx,
gpu_cache,
render_tasks,
deferred_resolves,
prim_headers,
);
} }
} }
@ -333,9 +340,9 @@ impl RenderTarget for ColorRenderTarget {
gpu_cache: &mut GpuCache, gpu_cache: &mut GpuCache,
render_tasks: &mut RenderTaskTree, render_tasks: &mut RenderTaskTree,
deferred_resolves: &mut Vec<DeferredResolve>, deferred_resolves: &mut Vec<DeferredResolve>,
prim_headers: &mut PrimitiveHeaders,
) { ) {
let mut merged_batches = AlphaBatchContainer::new(None); let mut merged_batches = AlphaBatchContainer::new(None);
let mut z_generator = ZBufferIdGenerator::new();
for task_id in &self.alpha_tasks { for task_id in &self.alpha_tasks {
let task = &render_tasks[*task_id]; let task = &render_tasks[*task_id];
@ -358,7 +365,7 @@ impl RenderTarget for ColorRenderTarget {
gpu_cache, gpu_cache,
render_tasks, render_tasks,
deferred_resolves, deferred_resolves,
&mut z_generator, prim_headers,
); );
if let Some(batch_container) = batch_builder.build(&mut merged_batches) { if let Some(batch_container) = batch_builder.build(&mut merged_batches) {
@ -594,6 +601,7 @@ impl RenderTarget for AlphaRenderTarget {
ctx.resource_cache, ctx.resource_cache,
gpu_cache, gpu_cache,
clip_store, clip_store,
ctx.transforms,
); );
} }
RenderTaskKind::ClipRegion(ref task) => { RenderTaskKind::ClipRegion(ref task) => {
@ -795,6 +803,7 @@ impl RenderPass {
render_tasks: &mut RenderTaskTree, render_tasks: &mut RenderTaskTree,
deferred_resolves: &mut Vec<DeferredResolve>, deferred_resolves: &mut Vec<DeferredResolve>,
clip_store: &ClipStore, clip_store: &ClipStore,
prim_headers: &mut PrimitiveHeaders,
) { ) {
profile_scope!("RenderPass::build"); profile_scope!("RenderPass::build");
@ -811,7 +820,13 @@ impl RenderPass {
deferred_resolves, deferred_resolves,
); );
} }
target.build(ctx, gpu_cache, render_tasks, deferred_resolves); target.build(
ctx,
gpu_cache,
render_tasks,
deferred_resolves,
prim_headers,
);
} }
RenderPassKind::OffScreen { ref mut color, ref mut alpha, ref mut texture_cache } => { RenderPassKind::OffScreen { ref mut color, ref mut alpha, ref mut texture_cache } => {
let is_shared_alpha = self.tasks.iter().any(|&task_id| { let is_shared_alpha = self.tasks.iter().any(|&task_id| {
@ -911,8 +926,22 @@ impl RenderPass {
} }
} }
color.build(ctx, gpu_cache, render_tasks, deferred_resolves, saved_color); color.build(
alpha.build(ctx, gpu_cache, render_tasks, deferred_resolves, saved_alpha); ctx,
gpu_cache,
render_tasks,
deferred_resolves,
saved_color,
prim_headers,
);
alpha.build(
ctx,
gpu_cache,
render_tasks,
deferred_resolves,
saved_alpha,
prim_headers,
);
alpha.is_shared = is_shared_alpha; alpha.is_shared = is_shared_alpha;
} }
} }
@ -956,9 +985,9 @@ pub struct Frame {
#[cfg_attr(any(feature = "capture", feature = "replay"), serde(default = "FrameProfileCounters::new", skip))] #[cfg_attr(any(feature = "capture", feature = "replay"), serde(default = "FrameProfileCounters::new", skip))]
pub profile_counters: FrameProfileCounters, pub profile_counters: FrameProfileCounters,
pub node_data: Vec<ClipScrollNodeData>, pub transform_palette: Vec<TransformData>,
pub clip_chain_local_clip_rects: Vec<LayoutRect>,
pub render_tasks: RenderTaskTree, pub render_tasks: RenderTaskTree,
pub prim_headers: PrimitiveHeaders,
/// The GPU cache frame that the contents of Self depend on /// The GPU cache frame that the contents of Self depend on
pub gpu_cache_frame_id: FrameId, pub gpu_cache_frame_id: FrameId,

Просмотреть файл

@ -1103,7 +1103,7 @@ pub struct DynamicProperties {
pub trait RenderNotifier: Send { pub trait RenderNotifier: Send {
fn clone(&self) -> Box<RenderNotifier>; fn clone(&self) -> Box<RenderNotifier>;
fn wake_up(&self); fn wake_up(&self);
fn new_frame_ready(&self, DocumentId, scrolled: bool, composite_needed: bool); fn new_frame_ready(&self, DocumentId, scrolled: bool, composite_needed: bool, render_time_ns: Option<u64>);
fn external_event(&self, _evt: ExternalEvent) { fn external_event(&self, _evt: ExternalEvent) {
unimplemented!() unimplemented!()
} }

Просмотреть файл

@ -115,7 +115,7 @@ pub struct ColorU {
impl ColorU { impl ColorU {
/// Constructs a new additive `ColorU` from its components. /// Constructs a new additive `ColorU` from its components.
pub fn new(r: u8, g: u8, b: u8, a: u8) -> ColorU { pub fn new(r: u8, g: u8, b: u8, a: u8) -> Self {
ColorU { r, g, b, a } ColorU { r, g, b, a }
} }
} }

Просмотреть файл

@ -273,22 +273,10 @@ pub enum RepeatMode {
} }
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
pub struct GradientBorder {
pub gradient: Gradient,
pub outset: SideOffsets2D<f32>,
}
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
pub struct RadialGradientBorder {
pub gradient: RadialGradient,
pub outset: SideOffsets2D<f32>,
}
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
/// TODO(mrobinson): Currently only images are supported, but we will
/// eventually add support for Gradient and RadialGradient.
pub enum NinePatchBorderSource { pub enum NinePatchBorderSource {
Image(ImageKey), Image(ImageKey),
Gradient(Gradient),
RadialGradient(RadialGradient),
} }
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
@ -333,8 +321,6 @@ pub struct NinePatchBorder {
pub enum BorderDetails { pub enum BorderDetails {
Normal(NormalBorder), Normal(NormalBorder),
NinePatch(NinePatchBorder), NinePatch(NinePatchBorder),
Gradient(GradientBorder),
RadialGradient(RadialGradientBorder),
} }
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]

Просмотреть файл

@ -27,8 +27,8 @@ use {StickyFrameDisplayItem, StickyOffsetBounds, TextDisplayItem, TransformStyle
use {YuvData, YuvImageDisplayItem}; use {YuvData, YuvImageDisplayItem};
// We don't want to push a long text-run. If a text-run is too long, split it into several parts. // We don't want to push a long text-run. If a text-run is too long, split it into several parts.
// This needs to be set to (renderer::MAX_VERTEX_TEXTURE_WIDTH - VECS_PER_PRIM_HEADER - VECS_PER_TEXT_RUN) * 2 // This needs to be set to (renderer::MAX_VERTEX_TEXTURE_WIDTH - VECS_PER_TEXT_RUN) * 2
pub const MAX_TEXT_RUN_LENGTH: usize = 2038; pub const MAX_TEXT_RUN_LENGTH: usize = 2040;
// We start at 2, because the root reference is always 0 and the root scroll node is always 1. // We start at 2, because the root reference is always 0 and the root scroll node is always 1.
const FIRST_CLIP_ID: usize = 2; const FIRST_CLIP_ID: usize = 2;

Просмотреть файл

@ -59,6 +59,7 @@ pub enum ImageFormat {
BGRA8 = 3, BGRA8 = 3,
RGBAF32 = 4, RGBAF32 = 4,
RG8 = 5, RG8 = 5,
RGBAI32 = 6,
} }
impl ImageFormat { impl ImageFormat {
@ -68,6 +69,7 @@ impl ImageFormat {
ImageFormat::BGRA8 => 4, ImageFormat::BGRA8 => 4,
ImageFormat::RGBAF32 => 16, ImageFormat::RGBAF32 => 16,
ImageFormat::RG8 => 2, ImageFormat::RG8 => 2,
ImageFormat::RGBAI32 => 16,
} }
} }
} }

Просмотреть файл

@ -1 +1 @@
cf98ad4d63729c678a7575eb9bce36794da5e270 cdfaaeb5f74e416f39af1081c9a676c752d23896

Просмотреть файл

@ -93,6 +93,7 @@ enum class ImageFormat : uint32_t {
BGRA8 = 3, BGRA8 = 3,
RGBAF32 = 4, RGBAF32 = 4,
RG8 = 5, RG8 = 5,
RGBAI32 = 6,
Sentinel /* this must be last for serialization purposes. */ Sentinel /* this must be last for serialization purposes. */
}; };

Просмотреть файл

@ -14,7 +14,7 @@ euclid = "0.17"
gleam = "0.5" gleam = "0.5"
glutin = "0.15" glutin = "0.15"
app_units = "0.6" app_units = "0.6"
image = "0.18" image = "0.19"
clap = { version = "2", features = ["yaml"] } clap = { version = "2", features = ["yaml"] }
lazy_static = "1" lazy_static = "1"
log = "0.4" log = "0.4"

Просмотреть файл

@ -67,6 +67,10 @@ args:
- no_batch: - no_batch:
long: no-batch long: no-batch
help: Disable batching of instanced draw calls help: Disable batching of instanced draw calls
- chase:
long: chase
help: Chase a particular primitive matching the local rect
takes_value: true
subcommands: subcommands:
- png: - png:

Просмотреть файл

@ -257,7 +257,7 @@ fn make_window(
}) })
.with_vsync(vsync); .with_vsync(vsync);
let window_builder = winit::WindowBuilder::new() let window_builder = winit::WindowBuilder::new()
.with_title("WRech") .with_title("WRench")
.with_multitouch() .with_multitouch()
.with_dimensions(size.width, size.height); .with_dimensions(size.width, size.height);
@ -351,7 +351,11 @@ impl RenderNotifier for Notifier {
self.tx.send(NotifierEvent::ShutDown).unwrap(); self.tx.send(NotifierEvent::ShutDown).unwrap();
} }
fn new_frame_ready(&self, _: DocumentId, _scrolled: bool, composite_needed: bool) { fn new_frame_ready(&self,
_: DocumentId,
_scrolled: bool,
composite_needed: bool,
_render_time: Option<u64>) {
if composite_needed { if composite_needed {
self.wake_up(); self.wake_up();
} }
@ -424,6 +428,20 @@ fn main() {
}) })
.unwrap_or(DeviceUintSize::new(1920, 1080)); .unwrap_or(DeviceUintSize::new(1920, 1080));
let zoom_factor = args.value_of("zoom").map(|z| z.parse::<f32>().unwrap()); let zoom_factor = args.value_of("zoom").map(|z| z.parse::<f32>().unwrap());
let chase_primitive = match args.value_of("chase") {
Some(s) => {
let mut items = s
.split(',')
.map(|s| s.parse::<f32>().unwrap())
.collect::<Vec<_>>();
let rect = LayoutRect::new(
LayoutPoint::new(items[0], items[1]),
LayoutSize::new(items[2], items[3]),
);
webrender::ChasePrimitive::LocalRect(rect)
},
None => webrender::ChasePrimitive::Nothing,
};
let mut events_loop = if args.is_present("headless") { let mut events_loop = if args.is_present("headless") {
None None
@ -462,6 +480,7 @@ fn main() {
args.is_present("precache"), args.is_present("precache"),
args.is_present("slow_subpixel"), args.is_present("slow_subpixel"),
zoom_factor.unwrap_or(1.0), zoom_factor.unwrap_or(1.0),
chase_primitive,
notifier, notifier,
); );
@ -634,17 +653,30 @@ fn render<'a>(
let path = PathBuf::from("../captures/wrench"); let path = PathBuf::from("../captures/wrench");
wrench.api.save_capture(path, CaptureBits::all()); wrench.api.save_capture(path, CaptureBits::all());
} }
VirtualKeyCode::Up => { VirtualKeyCode::Up | VirtualKeyCode::Down => {
let mut txn = Transaction::new();
let offset = match vk {
winit::VirtualKeyCode::Up => LayoutVector2D::new(0.0, 10.0),
winit::VirtualKeyCode::Down => LayoutVector2D::new(0.0, -10.0),
_ => unreachable!("Should not see non directional keys here.")
};
txn.scroll(ScrollLocation::Delta(offset), cursor_position);
txn.generate_frame();
wrench.api.send_transaction(wrench.document_id, txn);
do_frame = true;
}
VirtualKeyCode::Add => {
let current_zoom = wrench.get_page_zoom(); let current_zoom = wrench.get_page_zoom();
let new_zoom_factor = ZoomFactor::new(current_zoom.get() + 0.1); let new_zoom_factor = ZoomFactor::new(current_zoom.get() + 0.1);
wrench.set_page_zoom(new_zoom_factor); wrench.set_page_zoom(new_zoom_factor);
do_frame = true; do_frame = true;
} }
VirtualKeyCode::Down => { VirtualKeyCode::Subtract => {
let current_zoom = wrench.get_page_zoom(); let current_zoom = wrench.get_page_zoom();
let new_zoom_factor = ZoomFactor::new((current_zoom.get() - 0.1).max(0.1)); let new_zoom_factor = ZoomFactor::new((current_zoom.get() - 0.1).max(0.1));
wrench.set_page_zoom(new_zoom_factor); wrench.set_page_zoom(new_zoom_factor);
do_frame = true; do_frame = true;
} }

Просмотреть файл

@ -109,7 +109,10 @@ impl RenderNotifier for Notifier {
self.update(false); self.update(false);
} }
fn new_frame_ready(&self, _: DocumentId, scrolled: bool, _composite_needed: bool) { fn new_frame_ready(&self, _: DocumentId,
scrolled: bool,
_composite_needed: bool,
_render_time: Option<u64>) {
self.update(!scrolled); self.update(!scrolled);
} }
} }
@ -180,6 +183,7 @@ impl Wrench {
precache_shaders: bool, precache_shaders: bool,
disable_dual_source_blending: bool, disable_dual_source_blending: bool,
zoom_factor: f32, zoom_factor: f32,
chase_primitive: webrender::ChasePrimitive,
notifier: Option<Box<RenderNotifier>>, notifier: Option<Box<RenderNotifier>>,
) -> Self { ) -> Self {
println!("Shader override path: {:?}", shader_override_path); println!("Shader override path: {:?}", shader_override_path);
@ -212,6 +216,7 @@ impl Wrench {
precache_shaders, precache_shaders,
blob_image_renderer: Some(Box::new(blob::CheckerboardRenderer::new(callbacks.clone()))), blob_image_renderer: Some(Box::new(blob::CheckerboardRenderer::new(callbacks.clone()))),
disable_dual_source_blending, disable_dual_source_blending,
chase_primitive,
..Default::default() ..Default::default()
}; };

Просмотреть файл

@ -173,7 +173,8 @@ fn is_image_opaque(format: ImageFormat, bytes: &[u8]) -> bool {
} }
ImageFormat::RG8 => true, ImageFormat::RG8 => true,
ImageFormat::R8 => false, ImageFormat::R8 => false,
ImageFormat::RGBAF32 => unreachable!(), ImageFormat::RGBAF32 |
ImageFormat::RGBAI32 => unreachable!(),
} }
} }
@ -880,26 +881,28 @@ impl YamlFrameReader {
radius, radius,
})) }))
} }
"image" => { "image" | "gradient" | "radial-gradient" => {
let file = rsrc_path(&item["image-source"], &self.aux_dir);
let (image_key, _) = self
.add_or_get_image(&file, None, wrench);
let image_width = item["image-width"] let image_width = item["image-width"]
.as_i64() .as_i64()
.expect("border must have image-width"); .unwrap_or(info.rect.size.width as i64);
let image_height = item["image-height"] let image_height = item["image-height"]
.as_i64() .as_i64()
.expect("border must have image-height"); .unwrap_or(info.rect.size.height as i64);
let fill = item["fill"].as_bool().unwrap_or(false); let fill = item["fill"].as_bool().unwrap_or(false);
let slice = item["slice"].as_vec_u32().expect("border must have slice");
let slice = broadcast(&slice, 4); let slice = item["slice"].as_vec_u32();
let slice = match slice {
Some(slice) => broadcast(&slice, 4),
None => vec![widths.top as u32, widths.left as u32, widths.bottom as u32, widths.right as u32],
};
let outset = item["outset"] let outset = item["outset"]
.as_vec_f32() .as_vec_f32()
.expect("border must have outset"); .expect("border must have outset");
let outset = broadcast(&outset, 4); let outset = broadcast(&outset, 4);
let repeat_horizontal = match item["repeat-horizontal"] let repeat_horizontal = match item["repeat-horizontal"]
.as_str() .as_str()
.expect("border must have repeat-horizontal") .unwrap_or("stretch")
{ {
"stretch" => RepeatMode::Stretch, "stretch" => RepeatMode::Stretch,
"repeat" => RepeatMode::Repeat, "repeat" => RepeatMode::Repeat,
@ -909,7 +912,7 @@ impl YamlFrameReader {
}; };
let repeat_vertical = match item["repeat-vertical"] let repeat_vertical = match item["repeat-vertical"]
.as_str() .as_str()
.expect("border must have repeat-vertical") .unwrap_or("stretch")
{ {
"stretch" => RepeatMode::Stretch, "stretch" => RepeatMode::Stretch,
"repeat" => RepeatMode::Repeat, "repeat" => RepeatMode::Repeat,
@ -917,8 +920,27 @@ impl YamlFrameReader {
"space" => RepeatMode::Space, "space" => RepeatMode::Space,
s => panic!("Unknown box border image repeat mode {}", s), s => panic!("Unknown box border image repeat mode {}", s),
}; };
let source = match border_type {
"image" => {
let file = rsrc_path(&item["image-source"], &self.aux_dir);
let (image_key, _) = self
.add_or_get_image(&file, None, wrench);
NinePatchBorderSource::Image(image_key)
}
"gradient" => {
let gradient = self.to_gradient(dl, item);
NinePatchBorderSource::Gradient(gradient)
}
"radial-gradient" => {
let gradient = self.to_radial_gradient(dl, item);
NinePatchBorderSource::RadialGradient(gradient)
}
_ => unreachable!("Unexpected border type"),
};
Some(BorderDetails::NinePatch(NinePatchBorder { Some(BorderDetails::NinePatch(NinePatchBorder {
source: NinePatchBorderSource::Image(image_key), source,
width: image_width as u32, width: image_width as u32,
height: image_height as u32, height: image_height as u32,
slice: SideOffsets2D::new(slice[0], slice[1], slice[2], slice[3]), slice: SideOffsets2D::new(slice[0], slice[1], slice[2], slice[3]),
@ -928,28 +950,6 @@ impl YamlFrameReader {
outset: SideOffsets2D::new(outset[0], outset[1], outset[2], outset[3]), outset: SideOffsets2D::new(outset[0], outset[1], outset[2], outset[3]),
})) }))
} }
"gradient" => {
let gradient = self.to_gradient(dl, item);
let outset = item["outset"]
.as_vec_f32()
.expect("borders must have outset");
let outset = broadcast(&outset, 4);
Some(BorderDetails::Gradient(GradientBorder {
gradient,
outset: SideOffsets2D::new(outset[0], outset[1], outset[2], outset[3]),
}))
}
"radial-gradient" => {
let gradient = self.to_radial_gradient(dl, item);
let outset = item["outset"]
.as_vec_f32()
.expect("borders must have outset");
let outset = broadcast(&outset, 4);
Some(BorderDetails::RadialGradient(RadialGradientBorder {
gradient,
outset: SideOffsets2D::new(outset[0], outset[1], outset[2], outset[3]),
}))
}
_ => { _ => {
println!("Unable to parse border {:?}", item); println!("Unable to parse border {:?}", item);
None None
@ -1391,7 +1391,7 @@ impl YamlFrameReader {
clip_rect, clip_rect,
complex_clips, complex_clips,
image_mask, image_mask,
ScrollSensitivity::Script, ScrollSensitivity::ScriptAndInputEvents,
); );
if let Some(numeric_id) = numeric_id { if let Some(numeric_id) = numeric_id {
self.add_clip_id_mapping(numeric_id, real_id); self.add_clip_id_mapping(numeric_id, real_id);

Просмотреть файл

@ -885,14 +885,35 @@ impl YamlFrameWriter {
details.outset.left, details.outset.left,
]; ];
yaml_node(&mut v, "width", f32_vec_yaml(&widths, true)); yaml_node(&mut v, "width", f32_vec_yaml(&widths, true));
str_node(&mut v, "border-type", "image");
match details.source { match details.source {
NinePatchBorderSource::Image(image_key) => { NinePatchBorderSource::Image(image_key) => {
str_node(&mut v, "border-type", "image");
if let Some(path) = self.path_for_image(image_key) { if let Some(path) = self.path_for_image(image_key) {
path_node(&mut v, "image", &path); path_node(&mut v, "image", &path);
} }
} }
NinePatchBorderSource::Gradient(gradient) => {
str_node(&mut v, "gradient", "image");
point_node(&mut v, "start", &gradient.start_point);
point_node(&mut v, "end", &gradient.end_point);
let mut stops = vec![];
for stop in display_list.get(base.gradient_stops()) {
stops.push(Yaml::Real(stop.offset.to_string()));
stops.push(Yaml::String(color_to_string(stop.color)));
}
yaml_node(&mut v, "stops", Yaml::Array(stops));
bool_node(&mut v, "repeat", gradient.extend_mode == ExtendMode::Repeat);
}
NinePatchBorderSource::RadialGradient(gradient) => {
str_node(&mut v, "border-type", "radial-gradient");
radial_gradient_to_yaml(
&mut v,
&gradient,
base.gradient_stops(),
display_list
);
}
} }
u32_node(&mut v, "image-width", details.width); u32_node(&mut v, "image-width", details.width);
@ -924,59 +945,6 @@ impl YamlFrameWriter {
RepeatMode::Space => str_node(&mut v, "repeat-vertical", "space"), RepeatMode::Space => str_node(&mut v, "repeat-vertical", "space"),
}; };
} }
BorderDetails::Gradient(ref details) => {
let widths: Vec<f32> = vec![
item.widths.top,
item.widths.right,
item.widths.bottom,
item.widths.left,
];
let outset: Vec<f32> = vec![
details.outset.top,
details.outset.right,
details.outset.bottom,
details.outset.left,
];
yaml_node(&mut v, "width", f32_vec_yaml(&widths, true));
str_node(&mut v, "border-type", "gradient");
point_node(&mut v, "start", &details.gradient.start_point);
point_node(&mut v, "end", &details.gradient.end_point);
let mut stops = vec![];
for stop in display_list.get(base.gradient_stops()) {
stops.push(Yaml::Real(stop.offset.to_string()));
stops.push(Yaml::String(color_to_string(stop.color)));
}
yaml_node(&mut v, "stops", Yaml::Array(stops));
bool_node(
&mut v,
"repeat",
details.gradient.extend_mode == ExtendMode::Repeat,
);
yaml_node(&mut v, "outset", f32_vec_yaml(&outset, true));
}
BorderDetails::RadialGradient(ref details) => {
let widths: Vec<f32> = vec![
item.widths.top,
item.widths.right,
item.widths.bottom,
item.widths.left,
];
let outset: Vec<f32> = vec![
details.outset.top,
details.outset.right,
details.outset.bottom,
details.outset.left,
];
yaml_node(&mut v, "width", f32_vec_yaml(&widths, true));
str_node(&mut v, "border-type", "radial-gradient");
yaml_node(&mut v, "outset", f32_vec_yaml(&outset, true));
radial_gradient_to_yaml(
&mut v,
&details.gradient,
base.gradient_stops(),
display_list
);
}
} }
} }
BoxShadow(item) => { BoxShadow(item) => {