wgpu/backend/
wgpu_core.rs

1use alloc::{
2    borrow::Cow::{self, Borrowed},
3    boxed::Box,
4    format,
5    string::{String, ToString as _},
6    sync::Arc,
7    vec,
8    vec::Vec,
9};
10use core::{
11    error::Error,
12    fmt,
13    future::ready,
14    ops::{Deref, Range},
15    pin::Pin,
16    ptr::NonNull,
17    slice,
18};
19use hashbrown::HashMap;
20
21use arrayvec::ArrayVec;
22use smallvec::SmallVec;
23use wgc::{
24    error::ContextErrorSource, pipeline::CreateShaderModuleError,
25    resource::BlasPrepareCompactResult,
26};
27use wgt::{
28    error::{ErrorType, WebGpuError},
29    WasmNotSendSync,
30};
31
32use crate::{
33    api,
34    dispatch::{self, BlasCompactCallback, BufferMappedRangeInterface},
35    BindingResource, Blas, BufferBinding, BufferDescriptor, CompilationInfo, CompilationMessage,
36    CompilationMessageType, ErrorSource, Features, Label, LoadOp, MapMode, Operations,
37    ShaderSource, SurfaceTargetUnsafe, TextureDescriptor, Tlas, WriteOnly,
38};
39use crate::{dispatch::DispatchAdapter, util::Mutex};
40
41mod thread_id;
42
43#[derive(Clone)]
44pub struct ContextWgpuCore(Arc<wgc::global::Global>);
45
46impl Drop for ContextWgpuCore {
47    fn drop(&mut self) {
48        //nothing
49    }
50}
51
52impl fmt::Debug for ContextWgpuCore {
53    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54        f.debug_struct("ContextWgpuCore")
55            .field("type", &"Native")
56            .finish()
57    }
58}
59
60impl ContextWgpuCore {
61    pub unsafe fn from_hal_instance<A: hal::Api>(hal_instance: A::Instance) -> Self {
62        Self(unsafe {
63            Arc::new(wgc::global::Global::from_hal_instance::<A>(
64                "wgpu",
65                hal_instance,
66            ))
67        })
68    }
69
70    /// # Safety
71    ///
72    /// - The raw instance handle returned must not be manually destroyed.
73    pub unsafe fn instance_as_hal<A: hal::Api>(&self) -> Option<&A::Instance> {
74        unsafe { self.0.instance_as_hal::<A>() }
75    }
76
77    pub unsafe fn from_core_instance(core_instance: wgc::instance::Instance) -> Self {
78        Self(unsafe { Arc::new(wgc::global::Global::from_instance(core_instance)) })
79    }
80
81    #[cfg(wgpu_core)]
82    pub fn enumerate_adapters(&self, backends: wgt::Backends) -> Vec<wgc::id::AdapterId> {
83        self.0
84            .enumerate_adapters(backends, false /* no limit bucketing */)
85    }
86
87    pub unsafe fn create_adapter_from_hal<A: hal::Api>(
88        &self,
89        hal_adapter: hal::ExposedAdapter<A>,
90    ) -> wgc::id::AdapterId {
91        unsafe { self.0.create_adapter_from_hal(hal_adapter.into(), None) }
92    }
93
94    pub unsafe fn adapter_as_hal<A: hal::Api>(
95        &self,
96        adapter: &CoreAdapter,
97    ) -> Option<impl Deref<Target = A::Adapter> + WasmNotSendSync> {
98        unsafe { self.0.adapter_as_hal::<A>(adapter.id) }
99    }
100
101    pub unsafe fn buffer_as_hal<A: hal::Api>(
102        &self,
103        buffer: &CoreBuffer,
104    ) -> Option<impl Deref<Target = A::Buffer>> {
105        unsafe { self.0.buffer_as_hal::<A>(buffer.id) }
106    }
107
108    pub unsafe fn create_device_from_hal<A: hal::Api>(
109        &self,
110        adapter: &CoreAdapter,
111        hal_device: hal::OpenDevice<A>,
112        desc: &crate::DeviceDescriptor<'_>,
113    ) -> Result<(CoreDevice, CoreQueue), crate::RequestDeviceError> {
114        let (device_id, queue_id) = unsafe {
115            self.0.create_device_from_hal(
116                adapter.id,
117                hal_device.into(),
118                &desc.map_label(|l| l.map(Borrowed)),
119                None,
120                None,
121            )
122        }?;
123        let error_sink = Arc::new(Mutex::new(ErrorSinkRaw::new()));
124        let device = CoreDevice {
125            context: self.clone(),
126            id: device_id,
127            error_sink: error_sink.clone(),
128            features: desc.required_features,
129        };
130        let queue = CoreQueue {
131            context: self.clone(),
132            id: queue_id,
133            error_sink,
134        };
135        Ok((device, queue))
136    }
137
138    pub unsafe fn create_texture_from_hal<A: hal::Api>(
139        &self,
140        hal_texture: A::Texture,
141        device: &CoreDevice,
142        desc: &TextureDescriptor<'_>,
143        initial_state: wgt::TextureUses,
144    ) -> CoreTexture {
145        let descriptor = desc.map_label_and_view_formats(|l| l.map(Borrowed), |v| v.to_vec());
146        let (id, error) = unsafe {
147            self.0.create_texture_from_hal(
148                Box::new(hal_texture),
149                device.id,
150                &descriptor,
151                initial_state,
152                None,
153            )
154        };
155        if let Some(cause) = error {
156            self.handle_error(
157                &device.error_sink,
158                cause,
159                desc.label,
160                "Device::create_texture_from_hal",
161            );
162        }
163        CoreTexture {
164            context: self.clone(),
165            id,
166            error_sink: Arc::clone(&device.error_sink),
167        }
168    }
169
170    /// # Safety
171    ///
172    /// - `hal_buffer` must be created from `device`.
173    /// - `hal_buffer` must be created respecting `desc`
174    /// - `hal_buffer` must be initialized
175    /// - `hal_buffer` must not have zero size.
176    pub unsafe fn create_buffer_from_hal<A: hal::Api>(
177        &self,
178        hal_buffer: A::Buffer,
179        device: &CoreDevice,
180        desc: &BufferDescriptor<'_>,
181    ) -> CoreBuffer {
182        let (id, error) = unsafe {
183            self.0.create_buffer_from_hal::<A>(
184                hal_buffer,
185                device.id,
186                &desc.map_label(|l| l.map(Borrowed)),
187                None,
188            )
189        };
190        if let Some(cause) = error {
191            self.handle_error(
192                &device.error_sink,
193                cause,
194                desc.label,
195                "Device::create_buffer_from_hal",
196            );
197        }
198        CoreBuffer {
199            context: self.clone(),
200            id,
201            error_sink: Arc::clone(&device.error_sink),
202        }
203    }
204
205    pub unsafe fn device_as_hal<A: hal::Api>(
206        &self,
207        device: &CoreDevice,
208    ) -> Option<impl Deref<Target = A::Device>> {
209        unsafe { self.0.device_as_hal::<A>(device.id) }
210    }
211
212    pub unsafe fn surface_as_hal<A: hal::Api>(
213        &self,
214        surface: &CoreSurface,
215    ) -> Option<impl Deref<Target = A::Surface>> {
216        unsafe { self.0.surface_as_hal::<A>(surface.id) }
217    }
218
219    pub unsafe fn texture_as_hal<A: hal::Api>(
220        &self,
221        texture: &CoreTexture,
222    ) -> Option<impl Deref<Target = A::Texture>> {
223        unsafe { self.0.texture_as_hal::<A>(texture.id) }
224    }
225
226    pub unsafe fn texture_view_as_hal<A: hal::Api>(
227        &self,
228        texture_view: &CoreTextureView,
229    ) -> Option<impl Deref<Target = A::TextureView>> {
230        unsafe { self.0.texture_view_as_hal::<A>(texture_view.id) }
231    }
232
233    /// This method will start the wgpu_core level command recording.
234    pub unsafe fn command_encoder_as_hal_mut<
235        A: hal::Api,
236        F: FnOnce(Option<&mut A::CommandEncoder>) -> R,
237        R,
238    >(
239        &self,
240        command_encoder: &CoreCommandEncoder,
241        hal_command_encoder_callback: F,
242    ) -> R {
243        unsafe {
244            self.0.command_encoder_as_hal_mut::<A, F, R>(
245                command_encoder.id,
246                hal_command_encoder_callback,
247            )
248        }
249    }
250
251    pub unsafe fn blas_as_hal<A: hal::Api>(
252        &self,
253        blas: &CoreBlas,
254    ) -> Option<impl Deref<Target = A::AccelerationStructure>> {
255        unsafe { self.0.blas_as_hal::<A>(blas.id) }
256    }
257
258    pub unsafe fn tlas_as_hal<A: hal::Api>(
259        &self,
260        tlas: &CoreTlas,
261    ) -> Option<impl Deref<Target = A::AccelerationStructure>> {
262        unsafe { self.0.tlas_as_hal::<A>(tlas.id) }
263    }
264
265    pub fn generate_report(&self) -> wgc::global::GlobalReport {
266        self.0.generate_report()
267    }
268
269    #[cold]
270    #[track_caller]
271    #[inline(never)]
272    fn handle_error_inner(
273        &self,
274        sink_mutex: &Mutex<ErrorSinkRaw>,
275        error_type: ErrorType,
276        source: ContextErrorSource,
277        label: Label<'_>,
278        fn_ident: &'static str,
279    ) {
280        let source: ErrorSource = Box::new(wgc::error::ContextError {
281            fn_ident,
282            source,
283            label: label.unwrap_or_default().to_string(),
284        });
285        let final_error_handling = {
286            let mut sink = sink_mutex.lock();
287            let description = || self.format_error(&*source);
288            let error = match error_type {
289                ErrorType::Internal => {
290                    let description = description();
291                    crate::Error::Internal {
292                        source,
293                        description,
294                    }
295                }
296                ErrorType::OutOfMemory => crate::Error::OutOfMemory { source },
297                ErrorType::Validation => {
298                    let description = description();
299                    crate::Error::Validation {
300                        source,
301                        description,
302                    }
303                }
304                ErrorType::DeviceLost => return, // will be surfaced via callback
305            };
306            sink.handle_error_or_return_handler(error)
307        };
308
309        if let Some(f) = final_error_handling {
310            // If the user has provided their own `uncaptured_handler` callback, invoke it now,
311            // having released our lock on `sink_mutex`. See the comments on
312            // `handle_error_or_return_handler` for details.
313            f();
314        }
315    }
316
317    #[inline]
318    #[track_caller]
319    fn handle_error(
320        &self,
321        sink_mutex: &Mutex<ErrorSinkRaw>,
322        source: impl WebGpuError + WasmNotSendSync + 'static,
323        label: Label<'_>,
324        fn_ident: &'static str,
325    ) {
326        let error_type = source.webgpu_error_type();
327        self.handle_error_inner(sink_mutex, error_type, Box::new(source), label, fn_ident)
328    }
329
330    #[inline]
331    #[track_caller]
332    fn handle_error_nolabel(
333        &self,
334        sink_mutex: &Mutex<ErrorSinkRaw>,
335        source: impl WebGpuError + WasmNotSendSync + 'static,
336        fn_ident: &'static str,
337    ) {
338        let error_type = source.webgpu_error_type();
339        self.handle_error_inner(sink_mutex, error_type, Box::new(source), None, fn_ident)
340    }
341
342    #[track_caller]
343    #[cold]
344    fn handle_error_fatal(
345        &self,
346        cause: impl Error + WasmNotSendSync + 'static,
347        operation: &'static str,
348    ) -> ! {
349        panic!("Error in {operation}: {f}", f = self.format_error(&cause));
350    }
351
352    #[inline(never)]
353    fn format_error(&self, err: &(dyn Error + 'static)) -> String {
354        let mut output = String::new();
355        let mut level = 1;
356
357        fn print_tree(output: &mut String, level: &mut usize, e: &(dyn Error + 'static)) {
358            let mut print = |e: &(dyn Error + 'static)| {
359                use core::fmt::Write;
360                writeln!(output, "{}{}", " ".repeat(*level * 2), e).unwrap();
361
362                if let Some(e) = e.source() {
363                    *level += 1;
364                    print_tree(output, level, e);
365                    *level -= 1;
366                }
367            };
368            if let Some(multi) = e.downcast_ref::<wgc::error::MultiError>() {
369                for e in multi.errors() {
370                    print(e);
371                }
372            } else {
373                print(e);
374            }
375        }
376
377        print_tree(&mut output, &mut level, err);
378
379        format!("Validation Error\n\nCaused by:\n{output}")
380    }
381
382    pub unsafe fn queue_as_hal<A: hal::Api>(
383        &self,
384        queue: &CoreQueue,
385    ) -> Option<impl Deref<Target = A::Queue> + WasmNotSendSync> {
386        unsafe { self.0.queue_as_hal::<A>(queue.id) }
387    }
388}
389
390fn map_buffer_copy_view(
391    view: crate::TexelCopyBufferInfo<'_>,
392) -> wgt::TexelCopyBufferInfo<wgc::id::BufferId> {
393    wgt::TexelCopyBufferInfo {
394        buffer: view.buffer.inner.as_core().id,
395        layout: view.layout,
396    }
397}
398
399fn map_texture_copy_view(
400    view: crate::TexelCopyTextureInfo<'_>,
401) -> wgt::TexelCopyTextureInfo<wgc::id::TextureId> {
402    wgt::TexelCopyTextureInfo {
403        texture: view.texture.inner.as_core().id,
404        mip_level: view.mip_level,
405        origin: view.origin,
406        aspect: view.aspect,
407    }
408}
409
410#[cfg_attr(not(webgl), expect(unused))]
411fn map_texture_tagged_copy_view(
412    view: crate::CopyExternalImageDestInfo<&api::Texture>,
413) -> wgt::CopyExternalImageDestInfo<wgc::id::TextureId> {
414    wgt::CopyExternalImageDestInfo {
415        texture: view.texture.inner.as_core().id,
416        mip_level: view.mip_level,
417        origin: view.origin,
418        aspect: view.aspect,
419        color_space: view.color_space,
420        premultiplied_alpha: view.premultiplied_alpha,
421    }
422}
423
424fn map_load_op<V: Copy>(load: &LoadOp<V>) -> LoadOp<Option<V>> {
425    match *load {
426        LoadOp::Clear(clear_value) => LoadOp::Clear(Some(clear_value)),
427        LoadOp::DontCare(token) => LoadOp::DontCare(token),
428        LoadOp::Load => LoadOp::Load,
429    }
430}
431
432fn map_pass_channel<V: Copy>(ops: Option<&Operations<V>>) -> wgc::command::PassChannel<Option<V>> {
433    match ops {
434        Some(&Operations { load, store }) => wgc::command::PassChannel {
435            load_op: Some(map_load_op(&load)),
436            store_op: Some(store),
437            read_only: false,
438        },
439        None => wgc::command::PassChannel {
440            load_op: None,
441            store_op: None,
442            read_only: true,
443        },
444    }
445}
446
447#[derive(Debug)]
448pub struct CoreSurface {
449    pub(crate) context: ContextWgpuCore,
450    id: wgc::id::SurfaceId,
451    /// Configured device is needed to know which backend
452    /// code to execute when acquiring a new frame.
453    configured_device: Mutex<Option<wgc::id::DeviceId>>,
454    /// The error sink with which to report errors.
455    /// `None` if the surface has not been configured.
456    error_sink: Mutex<Option<ErrorSink>>,
457}
458
459#[derive(Debug)]
460pub struct CoreAdapter {
461    pub(crate) context: ContextWgpuCore,
462    pub(crate) id: wgc::id::AdapterId,
463}
464
465#[derive(Debug)]
466pub struct CoreDevice {
467    pub(crate) context: ContextWgpuCore,
468    id: wgc::id::DeviceId,
469    error_sink: ErrorSink,
470    features: Features,
471}
472
473#[derive(Debug)]
474pub struct CoreBuffer {
475    pub(crate) context: ContextWgpuCore,
476    id: wgc::id::BufferId,
477    error_sink: ErrorSink,
478}
479
480#[derive(Debug)]
481pub struct CoreShaderModule {
482    pub(crate) context: ContextWgpuCore,
483    id: wgc::id::ShaderModuleId,
484    compilation_info: CompilationInfo,
485}
486
487#[derive(Debug)]
488pub struct CoreBindGroupLayout {
489    pub(crate) context: ContextWgpuCore,
490    id: wgc::id::BindGroupLayoutId,
491}
492
493#[derive(Debug)]
494pub struct CoreBindGroup {
495    pub(crate) context: ContextWgpuCore,
496    id: wgc::id::BindGroupId,
497}
498
499#[derive(Debug)]
500pub struct CoreTexture {
501    pub(crate) context: ContextWgpuCore,
502    id: wgc::id::TextureId,
503    error_sink: ErrorSink,
504}
505
506#[derive(Debug)]
507pub struct CoreTextureView {
508    pub(crate) context: ContextWgpuCore,
509    id: wgc::id::TextureViewId,
510}
511
512#[derive(Debug)]
513pub struct CoreExternalTexture {
514    pub(crate) context: ContextWgpuCore,
515    id: wgc::id::ExternalTextureId,
516}
517
518#[derive(Debug)]
519pub struct CoreSampler {
520    pub(crate) context: ContextWgpuCore,
521    id: wgc::id::SamplerId,
522}
523
524#[derive(Debug)]
525pub struct CoreQuerySet {
526    pub(crate) context: ContextWgpuCore,
527    id: wgc::id::QuerySetId,
528}
529
530#[derive(Debug)]
531pub struct CorePipelineLayout {
532    pub(crate) context: ContextWgpuCore,
533    id: wgc::id::PipelineLayoutId,
534}
535
536#[derive(Debug)]
537pub struct CorePipelineCache {
538    pub(crate) context: ContextWgpuCore,
539    id: wgc::id::PipelineCacheId,
540}
541
542#[derive(Debug)]
543pub struct CoreCommandBuffer {
544    pub(crate) context: ContextWgpuCore,
545    id: wgc::id::CommandBufferId,
546}
547
548#[derive(Debug)]
549pub struct CoreRenderBundleEncoder {
550    pub(crate) context: ContextWgpuCore,
551    error_sink: ErrorSink,
552    encoder: Box<wgc::command::RenderBundleEncoder>,
553    id: crate::cmp::Identifier,
554}
555
556#[derive(Debug)]
557pub struct CoreRenderBundle {
558    context: ContextWgpuCore,
559    id: wgc::id::RenderBundleId,
560}
561
562#[derive(Debug)]
563pub struct CoreQueue {
564    pub(crate) context: ContextWgpuCore,
565    id: wgc::id::QueueId,
566    error_sink: ErrorSink,
567}
568
569#[derive(Debug)]
570pub struct CoreComputePipeline {
571    pub(crate) context: ContextWgpuCore,
572    id: wgc::id::ComputePipelineId,
573    error_sink: ErrorSink,
574}
575
576#[derive(Debug)]
577pub struct CoreRenderPipeline {
578    pub(crate) context: ContextWgpuCore,
579    id: wgc::id::RenderPipelineId,
580    error_sink: ErrorSink,
581}
582
583#[derive(Debug)]
584pub struct CoreComputePass {
585    pub(crate) context: ContextWgpuCore,
586    pass: wgc::command::ComputePass,
587    error_sink: ErrorSink,
588    id: crate::cmp::Identifier,
589}
590
591#[derive(Debug)]
592pub struct CoreRenderPass {
593    pub(crate) context: ContextWgpuCore,
594    pass: wgc::command::RenderPass,
595    error_sink: ErrorSink,
596    id: crate::cmp::Identifier,
597}
598
599#[derive(Debug)]
600pub struct CoreCommandEncoder {
601    pub(crate) context: ContextWgpuCore,
602    id: wgc::id::CommandEncoderId,
603    error_sink: ErrorSink,
604}
605
606#[derive(Debug)]
607pub struct CoreBlas {
608    pub(crate) context: ContextWgpuCore,
609    id: wgc::id::BlasId,
610    error_sink: ErrorSink,
611}
612
613#[derive(Debug)]
614pub struct CoreTlas {
615    pub(crate) context: ContextWgpuCore,
616    id: wgc::id::TlasId,
617    // error_sink: ErrorSink,
618}
619
620#[derive(Debug)]
621pub struct CoreSurfaceOutputDetail {
622    context: ContextWgpuCore,
623    surface_id: wgc::id::SurfaceId,
624    error_sink: ErrorSink,
625}
626
627type ErrorSink = Arc<Mutex<ErrorSinkRaw>>;
628
629struct ErrorScope {
630    error: Option<crate::Error>,
631    filter: crate::ErrorFilter,
632}
633
634struct ErrorSinkRaw {
635    scopes: HashMap<thread_id::ThreadId, Vec<ErrorScope>>,
636    uncaptured_handler: Option<Arc<dyn crate::UncapturedErrorHandler>>,
637}
638
639impl ErrorSinkRaw {
640    fn new() -> ErrorSinkRaw {
641        ErrorSinkRaw {
642            scopes: HashMap::new(),
643            uncaptured_handler: None,
644        }
645    }
646
647    /// Deliver the error to
648    ///
649    /// * the innermost error scope, if any, or
650    /// * the uncaptured error handler, if there is one, or
651    /// * [`default_error_handler()`].
652    ///
653    /// If a closure is returned, the caller should call it immediately after dropping the
654    /// [`ErrorSink`] mutex guard. This makes sure that the user callback is not called with
655    /// a wgpu mutex held.
656    #[track_caller]
657    #[must_use]
658    fn handle_error_or_return_handler(&mut self, err: crate::Error) -> Option<impl FnOnce()> {
659        let filter = match err {
660            crate::Error::OutOfMemory { .. } => crate::ErrorFilter::OutOfMemory,
661            crate::Error::Validation { .. } => crate::ErrorFilter::Validation,
662            crate::Error::Internal { .. } => crate::ErrorFilter::Internal,
663        };
664        let thread_id = thread_id::ThreadId::current();
665        let scopes = self.scopes.entry(thread_id).or_default();
666        match scopes.iter_mut().rev().find(|scope| scope.filter == filter) {
667            Some(scope) => {
668                if scope.error.is_none() {
669                    scope.error = Some(err);
670                }
671                None
672            }
673            None => {
674                if let Some(custom_handler) = &self.uncaptured_handler {
675                    let custom_handler = Arc::clone(custom_handler);
676                    Some(move || (custom_handler)(err))
677                } else {
678                    // direct call preserves #[track_caller] where dyn can't
679                    default_error_handler(err)
680                }
681            }
682        }
683    }
684}
685
686impl fmt::Debug for ErrorSinkRaw {
687    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
688        write!(f, "ErrorSink")
689    }
690}
691
692#[track_caller]
693fn default_error_handler(err: crate::Error) -> ! {
694    log::error!("Handling wgpu errors as fatal by default");
695    panic!("wgpu error: {err}\n");
696}
697
698impl From<CreateShaderModuleError> for CompilationInfo {
699    fn from(value: CreateShaderModuleError) -> Self {
700        match value {
701            #[cfg(feature = "wgsl")]
702            CreateShaderModuleError::Parsing(v) => v.into(),
703            #[cfg(feature = "glsl")]
704            CreateShaderModuleError::ParsingGlsl(v) => v.into(),
705            #[cfg(feature = "spirv")]
706            CreateShaderModuleError::ParsingSpirV(v) => v.into(),
707            CreateShaderModuleError::Validation(v) => v.into(),
708            // Device errors are reported through the error sink, and are not compilation errors.
709            // Same goes for native shader module generation errors.
710            CreateShaderModuleError::Device(_) | CreateShaderModuleError::Generation => {
711                CompilationInfo {
712                    messages: Vec::new(),
713                }
714            }
715            // Everything else is an error message without location information.
716            _ => CompilationInfo {
717                messages: vec![CompilationMessage {
718                    message: value.to_string(),
719                    message_type: CompilationMessageType::Error,
720                    location: None,
721                }],
722            },
723        }
724    }
725}
726
727#[derive(Debug)]
728pub struct CoreQueueWriteBuffer {
729    buffer_id: wgc::id::StagingBufferId,
730    mapping: CoreBufferMappedRange,
731}
732
733#[derive(Debug)]
734pub struct CoreBufferMappedRange {
735    ptr: NonNull<u8>,
736    size: usize,
737}
738
739#[cfg(send_sync)]
740unsafe impl Send for CoreBufferMappedRange {}
741#[cfg(send_sync)]
742unsafe impl Sync for CoreBufferMappedRange {}
743
744impl Drop for CoreBufferMappedRange {
745    fn drop(&mut self) {
746        // Intentionally left blank so that `BufferMappedRange` still
747        // implements `Drop`, to match the web backend
748    }
749}
750
751crate::cmp::impl_eq_ord_hash_arc_address!(ContextWgpuCore => .0);
752crate::cmp::impl_eq_ord_hash_proxy!(CoreAdapter => .id);
753crate::cmp::impl_eq_ord_hash_proxy!(CoreDevice => .id);
754crate::cmp::impl_eq_ord_hash_proxy!(CoreQueue => .id);
755crate::cmp::impl_eq_ord_hash_proxy!(CoreShaderModule => .id);
756crate::cmp::impl_eq_ord_hash_proxy!(CoreBindGroupLayout => .id);
757crate::cmp::impl_eq_ord_hash_proxy!(CoreBindGroup => .id);
758crate::cmp::impl_eq_ord_hash_proxy!(CoreTextureView => .id);
759crate::cmp::impl_eq_ord_hash_proxy!(CoreSampler => .id);
760crate::cmp::impl_eq_ord_hash_proxy!(CoreBuffer => .id);
761crate::cmp::impl_eq_ord_hash_proxy!(CoreTexture => .id);
762crate::cmp::impl_eq_ord_hash_proxy!(CoreExternalTexture => .id);
763crate::cmp::impl_eq_ord_hash_proxy!(CoreBlas => .id);
764crate::cmp::impl_eq_ord_hash_proxy!(CoreTlas => .id);
765crate::cmp::impl_eq_ord_hash_proxy!(CoreQuerySet => .id);
766crate::cmp::impl_eq_ord_hash_proxy!(CorePipelineLayout => .id);
767crate::cmp::impl_eq_ord_hash_proxy!(CoreRenderPipeline => .id);
768crate::cmp::impl_eq_ord_hash_proxy!(CoreComputePipeline => .id);
769crate::cmp::impl_eq_ord_hash_proxy!(CorePipelineCache => .id);
770crate::cmp::impl_eq_ord_hash_proxy!(CoreCommandEncoder => .id);
771crate::cmp::impl_eq_ord_hash_proxy!(CoreComputePass => .id);
772crate::cmp::impl_eq_ord_hash_proxy!(CoreRenderPass => .id);
773crate::cmp::impl_eq_ord_hash_proxy!(CoreCommandBuffer => .id);
774crate::cmp::impl_eq_ord_hash_proxy!(CoreRenderBundleEncoder => .id);
775crate::cmp::impl_eq_ord_hash_proxy!(CoreRenderBundle => .id);
776crate::cmp::impl_eq_ord_hash_proxy!(CoreSurface => .id);
777crate::cmp::impl_eq_ord_hash_proxy!(CoreSurfaceOutputDetail => .surface_id);
778crate::cmp::impl_eq_ord_hash_proxy!(CoreQueueWriteBuffer => .mapping.ptr);
779crate::cmp::impl_eq_ord_hash_proxy!(CoreBufferMappedRange => .ptr);
780
781impl dispatch::InstanceInterface for ContextWgpuCore {
782    fn new(desc: wgt::InstanceDescriptor) -> Self
783    where
784        Self: Sized,
785    {
786        Self(Arc::new(wgc::global::Global::new("wgpu", desc, None)))
787    }
788
789    unsafe fn create_surface(
790        &self,
791        target: crate::api::SurfaceTargetUnsafe,
792    ) -> Result<dispatch::DispatchSurface, crate::CreateSurfaceError> {
793        let id = match target {
794            SurfaceTargetUnsafe::RawHandle {
795                raw_display_handle,
796                raw_window_handle,
797            } => unsafe {
798                self.0
799                    .instance_create_surface(raw_display_handle, raw_window_handle, None)
800            },
801
802            #[cfg(all(drm, not(target_os = "netbsd")))]
803            SurfaceTargetUnsafe::Drm {
804                fd,
805                plane,
806                connector_id,
807                width,
808                height,
809                refresh_rate,
810            } => unsafe {
811                self.0.instance_create_surface_from_drm(
812                    fd,
813                    plane,
814                    connector_id,
815                    width,
816                    height,
817                    refresh_rate,
818                    None,
819                )
820            },
821
822            #[cfg(metal)]
823            SurfaceTargetUnsafe::CoreAnimationLayer(layer) => unsafe {
824                self.0.instance_create_surface_metal(layer, None)
825            },
826
827            #[cfg(all(drm, target_os = "netbsd"))]
828            SurfaceTargetUnsafe::Drm { .. } => Err(
829                wgc::instance::CreateSurfaceError::BackendNotEnabled(wgt::Backend::Vulkan),
830            ),
831
832            #[cfg(dx12)]
833            SurfaceTargetUnsafe::CompositionVisual(visual) => unsafe {
834                self.0.instance_create_surface_from_visual(visual, None)
835            },
836
837            #[cfg(dx12)]
838            SurfaceTargetUnsafe::SurfaceHandle(surface_handle) => unsafe {
839                self.0
840                    .instance_create_surface_from_surface_handle(surface_handle, None)
841            },
842
843            #[cfg(dx12)]
844            SurfaceTargetUnsafe::SwapChainPanel(swap_chain_panel) => unsafe {
845                self.0
846                    .instance_create_surface_from_swap_chain_panel(swap_chain_panel, None)
847            },
848        }?;
849
850        Ok(CoreSurface {
851            context: self.clone(),
852            id,
853            configured_device: Mutex::default(),
854            error_sink: Mutex::default(),
855        }
856        .into())
857    }
858
859    fn request_adapter(
860        &self,
861        options: &crate::api::RequestAdapterOptions<'_, '_>,
862    ) -> Pin<Box<dyn dispatch::RequestAdapterFuture>> {
863        let id = self.0.request_adapter(
864            &wgc::instance::RequestAdapterOptions {
865                power_preference: options.power_preference,
866                force_fallback_adapter: options.force_fallback_adapter,
867                compatible_surface: options
868                    .compatible_surface
869                    .map(|surface| surface.inner.as_core().id),
870                apply_limit_buckets: false,
871            },
872            wgt::Backends::all(),
873            None,
874        );
875        let adapter = id.map(|id| {
876            let core = CoreAdapter {
877                context: self.clone(),
878                id,
879            };
880            let generic: dispatch::DispatchAdapter = core.into();
881            generic
882        });
883        Box::pin(ready(adapter))
884    }
885
886    fn poll_all_devices(&self, force_wait: bool) -> bool {
887        match self.0.poll_all_devices(force_wait) {
888            Ok(all_queue_empty) => all_queue_empty,
889            Err(err) => self.handle_error_fatal(err, "Instance::poll_all_devices"),
890        }
891    }
892
893    #[cfg(feature = "wgsl")]
894    fn wgsl_language_features(&self) -> crate::WgslLanguageFeatures {
895        use wgc::naga::front::wgsl::ImplementedLanguageExtension;
896        ImplementedLanguageExtension::all().iter().copied().fold(
897            crate::WgslLanguageFeatures::empty(),
898            |acc, wle| {
899                acc | match wle {
900                    ImplementedLanguageExtension::ReadOnlyAndReadWriteStorageTextures => {
901                        crate::WgslLanguageFeatures::ReadOnlyAndReadWriteStorageTextures
902                    }
903                    ImplementedLanguageExtension::Packed4x8IntegerDotProduct => {
904                        crate::WgslLanguageFeatures::Packed4x8IntegerDotProduct
905                    }
906                    ImplementedLanguageExtension::PointerCompositeAccess => {
907                        crate::WgslLanguageFeatures::PointerCompositeAccess
908                    }
909                }
910            },
911        )
912    }
913
914    fn enumerate_adapters(
915        &self,
916        backends: crate::Backends,
917    ) -> Pin<Box<dyn dispatch::EnumerateAdapterFuture>> {
918        let adapters: Vec<DispatchAdapter> = self
919            .enumerate_adapters(backends)
920            .into_iter()
921            .map(|adapter| {
922                let core = crate::backend::wgpu_core::CoreAdapter {
923                    context: self.clone(),
924                    id: adapter,
925                };
926                core.into()
927            })
928            .collect();
929        Box::pin(ready(adapters))
930    }
931}
932
933impl dispatch::AdapterInterface for CoreAdapter {
934    fn request_device(
935        &self,
936        desc: &crate::DeviceDescriptor<'_>,
937    ) -> Pin<Box<dyn dispatch::RequestDeviceFuture>> {
938        let res = self.context.0.adapter_request_device(
939            self.id,
940            &desc.map_label(|l| l.map(Borrowed)),
941            None,
942            None,
943        );
944        let (device_id, queue_id) = match res {
945            Ok(ids) => ids,
946            Err(err) => {
947                return Box::pin(ready(Err(err.into())));
948            }
949        };
950        let error_sink = Arc::new(Mutex::new(ErrorSinkRaw::new()));
951        let device = CoreDevice {
952            context: self.context.clone(),
953            id: device_id,
954            error_sink: error_sink.clone(),
955            features: desc.required_features,
956        };
957        let queue = CoreQueue {
958            context: self.context.clone(),
959            id: queue_id,
960            error_sink,
961        };
962        Box::pin(ready(Ok((device.into(), queue.into()))))
963    }
964
965    fn is_surface_supported(&self, surface: &dispatch::DispatchSurface) -> bool {
966        let surface = surface.as_core();
967
968        self.context
969            .0
970            .adapter_is_surface_supported(self.id, surface.id)
971    }
972
973    fn features(&self) -> crate::Features {
974        self.context.0.adapter_features(self.id)
975    }
976
977    fn limits(&self) -> crate::Limits {
978        self.context.0.adapter_limits(self.id)
979    }
980
981    fn downlevel_capabilities(&self) -> crate::DownlevelCapabilities {
982        self.context.0.adapter_downlevel_capabilities(self.id)
983    }
984
985    fn get_info(&self) -> crate::AdapterInfo {
986        self.context.0.adapter_get_info(self.id)
987    }
988
989    fn get_texture_format_features(
990        &self,
991        format: crate::TextureFormat,
992    ) -> crate::TextureFormatFeatures {
993        self.context
994            .0
995            .adapter_get_texture_format_features(self.id, format)
996    }
997
998    fn get_presentation_timestamp(&self) -> crate::PresentationTimestamp {
999        self.context.0.adapter_get_presentation_timestamp(self.id)
1000    }
1001
1002    fn cooperative_matrix_properties(&self) -> Vec<crate::wgt::CooperativeMatrixProperties> {
1003        self.context
1004            .0
1005            .adapter_cooperative_matrix_properties(self.id)
1006    }
1007}
1008
1009impl Drop for CoreAdapter {
1010    fn drop(&mut self) {
1011        self.context.0.adapter_drop(self.id)
1012    }
1013}
1014
1015impl dispatch::DeviceInterface for CoreDevice {
1016    fn features(&self) -> crate::Features {
1017        self.context.0.device_features(self.id)
1018    }
1019
1020    fn limits(&self) -> crate::Limits {
1021        self.context.0.device_limits(self.id)
1022    }
1023
1024    fn adapter_info(&self) -> crate::AdapterInfo {
1025        self.context.0.device_adapter_info(self.id)
1026    }
1027
1028    // If we have no way to create a shader module, we can't return one, and so most of the function is unreachable.
1029    #[cfg_attr(
1030        not(any(
1031            feature = "spirv",
1032            feature = "glsl",
1033            feature = "wgsl",
1034            feature = "naga-ir"
1035        )),
1036        expect(unused)
1037    )]
1038    fn create_shader_module(
1039        &self,
1040        desc: crate::ShaderModuleDescriptor<'_>,
1041        shader_bound_checks: wgt::ShaderRuntimeChecks,
1042    ) -> dispatch::DispatchShaderModule {
1043        let descriptor = wgc::pipeline::ShaderModuleDescriptor {
1044            label: desc.label.map(Borrowed),
1045            runtime_checks: shader_bound_checks,
1046        };
1047        let source = match desc.source {
1048            #[cfg(feature = "spirv")]
1049            ShaderSource::SpirV(ref spv) => {
1050                // Parse the given shader code and store its representation.
1051                let options = naga::front::spv::Options {
1052                    adjust_coordinate_space: false, // we require NDC_Y_UP feature
1053                    strict_capabilities: true,
1054                    block_ctx_dump_prefix: None,
1055                };
1056                wgc::pipeline::ShaderModuleSource::SpirV(Borrowed(spv), options)
1057            }
1058            #[cfg(feature = "glsl")]
1059            ShaderSource::Glsl {
1060                ref shader,
1061                stage,
1062                defines,
1063            } => {
1064                let options = naga::front::glsl::Options {
1065                    stage,
1066                    defines: defines
1067                        .iter()
1068                        .map(|&(key, value)| (String::from(key), String::from(value)))
1069                        .collect(),
1070                };
1071                wgc::pipeline::ShaderModuleSource::Glsl(Borrowed(shader), options)
1072            }
1073            #[cfg(feature = "wgsl")]
1074            ShaderSource::Wgsl(ref code) => wgc::pipeline::ShaderModuleSource::Wgsl(Borrowed(code)),
1075            #[cfg(feature = "naga-ir")]
1076            ShaderSource::Naga(module) => wgc::pipeline::ShaderModuleSource::Naga(module),
1077            ShaderSource::Dummy(_) => panic!("found `ShaderSource::Dummy`"),
1078        };
1079        let (id, error) =
1080            self.context
1081                .0
1082                .device_create_shader_module(self.id, &descriptor, source, None);
1083        let compilation_info = match error {
1084            Some(cause) => {
1085                self.context.handle_error(
1086                    &self.error_sink,
1087                    cause.clone(),
1088                    desc.label,
1089                    "Device::create_shader_module",
1090                );
1091                CompilationInfo::from(cause)
1092            }
1093            None => CompilationInfo { messages: vec![] },
1094        };
1095
1096        CoreShaderModule {
1097            context: self.context.clone(),
1098            id,
1099            compilation_info,
1100        }
1101        .into()
1102    }
1103
1104    unsafe fn create_shader_module_passthrough(
1105        &self,
1106        desc: &crate::ShaderModuleDescriptorPassthrough<'_>,
1107    ) -> dispatch::DispatchShaderModule {
1108        let desc = desc.map_label(|l| l.map(Cow::from));
1109        let (id, error) = unsafe {
1110            self.context
1111                .0
1112                .device_create_shader_module_passthrough(self.id, &desc, None)
1113        };
1114
1115        let compilation_info = match error {
1116            Some(cause) => {
1117                self.context.handle_error(
1118                    &self.error_sink,
1119                    cause.clone(),
1120                    desc.label.as_deref(),
1121                    "Device::create_shader_module_passthrough",
1122                );
1123                CompilationInfo::from(cause)
1124            }
1125            None => CompilationInfo { messages: vec![] },
1126        };
1127
1128        CoreShaderModule {
1129            context: self.context.clone(),
1130            id,
1131            compilation_info,
1132        }
1133        .into()
1134    }
1135
1136    fn create_bind_group_layout(
1137        &self,
1138        desc: &crate::BindGroupLayoutDescriptor<'_>,
1139    ) -> dispatch::DispatchBindGroupLayout {
1140        let descriptor = wgc::binding_model::BindGroupLayoutDescriptor {
1141            label: desc.label.map(Borrowed),
1142            entries: Borrowed(desc.entries),
1143        };
1144        let (id, error) =
1145            self.context
1146                .0
1147                .device_create_bind_group_layout(self.id, &descriptor, None);
1148        if let Some(cause) = error {
1149            self.context.handle_error(
1150                &self.error_sink,
1151                cause,
1152                desc.label,
1153                "Device::create_bind_group_layout",
1154            );
1155        }
1156        CoreBindGroupLayout {
1157            context: self.context.clone(),
1158            id,
1159        }
1160        .into()
1161    }
1162
1163    fn create_bind_group(
1164        &self,
1165        desc: &crate::BindGroupDescriptor<'_>,
1166    ) -> dispatch::DispatchBindGroup {
1167        use wgc::binding_model as bm;
1168
1169        let mut arrayed_texture_views = Vec::new();
1170        let mut arrayed_samplers = Vec::new();
1171        if self.features.contains(Features::TEXTURE_BINDING_ARRAY) {
1172            // gather all the array view IDs first
1173            for entry in desc.entries.iter() {
1174                if let BindingResource::TextureViewArray(array) = entry.resource {
1175                    arrayed_texture_views.extend(array.iter().map(|view| view.inner.as_core().id));
1176                }
1177                if let BindingResource::SamplerArray(array) = entry.resource {
1178                    arrayed_samplers.extend(array.iter().map(|sampler| sampler.inner.as_core().id));
1179                }
1180            }
1181        }
1182        let mut remaining_arrayed_texture_views = &arrayed_texture_views[..];
1183        let mut remaining_arrayed_samplers = &arrayed_samplers[..];
1184
1185        let mut arrayed_buffer_bindings = Vec::new();
1186        if self.features.contains(Features::BUFFER_BINDING_ARRAY) {
1187            // gather all the buffers first
1188            for entry in desc.entries.iter() {
1189                if let BindingResource::BufferArray(array) = entry.resource {
1190                    arrayed_buffer_bindings.extend(array.iter().map(|binding| bm::BufferBinding {
1191                        buffer: binding.buffer.inner.as_core().id,
1192                        offset: binding.offset,
1193                        size: binding.size.map(wgt::BufferSize::get),
1194                    }));
1195                }
1196            }
1197        }
1198        let mut remaining_arrayed_buffer_bindings = &arrayed_buffer_bindings[..];
1199
1200        let mut arrayed_acceleration_structures = Vec::new();
1201        if self
1202            .features
1203            .contains(Features::ACCELERATION_STRUCTURE_BINDING_ARRAY)
1204        {
1205            // Gather all the TLAS IDs used by TLAS arrays first (same pattern as other arrayed resources).
1206            for entry in desc.entries.iter() {
1207                if let BindingResource::AccelerationStructureArray(array) = entry.resource {
1208                    arrayed_acceleration_structures
1209                        .extend(array.iter().map(|tlas| tlas.inner.as_core().id));
1210                }
1211            }
1212        }
1213        let mut remaining_arrayed_acceleration_structures = &arrayed_acceleration_structures[..];
1214
1215        let entries = desc
1216            .entries
1217            .iter()
1218            .map(|entry| bm::BindGroupEntry {
1219                binding: entry.binding,
1220                resource: match entry.resource {
1221                    BindingResource::Buffer(BufferBinding {
1222                        buffer,
1223                        offset,
1224                        size,
1225                    }) => bm::BindingResource::Buffer(bm::BufferBinding {
1226                        buffer: buffer.inner.as_core().id,
1227                        offset,
1228                        size: size.map(wgt::BufferSize::get),
1229                    }),
1230                    BindingResource::BufferArray(array) => {
1231                        let slice = &remaining_arrayed_buffer_bindings[..array.len()];
1232                        remaining_arrayed_buffer_bindings =
1233                            &remaining_arrayed_buffer_bindings[array.len()..];
1234                        bm::BindingResource::BufferArray(Borrowed(slice))
1235                    }
1236                    BindingResource::Sampler(sampler) => {
1237                        bm::BindingResource::Sampler(sampler.inner.as_core().id)
1238                    }
1239                    BindingResource::SamplerArray(array) => {
1240                        let slice = &remaining_arrayed_samplers[..array.len()];
1241                        remaining_arrayed_samplers = &remaining_arrayed_samplers[array.len()..];
1242                        bm::BindingResource::SamplerArray(Borrowed(slice))
1243                    }
1244                    BindingResource::TextureView(texture_view) => {
1245                        bm::BindingResource::TextureView(texture_view.inner.as_core().id)
1246                    }
1247                    BindingResource::TextureViewArray(array) => {
1248                        let slice = &remaining_arrayed_texture_views[..array.len()];
1249                        remaining_arrayed_texture_views =
1250                            &remaining_arrayed_texture_views[array.len()..];
1251                        bm::BindingResource::TextureViewArray(Borrowed(slice))
1252                    }
1253                    BindingResource::AccelerationStructure(acceleration_structure) => {
1254                        bm::BindingResource::AccelerationStructure(
1255                            acceleration_structure.inner.as_core().id,
1256                        )
1257                    }
1258                    BindingResource::AccelerationStructureArray(array) => {
1259                        let slice = &remaining_arrayed_acceleration_structures[..array.len()];
1260                        remaining_arrayed_acceleration_structures =
1261                            &remaining_arrayed_acceleration_structures[array.len()..];
1262                        bm::BindingResource::AccelerationStructureArray(Borrowed(slice))
1263                    }
1264                    BindingResource::ExternalTexture(external_texture) => {
1265                        bm::BindingResource::ExternalTexture(external_texture.inner.as_core().id)
1266                    }
1267                },
1268            })
1269            .collect::<Vec<_>>();
1270        let descriptor = bm::BindGroupDescriptor {
1271            label: desc.label.as_ref().map(|label| Borrowed(&label[..])),
1272            layout: desc.layout.inner.as_core().id,
1273            entries: Borrowed(&entries),
1274        };
1275
1276        let (id, error) = self
1277            .context
1278            .0
1279            .device_create_bind_group(self.id, &descriptor, None);
1280        if let Some(cause) = error {
1281            self.context.handle_error(
1282                &self.error_sink,
1283                cause,
1284                desc.label,
1285                "Device::create_bind_group",
1286            );
1287        }
1288        CoreBindGroup {
1289            context: self.context.clone(),
1290            id,
1291        }
1292        .into()
1293    }
1294
1295    fn create_pipeline_layout(
1296        &self,
1297        desc: &crate::PipelineLayoutDescriptor<'_>,
1298    ) -> dispatch::DispatchPipelineLayout {
1299        // Limit is always less or equal to hal::MAX_BIND_GROUPS, so this is always right
1300        // Guards following ArrayVec
1301        assert!(
1302            desc.bind_group_layouts.len() <= wgc::MAX_BIND_GROUPS,
1303            "Bind group layout count {} exceeds device bind group limit {}",
1304            desc.bind_group_layouts.len(),
1305            wgc::MAX_BIND_GROUPS
1306        );
1307
1308        let temp_layouts = desc
1309            .bind_group_layouts
1310            .iter()
1311            .map(|bgl| bgl.map(|bgl| bgl.inner.as_core().id))
1312            .collect::<ArrayVec<_, { wgc::MAX_BIND_GROUPS }>>();
1313        let descriptor = wgc::binding_model::PipelineLayoutDescriptor {
1314            label: desc.label.map(Borrowed),
1315            bind_group_layouts: Borrowed(&temp_layouts),
1316            immediate_size: desc.immediate_size,
1317        };
1318
1319        let (id, error) = self
1320            .context
1321            .0
1322            .device_create_pipeline_layout(self.id, &descriptor, None);
1323        if let Some(cause) = error {
1324            self.context.handle_error(
1325                &self.error_sink,
1326                cause,
1327                desc.label,
1328                "Device::create_pipeline_layout",
1329            );
1330        }
1331        CorePipelineLayout {
1332            context: self.context.clone(),
1333            id,
1334        }
1335        .into()
1336    }
1337
1338    fn create_render_pipeline(
1339        &self,
1340        desc: &crate::RenderPipelineDescriptor<'_>,
1341    ) -> dispatch::DispatchRenderPipeline {
1342        use wgc::pipeline as pipe;
1343
1344        let vertex_buffers: ArrayVec<_, { wgc::MAX_VERTEX_BUFFERS }> = desc
1345            .vertex
1346            .buffers
1347            .iter()
1348            .map(|vbuf| {
1349                vbuf.as_ref().map(|vbuf| pipe::VertexBufferLayout {
1350                    array_stride: vbuf.array_stride,
1351                    step_mode: vbuf.step_mode,
1352                    attributes: Borrowed(vbuf.attributes),
1353                })
1354            })
1355            .collect();
1356
1357        let vert_constants = desc
1358            .vertex
1359            .compilation_options
1360            .constants
1361            .iter()
1362            .map(|&(key, value)| (String::from(key), value))
1363            .collect();
1364
1365        let descriptor = pipe::RenderPipelineDescriptor {
1366            label: desc.label.map(Borrowed),
1367            layout: desc.layout.map(|layout| layout.inner.as_core().id),
1368            vertex: pipe::VertexState {
1369                stage: pipe::ProgrammableStageDescriptor {
1370                    module: desc.vertex.module.inner.as_core().id,
1371                    entry_point: desc.vertex.entry_point.map(Borrowed),
1372                    constants: vert_constants,
1373                    zero_initialize_workgroup_memory: desc
1374                        .vertex
1375                        .compilation_options
1376                        .zero_initialize_workgroup_memory,
1377                },
1378                buffers: Borrowed(&vertex_buffers),
1379            },
1380            primitive: desc.primitive,
1381            depth_stencil: desc.depth_stencil.clone(),
1382            multisample: desc.multisample,
1383            fragment: desc.fragment.as_ref().map(|frag| {
1384                let frag_constants = frag
1385                    .compilation_options
1386                    .constants
1387                    .iter()
1388                    .map(|&(key, value)| (String::from(key), value))
1389                    .collect();
1390                pipe::FragmentState {
1391                    stage: pipe::ProgrammableStageDescriptor {
1392                        module: frag.module.inner.as_core().id,
1393                        entry_point: frag.entry_point.map(Borrowed),
1394                        constants: frag_constants,
1395                        zero_initialize_workgroup_memory: frag
1396                            .compilation_options
1397                            .zero_initialize_workgroup_memory,
1398                    },
1399                    targets: Borrowed(frag.targets),
1400                }
1401            }),
1402            multiview_mask: desc.multiview_mask,
1403            cache: desc.cache.map(|cache| cache.inner.as_core().id),
1404        };
1405
1406        let (id, error) = self
1407            .context
1408            .0
1409            .device_create_render_pipeline(self.id, &descriptor, None);
1410        if let Some(cause) = error {
1411            if let wgc::pipeline::CreateRenderPipelineError::Internal { stage, ref error } = cause {
1412                log::error!("Shader translation error for stage {stage:?}: {error}");
1413                log::error!("Please report it to https://github.com/gfx-rs/wgpu");
1414            }
1415            self.context.handle_error(
1416                &self.error_sink,
1417                cause,
1418                desc.label,
1419                "Device::create_render_pipeline",
1420            );
1421        }
1422        CoreRenderPipeline {
1423            context: self.context.clone(),
1424            id,
1425            error_sink: Arc::clone(&self.error_sink),
1426        }
1427        .into()
1428    }
1429
1430    fn create_mesh_pipeline(
1431        &self,
1432        desc: &crate::MeshPipelineDescriptor<'_>,
1433    ) -> dispatch::DispatchRenderPipeline {
1434        use wgc::pipeline as pipe;
1435
1436        let mesh_constants = desc
1437            .mesh
1438            .compilation_options
1439            .constants
1440            .iter()
1441            .map(|&(key, value)| (String::from(key), value))
1442            .collect();
1443        let descriptor = pipe::MeshPipelineDescriptor {
1444            label: desc.label.map(Borrowed),
1445            task: desc.task.as_ref().map(|task| {
1446                let task_constants = task
1447                    .compilation_options
1448                    .constants
1449                    .iter()
1450                    .map(|&(key, value)| (String::from(key), value))
1451                    .collect();
1452                pipe::TaskState {
1453                    stage: pipe::ProgrammableStageDescriptor {
1454                        module: task.module.inner.as_core().id,
1455                        entry_point: task.entry_point.map(Borrowed),
1456                        constants: task_constants,
1457                        zero_initialize_workgroup_memory: desc
1458                            .mesh
1459                            .compilation_options
1460                            .zero_initialize_workgroup_memory,
1461                    },
1462                }
1463            }),
1464            mesh: pipe::MeshState {
1465                stage: pipe::ProgrammableStageDescriptor {
1466                    module: desc.mesh.module.inner.as_core().id,
1467                    entry_point: desc.mesh.entry_point.map(Borrowed),
1468                    constants: mesh_constants,
1469                    zero_initialize_workgroup_memory: desc
1470                        .mesh
1471                        .compilation_options
1472                        .zero_initialize_workgroup_memory,
1473                },
1474            },
1475            layout: desc.layout.map(|layout| layout.inner.as_core().id),
1476            primitive: desc.primitive,
1477            depth_stencil: desc.depth_stencil.clone(),
1478            multisample: desc.multisample,
1479            fragment: desc.fragment.as_ref().map(|frag| {
1480                let frag_constants = frag
1481                    .compilation_options
1482                    .constants
1483                    .iter()
1484                    .map(|&(key, value)| (String::from(key), value))
1485                    .collect();
1486                pipe::FragmentState {
1487                    stage: pipe::ProgrammableStageDescriptor {
1488                        module: frag.module.inner.as_core().id,
1489                        entry_point: frag.entry_point.map(Borrowed),
1490                        constants: frag_constants,
1491                        zero_initialize_workgroup_memory: frag
1492                            .compilation_options
1493                            .zero_initialize_workgroup_memory,
1494                    },
1495                    targets: Borrowed(frag.targets),
1496                }
1497            }),
1498            multiview: desc.multiview,
1499            cache: desc.cache.map(|cache| cache.inner.as_core().id),
1500        };
1501
1502        let (id, error) = self
1503            .context
1504            .0
1505            .device_create_mesh_pipeline(self.id, &descriptor, None);
1506        if let Some(cause) = error {
1507            if let wgc::pipeline::CreateRenderPipelineError::Internal { stage, ref error } = cause {
1508                log::error!("Shader translation error for stage {stage:?}: {error}");
1509                log::error!("Please report it to https://github.com/gfx-rs/wgpu");
1510            }
1511            self.context.handle_error(
1512                &self.error_sink,
1513                cause,
1514                desc.label,
1515                "Device::create_render_pipeline",
1516            );
1517        }
1518        CoreRenderPipeline {
1519            context: self.context.clone(),
1520            id,
1521            error_sink: Arc::clone(&self.error_sink),
1522        }
1523        .into()
1524    }
1525
1526    fn create_compute_pipeline(
1527        &self,
1528        desc: &crate::ComputePipelineDescriptor<'_>,
1529    ) -> dispatch::DispatchComputePipeline {
1530        use wgc::pipeline as pipe;
1531
1532        let constants = desc
1533            .compilation_options
1534            .constants
1535            .iter()
1536            .map(|&(key, value)| (String::from(key), value))
1537            .collect();
1538
1539        let descriptor = pipe::ComputePipelineDescriptor {
1540            label: desc.label.map(Borrowed),
1541            layout: desc.layout.map(|pll| pll.inner.as_core().id),
1542            stage: pipe::ProgrammableStageDescriptor {
1543                module: desc.module.inner.as_core().id,
1544                entry_point: desc.entry_point.map(Borrowed),
1545                constants,
1546                zero_initialize_workgroup_memory: desc
1547                    .compilation_options
1548                    .zero_initialize_workgroup_memory,
1549            },
1550            cache: desc.cache.map(|cache| cache.inner.as_core().id),
1551        };
1552
1553        let (id, error) = self
1554            .context
1555            .0
1556            .device_create_compute_pipeline(self.id, &descriptor, None);
1557        if let Some(cause) = error {
1558            if let wgc::pipeline::CreateComputePipelineError::Internal(ref error) = cause {
1559                log::error!(
1560                    "Shader translation error for stage {:?}: {}",
1561                    wgt::ShaderStages::COMPUTE,
1562                    error
1563                );
1564                log::error!("Please report it to https://github.com/gfx-rs/wgpu");
1565            }
1566            self.context.handle_error(
1567                &self.error_sink,
1568                cause,
1569                desc.label,
1570                "Device::create_compute_pipeline",
1571            );
1572        }
1573        CoreComputePipeline {
1574            context: self.context.clone(),
1575            id,
1576            error_sink: Arc::clone(&self.error_sink),
1577        }
1578        .into()
1579    }
1580
1581    unsafe fn create_pipeline_cache(
1582        &self,
1583        desc: &crate::PipelineCacheDescriptor<'_>,
1584    ) -> dispatch::DispatchPipelineCache {
1585        use wgc::pipeline as pipe;
1586
1587        let descriptor = pipe::PipelineCacheDescriptor {
1588            label: desc.label.map(Borrowed),
1589            data: desc.data.map(Borrowed),
1590            fallback: desc.fallback,
1591        };
1592        let (id, error) = unsafe {
1593            self.context
1594                .0
1595                .device_create_pipeline_cache(self.id, &descriptor, None)
1596        };
1597        if let Some(cause) = error {
1598            self.context.handle_error(
1599                &self.error_sink,
1600                cause,
1601                desc.label,
1602                "Device::device_create_pipeline_cache_init",
1603            );
1604        }
1605        CorePipelineCache {
1606            context: self.context.clone(),
1607            id,
1608        }
1609        .into()
1610    }
1611
1612    fn create_buffer(&self, desc: &crate::BufferDescriptor<'_>) -> dispatch::DispatchBuffer {
1613        let (id, error) = self.context.0.device_create_buffer(
1614            self.id,
1615            &desc.map_label(|l| l.map(Borrowed)),
1616            None,
1617        );
1618        if let Some(cause) = error {
1619            self.context
1620                .handle_error(&self.error_sink, cause, desc.label, "Device::create_buffer");
1621        }
1622
1623        CoreBuffer {
1624            context: self.context.clone(),
1625            id,
1626            error_sink: Arc::clone(&self.error_sink),
1627        }
1628        .into()
1629    }
1630
1631    fn create_texture(&self, desc: &crate::TextureDescriptor<'_>) -> dispatch::DispatchTexture {
1632        let wgt_desc = desc.map_label_and_view_formats(|l| l.map(Borrowed), |v| v.to_vec());
1633        let (id, error) = self
1634            .context
1635            .0
1636            .device_create_texture(self.id, &wgt_desc, None);
1637        if let Some(cause) = error {
1638            self.context.handle_error(
1639                &self.error_sink,
1640                cause,
1641                desc.label,
1642                "Device::create_texture",
1643            );
1644        }
1645
1646        CoreTexture {
1647            context: self.context.clone(),
1648            id,
1649            error_sink: Arc::clone(&self.error_sink),
1650        }
1651        .into()
1652    }
1653
1654    fn create_external_texture(
1655        &self,
1656        desc: &crate::ExternalTextureDescriptor<'_>,
1657        planes: &[&crate::TextureView],
1658    ) -> dispatch::DispatchExternalTexture {
1659        let wgt_desc = desc.map_label(|l| l.map(Borrowed));
1660        let planes = planes
1661            .iter()
1662            .map(|plane| plane.inner.as_core().id)
1663            .collect::<Vec<_>>();
1664        let (id, error) = self
1665            .context
1666            .0
1667            .device_create_external_texture(self.id, &wgt_desc, &planes, None);
1668        if let Some(cause) = error {
1669            self.context.handle_error(
1670                &self.error_sink,
1671                cause,
1672                desc.label,
1673                "Device::create_external_texture",
1674            );
1675        }
1676
1677        CoreExternalTexture {
1678            context: self.context.clone(),
1679            id,
1680        }
1681        .into()
1682    }
1683
1684    fn create_blas(
1685        &self,
1686        desc: &crate::CreateBlasDescriptor<'_>,
1687        sizes: crate::BlasGeometrySizeDescriptors,
1688    ) -> (Option<u64>, dispatch::DispatchBlas) {
1689        let global = &self.context.0;
1690        let (id, handle, error) =
1691            global.device_create_blas(self.id, &desc.map_label(|l| l.map(Borrowed)), sizes, None);
1692        if let Some(cause) = error {
1693            self.context
1694                .handle_error(&self.error_sink, cause, desc.label, "Device::create_blas");
1695        }
1696        (
1697            handle,
1698            CoreBlas {
1699                context: self.context.clone(),
1700                id,
1701                error_sink: Arc::clone(&self.error_sink),
1702            }
1703            .into(),
1704        )
1705    }
1706
1707    fn create_tlas(&self, desc: &crate::CreateTlasDescriptor<'_>) -> dispatch::DispatchTlas {
1708        let global = &self.context.0;
1709        let (id, error) =
1710            global.device_create_tlas(self.id, &desc.map_label(|l| l.map(Borrowed)), None);
1711        if let Some(cause) = error {
1712            self.context
1713                .handle_error(&self.error_sink, cause, desc.label, "Device::create_tlas");
1714        }
1715        CoreTlas {
1716            context: self.context.clone(),
1717            id,
1718            // error_sink: Arc::clone(&self.error_sink),
1719        }
1720        .into()
1721    }
1722
1723    fn create_sampler(&self, desc: &crate::SamplerDescriptor<'_>) -> dispatch::DispatchSampler {
1724        let descriptor = wgc::resource::SamplerDescriptor {
1725            label: desc.label.map(Borrowed),
1726            address_modes: [
1727                desc.address_mode_u,
1728                desc.address_mode_v,
1729                desc.address_mode_w,
1730            ],
1731            mag_filter: desc.mag_filter,
1732            min_filter: desc.min_filter,
1733            mipmap_filter: desc.mipmap_filter,
1734            lod_min_clamp: desc.lod_min_clamp,
1735            lod_max_clamp: desc.lod_max_clamp,
1736            compare: desc.compare,
1737            anisotropy_clamp: desc.anisotropy_clamp,
1738            border_color: desc.border_color,
1739        };
1740
1741        let (id, error) = self
1742            .context
1743            .0
1744            .device_create_sampler(self.id, &descriptor, None);
1745        if let Some(cause) = error {
1746            self.context.handle_error(
1747                &self.error_sink,
1748                cause,
1749                desc.label,
1750                "Device::create_sampler",
1751            );
1752        }
1753        CoreSampler {
1754            context: self.context.clone(),
1755            id,
1756        }
1757        .into()
1758    }
1759
1760    fn create_query_set(&self, desc: &crate::QuerySetDescriptor<'_>) -> dispatch::DispatchQuerySet {
1761        let (id, error) = self.context.0.device_create_query_set(
1762            self.id,
1763            &desc.map_label(|l| l.map(Borrowed)),
1764            None,
1765        );
1766        if let Some(cause) = error {
1767            self.context
1768                .handle_error_nolabel(&self.error_sink, cause, "Device::create_query_set");
1769        }
1770        CoreQuerySet {
1771            context: self.context.clone(),
1772            id,
1773        }
1774        .into()
1775    }
1776
1777    fn create_command_encoder(
1778        &self,
1779        desc: &crate::CommandEncoderDescriptor<'_>,
1780    ) -> dispatch::DispatchCommandEncoder {
1781        let (id, error) = self.context.0.device_create_command_encoder(
1782            self.id,
1783            &desc.map_label(|l| l.map(Borrowed)),
1784            None,
1785        );
1786        if let Some(cause) = error {
1787            self.context.handle_error(
1788                &self.error_sink,
1789                cause,
1790                desc.label,
1791                "Device::create_command_encoder",
1792            );
1793        }
1794
1795        CoreCommandEncoder {
1796            context: self.context.clone(),
1797            id,
1798            error_sink: Arc::clone(&self.error_sink),
1799        }
1800        .into()
1801    }
1802
1803    fn create_render_bundle_encoder(
1804        &self,
1805        desc: &crate::RenderBundleEncoderDescriptor<'_>,
1806    ) -> dispatch::DispatchRenderBundleEncoder {
1807        let descriptor = wgc::command::RenderBundleEncoderDescriptor {
1808            label: desc.label.map(Borrowed),
1809            color_formats: Borrowed(desc.color_formats),
1810            depth_stencil: desc.depth_stencil,
1811            sample_count: desc.sample_count,
1812            multiview: desc.multiview,
1813        };
1814        let (encoder, error) = self
1815            .context
1816            .0
1817            .device_create_render_bundle_encoder(self.id, &descriptor);
1818        if let Some(cause) = error {
1819            self.context.handle_error(
1820                &self.error_sink,
1821                cause,
1822                desc.label,
1823                "Device::create_render_bundle_encoder",
1824            );
1825        }
1826
1827        CoreRenderBundleEncoder {
1828            context: self.context.clone(),
1829            error_sink: Arc::clone(&self.error_sink),
1830            encoder,
1831            id: crate::cmp::Identifier::create(),
1832        }
1833        .into()
1834    }
1835
1836    fn set_device_lost_callback(&self, device_lost_callback: dispatch::BoxDeviceLostCallback) {
1837        self.context
1838            .0
1839            .device_set_device_lost_closure(self.id, device_lost_callback);
1840    }
1841
1842    fn on_uncaptured_error(&self, handler: Arc<dyn crate::UncapturedErrorHandler>) {
1843        let mut error_sink = self.error_sink.lock();
1844        error_sink.uncaptured_handler = Some(handler);
1845    }
1846
1847    fn push_error_scope(&self, filter: crate::ErrorFilter) -> u32 {
1848        let mut error_sink = self.error_sink.lock();
1849        let thread_id = thread_id::ThreadId::current();
1850        let scopes = error_sink.scopes.entry(thread_id).or_default();
1851        let index = scopes
1852            .len()
1853            .try_into()
1854            .expect("Greater than 2^32 nested error scopes");
1855        scopes.push(ErrorScope {
1856            error: None,
1857            filter,
1858        });
1859        index
1860    }
1861
1862    fn pop_error_scope(&self, index: u32) -> Pin<Box<dyn dispatch::PopErrorScopeFuture>> {
1863        let mut error_sink = self.error_sink.lock();
1864
1865        // We go out of our way to avoid panicking while unwinding, because that would abort the process,
1866        // and we are supposed to just drop the error scope on the floor.
1867        let is_panicking = crate::util::is_panicking();
1868        let thread_id = thread_id::ThreadId::current();
1869        let err = "Mismatched pop_error_scope call: no error scope for this thread. Error scopes are thread-local.";
1870        let scopes = match error_sink.scopes.get_mut(&thread_id) {
1871            Some(s) => s,
1872            None => {
1873                if !is_panicking {
1874                    panic!("{err}");
1875                } else {
1876                    return Box::pin(ready(None));
1877                }
1878            }
1879        };
1880        if scopes.is_empty() && !is_panicking {
1881            panic!("{err}");
1882        }
1883        if index as usize != scopes.len() - 1 && !is_panicking {
1884            panic!(
1885                "Mismatched pop_error_scope call: error scopes must be popped in reverse order."
1886            );
1887        }
1888
1889        // It would be more correct in this case to use `remove` here so that when unwinding is occurring
1890        // we would remove the correct error scope, but we don't have such a primitive on the web
1891        // and having consistent behavior here is more important. If you are unwinding and it unwinds
1892        // the guards in the wrong order, it's totally reasonable to have incorrect behavior.
1893        let scope = match scopes.pop() {
1894            Some(s) => s,
1895            None if !is_panicking => unreachable!(),
1896            None => return Box::pin(ready(None)),
1897        };
1898
1899        Box::pin(ready(scope.error))
1900    }
1901
1902    unsafe fn start_graphics_debugger_capture(&self) {
1903        unsafe {
1904            self.context
1905                .0
1906                .device_start_graphics_debugger_capture(self.id)
1907        };
1908    }
1909
1910    unsafe fn stop_graphics_debugger_capture(&self) {
1911        unsafe {
1912            self.context
1913                .0
1914                .device_stop_graphics_debugger_capture(self.id)
1915        };
1916    }
1917
1918    fn poll(&self, poll_type: wgt::PollType<u64>) -> Result<crate::PollStatus, crate::PollError> {
1919        match self.context.0.device_poll(self.id, poll_type) {
1920            Ok(status) => Ok(status),
1921            Err(err) => {
1922                if let Some(poll_error) = err.to_poll_error() {
1923                    return Err(poll_error);
1924                }
1925
1926                self.context.handle_error_fatal(err, "Device::poll")
1927            }
1928        }
1929    }
1930
1931    fn get_internal_counters(&self) -> crate::InternalCounters {
1932        self.context.0.device_get_internal_counters(self.id)
1933    }
1934
1935    fn generate_allocator_report(&self) -> Option<wgt::AllocatorReport> {
1936        self.context.0.device_generate_allocator_report(self.id)
1937    }
1938
1939    fn destroy(&self) {
1940        self.context.0.device_destroy(self.id);
1941    }
1942}
1943
1944impl Drop for CoreDevice {
1945    fn drop(&mut self) {
1946        self.context.0.device_drop(self.id)
1947    }
1948}
1949
1950impl dispatch::QueueInterface for CoreQueue {
1951    fn write_buffer(
1952        &self,
1953        buffer: &dispatch::DispatchBuffer,
1954        offset: crate::BufferAddress,
1955        data: &[u8],
1956    ) {
1957        let buffer = buffer.as_core();
1958
1959        match self
1960            .context
1961            .0
1962            .queue_write_buffer(self.id, buffer.id, offset, data)
1963        {
1964            Ok(()) => (),
1965            Err(err) => {
1966                self.context
1967                    .handle_error_nolabel(&self.error_sink, err, "Queue::write_buffer")
1968            }
1969        }
1970    }
1971
1972    fn create_staging_buffer(
1973        &self,
1974        size: crate::BufferSize,
1975    ) -> Option<dispatch::DispatchQueueWriteBuffer> {
1976        match self
1977            .context
1978            .0
1979            .queue_create_staging_buffer(self.id, size, None)
1980        {
1981            Ok((buffer_id, ptr)) => Some(
1982                CoreQueueWriteBuffer {
1983                    buffer_id,
1984                    mapping: CoreBufferMappedRange {
1985                        ptr,
1986                        size: size.get() as usize,
1987                    },
1988                }
1989                .into(),
1990            ),
1991            Err(err) => {
1992                self.context.handle_error_nolabel(
1993                    &self.error_sink,
1994                    err,
1995                    "Queue::write_buffer_with",
1996                );
1997                None
1998            }
1999        }
2000    }
2001
2002    fn validate_write_buffer(
2003        &self,
2004        buffer: &dispatch::DispatchBuffer,
2005        offset: wgt::BufferAddress,
2006        size: wgt::BufferSize,
2007    ) -> Option<()> {
2008        let buffer = buffer.as_core();
2009
2010        match self
2011            .context
2012            .0
2013            .queue_validate_write_buffer(self.id, buffer.id, offset, size)
2014        {
2015            Ok(()) => Some(()),
2016            Err(err) => {
2017                self.context.handle_error_nolabel(
2018                    &self.error_sink,
2019                    err,
2020                    "Queue::write_buffer_with",
2021                );
2022                None
2023            }
2024        }
2025    }
2026
2027    fn write_staging_buffer(
2028        &self,
2029        buffer: &dispatch::DispatchBuffer,
2030        offset: crate::BufferAddress,
2031        staging_buffer: &dispatch::DispatchQueueWriteBuffer,
2032    ) {
2033        let buffer = buffer.as_core();
2034        let staging_buffer = staging_buffer.as_core();
2035
2036        match self.context.0.queue_write_staging_buffer(
2037            self.id,
2038            buffer.id,
2039            offset,
2040            staging_buffer.buffer_id,
2041        ) {
2042            Ok(()) => (),
2043            Err(err) => {
2044                self.context.handle_error_nolabel(
2045                    &self.error_sink,
2046                    err,
2047                    "Queue::write_buffer_with",
2048                );
2049            }
2050        }
2051    }
2052
2053    fn write_texture(
2054        &self,
2055        texture: crate::TexelCopyTextureInfo<'_>,
2056        data: &[u8],
2057        data_layout: crate::TexelCopyBufferLayout,
2058        size: crate::Extent3d,
2059    ) {
2060        match self.context.0.queue_write_texture(
2061            self.id,
2062            &map_texture_copy_view(texture),
2063            data,
2064            &data_layout,
2065            &size,
2066        ) {
2067            Ok(()) => (),
2068            Err(err) => {
2069                self.context
2070                    .handle_error_nolabel(&self.error_sink, err, "Queue::write_texture")
2071            }
2072        }
2073    }
2074
2075    // This method needs to exist if either webgpu or webgl is enabled,
2076    // but we only actually have an implementation if webgl is enabled.
2077    #[cfg(web)]
2078    #[cfg_attr(not(webgl), expect(unused_variables))]
2079    fn copy_external_image_to_texture(
2080        &self,
2081        source: &crate::CopyExternalImageSourceInfo,
2082        dest: crate::CopyExternalImageDestInfo<&crate::api::Texture>,
2083        size: crate::Extent3d,
2084    ) {
2085        #[cfg(webgl)]
2086        match self.context.0.queue_copy_external_image_to_texture(
2087            self.id,
2088            source,
2089            map_texture_tagged_copy_view(dest),
2090            size,
2091        ) {
2092            Ok(()) => (),
2093            Err(err) => self.context.handle_error_nolabel(
2094                &self.error_sink,
2095                err,
2096                "Queue::copy_external_image_to_texture",
2097            ),
2098        }
2099    }
2100
2101    fn submit(
2102        &self,
2103        command_buffers: &mut dyn Iterator<Item = dispatch::DispatchCommandBuffer>,
2104    ) -> u64 {
2105        let temp_command_buffers = command_buffers.collect::<SmallVec<[_; 4]>>();
2106        let command_buffer_ids = temp_command_buffers
2107            .iter()
2108            .map(|cmdbuf| cmdbuf.as_core().id)
2109            .collect::<SmallVec<[_; 4]>>();
2110
2111        let index = match self.context.0.queue_submit(self.id, &command_buffer_ids) {
2112            Ok(index) => index,
2113            Err((index, err)) => {
2114                self.context
2115                    .handle_error_nolabel(&self.error_sink, err, "Queue::submit");
2116                index
2117            }
2118        };
2119
2120        drop(temp_command_buffers);
2121
2122        index
2123    }
2124
2125    fn get_timestamp_period(&self) -> f32 {
2126        self.context.0.queue_get_timestamp_period(self.id)
2127    }
2128
2129    fn on_submitted_work_done(&self, callback: dispatch::BoxSubmittedWorkDoneCallback) {
2130        self.context
2131            .0
2132            .queue_on_submitted_work_done(self.id, callback);
2133    }
2134
2135    fn compact_blas(&self, blas: &dispatch::DispatchBlas) -> (Option<u64>, dispatch::DispatchBlas) {
2136        let (id, handle, error) =
2137            self.context
2138                .0
2139                .queue_compact_blas(self.id, blas.as_core().id, None);
2140
2141        if let Some(cause) = error {
2142            self.context
2143                .handle_error_nolabel(&self.error_sink, cause, "Queue::compact_blas");
2144        }
2145        (
2146            handle,
2147            CoreBlas {
2148                context: self.context.clone(),
2149                id,
2150                error_sink: Arc::clone(&self.error_sink),
2151            }
2152            .into(),
2153        )
2154    }
2155
2156    fn present(&self, detail: &dispatch::DispatchSurfaceOutputDetail) {
2157        let detail = detail.as_core();
2158        match self.context.0.surface_present(detail.surface_id) {
2159            Ok(_status) => (),
2160            Err(err) => {
2161                self.context
2162                    .handle_error_nolabel(&self.error_sink, err, "Queue::present");
2163            }
2164        }
2165    }
2166}
2167
2168impl Drop for CoreQueue {
2169    fn drop(&mut self) {
2170        self.context.0.queue_drop(self.id)
2171    }
2172}
2173
2174impl dispatch::ShaderModuleInterface for CoreShaderModule {
2175    fn get_compilation_info(&self) -> Pin<Box<dyn dispatch::ShaderCompilationInfoFuture>> {
2176        Box::pin(ready(self.compilation_info.clone()))
2177    }
2178}
2179
2180impl Drop for CoreShaderModule {
2181    fn drop(&mut self) {
2182        self.context.0.shader_module_drop(self.id)
2183    }
2184}
2185
2186impl dispatch::BindGroupLayoutInterface for CoreBindGroupLayout {}
2187
2188impl Drop for CoreBindGroupLayout {
2189    fn drop(&mut self) {
2190        self.context.0.bind_group_layout_drop(self.id)
2191    }
2192}
2193
2194impl dispatch::BindGroupInterface for CoreBindGroup {}
2195
2196impl Drop for CoreBindGroup {
2197    fn drop(&mut self) {
2198        self.context.0.bind_group_drop(self.id)
2199    }
2200}
2201
2202impl dispatch::TextureViewInterface for CoreTextureView {}
2203
2204impl Drop for CoreTextureView {
2205    fn drop(&mut self) {
2206        self.context.0.texture_view_drop(self.id);
2207    }
2208}
2209
2210impl dispatch::ExternalTextureInterface for CoreExternalTexture {
2211    fn destroy(&self) {
2212        self.context.0.external_texture_destroy(self.id);
2213    }
2214}
2215
2216impl Drop for CoreExternalTexture {
2217    fn drop(&mut self) {
2218        self.context.0.external_texture_drop(self.id);
2219    }
2220}
2221
2222impl dispatch::SamplerInterface for CoreSampler {}
2223
2224impl Drop for CoreSampler {
2225    fn drop(&mut self) {
2226        self.context.0.sampler_drop(self.id)
2227    }
2228}
2229
2230impl dispatch::BufferInterface for CoreBuffer {
2231    fn map_async(
2232        &self,
2233        mode: crate::MapMode,
2234        range: Range<crate::BufferAddress>,
2235        callback: dispatch::BufferMapCallback,
2236    ) {
2237        let operation = wgc::resource::BufferMapOperation {
2238            host: match mode {
2239                MapMode::Read => wgc::device::HostMap::Read,
2240                MapMode::Write => wgc::device::HostMap::Write,
2241            },
2242            callback: Some(Box::new(|status| {
2243                let res = status.map_err(|_| crate::BufferAsyncError);
2244                callback(res);
2245            })),
2246        };
2247
2248        match self.context.0.buffer_map_async(
2249            self.id,
2250            range.start,
2251            Some(range.end - range.start),
2252            operation,
2253        ) {
2254            Ok(_) => (),
2255            Err(cause) => {
2256                self.context
2257                    .handle_error_nolabel(&self.error_sink, cause, "Buffer::map_async")
2258            }
2259        }
2260    }
2261
2262    fn get_mapped_range(
2263        &self,
2264        sub_range: Range<crate::BufferAddress>,
2265    ) -> Result<dispatch::DispatchBufferMappedRange, crate::MapRangeError> {
2266        let size = sub_range.end - sub_range.start;
2267        self.context
2268            .0
2269            .buffer_get_mapped_range(self.id, sub_range.start, Some(size))
2270            .map(|(ptr, size)| {
2271                CoreBufferMappedRange {
2272                    ptr,
2273                    size: size as usize,
2274                }
2275                .into()
2276            })
2277            .map_err(|err| crate::MapRangeError(self.context.format_error(&err)))
2278    }
2279
2280    fn unmap(&self) {
2281        match self.context.0.buffer_unmap(self.id) {
2282            Ok(()) => (),
2283            Err(cause) => {
2284                self.context
2285                    .handle_error_nolabel(&self.error_sink, cause, "Buffer::buffer_unmap")
2286            }
2287        }
2288    }
2289
2290    fn destroy(&self) {
2291        self.context.0.buffer_destroy(self.id);
2292    }
2293}
2294
2295impl Drop for CoreBuffer {
2296    fn drop(&mut self) {
2297        self.context.0.buffer_drop(self.id)
2298    }
2299}
2300
2301impl dispatch::TextureInterface for CoreTexture {
2302    fn create_view(
2303        &self,
2304        desc: &crate::TextureViewDescriptor<'_>,
2305    ) -> dispatch::DispatchTextureView {
2306        let descriptor = wgc::resource::TextureViewDescriptor {
2307            label: desc.label.map(Borrowed),
2308            format: desc.format,
2309            dimension: desc.dimension,
2310            usage: desc.usage,
2311            range: wgt::ImageSubresourceRange {
2312                aspect: desc.aspect,
2313                base_mip_level: desc.base_mip_level,
2314                mip_level_count: desc.mip_level_count,
2315                base_array_layer: desc.base_array_layer,
2316                array_layer_count: desc.array_layer_count,
2317            },
2318        };
2319        let (id, error) = self
2320            .context
2321            .0
2322            .texture_create_view(self.id, &descriptor, None);
2323        if let Some(cause) = error {
2324            self.context
2325                .handle_error(&self.error_sink, cause, desc.label, "Texture::create_view");
2326        }
2327        CoreTextureView {
2328            context: self.context.clone(),
2329            id,
2330        }
2331        .into()
2332    }
2333
2334    fn destroy(&self) {
2335        self.context.0.texture_destroy(self.id);
2336    }
2337}
2338
2339impl Drop for CoreTexture {
2340    fn drop(&mut self) {
2341        self.context.0.texture_drop(self.id)
2342    }
2343}
2344
2345impl dispatch::BlasInterface for CoreBlas {
2346    fn prepare_compact_async(&self, callback: BlasCompactCallback) {
2347        let callback: Option<wgc::resource::BlasCompactCallback> =
2348            Some(Box::new(|status: BlasPrepareCompactResult| {
2349                let res = status.map_err(|_| crate::BlasAsyncError);
2350                callback(res);
2351            }));
2352
2353        match self.context.0.blas_prepare_compact_async(self.id, callback) {
2354            Ok(_) => (),
2355            Err(cause) => self.context.handle_error_nolabel(
2356                &self.error_sink,
2357                cause,
2358                "Blas::prepare_compact_async",
2359            ),
2360        }
2361    }
2362
2363    fn ready_for_compaction(&self) -> bool {
2364        match self.context.0.ready_for_compaction(self.id) {
2365            Ok(ready) => ready,
2366            Err(cause) => {
2367                self.context.handle_error_nolabel(
2368                    &self.error_sink,
2369                    cause,
2370                    "Blas::ready_for_compaction",
2371                );
2372                // A BLAS is definitely not ready for compaction if it's not valid
2373                false
2374            }
2375        }
2376    }
2377}
2378
2379impl Drop for CoreBlas {
2380    fn drop(&mut self) {
2381        self.context.0.blas_drop(self.id)
2382    }
2383}
2384
2385impl dispatch::TlasInterface for CoreTlas {}
2386
2387impl Drop for CoreTlas {
2388    fn drop(&mut self) {
2389        self.context.0.tlas_drop(self.id)
2390    }
2391}
2392
2393impl dispatch::QuerySetInterface for CoreQuerySet {
2394    fn destroy(&self) {
2395        self.context.0.query_set_destroy(self.id);
2396    }
2397}
2398
2399impl Drop for CoreQuerySet {
2400    fn drop(&mut self) {
2401        self.context.0.query_set_drop(self.id)
2402    }
2403}
2404
2405impl dispatch::PipelineLayoutInterface for CorePipelineLayout {}
2406
2407impl Drop for CorePipelineLayout {
2408    fn drop(&mut self) {
2409        self.context.0.pipeline_layout_drop(self.id)
2410    }
2411}
2412
2413impl dispatch::RenderPipelineInterface for CoreRenderPipeline {
2414    fn get_bind_group_layout(&self, index: u32) -> dispatch::DispatchBindGroupLayout {
2415        let (id, error) = self
2416            .context
2417            .0
2418            .render_pipeline_get_bind_group_layout(self.id, index, None);
2419        if let Some(err) = error {
2420            self.context.handle_error_nolabel(
2421                &self.error_sink,
2422                err,
2423                "RenderPipeline::get_bind_group_layout",
2424            )
2425        }
2426        CoreBindGroupLayout {
2427            context: self.context.clone(),
2428            id,
2429        }
2430        .into()
2431    }
2432}
2433
2434impl Drop for CoreRenderPipeline {
2435    fn drop(&mut self) {
2436        self.context.0.render_pipeline_drop(self.id)
2437    }
2438}
2439
2440impl dispatch::ComputePipelineInterface for CoreComputePipeline {
2441    fn get_bind_group_layout(&self, index: u32) -> dispatch::DispatchBindGroupLayout {
2442        let (id, error) = self
2443            .context
2444            .0
2445            .compute_pipeline_get_bind_group_layout(self.id, index, None);
2446        if let Some(err) = error {
2447            self.context.handle_error_nolabel(
2448                &self.error_sink,
2449                err,
2450                "ComputePipeline::get_bind_group_layout",
2451            )
2452        }
2453        CoreBindGroupLayout {
2454            context: self.context.clone(),
2455            id,
2456        }
2457        .into()
2458    }
2459}
2460
2461impl Drop for CoreComputePipeline {
2462    fn drop(&mut self) {
2463        self.context.0.compute_pipeline_drop(self.id)
2464    }
2465}
2466
2467impl dispatch::PipelineCacheInterface for CorePipelineCache {
2468    fn get_data(&self) -> Option<Vec<u8>> {
2469        self.context.0.pipeline_cache_get_data(self.id)
2470    }
2471}
2472
2473impl Drop for CorePipelineCache {
2474    fn drop(&mut self) {
2475        self.context.0.pipeline_cache_drop(self.id)
2476    }
2477}
2478
2479impl dispatch::CommandEncoderInterface for CoreCommandEncoder {
2480    fn copy_buffer_to_buffer(
2481        &self,
2482        source: &dispatch::DispatchBuffer,
2483        source_offset: crate::BufferAddress,
2484        destination: &dispatch::DispatchBuffer,
2485        destination_offset: crate::BufferAddress,
2486        copy_size: Option<crate::BufferAddress>,
2487    ) {
2488        let source = source.as_core();
2489        let destination = destination.as_core();
2490
2491        if let Err(cause) = self.context.0.command_encoder_copy_buffer_to_buffer(
2492            self.id,
2493            source.id,
2494            source_offset,
2495            destination.id,
2496            destination_offset,
2497            copy_size,
2498        ) {
2499            self.context.handle_error_nolabel(
2500                &self.error_sink,
2501                cause,
2502                "CommandEncoder::copy_buffer_to_buffer",
2503            );
2504        }
2505    }
2506
2507    fn copy_buffer_to_texture(
2508        &self,
2509        source: crate::TexelCopyBufferInfo<'_>,
2510        destination: crate::TexelCopyTextureInfo<'_>,
2511        copy_size: crate::Extent3d,
2512    ) {
2513        if let Err(cause) = self.context.0.command_encoder_copy_buffer_to_texture(
2514            self.id,
2515            &map_buffer_copy_view(source),
2516            &map_texture_copy_view(destination),
2517            &copy_size,
2518        ) {
2519            self.context.handle_error_nolabel(
2520                &self.error_sink,
2521                cause,
2522                "CommandEncoder::copy_buffer_to_texture",
2523            );
2524        }
2525    }
2526
2527    fn copy_texture_to_buffer(
2528        &self,
2529        source: crate::TexelCopyTextureInfo<'_>,
2530        destination: crate::TexelCopyBufferInfo<'_>,
2531        copy_size: crate::Extent3d,
2532    ) {
2533        if let Err(cause) = self.context.0.command_encoder_copy_texture_to_buffer(
2534            self.id,
2535            &map_texture_copy_view(source),
2536            &map_buffer_copy_view(destination),
2537            &copy_size,
2538        ) {
2539            self.context.handle_error_nolabel(
2540                &self.error_sink,
2541                cause,
2542                "CommandEncoder::copy_texture_to_buffer",
2543            );
2544        }
2545    }
2546
2547    fn copy_texture_to_texture(
2548        &self,
2549        source: crate::TexelCopyTextureInfo<'_>,
2550        destination: crate::TexelCopyTextureInfo<'_>,
2551        copy_size: crate::Extent3d,
2552    ) {
2553        if let Err(cause) = self.context.0.command_encoder_copy_texture_to_texture(
2554            self.id,
2555            &map_texture_copy_view(source),
2556            &map_texture_copy_view(destination),
2557            &copy_size,
2558        ) {
2559            self.context.handle_error_nolabel(
2560                &self.error_sink,
2561                cause,
2562                "CommandEncoder::copy_texture_to_texture",
2563            );
2564        }
2565    }
2566
2567    fn begin_compute_pass(
2568        &self,
2569        desc: &crate::ComputePassDescriptor<'_>,
2570    ) -> dispatch::DispatchComputePass {
2571        let timestamp_writes =
2572            desc.timestamp_writes
2573                .as_ref()
2574                .map(|tw| wgc::command::PassTimestampWrites {
2575                    query_set: tw.query_set.inner.as_core().id,
2576                    beginning_of_pass_write_index: tw.beginning_of_pass_write_index,
2577                    end_of_pass_write_index: tw.end_of_pass_write_index,
2578                });
2579
2580        let (pass, err) = self.context.0.command_encoder_begin_compute_pass(
2581            self.id,
2582            &wgc::command::ComputePassDescriptor {
2583                label: desc.label.map(Borrowed),
2584                timestamp_writes,
2585            },
2586        );
2587
2588        if let Some(cause) = err {
2589            self.context.handle_error(
2590                &self.error_sink,
2591                cause,
2592                desc.label,
2593                "CommandEncoder::begin_compute_pass",
2594            );
2595        }
2596
2597        CoreComputePass {
2598            context: self.context.clone(),
2599            pass,
2600            error_sink: self.error_sink.clone(),
2601            id: crate::cmp::Identifier::create(),
2602        }
2603        .into()
2604    }
2605
2606    fn begin_render_pass(
2607        &self,
2608        desc: &crate::RenderPassDescriptor<'_>,
2609    ) -> dispatch::DispatchRenderPass {
2610        let colors = desc
2611            .color_attachments
2612            .iter()
2613            .map(|ca| {
2614                ca.as_ref()
2615                    .map(|at| wgc::command::RenderPassColorAttachment {
2616                        view: at.view.inner.as_core().id,
2617                        depth_slice: at.depth_slice,
2618                        resolve_target: at.resolve_target.map(|view| view.inner.as_core().id),
2619                        load_op: at.ops.load,
2620                        store_op: at.ops.store,
2621                    })
2622            })
2623            .collect::<Vec<_>>();
2624
2625        let depth_stencil = desc.depth_stencil_attachment.as_ref().map(|dsa| {
2626            wgc::command::RenderPassDepthStencilAttachment {
2627                view: dsa.view.inner.as_core().id,
2628                depth: map_pass_channel(dsa.depth_ops.as_ref()),
2629                stencil: map_pass_channel(dsa.stencil_ops.as_ref()),
2630            }
2631        });
2632
2633        let timestamp_writes =
2634            desc.timestamp_writes
2635                .as_ref()
2636                .map(|tw| wgc::command::PassTimestampWrites {
2637                    query_set: tw.query_set.inner.as_core().id,
2638                    beginning_of_pass_write_index: tw.beginning_of_pass_write_index,
2639                    end_of_pass_write_index: tw.end_of_pass_write_index,
2640                });
2641
2642        let (pass, err) = self.context.0.command_encoder_begin_render_pass(
2643            self.id,
2644            &wgc::command::RenderPassDescriptor {
2645                label: desc.label.map(Borrowed),
2646                timestamp_writes,
2647                color_attachments: Borrowed(&colors),
2648                depth_stencil_attachment: depth_stencil,
2649                occlusion_query_set: desc.occlusion_query_set.map(|qs| qs.inner.as_core().id),
2650                multiview_mask: desc.multiview_mask,
2651            },
2652        );
2653
2654        if let Some(cause) = err {
2655            self.context.handle_error(
2656                &self.error_sink,
2657                cause,
2658                desc.label,
2659                "CommandEncoder::begin_render_pass",
2660            );
2661        }
2662
2663        CoreRenderPass {
2664            context: self.context.clone(),
2665            pass,
2666            error_sink: self.error_sink.clone(),
2667            id: crate::cmp::Identifier::create(),
2668        }
2669        .into()
2670    }
2671
2672    fn finish(&mut self) -> dispatch::DispatchCommandBuffer {
2673        let descriptor = wgt::CommandBufferDescriptor::default();
2674        let (id, opt_label_and_error) =
2675            self.context
2676                .0
2677                .command_encoder_finish(self.id, &descriptor, None);
2678        if let Some((label, cause)) = opt_label_and_error {
2679            self.context
2680                .handle_error(&self.error_sink, cause, Some(&label), "a CommandEncoder");
2681        }
2682        CoreCommandBuffer {
2683            context: self.context.clone(),
2684            id,
2685        }
2686        .into()
2687    }
2688
2689    fn clear_texture(
2690        &self,
2691        texture: &dispatch::DispatchTexture,
2692        subresource_range: &crate::ImageSubresourceRange,
2693    ) {
2694        let texture = texture.as_core();
2695
2696        if let Err(cause) =
2697            self.context
2698                .0
2699                .command_encoder_clear_texture(self.id, texture.id, subresource_range)
2700        {
2701            self.context.handle_error_nolabel(
2702                &self.error_sink,
2703                cause,
2704                "CommandEncoder::clear_texture",
2705            );
2706        }
2707    }
2708
2709    fn clear_buffer(
2710        &self,
2711        buffer: &dispatch::DispatchBuffer,
2712        offset: crate::BufferAddress,
2713        size: Option<crate::BufferAddress>,
2714    ) {
2715        let buffer = buffer.as_core();
2716
2717        if let Err(cause) = self
2718            .context
2719            .0
2720            .command_encoder_clear_buffer(self.id, buffer.id, offset, size)
2721        {
2722            self.context.handle_error_nolabel(
2723                &self.error_sink,
2724                cause,
2725                "CommandEncoder::fill_buffer",
2726            );
2727        }
2728    }
2729
2730    fn insert_debug_marker(&self, label: &str) {
2731        if let Err(cause) = self
2732            .context
2733            .0
2734            .command_encoder_insert_debug_marker(self.id, label)
2735        {
2736            self.context.handle_error_nolabel(
2737                &self.error_sink,
2738                cause,
2739                "CommandEncoder::insert_debug_marker",
2740            );
2741        }
2742    }
2743
2744    fn push_debug_group(&self, label: &str) {
2745        if let Err(cause) = self
2746            .context
2747            .0
2748            .command_encoder_push_debug_group(self.id, label)
2749        {
2750            self.context.handle_error_nolabel(
2751                &self.error_sink,
2752                cause,
2753                "CommandEncoder::push_debug_group",
2754            );
2755        }
2756    }
2757
2758    fn pop_debug_group(&self) {
2759        if let Err(cause) = self.context.0.command_encoder_pop_debug_group(self.id) {
2760            self.context.handle_error_nolabel(
2761                &self.error_sink,
2762                cause,
2763                "CommandEncoder::pop_debug_group",
2764            );
2765        }
2766    }
2767
2768    fn write_timestamp(&self, query_set: &dispatch::DispatchQuerySet, query_index: u32) {
2769        let query_set = query_set.as_core();
2770
2771        if let Err(cause) =
2772            self.context
2773                .0
2774                .command_encoder_write_timestamp(self.id, query_set.id, query_index)
2775        {
2776            self.context.handle_error_nolabel(
2777                &self.error_sink,
2778                cause,
2779                "CommandEncoder::write_timestamp",
2780            );
2781        }
2782    }
2783
2784    fn resolve_query_set(
2785        &self,
2786        query_set: &dispatch::DispatchQuerySet,
2787        first_query: u32,
2788        query_count: u32,
2789        destination: &dispatch::DispatchBuffer,
2790        destination_offset: crate::BufferAddress,
2791    ) {
2792        let query_set = query_set.as_core();
2793        let destination = destination.as_core();
2794
2795        if let Err(cause) = self.context.0.command_encoder_resolve_query_set(
2796            self.id,
2797            query_set.id,
2798            first_query,
2799            query_count,
2800            destination.id,
2801            destination_offset,
2802        ) {
2803            self.context.handle_error_nolabel(
2804                &self.error_sink,
2805                cause,
2806                "CommandEncoder::resolve_query_set",
2807            );
2808        }
2809    }
2810
2811    fn mark_acceleration_structures_built<'a>(
2812        &self,
2813        blas: &mut dyn Iterator<Item = &'a Blas>,
2814        tlas: &mut dyn Iterator<Item = &'a Tlas>,
2815    ) {
2816        let blas = blas
2817            .map(|b| b.inner.as_core().id)
2818            .collect::<SmallVec<[_; 4]>>();
2819        let tlas = tlas
2820            .map(|t| t.inner.as_core().id)
2821            .collect::<SmallVec<[_; 4]>>();
2822        if let Err(cause) = self
2823            .context
2824            .0
2825            .command_encoder_mark_acceleration_structures_built(self.id, &blas, &tlas)
2826        {
2827            self.context.handle_error_nolabel(
2828                &self.error_sink,
2829                cause,
2830                "CommandEncoder::build_acceleration_structures_unsafe_tlas",
2831            );
2832        }
2833    }
2834
2835    fn build_acceleration_structures<'a>(
2836        &self,
2837        blas: &mut dyn Iterator<Item = &'a crate::BlasBuildEntry<'a>>,
2838        tlas: &mut dyn Iterator<Item = &'a crate::Tlas>,
2839    ) {
2840        let blas = blas.map(|e: &crate::BlasBuildEntry<'_>| {
2841            let geometries = match e.geometry {
2842                crate::BlasGeometries::TriangleGeometries(ref triangle_geometries) => {
2843                    let iter = triangle_geometries.iter().map(|tg| {
2844                        wgc::ray_tracing::BlasTriangleGeometry {
2845                            vertex_buffer: tg.vertex_buffer.inner.as_core().id,
2846                            index_buffer: tg.index_buffer.map(|buf| buf.inner.as_core().id),
2847                            transform_buffer: tg.transform_buffer.map(|buf| buf.inner.as_core().id),
2848                            size: tg.size,
2849                            transform_buffer_offset: tg.transform_buffer_offset,
2850                            first_vertex: tg.first_vertex,
2851                            vertex_stride: tg.vertex_stride,
2852                            first_index: tg.first_index,
2853                        }
2854                    });
2855                    wgc::ray_tracing::BlasGeometries::TriangleGeometries(Box::new(iter))
2856                }
2857                crate::BlasGeometries::AabbGeometries(ref aabb_geometries) => {
2858                    let iter =
2859                        aabb_geometries
2860                            .iter()
2861                            .map(|ag| wgc::ray_tracing::BlasAabbGeometry {
2862                                aabb_buffer: ag.aabb_buffer.inner.as_core().id,
2863                                stride: ag.stride,
2864                                size: ag.size,
2865                                primitive_offset: ag.primitive_offset,
2866                            });
2867                    wgc::ray_tracing::BlasGeometries::AabbGeometries(Box::new(iter))
2868                }
2869            };
2870            wgc::ray_tracing::BlasBuildEntry {
2871                blas: e.blas.inner.as_core().id,
2872                geometries,
2873            }
2874        });
2875
2876        let tlas = tlas.into_iter().map(|e| {
2877            let instances = e
2878                .instances
2879                .iter()
2880                .map(|instance: &Option<crate::TlasInstance>| {
2881                    instance
2882                        .as_ref()
2883                        .map(|instance| wgc::ray_tracing::TlasInstance {
2884                            blas: instance.blas.as_core().id,
2885                            transform: &instance.transform,
2886                            custom_data: instance.custom_data,
2887                            mask: instance.mask,
2888                        })
2889                });
2890            wgc::ray_tracing::TlasPackage {
2891                tlas: e.inner.as_core().id,
2892                instances: Box::new(instances),
2893                lowest_unmodified: e.lowest_unmodified,
2894            }
2895        });
2896
2897        if let Err(cause) = self
2898            .context
2899            .0
2900            .command_encoder_build_acceleration_structures(self.id, blas, tlas)
2901        {
2902            self.context.handle_error_nolabel(
2903                &self.error_sink,
2904                cause,
2905                "CommandEncoder::build_acceleration_structures_unsafe_tlas",
2906            );
2907        }
2908    }
2909
2910    fn transition_resources<'a>(
2911        &mut self,
2912        buffer_transitions: &mut dyn Iterator<
2913            Item = wgt::BufferTransition<&'a dispatch::DispatchBuffer>,
2914        >,
2915        texture_transitions: &mut dyn Iterator<
2916            Item = wgt::TextureTransition<&'a dispatch::DispatchTexture>,
2917        >,
2918    ) {
2919        let result = self.context.0.command_encoder_transition_resources(
2920            self.id,
2921            buffer_transitions.map(|t| wgt::BufferTransition {
2922                buffer: t.buffer.as_core().id,
2923                state: t.state,
2924            }),
2925            texture_transitions.map(|t| wgt::TextureTransition {
2926                texture: t.texture.as_core().id,
2927                selector: t.selector.clone(),
2928                state: t.state,
2929            }),
2930        );
2931
2932        if let Err(cause) = result {
2933            self.context.handle_error_nolabel(
2934                &self.error_sink,
2935                cause,
2936                "CommandEncoder::transition_resources",
2937            );
2938        }
2939    }
2940}
2941
2942impl Drop for CoreCommandEncoder {
2943    fn drop(&mut self) {
2944        self.context.0.command_encoder_drop(self.id)
2945    }
2946}
2947
2948impl dispatch::CommandBufferInterface for CoreCommandBuffer {}
2949
2950impl Drop for CoreCommandBuffer {
2951    fn drop(&mut self) {
2952        self.context.0.command_buffer_drop(self.id)
2953    }
2954}
2955
2956impl dispatch::ComputePassInterface for CoreComputePass {
2957    fn set_pipeline(&mut self, pipeline: &dispatch::DispatchComputePipeline) {
2958        let pipeline = pipeline.as_core();
2959
2960        if let Err(cause) = self
2961            .context
2962            .0
2963            .compute_pass_set_pipeline(&mut self.pass, pipeline.id)
2964        {
2965            self.context.handle_error(
2966                &self.error_sink,
2967                cause,
2968                self.pass.label(),
2969                "ComputePass::set_pipeline",
2970            );
2971        }
2972    }
2973
2974    fn set_bind_group(
2975        &mut self,
2976        index: u32,
2977        bind_group: Option<&dispatch::DispatchBindGroup>,
2978        offsets: &[crate::DynamicOffset],
2979    ) {
2980        let bg = bind_group.map(|bg| bg.as_core().id);
2981
2982        if let Err(cause) =
2983            self.context
2984                .0
2985                .compute_pass_set_bind_group(&mut self.pass, index, bg, offsets)
2986        {
2987            self.context.handle_error(
2988                &self.error_sink,
2989                cause,
2990                self.pass.label(),
2991                "ComputePass::set_bind_group",
2992            );
2993        }
2994    }
2995
2996    fn set_immediates(&mut self, offset: u32, data: &[u8]) {
2997        if let Err(cause) = self
2998            .context
2999            .0
3000            .compute_pass_set_immediates(&mut self.pass, offset, data)
3001        {
3002            self.context.handle_error(
3003                &self.error_sink,
3004                cause,
3005                self.pass.label(),
3006                "ComputePass::set_immediates",
3007            );
3008        }
3009    }
3010
3011    fn insert_debug_marker(&mut self, label: &str) {
3012        if let Err(cause) =
3013            self.context
3014                .0
3015                .compute_pass_insert_debug_marker(&mut self.pass, label, 0)
3016        {
3017            self.context.handle_error(
3018                &self.error_sink,
3019                cause,
3020                self.pass.label(),
3021                "ComputePass::insert_debug_marker",
3022            );
3023        }
3024    }
3025
3026    fn push_debug_group(&mut self, group_label: &str) {
3027        if let Err(cause) =
3028            self.context
3029                .0
3030                .compute_pass_push_debug_group(&mut self.pass, group_label, 0)
3031        {
3032            self.context.handle_error(
3033                &self.error_sink,
3034                cause,
3035                self.pass.label(),
3036                "ComputePass::push_debug_group",
3037            );
3038        }
3039    }
3040
3041    fn pop_debug_group(&mut self) {
3042        if let Err(cause) = self.context.0.compute_pass_pop_debug_group(&mut self.pass) {
3043            self.context.handle_error(
3044                &self.error_sink,
3045                cause,
3046                self.pass.label(),
3047                "ComputePass::pop_debug_group",
3048            );
3049        }
3050    }
3051
3052    fn write_timestamp(&mut self, query_set: &dispatch::DispatchQuerySet, query_index: u32) {
3053        let query_set = query_set.as_core();
3054
3055        if let Err(cause) =
3056            self.context
3057                .0
3058                .compute_pass_write_timestamp(&mut self.pass, query_set.id, query_index)
3059        {
3060            self.context.handle_error(
3061                &self.error_sink,
3062                cause,
3063                self.pass.label(),
3064                "ComputePass::write_timestamp",
3065            );
3066        }
3067    }
3068
3069    fn begin_pipeline_statistics_query(
3070        &mut self,
3071        query_set: &dispatch::DispatchQuerySet,
3072        query_index: u32,
3073    ) {
3074        let query_set = query_set.as_core();
3075
3076        if let Err(cause) = self.context.0.compute_pass_begin_pipeline_statistics_query(
3077            &mut self.pass,
3078            query_set.id,
3079            query_index,
3080        ) {
3081            self.context.handle_error(
3082                &self.error_sink,
3083                cause,
3084                self.pass.label(),
3085                "ComputePass::begin_pipeline_statistics_query",
3086            );
3087        }
3088    }
3089
3090    fn end_pipeline_statistics_query(&mut self) {
3091        if let Err(cause) = self
3092            .context
3093            .0
3094            .compute_pass_end_pipeline_statistics_query(&mut self.pass)
3095        {
3096            self.context.handle_error(
3097                &self.error_sink,
3098                cause,
3099                self.pass.label(),
3100                "ComputePass::end_pipeline_statistics_query",
3101            );
3102        }
3103    }
3104
3105    fn dispatch_workgroups(&mut self, x: u32, y: u32, z: u32) {
3106        if let Err(cause) = self
3107            .context
3108            .0
3109            .compute_pass_dispatch_workgroups(&mut self.pass, x, y, z)
3110        {
3111            self.context.handle_error(
3112                &self.error_sink,
3113                cause,
3114                self.pass.label(),
3115                "ComputePass::dispatch_workgroups",
3116            );
3117        }
3118    }
3119
3120    fn dispatch_workgroups_indirect(
3121        &mut self,
3122        indirect_buffer: &dispatch::DispatchBuffer,
3123        indirect_offset: crate::BufferAddress,
3124    ) {
3125        let indirect_buffer = indirect_buffer.as_core();
3126
3127        if let Err(cause) = self.context.0.compute_pass_dispatch_workgroups_indirect(
3128            &mut self.pass,
3129            indirect_buffer.id,
3130            indirect_offset,
3131        ) {
3132            self.context.handle_error(
3133                &self.error_sink,
3134                cause,
3135                self.pass.label(),
3136                "ComputePass::dispatch_workgroups_indirect",
3137            );
3138        }
3139    }
3140
3141    fn transition_resources<'a>(
3142        &mut self,
3143        buffer_transitions: &mut dyn Iterator<
3144            Item = wgt::BufferTransition<&'a dispatch::DispatchBuffer>,
3145        >,
3146        texture_transitions: &mut dyn Iterator<
3147            Item = wgt::TextureTransition<&'a dispatch::DispatchTextureView>,
3148        >,
3149    ) {
3150        let result = self.context.0.compute_pass_transition_resources(
3151            &mut self.pass,
3152            buffer_transitions.map(|t| wgt::BufferTransition {
3153                buffer: t.buffer.as_core().id,
3154                state: t.state,
3155            }),
3156            texture_transitions.map(|t| wgt::TextureTransition {
3157                texture: t.texture.as_core().id,
3158                selector: t.selector.clone(),
3159                state: t.state,
3160            }),
3161        );
3162
3163        if let Err(cause) = result {
3164            self.context.handle_error(
3165                &self.error_sink,
3166                cause,
3167                self.pass.label(),
3168                "ComputePass::transition_resources",
3169            );
3170        }
3171    }
3172}
3173
3174impl Drop for CoreComputePass {
3175    fn drop(&mut self) {
3176        if let Err(cause) = self.context.0.compute_pass_end(&mut self.pass) {
3177            self.context.handle_error(
3178                &self.error_sink,
3179                cause,
3180                self.pass.label(),
3181                "ComputePass::end",
3182            );
3183        }
3184    }
3185}
3186
3187impl dispatch::RenderPassInterface for CoreRenderPass {
3188    fn set_pipeline(&mut self, pipeline: &dispatch::DispatchRenderPipeline) {
3189        let pipeline = pipeline.as_core();
3190
3191        if let Err(cause) = self
3192            .context
3193            .0
3194            .render_pass_set_pipeline(&mut self.pass, pipeline.id)
3195        {
3196            self.context.handle_error(
3197                &self.error_sink,
3198                cause,
3199                self.pass.label(),
3200                "RenderPass::set_pipeline",
3201            );
3202        }
3203    }
3204
3205    fn set_bind_group(
3206        &mut self,
3207        index: u32,
3208        bind_group: Option<&dispatch::DispatchBindGroup>,
3209        offsets: &[crate::DynamicOffset],
3210    ) {
3211        let bg = bind_group.map(|bg| bg.as_core().id);
3212
3213        if let Err(cause) =
3214            self.context
3215                .0
3216                .render_pass_set_bind_group(&mut self.pass, index, bg, offsets)
3217        {
3218            self.context.handle_error(
3219                &self.error_sink,
3220                cause,
3221                self.pass.label(),
3222                "RenderPass::set_bind_group",
3223            );
3224        }
3225    }
3226
3227    fn set_index_buffer(
3228        &mut self,
3229        buffer: &dispatch::DispatchBuffer,
3230        index_format: crate::IndexFormat,
3231        offset: crate::BufferAddress,
3232        size: Option<crate::BufferSize>,
3233    ) {
3234        let buffer = buffer.as_core();
3235
3236        if let Err(cause) = self.context.0.render_pass_set_index_buffer(
3237            &mut self.pass,
3238            buffer.id,
3239            index_format,
3240            offset,
3241            size,
3242        ) {
3243            self.context.handle_error(
3244                &self.error_sink,
3245                cause,
3246                self.pass.label(),
3247                "RenderPass::set_index_buffer",
3248            );
3249        }
3250    }
3251
3252    fn set_vertex_buffer(
3253        &mut self,
3254        slot: u32,
3255        buffer: Option<&dispatch::DispatchBuffer>,
3256        offset: crate::BufferAddress,
3257        size: Option<crate::BufferSize>,
3258    ) {
3259        let buffer = buffer.map(|buffer| buffer.as_core().id);
3260
3261        if let Err(cause) =
3262            self.context
3263                .0
3264                .render_pass_set_vertex_buffer(&mut self.pass, slot, buffer, offset, size)
3265        {
3266            self.context.handle_error(
3267                &self.error_sink,
3268                cause,
3269                self.pass.label(),
3270                "RenderPass::set_vertex_buffer",
3271            );
3272        }
3273    }
3274
3275    fn set_immediates(&mut self, offset: u32, data: &[u8]) {
3276        if let Err(cause) = self
3277            .context
3278            .0
3279            .render_pass_set_immediates(&mut self.pass, offset, data)
3280        {
3281            self.context.handle_error(
3282                &self.error_sink,
3283                cause,
3284                self.pass.label(),
3285                "RenderPass::set_immediates",
3286            );
3287        }
3288    }
3289
3290    fn set_blend_constant(&mut self, color: crate::Color) {
3291        if let Err(cause) = self
3292            .context
3293            .0
3294            .render_pass_set_blend_constant(&mut self.pass, color)
3295        {
3296            self.context.handle_error(
3297                &self.error_sink,
3298                cause,
3299                self.pass.label(),
3300                "RenderPass::set_blend_constant",
3301            );
3302        }
3303    }
3304
3305    fn set_scissor_rect(&mut self, x: u32, y: u32, width: u32, height: u32) {
3306        if let Err(cause) =
3307            self.context
3308                .0
3309                .render_pass_set_scissor_rect(&mut self.pass, x, y, width, height)
3310        {
3311            self.context.handle_error(
3312                &self.error_sink,
3313                cause,
3314                self.pass.label(),
3315                "RenderPass::set_scissor_rect",
3316            );
3317        }
3318    }
3319
3320    fn set_viewport(
3321        &mut self,
3322        x: f32,
3323        y: f32,
3324        width: f32,
3325        height: f32,
3326        min_depth: f32,
3327        max_depth: f32,
3328    ) {
3329        if let Err(cause) = self.context.0.render_pass_set_viewport(
3330            &mut self.pass,
3331            x,
3332            y,
3333            width,
3334            height,
3335            min_depth,
3336            max_depth,
3337        ) {
3338            self.context.handle_error(
3339                &self.error_sink,
3340                cause,
3341                self.pass.label(),
3342                "RenderPass::set_viewport",
3343            );
3344        }
3345    }
3346
3347    fn set_stencil_reference(&mut self, reference: u32) {
3348        if let Err(cause) = self
3349            .context
3350            .0
3351            .render_pass_set_stencil_reference(&mut self.pass, reference)
3352        {
3353            self.context.handle_error(
3354                &self.error_sink,
3355                cause,
3356                self.pass.label(),
3357                "RenderPass::set_stencil_reference",
3358            );
3359        }
3360    }
3361
3362    fn draw(&mut self, vertices: Range<u32>, instances: Range<u32>) {
3363        if let Err(cause) = self.context.0.render_pass_draw(
3364            &mut self.pass,
3365            vertices.end - vertices.start,
3366            instances.end - instances.start,
3367            vertices.start,
3368            instances.start,
3369        ) {
3370            self.context.handle_error(
3371                &self.error_sink,
3372                cause,
3373                self.pass.label(),
3374                "RenderPass::draw",
3375            );
3376        }
3377    }
3378
3379    fn draw_indexed(&mut self, indices: Range<u32>, base_vertex: i32, instances: Range<u32>) {
3380        if let Err(cause) = self.context.0.render_pass_draw_indexed(
3381            &mut self.pass,
3382            indices.end - indices.start,
3383            instances.end - instances.start,
3384            indices.start,
3385            base_vertex,
3386            instances.start,
3387        ) {
3388            self.context.handle_error(
3389                &self.error_sink,
3390                cause,
3391                self.pass.label(),
3392                "RenderPass::draw_indexed",
3393            );
3394        }
3395    }
3396
3397    fn draw_mesh_tasks(&mut self, group_count_x: u32, group_count_y: u32, group_count_z: u32) {
3398        if let Err(cause) = self.context.0.render_pass_draw_mesh_tasks(
3399            &mut self.pass,
3400            group_count_x,
3401            group_count_y,
3402            group_count_z,
3403        ) {
3404            self.context.handle_error(
3405                &self.error_sink,
3406                cause,
3407                self.pass.label(),
3408                "RenderPass::draw_mesh_tasks",
3409            );
3410        }
3411    }
3412
3413    fn draw_indirect(
3414        &mut self,
3415        indirect_buffer: &dispatch::DispatchBuffer,
3416        indirect_offset: crate::BufferAddress,
3417    ) {
3418        let indirect_buffer = indirect_buffer.as_core();
3419
3420        if let Err(cause) = self.context.0.render_pass_draw_indirect(
3421            &mut self.pass,
3422            indirect_buffer.id,
3423            indirect_offset,
3424        ) {
3425            self.context.handle_error(
3426                &self.error_sink,
3427                cause,
3428                self.pass.label(),
3429                "RenderPass::draw_indirect",
3430            );
3431        }
3432    }
3433
3434    fn draw_indexed_indirect(
3435        &mut self,
3436        indirect_buffer: &dispatch::DispatchBuffer,
3437        indirect_offset: crate::BufferAddress,
3438    ) {
3439        let indirect_buffer = indirect_buffer.as_core();
3440
3441        if let Err(cause) = self.context.0.render_pass_draw_indexed_indirect(
3442            &mut self.pass,
3443            indirect_buffer.id,
3444            indirect_offset,
3445        ) {
3446            self.context.handle_error(
3447                &self.error_sink,
3448                cause,
3449                self.pass.label(),
3450                "RenderPass::draw_indexed_indirect",
3451            );
3452        }
3453    }
3454
3455    fn draw_mesh_tasks_indirect(
3456        &mut self,
3457        indirect_buffer: &dispatch::DispatchBuffer,
3458        indirect_offset: crate::BufferAddress,
3459    ) {
3460        let indirect_buffer = indirect_buffer.as_core();
3461
3462        if let Err(cause) = self.context.0.render_pass_draw_mesh_tasks_indirect(
3463            &mut self.pass,
3464            indirect_buffer.id,
3465            indirect_offset,
3466        ) {
3467            self.context.handle_error(
3468                &self.error_sink,
3469                cause,
3470                self.pass.label(),
3471                "RenderPass::draw_mesh_tasks_indirect",
3472            );
3473        }
3474    }
3475
3476    fn multi_draw_indirect(
3477        &mut self,
3478        indirect_buffer: &dispatch::DispatchBuffer,
3479        indirect_offset: crate::BufferAddress,
3480        count: u32,
3481    ) {
3482        let indirect_buffer = indirect_buffer.as_core();
3483
3484        if let Err(cause) = self.context.0.render_pass_multi_draw_indirect(
3485            &mut self.pass,
3486            indirect_buffer.id,
3487            indirect_offset,
3488            count,
3489        ) {
3490            self.context.handle_error(
3491                &self.error_sink,
3492                cause,
3493                self.pass.label(),
3494                "RenderPass::multi_draw_indirect",
3495            );
3496        }
3497    }
3498
3499    fn multi_draw_indexed_indirect(
3500        &mut self,
3501        indirect_buffer: &dispatch::DispatchBuffer,
3502        indirect_offset: crate::BufferAddress,
3503        count: u32,
3504    ) {
3505        let indirect_buffer = indirect_buffer.as_core();
3506
3507        if let Err(cause) = self.context.0.render_pass_multi_draw_indexed_indirect(
3508            &mut self.pass,
3509            indirect_buffer.id,
3510            indirect_offset,
3511            count,
3512        ) {
3513            self.context.handle_error(
3514                &self.error_sink,
3515                cause,
3516                self.pass.label(),
3517                "RenderPass::multi_draw_indexed_indirect",
3518            );
3519        }
3520    }
3521
3522    fn multi_draw_mesh_tasks_indirect(
3523        &mut self,
3524        indirect_buffer: &dispatch::DispatchBuffer,
3525        indirect_offset: crate::BufferAddress,
3526        count: u32,
3527    ) {
3528        let indirect_buffer = indirect_buffer.as_core();
3529
3530        if let Err(cause) = self.context.0.render_pass_multi_draw_mesh_tasks_indirect(
3531            &mut self.pass,
3532            indirect_buffer.id,
3533            indirect_offset,
3534            count,
3535        ) {
3536            self.context.handle_error(
3537                &self.error_sink,
3538                cause,
3539                self.pass.label(),
3540                "RenderPass::multi_draw_mesh_tasks_indirect",
3541            );
3542        }
3543    }
3544
3545    fn multi_draw_indirect_count(
3546        &mut self,
3547        indirect_buffer: &dispatch::DispatchBuffer,
3548        indirect_offset: crate::BufferAddress,
3549        count_buffer: &dispatch::DispatchBuffer,
3550        count_buffer_offset: crate::BufferAddress,
3551        max_count: u32,
3552    ) {
3553        let indirect_buffer = indirect_buffer.as_core();
3554        let count_buffer = count_buffer.as_core();
3555
3556        if let Err(cause) = self.context.0.render_pass_multi_draw_indirect_count(
3557            &mut self.pass,
3558            indirect_buffer.id,
3559            indirect_offset,
3560            count_buffer.id,
3561            count_buffer_offset,
3562            max_count,
3563        ) {
3564            self.context.handle_error(
3565                &self.error_sink,
3566                cause,
3567                self.pass.label(),
3568                "RenderPass::multi_draw_indirect_count",
3569            );
3570        }
3571    }
3572
3573    fn multi_draw_indexed_indirect_count(
3574        &mut self,
3575        indirect_buffer: &dispatch::DispatchBuffer,
3576        indirect_offset: crate::BufferAddress,
3577        count_buffer: &dispatch::DispatchBuffer,
3578        count_buffer_offset: crate::BufferAddress,
3579        max_count: u32,
3580    ) {
3581        let indirect_buffer = indirect_buffer.as_core();
3582        let count_buffer = count_buffer.as_core();
3583
3584        if let Err(cause) = self
3585            .context
3586            .0
3587            .render_pass_multi_draw_indexed_indirect_count(
3588                &mut self.pass,
3589                indirect_buffer.id,
3590                indirect_offset,
3591                count_buffer.id,
3592                count_buffer_offset,
3593                max_count,
3594            )
3595        {
3596            self.context.handle_error(
3597                &self.error_sink,
3598                cause,
3599                self.pass.label(),
3600                "RenderPass::multi_draw_indexed_indirect_count",
3601            );
3602        }
3603    }
3604
3605    fn multi_draw_mesh_tasks_indirect_count(
3606        &mut self,
3607        indirect_buffer: &dispatch::DispatchBuffer,
3608        indirect_offset: crate::BufferAddress,
3609        count_buffer: &dispatch::DispatchBuffer,
3610        count_buffer_offset: crate::BufferAddress,
3611        max_count: u32,
3612    ) {
3613        let indirect_buffer = indirect_buffer.as_core();
3614        let count_buffer = count_buffer.as_core();
3615
3616        if let Err(cause) = self
3617            .context
3618            .0
3619            .render_pass_multi_draw_mesh_tasks_indirect_count(
3620                &mut self.pass,
3621                indirect_buffer.id,
3622                indirect_offset,
3623                count_buffer.id,
3624                count_buffer_offset,
3625                max_count,
3626            )
3627        {
3628            self.context.handle_error(
3629                &self.error_sink,
3630                cause,
3631                self.pass.label(),
3632                "RenderPass::multi_draw_mesh_tasks_indirect_count",
3633            );
3634        }
3635    }
3636
3637    fn insert_debug_marker(&mut self, label: &str) {
3638        if let Err(cause) = self
3639            .context
3640            .0
3641            .render_pass_insert_debug_marker(&mut self.pass, label, 0)
3642        {
3643            self.context.handle_error(
3644                &self.error_sink,
3645                cause,
3646                self.pass.label(),
3647                "RenderPass::insert_debug_marker",
3648            );
3649        }
3650    }
3651
3652    fn push_debug_group(&mut self, group_label: &str) {
3653        if let Err(cause) =
3654            self.context
3655                .0
3656                .render_pass_push_debug_group(&mut self.pass, group_label, 0)
3657        {
3658            self.context.handle_error(
3659                &self.error_sink,
3660                cause,
3661                self.pass.label(),
3662                "RenderPass::push_debug_group",
3663            );
3664        }
3665    }
3666
3667    fn pop_debug_group(&mut self) {
3668        if let Err(cause) = self.context.0.render_pass_pop_debug_group(&mut self.pass) {
3669            self.context.handle_error(
3670                &self.error_sink,
3671                cause,
3672                self.pass.label(),
3673                "RenderPass::pop_debug_group",
3674            );
3675        }
3676    }
3677
3678    fn write_timestamp(&mut self, query_set: &dispatch::DispatchQuerySet, query_index: u32) {
3679        let query_set = query_set.as_core();
3680
3681        if let Err(cause) =
3682            self.context
3683                .0
3684                .render_pass_write_timestamp(&mut self.pass, query_set.id, query_index)
3685        {
3686            self.context.handle_error(
3687                &self.error_sink,
3688                cause,
3689                self.pass.label(),
3690                "RenderPass::write_timestamp",
3691            );
3692        }
3693    }
3694
3695    fn begin_occlusion_query(&mut self, query_index: u32) {
3696        if let Err(cause) = self
3697            .context
3698            .0
3699            .render_pass_begin_occlusion_query(&mut self.pass, query_index)
3700        {
3701            self.context.handle_error(
3702                &self.error_sink,
3703                cause,
3704                self.pass.label(),
3705                "RenderPass::begin_occlusion_query",
3706            );
3707        }
3708    }
3709
3710    fn end_occlusion_query(&mut self) {
3711        if let Err(cause) = self
3712            .context
3713            .0
3714            .render_pass_end_occlusion_query(&mut self.pass)
3715        {
3716            self.context.handle_error(
3717                &self.error_sink,
3718                cause,
3719                self.pass.label(),
3720                "RenderPass::end_occlusion_query",
3721            );
3722        }
3723    }
3724
3725    fn begin_pipeline_statistics_query(
3726        &mut self,
3727        query_set: &dispatch::DispatchQuerySet,
3728        query_index: u32,
3729    ) {
3730        let query_set = query_set.as_core();
3731
3732        if let Err(cause) = self.context.0.render_pass_begin_pipeline_statistics_query(
3733            &mut self.pass,
3734            query_set.id,
3735            query_index,
3736        ) {
3737            self.context.handle_error(
3738                &self.error_sink,
3739                cause,
3740                self.pass.label(),
3741                "RenderPass::begin_pipeline_statistics_query",
3742            );
3743        }
3744    }
3745
3746    fn end_pipeline_statistics_query(&mut self) {
3747        if let Err(cause) = self
3748            .context
3749            .0
3750            .render_pass_end_pipeline_statistics_query(&mut self.pass)
3751        {
3752            self.context.handle_error(
3753                &self.error_sink,
3754                cause,
3755                self.pass.label(),
3756                "RenderPass::end_pipeline_statistics_query",
3757            );
3758        }
3759    }
3760
3761    fn execute_bundles(
3762        &mut self,
3763        render_bundles: &mut dyn Iterator<Item = &dispatch::DispatchRenderBundle>,
3764    ) {
3765        let temp_render_bundles = render_bundles
3766            .map(|rb| rb.as_core().id)
3767            .collect::<SmallVec<[_; 4]>>();
3768        if let Err(cause) = self
3769            .context
3770            .0
3771            .render_pass_execute_bundles(&mut self.pass, &temp_render_bundles)
3772        {
3773            self.context.handle_error(
3774                &self.error_sink,
3775                cause,
3776                self.pass.label(),
3777                "RenderPass::execute_bundles",
3778            );
3779        }
3780    }
3781}
3782
3783impl Drop for CoreRenderPass {
3784    fn drop(&mut self) {
3785        if let Err(cause) = self.context.0.render_pass_end(&mut self.pass) {
3786            self.context.handle_error(
3787                &self.error_sink,
3788                cause,
3789                self.pass.label(),
3790                "RenderPass::end",
3791            );
3792        }
3793    }
3794}
3795
3796impl dispatch::RenderBundleEncoderInterface for CoreRenderBundleEncoder {
3797    fn set_pipeline(&mut self, pipeline: &dispatch::DispatchRenderPipeline) {
3798        let pipeline = pipeline.as_core();
3799
3800        self.context
3801            .0
3802            .render_bundle_encoder_set_pipeline(&mut self.encoder, pipeline.id)
3803            .expect("RenderBundleEncoder should not have ended")
3804    }
3805
3806    fn set_bind_group(
3807        &mut self,
3808        index: u32,
3809        bind_group: Option<&dispatch::DispatchBindGroup>,
3810        offsets: &[crate::DynamicOffset],
3811    ) {
3812        let bg = bind_group.map(|bg| bg.as_core().id);
3813
3814        self.context
3815            .0
3816            .render_bundle_encoder_set_bind_group(&mut self.encoder, index, bg, offsets)
3817            .expect("RenderBundleEncoder should not have ended");
3818    }
3819
3820    fn set_index_buffer(
3821        &mut self,
3822        buffer: &dispatch::DispatchBuffer,
3823        index_format: crate::IndexFormat,
3824        offset: crate::BufferAddress,
3825        size: Option<crate::BufferSize>,
3826    ) {
3827        let buffer = buffer.as_core();
3828
3829        self.context
3830            .0
3831            .render_bundle_encoder_set_index_buffer(
3832                &mut self.encoder,
3833                buffer.id,
3834                index_format,
3835                offset,
3836                size,
3837            )
3838            .expect("RenderBundleEncoder should not have ended");
3839    }
3840
3841    fn set_vertex_buffer(
3842        &mut self,
3843        slot: u32,
3844        buffer: Option<&dispatch::DispatchBuffer>,
3845        offset: crate::BufferAddress,
3846        size: Option<crate::BufferSize>,
3847    ) {
3848        let buffer = buffer.map(|buffer| buffer.as_core().id);
3849
3850        self.context
3851            .0
3852            .render_bundle_encoder_set_vertex_buffer(&mut self.encoder, slot, buffer, offset, size)
3853            .expect("RenderBundleEncoder should not have ended");
3854    }
3855
3856    fn set_immediates(&mut self, offset: u32, data: &[u8]) {
3857        if !data
3858            .len()
3859            .is_multiple_of(wgt::IMMEDIATE_DATA_ALIGNMENT as usize)
3860        {
3861            self.context.handle_error(
3862                &self.error_sink,
3863                wgc::binding_model::ImmediateUploadError::SizeUnaligned(data.len()),
3864                self.encoder.label(),
3865                "RenderBundleEncoder::set_immediates",
3866            );
3867            return;
3868        }
3869
3870        self.context
3871            .0
3872            .render_bundle_encoder_set_immediates(&mut self.encoder, offset, data)
3873            .expect("RenderBundleEncoder should not have ended");
3874    }
3875
3876    fn draw(&mut self, vertices: Range<u32>, instances: Range<u32>) {
3877        self.context
3878            .0
3879            .render_bundle_encoder_draw(
3880                &mut self.encoder,
3881                vertices.end - vertices.start,
3882                instances.end - instances.start,
3883                vertices.start,
3884                instances.start,
3885            )
3886            .expect("RenderBundleEncoder should not have ended");
3887    }
3888
3889    fn draw_indexed(&mut self, indices: Range<u32>, base_vertex: i32, instances: Range<u32>) {
3890        self.context
3891            .0
3892            .render_bundle_encoder_draw_indexed(
3893                &mut self.encoder,
3894                indices.end - indices.start,
3895                instances.end - instances.start,
3896                indices.start,
3897                base_vertex,
3898                instances.start,
3899            )
3900            .expect("RenderBundleEncoder should not have ended");
3901    }
3902
3903    fn draw_indirect(
3904        &mut self,
3905        indirect_buffer: &dispatch::DispatchBuffer,
3906        indirect_offset: crate::BufferAddress,
3907    ) {
3908        let indirect_buffer = indirect_buffer.as_core();
3909
3910        self.context
3911            .0
3912            .render_bundle_encoder_draw_indirect(
3913                &mut self.encoder,
3914                indirect_buffer.id,
3915                indirect_offset,
3916            )
3917            .expect("RenderBundleEncoder should not have ended");
3918    }
3919
3920    fn draw_indexed_indirect(
3921        &mut self,
3922        indirect_buffer: &dispatch::DispatchBuffer,
3923        indirect_offset: crate::BufferAddress,
3924    ) {
3925        let indirect_buffer = indirect_buffer.as_core();
3926
3927        self.context
3928            .0
3929            .render_bundle_encoder_draw_indexed_indirect(
3930                &mut self.encoder,
3931                indirect_buffer.id,
3932                indirect_offset,
3933            )
3934            .expect("RenderBundleEncoder should not have ended");
3935    }
3936
3937    fn finish(mut self, desc: &crate::RenderBundleDescriptor<'_>) -> dispatch::DispatchRenderBundle
3938    where
3939        Self: Sized,
3940    {
3941        let label = self.encoder.label().map(alloc::string::ToString::to_string);
3942        let (id, error) = self.context.0.render_bundle_encoder_finish(
3943            &mut self.encoder,
3944            &desc.map_label(|l| l.map(Borrowed)),
3945            None,
3946        );
3947        if let Some(err) = error {
3948            self.context.handle_error(
3949                &self.error_sink,
3950                err,
3951                label.as_deref(),
3952                "RenderBundleEncoder::finish",
3953            );
3954        }
3955        CoreRenderBundle {
3956            context: self.context.clone(),
3957            id,
3958        }
3959        .into()
3960    }
3961
3962    #[cfg(custom)]
3963    fn finish_boxed(
3964        self: Box<Self>,
3965        desc: &crate::RenderBundleDescriptor<'_>,
3966    ) -> dispatch::DispatchRenderBundle {
3967        (*self).finish(desc)
3968    }
3969}
3970
3971impl dispatch::RenderBundleInterface for CoreRenderBundle {}
3972
3973impl Drop for CoreRenderBundle {
3974    fn drop(&mut self) {
3975        self.context.0.render_bundle_drop(self.id)
3976    }
3977}
3978
3979impl dispatch::SurfaceInterface for CoreSurface {
3980    fn get_capabilities(&self, adapter: &dispatch::DispatchAdapter) -> wgt::SurfaceCapabilities {
3981        let adapter = adapter.as_core();
3982
3983        self.context
3984            .0
3985            .surface_get_capabilities(self.id, adapter.id)
3986            .unwrap_or_default()
3987    }
3988
3989    fn display_hdr_info(&self, adapter: &dispatch::DispatchAdapter) -> wgt::DisplayHdrInfo {
3990        let adapter = adapter.as_core();
3991
3992        self.context.0.surface_display_hdr_info(self.id, adapter.id)
3993    }
3994
3995    fn configure(&self, device: &dispatch::DispatchDevice, config: &crate::SurfaceConfiguration) {
3996        let device = device.as_core();
3997
3998        let error = self.context.0.surface_configure(self.id, device.id, config);
3999        if let Some(e) = error {
4000            self.context
4001                .handle_error_nolabel(&device.error_sink, e, "Surface::configure");
4002        } else {
4003            *self.configured_device.lock() = Some(device.id);
4004            *self.error_sink.lock() = Some(device.error_sink.clone());
4005        }
4006    }
4007
4008    fn get_current_texture(
4009        &self,
4010    ) -> (
4011        Option<dispatch::DispatchTexture>,
4012        crate::SurfaceStatus,
4013        dispatch::DispatchSurfaceOutputDetail,
4014    ) {
4015        let error_sink = if let Some(error_sink) = self.error_sink.lock().as_ref() {
4016            error_sink.clone()
4017        } else {
4018            Arc::new(Mutex::new(ErrorSinkRaw::new()))
4019        };
4020
4021        let output_detail = CoreSurfaceOutputDetail {
4022            context: self.context.clone(),
4023            surface_id: self.id,
4024            error_sink: error_sink.clone(),
4025        }
4026        .into();
4027
4028        match self.context.0.surface_get_current_texture(self.id, None) {
4029            Ok(wgc::present::SurfaceOutput {
4030                status,
4031                texture: texture_id,
4032            }) => {
4033                let data = texture_id
4034                    .map(|id| CoreTexture {
4035                        context: self.context.clone(),
4036                        id,
4037                        error_sink,
4038                    })
4039                    .map(Into::into);
4040
4041                (data, status, output_detail)
4042            }
4043            Err(err) => {
4044                let error_sink = self.error_sink.lock();
4045                match error_sink.as_ref() {
4046                    Some(error_sink) => {
4047                        self.context.handle_error_nolabel(
4048                            error_sink,
4049                            err,
4050                            "Surface::get_current_texture_view",
4051                        );
4052                        (None, crate::SurfaceStatus::Validation, output_detail)
4053                    }
4054                    None => self
4055                        .context
4056                        .handle_error_fatal(err, "Surface::get_current_texture_view"),
4057                }
4058            }
4059        }
4060    }
4061}
4062
4063impl Drop for CoreSurface {
4064    fn drop(&mut self) {
4065        self.context.0.surface_drop(self.id)
4066    }
4067}
4068
4069impl dispatch::SurfaceOutputDetailInterface for CoreSurfaceOutputDetail {
4070    fn texture_discard(&self) {
4071        match self.context.0.surface_texture_discard(self.surface_id) {
4072            Ok(_status) => (),
4073            Err(err) => {
4074                self.context
4075                    .handle_error_nolabel(&self.error_sink, err, "Surface::discard_texture")
4076            }
4077        }
4078    }
4079
4080    fn texture_release(&self) {
4081        match self.context.0.surface_texture_release(self.surface_id) {
4082            Ok(_status) => (),
4083            Err(err) => {
4084                self.context
4085                    .handle_error_nolabel(&self.error_sink, err, "Surface::release_texture")
4086            }
4087        }
4088    }
4089}
4090impl Drop for CoreSurfaceOutputDetail {
4091    fn drop(&mut self) {
4092        // Discard gets called by the api struct
4093
4094        // no-op
4095    }
4096}
4097
4098impl dispatch::QueueWriteBufferInterface for CoreQueueWriteBuffer {
4099    #[inline]
4100    fn len(&self) -> usize {
4101        self.mapping.len()
4102    }
4103
4104    #[inline]
4105    unsafe fn write_slice(&mut self) -> WriteOnly<'_, [u8]> {
4106        unsafe { self.mapping.write_slice() }
4107    }
4108}
4109impl Drop for CoreQueueWriteBuffer {
4110    fn drop(&mut self) {
4111        // The api struct calls queue.write_staging_buffer
4112
4113        // no-op
4114    }
4115}
4116
4117impl dispatch::BufferMappedRangeInterface for CoreBufferMappedRange {
4118    #[inline]
4119    fn len(&self) -> usize {
4120        self.size
4121    }
4122
4123    #[inline]
4124    unsafe fn read_slice(&self) -> &[u8] {
4125        unsafe { slice::from_raw_parts(self.ptr.as_ptr(), self.size) }
4126    }
4127
4128    #[inline]
4129    unsafe fn write_slice(&mut self) -> WriteOnly<'_, [u8]> {
4130        unsafe { WriteOnly::new(NonNull::slice_from_raw_parts(self.ptr, self.size)) }
4131    }
4132
4133    #[cfg(webgpu)]
4134    fn as_uint8array(&self) -> &js_sys::Uint8Array {
4135        panic!("Only available on WebGPU")
4136    }
4137}