1use super::{
2 impl_animated_server_object, CompositionTargetOverlays, DebugEventsDirtyRectCollectorProxy, IAnimatedServerObject,
3 IDirtyRectCollector, IDirtyRectTracker, IServerObject, MultiDirtyRectTracker, RegionDirtyRectTracker,
4 ServerCompositionVisual, ServerCompositor, ServerObject, SingleDirtyRectTracker,
5};
6use crate::media::Colors;
7use crate::platform::surfaces::IPlatformRenderSurface;
8use crate::platform::{
9 IDrawingContextImpl, IDrawingContextLayerImpl, IRenderTarget, LtrbRect, RenderTargetError, RenderTargetSceneInfo,
10};
11use crate::rendering::composition::generated::{
12 CompositionTargetChangedFields, ServerCompositionTargetHooks, ServerCompositionTargetProps,
13};
14use crate::rendering::composition::transport::BatchStreamReader;
15use crate::rendering::composition::{CompositionTransparencyLevel, ICompositionTargetDebugEvents};
16use crate::rendering::{LayoutPassTiming, RendererDebugOverlays};
17use crate::{Matrix, PixelRect, PixelSize, Size};
18use std::any::{Any, TypeId};
19use std::cell::{Cell, RefCell};
20use std::collections::HashMap;
21use std::sync::Arc;
22use std::rc::{Rc, Weak};
23use std::time::Duration;
24
25pub type RenderSurfaces = std::sync::Arc<dyn Fn() -> Vec<std::sync::Arc<dyn IPlatformRenderSurface>> + Send + Sync>;
30
31pub struct ServerCompositionTarget {
35 this: Weak<ServerCompositionTarget>,
36 object: ServerObject,
37 compositor: Weak<ServerCompositor>,
38 props: ServerCompositionTargetProps,
39 surfaces: RenderSurfaces,
40 overlays: CompositionTargetOverlays,
41 render_target: RefCell<Option<Rc<dyn IRenderTarget>>>,
42 layer_size: Cell<PixelSize>,
43 layer: RefCell<Option<Rc<dyn IDrawingContextLayerImpl>>>,
44 update_requested: Cell<bool>,
45 redraw_requested: Cell<bool>,
46 full_redraw_requested: Cell<bool>,
47 disposed: Cell<bool>,
48 attached_visuals: RefCell<HashMap<*const ServerCompositionVisual, Rc<ServerCompositionVisual>>>,
49 dirty_rects: Rc<dyn IDirtyRectTracker>,
50 id: i64,
51 debug_events: RefCell<Option<Arc<dyn ICompositionTargetDebugEvents>>>,
52 rendered_visuals: Cell<i32>,
53 visited_visuals: Cell<i32>,
54 is_waiting_for_ready_render_target: Cell<bool>,
55 is_waiting_for_render_loop_wakeup: Cell<bool>,
56 frame_times: RefCell<Option<Vec<std::time::Duration>>>,
62 drew_frame: Cell<bool>,
64}
65
66impl ServerCompositionTarget {
67 pub(crate) fn is_disposed(&self) -> bool {
70 self.disposed.get()
71 }
72
73 pub fn new(compositor: &Rc<ServerCompositor>, surfaces: RenderSurfaces, id: i64) -> Rc<ServerCompositionTarget> {
76 let mut dirty_rects: Option<Rc<dyn IDirtyRectTracker>> = None;
77 compositor.render_interface().with_platform_render_interface(|platform_render| {
80 if platform_render.supports_regions() && compositor.options().use_region_dirty_rect_clipping == Some(true) {
81 let max_rects = compositor.options().max_dirty_rects.unwrap_or(8);
82 dirty_rects = Some(if max_rects <= 0 {
83 Rc::new(RegionDirtyRectTracker::new(platform_render))
84 } else {
85 Rc::new(MultiDirtyRectTracker::new(
86 platform_render,
87 max_rects,
88 compositor.options().dirty_rect_merge_eagerness.unwrap_or(1000.0),
90 ))
91 });
92 }
93 });
94 let dirty_rects = dirty_rects.unwrap_or_else(|| Rc::new(SingleDirtyRectTracker::new()));
95
96 Rc::new_cyclic(|this: &Weak<ServerCompositionTarget>| {
97 let owner: Weak<dyn IAnimatedServerObject> = this.clone();
98 ServerCompositionTarget {
99 this: this.clone(),
100 object: ServerObject::new(compositor, owner),
101 compositor: Rc::downgrade(compositor),
102 props: ServerCompositionTargetProps::new(),
103 surfaces,
104 overlays: CompositionTargetOverlays::new(compositor),
105 render_target: RefCell::new(None),
106 layer_size: Cell::new(PixelSize::default()),
107 layer: RefCell::new(None),
108 update_requested: Cell::new(false),
109 redraw_requested: Cell::new(false),
110 full_redraw_requested: Cell::new(false),
111 disposed: Cell::new(false),
112 attached_visuals: RefCell::new(HashMap::new()),
113 dirty_rects,
114 id,
115 debug_events: RefCell::new(None),
116 rendered_visuals: Cell::new(0),
117 visited_visuals: Cell::new(0),
118 is_waiting_for_ready_render_target: Cell::new(false),
119 is_waiting_for_render_loop_wakeup: Cell::new(false),
120 frame_times: RefCell::new(
121 std::env::var("FERROUI_FRAME_TIMES").is_ok_and(|value| value == "1").then(Vec::new),
122 ),
123 drew_frame: Cell::new(false),
124 }
125 })
126 }
127
128 pub fn compositor(&self) -> Option<Rc<ServerCompositor>> {
129 self.compositor.upgrade()
130 }
131
132 pub fn dirty_rects(&self) -> &Rc<dyn IDirtyRectTracker> {
133 &self.dirty_rects
134 }
135
136 pub fn id(&self) -> i64 {
137 self.id
138 }
139
140 pub fn debug_events(&self) -> Option<Arc<dyn ICompositionTargetDebugEvents>> {
141 self.debug_events.borrow().clone()
142 }
143
144 pub fn set_debug_events(&self, value: Option<Arc<dyn ICompositionTargetDebugEvents>>) {
145 *self.debug_events.borrow_mut() = value;
146 }
147
148 pub fn rendered_visuals(&self) -> i32 {
149 self.rendered_visuals.get()
150 }
151
152 pub fn visited_visuals(&self) -> i32 {
153 self.visited_visuals.get()
154 }
155
156 pub fn pixel_size(&self) -> PixelSize {
157 PixelSize::from_size_ceiling(self.size(), self.scaling())
158 }
159
160 pub fn is_waiting_for_ready_render_target(&self) -> bool {
163 self.is_waiting_for_ready_render_target.get()
164 }
165
166 pub fn is_waiting_for_render_loop_wakeup(&self) -> bool {
170 self.is_waiting_for_render_loop_wakeup.get()
171 }
172
173 pub fn root(&self) -> Option<Rc<ServerCompositionVisual>> {
176 self.props.root().and_then(|o| o.into_any_rc().downcast::<ServerCompositionVisual>().ok())
177 }
178
179 pub fn is_enabled(&self) -> bool {
180 self.props.is_enabled()
181 }
182
183 pub fn debug_overlays(&self) -> RendererDebugOverlays {
184 self.props.debug_overlays()
185 }
186
187 pub fn last_layout_pass_timing(&self) -> LayoutPassTiming {
188 self.props.last_layout_pass_timing()
189 }
190
191 pub fn scaling(&self) -> f64 {
192 self.props.scaling()
193 }
194
195 pub fn size(&self) -> Size {
196 self.props.size()
197 }
198
199 pub fn transparency_level(&self) -> CompositionTransparencyLevel {
200 self.props.transparency_level()
201 }
202
203 pub fn platform_specific_scene_info(&self) -> Option<std::sync::Arc<dyn Any + Send + Sync>> {
204 self.props.platform_specific_scene_info()
205 }
206
207 pub fn update(self: &Rc<Self>, diagnostics_compositor_global_update_elapsed_time: Duration) {
210 let Some(compositor) = self.compositor() else { return };
211 if self.disposed.get() {
212 compositor.remove_composition_target(self);
213 return;
214 }
215
216 let Some(root) = self.root() else { return };
217
218 self.overlays.record_global_compositor_update_time(self, diagnostics_compositor_global_update_elapsed_time);
219 self.overlays.mark_update_call_start(self);
220
221 let scaling = self.scaling();
222 let transform = Matrix::create_scale(scaling, scaling);
223 let tracker: Rc<dyn IDirtyRectCollector> = self.dirty_rects.clone();
224 let collector: Rc<dyn IDirtyRectCollector> = match self.debug_events() {
225 Some(events) => Rc::new(DebugEventsDirtyRectCollectorProxy::new(tracker, events)),
226 None => tracker,
227 };
228 let pixel_size = self.pixel_size();
229 root.update_root(
230 collector,
231 transform,
232 LtrbRect::new(0.0, 0.0, pixel_size.width as f64, pixel_size.height as f64),
233 );
234 self.update_requested.set(false);
235 self.overlays.mark_update_call_end(self);
236 }
237
238 pub fn render(self: &Rc<Self>) {
239 if self.frame_times.borrow().is_none() {
240 return self.render_frame();
241 }
242 self.drew_frame.set(false);
243 let start = std::time::Instant::now();
244 self.render_frame();
245 if self.drew_frame.get() {
246 if let Some(times) = self.frame_times.borrow_mut().as_mut() {
247 times.push(start.elapsed());
248 }
249 }
250 }
251
252 fn frame_times_summary(&self) -> Option<String> {
255 let mut times = self.frame_times.borrow().clone()?;
256 if times.is_empty() {
257 return None;
258 }
259 times.sort();
260 let ms = |duration: std::time::Duration| duration.as_secs_f64() * 1000.0;
261 let mean = times.iter().map(|time| ms(*time)).sum::<f64>() / times.len() as f64;
262 Some(format!(
263 "frame times of composition target {}: {} frames; ms per frame: median {:.3}, mean {:.3}, p95 {:.3}, max {:.3}",
264 self.id,
265 times.len(),
266 ms(times[times.len() / 2]),
267 mean,
268 ms(times[(times.len() * 95 / 100).min(times.len() - 1)]),
269 ms(times[times.len() - 1]),
270 ))
271 }
272
273 fn render_frame(self: &Rc<Self>) {
274 self.is_waiting_for_ready_render_target.set(false);
275 self.is_waiting_for_render_loop_wakeup.set(false);
276
277 if self.disposed.get() {
278 return;
279 }
280
281 let Some(root) = self.root() else { return };
282 let Some(compositor) = self.compositor() else { return };
283
284 let corrupted = self.render_target.borrow().as_ref().is_some_and(|t| t.platform_render_target_state().is_corrupted);
285 if corrupted {
286 if let Some(layer) = self.layer.borrow_mut().take() {
287 layer.dispose();
288 }
289 if let Some(render_target) = self.render_target.borrow_mut().take() {
290 render_target.dispose();
291 }
292 self.redraw_requested.set(true);
293 }
294
295 if self.render_target.borrow().is_none() {
296 let surfaces = (self.surfaces)();
297 if !compositor.is_ready_to_create_render_target(&surfaces) {
298 self.is_waiting_for_ready_render_target.set(self.is_enabled());
299 return;
300 }
301 let render_target = compositor.create_render_target(&surfaces);
302 *self.render_target.borrow_mut() = Some(render_target);
303 }
304 let Some(render_target) = self.render_target.borrow().clone() else { return };
305
306 if self.dirty_rects.is_empty() && !self.redraw_requested.get() && !self.update_requested.get() {
307 return;
308 }
309
310 self.redraw_requested.set(self.redraw_requested.get() | !self.dirty_rects.is_empty());
311
312 if !self.redraw_requested.get() {
313 return;
314 }
315
316 let state = render_target.platform_render_target_state();
317 if !state.is_ready {
318 self.is_waiting_for_ready_render_target.set(self.is_enabled());
319 self.is_waiting_for_render_loop_wakeup
320 .set(self.is_enabled() && state.will_wake_up_render_loop_when_ready);
321 return;
322 }
323
324 let properties = render_target.properties();
325 let need_layer = self.overlays.require_layer() || !(properties.retains_previous_frame_contents && properties.is_suitable_for_direct_rendering);
328
329 let pixel_size = self.pixel_size();
330 let scene_info = RenderTargetSceneInfo {
331 size: pixel_size,
332 scaling: self.scaling(),
333 logical_size: self.size(),
334 transparency_level: self.transparency_level(),
335 platform_specific_scene_info: self.platform_specific_scene_info(),
336 };
337 self.drew_frame.set(true);
338 let (mut render_target_context, properties) = match render_target.try_create_drawing_context(&scene_info) {
339 Ok(created) => created,
340 Err(RenderTargetError::NotReady(_)) => {
341 self.is_waiting_for_ready_render_target.set(self.is_enabled());
342 return;
343 }
344 Err(RenderTargetError::Corrupted(_)) => return,
345 };
346
347 {
348 let mut full_redraw = false;
349
350 let layer_is_stale = {
351 let layer = self.layer.borrow();
352 pixel_size != self.layer_size.get() || layer.as_ref().is_none_or(|layer| layer.is_corrupted())
353 };
354 if need_layer && layer_is_stale {
355 if let Some(layer) = self.layer.borrow_mut().take() {
356 layer.dispose();
357 }
358 *self.layer.borrow_mut() = Some(render_target_context.create_layer(pixel_size));
359 self.layer_size.set(pixel_size);
360 full_redraw = true;
361 } else if !need_layer {
362 if let Some(layer) = self.layer.borrow_mut().take() {
363 layer.dispose();
364 }
365 }
366
367 if self.full_redraw_requested.get() || (!need_layer && !properties.previous_frame_is_retained) {
368 self.full_redraw_requested.set(false);
369 full_redraw = true;
370 }
371
372 let render_bounds = LtrbRect::new(0.0, 0.0, pixel_size.width as f64, pixel_size.height as f64);
373
374 if full_redraw {
375 self.dirty_rects.initialize(render_bounds);
376 self.dirty_rects.add_rect(render_bounds);
377 }
378
379 if !self.dirty_rects.is_empty() {
380 self.dirty_rects.finalize_frame(render_bounds);
381 let layer = self.layer.borrow().clone();
382 match layer {
383 Some(layer) => {
384 {
385 let mut context = layer.create_drawing_context();
386 self.render_root_to_context_with_clip(&compositor, &mut *context, &root);
387 context.dispose();
388 }
389
390 render_target_context.clear(Colors::TRANSPARENT);
391 render_target_context.set_transform(Matrix::IDENTITY);
392 if layer.can_blit() {
393 layer.blit(&mut *render_target_context);
394 } else {
395 let rect = PixelRect::from_size(pixel_size).to_rect(1.0);
396 render_target_context.draw_bitmap(&*layer, 1.0, rect, rect);
397 }
398 self.overlays.draw(self, &mut *render_target_context, true);
399 }
400 None => {
401 self.render_root_to_context_with_clip(&compositor, &mut *render_target_context, &root);
402 self.overlays.draw(self, &mut *render_target_context, false);
403 }
404 }
405 }
406
407 self.rendered_visuals.set(0);
408 self.visited_visuals.set(0);
409
410 self.redraw_requested.set(false);
411 self.dirty_rects.initialize(render_bounds);
412 }
413 render_target_context.dispose();
414 }
415
416 fn render_root_to_context_with_clip(
417 &self,
418 compositor: &ServerCompositor,
419 context: &mut dyn IDrawingContextImpl,
420 root: &Rc<ServerCompositionVisual>,
421 ) {
422 let use_layer_clip = compositor.options().use_save_layer_root_clip.unwrap_or(false);
423 self.dirty_rects.begin_draw(context);
424 {
425 context.clear(Colors::TRANSPARENT);
426 if use_layer_clip {
427 context.push_layer(self.dirty_rects.combined_rect().to_rect());
428 }
429 let scaling = self.scaling();
430 context.set_transform(Matrix::create_scale(scaling, scaling));
431 let pixel_size = self.pixel_size();
432 let (visited, rendered) = root.render(
433 context,
434 LtrbRect::new(0.0, 0.0, pixel_size.width as f64, pixel_size.height as f64),
435 Some(self.dirty_rects.clone()),
436 true,
437 false,
438 false,
439 );
440 self.visited_visuals.set(visited);
441 self.rendered_visuals.set(rendered);
442 if let Some(events) = self.debug_events() {
443 events.set_rendered_visuals(rendered);
444 events.set_visited_visuals(visited);
445 }
446
447 if use_layer_clip {
448 context.pop_layer();
449 }
450 }
451 self.dirty_rects.end_draw(context);
452 }
453
454 pub fn request_update(&self) {
455 self.update_requested.set(true);
456 }
457
458 pub fn reset_render_target(&self) {
459 if self.layer.borrow().is_none() && self.render_target.borrow().is_none() {
460 return;
461 }
462 let current = self.compositor().map(|compositor| compositor.render_interface().ensure_current());
463 self.release_render_target();
464 if let Some(current) = current {
465 current.dispose();
466 }
467 }
468
469 pub(crate) fn release_render_target(&self) {
474 if let Some(layer) = self.layer.borrow_mut().take() {
475 layer.dispose();
476 }
477 if let Some(render_target) = self.render_target.borrow_mut().take() {
478 render_target.dispose();
479 }
480 }
481
482 pub fn add_visual(&self, visual: &Rc<ServerCompositionVisual>) {
483 let added = self.attached_visuals.borrow_mut().insert(Rc::as_ptr(visual), visual.clone()).is_none();
484 if added && self.is_enabled() {
485 visual.activate();
486 }
487 }
488
489 pub fn remove_visual(&self, visual: &Rc<ServerCompositionVisual>) {
490 let removed = self.attached_visuals.borrow_mut().remove(&Rc::as_ptr(visual)).is_some();
491 if removed && self.is_enabled() {
492 visual.deactivate();
493 }
494 }
495
496 pub fn request_full_redraw(&self) {
497 self.redraw_requested.set(true);
498 }
499}
500
501impl ServerCompositionTargetHooks for ServerCompositionTarget {
502 fn deserialize_changes_extra(&self, _reader: &mut BatchStreamReader<'_>) {
503 self.redraw_requested.set(true);
504 self.full_redraw_requested.set(true);
505 }
506
507 fn on_fields_deserialized(&self, _changed: CompositionTargetChangedFields) {}
508
509 fn on_is_enabled_changed(&self) {
510 let (Some(compositor), Some(this)) = (self.compositor(), self.this.upgrade()) else { return };
511 let visuals: Vec<_> = self.attached_visuals.borrow().values().cloned().collect();
512 if self.is_enabled() {
513 compositor.add_composition_target(&this);
514 for visual in visuals {
515 visual.activate();
516 }
517 } else {
518 compositor.remove_composition_target(&this);
519 for visual in visuals {
520 visual.deactivate();
521 }
522 }
523 }
524
525 fn on_debug_overlays_changed(&self) {
526 self.full_redraw_requested.set(true);
527 self.overlays.on_changed(self.debug_overlays());
528 }
529
530 fn on_last_layout_pass_timing_changed(&self) {
531 self.overlays.on_last_layout_pass_timing_changed(self, self.last_layout_pass_timing());
532 }
533}
534
535impl_animated_server_object!(ServerCompositionTarget, object);
536
537impl IServerObject for ServerCompositionTarget {
538 fn deserialize_changes_core(&self, reader: &mut BatchStreamReader<'_>, committed_at: Duration) {
539 self.props.deserialize_changes_core(self, reader, committed_at);
540 }
541
542 fn dispose(&self) {
543 if self.disposed.replace(true) {
544 return;
545 }
546 if let Some(summary) = self.frame_times_summary() {
547 eprintln!("{summary}");
548 }
549 self.reset_render_target();
550 if let (Some(compositor), Some(this)) = (self.compositor(), self.this.upgrade()) {
551 compositor.remove_composition_target(&this);
552 }
553 self.attached_visuals.borrow_mut().clear();
556 ServerCompositionTargetProps::id_of_root_property().set_field(self, None);
557 }
558
559 fn get_props(&self, type_id: TypeId) -> Option<&dyn Any> {
560 self.props.find_props(type_id)
561 }
562
563 fn as_animated(self: Rc<Self>) -> Option<Rc<dyn IAnimatedServerObject>> {
564 Some(self)
565 }
566
567 fn as_any(&self) -> &dyn Any {
568 self
569 }
570
571 fn into_any_rc(self: Rc<Self>) -> Rc<dyn Any> {
572 self
573 }
574}