#![doc(html_logo_url = "https://raw.githubusercontent.com/gfx-rs/wgpu-rs/master/logo.png")]
mod backend;
pub mod util;
#[macro_use]
mod macros;
use std::{
future::Future,
marker::PhantomData,
ops::{Bound, Range, RangeBounds},
sync::Arc,
thread,
};
use futures::FutureExt as _;
use parking_lot::Mutex;
#[cfg(not(target_arch = "wasm32"))]
pub use wgc::instance::{AdapterInfo, DeviceType};
pub use wgt::{
AddressMode, Backend, BackendBit, BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingType,
BlendDescriptor, BlendFactor, BlendOperation, BufferAddress, BufferSize, BufferUsage,
Capabilities, Color, ColorStateDescriptor, ColorWrite, CommandBufferDescriptor,
CompareFunction, CullMode, DepthStencilStateDescriptor, DeviceDescriptor, DynamicOffset,
Extensions, Extent3d, FilterMode, FrontFace, IndexFormat, InputStepMode, Limits, LoadOp,
NonZeroBufferAddress, Origin3d, PowerPreference, PresentMode, PrimitiveTopology,
RasterizationStateDescriptor, RenderBundleEncoderDescriptor, ShaderLocation, ShaderStage,
StencilOperation, StencilStateFaceDescriptor, StoreOp, SwapChainDescriptor, SwapChainStatus,
TextureAspect, TextureComponentType, TextureDataLayout, TextureDimension, TextureFormat,
TextureUsage, TextureViewDimension, UnsafeExtensions, VertexAttributeDescriptor, VertexFormat,
BIND_BUFFER_ALIGNMENT, COPY_BUFFER_ALIGNMENT, COPY_BYTES_PER_ROW_ALIGNMENT,
};
use backend::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 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, offset: BufferAddress, size: BufferSize);
fn set_vertex_buffer(
&mut self,
slot: u32,
buffer: &Ctx::BufferId,
offset: BufferAddress,
size: BufferSize,
);
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,
);
}
trait RenderPassInner<Ctx: Context>: RenderInner<Ctx> {
fn set_blend_color(&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 execute_bundles<'a, I: Iterator<Item = &'a Ctx::RenderBundleId>>(
&mut self,
render_bundles: I,
);
}
trait Context: Sized {
type AdapterId: Send + Sync + 'static;
type DeviceId: Send + Sync + 'static;
type QueueId: Send + Sync + 'static;
type ShaderModuleId: Send + Sync + 'static;
type BindGroupLayoutId: Send + Sync + 'static;
type BindGroupId: Send + Sync + 'static;
type TextureViewId: Send + Sync + 'static;
type SamplerId: Send + Sync + 'static;
type BufferId: Send + Sync + 'static;
type TextureId: Send + Sync + 'static;
type PipelineLayoutId: Send + Sync + 'static;
type RenderPipelineId: Send + Sync + 'static;
type ComputePipelineId: Send + Sync + 'static;
type CommandEncoderId;
type ComputePassId: ComputePassInner<Self>;
type RenderPassId: RenderPassInner<Self>;
type CommandBufferId: Send + Sync;
type RenderBundleEncoderId: RenderInner<Self>;
type RenderBundleId: Send + Sync + 'static;
type SurfaceId: Send + Sync + 'static;
type SwapChainId: Send + Sync + 'static;
type SwapChainOutputDetail: 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;
fn init() -> Self;
fn instance_create_surface(
&self,
handle: &impl raw_window_handle::HasRawWindowHandle,
) -> Self::SurfaceId;
fn instance_request_adapter(
&self,
options: &RequestAdapterOptions<'_>,
unsafe_extensions: UnsafeExtensions,
backends: BackendBit,
) -> Self::RequestAdapterFuture;
fn adapter_request_device(
&self,
adapter: &Self::AdapterId,
desc: &DeviceDescriptor,
trace_dir: Option<&std::path::Path>,
) -> Self::RequestDeviceFuture;
fn adapter_extensions(&self, adapter: &Self::AdapterId) -> Extensions;
fn adapter_limits(&self, adapter: &Self::AdapterId) -> Limits;
fn adapter_capabilities(&self, adapter: &Self::AdapterId) -> Capabilities;
fn device_extensions(&self, device: &Self::DeviceId) -> Extensions;
fn device_limits(&self, device: &Self::DeviceId) -> Limits;
fn device_capabilities(&self, device: &Self::DeviceId) -> Capabilities;
fn device_create_swap_chain(
&self,
device: &Self::DeviceId,
surface: &Self::SurfaceId,
desc: &SwapChainDescriptor,
) -> Self::SwapChainId;
fn device_create_shader_module(
&self,
device: &Self::DeviceId,
source: ShaderModuleSource,
) -> 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_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 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>,
) -> &[u8];
fn buffer_get_mapped_range_mut(
&self,
buffer: &Self::BufferId,
sub_range: Range<BufferAddress>,
) -> &mut [u8];
fn buffer_unmap(&self, buffer: &Self::BufferId);
fn swap_chain_get_next_texture(
&self,
swap_chain: &Self::SwapChainId,
) -> (
Option<Self::TextureViewId>,
SwapChainStatus,
Self::SwapChainOutputDetail,
);
fn swap_chain_present(&self, view: &Self::TextureViewId, detail: &Self::SwapChainOutputDetail);
fn texture_create_view(
&self,
texture: &Self::TextureId,
desc: Option<&TextureViewDescriptor>,
) -> Self::TextureViewId;
fn texture_drop(&self, texture: &Self::TextureId);
fn texture_view_drop(&self, texture_view: &Self::TextureViewId);
fn sampler_drop(&self, sampler: &Self::SamplerId);
fn buffer_drop(&self, buffer: &Self::BufferId);
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_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 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: BufferCopyView,
destination: TextureCopyView,
copy_size: Extent3d,
);
fn command_encoder_copy_texture_to_buffer(
&self,
encoder: &Self::CommandEncoderId,
source: TextureCopyView,
destination: BufferCopyView,
copy_size: Extent3d,
);
fn command_encoder_copy_texture_to_texture(
&self,
encoder: &Self::CommandEncoderId,
source: TextureCopyView,
destination: TextureCopyView,
copy_size: Extent3d,
);
fn command_encoder_begin_compute_pass(
&self,
encoder: &Self::CommandEncoderId,
) -> 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 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: TextureCopyView,
data: &[u8],
data_layout: TextureDataLayout,
size: Extent3d,
);
fn queue_submit<I: Iterator<Item = Self::CommandBufferId>>(
&self,
queue: &Self::QueueId,
command_buffers: I,
);
}
pub struct Instance {
context: Arc<C>,
}
pub struct Adapter {
context: Arc<C>,
id: <C as Context>::AdapterId,
}
#[derive(Clone)]
pub struct RequestAdapterOptions<'a> {
pub power_preference: PowerPreference,
pub compatible_surface: Option<&'a Surface>,
}
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: BufferSize) -> BufferAddress {
let end = if size == BufferSize::WHOLE {
self.initial_range.end
} else {
offset + size.0
};
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: BufferSize) {
let end = if size == BufferSize::WHOLE {
self.initial_range.end
} else {
offset + size.0
};
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);
}
}
pub struct Buffer {
context: Arc<C>,
id: <C as Context>::BufferId,
map_context: Mutex<MapContext>,
usage: BufferUsage,
}
#[derive(Copy, Clone)]
pub struct BufferSlice<'a> {
buffer: &'a Buffer,
offset: BufferAddress,
size: BufferSize,
}
pub struct Texture {
context: Arc<C>,
id: <C as Context>::TextureId,
owned: bool,
}
pub struct TextureView {
context: Arc<C>,
id: <C as Context>::TextureViewId,
owned: bool,
}
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);
}
}
}
pub struct Surface {
id: <C as Context>::SurfaceId,
}
pub struct SwapChain {
context: Arc<C>,
id: <C as Context>::SwapChainId,
}
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);
}
}
}
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);
}
}
}
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 ShaderModuleSource<'a> {
SpirV(&'a [u32]),
Wgsl(&'a str),
}
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);
}
}
}
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);
}
}
}
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);
}
}
}
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);
}
}
}
}
pub struct CommandEncoder {
context: Arc<C>,
id: <C as Context>::CommandEncoderId,
_p: PhantomData<*const u8>,
}
pub struct RenderPass<'a> {
id: <C as Context>::RenderPassId,
parent: &'a mut CommandEncoder,
}
pub struct ComputePass<'a> {
id: <C as Context>::ComputePassId,
parent: &'a mut CommandEncoder,
}
pub struct RenderBundleEncoder<'a> {
context: Arc<C>,
id: <C as Context>::RenderBundleEncoderId,
_parent: &'a Device,
_p: PhantomData<*const u8>,
}
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 Queue {
context: Arc<C>,
id: <C as Context>::QueueId,
}
#[non_exhaustive]
pub enum BindingResource<'a> {
Buffer(BufferSlice<'a>),
Sampler(&'a Sampler),
TextureView(&'a TextureView),
TextureViewArray(&'a [TextureView]),
}
pub struct Binding<'a> {
pub binding: u32,
pub resource: BindingResource<'a>,
}
#[derive(Clone)]
pub struct BindGroupDescriptor<'a> {
pub layout: &'a BindGroupLayout,
pub bindings: &'a [Binding<'a>],
pub label: Option<&'a str>,
}
#[derive(Clone)]
pub struct PipelineLayoutDescriptor<'a> {
pub bind_group_layouts: &'a [&'a BindGroupLayout],
}
#[derive(Clone)]
pub struct ProgrammableStageDescriptor<'a> {
pub module: &'a ShaderModule,
pub entry_point: &'a str,
}
#[derive(Clone, Debug)]
pub struct VertexStateDescriptor<'a> {
pub index_format: IndexFormat,
pub vertex_buffers: &'a [VertexBufferDescriptor<'a>],
}
#[derive(Clone, Debug)]
pub struct VertexBufferDescriptor<'a> {
pub stride: BufferAddress,
pub step_mode: InputStepMode,
pub attributes: &'a [VertexAttributeDescriptor],
}
#[derive(Clone)]
pub struct RenderPipelineDescriptor<'a> {
pub layout: &'a PipelineLayout,
pub vertex_stage: ProgrammableStageDescriptor<'a>,
pub fragment_stage: Option<ProgrammableStageDescriptor<'a>>,
pub rasterization_state: Option<RasterizationStateDescriptor>,
pub primitive_topology: PrimitiveTopology,
pub color_states: &'a [ColorStateDescriptor],
pub depth_stencil_state: Option<DepthStencilStateDescriptor>,
pub vertex_state: VertexStateDescriptor<'a>,
pub sample_count: u32,
pub sample_mask: u32,
pub alpha_to_coverage_enabled: bool,
}
#[derive(Clone)]
pub struct ComputePipelineDescriptor<'a> {
pub layout: &'a PipelineLayout,
pub compute_stage: ProgrammableStageDescriptor<'a>,
}
pub use wgt::RenderPassColorAttachmentDescriptorBase;
pub type RenderPassColorAttachmentDescriptor<'a> =
wgt::RenderPassColorAttachmentDescriptorBase<&'a TextureView>;
pub use wgt::RenderPassDepthStencilAttachmentDescriptorBase;
pub type RenderPassDepthStencilAttachmentDescriptor<'a> =
wgt::RenderPassDepthStencilAttachmentDescriptorBase<&'a TextureView>;
pub struct RenderPassDescriptor<'a, 'b> {
pub color_attachments: &'b [RenderPassColorAttachmentDescriptor<'a>],
pub depth_stencil_attachment: Option<RenderPassDepthStencilAttachmentDescriptor<'a>>,
}
pub use wgt::BufferDescriptor as BufferDescriptorBase;
pub type BufferDescriptor<'a> = BufferDescriptorBase<Option<&'a str>>;
pub use wgt::CommandEncoderDescriptor as CommandEncoderDescriptorBase;
pub type CommandEncoderDescriptor<'a> = CommandEncoderDescriptorBase<Option<&'a str>>;
pub use wgt::RenderBundleDescriptor as RenderBundleDescriptorBase;
pub type RenderBundleDescriptor<'a> = RenderBundleDescriptorBase<Option<&'a str>>;
pub use wgt::TextureDescriptor as TextureDescriptorBase;
pub type TextureDescriptor<'a> = TextureDescriptorBase<Option<&'a str>>;
pub use wgt::TextureViewDescriptor as TextureViewDescriptorBase;
pub type TextureViewDescriptor<'a> = TextureViewDescriptorBase<Option<&'a str>>;
pub use wgt::SamplerDescriptor as SamplerDescriptorBase;
pub type SamplerDescriptor<'a> = SamplerDescriptorBase<Option<&'a str>>;
pub struct SwapChainTexture {
pub view: TextureView,
detail: <C as Context>::SwapChainOutputDetail,
}
pub struct SwapChainFrame {
pub output: SwapChainTexture,
pub suboptimal: bool,
}
#[derive(Debug)]
pub enum SwapChainError {
Timeout,
Outdated,
Lost,
OutOfMemory,
}
#[derive(Clone)]
pub struct BufferCopyView<'a> {
pub buffer: &'a Buffer,
pub layout: TextureDataLayout,
}
#[derive(Clone)]
pub struct TextureCopyView<'a> {
pub texture: &'a Texture,
pub mip_level: u32,
pub origin: Origin3d,
}
impl Instance {
pub fn new() -> Self {
Instance {
context: Arc::new(C::init()),
}
}
#[cfg(not(target_arch = "wasm32"))]
pub fn enumerate_adapters(
&self,
unsafe_extensions: UnsafeExtensions,
backends: BackendBit,
) -> impl Iterator<Item = Adapter> {
let context = Arc::clone(&self.context);
self.context
.enumerate_adapters(
unsafe_extensions,
wgc::instance::AdapterInputs::Mask(backends, |_| PhantomData),
)
.into_iter()
.map(move |id| crate::Adapter {
id,
context: Arc::clone(&context),
})
}
pub unsafe fn create_surface<W: raw_window_handle::HasRawWindowHandle>(
&self,
window: &W,
) -> Surface {
Surface {
id: Context::instance_create_surface(&*self.context, window),
}
}
#[cfg(any(target_os = "ios", target_os = "macos"))]
pub unsafe fn create_surface_from_core_animation_layer(
&self,
layer: *mut std::ffi::c_void,
) -> Surface {
let surface = wgc::instance::Surface {
#[cfg(feature = "vulkan-portability")]
vulkan: self
.context
.instance
.vulkan
.create_surface_from_layer(layer as *mut _, cfg!(debug_assertions)),
metal: self
.context
.instance
.metal
.create_surface_from_layer(layer as *mut _, cfg!(debug_assertions)),
};
crate::Surface {
id: self.context.surfaces.register_identity(
PhantomData,
surface,
&mut wgc::hub::Token::root(),
),
}
}
pub fn request_adapter(
&self,
options: &RequestAdapterOptions<'_>,
unsafe_extensions: UnsafeExtensions,
backends: BackendBit,
) -> impl Future<Output = Option<Adapter>> + Send {
let context = Arc::clone(&self.context);
self.context
.instance_request_adapter(options, unsafe_extensions, backends)
.map(|option| option.map(|id| Adapter { context, id }))
}
}
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);
Context::adapter_request_device(&*self.context, &self.id, desc, trace_path).map(|result| {
result.map(|(device_id, queue_id)| {
(
Device {
context: Arc::clone(&context),
id: device_id,
},
Queue {
context,
id: queue_id,
},
)
})
})
}
pub fn extensions(&self) -> Extensions {
Context::adapter_extensions(&*self.context, &self.id)
}
pub fn limits(&self) -> Limits {
Context::adapter_limits(&*self.context, &self.id)
}
pub fn capabilities(&self) -> Capabilities {
Context::adapter_capabilities(&*self.context, &self.id)
}
#[cfg(not(target_arch = "wasm32"))]
pub fn get_info(&self) -> AdapterInfo {
let context = &self.context;
wgc::gfx_select!(self.id => context.adapter_get_info(self.id))
}
}
impl Device {
pub fn poll(&self, maintain: Maintain) {
Context::device_poll(&*self.context, &self.id, maintain);
}
pub fn extensions(&self) -> Extensions {
Context::device_extensions(&*self.context, &self.id)
}
pub fn limits(&self) -> Limits {
Context::device_limits(&*self.context, &self.id)
}
pub fn capabilities(&self) -> Capabilities {
Context::device_capabilities(&*self.context, &self.id)
}
pub fn create_shader_module(&self, source: ShaderModuleSource) -> ShaderModule {
ShaderModule {
context: Arc::clone(&self.context),
id: Context::device_create_shader_module(&*self.context, &self.id, source),
}
}
pub fn create_command_encoder(&self, desc: &CommandEncoderDescriptor) -> CommandEncoder {
CommandEncoder {
context: Arc::clone(&self.context),
id: 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_buffer_with_data(&self, data: &[u8], usage: BufferUsage) -> Buffer {
let size = data.len() as u64;
let buffer = self.create_buffer(&BufferDescriptor {
label: None,
size,
usage,
mapped_at_creation: true,
});
Context::buffer_get_mapped_range_mut(&*self.context, &buffer.id, 0..size)
.copy_from_slice(data);
buffer.unmap();
buffer
}
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,
}
}
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_swap_chain(&self, surface: &Surface, desc: &SwapChainDescriptor) -> SwapChain {
SwapChain {
context: Arc::clone(&self.context),
id: Context::device_create_swap_chain(&*self.context, &self.id, &surface.id, desc),
}
}
}
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;
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct BufferAsyncError;
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum MapMode {
Read,
Write,
}
fn range_to_offset_size<S: RangeBounds<BufferAddress>>(bounds: S) -> (BufferAddress, 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) => BufferSize(bound + 1 - offset),
Bound::Excluded(&bound) => BufferSize(bound - offset),
Bound::Unbounded => BufferSize::WHOLE,
};
(offset, size)
}
pub struct BufferView<'a> {
slice: BufferSlice<'a>,
data: &'a [u8],
}
pub struct BufferViewMut<'a> {
slice: BufferSlice<'a>,
data: &'a mut [u8],
readable: bool,
}
impl std::ops::Deref for BufferView<'_> {
type Target = [u8];
fn deref(&self) -> &[u8] {
self.data
}
}
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
}
}
impl std::ops::DerefMut for BufferViewMut<'_> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.data
}
}
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 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);
}
}
impl BufferSlice<'_> {
pub fn slice<S: RangeBounds<BufferAddress>>(&self, bounds: S) -> Self {
let (sub_offset, sub_size) = range_to_offset_size(bounds);
let new_offset = self.offset + sub_offset;
let new_size = if sub_size == BufferSize::WHOLE {
BufferSize(
self.size
.0
.checked_sub(sub_offset)
.expect("underflow when slicing `BufferSlice`"),
)
} else {
assert!(
new_offset + sub_size.0 <= self.offset + self.size.0,
"offset and size must stay within the bounds of the parent slice"
);
sub_size
};
Self {
buffer: self.buffer,
offset: new_offset,
size: new_size,
}
}
pub fn map_async(
&self,
mode: MapMode,
) -> impl Future<Output = Result<(), BufferAsyncError>> + Send {
let end = {
let mut mc = self.buffer.map_context.lock();
assert_eq!(
mc.initial_range,
0..0,
"Buffer {:?} is already mapped",
self.buffer.id
);
let end = if self.size == BufferSize::WHOLE {
mc.total_size
} else {
self.offset + self.size.0
};
mc.initial_range = self.offset..end;
end
};
Context::buffer_map_async(
&*self.buffer.context,
&self.buffer.id,
mode,
self.offset..end,
)
}
pub fn get_mapped_range(&self) -> BufferView {
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 {
let end = self.buffer.map_context.lock().add(self.offset, self.size);
let data = Context::buffer_get_mapped_range_mut(
&*self.buffer.context,
&self.buffer.id,
self.offset..end,
);
BufferViewMut {
slice: *self,
data,
readable: self.buffer.usage.contains(BufferUsage::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, Some(desc)),
owned: true,
}
}
pub fn create_default_view(&self) -> TextureView {
TextureView {
context: Arc::clone(&self.context),
id: Context::texture_create_view(&*self.context, &self.id, None),
owned: true,
}
}
}
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 self.owned && !thread::panicking() {
self.context.texture_view_drop(&self.id);
}
}
}
impl CommandEncoder {
pub fn finish(self) -> CommandBuffer {
CommandBuffer {
context: Arc::clone(&self.context),
id: Some(Context::command_encoder_finish(&*self.context, &self.id)),
}
}
pub fn begin_render_pass<'a>(
&'a mut self,
desc: &RenderPassDescriptor<'a, '_>,
) -> RenderPass<'a> {
RenderPass {
id: Context::command_encoder_begin_render_pass(&*self.context, &self.id, desc),
parent: self,
}
}
pub fn begin_compute_pass(&mut self) -> ComputePass {
ComputePass {
id: Context::command_encoder_begin_compute_pass(&*self.context, &self.id),
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,
&source.id,
source_offset,
&destination.id,
destination_offset,
copy_size,
);
}
pub fn copy_buffer_to_texture(
&mut self,
source: BufferCopyView,
destination: TextureCopyView,
copy_size: Extent3d,
) {
Context::command_encoder_copy_buffer_to_texture(
&*self.context,
&self.id,
source,
destination,
copy_size,
);
}
pub fn copy_texture_to_buffer(
&mut self,
source: TextureCopyView,
destination: BufferCopyView,
copy_size: Extent3d,
) {
Context::command_encoder_copy_texture_to_buffer(
&*self.context,
&self.id,
source,
destination,
copy_size,
);
}
pub fn copy_texture_to_texture(
&mut self,
source: TextureCopyView,
destination: TextureCopyView,
copy_size: Extent3d,
) {
Context::command_encoder_copy_texture_to_texture(
&*self.context,
&self.id,
source,
destination,
copy_size,
);
}
}
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_color(&mut self, color: Color) {
self.id.set_blend_color(color)
}
pub fn set_index_buffer(&mut self, buffer_slice: BufferSlice<'a>) {
RenderInner::set_index_buffer(
&mut self.id,
&buffer_slice.buffer.id,
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> Drop for RenderPass<'a> {
fn drop(&mut self) {
if !thread::panicking() {
self.parent
.context
.command_encoder_end_render_pass(&self.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 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> Drop for ComputePass<'a> {
fn drop(&mut self) {
if !thread::panicking() {
self.parent
.context
.command_encoder_end_compute_pass(&self.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>) {
RenderInner::set_index_buffer(
&mut self.id,
&buffer_slice.buffer.id,
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 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: TextureCopyView,
data: &[u8],
data_layout: TextureDataLayout,
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()),
);
}
}
impl Drop for SwapChainTexture {
fn drop(&mut self) {
if !thread::panicking() {
Context::swap_chain_present(&*self.view.context, &self.view.id, &self.detail);
}
}
}
impl SwapChain {
pub fn get_next_frame(&mut self) -> Result<SwapChainFrame, SwapChainError> {
let (view_id, status, detail) =
Context::swap_chain_get_next_texture(&*self.context, &self.id);
let output = view_id.map(|id| SwapChainTexture {
view: TextureView {
context: Arc::clone(&self.context),
id: id,
owned: false,
},
detail,
});
match status {
SwapChainStatus::Good => Ok(SwapChainFrame {
output: output.unwrap(),
suboptimal: false,
}),
SwapChainStatus::Suboptimal => Ok(SwapChainFrame {
output: output.unwrap(),
suboptimal: true,
}),
SwapChainStatus::Timeout => Err(SwapChainError::Timeout),
SwapChainStatus::Outdated => Err(SwapChainError::Outdated),
SwapChainStatus::Lost => Err(SwapChainError::Lost),
SwapChainStatus::OutOfMemory => Err(SwapChainError::OutOfMemory),
}
}
}