mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
1668 lines
54 KiB
Rust
1668 lines
54 KiB
Rust
//! A cross-platform graphics and compute library based on WebGPU.
|
|
|
|
mod backend;
|
|
|
|
#[macro_use]
|
|
mod macros;
|
|
|
|
use futures::FutureExt as _;
|
|
use std::{
|
|
future::Future,
|
|
marker::PhantomData,
|
|
ops::{Bound, Range, RangeBounds},
|
|
sync::Arc,
|
|
thread,
|
|
};
|
|
|
|
#[cfg(not(target_arch = "wasm32"))]
|
|
pub use wgc::instance::{AdapterInfo, DeviceType};
|
|
pub use wgt::{
|
|
read_spirv, AddressMode, Backend, BackendBit, BlendDescriptor, BlendFactor, BlendOperation,
|
|
BufferAddress, BufferSize, BufferUsage, Color, ColorStateDescriptor, ColorWrite,
|
|
CommandBufferDescriptor, CompareFunction, CullMode, DepthStencilStateDescriptor,
|
|
DeviceDescriptor, DynamicOffset, Extensions, Extent3d, FilterMode, FrontFace, IndexFormat,
|
|
InputStepMode, Limits, LoadOp, Origin3d, PowerPreference, PresentMode, PrimitiveTopology,
|
|
RasterizationStateDescriptor, ShaderLocation, ShaderStage, StencilOperation,
|
|
StencilStateFaceDescriptor, StoreOp, SwapChainDescriptor, SwapChainStatus, TextureAspect,
|
|
TextureComponentType, TextureDataLayout, TextureDimension, TextureFormat, TextureUsage,
|
|
TextureViewDimension, VertexAttributeDescriptor, VertexFormat, BIND_BUFFER_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 RenderPassInner<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 set_blend_color(&mut self, color: wgt::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 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 Context: Sized {
|
|
type AdapterId: Send + Sync;
|
|
type DeviceId: Send + Sync;
|
|
type QueueId: Send + Sync;
|
|
type ShaderModuleId: Send + Sync;
|
|
type BindGroupLayoutId: Send + Sync;
|
|
type BindGroupId: Send + Sync;
|
|
type TextureViewId: Send + Sync;
|
|
type SamplerId: Send + Sync;
|
|
type BufferId: Send + Sync;
|
|
type TextureId: Send + Sync;
|
|
type PipelineLayoutId: Send + Sync;
|
|
type RenderPipelineId: Send + Sync;
|
|
type ComputePipelineId: Send + Sync;
|
|
type CommandEncoderId;
|
|
type ComputePassId: ComputePassInner<Self>;
|
|
type CommandBufferId: Send + Sync;
|
|
type SurfaceId: Send + Sync;
|
|
type SwapChainId: Send + Sync;
|
|
type RenderPassId: RenderPassInner<Self>;
|
|
|
|
type CreateBufferMappedDetail: Send;
|
|
type BufferReadMappingDetail: Send;
|
|
type BufferWriteMappingDetail: Send;
|
|
type SwapChainOutputDetail: Send;
|
|
|
|
type RequestAdapterFuture: Future<Output = Option<Self::AdapterId>> + Send;
|
|
type RequestDeviceFuture: Future<Output = Result<(Self::DeviceId, Self::QueueId), RequestDeviceError>>
|
|
+ Send;
|
|
type MapReadFuture: Future<Output = Result<Self::BufferReadMappingDetail, BufferAsyncError>>
|
|
+ Send;
|
|
type MapWriteFuture: Future<Output = Result<Self::BufferWriteMappingDetail, 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<'_>,
|
|
backends: wgt::BackendBit,
|
|
) -> Self::RequestAdapterFuture;
|
|
fn adapter_request_device(
|
|
&self,
|
|
adapter: &Self::AdapterId,
|
|
desc: &DeviceDescriptor,
|
|
trace_dir: Option<&std::path::Path>,
|
|
) -> Self::RequestDeviceFuture;
|
|
|
|
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,
|
|
spv: &[u32],
|
|
) -> 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_mapped<'a>(
|
|
&self,
|
|
device: &Self::DeviceId,
|
|
desc: &BufferDescriptor,
|
|
) -> (Self::BufferId, &'a mut [u8], Self::CreateBufferMappedDetail);
|
|
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_drop(&self, device: &Self::DeviceId);
|
|
fn device_poll(&self, device: &Self::DeviceId, maintain: Maintain);
|
|
|
|
fn buffer_map_read(
|
|
&self,
|
|
buffer: &Self::BufferId,
|
|
range: Range<BufferAddress>,
|
|
) -> Self::MapReadFuture;
|
|
fn buffer_map_write(
|
|
&self,
|
|
buffer: &Self::BufferId,
|
|
range: Range<BufferAddress>,
|
|
) -> Self::MapWriteFuture;
|
|
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 compute_pipeline_drop(&self, pipeline: &Self::ComputePipelineId);
|
|
fn render_pipeline_drop(&self, pipeline: &Self::RenderPipelineId);
|
|
|
|
fn 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 encoder_copy_buffer_to_texture(
|
|
&self,
|
|
encoder: &Self::CommandEncoderId,
|
|
source: BufferCopyView,
|
|
destination: TextureCopyView,
|
|
copy_size: Extent3d,
|
|
);
|
|
fn encoder_copy_texture_to_buffer(
|
|
&self,
|
|
encoder: &Self::CommandEncoderId,
|
|
source: TextureCopyView,
|
|
destination: BufferCopyView,
|
|
copy_size: Extent3d,
|
|
);
|
|
fn encoder_copy_texture_to_texture(
|
|
&self,
|
|
encoder: &Self::CommandEncoderId,
|
|
source: TextureCopyView,
|
|
destination: TextureCopyView,
|
|
copy_size: Extent3d,
|
|
);
|
|
|
|
fn flush_mapped_data(data: &mut [u8], detail: Self::CreateBufferMappedDetail);
|
|
fn encoder_begin_compute_pass(&self, encoder: &Self::CommandEncoderId) -> Self::ComputePassId;
|
|
fn encoder_end_compute_pass(
|
|
&self,
|
|
encoder: &Self::CommandEncoderId,
|
|
pass: &mut Self::ComputePassId,
|
|
);
|
|
fn encoder_begin_render_pass<'a>(
|
|
&self,
|
|
encoder: &Self::CommandEncoderId,
|
|
desc: &RenderPassDescriptor<'a, '_>,
|
|
) -> Self::RenderPassId;
|
|
fn encoder_end_render_pass(
|
|
&self,
|
|
encoder: &Self::CommandEncoderId,
|
|
pass: &mut Self::RenderPassId,
|
|
);
|
|
fn encoder_finish(&self, encoder: &Self::CommandEncoderId) -> Self::CommandBufferId;
|
|
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: wgt::TextureDataLayout,
|
|
size: wgt::Extent3d,
|
|
);
|
|
fn queue_submit<I: Iterator<Item = Self::CommandBufferId>>(
|
|
&self,
|
|
queue: &Self::QueueId,
|
|
command_buffers: I,
|
|
);
|
|
}
|
|
|
|
/// An instance sets up the context for all other wgpu objects.
|
|
///
|
|
/// An `Adapter` can be used to open a connection to the corresponding device on the host system,
|
|
/// yielding a [`Device`] object.
|
|
pub struct Instance {
|
|
context: Arc<C>,
|
|
}
|
|
|
|
/// A handle to a physical graphics and/or compute device.
|
|
///
|
|
/// An `Adapter` can be used to open a connection to the corresponding device on the host system,
|
|
/// yielding a [`Device`] object.
|
|
pub struct Adapter {
|
|
context: Arc<C>,
|
|
id: <C as Context>::AdapterId,
|
|
}
|
|
|
|
/// Options for requesting adapter.
|
|
#[derive(Clone)]
|
|
pub struct RequestAdapterOptions<'a> {
|
|
/// Power preference for the adapter.
|
|
pub power_preference: PowerPreference,
|
|
/// Surface that is required to be presentable with the requested adapter.
|
|
pub compatible_surface: Option<&'a Surface>,
|
|
}
|
|
|
|
/// An open connection to a graphics and/or compute device.
|
|
///
|
|
/// The `Device` is the responsible for the creation of most rendering and compute resources, as
|
|
/// well as exposing [`Queue`] objects.
|
|
pub struct Device {
|
|
context: Arc<C>,
|
|
id: <C as Context>::DeviceId,
|
|
}
|
|
|
|
/// This is passed to `Device::poll` to control whether
|
|
/// it should block or not.
|
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
|
pub enum Maintain {
|
|
Wait,
|
|
Poll,
|
|
}
|
|
|
|
/// A handle to a GPU-accessible buffer.
|
|
pub struct Buffer {
|
|
context: Arc<C>,
|
|
id: <C as Context>::BufferId,
|
|
size: BufferAddress,
|
|
}
|
|
|
|
/// A description of what portion of a buffer to use
|
|
pub struct BufferSlice<'a> {
|
|
buffer: &'a Buffer,
|
|
offset: BufferAddress,
|
|
size: BufferSize,
|
|
}
|
|
|
|
/// A handle to a texture on the GPU.
|
|
pub struct Texture {
|
|
context: Arc<C>,
|
|
id: <C as Context>::TextureId,
|
|
owned: bool,
|
|
}
|
|
|
|
/// A handle to a texture view.
|
|
///
|
|
/// A `TextureView` object describes a texture and associated metadata needed by a
|
|
/// [`RenderPipeline`] or [`BindGroup`].
|
|
pub struct TextureView {
|
|
context: Arc<C>,
|
|
id: <C as Context>::TextureViewId,
|
|
owned: bool,
|
|
}
|
|
|
|
/// A handle to a sampler.
|
|
///
|
|
/// A `Sampler` object defines how a pipeline will sample from a [`TextureView`]. Samplers define
|
|
/// image filters (including anisotropy) and address (wrapping) modes, among other things. See
|
|
/// the documentation for [`SamplerDescriptor`] for more information.
|
|
pub struct Sampler {
|
|
context: Arc<C>,
|
|
id: <C as Context>::SamplerId,
|
|
}
|
|
|
|
impl Drop for Sampler {
|
|
fn drop(&mut self) {
|
|
self.context.sampler_drop(&self.id);
|
|
}
|
|
}
|
|
|
|
/// A handle to a presentable surface.
|
|
///
|
|
/// A `Surface` represents a platform-specific surface (e.g. a window) to which rendered images may
|
|
/// be presented. A `Surface` may be created with [`Surface::create`].
|
|
pub struct Surface {
|
|
id: <C as Context>::SurfaceId,
|
|
}
|
|
|
|
/// A handle to a swap chain.
|
|
///
|
|
/// A `SwapChain` represents the image or series of images that will be presented to a [`Surface`].
|
|
/// A `SwapChain` may be created with [`Device::create_swap_chain`].
|
|
pub struct SwapChain {
|
|
context: Arc<C>,
|
|
id: <C as Context>::SwapChainId,
|
|
}
|
|
|
|
/// An opaque handle to a binding group layout.
|
|
///
|
|
/// A `BindGroupLayout` is a handle to the GPU-side layout of a binding group. It can be used to
|
|
/// create a [`BindGroupDescriptor`] object, which in turn can be used to create a [`BindGroup`]
|
|
/// object with [`Device::create_bind_group`]. A series of `BindGroupLayout`s can also be used to
|
|
/// create a [`PipelineLayoutDescriptor`], which can be used to create a [`PipelineLayout`].
|
|
pub struct BindGroupLayout {
|
|
context: Arc<C>,
|
|
id: <C as Context>::BindGroupLayoutId,
|
|
}
|
|
|
|
impl Drop for BindGroupLayout {
|
|
fn drop(&mut self) {
|
|
self.context.bind_group_layout_drop(&self.id);
|
|
}
|
|
}
|
|
|
|
/// An opaque handle to a binding group.
|
|
///
|
|
/// A `BindGroup` represents the set of resources bound to the bindings described by a
|
|
/// [`BindGroupLayout`]. It can be created with [`Device::create_bind_group`]. A `BindGroup` can
|
|
/// be bound to a particular [`RenderPass`] with [`RenderPass::set_bind_group`], or to a
|
|
/// [`ComputePass`] with [`ComputePass::set_bind_group`].
|
|
pub struct BindGroup {
|
|
context: Arc<C>,
|
|
id: <C as Context>::BindGroupId,
|
|
}
|
|
|
|
impl Drop for BindGroup {
|
|
fn drop(&mut self) {
|
|
self.context.bind_group_drop(&self.id);
|
|
}
|
|
}
|
|
|
|
/// A handle to a compiled shader module.
|
|
///
|
|
/// A `ShaderModule` represents a compiled shader module on the GPU. It can be created by passing
|
|
/// valid SPIR-V source code to [`Device::create_shader_module`]. Shader modules are used to define
|
|
/// programmable stages of a pipeline.
|
|
pub struct ShaderModule {
|
|
context: Arc<C>,
|
|
id: <C as Context>::ShaderModuleId,
|
|
}
|
|
|
|
impl Drop for ShaderModule {
|
|
fn drop(&mut self) {
|
|
self.context.shader_module_drop(&self.id);
|
|
}
|
|
}
|
|
|
|
/// An opaque handle to a pipeline layout.
|
|
///
|
|
/// A `PipelineLayout` object describes the available binding groups of a pipeline.
|
|
pub struct PipelineLayout {
|
|
context: Arc<C>,
|
|
id: <C as Context>::PipelineLayoutId,
|
|
}
|
|
|
|
impl Drop for PipelineLayout {
|
|
fn drop(&mut self) {
|
|
self.context.pipeline_layout_drop(&self.id);
|
|
}
|
|
}
|
|
|
|
/// A handle to a rendering (graphics) pipeline.
|
|
///
|
|
/// A `RenderPipeline` object represents a graphics pipeline and its stages, bindings, vertex
|
|
/// buffers and targets. A `RenderPipeline` may be created with [`Device::create_render_pipeline`].
|
|
pub struct RenderPipeline {
|
|
context: Arc<C>,
|
|
id: <C as Context>::RenderPipelineId,
|
|
}
|
|
|
|
impl Drop for RenderPipeline {
|
|
fn drop(&mut self) {
|
|
self.context.render_pipeline_drop(&self.id);
|
|
}
|
|
}
|
|
|
|
/// A handle to a compute pipeline.
|
|
pub struct ComputePipeline {
|
|
context: Arc<C>,
|
|
id: <C as Context>::ComputePipelineId,
|
|
}
|
|
|
|
impl Drop for ComputePipeline {
|
|
fn drop(&mut self) {
|
|
self.context.compute_pipeline_drop(&self.id);
|
|
}
|
|
}
|
|
|
|
/// An opaque handle to a command buffer on the GPU.
|
|
///
|
|
/// A `CommandBuffer` represents a complete sequence of commands that may be submitted to a command
|
|
/// queue with [`Queue::submit`]. A `CommandBuffer` is obtained by recording a series of commands to
|
|
/// a [`CommandEncoder`] and then calling [`CommandEncoder::finish`].
|
|
pub struct CommandBuffer {
|
|
context: Arc<C>,
|
|
id: Option<<C as Context>::CommandBufferId>,
|
|
}
|
|
|
|
impl Drop for CommandBuffer {
|
|
fn drop(&mut self) {
|
|
if let Some(ref id) = self.id {
|
|
self.context.command_buffer_drop(id);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// An object that encodes GPU operations.
|
|
///
|
|
/// A `CommandEncoder` can record [`RenderPass`]es, [`ComputePass`]es, and transfer operations
|
|
/// between driver-managed resources like [`Buffer`]s and [`Texture`]s.
|
|
///
|
|
/// When finished recording, call [`CommandEncoder::finish`] to obtain a [`CommandBuffer`] which may
|
|
/// be submitted for execution.
|
|
pub struct CommandEncoder {
|
|
context: Arc<C>,
|
|
id: <C as Context>::CommandEncoderId,
|
|
/// This type should be !Send !Sync, because it represents an allocation on this thread's
|
|
/// command buffer.
|
|
_p: PhantomData<*const u8>,
|
|
}
|
|
|
|
/// An in-progress recording of a render pass.
|
|
pub struct RenderPass<'a> {
|
|
id: <C as Context>::RenderPassId,
|
|
parent: &'a mut CommandEncoder,
|
|
}
|
|
|
|
/// An in-progress recording of a compute pass.
|
|
pub struct ComputePass<'a> {
|
|
id: <C as Context>::ComputePassId,
|
|
parent: &'a mut CommandEncoder,
|
|
}
|
|
|
|
/// A handle to a command queue on a device.
|
|
///
|
|
/// A `Queue` executes recorded [`CommandBuffer`] objects.
|
|
pub struct Queue {
|
|
context: Arc<C>,
|
|
id: <C as Context>::QueueId,
|
|
}
|
|
|
|
/// A resource that can be bound to a pipeline.
|
|
pub enum BindingResource<'a> {
|
|
Buffer(BufferSlice<'a>),
|
|
Sampler(&'a Sampler),
|
|
TextureView(&'a TextureView),
|
|
}
|
|
|
|
/// A bindable resource and the slot to bind it to.
|
|
pub struct Binding<'a> {
|
|
pub binding: u32,
|
|
pub resource: BindingResource<'a>,
|
|
}
|
|
|
|
/// Specific type of a binding.
|
|
/// WebGPU spec: https://gpuweb.github.io/gpuweb/#dictdef-gpubindgrouplayoutentry
|
|
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
|
pub enum BindingType {
|
|
/// A buffer for uniform values.
|
|
///
|
|
/// Example GLSL syntax:
|
|
/// ```cpp,ignore
|
|
/// layout(std140, binding = 0)
|
|
/// uniform Globals {
|
|
/// vec2 aUniform;
|
|
/// vec2 anotherUniform;
|
|
/// };
|
|
/// ```
|
|
UniformBuffer {
|
|
/// Indicates that the binding has a dynamic offset.
|
|
/// One offset must be passed to [RenderPass::set_bind_group] for each dynamic binding in increasing order of binding number.
|
|
dynamic: bool,
|
|
},
|
|
/// A storage buffer.
|
|
///
|
|
/// Example GLSL syntax:
|
|
/// ```cpp,ignore
|
|
/// layout (set=0, binding=0) buffer myStorageBuffer {
|
|
/// vec4 myElement[];
|
|
/// };
|
|
/// ```
|
|
StorageBuffer {
|
|
/// Indicates that the binding has a dynamic offset.
|
|
/// One offset must be passed to [RenderPass::set_bind_group] for each dynamic binding in increasing order of binding number.
|
|
dynamic: bool,
|
|
/// The buffer can only be read in the shader and it must be annotated with `readonly`.
|
|
///
|
|
/// Example GLSL syntax:
|
|
/// ```cpp,ignore
|
|
/// layout (set=0, binding=0) readonly buffer myStorageBuffer {
|
|
/// vec4 myElement[];
|
|
/// };
|
|
/// ```
|
|
readonly: bool,
|
|
},
|
|
/// A sampler that can be used to sample a texture.
|
|
///
|
|
/// Example GLSL syntax:
|
|
/// ```cpp,ignore
|
|
/// layout(binding = 0)
|
|
/// uniform sampler s;
|
|
/// ```
|
|
Sampler {
|
|
/// Use as a comparison sampler instead of a normal sampler.
|
|
/// For more info take a look at the analogous functionality in OpenGL: https://www.khronos.org/opengl/wiki/Sampler_Object#Comparison_mode.
|
|
comparison: bool,
|
|
},
|
|
/// A texture.
|
|
///
|
|
/// Example GLSL syntax:
|
|
/// ```cpp,ignore
|
|
/// layout(binding = 0)
|
|
/// uniform texture2D t;
|
|
/// ```
|
|
SampledTexture {
|
|
/// Dimension of the texture view that is going to be sampled.
|
|
dimension: TextureViewDimension,
|
|
/// Component type of the texture.
|
|
/// This must be compatible with the format of the texture.
|
|
component_type: TextureComponentType,
|
|
/// True if the texture has a sample count greater than 1.
|
|
multisampled: bool,
|
|
},
|
|
/// A storage texture.
|
|
/// Example GLSL syntax:
|
|
/// ```cpp,ignore
|
|
/// layout(set=0, binding=0, r32f) uniform image2D myStorageImage;
|
|
/// ```
|
|
/// Note that the texture format must be specified in the shader as well.
|
|
/// A list of valid formats can be found in the specification here: https://www.khronos.org/registry/OpenGL/specs/gl/GLSLangSpec.4.60.html#layout-qualifiers
|
|
StorageTexture {
|
|
/// Dimension of the texture view that is going to be sampled.
|
|
dimension: TextureViewDimension,
|
|
/// Component type of the texture.
|
|
/// This must be compatible with the format of the texture.
|
|
component_type: TextureComponentType,
|
|
/// Format of the texture.
|
|
format: TextureFormat,
|
|
/// The texture can only be read in the shader and it must be annotated with `readonly`.
|
|
///
|
|
/// Example GLSL syntax:
|
|
/// ```cpp,ignore
|
|
/// layout(set=0, binding=0, r32f) readonly uniform image2D myStorageImage;
|
|
/// ```
|
|
readonly: bool,
|
|
},
|
|
}
|
|
|
|
/// A description of a single binding inside a bind group.
|
|
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
|
|
pub struct BindGroupLayoutEntry {
|
|
pub binding: u32,
|
|
pub visibility: ShaderStage,
|
|
pub ty: BindingType,
|
|
}
|
|
|
|
/// A description of a bind group layout.
|
|
#[derive(Clone, Debug)]
|
|
pub struct BindGroupLayoutDescriptor<'a> {
|
|
pub bindings: &'a [BindGroupLayoutEntry],
|
|
|
|
/// An optional label to apply to the bind group layout.
|
|
/// This can be useful for debugging and performance analysis.
|
|
pub label: Option<&'a str>,
|
|
}
|
|
|
|
/// A description of a group of bindings and the resources to be bound.
|
|
#[derive(Clone)]
|
|
pub struct BindGroupDescriptor<'a> {
|
|
/// The layout for this bind group.
|
|
pub layout: &'a BindGroupLayout,
|
|
|
|
/// The resources to bind to this bind group.
|
|
pub bindings: &'a [Binding<'a>],
|
|
|
|
/// An optional label to apply to the bind group.
|
|
/// This can be useful for debugging and performance analysis.
|
|
pub label: Option<&'a str>,
|
|
}
|
|
|
|
/// A description of a pipeline layout.
|
|
///
|
|
/// A `PipelineLayoutDescriptor` can be passed to [`Device::create_pipeline_layout`] to obtain a
|
|
/// [`PipelineLayout`].
|
|
#[derive(Clone)]
|
|
pub struct PipelineLayoutDescriptor<'a> {
|
|
pub bind_group_layouts: &'a [&'a BindGroupLayout],
|
|
}
|
|
|
|
/// A description of a programmable pipeline stage.
|
|
#[derive(Clone)]
|
|
pub struct ProgrammableStageDescriptor<'a> {
|
|
/// The compiled shader module for this stage.
|
|
pub module: &'a ShaderModule,
|
|
|
|
/// The name of the entry point in the compiled shader.
|
|
pub entry_point: &'a str,
|
|
}
|
|
|
|
/// The vertex input state for a render pipeline.
|
|
#[derive(Clone, Debug)]
|
|
pub struct VertexStateDescriptor<'a> {
|
|
/// The format of any index buffers used with this pipeline.
|
|
pub index_format: IndexFormat,
|
|
|
|
/// The format of any vertex buffers used with this pipeline.
|
|
pub vertex_buffers: &'a [VertexBufferDescriptor<'a>],
|
|
}
|
|
|
|
/// A description of a vertex buffer.
|
|
#[derive(Clone, Debug)]
|
|
pub struct VertexBufferDescriptor<'a> {
|
|
/// The stride, in bytes, between elements of this buffer.
|
|
pub stride: BufferAddress,
|
|
|
|
pub step_mode: InputStepMode,
|
|
|
|
/// The list of attributes which comprise a single vertex.
|
|
pub attributes: &'a [VertexAttributeDescriptor],
|
|
}
|
|
|
|
/// A complete description of a render (graphics) pipeline.
|
|
#[derive(Clone)]
|
|
pub struct RenderPipelineDescriptor<'a> {
|
|
/// The layout of bind groups for this pipeline.
|
|
pub layout: &'a PipelineLayout,
|
|
|
|
/// The compiled vertex stage and its entry point.
|
|
pub vertex_stage: ProgrammableStageDescriptor<'a>,
|
|
|
|
/// The compiled fragment stage and its entry point, if any.
|
|
pub fragment_stage: Option<ProgrammableStageDescriptor<'a>>,
|
|
|
|
/// The rasterization process for this pipeline.
|
|
pub rasterization_state: Option<RasterizationStateDescriptor>,
|
|
|
|
/// The primitive topology used to interpret vertices.
|
|
pub primitive_topology: PrimitiveTopology,
|
|
|
|
/// The effect of draw calls on the color aspect of the output target.
|
|
pub color_states: &'a [ColorStateDescriptor],
|
|
|
|
/// The effect of draw calls on the depth and stencil aspects of the output target, if any.
|
|
pub depth_stencil_state: Option<DepthStencilStateDescriptor>,
|
|
|
|
/// The vertex input state for this pipeline.
|
|
pub vertex_state: VertexStateDescriptor<'a>,
|
|
|
|
/// The number of samples calculated per pixel (for MSAA).
|
|
pub sample_count: u32,
|
|
|
|
/// Bitmask that restricts the samples of a pixel modified by this pipeline.
|
|
pub sample_mask: u32,
|
|
|
|
/// When enabled, produces another sample mask per pixel based on the alpha output value, that
|
|
/// is ANDed with the sample_mask and the primitive coverage to restrict the set of samples
|
|
/// affected by a primitive.
|
|
/// The implicit mask produced for alpha of zero is guaranteed to be zero, and for alpha of one
|
|
/// is guaranteed to be all 1-s.
|
|
pub alpha_to_coverage_enabled: bool,
|
|
}
|
|
|
|
/// A complete description of a compute pipeline.
|
|
#[derive(Clone)]
|
|
pub struct ComputePipelineDescriptor<'a> {
|
|
/// The layout of bind groups for this pipeline.
|
|
pub layout: &'a PipelineLayout,
|
|
|
|
/// The compiled compute stage and its entry point.
|
|
pub compute_stage: ProgrammableStageDescriptor<'a>,
|
|
}
|
|
|
|
pub type RenderPassColorAttachmentDescriptor<'a> =
|
|
wgt::RenderPassColorAttachmentDescriptorBase<&'a TextureView>;
|
|
pub type RenderPassDepthStencilAttachmentDescriptor<'a> =
|
|
wgt::RenderPassDepthStencilAttachmentDescriptorBase<&'a TextureView>;
|
|
|
|
/// A description of all the attachments of a render pass.
|
|
pub struct RenderPassDescriptor<'a, 'b> {
|
|
/// The color attachments of the render pass.
|
|
pub color_attachments: &'b [RenderPassColorAttachmentDescriptor<'a>],
|
|
|
|
/// The depth and stencil attachment of the render pass, if any.
|
|
pub depth_stencil_attachment: Option<RenderPassDepthStencilAttachmentDescriptor<'a>>,
|
|
}
|
|
|
|
/// A description of a buffer.
|
|
pub type BufferDescriptor<'a> = wgt::BufferDescriptor<Option<&'a str>>;
|
|
|
|
/// A description of a command encoder.
|
|
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
|
|
pub struct CommandEncoderDescriptor<'a> {
|
|
/// An optional label to apply to the command encoder.
|
|
/// This can be useful for debugging and performance analysis.
|
|
pub label: Option<&'a str>,
|
|
}
|
|
|
|
/// A description of a texture.
|
|
pub type TextureDescriptor<'a> = wgt::TextureDescriptor<Option<&'a str>>;
|
|
|
|
/// A description of a texture view.
|
|
pub type TextureViewDescriptor<'a> = wgt::TextureViewDescriptor<Option<&'a str>>;
|
|
|
|
/// A description of a sampler.
|
|
pub type SamplerDescriptor<'a> = wgt::SamplerDescriptor<Option<&'a str>>;
|
|
|
|
/// A swap chain image that can be rendered to.
|
|
pub struct SwapChainTexture {
|
|
pub view: TextureView,
|
|
detail: <C as Context>::SwapChainOutputDetail,
|
|
}
|
|
|
|
/// The result of a successful call to `SwapChain::get_next_frame`.
|
|
pub struct SwapChainFrame {
|
|
pub output: SwapChainTexture,
|
|
pub suboptimal: bool,
|
|
}
|
|
|
|
/// The result of an unsuccessful call to `SwapChain::get_next_frame`.
|
|
#[derive(Debug)]
|
|
pub enum SwapChainError {
|
|
Timeout,
|
|
Outdated,
|
|
Lost,
|
|
OutOfMemory,
|
|
}
|
|
|
|
/// A view of a buffer which can be used to copy to or from a texture.
|
|
#[derive(Clone)]
|
|
pub struct BufferCopyView<'a> {
|
|
/// The buffer to be copied to or from.
|
|
pub buffer: &'a Buffer,
|
|
|
|
/// The layout of the texture data in this buffer.
|
|
pub layout: wgt::TextureDataLayout,
|
|
}
|
|
|
|
/// A view of a texture which can be used to copy to or from a buffer or another texture.
|
|
#[derive(Clone)]
|
|
pub struct TextureCopyView<'a> {
|
|
/// The texture to be copied to or from.
|
|
pub texture: &'a Texture,
|
|
|
|
/// The target mip level of the texture.
|
|
pub mip_level: u32,
|
|
|
|
/// The base texel of the texture in the selected `mip_level`.
|
|
pub origin: Origin3d,
|
|
}
|
|
|
|
/// A buffer being created, mapped in host memory.
|
|
pub struct CreateBufferMapped<'a> {
|
|
context: Arc<C>,
|
|
id: <C as Context>::BufferId,
|
|
/// The backing field for `data()`. This isn't `pub` because users shouldn't
|
|
/// be able to replace it to point somewhere else. We rely on it pointing to
|
|
/// to the correct memory later during `unmap()`.
|
|
mapped_data: &'a mut [u8],
|
|
detail: <C as Context>::CreateBufferMappedDetail,
|
|
}
|
|
|
|
impl CreateBufferMapped<'_> {
|
|
/// The mapped data.
|
|
pub fn data(&mut self) -> &mut [u8] {
|
|
self.mapped_data
|
|
}
|
|
|
|
/// Unmaps the buffer from host memory and returns a [`Buffer`].
|
|
pub fn finish(self) -> Buffer {
|
|
<C as Context>::flush_mapped_data(self.mapped_data, self.detail);
|
|
Context::buffer_unmap(&*self.context, &self.id);
|
|
Buffer {
|
|
context: self.context,
|
|
id: self.id,
|
|
size: self.mapped_data.len() as BufferAddress,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Instance {
|
|
/// Create an new instance.
|
|
pub fn new() -> Self {
|
|
Instance {
|
|
context: Arc::new(C::init()),
|
|
}
|
|
}
|
|
|
|
/// Retrieves all available [`Adapter`]s that match the given backends.
|
|
#[cfg(not(target_arch = "wasm32"))]
|
|
pub fn enumerate_adapters(&self, backends: wgt::BackendBit) -> impl Iterator<Item = Adapter> {
|
|
let context = Arc::clone(&self.context);
|
|
self.context
|
|
.enumerate_adapters(wgc::instance::AdapterInputs::Mask(backends, |_| {
|
|
PhantomData
|
|
}))
|
|
.into_iter()
|
|
.map(move |id| crate::Adapter {
|
|
id,
|
|
context: Arc::clone(&context),
|
|
})
|
|
}
|
|
|
|
/// Creates a surface from a raw window handle.
|
|
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(),
|
|
),
|
|
}
|
|
}
|
|
|
|
/// Retrieves an [`Adapter`] which matches the given options.
|
|
///
|
|
/// Some options are "soft", so treated as non-mandatory. Others are "hard".
|
|
///
|
|
/// If no adapters are found that suffice all the "hard" options, `None` is returned.
|
|
pub fn request_adapter(
|
|
&self,
|
|
options: &RequestAdapterOptions<'_>,
|
|
backends: BackendBit,
|
|
) -> impl Future<Output = Option<Adapter>> + Send {
|
|
let context = Arc::clone(&self.context);
|
|
self.context
|
|
.instance_request_adapter(options, backends)
|
|
.map(|option| option.map(|id| Adapter { context, id }))
|
|
}
|
|
}
|
|
|
|
impl Adapter {
|
|
/// Requests a connection to a physical device, creating a logical device.
|
|
/// Returns the device together with a queue that executes command buffers.
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// Panics if the extensions specified by `desc` are not supported by this 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,
|
|
},
|
|
)
|
|
})
|
|
})
|
|
}
|
|
|
|
#[cfg(not(target_arch = "wasm32"))]
|
|
pub fn get_info(&self) -> AdapterInfo {
|
|
//wgn::adapter_get_info(self.id)
|
|
unimplemented!()
|
|
}
|
|
}
|
|
|
|
impl Device {
|
|
/// Check for resource cleanups and mapping callbacks.
|
|
pub fn poll(&self, maintain: Maintain) {
|
|
Context::device_poll(&*self.context, &self.id, maintain);
|
|
}
|
|
|
|
/// Creates a shader module from SPIR-V source code.
|
|
pub fn create_shader_module(&self, spv: &[u32]) -> ShaderModule {
|
|
ShaderModule {
|
|
context: Arc::clone(&self.context),
|
|
id: Context::device_create_shader_module(&*self.context, &self.id, spv),
|
|
}
|
|
}
|
|
|
|
/// Creates an empty [`CommandEncoder`].
|
|
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(),
|
|
}
|
|
}
|
|
|
|
/// Creates a new bind group.
|
|
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),
|
|
}
|
|
}
|
|
|
|
/// Creates a bind group layout.
|
|
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),
|
|
}
|
|
}
|
|
|
|
/// Creates a pipeline layout.
|
|
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),
|
|
}
|
|
}
|
|
|
|
/// Creates a render pipeline.
|
|
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),
|
|
}
|
|
}
|
|
|
|
/// Creates a compute pipeline.
|
|
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),
|
|
}
|
|
}
|
|
|
|
/// Creates a new buffer.
|
|
pub fn create_buffer(&self, desc: &BufferDescriptor) -> Buffer {
|
|
Buffer {
|
|
context: Arc::clone(&self.context),
|
|
id: Context::device_create_buffer(&*self.context, &self.id, desc),
|
|
size: desc.size,
|
|
}
|
|
}
|
|
|
|
/// Creates a new buffer and maps it into host-visible memory.
|
|
///
|
|
/// This returns a [`CreateBufferMapped`], which exposes a `&mut [u8]`. The actual [`Buffer`]
|
|
/// will not be created until calling [`CreateBufferMapped::finish`].
|
|
pub fn create_buffer_mapped(&self, desc: &BufferDescriptor) -> CreateBufferMapped<'_> {
|
|
assert_ne!(desc.size, 0);
|
|
let (id, mapped_data, detail) =
|
|
Context::device_create_buffer_mapped(&*self.context, &self.id, desc);
|
|
CreateBufferMapped {
|
|
context: Arc::clone(&self.context),
|
|
id,
|
|
mapped_data,
|
|
detail,
|
|
}
|
|
}
|
|
|
|
/// Creates a new buffer, maps it into host-visible memory, copies data from the given slice,
|
|
/// and finally unmaps it, returning a [`Buffer`].
|
|
pub fn create_buffer_with_data(&self, data: &[u8], usage: BufferUsage) -> Buffer {
|
|
let mut mapped = self.create_buffer_mapped(&BufferDescriptor {
|
|
size: data.len() as u64,
|
|
usage,
|
|
label: None,
|
|
});
|
|
mapped.data().copy_from_slice(data);
|
|
mapped.finish()
|
|
}
|
|
|
|
/// Creates a new [`Texture`].
|
|
///
|
|
/// `desc` specifies the general format of the texture.
|
|
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,
|
|
}
|
|
}
|
|
|
|
/// Creates a new [`Sampler`].
|
|
///
|
|
/// `desc` specifies the behavior of the sampler.
|
|
pub fn create_sampler(&self, desc: &SamplerDescriptor) -> Sampler {
|
|
Sampler {
|
|
context: Arc::clone(&self.context),
|
|
id: Context::device_create_sampler(&*self.context, &self.id, desc),
|
|
}
|
|
}
|
|
|
|
/// Create a new [`SwapChain`] which targets `surface`.
|
|
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) {
|
|
self.context.device_drop(&self.id);
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
|
pub struct RequestDeviceError;
|
|
|
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
|
pub struct BufferAsyncError;
|
|
|
|
pub struct BufferReadMapping {
|
|
context: Arc<C>,
|
|
detail: <C as Context>::BufferReadMappingDetail,
|
|
}
|
|
|
|
unsafe impl Send for BufferReadMapping {}
|
|
unsafe impl Sync for BufferReadMapping {}
|
|
|
|
impl BufferReadMapping {
|
|
pub fn as_slice(&self) -> &[u8] {
|
|
self.detail.as_slice()
|
|
}
|
|
}
|
|
|
|
impl Drop for BufferReadMapping {
|
|
fn drop(&mut self) {
|
|
Context::buffer_unmap(&*self.context, &self.detail.buffer_id);
|
|
}
|
|
}
|
|
|
|
pub struct BufferWriteMapping {
|
|
context: Arc<C>,
|
|
detail: <C as Context>::BufferWriteMappingDetail,
|
|
}
|
|
|
|
unsafe impl Send for BufferWriteMapping {}
|
|
unsafe impl Sync for BufferWriteMapping {}
|
|
|
|
impl BufferWriteMapping {
|
|
pub fn as_slice(&mut self) -> &mut [u8] {
|
|
self.detail.as_slice()
|
|
}
|
|
}
|
|
|
|
impl Drop for BufferWriteMapping {
|
|
fn drop(&mut self) {
|
|
Context::buffer_unmap(&*self.context, &self.detail.buffer_id);
|
|
}
|
|
}
|
|
|
|
impl Buffer {
|
|
/// Use only a portion of this Buffer for a given operation. Choosing a range with 0 size will
|
|
/// return a slice that extends to the end of the buffer.
|
|
pub fn slice<S: RangeBounds<BufferAddress>>(&self, bounds: S) -> BufferSlice {
|
|
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,
|
|
};
|
|
BufferSlice {
|
|
buffer: self,
|
|
offset,
|
|
size,
|
|
}
|
|
}
|
|
|
|
/// Map the buffer for reading. The result is returned in a future.
|
|
///
|
|
/// For the future to complete, `device.poll(...)` must be called elsewhere in the runtime, possibly integrated
|
|
/// into an event loop, run on a separate thread, or continually polled in the same task runtime that this
|
|
/// future will be run on.
|
|
///
|
|
/// It's expected that wgpu will eventually supply its own event loop infrastructure that will be easy to integrate
|
|
/// into other event loops, like winit's.
|
|
pub fn map_read(
|
|
&self,
|
|
start: BufferAddress,
|
|
size: BufferSize,
|
|
) -> impl Future<Output = Result<BufferReadMapping, BufferAsyncError>> + Send {
|
|
let context = Arc::clone(&self.context);
|
|
let end = if size == BufferSize::WHOLE {
|
|
self.size
|
|
} else {
|
|
start + size.0
|
|
};
|
|
self.context
|
|
.buffer_map_read(&self.id, start..end)
|
|
.map(|result| result.map(|detail| BufferReadMapping { context, detail }))
|
|
}
|
|
|
|
/// Map the buffer for writing. The result is returned in a future.
|
|
///
|
|
/// See the documentation of (map_read)[#method.map_read] for more information about
|
|
/// how to run this future.
|
|
pub fn map_write(
|
|
&self,
|
|
start: BufferAddress,
|
|
size: BufferSize,
|
|
) -> impl Future<Output = Result<BufferWriteMapping, BufferAsyncError>> + Send {
|
|
let context = Arc::clone(&self.context);
|
|
let end = if size == BufferSize::WHOLE {
|
|
self.size
|
|
} else {
|
|
start + size.0
|
|
};
|
|
self.context
|
|
.buffer_map_write(&self.id, start..end)
|
|
.map(|result| result.map(|detail| BufferWriteMapping { context, detail }))
|
|
}
|
|
|
|
/// Flushes any pending write operations and unmaps the buffer from host memory.
|
|
pub fn unmap(&self) {
|
|
Context::buffer_unmap(&*self.context, &self.id);
|
|
}
|
|
}
|
|
|
|
impl Drop for Buffer {
|
|
fn drop(&mut self) {
|
|
self.context.buffer_drop(&self.id);
|
|
}
|
|
}
|
|
|
|
impl Texture {
|
|
/// Creates a view of this 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,
|
|
}
|
|
}
|
|
|
|
/// Creates a default view of this whole texture.
|
|
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 {
|
|
self.context.texture_drop(&self.id);
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Drop for TextureView {
|
|
fn drop(&mut self) {
|
|
if self.owned {
|
|
self.context.texture_view_drop(&self.id);
|
|
}
|
|
}
|
|
}
|
|
|
|
impl CommandEncoder {
|
|
/// Finishes recording and returns a [`CommandBuffer`] that can be submitted for execution.
|
|
pub fn finish(self) -> CommandBuffer {
|
|
CommandBuffer {
|
|
context: Arc::clone(&self.context),
|
|
id: Some(Context::encoder_finish(&*self.context, &self.id)),
|
|
}
|
|
}
|
|
|
|
/// Begins recording of a render pass.
|
|
///
|
|
/// This function returns a [`RenderPass`] object which records a single render pass.
|
|
pub fn begin_render_pass<'a>(
|
|
&'a mut self,
|
|
desc: &RenderPassDescriptor<'a, '_>,
|
|
) -> RenderPass<'a> {
|
|
RenderPass {
|
|
id: Context::encoder_begin_render_pass(&*self.context, &self.id, desc),
|
|
parent: self,
|
|
}
|
|
}
|
|
|
|
/// Begins recording of a compute pass.
|
|
///
|
|
/// This function returns a [`ComputePass`] object which records a single compute pass.
|
|
pub fn begin_compute_pass(&mut self) -> ComputePass {
|
|
ComputePass {
|
|
id: Context::encoder_begin_compute_pass(&*self.context, &self.id),
|
|
parent: self,
|
|
}
|
|
}
|
|
|
|
/// Copy data from one buffer to another.
|
|
pub fn copy_buffer_to_buffer(
|
|
&mut self,
|
|
source: &Buffer,
|
|
source_offset: BufferAddress,
|
|
destination: &Buffer,
|
|
destination_offset: BufferAddress,
|
|
copy_size: BufferAddress,
|
|
) {
|
|
Context::encoder_copy_buffer_to_buffer(
|
|
&*self.context,
|
|
&self.id,
|
|
&source.id,
|
|
source_offset,
|
|
&destination.id,
|
|
destination_offset,
|
|
copy_size,
|
|
);
|
|
}
|
|
|
|
/// Copy data from a buffer to a texture.
|
|
pub fn copy_buffer_to_texture(
|
|
&mut self,
|
|
source: BufferCopyView,
|
|
destination: TextureCopyView,
|
|
copy_size: Extent3d,
|
|
) {
|
|
Context::encoder_copy_buffer_to_texture(
|
|
&*self.context,
|
|
&self.id,
|
|
source,
|
|
destination,
|
|
copy_size,
|
|
);
|
|
}
|
|
|
|
/// Copy data from a texture to a buffer.
|
|
pub fn copy_texture_to_buffer(
|
|
&mut self,
|
|
source: TextureCopyView,
|
|
destination: BufferCopyView,
|
|
copy_size: Extent3d,
|
|
) {
|
|
Context::encoder_copy_texture_to_buffer(
|
|
&*self.context,
|
|
&self.id,
|
|
source,
|
|
destination,
|
|
copy_size,
|
|
);
|
|
}
|
|
|
|
/// Copy data from one texture to another.
|
|
pub fn copy_texture_to_texture(
|
|
&mut self,
|
|
source: TextureCopyView,
|
|
destination: TextureCopyView,
|
|
copy_size: Extent3d,
|
|
) {
|
|
Context::encoder_copy_texture_to_texture(
|
|
&*self.context,
|
|
&self.id,
|
|
source,
|
|
destination,
|
|
copy_size,
|
|
);
|
|
}
|
|
}
|
|
|
|
impl<'a> RenderPass<'a> {
|
|
/// Sets the active bind group for a given bind group index.
|
|
pub fn set_bind_group(
|
|
&mut self,
|
|
index: u32,
|
|
bind_group: &'a BindGroup,
|
|
offsets: &[DynamicOffset],
|
|
) {
|
|
RenderPassInner::set_bind_group(&mut self.id, index, &bind_group.id, offsets)
|
|
}
|
|
|
|
/// Sets the active render pipeline.
|
|
///
|
|
/// Subsequent draw calls will exhibit the behavior defined by `pipeline`.
|
|
pub fn set_pipeline(&mut self, pipeline: &'a RenderPipeline) {
|
|
RenderPassInner::set_pipeline(&mut self.id, &pipeline.id)
|
|
}
|
|
|
|
pub fn set_blend_color(&mut self, color: Color) {
|
|
self.id.set_blend_color(color)
|
|
}
|
|
|
|
/// Sets the active index buffer.
|
|
///
|
|
/// Subsequent calls to [`draw_indexed`](RenderPass::draw_indexed) on this [`RenderPass`] will
|
|
/// use `buffer` as the source index buffer.
|
|
pub fn set_index_buffer(&mut self, buffer_slice: BufferSlice<'a>) {
|
|
RenderPassInner::set_index_buffer(
|
|
&mut self.id,
|
|
&buffer_slice.buffer.id,
|
|
buffer_slice.offset,
|
|
buffer_slice.size,
|
|
)
|
|
}
|
|
|
|
/// Assign a vertex buffer to a slot.
|
|
///
|
|
/// Subsequent calls to [`draw`] and [`draw_indexed`] on this
|
|
/// [`RenderPass`] will use `buffer` as one of the source vertex buffers.
|
|
///
|
|
/// The `slot` refers to the index of the matching descriptor in
|
|
/// [`RenderPipelineDescriptor::vertex_buffers`].
|
|
///
|
|
/// [`draw`]: #method.draw
|
|
/// [`draw_indexed`]: #method.draw_indexed
|
|
/// [`RenderPass`]: struct.RenderPass.html
|
|
/// [`RenderPipelineDescriptor::vertex_buffers`]: struct.RenderPipelineDescriptor.html#structfield.vertex_buffers
|
|
pub fn set_vertex_buffer(&mut self, slot: u32, buffer_slice: BufferSlice<'a>) {
|
|
RenderPassInner::set_vertex_buffer(
|
|
&mut self.id,
|
|
slot,
|
|
&buffer_slice.buffer.id,
|
|
buffer_slice.offset,
|
|
buffer_slice.size,
|
|
)
|
|
}
|
|
|
|
/// Sets the scissor region.
|
|
///
|
|
/// Subsequent draw calls will discard any fragments that fall outside this region.
|
|
pub fn set_scissor_rect(&mut self, x: u32, y: u32, width: u32, height: u32) {
|
|
self.id.set_scissor_rect(x, y, width, height);
|
|
}
|
|
|
|
/// Sets the viewport region.
|
|
///
|
|
/// Subsequent draw calls will draw any fragments in this region.
|
|
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);
|
|
}
|
|
|
|
/// Sets the stencil reference.
|
|
///
|
|
/// Subsequent stencil tests will test against this value.
|
|
pub fn set_stencil_reference(&mut self, reference: u32) {
|
|
self.id.set_stencil_reference(reference);
|
|
}
|
|
|
|
/// Draws primitives from the active vertex buffer(s).
|
|
///
|
|
/// The active vertex buffers can be set with [`RenderPass::set_vertex_buffer`].
|
|
pub fn draw(&mut self, vertices: Range<u32>, instances: Range<u32>) {
|
|
RenderPassInner::draw(&mut self.id, vertices, instances)
|
|
}
|
|
|
|
/// Draws indexed primitives using the active index buffer and the active vertex buffers.
|
|
///
|
|
/// The active index buffer can be set with [`RenderPass::set_index_buffer`], while the active
|
|
/// vertex buffers can be set with [`RenderPass::set_vertex_buffer`].
|
|
pub fn draw_indexed(&mut self, indices: Range<u32>, base_vertex: i32, instances: Range<u32>) {
|
|
RenderPassInner::draw_indexed(&mut self.id, indices, base_vertex, instances);
|
|
}
|
|
|
|
/// Draws primitives from the active vertex buffer(s) based on the contents of the `indirect_buffer`.
|
|
///
|
|
/// The active vertex buffers can be set with [`RenderPass::set_vertex_buffer`].
|
|
///
|
|
/// The structure expected in `indirect_buffer` is the following:
|
|
///
|
|
/// ```rust
|
|
/// #[repr(C)]
|
|
/// struct DrawIndirect {
|
|
/// vertex_count: u32, // The number of vertices to draw.
|
|
/// instance_count: u32, // The number of instances to draw.
|
|
/// base_vertex: u32, // The Index of the first vertex to draw.
|
|
/// base_instance: u32, // The instance ID of the first instance to draw.
|
|
/// }
|
|
/// ```
|
|
pub fn draw_indirect(&mut self, indirect_buffer: &'a Buffer, indirect_offset: BufferAddress) {
|
|
self.id.draw_indirect(&indirect_buffer.id, indirect_offset);
|
|
}
|
|
|
|
/// Draws indexed primitives using the active index buffer and the active vertex buffers,
|
|
/// based on the contents of the `indirect_buffer`.
|
|
///
|
|
/// The active index buffer can be set with [`RenderPass::set_index_buffer`], while the active
|
|
/// vertex buffers can be set with [`RenderPass::set_vertex_buffer`].
|
|
///
|
|
/// The structure expected in `indirect_buffer` is the following:
|
|
///
|
|
/// ```rust
|
|
/// #[repr(C)]
|
|
/// struct DrawIndexedIndirect {
|
|
/// vertex_count: u32, // The number of vertices to draw.
|
|
/// instance_count: u32, // The number of instances to draw.
|
|
/// base_index: u32, // The base index within the index buffer.
|
|
/// vertex_offset: i32, // The value added to the vertex index before indexing into the vertex buffer.
|
|
/// base_instance: u32, // The instance ID of the first instance to draw.
|
|
/// }
|
|
/// ```
|
|
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> Drop for RenderPass<'a> {
|
|
fn drop(&mut self) {
|
|
if !thread::panicking() {
|
|
self.parent
|
|
.context
|
|
.encoder_end_render_pass(&self.parent.id, &mut self.id);
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a> ComputePass<'a> {
|
|
/// Sets the active bind group for a given bind group index.
|
|
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);
|
|
}
|
|
|
|
/// Sets the active compute pipeline.
|
|
pub fn set_pipeline(&mut self, pipeline: &'a ComputePipeline) {
|
|
ComputePassInner::set_pipeline(&mut self.id, &pipeline.id);
|
|
}
|
|
|
|
/// Dispatches compute work operations.
|
|
///
|
|
/// `x`, `y` and `z` denote the number of work groups to dispatch in each dimension.
|
|
pub fn dispatch(&mut self, x: u32, y: u32, z: u32) {
|
|
ComputePassInner::dispatch(&mut self.id, x, y, z);
|
|
}
|
|
|
|
/// Dispatches compute work operations, based on the contents of the `indirect_buffer`.
|
|
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
|
|
.encoder_end_compute_pass(&self.parent.id, &mut self.id);
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Queue {
|
|
/// Schedule a data write into `buffer` starting at `offset`.
|
|
pub fn write_buffer(&self, buffer: &Buffer, offset: BufferAddress, data: &[u8]) {
|
|
Context::queue_write_buffer(&*self.context, &self.id, &buffer.id, offset, data)
|
|
}
|
|
|
|
/// Schedule a data write into `texture`.
|
|
pub fn write_texture(
|
|
&self,
|
|
texture: TextureCopyView,
|
|
data: &[u8],
|
|
data_layout: wgt::TextureDataLayout,
|
|
size: wgt::Extent3d,
|
|
) {
|
|
Context::queue_write_texture(&*self.context, &self.id, texture, data, data_layout, size)
|
|
}
|
|
|
|
/// Submits a series of finished command buffers for execution.
|
|
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 {
|
|
/// Returns the next texture to be presented by the swapchain for drawing.
|
|
///
|
|
/// When the [`SwapChainOutput`] returned by this method is dropped, the swapchain will present
|
|
/// the texture to the associated [`Surface`].
|
|
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),
|
|
}
|
|
}
|
|
}
|