#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
#![allow(
// this happens on the GL backend, where it is both thread safe and non-thread safe in the same code.
clippy::arc_with_non_send_sync,
// 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,
// We unsafe impl `Send` for a reason.
clippy::non_send_fields_in_send_ty,
// TODO!
clippy::missing_safety_doc,
// It gets in the way a lot and does not prevent bugs in practice.
clippy::pattern_type_mismatch,
)]
#![warn(
clippy::ptr_as_ptr,
trivial_casts,
trivial_numeric_casts,
unsafe_op_in_unsafe_fn,
unused_extern_crates,
unused_qualifications
)]
#[cfg(dx12)]
pub mod dx12;
pub mod empty;
#[cfg(gles)]
pub mod gles;
#[cfg(metal)]
pub mod metal;
#[cfg(vulkan)]
pub mod vulkan;
pub mod auxil;
pub mod api {
#[cfg(dx12)]
pub use super::dx12::Api as Dx12;
pub use super::empty::Api as Empty;
#[cfg(gles)]
pub use super::gles::Api as Gles;
#[cfg(metal)]
pub use super::metal::Api as Metal;
#[cfg(vulkan)]
pub use super::vulkan::Api as Vulkan;
}
mod dynamic;
pub(crate) use dynamic::impl_dyn_resource;
pub use dynamic::{
DynAccelerationStructure, DynAcquiredSurfaceTexture, DynAdapter, DynBindGroup,
DynBindGroupLayout, DynBuffer, DynCommandBuffer, DynCommandEncoder, DynComputePipeline,
DynDevice, DynExposedAdapter, DynFence, DynInstance, DynOpenDevice, DynPipelineCache,
DynPipelineLayout, DynQuerySet, DynQueue, DynRenderPipeline, DynResource, DynSampler,
DynShaderModule, DynSurface, DynSurfaceTexture, DynTexture, DynTextureView,
};
use std::{
borrow::{Borrow, Cow},
fmt,
num::NonZeroU32,
ops::{Range, RangeInclusive},
ptr::NonNull,
sync::Arc,
};
use bitflags::bitflags;
use parking_lot::Mutex;
use thiserror::Error;
use wgt::WasmNotSendSync;
pub const MAX_CONCURRENT_SHADER_STAGES: usize = 2;
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;
pub const QUERY_SIZE: wgt::BufferAddress = 8;
pub type Label<'a> = Option<&'a str>;
pub type MemoryRange = Range<wgt::BufferAddress>;
pub type FenceValue = u64;
pub type AtomicFenceValue = std::sync::atomic::AtomicU64;
#[cfg(any(gles, vulkan))]
pub type DropCallback = Box<dyn FnMut() + Send + Sync + 'static>;
#[cfg(any(gles, vulkan))]
pub struct DropGuard {
callback: DropCallback,
}
#[cfg(all(any(gles, vulkan), any(native, Emscripten)))]
impl DropGuard {
fn from_option(callback: Option<DropCallback>) -> Option<Self> {
callback.map(|callback| Self { callback })
}
}
#[cfg(any(gles, vulkan))]
impl Drop for DropGuard {
fn drop(&mut self) {
(self.callback)();
}
}
#[cfg(any(gles, vulkan))]
impl fmt::Debug for DropGuard {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("DropGuard").finish()
}
}
#[derive(Clone, Debug, PartialEq, Eq, Error)]
pub enum DeviceError {
#[error("Out of memory")]
OutOfMemory,
#[error("Device is lost")]
Lost,
#[error("Creation of a resource failed for a reason other than running out of memory.")]
ResourceCreationFailed,
#[error("Unexpected error variant (driver implementation is at fault)")]
Unexpected,
}
#[allow(dead_code)] #[cold]
fn hal_usage_error<T: fmt::Display>(txt: T) -> ! {
panic!("wgpu-hal invariant was violated (usage error): {txt}")
}
#[allow(dead_code)] #[cold]
fn hal_internal_error<T: fmt::Display>(txt: T) -> ! {
panic!("wgpu-hal ran into a preventable internal error: {txt}")
}
#[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),
#[error("Pipeline constant error for stage {0:?}: {1}")]
PipelineConstants(wgt::ShaderStages, String),
}
#[derive(Clone, Debug, Eq, PartialEq, Error)]
pub enum PipelineCacheError {
#[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, Error)]
#[error("{message}")]
pub struct InstanceError {
message: String,
#[source]
source: Option<Arc<dyn std::error::Error + Send + Sync + 'static>>,
}
impl InstanceError {
#[allow(dead_code)] pub(crate) fn new(message: String) -> Self {
Self {
message,
source: None,
}
}
#[allow(dead_code)] pub(crate) fn with_source(
message: String,
source: impl std::error::Error + Send + Sync + 'static,
) -> Self {
Self {
message,
source: Some(Arc::new(source)),
}
}
}
pub trait Api: Clone + fmt::Debug + Sized {
type Instance: DynInstance + Instance<A = Self>;
type Surface: DynSurface + Surface<A = Self>;
type Adapter: DynAdapter + Adapter<A = Self>;
type Device: DynDevice + Device<A = Self>;
type Queue: DynQueue + Queue<A = Self>;
type CommandEncoder: DynCommandEncoder + CommandEncoder<A = Self>;
type CommandBuffer: DynCommandBuffer;
type Buffer: DynBuffer;
type Texture: DynTexture;
type SurfaceTexture: DynSurfaceTexture + Borrow<Self::Texture>;
type TextureView: DynTextureView;
type Sampler: DynSampler;
type QuerySet: DynQuerySet;
type Fence: DynFence;
type BindGroupLayout: DynBindGroupLayout;
type BindGroup: DynBindGroup;
type PipelineLayout: DynPipelineLayout;
type ShaderModule: DynShaderModule;
type RenderPipeline: DynRenderPipeline;
type ComputePipeline: DynComputePipeline;
type PipelineCache: DynPipelineCache;
type AccelerationStructure: DynAccelerationStructure + 'static;
}
pub trait Instance: Sized + WasmNotSendSync {
type A: Api;
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<<Self::A as Api>::Surface, InstanceError>;
unsafe fn enumerate_adapters(
&self,
surface_hint: Option<&<Self::A as Api>::Surface>,
) -> Vec<ExposedAdapter<Self::A>>;
}
pub trait Surface: WasmNotSendSync {
type A: Api;
unsafe fn configure(
&self,
device: &<Self::A as Api>::Device,
config: &SurfaceConfiguration,
) -> Result<(), SurfaceError>;
unsafe fn unconfigure(&self, device: &<Self::A as Api>::Device);
unsafe fn acquire_texture(
&self,
timeout: Option<std::time::Duration>,
fence: &<Self::A as Api>::Fence,
) -> Result<Option<AcquiredSurfaceTexture<Self::A>>, SurfaceError>;
unsafe fn discard_texture(&self, texture: <Self::A as Api>::SurfaceTexture);
}
pub trait Adapter: WasmNotSendSync {
type A: Api;
unsafe fn open(
&self,
features: wgt::Features,
limits: &wgt::Limits,
memory_hints: &wgt::MemoryHints,
) -> Result<OpenDevice<Self::A>, DeviceError>;
unsafe fn texture_format_capabilities(
&self,
format: wgt::TextureFormat,
) -> TextureFormatCapabilities;
unsafe fn surface_capabilities(
&self,
surface: &<Self::A as Api>::Surface,
) -> Option<SurfaceCapabilities>;
unsafe fn get_presentation_timestamp(&self) -> wgt::PresentationTimestamp;
}
pub trait Device: WasmNotSendSync {
type A: Api;
unsafe fn exit(self, queue: <Self::A as Api>::Queue);
unsafe fn create_buffer(
&self,
desc: &BufferDescriptor,
) -> Result<<Self::A as Api>::Buffer, DeviceError>;
unsafe fn destroy_buffer(&self, buffer: <Self::A as Api>::Buffer);
unsafe fn add_raw_buffer(&self, buffer: &<Self::A as Api>::Buffer);
unsafe fn map_buffer(
&self,
buffer: &<Self::A as Api>::Buffer,
range: MemoryRange,
) -> Result<BufferMapping, DeviceError>;
unsafe fn unmap_buffer(&self, buffer: &<Self::A as Api>::Buffer);
unsafe fn flush_mapped_ranges<I>(&self, buffer: &<Self::A as Api>::Buffer, ranges: I)
where
I: Iterator<Item = MemoryRange>;
unsafe fn invalidate_mapped_ranges<I>(&self, buffer: &<Self::A as Api>::Buffer, ranges: I)
where
I: Iterator<Item = MemoryRange>;
unsafe fn create_texture(
&self,
desc: &TextureDescriptor,
) -> Result<<Self::A as Api>::Texture, DeviceError>;
unsafe fn destroy_texture(&self, texture: <Self::A as Api>::Texture);
unsafe fn add_raw_texture(&self, texture: &<Self::A as Api>::Texture);
unsafe fn create_texture_view(
&self,
texture: &<Self::A as Api>::Texture,
desc: &TextureViewDescriptor,
) -> Result<<Self::A as Api>::TextureView, DeviceError>;
unsafe fn destroy_texture_view(&self, view: <Self::A as Api>::TextureView);
unsafe fn create_sampler(
&self,
desc: &SamplerDescriptor,
) -> Result<<Self::A as Api>::Sampler, DeviceError>;
unsafe fn destroy_sampler(&self, sampler: <Self::A as Api>::Sampler);
unsafe fn create_command_encoder(
&self,
desc: &CommandEncoderDescriptor<<Self::A as Api>::Queue>,
) -> Result<<Self::A as Api>::CommandEncoder, DeviceError>;
unsafe fn destroy_command_encoder(&self, pool: <Self::A as Api>::CommandEncoder);
unsafe fn create_bind_group_layout(
&self,
desc: &BindGroupLayoutDescriptor,
) -> Result<<Self::A as Api>::BindGroupLayout, DeviceError>;
unsafe fn destroy_bind_group_layout(&self, bg_layout: <Self::A as Api>::BindGroupLayout);
unsafe fn create_pipeline_layout(
&self,
desc: &PipelineLayoutDescriptor<<Self::A as Api>::BindGroupLayout>,
) -> Result<<Self::A as Api>::PipelineLayout, DeviceError>;
unsafe fn destroy_pipeline_layout(&self, pipeline_layout: <Self::A as Api>::PipelineLayout);
#[allow(clippy::type_complexity)]
unsafe fn create_bind_group(
&self,
desc: &BindGroupDescriptor<
<Self::A as Api>::BindGroupLayout,
<Self::A as Api>::Buffer,
<Self::A as Api>::Sampler,
<Self::A as Api>::TextureView,
<Self::A as Api>::AccelerationStructure,
>,
) -> Result<<Self::A as Api>::BindGroup, DeviceError>;
unsafe fn destroy_bind_group(&self, group: <Self::A as Api>::BindGroup);
unsafe fn create_shader_module(
&self,
desc: &ShaderModuleDescriptor,
shader: ShaderInput,
) -> Result<<Self::A as Api>::ShaderModule, ShaderError>;
unsafe fn destroy_shader_module(&self, module: <Self::A as Api>::ShaderModule);
#[allow(clippy::type_complexity)]
unsafe fn create_render_pipeline(
&self,
desc: &RenderPipelineDescriptor<
<Self::A as Api>::PipelineLayout,
<Self::A as Api>::ShaderModule,
<Self::A as Api>::PipelineCache,
>,
) -> Result<<Self::A as Api>::RenderPipeline, PipelineError>;
unsafe fn destroy_render_pipeline(&self, pipeline: <Self::A as Api>::RenderPipeline);
#[allow(clippy::type_complexity)]
unsafe fn create_compute_pipeline(
&self,
desc: &ComputePipelineDescriptor<
<Self::A as Api>::PipelineLayout,
<Self::A as Api>::ShaderModule,
<Self::A as Api>::PipelineCache,
>,
) -> Result<<Self::A as Api>::ComputePipeline, PipelineError>;
unsafe fn destroy_compute_pipeline(&self, pipeline: <Self::A as Api>::ComputePipeline);
unsafe fn create_pipeline_cache(
&self,
desc: &PipelineCacheDescriptor<'_>,
) -> Result<<Self::A as Api>::PipelineCache, PipelineCacheError>;
fn pipeline_cache_validation_key(&self) -> Option<[u8; 16]> {
None
}
unsafe fn destroy_pipeline_cache(&self, cache: <Self::A as Api>::PipelineCache);
unsafe fn create_query_set(
&self,
desc: &wgt::QuerySetDescriptor<Label>,
) -> Result<<Self::A as Api>::QuerySet, DeviceError>;
unsafe fn destroy_query_set(&self, set: <Self::A as Api>::QuerySet);
unsafe fn create_fence(&self) -> Result<<Self::A as Api>::Fence, DeviceError>;
unsafe fn destroy_fence(&self, fence: <Self::A as Api>::Fence);
unsafe fn get_fence_value(
&self,
fence: &<Self::A as Api>::Fence,
) -> Result<FenceValue, DeviceError>;
unsafe fn wait(
&self,
fence: &<Self::A as Api>::Fence,
value: FenceValue,
timeout_ms: u32,
) -> Result<bool, DeviceError>;
unsafe fn start_capture(&self) -> bool;
unsafe fn stop_capture(&self);
#[allow(unused_variables)]
unsafe fn pipeline_cache_get_data(
&self,
cache: &<Self::A as Api>::PipelineCache,
) -> Option<Vec<u8>> {
None
}
unsafe fn create_acceleration_structure(
&self,
desc: &AccelerationStructureDescriptor,
) -> Result<<Self::A as Api>::AccelerationStructure, DeviceError>;
unsafe fn get_acceleration_structure_build_sizes(
&self,
desc: &GetAccelerationStructureBuildSizesDescriptor<<Self::A as Api>::Buffer>,
) -> AccelerationStructureBuildSizes;
unsafe fn get_acceleration_structure_device_address(
&self,
acceleration_structure: &<Self::A as Api>::AccelerationStructure,
) -> wgt::BufferAddress;
unsafe fn destroy_acceleration_structure(
&self,
acceleration_structure: <Self::A as Api>::AccelerationStructure,
);
fn get_internal_counters(&self) -> wgt::HalCounters;
fn generate_allocator_report(&self) -> Option<wgt::AllocatorReport> {
None
}
}
pub trait Queue: WasmNotSendSync {
type A: Api;
unsafe fn submit(
&self,
command_buffers: &[&<Self::A as Api>::CommandBuffer],
surface_textures: &[&<Self::A as Api>::SurfaceTexture],
signal_fence: (&mut <Self::A as Api>::Fence, FenceValue),
) -> Result<(), DeviceError>;
unsafe fn present(
&self,
surface: &<Self::A as Api>::Surface,
texture: <Self::A as Api>::SurfaceTexture,
) -> Result<(), SurfaceError>;
unsafe fn get_timestamp_period(&self) -> f32;
}
pub trait CommandEncoder: WasmNotSendSync + fmt::Debug {
type A: Api;
unsafe fn begin_encoding(&mut self, label: Label) -> Result<(), DeviceError>;
unsafe fn discard_encoding(&mut self);
unsafe fn end_encoding(&mut self) -> Result<<Self::A as Api>::CommandBuffer, DeviceError>;
unsafe fn reset_all<I>(&mut self, command_buffers: I)
where
I: Iterator<Item = <Self::A as Api>::CommandBuffer>;
unsafe fn transition_buffers<'a, T>(&mut self, barriers: T)
where
T: Iterator<Item = BufferBarrier<'a, <Self::A as Api>::Buffer>>;
unsafe fn transition_textures<'a, T>(&mut self, barriers: T)
where
T: Iterator<Item = TextureBarrier<'a, <Self::A as Api>::Texture>>;
unsafe fn clear_buffer(&mut self, buffer: &<Self::A as Api>::Buffer, range: MemoryRange);
unsafe fn copy_buffer_to_buffer<T>(
&mut self,
src: &<Self::A as Api>::Buffer,
dst: &<Self::A as Api>::Buffer,
regions: T,
) where
T: Iterator<Item = BufferCopy>;
#[cfg(webgl)]
unsafe fn copy_external_image_to_texture<T>(
&mut self,
src: &wgt::ImageCopyExternalImage,
dst: &<Self::A as Api>::Texture,
dst_premultiplication: bool,
regions: T,
) where
T: Iterator<Item = TextureCopy>;
unsafe fn copy_texture_to_texture<T>(
&mut self,
src: &<Self::A as Api>::Texture,
src_usage: TextureUses,
dst: &<Self::A as Api>::Texture,
regions: T,
) where
T: Iterator<Item = TextureCopy>;
unsafe fn copy_buffer_to_texture<T>(
&mut self,
src: &<Self::A as Api>::Buffer,
dst: &<Self::A as Api>::Texture,
regions: T,
) where
T: Iterator<Item = BufferTextureCopy>;
unsafe fn copy_texture_to_buffer<T>(
&mut self,
src: &<Self::A as Api>::Texture,
src_usage: TextureUses,
dst: &<Self::A as Api>::Buffer,
regions: T,
) where
T: Iterator<Item = BufferTextureCopy>;
unsafe fn set_bind_group(
&mut self,
layout: &<Self::A as Api>::PipelineLayout,
index: u32,
group: &<Self::A as Api>::BindGroup,
dynamic_offsets: &[wgt::DynamicOffset],
);
unsafe fn set_push_constants(
&mut self,
layout: &<Self::A as Api>::PipelineLayout,
stages: wgt::ShaderStages,
offset_bytes: 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);
unsafe fn begin_query(&mut self, set: &<Self::A as Api>::QuerySet, index: u32);
unsafe fn end_query(&mut self, set: &<Self::A as Api>::QuerySet, index: u32);
unsafe fn write_timestamp(&mut self, set: &<Self::A as Api>::QuerySet, index: u32);
unsafe fn reset_queries(&mut self, set: &<Self::A as Api>::QuerySet, range: Range<u32>);
unsafe fn copy_query_results(
&mut self,
set: &<Self::A as Api>::QuerySet,
range: Range<u32>,
buffer: &<Self::A as Api>::Buffer,
offset: wgt::BufferAddress,
stride: wgt::BufferSize,
);
unsafe fn begin_render_pass(
&mut self,
desc: &RenderPassDescriptor<<Self::A as Api>::QuerySet, <Self::A as Api>::TextureView>,
);
unsafe fn end_render_pass(&mut self);
unsafe fn set_render_pipeline(&mut self, pipeline: &<Self::A as Api>::RenderPipeline);
unsafe fn set_index_buffer<'a>(
&mut self,
binding: BufferBinding<'a, <Self::A as Api>::Buffer>,
format: wgt::IndexFormat,
);
unsafe fn set_vertex_buffer<'a>(
&mut self,
index: u32,
binding: BufferBinding<'a, <Self::A as Api>::Buffer>,
);
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,
first_vertex: u32,
vertex_count: u32,
first_instance: u32,
instance_count: u32,
);
unsafe fn draw_indexed(
&mut self,
first_index: u32,
index_count: u32,
base_vertex: i32,
first_instance: u32,
instance_count: u32,
);
unsafe fn draw_indirect(
&mut self,
buffer: &<Self::A as Api>::Buffer,
offset: wgt::BufferAddress,
draw_count: u32,
);
unsafe fn draw_indexed_indirect(
&mut self,
buffer: &<Self::A as Api>::Buffer,
offset: wgt::BufferAddress,
draw_count: u32,
);
unsafe fn draw_indirect_count(
&mut self,
buffer: &<Self::A as Api>::Buffer,
offset: wgt::BufferAddress,
count_buffer: &<Self::A as Api>::Buffer,
count_offset: wgt::BufferAddress,
max_count: u32,
);
unsafe fn draw_indexed_indirect_count(
&mut self,
buffer: &<Self::A as Api>::Buffer,
offset: wgt::BufferAddress,
count_buffer: &<Self::A as Api>::Buffer,
count_offset: wgt::BufferAddress,
max_count: u32,
);
unsafe fn begin_compute_pass(
&mut self,
desc: &ComputePassDescriptor<<Self::A as Api>::QuerySet>,
);
unsafe fn end_compute_pass(&mut self);
unsafe fn set_compute_pipeline(&mut self, pipeline: &<Self::A as Api>::ComputePipeline);
unsafe fn dispatch(&mut self, count: [u32; 3]);
unsafe fn dispatch_indirect(
&mut self,
buffer: &<Self::A as Api>::Buffer,
offset: wgt::BufferAddress,
);
unsafe fn build_acceleration_structures<'a, T>(
&mut self,
descriptor_count: u32,
descriptors: T,
) where
Self::A: 'a,
T: IntoIterator<
Item = BuildAccelerationStructureDescriptor<
'a,
<Self::A as Api>::Buffer,
<Self::A as Api>::AccelerationStructure,
>,
>;
unsafe fn place_acceleration_structure_barrier(
&mut self,
barrier: AccelerationStructureBarrier,
);
}
bitflags!(
/// Pipeline layout creation flags.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct PipelineLayoutFlags: u32 {
/// Include support for `first_vertex` / `first_instance` drawing.
const FIRST_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;
const PLANE_0 = 1 << 3;
const PLANE_1 = 1 << 4;
const PLANE_2 = 1 << 5;
const DEPTH_STENCIL = Self::DEPTH.bits() | Self::STENCIL.bits();
}
);
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,
wgt::TextureAspect::Plane0 => Self::PLANE_0,
wgt::TextureAspect::Plane1 => Self::PLANE_1,
wgt::TextureAspect::Plane2 => Self::PLANE_2,
};
Self::from(format) & aspect_mask
}
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,
Self::PLANE_0 => wgt::TextureAspect::Plane0,
Self::PLANE_1 => wgt::TextureAspect::Plane1,
Self::PLANE_2 => wgt::TextureAspect::Plane2,
_ => 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_STENCIL
}
wgt::TextureFormat::NV12 => Self::PLANE_0 | Self::PLANE_1,
_ => Self::COLOR,
}
}
}
bitflags!(
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct MemoryFlags: u32 {
const TRANSIENT = 1 << 0;
const PREFER_COHERENT = 1 << 1;
}
);
bitflags!(
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct AttachmentOps: u8 {
const LOAD = 1 << 0;
const STORE = 1 << 1;
}
);
bitflags::bitflags! {
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct BufferUses: u16 {
const MAP_READ = 1 << 0;
const MAP_WRITE = 1 << 1;
const COPY_SRC = 1 << 2;
const COPY_DST = 1 << 3;
const INDEX = 1 << 4;
const VERTEX = 1 << 5;
const UNIFORM = 1 << 6;
const STORAGE_READ = 1 << 7;
const STORAGE_READ_WRITE = 1 << 8;
const INDIRECT = 1 << 9;
const QUERY_RESOLVE = 1 << 10;
const ACCELERATION_STRUCTURE_SCRATCH = 1 << 11;
const BOTTOM_LEVEL_ACCELERATION_STRUCTURE_INPUT = 1 << 12;
const TOP_LEVEL_ACCELERATION_STRUCTURE_INPUT = 1 << 13;
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() | Self::BOTTOM_LEVEL_ACCELERATION_STRUCTURE_INPUT.bits() | Self::TOP_LEVEL_ACCELERATION_STRUCTURE_INPUT.bits();
const EXCLUSIVE = Self::MAP_WRITE.bits() | Self::COPY_DST.bits() | Self::STORAGE_READ_WRITE.bits() | Self::ACCELERATION_STRUCTURE_SCRATCH.bits();
const ORDERED = Self::INCLUSIVE.bits() | Self::MAP_WRITE.bits();
}
}
bitflags::bitflags! {
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct TextureUses: u16 {
const UNINITIALIZED = 1 << 0;
const PRESENT = 1 << 1;
const COPY_SRC = 1 << 2;
const COPY_DST = 1 << 3;
const RESOURCE = 1 << 4;
const COLOR_TARGET = 1 << 5;
const DEPTH_STENCIL_READ = 1 << 6;
const DEPTH_STENCIL_WRITE = 1 << 7;
const STORAGE_READ = 1 << 8;
const STORAGE_READ_WRITE = 1 << 9;
const INCLUSIVE = Self::COPY_SRC.bits() | Self::RESOURCE.bits() | Self::DEPTH_STENCIL_READ.bits();
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();
const ORDERED = Self::INCLUSIVE.bits() | Self::COLOR_TARGET.bits() | Self::DEPTH_STENCIL_WRITE.bits() | Self::STORAGE_READ.bits();
const COMPLEX = 1 << 10;
const UNKNOWN = 1 << 11;
}
}
#[derive(Clone, Debug)]
pub struct InstanceDescriptor<'a> {
pub name: &'a str,
pub flags: wgt::InstanceFlags,
pub dx12_shader_compiler: wgt::Dx12Compiler,
pub gles_minor_version: wgt::Gles3MinorVersion,
}
#[derive(Clone, Debug)]
pub struct Alignments {
pub buffer_copy_offset: wgt::BufferSize,
pub buffer_copy_pitch: wgt::BufferSize,
pub uniform_bounds_check_alignment: 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,
}
#[derive(Debug, Clone)]
pub struct SurfaceCapabilities {
pub formats: Vec<wgt::TextureFormat>,
pub maximum_frame_latency: RangeInclusive<u32>,
pub current_extent: Option<wgt::Extent3d>,
pub usage: TextureUses,
pub present_modes: Vec<wgt::PresentMode>,
pub composite_alpha_modes: Vec<wgt::CompositeAlphaMode>,
}
#[derive(Debug)]
pub struct AcquiredSurfaceTexture<A: Api> {
pub texture: A::SurfaceTexture,
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,
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,
}
}
}
#[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>,
pub anisotropy_clamp: u16,
pub border_color: Option<wgt::SamplerBorderColor>,
}
#[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, B: DynBindGroupLayout + ?Sized> {
pub label: Label<'a>,
pub flags: PipelineLayoutFlags,
pub bind_group_layouts: &'a [&'a B],
pub push_constant_ranges: &'a [wgt::PushConstantRange],
}
#[derive(Debug)]
pub struct BufferBinding<'a, B: DynBuffer + ?Sized> {
pub buffer: &'a B,
pub offset: wgt::BufferAddress,
pub size: Option<wgt::BufferSize>,
}
impl<'a, T: DynBuffer + ?Sized> Clone for BufferBinding<'a, T> {
fn clone(&self) -> Self {
BufferBinding {
buffer: self.buffer,
offset: self.offset,
size: self.size,
}
}
}
#[derive(Debug)]
pub struct TextureBinding<'a, T: DynTextureView + ?Sized> {
pub view: &'a T,
pub usage: TextureUses,
}
impl<'a, T: DynTextureView + ?Sized> Clone for TextureBinding<'a, T> {
fn clone(&self) -> Self {
TextureBinding {
view: self.view,
usage: self.usage,
}
}
}
#[derive(Clone, Debug)]
pub struct BindGroupEntry {
pub binding: u32,
pub resource_index: u32,
pub count: u32,
}
#[derive(Clone, Debug)]
pub struct BindGroupDescriptor<
'a,
Bgl: DynBindGroupLayout + ?Sized,
B: DynBuffer + ?Sized,
S: DynSampler + ?Sized,
T: DynTextureView + ?Sized,
A: DynAccelerationStructure + ?Sized,
> {
pub label: Label<'a>,
pub layout: &'a Bgl,
pub buffers: &'a [BufferBinding<'a, B>],
pub samplers: &'a [&'a S],
pub textures: &'a [TextureBinding<'a, T>],
pub entries: &'a [BindGroupEntry],
pub acceleration_structures: &'a [&'a A],
}
#[derive(Clone, Debug)]
pub struct CommandEncoderDescriptor<'a, Q: DynQueue + ?Sized> {
pub label: Label<'a>,
pub queue: &'a Q,
}
pub struct NagaShader {
pub module: Cow<'static, naga::Module>,
pub info: naga::valid::ModuleInfo,
pub debug_source: Option<DebugSource>,
}
impl fmt::Debug for NagaShader {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "Naga shader")
}
}
#[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,
}
#[derive(Debug, Clone)]
pub struct DebugSource {
pub file_name: Cow<'static, str>,
pub source_code: Cow<'static, str>,
}
#[derive(Debug)]
pub struct ProgrammableStage<'a, M: DynShaderModule + ?Sized> {
pub module: &'a M,
pub entry_point: &'a str,
pub constants: &'a naga::back::PipelineConstants,
pub zero_initialize_workgroup_memory: bool,
}
impl<M: DynShaderModule + ?Sized> Clone for ProgrammableStage<'_, M> {
fn clone(&self) -> Self {
Self {
module: self.module,
entry_point: self.entry_point,
constants: self.constants,
zero_initialize_workgroup_memory: self.zero_initialize_workgroup_memory,
}
}
}
#[derive(Clone, Debug)]
pub struct ComputePipelineDescriptor<
'a,
Pl: DynPipelineLayout + ?Sized,
M: DynShaderModule + ?Sized,
Pc: DynPipelineCache + ?Sized,
> {
pub label: Label<'a>,
pub layout: &'a Pl,
pub stage: ProgrammableStage<'a, M>,
pub cache: Option<&'a Pc>,
}
pub struct PipelineCacheDescriptor<'a> {
pub label: Label<'a>,
pub data: Option<&'a [u8]>,
}
#[derive(Clone, Debug)]
pub struct VertexBufferLayout<'a> {
pub array_stride: wgt::BufferAddress,
pub step_mode: wgt::VertexStepMode,
pub attributes: &'a [wgt::VertexAttribute],
}
#[derive(Clone, Debug)]
pub struct RenderPipelineDescriptor<
'a,
Pl: DynPipelineLayout + ?Sized,
M: DynShaderModule + ?Sized,
Pc: DynPipelineCache + ?Sized,
> {
pub label: Label<'a>,
pub layout: &'a Pl,
pub vertex_buffers: &'a [VertexBufferLayout<'a>],
pub vertex_stage: ProgrammableStage<'a, M>,
pub primitive: wgt::PrimitiveState,
pub depth_stencil: Option<wgt::DepthStencilState>,
pub multisample: wgt::MultisampleState,
pub fragment_stage: Option<ProgrammableStage<'a, M>>,
pub color_targets: &'a [Option<wgt::ColorTargetState>],
pub multiview: Option<NonZeroU32>,
pub cache: Option<&'a Pc>,
}
#[derive(Debug, Clone)]
pub struct SurfaceConfiguration {
pub maximum_frame_latency: u32,
pub present_mode: wgt::PresentMode,
pub composite_alpha_mode: wgt::CompositeAlphaMode,
pub format: wgt::TextureFormat,
pub extent: wgt::Extent3d,
pub usage: TextureUses,
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, B: DynBuffer + ?Sized> {
pub buffer: &'a B,
pub usage: Range<BufferUses>,
}
#[derive(Debug, Clone)]
pub struct TextureBarrier<'a, T: DynTexture + ?Sized> {
pub texture: &'a T,
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,
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(Clone, Debug)]
pub struct Attachment<'a, T: DynTextureView + ?Sized> {
pub view: &'a T,
pub usage: TextureUses,
}
#[derive(Clone, Debug)]
pub struct ColorAttachment<'a, T: DynTextureView + ?Sized> {
pub target: Attachment<'a, T>,
pub resolve_target: Option<Attachment<'a, T>>,
pub ops: AttachmentOps,
pub clear_value: wgt::Color,
}
#[derive(Clone, Debug)]
pub struct DepthStencilAttachment<'a, T: DynTextureView + ?Sized> {
pub target: Attachment<'a, T>,
pub depth_ops: AttachmentOps,
pub stencil_ops: AttachmentOps,
pub clear_value: (f32, u32),
}
#[derive(Clone, Debug)]
pub struct PassTimestampWrites<'a, Q: DynQuerySet + ?Sized> {
pub query_set: &'a Q,
pub beginning_of_pass_write_index: Option<u32>,
pub end_of_pass_write_index: Option<u32>,
}
#[derive(Clone, Debug)]
pub struct RenderPassDescriptor<'a, Q: DynQuerySet + ?Sized, T: DynTextureView + ?Sized> {
pub label: Label<'a>,
pub extent: wgt::Extent3d,
pub sample_count: u32,
pub color_attachments: &'a [Option<ColorAttachment<'a, T>>],
pub depth_stencil_attachment: Option<DepthStencilAttachment<'a, T>>,
pub multiview: Option<NonZeroU32>,
pub timestamp_writes: Option<PassTimestampWrites<'a, Q>>,
pub occlusion_query_set: Option<&'a Q>,
}
#[derive(Clone, Debug)]
pub struct ComputePassDescriptor<'a, Q: DynQuerySet + ?Sized> {
pub label: Label<'a>,
pub timestamp_writes: Option<PassTimestampWrites<'a, Q>>,
}
pub static VALIDATION_CANARY: ValidationCanary = ValidationCanary {
inner: Mutex::new(Vec::new()),
};
pub struct ValidationCanary {
inner: Mutex<Vec<String>>,
}
impl ValidationCanary {
#[allow(dead_code)] fn add(&self, msg: String) {
self.inner.lock().push(msg);
}
pub fn get_and_reset(&self) -> Vec<String> {
self.inner.lock().drain(..).collect()
}
}
#[test]
fn test_default_limits() {
let limits = wgt::Limits::default();
assert!(limits.max_bind_groups <= MAX_BIND_GROUPS as u32);
}
#[derive(Clone, Debug)]
pub struct AccelerationStructureDescriptor<'a> {
pub label: Label<'a>,
pub size: wgt::BufferAddress,
pub format: AccelerationStructureFormat,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum AccelerationStructureFormat {
TopLevel,
BottomLevel,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum AccelerationStructureBuildMode {
Build,
Update,
}
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
pub struct AccelerationStructureBuildSizes {
pub acceleration_structure_size: wgt::BufferAddress,
pub update_scratch_size: wgt::BufferAddress,
pub build_scratch_size: wgt::BufferAddress,
}
#[derive(Clone, Debug)]
pub struct BuildAccelerationStructureDescriptor<
'a,
B: DynBuffer + ?Sized,
A: DynAccelerationStructure + ?Sized,
> {
pub entries: &'a AccelerationStructureEntries<'a, B>,
pub mode: AccelerationStructureBuildMode,
pub flags: AccelerationStructureBuildFlags,
pub source_acceleration_structure: Option<&'a A>,
pub destination_acceleration_structure: &'a A,
pub scratch_buffer: &'a B,
pub scratch_buffer_offset: wgt::BufferAddress,
}
#[derive(Clone, Debug)]
pub struct GetAccelerationStructureBuildSizesDescriptor<'a, B: DynBuffer + ?Sized> {
pub entries: &'a AccelerationStructureEntries<'a, B>,
pub flags: AccelerationStructureBuildFlags,
}
#[derive(Debug)]
pub enum AccelerationStructureEntries<'a, B: DynBuffer + ?Sized> {
Instances(AccelerationStructureInstances<'a, B>),
Triangles(Vec<AccelerationStructureTriangles<'a, B>>),
AABBs(Vec<AccelerationStructureAABBs<'a, B>>),
}
#[derive(Clone, Debug)]
pub struct AccelerationStructureTriangles<'a, B: DynBuffer + ?Sized> {
pub vertex_buffer: Option<&'a B>,
pub vertex_format: wgt::VertexFormat,
pub first_vertex: u32,
pub vertex_count: u32,
pub vertex_stride: wgt::BufferAddress,
pub indices: Option<AccelerationStructureTriangleIndices<'a, B>>,
pub transform: Option<AccelerationStructureTriangleTransform<'a, B>>,
pub flags: AccelerationStructureGeometryFlags,
}
#[derive(Clone, Debug)]
pub struct AccelerationStructureAABBs<'a, B: DynBuffer + ?Sized> {
pub buffer: Option<&'a B>,
pub offset: u32,
pub count: u32,
pub stride: wgt::BufferAddress,
pub flags: AccelerationStructureGeometryFlags,
}
#[derive(Clone, Debug)]
pub struct AccelerationStructureInstances<'a, B: DynBuffer + ?Sized> {
pub buffer: Option<&'a B>,
pub offset: u32,
pub count: u32,
}
#[derive(Clone, Debug)]
pub struct AccelerationStructureTriangleIndices<'a, B: DynBuffer + ?Sized> {
pub format: wgt::IndexFormat,
pub buffer: Option<&'a B>,
pub offset: u32,
pub count: u32,
}
#[derive(Clone, Debug)]
pub struct AccelerationStructureTriangleTransform<'a, B: DynBuffer + ?Sized> {
pub buffer: &'a B,
pub offset: u32,
}
pub use wgt::AccelerationStructureFlags as AccelerationStructureBuildFlags;
pub use wgt::AccelerationStructureGeometryFlags;
bitflags::bitflags! {
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct AccelerationStructureUses: u8 {
const BUILD_INPUT = 1 << 0;
const BUILD_OUTPUT = 1 << 1;
const SHADER_INPUT = 1 << 2;
}
}
#[derive(Debug, Clone)]
pub struct AccelerationStructureBarrier {
pub usage: Range<AccelerationStructureUses>,
}