From 4254b805d39e8f3812b41733c1a8bacf935eea39 Mon Sep 17 00:00:00 2001 From: Bert Peers Date: Fri, 3 Apr 2020 14:08:27 +0000 Subject: [PATCH 1/3] Bug 1624468 - Add a fast path for more gradient types in WR r=gw Differential Revision: https://phabricator.services.mozilla.com/D68945 [ghsync] From https://hg.mozilla.org/mozilla-central/rev/dfa94a886779bb2f33e436c0a2f4fb20313c98e8 --- webrender/src/batch.rs | 98 ++++++----- webrender/src/prim_store/gradient.rs | 22 +-- webrender/src/prim_store/mod.rs | 152 ++++++++++++++---- .../gradient/gradient_cache_5stops.yaml | 13 ++ .../gradient/gradient_cache_5stops_ref.yaml | 18 +++ .../gradient_cache_5stops_vertical.yaml | 13 ++ .../gradient_cache_5stops_vertical_ref.yaml | 18 +++ .../gradient/gradient_cache_clamp.yaml | 20 +++ .../gradient/gradient_cache_clamp_ref.yaml | 30 ++++ .../gradient/gradient_cache_hardstop.yaml | 19 +++ .../gradient_cache_hardstop_clip.yaml | 21 +++ .../gradient_cache_hardstop_clip_ref.yaml | 28 ++++ .../gradient/gradient_cache_hardstop_ref.yaml | 24 +++ wrench/reftests/gradient/reftest.list | 11 +- 14 files changed, 399 insertions(+), 88 deletions(-) create mode 100644 wrench/reftests/gradient/gradient_cache_5stops.yaml create mode 100644 wrench/reftests/gradient/gradient_cache_5stops_ref.yaml create mode 100644 wrench/reftests/gradient/gradient_cache_5stops_vertical.yaml create mode 100644 wrench/reftests/gradient/gradient_cache_5stops_vertical_ref.yaml create mode 100644 wrench/reftests/gradient/gradient_cache_clamp.yaml create mode 100644 wrench/reftests/gradient/gradient_cache_clamp_ref.yaml create mode 100644 wrench/reftests/gradient/gradient_cache_hardstop.yaml create mode 100644 wrench/reftests/gradient/gradient_cache_hardstop_clip.yaml create mode 100644 wrench/reftests/gradient/gradient_cache_hardstop_clip_ref.yaml create mode 100644 wrench/reftests/gradient/gradient_cache_hardstop_ref.yaml diff --git a/webrender/src/batch.rs b/webrender/src/batch.rs index cfa766029e..54635b1e45 100644 --- a/webrender/src/batch.rs +++ b/webrender/src/batch.rs @@ -2268,53 +2268,69 @@ impl BatchBuilder { BlendMode::None }; - if let Some(ref cache_handle) = gradient.cache_handle { - let rt_cache_entry = ctx.resource_cache - .get_cached_render_task(cache_handle); - let cache_item = ctx.resource_cache - .get_texture_cache_item(&rt_cache_entry.handle); + if !gradient.cache_segments.is_empty() { - if cache_item.texture_id == TextureSource::Invalid { - return; - } + for segment in &gradient.cache_segments { + let ref cache_handle = segment.handle; + let rt_cache_entry = ctx.resource_cache + .get_cached_render_task(cache_handle); + let cache_item = ctx.resource_cache + .get_texture_cache_item(&rt_cache_entry.handle); - let textures = BatchTextures::color(cache_item.texture_id); - let batch_kind = BrushBatchKind::Image(get_buffer_kind(cache_item.texture_id)); - let prim_user_data = ImageBrushData { - color_mode: ShaderColorMode::Image, - alpha_type: AlphaType::PremultipliedAlpha, - raster_space: RasterizationSpace::Local, - opacity: 1.0, - }.encode(); + if cache_item.texture_id == TextureSource::Invalid { + return; + } - let specific_resource_address = cache_item.uv_rect_handle.as_int(gpu_cache); - prim_header.specific_prim_address = gpu_cache.get_address(&ctx.globals.default_image_handle); + let textures = BatchTextures::color(cache_item.texture_id); + let batch_kind = BrushBatchKind::Image(get_buffer_kind(cache_item.texture_id)); + let prim_user_data = ImageBrushData { + color_mode: ShaderColorMode::Image, + alpha_type: AlphaType::PremultipliedAlpha, + raster_space: RasterizationSpace::Local, + opacity: 1.0, + }.encode(); + + let specific_resource_address = cache_item.uv_rect_handle.as_int(gpu_cache); + prim_header.specific_prim_address = gpu_cache.get_address(&ctx.globals.default_image_handle); + + let segment_local_clip_rect = prim_header.local_clip_rect.intersection(&segment.local_rect); + if segment_local_clip_rect.is_none() { + continue; + } - let prim_header_index = prim_headers.push( - &prim_header, - z_id, - prim_user_data, - ); + let segment_prim_header = PrimitiveHeader { + local_rect: segment.local_rect, + local_clip_rect: segment_local_clip_rect.unwrap(), + specific_prim_address: prim_header.specific_prim_address, + transform_id: prim_header.transform_id, + }; - let batch_key = BatchKey { - blend_mode: non_segmented_blend_mode, - kind: BatchKind::Brush(batch_kind), - textures, - }; + let prim_header_index = prim_headers.push( + &segment_prim_header, + z_id, + prim_user_data, + ); - self.add_brush_instance_to_batches( - batch_key, - batch_features, - bounding_rect, - z_id, - INVALID_SEGMENT_INDEX, - EdgeAaSegmentMask::all(), - clip_task_address.unwrap(), - BrushFlags::PERSPECTIVE_INTERPOLATION, - prim_header_index, - specific_resource_address, - prim_vis_mask, - ); + let batch_key = BatchKey { + blend_mode: non_segmented_blend_mode, + kind: BatchKind::Brush(batch_kind), + textures, + }; + + self.add_brush_instance_to_batches( + batch_key, + batch_features, + bounding_rect, + z_id, + INVALID_SEGMENT_INDEX, + EdgeAaSegmentMask::all(), + clip_task_address.unwrap(), + BrushFlags::PERSPECTIVE_INTERPOLATION, + prim_header_index, + specific_resource_address, + prim_vis_mask, + ); + } } else if gradient.visible_tiles_range.is_empty() { let batch_params = BrushBatchParameters::shared( BrushBatchKind::LinearGradient, diff --git a/webrender/src/prim_store/gradient.rs b/webrender/src/prim_store/gradient.rs index b8d59c8030..9e2c27be55 100644 --- a/webrender/src/prim_store/gradient.rs +++ b/webrender/src/prim_store/gradient.rs @@ -13,11 +13,10 @@ use crate::frame_builder::FrameBuildingState; use crate::gpu_cache::{GpuCacheHandle, GpuDataRequest}; use crate::intern::{Internable, InternDebug, Handle as InternHandle}; use crate::internal_types::LayoutPrimitiveInfo; -use crate::prim_store::{BrushSegment, GradientTileRange, VectorKey}; +use crate::prim_store::{BrushSegment, CachedGradientSegment, GradientTileRange, VectorKey}; use crate::prim_store::{PrimitiveInstanceKind, PrimitiveOpacity, PrimitiveSceneData}; use crate::prim_store::{PrimKeyCommonData, PrimTemplateCommonData, PrimitiveStore}; use crate::prim_store::{NinePatchDescriptor, PointKey, SizeKey, InternablePrimitive}; -use crate::render_task_cache::RenderTaskCacheEntryHandle; use std::{hash, ops::{Deref, DerefMut}}; use crate::util::pack_as_float; @@ -152,7 +151,7 @@ impl From for LinearGradientTemplate { // gradient in a smaller task, and drawing as an image. // TODO(gw): Aim to reduce the constraints on fast path gradients in future, // although this catches the vast majority of gradients on real pages. - let mut supports_caching = + let supports_caching = // No repeating support in fast path item.extend_mode == ExtendMode::Clamp && // Gradient must cover entire primitive @@ -161,28 +160,15 @@ impl From for LinearGradientTemplate { // Must be a vertical or horizontal gradient (item.start_point.x.approx_eq(&item.end_point.x) || item.start_point.y.approx_eq(&item.end_point.y)) && - // Fast path supports a limited number of stops - item.stops.len() <= GRADIENT_FP_STOPS && // Fast path not supported on segmented (border-image) gradients. item.nine_patch.is_none(); - let mut prev_offset = None; // Convert the stops to more convenient representation // for the current gradient builder. let stops: Vec = item.stops.iter().map(|stop| { let color: ColorF = stop.color.into(); min_alpha = min_alpha.min(color.a); - // The fast path doesn't support hard color stops, yet. - // Since the length of the gradient is a fixed size (512 device pixels), if there - // is a hard stop you will see bilinear interpolation with this method, instead - // of an abrupt color change. - if prev_offset == Some(stop.offset) { - supports_caching = false; - } - - prev_offset = Some(stop.offset); - GradientStop { offset: stop.offset, color, @@ -318,7 +304,7 @@ impl InternablePrimitive for LinearGradient { _reference_frame_relative_offset: LayoutVector2D, ) -> PrimitiveInstanceKind { let gradient_index = prim_store.linear_gradients.push(LinearGradientPrimitive { - cache_handle: None, + cache_segments: Vec::new(), visible_tiles_range: GradientTileRange::empty(), }); @@ -338,7 +324,7 @@ impl IsVisible for LinearGradient { #[derive(Debug)] #[cfg_attr(feature = "capture", derive(Serialize))] pub struct LinearGradientPrimitive { - pub cache_handle: Option, + pub cache_segments: Vec, pub visible_tiles_range: GradientTileRange, } diff --git a/webrender/src/prim_store/mod.rs b/webrender/src/prim_store/mod.rs index c9c16df149..82d17aa441 100644 --- a/webrender/src/prim_store/mod.rs +++ b/webrender/src/prim_store/mod.rs @@ -970,6 +970,13 @@ pub struct VisibleGradientTile { pub local_clip_rect: LayoutRect, } +#[derive(Debug)] +#[cfg_attr(feature = "capture", derive(Serialize))] +pub struct CachedGradientSegment { + pub handle: RenderTaskCacheEntryHandle, + pub local_rect: LayoutRect, +} + /// Information about how to cache a border segment, /// along with the current render task cache entry. #[cfg_attr(feature = "capture", derive(Serialize))] @@ -3284,7 +3291,7 @@ impl PrimitiveStore { }; // Build the cache key, including information about the stops. - let mut stops = [GradientStopKey::empty(); GRADIENT_FP_STOPS]; + let mut stops = vec![GradientStopKey::empty(); prim_data.stops.len()]; // Reverse the stops as required, same as the gradient builder does // for the slow path. @@ -3302,35 +3309,124 @@ impl PrimitiveStore { } } - let cache_key = GradientCacheKey { - orientation, - start_stop_point: VectorKey { - x: start_point, - y: end_point, - }, - stops, - }; + // To support clamping, we need to make sure that quads are emitted for the + // segments before and after the 0.0...1.0 range of offsets. The loop below + // can handle that by duplicating the first and last point if necessary: + if start_point < 0.0 { + stops.insert(0, GradientStopKey { + offset: start_point, + color : stops[0].color + }); + } - // Request the render task each frame. - gradient.cache_handle = Some(frame_state.resource_cache.request_render_task( - RenderTaskCacheKey { - size, - kind: RenderTaskCacheKeyKind::Gradient(cache_key), - }, - frame_state.gpu_cache, - frame_state.render_tasks, - None, - prim_data.stops_opacity.is_opaque, - |render_tasks| { - render_tasks.add().init(RenderTask::new_gradient( - size, - stops, - orientation, - start_point, - end_point, - )) + if end_point > 1.0 { + stops.push( GradientStopKey { + offset: end_point, + color : stops[stops.len()-1].color + }); + } + + gradient.cache_segments.clear(); + + let mut first_stop = 0; + // look for an inclusive range of stops [first_stop, last_stop]. + // once first_stop points at (or past) the last stop, we're done. + while first_stop < stops.len()-1 { + + // if the entire segment starts at an offset that's past the primitive's + // end_point, we're done. + if stops[first_stop].offset > end_point { + break; } - )); + + // accumulate stops until we have GRADIENT_FP_STOPS of them, or we hit + // a hard stop: + let mut last_stop = first_stop; + let mut hard_stop = false; // did we stop on a hard stop? + while last_stop < stops.len()-1 && + last_stop - first_stop + 1 < GRADIENT_FP_STOPS + { + if stops[last_stop+1].offset == stops[last_stop].offset { + hard_stop = true; + break; + } + + last_stop = last_stop + 1; + } + + let num_stops = last_stop - first_stop + 1; + + // repeated hard stops at the same offset, skip + if num_stops == 0 { + first_stop = last_stop + 1; + continue; + } + + // if the last stop offset is before start_point, the segment's not visible: + if stops[last_stop].offset < start_point { + first_stop = if hard_stop { last_stop+1 } else { last_stop }; + continue; + } + + let segment_start_point = start_point.max(stops[first_stop].offset); + let segment_end_point = end_point .min(stops[last_stop ].offset); + + let mut segment_stops = [GradientStopKey::empty(); GRADIENT_FP_STOPS]; + for i in 0..num_stops { + segment_stops[i] = stops[first_stop + i]; + } + + let cache_key = GradientCacheKey { + orientation, + start_stop_point: VectorKey { + x: segment_start_point, + y: segment_end_point, + }, + stops: segment_stops, + }; + + let mut prim_origin = prim_instance.prim_origin; + let mut prim_size = prim_data.common.prim_size; + + let inv_length = 1.0 / ( end_point - start_point ); + if orientation == LineOrientation::Horizontal { + prim_origin.x += ( segment_start_point - start_point ) * inv_length * prim_size.width; + prim_size.width *= ( segment_end_point - segment_start_point ) * inv_length; + } else { + prim_origin.y += ( segment_start_point - start_point ) * inv_length * prim_size.height; + prim_size.height *= ( segment_end_point - segment_start_point ) * inv_length; + } + + let local_rect = LayoutRect::new( prim_origin, prim_size ); + + // Request the render task each frame. + gradient.cache_segments.push( + CachedGradientSegment { + handle: frame_state.resource_cache.request_render_task( + RenderTaskCacheKey { + size, + kind: RenderTaskCacheKeyKind::Gradient(cache_key), + }, + frame_state.gpu_cache, + frame_state.render_tasks, + None, + prim_data.stops_opacity.is_opaque, + |render_tasks| { + render_tasks.add().init(RenderTask::new_gradient( + size, + segment_stops, + orientation, + segment_start_point, + segment_end_point, + )) + }), + local_rect: local_rect, + } + ); + + // if ending on a hardstop, skip past it for the start of the next run: + first_stop = if hard_stop { last_stop + 1 } else { last_stop }; + } } if prim_data.tile_spacing != LayoutSize::zero() { diff --git a/wrench/reftests/gradient/gradient_cache_5stops.yaml b/wrench/reftests/gradient/gradient_cache_5stops.yaml new file mode 100644 index 0000000000..d448723002 --- /dev/null +++ b/wrench/reftests/gradient/gradient_cache_5stops.yaml @@ -0,0 +1,13 @@ +--- +root: + items: + - type: gradient + bounds: 0 0 960 540 + start: 0 0 + end: 960 0 + stops: [0.0, red, + 0.25, green, + 0.5, blue, + 0.75, [40,40,40,1], + 1.0, [100,200,50,1]] + diff --git a/wrench/reftests/gradient/gradient_cache_5stops_ref.yaml b/wrench/reftests/gradient/gradient_cache_5stops_ref.yaml new file mode 100644 index 0000000000..34b6b0e01c --- /dev/null +++ b/wrench/reftests/gradient/gradient_cache_5stops_ref.yaml @@ -0,0 +1,18 @@ +--- +root: + items: + - type: gradient + bounds: 0 0 480 540 + start: 0 0 + end: 480 0 + stops: [0.0, red, + 0.5, green, + 1.0, blue] + - type: gradient + bounds: 480 0 480 540 + start: 0 0 + end: 480 0 + stops: [ 0.0, blue, + 0.5, [40,40,40,1], + 1.0, [100,200,50,1]] + diff --git a/wrench/reftests/gradient/gradient_cache_5stops_vertical.yaml b/wrench/reftests/gradient/gradient_cache_5stops_vertical.yaml new file mode 100644 index 0000000000..dd2c8b7c9d --- /dev/null +++ b/wrench/reftests/gradient/gradient_cache_5stops_vertical.yaml @@ -0,0 +1,13 @@ +--- +root: + items: + - type: gradient + bounds: 0 0 960 540 + start: 0 0 + end: 0 540 + stops: [0.0, red, + 0.25, green, + 0.5, blue, + 0.75, [40,40,40,1], + 1.0, [100,200,50,1]] + diff --git a/wrench/reftests/gradient/gradient_cache_5stops_vertical_ref.yaml b/wrench/reftests/gradient/gradient_cache_5stops_vertical_ref.yaml new file mode 100644 index 0000000000..704b5be2f6 --- /dev/null +++ b/wrench/reftests/gradient/gradient_cache_5stops_vertical_ref.yaml @@ -0,0 +1,18 @@ +--- +root: + items: + - type: gradient + bounds: 0 0 960 270 + start: 0 0 + end: 0 270 + stops: [0.0, red, + 0.5, green, + 1.0, blue] + - type: gradient + bounds: 0 270 960 270 + start: 0 0 + end: 0 270 + stops: [ 0.0, blue, + 0.5, [40,40,40,1], + 1.0, [100,200,50,1]] + diff --git a/wrench/reftests/gradient/gradient_cache_clamp.yaml b/wrench/reftests/gradient/gradient_cache_clamp.yaml new file mode 100644 index 0000000000..1c55a269a1 --- /dev/null +++ b/wrench/reftests/gradient/gradient_cache_clamp.yaml @@ -0,0 +1,20 @@ +--- +root: + items: + - type: gradient + bounds: 0 0 400 200 + start: 0 100 + end: 100 100 + stops: [0.0, blue, 1.0, blue, 1.0, red] + - type: gradient + bounds: 0 300 400 200 + start: 100 100 + end: 200 100 + stops: [0.0, blue, 1.0, blue, 1.0, red] + - type: gradient + bounds: 0 600 200 400 + start: 0 100 + end: 0 300 + stops: [ + 0.0, blue, + 1.0, red] diff --git a/wrench/reftests/gradient/gradient_cache_clamp_ref.yaml b/wrench/reftests/gradient/gradient_cache_clamp_ref.yaml new file mode 100644 index 0000000000..4631192cd8 --- /dev/null +++ b/wrench/reftests/gradient/gradient_cache_clamp_ref.yaml @@ -0,0 +1,30 @@ +--- +root: + items: + - type: gradient + bounds: 0 0 400 200 + start: 0 100 + end: 400 100 + stops: [ + 0.0, blue, + 0.25, blue, + 0.25, red, + 1.0, red] + - type: gradient + bounds: 0 300 400 200 + start: 0 100 + end: 400 100 + stops: [ + 0.0, blue, + 0.5, blue, + 0.5, red, + 1.0, red] + - type: gradient + bounds: 0 600 200 400 + start: 0 0 + end: 0 400 + stops: [ + 0.0, blue, + 0.25, blue, + 0.75, red, + 1.0, red] diff --git a/wrench/reftests/gradient/gradient_cache_hardstop.yaml b/wrench/reftests/gradient/gradient_cache_hardstop.yaml new file mode 100644 index 0000000000..53c908fb22 --- /dev/null +++ b/wrench/reftests/gradient/gradient_cache_hardstop.yaml @@ -0,0 +1,19 @@ +--- +root: + items: + - type: gradient + bounds: 0 0 960 540 + start: 0 0 + end: 960 0 + stops: [0.0, red, + 0.125, yellow, + 0.25, red, + 0.25, green, + 0.375, yellow, + 0.5, green, + 0.5, blue, + 0.625, yellow, + 0.75, blue, + 0.75, white, + 1.0, [100,200,50,1]] + diff --git a/wrench/reftests/gradient/gradient_cache_hardstop_clip.yaml b/wrench/reftests/gradient/gradient_cache_hardstop_clip.yaml new file mode 100644 index 0000000000..3e7a2e946f --- /dev/null +++ b/wrench/reftests/gradient/gradient_cache_hardstop_clip.yaml @@ -0,0 +1,21 @@ +--- +root: + items: + - type: gradient + bounds: 0 0 960 540 + start: 0 0 + end: 960 0 + stops: [0.0, red, + 0.125, yellow, + 0.25, red, + 0.25, green, + 0.375, yellow, + 0.5, green, + 0.5, blue, + 0.625, yellow, + 0.75, blue, + 0.75, white, + 1.0, [100,200,50,1]] + complex-clip: + rect: [100, 100, 760, 340] + radius: [32, 32] diff --git a/wrench/reftests/gradient/gradient_cache_hardstop_clip_ref.yaml b/wrench/reftests/gradient/gradient_cache_hardstop_clip_ref.yaml new file mode 100644 index 0000000000..2b27c5649c --- /dev/null +++ b/wrench/reftests/gradient/gradient_cache_hardstop_clip_ref.yaml @@ -0,0 +1,28 @@ +--- +root: + items: + - type: gradient + bounds: 0 0 480 540 + start: 0 0 + end: 480 0 + stops: [0.0, red, + 0.25, yellow, + 0.5, red, + 0.5, green, + 0.75, yellow, + 1.0, green] + complex-clip: + rect: [100, 100, 760, 340] + radius: [32, 32] + - type: gradient + bounds: 480 0 480 540 + start: 0 0 + end: 480 0 + stops: [0.0, blue, + 0.25, yellow, + 0.5, blue, + 0.5, white, + 1.0, [100,200,50,1]] + complex-clip: + rect: [100, 100, 760, 340] + radius: [32, 32] diff --git a/wrench/reftests/gradient/gradient_cache_hardstop_ref.yaml b/wrench/reftests/gradient/gradient_cache_hardstop_ref.yaml new file mode 100644 index 0000000000..e4b3928046 --- /dev/null +++ b/wrench/reftests/gradient/gradient_cache_hardstop_ref.yaml @@ -0,0 +1,24 @@ +--- +root: + items: + - type: gradient + bounds: 0 0 480 540 + start: 0 0 + end: 480 0 + stops: [0.0, red, + 0.25, yellow, + 0.5, red, + 0.5, green, + 0.75, yellow, + 1.0, green] + - type: gradient + bounds: 480 0 480 540 + start: 0 0 + end: 480 0 + stops: [0.0, blue, + 0.25, yellow, + 0.5, blue, + 0.5, white, + 1.0, [100,200,50,1]] + + diff --git a/wrench/reftests/gradient/reftest.list b/wrench/reftests/gradient/reftest.list index ac0b6454b4..c3b3eee9cd 100644 --- a/wrench/reftests/gradient/reftest.list +++ b/wrench/reftests/gradient/reftest.list @@ -16,7 +16,7 @@ platform(linux,mac) fuzzy(1,35000) == linear-stops.yaml linear-stops-ref.png == linear-clamp-1b.yaml linear-clamp-1-ref.yaml == linear-clamp-2.yaml linear-clamp-2-ref.yaml -== linear-hard-stop.yaml linear-hard-stop-ref.png +fuzzy-range(<=1,*4800) == linear-hard-stop.yaml linear-hard-stop-ref.png # dithering requires us to fuzz here fuzzy(1,20000) == linear.yaml linear-ref.yaml @@ -85,3 +85,12 @@ fuzzy(255,166) == conic-angle.yaml conic-angle.png fuzzy(1,1) == conic-angle-wraparound.yaml conic-angle.yaml fuzzy(1,1) == conic-angle-wraparound-negative.yaml conic-angle.yaml fuzzy(1,115) == conic-color-wheel.yaml conic-color-wheel.png + +# gradient caching tests +# replaces a computed gradient by a sampled texture, so a lot of off-by-one +# variation from interpolation, which is fine: +fuzzy-range(<=1,*195000) == gradient_cache_5stops.yaml gradient_cache_5stops_ref.yaml +fuzzy-range(<=1,*169000) == gradient_cache_5stops_vertical.yaml gradient_cache_5stops_vertical_ref.yaml +== gradient_cache_hardstop.yaml gradient_cache_hardstop_ref.yaml +== gradient_cache_hardstop_clip.yaml gradient_cache_hardstop_clip_ref.yaml +== gradient_cache_clamp.yaml gradient_cache_clamp_ref.yaml From 5917ecef1e50724bee8fce30a1489bde2dce9aca Mon Sep 17 00:00:00 2001 From: Stefan Hindli Date: Fri, 3 Apr 2020 14:08:35 +0000 Subject: [PATCH 2/3] Backed out changeset dfa94a886779 (bug 1624468) for causing web platform permafailures in /css/css-images/gradient-move-stops.html CLOSED TREE [ghsync] From https://hg.mozilla.org/mozilla-central/rev/92912f17f2b8bf2795d1229bff2caa006bfa85a6 --- webrender/src/batch.rs | 98 +++++------ webrender/src/prim_store/gradient.rs | 22 ++- webrender/src/prim_store/mod.rs | 152 ++++-------------- .../gradient/gradient_cache_5stops.yaml | 13 -- .../gradient/gradient_cache_5stops_ref.yaml | 18 --- .../gradient_cache_5stops_vertical.yaml | 13 -- .../gradient_cache_5stops_vertical_ref.yaml | 18 --- .../gradient/gradient_cache_clamp.yaml | 20 --- .../gradient/gradient_cache_clamp_ref.yaml | 30 ---- .../gradient/gradient_cache_hardstop.yaml | 19 --- .../gradient_cache_hardstop_clip.yaml | 21 --- .../gradient_cache_hardstop_clip_ref.yaml | 28 ---- .../gradient/gradient_cache_hardstop_ref.yaml | 24 --- wrench/reftests/gradient/reftest.list | 11 +- 14 files changed, 88 insertions(+), 399 deletions(-) delete mode 100644 wrench/reftests/gradient/gradient_cache_5stops.yaml delete mode 100644 wrench/reftests/gradient/gradient_cache_5stops_ref.yaml delete mode 100644 wrench/reftests/gradient/gradient_cache_5stops_vertical.yaml delete mode 100644 wrench/reftests/gradient/gradient_cache_5stops_vertical_ref.yaml delete mode 100644 wrench/reftests/gradient/gradient_cache_clamp.yaml delete mode 100644 wrench/reftests/gradient/gradient_cache_clamp_ref.yaml delete mode 100644 wrench/reftests/gradient/gradient_cache_hardstop.yaml delete mode 100644 wrench/reftests/gradient/gradient_cache_hardstop_clip.yaml delete mode 100644 wrench/reftests/gradient/gradient_cache_hardstop_clip_ref.yaml delete mode 100644 wrench/reftests/gradient/gradient_cache_hardstop_ref.yaml diff --git a/webrender/src/batch.rs b/webrender/src/batch.rs index 54635b1e45..cfa766029e 100644 --- a/webrender/src/batch.rs +++ b/webrender/src/batch.rs @@ -2268,69 +2268,53 @@ impl BatchBuilder { BlendMode::None }; - if !gradient.cache_segments.is_empty() { - - for segment in &gradient.cache_segments { - let ref cache_handle = segment.handle; - let rt_cache_entry = ctx.resource_cache - .get_cached_render_task(cache_handle); - let cache_item = ctx.resource_cache - .get_texture_cache_item(&rt_cache_entry.handle); + if let Some(ref cache_handle) = gradient.cache_handle { + let rt_cache_entry = ctx.resource_cache + .get_cached_render_task(cache_handle); + let cache_item = ctx.resource_cache + .get_texture_cache_item(&rt_cache_entry.handle); - if cache_item.texture_id == TextureSource::Invalid { - return; - } + if cache_item.texture_id == TextureSource::Invalid { + return; + } - let textures = BatchTextures::color(cache_item.texture_id); - let batch_kind = BrushBatchKind::Image(get_buffer_kind(cache_item.texture_id)); - let prim_user_data = ImageBrushData { - color_mode: ShaderColorMode::Image, - alpha_type: AlphaType::PremultipliedAlpha, - raster_space: RasterizationSpace::Local, - opacity: 1.0, - }.encode(); - - let specific_resource_address = cache_item.uv_rect_handle.as_int(gpu_cache); - prim_header.specific_prim_address = gpu_cache.get_address(&ctx.globals.default_image_handle); - - let segment_local_clip_rect = prim_header.local_clip_rect.intersection(&segment.local_rect); - if segment_local_clip_rect.is_none() { - continue; - } + let textures = BatchTextures::color(cache_item.texture_id); + let batch_kind = BrushBatchKind::Image(get_buffer_kind(cache_item.texture_id)); + let prim_user_data = ImageBrushData { + color_mode: ShaderColorMode::Image, + alpha_type: AlphaType::PremultipliedAlpha, + raster_space: RasterizationSpace::Local, + opacity: 1.0, + }.encode(); - let segment_prim_header = PrimitiveHeader { - local_rect: segment.local_rect, - local_clip_rect: segment_local_clip_rect.unwrap(), - specific_prim_address: prim_header.specific_prim_address, - transform_id: prim_header.transform_id, - }; + let specific_resource_address = cache_item.uv_rect_handle.as_int(gpu_cache); + prim_header.specific_prim_address = gpu_cache.get_address(&ctx.globals.default_image_handle); - let prim_header_index = prim_headers.push( - &segment_prim_header, - z_id, - prim_user_data, - ); + let prim_header_index = prim_headers.push( + &prim_header, + z_id, + prim_user_data, + ); - let batch_key = BatchKey { - blend_mode: non_segmented_blend_mode, - kind: BatchKind::Brush(batch_kind), - textures, - }; + let batch_key = BatchKey { + blend_mode: non_segmented_blend_mode, + kind: BatchKind::Brush(batch_kind), + textures, + }; - self.add_brush_instance_to_batches( - batch_key, - batch_features, - bounding_rect, - z_id, - INVALID_SEGMENT_INDEX, - EdgeAaSegmentMask::all(), - clip_task_address.unwrap(), - BrushFlags::PERSPECTIVE_INTERPOLATION, - prim_header_index, - specific_resource_address, - prim_vis_mask, - ); - } + self.add_brush_instance_to_batches( + batch_key, + batch_features, + bounding_rect, + z_id, + INVALID_SEGMENT_INDEX, + EdgeAaSegmentMask::all(), + clip_task_address.unwrap(), + BrushFlags::PERSPECTIVE_INTERPOLATION, + prim_header_index, + specific_resource_address, + prim_vis_mask, + ); } else if gradient.visible_tiles_range.is_empty() { let batch_params = BrushBatchParameters::shared( BrushBatchKind::LinearGradient, diff --git a/webrender/src/prim_store/gradient.rs b/webrender/src/prim_store/gradient.rs index 9e2c27be55..b8d59c8030 100644 --- a/webrender/src/prim_store/gradient.rs +++ b/webrender/src/prim_store/gradient.rs @@ -13,10 +13,11 @@ use crate::frame_builder::FrameBuildingState; use crate::gpu_cache::{GpuCacheHandle, GpuDataRequest}; use crate::intern::{Internable, InternDebug, Handle as InternHandle}; use crate::internal_types::LayoutPrimitiveInfo; -use crate::prim_store::{BrushSegment, CachedGradientSegment, GradientTileRange, VectorKey}; +use crate::prim_store::{BrushSegment, GradientTileRange, VectorKey}; use crate::prim_store::{PrimitiveInstanceKind, PrimitiveOpacity, PrimitiveSceneData}; use crate::prim_store::{PrimKeyCommonData, PrimTemplateCommonData, PrimitiveStore}; use crate::prim_store::{NinePatchDescriptor, PointKey, SizeKey, InternablePrimitive}; +use crate::render_task_cache::RenderTaskCacheEntryHandle; use std::{hash, ops::{Deref, DerefMut}}; use crate::util::pack_as_float; @@ -151,7 +152,7 @@ impl From for LinearGradientTemplate { // gradient in a smaller task, and drawing as an image. // TODO(gw): Aim to reduce the constraints on fast path gradients in future, // although this catches the vast majority of gradients on real pages. - let supports_caching = + let mut supports_caching = // No repeating support in fast path item.extend_mode == ExtendMode::Clamp && // Gradient must cover entire primitive @@ -160,15 +161,28 @@ impl From for LinearGradientTemplate { // Must be a vertical or horizontal gradient (item.start_point.x.approx_eq(&item.end_point.x) || item.start_point.y.approx_eq(&item.end_point.y)) && + // Fast path supports a limited number of stops + item.stops.len() <= GRADIENT_FP_STOPS && // Fast path not supported on segmented (border-image) gradients. item.nine_patch.is_none(); + let mut prev_offset = None; // Convert the stops to more convenient representation // for the current gradient builder. let stops: Vec = item.stops.iter().map(|stop| { let color: ColorF = stop.color.into(); min_alpha = min_alpha.min(color.a); + // The fast path doesn't support hard color stops, yet. + // Since the length of the gradient is a fixed size (512 device pixels), if there + // is a hard stop you will see bilinear interpolation with this method, instead + // of an abrupt color change. + if prev_offset == Some(stop.offset) { + supports_caching = false; + } + + prev_offset = Some(stop.offset); + GradientStop { offset: stop.offset, color, @@ -304,7 +318,7 @@ impl InternablePrimitive for LinearGradient { _reference_frame_relative_offset: LayoutVector2D, ) -> PrimitiveInstanceKind { let gradient_index = prim_store.linear_gradients.push(LinearGradientPrimitive { - cache_segments: Vec::new(), + cache_handle: None, visible_tiles_range: GradientTileRange::empty(), }); @@ -324,7 +338,7 @@ impl IsVisible for LinearGradient { #[derive(Debug)] #[cfg_attr(feature = "capture", derive(Serialize))] pub struct LinearGradientPrimitive { - pub cache_segments: Vec, + pub cache_handle: Option, pub visible_tiles_range: GradientTileRange, } diff --git a/webrender/src/prim_store/mod.rs b/webrender/src/prim_store/mod.rs index 82d17aa441..c9c16df149 100644 --- a/webrender/src/prim_store/mod.rs +++ b/webrender/src/prim_store/mod.rs @@ -970,13 +970,6 @@ pub struct VisibleGradientTile { pub local_clip_rect: LayoutRect, } -#[derive(Debug)] -#[cfg_attr(feature = "capture", derive(Serialize))] -pub struct CachedGradientSegment { - pub handle: RenderTaskCacheEntryHandle, - pub local_rect: LayoutRect, -} - /// Information about how to cache a border segment, /// along with the current render task cache entry. #[cfg_attr(feature = "capture", derive(Serialize))] @@ -3291,7 +3284,7 @@ impl PrimitiveStore { }; // Build the cache key, including information about the stops. - let mut stops = vec![GradientStopKey::empty(); prim_data.stops.len()]; + let mut stops = [GradientStopKey::empty(); GRADIENT_FP_STOPS]; // Reverse the stops as required, same as the gradient builder does // for the slow path. @@ -3309,124 +3302,35 @@ impl PrimitiveStore { } } - // To support clamping, we need to make sure that quads are emitted for the - // segments before and after the 0.0...1.0 range of offsets. The loop below - // can handle that by duplicating the first and last point if necessary: - if start_point < 0.0 { - stops.insert(0, GradientStopKey { - offset: start_point, - color : stops[0].color - }); - } - - if end_point > 1.0 { - stops.push( GradientStopKey { - offset: end_point, - color : stops[stops.len()-1].color - }); - } - - gradient.cache_segments.clear(); - - let mut first_stop = 0; - // look for an inclusive range of stops [first_stop, last_stop]. - // once first_stop points at (or past) the last stop, we're done. - while first_stop < stops.len()-1 { - - // if the entire segment starts at an offset that's past the primitive's - // end_point, we're done. - if stops[first_stop].offset > end_point { - break; - } - - // accumulate stops until we have GRADIENT_FP_STOPS of them, or we hit - // a hard stop: - let mut last_stop = first_stop; - let mut hard_stop = false; // did we stop on a hard stop? - while last_stop < stops.len()-1 && - last_stop - first_stop + 1 < GRADIENT_FP_STOPS - { - if stops[last_stop+1].offset == stops[last_stop].offset { - hard_stop = true; - break; - } - - last_stop = last_stop + 1; - } - - let num_stops = last_stop - first_stop + 1; - - // repeated hard stops at the same offset, skip - if num_stops == 0 { - first_stop = last_stop + 1; - continue; - } - - // if the last stop offset is before start_point, the segment's not visible: - if stops[last_stop].offset < start_point { - first_stop = if hard_stop { last_stop+1 } else { last_stop }; - continue; - } - - let segment_start_point = start_point.max(stops[first_stop].offset); - let segment_end_point = end_point .min(stops[last_stop ].offset); - - let mut segment_stops = [GradientStopKey::empty(); GRADIENT_FP_STOPS]; - for i in 0..num_stops { - segment_stops[i] = stops[first_stop + i]; - } - - let cache_key = GradientCacheKey { - orientation, - start_stop_point: VectorKey { - x: segment_start_point, - y: segment_end_point, - }, - stops: segment_stops, - }; - - let mut prim_origin = prim_instance.prim_origin; - let mut prim_size = prim_data.common.prim_size; + let cache_key = GradientCacheKey { + orientation, + start_stop_point: VectorKey { + x: start_point, + y: end_point, + }, + stops, + }; - let inv_length = 1.0 / ( end_point - start_point ); - if orientation == LineOrientation::Horizontal { - prim_origin.x += ( segment_start_point - start_point ) * inv_length * prim_size.width; - prim_size.width *= ( segment_end_point - segment_start_point ) * inv_length; - } else { - prim_origin.y += ( segment_start_point - start_point ) * inv_length * prim_size.height; - prim_size.height *= ( segment_end_point - segment_start_point ) * inv_length; + // Request the render task each frame. + gradient.cache_handle = Some(frame_state.resource_cache.request_render_task( + RenderTaskCacheKey { + size, + kind: RenderTaskCacheKeyKind::Gradient(cache_key), + }, + frame_state.gpu_cache, + frame_state.render_tasks, + None, + prim_data.stops_opacity.is_opaque, + |render_tasks| { + render_tasks.add().init(RenderTask::new_gradient( + size, + stops, + orientation, + start_point, + end_point, + )) } - - let local_rect = LayoutRect::new( prim_origin, prim_size ); - - // Request the render task each frame. - gradient.cache_segments.push( - CachedGradientSegment { - handle: frame_state.resource_cache.request_render_task( - RenderTaskCacheKey { - size, - kind: RenderTaskCacheKeyKind::Gradient(cache_key), - }, - frame_state.gpu_cache, - frame_state.render_tasks, - None, - prim_data.stops_opacity.is_opaque, - |render_tasks| { - render_tasks.add().init(RenderTask::new_gradient( - size, - segment_stops, - orientation, - segment_start_point, - segment_end_point, - )) - }), - local_rect: local_rect, - } - ); - - // if ending on a hardstop, skip past it for the start of the next run: - first_stop = if hard_stop { last_stop + 1 } else { last_stop }; - } + )); } if prim_data.tile_spacing != LayoutSize::zero() { diff --git a/wrench/reftests/gradient/gradient_cache_5stops.yaml b/wrench/reftests/gradient/gradient_cache_5stops.yaml deleted file mode 100644 index d448723002..0000000000 --- a/wrench/reftests/gradient/gradient_cache_5stops.yaml +++ /dev/null @@ -1,13 +0,0 @@ ---- -root: - items: - - type: gradient - bounds: 0 0 960 540 - start: 0 0 - end: 960 0 - stops: [0.0, red, - 0.25, green, - 0.5, blue, - 0.75, [40,40,40,1], - 1.0, [100,200,50,1]] - diff --git a/wrench/reftests/gradient/gradient_cache_5stops_ref.yaml b/wrench/reftests/gradient/gradient_cache_5stops_ref.yaml deleted file mode 100644 index 34b6b0e01c..0000000000 --- a/wrench/reftests/gradient/gradient_cache_5stops_ref.yaml +++ /dev/null @@ -1,18 +0,0 @@ ---- -root: - items: - - type: gradient - bounds: 0 0 480 540 - start: 0 0 - end: 480 0 - stops: [0.0, red, - 0.5, green, - 1.0, blue] - - type: gradient - bounds: 480 0 480 540 - start: 0 0 - end: 480 0 - stops: [ 0.0, blue, - 0.5, [40,40,40,1], - 1.0, [100,200,50,1]] - diff --git a/wrench/reftests/gradient/gradient_cache_5stops_vertical.yaml b/wrench/reftests/gradient/gradient_cache_5stops_vertical.yaml deleted file mode 100644 index dd2c8b7c9d..0000000000 --- a/wrench/reftests/gradient/gradient_cache_5stops_vertical.yaml +++ /dev/null @@ -1,13 +0,0 @@ ---- -root: - items: - - type: gradient - bounds: 0 0 960 540 - start: 0 0 - end: 0 540 - stops: [0.0, red, - 0.25, green, - 0.5, blue, - 0.75, [40,40,40,1], - 1.0, [100,200,50,1]] - diff --git a/wrench/reftests/gradient/gradient_cache_5stops_vertical_ref.yaml b/wrench/reftests/gradient/gradient_cache_5stops_vertical_ref.yaml deleted file mode 100644 index 704b5be2f6..0000000000 --- a/wrench/reftests/gradient/gradient_cache_5stops_vertical_ref.yaml +++ /dev/null @@ -1,18 +0,0 @@ ---- -root: - items: - - type: gradient - bounds: 0 0 960 270 - start: 0 0 - end: 0 270 - stops: [0.0, red, - 0.5, green, - 1.0, blue] - - type: gradient - bounds: 0 270 960 270 - start: 0 0 - end: 0 270 - stops: [ 0.0, blue, - 0.5, [40,40,40,1], - 1.0, [100,200,50,1]] - diff --git a/wrench/reftests/gradient/gradient_cache_clamp.yaml b/wrench/reftests/gradient/gradient_cache_clamp.yaml deleted file mode 100644 index 1c55a269a1..0000000000 --- a/wrench/reftests/gradient/gradient_cache_clamp.yaml +++ /dev/null @@ -1,20 +0,0 @@ ---- -root: - items: - - type: gradient - bounds: 0 0 400 200 - start: 0 100 - end: 100 100 - stops: [0.0, blue, 1.0, blue, 1.0, red] - - type: gradient - bounds: 0 300 400 200 - start: 100 100 - end: 200 100 - stops: [0.0, blue, 1.0, blue, 1.0, red] - - type: gradient - bounds: 0 600 200 400 - start: 0 100 - end: 0 300 - stops: [ - 0.0, blue, - 1.0, red] diff --git a/wrench/reftests/gradient/gradient_cache_clamp_ref.yaml b/wrench/reftests/gradient/gradient_cache_clamp_ref.yaml deleted file mode 100644 index 4631192cd8..0000000000 --- a/wrench/reftests/gradient/gradient_cache_clamp_ref.yaml +++ /dev/null @@ -1,30 +0,0 @@ ---- -root: - items: - - type: gradient - bounds: 0 0 400 200 - start: 0 100 - end: 400 100 - stops: [ - 0.0, blue, - 0.25, blue, - 0.25, red, - 1.0, red] - - type: gradient - bounds: 0 300 400 200 - start: 0 100 - end: 400 100 - stops: [ - 0.0, blue, - 0.5, blue, - 0.5, red, - 1.0, red] - - type: gradient - bounds: 0 600 200 400 - start: 0 0 - end: 0 400 - stops: [ - 0.0, blue, - 0.25, blue, - 0.75, red, - 1.0, red] diff --git a/wrench/reftests/gradient/gradient_cache_hardstop.yaml b/wrench/reftests/gradient/gradient_cache_hardstop.yaml deleted file mode 100644 index 53c908fb22..0000000000 --- a/wrench/reftests/gradient/gradient_cache_hardstop.yaml +++ /dev/null @@ -1,19 +0,0 @@ ---- -root: - items: - - type: gradient - bounds: 0 0 960 540 - start: 0 0 - end: 960 0 - stops: [0.0, red, - 0.125, yellow, - 0.25, red, - 0.25, green, - 0.375, yellow, - 0.5, green, - 0.5, blue, - 0.625, yellow, - 0.75, blue, - 0.75, white, - 1.0, [100,200,50,1]] - diff --git a/wrench/reftests/gradient/gradient_cache_hardstop_clip.yaml b/wrench/reftests/gradient/gradient_cache_hardstop_clip.yaml deleted file mode 100644 index 3e7a2e946f..0000000000 --- a/wrench/reftests/gradient/gradient_cache_hardstop_clip.yaml +++ /dev/null @@ -1,21 +0,0 @@ ---- -root: - items: - - type: gradient - bounds: 0 0 960 540 - start: 0 0 - end: 960 0 - stops: [0.0, red, - 0.125, yellow, - 0.25, red, - 0.25, green, - 0.375, yellow, - 0.5, green, - 0.5, blue, - 0.625, yellow, - 0.75, blue, - 0.75, white, - 1.0, [100,200,50,1]] - complex-clip: - rect: [100, 100, 760, 340] - radius: [32, 32] diff --git a/wrench/reftests/gradient/gradient_cache_hardstop_clip_ref.yaml b/wrench/reftests/gradient/gradient_cache_hardstop_clip_ref.yaml deleted file mode 100644 index 2b27c5649c..0000000000 --- a/wrench/reftests/gradient/gradient_cache_hardstop_clip_ref.yaml +++ /dev/null @@ -1,28 +0,0 @@ ---- -root: - items: - - type: gradient - bounds: 0 0 480 540 - start: 0 0 - end: 480 0 - stops: [0.0, red, - 0.25, yellow, - 0.5, red, - 0.5, green, - 0.75, yellow, - 1.0, green] - complex-clip: - rect: [100, 100, 760, 340] - radius: [32, 32] - - type: gradient - bounds: 480 0 480 540 - start: 0 0 - end: 480 0 - stops: [0.0, blue, - 0.25, yellow, - 0.5, blue, - 0.5, white, - 1.0, [100,200,50,1]] - complex-clip: - rect: [100, 100, 760, 340] - radius: [32, 32] diff --git a/wrench/reftests/gradient/gradient_cache_hardstop_ref.yaml b/wrench/reftests/gradient/gradient_cache_hardstop_ref.yaml deleted file mode 100644 index e4b3928046..0000000000 --- a/wrench/reftests/gradient/gradient_cache_hardstop_ref.yaml +++ /dev/null @@ -1,24 +0,0 @@ ---- -root: - items: - - type: gradient - bounds: 0 0 480 540 - start: 0 0 - end: 480 0 - stops: [0.0, red, - 0.25, yellow, - 0.5, red, - 0.5, green, - 0.75, yellow, - 1.0, green] - - type: gradient - bounds: 480 0 480 540 - start: 0 0 - end: 480 0 - stops: [0.0, blue, - 0.25, yellow, - 0.5, blue, - 0.5, white, - 1.0, [100,200,50,1]] - - diff --git a/wrench/reftests/gradient/reftest.list b/wrench/reftests/gradient/reftest.list index c3b3eee9cd..ac0b6454b4 100644 --- a/wrench/reftests/gradient/reftest.list +++ b/wrench/reftests/gradient/reftest.list @@ -16,7 +16,7 @@ platform(linux,mac) fuzzy(1,35000) == linear-stops.yaml linear-stops-ref.png == linear-clamp-1b.yaml linear-clamp-1-ref.yaml == linear-clamp-2.yaml linear-clamp-2-ref.yaml -fuzzy-range(<=1,*4800) == linear-hard-stop.yaml linear-hard-stop-ref.png +== linear-hard-stop.yaml linear-hard-stop-ref.png # dithering requires us to fuzz here fuzzy(1,20000) == linear.yaml linear-ref.yaml @@ -85,12 +85,3 @@ fuzzy(255,166) == conic-angle.yaml conic-angle.png fuzzy(1,1) == conic-angle-wraparound.yaml conic-angle.yaml fuzzy(1,1) == conic-angle-wraparound-negative.yaml conic-angle.yaml fuzzy(1,115) == conic-color-wheel.yaml conic-color-wheel.png - -# gradient caching tests -# replaces a computed gradient by a sampled texture, so a lot of off-by-one -# variation from interpolation, which is fine: -fuzzy-range(<=1,*195000) == gradient_cache_5stops.yaml gradient_cache_5stops_ref.yaml -fuzzy-range(<=1,*169000) == gradient_cache_5stops_vertical.yaml gradient_cache_5stops_vertical_ref.yaml -== gradient_cache_hardstop.yaml gradient_cache_hardstop_ref.yaml -== gradient_cache_hardstop_clip.yaml gradient_cache_hardstop_clip_ref.yaml -== gradient_cache_clamp.yaml gradient_cache_clamp_ref.yaml From fcc768d3d5efda65b54285b2cc5e26f49d94acb1 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Fri, 3 Apr 2020 14:08:44 +0000 Subject: [PATCH 3/3] Bug 1624881 - Work around the relative transform failed expectations r=gw we expect that the children spatial node goes after the parent. If it's not the case, we can still fall back to a full world transform, but it's not going to be correct with regards to flattening. As we don't know the circumstances and are unable to reproduce the issue, making this fallback could be a reasonable thing to do for now. Differential Revision: https://phabricator.services.mozilla.com/D69289 [ghsync] From https://hg.mozilla.org/mozilla-central/rev/085e6b728abbe83e92022f6aeeb157f240898fcf --- webrender/src/spatial_tree.rs | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/webrender/src/spatial_tree.rs b/webrender/src/spatial_tree.rs index e95fa748e4..e6ab9fcfd6 100644 --- a/webrender/src/spatial_tree.rs +++ b/webrender/src/spatial_tree.rs @@ -265,7 +265,6 @@ impl SpatialTree { child_index: SpatialNodeIndex, parent_index: SpatialNodeIndex, ) -> CoordinateSpaceMapping { - assert!(child_index.0 >= parent_index.0); if child_index == parent_index { return CoordinateSpaceMapping::Local; } @@ -280,6 +279,26 @@ impl SpatialTree { return CoordinateSpaceMapping::ScaleOffset(scale_offset); } + if child_index.0 < parent_index.0 { + warn!("Unexpected transform queried from {:?} to {:?}, please call the graphics team!", child_index, parent_index); + let child_cs = &self.coord_systems[child.coordinate_system_id.0 as usize]; + let child_transform = child.content_transform + .to_transform::() + .post_transform(&child_cs.world_transform); + let parent_cs = &self.coord_systems[parent.coordinate_system_id.0 as usize]; + let parent_transform = parent.content_transform + .to_transform() + .post_transform(&parent_cs.world_transform); + + let result = parent_transform + .inverse() + .unwrap_or_default() + .post_transform(&child_transform) + .with_source::() + .with_destination::(); + return CoordinateSpaceMapping::Transform(result); + } + let mut coordinate_system_id = child.coordinate_system_id; let mut transform = child.content_transform.to_transform();