From d0a7736e4364e4b4a66fa8533603969a15244302 Mon Sep 17 00:00:00 2001 From: Dan Glastonbury Date: Wed, 12 Dec 2018 11:41:22 +1000 Subject: [PATCH 1/2] Extract LineDecoration --- webrender/src/batch.rs | 7 +- webrender/src/display_list_flattener.rs | 20 ++- webrender/src/picture.rs | 4 +- webrender/src/prim_store/line_dec.rs | 195 ++++++++++++++++++++++++ webrender/src/prim_store/mod.rs | 170 +++++++-------------- webrender/src/profiler.rs | 3 + webrender/src/render_backend.rs | 11 +- webrender/src/render_task.rs | 3 +- webrender/src/scene_builder.rs | 18 +++ 9 files changed, 304 insertions(+), 127 deletions(-) create mode 100644 webrender/src/prim_store/line_dec.rs diff --git a/webrender/src/batch.rs b/webrender/src/batch.rs index 9d7d97563e..ef12fb2f62 100644 --- a/webrender/src/batch.rs +++ b/webrender/src/batch.rs @@ -790,9 +790,8 @@ impl AlphaBatchBuilder { PrimitiveInstanceKind::LineDecoration { data_handle, ref cache_handle, .. } => { // The GPU cache data is stored in the template and reused across // frames and display lists. - - let prim_data = &ctx.resources.prim_data_store[data_handle]; - let prim_cache_address = gpu_cache.get_address(&prim_data.gpu_cache_handle); + let common_data = &ctx.resources.line_decoration_data_store[data_handle].common; + let prim_cache_address = gpu_cache.get_address(&common_data.gpu_cache_handle); let (batch_kind, textures, prim_user_data, segment_user_data) = match cache_handle { Some(cache_handle) => { @@ -827,7 +826,7 @@ impl AlphaBatchBuilder { // TODO(gw): We can abstract some of the common code below into // helper methods, as we port more primitives to make // use of interning. - let blend_mode = if !prim_data.opacity.is_opaque || + let blend_mode = if !common_data.opacity.is_opaque || prim_instance.clip_task_index != ClipTaskIndex::INVALID || transform_kind == TransformedRectKind::Complex { diff --git a/webrender/src/display_list_flattener.rs b/webrender/src/display_list_flattener.rs index cce8d10918..fc54302aa3 100644 --- a/webrender/src/display_list_flattener.rs +++ b/webrender/src/display_list_flattener.rs @@ -24,11 +24,12 @@ use internal_types::{FastHashMap, FastHashSet}; use picture::{Picture3DContext, PictureCompositeMode, PicturePrimitive, PrimitiveList}; use prim_store::{PrimitiveInstance, PrimitiveKeyKind, PictureCompositeKey}; use prim_store::{PrimitiveKey, PrimitiveSceneData, PrimitiveInstanceKind, NinePatchDescriptor}; -use prim_store::{PrimitiveStore, PrimitiveStoreStats, LineDecorationCacheKey}; +use prim_store::{PrimitiveStore, PrimitiveStoreStats}; use prim_store::{ScrollNodeAndClipChain, PictureIndex, register_prim_chase_id, get_line_decoration_sizes}; use prim_store::borders::{ImageBorder, NormalBorderPrim}; use prim_store::gradient::{GradientStopKey, LinearGradient, RadialGradient, RadialGradientParams}; use prim_store::image::{Image, YuvImage}; +use prim_store::line_dec::{LineDecoration, LineDecorationCacheKey}; use prim_store::text_run::TextRun; use render_backend::{DocumentView}; use resource_cache::{FontInstanceMap, ImageRequest}; @@ -1825,6 +1826,9 @@ impl<'a> DisplayListFlattener<'a> { ShadowItem::Image(ref pending_image) => { self.add_shadow_prim(&pending_shadow, pending_image, &mut prims) } + ShadowItem::LineDecoration(ref pending_line_dec) => { + self.add_shadow_prim(&pending_shadow, pending_line_dec, &mut prims) + } ShadowItem::NormalBorder(ref pending_border) => { self.add_shadow_prim(&pending_shadow, pending_border, &mut prims) } @@ -1907,9 +1911,12 @@ impl<'a> DisplayListFlattener<'a> { ShadowItem::Image(pending_image) => { self.add_shadow_prim_to_draw_list(pending_image) }, + ShadowItem::LineDecoration(pending_line_dec) => { + self.add_shadow_prim_to_draw_list(pending_line_dec) + }, ShadowItem::NormalBorder(pending_border) => { self.add_shadow_prim_to_draw_list(pending_border) - } + }, ShadowItem::Primitive(pending_primitive) => { self.add_shadow_prim_to_draw_list(pending_primitive) }, @@ -2092,7 +2099,7 @@ impl<'a> DisplayListFlattener<'a> { clip_and_scroll, &info, Vec::new(), - PrimitiveKeyKind::LineDecoration { + LineDecoration { cache_key, color: color.into(), }, @@ -2683,6 +2690,7 @@ pub struct PendingShadow { pub enum ShadowItem { Shadow(PendingShadow), Image(PendingPrimitive), + LineDecoration(PendingPrimitive), NormalBorder(PendingPrimitive), Primitive(PendingPrimitive), TextRun(PendingPrimitive), @@ -2694,6 +2702,12 @@ impl From> for ShadowItem { } } +impl From> for ShadowItem { + fn from(line_dec: PendingPrimitive) -> Self { + ShadowItem::LineDecoration(line_dec) + } +} + impl From> for ShadowItem { fn from(border: PendingPrimitive) -> Self { ShadowItem::NormalBorder(border) diff --git a/webrender/src/picture.rs b/webrender/src/picture.rs index f25b6a7653..73285596f0 100644 --- a/webrender/src/picture.rs +++ b/webrender/src/picture.rs @@ -1393,7 +1393,6 @@ impl PrimitiveList { let prim_data = match prim_instance.kind { PrimitiveInstanceKind::Picture { data_handle, .. } | - PrimitiveInstanceKind::LineDecoration { data_handle, .. } | PrimitiveInstanceKind::Rectangle { data_handle, .. } | PrimitiveInstanceKind::Clear { data_handle, .. } => { &resources.prim_interner[data_handle] @@ -1404,6 +1403,9 @@ impl PrimitiveList { PrimitiveInstanceKind::ImageBorder { data_handle, .. } => { &resources.image_border_interner[data_handle] } + PrimitiveInstanceKind::LineDecoration { data_handle, .. } => { + &resources.line_decoration_interner[data_handle] + } PrimitiveInstanceKind::LinearGradient { data_handle, .. } => { &resources.linear_grad_interner[data_handle] } diff --git a/webrender/src/prim_store/line_dec.rs b/webrender/src/prim_store/line_dec.rs new file mode 100644 index 0000000000..fdebcaea60 --- /dev/null +++ b/webrender/src/prim_store/line_dec.rs @@ -0,0 +1,195 @@ +/* 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::{ + ColorF, ColorU, LayoutPrimitiveInfo, LayoutRect, LayoutSizeAu, + LineOrientation, LineStyle, PremultipliedColorF, Shadow, +}; +use app_units::Au; +use display_list_flattener::{AsInstanceKind, CreateShadow, IsVisible}; +use frame_builder::{FrameBuildingState}; +use gpu_cache::GpuDataRequest; +use intern; +use prim_store::{ + PrimKey, PrimKeyCommonData, PrimTemplate, PrimTemplateCommonData, + PrimitiveSceneData, PrimitiveStore, +}; +use prim_store::PrimitiveInstanceKind; + +#[derive(Clone, Debug, Hash, PartialEq, Eq)] +#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(feature = "replay", derive(Deserialize))] +pub struct LineDecorationCacheKey { + pub style: LineStyle, + pub orientation: LineOrientation, + pub wavy_line_thickness: Au, + pub size: LayoutSizeAu, +} + +/// Identifying key for a line decoration. +#[derive(Clone, Debug, Hash, PartialEq, Eq)] +#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(feature = "replay", derive(Deserialize))] +pub struct LineDecoration { + // If the cache_key is Some(..) it is a line decoration + // that relies on a render task (e.g. wavy). If the + // cache key is None, it uses a fast path to draw the + // line decoration as a solid rect. + pub cache_key: Option, + pub color: ColorU, +} + +pub type LineDecorationKey = PrimKey; + +impl LineDecorationKey { + pub fn new( + info: &LayoutPrimitiveInfo, + prim_relative_clip_rect: LayoutRect, + line_dec: LineDecoration, + ) -> Self { + LineDecorationKey { + common: PrimKeyCommonData::with_info( + info, + prim_relative_clip_rect, + ), + kind: line_dec, + } + } +} + +impl intern::InternDebug for LineDecorationKey {} + +impl AsInstanceKind for LineDecorationKey { + /// Construct a primitive instance that matches the type + /// of primitive key. + fn as_instance_kind( + &self, + data_handle: LineDecorationDataHandle, + _: &mut PrimitiveStore, + ) -> PrimitiveInstanceKind { + PrimitiveInstanceKind::LineDecoration { + data_handle, + cache_handle: None, + } + } +} + +#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(feature = "replay", derive(Deserialize))] +pub struct LineDecorationData { + pub cache_key: Option, + pub color: ColorF, +} + +impl LineDecorationData { + /// Update the GPU cache for a given primitive template. This may be called multiple + /// times per frame, by each primitive reference that refers to this interned + /// template. The initial request call to the GPU cache ensures that work is only + /// done if the cache entry is invalid (due to first use or eviction). + pub fn update( + &mut self, + common: &mut PrimTemplateCommonData, + frame_state: &mut FrameBuildingState, + ) { + if let Some(ref mut request) = frame_state.gpu_cache.request(&mut common.gpu_cache_handle) { + self.write_prim_gpu_blocks(request); + } + } + + fn write_prim_gpu_blocks( + &self, + request: &mut GpuDataRequest + ) { + match self.cache_key.as_ref() { + Some(cache_key) => { + request.push(self.color.premultiplied()); + request.push(PremultipliedColorF::WHITE); + request.push([ + cache_key.size.width.to_f32_px(), + cache_key.size.height.to_f32_px(), + 0.0, + 0.0, + ]); + } + None => { + request.push(self.color.premultiplied()); + } + } + } +} + +pub type LineDecorationTemplate = PrimTemplate; + +impl From for LineDecorationTemplate { + fn from(line_dec: LineDecorationKey) -> Self { + let common = PrimTemplateCommonData::with_key_common(line_dec.common); + LineDecorationTemplate { + common, + kind: LineDecorationData { + cache_key: line_dec.kind.cache_key, + color: line_dec.kind.color.into(), + } + } + } +} + +#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(feature = "replay", derive(Deserialize))] +#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)] +pub struct LineDecorationDataMarker; + +pub type LineDecorationDataStore = intern::DataStore; +pub type LineDecorationDataHandle = intern::Handle; +pub type LineDecorationDataUpdateList = intern::UpdateList; +pub type LineDecorationDataInterner = intern::Interner; + +impl intern::Internable for LineDecoration { + type Marker = LineDecorationDataMarker; + type Source = LineDecorationKey; + type StoreData = LineDecorationTemplate; + type InternData = PrimitiveSceneData; + + /// Build a new key from self with `info`. + fn build_key( + self, + info: &LayoutPrimitiveInfo, + prim_relative_clip_rect: LayoutRect, + ) -> LineDecorationKey { + LineDecorationKey::new( + info, + prim_relative_clip_rect, + self, + ) + } +} + +impl CreateShadow for LineDecoration { + fn create_shadow(&self, shadow: &Shadow) -> Self { + LineDecoration { + color: shadow.color.into(), + cache_key: self.cache_key.clone(), + } + } +} + +impl IsVisible for LineDecoration { + fn is_visible(&self) -> bool { + self.color.a > 0 + } +} + +#[test] +#[cfg(target_os = "linux")] +fn test_struct_sizes() { + use std::mem; + // The sizes of these structures are critical for performance on a number of + // talos stress tests. If you get a failure here on CI, there's two possibilities: + // (a) You made a structure smaller than it currently is. Great work! Update the + // 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::(), 20, "LineDecoration size changed"); + assert_eq!(mem::size_of::(), 88, "LineDecorationTemplate size changed"); + assert_eq!(mem::size_of::(), 48, "LineDecorationKey size changed"); +} diff --git a/webrender/src/prim_store/mod.rs b/webrender/src/prim_store/mod.rs index 816ae750c5..cf33fa8f60 100644 --- a/webrender/src/prim_store/mod.rs +++ b/webrender/src/prim_store/mod.rs @@ -8,7 +8,7 @@ use api::{FilterOp, ImageRendering, TileOffset, RepeatMode, MixBlendMode}; use api::{LayoutPoint, LayoutRect, LayoutSideOffsets, LayoutSize, PropertyBindingId}; use api::{PremultipliedColorF, PropertyBinding, Shadow}; use api::{WorldPixel, BoxShadowClipMode, WorldRect, LayoutToWorldScale}; -use api::{PicturePixel, RasterPixel, LineStyle, LineOrientation, LayoutSizeAu, AuHelpers}; +use api::{PicturePixel, RasterPixel, LineStyle, LineOrientation, AuHelpers}; use api::LayoutPrimitiveInfo; use app_units::Au; use border::{get_max_scale_for_border, build_border_instances}; @@ -30,6 +30,7 @@ use picture::{ClusterIndex, PrimitiveList, SurfaceIndex, SurfaceInfo, RetainedTi use prim_store::borders::{ImageBorderDataHandle, NormalBorderDataHandle}; use prim_store::gradient::{LinearGradientDataHandle, RadialGradientDataHandle}; use prim_store::image::{ImageDataHandle, ImageInstance, VisibleImageTile, YuvImageDataHandle}; +use prim_store::line_dec::LineDecorationDataHandle; use prim_store::text_run::{TextRunDataHandle, TextRunPrimitive}; #[cfg(debug_assertions)] use render_backend::{FrameId}; @@ -51,6 +52,7 @@ use smallvec::SmallVec; pub mod borders; pub mod gradient; pub mod image; +pub mod line_dec; pub mod text_run; /// Counter for unique primitive IDs for debug tracing. @@ -462,15 +464,6 @@ impl From> for PictureCompositeKey { #[cfg_attr(feature = "replay", derive(Deserialize))] #[derive(Debug, Clone, Eq, PartialEq, Hash)] pub enum PrimitiveKeyKind { - /// Identifying key for a line decoration. - LineDecoration { - // If the cache_key is Some(..) it is a line decoration - // that relies on a render task (e.g. wavy). If the - // cache key is None, it uses a fast path to draw the - // line decoration as a solid rect. - cache_key: Option, - color: ColorU, - }, /// Clear an existing rect, used for special effects on some platforms. Clear, Rectangle { @@ -752,12 +745,6 @@ impl AsInstanceKind for PrimitiveKey { _: &mut PrimitiveStore, ) -> PrimitiveInstanceKind { match self.kind { - PrimitiveKeyKind::LineDecoration { .. } => { - PrimitiveInstanceKind::LineDecoration { - data_handle, - cache_handle: None, - } - } PrimitiveKeyKind::Clear => { PrimitiveInstanceKind::Clear { data_handle @@ -784,10 +771,6 @@ impl AsInstanceKind for PrimitiveKey { #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub enum PrimitiveTemplateKind { - LineDecoration { - cache_key: Option, - color: ColorF, - }, Rectangle { color: ColorF, }, @@ -816,12 +799,6 @@ impl PrimitiveKeyKind { color: color.into(), } } - PrimitiveKeyKind::LineDecoration { cache_key, color } => { - PrimitiveTemplateKind::LineDecoration { - cache_key, - color: color.into(), - } - } } } } @@ -902,23 +879,6 @@ impl PrimitiveTemplateKind { PrimitiveTemplateKind::Rectangle { ref color, .. } => { request.push(color.premultiplied()); } - PrimitiveTemplateKind::LineDecoration { ref cache_key, ref color } => { - match cache_key { - Some(cache_key) => { - request.push(color.premultiplied()); - request.push(PremultipliedColorF::WHITE); - request.push([ - cache_key.size.width.to_f32_px(), - cache_key.size.height.to_f32_px(), - 0.0, - 0.0, - ]); - } - None => { - request.push(color.premultiplied()); - } - } - } PrimitiveTemplateKind::Picture { .. } => {} } } @@ -944,12 +904,6 @@ impl PrimitiveTemplate { PrimitiveTemplateKind::Rectangle { ref color, .. } => { PrimitiveOpacity::from_alpha(color.a) } - PrimitiveTemplateKind::LineDecoration { ref cache_key, ref color } => { - match cache_key { - Some(..) => PrimitiveOpacity::translucent(), - None => PrimitiveOpacity::from_alpha(color.a), - } - } PrimitiveTemplateKind::Picture { .. } => { PrimitiveOpacity::translucent() } @@ -1162,16 +1116,6 @@ impl BrushSegment { } } -#[derive(Clone, Debug, Hash, PartialEq, Eq)] -#[cfg_attr(feature = "capture", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] -pub struct LineDecorationCacheKey { - pub style: LineStyle, - pub orientation: LineOrientation, - pub wavy_line_thickness: Au, - pub size: LayoutSizeAu, -} - #[derive(Debug)] #[repr(C)] struct ClipRect { @@ -1409,8 +1353,7 @@ impl IsVisible for PrimitiveKeyKind { PrimitiveKeyKind::Picture { .. } => { true } - PrimitiveKeyKind::Rectangle { ref color, .. } | - PrimitiveKeyKind::LineDecoration { ref color, .. } => { + PrimitiveKeyKind::Rectangle { ref color, .. } => { color.a > 0 } } @@ -1426,12 +1369,6 @@ impl CreateShadow for PrimitiveKeyKind { shadow: &Shadow, ) -> PrimitiveKeyKind { match *self { - PrimitiveKeyKind::LineDecoration { ref cache_key, .. } => { - PrimitiveKeyKind::LineDecoration { - color: shadow.color.into(), - cache_key: cache_key.clone(), - } - } PrimitiveKeyKind::Rectangle { .. } => { PrimitiveKeyKind::Rectangle { color: shadow.color.into(), @@ -1469,7 +1406,7 @@ pub enum PrimitiveInstanceKind { /// task handle, if this line decoration is not a simple solid. LineDecoration { /// Handle to the common interned data for this primitive. - data_handle: PrimitiveDataHandle, + data_handle: LineDecorationDataHandle, // TODO(gw): For now, we need to store some information in // the primitive instance that is created during // prepare_prims and read during the batching pass. @@ -1606,7 +1543,6 @@ impl PrimitiveInstance { pub fn uid(&self) -> intern::ItemUid { match &self.kind { PrimitiveInstanceKind::Picture { data_handle, .. } | - PrimitiveInstanceKind::LineDecoration { data_handle, .. } | PrimitiveInstanceKind::Clear { data_handle, .. } | PrimitiveInstanceKind::Rectangle { data_handle, .. } => { data_handle.uid() @@ -1617,6 +1553,9 @@ impl PrimitiveInstance { PrimitiveInstanceKind::ImageBorder { data_handle, .. } => { data_handle.uid() } + PrimitiveInstanceKind::LineDecoration { data_handle, .. } => { + data_handle.uid() + } PrimitiveInstanceKind::LinearGradient { data_handle, .. } => { data_handle.uid() } @@ -2450,58 +2389,55 @@ impl PrimitiveStore { match &mut prim_instance.kind { PrimitiveInstanceKind::LineDecoration { data_handle, ref mut cache_handle, .. } => { - let prim_data = &mut resources.prim_data_store[*data_handle]; + let prim_data = &mut resources.line_decoration_data_store[*data_handle]; + let common_data = &mut prim_data.common; + let line_dec_data = &mut prim_data.kind; // Update the template this instane references, which may refresh the GPU // cache with any shared template data. - prim_data.update(frame_state); + line_dec_data.update(common_data, frame_state); - match &prim_data.kind { - PrimitiveTemplateKind::LineDecoration { ref cache_key, .. } => { - // Work out the device pixel size to be used to cache this line decoration. - if is_chased { - println!("\tline decoration key={:?}", cache_key); - } + // Work out the device pixel size to be used to cache this line decoration. + if is_chased { + println!("\tline decoration key={:?}", line_dec_data.cache_key); + } - // If we have a cache key, it's a wavy / dashed / dotted line. Otherwise, it's - // a simple solid line. - if let Some(cache_key) = cache_key { - // TODO(gw): Do we ever need / want to support scales for text decorations - // based on the current transform? - let scale_factor = TypedScale::new(1.0) * frame_context.device_pixel_scale; - let task_size = (LayoutSize::from_au(cache_key.size) * scale_factor).ceil().to_i32(); - let surfaces = &mut frame_state.surfaces; - - // Request a pre-rendered image task. - // TODO(gw): This match is a bit untidy, but it should disappear completely - // once the prepare_prims and batching are unified. When that - // happens, we can use the cache handle immediately, and not need - // to temporarily store it in the primitive instance. - *cache_handle = Some(frame_state.resource_cache.request_render_task( - RenderTaskCacheKey { - size: task_size, - kind: RenderTaskCacheKeyKind::LineDecoration(cache_key.clone()), - }, - frame_state.gpu_cache, - frame_state.render_tasks, - None, - false, - |render_tasks| { - let task = RenderTask::new_line_decoration( - task_size, - cache_key.style, - cache_key.orientation, - cache_key.wavy_line_thickness.to_f32_px(), - LayoutSize::from_au(cache_key.size), - ); - let task_id = render_tasks.add(task); - surfaces[pic_context.surface_index.0].tasks.push(task_id); - task_id - } - )); + // If we have a cache key, it's a wavy / dashed / dotted line. Otherwise, it's + // a simple solid line. + if let Some(cache_key) = line_dec_data.cache_key.as_ref() { + // TODO(gw): Do we ever need / want to support scales for text decorations + // based on the current transform? + let scale_factor = TypedScale::new(1.0) * frame_context.device_pixel_scale; + let task_size = (LayoutSize::from_au(cache_key.size) * scale_factor).ceil().to_i32(); + let surfaces = &mut frame_state.surfaces; + + // Request a pre-rendered image task. + // TODO(gw): This match is a bit untidy, but it should disappear completely + // once the prepare_prims and batching are unified. When that + // happens, we can use the cache handle immediately, and not need + // to temporarily store it in the primitive instance. + *cache_handle = Some(frame_state.resource_cache.request_render_task( + RenderTaskCacheKey { + size: task_size, + kind: RenderTaskCacheKeyKind::LineDecoration(cache_key.clone()), + }, + frame_state.gpu_cache, + frame_state.render_tasks, + None, + false, + |render_tasks| { + let task = RenderTask::new_line_decoration( + task_size, + cache_key.style, + cache_key.orientation, + cache_key.wavy_line_thickness.to_f32_px(), + LayoutSize::from_au(cache_key.size), + ); + let task_id = render_tasks.add(task); + surfaces[pic_context.surface_index.0].tasks.push(task_id); + task_id } - }, - _ => unreachable!(), + )); } } PrimitiveInstanceKind::TextRun { data_handle, run_index, .. } => { @@ -3528,8 +3464,8 @@ fn test_struct_sizes() { // be done with care, and after checking if talos performance regresses badly. assert_eq!(mem::size_of::(), 120, "PrimitiveInstance size changed"); assert_eq!(mem::size_of::(), 40, "PrimitiveInstanceKind size changed"); - assert_eq!(mem::size_of::(), 96, "PrimitiveTemplate size changed"); - assert_eq!(mem::size_of::(), 36, "PrimitiveTemplateKind size changed"); + assert_eq!(mem::size_of::(), 80, "PrimitiveTemplate size changed"); + assert_eq!(mem::size_of::(), 20, "PrimitiveTemplateKind size changed"); assert_eq!(mem::size_of::(), 116, "PrimitiveKey size changed"); assert_eq!(mem::size_of::(), 88, "PrimitiveKeyKind size changed"); } diff --git a/webrender/src/profiler.rs b/webrender/src/profiler.rs index b0c78a7bc0..cd134a5274 100644 --- a/webrender/src/profiler.rs +++ b/webrender/src/profiler.rs @@ -406,6 +406,7 @@ pub struct InternProfileCounters { pub prims: ResourceProfileCounter, pub images: ResourceProfileCounter, pub image_borders: ResourceProfileCounter, + pub line_decs: ResourceProfileCounter, pub linear_gradients: ResourceProfileCounter, pub normal_borders: ResourceProfileCounter, pub radial_gradients: ResourceProfileCounter, @@ -456,6 +457,7 @@ impl BackendProfileCounters { prims: ResourceProfileCounter::new("Interned primitives"), images: ResourceProfileCounter::new("Interned images"), image_borders: ResourceProfileCounter::new("Interned image borders"), + line_decs: ResourceProfileCounter::new("Interned line decorations"), linear_gradients: ResourceProfileCounter::new("Interned linear gradients"), normal_borders: ResourceProfileCounter::new("Interner normal borders"), radial_gradients: ResourceProfileCounter::new("Interned radial gradients"), @@ -1113,6 +1115,7 @@ impl Profiler { &backend_profile.intern.prims, &backend_profile.intern.images, &backend_profile.intern.image_borders, + &backend_profile.intern.line_decs, &backend_profile.intern.linear_gradients, &backend_profile.intern.normal_borders, &backend_profile.intern.radial_gradients, diff --git a/webrender/src/render_backend.rs b/webrender/src/render_backend.rs index 9337baa349..ba3f730fe8 100644 --- a/webrender/src/render_backend.rs +++ b/webrender/src/render_backend.rs @@ -36,6 +36,7 @@ use prim_store::{PrimitiveInstanceKind, PrimTemplateCommonData}; use prim_store::borders::{ImageBorderDataStore, NormalBorderDataStore}; use prim_store::gradient::{LinearGradientDataStore, RadialGradientDataStore}; use prim_store::image::{ImageDataStore, YuvImageDataStore}; +use prim_store::line_dec::LineDecorationDataStore; use prim_store::text_run::TextRunDataStore; use profiler::{BackendProfileCounters, IpcProfileCounters, ResourceProfileCounters}; use record::ApiRecordingReceiver; @@ -209,6 +210,7 @@ pub struct FrameResources { pub prim_data_store: PrimitiveDataStore, pub image_data_store: ImageDataStore, pub image_border_data_store: ImageBorderDataStore, + pub line_decoration_data_store: LineDecorationDataStore, pub linear_grad_data_store: LinearGradientDataStore, pub normal_border_data_store: NormalBorderDataStore, pub radial_grad_data_store: RadialGradientDataStore, @@ -223,7 +225,6 @@ impl FrameResources { ) -> &PrimTemplateCommonData { match prim_inst.kind { PrimitiveInstanceKind::Picture { data_handle, .. } | - PrimitiveInstanceKind::LineDecoration { data_handle, .. } | PrimitiveInstanceKind::Rectangle { data_handle, .. } | PrimitiveInstanceKind::Clear { data_handle, .. } => { let prim_data = &self.prim_data_store[data_handle]; @@ -237,6 +238,10 @@ impl FrameResources { let prim_data = &self.image_border_data_store[data_handle]; &prim_data.common } + PrimitiveInstanceKind::LineDecoration { data_handle, .. } => { + let prim_data = &self.line_decoration_data_store[data_handle]; + &prim_data.common + } PrimitiveInstanceKind::LinearGradient { data_handle, .. } => { let prim_data = &self.linear_grad_data_store[data_handle]; &prim_data.common @@ -1247,6 +1252,10 @@ impl RenderBackend { updates.image_border_updates, &mut profile_counters.intern.image_borders, ); + doc.resources.line_decoration_data_store.apply_updates( + updates.line_decoration_updates, + &mut profile_counters.intern.line_decs, + ); doc.resources.linear_grad_data_store.apply_updates( updates.linear_grad_updates, &mut profile_counters.intern.linear_gradients, diff --git a/webrender/src/render_task.rs b/webrender/src/render_task.rs index 167eac94d8..e0037d4d95 100644 --- a/webrender/src/render_task.rs +++ b/webrender/src/render_task.rs @@ -21,8 +21,9 @@ use gpu_types::{BorderInstance, ImageSource, UvRectKind}; use internal_types::{CacheTextureId, FastHashMap, LayerIndex, SavedTargetIndex}; #[cfg(feature = "pathfinder")] use pathfinder_partitioner::mesh::Mesh; -use prim_store::{PictureIndex, LineDecorationCacheKey}; +use prim_store::PictureIndex; use prim_store::image::ImageCacheKey; +use prim_store::line_dec::LineDecorationCacheKey; #[cfg(feature = "debugger")] use print_tree::{PrintTreePrinter}; use render_backend::FrameId; diff --git a/webrender/src/scene_builder.rs b/webrender/src/scene_builder.rs index 530b4a3c3f..7e0efb7f30 100644 --- a/webrender/src/scene_builder.rs +++ b/webrender/src/scene_builder.rs @@ -28,6 +28,9 @@ use prim_store::image::{ Image, ImageDataInterner, ImageDataUpdateList, YuvImage, YuvImageDataInterner, YuvImageDataUpdateList, }; +use prim_store::line_dec::{ + LineDecoration, LineDecorationDataInterner, LineDecorationDataUpdateList +}; use prim_store::text_run::{TextRunDataInterner, TextRun, TextRunDataUpdateList}; use resource_cache::{BlobImageRasterizerEpoch, FontInstanceMap}; use render_backend::DocumentView; @@ -45,6 +48,7 @@ pub struct DocumentResourceUpdates { pub prim_updates: PrimitiveDataUpdateList, pub image_updates: ImageDataUpdateList, pub image_border_updates: ImageBorderDataUpdateList, + pub line_decoration_updates: LineDecorationDataUpdateList, pub linear_grad_updates: LinearGradientDataUpdateList, pub normal_border_updates: NormalBorderDataUpdateList, pub radial_grad_updates: RadialGradientDataUpdateList, @@ -199,6 +203,7 @@ pub struct DocumentResources { pub prim_interner: PrimitiveDataInterner, pub image_interner: ImageDataInterner, pub image_border_interner: ImageBorderDataInterner, + pub line_decoration_interner: LineDecorationDataInterner, pub linear_grad_interner: LinearGradientDataInterner, pub normal_border_interner: NormalBorderDataInterner, pub radial_grad_interner: RadialGradientDataInterner, @@ -229,6 +234,7 @@ macro_rules! impl_internet_mut { impl_internet_mut! { Image: image_interner, ImageBorder: image_border_interner, + LineDecoration: line_decoration_interner, LinearGradient: linear_grad_interner, NormalBorderPrim: normal_border_interner, PrimitiveKeyKind: prim_interner, @@ -417,6 +423,11 @@ impl SceneBuilder { .image_border_interner .end_frame_and_get_pending_updates(); + let line_decoration_updates = item + .doc_resources + .line_decoration_interner + .end_frame_and_get_pending_updates(); + let linear_grad_updates = item .doc_resources .linear_grad_interner @@ -448,6 +459,7 @@ impl SceneBuilder { prim_updates, image_updates, image_border_updates, + line_decoration_updates, linear_grad_updates, normal_border_updates, radial_grad_updates, @@ -571,6 +583,11 @@ impl SceneBuilder { .image_border_interner .end_frame_and_get_pending_updates(); + let line_decoration_updates = doc + .resources + .line_decoration_interner + .end_frame_and_get_pending_updates(); + let linear_grad_updates = doc .resources .linear_grad_interner @@ -602,6 +619,7 @@ impl SceneBuilder { prim_updates, image_updates, image_border_updates, + line_decoration_updates, linear_grad_updates, normal_border_updates, radial_grad_updates, From f8f62d12adb38a770e4dbe9f3542d44966df2f77 Mon Sep 17 00:00:00 2001 From: Dan Glastonbury Date: Wed, 19 Dec 2018 07:49:05 +1000 Subject: [PATCH 2/2] Extract Picture --- webrender/src/display_list_flattener.rs | 41 ++-- webrender/src/picture.rs | 4 +- webrender/src/prim_store/mod.rs | 151 ++------------- webrender/src/prim_store/picture.rs | 239 ++++++++++++++++++++++++ webrender/src/profiler.rs | 5 +- webrender/src/render_backend.rs | 13 +- webrender/src/scene_builder.rs | 16 ++ 7 files changed, 303 insertions(+), 166 deletions(-) create mode 100644 webrender/src/prim_store/picture.rs diff --git a/webrender/src/display_list_flattener.rs b/webrender/src/display_list_flattener.rs index fc54302aa3..a77f4d29f3 100644 --- a/webrender/src/display_list_flattener.rs +++ b/webrender/src/display_list_flattener.rs @@ -22,14 +22,15 @@ use image::simplify_repeated_primitive; use intern::{Handle, Internable, InternDebug}; use internal_types::{FastHashMap, FastHashSet}; use picture::{Picture3DContext, PictureCompositeMode, PicturePrimitive, PrimitiveList}; -use prim_store::{PrimitiveInstance, PrimitiveKeyKind, PictureCompositeKey}; -use prim_store::{PrimitiveKey, PrimitiveSceneData, PrimitiveInstanceKind, NinePatchDescriptor}; -use prim_store::{PrimitiveStore, PrimitiveStoreStats}; -use prim_store::{ScrollNodeAndClipChain, PictureIndex, register_prim_chase_id, get_line_decoration_sizes}; +use prim_store::{PrimitiveInstance, PrimitiveKeyKind, PrimitiveSceneData}; +use prim_store::{PrimitiveInstanceKind, NinePatchDescriptor, PrimitiveStore}; +use prim_store::{PrimitiveStoreStats, ScrollNodeAndClipChain, PictureIndex}; +use prim_store::{register_prim_chase_id, get_line_decoration_sizes}; use prim_store::borders::{ImageBorder, NormalBorderPrim}; use prim_store::gradient::{GradientStopKey, LinearGradient, RadialGradient, RadialGradientParams}; use prim_store::image::{Image, YuvImage}; use prim_store::line_dec::{LineDecoration, LineDecorationCacheKey}; +use prim_store::picture::{Picture, PictureCompositeKey, PictureKey}; use prim_store::text_run::TextRun; use render_backend::{DocumentView}; use resource_cache::{FontInstanceMap, ImageRequest}; @@ -329,18 +330,18 @@ impl<'a> DisplayListFlattener<'a> { // Now, create a picture with tile caching enabled that will hold all // of the primitives selected as belonging to the main scroll root. - let prim_key = PrimitiveKey::new( + let pic_key = PictureKey::new( true, LayoutSize::zero(), LayoutRect::max_rect(), - PrimitiveKeyKind::Picture { + Picture { composite_mode_key: PictureCompositeKey::Identity, }, ); - let primitive_data_handle = self.resources - .prim_interner - .intern(&prim_key, || { + let pic_data_handle = self.resources + .picture_interner + .intern(&pic_key, || { PrimitiveSceneData { prim_relative_clip_rect: LayoutRect::max_rect(), prim_size: LayoutSize::zero(), @@ -365,7 +366,7 @@ impl<'a> DisplayListFlattener<'a> { let instance = PrimitiveInstance::new( LayoutPoint::zero(), PrimitiveInstanceKind::Picture { - data_handle: primitive_data_handle, + data_handle: pic_data_handle, pic_index: PictureIndex(pic_index) }, ClipChainId::NONE, @@ -1873,18 +1874,16 @@ impl<'a> DisplayListFlattener<'a> { )) ); - let shadow_prim_key = PrimitiveKey::new( + let shadow_pic_key = PictureKey::new( true, LayoutSize::zero(), LayoutRect::max_rect(), - PrimitiveKeyKind::Picture { - composite_mode_key, - }, + Picture { composite_mode_key }, ); let shadow_prim_data_handle = self.resources - .prim_interner - .intern(&shadow_prim_key, || { + .picture_interner + .intern(&shadow_pic_key, || { PrimitiveSceneData { prim_relative_clip_rect: LayoutRect::max_rect(), prim_size: LayoutSize::zero(), @@ -2734,18 +2733,16 @@ fn create_prim_instance( spatial_node_index: SpatialNodeIndex, resources: &mut DocumentResources, ) -> PrimitiveInstance { - let prim_key = PrimitiveKey::new( + let pic_key = PictureKey::new( is_backface_visible, LayoutSize::zero(), LayoutRect::max_rect(), - PrimitiveKeyKind::Picture { - composite_mode_key, - }, + Picture { composite_mode_key }, ); let data_handle = resources - .prim_interner - .intern(&prim_key, || { + .picture_interner + .intern(&pic_key, || { PrimitiveSceneData { prim_relative_clip_rect: LayoutRect::max_rect(), prim_size: LayoutSize::zero(), diff --git a/webrender/src/picture.rs b/webrender/src/picture.rs index 73285596f0..47126de9e5 100644 --- a/webrender/src/picture.rs +++ b/webrender/src/picture.rs @@ -1392,7 +1392,6 @@ impl PrimitiveList { }; let prim_data = match prim_instance.kind { - PrimitiveInstanceKind::Picture { data_handle, .. } | PrimitiveInstanceKind::Rectangle { data_handle, .. } | PrimitiveInstanceKind::Clear { data_handle, .. } => { &resources.prim_interner[data_handle] @@ -1412,6 +1411,9 @@ impl PrimitiveList { PrimitiveInstanceKind::NormalBorder { data_handle, .. } => { &resources.normal_border_interner[data_handle] } + PrimitiveInstanceKind::Picture { data_handle, .. } => { + &resources.picture_interner[data_handle] + } PrimitiveInstanceKind::RadialGradient { data_handle, ..} => { &resources.radial_grad_interner[data_handle] } diff --git a/webrender/src/prim_store/mod.rs b/webrender/src/prim_store/mod.rs index cf33fa8f60..10d8297e84 100644 --- a/webrender/src/prim_store/mod.rs +++ b/webrender/src/prim_store/mod.rs @@ -4,13 +4,12 @@ use api::{BorderRadius, ClipMode, ColorF, PictureRect, ColorU, LayoutVector2D}; use api::{DeviceIntRect, DevicePixelScale, DeviceRect}; -use api::{FilterOp, ImageRendering, TileOffset, RepeatMode, MixBlendMode}; -use api::{LayoutPoint, LayoutRect, LayoutSideOffsets, LayoutSize, PropertyBindingId}; +use api::{FilterOp, ImageRendering, TileOffset, RepeatMode}; +use api::{LayoutPoint, LayoutRect, LayoutSideOffsets, LayoutSize}; use api::{PremultipliedColorF, PropertyBinding, Shadow}; use api::{WorldPixel, BoxShadowClipMode, WorldRect, LayoutToWorldScale}; use api::{PicturePixel, RasterPixel, LineStyle, LineOrientation, AuHelpers}; use api::LayoutPrimitiveInfo; -use app_units::Au; use border::{get_max_scale_for_border, build_border_instances}; use border::BorderSegmentCacheKey; use clip::{ClipStore}; @@ -31,6 +30,7 @@ use prim_store::borders::{ImageBorderDataHandle, NormalBorderDataHandle}; use prim_store::gradient::{LinearGradientDataHandle, RadialGradientDataHandle}; use prim_store::image::{ImageDataHandle, ImageInstance, VisibleImageTile, YuvImageDataHandle}; use prim_store::line_dec::LineDecorationDataHandle; +use prim_store::picture::PictureDataHandle; use prim_store::text_run::{TextRunDataHandle, TextRunPrimitive}; #[cfg(debug_assertions)] use render_backend::{FrameId}; @@ -53,6 +53,7 @@ pub mod borders; pub mod gradient; pub mod image; pub mod line_dec; +pub mod picture; pub mod text_run; /// Counter for unique primitive IDs for debug tracing. @@ -348,116 +349,6 @@ pub struct PrimitiveSceneData { pub is_backface_visible: bool, } -/// Represents a hashable description of how a picture primitive -/// will be composited into its parent. -#[cfg_attr(feature = "capture", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] -#[derive(Debug, Clone, PartialEq, Hash, Eq)] -pub enum PictureCompositeKey { - // No visual compositing effect - Identity, - - // FilterOp - Blur(Au), - Brightness(Au), - Contrast(Au), - Grayscale(Au), - HueRotate(Au), - Invert(Au), - Opacity(Au), - OpacityBinding(PropertyBindingId, Au), - Saturate(Au), - Sepia(Au), - DropShadow(VectorKey, Au, ColorU), - ColorMatrix([Au; 20]), - SrgbToLinear, - LinearToSrgb, - - // MixBlendMode - Multiply, - Screen, - Overlay, - Darken, - Lighten, - ColorDodge, - ColorBurn, - HardLight, - SoftLight, - Difference, - Exclusion, - Hue, - Saturation, - Color, - Luminosity, -} - -impl From> for PictureCompositeKey { - fn from(mode: Option) -> Self { - match mode { - Some(PictureCompositeMode::MixBlend(mode)) => { - match mode { - MixBlendMode::Normal => PictureCompositeKey::Identity, - MixBlendMode::Multiply => PictureCompositeKey::Multiply, - MixBlendMode::Screen => PictureCompositeKey::Screen, - MixBlendMode::Overlay => PictureCompositeKey::Overlay, - MixBlendMode::Darken => PictureCompositeKey::Darken, - MixBlendMode::Lighten => PictureCompositeKey::Lighten, - MixBlendMode::ColorDodge => PictureCompositeKey::ColorDodge, - MixBlendMode::ColorBurn => PictureCompositeKey::ColorBurn, - MixBlendMode::HardLight => PictureCompositeKey::HardLight, - MixBlendMode::SoftLight => PictureCompositeKey::SoftLight, - MixBlendMode::Difference => PictureCompositeKey::Difference, - MixBlendMode::Exclusion => PictureCompositeKey::Exclusion, - MixBlendMode::Hue => PictureCompositeKey::Hue, - MixBlendMode::Saturation => PictureCompositeKey::Saturation, - MixBlendMode::Color => PictureCompositeKey::Color, - MixBlendMode::Luminosity => PictureCompositeKey::Luminosity, - } - } - Some(PictureCompositeMode::Filter(op)) => { - match op { - FilterOp::Blur(value) => PictureCompositeKey::Blur(Au::from_f32_px(value)), - FilterOp::Brightness(value) => PictureCompositeKey::Brightness(Au::from_f32_px(value)), - FilterOp::Contrast(value) => PictureCompositeKey::Contrast(Au::from_f32_px(value)), - FilterOp::Grayscale(value) => PictureCompositeKey::Grayscale(Au::from_f32_px(value)), - FilterOp::HueRotate(value) => PictureCompositeKey::HueRotate(Au::from_f32_px(value)), - FilterOp::Invert(value) => PictureCompositeKey::Invert(Au::from_f32_px(value)), - FilterOp::Saturate(value) => PictureCompositeKey::Saturate(Au::from_f32_px(value)), - FilterOp::Sepia(value) => PictureCompositeKey::Sepia(Au::from_f32_px(value)), - FilterOp::SrgbToLinear => PictureCompositeKey::SrgbToLinear, - FilterOp::LinearToSrgb => PictureCompositeKey::LinearToSrgb, - FilterOp::Identity => PictureCompositeKey::Identity, - FilterOp::DropShadow(offset, radius, color) => { - PictureCompositeKey::DropShadow(offset.into(), Au::from_f32_px(radius), color.into()) - } - FilterOp::Opacity(binding, _) => { - match binding { - PropertyBinding::Value(value) => { - PictureCompositeKey::Opacity(Au::from_f32_px(value)) - } - PropertyBinding::Binding(key, default) => { - PictureCompositeKey::OpacityBinding(key.id, Au::from_f32_px(default)) - } - } - } - FilterOp::ColorMatrix(values) => { - let mut quantized_values: [Au; 20] = [Au(0); 20]; - for (value, result) in values.iter().zip(quantized_values.iter_mut()) { - *result = Au::from_f32_px(*value); - } - PictureCompositeKey::ColorMatrix(quantized_values) - } - } - } - Some(PictureCompositeMode::Blit) | - Some(PictureCompositeMode::TileCache { .. }) | - None => { - PictureCompositeKey::Identity - } - } - } -} - /// Information specific to a primitive type that /// uniquely identifies a primitive template by key. #[cfg_attr(feature = "capture", derive(Serialize))] @@ -469,9 +360,6 @@ pub enum PrimitiveKeyKind { Rectangle { color: ColorU, }, - Picture { - composite_mode_key: PictureCompositeKey, - }, } #[cfg_attr(feature = "capture", derive(Serialize))] @@ -757,11 +645,6 @@ impl AsInstanceKind for PrimitiveKey { segment_instance_index: SegmentInstanceIndex::INVALID, } } - PrimitiveKeyKind::Picture { .. } => { - // Should never be hit as this method should not be - // called for pictures. - unreachable!(); - } } } } @@ -775,9 +658,6 @@ pub enum PrimitiveTemplateKind { color: ColorF, }, Clear, - Picture { - - }, } /// Construct the primitive template data from a primitive key. This @@ -786,11 +666,6 @@ pub enum PrimitiveTemplateKind { impl PrimitiveKeyKind { fn into_template(self) -> PrimitiveTemplateKind { match self { - PrimitiveKeyKind::Picture { .. } => { - PrimitiveTemplateKind::Picture { - - } - } PrimitiveKeyKind::Clear => { PrimitiveTemplateKind::Clear } @@ -879,7 +754,6 @@ impl PrimitiveTemplateKind { PrimitiveTemplateKind::Rectangle { ref color, .. } => { request.push(color.premultiplied()); } - PrimitiveTemplateKind::Picture { .. } => {} } } } @@ -904,9 +778,6 @@ impl PrimitiveTemplate { PrimitiveTemplateKind::Rectangle { ref color, .. } => { PrimitiveOpacity::from_alpha(color.a) } - PrimitiveTemplateKind::Picture { .. } => { - PrimitiveOpacity::translucent() - } }; } } @@ -1349,8 +1220,7 @@ impl IsVisible for PrimitiveKeyKind { // primitive types to use this. fn is_visible(&self) -> bool { match *self { - PrimitiveKeyKind::Clear | - PrimitiveKeyKind::Picture { .. } => { + PrimitiveKeyKind::Clear => { true } PrimitiveKeyKind::Rectangle { ref color, .. } => { @@ -1374,7 +1244,6 @@ impl CreateShadow for PrimitiveKeyKind { color: shadow.color.into(), } } - PrimitiveKeyKind::Picture { .. } | PrimitiveKeyKind::Clear => { panic!("bug: this prim is not supported in shadow contexts"); } @@ -1392,7 +1261,7 @@ pub enum PrimitiveInstanceKind { /// Direct reference to a Picture Picture { /// Handle to the common interned data for this primitive. - data_handle: PrimitiveDataHandle, + data_handle: PictureDataHandle, pic_index: PictureIndex, }, /// A run of glyphs, with associated font parameters. @@ -1542,7 +1411,6 @@ impl PrimitiveInstance { pub fn uid(&self) -> intern::ItemUid { match &self.kind { - PrimitiveInstanceKind::Picture { data_handle, .. } | PrimitiveInstanceKind::Clear { data_handle, .. } | PrimitiveInstanceKind::Rectangle { data_handle, .. } => { data_handle.uid() @@ -1562,6 +1430,9 @@ impl PrimitiveInstance { PrimitiveInstanceKind::NormalBorder { data_handle, .. } => { data_handle.uid() } + PrimitiveInstanceKind::Picture { data_handle, .. } => { + data_handle.uid() + } PrimitiveInstanceKind::RadialGradient { data_handle, .. } => { data_handle.uid() } @@ -3466,6 +3337,6 @@ fn test_struct_sizes() { assert_eq!(mem::size_of::(), 40, "PrimitiveInstanceKind size changed"); assert_eq!(mem::size_of::(), 80, "PrimitiveTemplate size changed"); assert_eq!(mem::size_of::(), 20, "PrimitiveTemplateKind size changed"); - assert_eq!(mem::size_of::(), 116, "PrimitiveKey size changed"); - assert_eq!(mem::size_of::(), 88, "PrimitiveKeyKind size changed"); + assert_eq!(mem::size_of::(), 36, "PrimitiveKey size changed"); + assert_eq!(mem::size_of::(), 5, "PrimitiveKeyKind size changed"); } diff --git a/webrender/src/prim_store/picture.rs b/webrender/src/prim_store/picture.rs new file mode 100644 index 0000000000..5b3e61810a --- /dev/null +++ b/webrender/src/prim_store/picture.rs @@ -0,0 +1,239 @@ +/* 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::{ + ColorU, FilterOp, LayoutRect, LayoutSize, LayoutPrimitiveInfo, MixBlendMode, + PropertyBinding, PropertyBindingId, +}; +use app_units::Au; +use display_list_flattener::{AsInstanceKind, IsVisible}; +use intern::{DataStore, Handle, Internable, Interner, InternDebug, UpdateList}; +use picture::PictureCompositeMode; +use prim_store::{ + PrimKey, PrimKeyCommonData, PrimTemplate, PrimTemplateCommonData, + PrimitiveInstanceKind, PrimitiveSceneData, PrimitiveStore, VectorKey, +}; + +/// Represents a hashable description of how a picture primitive +/// will be composited into its parent. +#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(feature = "replay", derive(Deserialize))] +#[derive(Debug, Clone, PartialEq, Hash, Eq)] +pub enum PictureCompositeKey { + // No visual compositing effect + Identity, + + // FilterOp + Blur(Au), + Brightness(Au), + Contrast(Au), + Grayscale(Au), + HueRotate(Au), + Invert(Au), + Opacity(Au), + OpacityBinding(PropertyBindingId, Au), + Saturate(Au), + Sepia(Au), + DropShadow(VectorKey, Au, ColorU), + ColorMatrix([Au; 20]), + SrgbToLinear, + LinearToSrgb, + + // MixBlendMode + Multiply, + Screen, + Overlay, + Darken, + Lighten, + ColorDodge, + ColorBurn, + HardLight, + SoftLight, + Difference, + Exclusion, + Hue, + Saturation, + Color, + Luminosity, +} + +impl From> for PictureCompositeKey { + fn from(mode: Option) -> Self { + match mode { + Some(PictureCompositeMode::MixBlend(mode)) => { + match mode { + MixBlendMode::Normal => PictureCompositeKey::Identity, + MixBlendMode::Multiply => PictureCompositeKey::Multiply, + MixBlendMode::Screen => PictureCompositeKey::Screen, + MixBlendMode::Overlay => PictureCompositeKey::Overlay, + MixBlendMode::Darken => PictureCompositeKey::Darken, + MixBlendMode::Lighten => PictureCompositeKey::Lighten, + MixBlendMode::ColorDodge => PictureCompositeKey::ColorDodge, + MixBlendMode::ColorBurn => PictureCompositeKey::ColorBurn, + MixBlendMode::HardLight => PictureCompositeKey::HardLight, + MixBlendMode::SoftLight => PictureCompositeKey::SoftLight, + MixBlendMode::Difference => PictureCompositeKey::Difference, + MixBlendMode::Exclusion => PictureCompositeKey::Exclusion, + MixBlendMode::Hue => PictureCompositeKey::Hue, + MixBlendMode::Saturation => PictureCompositeKey::Saturation, + MixBlendMode::Color => PictureCompositeKey::Color, + MixBlendMode::Luminosity => PictureCompositeKey::Luminosity, + } + } + Some(PictureCompositeMode::Filter(op)) => { + match op { + FilterOp::Blur(value) => PictureCompositeKey::Blur(Au::from_f32_px(value)), + FilterOp::Brightness(value) => PictureCompositeKey::Brightness(Au::from_f32_px(value)), + FilterOp::Contrast(value) => PictureCompositeKey::Contrast(Au::from_f32_px(value)), + FilterOp::Grayscale(value) => PictureCompositeKey::Grayscale(Au::from_f32_px(value)), + FilterOp::HueRotate(value) => PictureCompositeKey::HueRotate(Au::from_f32_px(value)), + FilterOp::Invert(value) => PictureCompositeKey::Invert(Au::from_f32_px(value)), + FilterOp::Saturate(value) => PictureCompositeKey::Saturate(Au::from_f32_px(value)), + FilterOp::Sepia(value) => PictureCompositeKey::Sepia(Au::from_f32_px(value)), + FilterOp::SrgbToLinear => PictureCompositeKey::SrgbToLinear, + FilterOp::LinearToSrgb => PictureCompositeKey::LinearToSrgb, + FilterOp::Identity => PictureCompositeKey::Identity, + FilterOp::DropShadow(offset, radius, color) => { + PictureCompositeKey::DropShadow(offset.into(), Au::from_f32_px(radius), color.into()) + } + FilterOp::Opacity(binding, _) => { + match binding { + PropertyBinding::Value(value) => { + PictureCompositeKey::Opacity(Au::from_f32_px(value)) + } + PropertyBinding::Binding(key, default) => { + PictureCompositeKey::OpacityBinding(key.id, Au::from_f32_px(default)) + } + } + } + FilterOp::ColorMatrix(values) => { + let mut quantized_values: [Au; 20] = [Au(0); 20]; + for (value, result) in values.iter().zip(quantized_values.iter_mut()) { + *result = Au::from_f32_px(*value); + } + PictureCompositeKey::ColorMatrix(quantized_values) + } + } + } + Some(PictureCompositeMode::Blit) | + Some(PictureCompositeMode::TileCache { .. }) | + None => { + PictureCompositeKey::Identity + } + } + } +} + +#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(feature = "replay", derive(Deserialize))] +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +pub struct Picture { + pub composite_mode_key: PictureCompositeKey, +} + +pub type PictureKey = PrimKey; + +impl PictureKey { + pub fn new( + is_backface_visible: bool, + prim_size: LayoutSize, + prim_relative_clip_rect: LayoutRect, + pic: Picture, + ) -> Self { + + PictureKey { + common: PrimKeyCommonData { + is_backface_visible, + prim_size: prim_size.into(), + prim_relative_clip_rect: prim_relative_clip_rect.into(), + }, + kind: pic, + } + } +} + +impl InternDebug for PictureKey {} + +impl AsInstanceKind for PictureKey { + /// Construct a primitive instance that matches the type + /// of primitive key. + fn as_instance_kind( + &self, + _: PictureDataHandle, + _: &mut PrimitiveStore, + ) -> PrimitiveInstanceKind { + // Should never be hit as this method should not be + // called for pictures. + unreachable!(); + } +} + +#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(feature = "replay", derive(Deserialize))] +pub struct PictureData; + +pub type PictureTemplate = PrimTemplate; + +impl From for PictureTemplate { + fn from(key: PictureKey) -> Self { + let common = PrimTemplateCommonData::with_key_common(key.common); + + PictureTemplate { + common, + kind: PictureData, + } + } +} + +#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(feature = "replay", derive(Deserialize))] +#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)] +pub struct PictureDataMarker; + +pub type PictureDataStore = DataStore; +pub type PictureDataHandle = Handle; +pub type PictureDataUpdateList = UpdateList; +pub type PictureDataInterner = Interner; + +impl Internable for Picture { + type Marker = PictureDataMarker; + type Source = PictureKey; + type StoreData = PictureTemplate; + type InternData = PrimitiveSceneData; + + /// Build a new key from self with `info`. + fn build_key( + self, + info: &LayoutPrimitiveInfo, + prim_relative_clip_rect: LayoutRect, + ) -> PictureKey { + PictureKey::new( + info.is_backface_visible, + info.rect.size, + prim_relative_clip_rect, + self + ) + } +} + +impl IsVisible for Picture { + fn is_visible(&self) -> bool { + true + } +} + +#[test] +#[cfg(target_os = "linux")] +fn test_struct_sizes() { + use std::mem; + // The sizes of these structures are critical for performance on a number of + // talos stress tests. If you get a failure here on CI, there's two possibilities: + // (a) You made a structure smaller than it currently is. Great work! Update the + // 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::(), 84, "Picture size changed"); + assert_eq!(mem::size_of::(), 56, "PictureTemplate size changed"); + assert_eq!(mem::size_of::(), 112, "PictureKey size changed"); +} diff --git a/webrender/src/profiler.rs b/webrender/src/profiler.rs index cd134a5274..69aa974182 100644 --- a/webrender/src/profiler.rs +++ b/webrender/src/profiler.rs @@ -409,6 +409,7 @@ pub struct InternProfileCounters { pub line_decs: ResourceProfileCounter, pub linear_gradients: ResourceProfileCounter, pub normal_borders: ResourceProfileCounter, + pub pictures: ResourceProfileCounter, pub radial_gradients: ResourceProfileCounter, pub text_runs: ResourceProfileCounter, pub yuv_images: ResourceProfileCounter, @@ -459,7 +460,8 @@ impl BackendProfileCounters { image_borders: ResourceProfileCounter::new("Interned image borders"), line_decs: ResourceProfileCounter::new("Interned line decorations"), linear_gradients: ResourceProfileCounter::new("Interned linear gradients"), - normal_borders: ResourceProfileCounter::new("Interner normal borders"), + normal_borders: ResourceProfileCounter::new("Interned normal borders"), + pictures: ResourceProfileCounter::new("Interned pictures"), radial_gradients: ResourceProfileCounter::new("Interned radial gradients"), text_runs: ResourceProfileCounter::new("Interned text runs"), yuv_images: ResourceProfileCounter::new("Interned YUV images"), @@ -1118,6 +1120,7 @@ impl Profiler { &backend_profile.intern.line_decs, &backend_profile.intern.linear_gradients, &backend_profile.intern.normal_borders, + &backend_profile.intern.pictures, &backend_profile.intern.radial_gradients, &backend_profile.intern.text_runs, &backend_profile.intern.yuv_images, diff --git a/webrender/src/render_backend.rs b/webrender/src/render_backend.rs index ba3f730fe8..96226c0134 100644 --- a/webrender/src/render_backend.rs +++ b/webrender/src/render_backend.rs @@ -37,6 +37,7 @@ use prim_store::borders::{ImageBorderDataStore, NormalBorderDataStore}; use prim_store::gradient::{LinearGradientDataStore, RadialGradientDataStore}; use prim_store::image::{ImageDataStore, YuvImageDataStore}; use prim_store::line_dec::LineDecorationDataStore; +use prim_store::picture::PictureDataStore; use prim_store::text_run::TextRunDataStore; use profiler::{BackendProfileCounters, IpcProfileCounters, ResourceProfileCounters}; use record::ApiRecordingReceiver; @@ -213,6 +214,7 @@ pub struct FrameResources { pub line_decoration_data_store: LineDecorationDataStore, pub linear_grad_data_store: LinearGradientDataStore, pub normal_border_data_store: NormalBorderDataStore, + pub picture_data_store: PictureDataStore, pub radial_grad_data_store: RadialGradientDataStore, pub text_run_data_store: TextRunDataStore, pub yuv_image_data_store: YuvImageDataStore, @@ -224,7 +226,6 @@ impl FrameResources { prim_inst: &PrimitiveInstance ) -> &PrimTemplateCommonData { match prim_inst.kind { - PrimitiveInstanceKind::Picture { data_handle, .. } | PrimitiveInstanceKind::Rectangle { data_handle, .. } | PrimitiveInstanceKind::Clear { data_handle, .. } => { let prim_data = &self.prim_data_store[data_handle]; @@ -250,7 +251,11 @@ impl FrameResources { let prim_data = &self.normal_border_data_store[data_handle]; &prim_data.common } - PrimitiveInstanceKind::RadialGradient { data_handle, .. } =>{ + PrimitiveInstanceKind::Picture { data_handle, .. } => { + let prim_data = &self.picture_data_store[data_handle]; + &prim_data.common + } + PrimitiveInstanceKind::RadialGradient { data_handle, .. } => { let prim_data = &self.radial_grad_data_store[data_handle]; &prim_data.common } @@ -1264,6 +1269,10 @@ impl RenderBackend { updates.normal_border_updates, &mut profile_counters.intern.normal_borders, ); + doc.resources.picture_data_store.apply_updates( + updates.picture_updates, + &mut profile_counters.intern.pictures, + ); doc.resources.radial_grad_data_store.apply_updates( updates.radial_grad_updates, &mut profile_counters.intern.radial_gradients, diff --git a/webrender/src/scene_builder.rs b/webrender/src/scene_builder.rs index 7e0efb7f30..cda7eab506 100644 --- a/webrender/src/scene_builder.rs +++ b/webrender/src/scene_builder.rs @@ -31,6 +31,7 @@ use prim_store::image::{ use prim_store::line_dec::{ LineDecoration, LineDecorationDataInterner, LineDecorationDataUpdateList }; +use prim_store::picture::{PictureDataInterner, Picture, PictureDataUpdateList}; use prim_store::text_run::{TextRunDataInterner, TextRun, TextRunDataUpdateList}; use resource_cache::{BlobImageRasterizerEpoch, FontInstanceMap}; use render_backend::DocumentView; @@ -51,6 +52,7 @@ pub struct DocumentResourceUpdates { pub line_decoration_updates: LineDecorationDataUpdateList, pub linear_grad_updates: LinearGradientDataUpdateList, pub normal_border_updates: NormalBorderDataUpdateList, + pub picture_updates: PictureDataUpdateList, pub radial_grad_updates: RadialGradientDataUpdateList, pub text_run_updates: TextRunDataUpdateList, pub yuv_image_updates: YuvImageDataUpdateList, @@ -206,6 +208,7 @@ pub struct DocumentResources { pub line_decoration_interner: LineDecorationDataInterner, pub linear_grad_interner: LinearGradientDataInterner, pub normal_border_interner: NormalBorderDataInterner, + pub picture_interner: PictureDataInterner, pub radial_grad_interner: RadialGradientDataInterner, pub text_run_interner: TextRunDataInterner, pub yuv_image_interner: YuvImageDataInterner, @@ -237,6 +240,7 @@ impl_internet_mut! { LineDecoration: line_decoration_interner, LinearGradient: linear_grad_interner, NormalBorderPrim: normal_border_interner, + Picture: picture_interner, PrimitiveKeyKind: prim_interner, RadialGradient: radial_grad_interner, TextRun: text_run_interner, @@ -438,6 +442,11 @@ impl SceneBuilder { .normal_border_interner .end_frame_and_get_pending_updates(); + let picture_updates = item + .doc_resources + .picture_interner + .end_frame_and_get_pending_updates(); + let radial_grad_updates = item .doc_resources .radial_grad_interner @@ -462,6 +471,7 @@ impl SceneBuilder { line_decoration_updates, linear_grad_updates, normal_border_updates, + picture_updates, radial_grad_updates, text_run_updates, yuv_image_updates, @@ -598,6 +608,11 @@ impl SceneBuilder { .normal_border_interner .end_frame_and_get_pending_updates(); + let picture_updates = doc + .resources + .picture_interner + .end_frame_and_get_pending_updates(); + let radial_grad_updates = doc .resources .radial_grad_interner @@ -622,6 +637,7 @@ impl SceneBuilder { line_decoration_updates, linear_grad_updates, normal_border_updates, + picture_updates, radial_grad_updates, text_run_updates, yuv_image_updates,