Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Correctness and optimizations for clips in different coord systems. #2980

Merged
merged 2 commits into from
Aug 24, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
301 changes: 187 additions & 114 deletions webrender/src/clip.rs

Large diffs are not rendered by default.

3 changes: 1 addition & 2 deletions webrender/src/display_list_flattener.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use hit_test::{HitTestingItem, HitTestingRun};
use image::simplify_repeated_primitive;
use internal_types::{FastHashMap, FastHashSet};
use picture::{PictureCompositeMode, PictureId, PicturePrimitive};
use prim_store::{BrushClipMaskKind, BrushKind, BrushPrimitive, BrushSegmentDescriptor};
use prim_store::{BrushKind, BrushPrimitive, BrushSegmentDescriptor};
use prim_store::{EdgeAaSegmentMask, ImageSource};
use prim_store::{BorderSource, BrushSegment, PrimitiveContainer, PrimitiveIndex, PrimitiveStore};
use prim_store::{OpacityBinding, ScrollNodeAndClipChain, TextRunPrimitive};
Expand Down Expand Up @@ -1706,7 +1706,6 @@ impl<'a> DisplayListFlattener<'a> {
);
let descriptor = BrushSegmentDescriptor {
segments,
clip_mask_kind: BrushClipMaskKind::Unknown,
};

let brush_kind = match border.source {
Expand Down
149 changes: 83 additions & 66 deletions webrender/src/prim_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use renderer::{MAX_VERTEX_TEXTURE_WIDTH};
use resource_cache::{ImageProperties, ImageRequest, ResourceCache};
use scene::SceneProperties;
use segment::SegmentBuilder;
use std::{mem, usize};
use std::{cmp, mem, usize};
use util::{MatrixHelpers, calculate_screen_bounding_rect};
use util::{pack_as_float, recycle_vec, TransformedRectKind};

Expand Down Expand Up @@ -482,17 +482,9 @@ impl BrushSegment {
}
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum BrushClipMaskKind {
Unknown,
Individual,
Global,
}

#[derive(Debug)]
pub struct BrushSegmentDescriptor {
pub segments: Vec<BrushSegment>,
pub clip_mask_kind: BrushClipMaskKind,
}

#[derive(Debug)]
Expand Down Expand Up @@ -1659,21 +1651,9 @@ impl PrimitiveStore {
}
};

let clipped_device_rect = match calculate_screen_bounding_rect(
&prim_context.spatial_node.world_content_transform,
&clip_chain.local_bounding_rect,
frame_context.device_pixel_scale,
None,
) {
Some(rect) => rect,
None => {
if cfg!(debug_assertions) && is_chased {
println!("\tculled for being behind the near plane of transform: {:?}",
prim_context.spatial_node.world_content_transform);
}
return None
}
};
let clipped_device_rect = (clip_chain.world_clip_rect * frame_context.device_pixel_scale)
.round_out()
.to_i32();

let clipped_device_rect = match clipped_device_rect.intersection(&frame_context.screen_rect) {
Some(clipped_device_rect) => clipped_device_rect,
Expand Down Expand Up @@ -1971,12 +1951,9 @@ fn write_brush_segment_description(
frame_state: &mut FrameBuildingState,
) {
match brush.segment_desc {
Some(ref segment_desc) => {
// If we already have a segment descriptor, only run through the
// clips list if we haven't already determined the mask kind.
if segment_desc.clip_mask_kind == clip_chain.clip_mask_kind {
return;
}
Some(..) => {
// If we already have a segment descriptor, skip segment build.
return;
}
None => {
// If no segment descriptor built yet, see if it is a brush
Expand Down Expand Up @@ -2006,6 +1983,7 @@ fn write_brush_segment_description(
);

// Segment the primitive on all the local-space clip sources that we can.
let mut local_clip_count = 0;
for i in 0 .. clip_chain.clips_range.count {
let (clip_node, flags) = frame_state.clip_store.get_node_from_range(&clip_chain.clips_range, i);

Expand All @@ -2018,6 +1996,8 @@ fn write_brush_segment_description(
continue;
}

local_clip_count += 1;

let (local_clip_rect, radius, mode) = match clip_node.item {
ClipItem::RoundedRectangle(rect, radii, clip_mode) => {
rect_clips_only = false;
Expand Down Expand Up @@ -2063,10 +2043,40 @@ fn write_brush_segment_description(
}

if is_large || rect_clips_only {
match brush.segment_desc {
Some(ref mut segment_desc) => {
segment_desc.clip_mask_kind = clip_chain.clip_mask_kind;
// If there were no local clips, then we will subdivide the primitive into
// a uniform grid (up to 8x8 segments). This will typically result in
// a significant number of those segments either being completely clipped,
// or determined to not need a clip mask for that segment.
if local_clip_count == 0 && clip_chain.clips_range.count > 0 {
let x_clip_count = cmp::min(8, (metadata.local_rect.size.width / 128.0).ceil() as i32);
let y_clip_count = cmp::min(8, (metadata.local_rect.size.height / 128.0).ceil() as i32);

for y in 0 .. y_clip_count {
let y0 = metadata.local_rect.size.height * y as f32 / y_clip_count as f32;
let y1 = metadata.local_rect.size.height * (y+1) as f32 / y_clip_count as f32;

for x in 0 .. x_clip_count {
let x0 = metadata.local_rect.size.width * x as f32 / x_clip_count as f32;
let x1 = metadata.local_rect.size.width * (x+1) as f32 / x_clip_count as f32;

let rect = LayoutRect::new(
LayoutPoint::new(
x0 + metadata.local_rect.origin.x,
y0 + metadata.local_rect.origin.y,
),
LayoutSize::new(
x1 - x0,
y1 - y0,
),
);

segment_builder.push_mask_region(rect, LayoutRect::zero(), None);
}
}
}

match brush.segment_desc {
Some(..) => panic!("bug: should not already have descriptor"),
None => {
// TODO(gw): We can probably make the allocation
// patterns of this and the segment
Expand All @@ -2088,7 +2098,6 @@ fn write_brush_segment_description(

brush.segment_desc = Some(BrushSegmentDescriptor {
segments,
clip_mask_kind: clip_chain.clip_mask_kind,
});
}
}
Expand All @@ -2099,7 +2108,7 @@ impl Primitive {
fn update_clip_task_for_brush(
&mut self,
prim_context: &PrimitiveContext,
clip_chain: &ClipChainInstance,
prim_clip_chain: &ClipChainInstance,
combined_outer_rect: &DeviceIntRect,
pic_state: &mut PictureState,
frame_context: &FrameBuildingContext,
Expand All @@ -2115,50 +2124,59 @@ impl Primitive {
write_brush_segment_description(
brush,
&self.metadata,
clip_chain,
prim_clip_chain,
frame_state,
);

let segment_desc = match brush.segment_desc {
Some(ref mut description) => description,
None => return false,
};
let clip_mask_kind = segment_desc.clip_mask_kind;

for segment in &mut segment_desc.segments {
if !segment.may_need_clip_mask && clip_mask_kind != BrushClipMaskKind::Global {
segment.clip_task_id = BrushSegmentTaskId::Opaque;
continue;
}
// Build a clip chain for the smaller segment rect. This will
// often manage to eliminate most/all clips, and sometimes
// clip the segment completely.
let segment_clip_chain = frame_state
.clip_store
.build_clip_chain_instance(
self.metadata.clip_chain_id,
segment.local_rect,
self.metadata.local_clip_rect,
prim_context.spatial_node_index,
&frame_context.clip_scroll_tree,
frame_state.gpu_cache,
frame_state.resource_cache,
frame_context.device_pixel_scale,
);

let intersected_rect = calculate_screen_bounding_rect(
&prim_context.spatial_node.world_content_transform,
&segment.local_rect,
frame_context.device_pixel_scale,
Some(&combined_outer_rect),
);
match segment_clip_chain {
Some(segment_clip_chain) => {
if segment_clip_chain.clips_range.count == 0 {
segment.clip_task_id = BrushSegmentTaskId::Opaque;
continue;
}

let bounds = (segment_clip_chain.world_clip_rect * frame_context.device_pixel_scale)
.round_out()
.to_i32();

let clip_task = RenderTask::new_mask(
bounds,
segment_clip_chain.clips_range,
frame_state.clip_store,
frame_state.gpu_cache,
frame_state.resource_cache,
frame_state.render_tasks,
);

let bounds = match intersected_rect {
Some(bounds) => bounds,
let clip_task_id = frame_state.render_tasks.add(clip_task);
pic_state.tasks.push(clip_task_id);
segment.clip_task_id = BrushSegmentTaskId::RenderTaskId(clip_task_id);
}
None => {
segment.clip_task_id = BrushSegmentTaskId::Empty;
continue;
}
};

if clip_chain.clips_range.count > 0 {
let clip_task = RenderTask::new_mask(
bounds,
clip_chain.clips_range,
frame_state.clip_store,
frame_state.gpu_cache,
frame_state.resource_cache,
frame_state.render_tasks,
);

let clip_task_id = frame_state.render_tasks.add(clip_task);
pic_state.tasks.push(clip_task_id);
segment.clip_task_id = BrushSegmentTaskId::RenderTaskId(clip_task_id);
}
}

Expand Down Expand Up @@ -2754,7 +2772,6 @@ impl Primitive {
if needs_update {
brush.segment_desc = Some(BrushSegmentDescriptor {
segments: new_segments,
clip_mask_kind: BrushClipMaskKind::Unknown,
});

// The segments have changed, so force the GPU cache to
Expand Down
19 changes: 5 additions & 14 deletions webrender/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use api::{BorderRadius, DeviceIntPoint, DeviceIntRect, DeviceIntSize, DevicePixelScale};
use api::{DevicePoint, DeviceRect, DeviceSize, LayoutPixel, LayoutPoint, LayoutRect, LayoutSize};
use api::{DeviceRect, LayoutPixel, LayoutRect};
use api::{WorldPixel, WorldRect};
use euclid::{Point2D, Rect, Size2D, TypedPoint2D, TypedRect, TypedSize2D};
use euclid::{TypedTransform2D, TypedTransform3D, TypedVector2D};
Expand Down Expand Up @@ -331,15 +331,6 @@ pub trait MaxRect {
fn max_rect() -> Self;
}

impl MaxRect for LayoutRect {
fn max_rect() -> Self {
LayoutRect::new(
LayoutPoint::new(f32::MIN / 2.0, f32::MIN / 2.0),
LayoutSize::new(f32::MAX, f32::MAX),
)
}
}

impl MaxRect for DeviceIntRect {
fn max_rect() -> Self {
DeviceIntRect::new(
Expand All @@ -349,7 +340,7 @@ impl MaxRect for DeviceIntRect {
}
}

impl MaxRect for DeviceRect {
impl<U> MaxRect for TypedRect<f32, U> {
fn max_rect() -> Self {
// Having an unlimited bounding box is fine up until we try
// to cast it to `i32`, where we get `-2147483648` for any
Expand All @@ -359,9 +350,9 @@ impl MaxRect for DeviceRect {
// with explanation left as an exercise for the reader.
const MAX_COORD: f32 = 1.0e9;

DeviceRect::new(
DevicePoint::new(-MAX_COORD, -MAX_COORD),
DeviceSize::new(2.0 * MAX_COORD, 2.0 * MAX_COORD),
TypedRect::new(
TypedPoint2D::new(-MAX_COORD, -MAX_COORD),
TypedSize2D::new(2.0 * MAX_COORD, 2.0 * MAX_COORD),
)
}
}
Expand Down
Binary file modified wrench/reftests/boxshadow/box-shadow-stretch-mode-x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified wrench/reftests/clip/border-with-rounded-clip.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added wrench/reftests/transforms/coord-system.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified wrench/reftests/transforms/perspective-mask.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified wrench/reftests/transforms/perspective.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion wrench/reftests/transforms/reftest.list
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ platform(linux) fuzzy(1,630) == perspective.yaml perspective.png
platform(linux,mac) fuzzy(1,156) == prim-suite.yaml prim-suite.png
== segments-bug.yaml segments-bug-ref.yaml
platform(linux,mac) == content-offset.yaml content-offset.png
platform(linux,mac) == coord-system.yaml blank.yaml
platform(linux,mac) == coord-system.yaml coord-system.png
platform(linux,mac) zoom(4) == border-zoom.yaml border-zoom.png
platform(linux) fuzzy(1,520) == perspective-origin.yaml perspective-origin.png
platform(linux,mac) color_targets(1) alpha_targets(0) fuzzy(1,180) == screen-space-blit.yaml screen-space-blit.png
Expand All @@ -19,3 +19,4 @@ platform(linux,mac) == nested-rotate-x.yaml nested-rotate-x.png
platform(linux,mac) == nested-preserve-3d.yaml nested-preserve-3d.png
platform(linux,mac) == near-plane-clip.yaml near-plane-clip.png
platform(linux,mac) == perspective-mask.yaml perspective-mask.png
rotate-clip.yaml rotate-clip-ref.yaml
7 changes: 7 additions & 0 deletions wrench/reftests/transforms/rotate-clip-ref.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
root:
items:
-
bounds: [100, 146, 150, 107]
type: rect
color: 0 128 0 1.0000
18 changes: 18 additions & 0 deletions wrench/reftests/transforms/rotate-clip.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
root:
items:
-
type: clip
bounds: [0, 0, 2000, 2000]
clip-rect: [0, 0, 2000, 2000]
items:
-
bounds: [100, 0, 150, 150]
type: "stacking-context"
transform: rotate-x(45)
transform-origin: [0, 500]
items:
-
bounds: [0, 0, 150, 150]
type: rect
color: 0 128 0 1.0000