diff --git a/src/angle/connection.rs b/src/angle/connection.rs index 2a7aa9e8..40c43741 100644 --- a/src/angle/connection.rs +++ b/src/angle/connection.rs @@ -8,7 +8,9 @@ use super::adapter::AngleAdapter; use super::device::{AngleDevice, NativeDevice, VendorPreference}; use crate::egl::types::EGLDisplay; -use crate::{Adapter, AdapterPreferences, Error, GLApi, PowerPreference, RenderingPreference}; +use crate::{ + Adapter, AdapterPreferences, Device, Error, GLApi, PowerPreference, RenderingPreference, +}; use winapi::shared::minwindef::UINT; use winapi::um::d3dcommon::{D3D_DRIVER_TYPE_UNKNOWN, D3D_DRIVER_TYPE_WARP}; @@ -76,8 +78,8 @@ impl AngleConnection { /// /// Device handles are local to a single thread. #[inline] - pub fn create_device(&self, adapter: &Adapter) -> Result { - AngleDevice::new(adapter.angle()?) + pub fn create_device(&self, adapter: &Adapter) -> Result { + AngleDevice::new(adapter.angle()?).map(Device::from) } /// Wraps a `NativeDevice` in a `Device` and returns it. diff --git a/src/angle/mod.rs b/src/angle/mod.rs index a1812608..f4af0dbf 100644 --- a/src/angle/mod.rs +++ b/src/angle/mod.rs @@ -6,12 +6,12 @@ pub mod context; pub mod device; pub mod surface; -crate::implement_interfaces!(AngleConnection, AngleDevice); +crate::implement_interfaces!(AngleConnection); #[cfg(test)] use self::connection::AngleConnection as Connection; #[cfg(test)] -use self::device::AngleDevice as Device; +use self::device::AngleDevice as ConcreteDevice; #[cfg(test)] #[path = "../tests.rs"] mod tests; diff --git a/src/cgl/connection.rs b/src/cgl/connection.rs index 31fcde50..6f1c6702 100644 --- a/src/cgl/connection.rs +++ b/src/cgl/connection.rs @@ -7,8 +7,8 @@ use super::device::CglDevice; use crate::adapter::{Adapter, AdapterPreferences}; use crate::base::io_surface::connection::Connection as SystemConnection; use crate::base::io_surface::device::NativeDevice; -use crate::Error; use crate::GLApi; +use crate::{Device, Error}; pub use crate::base::io_surface::connection::NativeConnection; @@ -53,8 +53,11 @@ impl CglConnection { /// /// Device handles are local to a single thread. #[inline] - pub fn create_device(&self, adapter: &Adapter) -> Result { - self.0.create_device(adapter.apple()?).map(CglDevice) + pub fn create_device(&self, adapter: &Adapter) -> Result { + self.0 + .create_device(adapter.apple()?) + .map(CglDevice) + .map(Device::from) } /// An alias for `connection.create_device()` with the default adapter. diff --git a/src/cgl/mod.rs b/src/cgl/mod.rs index fcb42dcf..11885986 100644 --- a/src/cgl/mod.rs +++ b/src/cgl/mod.rs @@ -8,12 +8,12 @@ pub mod surface; mod error; mod ffi; -crate::implement_interfaces!(CglConnection, CglDevice); +crate::implement_interfaces!(CglConnection); #[cfg(test)] use self::connection::CglConnection as Connection; #[cfg(test)] -use self::device::CglDevice as Device; +use self::device::CglDevice as ConcreteDevice; #[cfg(test)] #[path = "../tests.rs"] mod tests; diff --git a/src/connection.rs b/src/connection.rs index 22adc0c8..f572da44 100644 --- a/src/connection.rs +++ b/src/connection.rs @@ -2,14 +2,12 @@ use crate::adapter::AdapterPreferences; use crate::Adapter; +use crate::Device; use crate::Error; use crate::GLApi; /// Methods relating to display server connections. pub trait Connection: Sized { - /// The device type associated with this connection. - type Device; - /// Connects to the default display. fn new() -> Result; @@ -20,7 +18,7 @@ pub trait Connection: Sized { fn create_adapter(&self, preferences: AdapterPreferences) -> Result; /// Opens a device. - fn create_device(&self, adapter: &Adapter) -> Result; + fn create_device(&self, adapter: &Adapter) -> Result; /// Opens the display connection corresponding to the given `DisplayHandle`. fn from_display_handle(handle: raw_window_handle::DisplayHandle) -> Result; diff --git a/src/device.rs b/src/device.rs index 2b8b030e..2b5a1879 100644 --- a/src/device.rs +++ b/src/device.rs @@ -1,6 +1,6 @@ -//! The abstract interface that all devices conform to. +//! A platform-independent representation of a display device. -use super::connection::Connection as ConnectionInterface; +use crate::macros::{dispatch, enum_conversion}; use crate::{ Adapter, Context, ContextAttributes, ContextDescriptor, ContextID, Error, GLApi, Surface, SurfaceAccess, SurfaceInfo, SurfaceTexture, SurfaceType, @@ -10,68 +10,142 @@ use glow::Texture; use std::os::raw::c_void; +#[cfg(all(windows_platform, feature = "sm-angle"))] +use crate::angle::device::AngleDevice; +#[cfg(macos_platform)] +use crate::cgl::device::CglDevice; +#[cfg(any(android_platform, ohos_platform))] +use crate::hardware_buffer::device::HardwareBufferDevice; +#[cfg(free_unix)] +use crate::mesa_surfaceless::device::SurfacelessMesaDevice; +#[cfg(wayland_platform)] +use crate::wayland::device::WaylandDevice; +#[cfg(all(windows_platform, not(feature = "sm-no-wgl")))] +use crate::wgl::device::WglDevice; +#[cfg(x11_platform)] +use crate::x11::device::X11Device; + /// A thread-local handle to a device. /// /// Devices contain most of the relevant surface management methods. -pub trait Device: Sized -where - Self::Connection: ConnectionInterface, -{ - /// The connection type associated with this device. - type Connection; +pub enum Device { + /// An ANGLE device for Windows systems. + #[cfg(all(windows_platform, feature = "sm-angle"))] + Angle(AngleDevice), + /// A device for Apple systems. + #[cfg(macos_platform)] + Cgl(CglDevice), + /// A hardware buffer device for OHOS and Android systems. + #[cfg(any(android_platform, ohos_platform))] + HardwareBuffer(HardwareBufferDevice), + /// A surfaceless Mesa device for X11 / Wayland systems. + #[cfg(free_unix)] + SurfacelessMesa(SurfacelessMesaDevice), + /// A device for Wayland systems. + #[cfg(wayland_platform)] + Wayland(WaylandDevice), + /// A WGL device for Windows systems. + #[cfg(all(windows_platform, not(feature = "sm-no-wgl")))] + Wgl(WglDevice), + /// A device for X11 systems. + #[cfg(x11_platform)] + X11(X11Device), +} - // device.rs +#[cfg(all(windows_platform, feature = "sm-angle"))] +enum_conversion!(Device, Angle, AngleDevice, angle, IncompatibleDevice); +#[cfg(macos_platform)] +enum_conversion!(Device, Cgl, CglDevice, cgl, IncompatibleDevice); +#[cfg(any(android_platform, ohos_platform))] +enum_conversion!( + Device, + HardwareBuffer, + HardwareBufferDevice, + hardware_buffer, + IncompatibleDevice +); +#[cfg(free_unix)] +enum_conversion!( + Device, + SurfacelessMesa, + SurfacelessMesaDevice, + surfaceless_mesa, + IncompatibleDevice +); +#[cfg(wayland_platform)] +enum_conversion!(Device, Wayland, WaylandDevice, wayland, IncompatibleDevice); +#[cfg(all(windows_platform, not(feature = "sm-no-wgl")))] +enum_conversion!(Device, Wgl, WglDevice, wgl, IncompatibleDevice); +#[cfg(x11_platform)] +enum_conversion!(Device, X11, X11Device, x11, IncompatibleDevice); +impl Device { /// Returns the adapter that this device was created with. - fn adapter(&self) -> Adapter; + pub fn adapter(&self) -> Adapter { + dispatch!(Device, self, device => device.adapter()) + } /// Returns the OpenGL API flavor that this device supports (OpenGL or OpenGL ES). - fn gl_api(&self) -> GLApi; - - // context.rs + pub fn gl_api(&self) -> GLApi { + dispatch!(Device, self, device => device.gl_api()) + } /// Creates a context descriptor with the given attributes. /// /// Context descriptors are local to this device. - fn create_context_descriptor( + pub fn create_context_descriptor( &self, attributes: &ContextAttributes, - ) -> Result; + ) -> Result { + dispatch!(Device, self, device => device.create_context_descriptor(attributes)) + } /// Creates a new OpenGL context and makes it current. /// /// The context initially has no surface attached. Until a surface is bound to it, rendering /// commands will fail or have no effect. - fn create_context( + pub fn create_context( &self, descriptor: &ContextDescriptor, share_with: Option<&Context>, - ) -> Result; + ) -> Result { + dispatch!(Device, self, device => device.create_context(descriptor, share_with)) + } /// Destroys a context. /// /// The context must have been created on this device. - fn destroy_context(&self, context: &mut Context) -> Result<(), Error>; + pub fn destroy_context(&self, context: &mut Context) -> Result<(), Error> { + dispatch!(Device, self, device => device.destroy_context(context)) + } /// Returns the descriptor that this context was created with. - fn context_descriptor(&self, context: &Context) -> ContextDescriptor; + pub fn context_descriptor(&self, context: &Context) -> ContextDescriptor { + dispatch!(Device, self, device => device.context_descriptor(context)) + } /// Makes the context the current OpenGL context for this thread. /// /// After calling this function, it is valid to use OpenGL rendering commands. - fn make_context_current(&self, context: &Context) -> Result<(), Error>; + pub fn make_context_current(&self, context: &Context) -> Result<(), Error> { + dispatch!(Device, self, device => device.make_context_current(context)) + } /// Removes the current OpenGL context from this thread. /// /// After calling this function, OpenGL rendering commands will fail until a new context is /// made current. - fn make_no_context_current(&self) -> Result<(), Error>; + pub fn make_no_context_current(&self) -> Result<(), Error> { + dispatch!(Device, self, device => device.make_no_context_current()) + } /// Returns the attributes that the context descriptor was created with. - fn context_descriptor_attributes( + pub fn context_descriptor_attributes( &self, context_descriptor: &ContextDescriptor, - ) -> ContextAttributes; + ) -> ContextAttributes { + dispatch!(Device, self, device => device.context_descriptor_attributes(context_descriptor)) + } /// Fetches the address of an OpenGL function associated with this context. /// @@ -80,7 +154,9 @@ where /// /// This method is typically used with a function like `gl::load_with()` from the `gl` crate to /// load OpenGL function pointers. - fn get_proc_address(&self, context: &Context, symbol_name: &str) -> *const c_void; + pub fn get_proc_address(&self, context: &Context, symbol_name: &str) -> *const c_void { + dispatch!(Device, self, device => device.get_proc_address(context, symbol_name)) + } /// Attaches a surface to a context for rendering. /// @@ -92,41 +168,52 @@ where /// `unbind_surface_from_context`. /// /// If an error is returned, the surface is returned alongside it. - fn bind_surface_to_context( + pub fn bind_surface_to_context( &self, context: &mut Context, surface: Surface, - ) -> Result<(), (Error, Surface)>; + ) -> Result<(), (Error, Surface)> { + dispatch!(Device, self, device => device.bind_surface_to_context(context, surface)) + } /// Removes and returns any attached surface from this context. /// /// Any pending OpenGL commands targeting this surface will be automatically flushed, so the /// surface is safe to read from immediately when this function returns. - fn unbind_surface_from_context(&self, context: &mut Context) -> Result, Error>; + pub fn unbind_surface_from_context( + &self, + context: &mut Context, + ) -> Result, Error> { + dispatch!(Device, self, device => device.unbind_surface_from_context(context)) + } /// Returns a unique ID representing a context. /// /// This ID is unique to all currently-allocated contexts. If you destroy a context and create /// a new one, the new context might have the same ID as the destroyed one. - fn context_id(&self, context: &Context) -> ContextID; + pub fn context_id(&self, context: &Context) -> ContextID { + dispatch!(Device, self, device => device.context_id(context)) + } /// Returns various information about the surface attached to a context. /// /// This includes, most notably, the OpenGL framebuffer object needed to render to the surface. - fn context_surface_info(&self, context: &Context) -> Result, Error>; - - // surface.rs + pub fn context_surface_info(&self, context: &Context) -> Result, Error> { + dispatch!(Device, self, device => device.context_surface_info(context)) + } /// Creates either a generic or a widget surface, depending on the supplied surface type. /// /// Only the given context may ever render to the surface, but generic surfaces can be wrapped /// up in a `SurfaceTexture` for reading by other contexts. - fn create_surface( + pub fn create_surface( &self, context: &Context, surface_access: SurfaceAccess, surface_type: SurfaceType<'_>, - ) -> Result; + ) -> Result { + dispatch!(Device, self, device => device.create_surface(context, surface_access, surface_type)) + } /// Creates a surface texture from an existing generic surface for use with the given context. /// @@ -138,11 +225,13 @@ where /// in another context. /// /// Calling this method on a widget surface returns a `WidgetAttached` error. - fn create_surface_texture( + pub fn create_surface_texture( &self, context: &mut Context, surface: Surface, - ) -> Result; + ) -> Result { + dispatch!(Device, self, device => device.create_surface_texture(context, surface)) + } /// Destroys a surface. /// @@ -151,7 +240,13 @@ where /// /// You must explicitly call this method to dispose of a surface. Otherwise, a panic occurs in /// the `drop` method. - fn destroy_surface(&self, context: &mut Context, surface: &mut Surface) -> Result<(), Error>; + pub fn destroy_surface( + &self, + context: &mut Context, + surface: &mut Surface, + ) -> Result<(), Error> { + dispatch!(Device, self, device => device.destroy_surface(context, surface)) + } /// Destroys a surface texture and returns the underlying surface. /// @@ -160,23 +255,29 @@ where /// /// All surface textures must be explicitly destroyed with this function, or a panic will /// occur. - fn destroy_surface_texture( + pub fn destroy_surface_texture( &self, context: &mut Context, surface_texture: SurfaceTexture, - ) -> Result; + ) -> Result { + dispatch!(Device, self, device => device.destroy_surface_texture(context, surface_texture)) + } /// Returns the OpenGL texture target needed to read from this surface texture. /// /// This will be `GL_TEXTURE_2D` or `GL_TEXTURE_RECTANGLE`, depending on platform. - fn surface_gl_texture_target(&self) -> u32; + pub fn surface_gl_texture_target(&self) -> u32 { + dispatch!(Device, self, device => device.surface_gl_texture_target()) + } /// Displays the contents of the currently bound surface to the screen, if /// it is a widget surface. /// /// Widget surfaces are internally double-buffered, so changes to them don't /// show up in their associated widgets until this method is called. - fn present_bound_surface(&self, context: &mut Context) -> Result<(), Error>; + pub fn present_bound_surface(&self, context: &mut Context) -> Result<(), Error> { + dispatch!(Device, self, device => device.present_bound_surface(context)) + } /// Displays the contents of a widget surface on screen. /// @@ -185,18 +286,28 @@ where /// /// The supplied context must match the context the surface was created with, or an /// `IncompatibleSurface` error is returned. - fn present_surface(&self, context: &Context, surface: &mut Surface) -> Result<(), Error>; + pub fn present_surface(&self, context: &Context, surface: &mut Surface) -> Result<(), Error> { + dispatch!(Device, self, device => device.present_surface(context, surface)) + } /// If the currently bound surface is a widget surface, resize it, - fn resize_bound_surface(&self, context: &mut Context, size: Size2D) -> Result<(), Error>; + pub fn resize_bound_surface( + &self, + context: &mut Context, + size: Size2D, + ) -> Result<(), Error> { + dispatch!(Device, self, device => device.resize_bound_surface(context, size)) + } /// Resizes a widget surface. - fn resize_surface( + pub fn resize_surface( &self, context: &Context, surface: &mut Surface, size: Size2D, - ) -> Result<(), Error>; + ) -> Result<(), Error> { + dispatch!(Device, self, device => device.resize_surface(context, surface, size)) + } /// Returns various information about the surface, including the framebuffer object needed to /// render to this surface. @@ -204,10 +315,14 @@ where /// Before rendering to a surface attached to a context, you must call `glBindFramebuffer()` /// on the framebuffer object returned by this function. This framebuffer object may or not be /// 0, the default framebuffer, depending on platform. - fn surface_info(&self, surface: &Surface) -> SurfaceInfo; + pub fn surface_info(&self, surface: &Surface) -> SurfaceInfo { + dispatch!(Device, self, device => device.surface_info(surface)) + } /// Returns the OpenGL texture object containing the contents of this surface. /// /// It is only legal to read from, not write to, this texture object. - fn surface_texture_object(&self, surface_texture: &SurfaceTexture) -> Option; + pub fn surface_texture_object(&self, surface_texture: &SurfaceTexture) -> Option { + dispatch!(Device, self, device => device.surface_texture_object(surface_texture)) + } } diff --git a/src/error.rs b/src/error.rs index 8e77c459..91efbcbf 100644 --- a/src/error.rs +++ b/src/error.rs @@ -92,6 +92,8 @@ pub enum Error { IncompatibleNativeContext, /// The native device does not match the supplied connection. IncompatibleNativeDevice, + /// The device is not of the requested backend. + IncompatibleDevice, } /// Abstraction of the errors that EGL, CGL, GLX, CGL, etc. return. diff --git a/src/hardware_buffer/connection.rs b/src/hardware_buffer/connection.rs index f1ef9aa8..07258e2c 100644 --- a/src/hardware_buffer/connection.rs +++ b/src/hardware_buffer/connection.rs @@ -4,7 +4,7 @@ use super::adapter::HardwareBufferAdapter; use super::device::{HardwareBufferDevice, NativeDevice}; -use crate::{Adapter, AdapterPreferences, Error, GLApi}; +use crate::{Adapter, AdapterPreferences, Device, Error, GLApi}; /// A connection to the display server. #[derive(Clone)] @@ -51,8 +51,8 @@ impl HardwareBufferConnection { /// /// Device handles are local to a single thread. #[inline] - pub fn create_device(&self, _: &Adapter) -> Result { - HardwareBufferDevice::new() + pub fn create_device(&self, _: &Adapter) -> Result { + HardwareBufferDevice::new().map(Device::from) } /// Wraps an Android `EGLDisplay` in a device and returns it. diff --git a/src/hardware_buffer/mod.rs b/src/hardware_buffer/mod.rs index 131ee6f5..125a03cc 100644 --- a/src/hardware_buffer/mod.rs +++ b/src/hardware_buffer/mod.rs @@ -12,12 +12,12 @@ mod android_ffi; #[cfg(ohos_platform)] mod ohos_ffi; -crate::implement_interfaces!(HardwareBufferConnection, HardwareBufferDevice); +crate::implement_interfaces!(HardwareBufferConnection); #[cfg(any(test, feature = "sm-test"))] use self::connection::HardwareBufferConnection as Connection; #[cfg(any(test, feature = "sm-test"))] -use self::device::HardwareBufferDevice as Device; +use self::device::HardwareBufferDevice as ConcreteDevice; #[cfg(feature = "sm-test")] #[path = "../tests.rs"] diff --git a/src/lib.rs b/src/lib.rs index 08efd799..b4126fd6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -63,6 +63,7 @@ pub use wgl as default; pub use crate::context::{Context, ContextAttributeFlags, ContextAttributes, ContextID}; pub use crate::context_descriptor::ContextDescriptor; +pub use crate::device::Device; pub use crate::error::{Error, WindowingApiError}; pub use crate::info::{GLApi, GLVersion}; pub use crate::surface::{Surface, SurfaceAccess, SurfaceID, SurfaceInfo, SurfaceType}; @@ -72,19 +73,17 @@ pub(crate) use glow::{self as gl, Context as Gl}; pub(crate) use macros::implement_interfaces; #[cfg(all(windows_platform, angle_default))] -pub use angle::{connection::AngleConnection as Connection, device::AngleDevice as Device}; +pub use angle::connection::AngleConnection as Connection; #[cfg(macos_platform)] -pub use cgl::{connection::CglConnection as Connection, device::CglDevice as Device}; +pub use cgl::connection::CglConnection as Connection; #[cfg(any(android_platform, ohos_platform))] -pub use hardware_buffer::{ - connection::HardwareBufferConnection as Connection, device::HardwareBufferDevice as Device, -}; +pub use hardware_buffer::connection::HardwareBufferConnection as Connection; #[cfg(all(x11_platform, not(wayland_default)))] -pub use unix::{connection::Connection, device::Device}; +pub use unix::connection::Connection; #[cfg(wayland_default)] -pub use wayland::{connection::WaylandConnection as Connection, device::WaylandDevice as Device}; +pub use wayland::connection::WaylandConnection as Connection; #[cfg(all(windows_platform, not(angle_default)))] -pub use wgl::{connection::WglConnection as Connection, device::WglDevice as Device}; +pub use wgl::connection::WglConnection as Connection; // TODO(pcwalton): Fill this in with other OS's. #[cfg(target_os = "macos")] diff --git a/src/macros.rs b/src/macros.rs index 3a39508c..6207d63f 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -1,4 +1,4 @@ -//! A macro for use in the top-level crate. +//! Macros for use in the top-level crate. /// When using `surfman`, you should place this macro at the top of your crate, like so: /// @@ -30,28 +30,17 @@ macro_rules! declare_surfman { }; } -/// Internal macro used for generating implementations of the `Connection` and `Device` traits. +/// Internal macro used for generating implementations of the `Connection` trait. macro_rules! implement_interfaces { - ($connection:ident, $device:ident) => { + ($connection:ident) => { mod implementation { use super::connection::$connection as Connection; - use super::device::$device as Device; - use euclid::default::Size2D; - use glow::Texture; - use std::os::raw::c_void; use $crate::adapter::{Adapter, AdapterPreferences}; use $crate::connection::Connection as ConnectionInterface; - use $crate::device::Device as DeviceInterface; use $crate::info::GLApi; - use $crate::Error; - use $crate::{ - Context, ContextAttributes, ContextDescriptor, ContextID, Surface, SurfaceAccess, - SurfaceInfo, SurfaceTexture, SurfaceType, - }; + use $crate::{Device, Error}; impl ConnectionInterface for Connection { - type Device = Device; - #[inline] fn new() -> Result { Connection::new() @@ -71,7 +60,7 @@ macro_rules! implement_interfaces { } #[inline] - fn create_device(&self, adapter: &Adapter) -> Result { + fn create_device(&self, adapter: &Adapter) -> Result { Connection::create_device(self, adapter) } @@ -82,194 +71,6 @@ macro_rules! implement_interfaces { Connection::from_display_handle(handle) } } - - impl DeviceInterface for Device { - type Connection = Connection; - - // device.rs - - #[inline] - fn adapter(&self) -> Adapter { - Device::adapter(self) - } - - #[inline] - fn gl_api(&self) -> GLApi { - Device::gl_api(self) - } - - // context.rs - - #[inline] - fn create_context_descriptor( - &self, - attributes: &ContextAttributes, - ) -> Result { - Device::create_context_descriptor(self, attributes) - } - - #[inline] - fn create_context( - &self, - descriptor: &ContextDescriptor, - share_with: Option<&Context>, - ) -> Result { - Device::create_context(self, descriptor, share_with) - } - - #[inline] - fn destroy_context(&self, context: &mut Context) -> Result<(), Error> { - Device::destroy_context(self, context) - } - - #[inline] - fn context_descriptor(&self, context: &Context) -> ContextDescriptor { - Device::context_descriptor(self, context) - } - - #[inline] - fn make_context_current(&self, context: &Context) -> Result<(), Error> { - Device::make_context_current(self, context) - } - - #[inline] - fn make_no_context_current(&self) -> Result<(), Error> { - Device::make_no_context_current(self) - } - - #[inline] - fn context_descriptor_attributes( - &self, - context_descriptor: &ContextDescriptor, - ) -> ContextAttributes { - Device::context_descriptor_attributes(self, context_descriptor) - } - - #[inline] - fn get_proc_address(&self, context: &Context, symbol_name: &str) -> *const c_void { - Device::get_proc_address(self, context, symbol_name) - } - - #[inline] - fn bind_surface_to_context( - &self, - context: &mut Context, - surface: Surface, - ) -> Result<(), (Error, Surface)> { - Device::bind_surface_to_context(self, context, surface) - } - - #[inline] - fn unbind_surface_from_context( - &self, - context: &mut Context, - ) -> Result, Error> { - Device::unbind_surface_from_context(self, context) - } - - #[inline] - fn context_id(&self, context: &Context) -> ContextID { - Device::context_id(self, context) - } - - #[inline] - fn context_surface_info( - &self, - context: &Context, - ) -> Result, Error> { - Device::context_surface_info(self, context) - } - - // surface.rs - - #[inline] - fn create_surface( - &self, - context: &Context, - surface_access: SurfaceAccess, - surface_type: SurfaceType<'_>, - ) -> Result { - Device::create_surface(self, context, surface_access, surface_type) - } - - #[inline] - fn create_surface_texture( - &self, - context: &mut Context, - surface: Surface, - ) -> Result { - Device::create_surface_texture(self, context, surface) - } - - #[inline] - fn destroy_surface( - &self, - context: &mut Context, - surface: &mut Surface, - ) -> Result<(), Error> { - Device::destroy_surface(self, context, surface) - } - - #[inline] - fn destroy_surface_texture( - &self, - context: &mut Context, - surface_texture: SurfaceTexture, - ) -> Result { - Device::destroy_surface_texture(self, context, surface_texture) - } - - #[inline] - fn surface_gl_texture_target(&self) -> u32 { - Device::surface_gl_texture_target(self) - } - - #[inline] - fn present_bound_surface(&self, context: &mut Context) -> Result<(), Error> { - Device::present_bound_surface(self, context) - } - - #[inline] - fn present_surface( - &self, - context: &Context, - surface: &mut Surface, - ) -> Result<(), Error> { - Device::present_surface(self, context, surface) - } - - #[inline] - fn resize_bound_surface( - &self, - context: &mut Context, - size: Size2D, - ) -> Result<(), Error> { - Device::resize_bound_surface(self, context, size) - } - - #[inline] - fn resize_surface( - &self, - context: &Context, - surface: &mut Surface, - size: Size2D, - ) -> Result<(), Error> { - Device::resize_surface(self, context, surface, size) - } - - #[inline] - fn surface_info(&self, surface: &Surface) -> SurfaceInfo { - Device::surface_info(self, surface) - } - - #[inline] - fn surface_texture_object( - &self, - surface_texture: &SurfaceTexture, - ) -> Option { - Device::surface_texture_object(self, surface_texture) - } - } } }; } @@ -319,5 +120,28 @@ macro_rules! enum_conversion { }; } +/// A macro that forwards a call to the backend type wrapped by a [`crate::Device`]. +macro_rules! dispatch { + ($enum:ident, $value:expr, $inner:ident => $body:expr) => { + match $value { + #[cfg(all(windows_platform, feature = "sm-angle"))] + $enum::Angle($inner) => $body, + #[cfg(macos_platform)] + $enum::Cgl($inner) => $body, + #[cfg(any(android_platform, ohos_platform))] + $enum::HardwareBuffer($inner) => $body, + #[cfg(free_unix)] + $enum::SurfacelessMesa($inner) => $body, + #[cfg(wayland_platform)] + $enum::Wayland($inner) => $body, + #[cfg(all(windows_platform, not(feature = "sm-no-wgl")))] + $enum::Wgl($inner) => $body, + #[cfg(x11_platform)] + $enum::X11($inner) => $body, + } + }; +} + +pub(crate) use dispatch; pub(crate) use enum_conversion; pub(crate) use implement_interfaces; diff --git a/src/mesa_surfaceless/connection.rs b/src/mesa_surfaceless/connection.rs index 387571b1..30beb2fe 100644 --- a/src/mesa_surfaceless/connection.rs +++ b/src/mesa_surfaceless/connection.rs @@ -6,8 +6,8 @@ use crate::base::egl::ffi::EGL_PLATFORM_SURFACELESS_MESA; use crate::egl::types::{EGLAttrib, EGLDisplay}; use crate::free_unix::adapter::FreeUnixAdapter; use crate::info::GLApi; -use crate::Error; use crate::{egl, Adapter, AdapterPreferences}; +use crate::{Device, Error}; use std::os::raw::c_void; use std::sync::Arc; @@ -93,8 +93,8 @@ impl SurfacelessMesaConnection { /// /// Device handles are local to a single thread. #[inline] - pub fn create_device(&self, adapter: &Adapter) -> Result { - SurfacelessMesaDevice::new(self, adapter) + pub fn create_device(&self, adapter: &Adapter) -> Result { + SurfacelessMesaDevice::new(self, adapter).map(Device::from) } /// An alias for `connection.create_device()` with the default adapter. diff --git a/src/mesa_surfaceless/mod.rs b/src/mesa_surfaceless/mod.rs index 99e72e78..c4ed2821 100644 --- a/src/mesa_surfaceless/mod.rs +++ b/src/mesa_surfaceless/mod.rs @@ -6,12 +6,12 @@ pub mod context; pub mod device; pub mod surface; -crate::implement_interfaces!(SurfacelessMesaConnection, SurfacelessMesaDevice); +crate::implement_interfaces!(SurfacelessMesaConnection); #[cfg(test)] use self::connection::SurfacelessMesaConnection as Connection; #[cfg(test)] -use self::device::SurfacelessMesaDevice as Device; +use self::device::SurfacelessMesaDevice as ConcreteDevice; #[cfg(test)] #[path = "../tests.rs"] mod tests; diff --git a/src/multi/connection.rs b/src/multi/connection.rs index 86d29619..fc454ff0 100644 --- a/src/multi/connection.rs +++ b/src/multi/connection.rs @@ -1,54 +1,34 @@ //! A connection abstraction that allows the choice of backends dynamically. -use super::device::Device; use crate::adapter::AdapterPreferences; use crate::connection::Connection as ConnectionInterface; -use crate::device::Device as DeviceInterface; use crate::GLApi; -use crate::{Adapter, Error}; +use crate::{Adapter, Device, Error}; /// A connection to the display server. +#[derive(Clone)] pub enum Connection where - Def: DeviceInterface, - Alt: DeviceInterface, - Def::Connection: ConnectionInterface, - Alt::Connection: ConnectionInterface, + Def: ConnectionInterface, + Alt: ConnectionInterface, { /// The default connection to the display server. - Default(Def::Connection), + Default(Def), /// The alternate connection to the display server. - Alternate(Alt::Connection), -} - -impl Clone for Connection -where - Def: DeviceInterface, - Alt: DeviceInterface, - Def::Connection: Clone, - Alt::Connection: Clone, -{ - fn clone(&self) -> Self { - match self { - Connection::Default(ref connection) => Connection::Default(connection.clone()), - Connection::Alternate(ref connection) => Connection::Alternate(connection.clone()), - } - } + Alternate(Alt), } impl Connection where - Def: DeviceInterface, - Alt: DeviceInterface, - Def::Connection: ConnectionInterface, - Alt::Connection: ConnectionInterface, + Def: ConnectionInterface, + Alt: ConnectionInterface, { /// Connects to the default display. #[inline] pub fn new() -> Result, Error> { - match ::new() { + match Def::new() { Ok(connection) => Ok(Connection::Default(connection)), - Err(_) => ::new().map(Connection::Alternate), + Err(_) => Alt::new().map(Connection::Alternate), } } @@ -71,10 +51,10 @@ where /// Opens the hardware device corresponding to the given adapter. /// /// Device handles are local to a single thread. - pub fn create_device(&self, adapter: &Adapter) -> Result, Error> { + pub fn create_device(&self, adapter: &Adapter) -> Result { match self { - Self::Default(connection) => connection.create_device(adapter).map(Device::Default), - Self::Alternate(connection) => connection.create_device(adapter).map(Device::Alternate), + Self::Default(connection) => connection.create_device(adapter), + Self::Alternate(connection) => connection.create_device(adapter), } } @@ -82,22 +62,18 @@ where pub fn from_display_handle( handle: raw_window_handle::DisplayHandle, ) -> Result, Error> { - match ::from_display_handle(handle) { + match Def::from_display_handle(handle) { Ok(connection) => Ok(Connection::Default(connection)), - Err(_) => ::from_display_handle(handle).map(Connection::Alternate), + Err(_) => Alt::from_display_handle(handle).map(Connection::Alternate), } } } impl ConnectionInterface for Connection where - Def: DeviceInterface, - Alt: DeviceInterface, - Def::Connection: ConnectionInterface, - Alt::Connection: ConnectionInterface, + Def: ConnectionInterface, + Alt: ConnectionInterface, { - type Device = Device; - #[inline] fn new() -> Result, Error> { Connection::new() @@ -114,7 +90,7 @@ where } #[inline] - fn create_device(&self, adapter: &Adapter) -> Result, Error> { + fn create_device(&self, adapter: &Adapter) -> Result { Connection::create_device(self, adapter) } diff --git a/src/multi/context.rs b/src/multi/context.rs deleted file mode 100644 index ae2ae5e8..00000000 --- a/src/multi/context.rs +++ /dev/null @@ -1,189 +0,0 @@ -//! A context abstraction that allows the choice of backends dynamically. - -use euclid::default::Size2D; - -use super::device::Device; -use crate::device::Device as DeviceInterface; -use crate::{ - Context, ContextAttributes, ContextDescriptor, ContextID, Error, Surface, SurfaceInfo, -}; - -use std::os::raw::c_void; - -impl Device -where - Def: DeviceInterface, - Alt: DeviceInterface, -{ - /// Creates a context descriptor with the given attributes. - /// - /// Context descriptors are local to this device. - pub fn create_context_descriptor( - &self, - attributes: &ContextAttributes, - ) -> Result { - match *self { - Device::Default(ref device) => device.create_context_descriptor(attributes), - Device::Alternate(ref device) => device.create_context_descriptor(attributes), - } - } - - /// Creates a new OpenGL context. - /// - /// The context initially has no surface attached. Until a surface is bound to it, rendering - /// commands will fail or have no effect. - pub fn create_context( - &self, - descriptor: &ContextDescriptor, - share_with: Option<&Context>, - ) -> Result { - match self { - Device::Default(device) => device.create_context(descriptor, share_with), - Device::Alternate(device) => device.create_context(descriptor, share_with), - } - } - - /// Destroys a context. - /// - /// The context must have been created on this device. - pub fn destroy_context(&self, context: &mut Context) -> Result<(), Error> { - match self { - Device::Default(device) => device.destroy_context(context), - Device::Alternate(device) => device.destroy_context(context), - } - } - - /// Returns the descriptor that this context was created with. - pub fn context_descriptor(&self, context: &Context) -> ContextDescriptor { - match self { - Device::Default(device) => device.context_descriptor(context), - Device::Alternate(device) => device.context_descriptor(context), - } - } - - /// Makes the context the current OpenGL context for this thread. - /// - /// After calling this function, it is valid to use OpenGL rendering commands. - pub fn make_context_current(&self, context: &Context) -> Result<(), Error> { - match self { - Device::Default(device) => device.make_context_current(context), - Device::Alternate(device) => device.make_context_current(context), - } - } - - /// Removes the current OpenGL context from this thread. - /// - /// After calling this function, OpenGL rendering commands will fail until a new context is - /// made current. - pub fn make_no_context_current(&self) -> Result<(), Error> { - match self { - Device::Default(device) => device.make_no_context_current(), - Device::Alternate(device) => device.make_no_context_current(), - } - } - - /// Attaches a surface to a context for rendering. - /// - /// This function takes ownership of the surface. The surface must have been created with this - /// context, or an `IncompatibleSurface` error is returned. - /// - /// If this function is called with a surface already bound, a `SurfaceAlreadyBound` error is - /// returned. To avoid this error, first unbind the existing surface with - /// `unbind_surface_from_context`. - /// - /// If an error is returned, the surface is returned alongside it. - pub fn bind_surface_to_context( - &self, - context: &mut Context, - surface: Surface, - ) -> Result<(), (Error, Surface)> { - match self { - Device::Default(device) => device.bind_surface_to_context(context, surface), - Device::Alternate(device) => device.bind_surface_to_context(context, surface), - } - } - - /// Removes and returns any attached surface from this context. - /// - /// Any pending OpenGL commands targeting this surface will be automatically flushed, so the - /// surface is safe to read from immediately when this function returns. - pub fn unbind_surface_from_context( - &self, - context: &mut Context, - ) -> Result, Error> { - match self { - Device::Default(device) => device.unbind_surface_from_context(context), - Device::Alternate(device) => device.unbind_surface_from_context(context), - } - } - - /// Displays the contents of the currently bound surface to the screen, if - /// it is a widget surface. - /// - /// Widget surfaces are internally double-buffered, so changes to them don't - /// show up in their associated widgets until this method is called. - pub fn present_bound_surface(&self, context: &mut Context) -> Result<(), Error> { - match self { - Device::Default(device) => device.present_bound_surface(context), - Device::Alternate(device) => device.present_bound_surface(context), - } - } - - /// Resizes the currently bound surface. - pub fn resize_bound_surface( - &self, - context: &mut Context, - size: Size2D, - ) -> Result<(), Error> { - match self { - Device::Default(device) => device.resize_bound_surface(context, size), - Device::Alternate(device) => device.resize_bound_surface(context, size), - } - } - - /// Returns the attributes that the context descriptor was created with. - pub fn context_descriptor_attributes( - &self, - context_descriptor: &ContextDescriptor, - ) -> ContextAttributes { - match self { - Device::Default(device) => device.context_descriptor_attributes(context_descriptor), - Device::Alternate(device) => device.context_descriptor_attributes(context_descriptor), - } - } - - /// Fetches the address of an OpenGL function associated with this context. - /// - /// OpenGL functions are local to a context. You should not use OpenGL functions on one context - /// with any other context. - /// - /// This method is typically used with a function like `gl::load_with()` from the `gl` crate to - /// load OpenGL function pointers. - pub fn get_proc_address(&self, context: &Context, symbol_name: &str) -> *const c_void { - match self { - Device::Default(device) => device.get_proc_address(context, symbol_name), - Device::Alternate(device) => device.get_proc_address(context, symbol_name), - } - } - - /// Returns a unique ID representing a context. - /// - /// This ID is unique to all currently-allocated contexts. If you destroy a context and create - /// a new one, the new context might have the same ID as the destroyed one. - pub fn context_id(&self, context: &Context) -> ContextID { - match self { - Device::Default(device) => device.context_id(context), - Device::Alternate(device) => device.context_id(context), - } - } - - /// Returns various information about the surface attached to a context. - /// - /// This includes, most notably, the OpenGL framebuffer object needed to render to the surface. - pub fn context_surface_info(&self, context: &Context) -> Result, Error> { - match self { - Device::Default(device) => device.context_surface_info(context), - Device::Alternate(device) => device.context_surface_info(context), - } - } -} diff --git a/src/multi/device.rs b/src/multi/device.rs deleted file mode 100644 index 1609a275..00000000 --- a/src/multi/device.rs +++ /dev/null @@ -1,225 +0,0 @@ -//! A device abstraction that allows the choice of backends dynamically. - -use super::connection::Connection; -use crate::connection::Connection as ConnectionInterface; -use crate::context::ContextAttributes; -use crate::device::Device as DeviceInterface; -use crate::{ - Adapter, Context, ContextDescriptor, ContextID, Error, GLApi, Surface, SurfaceAccess, - SurfaceInfo, SurfaceTexture, SurfaceType, -}; -use euclid::default::Size2D; -use glow::Texture; - -use std::os::raw::c_void; - -/// A thread-local handle to a device. -/// -/// Devices contain most of the relevant surface management methods. -pub enum Device -where - Def: DeviceInterface, - Alt: DeviceInterface, -{ - /// The default device type. - Default(Def), - /// The alternate device type. - Alternate(Alt), -} - -impl Device -where - Def: DeviceInterface, - Alt: DeviceInterface, - Def::Connection: ConnectionInterface, - Alt::Connection: ConnectionInterface, -{ - /// Returns the adapter that this device was created with. - pub fn adapter(&self) -> Adapter { - match *self { - Device::Default(ref device) => device.adapter(), - Device::Alternate(ref device) => device.adapter(), - } - } - - /// Returns the OpenGL API flavor that this device supports (OpenGL or OpenGL ES). - pub fn gl_api(&self) -> GLApi { - match *self { - Device::Default(ref device) => device.gl_api(), - Device::Alternate(ref device) => device.gl_api(), - } - } -} - -impl DeviceInterface for Device -where - Def: DeviceInterface, - Alt: DeviceInterface, - Def::Connection: ConnectionInterface, - Alt::Connection: ConnectionInterface, -{ - type Connection = Connection; - - // device.rs - - #[inline] - fn adapter(&self) -> Adapter { - Device::adapter(self) - } - - #[inline] - fn gl_api(&self) -> GLApi { - Device::gl_api(self) - } - - // context.rs - - #[inline] - fn create_context_descriptor( - &self, - attributes: &ContextAttributes, - ) -> Result { - Device::create_context_descriptor(self, attributes) - } - - #[inline] - fn create_context( - &self, - descriptor: &ContextDescriptor, - share_with: Option<&Context>, - ) -> Result { - Device::create_context(self, descriptor, share_with) - } - - #[inline] - fn destroy_context(&self, context: &mut Context) -> Result<(), Error> { - Device::destroy_context(self, context) - } - - #[inline] - fn context_descriptor(&self, context: &Context) -> ContextDescriptor { - Device::context_descriptor(self, context) - } - - #[inline] - fn make_context_current(&self, context: &Context) -> Result<(), Error> { - Device::make_context_current(self, context) - } - - #[inline] - fn make_no_context_current(&self) -> Result<(), Error> { - Device::make_no_context_current(self) - } - - #[inline] - fn context_descriptor_attributes( - &self, - context_descriptor: &ContextDescriptor, - ) -> ContextAttributes { - Device::context_descriptor_attributes(self, context_descriptor) - } - - #[inline] - fn get_proc_address(&self, context: &Context, symbol_name: &str) -> *const c_void { - Device::get_proc_address(self, context, symbol_name) - } - - #[inline] - fn bind_surface_to_context( - &self, - context: &mut Context, - surface: Surface, - ) -> Result<(), (Error, Surface)> { - Device::bind_surface_to_context(self, context, surface) - } - - #[inline] - fn unbind_surface_from_context(&self, context: &mut Context) -> Result, Error> { - Device::unbind_surface_from_context(self, context) - } - - #[inline] - fn context_id(&self, context: &Context) -> ContextID { - Device::context_id(self, context) - } - - #[inline] - fn context_surface_info(&self, context: &Context) -> Result, Error> { - Device::context_surface_info(self, context) - } - - // surface.rs - - #[inline] - fn create_surface( - &self, - context: &Context, - surface_access: SurfaceAccess, - surface_type: SurfaceType<'_>, - ) -> Result { - Device::create_surface(self, context, surface_access, surface_type) - } - - #[inline] - fn create_surface_texture( - &self, - context: &mut Context, - surface: Surface, - ) -> Result { - Device::create_surface_texture(self, context, surface) - } - - #[inline] - fn destroy_surface(&self, context: &mut Context, surface: &mut Surface) -> Result<(), Error> { - Device::destroy_surface(self, context, surface) - } - - #[inline] - fn destroy_surface_texture( - &self, - context: &mut Context, - surface_texture: SurfaceTexture, - ) -> Result { - Device::destroy_surface_texture(self, context, surface_texture) - } - - #[inline] - fn surface_gl_texture_target(&self) -> u32 { - Device::surface_gl_texture_target(self) - } - - #[inline] - fn present_bound_surface(&self, context: &mut Context) -> Result<(), Error> { - Device::present_bound_surface(self, context) - } - - #[inline] - fn resize_bound_surface(&self, context: &mut Context, size: Size2D) -> Result<(), Error> { - Device::resize_bound_surface(self, context, size) - } - - #[inline] - fn present_surface(&self, context: &Context, surface: &mut Surface) -> Result<(), Error> { - Device::present_surface(self, context, surface) - } - - #[inline] - fn resize_surface( - &self, - context: &Context, - surface: &mut Surface, - size: Size2D, - ) -> Result<(), Error> { - Device::resize_surface(self, context, surface, size) - } - - #[inline] - fn surface_info(&self, surface: &Surface) -> SurfaceInfo { - Device::surface_info(self, surface) - } - - #[inline] - fn surface_texture_object(&self, surface_texture: &SurfaceTexture) -> Option { - Device::surface_texture_object(self, surface_texture) - } -} diff --git a/src/multi/mod.rs b/src/multi/mod.rs index 173412eb..9dbc62ff 100644 --- a/src/multi/mod.rs +++ b/src/multi/mod.rs @@ -2,18 +2,5 @@ //! //! This is useful on Unix systems, because it allows for Wayland to be tried first, and, failing //! that, to use X11. -//! -//! Each type here has two type parameters: a "default" device and an "alternate" device. Opening a -//! connection will first attempt to open the default connection and, if that fails, attempts to -//! open the alternate connection. You can also create instances of these types manually (i.e. -//! wrapping a default or alternate type directly) if you have platform-specific initialization -//! code. -//! -//! You can "daisy chain" these types to switch between more than two backends. For example, you -//! might use `multi::Device>` for a -//! device that can dynamically switch between Wayland, X11, and OSMesa. pub mod connection; -pub mod context; -pub mod device; -pub mod surface; diff --git a/src/multi/surface.rs b/src/multi/surface.rs deleted file mode 100644 index c3f3914f..00000000 --- a/src/multi/surface.rs +++ /dev/null @@ -1,149 +0,0 @@ -//! A surface abstraction that allows the choice of backends dynamically. - -use super::device::Device; -use crate::device::Device as DeviceInterface; -use crate::{Context, Error, Surface, SurfaceAccess, SurfaceInfo, SurfaceTexture, SurfaceType}; -use euclid::default::Size2D; -use glow::Texture; - -impl Device -where - Def: DeviceInterface, - Alt: DeviceInterface, -{ - /// Creates either a generic or a widget surface, depending on the supplied surface type. - /// - /// Only the given context may ever render to the surface, but generic surfaces can be wrapped - /// up in a `SurfaceTexture` for reading by other contexts. - pub fn create_surface( - &self, - context: &Context, - surface_access: SurfaceAccess, - surface_type: SurfaceType<'_>, - ) -> Result { - match self { - Device::Default(device) => device.create_surface(context, surface_access, surface_type), - Device::Alternate(device) => { - device.create_surface(context, surface_access, surface_type) - } - } - } - - /// Creates a surface texture from an existing generic surface for use with the given context. - /// - /// The surface texture is local to the supplied context and takes ownership of the surface. - /// Destroying the surface texture allows you to retrieve the surface again. - /// - /// *The supplied context does not have to be the same context that the surface is associated - /// with.* This allows you to render to a surface in one context and sample from that surface - /// in another context. - /// - /// Calling this method on a widget surface returns a `WidgetAttached` error. - pub fn create_surface_texture( - &self, - context: &mut Context, - surface: Surface, - ) -> Result { - match self { - Device::Default(device) => device.create_surface_texture(context, surface), - Device::Alternate(device) => device.create_surface_texture(context, surface), - } - } - - /// Destroys a surface. - /// - /// The supplied context must be the context the surface is associated with, or this returns - /// an `IncompatibleSurface` error. - /// - /// You must explicitly call this method to dispose of a surface. Otherwise, a panic occurs in - /// the `drop` method. - pub fn destroy_surface( - &self, - context: &mut Context, - surface: &mut Surface, - ) -> Result<(), Error> { - match self { - Device::Default(device) => device.destroy_surface(context, surface), - Device::Alternate(device) => device.destroy_surface(context, surface), - } - } - - /// Destroys a surface texture and returns the underlying surface. - /// - /// The supplied context must be the same context the surface texture was created with, or an - /// `IncompatibleSurfaceTexture` error is returned. - /// - /// All surface textures must be explicitly destroyed with this function, or a panic will - /// occur. - pub fn destroy_surface_texture( - &self, - context: &mut Context, - surface_texture: SurfaceTexture, - ) -> Result { - match self { - Device::Default(device) => device.destroy_surface_texture(context, surface_texture), - Device::Alternate(device) => device.destroy_surface_texture(context, surface_texture), - } - } - - /// Displays the contents of a widget surface on screen. - /// - /// Widget surfaces are internally double-buffered, so changes to them don't show up in their - /// associated widgets until this method is called. - /// - /// The supplied context must match the context the surface was created with, or an - /// `IncompatibleSurface` error is returned. - pub fn present_surface(&self, context: &Context, surface: &mut Surface) -> Result<(), Error> { - match self { - Device::Default(device) => device.present_surface(context, surface), - Device::Alternate(device) => device.present_surface(context, surface), - } - } - - /// Resizes a widget surface. - pub fn resize_surface( - &self, - context: &Context, - surface: &mut Surface, - size: Size2D, - ) -> Result<(), Error> { - match self { - Device::Default(device) => device.resize_surface(context, surface, size), - Device::Alternate(device) => device.resize_surface(context, surface, size), - } - } - - /// Returns the OpenGL texture target needed to read from this surface texture. - /// - /// This will be `GL_TEXTURE_2D` or `GL_TEXTURE_RECTANGLE`, depending on platform. - #[inline] - pub fn surface_gl_texture_target(&self) -> u32 { - match *self { - Device::Default(ref device) => device.surface_gl_texture_target(), - Device::Alternate(ref device) => device.surface_gl_texture_target(), - } - } - - /// Returns various information about the surface, including the framebuffer object needed to - /// render to this surface. - /// - /// Before rendering to a surface attached to a context, you must call `glBindFramebuffer()` - /// on the framebuffer object returned by this function. This framebuffer object may or not be - /// 0, the default framebuffer, depending on platform. - pub fn surface_info(&self, surface: &Surface) -> SurfaceInfo { - match self { - Device::Default(device) => device.surface_info(surface), - Device::Alternate(device) => device.surface_info(surface), - } - } - - /// Returns the OpenGL texture object containing the contents of this surface. - /// - /// It is only legal to read from, not write to, this texture object. - pub fn surface_texture_object(&self, surface_texture: &SurfaceTexture) -> Option { - match self { - Device::Default(device) => device.surface_texture_object(surface_texture), - Device::Alternate(device) => device.surface_texture_object(surface_texture), - } - } -} diff --git a/src/tests.rs b/src/tests.rs index ed39417a..50bfec13 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -7,11 +7,12 @@ #![allow(missing_docs)] use super::context::NativeContext; -use super::{Connection, Device}; +use super::ConcreteDevice; +use super::Connection; use crate::{ gl, Adapter, AdapterPreferences, Context, ContextAttributeFlags, ContextAttributes, - ContextDescriptor, Error, GLApi, GLVersion, Gl, PowerPreference, RenderingPreference, Surface, - SurfaceAccess, SurfaceType, WindowingApiError, + ContextDescriptor, Device, Error, GLApi, GLVersion, Gl, PowerPreference, RenderingPreference, + Surface, SurfaceAccess, SurfaceType, WindowingApiError, }; use euclid::default::Size2D; @@ -887,8 +888,10 @@ pub fn test_get_native_context() { unsafe { clear(&env.gl, &[0, 255, 0, 255]); - let mut other_context = env - .device + let concrete_device: &mut ConcreteDevice = (&mut env.device) + .try_into() + .expect("Device should belong to this backend"); + let mut other_context = concrete_device .create_context_from_native_context(native_context) .unwrap(); diff --git a/src/unix.rs b/src/unix.rs index affd9657..284923e7 100644 --- a/src/unix.rs +++ b/src/unix.rs @@ -4,30 +4,14 @@ /// Wayland or X11 display server connections. pub mod connection { - use crate::mesa_surfaceless::device::SurfacelessMesaDevice as SWDevice; + use crate::mesa_surfaceless::connection::SurfacelessMesaConnection as SWConnection; use crate::multi::connection::Connection as MultiConnection; - use crate::multi::device::Device as MultiDevice; - use crate::wayland::device::WaylandDevice; - use crate::x11::device::X11Device; - type HWDevice = MultiDevice; + use crate::wayland::connection::WaylandConnection; + use crate::x11::connection::X11Connection; + type HWConnection = MultiConnection; /// Either a Wayland or an X11 display server connection. - pub type Connection = MultiConnection; -} - -/// Thread-local handles to devices. -pub mod device { - use crate::mesa_surfaceless::device::SurfacelessMesaDevice as SWDevice; - use crate::wayland::device::WaylandDevice; - use crate::x11::device::X11Device; - - use crate::multi::device::Device as MultiDevice; - type HWDevice = MultiDevice; - - /// A thread-local handle to a device. - /// - /// Devices contain most of the relevant surface management methods. - pub type Device = MultiDevice; + pub type Connection = MultiConnection; } /// Hardware buffers of pixels. diff --git a/src/wayland/connection.rs b/src/wayland/connection.rs index 80bfc188..ebec5e5c 100644 --- a/src/wayland/connection.rs +++ b/src/wayland/connection.rs @@ -6,8 +6,8 @@ use crate::base::egl::ffi::EGL_PLATFORM_WAYLAND_KHR; use crate::egl::types::{EGLAttrib, EGLDisplay}; use crate::free_unix::adapter::FreeUnixAdapter; use crate::info::GLApi; -use crate::Error; use crate::{egl, Adapter, AdapterPreferences}; +use crate::{Device, Error}; use std::os::raw::c_void; use std::ptr; @@ -77,8 +77,8 @@ impl WaylandConnection { /// /// Device handles are local to a single thread. #[inline] - pub fn create_device(&self, adapter: &Adapter) -> Result { - WaylandDevice::new(self, adapter.free_unix()?) + pub fn create_device(&self, adapter: &Adapter) -> Result { + WaylandDevice::new(self, adapter.free_unix()?).map(Device::from) } /// Opens the hardware device corresponding to the adapter wrapped in the given native diff --git a/src/wayland/mod.rs b/src/wayland/mod.rs index 1b81dabb..70e5c242 100644 --- a/src/wayland/mod.rs +++ b/src/wayland/mod.rs @@ -5,12 +5,12 @@ pub mod context; pub mod device; pub mod surface; -crate::implement_interfaces!(WaylandConnection, WaylandDevice); +crate::implement_interfaces!(WaylandConnection); #[cfg(test)] use self::connection::WaylandConnection as Connection; #[cfg(test)] -use self::device::WaylandDevice as Device; +use self::device::WaylandDevice as ConcreteDevice; #[cfg(test)] #[path = "../tests.rs"] mod tests; diff --git a/src/wgl/connection.rs b/src/wgl/connection.rs index cbc9f674..88efbb49 100644 --- a/src/wgl/connection.rs +++ b/src/wgl/connection.rs @@ -4,7 +4,7 @@ use super::adapter::WglAdapter; use super::device::{NativeDevice, WglDevice}; -use crate::{Adapter, AdapterPreferences, Error, GLApi}; +use crate::{Adapter, AdapterPreferences, Device, Error, GLApi}; /// Represents a connection to the display server. /// @@ -51,8 +51,8 @@ impl WglConnection { /// Opens a device. #[inline] - pub fn create_device(&self, adapter: &Adapter) -> Result { - WglDevice::new(adapter.wgl()?) + pub fn create_device(&self, adapter: &Adapter) -> Result { + WglDevice::new(adapter.wgl()?).map(Device::from) } /// Creates a `Device` from a Direct3D 11 device and associated GL/DX interop handle. diff --git a/src/wgl/mod.rs b/src/wgl/mod.rs index fedcc698..c3fa35b3 100644 --- a/src/wgl/mod.rs +++ b/src/wgl/mod.rs @@ -8,12 +8,12 @@ pub mod context; pub mod device; pub mod surface; -crate::implement_interfaces!(WglConnection, WglDevice); +crate::implement_interfaces!(WglConnection); #[cfg(test)] use self::connection::WglConnection as Connection; #[cfg(test)] -use self::device::WglDevice as Device; +use self::device::WglDevice as ConcreteDevice; #[cfg(test)] #[path = "../tests.rs"] mod tests; diff --git a/src/x11/connection.rs b/src/x11/connection.rs index 6b5f7e6c..2034c7f9 100644 --- a/src/x11/connection.rs +++ b/src/x11/connection.rs @@ -7,7 +7,7 @@ use crate::egl::types::{EGLAttrib, EGLDisplay}; use crate::error::Error; use crate::free_unix::adapter::FreeUnixAdapter; use crate::info::GLApi; -use crate::{egl, Adapter, AdapterPreferences}; +use crate::{egl, Adapter, AdapterPreferences, Device}; use std::marker::PhantomData; use std::os::raw::c_void; @@ -156,8 +156,8 @@ impl X11Connection { /// /// Device handles are local to a single thread. #[inline] - pub fn create_device(&self, adapter: &Adapter) -> Result { - X11Device::new(self, adapter.free_unix()?) + pub fn create_device(&self, adapter: &Adapter) -> Result { + X11Device::new(self, adapter.free_unix()?).map(Device::from) } /// Opens the hardware device corresponding to the adapter wrapped in the given native diff --git a/src/x11/mod.rs b/src/x11/mod.rs index dd5d51c2..143f8fab 100644 --- a/src/x11/mod.rs +++ b/src/x11/mod.rs @@ -5,12 +5,12 @@ pub mod context; pub mod device; pub mod surface; -crate::implement_interfaces!(X11Connection, X11Device); +crate::implement_interfaces!(X11Connection); #[cfg(test)] use self::connection::X11Connection as Connection; #[cfg(test)] -use self::device::X11Device as Device; +use self::device::X11Device as ConcreteDevice; #[cfg(test)] #[path = "../tests.rs"] mod tests;