diff --git a/examples/chaos_game.rs b/examples/chaos_game.rs index 37f24abc..af44a786 100644 --- a/examples/chaos_game.rs +++ b/examples/chaos_game.rs @@ -39,7 +39,7 @@ fn main() { } let connection = SystemConnection::new().unwrap(); - let adapter = connection.create_adapter().unwrap(); + let adapter = connection.create_adapter(Default::default()).unwrap(); let mut device = connection.create_device(&adapter).unwrap(); let event_loop = EventLoop::new().unwrap(); diff --git a/examples/offscreen.rs b/examples/offscreen.rs index 6929879c..703bb2be 100644 --- a/examples/offscreen.rs +++ b/examples/offscreen.rs @@ -12,7 +12,10 @@ use std::fs::File; use std::mem; use std::path::Path; use std::slice; -use surfman::{Connection, ContextAttributeFlags, ContextAttributes, GLApi, GLVersion}; +use surfman::{ + AdapterPreferences, Connection, ContextAttributeFlags, ContextAttributes, GLApi, GLVersion, + RenderingPreference, +}; use surfman::{SurfaceAccess, SurfaceType}; mod common; @@ -85,13 +88,17 @@ fn main() { let connection = Connection::new().unwrap(); - let adapter = if matches.is_present("software") { - connection.create_software_adapter().unwrap() - } else if matches.is_present("hardware") { - connection.create_hardware_adapter().unwrap() + let rendering = if matches.is_present("software") { + RenderingPreference::Software } else { - connection.create_adapter().unwrap() + RenderingPreference::Hardware }; + let adapter = connection + .create_adapter(AdapterPreferences { + rendering, + ..Default::default() + }) + .unwrap(); let output_path = Path::new(matches.value_of("OUTPUT").unwrap()).to_owned(); let output_file = File::create(output_path).unwrap(); diff --git a/examples/threads.rs b/examples/threads.rs index 7bea5da0..7f03bdb4 100644 --- a/examples/threads.rs +++ b/examples/threads.rs @@ -14,7 +14,9 @@ use surfman::{Adapter, Connection, Context, ContextDescriptor, Device, GLApi, Su use self::common::FilesystemResourceLoader; #[cfg(not(target_os = "android"))] -use surfman::{ContextAttributeFlags, ContextAttributes, GLVersion}; +use surfman::{ + AdapterPreferences, ContextAttributeFlags, ContextAttributes, GLVersion, PowerPreference, +}; #[cfg(not(target_os = "android"))] use winit::{ dpi::PhysicalSize, @@ -134,7 +136,12 @@ fn main() { let window_size = window.inner_size(); let window_size = Size2D::new(window_size.width as i32, window_size.height as i32); let native_widget = make_native_widget(&window, &connection, window_size); - let adapter = connection.create_low_power_adapter().unwrap(); + let adapter = connection + .create_adapter(AdapterPreferences { + power: PowerPreference::LowPower, + ..Default::default() + }) + .unwrap(); let device = connection.create_device(&adapter).unwrap(); let context_attributes = ContextAttributes { diff --git a/src/adapter.rs b/src/adapter.rs index a33ea66c..354c53a4 100644 --- a/src/adapter.rs +++ b/src/adapter.rs @@ -16,6 +16,36 @@ use crate::hardware_buffer::adapter::HardwareBufferAdapter; use crate::wgl::adapter::WglAdapter; use crate::Error; +/// A power usage preference for selecting an adapter. +#[derive(Copy, Clone, Debug, Default)] +pub enum PowerPreference { + /// Prefer a high-performance adapter. + #[default] + HighPerformance, + /// Prefer a low-power adapter. + LowPower, +} + +/// A hardware/software preference for selecting an adapter. +#[derive(Copy, Clone, Debug, Default)] +pub enum RenderingPreference { + /// Prefer a hardware adapter. + #[default] + Hardware, + /// Prefer a software adapter. + Software, +} + +/// A set of options to use when choosing an adapter. The default preference is +/// for a high-power hardware adapter. +#[derive(Copy, Clone, Debug, Default)] +pub struct AdapterPreferences { + /// The [`PowerPreference`] for choosing an adapter. + pub power: PowerPreference, + /// The [`RenderingPreference`] for choosing an adapter. + pub rendering: RenderingPreference, +} + /// Represents a hardware display adapter that can be used for rendering (including the CPU). /// /// Adapters can be sent between threads. To render with an adapter, open a thread-local `Device`. diff --git a/src/angle/adapter.rs b/src/angle/adapter.rs index cc19ca25..ea41269f 100644 --- a/src/angle/adapter.rs +++ b/src/angle/adapter.rs @@ -72,7 +72,6 @@ impl AngleAdapter { let choose_this = match vendor_preference { VendorPreference::Prefer(vendor_id) => vendor_id == adapter_desc.VendorId, VendorPreference::Avoid(vendor_id) => vendor_id != adapter_desc.VendorId, - VendorPreference::None => true, }; if choose_this { let mut dxgi_adapter: *mut IDXGIAdapter = ptr::null_mut(); diff --git a/src/angle/connection.rs b/src/angle/connection.rs index d2613311..b46a5c57 100644 --- a/src/angle/connection.rs +++ b/src/angle/connection.rs @@ -9,7 +9,7 @@ use super::adapter::AngleAdapter; use super::device::{Device, NativeDevice, VendorPreference}; use super::surface::NativeWidget; use crate::egl::types::{EGLDisplay, EGLNativeWindowType}; -use crate::{Adapter, Error, GLApi}; +use crate::{Adapter, AdapterPreferences, Error, GLApi, PowerPreference, RenderingPreference}; use euclid::default::Size2D; @@ -63,38 +63,18 @@ impl Connection { GLApi::GLES } - /// Returns the "best" adapter on this system, preferring high-performance hardware adapters. - /// - /// This is an alias for `Connection::create_hardware_adapter()`. - #[inline] - pub fn create_adapter(&self) -> Result { - self.create_hardware_adapter() - } - - /// Returns the "best" adapter on this system, preferring high-performance hardware adapters. - #[inline] - pub fn create_hardware_adapter(&self) -> Result { - AngleAdapter::new( - D3D_DRIVER_TYPE_UNKNOWN, - VendorPreference::Avoid(INTEL_PCI_ID), - ) - .map(Into::into) - } - - /// Returns the "best" adapter on this system, preferring low-power hardware adapters. - #[inline] - pub fn create_low_power_adapter(&self) -> Result { - AngleAdapter::new( - D3D_DRIVER_TYPE_UNKNOWN, - VendorPreference::Prefer(INTEL_PCI_ID), - ) - .map(Into::into) - } - - /// Returns the "best" adapter on this system, preferring software adapters. + /// Returns an adapter on this system according to the provided preferences. #[inline] - pub fn create_software_adapter(&self) -> Result { - AngleAdapter::new(D3D_DRIVER_TYPE_WARP, VendorPreference::None).map(Into::into) + pub fn create_adapter(&self, preferences: AdapterPreferences) -> Result { + let driver_type = match preferences.rendering { + RenderingPreference::Hardware => D3D_DRIVER_TYPE_UNKNOWN, + RenderingPreference::Software => D3D_DRIVER_TYPE_WARP, + }; + let vendor_preference = match preferences.power { + PowerPreference::HighPerformance => VendorPreference::Avoid(INTEL_PCI_ID), + PowerPreference::LowPower => VendorPreference::Prefer(INTEL_PCI_ID), + }; + AngleAdapter::new(driver_type, vendor_preference).map(Into::into) } /// Opens the hardware device corresponding to the given adapter. diff --git a/src/angle/device.rs b/src/angle/device.rs index cd188308..88c6b4c5 100644 --- a/src/angle/device.rs +++ b/src/angle/device.rs @@ -54,7 +54,6 @@ pub struct Device { } pub(crate) enum VendorPreference { - None, Prefer(UINT), Avoid(UINT), } diff --git a/src/base/io_surface/connection.rs b/src/base/io_surface/connection.rs index df8583f0..92d4f36e 100644 --- a/src/base/io_surface/connection.rs +++ b/src/base/io_surface/connection.rs @@ -6,6 +6,7 @@ use super::adapter::AppleAdapter; use super::device::{Device, NativeDevice}; use super::surface::NativeWidget; +use crate::adapter::{AdapterPreferences, PowerPreference, RenderingPreference}; use crate::Error; use objc2::rc::Retained; @@ -67,32 +68,12 @@ impl Connection { NativeConnection } - /// Returns the "best" adapter on this system, preferring high-performance hardware adapters. - /// - /// This is an alias for `Connection::create_hardware_adapter()`. - #[inline] - pub fn create_adapter(&self) -> Result { - self.create_hardware_adapter() - } - - /// Returns the "best" adapter on this system, preferring high-performance hardware adapters. - #[inline] - pub fn create_hardware_adapter(&self) -> Result { - Ok(AppleAdapter { - is_low_power: false, - }) - } - - /// Returns the "best" adapter on this system, preferring low-power hardware adapters. - #[inline] - pub fn create_low_power_adapter(&self) -> Result { - Ok(AppleAdapter { is_low_power: true }) - } - - /// Returns the "best" adapter on this system, preferring software adapters. + /// Returns an adapter on this system according to the provided preferences. #[inline] - pub fn create_software_adapter(&self) -> Result { - self.create_low_power_adapter() + pub fn create_adapter(&self, preferences: AdapterPreferences) -> Result { + let is_low_power = matches!(preferences.power, PowerPreference::LowPower) + || matches!(preferences.rendering, RenderingPreference::Software); + Ok(AppleAdapter { is_low_power }) } /// Opens the hardware device corresponding to the given adapter. @@ -109,7 +90,7 @@ impl Connection { &self, _: NativeDevice, ) -> Result { - self.create_device(&self.create_adapter()?) + self.create_device(&self.create_adapter(Default::default())?) } /// Opens the display connection corresponding to the given `DisplayHandle`. diff --git a/src/cgl/connection.rs b/src/cgl/connection.rs index 5e584b30..2ee2fb43 100644 --- a/src/cgl/connection.rs +++ b/src/cgl/connection.rs @@ -4,7 +4,7 @@ //! global window server connection. use super::device::Device; -use crate::adapter::Adapter; +use crate::adapter::{Adapter, AdapterPreferences}; use crate::base::io_surface::connection::Connection as SystemConnection; use crate::base::io_surface::device::NativeDevice; use crate::base::io_surface::surface::NativeWidget; @@ -48,30 +48,10 @@ impl Connection { GLApi::GL } - /// Returns the "best" adapter on this system, preferring high-performance hardware adapters. - /// - /// This is an alias for `Connection::create_hardware_adapter()`. - #[inline] - pub fn create_adapter(&self) -> Result { - self.0.create_adapter().map(Into::into) - } - - /// Returns the "best" adapter on this system, preferring high-performance hardware adapters. - #[inline] - pub fn create_hardware_adapter(&self) -> Result { - self.0.create_hardware_adapter().map(Into::into) - } - - /// Returns the "best" adapter on this system, preferring low-power hardware adapters. - #[inline] - pub fn create_low_power_adapter(&self) -> Result { - self.0.create_low_power_adapter().map(Into::into) - } - - /// Returns the "best" adapter on this system, preferring software adapters. + /// Returns an adapter on this system according to the provided preferences. #[inline] - pub fn create_software_adapter(&self) -> Result { - self.0.create_software_adapter().map(Into::into) + pub fn create_adapter(&self, preferences: AdapterPreferences) -> Result { + self.0.create_adapter(preferences).map(Into::into) } /// Opens the hardware device corresponding to the given adapter. diff --git a/src/connection.rs b/src/connection.rs index d9adb0aa..940913a5 100644 --- a/src/connection.rs +++ b/src/connection.rs @@ -1,5 +1,6 @@ //! The abstract interface that all connections conform to. +use crate::adapter::AdapterPreferences; use crate::Adapter; use crate::Error; use crate::GLApi; @@ -21,19 +22,8 @@ pub trait Connection: Sized { /// Returns the OpenGL API flavor that this connection supports (OpenGL or OpenGL ES). fn gl_api(&self) -> GLApi; - /// Returns the "best" adapter on this system, preferring high-performance hardware adapters. - /// - /// This is an alias for `Connection::create_hardware_adapter()`. - fn create_adapter(&self) -> Result; - - /// Returns the "best" adapter on this system, preferring high-performance hardware adapters. - fn create_hardware_adapter(&self) -> Result; - - /// Returns the "best" adapter on this system, preferring low-power hardware adapters. - fn create_low_power_adapter(&self) -> Result; - - /// Returns the "best" adapter on this system, preferring software adapters. - fn create_software_adapter(&self) -> Result; + /// Returns an adapter on this system according to the provided preferences. + fn create_adapter(&self, preferences: AdapterPreferences) -> Result; /// Opens a device. fn create_device(&self, adapter: &Adapter) -> Result; diff --git a/src/free_unix/adapter.rs b/src/free_unix/adapter.rs index 467bf3f9..17d35153 100644 --- a/src/free_unix/adapter.rs +++ b/src/free_unix/adapter.rs @@ -4,6 +4,7 @@ //! A hardware display adapter on Wayland / X11 systems. +use crate::{AdapterPreferences, PowerPreference, RenderingPreference}; use std::env; static MESA_SOFTWARE_RENDERING_ENV_VAR: &str = "LIBGL_ALWAYS_SOFTWARE"; @@ -11,49 +12,23 @@ static MESA_DRI_PRIME_ENV_VAR: &str = "DRI_PRIME"; /// An implementation of [`crate::Adapter`] for Wayland / X11 platforms. #[derive(Clone, Debug)] -pub enum FreeUnixAdapter { - #[doc(hidden)] - Hardware, - #[doc(hidden)] - HardwarePrime, - #[doc(hidden)] - Software, -} +pub struct FreeUnixAdapter(AdapterPreferences); impl FreeUnixAdapter { #[inline] - pub(crate) fn hardware() -> Self { - Self::HardwarePrime - } - - #[inline] - pub(crate) fn low_power() -> Self { - Self::Hardware - } - - #[inline] - pub(crate) fn software() -> Self { - Self::Software + pub(crate) fn new(preferences: AdapterPreferences) -> Self { + Self(preferences) } pub(crate) fn set_environment_variables(&self) { - match *self { - Self::Hardware | Self::HardwarePrime => { - env::remove_var(MESA_SOFTWARE_RENDERING_ENV_VAR); - } - Self::Software => { - env::set_var(MESA_SOFTWARE_RENDERING_ENV_VAR, "1"); - } - } - - match *self { - Self::Software => {} - Self::Hardware => { - env::remove_var(MESA_DRI_PRIME_ENV_VAR); - } - Self::HardwarePrime => { - env::set_var(MESA_DRI_PRIME_ENV_VAR, "1"); - } + env::remove_var(MESA_SOFTWARE_RENDERING_ENV_VAR); + env::remove_var(MESA_DRI_PRIME_ENV_VAR); + match self.0.rendering { + RenderingPreference::Hardware => match self.0.power { + PowerPreference::HighPerformance => env::set_var(MESA_DRI_PRIME_ENV_VAR, "1"), + PowerPreference::LowPower => {} + }, + RenderingPreference::Software => env::set_var(MESA_SOFTWARE_RENDERING_ENV_VAR, "1"), } } } diff --git a/src/hardware_buffer/connection.rs b/src/hardware_buffer/connection.rs index e43aaae9..d95f58c7 100644 --- a/src/hardware_buffer/connection.rs +++ b/src/hardware_buffer/connection.rs @@ -5,7 +5,7 @@ use super::adapter::HardwareBufferAdapter; use super::device::{Device, NativeDevice}; use super::surface::NativeWidget; -use crate::{Adapter, Error, GLApi}; +use crate::{Adapter, AdapterPreferences, Error, GLApi}; #[cfg(android_platform)] use super::android_ffi::ANativeWindow; @@ -49,29 +49,9 @@ impl Connection { GLApi::GLES } - /// Returns the "best" adapter on this system. - /// - /// This is an alias for `Connection::create_hardware_adapter()`. - #[inline] - pub fn create_adapter(&self) -> Result { - self.create_hardware_adapter() - } - - /// Returns the "best" adapter on this system, preferring high-performance hardware adapters. - #[inline] - pub fn create_hardware_adapter(&self) -> Result { - Ok(HardwareBufferAdapter.into()) - } - - /// Returns the "best" adapter on this system, preferring low-power hardware adapters. - #[inline] - pub fn create_low_power_adapter(&self) -> Result { - Ok(HardwareBufferAdapter.into()) - } - - /// Returns the "best" adapter on this system, preferring software adapters. + /// Returns an adapter on this system according to the provided preferences. #[inline] - pub fn create_software_adapter(&self) -> Result { + pub fn create_adapter(&self, _: AdapterPreferences) -> Result { Ok(HardwareBufferAdapter.into()) } diff --git a/src/lib.rs b/src/lib.rs index 2c32ca9d..5db995ce 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -63,7 +63,7 @@ pub use crate::context::{ContextAttributeFlags, ContextAttributes, ContextID}; pub use crate::error::{Error, WindowingApiError}; pub use crate::info::{GLApi, GLVersion}; pub use crate::surface::{SurfaceAccess, SurfaceID, SurfaceInfo, SurfaceType, SystemSurfaceInfo}; -pub use adapter::Adapter; +pub use adapter::{Adapter, AdapterPreferences, PowerPreference, RenderingPreference}; pub use default::connection::Connection; pub use default::context::{Context, ContextDescriptor}; pub use default::device::Device; diff --git a/src/macros.rs b/src/macros.rs index 24bb85bf..d747120e 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -41,7 +41,7 @@ macro_rules! implement_interfaces { use euclid::default::Size2D; use glow::Texture; use std::os::raw::c_void; - use $crate::adapter::Adapter; + use $crate::adapter::{Adapter, AdapterPreferences}; use $crate::connection::Connection as ConnectionInterface; use $crate::device::Device as DeviceInterface; use $crate::info::GLApi; @@ -63,23 +63,11 @@ macro_rules! implement_interfaces { } #[inline] - fn create_adapter(&self) -> Result { - Connection::create_adapter(self) - } - - #[inline] - fn create_hardware_adapter(&self) -> Result { - Connection::create_hardware_adapter(self) - } - - #[inline] - fn create_low_power_adapter(&self) -> Result { - Connection::create_low_power_adapter(self) - } - - #[inline] - fn create_software_adapter(&self) -> Result { - Connection::create_software_adapter(self) + fn create_adapter( + &self, + preferences: AdapterPreferences, + ) -> Result { + Connection::create_adapter(self, preferences) } #[inline] diff --git a/src/mesa_surfaceless/connection.rs b/src/mesa_surfaceless/connection.rs index 2284ea22..97ecdd0d 100644 --- a/src/mesa_surfaceless/connection.rs +++ b/src/mesa_surfaceless/connection.rs @@ -8,7 +8,7 @@ use crate::egl::types::{EGLAttrib, EGLDisplay}; use crate::free_unix::adapter::FreeUnixAdapter; use crate::info::GLApi; use crate::Error; -use crate::{egl, Adapter}; +use crate::{egl, Adapter, AdapterPreferences}; use euclid::default::Size2D; @@ -86,34 +86,10 @@ impl Connection { GLApi::GL } - /// Returns the "best" adapter on this system, preferring high-performance hardware adapters. - /// - /// This is an alias for `Connection::create_hardware_adapter()`. - #[inline] - pub fn create_adapter(&self) -> Result { - self.create_hardware_adapter() - } - - /// Returns the "best" adapter on this system, preferring high-performance hardware adapters. - /// - /// On the OSMesa backend, this returns a software adapter. - #[inline] - pub fn create_hardware_adapter(&self) -> Result { - Ok(FreeUnixAdapter::hardware().into()) - } - - /// Returns the "best" adapter on this system, preferring low-power hardware adapters. - /// - /// On the OSMesa backend, this returns a software adapter. - #[inline] - pub fn create_low_power_adapter(&self) -> Result { - Ok(FreeUnixAdapter::low_power().into()) - } - - /// Returns the "best" adapter on this system, preferring software adapters. + /// Returns an adapter on this system according to the provided preferences. #[inline] - pub fn create_software_adapter(&self) -> Result { - Ok(FreeUnixAdapter::software().into()) + pub fn create_adapter(&self, preferences: AdapterPreferences) -> Result { + Ok(FreeUnixAdapter::new(preferences).into()) } /// Opens the hardware device corresponding to the given adapter. @@ -130,7 +106,7 @@ impl Connection { &self, _: NativeDevice, ) -> Result { - Device::new(self, &self.create_adapter()?) + Device::new(self, &self.create_adapter(Default::default())?) } /// Opens the display connection corresponding to the given `DisplayHandle`. diff --git a/src/multi/connection.rs b/src/multi/connection.rs index a2b168a5..c5cff495 100644 --- a/src/multi/connection.rs +++ b/src/multi/connection.rs @@ -2,6 +2,7 @@ use super::device::Device; use super::surface::NativeWidget; +use crate::adapter::AdapterPreferences; use crate::connection::Connection as ConnectionInterface; use crate::device::Device as DeviceInterface; use crate::GLApi; @@ -64,37 +65,11 @@ where } } - /// Returns the "best" adapter on this system. - /// - /// This is an alias for `Connection::create_hardware_adapter()`. - pub fn create_adapter(&self) -> Result { - match *self { - Self::Default(ref connection) => connection.create_adapter(), - Self::Alternate(ref connection) => connection.create_adapter(), - } - } - - /// Returns the "best" adapter on this system, preferring high-performance hardware adapters. - pub fn create_hardware_adapter(&self) -> Result { - match *self { - Self::Default(ref connection) => connection.create_hardware_adapter(), - Self::Alternate(ref connection) => connection.create_hardware_adapter(), - } - } - - /// Returns the "best" adapter on this system, preferring low-power hardware adapters. - pub fn create_low_power_adapter(&self) -> Result { - match *self { - Self::Default(ref connection) => connection.create_low_power_adapter(), - Self::Alternate(ref connection) => connection.create_low_power_adapter(), - } - } - - /// Returns the "best" adapter on this system, preferring software adapters. - pub fn create_software_adapter(&self) -> Result { + /// Returns an adapter on this system according to the provided preferences. + pub fn create_adapter(&self, preferences: AdapterPreferences) -> Result { match *self { - Self::Default(ref connection) => connection.create_software_adapter(), - Self::Alternate(ref connection) => connection.create_software_adapter(), + Self::Default(ref connection) => connection.create_adapter(preferences), + Self::Alternate(ref connection) => connection.create_adapter(preferences), } } @@ -172,23 +147,8 @@ where } #[inline] - fn create_adapter(&self) -> Result { - Connection::create_adapter(self) - } - - #[inline] - fn create_hardware_adapter(&self) -> Result { - Connection::create_hardware_adapter(self) - } - - #[inline] - fn create_low_power_adapter(&self) -> Result { - Connection::create_low_power_adapter(self) - } - - #[inline] - fn create_software_adapter(&self) -> Result { - Connection::create_software_adapter(self) + fn create_adapter(&self, preferences: AdapterPreferences) -> Result { + Connection::create_adapter(self, preferences) } #[inline] diff --git a/src/tests.rs b/src/tests.rs index 38fd6559..8a8d9942 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -10,8 +10,8 @@ use super::connection::Connection; use super::context::{Context, ContextDescriptor, NativeContext}; use super::device::Device; use super::surface::Surface; -use crate::gl; -use crate::Adapter; +use crate::{gl, AdapterPreferences, PowerPreference}; +use crate::{Adapter, RenderingPreference}; use crate::{ContextAttributeFlags, ContextAttributes, Error, GLApi, GLVersion, Gl, SurfaceAccess}; use crate::{SurfaceType, WindowingApiError}; @@ -39,17 +39,31 @@ static GL_ES_VERSIONS: [GLVersion; 4] = [ #[cfg_attr(not(feature = "sm-test"), test)] pub fn test_adapter_creation() { let connection = Connection::new().unwrap(); - connection.create_hardware_adapter().unwrap(); - connection.create_low_power_adapter().unwrap(); - connection.create_software_adapter().unwrap(); + connection.create_adapter(Default::default()).unwrap(); + connection + .create_adapter(AdapterPreferences { + power: PowerPreference::LowPower, + ..Default::default() + }) + .unwrap(); + connection + .create_adapter(AdapterPreferences { + rendering: RenderingPreference::Software, + ..Default::default() + }) + .unwrap(); + connection + .create_adapter(AdapterPreferences { + rendering: RenderingPreference::Software, + power: PowerPreference::LowPower, + }) + .unwrap(); } #[cfg_attr(not(feature = "sm-test"), test)] pub fn test_device_creation() { let connection = Connection::new().unwrap(); - let adapter = connection - .create_low_power_adapter() - .expect("Failed to create adapter!"); + let adapter = low_power_adapter(&connection); match connection.create_device(&adapter) { Ok(_) => {} Err(Error::RequiredExtensionUnavailable) => { @@ -62,7 +76,7 @@ pub fn test_device_creation() { #[cfg_attr(not(feature = "sm-test"), test)] pub fn test_device_accessors() { let connection = Connection::new().unwrap(); - let adapter = connection.create_low_power_adapter().unwrap(); + let adapter = low_power_adapter(&connection); let device = match connection.create_device(&adapter) { Ok(device) => device, Err(Error::RequiredExtensionUnavailable) => { @@ -80,9 +94,7 @@ pub fn test_device_accessors() { #[cfg_attr(not(feature = "sm-test"), test)] pub fn test_context_creation() { let connection = Connection::new().unwrap(); - let adapter = connection - .create_low_power_adapter() - .expect("Failed to create adapter!"); + let adapter = low_power_adapter(&connection); let device = match connection.create_device(&adapter) { Ok(device) => device, Err(Error::RequiredExtensionUnavailable) => { @@ -168,9 +180,7 @@ pub fn test_context_creation() { #[cfg_attr(not(feature = "sm-test"), test)] pub fn test_newly_created_contexts_are_current() { let connection = Connection::new().unwrap(); - let adapter = connection - .create_low_power_adapter() - .expect("Failed to create adapter!"); + let adapter = low_power_adapter(&connection); let mut device = match connection.create_device(&adapter) { Ok(device) => device, Err(Error::RequiredExtensionUnavailable) => { @@ -234,9 +244,7 @@ pub fn test_newly_created_contexts_are_current() { #[cfg_attr(not(feature = "sm-test"), test)] pub fn test_context_sharing() { let connection = Connection::new().unwrap(); - let adapter = connection - .create_low_power_adapter() - .expect("Failed to create adapter!"); + let adapter = low_power_adapter(&connection); let device = match connection.create_device(&adapter) { Ok(device) => device, Err(Error::RequiredExtensionUnavailable) => { @@ -274,9 +282,7 @@ pub fn test_context_sharing() { #[cfg_attr(not(feature = "sm-test"), test)] pub fn test_generic_surface_creation() { let connection = Connection::new().unwrap(); - let adapter = connection - .create_low_power_adapter() - .expect("Failed to create adapter!"); + let adapter = low_power_adapter(&connection); let device = match connection.create_device(&adapter) { Ok(device) => device, Err(Error::RequiredExtensionUnavailable) => { @@ -748,9 +754,7 @@ pub fn test_depth_and_stencil() { use glow::PixelPackData; let connection = Connection::new().unwrap(); - let adapter = connection - .create_low_power_adapter() - .expect("Failed to create adapter!"); + let adapter = low_power_adapter(&connection); let mut device = match connection.create_device(&adapter) { Ok(device) => device, Err(Error::RequiredExtensionUnavailable) => { @@ -970,6 +974,15 @@ fn make_fbo(gl: &Gl, texture_target: u32, texture: Option) -> Framebuff } } +fn low_power_adapter(connection: &Connection) -> Adapter { + connection + .create_adapter(AdapterPreferences { + power: PowerPreference::LowPower, + ..Default::default() + }) + .expect("Could not create low power adapter") +} + struct BasicEnvironment { connection: Connection, adapter: Adapter, @@ -983,8 +996,11 @@ impl BasicEnvironment { fn new() -> Option { let connection = Connection::new().unwrap(); let adapter = connection - .create_low_power_adapter() - .expect("Failed to create adapter!"); + .create_adapter(AdapterPreferences { + power: PowerPreference::LowPower, + ..Default::default() + }) + .unwrap(); let mut device = match connection.create_device(&adapter) { Ok(device) => device, Err(Error::RequiredExtensionUnavailable) => { diff --git a/src/wayland/connection.rs b/src/wayland/connection.rs index 58006d8b..6c304af4 100644 --- a/src/wayland/connection.rs +++ b/src/wayland/connection.rs @@ -8,7 +8,7 @@ use crate::egl::types::{EGLAttrib, EGLDisplay}; use crate::free_unix::adapter::FreeUnixAdapter; use crate::info::GLApi; use crate::Error; -use crate::{egl, Adapter}; +use crate::{egl, Adapter, AdapterPreferences}; use euclid::default::Size2D; use std::os::raw::c_void; @@ -69,30 +69,10 @@ impl Connection { } } - /// Returns the "best" adapter on this system, preferring high-performance hardware adapters. - /// - /// This is an alias for `Connection::create_hardware_adapter()`. - #[inline] - pub fn create_adapter(&self) -> Result { - self.create_hardware_adapter() - } - - /// Returns the "best" adapter on this system, preferring high-performance hardware adapters. - #[inline] - pub fn create_hardware_adapter(&self) -> Result { - Ok(FreeUnixAdapter::hardware().into()) - } - - /// Returns the "best" adapter on this system, preferring low-power hardware adapters. - #[inline] - pub fn create_low_power_adapter(&self) -> Result { - Ok(FreeUnixAdapter::low_power().into()) - } - - /// Returns the "best" adapter on this system, preferring software adapters. + /// Returns an adapter on this system according to the provided preferences. #[inline] - pub fn create_software_adapter(&self) -> Result { - Ok(FreeUnixAdapter::software().into()) + pub fn create_adapter(&self, preferences: AdapterPreferences) -> Result { + Ok(FreeUnixAdapter::new(preferences).into()) } /// Opens the hardware device corresponding to the given adapter. diff --git a/src/wgl/adapter.rs b/src/wgl/adapter.rs index 0df98e65..febb14af 100644 --- a/src/wgl/adapter.rs +++ b/src/wgl/adapter.rs @@ -4,6 +4,7 @@ //! A hardware display adapter for WGL on Windows systems. +use crate::{AdapterPreferences, PowerPreference, RenderingPreference}; use log::warn; use std::ffi::CStr; use winapi::um::libloaderapi; @@ -13,14 +14,13 @@ static AMD_GPU_SELECT_SYMBOL: &CStr = c"AmdPowerXpressRequestHighPerformance"; /// An implementation of [`crate::Adapter`] for WGL (Windows) platforms. #[derive(Clone, Debug)] -pub enum WglAdapter { - #[doc(hidden)] - HighPerformance, - #[doc(hidden)] - LowPower, -} +pub struct WglAdapter(AdapterPreferences); impl WglAdapter { + pub(crate) fn new(preferences: AdapterPreferences) -> Self { + Self(preferences) + } + pub(crate) fn set_exported_variables(&self) { unsafe { let current_module = libloaderapi::GetModuleHandleA(std::ptr::null()); @@ -48,10 +48,12 @@ impl WglAdapter { ); return; } - let value = match *self { - Self::HighPerformance => 1, - Self::LowPower => 0, + + let value = match (self.0.power, self.0.rendering) { + (PowerPreference::LowPower, _) | (_, RenderingPreference::Software) => 0, + (PowerPreference::HighPerformance, _) => 1, }; + *nvidia_gpu_select_variable = value; *amd_gpu_select_variable = value; } diff --git a/src/wgl/connection.rs b/src/wgl/connection.rs index f6376fb4..00b0501d 100644 --- a/src/wgl/connection.rs +++ b/src/wgl/connection.rs @@ -5,7 +5,7 @@ use super::adapter::WglAdapter; use super::device::{Device, NativeDevice}; use super::surface::NativeWidget; -use crate::{Adapter, Error, GLApi}; +use crate::{Adapter, AdapterPreferences, Error, GLApi}; use euclid::default::Size2D; @@ -50,30 +50,10 @@ impl Connection { GLApi::GL } - /// Returns the "best" adapter on this system, preferring high-performance hardware adapters. - /// - /// This is an alias for `Connection::create_hardware_adapter()`. - #[inline] - pub fn create_adapter(&self) -> Result { - self.create_hardware_adapter() - } - - /// Returns the "best" adapter on this system, preferring high-performance hardware adapters. - #[inline] - pub fn create_hardware_adapter(&self) -> Result { - Ok(WglAdapter::HighPerformance.into()) - } - - /// Returns the "best" adapter on this system, preferring low-power hardware adapters. - #[inline] - pub fn create_low_power_adapter(&self) -> Result { - Ok(WglAdapter::LowPower.into()) - } - - /// Returns the "best" adapter on this system, preferring software adapters. + /// Returns an adapter on this system according to the provided preferences. #[inline] - pub fn create_software_adapter(&self) -> Result { - self.create_low_power_adapter() + pub fn create_adapter(&self, preferences: AdapterPreferences) -> Result { + Ok(WglAdapter::new(preferences).into()) } /// Opens a device. diff --git a/src/wgl/device.rs b/src/wgl/device.rs index 90dd13df..683b4075 100644 --- a/src/wgl/device.rs +++ b/src/wgl/device.rs @@ -13,8 +13,8 @@ use crate::wgl::context::{ NativeContext, OPENGL_LIBRARY, WGL_EXTENSION_FUNCTIONS, }; use crate::wgl::surface::{NativeWidget, Surface, SurfaceDataGuard, SurfaceTexture, Win32Objects}; -use crate::Adapter; use crate::{gl, gl_utils, GLApi, Gl, SurfaceAccess, SurfaceType}; +use crate::{Adapter, AdapterPreferences, PowerPreference}; use crate::{ContextAttributeFlags, ContextAttributes, Error, GLVersion, SurfaceInfo}; use euclid::default::Size2D; use glow::HasContext; @@ -1238,11 +1238,16 @@ impl Adapter { let result = dxgi_adapter.GetDesc(&mut adapter_desc); assert_eq!(result, S_OK); - if adapter_desc.VendorId == INTEL_PCI_ID { - WglAdapter::LowPower + let power = if adapter_desc.VendorId == INTEL_PCI_ID { + PowerPreference::LowPower } else { - WglAdapter::HighPerformance - } + PowerPreference::HighPerformance + }; + + WglAdapter::new(AdapterPreferences { + power, + ..Default::default() + }) } } } diff --git a/src/x11/connection.rs b/src/x11/connection.rs index 36491308..b1ba4369 100644 --- a/src/x11/connection.rs +++ b/src/x11/connection.rs @@ -4,12 +4,11 @@ use super::device::{Device, NativeDevice}; use super::surface::NativeWidget; use crate::base::egl::device::EGL_FUNCTIONS; use crate::base::egl::ffi::EGL_PLATFORM_X11_KHR; -use crate::egl; use crate::egl::types::{EGLAttrib, EGLDisplay}; use crate::error::Error; use crate::free_unix::adapter::FreeUnixAdapter; use crate::info::GLApi; -use crate::Adapter; +use crate::{egl, Adapter, AdapterPreferences}; use euclid::default::Size2D; @@ -150,30 +149,10 @@ impl Connection { GLApi::GL } - /// Returns the "best" adapter on this system, preferring high-performance hardware adapters. - /// - /// This is an alias for `Connection::create_hardware_adapter()`. - #[inline] - pub fn create_adapter(&self) -> Result { - self.create_hardware_adapter() - } - - /// Returns the "best" adapter on this system, preferring high-performance hardware adapters. - #[inline] - pub fn create_hardware_adapter(&self) -> Result { - Ok(FreeUnixAdapter::hardware().into()) - } - - /// Returns the "best" adapter on this system, preferring low-power hardware adapters. - #[inline] - pub fn create_low_power_adapter(&self) -> Result { - Ok(FreeUnixAdapter::low_power().into()) - } - - /// Returns the "best" adapter on this system, preferring software adapters. + /// Returns an adapter on this system according to the provided preferences. #[inline] - pub fn create_software_adapter(&self) -> Result { - Ok(FreeUnixAdapter::software().into()) + pub fn create_adapter(&self, preferences: AdapterPreferences) -> Result { + Ok(FreeUnixAdapter::new(preferences).into()) } /// Opens the hardware device corresponding to the given adapter. @@ -310,10 +289,15 @@ mod tests { #[cfg_attr(not(feature = "sm-test"), test)] pub fn test_from_x11_display() { - use crate::{ContextAttributeFlags, ContextAttributes, GLVersion}; + use crate::{ContextAttributeFlags, ContextAttributes, GLVersion, PowerPreference}; let connection = Connection::new().unwrap(); - let adapter = connection.create_low_power_adapter().unwrap(); + let adapter = connection + .create_adapter(AdapterPreferences { + power: PowerPreference::LowPower, + ..Default::default() + }) + .unwrap(); let device = match connection.create_device(&adapter) { Ok(device) => device, Err(Error::RequiredExtensionUnavailable) => {