1use api::{BuiltDisplayList, DisplayListWithCache, 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: DisplayListWithCache,
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 display_list = match self.pipelines.remove(&pipeline_id) {
212 Some(mut pipeline) => {
213 pipeline.display_list.update(display_list);
214 pipeline.display_list
215 }
216 None => DisplayListWithCache::new_from_list(display_list)
217 };
218
219 let new_pipeline = ScenePipeline {
220 display_list,
221 };
222
223 self.pipelines.insert(pipeline_id, new_pipeline);
224 self.pipeline_epochs.insert(pipeline_id, epoch);
225 }
226
227 pub fn remove_pipeline(&mut self, pipeline_id: PipelineId) {
228 if self.root_pipeline_id == Some(pipeline_id) {
229 self.root_pipeline_id = None;
230 }
231 self.pipelines.remove(&pipeline_id);
232 self.pipeline_epochs.remove(&pipeline_id);
233 }
234
235 pub fn update_epoch(&mut self, pipeline_id: PipelineId, epoch: Epoch) {
236 self.pipeline_epochs.insert(pipeline_id, epoch);
237 }
238
239 pub fn has_root_pipeline(&self) -> bool {
240 if let Some(ref root_id) = self.root_pipeline_id {
241 return self.pipelines.contains_key(root_id);
242 }
243
244 false
245 }
246
247 pub fn report_memory(
248 &self,
249 ops: &mut MallocSizeOfOps,
250 report: &mut MemoryReport
251 ) {
252 for (_, pipeline) in &self.pipelines {
253 report.display_list += pipeline.display_list.size_of(ops)
254 }
255 }
256}
257
258pub trait StackingContextHelpers {
259 fn mix_blend_mode_for_compositing(&self) -> Option<MixBlendMode>;
260}
261
262impl StackingContextHelpers for StackingContext {
263 fn mix_blend_mode_for_compositing(&self) -> Option<MixBlendMode> {
264 match self.mix_blend_mode {
265 MixBlendMode::Normal => None,
266 _ => Some(self.mix_blend_mode),
267 }
268 }
269}
270
271
272pub struct BuiltScene {
274 pub has_root_pipeline: bool,
275 pub pipeline_epochs: FastHashMap<PipelineId, Epoch>,
276 pub output_rect: DeviceIntRect,
277 pub prim_store: PrimitiveStore,
278 pub clip_store: ClipStore,
279 pub config: FrameBuilderConfig,
280 pub hit_testing_scene: Arc<HitTestingScene>,
281 pub tile_cache_config: TileCacheConfig,
282 pub snapshot_pictures: Vec<PictureIndex>,
283 pub tile_cache_pictures: Vec<PictureIndex>,
284 pub picture_graph: PictureGraph,
285 pub num_plane_splitters: usize,
286 pub prim_instances: Vec<PrimitiveInstance>,
287 pub surfaces: Vec<SurfaceInfo>,
288 pub clip_tree: ClipTree,
289
290 pub recycler_tx: Option<Sender<BuiltScene>>,
295}
296
297impl BuiltScene {
298 pub fn empty() -> Self {
299 BuiltScene {
300 has_root_pipeline: false,
301 pipeline_epochs: FastHashMap::default(),
302 output_rect: DeviceIntRect::zero(),
303 prim_store: PrimitiveStore::new(&PrimitiveStoreStats::empty()),
304 clip_store: ClipStore::new(),
305 hit_testing_scene: Arc::new(HitTestingScene::new(&HitTestingSceneStats::empty())),
306 tile_cache_config: TileCacheConfig::new(0),
307 snapshot_pictures: Vec::new(),
308 tile_cache_pictures: Vec::new(),
309 picture_graph: PictureGraph::new(),
310 num_plane_splitters: 0,
311 prim_instances: Vec::new(),
312 surfaces: Vec::new(),
313 clip_tree: ClipTree::new(),
314 recycler_tx: None,
315 config: FrameBuilderConfig {
316 default_font_render_mode: FontRenderMode::Mono,
317 dual_source_blending_is_supported: false,
318 testing: false,
319 gpu_supports_fast_clears: false,
320 gpu_supports_advanced_blend: false,
321 advanced_blend_is_coherent: false,
322 gpu_supports_render_target_partial_update: true,
323 external_images_require_copy: false,
324 batch_lookback_count: 0,
325 background_color: None,
326 compositor_kind: CompositorKind::default(),
327 tile_size_override: None,
328 max_surface_override: None,
329 max_depth_ids: 0,
330 max_target_size: 0,
331 force_invalidation: false,
332 is_software: false,
333 low_quality_pinch_zoom: false,
334 max_shared_surface_size: 2048,
335 },
336 }
337 }
338
339 pub fn recycle(mut self) {
342 if let Some(tx) = self.recycler_tx.take() {
343 let _ = tx.send(self);
344 }
345 }
346
347 pub fn get_stats(&self) -> SceneStats {
349 SceneStats {
350 prim_store_stats: self.prim_store.get_stats(),
351 hit_test_stats: self.hit_testing_scene.get_stats(),
352 }
353 }
354
355 pub fn create_hit_tester(
356 &mut self,
357 spatial_tree: &SpatialTree,
358 ) -> HitTester {
359 HitTester::new(
360 Arc::clone(&self.hit_testing_scene),
361 spatial_tree,
362 )
363 }
364}
365
366pub struct SceneStats {
371 pub prim_store_stats: PrimitiveStoreStats,
372 pub hit_test_stats: HitTestingSceneStats,
373}
374
375impl SceneStats {
376 pub fn empty() -> Self {
377 SceneStats {
378 prim_store_stats: PrimitiveStoreStats::empty(),
379 hit_test_stats: HitTestingSceneStats::empty(),
380 }
381 }
382}