wgpu_core/
id.rs

1use crate::{Epoch, Index};
2use core::{
3    cmp::Ordering,
4    fmt::{self, Debug},
5    hash::Hash,
6    marker::PhantomData,
7    num::NonZeroU64,
8};
9use wgt::WasmNotSendSync;
10
11const _: () = {
12    if size_of::<Index>() != 4 {
13        panic!()
14    }
15};
16const _: () = {
17    if size_of::<Epoch>() != 4 {
18        panic!()
19    }
20};
21const _: () = {
22    if size_of::<RawId>() != 8 {
23        panic!()
24    }
25};
26
27/// The raw underlying representation of an identifier.
28#[repr(transparent)]
29#[cfg_attr(
30    any(feature = "serde", feature = "trace"),
31    derive(serde::Serialize),
32    serde(into = "SerialId")
33)]
34#[cfg_attr(
35    any(feature = "serde", feature = "replay"),
36    derive(serde::Deserialize),
37    serde(from = "SerialId")
38)]
39#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
40pub struct RawId(NonZeroU64);
41
42impl RawId {
43    /// Zip together an identifier and return its raw underlying representation.
44    pub fn zip(index: Index, epoch: Epoch) -> RawId {
45        let v = (index as u64) | ((epoch as u64) << 32);
46        Self(NonZeroU64::new(v).unwrap())
47    }
48
49    /// Unzip a raw identifier into its components.
50    pub fn unzip(self) -> (Index, Epoch) {
51        (self.0.get() as Index, (self.0.get() >> 32) as Epoch)
52    }
53}
54
55/// An identifier for a wgpu object.
56///
57/// An `Id<T>` value identifies a value stored in a [`Global`]'s [`Hub`].
58///
59/// ## Note on `Id` typing
60///
61/// You might assume that an `Id<T>` can only be used to retrieve a resource of
62/// type `T`, but that is not quite the case. The id types in `wgpu-core`'s
63/// public API ([`TextureId`], for example) can refer to resources belonging to
64/// any backend, but the corresponding resource types ([`Texture<A>`], for
65/// example) are always parameterized by a specific backend `A`.
66///
67/// So the `T` in `Id<T>` is usually a resource type like `Texture<Noop>`,
68/// where [`Noop`] is the `wgpu_hal` dummy back end. These empty types are
69/// never actually used, beyond just making sure you access each `Storage` with
70/// the right kind of identifier. The members of [`Hub<A>`] pair up each
71/// `X<Noop>` type with the resource type `X<A>`, for some specific backend
72/// `A`.
73///
74/// [`Global`]: crate::global::Global
75/// [`Hub`]: crate::hub::Hub
76/// [`Hub<A>`]: crate::hub::Hub
77/// [`Texture<A>`]: crate::resource::Texture
78/// [`Registry`]: crate::hub::Registry
79/// [`Noop`]: hal::api::Noop
80#[repr(transparent)]
81#[cfg_attr(any(feature = "serde", feature = "trace"), derive(serde::Serialize))]
82#[cfg_attr(any(feature = "serde", feature = "replay"), derive(serde::Deserialize))]
83#[cfg_attr(
84    any(feature = "serde", feature = "trace", feature = "replay"),
85    serde(transparent)
86)]
87pub struct Id<T: Marker>(RawId, PhantomData<T>);
88
89// This type represents Id in a more readable (and editable) way.
90#[allow(dead_code)]
91#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
92enum SerialId {
93    // The only variant forces RON to not ignore "Id"
94    Id(Index, Epoch),
95}
96
97impl From<RawId> for SerialId {
98    fn from(id: RawId) -> Self {
99        let (index, epoch) = id.unzip();
100        Self::Id(index, epoch)
101    }
102}
103
104impl From<SerialId> for RawId {
105    fn from(id: SerialId) -> Self {
106        match id {
107            SerialId::Id(index, epoch) => RawId::zip(index, epoch),
108        }
109    }
110}
111
112impl<T> Id<T>
113where
114    T: Marker,
115{
116    /// # Safety
117    ///
118    /// The raw id must be valid for the type.
119    pub unsafe fn from_raw(raw: RawId) -> Self {
120        Self(raw, PhantomData)
121    }
122
123    /// Coerce the identifiers into its raw underlying representation.
124    pub fn into_raw(self) -> RawId {
125        self.0
126    }
127
128    #[inline]
129    pub fn zip(index: Index, epoch: Epoch) -> Self {
130        Id(RawId::zip(index, epoch), PhantomData)
131    }
132
133    #[inline]
134    pub fn unzip(self) -> (Index, Epoch) {
135        self.0.unzip()
136    }
137}
138
139impl<T> Copy for Id<T> where T: Marker {}
140
141impl<T> Clone for Id<T>
142where
143    T: Marker,
144{
145    #[inline]
146    fn clone(&self) -> Self {
147        *self
148    }
149}
150
151impl<T> Debug for Id<T>
152where
153    T: Marker,
154{
155    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
156        let (index, epoch) = self.unzip();
157        write!(formatter, "Id({index},{epoch})")?;
158        Ok(())
159    }
160}
161
162impl<T> Hash for Id<T>
163where
164    T: Marker,
165{
166    #[inline]
167    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
168        self.0.hash(state);
169    }
170}
171
172impl<T> PartialEq for Id<T>
173where
174    T: Marker,
175{
176    #[inline]
177    fn eq(&self, other: &Self) -> bool {
178        self.0 == other.0
179    }
180}
181
182impl<T> Eq for Id<T> where T: Marker {}
183
184impl<T> PartialOrd for Id<T>
185where
186    T: Marker,
187{
188    #[inline]
189    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
190        Some(self.cmp(other))
191    }
192}
193
194impl<T> Ord for Id<T>
195where
196    T: Marker,
197{
198    #[inline]
199    fn cmp(&self, other: &Self) -> Ordering {
200        self.0.cmp(&other.0)
201    }
202}
203
204/// Marker trait used to determine which types uniquely identify a resource.
205///
206/// For example, `Device<A>` will have the same type of identifier as
207/// `Device<B>` because `Device<T>` for any `T` defines the same maker type.
208pub trait Marker: 'static + WasmNotSendSync {}
209
210// This allows `()` to be used as a marker type for tests.
211//
212// We don't want these in production code, since they essentially remove type
213// safety, like how identifiers across different types can be compared.
214#[cfg(test)]
215impl Marker for () {}
216
217/// Define identifiers for each resource.
218macro_rules! ids {
219    ($(
220        $(#[$($meta:meta)*])*
221        pub type $name:ident $marker:ident;
222    )*) => {
223        /// Marker types for each resource.
224        pub mod markers {
225            $(
226                #[derive(Debug)]
227                pub enum $marker {}
228                impl super::Marker for $marker {}
229            )*
230        }
231
232        $(
233            $(#[$($meta)*])*
234            pub type $name = Id<self::markers::$marker>;
235        )*
236    }
237}
238
239ids! {
240    pub type AdapterId Adapter;
241    pub type SurfaceId Surface;
242    pub type DeviceId Device;
243    pub type QueueId Queue;
244    pub type BufferId Buffer;
245    pub type StagingBufferId StagingBuffer;
246    pub type TextureViewId TextureView;
247    pub type TextureId Texture;
248    pub type SamplerId Sampler;
249    pub type BindGroupLayoutId BindGroupLayout;
250    pub type PipelineLayoutId PipelineLayout;
251    pub type BindGroupId BindGroup;
252    pub type ShaderModuleId ShaderModule;
253    pub type RenderPipelineId RenderPipeline;
254    pub type ComputePipelineId ComputePipeline;
255    pub type PipelineCacheId PipelineCache;
256    pub type CommandEncoderId CommandEncoder;
257    pub type CommandBufferId CommandBuffer;
258    pub type RenderPassEncoderId RenderPassEncoder;
259    pub type ComputePassEncoderId ComputePassEncoder;
260    pub type RenderBundleEncoderId RenderBundleEncoder;
261    pub type RenderBundleId RenderBundle;
262    pub type QuerySetId QuerySet;
263    pub type BlasId Blas;
264    pub type TlasId Tlas;
265}
266
267// The CommandBuffer type serves both as encoder and
268// buffer, which is why the 2 functions below exist.
269
270impl CommandEncoderId {
271    pub fn into_command_buffer_id(self) -> CommandBufferId {
272        Id(self.0, PhantomData)
273    }
274}
275
276impl CommandBufferId {
277    pub fn into_command_encoder_id(self) -> CommandEncoderId {
278        Id(self.0, PhantomData)
279    }
280}
281
282#[test]
283fn test_id() {
284    let indexes = [0, Index::MAX / 2 - 1, Index::MAX / 2 + 1, Index::MAX];
285    let epochs = [1, Epoch::MAX / 2 - 1, Epoch::MAX / 2 + 1, Epoch::MAX];
286    for &i in &indexes {
287        for &e in &epochs {
288            let id = Id::<()>::zip(i, e);
289            let (index, epoch) = id.unzip();
290            assert_eq!(index, i);
291            assert_eq!(epoch, e);
292        }
293    }
294}