/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use std::fmt::Debug; use std::num::NonZeroU32; use std::sync::atomic::{AtomicUsize, Ordering}; use euclid::{Rect, Size2D}; use crate::{Error, Viewport, Viewports}; #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] #[cfg_attr(feature = "ipc", derive(Deserialize, Serialize))] pub struct ContextId(pub u64); #[cfg(feature = "ipc")] use serde::{Deserialize, Serialize}; pub trait GLTypes { type Device; type Context; type Bindings; } pub trait GLContexts { fn bindings(&mut self, device: &GL::Device, context_id: ContextId) -> Option<&GL::Bindings>; fn context(&mut self, device: &GL::Device, context_id: ContextId) -> Option<&mut GL::Context>; } impl GLTypes for () { type Bindings = (); type Device = (); type Context = (); } impl GLContexts<()> for () { fn context(&mut self, _: &(), _: ContextId) -> Option<&mut ()> { Some(self) } fn bindings(&mut self, _: &(), _: ContextId) -> Option<&()> { Some(self) } } pub trait LayerGrandManagerAPI { fn create_layer_manager(&self, factory: LayerManagerFactory) -> Result; fn clone_layer_grand_manager(&self) -> LayerGrandManager; } pub struct LayerGrandManager(Box>); impl Clone for LayerGrandManager { fn clone(&self) -> Self { self.0.clone_layer_grand_manager() } } impl Debug for LayerGrandManager { fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { "LayerGrandManager(...)".fmt(fmt) } } impl LayerGrandManager { pub fn new(grand_manager: GM) -> LayerGrandManager where GM: 'static + Send + LayerGrandManagerAPI, { LayerGrandManager(Box::new(grand_manager)) } pub fn create_layer_manager(&self, factory: F) -> Result where F: 'static + Send + FnOnce(&mut GL::Device, &mut dyn GLContexts) -> Result, M: 'static + LayerManagerAPI, { self.0 .create_layer_manager(LayerManagerFactory::new(factory)) } } pub trait LayerManagerAPI { fn create_layer( &mut self, device: &mut GL::Device, contexts: &mut dyn GLContexts, context_id: ContextId, init: LayerInit, ) -> Result; fn destroy_layer( &mut self, device: &mut GL::Device, contexts: &mut dyn GLContexts, context_id: ContextId, layer_id: LayerId, ); fn layers(&self) -> &[(ContextId, LayerId)]; fn begin_frame( &mut self, device: &mut GL::Device, contexts: &mut dyn GLContexts, layers: &[(ContextId, LayerId)], ) -> Result, Error>; fn end_frame( &mut self, device: &mut GL::Device, contexts: &mut dyn GLContexts, layers: &[(ContextId, LayerId)], ) -> Result<(), Error>; } pub struct LayerManager(Box>); impl Debug for LayerManager { fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { "LayerManager(...)".fmt(fmt) } } impl LayerManager { pub fn create_layer( &mut self, context_id: ContextId, init: LayerInit, ) -> Result { self.0.create_layer(&mut (), &mut (), context_id, init) } pub fn destroy_layer(&mut self, context_id: ContextId, layer_id: LayerId) { self.0.destroy_layer(&mut (), &mut (), context_id, layer_id); } pub fn begin_frame( &mut self, layers: &[(ContextId, LayerId)], ) -> Result, Error> { self.0.begin_frame(&mut (), &mut (), layers) } pub fn end_frame(&mut self, layers: &[(ContextId, LayerId)]) -> Result<(), Error> { self.0.end_frame(&mut (), &mut (), layers) } } impl LayerManager { pub fn new(manager: M) -> LayerManager where M: 'static + Send + LayerManagerAPI<()>, { LayerManager(Box::new(manager)) } } impl Drop for LayerManager { fn drop(&mut self) { log::debug!("Dropping LayerManager"); let layers: Vec<_> = self.0.layers().to_vec(); for (context_id, layer_id) in layers.into_iter() { self.destroy_layer(context_id, layer_id); } } } #[allow(clippy::type_complexity)] pub struct LayerManagerFactory( Box< dyn Send + FnOnce( &mut GL::Device, &mut dyn GLContexts, ) -> Result>, Error>, >, ); impl Debug for LayerManagerFactory { fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { "LayerManagerFactory(...)".fmt(fmt) } } impl LayerManagerFactory { pub fn new(factory: F) -> LayerManagerFactory where F: 'static + Send + FnOnce(&mut GL::Device, &mut dyn GLContexts) -> Result, M: 'static + LayerManagerAPI, { LayerManagerFactory(Box::new(move |device, contexts| { Ok(Box::new(factory(device, contexts)?)) })) } pub fn build( self, device: &mut GL::Device, contexts: &mut dyn GLContexts, ) -> Result>, Error> { (self.0)(device, contexts) } } #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] #[cfg_attr(feature = "ipc", derive(Deserialize, Serialize))] pub struct LayerId(usize); static NEXT_LAYER_ID: AtomicUsize = AtomicUsize::new(0); impl Default for LayerId { fn default() -> Self { LayerId(NEXT_LAYER_ID.fetch_add(1, Ordering::SeqCst)) } } #[derive(Clone, Copy, Debug)] #[cfg_attr(feature = "ipc", derive(Deserialize, Serialize))] pub enum LayerInit { /// WebGLLayer { antialias: bool, depth: bool, stencil: bool, alpha: bool, ignore_depth_values: bool, framebuffer_scale_factor: f32, }, /// ProjectionLayer { depth: bool, stencil: bool, alpha: bool, scale_factor: f32, }, // TODO: other layer types } impl LayerInit { pub fn texture_size(&self, viewports: &Viewports) -> Size2D { match self { LayerInit::WebGLLayer { framebuffer_scale_factor: scale, .. } | LayerInit::ProjectionLayer { scale_factor: scale, .. } => { let native_size = viewports .viewports .iter() .fold(Rect::zero(), |acc, view| acc.union(view)) .size; (native_size.to_f32() * *scale).to_i32() }, } } } /// #[derive(Clone, Copy, Debug)] #[cfg_attr(feature = "ipc", derive(Deserialize, Serialize))] pub enum LayerLayout { // TODO: Default // Allocates one texture Mono, // Allocates one texture, which is split in half vertically, giving two subimages StereoLeftRight, // Allocates one texture, which is split in half horizonally, giving two subimages StereoTopBottom, } #[derive(Clone, Debug)] #[cfg_attr(feature = "ipc", derive(Deserialize, Serialize))] pub struct SubImages { pub layer_id: LayerId, pub sub_image: Option, pub view_sub_images: Vec, } /// #[derive(Clone, Debug)] #[cfg_attr(feature = "ipc", derive(Deserialize, Serialize))] pub struct SubImage { pub color_texture: Option, pub depth_stencil_texture: Option, pub texture_array_index: Option, pub viewport: Rect, }