diff options
Diffstat (limited to 'gfx/wr/webrender/src/scene.rs')
-rw-r--r-- | gfx/wr/webrender/src/scene.rs | 373 |
1 files changed, 373 insertions, 0 deletions
diff --git a/gfx/wr/webrender/src/scene.rs b/gfx/wr/webrender/src/scene.rs new file mode 100644 index 0000000000..454a2001a9 --- /dev/null +++ b/gfx/wr/webrender/src/scene.rs @@ -0,0 +1,373 @@ +/* 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::{BuiltDisplayList, DisplayListWithCache, ColorF, DynamicProperties, Epoch, FontRenderMode}; +use api::{PipelineId, PropertyBinding, PropertyBindingId, PropertyValue, MixBlendMode, StackingContext}; +use api::units::*; +use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; +use crate::render_api::MemoryReport; +use crate::composite::CompositorKind; +use crate::clip::{ClipStore, ClipTree}; +use crate::spatial_tree::SpatialTree; +use crate::frame_builder::{FrameBuilderConfig}; +use crate::hit_test::{HitTester, HitTestingScene, HitTestingSceneStats}; +use crate::internal_types::FastHashMap; +use crate::picture::SurfaceInfo; +use crate::picture_graph::PictureGraph; +use crate::prim_store::{PrimitiveStore, PrimitiveStoreStats, PictureIndex, PrimitiveInstance}; +use crate::tile_cache::TileCacheConfig; +use std::sync::Arc; + +/// Stores a map of the animated property bindings for the current display list. These +/// can be used to animate the transform and/or opacity of a display list without +/// re-submitting the display list itself. +#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(feature = "replay", derive(Deserialize))] +pub struct SceneProperties { + transform_properties: FastHashMap<PropertyBindingId, LayoutTransform>, + float_properties: FastHashMap<PropertyBindingId, f32>, + color_properties: FastHashMap<PropertyBindingId, ColorF>, + current_properties: DynamicProperties, + pending_properties: Option<DynamicProperties>, +} + +impl SceneProperties { + pub fn new() -> Self { + SceneProperties { + transform_properties: FastHashMap::default(), + float_properties: FastHashMap::default(), + color_properties: FastHashMap::default(), + current_properties: DynamicProperties::default(), + pending_properties: None, + } + } + + /// Reset the pending properties without flush. + pub fn reset_properties(&mut self) { + self.pending_properties = None; + } + + /// Add to the current property list for this display list. + pub fn add_properties(&mut self, properties: DynamicProperties) { + let mut pending_properties = self.pending_properties + .take() + .unwrap_or_default(); + + pending_properties.extend(properties); + + self.pending_properties = Some(pending_properties); + } + + /// Add to the current transform property list for this display list. + pub fn add_transforms(&mut self, transforms: Vec<PropertyValue<LayoutTransform>>) { + let mut pending_properties = self.pending_properties + .take() + .unwrap_or_default(); + + pending_properties.transforms.extend(transforms); + + self.pending_properties = Some(pending_properties); + } + + /// Flush any pending updates to the scene properties. Returns + /// true if the properties have changed since the last flush + /// was called. This code allows properties to be changed by + /// multiple reset_properties, add_properties and add_transforms calls + /// during a single transaction, and still correctly determine if any + /// properties have changed. This can have significant power + /// saving implications, allowing a frame build to be skipped + /// if the properties haven't changed in many cases. + pub fn flush_pending_updates(&mut self) -> bool { + let mut properties_changed = false; + + if let Some(ref pending_properties) = self.pending_properties { + if *pending_properties != self.current_properties { + self.transform_properties.clear(); + self.float_properties.clear(); + self.color_properties.clear(); + + for property in &pending_properties.transforms { + self.transform_properties + .insert(property.key.id, property.value); + } + + for property in &pending_properties.floats { + self.float_properties + .insert(property.key.id, property.value); + } + + for property in &pending_properties.colors { + self.color_properties + .insert(property.key.id, property.value); + } + + self.current_properties = pending_properties.clone(); + properties_changed = true; + } + } + + properties_changed + } + + /// Get the current value for a transform property. + pub fn resolve_layout_transform( + &self, + property: &PropertyBinding<LayoutTransform>, + ) -> LayoutTransform { + match *property { + PropertyBinding::Value(value) => value, + PropertyBinding::Binding(ref key, v) => { + self.transform_properties + .get(&key.id) + .cloned() + .unwrap_or(v) + } + } + } + + /// Get the current value for a float property. + pub fn resolve_float( + &self, + property: &PropertyBinding<f32> + ) -> f32 { + match *property { + PropertyBinding::Value(value) => value, + PropertyBinding::Binding(ref key, v) => { + self.float_properties + .get(&key.id) + .cloned() + .unwrap_or(v) + } + } + } + + pub fn float_properties(&self) -> &FastHashMap<PropertyBindingId, f32> { + &self.float_properties + } + + /// Get the current value for a color property. + pub fn resolve_color( + &self, + property: &PropertyBinding<ColorF> + ) -> ColorF { + match *property { + PropertyBinding::Value(value) => value, + PropertyBinding::Binding(ref key, v) => { + self.color_properties + .get(&key.id) + .cloned() + .unwrap_or(v) + } + } + } + + pub fn color_properties(&self) -> &FastHashMap<PropertyBindingId, ColorF> { + &self.color_properties + } + +} + +/// A representation of the layout within the display port for a given document or iframe. +#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(feature = "replay", derive(Deserialize))] +#[derive(Clone)] +pub struct ScenePipeline { + pub pipeline_id: PipelineId, + pub viewport_size: LayoutSize, + pub background_color: Option<ColorF>, + pub display_list: DisplayListWithCache, +} + +/// A complete representation of the layout bundling visible pipelines together. +#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(feature = "replay", derive(Deserialize))] +#[derive(Clone)] +pub struct Scene { + pub root_pipeline_id: Option<PipelineId>, + pub pipelines: FastHashMap<PipelineId, ScenePipeline>, + pub pipeline_epochs: FastHashMap<PipelineId, Epoch>, +} + +impl Scene { + pub fn new() -> Self { + Scene { + root_pipeline_id: None, + pipelines: FastHashMap::default(), + pipeline_epochs: FastHashMap::default(), + } + } + + pub fn set_root_pipeline_id(&mut self, pipeline_id: PipelineId) { + self.root_pipeline_id = Some(pipeline_id); + } + + pub fn set_display_list( + &mut self, + pipeline_id: PipelineId, + epoch: Epoch, + display_list: BuiltDisplayList, + background_color: Option<ColorF>, + viewport_size: LayoutSize, + ) { + // Adds a cache to the given display list. If this pipeline already had + // a display list before, that display list is updated and used instead. + let display_list = match self.pipelines.remove(&pipeline_id) { + Some(mut pipeline) => { + pipeline.display_list.update(display_list); + pipeline.display_list + } + None => DisplayListWithCache::new_from_list(display_list) + }; + + let new_pipeline = ScenePipeline { + pipeline_id, + viewport_size, + background_color, + display_list, + }; + + self.pipelines.insert(pipeline_id, new_pipeline); + self.pipeline_epochs.insert(pipeline_id, epoch); + } + + pub fn remove_pipeline(&mut self, pipeline_id: PipelineId) { + if self.root_pipeline_id == Some(pipeline_id) { + self.root_pipeline_id = None; + } + self.pipelines.remove(&pipeline_id); + self.pipeline_epochs.remove(&pipeline_id); + } + + pub fn update_epoch(&mut self, pipeline_id: PipelineId, epoch: Epoch) { + self.pipeline_epochs.insert(pipeline_id, epoch); + } + + pub fn has_root_pipeline(&self) -> bool { + if let Some(ref root_id) = self.root_pipeline_id { + return self.pipelines.contains_key(root_id); + } + + false + } + + pub fn report_memory( + &self, + ops: &mut MallocSizeOfOps, + report: &mut MemoryReport + ) { + for (_, pipeline) in &self.pipelines { + report.display_list += pipeline.display_list.size_of(ops) + } + } +} + +pub trait StackingContextHelpers { + fn mix_blend_mode_for_compositing(&self) -> Option<MixBlendMode>; +} + +impl StackingContextHelpers for StackingContext { + fn mix_blend_mode_for_compositing(&self) -> Option<MixBlendMode> { + match self.mix_blend_mode { + MixBlendMode::Normal => None, + _ => Some(self.mix_blend_mode), + } + } +} + + +/// WebRender's internal representation of the scene. +pub struct BuiltScene { + pub has_root_pipeline: bool, + pub pipeline_epochs: FastHashMap<PipelineId, Epoch>, + pub output_rect: DeviceIntRect, + pub background_color: Option<ColorF>, + pub prim_store: PrimitiveStore, + pub clip_store: ClipStore, + pub config: FrameBuilderConfig, + pub hit_testing_scene: Arc<HitTestingScene>, + pub tile_cache_config: TileCacheConfig, + pub tile_cache_pictures: Vec<PictureIndex>, + pub picture_graph: PictureGraph, + pub num_plane_splitters: usize, + pub prim_instances: Vec<PrimitiveInstance>, + pub surfaces: Vec<SurfaceInfo>, + pub clip_tree: ClipTree, +} + +impl BuiltScene { + pub fn empty() -> Self { + BuiltScene { + has_root_pipeline: false, + pipeline_epochs: FastHashMap::default(), + output_rect: DeviceIntRect::zero(), + background_color: None, + prim_store: PrimitiveStore::new(&PrimitiveStoreStats::empty()), + clip_store: ClipStore::new(), + hit_testing_scene: Arc::new(HitTestingScene::new(&HitTestingSceneStats::empty())), + tile_cache_config: TileCacheConfig::new(0), + tile_cache_pictures: Vec::new(), + picture_graph: PictureGraph::new(), + num_plane_splitters: 0, + prim_instances: Vec::new(), + surfaces: Vec::new(), + clip_tree: ClipTree::new(), + config: FrameBuilderConfig { + default_font_render_mode: FontRenderMode::Mono, + dual_source_blending_is_supported: false, + testing: false, + gpu_supports_fast_clears: false, + gpu_supports_advanced_blend: false, + advanced_blend_is_coherent: false, + gpu_supports_render_target_partial_update: true, + external_images_require_copy: false, + batch_lookback_count: 0, + background_color: None, + compositor_kind: CompositorKind::default(), + tile_size_override: None, + max_surface_override: None, + max_depth_ids: 0, + max_target_size: 0, + force_invalidation: false, + is_software: false, + low_quality_pinch_zoom: false, + }, + } + } + + /// Get the memory usage statistics to pre-allocate for the next scene. + pub fn get_stats(&self) -> SceneStats { + SceneStats { + prim_store_stats: self.prim_store.get_stats(), + hit_test_stats: self.hit_testing_scene.get_stats(), + } + } + + pub fn create_hit_tester( + &mut self, + spatial_tree: &SpatialTree, + ) -> HitTester { + HitTester::new( + Arc::clone(&self.hit_testing_scene), + spatial_tree, + ) + } +} + +/// Stores the allocation sizes of various arrays in the built +/// scene. This is retrieved from the current frame builder +/// and used to reserve an approximately correct capacity of +/// the arrays for the next scene that is getting built. +pub struct SceneStats { + pub prim_store_stats: PrimitiveStoreStats, + pub hit_test_stats: HitTestingSceneStats, +} + +impl SceneStats { + pub fn empty() -> Self { + SceneStats { + prim_store_stats: PrimitiveStoreStats::empty(), + hit_test_stats: HitTestingSceneStats::empty(), + } + } +} |