diff --git a/all-is-cubes-gpu/src/common.rs b/all-is-cubes-gpu/src/common.rs index 7d1196846..db21fe3f5 100644 --- a/all-is-cubes-gpu/src/common.rs +++ b/all-is-cubes-gpu/src/common.rs @@ -9,6 +9,8 @@ mod debug_lines; pub(crate) use debug_lines::*; mod draw_to_texture; pub(crate) use draw_to_texture::*; +mod id; +pub(crate) use id::*; mod info; pub use info::*; mod msw; diff --git a/all-is-cubes-gpu/src/common/id.rs b/all-is-cubes-gpu/src/common/id.rs new file mode 100644 index 000000000..71d0a64cc --- /dev/null +++ b/all-is-cubes-gpu/src/common/id.rs @@ -0,0 +1,75 @@ +//! DIY replacement for the `wgpu` `.global_id()` functionality which is being removed +//! in `wgpu` version 23. + +use std::fmt; +use std::marker::PhantomData; +use std::ops; +use std::sync::atomic::{self, Ordering}; +use std::sync::Arc; + +/// Adds a globally unique identifier to a value. +/// +/// This identifier may be used to compare two values which do not implement [`PartialEq`], +/// or remember their identities without necessarily retaining the values themselves. +#[derive(Clone, Debug)] +pub(crate) struct Identified { + id: Id, + value: T, +} + +/// A unique identifier for some [`Identified`] value. +pub(crate) struct Id { + id: u64, + _phantom: PhantomData>, +} + +impl Identified { + /// Wraps the given value and assigns a new unique [`Id`] for it. + pub fn new(value: T) -> Self { + static ID_COUNTER: atomic::AtomicU64 = atomic::AtomicU64::new(0); + let id = ID_COUNTER.fetch_add(1, Ordering::Relaxed); + Self { + id: Id { + id, + _phantom: PhantomData, + }, + value, + } + } + + pub fn global_id(&self) -> Id { + self.id + } +} + +impl ops::Deref for Identified { + type Target = T; + fn deref(&self) -> &T { + &self.value + } +} + +impl Eq for Id {} +impl PartialEq for Id { + fn eq(&self, other: &Self) -> bool { + self.id == other.id + } +} +impl std::hash::Hash for Id { + fn hash(&self, state: &mut H) { + self.id.hash(state); + } +} + +impl fmt::Debug for Id { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("Id").field(&self.id).finish() + } +} + +impl Copy for Id {} +impl Clone for Id { + fn clone(&self) -> Self { + *self + } +} diff --git a/all-is-cubes-gpu/src/in_wgpu.rs b/all-is-cubes-gpu/src/in_wgpu.rs index 1d6f6fc58..50111fb2a 100644 --- a/all-is-cubes-gpu/src/in_wgpu.rs +++ b/all-is-cubes-gpu/src/in_wgpu.rs @@ -24,6 +24,7 @@ use all_is_cubes::util::Executor; use crate::in_wgpu::raytrace_to_texture::RaytraceToTexture; use crate::in_wgpu::shaders::Shaders; +use crate::Id; #[cfg(feature = "rerun")] use crate::RerunFilter; use crate::{ @@ -297,10 +298,9 @@ struct EverythingRenderer { lines_vertex_count: u32, /// Pipeline for the color postprocessing + info text layer drawing. - postprocess_render_pipeline: Memo, wgpu::RenderPipeline>, + postprocess_render_pipeline: Memo, wgpu::RenderPipeline>, #[allow(clippy::type_complexity)] - postprocess_bind_group: - Memo<(wgpu::Id, frame_texture::FbtId), wgpu::BindGroup>, + postprocess_bind_group: Memo<(Id, frame_texture::FbtId), wgpu::BindGroup>, postprocess_bind_group_layout: wgpu::BindGroupLayout, postprocess_camera_buffer: wgpu::Buffer, diff --git a/all-is-cubes-gpu/src/in_wgpu/block_texture.rs b/all-is-cubes-gpu/src/in_wgpu/block_texture.rs index 089fe07b5..9357d14bb 100644 --- a/all-is-cubes-gpu/src/in_wgpu/block_texture.rs +++ b/all-is-cubes-gpu/src/in_wgpu/block_texture.rs @@ -15,7 +15,7 @@ use all_is_cubes_mesh::texture::{self, Channels}; use crate::in_wgpu::glue::{size3d_to_extent, write_texture_by_aab}; use crate::in_wgpu::vertex::{AtlasTexel, FixTexCoord, TexPoint}; use crate::octree_alloc::{Alloctree, AlloctreeHandle}; -use crate::{BlockTextureInfo, Msw}; +use crate::{BlockTextureInfo, Identified, Msw}; //------------------------------------------------------------------------------------------------// // Types @@ -56,9 +56,9 @@ pub struct AtlasTile { } pub(crate) struct BlockTextureViews { - pub g0_reflectance: Arc, - pub g1_reflectance: Arc, - pub g1_emission: Arc, + pub g0_reflectance: Arc>, + pub g1_reflectance: Arc>, + pub g1_emission: Arc>, } /// Internal, weak-referencing version of [`AtlasTile`]. @@ -137,7 +137,7 @@ struct GpuTexture { texture: wgpu::Texture, /// The texture view is wrapped in [`Arc`] so that it can be used by drawing code /// without holding the lock around this. - texture_view: Arc, + texture_view: Arc>, } //------------------------------------------------------------------------------------------------// @@ -298,7 +298,7 @@ impl AllocatorBacking { backing_mutex: &Mutex, device: &wgpu::Device, queue: &wgpu::Queue, - ) -> (Group>, BlockTextureInfo) { + ) -> (Group>>, BlockTextureInfo) { let mut backing_lock_guard = backing_mutex.lock().unwrap(); let backing = &mut *backing_lock_guard; @@ -492,7 +492,9 @@ impl GpuTexture { | wgpu::TextureUsages::COPY_DST, label: Some(label), }); - let texture_view = Arc::new(texture.create_view(&wgpu::TextureViewDescriptor::default())); + let texture_view = Arc::new(Identified::new( + texture.create_view(&wgpu::TextureViewDescriptor::default()), + )); Self { texture, texture_view, diff --git a/all-is-cubes-gpu/src/in_wgpu/bloom.rs b/all-is-cubes-gpu/src/in_wgpu/bloom.rs index 6f76689ec..100b50821 100644 --- a/all-is-cubes-gpu/src/in_wgpu/bloom.rs +++ b/all-is-cubes-gpu/src/in_wgpu/bloom.rs @@ -8,7 +8,7 @@ pub(crate) struct BloomPipelines { linear_sampler: wgpu::Sampler, downsample_pipeline: wgpu::RenderPipeline, upsample_pipeline: wgpu::RenderPipeline, - bloom_shader_id: wgpu::Id, + bloom_shader_id: crate::Id, } impl BloomPipelines { @@ -167,7 +167,7 @@ pub(crate) struct BloomResources { pub bloom_output_texture_view: wgpu::TextureView, - bloom_shader_id: wgpu::Id, + bloom_shader_id: crate::Id, } impl BloomResources { @@ -281,7 +281,7 @@ impl BloomResources { } /// For determinig whether this is outdated - pub(crate) fn bloom_shader_id(&self) -> wgpu::Id { + pub(crate) fn bloom_shader_id(&self) -> crate::Id { self.bloom_shader_id } } diff --git a/all-is-cubes-gpu/src/in_wgpu/frame_texture.rs b/all-is-cubes-gpu/src/in_wgpu/frame_texture.rs index a300cc2d8..8ed8dbe12 100644 --- a/all-is-cubes-gpu/src/in_wgpu/frame_texture.rs +++ b/all-is-cubes-gpu/src/in_wgpu/frame_texture.rs @@ -8,13 +8,13 @@ use all_is_cubes_render::Flaws; use super::bloom; use crate::in_wgpu::shaders::Shaders; -use crate::EgFramebuffer; +use crate::{EgFramebuffer, Identified}; /// A RGBA [`wgpu::Texture`] with a CPU-side buffer that can be drawn on. pub(crate) struct DrawableTexture { texture_format: wgpu::TextureFormat, texture: Option, - texture_view: Option, + texture_view: Option>, size: wgpu::Extent3d, local_buffer: EgFramebuffer, } @@ -72,7 +72,9 @@ impl DrawableTexture { width: new_extent.width, height: new_extent.height, }), - texture_view: Some(texture.create_view(&wgpu::TextureViewDescriptor::default())), + texture_view: Some(Identified::new( + texture.create_view(&wgpu::TextureViewDescriptor::default()), + )), texture: Some(texture), size: new_extent, }; @@ -82,7 +84,7 @@ impl DrawableTexture { &mut self.local_buffer } - pub fn view(&self) -> Option<&wgpu::TextureView> { + pub fn view(&self) -> Option<&Identified> { self.texture_view.as_ref() } @@ -166,7 +168,7 @@ pub(crate) struct FramebufferTextures { linear_scene_tex: wgpu::Texture, /// View for writing into [`Self::linear_scene_texture`], and reading if multisampling /// is not enabled. - linear_scene_view: wgpu::TextureView, + linear_scene_view: Identified, /// If multisampling is enabled, provides the “resolve target” companion to /// `linear_scene_texture`. This texture has a `sample_count` of 1, is @@ -175,7 +177,7 @@ pub(crate) struct FramebufferTextures { /// `linear_scene_texture` directly as input to postprocessing. linear_scene_resolved_tex: Option, /// View for reading [`Self::linear_scene_resolved_tex`]. - linear_scene_resolved_view: Option, + linear_scene_resolved_view: Option>, /// Depth texture to pair with `linear_scene_texture`. depth_texture_view: wgpu::TextureView, @@ -256,10 +258,10 @@ impl FramebufferTextures { None }; - let linear_scene_view = linear_scene_tex.create_view(&Default::default()); + let linear_scene_view = Identified::new(linear_scene_tex.create_view(&Default::default())); let linear_scene_resolved_view = linear_scene_resolved_tex .as_ref() - .map(|t| t.create_view(&Default::default())); + .map(|t| Identified::new(t.create_view(&Default::default()))); // TODO: duplicative with scene_for_postprocessing_input let bloom_input_view = if let Some(resolved) = &linear_scene_resolved_view { @@ -296,7 +298,7 @@ impl FramebufferTextures { ) -> wgpu::RenderPassColorAttachment<'_> { wgpu::RenderPassColorAttachment { view: &self.linear_scene_view, - resolve_target: self.linear_scene_resolved_view.as_ref(), + resolve_target: self.linear_scene_resolved_view.as_deref(), ops: wgpu::Operations { load: color_load_op, store: wgpu::StoreOp::Store, @@ -324,7 +326,7 @@ impl FramebufferTextures { stencil_ops: None, } } - pub(crate) fn scene_for_postprocessing_input(&self) -> &wgpu::TextureView { + pub(crate) fn scene_for_postprocessing_input(&self) -> &Identified { if let Some(resolved) = &self.linear_scene_resolved_view { resolved } else { @@ -416,7 +418,7 @@ impl FramebufferTextures { /// has the same GPU resources or not, for [`common::Memo`] purposes. #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub(crate) struct FbtId { - scene_id: wgpu::Id, + scene_id: crate::Id, } /// Pure-data inputs to [`FramebufferTextures`]'s choice of texture format and size. diff --git a/all-is-cubes-gpu/src/in_wgpu/light_texture.rs b/all-is-cubes-gpu/src/in_wgpu/light_texture.rs index 05fccddc1..672c4552c 100644 --- a/all-is-cubes-gpu/src/in_wgpu/light_texture.rs +++ b/all-is-cubes-gpu/src/in_wgpu/light_texture.rs @@ -12,8 +12,9 @@ use all_is_cubes::math::{ use all_is_cubes::space::Space; use all_is_cubes_render::camera::Camera; -use crate::in_wgpu::glue::{ - extent_to_size3d, point_to_origin, size3d_to_extent, write_texture_by_aab, +use crate::{ + in_wgpu::glue::{extent_to_size3d, point_to_origin, size3d_to_extent, write_texture_by_aab}, + Identified, }; type Texel = [u8; LightTexture::COMPONENTS]; @@ -63,7 +64,7 @@ fn visible_light_volume(space_bounds: GridAab, camera: &Camera) -> GridAab { #[doc(hidden)] // public for benchmark pub struct LightTexture { texture: wgpu::Texture, - texture_view: wgpu::TextureView, + texture_view: Identified, /// Temporary storage for updated light texels to be copied into the texture. copy_buffer: wgpu::Buffer, @@ -116,7 +117,9 @@ impl LightTexture { label: Some(&format!("{label_prefix} space light")), }); Self { - texture_view: texture.create_view(&wgpu::TextureViewDescriptor::default()), + texture_view: Identified::new( + texture.create_view(&wgpu::TextureViewDescriptor::default()), + ), texture, copy_buffer: device.create_buffer(&wgpu::BufferDescriptor { label: Some(&format!("{label_prefix} space light copy buffer")), @@ -392,7 +395,7 @@ impl LightTexture { total_count } - pub fn texture_view(&self) -> &wgpu::TextureView { + pub(crate) fn texture_view(&self) -> &Identified { &self.texture_view } } diff --git a/all-is-cubes-gpu/src/in_wgpu/raytrace_to_texture.rs b/all-is-cubes-gpu/src/in_wgpu/raytrace_to_texture.rs index 7cb7b63a3..b3a344d46 100644 --- a/all-is-cubes-gpu/src/in_wgpu/raytrace_to_texture.rs +++ b/all-is-cubes-gpu/src/in_wgpu/raytrace_to_texture.rs @@ -24,12 +24,12 @@ use all_is_cubes_render::RenderError; use crate::in_wgpu::frame_texture::DrawableTexture; use crate::in_wgpu::pipelines::Pipelines; -use crate::{Memo, ToTexel}; +use crate::{Identified, Memo, ToTexel}; #[derive(Debug)] pub(crate) struct RaytraceToTexture { inner: Arc>, - frame_copy_bind_group: Memo, wgpu::BindGroup>, + frame_copy_bind_group: Memo, wgpu::BindGroup>, } /// State for the possibly-asynchronous tracing job. @@ -102,7 +102,7 @@ impl RaytraceToTexture { inner.set_viewport(device, raytracer_size_policy(camera.viewport())); // Update bind group if needed - let rt_texture_view: &wgpu::TextureView = inner.render_target.view().unwrap(); + let rt_texture_view: &Identified = inner.render_target.view().unwrap(); self.frame_copy_bind_group .get_or_insert(rt_texture_view.global_id(), || { device.create_bind_group(&wgpu::BindGroupDescriptor { diff --git a/all-is-cubes-gpu/src/in_wgpu/rerun_image.rs b/all-is-cubes-gpu/src/in_wgpu/rerun_image.rs index 9ab6e82e0..b028b95c1 100644 --- a/all-is-cubes-gpu/src/in_wgpu/rerun_image.rs +++ b/all-is-cubes-gpu/src/in_wgpu/rerun_image.rs @@ -22,7 +22,7 @@ pub(crate) struct RerunImageExport { /// Intermediate textures used for format conversions. /// The texture ID is of the scene color texture we need to read. /// The image size is our intermediate texture size, which may be different. - resources: Memo<(wgpu::Id, ImageSize), Resources>, + resources: Memo<(crate::Id, ImageSize), Resources>, } struct Resources { diff --git a/all-is-cubes-gpu/src/in_wgpu/shaders.rs b/all-is-cubes-gpu/src/in_wgpu/shaders.rs index ad660beab..bd804529b 100644 --- a/all-is-cubes-gpu/src/in_wgpu/shaders.rs +++ b/all-is-cubes-gpu/src/in_wgpu/shaders.rs @@ -11,6 +11,7 @@ use futures_util::task::noop_waker_ref; use all_is_cubes::listen; use crate::reloadable::{reloadable_str, Reloadable}; +use crate::Identified; /// All shaders that are built into the source code of this crate. pub(crate) struct Shaders { @@ -100,7 +101,7 @@ pub(crate) struct ReloadableShader { label: String, source: listen::ListenableSource>, dirty: listen::DirtyFlag, - current_module: wgpu::ShaderModule, + current_module: Identified, next_module: Option>>, } @@ -111,10 +112,11 @@ impl ReloadableShader { wgsl_source: listen::ListenableSource>, ) -> Self { let dirty = listen::DirtyFlag::listening(false, &wgsl_source); - let current_module = device.create_shader_module(wgpu::ShaderModuleDescriptor { - label: Some(&label), - source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(&*wgsl_source.get())), - }); + let current_module = + Identified::new(device.create_shader_module(wgpu::ShaderModuleDescriptor { + label: Some(&label), + source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(&*wgsl_source.get())), + })); Self { label, @@ -125,7 +127,7 @@ impl ReloadableShader { } } - pub fn get(&self) -> &wgpu::ShaderModule { + pub fn get(&self) -> &Identified { &self.current_module } @@ -166,7 +168,7 @@ impl ReloadableShader { self.next_module = None; match result { Ok(new_module) => { - self.current_module = new_module; + self.current_module = Identified::new(new_module); true } Err(e) => { diff --git a/all-is-cubes-gpu/src/in_wgpu/skybox.rs b/all-is-cubes-gpu/src/in_wgpu/skybox.rs index fbae40a0b..a126b3951 100644 --- a/all-is-cubes-gpu/src/in_wgpu/skybox.rs +++ b/all-is-cubes-gpu/src/in_wgpu/skybox.rs @@ -1,13 +1,16 @@ +use half::f16; + use all_is_cubes::euclid::vec3; use all_is_cubes::space::Sky; -use half::f16; + +use crate::Identified; /// GPU resources to render a [`Sky`]. #[derive(Debug)] pub(in crate::in_wgpu) struct Skybox { texture_label: String, texture: wgpu::Texture, - texture_view: wgpu::TextureView, + texture_view: Identified, } impl Skybox { @@ -37,7 +40,7 @@ impl Skybox { self.texture.width() } - pub(crate) fn texture_view(&self) -> &wgpu::TextureView { + pub(crate) fn texture_view(&self) -> &Identified { &self.texture_view } } @@ -77,12 +80,15 @@ pub(in crate::in_wgpu) fn create_skybox_texture( }) } -fn create_skybox_texture_view(label: &str, texture: &wgpu::Texture) -> wgpu::TextureView { - texture.create_view(&wgpu::TextureViewDescriptor { +fn create_skybox_texture_view( + label: &str, + texture: &wgpu::Texture, +) -> Identified { + Identified::new(texture.create_view(&wgpu::TextureViewDescriptor { label: Some(label), dimension: Some(wgpu::TextureViewDimension::Cube), ..Default::default() - }) + })) } // texture format must be HDR supporting diff --git a/all-is-cubes-gpu/src/in_wgpu/space.rs b/all-is-cubes-gpu/src/in_wgpu/space.rs index 6787b9cae..f1ff414ac 100644 --- a/all-is-cubes-gpu/src/in_wgpu/space.rs +++ b/all-is-cubes-gpu/src/in_wgpu/space.rs @@ -78,7 +78,7 @@ pub(crate) struct SpaceRenderer { /// Bind group containing our block texture and light texture, #[allow(clippy::type_complexity)] - space_bind_group: Memo<[wgpu::Id; 4], wgpu::BindGroup>, + space_bind_group: Memo<[crate::Id; 4], wgpu::BindGroup>, /// Mesh generator and updater. ///