From 205a85ad05df3c25939ebb433868ddffac7abec4 Mon Sep 17 00:00:00 2001 From: Martin Robinson Date: Mon, 4 Dec 2017 17:53:16 +0100 Subject: [PATCH 1/2] Calculate local clipping rectangle per-primitive run Instead of using the hierarchical nature of the ClipScrollTree to calculate local clipping rectangles for primitives, do it when we are about to render a particular primitive run. This will allow us to handle custom clip chains while maintaining local clipping rectangle optimizations. It also allows us to greatly simplify a lot of shader code that used to deal with both clipping and scrolling nodes, as the local clipping rectangle is now bundled into the primitives local_clip_rect. TransformOrOffset is the main struct that handles the efficient transformation of clipping rectangles between compatible coordinate systems. It will avoid doing expensive matrix operations as much as possible, which should make these calculations cheaper -- important now that they are done per-primitive run. --- webrender/res/brush.glsl | 28 ++-- webrender/res/clip_shared.glsl | 14 +- webrender/res/cs_clip_border.glsl | 8 +- webrender/res/cs_clip_image.glsl | 4 +- webrender/res/cs_clip_rectangle.glsl | 6 +- webrender/res/prim_shared.glsl | 106 ++++++-------- webrender/res/ps_angle_gradient.glsl | 2 +- webrender/res/ps_border_corner.glsl | 4 +- webrender/res/ps_border_edge.glsl | 4 +- webrender/res/ps_gradient.glsl | 4 +- webrender/res/ps_image.glsl | 2 +- webrender/res/ps_line.glsl | 2 +- webrender/res/ps_radial_gradient.glsl | 2 +- webrender/res/ps_text_run.glsl | 27 ++-- webrender/res/ps_yuv_image.glsl | 2 +- webrender/src/clip_scroll_node.rs | 130 ++++++++---------- webrender/src/clip_scroll_tree.rs | 14 +- webrender/src/frame_builder.rs | 31 +++-- webrender/src/gpu_types.rs | 35 ++--- webrender/src/prim_store.rs | 62 ++++++++- webrender/src/render_task.rs | 1 + webrender/src/renderer.rs | 36 +++-- webrender/src/tiling.rs | 33 ++--- webrender/src/util.rs | 103 +++++++++++++- wrench/reftests/boxshadow/overlap1.png | Bin 7657 -> 10871 bytes .../reftests/clip/clip-3d-transform-ref.yaml | 8 ++ wrench/reftests/clip/clip-3d-transform.yaml | 30 ++++ .../clip/clip-45-degree-rotation-ref.png | Bin 2871 -> 4038 bytes wrench/reftests/clip/reftest.list | 1 + 29 files changed, 424 insertions(+), 275 deletions(-) create mode 100644 wrench/reftests/clip/clip-3d-transform-ref.yaml create mode 100644 wrench/reftests/clip/clip-3d-transform.yaml diff --git a/webrender/res/brush.glsl b/webrender/res/brush.glsl index e48f586498..ac1d57d077 100644 --- a/webrender/res/brush.glsl +++ b/webrender/res/brush.glsl @@ -20,7 +20,7 @@ void brush_vs( struct BrushInstance { int picture_address; int prim_address; - int clip_node_id; + int clip_chain_rect_index; int scroll_node_id; int clip_address; int z; @@ -29,11 +29,11 @@ struct BrushInstance { }; BrushInstance load_brush() { - BrushInstance bi; + BrushInstance bi; bi.picture_address = aData0.x; bi.prim_address = aData0.y; - bi.clip_node_id = aData0.z / 65536; + bi.clip_chain_rect_index = aData0.z / 65536; bi.scroll_node_id = aData0.z % 65536; bi.clip_address = aData0.w; bi.z = aData1.x; @@ -48,13 +48,14 @@ struct BrushPrimitive { RectWithSize local_clip_rect; }; -BrushPrimitive fetch_brush_primitive(int address) { +BrushPrimitive fetch_brush_primitive(int address, int clip_chain_rect_index) { vec4 data[2] = fetch_from_resource_cache_2(address); - BrushPrimitive prim = BrushPrimitive( - RectWithSize(data[0].xy, data[0].zw), - RectWithSize(data[1].xy, data[1].zw) - ); + 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; } @@ -66,7 +67,8 @@ void main(void) { // Load the geometry for this brush. For now, this is simply the // local rect of the primitive. In the future, this will support // loading segment rects, and other rect formats (glyphs). - BrushPrimitive brush_prim = fetch_brush_primitive(brush.prim_address); + BrushPrimitive brush_prim = + fetch_brush_primitive(brush.prim_address, brush.clip_chain_rect_index); // Fetch the segment of this brush primitive we are drawing. int segment_address = brush.prim_address + @@ -95,16 +97,16 @@ void main(void) { gl_Position = uTransform * vec4(device_pos, 0.0, 1.0); } else { VertexInfo vi; - Layer layer = fetch_layer(brush.clip_node_id, brush.scroll_node_id); + ClipScrollNode scroll_node = fetch_clip_scroll_node(brush.scroll_node_id); ClipArea clip_area = fetch_clip_area(brush.clip_address); // Write the normal vertex information out. - if (layer.is_axis_aligned) { + if (scroll_node.is_axis_aligned) { vi = write_vertex( local_segment_rect, brush_prim.local_clip_rect, float(brush.z), - layer, + scroll_node, pic_task, brush_prim.local_rect ); @@ -125,7 +127,7 @@ void main(void) { brush_prim.local_clip_rect, edge_aa_segment_mask, float(brush.z), - layer, + scroll_node, pic_task ); } diff --git a/webrender/res/clip_shared.glsl b/webrender/res/clip_shared.glsl index 90da9e7799..7da359ffdb 100644 --- a/webrender/res/clip_shared.glsl +++ b/webrender/res/clip_shared.glsl @@ -11,13 +11,13 @@ #define SEGMENT_CORNER_BR 4 in int aClipRenderTaskAddress; -in int aClipLayerAddress; +in int aScrollNodeId; in int aClipSegment; in ivec4 aClipDataResourceAddress; struct ClipMaskInstance { int render_task_address; - int layer_address; + int scroll_node_id; int segment; ivec2 clip_data_address; ivec2 resource_address; @@ -27,7 +27,7 @@ ClipMaskInstance fetch_clip_item() { ClipMaskInstance cmi; cmi.render_task_address = aClipRenderTaskAddress; - cmi.layer_address = aClipLayerAddress; + cmi.scroll_node_id = aScrollNodeId; cmi.segment = aClipSegment; cmi.clip_data_address = aClipDataResourceAddress.xy; cmi.resource_address = aClipDataResourceAddress.zw; @@ -49,13 +49,13 @@ RectWithSize intersect_rect(RectWithSize a, RectWithSize b) { // The transformed vertex function that always covers the whole clip area, // which is the intersection of all clip instances of a given primitive ClipVertexInfo write_clip_tile_vertex(RectWithSize local_clip_rect, - Layer layer, + ClipScrollNode scroll_node, ClipArea area) { vec2 actual_pos = area.screen_origin + aPosition.xy * area.common_data.task_rect.size; - vec4 layer_pos = get_layer_pos(actual_pos / uDevicePixelRatio, layer); + vec4 node_pos = get_node_pos(actual_pos / uDevicePixelRatio, scroll_node); - // compute the point position in side the layer, in CSS space + // compute the point position inside the scroll node, in CSS space vec2 vertex_pos = actual_pos + area.common_data.task_rect.p0 - area.screen_origin; @@ -64,7 +64,7 @@ ClipVertexInfo write_clip_tile_vertex(RectWithSize local_clip_rect, vLocalBounds = vec4(local_clip_rect.p0, local_clip_rect.p0 + local_clip_rect.size); - ClipVertexInfo vi = ClipVertexInfo(layer_pos.xyw, actual_pos, local_clip_rect); + ClipVertexInfo vi = ClipVertexInfo(node_pos.xyw, actual_pos, local_clip_rect); return vi; } diff --git a/webrender/res/cs_clip_border.glsl b/webrender/res/cs_clip_border.glsl index e2b5ae3b2a..a82708ffa4 100644 --- a/webrender/res/cs_clip_border.glsl +++ b/webrender/res/cs_clip_border.glsl @@ -64,7 +64,7 @@ BorderClipDot fetch_border_clip_dot(ivec2 address, int segment) { void main(void) { ClipMaskInstance cmi = fetch_clip_item(); ClipArea area = fetch_clip_area(cmi.render_task_address); - Layer layer = fetch_layer(cmi.layer_address, cmi.layer_address); + ClipScrollNode scroll_node = fetch_clip_scroll_node(cmi.scroll_node_id); // Fetch the header information for this corner clip. BorderCorner corner = fetch_border_corner(cmi.clip_data_address); @@ -120,7 +120,7 @@ void main(void) { vec2 pos = corner.rect.p0 + aPosition.xy * corner.rect.size; // Transform to world pos - vec4 world_pos = layer.transform * vec4(pos, 0.0, 1.0); + vec4 world_pos = scroll_node.transform * vec4(pos, 0.0, 1.0); world_pos.xyz /= world_pos.w; // Scale into device pixels. @@ -132,8 +132,8 @@ void main(void) { area.common_data.task_rect.p0; // Calculate the local space position for this vertex. - vec4 layer_pos = get_layer_pos(world_pos.xy, layer); - vPos = layer_pos.xyw; + vec4 node_pos = get_node_pos(world_pos.xy, scroll_node); + vPos = node_pos.xyw; gl_Position = uTransform * vec4(final_pos, 0.0, 1.0); } diff --git a/webrender/res/cs_clip_image.glsl b/webrender/res/cs_clip_image.glsl index 009896e17c..d8d703f16c 100644 --- a/webrender/res/cs_clip_image.glsl +++ b/webrender/res/cs_clip_image.glsl @@ -24,13 +24,13 @@ ImageMaskData fetch_mask_data(ivec2 address) { void main(void) { ClipMaskInstance cmi = fetch_clip_item(); ClipArea area = fetch_clip_area(cmi.render_task_address); - Layer layer = fetch_layer(cmi.layer_address, cmi.layer_address); + ClipScrollNode scroll_node = fetch_clip_scroll_node(cmi.scroll_node_id); ImageMaskData mask = fetch_mask_data(cmi.clip_data_address); RectWithSize local_rect = mask.local_rect; ImageResource res = fetch_image_resource_direct(cmi.resource_address); ClipVertexInfo vi = write_clip_tile_vertex(local_rect, - layer, + scroll_node, area); vPos = vi.local_pos; diff --git a/webrender/res/cs_clip_rectangle.glsl b/webrender/res/cs_clip_rectangle.glsl index c1a985ce1f..2dafddab0f 100644 --- a/webrender/res/cs_clip_rectangle.glsl +++ b/webrender/res/cs_clip_rectangle.glsl @@ -58,13 +58,11 @@ ClipData fetch_clip(ivec2 address) { void main(void) { ClipMaskInstance cmi = fetch_clip_item(); ClipArea area = fetch_clip_area(cmi.render_task_address); - Layer layer = fetch_layer(cmi.layer_address, cmi.layer_address); + ClipScrollNode scroll_node = fetch_clip_scroll_node(cmi.scroll_node_id); ClipData clip = fetch_clip(cmi.clip_data_address); RectWithSize local_rect = clip.rect.rect; - ClipVertexInfo vi = write_clip_tile_vertex(local_rect, - layer, - area); + ClipVertexInfo vi = write_clip_tile_vertex(local_rect, scroll_node, area); vPos = vi.local_pos; vClipMode = clip.rect.mode.x; diff --git a/webrender/res/prim_shared.glsl b/webrender/res/prim_shared.glsl index 153cab7767..193dcd79c7 100644 --- a/webrender/res/prim_shared.glsl +++ b/webrender/res/prim_shared.glsl @@ -69,7 +69,8 @@ vec4[2] fetch_from_resource_cache_2(int address) { #ifdef WR_VERTEX_SHADER -#define VECS_PER_LAYER 7 +#define VECS_PER_CLIP_SCROLL_NODE 5 +#define VECS_PER_LOCAL_CLIP_RECT 1 #define VECS_PER_RENDER_TASK 3 #define VECS_PER_PRIM_HEADER 2 #define VECS_PER_TEXT_RUN 3 @@ -77,6 +78,7 @@ vec4[2] fetch_from_resource_cache_2(int address) { #define VECS_PER_GRADIENT_STOP 2 uniform HIGHP_SAMPLER_FLOAT sampler2D sClipScrollNodes; +uniform HIGHP_SAMPLER_FLOAT sampler2D sLocalClipRects; uniform HIGHP_SAMPLER_FLOAT sampler2D sRenderTasks; // Instanced attributes @@ -143,9 +145,6 @@ vec4 fetch_from_resource_cache_1(int address) { struct ClipScrollNode { mat4 transform; - vec4 local_clip_rect; - vec2 reference_frame_relative_scroll_offset; - vec2 scroll_offset; bool is_axis_aligned; }; @@ -156,7 +155,7 @@ ClipScrollNode fetch_clip_scroll_node(int index) { // 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_LAYER); + ivec2 uv = get_fetch_uv(index, VECS_PER_CLIP_SCROLL_NODE); ivec2 uv0 = ivec2(uv.x + 0, uv.y); node.transform[0] = TEXEL_FETCH(sClipScrollNodes, uv0, 0, ivec2(0, 0)); @@ -164,41 +163,16 @@ ClipScrollNode fetch_clip_scroll_node(int index) { node.transform[2] = TEXEL_FETCH(sClipScrollNodes, uv0, 0, ivec2(2, 0)); node.transform[3] = TEXEL_FETCH(sClipScrollNodes, uv0, 0, ivec2(3, 0)); - vec4 clip_rect = TEXEL_FETCH(sClipScrollNodes, uv0, 0, ivec2(4, 0)); - node.local_clip_rect = clip_rect; - - vec4 offsets = TEXEL_FETCH(sClipScrollNodes, uv0, 0, ivec2(5, 0)); - node.reference_frame_relative_scroll_offset = offsets.xy; - node.scroll_offset = offsets.zw; - - vec4 misc = TEXEL_FETCH(sClipScrollNodes, uv0, 0, ivec2(6, 0)); + vec4 misc = TEXEL_FETCH(sClipScrollNodes, uv0, 0, ivec2(4, 0)); node.is_axis_aligned = misc.x == 0.0; return node; } -struct Layer { - mat4 transform; - RectWithSize local_clip_rect; - bool is_axis_aligned; -}; - -Layer fetch_layer(int clip_node_id, int scroll_node_id) { - ClipScrollNode clip_node = fetch_clip_scroll_node(clip_node_id); - ClipScrollNode scroll_node = fetch_clip_scroll_node(scroll_node_id); - - Layer layer; - layer.transform = scroll_node.transform; - - vec4 local_clip_rect = clip_node.local_clip_rect; - local_clip_rect.xy += clip_node.reference_frame_relative_scroll_offset; - local_clip_rect.xy -= scroll_node.reference_frame_relative_scroll_offset; - local_clip_rect.xy -= scroll_node.scroll_offset; - - layer.local_clip_rect = RectWithSize(local_clip_rect.xy, local_clip_rect.zw); - layer.is_axis_aligned = scroll_node.is_axis_aligned; - - return layer; +RectWithSize fetch_clip_chain_rect(int index) { + ivec2 uv = get_fetch_uv(index, VECS_PER_LOCAL_CLIP_RECT); + vec4 rect = TEXEL_FETCH(sLocalClipRects, uv, 0, ivec2(0, 0)); + return RectWithSize(rect.xy, rect.zw); } struct RenderTaskCommonData { @@ -401,7 +375,7 @@ struct PrimitiveInstance { int render_task_index; int clip_task_index; int scroll_node_id; - int clip_node_id; + int clip_chain_rect_index; int z; int user_data0; int user_data1; @@ -415,7 +389,7 @@ PrimitiveInstance fetch_prim_instance() { pi.specific_prim_address = pi.prim_address + VECS_PER_PRIM_HEADER; pi.render_task_index = aData0.y; pi.clip_task_index = aData0.z; - pi.clip_node_id = aData0.w / 65536; + pi.clip_chain_rect_index = aData0.w / 65536; pi.scroll_node_id = aData0.w % 65536; pi.z = aData1.x; pi.user_data0 = aData1.y; @@ -453,7 +427,7 @@ CompositeInstance fetch_composite_instance() { } struct Primitive { - Layer layer; + ClipScrollNode scroll_node; ClipArea clip_area; PictureTask task; RectWithSize local_rect; @@ -481,13 +455,15 @@ Primitive load_primitive() { Primitive prim; - prim.layer = fetch_layer(pi.clip_node_id, pi.scroll_node_id); + 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 = geom.local_clip_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; @@ -515,50 +491,50 @@ bool ray_plane(vec3 normal, vec3 point, vec3 ray_origin, vec3 ray_dir, out float // Apply the inverse transform "inv_transform" // to the reference point "ref" in CSS space, -// producing a local point on a layer plane, +// 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 layer plane with Z axis vector, + // 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 layer + 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 layer space. -vec4 get_layer_pos(vec2 pos, Layer layer) { - // get a point on the layer plane - vec4 ah = layer.transform * vec4(0.0, 0.0, 0.0, 1.0); +// 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 layer plane - mat4 inv_transform = inverse(layer.transform); + // get the normal to the scroll node plane + mat4 inv_transform = inverse(node.transform); vec3 n = transpose(mat3(inv_transform)) * vec3(0.0, 0.0, 1.0); return untransform(pos, n, a, inv_transform); } // Compute a snapping offset in world space (adjusted to pixel ratio), -// given local position on the layer and a snap rectangle. +// given local position on the scroll_node and a snap rectangle. vec2 compute_snap_offset(vec2 local_pos, - Layer layer, + ClipScrollNode scroll_node, RectWithSize snap_rect) { // 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, // how should it interact with sub-pixel snap rects when there - // is a layer transform with scale present? But it does fix + // is a scroll_node transform with scale present? But it does fix // the test cases we have in Servo that are failing without it // and seem better than not having this at all. snap_rect.size = max(snap_rect.size, vec2(1.0 / uDevicePixelRatio)); // Transform the snap corners to the world space. - vec4 world_snap_p0 = layer.transform * vec4(snap_rect.p0, 0.0, 1.0); - vec4 world_snap_p1 = layer.transform * vec4(snap_rect.p0 + snap_rect.size, 0.0, 1.0); + vec4 world_snap_p0 = scroll_node.transform * vec4(snap_rect.p0, 0.0, 1.0); + vec4 world_snap_p1 = scroll_node.transform * vec4(snap_rect.p0 + snap_rect.size, 0.0, 1.0); // Snap bounds in world coordinates, adjusted for pixel ratio. XY = top left, ZW = bottom right vec4 world_snap = uDevicePixelRatio * vec4(world_snap_p0.xy, world_snap_p1.xy) / vec4(world_snap_p0.ww, world_snap_p1.ww); @@ -579,7 +555,7 @@ struct VertexInfo { VertexInfo write_vertex(RectWithSize instance_rect, RectWithSize local_clip_rect, float z, - Layer layer, + ClipScrollNode scroll_node, PictureTask task, RectWithSize snap_rect) { @@ -587,13 +563,13 @@ VertexInfo write_vertex(RectWithSize instance_rect, vec2 local_pos = instance_rect.p0 + instance_rect.size * aPosition.xy; // Clamp to the two local clip rects. - vec2 clamped_local_pos = clamp_rect(clamp_rect(local_pos, local_clip_rect), layer.local_clip_rect); + vec2 clamped_local_pos = clamp_rect(local_pos, local_clip_rect); /// Compute the snapping offset. - vec2 snap_offset = compute_snap_offset(clamped_local_pos, layer, snap_rect); + vec2 snap_offset = compute_snap_offset(clamped_local_pos, scroll_node, snap_rect); // Transform the current vertex to world space. - vec4 world_pos = layer.transform * vec4(clamped_local_pos, 0.0, 1.0); + vec4 world_pos = scroll_node.transform * vec4(clamped_local_pos, 0.0, 1.0); // Convert the world positions to device pixel space. vec2 device_pos = world_pos.xy / world_pos.w * uDevicePixelRatio; @@ -633,19 +609,15 @@ VertexInfo write_transform_vertex(RectWithSize local_segment_rect, RectWithSize local_clip_rect, vec4 clip_edge_mask, float z, - Layer layer, + ClipScrollNode scroll_node, PictureTask task) { - // Calculate a clip rect from local clip + layer clip. + // Calculate a clip rect from local_rect + local clip RectWithEndpoint clip_rect = to_rect_with_endpoint(local_clip_rect); - clip_rect.p0 = clamp_rect(clip_rect.p0, layer.local_clip_rect); - clip_rect.p1 = clamp_rect(clip_rect.p1, layer.local_clip_rect); - - // Calculate a clip rect from local_rect + local clip + layer clip. RectWithEndpoint segment_rect = to_rect_with_endpoint(local_segment_rect); segment_rect.p0 = clamp(segment_rect.p0, clip_rect.p0, clip_rect.p1); segment_rect.p1 = clamp(segment_rect.p1, clip_rect.p0, clip_rect.p1); - // Calculate a clip rect from local_rect + local clip + layer clip. + // Calculate a clip rect from local_rect + local clip RectWithEndpoint prim_rect = to_rect_with_endpoint(local_prim_rect); prim_rect.p0 = clamp(prim_rect.p0, clip_rect.p0, clip_rect.p1); prim_rect.p1 = clamp(prim_rect.p1, clip_rect.p0, clip_rect.p1); @@ -666,7 +638,7 @@ VertexInfo write_transform_vertex(RectWithSize local_segment_rect, vec2 local_pos = local_segment_rect.p0 + local_segment_rect.size * aPosition.xy; // Transform the current vertex to the world cpace. - vec4 world_pos = layer.transform * vec4(local_pos, 0.0, 1.0); + vec4 world_pos = scroll_node.transform * vec4(local_pos, 0.0, 1.0); // Convert the world positions to device pixel space. vec2 device_pos = world_pos.xy / world_pos.w * uDevicePixelRatio; @@ -698,7 +670,7 @@ VertexInfo write_transform_vertex_primitive(Primitive prim) { prim.local_clip_rect, vec4(0.0), prim.z, - prim.layer, + prim.scroll_node, prim.task ); } diff --git a/webrender/res/ps_angle_gradient.glsl b/webrender/res/ps_angle_gradient.glsl index 7056fc5c2b..81abc6bc4d 100644 --- a/webrender/res/ps_angle_gradient.glsl +++ b/webrender/res/ps_angle_gradient.glsl @@ -23,7 +23,7 @@ void main(void) { VertexInfo vi = write_vertex(prim.local_rect, prim.local_clip_rect, prim.z, - prim.layer, + prim.scroll_node, prim.task, prim.local_rect); diff --git a/webrender/res/ps_border_corner.glsl b/webrender/res/ps_border_corner.glsl index 1064543fb9..bea4ffcfea 100644 --- a/webrender/res/ps_border_corner.glsl +++ b/webrender/res/ps_border_corner.glsl @@ -303,13 +303,13 @@ void main(void) { prim.local_clip_rect, vec4(1.0), prim.z, - prim.layer, + prim.scroll_node, prim.task); #else VertexInfo vi = write_vertex(segment_rect, prim.local_clip_rect, prim.z, - prim.layer, + prim.scroll_node, prim.task, prim.local_rect); #endif diff --git a/webrender/res/ps_border_edge.glsl b/webrender/res/ps_border_edge.glsl index b7a0087217..7dc0708285 100644 --- a/webrender/res/ps_border_edge.glsl +++ b/webrender/res/ps_border_edge.glsl @@ -221,13 +221,13 @@ void main(void) { prim.local_clip_rect, vec4(1.0), prim.z, - prim.layer, + prim.scroll_node, prim.task); #else VertexInfo vi = write_vertex(segment_rect, prim.local_clip_rect, prim.z, - prim.layer, + prim.scroll_node, prim.task, prim.local_rect); #endif diff --git a/webrender/res/ps_gradient.glsl b/webrender/res/ps_gradient.glsl index 1aec09fc9d..390a250581 100644 --- a/webrender/res/ps_gradient.glsl +++ b/webrender/res/ps_gradient.glsl @@ -72,7 +72,7 @@ void main(void) { prim.local_clip_rect, vec4(1.0), prim.z, - prim.layer, + prim.scroll_node, prim.task); vLocalPos = vi.local_pos; vec2 f = (vi.local_pos.xy - prim.local_rect.p0) / prim.local_rect.size; @@ -80,7 +80,7 @@ void main(void) { VertexInfo vi = write_vertex(segment_rect, prim.local_clip_rect, prim.z, - prim.layer, + prim.scroll_node, prim.task, prim.local_rect); diff --git a/webrender/res/ps_image.glsl b/webrender/res/ps_image.glsl index cfff1c3162..fe36b9aaf1 100644 --- a/webrender/res/ps_image.glsl +++ b/webrender/res/ps_image.glsl @@ -34,7 +34,7 @@ void main(void) { VertexInfo vi = write_vertex(prim.local_rect, prim.local_clip_rect, prim.z, - prim.layer, + prim.scroll_node, prim.task, prim.local_rect); vLocalPos = vi.local_pos - prim.local_rect.p0; diff --git a/webrender/res/ps_line.glsl b/webrender/res/ps_line.glsl index d583d52785..dc4f4286f0 100644 --- a/webrender/res/ps_line.glsl +++ b/webrender/res/ps_line.glsl @@ -114,7 +114,7 @@ void main(void) { VertexInfo vi = write_vertex(prim.local_rect, prim.local_clip_rect, prim.z, - prim.layer, + prim.scroll_node, prim.task, prim.local_rect); #endif diff --git a/webrender/res/ps_radial_gradient.glsl b/webrender/res/ps_radial_gradient.glsl index f7d65485f5..46483ee5b0 100644 --- a/webrender/res/ps_radial_gradient.glsl +++ b/webrender/res/ps_radial_gradient.glsl @@ -25,7 +25,7 @@ void main(void) { VertexInfo vi = write_vertex(prim.local_rect, prim.local_clip_rect, prim.z, - prim.layer, + prim.scroll_node, prim.task, prim.local_rect); diff --git a/webrender/res/ps_text_run.glsl b/webrender/res/ps_text_run.glsl index 6d49745c45..3c0dd90694 100644 --- a/webrender/res/ps_text_run.glsl +++ b/webrender/res/ps_text_run.glsl @@ -29,11 +29,11 @@ varying vec4 vUvClip; VertexInfo write_text_vertex(vec2 clamped_local_pos, RectWithSize local_clip_rect, float z, - Layer layer, + ClipScrollNode scroll_node, PictureTask task, RectWithSize snap_rect) { // Transform the current vertex to world space. - vec4 world_pos = layer.transform * vec4(clamped_local_pos, 0.0, 1.0); + vec4 world_pos = scroll_node.transform * vec4(clamped_local_pos, 0.0, 1.0); // Convert the world positions to device pixel space. vec2 device_pos = world_pos.xy / world_pos.w * uDevicePixelRatio; @@ -45,12 +45,12 @@ VertexInfo write_text_vertex(vec2 clamped_local_pos, #ifdef WR_FEATURE_GLYPH_TRANSFORM // For transformed subpixels, we just need to align the glyph origin to a device pixel. - // Only check the layer transform's translation since the scales and axes match. - vec2 world_snap_p0 = snap_rect.p0 + layer.transform[3].xy * uDevicePixelRatio; + // Only check the scroll node transform's translation since the scales and axes match. + vec2 world_snap_p0 = snap_rect.p0 + scroll_node.transform[3].xy * uDevicePixelRatio; final_pos += floor(world_snap_p0 + 0.5) - world_snap_p0; #elif !defined(WR_FEATURE_TRANSFORM) - // Compute the snapping offset only if the layer transform is axis-aligned. - final_pos += compute_snap_offset(clamped_local_pos, layer, snap_rect); + // Compute the snapping offset only if the scroll node transform is axis-aligned. + final_pos += compute_snap_offset(clamped_local_pos, scroll_node, snap_rect); #endif gl_Position = uTransform * vec4(final_pos, z, 1.0); @@ -74,7 +74,7 @@ void main(void) { #ifdef WR_FEATURE_GLYPH_TRANSFORM // Transform from local space to glyph space. - mat2 transform = mat2(prim.layer.transform) * uDevicePixelRatio; + mat2 transform = mat2(prim.scroll_node.transform) * uDevicePixelRatio; // Compute the glyph rect in glyph space. RectWithSize glyph_rect = RectWithSize(res.offset + transform * (text.offset + glyph.offset), @@ -87,15 +87,12 @@ void main(void) { // Select the corner of the glyph's local space rect that we are processing. vec2 local_pos = local_rect.p0 + local_rect.size * aPosition.xy; - // Calculate a combined local clip rect. - RectWithSize local_clip_rect = intersect_rects(prim.local_clip_rect, prim.layer.local_clip_rect); - // 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. // Otherwise, fall back to clamping the glyph's local rect to the local clip rect. - local_pos = rect_inside_rect(local_rect, local_clip_rect) ? + local_pos = rect_inside_rect(local_rect, prim.local_clip_rect) ? inv * (glyph_rect.p0 + glyph_rect.size * aPosition.xy) : - clamp_rect(local_pos, local_clip_rect); + clamp_rect(local_pos, prim.local_clip_rect); #else // Scale from glyph space to local space. float scale = res.scale / uDevicePixelRatio; @@ -107,14 +104,14 @@ void main(void) { // Select the corner of the glyph rect that we are processing. vec2 local_pos = glyph_rect.p0 + glyph_rect.size * aPosition.xy; - // Clamp to the two local clip rects. - local_pos = clamp_rect(clamp_rect(local_pos, prim.local_clip_rect), prim.layer.local_clip_rect); + // Clamp to the local clip rect. + local_pos = clamp_rect(local_pos, prim.local_clip_rect); #endif VertexInfo vi = write_text_vertex(local_pos, prim.local_clip_rect, prim.z, - prim.layer, + prim.scroll_node, prim.task, glyph_rect); diff --git a/webrender/res/ps_yuv_image.glsl b/webrender/res/ps_yuv_image.glsl index a82ea142f6..e8a51016e6 100644 --- a/webrender/res/ps_yuv_image.glsl +++ b/webrender/res/ps_yuv_image.glsl @@ -43,7 +43,7 @@ void main(void) { VertexInfo vi = write_vertex(prim.local_rect, prim.local_clip_rect, prim.z, - prim.layer, + prim.scroll_node, prim.task, prim.local_rect); vLocalPos = vi.local_pos - prim.local_rect.p0; diff --git a/webrender/src/clip_scroll_node.rs b/webrender/src/clip_scroll_node.rs index a9bad59dbc..f43d358778 100644 --- a/webrender/src/clip_scroll_node.rs +++ b/webrender/src/clip_scroll_node.rs @@ -2,10 +2,10 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use api::{ClipId, DeviceIntRect, LayerPixel, LayerPoint, LayerRect, LayerSize}; -use api::{LayerToScrollTransform, LayerToWorldTransform, LayerVector2D, LayoutVector2D, PipelineId}; -use api::{ScrollClamping, ScrollEventPhase, ScrollLocation, ScrollSensitivity}; -use api::{DevicePixelScale, LayoutTransform, PropertyBinding, StickyOffsetBounds, WorldPoint}; +use api::{ClipId, DeviceIntRect, DevicePixelScale, LayerPixel, LayerPoint, LayerRect, LayerSize}; +use api::{LayerToWorldTransform, LayerTransform, LayerVector2D, LayoutTransform, LayoutVector2D}; +use api::{PipelineId, PropertyBinding, ScrollClamping, ScrollEventPhase, ScrollLocation}; +use api::{ScrollSensitivity, StickyOffsetBounds, WorldPoint}; use clip::{ClipSourcesHandle, ClipStore}; use clip_scroll_tree::{CoordinateSystemId, TransformUpdateState}; use euclid::SideOffsets2D; @@ -17,7 +17,7 @@ use resource_cache::ResourceCache; use scene::SceneProperties; use spring::{DAMPING, STIFFNESS, Spring}; use std::rc::Rc; -use util::{MatrixHelpers, MaxRect, TransformedRectKind}; +use util::{MatrixHelpers, MaxRect, TransformOrOffset, TransformedRectKind}; #[cfg(target_os = "macos")] const CAN_OVERSCROLL: bool = true; @@ -122,6 +122,11 @@ pub struct ClipScrollNode { /// The axis-aligned coordinate system id of this node. pub coordinate_system_id: CoordinateSystemId, + /// The transformation from the coordinate system which established our compatible coordinate + /// system (same coordinate system id) and us. This can change via scroll offsets and via new + /// reference frame transforms. + pub coordinate_system_relative_transform: TransformOrOffset, + /// A linear ID / index of this clip-scroll node. Used as a reference to /// pass to shaders, to allow them to fetch a given clip-scroll node. pub node_data_index: ClipScrollNodeIndex, @@ -146,6 +151,7 @@ impl ClipScrollNode { clip_chain_node: None, combined_clip_outer_bounds: DeviceIntRect::max_rect(), coordinate_system_id: CoordinateSystemId(0), + coordinate_system_relative_transform: TransformOrOffset::zero(), node_data_index: ClipScrollNodeIndex(0), } } @@ -187,10 +193,11 @@ impl ClipScrollNode { ) -> Self { let identity = LayoutTransform::identity(); let info = ReferenceFrameInfo { - resolved_transform: LayerToScrollTransform::identity(), + resolved_transform: LayerTransform::identity(), source_transform: source_transform.unwrap_or(PropertyBinding::Value(identity)), source_perspective: source_perspective.unwrap_or(identity), origin_in_parent_reference_frame, + invertible: true, }; Self::new(pipeline_id, parent_id, frame_rect, NodeType::ReferenceFrame(info)) } @@ -271,53 +278,19 @@ impl ClipScrollNode { self.clip_chain_node = None; } - pub fn push_gpu_node_data( - &mut self, - state: &TransformUpdateState, - node_data: &mut Vec - ) { + pub fn push_gpu_node_data(&mut self, node_data: &mut Vec) { if self.combined_clip_outer_bounds.is_empty() { node_data.push(ClipScrollNodeData::invalid()); return; } - let local_clip_rect = match self.node_type { - _ if self.world_content_transform.has_perspective_component() => LayerRect::max_rect(), - NodeType::ReferenceFrame(ref info) => { - info.resolved_transform.with_destination::() - .inverse_rect_footprint(&state.parent_combined_viewport_rect) - } - NodeType::Clip(_) | NodeType::ScrollFrame(_) => { - state.parent_combined_viewport_rect - .intersection(&self.local_clip_rect) - .unwrap_or(LayerRect::zero()) - } - NodeType::StickyFrame(ref sticky_info) => { - state.parent_combined_viewport_rect - .translate(&-sticky_info.current_offset) - .intersection(&self.local_clip_rect) - .unwrap_or(LayerRect::zero()) - } - }; - let transform_kind = if self.world_content_transform.preserves_2d_axis_alignment() { TransformedRectKind::AxisAligned } else { TransformedRectKind::Complex }; - - let reference_frame_relative_scroll_offset = match self.node_type { - NodeType::ReferenceFrame(_) => LayerVector2D::zero(), - NodeType::Clip(_) | NodeType::ScrollFrame(_) => state.parent_accumulated_scroll_offset, - NodeType::StickyFrame(ref sticky_info) => - state.parent_accumulated_scroll_offset + sticky_info.current_offset, - }; - let data = ClipScrollNodeData { transform: self.world_content_transform, - local_clip_rect, - reference_frame_relative_scroll_offset, - scroll_offset: self.scroll_offset(), transform_kind: transform_kind as u32 as f32, padding: [0.0; 3], }; @@ -343,17 +316,19 @@ impl ClipScrollNode { return; } + self.update_transform(state, next_coordinate_system_id, scene_properties); + // If this node is a reference frame, we check if the determinant is 0, which means it // has a non-invertible matrix. For non-reference-frames we assume that they will // produce only additional translations which should be invertible. - if self.node_type.is_reference_frame() { - if self.world_content_transform.determinant() == 0.0 { + match self.node_type { + NodeType::ReferenceFrame(info) if !info.invertible => { self.update_to_empty_rect(); return; } + _ => {}, } - self.update_transform(state, next_coordinate_system_id, scene_properties); self.update_clip_work_item( state, device_pixel_scale, @@ -424,12 +399,15 @@ impl ClipScrollNode { state.combined_inner_clip_bounds = combined_inner_screen_rect; self.combined_clip_outer_bounds = combined_outer_screen_rect; + let local_clip_rect = self.coordinate_system_relative_transform.apply(&self.local_clip_rect); + self.clip_chain_node = Some(Rc::new(ClipChainNode { work_item: ClipWorkItem { scroll_node_data_index: self.node_data_index, clip_sources: clip_sources_handle.weak(), coordinate_system_id: state.current_coordinate_system_id, }, + local_clip_rect, screen_inner_rect, combined_outer_screen_rect, combined_inner_screen_rect, @@ -479,6 +457,10 @@ impl ClipScrollNode { self.world_viewport_transform }; + let added_offset = state.parent_accumulated_scroll_offset + sticky_offset + scroll_offset; + self.coordinate_system_relative_transform = + state.coordinate_system_relative_transform.offset(added_offset); + match self.node_type { NodeType::StickyFrame(ref mut info) => info.current_offset = sticky_offset, _ => {}, @@ -500,30 +482,41 @@ impl ClipScrollNode { // Resolve the transform against any property bindings. let source_transform = scene_properties.resolve_layout_transform(&info.source_transform); - info.resolved_transform = LayerToScrollTransform::create_translation( + info.resolved_transform = LayerTransform::create_translation( info.origin_in_parent_reference_frame.x, info.origin_in_parent_reference_frame.y, 0.0 ).pre_mul(&source_transform) .pre_mul(&info.source_perspective); - if !info.resolved_transform.preserves_2d_axis_alignment() || - info.resolved_transform.has_perspective_component() { - state.current_coordinate_system_id = *next_coordinate_system_id; - next_coordinate_system_id.advance(); - } - self.coordinate_system_id = state.current_coordinate_system_id; - // The transformation for this viewport in world coordinates is the transformation for // our parent reference frame, plus any accumulated scrolling offsets from nodes // between our reference frame and this node. Finally, we also include // whatever local transformation this reference frame provides. This can be combined // with the local_viewport_rect to get its position in world space. - self.world_viewport_transform = state - .parent_reference_frame_transform - .pre_translate(state.parent_accumulated_scroll_offset.to_3d()) - .pre_mul(&info.resolved_transform.with_destination::()); + let relative_transform = info.resolved_transform + .post_translate(state.parent_accumulated_scroll_offset.to_3d()); + self.world_viewport_transform = state.parent_reference_frame_transform + .pre_mul(&relative_transform.with_destination::()); self.world_content_transform = self.world_viewport_transform; + + info.invertible = relative_transform.determinant() != 0.0; + if !info.invertible { + return; + } + + // Try to update our compatible coordinate system transform. If we cannot, start a new + // incompatible coordinate system. + match state.coordinate_system_relative_transform.update(relative_transform) { + Some(offset) => self.coordinate_system_relative_transform = offset, + None => { + self.coordinate_system_relative_transform = TransformOrOffset::zero(); + state.current_coordinate_system_id = *next_coordinate_system_id; + next_coordinate_system_id.advance(); + } + } + + self.coordinate_system_id = state.current_coordinate_system_id; } fn calculate_sticky_offset( @@ -635,21 +628,13 @@ impl ClipScrollNode { sticky_offset } - pub fn prepare_state_for_children( - &self, - state: &mut TransformUpdateState, - node_data: &Vec - ) { + pub fn prepare_state_for_children(&self, state: &mut TransformUpdateState) { if self.combined_clip_outer_bounds.is_empty() { - state.parent_combined_viewport_rect = LayerRect::zero(); state.combined_outer_clip_bounds = DeviceIntRect::zero(); state.parent_clip_chain = None; return; } - let combined_local_viewport_rect = - node_data[self.node_data_index.0 as usize].local_clip_rect; - // The transformation we are passing is the transformation of the parent // reference frame and the offset is the accumulated offset of all the nodes // between us and the parent reference frame. If we are a reference frame, @@ -657,19 +642,16 @@ impl ClipScrollNode { match self.node_type { NodeType::ReferenceFrame(ref info) => { state.parent_reference_frame_transform = self.world_viewport_transform; - state.parent_combined_viewport_rect = combined_local_viewport_rect; state.parent_accumulated_scroll_offset = LayerVector2D::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(..) => { - state.parent_combined_viewport_rect = combined_local_viewport_rect; - }, + NodeType::Clip(..) => { } NodeType::ScrollFrame(ref scrolling) => { - state.parent_combined_viewport_rect = - combined_local_viewport_rect.translate(&-scrolling.offset); state.parent_accumulated_scroll_offset = scrolling.offset + state.parent_accumulated_scroll_offset; state.nearest_scrolling_ancestor_offset = scrolling.offset; @@ -679,7 +661,6 @@ impl ClipScrollNode { // 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_combined_viewport_rect = combined_local_viewport_rect; state.parent_accumulated_scroll_offset = info.current_offset + state.parent_accumulated_scroll_offset; } @@ -898,7 +879,7 @@ impl ScrollingState { pub struct ReferenceFrameInfo { /// The transformation that establishes this reference frame, relative to the parent /// reference frame. The origin of the reference frame is included in the transformation. - pub resolved_transform: LayerToScrollTransform, + pub resolved_transform: LayerTransform, /// The source transform and perspective matrices provided by the stacking context /// that forms this reference frame. We maintain the property binding information @@ -911,4 +892,7 @@ pub struct ReferenceFrameInfo { /// origin of this reference frame. This is already rolled into the `transform' property, but /// we also store it here to properly transform the viewport for sticky positioning. pub origin_in_parent_reference_frame: LayerVector2D, + + /// True if the resolved transform is invertible. + pub invertible: bool, } diff --git a/webrender/src/clip_scroll_tree.rs b/webrender/src/clip_scroll_tree.rs index 09c67dfe0f..cfcd90efd3 100644 --- a/webrender/src/clip_scroll_tree.rs +++ b/webrender/src/clip_scroll_tree.rs @@ -14,7 +14,7 @@ use print_tree::{PrintTree, PrintTreePrinter}; use render_task::ClipChain; use resource_cache::ResourceCache; use scene::SceneProperties; -use util::MaxRect; +use util::{MaxRect, TransformOrOffset}; pub type ScrollStates = FastHashMap; @@ -82,6 +82,9 @@ pub struct TransformUpdateState { /// display list item, since optimizations can usually only be done among /// coordinate systems which are relatively axis aligned. pub current_coordinate_system_id: CoordinateSystemId, + + /// Transform from the coordinate system that started this compatible coordinate system. + pub coordinate_system_relative_transform: TransformOrOffset, } impl ClipScrollTree { @@ -366,6 +369,7 @@ impl ClipScrollTree { combined_outer_clip_bounds: *screen_rect, combined_inner_clip_bounds: DeviceIntRect::max_rect(), current_coordinate_system_id: CoordinateSystemId::root(), + coordinate_system_relative_transform: TransformOrOffset::zero(), }; let mut next_coordinate_system_id = state.current_coordinate_system_id.next(); self.update_node( @@ -415,13 +419,13 @@ impl ClipScrollTree { scene_properties, ); - node.push_gpu_node_data(&state, gpu_node_data); + node.push_gpu_node_data(gpu_node_data); - if node.children.is_empty() { - return; + if node.children.is_empty() || node.combined_clip_outer_bounds.is_empty() { + return } - node.prepare_state_for_children(&mut state, gpu_node_data); + node.prepare_state_for_children(&mut state); node.children.clone() }; diff --git a/webrender/src/frame_builder.rs b/webrender/src/frame_builder.rs index 6bf0d72d87..783b66d4b2 100644 --- a/webrender/src/frame_builder.rs +++ b/webrender/src/frame_builder.rs @@ -2,17 +2,15 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use api::{BorderDetails, BorderDisplayItem, BuiltDisplayList}; -use api::{ClipAndScrollInfo, ClipId, ColorF, ColorU, PropertyBinding}; -use api::{DeviceIntPoint, DeviceUintPoint, DeviceUintRect, DeviceUintSize}; -use api::{DevicePixelScale, LayerToWorldScale, WorldRect}; -use api::{DocumentLayer, ExtendMode, FontRenderMode, LayoutTransform}; -use api::{GlyphInstance, GlyphOptions, GradientStop, HitTestFlags, HitTestItem, HitTestResult}; -use api::{ImageKey, ImageRendering, ItemRange, ItemTag, LayerPoint, LayerPrimitiveInfo, LayerRect}; -use api::{LayerSize, LayerToScrollTransform, LayerVector2D, LayoutVector2D, LineOrientation}; -use api::{LineStyle, LocalClip, PipelineId, RepeatMode}; -use api::{ScrollSensitivity, Shadow, TileOffset, TransformStyle}; -use api::{PremultipliedColorF, WorldPoint, YuvColorSpace, YuvData}; +use api::{BorderDetails, BorderDisplayItem, BuiltDisplayList, ClipAndScrollInfo, ClipId, ColorF}; +use api::{ColorU, DeviceIntPoint, DevicePixelScale, DeviceUintPoint, DeviceUintRect}; +use api::{DeviceUintSize, DocumentLayer, ExtendMode, FontRenderMode, GlyphInstance, GlyphOptions}; +use api::{GradientStop, HitTestFlags, HitTestItem, HitTestResult, ImageKey, ImageRendering}; +use api::{ItemRange, ItemTag, LayerPoint, LayerPrimitiveInfo, LayerRect, LayerSize}; +use api::{LayerToWorldScale, LayerTransform, LayerVector2D, LayoutTransform, LayoutVector2D}; +use api::{LineOrientation, LineStyle, LocalClip, PipelineId, PremultipliedColorF, PropertyBinding}; +use api::{RepeatMode, ScrollSensitivity, Shadow, TileOffset, TransformStyle, WorldPoint}; +use api::{WorldRect, YuvColorSpace, YuvData}; use app_units::Au; use border::ImageBorderSegment; use clip::{ClipRegion, ClipSource, ClipSources, ClipStore, Contains}; @@ -609,7 +607,7 @@ impl FrameBuilder { let root_id = clip_scroll_tree.root_reference_frame_id(); if let Some(root_node) = clip_scroll_tree.nodes.get_mut(&root_id) { if let NodeType::ReferenceFrame(ref mut info) = root_node.node_type { - info.resolved_transform = LayerToScrollTransform::create_translation( + info.resolved_transform = LayerTransform::create_translation( viewport_offset.x, viewport_offset.y, 0.0, @@ -1578,6 +1576,7 @@ impl FrameBuilder { device_pixel_scale: DevicePixelScale, scene_properties: &SceneProperties, node_data: &[ClipScrollNodeData], + local_rects: &mut Vec, ) -> Option { profile_scope!("cull"); @@ -1621,6 +1620,7 @@ impl FrameBuilder { SpecificPrimitiveIndex(0), &self.screen_rect.to_i32(), node_data, + local_rects, ); let pic = &mut self.prim_store.cpu_pictures[0]; @@ -1700,6 +1700,11 @@ impl FrameBuilder { gpu_cache.begin_frame(); let mut node_data = Vec::with_capacity(clip_scroll_tree.nodes.len()); + let total_prim_runs = + self.prim_store.cpu_pictures.iter().fold(1, |count, ref pic| count + pic.runs.len()); + let mut clip_chain_local_clip_rects = Vec::with_capacity(total_prim_runs); + clip_chain_local_clip_rects.push(LayerRect::max_rect()); + clip_scroll_tree.update_tree( &self.screen_rect.to_i32(), device_pixel_scale, @@ -1725,6 +1730,7 @@ impl FrameBuilder { device_pixel_scale, scene_properties, &node_data, + &mut clip_chain_local_clip_rects, ); let mut passes = Vec::new(); @@ -1788,6 +1794,7 @@ impl FrameBuilder { profile_counters, passes, node_data, + clip_chain_local_clip_rects, render_tasks, deferred_resolves, gpu_cache_updates: Some(gpu_cache_updates), diff --git a/webrender/src/gpu_types.rs b/webrender/src/gpu_types.rs index 3a6483c6de..ac48a32dda 100644 --- a/webrender/src/gpu_types.rs +++ b/webrender/src/gpu_types.rs @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use api::{LayerVector2D, LayerRect, LayerToWorldTransform}; +use api::{LayerRect, LayerToWorldTransform}; use gpu_cache::GpuCacheAddress; use render_task::RenderTaskAddress; @@ -47,7 +47,7 @@ pub struct SimplePrimitiveInstance { pub specific_prim_address: GpuCacheAddress, pub task_address: RenderTaskAddress, pub clip_task_address: RenderTaskAddress, - pub clip_id: ClipScrollNodeIndex, + pub clip_chain_rect_index: ClipChainRectIndex, pub scroll_id: ClipScrollNodeIndex, pub z_sort_index: i32, } @@ -57,7 +57,7 @@ impl SimplePrimitiveInstance { specific_prim_address: GpuCacheAddress, task_address: RenderTaskAddress, clip_task_address: RenderTaskAddress, - clip_id: ClipScrollNodeIndex, + clip_chain_rect_index: ClipChainRectIndex, scroll_id: ClipScrollNodeIndex, z_sort_index: i32, ) -> SimplePrimitiveInstance { @@ -65,7 +65,7 @@ impl SimplePrimitiveInstance { specific_prim_address, task_address, clip_task_address, - clip_id, + clip_chain_rect_index, scroll_id, z_sort_index, } @@ -77,7 +77,7 @@ impl SimplePrimitiveInstance { self.specific_prim_address.as_int(), self.task_address.0 as i32, self.clip_task_address.0 as i32, - ((self.clip_id.0 as i32) << 16) | self.scroll_id.0 as i32, + ((self.clip_chain_rect_index.0 as i32) << 16) | self.scroll_id.0 as i32, self.z_sort_index, data0, data1, @@ -150,7 +150,7 @@ impl From for PrimitiveInstance { pub struct BrushInstance { pub picture_address: RenderTaskAddress, pub prim_address: GpuCacheAddress, - pub clip_id: ClipScrollNodeIndex, + pub clip_chain_rect_index: ClipChainRectIndex, pub scroll_id: ClipScrollNodeIndex, pub clip_task_address: RenderTaskAddress, pub z: i32, @@ -165,7 +165,7 @@ impl From for PrimitiveInstance { data: [ instance.picture_address.0 as i32, instance.prim_address.as_int(), - ((instance.clip_id.0 as i32) << 16) | instance.scroll_id.0 as i32, + ((instance.clip_chain_rect_index.0 as i32) << 16) | instance.scroll_id.0 as i32, instance.clip_task_address.0 as i32, instance.z, instance.segment_index, @@ -195,20 +195,6 @@ pub struct ClipScrollNodeIndex(pub u32); #[repr(C)] pub struct ClipScrollNodeData { pub transform: LayerToWorldTransform, - - /// Viewport rectangle clipped against parent viewport rectangles. This is - /// in the coordinate system of the node origin. Precisely, it combines the - /// local clipping rectangles of all the parent nodes on the way to the root, - /// including those of `ClipRegion` rectangles. The combined clip is reset to - /// maximum when an incompatible coordinate system is encountered. - pub local_clip_rect: LayerRect, - - /// The scroll offset of all the nodes between us and our parent reference frame. - /// This is used to calculate intersections between us and content or nodes that - /// are also direct children of our reference frame. - pub reference_frame_relative_scroll_offset: LayerVector2D, - - pub scroll_offset: LayerVector2D, pub transform_kind: f32, pub padding: [f32; 3], } @@ -217,11 +203,12 @@ impl ClipScrollNodeData { pub fn invalid() -> ClipScrollNodeData { ClipScrollNodeData { transform: LayerToWorldTransform::identity(), - local_clip_rect: LayerRect::zero(), - reference_frame_relative_scroll_offset: LayerVector2D::zero(), - scroll_offset: LayerVector2D::zero(), transform_kind: 0.0, padding: [0.0; 3], } } } + +#[derive(Copy, Debug, Clone, PartialEq)] +#[repr(C)] +pub struct ClipChainRectIndex(pub usize); diff --git a/webrender/src/prim_store.rs b/webrender/src/prim_store.rs index 02c7d00ba2..2d33c56bdc 100644 --- a/webrender/src/prim_store.rs +++ b/webrender/src/prim_store.rs @@ -11,13 +11,14 @@ use api::{LineStyle, PipelineId, PremultipliedColorF, TileOffset, WorldToLayerTr use api::{YuvColorSpace, YuvFormat}; use border::BorderCornerInstance; use clip_scroll_tree::{CoordinateSystemId, ClipScrollTree}; +use clip_scroll_node::ClipScrollNode; use clip::{ClipSource, ClipSourcesHandle, ClipStore}; use frame_builder::PrimitiveContext; use glyph_rasterizer::{FontInstance, FontTransform}; use internal_types::{FastHashMap}; use gpu_cache::{GpuBlockData, GpuCache, GpuCacheAddress, GpuCacheHandle, GpuDataRequest, ToGpuBlocks}; -use gpu_types::ClipScrollNodeData; +use gpu_types::{ClipChainRectIndex, ClipScrollNodeData}; use picture::{PictureKind, PicturePrimitive}; use profiler::FrameProfileCounters; use render_task::{ClipChain, ClipChainNode, ClipChainNodeIter, ClipWorkItem, RenderTask}; @@ -185,6 +186,7 @@ pub struct PrimitiveMetadata { // storing them here. pub local_rect: LayerRect, pub local_clip_rect: LayerRect, + pub clip_chain_rect_index: ClipChainRectIndex, pub is_backface_visible: bool, pub screen_rect: Option, @@ -1007,6 +1009,7 @@ impl PrimitiveStore { clip_task_id: None, local_rect: *local_rect, local_clip_rect: *local_clip_rect, + clip_chain_rect_index: ClipChainRectIndex(0), is_backface_visible: is_backface_visible, screen_rect: None, tag, @@ -1560,6 +1563,11 @@ impl PrimitiveStore { clip_sources: metadata.clip_sources.weak(), coordinate_system_id: prim_coordinate_system_id, }, + // The local_clip_rect a property of ClipChain nodes that are ClipScrollNodes. + // It's used to calculate a local clipping rectangle before we reach this + // point, so we can set it to zero here. It should be unused from this point + // on. + local_clip_rect: LayerRect::zero(), screen_inner_rect, combined_outer_screen_rect: combined_outer_rect.unwrap_or_else(DeviceIntRect::zero), @@ -1655,7 +1663,9 @@ impl PrimitiveStore { profile_counters: &mut FrameProfileCounters, pic_index: SpecificPrimitiveIndex, screen_rect: &DeviceIntRect, + clip_chain_rect_index: ClipChainRectIndex, node_data: &[ClipScrollNodeData], + local_rects: &mut Vec, ) -> Option { // Reset the visibility of this primitive. // Do some basic checks first, that can early out @@ -1723,6 +1733,7 @@ impl PrimitiveStore { cpu_prim_index, screen_rect, node_data, + local_rects, ); let metadata = &mut self.cpu_metadata[prim_index.0]; @@ -1745,7 +1756,7 @@ impl PrimitiveStore { return None; } - let local_rect = metadata.local_rect.intersection(&metadata.local_clip_rect); + let local_rect = metadata.local_clip_rect.intersection(&metadata.local_rect); let local_rect = match local_rect { Some(local_rect) => local_rect, None if perform_culling => return None, @@ -1765,6 +1776,8 @@ impl PrimitiveStore { return None; } + metadata.clip_chain_rect_index = clip_chain_rect_index; + (local_rect, screen_bounding_rect) }; @@ -1824,6 +1837,7 @@ impl PrimitiveStore { pic_index: SpecificPrimitiveIndex, screen_rect: &DeviceIntRect, node_data: &[ClipScrollNodeData], + local_rects: &mut Vec, ) -> PrimitiveRunLocalRect { let mut result = PrimitiveRunLocalRect { local_rect_in_actual_parent_space: LayerRect::zero(), @@ -1873,6 +1887,22 @@ impl PrimitiveStore { scroll_node, ); + + let clip_chain_rect = match perform_culling { + true => get_local_clip_rect_for_nodes(scroll_node, clip_node), + false => None, + }; + + let clip_chain_rect_index = match clip_chain_rect { + Some(rect) if rect.is_empty() => continue, + Some(rect) => { + local_rects.push(rect); + ClipChainRectIndex(local_rects.len() - 1) + } + None => ClipChainRectIndex(0), // This is no clipping. + }; + + for i in 0 .. run.count { let prim_index = PrimitiveIndex(run.base_prim_index.0 + i); @@ -1891,7 +1921,9 @@ impl PrimitiveStore { profile_counters, pic_index, screen_rect, + clip_chain_rect_index, node_data, + local_rects, ) { profile_counters.visible_primitives.inc(); @@ -1968,3 +2000,29 @@ fn convert_clip_chain_to_clip_vector( }) .collect() } + +fn get_local_clip_rect_for_nodes( + scroll_node: &ClipScrollNode, + clip_node: &ClipScrollNode, +) -> Option { + let local_rect = ClipChainNodeIter { current: clip_node.clip_chain_node.clone() }.fold( + None, + |combined_local_clip_rect: Option, node| { + if node.work_item.coordinate_system_id != scroll_node.coordinate_system_id { + return combined_local_clip_rect; + } + + Some(match combined_local_clip_rect { + Some(combined_rect) => + combined_rect.intersection(&node.local_clip_rect).unwrap_or_else(LayerRect::zero), + None => node.local_clip_rect, + }) + } + ); + + match local_rect { + Some(local_rect) => + Some(scroll_node.coordinate_system_relative_transform.unapply(&local_rect)), + None => None, + } +} diff --git a/webrender/src/render_task.rs b/webrender/src/render_task.rs index 76c79ad823..af04d6cac8 100644 --- a/webrender/src/render_task.rs +++ b/webrender/src/render_task.rs @@ -40,6 +40,7 @@ pub type ClipChain = Option>; #[derive(Debug)] pub struct ClipChainNode { pub work_item: ClipWorkItem, + pub local_clip_rect: LayerRect, pub screen_inner_rect: DeviceIntRect, pub combined_outer_screen_rect: DeviceIntRect, pub combined_inner_screen_rect: DeviceIntRect, diff --git a/webrender/src/renderer.rs b/webrender/src/renderer.rs index f9b93bb4c0..8c7372f995 100644 --- a/webrender/src/renderer.rs +++ b/webrender/src/renderer.rs @@ -9,13 +9,10 @@ //! //! [renderer]: struct.Renderer.html -use api::{channel, BlobImageRenderer, FontRenderMode}; -use api::{ColorF, DocumentId, Epoch, PipelineId, RenderApiSender, RenderNotifier}; -use api::{DeviceIntPoint, DeviceIntRect, DeviceIntSize}; -use api::{DeviceUintPoint, DeviceUintRect, DeviceUintSize, ColorU}; -use api::{ExternalImageId, ExternalImageType, ImageFormat}; -use api::{YUV_COLOR_SPACES, YUV_FORMATS}; -use api::{YuvColorSpace, YuvFormat}; +use api::{BlobImageRenderer, ColorF, ColorU, DeviceIntPoint, DeviceIntRect, DeviceIntSize}; +use api::{DeviceUintPoint, DeviceUintRect, DeviceUintSize, DocumentId, Epoch, ExternalImageId}; +use api::{ExternalImageType, FontRenderMode, ImageFormat, PipelineId, RenderApiSender}; +use api::{RenderNotifier, YUV_COLOR_SPACES, YUV_FORMATS, YuvColorSpace, YuvFormat, channel}; #[cfg(not(feature = "debugger"))] use api::ApiMsg; use api::DebugCommand; @@ -328,6 +325,7 @@ enum TextureSampler { // the *first* pass. Items rendered in this target are // available as inputs to tasks in any subsequent pass. SharedCacheA8, + LocalClipRects } impl TextureSampler { @@ -356,6 +354,7 @@ impl Into for TextureSampler { TextureSampler::RenderTasks => TextureSlot(7), TextureSampler::Dither => TextureSlot(8), TextureSampler::SharedCacheA8 => TextureSlot(9), + TextureSampler::LocalClipRects => TextureSlot(10), } } } @@ -435,7 +434,7 @@ const DESC_CLIP: VertexDescriptor = VertexDescriptor { kind: VertexAttributeKind::I32, }, VertexAttribute { - name: "aClipLayerAddress", + name: "aScrollNodeId", count: 1, kind: VertexAttributeKind::I32, }, @@ -1495,6 +1494,7 @@ fn create_prim_shader( ("sRenderTasks", TextureSampler::RenderTasks), ("sResourceCache", TextureSampler::ResourceCache), ("sSharedCacheA8", TextureSampler::SharedCacheA8), + ("sLocalClipRects", TextureSampler::LocalClipRects), ], ); } @@ -1522,6 +1522,7 @@ fn create_clip_shader(name: &'static str, device: &mut Device) -> Result, + pub clip_chain_local_clip_rects: Vec, pub render_tasks: RenderTaskTree, // List of updates that need to be pushed to the diff --git a/webrender/src/util.rs b/webrender/src/util.rs index 85b64078be..49056f5197 100644 --- a/webrender/src/util.rs +++ b/webrender/src/util.rs @@ -2,11 +2,11 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use api::{BorderRadius, DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePoint, DeviceRect}; -use api::{DeviceSize, LayerPoint, LayerRect, LayerSize}; -use api::{DevicePixelScale, LayerToWorldTransform, WorldRect}; -use euclid::{Point2D, Rect, Size2D, TypedPoint2D, TypedRect, TypedSize2D}; -use euclid::{TypedTransform2D, TypedTransform3D}; +use api::{BorderRadius, DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePixelScale}; +use api::{DevicePoint, DeviceRect, DeviceSize, LayerPoint, LayerRect, LayerSize}; +use api::{LayerToWorldTransform, LayerTransform, LayerVector2D, WorldRect}; +use euclid::{Point2D, Rect, Size2D, TypedPoint2D, TypedRect, TypedSize2D, TypedTransform2D}; +use euclid::TypedTransform3D; use num_traits::Zero; use std::{i32, f32}; @@ -21,6 +21,7 @@ pub trait MatrixHelpers { fn inverse_project(&self, target: &TypedPoint2D) -> Option>; fn inverse_rect_footprint(&self, rect: &TypedRect) -> TypedRect; fn transform_kind(&self) -> TransformedRectKind; + fn is_simple_translation(&self) -> bool; } impl MatrixHelpers for TypedTransform3D { @@ -93,6 +94,17 @@ impl MatrixHelpers for TypedTransform3D { TransformedRectKind::Complex } } + + fn is_simple_translation(&self) -> bool { + if self.m11 != 1. || self.m22 != 1. || self.m33 != 1. { + return false; + } + self.m12.abs() < NEARLY_ZERO || self.m13.abs() < NEARLY_ZERO || + self.m14.abs() < NEARLY_ZERO || self.m21.abs() < NEARLY_ZERO || + self.m23.abs() < NEARLY_ZERO || self.m24.abs() < NEARLY_ZERO || + self.m31.abs() < NEARLY_ZERO || self.m32.abs() < NEARLY_ZERO || + self.m34.abs() < NEARLY_ZERO + } } pub trait RectHelpers @@ -323,3 +335,84 @@ impl MaxRect for DeviceRect { ) } } + +/// An enum that tries to avoid expensive transformation matrix calculations +/// when possible when dealing with non-perspective axis-aligned transformations. +#[derive(Debug, Clone)] +pub enum TransformOrOffset { + /// A simple offset, which can be used without doing any matrix math. + Offset(LayerVector2D), + + /// A transformation with an inverse. If the inverse isn't present, this isn't a 2D + /// transformation, which means we need to fall back to using inverse_rect_footprint. + /// Since this operation is so expensive, we avoid it for the 2D case. + Transform { + transform: LayerTransform, + inverse: Option, + } +} + +impl TransformOrOffset { + pub fn zero() -> TransformOrOffset { + TransformOrOffset::Offset(LayerVector2D::zero()) + } + + fn new_transform(transform: LayerTransform) -> TransformOrOffset { + if transform.is_2d() { + TransformOrOffset::Transform { + transform, + inverse: Some(transform.inverse().expect("Expected invertible matrix.")) + } + } else { + TransformOrOffset::Transform { transform, inverse: None } + } + } + + pub fn apply(&self, rect: &LayerRect) -> LayerRect { + match *self { + TransformOrOffset::Offset(offset) => rect.translate(&offset), + TransformOrOffset::Transform {transform, .. } => transform.transform_rect(&rect), + } + } + + pub fn unapply(&self, rect: &LayerRect) -> LayerRect { + match *self { + TransformOrOffset::Offset(offset) => rect.translate(&-offset), + TransformOrOffset::Transform { inverse: Some(inverse), .. } => + inverse.transform_rect(&rect), + TransformOrOffset::Transform { transform, inverse: None } => + transform.inverse_rect_footprint(rect), + } + } + + pub fn offset(&self, new_offset: LayerVector2D) -> TransformOrOffset { + match *self { + TransformOrOffset::Offset(offset) => TransformOrOffset::Offset(offset + new_offset), + TransformOrOffset::Transform { transform, .. } => { + let transform = transform.pre_translate(new_offset.to_3d()); + TransformOrOffset::new_transform(transform) + } + } + } + + pub fn update(&self, transform: LayerTransform) -> Option { + if transform.is_simple_translation() { + let offset = LayerVector2D::new(transform.m41, transform.m42); + return Some(self.offset(offset)); + } + + // If we break 2D axis alignment or have a perspective component, we need to start a + // new incompatible coordinate system with which we cannot share clips without masking. + if !transform.preserves_2d_axis_alignment() || transform.has_perspective_component() { + return None; + } + + let transform = match *self { + TransformOrOffset::Offset(offset) => transform.post_translate(offset.to_3d()), + TransformOrOffset::Transform { transform: existing_transform, .. } => + transform.post_mul(&existing_transform), + }; + + Some(TransformOrOffset::new_transform(transform)) + } +} diff --git a/wrench/reftests/boxshadow/overlap1.png b/wrench/reftests/boxshadow/overlap1.png index 3558bfaa60acd72190d438225b618943868c1f85..e0518aceff96fe6e799835c3f708476ec87a45bc 100644 GIT binary patch literal 10871 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 literal 7657 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 diff --git a/wrench/reftests/clip/clip-3d-transform-ref.yaml b/wrench/reftests/clip/clip-3d-transform-ref.yaml new file mode 100644 index 0000000000..58d66bec5a --- /dev/null +++ b/wrench/reftests/clip/clip-3d-transform-ref.yaml @@ -0,0 +1,8 @@ +--- +root: + items: + - + bounds: [0, 0, 200, 200] + "clip-rect": [0, 0, 200, 200] + type: rect + color: green diff --git a/wrench/reftests/clip/clip-3d-transform.yaml b/wrench/reftests/clip/clip-3d-transform.yaml new file mode 100644 index 0000000000..bae83dffe3 --- /dev/null +++ b/wrench/reftests/clip/clip-3d-transform.yaml @@ -0,0 +1,30 @@ +# This tests that clipping works well inside of a transformation with a 3d component that +# is still axis-aligned and lacking a perspective component. These two spaces should exist +# within a compatible coordinate system for local clipping (no masking). +--- +root: + items: + - + bounds: [0, 0, 0, 0] + "clip-rect": [0, 0, 0, 0] + "backface-visible": true + type: "stacking-context" + "scroll-policy": scrollable + transform: [0.5, 0, -0.8660254, 0, 0, 1, 0, 0, 0.8660254, 0, 0.5, 0, 0, 0, 0, 1] + "transform-style": flat + filters: [] + items: + - + bounds: [0, 0, 800, 400] + "clip-rect": [0, 0, 800, 400] + "backface-visible": true + type: clip + id: 1 + "content-size": [800, 400] + - + bounds: [0, 0, 400, 200] + "clip-rect": [0, 0, 400, 200] + "backface-visible": true + type: rect + "clip-and-scroll": 1 + color: green diff --git a/wrench/reftests/clip/clip-45-degree-rotation-ref.png b/wrench/reftests/clip/clip-45-degree-rotation-ref.png index 5a5e9ac10b9bd525d53087572f72b15aefbe51e2..41d72d634d867616dbc640cde2b78b1bd30c6394 100644 GIT binary patch literal 4038 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 Dr_Xk= literal 2871 zcmc&$3rtg27(Tb{=;hf9KB6LU9U8L->Y^E8-r<3Pg&@c_*u%w0bWRpCCPT+HLbynU zI;W73;RCE>F(FXJ7%>{O8>>8Aa8O6GiNRspNT*C~7ay2S*niHwEud`KmL&^mIp6>P z-{U{I$?fjU41I9GoB)JSaB51@8wfE+;B$=igNiDsX+Qk)Tc4&+LSy8w-qKJF75^rORpZar$7%}g?*iUA(ZESrJKR%it#C}?r6xw_E{KMkI@33{RaVsMI zdpcU1H#6(D7oIoYUw{0LHw{?p6fc7$0RBps>zv7X)o$t4~^nXBa7}l zQ!ygR^2D1b`;<`(F^C1lJT~fREM8zahnijo;D`*BVT2dTQ|^9Ms7iz-S~D=MkQXS0c)Ss3>Wj^dh6(lqjgRO!vkW*$@ z)qr`DyV8v&Q3)ow!7N$;sY-u?R+A#N>qW$bMZuZ%ghpZ+Cl(pB98WP9WoI-gUOe%P zrSUqJCd>`(k-cdaR!6*O7OUFl?MAHa=(t~4eZEr;MH**)4NdNVH!)Hz%k!o{%$!)b zcDlKQ_J(^SVyScQxRtXLR_hG04Z*(1sm*;8WTiM&%R!KA6PT+>AeYmOPItlBP+;a} z0(;Qu4g!NS(+IqSIv^KPO((K!<}xtl@nzskDEa?sxB_g?3h1c1h1H>(D8{PBui!my zR23qZ?>QU~wsMhZw6V`T*tD;!wfKHt^;lQ(@zaOGq>^EmbM)IIhhm1**Pk2h)^BmB zv4H>KS6lzJF?ZuFyS;mGak{E4&hlu>+PmvYj~F5CfV^J{H%IyanYAuM)UUd^r@{54<4Ml3Ewk|{Sc2AoaLMPpn%2Za!cpN;nkTEvJ(N$6bJK?+eo(S73c`v zWRr>V=%Pzk!`56Ry@!Jf!Je(8J71ax3I;uG+Q%EbFtIU2@>!#0)}>^{m$I-(tY{8{ ze!^Mni(yajI@4JVYnZynjR)~0NLVDeXNIYE2Nk#4`?vRgCdXhoRwr+)Q)#Sa@{;iO zaPyGxNep}Pm>0<9zy`tsd}2ia2SqN#cH;}+7^l`yI7Cyi0}V17?Zqm?Q#}#|qQM(U z@XnF5V!>nDqcP{p=Xrt>c|wonUS$wg6&C3sR~eBgNumm=$a9?rufMVjr}&fqGz5o)4#`uRjk^VKvc z3Dv}>eXehx`cn)|OBra|~gX`X%kWJSf`@a+>T-pVFRCk5Vf p Date: Fri, 8 Dec 2017 09:16:55 +0100 Subject: [PATCH 2/2] Remove parent_combined_viewport_rect from TransformUpdateState It's unused now. --- webrender/src/clip_scroll_tree.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/webrender/src/clip_scroll_tree.rs b/webrender/src/clip_scroll_tree.rs index cfcd90efd3..243173319e 100644 --- a/webrender/src/clip_scroll_tree.rs +++ b/webrender/src/clip_scroll_tree.rs @@ -69,7 +69,6 @@ pub struct ClipScrollTree { #[derive(Clone)] pub struct TransformUpdateState { pub parent_reference_frame_transform: LayerToWorldTransform, - pub parent_combined_viewport_rect: LayerRect, pub parent_accumulated_scroll_offset: LayerVector2D, pub nearest_scrolling_ancestor_offset: LayerVector2D, pub nearest_scrolling_ancestor_viewport: LayerRect, @@ -353,15 +352,12 @@ impl ClipScrollTree { } let root_reference_frame_id = self.root_reference_frame_id(); - let root_viewport = self.nodes[&root_reference_frame_id].local_clip_rect; - let mut state = TransformUpdateState { parent_reference_frame_transform: LayerToWorldTransform::create_translation( pan.x, pan.y, 0.0, ), - parent_combined_viewport_rect: root_viewport, parent_accumulated_scroll_offset: LayerVector2D::zero(), nearest_scrolling_ancestor_offset: LayerVector2D::zero(), nearest_scrolling_ancestor_viewport: LayerRect::zero(),