Add option to initialize on existing wgpu setup (#5319)
When mixing and matching eframe with other wgpu applications (https://github.com/tracel-ai/burn in my case), it can be helpful to use an existing wgpu setup to initialize eframe with. This PR changes the WpuConfiguration (in a non-backwards compat way :/), to either take some options how to create a wgpu setup, or an existing wgpu setup (consisting of an instance, adapter, device and queue). * [x] I have followed the instructions in the PR template --------- Co-authored-by: Andreas Reich <r_andreas2@web.de>
This commit is contained in:
parent
fba2dc85a3
commit
759a0b2a21
|
|
@ -1,15 +1,13 @@
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use raw_window_handle::{
|
use raw_window_handle::{
|
||||||
DisplayHandle, HandleError, HasDisplayHandle, HasWindowHandle, RawDisplayHandle,
|
DisplayHandle, HandleError, HasDisplayHandle, HasWindowHandle, RawDisplayHandle,
|
||||||
RawWindowHandle, WebDisplayHandle, WebWindowHandle, WindowHandle,
|
RawWindowHandle, WebDisplayHandle, WebWindowHandle, WindowHandle,
|
||||||
};
|
};
|
||||||
|
use std::sync::Arc;
|
||||||
use wasm_bindgen::JsValue;
|
use wasm_bindgen::JsValue;
|
||||||
use web_sys::HtmlCanvasElement;
|
use web_sys::HtmlCanvasElement;
|
||||||
|
|
||||||
use egui_wgpu::{RenderState, SurfaceErrorAction};
|
|
||||||
|
|
||||||
use crate::WebOptions;
|
use crate::WebOptions;
|
||||||
|
use egui_wgpu::{RenderState, SurfaceErrorAction, WgpuSetup};
|
||||||
|
|
||||||
use super::web_painter::WebPainter;
|
use super::web_painter::WebPainter;
|
||||||
|
|
||||||
|
|
@ -89,81 +87,97 @@ impl WebPainterWgpu {
|
||||||
) -> Result<Self, String> {
|
) -> Result<Self, String> {
|
||||||
log::debug!("Creating wgpu painter");
|
log::debug!("Creating wgpu painter");
|
||||||
|
|
||||||
let mut backends = options.wgpu_options.supported_backends;
|
let instance = match &options.wgpu_options.wgpu_setup {
|
||||||
|
WgpuSetup::CreateNew {
|
||||||
|
supported_backends: backends,
|
||||||
|
power_preference,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
let mut backends = *backends;
|
||||||
|
|
||||||
// Don't try WebGPU if we're not in a secure context.
|
// Don't try WebGPU if we're not in a secure context.
|
||||||
if backends.contains(wgpu::Backends::BROWSER_WEBGPU) {
|
if backends.contains(wgpu::Backends::BROWSER_WEBGPU) {
|
||||||
let is_secure_context = web_sys::window().map_or(false, |w| w.is_secure_context());
|
let is_secure_context =
|
||||||
if !is_secure_context {
|
web_sys::window().map_or(false, |w| w.is_secure_context());
|
||||||
log::info!(
|
if !is_secure_context {
|
||||||
"WebGPU is only available in secure contexts, i.e. on HTTPS and on localhost."
|
log::info!(
|
||||||
);
|
"WebGPU is only available in secure contexts, i.e. on HTTPS and on localhost."
|
||||||
|
);
|
||||||
|
|
||||||
// Don't try WebGPU since we established now that it will fail.
|
// Don't try WebGPU since we established now that it will fail.
|
||||||
backends.remove(wgpu::Backends::BROWSER_WEBGPU);
|
backends.remove(wgpu::Backends::BROWSER_WEBGPU);
|
||||||
|
|
||||||
if backends.is_empty() {
|
if backends.is_empty() {
|
||||||
return Err("No available supported graphics backends.".to_owned());
|
return Err("No available supported graphics backends.".to_owned());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
log::debug!("Creating wgpu instance with backends {:?}", backends);
|
log::debug!("Creating wgpu instance with backends {:?}", backends);
|
||||||
let mut instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
|
let mut instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
|
||||||
backends,
|
backends,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
|
|
||||||
// It can happen that a browser advertises WebGPU support, but then fails to create a
|
// It can happen that a browser advertises WebGPU support, but then fails to create a
|
||||||
// suitable adapter. As of writing this happens for example on Linux with Chrome 121.
|
// suitable adapter. As of writing this happens for example on Linux with Chrome 121.
|
||||||
//
|
//
|
||||||
// Since WebGPU is handled in a special way in wgpu, we have to recreate the instance
|
// Since WebGPU is handled in a special way in wgpu, we have to recreate the instance
|
||||||
// if we instead want to try with WebGL.
|
// if we instead want to try with WebGL.
|
||||||
//
|
//
|
||||||
// To make matters worse, once a canvas has been used with either WebGL or WebGPU,
|
// To make matters worse, once a canvas has been used with either WebGL or WebGPU,
|
||||||
// we can't go back and change that without replacing the canvas (which is hard to do from here).
|
// we can't go back and change that without replacing the canvas (which is hard to do from here).
|
||||||
// Therefore, we have to create the surface *after* requesting the adapter.
|
// Therefore, we have to create the surface *after* requesting the adapter.
|
||||||
// However, wgpu offers to pass in a surface on adapter creation to ensure it is actually compatible with the chosen backend.
|
// However, wgpu offers to pass in a surface on adapter creation to ensure it is actually compatible with the chosen backend.
|
||||||
// This in turn isn't all that important on the web, but it still makes sense for the design of
|
// This in turn isn't all that important on the web, but it still makes sense for the design of
|
||||||
// `egui::RenderState`!
|
// `egui::RenderState`!
|
||||||
// Therefore, we have to first check if it's possible to create a WebGPU adapter,
|
// Therefore, we have to first check if it's possible to create a WebGPU adapter,
|
||||||
// and if it is not, start over with a WebGL instance.
|
// and if it is not, start over with a WebGL instance.
|
||||||
//
|
//
|
||||||
// Note that we also might needlessly try this here if wgpu already determined that there's no
|
// Note that we also might needlessly try this here if wgpu already determined that there's no
|
||||||
// WebGPU support in the first place. This is not a huge problem since it fails very fast, but
|
// WebGPU support in the first place. This is not a huge problem since it fails very fast, but
|
||||||
// it would be nice to avoid this. See https://github.com/gfx-rs/wgpu/issues/5142
|
// it would be nice to avoid this. See https://github.com/gfx-rs/wgpu/issues/5142
|
||||||
if backends.contains(wgpu::Backends::BROWSER_WEBGPU) {
|
if backends.contains(wgpu::Backends::BROWSER_WEBGPU) {
|
||||||
log::debug!("Attempting to create WebGPU adapter to check for support.");
|
log::debug!("Attempting to create WebGPU adapter to check for support.");
|
||||||
if let Some(adapter) = instance
|
if let Some(adapter) = instance
|
||||||
.request_adapter(&wgpu::RequestAdapterOptions {
|
.request_adapter(&wgpu::RequestAdapterOptions {
|
||||||
power_preference: options.wgpu_options.power_preference,
|
power_preference: *power_preference,
|
||||||
compatible_surface: None,
|
compatible_surface: None,
|
||||||
force_fallback_adapter: false,
|
force_fallback_adapter: false,
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
// WebGPU doesn't spec yet a destroy on the adapter, only on the device.
|
// WebGPU doesn't spec yet a destroy on the adapter, only on the device.
|
||||||
//adapter.destroy();
|
//adapter.destroy();
|
||||||
log::debug!(
|
log::debug!(
|
||||||
"Successfully created WebGPU adapter, WebGPU confirmed to be supported!"
|
"Successfully created WebGPU adapter, WebGPU confirmed to be supported!"
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
log::debug!("Failed to create WebGPU adapter.");
|
log::debug!("Failed to create WebGPU adapter.");
|
||||||
|
|
||||||
if backends.contains(wgpu::Backends::GL) {
|
if backends.contains(wgpu::Backends::GL) {
|
||||||
log::debug!("Recreating wgpu instance with WebGL backend only.");
|
log::debug!("Recreating wgpu instance with WebGL backend only.");
|
||||||
backends = wgpu::Backends::GL;
|
backends = wgpu::Backends::GL;
|
||||||
instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
|
instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
|
||||||
backends,
|
backends,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return Err(
|
return Err(
|
||||||
"Failed to create WebGPU adapter and WebGL was not enabled.".to_owned()
|
"Failed to create WebGPU adapter and WebGL was not enabled."
|
||||||
);
|
.to_owned(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// On wasm, depending on feature flags, wgpu objects may or may not implement sync.
|
||||||
|
// It doesn't make sense to switch to Rc for that special usecase, so simply disable the lint.
|
||||||
|
#[allow(clippy::arc_with_non_send_sync)]
|
||||||
|
Arc::new(instance)
|
||||||
}
|
}
|
||||||
}
|
WgpuSetup::Existing { instance, .. } => instance.clone(),
|
||||||
|
};
|
||||||
|
|
||||||
let surface = instance
|
let surface = instance
|
||||||
.create_surface(wgpu::SurfaceTarget::Canvas(canvas.clone()))
|
.create_surface(wgpu::SurfaceTarget::Canvas(canvas.clone()))
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,8 @@
|
||||||
//! wgpu = { version = "*", features = ["webgpu", "webgl"] }
|
//! wgpu = { version = "*", features = ["webgpu", "webgl"] }
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! You can control whether WebGL or WebGPU will be picked at runtime by setting
|
//! You can control whether WebGL or WebGPU will be picked at runtime by configuring
|
||||||
//! [`WgpuConfiguration::supported_backends`].
|
//! [`WgpuConfiguration::wgpu_setup`].
|
||||||
//! The default is to prefer WebGPU and fall back on WebGL.
|
//! The default is to prefer WebGPU and fall back on WebGL.
|
||||||
//!
|
//!
|
||||||
//! ## Feature flags
|
//! ## Feature flags
|
||||||
|
|
@ -24,6 +24,7 @@ pub use wgpu;
|
||||||
mod renderer;
|
mod renderer;
|
||||||
|
|
||||||
pub use renderer::*;
|
pub use renderer::*;
|
||||||
|
use wgpu::{Adapter, Device, Instance, Queue};
|
||||||
|
|
||||||
/// Module for painting [`egui`](https://github.com/emilk/egui) with [`wgpu`] on [`winit`].
|
/// Module for painting [`egui`](https://github.com/emilk/egui) with [`wgpu`] on [`winit`].
|
||||||
#[cfg(feature = "winit")]
|
#[cfg(feature = "winit")]
|
||||||
|
|
@ -98,73 +99,92 @@ impl RenderState {
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
let available_adapters = instance.enumerate_adapters(wgpu::Backends::all());
|
let available_adapters = instance.enumerate_adapters(wgpu::Backends::all());
|
||||||
|
|
||||||
let adapter = {
|
let (adapter, device, queue) = match config.wgpu_setup.clone() {
|
||||||
crate::profile_scope!("request_adapter");
|
WgpuSetup::CreateNew {
|
||||||
instance
|
supported_backends: _,
|
||||||
.request_adapter(&wgpu::RequestAdapterOptions {
|
power_preference,
|
||||||
power_preference: config.power_preference,
|
device_descriptor,
|
||||||
compatible_surface: Some(surface),
|
} => {
|
||||||
force_fallback_adapter: false,
|
let adapter = {
|
||||||
})
|
crate::profile_scope!("request_adapter");
|
||||||
.await
|
instance
|
||||||
.ok_or_else(|| {
|
.request_adapter(&wgpu::RequestAdapterOptions {
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
power_preference,
|
||||||
if available_adapters.is_empty() {
|
compatible_surface: Some(surface),
|
||||||
log::info!("No wgpu adapters found");
|
force_fallback_adapter: false,
|
||||||
} else if available_adapters.len() == 1 {
|
})
|
||||||
log::info!(
|
.await
|
||||||
"The only available wgpu adapter was not suitable: {}",
|
.ok_or_else(|| {
|
||||||
adapter_info_summary(&available_adapters[0].get_info())
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
);
|
if available_adapters.is_empty() {
|
||||||
} else {
|
log::info!("No wgpu adapters found");
|
||||||
log::info!(
|
} else if available_adapters.len() == 1 {
|
||||||
"No suitable wgpu adapter found out of the {} available ones: {}",
|
log::info!(
|
||||||
available_adapters.len(),
|
"The only available wgpu adapter was not suitable: {}",
|
||||||
describe_adapters(&available_adapters)
|
adapter_info_summary(&available_adapters[0].get_info())
|
||||||
);
|
);
|
||||||
}
|
} else {
|
||||||
|
log::info!(
|
||||||
|
"No suitable wgpu adapter found out of the {} available ones: {}",
|
||||||
|
available_adapters.len(),
|
||||||
|
describe_adapters(&available_adapters)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
WgpuError::NoSuitableAdapterFound
|
WgpuError::NoSuitableAdapterFound
|
||||||
})?
|
})?
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
log::debug!(
|
||||||
|
"Picked wgpu adapter: {}",
|
||||||
|
adapter_info_summary(&adapter.get_info())
|
||||||
|
);
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
if available_adapters.len() == 1 {
|
||||||
|
log::debug!(
|
||||||
|
"Picked the only available wgpu adapter: {}",
|
||||||
|
adapter_info_summary(&adapter.get_info())
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
log::info!(
|
||||||
|
"There were {} available wgpu adapters: {}",
|
||||||
|
available_adapters.len(),
|
||||||
|
describe_adapters(&available_adapters)
|
||||||
|
);
|
||||||
|
log::debug!(
|
||||||
|
"Picked wgpu adapter: {}",
|
||||||
|
adapter_info_summary(&adapter.get_info())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let (device, queue) = {
|
||||||
|
crate::profile_scope!("request_device");
|
||||||
|
adapter
|
||||||
|
.request_device(&(*device_descriptor)(&adapter), None)
|
||||||
|
.await?
|
||||||
|
};
|
||||||
|
|
||||||
|
// On wasm, depending on feature flags, wgpu objects may or may not implement sync.
|
||||||
|
// It doesn't make sense to switch to Rc for that special usecase, so simply disable the lint.
|
||||||
|
#[allow(clippy::arc_with_non_send_sync)]
|
||||||
|
(Arc::new(adapter), Arc::new(device), Arc::new(queue))
|
||||||
|
}
|
||||||
|
WgpuSetup::Existing {
|
||||||
|
instance: _,
|
||||||
|
adapter,
|
||||||
|
device,
|
||||||
|
queue,
|
||||||
|
} => (adapter, device, queue),
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
|
||||||
log::debug!(
|
|
||||||
"Picked wgpu adapter: {}",
|
|
||||||
adapter_info_summary(&adapter.get_info())
|
|
||||||
);
|
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
|
||||||
if available_adapters.len() == 1 {
|
|
||||||
log::debug!(
|
|
||||||
"Picked the only available wgpu adapter: {}",
|
|
||||||
adapter_info_summary(&adapter.get_info())
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
log::info!(
|
|
||||||
"There were {} available wgpu adapters: {}",
|
|
||||||
available_adapters.len(),
|
|
||||||
describe_adapters(&available_adapters)
|
|
||||||
);
|
|
||||||
log::debug!(
|
|
||||||
"Picked wgpu adapter: {}",
|
|
||||||
adapter_info_summary(&adapter.get_info())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let capabilities = {
|
let capabilities = {
|
||||||
crate::profile_scope!("get_capabilities");
|
crate::profile_scope!("get_capabilities");
|
||||||
surface.get_capabilities(&adapter).formats
|
surface.get_capabilities(&adapter).formats
|
||||||
};
|
};
|
||||||
let target_format = crate::preferred_framebuffer_format(&capabilities)?;
|
let target_format = crate::preferred_framebuffer_format(&capabilities)?;
|
||||||
|
|
||||||
let (device, queue) = {
|
|
||||||
crate::profile_scope!("request_device");
|
|
||||||
adapter
|
|
||||||
.request_device(&(*config.device_descriptor)(&adapter), None)
|
|
||||||
.await?
|
|
||||||
};
|
|
||||||
|
|
||||||
let renderer = Renderer::new(
|
let renderer = Renderer::new(
|
||||||
&device,
|
&device,
|
||||||
target_format,
|
target_format,
|
||||||
|
|
@ -177,11 +197,11 @@ impl RenderState {
|
||||||
// It doesn't make sense to switch to Rc for that special usecase, so simply disable the lint.
|
// It doesn't make sense to switch to Rc for that special usecase, so simply disable the lint.
|
||||||
#[allow(clippy::arc_with_non_send_sync)]
|
#[allow(clippy::arc_with_non_send_sync)]
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
adapter: Arc::new(adapter),
|
adapter,
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
available_adapters: available_adapters.into(),
|
available_adapters: available_adapters.into(),
|
||||||
device: Arc::new(device),
|
device,
|
||||||
queue: Arc::new(queue),
|
queue,
|
||||||
target_format,
|
target_format,
|
||||||
renderer: Arc::new(RwLock::new(renderer)),
|
renderer: Arc::new(RwLock::new(renderer)),
|
||||||
})
|
})
|
||||||
|
|
@ -215,27 +235,65 @@ pub enum SurfaceErrorAction {
|
||||||
RecreateSurface,
|
RecreateSurface,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum WgpuSetup {
|
||||||
|
/// Construct a wgpu setup using some predefined settings & heuristics.
|
||||||
|
/// This is the default option. You can customize most behaviours overriding the
|
||||||
|
/// supported backends, power preferences, and device description.
|
||||||
|
///
|
||||||
|
/// This can also be configured with the environment variables:
|
||||||
|
/// * `WGPU_BACKEND`: `vulkan`, `dx11`, `dx12`, `metal`, `opengl`, `webgpu`
|
||||||
|
/// * `WGPU_POWER_PREF`: `low`, `high` or `none`
|
||||||
|
CreateNew {
|
||||||
|
/// Backends that should be supported (wgpu will pick one of these).
|
||||||
|
///
|
||||||
|
/// For instance, if you only want to support WebGL (and not WebGPU),
|
||||||
|
/// you can set this to [`wgpu::Backends::GL`].
|
||||||
|
///
|
||||||
|
/// By default on web, WebGPU will be used if available.
|
||||||
|
/// WebGL will only be used as a fallback,
|
||||||
|
/// and only if you have enabled the `webgl` feature of crate `wgpu`.
|
||||||
|
supported_backends: wgpu::Backends,
|
||||||
|
|
||||||
|
/// Power preference for the adapter.
|
||||||
|
power_preference: wgpu::PowerPreference,
|
||||||
|
|
||||||
|
/// Configuration passed on device request, given an adapter
|
||||||
|
device_descriptor:
|
||||||
|
Arc<dyn Fn(&wgpu::Adapter) -> wgpu::DeviceDescriptor<'static> + Send + Sync>,
|
||||||
|
},
|
||||||
|
|
||||||
|
/// Run on an existing wgpu setup.
|
||||||
|
Existing {
|
||||||
|
instance: Arc<Instance>,
|
||||||
|
adapter: Arc<Adapter>,
|
||||||
|
device: Arc<Device>,
|
||||||
|
queue: Arc<Queue>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for WgpuSetup {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::CreateNew {
|
||||||
|
supported_backends,
|
||||||
|
power_preference,
|
||||||
|
device_descriptor: _,
|
||||||
|
} => f
|
||||||
|
.debug_struct("AdapterSelection::Standard")
|
||||||
|
.field("supported_backends", &supported_backends)
|
||||||
|
.field("power_preference", &power_preference)
|
||||||
|
.finish(),
|
||||||
|
Self::Existing { .. } => f
|
||||||
|
.debug_struct("AdapterSelection::Existing")
|
||||||
|
.finish_non_exhaustive(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Configuration for using wgpu with eframe or the egui-wgpu winit feature.
|
/// Configuration for using wgpu with eframe or the egui-wgpu winit feature.
|
||||||
///
|
|
||||||
/// This can also be configured with the environment variables:
|
|
||||||
/// * `WGPU_BACKEND`: `vulkan`, `dx11`, `dx12`, `metal`, `opengl`, `webgpu`
|
|
||||||
/// * `WGPU_POWER_PREF`: `low`, `high` or `none`
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct WgpuConfiguration {
|
pub struct WgpuConfiguration {
|
||||||
/// Backends that should be supported (wgpu will pick one of these).
|
|
||||||
///
|
|
||||||
/// For instance, if you only want to support WebGL (and not WebGPU),
|
|
||||||
/// you can set this to [`wgpu::Backends::GL`].
|
|
||||||
///
|
|
||||||
/// By default on web, WebGPU will be used if available.
|
|
||||||
/// WebGL will only be used as a fallback,
|
|
||||||
/// and only if you have enabled the `webgl` feature of crate `wgpu`.
|
|
||||||
pub supported_backends: wgpu::Backends,
|
|
||||||
|
|
||||||
/// Configuration passed on device request, given an adapter
|
|
||||||
pub device_descriptor:
|
|
||||||
Arc<dyn Fn(&wgpu::Adapter) -> wgpu::DeviceDescriptor<'static> + Send + Sync>,
|
|
||||||
|
|
||||||
/// Present mode used for the primary surface.
|
/// Present mode used for the primary surface.
|
||||||
pub present_mode: wgpu::PresentMode,
|
pub present_mode: wgpu::PresentMode,
|
||||||
|
|
||||||
|
|
@ -248,8 +306,8 @@ pub struct WgpuConfiguration {
|
||||||
/// `None` = `wgpu` default.
|
/// `None` = `wgpu` default.
|
||||||
pub desired_maximum_frame_latency: Option<u32>,
|
pub desired_maximum_frame_latency: Option<u32>,
|
||||||
|
|
||||||
/// Power preference for the adapter.
|
/// How to create the wgpu adapter & device
|
||||||
pub power_preference: wgpu::PowerPreference,
|
pub wgpu_setup: WgpuSetup,
|
||||||
|
|
||||||
/// Callback for surface errors.
|
/// Callback for surface errors.
|
||||||
pub on_surface_error: Arc<dyn Fn(wgpu::SurfaceError) -> SurfaceErrorAction + Send + Sync>,
|
pub on_surface_error: Arc<dyn Fn(wgpu::SurfaceError) -> SurfaceErrorAction + Send + Sync>,
|
||||||
|
|
@ -264,21 +322,18 @@ fn wgpu_config_impl_send_sync() {
|
||||||
impl std::fmt::Debug for WgpuConfiguration {
|
impl std::fmt::Debug for WgpuConfiguration {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
let Self {
|
let Self {
|
||||||
supported_backends,
|
|
||||||
device_descriptor: _,
|
|
||||||
present_mode,
|
present_mode,
|
||||||
desired_maximum_frame_latency,
|
desired_maximum_frame_latency,
|
||||||
power_preference,
|
wgpu_setup,
|
||||||
on_surface_error: _,
|
on_surface_error: _,
|
||||||
} = self;
|
} = self;
|
||||||
f.debug_struct("WgpuConfiguration")
|
f.debug_struct("WgpuConfiguration")
|
||||||
.field("supported_backends", &supported_backends)
|
|
||||||
.field("present_mode", &present_mode)
|
.field("present_mode", &present_mode)
|
||||||
.field(
|
.field(
|
||||||
"desired_maximum_frame_latency",
|
"desired_maximum_frame_latency",
|
||||||
&desired_maximum_frame_latency,
|
&desired_maximum_frame_latency,
|
||||||
)
|
)
|
||||||
.field("power_preference", &power_preference)
|
.field("wgpu_setup", &wgpu_setup)
|
||||||
.finish_non_exhaustive()
|
.finish_non_exhaustive()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -286,37 +341,42 @@ impl std::fmt::Debug for WgpuConfiguration {
|
||||||
impl Default for WgpuConfiguration {
|
impl Default for WgpuConfiguration {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
// Add GL backend, primarily because WebGPU is not stable enough yet.
|
|
||||||
// (note however, that the GL backend needs to be opted-in via the wgpu feature flag "webgl")
|
|
||||||
supported_backends: wgpu::util::backend_bits_from_env()
|
|
||||||
.unwrap_or(wgpu::Backends::PRIMARY | wgpu::Backends::GL),
|
|
||||||
|
|
||||||
device_descriptor: Arc::new(|adapter| {
|
|
||||||
let base_limits = if adapter.get_info().backend == wgpu::Backend::Gl {
|
|
||||||
wgpu::Limits::downlevel_webgl2_defaults()
|
|
||||||
} else {
|
|
||||||
wgpu::Limits::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
wgpu::DeviceDescriptor {
|
|
||||||
label: Some("egui wgpu device"),
|
|
||||||
required_features: wgpu::Features::default(),
|
|
||||||
required_limits: wgpu::Limits {
|
|
||||||
// When using a depth buffer, we have to be able to create a texture
|
|
||||||
// large enough for the entire surface, and we want to support 4k+ displays.
|
|
||||||
max_texture_dimension_2d: 8192,
|
|
||||||
..base_limits
|
|
||||||
},
|
|
||||||
memory_hints: wgpu::MemoryHints::default(),
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
|
|
||||||
present_mode: wgpu::PresentMode::AutoVsync,
|
present_mode: wgpu::PresentMode::AutoVsync,
|
||||||
|
|
||||||
desired_maximum_frame_latency: None,
|
desired_maximum_frame_latency: None,
|
||||||
|
|
||||||
power_preference: wgpu::util::power_preference_from_env()
|
// By default, create a new wgpu setup. This will create a new instance, adapter, device and queue.
|
||||||
.unwrap_or(wgpu::PowerPreference::HighPerformance),
|
// This will create an instance for the supported backends (which can be configured by
|
||||||
|
// `WGPU_BACKEND`), and will pick an adapter by iterating adapters based on their power preference. The power
|
||||||
|
// preference can also be configured by `WGPU_POWER_PREF`.
|
||||||
|
wgpu_setup: WgpuSetup::CreateNew {
|
||||||
|
// Add GL backend, primarily because WebGPU is not stable enough yet.
|
||||||
|
// (note however, that the GL backend needs to be opted-in via the wgpu feature flag "webgl")
|
||||||
|
supported_backends: wgpu::util::backend_bits_from_env()
|
||||||
|
.unwrap_or(wgpu::Backends::PRIMARY | wgpu::Backends::GL),
|
||||||
|
|
||||||
|
power_preference: wgpu::util::power_preference_from_env()
|
||||||
|
.unwrap_or(wgpu::PowerPreference::HighPerformance),
|
||||||
|
device_descriptor: Arc::new(|adapter| {
|
||||||
|
let base_limits = if adapter.get_info().backend == wgpu::Backend::Gl {
|
||||||
|
wgpu::Limits::downlevel_webgl2_defaults()
|
||||||
|
} else {
|
||||||
|
wgpu::Limits::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
wgpu::DeviceDescriptor {
|
||||||
|
label: Some("egui wgpu device"),
|
||||||
|
required_features: wgpu::Features::default(),
|
||||||
|
required_limits: wgpu::Limits {
|
||||||
|
// When using a depth buffer, we have to be able to create a texture
|
||||||
|
// large enough for the entire surface, and we want to support 4k+ displays.
|
||||||
|
max_texture_dimension_2d: 8192,
|
||||||
|
..base_limits
|
||||||
|
},
|
||||||
|
memory_hints: wgpu::MemoryHints::default(),
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
|
||||||
on_surface_error: Arc::new(|err| {
|
on_surface_error: Arc::new(|err| {
|
||||||
if err == wgpu::SurfaceError::Outdated {
|
if err == wgpu::SurfaceError::Outdated {
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,7 @@ pub struct Painter {
|
||||||
depth_format: Option<wgpu::TextureFormat>,
|
depth_format: Option<wgpu::TextureFormat>,
|
||||||
screen_capture_state: Option<CaptureState>,
|
screen_capture_state: Option<CaptureState>,
|
||||||
|
|
||||||
instance: wgpu::Instance,
|
instance: Arc<wgpu::Instance>,
|
||||||
render_state: Option<RenderState>,
|
render_state: Option<RenderState>,
|
||||||
|
|
||||||
// Per viewport/window:
|
// Per viewport/window:
|
||||||
|
|
@ -116,10 +116,15 @@ impl Painter {
|
||||||
support_transparent_backbuffer: bool,
|
support_transparent_backbuffer: bool,
|
||||||
dithering: bool,
|
dithering: bool,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
|
let instance = match &configuration.wgpu_setup {
|
||||||
backends: configuration.supported_backends,
|
crate::WgpuSetup::CreateNew {
|
||||||
..Default::default()
|
supported_backends, ..
|
||||||
});
|
} => Arc::new(wgpu::Instance::new(wgpu::InstanceDescriptor {
|
||||||
|
backends: *supported_backends,
|
||||||
|
..Default::default()
|
||||||
|
})),
|
||||||
|
crate::WgpuSetup::Existing { instance, .. } => instance.clone(),
|
||||||
|
};
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
configuration,
|
configuration,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue