1#[cfg(feature = "trace")]
2use crate::device::trace;
3use crate::{
4 api_log,
5 binding_model::{
6 self, BindGroupEntry, BindingResource, BufferBinding, ResolvedBindGroupDescriptor,
7 ResolvedBindGroupEntry, ResolvedBindingResource, ResolvedBufferBinding,
8 },
9 command::{self, CommandBuffer},
10 conv,
11 device::{bgl, life::WaitIdleError, DeviceError, DeviceLostClosure},
12 global::Global,
13 hal_api::HalApi,
14 id::{self, AdapterId, DeviceId, QueueId, SurfaceId},
15 instance::{self, Adapter, Surface},
16 pipeline::{
17 self, ResolvedComputePipelineDescriptor, ResolvedFragmentState,
18 ResolvedProgrammableStageDescriptor, ResolvedRenderPipelineDescriptor, ResolvedVertexState,
19 },
20 present,
21 resource::{
22 self, BufferAccessError, BufferAccessResult, BufferMapOperation, CreateBufferError,
23 Fallible,
24 },
25 storage::Storage,
26 Label, LabelHelpers,
27};
28
29use wgt::{BufferAddress, TextureFormat};
30
31use std::{
32 borrow::Cow,
33 ptr::NonNull,
34 sync::{atomic::Ordering, Arc},
35};
36
37use super::{ImplicitPipelineIds, UserClosures};
38
39impl Global {
40 pub fn adapter_is_surface_supported(
41 &self,
42 adapter_id: AdapterId,
43 surface_id: SurfaceId,
44 ) -> bool {
45 let surface = self.surfaces.get(surface_id);
46 let adapter = self.hub.adapters.get(adapter_id);
47 adapter.is_surface_supported(&surface)
48 }
49
50 pub fn surface_get_capabilities(
51 &self,
52 surface_id: SurfaceId,
53 adapter_id: AdapterId,
54 ) -> Result<wgt::SurfaceCapabilities, instance::GetSurfaceSupportError> {
55 profiling::scope!("Surface::get_capabilities");
56 self.fetch_adapter_and_surface::<_, _>(surface_id, adapter_id, |adapter, surface| {
57 let mut hal_caps = surface.get_capabilities(adapter)?;
58
59 hal_caps.formats.sort_by_key(|f| !f.is_srgb());
60
61 let usages = conv::map_texture_usage_from_hal(hal_caps.usage);
62
63 Ok(wgt::SurfaceCapabilities {
64 formats: hal_caps.formats,
65 present_modes: hal_caps.present_modes,
66 alpha_modes: hal_caps.composite_alpha_modes,
67 usages,
68 })
69 })
70 }
71
72 fn fetch_adapter_and_surface<F: FnOnce(&Adapter, &Surface) -> B, B>(
73 &self,
74 surface_id: SurfaceId,
75 adapter_id: AdapterId,
76 get_supported_callback: F,
77 ) -> B {
78 let surface = self.surfaces.get(surface_id);
79 let adapter = self.hub.adapters.get(adapter_id);
80 get_supported_callback(&adapter, &surface)
81 }
82
83 pub fn device_features(&self, device_id: DeviceId) -> wgt::Features {
84 let device = self.hub.devices.get(device_id);
85 device.features
86 }
87
88 pub fn device_limits(&self, device_id: DeviceId) -> wgt::Limits {
89 let device = self.hub.devices.get(device_id);
90 device.limits.clone()
91 }
92
93 pub fn device_downlevel_properties(&self, device_id: DeviceId) -> wgt::DownlevelCapabilities {
94 let device = self.hub.devices.get(device_id);
95 device.downlevel.clone()
96 }
97
98 pub fn device_create_buffer(
99 &self,
100 device_id: DeviceId,
101 desc: &resource::BufferDescriptor,
102 id_in: Option<id::BufferId>,
103 ) -> (id::BufferId, Option<CreateBufferError>) {
104 profiling::scope!("Device::create_buffer");
105
106 let hub = &self.hub;
107 let fid = hub.buffers.prepare(id_in);
108
109 let error = 'error: {
110 let device = self.hub.devices.get(device_id);
111
112 #[cfg(feature = "trace")]
113 if let Some(ref mut trace) = *device.trace.lock() {
114 let mut desc = desc.clone();
115 let mapped_at_creation = std::mem::replace(&mut desc.mapped_at_creation, false);
116 if mapped_at_creation && !desc.usage.contains(wgt::BufferUsages::MAP_WRITE) {
117 desc.usage |= wgt::BufferUsages::COPY_DST;
118 }
119 trace.add(trace::Action::CreateBuffer(fid.id(), desc));
120 }
121
122 let buffer = match device.create_buffer(desc) {
123 Ok(buffer) => buffer,
124 Err(e) => {
125 break 'error e;
126 }
127 };
128
129 let id = fid.assign(Fallible::Valid(buffer));
130
131 api_log!(
132 "Device::create_buffer({:?}{}) -> {id:?}",
133 desc.label.as_deref().unwrap_or(""),
134 if desc.mapped_at_creation {
135 ", mapped_at_creation"
136 } else {
137 ""
138 }
139 );
140
141 return (id, None);
142 };
143
144 let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
145 (id, Some(error))
146 }
147
148 pub fn create_buffer_error(
177 &self,
178 id_in: Option<id::BufferId>,
179 desc: &resource::BufferDescriptor,
180 ) {
181 let fid = self.hub.buffers.prepare(id_in);
182 fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
183 }
184
185 pub fn create_render_bundle_error(
186 &self,
187 id_in: Option<id::RenderBundleId>,
188 desc: &command::RenderBundleDescriptor,
189 ) {
190 let fid = self.hub.render_bundles.prepare(id_in);
191 fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
192 }
193
194 pub fn create_texture_error(
198 &self,
199 id_in: Option<id::TextureId>,
200 desc: &resource::TextureDescriptor,
201 ) {
202 let fid = self.hub.textures.prepare(id_in);
203 fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
204 }
205
206 #[cfg(feature = "replay")]
207 pub fn device_set_buffer_data(
208 &self,
209 buffer_id: id::BufferId,
210 offset: BufferAddress,
211 data: &[u8],
212 ) -> BufferAccessResult {
213 let hub = &self.hub;
214
215 let buffer = hub.buffers.get(buffer_id).get()?;
216
217 let device = &buffer.device;
218
219 device.check_is_valid()?;
220 buffer.check_usage(wgt::BufferUsages::MAP_WRITE)?;
221
222 let last_submission = device.get_queue().and_then(|queue| {
223 queue
224 .lock_life()
225 .get_buffer_latest_submission_index(&buffer)
226 });
227
228 if let Some(last_submission) = last_submission {
229 device.wait_for_submit(last_submission)?;
230 }
231
232 let snatch_guard = device.snatchable_lock.read();
233 let raw_buf = buffer.try_raw(&snatch_guard)?;
234
235 let mapping = unsafe {
236 device
237 .raw()
238 .map_buffer(raw_buf, offset..offset + data.len() as u64)
239 }
240 .map_err(|e| device.handle_hal_error(e))?;
241
242 unsafe { std::ptr::copy_nonoverlapping(data.as_ptr(), mapping.ptr.as_ptr(), data.len()) };
243
244 if !mapping.is_coherent {
245 #[allow(clippy::single_range_in_vec_init)]
246 unsafe {
247 device
248 .raw()
249 .flush_mapped_ranges(raw_buf, &[offset..offset + data.len() as u64])
250 };
251 }
252
253 unsafe { device.raw().unmap_buffer(raw_buf) };
254
255 Ok(())
256 }
257
258 pub fn buffer_destroy(&self, buffer_id: id::BufferId) -> Result<(), resource::DestroyError> {
259 profiling::scope!("Buffer::destroy");
260 api_log!("Buffer::destroy {buffer_id:?}");
261
262 let hub = &self.hub;
263
264 let buffer = hub.buffers.get(buffer_id).get()?;
265
266 #[cfg(feature = "trace")]
267 if let Some(trace) = buffer.device.trace.lock().as_mut() {
268 trace.add(trace::Action::FreeBuffer(buffer_id));
269 }
270
271 let _ = buffer.unmap(
272 #[cfg(feature = "trace")]
273 buffer_id,
274 );
275
276 buffer.destroy()
277 }
278
279 pub fn buffer_drop(&self, buffer_id: id::BufferId) {
280 profiling::scope!("Buffer::drop");
281 api_log!("Buffer::drop {buffer_id:?}");
282
283 let hub = &self.hub;
284
285 let buffer = match hub.buffers.remove(buffer_id).get() {
286 Ok(buffer) => buffer,
287 Err(_) => {
288 return;
289 }
290 };
291
292 #[cfg(feature = "trace")]
293 if let Some(t) = buffer.device.trace.lock().as_mut() {
294 t.add(trace::Action::DestroyBuffer(buffer_id));
295 }
296
297 let _ = buffer.unmap(
298 #[cfg(feature = "trace")]
299 buffer_id,
300 );
301 }
302
303 pub fn device_create_texture(
304 &self,
305 device_id: DeviceId,
306 desc: &resource::TextureDescriptor,
307 id_in: Option<id::TextureId>,
308 ) -> (id::TextureId, Option<resource::CreateTextureError>) {
309 profiling::scope!("Device::create_texture");
310
311 let hub = &self.hub;
312
313 let fid = hub.textures.prepare(id_in);
314
315 let error = 'error: {
316 let device = self.hub.devices.get(device_id);
317
318 #[cfg(feature = "trace")]
319 if let Some(ref mut trace) = *device.trace.lock() {
320 trace.add(trace::Action::CreateTexture(fid.id(), desc.clone()));
321 }
322
323 let texture = match device.create_texture(desc) {
324 Ok(texture) => texture,
325 Err(error) => break 'error error,
326 };
327
328 let id = fid.assign(Fallible::Valid(texture));
329 api_log!("Device::create_texture({desc:?}) -> {id:?}");
330
331 return (id, None);
332 };
333
334 let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
335 (id, Some(error))
336 }
337
338 pub unsafe fn create_texture_from_hal(
344 &self,
345 hal_texture: Box<dyn hal::DynTexture>,
346 device_id: DeviceId,
347 desc: &resource::TextureDescriptor,
348 id_in: Option<id::TextureId>,
349 ) -> (id::TextureId, Option<resource::CreateTextureError>) {
350 profiling::scope!("Device::create_texture_from_hal");
351
352 let hub = &self.hub;
353
354 let fid = hub.textures.prepare(id_in);
355
356 let error = 'error: {
357 let device = self.hub.devices.get(device_id);
358
359 #[cfg(feature = "trace")]
362 if let Some(ref mut trace) = *device.trace.lock() {
363 trace.add(trace::Action::CreateTexture(fid.id(), desc.clone()));
364 }
365
366 let texture = match device.create_texture_from_hal(hal_texture, desc) {
367 Ok(texture) => texture,
368 Err(error) => break 'error error,
369 };
370
371 let id = fid.assign(Fallible::Valid(texture));
372 api_log!("Device::create_texture({desc:?}) -> {id:?}");
373
374 return (id, None);
375 };
376
377 let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
378 (id, Some(error))
379 }
380
381 pub unsafe fn create_buffer_from_hal<A: HalApi>(
387 &self,
388 hal_buffer: A::Buffer,
389 device_id: DeviceId,
390 desc: &resource::BufferDescriptor,
391 id_in: Option<id::BufferId>,
392 ) -> (id::BufferId, Option<CreateBufferError>) {
393 profiling::scope!("Device::create_buffer");
394
395 let hub = &self.hub;
396 let fid = hub.buffers.prepare(id_in);
397
398 let device = self.hub.devices.get(device_id);
399
400 #[cfg(feature = "trace")]
403 if let Some(trace) = device.trace.lock().as_mut() {
404 trace.add(trace::Action::CreateBuffer(fid.id(), desc.clone()));
405 }
406
407 let (buffer, err) = device.create_buffer_from_hal(Box::new(hal_buffer), desc);
408
409 let id = fid.assign(buffer);
410 api_log!("Device::create_buffer -> {id:?}");
411
412 (id, err)
413 }
414
415 pub fn texture_destroy(&self, texture_id: id::TextureId) -> Result<(), resource::DestroyError> {
416 profiling::scope!("Texture::destroy");
417 api_log!("Texture::destroy {texture_id:?}");
418
419 let hub = &self.hub;
420
421 let texture = hub.textures.get(texture_id).get()?;
422
423 #[cfg(feature = "trace")]
424 if let Some(trace) = texture.device.trace.lock().as_mut() {
425 trace.add(trace::Action::FreeTexture(texture_id));
426 }
427
428 texture.destroy()
429 }
430
431 pub fn texture_drop(&self, texture_id: id::TextureId) {
432 profiling::scope!("Texture::drop");
433 api_log!("Texture::drop {texture_id:?}");
434
435 let hub = &self.hub;
436
437 let _texture = hub.textures.remove(texture_id);
438 #[cfg(feature = "trace")]
439 if let Ok(texture) = _texture.get() {
440 if let Some(t) = texture.device.trace.lock().as_mut() {
441 t.add(trace::Action::DestroyTexture(texture_id));
442 }
443 }
444 }
445
446 pub fn texture_create_view(
447 &self,
448 texture_id: id::TextureId,
449 desc: &resource::TextureViewDescriptor,
450 id_in: Option<id::TextureViewId>,
451 ) -> (id::TextureViewId, Option<resource::CreateTextureViewError>) {
452 profiling::scope!("Texture::create_view");
453
454 let hub = &self.hub;
455
456 let fid = hub.texture_views.prepare(id_in);
457
458 let error = 'error: {
459 let texture = match hub.textures.get(texture_id).get() {
460 Ok(texture) => texture,
461 Err(e) => break 'error e.into(),
462 };
463 let device = &texture.device;
464
465 #[cfg(feature = "trace")]
466 if let Some(ref mut trace) = *device.trace.lock() {
467 trace.add(trace::Action::CreateTextureView {
468 id: fid.id(),
469 parent_id: texture_id,
470 desc: desc.clone(),
471 });
472 }
473
474 let view = match device.create_texture_view(&texture, desc) {
475 Ok(view) => view,
476 Err(e) => break 'error e,
477 };
478
479 let id = fid.assign(Fallible::Valid(view));
480
481 api_log!("Texture::create_view({texture_id:?}) -> {id:?}");
482
483 return (id, None);
484 };
485
486 let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
487 (id, Some(error))
488 }
489
490 pub fn texture_view_drop(
491 &self,
492 texture_view_id: id::TextureViewId,
493 ) -> Result<(), resource::TextureViewDestroyError> {
494 profiling::scope!("TextureView::drop");
495 api_log!("TextureView::drop {texture_view_id:?}");
496
497 let hub = &self.hub;
498
499 let _view = hub.texture_views.remove(texture_view_id);
500
501 #[cfg(feature = "trace")]
502 if let Ok(view) = _view.get() {
503 if let Some(t) = view.device.trace.lock().as_mut() {
504 t.add(trace::Action::DestroyTextureView(texture_view_id));
505 }
506 }
507 Ok(())
508 }
509
510 pub fn device_create_sampler(
511 &self,
512 device_id: DeviceId,
513 desc: &resource::SamplerDescriptor,
514 id_in: Option<id::SamplerId>,
515 ) -> (id::SamplerId, Option<resource::CreateSamplerError>) {
516 profiling::scope!("Device::create_sampler");
517
518 let hub = &self.hub;
519 let fid = hub.samplers.prepare(id_in);
520
521 let error = 'error: {
522 let device = self.hub.devices.get(device_id);
523
524 #[cfg(feature = "trace")]
525 if let Some(ref mut trace) = *device.trace.lock() {
526 trace.add(trace::Action::CreateSampler(fid.id(), desc.clone()));
527 }
528
529 let sampler = match device.create_sampler(desc) {
530 Ok(sampler) => sampler,
531 Err(e) => break 'error e,
532 };
533
534 let id = fid.assign(Fallible::Valid(sampler));
535 api_log!("Device::create_sampler -> {id:?}");
536
537 return (id, None);
538 };
539
540 let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
541 (id, Some(error))
542 }
543
544 pub fn sampler_drop(&self, sampler_id: id::SamplerId) {
545 profiling::scope!("Sampler::drop");
546 api_log!("Sampler::drop {sampler_id:?}");
547
548 let hub = &self.hub;
549
550 let _sampler = hub.samplers.remove(sampler_id);
551
552 #[cfg(feature = "trace")]
553 if let Ok(sampler) = _sampler.get() {
554 if let Some(t) = sampler.device.trace.lock().as_mut() {
555 t.add(trace::Action::DestroySampler(sampler_id));
556 }
557 }
558 }
559
560 pub fn device_create_bind_group_layout(
561 &self,
562 device_id: DeviceId,
563 desc: &binding_model::BindGroupLayoutDescriptor,
564 id_in: Option<id::BindGroupLayoutId>,
565 ) -> (
566 id::BindGroupLayoutId,
567 Option<binding_model::CreateBindGroupLayoutError>,
568 ) {
569 profiling::scope!("Device::create_bind_group_layout");
570
571 let hub = &self.hub;
572 let fid = hub.bind_group_layouts.prepare(id_in);
573
574 let error = 'error: {
575 let device = self.hub.devices.get(device_id);
576
577 #[cfg(feature = "trace")]
578 if let Some(ref mut trace) = *device.trace.lock() {
579 trace.add(trace::Action::CreateBindGroupLayout(fid.id(), desc.clone()));
580 }
581
582 if let Err(e) = device.check_is_valid() {
584 break 'error e.into();
585 }
586
587 let entry_map = match bgl::EntryMap::from_entries(&device.limits, &desc.entries) {
588 Ok(map) => map,
589 Err(e) => break 'error e,
590 };
591
592 let bgl_result = device.bgl_pool.get_or_init(entry_map, |entry_map| {
593 let bgl =
594 device.create_bind_group_layout(&desc.label, entry_map, bgl::Origin::Pool)?;
595 bgl.exclusive_pipeline
596 .set(binding_model::ExclusivePipeline::None)
597 .unwrap();
598 Ok(bgl)
599 });
600
601 let layout = match bgl_result {
602 Ok(layout) => layout,
603 Err(e) => break 'error e,
604 };
605
606 let id = fid.assign(Fallible::Valid(layout.clone()));
607
608 api_log!("Device::create_bind_group_layout -> {id:?}");
609 return (id, None);
610 };
611
612 let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
613 (id, Some(error))
614 }
615
616 pub fn bind_group_layout_drop(&self, bind_group_layout_id: id::BindGroupLayoutId) {
617 profiling::scope!("BindGroupLayout::drop");
618 api_log!("BindGroupLayout::drop {bind_group_layout_id:?}");
619
620 let hub = &self.hub;
621
622 let _layout = hub.bind_group_layouts.remove(bind_group_layout_id);
623
624 #[cfg(feature = "trace")]
625 if let Ok(layout) = _layout.get() {
626 if let Some(t) = layout.device.trace.lock().as_mut() {
627 t.add(trace::Action::DestroyBindGroupLayout(bind_group_layout_id));
628 }
629 }
630 }
631
632 pub fn device_create_pipeline_layout(
633 &self,
634 device_id: DeviceId,
635 desc: &binding_model::PipelineLayoutDescriptor,
636 id_in: Option<id::PipelineLayoutId>,
637 ) -> (
638 id::PipelineLayoutId,
639 Option<binding_model::CreatePipelineLayoutError>,
640 ) {
641 profiling::scope!("Device::create_pipeline_layout");
642
643 let hub = &self.hub;
644 let fid = hub.pipeline_layouts.prepare(id_in);
645
646 let error = 'error: {
647 let device = self.hub.devices.get(device_id);
648
649 #[cfg(feature = "trace")]
650 if let Some(ref mut trace) = *device.trace.lock() {
651 trace.add(trace::Action::CreatePipelineLayout(fid.id(), desc.clone()));
652 }
653
654 let bind_group_layouts = {
655 let bind_group_layouts_guard = hub.bind_group_layouts.read();
656 desc.bind_group_layouts
657 .iter()
658 .map(|bgl_id| bind_group_layouts_guard.get(*bgl_id).get())
659 .collect::<Result<Vec<_>, _>>()
660 };
661
662 let bind_group_layouts = match bind_group_layouts {
663 Ok(bind_group_layouts) => bind_group_layouts,
664 Err(e) => break 'error e.into(),
665 };
666
667 let desc = binding_model::ResolvedPipelineLayoutDescriptor {
668 label: desc.label.clone(),
669 bind_group_layouts: Cow::Owned(bind_group_layouts),
670 push_constant_ranges: desc.push_constant_ranges.clone(),
671 };
672
673 let layout = match device.create_pipeline_layout(&desc) {
674 Ok(layout) => layout,
675 Err(e) => break 'error e,
676 };
677
678 let id = fid.assign(Fallible::Valid(layout));
679 api_log!("Device::create_pipeline_layout -> {id:?}");
680 return (id, None);
681 };
682
683 let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
684 (id, Some(error))
685 }
686
687 pub fn pipeline_layout_drop(&self, pipeline_layout_id: id::PipelineLayoutId) {
688 profiling::scope!("PipelineLayout::drop");
689 api_log!("PipelineLayout::drop {pipeline_layout_id:?}");
690
691 let hub = &self.hub;
692
693 let _layout = hub.pipeline_layouts.remove(pipeline_layout_id);
694
695 #[cfg(feature = "trace")]
696 if let Ok(layout) = _layout.get() {
697 if let Some(t) = layout.device.trace.lock().as_mut() {
698 t.add(trace::Action::DestroyPipelineLayout(pipeline_layout_id));
699 }
700 }
701 }
702
703 pub fn device_create_bind_group(
704 &self,
705 device_id: DeviceId,
706 desc: &binding_model::BindGroupDescriptor,
707 id_in: Option<id::BindGroupId>,
708 ) -> (id::BindGroupId, Option<binding_model::CreateBindGroupError>) {
709 profiling::scope!("Device::create_bind_group");
710
711 let hub = &self.hub;
712 let fid = hub.bind_groups.prepare(id_in);
713
714 let error = 'error: {
715 let device = self.hub.devices.get(device_id);
716
717 #[cfg(feature = "trace")]
718 if let Some(ref mut trace) = *device.trace.lock() {
719 trace.add(trace::Action::CreateBindGroup(fid.id(), desc.clone()));
720 }
721
722 let layout = match hub.bind_group_layouts.get(desc.layout).get() {
723 Ok(layout) => layout,
724 Err(e) => break 'error e.into(),
725 };
726
727 fn resolve_entry<'a>(
728 e: &BindGroupEntry<'a>,
729 buffer_storage: &Storage<Fallible<resource::Buffer>>,
730 sampler_storage: &Storage<Fallible<resource::Sampler>>,
731 texture_view_storage: &Storage<Fallible<resource::TextureView>>,
732 tlas_storage: &Storage<Fallible<resource::Tlas>>,
733 ) -> Result<ResolvedBindGroupEntry<'a>, binding_model::CreateBindGroupError>
734 {
735 let resolve_buffer = |bb: &BufferBinding| {
736 buffer_storage
737 .get(bb.buffer_id)
738 .get()
739 .map(|buffer| ResolvedBufferBinding {
740 buffer,
741 offset: bb.offset,
742 size: bb.size,
743 })
744 .map_err(binding_model::CreateBindGroupError::from)
745 };
746 let resolve_sampler = |id: &id::SamplerId| {
747 sampler_storage
748 .get(*id)
749 .get()
750 .map_err(binding_model::CreateBindGroupError::from)
751 };
752 let resolve_view = |id: &id::TextureViewId| {
753 texture_view_storage
754 .get(*id)
755 .get()
756 .map_err(binding_model::CreateBindGroupError::from)
757 };
758 let resolve_tlas = |id: &id::TlasId| {
759 tlas_storage
760 .get(*id)
761 .get()
762 .map_err(binding_model::CreateBindGroupError::from)
763 };
764 let resource = match e.resource {
765 BindingResource::Buffer(ref buffer) => {
766 ResolvedBindingResource::Buffer(resolve_buffer(buffer)?)
767 }
768 BindingResource::BufferArray(ref buffers) => {
769 let buffers = buffers
770 .iter()
771 .map(resolve_buffer)
772 .collect::<Result<Vec<_>, _>>()?;
773 ResolvedBindingResource::BufferArray(Cow::Owned(buffers))
774 }
775 BindingResource::Sampler(ref sampler) => {
776 ResolvedBindingResource::Sampler(resolve_sampler(sampler)?)
777 }
778 BindingResource::SamplerArray(ref samplers) => {
779 let samplers = samplers
780 .iter()
781 .map(resolve_sampler)
782 .collect::<Result<Vec<_>, _>>()?;
783 ResolvedBindingResource::SamplerArray(Cow::Owned(samplers))
784 }
785 BindingResource::TextureView(ref view) => {
786 ResolvedBindingResource::TextureView(resolve_view(view)?)
787 }
788 BindingResource::TextureViewArray(ref views) => {
789 let views = views
790 .iter()
791 .map(resolve_view)
792 .collect::<Result<Vec<_>, _>>()?;
793 ResolvedBindingResource::TextureViewArray(Cow::Owned(views))
794 }
795 BindingResource::AccelerationStructure(ref tlas) => {
796 ResolvedBindingResource::AccelerationStructure(resolve_tlas(tlas)?)
797 }
798 };
799 Ok(ResolvedBindGroupEntry {
800 binding: e.binding,
801 resource,
802 })
803 }
804
805 let entries = {
806 let buffer_guard = hub.buffers.read();
807 let texture_view_guard = hub.texture_views.read();
808 let sampler_guard = hub.samplers.read();
809 let tlas_guard = hub.tlas_s.read();
810 desc.entries
811 .iter()
812 .map(|e| {
813 resolve_entry(
814 e,
815 &buffer_guard,
816 &sampler_guard,
817 &texture_view_guard,
818 &tlas_guard,
819 )
820 })
821 .collect::<Result<Vec<_>, _>>()
822 };
823 let entries = match entries {
824 Ok(entries) => Cow::Owned(entries),
825 Err(e) => break 'error e,
826 };
827
828 let desc = ResolvedBindGroupDescriptor {
829 label: desc.label.clone(),
830 layout,
831 entries,
832 };
833
834 let bind_group = match device.create_bind_group(desc) {
835 Ok(bind_group) => bind_group,
836 Err(e) => break 'error e,
837 };
838
839 let id = fid.assign(Fallible::Valid(bind_group));
840
841 api_log!("Device::create_bind_group -> {id:?}");
842
843 return (id, None);
844 };
845
846 let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
847 (id, Some(error))
848 }
849
850 pub fn bind_group_drop(&self, bind_group_id: id::BindGroupId) {
851 profiling::scope!("BindGroup::drop");
852 api_log!("BindGroup::drop {bind_group_id:?}");
853
854 let hub = &self.hub;
855
856 let _bind_group = hub.bind_groups.remove(bind_group_id);
857
858 #[cfg(feature = "trace")]
859 if let Ok(_bind_group) = _bind_group.get() {
860 if let Some(t) = _bind_group.device.trace.lock().as_mut() {
861 t.add(trace::Action::DestroyBindGroup(bind_group_id));
862 }
863 }
864 }
865
866 pub fn device_create_shader_module(
881 &self,
882 device_id: DeviceId,
883 desc: &pipeline::ShaderModuleDescriptor,
884 source: pipeline::ShaderModuleSource,
885 id_in: Option<id::ShaderModuleId>,
886 ) -> (
887 id::ShaderModuleId,
888 Option<pipeline::CreateShaderModuleError>,
889 ) {
890 profiling::scope!("Device::create_shader_module");
891
892 let hub = &self.hub;
893 let fid = hub.shader_modules.prepare(id_in);
894
895 let error = 'error: {
896 let device = self.hub.devices.get(device_id);
897
898 #[cfg(feature = "trace")]
899 if let Some(ref mut trace) = *device.trace.lock() {
900 let data = match source {
901 #[cfg(feature = "wgsl")]
902 pipeline::ShaderModuleSource::Wgsl(ref code) => {
903 trace.make_binary("wgsl", code.as_bytes())
904 }
905 #[cfg(feature = "glsl")]
906 pipeline::ShaderModuleSource::Glsl(ref code, _) => {
907 trace.make_binary("glsl", code.as_bytes())
908 }
909 #[cfg(feature = "spirv")]
910 pipeline::ShaderModuleSource::SpirV(ref code, _) => {
911 trace.make_binary("spirv", bytemuck::cast_slice::<u32, u8>(code))
912 }
913 pipeline::ShaderModuleSource::Naga(ref module) => {
914 let string =
915 ron::ser::to_string_pretty(module, ron::ser::PrettyConfig::default())
916 .unwrap();
917 trace.make_binary("ron", string.as_bytes())
918 }
919 pipeline::ShaderModuleSource::Dummy(_) => {
920 panic!("found `ShaderModuleSource::Dummy`")
921 }
922 };
923 trace.add(trace::Action::CreateShaderModule {
924 id: fid.id(),
925 desc: desc.clone(),
926 data,
927 });
928 };
929
930 let shader = match device.create_shader_module(desc, source) {
931 Ok(shader) => shader,
932 Err(e) => break 'error e,
933 };
934
935 let id = fid.assign(Fallible::Valid(shader));
936 api_log!("Device::create_shader_module -> {id:?}");
937 return (id, None);
938 };
939
940 let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
941 (id, Some(error))
942 }
943
944 #[allow(unused_unsafe)]
946 pub unsafe fn device_create_shader_module_spirv(
951 &self,
952 device_id: DeviceId,
953 desc: &pipeline::ShaderModuleDescriptor,
954 source: Cow<[u32]>,
955 id_in: Option<id::ShaderModuleId>,
956 ) -> (
957 id::ShaderModuleId,
958 Option<pipeline::CreateShaderModuleError>,
959 ) {
960 profiling::scope!("Device::create_shader_module");
961
962 let hub = &self.hub;
963 let fid = hub.shader_modules.prepare(id_in);
964
965 let error = 'error: {
966 let device = self.hub.devices.get(device_id);
967
968 #[cfg(feature = "trace")]
969 if let Some(ref mut trace) = *device.trace.lock() {
970 let data = trace.make_binary("spv", unsafe {
971 std::slice::from_raw_parts(source.as_ptr().cast::<u8>(), source.len() * 4)
972 });
973 trace.add(trace::Action::CreateShaderModule {
974 id: fid.id(),
975 desc: desc.clone(),
976 data,
977 });
978 };
979
980 let shader = match unsafe { device.create_shader_module_spirv(desc, &source) } {
981 Ok(shader) => shader,
982 Err(e) => break 'error e,
983 };
984 let id = fid.assign(Fallible::Valid(shader));
985 api_log!("Device::create_shader_module_spirv -> {id:?}");
986 return (id, None);
987 };
988
989 let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
990 (id, Some(error))
991 }
992
993 pub fn shader_module_drop(&self, shader_module_id: id::ShaderModuleId) {
994 profiling::scope!("ShaderModule::drop");
995 api_log!("ShaderModule::drop {shader_module_id:?}");
996
997 let hub = &self.hub;
998
999 let _shader_module = hub.shader_modules.remove(shader_module_id);
1000
1001 #[cfg(feature = "trace")]
1002 if let Ok(shader_module) = _shader_module.get() {
1003 if let Some(t) = shader_module.device.trace.lock().as_mut() {
1004 t.add(trace::Action::DestroyShaderModule(shader_module_id));
1005 }
1006 }
1007 }
1008
1009 pub fn device_create_command_encoder(
1010 &self,
1011 device_id: DeviceId,
1012 desc: &wgt::CommandEncoderDescriptor<Label>,
1013 id_in: Option<id::CommandEncoderId>,
1014 ) -> (id::CommandEncoderId, Option<DeviceError>) {
1015 profiling::scope!("Device::create_command_encoder");
1016
1017 let hub = &self.hub;
1018 let fid = hub
1019 .command_buffers
1020 .prepare(id_in.map(|id| id.into_command_buffer_id()));
1021
1022 let device = self.hub.devices.get(device_id);
1023
1024 let error = 'error: {
1025 let command_buffer = match device.create_command_encoder(&desc.label) {
1026 Ok(command_buffer) => command_buffer,
1027 Err(e) => break 'error e,
1028 };
1029
1030 let id = fid.assign(command_buffer);
1031 api_log!("Device::create_command_encoder -> {id:?}");
1032 return (id.into_command_encoder_id(), None);
1033 };
1034
1035 let id = fid.assign(Arc::new(CommandBuffer::new_invalid(&device, &desc.label)));
1036 (id.into_command_encoder_id(), Some(error))
1037 }
1038
1039 pub fn command_encoder_drop(&self, command_encoder_id: id::CommandEncoderId) {
1040 profiling::scope!("CommandEncoder::drop");
1041 api_log!("CommandEncoder::drop {command_encoder_id:?}");
1042
1043 let hub = &self.hub;
1044
1045 let _cmd_buf = hub
1046 .command_buffers
1047 .remove(command_encoder_id.into_command_buffer_id());
1048 }
1049
1050 pub fn command_buffer_drop(&self, command_buffer_id: id::CommandBufferId) {
1051 profiling::scope!("CommandBuffer::drop");
1052 api_log!("CommandBuffer::drop {command_buffer_id:?}");
1053 self.command_encoder_drop(command_buffer_id.into_command_encoder_id())
1054 }
1055
1056 pub fn device_create_render_bundle_encoder(
1057 &self,
1058 device_id: DeviceId,
1059 desc: &command::RenderBundleEncoderDescriptor,
1060 ) -> (
1061 *mut command::RenderBundleEncoder,
1062 Option<command::CreateRenderBundleError>,
1063 ) {
1064 profiling::scope!("Device::create_render_bundle_encoder");
1065 api_log!("Device::device_create_render_bundle_encoder");
1066 let (encoder, error) = match command::RenderBundleEncoder::new(desc, device_id, None) {
1067 Ok(encoder) => (encoder, None),
1068 Err(e) => (command::RenderBundleEncoder::dummy(device_id), Some(e)),
1069 };
1070 (Box::into_raw(Box::new(encoder)), error)
1071 }
1072
1073 pub fn render_bundle_encoder_finish(
1074 &self,
1075 bundle_encoder: command::RenderBundleEncoder,
1076 desc: &command::RenderBundleDescriptor,
1077 id_in: Option<id::RenderBundleId>,
1078 ) -> (id::RenderBundleId, Option<command::RenderBundleError>) {
1079 profiling::scope!("RenderBundleEncoder::finish");
1080
1081 let hub = &self.hub;
1082
1083 let fid = hub.render_bundles.prepare(id_in);
1084
1085 let error = 'error: {
1086 let device = self.hub.devices.get(bundle_encoder.parent());
1087
1088 #[cfg(feature = "trace")]
1089 if let Some(ref mut trace) = *device.trace.lock() {
1090 trace.add(trace::Action::CreateRenderBundle {
1091 id: fid.id(),
1092 desc: trace::new_render_bundle_encoder_descriptor(
1093 desc.label.clone(),
1094 &bundle_encoder.context,
1095 bundle_encoder.is_depth_read_only,
1096 bundle_encoder.is_stencil_read_only,
1097 ),
1098 base: bundle_encoder.to_base_pass(),
1099 });
1100 }
1101
1102 let render_bundle = match bundle_encoder.finish(desc, &device, hub) {
1103 Ok(bundle) => bundle,
1104 Err(e) => break 'error e,
1105 };
1106
1107 let id = fid.assign(Fallible::Valid(render_bundle));
1108 api_log!("RenderBundleEncoder::finish -> {id:?}");
1109
1110 return (id, None);
1111 };
1112
1113 let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
1114 (id, Some(error))
1115 }
1116
1117 pub fn render_bundle_drop(&self, render_bundle_id: id::RenderBundleId) {
1118 profiling::scope!("RenderBundle::drop");
1119 api_log!("RenderBundle::drop {render_bundle_id:?}");
1120
1121 let hub = &self.hub;
1122
1123 let _bundle = hub.render_bundles.remove(render_bundle_id);
1124
1125 #[cfg(feature = "trace")]
1126 if let Ok(bundle) = _bundle.get() {
1127 if let Some(t) = bundle.device.trace.lock().as_mut() {
1128 t.add(trace::Action::DestroyRenderBundle(render_bundle_id));
1129 }
1130 }
1131 }
1132
1133 pub fn device_create_query_set(
1134 &self,
1135 device_id: DeviceId,
1136 desc: &resource::QuerySetDescriptor,
1137 id_in: Option<id::QuerySetId>,
1138 ) -> (id::QuerySetId, Option<resource::CreateQuerySetError>) {
1139 profiling::scope!("Device::create_query_set");
1140
1141 let hub = &self.hub;
1142 let fid = hub.query_sets.prepare(id_in);
1143
1144 let error = 'error: {
1145 let device = self.hub.devices.get(device_id);
1146
1147 #[cfg(feature = "trace")]
1148 if let Some(ref mut trace) = *device.trace.lock() {
1149 trace.add(trace::Action::CreateQuerySet {
1150 id: fid.id(),
1151 desc: desc.clone(),
1152 });
1153 }
1154
1155 let query_set = match device.create_query_set(desc) {
1156 Ok(query_set) => query_set,
1157 Err(err) => break 'error err,
1158 };
1159
1160 let id = fid.assign(Fallible::Valid(query_set));
1161 api_log!("Device::create_query_set -> {id:?}");
1162
1163 return (id, None);
1164 };
1165
1166 let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
1167 (id, Some(error))
1168 }
1169
1170 pub fn query_set_drop(&self, query_set_id: id::QuerySetId) {
1171 profiling::scope!("QuerySet::drop");
1172 api_log!("QuerySet::drop {query_set_id:?}");
1173
1174 let hub = &self.hub;
1175
1176 let _query_set = hub.query_sets.remove(query_set_id);
1177
1178 #[cfg(feature = "trace")]
1179 if let Ok(query_set) = _query_set.get() {
1180 if let Some(trace) = query_set.device.trace.lock().as_mut() {
1181 trace.add(trace::Action::DestroyQuerySet(query_set_id));
1182 }
1183 }
1184 }
1185
1186 pub fn device_create_render_pipeline(
1187 &self,
1188 device_id: DeviceId,
1189 desc: &pipeline::RenderPipelineDescriptor,
1190 id_in: Option<id::RenderPipelineId>,
1191 implicit_pipeline_ids: Option<ImplicitPipelineIds<'_>>,
1192 ) -> (
1193 id::RenderPipelineId,
1194 Option<pipeline::CreateRenderPipelineError>,
1195 ) {
1196 profiling::scope!("Device::create_render_pipeline");
1197
1198 let hub = &self.hub;
1199
1200 let missing_implicit_pipeline_ids =
1201 desc.layout.is_none() && id_in.is_some() && implicit_pipeline_ids.is_none();
1202
1203 let fid = hub.render_pipelines.prepare(id_in);
1204 let implicit_context = implicit_pipeline_ids.map(|ipi| ipi.prepare(hub));
1205
1206 let error = 'error: {
1207 if missing_implicit_pipeline_ids {
1208 break 'error pipeline::ImplicitLayoutError::MissingImplicitPipelineIds.into();
1210 }
1211
1212 let device = self.hub.devices.get(device_id);
1213
1214 #[cfg(feature = "trace")]
1215 if let Some(ref mut trace) = *device.trace.lock() {
1216 trace.add(trace::Action::CreateRenderPipeline {
1217 id: fid.id(),
1218 desc: desc.clone(),
1219 implicit_context: implicit_context.clone(),
1220 });
1221 }
1222
1223 let layout = desc
1224 .layout
1225 .map(|layout| hub.pipeline_layouts.get(layout).get())
1226 .transpose();
1227 let layout = match layout {
1228 Ok(layout) => layout,
1229 Err(e) => break 'error e.into(),
1230 };
1231
1232 let cache = desc
1233 .cache
1234 .map(|cache| hub.pipeline_caches.get(cache).get())
1235 .transpose();
1236 let cache = match cache {
1237 Ok(cache) => cache,
1238 Err(e) => break 'error e.into(),
1239 };
1240
1241 let vertex = {
1242 let module = hub
1243 .shader_modules
1244 .get(desc.vertex.stage.module)
1245 .get()
1246 .map_err(|e| pipeline::CreateRenderPipelineError::Stage {
1247 stage: wgt::ShaderStages::VERTEX,
1248 error: e.into(),
1249 });
1250 let module = match module {
1251 Ok(module) => module,
1252 Err(e) => break 'error e,
1253 };
1254 let stage = ResolvedProgrammableStageDescriptor {
1255 module,
1256 entry_point: desc.vertex.stage.entry_point.clone(),
1257 constants: desc.vertex.stage.constants.clone(),
1258 zero_initialize_workgroup_memory: desc
1259 .vertex
1260 .stage
1261 .zero_initialize_workgroup_memory,
1262 };
1263 ResolvedVertexState {
1264 stage,
1265 buffers: desc.vertex.buffers.clone(),
1266 }
1267 };
1268
1269 let fragment = if let Some(ref state) = desc.fragment {
1270 let module = hub
1271 .shader_modules
1272 .get(state.stage.module)
1273 .get()
1274 .map_err(|e| pipeline::CreateRenderPipelineError::Stage {
1275 stage: wgt::ShaderStages::FRAGMENT,
1276 error: e.into(),
1277 });
1278 let module = match module {
1279 Ok(module) => module,
1280 Err(e) => break 'error e,
1281 };
1282 let stage = ResolvedProgrammableStageDescriptor {
1283 module,
1284 entry_point: state.stage.entry_point.clone(),
1285 constants: state.stage.constants.clone(),
1286 zero_initialize_workgroup_memory: desc
1287 .vertex
1288 .stage
1289 .zero_initialize_workgroup_memory,
1290 };
1291 Some(ResolvedFragmentState {
1292 stage,
1293 targets: state.targets.clone(),
1294 })
1295 } else {
1296 None
1297 };
1298
1299 let desc = ResolvedRenderPipelineDescriptor {
1300 label: desc.label.clone(),
1301 layout,
1302 vertex,
1303 primitive: desc.primitive,
1304 depth_stencil: desc.depth_stencil.clone(),
1305 multisample: desc.multisample,
1306 fragment,
1307 multiview: desc.multiview,
1308 cache,
1309 };
1310
1311 let pipeline = match device.create_render_pipeline(desc) {
1312 Ok(pair) => pair,
1313 Err(e) => break 'error e,
1314 };
1315
1316 if let Some(ids) = implicit_context.as_ref() {
1317 let group_count = pipeline.layout.bind_group_layouts.len();
1318 if ids.group_ids.len() < group_count {
1319 log::error!(
1320 "Not enough bind group IDs ({}) specified for the implicit layout ({})",
1321 ids.group_ids.len(),
1322 group_count
1323 );
1324 break 'error pipeline::ImplicitLayoutError::MissingIds(group_count as _)
1326 .into();
1327 }
1328
1329 let mut pipeline_layout_guard = hub.pipeline_layouts.write();
1330 let mut bgl_guard = hub.bind_group_layouts.write();
1331 pipeline_layout_guard.insert(ids.root_id, Fallible::Valid(pipeline.layout.clone()));
1332 let mut group_ids = ids.group_ids.iter();
1333 for (bgl, bgl_id) in pipeline
1338 .layout
1339 .bind_group_layouts
1340 .iter()
1341 .zip(&mut group_ids)
1342 {
1343 bgl_guard.insert(*bgl_id, Fallible::Valid(bgl.clone()));
1344 }
1345 for bgl_id in group_ids {
1346 bgl_guard.insert(*bgl_id, Fallible::Invalid(Arc::new(String::new())));
1347 }
1348 }
1349
1350 let id = fid.assign(Fallible::Valid(pipeline));
1351 api_log!("Device::create_render_pipeline -> {id:?}");
1352
1353 return (id, None);
1354 };
1355
1356 let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
1357
1358 if let Some(ids) = implicit_context {
1361 let mut pipeline_layout_guard = hub.pipeline_layouts.write();
1362 let mut bgl_guard = hub.bind_group_layouts.write();
1363 pipeline_layout_guard.insert(ids.root_id, Fallible::Invalid(Arc::new(String::new())));
1364 for bgl_id in ids.group_ids {
1365 bgl_guard.insert(bgl_id, Fallible::Invalid(Arc::new(String::new())));
1366 }
1367 }
1368
1369 (id, Some(error))
1370 }
1371
1372 pub fn render_pipeline_get_bind_group_layout(
1375 &self,
1376 pipeline_id: id::RenderPipelineId,
1377 index: u32,
1378 id_in: Option<id::BindGroupLayoutId>,
1379 ) -> (
1380 id::BindGroupLayoutId,
1381 Option<binding_model::GetBindGroupLayoutError>,
1382 ) {
1383 let hub = &self.hub;
1384
1385 let fid = hub.bind_group_layouts.prepare(id_in);
1386
1387 let error = 'error: {
1388 let pipeline = match hub.render_pipelines.get(pipeline_id).get() {
1389 Ok(pipeline) => pipeline,
1390 Err(e) => break 'error e.into(),
1391 };
1392 let id = match pipeline.layout.bind_group_layouts.get(index as usize) {
1393 Some(bg) => fid.assign(Fallible::Valid(bg.clone())),
1394 None => {
1395 break 'error binding_model::GetBindGroupLayoutError::InvalidGroupIndex(index)
1396 }
1397 };
1398 return (id, None);
1399 };
1400
1401 let id = fid.assign(Fallible::Invalid(Arc::new(String::new())));
1402 (id, Some(error))
1403 }
1404
1405 pub fn render_pipeline_drop(&self, render_pipeline_id: id::RenderPipelineId) {
1406 profiling::scope!("RenderPipeline::drop");
1407 api_log!("RenderPipeline::drop {render_pipeline_id:?}");
1408
1409 let hub = &self.hub;
1410
1411 let _pipeline = hub.render_pipelines.remove(render_pipeline_id);
1412
1413 #[cfg(feature = "trace")]
1414 if let Ok(pipeline) = _pipeline.get() {
1415 if let Some(t) = pipeline.device.trace.lock().as_mut() {
1416 t.add(trace::Action::DestroyRenderPipeline(render_pipeline_id));
1417 }
1418 }
1419 }
1420
1421 pub fn device_create_compute_pipeline(
1422 &self,
1423 device_id: DeviceId,
1424 desc: &pipeline::ComputePipelineDescriptor,
1425 id_in: Option<id::ComputePipelineId>,
1426 implicit_pipeline_ids: Option<ImplicitPipelineIds<'_>>,
1427 ) -> (
1428 id::ComputePipelineId,
1429 Option<pipeline::CreateComputePipelineError>,
1430 ) {
1431 profiling::scope!("Device::create_compute_pipeline");
1432
1433 let hub = &self.hub;
1434
1435 let missing_implicit_pipeline_ids =
1436 desc.layout.is_none() && id_in.is_some() && implicit_pipeline_ids.is_none();
1437
1438 let fid = hub.compute_pipelines.prepare(id_in);
1439 let implicit_context = implicit_pipeline_ids.map(|ipi| ipi.prepare(hub));
1440
1441 let error = 'error: {
1442 if missing_implicit_pipeline_ids {
1443 break 'error pipeline::ImplicitLayoutError::MissingImplicitPipelineIds.into();
1445 }
1446
1447 let device = self.hub.devices.get(device_id);
1448
1449 #[cfg(feature = "trace")]
1450 if let Some(ref mut trace) = *device.trace.lock() {
1451 trace.add(trace::Action::CreateComputePipeline {
1452 id: fid.id(),
1453 desc: desc.clone(),
1454 implicit_context: implicit_context.clone(),
1455 });
1456 }
1457
1458 let layout = desc
1459 .layout
1460 .map(|layout| hub.pipeline_layouts.get(layout).get())
1461 .transpose();
1462 let layout = match layout {
1463 Ok(layout) => layout,
1464 Err(e) => break 'error e.into(),
1465 };
1466
1467 let cache = desc
1468 .cache
1469 .map(|cache| hub.pipeline_caches.get(cache).get())
1470 .transpose();
1471 let cache = match cache {
1472 Ok(cache) => cache,
1473 Err(e) => break 'error e.into(),
1474 };
1475
1476 let module = hub.shader_modules.get(desc.stage.module).get();
1477 let module = match module {
1478 Ok(module) => module,
1479 Err(e) => break 'error e.into(),
1480 };
1481 let stage = ResolvedProgrammableStageDescriptor {
1482 module,
1483 entry_point: desc.stage.entry_point.clone(),
1484 constants: desc.stage.constants.clone(),
1485 zero_initialize_workgroup_memory: desc.stage.zero_initialize_workgroup_memory,
1486 };
1487
1488 let desc = ResolvedComputePipelineDescriptor {
1489 label: desc.label.clone(),
1490 layout,
1491 stage,
1492 cache,
1493 };
1494
1495 let pipeline = match device.create_compute_pipeline(desc) {
1496 Ok(pair) => pair,
1497 Err(e) => break 'error e,
1498 };
1499
1500 if let Some(ids) = implicit_context.as_ref() {
1501 let group_count = pipeline.layout.bind_group_layouts.len();
1502 if ids.group_ids.len() < group_count {
1503 log::error!(
1504 "Not enough bind group IDs ({}) specified for the implicit layout ({})",
1505 ids.group_ids.len(),
1506 group_count
1507 );
1508 break 'error pipeline::ImplicitLayoutError::MissingIds(group_count as _)
1510 .into();
1511 }
1512
1513 let mut pipeline_layout_guard = hub.pipeline_layouts.write();
1514 let mut bgl_guard = hub.bind_group_layouts.write();
1515 pipeline_layout_guard.insert(ids.root_id, Fallible::Valid(pipeline.layout.clone()));
1516 let mut group_ids = ids.group_ids.iter();
1517 for (bgl, bgl_id) in pipeline
1522 .layout
1523 .bind_group_layouts
1524 .iter()
1525 .zip(&mut group_ids)
1526 {
1527 bgl_guard.insert(*bgl_id, Fallible::Valid(bgl.clone()));
1528 }
1529 for bgl_id in group_ids {
1530 bgl_guard.insert(*bgl_id, Fallible::Invalid(Arc::new(String::new())));
1531 }
1532 }
1533
1534 let id = fid.assign(Fallible::Valid(pipeline));
1535 api_log!("Device::create_compute_pipeline -> {id:?}");
1536
1537 return (id, None);
1538 };
1539
1540 let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
1541
1542 if let Some(ids) = implicit_context {
1545 let mut pipeline_layout_guard = hub.pipeline_layouts.write();
1546 let mut bgl_guard = hub.bind_group_layouts.write();
1547 pipeline_layout_guard.insert(ids.root_id, Fallible::Invalid(Arc::new(String::new())));
1548 for bgl_id in ids.group_ids {
1549 bgl_guard.insert(bgl_id, Fallible::Invalid(Arc::new(String::new())));
1550 }
1551 }
1552
1553 (id, Some(error))
1554 }
1555
1556 pub fn compute_pipeline_get_bind_group_layout(
1559 &self,
1560 pipeline_id: id::ComputePipelineId,
1561 index: u32,
1562 id_in: Option<id::BindGroupLayoutId>,
1563 ) -> (
1564 id::BindGroupLayoutId,
1565 Option<binding_model::GetBindGroupLayoutError>,
1566 ) {
1567 let hub = &self.hub;
1568
1569 let fid = hub.bind_group_layouts.prepare(id_in);
1570
1571 let error = 'error: {
1572 let pipeline = match hub.compute_pipelines.get(pipeline_id).get() {
1573 Ok(pipeline) => pipeline,
1574 Err(e) => break 'error e.into(),
1575 };
1576
1577 let id = match pipeline.layout.bind_group_layouts.get(index as usize) {
1578 Some(bg) => fid.assign(Fallible::Valid(bg.clone())),
1579 None => {
1580 break 'error binding_model::GetBindGroupLayoutError::InvalidGroupIndex(index)
1581 }
1582 };
1583
1584 return (id, None);
1585 };
1586
1587 let id = fid.assign(Fallible::Invalid(Arc::new(String::new())));
1588 (id, Some(error))
1589 }
1590
1591 pub fn compute_pipeline_drop(&self, compute_pipeline_id: id::ComputePipelineId) {
1592 profiling::scope!("ComputePipeline::drop");
1593 api_log!("ComputePipeline::drop {compute_pipeline_id:?}");
1594
1595 let hub = &self.hub;
1596
1597 let _pipeline = hub.compute_pipelines.remove(compute_pipeline_id);
1598
1599 #[cfg(feature = "trace")]
1600 if let Ok(pipeline) = _pipeline.get() {
1601 if let Some(t) = pipeline.device.trace.lock().as_mut() {
1602 t.add(trace::Action::DestroyComputePipeline(compute_pipeline_id));
1603 }
1604 }
1605 }
1606
1607 pub unsafe fn device_create_pipeline_cache(
1611 &self,
1612 device_id: DeviceId,
1613 desc: &pipeline::PipelineCacheDescriptor<'_>,
1614 id_in: Option<id::PipelineCacheId>,
1615 ) -> (
1616 id::PipelineCacheId,
1617 Option<pipeline::CreatePipelineCacheError>,
1618 ) {
1619 profiling::scope!("Device::create_pipeline_cache");
1620
1621 let hub = &self.hub;
1622
1623 let fid = hub.pipeline_caches.prepare(id_in);
1624 let error: pipeline::CreatePipelineCacheError = 'error: {
1625 let device = self.hub.devices.get(device_id);
1626
1627 #[cfg(feature = "trace")]
1628 if let Some(ref mut trace) = *device.trace.lock() {
1629 trace.add(trace::Action::CreatePipelineCache {
1630 id: fid.id(),
1631 desc: desc.clone(),
1632 });
1633 }
1634
1635 let cache = unsafe { device.create_pipeline_cache(desc) };
1636 match cache {
1637 Ok(cache) => {
1638 let id = fid.assign(Fallible::Valid(cache));
1639 api_log!("Device::create_pipeline_cache -> {id:?}");
1640 return (id, None);
1641 }
1642 Err(e) => break 'error e,
1643 }
1644 };
1645
1646 let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
1647
1648 (id, Some(error))
1649 }
1650
1651 pub fn pipeline_cache_drop(&self, pipeline_cache_id: id::PipelineCacheId) {
1652 profiling::scope!("PipelineCache::drop");
1653 api_log!("PipelineCache::drop {pipeline_cache_id:?}");
1654
1655 let hub = &self.hub;
1656
1657 let _cache = hub.pipeline_caches.remove(pipeline_cache_id);
1658
1659 #[cfg(feature = "trace")]
1660 if let Ok(cache) = _cache.get() {
1661 if let Some(t) = cache.device.trace.lock().as_mut() {
1662 t.add(trace::Action::DestroyPipelineCache(pipeline_cache_id));
1663 }
1664 }
1665 }
1666
1667 pub fn surface_configure(
1668 &self,
1669 surface_id: SurfaceId,
1670 device_id: DeviceId,
1671 config: &wgt::SurfaceConfiguration<Vec<TextureFormat>>,
1672 ) -> Option<present::ConfigureSurfaceError> {
1673 use present::ConfigureSurfaceError as E;
1674 profiling::scope!("surface_configure");
1675
1676 fn validate_surface_configuration(
1677 config: &mut hal::SurfaceConfiguration,
1678 caps: &hal::SurfaceCapabilities,
1679 max_texture_dimension_2d: u32,
1680 ) -> Result<(), E> {
1681 let width = config.extent.width;
1682 let height = config.extent.height;
1683
1684 if width > max_texture_dimension_2d || height > max_texture_dimension_2d {
1685 return Err(E::TooLarge {
1686 width,
1687 height,
1688 max_texture_dimension_2d,
1689 });
1690 }
1691
1692 if !caps.present_modes.contains(&config.present_mode) {
1693 let fallbacks = match config.present_mode {
1697 wgt::PresentMode::AutoVsync => {
1698 &[wgt::PresentMode::FifoRelaxed, wgt::PresentMode::Fifo][..]
1699 }
1700 wgt::PresentMode::AutoNoVsync => &[
1702 wgt::PresentMode::Immediate,
1703 wgt::PresentMode::Mailbox,
1704 wgt::PresentMode::Fifo,
1705 ][..],
1706 _ => {
1707 return Err(E::UnsupportedPresentMode {
1708 requested: config.present_mode,
1709 available: caps.present_modes.clone(),
1710 });
1711 }
1712 };
1713
1714 let new_mode = fallbacks
1715 .iter()
1716 .copied()
1717 .find(|fallback| caps.present_modes.contains(fallback))
1718 .unwrap_or_else(|| {
1719 unreachable!(
1720 "Fallback system failed to choose present mode. \
1721 This is a bug. Mode: {:?}, Options: {:?}",
1722 config.present_mode, &caps.present_modes
1723 );
1724 });
1725
1726 api_log!(
1727 "Automatically choosing presentation mode by rule {:?}. Chose {new_mode:?}",
1728 config.present_mode
1729 );
1730 config.present_mode = new_mode;
1731 }
1732 if !caps.formats.contains(&config.format) {
1733 return Err(E::UnsupportedFormat {
1734 requested: config.format,
1735 available: caps.formats.clone(),
1736 });
1737 }
1738 if !caps
1739 .composite_alpha_modes
1740 .contains(&config.composite_alpha_mode)
1741 {
1742 let new_alpha_mode = 'alpha: {
1743 let fallbacks = match config.composite_alpha_mode {
1745 wgt::CompositeAlphaMode::Auto => &[
1746 wgt::CompositeAlphaMode::Opaque,
1747 wgt::CompositeAlphaMode::Inherit,
1748 ][..],
1749 _ => {
1750 return Err(E::UnsupportedAlphaMode {
1751 requested: config.composite_alpha_mode,
1752 available: caps.composite_alpha_modes.clone(),
1753 });
1754 }
1755 };
1756
1757 for &fallback in fallbacks {
1758 if caps.composite_alpha_modes.contains(&fallback) {
1759 break 'alpha fallback;
1760 }
1761 }
1762
1763 unreachable!(
1764 "Fallback system failed to choose alpha mode. This is a bug. \
1765 AlphaMode: {:?}, Options: {:?}",
1766 config.composite_alpha_mode, &caps.composite_alpha_modes
1767 );
1768 };
1769
1770 api_log!(
1771 "Automatically choosing alpha mode by rule {:?}. Chose {new_alpha_mode:?}",
1772 config.composite_alpha_mode
1773 );
1774 config.composite_alpha_mode = new_alpha_mode;
1775 }
1776 if !caps.usage.contains(config.usage) {
1777 return Err(E::UnsupportedUsage {
1778 requested: config.usage,
1779 available: caps.usage,
1780 });
1781 }
1782 if width == 0 || height == 0 {
1783 return Err(E::ZeroArea);
1784 }
1785 Ok(())
1786 }
1787
1788 log::debug!("configuring surface with {:?}", config);
1789
1790 let error = 'error: {
1791 let user_callbacks;
1793 {
1794 let device = self.hub.devices.get(device_id);
1795
1796 #[cfg(feature = "trace")]
1797 if let Some(ref mut trace) = *device.trace.lock() {
1798 trace.add(trace::Action::ConfigureSurface(surface_id, config.clone()));
1799 }
1800
1801 if let Err(e) = device.check_is_valid() {
1802 break 'error e.into();
1803 }
1804
1805 let surface = self.surfaces.get(surface_id);
1806
1807 let caps = match surface.get_capabilities(&device.adapter) {
1808 Ok(caps) => caps,
1809 Err(_) => break 'error E::UnsupportedQueueFamily,
1810 };
1811
1812 let mut hal_view_formats = vec![];
1813 for format in config.view_formats.iter() {
1814 if *format == config.format {
1815 continue;
1816 }
1817 if !caps.formats.contains(&config.format) {
1818 break 'error E::UnsupportedFormat {
1819 requested: config.format,
1820 available: caps.formats,
1821 };
1822 }
1823 if config.format.remove_srgb_suffix() != format.remove_srgb_suffix() {
1824 break 'error E::InvalidViewFormat(*format, config.format);
1825 }
1826 hal_view_formats.push(*format);
1827 }
1828
1829 if !hal_view_formats.is_empty() {
1830 if let Err(missing_flag) =
1831 device.require_downlevel_flags(wgt::DownlevelFlags::SURFACE_VIEW_FORMATS)
1832 {
1833 break 'error E::MissingDownlevelFlags(missing_flag);
1834 }
1835 }
1836
1837 let maximum_frame_latency = config.desired_maximum_frame_latency.clamp(
1838 *caps.maximum_frame_latency.start(),
1839 *caps.maximum_frame_latency.end(),
1840 );
1841 let mut hal_config = hal::SurfaceConfiguration {
1842 maximum_frame_latency,
1843 present_mode: config.present_mode,
1844 composite_alpha_mode: config.alpha_mode,
1845 format: config.format,
1846 extent: wgt::Extent3d {
1847 width: config.width,
1848 height: config.height,
1849 depth_or_array_layers: 1,
1850 },
1851 usage: conv::map_texture_usage(
1852 config.usage,
1853 hal::FormatAspects::COLOR,
1854 wgt::TextureFormatFeatureFlags::STORAGE_READ_ONLY
1855 | wgt::TextureFormatFeatureFlags::STORAGE_WRITE_ONLY
1856 | wgt::TextureFormatFeatureFlags::STORAGE_READ_WRITE,
1857 ),
1858 view_formats: hal_view_formats,
1859 };
1860
1861 if let Err(error) = validate_surface_configuration(
1862 &mut hal_config,
1863 &caps,
1864 device.limits.max_texture_dimension_2d,
1865 ) {
1866 break 'error error;
1867 }
1868
1869 let snatch_guard = device.snatchable_lock.read();
1871 let fence = device.fence.read();
1872 match device.maintain(fence, wgt::Maintain::Wait, snatch_guard) {
1873 Ok((closures, _)) => {
1874 user_callbacks = closures;
1875 }
1876 Err(e) => {
1877 break 'error e.into();
1878 }
1879 }
1880
1881 if let Some(present) = surface.presentation.lock().take() {
1883 if present.acquired_texture.is_some() {
1884 break 'error E::PreviousOutputExists;
1885 }
1886 }
1887
1888 let surface_raw = surface.raw(device.backend()).unwrap();
1895 match unsafe { surface_raw.configure(device.raw(), &hal_config) } {
1896 Ok(()) => (),
1897 Err(error) => {
1898 break 'error match error {
1899 hal::SurfaceError::Outdated | hal::SurfaceError::Lost => {
1900 E::InvalidSurface
1901 }
1902 hal::SurfaceError::Device(error) => {
1903 E::Device(device.handle_hal_error(error))
1904 }
1905 hal::SurfaceError::Other(message) => {
1906 log::error!("surface configuration failed: {}", message);
1907 E::InvalidSurface
1908 }
1909 }
1910 }
1911 }
1912
1913 let mut presentation = surface.presentation.lock();
1914 *presentation = Some(present::Presentation {
1915 device,
1916 config: config.clone(),
1917 acquired_texture: None,
1918 });
1919 }
1920
1921 user_callbacks.fire();
1922 return None;
1923 };
1924
1925 Some(error)
1926 }
1927
1928 pub fn device_poll(
1932 &self,
1933 device_id: DeviceId,
1934 maintain: wgt::Maintain<crate::SubmissionIndex>,
1935 ) -> Result<bool, WaitIdleError> {
1936 api_log!("Device::poll {maintain:?}");
1937
1938 let device = self.hub.devices.get(device_id);
1939
1940 let DevicePoll {
1941 closures,
1942 queue_empty,
1943 } = Self::poll_single_device(&device, maintain)?;
1944
1945 closures.fire();
1946
1947 Ok(queue_empty)
1948 }
1949
1950 fn poll_single_device(
1951 device: &crate::device::Device,
1952 maintain: wgt::Maintain<crate::SubmissionIndex>,
1953 ) -> Result<DevicePoll, WaitIdleError> {
1954 let snatch_guard = device.snatchable_lock.read();
1955 let fence = device.fence.read();
1956 let (closures, queue_empty) = device.maintain(fence, maintain, snatch_guard)?;
1957
1958 device.deferred_resource_destruction();
1961
1962 Ok(DevicePoll {
1963 closures,
1964 queue_empty,
1965 })
1966 }
1967
1968 fn poll_all_devices_of_api(
1975 &self,
1976 force_wait: bool,
1977 closures: &mut UserClosures,
1978 ) -> Result<bool, WaitIdleError> {
1979 profiling::scope!("poll_device");
1980
1981 let hub = &self.hub;
1982 let mut all_queue_empty = true;
1983 {
1984 let device_guard = hub.devices.read();
1985
1986 for (_id, device) in device_guard.iter() {
1987 let maintain = if force_wait {
1988 wgt::Maintain::Wait
1989 } else {
1990 wgt::Maintain::Poll
1991 };
1992
1993 let DevicePoll {
1994 closures: cbs,
1995 queue_empty,
1996 } = Self::poll_single_device(device, maintain)?;
1997
1998 all_queue_empty &= queue_empty;
1999
2000 closures.extend(cbs);
2001 }
2002 }
2003
2004 Ok(all_queue_empty)
2005 }
2006
2007 pub fn poll_all_devices(&self, force_wait: bool) -> Result<bool, WaitIdleError> {
2014 api_log!("poll_all_devices");
2015 let mut closures = UserClosures::default();
2016 let all_queue_empty = self.poll_all_devices_of_api(force_wait, &mut closures)?;
2017
2018 closures.fire();
2019
2020 Ok(all_queue_empty)
2021 }
2022
2023 pub fn device_start_capture(&self, device_id: DeviceId) {
2024 api_log!("Device::start_capture");
2025
2026 let device = self.hub.devices.get(device_id);
2027
2028 if !device.is_valid() {
2029 return;
2030 }
2031 unsafe { device.raw().start_capture() };
2032 }
2033
2034 pub fn device_stop_capture(&self, device_id: DeviceId) {
2035 api_log!("Device::stop_capture");
2036
2037 let device = self.hub.devices.get(device_id);
2038
2039 if !device.is_valid() {
2040 return;
2041 }
2042 unsafe { device.raw().stop_capture() };
2043 }
2044
2045 pub fn pipeline_cache_get_data(&self, id: id::PipelineCacheId) -> Option<Vec<u8>> {
2046 use crate::pipeline_cache;
2047 api_log!("PipelineCache::get_data");
2048 let hub = &self.hub;
2049
2050 if let Ok(cache) = hub.pipeline_caches.get(id).get() {
2051 if !cache.device.is_valid() {
2053 return None;
2054 }
2055 let mut vec = unsafe { cache.device.raw().pipeline_cache_get_data(cache.raw()) }?;
2056 let validation_key = cache.device.raw().pipeline_cache_validation_key()?;
2057
2058 let mut header_contents = [0; pipeline_cache::HEADER_LENGTH];
2059 pipeline_cache::add_cache_header(
2060 &mut header_contents,
2061 &vec,
2062 &cache.device.adapter.raw.info,
2063 validation_key,
2064 );
2065
2066 let deleted = vec.splice(..0, header_contents).collect::<Vec<_>>();
2067 debug_assert!(deleted.is_empty());
2068
2069 return Some(vec);
2070 }
2071 None
2072 }
2073
2074 pub fn device_drop(&self, device_id: DeviceId) {
2075 profiling::scope!("Device::drop");
2076 api_log!("Device::drop {device_id:?}");
2077
2078 self.hub.devices.remove(device_id);
2079 }
2080
2081 pub fn device_set_device_lost_closure(
2083 &self,
2084 device_id: DeviceId,
2085 device_lost_closure: DeviceLostClosure,
2086 ) {
2087 let device = self.hub.devices.get(device_id);
2088
2089 device
2090 .device_lost_closure
2091 .lock()
2092 .replace(device_lost_closure);
2093 }
2094
2095 pub fn device_destroy(&self, device_id: DeviceId) {
2096 api_log!("Device::destroy {device_id:?}");
2097
2098 let device = self.hub.devices.get(device_id);
2099
2100 if !device.is_valid() {
2106 return;
2107 }
2108
2109 device.valid.store(false, Ordering::Release);
2117 }
2118
2119 pub fn device_get_internal_counters(&self, device_id: DeviceId) -> wgt::InternalCounters {
2120 let device = self.hub.devices.get(device_id);
2121 wgt::InternalCounters {
2122 hal: device.get_hal_counters(),
2123 core: wgt::CoreCounters {},
2124 }
2125 }
2126
2127 pub fn device_generate_allocator_report(
2128 &self,
2129 device_id: DeviceId,
2130 ) -> Option<wgt::AllocatorReport> {
2131 let device = self.hub.devices.get(device_id);
2132 device.generate_allocator_report()
2133 }
2134
2135 pub fn queue_drop(&self, queue_id: QueueId) {
2136 profiling::scope!("Queue::drop");
2137 api_log!("Queue::drop {queue_id:?}");
2138
2139 self.hub.queues.remove(queue_id);
2140 }
2141
2142 pub fn buffer_map_async(
2144 &self,
2145 buffer_id: id::BufferId,
2146 offset: BufferAddress,
2147 size: Option<BufferAddress>,
2148 op: BufferMapOperation,
2149 ) -> Result<crate::SubmissionIndex, BufferAccessError> {
2150 profiling::scope!("Buffer::map_async");
2151 api_log!("Buffer::map_async {buffer_id:?} offset {offset:?} size {size:?} op: {op:?}");
2152
2153 let hub = &self.hub;
2154
2155 let map_result = match hub.buffers.get(buffer_id).get() {
2156 Ok(buffer) => buffer.map_async(offset, size, op),
2157 Err(e) => Err((op, e.into())),
2158 };
2159
2160 match map_result {
2161 Ok(submission_index) => Ok(submission_index),
2162 Err((mut operation, err)) => {
2163 if let Some(callback) = operation.callback.take() {
2164 callback(Err(err.clone()));
2165 }
2166 Err(err)
2167 }
2168 }
2169 }
2170
2171 pub fn buffer_get_mapped_range(
2172 &self,
2173 buffer_id: id::BufferId,
2174 offset: BufferAddress,
2175 size: Option<BufferAddress>,
2176 ) -> Result<(NonNull<u8>, u64), BufferAccessError> {
2177 profiling::scope!("Buffer::get_mapped_range");
2178 api_log!("Buffer::get_mapped_range {buffer_id:?} offset {offset:?} size {size:?}");
2179
2180 let hub = &self.hub;
2181
2182 let buffer = hub.buffers.get(buffer_id).get()?;
2183
2184 {
2185 let snatch_guard = buffer.device.snatchable_lock.read();
2186 buffer.check_destroyed(&snatch_guard)?;
2187 }
2188
2189 let range_size = if let Some(size) = size {
2190 size
2191 } else if offset > buffer.size {
2192 0
2193 } else {
2194 buffer.size - offset
2195 };
2196
2197 if offset % wgt::MAP_ALIGNMENT != 0 {
2198 return Err(BufferAccessError::UnalignedOffset { offset });
2199 }
2200 if range_size % wgt::COPY_BUFFER_ALIGNMENT != 0 {
2201 return Err(BufferAccessError::UnalignedRangeSize { range_size });
2202 }
2203 let map_state = &*buffer.map_state.lock();
2204 match *map_state {
2205 resource::BufferMapState::Init { ref staging_buffer } => {
2206 if offset + range_size > buffer.size {
2208 return Err(BufferAccessError::OutOfBoundsOverrun {
2209 index: offset + range_size - 1,
2210 max: buffer.size,
2211 });
2212 }
2213 let ptr = unsafe { staging_buffer.ptr() };
2214 let ptr = unsafe { NonNull::new_unchecked(ptr.as_ptr().offset(offset as isize)) };
2215 Ok((ptr, range_size))
2216 }
2217 resource::BufferMapState::Active {
2218 ref mapping,
2219 ref range,
2220 ..
2221 } => {
2222 if offset < range.start {
2223 return Err(BufferAccessError::OutOfBoundsUnderrun {
2224 index: offset,
2225 min: range.start,
2226 });
2227 }
2228 if offset + range_size > range.end {
2229 return Err(BufferAccessError::OutOfBoundsOverrun {
2230 index: offset + range_size - 1,
2231 max: range.end,
2232 });
2233 }
2234 let relative_offset = (offset - range.start) as isize;
2237 unsafe {
2238 Ok((
2239 NonNull::new_unchecked(mapping.ptr.as_ptr().offset(relative_offset)),
2240 range_size,
2241 ))
2242 }
2243 }
2244 resource::BufferMapState::Idle | resource::BufferMapState::Waiting(_) => {
2245 Err(BufferAccessError::NotMapped)
2246 }
2247 }
2248 }
2249 pub fn buffer_unmap(&self, buffer_id: id::BufferId) -> BufferAccessResult {
2250 profiling::scope!("unmap", "Buffer");
2251 api_log!("Buffer::unmap {buffer_id:?}");
2252
2253 let hub = &self.hub;
2254
2255 let buffer = hub.buffers.get(buffer_id).get()?;
2256
2257 let snatch_guard = buffer.device.snatchable_lock.read();
2258 buffer.check_destroyed(&snatch_guard)?;
2259 drop(snatch_guard);
2260
2261 buffer.device.check_is_valid()?;
2262 buffer.unmap(
2263 #[cfg(feature = "trace")]
2264 buffer_id,
2265 )
2266 }
2267}
2268
2269struct DevicePoll {
2270 closures: UserClosures,
2271 queue_empty: bool,
2272}