ferroui_base/rendering/composition/server/
server_composition_target.rs1use 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}
57
58impl ServerCompositionTarget {
59 pub(crate) fn is_disposed(&self) -> bool {
62 self.disposed.get()
63 }
64
65 pub fn new(compositor: &Rc<ServerCompositor>, surfaces: RenderSurfaces, id: i64) -> Rc<ServerCompositionTarget> {
68 let mut dirty_rects: Option<Rc<dyn IDirtyRectTracker>> = None;
69 compositor.render_interface().with_platform_render_interface(|platform_render| {
72 if platform_render.supports_regions() && compositor.options().use_region_dirty_rect_clipping == Some(true) {
73 let max_rects = compositor.options().max_dirty_rects.unwrap_or(8);
74 dirty_rects = Some(if max_rects <= 0 {
75 Rc::new(RegionDirtyRectTracker::new(platform_render))
76 } else {
77 Rc::new(MultiDirtyRectTracker::new(
78 platform_render,
79 max_rects,
80 compositor.options().dirty_rect_merge_eagerness.unwrap_or(1000.0),
82 ))
83 });
84 }
85 });
86 let dirty_rects = dirty_rects.unwrap_or_else(|| Rc::new(SingleDirtyRectTracker::new()));
87
88 Rc::new_cyclic(|this: &Weak<ServerCompositionTarget>| {
89 let owner: Weak<dyn IAnimatedServerObject> = this.clone();
90 ServerCompositionTarget {
91 this: this.clone(),
92 object: ServerObject::new(compositor, owner),
93 compositor: Rc::downgrade(compositor),
94 props: ServerCompositionTargetProps::new(),
95 surfaces,
96 overlays: CompositionTargetOverlays::new(compositor),
97 render_target: RefCell::new(None),
98 layer_size: Cell::new(PixelSize::default()),
99 layer: RefCell::new(None),
100 update_requested: Cell::new(false),
101 redraw_requested: Cell::new(false),
102 full_redraw_requested: Cell::new(false),
103 disposed: Cell::new(false),
104 attached_visuals: RefCell::new(HashMap::new()),
105 dirty_rects,
106 id,
107 debug_events: RefCell::new(None),
108 rendered_visuals: Cell::new(0),
109 visited_visuals: Cell::new(0),
110 is_waiting_for_ready_render_target: Cell::new(false),
111 is_waiting_for_render_loop_wakeup: Cell::new(false),
112 }
113 })
114 }
115
116 pub fn compositor(&self) -> Option<Rc<ServerCompositor>> {
117 self.compositor.upgrade()
118 }
119
120 pub fn dirty_rects(&self) -> &Rc<dyn IDirtyRectTracker> {
121 &self.dirty_rects
122 }
123
124 pub fn id(&self) -> i64 {
125 self.id
126 }
127
128 pub fn debug_events(&self) -> Option<Arc<dyn ICompositionTargetDebugEvents>> {
129 self.debug_events.borrow().clone()
130 }
131
132 pub fn set_debug_events(&self, value: Option<Arc<dyn ICompositionTargetDebugEvents>>) {
133 *self.debug_events.borrow_mut() = value;
134 }
135
136 pub fn rendered_visuals(&self) -> i32 {
137 self.rendered_visuals.get()
138 }
139
140 pub fn visited_visuals(&self) -> i32 {
141 self.visited_visuals.get()
142 }
143
144 pub fn pixel_size(&self) -> PixelSize {
145 PixelSize::from_size_ceiling(self.size(), self.scaling())
146 }
147
148 pub fn is_waiting_for_ready_render_target(&self) -> bool {
151 self.is_waiting_for_ready_render_target.get()
152 }
153
154 pub fn is_waiting_for_render_loop_wakeup(&self) -> bool {
158 self.is_waiting_for_render_loop_wakeup.get()
159 }
160
161 pub fn root(&self) -> Option<Rc<ServerCompositionVisual>> {
164 self.props.root().and_then(|o| o.into_any_rc().downcast::<ServerCompositionVisual>().ok())
165 }
166
167 pub fn is_enabled(&self) -> bool {
168 self.props.is_enabled()
169 }
170
171 pub fn debug_overlays(&self) -> RendererDebugOverlays {
172 self.props.debug_overlays()
173 }
174
175 pub fn last_layout_pass_timing(&self) -> LayoutPassTiming {
176 self.props.last_layout_pass_timing()
177 }
178
179 pub fn scaling(&self) -> f64 {
180 self.props.scaling()
181 }
182
183 pub fn size(&self) -> Size {
184 self.props.size()
185 }
186
187 pub fn transparency_level(&self) -> CompositionTransparencyLevel {
188 self.props.transparency_level()
189 }
190
191 pub fn platform_specific_scene_info(&self) -> Option<std::sync::Arc<dyn Any + Send + Sync>> {
192 self.props.platform_specific_scene_info()
193 }
194
195 pub fn update(self: &Rc<Self>, diagnostics_compositor_global_update_elapsed_time: Duration) {
198 let Some(compositor) = self.compositor() else { return };
199 if self.disposed.get() {
200 compositor.remove_composition_target(self);
201 return;
202 }
203
204 let Some(root) = self.root() else { return };
205
206 self.overlays.record_global_compositor_update_time(self, diagnostics_compositor_global_update_elapsed_time);
207 self.overlays.mark_update_call_start(self);
208
209 let scaling = self.scaling();
210 let transform = Matrix::create_scale(scaling, scaling);
211 let tracker: Rc<dyn IDirtyRectCollector> = self.dirty_rects.clone();
212 let collector: Rc<dyn IDirtyRectCollector> = match self.debug_events() {
213 Some(events) => Rc::new(DebugEventsDirtyRectCollectorProxy::new(tracker, events)),
214 None => tracker,
215 };
216 let pixel_size = self.pixel_size();
217 root.update_root(
218 collector,
219 transform,
220 LtrbRect::new(0.0, 0.0, pixel_size.width as f64, pixel_size.height as f64),
221 );
222 self.update_requested.set(false);
223 self.overlays.mark_update_call_end(self);
224 }
225
226 pub fn render(self: &Rc<Self>) {
227 self.is_waiting_for_ready_render_target.set(false);
228 self.is_waiting_for_render_loop_wakeup.set(false);
229
230 if self.disposed.get() {
231 return;
232 }
233
234 let Some(root) = self.root() else { return };
235 let Some(compositor) = self.compositor() else { return };
236
237 let corrupted = self.render_target.borrow().as_ref().is_some_and(|t| t.platform_render_target_state().is_corrupted);
238 if corrupted {
239 if let Some(layer) = self.layer.borrow_mut().take() {
240 layer.dispose();
241 }
242 if let Some(render_target) = self.render_target.borrow_mut().take() {
243 render_target.dispose();
244 }
245 self.redraw_requested.set(true);
246 }
247
248 if self.render_target.borrow().is_none() {
249 let surfaces = (self.surfaces)();
250 if !compositor.is_ready_to_create_render_target(&surfaces) {
251 self.is_waiting_for_ready_render_target.set(self.is_enabled());
252 return;
253 }
254 let render_target = compositor.create_render_target(&surfaces);
255 *self.render_target.borrow_mut() = Some(render_target);
256 }
257 let Some(render_target) = self.render_target.borrow().clone() else { return };
258
259 if self.dirty_rects.is_empty() && !self.redraw_requested.get() && !self.update_requested.get() {
260 return;
261 }
262
263 self.redraw_requested.set(self.redraw_requested.get() | !self.dirty_rects.is_empty());
264
265 if !self.redraw_requested.get() {
266 return;
267 }
268
269 let state = render_target.platform_render_target_state();
270 if !state.is_ready {
271 self.is_waiting_for_ready_render_target.set(self.is_enabled());
272 self.is_waiting_for_render_loop_wakeup
273 .set(self.is_enabled() && state.will_wake_up_render_loop_when_ready);
274 return;
275 }
276
277 let properties = render_target.properties();
278 let need_layer = self.overlays.require_layer() || !(properties.retains_previous_frame_contents && properties.is_suitable_for_direct_rendering);
281
282 let pixel_size = self.pixel_size();
283 let scene_info = RenderTargetSceneInfo {
284 size: pixel_size,
285 scaling: self.scaling(),
286 logical_size: self.size(),
287 transparency_level: self.transparency_level(),
288 platform_specific_scene_info: self.platform_specific_scene_info(),
289 };
290 let (mut render_target_context, properties) = match render_target.try_create_drawing_context(&scene_info) {
291 Ok(created) => created,
292 Err(RenderTargetError::NotReady(_)) => {
293 self.is_waiting_for_ready_render_target.set(self.is_enabled());
294 return;
295 }
296 Err(RenderTargetError::Corrupted(_)) => return,
297 };
298
299 {
300 let mut full_redraw = false;
301
302 let layer_is_stale = {
303 let layer = self.layer.borrow();
304 pixel_size != self.layer_size.get() || layer.as_ref().is_none_or(|layer| layer.is_corrupted())
305 };
306 if need_layer && layer_is_stale {
307 if let Some(layer) = self.layer.borrow_mut().take() {
308 layer.dispose();
309 }
310 *self.layer.borrow_mut() = Some(render_target_context.create_layer(pixel_size));
311 self.layer_size.set(pixel_size);
312 full_redraw = true;
313 } else if !need_layer {
314 if let Some(layer) = self.layer.borrow_mut().take() {
315 layer.dispose();
316 }
317 }
318
319 if self.full_redraw_requested.get() || (!need_layer && !properties.previous_frame_is_retained) {
320 self.full_redraw_requested.set(false);
321 full_redraw = true;
322 }
323
324 let render_bounds = LtrbRect::new(0.0, 0.0, pixel_size.width as f64, pixel_size.height as f64);
325
326 if full_redraw {
327 self.dirty_rects.initialize(render_bounds);
328 self.dirty_rects.add_rect(render_bounds);
329 }
330
331 if !self.dirty_rects.is_empty() {
332 self.dirty_rects.finalize_frame(render_bounds);
333 let layer = self.layer.borrow().clone();
334 match layer {
335 Some(layer) => {
336 {
337 let mut context = layer.create_drawing_context();
338 self.render_root_to_context_with_clip(&compositor, &mut *context, &root);
339 context.dispose();
340 }
341
342 render_target_context.clear(Colors::TRANSPARENT);
343 render_target_context.set_transform(Matrix::IDENTITY);
344 if layer.can_blit() {
345 layer.blit(&mut *render_target_context);
346 } else {
347 let rect = PixelRect::from_size(pixel_size).to_rect(1.0);
348 render_target_context.draw_bitmap(&*layer, 1.0, rect, rect);
349 }
350 self.overlays.draw(self, &mut *render_target_context, true);
351 }
352 None => {
353 self.render_root_to_context_with_clip(&compositor, &mut *render_target_context, &root);
354 self.overlays.draw(self, &mut *render_target_context, false);
355 }
356 }
357 }
358
359 self.rendered_visuals.set(0);
360 self.visited_visuals.set(0);
361
362 self.redraw_requested.set(false);
363 self.dirty_rects.initialize(render_bounds);
364 }
365 render_target_context.dispose();
366 }
367
368 fn render_root_to_context_with_clip(
369 &self,
370 compositor: &ServerCompositor,
371 context: &mut dyn IDrawingContextImpl,
372 root: &Rc<ServerCompositionVisual>,
373 ) {
374 let use_layer_clip = compositor.options().use_save_layer_root_clip.unwrap_or(false);
375 self.dirty_rects.begin_draw(context);
376 {
377 context.clear(Colors::TRANSPARENT);
378 if use_layer_clip {
379 context.push_layer(self.dirty_rects.combined_rect().to_rect());
380 }
381 let scaling = self.scaling();
382 context.set_transform(Matrix::create_scale(scaling, scaling));
383 let pixel_size = self.pixel_size();
384 let (visited, rendered) = root.render(
385 context,
386 LtrbRect::new(0.0, 0.0, pixel_size.width as f64, pixel_size.height as f64),
387 Some(self.dirty_rects.clone()),
388 true,
389 false,
390 false,
391 );
392 self.visited_visuals.set(visited);
393 self.rendered_visuals.set(rendered);
394 if let Some(events) = self.debug_events() {
395 events.set_rendered_visuals(rendered);
396 events.set_visited_visuals(visited);
397 }
398
399 if use_layer_clip {
400 context.pop_layer();
401 }
402 }
403 self.dirty_rects.end_draw(context);
404 }
405
406 pub fn request_update(&self) {
407 self.update_requested.set(true);
408 }
409
410 pub fn reset_render_target(&self) {
411 if self.layer.borrow().is_none() && self.render_target.borrow().is_none() {
412 return;
413 }
414 let current = self.compositor().map(|compositor| compositor.render_interface().ensure_current());
415 self.release_render_target();
416 if let Some(current) = current {
417 current.dispose();
418 }
419 }
420
421 pub(crate) fn release_render_target(&self) {
426 if let Some(layer) = self.layer.borrow_mut().take() {
427 layer.dispose();
428 }
429 if let Some(render_target) = self.render_target.borrow_mut().take() {
430 render_target.dispose();
431 }
432 }
433
434 pub fn add_visual(&self, visual: &Rc<ServerCompositionVisual>) {
435 let added = self.attached_visuals.borrow_mut().insert(Rc::as_ptr(visual), visual.clone()).is_none();
436 if added && self.is_enabled() {
437 visual.activate();
438 }
439 }
440
441 pub fn remove_visual(&self, visual: &Rc<ServerCompositionVisual>) {
442 let removed = self.attached_visuals.borrow_mut().remove(&Rc::as_ptr(visual)).is_some();
443 if removed && self.is_enabled() {
444 visual.deactivate();
445 }
446 }
447
448 pub fn request_full_redraw(&self) {
449 self.redraw_requested.set(true);
450 }
451}
452
453impl ServerCompositionTargetHooks for ServerCompositionTarget {
454 fn deserialize_changes_extra(&self, _reader: &mut BatchStreamReader<'_>) {
455 self.redraw_requested.set(true);
456 self.full_redraw_requested.set(true);
457 }
458
459 fn on_fields_deserialized(&self, _changed: CompositionTargetChangedFields) {}
460
461 fn on_is_enabled_changed(&self) {
462 let (Some(compositor), Some(this)) = (self.compositor(), self.this.upgrade()) else { return };
463 let visuals: Vec<_> = self.attached_visuals.borrow().values().cloned().collect();
464 if self.is_enabled() {
465 compositor.add_composition_target(&this);
466 for visual in visuals {
467 visual.activate();
468 }
469 } else {
470 compositor.remove_composition_target(&this);
471 for visual in visuals {
472 visual.deactivate();
473 }
474 }
475 }
476
477 fn on_debug_overlays_changed(&self) {
478 self.full_redraw_requested.set(true);
479 self.overlays.on_changed(self.debug_overlays());
480 }
481
482 fn on_last_layout_pass_timing_changed(&self) {
483 self.overlays.on_last_layout_pass_timing_changed(self, self.last_layout_pass_timing());
484 }
485}
486
487impl_animated_server_object!(ServerCompositionTarget, object);
488
489impl IServerObject for ServerCompositionTarget {
490 fn deserialize_changes_core(&self, reader: &mut BatchStreamReader<'_>, committed_at: Duration) {
491 self.props.deserialize_changes_core(self, reader, committed_at);
492 }
493
494 fn dispose(&self) {
495 if self.disposed.replace(true) {
496 return;
497 }
498 self.reset_render_target();
499 if let (Some(compositor), Some(this)) = (self.compositor(), self.this.upgrade()) {
500 compositor.remove_composition_target(&this);
501 }
502 self.attached_visuals.borrow_mut().clear();
505 ServerCompositionTargetProps::id_of_root_property().set_field(self, None);
506 }
507
508 fn get_props(&self, type_id: TypeId) -> Option<&dyn Any> {
509 self.props.find_props(type_id)
510 }
511
512 fn as_animated(self: Rc<Self>) -> Option<Rc<dyn IAnimatedServerObject>> {
513 Some(self)
514 }
515
516 fn as_any(&self) -> &dyn Any {
517 self
518 }
519
520 fn into_any_rc(self: Rc<Self>) -> Rc<dyn Any> {
521 self
522 }
523}