ferroui_base/rendering/composition/server/
server_composition_drawing_surface.rs1use super::{IServerCompositionSurface, IServerObject, ServerCompositor, ServerCompositionSurfaceChanged};
2use crate::platform::{IBitmapImpl, IPlatformRenderInterfaceContext, PlatformGraphicsContextLostException};
3use crate::rendering::composition::{IServerGpuImportedObject, ServerImportedGpuImage, ServerImportedGpuSemaphore};
4use crate::utilities::{RefCountable, RefCounted};
5use std::any::Any;
6use std::cell::{Cell, RefCell};
7use std::sync::Arc;
8use std::rc::{Rc, Weak};
9
10#[derive(Clone, Debug)]
12pub struct DrawingSurfaceUpdateError(&'static str);
13
14impl std::fmt::Display for DrawingSurfaceUpdateError {
15 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
16 f.write_str(self.0)
17 }
18}
19
20impl std::error::Error for DrawingSurfaceUpdateError {}
21
22type UpdateResult = Result<(), crate::rendering::composition::ServerJobError>;
23
24fn context_lost() -> crate::rendering::composition::ServerJobError {
25 Arc::new(PlatformGraphicsContextLostException)
26}
27
28pub struct ServerCompositionDrawingSurface {
32 compositor: Weak<ServerCompositor>,
33 bitmap: RefCell<Option<RefCounted<crate::platform::SharedBitmapImpl>>>,
34 created_with_context: RefCell<Option<Rc<dyn IPlatformRenderInterfaceContext>>>,
35 disposed: Cell<bool>,
36 changed: ServerCompositionSurfaceChanged,
37}
38
39impl ServerCompositionDrawingSurface {
40 pub fn new(compositor: &Rc<ServerCompositor>) -> Rc<ServerCompositionDrawingSurface> {
41 Rc::new(ServerCompositionDrawingSurface {
42 compositor: Rc::downgrade(compositor),
43 bitmap: RefCell::new(None),
44 created_with_context: RefCell::new(None),
45 disposed: Cell::new(false),
46 changed: ServerCompositionSurfaceChanged::new(),
47 })
48 }
49
50 fn compositor(&self) -> Rc<ServerCompositor> {
51 self.compositor.upgrade().expect("the compositor of a server object is alive while the object is used")
52 }
53
54 fn current_context(&self) -> Rc<dyn IPlatformRenderInterfaceContext> {
55 self.compositor().render_interface().value()
56 }
57
58 pub fn bitmap_ref(&self) -> Option<RefCounted<crate::platform::SharedBitmapImpl>> {
60 let current = self.current_context();
62 let same = self
63 .created_with_context
64 .borrow()
65 .as_ref()
66 .is_some_and(|context| std::ptr::addr_eq(Rc::as_ptr(context), Rc::as_ptr(¤t)));
67 if !same {
68 return None;
69 }
70 self.bitmap.borrow().as_ref().map(|bitmap| bitmap.clone_ref())
71 }
72
73 fn perform_sanity_checks(&self, image: &ServerImportedGpuImage) -> UpdateResult {
74 if !image.is_usable(&self.compositor()) {
76 return Err(context_lost());
77 }
78
79 match image.base().import_result() {
80 None => Err(std::sync::Arc::new(DrawingSurfaceUpdateError("The import operation is not completed yet"))),
82 Some(Err(error)) => Err(error),
84 Some(Ok(())) => Ok(()),
85 }
86 }
87
88 fn update(&self, new_image: std::sync::Arc<crate::platform::SharedBitmapImpl>, context: Rc<dyn IPlatformRenderInterfaceContext>) {
89 if self.disposed.get() {
90 new_image.dispose();
95 return;
96 }
97 if let Some(bitmap) = self.bitmap.borrow_mut().take() {
98 bitmap.dispose();
99 }
100 let item = new_image.clone();
101 *self.bitmap.borrow_mut() = Some(RefCountable::create(new_image, move || item.dispose()));
102 *self.created_with_context.borrow_mut() = Some(context);
103 self.changed.invoke();
104 }
105
106 fn with_current_context(&self, f: impl FnOnce() -> UpdateResult) -> UpdateResult {
108 let current = self.compositor().render_interface().ensure_current();
109 let result = f();
110 current.dispose();
111 result
112 }
113
114 pub fn update_with_automatic_sync(&self, image: &ServerImportedGpuImage) -> UpdateResult {
115 self.with_current_context(|| {
116 self.perform_sanity_checks(image)?;
117 self.update(image.image().snapshot_with_automatic_sync(), image.context().clone());
118 Ok(())
119 })
120 }
121
122 pub fn update_with_keyed_mutex(
123 &self,
124 image: &ServerImportedGpuImage,
125 acquire_index: u32,
126 release_index: u32,
127 ) -> UpdateResult {
128 self.with_current_context(|| {
129 self.perform_sanity_checks(image)?;
130 self.update(image.image().snapshot_with_keyed_mutex(acquire_index, release_index), image.context().clone());
131 Ok(())
132 })
133 }
134
135 pub fn update_with_semaphores(
136 &self,
137 image: &ServerImportedGpuImage,
138 wait: &ServerImportedGpuSemaphore,
139 signal: &ServerImportedGpuSemaphore,
140 ) -> UpdateResult {
141 self.with_current_context(|| {
142 self.perform_sanity_checks(image)?;
143 let compositor = self.compositor();
144 if !wait.is_usable(&compositor) || !signal.is_usable(&compositor) {
145 return Err(context_lost());
146 }
147 self.update(
148 image.image().snapshot_with_semaphores(&wait.semaphore(), &signal.semaphore()),
149 image.context().clone(),
150 );
151 Ok(())
152 })
153 }
154
155 pub fn update_with_timeline_semaphores(
156 &self,
157 image: &ServerImportedGpuImage,
158 wait: &ServerImportedGpuSemaphore,
159 wait_for_value: u64,
160 signal: &ServerImportedGpuSemaphore,
161 signal_value: u64,
162 ) -> UpdateResult {
163 self.with_current_context(|| {
164 self.perform_sanity_checks(image)?;
165 let compositor = self.compositor();
166 if !wait.is_usable(&compositor) || !signal.is_usable(&compositor) {
167 return Err(context_lost());
168 }
169 self.update(
170 image.image().snapshot_with_timeline_semaphores(
171 &wait.semaphore(),
172 wait_for_value,
173 &signal.semaphore(),
174 signal_value,
175 ),
176 image.context().clone(),
177 );
178 Ok(())
179 })
180 }
181}
182
183impl IServerObject for ServerCompositionDrawingSurface {
184 fn dispose(&self) {
185 if let Some(bitmap) = self.bitmap.borrow_mut().take() {
186 bitmap.dispose();
187 }
188 self.disposed.set(true);
189 }
190
191 fn as_surface(self: Rc<Self>) -> Option<Rc<dyn IServerCompositionSurface>> {
192 Some(self)
193 }
194
195 fn as_any(&self) -> &dyn Any {
196 self
197 }
198
199 fn into_any_rc(self: Rc<Self>) -> Rc<dyn Any> {
200 self
201 }
202}
203
204impl IServerCompositionSurface for ServerCompositionDrawingSurface {
205 fn bitmap(&self) -> Option<std::sync::Arc<crate::platform::SharedBitmapImpl>> {
206 self.bitmap_ref().map(|bitmap| bitmap.item())
207 }
208
209 fn changed(&self) -> &ServerCompositionSurfaceChanged {
210 &self.changed
211 }
212}