1use api::{BuiltDisplayList, ColorF, DynamicProperties, Epoch, FontRenderMode};
6use api::{PipelineId, PropertyBinding, PropertyBindingId, PropertyValue, MixBlendMode, StackingContext};
7use api::units::*;
8use api::channel::Sender;
9use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
10use crate::render_api::MemoryReport;
11use crate::composite::CompositorKind;
12use crate::clip::{ClipStore, ClipTree};
13use crate::spatial_tree::SpatialTree;
14use crate::frame_builder::FrameBuilderConfig;
15use crate::hit_test::{HitTester, HitTestingScene, HitTestingSceneStats};
16use crate::internal_types::FastHashMap;
17use crate::picture::SurfaceInfo;
18use crate::picture_graph::PictureGraph;
19use crate::prim_store::{PrimitiveStore, PrimitiveStoreStats, PictureIndex, PrimitiveInstance};
20use crate::tile_cache::TileCacheConfig;
21use std::sync::Arc;
22
23#[cfg_attr(feature = "capture", derive(Serialize))]
27#[cfg_attr(feature = "replay", derive(Deserialize))]
28pub struct SceneProperties {
29 transform_properties: FastHashMap<PropertyBindingId, LayoutTransform>,
30 float_properties: FastHashMap<PropertyBindingId, f32>,
31 color_properties: FastHashMap<PropertyBindingId, ColorF>,
32 current_properties: DynamicProperties,
33 pending_properties: Option<DynamicProperties>,
34}
35
36impl SceneProperties {
37 pub fn new() -> Self {
38 SceneProperties {
39 transform_properties: FastHashMap::default(),
40 float_properties: FastHashMap::default(),
41 color_properties: FastHashMap::default(),
42 current_properties: DynamicProperties::default(),
43 pending_properties: None,
44 }
45 }
46
47 pub fn reset_properties(&mut self) {
49 self.pending_properties = None;
50 }
51
52 pub fn add_properties(&mut self, properties: DynamicProperties) {
54 let mut pending_properties = self.pending_properties
55 .take()
56 .unwrap_or_default();
57
58 pending_properties.extend(properties);
59
60 self.pending_properties = Some(pending_properties);
61 }
62
63 pub fn add_transforms(&mut self, transforms: Vec<PropertyValue<LayoutTransform>>) {
65 let mut pending_properties = self.pending_properties
66 .take()
67 .unwrap_or_default();
68
69 pending_properties.transforms.extend(transforms);
70
71 self.pending_properties = Some(pending_properties);
72 }
73
74 pub fn flush_pending_updates(&mut self) -> bool {
83 let mut properties_changed = false;
84
85 if let Some(ref pending_properties) = self.pending_properties {
86 if *pending_properties != self.current_properties {
87 self.transform_properties.clear();
88 self.float_properties.clear();
89 self.color_properties.clear();
90
91 for property in &pending_properties.transforms {
92 self.transform_properties
93 .insert(property.key.id, property.value);
94 }
95
96 for property in &pending_properties.floats {
97 self.float_properties
98 .insert(property.key.id, property.value);
99 }
100
101 for property in &pending_properties.colors {
102 self.color_properties
103 .insert(property.key.id, property.value);
104 }
105
106 self.current_properties = pending_properties.clone();
107 properties_changed = true;
108 }
109 }
110
111 properties_changed
112 }
113
114 pub fn resolve_layout_transform(
116 &self,
117 property: &PropertyBinding<LayoutTransform>,
118 ) -> LayoutTransform {
119 match *property {
120 PropertyBinding::Value(value) => value,
121 PropertyBinding::Binding(ref key, v) => {
122 self.transform_properties
123 .get(&key.id)
124 .cloned()
125 .unwrap_or(v)
126 }
127 }
128 }
129
130 pub fn resolve_float(
132 &self,
133 property: &PropertyBinding<f32>
134 ) -> f32 {
135 match *property {
136 PropertyBinding::Value(value) => value,
137 PropertyBinding::Binding(ref key, v) => {
138 self.float_properties
139 .get(&key.id)
140 .cloned()
141 .unwrap_or(v)
142 }
143 }
144 }
145
146 pub fn float_properties(&self) -> &FastHashMap<PropertyBindingId, f32> {
147 &self.float_properties
148 }
149
150 pub fn resolve_color(
152 &self,
153 property: &PropertyBinding<ColorF>
154 ) -> ColorF {
155 match *property {
156 PropertyBinding::Value(value) => value,
157 PropertyBinding::Binding(ref key, v) => {
158 self.color_properties
159 .get(&key.id)
160 .cloned()
161 .unwrap_or(v)
162 }
163 }
164 }
165
166 pub fn color_properties(&self) -> &FastHashMap<PropertyBindingId, ColorF> {
167 &self.color_properties
168 }
169
170}
171
172#[cfg_attr(feature = "capture", derive(Serialize))]
174#[cfg_attr(feature = "replay", derive(Deserialize))]
175#[derive(Clone)]
176pub struct ScenePipeline {
177 pub display_list: BuiltDisplayList,
178}
179
180#[cfg_attr(feature = "capture", derive(Serialize))]
182#[cfg_attr(feature = "replay", derive(Deserialize))]
183#[derive(Clone)]
184pub struct Scene {
185 pub root_pipeline_id: Option<PipelineId>,
186 pub pipelines: FastHashMap<PipelineId, ScenePipeline>,
187 pub pipeline_epochs: FastHashMap<PipelineId, Epoch>,
188}
189
190impl Scene {
191 pub fn new() -> Self {
192 Scene {
193 root_pipeline_id: None,
194 pipelines: FastHashMap::default(),
195 pipeline_epochs: FastHashMap::default(),
196 }
197 }
198
199 pub fn set_root_pipeline_id(&mut self, pipeline_id: PipelineId) {
200 self.root_pipeline_id = Some(pipeline_id);
201 }
202
203 pub fn set_display_list(
204 &mut self,
205 pipeline_id: PipelineId,
206 epoch: Epoch,
207 display_list: BuiltDisplayList,
208 ) {
209 let new_pipeline = ScenePipeline {
210 display_list,
211 };
212
213 self.pipelines.insert(pipeline_id, new_pipeline);
214 self.pipeline_epochs.insert(pipeline_id, epoch);
215 }
216
217 pub fn remove_pipeline(&mut self, pipeline_id: PipelineId) {
218 if self.root_pipeline_id == Some(pipeline_id) {
219 self.root_pipeline_id = None;
220 }
221 self.pipelines.remove(&pipeline_id);
222 self.pipeline_epochs.remove(&pipeline_id);
223 }
224
225 pub fn update_epoch(&mut self, pipeline_id: PipelineId, epoch: Epoch) {
226 self.pipeline_epochs.insert(pipeline_id, epoch);
227 }
228
229 pub fn has_root_pipeline(&self) -> bool {
230 if let Some(ref root_id) = self.root_pipeline_id {
231 return self.pipelines.contains_key(root_id);
232 }
233
234 false
235 }
236
237 pub fn report_memory(
238 &self,
239 ops: &mut MallocSizeOfOps,
240 report: &mut MemoryReport
241 ) {
242 for (_, pipeline) in &self.pipelines {
243 report.display_list += pipeline.display_list.size_of(ops)
244 }
245 }
246}
247
248pub trait StackingContextHelpers {
249 fn mix_blend_mode_for_compositing(&self) -> Option<MixBlendMode>;
250}
251
252impl StackingContextHelpers for StackingContext {
253 fn mix_blend_mode_for_compositing(&self) -> Option<MixBlendMode> {
254 match self.mix_blend_mode {
255 MixBlendMode::Normal => None,
256 _ => Some(self.mix_blend_mode),
257 }
258 }
259}
260
261
262pub struct BuiltScene {
264 pub has_root_pipeline: bool,
265 pub pipeline_epochs: FastHashMap<PipelineId, Epoch>,
266 pub output_rect: DeviceIntRect,
267 pub prim_store: PrimitiveStore,
268 pub clip_store: ClipStore,
269 pub config: FrameBuilderConfig,
270 pub hit_testing_scene: Arc<HitTestingScene>,
271 pub tile_cache_config: TileCacheConfig,
272 pub snapshot_pictures: Vec<PictureIndex>,
273 pub tile_cache_pictures: Vec<PictureIndex>,
274 pub picture_graph: PictureGraph,
275 pub num_plane_splitters: usize,
276 pub prim_instances: Vec<PrimitiveInstance>,
277 pub surfaces: Vec<SurfaceInfo>,
278 pub clip_tree: ClipTree,
279
280 pub recycler_tx: Option<Sender<BuiltScene>>,
285}
286
287impl BuiltScene {
288 pub fn empty() -> Self {
289 BuiltScene {
290 has_root_pipeline: false,
291 pipeline_epochs: FastHashMap::default(),
292 output_rect: DeviceIntRect::zero(),
293 prim_store: PrimitiveStore::new(&PrimitiveStoreStats::empty()),
294 clip_store: ClipStore::new(),
295 hit_testing_scene: Arc::new(HitTestingScene::new(&HitTestingSceneStats::empty())),
296 tile_cache_config: TileCacheConfig::new(0),
297 snapshot_pictures: Vec::new(),
298 tile_cache_pictures: Vec::new(),
299 picture_graph: PictureGraph::new(),
300 num_plane_splitters: 0,
301 prim_instances: Vec::new(),
302 surfaces: Vec::new(),
303 clip_tree: ClipTree::new(),
304 recycler_tx: None,
305 config: FrameBuilderConfig {
306 default_font_render_mode: FontRenderMode::Mono,
307 dual_source_blending_is_supported: false,
308 testing: false,
309 gpu_supports_fast_clears: false,
310 gpu_supports_advanced_blend: false,
311 advanced_blend_is_coherent: false,
312 gpu_supports_render_target_partial_update: true,
313 external_images_require_copy: false,
314 batch_lookback_count: 0,
315 background_color: None,
316 compositor_kind: CompositorKind::default(),
317 tile_size_override: None,
318 max_surface_override: None,
319 max_depth_ids: 0,
320 max_target_size: 0,
321 force_invalidation: false,
322 is_software: false,
323 low_quality_pinch_zoom: false,
324 max_shared_surface_size: 2048,
325 enable_dithering: false,
326 },
327 }
328 }
329
330 pub fn recycle(mut self) {
333 if let Some(tx) = self.recycler_tx.take() {
334 let _ = tx.send(self);
335 }
336 }
337
338 pub fn get_stats(&self) -> SceneStats {
340 SceneStats {
341 prim_store_stats: self.prim_store.get_stats(),
342 hit_test_stats: self.hit_testing_scene.get_stats(),
343 }
344 }
345
346 pub fn create_hit_tester(
347 &mut self,
348 spatial_tree: &SpatialTree,
349 ) -> HitTester {
350 HitTester::new(
351 Arc::clone(&self.hit_testing_scene),
352 spatial_tree,
353 )
354 }
355}
356
357pub struct SceneStats {
362 pub prim_store_stats: PrimitiveStoreStats,
363 pub hit_test_stats: HitTestingSceneStats,
364}
365
366impl SceneStats {
367 pub fn empty() -> Self {
368 SceneStats {
369 prim_store_stats: PrimitiveStoreStats::empty(),
370 hit_test_stats: HitTestingSceneStats::empty(),
371 }
372 }
373}