From 813d7f244705df4c258cd15ab0f24ff85ef91a69 Mon Sep 17 00:00:00 2001 From: Glenn Watson Date: Fri, 8 Sep 2017 11:10:07 +1000 Subject: [PATCH 1/5] Add recycle() to free list, and support cloning weak handles. --- webrender/src/freelist.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/webrender/src/freelist.rs b/webrender/src/freelist.rs index d43d7145a7..79c4e3d2ee 100644 --- a/webrender/src/freelist.rs +++ b/webrender/src/freelist.rs @@ -3,6 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use std::marker::PhantomData; +use util::recycle_vec; // TODO(gw): Add an occupied list head, for fast // iteration of the occupied list to implement @@ -17,6 +18,16 @@ pub struct FreeListHandle { _marker: PhantomData, } +impl Clone for WeakFreeListHandle { + fn clone(&self) -> WeakFreeListHandle { + WeakFreeListHandle { + index: self.index, + epoch: self.epoch, + _marker: PhantomData, + } + } +} + #[derive(Debug)] pub struct WeakFreeListHandle { index: u32, @@ -48,6 +59,13 @@ impl FreeList { } } + pub fn recycle(self) -> FreeList { + FreeList { + slots: recycle_vec(self.slots), + free_list_head: None, + } + } + #[allow(dead_code)] pub fn get(&self, id: &FreeListHandle) -> &T { self.slots[id.index as usize] From b0ff1e63662cc1c8bee8682dd078c15916abe5f4 Mon Sep 17 00:00:00 2001 From: Glenn Watson Date: Fri, 8 Sep 2017 11:11:40 +1000 Subject: [PATCH 2/5] Introduce ClipStore, an arena for storing clip sources. This reduces a lot of memory copying and allocations, since the clip stack built each frame now just contains handles into the clip store, rather than copying the entire mask cache. --- webrender/src/clip.rs | 15 +++--- webrender/src/clip_scroll_node.rs | 10 ++-- webrender/src/clip_scroll_tree.rs | 18 +++++--- webrender/src/frame.rs | 2 +- webrender/src/frame_builder.rs | 67 ++++++++++++++++++--------- webrender/src/mask_cache.rs | 8 ---- webrender/src/prim_store.rs | 42 +++++++++-------- webrender/src/render_backend.rs | 7 ++- webrender/src/render_task.rs | 43 ++++++++++++----- webrender/src/tiling.rs | 77 ++++++++++++++++++++----------- 10 files changed, 176 insertions(+), 113 deletions(-) diff --git a/webrender/src/clip.rs b/webrender/src/clip.rs index 58e64fcd33..1ea5f250a5 100644 --- a/webrender/src/clip.rs +++ b/webrender/src/clip.rs @@ -5,11 +5,16 @@ use api::{BorderRadius, ComplexClipRegion, ImageMask, ImageRendering}; use api::{LayerPoint, LayerRect, LayerToWorldTransform, LocalClip}; use border::BorderCornerClipSource; +use freelist::{FreeList, FreeListHandle, WeakFreeListHandle}; use gpu_cache::GpuCache; use mask_cache::MaskCacheInfo; use resource_cache::ResourceCache; use std::ops::Not; +pub type ClipStore = FreeList; +pub type ClipSourcesHandle = FreeListHandle; +pub type ClipSourcesWeakHandle = WeakFreeListHandle; + #[derive(Clone, Debug)] pub struct ClipRegion { pub origin: LayerPoint, @@ -102,7 +107,7 @@ impl From for ClipSources { #[derive(Debug)] pub struct ClipSources { clips: Vec, - mask_cache_info: MaskCacheInfo, + pub mask_cache_info: MaskCacheInfo, } impl ClipSources { @@ -147,12 +152,4 @@ impl ClipSources { pub fn is_masking(&self) -> bool { self.mask_cache_info.is_masking() } - - pub fn clone_mask_cache_info(&self, keep_aligned: bool) -> MaskCacheInfo { - if keep_aligned { - self.mask_cache_info.clone() - } else { - self.mask_cache_info.strip_aligned() - } - } } diff --git a/webrender/src/clip_scroll_node.rs b/webrender/src/clip_scroll_node.rs index 2b61b0aaf4..1d3effa14c 100644 --- a/webrender/src/clip_scroll_node.rs +++ b/webrender/src/clip_scroll_node.rs @@ -6,7 +6,7 @@ use api::{ClipId, DeviceIntRect, LayerPixel, LayerPoint, LayerRect, LayerSize}; use api::{LayerToScrollTransform, LayerToWorldTransform, LayerVector2D, PipelineId}; use api::{ScrollClamping, ScrollEventPhase, ScrollLocation, ScrollSensitivity, StickyFrameInfo}; use api::WorldPoint; -use clip::{ClipRegion, ClipSources}; +use clip::{ClipRegion, ClipSources, ClipSourcesHandle, ClipStore}; use clip_scroll_tree::TransformUpdateState; use geometry::ray_intersects_rect; use spring::{DAMPING, STIFFNESS, Spring}; @@ -22,7 +22,7 @@ const CAN_OVERSCROLL: bool = false; #[derive(Debug)] pub struct ClipInfo { /// The clips for this node. - pub clip_sources: ClipSources, + pub clip_sources: ClipSourcesHandle, /// The packed layer index for this node, which is used to render a clip mask /// for it, if necessary. @@ -39,10 +39,12 @@ pub struct ClipInfo { } impl ClipInfo { - pub fn new(clip_region: ClipRegion, packed_layer_index: PackedLayerIndex) -> ClipInfo { + pub fn new(clip_region: ClipRegion, + packed_layer_index: PackedLayerIndex, + clip_store: &mut ClipStore) -> ClipInfo { let clip_rect = LayerRect::new(clip_region.origin, clip_region.main.size); ClipInfo { - clip_sources: ClipSources::from(clip_region), + clip_sources: clip_store.insert(ClipSources::from(clip_region)), packed_layer_index, screen_bounding_rect: None, clip_rect: clip_rect, diff --git a/webrender/src/clip_scroll_tree.rs b/webrender/src/clip_scroll_tree.rs index ae5c225281..1997f933fc 100644 --- a/webrender/src/clip_scroll_tree.rs +++ b/webrender/src/clip_scroll_tree.rs @@ -2,6 +2,7 @@ * 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 clip::ClipStore; use clip_scroll_node::{ClipScrollNode, NodeType, ScrollingState}; use internal_types::{FastHashSet, FastHashMap}; use print_tree::{PrintTree, PrintTreePrinter}; @@ -370,7 +371,10 @@ impl ClipScrollTree { } } - fn print_node(&self, id: &ClipId, pt: &mut T) { + fn print_node(&self, + id: &ClipId, + pt: &mut T, + clip_store: &ClipStore) { let node = self.nodes.get(id).unwrap(); match node.node_type { @@ -378,7 +382,7 @@ impl ClipScrollTree { pt.new_level("Clip".to_owned()); pt.add_item(format!("screen_bounding_rect: {:?}", info.screen_bounding_rect)); - let clips = info.clip_sources.clips(); + let clips = clip_store.get(&info.clip_sources).clips(); pt.new_level(format!("Clip Sources [{}]", clips.len())); for source in clips { pt.add_item(format!("{:?}", source)); @@ -406,23 +410,23 @@ impl ClipScrollTree { pt.add_item(format!("world_content_transform: {:?}", node.world_content_transform)); for child_id in &node.children { - self.print_node(child_id, pt); + self.print_node(child_id, pt, clip_store); } pt.end_level(); } #[allow(dead_code)] - pub fn print(&self) { + pub fn print(&self, clip_store: &ClipStore) { if !self.nodes.is_empty() { let mut pt = PrintTree::new("clip_scroll tree"); - self.print_with(&mut pt); + self.print_with(clip_store, &mut pt,); } } - pub fn print_with(&self, pt: &mut T) { + pub fn print_with(&self, clip_store: &ClipStore, pt: &mut T) { if !self.nodes.is_empty() { - self.print_node(&self.root_reference_frame_id, pt); + self.print_node(&self.root_reference_frame_id, pt, clip_store); } } } diff --git a/webrender/src/frame.rs b/webrender/src/frame.rs index 789c8ef516..586d3da9bc 100644 --- a/webrender/src/frame.rs +++ b/webrender/src/frame.rs @@ -186,7 +186,7 @@ pub struct Frame { pub pipeline_epoch_map: FastHashMap, id: FrameId, frame_builder_config: FrameBuilderConfig, - frame_builder: Option, + pub frame_builder: Option, } trait FilterOpHelpers { diff --git a/webrender/src/frame_builder.rs b/webrender/src/frame_builder.rs index 174437cbf1..677bb5f941 100644 --- a/webrender/src/frame_builder.rs +++ b/webrender/src/frame_builder.rs @@ -11,7 +11,7 @@ use api::{LayerToScrollTransform, LayerVector2D, LayoutVector2D, LineOrientation use api::{LocalClip, PipelineId, RepeatMode, ScrollSensitivity, SubpixelDirection, TextShadow}; use api::{TileOffset, TransformStyle, WorldPixel, YuvColorSpace, YuvData}; use app_units::Au; -use clip::{ClipMode, ClipRegion, ClipSource, ClipSources}; +use clip::{ClipMode, ClipRegion, ClipSource, ClipSources, ClipStore}; use frame::FrameId; use gpu_cache::GpuCache; use internal_types::{FastHashMap, HardwareCompositeOp}; @@ -110,6 +110,7 @@ pub struct FrameBuilder { screen_size: DeviceUintSize, background_color: Option, prim_store: PrimitiveStore, + pub clip_store: ClipStore, cmds: Vec, config: FrameBuilderConfig, @@ -155,6 +156,7 @@ impl FrameBuilder { reference_frame_stack: recycle_vec(prev.reference_frame_stack), stacking_context_stack: recycle_vec(prev.stacking_context_stack), prim_store: prev.prim_store.recycle(), + clip_store: prev.clip_store.recycle(), screen_size, background_color, config, @@ -173,6 +175,7 @@ impl FrameBuilder { reference_frame_stack: Vec::new(), stacking_context_stack: Vec::new(), prim_store: PrimitiveStore::new(), + clip_store: ClipStore::new(), screen_size, background_color, config, @@ -207,7 +210,7 @@ impl FrameBuilder { clip_sources.push(ClipSource::RoundedRectangle(region.rect, region.radii, ClipMode::Clip)); } - let clip_sources = ClipSources::new(clip_sources); + let clip_sources = self.clip_store.insert(ClipSources::new(clip_sources)); let prim_index = self.prim_store.add_primitive(rect, &local_clip.clip_rect(), @@ -402,7 +405,9 @@ impl FrameBuilder { pipeline_id: PipelineId, clip_region: ClipRegion, clip_scroll_tree: &mut ClipScrollTree) { - let clip_info = ClipInfo::new(clip_region, PackedLayerIndex(self.packed_layers.len())); + let clip_info = ClipInfo::new(clip_region, + PackedLayerIndex(self.packed_layers.len()), + &mut self.clip_store); let node = ClipScrollNode::new(pipeline_id, parent_id, clip_info); clip_scroll_tree.add_node(node, new_node_id); self.packed_layers.push(PackedLayer::empty()); @@ -1631,7 +1636,7 @@ impl FrameBuilder { resource_cache, }; - pass.build(&ctx, gpu_cache, &mut render_tasks, &mut deferred_resolves); + pass.build(&ctx, gpu_cache, &mut render_tasks, &mut deferred_resolves, &self.clip_store); profile_counters.passes.inc(); profile_counters.color_targets.add(pass.color_targets.target_count()); @@ -1764,10 +1769,11 @@ impl<'a> LayerRectCalculationAndCullingPass<'a> { None }; - node_clip_info.clip_sources.update(&transform, - self.gpu_cache, - self.resource_cache, - self.device_pixel_ratio); + let clip_sources = self.frame_builder.clip_store.get_mut(&node_clip_info.clip_sources); + clip_sources.update(&transform, + self.gpu_cache, + self.resource_cache, + self.device_pixel_ratio); } } @@ -1876,10 +1882,19 @@ impl<'a> LayerRectCalculationAndCullingPass<'a> { next_node_needs_region_mask |= !info.transform.preserves_2d_axis_alignment(); continue }, - NodeType::Clip(ref clip) if clip.clip_sources.is_masking() => clip, - _ => continue, + NodeType::Clip(ref clip) => { + clip + } + NodeType::StickyFrame(..) | NodeType::ScrollFrame(..) => { + continue; + } }; + let clip_sources = self.frame_builder.clip_store.get(&clip.clip_sources); + if !clip_sources.is_masking() { + continue; + } + // apply the screen bounds of the clip node //Note: these are based on the local combined viewport, so can be tighter if let Some((_kind, ref screen_rect)) = clip.screen_bounding_rect { @@ -1889,10 +1904,8 @@ impl<'a> LayerRectCalculationAndCullingPass<'a> { } } - let clip_info = clip.clip_sources.clone_mask_cache_info(next_node_needs_region_mask); - // apply the outer device bounds of the clip stack - if let Some(ref outer) = clip_info.bounds.outer { + if let Some(ref outer) = clip_sources.mask_cache_info.bounds.outer { bounding_rect = match bounding_rect.intersection(&outer.device_rect) { Some(rect) => rect, None => return None, @@ -1900,7 +1913,11 @@ impl<'a> LayerRectCalculationAndCullingPass<'a> { } //TODO-LCCR: bake a single LCCR instead of all aligned rects? - self.current_clip_stack.push((clip.packed_layer_index, clip_info)); + self.current_clip_stack.push(ClipWorkItem { + layer_index: clip.packed_layer_index, + clip_sources: self.frame_builder.clip_store.create_weak_handle(&clip.clip_sources), + apply_rectangles: next_node_needs_region_mask, + }); next_node_needs_region_mask = false; } @@ -1972,18 +1989,18 @@ impl<'a> LayerRectCalculationAndCullingPass<'a> { self.device_pixel_ratio, display_list, TextRunMode::Normal, - &mut self.render_tasks); + &mut self.render_tasks, + &mut self.frame_builder.clip_store); stacking_context.screen_bounds = stacking_context.screen_bounds.union(&prim_screen_rect); stacking_context.isolated_items_bounds = stacking_context.isolated_items_bounds.union(&prim_local_rect); // Try to create a mask if we may need to. - let clip_task = if prim_metadata.clips.is_masking() { - let info = prim_metadata.clips.clone_mask_cache_info(false); - + let prim_clips = self.frame_builder.clip_store.get(&prim_metadata.clip_sources); + let clip_task = if prim_clips.is_masking() { // Take into account the actual clip info of the primitive, and // mutate the current bounds accordingly. - let mask_rect = match info.bounds.outer { + let mask_rect = match prim_clips.mask_cache_info.bounds.outer { Some(ref outer) => { match prim_screen_rect.intersection(&outer.device_rect) { Some(rect) => rect, @@ -1993,13 +2010,18 @@ impl<'a> LayerRectCalculationAndCullingPass<'a> { _ => prim_screen_rect, }; - let extra = (packed_layer_index, info); + let extra = ClipWorkItem { + layer_index: packed_layer_index, + clip_sources: self.frame_builder.clip_store.create_weak_handle(&prim_metadata.clip_sources), + apply_rectangles: false, + }; RenderTask::new_mask(None, mask_rect, &self.current_clip_stack, Some(extra), - prim_screen_rect) + prim_screen_rect, + &self.frame_builder.clip_store) } else if !self.current_clip_stack.is_empty() { // If the primitive doesn't have a specific clip, key the task ID off the // stacking context. This means that two primitives which are only clipped @@ -2009,7 +2031,8 @@ impl<'a> LayerRectCalculationAndCullingPass<'a> { clip_bounds, &self.current_clip_stack, None, - prim_screen_rect) + prim_screen_rect, + &self.frame_builder.clip_store) } else { None }; diff --git a/webrender/src/mask_cache.rs b/webrender/src/mask_cache.rs index b04f3f721e..05d39fe52c 100644 --- a/webrender/src/mask_cache.rs +++ b/webrender/src/mask_cache.rs @@ -255,12 +255,4 @@ impl MaskCacheInfo { self.layer_clip_range.item_count != 0 || !self.border_corners.is_empty() } - - /// Return a clone of this object without any layer-aligned clip items - pub fn strip_aligned(&self) -> Self { - MaskCacheInfo { - layer_clip_range: ClipAddressRange::new(0), - .. self.clone() - } - } } diff --git a/webrender/src/prim_store.rs b/webrender/src/prim_store.rs index 54ca730c3a..4548d5ba76 100644 --- a/webrender/src/prim_store.rs +++ b/webrender/src/prim_store.rs @@ -9,7 +9,7 @@ use api::{GlyphKey, LayerToWorldTransform, TileOffset, YuvColorSpace, YuvFormat} use api::{device_length, FontInstance, LayerVector2D, LineOrientation, LineStyle}; use app_units::Au; use border::BorderCornerInstance; -use clip::{ClipMode, ClipSources}; +use clip::{ClipMode, ClipSourcesHandle, ClipStore}; use euclid::{Size2D}; use gpu_cache::{GpuCacheAddress, GpuBlockData, GpuCache, GpuCacheHandle, GpuDataRequest, ToGpuBlocks}; use renderer::MAX_VERTEX_TEXTURE_WIDTH; @@ -134,7 +134,7 @@ impl GpuCacheHandle { #[derive(Debug)] pub struct PrimitiveMetadata { pub opacity: PrimitiveOpacity, - pub clips: ClipSources, + pub clip_sources: ClipSourcesHandle, pub prim_kind: PrimitiveKind, pub cpu_prim_index: SpecificPrimitiveIndex, pub gpu_location: GpuCacheHandle, @@ -804,7 +804,7 @@ impl PrimitiveStore { pub fn add_primitive(&mut self, local_rect: &LayerRect, local_clip_rect: &LayerRect, - clips: ClipSources, + clip_sources: ClipSourcesHandle, container: PrimitiveContainer) -> PrimitiveIndex { let prim_index = self.cpu_metadata.len(); self.cpu_bounding_rects.push(None); @@ -813,7 +813,7 @@ impl PrimitiveStore { PrimitiveContainer::Rectangle(rect) => { let metadata = PrimitiveMetadata { opacity: PrimitiveOpacity::from_alpha(rect.color.a), - clips, + clip_sources, prim_kind: PrimitiveKind::Rectangle, cpu_prim_index: SpecificPrimitiveIndex(self.cpu_rectangles.len()), gpu_location: GpuCacheHandle::new(), @@ -830,7 +830,7 @@ impl PrimitiveStore { PrimitiveContainer::Line(line) => { let metadata = PrimitiveMetadata { opacity: PrimitiveOpacity::translucent(), - clips, + clip_sources, prim_kind: PrimitiveKind::Line, cpu_prim_index: SpecificPrimitiveIndex(self.cpu_lines.len()), gpu_location: GpuCacheHandle::new(), @@ -846,7 +846,7 @@ impl PrimitiveStore { PrimitiveContainer::TextRun(text_cpu) => { let metadata = PrimitiveMetadata { opacity: PrimitiveOpacity::translucent(), - clips, + clip_sources, prim_kind: PrimitiveKind::TextRun, cpu_prim_index: SpecificPrimitiveIndex(self.cpu_text_runs.len()), gpu_location: GpuCacheHandle::new(), @@ -862,7 +862,7 @@ impl PrimitiveStore { PrimitiveContainer::TextShadow(text_shadow) => { let metadata = PrimitiveMetadata { opacity: PrimitiveOpacity::translucent(), - clips, + clip_sources, prim_kind: PrimitiveKind::TextShadow, cpu_prim_index: SpecificPrimitiveIndex(self.cpu_text_shadows.len()), gpu_location: GpuCacheHandle::new(), @@ -878,7 +878,7 @@ impl PrimitiveStore { PrimitiveContainer::Image(image_cpu) => { let metadata = PrimitiveMetadata { opacity: PrimitiveOpacity::translucent(), - clips, + clip_sources, prim_kind: PrimitiveKind::Image, cpu_prim_index: SpecificPrimitiveIndex(self.cpu_images.len()), gpu_location: GpuCacheHandle::new(), @@ -894,7 +894,7 @@ impl PrimitiveStore { PrimitiveContainer::YuvImage(image_cpu) => { let metadata = PrimitiveMetadata { opacity: PrimitiveOpacity::opaque(), - clips, + clip_sources, prim_kind: PrimitiveKind::YuvImage, cpu_prim_index: SpecificPrimitiveIndex(self.cpu_yuv_images.len()), gpu_location: GpuCacheHandle::new(), @@ -910,7 +910,7 @@ impl PrimitiveStore { PrimitiveContainer::Border(border_cpu) => { let metadata = PrimitiveMetadata { opacity: PrimitiveOpacity::translucent(), - clips, + clip_sources, prim_kind: PrimitiveKind::Border, cpu_prim_index: SpecificPrimitiveIndex(self.cpu_borders.len()), gpu_location: GpuCacheHandle::new(), @@ -926,7 +926,7 @@ impl PrimitiveStore { PrimitiveContainer::AlignedGradient(gradient_cpu) => { let metadata = PrimitiveMetadata { opacity: PrimitiveOpacity::translucent(), - clips, + clip_sources, prim_kind: PrimitiveKind::AlignedGradient, cpu_prim_index: SpecificPrimitiveIndex(self.cpu_gradients.len()), gpu_location: GpuCacheHandle::new(), @@ -943,7 +943,7 @@ impl PrimitiveStore { let metadata = PrimitiveMetadata { // TODO: calculate if the gradient is actually opaque opacity: PrimitiveOpacity::translucent(), - clips, + clip_sources, prim_kind: PrimitiveKind::AngleGradient, cpu_prim_index: SpecificPrimitiveIndex(self.cpu_gradients.len()), gpu_location: GpuCacheHandle::new(), @@ -960,7 +960,7 @@ impl PrimitiveStore { let metadata = PrimitiveMetadata { // TODO: calculate if the gradient is actually opaque opacity: PrimitiveOpacity::translucent(), - clips, + clip_sources, prim_kind: PrimitiveKind::RadialGradient, cpu_prim_index: SpecificPrimitiveIndex(self.cpu_radial_gradients.len()), gpu_location: GpuCacheHandle::new(), @@ -976,7 +976,7 @@ impl PrimitiveStore { PrimitiveContainer::BoxShadow(box_shadow) => { let metadata = PrimitiveMetadata { opacity: PrimitiveOpacity::translucent(), - clips, + clip_sources, prim_kind: PrimitiveKind::BoxShadow, cpu_prim_index: SpecificPrimitiveIndex(self.cpu_box_shadows.len()), gpu_location: GpuCacheHandle::new(), @@ -1035,7 +1035,8 @@ impl PrimitiveStore { device_pixel_ratio: f32, display_list: &BuiltDisplayList, text_run_mode: TextRunMode, - render_tasks: &mut RenderTaskTree) + render_tasks: &mut RenderTaskTree, + clip_store: &mut ClipStore) -> &mut PrimitiveMetadata { let (prim_kind, cpu_prim_index) = { let metadata = &self.cpu_metadata[prim_index.0]; @@ -1056,15 +1057,16 @@ impl PrimitiveStore { device_pixel_ratio, display_list, TextRunMode::Shadow, - render_tasks); + render_tasks, + clip_store); } } let metadata = &mut self.cpu_metadata[prim_index.0]; - metadata.clips.update(layer_transform, - gpu_cache, - resource_cache, - device_pixel_ratio); + clip_store.get_mut(&metadata.clip_sources).update(layer_transform, + gpu_cache, + resource_cache, + device_pixel_ratio); match metadata.prim_kind { PrimitiveKind::Rectangle | diff --git a/webrender/src/render_backend.rs b/webrender/src/render_backend.rs index e124428cd6..e2c51d18ae 100644 --- a/webrender/src/render_backend.rs +++ b/webrender/src/render_backend.rs @@ -613,9 +613,12 @@ impl RenderBackend { for (_, doc) in &self.documents { let debug_node = debug_server::TreeNode::new("document clip_scroll tree"); let mut builder = debug_server::TreeNodeBuilder::new(debug_node); - doc.frame.clip_scroll_tree.print_with(&mut builder); + // TODO(gw): Restructure the storage of clip-scroll tree, clip store + // etc so this isn't so untidy. + let clip_store = &doc.frame.frame_builder.as_ref().unwrap().clip_store; + doc.frame.clip_scroll_tree.print_with(clip_store, &mut builder); - debug_root.add(builder.build()); + debug_root.add(builder.build()); } serde_json::to_string(&debug_root).unwrap() diff --git a/webrender/src/render_task.rs b/webrender/src/render_task.rs index 1ad7cf3a33..6bccb6d9d5 100644 --- a/webrender/src/render_task.rs +++ b/webrender/src/render_task.rs @@ -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 clip::{ClipSourcesWeakHandle, ClipStore}; use gpu_cache::GpuCacheHandle; use internal_types::HardwareCompositeOp; -use mask_cache::MaskCacheInfo; use prim_store::{BoxShadowPrimitiveCacheKey, PrimitiveIndex}; use std::{cmp, f32, i32, usize}; use tiling::{ClipScrollGroupIndex, PackedLayerIndex, RenderPass, RenderTargetIndex}; @@ -157,7 +157,28 @@ pub enum MaskGeometryKind { // TODO(gw): Add more types here (e.g. 4 rectangles outside the inner rect) } -pub type ClipWorkItem = (PackedLayerIndex, MaskCacheInfo); +#[derive(Debug, Clone)] +pub struct ClipWorkItem { + pub layer_index: PackedLayerIndex, + pub clip_sources: ClipSourcesWeakHandle, + pub apply_rectangles: bool, +} + +impl ClipWorkItem { + fn get_geometry_kind(&self, clip_store: &ClipStore) -> MaskGeometryKind { + let info = &clip_store.get_opt(&self.clip_sources) + .expect("bug: clip handle should be valid") + .mask_cache_info; + if info.border_corners.is_empty() && + info.image.is_none() && + info.complex_clip_range.get_count() == 1 && + (info.layer_clip_range.get_count() == 0 || !self.apply_rectangles) { + MaskGeometryKind::CornersOnly + } else { + MaskGeometryKind::Default + } + } +} #[derive(Debug)] pub struct CacheMaskTask { @@ -245,13 +266,17 @@ impl RenderTask { task_rect: DeviceIntRect, raw_clips: &[ClipWorkItem], extra_clip: Option, - prim_rect: DeviceIntRect) + prim_rect: DeviceIntRect, + clip_store: &ClipStore) -> Option { // Filter out all the clip instances that don't contribute to the result let mut inner_rect = Some(task_rect); let clips: Vec<_> = raw_clips.iter() .chain(extra_clip.iter()) - .filter(|&&(_, ref clip_info)| { + .filter(|work_item| { + let clip_info = clip_store.get_opt(&work_item.clip_sources) + .expect("bug: clip item should exist"); + // If this clip does not contribute to a mask, then ensure // it gets filtered out here. Otherwise, if a mask is // created (by a different clip in the list), the allocated @@ -261,7 +286,7 @@ impl RenderTask { return false; } - match clip_info.bounds.inner { + match clip_info.mask_cache_info.bounds.inner { Some(ref inner) if !inner.device_rect.is_empty() => { inner_rect = inner_rect.and_then(|r| r.intersection(&inner.device_rect)); !inner.device_rect.contains_rect(&task_rect) @@ -291,13 +316,7 @@ impl RenderTask { return None; } if clips.len() == 1 { - let (_, ref info) = clips[0]; - if info.border_corners.is_empty() && - info.image.is_none() && - info.complex_clip_range.get_count() == 1 && - info.layer_clip_range.get_count() == 0 { - geometry_kind = MaskGeometryKind::CornersOnly; - } + geometry_kind = clips[0].get_geometry_kind(clip_store); } } diff --git a/webrender/src/tiling.rs b/webrender/src/tiling.rs index b7abeb21c1..1abe772f8b 100644 --- a/webrender/src/tiling.rs +++ b/webrender/src/tiling.rs @@ -3,16 +3,16 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use border::{BorderCornerInstance, BorderCornerSide}; +use clip::ClipStore; use device::Texture; use gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle, GpuCacheUpdateList}; use gpu_types::BoxShadowCacheInstance; use internal_types::BatchTextures; use internal_types::{FastHashMap, SourceTexture}; -use mask_cache::MaskCacheInfo; use prim_store::{CLIP_DATA_GPU_BLOCKS, DeferredResolve}; use prim_store::{PrimitiveIndex, PrimitiveKind, PrimitiveMetadata, PrimitiveStore}; use profiler::FrameProfileCounters; -use render_task::{AlphaRenderItem, MaskGeometryKind, MaskSegment}; +use render_task::{AlphaRenderItem, ClipWorkItem, MaskGeometryKind, MaskSegment}; use render_task::{RenderTaskAddress, RenderTaskId, RenderTaskKey, RenderTaskKind}; use render_task::{RenderTaskLocation, RenderTaskTree}; use renderer::BlendMode; @@ -669,26 +669,28 @@ impl ClipBatcher { } } - fn add<'a>(&mut self, - task_address: RenderTaskAddress, - clips: &[(PackedLayerIndex, MaskCacheInfo)], - resource_cache: &ResourceCache, - gpu_cache: &GpuCache, - geometry_kind: MaskGeometryKind) { - - for &(packed_layer_index, ref info) in clips.iter() { + fn add(&mut self, + task_address: RenderTaskAddress, + clips: &[ClipWorkItem], + resource_cache: &ResourceCache, + gpu_cache: &GpuCache, + geometry_kind: MaskGeometryKind, + clip_store: &ClipStore) { + for work_item in clips.iter() { let instance = CacheClipInstance { render_task_address: task_address.0 as i32, - layer_index: packed_layer_index.0 as i32, + layer_index: work_item.layer_index.0 as i32, segment: 0, clip_data_address: GpuCacheAddress::invalid(), resource_address: GpuCacheAddress::invalid(), }; + let info = clip_store.get_opt(&work_item.clip_sources) + .expect("bug: clip handle should be valid"); - if !info.complex_clip_range.is_empty() { - let base_gpu_address = gpu_cache.get_address(&info.complex_clip_range.location); + if !info.mask_cache_info.complex_clip_range.is_empty() { + let base_gpu_address = gpu_cache.get_address(&info.mask_cache_info.complex_clip_range.location); - for clip_index in 0 .. info.complex_clip_range.get_count() { + for clip_index in 0 .. info.mask_cache_info.complex_clip_range.get_count() { let gpu_address = base_gpu_address + CLIP_DATA_GPU_BLOCKS * clip_index; match geometry_kind { MaskGeometryKind::Default => { @@ -726,10 +728,10 @@ impl ClipBatcher { } } - if !info.layer_clip_range.is_empty() { - let base_gpu_address = gpu_cache.get_address(&info.layer_clip_range.location); + if work_item.apply_rectangles && !info.mask_cache_info.layer_clip_range.is_empty() { + let base_gpu_address = gpu_cache.get_address(&info.mask_cache_info.layer_clip_range.location); - for clip_index in 0 .. info.layer_clip_range.get_count() { + for clip_index in 0 .. info.mask_cache_info.layer_clip_range.get_count() { let gpu_address = base_gpu_address + CLIP_DATA_GPU_BLOCKS * clip_index; self.rectangles.push(CacheClipInstance { clip_data_address: gpu_address, @@ -739,7 +741,7 @@ impl ClipBatcher { } } - if let Some((ref mask, ref gpu_location)) = info.image { + if let Some((ref mask, ref gpu_location)) = info.mask_cache_info.image { let cache_item = resource_cache.get_cached_image(mask.image, ImageRendering::Auto, None); self.images.entry(cache_item.texture_id) .or_insert(Vec::new()) @@ -750,7 +752,7 @@ impl ClipBatcher { }) } - for &(ref source, ref gpu_location) in &info.border_corners { + for &(ref source, ref gpu_location) in &info.mask_cache_info.border_corners { let gpu_address = gpu_cache.get_address(gpu_location); self.border_clears.push(CacheClipInstance { clip_data_address: gpu_address, @@ -829,7 +831,8 @@ pub trait RenderTarget { task_id: RenderTaskId, ctx: &RenderTargetContext, gpu_cache: &GpuCache, - render_tasks: &RenderTaskTree); + render_tasks: &RenderTaskTree, + clip_store: &ClipStore); fn used_rect(&self) -> DeviceIntRect; } @@ -875,8 +878,12 @@ impl RenderTargetList { task_id: RenderTaskId, ctx: &RenderTargetContext, gpu_cache: &GpuCache, - render_tasks: &mut RenderTaskTree) { - self.targets.last_mut().unwrap().add_task(task_id, ctx, gpu_cache, render_tasks); + render_tasks: &mut RenderTaskTree, + clip_store: &ClipStore) { + self.targets + .last_mut() + .unwrap() + .add_task(task_id, ctx, gpu_cache, render_tasks, clip_store); } fn allocate(&mut self, alloc_size: DeviceUintSize) -> (DeviceUintPoint, RenderTargetIndex) { @@ -957,7 +964,8 @@ impl RenderTarget for ColorRenderTarget { task_id: RenderTaskId, ctx: &RenderTargetContext, gpu_cache: &GpuCache, - render_tasks: &RenderTaskTree) { + render_tasks: &RenderTaskTree, + _: &ClipStore) { let task = render_tasks.get(task_id); match task.kind { @@ -1094,7 +1102,8 @@ impl RenderTarget for AlphaRenderTarget { task_id: RenderTaskId, ctx: &RenderTargetContext, gpu_cache: &GpuCache, - render_tasks: &RenderTaskTree) { + render_tasks: &RenderTaskTree, + clip_store: &ClipStore) { let task = render_tasks.get(task_id); match task.kind { RenderTaskKind::Alias(..) => { @@ -1128,7 +1137,8 @@ impl RenderTarget for AlphaRenderTarget { &task_info.clips, &ctx.resource_cache, gpu_cache, - task_info.geometry_kind); + task_info.geometry_kind, + clip_store); } } } @@ -1185,7 +1195,8 @@ impl RenderPass { ctx: &RenderTargetContext, gpu_cache: &mut GpuCache, render_tasks: &mut RenderTaskTree, - deferred_resolves: &mut Vec) { + deferred_resolves: &mut Vec, + clip_store: &ClipStore) { profile_scope!("RenderPass::build"); // Step through each task, adding to batches as appropriate. @@ -1241,8 +1252,18 @@ impl RenderPass { }; match target_kind { - RenderTargetKind::Color => self.color_targets.add_task(task_id, ctx, gpu_cache, render_tasks), - RenderTargetKind::Alpha => self.alpha_targets.add_task(task_id, ctx, gpu_cache, render_tasks), + RenderTargetKind::Color => self.color_targets + .add_task(task_id, + ctx, + gpu_cache, + render_tasks, + clip_store), + RenderTargetKind::Alpha => self.alpha_targets + .add_task(task_id, + ctx, + gpu_cache, + render_tasks, + clip_store), } } From 55ff4d487e2564d3ad48ebf21bed541d0949d296 Mon Sep 17 00:00:00 2001 From: Glenn Watson Date: Fri, 8 Sep 2017 11:29:11 +1000 Subject: [PATCH 3/5] Move MaskBounds into the ClipSources (from the MaskCacheInfo struct). --- webrender/src/clip.rs | 120 ++++++++++++++++++++++++++++++-- webrender/src/frame_builder.rs | 4 +- webrender/src/mask_cache.rs | 123 +-------------------------------- webrender/src/render_task.rs | 2 +- 4 files changed, 120 insertions(+), 129 deletions(-) diff --git a/webrender/src/clip.rs b/webrender/src/clip.rs index 1ea5f250a5..c52777b280 100644 --- a/webrender/src/clip.rs +++ b/webrender/src/clip.rs @@ -3,13 +3,16 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use api::{BorderRadius, ComplexClipRegion, ImageMask, ImageRendering}; -use api::{LayerPoint, LayerRect, LayerToWorldTransform, LocalClip}; +use api::{DeviceIntRect, LayerPoint, LayerRect, LayerSize, LayerToWorldTransform, LocalClip}; use border::BorderCornerClipSource; use freelist::{FreeList, FreeListHandle, WeakFreeListHandle}; use gpu_cache::GpuCache; use mask_cache::MaskCacheInfo; use resource_cache::ResourceCache; use std::ops::Not; +use util::{extract_inner_rect_safe, TransformedRect}; + +const MAX_CLIP: f32 = 1000000.0; pub type ClipStore = FreeList; pub type ClipSourcesHandle = FreeListHandle; @@ -108,6 +111,7 @@ impl From for ClipSources { pub struct ClipSources { clips: Vec, pub mask_cache_info: MaskCacheInfo, + pub bounds: MaskBounds, } impl ClipSources { @@ -117,6 +121,10 @@ impl ClipSources { ClipSources { clips, mask_cache_info, + bounds: MaskBounds { + inner: None, + outer: None, + }, } } @@ -133,11 +141,65 @@ impl ClipSources { return; } - self.mask_cache_info - .update(&self.clips, - layer_transform, - gpu_cache, - device_pixel_ratio); + // compute the local bounds + if self.bounds.inner.is_none() { + let mut local_rect = Some(LayerRect::new(LayerPoint::new(-MAX_CLIP, -MAX_CLIP), + LayerSize::new(2.0 * MAX_CLIP, 2.0 * MAX_CLIP))); + let mut local_inner = local_rect; + let mut has_clip_out = false; + let mut has_border_clip = false; + + for source in &self.clips { + match *source { + ClipSource::Image(ref mask) => { + if !mask.repeat { + local_rect = local_rect.and_then(|r| r.intersection(&mask.rect)); + } + local_inner = None; + } + ClipSource::Rectangle(rect) => { + local_rect = local_rect.and_then(|r| r.intersection(&rect)); + local_inner = local_inner.and_then(|r| r.intersection(&rect)); + } + ClipSource::RoundedRectangle(ref rect, ref radius, mode) => { + // Once we encounter a clip-out, we just assume the worst + // case clip mask size, for now. + if mode == ClipMode::ClipOut { + has_clip_out = true; + break; + } + + local_rect = local_rect.and_then(|r| r.intersection(rect)); + + let inner_rect = extract_inner_rect_safe(rect, radius); + local_inner = local_inner.and_then(|r| inner_rect.and_then(|ref inner| r.intersection(inner))); + } + ClipSource::BorderCorner{..} => { + has_border_clip = true; + } + } + } + + // Work out the type of mask geometry we have, based on the + // list of clip sources above. + self.bounds = if has_clip_out || has_border_clip { + // For clip-out, the mask rect is not known. + MaskBounds { + outer: None, + inner: Some(LayerRect::zero().into()), + } + } else { + MaskBounds { + outer: Some(local_rect.unwrap_or(LayerRect::zero()).into()), + inner: Some(local_inner.unwrap_or(LayerRect::zero()).into()), + } + }; + } + + // update the screen bounds + self.bounds.update(layer_transform, device_pixel_ratio); + + self.mask_cache_info.update(&self.clips, gpu_cache); for clip in &self.clips { if let ClipSource::Image(ref mask) = *clip { @@ -153,3 +215,49 @@ impl ClipSources { self.mask_cache_info.is_masking() } } + +/// Represents a local rect and a device space +/// rectangles that are either outside or inside bounds. +#[derive(Clone, Debug, PartialEq)] +pub struct Geometry { + pub local_rect: LayerRect, + pub device_rect: DeviceIntRect, +} + +impl From for Geometry { + fn from(local_rect: LayerRect) -> Self { + Geometry { + local_rect, + device_rect: DeviceIntRect::zero(), + } + } +} + +/// Depending on the complexity of the clip, we may either +/// know the outer and/or inner rect, or neither or these. +/// In the case of a clip-out, we currently set the mask +/// bounds to be unknown. This is conservative, but ensures +/// correctness. In the future we can make this a lot +/// more clever with some proper region handling. +#[derive(Clone, Debug, PartialEq)] +pub struct MaskBounds { + pub outer: Option, + pub inner: Option, +} + +impl MaskBounds { + pub fn update(&mut self, transform: &LayerToWorldTransform, device_pixel_ratio: f32) { + if let Some(ref mut outer) = self.outer { + let transformed = TransformedRect::new(&outer.local_rect, + transform, + device_pixel_ratio); + outer.device_rect = transformed.bounding_rect; + } + if let Some(ref mut inner) = self.inner { + let transformed = TransformedRect::new(&inner.local_rect, + transform, + device_pixel_ratio); + inner.device_rect = transformed.inner_rect; + } + } +} diff --git a/webrender/src/frame_builder.rs b/webrender/src/frame_builder.rs index 677bb5f941..090234f945 100644 --- a/webrender/src/frame_builder.rs +++ b/webrender/src/frame_builder.rs @@ -1905,7 +1905,7 @@ impl<'a> LayerRectCalculationAndCullingPass<'a> { } // apply the outer device bounds of the clip stack - if let Some(ref outer) = clip_sources.mask_cache_info.bounds.outer { + if let Some(ref outer) = clip_sources.bounds.outer { bounding_rect = match bounding_rect.intersection(&outer.device_rect) { Some(rect) => rect, None => return None, @@ -2000,7 +2000,7 @@ impl<'a> LayerRectCalculationAndCullingPass<'a> { let clip_task = if prim_clips.is_masking() { // Take into account the actual clip info of the primitive, and // mutate the current bounds accordingly. - let mask_rect = match prim_clips.mask_cache_info.bounds.outer { + let mask_rect = match prim_clips.bounds.outer { Some(ref outer) => { match prim_screen_rect.intersection(&outer.device_rect) { Some(rect) => rect, diff --git a/webrender/src/mask_cache.rs b/webrender/src/mask_cache.rs index 05d39fe52c..0e9b07990a 100644 --- a/webrender/src/mask_cache.rs +++ b/webrender/src/mask_cache.rs @@ -2,15 +2,11 @@ * 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::{DeviceIntRect, ImageMask, LayerPoint, LayerRect}; -use api::{LayerSize, LayerToWorldTransform}; +use api::ImageMask; use border::BorderCornerClipSource; use clip::{ClipMode, ClipSource}; use gpu_cache::{GpuCache, GpuCacheHandle, ToGpuBlocks}; use prim_store::{CLIP_DATA_GPU_BLOCKS, ClipData, ImageMaskData}; -use util::{extract_inner_rect_safe, TransformedRect}; - -const MAX_CLIP: f32 = 1000000.0; #[derive(Debug, Copy, Clone)] pub struct ClipAddressRange { @@ -43,52 +39,6 @@ impl ClipAddressRange { } } -/// Represents a local rect and a device space -/// rectangles that are either outside or inside bounds. -#[derive(Clone, Debug, PartialEq)] -pub struct Geometry { - pub local_rect: LayerRect, - pub device_rect: DeviceIntRect, -} - -impl From for Geometry { - fn from(local_rect: LayerRect) -> Self { - Geometry { - local_rect, - device_rect: DeviceIntRect::zero(), - } - } -} - -/// Depending on the complexity of the clip, we may either -/// know the outer and/or inner rect, or neither or these. -/// In the case of a clip-out, we currently set the mask -/// bounds to be unknown. This is conservative, but ensures -/// correctness. In the future we can make this a lot -/// more clever with some proper region handling. -#[derive(Clone, Debug, PartialEq)] -pub struct MaskBounds { - pub outer: Option, - pub inner: Option, -} - -impl MaskBounds { - pub fn update(&mut self, transform: &LayerToWorldTransform, device_pixel_ratio: f32) { - if let Some(ref mut outer) = self.outer { - let transformed = TransformedRect::new(&outer.local_rect, - transform, - device_pixel_ratio); - outer.device_rect = transformed.bounding_rect; - } - if let Some(ref mut inner) = self.inner { - let transformed = TransformedRect::new(&inner.local_rect, - transform, - device_pixel_ratio); - inner.device_rect = transformed.inner_rect; - } - } -} - #[derive(Clone, Debug)] pub struct MaskCacheInfo { /// Clip items that are always applied @@ -98,7 +48,6 @@ pub struct MaskCacheInfo { pub layer_clip_range: ClipAddressRange, pub image: Option<(ImageMask, GpuCacheHandle)>, pub border_corners: Vec<(BorderCornerClipSource, GpuCacheHandle)>, - pub bounds: MaskBounds, } impl MaskCacheInfo { @@ -135,75 +84,13 @@ impl MaskCacheInfo { layer_clip_range: ClipAddressRange::new(layer_clip_count), image, border_corners, - bounds: MaskBounds { - inner: None, - outer: None, - }, } } pub fn update(&mut self, sources: &[ClipSource], - transform: &LayerToWorldTransform, - gpu_cache: &mut GpuCache, - device_pixel_ratio: f32) - -> &MaskBounds { - // Step[1] - compute the local bounds - //TODO: move to initialization stage? - if self.bounds.inner.is_none() { - let mut local_rect = Some(LayerRect::new(LayerPoint::new(-MAX_CLIP, -MAX_CLIP), - LayerSize::new(2.0 * MAX_CLIP, 2.0 * MAX_CLIP))); - let mut local_inner = local_rect; - let mut has_clip_out = false; - let has_border_clip = !self.border_corners.is_empty(); - - for source in sources { - match *source { - ClipSource::Image(ref mask) => { - if !mask.repeat { - local_rect = local_rect.and_then(|r| r.intersection(&mask.rect)); - } - local_inner = None; - } - ClipSource::Rectangle(rect) => { - local_rect = local_rect.and_then(|r| r.intersection(&rect)); - local_inner = local_inner.and_then(|r| r.intersection(&rect)); - } - ClipSource::RoundedRectangle(ref rect, ref radius, mode) => { - // Once we encounter a clip-out, we just assume the worst - // case clip mask size, for now. - if mode == ClipMode::ClipOut { - has_clip_out = true; - break; - } - - local_rect = local_rect.and_then(|r| r.intersection(rect)); - - let inner_rect = extract_inner_rect_safe(rect, radius); - local_inner = local_inner.and_then(|r| inner_rect.and_then(|ref inner| r.intersection(inner))); - } - ClipSource::BorderCorner{..} => {} - } - } - - // Work out the type of mask geometry we have, based on the - // list of clip sources above. - self.bounds = if has_clip_out || has_border_clip { - // For clip-out, the mask rect is not known. - MaskBounds { - outer: None, - inner: Some(LayerRect::zero().into()), - } - } else { - MaskBounds { - outer: Some(local_rect.unwrap_or(LayerRect::zero()).into()), - inner: Some(local_inner.unwrap_or(LayerRect::zero()).into()), - } - }; - } - - // Step[2] - update GPU cache data - + gpu_cache: &mut GpuCache) { + // update GPU cache data if let Some(block_count) = self.complex_clip_range.get_block_count() { if let Some(mut request) = gpu_cache.request(&mut self.complex_clip_range.location) { for source in sources { @@ -242,10 +129,6 @@ impl MaskCacheInfo { data.write_gpu_blocks(request); } } - - // Step[3] - update the screen bounds - self.bounds.update(transform, device_pixel_ratio); - &self.bounds } /// Check if this `MaskCacheInfo` actually carries any masks. diff --git a/webrender/src/render_task.rs b/webrender/src/render_task.rs index 6bccb6d9d5..75f7947aa5 100644 --- a/webrender/src/render_task.rs +++ b/webrender/src/render_task.rs @@ -286,7 +286,7 @@ impl RenderTask { return false; } - match clip_info.mask_cache_info.bounds.inner { + match clip_info.bounds.inner { Some(ref inner) if !inner.device_rect.is_empty() => { inner_rect = inner_rect.and_then(|r| r.intersection(&inner.device_rect)); !inner.device_rect.contains_rect(&task_rect) From fe7444e7772eb711cd219802a2cb3f6ade1dc65d Mon Sep 17 00:00:00 2001 From: Glenn Watson Date: Fri, 8 Sep 2017 12:03:34 +1000 Subject: [PATCH 4/5] Move remaining mask cache code into ClipSources, and simplify it. We no longer need to copy the border sources etc into the mask cache structures - they can be referenced directly from the clip sources. We also use a separate GPU cache handle for each clip now, so the ClipAddressRange code is no longer needed. This is possible since we use the GpuCache now, which doesn't need to allocate space during initialization. This also simplifies the code in the clip batcher that adds clip instances to the render targets. Add support for multiple image masks (a by-product of removing the init step of the mask cache code). --- webrender/src/clip.rs | 41 +++++++--- webrender/src/lib.rs | 1 - webrender/src/mask_cache.rs | 141 ----------------------------------- webrender/src/prim_store.rs | 3 - webrender/src/render_task.rs | 30 ++++++-- webrender/src/tiling.rs | 134 ++++++++++++++++----------------- 6 files changed, 118 insertions(+), 232 deletions(-) delete mode 100644 webrender/src/mask_cache.rs diff --git a/webrender/src/clip.rs b/webrender/src/clip.rs index c52777b280..5110587cac 100644 --- a/webrender/src/clip.rs +++ b/webrender/src/clip.rs @@ -6,8 +6,8 @@ use api::{BorderRadius, ComplexClipRegion, ImageMask, ImageRendering}; use api::{DeviceIntRect, LayerPoint, LayerRect, LayerSize, LayerToWorldTransform, LocalClip}; use border::BorderCornerClipSource; use freelist::{FreeList, FreeListHandle, WeakFreeListHandle}; -use gpu_cache::GpuCache; -use mask_cache::MaskCacheInfo; +use gpu_cache::{GpuCache, GpuCacheHandle, ToGpuBlocks}; +use prim_store::{ClipData, ImageMaskData}; use resource_cache::ResourceCache; use std::ops::Not; use util::{extract_inner_rect_safe, TransformedRect}; @@ -109,18 +109,16 @@ impl From for ClipSources { #[derive(Debug)] pub struct ClipSources { - clips: Vec, - pub mask_cache_info: MaskCacheInfo, + pub clips: Vec, + pub handles: Vec, pub bounds: MaskBounds, } impl ClipSources { pub fn new(clips: Vec) -> ClipSources { - let mask_cache_info = MaskCacheInfo::new(&clips); - ClipSources { + handles: Vec::with_capacity(clips.len()), clips, - mask_cache_info, bounds: MaskBounds { inner: None, outer: None, @@ -150,6 +148,8 @@ impl ClipSources { let mut has_border_clip = false; for source in &self.clips { + self.handles.push(GpuCacheHandle::new()); + match *source { ClipSource::Image(ref mask) => { if !mask.repeat { @@ -166,7 +166,6 @@ impl ClipSources { // case clip mask size, for now. if mode == ClipMode::ClipOut { has_clip_out = true; - break; } local_rect = local_rect.and_then(|r| r.intersection(rect)); @@ -199,7 +198,29 @@ impl ClipSources { // update the screen bounds self.bounds.update(layer_transform, device_pixel_ratio); - self.mask_cache_info.update(&self.clips, gpu_cache); + for (source, handle) in self.clips.iter_mut().zip(self.handles.iter_mut()) { + if let Some(mut request) = gpu_cache.request(handle) { + match *source { + ClipSource::Image(ref mask) => { + let data = ImageMaskData { + local_rect: mask.rect, + }; + data.write_gpu_blocks(request); + } + ClipSource::Rectangle(rect) => { + let data = ClipData::uniform(rect, 0.0, ClipMode::Clip); + data.write(&mut request); + } + ClipSource::RoundedRectangle(ref rect, ref radius, mode) => { + let data = ClipData::rounded_rect(rect, radius, mode); + data.write(&mut request); + } + ClipSource::BorderCorner(ref mut source) => { + source.write(request); + } + } + } + } for clip in &self.clips { if let ClipSource::Image(ref mask) = *clip { @@ -212,7 +233,7 @@ impl ClipSources { } pub fn is_masking(&self) -> bool { - self.mask_cache_info.is_masking() + !self.clips.is_empty() } } diff --git a/webrender/src/lib.rs b/webrender/src/lib.rs index 1eacc5f05b..e1595ed2d3 100644 --- a/webrender/src/lib.rs +++ b/webrender/src/lib.rs @@ -69,7 +69,6 @@ mod glyph_rasterizer; mod gpu_cache; mod gpu_types; mod internal_types; -mod mask_cache; mod prim_store; mod print_tree; mod profiler; diff --git a/webrender/src/mask_cache.rs b/webrender/src/mask_cache.rs deleted file mode 100644 index 0e9b07990a..0000000000 --- a/webrender/src/mask_cache.rs +++ /dev/null @@ -1,141 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * 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::ImageMask; -use border::BorderCornerClipSource; -use clip::{ClipMode, ClipSource}; -use gpu_cache::{GpuCache, GpuCacheHandle, ToGpuBlocks}; -use prim_store::{CLIP_DATA_GPU_BLOCKS, ClipData, ImageMaskData}; - -#[derive(Debug, Copy, Clone)] -pub struct ClipAddressRange { - pub location: GpuCacheHandle, - item_count: usize, -} - -impl ClipAddressRange { - fn new(count: usize) -> Self { - ClipAddressRange { - location: GpuCacheHandle::new(), - item_count: count, - } - } - - pub fn is_empty(&self) -> bool { - self.item_count == 0 - } - - pub fn get_count(&self) -> usize { - self.item_count - } - - fn get_block_count(&self) -> Option { - if self.item_count != 0 { - Some(self.item_count * CLIP_DATA_GPU_BLOCKS) - } else { - None - } - } -} - -#[derive(Clone, Debug)] -pub struct MaskCacheInfo { - /// Clip items that are always applied - pub complex_clip_range: ClipAddressRange, - /// Clip items that are only applied if the clip space is transformed from - /// the local space of target primitive/layer. - pub layer_clip_range: ClipAddressRange, - pub image: Option<(ImageMask, GpuCacheHandle)>, - pub border_corners: Vec<(BorderCornerClipSource, GpuCacheHandle)>, -} - -impl MaskCacheInfo { - /// Create a new mask cache info. It allocates the GPU store data but leaves - /// it uninitialized for the following `update()` call to deal with. - pub fn new(clips: &[ClipSource]) -> MaskCacheInfo { - let mut image = None; - let mut border_corners = Vec::new(); - let mut complex_clip_count = 0; - let mut layer_clip_count = 0; - - // Work out how much clip data space we need to allocate - // and if we have an image mask. - for clip in clips { - match *clip { - ClipSource::RoundedRectangle(..) => { - complex_clip_count += 1; - } - ClipSource::Rectangle(..) => { - layer_clip_count += 1; - } - ClipSource::Image(image_mask) => { - debug_assert!(image.is_none()); // TODO(gw): Support >1 image mask! - image = Some((image_mask, GpuCacheHandle::new())); - } - ClipSource::BorderCorner(ref source) => { - border_corners.push((source.clone(), GpuCacheHandle::new())); - } - } - } - - MaskCacheInfo { - complex_clip_range: ClipAddressRange::new(complex_clip_count), - layer_clip_range: ClipAddressRange::new(layer_clip_count), - image, - border_corners, - } - } - - pub fn update(&mut self, - sources: &[ClipSource], - gpu_cache: &mut GpuCache) { - // update GPU cache data - if let Some(block_count) = self.complex_clip_range.get_block_count() { - if let Some(mut request) = gpu_cache.request(&mut self.complex_clip_range.location) { - for source in sources { - if let ClipSource::RoundedRectangle(ref rect, ref radius, mode) = *source { - let data = ClipData::rounded_rect(rect, radius, mode); - data.write(&mut request); - } - } - assert_eq!(request.close(), block_count); - } - } - - if let Some(block_count) = self.layer_clip_range.get_block_count() { - if let Some(mut request) = gpu_cache.request(&mut self.layer_clip_range.location) { - for source in sources { - if let ClipSource::Rectangle(rect) = *source { - let data = ClipData::uniform(rect, 0.0, ClipMode::Clip); - data.write(&mut request); - } - } - assert_eq!(request.close(), block_count); - } - } - - for &mut (ref mut border_source, ref mut gpu_location) in &mut self.border_corners { - if let Some(request) = gpu_cache.request(gpu_location) { - border_source.write(request); - } - } - - if let Some((ref mask, ref mut gpu_location)) = self.image { - if let Some(request) = gpu_cache.request(gpu_location) { - let data = ImageMaskData { - local_rect: mask.rect, - }; - data.write_gpu_blocks(request); - } - } - } - - /// Check if this `MaskCacheInfo` actually carries any masks. - pub fn is_masking(&self) -> bool { - self.image.is_some() || - self.complex_clip_range.item_count != 0 || - self.layer_clip_range.item_count != 0 || - !self.border_corners.is_empty() - } -} diff --git a/webrender/src/prim_store.rs b/webrender/src/prim_store.rs index 4548d5ba76..bfc7b56140 100644 --- a/webrender/src/prim_store.rs +++ b/webrender/src/prim_store.rs @@ -18,9 +18,6 @@ use resource_cache::{ImageProperties, ResourceCache}; use std::{mem, usize}; use util::{pack_as_float, TransformedRect, recycle_vec}; - -pub const CLIP_DATA_GPU_BLOCKS: usize = 10; - #[derive(Debug, Copy, Clone)] pub struct PrimitiveOpacity { pub is_opaque: bool, diff --git a/webrender/src/render_task.rs b/webrender/src/render_task.rs index 75f7947aa5..9b05d0fa91 100644 --- a/webrender/src/render_task.rs +++ b/webrender/src/render_task.rs @@ -2,7 +2,7 @@ * 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 clip::{ClipSourcesWeakHandle, ClipStore}; +use clip::{ClipSource, ClipSourcesWeakHandle, ClipStore}; use gpu_cache::GpuCacheHandle; use internal_types::HardwareCompositeOp; use prim_store::{BoxShadowPrimitiveCacheKey, PrimitiveIndex}; @@ -166,13 +166,29 @@ pub struct ClipWorkItem { impl ClipWorkItem { fn get_geometry_kind(&self, clip_store: &ClipStore) -> MaskGeometryKind { - let info = &clip_store.get_opt(&self.clip_sources) + let clips = clip_store.get_opt(&self.clip_sources) .expect("bug: clip handle should be valid") - .mask_cache_info; - if info.border_corners.is_empty() && - info.image.is_none() && - info.complex_clip_range.get_count() == 1 && - (info.layer_clip_range.get_count() == 0 || !self.apply_rectangles) { + .clips(); + let mut rounded_rect_count = 0; + + for clip in clips { + match *clip { + ClipSource::Rectangle(..) => { + if self.apply_rectangles { + return MaskGeometryKind::Default; + } + } + ClipSource::RoundedRectangle(..) => { + rounded_rect_count += 1; + } + ClipSource::Image(..) | + ClipSource::BorderCorner(..) => { + return MaskGeometryKind::Default; + } + } + } + + if rounded_rect_count == 1 { MaskGeometryKind::CornersOnly } else { MaskGeometryKind::Default diff --git a/webrender/src/tiling.rs b/webrender/src/tiling.rs index 1abe772f8b..91f3360d60 100644 --- a/webrender/src/tiling.rs +++ b/webrender/src/tiling.rs @@ -3,13 +3,13 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use border::{BorderCornerInstance, BorderCornerSide}; -use clip::ClipStore; +use clip::{ClipSource, ClipStore}; use device::Texture; use gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle, GpuCacheUpdateList}; use gpu_types::BoxShadowCacheInstance; use internal_types::BatchTextures; use internal_types::{FastHashMap, SourceTexture}; -use prim_store::{CLIP_DATA_GPU_BLOCKS, DeferredResolve}; +use prim_store::{DeferredResolve}; use prim_store::{PrimitiveIndex, PrimitiveKind, PrimitiveMetadata, PrimitiveStore}; use profiler::FrameProfileCounters; use render_task::{AlphaRenderItem, ClipWorkItem, MaskGeometryKind, MaskSegment}; @@ -687,84 +687,78 @@ impl ClipBatcher { let info = clip_store.get_opt(&work_item.clip_sources) .expect("bug: clip handle should be valid"); - if !info.mask_cache_info.complex_clip_range.is_empty() { - let base_gpu_address = gpu_cache.get_address(&info.mask_cache_info.complex_clip_range.location); - - for clip_index in 0 .. info.mask_cache_info.complex_clip_range.get_count() { - let gpu_address = base_gpu_address + CLIP_DATA_GPU_BLOCKS * clip_index; - match geometry_kind { - MaskGeometryKind::Default => { + for (source, handle) in info.clips.iter().zip(info.handles.iter()) { + let gpu_address = gpu_cache.get_address(handle); + + match *source { + ClipSource::Image(ref mask) => { + let cache_item = resource_cache.get_cached_image(mask.image, ImageRendering::Auto, None); + self.images.entry(cache_item.texture_id) + .or_insert(Vec::new()) + .push(CacheClipInstance { + clip_data_address: gpu_address, + resource_address: gpu_cache.get_address(&cache_item.uv_rect_handle), + ..instance + }); + } + ClipSource::Rectangle(..) => { + if work_item.apply_rectangles { self.rectangles.push(CacheClipInstance { clip_data_address: gpu_address, segment: MaskSegment::All as i32, ..instance }); } - MaskGeometryKind::CornersOnly => { - self.rectangles.extend_from_slice(&[ - CacheClipInstance { - clip_data_address: gpu_address, - segment: MaskSegment::TopLeftCorner as i32, - ..instance - }, - CacheClipInstance { - clip_data_address: gpu_address, - segment: MaskSegment::TopRightCorner as i32, - ..instance - }, - CacheClipInstance { - clip_data_address: gpu_address, - segment: MaskSegment::BottomLeftCorner as i32, - ..instance - }, - CacheClipInstance { + } + ClipSource::RoundedRectangle(..) => { + match geometry_kind { + MaskGeometryKind::Default => { + self.rectangles.push(CacheClipInstance { clip_data_address: gpu_address, - segment: MaskSegment::BottomRightCorner as i32, + segment: MaskSegment::All as i32, ..instance - }, - ]); + }); + } + MaskGeometryKind::CornersOnly => { + self.rectangles.extend_from_slice(&[ + CacheClipInstance { + clip_data_address: gpu_address, + segment: MaskSegment::TopLeftCorner as i32, + ..instance + }, + CacheClipInstance { + clip_data_address: gpu_address, + segment: MaskSegment::TopRightCorner as i32, + ..instance + }, + CacheClipInstance { + clip_data_address: gpu_address, + segment: MaskSegment::BottomLeftCorner as i32, + ..instance + }, + CacheClipInstance { + clip_data_address: gpu_address, + segment: MaskSegment::BottomRightCorner as i32, + ..instance + }, + ]); + } + } + } + ClipSource::BorderCorner(ref source) => { + self.border_clears.push(CacheClipInstance { + clip_data_address: gpu_address, + segment: 0, + ..instance + }); + for clip_index in 0..source.actual_clip_count { + self.borders.push(CacheClipInstance { + clip_data_address: gpu_address, + segment: 1 + clip_index as i32, + ..instance + }) } } - } - } - - if work_item.apply_rectangles && !info.mask_cache_info.layer_clip_range.is_empty() { - let base_gpu_address = gpu_cache.get_address(&info.mask_cache_info.layer_clip_range.location); - - for clip_index in 0 .. info.mask_cache_info.layer_clip_range.get_count() { - let gpu_address = base_gpu_address + CLIP_DATA_GPU_BLOCKS * clip_index; - self.rectangles.push(CacheClipInstance { - clip_data_address: gpu_address, - segment: MaskSegment::All as i32, - ..instance - }); - } - } - - if let Some((ref mask, ref gpu_location)) = info.mask_cache_info.image { - let cache_item = resource_cache.get_cached_image(mask.image, ImageRendering::Auto, None); - self.images.entry(cache_item.texture_id) - .or_insert(Vec::new()) - .push(CacheClipInstance { - clip_data_address: gpu_cache.get_address(gpu_location), - resource_address: gpu_cache.get_address(&cache_item.uv_rect_handle), - ..instance - }) - } - - for &(ref source, ref gpu_location) in &info.mask_cache_info.border_corners { - let gpu_address = gpu_cache.get_address(gpu_location); - self.border_clears.push(CacheClipInstance { - clip_data_address: gpu_address, - segment: 0, - ..instance - }); - for clip_index in 0..source.actual_clip_count { - self.borders.push(CacheClipInstance { - clip_data_address: gpu_address, - segment: 1 + clip_index as i32, - ..instance - }) } } } From e1ef40865415d2d0e97500a012fbee48f9aba06e Mon Sep 17 00:00:00 2001 From: Glenn Watson Date: Tue, 12 Sep 2017 06:52:50 +1000 Subject: [PATCH 5/5] Switch handles to use tuples in clip.rs --- webrender/src/clip.rs | 18 +++++++++--------- webrender/src/render_task.rs | 2 +- webrender/src/tiling.rs | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/webrender/src/clip.rs b/webrender/src/clip.rs index 5110587cac..26142de207 100644 --- a/webrender/src/clip.rs +++ b/webrender/src/clip.rs @@ -109,15 +109,17 @@ impl From for ClipSources { #[derive(Debug)] pub struct ClipSources { - pub clips: Vec, - pub handles: Vec, + pub clips: Vec<(ClipSource, GpuCacheHandle)>, pub bounds: MaskBounds, } impl ClipSources { pub fn new(clips: Vec) -> ClipSources { + let clips = clips.into_iter() + .map(|clip| (clip, GpuCacheHandle::new())) + .collect(); + ClipSources { - handles: Vec::with_capacity(clips.len()), clips, bounds: MaskBounds { inner: None, @@ -126,7 +128,7 @@ impl ClipSources { } } - pub fn clips(&self) -> &[ClipSource] { + pub fn clips(&self) -> &[(ClipSource, GpuCacheHandle)] { &self.clips } @@ -147,9 +149,7 @@ impl ClipSources { let mut has_clip_out = false; let mut has_border_clip = false; - for source in &self.clips { - self.handles.push(GpuCacheHandle::new()); - + for &(ref source, _) in &self.clips { match *source { ClipSource::Image(ref mask) => { if !mask.repeat { @@ -198,7 +198,7 @@ impl ClipSources { // update the screen bounds self.bounds.update(layer_transform, device_pixel_ratio); - for (source, handle) in self.clips.iter_mut().zip(self.handles.iter_mut()) { + for &mut (ref mut source, ref mut handle) in &mut self.clips { if let Some(mut request) = gpu_cache.request(handle) { match *source { ClipSource::Image(ref mask) => { @@ -222,7 +222,7 @@ impl ClipSources { } } - for clip in &self.clips { + for &(ref clip, _) in &self.clips { if let ClipSource::Image(ref mask) = *clip { resource_cache.request_image(mask.image, ImageRendering::Auto, diff --git a/webrender/src/render_task.rs b/webrender/src/render_task.rs index 9b05d0fa91..9036428c46 100644 --- a/webrender/src/render_task.rs +++ b/webrender/src/render_task.rs @@ -171,7 +171,7 @@ impl ClipWorkItem { .clips(); let mut rounded_rect_count = 0; - for clip in clips { + for &(ref clip, _) in clips { match *clip { ClipSource::Rectangle(..) => { if self.apply_rectangles { diff --git a/webrender/src/tiling.rs b/webrender/src/tiling.rs index 91f3360d60..7d186b718d 100644 --- a/webrender/src/tiling.rs +++ b/webrender/src/tiling.rs @@ -687,7 +687,7 @@ impl ClipBatcher { let info = clip_store.get_opt(&work_item.clip_sources) .expect("bug: clip handle should be valid"); - for (source, handle) in info.clips.iter().zip(info.handles.iter()) { + for &(ref source, ref handle) in &info.clips { let gpu_address = gpu_cache.get_address(handle); match *source {