wgpu/lib.rs
1//! A cross-platform graphics and compute library based on [WebGPU](https://gpuweb.github.io/gpuweb/).
2//!
3//! To start using the API, create an [`Instance`].
4
5#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
6#![doc(html_logo_url = "https://raw.githubusercontent.com/gfx-rs/wgpu/master/logo.png")]
7#![warn(missing_docs, unsafe_op_in_unsafe_fn)]
8
9mod backend;
10mod context;
11pub mod util;
12#[macro_use]
13mod macros;
14
15use std::{
16 any::Any,
17 borrow::Cow,
18 error,
19 fmt::{Debug, Display},
20 future::Future,
21 marker::PhantomData,
22 num::NonZeroU32,
23 ops::{Bound, Deref, DerefMut, Range, RangeBounds},
24 sync::Arc,
25 thread,
26};
27
28use context::{Context, DeviceRequest, DynContext, ObjectId};
29use parking_lot::Mutex;
30
31pub use wgt::{
32 AdapterInfo, AddressMode, AstcBlock, AstcChannel, Backend, Backends, BindGroupLayoutEntry,
33 BindingType, BlendComponent, BlendFactor, BlendOperation, BlendState, BufferAddress,
34 BufferBindingType, BufferSize, BufferUsages, Color, ColorTargetState, ColorWrites,
35 CommandBufferDescriptor, CompareFunction, CompositeAlphaMode, DepthBiasState,
36 DepthStencilState, DeviceType, DownlevelCapabilities, DownlevelFlags, Dx12Compiler,
37 DynamicOffset, Extent3d, Face, Features, FilterMode, FrontFace, ImageDataLayout,
38 ImageSubresourceRange, IndexFormat, InstanceDescriptor, Limits, MultisampleState, Origin2d,
39 Origin3d, PipelineStatisticsTypes, PolygonMode, PowerPreference, PredefinedColorSpace,
40 PresentMode, PresentationTimestamp, PrimitiveState, PrimitiveTopology, PushConstantRange,
41 QueryType, RenderBundleDepthStencil, SamplerBindingType, SamplerBorderColor, ShaderLocation,
42 ShaderModel, ShaderStages, StencilFaceState, StencilOperation, StencilState,
43 StorageTextureAccess, SurfaceCapabilities, SurfaceStatus, TextureAspect, TextureDimension,
44 TextureFormat, TextureFormatFeatureFlags, TextureFormatFeatures, TextureSampleType,
45 TextureUsages, TextureViewDimension, VertexAttribute, VertexFormat, VertexStepMode,
46 WasmNotSend, WasmNotSync, COPY_BUFFER_ALIGNMENT, COPY_BYTES_PER_ROW_ALIGNMENT, MAP_ALIGNMENT,
47 PUSH_CONSTANT_ALIGNMENT, QUERY_RESOLVE_BUFFER_ALIGNMENT, QUERY_SET_MAX_QUERIES, QUERY_SIZE,
48 VERTEX_STRIDE_ALIGNMENT,
49};
50
51#[cfg(any(
52 not(target_arch = "wasm32"),
53 feature = "webgl",
54 target_os = "emscripten"
55))]
56#[doc(hidden)]
57pub use ::hal;
58#[cfg(any(
59 not(target_arch = "wasm32"),
60 feature = "webgl",
61 target_os = "emscripten"
62))]
63#[doc(hidden)]
64pub use ::wgc as core;
65
66// wasm-only types, we try to keep as many types non-platform
67// specific, but these need to depend on web-sys.
68#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
69pub use wgt::{ExternalImageSource, ImageCopyExternalImage};
70
71/// Filter for error scopes.
72#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd)]
73pub enum ErrorFilter {
74 /// Catch only out-of-memory errors.
75 OutOfMemory,
76 /// Catch only validation errors.
77 Validation,
78}
79static_assertions::assert_impl_all!(ErrorFilter: Send, Sync);
80
81type C = dyn DynContext;
82#[cfg(any(
83 not(target_arch = "wasm32"),
84 all(
85 feature = "fragile-send-sync-non-atomic-wasm",
86 not(target_feature = "atomics")
87 )
88))]
89type Data = dyn Any + Send + Sync;
90#[cfg(not(any(
91 not(target_arch = "wasm32"),
92 all(
93 feature = "fragile-send-sync-non-atomic-wasm",
94 not(target_feature = "atomics")
95 )
96)))]
97type Data = dyn Any;
98
99/// Context for all other wgpu objects. Instance of wgpu.
100///
101/// This is the first thing you create when using wgpu.
102/// Its primary use is to create [`Adapter`]s and [`Surface`]s.
103///
104/// Does not have to be kept alive.
105///
106/// Corresponds to [WebGPU `GPU`](https://gpuweb.github.io/gpuweb/#gpu-interface).
107#[derive(Debug)]
108pub struct Instance {
109 context: Arc<C>,
110}
111#[cfg(any(
112 not(target_arch = "wasm32"),
113 all(
114 feature = "fragile-send-sync-non-atomic-wasm",
115 not(target_feature = "atomics")
116 )
117))]
118static_assertions::assert_impl_all!(Instance: Send, Sync);
119
120/// Handle to a physical graphics and/or compute device.
121///
122/// Adapters can be used to open a connection to the corresponding [`Device`]
123/// on the host system by using [`Adapter::request_device`].
124///
125/// Does not have to be kept alive.
126///
127/// Corresponds to [WebGPU `GPUAdapter`](https://gpuweb.github.io/gpuweb/#gpu-adapter).
128#[derive(Debug)]
129pub struct Adapter {
130 context: Arc<C>,
131 id: ObjectId,
132 data: Box<Data>,
133}
134#[cfg(any(
135 not(target_arch = "wasm32"),
136 all(
137 feature = "fragile-send-sync-non-atomic-wasm",
138 not(target_feature = "atomics")
139 )
140))]
141static_assertions::assert_impl_all!(Adapter: Send, Sync);
142
143impl Drop for Adapter {
144 fn drop(&mut self) {
145 if !thread::panicking() {
146 self.context.adapter_drop(&self.id, self.data.as_ref())
147 }
148 }
149}
150
151/// Open connection to a graphics and/or compute device.
152///
153/// Responsible for the creation of most rendering and compute resources.
154/// These are then used in commands, which are submitted to a [`Queue`].
155///
156/// A device may be requested from an adapter with [`Adapter::request_device`].
157///
158/// Corresponds to [WebGPU `GPUDevice`](https://gpuweb.github.io/gpuweb/#gpu-device).
159#[derive(Debug)]
160pub struct Device {
161 context: Arc<C>,
162 id: ObjectId,
163 data: Box<Data>,
164}
165#[cfg(any(
166 not(target_arch = "wasm32"),
167 all(
168 feature = "fragile-send-sync-non-atomic-wasm",
169 not(target_feature = "atomics")
170 )
171))]
172static_assertions::assert_impl_all!(Device: Send, Sync);
173
174/// Identifier for a particular call to [`Queue::submit`]. Can be used
175/// as part of an argument to [`Device::poll`] to block for a particular
176/// submission to finish.
177///
178/// This type is unique to the Rust API of `wgpu`.
179/// There is no analogue in the WebGPU specification.
180#[derive(Debug, Clone)]
181pub struct SubmissionIndex(ObjectId, Arc<crate::Data>);
182#[cfg(any(
183 not(target_arch = "wasm32"),
184 all(
185 feature = "fragile-send-sync-non-atomic-wasm",
186 not(target_feature = "atomics")
187 )
188))]
189static_assertions::assert_impl_all!(SubmissionIndex: Send, Sync);
190
191/// The main purpose of this struct is to resolve mapped ranges (convert sizes
192/// to end points), and to ensure that the sub-ranges don't intersect.
193#[derive(Debug)]
194struct MapContext {
195 total_size: BufferAddress,
196 initial_range: Range<BufferAddress>,
197 sub_ranges: Vec<Range<BufferAddress>>,
198}
199
200impl MapContext {
201 fn new(total_size: BufferAddress) -> Self {
202 Self {
203 total_size,
204 initial_range: 0..0,
205 sub_ranges: Vec::new(),
206 }
207 }
208
209 fn reset(&mut self) {
210 self.initial_range = 0..0;
211
212 assert!(
213 self.sub_ranges.is_empty(),
214 "You cannot unmap a buffer that still has accessible mapped views"
215 );
216 }
217
218 fn add(&mut self, offset: BufferAddress, size: Option<BufferSize>) -> BufferAddress {
219 let end = match size {
220 Some(s) => offset + s.get(),
221 None => self.initial_range.end,
222 };
223 assert!(self.initial_range.start <= offset && end <= self.initial_range.end);
224 for sub in self.sub_ranges.iter() {
225 assert!(
226 end <= sub.start || offset >= sub.end,
227 "Intersecting map range with {sub:?}"
228 );
229 }
230 self.sub_ranges.push(offset..end);
231 end
232 }
233
234 fn remove(&mut self, offset: BufferAddress, size: Option<BufferSize>) {
235 let end = match size {
236 Some(s) => offset + s.get(),
237 None => self.initial_range.end,
238 };
239
240 let index = self
241 .sub_ranges
242 .iter()
243 .position(|r| *r == (offset..end))
244 .expect("unable to remove range from map context");
245 self.sub_ranges.swap_remove(index);
246 }
247}
248
249/// Handle to a GPU-accessible buffer.
250///
251/// Created with [`Device::create_buffer`] or
252/// [`DeviceExt::create_buffer_init`](util::DeviceExt::create_buffer_init).
253///
254/// Corresponds to [WebGPU `GPUBuffer`](https://gpuweb.github.io/gpuweb/#buffer-interface).
255#[derive(Debug)]
256pub struct Buffer {
257 context: Arc<C>,
258 id: ObjectId,
259 data: Box<Data>,
260 map_context: Mutex<MapContext>,
261 size: wgt::BufferAddress,
262 usage: BufferUsages,
263 // Todo: missing map_state https://www.w3.org/TR/webgpu/#dom-gpubuffer-mapstate
264}
265#[cfg(any(
266 not(target_arch = "wasm32"),
267 all(
268 feature = "fragile-send-sync-non-atomic-wasm",
269 not(target_feature = "atomics")
270 )
271))]
272static_assertions::assert_impl_all!(Buffer: Send, Sync);
273
274/// Slice into a [`Buffer`].
275///
276/// It can be created with [`Buffer::slice`]. To use the whole buffer, call with unbounded slice:
277///
278/// `buffer.slice(..)`
279///
280/// This type is unique to the Rust API of `wgpu`. In the WebGPU specification,
281/// an offset and size are specified as arguments to each call working with the [`Buffer`], instead.
282#[derive(Copy, Clone, Debug)]
283pub struct BufferSlice<'a> {
284 buffer: &'a Buffer,
285 offset: BufferAddress,
286 size: Option<BufferSize>,
287}
288#[cfg(any(
289 not(target_arch = "wasm32"),
290 all(
291 feature = "fragile-send-sync-non-atomic-wasm",
292 not(target_feature = "atomics")
293 )
294))]
295static_assertions::assert_impl_all!(BufferSlice: Send, Sync);
296
297/// Handle to a texture on the GPU.
298///
299/// It can be created with [`Device::create_texture`].
300///
301/// Corresponds to [WebGPU `GPUTexture`](https://gpuweb.github.io/gpuweb/#texture-interface).
302#[derive(Debug)]
303pub struct Texture {
304 context: Arc<C>,
305 id: ObjectId,
306 data: Box<Data>,
307 owned: bool,
308 descriptor: TextureDescriptor<'static>,
309}
310#[cfg(any(
311 not(target_arch = "wasm32"),
312 all(
313 feature = "fragile-send-sync-non-atomic-wasm",
314 not(target_feature = "atomics")
315 )
316))]
317static_assertions::assert_impl_all!(Texture: Send, Sync);
318
319/// Handle to a texture view.
320///
321/// A `TextureView` object describes a texture and associated metadata needed by a
322/// [`RenderPipeline`] or [`BindGroup`].
323///
324/// Corresponds to [WebGPU `GPUTextureView`](https://gpuweb.github.io/gpuweb/#gputextureview).
325#[derive(Debug)]
326pub struct TextureView {
327 context: Arc<C>,
328 id: ObjectId,
329 data: Box<Data>,
330}
331#[cfg(any(
332 not(target_arch = "wasm32"),
333 all(
334 feature = "fragile-send-sync-non-atomic-wasm",
335 not(target_feature = "atomics")
336 )
337))]
338static_assertions::assert_impl_all!(TextureView: Send, Sync);
339
340/// Handle to a sampler.
341///
342/// A `Sampler` object defines how a pipeline will sample from a [`TextureView`]. Samplers define
343/// image filters (including anisotropy) and address (wrapping) modes, among other things. See
344/// the documentation for [`SamplerDescriptor`] for more information.
345///
346/// It can be created with [`Device::create_sampler`].
347///
348/// Corresponds to [WebGPU `GPUSampler`](https://gpuweb.github.io/gpuweb/#sampler-interface).
349#[derive(Debug)]
350pub struct Sampler {
351 context: Arc<C>,
352 id: ObjectId,
353 data: Box<Data>,
354}
355#[cfg(any(
356 not(target_arch = "wasm32"),
357 all(
358 feature = "fragile-send-sync-non-atomic-wasm",
359 not(target_feature = "atomics")
360 )
361))]
362static_assertions::assert_impl_all!(Sampler: Send, Sync);
363
364impl Drop for Sampler {
365 fn drop(&mut self) {
366 if !thread::panicking() {
367 self.context.sampler_drop(&self.id, self.data.as_ref());
368 }
369 }
370}
371
372/// Describes a [`Surface`].
373///
374/// For use with [`Surface::configure`].
375///
376/// Corresponds to [WebGPU `GPUCanvasConfiguration`](
377/// https://gpuweb.github.io/gpuweb/#canvas-configuration).
378pub type SurfaceConfiguration = wgt::SurfaceConfiguration<Vec<TextureFormat>>;
379static_assertions::assert_impl_all!(SurfaceConfiguration: Send, Sync);
380
381/// Handle to a presentable surface.
382///
383/// A `Surface` represents a platform-specific surface (e.g. a window) onto which rendered images may
384/// be presented. A `Surface` may be created with the unsafe function [`Instance::create_surface`].
385///
386/// This type is unique to the Rust API of `wgpu`. In the WebGPU specification,
387/// [`GPUCanvasContext`](https://gpuweb.github.io/gpuweb/#canvas-context)
388/// serves a similar role.
389#[derive(Debug)]
390pub struct Surface {
391 context: Arc<C>,
392 id: ObjectId,
393 data: Box<Data>,
394 // Stores the latest `SurfaceConfiguration` that was set using `Surface::configure`.
395 // It is required to set the attributes of the `SurfaceTexture` in the
396 // `Surface::get_current_texture` method.
397 // Because the `Surface::configure` method operates on an immutable reference this type has to
398 // be wrapped in a mutex and since the configuration is only supplied after the surface has
399 // been created is is additionally wrapped in an option.
400 config: Mutex<Option<SurfaceConfiguration>>,
401}
402#[cfg(any(
403 not(target_arch = "wasm32"),
404 all(
405 feature = "fragile-send-sync-non-atomic-wasm",
406 not(target_feature = "atomics")
407 )
408))]
409static_assertions::assert_impl_all!(Surface: Send, Sync);
410
411impl Drop for Surface {
412 fn drop(&mut self) {
413 if !thread::panicking() {
414 self.context.surface_drop(&self.id, self.data.as_ref())
415 }
416 }
417}
418
419/// Handle to a binding group layout.
420///
421/// A `BindGroupLayout` is a handle to the GPU-side layout of a binding group. It can be used to
422/// create a [`BindGroupDescriptor`] object, which in turn can be used to create a [`BindGroup`]
423/// object with [`Device::create_bind_group`]. A series of `BindGroupLayout`s can also be used to
424/// create a [`PipelineLayoutDescriptor`], which can be used to create a [`PipelineLayout`].
425///
426/// It can be created with [`Device::create_bind_group_layout`].
427///
428/// Corresponds to [WebGPU `GPUBindGroupLayout`](
429/// https://gpuweb.github.io/gpuweb/#gpubindgrouplayout).
430#[derive(Debug)]
431pub struct BindGroupLayout {
432 context: Arc<C>,
433 id: ObjectId,
434 data: Box<Data>,
435}
436#[cfg(any(
437 not(target_arch = "wasm32"),
438 all(
439 feature = "fragile-send-sync-non-atomic-wasm",
440 not(target_feature = "atomics")
441 )
442))]
443static_assertions::assert_impl_all!(BindGroupLayout: Send, Sync);
444
445impl Drop for BindGroupLayout {
446 fn drop(&mut self) {
447 if !thread::panicking() {
448 self.context
449 .bind_group_layout_drop(&self.id, self.data.as_ref());
450 }
451 }
452}
453
454/// Handle to a binding group.
455///
456/// A `BindGroup` represents the set of resources bound to the bindings described by a
457/// [`BindGroupLayout`]. It can be created with [`Device::create_bind_group`]. A `BindGroup` can
458/// be bound to a particular [`RenderPass`] with [`RenderPass::set_bind_group`], or to a
459/// [`ComputePass`] with [`ComputePass::set_bind_group`].
460///
461/// Corresponds to [WebGPU `GPUBindGroup`](https://gpuweb.github.io/gpuweb/#gpubindgroup).
462#[derive(Debug)]
463pub struct BindGroup {
464 context: Arc<C>,
465 id: ObjectId,
466 data: Box<Data>,
467}
468#[cfg(any(
469 not(target_arch = "wasm32"),
470 all(
471 feature = "fragile-send-sync-non-atomic-wasm",
472 not(target_feature = "atomics")
473 )
474))]
475static_assertions::assert_impl_all!(BindGroup: Send, Sync);
476
477impl Drop for BindGroup {
478 fn drop(&mut self) {
479 if !thread::panicking() {
480 self.context.bind_group_drop(&self.id, self.data.as_ref());
481 }
482 }
483}
484
485/// Handle to a compiled shader module.
486///
487/// A `ShaderModule` represents a compiled shader module on the GPU. It can be created by passing
488/// source code to [`Device::create_shader_module`] or valid SPIR-V binary to
489/// [`Device::create_shader_module_spirv`]. Shader modules are used to define programmable stages
490/// of a pipeline.
491///
492/// Corresponds to [WebGPU `GPUShaderModule`](https://gpuweb.github.io/gpuweb/#shader-module).
493#[derive(Debug)]
494pub struct ShaderModule {
495 context: Arc<C>,
496 id: ObjectId,
497 data: Box<Data>,
498}
499#[cfg(any(
500 not(target_arch = "wasm32"),
501 all(
502 feature = "fragile-send-sync-non-atomic-wasm",
503 not(target_feature = "atomics")
504 )
505))]
506static_assertions::assert_impl_all!(ShaderModule: Send, Sync);
507
508impl Drop for ShaderModule {
509 fn drop(&mut self) {
510 if !thread::panicking() {
511 self.context
512 .shader_module_drop(&self.id, self.data.as_ref());
513 }
514 }
515}
516
517/// Source of a shader module.
518///
519/// The source will be parsed and validated.
520///
521/// Any necessary shader translation (e.g. from WGSL to SPIR-V or vice versa)
522/// will be done internally by wgpu.
523///
524/// This type is unique to the Rust API of `wgpu`. In the WebGPU specification,
525/// only WGSL source code strings are accepted.
526#[cfg_attr(feature = "naga", allow(clippy::large_enum_variant))]
527#[derive(Clone)]
528#[non_exhaustive]
529pub enum ShaderSource<'a> {
530 /// SPIR-V module represented as a slice of words.
531 ///
532 /// See also: [`util::make_spirv`], [`include_spirv`]
533 #[cfg(feature = "spirv")]
534 SpirV(Cow<'a, [u32]>),
535 /// GLSL module as a string slice.
536 ///
537 /// Note: GLSL is not yet fully supported and must be a specific ShaderStage.
538 #[cfg(feature = "glsl")]
539 Glsl {
540 /// The source code of the shader.
541 shader: Cow<'a, str>,
542 /// The shader stage that the shader targets. For example, `naga::ShaderStage::Vertex`
543 stage: naga::ShaderStage,
544 /// Defines to unlock configured shader features.
545 defines: naga::FastHashMap<String, String>,
546 },
547 /// WGSL module as a string slice.
548 #[cfg(feature = "wgsl")]
549 Wgsl(Cow<'a, str>),
550 /// Naga module.
551 #[cfg(feature = "naga")]
552 Naga(Cow<'static, naga::Module>),
553 /// Dummy variant because `Naga` doesn't have a lifetime and without enough active features it
554 /// could be the last one active.
555 #[doc(hidden)]
556 Dummy(PhantomData<&'a ()>),
557}
558static_assertions::assert_impl_all!(ShaderSource: Send, Sync);
559
560/// Descriptor for use with [`Device::create_shader_module`].
561///
562/// Corresponds to [WebGPU `GPUShaderModuleDescriptor`](
563/// https://gpuweb.github.io/gpuweb/#dictdef-gpushadermoduledescriptor).
564#[derive(Clone)]
565pub struct ShaderModuleDescriptor<'a> {
566 /// Debug label of the shader module. This will show up in graphics debuggers for easy identification.
567 pub label: Label<'a>,
568 /// Source code for the shader.
569 pub source: ShaderSource<'a>,
570}
571static_assertions::assert_impl_all!(ShaderModuleDescriptor: Send, Sync);
572
573/// Descriptor for a shader module given by SPIR-V binary, for use with
574/// [`Device::create_shader_module_spirv`].
575///
576/// This type is unique to the Rust API of `wgpu`. In the WebGPU specification,
577/// only WGSL source code strings are accepted.
578pub struct ShaderModuleDescriptorSpirV<'a> {
579 /// Debug label of the shader module. This will show up in graphics debuggers for easy identification.
580 pub label: Label<'a>,
581 /// Binary SPIR-V data, in 4-byte words.
582 pub source: Cow<'a, [u32]>,
583}
584static_assertions::assert_impl_all!(ShaderModuleDescriptorSpirV: Send, Sync);
585
586/// Handle to a pipeline layout.
587///
588/// A `PipelineLayout` object describes the available binding groups of a pipeline.
589/// It can be created with [`Device::create_pipeline_layout`].
590///
591/// Corresponds to [WebGPU `GPUPipelineLayout`](https://gpuweb.github.io/gpuweb/#gpupipelinelayout).
592#[derive(Debug)]
593pub struct PipelineLayout {
594 context: Arc<C>,
595 id: ObjectId,
596 data: Box<Data>,
597}
598#[cfg(any(
599 not(target_arch = "wasm32"),
600 all(
601 feature = "fragile-send-sync-non-atomic-wasm",
602 not(target_feature = "atomics")
603 )
604))]
605static_assertions::assert_impl_all!(PipelineLayout: Send, Sync);
606
607impl Drop for PipelineLayout {
608 fn drop(&mut self) {
609 if !thread::panicking() {
610 self.context
611 .pipeline_layout_drop(&self.id, self.data.as_ref());
612 }
613 }
614}
615
616/// Handle to a rendering (graphics) pipeline.
617///
618/// A `RenderPipeline` object represents a graphics pipeline and its stages, bindings, vertex
619/// buffers and targets. It can be created with [`Device::create_render_pipeline`].
620///
621/// Corresponds to [WebGPU `GPURenderPipeline`](https://gpuweb.github.io/gpuweb/#render-pipeline).
622#[derive(Debug)]
623pub struct RenderPipeline {
624 context: Arc<C>,
625 id: ObjectId,
626 data: Box<Data>,
627}
628#[cfg(any(
629 not(target_arch = "wasm32"),
630 all(
631 feature = "fragile-send-sync-non-atomic-wasm",
632 not(target_feature = "atomics")
633 )
634))]
635static_assertions::assert_impl_all!(RenderPipeline: Send, Sync);
636
637impl Drop for RenderPipeline {
638 fn drop(&mut self) {
639 if !thread::panicking() {
640 self.context
641 .render_pipeline_drop(&self.id, self.data.as_ref());
642 }
643 }
644}
645
646impl RenderPipeline {
647 /// Get an object representing the bind group layout at a given index.
648 pub fn get_bind_group_layout(&self, index: u32) -> BindGroupLayout {
649 let context = Arc::clone(&self.context);
650 let (id, data) =
651 self.context
652 .render_pipeline_get_bind_group_layout(&self.id, self.data.as_ref(), index);
653 BindGroupLayout { context, id, data }
654 }
655}
656
657/// Handle to a compute pipeline.
658///
659/// A `ComputePipeline` object represents a compute pipeline and its single shader stage.
660/// It can be created with [`Device::create_compute_pipeline`].
661///
662/// Corresponds to [WebGPU `GPUComputePipeline`](https://gpuweb.github.io/gpuweb/#compute-pipeline).
663#[derive(Debug)]
664pub struct ComputePipeline {
665 context: Arc<C>,
666 id: ObjectId,
667 data: Box<Data>,
668}
669#[cfg(any(
670 not(target_arch = "wasm32"),
671 all(
672 feature = "fragile-send-sync-non-atomic-wasm",
673 not(target_feature = "atomics")
674 )
675))]
676static_assertions::assert_impl_all!(ComputePipeline: Send, Sync);
677
678impl Drop for ComputePipeline {
679 fn drop(&mut self) {
680 if !thread::panicking() {
681 self.context
682 .compute_pipeline_drop(&self.id, self.data.as_ref());
683 }
684 }
685}
686
687impl ComputePipeline {
688 /// Get an object representing the bind group layout at a given index.
689 pub fn get_bind_group_layout(&self, index: u32) -> BindGroupLayout {
690 let context = Arc::clone(&self.context);
691 let (id, data) = self.context.compute_pipeline_get_bind_group_layout(
692 &self.id,
693 self.data.as_ref(),
694 index,
695 );
696 BindGroupLayout { context, id, data }
697 }
698}
699
700/// Handle to a command buffer on the GPU.
701///
702/// A `CommandBuffer` represents a complete sequence of commands that may be submitted to a command
703/// queue with [`Queue::submit`]. A `CommandBuffer` is obtained by recording a series of commands to
704/// a [`CommandEncoder`] and then calling [`CommandEncoder::finish`].
705///
706/// Corresponds to [WebGPU `GPUCommandBuffer`](https://gpuweb.github.io/gpuweb/#command-buffer).
707#[derive(Debug)]
708pub struct CommandBuffer {
709 context: Arc<C>,
710 id: Option<ObjectId>,
711 data: Option<Box<Data>>,
712}
713#[cfg(any(
714 not(target_arch = "wasm32"),
715 all(
716 feature = "fragile-send-sync-non-atomic-wasm",
717 not(target_feature = "atomics")
718 )
719))]
720static_assertions::assert_impl_all!(CommandBuffer: Send, Sync);
721
722impl Drop for CommandBuffer {
723 fn drop(&mut self) {
724 if !thread::panicking() {
725 if let Some(id) = self.id.take() {
726 self.context
727 .command_buffer_drop(&id, self.data.take().unwrap().as_ref());
728 }
729 }
730 }
731}
732
733/// Encodes a series of GPU operations.
734///
735/// A command encoder can record [`RenderPass`]es, [`ComputePass`]es,
736/// and transfer operations between driver-managed resources like [`Buffer`]s and [`Texture`]s.
737///
738/// When finished recording, call [`CommandEncoder::finish`] to obtain a [`CommandBuffer`] which may
739/// be submitted for execution.
740///
741/// Corresponds to [WebGPU `GPUCommandEncoder`](https://gpuweb.github.io/gpuweb/#command-encoder).
742#[derive(Debug)]
743pub struct CommandEncoder {
744 context: Arc<C>,
745 id: Option<ObjectId>,
746 data: Box<Data>,
747}
748#[cfg(any(
749 not(target_arch = "wasm32"),
750 all(
751 feature = "fragile-send-sync-non-atomic-wasm",
752 not(target_feature = "atomics")
753 )
754))]
755static_assertions::assert_impl_all!(CommandEncoder: Send, Sync);
756
757impl Drop for CommandEncoder {
758 fn drop(&mut self) {
759 if !thread::panicking() {
760 if let Some(id) = self.id.take() {
761 self.context.command_encoder_drop(&id, self.data.as_ref());
762 }
763 }
764 }
765}
766
767/// In-progress recording of a render pass.
768///
769/// It can be created with [`CommandEncoder::begin_render_pass`].
770///
771/// Corresponds to [WebGPU `GPURenderPassEncoder`](
772/// https://gpuweb.github.io/gpuweb/#render-pass-encoder).
773#[derive(Debug)]
774pub struct RenderPass<'a> {
775 id: ObjectId,
776 data: Box<Data>,
777 parent: &'a mut CommandEncoder,
778}
779
780/// In-progress recording of a compute pass.
781///
782/// It can be created with [`CommandEncoder::begin_compute_pass`].
783///
784/// Corresponds to [WebGPU `GPUComputePassEncoder`](
785/// https://gpuweb.github.io/gpuweb/#compute-pass-encoder).
786#[derive(Debug)]
787pub struct ComputePass<'a> {
788 id: ObjectId,
789 data: Box<Data>,
790 parent: &'a mut CommandEncoder,
791}
792
793/// Encodes a series of GPU operations into a reusable "render bundle".
794///
795/// It only supports a handful of render commands, but it makes them reusable.
796/// It can be created with [`Device::create_render_bundle_encoder`].
797/// It can be executed onto a [`CommandEncoder`] using [`RenderPass::execute_bundles`].
798///
799/// Executing a [`RenderBundle`] is often more efficient than issuing the underlying commands
800/// manually.
801///
802/// Corresponds to [WebGPU `GPURenderBundleEncoder`](
803/// https://gpuweb.github.io/gpuweb/#gpurenderbundleencoder).
804#[derive(Debug)]
805pub struct RenderBundleEncoder<'a> {
806 context: Arc<C>,
807 id: ObjectId,
808 data: Box<Data>,
809 parent: &'a Device,
810 /// This type should be !Send !Sync, because it represents an allocation on this thread's
811 /// command buffer.
812 _p: PhantomData<*const u8>,
813}
814static_assertions::assert_not_impl_any!(RenderBundleEncoder<'_>: Send, Sync);
815
816/// Pre-prepared reusable bundle of GPU operations.
817///
818/// It only supports a handful of render commands, but it makes them reusable. Executing a
819/// [`RenderBundle`] is often more efficient than issuing the underlying commands manually.
820///
821/// It can be created by use of a [`RenderBundleEncoder`], and executed onto a [`CommandEncoder`]
822/// using [`RenderPass::execute_bundles`].
823///
824/// Corresponds to [WebGPU `GPURenderBundle`](https://gpuweb.github.io/gpuweb/#render-bundle).
825#[derive(Debug)]
826pub struct RenderBundle {
827 context: Arc<C>,
828 id: ObjectId,
829 data: Box<Data>,
830}
831#[cfg(any(
832 not(target_arch = "wasm32"),
833 all(
834 feature = "fragile-send-sync-non-atomic-wasm",
835 not(target_feature = "atomics")
836 )
837))]
838static_assertions::assert_impl_all!(RenderBundle: Send, Sync);
839
840impl Drop for RenderBundle {
841 fn drop(&mut self) {
842 if !thread::panicking() {
843 self.context
844 .render_bundle_drop(&self.id, self.data.as_ref());
845 }
846 }
847}
848
849/// Handle to a query set.
850///
851/// It can be created with [`Device::create_query_set`].
852///
853/// Corresponds to [WebGPU `GPUQuerySet`](https://gpuweb.github.io/gpuweb/#queryset).
854pub struct QuerySet {
855 context: Arc<C>,
856 id: ObjectId,
857 data: Box<Data>,
858}
859#[cfg(any(
860 not(target_arch = "wasm32"),
861 all(
862 feature = "fragile-send-sync-non-atomic-wasm",
863 not(target_feature = "atomics")
864 )
865))]
866static_assertions::assert_impl_all!(QuerySet: Send, Sync);
867
868impl Drop for QuerySet {
869 fn drop(&mut self) {
870 if !thread::panicking() {
871 self.context.query_set_drop(&self.id, self.data.as_ref());
872 }
873 }
874}
875
876/// Handle to a command queue on a device.
877///
878/// A `Queue` executes recorded [`CommandBuffer`] objects and provides convenience methods
879/// for writing to [buffers](Queue::write_buffer) and [textures](Queue::write_texture).
880/// It can be created along with a [`Device`] by calling [`Adapter::request_device`].
881///
882/// Corresponds to [WebGPU `GPUQueue`](https://gpuweb.github.io/gpuweb/#gpu-queue).
883#[derive(Debug)]
884pub struct Queue {
885 context: Arc<C>,
886 id: ObjectId,
887 data: Box<Data>,
888}
889#[cfg(any(
890 not(target_arch = "wasm32"),
891 all(
892 feature = "fragile-send-sync-non-atomic-wasm",
893 not(target_feature = "atomics")
894 )
895))]
896static_assertions::assert_impl_all!(Queue: Send, Sync);
897
898/// Resource that can be bound to a pipeline.
899///
900/// Corresponds to [WebGPU `GPUBindingResource`](
901/// https://gpuweb.github.io/gpuweb/#typedefdef-gpubindingresource).
902#[non_exhaustive]
903#[derive(Clone, Debug)]
904pub enum BindingResource<'a> {
905 /// Binding is backed by a buffer.
906 ///
907 /// Corresponds to [`wgt::BufferBindingType::Uniform`] and [`wgt::BufferBindingType::Storage`]
908 /// with [`BindGroupLayoutEntry::count`] set to None.
909 Buffer(BufferBinding<'a>),
910 /// Binding is backed by an array of buffers.
911 ///
912 /// [`Features::BUFFER_BINDING_ARRAY`] must be supported to use this feature.
913 ///
914 /// Corresponds to [`wgt::BufferBindingType::Uniform`] and [`wgt::BufferBindingType::Storage`]
915 /// with [`BindGroupLayoutEntry::count`] set to Some.
916 BufferArray(&'a [BufferBinding<'a>]),
917 /// Binding is a sampler.
918 ///
919 /// Corresponds to [`wgt::BindingType::Sampler`] with [`BindGroupLayoutEntry::count`] set to None.
920 Sampler(&'a Sampler),
921 /// Binding is backed by an array of samplers.
922 ///
923 /// [`Features::TEXTURE_BINDING_ARRAY`] must be supported to use this feature.
924 ///
925 /// Corresponds to [`wgt::BindingType::Sampler`] with [`BindGroupLayoutEntry::count`] set
926 /// to Some.
927 SamplerArray(&'a [&'a Sampler]),
928 /// Binding is backed by a texture.
929 ///
930 /// Corresponds to [`wgt::BindingType::Texture`] and [`wgt::BindingType::StorageTexture`] with
931 /// [`BindGroupLayoutEntry::count`] set to None.
932 TextureView(&'a TextureView),
933 /// Binding is backed by an array of textures.
934 ///
935 /// [`Features::TEXTURE_BINDING_ARRAY`] must be supported to use this feature.
936 ///
937 /// Corresponds to [`wgt::BindingType::Texture`] and [`wgt::BindingType::StorageTexture`] with
938 /// [`BindGroupLayoutEntry::count`] set to Some.
939 TextureViewArray(&'a [&'a TextureView]),
940}
941#[cfg(any(
942 not(target_arch = "wasm32"),
943 all(
944 feature = "fragile-send-sync-non-atomic-wasm",
945 not(target_feature = "atomics")
946 )
947))]
948static_assertions::assert_impl_all!(BindingResource: Send, Sync);
949
950/// Describes the segment of a buffer to bind.
951///
952/// Corresponds to [WebGPU `GPUBufferBinding`](
953/// https://gpuweb.github.io/gpuweb/#dictdef-gpubufferbinding).
954#[derive(Clone, Debug)]
955pub struct BufferBinding<'a> {
956 /// The buffer to bind.
957 pub buffer: &'a Buffer,
958
959 /// Base offset of the buffer, in bytes.
960 ///
961 /// If the [`has_dynamic_offset`] field of this buffer's layout entry is
962 /// `true`, the offset here will be added to the dynamic offset passed to
963 /// [`RenderPass::set_bind_group`] or [`ComputePass::set_bind_group`].
964 ///
965 /// If the buffer was created with [`BufferUsages::UNIFORM`], then this
966 /// offset must be a multiple of
967 /// [`Limits::min_uniform_buffer_offset_alignment`].
968 ///
969 /// If the buffer was created with [`BufferUsages::STORAGE`], then this
970 /// offset must be a multiple of
971 /// [`Limits::min_storage_buffer_offset_alignment`].
972 ///
973 /// [`has_dynamic_offset`]: BindingType::Buffer::has_dynamic_offset
974 pub offset: BufferAddress,
975
976 /// Size of the binding in bytes, or `None` for using the rest of the buffer.
977 pub size: Option<BufferSize>,
978}
979#[cfg(any(
980 not(target_arch = "wasm32"),
981 all(
982 feature = "fragile-send-sync-non-atomic-wasm",
983 not(target_feature = "atomics")
984 )
985))]
986static_assertions::assert_impl_all!(BufferBinding: Send, Sync);
987
988/// Operation to perform to the output attachment at the start of a render pass.
989///
990/// The render target must be cleared at least once before its content is loaded.
991///
992/// Corresponds to [WebGPU `GPULoadOp`](https://gpuweb.github.io/gpuweb/#enumdef-gpuloadop).
993#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
994#[cfg_attr(feature = "trace", derive(serde::Serialize))]
995#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
996pub enum LoadOp<V> {
997 /// Clear with a specified value.
998 Clear(V),
999 /// Load from memory.
1000 Load,
1001}
1002
1003impl<V: Default> Default for LoadOp<V> {
1004 fn default() -> Self {
1005 Self::Clear(Default::default())
1006 }
1007}
1008
1009/// Pair of load and store operations for an attachment aspect.
1010///
1011/// This type is unique to the Rust API of `wgpu`. In the WebGPU specification,
1012/// separate `loadOp` and `storeOp` fields are used instead.
1013#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
1014#[cfg_attr(feature = "trace", derive(serde::Serialize))]
1015#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
1016pub struct Operations<V> {
1017 /// How data should be read through this attachment.
1018 pub load: LoadOp<V>,
1019 /// Whether data will be written to through this attachment.
1020 pub store: bool,
1021}
1022
1023impl<V: Default> Default for Operations<V> {
1024 fn default() -> Self {
1025 Self {
1026 load: Default::default(),
1027 store: true,
1028 }
1029 }
1030}
1031
1032/// Describes a color attachment to a [`RenderPass`].
1033///
1034/// For use with [`RenderPassDescriptor`].
1035///
1036/// Corresponds to [WebGPU `GPURenderPassColorAttachment`](
1037/// https://gpuweb.github.io/gpuweb/#color-attachments).
1038#[derive(Clone, Debug)]
1039pub struct RenderPassColorAttachment<'tex> {
1040 /// The view to use as an attachment.
1041 pub view: &'tex TextureView,
1042 /// The view that will receive the resolved output if multisampling is used.
1043 pub resolve_target: Option<&'tex TextureView>,
1044 /// What operations will be performed on this color attachment.
1045 pub ops: Operations<Color>,
1046}
1047#[cfg(any(
1048 not(target_arch = "wasm32"),
1049 all(
1050 feature = "fragile-send-sync-non-atomic-wasm",
1051 not(target_feature = "atomics")
1052 )
1053))]
1054static_assertions::assert_impl_all!(RenderPassColorAttachment: Send, Sync);
1055
1056/// Describes a depth/stencil attachment to a [`RenderPass`].
1057///
1058/// For use with [`RenderPassDescriptor`].
1059///
1060/// Corresponds to [WebGPU `GPURenderPassDepthStencilAttachment`](
1061/// https://gpuweb.github.io/gpuweb/#depth-stencil-attachments).
1062#[derive(Clone, Debug)]
1063pub struct RenderPassDepthStencilAttachment<'tex> {
1064 /// The view to use as an attachment.
1065 pub view: &'tex TextureView,
1066 /// What operations will be performed on the depth part of the attachment.
1067 pub depth_ops: Option<Operations<f32>>,
1068 /// What operations will be performed on the stencil part of the attachment.
1069 pub stencil_ops: Option<Operations<u32>>,
1070}
1071#[cfg(any(
1072 not(target_arch = "wasm32"),
1073 all(
1074 feature = "fragile-send-sync-non-atomic-wasm",
1075 not(target_feature = "atomics")
1076 )
1077))]
1078static_assertions::assert_impl_all!(RenderPassDepthStencilAttachment: Send, Sync);
1079
1080// The underlying types are also exported so that documentation shows up for them
1081
1082/// Object debugging label.
1083pub type Label<'a> = Option<&'a str>;
1084pub use wgt::RequestAdapterOptions as RequestAdapterOptionsBase;
1085/// Additional information required when requesting an adapter.
1086///
1087/// For use with [`Instance::request_adapter`].
1088///
1089/// Corresponds to [WebGPU `GPURequestAdapterOptions`](
1090/// https://gpuweb.github.io/gpuweb/#dictdef-gpurequestadapteroptions).
1091pub type RequestAdapterOptions<'a> = RequestAdapterOptionsBase<&'a Surface>;
1092#[cfg(any(
1093 not(target_arch = "wasm32"),
1094 all(
1095 feature = "fragile-send-sync-non-atomic-wasm",
1096 not(target_feature = "atomics")
1097 )
1098))]
1099static_assertions::assert_impl_all!(RequestAdapterOptions: Send, Sync);
1100/// Describes a [`Device`].
1101///
1102/// For use with [`Adapter::request_device`].
1103///
1104/// Corresponds to [WebGPU `GPUDeviceDescriptor`](
1105/// https://gpuweb.github.io/gpuweb/#dictdef-gpudevicedescriptor).
1106pub type DeviceDescriptor<'a> = wgt::DeviceDescriptor<Label<'a>>;
1107static_assertions::assert_impl_all!(DeviceDescriptor: Send, Sync);
1108/// Describes a [`Buffer`].
1109///
1110/// For use with [`Device::create_buffer`].
1111///
1112/// Corresponds to [WebGPU `GPUBufferDescriptor`](
1113/// https://gpuweb.github.io/gpuweb/#dictdef-gpubufferdescriptor).
1114pub type BufferDescriptor<'a> = wgt::BufferDescriptor<Label<'a>>;
1115static_assertions::assert_impl_all!(BufferDescriptor: Send, Sync);
1116/// Describes a [`CommandEncoder`].
1117///
1118/// For use with [`Device::create_command_encoder`].
1119///
1120/// Corresponds to [WebGPU `GPUCommandEncoderDescriptor`](
1121/// https://gpuweb.github.io/gpuweb/#dictdef-gpucommandencoderdescriptor).
1122pub type CommandEncoderDescriptor<'a> = wgt::CommandEncoderDescriptor<Label<'a>>;
1123static_assertions::assert_impl_all!(CommandEncoderDescriptor: Send, Sync);
1124/// Describes a [`RenderBundle`].
1125///
1126/// For use with [`RenderBundleEncoder::finish`].
1127///
1128/// Corresponds to [WebGPU `GPURenderBundleDescriptor`](
1129/// https://gpuweb.github.io/gpuweb/#dictdef-gpurenderbundledescriptor).
1130pub type RenderBundleDescriptor<'a> = wgt::RenderBundleDescriptor<Label<'a>>;
1131static_assertions::assert_impl_all!(RenderBundleDescriptor: Send, Sync);
1132/// Describes a [`Texture`].
1133///
1134/// For use with [`Device::create_texture`].
1135///
1136/// Corresponds to [WebGPU `GPUTextureDescriptor`](
1137/// https://gpuweb.github.io/gpuweb/#dictdef-gputexturedescriptor).
1138pub type TextureDescriptor<'a> = wgt::TextureDescriptor<Label<'a>, &'a [TextureFormat]>;
1139static_assertions::assert_impl_all!(TextureDescriptor: Send, Sync);
1140/// Describes a [`QuerySet`].
1141///
1142/// For use with [`Device::create_query_set`].
1143///
1144/// Corresponds to [WebGPU `GPUQuerySetDescriptor`](
1145/// https://gpuweb.github.io/gpuweb/#dictdef-gpuquerysetdescriptor).
1146pub type QuerySetDescriptor<'a> = wgt::QuerySetDescriptor<Label<'a>>;
1147static_assertions::assert_impl_all!(QuerySetDescriptor: Send, Sync);
1148pub use wgt::Maintain as MaintainBase;
1149/// Passed to [`Device::poll`] to control how and if it should block.
1150pub type Maintain = wgt::Maintain<SubmissionIndex>;
1151#[cfg(any(
1152 not(target_arch = "wasm32"),
1153 all(
1154 feature = "fragile-send-sync-non-atomic-wasm",
1155 not(target_feature = "atomics")
1156 )
1157))]
1158static_assertions::assert_impl_all!(Maintain: Send, Sync);
1159
1160/// Describes a [`TextureView`].
1161///
1162/// For use with [`Texture::create_view`].
1163///
1164/// Corresponds to [WebGPU `GPUTextureViewDescriptor`](
1165/// https://gpuweb.github.io/gpuweb/#dictdef-gputextureviewdescriptor).
1166#[derive(Clone, Debug, Default, Eq, PartialEq)]
1167pub struct TextureViewDescriptor<'a> {
1168 /// Debug label of the texture view. This will show up in graphics debuggers for easy identification.
1169 pub label: Label<'a>,
1170 /// Format of the texture view. Either must be the same as the texture format or in the list
1171 /// of `view_formats` in the texture's descriptor.
1172 pub format: Option<TextureFormat>,
1173 /// The dimension of the texture view. For 1D textures, this must be `D1`. For 2D textures it must be one of
1174 /// `D2`, `D2Array`, `Cube`, and `CubeArray`. For 3D textures it must be `D3`
1175 pub dimension: Option<TextureViewDimension>,
1176 /// Aspect of the texture. Color textures must be [`TextureAspect::All`].
1177 pub aspect: TextureAspect,
1178 /// Base mip level.
1179 pub base_mip_level: u32,
1180 /// Mip level count.
1181 /// If `Some(count)`, `base_mip_level + count` must be less or equal to underlying texture mip count.
1182 /// If `None`, considered to include the rest of the mipmap levels, but at least 1 in total.
1183 pub mip_level_count: Option<u32>,
1184 /// Base array layer.
1185 pub base_array_layer: u32,
1186 /// Layer count.
1187 /// If `Some(count)`, `base_array_layer + count` must be less or equal to the underlying array count.
1188 /// If `None`, considered to include the rest of the array layers, but at least 1 in total.
1189 pub array_layer_count: Option<u32>,
1190}
1191static_assertions::assert_impl_all!(TextureViewDescriptor: Send, Sync);
1192
1193/// Describes a [`PipelineLayout`].
1194///
1195/// For use with [`Device::create_pipeline_layout`].
1196///
1197/// Corresponds to [WebGPU `GPUPipelineLayoutDescriptor`](
1198/// https://gpuweb.github.io/gpuweb/#dictdef-gpupipelinelayoutdescriptor).
1199#[derive(Clone, Debug, Default)]
1200pub struct PipelineLayoutDescriptor<'a> {
1201 /// Debug label of the pipeline layout. This will show up in graphics debuggers for easy identification.
1202 pub label: Label<'a>,
1203 /// Bind groups that this pipeline uses. The first entry will provide all the bindings for
1204 /// "set = 0", second entry will provide all the bindings for "set = 1" etc.
1205 pub bind_group_layouts: &'a [&'a BindGroupLayout],
1206 /// Set of push constant ranges this pipeline uses. Each shader stage that uses push constants
1207 /// must define the range in push constant memory that corresponds to its single `layout(push_constant)`
1208 /// uniform block.
1209 ///
1210 /// If this array is non-empty, the [`Features::PUSH_CONSTANTS`] must be enabled.
1211 pub push_constant_ranges: &'a [PushConstantRange],
1212}
1213#[cfg(any(
1214 not(target_arch = "wasm32"),
1215 all(
1216 feature = "fragile-send-sync-non-atomic-wasm",
1217 not(target_feature = "atomics")
1218 )
1219))]
1220static_assertions::assert_impl_all!(PipelineLayoutDescriptor: Send, Sync);
1221
1222/// Describes a [`Sampler`].
1223///
1224/// For use with [`Device::create_sampler`].
1225///
1226/// Corresponds to [WebGPU `GPUSamplerDescriptor`](
1227/// https://gpuweb.github.io/gpuweb/#dictdef-gpusamplerdescriptor).
1228#[derive(Clone, Debug, PartialEq)]
1229pub struct SamplerDescriptor<'a> {
1230 /// Debug label of the sampler. This will show up in graphics debuggers for easy identification.
1231 pub label: Label<'a>,
1232 /// How to deal with out of bounds accesses in the u (i.e. x) direction
1233 pub address_mode_u: AddressMode,
1234 /// How to deal with out of bounds accesses in the v (i.e. y) direction
1235 pub address_mode_v: AddressMode,
1236 /// How to deal with out of bounds accesses in the w (i.e. z) direction
1237 pub address_mode_w: AddressMode,
1238 /// How to filter the texture when it needs to be magnified (made larger)
1239 pub mag_filter: FilterMode,
1240 /// How to filter the texture when it needs to be minified (made smaller)
1241 pub min_filter: FilterMode,
1242 /// How to filter between mip map levels
1243 pub mipmap_filter: FilterMode,
1244 /// Minimum level of detail (i.e. mip level) to use
1245 pub lod_min_clamp: f32,
1246 /// Maximum level of detail (i.e. mip level) to use
1247 pub lod_max_clamp: f32,
1248 /// If this is enabled, this is a comparison sampler using the given comparison function.
1249 pub compare: Option<CompareFunction>,
1250 /// Must be at least 1. If this is not 1, all filter modes must be linear.
1251 pub anisotropy_clamp: u16,
1252 /// Border color to use when address_mode is [`AddressMode::ClampToBorder`]
1253 pub border_color: Option<SamplerBorderColor>,
1254}
1255static_assertions::assert_impl_all!(SamplerDescriptor: Send, Sync);
1256
1257impl Default for SamplerDescriptor<'_> {
1258 fn default() -> Self {
1259 Self {
1260 label: None,
1261 address_mode_u: Default::default(),
1262 address_mode_v: Default::default(),
1263 address_mode_w: Default::default(),
1264 mag_filter: Default::default(),
1265 min_filter: Default::default(),
1266 mipmap_filter: Default::default(),
1267 lod_min_clamp: 0.0,
1268 lod_max_clamp: 32.0,
1269 compare: None,
1270 anisotropy_clamp: 1,
1271 border_color: None,
1272 }
1273 }
1274}
1275
1276/// An element of a [`BindGroupDescriptor`], consisting of a bindable resource
1277/// and the slot to bind it to.
1278///
1279/// Corresponds to [WebGPU `GPUBindGroupEntry`](
1280/// https://gpuweb.github.io/gpuweb/#dictdef-gpubindgroupentry).
1281#[derive(Clone, Debug)]
1282pub struct BindGroupEntry<'a> {
1283 /// Slot for which binding provides resource. Corresponds to an entry of the same
1284 /// binding index in the [`BindGroupLayoutDescriptor`].
1285 pub binding: u32,
1286 /// Resource to attach to the binding
1287 pub resource: BindingResource<'a>,
1288}
1289#[cfg(any(
1290 not(target_arch = "wasm32"),
1291 all(
1292 feature = "fragile-send-sync-non-atomic-wasm",
1293 not(target_feature = "atomics")
1294 )
1295))]
1296static_assertions::assert_impl_all!(BindGroupEntry: Send, Sync);
1297
1298/// Describes a group of bindings and the resources to be bound.
1299///
1300/// For use with [`Device::create_bind_group`].
1301///
1302/// Corresponds to [WebGPU `GPUBindGroupDescriptor`](
1303/// https://gpuweb.github.io/gpuweb/#dictdef-gpubindgroupdescriptor).
1304#[derive(Clone, Debug)]
1305pub struct BindGroupDescriptor<'a> {
1306 /// Debug label of the bind group. This will show up in graphics debuggers for easy identification.
1307 pub label: Label<'a>,
1308 /// The [`BindGroupLayout`] that corresponds to this bind group.
1309 pub layout: &'a BindGroupLayout,
1310 /// The resources to bind to this bind group.
1311 pub entries: &'a [BindGroupEntry<'a>],
1312}
1313#[cfg(any(
1314 not(target_arch = "wasm32"),
1315 all(
1316 feature = "fragile-send-sync-non-atomic-wasm",
1317 not(target_feature = "atomics")
1318 )
1319))]
1320static_assertions::assert_impl_all!(BindGroupDescriptor: Send, Sync);
1321
1322/// Describes the attachments of a render pass.
1323///
1324/// For use with [`CommandEncoder::begin_render_pass`].
1325///
1326/// Note: separate lifetimes are needed because the texture views (`'tex`)
1327/// have to live as long as the pass is recorded, while everything else (`'desc`) doesn't.
1328///
1329/// Corresponds to [WebGPU `GPURenderPassDescriptor`](
1330/// https://gpuweb.github.io/gpuweb/#dictdef-gpurenderpassdescriptor).
1331#[derive(Clone, Debug, Default)]
1332pub struct RenderPassDescriptor<'tex, 'desc> {
1333 /// Debug label of the render pass. This will show up in graphics debuggers for easy identification.
1334 pub label: Label<'desc>,
1335 /// The color attachments of the render pass.
1336 pub color_attachments: &'desc [Option<RenderPassColorAttachment<'tex>>],
1337 /// The depth and stencil attachment of the render pass, if any.
1338 pub depth_stencil_attachment: Option<RenderPassDepthStencilAttachment<'tex>>,
1339}
1340#[cfg(any(
1341 not(target_arch = "wasm32"),
1342 all(
1343 feature = "fragile-send-sync-non-atomic-wasm",
1344 not(target_feature = "atomics")
1345 )
1346))]
1347static_assertions::assert_impl_all!(RenderPassDescriptor: Send, Sync);
1348
1349/// Describes how the vertex buffer is interpreted.
1350///
1351/// For use in [`VertexState`].
1352///
1353/// Corresponds to [WebGPU `GPUVertexBufferLayout`](
1354/// https://gpuweb.github.io/gpuweb/#dictdef-gpuvertexbufferlayout).
1355#[derive(Clone, Debug, Hash, Eq, PartialEq)]
1356pub struct VertexBufferLayout<'a> {
1357 /// The stride, in bytes, between elements of this buffer.
1358 pub array_stride: BufferAddress,
1359 /// How often this vertex buffer is "stepped" forward.
1360 pub step_mode: VertexStepMode,
1361 /// The list of attributes which comprise a single vertex.
1362 pub attributes: &'a [VertexAttribute],
1363}
1364static_assertions::assert_impl_all!(VertexBufferLayout: Send, Sync);
1365
1366/// Describes the vertex processing in a render pipeline.
1367///
1368/// For use in [`RenderPipelineDescriptor`].
1369///
1370/// Corresponds to [WebGPU `GPUVertexState`](
1371/// https://gpuweb.github.io/gpuweb/#dictdef-gpuvertexstate).
1372#[derive(Clone, Debug)]
1373pub struct VertexState<'a> {
1374 /// The compiled shader module for this stage.
1375 pub module: &'a ShaderModule,
1376 /// The name of the entry point in the compiled shader. There must be a function with this name
1377 /// in the shader.
1378 pub entry_point: &'a str,
1379 /// The format of any vertex buffers used with this pipeline.
1380 pub buffers: &'a [VertexBufferLayout<'a>],
1381}
1382#[cfg(any(
1383 not(target_arch = "wasm32"),
1384 all(
1385 feature = "fragile-send-sync-non-atomic-wasm",
1386 not(target_feature = "atomics")
1387 )
1388))]
1389static_assertions::assert_impl_all!(VertexState: Send, Sync);
1390
1391/// Describes the fragment processing in a render pipeline.
1392///
1393/// For use in [`RenderPipelineDescriptor`].
1394///
1395/// Corresponds to [WebGPU `GPUFragmentState`](
1396/// https://gpuweb.github.io/gpuweb/#dictdef-gpufragmentstate).
1397#[derive(Clone, Debug)]
1398pub struct FragmentState<'a> {
1399 /// The compiled shader module for this stage.
1400 pub module: &'a ShaderModule,
1401 /// The name of the entry point in the compiled shader. There must be a function with this name
1402 /// in the shader.
1403 pub entry_point: &'a str,
1404 /// The color state of the render targets.
1405 pub targets: &'a [Option<ColorTargetState>],
1406}
1407#[cfg(any(
1408 not(target_arch = "wasm32"),
1409 all(
1410 feature = "fragile-send-sync-non-atomic-wasm",
1411 not(target_feature = "atomics")
1412 )
1413))]
1414static_assertions::assert_impl_all!(FragmentState: Send, Sync);
1415
1416/// Describes a render (graphics) pipeline.
1417///
1418/// For use with [`Device::create_render_pipeline`].
1419///
1420/// Corresponds to [WebGPU `GPURenderPipelineDescriptor`](
1421/// https://gpuweb.github.io/gpuweb/#dictdef-gpurenderpipelinedescriptor).
1422#[derive(Clone, Debug)]
1423pub struct RenderPipelineDescriptor<'a> {
1424 /// Debug label of the pipeline. This will show up in graphics debuggers for easy identification.
1425 pub label: Label<'a>,
1426 /// The layout of bind groups for this pipeline.
1427 pub layout: Option<&'a PipelineLayout>,
1428 /// The compiled vertex stage, its entry point, and the input buffers layout.
1429 pub vertex: VertexState<'a>,
1430 /// The properties of the pipeline at the primitive assembly and rasterization level.
1431 pub primitive: PrimitiveState,
1432 /// The effect of draw calls on the depth and stencil aspects of the output target, if any.
1433 pub depth_stencil: Option<DepthStencilState>,
1434 /// The multi-sampling properties of the pipeline.
1435 pub multisample: MultisampleState,
1436 /// The compiled fragment stage, its entry point, and the color targets.
1437 pub fragment: Option<FragmentState<'a>>,
1438 /// If the pipeline will be used with a multiview render pass, this indicates how many array
1439 /// layers the attachments will have.
1440 pub multiview: Option<NonZeroU32>,
1441}
1442#[cfg(any(
1443 not(target_arch = "wasm32"),
1444 all(
1445 feature = "fragile-send-sync-non-atomic-wasm",
1446 not(target_feature = "atomics")
1447 )
1448))]
1449static_assertions::assert_impl_all!(RenderPipelineDescriptor: Send, Sync);
1450
1451/// Describes the attachments of a compute pass.
1452///
1453/// For use with [`CommandEncoder::begin_compute_pass`].
1454///
1455/// Corresponds to [WebGPU `GPUComputePassDescriptor`](
1456/// https://gpuweb.github.io/gpuweb/#dictdef-gpucomputepassdescriptor).
1457#[derive(Clone, Debug, Default)]
1458pub struct ComputePassDescriptor<'a> {
1459 /// Debug label of the compute pass. This will show up in graphics debuggers for easy identification.
1460 pub label: Label<'a>,
1461}
1462static_assertions::assert_impl_all!(ComputePassDescriptor: Send, Sync);
1463
1464/// Describes a compute pipeline.
1465///
1466/// For use with [`Device::create_compute_pipeline`].
1467///
1468/// Corresponds to [WebGPU `GPUComputePipelineDescriptor`](
1469/// https://gpuweb.github.io/gpuweb/#dictdef-gpucomputepipelinedescriptor).
1470#[derive(Clone, Debug)]
1471pub struct ComputePipelineDescriptor<'a> {
1472 /// Debug label of the pipeline. This will show up in graphics debuggers for easy identification.
1473 pub label: Label<'a>,
1474 /// The layout of bind groups for this pipeline.
1475 pub layout: Option<&'a PipelineLayout>,
1476 /// The compiled shader module for this stage.
1477 pub module: &'a ShaderModule,
1478 /// The name of the entry point in the compiled shader. There must be a function with this name
1479 /// and no return value in the shader.
1480 pub entry_point: &'a str,
1481}
1482#[cfg(any(
1483 not(target_arch = "wasm32"),
1484 all(
1485 feature = "fragile-send-sync-non-atomic-wasm",
1486 not(target_feature = "atomics")
1487 )
1488))]
1489static_assertions::assert_impl_all!(ComputePipelineDescriptor: Send, Sync);
1490
1491pub use wgt::ImageCopyBuffer as ImageCopyBufferBase;
1492/// View of a buffer which can be used to copy to/from a texture.
1493///
1494/// Corresponds to [WebGPU `GPUImageCopyBuffer`](
1495/// https://gpuweb.github.io/gpuweb/#dictdef-gpuimagecopybuffer).
1496pub type ImageCopyBuffer<'a> = ImageCopyBufferBase<&'a Buffer>;
1497#[cfg(any(
1498 not(target_arch = "wasm32"),
1499 all(
1500 feature = "fragile-send-sync-non-atomic-wasm",
1501 not(target_feature = "atomics")
1502 )
1503))]
1504static_assertions::assert_impl_all!(ImageCopyBuffer: Send, Sync);
1505
1506pub use wgt::ImageCopyTexture as ImageCopyTextureBase;
1507/// View of a texture which can be used to copy to/from a buffer/texture.
1508///
1509/// Corresponds to [WebGPU `GPUImageCopyTexture`](
1510/// https://gpuweb.github.io/gpuweb/#dictdef-gpuimagecopytexture).
1511pub type ImageCopyTexture<'a> = ImageCopyTextureBase<&'a Texture>;
1512#[cfg(any(
1513 not(target_arch = "wasm32"),
1514 all(
1515 feature = "fragile-send-sync-non-atomic-wasm",
1516 not(target_feature = "atomics")
1517 )
1518))]
1519static_assertions::assert_impl_all!(ImageCopyTexture: Send, Sync);
1520
1521pub use wgt::ImageCopyTextureTagged as ImageCopyTextureTaggedBase;
1522/// View of a texture which can be used to copy to a texture, including
1523/// color space and alpha premultiplication information.
1524///
1525/// Corresponds to [WebGPU `GPUImageCopyTextureTagged`](
1526/// https://gpuweb.github.io/gpuweb/#dictdef-gpuimagecopytexturetagged).
1527pub type ImageCopyTextureTagged<'a> = ImageCopyTextureTaggedBase<&'a Texture>;
1528#[cfg(any(
1529 not(target_arch = "wasm32"),
1530 all(
1531 feature = "fragile-send-sync-non-atomic-wasm",
1532 not(target_feature = "atomics")
1533 )
1534))]
1535static_assertions::assert_impl_all!(ImageCopyTexture: Send, Sync);
1536
1537/// Describes a [`BindGroupLayout`].
1538///
1539/// For use with [`Device::create_bind_group_layout`].
1540///
1541/// Corresponds to [WebGPU `GPUBindGroupLayoutDescriptor`](
1542/// https://gpuweb.github.io/gpuweb/#dictdef-gpubindgrouplayoutdescriptor).
1543#[derive(Clone, Debug)]
1544pub struct BindGroupLayoutDescriptor<'a> {
1545 /// Debug label of the bind group layout. This will show up in graphics debuggers for easy identification.
1546 pub label: Label<'a>,
1547
1548 /// Array of entries in this BindGroupLayout
1549 pub entries: &'a [BindGroupLayoutEntry],
1550}
1551static_assertions::assert_impl_all!(BindGroupLayoutDescriptor: Send, Sync);
1552
1553/// Describes a [`RenderBundleEncoder`].
1554///
1555/// For use with [`Device::create_render_bundle_encoder`].
1556///
1557/// Corresponds to [WebGPU `GPURenderBundleEncoderDescriptor`](
1558/// https://gpuweb.github.io/gpuweb/#dictdef-gpurenderbundleencoderdescriptor).
1559#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
1560pub struct RenderBundleEncoderDescriptor<'a> {
1561 /// Debug label of the render bundle encoder. This will show up in graphics debuggers for easy identification.
1562 pub label: Label<'a>,
1563 /// The formats of the color attachments that this render bundle is capable to rendering to. This
1564 /// must match the formats of the color attachments in the render pass this render bundle is executed in.
1565 pub color_formats: &'a [Option<TextureFormat>],
1566 /// Information about the depth attachment that this render bundle is capable to rendering to. This
1567 /// must match the format of the depth attachments in the render pass this render bundle is executed in.
1568 pub depth_stencil: Option<RenderBundleDepthStencil>,
1569 /// Sample count this render bundle is capable of rendering to. This must match the pipelines and
1570 /// the render passes it is used in.
1571 pub sample_count: u32,
1572 /// If this render bundle will rendering to multiple array layers in the attachments at the same time.
1573 pub multiview: Option<NonZeroU32>,
1574}
1575static_assertions::assert_impl_all!(RenderBundleEncoderDescriptor: Send, Sync);
1576
1577/// Surface texture that can be rendered to.
1578/// Result of a successful call to [`Surface::get_current_texture`].
1579///
1580/// This type is unique to the Rust API of `wgpu`. In the WebGPU specification,
1581/// the [`GPUCanvasContext`](https://gpuweb.github.io/gpuweb/#canvas-context) provides
1582/// a texture without any additional information.
1583#[derive(Debug)]
1584pub struct SurfaceTexture {
1585 /// Accessible view of the frame.
1586 pub texture: Texture,
1587 /// `true` if the acquired buffer can still be used for rendering,
1588 /// but should be recreated for maximum performance.
1589 pub suboptimal: bool,
1590 presented: bool,
1591 detail: Box<dyn AnyWasmNotSendSync>,
1592}
1593#[cfg(any(
1594 not(target_arch = "wasm32"),
1595 all(
1596 feature = "fragile-send-sync-non-atomic-wasm",
1597 not(target_feature = "atomics")
1598 )
1599))]
1600static_assertions::assert_impl_all!(SurfaceTexture: Send, Sync);
1601
1602/// Result of an unsuccessful call to [`Surface::get_current_texture`].
1603#[derive(Clone, PartialEq, Eq, Debug)]
1604pub enum SurfaceError {
1605 /// A timeout was encountered while trying to acquire the next frame.
1606 Timeout,
1607 /// The underlying surface has changed, and therefore the swap chain must be updated.
1608 Outdated,
1609 /// The swap chain has been lost and needs to be recreated.
1610 Lost,
1611 /// There is no more memory left to allocate a new frame.
1612 OutOfMemory,
1613}
1614static_assertions::assert_impl_all!(SurfaceError: Send, Sync);
1615
1616impl Display for SurfaceError {
1617 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1618 write!(f, "{}", match self {
1619 Self::Timeout => "A timeout was encountered while trying to acquire the next frame",
1620 Self::Outdated => "The underlying surface has changed, and therefore the swap chain must be updated",
1621 Self::Lost => "The swap chain has been lost and needs to be recreated",
1622 Self::OutOfMemory => "There is no more memory left to allocate a new frame",
1623 })
1624 }
1625}
1626
1627impl error::Error for SurfaceError {}
1628
1629impl Default for Instance {
1630 /// Creates a new instance of wgpu with default options.
1631 ///
1632 /// Backends are set to `Backends::all()`, and FXC is chosen as the `dx12_shader_compiler`.
1633 fn default() -> Self {
1634 Self::new(InstanceDescriptor::default())
1635 }
1636}
1637
1638impl Instance {
1639 /// Create an new instance of wgpu.
1640 ///
1641 /// # Arguments
1642 ///
1643 /// - `instance_desc` - Has fields for which [backends][Backends] wgpu will choose
1644 /// during instantiation, and which [DX12 shader compiler][Dx12Compiler] wgpu will use.
1645 pub fn new(instance_desc: InstanceDescriptor) -> Self {
1646 Self {
1647 context: Arc::from(crate::backend::Context::init(instance_desc)),
1648 }
1649 }
1650
1651 /// Create an new instance of wgpu from a wgpu-hal instance.
1652 ///
1653 /// # Arguments
1654 ///
1655 /// - `hal_instance` - wgpu-hal instance.
1656 ///
1657 /// # Safety
1658 ///
1659 /// Refer to the creation of wgpu-hal Instance for every backend.
1660 #[cfg(any(
1661 not(target_arch = "wasm32"),
1662 target_os = "emscripten",
1663 feature = "webgl"
1664 ))]
1665 pub unsafe fn from_hal<A: wgc::hal_api::HalApi>(hal_instance: A::Instance) -> Self {
1666 Self {
1667 context: Arc::new(unsafe {
1668 crate::backend::Context::from_hal_instance::<A>(hal_instance)
1669 }),
1670 }
1671 }
1672
1673 /// Return a reference to a specific backend instance, if available.
1674 ///
1675 /// If this `Instance` has a wgpu-hal [`Instance`] for backend
1676 /// `A`, return a reference to it. Otherwise, return `None`.
1677 ///
1678 /// # Safety
1679 ///
1680 /// - The raw instance handle returned must not be manually destroyed.
1681 ///
1682 /// [`Instance`]: hal::Api::Instance
1683 #[cfg(any(
1684 not(target_arch = "wasm32"),
1685 target_os = "emscripten",
1686 feature = "webgl"
1687 ))]
1688 pub unsafe fn as_hal<A: wgc::hal_api::HalApi>(&self) -> Option<&A::Instance> {
1689 unsafe {
1690 self.context
1691 .as_any()
1692 .downcast_ref::<crate::backend::Context>()
1693 .unwrap()
1694 .instance_as_hal::<A>()
1695 }
1696 }
1697
1698 /// Create an new instance of wgpu from a wgpu-core instance.
1699 ///
1700 /// # Arguments
1701 ///
1702 /// - `core_instance` - wgpu-core instance.
1703 ///
1704 /// # Safety
1705 ///
1706 /// Refer to the creation of wgpu-core Instance.
1707 #[cfg(any(
1708 not(target_arch = "wasm32"),
1709 target_os = "emscripten",
1710 feature = "webgl"
1711 ))]
1712 pub unsafe fn from_core(core_instance: wgc::instance::Instance) -> Self {
1713 Self {
1714 context: Arc::new(unsafe {
1715 crate::backend::Context::from_core_instance(core_instance)
1716 }),
1717 }
1718 }
1719
1720 /// Retrieves all available [`Adapter`]s that match the given [`Backends`].
1721 ///
1722 /// # Arguments
1723 ///
1724 /// - `backends` - Backends from which to enumerate adapters.
1725 #[cfg(any(
1726 not(target_arch = "wasm32"),
1727 target_os = "emscripten",
1728 feature = "webgl"
1729 ))]
1730 pub fn enumerate_adapters(&self, backends: Backends) -> impl ExactSizeIterator<Item = Adapter> {
1731 let context = Arc::clone(&self.context);
1732 self.context
1733 .as_any()
1734 .downcast_ref::<crate::backend::Context>()
1735 .unwrap()
1736 .enumerate_adapters(backends)
1737 .into_iter()
1738 .map(move |id| crate::Adapter {
1739 context: Arc::clone(&context),
1740 id: ObjectId::from(id),
1741 data: Box::new(()),
1742 })
1743 }
1744
1745 /// Retrieves an [`Adapter`] which matches the given [`RequestAdapterOptions`].
1746 ///
1747 /// Some options are "soft", so treated as non-mandatory. Others are "hard".
1748 ///
1749 /// If no adapters are found that suffice all the "hard" options, `None` is returned.
1750 pub fn request_adapter(
1751 &self,
1752 options: &RequestAdapterOptions,
1753 ) -> impl Future<Output = Option<Adapter>> + WasmNotSend {
1754 let context = Arc::clone(&self.context);
1755 let adapter = self.context.instance_request_adapter(options);
1756 async move {
1757 adapter
1758 .await
1759 .map(|(id, data)| Adapter { context, id, data })
1760 }
1761 }
1762
1763 /// Converts a wgpu-hal `ExposedAdapter` to a wgpu [`Adapter`].
1764 ///
1765 /// # Safety
1766 ///
1767 /// `hal_adapter` must be created from this instance internal handle.
1768 #[cfg(any(
1769 not(target_arch = "wasm32"),
1770 target_os = "emscripten",
1771 feature = "webgl"
1772 ))]
1773 pub unsafe fn create_adapter_from_hal<A: wgc::hal_api::HalApi>(
1774 &self,
1775 hal_adapter: hal::ExposedAdapter<A>,
1776 ) -> Adapter {
1777 let context = Arc::clone(&self.context);
1778 let id = unsafe {
1779 context
1780 .as_any()
1781 .downcast_ref::<crate::backend::Context>()
1782 .unwrap()
1783 .create_adapter_from_hal(hal_adapter)
1784 .into()
1785 };
1786 Adapter {
1787 context,
1788 id,
1789 data: Box::new(()),
1790 }
1791 }
1792
1793 /// Creates a surface from a raw window handle.
1794 ///
1795 /// If the specified display and window handle are not supported by any of the backends, then the surface
1796 /// will not be supported by any adapters.
1797 ///
1798 /// # Safety
1799 ///
1800 /// - `raw_window_handle` must be a valid object to create a surface upon.
1801 /// - `raw_window_handle` must remain valid until after the returned [`Surface`] is
1802 /// dropped.
1803 ///
1804 /// # Errors
1805 ///
1806 /// - On WebGL2: Will return an error if the browser does not support WebGL2,
1807 /// or declines to provide GPU access (such as due to a resource shortage).
1808 ///
1809 /// # Panics
1810 ///
1811 /// - On macOS/Metal: will panic if not called on the main thread.
1812 /// - On web: will panic if the `raw_window_handle` does not properly refer to a
1813 /// canvas element.
1814 pub unsafe fn create_surface<
1815 W: raw_window_handle::HasRawWindowHandle + raw_window_handle::HasRawDisplayHandle,
1816 >(
1817 &self,
1818 window: &W,
1819 ) -> Result<Surface, CreateSurfaceError> {
1820 let (id, data) = DynContext::instance_create_surface(
1821 &*self.context,
1822 raw_window_handle::HasRawDisplayHandle::raw_display_handle(window),
1823 raw_window_handle::HasRawWindowHandle::raw_window_handle(window),
1824 )?;
1825 Ok(Surface {
1826 context: Arc::clone(&self.context),
1827 id,
1828 data,
1829 config: Mutex::new(None),
1830 })
1831 }
1832
1833 /// Creates a surface from `CoreAnimationLayer`.
1834 ///
1835 /// # Safety
1836 ///
1837 /// - layer must be a valid object to create a surface upon.
1838 #[cfg(any(target_os = "ios", target_os = "macos"))]
1839 pub unsafe fn create_surface_from_core_animation_layer(
1840 &self,
1841 layer: *mut std::ffi::c_void,
1842 ) -> Surface {
1843 let surface = unsafe {
1844 self.context
1845 .as_any()
1846 .downcast_ref::<crate::backend::Context>()
1847 .unwrap()
1848 .create_surface_from_core_animation_layer(layer)
1849 };
1850 Surface {
1851 context: Arc::clone(&self.context),
1852 id: ObjectId::from(surface.id()),
1853 data: Box::new(surface),
1854 config: Mutex::new(None),
1855 }
1856 }
1857
1858 /// Creates a surface from `IDCompositionVisual`.
1859 ///
1860 /// # Safety
1861 ///
1862 /// - visual must be a valid IDCompositionVisual to create a surface upon.
1863 #[cfg(target_os = "windows")]
1864 pub unsafe fn create_surface_from_visual(&self, visual: *mut std::ffi::c_void) -> Surface {
1865 let surface = unsafe {
1866 self.context
1867 .as_any()
1868 .downcast_ref::<crate::backend::Context>()
1869 .unwrap()
1870 .create_surface_from_visual(visual)
1871 };
1872 Surface {
1873 context: Arc::clone(&self.context),
1874 id: ObjectId::from(surface.id()),
1875 data: Box::new(surface),
1876 config: Mutex::new(None),
1877 }
1878 }
1879
1880 /// Creates a surface from `SurfaceHandle`.
1881 ///
1882 /// # Safety
1883 ///
1884 /// - surface_handle must be a valid SurfaceHandle to create a surface upon.
1885 #[cfg(target_os = "windows")]
1886 pub unsafe fn create_surface_from_surface_handle(
1887 &self,
1888 surface_handle: *mut std::ffi::c_void,
1889 ) -> Surface {
1890 let surface = unsafe {
1891 self.context
1892 .as_any()
1893 .downcast_ref::<crate::backend::Context>()
1894 .unwrap()
1895 .create_surface_from_surface_handle(surface_handle)
1896 };
1897 Surface {
1898 context: Arc::clone(&self.context),
1899 id: ObjectId::from(surface.id()),
1900 data: Box::new(surface),
1901 config: Mutex::new(None),
1902 }
1903 }
1904
1905 /// Creates a surface from a `web_sys::HtmlCanvasElement`.
1906 ///
1907 /// The `canvas` argument must be a valid `<canvas>` element to
1908 /// create a surface upon.
1909 ///
1910 /// # Errors
1911 ///
1912 /// - On WebGL2: Will return an error if the browser does not support WebGL2,
1913 /// or declines to provide GPU access (such as due to a resource shortage).
1914 #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
1915 pub fn create_surface_from_canvas(
1916 &self,
1917 canvas: web_sys::HtmlCanvasElement,
1918 ) -> Result<Surface, CreateSurfaceError> {
1919 let surface = self
1920 .context
1921 .as_any()
1922 .downcast_ref::<crate::backend::Context>()
1923 .unwrap()
1924 .instance_create_surface_from_canvas(canvas)?;
1925
1926 // TODO: This is ugly, a way to create things from a native context needs to be made nicer.
1927 Ok(Surface {
1928 context: Arc::clone(&self.context),
1929 #[cfg(any(not(target_arch = "wasm32"), feature = "webgl"))]
1930 id: ObjectId::from(surface.id()),
1931 #[cfg(any(not(target_arch = "wasm32"), feature = "webgl"))]
1932 data: Box::new(surface),
1933 #[cfg(all(target_arch = "wasm32", not(feature = "webgl")))]
1934 id: ObjectId::UNUSED,
1935 #[cfg(all(target_arch = "wasm32", not(feature = "webgl")))]
1936 data: Box::new(surface.1),
1937 config: Mutex::new(None),
1938 })
1939 }
1940
1941 /// Creates a surface from a `web_sys::OffscreenCanvas`.
1942 ///
1943 /// The `canvas` argument must be a valid `OffscreenCanvas` object
1944 /// to create a surface upon.
1945 ///
1946 /// # Errors
1947 ///
1948 /// - On WebGL2: Will return an error if the browser does not support WebGL2,
1949 /// or declines to provide GPU access (such as due to a resource shortage).
1950 #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
1951 pub fn create_surface_from_offscreen_canvas(
1952 &self,
1953 canvas: web_sys::OffscreenCanvas,
1954 ) -> Result<Surface, CreateSurfaceError> {
1955 let surface = self
1956 .context
1957 .as_any()
1958 .downcast_ref::<crate::backend::Context>()
1959 .unwrap()
1960 .instance_create_surface_from_offscreen_canvas(canvas)?;
1961
1962 // TODO: This is ugly, a way to create things from a native context needs to be made nicer.
1963 Ok(Surface {
1964 context: Arc::clone(&self.context),
1965 #[cfg(any(not(target_arch = "wasm32"), feature = "webgl"))]
1966 id: ObjectId::from(surface.id()),
1967 #[cfg(any(not(target_arch = "wasm32"), feature = "webgl"))]
1968 data: Box::new(surface),
1969 #[cfg(all(target_arch = "wasm32", not(feature = "webgl")))]
1970 id: ObjectId::UNUSED,
1971 #[cfg(all(target_arch = "wasm32", not(feature = "webgl")))]
1972 data: Box::new(surface.1),
1973 config: Mutex::new(None),
1974 })
1975 }
1976
1977 /// Polls all devices.
1978 ///
1979 /// If `force_wait` is true and this is not running on the web, then this
1980 /// function will block until all in-flight buffers have been mapped and
1981 /// all submitted commands have finished execution.
1982 ///
1983 /// Return `true` if all devices' queues are empty, or `false` if there are
1984 /// queue submissions still in flight. (Note that, unless access to all
1985 /// [`Queue`s] associated with this [`Instance`] is coordinated somehow,
1986 /// this information could be out of date by the time the caller receives
1987 /// it. `Queue`s can be shared between threads, and other threads could
1988 /// submit new work at any time.)
1989 ///
1990 /// On the web, this is a no-op. `Device`s are automatically polled.
1991 ///
1992 /// [`Queue`s]: Queue
1993 pub fn poll_all(&self, force_wait: bool) -> bool {
1994 self.context.instance_poll_all_devices(force_wait)
1995 }
1996
1997 /// Generates memory report.
1998 #[cfg(any(
1999 not(target_arch = "wasm32"),
2000 target_os = "emscripten",
2001 feature = "webgl"
2002 ))]
2003 pub fn generate_report(&self) -> wgc::global::GlobalReport {
2004 self.context
2005 .as_any()
2006 .downcast_ref::<crate::backend::Context>()
2007 .unwrap()
2008 .generate_report()
2009 }
2010}
2011
2012impl Adapter {
2013 /// Requests a connection to a physical device, creating a logical device.
2014 ///
2015 /// Returns the [`Device`] together with a [`Queue`] that executes command buffers.
2016 ///
2017 /// # Arguments
2018 ///
2019 /// - `desc` - Description of the features and limits requested from the given device.
2020 /// - `trace_path` - Can be used for API call tracing, if that feature is
2021 /// enabled in `wgpu-core`.
2022 ///
2023 /// # Panics
2024 ///
2025 /// - Features specified by `desc` are not supported by this adapter.
2026 /// - Unsafe features were requested but not enabled when requesting the adapter.
2027 /// - Limits requested exceed the values provided by the adapter.
2028 /// - Adapter does not support all features wgpu requires to safely operate.
2029 pub fn request_device(
2030 &self,
2031 desc: &DeviceDescriptor,
2032 trace_path: Option<&std::path::Path>,
2033 ) -> impl Future<Output = Result<(Device, Queue), RequestDeviceError>> + WasmNotSend {
2034 let context = Arc::clone(&self.context);
2035 let device = DynContext::adapter_request_device(
2036 &*self.context,
2037 &self.id,
2038 self.data.as_ref(),
2039 desc,
2040 trace_path,
2041 );
2042 async move {
2043 device.await.map(
2044 |DeviceRequest {
2045 device_id,
2046 device_data,
2047 queue_id,
2048 queue_data,
2049 }| {
2050 (
2051 Device {
2052 context: Arc::clone(&context),
2053 id: device_id,
2054 data: device_data,
2055 },
2056 Queue {
2057 context,
2058 id: queue_id,
2059 data: queue_data,
2060 },
2061 )
2062 },
2063 )
2064 }
2065 }
2066
2067 /// Create a wgpu [`Device`] and [`Queue`] from a wgpu-hal `OpenDevice`
2068 ///
2069 /// # Safety
2070 ///
2071 /// - `hal_device` must be created from this adapter internal handle.
2072 /// - `desc.features` must be a subset of `hal_device` features.
2073 #[cfg(any(
2074 not(target_arch = "wasm32"),
2075 target_os = "emscripten",
2076 feature = "webgl"
2077 ))]
2078 pub unsafe fn create_device_from_hal<A: wgc::hal_api::HalApi>(
2079 &self,
2080 hal_device: hal::OpenDevice<A>,
2081 desc: &DeviceDescriptor,
2082 trace_path: Option<&std::path::Path>,
2083 ) -> Result<(Device, Queue), RequestDeviceError> {
2084 let context = Arc::clone(&self.context);
2085 unsafe {
2086 self.context
2087 .as_any()
2088 .downcast_ref::<crate::backend::Context>()
2089 .unwrap()
2090 .create_device_from_hal(&self.id.into(), hal_device, desc, trace_path)
2091 }
2092 .map(|(device, queue)| {
2093 (
2094 Device {
2095 context: Arc::clone(&context),
2096 id: device.id().into(),
2097 data: Box::new(device),
2098 },
2099 Queue {
2100 context,
2101 id: queue.id().into(),
2102 data: Box::new(queue),
2103 },
2104 )
2105 })
2106 }
2107
2108 /// Apply a callback to this `Adapter`'s underlying backend adapter.
2109 ///
2110 /// If this `Adapter` is implemented by the backend API given by `A` (Vulkan,
2111 /// Dx12, etc.), then apply `hal_adapter_callback` to `Some(&adapter)`, where
2112 /// `adapter` is the underlying backend adapter type, [`A::Adapter`].
2113 ///
2114 /// If this `Adapter` uses a different backend, apply `hal_adapter_callback`
2115 /// to `None`.
2116 ///
2117 /// The adapter is locked for reading while `hal_adapter_callback` runs. If
2118 /// the callback attempts to perform any `wgpu` operations that require
2119 /// write access to the adapter, deadlock will occur. The locks are
2120 /// automatically released when the callback returns.
2121 ///
2122 /// # Safety
2123 ///
2124 /// - The raw handle passed to the callback must not be manually destroyed.
2125 ///
2126 /// [`A::Adapter`]: hal::Api::Adapter
2127 #[cfg(any(
2128 not(target_arch = "wasm32"),
2129 target_os = "emscripten",
2130 feature = "webgl"
2131 ))]
2132 pub unsafe fn as_hal<A: wgc::hal_api::HalApi, F: FnOnce(Option<&A::Adapter>) -> R, R>(
2133 &self,
2134 hal_adapter_callback: F,
2135 ) -> R {
2136 unsafe {
2137 self.context
2138 .as_any()
2139 .downcast_ref::<crate::backend::Context>()
2140 .unwrap()
2141 .adapter_as_hal::<A, F, R>(self.id.into(), hal_adapter_callback)
2142 }
2143 }
2144
2145 /// Returns whether this adapter may present to the passed surface.
2146 pub fn is_surface_supported(&self, surface: &Surface) -> bool {
2147 DynContext::adapter_is_surface_supported(
2148 &*self.context,
2149 &self.id,
2150 self.data.as_ref(),
2151 &surface.id,
2152 surface.data.as_ref(),
2153 )
2154 }
2155
2156 /// List all features that are supported with this adapter.
2157 ///
2158 /// Features must be explicitly requested in [`Adapter::request_device`] in order
2159 /// to use them.
2160 pub fn features(&self) -> Features {
2161 DynContext::adapter_features(&*self.context, &self.id, self.data.as_ref())
2162 }
2163
2164 /// List the "best" limits that are supported by this adapter.
2165 ///
2166 /// Limits must be explicitly requested in [`Adapter::request_device`] to set
2167 /// the values that you are allowed to use.
2168 pub fn limits(&self) -> Limits {
2169 DynContext::adapter_limits(&*self.context, &self.id, self.data.as_ref())
2170 }
2171
2172 /// Get info about the adapter itself.
2173 pub fn get_info(&self) -> AdapterInfo {
2174 DynContext::adapter_get_info(&*self.context, &self.id, self.data.as_ref())
2175 }
2176
2177 /// Get info about the adapter itself.
2178 pub fn get_downlevel_capabilities(&self) -> DownlevelCapabilities {
2179 DynContext::adapter_downlevel_capabilities(&*self.context, &self.id, self.data.as_ref())
2180 }
2181
2182 /// Returns the features supported for a given texture format by this adapter.
2183 ///
2184 /// Note that the WebGPU spec further restricts the available usages/features.
2185 /// To disable these restrictions on a device, request the [`Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES`] feature.
2186 pub fn get_texture_format_features(&self, format: TextureFormat) -> TextureFormatFeatures {
2187 DynContext::adapter_get_texture_format_features(
2188 &*self.context,
2189 &self.id,
2190 self.data.as_ref(),
2191 format,
2192 )
2193 }
2194
2195 /// Generates a timestamp using the clock used by the presentation engine.
2196 ///
2197 /// When comparing completely opaque timestamp systems, we need a way of generating timestamps that signal
2198 /// the exact same time. You can do this by calling your own timestamp function immediately after a call to
2199 /// this function. This should result in timestamps that are 0.5 to 5 microseconds apart. There are locks
2200 /// that must be taken during the call, so don't call your function before.
2201 ///
2202 /// ```no_run
2203 /// # let adapter: wgpu::Adapter = panic!();
2204 /// # let some_code = || wgpu::PresentationTimestamp::INVALID_TIMESTAMP;
2205 /// use std::time::{Duration, Instant};
2206 /// let presentation = adapter.get_presentation_timestamp();
2207 /// let instant = Instant::now();
2208 ///
2209 /// // We can now turn a new presentation timestamp into an Instant.
2210 /// let some_pres_timestamp = some_code();
2211 /// let duration = Duration::from_nanos((some_pres_timestamp.0 - presentation.0) as u64);
2212 /// let new_instant: Instant = instant + duration;
2213 /// ```
2214 //
2215 /// [Instant]: std::time::Instant
2216 pub fn get_presentation_timestamp(&self) -> PresentationTimestamp {
2217 DynContext::adapter_get_presentation_timestamp(&*self.context, &self.id, self.data.as_ref())
2218 }
2219}
2220
2221impl Device {
2222 /// Check for resource cleanups and mapping callbacks.
2223 ///
2224 /// Return `true` if the queue is empty, or `false` if there are more queue
2225 /// submissions still in flight. (Note that, unless access to the [`Queue`] is
2226 /// coordinated somehow, this information could be out of date by the time
2227 /// the caller receives it. `Queue`s can be shared between threads, so
2228 /// other threads could submit new work at any time.)
2229 ///
2230 /// On the web, this is a no-op. `Device`s are automatically polled.
2231 pub fn poll(&self, maintain: Maintain) -> bool {
2232 DynContext::device_poll(&*self.context, &self.id, self.data.as_ref(), maintain)
2233 }
2234
2235 /// List all features that may be used with this device.
2236 ///
2237 /// Functions may panic if you use unsupported features.
2238 pub fn features(&self) -> Features {
2239 DynContext::device_features(&*self.context, &self.id, self.data.as_ref())
2240 }
2241
2242 /// List all limits that were requested of this device.
2243 ///
2244 /// If any of these limits are exceeded, functions may panic.
2245 pub fn limits(&self) -> Limits {
2246 DynContext::device_limits(&*self.context, &self.id, self.data.as_ref())
2247 }
2248
2249 /// Creates a shader module from either SPIR-V or WGSL source code.
2250 pub fn create_shader_module(&self, desc: ShaderModuleDescriptor) -> ShaderModule {
2251 let (id, data) = DynContext::device_create_shader_module(
2252 &*self.context,
2253 &self.id,
2254 self.data.as_ref(),
2255 desc,
2256 wgt::ShaderBoundChecks::new(),
2257 );
2258 ShaderModule {
2259 context: Arc::clone(&self.context),
2260 id,
2261 data,
2262 }
2263 }
2264
2265 /// Creates a shader module from either SPIR-V or WGSL source code without runtime checks.
2266 ///
2267 /// # Safety
2268 /// In contrast with [`create_shader_module`](Self::create_shader_module) this function
2269 /// creates a shader module without runtime checks which allows shaders to perform
2270 /// operations which can lead to undefined behavior like indexing out of bounds, thus it's
2271 /// the caller responsibility to pass a shader which doesn't perform any of this
2272 /// operations.
2273 ///
2274 /// This has no effect on web.
2275 pub unsafe fn create_shader_module_unchecked(
2276 &self,
2277 desc: ShaderModuleDescriptor,
2278 ) -> ShaderModule {
2279 let (id, data) = DynContext::device_create_shader_module(
2280 &*self.context,
2281 &self.id,
2282 self.data.as_ref(),
2283 desc,
2284 unsafe { wgt::ShaderBoundChecks::unchecked() },
2285 );
2286 ShaderModule {
2287 context: Arc::clone(&self.context),
2288 id,
2289 data,
2290 }
2291 }
2292
2293 /// Creates a shader module from SPIR-V binary directly.
2294 ///
2295 /// # Safety
2296 ///
2297 /// This function passes binary data to the backend as-is and can potentially result in a
2298 /// driver crash or bogus behaviour. No attempt is made to ensure that data is valid SPIR-V.
2299 ///
2300 /// See also [`include_spirv_raw!`] and [`util::make_spirv_raw`].
2301 pub unsafe fn create_shader_module_spirv(
2302 &self,
2303 desc: &ShaderModuleDescriptorSpirV,
2304 ) -> ShaderModule {
2305 let (id, data) = unsafe {
2306 DynContext::device_create_shader_module_spirv(
2307 &*self.context,
2308 &self.id,
2309 self.data.as_ref(),
2310 desc,
2311 )
2312 };
2313 ShaderModule {
2314 context: Arc::clone(&self.context),
2315 id,
2316 data,
2317 }
2318 }
2319
2320 /// Creates an empty [`CommandEncoder`].
2321 pub fn create_command_encoder(&self, desc: &CommandEncoderDescriptor) -> CommandEncoder {
2322 let (id, data) = DynContext::device_create_command_encoder(
2323 &*self.context,
2324 &self.id,
2325 self.data.as_ref(),
2326 desc,
2327 );
2328 CommandEncoder {
2329 context: Arc::clone(&self.context),
2330 id: Some(id),
2331 data,
2332 }
2333 }
2334
2335 /// Creates an empty [`RenderBundleEncoder`].
2336 pub fn create_render_bundle_encoder(
2337 &self,
2338 desc: &RenderBundleEncoderDescriptor,
2339 ) -> RenderBundleEncoder {
2340 let (id, data) = DynContext::device_create_render_bundle_encoder(
2341 &*self.context,
2342 &self.id,
2343 self.data.as_ref(),
2344 desc,
2345 );
2346 RenderBundleEncoder {
2347 context: Arc::clone(&self.context),
2348 id,
2349 data,
2350 parent: self,
2351 _p: Default::default(),
2352 }
2353 }
2354
2355 /// Creates a new [`BindGroup`].
2356 pub fn create_bind_group(&self, desc: &BindGroupDescriptor) -> BindGroup {
2357 let (id, data) = DynContext::device_create_bind_group(
2358 &*self.context,
2359 &self.id,
2360 self.data.as_ref(),
2361 desc,
2362 );
2363 BindGroup {
2364 context: Arc::clone(&self.context),
2365 id,
2366 data,
2367 }
2368 }
2369
2370 /// Creates a [`BindGroupLayout`].
2371 pub fn create_bind_group_layout(&self, desc: &BindGroupLayoutDescriptor) -> BindGroupLayout {
2372 let (id, data) = DynContext::device_create_bind_group_layout(
2373 &*self.context,
2374 &self.id,
2375 self.data.as_ref(),
2376 desc,
2377 );
2378 BindGroupLayout {
2379 context: Arc::clone(&self.context),
2380 id,
2381 data,
2382 }
2383 }
2384
2385 /// Creates a [`PipelineLayout`].
2386 pub fn create_pipeline_layout(&self, desc: &PipelineLayoutDescriptor) -> PipelineLayout {
2387 let (id, data) = DynContext::device_create_pipeline_layout(
2388 &*self.context,
2389 &self.id,
2390 self.data.as_ref(),
2391 desc,
2392 );
2393 PipelineLayout {
2394 context: Arc::clone(&self.context),
2395 id,
2396 data,
2397 }
2398 }
2399
2400 /// Creates a [`RenderPipeline`].
2401 pub fn create_render_pipeline(&self, desc: &RenderPipelineDescriptor) -> RenderPipeline {
2402 let (id, data) = DynContext::device_create_render_pipeline(
2403 &*self.context,
2404 &self.id,
2405 self.data.as_ref(),
2406 desc,
2407 );
2408 RenderPipeline {
2409 context: Arc::clone(&self.context),
2410 id,
2411 data,
2412 }
2413 }
2414
2415 /// Creates a [`ComputePipeline`].
2416 pub fn create_compute_pipeline(&self, desc: &ComputePipelineDescriptor) -> ComputePipeline {
2417 let (id, data) = DynContext::device_create_compute_pipeline(
2418 &*self.context,
2419 &self.id,
2420 self.data.as_ref(),
2421 desc,
2422 );
2423 ComputePipeline {
2424 context: Arc::clone(&self.context),
2425 id,
2426 data,
2427 }
2428 }
2429
2430 /// Creates a [`Buffer`].
2431 pub fn create_buffer(&self, desc: &BufferDescriptor) -> Buffer {
2432 let mut map_context = MapContext::new(desc.size);
2433 if desc.mapped_at_creation {
2434 map_context.initial_range = 0..desc.size;
2435 }
2436
2437 let (id, data) =
2438 DynContext::device_create_buffer(&*self.context, &self.id, self.data.as_ref(), desc);
2439
2440 Buffer {
2441 context: Arc::clone(&self.context),
2442 id,
2443 data,
2444 map_context: Mutex::new(map_context),
2445 size: desc.size,
2446 usage: desc.usage,
2447 }
2448 }
2449
2450 /// Creates a new [`Texture`].
2451 ///
2452 /// `desc` specifies the general format of the texture.
2453 pub fn create_texture(&self, desc: &TextureDescriptor) -> Texture {
2454 let (id, data) =
2455 DynContext::device_create_texture(&*self.context, &self.id, self.data.as_ref(), desc);
2456 Texture {
2457 context: Arc::clone(&self.context),
2458 id,
2459 data,
2460 owned: true,
2461 descriptor: TextureDescriptor {
2462 label: None,
2463 view_formats: &[],
2464 ..desc.clone()
2465 },
2466 }
2467 }
2468
2469 /// Creates a [`Texture`] from a wgpu-hal Texture.
2470 ///
2471 /// # Safety
2472 ///
2473 /// - `hal_texture` must be created from this device internal handle
2474 /// - `hal_texture` must be created respecting `desc`
2475 /// - `hal_texture` must be initialized
2476 #[cfg(any(
2477 not(target_arch = "wasm32"),
2478 target_os = "emscripten",
2479 feature = "webgl"
2480 ))]
2481 pub unsafe fn create_texture_from_hal<A: wgc::hal_api::HalApi>(
2482 &self,
2483 hal_texture: A::Texture,
2484 desc: &TextureDescriptor,
2485 ) -> Texture {
2486 let texture = unsafe {
2487 self.context
2488 .as_any()
2489 .downcast_ref::<crate::backend::Context>()
2490 .unwrap()
2491 .create_texture_from_hal::<A>(
2492 hal_texture,
2493 self.data.as_ref().downcast_ref().unwrap(),
2494 desc,
2495 )
2496 };
2497 Texture {
2498 context: Arc::clone(&self.context),
2499 id: ObjectId::from(texture.id()),
2500 data: Box::new(texture),
2501 owned: true,
2502 descriptor: TextureDescriptor {
2503 label: None,
2504 view_formats: &[],
2505 ..desc.clone()
2506 },
2507 }
2508 }
2509
2510 /// Creates a [`Buffer`] from a wgpu-hal Buffer.
2511 ///
2512 /// # Safety
2513 ///
2514 /// - `hal_buffer` must be created from this device internal handle
2515 /// - `hal_buffer` must be created respecting `desc`
2516 /// - `hal_buffer` must be initialized
2517 #[cfg(any(
2518 not(target_arch = "wasm32"),
2519 target_os = "emscripten",
2520 feature = "webgl"
2521 ))]
2522 pub unsafe fn create_buffer_from_hal<A: wgc::hal_api::HalApi>(
2523 &self,
2524 hal_buffer: A::Buffer,
2525 desc: &BufferDescriptor,
2526 ) -> Buffer {
2527 let mut map_context = MapContext::new(desc.size);
2528 if desc.mapped_at_creation {
2529 map_context.initial_range = 0..desc.size;
2530 }
2531
2532 let (id, buffer) = unsafe {
2533 self.context
2534 .as_any()
2535 .downcast_ref::<crate::backend::Context>()
2536 .unwrap()
2537 .create_buffer_from_hal::<A>(
2538 hal_buffer,
2539 self.data.as_ref().downcast_ref().unwrap(),
2540 desc,
2541 )
2542 };
2543
2544 Buffer {
2545 context: Arc::clone(&self.context),
2546 id: ObjectId::from(id),
2547 data: Box::new(buffer),
2548 map_context: Mutex::new(map_context),
2549 size: desc.size,
2550 usage: desc.usage,
2551 }
2552 }
2553
2554 /// Creates a new [`Sampler`].
2555 ///
2556 /// `desc` specifies the behavior of the sampler.
2557 pub fn create_sampler(&self, desc: &SamplerDescriptor) -> Sampler {
2558 let (id, data) =
2559 DynContext::device_create_sampler(&*self.context, &self.id, self.data.as_ref(), desc);
2560 Sampler {
2561 context: Arc::clone(&self.context),
2562 id,
2563 data,
2564 }
2565 }
2566
2567 /// Creates a new [`QuerySet`].
2568 pub fn create_query_set(&self, desc: &QuerySetDescriptor) -> QuerySet {
2569 let (id, data) =
2570 DynContext::device_create_query_set(&*self.context, &self.id, self.data.as_ref(), desc);
2571 QuerySet {
2572 context: Arc::clone(&self.context),
2573 id,
2574 data,
2575 }
2576 }
2577
2578 /// Set a callback for errors that are not handled in error scopes.
2579 pub fn on_uncaptured_error(&self, handler: Box<dyn UncapturedErrorHandler>) {
2580 self.context
2581 .device_on_uncaptured_error(&self.id, self.data.as_ref(), handler);
2582 }
2583
2584 /// Push an error scope.
2585 pub fn push_error_scope(&self, filter: ErrorFilter) {
2586 self.context
2587 .device_push_error_scope(&self.id, self.data.as_ref(), filter);
2588 }
2589
2590 /// Pop an error scope.
2591 pub fn pop_error_scope(&self) -> impl Future<Output = Option<Error>> + WasmNotSend {
2592 self.context
2593 .device_pop_error_scope(&self.id, self.data.as_ref())
2594 }
2595
2596 /// Starts frame capture.
2597 pub fn start_capture(&self) {
2598 DynContext::device_start_capture(&*self.context, &self.id, self.data.as_ref())
2599 }
2600
2601 /// Stops frame capture.
2602 pub fn stop_capture(&self) {
2603 DynContext::device_stop_capture(&*self.context, &self.id, self.data.as_ref())
2604 }
2605
2606 /// Apply a callback to this `Device`'s underlying backend device.
2607 ///
2608 /// If this `Device` is implemented by the backend API given by `A` (Vulkan,
2609 /// Dx12, etc.), then apply `hal_device_callback` to `Some(&device)`, where
2610 /// `device` is the underlying backend device type, [`A::Device`].
2611 ///
2612 /// If this `Device` uses a different backend, apply `hal_device_callback`
2613 /// to `None`.
2614 ///
2615 /// The device is locked for reading while `hal_device_callback` runs. If
2616 /// the callback attempts to perform any `wgpu` operations that require
2617 /// write access to the device (destroying a buffer, say), deadlock will
2618 /// occur. The locks are automatically released when the callback returns.
2619 ///
2620 /// # Safety
2621 ///
2622 /// - The raw handle passed to the callback must not be manually destroyed.
2623 ///
2624 /// [`A::Device`]: hal::Api::Device
2625 #[cfg(any(
2626 not(target_arch = "wasm32"),
2627 target_os = "emscripten",
2628 feature = "webgl"
2629 ))]
2630 pub unsafe fn as_hal<A: wgc::hal_api::HalApi, F: FnOnce(Option<&A::Device>) -> R, R>(
2631 &self,
2632 hal_device_callback: F,
2633 ) -> R {
2634 unsafe {
2635 self.context
2636 .as_any()
2637 .downcast_ref::<crate::backend::Context>()
2638 .unwrap()
2639 .device_as_hal::<A, F, R>(
2640 self.data.as_ref().downcast_ref().unwrap(),
2641 hal_device_callback,
2642 )
2643 }
2644 }
2645}
2646
2647impl Drop for Device {
2648 fn drop(&mut self) {
2649 if !thread::panicking() {
2650 self.context.device_drop(&self.id, self.data.as_ref());
2651 }
2652 }
2653}
2654
2655/// Requesting a device failed.
2656#[derive(Clone, PartialEq, Eq, Debug)]
2657pub struct RequestDeviceError;
2658static_assertions::assert_impl_all!(RequestDeviceError: Send, Sync);
2659
2660impl Display for RequestDeviceError {
2661 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2662 write!(f, "Requesting a device failed")
2663 }
2664}
2665
2666impl error::Error for RequestDeviceError {}
2667
2668/// [`Instance::create_surface()`] or a related function failed.
2669#[derive(Clone, PartialEq, Eq, Debug)]
2670#[non_exhaustive]
2671pub struct CreateSurfaceError {
2672 // TODO: Report diagnostic clues
2673}
2674static_assertions::assert_impl_all!(CreateSurfaceError: Send, Sync);
2675
2676impl Display for CreateSurfaceError {
2677 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2678 write!(f, "Creating a surface failed")
2679 }
2680}
2681
2682impl error::Error for CreateSurfaceError {}
2683
2684/// Error occurred when trying to async map a buffer.
2685#[derive(Clone, PartialEq, Eq, Debug)]
2686pub struct BufferAsyncError;
2687static_assertions::assert_impl_all!(BufferAsyncError: Send, Sync);
2688
2689impl Display for BufferAsyncError {
2690 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2691 write!(f, "Error occurred when trying to async map a buffer")
2692 }
2693}
2694
2695impl error::Error for BufferAsyncError {}
2696
2697/// Type of buffer mapping.
2698#[derive(Debug, Clone, Copy, Eq, PartialEq)]
2699pub enum MapMode {
2700 /// Map only for reading
2701 Read,
2702 /// Map only for writing
2703 Write,
2704}
2705static_assertions::assert_impl_all!(MapMode: Send, Sync);
2706
2707fn range_to_offset_size<S: RangeBounds<BufferAddress>>(
2708 bounds: S,
2709) -> (BufferAddress, Option<BufferSize>) {
2710 let offset = match bounds.start_bound() {
2711 Bound::Included(&bound) => bound,
2712 Bound::Excluded(&bound) => bound + 1,
2713 Bound::Unbounded => 0,
2714 };
2715 let size = match bounds.end_bound() {
2716 Bound::Included(&bound) => Some(bound + 1 - offset),
2717 Bound::Excluded(&bound) => Some(bound - offset),
2718 Bound::Unbounded => None,
2719 }
2720 .map(|size| BufferSize::new(size).expect("Buffer slices can not be empty"));
2721
2722 (offset, size)
2723}
2724
2725#[cfg(test)]
2726mod tests {
2727 use crate::BufferSize;
2728
2729 #[test]
2730 fn range_to_offset_size_works() {
2731 assert_eq!(crate::range_to_offset_size(0..2), (0, BufferSize::new(2)));
2732 assert_eq!(crate::range_to_offset_size(2..5), (2, BufferSize::new(3)));
2733 assert_eq!(crate::range_to_offset_size(..), (0, None));
2734 assert_eq!(crate::range_to_offset_size(21..), (21, None));
2735 assert_eq!(crate::range_to_offset_size(0..), (0, None));
2736 assert_eq!(crate::range_to_offset_size(..21), (0, BufferSize::new(21)));
2737 }
2738
2739 #[test]
2740 #[should_panic]
2741 fn range_to_offset_size_panics_for_empty_range() {
2742 crate::range_to_offset_size(123..123);
2743 }
2744
2745 #[test]
2746 #[should_panic]
2747 fn range_to_offset_size_panics_for_unbounded_empty_range() {
2748 crate::range_to_offset_size(..0);
2749 }
2750}
2751
2752/// Read only view into a mapped buffer.
2753#[derive(Debug)]
2754pub struct BufferView<'a> {
2755 slice: BufferSlice<'a>,
2756 data: Box<dyn crate::context::BufferMappedRange>,
2757}
2758
2759/// Write only view into mapped buffer.
2760///
2761/// It is possible to read the buffer using this view, but doing so is not
2762/// recommended, as it is likely to be slow.
2763#[derive(Debug)]
2764pub struct BufferViewMut<'a> {
2765 slice: BufferSlice<'a>,
2766 data: Box<dyn crate::context::BufferMappedRange>,
2767 readable: bool,
2768}
2769
2770impl std::ops::Deref for BufferView<'_> {
2771 type Target = [u8];
2772
2773 #[inline]
2774 fn deref(&self) -> &[u8] {
2775 self.data.slice()
2776 }
2777}
2778
2779impl AsRef<[u8]> for BufferView<'_> {
2780 #[inline]
2781 fn as_ref(&self) -> &[u8] {
2782 self.data.slice()
2783 }
2784}
2785
2786impl AsMut<[u8]> for BufferViewMut<'_> {
2787 #[inline]
2788 fn as_mut(&mut self) -> &mut [u8] {
2789 self.data.slice_mut()
2790 }
2791}
2792
2793impl Deref for BufferViewMut<'_> {
2794 type Target = [u8];
2795
2796 fn deref(&self) -> &Self::Target {
2797 if !self.readable {
2798 log::warn!("Reading from a BufferViewMut is slow and not recommended.");
2799 }
2800
2801 self.data.slice()
2802 }
2803}
2804
2805impl DerefMut for BufferViewMut<'_> {
2806 fn deref_mut(&mut self) -> &mut Self::Target {
2807 self.data.slice_mut()
2808 }
2809}
2810
2811impl Drop for BufferView<'_> {
2812 fn drop(&mut self) {
2813 self.slice
2814 .buffer
2815 .map_context
2816 .lock()
2817 .remove(self.slice.offset, self.slice.size);
2818 }
2819}
2820
2821impl Drop for BufferViewMut<'_> {
2822 fn drop(&mut self) {
2823 self.slice
2824 .buffer
2825 .map_context
2826 .lock()
2827 .remove(self.slice.offset, self.slice.size);
2828 }
2829}
2830
2831impl Buffer {
2832 /// Return the binding view of the entire buffer.
2833 pub fn as_entire_binding(&self) -> BindingResource {
2834 BindingResource::Buffer(self.as_entire_buffer_binding())
2835 }
2836
2837 /// Return the binding view of the entire buffer.
2838 pub fn as_entire_buffer_binding(&self) -> BufferBinding {
2839 BufferBinding {
2840 buffer: self,
2841 offset: 0,
2842 size: None,
2843 }
2844 }
2845
2846 /// Use only a portion of this Buffer for a given operation. Choosing a range with no end
2847 /// will use the rest of the buffer. Using a totally unbounded range will use the entire buffer.
2848 pub fn slice<S: RangeBounds<BufferAddress>>(&self, bounds: S) -> BufferSlice {
2849 let (offset, size) = range_to_offset_size(bounds);
2850 BufferSlice {
2851 buffer: self,
2852 offset,
2853 size,
2854 }
2855 }
2856
2857 /// Flushes any pending write operations and unmaps the buffer from host memory.
2858 pub fn unmap(&self) {
2859 self.map_context.lock().reset();
2860 DynContext::buffer_unmap(&*self.context, &self.id, self.data.as_ref());
2861 }
2862
2863 /// Destroy the associated native resources as soon as possible.
2864 pub fn destroy(&self) {
2865 DynContext::buffer_destroy(&*self.context, &self.id, self.data.as_ref());
2866 }
2867
2868 /// Returns the length of the buffer allocation in bytes.
2869 ///
2870 /// This is always equal to the `size` that was specified when creating the buffer.
2871 pub fn size(&self) -> BufferAddress {
2872 self.size
2873 }
2874
2875 /// Returns the allowed usages for this `Buffer`.
2876 ///
2877 /// This is always equal to the `usage` that was specified when creating the buffer.
2878 pub fn usage(&self) -> BufferUsages {
2879 self.usage
2880 }
2881}
2882
2883impl<'a> BufferSlice<'a> {
2884 /// Map the buffer. Buffer is ready to map once the callback is called.
2885 ///
2886 /// For the callback to complete, either `queue.submit(..)`, `instance.poll_all(..)`, or `device.poll(..)`
2887 /// must be called elsewhere in the runtime, possibly integrated into an event loop or run on a separate thread.
2888 ///
2889 /// The callback will be called on the thread that first calls the above functions after the gpu work
2890 /// has completed. There are no restrictions on the code you can run in the callback, however on native the
2891 /// call to the function will not complete until the callback returns, so prefer keeping callbacks short
2892 /// and used to set flags, send messages, etc.
2893 pub fn map_async(
2894 &self,
2895 mode: MapMode,
2896 callback: impl FnOnce(Result<(), BufferAsyncError>) + WasmNotSend + 'static,
2897 ) {
2898 let mut mc = self.buffer.map_context.lock();
2899 assert_eq!(
2900 mc.initial_range,
2901 0..0,
2902 "Buffer {:?} is already mapped",
2903 self.buffer.id
2904 );
2905 let end = match self.size {
2906 Some(s) => self.offset + s.get(),
2907 None => mc.total_size,
2908 };
2909 mc.initial_range = self.offset..end;
2910
2911 DynContext::buffer_map_async(
2912 &*self.buffer.context,
2913 &self.buffer.id,
2914 self.buffer.data.as_ref(),
2915 mode,
2916 self.offset..end,
2917 Box::new(callback),
2918 )
2919 }
2920
2921 /// Synchronously and immediately map a buffer for reading. If the buffer is not immediately mappable
2922 /// through [`BufferDescriptor::mapped_at_creation`] or [`BufferSlice::map_async`], will panic.
2923 pub fn get_mapped_range(&self) -> BufferView<'a> {
2924 let end = self.buffer.map_context.lock().add(self.offset, self.size);
2925 let data = DynContext::buffer_get_mapped_range(
2926 &*self.buffer.context,
2927 &self.buffer.id,
2928 self.buffer.data.as_ref(),
2929 self.offset..end,
2930 );
2931 BufferView { slice: *self, data }
2932 }
2933
2934 /// Synchronously and immediately map a buffer for reading. If the buffer is not immediately mappable
2935 /// through [`BufferDescriptor::mapped_at_creation`] or [`BufferSlice::map_async`], will panic.
2936 ///
2937 /// This is useful in wasm builds when you want to pass mapped data directly to js. Unlike `get_mapped_range`
2938 /// which unconditionally copies mapped data into the wasm heap, this function directly hands you the
2939 /// ArrayBuffer that we mapped the data into in js.
2940 #[cfg(all(
2941 target_arch = "wasm32",
2942 not(any(target_os = "emscripten", feature = "webgl"))
2943 ))]
2944 pub fn get_mapped_range_as_array_buffer(&self) -> js_sys::ArrayBuffer {
2945 let end = self.buffer.map_context.lock().add(self.offset, self.size);
2946 DynContext::buffer_get_mapped_range_as_array_buffer(
2947 &*self.buffer.context,
2948 &self.buffer.id,
2949 self.buffer.data.as_ref(),
2950 self.offset..end,
2951 )
2952 }
2953
2954 /// Synchronously and immediately map a buffer for writing. If the buffer is not immediately mappable
2955 /// through [`BufferDescriptor::mapped_at_creation`] or [`BufferSlice::map_async`], will panic.
2956 pub fn get_mapped_range_mut(&self) -> BufferViewMut<'a> {
2957 let end = self.buffer.map_context.lock().add(self.offset, self.size);
2958 let data = DynContext::buffer_get_mapped_range(
2959 &*self.buffer.context,
2960 &self.buffer.id,
2961 self.buffer.data.as_ref(),
2962 self.offset..end,
2963 );
2964 BufferViewMut {
2965 slice: *self,
2966 data,
2967 readable: self.buffer.usage.contains(BufferUsages::MAP_READ),
2968 }
2969 }
2970}
2971
2972impl Drop for Buffer {
2973 fn drop(&mut self) {
2974 if !thread::panicking() {
2975 self.context.buffer_drop(&self.id, self.data.as_ref());
2976 }
2977 }
2978}
2979
2980impl Texture {
2981 /// Returns the inner hal Texture using a callback. The hal texture will be `None` if the
2982 /// backend type argument does not match with this wgpu Texture
2983 ///
2984 /// # Safety
2985 ///
2986 /// - The raw handle obtained from the hal Texture must not be manually destroyed
2987 #[cfg(any(
2988 not(target_arch = "wasm32"),
2989 target_os = "emscripten",
2990 feature = "webgl"
2991 ))]
2992 pub unsafe fn as_hal<A: wgc::hal_api::HalApi, F: FnOnce(Option<&A::Texture>)>(
2993 &self,
2994 hal_texture_callback: F,
2995 ) {
2996 let texture = self.data.as_ref().downcast_ref().unwrap();
2997 unsafe {
2998 self.context
2999 .as_any()
3000 .downcast_ref::<crate::backend::Context>()
3001 .unwrap()
3002 .texture_as_hal::<A, F>(texture, hal_texture_callback)
3003 }
3004 }
3005
3006 /// Creates a view of this texture.
3007 pub fn create_view(&self, desc: &TextureViewDescriptor) -> TextureView {
3008 let (id, data) =
3009 DynContext::texture_create_view(&*self.context, &self.id, self.data.as_ref(), desc);
3010 TextureView {
3011 context: Arc::clone(&self.context),
3012 id,
3013 data,
3014 }
3015 }
3016
3017 /// Destroy the associated native resources as soon as possible.
3018 pub fn destroy(&self) {
3019 DynContext::texture_destroy(&*self.context, &self.id, self.data.as_ref());
3020 }
3021
3022 /// Make an `ImageCopyTexture` representing the whole texture.
3023 pub fn as_image_copy(&self) -> ImageCopyTexture {
3024 ImageCopyTexture {
3025 texture: self,
3026 mip_level: 0,
3027 origin: Origin3d::ZERO,
3028 aspect: TextureAspect::All,
3029 }
3030 }
3031
3032 /// Returns the size of this `Texture`.
3033 ///
3034 /// This is always equal to the `size` that was specified when creating the texture.
3035 pub fn size(&self) -> Extent3d {
3036 self.descriptor.size
3037 }
3038
3039 /// Returns the width of this `Texture`.
3040 ///
3041 /// This is always equal to the `size.width` that was specified when creating the texture.
3042 pub fn width(&self) -> u32 {
3043 self.descriptor.size.width
3044 }
3045
3046 /// Returns the height of this `Texture`.
3047 ///
3048 /// This is always equal to the `size.height` that was specified when creating the texture.
3049 pub fn height(&self) -> u32 {
3050 self.descriptor.size.height
3051 }
3052
3053 /// Returns the depth or layer count of this `Texture`.
3054 ///
3055 /// This is always equal to the `size.depth_or_array_layers` that was specified when creating the texture.
3056 pub fn depth_or_array_layers(&self) -> u32 {
3057 self.descriptor.size.depth_or_array_layers
3058 }
3059
3060 /// Returns the mip_level_count of this `Texture`.
3061 ///
3062 /// This is always equal to the `mip_level_count` that was specified when creating the texture.
3063 pub fn mip_level_count(&self) -> u32 {
3064 self.descriptor.mip_level_count
3065 }
3066
3067 /// Returns the sample_count of this `Texture`.
3068 ///
3069 /// This is always equal to the `sample_count` that was specified when creating the texture.
3070 pub fn sample_count(&self) -> u32 {
3071 self.descriptor.sample_count
3072 }
3073
3074 /// Returns the dimension of this `Texture`.
3075 ///
3076 /// This is always equal to the `dimension` that was specified when creating the texture.
3077 pub fn dimension(&self) -> TextureDimension {
3078 self.descriptor.dimension
3079 }
3080
3081 /// Returns the format of this `Texture`.
3082 ///
3083 /// This is always equal to the `format` that was specified when creating the texture.
3084 pub fn format(&self) -> TextureFormat {
3085 self.descriptor.format
3086 }
3087
3088 /// Returns the allowed usages of this `Texture`.
3089 ///
3090 /// This is always equal to the `usage` that was specified when creating the texture.
3091 pub fn usage(&self) -> TextureUsages {
3092 self.descriptor.usage
3093 }
3094}
3095
3096impl Drop for Texture {
3097 fn drop(&mut self) {
3098 if self.owned && !thread::panicking() {
3099 self.context.texture_drop(&self.id, self.data.as_ref());
3100 }
3101 }
3102}
3103
3104impl Drop for TextureView {
3105 fn drop(&mut self) {
3106 if !thread::panicking() {
3107 self.context.texture_view_drop(&self.id, self.data.as_ref());
3108 }
3109 }
3110}
3111
3112impl CommandEncoder {
3113 /// Finishes recording and returns a [`CommandBuffer`] that can be submitted for execution.
3114 pub fn finish(mut self) -> CommandBuffer {
3115 let (id, data) = DynContext::command_encoder_finish(
3116 &*self.context,
3117 self.id.take().unwrap(),
3118 self.data.as_mut(),
3119 );
3120 CommandBuffer {
3121 context: Arc::clone(&self.context),
3122 id: Some(id),
3123 data: Some(data),
3124 }
3125 }
3126
3127 /// Begins recording of a render pass.
3128 ///
3129 /// This function returns a [`RenderPass`] object which records a single render pass.
3130 pub fn begin_render_pass<'pass>(
3131 &'pass mut self,
3132 desc: &RenderPassDescriptor<'pass, '_>,
3133 ) -> RenderPass<'pass> {
3134 let id = self.id.as_ref().unwrap();
3135 let (id, data) = DynContext::command_encoder_begin_render_pass(
3136 &*self.context,
3137 id,
3138 self.data.as_ref(),
3139 desc,
3140 );
3141 RenderPass {
3142 id,
3143 data,
3144 parent: self,
3145 }
3146 }
3147
3148 /// Begins recording of a compute pass.
3149 ///
3150 /// This function returns a [`ComputePass`] object which records a single compute pass.
3151 pub fn begin_compute_pass(&mut self, desc: &ComputePassDescriptor) -> ComputePass {
3152 let id = self.id.as_ref().unwrap();
3153 let (id, data) = DynContext::command_encoder_begin_compute_pass(
3154 &*self.context,
3155 id,
3156 self.data.as_ref(),
3157 desc,
3158 );
3159 ComputePass {
3160 id,
3161 data,
3162 parent: self,
3163 }
3164 }
3165
3166 /// Copy data from one buffer to another.
3167 ///
3168 /// # Panics
3169 ///
3170 /// - Buffer offsets or copy size not a multiple of [`COPY_BUFFER_ALIGNMENT`].
3171 /// - Copy would overrun buffer.
3172 /// - Copy within the same buffer.
3173 pub fn copy_buffer_to_buffer(
3174 &mut self,
3175 source: &Buffer,
3176 source_offset: BufferAddress,
3177 destination: &Buffer,
3178 destination_offset: BufferAddress,
3179 copy_size: BufferAddress,
3180 ) {
3181 DynContext::command_encoder_copy_buffer_to_buffer(
3182 &*self.context,
3183 self.id.as_ref().unwrap(),
3184 self.data.as_ref(),
3185 &source.id,
3186 source.data.as_ref(),
3187 source_offset,
3188 &destination.id,
3189 destination.data.as_ref(),
3190 destination_offset,
3191 copy_size,
3192 );
3193 }
3194
3195 /// Copy data from a buffer to a texture.
3196 pub fn copy_buffer_to_texture(
3197 &mut self,
3198 source: ImageCopyBuffer,
3199 destination: ImageCopyTexture,
3200 copy_size: Extent3d,
3201 ) {
3202 DynContext::command_encoder_copy_buffer_to_texture(
3203 &*self.context,
3204 self.id.as_ref().unwrap(),
3205 self.data.as_ref(),
3206 source,
3207 destination,
3208 copy_size,
3209 );
3210 }
3211
3212 /// Copy data from a texture to a buffer.
3213 pub fn copy_texture_to_buffer(
3214 &mut self,
3215 source: ImageCopyTexture,
3216 destination: ImageCopyBuffer,
3217 copy_size: Extent3d,
3218 ) {
3219 DynContext::command_encoder_copy_texture_to_buffer(
3220 &*self.context,
3221 self.id.as_ref().unwrap(),
3222 self.data.as_ref(),
3223 source,
3224 destination,
3225 copy_size,
3226 );
3227 }
3228
3229 /// Copy data from one texture to another.
3230 ///
3231 /// # Panics
3232 ///
3233 /// - Textures are not the same type
3234 /// - If a depth texture, or a multisampled texture, the entire texture must be copied
3235 /// - Copy would overrun either texture
3236 pub fn copy_texture_to_texture(
3237 &mut self,
3238 source: ImageCopyTexture,
3239 destination: ImageCopyTexture,
3240 copy_size: Extent3d,
3241 ) {
3242 DynContext::command_encoder_copy_texture_to_texture(
3243 &*self.context,
3244 self.id.as_ref().unwrap(),
3245 self.data.as_ref(),
3246 source,
3247 destination,
3248 copy_size,
3249 );
3250 }
3251
3252 /// Clears texture to zero.
3253 ///
3254 /// Note that unlike with clear_buffer, `COPY_DST` usage is not required.
3255 ///
3256 /// # Implementation notes
3257 ///
3258 /// - implemented either via buffer copies and render/depth target clear, path depends on texture usages
3259 /// - behaves like texture zero init, but is performed immediately (clearing is *not* delayed via marking it as uninitialized)
3260 ///
3261 /// # Panics
3262 ///
3263 /// - `CLEAR_TEXTURE` extension not enabled
3264 /// - Range is out of bounds
3265 pub fn clear_texture(&mut self, texture: &Texture, subresource_range: &ImageSubresourceRange) {
3266 DynContext::command_encoder_clear_texture(
3267 &*self.context,
3268 self.id.as_ref().unwrap(),
3269 self.data.as_ref(),
3270 texture,
3271 subresource_range,
3272 );
3273 }
3274
3275 /// Clears buffer to zero.
3276 ///
3277 /// # Panics
3278 ///
3279 /// - Buffer does not have `COPY_DST` usage.
3280 /// - Range it out of bounds
3281 pub fn clear_buffer(
3282 &mut self,
3283 buffer: &Buffer,
3284 offset: BufferAddress,
3285 size: Option<BufferSize>,
3286 ) {
3287 DynContext::command_encoder_clear_buffer(
3288 &*self.context,
3289 self.id.as_ref().unwrap(),
3290 self.data.as_ref(),
3291 buffer,
3292 offset,
3293 size,
3294 );
3295 }
3296
3297 /// Inserts debug marker.
3298 pub fn insert_debug_marker(&mut self, label: &str) {
3299 let id = self.id.as_ref().unwrap();
3300 DynContext::command_encoder_insert_debug_marker(
3301 &*self.context,
3302 id,
3303 self.data.as_ref(),
3304 label,
3305 );
3306 }
3307
3308 /// Start record commands and group it into debug marker group.
3309 pub fn push_debug_group(&mut self, label: &str) {
3310 let id = self.id.as_ref().unwrap();
3311 DynContext::command_encoder_push_debug_group(&*self.context, id, self.data.as_ref(), label);
3312 }
3313
3314 /// Stops command recording and creates debug group.
3315 pub fn pop_debug_group(&mut self) {
3316 let id = self.id.as_ref().unwrap();
3317 DynContext::command_encoder_pop_debug_group(&*self.context, id, self.data.as_ref());
3318 }
3319}
3320
3321/// [`Features::TIMESTAMP_QUERY`] must be enabled on the device in order to call these functions.
3322impl CommandEncoder {
3323 /// Issue a timestamp command at this point in the queue.
3324 /// The timestamp will be written to the specified query set, at the specified index.
3325 ///
3326 /// Must be multiplied by [`Queue::get_timestamp_period`] to get
3327 /// the value in nanoseconds. Absolute values have no meaning,
3328 /// but timestamps can be subtracted to get the time it takes
3329 /// for a string of operations to complete.
3330 pub fn write_timestamp(&mut self, query_set: &QuerySet, query_index: u32) {
3331 DynContext::command_encoder_write_timestamp(
3332 &*self.context,
3333 self.id.as_ref().unwrap(),
3334 self.data.as_mut(),
3335 &query_set.id,
3336 query_set.data.as_ref(),
3337 query_index,
3338 )
3339 }
3340}
3341
3342/// [`Features::TIMESTAMP_QUERY`] or [`Features::PIPELINE_STATISTICS_QUERY`] must be enabled on the device in order to call these functions.
3343impl CommandEncoder {
3344 /// Resolve a query set, writing the results into the supplied destination buffer.
3345 ///
3346 /// Queries may be between 8 and 40 bytes each. See [`PipelineStatisticsTypes`] for more information.
3347 pub fn resolve_query_set(
3348 &mut self,
3349 query_set: &QuerySet,
3350 query_range: Range<u32>,
3351 destination: &Buffer,
3352 destination_offset: BufferAddress,
3353 ) {
3354 DynContext::command_encoder_resolve_query_set(
3355 &*self.context,
3356 self.id.as_ref().unwrap(),
3357 self.data.as_ref(),
3358 &query_set.id,
3359 query_set.data.as_ref(),
3360 query_range.start,
3361 query_range.end - query_range.start,
3362 &destination.id,
3363 destination.data.as_ref(),
3364 destination_offset,
3365 )
3366 }
3367}
3368
3369impl<'a> RenderPass<'a> {
3370 /// Sets the active bind group for a given bind group index. The bind group layout
3371 /// in the active pipeline when any `draw()` function is called must match the layout of this bind group.
3372 ///
3373 /// If the bind group have dynamic offsets, provide them in binding order.
3374 /// These offsets have to be aligned to [`Limits::min_uniform_buffer_offset_alignment`]
3375 /// or [`Limits::min_storage_buffer_offset_alignment`] appropriately.
3376 pub fn set_bind_group(
3377 &mut self,
3378 index: u32,
3379 bind_group: &'a BindGroup,
3380 offsets: &[DynamicOffset],
3381 ) {
3382 DynContext::render_pass_set_bind_group(
3383 &*self.parent.context,
3384 &mut self.id,
3385 self.data.as_mut(),
3386 index,
3387 &bind_group.id,
3388 bind_group.data.as_ref(),
3389 offsets,
3390 )
3391 }
3392
3393 /// Sets the active render pipeline.
3394 ///
3395 /// Subsequent draw calls will exhibit the behavior defined by `pipeline`.
3396 pub fn set_pipeline(&mut self, pipeline: &'a RenderPipeline) {
3397 DynContext::render_pass_set_pipeline(
3398 &*self.parent.context,
3399 &mut self.id,
3400 self.data.as_mut(),
3401 &pipeline.id,
3402 pipeline.data.as_ref(),
3403 )
3404 }
3405
3406 /// Sets the blend color as used by some of the blending modes.
3407 ///
3408 /// Subsequent blending tests will test against this value.
3409 pub fn set_blend_constant(&mut self, color: Color) {
3410 DynContext::render_pass_set_blend_constant(
3411 &*self.parent.context,
3412 &mut self.id,
3413 self.data.as_mut(),
3414 color,
3415 )
3416 }
3417
3418 /// Sets the active index buffer.
3419 ///
3420 /// Subsequent calls to [`draw_indexed`](RenderPass::draw_indexed) on this [`RenderPass`] will
3421 /// use `buffer` as the source index buffer.
3422 pub fn set_index_buffer(&mut self, buffer_slice: BufferSlice<'a>, index_format: IndexFormat) {
3423 DynContext::render_pass_set_index_buffer(
3424 &*self.parent.context,
3425 &mut self.id,
3426 self.data.as_mut(),
3427 &buffer_slice.buffer.id,
3428 buffer_slice.buffer.data.as_ref(),
3429 index_format,
3430 buffer_slice.offset,
3431 buffer_slice.size,
3432 )
3433 }
3434
3435 /// Assign a vertex buffer to a slot.
3436 ///
3437 /// Subsequent calls to [`draw`] and [`draw_indexed`] on this
3438 /// [`RenderPass`] will use `buffer` as one of the source vertex buffers.
3439 ///
3440 /// The `slot` refers to the index of the matching descriptor in
3441 /// [`VertexState::buffers`].
3442 ///
3443 /// [`draw`]: RenderPass::draw
3444 /// [`draw_indexed`]: RenderPass::draw_indexed
3445 pub fn set_vertex_buffer(&mut self, slot: u32, buffer_slice: BufferSlice<'a>) {
3446 DynContext::render_pass_set_vertex_buffer(
3447 &*self.parent.context,
3448 &mut self.id,
3449 self.data.as_mut(),
3450 slot,
3451 &buffer_slice.buffer.id,
3452 buffer_slice.buffer.data.as_ref(),
3453 buffer_slice.offset,
3454 buffer_slice.size,
3455 )
3456 }
3457
3458 /// Sets the scissor rectangle used during the rasterization stage.
3459 /// After transformation into [viewport coordinates](https://www.w3.org/TR/webgpu/#viewport-coordinates).
3460 ///
3461 /// Subsequent draw calls will discard any fragments which fall outside the scissor rectangle.
3462 pub fn set_scissor_rect(&mut self, x: u32, y: u32, width: u32, height: u32) {
3463 DynContext::render_pass_set_scissor_rect(
3464 &*self.parent.context,
3465 &mut self.id,
3466 self.data.as_mut(),
3467 x,
3468 y,
3469 width,
3470 height,
3471 );
3472 }
3473
3474 /// Sets the viewport used during the rasterization stage to linearly map
3475 /// from [normalized device coordinates](https://www.w3.org/TR/webgpu/#ndc) to [viewport coordinates](https://www.w3.org/TR/webgpu/#viewport-coordinates).
3476 ///
3477 /// Subsequent draw calls will draw any fragments in this region.
3478 pub fn set_viewport(&mut self, x: f32, y: f32, w: f32, h: f32, min_depth: f32, max_depth: f32) {
3479 DynContext::render_pass_set_viewport(
3480 &*self.parent.context,
3481 &mut self.id,
3482 self.data.as_mut(),
3483 x,
3484 y,
3485 w,
3486 h,
3487 min_depth,
3488 max_depth,
3489 );
3490 }
3491
3492 /// Sets the stencil reference.
3493 ///
3494 /// Subsequent stencil tests will test against this value.
3495 pub fn set_stencil_reference(&mut self, reference: u32) {
3496 DynContext::render_pass_set_stencil_reference(
3497 &*self.parent.context,
3498 &mut self.id,
3499 self.data.as_mut(),
3500 reference,
3501 );
3502 }
3503
3504 /// Draws primitives from the active vertex buffer(s).
3505 ///
3506 /// The active vertex buffer(s) can be set with [`RenderPass::set_vertex_buffer`].
3507 /// Does not use an Index Buffer. If you need this see [`RenderPass::draw_indexed`]
3508 ///
3509 /// Panics if vertices Range is outside of the range of the vertices range of any set vertex buffer.
3510 ///
3511 /// vertices: The range of vertices to draw.
3512 /// instances: Range of Instances to draw. Use 0..1 if instance buffers are not used.
3513 /// E.g.of how its used internally
3514 /// ```rust ignore
3515 /// for instance_id in instance_range {
3516 /// for vertex_id in vertex_range {
3517 /// let vertex = vertex[vertex_id];
3518 /// vertex_shader(vertex, vertex_id, instance_id);
3519 /// }
3520 /// }
3521 /// ```
3522 pub fn draw(&mut self, vertices: Range<u32>, instances: Range<u32>) {
3523 DynContext::render_pass_draw(
3524 &*self.parent.context,
3525 &mut self.id,
3526 self.data.as_mut(),
3527 vertices,
3528 instances,
3529 )
3530 }
3531
3532 /// Inserts debug marker.
3533 pub fn insert_debug_marker(&mut self, label: &str) {
3534 DynContext::render_pass_insert_debug_marker(
3535 &*self.parent.context,
3536 &mut self.id,
3537 self.data.as_mut(),
3538 label,
3539 );
3540 }
3541
3542 /// Start record commands and group it into debug marker group.
3543 pub fn push_debug_group(&mut self, label: &str) {
3544 DynContext::render_pass_push_debug_group(
3545 &*self.parent.context,
3546 &mut self.id,
3547 self.data.as_mut(),
3548 label,
3549 );
3550 }
3551
3552 /// Stops command recording and creates debug group.
3553 pub fn pop_debug_group(&mut self) {
3554 DynContext::render_pass_pop_debug_group(
3555 &*self.parent.context,
3556 &mut self.id,
3557 self.data.as_mut(),
3558 );
3559 }
3560
3561 /// Draws indexed primitives using the active index buffer and the active vertex buffers.
3562 ///
3563 /// The active index buffer can be set with [`RenderPass::set_index_buffer`]
3564 /// The active vertex buffers can be set with [`RenderPass::set_vertex_buffer`].
3565 ///
3566 /// Panics if indices Range is outside of the range of the indices range of any set index buffer.
3567 ///
3568 /// indices: The range of indices to draw.
3569 /// base_vertex: value added to each index value before indexing into the vertex buffers.
3570 /// instances: Range of Instances to draw. Use 0..1 if instance buffers are not used.
3571 /// E.g.of how its used internally
3572 /// ```rust ignore
3573 /// for instance_id in instance_range {
3574 /// for index_index in index_range {
3575 /// let vertex_id = index_buffer[index_index];
3576 /// let adjusted_vertex_id = vertex_id + base_vertex;
3577 /// let vertex = vertex[adjusted_vertex_id];
3578 /// vertex_shader(vertex, adjusted_vertex_id, instance_id);
3579 /// }
3580 /// }
3581 /// ```
3582 pub fn draw_indexed(&mut self, indices: Range<u32>, base_vertex: i32, instances: Range<u32>) {
3583 DynContext::render_pass_draw_indexed(
3584 &*self.parent.context,
3585 &mut self.id,
3586 self.data.as_mut(),
3587 indices,
3588 base_vertex,
3589 instances,
3590 );
3591 }
3592
3593 /// Draws primitives from the active vertex buffer(s) based on the contents of the `indirect_buffer`.
3594 ///
3595 /// The active vertex buffers can be set with [`RenderPass::set_vertex_buffer`].
3596 ///
3597 /// The structure expected in `indirect_buffer` must conform to [`DrawIndirect`](crate::util::DrawIndirect).
3598 pub fn draw_indirect(&mut self, indirect_buffer: &'a Buffer, indirect_offset: BufferAddress) {
3599 DynContext::render_pass_draw_indirect(
3600 &*self.parent.context,
3601 &mut self.id,
3602 self.data.as_mut(),
3603 &indirect_buffer.id,
3604 indirect_buffer.data.as_ref(),
3605 indirect_offset,
3606 );
3607 }
3608
3609 /// Draws indexed primitives using the active index buffer and the active vertex buffers,
3610 /// based on the contents of the `indirect_buffer`.
3611 ///
3612 /// The active index buffer can be set with [`RenderPass::set_index_buffer`], while the active
3613 /// vertex buffers can be set with [`RenderPass::set_vertex_buffer`].
3614 ///
3615 /// The structure expected in `indirect_buffer` must conform to [`DrawIndexedIndirect`](crate::util::DrawIndexedIndirect).
3616 pub fn draw_indexed_indirect(
3617 &mut self,
3618 indirect_buffer: &'a Buffer,
3619 indirect_offset: BufferAddress,
3620 ) {
3621 DynContext::render_pass_draw_indexed_indirect(
3622 &*self.parent.context,
3623 &mut self.id,
3624 self.data.as_mut(),
3625 &indirect_buffer.id,
3626 indirect_buffer.data.as_ref(),
3627 indirect_offset,
3628 );
3629 }
3630
3631 /// Execute a [render bundle][RenderBundle], which is a set of pre-recorded commands
3632 /// that can be run together.
3633 pub fn execute_bundles<I: IntoIterator<Item = &'a RenderBundle> + 'a>(
3634 &mut self,
3635 render_bundles: I,
3636 ) {
3637 DynContext::render_pass_execute_bundles(
3638 &*self.parent.context,
3639 &mut self.id,
3640 self.data.as_mut(),
3641 Box::new(
3642 render_bundles
3643 .into_iter()
3644 .map(|rb| (&rb.id, rb.data.as_ref())),
3645 ),
3646 )
3647 }
3648}
3649
3650/// [`Features::MULTI_DRAW_INDIRECT`] must be enabled on the device in order to call these functions.
3651impl<'a> RenderPass<'a> {
3652 /// Dispatches multiple draw calls from the active vertex buffer(s) based on the contents of the `indirect_buffer`.
3653 /// `count` draw calls are issued.
3654 ///
3655 /// The active vertex buffers can be set with [`RenderPass::set_vertex_buffer`].
3656 ///
3657 /// The structure expected in `indirect_buffer` must conform to [`DrawIndirect`](crate::util::DrawIndirect).
3658 ///
3659 /// These draw structures are expected to be tightly packed.
3660 pub fn multi_draw_indirect(
3661 &mut self,
3662 indirect_buffer: &'a Buffer,
3663 indirect_offset: BufferAddress,
3664 count: u32,
3665 ) {
3666 DynContext::render_pass_multi_draw_indirect(
3667 &*self.parent.context,
3668 &mut self.id,
3669 self.data.as_mut(),
3670 &indirect_buffer.id,
3671 indirect_buffer.data.as_ref(),
3672 indirect_offset,
3673 count,
3674 );
3675 }
3676
3677 /// Dispatches multiple draw calls from the active index buffer and the active vertex buffers,
3678 /// based on the contents of the `indirect_buffer`. `count` draw calls are issued.
3679 ///
3680 /// The active index buffer can be set with [`RenderPass::set_index_buffer`], while the active
3681 /// vertex buffers can be set with [`RenderPass::set_vertex_buffer`].
3682 ///
3683 /// The structure expected in `indirect_buffer` must conform to [`DrawIndexedIndirect`](crate::util::DrawIndexedIndirect).
3684 ///
3685 /// These draw structures are expected to be tightly packed.
3686 pub fn multi_draw_indexed_indirect(
3687 &mut self,
3688 indirect_buffer: &'a Buffer,
3689 indirect_offset: BufferAddress,
3690 count: u32,
3691 ) {
3692 DynContext::render_pass_multi_draw_indexed_indirect(
3693 &*self.parent.context,
3694 &mut self.id,
3695 self.data.as_mut(),
3696 &indirect_buffer.id,
3697 indirect_buffer.data.as_ref(),
3698 indirect_offset,
3699 count,
3700 );
3701 }
3702}
3703
3704/// [`Features::MULTI_DRAW_INDIRECT_COUNT`] must be enabled on the device in order to call these functions.
3705impl<'a> RenderPass<'a> {
3706 /// Dispatches multiple draw calls from the active vertex buffer(s) based on the contents of the `indirect_buffer`.
3707 /// The count buffer is read to determine how many draws to issue.
3708 ///
3709 /// The indirect buffer must be long enough to account for `max_count` draws, however only `count`
3710 /// draws will be read. If `count` is greater than `max_count`, `max_count` will be used.
3711 ///
3712 /// The active vertex buffers can be set with [`RenderPass::set_vertex_buffer`].
3713 ///
3714 /// The structure expected in `indirect_buffer` must conform to [`DrawIndirect`](crate::util::DrawIndirect).
3715 ///
3716 /// These draw structures are expected to be tightly packed.
3717 ///
3718 /// The structure expected in `count_buffer` is the following:
3719 ///
3720 /// ```rust
3721 /// #[repr(C)]
3722 /// struct DrawIndirectCount {
3723 /// count: u32, // Number of draw calls to issue.
3724 /// }
3725 /// ```
3726 pub fn multi_draw_indirect_count(
3727 &mut self,
3728 indirect_buffer: &'a Buffer,
3729 indirect_offset: BufferAddress,
3730 count_buffer: &'a Buffer,
3731 count_offset: BufferAddress,
3732 max_count: u32,
3733 ) {
3734 DynContext::render_pass_multi_draw_indirect_count(
3735 &*self.parent.context,
3736 &mut self.id,
3737 self.data.as_mut(),
3738 &indirect_buffer.id,
3739 indirect_buffer.data.as_ref(),
3740 indirect_offset,
3741 &count_buffer.id,
3742 count_buffer.data.as_ref(),
3743 count_offset,
3744 max_count,
3745 );
3746 }
3747
3748 /// Dispatches multiple draw calls from the active index buffer and the active vertex buffers,
3749 /// based on the contents of the `indirect_buffer`. The count buffer is read to determine how many draws to issue.
3750 ///
3751 /// The indirect buffer must be long enough to account for `max_count` draws, however only `count`
3752 /// draws will be read. If `count` is greater than `max_count`, `max_count` will be used.
3753 ///
3754 /// The active index buffer can be set with [`RenderPass::set_index_buffer`], while the active
3755 /// vertex buffers can be set with [`RenderPass::set_vertex_buffer`].
3756 ///
3757 ///
3758 /// The structure expected in `indirect_buffer` must conform to [`DrawIndexedIndirect`](crate::util::DrawIndexedIndirect).
3759 ///
3760 /// These draw structures are expected to be tightly packed.
3761 ///
3762 /// The structure expected in `count_buffer` is the following:
3763 ///
3764 /// ```rust
3765 /// #[repr(C)]
3766 /// struct DrawIndexedIndirectCount {
3767 /// count: u32, // Number of draw calls to issue.
3768 /// }
3769 /// ```
3770 pub fn multi_draw_indexed_indirect_count(
3771 &mut self,
3772 indirect_buffer: &'a Buffer,
3773 indirect_offset: BufferAddress,
3774 count_buffer: &'a Buffer,
3775 count_offset: BufferAddress,
3776 max_count: u32,
3777 ) {
3778 DynContext::render_pass_multi_draw_indexed_indirect_count(
3779 &*self.parent.context,
3780 &mut self.id,
3781 self.data.as_mut(),
3782 &indirect_buffer.id,
3783 indirect_buffer.data.as_ref(),
3784 indirect_offset,
3785 &count_buffer.id,
3786 count_buffer.data.as_ref(),
3787 count_offset,
3788 max_count,
3789 );
3790 }
3791}
3792
3793/// [`Features::PUSH_CONSTANTS`] must be enabled on the device in order to call these functions.
3794impl<'a> RenderPass<'a> {
3795 /// Set push constant data for subsequent draw calls.
3796 ///
3797 /// Write the bytes in `data` at offset `offset` within push constant
3798 /// storage, all of which are accessible by all the pipeline stages in
3799 /// `stages`, and no others. Both `offset` and the length of `data` must be
3800 /// multiples of [`PUSH_CONSTANT_ALIGNMENT`], which is always 4.
3801 ///
3802 /// For example, if `offset` is `4` and `data` is eight bytes long, this
3803 /// call will write `data` to bytes `4..12` of push constant storage.
3804 ///
3805 /// # Stage matching
3806 ///
3807 /// Every byte in the affected range of push constant storage must be
3808 /// accessible to exactly the same set of pipeline stages, which must match
3809 /// `stages`. If there are two bytes of storage that are accessible by
3810 /// different sets of pipeline stages - say, one is accessible by fragment
3811 /// shaders, and the other is accessible by both fragment shaders and vertex
3812 /// shaders - then no single `set_push_constants` call may affect both of
3813 /// them; to write both, you must make multiple calls, each with the
3814 /// appropriate `stages` value.
3815 ///
3816 /// Which pipeline stages may access a given byte is determined by the
3817 /// pipeline's [`PushConstant`] global variable and (if it is a struct) its
3818 /// members' offsets.
3819 ///
3820 /// For example, suppose you have twelve bytes of push constant storage,
3821 /// where bytes `0..8` are accessed by the vertex shader, and bytes `4..12`
3822 /// are accessed by the fragment shader. This means there are three byte
3823 /// ranges each accessed by a different set of stages:
3824 ///
3825 /// - Bytes `0..4` are accessed only by the fragment shader.
3826 ///
3827 /// - Bytes `4..8` are accessed by both the fragment shader and the vertex shader.
3828 ///
3829 /// - Bytes `8..12` are accessed only by the vertex shader.
3830 ///
3831 /// To write all twelve bytes requires three `set_push_constants` calls, one
3832 /// for each range, each passing the matching `stages` mask.
3833 ///
3834 /// [`PushConstant`]: https://docs.rs/naga/latest/naga/enum.StorageClass.html#variant.PushConstant
3835 pub fn set_push_constants(&mut self, stages: ShaderStages, offset: u32, data: &[u8]) {
3836 DynContext::render_pass_set_push_constants(
3837 &*self.parent.context,
3838 &mut self.id,
3839 self.data.as_mut(),
3840 stages,
3841 offset,
3842 data,
3843 );
3844 }
3845}
3846
3847/// [`Features::TIMESTAMP_QUERY_INSIDE_PASSES`] must be enabled on the device in order to call these functions.
3848impl<'a> RenderPass<'a> {
3849 /// Issue a timestamp command at this point in the queue. The
3850 /// timestamp will be written to the specified query set, at the specified index.
3851 ///
3852 /// Must be multiplied by [`Queue::get_timestamp_period`] to get
3853 /// the value in nanoseconds. Absolute values have no meaning,
3854 /// but timestamps can be subtracted to get the time it takes
3855 /// for a string of operations to complete.
3856 pub fn write_timestamp(&mut self, query_set: &QuerySet, query_index: u32) {
3857 DynContext::render_pass_write_timestamp(
3858 &*self.parent.context,
3859 &mut self.id,
3860 self.data.as_mut(),
3861 &query_set.id,
3862 query_set.data.as_ref(),
3863 query_index,
3864 )
3865 }
3866}
3867
3868/// [`Features::PIPELINE_STATISTICS_QUERY`] must be enabled on the device in order to call these functions.
3869impl<'a> RenderPass<'a> {
3870 /// Start a pipeline statistics query on this render pass. It can be ended with
3871 /// `end_pipeline_statistics_query`. Pipeline statistics queries may not be nested.
3872 pub fn begin_pipeline_statistics_query(&mut self, query_set: &QuerySet, query_index: u32) {
3873 DynContext::render_pass_begin_pipeline_statistics_query(
3874 &*self.parent.context,
3875 &mut self.id,
3876 self.data.as_mut(),
3877 &query_set.id,
3878 query_set.data.as_ref(),
3879 query_index,
3880 );
3881 }
3882
3883 /// End the pipeline statistics query on this render pass. It can be started with
3884 /// `begin_pipeline_statistics_query`. Pipeline statistics queries may not be nested.
3885 pub fn end_pipeline_statistics_query(&mut self) {
3886 DynContext::render_pass_end_pipeline_statistics_query(
3887 &*self.parent.context,
3888 &mut self.id,
3889 self.data.as_mut(),
3890 );
3891 }
3892}
3893
3894impl<'a> Drop for RenderPass<'a> {
3895 fn drop(&mut self) {
3896 if !thread::panicking() {
3897 let parent_id = self.parent.id.as_ref().unwrap();
3898 self.parent.context.command_encoder_end_render_pass(
3899 parent_id,
3900 self.parent.data.as_ref(),
3901 &mut self.id,
3902 self.data.as_mut(),
3903 );
3904 }
3905 }
3906}
3907
3908impl<'a> ComputePass<'a> {
3909 /// Sets the active bind group for a given bind group index. The bind group layout
3910 /// in the active pipeline when the `dispatch()` function is called must match the layout of this bind group.
3911 ///
3912 /// If the bind group have dynamic offsets, provide them in the binding order.
3913 /// These offsets have to be aligned to [`Limits::min_uniform_buffer_offset_alignment`]
3914 /// or [`Limits::min_storage_buffer_offset_alignment`] appropriately.
3915 pub fn set_bind_group(
3916 &mut self,
3917 index: u32,
3918 bind_group: &'a BindGroup,
3919 offsets: &[DynamicOffset],
3920 ) {
3921 DynContext::compute_pass_set_bind_group(
3922 &*self.parent.context,
3923 &mut self.id,
3924 self.data.as_mut(),
3925 index,
3926 &bind_group.id,
3927 bind_group.data.as_ref(),
3928 offsets,
3929 );
3930 }
3931
3932 /// Sets the active compute pipeline.
3933 pub fn set_pipeline(&mut self, pipeline: &'a ComputePipeline) {
3934 DynContext::compute_pass_set_pipeline(
3935 &*self.parent.context,
3936 &mut self.id,
3937 self.data.as_mut(),
3938 &pipeline.id,
3939 pipeline.data.as_ref(),
3940 );
3941 }
3942
3943 /// Inserts debug marker.
3944 pub fn insert_debug_marker(&mut self, label: &str) {
3945 DynContext::compute_pass_insert_debug_marker(
3946 &*self.parent.context,
3947 &mut self.id,
3948 self.data.as_mut(),
3949 label,
3950 );
3951 }
3952
3953 /// Start record commands and group it into debug marker group.
3954 pub fn push_debug_group(&mut self, label: &str) {
3955 DynContext::compute_pass_push_debug_group(
3956 &*self.parent.context,
3957 &mut self.id,
3958 self.data.as_mut(),
3959 label,
3960 );
3961 }
3962
3963 /// Stops command recording and creates debug group.
3964 pub fn pop_debug_group(&mut self) {
3965 DynContext::compute_pass_pop_debug_group(
3966 &*self.parent.context,
3967 &mut self.id,
3968 self.data.as_mut(),
3969 );
3970 }
3971
3972 /// Dispatches compute work operations.
3973 ///
3974 /// `x`, `y` and `z` denote the number of work groups to dispatch in each dimension.
3975 pub fn dispatch_workgroups(&mut self, x: u32, y: u32, z: u32) {
3976 DynContext::compute_pass_dispatch_workgroups(
3977 &*self.parent.context,
3978 &mut self.id,
3979 self.data.as_mut(),
3980 x,
3981 y,
3982 z,
3983 );
3984 }
3985
3986 /// Dispatches compute work operations, based on the contents of the `indirect_buffer`.
3987 ///
3988 /// The structure expected in `indirect_buffer` must conform to [`DispatchIndirect`](crate::util::DispatchIndirect).
3989 pub fn dispatch_workgroups_indirect(
3990 &mut self,
3991 indirect_buffer: &'a Buffer,
3992 indirect_offset: BufferAddress,
3993 ) {
3994 DynContext::compute_pass_dispatch_workgroups_indirect(
3995 &*self.parent.context,
3996 &mut self.id,
3997 self.data.as_mut(),
3998 &indirect_buffer.id,
3999 indirect_buffer.data.as_ref(),
4000 indirect_offset,
4001 );
4002 }
4003}
4004
4005/// [`Features::PUSH_CONSTANTS`] must be enabled on the device in order to call these functions.
4006impl<'a> ComputePass<'a> {
4007 /// Set push constant data for subsequent dispatch calls.
4008 ///
4009 /// Write the bytes in `data` at offset `offset` within push constant
4010 /// storage. Both `offset` and the length of `data` must be
4011 /// multiples of [`PUSH_CONSTANT_ALIGNMENT`], which is always 4.
4012 ///
4013 /// For example, if `offset` is `4` and `data` is eight bytes long, this
4014 /// call will write `data` to bytes `4..12` of push constant storage.
4015 pub fn set_push_constants(&mut self, offset: u32, data: &[u8]) {
4016 DynContext::compute_pass_set_push_constants(
4017 &*self.parent.context,
4018 &mut self.id,
4019 self.data.as_mut(),
4020 offset,
4021 data,
4022 );
4023 }
4024}
4025
4026/// [`Features::TIMESTAMP_QUERY_INSIDE_PASSES`] must be enabled on the device in order to call these functions.
4027impl<'a> ComputePass<'a> {
4028 /// Issue a timestamp command at this point in the queue. The timestamp will be written to the specified query set, at the specified index.
4029 ///
4030 /// Must be multiplied by [`Queue::get_timestamp_period`] to get
4031 /// the value in nanoseconds. Absolute values have no meaning,
4032 /// but timestamps can be subtracted to get the time it takes
4033 /// for a string of operations to complete.
4034 pub fn write_timestamp(&mut self, query_set: &QuerySet, query_index: u32) {
4035 DynContext::compute_pass_write_timestamp(
4036 &*self.parent.context,
4037 &mut self.id,
4038 self.data.as_mut(),
4039 &query_set.id,
4040 query_set.data.as_ref(),
4041 query_index,
4042 )
4043 }
4044}
4045
4046/// [`Features::PIPELINE_STATISTICS_QUERY`] must be enabled on the device in order to call these functions.
4047impl<'a> ComputePass<'a> {
4048 /// Start a pipeline statistics query on this render pass. It can be ended with
4049 /// `end_pipeline_statistics_query`. Pipeline statistics queries may not be nested.
4050 pub fn begin_pipeline_statistics_query(&mut self, query_set: &QuerySet, query_index: u32) {
4051 DynContext::compute_pass_begin_pipeline_statistics_query(
4052 &*self.parent.context,
4053 &mut self.id,
4054 self.data.as_mut(),
4055 &query_set.id,
4056 query_set.data.as_ref(),
4057 query_index,
4058 );
4059 }
4060
4061 /// End the pipeline statistics query on this render pass. It can be started with
4062 /// `begin_pipeline_statistics_query`. Pipeline statistics queries may not be nested.
4063 pub fn end_pipeline_statistics_query(&mut self) {
4064 DynContext::compute_pass_end_pipeline_statistics_query(
4065 &*self.parent.context,
4066 &mut self.id,
4067 self.data.as_mut(),
4068 );
4069 }
4070}
4071
4072impl<'a> Drop for ComputePass<'a> {
4073 fn drop(&mut self) {
4074 if !thread::panicking() {
4075 let parent_id = self.parent.id.as_ref().unwrap();
4076 self.parent.context.command_encoder_end_compute_pass(
4077 parent_id,
4078 self.parent.data.as_ref(),
4079 &mut self.id,
4080 self.data.as_mut(),
4081 );
4082 }
4083 }
4084}
4085
4086impl<'a> RenderBundleEncoder<'a> {
4087 /// Finishes recording and returns a [`RenderBundle`] that can be executed in other render passes.
4088 pub fn finish(self, desc: &RenderBundleDescriptor) -> RenderBundle {
4089 let (id, data) =
4090 DynContext::render_bundle_encoder_finish(&*self.context, self.id, self.data, desc);
4091 RenderBundle {
4092 context: Arc::clone(&self.context),
4093 id,
4094 data,
4095 }
4096 }
4097
4098 /// Sets the active bind group for a given bind group index. The bind group layout
4099 /// in the active pipeline when any `draw()` function is called must match the layout of this bind group.
4100 ///
4101 /// If the bind group have dynamic offsets, provide them in the binding order.
4102 pub fn set_bind_group(
4103 &mut self,
4104 index: u32,
4105 bind_group: &'a BindGroup,
4106 offsets: &[DynamicOffset],
4107 ) {
4108 DynContext::render_bundle_encoder_set_bind_group(
4109 &*self.parent.context,
4110 &mut self.id,
4111 self.data.as_mut(),
4112 index,
4113 &bind_group.id,
4114 bind_group.data.as_ref(),
4115 offsets,
4116 )
4117 }
4118
4119 /// Sets the active render pipeline.
4120 ///
4121 /// Subsequent draw calls will exhibit the behavior defined by `pipeline`.
4122 pub fn set_pipeline(&mut self, pipeline: &'a RenderPipeline) {
4123 DynContext::render_bundle_encoder_set_pipeline(
4124 &*self.parent.context,
4125 &mut self.id,
4126 self.data.as_mut(),
4127 &pipeline.id,
4128 pipeline.data.as_ref(),
4129 )
4130 }
4131
4132 /// Sets the active index buffer.
4133 ///
4134 /// Subsequent calls to [`draw_indexed`](RenderBundleEncoder::draw_indexed) on this [`RenderBundleEncoder`] will
4135 /// use `buffer` as the source index buffer.
4136 pub fn set_index_buffer(&mut self, buffer_slice: BufferSlice<'a>, index_format: IndexFormat) {
4137 DynContext::render_bundle_encoder_set_index_buffer(
4138 &*self.parent.context,
4139 &mut self.id,
4140 self.data.as_mut(),
4141 &buffer_slice.buffer.id,
4142 buffer_slice.buffer.data.as_ref(),
4143 index_format,
4144 buffer_slice.offset,
4145 buffer_slice.size,
4146 )
4147 }
4148
4149 /// Assign a vertex buffer to a slot.
4150 ///
4151 /// Subsequent calls to [`draw`] and [`draw_indexed`] on this
4152 /// [`RenderBundleEncoder`] will use `buffer` as one of the source vertex buffers.
4153 ///
4154 /// The `slot` refers to the index of the matching descriptor in
4155 /// [`VertexState::buffers`].
4156 ///
4157 /// [`draw`]: RenderBundleEncoder::draw
4158 /// [`draw_indexed`]: RenderBundleEncoder::draw_indexed
4159 pub fn set_vertex_buffer(&mut self, slot: u32, buffer_slice: BufferSlice<'a>) {
4160 DynContext::render_bundle_encoder_set_vertex_buffer(
4161 &*self.parent.context,
4162 &mut self.id,
4163 self.data.as_mut(),
4164 slot,
4165 &buffer_slice.buffer.id,
4166 buffer_slice.buffer.data.as_ref(),
4167 buffer_slice.offset,
4168 buffer_slice.size,
4169 )
4170 }
4171
4172 /// Draws primitives from the active vertex buffer(s).
4173 ///
4174 /// The active vertex buffers can be set with [`RenderBundleEncoder::set_vertex_buffer`].
4175 /// Does not use an Index Buffer. If you need this see [`RenderBundleEncoder::draw_indexed`]
4176 ///
4177 /// Panics if vertices Range is outside of the range of the vertices range of any set vertex buffer.
4178 ///
4179 /// vertices: The range of vertices to draw.
4180 /// instances: Range of Instances to draw. Use 0..1 if instance buffers are not used.
4181 /// E.g.of how its used internally
4182 /// ```rust ignore
4183 /// for instance_id in instance_range {
4184 /// for vertex_id in vertex_range {
4185 /// let vertex = vertex[vertex_id];
4186 /// vertex_shader(vertex, vertex_id, instance_id);
4187 /// }
4188 /// }
4189 /// ```
4190 pub fn draw(&mut self, vertices: Range<u32>, instances: Range<u32>) {
4191 DynContext::render_bundle_encoder_draw(
4192 &*self.parent.context,
4193 &mut self.id,
4194 self.data.as_mut(),
4195 vertices,
4196 instances,
4197 )
4198 }
4199
4200 /// Draws indexed primitives using the active index buffer and the active vertex buffer(s).
4201 ///
4202 /// The active index buffer can be set with [`RenderBundleEncoder::set_index_buffer`].
4203 /// The active vertex buffer(s) can be set with [`RenderBundleEncoder::set_vertex_buffer`].
4204 ///
4205 /// Panics if indices Range is outside of the range of the indices range of any set index buffer.
4206 ///
4207 /// indices: The range of indices to draw.
4208 /// base_vertex: value added to each index value before indexing into the vertex buffers.
4209 /// instances: Range of Instances to draw. Use 0..1 if instance buffers are not used.
4210 /// E.g.of how its used internally
4211 /// ```rust ignore
4212 /// for instance_id in instance_range {
4213 /// for index_index in index_range {
4214 /// let vertex_id = index_buffer[index_index];
4215 /// let adjusted_vertex_id = vertex_id + base_vertex;
4216 /// let vertex = vertex[adjusted_vertex_id];
4217 /// vertex_shader(vertex, adjusted_vertex_id, instance_id);
4218 /// }
4219 /// }
4220 /// ```
4221 pub fn draw_indexed(&mut self, indices: Range<u32>, base_vertex: i32, instances: Range<u32>) {
4222 DynContext::render_bundle_encoder_draw_indexed(
4223 &*self.parent.context,
4224 &mut self.id,
4225 self.data.as_mut(),
4226 indices,
4227 base_vertex,
4228 instances,
4229 );
4230 }
4231
4232 /// Draws primitives from the active vertex buffer(s) based on the contents of the `indirect_buffer`.
4233 ///
4234 /// The active vertex buffers can be set with [`RenderBundleEncoder::set_vertex_buffer`].
4235 ///
4236 /// The structure expected in `indirect_buffer` must conform to [`DrawIndirect`](crate::util::DrawIndirect).
4237 pub fn draw_indirect(&mut self, indirect_buffer: &'a Buffer, indirect_offset: BufferAddress) {
4238 DynContext::render_bundle_encoder_draw_indirect(
4239 &*self.parent.context,
4240 &mut self.id,
4241 self.data.as_mut(),
4242 &indirect_buffer.id,
4243 indirect_buffer.data.as_ref(),
4244 indirect_offset,
4245 );
4246 }
4247
4248 /// Draws indexed primitives using the active index buffer and the active vertex buffers,
4249 /// based on the contents of the `indirect_buffer`.
4250 ///
4251 /// The active index buffer can be set with [`RenderBundleEncoder::set_index_buffer`], while the active
4252 /// vertex buffers can be set with [`RenderBundleEncoder::set_vertex_buffer`].
4253 ///
4254 /// The structure expected in `indirect_buffer` must conform to [`DrawIndexedIndirect`](crate::util::DrawIndexedIndirect).
4255 pub fn draw_indexed_indirect(
4256 &mut self,
4257 indirect_buffer: &'a Buffer,
4258 indirect_offset: BufferAddress,
4259 ) {
4260 DynContext::render_bundle_encoder_draw_indexed_indirect(
4261 &*self.parent.context,
4262 &mut self.id,
4263 self.data.as_mut(),
4264 &indirect_buffer.id,
4265 indirect_buffer.data.as_ref(),
4266 indirect_offset,
4267 );
4268 }
4269}
4270
4271/// [`Features::PUSH_CONSTANTS`] must be enabled on the device in order to call these functions.
4272impl<'a> RenderBundleEncoder<'a> {
4273 /// Set push constant data.
4274 ///
4275 /// Offset is measured in bytes, but must be a multiple of [`PUSH_CONSTANT_ALIGNMENT`].
4276 ///
4277 /// Data size must be a multiple of 4 and must have an alignment of 4.
4278 /// For example, with an offset of 4 and an array of `[u8; 8]`, that will write to the range
4279 /// of 4..12.
4280 ///
4281 /// For each byte in the range of push constant data written, the union of the stages of all push constant
4282 /// ranges that covers that byte must be exactly `stages`. There's no good way of explaining this simply,
4283 /// so here are some examples:
4284 ///
4285 /// ```text
4286 /// For the given ranges:
4287 /// - 0..4 Vertex
4288 /// - 4..8 Fragment
4289 /// ```
4290 ///
4291 /// You would need to upload this in two set_push_constants calls. First for the `Vertex` range, second for the `Fragment` range.
4292 ///
4293 /// ```text
4294 /// For the given ranges:
4295 /// - 0..8 Vertex
4296 /// - 4..12 Fragment
4297 /// ```
4298 ///
4299 /// You would need to upload this in three set_push_constants calls. First for the `Vertex` only range 0..4, second
4300 /// for the `Vertex | Fragment` range 4..8, third for the `Fragment` range 8..12.
4301 pub fn set_push_constants(&mut self, stages: ShaderStages, offset: u32, data: &[u8]) {
4302 DynContext::render_bundle_encoder_set_push_constants(
4303 &*self.parent.context,
4304 &mut self.id,
4305 self.data.as_mut(),
4306 stages,
4307 offset,
4308 data,
4309 );
4310 }
4311}
4312
4313/// A read-only view into a staging buffer.
4314///
4315/// Reading into this buffer won't yield the contents of the buffer from the
4316/// GPU and is likely to be slow. Because of this, although [`AsMut`] is
4317/// implemented for this type, [`AsRef`] is not.
4318pub struct QueueWriteBufferView<'a> {
4319 queue: &'a Queue,
4320 buffer: &'a Buffer,
4321 offset: BufferAddress,
4322 inner: Box<dyn context::QueueWriteBuffer>,
4323}
4324#[cfg(any(
4325 not(target_arch = "wasm32"),
4326 all(
4327 feature = "fragile-send-sync-non-atomic-wasm",
4328 not(target_feature = "atomics")
4329 )
4330))]
4331static_assertions::assert_impl_all!(QueueWriteBufferView: Send, Sync);
4332
4333impl Deref for QueueWriteBufferView<'_> {
4334 type Target = [u8];
4335
4336 fn deref(&self) -> &Self::Target {
4337 log::warn!("Reading from a QueueWriteBufferView won't yield the contents of the buffer and may be slow.");
4338 self.inner.slice()
4339 }
4340}
4341
4342impl DerefMut for QueueWriteBufferView<'_> {
4343 fn deref_mut(&mut self) -> &mut Self::Target {
4344 self.inner.slice_mut()
4345 }
4346}
4347
4348impl<'a> AsMut<[u8]> for QueueWriteBufferView<'a> {
4349 fn as_mut(&mut self) -> &mut [u8] {
4350 self.inner.slice_mut()
4351 }
4352}
4353
4354impl<'a> Drop for QueueWriteBufferView<'a> {
4355 fn drop(&mut self) {
4356 DynContext::queue_write_staging_buffer(
4357 &*self.queue.context,
4358 &self.queue.id,
4359 self.queue.data.as_ref(),
4360 &self.buffer.id,
4361 self.buffer.data.as_ref(),
4362 self.offset,
4363 &*self.inner,
4364 );
4365 }
4366}
4367
4368impl Queue {
4369 /// Schedule a data write into `buffer` starting at `offset`.
4370 ///
4371 /// This method is intended to have low performance costs.
4372 /// As such, the write is not immediately submitted, and instead enqueued
4373 /// internally to happen at the start of the next `submit()` call.
4374 ///
4375 /// This method fails if `data` overruns the size of `buffer` starting at `offset`.
4376 pub fn write_buffer(&self, buffer: &Buffer, offset: BufferAddress, data: &[u8]) {
4377 DynContext::queue_write_buffer(
4378 &*self.context,
4379 &self.id,
4380 self.data.as_ref(),
4381 &buffer.id,
4382 buffer.data.as_ref(),
4383 offset,
4384 data,
4385 )
4386 }
4387
4388 /// Schedule a data write into `buffer` starting at `offset` via the returned
4389 /// [`QueueWriteBufferView`].
4390 ///
4391 /// Reading from this buffer is slow and will not yield the actual contents of the buffer.
4392 ///
4393 /// This method is intended to have low performance costs.
4394 /// As such, the write is not immediately submitted, and instead enqueued
4395 /// internally to happen at the start of the next `submit()` call.
4396 ///
4397 /// This method fails if `size` is greater than the size of `buffer` starting at `offset`.
4398 #[must_use]
4399 pub fn write_buffer_with<'a>(
4400 &'a self,
4401 buffer: &'a Buffer,
4402 offset: BufferAddress,
4403 size: BufferSize,
4404 ) -> Option<QueueWriteBufferView<'a>> {
4405 profiling::scope!("Queue::write_buffer_with");
4406 DynContext::queue_validate_write_buffer(
4407 &*self.context,
4408 &self.id,
4409 self.data.as_ref(),
4410 &buffer.id,
4411 buffer.data.as_ref(),
4412 offset,
4413 size,
4414 )?;
4415 let staging_buffer = DynContext::queue_create_staging_buffer(
4416 &*self.context,
4417 &self.id,
4418 self.data.as_ref(),
4419 size,
4420 )?;
4421 Some(QueueWriteBufferView {
4422 queue: self,
4423 buffer,
4424 offset,
4425 inner: staging_buffer,
4426 })
4427 }
4428
4429 /// Schedule a write of some data into a texture.
4430 ///
4431 /// * `data` contains the texels to be written, which must be in
4432 /// [the same format as the texture](TextureFormat).
4433 /// * `data_layout` describes the memory layout of `data`, which does not necessarily
4434 /// have to have tightly packed rows.
4435 /// * `texture` specifies the texture to write into, and the location within the
4436 /// texture (coordinate offset, mip level) that will be overwritten.
4437 /// * `size` is the size, in texels, of the region to be written.
4438 ///
4439 /// This method is intended to have low performance costs.
4440 /// As such, the write is not immediately submitted, and instead enqueued
4441 /// internally to happen at the start of the next `submit()` call.
4442 /// However, `data` will be immediately copied into staging memory; so the caller may
4443 /// discard it any time after this call completes.
4444 ///
4445 /// This method fails if `size` overruns the size of `texture`, or if `data` is too short.
4446 pub fn write_texture(
4447 &self,
4448 texture: ImageCopyTexture,
4449 data: &[u8],
4450 data_layout: ImageDataLayout,
4451 size: Extent3d,
4452 ) {
4453 DynContext::queue_write_texture(
4454 &*self.context,
4455 &self.id,
4456 self.data.as_ref(),
4457 texture,
4458 data,
4459 data_layout,
4460 size,
4461 )
4462 }
4463
4464 /// Schedule a copy of data from `image` into `texture`.
4465 #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
4466 pub fn copy_external_image_to_texture(
4467 &self,
4468 source: &wgt::ImageCopyExternalImage,
4469 dest: ImageCopyTextureTagged,
4470 size: Extent3d,
4471 ) {
4472 DynContext::queue_copy_external_image_to_texture(
4473 &*self.context,
4474 &self.id,
4475 self.data.as_ref(),
4476 source,
4477 dest,
4478 size,
4479 )
4480 }
4481
4482 /// Submits a series of finished command buffers for execution.
4483 pub fn submit<I: IntoIterator<Item = CommandBuffer>>(
4484 &self,
4485 command_buffers: I,
4486 ) -> SubmissionIndex {
4487 let (raw, data) = DynContext::queue_submit(
4488 &*self.context,
4489 &self.id,
4490 self.data.as_ref(),
4491 Box::new(
4492 command_buffers
4493 .into_iter()
4494 .map(|mut comb| (comb.id.take().unwrap(), comb.data.take().unwrap())),
4495 ),
4496 );
4497
4498 SubmissionIndex(raw, data)
4499 }
4500
4501 /// Gets the amount of nanoseconds each tick of a timestamp query represents.
4502 ///
4503 /// Returns zero if timestamp queries are unsupported.
4504 pub fn get_timestamp_period(&self) -> f32 {
4505 DynContext::queue_get_timestamp_period(&*self.context, &self.id, self.data.as_ref())
4506 }
4507
4508 /// Registers a callback when the previous call to submit finishes running on the gpu. This callback
4509 /// being called implies that all mapped buffer callbacks attached to the same submission have also
4510 /// been called.
4511 ///
4512 /// For the callback to complete, either `queue.submit(..)`, `instance.poll_all(..)`, or `device.poll(..)`
4513 /// must be called elsewhere in the runtime, possibly integrated into an event loop or run on a separate thread.
4514 ///
4515 /// The callback will be called on the thread that first calls the above functions after the gpu work
4516 /// has completed. There are no restrictions on the code you can run in the callback, however on native the
4517 /// call to the function will not complete until the callback returns, so prefer keeping callbacks short
4518 /// and used to set flags, send messages, etc.
4519 pub fn on_submitted_work_done(&self, callback: impl FnOnce() + Send + 'static) {
4520 DynContext::queue_on_submitted_work_done(
4521 &*self.context,
4522 &self.id,
4523 self.data.as_ref(),
4524 Box::new(callback),
4525 )
4526 }
4527}
4528
4529impl SurfaceTexture {
4530 /// Schedule this texture to be presented on the owning surface.
4531 ///
4532 /// Needs to be called after any work on the texture is scheduled via [`Queue::submit`].
4533 pub fn present(mut self) {
4534 self.presented = true;
4535 DynContext::surface_present(
4536 &*self.texture.context,
4537 &self.texture.id,
4538 // This call to as_ref is essential because we want the DynContext implementation to see the inner
4539 // value of the Box (T::SurfaceOutputDetail), not the Box itself.
4540 self.detail.as_ref(),
4541 );
4542 }
4543}
4544
4545impl Drop for SurfaceTexture {
4546 fn drop(&mut self) {
4547 if !self.presented && !thread::panicking() {
4548 DynContext::surface_texture_discard(
4549 &*self.texture.context,
4550 &self.texture.id,
4551 // This call to as_ref is essential because we want the DynContext implementation to see the inner
4552 // value of the Box (T::SurfaceOutputDetail), not the Box itself.
4553 self.detail.as_ref(),
4554 );
4555 }
4556 }
4557}
4558
4559impl Surface {
4560 /// Returns the capabilities of the surface when used with the given adapter.
4561 ///
4562 /// Returns specified values (see [`SurfaceCapabilities`]) if surface is incompatible with the adapter.
4563 pub fn get_capabilities(&self, adapter: &Adapter) -> SurfaceCapabilities {
4564 DynContext::surface_get_capabilities(
4565 &*self.context,
4566 &self.id,
4567 self.data.as_ref(),
4568 &adapter.id,
4569 adapter.data.as_ref(),
4570 )
4571 }
4572
4573 /// Return a default `SurfaceConfiguration` from width and height to use for the [`Surface`] with this adapter.
4574 ///
4575 /// Returns None if the surface isn't supported by this adapter
4576 pub fn get_default_config(
4577 &self,
4578 adapter: &Adapter,
4579 width: u32,
4580 height: u32,
4581 ) -> Option<SurfaceConfiguration> {
4582 let caps = self.get_capabilities(adapter);
4583 Some(SurfaceConfiguration {
4584 usage: wgt::TextureUsages::RENDER_ATTACHMENT,
4585 format: *caps.formats.get(0)?,
4586 width,
4587 height,
4588 present_mode: *caps.present_modes.get(0)?,
4589 alpha_mode: wgt::CompositeAlphaMode::Auto,
4590 view_formats: vec![],
4591 })
4592 }
4593
4594 /// Initializes [`Surface`] for presentation.
4595 ///
4596 /// # Panics
4597 ///
4598 /// - A old [`SurfaceTexture`] is still alive referencing an old surface.
4599 /// - Texture format requested is unsupported on the surface.
4600 pub fn configure(&self, device: &Device, config: &SurfaceConfiguration) {
4601 DynContext::surface_configure(
4602 &*self.context,
4603 &self.id,
4604 self.data.as_ref(),
4605 &device.id,
4606 device.data.as_ref(),
4607 config,
4608 );
4609
4610 let mut conf = self.config.lock();
4611 *conf = Some(config.clone());
4612 }
4613
4614 /// Returns the next texture to be presented by the swapchain for drawing.
4615 ///
4616 /// In order to present the [`SurfaceTexture`] returned by this method,
4617 /// first a [`Queue::submit`] needs to be done with some work rendering to this texture.
4618 /// Then [`SurfaceTexture::present`] needs to be called.
4619 ///
4620 /// If a SurfaceTexture referencing this surface is alive when the swapchain is recreated,
4621 /// recreating the swapchain will panic.
4622 pub fn get_current_texture(&self) -> Result<SurfaceTexture, SurfaceError> {
4623 let (texture_id, texture_data, status, detail) =
4624 DynContext::surface_get_current_texture(&*self.context, &self.id, self.data.as_ref());
4625
4626 let suboptimal = match status {
4627 SurfaceStatus::Good => false,
4628 SurfaceStatus::Suboptimal => true,
4629 SurfaceStatus::Timeout => return Err(SurfaceError::Timeout),
4630 SurfaceStatus::Outdated => return Err(SurfaceError::Outdated),
4631 SurfaceStatus::Lost => return Err(SurfaceError::Lost),
4632 };
4633
4634 let guard = self.config.lock();
4635 let config = guard
4636 .as_ref()
4637 .expect("This surface has not been configured yet.");
4638
4639 let descriptor = TextureDescriptor {
4640 label: None,
4641 size: Extent3d {
4642 width: config.width,
4643 height: config.height,
4644 depth_or_array_layers: 1,
4645 },
4646 format: config.format,
4647 usage: config.usage,
4648 mip_level_count: 1,
4649 sample_count: 1,
4650 dimension: TextureDimension::D2,
4651 view_formats: &[],
4652 };
4653
4654 texture_id
4655 .zip(texture_data)
4656 .map(|(id, data)| SurfaceTexture {
4657 texture: Texture {
4658 context: Arc::clone(&self.context),
4659 id,
4660 data,
4661 owned: false,
4662 descriptor,
4663 },
4664 suboptimal,
4665 presented: false,
4666 detail,
4667 })
4668 .ok_or(SurfaceError::Lost)
4669 }
4670
4671 /// Returns the inner hal Surface using a callback. The hal surface will be `None` if the
4672 /// backend type argument does not match with this wgpu Surface
4673 ///
4674 /// # Safety
4675 ///
4676 /// - The raw handle obtained from the hal Surface must not be manually destroyed
4677 #[cfg(any(
4678 not(target_arch = "wasm32"),
4679 target_os = "emscripten",
4680 feature = "webgl"
4681 ))]
4682 pub unsafe fn as_hal_mut<
4683 A: wgc::hal_api::HalApi,
4684 F: FnOnce(Option<&mut A::Surface>) -> R,
4685 R,
4686 >(
4687 &mut self,
4688 hal_surface_callback: F,
4689 ) -> R {
4690 unsafe {
4691 self.context
4692 .as_any()
4693 .downcast_ref::<crate::backend::Context>()
4694 .unwrap()
4695 .surface_as_hal_mut::<A, F, R>(
4696 self.data.downcast_ref().unwrap(),
4697 hal_surface_callback,
4698 )
4699 }
4700 }
4701}
4702
4703/// Opaque globally-unique identifier
4704#[cfg(feature = "expose-ids")]
4705#[cfg_attr(docsrs, doc(cfg(feature = "expose-ids")))]
4706#[repr(transparent)]
4707pub struct Id<T>(::core::num::NonZeroU64, std::marker::PhantomData<*mut T>);
4708
4709// SAFETY: `Id` is a bare `NonZeroU64`, the type parameter is a marker purely to avoid confusing Ids
4710// returned for different types , so `Id` can safely implement Send and Sync.
4711#[cfg(feature = "expose-ids")]
4712unsafe impl<T> Send for Id<T> {}
4713
4714// SAFETY: See the implementation for `Send`.
4715#[cfg(feature = "expose-ids")]
4716unsafe impl<T> Sync for Id<T> {}
4717
4718#[cfg(feature = "expose-ids")]
4719impl<T> Clone for Id<T> {
4720 fn clone(&self) -> Self {
4721 *self
4722 }
4723}
4724
4725#[cfg(feature = "expose-ids")]
4726impl<T> Copy for Id<T> {}
4727
4728#[cfg(feature = "expose-ids")]
4729impl<T> Debug for Id<T> {
4730 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
4731 f.debug_tuple("Id").field(&self.0).finish()
4732 }
4733}
4734
4735#[cfg(feature = "expose-ids")]
4736impl<T> PartialEq for Id<T> {
4737 fn eq(&self, other: &Id<T>) -> bool {
4738 self.0 == other.0
4739 }
4740}
4741
4742#[cfg(feature = "expose-ids")]
4743impl<T> Eq for Id<T> {}
4744
4745#[cfg(feature = "expose-ids")]
4746impl<T> std::hash::Hash for Id<T> {
4747 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
4748 self.0.hash(state)
4749 }
4750}
4751
4752#[cfg(feature = "expose-ids")]
4753impl Adapter {
4754 /// Returns a globally-unique identifier for this `Adapter`.
4755 ///
4756 /// Calling this method multiple times on the same object will always return the same value.
4757 /// The returned value is guaranteed to be unique among all `Adapter`s created from the same
4758 /// `Instance`.
4759 #[cfg_attr(docsrs, doc(cfg(feature = "expose-ids")))]
4760 pub fn global_id(&self) -> Id<Adapter> {
4761 Id(self.id.global_id(), std::marker::PhantomData)
4762 }
4763}
4764
4765#[cfg(feature = "expose-ids")]
4766impl Device {
4767 /// Returns a globally-unique identifier for this `Device`.
4768 ///
4769 /// Calling this method multiple times on the same object will always return the same value.
4770 /// The returned value is guaranteed to be unique among all `Device`s created from the same
4771 /// `Instance`.
4772 #[cfg_attr(docsrs, doc(cfg(feature = "expose-ids")))]
4773 pub fn global_id(&self) -> Id<Device> {
4774 Id(self.id.global_id(), std::marker::PhantomData)
4775 }
4776}
4777
4778#[cfg(feature = "expose-ids")]
4779impl Queue {
4780 /// Returns a globally-unique identifier for this `Queue`.
4781 ///
4782 /// Calling this method multiple times on the same object will always return the same value.
4783 /// The returned value is guaranteed to be unique among all `Queue`s created from the same
4784 /// `Instance`.
4785 #[cfg_attr(docsrs, doc(cfg(feature = "expose-ids")))]
4786 pub fn global_id(&self) -> Id<Queue> {
4787 Id(self.id.global_id(), std::marker::PhantomData)
4788 }
4789}
4790
4791#[cfg(feature = "expose-ids")]
4792impl ShaderModule {
4793 /// Returns a globally-unique identifier for this `ShaderModule`.
4794 ///
4795 /// Calling this method multiple times on the same object will always return the same value.
4796 /// The returned value is guaranteed to be unique among all `ShaderModule`s created from the same
4797 /// `Instance`.
4798 #[cfg_attr(docsrs, doc(cfg(feature = "expose-ids")))]
4799 pub fn global_id(&self) -> Id<ShaderModule> {
4800 Id(self.id.global_id(), std::marker::PhantomData)
4801 }
4802}
4803
4804#[cfg(feature = "expose-ids")]
4805impl BindGroupLayout {
4806 /// Returns a globally-unique identifier for this `BindGroupLayout`.
4807 ///
4808 /// Calling this method multiple times on the same object will always return the same value.
4809 /// The returned value is guaranteed to be unique among all `BindGroupLayout`s created from the same
4810 /// `Instance`.
4811 #[cfg_attr(docsrs, doc(cfg(feature = "expose-ids")))]
4812 pub fn global_id(&self) -> Id<BindGroupLayout> {
4813 Id(self.id.global_id(), std::marker::PhantomData)
4814 }
4815}
4816
4817#[cfg(feature = "expose-ids")]
4818impl BindGroup {
4819 /// Returns a globally-unique identifier for this `BindGroup`.
4820 ///
4821 /// Calling this method multiple times on the same object will always return the same value.
4822 /// The returned value is guaranteed to be unique among all `BindGroup`s created from the same
4823 /// `Instance`.
4824 #[cfg_attr(docsrs, doc(cfg(feature = "expose-ids")))]
4825 pub fn global_id(&self) -> Id<BindGroup> {
4826 Id(self.id.global_id(), std::marker::PhantomData)
4827 }
4828}
4829
4830#[cfg(feature = "expose-ids")]
4831impl TextureView {
4832 /// Returns a globally-unique identifier for this `TextureView`.
4833 ///
4834 /// Calling this method multiple times on the same object will always return the same value.
4835 /// The returned value is guaranteed to be unique among all `TextureView`s created from the same
4836 /// `Instance`.
4837 #[cfg_attr(docsrs, doc(cfg(feature = "expose-ids")))]
4838 pub fn global_id(&self) -> Id<TextureView> {
4839 Id(self.id.global_id(), std::marker::PhantomData)
4840 }
4841}
4842
4843#[cfg(feature = "expose-ids")]
4844impl Sampler {
4845 /// Returns a globally-unique identifier for this `Sampler`.
4846 ///
4847 /// Calling this method multiple times on the same object will always return the same value.
4848 /// The returned value is guaranteed to be unique among all `Sampler`s created from the same
4849 /// `Instance`.
4850 #[cfg_attr(docsrs, doc(cfg(feature = "expose-ids")))]
4851 pub fn global_id(&self) -> Id<Sampler> {
4852 Id(self.id.global_id(), std::marker::PhantomData)
4853 }
4854}
4855
4856#[cfg(feature = "expose-ids")]
4857impl Buffer {
4858 /// Returns a globally-unique identifier for this `Buffer`.
4859 ///
4860 /// Calling this method multiple times on the same object will always return the same value.
4861 /// The returned value is guaranteed to be unique among all `Buffer`s created from the same
4862 /// `Instance`.
4863 #[cfg_attr(docsrs, doc(cfg(feature = "expose-ids")))]
4864 pub fn global_id(&self) -> Id<Buffer> {
4865 Id(self.id.global_id(), std::marker::PhantomData)
4866 }
4867}
4868
4869#[cfg(feature = "expose-ids")]
4870impl Texture {
4871 /// Returns a globally-unique identifier for this `Texture`.
4872 ///
4873 /// Calling this method multiple times on the same object will always return the same value.
4874 /// The returned value is guaranteed to be unique among all `Texture`s created from the same
4875 /// `Instance`.
4876 #[cfg_attr(docsrs, doc(cfg(feature = "expose-ids")))]
4877 pub fn global_id(&self) -> Id<Texture> {
4878 Id(self.id.global_id(), std::marker::PhantomData)
4879 }
4880}
4881
4882#[cfg(feature = "expose-ids")]
4883impl QuerySet {
4884 /// Returns a globally-unique identifier for this `QuerySet`.
4885 ///
4886 /// Calling this method multiple times on the same object will always return the same value.
4887 /// The returned value is guaranteed to be unique among all `QuerySet`s created from the same
4888 /// `Instance`.
4889 #[cfg_attr(docsrs, doc(cfg(feature = "expose-ids")))]
4890 pub fn global_id(&self) -> Id<QuerySet> {
4891 Id(self.id.global_id(), std::marker::PhantomData)
4892 }
4893}
4894
4895#[cfg(feature = "expose-ids")]
4896impl PipelineLayout {
4897 /// Returns a globally-unique identifier for this `PipelineLayout`.
4898 ///
4899 /// Calling this method multiple times on the same object will always return the same value.
4900 /// The returned value is guaranteed to be unique among all `PipelineLayout`s created from the same
4901 /// `Instance`.
4902 #[cfg_attr(docsrs, doc(cfg(feature = "expose-ids")))]
4903 pub fn global_id(&self) -> Id<PipelineLayout> {
4904 Id(self.id.global_id(), std::marker::PhantomData)
4905 }
4906}
4907
4908#[cfg(feature = "expose-ids")]
4909impl RenderPipeline {
4910 /// Returns a globally-unique identifier for this `RenderPipeline`.
4911 ///
4912 /// Calling this method multiple times on the same object will always return the same value.
4913 /// The returned value is guaranteed to be unique among all `RenderPipeline`s created from the same
4914 /// `Instance`.
4915 #[cfg_attr(docsrs, doc(cfg(feature = "expose-ids")))]
4916 pub fn global_id(&self) -> Id<RenderPipeline> {
4917 Id(self.id.global_id(), std::marker::PhantomData)
4918 }
4919}
4920
4921#[cfg(feature = "expose-ids")]
4922impl ComputePipeline {
4923 /// Returns a globally-unique identifier for this `ComputePipeline`.
4924 ///
4925 /// Calling this method multiple times on the same object will always return the same value.
4926 /// The returned value is guaranteed to be unique among all `ComputePipeline`s created from the same
4927 /// `Instance`.
4928 #[cfg_attr(docsrs, doc(cfg(feature = "expose-ids")))]
4929 pub fn global_id(&self) -> Id<ComputePipeline> {
4930 Id(self.id.global_id(), std::marker::PhantomData)
4931 }
4932}
4933
4934#[cfg(feature = "expose-ids")]
4935impl RenderBundle {
4936 /// Returns a globally-unique identifier for this `RenderBundle`.
4937 ///
4938 /// Calling this method multiple times on the same object will always return the same value.
4939 /// The returned value is guaranteed to be unique among all `RenderBundle`s created from the same
4940 /// `Instance`.
4941 #[cfg_attr(docsrs, doc(cfg(feature = "expose-ids")))]
4942 pub fn global_id(&self) -> Id<RenderBundle> {
4943 Id(self.id.global_id(), std::marker::PhantomData)
4944 }
4945}
4946
4947#[cfg(feature = "expose-ids")]
4948impl Surface {
4949 /// Returns a globally-unique identifier for this `Surface`.
4950 ///
4951 /// Calling this method multiple times on the same object will always return the same value.
4952 /// The returned value is guaranteed to be unique among all `Surface`s created from the same
4953 /// `Instance`.
4954 #[cfg_attr(docsrs, doc(cfg(feature = "expose-ids")))]
4955 pub fn global_id(&self) -> Id<Surface> {
4956 Id(self.id.global_id(), std::marker::PhantomData)
4957 }
4958}
4959
4960/// Type for the callback of uncaptured error handler
4961pub trait UncapturedErrorHandler: Fn(Error) + Send + 'static {}
4962impl<T> UncapturedErrorHandler for T where T: Fn(Error) + Send + 'static {}
4963
4964/// Error type
4965#[derive(Debug)]
4966pub enum Error {
4967 /// Out of memory error
4968 OutOfMemory {
4969 /// Lower level source of the error.
4970 #[cfg(any(
4971 not(target_arch = "wasm32"),
4972 all(
4973 feature = "fragile-send-sync-non-atomic-wasm",
4974 not(target_feature = "atomics")
4975 )
4976 ))]
4977 source: Box<dyn error::Error + Send + 'static>,
4978 /// Lower level source of the error.
4979 #[cfg(not(any(
4980 not(target_arch = "wasm32"),
4981 all(
4982 feature = "fragile-send-sync-non-atomic-wasm",
4983 not(target_feature = "atomics")
4984 )
4985 )))]
4986 source: Box<dyn error::Error + 'static>,
4987 },
4988 /// Validation error, signifying a bug in code or data
4989 Validation {
4990 /// Lower level source of the error.
4991 #[cfg(any(
4992 not(target_arch = "wasm32"),
4993 all(
4994 feature = "fragile-send-sync-non-atomic-wasm",
4995 not(target_feature = "atomics")
4996 )
4997 ))]
4998 source: Box<dyn error::Error + Send + 'static>,
4999 /// Lower level source of the error.
5000 #[cfg(not(any(
5001 not(target_arch = "wasm32"),
5002 all(
5003 feature = "fragile-send-sync-non-atomic-wasm",
5004 not(target_feature = "atomics")
5005 )
5006 )))]
5007 source: Box<dyn error::Error + 'static>,
5008 /// Description of the validation error.
5009 description: String,
5010 },
5011}
5012#[cfg(any(
5013 not(target_arch = "wasm32"),
5014 all(
5015 feature = "fragile-send-sync-non-atomic-wasm",
5016 not(target_feature = "atomics")
5017 )
5018))]
5019static_assertions::assert_impl_all!(Error: Send);
5020
5021impl error::Error for Error {
5022 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
5023 match self {
5024 Error::OutOfMemory { source } => Some(source.as_ref()),
5025 Error::Validation { source, .. } => Some(source.as_ref()),
5026 }
5027 }
5028}
5029
5030impl Display for Error {
5031 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5032 match self {
5033 Error::OutOfMemory { .. } => f.write_str("Out of Memory"),
5034 Error::Validation { description, .. } => f.write_str(description),
5035 }
5036 }
5037}
5038
5039use send_sync::*;
5040
5041mod send_sync {
5042 use std::any::Any;
5043 use std::fmt;
5044
5045 use wgt::{WasmNotSend, WasmNotSync};
5046
5047 pub trait AnyWasmNotSendSync: Any + WasmNotSend + WasmNotSync {
5048 fn upcast_any_ref(&self) -> &dyn Any;
5049 }
5050 impl<T: Any + WasmNotSend + WasmNotSync> AnyWasmNotSendSync for T {
5051 #[inline]
5052 fn upcast_any_ref(&self) -> &dyn Any {
5053 self
5054 }
5055 }
5056
5057 impl dyn AnyWasmNotSendSync + 'static {
5058 #[inline]
5059 pub fn downcast_ref<T: 'static>(&self) -> Option<&T> {
5060 self.upcast_any_ref().downcast_ref::<T>()
5061 }
5062 }
5063
5064 impl fmt::Debug for dyn AnyWasmNotSendSync {
5065 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
5066 f.debug_struct("Any").finish_non_exhaustive()
5067 }
5068 }
5069}