--- a/gfx/webrender/src/picture.rs
+++ b/gfx/webrender/src/picture.rs
@@ -4,17 +4,17 @@
use api::{BorderRadiusKind, ColorF, ClipAndScrollInfo, FilterOp, MixBlendMode};
use api::{device_length, DeviceIntRect, DeviceIntSize, PipelineId};
use api::{BoxShadowClipMode, LayerPoint, LayerRect, LayerSize, LayerVector2D, Shadow};
use api::{ClipId, PremultipliedColorF};
use box_shadow::BLUR_SAMPLE_SCALE;
use frame_builder::PrimitiveContext;
use gpu_cache::GpuDataRequest;
-use prim_store::{PrimitiveIndex, PrimitiveRun};
+use prim_store::{PrimitiveIndex, PrimitiveRun, PrimitiveRunLocalRect};
use render_task::{ClearMode, RenderTask, RenderTaskId, RenderTaskTree};
use tiling::RenderTargetKind;
/*
A picture represents a dynamically rendered image. It consists of:
* A number of primitives that are drawn onto the picture.
* A composite operation describing how to composite this
@@ -178,23 +178,24 @@ impl PicturePrimitive {
self.runs.push(PrimitiveRun {
base_prim_index: prim_index,
count: 1,
clip_and_scroll,
});
}
pub fn update_local_rect(&mut self,
- local_rect: LayerRect,
- local_content_rect: LayerRect,
- local_content_rect2: LayerRect,
+ prim_local_rect: LayerRect,
+ prim_run_rect: PrimitiveRunLocalRect,
) -> LayerRect {
+ let local_content_rect = prim_run_rect.local_rect_in_actual_parent_space;
+
match self.kind {
PictureKind::Image { composite_mode, ref mut real_local_rect, .. } => {
- *real_local_rect = local_content_rect2;
+ *real_local_rect = prim_run_rect.local_rect_in_original_parent_space;
match composite_mode {
Some(PictureCompositeMode::Filter(FilterOp::Blur(blur_radius))) => {
let inflate_size = blur_radius * BLUR_SAMPLE_SCALE;
local_content_rect.inflate(inflate_size, inflate_size)
}
_ => {
local_content_rect
@@ -243,17 +244,17 @@ impl PicturePrimitive {
}
}
}
BoxShadowClipMode::Inset => {
*content_rect = local_content_rect;
}
}
- local_rect
+ prim_local_rect
}
}
}
pub fn prepare_for_render(
&mut self,
prim_index: PrimitiveIndex,
prim_context: &PrimitiveContext,
--- a/gfx/webrender/src/prim_store.rs
+++ b/gfx/webrender/src/prim_store.rs
@@ -2,17 +2,17 @@
* 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, BuiltDisplayList, ColorF, ComplexClipRegion, DeviceIntRect};
use api::{DevicePoint, ExtendMode, GlyphInstance, GlyphKey};
use api::{GradientStop, ImageKey, ImageRendering, ItemRange, ItemTag, LayerPoint, LayerRect};
use api::{ClipMode, LayerSize, LayerVector2D, LineOrientation, LineStyle};
use api::{ClipAndScrollInfo, EdgeAaSegmentMask, PremultipliedColorF, TileOffset};
-use api::{ClipId, PipelineId, YuvColorSpace, YuvFormat};
+use api::{ClipId, LayerTransform, PipelineId, YuvColorSpace, YuvFormat};
use border::BorderCornerInstance;
use clip_scroll_tree::ClipScrollTree;
use clip::{ClipSourcesHandle, ClipStore};
use frame_builder::PrimitiveContext;
use glyph_rasterizer::FontInstance;
use internal_types::FastHashMap;
use gpu_cache::{GpuBlockData, GpuCache, GpuCacheAddress, GpuCacheHandle, GpuDataRequest,
ToGpuBlocks};
@@ -54,16 +54,37 @@ impl PrimitiveOpacity {
}
}
pub fn accumulate(&mut self, alpha: f32) {
self.is_opaque = self.is_opaque && alpha == 1.0;
}
}
+// Represents the local space rect of a list of
+// primitive runs. For most primitive runs, the
+// primitive runs are attached to the parent they
+// are declared in. However, when a primitive run
+// is part of a 3d rendering context, it may get
+// hoisted to a higher level in the picture tree.
+// When this happens, we need to also calculate the
+// local space rects in the original space. This
+// allows constructing the true world space polygons
+// for the primitive, to enable the plane splitting
+// logic to work correctly.
+// TODO(gw) In the future, we can probably simplify
+// this - perhaps calculate the world space
+// polygons directly and store internally
+// in the picture structure.
+#[derive(Debug)]
+pub struct PrimitiveRunLocalRect {
+ pub local_rect_in_actual_parent_space: LayerRect,
+ pub local_rect_in_original_parent_space: LayerRect,
+}
+
/// Stores two coordinates in texel space. The coordinates
/// are stored in texel coordinates because the texture atlas
/// may grow. Storing them as texel coords and normalizing
/// the UVs in the vertex shader means nothing needs to be
/// updated on the CPU when the texture size changes.
#[derive(Copy, Clone, Debug)]
pub struct TexelRect {
pub uv0: DevicePoint,
@@ -1313,17 +1334,17 @@ impl PrimitiveStore {
// If we have dependencies, we need to prepare them first, in order
// to know the actual rect of this primitive.
// For example, scrolling may affect the location of an item in
// local space, which may force us to render this item on a larger
// picture target, if being composited.
let mut child_tasks = Vec::new();
if let Some((pipeline_id, dependencies, rfid)) = dependencies {
- let (child_local_rect, child_local_rect2) = self.prepare_prim_runs(
+ let result = self.prepare_prim_runs(
&dependencies,
pipeline_id,
gpu_cache,
resource_cache,
render_tasks,
clip_store,
clip_scroll_tree,
pipelines,
@@ -1337,18 +1358,17 @@ impl PrimitiveStore {
let metadata = &mut self.cpu_metadata[prim_index.0];
// Restore the dependencies (borrow check dance)
let pic = &mut self.cpu_pictures[cpu_prim_index.0];
pic.runs = dependencies;
metadata.local_rect = pic.update_local_rect(
metadata.local_rect,
- child_local_rect,
- child_local_rect2,
+ result,
);
}
let (local_rect, device_rect) = {
let metadata = &mut self.cpu_metadata[prim_index.0];
if metadata.local_rect.size.width <= 0.0 ||
metadata.local_rect.size.height <= 0.0 {
warn!("invalid primitive rect {:?}", metadata.local_rect);
@@ -1424,33 +1444,54 @@ impl PrimitiveStore {
render_tasks: &mut RenderTaskTree,
clip_store: &mut ClipStore,
clip_scroll_tree: &ClipScrollTree,
pipelines: &FastHashMap<PipelineId, ScenePipeline>,
parent_prim_context: &PrimitiveContext,
perform_culling: bool,
parent_tasks: &mut Vec<RenderTaskId>,
profile_counters: &mut FrameProfileCounters,
- reference_frame_id: Option<ClipId>,
- ) -> (LayerRect, LayerRect) {
- let mut local_rect_in_moved_space = LayerRect::zero();
- let mut local_rect_in_original_space = LayerRect::zero();
+ original_reference_frame_id: Option<ClipId>,
+ ) -> PrimitiveRunLocalRect {
+ let mut result = PrimitiveRunLocalRect {
+ local_rect_in_actual_parent_space: LayerRect::zero(),
+ local_rect_in_original_parent_space: LayerRect::zero(),
+ };
for run in runs {
// TODO(gw): Perhaps we can restructure this to not need to create
// a new primitive context for every run (if the hash
// lookups ever show up in a profile).
let scroll_node = &clip_scroll_tree.nodes[&run.clip_and_scroll.scroll_node_id];
let clip_node = &clip_scroll_tree.nodes[&run.clip_and_scroll.clip_node_id()];
if !clip_node.is_visible() {
debug!("{:?} of clipped out {:?}", run.base_prim_index, pipeline_id);
continue;
}
+ let parent_relative_transform = parent_prim_context
+ .scroll_node
+ .world_content_transform
+ .inverse()
+ .map(|inv_parent| {
+ inv_parent.pre_mul(&scroll_node.world_content_transform)
+ });
+
+ let original_relative_transform = original_reference_frame_id
+ .and_then(|original_reference_frame_id| {
+ let parent = clip_scroll_tree
+ .nodes[&original_reference_frame_id]
+ .world_content_transform;
+ parent.inverse()
+ .map(|inv_parent| {
+ inv_parent.pre_mul(&scroll_node.world_content_transform)
+ })
+ });
+
let display_list = &pipelines
.get(&pipeline_id)
.expect("No display list?")
.display_list;
let child_prim_context = PrimitiveContext::new(
parent_prim_context.device_pixel_ratio,
display_list,
@@ -1471,78 +1512,32 @@ impl PrimitiveStore {
clip_scroll_tree,
pipelines,
perform_culling,
parent_tasks,
profile_counters,
) {
profile_counters.visible_primitives.inc();
- if let Some(reference_frame_id) = reference_frame_id {
- if let Some(m0) = clip_scroll_tree.nodes[&reference_frame_id].world_content_transform.inverse() {
- let m1 = scroll_node.world_content_transform;
- let m = m0.pre_mul(&m1);
-
- let vertices = [
- m.transform_point3d(&prim_local_rect.origin.to_3d()),
- m.transform_point3d(&prim_local_rect.bottom_left().to_3d()),
- m.transform_point3d(&prim_local_rect.bottom_right().to_3d()),
- m.transform_point3d(&prim_local_rect.top_right().to_3d()),
- ];
-
- let mut x0 = vertices[0].x;
- let mut y0 = vertices[0].y;
- let mut x1 = vertices[0].x;
- let mut y1 = vertices[0].y;
-
- for v in &vertices {
- x0 = x0.min(v.x);
- y0 = y0.min(v.y);
- x1 = x1.max(v.x);
- y1 = y1.max(v.y);
- }
-
- let bounds = LayerRect::new(LayerPoint::new(x0, y0), LayerSize::new(x1 - x0, y1 - y0));
-
- local_rect_in_original_space = local_rect_in_original_space.union(&bounds);
- }
+ if let Some(ref matrix) = original_relative_transform {
+ let bounds = get_local_bounding_rect(&prim_local_rect, matrix);
+ result.local_rect_in_original_parent_space =
+ result.local_rect_in_original_parent_space.union(&bounds);
}
- if let Some(m0) = parent_prim_context.scroll_node.world_content_transform.inverse() {
- let m1 = scroll_node.world_content_transform;
- let m = m0.pre_mul(&m1);
-
- let vertices = [
- m.transform_point3d(&prim_local_rect.origin.to_3d()),
- m.transform_point3d(&prim_local_rect.bottom_left().to_3d()),
- m.transform_point3d(&prim_local_rect.bottom_right().to_3d()),
- m.transform_point3d(&prim_local_rect.top_right().to_3d()),
- ];
-
- let mut x0 = vertices[0].x;
- let mut y0 = vertices[0].y;
- let mut x1 = vertices[0].x;
- let mut y1 = vertices[0].y;
-
- for v in &vertices {
- x0 = x0.min(v.x);
- y0 = y0.min(v.y);
- x1 = x1.max(v.x);
- y1 = y1.max(v.y);
- }
-
- let bounds = LayerRect::new(LayerPoint::new(x0, y0), LayerSize::new(x1 - x0, y1 - y0));
-
- local_rect_in_moved_space = local_rect_in_moved_space.union(&bounds);
+ if let Some(ref matrix) = parent_relative_transform {
+ let bounds = get_local_bounding_rect(&prim_local_rect, matrix);
+ result.local_rect_in_actual_parent_space =
+ result.local_rect_in_actual_parent_space.union(&bounds);
}
}
}
}
- (local_rect_in_moved_space, local_rect_in_original_space)
+ result
}
}
//Test for one clip region contains another
trait InsideTest<T> {
fn might_contain(&self, clip: &T) -> bool;
}
@@ -1560,8 +1555,34 @@ impl InsideTest<ComplexClipRegion> for C
clip.radii.top_right.width >= self.radii.top_right.width - delta_right &&
clip.radii.top_right.height >= self.radii.top_right.height - delta_top &&
clip.radii.bottom_left.width >= self.radii.bottom_left.width - delta_left &&
clip.radii.bottom_left.height >= self.radii.bottom_left.height - delta_bottom &&
clip.radii.bottom_right.width >= self.radii.bottom_right.width - delta_right &&
clip.radii.bottom_right.height >= self.radii.bottom_right.height - delta_bottom
}
}
+
+fn get_local_bounding_rect(
+ local_rect: &LayerRect,
+ matrix: &LayerTransform
+) -> LayerRect {
+ let vertices = [
+ matrix.transform_point3d(&local_rect.origin.to_3d()),
+ matrix.transform_point3d(&local_rect.bottom_left().to_3d()),
+ matrix.transform_point3d(&local_rect.bottom_right().to_3d()),
+ matrix.transform_point3d(&local_rect.top_right().to_3d()),
+ ];
+
+ let mut x0 = vertices[0].x;
+ let mut y0 = vertices[0].y;
+ let mut x1 = vertices[0].x;
+ let mut y1 = vertices[0].y;
+
+ for v in &vertices[1..] {
+ x0 = x0.min(v.x);
+ y0 = y0.min(v.y);
+ x1 = x1.max(v.x);
+ y1 = y1.max(v.y);
+ }
+
+ LayerRect::new(LayerPoint::new(x0, y0), LayerSize::new(x1 - x0, y1 - y0))
+}