summaryrefslogtreecommitdiffstats
path: root/third_party/rust/wgpu-hal/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/wgpu-hal/src/lib.rs')
-rw-r--r--third_party/rust/wgpu-hal/src/lib.rs1316
1 files changed, 1316 insertions, 0 deletions
diff --git a/third_party/rust/wgpu-hal/src/lib.rs b/third_party/rust/wgpu-hal/src/lib.rs
new file mode 100644
index 0000000000..1758149380
--- /dev/null
+++ b/third_party/rust/wgpu-hal/src/lib.rs
@@ -0,0 +1,1316 @@
+/*! This library describes the internal unsafe graphics abstraction API.
+ * It follows WebGPU for the most part, re-using wgpu-types,
+ * with the following deviations:
+ * - Fully unsafe: zero overhead, zero validation.
+ * - Compile-time backend selection via traits.
+ * - Objects are passed by references and returned by value. No IDs.
+ * - Mapping is persistent, with explicit synchronization.
+ * - Resource transitions are explicit.
+ * - All layouts are explicit. Binding model has compatibility.
+ *
+ * General design direction is to follow the majority by the following weights:
+ * - wgpu-core: 1.5
+ * - primary backends (Vulkan/Metal/DX12): 1.0 each
+ * - secondary backends (DX11/GLES): 0.5 each
+ */
+
+#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
+#![allow(
+ // for `if_then_panic` until it reaches stable
+ unknown_lints,
+ // We use loops for getting early-out of scope without closures.
+ clippy::never_loop,
+ // We don't use syntax sugar where it's not necessary.
+ clippy::match_like_matches_macro,
+ // Redundant matching is more explicit.
+ clippy::redundant_pattern_matching,
+ // Explicit lifetimes are often easier to reason about.
+ clippy::needless_lifetimes,
+ // No need for defaults in the internal types.
+ clippy::new_without_default,
+ // Matches are good and extendable, no need to make an exception here.
+ clippy::single_match,
+ // Push commands are more regular than macros.
+ clippy::vec_init_then_push,
+ // "if panic" is a good uniform construct.
+ clippy::if_then_panic,
+ // We unsafe impl `Send` for a reason.
+ clippy::non_send_fields_in_send_ty,
+ // TODO!
+ clippy::missing_safety_doc,
+ // Clashes with clippy::pattern_type_mismatch
+ clippy::needless_borrowed_reference,
+)]
+#![warn(
+ trivial_casts,
+ trivial_numeric_casts,
+ unsafe_op_in_unsafe_fn,
+ unused_extern_crates,
+ unused_qualifications,
+ // We don't match on a reference, unless required.
+ clippy::pattern_type_mismatch,
+)]
+
+/// DirectX11 API internals.
+#[cfg(all(feature = "dx11", windows))]
+pub mod dx11;
+/// DirectX12 API internals.
+#[cfg(all(feature = "dx12", windows))]
+pub mod dx12;
+/// A dummy API implementation.
+pub mod empty;
+/// GLES API internals.
+#[cfg(all(feature = "gles"))]
+pub mod gles;
+/// Metal API internals.
+#[cfg(all(feature = "metal", any(target_os = "macos", target_os = "ios")))]
+pub mod metal;
+/// Vulkan API internals.
+#[cfg(all(feature = "vulkan", not(target_arch = "wasm32")))]
+pub mod vulkan;
+
+pub mod auxil;
+pub mod api {
+ #[cfg(all(feature = "dx11", windows))]
+ pub use super::dx11::Api as Dx11;
+ #[cfg(all(feature = "dx12", windows))]
+ pub use super::dx12::Api as Dx12;
+ pub use super::empty::Api as Empty;
+ #[cfg(feature = "gles")]
+ pub use super::gles::Api as Gles;
+ #[cfg(all(feature = "metal", any(target_os = "macos", target_os = "ios")))]
+ pub use super::metal::Api as Metal;
+ #[cfg(all(feature = "vulkan", not(target_arch = "wasm32")))]
+ pub use super::vulkan::Api as Vulkan;
+}
+
+use std::{
+ borrow::{Borrow, Cow},
+ fmt,
+ num::NonZeroU32,
+ ops::{Range, RangeInclusive},
+ ptr::NonNull,
+ sync::atomic::AtomicBool,
+};
+
+use bitflags::bitflags;
+use thiserror::Error;
+
+pub const MAX_ANISOTROPY: u8 = 16;
+pub const MAX_BIND_GROUPS: usize = 8;
+pub const MAX_VERTEX_BUFFERS: usize = 16;
+pub const MAX_COLOR_ATTACHMENTS: usize = 8;
+pub const MAX_MIP_LEVELS: u32 = 16;
+/// Size of a single occlusion/timestamp query, when copied into a buffer, in bytes.
+pub const QUERY_SIZE: wgt::BufferAddress = 8;
+
+pub type Label<'a> = Option<&'a str>;
+pub type MemoryRange = Range<wgt::BufferAddress>;
+pub type FenceValue = u64;
+
+/// Drop guard to signal wgpu-hal is no longer using an externally created object.
+pub type DropGuard = Box<dyn std::any::Any + Send + Sync>;
+
+#[derive(Clone, Debug, PartialEq, Eq, Error)]
+pub enum DeviceError {
+ #[error("Out of memory")]
+ OutOfMemory,
+ #[error("Device is lost")]
+ Lost,
+}
+
+#[derive(Clone, Debug, Eq, PartialEq, Error)]
+pub enum ShaderError {
+ #[error("Compilation failed: {0:?}")]
+ Compilation(String),
+ #[error(transparent)]
+ Device(#[from] DeviceError),
+}
+
+#[derive(Clone, Debug, Eq, PartialEq, Error)]
+pub enum PipelineError {
+ #[error("Linkage failed for stage {0:?}: {1}")]
+ Linkage(wgt::ShaderStages, String),
+ #[error("Entry point for stage {0:?} is invalid")]
+ EntryPoint(naga::ShaderStage),
+ #[error(transparent)]
+ Device(#[from] DeviceError),
+}
+
+#[derive(Clone, Debug, Eq, PartialEq, Error)]
+pub enum SurfaceError {
+ #[error("Surface is lost")]
+ Lost,
+ #[error("Surface is outdated, needs to be re-created")]
+ Outdated,
+ #[error(transparent)]
+ Device(#[from] DeviceError),
+ #[error("Other reason: {0}")]
+ Other(&'static str),
+}
+
+#[derive(Clone, Debug, Eq, PartialEq, Error)]
+#[error("Not supported")]
+pub struct InstanceError;
+
+pub trait Api: Clone + Sized {
+ type Instance: Instance<Self>;
+ type Surface: Surface<Self>;
+ type Adapter: Adapter<Self>;
+ type Device: Device<Self>;
+
+ type Queue: Queue<Self>;
+ type CommandEncoder: CommandEncoder<Self>;
+ type CommandBuffer: Send + Sync + fmt::Debug;
+
+ type Buffer: fmt::Debug + Send + Sync + 'static;
+ type Texture: fmt::Debug + Send + Sync + 'static;
+ type SurfaceTexture: fmt::Debug + Send + Sync + Borrow<Self::Texture>;
+ type TextureView: fmt::Debug + Send + Sync;
+ type Sampler: fmt::Debug + Send + Sync;
+ type QuerySet: fmt::Debug + Send + Sync;
+ type Fence: fmt::Debug + Send + Sync;
+
+ type BindGroupLayout: Send + Sync;
+ type BindGroup: fmt::Debug + Send + Sync;
+ type PipelineLayout: Send + Sync;
+ type ShaderModule: fmt::Debug + Send + Sync;
+ type RenderPipeline: Send + Sync;
+ type ComputePipeline: Send + Sync;
+}
+
+pub trait Instance<A: Api>: Sized + Send + Sync {
+ unsafe fn init(desc: &InstanceDescriptor) -> Result<Self, InstanceError>;
+ unsafe fn create_surface(
+ &self,
+ display_handle: raw_window_handle::RawDisplayHandle,
+ window_handle: raw_window_handle::RawWindowHandle,
+ ) -> Result<A::Surface, InstanceError>;
+ unsafe fn destroy_surface(&self, surface: A::Surface);
+ unsafe fn enumerate_adapters(&self) -> Vec<ExposedAdapter<A>>;
+}
+
+pub trait Surface<A: Api>: Send + Sync {
+ unsafe fn configure(
+ &mut self,
+ device: &A::Device,
+ config: &SurfaceConfiguration,
+ ) -> Result<(), SurfaceError>;
+
+ unsafe fn unconfigure(&mut self, device: &A::Device);
+
+ /// Returns the next texture to be presented by the swapchain for drawing
+ ///
+ /// A `timeout` of `None` means to wait indefinitely, with no timeout.
+ ///
+ /// # Portability
+ ///
+ /// Some backends can't support a timeout when acquiring a texture and
+ /// the timeout will be ignored.
+ ///
+ /// Returns `None` on timing out.
+ unsafe fn acquire_texture(
+ &mut self,
+ timeout: Option<std::time::Duration>,
+ ) -> Result<Option<AcquiredSurfaceTexture<A>>, SurfaceError>;
+ unsafe fn discard_texture(&mut self, texture: A::SurfaceTexture);
+}
+
+pub trait Adapter<A: Api>: Send + Sync {
+ unsafe fn open(
+ &self,
+ features: wgt::Features,
+ limits: &wgt::Limits,
+ ) -> Result<OpenDevice<A>, DeviceError>;
+
+ /// Return the set of supported capabilities for a texture format.
+ unsafe fn texture_format_capabilities(
+ &self,
+ format: wgt::TextureFormat,
+ ) -> TextureFormatCapabilities;
+
+ /// Returns the capabilities of working with a specified surface.
+ ///
+ /// `None` means presentation is not supported for it.
+ unsafe fn surface_capabilities(&self, surface: &A::Surface) -> Option<SurfaceCapabilities>;
+
+ /// Creates a [`PresentationTimestamp`] using the adapter's WSI.
+ ///
+ /// [`PresentationTimestamp`]: wgt::PresentationTimestamp
+ unsafe fn get_presentation_timestamp(&self) -> wgt::PresentationTimestamp;
+}
+
+pub trait Device<A: Api>: Send + Sync {
+ /// Exit connection to this logical device.
+ unsafe fn exit(self, queue: A::Queue);
+ /// Creates a new buffer.
+ ///
+ /// The initial usage is `BufferUses::empty()`.
+ unsafe fn create_buffer(&self, desc: &BufferDescriptor) -> Result<A::Buffer, DeviceError>;
+ unsafe fn destroy_buffer(&self, buffer: A::Buffer);
+ //TODO: clarify if zero-sized mapping is allowed
+ unsafe fn map_buffer(
+ &self,
+ buffer: &A::Buffer,
+ range: MemoryRange,
+ ) -> Result<BufferMapping, DeviceError>;
+ unsafe fn unmap_buffer(&self, buffer: &A::Buffer) -> Result<(), DeviceError>;
+ unsafe fn flush_mapped_ranges<I>(&self, buffer: &A::Buffer, ranges: I)
+ where
+ I: Iterator<Item = MemoryRange>;
+ unsafe fn invalidate_mapped_ranges<I>(&self, buffer: &A::Buffer, ranges: I)
+ where
+ I: Iterator<Item = MemoryRange>;
+
+ /// Creates a new texture.
+ ///
+ /// The initial usage for all subresources is `TextureUses::UNINITIALIZED`.
+ unsafe fn create_texture(&self, desc: &TextureDescriptor) -> Result<A::Texture, DeviceError>;
+ unsafe fn destroy_texture(&self, texture: A::Texture);
+ unsafe fn create_texture_view(
+ &self,
+ texture: &A::Texture,
+ desc: &TextureViewDescriptor,
+ ) -> Result<A::TextureView, DeviceError>;
+ unsafe fn destroy_texture_view(&self, view: A::TextureView);
+ unsafe fn create_sampler(&self, desc: &SamplerDescriptor) -> Result<A::Sampler, DeviceError>;
+ unsafe fn destroy_sampler(&self, sampler: A::Sampler);
+
+ unsafe fn create_command_encoder(
+ &self,
+ desc: &CommandEncoderDescriptor<A>,
+ ) -> Result<A::CommandEncoder, DeviceError>;
+ unsafe fn destroy_command_encoder(&self, pool: A::CommandEncoder);
+
+ /// Creates a bind group layout.
+ unsafe fn create_bind_group_layout(
+ &self,
+ desc: &BindGroupLayoutDescriptor,
+ ) -> Result<A::BindGroupLayout, DeviceError>;
+ unsafe fn destroy_bind_group_layout(&self, bg_layout: A::BindGroupLayout);
+ unsafe fn create_pipeline_layout(
+ &self,
+ desc: &PipelineLayoutDescriptor<A>,
+ ) -> Result<A::PipelineLayout, DeviceError>;
+ unsafe fn destroy_pipeline_layout(&self, pipeline_layout: A::PipelineLayout);
+ unsafe fn create_bind_group(
+ &self,
+ desc: &BindGroupDescriptor<A>,
+ ) -> Result<A::BindGroup, DeviceError>;
+ unsafe fn destroy_bind_group(&self, group: A::BindGroup);
+
+ unsafe fn create_shader_module(
+ &self,
+ desc: &ShaderModuleDescriptor,
+ shader: ShaderInput,
+ ) -> Result<A::ShaderModule, ShaderError>;
+ unsafe fn destroy_shader_module(&self, module: A::ShaderModule);
+ unsafe fn create_render_pipeline(
+ &self,
+ desc: &RenderPipelineDescriptor<A>,
+ ) -> Result<A::RenderPipeline, PipelineError>;
+ unsafe fn destroy_render_pipeline(&self, pipeline: A::RenderPipeline);
+ unsafe fn create_compute_pipeline(
+ &self,
+ desc: &ComputePipelineDescriptor<A>,
+ ) -> Result<A::ComputePipeline, PipelineError>;
+ unsafe fn destroy_compute_pipeline(&self, pipeline: A::ComputePipeline);
+
+ unsafe fn create_query_set(
+ &self,
+ desc: &wgt::QuerySetDescriptor<Label>,
+ ) -> Result<A::QuerySet, DeviceError>;
+ unsafe fn destroy_query_set(&self, set: A::QuerySet);
+ unsafe fn create_fence(&self) -> Result<A::Fence, DeviceError>;
+ unsafe fn destroy_fence(&self, fence: A::Fence);
+ unsafe fn get_fence_value(&self, fence: &A::Fence) -> Result<FenceValue, DeviceError>;
+ /// Calling wait with a lower value than the current fence value will immediately return.
+ unsafe fn wait(
+ &self,
+ fence: &A::Fence,
+ value: FenceValue,
+ timeout_ms: u32,
+ ) -> Result<bool, DeviceError>;
+
+ unsafe fn start_capture(&self) -> bool;
+ unsafe fn stop_capture(&self);
+}
+
+pub trait Queue<A: Api>: Send + Sync {
+ /// Submits the command buffers for execution on GPU.
+ ///
+ /// Valid usage:
+ /// - all of the command buffers were created from command pools
+ /// that are associated with this queue.
+ /// - all of the command buffers had `CommadBuffer::finish()` called.
+ unsafe fn submit(
+ &mut self,
+ command_buffers: &[&A::CommandBuffer],
+ signal_fence: Option<(&mut A::Fence, FenceValue)>,
+ ) -> Result<(), DeviceError>;
+ unsafe fn present(
+ &mut self,
+ surface: &mut A::Surface,
+ texture: A::SurfaceTexture,
+ ) -> Result<(), SurfaceError>;
+ unsafe fn get_timestamp_period(&self) -> f32;
+}
+
+/// Encoder for commands in command buffers.
+/// Serves as a parent for all the encoded command buffers.
+/// Works in bursts of action: one or more command buffers are recorded,
+/// then submitted to a queue, and then it needs to be `reset_all()`.
+pub trait CommandEncoder<A: Api>: Send + Sync + fmt::Debug {
+ /// Begin encoding a new command buffer.
+ unsafe fn begin_encoding(&mut self, label: Label) -> Result<(), DeviceError>;
+ /// Discard currently recorded list, if any.
+ unsafe fn discard_encoding(&mut self);
+ unsafe fn end_encoding(&mut self) -> Result<A::CommandBuffer, DeviceError>;
+ /// Reclaims all resources that are allocated for this encoder.
+ /// Must get all of the produced command buffers back,
+ /// and they must not be used by GPU at this moment.
+ unsafe fn reset_all<I>(&mut self, command_buffers: I)
+ where
+ I: Iterator<Item = A::CommandBuffer>;
+
+ unsafe fn transition_buffers<'a, T>(&mut self, barriers: T)
+ where
+ T: Iterator<Item = BufferBarrier<'a, A>>;
+
+ unsafe fn transition_textures<'a, T>(&mut self, barriers: T)
+ where
+ T: Iterator<Item = TextureBarrier<'a, A>>;
+
+ // copy operations
+
+ unsafe fn clear_buffer(&mut self, buffer: &A::Buffer, range: MemoryRange);
+
+ unsafe fn copy_buffer_to_buffer<T>(&mut self, src: &A::Buffer, dst: &A::Buffer, regions: T)
+ where
+ T: Iterator<Item = BufferCopy>;
+
+ /// Copy from an external image to an internal texture.
+ /// Works with a single array layer.
+ /// Note: `dst` current usage has to be `TextureUses::COPY_DST`.
+ /// Note: the copy extent is in physical size (rounded to the block size)
+ #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
+ unsafe fn copy_external_image_to_texture<T>(
+ &mut self,
+ src: &wgt::ImageCopyExternalImage,
+ dst: &A::Texture,
+ dst_premultiplication: bool,
+ regions: T,
+ ) where
+ T: Iterator<Item = TextureCopy>;
+
+ /// Copy from one texture to another.
+ /// Works with a single array layer.
+ /// Note: `dst` current usage has to be `TextureUses::COPY_DST`.
+ /// Note: the copy extent is in physical size (rounded to the block size)
+ unsafe fn copy_texture_to_texture<T>(
+ &mut self,
+ src: &A::Texture,
+ src_usage: TextureUses,
+ dst: &A::Texture,
+ regions: T,
+ ) where
+ T: Iterator<Item = TextureCopy>;
+
+ /// Copy from buffer to texture.
+ /// Works with a single array layer.
+ /// Note: `dst` current usage has to be `TextureUses::COPY_DST`.
+ /// Note: the copy extent is in physical size (rounded to the block size)
+ unsafe fn copy_buffer_to_texture<T>(&mut self, src: &A::Buffer, dst: &A::Texture, regions: T)
+ where
+ T: Iterator<Item = BufferTextureCopy>;
+
+ /// Copy from texture to buffer.
+ /// Works with a single array layer.
+ /// Note: the copy extent is in physical size (rounded to the block size)
+ unsafe fn copy_texture_to_buffer<T>(
+ &mut self,
+ src: &A::Texture,
+ src_usage: TextureUses,
+ dst: &A::Buffer,
+ regions: T,
+ ) where
+ T: Iterator<Item = BufferTextureCopy>;
+
+ // pass common
+
+ /// Sets the bind group at `index` to `group`, assuming the layout
+ /// of all the preceeding groups to be taken from `layout`.
+ unsafe fn set_bind_group(
+ &mut self,
+ layout: &A::PipelineLayout,
+ index: u32,
+ group: &A::BindGroup,
+ dynamic_offsets: &[wgt::DynamicOffset],
+ );
+
+ unsafe fn set_push_constants(
+ &mut self,
+ layout: &A::PipelineLayout,
+ stages: wgt::ShaderStages,
+ offset: u32,
+ data: &[u32],
+ );
+
+ unsafe fn insert_debug_marker(&mut self, label: &str);
+ unsafe fn begin_debug_marker(&mut self, group_label: &str);
+ unsafe fn end_debug_marker(&mut self);
+
+ // queries
+
+ unsafe fn begin_query(&mut self, set: &A::QuerySet, index: u32);
+ unsafe fn end_query(&mut self, set: &A::QuerySet, index: u32);
+ unsafe fn write_timestamp(&mut self, set: &A::QuerySet, index: u32);
+ unsafe fn reset_queries(&mut self, set: &A::QuerySet, range: Range<u32>);
+ unsafe fn copy_query_results(
+ &mut self,
+ set: &A::QuerySet,
+ range: Range<u32>,
+ buffer: &A::Buffer,
+ offset: wgt::BufferAddress,
+ stride: wgt::BufferSize,
+ );
+
+ // render passes
+
+ // Begins a render pass, clears all active bindings.
+ unsafe fn begin_render_pass(&mut self, desc: &RenderPassDescriptor<A>);
+ unsafe fn end_render_pass(&mut self);
+
+ unsafe fn set_render_pipeline(&mut self, pipeline: &A::RenderPipeline);
+
+ unsafe fn set_index_buffer<'a>(
+ &mut self,
+ binding: BufferBinding<'a, A>,
+ format: wgt::IndexFormat,
+ );
+ unsafe fn set_vertex_buffer<'a>(&mut self, index: u32, binding: BufferBinding<'a, A>);
+ unsafe fn set_viewport(&mut self, rect: &Rect<f32>, depth_range: Range<f32>);
+ unsafe fn set_scissor_rect(&mut self, rect: &Rect<u32>);
+ unsafe fn set_stencil_reference(&mut self, value: u32);
+ unsafe fn set_blend_constants(&mut self, color: &[f32; 4]);
+
+ unsafe fn draw(
+ &mut self,
+ start_vertex: u32,
+ vertex_count: u32,
+ start_instance: u32,
+ instance_count: u32,
+ );
+ unsafe fn draw_indexed(
+ &mut self,
+ start_index: u32,
+ index_count: u32,
+ base_vertex: i32,
+ start_instance: u32,
+ instance_count: u32,
+ );
+ unsafe fn draw_indirect(
+ &mut self,
+ buffer: &A::Buffer,
+ offset: wgt::BufferAddress,
+ draw_count: u32,
+ );
+ unsafe fn draw_indexed_indirect(
+ &mut self,
+ buffer: &A::Buffer,
+ offset: wgt::BufferAddress,
+ draw_count: u32,
+ );
+ unsafe fn draw_indirect_count(
+ &mut self,
+ buffer: &A::Buffer,
+ offset: wgt::BufferAddress,
+ count_buffer: &A::Buffer,
+ count_offset: wgt::BufferAddress,
+ max_count: u32,
+ );
+ unsafe fn draw_indexed_indirect_count(
+ &mut self,
+ buffer: &A::Buffer,
+ offset: wgt::BufferAddress,
+ count_buffer: &A::Buffer,
+ count_offset: wgt::BufferAddress,
+ max_count: u32,
+ );
+
+ // compute passes
+
+ // Begins a compute pass, clears all active bindings.
+ unsafe fn begin_compute_pass(&mut self, desc: &ComputePassDescriptor);
+ unsafe fn end_compute_pass(&mut self);
+
+ unsafe fn set_compute_pipeline(&mut self, pipeline: &A::ComputePipeline);
+
+ unsafe fn dispatch(&mut self, count: [u32; 3]);
+ unsafe fn dispatch_indirect(&mut self, buffer: &A::Buffer, offset: wgt::BufferAddress);
+}
+
+bitflags!(
+ /// Instance initialization flags.
+ #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+ pub struct InstanceFlags: u32 {
+ /// Generate debug information in shaders and objects.
+ const DEBUG = 1 << 0;
+ /// Enable validation, if possible.
+ const VALIDATION = 1 << 1;
+ }
+);
+
+bitflags!(
+ /// Pipeline layout creation flags.
+ #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+ pub struct PipelineLayoutFlags: u32 {
+ /// Include support for base vertex/instance drawing.
+ const BASE_VERTEX_INSTANCE = 1 << 0;
+ /// Include support for num work groups builtin.
+ const NUM_WORK_GROUPS = 1 << 1;
+ }
+);
+
+bitflags!(
+ /// Pipeline layout creation flags.
+ #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+ pub struct BindGroupLayoutFlags: u32 {
+ /// Allows for bind group binding arrays to be shorter than the array in the BGL.
+ const PARTIALLY_BOUND = 1 << 0;
+ }
+);
+
+bitflags!(
+ /// Texture format capability flags.
+ #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+ pub struct TextureFormatCapabilities: u32 {
+ /// Format can be sampled.
+ const SAMPLED = 1 << 0;
+ /// Format can be sampled with a linear sampler.
+ const SAMPLED_LINEAR = 1 << 1;
+ /// Format can be sampled with a min/max reduction sampler.
+ const SAMPLED_MINMAX = 1 << 2;
+
+ /// Format can be used as storage with write-only access.
+ const STORAGE = 1 << 3;
+ /// Format can be used as storage with read and read/write access.
+ const STORAGE_READ_WRITE = 1 << 4;
+ /// Format can be used as storage with atomics.
+ const STORAGE_ATOMIC = 1 << 5;
+
+ /// Format can be used as color and input attachment.
+ const COLOR_ATTACHMENT = 1 << 6;
+ /// Format can be used as color (with blending) and input attachment.
+ const COLOR_ATTACHMENT_BLEND = 1 << 7;
+ /// Format can be used as depth-stencil and input attachment.
+ const DEPTH_STENCIL_ATTACHMENT = 1 << 8;
+
+ /// Format can be multisampled by x2.
+ const MULTISAMPLE_X2 = 1 << 9;
+ /// Format can be multisampled by x4.
+ const MULTISAMPLE_X4 = 1 << 10;
+ /// Format can be multisampled by x8.
+ const MULTISAMPLE_X8 = 1 << 11;
+ /// Format can be multisampled by x16.
+ const MULTISAMPLE_X16 = 1 << 12;
+
+ /// Format can be used for render pass resolve targets.
+ const MULTISAMPLE_RESOLVE = 1 << 13;
+
+ /// Format can be copied from.
+ const COPY_SRC = 1 << 14;
+ /// Format can be copied to.
+ const COPY_DST = 1 << 15;
+ }
+);
+
+bitflags!(
+ /// Texture format capability flags.
+ #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+ pub struct FormatAspects: u8 {
+ const COLOR = 1 << 0;
+ const DEPTH = 1 << 1;
+ const STENCIL = 1 << 2;
+ }
+);
+
+impl FormatAspects {
+ pub fn new(format: wgt::TextureFormat, aspect: wgt::TextureAspect) -> Self {
+ let aspect_mask = match aspect {
+ wgt::TextureAspect::All => Self::all(),
+ wgt::TextureAspect::DepthOnly => Self::DEPTH,
+ wgt::TextureAspect::StencilOnly => Self::STENCIL,
+ };
+ Self::from(format) & aspect_mask
+ }
+
+ /// Returns `true` if only one flag is set
+ pub fn is_one(&self) -> bool {
+ self.bits().count_ones() == 1
+ }
+
+ pub fn map(&self) -> wgt::TextureAspect {
+ match *self {
+ Self::COLOR => wgt::TextureAspect::All,
+ Self::DEPTH => wgt::TextureAspect::DepthOnly,
+ Self::STENCIL => wgt::TextureAspect::StencilOnly,
+ _ => unreachable!(),
+ }
+ }
+}
+
+impl From<wgt::TextureFormat> for FormatAspects {
+ fn from(format: wgt::TextureFormat) -> Self {
+ match format {
+ wgt::TextureFormat::Stencil8 => Self::STENCIL,
+ wgt::TextureFormat::Depth16Unorm
+ | wgt::TextureFormat::Depth32Float
+ | wgt::TextureFormat::Depth24Plus => Self::DEPTH,
+ wgt::TextureFormat::Depth32FloatStencil8 | wgt::TextureFormat::Depth24PlusStencil8 => {
+ Self::DEPTH | Self::STENCIL
+ }
+ _ => Self::COLOR,
+ }
+ }
+}
+
+bitflags!(
+ #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+ pub struct MemoryFlags: u32 {
+ const TRANSIENT = 1 << 0;
+ const PREFER_COHERENT = 1 << 1;
+ }
+);
+
+//TODO: it's not intuitive for the backends to consider `LOAD` being optional.
+
+bitflags!(
+ #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+ pub struct AttachmentOps: u8 {
+ const LOAD = 1 << 0;
+ const STORE = 1 << 1;
+ }
+);
+
+bitflags::bitflags! {
+ /// Similar to `wgt::BufferUsages` but for internal use.
+ #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+ pub struct BufferUses: u16 {
+ /// The argument to a read-only mapping.
+ const MAP_READ = 1 << 0;
+ /// The argument to a write-only mapping.
+ const MAP_WRITE = 1 << 1;
+ /// The source of a hardware copy.
+ const COPY_SRC = 1 << 2;
+ /// The destination of a hardware copy.
+ const COPY_DST = 1 << 3;
+ /// The index buffer used for drawing.
+ const INDEX = 1 << 4;
+ /// A vertex buffer used for drawing.
+ const VERTEX = 1 << 5;
+ /// A uniform buffer bound in a bind group.
+ const UNIFORM = 1 << 6;
+ /// A read-only storage buffer used in a bind group.
+ const STORAGE_READ = 1 << 7;
+ /// A read-write or write-only buffer used in a bind group.
+ const STORAGE_READ_WRITE = 1 << 8;
+ /// The indirect or count buffer in a indirect draw or dispatch.
+ const INDIRECT = 1 << 9;
+ /// The combination of states that a buffer may be in _at the same time_.
+ const INCLUSIVE = Self::MAP_READ.bits() | Self::COPY_SRC.bits() |
+ Self::INDEX.bits() | Self::VERTEX.bits() | Self::UNIFORM.bits() |
+ Self::STORAGE_READ.bits() | Self::INDIRECT.bits();
+ /// The combination of states that a buffer must exclusively be in.
+ const EXCLUSIVE = Self::MAP_WRITE.bits() | Self::COPY_DST.bits() | Self::STORAGE_READ_WRITE.bits();
+ /// The combination of all usages that the are guaranteed to be be ordered by the hardware.
+ /// If a usage is ordered, then if the buffer state doesn't change between draw calls, there
+ /// are no barriers needed for synchronization.
+ const ORDERED = Self::INCLUSIVE.bits() | Self::MAP_WRITE.bits();
+ }
+}
+
+bitflags::bitflags! {
+ /// Similar to `wgt::TextureUsages` but for internal use.
+ #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+ pub struct TextureUses: u16 {
+ /// The texture is in unknown state.
+ const UNINITIALIZED = 1 << 0;
+ /// Ready to present image to the surface.
+ const PRESENT = 1 << 1;
+ /// The source of a hardware copy.
+ const COPY_SRC = 1 << 2;
+ /// The destination of a hardware copy.
+ const COPY_DST = 1 << 3;
+ /// Read-only sampled or fetched resource.
+ const RESOURCE = 1 << 4;
+ /// The color target of a renderpass.
+ const COLOR_TARGET = 1 << 5;
+ /// Read-only depth stencil usage.
+ const DEPTH_STENCIL_READ = 1 << 6;
+ /// Read-write depth stencil usage
+ const DEPTH_STENCIL_WRITE = 1 << 7;
+ /// Read-only storage buffer usage. Corresponds to a UAV in d3d, so is exclusive, despite being read only.
+ const STORAGE_READ = 1 << 8;
+ /// Read-write or write-only storage buffer usage.
+ const STORAGE_READ_WRITE = 1 << 9;
+ /// The combination of states that a texture may be in _at the same time_.
+ const INCLUSIVE = Self::COPY_SRC.bits() | Self::RESOURCE.bits() | Self::DEPTH_STENCIL_READ.bits();
+ /// The combination of states that a texture must exclusively be in.
+ const EXCLUSIVE = Self::COPY_DST.bits() | Self::COLOR_TARGET.bits() | Self::DEPTH_STENCIL_WRITE.bits() | Self::STORAGE_READ.bits() | Self::STORAGE_READ_WRITE.bits() | Self::PRESENT.bits();
+ /// The combination of all usages that the are guaranteed to be be ordered by the hardware.
+ /// If a usage is ordered, then if the texture state doesn't change between draw calls, there
+ /// are no barriers needed for synchronization.
+ const ORDERED = Self::INCLUSIVE.bits() | Self::COLOR_TARGET.bits() | Self::DEPTH_STENCIL_WRITE.bits() | Self::STORAGE_READ.bits();
+
+ /// Flag used by the wgpu-core texture tracker to say a texture is in different states for every sub-resource
+ const COMPLEX = 1 << 10;
+ /// Flag used by the wgpu-core texture tracker to say that the tracker does not know the state of the sub-resource.
+ /// This is different from UNINITIALIZED as that says the tracker does know, but the texture has not been initialized.
+ const UNKNOWN = 1 << 11;
+ }
+}
+
+#[derive(Clone, Debug)]
+pub struct InstanceDescriptor<'a> {
+ pub name: &'a str,
+ pub flags: InstanceFlags,
+ pub dx12_shader_compiler: wgt::Dx12Compiler,
+}
+
+#[derive(Clone, Debug)]
+pub struct Alignments {
+ /// The alignment of the start of the buffer used as a GPU copy source.
+ pub buffer_copy_offset: wgt::BufferSize,
+ /// The alignment of the row pitch of the texture data stored in a buffer that is
+ /// used in a GPU copy operation.
+ pub buffer_copy_pitch: wgt::BufferSize,
+}
+
+#[derive(Clone, Debug)]
+pub struct Capabilities {
+ pub limits: wgt::Limits,
+ pub alignments: Alignments,
+ pub downlevel: wgt::DownlevelCapabilities,
+}
+
+#[derive(Debug)]
+pub struct ExposedAdapter<A: Api> {
+ pub adapter: A::Adapter,
+ pub info: wgt::AdapterInfo,
+ pub features: wgt::Features,
+ pub capabilities: Capabilities,
+}
+
+/// Describes information about what a `Surface`'s presentation capabilities are.
+/// Fetch this with [Adapter::surface_capabilities].
+#[derive(Debug, Clone)]
+pub struct SurfaceCapabilities {
+ /// List of supported texture formats.
+ ///
+ /// Must be at least one.
+ pub formats: Vec<wgt::TextureFormat>,
+
+ /// Range for the swap chain sizes.
+ ///
+ /// - `swap_chain_sizes.start` must be at least 1.
+ /// - `swap_chain_sizes.end` must be larger or equal to `swap_chain_sizes.start`.
+ pub swap_chain_sizes: RangeInclusive<u32>,
+
+ /// Current extent of the surface, if known.
+ pub current_extent: Option<wgt::Extent3d>,
+
+ /// Range of supported extents.
+ ///
+ /// `current_extent` must be inside this range.
+ pub extents: RangeInclusive<wgt::Extent3d>,
+
+ /// Supported texture usage flags.
+ ///
+ /// Must have at least `TextureUses::COLOR_TARGET`
+ pub usage: TextureUses,
+
+ /// List of supported V-sync modes.
+ ///
+ /// Must be at least one.
+ pub present_modes: Vec<wgt::PresentMode>,
+
+ /// List of supported alpha composition modes.
+ ///
+ /// Must be at least one.
+ pub composite_alpha_modes: Vec<wgt::CompositeAlphaMode>,
+}
+
+#[derive(Debug)]
+pub struct AcquiredSurfaceTexture<A: Api> {
+ pub texture: A::SurfaceTexture,
+ /// The presentation configuration no longer matches
+ /// the surface properties exactly, but can still be used to present
+ /// to the surface successfully.
+ pub suboptimal: bool,
+}
+
+#[derive(Debug)]
+pub struct OpenDevice<A: Api> {
+ pub device: A::Device,
+ pub queue: A::Queue,
+}
+
+#[derive(Clone, Debug)]
+pub struct BufferMapping {
+ pub ptr: NonNull<u8>,
+ pub is_coherent: bool,
+}
+
+#[derive(Clone, Debug)]
+pub struct BufferDescriptor<'a> {
+ pub label: Label<'a>,
+ pub size: wgt::BufferAddress,
+ pub usage: BufferUses,
+ pub memory_flags: MemoryFlags,
+}
+
+#[derive(Clone, Debug)]
+pub struct TextureDescriptor<'a> {
+ pub label: Label<'a>,
+ pub size: wgt::Extent3d,
+ pub mip_level_count: u32,
+ pub sample_count: u32,
+ pub dimension: wgt::TextureDimension,
+ pub format: wgt::TextureFormat,
+ pub usage: TextureUses,
+ pub memory_flags: MemoryFlags,
+ /// Allows views of this texture to have a different format
+ /// than the texture does.
+ pub view_formats: Vec<wgt::TextureFormat>,
+}
+
+impl TextureDescriptor<'_> {
+ pub fn copy_extent(&self) -> CopyExtent {
+ CopyExtent::map_extent_to_copy_size(&self.size, self.dimension)
+ }
+
+ pub fn is_cube_compatible(&self) -> bool {
+ self.dimension == wgt::TextureDimension::D2
+ && self.size.depth_or_array_layers % 6 == 0
+ && self.sample_count == 1
+ && self.size.width == self.size.height
+ }
+
+ pub fn array_layer_count(&self) -> u32 {
+ match self.dimension {
+ wgt::TextureDimension::D1 | wgt::TextureDimension::D3 => 1,
+ wgt::TextureDimension::D2 => self.size.depth_or_array_layers,
+ }
+ }
+}
+
+/// TextureView descriptor.
+///
+/// Valid usage:
+///. - `format` has to be the same as `TextureDescriptor::format`
+///. - `dimension` has to be compatible with `TextureDescriptor::dimension`
+///. - `usage` has to be a subset of `TextureDescriptor::usage`
+///. - `range` has to be a subset of parent texture
+#[derive(Clone, Debug)]
+pub struct TextureViewDescriptor<'a> {
+ pub label: Label<'a>,
+ pub format: wgt::TextureFormat,
+ pub dimension: wgt::TextureViewDimension,
+ pub usage: TextureUses,
+ pub range: wgt::ImageSubresourceRange,
+}
+
+#[derive(Clone, Debug)]
+pub struct SamplerDescriptor<'a> {
+ pub label: Label<'a>,
+ pub address_modes: [wgt::AddressMode; 3],
+ pub mag_filter: wgt::FilterMode,
+ pub min_filter: wgt::FilterMode,
+ pub mipmap_filter: wgt::FilterMode,
+ pub lod_clamp: Range<f32>,
+ pub compare: Option<wgt::CompareFunction>,
+ // Must in the range [1, 16].
+ //
+ // Anisotropic filtering must be supported if this is not 1.
+ pub anisotropy_clamp: u16,
+ pub border_color: Option<wgt::SamplerBorderColor>,
+}
+
+/// BindGroupLayout descriptor.
+///
+/// Valid usage:
+/// - `entries` are sorted by ascending `wgt::BindGroupLayoutEntry::binding`
+#[derive(Clone, Debug)]
+pub struct BindGroupLayoutDescriptor<'a> {
+ pub label: Label<'a>,
+ pub flags: BindGroupLayoutFlags,
+ pub entries: &'a [wgt::BindGroupLayoutEntry],
+}
+
+#[derive(Clone, Debug)]
+pub struct PipelineLayoutDescriptor<'a, A: Api> {
+ pub label: Label<'a>,
+ pub flags: PipelineLayoutFlags,
+ pub bind_group_layouts: &'a [&'a A::BindGroupLayout],
+ pub push_constant_ranges: &'a [wgt::PushConstantRange],
+}
+
+#[derive(Debug)]
+pub struct BufferBinding<'a, A: Api> {
+ /// The buffer being bound.
+ pub buffer: &'a A::Buffer,
+
+ /// The offset at which the bound region starts.
+ ///
+ /// This must be less than the size of the buffer. Some back ends
+ /// cannot tolerate zero-length regions; for example, see
+ /// [VUID-VkDescriptorBufferInfo-offset-00340][340] and
+ /// [VUID-VkDescriptorBufferInfo-range-00341][341], or the
+ /// documentation for GLES's [glBindBufferRange][bbr].
+ ///
+ /// [340]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-VkDescriptorBufferInfo-offset-00340
+ /// [341]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-VkDescriptorBufferInfo-range-00341
+ /// [bbr]: https://registry.khronos.org/OpenGL-Refpages/es3.0/html/glBindBufferRange.xhtml
+ pub offset: wgt::BufferAddress,
+
+ /// The size of the region bound, in bytes.
+ ///
+ /// If `None`, the region extends from `offset` to the end of the
+ /// buffer. Given the restrictions on `offset`, this means that
+ /// the size is always greater than zero.
+ pub size: Option<wgt::BufferSize>,
+}
+
+// Rust gets confused about the impl requirements for `A`
+impl<A: Api> Clone for BufferBinding<'_, A> {
+ fn clone(&self) -> Self {
+ Self {
+ buffer: self.buffer,
+ offset: self.offset,
+ size: self.size,
+ }
+ }
+}
+
+#[derive(Debug)]
+pub struct TextureBinding<'a, A: Api> {
+ pub view: &'a A::TextureView,
+ pub usage: TextureUses,
+}
+
+// Rust gets confused about the impl requirements for `A`
+impl<A: Api> Clone for TextureBinding<'_, A> {
+ fn clone(&self) -> Self {
+ Self {
+ view: self.view,
+ usage: self.usage,
+ }
+ }
+}
+
+#[derive(Clone, Debug)]
+pub struct BindGroupEntry {
+ pub binding: u32,
+ pub resource_index: u32,
+ pub count: u32,
+}
+
+/// BindGroup descriptor.
+///
+/// Valid usage:
+///. - `entries` has to be sorted by ascending `BindGroupEntry::binding`
+///. - `entries` has to have the same set of `BindGroupEntry::binding` as `layout`
+///. - each entry has to be compatible with the `layout`
+///. - each entry's `BindGroupEntry::resource_index` is within range
+/// of the corresponding resource array, selected by the relevant
+/// `BindGroupLayoutEntry`.
+#[derive(Clone, Debug)]
+pub struct BindGroupDescriptor<'a, A: Api> {
+ pub label: Label<'a>,
+ pub layout: &'a A::BindGroupLayout,
+ pub buffers: &'a [BufferBinding<'a, A>],
+ pub samplers: &'a [&'a A::Sampler],
+ pub textures: &'a [TextureBinding<'a, A>],
+ pub entries: &'a [BindGroupEntry],
+}
+
+#[derive(Clone, Debug)]
+pub struct CommandEncoderDescriptor<'a, A: Api> {
+ pub label: Label<'a>,
+ pub queue: &'a A::Queue,
+}
+
+/// Naga shader module.
+pub struct NagaShader {
+ /// Shader module IR.
+ pub module: Cow<'static, naga::Module>,
+ /// Analysis information of the module.
+ pub info: naga::valid::ModuleInfo,
+}
+
+// Custom implementation avoids the need to generate Debug impl code
+// for the whole Naga module and info.
+impl fmt::Debug for NagaShader {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ write!(formatter, "Naga shader")
+ }
+}
+
+/// Shader input.
+#[allow(clippy::large_enum_variant)]
+pub enum ShaderInput<'a> {
+ Naga(NagaShader),
+ SpirV(&'a [u32]),
+}
+
+pub struct ShaderModuleDescriptor<'a> {
+ pub label: Label<'a>,
+ pub runtime_checks: bool,
+}
+
+/// Describes a programmable pipeline stage.
+#[derive(Debug)]
+pub struct ProgrammableStage<'a, A: Api> {
+ /// The compiled shader module for this stage.
+ pub module: &'a A::ShaderModule,
+ /// The name of the entry point in the compiled shader. There must be a function with this name
+ /// in the shader.
+ pub entry_point: &'a str,
+}
+
+// Rust gets confused about the impl requirements for `A`
+impl<A: Api> Clone for ProgrammableStage<'_, A> {
+ fn clone(&self) -> Self {
+ Self {
+ module: self.module,
+ entry_point: self.entry_point,
+ }
+ }
+}
+
+/// Describes a compute pipeline.
+#[derive(Clone, Debug)]
+pub struct ComputePipelineDescriptor<'a, A: Api> {
+ pub label: Label<'a>,
+ /// The layout of bind groups for this pipeline.
+ pub layout: &'a A::PipelineLayout,
+ /// The compiled compute stage and its entry point.
+ pub stage: ProgrammableStage<'a, A>,
+}
+
+/// Describes how the vertex buffer is interpreted.
+#[derive(Clone, Debug)]
+pub struct VertexBufferLayout<'a> {
+ /// The stride, in bytes, between elements of this buffer.
+ pub array_stride: wgt::BufferAddress,
+ /// How often this vertex buffer is "stepped" forward.
+ pub step_mode: wgt::VertexStepMode,
+ /// The list of attributes which comprise a single vertex.
+ pub attributes: &'a [wgt::VertexAttribute],
+}
+
+/// Describes a render (graphics) pipeline.
+#[derive(Clone, Debug)]
+pub struct RenderPipelineDescriptor<'a, A: Api> {
+ pub label: Label<'a>,
+ /// The layout of bind groups for this pipeline.
+ pub layout: &'a A::PipelineLayout,
+ /// The format of any vertex buffers used with this pipeline.
+ pub vertex_buffers: &'a [VertexBufferLayout<'a>],
+ /// The vertex stage for this pipeline.
+ pub vertex_stage: ProgrammableStage<'a, A>,
+ /// The properties of the pipeline at the primitive assembly and rasterization level.
+ pub primitive: wgt::PrimitiveState,
+ /// The effect of draw calls on the depth and stencil aspects of the output target, if any.
+ pub depth_stencil: Option<wgt::DepthStencilState>,
+ /// The multi-sampling properties of the pipeline.
+ pub multisample: wgt::MultisampleState,
+ /// The fragment stage for this pipeline.
+ pub fragment_stage: Option<ProgrammableStage<'a, A>>,
+ /// The effect of draw calls on the color aspect of the output target.
+ pub color_targets: &'a [Option<wgt::ColorTargetState>],
+ /// If the pipeline will be used with a multiview render pass, this indicates how many array
+ /// layers the attachments will have.
+ pub multiview: Option<NonZeroU32>,
+}
+
+#[derive(Debug, Clone)]
+pub struct SurfaceConfiguration {
+ /// Number of textures in the swap chain. Must be in
+ /// `SurfaceCapabilities::swap_chain_size` range.
+ pub swap_chain_size: u32,
+ /// Vertical synchronization mode.
+ pub present_mode: wgt::PresentMode,
+ /// Alpha composition mode.
+ pub composite_alpha_mode: wgt::CompositeAlphaMode,
+ /// Format of the surface textures.
+ pub format: wgt::TextureFormat,
+ /// Requested texture extent. Must be in
+ /// `SurfaceCapabilities::extents` range.
+ pub extent: wgt::Extent3d,
+ /// Allowed usage of surface textures,
+ pub usage: TextureUses,
+ /// Allows views of swapchain texture to have a different format
+ /// than the texture does.
+ pub view_formats: Vec<wgt::TextureFormat>,
+}
+
+#[derive(Debug, Clone)]
+pub struct Rect<T> {
+ pub x: T,
+ pub y: T,
+ pub w: T,
+ pub h: T,
+}
+
+#[derive(Debug, Clone)]
+pub struct BufferBarrier<'a, A: Api> {
+ pub buffer: &'a A::Buffer,
+ pub usage: Range<BufferUses>,
+}
+
+#[derive(Debug, Clone)]
+pub struct TextureBarrier<'a, A: Api> {
+ pub texture: &'a A::Texture,
+ pub range: wgt::ImageSubresourceRange,
+ pub usage: Range<TextureUses>,
+}
+
+#[derive(Clone, Copy, Debug)]
+pub struct BufferCopy {
+ pub src_offset: wgt::BufferAddress,
+ pub dst_offset: wgt::BufferAddress,
+ pub size: wgt::BufferSize,
+}
+
+#[derive(Clone, Debug)]
+pub struct TextureCopyBase {
+ pub mip_level: u32,
+ pub array_layer: u32,
+ /// Origin within a texture.
+ /// Note: for 1D and 2D textures, Z must be 0.
+ pub origin: wgt::Origin3d,
+ pub aspect: FormatAspects,
+}
+
+#[derive(Clone, Copy, Debug)]
+pub struct CopyExtent {
+ pub width: u32,
+ pub height: u32,
+ pub depth: u32,
+}
+
+#[derive(Clone, Debug)]
+pub struct TextureCopy {
+ pub src_base: TextureCopyBase,
+ pub dst_base: TextureCopyBase,
+ pub size: CopyExtent,
+}
+
+#[derive(Clone, Debug)]
+pub struct BufferTextureCopy {
+ pub buffer_layout: wgt::ImageDataLayout,
+ pub texture_base: TextureCopyBase,
+ pub size: CopyExtent,
+}
+
+#[derive(Debug)]
+pub struct Attachment<'a, A: Api> {
+ pub view: &'a A::TextureView,
+ /// Contains either a single mutating usage as a target,
+ /// or a valid combination of read-only usages.
+ pub usage: TextureUses,
+}
+
+// Rust gets confused about the impl requirements for `A`
+impl<A: Api> Clone for Attachment<'_, A> {
+ fn clone(&self) -> Self {
+ Self {
+ view: self.view,
+ usage: self.usage,
+ }
+ }
+}
+
+#[derive(Debug)]
+pub struct ColorAttachment<'a, A: Api> {
+ pub target: Attachment<'a, A>,
+ pub resolve_target: Option<Attachment<'a, A>>,
+ pub ops: AttachmentOps,
+ pub clear_value: wgt::Color,
+}
+
+// Rust gets confused about the impl requirements for `A`
+impl<A: Api> Clone for ColorAttachment<'_, A> {
+ fn clone(&self) -> Self {
+ Self {
+ target: self.target.clone(),
+ resolve_target: self.resolve_target.clone(),
+ ops: self.ops,
+ clear_value: self.clear_value,
+ }
+ }
+}
+
+#[derive(Clone, Debug)]
+pub struct DepthStencilAttachment<'a, A: Api> {
+ pub target: Attachment<'a, A>,
+ pub depth_ops: AttachmentOps,
+ pub stencil_ops: AttachmentOps,
+ pub clear_value: (f32, u32),
+}
+
+#[derive(Clone, Debug)]
+pub struct RenderPassDescriptor<'a, A: Api> {
+ pub label: Label<'a>,
+ pub extent: wgt::Extent3d,
+ pub sample_count: u32,
+ pub color_attachments: &'a [Option<ColorAttachment<'a, A>>],
+ pub depth_stencil_attachment: Option<DepthStencilAttachment<'a, A>>,
+ pub multiview: Option<NonZeroU32>,
+}
+
+#[derive(Clone, Debug)]
+pub struct ComputePassDescriptor<'a> {
+ pub label: Label<'a>,
+}
+
+/// Stores if any API validation error has occurred in this process
+/// since it was last reset.
+///
+/// This is used for internal wgpu testing only and _must not_ be used
+/// as a way to check for errors.
+///
+/// This works as a static because `cargo nextest` runs all of our
+/// tests in separate processes, so each test gets its own canary.
+///
+/// This prevents the issue of one validation error terminating the
+/// entire process.
+pub static VALIDATION_CANARY: ValidationCanary = ValidationCanary {
+ inner: AtomicBool::new(false),
+};
+
+/// Flag for internal testing.
+pub struct ValidationCanary {
+ inner: AtomicBool,
+}
+
+impl ValidationCanary {
+ #[allow(dead_code)] // in some configurations this function is dead
+ fn set(&self) {
+ self.inner.store(true, std::sync::atomic::Ordering::SeqCst);
+ }
+
+ /// Returns true if any API validation error has occurred in this process
+ /// since the last call to this function.
+ pub fn get_and_reset(&self) -> bool {
+ self.inner.swap(false, std::sync::atomic::Ordering::SeqCst)
+ }
+}
+
+#[test]
+fn test_default_limits() {
+ let limits = wgt::Limits::default();
+ assert!(limits.max_bind_groups <= MAX_BIND_GROUPS as u32);
+}