From 4b46e885fd28c955be89cff33ab55eb2f9191c83 Mon Sep 17 00:00:00 2001 From: Aaron Loucks Date: Sat, 11 Jan 2020 03:07:45 -0500 Subject: [PATCH 1/2] Prefer discrete GPU for PowerPreference::Default --- wgpu-core/src/instance.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wgpu-core/src/instance.rs b/wgpu-core/src/instance.rs index c1f31c3b5..fa2d15b9e 100644 --- a/wgpu-core/src/instance.rs +++ b/wgpu-core/src/instance.rs @@ -271,7 +271,7 @@ impl> Global { } let preferred_gpu = match desc.power_preference { - PowerPreference::Default => integrated.or(discrete).or(other).or(virt), + PowerPreference::Default => discrete.or(integrated).or(other).or(virt), PowerPreference::LowPower => integrated.or(other).or(discrete).or(virt), PowerPreference::HighPerformance => discrete.or(other).or(integrated).or(virt), }; From 5ca57374f61052385b209f29867d7e0ac8522379 Mon Sep 17 00:00:00 2001 From: Aaron Loucks Date: Sun, 12 Jan 2020 17:26:54 -0500 Subject: [PATCH 2/2] Check power/battery status when selecting adaptors PowerPreference::Default will now prefer discrete GPUs when on AC power and will prefer integrated GPUs while on battery power (i.e. the battery is discharging). --- examples/compute/CMakeLists.txt | 2 +- examples/triangle/CMakeLists.txt | 2 +- wgpu-core/Cargo.toml | 3 ++ wgpu-core/src/instance.rs | 12 +++++- wgpu-core/src/lib.rs | 1 + wgpu-core/src/power.rs | 63 ++++++++++++++++++++++++++++++++ 6 files changed, 80 insertions(+), 3 deletions(-) create mode 100644 wgpu-core/src/power.rs diff --git a/examples/compute/CMakeLists.txt b/examples/compute/CMakeLists.txt index 9b4c748f1..d9fbfc752 100644 --- a/examples/compute/CMakeLists.txt +++ b/examples/compute/CMakeLists.txt @@ -9,7 +9,7 @@ add_executable(compute main.c ../framework.c) if(MSVC) add_definitions(-DWGPU_TARGET=WGPU_TARGET_WINDOWS) target_compile_options(${TARGET_NAME} PRIVATE /W4) - set(OS_LIBRARIES "userenv" "ws2_32" "Dwmapi" "dbghelp" "d3dcompiler" "D3D12" "D3D11" "DXGI") + set(OS_LIBRARIES "userenv" "ws2_32" "Dwmapi" "dbghelp" "d3dcompiler" "D3D12" "D3D11" "DXGI" "setupapi") elseif(APPLE) add_definitions(-DWGPU_TARGET=WGPU_TARGET_MACOS) set(OS_LIBRARIES "-framework Cocoa" "-framework CoreVideo" "-framework IOKit" "-framework QuartzCore") diff --git a/examples/triangle/CMakeLists.txt b/examples/triangle/CMakeLists.txt index de2d6bad5..56a44db98 100644 --- a/examples/triangle/CMakeLists.txt +++ b/examples/triangle/CMakeLists.txt @@ -9,7 +9,7 @@ add_executable(triangle main.c ../framework.c) if(MSVC) add_definitions(-DWGPU_TARGET=WGPU_TARGET_WINDOWS) target_compile_options(${TARGET_NAME} PRIVATE /W4) - set(OS_LIBRARIES "userenv" "ws2_32" "Dwmapi" "dbghelp" "d3dcompiler" "D3D12" "D3D11" "DXGI") + set(OS_LIBRARIES "userenv" "ws2_32" "Dwmapi" "dbghelp" "d3dcompiler" "D3D12" "D3D11" "DXGI" "setupapi") elseif(APPLE) add_definitions(-DWGPU_TARGET=WGPU_TARGET_MACOS) set(OS_LIBRARIES "-framework Cocoa" "-framework CoreVideo" "-framework IOKit" "-framework QuartzCore") diff --git a/wgpu-core/Cargo.toml b/wgpu-core/Cargo.toml index a1b799ebc..7ce6d763b 100644 --- a/wgpu-core/Cargo.toml +++ b/wgpu-core/Cargo.toml @@ -46,3 +46,6 @@ gfx-backend-vulkan = { version = "0.4", features = ["x11"] } gfx-backend-dx12 = { version = "0.4.1" } gfx-backend-dx11 = { version = "0.4" } gfx-backend-vulkan = { version = "0.4" } + +[target.'cfg(any(target_os = "linux", target_os = "macos", target_os = "windows", target_os = "dragonfly", target_os = "freebsd"))'.dependencies] +battery = "0.7" \ No newline at end of file diff --git a/wgpu-core/src/instance.rs b/wgpu-core/src/instance.rs index fa2d15b9e..e156f4042 100644 --- a/wgpu-core/src/instance.rs +++ b/wgpu-core/src/instance.rs @@ -8,6 +8,7 @@ use crate::{ device::{Device, BIND_BUFFER_ALIGNMENT}, hub::{GfxBackend, Global, IdentityFilter, Token}, id::{AdapterId, DeviceId}, + power, Backend, }; @@ -271,7 +272,16 @@ impl> Global { } let preferred_gpu = match desc.power_preference { - PowerPreference::Default => discrete.or(integrated).or(other).or(virt), + PowerPreference::Default => { + match power::is_battery_discharging() { + Ok(false) => discrete.or(integrated).or(other).or(virt), + Ok(true) => integrated.or(discrete).or(other).or(virt), + Err(err) => { + log::debug!("Power info unavailable, preferring integrated gpu ({})", err); + integrated.or(discrete).or(other).or(virt) + } + } + }, PowerPreference::LowPower => integrated.or(other).or(discrete).or(virt), PowerPreference::HighPerformance => discrete.or(other).or(integrated).or(virt), }; diff --git a/wgpu-core/src/lib.rs b/wgpu-core/src/lib.rs index 40d2b7cb7..1789d38fe 100644 --- a/wgpu-core/src/lib.rs +++ b/wgpu-core/src/lib.rs @@ -25,6 +25,7 @@ pub mod hub; pub mod id; pub mod instance; pub mod pipeline; +pub mod power; pub mod resource; pub mod swap_chain; pub mod track; diff --git a/wgpu-core/src/power.rs b/wgpu-core/src/power.rs new file mode 100644 index 000000000..188906368 --- /dev/null +++ b/wgpu-core/src/power.rs @@ -0,0 +1,63 @@ +use std::fmt; + +#[derive(Debug)] +pub enum Error { + Unsupported, + Error(Box), +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Error::Unsupported => write!(f, "Battery status is unsupported on this platform"), + Error::Error(err) => write!(f, "Battery status retrieval failed: {}", err), + } + } +} + +#[cfg(any( + target_os = "linux", + target_os = "macos", + target_os = "windows", + target_os = "dragonfly", + target_os = "freebsd" +))] +mod platform { + use super::Error; + use battery::{self, Manager, State}; + + impl From for Error { + fn from(err: battery::errors::Error) -> Error { + // Box the error so that the battery::errors::Error type does + // not leak out of this module. + Error::Error(Box::new(err)) + } + } + + pub fn is_battery_discharging() -> Result { + let manager = Manager::new()?; + for battery in manager.batteries()? { + if battery?.state() == State::Discharging { + return Ok(true); + } + } + Ok(false) + } +} + +#[cfg(not(any( + target_os = "linux", + target_os = "macos", + target_os = "windows", + target_os = "dragonfly", + target_os = "freebsd" +)))] +mod platform { + use super::Error; + + pub fn is_battery_discharging() -> Result { + Err(Error::Unsupported) + } +} + +pub use platform::is_battery_discharging;