Use wgpu environment variables (#198)

- Enables projects using `pixels` to select GPU and backend with
  the same environment variables used by `wgpu` examples.
- cc #142
This commit is contained in:
Jay Oster 2021-09-04 15:26:30 -07:00 committed by GitHub
parent 50c77a5f83
commit c94dab65b7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 35 additions and 36 deletions

View file

@ -50,7 +50,7 @@ resolver = "2"
### Driver issues ### Driver issues
The most common issue is having an outdated graphics driver installed on the host machine. `pixels` The most common issue is having an outdated graphics driver installed on the host machine. `pixels`
requests a low power (aka integrated) GPU by default. If the examples are not working for any reason, you may try setting the `PIXELS_HIGH_PERF` environment variable (the value does not matter, e.g. `PIXELS_HIGH_PERF=1` is fine) to see if that addresses the issue on your host machine. requests a low power (aka integrated) GPU by default. If the examples are not working for any reason, you may try setting the `WGPU_POWER_PREF=high` environment variable to see if that addresses the issue on your host machine.
You should also try to keep your graphics drivers up-to-date, especially if you have an old Intel integrated GPU. Keep in mind that some drivers and GPUs are EOL and will not be supported. You should also try to keep your graphics drivers up-to-date, especially if you have an old Intel integrated GPU. Keep in mind that some drivers and GPUs are EOL and will not be supported.

View file

@ -2,7 +2,6 @@ use crate::renderers::{ScalingMatrix, ScalingRenderer};
use crate::SurfaceSize; use crate::SurfaceSize;
use crate::{Error, Pixels, PixelsContext, SurfaceTexture}; use crate::{Error, Pixels, PixelsContext, SurfaceTexture};
use raw_window_handle::HasRawWindowHandle; use raw_window_handle::HasRawWindowHandle;
use std::env;
/// A builder to help create customized pixel buffers. /// A builder to help create customized pixel buffers.
pub struct PixelsBuilder<'req, 'dev, 'win, W: HasRawWindowHandle> { pub struct PixelsBuilder<'req, 'dev, 'win, W: HasRawWindowHandle> {
@ -51,7 +50,7 @@ impl<'req, 'dev, 'win, W: HasRawWindowHandle> PixelsBuilder<'req, 'dev, 'win, W>
PixelsBuilder { PixelsBuilder {
request_adapter_options: None, request_adapter_options: None,
device_descriptor: wgpu::DeviceDescriptor::default(), device_descriptor: wgpu::DeviceDescriptor::default(),
backend: wgpu::Backends::PRIMARY, backend: wgpu::util::backend_bits_from_env().unwrap_or(wgpu::Backends::PRIMARY),
width, width,
height, height,
_pixel_aspect_ratio: 1.0, _pixel_aspect_ratio: 1.0,
@ -194,17 +193,25 @@ impl<'req, 'dev, 'win, W: HasRawWindowHandle> PixelsBuilder<'req, 'dev, 'win, W>
// TODO: Use `options.pixel_aspect_ratio` to stretch the scaled texture // TODO: Use `options.pixel_aspect_ratio` to stretch the scaled texture
let surface = unsafe { instance.create_surface(self.surface_texture.window) }; let surface = unsafe { instance.create_surface(self.surface_texture.window) };
let compatible_surface = Some(&surface); let compatible_surface = Some(&surface);
let adapter = instance.request_adapter(&self.request_adapter_options.map_or_else( let request_adapter_options = &self.request_adapter_options;
|| wgpu::RequestAdapterOptions { let adapter =
compatible_surface, wgpu::util::initialize_adapter_from_env(&instance, self.backend).or_else(|| {
power_preference: get_default_power_preference(), let future =
}, instance.request_adapter(&request_adapter_options.as_ref().map_or_else(
|rao| wgpu::RequestAdapterOptions { || wgpu::RequestAdapterOptions {
compatible_surface: rao.compatible_surface.or(compatible_surface), compatible_surface,
power_preference: rao.power_preference, power_preference:
}, wgpu::util::power_preference_from_env().unwrap_or_default(),
)); },
let adapter = pollster::block_on(adapter).ok_or(Error::AdapterNotFound)?; |rao| wgpu::RequestAdapterOptions {
compatible_surface: rao.compatible_surface.or(compatible_surface),
power_preference: rao.power_preference,
},
));
pollster::block_on(future)
});
let adapter = adapter.ok_or(Error::AdapterNotFound)?;
let (device, queue) = let (device, queue) =
pollster::block_on(adapter.request_device(&self.device_descriptor, None)) pollster::block_on(adapter.request_device(&self.device_descriptor, None))
@ -459,14 +466,3 @@ const fn get_texture_format_size(texture_format: wgpu::TextureFormat) -> f32 {
| Astc12x12RgbaUnormSrgb => 9.0, // 12.0 * 12.0 / 16.0 | Astc12x12RgbaUnormSrgb => 9.0, // 12.0 * 12.0 / 16.0
} }
} }
fn get_default_power_preference() -> wgpu::PowerPreference {
env::var("PIXELS_HIGH_PERF").map_or_else(
|_| {
env::var("PIXELS_LOW_POWER").map_or(wgpu::PowerPreference::default(), |_| {
wgpu::PowerPreference::LowPower
})
},
|_| wgpu::PowerPreference::HighPerformance,
)
}

View file

@ -12,19 +12,22 @@
//! //!
//! # Environment variables //! # Environment variables
//! //!
//! * `PIXELS_HIGH_PERF`: Switch the default adapter to high performance. //! Pixels will default to selecting the most powerful GPU and most modern graphics API available on
//! * `PIXELS_LOW_POWER`: Switch the default adapter to low power. //! the system, and these choices can be overridden with environment variables. These are the same
//! vars supported by the [`wgpu` examples](https://github.com/gfx-rs/wgpu/tree/v0.10/wgpu#usage).
//! //!
//! These variables change the default adapter to request either high performance or low power. //! * `WGPU_BACKEND`: Select the backend (aka graphics API).
//! (I.e. discrete or integrated GPUs.) The value is not checked, only the existence //! * Supported values: `vulkan`, `metal`, `dx11`, `dx12`, `gl`, `webgpu`
//! of the variable is relevant. //! * The default depends on capabilities of the host system, with `vulkan` being preferred on
//! Linux and Windows, and `metal` preferred on macOS.
//! * `WGPU_ADAPTER_NAME`: Select an adapter (aka GPU) with substring matching.
//! * E.g. `1080` will match `NVIDIA GeForce 1080ti`
//! * `WGPU_POWER_PREF`: Select an adapter (aka GPU) that meets the given power profile.
//! * Supported values: `low`, `high`
//! * The default is `low`. I.e. an integrated GPU will be preferred over a discrete GPU.
//! //!
//! The order of precedence for choosing a power preference is: //! Note that `WGPU_ADAPTER_NAME` and `WGPU_POWER_PREF` are mutually exclusive and that
//! //! `WGPU_ADAPTER_NAME` takes precedence.
//! 1. Application's specific adapter request through [`PixelsBuilder::request_adapter_options`]
//! 2. `PIXELS_HIGH_PERF`
//! 3. `PIXELS_LOW_POWER`
//! 4. `wgpu` default power preference (usually low power)
#![deny(clippy::all)] #![deny(clippy::all)]