#![doc(html_logo_url = "https://raw.githubusercontent.com/gfx-rs/wgpu/master/logo.png")]
#![warn(missing_docs)]
mod backend;
pub mod util;
#[macro_use]
mod macros;
use std::{
borrow::Cow,
error,
fmt::{Debug, Display},
future::Future,
marker::PhantomData,
num::{NonZeroU32, NonZeroU8},
ops::{Bound, Range, RangeBounds},
sync::Arc,
thread,
};
use parking_lot::Mutex;
pub use wgt::{
AdapterInfo, AddressMode, Backend, Backends, BindGroupLayoutEntry, BindingType, BlendComponent,
BlendFactor, BlendOperation, BlendState, BufferAddress, BufferBindingType, BufferSize,
BufferUsages, Color, ColorTargetState, ColorWrites, CommandBufferDescriptor, CompareFunction,
DepthBiasState, DepthStencilState, DeviceType, DownlevelCapabilities, DownlevelFlags,
DynamicOffset, Extent3d, Face, Features, FilterMode, FrontFace, ImageDataLayout,
ImageSubresourceRange, IndexFormat, Limits, MultisampleState, Origin3d,
PipelineStatisticsTypes, PolygonMode, PowerPreference, PresentMode, PrimitiveState,
PrimitiveTopology, PushConstantRange, QueryType, RenderBundleDepthStencil, SamplerBorderColor,
ShaderLocation, ShaderModel, ShaderStages, StencilFaceState, StencilOperation, StencilState,
StorageTextureAccess, SurfaceConfiguration, SurfaceStatus, TextureAspect, TextureDimension,
TextureFormat, TextureFormatFeatureFlags, TextureFormatFeatures, TextureSampleType,
TextureUsages, TextureViewDimension, VertexAttribute, VertexFormat, VertexStepMode,
BIND_BUFFER_ALIGNMENT, COPY_BUFFER_ALIGNMENT, COPY_BYTES_PER_ROW_ALIGNMENT, MAP_ALIGNMENT,
PUSH_CONSTANT_ALIGNMENT, QUERY_SET_MAX_QUERIES, QUERY_SIZE, VERTEX_STRIDE_ALIGNMENT,
};
use backend::{BufferMappedRange, Context as C};
trait ComputePassInner<Ctx: Context> {
fn set_pipeline(&mut self, pipeline: &Ctx::ComputePipelineId);
fn set_bind_group(
&mut self,
index: u32,
bind_group: &Ctx::BindGroupId,
offsets: &[DynamicOffset],
);
fn set_push_constants(&mut self, offset: u32, data: &[u8]);
fn insert_debug_marker(&mut self, label: &str);
fn push_debug_group(&mut self, group_label: &str);
fn pop_debug_group(&mut self);
fn write_timestamp(&mut self, query_set: &Ctx::QuerySetId, query_index: u32);
fn begin_pipeline_statistics_query(&mut self, query_set: &Ctx::QuerySetId, query_index: u32);
fn end_pipeline_statistics_query(&mut self);
fn dispatch(&mut self, x: u32, y: u32, z: u32);
fn dispatch_indirect(
&mut self,
indirect_buffer: &Ctx::BufferId,
indirect_offset: BufferAddress,
);
}
trait RenderInner<Ctx: Context> {
fn set_pipeline(&mut self, pipeline: &Ctx::RenderPipelineId);
fn set_bind_group(
&mut self,
index: u32,
bind_group: &Ctx::BindGroupId,
offsets: &[DynamicOffset],
);
fn set_index_buffer(
&mut self,
buffer: &Ctx::BufferId,
index_format: IndexFormat,
offset: BufferAddress,
size: Option<BufferSize>,
);
fn set_vertex_buffer(
&mut self,
slot: u32,
buffer: &Ctx::BufferId,
offset: BufferAddress,
size: Option<BufferSize>,
);
fn set_push_constants(&mut self, stages: ShaderStages, offset: u32, data: &[u8]);
fn draw(&mut self, vertices: Range<u32>, instances: Range<u32>);
fn draw_indexed(&mut self, indices: Range<u32>, base_vertex: i32, instances: Range<u32>);
fn draw_indirect(&mut self, indirect_buffer: &Ctx::BufferId, indirect_offset: BufferAddress);
fn draw_indexed_indirect(
&mut self,
indirect_buffer: &Ctx::BufferId,
indirect_offset: BufferAddress,
);
fn multi_draw_indirect(
&mut self,
indirect_buffer: &Ctx::BufferId,
indirect_offset: BufferAddress,
count: u32,
);
fn multi_draw_indexed_indirect(
&mut self,
indirect_buffer: &Ctx::BufferId,
indirect_offset: BufferAddress,
count: u32,
);
fn multi_draw_indirect_count(
&mut self,
indirect_buffer: &Ctx::BufferId,
indirect_offset: BufferAddress,
count_buffer: &Ctx::BufferId,
count_buffer_offset: BufferAddress,
max_count: u32,
);
fn multi_draw_indexed_indirect_count(
&mut self,
indirect_buffer: &Ctx::BufferId,
indirect_offset: BufferAddress,
count_buffer: &Ctx::BufferId,
count_buffer_offset: BufferAddress,
max_count: u32,
);
}
trait RenderPassInner<Ctx: Context>: RenderInner<Ctx> {
fn set_blend_constant(&mut self, color: Color);
fn set_scissor_rect(&mut self, x: u32, y: u32, width: u32, height: u32);
fn set_viewport(
&mut self,
x: f32,
y: f32,
width: f32,
height: f32,
min_depth: f32,
max_depth: f32,
);
fn set_stencil_reference(&mut self, reference: u32);
fn insert_debug_marker(&mut self, label: &str);
fn push_debug_group(&mut self, group_label: &str);
fn pop_debug_group(&mut self);
fn write_timestamp(&mut self, query_set: &Ctx::QuerySetId, query_index: u32);
fn begin_pipeline_statistics_query(&mut self, query_set: &Ctx::QuerySetId, query_index: u32);
fn end_pipeline_statistics_query(&mut self);
fn execute_bundles<'a, I: Iterator<Item = &'a Ctx::RenderBundleId>>(
&mut self,
render_bundles: I,
);
}
trait Context: Debug + Send + Sized + Sync {
type AdapterId: Debug + Send + Sync + 'static;
type DeviceId: Debug + Send + Sync + 'static;
type QueueId: Debug + Send + Sync + 'static;
type ShaderModuleId: Debug + Send + Sync + 'static;
type BindGroupLayoutId: Debug + Send + Sync + 'static;
type BindGroupId: Debug + Send + Sync + 'static;
type TextureViewId: Debug + Send + Sync + 'static;
type SamplerId: Debug + Send + Sync + 'static;
type BufferId: Debug + Send + Sync + 'static;
type TextureId: Debug + Send + Sync + 'static;
type QuerySetId: Debug + Send + Sync + 'static;
type PipelineLayoutId: Debug + Send + Sync + 'static;
type RenderPipelineId: Debug + Send + Sync + 'static;
type ComputePipelineId: Debug + Send + Sync + 'static;
type CommandEncoderId: Debug;
type ComputePassId: Debug + ComputePassInner<Self>;
type RenderPassId: Debug + RenderPassInner<Self>;
type CommandBufferId: Debug + Send + Sync;
type RenderBundleEncoderId: Debug + RenderInner<Self>;
type RenderBundleId: Debug + Send + Sync + 'static;
type SurfaceId: Debug + Send + Sync + 'static;
type SurfaceOutputDetail: Send;
type RequestAdapterFuture: Future<Output = Option<Self::AdapterId>> + Send;
type RequestDeviceFuture: Future<Output = Result<(Self::DeviceId, Self::QueueId), RequestDeviceError>>
+ Send;
type MapAsyncFuture: Future<Output = Result<(), BufferAsyncError>> + Send;
type OnSubmittedWorkDoneFuture: Future<Output = ()> + Send;
fn init(backends: Backends) -> Self;
fn instance_create_surface(
&self,
handle: &impl raw_window_handle::HasRawWindowHandle,
) -> Self::SurfaceId;
fn instance_request_adapter(
&self,
options: &RequestAdapterOptions<'_>,
) -> Self::RequestAdapterFuture;
fn adapter_request_device(
&self,
adapter: &Self::AdapterId,
desc: &DeviceDescriptor,
trace_dir: Option<&std::path::Path>,
) -> Self::RequestDeviceFuture;
fn instance_poll_all_devices(&self, force_wait: bool);
fn adapter_is_surface_supported(
&self,
adapter: &Self::AdapterId,
surface: &Self::SurfaceId,
) -> bool;
fn adapter_features(&self, adapter: &Self::AdapterId) -> Features;
fn adapter_limits(&self, adapter: &Self::AdapterId) -> Limits;
fn adapter_downlevel_properties(&self, adapter: &Self::AdapterId) -> DownlevelCapabilities;
fn adapter_get_info(&self, adapter: &Self::AdapterId) -> AdapterInfo;
fn adapter_get_texture_format_features(
&self,
adapter: &Self::AdapterId,
format: TextureFormat,
) -> TextureFormatFeatures;
fn surface_get_preferred_format(
&self,
surface: &Self::SurfaceId,
adapter: &Self::AdapterId,
) -> Option<TextureFormat>;
fn surface_configure(
&self,
surface: &Self::SurfaceId,
device: &Self::DeviceId,
config: &SurfaceConfiguration,
);
fn surface_get_current_texture(
&self,
surface: &Self::SurfaceId,
) -> (
Option<Self::TextureId>,
SurfaceStatus,
Self::SurfaceOutputDetail,
);
fn surface_present(&self, texture: &Self::TextureId, detail: &Self::SurfaceOutputDetail);
fn device_features(&self, device: &Self::DeviceId) -> Features;
fn device_limits(&self, device: &Self::DeviceId) -> Limits;
fn device_downlevel_properties(&self, device: &Self::DeviceId) -> DownlevelCapabilities;
fn device_create_shader_module(
&self,
device: &Self::DeviceId,
desc: &ShaderModuleDescriptor,
) -> Self::ShaderModuleId;
unsafe fn device_create_shader_module_spirv(
&self,
device: &Self::DeviceId,
desc: &ShaderModuleDescriptorSpirV,
) -> Self::ShaderModuleId;
fn device_create_bind_group_layout(
&self,
device: &Self::DeviceId,
desc: &BindGroupLayoutDescriptor,
) -> Self::BindGroupLayoutId;
fn device_create_bind_group(
&self,
device: &Self::DeviceId,
desc: &BindGroupDescriptor,
) -> Self::BindGroupId;
fn device_create_pipeline_layout(
&self,
device: &Self::DeviceId,
desc: &PipelineLayoutDescriptor,
) -> Self::PipelineLayoutId;
fn device_create_render_pipeline(
&self,
device: &Self::DeviceId,
desc: &RenderPipelineDescriptor,
) -> Self::RenderPipelineId;
fn device_create_compute_pipeline(
&self,
device: &Self::DeviceId,
desc: &ComputePipelineDescriptor,
) -> Self::ComputePipelineId;
fn device_create_buffer(
&self,
device: &Self::DeviceId,
desc: &BufferDescriptor,
) -> Self::BufferId;
fn device_create_texture(
&self,
device: &Self::DeviceId,
desc: &TextureDescriptor,
) -> Self::TextureId;
fn device_create_sampler(
&self,
device: &Self::DeviceId,
desc: &SamplerDescriptor,
) -> Self::SamplerId;
fn device_create_query_set(
&self,
device: &Self::DeviceId,
desc: &QuerySetDescriptor,
) -> Self::QuerySetId;
fn device_create_command_encoder(
&self,
device: &Self::DeviceId,
desc: &CommandEncoderDescriptor,
) -> Self::CommandEncoderId;
fn device_create_render_bundle_encoder(
&self,
device: &Self::DeviceId,
desc: &RenderBundleEncoderDescriptor,
) -> Self::RenderBundleEncoderId;
fn device_drop(&self, device: &Self::DeviceId);
fn device_poll(&self, device: &Self::DeviceId, maintain: Maintain);
fn device_on_uncaptured_error(
&self,
device: &Self::DeviceId,
handler: impl UncapturedErrorHandler,
);
fn buffer_map_async(
&self,
buffer: &Self::BufferId,
mode: MapMode,
range: Range<BufferAddress>,
) -> Self::MapAsyncFuture;
fn buffer_get_mapped_range(
&self,
buffer: &Self::BufferId,
sub_range: Range<BufferAddress>,
) -> BufferMappedRange;
fn buffer_unmap(&self, buffer: &Self::BufferId);
fn texture_create_view(
&self,
texture: &Self::TextureId,
desc: &TextureViewDescriptor,
) -> Self::TextureViewId;
fn surface_drop(&self, surface: &Self::SurfaceId);
fn adapter_drop(&self, adapter: &Self::AdapterId);
fn buffer_destroy(&self, buffer: &Self::BufferId);
fn buffer_drop(&self, buffer: &Self::BufferId);
fn texture_destroy(&self, buffer: &Self::TextureId);
fn texture_drop(&self, texture: &Self::TextureId);
fn texture_view_drop(&self, texture_view: &Self::TextureViewId);
fn sampler_drop(&self, sampler: &Self::SamplerId);
fn query_set_drop(&self, query_set: &Self::QuerySetId);
fn bind_group_drop(&self, bind_group: &Self::BindGroupId);
fn bind_group_layout_drop(&self, bind_group_layout: &Self::BindGroupLayoutId);
fn pipeline_layout_drop(&self, pipeline_layout: &Self::PipelineLayoutId);
fn shader_module_drop(&self, shader_module: &Self::ShaderModuleId);
fn command_encoder_drop(&self, command_encoder: &Self::CommandEncoderId);
fn command_buffer_drop(&self, command_buffer: &Self::CommandBufferId);
fn render_bundle_drop(&self, render_bundle: &Self::RenderBundleId);
fn compute_pipeline_drop(&self, pipeline: &Self::ComputePipelineId);
fn render_pipeline_drop(&self, pipeline: &Self::RenderPipelineId);
fn compute_pipeline_get_bind_group_layout(
&self,
pipeline: &Self::ComputePipelineId,
index: u32,
) -> Self::BindGroupLayoutId;
fn render_pipeline_get_bind_group_layout(
&self,
pipeline: &Self::RenderPipelineId,
index: u32,
) -> Self::BindGroupLayoutId;
fn command_encoder_copy_buffer_to_buffer(
&self,
encoder: &Self::CommandEncoderId,
source: &Self::BufferId,
source_offset: BufferAddress,
destination: &Self::BufferId,
destination_offset: BufferAddress,
copy_size: BufferAddress,
);
fn command_encoder_copy_buffer_to_texture(
&self,
encoder: &Self::CommandEncoderId,
source: ImageCopyBuffer,
destination: ImageCopyTexture,
copy_size: Extent3d,
);
fn command_encoder_copy_texture_to_buffer(
&self,
encoder: &Self::CommandEncoderId,
source: ImageCopyTexture,
destination: ImageCopyBuffer,
copy_size: Extent3d,
);
fn command_encoder_copy_texture_to_texture(
&self,
encoder: &Self::CommandEncoderId,
source: ImageCopyTexture,
destination: ImageCopyTexture,
copy_size: Extent3d,
);
fn command_encoder_begin_compute_pass(
&self,
encoder: &Self::CommandEncoderId,
desc: &ComputePassDescriptor,
) -> Self::ComputePassId;
fn command_encoder_end_compute_pass(
&self,
encoder: &Self::CommandEncoderId,
pass: &mut Self::ComputePassId,
);
fn command_encoder_begin_render_pass<'a>(
&self,
encoder: &Self::CommandEncoderId,
desc: &RenderPassDescriptor<'a, '_>,
) -> Self::RenderPassId;
fn command_encoder_end_render_pass(
&self,
encoder: &Self::CommandEncoderId,
pass: &mut Self::RenderPassId,
);
fn command_encoder_finish(&self, encoder: Self::CommandEncoderId) -> Self::CommandBufferId;
fn command_encoder_clear_image(
&self,
encoder: &Self::CommandEncoderId,
texture: &Texture,
subresource_range: &ImageSubresourceRange,
);
fn command_encoder_clear_buffer(
&self,
encoder: &Self::CommandEncoderId,
buffer: &Buffer,
offset: BufferAddress,
size: Option<BufferSize>,
);
fn command_encoder_insert_debug_marker(&self, encoder: &Self::CommandEncoderId, label: &str);
fn command_encoder_push_debug_group(&self, encoder: &Self::CommandEncoderId, label: &str);
fn command_encoder_pop_debug_group(&self, encoder: &Self::CommandEncoderId);
fn command_encoder_write_timestamp(
&self,
encoder: &Self::CommandEncoderId,
query_set: &Self::QuerySetId,
query_index: u32,
);
fn command_encoder_resolve_query_set(
&self,
encoder: &Self::CommandEncoderId,
query_set: &Self::QuerySetId,
first_query: u32,
query_count: u32,
destination: &Self::BufferId,
destination_offset: BufferAddress,
);
fn render_bundle_encoder_finish(
&self,
encoder: Self::RenderBundleEncoderId,
desc: &RenderBundleDescriptor,
) -> Self::RenderBundleId;
fn queue_write_buffer(
&self,
queue: &Self::QueueId,
buffer: &Self::BufferId,
offset: BufferAddress,
data: &[u8],
);
fn queue_write_texture(
&self,
queue: &Self::QueueId,
texture: ImageCopyTexture,
data: &[u8],
data_layout: ImageDataLayout,
size: Extent3d,
);
fn queue_submit<I: Iterator<Item = Self::CommandBufferId>>(
&self,
queue: &Self::QueueId,
command_buffers: I,
);
fn queue_get_timestamp_period(&self, queue: &Self::QueueId) -> f32;
fn queue_on_submitted_work_done(
&self,
queue: &Self::QueueId,
) -> Self::OnSubmittedWorkDoneFuture;
fn device_start_capture(&self, device: &Self::DeviceId);
fn device_stop_capture(&self, device: &Self::DeviceId);
}
#[derive(Debug)]
pub struct Instance {
context: Arc<C>,
}
#[derive(Debug)]
pub struct Adapter {
context: Arc<C>,
id: <C as Context>::AdapterId,
}
impl Drop for Adapter {
fn drop(&mut self) {
if !thread::panicking() {
self.context.adapter_drop(&self.id)
}
}
}
#[derive(Debug)]
pub struct Device {
context: Arc<C>,
id: <C as Context>::DeviceId,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Maintain {
Wait,
Poll,
}
#[derive(Debug)]
struct MapContext {
total_size: BufferAddress,
initial_range: Range<BufferAddress>,
sub_ranges: Vec<Range<BufferAddress>>,
}
impl MapContext {
fn new(total_size: BufferAddress) -> Self {
MapContext {
total_size,
initial_range: 0..0,
sub_ranges: Vec::new(),
}
}
fn reset(&mut self) {
self.initial_range = 0..0;
assert!(
self.sub_ranges.is_empty(),
"You cannot unmap a buffer that still has accessible mapped views"
);
}
fn add(&mut self, offset: BufferAddress, size: Option<BufferSize>) -> BufferAddress {
let end = match size {
Some(s) => offset + s.get(),
None => self.initial_range.end,
};
assert!(self.initial_range.start <= offset && end <= self.initial_range.end);
for sub in self.sub_ranges.iter() {
assert!(
end <= sub.start || offset >= sub.end,
"Intersecting map range with {:?}",
sub
);
}
self.sub_ranges.push(offset..end);
end
}
fn remove(&mut self, offset: BufferAddress, size: Option<BufferSize>) {
let end = match size {
Some(s) => offset + s.get(),
None => self.initial_range.end,
};
let index = self
.sub_ranges
.iter()
.position(|r| *r == (offset..end))
.expect("unable to remove range from map context");
self.sub_ranges.swap_remove(index);
}
}
#[derive(Debug)]
pub struct Buffer {
context: Arc<C>,
id: <C as Context>::BufferId,
map_context: Mutex<MapContext>,
usage: BufferUsages,
}
#[derive(Copy, Clone, Debug)]
pub struct BufferSlice<'a> {
buffer: &'a Buffer,
offset: BufferAddress,
size: Option<BufferSize>,
}
#[derive(Debug)]
pub struct Texture {
context: Arc<C>,
id: <C as Context>::TextureId,
owned: bool,
}
#[derive(Debug)]
pub struct TextureView {
context: Arc<C>,
id: <C as Context>::TextureViewId,
}
#[derive(Debug)]
pub struct Sampler {
context: Arc<C>,
id: <C as Context>::SamplerId,
}
impl Drop for Sampler {
fn drop(&mut self) {
if !thread::panicking() {
self.context.sampler_drop(&self.id);
}
}
}
#[derive(Debug)]
pub struct Surface {
context: Arc<C>,
id: <C as Context>::SurfaceId,
}
impl Drop for Surface {
fn drop(&mut self) {
if !thread::panicking() {
self.context.surface_drop(&self.id)
}
}
}
#[derive(Debug)]
pub struct BindGroupLayout {
context: Arc<C>,
id: <C as Context>::BindGroupLayoutId,
}
impl Drop for BindGroupLayout {
fn drop(&mut self) {
if !thread::panicking() {
self.context.bind_group_layout_drop(&self.id);
}
}
}
#[derive(Debug)]
pub struct BindGroup {
context: Arc<C>,
id: <C as Context>::BindGroupId,
}
impl Drop for BindGroup {
fn drop(&mut self) {
if !thread::panicking() {
self.context.bind_group_drop(&self.id);
}
}
}
#[derive(Debug)]
pub struct ShaderModule {
context: Arc<C>,
id: <C as Context>::ShaderModuleId,
}
impl Drop for ShaderModule {
fn drop(&mut self) {
if !thread::panicking() {
self.context.shader_module_drop(&self.id);
}
}
}
pub enum ShaderSource<'a> {
#[cfg(feature = "spirv")]
SpirV(Cow<'a, [u32]>),
Wgsl(Cow<'a, str>),
}
pub struct ShaderModuleDescriptor<'a> {
pub label: Label<'a>,
pub source: ShaderSource<'a>,
}
pub struct ShaderModuleDescriptorSpirV<'a> {
pub label: Label<'a>,
pub source: Cow<'a, [u32]>,
}
#[derive(Debug)]
pub struct PipelineLayout {
context: Arc<C>,
id: <C as Context>::PipelineLayoutId,
}
impl Drop for PipelineLayout {
fn drop(&mut self) {
if !thread::panicking() {
self.context.pipeline_layout_drop(&self.id);
}
}
}
#[derive(Debug)]
pub struct RenderPipeline {
context: Arc<C>,
id: <C as Context>::RenderPipelineId,
}
impl Drop for RenderPipeline {
fn drop(&mut self) {
if !thread::panicking() {
self.context.render_pipeline_drop(&self.id);
}
}
}
impl RenderPipeline {
pub fn get_bind_group_layout(&self, index: u32) -> BindGroupLayout {
let context = Arc::clone(&self.context);
BindGroupLayout {
context,
id: self
.context
.render_pipeline_get_bind_group_layout(&self.id, index),
}
}
}
#[derive(Debug)]
pub struct ComputePipeline {
context: Arc<C>,
id: <C as Context>::ComputePipelineId,
}
impl Drop for ComputePipeline {
fn drop(&mut self) {
if !thread::panicking() {
self.context.compute_pipeline_drop(&self.id);
}
}
}
impl ComputePipeline {
pub fn get_bind_group_layout(&self, index: u32) -> BindGroupLayout {
let context = Arc::clone(&self.context);
BindGroupLayout {
context,
id: self
.context
.compute_pipeline_get_bind_group_layout(&self.id, index),
}
}
}
#[derive(Debug)]
pub struct CommandBuffer {
context: Arc<C>,
id: Option<<C as Context>::CommandBufferId>,
}
impl Drop for CommandBuffer {
fn drop(&mut self) {
if !thread::panicking() {
if let Some(ref id) = self.id {
self.context.command_buffer_drop(id);
}
}
}
}
#[derive(Debug)]
pub struct CommandEncoder {
context: Arc<C>,
id: Option<<C as Context>::CommandEncoderId>,
_p: PhantomData<*const u8>,
}
impl Drop for CommandEncoder {
fn drop(&mut self) {
if !thread::panicking() {
if let Some(id) = self.id.take() {
self.context.command_encoder_drop(&id);
}
}
}
}
#[derive(Debug)]
pub struct RenderPass<'a> {
id: <C as Context>::RenderPassId,
parent: &'a mut CommandEncoder,
}
#[derive(Debug)]
pub struct ComputePass<'a> {
id: <C as Context>::ComputePassId,
parent: &'a mut CommandEncoder,
}
#[derive(Debug)]
pub struct RenderBundleEncoder<'a> {
context: Arc<C>,
id: <C as Context>::RenderBundleEncoderId,
_parent: &'a Device,
_p: PhantomData<*const u8>,
}
#[derive(Debug)]
pub struct RenderBundle {
context: Arc<C>,
id: <C as Context>::RenderBundleId,
}
impl Drop for RenderBundle {
fn drop(&mut self) {
if !thread::panicking() {
self.context.render_bundle_drop(&self.id);
}
}
}
pub struct QuerySet {
context: Arc<C>,
id: <C as Context>::QuerySetId,
}
impl Drop for QuerySet {
fn drop(&mut self) {
if !thread::panicking() {
self.context.query_set_drop(&self.id);
}
}
}
#[derive(Debug)]
pub struct Queue {
context: Arc<C>,
id: <C as Context>::QueueId,
}
#[non_exhaustive]
#[derive(Clone, Debug)]
pub enum BindingResource<'a> {
Buffer(BufferBinding<'a>),
BufferArray(&'a [BufferBinding<'a>]),
Sampler(&'a Sampler),
TextureView(&'a TextureView),
TextureViewArray(&'a [&'a TextureView]),
}
#[derive(Clone, Debug)]
pub struct BufferBinding<'a> {
pub buffer: &'a Buffer,
pub offset: BufferAddress,
pub size: Option<BufferSize>,
}
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub enum LoadOp<V> {
Clear(V),
Load,
}
impl<V: Default> Default for LoadOp<V> {
fn default() -> Self {
Self::Clear(Default::default())
}
}
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub struct Operations<V> {
pub load: LoadOp<V>,
pub store: bool,
}
impl<V: Default> Default for Operations<V> {
fn default() -> Self {
Self {
load: Default::default(),
store: true,
}
}
}
#[derive(Clone, Debug)]
pub struct RenderPassColorAttachment<'a> {
pub view: &'a TextureView,
pub resolve_target: Option<&'a TextureView>,
pub ops: Operations<Color>,
}
#[derive(Clone, Debug)]
pub struct RenderPassDepthStencilAttachment<'a> {
pub view: &'a TextureView,
pub depth_ops: Option<Operations<f32>>,
pub stencil_ops: Option<Operations<u32>>,
}
pub type Label<'a> = Option<&'a str>;
pub use wgt::RequestAdapterOptions as RequestAdapterOptionsBase;
pub type RequestAdapterOptions<'a> = RequestAdapterOptionsBase<&'a Surface>;
pub type DeviceDescriptor<'a> = wgt::DeviceDescriptor<Label<'a>>;
pub type BufferDescriptor<'a> = wgt::BufferDescriptor<Label<'a>>;
pub type CommandEncoderDescriptor<'a> = wgt::CommandEncoderDescriptor<Label<'a>>;
pub type RenderBundleDescriptor<'a> = wgt::RenderBundleDescriptor<Label<'a>>;
pub type TextureDescriptor<'a> = wgt::TextureDescriptor<Label<'a>>;
pub type QuerySetDescriptor<'a> = wgt::QuerySetDescriptor<Label<'a>>;
#[derive(Clone, Debug, Default, PartialEq)]
pub struct TextureViewDescriptor<'a> {
pub label: Label<'a>,
pub format: Option<TextureFormat>,
pub dimension: Option<TextureViewDimension>,
pub aspect: TextureAspect,
pub base_mip_level: u32,
pub mip_level_count: Option<NonZeroU32>,
pub base_array_layer: u32,
pub array_layer_count: Option<NonZeroU32>,
}
#[derive(Clone, Debug, Default)]
pub struct PipelineLayoutDescriptor<'a> {
pub label: Label<'a>,
pub bind_group_layouts: &'a [&'a BindGroupLayout],
pub push_constant_ranges: &'a [PushConstantRange],
}
#[derive(Clone, Debug, PartialEq)]
pub struct SamplerDescriptor<'a> {
pub label: Label<'a>,
pub address_mode_u: AddressMode,
pub address_mode_v: AddressMode,
pub address_mode_w: AddressMode,
pub mag_filter: FilterMode,
pub min_filter: FilterMode,
pub mipmap_filter: FilterMode,
pub lod_min_clamp: f32,
pub lod_max_clamp: f32,
pub compare: Option<CompareFunction>,
pub anisotropy_clamp: Option<NonZeroU8>,
pub border_color: Option<SamplerBorderColor>,
}
impl Default for SamplerDescriptor<'_> {
fn default() -> Self {
Self {
label: None,
address_mode_u: Default::default(),
address_mode_v: Default::default(),
address_mode_w: Default::default(),
mag_filter: Default::default(),
min_filter: Default::default(),
mipmap_filter: Default::default(),
lod_min_clamp: 0.0,
lod_max_clamp: std::f32::MAX,
compare: None,
anisotropy_clamp: None,
border_color: None,
}
}
}
#[derive(Clone, Debug)]
pub struct BindGroupEntry<'a> {
pub binding: u32,
pub resource: BindingResource<'a>,
}
#[derive(Clone, Debug)]
pub struct BindGroupDescriptor<'a> {
pub label: Label<'a>,
pub layout: &'a BindGroupLayout,
pub entries: &'a [BindGroupEntry<'a>],
}
#[derive(Clone, Debug, Default)]
pub struct RenderPassDescriptor<'a, 'b> {
pub label: Label<'a>,
pub color_attachments: &'b [RenderPassColorAttachment<'a>],
pub depth_stencil_attachment: Option<RenderPassDepthStencilAttachment<'a>>,
}
#[derive(Clone, Debug, Hash, Eq, PartialEq)]
pub struct VertexBufferLayout<'a> {
pub array_stride: BufferAddress,
pub step_mode: VertexStepMode,
pub attributes: &'a [VertexAttribute],
}
#[derive(Clone, Debug)]
pub struct VertexState<'a> {
pub module: &'a ShaderModule,
pub entry_point: &'a str,
pub buffers: &'a [VertexBufferLayout<'a>],
}
#[derive(Clone, Debug)]
pub struct FragmentState<'a> {
pub module: &'a ShaderModule,
pub entry_point: &'a str,
pub targets: &'a [ColorTargetState],
}
#[derive(Clone, Debug)]
pub struct RenderPipelineDescriptor<'a> {
pub label: Label<'a>,
pub layout: Option<&'a PipelineLayout>,
pub vertex: VertexState<'a>,
pub primitive: PrimitiveState,
pub depth_stencil: Option<DepthStencilState>,
pub multisample: MultisampleState,
pub fragment: Option<FragmentState<'a>>,
}
#[derive(Clone, Debug, Default)]
pub struct ComputePassDescriptor<'a> {
pub label: Label<'a>,
}
#[derive(Clone, Debug)]
pub struct ComputePipelineDescriptor<'a> {
pub label: Label<'a>,
pub layout: Option<&'a PipelineLayout>,
pub module: &'a ShaderModule,
pub entry_point: &'a str,
}
pub use wgt::ImageCopyBuffer as ImageCopyBufferBase;
pub type ImageCopyBuffer<'a> = ImageCopyBufferBase<&'a Buffer>;
pub use wgt::ImageCopyTexture as ImageCopyTextureBase;
pub type ImageCopyTexture<'a> = ImageCopyTextureBase<&'a Texture>;
#[derive(Clone, Debug)]
pub struct BindGroupLayoutDescriptor<'a> {
pub label: Label<'a>,
pub entries: &'a [BindGroupLayoutEntry],
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
pub struct RenderBundleEncoderDescriptor<'a> {
pub label: Label<'a>,
pub color_formats: &'a [TextureFormat],
pub depth_stencil: Option<RenderBundleDepthStencil>,
pub sample_count: u32,
}
#[derive(Debug)]
pub struct SurfaceTexture {
pub texture: Texture,
detail: <C as Context>::SurfaceOutputDetail,
}
#[derive(Debug)]
pub struct SurfaceFrame {
pub output: SurfaceTexture,
pub suboptimal: bool,
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum SurfaceError {
Timeout,
Outdated,
Lost,
OutOfMemory,
}
impl Display for SurfaceError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", match self {
Self::Timeout => "A timeout was encountered while trying to acquire the next frame",
Self::Outdated => "The underlying surface has changed, and therefore the swap chain must be updated",
Self::Lost => "The swap chain has been lost and needs to be recreated",
Self::OutOfMemory => "There is no more memory left to allocate a new frame",
})
}
}
impl error::Error for SurfaceError {}
impl Instance {
pub fn new(backends: Backends) -> Self {
Instance {
context: Arc::new(C::init(backends)),
}
}
#[cfg(not(target_arch = "wasm32"))]
pub unsafe fn from_hal<A: wgc::hub::HalApi>(hal_instance: A::Instance) -> Self {
Instance {
context: Arc::new(C::from_hal_instance::<A>(hal_instance)),
}
}
#[cfg(not(target_arch = "wasm32"))]
pub fn enumerate_adapters(&self, backends: Backends) -> impl Iterator<Item = Adapter> {
let context = Arc::clone(&self.context);
self.context
.enumerate_adapters(backends)
.into_iter()
.map(move |id| crate::Adapter {
id,
context: Arc::clone(&context),
})
}
pub fn request_adapter(
&self,
options: &RequestAdapterOptions,
) -> impl Future<Output = Option<Adapter>> + Send {
let context = Arc::clone(&self.context);
let adapter = self.context.instance_request_adapter(options);
async move { adapter.await.map(|id| Adapter { context, id }) }
}
#[cfg(not(target_arch = "wasm32"))]
pub unsafe fn create_adapter_from_hal<A: wgc::hub::HalApi>(
&self,
hal_adapter: hal::ExposedAdapter<A>,
) -> Adapter {
let context = Arc::clone(&self.context);
let id = context.create_adapter_from_hal(hal_adapter);
Adapter { context, id }
}
pub unsafe fn create_surface<W: raw_window_handle::HasRawWindowHandle>(
&self,
window: &W,
) -> Surface {
Surface {
context: Arc::clone(&self.context),
id: Context::instance_create_surface(&*self.context, window),
}
}
pub fn poll_all(&self, force_wait: bool) {
self.context.instance_poll_all_devices(force_wait);
}
#[cfg(not(target_arch = "wasm32"))]
pub fn generate_report(&self) -> wgc::hub::GlobalReport {
self.context.generate_report()
}
}
impl Adapter {
pub fn request_device(
&self,
desc: &DeviceDescriptor,
trace_path: Option<&std::path::Path>,
) -> impl Future<Output = Result<(Device, Queue), RequestDeviceError>> + Send {
let context = Arc::clone(&self.context);
let device = Context::adapter_request_device(&*self.context, &self.id, desc, trace_path);
async move {
device.await.map(|(device_id, queue_id)| {
(
Device {
context: Arc::clone(&context),
id: device_id,
},
Queue {
context,
id: queue_id,
},
)
})
}
}
#[cfg(not(target_arch = "wasm32"))]
pub unsafe fn create_device_from_hal<A: wgc::hub::HalApi>(
&self,
hal_device: hal::OpenDevice<A>,
desc: &DeviceDescriptor,
trace_path: Option<&std::path::Path>,
) -> Result<(Device, Queue), RequestDeviceError> {
let context = Arc::clone(&self.context);
self.context
.create_device_from_hal(&self.id, hal_device, desc, trace_path)
.map(|(device_id, queue_id)| {
(
Device {
context: Arc::clone(&context),
id: device_id,
},
Queue {
context,
id: queue_id,
},
)
})
}
pub fn is_surface_supported(&self, surface: &Surface) -> bool {
Context::adapter_is_surface_supported(&*self.context, &self.id, &surface.id)
}
pub fn features(&self) -> Features {
Context::adapter_features(&*self.context, &self.id)
}
pub fn limits(&self) -> Limits {
Context::adapter_limits(&*self.context, &self.id)
}
pub fn get_info(&self) -> AdapterInfo {
Context::adapter_get_info(&*self.context, &self.id)
}
pub fn get_downlevel_properties(&self) -> DownlevelCapabilities {
Context::adapter_downlevel_properties(&*self.context, &self.id)
}
pub fn get_texture_format_features(&self, format: TextureFormat) -> TextureFormatFeatures {
Context::adapter_get_texture_format_features(&*self.context, &self.id, format)
}
}
impl Device {
pub fn poll(&self, maintain: Maintain) {
Context::device_poll(&*self.context, &self.id, maintain);
}
pub fn features(&self) -> Features {
Context::device_features(&*self.context, &self.id)
}
pub fn limits(&self) -> Limits {
Context::device_limits(&*self.context, &self.id)
}
pub fn create_shader_module(&self, desc: &ShaderModuleDescriptor) -> ShaderModule {
ShaderModule {
context: Arc::clone(&self.context),
id: Context::device_create_shader_module(&*self.context, &self.id, desc),
}
}
pub unsafe fn create_shader_module_spirv(
&self,
desc: &ShaderModuleDescriptorSpirV,
) -> ShaderModule {
ShaderModule {
context: Arc::clone(&self.context),
id: Context::device_create_shader_module_spirv(&*self.context, &self.id, desc),
}
}
pub fn create_command_encoder(&self, desc: &CommandEncoderDescriptor) -> CommandEncoder {
CommandEncoder {
context: Arc::clone(&self.context),
id: Some(Context::device_create_command_encoder(
&*self.context,
&self.id,
desc,
)),
_p: Default::default(),
}
}
pub fn create_render_bundle_encoder(
&self,
desc: &RenderBundleEncoderDescriptor,
) -> RenderBundleEncoder {
RenderBundleEncoder {
context: Arc::clone(&self.context),
id: Context::device_create_render_bundle_encoder(&*self.context, &self.id, desc),
_parent: self,
_p: Default::default(),
}
}
pub fn create_bind_group(&self, desc: &BindGroupDescriptor) -> BindGroup {
BindGroup {
context: Arc::clone(&self.context),
id: Context::device_create_bind_group(&*self.context, &self.id, desc),
}
}
pub fn create_bind_group_layout(&self, desc: &BindGroupLayoutDescriptor) -> BindGroupLayout {
BindGroupLayout {
context: Arc::clone(&self.context),
id: Context::device_create_bind_group_layout(&*self.context, &self.id, desc),
}
}
pub fn create_pipeline_layout(&self, desc: &PipelineLayoutDescriptor) -> PipelineLayout {
PipelineLayout {
context: Arc::clone(&self.context),
id: Context::device_create_pipeline_layout(&*self.context, &self.id, desc),
}
}
pub fn create_render_pipeline(&self, desc: &RenderPipelineDescriptor) -> RenderPipeline {
RenderPipeline {
context: Arc::clone(&self.context),
id: Context::device_create_render_pipeline(&*self.context, &self.id, desc),
}
}
pub fn create_compute_pipeline(&self, desc: &ComputePipelineDescriptor) -> ComputePipeline {
ComputePipeline {
context: Arc::clone(&self.context),
id: Context::device_create_compute_pipeline(&*self.context, &self.id, desc),
}
}
pub fn create_buffer(&self, desc: &BufferDescriptor) -> Buffer {
let mut map_context = MapContext::new(desc.size);
if desc.mapped_at_creation {
map_context.initial_range = 0..desc.size;
}
Buffer {
context: Arc::clone(&self.context),
id: Context::device_create_buffer(&*self.context, &self.id, desc),
map_context: Mutex::new(map_context),
usage: desc.usage,
}
}
pub fn create_texture(&self, desc: &TextureDescriptor) -> Texture {
Texture {
context: Arc::clone(&self.context),
id: Context::device_create_texture(&*self.context, &self.id, desc),
owned: true,
}
}
#[cfg(not(target_arch = "wasm32"))]
pub unsafe fn create_texture_from_hal<A: wgc::hub::HalApi>(
&self,
hal_texture: A::Texture,
desc: &TextureDescriptor,
) -> Texture {
Texture {
context: Arc::clone(&self.context),
id: self
.context
.create_texture_from_hal::<A>(hal_texture, &self.id, desc),
owned: true,
}
}
pub fn create_sampler(&self, desc: &SamplerDescriptor) -> Sampler {
Sampler {
context: Arc::clone(&self.context),
id: Context::device_create_sampler(&*self.context, &self.id, desc),
}
}
pub fn create_query_set(&self, desc: &QuerySetDescriptor) -> QuerySet {
QuerySet {
context: Arc::clone(&self.context),
id: Context::device_create_query_set(&*self.context, &self.id, desc),
}
}
pub fn on_uncaptured_error(&self, handler: impl UncapturedErrorHandler) {
self.context.device_on_uncaptured_error(&self.id, handler);
}
pub fn start_capture(&self) {
Context::device_start_capture(&*self.context, &self.id)
}
pub fn stop_capture(&self) {
Context::device_stop_capture(&*self.context, &self.id)
}
}
impl Drop for Device {
fn drop(&mut self) {
if !thread::panicking() {
self.context.device_drop(&self.id);
}
}
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct RequestDeviceError;
impl Display for RequestDeviceError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Requesting a device failed")
}
}
impl error::Error for RequestDeviceError {}
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct BufferAsyncError;
impl Display for BufferAsyncError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Error occurred when trying to async map a buffer")
}
}
impl error::Error for BufferAsyncError {}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum MapMode {
Read,
Write,
}
fn range_to_offset_size<S: RangeBounds<BufferAddress>>(
bounds: S,
) -> (BufferAddress, Option<BufferSize>) {
let offset = match bounds.start_bound() {
Bound::Included(&bound) => bound,
Bound::Excluded(&bound) => bound + 1,
Bound::Unbounded => 0,
};
let size = match bounds.end_bound() {
Bound::Included(&bound) => Some(bound + 1 - offset),
Bound::Excluded(&bound) => Some(bound - offset),
Bound::Unbounded => None,
}
.map(|size| BufferSize::new(size).expect("Buffer slices can not be empty"));
(offset, size)
}
#[cfg(test)]
mod tests {
use crate::BufferSize;
#[test]
fn range_to_offset_size_works() {
assert_eq!(crate::range_to_offset_size(0..2), (0, BufferSize::new(2)));
assert_eq!(crate::range_to_offset_size(2..5), (2, BufferSize::new(3)));
assert_eq!(crate::range_to_offset_size(..), (0, None));
assert_eq!(crate::range_to_offset_size(21..), (21, None));
assert_eq!(crate::range_to_offset_size(0..), (0, None));
assert_eq!(crate::range_to_offset_size(..21), (0, BufferSize::new(21)));
}
#[test]
#[should_panic]
fn range_to_offset_size_panics_for_empty_range() {
crate::range_to_offset_size(123..123);
}
#[test]
#[should_panic]
fn range_to_offset_size_panics_for_unbounded_empty_range() {
crate::range_to_offset_size(..0);
}
}
trait BufferMappedRangeSlice {
fn slice(&self) -> &[u8];
fn slice_mut(&mut self) -> &mut [u8];
}
#[derive(Debug)]
pub struct BufferView<'a> {
slice: BufferSlice<'a>,
data: BufferMappedRange,
}
#[derive(Debug)]
pub struct BufferViewMut<'a> {
slice: BufferSlice<'a>,
data: BufferMappedRange,
readable: bool,
}
impl std::ops::Deref for BufferView<'_> {
type Target = [u8];
fn deref(&self) -> &[u8] {
self.data.slice()
}
}
impl std::ops::Deref for BufferViewMut<'_> {
type Target = [u8];
fn deref(&self) -> &[u8] {
assert!(
self.readable,
"Attempting to read a write-only mapping for buffer {:?}",
self.slice.buffer.id
);
self.data.slice()
}
}
impl std::ops::DerefMut for BufferViewMut<'_> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.data.slice_mut()
}
}
impl AsRef<[u8]> for BufferView<'_> {
fn as_ref(&self) -> &[u8] {
self.data.slice()
}
}
impl AsMut<[u8]> for BufferViewMut<'_> {
fn as_mut(&mut self) -> &mut [u8] {
self.data.slice_mut()
}
}
impl Drop for BufferView<'_> {
fn drop(&mut self) {
self.slice
.buffer
.map_context
.lock()
.remove(self.slice.offset, self.slice.size);
}
}
impl Drop for BufferViewMut<'_> {
fn drop(&mut self) {
self.slice
.buffer
.map_context
.lock()
.remove(self.slice.offset, self.slice.size);
}
}
impl Buffer {
pub fn as_entire_binding(&self) -> BindingResource {
BindingResource::Buffer(self.as_entire_buffer_binding())
}
pub fn as_entire_buffer_binding(&self) -> BufferBinding {
BufferBinding {
buffer: self,
offset: 0,
size: None,
}
}
pub fn slice<S: RangeBounds<BufferAddress>>(&self, bounds: S) -> BufferSlice {
let (offset, size) = range_to_offset_size(bounds);
BufferSlice {
buffer: self,
offset,
size,
}
}
pub fn unmap(&self) {
self.map_context.lock().reset();
Context::buffer_unmap(&*self.context, &self.id);
}
pub fn destroy(&self) {
Context::buffer_destroy(&*self.context, &self.id);
}
}
impl<'a> BufferSlice<'a> {
pub fn map_async(
&self,
mode: MapMode,
) -> impl Future<Output = Result<(), BufferAsyncError>> + Send {
let mut mc = self.buffer.map_context.lock();
assert_eq!(
mc.initial_range,
0..0,
"Buffer {:?} is already mapped",
self.buffer.id
);
let end = match self.size {
Some(s) => self.offset + s.get(),
None => mc.total_size,
};
mc.initial_range = self.offset..end;
Context::buffer_map_async(
&*self.buffer.context,
&self.buffer.id,
mode,
self.offset..end,
)
}
pub fn get_mapped_range(&self) -> BufferView<'a> {
let end = self.buffer.map_context.lock().add(self.offset, self.size);
let data = Context::buffer_get_mapped_range(
&*self.buffer.context,
&self.buffer.id,
self.offset..end,
);
BufferView { slice: *self, data }
}
pub fn get_mapped_range_mut(&self) -> BufferViewMut<'a> {
let end = self.buffer.map_context.lock().add(self.offset, self.size);
let data = Context::buffer_get_mapped_range(
&*self.buffer.context,
&self.buffer.id,
self.offset..end,
);
BufferViewMut {
slice: *self,
data,
readable: self.buffer.usage.contains(BufferUsages::MAP_READ),
}
}
}
impl Drop for Buffer {
fn drop(&mut self) {
if !thread::panicking() {
self.context.buffer_drop(&self.id);
}
}
}
impl Texture {
pub fn create_view(&self, desc: &TextureViewDescriptor) -> TextureView {
TextureView {
context: Arc::clone(&self.context),
id: Context::texture_create_view(&*self.context, &self.id, desc),
}
}
pub fn destroy(&self) {
Context::texture_destroy(&*self.context, &self.id);
}
pub fn as_image_copy(&self) -> ImageCopyTexture {
ImageCopyTexture {
texture: self,
mip_level: 0,
origin: Origin3d::ZERO,
aspect: TextureAspect::All,
}
}
}
impl Drop for Texture {
fn drop(&mut self) {
if self.owned && !thread::panicking() {
self.context.texture_drop(&self.id);
}
}
}
impl Drop for TextureView {
fn drop(&mut self) {
if !thread::panicking() {
self.context.texture_view_drop(&self.id);
}
}
}
impl CommandEncoder {
pub fn finish(mut self) -> CommandBuffer {
CommandBuffer {
context: Arc::clone(&self.context),
id: Some(Context::command_encoder_finish(
&*self.context,
self.id.take().unwrap(),
)),
}
}
pub fn begin_render_pass<'a>(
&'a mut self,
desc: &RenderPassDescriptor<'a, '_>,
) -> RenderPass<'a> {
let id = self.id.as_ref().unwrap();
RenderPass {
id: Context::command_encoder_begin_render_pass(&*self.context, id, desc),
parent: self,
}
}
pub fn begin_compute_pass(&mut self, desc: &ComputePassDescriptor) -> ComputePass {
let id = self.id.as_ref().unwrap();
ComputePass {
id: Context::command_encoder_begin_compute_pass(&*self.context, id, desc),
parent: self,
}
}
pub fn copy_buffer_to_buffer(
&mut self,
source: &Buffer,
source_offset: BufferAddress,
destination: &Buffer,
destination_offset: BufferAddress,
copy_size: BufferAddress,
) {
Context::command_encoder_copy_buffer_to_buffer(
&*self.context,
self.id.as_ref().unwrap(),
&source.id,
source_offset,
&destination.id,
destination_offset,
copy_size,
);
}
pub fn copy_buffer_to_texture(
&mut self,
source: ImageCopyBuffer,
destination: ImageCopyTexture,
copy_size: Extent3d,
) {
Context::command_encoder_copy_buffer_to_texture(
&*self.context,
self.id.as_ref().unwrap(),
source,
destination,
copy_size,
);
}
pub fn copy_texture_to_buffer(
&mut self,
source: ImageCopyTexture,
destination: ImageCopyBuffer,
copy_size: Extent3d,
) {
Context::command_encoder_copy_texture_to_buffer(
&*self.context,
self.id.as_ref().unwrap(),
source,
destination,
copy_size,
);
}
pub fn copy_texture_to_texture(
&mut self,
source: ImageCopyTexture,
destination: ImageCopyTexture,
copy_size: Extent3d,
) {
Context::command_encoder_copy_texture_to_texture(
&*self.context,
self.id.as_ref().unwrap(),
source,
destination,
copy_size,
);
}
pub fn clear_texture(&mut self, texture: &Texture, subresource_range: &ImageSubresourceRange) {
Context::command_encoder_clear_image(
&*self.context,
self.id.as_ref().unwrap(),
texture,
subresource_range,
);
}
pub fn clear_buffer(
&mut self,
buffer: &Buffer,
offset: BufferAddress,
size: Option<BufferSize>,
) {
Context::command_encoder_clear_buffer(
&*self.context,
self.id.as_ref().unwrap(),
buffer,
offset,
size,
);
}
pub fn insert_debug_marker(&mut self, label: &str) {
let id = self.id.as_ref().unwrap();
Context::command_encoder_insert_debug_marker(&*self.context, id, label);
}
pub fn push_debug_group(&mut self, label: &str) {
let id = self.id.as_ref().unwrap();
Context::command_encoder_push_debug_group(&*self.context, id, label);
}
pub fn pop_debug_group(&mut self) {
let id = self.id.as_ref().unwrap();
Context::command_encoder_pop_debug_group(&*self.context, id);
}
}
impl CommandEncoder {
pub fn write_timestamp(&mut self, query_set: &QuerySet, query_index: u32) {
Context::command_encoder_write_timestamp(
&*self.context,
self.id.as_ref().unwrap(),
&query_set.id,
query_index,
)
}
}
impl CommandEncoder {
pub fn resolve_query_set(
&mut self,
query_set: &QuerySet,
query_range: Range<u32>,
destination: &Buffer,
destination_offset: BufferAddress,
) {
Context::command_encoder_resolve_query_set(
&*self.context,
self.id.as_ref().unwrap(),
&query_set.id,
query_range.start,
query_range.end - query_range.start,
&destination.id,
destination_offset,
)
}
}
impl<'a> RenderPass<'a> {
pub fn set_bind_group(
&mut self,
index: u32,
bind_group: &'a BindGroup,
offsets: &[DynamicOffset],
) {
RenderInner::set_bind_group(&mut self.id, index, &bind_group.id, offsets)
}
pub fn set_pipeline(&mut self, pipeline: &'a RenderPipeline) {
RenderInner::set_pipeline(&mut self.id, &pipeline.id)
}
pub fn set_blend_constant(&mut self, color: Color) {
self.id.set_blend_constant(color)
}
pub fn set_index_buffer(&mut self, buffer_slice: BufferSlice<'a>, index_format: IndexFormat) {
RenderInner::set_index_buffer(
&mut self.id,
&buffer_slice.buffer.id,
index_format,
buffer_slice.offset,
buffer_slice.size,
)
}
pub fn set_vertex_buffer(&mut self, slot: u32, buffer_slice: BufferSlice<'a>) {
RenderInner::set_vertex_buffer(
&mut self.id,
slot,
&buffer_slice.buffer.id,
buffer_slice.offset,
buffer_slice.size,
)
}
pub fn set_scissor_rect(&mut self, x: u32, y: u32, width: u32, height: u32) {
self.id.set_scissor_rect(x, y, width, height);
}
pub fn set_viewport(&mut self, x: f32, y: f32, w: f32, h: f32, min_depth: f32, max_depth: f32) {
self.id.set_viewport(x, y, w, h, min_depth, max_depth);
}
pub fn set_stencil_reference(&mut self, reference: u32) {
self.id.set_stencil_reference(reference);
}
pub fn draw(&mut self, vertices: Range<u32>, instances: Range<u32>) {
RenderInner::draw(&mut self.id, vertices, instances)
}
pub fn insert_debug_marker(&mut self, label: &str) {
self.id.insert_debug_marker(label);
}
pub fn push_debug_group(&mut self, label: &str) {
self.id.push_debug_group(label);
}
pub fn pop_debug_group(&mut self) {
self.id.pop_debug_group();
}
pub fn draw_indexed(&mut self, indices: Range<u32>, base_vertex: i32, instances: Range<u32>) {
RenderInner::draw_indexed(&mut self.id, indices, base_vertex, instances);
}
pub fn draw_indirect(&mut self, indirect_buffer: &'a Buffer, indirect_offset: BufferAddress) {
self.id.draw_indirect(&indirect_buffer.id, indirect_offset);
}
pub fn draw_indexed_indirect(
&mut self,
indirect_buffer: &'a Buffer,
indirect_offset: BufferAddress,
) {
self.id
.draw_indexed_indirect(&indirect_buffer.id, indirect_offset);
}
pub fn execute_bundles<I: Iterator<Item = &'a RenderBundle>>(&mut self, render_bundles: I) {
self.id
.execute_bundles(render_bundles.into_iter().map(|rb| &rb.id))
}
}
impl<'a> RenderPass<'a> {
pub fn multi_draw_indirect(
&mut self,
indirect_buffer: &'a Buffer,
indirect_offset: BufferAddress,
count: u32,
) {
self.id
.multi_draw_indirect(&indirect_buffer.id, indirect_offset, count);
}
pub fn multi_draw_indexed_indirect(
&mut self,
indirect_buffer: &'a Buffer,
indirect_offset: BufferAddress,
count: u32,
) {
self.id
.multi_draw_indexed_indirect(&indirect_buffer.id, indirect_offset, count);
}
}
impl<'a> RenderPass<'a> {
pub fn multi_draw_indirect_count(
&mut self,
indirect_buffer: &'a Buffer,
indirect_offset: BufferAddress,
count_buffer: &'a Buffer,
count_offset: BufferAddress,
max_count: u32,
) {
self.id.multi_draw_indirect_count(
&indirect_buffer.id,
indirect_offset,
&count_buffer.id,
count_offset,
max_count,
);
}
pub fn multi_draw_indexed_indirect_count(
&mut self,
indirect_buffer: &'a Buffer,
indirect_offset: BufferAddress,
count_buffer: &'a Buffer,
count_offset: BufferAddress,
max_count: u32,
) {
self.id.multi_draw_indexed_indirect_count(
&indirect_buffer.id,
indirect_offset,
&count_buffer.id,
count_offset,
max_count,
);
}
}
impl<'a> RenderPass<'a> {
pub fn set_push_constants(&mut self, stages: ShaderStages, offset: u32, data: &[u8]) {
self.id.set_push_constants(stages, offset, data);
}
}
impl<'a> RenderPass<'a> {
pub fn write_timestamp(&mut self, query_set: &QuerySet, query_index: u32) {
self.id.write_timestamp(&query_set.id, query_index)
}
}
impl<'a> RenderPass<'a> {
pub fn begin_pipeline_statistics_query(&mut self, query_set: &QuerySet, query_index: u32) {
self.id
.begin_pipeline_statistics_query(&query_set.id, query_index);
}
pub fn end_pipeline_statistics_query(&mut self) {
self.id.end_pipeline_statistics_query();
}
}
impl<'a> Drop for RenderPass<'a> {
fn drop(&mut self) {
if !thread::panicking() {
let parent_id = self.parent.id.as_ref().unwrap();
self.parent
.context
.command_encoder_end_render_pass(parent_id, &mut self.id);
}
}
}
impl<'a> ComputePass<'a> {
pub fn set_bind_group(
&mut self,
index: u32,
bind_group: &'a BindGroup,
offsets: &[DynamicOffset],
) {
ComputePassInner::set_bind_group(&mut self.id, index, &bind_group.id, offsets);
}
pub fn set_pipeline(&mut self, pipeline: &'a ComputePipeline) {
ComputePassInner::set_pipeline(&mut self.id, &pipeline.id);
}
pub fn insert_debug_marker(&mut self, label: &str) {
self.id.insert_debug_marker(label);
}
pub fn push_debug_group(&mut self, label: &str) {
self.id.push_debug_group(label);
}
pub fn pop_debug_group(&mut self) {
self.id.pop_debug_group();
}
pub fn dispatch(&mut self, x: u32, y: u32, z: u32) {
ComputePassInner::dispatch(&mut self.id, x, y, z);
}
pub fn dispatch_indirect(
&mut self,
indirect_buffer: &'a Buffer,
indirect_offset: BufferAddress,
) {
ComputePassInner::dispatch_indirect(&mut self.id, &indirect_buffer.id, indirect_offset);
}
}
impl<'a> ComputePass<'a> {
pub fn set_push_constants(&mut self, offset: u32, data: &[u8]) {
self.id.set_push_constants(offset, data);
}
}
impl<'a> ComputePass<'a> {
pub fn write_timestamp(&mut self, query_set: &QuerySet, query_index: u32) {
self.id.write_timestamp(&query_set.id, query_index)
}
}
impl<'a> ComputePass<'a> {
pub fn begin_pipeline_statistics_query(&mut self, query_set: &QuerySet, query_index: u32) {
self.id
.begin_pipeline_statistics_query(&query_set.id, query_index);
}
pub fn end_pipeline_statistics_query(&mut self) {
self.id.end_pipeline_statistics_query();
}
}
impl<'a> Drop for ComputePass<'a> {
fn drop(&mut self) {
if !thread::panicking() {
let parent_id = self.parent.id.as_ref().unwrap();
self.parent
.context
.command_encoder_end_compute_pass(parent_id, &mut self.id);
}
}
}
impl<'a> RenderBundleEncoder<'a> {
pub fn finish(self, desc: &RenderBundleDescriptor) -> RenderBundle {
RenderBundle {
context: Arc::clone(&self.context),
id: Context::render_bundle_encoder_finish(&*self.context, self.id, desc),
}
}
pub fn set_bind_group(
&mut self,
index: u32,
bind_group: &'a BindGroup,
offsets: &[DynamicOffset],
) {
RenderInner::set_bind_group(&mut self.id, index, &bind_group.id, offsets)
}
pub fn set_pipeline(&mut self, pipeline: &'a RenderPipeline) {
RenderInner::set_pipeline(&mut self.id, &pipeline.id)
}
pub fn set_index_buffer(&mut self, buffer_slice: BufferSlice<'a>, index_format: IndexFormat) {
RenderInner::set_index_buffer(
&mut self.id,
&buffer_slice.buffer.id,
index_format,
buffer_slice.offset,
buffer_slice.size,
)
}
pub fn set_vertex_buffer(&mut self, slot: u32, buffer_slice: BufferSlice<'a>) {
RenderInner::set_vertex_buffer(
&mut self.id,
slot,
&buffer_slice.buffer.id,
buffer_slice.offset,
buffer_slice.size,
)
}
pub fn draw(&mut self, vertices: Range<u32>, instances: Range<u32>) {
RenderInner::draw(&mut self.id, vertices, instances)
}
pub fn draw_indexed(&mut self, indices: Range<u32>, base_vertex: i32, instances: Range<u32>) {
RenderInner::draw_indexed(&mut self.id, indices, base_vertex, instances);
}
pub fn draw_indirect(&mut self, indirect_buffer: &'a Buffer, indirect_offset: BufferAddress) {
self.id.draw_indirect(&indirect_buffer.id, indirect_offset);
}
pub fn draw_indexed_indirect(
&mut self,
indirect_buffer: &'a Buffer,
indirect_offset: BufferAddress,
) {
self.id
.draw_indexed_indirect(&indirect_buffer.id, indirect_offset);
}
}
impl<'a> RenderBundleEncoder<'a> {
pub fn set_push_constants(&mut self, stages: ShaderStages, offset: u32, data: &[u8]) {
self.id.set_push_constants(stages, offset, data);
}
}
impl Queue {
pub fn write_buffer(&self, buffer: &Buffer, offset: BufferAddress, data: &[u8]) {
Context::queue_write_buffer(&*self.context, &self.id, &buffer.id, offset, data)
}
pub fn write_texture(
&self,
texture: ImageCopyTexture,
data: &[u8],
data_layout: ImageDataLayout,
size: Extent3d,
) {
Context::queue_write_texture(&*self.context, &self.id, texture, data, data_layout, size)
}
pub fn submit<I: IntoIterator<Item = CommandBuffer>>(&self, command_buffers: I) {
Context::queue_submit(
&*self.context,
&self.id,
command_buffers
.into_iter()
.map(|mut comb| comb.id.take().unwrap()),
);
}
pub fn get_timestamp_period(&self) -> f32 {
Context::queue_get_timestamp_period(&*self.context, &self.id)
}
pub fn on_submitted_work_done(&self) -> impl Future<Output = ()> + Send {
Context::queue_on_submitted_work_done(&*self.context, &self.id)
}
}
impl Drop for SurfaceTexture {
fn drop(&mut self) {
if !thread::panicking() {
Context::surface_present(&*self.texture.context, &self.texture.id, &self.detail);
}
}
}
impl Surface {
pub fn get_preferred_format(&self, adapter: &Adapter) -> Option<TextureFormat> {
Context::surface_get_preferred_format(&*self.context, &self.id, &adapter.id)
}
pub fn configure(&self, device: &Device, config: &SurfaceConfiguration) {
Context::surface_configure(&*self.context, &self.id, &device.id, config)
}
pub fn get_current_frame(&self) -> Result<SurfaceFrame, SurfaceError> {
let (texture_id, status, detail) =
Context::surface_get_current_texture(&*self.context, &self.id);
let output = texture_id.map(|id| SurfaceTexture {
texture: Texture {
context: Arc::clone(&self.context),
id,
owned: false,
},
detail,
});
match status {
SurfaceStatus::Good => Ok(SurfaceFrame {
output: output.unwrap(),
suboptimal: false,
}),
SurfaceStatus::Suboptimal => Ok(SurfaceFrame {
output: output.unwrap(),
suboptimal: true,
}),
SurfaceStatus::Timeout => Err(SurfaceError::Timeout),
SurfaceStatus::Outdated => Err(SurfaceError::Outdated),
SurfaceStatus::Lost => Err(SurfaceError::Lost),
}
}
}
pub trait UncapturedErrorHandler: Fn(Error) + Send + 'static {}
impl<T> UncapturedErrorHandler for T where T: Fn(Error) + Send + 'static {}
#[derive(Debug)]
pub enum Error {
OutOfMemoryError {
source: Box<dyn error::Error + Send + 'static>,
},
ValidationError {
source: Box<dyn error::Error + Send + 'static>,
description: String,
},
}
impl error::Error for Error {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match self {
Error::OutOfMemoryError { source } => Some(source.as_ref()),
Error::ValidationError { source, .. } => Some(source.as_ref()),
}
}
}
impl Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Error::OutOfMemoryError { .. } => f.write_str("Out of Memory"),
Error::ValidationError { description, .. } => f.write_str(description),
}
}
}