mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 05:11:16 +00:00
Bug 1779952 - Refactor and optimize internal representation of clip state r=nical
This patch refactors how clip chains are internally represented and used during scene and frame building. The intent is to make clip processing during frame building more efficient and consistent. Additionally, this work enables follow ups to cache the result of clip-chain builds between frame and scene builds. These changes will significantly reduce the cost of the visibility pass for the common case when not much content has changed. In this patch, the public API for clipping remains (mostly) the same, in order to allow landing and stabilising this work without major changes to Gecko. However, a longer term goal is to make the public WR clip API more closely match the internal representation, to reduce work done during scene building. Clips on a primitive can be categorized into two buckets. The first are local clips that are specific to the primitive and move with it. These could essentially be considered part of the definition of the primitive itself. The second are a hierarchy of clips that apply to one or more items, and may move independently of the primitive(s) they clip. These clips are things like scroll regions, stacking context clips, iframe clip regions etc. On (real world) pages, the clip hierarchy is typically quite shallow, with a small number of clips that are shared by a large number of primitives. Finding clips that are shared between primitives is both required (for things such as determining which picture cache slice a primitive can be assigned to, while applying the shared clips during composition), and also a potential optimization (processing shared clips only once and caching this clip state similar primitives). The public clip-chain API has two complexities that make the above difficult and time consuming for WR to determine. It was possible to express a clipping hierarchy both via the legacy clip parenting path (via `ClipId` definitions) and also via clip-chains (the `parent` field of a `ClipChain`). Second, clip-chains themselves can define an arbitrary number and ordering of clips. Clips can also implicitly apply to primitives via parent stacking contexts and iframes, but must sometimes be removed (when an intermediate surface is created) for performance reasons. The new internal representation provided by this patch introduces a `ClipTree` structure which is built during scene building by accumulating the set of clips that apply to a primitive from all explicit and implicit sources, and grafting this on to the existing clip-tree structure. This provides WR a simple way to determine which clips are shared between primitive (by checking ancestry) and reduces the size of the internal representation (by sharing clips where possible rather than duplicating). Interning is still used to identify parts of the clip-tree that define the same clipping state. Specific changes in this patch: * Remove legacy `ClipId` style parenting support (in conjunction with previous patches) * Remove the public API ability to specify the clip on a primitive via `ClipId` (it must now be a clip-chain) * Remove `combined_local_clip_rect` from `PrimitiveInstance`, reducing the size of the structure significantly * Introduce `ClipTree` used during frame building, which is created by `ClipTreeBuilder` during scene building * Separate out per-primitive clip concept (`ClipTreeLeaf`) from clipping hierarchy (`ClipTreeNode`). In future, more elements will be moved to the `ClipTreeLeaf` and the state of each `ClipTreeNode` will be cached) * Simplify the logic to disable / remove clips during frame building that are applied by parent surface(s) * Port hit-testing to be based on `ClipTree` which is simpler, faster and also resolves some edge case correctness bugs * Use a simpler and faster method to find shared clips during picture cache slice assignment of primitives * Update wrench to use the public clip-chain API definition changes This patch already introduces some real-world optimizations (for example, `displaylist_mutate` becomes 6% faster overall), but mostly sets things up for follow up patches to be able to cache clip-state between frames, which should result in much larger wins. Differential Revision: https://phabricator.services.mozilla.com/D151987
This commit is contained in:
parent
ae6f4c94fc
commit
a00b8ca709
@ -3927,14 +3927,11 @@ pub struct WrClipId {
|
||||
|
||||
impl WrClipId {
|
||||
fn to_webrender(&self, pipeline_id: WrPipelineId) -> ClipId {
|
||||
ClipId::Clip(self.id, pipeline_id)
|
||||
ClipId(self.id, pipeline_id)
|
||||
}
|
||||
|
||||
fn from_webrender(clip_id: ClipId) -> Self {
|
||||
match clip_id {
|
||||
ClipId::Clip(id, _) => WrClipId { id },
|
||||
ClipId::ClipChain(_) => panic!("Unexpected clip chain"),
|
||||
}
|
||||
WrClipId { id: clip_id.0 }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -917,7 +917,7 @@ impl BatchBuilder {
|
||||
|
||||
let prim_header = PrimitiveHeader {
|
||||
local_rect: prim_rect,
|
||||
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||
local_clip_rect: prim_info.clip_chain.local_clip_rect,
|
||||
specific_prim_address: prim_cache_address,
|
||||
transform_id,
|
||||
};
|
||||
@ -984,7 +984,7 @@ impl BatchBuilder {
|
||||
|
||||
let prim_header = PrimitiveHeader {
|
||||
local_rect: prim_rect,
|
||||
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||
local_clip_rect: prim_info.clip_chain.local_clip_rect,
|
||||
specific_prim_address: prim_cache_address,
|
||||
transform_id,
|
||||
};
|
||||
@ -1048,7 +1048,7 @@ impl BatchBuilder {
|
||||
min: prim_rect.min - run.reference_frame_relative_offset,
|
||||
max: run.snapped_reference_frame_relative_offset.to_point(),
|
||||
},
|
||||
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||
local_clip_rect: prim_info.clip_chain.local_clip_rect,
|
||||
specific_prim_address: prim_cache_address,
|
||||
transform_id,
|
||||
};
|
||||
@ -1320,7 +1320,7 @@ impl BatchBuilder {
|
||||
|
||||
let prim_header = PrimitiveHeader {
|
||||
local_rect: prim_rect,
|
||||
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||
local_clip_rect: prim_info.clip_chain.local_clip_rect,
|
||||
specific_prim_address: prim_cache_address,
|
||||
transform_id,
|
||||
};
|
||||
@ -1362,7 +1362,7 @@ impl BatchBuilder {
|
||||
let brush_flags = brush_flags | BrushFlags::PERSPECTIVE_INTERPOLATION;
|
||||
|
||||
let surface = &ctx.surfaces[raster_config.surface_index.0];
|
||||
let mut local_clip_rect = prim_info.combined_local_clip_rect;
|
||||
let mut local_clip_rect = prim_info.clip_chain.local_clip_rect;
|
||||
|
||||
// If we are drawing with snapping enabled, form a simple transform that just applies
|
||||
// the scale / translation from the raster transform. Otherwise, in edge cases where the
|
||||
@ -1391,7 +1391,7 @@ impl BatchBuilder {
|
||||
let transform = ScaleOffset::new(sx, sy, tx, ty);
|
||||
|
||||
let raster_clip_rect = map_local_to_raster
|
||||
.map(&prim_info.combined_local_clip_rect)
|
||||
.map(&prim_info.clip_chain.local_clip_rect)
|
||||
.unwrap();
|
||||
local_clip_rect = transform.unmap_rect(&raster_clip_rect);
|
||||
|
||||
@ -1926,7 +1926,7 @@ impl BatchBuilder {
|
||||
|
||||
let prim_header = PrimitiveHeader {
|
||||
local_rect: prim_rect,
|
||||
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||
local_clip_rect: prim_info.clip_chain.local_clip_rect,
|
||||
specific_prim_address: GpuCacheAddress::INVALID,
|
||||
transform_id: transforms
|
||||
.get_id(
|
||||
@ -2130,7 +2130,7 @@ impl BatchBuilder {
|
||||
|
||||
let prim_header = PrimitiveHeader {
|
||||
local_rect: prim_rect,
|
||||
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||
local_clip_rect: prim_info.clip_chain.local_clip_rect,
|
||||
specific_prim_address: prim_cache_address,
|
||||
transform_id,
|
||||
};
|
||||
@ -2200,7 +2200,7 @@ impl BatchBuilder {
|
||||
|
||||
let prim_header = PrimitiveHeader {
|
||||
local_rect: prim_rect,
|
||||
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||
local_clip_rect: prim_info.clip_chain.local_clip_rect,
|
||||
specific_prim_address: prim_cache_address,
|
||||
transform_id,
|
||||
};
|
||||
@ -2305,7 +2305,7 @@ impl BatchBuilder {
|
||||
|
||||
let prim_header = PrimitiveHeader {
|
||||
local_rect: prim_rect,
|
||||
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||
local_clip_rect: prim_info.clip_chain.local_clip_rect,
|
||||
specific_prim_address: prim_cache_address,
|
||||
transform_id,
|
||||
};
|
||||
@ -2394,7 +2394,7 @@ impl BatchBuilder {
|
||||
|
||||
let prim_header = PrimitiveHeader {
|
||||
local_rect: prim_rect,
|
||||
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||
local_clip_rect: prim_info.clip_chain.local_clip_rect,
|
||||
specific_prim_address: prim_cache_address,
|
||||
transform_id,
|
||||
};
|
||||
@ -2493,7 +2493,7 @@ impl BatchBuilder {
|
||||
|
||||
let mut prim_header = PrimitiveHeader {
|
||||
local_rect: prim_rect,
|
||||
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||
local_clip_rect: prim_info.clip_chain.local_clip_rect,
|
||||
specific_prim_address: GpuCacheAddress::INVALID,
|
||||
transform_id,
|
||||
};
|
||||
@ -2598,7 +2598,7 @@ impl BatchBuilder {
|
||||
|
||||
let prim_header = PrimitiveHeader {
|
||||
local_rect: prim_rect,
|
||||
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||
local_clip_rect: prim_info.clip_chain.local_clip_rect,
|
||||
specific_prim_address: gpu_cache.get_address(&common_data.gpu_cache_handle),
|
||||
transform_id,
|
||||
};
|
||||
@ -2715,7 +2715,7 @@ impl BatchBuilder {
|
||||
|
||||
let prim_header = PrimitiveHeader {
|
||||
local_rect: prim_rect,
|
||||
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||
local_clip_rect: prim_info.clip_chain.local_clip_rect,
|
||||
specific_prim_address: gpu_cache.get_address(&common_data.gpu_cache_handle),
|
||||
transform_id,
|
||||
};
|
||||
@ -2834,7 +2834,7 @@ impl BatchBuilder {
|
||||
|
||||
let prim_header = PrimitiveHeader {
|
||||
local_rect: prim_rect,
|
||||
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||
local_clip_rect: prim_info.clip_chain.local_clip_rect,
|
||||
specific_prim_address: gpu_cache.get_address(&common_data.gpu_cache_handle),
|
||||
transform_id,
|
||||
};
|
||||
@ -2943,7 +2943,7 @@ impl BatchBuilder {
|
||||
|
||||
let prim_header = PrimitiveHeader {
|
||||
local_rect: prim_rect,
|
||||
local_clip_rect: prim_info.combined_local_clip_rect,
|
||||
local_clip_rect: prim_info.clip_chain.local_clip_rect,
|
||||
specific_prim_address: prim_cache_address,
|
||||
transform_id,
|
||||
};
|
||||
|
@ -5,7 +5,7 @@
|
||||
use api::{BorderRadius, BorderSide, BorderStyle, ColorF, ColorU};
|
||||
use api::{NormalBorder as ApiNormalBorder, RepeatMode};
|
||||
use api::units::*;
|
||||
use crate::clip::ClipChainId;
|
||||
use crate::clip::ClipNodeId;
|
||||
use crate::ellipse::Ellipse;
|
||||
use euclid::vec2;
|
||||
use crate::scene_building::SceneBuilder;
|
||||
@ -217,14 +217,14 @@ impl<'a> SceneBuilder<'a> {
|
||||
border: &ApiNormalBorder,
|
||||
widths: LayoutSideOffsets,
|
||||
spatial_node_index: SpatialNodeIndex,
|
||||
clip_chain_id: ClipChainId,
|
||||
clip_node_id: ClipNodeId,
|
||||
) {
|
||||
let mut border = *border;
|
||||
ensure_no_corner_overlap(&mut border.radius, info.rect.size());
|
||||
|
||||
self.add_primitive(
|
||||
spatial_node_index,
|
||||
clip_chain_id,
|
||||
clip_node_id,
|
||||
info,
|
||||
Vec::new(),
|
||||
NormalBorderPrim {
|
||||
|
@ -5,7 +5,7 @@
|
||||
use api::{BorderRadius, BoxShadowClipMode, ClipMode, ColorF, PrimitiveKeyKind};
|
||||
use api::PropertyBinding;
|
||||
use api::units::*;
|
||||
use crate::clip::{ClipItemKey, ClipItemKeyKind, ClipChainId};
|
||||
use crate::clip::{ClipItemKey, ClipItemKeyKind, ClipNodeId};
|
||||
use crate::scene_building::SceneBuilder;
|
||||
use crate::spatial_tree::SpatialNodeIndex;
|
||||
use crate::gpu_types::BoxShadowStretchMode;
|
||||
@ -74,7 +74,7 @@ impl<'a> SceneBuilder<'a> {
|
||||
pub fn add_box_shadow(
|
||||
&mut self,
|
||||
spatial_node_index: SpatialNodeIndex,
|
||||
clip_chain_id: ClipChainId,
|
||||
clip_node_id: ClipNodeId,
|
||||
prim_info: &LayoutPrimitiveInfo,
|
||||
box_offset: &LayoutVector2D,
|
||||
color: ColorF,
|
||||
@ -163,7 +163,7 @@ impl<'a> SceneBuilder<'a> {
|
||||
|
||||
self.add_primitive(
|
||||
spatial_node_index,
|
||||
clip_chain_id,
|
||||
clip_node_id,
|
||||
&LayoutPrimitiveInfo::with_clip_rect(final_prim_rect, prim_info.clip_rect),
|
||||
clips,
|
||||
PrimitiveKeyKind::Rectangle {
|
||||
@ -246,7 +246,7 @@ impl<'a> SceneBuilder<'a> {
|
||||
|
||||
self.add_primitive(
|
||||
spatial_node_index,
|
||||
clip_chain_id,
|
||||
clip_node_id,
|
||||
&prim_info,
|
||||
extra_clips,
|
||||
prim,
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -5,7 +5,7 @@
|
||||
use api::{ColorF, DebugFlags, FontRenderMode, PremultipliedColorF};
|
||||
use api::units::*;
|
||||
use crate::batch::{BatchBuilder, AlphaBatchBuilder, AlphaBatchContainer, CommandBufferList};
|
||||
use crate::clip::{ClipStore, ClipChainStack};
|
||||
use crate::clip::ClipStore;
|
||||
use crate::spatial_tree::{SpatialTree, SpatialNodeIndex};
|
||||
use crate::composite::{CompositorKind, CompositeState, CompositeStatePreallocator};
|
||||
use crate::debug_item::DebugItem;
|
||||
@ -111,7 +111,6 @@ impl FrameGlobalResources {
|
||||
pub struct FrameScratchBuffer {
|
||||
dirty_region_stack: Vec<DirtyRegion>,
|
||||
surface_stack: Vec<(PictureIndex, SurfaceIndex)>,
|
||||
clip_chain_stack: ClipChainStack,
|
||||
}
|
||||
|
||||
impl Default for FrameScratchBuffer {
|
||||
@ -119,7 +118,6 @@ impl Default for FrameScratchBuffer {
|
||||
FrameScratchBuffer {
|
||||
dirty_region_stack: Vec::new(),
|
||||
surface_stack: Vec::new(),
|
||||
clip_chain_stack: ClipChainStack::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -128,7 +126,6 @@ impl FrameScratchBuffer {
|
||||
pub fn begin_frame(&mut self) {
|
||||
self.dirty_region_stack.clear();
|
||||
self.surface_stack.clear();
|
||||
self.clip_chain_stack.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@ -190,7 +187,6 @@ impl<'a> FrameBuildingState<'a> {
|
||||
#[derive(Debug)]
|
||||
pub struct PictureContext {
|
||||
pub pic_index: PictureIndex,
|
||||
pub apply_local_clip_rect: bool,
|
||||
pub surface_spatial_node_index: SpatialNodeIndex,
|
||||
pub raster_spatial_node_index: SpatialNodeIndex,
|
||||
/// The surface that this picture will render on.
|
||||
@ -305,7 +301,6 @@ impl FrameBuilder {
|
||||
.expect("bug: non-existent tile cache");
|
||||
|
||||
let mut visibility_state = FrameVisibilityState {
|
||||
clip_chain_stack: scratch.frame.clip_chain_stack.take(),
|
||||
surface_stack: scratch.frame.surface_stack.take(),
|
||||
resource_cache,
|
||||
gpu_cache,
|
||||
@ -313,6 +308,7 @@ impl FrameBuilder {
|
||||
scratch,
|
||||
data_stores,
|
||||
composite_state,
|
||||
clip_tree: &mut scene.clip_tree,
|
||||
};
|
||||
|
||||
// If we have a tile cache for this picture, see if any of the
|
||||
@ -331,9 +327,8 @@ impl FrameBuilder {
|
||||
visibility_state.push_surface(
|
||||
*pic_index,
|
||||
surface_index,
|
||||
&tile_cache.shared_clips,
|
||||
frame_context.spatial_tree,
|
||||
);
|
||||
visibility_state.clip_tree.push_clip_root_node(tile_cache.shared_clip_node_id);
|
||||
|
||||
update_prim_visibility(
|
||||
*pic_index,
|
||||
@ -354,8 +349,8 @@ impl FrameBuilder {
|
||||
&mut visibility_state,
|
||||
);
|
||||
|
||||
visibility_state.clip_tree.pop_clip_root();
|
||||
visibility_state.pop_surface();
|
||||
visibility_state.scratch.frame.clip_chain_stack = visibility_state.clip_chain_stack.take();
|
||||
visibility_state.scratch.frame.surface_stack = visibility_state.surface_stack.take();
|
||||
}
|
||||
_ => {
|
||||
|
@ -3,17 +3,16 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use api::{BorderRadius, ClipMode, HitTestResultItem, HitTestResult, ItemTag, PrimitiveFlags};
|
||||
use api::{PipelineId, ApiHitTester, ClipId};
|
||||
use api::{PipelineId, ApiHitTester};
|
||||
use api::units::*;
|
||||
use crate::clip::{ClipItemKind, ClipStore, ClipNode, rounded_rectangle_contains_point};
|
||||
use crate::clip::{polygon_contains_point};
|
||||
use crate::clip::{rounded_rectangle_contains_point, ClipNodeId, ClipTreeBuilder};
|
||||
use crate::clip::{polygon_contains_point, ClipItemKey, ClipItemKeyKind};
|
||||
use crate::prim_store::PolygonKey;
|
||||
use crate::scene_builder_thread::Interners;
|
||||
use crate::spatial_tree::{SpatialNodeIndex, SpatialTree, get_external_scroll_offset};
|
||||
use crate::internal_types::{FastHashMap, FastHashSet, LayoutPrimitiveInfo};
|
||||
use std::ops;
|
||||
use crate::internal_types::{FastHashMap, LayoutPrimitiveInfo};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use crate::util::{LayoutToWorldFastTransform, VecHelper};
|
||||
use crate::util::{LayoutToWorldFastTransform};
|
||||
|
||||
pub struct SharedHitTester {
|
||||
// We don't really need a mutex here. We could do with some sort of
|
||||
@ -74,36 +73,39 @@ struct HitTestClipNode {
|
||||
region: HitTestRegion,
|
||||
/// The positioning node for this clip
|
||||
spatial_node_index: SpatialNodeIndex,
|
||||
/// Parent clip node
|
||||
parent: ClipNodeId,
|
||||
}
|
||||
|
||||
impl HitTestClipNode {
|
||||
fn new(
|
||||
node: ClipNode,
|
||||
spatial_node_index: SpatialNodeIndex,
|
||||
item: &ClipItemKey,
|
||||
interners: &Interners,
|
||||
parent: ClipNodeId,
|
||||
) -> Self {
|
||||
let region = match node.item.kind {
|
||||
ClipItemKind::Rectangle { rect, mode } => {
|
||||
HitTestRegion::Rectangle(rect, mode)
|
||||
let region = match item.kind {
|
||||
ClipItemKeyKind::Rectangle(rect, mode) => {
|
||||
HitTestRegion::Rectangle(rect.into(), mode)
|
||||
}
|
||||
ClipItemKind::RoundedRectangle { rect, radius, mode } => {
|
||||
HitTestRegion::RoundedRectangle(rect, radius, mode)
|
||||
ClipItemKeyKind::RoundedRectangle(rect, radius, mode) => {
|
||||
HitTestRegion::RoundedRectangle(rect.into(), radius.into(), mode)
|
||||
}
|
||||
ClipItemKind::Image { rect, polygon_handle, .. } => {
|
||||
ClipItemKeyKind::ImageMask(rect, _, _, polygon_handle) => {
|
||||
if let Some(handle) = polygon_handle {
|
||||
// Retrieve the polygon data from the interner.
|
||||
let polygon = &interners.polygon[handle];
|
||||
HitTestRegion::Polygon(rect, *polygon)
|
||||
HitTestRegion::Polygon(rect.into(), *polygon)
|
||||
} else {
|
||||
HitTestRegion::Rectangle(rect, ClipMode::Clip)
|
||||
HitTestRegion::Rectangle(rect.into(), ClipMode::Clip)
|
||||
}
|
||||
}
|
||||
ClipItemKind::BoxShadow { .. } => HitTestRegion::Invalid,
|
||||
ClipItemKeyKind::BoxShadow(..) => HitTestRegion::Invalid,
|
||||
};
|
||||
|
||||
HitTestClipNode {
|
||||
region,
|
||||
spatial_node_index,
|
||||
spatial_node_index: item.spatial_node_index,
|
||||
parent,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -111,13 +113,11 @@ impl HitTestClipNode {
|
||||
#[derive(Clone, MallocSizeOf)]
|
||||
struct HitTestingItem {
|
||||
rect: LayoutRect,
|
||||
clip_rect: LayoutRect,
|
||||
tag: ItemTag,
|
||||
animation_id: u64,
|
||||
is_backface_visible: bool,
|
||||
spatial_node_index: SpatialNodeIndex,
|
||||
#[ignore_malloc_size_of = "Range"]
|
||||
clip_nodes_range: ops::Range<ClipNodeIndex>,
|
||||
clip_node_id: ClipNodeId,
|
||||
}
|
||||
|
||||
impl HitTestingItem {
|
||||
@ -126,16 +126,15 @@ impl HitTestingItem {
|
||||
animation_id: u64,
|
||||
info: &LayoutPrimitiveInfo,
|
||||
spatial_node_index: SpatialNodeIndex,
|
||||
clip_nodes_range: ops::Range<ClipNodeIndex>,
|
||||
clip_node_id: ClipNodeId,
|
||||
) -> HitTestingItem {
|
||||
HitTestingItem {
|
||||
rect: info.rect,
|
||||
clip_rect: info.clip_rect,
|
||||
tag,
|
||||
animation_id,
|
||||
is_backface_visible: info.flags.contains(PrimitiveFlags::IS_BACKFACE_VISIBLE),
|
||||
spatial_node_index,
|
||||
clip_nodes_range,
|
||||
clip_node_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -167,25 +166,10 @@ pub struct ClipNodeIndex(u32);
|
||||
/// hit tester instances via Arc.
|
||||
#[derive(MallocSizeOf)]
|
||||
pub struct HitTestingScene {
|
||||
/// Packed array of all hit test clip nodes
|
||||
clip_nodes: Vec<HitTestClipNode>,
|
||||
clip_nodes: FastHashMap<ClipNodeId, HitTestClipNode>,
|
||||
|
||||
/// List of hit testing primitives.
|
||||
items: Vec<HitTestingItem>,
|
||||
|
||||
/// Current stack of clip ids from stacking context
|
||||
#[ignore_malloc_size_of = "ClipId"]
|
||||
clip_id_stack: Vec<ClipId>,
|
||||
|
||||
/// Last cached clip id, useful for scenes with a lot
|
||||
/// of hit-test items that reference the same clip
|
||||
#[ignore_malloc_size_of = "simple"]
|
||||
cached_clip_id: Option<(ClipId, ops::Range<ClipNodeIndex>)>,
|
||||
|
||||
/// Temporary buffer used to de-duplicate clip ids when creating hit
|
||||
/// test clip nodes.
|
||||
#[ignore_malloc_size_of = "ClipId"]
|
||||
seen_clips: FastHashSet<ClipId>,
|
||||
}
|
||||
|
||||
impl HitTestingScene {
|
||||
@ -193,22 +177,49 @@ impl HitTestingScene {
|
||||
/// provided by previous scene stats.
|
||||
pub fn new(stats: &HitTestingSceneStats) -> Self {
|
||||
HitTestingScene {
|
||||
clip_nodes: Vec::with_capacity(stats.clip_nodes_count),
|
||||
clip_nodes: FastHashMap::default(),
|
||||
items: Vec::with_capacity(stats.items_count),
|
||||
clip_id_stack: Vec::with_capacity(8),
|
||||
cached_clip_id: None,
|
||||
seen_clips: FastHashSet::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get stats about the current scene allocation sizes.
|
||||
pub fn get_stats(&self) -> HitTestingSceneStats {
|
||||
HitTestingSceneStats {
|
||||
clip_nodes_count: self.clip_nodes.len(),
|
||||
clip_nodes_count: 0,
|
||||
items_count: self.items.len(),
|
||||
}
|
||||
}
|
||||
|
||||
fn add_clip_node(
|
||||
&mut self,
|
||||
clip_node_id: ClipNodeId,
|
||||
clip_tree_builder: &ClipTreeBuilder,
|
||||
interners: &Interners,
|
||||
) {
|
||||
if clip_node_id == ClipNodeId::NONE {
|
||||
return;
|
||||
}
|
||||
|
||||
if !self.clip_nodes.contains_key(&clip_node_id) {
|
||||
let src_clip_node = clip_tree_builder.get_node(clip_node_id);
|
||||
let clip_item = &interners.clip[src_clip_node.handle];
|
||||
|
||||
let clip_node = HitTestClipNode::new(
|
||||
&clip_item.key,
|
||||
interners,
|
||||
src_clip_node.parent,
|
||||
);
|
||||
|
||||
self.clip_nodes.insert(clip_node_id, clip_node);
|
||||
|
||||
self.add_clip_node(
|
||||
src_clip_node.parent,
|
||||
clip_tree_builder,
|
||||
interners,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a hit testing primitive.
|
||||
pub fn add_item(
|
||||
&mut self,
|
||||
@ -216,84 +227,26 @@ impl HitTestingScene {
|
||||
anim_id: u64,
|
||||
info: &LayoutPrimitiveInfo,
|
||||
spatial_node_index: SpatialNodeIndex,
|
||||
clip_id: ClipId,
|
||||
clip_store: &ClipStore,
|
||||
clip_node_id: ClipNodeId,
|
||||
clip_tree_builder: &ClipTreeBuilder,
|
||||
interners: &Interners,
|
||||
) {
|
||||
let clip_range = match self.cached_clip_id {
|
||||
Some((cached_clip_id, ref range)) if cached_clip_id == clip_id => {
|
||||
range.clone()
|
||||
}
|
||||
Some(_) | None => {
|
||||
let start = ClipNodeIndex(self.clip_nodes.len() as u32);
|
||||
|
||||
// Clear the set of which clip ids have been encountered for this item
|
||||
self.seen_clips.clear();
|
||||
|
||||
// Flatten all clips from the stacking context hierarchy
|
||||
for clip_id in &self.clip_id_stack {
|
||||
add_clips(
|
||||
*clip_id,
|
||||
clip_store,
|
||||
&mut self.clip_nodes,
|
||||
&mut self.seen_clips,
|
||||
interners,
|
||||
);
|
||||
}
|
||||
|
||||
// Add the primitive clip
|
||||
add_clips(
|
||||
clip_id,
|
||||
clip_store,
|
||||
&mut self.clip_nodes,
|
||||
&mut self.seen_clips,
|
||||
interners,
|
||||
);
|
||||
|
||||
let end = ClipNodeIndex(self.clip_nodes.len() as u32);
|
||||
|
||||
let range = ops::Range {
|
||||
start,
|
||||
end,
|
||||
};
|
||||
|
||||
self.cached_clip_id = Some((clip_id, range.clone()));
|
||||
|
||||
range
|
||||
}
|
||||
};
|
||||
self.add_clip_node(
|
||||
clip_node_id,
|
||||
clip_tree_builder,
|
||||
interners,
|
||||
);
|
||||
|
||||
let item = HitTestingItem::new(
|
||||
tag,
|
||||
anim_id,
|
||||
info,
|
||||
spatial_node_index,
|
||||
clip_range,
|
||||
clip_node_id,
|
||||
);
|
||||
|
||||
self.items.push(item);
|
||||
}
|
||||
|
||||
/// Push a clip onto the current stack
|
||||
pub fn push_clip(
|
||||
&mut self,
|
||||
clip_id: ClipId,
|
||||
) {
|
||||
// Invalidate the cache since the stack may affect the produced hit test clip struct
|
||||
self.cached_clip_id = None;
|
||||
|
||||
self.clip_id_stack.push(clip_id);
|
||||
}
|
||||
|
||||
/// Pop a clip from the current stack
|
||||
pub fn pop_clip(
|
||||
&mut self,
|
||||
) {
|
||||
// Invalidate the cache since the stack may affect the produced hit test clip struct
|
||||
self.cached_clip_id = None;
|
||||
|
||||
self.clip_id_stack.pop().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(MallocSizeOf)]
|
||||
@ -407,27 +360,28 @@ impl HitTester {
|
||||
continue;
|
||||
}
|
||||
|
||||
if !item.clip_rect.contains(point_in_layer) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// See if any of the clips for this primitive cull out the item.
|
||||
let clip_nodes = &self.scene.clip_nodes[item.clip_nodes_range.start.0 as usize .. item.clip_nodes_range.end.0 as usize];
|
||||
let is_valid = clip_nodes.iter().all(|clip_node| {
|
||||
let mut current_clip_node_id = item.clip_node_id;
|
||||
let mut is_valid = true;
|
||||
|
||||
while current_clip_node_id != ClipNodeId::NONE {
|
||||
let clip_node = &self.scene.clip_nodes[¤t_clip_node_id];
|
||||
|
||||
let transform = self
|
||||
.spatial_nodes[&clip_node.spatial_node_index]
|
||||
.world_content_transform;
|
||||
let transformed_point = match transform
|
||||
if let Some(transformed_point) = transform
|
||||
.inverse()
|
||||
.and_then(|inverted| inverted.project_point2d(test.point))
|
||||
{
|
||||
Some(point) => point,
|
||||
// XXX This `return true` is a bit sketchy, but matches
|
||||
// pre-existing behavior.
|
||||
None => return true,
|
||||
};
|
||||
clip_node.region.contains(&transformed_point)
|
||||
});
|
||||
if !clip_node.region.contains(&transformed_point) {
|
||||
is_valid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
current_clip_node_id = clip_node.parent;
|
||||
}
|
||||
|
||||
if !is_valid {
|
||||
continue;
|
||||
@ -464,45 +418,3 @@ impl HitTest {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Collect clips for a given ClipId, convert and add them to the hit testing
|
||||
/// scene, if not already present.
|
||||
fn add_clips(
|
||||
clip_id: ClipId,
|
||||
clip_store: &ClipStore,
|
||||
clip_nodes: &mut Vec<HitTestClipNode>,
|
||||
seen_clips: &mut FastHashSet<ClipId>,
|
||||
interners: &Interners,
|
||||
) {
|
||||
// If this clip-id has already been added to this hit-test item, skip it
|
||||
if seen_clips.contains(&clip_id) {
|
||||
return;
|
||||
}
|
||||
seen_clips.insert(clip_id);
|
||||
|
||||
let template = &clip_store.templates[&clip_id];
|
||||
let instances = &clip_store.instances[template.clips.start as usize .. template.clips.end as usize];
|
||||
|
||||
for clip in instances {
|
||||
clip_nodes.alloc().init(
|
||||
HitTestClipNode::new(
|
||||
clip.key.into(),
|
||||
clip.key.spatial_node_index,
|
||||
interners,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// The ClipId parenting is terminated when we reach the root ClipId
|
||||
if let Some(parent) = template.parent {
|
||||
if clip_id != parent {
|
||||
add_clips(
|
||||
parent,
|
||||
clip_store,
|
||||
clip_nodes,
|
||||
seen_clips,
|
||||
interners,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -137,6 +137,8 @@ impl<I> Handle<I> {
|
||||
uid: ((self.index as u64) << 32) | self.epoch.0 as u64
|
||||
}
|
||||
}
|
||||
|
||||
pub const INVALID: Self = Handle { index: !0, epoch: Epoch(!0), _marker: PhantomData };
|
||||
}
|
||||
|
||||
pub trait InternDebug {
|
||||
|
@ -100,7 +100,7 @@ use api::{DebugFlags, ImageKey, ColorF, ColorU, PrimitiveFlags};
|
||||
use api::{ImageRendering, ColorDepth, YuvRangedColorSpace, YuvFormat, AlphaType};
|
||||
use api::units::*;
|
||||
use crate::box_shadow::BLUR_SAMPLE_SCALE;
|
||||
use crate::clip::{ClipStore, ClipChainInstance, ClipChainId, ClipInstance};
|
||||
use crate::clip::{ClipStore, ClipChainInstance, ClipLeafId, ClipNodeId, ClipTreeBuilder};
|
||||
use crate::spatial_tree::{SpatialTree, CoordinateSpaceMapping, SpatialNodeIndex, VisibleFace};
|
||||
use crate::composite::{CompositorKind, CompositeState, NativeSurfaceId, NativeTileId, CompositeTileSurface, tile_kind};
|
||||
use crate::composite::{ExternalSurfaceDescriptor, ExternalSurfaceDependency, CompositeTileDescriptor, CompositeTile};
|
||||
@ -1722,10 +1722,10 @@ pub struct TileCacheParams {
|
||||
// Optional background color of this tilecache. If present, can be used as an optimization
|
||||
// to enable opaque blending and/or subpixel AA in more places.
|
||||
pub background_color: Option<ColorF>,
|
||||
// List of clips shared by all prims that are promoted to this tile cache
|
||||
pub shared_clips: Vec<ClipInstance>,
|
||||
// The clip chain handle representing `shared_clips`
|
||||
pub shared_clip_chain: ClipChainId,
|
||||
// Node in the clip-tree that defines where we exclude clips from child prims
|
||||
pub shared_clip_node_id: ClipNodeId,
|
||||
// Clip leaf that is used to build the clip-chain for this tile cache.
|
||||
pub shared_clip_leaf_id: Option<ClipLeafId>,
|
||||
// Virtual surface sizes are always square, so this represents both the width and height
|
||||
pub virtual_surface_size: i32,
|
||||
// The number of compositor surfaces that are being requested for this tile cache.
|
||||
@ -1893,14 +1893,10 @@ pub struct TileCacheInstance {
|
||||
/// The allowed subpixel mode for this surface, which depends on the detected
|
||||
/// opacity of the background.
|
||||
pub subpixel_mode: SubpixelMode,
|
||||
/// A list of clip handles that exist on every (top-level) primitive in this picture.
|
||||
/// It's often the case that these are root / fixed position clips. By handling them
|
||||
/// here, we can avoid applying them to the items, which reduces work, but more importantly
|
||||
/// reduces invalidations.
|
||||
pub shared_clips: Vec<ClipInstance>,
|
||||
/// The clip chain that represents the shared_clips above. Used to build the local
|
||||
/// clip rect for this tile cache.
|
||||
shared_clip_chain: ClipChainId,
|
||||
// Node in the clip-tree that defines where we exclude clips from child prims
|
||||
pub shared_clip_node_id: ClipNodeId,
|
||||
// Clip leaf that is used to build the clip-chain for this tile cache.
|
||||
pub shared_clip_leaf_id: Option<ClipLeafId>,
|
||||
/// The number of frames until this cache next evaluates what tile size to use.
|
||||
/// If a picture rect size is regularly changing just around a size threshold,
|
||||
/// we don't want to constantly invalidate and reallocate different tile size
|
||||
@ -1981,8 +1977,8 @@ impl TileCacheInstance {
|
||||
background_color: params.background_color,
|
||||
backdrop: BackdropInfo::empty(),
|
||||
subpixel_mode: SubpixelMode::Allow,
|
||||
shared_clips: params.shared_clips,
|
||||
shared_clip_chain: params.shared_clip_chain,
|
||||
shared_clip_node_id: params.shared_clip_node_id,
|
||||
shared_clip_leaf_id: params.shared_clip_leaf_id,
|
||||
current_tile_size: DeviceIntSize::zero(),
|
||||
frames_until_size_eval: 0,
|
||||
// Default to centering the virtual offset in the middle of the DC virtual surface
|
||||
@ -2059,8 +2055,8 @@ impl TileCacheInstance {
|
||||
self.slice_flags = params.slice_flags;
|
||||
self.spatial_node_index = params.spatial_node_index;
|
||||
self.background_color = params.background_color;
|
||||
self.shared_clips = params.shared_clips;
|
||||
self.shared_clip_chain = params.shared_clip_chain;
|
||||
self.shared_clip_leaf_id = params.shared_clip_leaf_id;
|
||||
self.shared_clip_node_id = params.shared_clip_node_id;
|
||||
|
||||
// Since the slice flags may have changed, ensure we re-evaluate the
|
||||
// appropriate tile size for this cache next update.
|
||||
@ -2150,29 +2146,19 @@ impl TileCacheInstance {
|
||||
// If there is a valid set of shared clips, build a clip chain instance for this,
|
||||
// which will provide a local clip rect. This is useful for establishing things
|
||||
// like whether the backdrop rect supplied by Gecko can be considered opaque.
|
||||
if self.shared_clip_chain != ClipChainId::NONE {
|
||||
let shared_clips = &mut frame_state.scratch.picture.clip_chain_ids;
|
||||
shared_clips.clear();
|
||||
|
||||
if let Some(shared_clip_leaf_id) = self.shared_clip_leaf_id {
|
||||
let map_local_to_surface = SpaceMapper::new(
|
||||
self.spatial_node_index,
|
||||
pic_rect,
|
||||
);
|
||||
|
||||
let mut current_clip_chain_id = self.shared_clip_chain;
|
||||
while current_clip_chain_id != ClipChainId::NONE {
|
||||
shared_clips.push(current_clip_chain_id);
|
||||
let clip_chain_node = &frame_state.clip_store.clip_chain_nodes[current_clip_chain_id.0 as usize];
|
||||
current_clip_chain_id = clip_chain_node.parent_clip_chain_id;
|
||||
}
|
||||
|
||||
frame_state.clip_store.set_active_clips(
|
||||
LayoutRect::max_rect(),
|
||||
self.spatial_node_index,
|
||||
map_local_to_surface.ref_spatial_node_index,
|
||||
&shared_clips,
|
||||
shared_clip_leaf_id,
|
||||
frame_context.spatial_tree,
|
||||
&mut frame_state.data_stores.clip,
|
||||
&frame_state.clip_tree,
|
||||
);
|
||||
|
||||
let clip_chain_instance = frame_state.clip_store.build_clip_chain_instance(
|
||||
@ -3803,14 +3789,12 @@ impl TileCacheInstance {
|
||||
|
||||
pub struct PictureScratchBuffer {
|
||||
surface_stack: Vec<SurfaceIndex>,
|
||||
clip_chain_ids: Vec<ClipChainId>,
|
||||
}
|
||||
|
||||
impl Default for PictureScratchBuffer {
|
||||
fn default() -> Self {
|
||||
PictureScratchBuffer {
|
||||
surface_stack: Vec::new(),
|
||||
clip_chain_ids: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3818,7 +3802,6 @@ impl Default for PictureScratchBuffer {
|
||||
impl PictureScratchBuffer {
|
||||
pub fn begin_frame(&mut self) {
|
||||
self.surface_stack.clear();
|
||||
self.clip_chain_ids.clear();
|
||||
}
|
||||
|
||||
pub fn recycle(&mut self, recycler: &mut Recycler) {
|
||||
@ -4388,6 +4371,7 @@ impl PrimitiveList {
|
||||
spatial_node_index: SpatialNodeIndex,
|
||||
prim_flags: PrimitiveFlags,
|
||||
prim_instances: &mut Vec<PrimitiveInstance>,
|
||||
clip_tree_builder: &ClipTreeBuilder,
|
||||
) {
|
||||
let mut flags = ClusterFlags::empty();
|
||||
|
||||
@ -4408,7 +4392,8 @@ impl PrimitiveList {
|
||||
self.compositor_surface_count += 1;
|
||||
}
|
||||
|
||||
let culling_rect = prim_instance.clip_set.local_clip_rect
|
||||
let clip_leaf = clip_tree_builder.get_leaf(prim_instance.clip_leaf_id);
|
||||
let culling_rect = clip_leaf.local_clip_rect
|
||||
.intersection(&prim_rect)
|
||||
.unwrap_or_else(LayoutRect::zero);
|
||||
|
||||
@ -4470,9 +4455,6 @@ pub struct PicturePrimitive {
|
||||
/// List of primitives, and associated info for this picture.
|
||||
pub prim_list: PrimitiveList,
|
||||
|
||||
/// If true, apply the local clip rect to primitive drawn
|
||||
/// in this picture.
|
||||
pub apply_local_clip_rect: bool,
|
||||
/// If false and transform ends up showing the back of the picture,
|
||||
/// it will be considered invisible.
|
||||
pub is_backface_visible: bool,
|
||||
@ -4607,7 +4589,6 @@ impl PicturePrimitive {
|
||||
pub fn new_image(
|
||||
composite_mode: Option<PictureCompositeMode>,
|
||||
context_3d: Picture3DContext<OrderedPictureChild>,
|
||||
apply_local_clip_rect: bool,
|
||||
prim_flags: PrimitiveFlags,
|
||||
prim_list: PrimitiveList,
|
||||
spatial_node_index: SpatialNodeIndex,
|
||||
@ -4622,7 +4603,6 @@ impl PicturePrimitive {
|
||||
raster_config: None,
|
||||
context_3d,
|
||||
extra_gpu_data_handles: SmallVec::new(),
|
||||
apply_local_clip_rect,
|
||||
is_backface_visible: prim_flags.contains(PrimitiveFlags::IS_BACKFACE_VISIBLE),
|
||||
spatial_node_index,
|
||||
prev_local_rect: LayoutRect::zero(),
|
||||
@ -5827,7 +5807,6 @@ impl PicturePrimitive {
|
||||
|
||||
let context = PictureContext {
|
||||
pic_index,
|
||||
apply_local_clip_rect: self.apply_local_clip_rect,
|
||||
raster_spatial_node_index: frame_state.surfaces[surface_index.0].raster_spatial_node_index,
|
||||
surface_spatial_node_index,
|
||||
surface_index,
|
||||
|
@ -753,7 +753,7 @@ fn prepare_interned_prim_for_render(
|
||||
frame_context.spatial_tree,
|
||||
prim_spatial_node_index,
|
||||
local_prim_rect,
|
||||
&prim_instance.vis.combined_local_clip_rect,
|
||||
&prim_instance.vis.clip_chain.local_clip_rect,
|
||||
dirty_rect,
|
||||
plane_split_anchor,
|
||||
);
|
||||
@ -852,7 +852,8 @@ fn decompose_repeated_gradient(
|
||||
// produce primitives that are partially covering the original image
|
||||
// rect and we want to clip these extra parts out.
|
||||
if let Some(tight_clip_rect) = prim_vis
|
||||
.combined_local_clip_rect
|
||||
.clip_chain
|
||||
.local_clip_rect
|
||||
.intersection(prim_local_rect) {
|
||||
|
||||
let visible_rect = compute_conservative_visible_rect(
|
||||
@ -1218,7 +1219,6 @@ pub fn update_brush_segment_clip_task(
|
||||
|
||||
fn write_brush_segment_description(
|
||||
prim_local_rect: LayoutRect,
|
||||
prim_local_clip_rect: LayoutRect,
|
||||
clip_chain: &ClipChainInstance,
|
||||
segment_builder: &mut SegmentBuilder,
|
||||
clip_store: &ClipStore,
|
||||
@ -1233,7 +1233,7 @@ fn write_brush_segment_description(
|
||||
segment_builder.initialize(
|
||||
prim_local_rect,
|
||||
None,
|
||||
prim_local_clip_rect
|
||||
clip_chain.local_clip_rect
|
||||
);
|
||||
|
||||
// Segment the primitive on all the local-space clip sources that we can.
|
||||
@ -1378,7 +1378,6 @@ fn build_segments_if_needed(
|
||||
|
||||
if write_brush_segment_description(
|
||||
prim_local_rect,
|
||||
instance.clip_set.local_clip_rect,
|
||||
prim_clip_chain,
|
||||
&mut frame_state.segment_builder,
|
||||
frame_state.clip_store,
|
||||
|
@ -302,7 +302,8 @@ impl ImageData {
|
||||
// produce primitives that are partially covering the original image
|
||||
// rect and we want to clip these extra parts out.
|
||||
let tight_clip_rect = visibility
|
||||
.combined_local_clip_rect
|
||||
.clip_chain
|
||||
.local_clip_rect
|
||||
.intersection(&common.prim_rect).unwrap();
|
||||
image_instance.tight_local_clip_rect = tight_clip_rect;
|
||||
|
||||
|
@ -9,9 +9,9 @@ use api::{PrimitiveKeyKind, FillRule, POLYGON_CLIP_VERTEX_MAX};
|
||||
use api::units::*;
|
||||
use euclid::{SideOffsets2D, Size2D};
|
||||
use malloc_size_of::MallocSizeOf;
|
||||
use crate::clip::ClipLeafId;
|
||||
use crate::segment::EdgeAaSegmentMask;
|
||||
use crate::border::BorderSegmentCacheKey;
|
||||
use crate::clip::{ClipChainId, ClipSet};
|
||||
use crate::debug_item::{DebugItem, DebugMessage};
|
||||
use crate::debug_colors;
|
||||
use crate::scene_building::{CreateShadow, IsVisible};
|
||||
@ -1072,28 +1072,23 @@ pub struct PrimitiveInstance {
|
||||
pub kind: PrimitiveInstanceKind,
|
||||
|
||||
/// All information and state related to clip(s) for this primitive
|
||||
pub clip_set: ClipSet,
|
||||
pub clip_leaf_id: ClipLeafId,
|
||||
|
||||
/// Information related to the current visibility state of this
|
||||
/// primitive.
|
||||
// TODO(gw): Currently built each frame, but can be retained.
|
||||
// TODO(gw): Remove clipped_world_rect (use tile bounds to determine vis flags)
|
||||
pub vis: PrimitiveVisibility,
|
||||
}
|
||||
|
||||
impl PrimitiveInstance {
|
||||
pub fn new(
|
||||
local_clip_rect: LayoutRect,
|
||||
kind: PrimitiveInstanceKind,
|
||||
clip_chain_id: ClipChainId,
|
||||
clip_leaf_id: ClipLeafId,
|
||||
) -> Self {
|
||||
PrimitiveInstance {
|
||||
kind,
|
||||
vis: PrimitiveVisibility::new(),
|
||||
clip_set: ClipSet {
|
||||
local_clip_rect,
|
||||
clip_chain_id,
|
||||
},
|
||||
clip_leaf_id,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1444,7 +1439,7 @@ fn test_struct_sizes() {
|
||||
// test expectations and move on.
|
||||
// (b) You made a structure larger. This is not necessarily a problem, but should only
|
||||
// be done with care, and after checking if talos performance regresses badly.
|
||||
assert_eq!(mem::size_of::<PrimitiveInstance>(), 136, "PrimitiveInstance size changed");
|
||||
assert_eq!(mem::size_of::<PrimitiveInstance>(), 104, "PrimitiveInstance size changed");
|
||||
assert_eq!(mem::size_of::<PrimitiveInstanceKind>(), 24, "PrimitiveInstanceKind size changed");
|
||||
assert_eq!(mem::size_of::<PrimitiveTemplate>(), 56, "PrimitiveTemplate size changed");
|
||||
assert_eq!(mem::size_of::<PrimitiveTemplateKind>(), 28, "PrimitiveTemplateKind size changed");
|
||||
|
@ -8,7 +8,7 @@ use api::units::*;
|
||||
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
|
||||
use crate::render_api::MemoryReport;
|
||||
use crate::composite::CompositorKind;
|
||||
use crate::clip::{ClipStore, ClipStoreStats};
|
||||
use crate::clip::{ClipStore, ClipTree};
|
||||
use crate::spatial_tree::SpatialTree;
|
||||
use crate::frame_builder::{FrameBuilderConfig};
|
||||
use crate::hit_test::{HitTester, HitTestingScene, HitTestingSceneStats};
|
||||
@ -292,6 +292,7 @@ pub struct BuiltScene {
|
||||
pub plane_splitters: Vec<PlaneSplitter>,
|
||||
pub prim_instances: Vec<PrimitiveInstance>,
|
||||
pub surfaces: Vec<SurfaceInfo>,
|
||||
pub clip_tree: ClipTree,
|
||||
}
|
||||
|
||||
impl BuiltScene {
|
||||
@ -302,7 +303,7 @@ impl BuiltScene {
|
||||
output_rect: DeviceIntRect::zero(),
|
||||
background_color: None,
|
||||
prim_store: PrimitiveStore::new(&PrimitiveStoreStats::empty()),
|
||||
clip_store: ClipStore::new(&ClipStoreStats::empty()),
|
||||
clip_store: ClipStore::new(),
|
||||
hit_testing_scene: Arc::new(HitTestingScene::new(&HitTestingSceneStats::empty())),
|
||||
tile_cache_config: TileCacheConfig::new(0),
|
||||
tile_cache_pictures: Vec::new(),
|
||||
@ -310,6 +311,7 @@ impl BuiltScene {
|
||||
plane_splitters: Vec::new(),
|
||||
prim_instances: Vec::new(),
|
||||
surfaces: Vec::new(),
|
||||
clip_tree: ClipTree::new(),
|
||||
config: FrameBuilderConfig {
|
||||
default_font_render_mode: FontRenderMode::Mono,
|
||||
dual_source_blending_is_enabled: true,
|
||||
@ -339,7 +341,6 @@ impl BuiltScene {
|
||||
SceneStats {
|
||||
prim_store_stats: self.prim_store.get_stats(),
|
||||
hit_test_stats: self.hit_testing_scene.get_stats(),
|
||||
clip_store_stats: self.clip_store.get_stats(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -361,7 +362,6 @@ impl BuiltScene {
|
||||
pub struct SceneStats {
|
||||
pub prim_store_stats: PrimitiveStoreStats,
|
||||
pub hit_test_stats: HitTestingSceneStats,
|
||||
pub clip_store_stats: ClipStoreStats,
|
||||
}
|
||||
|
||||
impl SceneStats {
|
||||
@ -369,7 +369,6 @@ impl SceneStats {
|
||||
SceneStats {
|
||||
prim_store_stats: PrimitiveStoreStats::empty(),
|
||||
hit_test_stats: HitTestingSceneStats::empty(),
|
||||
clip_store_stats: ClipStoreStats::empty(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -2,9 +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/. */
|
||||
|
||||
use api::{ColorF, PrimitiveFlags, QualitySettings, RasterSpace};
|
||||
use api::{ColorF, PrimitiveFlags, QualitySettings, RasterSpace, ClipId};
|
||||
use api::units::*;
|
||||
use crate::clip::{ClipChainId, ClipNodeKind, ClipStore, ClipInstance};
|
||||
use crate::clip::{ClipNodeKind, ClipLeafId, ClipNodeId, ClipTreeBuilder};
|
||||
use crate::frame_builder::FrameBuilderConfig;
|
||||
use crate::internal_types::{FastHashMap};
|
||||
use crate::picture::{PrimitiveList, PictureCompositeMode, PicturePrimitive, SliceId};
|
||||
@ -34,7 +34,7 @@ const MAX_CACHE_SLICES: usize = 12;
|
||||
struct SliceDescriptor {
|
||||
prim_list: PrimitiveList,
|
||||
scroll_root: SpatialNodeIndex,
|
||||
shared_clips: Vec<ClipInstance>,
|
||||
shared_clip_node_id: ClipNodeId,
|
||||
}
|
||||
|
||||
enum SliceKind {
|
||||
@ -60,17 +60,15 @@ struct PrimarySlice {
|
||||
/// Optional background color of this slice
|
||||
background_color: Option<ColorF>,
|
||||
/// Optional root clip for the iframe
|
||||
iframe_clip: Option<ClipChainId>,
|
||||
iframe_clip: Option<ClipId>,
|
||||
/// Information about how to draw and composite this slice
|
||||
slice_flags: SliceFlags,
|
||||
/// Wrapping clip-chain for this slice
|
||||
clip_chain_id: ClipChainId,
|
||||
}
|
||||
|
||||
impl PrimarySlice {
|
||||
fn new(
|
||||
slice_flags: SliceFlags,
|
||||
iframe_clip: Option<ClipChainId>,
|
||||
iframe_clip: Option<ClipId>,
|
||||
background_color: Option<ColorF>,
|
||||
) -> Self {
|
||||
PrimarySlice {
|
||||
@ -78,21 +76,18 @@ impl PrimarySlice {
|
||||
background_color,
|
||||
iframe_clip,
|
||||
slice_flags,
|
||||
clip_chain_id: ClipChainId::NONE,
|
||||
}
|
||||
}
|
||||
|
||||
fn atomic(
|
||||
prim_list: PrimitiveList,
|
||||
iframe_clip: Option<ClipChainId>,
|
||||
clip_chain_id: ClipChainId,
|
||||
iframe_clip: Option<ClipId>,
|
||||
) -> Self {
|
||||
PrimarySlice {
|
||||
kind: SliceKind::Atomic { prim_list },
|
||||
background_color: None,
|
||||
iframe_clip,
|
||||
slice_flags: SliceFlags::IS_ATOMIC,
|
||||
clip_chain_id,
|
||||
}
|
||||
}
|
||||
|
||||
@ -134,10 +129,6 @@ pub struct TileCacheBuilder {
|
||||
primary_slices: Vec<PrimarySlice>,
|
||||
/// Cache the previous scroll root search for a spatial node, since they are often the same.
|
||||
prev_scroll_root_cache: (SpatialNodeIndex, SpatialNodeIndex),
|
||||
/// A buffer for collecting clips for a clip-chain. Retained here to avoid memory allocations in add_prim.
|
||||
prim_clips_buffer: Vec<ClipInstance>,
|
||||
/// Cache the last clip-chain that was added to the shared clips as it's often the same between prims.
|
||||
last_checked_clip_chain: ClipChainId,
|
||||
/// Handle to the root reference frame
|
||||
root_spatial_node_index: SpatialNodeIndex,
|
||||
}
|
||||
@ -170,8 +161,6 @@ impl TileCacheBuilder {
|
||||
TileCacheBuilder {
|
||||
primary_slices: vec![PrimarySlice::new(SliceFlags::empty(), None, background_color)],
|
||||
prev_scroll_root_cache: (SpatialNodeIndex::INVALID, SpatialNodeIndex::INVALID),
|
||||
prim_clips_buffer: Vec::new(),
|
||||
last_checked_clip_chain: ClipChainId::INVALID,
|
||||
root_spatial_node_index,
|
||||
}
|
||||
}
|
||||
@ -187,7 +176,7 @@ impl TileCacheBuilder {
|
||||
pub fn add_tile_cache_barrier(
|
||||
&mut self,
|
||||
slice_flags: SliceFlags,
|
||||
iframe_clip: Option<ClipChainId>,
|
||||
iframe_clip: Option<ClipId>,
|
||||
) {
|
||||
let new_slice = PrimarySlice::new(
|
||||
slice_flags,
|
||||
@ -202,13 +191,11 @@ impl TileCacheBuilder {
|
||||
pub fn add_tile_cache(
|
||||
&mut self,
|
||||
prim_list: PrimitiveList,
|
||||
clip_chain_id: ClipChainId,
|
||||
iframe_clip: Option<ClipChainId>,
|
||||
iframe_clip: Option<ClipId>,
|
||||
) {
|
||||
let atomic_slice = PrimarySlice::atomic(
|
||||
prim_list,
|
||||
iframe_clip,
|
||||
clip_chain_id,
|
||||
);
|
||||
|
||||
let next_slice = PrimarySlice::new(
|
||||
@ -225,11 +212,9 @@ impl TileCacheBuilder {
|
||||
fn build_tile_cache(
|
||||
&mut self,
|
||||
prim_list: PrimitiveList,
|
||||
clip_chain_id: ClipChainId,
|
||||
spatial_tree: &SceneSpatialTree,
|
||||
clip_store: &ClipStore,
|
||||
interners: &Interners,
|
||||
prim_instances: &[PrimitiveInstance],
|
||||
clip_tree_builder: &ClipTreeBuilder,
|
||||
) -> Option<SliceDescriptor> {
|
||||
if prim_list.is_empty() {
|
||||
return None;
|
||||
@ -293,73 +278,33 @@ impl TileCacheBuilder {
|
||||
.map(|(spatial_node_index, _)| *spatial_node_index)
|
||||
.unwrap_or(self.root_spatial_node_index);
|
||||
|
||||
let mut first = true;
|
||||
let prim_clips_buffer = &mut self.prim_clips_buffer;
|
||||
let mut shared_clips = Vec::new();
|
||||
|
||||
// Work out which clips are shared by all prim instances and can thus be applied
|
||||
// at the tile cache level. In future, we aim to remove this limitation by knowing
|
||||
// during initial scene build which are the relevant compositor clips, but for now
|
||||
// this is unlikely to be a significant cost.
|
||||
let mut shared_clip_node_id = None;
|
||||
|
||||
for cluster in &prim_list.clusters {
|
||||
for prim_instance in &prim_instances[cluster.prim_range()] {
|
||||
if first {
|
||||
add_clips(
|
||||
scroll_root,
|
||||
prim_instance.clip_set.clip_chain_id,
|
||||
&mut shared_clips,
|
||||
clip_store,
|
||||
interners,
|
||||
spatial_tree,
|
||||
);
|
||||
let leaf = clip_tree_builder.get_leaf(prim_instance.clip_leaf_id);
|
||||
|
||||
self.last_checked_clip_chain = prim_instance.clip_set.clip_chain_id;
|
||||
first = false;
|
||||
} else {
|
||||
if self.last_checked_clip_chain != prim_instance.clip_set.clip_chain_id {
|
||||
prim_clips_buffer.clear();
|
||||
|
||||
add_clips(
|
||||
scroll_root,
|
||||
prim_instance.clip_set.clip_chain_id,
|
||||
prim_clips_buffer,
|
||||
clip_store,
|
||||
interners,
|
||||
spatial_tree,
|
||||
);
|
||||
|
||||
shared_clips.retain(|h1: &ClipInstance| {
|
||||
let uid = h1.handle.uid();
|
||||
prim_clips_buffer.iter().any(|h2| {
|
||||
uid == h2.handle.uid()
|
||||
})
|
||||
});
|
||||
|
||||
self.last_checked_clip_chain = prim_instance.clip_set.clip_chain_id;
|
||||
// TODO(gw): Need to cache last clip-node id here?
|
||||
shared_clip_node_id = match shared_clip_node_id {
|
||||
Some(current) => {
|
||||
Some(clip_tree_builder.find_lowest_common_ancestor(current, leaf.node_id))
|
||||
}
|
||||
None => {
|
||||
Some(leaf.node_id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If a blend-container has any clips on the stacking context we are removing,
|
||||
// we need to ensure those clips are added to the shared clips applied to the
|
||||
// tile cache we are creating.
|
||||
let mut current_clip_chain_id = clip_chain_id;
|
||||
while current_clip_chain_id != ClipChainId::NONE {
|
||||
let clip_chain_node = &clip_store
|
||||
.clip_chain_nodes[current_clip_chain_id.0 as usize];
|
||||
|
||||
let clip_node_data = &interners.clip[clip_chain_node.handle];
|
||||
if let ClipNodeKind::Rectangle = clip_node_data.clip_node_kind {
|
||||
shared_clips.push(ClipInstance::new(clip_chain_node.handle));
|
||||
}
|
||||
|
||||
current_clip_chain_id = clip_chain_node.parent_clip_chain_id;
|
||||
}
|
||||
let shared_clip_node_id = shared_clip_node_id.expect("bug: no shared clip root");
|
||||
|
||||
Some(SliceDescriptor {
|
||||
scroll_root,
|
||||
shared_clips,
|
||||
shared_clip_node_id,
|
||||
prim_list,
|
||||
})
|
||||
}
|
||||
@ -372,10 +317,10 @@ impl TileCacheBuilder {
|
||||
spatial_node_index: SpatialNodeIndex,
|
||||
prim_flags: PrimitiveFlags,
|
||||
spatial_tree: &SceneSpatialTree,
|
||||
clip_store: &ClipStore,
|
||||
interners: &Interners,
|
||||
quality_settings: &QualitySettings,
|
||||
prim_instances: &mut Vec<PrimitiveInstance>,
|
||||
clip_tree_builder: &ClipTreeBuilder,
|
||||
) {
|
||||
let primary_slice = self.primary_slices.last_mut().unwrap();
|
||||
|
||||
@ -387,6 +332,7 @@ impl TileCacheBuilder {
|
||||
spatial_node_index,
|
||||
prim_flags,
|
||||
prim_instances,
|
||||
clip_tree_builder,
|
||||
);
|
||||
}
|
||||
SliceKind::Default { ref mut secondary_slices } => {
|
||||
@ -429,21 +375,27 @@ impl TileCacheBuilder {
|
||||
// slices, the intra-slice dirty rect handling typically works quite well
|
||||
// (a common case is parallax scrolling effects).
|
||||
let mut create_slice = true;
|
||||
let mut current_clip_chain_id = prim_instance.clip_set.clip_chain_id;
|
||||
|
||||
while current_clip_chain_id != ClipChainId::NONE {
|
||||
let clip_chain_node = &clip_store.clip_chain_nodes[current_clip_chain_id.0 as usize];
|
||||
let clip_node_data = &interners.clip[clip_chain_node.handle];
|
||||
let leaf = clip_tree_builder.get_leaf(prim_instance.clip_leaf_id);
|
||||
let mut current_node_id = leaf.node_id;
|
||||
|
||||
while current_node_id != ClipNodeId::NONE {
|
||||
let node = clip_tree_builder.get_node(current_node_id);
|
||||
|
||||
let clip_node_data = &interners.clip[node.handle];
|
||||
|
||||
let spatial_root = find_scroll_root(
|
||||
clip_node_data.spatial_node_index,
|
||||
clip_node_data.key.spatial_node_index,
|
||||
&mut self.prev_scroll_root_cache,
|
||||
spatial_tree,
|
||||
);
|
||||
|
||||
if spatial_root != self.root_spatial_node_index {
|
||||
create_slice = false;
|
||||
break;
|
||||
}
|
||||
current_clip_chain_id = clip_chain_node.parent_clip_chain_id;
|
||||
|
||||
current_node_id = node.parent;
|
||||
}
|
||||
|
||||
create_slice
|
||||
@ -457,51 +409,35 @@ impl TileCacheBuilder {
|
||||
|
||||
// Update the list of clips that apply to this primitive instance, to track which are the
|
||||
// shared clips for this tile cache that can be applied during compositing.
|
||||
if self.last_checked_clip_chain != prim_instance.clip_set.clip_chain_id {
|
||||
let prim_clips_buffer = &mut self.prim_clips_buffer;
|
||||
prim_clips_buffer.clear();
|
||||
add_clips(
|
||||
current_scroll_root,
|
||||
prim_instance.clip_set.clip_chain_id,
|
||||
prim_clips_buffer,
|
||||
clip_store,
|
||||
interners,
|
||||
spatial_tree,
|
||||
);
|
||||
|
||||
let current_shared_clips = &secondary_slices
|
||||
.last()
|
||||
.unwrap()
|
||||
.shared_clips;
|
||||
let shared_clip_node_id = find_shared_clip_root(
|
||||
current_scroll_root,
|
||||
prim_instance.clip_leaf_id,
|
||||
spatial_tree,
|
||||
clip_tree_builder,
|
||||
interners,
|
||||
);
|
||||
|
||||
// If the shared clips are not compatible, create a new slice.
|
||||
// TODO(gw): Does Gecko ever supply duplicate or out-of-order
|
||||
// shared clips? It doesn't seem to, but if it does,
|
||||
// we will need to be more clever here to check if
|
||||
// the shared clips are compatible.
|
||||
want_new_tile_cache |= current_shared_clips != prim_clips_buffer;
|
||||
let current_shared_clip_node_id = secondary_slices.last().unwrap().shared_clip_node_id;
|
||||
|
||||
self.last_checked_clip_chain = prim_instance.clip_set.clip_chain_id;
|
||||
}
|
||||
// If the shared clips are not compatible, create a new slice.
|
||||
want_new_tile_cache |= shared_clip_node_id != current_shared_clip_node_id;
|
||||
}
|
||||
|
||||
if want_new_tile_cache {
|
||||
let mut shared_clips = Vec::new();
|
||||
add_clips(
|
||||
scroll_root,
|
||||
prim_instance.clip_set.clip_chain_id,
|
||||
&mut shared_clips,
|
||||
clip_store,
|
||||
interners,
|
||||
spatial_tree,
|
||||
);
|
||||
|
||||
self.last_checked_clip_chain = prim_instance.clip_set.clip_chain_id;
|
||||
let shared_clip_node_id = find_shared_clip_root(
|
||||
scroll_root,
|
||||
prim_instance.clip_leaf_id,
|
||||
spatial_tree,
|
||||
clip_tree_builder,
|
||||
interners,
|
||||
);
|
||||
|
||||
secondary_slices.push(SliceDescriptor {
|
||||
prim_list: PrimitiveList::empty(),
|
||||
scroll_root,
|
||||
shared_clips,
|
||||
shared_clip_node_id,
|
||||
});
|
||||
}
|
||||
|
||||
@ -515,6 +451,7 @@ impl TileCacheBuilder {
|
||||
spatial_node_index,
|
||||
prim_flags,
|
||||
prim_instances,
|
||||
clip_tree_builder,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -524,11 +461,10 @@ impl TileCacheBuilder {
|
||||
pub fn build(
|
||||
mut self,
|
||||
config: &FrameBuilderConfig,
|
||||
clip_store: &mut ClipStore,
|
||||
prim_store: &mut PrimitiveStore,
|
||||
interners: &Interners,
|
||||
spatial_tree: &SceneSpatialTree,
|
||||
prim_instances: &[PrimitiveInstance],
|
||||
clip_tree_builder: &mut ClipTreeBuilder,
|
||||
) -> (TileCacheConfig, Vec<PictureIndex>) {
|
||||
let mut result = TileCacheConfig::new(self.primary_slices.len());
|
||||
let mut tile_cache_pictures = Vec::new();
|
||||
@ -544,11 +480,9 @@ impl TileCacheBuilder {
|
||||
SliceKind::Atomic { prim_list } => {
|
||||
if let Some(descriptor) = self.build_tile_cache(
|
||||
prim_list,
|
||||
primary_slice.clip_chain_id,
|
||||
spatial_tree,
|
||||
clip_store,
|
||||
interners,
|
||||
prim_instances,
|
||||
clip_tree_builder,
|
||||
) {
|
||||
create_tile_cache(
|
||||
primary_slice.slice_flags,
|
||||
@ -556,13 +490,12 @@ impl TileCacheBuilder {
|
||||
primary_slice.iframe_clip,
|
||||
descriptor.prim_list,
|
||||
primary_slice.background_color,
|
||||
descriptor.shared_clips,
|
||||
descriptor.shared_clip_node_id,
|
||||
prim_store,
|
||||
clip_store,
|
||||
config,
|
||||
&mut result.tile_caches,
|
||||
&mut tile_cache_pictures,
|
||||
interners,
|
||||
clip_tree_builder,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -574,13 +507,12 @@ impl TileCacheBuilder {
|
||||
primary_slice.iframe_clip,
|
||||
descriptor.prim_list,
|
||||
primary_slice.background_color,
|
||||
descriptor.shared_clips,
|
||||
descriptor.shared_clip_node_id,
|
||||
prim_store,
|
||||
clip_store,
|
||||
config,
|
||||
&mut result.tile_caches,
|
||||
&mut tile_cache_pictures,
|
||||
interners,
|
||||
clip_tree_builder,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -607,55 +539,34 @@ fn find_scroll_root(
|
||||
scroll_root
|
||||
}
|
||||
|
||||
// Helper fn to collect clip handles from a given clip chain.
|
||||
fn add_clips(
|
||||
fn find_shared_clip_root(
|
||||
scroll_root: SpatialNodeIndex,
|
||||
clip_chain_id: ClipChainId,
|
||||
prim_clips: &mut Vec<ClipInstance>,
|
||||
clip_store: &ClipStore,
|
||||
interners: &Interners,
|
||||
clip_leaf_id: ClipLeafId,
|
||||
spatial_tree: &SceneSpatialTree,
|
||||
) {
|
||||
let mut current_clip_chain_id = clip_chain_id;
|
||||
clip_tree_builder: &ClipTreeBuilder,
|
||||
interners: &Interners,
|
||||
) -> ClipNodeId {
|
||||
let leaf = clip_tree_builder.get_leaf(clip_leaf_id);
|
||||
let mut current_node_id = leaf.node_id;
|
||||
|
||||
while current_clip_chain_id != ClipChainId::NONE {
|
||||
let clip_chain_node = &clip_store
|
||||
.clip_chain_nodes[current_clip_chain_id.0 as usize];
|
||||
while current_node_id != ClipNodeId::NONE {
|
||||
let node = clip_tree_builder.get_node(current_node_id);
|
||||
|
||||
let clip_node_data = &interners.clip[clip_chain_node.handle];
|
||||
if let ClipNodeKind::Rectangle = clip_node_data.clip_node_kind {
|
||||
let clip_node_data = &interners.clip[node.handle];
|
||||
|
||||
if let ClipNodeKind::Rectangle = clip_node_data.key.kind.node_kind() {
|
||||
if spatial_tree.is_ancestor(
|
||||
clip_node_data.spatial_node_index,
|
||||
clip_node_data.key.spatial_node_index,
|
||||
scroll_root,
|
||||
) {
|
||||
prim_clips.push(ClipInstance::new(clip_chain_node.handle));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
current_clip_chain_id = clip_chain_node.parent_clip_chain_id;
|
||||
current_node_id = node.parent;
|
||||
}
|
||||
}
|
||||
|
||||
// Walk a clip-chain, and accumulate all clip instances into supplied `prim_clips` array.
|
||||
fn add_all_rect_clips(
|
||||
clip_chain_id: ClipChainId,
|
||||
prim_clips: &mut Vec<ClipInstance>,
|
||||
clip_store: &ClipStore,
|
||||
interners: &Interners,
|
||||
) {
|
||||
let mut current_clip_chain_id = clip_chain_id;
|
||||
|
||||
while current_clip_chain_id != ClipChainId::NONE {
|
||||
let clip_chain_node = &clip_store
|
||||
.clip_chain_nodes[current_clip_chain_id.0 as usize];
|
||||
|
||||
let clip_node_data = &interners.clip[clip_chain_node.handle];
|
||||
if let ClipNodeKind::Rectangle = clip_node_data.clip_node_kind {
|
||||
prim_clips.push(ClipInstance::new(clip_chain_node.handle));
|
||||
}
|
||||
|
||||
current_clip_chain_id = clip_chain_node.parent_clip_chain_id;
|
||||
}
|
||||
current_node_id
|
||||
}
|
||||
|
||||
/// Given a PrimitiveList and scroll root, construct a tile cache primitive instance
|
||||
@ -663,28 +574,29 @@ fn add_all_rect_clips(
|
||||
fn create_tile_cache(
|
||||
slice_flags: SliceFlags,
|
||||
scroll_root: SpatialNodeIndex,
|
||||
iframe_clip: Option<ClipChainId>,
|
||||
iframe_clip: Option<ClipId>,
|
||||
prim_list: PrimitiveList,
|
||||
background_color: Option<ColorF>,
|
||||
mut shared_clips: Vec<ClipInstance>,
|
||||
shared_clip_node_id: ClipNodeId,
|
||||
prim_store: &mut PrimitiveStore,
|
||||
clip_store: &mut ClipStore,
|
||||
frame_builder_config: &FrameBuilderConfig,
|
||||
tile_caches: &mut FastHashMap<SliceId, TileCacheParams>,
|
||||
tile_cache_pictures: &mut Vec<PictureIndex>,
|
||||
interners: &Interners,
|
||||
clip_tree_builder: &mut ClipTreeBuilder,
|
||||
) {
|
||||
// Accumulate any clip instances from the iframe_clip into the shared clips
|
||||
// that will be applied by this tile cache during compositing.
|
||||
if let Some(clip_chain_id) = iframe_clip {
|
||||
add_all_rect_clips(
|
||||
clip_chain_id,
|
||||
&mut shared_clips,
|
||||
clip_store,
|
||||
interners,
|
||||
);
|
||||
let mut additional_clips = Vec::new();
|
||||
|
||||
if let Some(clip_id) = iframe_clip {
|
||||
additional_clips.push(clip_id);
|
||||
}
|
||||
|
||||
let shared_clip_leaf_id = Some(clip_tree_builder.build_for_tile_cache(
|
||||
shared_clip_node_id,
|
||||
&additional_clips,
|
||||
));
|
||||
|
||||
// Build a clip-chain for the tile cache, that contains any of the shared clips
|
||||
// we will apply when drawing the tiles. In all cases provided by Gecko, these
|
||||
// are rectangle clips with a scale/offset transform only, and get handled as
|
||||
@ -700,14 +612,6 @@ fn create_tile_cache(
|
||||
None
|
||||
};
|
||||
|
||||
let mut parent_clip_chain_id = ClipChainId::NONE;
|
||||
for clip_instance in &shared_clips {
|
||||
parent_clip_chain_id = clip_store.add_clip_chain_node(
|
||||
clip_instance.handle,
|
||||
parent_clip_chain_id,
|
||||
);
|
||||
}
|
||||
|
||||
let slice_id = SliceId::new(slice);
|
||||
|
||||
// Store some information about the picture cache slice. This is used when we swap the
|
||||
@ -717,8 +621,8 @@ fn create_tile_cache(
|
||||
slice_flags,
|
||||
spatial_node_index: scroll_root,
|
||||
background_color,
|
||||
shared_clips,
|
||||
shared_clip_chain: parent_clip_chain_id,
|
||||
shared_clip_node_id,
|
||||
shared_clip_leaf_id,
|
||||
virtual_surface_size: frame_builder_config.compositor_kind.get_virtual_surface_size(),
|
||||
compositor_surface_count: prim_list.compositor_surface_count,
|
||||
});
|
||||
@ -726,7 +630,6 @@ fn create_tile_cache(
|
||||
let pic_index = prim_store.pictures.alloc().init(PicturePrimitive::new_image(
|
||||
Some(PictureCompositeMode::TileCache { slice_id }),
|
||||
Picture3DContext::Out,
|
||||
true,
|
||||
PrimitiveFlags::IS_BACKFACE_VISIBLE,
|
||||
prim_list,
|
||||
scroll_root,
|
||||
|
@ -10,10 +10,10 @@
|
||||
use api::{DebugFlags};
|
||||
use api::units::*;
|
||||
use std::{usize};
|
||||
use crate::clip::{ClipStore, ClipChainStack};
|
||||
use crate::clip::ClipStore;
|
||||
use crate::composite::CompositeState;
|
||||
use crate::spatial_tree::{SpatialTree, SpatialNodeIndex};
|
||||
use crate::clip::{ClipInstance, ClipChainInstance};
|
||||
use crate::clip::{ClipChainInstance, ClipTree};
|
||||
use crate::frame_builder::FrameBuilderConfig;
|
||||
use crate::gpu_cache::GpuCache;
|
||||
use crate::picture::{PictureCompositeMode, ClusterFlags, SurfaceInfo, TileCacheInstance};
|
||||
@ -42,7 +42,7 @@ pub struct FrameVisibilityState<'a> {
|
||||
pub gpu_cache: &'a mut GpuCache,
|
||||
pub scratch: &'a mut ScratchBuffer,
|
||||
pub data_stores: &'a mut DataStores,
|
||||
pub clip_chain_stack: ClipChainStack,
|
||||
pub clip_tree: &'a mut ClipTree,
|
||||
pub composite_state: &'a mut CompositeState,
|
||||
/// A stack of currently active off-screen surfaces during the
|
||||
/// visibility frame traversal.
|
||||
@ -54,20 +54,12 @@ impl<'a> FrameVisibilityState<'a> {
|
||||
&mut self,
|
||||
pic_index: PictureIndex,
|
||||
surface_index: SurfaceIndex,
|
||||
shared_clips: &[ClipInstance],
|
||||
spatial_tree: &SpatialTree,
|
||||
) {
|
||||
self.surface_stack.push((pic_index, surface_index));
|
||||
self.clip_chain_stack.push_surface(
|
||||
shared_clips,
|
||||
spatial_tree,
|
||||
&self.data_stores.clip,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn pop_surface(&mut self) {
|
||||
self.surface_stack.pop().unwrap();
|
||||
self.clip_chain_stack.pop_surface();
|
||||
}
|
||||
}
|
||||
|
||||
@ -129,10 +121,6 @@ pub struct PrimitiveVisibility {
|
||||
/// global clip mask task for this primitive, or the first of
|
||||
/// a list of clip task ids (one per segment).
|
||||
pub clip_task_index: ClipTaskIndex,
|
||||
|
||||
/// The current combined local clip for this primitive, from
|
||||
/// the primitive local clip above and the current clip chain.
|
||||
pub combined_local_clip_rect: LayoutRect,
|
||||
}
|
||||
|
||||
impl PrimitiveVisibility {
|
||||
@ -141,7 +129,6 @@ impl PrimitiveVisibility {
|
||||
state: VisibilityState::Unset,
|
||||
clip_chain: ClipChainInstance::empty(),
|
||||
clip_task_index: ClipTaskIndex::INVALID,
|
||||
combined_local_clip_rect: LayoutRect::zero(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -173,8 +160,6 @@ pub fn update_prim_visibility(
|
||||
frame_state.push_surface(
|
||||
pic_index,
|
||||
raster_config.surface_index,
|
||||
&[],
|
||||
frame_context.spatial_tree,
|
||||
);
|
||||
|
||||
let surface_local_rect = surfaces[raster_config.surface_index.0]
|
||||
@ -246,10 +231,9 @@ pub fn update_prim_visibility(
|
||||
None => true,
|
||||
};
|
||||
|
||||
if is_passthrough {
|
||||
frame_state.clip_chain_stack.push_clip(
|
||||
prim_instances[prim_instance_index].clip_set.clip_chain_id,
|
||||
frame_state.clip_store,
|
||||
if !is_passthrough {
|
||||
frame_state.clip_tree.push_clip_root_leaf(
|
||||
prim_instances[prim_instance_index].clip_leaf_id,
|
||||
);
|
||||
}
|
||||
|
||||
@ -267,12 +251,12 @@ pub fn update_prim_visibility(
|
||||
);
|
||||
|
||||
if is_passthrough {
|
||||
frame_state.clip_chain_stack.pop_clip();
|
||||
|
||||
// Pass through pictures are always considered visible in all dirty tiles.
|
||||
prim_instances[prim_instance_index].vis.state = VisibilityState::PassThrough;
|
||||
|
||||
continue;
|
||||
} else {
|
||||
frame_state.clip_tree.pop_clip_root();
|
||||
}
|
||||
}
|
||||
|
||||
@ -284,19 +268,13 @@ pub fn update_prim_visibility(
|
||||
surfaces,
|
||||
);
|
||||
|
||||
// Include the clip chain for this primitive in the current stack.
|
||||
frame_state.clip_chain_stack.push_clip(
|
||||
prim_instance.clip_set.clip_chain_id,
|
||||
frame_state.clip_store,
|
||||
);
|
||||
|
||||
frame_state.clip_store.set_active_clips(
|
||||
prim_instance.clip_set.local_clip_rect,
|
||||
cluster.spatial_node_index,
|
||||
map_local_to_surface.ref_spatial_node_index,
|
||||
frame_state.clip_chain_stack.current_clips_array(),
|
||||
prim_instance.clip_leaf_id,
|
||||
&frame_context.spatial_tree,
|
||||
&frame_state.data_stores.clip,
|
||||
frame_state.clip_tree,
|
||||
);
|
||||
|
||||
let clip_chain = frame_state
|
||||
@ -314,9 +292,6 @@ pub fn update_prim_visibility(
|
||||
true,
|
||||
);
|
||||
|
||||
// Ensure the primitive clip is popped
|
||||
frame_state.clip_chain_stack.pop_clip();
|
||||
|
||||
prim_instance.vis.clip_chain = match clip_chain {
|
||||
Some(clip_chain) => clip_chain,
|
||||
None => {
|
||||
@ -324,12 +299,6 @@ pub fn update_prim_visibility(
|
||||
}
|
||||
};
|
||||
|
||||
prim_instance.vis.combined_local_clip_rect = if pic.apply_local_clip_rect {
|
||||
prim_instance.vis.clip_chain.local_clip_rect
|
||||
} else {
|
||||
prim_instance.clip_set.local_clip_rect
|
||||
};
|
||||
|
||||
tile_cache.update_prim_dependencies(
|
||||
prim_instance,
|
||||
cluster.spatial_node_index,
|
||||
|
@ -1635,9 +1635,12 @@ impl ClipChainId {
|
||||
|
||||
/// A reference to a clipping node defining how an item is clipped.
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize, PeekPoke)]
|
||||
pub enum ClipId {
|
||||
Clip(usize, PipelineId),
|
||||
ClipChain(ClipChainId),
|
||||
pub struct ClipId(pub usize, pub PipelineId);
|
||||
|
||||
impl Default for ClipId {
|
||||
fn default() -> Self {
|
||||
ClipId::invalid()
|
||||
}
|
||||
}
|
||||
|
||||
const ROOT_CLIP_ID: usize = 0;
|
||||
@ -1645,33 +1648,30 @@ const ROOT_CLIP_ID: usize = 0;
|
||||
impl ClipId {
|
||||
/// Return the root clip ID - effectively doing no clipping.
|
||||
pub fn root(pipeline_id: PipelineId) -> Self {
|
||||
ClipId::Clip(ROOT_CLIP_ID, pipeline_id)
|
||||
ClipId(ROOT_CLIP_ID, pipeline_id)
|
||||
}
|
||||
|
||||
/// Return an invalid clip ID - needed in places where we carry
|
||||
/// one but need to not attempt to use it.
|
||||
pub fn invalid() -> Self {
|
||||
ClipId::Clip(!0, PipelineId::dummy())
|
||||
ClipId(!0, PipelineId::dummy())
|
||||
}
|
||||
|
||||
pub fn pipeline_id(&self) -> PipelineId {
|
||||
match *self {
|
||||
ClipId::Clip(_, pipeline_id) |
|
||||
ClipId::ClipChain(ClipChainId(_, pipeline_id)) => pipeline_id,
|
||||
ClipId(_, pipeline_id) => pipeline_id,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_root(&self) -> bool {
|
||||
match *self {
|
||||
ClipId::Clip(id, _) => id == ROOT_CLIP_ID,
|
||||
ClipId::ClipChain(_) => false,
|
||||
ClipId(id, _) => id == ROOT_CLIP_ID,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_valid(&self) -> bool {
|
||||
match *self {
|
||||
ClipId::Clip(id, _) => id != !0,
|
||||
_ => true,
|
||||
ClipId(id, _) => id != !0,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1788,7 +1788,6 @@ impl_default_for_enums! {
|
||||
ComponentTransferFuncType => Identity,
|
||||
ClipMode => Clip,
|
||||
FillRule => Nonzero,
|
||||
ClipId => ClipId::invalid(),
|
||||
ReferenceFrameKind => Transform {
|
||||
is_2d_scale_translation: false,
|
||||
should_snap: false,
|
||||
|
@ -1868,7 +1868,7 @@ impl DisplayListBuilder {
|
||||
|
||||
fn generate_clip_index(&mut self) -> di::ClipId {
|
||||
self.next_clip_index += 1;
|
||||
di::ClipId::Clip(self.next_clip_index - 1, self.pipeline_id)
|
||||
di::ClipId(self.next_clip_index - 1, self.pipeline_id)
|
||||
}
|
||||
|
||||
fn generate_spatial_index(&mut self) -> di::SpatialId {
|
||||
|
@ -337,6 +337,7 @@ pub struct YamlFrameReader {
|
||||
/// A HashMap that allows specifying a numeric id for clip and clip chains in YAML
|
||||
/// and having each of those ids correspond to a unique ClipId.
|
||||
user_clip_id_map: HashMap<u64, ClipId>,
|
||||
user_clipchain_id_map: HashMap<u64, ClipChainId>,
|
||||
user_spatial_id_map: HashMap<u64, SpatialId>,
|
||||
|
||||
spatial_id_stack: Vec<SpatialId>,
|
||||
@ -368,6 +369,7 @@ impl YamlFrameReader {
|
||||
allow_mipmaps: false,
|
||||
image_map: HashMap::new(),
|
||||
user_clip_id_map: HashMap::new(),
|
||||
user_clipchain_id_map: HashMap::new(),
|
||||
user_spatial_id_map: HashMap::new(),
|
||||
spatial_id_stack: Vec::new(),
|
||||
yaml_string: String::new(),
|
||||
@ -461,6 +463,7 @@ impl YamlFrameReader {
|
||||
) {
|
||||
// Don't allow referencing clips between pipelines for now.
|
||||
self.user_clip_id_map.clear();
|
||||
self.user_clipchain_id_map.clear();
|
||||
self.user_spatial_id_map.clear();
|
||||
self.spatial_id_stack.clear();
|
||||
self.spatial_id_stack.push(SpatialId::root_scroll_node(pipeline_id));
|
||||
@ -479,15 +482,6 @@ impl YamlFrameReader {
|
||||
assert_eq!(self.spatial_id_stack.len(), 1);
|
||||
}
|
||||
|
||||
fn to_clip_id(&self, item: &Yaml, pipeline_id: PipelineId) -> Option<ClipId> {
|
||||
match *item {
|
||||
Yaml::Integer(value) => Some(self.user_clip_id_map[&(value as u64)]),
|
||||
Yaml::String(ref id_string) if id_string == "root_clip" =>
|
||||
Some(ClipId::root(pipeline_id)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn to_clip_chain_id(
|
||||
&self,
|
||||
item: &Yaml,
|
||||
@ -495,11 +489,7 @@ impl YamlFrameReader {
|
||||
) -> Option<ClipChainId> {
|
||||
match *item {
|
||||
Yaml::Integer(value) => {
|
||||
let clip_id = self.user_clip_id_map[&(value as u64)];
|
||||
match clip_id {
|
||||
ClipId::ClipChain(id) => Some(id),
|
||||
ClipId::Clip(..) => panic!("bug: must be a valid clip-chain id"),
|
||||
}
|
||||
Some(self.user_clipchain_id_map[&(value as u64)])
|
||||
}
|
||||
Yaml::Array(ref array) => {
|
||||
let clip_ids: Vec<ClipId> = array
|
||||
@ -536,6 +526,11 @@ impl YamlFrameReader {
|
||||
self.user_clip_id_map.insert(numeric_id, real_id);
|
||||
}
|
||||
|
||||
fn add_clip_chain_id_mapping(&mut self, numeric_id: u64, real_id: ClipChainId) {
|
||||
assert_ne!(numeric_id, 0, "id=0 is reserved for the root clip-chain");
|
||||
self.user_clipchain_id_map.insert(numeric_id, real_id);
|
||||
}
|
||||
|
||||
fn add_spatial_id_mapping(&mut self, numeric_id: u64, real_id: SpatialId) {
|
||||
assert_ne!(numeric_id, 0, "id=0 is reserved for the root reference frame");
|
||||
assert_ne!(numeric_id, 1, "id=1 is reserved for the root scroll node");
|
||||
@ -1792,15 +1787,9 @@ impl YamlFrameReader {
|
||||
.map(|id| self.user_clip_id_map[id])
|
||||
.collect();
|
||||
|
||||
let parent = self.to_clip_id(&yaml["parent"], builder.pipeline_id);
|
||||
let parent = match parent {
|
||||
Some(ClipId::ClipChain(clip_chain_id)) => Some(clip_chain_id),
|
||||
Some(_) => panic!("Tried to create a ClipChain with a non-ClipChain parent"),
|
||||
None => None,
|
||||
};
|
||||
|
||||
let parent = self.to_clip_chain_id(&yaml["parent"], builder);
|
||||
let real_id = builder.define_clip_chain(parent, clip_ids);
|
||||
self.add_clip_id_mapping(numeric_id as u64, ClipId::ClipChain(real_id));
|
||||
self.add_clip_chain_id_mapping(numeric_id as u64, real_id);
|
||||
}
|
||||
|
||||
fn handle_clip(&mut self, dl: &mut DisplayListBuilder, wrench: &mut Wrench, yaml: &Yaml) {
|
||||
|
@ -5,7 +5,7 @@ skip-if(!asyncPan) == bg-fixed-cover-3.html bg-fixed-cover-3-ref.html
|
||||
skip-if(!asyncPan) == bg-fixed-child.html bg-fixed-child-ref.html
|
||||
skip-if(!asyncPan) == bg-fixed-child-clip-1.html bg-fixed-child-clip-ref.html
|
||||
skip-if(!asyncPan) == bg-fixed-child-clip-2.html bg-fixed-child-clip-ref.html
|
||||
fuzzy(41-42,154-181) skip-if(!asyncPan) == bg-fixed-child-mask.html bg-fixed-child-mask-ref.html
|
||||
skip-if(!asyncPan) == bg-fixed-child-mask.html bg-fixed-child-mask-ref.html
|
||||
skip-if(!asyncPan) == bg-fixed-in-opacity.html bg-fixed-in-opacity-ref.html
|
||||
# Passing the test below without WebRender would require implementing CSS filters in the Gecko compositor.
|
||||
skip-if(!asyncPan) fuzzy-if(gtkWidget,0-1,0-87) fuzzy-if(!gtkWidget,0-1,0-3951) == bg-fixed-in-css-filter.html bg-fixed-in-css-filter-ref.html # bug 1454794 for webrender fuzziness
|
||||
|
Loading…
Reference in New Issue
Block a user