Wgpu resources are no longer wrapped in `Arc` (since they are now `Clone`) (#5612)

Co-authored-by: Nicolas <bircni@icloud.com>
This commit is contained in:
Andreas Reich 2025-01-20 18:06:35 +01:00 committed by GitHub
parent cf965aaa30
commit 30e66e4575
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 37 additions and 45 deletions

View File

@ -63,21 +63,20 @@ pub enum WgpuError {
#[derive(Clone)] #[derive(Clone)]
pub struct RenderState { pub struct RenderState {
/// Wgpu adapter used for rendering. /// Wgpu adapter used for rendering.
pub adapter: Arc<wgpu::Adapter>, pub adapter: wgpu::Adapter,
/// All the available adapters. /// All the available adapters.
/// ///
/// This is not available on web. /// This is not available on web.
/// On web, we always select WebGPU is available, then fall back to WebGL if not. /// On web, we always select WebGPU is available, then fall back to WebGL if not.
// TODO(gfx-rs/wgpu#6665): Remove layer of `Arc` here once we update to wgpu 24
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
pub available_adapters: Arc<[Arc<wgpu::Adapter>]>, pub available_adapters: Vec<wgpu::Adapter>,
/// Wgpu device used for rendering, created from the adapter. /// Wgpu device used for rendering, created from the adapter.
pub device: Arc<wgpu::Device>, pub device: wgpu::Device,
/// Wgpu queue used for rendering, created from the adapter. /// Wgpu queue used for rendering, created from the adapter.
pub queue: Arc<wgpu::Queue>, pub queue: wgpu::Queue,
/// The target texture format used for presenting to the window. /// The target texture format used for presenting to the window.
pub target_format: wgpu::TextureFormat, pub target_format: wgpu::TextureFormat,
@ -90,8 +89,8 @@ async fn request_adapter(
instance: &wgpu::Instance, instance: &wgpu::Instance,
power_preference: wgpu::PowerPreference, power_preference: wgpu::PowerPreference,
compatible_surface: Option<&wgpu::Surface<'_>>, compatible_surface: Option<&wgpu::Surface<'_>>,
_available_adapters: &[Arc<wgpu::Adapter>], _available_adapters: &[wgpu::Adapter],
) -> Result<Arc<wgpu::Adapter>, WgpuError> { ) -> Result<wgpu::Adapter, WgpuError> {
profiling::function_scope!(); profiling::function_scope!();
let adapter = instance let adapter = instance
@ -149,10 +148,7 @@ async fn request_adapter(
); );
} }
// On wasm, depending on feature flags, wgpu objects may or may not implement sync. Ok(adapter)
// 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)]
Ok(Arc::new(adapter))
} }
impl RenderState { impl RenderState {
@ -179,12 +175,7 @@ impl RenderState {
wgpu::Backends::all() wgpu::Backends::all()
}; };
instance instance.enumerate_adapters(backends)
.enumerate_adapters(backends)
// TODO(gfx-rs/wgpu#6665): Remove layer of `Arc` here once we update to wgpu 24.
.into_iter()
.map(Arc::new)
.collect::<Vec<_>>()
}; };
let (adapter, device, queue) = match config.wgpu_setup.clone() { let (adapter, device, queue) = match config.wgpu_setup.clone() {
@ -222,10 +213,7 @@ impl RenderState {
.await? .await?
}; };
// On wasm, depending on feature flags, wgpu objects may or may not implement sync. (adapter, device, queue)
// 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)]
(adapter, Arc::new(device), Arc::new(queue))
} }
WgpuSetup::Existing(WgpuSetupExisting { WgpuSetup::Existing(WgpuSetupExisting {
instance: _, instance: _,
@ -258,7 +246,7 @@ impl RenderState {
Ok(Self { Ok(Self {
adapter, adapter,
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
available_adapters: available_adapters.into(), available_adapters,
device, device,
queue, queue,
target_format, target_format,
@ -268,7 +256,7 @@ impl RenderState {
} }
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
fn describe_adapters(adapters: &[Arc<wgpu::Adapter>]) -> String { fn describe_adapters(adapters: &[wgpu::Adapter]) -> String {
if adapters.is_empty() { if adapters.is_empty() {
"(none)".to_owned() "(none)".to_owned()
} else if adapters.len() == 1 { } else if adapters.len() == 1 {

View File

@ -45,7 +45,7 @@ impl WgpuSetup {
/// ///
/// Does *not* store the wgpu instance, so calling this repeatedly may /// Does *not* store the wgpu instance, so calling this repeatedly may
/// create a new instance every time! /// create a new instance every time!
pub async fn new_instance(&self) -> Arc<wgpu::Instance> { pub async fn new_instance(&self) -> wgpu::Instance {
match self { match self {
Self::CreateNew(create_new) => { Self::CreateNew(create_new) => {
#[allow(unused_mut)] #[allow(unused_mut)]
@ -65,12 +65,8 @@ impl WgpuSetup {
} }
log::debug!("Creating wgpu instance with backends {:?}", backends); log::debug!("Creating wgpu instance with backends {:?}", backends);
#[allow(clippy::arc_with_non_send_sync)]
Arc::new(
wgpu::util::new_instance_with_webgpu_detection(&create_new.instance_descriptor) wgpu::util::new_instance_with_webgpu_detection(&create_new.instance_descriptor)
.await, .await
)
} }
Self::Existing(existing) => existing.instance.clone(), Self::Existing(existing) => existing.instance.clone(),
} }
@ -93,9 +89,8 @@ impl From<WgpuSetupExisting> for WgpuSetup {
/// ///
/// This can be used for fully custom adapter selection. /// This can be used for fully custom adapter selection.
/// If available, `wgpu::Surface` is passed to allow checking for surface compatibility. /// If available, `wgpu::Surface` is passed to allow checking for surface compatibility.
// TODO(gfx-rs/wgpu#6665): Remove layer of `Arc` here.
pub type NativeAdapterSelectorMethod = Arc< pub type NativeAdapterSelectorMethod = Arc<
dyn Fn(&[Arc<wgpu::Adapter>], Option<&wgpu::Surface<'_>>) -> Result<Arc<wgpu::Adapter>, String> dyn Fn(&[wgpu::Adapter], Option<&wgpu::Surface<'_>>) -> Result<wgpu::Adapter, String>
+ Send + Send
+ Sync, + Sync,
>; >;
@ -215,8 +210,8 @@ impl Default for WgpuSetupCreateNew {
/// Used for [`WgpuSetup::Existing`]. /// Used for [`WgpuSetup::Existing`].
#[derive(Clone)] #[derive(Clone)]
pub struct WgpuSetupExisting { pub struct WgpuSetupExisting {
pub instance: Arc<wgpu::Instance>, pub instance: wgpu::Instance,
pub adapter: Arc<wgpu::Adapter>, pub adapter: wgpu::Adapter,
pub device: Arc<wgpu::Device>, pub device: wgpu::Device,
pub queue: Arc<wgpu::Queue>, pub queue: wgpu::Queue,
} }

View File

@ -27,7 +27,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: Arc<wgpu::Instance>, instance: wgpu::Instance,
render_state: Option<RenderState>, render_state: Option<RenderState>,
// Per viewport/window: // Per viewport/window:

View File

@ -1,5 +1,4 @@
use crate::app_kind::AppKind; use crate::app_kind::AppKind;
use crate::wgpu::WgpuTestRenderer;
use crate::{Harness, LazyRenderer, TestRenderer}; use crate::{Harness, LazyRenderer, TestRenderer};
use egui::{Pos2, Rect, Vec2}; use egui::{Pos2, Rect, Vec2};
use std::marker::PhantomData; use std::marker::PhantomData;
@ -75,16 +74,16 @@ impl<State> HarnessBuilder<State> {
/// Enable wgpu rendering with a default setup suitable for testing. /// Enable wgpu rendering with a default setup suitable for testing.
/// ///
/// This sets up a [`WgpuTestRenderer`] with the default setup. /// This sets up a [`crate::wgpu::WgpuTestRenderer`] with the default setup.
#[cfg(feature = "wgpu")] #[cfg(feature = "wgpu")]
pub fn wgpu(self) -> Self { pub fn wgpu(self) -> Self {
self.renderer(WgpuTestRenderer::default()) self.renderer(crate::wgpu::WgpuTestRenderer::default())
} }
/// Enable wgpu rendering with the given setup. /// Enable wgpu rendering with the given setup.
#[cfg(feature = "wgpu")] #[cfg(feature = "wgpu")]
pub fn wgpu_setup(self, setup: egui_wgpu::WgpuSetup) -> Self { pub fn wgpu_setup(self, setup: egui_wgpu::WgpuSetup) -> Self {
self.renderer(WgpuTestRenderer::from_setup(setup)) self.renderer(crate::wgpu::WgpuTestRenderer::from_setup(setup))
} }
/// Create a new Harness with the given app closure and a state. /// Create a new Harness with the given app closure and a state.

View File

@ -402,6 +402,7 @@ impl<'a, State> Harness<'a, State> {
/// ///
/// # Errors /// # Errors
/// Returns an error if the rendering fails. /// Returns an error if the rendering fails.
#[cfg(any(feature = "wgpu", feature = "snapshot"))]
pub fn render(&mut self) -> Result<image::RgbaImage, String> { pub fn render(&mut self) -> Result<image::RgbaImage, String> {
self.renderer.render(&self.ctx, &self.output) self.renderer.render(&self.ctx, &self.output)
} }

View File

@ -1,5 +1,4 @@
use egui::{Context, FullOutput, TexturesDelta}; use egui::TexturesDelta;
use image::RgbaImage;
pub trait TestRenderer { pub trait TestRenderer {
/// We use this to pass the glow / wgpu render state to [`eframe::Frame`]. /// We use this to pass the glow / wgpu render state to [`eframe::Frame`].
@ -13,7 +12,12 @@ pub trait TestRenderer {
/// ///
/// # Errors /// # Errors
/// Returns an error if the rendering fails. /// Returns an error if the rendering fails.
fn render(&mut self, ctx: &Context, output: &FullOutput) -> Result<RgbaImage, String>; #[cfg(any(feature = "wgpu", feature = "snapshot"))]
fn render(
&mut self,
ctx: &egui::Context,
output: &egui::FullOutput,
) -> Result<image::RgbaImage, String>;
} }
/// A lazy renderer that initializes the renderer on the first render call. /// A lazy renderer that initializes the renderer on the first render call.
@ -58,7 +62,12 @@ impl TestRenderer for LazyRenderer {
} }
} }
fn render(&mut self, ctx: &Context, output: &FullOutput) -> Result<RgbaImage, String> { #[cfg(any(feature = "wgpu", feature = "snapshot"))]
fn render(
&mut self,
ctx: &egui::Context,
output: &egui::FullOutput,
) -> Result<image::RgbaImage, String> {
match self { match self {
Self::Uninitialized { Self::Uninitialized {
texture_ops, texture_ops,