1use super::server::{LockBound, LockedServerCompositor, ServerCompositor};
15use super::{
16 CompositionGpuImportedImageSynchronizationCapabilities, Compositor, ICompositionGpuImportedObject,
17 ICompositionGpuInterop, ICompositionImportableSharedGpuContextImage, ICompositionImportableSharedGpuContextSemaphore,
18 ICompositionImportedGpuImage, ICompositionImportedGpuSemaphore, ServerJobError, ServerJobTask,
19};
20use crate::platform::{
21 IExternalObjectsHandleWrapRenderInterfaceContextFeature, IExternalObjectsRenderInterfaceContextFeature,
22 IExternalObjectsWrappedGpuHandle, IPlatformHandle, IPlatformRenderInterfaceContext,
23 IPlatformRenderInterfaceImportedImage, IPlatformRenderInterfaceImportedSemaphore, PlatformGraphicsContextLostException,
24 PlatformGraphicsDrmFormat, PlatformGraphicsExternalImageProperties, PlatformHandle,
25};
26use std::cell::RefCell;
27use std::rc::Rc;
28use std::sync::Arc;
29
30fn same_context(a: &Rc<dyn IPlatformRenderInterfaceContext>, b: &Rc<dyn IPlatformRenderInterfaceContext>) -> bool {
31 std::ptr::addr_eq(Rc::as_ptr(a), Rc::as_ptr(b))
32}
33
34struct InteropState {
38 context: Rc<dyn IPlatformRenderInterfaceContext>,
39 external_objects: Rc<dyn IExternalObjectsRenderInterfaceContextFeature>,
40 external_objects_with_handle_wrap: Option<Rc<dyn IExternalObjectsHandleWrapRenderInterfaceContextFeature>>,
41}
42
43impl InteropState {
44 fn imported_object_base(&self) -> ServerGpuImportedObjectBase {
45 ServerGpuImportedObjectBase {
46 context: self.context.clone(),
47 feature: self.external_objects.clone(),
48 import_result: RefCell::new(None),
49 }
50 }
51}
52
53pub(crate) struct CompositionInteropServerPart {
58 state: LockBound<InteropState>,
59 device_luid: Option<Vec<u8>>,
60 device_uuid: Option<Vec<u8>>,
61}
62
63pub struct CompositionInterop {
66 compositor: Rc<Compositor>,
67 state: LockBound<InteropState>,
68 device_luid: RefCell<Option<Vec<u8>>>,
69 device_uuid: RefCell<Option<Vec<u8>>>,
70}
71
72impl CompositionInterop {
73 pub fn new(
85 compositor: &Rc<Compositor>,
86 external_objects: Rc<dyn IExternalObjectsRenderInterfaceContextFeature>,
87 ) -> Rc<CompositionInterop> {
88 match Self::try_new(compositor, external_objects) {
89 Some(interop) => interop,
90 None => panic!("the context of the render interface is created by the render thread, which has none"),
91 }
92 }
93
94 pub(crate) fn try_new(
102 compositor: &Rc<Compositor>,
103 external_objects: Rc<dyn IExternalObjectsRenderInterfaceContextFeature>,
104 ) -> Option<Rc<CompositionInterop>> {
105 let locked = compositor.locked_server();
106 let may_create_context = !compositor.is_confined_to_render_thread();
107 let part =
108 compositor.with_server(|server| Self::server_part(&locked, server, external_objects, may_create_context))?;
109 Some(Self::from_server_part(compositor, part))
110 }
111
112 pub(crate) fn server_part(
123 locked: &Arc<LockedServerCompositor>,
124 server: &ServerCompositor,
125 external_objects: Rc<dyn IExternalObjectsRenderInterfaceContextFeature>,
126 may_create_context: bool,
127 ) -> Option<CompositionInteropServerPart> {
128 let context = if may_create_context {
129 server.render_interface().value()
130 } else {
131 server.render_interface().existing_backend_context()?
132 };
133 let external_objects_with_handle_wrap = {
134 let features: &dyn crate::platform::IOptionalFeatureProvider = &*context;
135 features.try_get::<dyn IExternalObjectsHandleWrapRenderInterfaceContextFeature>()
136 };
137 Some(CompositionInteropServerPart {
138 device_luid: external_objects.device_luid(),
139 device_uuid: external_objects.device_uuid(),
140 state: LockBound::new(
141 locked,
142 server,
143 InteropState { context, external_objects, external_objects_with_handle_wrap },
144 ),
145 })
146 }
147
148 pub(crate) fn from_server_part(compositor: &Rc<Compositor>, part: CompositionInteropServerPart) -> Rc<Self> {
150 Rc::new(CompositionInterop {
151 compositor: compositor.clone(),
152 device_luid: RefCell::new(part.device_luid),
153 device_uuid: RefCell::new(part.device_uuid),
154 state: part.state,
155 })
156 }
157
158 fn with_state<R>(&self, f: impl FnOnce(&ServerCompositor, &InteropState) -> R) -> R {
161 self.compositor.with_server(|server| {
162 let server: &ServerCompositor = server;
163 f(server, self.state.get(server))
164 })
165 }
166}
167
168impl ICompositionGpuInterop for CompositionInterop {
169 fn supported_image_handle_types(&self) -> Vec<String> {
170 self.with_state(|_, state| state.external_objects.supported_image_handle_types())
171 }
172
173 fn supported_semaphore_types(&self) -> Vec<String> {
174 self.with_state(|_, state| state.external_objects.supported_semaphore_types())
175 }
176
177 fn supported_dma_buf_formats(&self) -> Option<Vec<PlatformGraphicsDrmFormat>> {
178 self.with_state(|_, state| state.external_objects.supported_dma_buf_formats())
179 }
180
181 fn get_synchronization_capabilities(&self, image_handle_type: &str) -> CompositionGpuImportedImageSynchronizationCapabilities {
182 self.with_state(|_, state| state.external_objects.get_synchronization_capabilities(image_handle_type))
183 }
184
185 fn import_image(
186 &self,
187 handle: Rc<dyn IPlatformHandle>,
188 properties: PlatformGraphicsExternalImageProperties,
189 ) -> Rc<dyn ICompositionImportedGpuImage> {
190 let server = self.with_state(|server, state| {
191 let wrapped = state
192 .external_objects_with_handle_wrap
193 .as_ref()
194 .and_then(|wrap| wrap.wrap_image_handle_on_any_thread(&handle, properties.clone()));
195 let source = ImageSource::Handle(ImportHandle::new(wrapped, &*handle), properties);
196 Arc::new(self.compositor.bind_to_lock(server, ServerImportedGpuImage::new(state, source)))
197 });
198 CompositionImportedGpuImage::new(&self.compositor, server)
199 }
200
201 fn import_shared_image(&self, image: Arc<dyn ICompositionImportableSharedGpuContextImage>) -> Rc<dyn ICompositionImportedGpuImage> {
202 let source = ImageSource::Shared(image);
205 let server = self.with_state(|server, state| {
206 Arc::new(self.compositor.bind_to_lock(server, ServerImportedGpuImage::new(state, source)))
207 });
208 CompositionImportedGpuImage::new(&self.compositor, server)
209 }
210
211 fn import_semaphore(&self, handle: Rc<dyn IPlatformHandle>) -> Rc<dyn ICompositionImportedGpuSemaphore> {
212 let server = self.with_state(|server, state| {
213 let wrapped = state
214 .external_objects_with_handle_wrap
215 .as_ref()
216 .and_then(|wrap| wrap.wrap_semaphore_handle_on_any_thread(&handle));
217 let handle = ImportHandle::new(wrapped, &*handle);
218 Arc::new(self.compositor.bind_to_lock(server, ServerImportedGpuSemaphore::new(state, handle)))
219 });
220 CompositionImportedGpuSemaphore::new(&self.compositor, server)
221 }
222
223 fn import_shared_semaphore(
225 &self,
226 _image: Rc<dyn ICompositionImportableSharedGpuContextSemaphore>,
227 ) -> Rc<dyn ICompositionImportedGpuImage> {
228 panic!("Specified method is not supported.");
229 }
230
231 fn is_lost(&self) -> bool {
232 self.with_state(|_, state| state.context.is_lost())
233 }
234
235 fn device_luid(&self) -> Option<Vec<u8>> {
236 self.device_luid.borrow().clone()
237 }
238
239 fn set_device_luid(&self, value: Option<Vec<u8>>) {
240 *self.device_luid.borrow_mut() = value;
241 }
242
243 fn device_uuid(&self) -> Option<Vec<u8>> {
244 self.device_uuid.borrow().clone()
245 }
246
247 fn set_device_uuid(&self, value: Option<Vec<u8>>) {
248 *self.device_uuid.borrow_mut() = value;
249 }
250}
251
252enum ImportHandle {
254 Wrapped(Rc<dyn IExternalObjectsWrappedGpuHandle>),
258 Copied(PlatformHandle),
263}
264
265impl ImportHandle {
266 fn new(wrapped: Option<Rc<dyn IExternalObjectsWrappedGpuHandle>>, handle: &dyn IPlatformHandle) -> ImportHandle {
267 match wrapped {
268 Some(wrapped) => ImportHandle::Wrapped(wrapped),
269 None => ImportHandle::Copied(PlatformHandle::new(handle.handle(), handle.handle_descriptor())),
270 }
271 }
272
273 fn platform_handle(&self) -> Rc<dyn IPlatformHandle> {
274 match self {
275 ImportHandle::Wrapped(wrapped) => wrapped.clone().as_platform_handle(),
276 ImportHandle::Copied(handle) => Rc::new(handle.clone()),
277 }
278 }
279
280 fn dispose(self) {
282 if let ImportHandle::Wrapped(wrapped) = self {
283 wrapped.dispose();
284 }
285 }
286}
287
288enum ImageSource {
290 Handle(ImportHandle, PlatformGraphicsExternalImageProperties),
291 Shared(Arc<dyn ICompositionImportableSharedGpuContextImage>),
296}
297
298impl ImageSource {
299 fn import(
300 &self,
301 feature: &dyn IExternalObjectsRenderInterfaceContextFeature,
302 ) -> Result<Rc<dyn IPlatformRenderInterfaceImportedImage>, ServerJobError> {
303 match self {
304 ImageSource::Handle(handle, properties) => Ok(feature.import_image(handle.platform_handle(), properties.clone())),
305 ImageSource::Shared(image) => Ok(feature.import_shared_image(image.clone())),
306 }
307 }
308
309 fn dispose(self) {
310 if let ImageSource::Handle(handle, _) = self {
311 handle.dispose();
312 }
313 }
314}
315
316pub struct ServerGpuImportedObjectBase {
319 context: Rc<dyn IPlatformRenderInterfaceContext>,
320 feature: Rc<dyn IExternalObjectsRenderInterfaceContextFeature>,
321 import_result: RefCell<Option<Result<(), ServerJobError>>>,
324}
325
326impl ServerGpuImportedObjectBase {
327 pub fn context(&self) -> &Rc<dyn IPlatformRenderInterfaceContext> {
328 &self.context
329 }
330
331 pub fn feature(&self) -> &Rc<dyn IExternalObjectsRenderInterfaceContextFeature> {
332 &self.feature
333 }
334
335 pub fn import_result(&self) -> Option<Result<(), ServerJobError>> {
337 self.import_result.borrow().clone()
338 }
339
340 fn is_current_context(&self, server: &ServerCompositor) -> bool {
343 same_context(&server.render_interface().value(), &self.context)
344 }
345}
346
347pub trait IServerGpuImportedObject: 'static {
350 fn base(&self) -> &ServerGpuImportedObjectBase;
351
352 fn import(&self, server: &ServerCompositor) -> Result<(), ServerJobError>;
354
355 fn dispose(&self);
357}
358
359pub struct CompositionGpuImportedObjectBase<T: IServerGpuImportedObject> {
363 compositor: Rc<Compositor>,
364 server: Arc<LockBound<T>>,
365 import_completed: ServerJobTask<()>,
366}
367
368impl<T: IServerGpuImportedObject> CompositionGpuImportedObjectBase<T> {
369 fn new(compositor: &Rc<Compositor>, server: Arc<LockBound<T>>) -> Self {
371 let object = server.clone();
372 let import_completed = compositor.invoke_server_job_async(
373 move |compositor| {
374 let object = object.get(compositor);
375 let result = object.import(compositor);
376 *object.base().import_result.borrow_mut() = Some(result.clone());
377 result
378 },
379 false,
380 );
381 Self { compositor: compositor.clone(), server, import_completed }
382 }
383
384 pub fn compositor(&self) -> &Rc<Compositor> {
385 &self.compositor
386 }
387
388 pub(crate) fn server(&self) -> Arc<LockBound<T>> {
390 self.server.clone()
391 }
392
393 pub fn import_completed(&self) -> ServerJobTask<()> {
394 self.import_completed.clone()
395 }
396
397 pub fn is_lost(&self) -> bool {
400 self.compositor.with_server(|server| self.server.get(server).base().context.is_lost())
401 }
402
403 fn dispose_async(&self) -> ServerJobTask<()> {
404 let object = self.server.clone();
408 self.compositor.invoke_server_job_async(
409 move |compositor| {
410 let object = object.get(compositor);
411 if matches!(object.base().import_result(), Some(Ok(()))) {
412 object.dispose();
413 }
414 Ok(())
415 },
416 false,
417 )
418 }
419}
420
421pub struct ServerImportedGpuImage {
423 base: ServerGpuImportedObjectBase,
424 source: RefCell<Option<ImageSource>>,
425 image: RefCell<Option<Rc<dyn IPlatformRenderInterfaceImportedImage>>>,
426}
427
428impl ServerImportedGpuImage {
429 fn new(state: &InteropState, source: ImageSource) -> ServerImportedGpuImage {
430 ServerImportedGpuImage {
431 base: state.imported_object_base(),
432 source: RefCell::new(Some(source)),
433 image: RefCell::new(None),
434 }
435 }
436
437 pub fn image(&self) -> Rc<dyn IPlatformRenderInterfaceImportedImage> {
440 match self.image.borrow().clone() {
441 Some(image) => image,
442 None => panic!("Cannot access a disposed object.\nObject name: 'CompositionImportedGpuImage'."),
443 }
444 }
445
446 pub fn context(&self) -> &Rc<dyn IPlatformRenderInterfaceContext> {
447 &self.base.context
448 }
449
450 pub fn is_usable(&self, server: &ServerCompositor) -> bool {
451 self.image.borrow().is_some() && self.base.is_current_context(server)
452 }
453}
454
455impl IServerGpuImportedObject for ServerImportedGpuImage {
456 fn base(&self) -> &ServerGpuImportedObjectBase {
457 &self.base
458 }
459
460 fn import(&self, server: &ServerCompositor) -> Result<(), ServerJobError> {
461 let source = self.source.borrow_mut().take();
462 let current = server.render_interface().ensure_current();
463 let result = (|| {
464 if !self.base.is_current_context(server) {
466 return Err(Arc::new(PlatformGraphicsContextLostException) as ServerJobError);
467 }
468 if let Some(source) = &source {
469 *self.image.borrow_mut() = Some(source.import(&*self.base.feature)?);
470 }
471 Ok(())
472 })();
473 current.dispose();
474 if let Some(source) = source {
476 source.dispose();
477 }
478 result
479 }
480
481 fn dispose(&self) {
482 if let Some(image) = self.image.borrow_mut().take() {
483 image.dispose();
484 }
485 }
486}
487
488pub struct CompositionImportedGpuImage {
490 base: CompositionGpuImportedObjectBase<ServerImportedGpuImage>,
491}
492
493impl CompositionImportedGpuImage {
494 fn new(compositor: &Rc<Compositor>, server: Arc<LockBound<ServerImportedGpuImage>>) -> Rc<CompositionImportedGpuImage> {
495 Rc::new(CompositionImportedGpuImage { base: CompositionGpuImportedObjectBase::new(compositor, server) })
496 }
497
498 pub fn base(&self) -> &CompositionGpuImportedObjectBase<ServerImportedGpuImage> {
499 &self.base
500 }
501
502 pub(crate) fn server(&self) -> Arc<LockBound<ServerImportedGpuImage>> {
504 self.base.server()
505 }
506}
507
508impl ICompositionGpuImportedObject for CompositionImportedGpuImage {
509 fn import_completed(&self) -> ServerJobTask<()> {
510 self.base.import_completed()
511 }
512
513 fn is_lost(&self) -> bool {
514 self.base.is_lost()
515 }
516
517 fn dispose_async(&self) -> ServerJobTask<()> {
518 self.base.dispose_async()
519 }
520}
521
522impl ICompositionImportedGpuImage for CompositionImportedGpuImage {
523 fn as_imported_gpu_image(&self) -> Option<&CompositionImportedGpuImage> {
524 Some(self)
525 }
526}
527
528pub struct ServerImportedGpuSemaphore {
530 base: ServerGpuImportedObjectBase,
531 handle: RefCell<Option<ImportHandle>>,
532 semaphore: RefCell<Option<Rc<dyn IPlatformRenderInterfaceImportedSemaphore>>>,
533}
534
535impl ServerImportedGpuSemaphore {
536 fn new(state: &InteropState, handle: ImportHandle) -> ServerImportedGpuSemaphore {
537 ServerImportedGpuSemaphore {
538 base: state.imported_object_base(),
539 handle: RefCell::new(Some(handle)),
540 semaphore: RefCell::new(None),
541 }
542 }
543
544 pub fn semaphore(&self) -> Rc<dyn IPlatformRenderInterfaceImportedSemaphore> {
547 match self.semaphore.borrow().clone() {
548 Some(semaphore) => semaphore,
549 None => panic!("Cannot access a disposed object.\nObject name: 'CompositionImportedGpuSemaphore'."),
550 }
551 }
552
553 pub fn is_usable(&self, server: &ServerCompositor) -> bool {
554 self.semaphore.borrow().is_some() && self.base.is_current_context(server)
555 }
556}
557
558impl IServerGpuImportedObject for ServerImportedGpuSemaphore {
559 fn base(&self) -> &ServerGpuImportedObjectBase {
560 &self.base
561 }
562
563 fn import(&self, _server: &ServerCompositor) -> Result<(), ServerJobError> {
564 let handle = self.handle.borrow_mut().take();
565 if let Some(handle) = handle {
566 *self.semaphore.borrow_mut() = Some(self.base.feature.import_semaphore(handle.platform_handle()));
567 handle.dispose();
569 }
570 Ok(())
571 }
572
573 fn dispose(&self) {
574 if let Some(semaphore) = self.semaphore.borrow_mut().take() {
575 semaphore.dispose();
576 }
577 }
578}
579
580pub struct CompositionImportedGpuSemaphore {
582 base: CompositionGpuImportedObjectBase<ServerImportedGpuSemaphore>,
583}
584
585impl CompositionImportedGpuSemaphore {
586 fn new(
587 compositor: &Rc<Compositor>,
588 server: Arc<LockBound<ServerImportedGpuSemaphore>>,
589 ) -> Rc<CompositionImportedGpuSemaphore> {
590 Rc::new(CompositionImportedGpuSemaphore { base: CompositionGpuImportedObjectBase::new(compositor, server) })
591 }
592
593 pub fn base(&self) -> &CompositionGpuImportedObjectBase<ServerImportedGpuSemaphore> {
594 &self.base
595 }
596
597 pub(crate) fn server(&self) -> Arc<LockBound<ServerImportedGpuSemaphore>> {
599 self.base.server()
600 }
601}
602
603impl ICompositionGpuImportedObject for CompositionImportedGpuSemaphore {
604 fn import_completed(&self) -> ServerJobTask<()> {
605 self.base.import_completed()
606 }
607
608 fn is_lost(&self) -> bool {
609 self.base.is_lost()
610 }
611
612 fn dispose_async(&self) -> ServerJobTask<()> {
613 self.base.dispose_async()
614 }
615}
616
617impl ICompositionImportedGpuSemaphore for CompositionImportedGpuSemaphore {
618 fn as_imported_gpu_semaphore(&self) -> Option<&CompositionImportedGpuSemaphore> {
619 Some(self)
620 }
621}