diff --git a/gfx/webrender/Cargo.toml b/gfx/webrender/Cargo.toml index 08f2af2b32de..ca493720bbf5 100644 --- a/gfx/webrender/Cargo.toml +++ b/gfx/webrender/Cargo.toml @@ -25,7 +25,7 @@ lazy_static = "1" log = "0.4" num-traits = "0.1.32" time = "0.1" -rayon = "0.8" +rayon = "1" webrender_api = {path = "../webrender_api"} bitflags = "1.0" thread_profiler = "0.1.1" diff --git a/gfx/webrender/examples/blob.rs b/gfx/webrender/examples/blob.rs index aa87e7811221..542764356f27 100644 --- a/gfx/webrender/examples/blob.rs +++ b/gfx/webrender/examples/blob.rs @@ -11,7 +11,7 @@ extern crate webrender; mod boilerplate; use boilerplate::{Example, HandyDandyRectBuilder}; -use rayon::{Configuration as ThreadPoolConfig, ThreadPool}; +use rayon::{ThreadPool, ThreadPoolBuilder}; use std::collections::HashMap; use std::collections::hash_map::Entry; use std::sync::Arc; @@ -282,10 +282,11 @@ impl Example for App { } fn main() { - let worker_config = - ThreadPoolConfig::new().thread_name(|idx| format!("WebRender:Worker#{}", idx)); + let workers = + ThreadPoolBuilder::new().thread_name(|idx| format!("WebRender:Worker#{}", idx)) + .build(); - let workers = Arc::new(ThreadPool::new(worker_config).unwrap()); + let workers = Arc::new(workers.unwrap()); let opts = webrender::RendererOptions { workers: Some(Arc::clone(&workers)), diff --git a/gfx/webrender/res/brush.glsl b/gfx/webrender/res/brush.glsl index 2c5de9bb82de..ea62a68186b1 100644 --- a/gfx/webrender/res/brush.glsl +++ b/gfx/webrender/res/brush.glsl @@ -15,6 +15,8 @@ void brush_vs( #define VECS_PER_BRUSH_PRIM 2 #define VECS_PER_SEGMENT 2 +#define BRUSH_FLAG_PERSPECTIVE_INTERPOLATION 1 + struct BrushInstance { int picture_address; int prim_address; @@ -24,6 +26,7 @@ struct BrushInstance { int z; int segment_index; int edge_mask; + int flags; ivec3 user_data; }; @@ -37,7 +40,8 @@ BrushInstance load_brush() { bi.scroll_node_id = aData0.z & 0xffff; bi.z = aData0.w; bi.segment_index = aData1.x & 0xffff; - bi.edge_mask = aData1.x >> 16; + bi.edge_mask = (aData1.x >> 16) & 0xff; + bi.flags = (aData1.x >> 24); bi.user_data = aData1.yzw; return bi; @@ -135,6 +139,8 @@ void main(void) { #endif } else { bvec4 edge_mask = notEqual(brush.edge_mask & ivec4(1, 2, 4, 8), ivec4(0)); + bool do_perspective_interpolation = (brush.flags & BRUSH_FLAG_PERSPECTIVE_INTERPOLATION) != 0; + vi = write_transform_vertex( local_segment_rect, brush_prim.local_rect, @@ -142,7 +148,8 @@ void main(void) { mix(vec4(0.0), vec4(1.0), edge_mask), float(brush.z), scroll_node, - pic_task + pic_task, + do_perspective_interpolation ); } diff --git a/gfx/webrender/res/brush_blend.glsl b/gfx/webrender/res/brush_blend.glsl index 97dbde947a77..2e8ddecc887a 100644 --- a/gfx/webrender/res/brush_blend.glsl +++ b/gfx/webrender/res/brush_blend.glsl @@ -3,11 +3,11 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #define VECS_PER_SPECIFIC_BRUSH 5 +#define FORCE_NO_PERSPECTIVE #include shared,prim_shared,brush varying vec3 vUv; -varying float vW; flat varying float vAmount; flat varying int vOp; @@ -25,10 +25,9 @@ void brush_vs( ) { PictureTask src_task = fetch_picture_task(user_data.x); vec2 texture_size = vec2(textureSize(sColor0, 0).xy); - vec2 uv = (vi.snapped_device_pos + - src_task.common_data.task_rect.p0 - - src_task.content_origin) * vi.w; - vW = vi.w; + vec2 uv = vi.snapped_device_pos + + src_task.common_data.task_rect.p0 - + src_task.content_origin; vUv = vec3(uv / texture_size, src_task.common_data.texture_layer_index); vOp = user_data.y; @@ -115,8 +114,7 @@ vec4 Opacity(vec4 Cs, float amount) { } vec4 brush_fs() { - vec2 uv = vUv.xy / vW; - vec4 Cs = texture(sColor0, vec3(uv, vUv.z)); + vec4 Cs = texture(sColor0, vUv); // Un-premultiply the input. Cs.rgb /= Cs.a; diff --git a/gfx/webrender/res/brush_mix_blend.glsl b/gfx/webrender/res/brush_mix_blend.glsl index 4ff88b25b7d0..a5c38e6322c6 100644 --- a/gfx/webrender/res/brush_mix_blend.glsl +++ b/gfx/webrender/res/brush_mix_blend.glsl @@ -6,9 +6,6 @@ #include shared,prim_shared,brush -varying vec3 vUv; -varying float vW; - varying vec3 vSrcUv; varying vec3 vBackdropUv; flat varying int vOp; @@ -24,18 +21,17 @@ void brush_vs( ) { vec2 texture_size = vec2(textureSize(sCacheRGBA8, 0)); vOp = user_data.x; - vW = vi.w; PictureTask src_task = fetch_picture_task(user_data.z); - vec2 src_uv = (vi.snapped_device_pos + - src_task.common_data.task_rect.p0 - - src_task.content_origin) * vi.w; + vec2 src_uv = vi.snapped_device_pos + + src_task.common_data.task_rect.p0 - + src_task.content_origin; vSrcUv = vec3(src_uv / texture_size, src_task.common_data.texture_layer_index); RenderTaskCommonData backdrop_task = fetch_render_task_common_data(user_data.y); - vec2 backdrop_uv = (vi.snapped_device_pos + - backdrop_task.task_rect.p0 - - src_task.content_origin) * vi.w; + vec2 backdrop_uv = vi.snapped_device_pos + + backdrop_task.task_rect.p0 - + src_task.content_origin; vBackdropUv = vec3(backdrop_uv / texture_size, backdrop_task.texture_layer_index); } #endif @@ -205,10 +201,8 @@ const int MixBlendMode_Color = 14; const int MixBlendMode_Luminosity = 15; vec4 brush_fs() { - vec2 uv = vUv.xy / vW; - - vec4 Cb = texture(sCacheRGBA8, vBackdropUv); - vec4 Cs = texture(sCacheRGBA8, vSrcUv); + vec4 Cb = textureLod(sCacheRGBA8, vBackdropUv, 0.0); + vec4 Cs = textureLod(sCacheRGBA8, vSrcUv, 0.0); if (Cb.a == 0.0) { return Cs; diff --git a/gfx/webrender/res/ps_radial_gradient.glsl b/gfx/webrender/res/brush_radial_gradient.glsl similarity index 69% rename from gfx/webrender/res/ps_radial_gradient.glsl rename to gfx/webrender/res/brush_radial_gradient.glsl index 46483ee5b07d..2cc8f3a27680 100644 --- a/gfx/webrender/res/ps_radial_gradient.glsl +++ b/gfx/webrender/res/brush_radial_gradient.glsl @@ -2,7 +2,9 @@ * 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/. */ -#include shared,prim_shared +#define VECS_PER_SPECIFIC_BRUSH 2 + +#include shared,prim_shared,brush flat varying int vGradientAddress; flat varying float vGradientRepeat; @@ -12,24 +14,34 @@ flat varying vec2 vEndCenter; flat varying float vStartRadius; flat varying float vEndRadius; -flat varying vec2 vTileSize; -flat varying vec2 vTileRepeat; - varying vec2 vPos; +#ifdef WR_FEATURE_ALPHA_PASS +varying vec2 vLocalPos; +#endif + #ifdef WR_VERTEX_SHADER -void main(void) { - Primitive prim = load_primitive(); - RadialGradient gradient = fetch_radial_gradient(prim.specific_prim_address); - VertexInfo vi = write_vertex(prim.local_rect, - prim.local_clip_rect, - prim.z, - prim.scroll_node, - prim.task, - prim.local_rect); +struct RadialGradient { + vec4 start_end_center; + vec4 start_end_radius_ratio_xy_extend_mode; +}; - vPos = vi.local_pos - prim.local_rect.p0; +RadialGradient fetch_radial_gradient(int address) { + vec4 data[2] = fetch_from_resource_cache_2(address); + return RadialGradient(data[0], data[1]); +} + +void brush_vs( + VertexInfo vi, + int prim_address, + RectWithSize local_rect, + ivec3 user_data, + PictureTask pic_task +) { + RadialGradient gradient = fetch_radial_gradient(prim_address); + + vPos = vi.local_pos - local_rect.p0; vStartCenter = gradient.start_end_center.xy; vEndCenter = gradient.start_end_center.zw; @@ -37,38 +49,28 @@ void main(void) { vStartRadius = gradient.start_end_radius_ratio_xy_extend_mode.x; vEndRadius = gradient.start_end_radius_ratio_xy_extend_mode.y; - vTileSize = gradient.tile_size_repeat.xy; - vTileRepeat = gradient.tile_size_repeat.zw; - // Transform all coordinates by the y scale so the // fragment shader can work with circles float ratio_xy = gradient.start_end_radius_ratio_xy_extend_mode.z; vPos.y *= ratio_xy; vStartCenter.y *= ratio_xy; vEndCenter.y *= ratio_xy; - vTileSize.y *= ratio_xy; - vTileRepeat.y *= ratio_xy; - vGradientAddress = prim.specific_prim_address + VECS_PER_GRADIENT; + vGradientAddress = user_data.x; // Whether to repeat the gradient instead of clamping. vGradientRepeat = float(int(gradient.start_end_radius_ratio_xy_extend_mode.w) != EXTEND_MODE_CLAMP); - write_clip(vi.screen_pos, prim.clip_area); +#ifdef WR_FEATURE_ALPHA_PASS + vLocalPos = vi.local_pos; +#endif } #endif #ifdef WR_FRAGMENT_SHADER -void main(void) { - vec2 pos = mod(vPos, vTileRepeat); - - if (pos.x >= vTileSize.x || - pos.y >= vTileSize.y) { - discard; - } - +vec4 brush_fs() { vec2 cd = vEndCenter - vStartCenter; - vec2 pd = pos - vStartCenter; + vec2 pd = vPos - vStartCenter; float rd = vEndRadius - vStartRadius; // Solve for t in length(t * cd - pd) = vStartRadius + t * rd @@ -110,6 +112,10 @@ void main(void) { offset, vGradientRepeat); - oFragColor = color * do_clip(); +#ifdef WR_FEATURE_ALPHA_PASS + color *= init_transform_fs(vLocalPos); +#endif + + return color; } #endif diff --git a/gfx/webrender/res/brush_yuv_image.glsl b/gfx/webrender/res/brush_yuv_image.glsl new file mode 100644 index 000000000000..a8407acfa2f6 --- /dev/null +++ b/gfx/webrender/res/brush_yuv_image.glsl @@ -0,0 +1,166 @@ +/* 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/. */ + +#define VECS_PER_SPECIFIC_BRUSH 0 + +#include shared,prim_shared,brush + +// TODO(gw): Consider whether we should even have separate shader compilations +// for the various YUV modes. To save on the number of shaders we +// need to compile, it might be worth just doing this as an +// uber-shader instead. +// TODO(gw): Regardless of the above, we should remove the separate shader +// compilations for the different color space matrix below. That +// can be provided by a branch in the VS and pushed through the +// interpolators, or even as a uniform that breaks batches, rather +// that needing to compile to / select a different shader when +// there is a different color space. + +#ifdef WR_FEATURE_ALPHA_PASS +varying vec2 vLocalPos; +#endif + +#if defined (WR_FEATURE_YUV_PLANAR) + varying vec3 vUv_Y; + flat varying vec4 vUvBounds_Y; + + varying vec3 vUv_U; + flat varying vec4 vUvBounds_U; + + varying vec3 vUv_V; + flat varying vec4 vUvBounds_V; +#elif defined (WR_FEATURE_YUV_NV12) + varying vec3 vUv_Y; + flat varying vec4 vUvBounds_Y; + + varying vec3 vUv_UV; + flat varying vec4 vUvBounds_UV; +#elif defined (WR_FEATURE_YUV_INTERLEAVED) + varying vec3 vUv_YUV; + flat varying vec4 vUvBounds_YUV; +#endif + +#ifdef WR_VERTEX_SHADER +void write_uv_rect( + int resource_id, + vec2 f, + vec2 texture_size, + out vec3 uv, + out vec4 uv_bounds +) { + ImageResource res = fetch_image_resource(resource_id); + vec2 uv0 = res.uv_rect.p0; + vec2 uv1 = res.uv_rect.p1; + + uv.xy = mix(uv0, uv1, f); + uv.z = res.layer; + + uv_bounds = vec4(uv0 + vec2(0.5), uv1 - vec2(0.5)); + + #ifndef WR_FEATURE_TEXTURE_RECT + uv.xy /= texture_size; + uv_bounds /= texture_size.xyxy; + #endif +} + +void brush_vs( + VertexInfo vi, + int prim_address, + RectWithSize local_rect, + ivec3 user_data, + PictureTask pic_task +) { + vec2 f = (vi.local_pos - local_rect.p0) / local_rect.size; + +#ifdef WR_FEATURE_ALPHA_PASS + vLocalPos = vi.local_pos; +#endif + +#if defined (WR_FEATURE_YUV_PLANAR) + write_uv_rect(user_data.x, f, vec2(textureSize(sColor0, 0).xy), vUv_Y, vUvBounds_Y); + write_uv_rect(user_data.y, f, vec2(textureSize(sColor1, 0).xy), vUv_U, vUvBounds_U); + write_uv_rect(user_data.z, f, vec2(textureSize(sColor2, 0).xy), vUv_V, vUvBounds_V); +#elif defined (WR_FEATURE_YUV_NV12) + write_uv_rect(user_data.x, f, vec2(textureSize(sColor0, 0).xy), vUv_Y, vUvBounds_Y); + write_uv_rect(user_data.y, f, vec2(textureSize(sColor1, 0).xy), vUv_UV, vUvBounds_UV); +#elif defined (WR_FEATURE_YUV_INTERLEAVED) + write_uv_rect(user_data.x, f, vec2(textureSize(sColor0, 0).xy), vUv_YUV, vUvBounds_YUV); +#endif //WR_FEATURE_YUV_* +} +#endif + +#ifdef WR_FRAGMENT_SHADER + +#if !defined(WR_FEATURE_YUV_REC601) && !defined(WR_FEATURE_YUV_REC709) +#define WR_FEATURE_YUV_REC601 +#endif + +// The constants added to the Y, U and V components are applied in the fragment shader. +#if defined(WR_FEATURE_YUV_REC601) +// From Rec601: +// [R] [1.1643835616438356, 0.0, 1.5960267857142858 ] [Y - 16] +// [G] = [1.1643835616438358, -0.3917622900949137, -0.8129676472377708 ] x [U - 128] +// [B] [1.1643835616438356, 2.017232142857143, 8.862867620416422e-17] [V - 128] +// +// For the range [0,1] instead of [0,255]. +// +// The matrix is stored in column-major. +const mat3 YuvColorMatrix = mat3( + 1.16438, 1.16438, 1.16438, + 0.0, -0.39176, 2.01723, + 1.59603, -0.81297, 0.0 +); +#elif defined(WR_FEATURE_YUV_REC709) +// From Rec709: +// [R] [1.1643835616438356, 4.2781193979771426e-17, 1.7927410714285714] [Y - 16] +// [G] = [1.1643835616438358, -0.21324861427372963, -0.532909328559444 ] x [U - 128] +// [B] [1.1643835616438356, 2.1124017857142854, 0.0 ] [V - 128] +// +// For the range [0,1] instead of [0,255]: +// +// The matrix is stored in column-major. +const mat3 YuvColorMatrix = mat3( + 1.16438, 1.16438, 1.16438, + 0.0 , -0.21325, 2.11240, + 1.79274, -0.53291, 0.0 +); +#endif + +vec4 brush_fs() { + vec3 yuv_value; + +#if defined (WR_FEATURE_YUV_PLANAR) + // The yuv_planar format should have this third texture coordinate. + vec2 uv_y = clamp(vUv_Y.xy, vUvBounds_Y.xy, vUvBounds_Y.zw); + vec2 uv_u = clamp(vUv_U.xy, vUvBounds_U.xy, vUvBounds_U.zw); + vec2 uv_v = clamp(vUv_V.xy, vUvBounds_V.xy, vUvBounds_V.zw); + yuv_value.x = TEX_SAMPLE(sColor0, vec3(uv_y, vUv_Y.z)).r; + yuv_value.y = TEX_SAMPLE(sColor1, vec3(uv_u, vUv_U.z)).r; + yuv_value.z = TEX_SAMPLE(sColor2, vec3(uv_v, vUv_V.z)).r; +#elif defined (WR_FEATURE_YUV_NV12) + vec2 uv_y = clamp(vUv_Y.xy, vUvBounds_Y.xy, vUvBounds_Y.zw); + vec2 uv_uv = clamp(vUv_UV.xy, vUvBounds_UV.xy, vUvBounds_UV.zw); + yuv_value.x = TEX_SAMPLE(sColor0, vec3(uv_y, vUv_Y.z)).r; + yuv_value.yz = TEX_SAMPLE(sColor1, vec3(uv_uv, vUv_UV.z)).rg; +#elif defined (WR_FEATURE_YUV_INTERLEAVED) + // "The Y, Cb and Cr color channels within the 422 data are mapped into + // the existing green, blue and red color channels." + // https://www.khronos.org/registry/OpenGL/extensions/APPLE/APPLE_rgb_422.txt + vec2 uv_y = clamp(vUv_YUV.xy, vUvBounds_YUV.xy, vUvBounds_YUV.zw); + yuv_value = TEX_SAMPLE(sColor0, vec3(uv_y, vUv_YUV.z)).gbr; +#else + yuv_value = vec3(0.0); +#endif + + // See the YuvColorMatrix definition for an explanation of where the constants come from. + vec3 rgb = YuvColorMatrix * (yuv_value - vec3(0.06275, 0.50196, 0.50196)); + vec4 color = vec4(rgb, 1.0); + +#ifdef WR_FEATURE_ALPHA_PASS + color *= init_transform_fs(vLocalPos); +#endif + + return color; +} +#endif diff --git a/gfx/webrender/res/ellipse.glsl b/gfx/webrender/res/ellipse.glsl index c3f8d36dac02..fc48cfac4f3c 100644 --- a/gfx/webrender/res/ellipse.glsl +++ b/gfx/webrender/res/ellipse.glsl @@ -4,73 +4,31 @@ #ifdef WR_FRAGMENT_SHADER +// One iteration of Newton's method on the 2D equation of an ellipse: // -// Signed distance to an ellipse. -// Taken from http://www.iquilezles.org/www/articles/ellipsedist/ellipsedist.htm -// Note that this fails for exact circles. +// E(x, y) = x^2/a^2 + y^2/b^2 - 1 // -float sdEllipse( vec2 p, in vec2 ab ) { - p = abs( p ); if( p.x > p.y ){ p=p.yx; ab=ab.yx; } - float l = ab.y*ab.y - ab.x*ab.x; - - float m = ab.x*p.x/l; - float n = ab.y*p.y/l; - float m2 = m*m; - float n2 = n*n; - - float c = (m2 + n2 - 1.0)/3.0; - float c3 = c*c*c; - - float q = c3 + m2*n2*2.0; - float d = c3 + m2*n2; - float g = m + m*n2; - - float co; - - if( d<0.0 ) - { - float p = acos(q/c3)/3.0; - float s = cos(p); - float t = sin(p)*sqrt(3.0); - float rx = sqrt( -c*(s + t + 2.0) + m2 ); - float ry = sqrt( -c*(s - t + 2.0) + m2 ); - co = ( ry + sign(l)*rx + abs(g)/(rx*ry) - m)/2.0; - } - else - { - float h = 2.0*m*n*sqrt( d ); - float s = sign(q+h)*pow( abs(q+h), 1.0/3.0 ); - float u = sign(q-h)*pow( abs(q-h), 1.0/3.0 ); - float rx = -s - u - c*4.0 + 2.0*m2; - float ry = (s - u)*sqrt(3.0); - float rm = sqrt( rx*rx + ry*ry ); - float p = ry/sqrt(rm-rx); - co = (p + 2.0*g/rm - m)/2.0; - } - - float si = sqrt( 1.0 - co*co ); - - vec2 r = vec2( ab.x*co, ab.y*si ); - - return length(r - p ) * sign(p.y-r.y); -} - +// The Jacobian of this equation is: +// +// J(E(x, y)) = [ 2*x/a^2 2*y/b^2 ] +// +// We approximate the distance with: +// +// E(x, y) / ||J(E(x, y))|| +// +// See G. Taubin, "Distance Approximations for Rasterizing Implicit +// Curves", section 3. float distance_to_ellipse(vec2 p, vec2 radii, float aa_range) { - // sdEllipse fails on exact circles, so handle equal - // radii here. The branch coherency should make this - // a performance win for the circle case too. - float len = length(p); - if (radii.x == radii.y) { - return len - radii.x; + float dist; + if (any(lessThanEqual(radii, vec2(0.0)))) { + dist = length(p); } else { - if (len < min(radii.x, radii.y) - aa_range) { - return -aa_range; - } else if (len > max(radii.x, radii.y) + aa_range) { - return aa_range; - } - - return sdEllipse(p, radii); + vec2 invRadiiSq = 1.0 / (radii * radii); + float g = dot(p * p * invRadiiSq, vec2(1.0)) - 1.0; + vec2 dG = 2.0 * p * invRadiiSq; + dist = g * inversesqrt(dot(dG, dG)); } + return clamp(dist, -aa_range, aa_range); } float clip_against_ellipse_if_needed( diff --git a/gfx/webrender/res/prim_shared.glsl b/gfx/webrender/res/prim_shared.glsl index cfa4d0ac2436..281de1c7a7bc 100644 --- a/gfx/webrender/res/prim_shared.glsl +++ b/gfx/webrender/res/prim_shared.glsl @@ -315,27 +315,6 @@ Gradient fetch_gradient(int address) { return Gradient(data[0], data[1], data[2]); } -struct GradientStop { - vec4 color; - vec4 offset; -}; - -GradientStop fetch_gradient_stop(int address) { - vec4 data[2] = fetch_from_resource_cache_2(address); - return GradientStop(data[0], data[1]); -} - -struct RadialGradient { - vec4 start_end_center; - vec4 start_end_radius_ratio_xy_extend_mode; - vec4 tile_size_repeat; -}; - -RadialGradient fetch_radial_gradient(int address) { - vec4 data[3] = fetch_from_resource_cache_3(address); - return RadialGradient(data[0], data[1], data[2]); -} - struct Glyph { vec2 offset; }; @@ -624,7 +603,8 @@ VertexInfo write_transform_vertex(RectWithSize local_segment_rect, vec4 clip_edge_mask, float z, ClipScrollNode scroll_node, - PictureTask task) { + PictureTask task, + bool do_perspective_interpolation) { // Calculate a clip rect from local_rect + local clip RectWithEndpoint clip_rect = to_rect_with_endpoint(local_clip_rect); RectWithEndpoint segment_rect = to_rect_with_endpoint(local_segment_rect); @@ -661,13 +641,16 @@ VertexInfo write_transform_vertex(RectWithSize local_segment_rect, vec2 device_pos = world_pos.xy / world_pos.w * uDevicePixelRatio; vec2 task_offset = task.common_data.task_rect.p0 - task.content_origin; + // Force w = 1, if we don't want perspective interpolation (for + // example, drawing a screen-space quad on an element with a + // perspective transform). + world_pos.w = mix(1.0, world_pos.w, do_perspective_interpolation); + // We want the world space coords to be perspective divided by W. // We also want that to apply to any interpolators. However, we // want a constant Z across the primitive, since we're using it // for draw ordering - so scale by the W coord to ensure this. - vec4 final_pos = vec4((device_pos + task_offset) * world_pos.w, - z * world_pos.w, - world_pos.w); + vec4 final_pos = vec4(device_pos + task_offset, z, 1.0) * world_pos.w; gl_Position = uTransform * final_pos; vLocalBounds = mix( @@ -694,7 +677,8 @@ VertexInfo write_transform_vertex_primitive(Primitive prim) { vec4(1.0), prim.z, prim.scroll_node, - prim.task + prim.task, + true ); } diff --git a/gfx/webrender/res/ps_border_corner.glsl b/gfx/webrender/res/ps_border_corner.glsl index e67be5086ebb..28d484d45b98 100644 --- a/gfx/webrender/res/ps_border_corner.glsl +++ b/gfx/webrender/res/ps_border_corner.glsl @@ -320,7 +320,8 @@ void main(void) { edge_mask, prim.z, prim.scroll_node, - prim.task); + prim.task, + true); #else VertexInfo vi = write_vertex(segment_rect, prim.local_clip_rect, diff --git a/gfx/webrender/res/ps_border_edge.glsl b/gfx/webrender/res/ps_border_edge.glsl index 784e25ac98d4..a66713548ad6 100644 --- a/gfx/webrender/res/ps_border_edge.glsl +++ b/gfx/webrender/res/ps_border_edge.glsl @@ -233,7 +233,8 @@ void main(void) { edge_mask, prim.z, prim.scroll_node, - prim.task); + prim.task, + true); #else VertexInfo vi = write_vertex(segment_rect, prim.local_clip_rect, diff --git a/gfx/webrender/res/ps_gradient.glsl b/gfx/webrender/res/ps_gradient.glsl index 390a25058151..2743f11d1832 100644 --- a/gfx/webrender/res/ps_gradient.glsl +++ b/gfx/webrender/res/ps_gradient.glsl @@ -9,6 +9,16 @@ varying vec4 vColor; varying vec2 vLocalPos; #ifdef WR_VERTEX_SHADER +struct GradientStop { + vec4 color; + vec4 offset; +}; + +GradientStop fetch_gradient_stop(int address) { + vec4 data[2] = fetch_from_resource_cache_2(address); + return GradientStop(data[0], data[1]); +} + void main(void) { Primitive prim = load_primitive(); Gradient gradient = fetch_gradient(prim.specific_prim_address); @@ -73,7 +83,8 @@ void main(void) { vec4(1.0), prim.z, prim.scroll_node, - prim.task); + prim.task, + true); vLocalPos = vi.local_pos; vec2 f = (vi.local_pos.xy - prim.local_rect.p0) / prim.local_rect.size; #else diff --git a/gfx/webrender/res/ps_yuv_image.glsl b/gfx/webrender/res/ps_yuv_image.glsl deleted file mode 100644 index 093a55083bb0..000000000000 --- a/gfx/webrender/res/ps_yuv_image.glsl +++ /dev/null @@ -1,197 +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/. */ - -#include shared,prim_shared - -// If this is in WR_FEATURE_TEXTURE_RECT mode, the rect and size use non-normalized -// texture coordinates. Otherwise, it uses normalized texture coordinates. Please -// check GL_TEXTURE_RECTANGLE. -flat varying vec2 vTextureOffsetY; // Offset of the y plane into the texture atlas. -flat varying vec2 vTextureOffsetU; // Offset of the u plane into the texture atlas. -flat varying vec2 vTextureOffsetV; // Offset of the v plane into the texture atlas. -flat varying vec2 vTextureSizeY; // Size of the y plane in the texture atlas. -flat varying vec2 vTextureSizeUv; // Size of the u and v planes in the texture atlas. -flat varying vec2 vStretchSize; -flat varying vec2 vHalfTexelY; // Normalized length of the half of a Y texel. -flat varying vec2 vHalfTexelUv; // Normalized length of the half of u and v texels. -flat varying vec3 vLayers; - -#ifdef WR_FEATURE_TRANSFORM -flat varying vec4 vLocalRect; -#endif - -varying vec2 vLocalPos; - -#ifdef WR_VERTEX_SHADER -struct YuvImage { - vec2 size; -}; - -YuvImage fetch_yuv_image(int address) { - vec4 data = fetch_from_resource_cache_1(address); - return YuvImage(data.xy); -} - -void main(void) { - Primitive prim = load_primitive(); -#ifdef WR_FEATURE_TRANSFORM - VertexInfo vi = write_transform_vertex_primitive(prim); - vLocalPos = vi.local_pos; - vLocalRect = vec4(prim.local_rect.p0, prim.local_rect.p0 + prim.local_rect.size); -#else - VertexInfo vi = write_vertex(prim.local_rect, - prim.local_clip_rect, - prim.z, - prim.scroll_node, - prim.task, - prim.local_rect); - vLocalPos = vi.local_pos - prim.local_rect.p0; -#endif - - write_clip(vi.screen_pos, prim.clip_area); - - ImageResource y_rect = fetch_image_resource(prim.user_data0); - vLayers = vec3(y_rect.layer, 0.0, 0.0); - -#ifndef WR_FEATURE_INTERLEAVED_Y_CB_CR // only 1 channel - ImageResource u_rect = fetch_image_resource(prim.user_data1); - vLayers.y = u_rect.layer; -#ifndef WR_FEATURE_NV12 // 2 channel - ImageResource v_rect = fetch_image_resource(prim.user_data2); - vLayers.z = v_rect.layer; -#endif -#endif - - // If this is in WR_FEATURE_TEXTURE_RECT mode, the rect and size use - // non-normalized texture coordinates. -#ifdef WR_FEATURE_TEXTURE_RECT - vec2 y_texture_size_normalization_factor = vec2(1, 1); -#else - vec2 y_texture_size_normalization_factor = vec2(textureSize(sColor0, 0)); -#endif - vec2 y_st0 = y_rect.uv_rect.p0 / y_texture_size_normalization_factor; - vec2 y_st1 = y_rect.uv_rect.p1 / y_texture_size_normalization_factor; - - vTextureSizeY = y_st1 - y_st0; - vTextureOffsetY = y_st0; - -#ifndef WR_FEATURE_INTERLEAVED_Y_CB_CR - // This assumes the U and V surfaces have the same size. -#ifdef WR_FEATURE_TEXTURE_RECT - vec2 uv_texture_size_normalization_factor = vec2(1, 1); -#else - vec2 uv_texture_size_normalization_factor = vec2(textureSize(sColor1, 0)); -#endif - vec2 u_st0 = u_rect.uv_rect.p0 / uv_texture_size_normalization_factor; - vec2 u_st1 = u_rect.uv_rect.p1 / uv_texture_size_normalization_factor; - -#ifndef WR_FEATURE_NV12 - vec2 v_st0 = v_rect.uv_rect.p0 / uv_texture_size_normalization_factor; -#endif - - vTextureSizeUv = u_st1 - u_st0; - vTextureOffsetU = u_st0; -#ifndef WR_FEATURE_NV12 - vTextureOffsetV = v_st0; -#endif -#endif - - YuvImage image = fetch_yuv_image(prim.specific_prim_address); - vStretchSize = image.size; - - vHalfTexelY = vec2(0.5) / y_texture_size_normalization_factor; -#ifndef WR_FEATURE_INTERLEAVED_Y_CB_CR - vHalfTexelUv = vec2(0.5) / uv_texture_size_normalization_factor; -#endif -} -#endif - -#ifdef WR_FRAGMENT_SHADER -#if !defined(WR_FEATURE_YUV_REC601) && !defined(WR_FEATURE_YUV_REC709) -#define WR_FEATURE_YUV_REC601 -#endif - -// The constants added to the Y, U and V components are applied in the fragment shader. -#if defined(WR_FEATURE_YUV_REC601) -// From Rec601: -// [R] [1.1643835616438356, 0.0, 1.5960267857142858 ] [Y - 16] -// [G] = [1.1643835616438358, -0.3917622900949137, -0.8129676472377708 ] x [U - 128] -// [B] [1.1643835616438356, 2.017232142857143, 8.862867620416422e-17] [V - 128] -// -// For the range [0,1] instead of [0,255]. -// -// The matrix is stored in column-major. -const mat3 YuvColorMatrix = mat3( - 1.16438, 1.16438, 1.16438, - 0.0, -0.39176, 2.01723, - 1.59603, -0.81297, 0.0 -); -#elif defined(WR_FEATURE_YUV_REC709) -// From Rec709: -// [R] [1.1643835616438356, 4.2781193979771426e-17, 1.7927410714285714] [Y - 16] -// [G] = [1.1643835616438358, -0.21324861427372963, -0.532909328559444 ] x [U - 128] -// [B] [1.1643835616438356, 2.1124017857142854, 0.0 ] [V - 128] -// -// For the range [0,1] instead of [0,255]: -// -// The matrix is stored in column-major. -const mat3 YuvColorMatrix = mat3( - 1.16438, 1.16438, 1.16438, - 0.0 , -0.21325, 2.11240, - 1.79274, -0.53291, 0.0 -); -#endif - -void main(void) { -#ifdef WR_FEATURE_TRANSFORM - float alpha = init_transform_fs(vLocalPos); - - // We clamp the texture coordinate calculation here to the local rectangle boundaries, - // which makes the edge of the texture stretch instead of repeat. - vec2 relative_pos_in_rect = clamp(vLocalPos, vLocalRect.xy, vLocalRect.zw) - vLocalRect.xy; -#else - float alpha = 1.0;; - vec2 relative_pos_in_rect = vLocalPos; -#endif - - alpha *= do_clip(); - - // We clamp the texture coordinates to the half-pixel offset from the borders - // in order to avoid sampling outside of the texture area. - vec2 st_y = vTextureOffsetY + clamp( - relative_pos_in_rect / vStretchSize * vTextureSizeY, - vHalfTexelY, vTextureSizeY - vHalfTexelY); -#ifndef WR_FEATURE_INTERLEAVED_Y_CB_CR - vec2 uv_offset = clamp( - relative_pos_in_rect / vStretchSize * vTextureSizeUv, - vHalfTexelUv, vTextureSizeUv - vHalfTexelUv); - // NV12 only uses 2 textures. The sColor0 is for y and sColor1 is for uv. - // The texture coordinates of u and v are the same. So, we could skip the - // st_v if the format is NV12. - vec2 st_u = vTextureOffsetU + uv_offset; -#endif - - vec3 yuv_value; -#ifdef WR_FEATURE_INTERLEAVED_Y_CB_CR - // "The Y, Cb and Cr color channels within the 422 data are mapped into - // the existing green, blue and red color channels." - // https://www.khronos.org/registry/OpenGL/extensions/APPLE/APPLE_rgb_422.txt - yuv_value = TEX_SAMPLE(sColor0, vec3(st_y, vLayers.x)).gbr; -#elif defined(WR_FEATURE_NV12) - yuv_value.x = TEX_SAMPLE(sColor0, vec3(st_y, vLayers.x)).r; - yuv_value.yz = TEX_SAMPLE(sColor1, vec3(st_u, vLayers.y)).rg; -#else - // The yuv_planar format should have this third texture coordinate. - vec2 st_v = vTextureOffsetV + uv_offset; - - yuv_value.x = TEX_SAMPLE(sColor0, vec3(st_y, vLayers.x)).r; - yuv_value.y = TEX_SAMPLE(sColor1, vec3(st_u, vLayers.y)).r; - yuv_value.z = TEX_SAMPLE(sColor2, vec3(st_v, vLayers.z)).r; -#endif - - // See the YuvColorMatrix definition for an explanation of where the constants come from. - vec3 rgb = YuvColorMatrix * (yuv_value - vec3(0.06275, 0.50196, 0.50196)); - oFragColor = vec4(rgb * alpha, alpha); -} -#endif diff --git a/gfx/webrender/src/batch.rs b/gfx/webrender/src/batch.rs index bdbd5856ceb4..ddb939477be5 100644 --- a/gfx/webrender/src/batch.rs +++ b/gfx/webrender/src/batch.rs @@ -7,22 +7,20 @@ use api::{DeviceUintRect, DeviceUintPoint, DeviceUintSize, ExternalImageType, Fi use api::{DeviceIntPoint, LayerPoint, SubpixelDirection, YuvColorSpace, YuvFormat}; use api::{LayerToWorldTransform, WorldPixel}; use border::{BorderCornerInstance, BorderCornerSide, BorderEdgeKind}; -use clip::{ClipSource, ClipStore}; +use clip::{ClipSource, ClipStore, ClipWorkItem}; use clip_scroll_tree::{CoordinateSystemId}; use euclid::{TypedTransform3D, vec3}; use glyph_rasterizer::GlyphFormat; use gpu_cache::{GpuCache, GpuCacheAddress}; -use gpu_types::{BrushImageKind, BrushInstance, ClipChainRectIndex}; +use gpu_types::{BrushFlags, BrushImageKind, BrushInstance, ClipChainRectIndex}; use gpu_types::{ClipMaskInstance, ClipScrollNodeIndex}; use gpu_types::{CompositePrimitiveInstance, PrimitiveInstance, SimplePrimitiveInstance}; -use internal_types::{FastHashMap, SourceTexture}; +use internal_types::{FastHashMap, SavedTargetIndex, SourceTexture}; use picture::{ContentOrigin, PictureCompositeMode, PictureKind, PicturePrimitive, PictureSurface}; use plane_split::{BspSplitter, Polygon, Splitter}; use prim_store::{ImageSource, PrimitiveIndex, PrimitiveKind, PrimitiveMetadata, PrimitiveStore}; use prim_store::{BrushPrimitive, BrushKind, DeferredResolve, EdgeAaSegmentMask, PrimitiveRun}; -use render_task::{ClipWorkItem}; -use render_task::{RenderTaskAddress, RenderTaskId}; -use render_task::{RenderTaskKind, RenderTaskTree}; +use render_task::{RenderTaskAddress, RenderTaskId, RenderTaskKind, RenderTaskTree}; use renderer::{BlendMode, ImageBufferKind}; use renderer::BLOCKS_PER_UV_RECT; use resource_cache::{CacheItem, GlyphFetchResult, ImageRequest, ResourceCache}; @@ -40,10 +38,8 @@ const OPAQUE_TASK_ADDRESS: RenderTaskAddress = RenderTaskAddress(0x7fff); pub enum TransformBatchKind { TextRun(GlyphFormat), Image(ImageBufferKind), - YuvImage(ImageBufferKind, YuvFormat, YuvColorSpace), AlignedGradient, AngleGradient, - RadialGradient, BorderCorner, BorderEdge, } @@ -80,6 +76,8 @@ pub enum BrushBatchKind { source_id: RenderTaskId, backdrop_id: RenderTaskId, }, + YuvImage(ImageBufferKind, YuvFormat, YuvColorSpace), + RadialGradient, } #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] @@ -953,6 +951,7 @@ impl AlphaBatchBuilder { z, segment_index: 0, edge_flags: EdgeAaSegmentMask::empty(), + brush_flags: BrushFlags::PERSPECTIVE_INTERPOLATION, user_data: [ cache_task_address.0 as i32, BrushImageKind::Simple as i32, @@ -1039,6 +1038,7 @@ impl AlphaBatchBuilder { z, segment_index: 0, edge_flags: EdgeAaSegmentMask::empty(), + brush_flags: BrushFlags::PERSPECTIVE_INTERPOLATION, user_data: [ cache_task_address.0 as i32, BrushImageKind::Simple as i32, @@ -1052,12 +1052,12 @@ impl AlphaBatchBuilder { } let secondary_id = secondary_render_task_id.expect("no secondary!?"); - let render_task = &render_tasks[secondary_id]; + let saved_index = render_tasks[secondary_id].saved_index.expect("no saved index!?"); + debug_assert_ne!(saved_index, SavedTargetIndex::PENDING); let secondary_task_address = render_tasks.get_task_address(secondary_id); - let render_pass_index = render_task.pass_index.expect("no render_pass_index!?"); let secondary_textures = BatchTextures { colors: [ - SourceTexture::RenderTaskCacheRGBA8(render_pass_index), + SourceTexture::RenderTaskCache(saved_index), SourceTexture::Invalid, SourceTexture::Invalid, ], @@ -1116,6 +1116,7 @@ impl AlphaBatchBuilder { z, segment_index: 0, edge_flags: EdgeAaSegmentMask::empty(), + brush_flags: BrushFlags::empty(), user_data: [ cache_task_address.0 as i32, filter_mode, @@ -1155,6 +1156,7 @@ impl AlphaBatchBuilder { z, segment_index: 0, edge_flags: EdgeAaSegmentMask::empty(), + brush_flags: BrushFlags::empty(), user_data: [ mode as u32 as i32, backdrop_task_address.0 as i32, @@ -1226,73 +1228,6 @@ impl AlphaBatchBuilder { let batch = self.batch_list.get_suitable_batch(key, &task_relative_bounding_rect); batch.push(base_instance.build(0, 0, 0)); } - PrimitiveKind::RadialGradient => { - let kind = BatchKind::Transformable( - transform_kind, - TransformBatchKind::RadialGradient, - ); - let key = BatchKey::new(kind, non_segmented_blend_mode, no_textures); - let batch = self.batch_list.get_suitable_batch(key, &task_relative_bounding_rect); - batch.push(base_instance.build(0, 0, 0)); - } - PrimitiveKind::YuvImage => { - let mut textures = BatchTextures::no_texture(); - let mut uv_rect_addresses = [0; 3]; - let image_yuv_cpu = - &ctx.prim_store.cpu_yuv_images[prim_metadata.cpu_prim_index.0]; - - //yuv channel - let channel_count = image_yuv_cpu.format.get_plane_num(); - debug_assert!(channel_count <= 3); - for channel in 0 .. channel_count { - let image_key = image_yuv_cpu.yuv_key[channel]; - - let cache_item = resolve_image( - ImageRequest { - key: image_key, - rendering: image_yuv_cpu.image_rendering, - tile: None, - }, - ctx.resource_cache, - gpu_cache, - deferred_resolves, - ); - - if cache_item.texture_id == SourceTexture::Invalid { - warn!("Warnings: skip a PrimitiveKind::YuvImage"); - debug!("at {:?}.", task_relative_bounding_rect); - return; - } - - textures.colors[channel] = cache_item.texture_id; - uv_rect_addresses[channel] = cache_item.uv_rect_handle.as_int(gpu_cache); - } - - // All yuv textures should be the same type. - let buffer_kind = get_buffer_kind(textures.colors[0]); - assert!( - textures.colors[1 .. image_yuv_cpu.format.get_plane_num()] - .iter() - .all(|&tid| buffer_kind == get_buffer_kind(tid)) - ); - - let kind = BatchKind::Transformable( - transform_kind, - TransformBatchKind::YuvImage( - buffer_kind, - image_yuv_cpu.format, - image_yuv_cpu.color_space, - ), - ); - let key = BatchKey::new(kind, non_segmented_blend_mode, textures); - let batch = self.batch_list.get_suitable_batch(key, &task_relative_bounding_rect); - - batch.push(base_instance.build( - uv_rect_addresses[0], - uv_rect_addresses[1], - uv_rect_addresses[2], - )); - } } } @@ -1324,6 +1259,7 @@ impl AlphaBatchBuilder { z, segment_index: 0, edge_flags: EdgeAaSegmentMask::all(), + brush_flags: BrushFlags::PERSPECTIVE_INTERPOLATION, user_data, }; @@ -1440,6 +1376,71 @@ impl BrushPrimitive { [0; 3], )) } + BrushKind::RadialGradient { ref stops_handle, .. } => { + Some(( + BrushBatchKind::RadialGradient, + BatchTextures::no_texture(), + [ + stops_handle.as_int(gpu_cache), + 0, + 0, + ], + )) + } + BrushKind::YuvImage { format, yuv_key, image_rendering, color_space } => { + let mut textures = BatchTextures::no_texture(); + let mut uv_rect_addresses = [0; 3]; + + //yuv channel + let channel_count = format.get_plane_num(); + debug_assert!(channel_count <= 3); + for channel in 0 .. channel_count { + let image_key = yuv_key[channel]; + + let cache_item = resolve_image( + ImageRequest { + key: image_key, + rendering: image_rendering, + tile: None, + }, + resource_cache, + gpu_cache, + deferred_resolves, + ); + + if cache_item.texture_id == SourceTexture::Invalid { + warn!("Warnings: skip a PrimitiveKind::YuvImage"); + return None; + } + + textures.colors[channel] = cache_item.texture_id; + uv_rect_addresses[channel] = cache_item.uv_rect_handle.as_int(gpu_cache); + } + + // All yuv textures should be the same type. + let buffer_kind = get_buffer_kind(textures.colors[0]); + assert!( + textures.colors[1 .. format.get_plane_num()] + .iter() + .all(|&tid| buffer_kind == get_buffer_kind(tid)) + ); + + let kind = BrushBatchKind::YuvImage( + buffer_kind, + format, + color_space, + ); + + Some(( + kind, + textures, + [ + uv_rect_addresses[0], + uv_rect_addresses[1], + uv_rect_addresses[2], + ], + )) + } BrushKind::Mask { .. } => { unreachable!("bug: mask brushes not expected in normal alpha pass"); } @@ -1463,10 +1464,8 @@ impl AlphaBatchHelpers for PrimitiveStore { } PrimitiveKind::Border | - PrimitiveKind::YuvImage | PrimitiveKind::AlignedGradient | PrimitiveKind::AngleGradient | - PrimitiveKind::RadialGradient | PrimitiveKind::Picture => { BlendMode::PremultipliedAlpha } @@ -1486,6 +1485,8 @@ impl AlphaBatchHelpers for PrimitiveStore { BrushKind::Solid { .. } | BrushKind::Mask { .. } | BrushKind::Line { .. } | + BrushKind::YuvImage { .. } | + BrushKind::RadialGradient { .. } | BrushKind::Picture => { BlendMode::PremultipliedAlpha } diff --git a/gfx/webrender/src/border.rs b/gfx/webrender/src/border.rs index 677b76b0b0a4..6e809bcd827c 100644 --- a/gfx/webrender/src/border.rs +++ b/gfx/webrender/src/border.rs @@ -2,15 +2,14 @@ * 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, BorderSide, BorderStyle, BorderWidths, ClipAndScrollInfo, ColorF}; -use api::{LayerPoint, LayerRect, LayerPrimitiveInfo, LayerSize}; -use api::{NormalBorder, RepeatMode, TexelRect}; +use api::{BorderRadius, BorderSide, BorderStyle, BorderWidths, ColorF, LayerPoint}; +use api::{LayerPrimitiveInfo, LayerRect, LayerSize, NormalBorder, RepeatMode, TexelRect}; use clip::ClipSource; use ellipse::Ellipse; use frame_builder::FrameBuilder; use gpu_cache::GpuDataRequest; -use prim_store::{BorderPrimitiveCpu, BrushSegment, BrushSegmentDescriptor}; -use prim_store::{BrushClipMaskKind, EdgeAaSegmentMask, PrimitiveContainer}; +use prim_store::{BorderPrimitiveCpu, BrushClipMaskKind, BrushSegment, BrushSegmentDescriptor}; +use prim_store::{EdgeAaSegmentMask, PrimitiveContainer, ScrollNodeAndClipChain}; use util::{lerp, pack_as_float}; #[repr(u8)] @@ -286,7 +285,7 @@ impl FrameBuilder { info: &LayerPrimitiveInfo, border: &NormalBorder, widths: &BorderWidths, - clip_and_scroll: ClipAndScrollInfo, + clip_and_scroll: ScrollNodeAndClipChain, corner_instances: [BorderCornerInstance; 4], edges: [BorderEdgeKind; 4], clip_sources: Vec, @@ -354,7 +353,7 @@ impl FrameBuilder { info: &LayerPrimitiveInfo, border: &NormalBorder, widths: &BorderWidths, - clip_and_scroll: ClipAndScrollInfo, + clip_and_scroll: ScrollNodeAndClipChain, ) { // The border shader is quite expensive. For simple borders, we can just draw // the border with a few rectangles. This generally gives better batching, and diff --git a/gfx/webrender/src/box_shadow.rs b/gfx/webrender/src/box_shadow.rs index 7d369be6b29b..9b66cf37eeaa 100644 --- a/gfx/webrender/src/box_shadow.rs +++ b/gfx/webrender/src/box_shadow.rs @@ -2,16 +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::{ColorF, LayerPoint, LayerRect, LayerSize, LayerVector2D}; -use api::{BorderRadius, BoxShadowClipMode, LayoutSize, LayerPrimitiveInfo}; -use api::{ClipMode, ClipAndScrollInfo, ComplexClipRegion, LocalClip}; -use api::{PipelineId}; +use api::{BorderRadius, BoxShadowClipMode, ClipMode, ColorF, ComplexClipRegion, LayerPoint}; +use api::{LayerPrimitiveInfo, LayerRect, LayerSize, LayerVector2D, LayoutSize, LocalClip}; +use api::PipelineId; use app_units::Au; use clip::ClipSource; use frame_builder::FrameBuilder; use gpu_types::BrushImageKind; -use prim_store::{PrimitiveContainer}; -use prim_store::{BrushMaskKind, BrushKind, BrushPrimitive}; +use prim_store::{BrushKind, BrushMaskKind, BrushPrimitive, PrimitiveContainer}; +use prim_store::ScrollNodeAndClipChain; use picture::PicturePrimitive; use util::RectHelpers; use render_task::MAX_BLUR_STD_DEVIATION; @@ -53,7 +52,7 @@ impl FrameBuilder { pub fn add_box_shadow( &mut self, pipeline_id: PipelineId, - clip_and_scroll: ClipAndScrollInfo, + clip_and_scroll: ScrollNodeAndClipChain, prim_info: &LayerPrimitiveInfo, box_offset: &LayerVector2D, color: &ColorF, @@ -88,7 +87,8 @@ impl FrameBuilder { if box_offset.x == 0.0 && box_offset.y == 0.0 && spread_amount == 0.0 { return; } - let mut clips = Vec::new(); + let mut clips = Vec::with_capacity(2); + clips.push(ClipSource::Rectangle(*prim_info.local_clip.clip_rect())); let fast_info = match clip_mode { BoxShadowClipMode::Outset => { @@ -264,8 +264,10 @@ impl FrameBuilder { border_radius, ClipMode::ClipOut, )); - - let pic_info = LayerPrimitiveInfo::new(pic_rect); + let pic_info = LayerPrimitiveInfo::with_clip_rect( + pic_rect, + *prim_info.local_clip.clip_rect() + ); self.add_primitive( clip_and_scroll, &pic_info, @@ -332,6 +334,12 @@ impl FrameBuilder { clip_and_scroll ); + let clip_rect = prim_info.local_clip.clip_rect(); + let clip_rect = match prim_info.rect.intersection(clip_rect) { + Some(clip_rect) => clip_rect, + None => return, + }; + // Draw the picture one pixel outside the original // rect to account for the inflate above. This // extra edge will be clipped by the local clip @@ -339,7 +347,7 @@ impl FrameBuilder { let pic_rect = prim_info.rect.inflate(inflate_size + box_offset.x.abs(), inflate_size + box_offset.y.abs()); let pic_info = LayerPrimitiveInfo::with_clip_rect( pic_rect, - prim_info.rect + clip_rect ); // Add a normal clip to ensure nothing gets drawn diff --git a/gfx/webrender/src/clip.rs b/gfx/webrender/src/clip.rs index ead309140f12..59ed948ac292 100644 --- a/gfx/webrender/src/clip.rs +++ b/gfx/webrender/src/clip.rs @@ -6,12 +6,15 @@ use api::{BorderRadius, ClipMode, ComplexClipRegion, DeviceIntRect, DevicePixelS use api::{ImageRendering, LayerRect, LayerToWorldTransform, LayoutPoint, LayoutVector2D}; use api::LocalClip; use border::{BorderCornerClipSource, ensure_no_corner_overlap}; +use clip_scroll_tree::{ClipChainIndex, CoordinateSystemId}; use ellipse::Ellipse; use freelist::{FreeList, FreeListHandle, WeakFreeListHandle}; use gpu_cache::{GpuCache, GpuCacheHandle, ToGpuBlocks}; +use gpu_types::ClipScrollNodeIndex; use prim_store::{ClipData, ImageMaskData}; use resource_cache::{ImageRequest, ResourceCache}; use util::{MaxRect, MatrixHelpers, calculate_screen_bounding_rect, extract_inner_rect_safe}; +use std::rc::Rc; pub type ClipStore = FreeList; pub type ClipSourcesHandle = FreeListHandle; @@ -349,3 +352,106 @@ pub fn rounded_rectangle_contains_point(point: &LayoutPoint, true } + +pub type ClipChainNodeRef = Option>; + +#[derive(Debug, Clone)] +pub struct ClipChainNode { + pub work_item: ClipWorkItem, + pub local_clip_rect: LayerRect, + pub screen_outer_rect: DeviceIntRect, + pub screen_inner_rect: DeviceIntRect, + pub prev: ClipChainNodeRef, +} + +#[derive(Debug, Clone)] +pub struct ClipChain { + pub parent_index: Option, + pub combined_outer_screen_rect: DeviceIntRect, + pub combined_inner_screen_rect: DeviceIntRect, + pub nodes: ClipChainNodeRef, +} + +impl ClipChain { + pub fn empty(screen_rect: &DeviceIntRect) -> ClipChain { + ClipChain { + parent_index: None, + combined_inner_screen_rect: *screen_rect, + combined_outer_screen_rect: *screen_rect, + nodes: None, + } + } + + pub fn new_with_added_node( + &self, + work_item: ClipWorkItem, + local_clip_rect: LayerRect, + screen_outer_rect: DeviceIntRect, + screen_inner_rect: DeviceIntRect, + ) -> ClipChain { + // If the new node's inner rectangle completely surrounds our outer rectangle, + // we can discard the new node entirely since it isn't going to affect anything. + if screen_inner_rect.contains_rect(&self.combined_outer_screen_rect) { + return self.clone(); + } + + let new_node = ClipChainNode { + work_item, + local_clip_rect, + screen_outer_rect, + screen_inner_rect, + prev: None, + }; + + let mut new_chain = self.clone(); + new_chain.add_node(new_node); + new_chain + } + + pub fn add_node(&mut self, mut new_node: ClipChainNode) { + new_node.prev = self.nodes.clone(); + + // If this clip's outer rectangle is completely enclosed by the clip + // chain's inner rectangle, then the only clip that matters from this point + // on is this clip. We can disconnect this clip from the parent clip chain. + if self.combined_inner_screen_rect.contains_rect(&new_node.screen_outer_rect) { + new_node.prev = None; + } + + self.combined_outer_screen_rect = + self.combined_outer_screen_rect.intersection(&new_node.screen_outer_rect) + .unwrap_or_else(DeviceIntRect::zero); + self.combined_inner_screen_rect = + self.combined_inner_screen_rect.intersection(&new_node.screen_inner_rect) + .unwrap_or_else(DeviceIntRect::zero); + + self.nodes = Some(Rc::new(new_node)); + } +} + +pub struct ClipChainNodeIter { + pub current: ClipChainNodeRef, +} + +impl Iterator for ClipChainNodeIter { + type Item = Rc; + + fn next(&mut self) -> ClipChainNodeRef { + let previous = self.current.clone(); + self.current = match self.current { + Some(ref item) => item.prev.clone(), + None => return None, + }; + previous + } +} + +#[derive(Debug, Clone)] +#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(feature = "replay", derive(Deserialize))] +pub struct ClipWorkItem { + pub scroll_node_data_index: ClipScrollNodeIndex, + pub clip_sources: ClipSourcesWeakHandle, + pub coordinate_system_id: CoordinateSystemId, +} + diff --git a/gfx/webrender/src/clip_scroll_node.rs b/gfx/webrender/src/clip_scroll_node.rs index 7df399310750..c699a7912f2b 100644 --- a/gfx/webrender/src/clip_scroll_node.rs +++ b/gfx/webrender/src/clip_scroll_node.rs @@ -5,14 +5,13 @@ use api::{ClipId, DevicePixelScale, ExternalScrollId, LayerPixel, LayerPoint, LayerRect}; use api::{LayerSize, LayerToWorldTransform, LayerTransform, LayerVector2D, LayoutTransform}; use api::{LayoutVector2D, PipelineId, PropertyBinding, ScrollClamping, ScrollEventPhase}; -use api::{ScrollLocation, ScrollNodeIdType, ScrollSensitivity, StickyOffsetBounds, WorldPoint}; -use clip::{ClipSourcesHandle, ClipStore}; -use clip_scroll_tree::{CoordinateSystemId, TransformUpdateState}; +use api::{ScrollLocation, ScrollSensitivity, StickyOffsetBounds, WorldPoint}; +use clip::{ClipChain, ClipSourcesHandle, ClipStore, ClipWorkItem}; +use clip_scroll_tree::{ClipChainIndex, CoordinateSystemId, TransformUpdateState}; use euclid::SideOffsets2D; use geometry::ray_intersects_rect; use gpu_cache::GpuCache; use gpu_types::{ClipScrollNodeIndex, ClipScrollNodeData}; -use render_task::{ClipChain, ClipWorkItem}; use resource_cache::ResourceCache; use scene::SceneProperties; use spring::{DAMPING, STIFFNESS, Spring}; @@ -56,7 +55,10 @@ pub enum NodeType { ReferenceFrame(ReferenceFrameInfo), /// Other nodes just do clipping, but no transformation. - Clip(ClipSourcesHandle), + Clip { + handle: ClipSourcesHandle, + clip_chain_index: ClipChainIndex + }, /// Transforms it's content, but doesn't clip it. Can also be adjusted /// by scroll events or setting scroll offsets. @@ -106,9 +108,6 @@ pub struct ClipScrollNode { /// The type of this node and any data associated with that node type. pub node_type: NodeType, - /// The ClipChain that will be used if this node is used as the 'clipping node.' - pub clip_chain: Option, - /// True if this node is transformed by an invertible transform. If not, display items /// transformed by this node will not be displayed and display items not transformed by this /// node will not be clipped by clips that are transformed by this node. @@ -128,7 +127,7 @@ pub struct ClipScrollNode { } impl ClipScrollNode { - fn new( + pub fn new( pipeline_id: PipelineId, parent_id: Option, rect: &LayerRect, @@ -142,7 +141,6 @@ impl ClipScrollNode { children: Vec::new(), pipeline_id, node_type: node_type, - clip_chain: None, invertible: true, coordinate_system_id: CoordinateSystemId(0), coordinate_system_relative_transform: TransformOrOffset::zero(), @@ -170,15 +168,6 @@ impl ClipScrollNode { Self::new(pipeline_id, Some(parent_id), frame_rect, node_type) } - pub fn new_clip_node( - pipeline_id: PipelineId, - parent_id: ClipId, - handle: ClipSourcesHandle, - clip_rect: LayerRect, - ) -> Self { - Self::new(pipeline_id, Some(parent_id), &clip_rect, NodeType::Clip(handle)) - } - pub fn new_reference_frame( parent_id: Option, frame_rect: &LayerRect, @@ -271,7 +260,6 @@ impl ClipScrollNode { self.invertible = false; self.world_content_transform = LayerToWorldTransform::identity(); self.world_viewport_transform = LayerToWorldTransform::identity(); - self.clip_chain = None; } pub fn push_gpu_node_data(&mut self, node_data: &mut Vec) { @@ -304,6 +292,7 @@ impl ClipScrollNode { resource_cache: &mut ResourceCache, gpu_cache: &mut GpuCache, scene_properties: &SceneProperties, + clip_chains: &mut Vec, ) { // If any of our parents was not rendered, we are not rendered either and can just // quit here. @@ -331,6 +320,7 @@ impl ClipScrollNode { clip_store, resource_cache, gpu_cache, + clip_chains, ); } @@ -341,11 +331,11 @@ impl ClipScrollNode { clip_store: &mut ClipStore, resource_cache: &mut ResourceCache, gpu_cache: &mut GpuCache, + clip_chains: &mut Vec, ) { - let clip_sources_handle = match self.node_type { - NodeType::Clip(ref handle) => handle, + let (clip_sources_handle, clip_chain_index) = match self.node_type { + NodeType::Clip { ref handle, clip_chain_index } => (handle, clip_chain_index), _ => { - self.clip_chain = Some(state.parent_clip_chain.clone()); self.invertible = true; return; } @@ -364,29 +354,22 @@ impl ClipScrollNode { "Clipping node didn't have outer rect." ); - // If this clip's inner rectangle completely surrounds the existing clip - // chain's outer rectangle, we can discard this clip entirely since it isn't - // going to affect anything. - if screen_inner_rect.contains_rect(&state.parent_clip_chain.combined_outer_screen_rect) { - self.clip_chain = Some(state.parent_clip_chain.clone()); - return; - } - let 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, }; - let clip_chain = state.parent_clip_chain.new_with_added_node( + let mut clip_chain = clip_chains[state.parent_clip_chain_index.0].new_with_added_node( work_item, self.coordinate_system_relative_transform.apply(&local_outer_rect), screen_outer_rect, screen_inner_rect, ); - self.clip_chain = Some(clip_chain.clone()); - state.parent_clip_chain = clip_chain; + clip_chain.parent_index = Some(state.parent_clip_chain_index); + clip_chains[clip_chain_index.0] = clip_chain; + state.parent_clip_chain_index = clip_chain_index; } pub fn update_transform( @@ -621,7 +604,7 @@ impl ClipScrollNode { 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; @@ -768,12 +751,7 @@ impl ClipScrollNode { } } - pub fn matches_id(&self, node_id: ClipId, id_to_match: ScrollNodeIdType) -> bool { - let external_id = match id_to_match { - ScrollNodeIdType::ExternalScrollId(id) => id, - ScrollNodeIdType::ClipId(clip_id) => return node_id == clip_id, - }; - + pub fn matches_external_id(&self, external_id: ExternalScrollId) -> bool { match self.node_type { NodeType::ScrollFrame(info) if info.external_id == Some(external_id) => true, _ => false, diff --git a/gfx/webrender/src/clip_scroll_tree.rs b/gfx/webrender/src/clip_scroll_tree.rs index c82bcb927884..c3adee1b30d1 100644 --- a/gfx/webrender/src/clip_scroll_tree.rs +++ b/gfx/webrender/src/clip_scroll_tree.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::{ClipChainId, ClipId, DeviceIntRect, DevicePixelScale, ExternalScrollId, LayerPoint}; -use api::{LayerRect, LayerToWorldTransform, LayerVector2D, PipelineId, ScrollClamping}; -use api::{ScrollEventPhase, ScrollLocation, ScrollNodeIdType}; -use api::{ScrollNodeState, WorldPoint}; -use clip::ClipStore; +use api::{ClipId, DeviceIntRect, DevicePixelScale, ExternalScrollId, LayerPoint, LayerRect}; +use api::{LayerToWorldTransform, LayerVector2D, PipelineId, ScrollClamping, ScrollEventPhase}; +use api::{ScrollLocation, ScrollNodeState, WorldPoint}; +use clip::{ClipChain, ClipSourcesHandle, ClipStore}; use clip_scroll_node::{ClipScrollNode, NodeType, ScrollFrameInfo, StickyFrameInfo}; use gpu_cache::GpuCache; use gpu_types::{ClipScrollNodeIndex, ClipScrollNodeData}; use internal_types::{FastHashMap, FastHashSet}; use print_tree::{PrintTree, PrintTreePrinter}; -use render_task::ClipChain; use resource_cache::ResourceCache; use scene::SceneProperties; use util::TransformOrOffset; @@ -44,11 +42,14 @@ impl CoordinateSystemId { } pub struct ClipChainDescriptor { - pub id: ClipChainId, - pub parent: Option, + pub index: ClipChainIndex, + pub parent: Option, pub clips: Vec, } +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct ClipChainIndex(pub usize); + pub struct ClipScrollTree { pub nodes: FastHashMap, @@ -57,10 +58,11 @@ pub struct ClipScrollTree { /// the children of ClipChains later in the list. pub clip_chains_descriptors: Vec, - /// A HashMap of built ClipChains that are described by `clip_chains_descriptors`. - pub clip_chains: FastHashMap, + /// A vector of all ClipChains in this ClipScrollTree including those from + /// ClipChainDescriptors and also those defined by the clipping node hierarchy. + pub clip_chains: Vec, - pub pending_scroll_offsets: FastHashMap, + pub pending_scroll_offsets: FastHashMap, /// The ClipId of the currently scrolling node. Used to allow the same /// node to scroll even if a touch operation leaves the boundaries of that node. @@ -90,7 +92,9 @@ pub struct TransformUpdateState { pub parent_accumulated_scroll_offset: LayerVector2D, pub nearest_scrolling_ancestor_offset: LayerVector2D, pub nearest_scrolling_ancestor_viewport: LayerRect, - pub parent_clip_chain: ClipChain, + + /// The index of the current parent's clip chain. + pub parent_clip_chain_index: ClipChainIndex, /// An id for keeping track of the axis-aligned space of this node. This is used in /// order to to track what kinds of clip optimizations can be done for a particular @@ -113,7 +117,7 @@ impl ClipScrollTree { ClipScrollTree { nodes: FastHashMap::default(), clip_chains_descriptors: Vec::new(), - clip_chains: FastHashMap::default(), + clip_chains: vec![ClipChain::empty(&DeviceIntRect::zero())], pending_scroll_offsets: FastHashMap::default(), currently_scrolling_node_id: None, root_reference_frame_id: ClipId::root_reference_frame(dummy_pipeline), @@ -211,7 +215,7 @@ impl ClipScrollTree { } self.pipelines_to_discard.clear(); - self.clip_chains.clear(); + self.clip_chains = vec![ClipChain::empty(&DeviceIntRect::zero())]; self.clip_chains_descriptors.clear(); scroll_states } @@ -219,11 +223,11 @@ impl ClipScrollTree { pub fn scroll_node( &mut self, origin: LayerPoint, - id: ScrollNodeIdType, + id: ExternalScrollId, clamp: ScrollClamping ) -> bool { - for (clip_id, node) in &mut self.nodes { - if node.matches_id(*clip_id, id) { + for node in &mut self.nodes.values_mut() { + if node.matches_external_id(id) { return node.set_scroll_origin(&origin, clamp); } } @@ -321,6 +325,8 @@ impl ClipScrollTree { return; } + self.clip_chains[0] = ClipChain::empty(screen_rect); + let root_reference_frame_id = self.root_reference_frame_id(); let mut state = TransformUpdateState { parent_reference_frame_transform: LayerToWorldTransform::create_translation( @@ -331,7 +337,7 @@ impl ClipScrollTree { parent_accumulated_scroll_offset: LayerVector2D::zero(), nearest_scrolling_ancestor_offset: LayerVector2D::zero(), nearest_scrolling_ancestor_viewport: LayerRect::zero(), - parent_clip_chain: ClipChain::empty(screen_rect), + parent_clip_chain_index: ClipChainIndex(0), current_coordinate_system_id: CoordinateSystemId::root(), coordinate_system_relative_transform: TransformOrOffset::zero(), invertible: true, @@ -384,6 +390,7 @@ impl ClipScrollTree { resource_cache, gpu_cache, scene_properties, + &mut self.clip_chains, ); node.push_gpu_node_data(gpu_node_data); @@ -417,21 +424,28 @@ impl ClipScrollTree { // ClipScrollNode clipping nodes. Here we start the ClipChain with a clone of the // parent's node, if necessary. let mut chain = match descriptor.parent { - Some(id) => self.clip_chains[&id].clone(), + Some(index) => self.clip_chains[index.0].clone(), None => ClipChain::empty(screen_rect), }; // Now we walk through each ClipScrollNode in the vector of clip nodes and // extract their ClipChain nodes to construct the final list. for clip_id in &descriptor.clips { - if let Some(ref node_chain) = self.nodes[&clip_id].clip_chain { - if let Some(ref nodes) = node_chain.nodes { - chain.add_node((**nodes).clone()); + let node_clip_chain_index = match self.nodes[&clip_id].node_type { + NodeType::Clip { clip_chain_index, .. } => clip_chain_index, + _ => { + warn!("Tried to create a clip chain with non-clipping node."); + continue; } + }; + + if let Some(ref nodes) = self.clip_chains[node_clip_chain_index.0].nodes { + chain.add_node((**nodes).clone()); } } - self.clip_chains.insert(descriptor.id, chain); + chain.parent_index = descriptor.parent; + self.clip_chains[descriptor.index.0] = chain; } } @@ -442,30 +456,37 @@ impl ClipScrollTree { } pub fn finalize_and_apply_pending_scroll_offsets(&mut self, old_states: ScrollStates) { - for (clip_id, node) in &mut self.nodes { + for node in self.nodes.values_mut() { let external_id = match node.node_type { - NodeType::ScrollFrame(info) => info.external_id, - _ => None, + NodeType::ScrollFrame(ScrollFrameInfo { external_id: Some(id), ..} ) => id, + _ => continue, }; - if let Some(external_id) = external_id { - if let Some(scrolling_state) = old_states.get(&external_id) { - node.apply_old_scrolling_state(scrolling_state); - } - - - let id = external_id.into(); - if let Some((offset, clamping)) = self.pending_scroll_offsets.remove(&id) { - node.set_scroll_origin(&offset, clamping); - } + if let Some(scrolling_state) = old_states.get(&external_id) { + node.apply_old_scrolling_state(scrolling_state); } - if let Some((offset, clamping)) = self.pending_scroll_offsets.remove(&clip_id.into()) { + + if let Some((offset, clamping)) = self.pending_scroll_offsets.remove(&external_id) { node.set_scroll_origin(&offset, clamping); } } } + pub fn add_clip_node( + &mut self, + id: ClipId, + parent_id: ClipId, + handle: ClipSourcesHandle, + clip_rect: LayerRect, + ) -> ClipChainIndex { + let clip_chain_index = self.allocate_clip_chain(); + let node_type = NodeType::Clip { handle, clip_chain_index }; + let node = ClipScrollNode::new(id.pipeline_id(), Some(parent_id), &clip_rect, node_type); + self.add_node(node, id); + clip_chain_index + } + pub fn add_sticky_frame( &mut self, id: ClipId, @@ -484,11 +505,12 @@ impl ClipScrollTree { pub fn add_clip_chain_descriptor( &mut self, - id: ClipChainId, - parent: Option, + parent: Option, clips: Vec - ) { - self.clip_chains_descriptors.push(ClipChainDescriptor { id, parent, clips }); + ) -> ClipChainIndex { + let index = self.allocate_clip_chain(); + self.clip_chains_descriptors.push(ClipChainDescriptor { index, parent, clips }); + index } pub fn add_node(&mut self, node: ClipScrollNode, id: ClipId) { @@ -515,11 +537,11 @@ impl ClipScrollTree { let node = self.nodes.get(id).unwrap(); match node.node_type { - NodeType::Clip(ref clip_sources_handle) => { + NodeType::Clip { ref handle, .. } => { pt.new_level("Clip".to_owned()); pt.add_item(format!("id: {:?}", id)); - let clips = clip_store.get(&clip_sources_handle).clips(); + let clips = clip_store.get(&handle).clips(); pt.new_level(format!("Clip Sources [{}]", clips.len())); for source in clips { pt.add_item(format!("{:?}", source)); @@ -581,11 +603,15 @@ impl ClipScrollTree { } } - pub fn get_clip_chain(&self, id: &ClipId) -> Option<&ClipChain> { - match id { - &ClipId::ClipChain(clip_chain_id) => Some(&self.clip_chains[&clip_chain_id]), - _ => self.nodes[id].clip_chain.as_ref(), - } + pub fn allocate_clip_chain(&mut self) -> ClipChainIndex { + debug_assert!(!self.clip_chains.is_empty()); + let new_clip_chain =self.clip_chains[0].clone(); + self.clip_chains.push(new_clip_chain); + ClipChainIndex(self.clip_chains.len() - 1) + } + + pub fn get_clip_chain(&self, index: ClipChainIndex) -> &ClipChain { + &self.clip_chains[index.0] } } diff --git a/gfx/webrender/src/device.rs b/gfx/webrender/src/device.rs index 58e64c3a9c76..c40af173ba6c 100644 --- a/gfx/webrender/src/device.rs +++ b/gfx/webrender/src/device.rs @@ -438,6 +438,7 @@ pub struct Texture { render_target: Option, fbo_ids: Vec, depth_rb: Option, + last_frame_used: FrameId, } impl Texture { @@ -473,6 +474,10 @@ impl Texture { self.render_target.as_ref() } + pub fn used_in_frame(&self, frame_id: FrameId) -> bool { + self.last_frame_used == frame_id + } + #[cfg(feature = "replay")] pub fn into_external(mut self) -> ExternalTexture { let ext = ExternalTexture { @@ -940,6 +945,7 @@ impl Device { render_target: None, fbo_ids: vec![], depth_rb: None, + last_frame_used: self.frame_id, } } @@ -1019,6 +1025,7 @@ impl Device { texture.filter = filter; texture.layer_count = layer_count; texture.render_target = render_target; + texture.last_frame_used = self.frame_id; self.bind_texture(DEFAULT_TEXTURE, texture); self.set_texture_parameters(texture.target, filter); diff --git a/gfx/webrender/src/frame.rs b/gfx/webrender/src/frame.rs index 2f7fff636c48..8a4d54632d01 100644 --- a/gfx/webrender/src/frame.rs +++ b/gfx/webrender/src/frame.rs @@ -3,21 +3,22 @@ * 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::{BuiltDisplayListIter, ClipAndScrollInfo, ClipId, ColorF, ComplexClipRegion}; -use api::{DevicePixelScale, DeviceUintRect, DeviceUintSize, DisplayItemRef, DocumentLayer, Epoch}; -use api::{ExternalScrollId, FilterOp, IframeDisplayItem, ImageDisplayItem, ItemRange, LayerPoint}; +use api::{BuiltDisplayListIter, ClipId, ColorF, ComplexClipRegion, DevicePixelScale}; +use api::{DeviceUintRect, DeviceUintSize, DisplayItemRef, DocumentLayer, Epoch, ExternalScrollId}; +use api::{FilterOp, IframeDisplayItem, ImageDisplayItem, ItemRange, LayerPoint}; use api::{LayerPrimitiveInfo, LayerRect, LayerSize, LayerVector2D, LayoutSize, PipelineId}; use api::{ScrollClamping, ScrollEventPhase, ScrollFrameDisplayItem, ScrollLocation}; -use api::{ScrollNodeIdType, ScrollNodeState, ScrollPolicy, ScrollSensitivity, SpecificDisplayItem}; -use api::{StackingContext, TileOffset, TransformStyle, WorldPoint}; +use api::{ScrollNodeState, ScrollPolicy, ScrollSensitivity, SpecificDisplayItem, StackingContext}; +use api::{TileOffset, TransformStyle, WorldPoint}; use clip::ClipRegion; use clip_scroll_node::StickyFrameInfo; -use clip_scroll_tree::{ClipScrollTree, ScrollStates}; +use clip_scroll_tree::{ClipChainIndex, ClipScrollTree, ScrollStates}; use euclid::rect; use frame_builder::{FrameBuilder, FrameBuilderConfig, ScrollbarInfo}; use gpu_cache::GpuCache; use hit_test::HitTester; use internal_types::{FastHashMap, FastHashSet, RenderedDocument}; +use prim_store::ScrollNodeAndClipChain; use profiler::{GpuCacheProfileCounters, TextureCacheProfileCounters}; use resource_cache::{FontInstanceMap,ResourceCache, TiledImageMap}; use scene::{Scene, StackingContextHelpers, ScenePipeline, SceneProperties}; @@ -36,6 +37,53 @@ static DEFAULT_SCROLLBAR_COLOR: ColorF = ColorF { a: 0.6, }; +/// A data structure that keeps track of mapping between API clip ids and the indices +/// used internally in the ClipScrollTree to avoid having to do HashMap lookups. This +/// also includes a small LRU cache. Currently the cache is small (1 entry), but in the +/// future we could use uluru here to do something more involved. +pub struct ClipIdToIndexMapper { + map: FastHashMap, + cached_index: Option<(ClipId, ClipChainIndex)>, +} + +impl ClipIdToIndexMapper { + fn new() -> ClipIdToIndexMapper { + ClipIdToIndexMapper { + map: FastHashMap::default(), + cached_index: None, + } + } + + pub fn add(&mut self, id: ClipId, index: ClipChainIndex) { + debug_assert!(!self.map.contains_key(&id)); + self.map.insert(id, index); + } + + pub fn map_to_parent_clip_chain(&mut self, id: ClipId, parent_id: &ClipId) { + let parent_chain_index = self.map_clip_id(parent_id); + self.add(id, parent_chain_index); + } + + pub fn map_clip_id(&mut self, id: &ClipId) -> ClipChainIndex { + match self.cached_index { + Some((cached_id, cached_index)) if cached_id == *id => return cached_index, + _ => {} + } + + self.map[id] + } + + pub fn map_clip_id_and_cache_result(&mut self, id: &ClipId) -> ClipChainIndex { + let index = self.map_clip_id(id); + self.cached_index = Some((*id, index)); + index + } + + pub fn simple_scroll_and_clip_chain(&mut self, id: &ClipId) -> ScrollNodeAndClipChain { + ScrollNodeAndClipChain::new(*id, self.map_clip_id(&id)) + } +} + struct FlattenContext<'a> { scene: &'a Scene, builder: FrameBuilder, @@ -45,6 +93,7 @@ struct FlattenContext<'a> { pipeline_epochs: Vec<(PipelineId, Epoch)>, replacements: Vec<(ClipId, ClipId)>, output_pipelines: &'a FastHashSet, + id_to_index_mapper: ClipIdToIndexMapper, } impl<'a> FlattenContext<'a> { @@ -104,13 +153,23 @@ impl<'a> FlattenContext<'a> { let root_reference_frame_id = ClipId::root_reference_frame(pipeline_id); let root_scroll_frame_id = ClipId::root_scroll_node(pipeline_id); + let root_clip_chain_index = + self.id_to_index_mapper.map_clip_id_and_cache_result(&root_reference_frame_id); + let root_reference_frame_clip_and_scroll = ScrollNodeAndClipChain::new( + root_reference_frame_id, + root_clip_chain_index, + ); + self.builder.push_stacking_context( pipeline_id, CompositeOps::default(), TransformStyle::Flat, true, true, - ClipAndScrollInfo::simple(root_scroll_frame_id), + ScrollNodeAndClipChain::new( + ClipId::root_scroll_node(pipeline_id), + root_clip_chain_index, + ), self.output_pipelines, ); @@ -122,7 +181,7 @@ impl<'a> FlattenContext<'a> { let root_bounds = LayerRect::new(LayerPoint::zero(), *frame_size); let info = LayerPrimitiveInfo::new(root_bounds); self.builder.add_solid_rectangle( - ClipAndScrollInfo::simple(root_reference_frame_id), + root_reference_frame_clip_and_scroll, &info, bg_color, None, @@ -142,7 +201,7 @@ impl<'a> FlattenContext<'a> { let scrollbar_rect = LayerRect::new(LayerPoint::zero(), LayerSize::new(10.0, 70.0)); let container_rect = LayerRect::new(LayerPoint::zero(), *frame_size); self.builder.add_scroll_bar( - ClipAndScrollInfo::simple(root_reference_frame_id), + root_reference_frame_clip_and_scroll, &LayerPrimitiveInfo::new(scrollbar_rect), DEFAULT_SCROLLBAR_COLOR, ScrollbarInfo(root_scroll_frame_id, container_rect), @@ -184,19 +243,13 @@ impl<'a> FlattenContext<'a> { } } - fn flatten_clip( - &mut self, - pipeline_id: PipelineId, - parent_id: &ClipId, - new_clip_id: &ClipId, - clip_region: ClipRegion, - ) { + fn flatten_clip(&mut self, parent_id: &ClipId, new_clip_id: &ClipId, clip_region: ClipRegion) { self.builder.add_clip_node( *new_clip_id, *parent_id, - pipeline_id, clip_region, self.clip_scroll_tree, + &mut self.id_to_index_mapper, ); } @@ -205,7 +258,7 @@ impl<'a> FlattenContext<'a> { item: &DisplayItemRef, info: &ScrollFrameDisplayItem, pipeline_id: PipelineId, - clip_and_scroll: &ClipAndScrollInfo, + clip_and_scroll: &ScrollNodeAndClipChain, reference_frame_relative_offset: &LayerVector2D, ) { let complex_clips = self.get_complex_clips(pipeline_id, item.complex_clip().0); @@ -229,9 +282,9 @@ impl<'a> FlattenContext<'a> { self.builder.add_clip_node( info.clip_id, clip_and_scroll.scroll_node_id, - pipeline_id, clip_region, self.clip_scroll_tree, + &mut self.id_to_index_mapper, ); self.builder.add_scroll_frame( @@ -243,6 +296,7 @@ impl<'a> FlattenContext<'a> { &content_rect.size, info.scroll_sensitivity, self.clip_scroll_tree, + &mut self.id_to_index_mapper, ); } @@ -250,7 +304,8 @@ impl<'a> FlattenContext<'a> { &mut self, traversal: &mut BuiltDisplayListIter<'a>, pipeline_id: PipelineId, - context_scroll_node_id: ClipId, + unreplaced_scroll_id: ClipId, + clip_and_scroll: ScrollNodeAndClipChain, mut reference_frame_relative_offset: LayerVector2D, bounds: &LayerRect, stacking_context: &StackingContext, @@ -279,7 +334,7 @@ impl<'a> FlattenContext<'a> { if stacking_context.scroll_policy == ScrollPolicy::Fixed { self.replacements.push(( - context_scroll_node_id, + unreplaced_scroll_id, self.builder.current_reference_frame_id(), )); } @@ -296,30 +351,33 @@ impl<'a> FlattenContext<'a> { ); let reference_frame_bounds = LayerRect::new(LayerPoint::zero(), bounds.size); - let mut parent_id = self.apply_scroll_frame_id_replacement(context_scroll_node_id); self.builder.push_reference_frame( reference_frame_id, - Some(parent_id), + Some(clip_and_scroll.scroll_node_id), pipeline_id, &reference_frame_bounds, stacking_context.transform, stacking_context.perspective, reference_frame_relative_offset, self.clip_scroll_tree, + &mut self.id_to_index_mapper, ); - self.replacements.push((context_scroll_node_id, reference_frame_id)); + self.replacements.push((unreplaced_scroll_id, reference_frame_id)); reference_frame_relative_offset = LayerVector2D::zero(); } - let sc_scroll_node_id = self.apply_scroll_frame_id_replacement(context_scroll_node_id); - + // We apply the replacements one more time in case we need to set it to a replacement + // that we just pushed above. + let new_scroll_node = self.apply_scroll_frame_id_replacement(unreplaced_scroll_id); + let stacking_context_clip_and_scroll = + self.id_to_index_mapper.simple_scroll_and_clip_chain(&new_scroll_node); self.builder.push_stacking_context( pipeline_id, composition_operations, stacking_context.transform_style, is_backface_visible, false, - ClipAndScrollInfo::simple(sc_scroll_node_id), + stacking_context_clip_and_scroll, self.output_pipelines, ); @@ -345,8 +403,7 @@ impl<'a> FlattenContext<'a> { &mut self, item: &DisplayItemRef, info: &IframeDisplayItem, - parent_pipeline_id: PipelineId, - clip_and_scroll: &ClipAndScrollInfo, + clip_and_scroll: &ScrollNodeAndClipChain, reference_frame_relative_offset: &LayerVector2D, ) { let iframe_pipeline_id = info.pipeline_id; @@ -358,12 +415,12 @@ impl<'a> FlattenContext<'a> { self.builder.add_clip_node( info.clip_id, clip_and_scroll.scroll_node_id, - parent_pipeline_id, ClipRegion::create_for_clip_node_with_local_clip( &item.local_clip(), &reference_frame_relative_offset ), self.clip_scroll_tree, + &mut self.id_to_index_mapper, ); self.pipeline_epochs.push((iframe_pipeline_id, pipeline.epoch)); @@ -380,6 +437,7 @@ impl<'a> FlattenContext<'a> { None, origin, self.clip_scroll_tree, + &mut self.id_to_index_mapper, ); self.builder.add_scroll_frame( @@ -391,6 +449,7 @@ impl<'a> FlattenContext<'a> { &pipeline.content_size, ScrollSensitivity::ScriptAndInputEvents, self.clip_scroll_tree, + &mut self.id_to_index_mapper, ); self.flatten_root(&mut pipeline.display_list.iter(), iframe_pipeline_id, &iframe_rect.size); @@ -404,7 +463,11 @@ impl<'a> FlattenContext<'a> { pipeline_id: PipelineId, reference_frame_relative_offset: LayerVector2D, ) -> Option> { - let mut clip_and_scroll = item.clip_and_scroll(); + let clip_and_scroll = item.clip_and_scroll(); + let mut clip_and_scroll = ScrollNodeAndClipChain::new( + clip_and_scroll.scroll_node_id, + self.id_to_index_mapper.map_clip_id_and_cache_result(&clip_and_scroll.clip_node_id()), + ); let unreplaced_scroll_id = clip_and_scroll.scroll_node_id; clip_and_scroll.scroll_node_id = @@ -557,6 +620,7 @@ impl<'a> FlattenContext<'a> { &mut subtraversal, pipeline_id, unreplaced_scroll_id, + clip_and_scroll, reference_frame_relative_offset, &item.rect(), &info.stacking_context, @@ -569,7 +633,6 @@ impl<'a> FlattenContext<'a> { self.flatten_iframe( &item, info, - pipeline_id, &clip_and_scroll, &reference_frame_relative_offset ); @@ -582,16 +645,16 @@ impl<'a> FlattenContext<'a> { info.image_mask, &reference_frame_relative_offset, ); - self.flatten_clip( - pipeline_id, - &clip_and_scroll.scroll_node_id, - &info.id, - clip_region, - ); + self.flatten_clip(&clip_and_scroll.scroll_node_id, &info.id, clip_region); } SpecificDisplayItem::ClipChain(ref info) => { let items = self.get_clip_chain_items(pipeline_id, item.clip_chain_items()); - self.clip_scroll_tree.add_clip_chain_descriptor(info.id, info.parent, items); + let parent = info.parent.map(|id| + self.id_to_index_mapper.map_clip_id(&ClipId::ClipChain(id)) + ); + let clip_chain_index = + self.clip_scroll_tree.add_clip_chain_descriptor(parent, items); + self.id_to_index_mapper.add(ClipId::ClipChain(info.id), clip_chain_index); }, SpecificDisplayItem::ScrollFrame(ref info) => { self.flatten_scroll_frame( @@ -610,12 +673,14 @@ impl<'a> FlattenContext<'a> { info.horizontal_offset_bounds, info.previously_applied_offset, ); + let parent_id = clip_and_scroll.scroll_node_id; self.clip_scroll_tree.add_sticky_frame( info.id, - clip_and_scroll.scroll_node_id, /* parent id */ + parent_id, frame_rect, sticky_frame_info ); + self.id_to_index_mapper.map_to_parent_clip_chain(info.id, &parent_id); } // Do nothing; these are dummy items for the display list parser @@ -650,7 +715,7 @@ impl<'a> FlattenContext<'a> { /// takes care of the decomposition required by the internal tiling of the image. fn decompose_image( &mut self, - clip_and_scroll: ClipAndScrollInfo, + clip_and_scroll: ScrollNodeAndClipChain, prim_info: &LayerPrimitiveInfo, info: &ImageDisplayItem, image_size: DeviceUintSize, @@ -696,7 +761,7 @@ impl<'a> FlattenContext<'a> { fn decompose_image_row( &mut self, - clip_and_scroll: ClipAndScrollInfo, + clip_and_scroll: ScrollNodeAndClipChain, prim_info: &LayerPrimitiveInfo, info: &ImageDisplayItem, image_size: DeviceUintSize, @@ -742,7 +807,7 @@ impl<'a> FlattenContext<'a> { fn decompose_tiled_image( &mut self, - clip_and_scroll: ClipAndScrollInfo, + clip_and_scroll: ScrollNodeAndClipChain, prim_info: &LayerPrimitiveInfo, info: &ImageDisplayItem, image_size: DeviceUintSize, @@ -878,7 +943,7 @@ impl<'a> FlattenContext<'a> { fn add_tile_primitive( &mut self, - clip_and_scroll: ClipAndScrollInfo, + clip_and_scroll: ScrollNodeAndClipChain, prim_info: &LayerPrimitiveInfo, info: &ImageDisplayItem, tile_offset: TileOffset, @@ -983,7 +1048,7 @@ impl FrameContext { pub fn scroll_node( &mut self, origin: LayerPoint, - id: ScrollNodeIdType, + id: ExternalScrollId, clamp: ScrollClamping ) -> bool { self.clip_scroll_tree.scroll_node(origin, id, clamp) @@ -1056,6 +1121,7 @@ impl FrameContext { pipeline_epochs: Vec::new(), replacements: Vec::new(), output_pipelines, + id_to_index_mapper: ClipIdToIndexMapper::new(), }; roller.builder.push_root( @@ -1063,6 +1129,7 @@ impl FrameContext { &root_pipeline.viewport_size, &root_pipeline.content_size, roller.clip_scroll_tree, + &mut roller.id_to_index_mapper, ); roller.builder.setup_viewport_offset( diff --git a/gfx/webrender/src/frame_builder.rs b/gfx/webrender/src/frame_builder.rs index 9a7f45f01797..b856b7410092 100644 --- a/gfx/webrender/src/frame_builder.rs +++ b/gfx/webrender/src/frame_builder.rs @@ -2,35 +2,34 @@ * 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::{AlphaType, BorderDetails, BorderDisplayItem, BuiltDisplayList, ClipAndScrollInfo}; -use api::{ClipId, ColorF, DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePixelScale}; -use api::{DeviceUintPoint, DeviceUintRect, DeviceUintSize, DocumentLayer, Epoch, ExtendMode}; -use api::{ExternalScrollId, FontRenderMode, GlyphInstance, GlyphOptions, GradientStop, ImageKey}; -use api::{ImageRendering, ItemRange, LayerPoint, LayerPrimitiveInfo, LayerRect, LayerSize}; -use api::{LayerTransform, LayerVector2D, LayoutTransform, LayoutVector2D, LineOrientation}; -use api::{LineStyle, LocalClip, PipelineId, PremultipliedColorF, PropertyBinding, RepeatMode}; -use api::{ScrollSensitivity, Shadow, TexelRect, TileOffset, TransformStyle, WorldPoint}; -use api::{WorldToLayerTransform, YuvColorSpace, YuvData}; +use api::{AlphaType, BorderDetails, BorderDisplayItem, BuiltDisplayList, ClipId, ColorF}; +use api::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePixelScale, DeviceUintPoint}; +use api::{DeviceUintRect, DeviceUintSize, DocumentLayer, Epoch, ExtendMode, ExternalScrollId}; +use api::{FontRenderMode, GlyphInstance, GlyphOptions, GradientStop, ImageKey, ImageRendering}; +use api::{ItemRange, LayerPoint, LayerPrimitiveInfo, LayerRect, LayerSize, LayerTransform}; +use api::{LayerVector2D, LayoutTransform, LayoutVector2D, LineOrientation, LineStyle, LocalClip}; +use api::{PipelineId, PremultipliedColorF, PropertyBinding, RepeatMode, ScrollSensitivity, Shadow}; +use api::{TexelRect, TileOffset, TransformStyle, WorldPoint, WorldToLayerTransform, YuvColorSpace}; +use api::YuvData; use app_units::Au; use border::ImageBorderSegment; -use clip::{ClipRegion, ClipSource, ClipSources, ClipStore}; +use clip::{ClipChain, ClipRegion, ClipSource, ClipSources, ClipStore}; use clip_scroll_node::{ClipScrollNode, NodeType}; -use clip_scroll_tree::ClipScrollTree; +use clip_scroll_tree::{ClipScrollTree, ClipChainIndex}; use euclid::{SideOffsets2D, vec2}; -use frame::FrameId; +use frame::{FrameId, ClipIdToIndexMapper}; use glyph_rasterizer::FontInstance; -use gpu_cache::GpuCache; +use gpu_cache::{GpuCache, GpuCacheHandle}; use gpu_types::{ClipChainRectIndex, ClipScrollNodeData, PictureType}; use hit_test::{HitTester, HitTestingItem, HitTestingRun}; -use internal_types::{FastHashMap, FastHashSet, RenderPassIndex}; +use internal_types::{FastHashMap, FastHashSet}; use picture::{ContentOrigin, PictureCompositeMode, PictureKind, PicturePrimitive, PictureSurface}; -use prim_store::{BrushKind, BrushPrimitive, ImageCacheKey, YuvImagePrimitiveCpu}; -use prim_store::{GradientPrimitiveCpu, ImagePrimitiveCpu, ImageSource, PrimitiveKind}; -use prim_store::{PrimitiveContainer, PrimitiveIndex}; -use prim_store::{PrimitiveStore, RadialGradientPrimitiveCpu}; -use prim_store::{BrushSegmentDescriptor, PrimitiveRun, TextRunPrimitiveCpu}; +use prim_store::{BrushKind, BrushPrimitive, BrushSegmentDescriptor, GradientPrimitiveCpu}; +use prim_store::{ImageCacheKey, ImagePrimitiveCpu, ImageSource, PrimitiveContainer}; +use prim_store::{PrimitiveIndex, PrimitiveKind, PrimitiveRun, PrimitiveStore}; +use prim_store::{ScrollNodeAndClipChain, TextRunPrimitiveCpu}; use profiler::{FrameProfileCounters, GpuCacheProfileCounters, TextureCacheProfileCounters}; -use render_task::{ClearMode, ClipChain, RenderTask, RenderTaskId, RenderTaskLocation, RenderTaskTree}; +use render_task::{ClearMode, RenderTask, RenderTaskId, RenderTaskLocation, RenderTaskTree}; use resource_cache::{ImageRequest, ResourceCache}; use scene::{ScenePipeline, SceneProperties}; use std::{mem, usize, f32}; @@ -90,10 +89,10 @@ pub struct FrameBuilder { // A stack of the current shadow primitives. // The sub-Vec stores a buffer of fast-path primitives to be appended on pop. - shadow_prim_stack: Vec<(PrimitiveIndex, Vec<(PrimitiveIndex, ClipAndScrollInfo)>)>, + shadow_prim_stack: Vec<(PrimitiveIndex, Vec<(PrimitiveIndex, ScrollNodeAndClipChain)>)>, // If we're doing any fast-path shadows, we buffer the "real" // content here, to be appended when the shadow stack is empty. - pending_shadow_contents: Vec<(PrimitiveIndex, ClipAndScrollInfo, LayerPrimitiveInfo)>, + pending_shadow_contents: Vec<(PrimitiveIndex, ScrollNodeAndClipChain, LayerPrimitiveInfo)>, scrollbar_prims: Vec, @@ -150,14 +149,14 @@ impl PictureState { } pub struct PrimitiveRunContext<'a> { - pub clip_chain: Option<&'a ClipChain>, + pub clip_chain: &'a ClipChain, pub scroll_node: &'a ClipScrollNode, pub clip_chain_rect_index: ClipChainRectIndex, } impl<'a> PrimitiveRunContext<'a> { pub fn new( - clip_chain: Option<&'a ClipChain>, + clip_chain: &'a ClipChain, scroll_node: &'a ClipScrollNode, clip_chain_rect_index: ClipChainRectIndex, ) -> Self { @@ -252,7 +251,7 @@ impl FrameBuilder { pub fn add_primitive_to_hit_testing_list( &mut self, info: &LayerPrimitiveInfo, - clip_and_scroll: ClipAndScrollInfo + clip_and_scroll: ScrollNodeAndClipChain ) { let tag = match info.tag { Some(tag) => tag, @@ -276,7 +275,7 @@ impl FrameBuilder { pub fn add_primitive_to_draw_list( &mut self, prim_index: PrimitiveIndex, - clip_and_scroll: ClipAndScrollInfo, + clip_and_scroll: ScrollNodeAndClipChain, ) { // Add primitive to the top-most Picture on the stack. // TODO(gw): Let's consider removing the extra indirection @@ -294,7 +293,7 @@ impl FrameBuilder { /// to the draw list. pub fn add_primitive( &mut self, - clip_and_scroll: ClipAndScrollInfo, + clip_and_scroll: ScrollNodeAndClipChain, info: &LayerPrimitiveInfo, clip_sources: Vec, container: PrimitiveContainer, @@ -313,7 +312,7 @@ impl FrameBuilder { transform_style: TransformStyle, is_backface_visible: bool, is_pipeline_root: bool, - clip_and_scroll: ClipAndScrollInfo, + clip_and_scroll: ScrollNodeAndClipChain, output_pipelines: &FastHashSet, ) { // Construct the necessary set of Picture primitives @@ -640,6 +639,7 @@ impl FrameBuilder { source_perspective: Option, origin_in_parent_reference_frame: LayerVector2D, clip_scroll_tree: &mut ClipScrollTree, + id_to_index_mapper: &mut ClipIdToIndexMapper, ) { let node = ClipScrollNode::new_reference_frame( parent_id, @@ -651,6 +651,12 @@ impl FrameBuilder { ); clip_scroll_tree.add_node(node, reference_frame_id); self.reference_frame_stack.push(reference_frame_id); + + match parent_id { + Some(ref parent_id) => + id_to_index_mapper.map_to_parent_clip_chain(reference_frame_id, parent_id), + _ => id_to_index_mapper.add(reference_frame_id, ClipChainIndex(0)), + } } pub fn current_reference_frame_id(&self) -> ClipId { @@ -682,6 +688,7 @@ impl FrameBuilder { viewport_size: &LayerSize, content_size: &LayerSize, clip_scroll_tree: &mut ClipScrollTree, + id_to_index_mapper: &mut ClipIdToIndexMapper, ) -> ClipId { let viewport_rect = LayerRect::new(LayerPoint::zero(), *viewport_size); self.push_reference_frame( @@ -693,6 +700,7 @@ impl FrameBuilder { None, LayerVector2D::zero(), clip_scroll_tree, + id_to_index_mapper, ); let topmost_scrolling_node_id = ClipId::root_scroll_node(pipeline_id); @@ -707,6 +715,7 @@ impl FrameBuilder { content_size, ScrollSensitivity::ScriptAndInputEvents, clip_scroll_tree, + id_to_index_mapper, ); topmost_scrolling_node_id @@ -716,18 +725,23 @@ impl FrameBuilder { &mut self, new_node_id: ClipId, parent_id: ClipId, - pipeline_id: PipelineId, clip_region: ClipRegion, clip_scroll_tree: &mut ClipScrollTree, + id_to_index_mapper: &mut ClipIdToIndexMapper, ) { let clip_rect = clip_region.main; let clip_sources = ClipSources::from(clip_region); - debug_assert!(clip_sources.has_clips()); + debug_assert!(clip_sources.has_clips()); let handle = self.clip_store.insert(clip_sources); - let node = ClipScrollNode::new_clip_node(pipeline_id, parent_id, handle, clip_rect); - clip_scroll_tree.add_node(node, new_node_id); + let clip_chain_index = clip_scroll_tree.add_clip_node( + new_node_id, + parent_id, + handle, + clip_rect + ); + id_to_index_mapper.add(new_node_id, clip_chain_index); } pub fn add_scroll_frame( @@ -740,6 +754,7 @@ impl FrameBuilder { content_size: &LayerSize, scroll_sensitivity: ScrollSensitivity, clip_scroll_tree: &mut ClipScrollTree, + id_to_index_mapper: &mut ClipIdToIndexMapper, ) { let node = ClipScrollNode::new_scroll_frame( pipeline_id, @@ -751,6 +766,7 @@ impl FrameBuilder { ); clip_scroll_tree.add_node(node, new_node_id); + id_to_index_mapper.map_to_parent_clip_chain(new_node_id, &parent_id); } pub fn pop_reference_frame(&mut self) { @@ -760,7 +776,7 @@ impl FrameBuilder { pub fn push_shadow( &mut self, shadow: Shadow, - clip_and_scroll: ClipAndScrollInfo, + clip_and_scroll: ScrollNodeAndClipChain, info: &LayerPrimitiveInfo, ) { let pipeline_id = self.sc_stack.last().unwrap().pipeline_id; @@ -804,7 +820,7 @@ impl FrameBuilder { pub fn add_solid_rectangle( &mut self, - clip_and_scroll: ClipAndScrollInfo, + clip_and_scroll: ScrollNodeAndClipChain, info: &LayerPrimitiveInfo, color: ColorF, segments: Option, @@ -833,7 +849,7 @@ impl FrameBuilder { pub fn add_clear_rectangle( &mut self, - clip_and_scroll: ClipAndScrollInfo, + clip_and_scroll: ScrollNodeAndClipChain, info: &LayerPrimitiveInfo, ) { let prim = BrushPrimitive::new( @@ -851,7 +867,7 @@ impl FrameBuilder { pub fn add_scroll_bar( &mut self, - clip_and_scroll: ClipAndScrollInfo, + clip_and_scroll: ScrollNodeAndClipChain, info: &LayerPrimitiveInfo, color: ColorF, scrollbar_info: ScrollbarInfo, @@ -883,7 +899,7 @@ impl FrameBuilder { pub fn add_line( &mut self, - clip_and_scroll: ClipAndScrollInfo, + clip_and_scroll: ScrollNodeAndClipChain, info: &LayerPrimitiveInfo, wavy_line_thickness: f32, orientation: LineOrientation, @@ -970,7 +986,7 @@ impl FrameBuilder { pub fn add_border( &mut self, - clip_and_scroll: ClipAndScrollInfo, + clip_and_scroll: ScrollNodeAndClipChain, info: &LayerPrimitiveInfo, border_item: &BorderDisplayItem, gradient_stops: ItemRange, @@ -1222,7 +1238,7 @@ impl FrameBuilder { pub fn add_gradient( &mut self, - clip_and_scroll: ClipAndScrollInfo, + clip_and_scroll: ScrollNodeAndClipChain, info: &LayerPrimitiveInfo, start_point: LayerPoint, end_point: LayerPoint, @@ -1290,9 +1306,43 @@ impl FrameBuilder { self.add_primitive(clip_and_scroll, info, Vec::new(), prim); } + fn add_radial_gradient_impl( + &mut self, + clip_and_scroll: ScrollNodeAndClipChain, + info: &LayerPrimitiveInfo, + start_center: LayerPoint, + start_radius: f32, + end_center: LayerPoint, + end_radius: f32, + ratio_xy: f32, + stops: ItemRange, + extend_mode: ExtendMode, + ) { + let prim = BrushPrimitive::new( + BrushKind::RadialGradient { + stops_range: stops, + extend_mode, + stops_handle: GpuCacheHandle::new(), + start_center, + end_center, + start_radius, + end_radius, + ratio_xy, + }, + None, + ); + + self.add_primitive( + clip_and_scroll, + info, + Vec::new(), + PrimitiveContainer::Brush(prim), + ); + } + pub fn add_radial_gradient( &mut self, - clip_and_scroll: ClipAndScrollInfo, + clip_and_scroll: ScrollNodeAndClipChain, info: &LayerPrimitiveInfo, start_center: LayerPoint, start_radius: f32, @@ -1304,40 +1354,44 @@ impl FrameBuilder { tile_size: LayerSize, tile_spacing: LayerSize, ) { - let tile_repeat = tile_size + tile_spacing; + let prim_infos = info.decompose( + tile_size, + tile_spacing, + 64 * 64, + ); - let radial_gradient_cpu = RadialGradientPrimitiveCpu { - stops_range: stops, - extend_mode, - gpu_data_count: 0, - gpu_blocks: [ - [start_center.x, start_center.y, end_center.x, end_center.y].into(), - [ + if prim_infos.is_empty() { + self.add_radial_gradient_impl( + clip_and_scroll, + info, + start_center, + start_radius, + end_center, + end_radius, + ratio_xy, + stops, + extend_mode, + ); + } else { + for prim_info in prim_infos { + self.add_radial_gradient_impl( + clip_and_scroll, + &prim_info, + start_center, start_radius, + end_center, end_radius, ratio_xy, - pack_as_float(extend_mode as u32), - ].into(), - [ - tile_size.width, - tile_size.height, - tile_repeat.width, - tile_repeat.height, - ].into(), - ], - }; - - self.add_primitive( - clip_and_scroll, - info, - Vec::new(), - PrimitiveContainer::RadialGradient(radial_gradient_cpu), - ); + stops, + extend_mode, + ); + } + } } pub fn add_text( &mut self, - clip_and_scroll: ClipAndScrollInfo, + clip_and_scroll: ScrollNodeAndClipChain, run_offset: LayoutVector2D, info: &LayerPrimitiveInfo, font: &FontInstance, @@ -1493,7 +1547,7 @@ impl FrameBuilder { pub fn add_image( &mut self, - clip_and_scroll: ClipAndScrollInfo, + clip_and_scroll: ScrollNodeAndClipChain, info: &LayerPrimitiveInfo, stretch_size: LayerSize, mut tile_spacing: LayerSize, @@ -1573,7 +1627,7 @@ impl FrameBuilder { pub fn add_yuv_image( &mut self, - clip_and_scroll: ClipAndScrollInfo, + clip_and_scroll: ScrollNodeAndClipChain, info: &LayerPrimitiveInfo, yuv_data: YuvData, color_space: YuvColorSpace, @@ -1586,19 +1640,21 @@ impl FrameBuilder { YuvData::InterleavedYCbCr(plane_0) => [plane_0, ImageKey::DUMMY, ImageKey::DUMMY], }; - let prim_cpu = YuvImagePrimitiveCpu { - yuv_key, - format, - color_space, - image_rendering, - gpu_block: [info.rect.size.width, info.rect.size.height, 0.0, 0.0].into(), - }; + let prim = BrushPrimitive::new( + BrushKind::YuvImage { + yuv_key, + format, + color_space, + image_rendering, + }, + None, + ); self.add_primitive( clip_and_scroll, info, Vec::new(), - PrimitiveContainer::YuvImage(prim_cpu), + PrimitiveContainer::Brush(prim), ); } @@ -1807,7 +1863,7 @@ impl FrameBuilder { let use_dual_source_blending = self.config.dual_source_blending_is_enabled && self.config.dual_source_blending_is_supported; - for (pass_index, pass) in passes.iter_mut().enumerate() { + for pass in &mut passes { let ctx = RenderTargetContext { device_pixel_scale, prim_store: &self.prim_store, @@ -1823,7 +1879,6 @@ impl FrameBuilder { &mut render_tasks, &mut deferred_resolves, &self.clip_store, - RenderPassIndex(pass_index), ); if let RenderPassKind::OffScreen { ref texture_cache, .. } = pass.kind { @@ -1863,3 +1918,67 @@ impl FrameBuilder { ) } } + +trait PrimitiveInfoTiler { + fn decompose( + &self, + tile_size: LayerSize, + tile_spacing: LayerSize, + max_prims: usize, + ) -> Vec; +} + +impl PrimitiveInfoTiler for LayerPrimitiveInfo { + fn decompose( + &self, + tile_size: LayerSize, + tile_spacing: LayerSize, + max_prims: usize, + ) -> Vec { + let mut prims = Vec::new(); + let tile_repeat = tile_size + tile_spacing; + + if tile_repeat.width <= 0.0 || + tile_repeat.height <= 0.0 { + return prims; + } + + if tile_repeat.width < self.rect.size.width || + tile_repeat.height < self.rect.size.height { + let local_clip = self.local_clip.clip_by(&self.rect); + let rect_p0 = self.rect.origin; + let rect_p1 = self.rect.bottom_right(); + + let mut y0 = rect_p0.y; + while y0 < rect_p1.y { + let mut x0 = rect_p0.x; + + while x0 < rect_p1.x { + prims.push(LayerPrimitiveInfo { + rect: LayerRect::new( + LayerPoint::new(x0, y0), + tile_size, + ), + local_clip, + is_backface_visible: self.is_backface_visible, + tag: self.tag, + }); + + // Mostly a safety against a crazy number of primitives + // being generated. If we exceed that amount, just bail + // out and only draw the maximum amount. + if prims.len() > max_prims { + warn!("too many prims found due to repeat/tile. dropping extra prims!"); + return prims; + } + + x0 += tile_repeat.width; + } + + y0 += tile_repeat.height; + } + } + + prims + } +} diff --git a/gfx/webrender/src/glyph_rasterizer.rs b/gfx/webrender/src/glyph_rasterizer.rs index 32688b48633d..65a05063325d 100644 --- a/gfx/webrender/src/glyph_rasterizer.rs +++ b/gfx/webrender/src/glyph_rasterizer.rs @@ -628,16 +628,17 @@ fn rasterize_200_glyphs() { // This test loads a font from disc, the renders 4 requests containing // 50 glyphs each, deletes the font and waits for the result. - use rayon::Configuration; + use rayon::ThreadPoolBuilder; use std::fs::File; use std::io::Read; - let worker_config = Configuration::new() + let worker = ThreadPoolBuilder::new() .thread_name(|idx|{ format!("WRWorker#{}", idx) }) .start_handler(move |idx| { register_thread_with_profiler(format!("WRWorker#{}", idx)); - }); - let workers = Arc::new(ThreadPool::new(worker_config).unwrap()); + }) + .build(); + let workers = Arc::new(worker.unwrap()); let mut glyph_rasterizer = GlyphRasterizer::new(workers).unwrap(); let mut glyph_cache = GlyphCache::new(); let mut gpu_cache = GpuCache::new(); diff --git a/gfx/webrender/src/gpu_types.rs b/gfx/webrender/src/gpu_types.rs index 18435ebbadd6..97d7d658a36b 100644 --- a/gfx/webrender/src/gpu_types.rs +++ b/gfx/webrender/src/gpu_types.rs @@ -147,6 +147,14 @@ impl From for PrimitiveInstance { } } +bitflags! { + /// Flags that define how the common brush shader + /// code should process this instance. + pub struct BrushFlags: u8 { + const PERSPECTIVE_INTERPOLATION = 0x1; + } +} + // TODO(gw): While we are comverting things over, we // need to have the instance be the same // size as an old PrimitiveInstance. In the @@ -164,6 +172,7 @@ pub struct BrushInstance { pub z: i32, pub segment_index: i32, pub edge_flags: EdgeAaSegmentMask, + pub brush_flags: BrushFlags, pub user_data: [i32; 3], } @@ -175,7 +184,9 @@ impl From for PrimitiveInstance { instance.prim_address.as_int(), ((instance.clip_chain_rect_index.0 as i32) << 16) | instance.scroll_id.0 as i32, instance.z, - instance.segment_index | ((instance.edge_flags.bits() as i32) << 16), + instance.segment_index | + ((instance.edge_flags.bits() as i32) << 16) | + ((instance.brush_flags.bits() as i32) << 24), instance.user_data[0], instance.user_data[1], instance.user_data[2], diff --git a/gfx/webrender/src/hit_test.rs b/gfx/webrender/src/hit_test.rs index 55b9fa90b8e1..d4b7b2b689b3 100644 --- a/gfx/webrender/src/hit_test.rs +++ b/gfx/webrender/src/hit_test.rs @@ -2,13 +2,14 @@ * 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, ClipAndScrollInfo, ClipId, ClipMode, HitTestFlags, HitTestItem}; -use api::{HitTestResult, ItemTag, LayerPoint, LayerPrimitiveInfo, LayerRect}; -use api::{LayerToWorldTransform, LocalClip, PipelineId, WorldPoint}; +use api::{BorderRadius, ClipId, ClipMode, HitTestFlags, HitTestItem, HitTestResult, ItemTag}; +use api::{LayerPoint, LayerPrimitiveInfo, LayerRect, LayerToWorldTransform, LocalClip, PipelineId}; +use api::WorldPoint; use clip::{ClipSource, ClipStore, Contains, rounded_rectangle_contains_point}; use clip_scroll_node::{ClipScrollNode, NodeType}; -use clip_scroll_tree::ClipScrollTree; +use clip_scroll_tree::{ClipChainIndex, ClipScrollTree}; use internal_types::FastHashMap; +use prim_store::ScrollNodeAndClipChain; /// A copy of important clip scroll node data to use during hit testing. This a copy of /// data from the ClipScrollTree that will persist as a new frame is under construction, @@ -33,11 +34,21 @@ pub struct HitTestClipScrollNode { /// handled the same way during hit testing. Once we represent all ClipChains /// using ClipChainDescriptors, we can get rid of this and just use the /// ClipChainDescriptor here. +#[derive(Clone)] struct HitTestClipChainDescriptor { - parent: Option, + parent: Option, clips: Vec, } +impl HitTestClipChainDescriptor { + fn empty() -> HitTestClipChainDescriptor { + HitTestClipChainDescriptor { + parent: None, + clips: Vec::new(), + } + } +} + #[derive(Clone)] pub struct HitTestingItem { rect: LayerRect, @@ -56,7 +67,7 @@ impl HitTestingItem { } #[derive(Clone)] -pub struct HitTestingRun(pub Vec, pub ClipAndScrollInfo); +pub struct HitTestingRun(pub Vec, pub ScrollNodeAndClipChain); enum HitTestRegion { Rectangle(LayerRect), @@ -78,7 +89,7 @@ impl HitTestRegion { pub struct HitTester { runs: Vec, nodes: FastHashMap, - clip_chains: FastHashMap, + clip_chains: Vec, } impl HitTester { @@ -90,7 +101,7 @@ impl HitTester { let mut hit_tester = HitTester { runs: runs.clone(), nodes: FastHashMap::default(), - clip_chains: FastHashMap::default(), + clip_chains: Vec::new(), }; hit_tester.read_clip_scroll_tree(clip_scroll_tree, clip_store); hit_tester @@ -102,6 +113,11 @@ impl HitTester { clip_store: &ClipStore ) { self.nodes.clear(); + self.clip_chains.clear(); + self.clip_chains.resize( + clip_scroll_tree.clip_chains.len(), + HitTestClipChainDescriptor::empty() + ); for (id, node) in &clip_scroll_tree.nodes { self.nodes.insert(*id, HitTestClipScrollNode { @@ -111,52 +127,50 @@ impl HitTester { node_origin: node.local_viewport_rect.origin, }); - self.clip_chains.insert(*id, HitTestClipChainDescriptor { - parent: node.parent, - clips: vec![*id], - }); + if let NodeType::Clip { clip_chain_index, .. } = node.node_type { + let clip_chain = self.clip_chains.get_mut(clip_chain_index.0).unwrap(); + clip_chain.parent = + clip_scroll_tree.get_clip_chain(clip_chain_index).parent_index; + clip_chain.clips = vec![*id]; + } } for descriptor in &clip_scroll_tree.clip_chains_descriptors { - self.clip_chains.insert( - ClipId::ClipChain(descriptor.id), - HitTestClipChainDescriptor { - parent: descriptor.parent.map(|id| ClipId::ClipChain(id)), - clips: descriptor.clips.clone(), - } - ); + let clip_chain = self.clip_chains.get_mut(descriptor.index.0).unwrap(); + clip_chain.parent = clip_scroll_tree.get_clip_chain(descriptor.index).parent_index; + clip_chain.clips = descriptor.clips.clone(); } } fn is_point_clipped_in_for_clip_chain( &self, point: WorldPoint, - chain_id: &ClipId, + clip_chain_index: ClipChainIndex, test: &mut HitTest ) -> bool { - if let Some(result) = test.clip_chain_cache.get(&chain_id) { - return *result; + if let Some(result) = test.get_from_clip_chain_cache(clip_chain_index) { + return result; } - let descriptor = &self.clip_chains[&chain_id]; + let descriptor = &self.clip_chains[clip_chain_index.0]; let parent_clipped_in = match descriptor.parent { None => true, - Some(ref parent) => self.is_point_clipped_in_for_clip_chain(point, parent, test), + Some(parent) => self.is_point_clipped_in_for_clip_chain(point, parent, test), }; if !parent_clipped_in { - test.clip_chain_cache.insert(*chain_id, false); + test.set_in_clip_chain_cache(clip_chain_index, false); return false; } for clip_node in &descriptor.clips { if !self.is_point_clipped_in_for_node(point, clip_node, test) { - test.clip_chain_cache.insert(*chain_id, false); + test.set_in_clip_chain_cache(clip_chain_index, false); return false; } } - test.clip_chain_cache.insert(*chain_id, true); + test.set_in_clip_chain_cache(clip_chain_index, true); true } @@ -197,7 +211,9 @@ impl HitTester { let mut result = HitTestResult::default(); for &HitTestingRun(ref items, ref clip_and_scroll) in self.runs.iter().rev() { - let scroll_node = &self.nodes[&clip_and_scroll.scroll_node_id]; + let scroll_node_id = clip_and_scroll.scroll_node_id; + let scroll_node = &self.nodes[&scroll_node_id]; + let pipeline_id = scroll_node_id.pipeline_id(); match (test.pipeline_id, clip_and_scroll.scroll_node_id.pipeline_id()) { (Some(id), node_id) if node_id != id => continue, _ => {}, @@ -215,12 +231,11 @@ impl HitTester { continue; } - let clip_id = &clip_and_scroll.clip_node_id(); + let clip_chain_index = clip_and_scroll.clip_chain_index; + clipped_in |= + self.is_point_clipped_in_for_clip_chain(point, clip_chain_index, &mut test); if !clipped_in { - clipped_in = self.is_point_clipped_in_for_clip_chain(point, clip_id, &mut test); - if !clipped_in { - break; - } + break; } // We need to trigger a lookup against the root reference frame here, because @@ -228,7 +243,7 @@ impl HitTester { // hierarchy. If we don't have a valid point for this test, we are likely // in a situation where the reference frame has an univertible transform, but the // item's clip does not. - let root_reference_frame = ClipId::root_reference_frame(clip_id.pipeline_id()); + let root_reference_frame = ClipId::root_reference_frame(pipeline_id); if !self.is_point_clipped_in_for_node(point, &root_reference_frame, &mut test) { continue; } @@ -238,7 +253,7 @@ impl HitTester { }; result.items.push(HitTestItem { - pipeline: clip_and_scroll.clip_node_id().pipeline_id(), + pipeline: pipeline_id, tag: item.tag, point_in_viewport, point_relative_to_item: point_in_layer - item.rect.origin.to_vector(), @@ -259,7 +274,7 @@ fn get_regions_for_clip_scroll_node( clip_store: &ClipStore ) -> Vec { let clips = match node.node_type { - NodeType::Clip(ref handle) => clip_store.get(handle).clips(), + NodeType::Clip{ ref handle, .. } => clip_store.get(handle).clips(), _ => return Vec::new(), }; @@ -280,7 +295,7 @@ pub struct HitTest { point: WorldPoint, flags: HitTestFlags, node_cache: FastHashMap>, - clip_chain_cache: FastHashMap, + clip_chain_cache: Vec>, } impl HitTest { @@ -294,10 +309,25 @@ impl HitTest { point, flags, node_cache: FastHashMap::default(), - clip_chain_cache: FastHashMap::default(), + clip_chain_cache: Vec::new(), } } + pub fn get_from_clip_chain_cache(&mut self, index: ClipChainIndex) -> Option { + if index.0 >= self.clip_chain_cache.len() { + None + } else { + self.clip_chain_cache[index.0] + } + } + + pub fn set_in_clip_chain_cache(&mut self, index: ClipChainIndex, value: bool) { + if index.0 >= self.clip_chain_cache.len() { + self.clip_chain_cache.resize(index.0 + 1, None); + } + self.clip_chain_cache[index.0] = Some(value); + } + pub fn get_absolute_point(&self, hit_tester: &HitTester) -> WorldPoint { if !self.flags.contains(HitTestFlags::POINT_RELATIVE_TO_PIPELINE_VIEWPORT) { return self.point; diff --git a/gfx/webrender/src/internal_types.rs b/gfx/webrender/src/internal_types.rs index c7a495f26007..6034f332c9ee 100644 --- a/gfx/webrender/src/internal_types.rs +++ b/gfx/webrender/src/internal_types.rs @@ -44,7 +44,11 @@ pub struct CacheTextureId(pub usize); #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -pub struct RenderPassIndex(pub usize); +pub struct SavedTargetIndex(pub usize); + +impl SavedTargetIndex { + pub const PENDING: Self = SavedTargetIndex(!0); +} // Represents the source for a texture. // These are passed from throughout the @@ -61,10 +65,7 @@ pub enum SourceTexture { External(ExternalImageData), CacheA8, CacheRGBA8, - // XXX Remove this once RenderTaskCacheA8 is used. - #[allow(dead_code)] - RenderTaskCacheA8(RenderPassIndex), - RenderTaskCacheRGBA8(RenderPassIndex), + RenderTaskCache(SavedTargetIndex), } pub const ORTHO_NEAR_PLANE: f32 = -1000000.0; diff --git a/gfx/webrender/src/picture.rs b/gfx/webrender/src/picture.rs index c86666991fcc..8abf253d8276 100644 --- a/gfx/webrender/src/picture.rs +++ b/gfx/webrender/src/picture.rs @@ -2,15 +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::{ColorF, ClipAndScrollInfo, FilterOp, MixBlendMode}; -use api::{DeviceIntPoint, DeviceIntRect, LayerToWorldScale, PipelineId}; -use api::{BoxShadowClipMode, LayerPoint, LayerRect, LayerVector2D, Shadow}; -use api::{ClipId, PremultipliedColorF}; +use api::{BoxShadowClipMode, ClipId, ColorF, DeviceIntPoint, DeviceIntRect, FilterOp, LayerPoint}; +use api::{LayerRect, LayerToWorldScale, LayerVector2D, MixBlendMode, PipelineId}; +use api::{PremultipliedColorF, Shadow}; use box_shadow::{BLUR_SAMPLE_SCALE, BoxShadowCacheKey}; use frame_builder::{FrameContext, FrameState, PictureState}; use gpu_cache::GpuDataRequest; use gpu_types::{BrushImageKind, PictureType}; use prim_store::{BrushKind, BrushPrimitive, PrimitiveIndex, PrimitiveRun, PrimitiveRunLocalRect}; +use prim_store::ScrollNodeAndClipChain; use render_task::{ClearMode, RenderTask, RenderTaskCacheKey}; use render_task::{RenderTaskCacheKeyKind, RenderTaskId, RenderTaskLocation}; use resource_cache::CacheItem; @@ -230,7 +230,7 @@ impl PicturePrimitive { pub fn add_primitive( &mut self, prim_index: PrimitiveIndex, - clip_and_scroll: ClipAndScrollInfo + clip_and_scroll: ScrollNodeAndClipChain ) { if let Some(ref mut run) = self.runs.last_mut() { if run.clip_and_scroll == clip_and_scroll && @@ -368,7 +368,7 @@ impl PicturePrimitive { } Some(PictureCompositeMode::Filter(FilterOp::DropShadow(offset, blur_radius, color))) => { let rect = (prim_local_rect.translate(&-offset) * content_scale).round().to_i32(); - let picture_task = RenderTask::new_picture( + let mut picture_task = RenderTask::new_picture( RenderTaskLocation::Dynamic(None, rect.size), prim_index, RenderTargetKind::Color, @@ -378,6 +378,7 @@ impl PicturePrimitive { pic_state_for_children.tasks, PictureType::Image, ); + picture_task.mark_for_saving(); let blur_std_deviation = blur_radius * frame_context.device_pixel_scale.0; let picture_task_id = frame_state.render_tasks.add(picture_task); @@ -601,7 +602,7 @@ impl PicturePrimitive { match composite_mode { Some(PictureCompositeMode::Filter(FilterOp::ColorMatrix(m))) => { for i in 0..5 { - request.push([m[i], m[i+5], m[i+10], m[i+15]]); + request.push([m[i*4], m[i*4+1], m[i*4+2], m[i*4+3]]); } } Some(PictureCompositeMode::Filter(filter)) => { diff --git a/gfx/webrender/src/prim_store.rs b/gfx/webrender/src/prim_store.rs index 600a19706567..263b079d418a 100644 --- a/gfx/webrender/src/prim_store.rs +++ b/gfx/webrender/src/prim_store.rs @@ -2,25 +2,24 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use api::{AlphaType, BorderRadius, BuiltDisplayList, ClipAndScrollInfo, ClipMode}; -use api::{ColorF, DeviceIntRect, DeviceIntSize, DevicePixelScale, Epoch}; -use api::{ComplexClipRegion, ExtendMode, FontRenderMode}; +use api::{AlphaType, BorderRadius, BuiltDisplayList, ClipId, ClipMode, ColorF, ComplexClipRegion}; +use api::{DeviceIntRect, DeviceIntSize, DevicePixelScale, Epoch, ExtendMode, FontRenderMode}; use api::{GlyphInstance, GlyphKey, GradientStop, ImageKey, ImageRendering, ItemRange, ItemTag}; use api::{LayerPoint, LayerRect, LayerSize, LayerToWorldTransform, LayerVector2D, LineOrientation}; -use api::{LineStyle, PremultipliedColorF}; -use api::{WorldToLayerTransform, YuvColorSpace, YuvFormat}; +use api::{LineStyle, PremultipliedColorF, WorldToLayerTransform, YuvColorSpace, YuvFormat}; use border::{BorderCornerInstance, BorderEdgeKind}; -use clip_scroll_tree::{CoordinateSystemId}; +use clip_scroll_tree::{ClipChainIndex, CoordinateSystemId}; use clip_scroll_node::ClipScrollNode; -use clip::{ClipSource, ClipSourcesHandle}; +use clip::{ClipChain, ClipChainNode, ClipChainNodeIter, ClipChainNodeRef, ClipSource}; +use clip::{ClipSourcesHandle, ClipWorkItem}; use frame_builder::{FrameContext, FrameState, PictureContext, PictureState, PrimitiveRunContext}; use glyph_rasterizer::{FontInstance, FontTransform}; use gpu_cache::{GpuBlockData, GpuCache, GpuCacheAddress, GpuCacheHandle, GpuDataRequest, ToGpuBlocks}; use gpu_types::{ClipChainRectIndex}; use picture::{PictureKind, PicturePrimitive}; -use render_task::{BlitSource, ClipChain, ClipChainNode, ClipChainNodeIter, ClipChainNodeRef, ClipWorkItem}; -use render_task::{RenderTask, RenderTaskCacheKey, RenderTaskCacheKeyKind, RenderTaskId}; +use render_task::{BlitSource, RenderTask, RenderTaskCacheKey, RenderTaskCacheKeyKind}; +use render_task::RenderTaskId; use renderer::{MAX_VERTEX_TEXTURE_WIDTH}; use resource_cache::{CacheItem, ImageProperties, ImageRequest, ResourceCache}; use segment::SegmentBuilder; @@ -32,11 +31,23 @@ use util::recycle_vec; const MIN_BRUSH_SPLIT_AREA: f32 = 128.0 * 128.0; +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct ScrollNodeAndClipChain { + pub scroll_node_id: ClipId, + pub clip_chain_index: ClipChainIndex, +} + +impl ScrollNodeAndClipChain { + pub fn new(scroll_node_id: ClipId, clip_chain_index: ClipChainIndex) -> ScrollNodeAndClipChain { + ScrollNodeAndClipChain { scroll_node_id, clip_chain_index } + } +} + #[derive(Debug)] pub struct PrimitiveRun { pub base_prim_index: PrimitiveIndex, pub count: usize, - pub clip_and_scroll: ClipAndScrollInfo, + pub clip_and_scroll: ScrollNodeAndClipChain, } #[derive(Debug, Copy, Clone)] @@ -112,11 +123,9 @@ pub struct PrimitiveIndex(pub usize); pub enum PrimitiveKind { TextRun, Image, - YuvImage, Border, AlignedGradient, AngleGradient, - RadialGradient, Picture, Brush, } @@ -195,6 +204,22 @@ pub enum BrushKind { current_epoch: Epoch, alpha_type: AlphaType, }, + YuvImage { + yuv_key: [ImageKey; 3], + format: YuvFormat, + color_space: YuvColorSpace, + image_rendering: ImageRendering, + }, + RadialGradient { + stops_range: ItemRange, + extend_mode: ExtendMode, + stops_handle: GpuCacheHandle, + start_center: LayerPoint, + end_center: LayerPoint, + start_radius: f32, + end_radius: f32, + ratio_xy: f32, + } } impl BrushKind { @@ -202,7 +227,9 @@ impl BrushKind { match *self { BrushKind::Solid { .. } | BrushKind::Picture | - BrushKind::Image { .. } => true, + BrushKind::Image { .. } | + BrushKind::YuvImage { .. } | + BrushKind::RadialGradient { .. } => true, BrushKind::Mask { .. } | BrushKind::Clear | @@ -284,7 +311,8 @@ impl BrushPrimitive { // has to match VECS_PER_SPECIFIC_BRUSH match self.kind { BrushKind::Picture | - BrushKind::Image { .. } => { + BrushKind::Image { .. } | + BrushKind::YuvImage { .. } => { } BrushKind::Solid { color } => { request.push(color.premultiplied()); @@ -331,6 +359,20 @@ impl BrushPrimitive { 0.0, ]); } + BrushKind::RadialGradient { start_center, end_center, start_radius, end_radius, ratio_xy, extend_mode, .. } => { + request.push([ + start_center.x, + start_center.y, + end_center.x, + end_center.y, + ]); + request.push([ + start_radius, + end_radius, + ratio_xy, + pack_as_float(extend_mode as u32), + ]); + } } } } @@ -377,24 +419,6 @@ impl ToGpuBlocks for ImagePrimitiveCpu { } } -#[derive(Debug)] -pub struct YuvImagePrimitiveCpu { - pub yuv_key: [ImageKey; 3], - pub format: YuvFormat, - pub color_space: YuvColorSpace, - - pub image_rendering: ImageRendering, - - // TODO(gw): Generate on demand - pub gpu_block: GpuBlockData, -} - -impl ToGpuBlocks for YuvImagePrimitiveCpu { - fn write_gpu_blocks(&self, mut request: GpuDataRequest) { - request.push(self.gpu_block); - } -} - #[derive(Debug)] pub struct BorderPrimitiveCpu { pub corner_instances: [BorderCornerInstance; 4], @@ -631,27 +655,6 @@ impl<'a> GradientGpuBlockBuilder<'a> { } } -#[derive(Debug)] -pub struct RadialGradientPrimitiveCpu { - pub stops_range: ItemRange, - pub extend_mode: ExtendMode, - pub gpu_data_count: i32, - pub gpu_blocks: [GpuBlockData; 3], -} - -impl RadialGradientPrimitiveCpu { - fn build_gpu_blocks_for_angle_radial( - &self, - display_list: &BuiltDisplayList, - mut request: GpuDataRequest, - ) { - request.extend_from_slice(&self.gpu_blocks); - - let gradient_builder = GradientGpuBlockBuilder::new(self.stops_range, display_list); - gradient_builder.build(false, &mut request); - } -} - #[derive(Debug, Clone)] pub struct TextRunPrimitiveCpu { pub font: FontInstance, @@ -933,11 +936,9 @@ impl ClipData { pub enum PrimitiveContainer { TextRun(TextRunPrimitiveCpu), Image(ImagePrimitiveCpu), - YuvImage(YuvImagePrimitiveCpu), Border(BorderPrimitiveCpu), AlignedGradient(GradientPrimitiveCpu), AngleGradient(GradientPrimitiveCpu), - RadialGradient(RadialGradientPrimitiveCpu), Picture(PicturePrimitive), Brush(BrushPrimitive), } @@ -948,9 +949,7 @@ pub struct PrimitiveStore { pub cpu_text_runs: Vec, pub cpu_pictures: Vec, pub cpu_images: Vec, - pub cpu_yuv_images: Vec, pub cpu_gradients: Vec, - pub cpu_radial_gradients: Vec, pub cpu_metadata: Vec, pub cpu_borders: Vec, } @@ -963,9 +962,7 @@ impl PrimitiveStore { cpu_text_runs: Vec::new(), cpu_pictures: Vec::new(), cpu_images: Vec::new(), - cpu_yuv_images: Vec::new(), cpu_gradients: Vec::new(), - cpu_radial_gradients: Vec::new(), cpu_borders: Vec::new(), } } @@ -977,9 +974,7 @@ impl PrimitiveStore { cpu_text_runs: recycle_vec(self.cpu_text_runs), cpu_pictures: recycle_vec(self.cpu_pictures), cpu_images: recycle_vec(self.cpu_images), - cpu_yuv_images: recycle_vec(self.cpu_yuv_images), cpu_gradients: recycle_vec(self.cpu_gradients), - cpu_radial_gradients: recycle_vec(self.cpu_radial_gradients), cpu_borders: recycle_vec(self.cpu_borders), } } @@ -1018,6 +1013,8 @@ impl PrimitiveStore { BrushKind::Mask { .. } => PrimitiveOpacity::translucent(), BrushKind::Line { .. } => PrimitiveOpacity::translucent(), BrushKind::Image { .. } => PrimitiveOpacity::translucent(), + BrushKind::YuvImage { .. } => PrimitiveOpacity::opaque(), + BrushKind::RadialGradient { .. } => PrimitiveOpacity::translucent(), BrushKind::Picture => { // TODO(gw): This is not currently used. In the future // we should detect opaque pictures. @@ -1069,17 +1066,6 @@ impl PrimitiveStore { self.cpu_images.push(image_cpu); metadata } - PrimitiveContainer::YuvImage(image_cpu) => { - let metadata = PrimitiveMetadata { - opacity: PrimitiveOpacity::opaque(), - prim_kind: PrimitiveKind::YuvImage, - cpu_prim_index: SpecificPrimitiveIndex(self.cpu_yuv_images.len()), - ..base_metadata - }; - - self.cpu_yuv_images.push(image_cpu); - metadata - } PrimitiveContainer::Border(border_cpu) => { let metadata = PrimitiveMetadata { opacity: PrimitiveOpacity::translucent(), @@ -1114,18 +1100,6 @@ impl PrimitiveStore { self.cpu_gradients.push(gradient_cpu); metadata } - PrimitiveContainer::RadialGradient(radial_gradient_cpu) => { - let metadata = PrimitiveMetadata { - // TODO: calculate if the gradient is actually opaque - opacity: PrimitiveOpacity::translucent(), - prim_kind: PrimitiveKind::RadialGradient, - cpu_prim_index: SpecificPrimitiveIndex(self.cpu_radial_gradients.len()), - ..base_metadata - }; - - self.cpu_radial_gradients.push(radial_gradient_cpu); - metadata - } }; self.cpu_metadata.push(metadata); @@ -1293,22 +1267,6 @@ impl PrimitiveStore { } } } - PrimitiveKind::YuvImage => { - let image_cpu = &mut self.cpu_yuv_images[metadata.cpu_prim_index.0]; - - let channel_num = image_cpu.format.get_plane_num(); - debug_assert!(channel_num <= 3); - for channel in 0 .. channel_num { - frame_state.resource_cache.request_image( - ImageRequest { - key: image_cpu.yuv_key[channel], - rendering: image_cpu.image_rendering, - tile: None, - }, - frame_state.gpu_cache, - ); - } - } PrimitiveKind::Brush => { let brush = &mut self.cpu_brushes[metadata.cpu_prim_index.0]; @@ -1332,6 +1290,32 @@ impl PrimitiveStore { frame_state.gpu_cache, ); } + BrushKind::YuvImage { format, yuv_key, image_rendering, .. } => { + let channel_num = format.get_plane_num(); + debug_assert!(channel_num <= 3); + for channel in 0 .. channel_num { + frame_state.resource_cache.request_image( + ImageRequest { + key: yuv_key[channel], + rendering: image_rendering, + tile: None, + }, + frame_state.gpu_cache, + ); + } + } + BrushKind::RadialGradient { ref mut stops_handle, stops_range, .. } => { + if let Some(mut request) = frame_state.gpu_cache.request(stops_handle) { + let gradient_builder = GradientGpuBlockBuilder::new( + stops_range, + pic_context.display_list, + ); + gradient_builder.build( + false, + &mut request, + ); + } + } BrushKind::Mask { .. } | BrushKind::Solid { .. } | BrushKind::Clear | @@ -1340,8 +1324,7 @@ impl PrimitiveStore { } } PrimitiveKind::AlignedGradient | - PrimitiveKind::AngleGradient | - PrimitiveKind::RadialGradient => {} + PrimitiveKind::AngleGradient => {} } // Mark this GPU resource as required for this frame. @@ -1359,10 +1342,6 @@ impl PrimitiveStore { let image = &self.cpu_images[metadata.cpu_prim_index.0]; image.write_gpu_blocks(request); } - PrimitiveKind::YuvImage => { - let yuv_image = &self.cpu_yuv_images[metadata.cpu_prim_index.0]; - yuv_image.write_gpu_blocks(request); - } PrimitiveKind::AlignedGradient => { let gradient = &self.cpu_gradients[metadata.cpu_prim_index.0]; metadata.opacity = gradient.build_gpu_blocks_for_aligned( @@ -1377,13 +1356,6 @@ impl PrimitiveStore { request, ); } - PrimitiveKind::RadialGradient => { - let gradient = &self.cpu_radial_gradients[metadata.cpu_prim_index.0]; - gradient.build_gpu_blocks_for_angle_radial( - pic_context.display_list, - request, - ); - } PrimitiveKind::TextRun => { let text = &self.cpu_text_runs[metadata.cpu_prim_index.0]; text.write_gpu_blocks(&mut request); @@ -1634,12 +1606,9 @@ impl PrimitiveStore { } }; - let mut combined_outer_rect = match prim_run_context.clip_chain { - Some(ref chain) => prim_screen_rect.intersection(&chain.combined_outer_screen_rect), - None => Some(prim_screen_rect), - }; - - let clip_chain = prim_run_context.clip_chain.map_or(None, |x| x.nodes.clone()); + let mut combined_outer_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 prim_coordinate_system_id = prim_run_context.scroll_node.coordinate_system_id; let transform = &prim_run_context.scroll_node.world_content_transform; @@ -1860,12 +1829,8 @@ impl PrimitiveStore { frame_context.device_pixel_scale, ); - let clip_bounds = match prim_run_context.clip_chain { - Some(ref node) => node.combined_outer_screen_rect, - None => frame_context.screen_rect, - }; metadata.screen_rect = screen_bounding_rect - .intersection(&clip_bounds) + .intersection(&prim_run_context.clip_chain.combined_outer_screen_rect) .map(|clipped| { ScreenRect { clipped, @@ -1935,7 +1900,7 @@ impl PrimitiveStore { .nodes[&run.clip_and_scroll.scroll_node_id]; let clip_chain = frame_context .clip_scroll_tree - .get_clip_chain(&run.clip_and_scroll.clip_node_id()); + .get_clip_chain(run.clip_and_scroll.clip_chain_index); if pic_context.perform_culling { if !scroll_node.invertible { @@ -1943,16 +1908,12 @@ impl PrimitiveStore { continue; } - match clip_chain { - Some(ref chain) if chain.combined_outer_screen_rect.is_empty() => { - debug!("{:?} {:?}: clipped out", run.base_prim_index, pic_context.pipeline_id); - continue; - } - _ => {}, + if clip_chain.combined_outer_screen_rect.is_empty() { + debug!("{:?} {:?}: clipped out", run.base_prim_index, pic_context.pipeline_id); + continue; } } - let parent_relative_transform = pic_context .inv_world_transform .map(|inv_parent| { @@ -2082,14 +2043,9 @@ fn convert_clip_chain_to_clip_vector( fn get_local_clip_rect_for_nodes( scroll_node: &ClipScrollNode, - clip_chain: Option<&ClipChain>, + clip_chain: &ClipChain, ) -> Option { - let clip_chain_nodes = match clip_chain { - Some(ref clip_chain) => clip_chain.nodes.clone(), - None => return None, - }; - - let local_rect = ClipChainNodeIter { current: clip_chain_nodes }.fold( + let local_rect = ClipChainNodeIter { current: clip_chain.nodes.clone() }.fold( None, |combined_local_clip_rect: Option, node| { if node.work_item.coordinate_system_id != scroll_node.coordinate_system_id { diff --git a/gfx/webrender/src/profiler.rs b/gfx/webrender/src/profiler.rs index deb31f02b7dd..f230a6a4bff4 100644 --- a/gfx/webrender/src/profiler.rs +++ b/gfx/webrender/src/profiler.rs @@ -300,6 +300,9 @@ impl ProfileCounter for AverageTimeProfileCounter { pub struct FrameProfileCounters { pub total_primitives: IntProfileCounter, pub visible_primitives: IntProfileCounter, + pub targets_used: IntProfileCounter, + pub targets_changed: IntProfileCounter, + pub targets_created: IntProfileCounter, } impl FrameProfileCounters { @@ -307,8 +310,16 @@ impl FrameProfileCounters { FrameProfileCounters { total_primitives: IntProfileCounter::new("Total Primitives"), visible_primitives: IntProfileCounter::new("Visible Primitives"), + targets_used: IntProfileCounter::new("Used targets"), + targets_changed: IntProfileCounter::new("Changed targets"), + targets_created: IntProfileCounter::new("Created targets"), } } + pub fn reset_targets(&mut self) { + self.targets_used.reset(); + self.targets_changed.reset(); + self.targets_created.reset(); + } } #[derive(Clone)] @@ -840,7 +851,7 @@ impl Profiler { } } - fn draw_gpu_cache_bar( + fn draw_bar( &mut self, label: &str, label_color: ColorU, @@ -898,9 +909,9 @@ impl Profiler { value: counters.allocated_rows.value * MAX_VERTEX_TEXTURE_WIDTH, }; - let rect0 = self.draw_gpu_cache_bar( + let rect0 = self.draw_bar( &format!("GPU cache rows ({}):", counters.allocated_rows.value), - ColorU::new(255, 255, 255, 255), + ColorU::new(0xFF, 0xFF, 0xFF, 0xFF), &[ (color_updated, &counters.updated_rows), (color_free, &counters.allocated_rows), @@ -908,14 +919,53 @@ impl Profiler { debug_renderer, ); - let rect1 = self.draw_gpu_cache_bar( + let rect1 = self.draw_bar( "GPU cache blocks", - ColorU::new(255, 255, 0, 255), + ColorU::new(0xFF, 0xFF, 0, 0xFF), &[ (color_updated, &counters.updated_blocks), (color_saved, &requested_blocks), (color_free, &counters.allocated_blocks), - (ColorU::new(0, 0, 0, 255), &total_blocks), + (ColorU::new(0, 0, 0, 0xFF), &total_blocks), + ], + debug_renderer, + ); + + let total_rect = rect0.union(&rect1).inflate(10.0, 10.0); + debug_renderer.add_quad( + total_rect.origin.x, + total_rect.origin.y, + total_rect.origin.x + total_rect.size.width, + total_rect.origin.y + total_rect.size.height, + ColorF::new(0.1, 0.1, 0.1, 0.8).into(), + ColorF::new(0.2, 0.2, 0.2, 0.8).into(), + ); + + self.draw_state.y_left = total_rect.origin.y + total_rect.size.height + 30.0; + } + + fn draw_frame_bars( + &mut self, + counters: &FrameProfileCounters, + debug_renderer: &mut DebugRenderer, + ) { + let rect0 = self.draw_bar( + &format!("primitives ({}):", counters.total_primitives.value), + ColorU::new(0xFF, 0xFF, 0xFF, 0xFF), + &[ + (ColorU::new(0, 0, 0xFF, 0xFF), &counters.visible_primitives), + (ColorU::new(0, 0, 0, 0xFF), &counters.total_primitives), + ], + debug_renderer, + ); + + let rect1 = self.draw_bar( + &format!("GPU targets ({}):", &counters.targets_used.value), + ColorU::new(0xFF, 0xFF, 0, 0xFF), + &[ + (ColorU::new(0, 0, 0xFF, 0xFF), &counters.targets_created), + (ColorU::new(0xFF, 0, 0, 0xFF), &counters.targets_changed), + (ColorU::new(0, 0xFF, 0, 0xFF), &counters.targets_used), ], debug_renderer, ); @@ -1017,15 +1067,7 @@ impl Profiler { ); for frame_profile in frame_profiles { - Profiler::draw_counters( - &[ - &frame_profile.total_primitives, - &frame_profile.visible_primitives, - ], - debug_renderer, - true, - &mut self.draw_state - ); + self.draw_frame_bars(frame_profile, debug_renderer); } Profiler::draw_counters( diff --git a/gfx/webrender/src/render_task.rs b/gfx/webrender/src/render_task.rs index 69356de64615..c5a682412959 100644 --- a/gfx/webrender/src/render_task.rs +++ b/gfx/webrender/src/render_task.rs @@ -2,22 +2,21 @@ * 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::{DeviceIntPoint, DeviceIntRect, DeviceIntSize}; -use api::{ImageDescriptor, ImageFormat, LayerRect, PremultipliedColorF}; +use api::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, ImageDescriptor, ImageFormat}; +use api::PremultipliedColorF; use box_shadow::BoxShadowCacheKey; -use clip::{ClipSourcesWeakHandle}; +use clip::ClipWorkItem; use clip_scroll_tree::CoordinateSystemId; use device::TextureFilter; use gpu_cache::GpuCache; -use gpu_types::{ClipScrollNodeIndex, PictureType}; -use internal_types::{FastHashMap, RenderPassIndex, SourceTexture}; +use gpu_types::PictureType; +use internal_types::{FastHashMap, SavedTargetIndex, SourceTexture}; use picture::ContentOrigin; use prim_store::{PrimitiveIndex, ImageCacheKey}; #[cfg(feature = "debugger")] use print_tree::{PrintTreePrinter}; use resource_cache::CacheItem; use std::{cmp, ops, usize, f32, i32}; -use std::rc::Rc; use texture_cache::{TextureCache, TextureCacheHandle}; use tiling::{RenderPass, RenderTargetIndex}; use tiling::{RenderTargetKind}; @@ -43,91 +42,7 @@ pub struct RenderTaskAddress(pub u32); pub struct RenderTaskTree { pub tasks: Vec, pub task_data: Vec, -} - -pub type ClipChainNodeRef = Option>; - -#[derive(Debug, Clone)] -pub struct ClipChainNode { - pub work_item: ClipWorkItem, - pub local_clip_rect: LayerRect, - pub screen_outer_rect: DeviceIntRect, - pub screen_inner_rect: DeviceIntRect, - pub prev: ClipChainNodeRef, -} - -#[derive(Debug, Clone)] -pub struct ClipChain { - pub combined_outer_screen_rect: DeviceIntRect, - pub combined_inner_screen_rect: DeviceIntRect, - pub nodes: ClipChainNodeRef, -} - -impl ClipChain { - pub fn empty(screen_rect: &DeviceIntRect) -> ClipChain { - ClipChain { - combined_inner_screen_rect: *screen_rect, - combined_outer_screen_rect: *screen_rect, - nodes: None, - } - } - - pub fn new_with_added_node( - &self, - work_item: ClipWorkItem, - local_clip_rect: LayerRect, - screen_outer_rect: DeviceIntRect, - screen_inner_rect: DeviceIntRect, - ) -> ClipChain { - let new_node = ClipChainNode { - work_item, - local_clip_rect, - screen_outer_rect, - screen_inner_rect, - prev: None, - }; - - let mut new_chain = self.clone(); - new_chain.add_node(new_node); - new_chain - } - - pub fn add_node(&mut self, mut new_node: ClipChainNode) { - new_node.prev = self.nodes.clone(); - - // If this clip's outer rectangle is completely enclosed by the clip - // chain's inner rectangle, then the only clip that matters from this point - // on is this clip. We can disconnect this clip from the parent clip chain. - if self.combined_inner_screen_rect.contains_rect(&new_node.screen_outer_rect) { - new_node.prev = None; - } - - self.combined_outer_screen_rect = - self.combined_outer_screen_rect.intersection(&new_node.screen_outer_rect) - .unwrap_or_else(DeviceIntRect::zero); - self.combined_inner_screen_rect = - self.combined_inner_screen_rect.intersection(&new_node.screen_inner_rect) - .unwrap_or_else(DeviceIntRect::zero); - - self.nodes = Some(Rc::new(new_node)); - } -} - -pub struct ClipChainNodeIter { - pub current: ClipChainNodeRef, -} - -impl Iterator for ClipChainNodeIter { - type Item = Rc; - - fn next(&mut self) -> ClipChainNodeRef { - let previous = self.current.clone(); - self.current = match self.current { - Some(ref item) => item.prev.clone(), - None => return None, - }; - previous - } + next_saved: SavedTargetIndex, } impl RenderTaskTree { @@ -135,6 +50,7 @@ impl RenderTaskTree { RenderTaskTree { tasks: Vec::new(), task_data: Vec::new(), + next_saved: SavedTargetIndex(0), } } @@ -195,10 +111,16 @@ impl RenderTaskTree { } pub fn build(&mut self) { - for task in &mut self.tasks { + for task in &self.tasks { self.task_data.push(task.write_task_data()); } } + + pub fn save_target(&mut self) -> SavedTargetIndex { + let id = self.next_saved; + self.next_saved.0 += 1; + id + } } impl ops::Index for RenderTaskTree { @@ -223,15 +145,6 @@ pub enum RenderTaskLocation { TextureCache(SourceTexture, i32, DeviceIntRect), } -#[derive(Debug, Clone)] -#[cfg_attr(feature = "capture", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] -pub struct ClipWorkItem { - pub scroll_node_data_index: ClipScrollNodeIndex, - pub clip_sources: ClipSourcesWeakHandle, - pub coordinate_system_id: CoordinateSystemId, -} - #[derive(Debug)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] @@ -331,7 +244,7 @@ pub struct RenderTask { pub children: Vec, pub kind: RenderTaskKind, pub clear_mode: ClearMode, - pub pass_index: Option, + pub saved_index: Option, } impl RenderTask { @@ -356,7 +269,7 @@ impl RenderTask { pic_type, }), clear_mode, - pass_index: None, + saved_index: None, } } @@ -366,7 +279,7 @@ impl RenderTask { location: RenderTaskLocation::Dynamic(None, screen_rect.size), kind: RenderTaskKind::Readback(screen_rect), clear_mode: ClearMode::Transparent, - pass_index: None, + saved_index: None, } } @@ -392,7 +305,7 @@ impl RenderTask { source, }), clear_mode: ClearMode::Transparent, - pass_index: None, + saved_index: None, } } @@ -400,7 +313,7 @@ impl RenderTask { outer_rect: DeviceIntRect, clips: Vec, prim_coordinate_system_id: CoordinateSystemId, - ) -> RenderTask { + ) -> Self { RenderTask { children: Vec::new(), location: RenderTaskLocation::Dynamic(None, outer_rect.size), @@ -410,7 +323,7 @@ impl RenderTask { coordinate_system_id: prim_coordinate_system_id, }), clear_mode: ClearMode::One, - pass_index: None, + saved_index: None, } } @@ -473,7 +386,7 @@ impl RenderTask { scale_factor, }), clear_mode, - pass_index: None, + saved_index: None, }; let blur_task_v_id = render_tasks.add(blur_task_v); @@ -488,7 +401,7 @@ impl RenderTask { scale_factor, }), clear_mode, - pass_index: None, + saved_index: None, }; (blur_task_h, scale_factor) @@ -507,7 +420,7 @@ impl RenderTask { RenderTargetKind::Color => ClearMode::Transparent, RenderTargetKind::Alpha => ClearMode::One, }, - pass_index: None, + saved_index: None, } } @@ -674,7 +587,6 @@ impl RenderTask { RenderTaskKind::HorizontalBlur(..) | RenderTaskKind::Scaling(..) | RenderTaskKind::Blit(..) => false, - RenderTaskKind::CacheMask(..) => true, } } @@ -723,6 +635,19 @@ impl RenderTask { pt.end_level(); true } + + /// Mark this render task for keeping the results alive up until the end of the frame. + pub fn mark_for_saving(&mut self) { + match self.location { + RenderTaskLocation::Fixed(..) | + RenderTaskLocation::Dynamic(..) => { + self.saved_index = Some(SavedTargetIndex::PENDING); + } + RenderTaskLocation::TextureCache(..) => { + panic!("Unable to mark a permanently cached task for saving!"); + } + } + } } #[derive(Debug, Hash, PartialEq, Eq)] diff --git a/gfx/webrender/src/renderer.rs b/gfx/webrender/src/renderer.rs index c08aa3d6f11d..16078ecf9512 100644 --- a/gfx/webrender/src/renderer.rs +++ b/gfx/webrender/src/renderer.rs @@ -40,15 +40,15 @@ use glyph_rasterizer::GlyphFormat; use gpu_cache::{GpuBlockData, GpuCacheUpdate, GpuCacheUpdateList}; use gpu_types::PrimitiveInstance; use internal_types::{SourceTexture, ORTHO_FAR_PLANE, ORTHO_NEAR_PLANE, ResourceCacheError}; -use internal_types::{CacheTextureId, FastHashMap, RenderedDocument, ResultMsg, TextureUpdateOp}; -use internal_types::{DebugOutput, RenderPassIndex, RenderTargetInfo, TextureUpdateList, TextureUpdateSource}; +use internal_types::{CacheTextureId, DebugOutput, FastHashMap, RenderedDocument, ResultMsg}; +use internal_types::{TextureUpdateList, TextureUpdateOp, TextureUpdateSource}; +use internal_types::{RenderTargetInfo, SavedTargetIndex}; use picture::ContentOrigin; use prim_store::DeferredResolve; -use profiler::{BackendProfileCounters, Profiler}; +use profiler::{BackendProfileCounters, FrameProfileCounters, Profiler}; use profiler::{GpuProfileTag, RendererProfileCounters, RendererProfileTimers}; use query::{GpuProfiler, GpuTimer}; -use rayon::Configuration as ThreadPoolConfig; -use rayon::ThreadPool; +use rayon::{ThreadPool, ThreadPoolBuilder}; use record::ApiRecordingReceiver; use render_backend::RenderBackend; use render_task::{RenderTaskKind, RenderTaskTree}; @@ -83,6 +83,14 @@ const GPU_CACHE_RESIZE_TEST: bool = false; /// Number of GPU blocks per UV rectangle provided for an image. pub const BLOCKS_PER_UV_RECT: usize = 2; +const GPU_TAG_BRUSH_RADIAL_GRADIENT: GpuProfileTag = GpuProfileTag { + label: "B_RadialGradient", + color: debug_colors::LIGHTPINK, +}; +const GPU_TAG_BRUSH_YUV_IMAGE: GpuProfileTag = GpuProfileTag { + label: "B_YuvImage", + color: debug_colors::DARKGREEN, +}; const GPU_TAG_BRUSH_MIXBLEND: GpuProfileTag = GpuProfileTag { label: "B_MixBlend", color: debug_colors::MAGENTA, @@ -131,10 +139,6 @@ const GPU_TAG_PRIM_IMAGE: GpuProfileTag = GpuProfileTag { label: "Image", color: debug_colors::GREEN, }; -const GPU_TAG_PRIM_YUV_IMAGE: GpuProfileTag = GpuProfileTag { - label: "YuvImage", - color: debug_colors::DARKGREEN, -}; const GPU_TAG_PRIM_HW_COMPOSITE: GpuProfileTag = GpuProfileTag { label: "HwComposite", color: debug_colors::DODGERBLUE, @@ -155,10 +159,6 @@ const GPU_TAG_PRIM_ANGLE_GRADIENT: GpuProfileTag = GpuProfileTag { label: "AngleGradient", color: debug_colors::POWDERBLUE, }; -const GPU_TAG_PRIM_RADIAL_GRADIENT: GpuProfileTag = GpuProfileTag { - label: "RadialGradient", - color: debug_colors::LIGHTPINK, -}; const GPU_TAG_PRIM_BORDER_CORNER: GpuProfileTag = GpuProfileTag { label: "BorderCorner", color: debug_colors::DARKSLATEGREY, @@ -200,10 +200,8 @@ impl TransformBatchKind { ImageBufferKind::TextureExternal => "Image (External)", ImageBufferKind::Texture2DArray => "Image (Array)", }, - TransformBatchKind::YuvImage(..) => "YuvImage", TransformBatchKind::AlignedGradient => "AlignedGradient", TransformBatchKind::AngleGradient => "AngleGradient", - TransformBatchKind::RadialGradient => "RadialGradient", TransformBatchKind::BorderCorner => "BorderCorner", TransformBatchKind::BorderEdge => "BorderEdge", } @@ -213,12 +211,10 @@ impl TransformBatchKind { match *self { TransformBatchKind::TextRun(..) => GPU_TAG_PRIM_TEXT_RUN, TransformBatchKind::Image(..) => GPU_TAG_PRIM_IMAGE, - TransformBatchKind::YuvImage(..) => GPU_TAG_PRIM_YUV_IMAGE, TransformBatchKind::BorderCorner => GPU_TAG_PRIM_BORDER_CORNER, TransformBatchKind::BorderEdge => GPU_TAG_PRIM_BORDER_EDGE, TransformBatchKind::AlignedGradient => GPU_TAG_PRIM_GRADIENT, TransformBatchKind::AngleGradient => GPU_TAG_PRIM_ANGLE_GRADIENT, - TransformBatchKind::RadialGradient => GPU_TAG_PRIM_RADIAL_GRADIENT, } } } @@ -237,6 +233,8 @@ impl BatchKind { BrushBatchKind::Image(..) => "Brush (Image)", BrushBatchKind::Blend => "Brush (Blend)", BrushBatchKind::MixBlend { .. } => "Brush (Composite)", + BrushBatchKind::YuvImage(..) => "Brush (YuvImage)", + BrushBatchKind::RadialGradient => "Brush (RadialGradient)", } } BatchKind::Transformable(_, batch_kind) => batch_kind.debug_name(), @@ -255,6 +253,8 @@ impl BatchKind { BrushBatchKind::Image(..) => GPU_TAG_BRUSH_IMAGE, BrushBatchKind::Blend => GPU_TAG_BRUSH_BLEND, BrushBatchKind::MixBlend { .. } => GPU_TAG_BRUSH_MIXBLEND, + BrushBatchKind::YuvImage(..) => GPU_TAG_BRUSH_YUV_IMAGE, + BrushBatchKind::RadialGradient => GPU_TAG_BRUSH_RADIAL_GRADIENT, } } BatchKind::Transformable(_, batch_kind) => batch_kind.gpu_sampler_tag(), @@ -598,7 +598,11 @@ impl CpuProfile { } } -struct RenderTargetPoolId(usize); +struct ActiveTexture { + texture: Texture, + saved_index: Option, + is_shared: bool, +} struct SourceTextureResolver { /// A vector for fast resolves of texture cache IDs to @@ -620,12 +624,17 @@ struct SourceTextureResolver { dummy_cache_texture: Texture, /// The current cache textures. - cache_rgba8_texture: Option, - cache_a8_texture: Option, + cache_rgba8_texture: Option, + cache_a8_texture: Option, - pass_rgba8_textures: FastHashMap, - pass_a8_textures: FastHashMap, + /// An alpha texture shared between all passes. + //TODO: just use the standard texture saving logic instead. + shared_alpha_texture: Option, + /// Saved cache textures that are to be re-used. + saved_textures: Vec, + + /// General pool of render targets. render_target_pool: Vec, } @@ -649,8 +658,8 @@ impl SourceTextureResolver { dummy_cache_texture, cache_a8_texture: None, cache_rgba8_texture: None, - pass_rgba8_textures: FastHashMap::default(), - pass_a8_textures: FastHashMap::default(), + shared_alpha_texture: None, + saved_textures: Vec::default(), render_target_pool: Vec::new(), } } @@ -670,34 +679,47 @@ impl SourceTextureResolver { fn begin_frame(&mut self) { assert!(self.cache_rgba8_texture.is_none()); assert!(self.cache_a8_texture.is_none()); - - self.pass_rgba8_textures.clear(); - self.pass_a8_textures.clear(); + assert!(self.saved_textures.is_empty()); } - fn end_frame(&mut self, pass_index: RenderPassIndex) { + fn end_frame(&mut self) { // return the cached targets to the pool - self.end_pass(None, None, pass_index) + self.end_pass(None, None); + // return the global alpha texture + self.render_target_pool.extend(self.shared_alpha_texture.take()); + // return the saved targets as well + self.render_target_pool.extend(self.saved_textures.drain(..)); } fn end_pass( &mut self, - a8_texture: Option, - rgba8_texture: Option, - pass_index: RenderPassIndex, + a8_texture: Option, + rgba8_texture: Option, ) { // If we have cache textures from previous pass, return them to the pool. // Also assign the pool index of those cache textures to last pass's index because this is // the result of last pass. - if let Some(texture) = self.cache_rgba8_texture.take() { - self.pass_rgba8_textures.insert( - RenderPassIndex(pass_index.0 - 1), RenderTargetPoolId(self.render_target_pool.len())); - self.render_target_pool.push(texture); + // Note: the order here is important, needs to match the logic in `RenderPass::build()`. + if let Some(at) = self.cache_rgba8_texture.take() { + assert!(!at.is_shared); + if let Some(index) = at.saved_index { + assert_eq!(self.saved_textures.len(), index.0); + self.saved_textures.push(at.texture); + } else { + self.render_target_pool.push(at.texture); + } } - if let Some(texture) = self.cache_a8_texture.take() { - self.pass_a8_textures.insert( - RenderPassIndex(pass_index.0 - 1), RenderTargetPoolId(self.render_target_pool.len())); - self.render_target_pool.push(texture); + if let Some(at) = self.cache_a8_texture.take() { + if let Some(index) = at.saved_index { + assert!(!at.is_shared); + assert_eq!(self.saved_textures.len(), index.0); + self.saved_textures.push(at.texture); + } else if at.is_shared { + assert!(self.shared_alpha_texture.is_none()); + self.shared_alpha_texture = Some(at.texture); + } else { + self.render_target_pool.push(at.texture); + } } // We have another pass to process, make these textures available @@ -711,15 +733,17 @@ impl SourceTextureResolver { match *texture_id { SourceTexture::Invalid => {} SourceTexture::CacheA8 => { - let texture = self.cache_a8_texture - .as_ref() - .unwrap_or(&self.dummy_cache_texture); + let texture = match self.cache_a8_texture { + Some(ref at) => &at.texture, + None => &self.dummy_cache_texture, + }; device.bind_texture(sampler, texture); } SourceTexture::CacheRGBA8 => { - let texture = self.cache_rgba8_texture - .as_ref() - .unwrap_or(&self.dummy_cache_texture); + let texture = match self.cache_rgba8_texture { + Some(ref at) => &at.texture, + None => &self.dummy_cache_texture, + }; device.bind_texture(sampler, texture); } SourceTexture::External(external_image) => { @@ -732,17 +756,9 @@ impl SourceTextureResolver { let texture = &self.cache_texture_map[index.0]; device.bind_texture(sampler, texture); } - SourceTexture::RenderTaskCacheRGBA8(pass_index) => { - let pool_index = self.pass_rgba8_textures - .get(&pass_index) - .expect("BUG: pass_index doesn't map to pool_index"); - device.bind_texture(sampler, &self.render_target_pool[pool_index.0]) - } - SourceTexture::RenderTaskCacheA8(pass_index) => { - let pool_index = self.pass_a8_textures - .get(&pass_index) - .expect("BUG: pass_index doesn't map to pool_index"); - device.bind_texture(sampler, &self.render_target_pool[pool_index.0]) + SourceTexture::RenderTaskCache(saved_index) => { + let texture = &self.saved_textures[saved_index.0]; + device.bind_texture(sampler, texture) } } } @@ -754,31 +770,26 @@ impl SourceTextureResolver { match *texture_id { SourceTexture::Invalid => None, SourceTexture::CacheA8 => Some( - self.cache_a8_texture - .as_ref() - .unwrap_or(&self.dummy_cache_texture), + match self.cache_a8_texture { + Some(ref at) => &at.texture, + None => &self.dummy_cache_texture, + } ), SourceTexture::CacheRGBA8 => Some( - self.cache_rgba8_texture - .as_ref() - .unwrap_or(&self.dummy_cache_texture), + match self.cache_rgba8_texture { + Some(ref at) => &at.texture, + None => &self.dummy_cache_texture, + } ), SourceTexture::External(..) => { panic!("BUG: External textures cannot be resolved, they can only be bound."); } - SourceTexture::TextureCache(index) => Some(&self.cache_texture_map[index.0]), - SourceTexture::RenderTaskCacheRGBA8(pass_index) => { - let pool_index = self.pass_rgba8_textures - .get(&pass_index) - .expect("BUG: pass_index doesn't map to pool_index"); - Some(&self.render_target_pool[pool_index.0]) - }, - SourceTexture::RenderTaskCacheA8(pass_index) => { - let pool_index = self.pass_a8_textures - .get(&pass_index) - .expect("BUG: pass_index doesn't map to pool_index"); - Some(&self.render_target_pool[pool_index.0]) - }, + SourceTexture::TextureCache(index) => { + Some(&self.cache_texture_map[index.0]) + } + SourceTexture::RenderTaskCache(saved_index) => { + Some(&self.saved_textures[saved_index.0]) + } } } } @@ -1605,6 +1616,8 @@ pub struct Renderer { brush_image: Vec>, brush_blend: BrushShader, brush_mix_blend: BrushShader, + brush_yuv_image: Vec>, + brush_radial_gradient: BrushShader, /// These are "cache clip shaders". These shaders are used to /// draw clip instances into the cached clip mask. The results @@ -1623,12 +1636,10 @@ pub struct Renderer { ps_text_run: TextShader, ps_text_run_dual_source: TextShader, ps_image: Vec>, - ps_yuv_image: Vec>, ps_border_corner: PrimitiveShader, ps_border_edge: PrimitiveShader, ps_gradient: PrimitiveShader, ps_angle_gradient: PrimitiveShader, - ps_radial_gradient: PrimitiveShader, ps_hw_composite: LazilyCompiledShader, ps_split_composite: LazilyCompiledShader, @@ -1745,6 +1756,7 @@ impl Renderer { let (payload_tx, payload_rx) = try!{ channel::payload_channel() }; let (result_tx, result_rx) = channel(); let gl_type = gl.get_type(); + let dithering_feature = ["DITHERING"]; let debug_server = DebugServer::new(api_tx.clone()); @@ -1861,6 +1873,17 @@ impl Renderer { options.precache_shaders) }; + let brush_radial_gradient = try!{ + BrushShader::new("brush_radial_gradient", + &mut device, + if options.enable_dithering { + &dithering_feature + } else { + &[] + }, + options.precache_shaders) + }; + let cs_blur_a8 = try!{ LazilyCompiledShader::new(ShaderKind::Cache(VertexArrayKind::Blur), "cs_blur", @@ -1952,10 +1975,10 @@ impl Renderer { // All yuv_image configuration. let mut yuv_features = Vec::new(); let yuv_shader_num = IMAGE_BUFFER_KINDS.len() * YUV_FORMATS.len() * YUV_COLOR_SPACES.len(); - let mut ps_yuv_image: Vec> = Vec::new(); + let mut brush_yuv_image = Vec::new(); // PrimitiveShader is not clonable. Use push() to initialize the vec. for _ in 0 .. yuv_shader_num { - ps_yuv_image.push(None); + brush_yuv_image.push(None); } for buffer_kind in 0 .. IMAGE_BUFFER_KINDS.len() { if IMAGE_BUFFER_KINDS[buffer_kind].has_platform_support(&gl_type) { @@ -1976,17 +1999,17 @@ impl Renderer { } let shader = try!{ - PrimitiveShader::new("ps_yuv_image", - &mut device, - &yuv_features, - options.precache_shaders) + BrushShader::new("brush_yuv_image", + &mut device, + &yuv_features, + options.precache_shaders) }; let index = Renderer::get_yuv_shader_index( IMAGE_BUFFER_KINDS[buffer_kind], YUV_FORMATS[format_kind], YUV_COLOR_SPACES[color_space_kind], ); - ps_yuv_image[index] = Some(shader); + brush_yuv_image[index] = Some(shader); yuv_features.clear(); } } @@ -2007,8 +2030,6 @@ impl Renderer { options.precache_shaders) }; - let dithering_feature = ["DITHERING"]; - let ps_gradient = try!{ PrimitiveShader::new("ps_gradient", &mut device, @@ -2031,17 +2052,6 @@ impl Renderer { options.precache_shaders) }; - let ps_radial_gradient = try!{ - PrimitiveShader::new("ps_radial_gradient", - &mut device, - if options.enable_dithering { - &dithering_feature - } else { - &[] - }, - options.precache_shaders) - }; - let ps_hw_composite = try!{ LazilyCompiledShader::new(ShaderKind::Primitive, "ps_hardware_composite", @@ -2215,7 +2225,7 @@ impl Renderer { .workers .take() .unwrap_or_else(|| { - let worker_config = ThreadPoolConfig::new() + let worker = ThreadPoolBuilder::new() .thread_name(|idx|{ format!("WRWorker#{}", idx) }) .start_handler(move |idx| { register_thread_with_profiler(format!("WRWorker#{}", idx)); @@ -2227,8 +2237,9 @@ impl Renderer { if let Some(ref thread_listener) = *thread_listener_for_rayon_end { thread_listener.thread_stopped(&format!("WRWorker#{}", idx)); } - }); - Arc::new(ThreadPool::new(worker_config).unwrap()) + }) + .build(); + Arc::new(worker.unwrap()) }); let enable_render_on_scroll = options.enable_render_on_scroll; @@ -2290,18 +2301,18 @@ impl Renderer { brush_image, brush_blend, brush_mix_blend, + brush_yuv_image, + brush_radial_gradient, cs_clip_rectangle, cs_clip_border, cs_clip_image, ps_text_run, ps_text_run_dual_source, ps_image, - ps_yuv_image, ps_border_corner, ps_border_edge, ps_gradient, ps_angle_gradient, - ps_radial_gradient, ps_hw_composite, ps_split_composite, debug: debug_renderer, @@ -2873,18 +2884,13 @@ impl Renderer { } } - // Re-use whatever targets possible from the pool, before - // they get changed/re-allocated by the rendered frames. - for doc_with_id in &mut active_documents { - self.prepare_tile_frame(&mut doc_with_id.1.frame); - } - #[cfg(feature = "replay")] self.texture_resolver.external_images.extend( self.owned_external_images.iter().map(|(key, value)| (*key, value.clone())) ); for &mut (_, RenderedDocument { ref mut frame, .. }) in &mut active_documents { + frame.profile_counters.reset_targets(); self.prepare_gpu_cache(frame); assert!(frame.gpu_cache_frame_id <= self.gpu_cache_frame_id); @@ -3257,6 +3263,29 @@ impl Renderer { &mut self.renderer_errors, ); } + BrushBatchKind::RadialGradient => { + self.brush_radial_gradient.bind( + &mut self.device, + key.blend_mode, + projection, + 0, + &mut self.renderer_errors, + ); + } + BrushBatchKind::YuvImage(image_buffer_kind, format, color_space) => { + let shader_index = + Renderer::get_yuv_shader_index(image_buffer_kind, format, color_space); + self.brush_yuv_image[shader_index] + .as_mut() + .expect("Unsupported YUV shader kind") + .bind( + &mut self.device, + key.blend_mode, + projection, + 0, + &mut self.renderer_errors, + ); + } } } BatchKind::Transformable(transform_kind, batch_kind) => match batch_kind { @@ -3275,20 +3304,6 @@ impl Renderer { &mut self.renderer_errors, ); } - TransformBatchKind::YuvImage(image_buffer_kind, format, color_space) => { - let shader_index = - Renderer::get_yuv_shader_index(image_buffer_kind, format, color_space); - self.ps_yuv_image[shader_index] - .as_mut() - .expect("Unsupported YUV shader kind") - .bind( - &mut self.device, - transform_kind, - projection, - 0, - &mut self.renderer_errors, - ); - } TransformBatchKind::BorderCorner => { self.ps_border_corner.bind( &mut self.device, @@ -3325,15 +3340,6 @@ impl Renderer { &mut self.renderer_errors, ); } - TransformBatchKind::RadialGradient => { - self.ps_radial_gradient.bind( - &mut self.device, - transform_kind, - projection, - 0, - &mut self.renderer_errors, - ); - } }, }; @@ -4250,47 +4256,52 @@ impl Renderer { } } - fn prepare_target_list( + fn allocate_target_texture( &mut self, list: &mut RenderTargetList, - perfect_only: bool, - ) { + counters: &mut FrameProfileCounters, + frame_id: FrameId, + ) -> Option { debug_assert_ne!(list.max_size, DeviceUintSize::zero()); if list.targets.is_empty() { - return; + return None } - let mut texture = if perfect_only { - debug_assert!(list.texture.is_none()); - let selector = TargetSelector { - size: list.max_size, - num_layers: list.targets.len() as _, - format: list.format, - }; - let index = self.texture_resolver.render_target_pool + counters.targets_used.inc(); + + // First, try finding a perfect match + let selector = TargetSelector { + size: list.max_size, + num_layers: list.targets.len() as _, + format: list.format, + }; + let mut index = self.texture_resolver.render_target_pool + .iter() + .position(|texture| { + //TODO: re-use a part of a larger target, if available + selector == TargetSelector { + size: texture.get_dimensions(), + num_layers: texture.get_render_target_layer_count(), + format: texture.get_format(), + } + }); + + // Next, try at least finding a matching format + if index.is_none() { + counters.targets_changed.inc(); + index = self.texture_resolver.render_target_pool .iter() - .position(|texture| { - selector == TargetSelector { - size: texture.get_dimensions(), - num_layers: texture.get_render_target_layer_count(), - format: texture.get_format(), - } - }); - match index { - Some(pos) => self.texture_resolver.render_target_pool.swap_remove(pos), - None => return, + .position(|texture| texture.get_format() == list.format && !texture.used_in_frame(frame_id)); + } + + let mut texture = match index { + Some(pos) => { + self.texture_resolver.render_target_pool.swap_remove(pos) } - } else { - if list.texture.is_some() { - list.check_ready(); - return - } - let index = self.texture_resolver.render_target_pool - .iter() - .position(|texture| texture.get_format() == list.format); - match index { - Some(pos) => self.texture_resolver.render_target_pool.swap_remove(pos), - None => self.device.create_texture(TextureTarget::Array, list.format), + None => { + counters.targets_created.inc(); + // finally, give up and create a new one + self.device.create_texture(TextureTarget::Array, list.format) } }; @@ -4305,34 +4316,19 @@ impl Renderer { list.targets.len() as _, None, ); - list.texture = Some(texture); - list.check_ready(); - } - fn prepare_tile_frame(&mut self, frame: &mut Frame) { - // Init textures and render targets to match this scene. - // First pass grabs all the perfectly matching targets from the pool. - for pass in &mut frame.passes { - if let RenderPassKind::OffScreen { ref mut alpha, ref mut color, .. } = pass.kind { - self.prepare_target_list(alpha, true); - self.prepare_target_list(color, true); - } - } + list.check_ready(&texture); + Some(ActiveTexture { + texture, + saved_index: list.saved_index.clone(), + is_shared: list.is_shared, + }) } fn bind_frame_data(&mut self, frame: &mut Frame) { let _timer = self.gpu_profile.start_timer(GPU_TAG_SETUP_DATA); self.device.set_device_pixel_ratio(frame.device_pixel_ratio); - // Some of the textures are already assigned by `prepare_frame`. - // Now re-allocate the space for the rest of the target textures. - for pass in &mut frame.passes { - if let RenderPassKind::OffScreen { ref mut alpha, ref mut color, .. } = pass.kind { - self.prepare_target_list(alpha, false); - self.prepare_target_list(color, false); - } - } - self.node_data_texture.update(&mut self.device, &mut frame.node_data); self.device.bind_texture(TextureSampler::ClipScrollNodes, &self.node_data_texture.texture); @@ -4424,8 +4420,8 @@ impl Renderer { (None, None) } RenderPassKind::OffScreen { ref mut alpha, ref mut color, ref mut texture_cache } => { - alpha.check_ready(); - color.check_ready(); + let alpha_tex = self.allocate_target_texture(alpha, &mut frame.profile_counters, frame_id); + let color_tex = self.allocate_target_texture(color, &mut frame.profile_counters, frame_id); // If this frame has already been drawn, then any texture // cache targets have already been updated and can be @@ -4455,7 +4451,7 @@ impl Renderer { ); self.draw_alpha_target( - (alpha.texture.as_ref().unwrap(), target_index as i32), + (&alpha_tex.as_ref().unwrap().texture, target_index as i32), target, alpha.max_size, &projection, @@ -4477,7 +4473,7 @@ impl Renderer { ); self.draw_color_target( - Some((color.texture.as_ref().unwrap(), target_index as i32)), + Some((&color_tex.as_ref().unwrap().texture, target_index as i32)), target, frame.inner_rect, color.max_size, @@ -4490,29 +4486,23 @@ impl Renderer { ); } - (alpha.texture.take(), color.texture.take()) + (alpha_tex, color_tex) } }; + //Note: the `end_pass` will make sure this texture is not recycled this frame + if let Some(ActiveTexture { ref texture, is_shared: true, .. }) = cur_alpha { + self.device + .bind_texture(TextureSampler::SharedCacheA8, texture); + } + self.texture_resolver.end_pass( cur_alpha, cur_color, - RenderPassIndex(pass_index), ); - - // After completing the first pass, make the A8 target available as an - // input to any subsequent passes. - if pass_index == 0 { - if let Some(shared_alpha_texture) = - self.texture_resolver.resolve(&SourceTexture::CacheA8) - { - self.device - .bind_texture(TextureSampler::SharedCacheA8, shared_alpha_texture); - } - } } - self.texture_resolver.end_frame(RenderPassIndex(frame.passes.len())); + self.texture_resolver.end_frame(); if let Some(framebuffer_size) = framebuffer_size { self.draw_render_target_debug(framebuffer_size); self.draw_texture_cache_debug(framebuffer_size); @@ -4750,6 +4740,7 @@ impl Renderer { self.brush_line.deinit(&mut self.device); self.brush_blend.deinit(&mut self.device); self.brush_mix_blend.deinit(&mut self.device); + self.brush_radial_gradient.deinit(&mut self.device); self.cs_clip_rectangle.deinit(&mut self.device); self.cs_clip_image.deinit(&mut self.device); self.cs_clip_border.deinit(&mut self.device); @@ -4765,7 +4756,7 @@ impl Renderer { shader.deinit(&mut self.device); } } - for shader in self.ps_yuv_image { + for shader in self.brush_yuv_image { if let Some(shader) = shader { shader.deinit(&mut self.device); } @@ -4777,7 +4768,6 @@ impl Renderer { self.ps_border_edge.deinit(&mut self.device); self.ps_gradient.deinit(&mut self.device); self.ps_angle_gradient.deinit(&mut self.device); - self.ps_radial_gradient.deinit(&mut self.device); self.ps_hw_composite.deinit(&mut self.device); self.ps_split_composite.deinit(&mut self.device); #[cfg(feature = "capture")] diff --git a/gfx/webrender/src/scene.rs b/gfx/webrender/src/scene.rs index 01e0718583f8..80eec2d4d350 100644 --- a/gfx/webrender/src/scene.rs +++ b/gfx/webrender/src/scene.rs @@ -197,10 +197,11 @@ impl FilterOpHelpers for FilterOp { offset.x == 0.0 && offset.y == 0.0 && blur == 0.0 }, FilterOp::ColorMatrix(matrix) => { - matrix == [1.0, 0.0, 0.0, 0.0, 0.0, - 0.0, 1.0, 0.0, 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, 0.0, - 0.0, 0.0, 0.0, 1.0, 0.0] + matrix == [1.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0, + 0.0, 0.0, 0.0, 0.0] } } } diff --git a/gfx/webrender/src/tiling.rs b/gfx/webrender/src/tiling.rs index d10aa6588a9a..e538f3311a7c 100644 --- a/gfx/webrender/src/tiling.rs +++ b/gfx/webrender/src/tiling.rs @@ -11,10 +11,10 @@ use clip::{ClipStore}; use clip_scroll_tree::{ClipScrollTree}; use device::{FrameId, Texture}; use gpu_cache::{GpuCache}; -use gpu_types::{BlurDirection, BlurInstance, BrushInstance, ClipChainRectIndex}; +use gpu_types::{BlurDirection, BlurInstance, BrushFlags, BrushInstance, ClipChainRectIndex}; use gpu_types::{ClipScrollNodeData, ClipScrollNodeIndex}; use gpu_types::{PrimitiveInstance}; -use internal_types::{FastHashMap, RenderPassIndex, SourceTexture}; +use internal_types::{FastHashMap, SavedTargetIndex, SourceTexture}; use picture::{PictureKind}; use prim_store::{PrimitiveIndex, PrimitiveKind, PrimitiveStore}; use prim_store::{BrushMaskKind, BrushKind, DeferredResolve, EdgeAaSegmentMask}; @@ -137,8 +137,8 @@ pub struct RenderTargetList { pub format: ImageFormat, pub max_size: DeviceUintSize, pub targets: Vec, - #[cfg_attr(feature = "serde", serde(skip))] - pub texture: Option, + pub saved_index: Option, + pub is_shared: bool, } impl RenderTargetList { @@ -151,7 +151,8 @@ impl RenderTargetList { format, max_size: DeviceUintSize::new(MIN_TARGET_SIZE, MIN_TARGET_SIZE), targets: Vec::new(), - texture: None, + saved_index: None, + is_shared: false, } } @@ -161,7 +162,11 @@ impl RenderTargetList { gpu_cache: &mut GpuCache, render_tasks: &mut RenderTaskTree, deferred_resolves: &mut Vec, + saved_index: Option, ) { + debug_assert_eq!(None, self.saved_index); + self.saved_index = saved_index; + for target in &mut self.targets { target.build(ctx, gpu_cache, render_tasks, deferred_resolves); } @@ -214,20 +219,13 @@ impl RenderTargetList { self.targets.iter().any(|target| target.needs_depth()) } - pub fn check_ready(&self) { - match self.texture { - Some(ref t) => { - assert_eq!(t.get_dimensions(), self.max_size); - assert_eq!(t.get_format(), self.format); - assert_eq!(t.get_render_target_layer_count(), self.targets.len()); - assert_eq!(t.get_layer_count() as usize, self.targets.len()); - assert_eq!(t.has_depth(), t.get_rt_info().unwrap().has_depth); - assert_eq!(t.has_depth(), self.needs_depth()); - } - None => { - assert!(self.targets.is_empty()) - } - } + pub fn check_ready(&self, t: &Texture) { + assert_eq!(t.get_dimensions(), self.max_size); + assert_eq!(t.get_format(), self.format); + assert_eq!(t.get_render_target_layer_count(), self.targets.len()); + assert_eq!(t.get_layer_count() as usize, self.targets.len()); + assert_eq!(t.has_depth(), t.get_rt_info().unwrap().has_depth); + assert_eq!(t.has_depth(), self.needs_depth()); } } @@ -589,6 +587,7 @@ impl RenderTarget for AlphaRenderTarget { clip_task_address: RenderTaskAddress(0), z: 0, segment_index: 0, + brush_flags: BrushFlags::PERSPECTIVE_INTERPOLATION, edge_flags: EdgeAaSegmentMask::empty(), user_data: [0; 3], }; @@ -598,6 +597,8 @@ impl RenderTarget for AlphaRenderTarget { BrushKind::Clear | BrushKind::Picture | BrushKind::Line { .. } | + BrushKind::YuvImage { .. } | + BrushKind::RadialGradient { .. } | BrushKind::Image { .. } => { unreachable!("bug: unexpected brush here"); } @@ -784,7 +785,6 @@ impl RenderPass { render_tasks: &mut RenderTaskTree, deferred_resolves: &mut Vec, clip_store: &ClipStore, - pass_index: RenderPassIndex, ) { profile_scope!("RenderPass::build"); @@ -792,7 +792,6 @@ impl RenderPass { RenderPassKind::MainFramebuffer(ref mut target) => { for &task_id in &self.tasks { assert_eq!(render_tasks[task_id].target_kind(), RenderTargetKind::Color); - render_tasks[task_id].pass_index = Some(pass_index); target.add_task( task_id, ctx, @@ -805,16 +804,38 @@ impl RenderPass { target.build(ctx, gpu_cache, render_tasks, deferred_resolves); } RenderPassKind::OffScreen { ref mut color, ref mut alpha, ref mut texture_cache } => { + let is_shared_alpha = self.tasks.iter().any(|&task_id| { + match render_tasks[task_id].kind { + RenderTaskKind::CacheMask(..) => true, + _ => false, + } + }); + let saved_color = if self.tasks.iter().any(|&task_id| { + let t = &render_tasks[task_id]; + t.target_kind() == RenderTargetKind::Color && t.saved_index.is_some() + }) { + Some(render_tasks.save_target()) + } else { + None + }; + let saved_alpha = if self.tasks.iter().any(|&task_id| { + let t = &render_tasks[task_id]; + t.target_kind() == RenderTargetKind::Alpha && t.saved_index.is_some() + }) { + Some(render_tasks.save_target()) + } else { + None + }; + // Step through each task, adding to batches as appropriate. for &task_id in &self.tasks { let (target_kind, texture_target) = { let task = &mut render_tasks[task_id]; - task.pass_index = Some(pass_index); let target_kind = task.target_kind(); // Find a target to assign this task to, or create a new // one if required. - match task.location { + let (target_kind, texture_target) = match task.location { RenderTaskLocation::TextureCache(texture_id, layer, _) => { // TODO(gw): When we support caching color items, we will // need to calculate that here to get the @@ -834,7 +855,18 @@ impl RenderPass { (target_kind, None) } + }; + + // Replace the pending saved index with a real one + if let Some(index) = task.saved_index { + assert_eq!(index, SavedTargetIndex::PENDING); + task.saved_index = match target_kind { + RenderTargetKind::Color => saved_color, + RenderTargetKind::Alpha => saved_alpha, + }; } + + (target_kind, texture_target) }; match texture_target { @@ -869,8 +901,9 @@ impl RenderPass { } } - color.build(ctx, gpu_cache, render_tasks, deferred_resolves); - alpha.build(ctx, gpu_cache, render_tasks, deferred_resolves); + color.build(ctx, gpu_cache, render_tasks, deferred_resolves, saved_color); + alpha.build(ctx, gpu_cache, render_tasks, deferred_resolves, saved_alpha); + alpha.is_shared = is_shared_alpha; } } } diff --git a/gfx/webrender/tests/angle_shader_validation.rs b/gfx/webrender/tests/angle_shader_validation.rs index 367179073555..00e4e719902c 100644 --- a/gfx/webrender/tests/angle_shader_validation.rs +++ b/gfx/webrender/tests/angle_shader_validation.rs @@ -62,10 +62,6 @@ const SHADERS: &[Shader] = &[ name: "ps_angle_gradient", features: PRIM_FEATURES, }, - Shader { - name: "ps_radial_gradient", - features: PRIM_FEATURES, - }, Shader { name: "ps_hardware_composite", features: PRIM_FEATURES, @@ -78,15 +74,15 @@ const SHADERS: &[Shader] = &[ name: "ps_image", features: PRIM_FEATURES, }, - Shader { - name: "ps_yuv_image", - features: PRIM_FEATURES, - }, Shader { name: "ps_text_run", features: PRIM_FEATURES, }, // Brush shaders + Shader { + name: "brush_yuv_image", + features: &["", "YUV_NV12", "YUV_PLANAR", "YUV_INTERLEAVED"], + }, Shader { name: "brush_mask", features: &[], @@ -111,6 +107,10 @@ const SHADERS: &[Shader] = &[ name: "brush_line", features: &[], }, + Shader { + name: "brush_radial_gradient", + features: &[], + }, ]; const VERSION_STRING: &str = "#version 300 es\n"; diff --git a/gfx/webrender_api/src/api.rs b/gfx/webrender_api/src/api.rs index 208d24570662..86b1eb5403ee 100644 --- a/gfx/webrender_api/src/api.rs +++ b/gfx/webrender_api/src/api.rs @@ -9,7 +9,7 @@ use std::fmt; use std::marker::PhantomData; use std::path::PathBuf; use std::u32; -use {BuiltDisplayList, BuiltDisplayListDescriptor, ClipId, ColorF, DeviceIntPoint, DeviceUintRect}; +use {BuiltDisplayList, BuiltDisplayListDescriptor, ColorF, DeviceIntPoint, DeviceUintRect}; use {DeviceUintSize, ExternalScrollId, FontInstanceKey, FontInstanceOptions}; use {FontInstancePlatformOptions, FontKey, FontVariation, GlyphDimensions, GlyphKey, ImageData}; use {ImageDescriptor, ImageKey, ItemTag, LayoutPoint, LayoutSize, LayoutTransform, LayoutVector2D}; @@ -254,7 +254,7 @@ impl Transaction { pub fn scroll_node_with_id( &mut self, origin: LayoutPoint, - id: ScrollNodeIdType, + id: ExternalScrollId, clamp: ScrollClamping, ) { self.ops.push(DocumentMsg::ScrollNodeWithId(origin, id, clamp)); @@ -384,37 +384,13 @@ pub enum DocumentMsg { device_pixel_ratio: f32, }, Scroll(ScrollLocation, WorldPoint, ScrollEventPhase), - ScrollNodeWithId(LayoutPoint, ScrollNodeIdType, ScrollClamping), + ScrollNodeWithId(LayoutPoint, ExternalScrollId, ScrollClamping), TickScrollingBounce, GetScrollNodeState(MsgSender>), GenerateFrame, UpdateDynamicProperties(DynamicProperties), } -#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] -pub enum ScrollNodeIdType { - ExternalScrollId(ExternalScrollId), - ClipId(ClipId), -} - -impl From for ScrollNodeIdType { - fn from(id: ExternalScrollId) -> Self { - ScrollNodeIdType::ExternalScrollId(id) - } -} - -impl From for ScrollNodeIdType { - fn from(id: ClipId) -> Self { - ScrollNodeIdType::ClipId(id) - } -} - -impl<'a> From<&'a ClipId> for ScrollNodeIdType { - fn from(id: &'a ClipId) -> Self { - ScrollNodeIdType::ClipId(*id) - } -} - impl fmt::Debug for DocumentMsg { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(match *self { diff --git a/gfx/webrender_api/src/display_item.rs b/gfx/webrender_api/src/display_item.rs index 31a17ef13ccd..3ef67afaf6cb 100644 --- a/gfx/webrender_api/src/display_item.rs +++ b/gfx/webrender_api/src/display_item.rs @@ -601,9 +601,9 @@ impl YuvFormat { pub fn get_feature_string(&self) -> &'static str { match *self { - YuvFormat::NV12 => "NV12", - YuvFormat::PlanarYCbCr => "", - YuvFormat::InterleavedYCbCr => "INTERLEAVED_Y_CB_CR", + YuvFormat::NV12 => "YUV_NV12", + YuvFormat::PlanarYCbCr => "YUV_PLANAR", + YuvFormat::InterleavedYCbCr => "YUV_INTERLEAVED", } } } @@ -649,6 +649,22 @@ impl LocalClip { ), } } + + pub fn clip_by(&self, rect: &LayoutRect) -> LocalClip { + match *self { + LocalClip::Rect(clip_rect) => { + LocalClip::Rect( + clip_rect.intersection(rect).unwrap_or(LayoutRect::zero()) + ) + } + LocalClip::RoundedRect(clip_rect, complex) => { + LocalClip::RoundedRect( + clip_rect.intersection(rect).unwrap_or(LayoutRect::zero()), + complex, + ) + } + } + } } #[repr(C)] diff --git a/gfx/webrender_bindings/Cargo.toml b/gfx/webrender_bindings/Cargo.toml index 7a666fe37c19..4ba1a423ee4a 100644 --- a/gfx/webrender_bindings/Cargo.toml +++ b/gfx/webrender_bindings/Cargo.toml @@ -5,7 +5,7 @@ authors = ["The Mozilla Project Developers"] license = "MPL-2.0" [dependencies] -rayon = "0.8" +rayon = "1" thread_profiler = "0.1.1" euclid = "0.16" app_units = "0.6" diff --git a/gfx/webrender_bindings/revision.txt b/gfx/webrender_bindings/revision.txt index 255b4a1c3dff..e26cd1e1f422 100644 --- a/gfx/webrender_bindings/revision.txt +++ b/gfx/webrender_bindings/revision.txt @@ -1 +1 @@ -4af31b8aa79d5a1f3c0242dea6be4876c71075c5 +e8d2ffb404a85651fe08a6d09abbece9bd2b9182 diff --git a/gfx/wrench/src/wrench.rs b/gfx/wrench/src/wrench.rs index c1abb791ac55..d629ada01a2e 100644 --- a/gfx/wrench/src/wrench.rs +++ b/gfx/wrench/src/wrench.rs @@ -502,7 +502,7 @@ impl Wrench { &mut self, frame_number: u32, display_lists: Vec<(PipelineId, LayerSize, BuiltDisplayList)>, - scroll_offsets: &HashMap, + scroll_offsets: &HashMap, ) { let root_background_color = Some(ColorF::new(1.0, 1.0, 1.0, 1.0)); @@ -523,7 +523,7 @@ impl Wrench { let mut txn = Transaction::new(); for (id, offset) in scroll_offsets { - txn.scroll_node_with_id(*offset, id.into(), ScrollClamping::NoClamping); + txn.scroll_node_with_id(*offset, *id, ScrollClamping::NoClamping); } // TODO(nical) - Wrench does not notify frames when there was scrolling // in the transaction (See RenderNotifier implementations). If we don't diff --git a/gfx/wrench/src/yaml_frame_reader.rs b/gfx/wrench/src/yaml_frame_reader.rs index 895f3cf47b22..cd6c095b82c0 100644 --- a/gfx/wrench/src/yaml_frame_reader.rs +++ b/gfx/wrench/src/yaml_frame_reader.rs @@ -193,7 +193,7 @@ pub struct YamlFrameReader { /// A HashMap of offsets which specify what scroll offsets particular /// scroll layers should be initialized with. - scroll_offsets: HashMap, + scroll_offsets: HashMap, image_map: HashMap<(PathBuf, Option), (ImageKey, LayoutSize)>, @@ -1273,7 +1273,12 @@ impl YamlFrameReader { wrench: &mut Wrench, yaml: &Yaml, ) { - let full_clip = LayoutRect::new(LayoutPoint::zero(), wrench.window_size_f32()); + // A very large number (but safely far away from finite limits of f32) + let big_number = 1.0e30; + // A rect that should in practical terms serve as a no-op for clipping + let full_clip = LayoutRect::new( + LayoutPoint::new(-big_number / 2.0, -big_number / 2.0), + LayoutSize::new(big_number, big_number)); for item in yaml.as_vec().unwrap() { // an explicit type can be skipped with some shorthand @@ -1362,7 +1367,12 @@ impl YamlFrameReader { let complex_clips = self.to_complex_clip_regions(&yaml["complex"]); let image_mask = self.to_image_mask(&yaml["image-mask"], wrench); - let external_id = numeric_id.map(|id| ExternalScrollId(id as u64, dl.pipeline_id)); + let external_id = yaml["scroll-offset"].as_point().map(|size| { + let id = ExternalScrollId((self.scroll_offsets.len() + 1) as u64, dl.pipeline_id); + self.scroll_offsets.insert(id, LayerPoint::new(size.x, size.y)); + id + }); + let real_id = dl.define_scroll_frame( external_id, content_rect, @@ -1375,10 +1385,6 @@ impl YamlFrameReader { self.clip_id_map.insert(numeric_id, real_id); } - if let Some(size) = yaml["scroll-offset"].as_point() { - self.scroll_offsets.insert(real_id, LayerPoint::new(size.x, size.y)); - } - if !yaml["items"].is_badvalue() { dl.push_clip_id(real_id); self.add_display_list_items_from_yaml(dl, wrench, &yaml["items"]); @@ -1542,9 +1548,8 @@ impl YamlFrameReader { if is_root { if let Some(size) = yaml["scroll-offset"].as_point() { - let id = ClipId::root_scroll_node(dl.pipeline_id); - self.scroll_offsets - .insert(id, LayerPoint::new(size.x, size.y)); + let external_id = ExternalScrollId(0, dl.pipeline_id); + self.scroll_offsets.insert(external_id, LayerPoint::new(size.x, size.y)); } }