зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1624468 - Add a fast path for more gradient types in WR r=gw
Differential Revision: https://phabricator.services.mozilla.com/D68945 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
3b3f1af25e
Коммит
7f2e1717d9
|
@ -2268,7 +2268,10 @@ impl BatchBuilder {
|
|||
BlendMode::None
|
||||
};
|
||||
|
||||
if let Some(ref cache_handle) = gradient.cache_handle {
|
||||
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
|
||||
|
@ -2290,8 +2293,20 @@ impl BatchBuilder {
|
|||
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 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 prim_header_index = prim_headers.push(
|
||||
&prim_header,
|
||||
&segment_prim_header,
|
||||
z_id,
|
||||
prim_user_data,
|
||||
);
|
||||
|
@ -2315,6 +2330,7 @@ impl BatchBuilder {
|
|||
specific_resource_address,
|
||||
prim_vis_mask,
|
||||
);
|
||||
}
|
||||
} else if gradient.visible_tiles_range.is_empty() {
|
||||
let batch_params = BrushBatchParameters::shared(
|
||||
BrushBatchKind::LinearGradient,
|
||||
|
|
|
@ -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<LinearGradientKey> 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<LinearGradientKey> 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<GradientStop> = 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<RenderTaskCacheEntryHandle>,
|
||||
pub cache_segments: Vec<CachedGradientSegment>,
|
||||
pub visible_tiles_range: GradientTileRange,
|
||||
}
|
||||
|
||||
|
|
|
@ -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,17 +3309,100 @@ 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: start_point,
|
||||
y: end_point,
|
||||
x: segment_start_point,
|
||||
y: segment_end_point,
|
||||
},
|
||||
stops,
|
||||
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_handle = Some(frame_state.resource_cache.request_render_task(
|
||||
gradient.cache_segments.push(
|
||||
CachedGradientSegment {
|
||||
handle: frame_state.resource_cache.request_render_task(
|
||||
RenderTaskCacheKey {
|
||||
size,
|
||||
kind: RenderTaskCacheKeyKind::Gradient(cache_key),
|
||||
|
@ -3324,13 +3414,19 @@ impl PrimitiveStore {
|
|||
|render_tasks| {
|
||||
render_tasks.add().init(RenderTask::new_gradient(
|
||||
size,
|
||||
stops,
|
||||
segment_stops,
|
||||
orientation,
|
||||
start_point,
|
||||
end_point,
|
||||
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() {
|
||||
|
|
|
@ -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]]
|
||||
|
|
@ -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]]
|
||||
|
|
@ -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]]
|
||||
|
|
@ -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]]
|
||||
|
|
@ -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]
|
|
@ -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]
|
|
@ -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]]
|
||||
|
|
@ -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]
|
|
@ -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]
|
|
@ -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]]
|
||||
|
||||
|
|
@ -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
|
||||
|
|
|
@ -20,9 +20,10 @@ fuzzy-if(winWidget,0-1,0-37800) fuzzy-if(skiaContent,0-1,0-45000) == linear-size
|
|||
== linear-stops-1a.html linear-stops-1-ref.html
|
||||
== linear-stops-1b.html linear-stops-1-ref.html
|
||||
== linear-stops-1c.html linear-stops-1-ref.html
|
||||
== linear-stops-1d.html linear-stops-1-ref.html
|
||||
== linear-stops-1e.html linear-stops-1-ref.html
|
||||
== linear-stops-1f.html linear-stops-1-ref.html
|
||||
# these gradients will be cached (in WebRender) and thus exhibit off-by-1 texture interpolation differences:
|
||||
fuzzy(0-1,0-35100) == linear-stops-1d.html linear-stops-1-ref.html
|
||||
fuzzy(0-1,0-35100) == linear-stops-1e.html linear-stops-1-ref.html
|
||||
fuzzy(0-1,0-35100) == linear-stops-1f.html linear-stops-1-ref.html
|
||||
fuzzy-if(!contentSameGfxBackendAsCanvas,0-3,0-88500) fuzzy-if(azureSkiaGL||skiaContent,0-3,0-89700) == linear-vertical-1a.html linear-vertical-1-ref.html
|
||||
fuzzy-if(!contentSameGfxBackendAsCanvas,0-3,0-88500) fuzzy-if(azureSkiaGL||skiaContent,0-3,0-89700) == linear-vertical-1b.html linear-vertical-1-ref.html
|
||||
fuzzy-if(!contentSameGfxBackendAsCanvas,0-3,0-88500) fuzzy-if(azureSkiaGL||skiaContent,0-3,0-89700) == linear-vertical-1c.html linear-vertical-1-ref.html
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[gradient-move-stops.html]
|
||||
expected:
|
||||
if webrender: FAIL
|
||||
if webrender and (os == "win"): FAIL
|
||||
|
||||
[border-image-repeat-round-2.html]
|
||||
fuzzy:
|
||||
|
|
Загрузка…
Ссылка в новой задаче