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