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