[wgpu] Expose wgpu::Adapter via RenderState (#2954)
* [wgpu] Expose adapter, better errors, better docs, more code sharing, use stencil bits * doc fix * remove unnecessary unsafe * handle missing framebuffer format * better handling of renderstate creation in winit.rs * remove unnecessary use directive
This commit is contained in:
parent
20e291d3f6
commit
f76eefb98d
|
|
@ -1251,6 +1251,7 @@ dependencies = [
|
||||||
"epaint",
|
"epaint",
|
||||||
"log",
|
"log",
|
||||||
"puffin",
|
"puffin",
|
||||||
|
"thiserror",
|
||||||
"type-map",
|
"type-map",
|
||||||
"wgpu",
|
"wgpu",
|
||||||
"winit",
|
"winit",
|
||||||
|
|
|
||||||
|
|
@ -33,3 +33,6 @@ opt-level = 2 # fast and small wasm, basically same as `opt-level = 's'`
|
||||||
# Optimize all dependencies even in debug builds (does not affect workspace packages):
|
# Optimize all dependencies even in debug builds (does not affect workspace packages):
|
||||||
[profile.dev.package."*"]
|
[profile.dev.package."*"]
|
||||||
opt-level = 2
|
opt-level = 2
|
||||||
|
|
||||||
|
[workspace.dependencies]
|
||||||
|
thiserror = "1.0.37"
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,7 @@ egui = { version = "0.21.0", path = "../egui", default-features = false, feature
|
||||||
"log",
|
"log",
|
||||||
] }
|
] }
|
||||||
log = { version = "0.4", features = ["std"] }
|
log = { version = "0.4", features = ["std"] }
|
||||||
thiserror = "1.0.37"
|
thiserror.workspace = true
|
||||||
|
|
||||||
#! ### Optional dependencies
|
#! ### Optional dependencies
|
||||||
## Enable this when generating docs.
|
## Enable this when generating docs.
|
||||||
|
|
|
||||||
|
|
@ -312,10 +312,6 @@ pub struct NativeOptions {
|
||||||
/// Sets the number of bits in the depth buffer.
|
/// Sets the number of bits in the depth buffer.
|
||||||
///
|
///
|
||||||
/// `egui` doesn't need the depth buffer, so the default value is 0.
|
/// `egui` doesn't need the depth buffer, so the default value is 0.
|
||||||
///
|
|
||||||
/// On `wgpu` backends, due to limited depth texture format options, this
|
|
||||||
/// will be interpreted as a boolean (non-zero = true) for whether or not
|
|
||||||
/// specifically a `Depth32Float` buffer is used.
|
|
||||||
pub depth_buffer: u8,
|
pub depth_buffer: u8,
|
||||||
|
|
||||||
/// Sets the number of bits in the stencil buffer.
|
/// Sets the number of bits in the stencil buffer.
|
||||||
|
|
@ -475,6 +471,12 @@ pub struct WebOptions {
|
||||||
/// Default: `Theme::Dark`.
|
/// Default: `Theme::Dark`.
|
||||||
pub default_theme: Theme,
|
pub default_theme: Theme,
|
||||||
|
|
||||||
|
/// Sets the number of bits in the depth buffer.
|
||||||
|
///
|
||||||
|
/// `egui` doesn't need the depth buffer, so the default value is 0.
|
||||||
|
/// Unused by webgl context as of writing.
|
||||||
|
pub depth_buffer: u8,
|
||||||
|
|
||||||
/// Which version of WebGl context to select
|
/// Which version of WebGl context to select
|
||||||
///
|
///
|
||||||
/// Default: [`WebGlContextOption::BestFirst`].
|
/// Default: [`WebGlContextOption::BestFirst`].
|
||||||
|
|
@ -492,6 +494,7 @@ impl Default for WebOptions {
|
||||||
Self {
|
Self {
|
||||||
follow_system_theme: true,
|
follow_system_theme: true,
|
||||||
default_theme: Theme::Dark,
|
default_theme: Theme::Dark,
|
||||||
|
depth_buffer: 0,
|
||||||
|
|
||||||
#[cfg(feature = "glow")]
|
#[cfg(feature = "glow")]
|
||||||
webgl_context_option: WebGlContextOption::BestFirst,
|
webgl_context_option: WebGlContextOption::BestFirst,
|
||||||
|
|
|
||||||
|
|
@ -1122,9 +1122,7 @@ mod wgpu_integration {
|
||||||
) -> std::result::Result<(), egui_wgpu::WgpuError> {
|
) -> std::result::Result<(), egui_wgpu::WgpuError> {
|
||||||
self.window = Some(window);
|
self.window = Some(window);
|
||||||
if let Some(running) = &mut self.running {
|
if let Some(running) = &mut self.running {
|
||||||
unsafe {
|
pollster::block_on(running.painter.set_window(self.window.as_ref()))?;
|
||||||
pollster::block_on(running.painter.set_window(self.window.as_ref()))?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -1134,9 +1132,7 @@ mod wgpu_integration {
|
||||||
fn drop_window(&mut self) -> std::result::Result<(), egui_wgpu::WgpuError> {
|
fn drop_window(&mut self) -> std::result::Result<(), egui_wgpu::WgpuError> {
|
||||||
self.window = None;
|
self.window = None;
|
||||||
if let Some(running) = &mut self.running {
|
if let Some(running) = &mut self.running {
|
||||||
unsafe {
|
pollster::block_on(running.painter.set_window(None))?;
|
||||||
pollster::block_on(running.painter.set_window(None))?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -1148,16 +1144,16 @@ mod wgpu_integration {
|
||||||
window: winit::window::Window,
|
window: winit::window::Window,
|
||||||
) -> std::result::Result<(), egui_wgpu::WgpuError> {
|
) -> std::result::Result<(), egui_wgpu::WgpuError> {
|
||||||
#[allow(unsafe_code, unused_mut, unused_unsafe)]
|
#[allow(unsafe_code, unused_mut, unused_unsafe)]
|
||||||
let painter = unsafe {
|
let mut painter = egui_wgpu::winit::Painter::new(
|
||||||
let mut painter = egui_wgpu::winit::Painter::new(
|
self.native_options.wgpu_options.clone(),
|
||||||
self.native_options.wgpu_options.clone(),
|
self.native_options.multisampling.max(1) as _,
|
||||||
self.native_options.multisampling.max(1) as _,
|
egui_wgpu::depth_format_from_bits(
|
||||||
self.native_options.depth_buffer,
|
self.native_options.depth_buffer,
|
||||||
self.native_options.transparent,
|
self.native_options.stencil_buffer,
|
||||||
);
|
),
|
||||||
pollster::block_on(painter.set_window(Some(&window)))?;
|
self.native_options.transparent,
|
||||||
painter
|
);
|
||||||
};
|
pollster::block_on(painter.set_window(Some(&window)))?;
|
||||||
|
|
||||||
let wgpu_render_state = painter.render_state();
|
let wgpu_render_state = painter.render_state();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ use std::sync::Arc;
|
||||||
use wasm_bindgen::JsValue;
|
use wasm_bindgen::JsValue;
|
||||||
use web_sys::HtmlCanvasElement;
|
use web_sys::HtmlCanvasElement;
|
||||||
|
|
||||||
use egui::mutex::RwLock;
|
|
||||||
use egui_wgpu::{renderer::ScreenDescriptor, RenderState, SurfaceErrorAction};
|
use egui_wgpu::{renderer::ScreenDescriptor, RenderState, SurfaceErrorAction};
|
||||||
|
|
||||||
use crate::WebOptions;
|
use crate::WebOptions;
|
||||||
|
|
@ -99,43 +98,20 @@ impl WebPainterWgpu {
|
||||||
}
|
}
|
||||||
.map_err(|err| format!("failed to create wgpu surface: {err}"))?;
|
.map_err(|err| format!("failed to create wgpu surface: {err}"))?;
|
||||||
|
|
||||||
let adapter = instance
|
let depth_format = egui_wgpu::depth_format_from_bits(options.depth_buffer, 0);
|
||||||
.request_adapter(&wgpu::RequestAdapterOptions {
|
let render_state =
|
||||||
power_preference: options.wgpu_options.power_preference,
|
RenderState::create(&options.wgpu_options, &instance, &surface, depth_format, 1)
|
||||||
force_fallback_adapter: false,
|
.await
|
||||||
compatible_surface: None,
|
.map_err(|err| err.to_string())?;
|
||||||
})
|
|
||||||
.await
|
|
||||||
.ok_or_else(|| "No suitable GPU adapters found on the system".to_owned())?;
|
|
||||||
|
|
||||||
let (device, queue) = adapter
|
|
||||||
.request_device(
|
|
||||||
&(*options.wgpu_options.device_descriptor)(&adapter),
|
|
||||||
None, // Capture doesn't work in the browser environment.
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.map_err(|err| format!("Failed to find wgpu device: {}", err))?;
|
|
||||||
|
|
||||||
let target_format =
|
|
||||||
egui_wgpu::preferred_framebuffer_format(&surface.get_capabilities(&adapter).formats);
|
|
||||||
|
|
||||||
let depth_format = options.wgpu_options.depth_format;
|
|
||||||
let renderer = egui_wgpu::Renderer::new(&device, target_format, depth_format, 1);
|
|
||||||
let render_state = RenderState {
|
|
||||||
device: Arc::new(device),
|
|
||||||
queue: Arc::new(queue),
|
|
||||||
target_format,
|
|
||||||
renderer: Arc::new(RwLock::new(renderer)),
|
|
||||||
};
|
|
||||||
|
|
||||||
let surface_configuration = wgpu::SurfaceConfiguration {
|
let surface_configuration = wgpu::SurfaceConfiguration {
|
||||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
||||||
format: target_format,
|
format: render_state.target_format,
|
||||||
width: 0,
|
width: 0,
|
||||||
height: 0,
|
height: 0,
|
||||||
present_mode: options.wgpu_options.present_mode,
|
present_mode: options.wgpu_options.present_mode,
|
||||||
alpha_mode: wgpu::CompositeAlphaMode::Auto,
|
alpha_mode: wgpu::CompositeAlphaMode::Auto,
|
||||||
view_formats: vec![target_format],
|
view_formats: vec![render_state.target_format],
|
||||||
};
|
};
|
||||||
|
|
||||||
log::debug!("wgpu painter initialized.");
|
log::debug!("wgpu painter initialized.");
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ epaint = { version = "0.21.0", path = "../epaint", default-features = false, fea
|
||||||
|
|
||||||
bytemuck = "1.7"
|
bytemuck = "1.7"
|
||||||
log = { version = "0.4", features = ["std"] }
|
log = { version = "0.4", features = ["std"] }
|
||||||
|
thiserror.workspace = true
|
||||||
type-map = "0.5.0"
|
type-map = "0.5.0"
|
||||||
wgpu = "0.16.0"
|
wgpu = "0.16.0"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,15 +21,80 @@ use std::sync::Arc;
|
||||||
|
|
||||||
use epaint::mutex::RwLock;
|
use epaint::mutex::RwLock;
|
||||||
|
|
||||||
|
#[derive(thiserror::Error, Debug)]
|
||||||
|
pub enum WgpuError {
|
||||||
|
#[error("Failed to create wgpu adapter, no suitable adapter found.")]
|
||||||
|
NoSuitableAdapterFound,
|
||||||
|
|
||||||
|
#[error("There was no valid format for the surface at all.")]
|
||||||
|
NoSurfaceFormatsAvailable,
|
||||||
|
|
||||||
|
#[error(transparent)]
|
||||||
|
RequestDeviceError(#[from] wgpu::RequestDeviceError),
|
||||||
|
|
||||||
|
#[error(transparent)]
|
||||||
|
CreateSurfaceError(#[from] wgpu::CreateSurfaceError),
|
||||||
|
}
|
||||||
|
|
||||||
/// Access to the render state for egui.
|
/// Access to the render state for egui.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct RenderState {
|
pub struct RenderState {
|
||||||
|
/// Wgpu adapter used for rendering.
|
||||||
|
pub adapter: Arc<wgpu::Adapter>,
|
||||||
|
|
||||||
|
/// Wgpu device used for rendering, created from the adapter.
|
||||||
pub device: Arc<wgpu::Device>,
|
pub device: Arc<wgpu::Device>,
|
||||||
|
|
||||||
|
/// Wgpu queue used for rendering, created from the adapter.
|
||||||
pub queue: Arc<wgpu::Queue>,
|
pub queue: Arc<wgpu::Queue>,
|
||||||
|
|
||||||
|
/// The target texture format used for presenting to the window.
|
||||||
pub target_format: wgpu::TextureFormat,
|
pub target_format: wgpu::TextureFormat,
|
||||||
|
|
||||||
|
/// Egui renderer responsible for drawing the UI.
|
||||||
pub renderer: Arc<RwLock<Renderer>>,
|
pub renderer: Arc<RwLock<Renderer>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl RenderState {
|
||||||
|
/// Creates a new `RenderState`, containing everything needed for drawing egui with wgpu.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
/// Wgpu initialization may fail due to incompatible hardware or driver for a given config.
|
||||||
|
pub async fn create(
|
||||||
|
config: &WgpuConfiguration,
|
||||||
|
instance: &wgpu::Instance,
|
||||||
|
surface: &wgpu::Surface,
|
||||||
|
depth_format: Option<wgpu::TextureFormat>,
|
||||||
|
msaa_samples: u32,
|
||||||
|
) -> Result<Self, WgpuError> {
|
||||||
|
let adapter = instance
|
||||||
|
.request_adapter(&wgpu::RequestAdapterOptions {
|
||||||
|
power_preference: config.power_preference,
|
||||||
|
compatible_surface: Some(surface),
|
||||||
|
force_fallback_adapter: false,
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.ok_or(WgpuError::NoSuitableAdapterFound)?;
|
||||||
|
|
||||||
|
let target_format =
|
||||||
|
crate::preferred_framebuffer_format(&surface.get_capabilities(&adapter).formats)?;
|
||||||
|
|
||||||
|
let (device, queue) = adapter
|
||||||
|
.request_device(&(*config.device_descriptor)(&adapter), None)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let renderer = Renderer::new(&device, target_format, depth_format, msaa_samples);
|
||||||
|
|
||||||
|
Ok(RenderState {
|
||||||
|
adapter: Arc::new(adapter),
|
||||||
|
device: Arc::new(device),
|
||||||
|
queue: Arc::new(queue),
|
||||||
|
target_format,
|
||||||
|
renderer: Arc::new(RwLock::new(renderer)),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Specifies which action should be taken as consequence of a [`wgpu::SurfaceError`]
|
/// Specifies which action should be taken as consequence of a [`wgpu::SurfaceError`]
|
||||||
pub enum SurfaceErrorAction {
|
pub enum SurfaceErrorAction {
|
||||||
/// Do nothing and skip the current frame.
|
/// Do nothing and skip the current frame.
|
||||||
|
|
@ -56,8 +121,6 @@ pub struct WgpuConfiguration {
|
||||||
|
|
||||||
/// Callback for surface errors.
|
/// Callback for surface errors.
|
||||||
pub on_surface_error: Arc<dyn Fn(wgpu::SurfaceError) -> SurfaceErrorAction>,
|
pub on_surface_error: Arc<dyn Fn(wgpu::SurfaceError) -> SurfaceErrorAction>,
|
||||||
|
|
||||||
pub depth_format: Option<wgpu::TextureFormat>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for WgpuConfiguration {
|
impl Default for WgpuConfiguration {
|
||||||
|
|
@ -88,7 +151,6 @@ impl Default for WgpuConfiguration {
|
||||||
present_mode: wgpu::PresentMode::AutoVsync,
|
present_mode: wgpu::PresentMode::AutoVsync,
|
||||||
power_preference: wgpu::util::power_preference_from_env()
|
power_preference: wgpu::util::power_preference_from_env()
|
||||||
.unwrap_or(wgpu::PowerPreference::HighPerformance),
|
.unwrap_or(wgpu::PowerPreference::HighPerformance),
|
||||||
depth_format: None,
|
|
||||||
|
|
||||||
on_surface_error: Arc::new(|err| {
|
on_surface_error: Arc::new(|err| {
|
||||||
if err == wgpu::SurfaceError::Outdated {
|
if err == wgpu::SurfaceError::Outdated {
|
||||||
|
|
@ -105,50 +167,40 @@ impl Default for WgpuConfiguration {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Find the framebuffer format that egui prefers
|
/// Find the framebuffer format that egui prefers
|
||||||
pub fn preferred_framebuffer_format(formats: &[wgpu::TextureFormat]) -> wgpu::TextureFormat {
|
///
|
||||||
|
/// # Errors
|
||||||
|
/// Returns [`WgpuError::NoSurfaceFormatsAvailable`] if the given list of formats is empty.
|
||||||
|
pub fn preferred_framebuffer_format(
|
||||||
|
formats: &[wgpu::TextureFormat],
|
||||||
|
) -> Result<wgpu::TextureFormat, WgpuError> {
|
||||||
for &format in formats {
|
for &format in formats {
|
||||||
if matches!(
|
if matches!(
|
||||||
format,
|
format,
|
||||||
wgpu::TextureFormat::Rgba8Unorm | wgpu::TextureFormat::Bgra8Unorm
|
wgpu::TextureFormat::Rgba8Unorm | wgpu::TextureFormat::Bgra8Unorm
|
||||||
) {
|
) {
|
||||||
return format;
|
return Ok(format);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
formats[0] // take the first
|
|
||||||
}
|
formats
|
||||||
// maybe use this-error?
|
.get(0)
|
||||||
#[derive(Debug)]
|
.copied()
|
||||||
pub enum WgpuError {
|
.ok_or(WgpuError::NoSurfaceFormatsAvailable)
|
||||||
DeviceError(wgpu::RequestDeviceError),
|
|
||||||
SurfaceError(wgpu::CreateSurfaceError),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for WgpuError {
|
/// Take's epi's depth/stencil bits and returns the corresponding wgpu format.
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
pub fn depth_format_from_bits(depth_buffer: u8, stencil_buffer: u8) -> Option<wgpu::TextureFormat> {
|
||||||
std::fmt::Debug::fmt(self, f)
|
match (depth_buffer, stencil_buffer) {
|
||||||
|
(0, 8) => Some(wgpu::TextureFormat::Stencil8),
|
||||||
|
(16, 0) => Some(wgpu::TextureFormat::Depth16Unorm),
|
||||||
|
(24, 0) => Some(wgpu::TextureFormat::Depth24Plus),
|
||||||
|
(24, 8) => Some(wgpu::TextureFormat::Depth24PlusStencil8),
|
||||||
|
(32, 0) => Some(wgpu::TextureFormat::Depth32Float),
|
||||||
|
(32, 8) => Some(wgpu::TextureFormat::Depth32FloatStencil8),
|
||||||
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::error::Error for WgpuError {
|
|
||||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
|
||||||
match self {
|
|
||||||
WgpuError::DeviceError(e) => e.source(),
|
|
||||||
WgpuError::SurfaceError(e) => e.source(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<wgpu::RequestDeviceError> for WgpuError {
|
|
||||||
fn from(e: wgpu::RequestDeviceError) -> Self {
|
|
||||||
Self::DeviceError(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<wgpu::CreateSurfaceError> for WgpuError {
|
|
||||||
fn from(e: wgpu::CreateSurfaceError) -> Self {
|
|
||||||
Self::SurfaceError(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
/// Profiling macro for feature "puffin"
|
/// Profiling macro for feature "puffin"
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use epaint::{self, mutex::RwLock};
|
use crate::{renderer, RenderState, SurfaceErrorAction, WgpuConfiguration};
|
||||||
|
|
||||||
use crate::{renderer, RenderState, Renderer, SurfaceErrorAction, WgpuConfiguration};
|
|
||||||
|
|
||||||
struct SurfaceState {
|
struct SurfaceState {
|
||||||
surface: wgpu::Surface,
|
surface: wgpu::Surface,
|
||||||
|
|
@ -83,7 +81,6 @@ pub struct Painter {
|
||||||
screen_capture_state: Option<CaptureState>,
|
screen_capture_state: Option<CaptureState>,
|
||||||
|
|
||||||
instance: wgpu::Instance,
|
instance: wgpu::Instance,
|
||||||
adapter: Option<wgpu::Adapter>,
|
|
||||||
render_state: Option<RenderState>,
|
render_state: Option<RenderState>,
|
||||||
surface_state: Option<SurfaceState>,
|
surface_state: Option<SurfaceState>,
|
||||||
}
|
}
|
||||||
|
|
@ -104,7 +101,7 @@ impl Painter {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
configuration: WgpuConfiguration,
|
configuration: WgpuConfiguration,
|
||||||
msaa_samples: u32,
|
msaa_samples: u32,
|
||||||
depth_bits: u8,
|
depth_format: Option<wgpu::TextureFormat>,
|
||||||
support_transparent_backbuffer: bool,
|
support_transparent_backbuffer: bool,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
|
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
|
||||||
|
|
@ -116,12 +113,11 @@ impl Painter {
|
||||||
configuration,
|
configuration,
|
||||||
msaa_samples,
|
msaa_samples,
|
||||||
support_transparent_backbuffer,
|
support_transparent_backbuffer,
|
||||||
depth_format: (depth_bits > 0).then_some(wgpu::TextureFormat::Depth32Float),
|
depth_format,
|
||||||
depth_texture_view: None,
|
depth_texture_view: None,
|
||||||
screen_capture_state: None,
|
screen_capture_state: None,
|
||||||
|
|
||||||
instance,
|
instance,
|
||||||
adapter: None,
|
|
||||||
render_state: None,
|
render_state: None,
|
||||||
surface_state: None,
|
surface_state: None,
|
||||||
msaa_texture_view: None,
|
msaa_texture_view: None,
|
||||||
|
|
@ -135,60 +131,6 @@ impl Painter {
|
||||||
self.render_state.clone()
|
self.render_state.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn init_render_state(
|
|
||||||
&self,
|
|
||||||
adapter: &wgpu::Adapter,
|
|
||||||
target_format: wgpu::TextureFormat,
|
|
||||||
) -> Result<RenderState, wgpu::RequestDeviceError> {
|
|
||||||
adapter
|
|
||||||
.request_device(&(*self.configuration.device_descriptor)(adapter), None)
|
|
||||||
.await
|
|
||||||
.map(|(device, queue)| {
|
|
||||||
let renderer =
|
|
||||||
Renderer::new(&device, target_format, self.depth_format, self.msaa_samples);
|
|
||||||
RenderState {
|
|
||||||
device: Arc::new(device),
|
|
||||||
queue: Arc::new(queue),
|
|
||||||
target_format,
|
|
||||||
renderer: Arc::new(RwLock::new(renderer)),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// We want to defer the initialization of our render state until we have a surface
|
|
||||||
// so we can take its format into account.
|
|
||||||
//
|
|
||||||
// After we've initialized our render state once though we expect all future surfaces
|
|
||||||
// will have the same format and so this render state will remain valid.
|
|
||||||
async fn ensure_render_state_for_surface(
|
|
||||||
&mut self,
|
|
||||||
surface: &wgpu::Surface,
|
|
||||||
) -> Result<(), wgpu::RequestDeviceError> {
|
|
||||||
if self.adapter.is_none() {
|
|
||||||
self.adapter = self
|
|
||||||
.instance
|
|
||||||
.request_adapter(&wgpu::RequestAdapterOptions {
|
|
||||||
power_preference: self.configuration.power_preference,
|
|
||||||
compatible_surface: Some(surface),
|
|
||||||
force_fallback_adapter: false,
|
|
||||||
})
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
if self.render_state.is_none() {
|
|
||||||
match &self.adapter {
|
|
||||||
Some(adapter) => {
|
|
||||||
let swapchain_format = crate::preferred_framebuffer_format(
|
|
||||||
&surface.get_capabilities(adapter).formats,
|
|
||||||
);
|
|
||||||
let rs = self.init_render_state(adapter, swapchain_format).await?;
|
|
||||||
self.render_state = Some(rs);
|
|
||||||
}
|
|
||||||
None => return Err(wgpu::RequestDeviceError {}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn configure_surface(
|
fn configure_surface(
|
||||||
surface_state: &SurfaceState,
|
surface_state: &SurfaceState,
|
||||||
render_state: &RenderState,
|
render_state: &RenderState,
|
||||||
|
|
@ -235,20 +177,31 @@ impl Painter {
|
||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
/// If the provided wgpu configuration does not match an available device.
|
/// If the provided wgpu configuration does not match an available device.
|
||||||
pub async unsafe fn set_window(
|
pub async fn set_window(
|
||||||
&mut self,
|
&mut self,
|
||||||
window: Option<&winit::window::Window>,
|
window: Option<&winit::window::Window>,
|
||||||
) -> Result<(), crate::WgpuError> {
|
) -> Result<(), crate::WgpuError> {
|
||||||
match window {
|
match window {
|
||||||
Some(window) => {
|
Some(window) => {
|
||||||
let surface = self.instance.create_surface(&window)?;
|
let surface = unsafe { self.instance.create_surface(&window)? };
|
||||||
|
|
||||||
self.ensure_render_state_for_surface(&surface).await?;
|
let render_state = if let Some(render_state) = &self.render_state {
|
||||||
|
render_state
|
||||||
|
} else {
|
||||||
|
let render_state = RenderState::create(
|
||||||
|
&self.configuration,
|
||||||
|
&self.instance,
|
||||||
|
&surface,
|
||||||
|
self.depth_format,
|
||||||
|
self.msaa_samples,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
self.render_state.get_or_insert(render_state)
|
||||||
|
};
|
||||||
|
|
||||||
let alpha_mode = if self.support_transparent_backbuffer {
|
let alpha_mode = if self.support_transparent_backbuffer {
|
||||||
let supported_alpha_modes = surface
|
let supported_alpha_modes =
|
||||||
.get_capabilities(self.adapter.as_ref().unwrap())
|
surface.get_capabilities(&render_state.adapter).alpha_modes;
|
||||||
.alpha_modes;
|
|
||||||
|
|
||||||
// Prefer pre multiplied over post multiplied!
|
// Prefer pre multiplied over post multiplied!
|
||||||
if supported_alpha_modes.contains(&wgpu::CompositeAlphaMode::PreMultiplied) {
|
if supported_alpha_modes.contains(&wgpu::CompositeAlphaMode::PreMultiplied) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue