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::{self, IntoTrace};
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::{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_adapter_info(&self, device_id: DeviceId) -> wgt::AdapterInfo {
91 let device = self.hub.devices.get(device_id);
92 device.adapter.get_info()
93 }
94
95 pub fn device_downlevel_properties(&self, device_id: DeviceId) -> wgt::DownlevelCapabilities {
96 let device = self.hub.devices.get(device_id);
97 device.downlevel.clone()
98 }
99
100 pub fn device_create_buffer(
101 &self,
102 device_id: DeviceId,
103 desc: &resource::BufferDescriptor,
104 id_in: Option<id::BufferId>,
105 ) -> (id::BufferId, Option<CreateBufferError>) {
106 profiling::scope!("Device::create_buffer");
107
108 let hub = &self.hub;
109 let fid = hub.buffers.prepare(id_in);
110
111 let error = 'error: {
112 let device = self.hub.devices.get(device_id);
113
114 let buffer = match device.create_buffer(desc) {
115 Ok(buffer) => buffer,
116 Err(e) => {
117 break 'error e;
118 }
119 };
120
121 #[cfg(feature = "trace")]
122 if let Some(ref mut trace) = *device.trace.lock() {
123 let mut desc = desc.clone();
124 let mapped_at_creation = core::mem::replace(&mut desc.mapped_at_creation, false);
125 if mapped_at_creation && !desc.usage.contains(wgt::BufferUsages::MAP_WRITE) {
126 desc.usage |= wgt::BufferUsages::COPY_DST;
127 }
128 trace.add(trace::Action::CreateBuffer(buffer.to_trace(), desc));
129 }
130
131 let id = fid.assign(Fallible::Valid(buffer));
132
133 api_log!(
134 "Device::create_buffer({:?}{}) -> {id:?}",
135 desc.label.as_deref().unwrap_or(""),
136 if desc.mapped_at_creation {
137 ", mapped_at_creation"
138 } else {
139 ""
140 }
141 );
142
143 return (id, None);
144 };
145
146 let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
147 (id, Some(error))
148 }
149
150 pub fn create_buffer_error(
179 &self,
180 id_in: Option<id::BufferId>,
181 desc: &resource::BufferDescriptor,
182 ) {
183 let fid = self.hub.buffers.prepare(id_in);
184 fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
185 }
186
187 pub fn create_render_bundle_error(
191 &self,
192 id_in: Option<id::RenderBundleId>,
193 desc: &command::RenderBundleDescriptor,
194 ) {
195 let fid = self.hub.render_bundles.prepare(id_in);
196 fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
197 }
198
199 pub fn create_texture_error(
203 &self,
204 id_in: Option<id::TextureId>,
205 desc: &resource::TextureDescriptor,
206 ) {
207 let fid = self.hub.textures.prepare(id_in);
208 fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
209 }
210
211 pub fn create_external_texture_error(
215 &self,
216 id_in: Option<id::ExternalTextureId>,
217 desc: &resource::ExternalTextureDescriptor,
218 ) {
219 let fid = self.hub.external_textures.prepare(id_in);
220 fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
221 }
222
223 pub fn create_bind_group_layout_error(
232 &self,
233 id_in: Option<id::BindGroupLayoutId>,
234 label: Option<Cow<'_, str>>,
235 ) {
236 let fid = self.hub.bind_group_layouts.prepare(id_in);
237 fid.assign(Fallible::Invalid(Arc::new(label.to_string())));
238 }
239
240 pub fn buffer_destroy(&self, buffer_id: id::BufferId) {
241 profiling::scope!("Buffer::destroy");
242 api_log!("Buffer::destroy {buffer_id:?}");
243
244 let hub = &self.hub;
245
246 let Ok(buffer) = hub.buffers.get(buffer_id).get() else {
247 return;
249 };
250
251 #[cfg(feature = "trace")]
252 if let Some(trace) = buffer.device.trace.lock().as_mut() {
253 trace.add(trace::Action::FreeBuffer(buffer.to_trace()));
254 }
255
256 let _ = buffer.unmap();
257
258 buffer.destroy();
259 }
260
261 pub fn buffer_drop(&self, buffer_id: id::BufferId) {
262 profiling::scope!("Buffer::drop");
263 api_log!("Buffer::drop {buffer_id:?}");
264
265 let hub = &self.hub;
266
267 let buffer = match hub.buffers.remove(buffer_id).get() {
268 Ok(buffer) => buffer,
269 Err(_) => {
270 return;
271 }
272 };
273
274 #[cfg(feature = "trace")]
275 if let Some(t) = buffer.device.trace.lock().as_mut() {
276 t.add(trace::Action::DestroyBuffer(buffer.to_trace()));
277 }
278
279 let _ = buffer.unmap();
280 }
281
282 pub fn device_create_texture(
283 &self,
284 device_id: DeviceId,
285 desc: &resource::TextureDescriptor,
286 id_in: Option<id::TextureId>,
287 ) -> (id::TextureId, Option<resource::CreateTextureError>) {
288 profiling::scope!("Device::create_texture");
289
290 let hub = &self.hub;
291
292 let fid = hub.textures.prepare(id_in);
293
294 let error = 'error: {
295 let device = self.hub.devices.get(device_id);
296
297 let texture = match device.create_texture(desc) {
298 Ok(texture) => texture,
299 Err(error) => break 'error error,
300 };
301
302 #[cfg(feature = "trace")]
303 if let Some(ref mut trace) = *device.trace.lock() {
304 trace.add(trace::Action::CreateTexture(
305 texture.to_trace(),
306 desc.clone(),
307 ));
308 }
309
310 let id = fid.assign(Fallible::Valid(texture));
311 api_log!("Device::create_texture({desc:?}) -> {id:?}");
312
313 return (id, None);
314 };
315
316 let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
317 (id, Some(error))
318 }
319
320 pub unsafe fn create_texture_from_hal(
328 &self,
329 hal_texture: Box<dyn hal::DynTexture>,
330 device_id: DeviceId,
331 desc: &resource::TextureDescriptor,
332 initial_state: wgt::TextureUses,
333 id_in: Option<id::TextureId>,
334 ) -> (id::TextureId, Option<resource::CreateTextureError>) {
335 profiling::scope!("Device::create_texture_from_hal");
336
337 let hub = &self.hub;
338
339 let fid = hub.textures.prepare(id_in);
340
341 let error = 'error: {
342 let device = self.hub.devices.get(device_id);
343
344 let texture = match device.create_texture_from_hal(hal_texture, desc, initial_state) {
345 Ok(texture) => texture,
346 Err(error) => break 'error error,
347 };
348
349 #[cfg(feature = "trace")]
352 if let Some(ref mut trace) = *device.trace.lock() {
353 trace.add(trace::Action::CreateTexture(
354 texture.to_trace(),
355 desc.clone(),
356 ));
357 }
358
359 let id = fid.assign(Fallible::Valid(texture));
360 api_log!("Device::create_texture({desc:?}) -> {id:?}");
361
362 return (id, None);
363 };
364
365 let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
366 (id, Some(error))
367 }
368
369 pub unsafe fn create_buffer_from_hal<A: hal::Api>(
376 &self,
377 hal_buffer: A::Buffer,
378 device_id: DeviceId,
379 desc: &resource::BufferDescriptor,
380 id_in: Option<id::BufferId>,
381 ) -> (id::BufferId, Option<CreateBufferError>) {
382 profiling::scope!("Device::create_buffer");
383
384 let hub = &self.hub;
385 let fid = hub.buffers.prepare(id_in);
386
387 let device = self.hub.devices.get(device_id);
388
389 let (buffer, err) = unsafe { device.create_buffer_from_hal(Box::new(hal_buffer), desc) };
390
391 #[cfg(feature = "trace")]
394 if let Some(trace) = device.trace.lock().as_mut() {
395 match &buffer {
396 Fallible::Valid(arc) => {
397 trace.add(trace::Action::CreateBuffer(arc.to_trace(), desc.clone()))
398 }
399 Fallible::Invalid(_) => {}
400 }
401 }
402
403 let id = fid.assign(buffer);
404 api_log!("Device::create_buffer -> {id:?}");
405
406 (id, err)
407 }
408
409 pub fn texture_destroy(&self, texture_id: id::TextureId) {
410 profiling::scope!("Texture::destroy");
411 api_log!("Texture::destroy {texture_id:?}");
412
413 let hub = &self.hub;
414
415 let Ok(texture) = hub.textures.get(texture_id).get() else {
416 return;
418 };
419
420 #[cfg(feature = "trace")]
421 if let Some(trace) = texture.device.trace.lock().as_mut() {
422 trace.add(trace::Action::FreeTexture(texture.to_trace()));
423 }
424
425 texture.destroy();
426 }
427
428 pub fn texture_drop(&self, texture_id: id::TextureId) {
429 profiling::scope!("Texture::drop");
430 api_log!("Texture::drop {texture_id:?}");
431
432 let hub = &self.hub;
433
434 let _texture = hub.textures.remove(texture_id);
435 #[cfg(feature = "trace")]
436 if let Ok(texture) = _texture.get() {
437 if let Some(t) = texture.device.trace.lock().as_mut() {
438 t.add(trace::Action::DestroyTexture(texture.to_trace()));
439 }
440 }
441 }
442
443 pub fn texture_create_view(
444 &self,
445 texture_id: id::TextureId,
446 desc: &resource::TextureViewDescriptor,
447 id_in: Option<id::TextureViewId>,
448 ) -> (id::TextureViewId, Option<resource::CreateTextureViewError>) {
449 profiling::scope!("Texture::create_view");
450
451 let hub = &self.hub;
452
453 let fid = hub.texture_views.prepare(id_in);
454
455 let error = 'error: {
456 let texture = match hub.textures.get(texture_id).get() {
457 Ok(texture) => texture,
458 Err(e) => break 'error e.into(),
459 };
460 let device = &texture.device;
461
462 let view = match device.create_texture_view(&texture, desc) {
463 Ok(view) => view,
464 Err(e) => break 'error e,
465 };
466
467 #[cfg(feature = "trace")]
468 if let Some(ref mut trace) = *device.trace.lock() {
469 trace.add(trace::Action::CreateTextureView {
470 id: view.to_trace(),
471 parent: texture.to_trace(),
472 desc: desc.clone(),
473 });
474 }
475
476 let id = fid.assign(Fallible::Valid(view));
477
478 api_log!("Texture::create_view({texture_id:?}) -> {id:?}");
479
480 return (id, None);
481 };
482
483 let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
484 (id, Some(error))
485 }
486
487 pub fn texture_view_drop(&self, texture_view_id: id::TextureViewId) {
488 profiling::scope!("TextureView::drop");
489 api_log!("TextureView::drop {texture_view_id:?}");
490
491 let hub = &self.hub;
492
493 let _view = hub.texture_views.remove(texture_view_id);
494
495 #[cfg(feature = "trace")]
496 if let Ok(view) = _view.get() {
497 if let Some(t) = view.device.trace.lock().as_mut() {
498 t.add(trace::Action::DestroyTextureView(view.to_trace()));
499 }
500 }
501 }
502
503 pub fn device_create_external_texture(
504 &self,
505 device_id: DeviceId,
506 desc: &resource::ExternalTextureDescriptor,
507 planes: &[id::TextureViewId],
508 id_in: Option<id::ExternalTextureId>,
509 ) -> (
510 id::ExternalTextureId,
511 Option<resource::CreateExternalTextureError>,
512 ) {
513 profiling::scope!("Device::create_external_texture");
514
515 let hub = &self.hub;
516
517 let fid = hub.external_textures.prepare(id_in);
518
519 let error = 'error: {
520 let device = self.hub.devices.get(device_id);
521
522 let planes = planes
523 .iter()
524 .map(|plane_id| self.hub.texture_views.get(*plane_id).get())
525 .collect::<Result<Vec<_>, _>>();
526 let planes = match planes {
527 Ok(planes) => planes,
528 Err(error) => break 'error error.into(),
529 };
530
531 let external_texture = match device.create_external_texture(desc, &planes) {
532 Ok(external_texture) => external_texture,
533 Err(error) => break 'error error,
534 };
535
536 #[cfg(feature = "trace")]
537 if let Some(ref mut trace) = *device.trace.lock() {
538 let planes = Box::from(
539 planes
540 .into_iter()
541 .map(|plane| plane.to_trace())
542 .collect::<Vec<_>>(),
543 );
544 trace.add(trace::Action::CreateExternalTexture {
545 id: external_texture.to_trace(),
546 desc: desc.clone(),
547 planes,
548 });
549 }
550
551 let id = fid.assign(Fallible::Valid(external_texture));
552 api_log!("Device::create_external_texture({desc:?}) -> {id:?}");
553
554 return (id, None);
555 };
556
557 let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
558 (id, Some(error))
559 }
560
561 pub fn external_texture_destroy(&self, external_texture_id: id::ExternalTextureId) {
562 profiling::scope!("ExternalTexture::destroy");
563 api_log!("ExternalTexture::destroy {external_texture_id:?}");
564
565 let hub = &self.hub;
566
567 let Ok(external_texture) = hub.external_textures.get(external_texture_id).get() else {
568 return;
570 };
571
572 #[cfg(feature = "trace")]
573 if let Some(trace) = external_texture.device.trace.lock().as_mut() {
574 trace.add(trace::Action::FreeExternalTexture(
575 external_texture.to_trace(),
576 ));
577 }
578
579 external_texture.destroy();
580 }
581
582 pub fn external_texture_drop(&self, external_texture_id: id::ExternalTextureId) {
583 profiling::scope!("ExternalTexture::drop");
584 api_log!("ExternalTexture::drop {external_texture_id:?}");
585
586 let hub = &self.hub;
587
588 let _external_texture = hub.external_textures.remove(external_texture_id);
589
590 #[cfg(feature = "trace")]
591 if let Ok(external_texture) = _external_texture.get() {
592 if let Some(t) = external_texture.device.trace.lock().as_mut() {
593 t.add(trace::Action::DestroyExternalTexture(
594 external_texture.to_trace(),
595 ));
596 }
597 }
598 }
599
600 pub fn device_create_sampler(
601 &self,
602 device_id: DeviceId,
603 desc: &resource::SamplerDescriptor,
604 id_in: Option<id::SamplerId>,
605 ) -> (id::SamplerId, Option<resource::CreateSamplerError>) {
606 profiling::scope!("Device::create_sampler");
607
608 let hub = &self.hub;
609 let fid = hub.samplers.prepare(id_in);
610
611 let error = 'error: {
612 let device = self.hub.devices.get(device_id);
613
614 let sampler = match device.create_sampler(desc) {
615 Ok(sampler) => sampler,
616 Err(e) => break 'error e,
617 };
618
619 #[cfg(feature = "trace")]
620 if let Some(ref mut trace) = *device.trace.lock() {
621 trace.add(trace::Action::CreateSampler(
622 sampler.to_trace(),
623 desc.clone(),
624 ));
625 }
626
627 let id = fid.assign(Fallible::Valid(sampler));
628 api_log!("Device::create_sampler -> {id:?}");
629
630 return (id, None);
631 };
632
633 let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
634 (id, Some(error))
635 }
636
637 pub fn sampler_drop(&self, sampler_id: id::SamplerId) {
638 profiling::scope!("Sampler::drop");
639 api_log!("Sampler::drop {sampler_id:?}");
640
641 let hub = &self.hub;
642
643 let _sampler = hub.samplers.remove(sampler_id);
644
645 #[cfg(feature = "trace")]
646 if let Ok(sampler) = _sampler.get() {
647 if let Some(t) = sampler.device.trace.lock().as_mut() {
648 t.add(trace::Action::DestroySampler(sampler.to_trace()));
649 }
650 }
651 }
652
653 pub fn device_create_bind_group_layout(
654 &self,
655 device_id: DeviceId,
656 desc: &binding_model::BindGroupLayoutDescriptor,
657 id_in: Option<id::BindGroupLayoutId>,
658 ) -> (
659 id::BindGroupLayoutId,
660 Option<binding_model::CreateBindGroupLayoutError>,
661 ) {
662 profiling::scope!("Device::create_bind_group_layout");
663
664 let hub = &self.hub;
665 let fid = hub.bind_group_layouts.prepare(id_in);
666
667 let error = 'error: {
668 let device = self.hub.devices.get(device_id);
669
670 let layout = match device.create_bind_group_layout(desc) {
671 Ok(layout) => layout,
672 Err(e) => break 'error e,
673 };
674
675 #[cfg(feature = "trace")]
676 if let Some(ref mut trace) = *device.trace.lock() {
677 trace.add(trace::Action::CreateBindGroupLayout(
678 layout.to_trace(),
679 desc.clone(),
680 ));
681 }
682
683 let id = fid.assign(Fallible::Valid(layout.clone()));
684
685 api_log!("Device::create_bind_group_layout -> {id:?}");
686 return (id, None);
687 };
688
689 let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
690 (id, Some(error))
691 }
692
693 pub fn bind_group_layout_drop(&self, bind_group_layout_id: id::BindGroupLayoutId) {
694 profiling::scope!("BindGroupLayout::drop");
695 api_log!("BindGroupLayout::drop {bind_group_layout_id:?}");
696
697 let hub = &self.hub;
698
699 let _layout = hub.bind_group_layouts.remove(bind_group_layout_id);
700
701 #[cfg(feature = "trace")]
702 if let Ok(layout) = _layout.get() {
703 if let Some(t) = layout.device.trace.lock().as_mut() {
704 t.add(trace::Action::DestroyBindGroupLayout(layout.to_trace()));
705 }
706 }
707 }
708
709 pub fn device_create_pipeline_layout(
710 &self,
711 device_id: DeviceId,
712 desc: &binding_model::PipelineLayoutDescriptor,
713 id_in: Option<id::PipelineLayoutId>,
714 ) -> (
715 id::PipelineLayoutId,
716 Option<binding_model::CreatePipelineLayoutError>,
717 ) {
718 profiling::scope!("Device::create_pipeline_layout");
719
720 let hub = &self.hub;
721 let fid = hub.pipeline_layouts.prepare(id_in);
722
723 let error = 'error: {
724 let device = self.hub.devices.get(device_id);
725
726 if let Err(e) = device.check_is_valid() {
727 break 'error e.into();
728 }
729
730 let bind_group_layouts = {
731 let bind_group_layouts_guard = hub.bind_group_layouts.read();
732 desc.bind_group_layouts
733 .iter()
734 .map(|bgl_id| match bgl_id {
735 Some(bgl_id) => bind_group_layouts_guard.get(*bgl_id).get().map(Some),
736 None => Ok(None),
737 })
738 .collect::<Result<Vec<_>, _>>()
739 };
740
741 let bind_group_layouts = match bind_group_layouts {
742 Ok(bind_group_layouts) => bind_group_layouts,
743 Err(e) => break 'error e.into(),
744 };
745
746 let desc = binding_model::ResolvedPipelineLayoutDescriptor {
747 label: desc.label.clone(),
748 bind_group_layouts: Cow::Owned(bind_group_layouts),
749 immediate_size: desc.immediate_size,
750 };
751
752 let layout = match device.create_pipeline_layout(&desc) {
753 Ok(layout) => layout,
754 Err(e) => break 'error e,
755 };
756
757 #[cfg(feature = "trace")]
758 if let Some(ref mut trace) = *device.trace.lock() {
759 trace.add(trace::Action::CreatePipelineLayout(
760 layout.to_trace(),
761 desc.to_trace(),
762 ));
763 }
764
765 let id = fid.assign(Fallible::Valid(layout));
766 api_log!("Device::create_pipeline_layout -> {id:?}");
767 return (id, None);
768 };
769
770 let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
771 (id, Some(error))
772 }
773
774 pub fn pipeline_layout_drop(&self, pipeline_layout_id: id::PipelineLayoutId) {
775 profiling::scope!("PipelineLayout::drop");
776 api_log!("PipelineLayout::drop {pipeline_layout_id:?}");
777
778 let hub = &self.hub;
779
780 let _layout = hub.pipeline_layouts.remove(pipeline_layout_id);
781
782 #[cfg(feature = "trace")]
783 if let Ok(layout) = _layout.get() {
784 if let Some(t) = layout.device.trace.lock().as_mut() {
785 t.add(trace::Action::DestroyPipelineLayout(layout.to_trace()));
786 }
787 }
788 }
789
790 pub fn device_create_bind_group(
791 &self,
792 device_id: DeviceId,
793 desc: &binding_model::BindGroupDescriptor,
794 id_in: Option<id::BindGroupId>,
795 ) -> (id::BindGroupId, Option<binding_model::CreateBindGroupError>) {
796 profiling::scope!("Device::create_bind_group");
797
798 let hub = &self.hub;
799 let fid = hub.bind_groups.prepare(id_in);
800
801 let error = 'error: {
802 let device = self.hub.devices.get(device_id);
803
804 if let Err(e) = device.check_is_valid() {
805 break 'error e.into();
806 }
807
808 let layout = match hub.bind_group_layouts.get(desc.layout).get() {
809 Ok(layout) => layout,
810 Err(e) => break 'error e.into(),
811 };
812
813 fn resolve_entry<'a>(
814 e: &BindGroupEntry<'a>,
815 buffer_storage: &Storage<Fallible<resource::Buffer>>,
816 sampler_storage: &Storage<Fallible<resource::Sampler>>,
817 texture_view_storage: &Storage<Fallible<resource::TextureView>>,
818 tlas_storage: &Storage<Fallible<resource::Tlas>>,
819 external_texture_storage: &Storage<Fallible<resource::ExternalTexture>>,
820 ) -> Result<ResolvedBindGroupEntry<'a>, binding_model::CreateBindGroupError>
821 {
822 let resolve_buffer = |bb: &BufferBinding| {
823 buffer_storage
824 .get(bb.buffer)
825 .get()
826 .map(|buffer| ResolvedBufferBinding {
827 buffer,
828 offset: bb.offset,
829 size: bb.size,
830 })
831 .map_err(binding_model::CreateBindGroupError::from)
832 };
833 let resolve_sampler = |id: &id::SamplerId| {
834 sampler_storage
835 .get(*id)
836 .get()
837 .map_err(binding_model::CreateBindGroupError::from)
838 };
839 let resolve_view = |id: &id::TextureViewId| {
840 texture_view_storage
841 .get(*id)
842 .get()
843 .map_err(binding_model::CreateBindGroupError::from)
844 };
845 let resolve_tlas = |id: &id::TlasId| {
846 tlas_storage
847 .get(*id)
848 .get()
849 .map_err(binding_model::CreateBindGroupError::from)
850 };
851 let resolve_external_texture = |id: &id::ExternalTextureId| {
852 external_texture_storage
853 .get(*id)
854 .get()
855 .map_err(binding_model::CreateBindGroupError::from)
856 };
857 let resource = match e.resource {
858 BindingResource::Buffer(ref buffer) => {
859 ResolvedBindingResource::Buffer(resolve_buffer(buffer)?)
860 }
861 BindingResource::BufferArray(ref buffers) => {
862 let buffers = buffers
863 .iter()
864 .map(resolve_buffer)
865 .collect::<Result<Vec<_>, _>>()?;
866 ResolvedBindingResource::BufferArray(Cow::Owned(buffers))
867 }
868 BindingResource::Sampler(ref sampler) => {
869 ResolvedBindingResource::Sampler(resolve_sampler(sampler)?)
870 }
871 BindingResource::SamplerArray(ref samplers) => {
872 let samplers = samplers
873 .iter()
874 .map(resolve_sampler)
875 .collect::<Result<Vec<_>, _>>()?;
876 ResolvedBindingResource::SamplerArray(Cow::Owned(samplers))
877 }
878 BindingResource::TextureView(ref view) => {
879 ResolvedBindingResource::TextureView(resolve_view(view)?)
880 }
881 BindingResource::TextureViewArray(ref views) => {
882 let views = views
883 .iter()
884 .map(resolve_view)
885 .collect::<Result<Vec<_>, _>>()?;
886 ResolvedBindingResource::TextureViewArray(Cow::Owned(views))
887 }
888 BindingResource::AccelerationStructure(ref tlas) => {
889 ResolvedBindingResource::AccelerationStructure(resolve_tlas(tlas)?)
890 }
891 BindingResource::AccelerationStructureArray(ref tlas_array) => {
892 let tlas_array = tlas_array
893 .iter()
894 .map(resolve_tlas)
895 .collect::<Result<Vec<_>, _>>()?;
896 ResolvedBindingResource::AccelerationStructureArray(Cow::Owned(tlas_array))
897 }
898 BindingResource::ExternalTexture(ref et) => {
899 ResolvedBindingResource::ExternalTexture(resolve_external_texture(et)?)
900 }
901 };
902 Ok(ResolvedBindGroupEntry {
903 binding: e.binding,
904 resource,
905 })
906 }
907
908 let entries = {
909 let buffer_guard = hub.buffers.read();
910 let texture_view_guard = hub.texture_views.read();
911 let sampler_guard = hub.samplers.read();
912 let tlas_guard = hub.tlas_s.read();
913 let external_texture_guard = hub.external_textures.read();
914 desc.entries
915 .iter()
916 .map(|e| {
917 resolve_entry(
918 e,
919 &buffer_guard,
920 &sampler_guard,
921 &texture_view_guard,
922 &tlas_guard,
923 &external_texture_guard,
924 )
925 })
926 .collect::<Result<Vec<_>, _>>()
927 };
928 let entries = match entries {
929 Ok(entries) => Cow::Owned(entries),
930 Err(e) => break 'error e,
931 };
932
933 let desc = ResolvedBindGroupDescriptor {
934 label: desc.label.clone(),
935 layout,
936 entries,
937 };
938 #[cfg(feature = "trace")]
939 let trace_desc = (&desc).to_trace();
940
941 let bind_group = match device.create_bind_group(desc) {
942 Ok(bind_group) => bind_group,
943 Err(e) => break 'error e,
944 };
945
946 #[cfg(feature = "trace")]
947 if let Some(ref mut trace) = *device.trace.lock() {
948 trace.add(trace::Action::CreateBindGroup(
949 bind_group.to_trace(),
950 trace_desc,
951 ));
952 }
953
954 let id = fid.assign(Fallible::Valid(bind_group));
955
956 api_log!("Device::create_bind_group -> {id:?}");
957
958 return (id, None);
959 };
960
961 let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
962 (id, Some(error))
963 }
964
965 pub fn bind_group_drop(&self, bind_group_id: id::BindGroupId) {
966 profiling::scope!("BindGroup::drop");
967 api_log!("BindGroup::drop {bind_group_id:?}");
968
969 let hub = &self.hub;
970
971 let _bind_group = hub.bind_groups.remove(bind_group_id);
972
973 #[cfg(feature = "trace")]
974 if let Ok(bind_group) = _bind_group.get() {
975 if let Some(t) = bind_group.device.trace.lock().as_mut() {
976 t.add(trace::Action::DestroyBindGroup(bind_group.to_trace()));
977 }
978 }
979 }
980
981 pub fn device_create_shader_module(
996 &self,
997 device_id: DeviceId,
998 desc: &pipeline::ShaderModuleDescriptor,
999 source: pipeline::ShaderModuleSource,
1000 id_in: Option<id::ShaderModuleId>,
1001 ) -> (
1002 id::ShaderModuleId,
1003 Option<pipeline::CreateShaderModuleError>,
1004 ) {
1005 profiling::scope!("Device::create_shader_module");
1006
1007 let hub = &self.hub;
1008 let fid = hub.shader_modules.prepare(id_in);
1009
1010 let error = 'error: {
1011 let device = self.hub.devices.get(device_id);
1012
1013 #[cfg(feature = "trace")]
1014 let data = device.trace.lock().as_mut().map(|trace| {
1015 use crate::device::trace::DataKind;
1016
1017 match source {
1018 #[cfg(feature = "wgsl")]
1019 pipeline::ShaderModuleSource::Wgsl(ref code) => {
1020 trace.make_binary(DataKind::Wgsl, code.as_bytes())
1021 }
1022 #[cfg(feature = "glsl")]
1023 pipeline::ShaderModuleSource::Glsl(ref code, _) => {
1024 trace.make_binary(DataKind::Glsl, code.as_bytes())
1025 }
1026 #[cfg(feature = "spirv")]
1027 pipeline::ShaderModuleSource::SpirV(ref code, _) => {
1028 trace.make_binary(DataKind::Spv, bytemuck::cast_slice::<u32, u8>(code))
1029 }
1030 pipeline::ShaderModuleSource::Naga(ref module) => {
1031 let string =
1032 ron::ser::to_string_pretty(module, ron::ser::PrettyConfig::default())
1033 .unwrap();
1034 trace.make_binary(DataKind::Ron, string.as_bytes())
1035 }
1036 pipeline::ShaderModuleSource::Dummy(_) => {
1037 panic!("found `ShaderModuleSource::Dummy`")
1038 }
1039 }
1040 });
1041
1042 let shader = match device.create_shader_module(desc, source) {
1043 Ok(shader) => shader,
1044 Err(e) => break 'error e,
1045 };
1046
1047 #[cfg(feature = "trace")]
1048 if let Some(data) = data {
1049 device
1051 .trace
1052 .lock()
1053 .as_mut()
1054 .expect("trace went away during create_shader_module?")
1055 .add(trace::Action::CreateShaderModule {
1056 id: shader.to_trace(),
1057 desc: desc.clone(),
1058 data,
1059 });
1060 };
1061
1062 let id = fid.assign(Fallible::Valid(shader));
1063 api_log!("Device::create_shader_module -> {id:?}");
1064 return (id, None);
1065 };
1066
1067 let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
1068 (id, Some(error))
1069 }
1070
1071 pub unsafe fn device_create_shader_module_passthrough(
1076 &self,
1077 device_id: DeviceId,
1078 desc: &pipeline::ShaderModuleDescriptorPassthrough<'_>,
1079 id_in: Option<id::ShaderModuleId>,
1080 ) -> (
1081 id::ShaderModuleId,
1082 Option<pipeline::CreateShaderModuleError>,
1083 ) {
1084 profiling::scope!("Device::create_shader_module_passthrough");
1085
1086 let hub = &self.hub;
1087 let fid = hub.shader_modules.prepare(id_in);
1088
1089 let error = 'error: {
1090 let device = self.hub.devices.get(device_id);
1091
1092 let result = unsafe { device.create_shader_module_passthrough(desc) };
1093
1094 let shader = match result {
1095 Ok(shader) => shader,
1096 Err(e) => break 'error e,
1097 };
1098
1099 #[cfg(feature = "trace")]
1100 if let Some(ref mut trace) = *device.trace.lock() {
1101 use crate::device::trace::DataKind;
1102
1103 let mut file_names = Vec::new();
1104 for (data, kind) in [
1105 (
1106 desc.spirv.as_ref().map(|a| bytemuck::cast_slice(a)),
1107 DataKind::Spv,
1108 ),
1109 (desc.dxil.as_deref(), DataKind::Dxil),
1110 (desc.hlsl.as_ref().map(|a| a.as_bytes()), DataKind::Hlsl),
1111 (desc.metallib.as_deref(), DataKind::MetalLib),
1112 (desc.msl.as_ref().map(|a| a.as_bytes()), DataKind::Msl),
1113 (desc.glsl.as_ref().map(|a| a.as_bytes()), DataKind::Glsl),
1114 (desc.wgsl.as_ref().map(|a| a.as_bytes()), DataKind::Wgsl),
1115 ] {
1116 if let Some(data) = data {
1117 file_names.push(trace.make_binary(kind, data));
1118 }
1119 }
1120 trace.add(trace::Action::CreateShaderModulePassthrough {
1121 id: shader.to_trace(),
1122 data: file_names,
1123 label: desc.label.clone(),
1124 entry_points: desc.entry_points.clone(),
1125 });
1126 };
1127
1128 let id = fid.assign(Fallible::Valid(shader));
1129 api_log!("Device::create_shader_module_spirv -> {id:?}");
1130 return (id, None);
1131 };
1132
1133 let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
1134 (id, Some(error))
1135 }
1136
1137 pub fn shader_module_drop(&self, shader_module_id: id::ShaderModuleId) {
1138 profiling::scope!("ShaderModule::drop");
1139 api_log!("ShaderModule::drop {shader_module_id:?}");
1140
1141 let hub = &self.hub;
1142
1143 let _shader_module = hub.shader_modules.remove(shader_module_id);
1144
1145 #[cfg(feature = "trace")]
1146 if let Ok(shader_module) = _shader_module.get() {
1147 if let Some(t) = shader_module.device.trace.lock().as_mut() {
1148 t.add(trace::Action::DestroyShaderModule(shader_module.to_trace()));
1149 }
1150 }
1151 }
1152
1153 pub fn device_create_command_encoder(
1154 &self,
1155 device_id: DeviceId,
1156 desc: &wgt::CommandEncoderDescriptor<Label>,
1157 id_in: Option<id::CommandEncoderId>,
1158 ) -> (id::CommandEncoderId, Option<DeviceError>) {
1159 profiling::scope!("Device::create_command_encoder");
1160
1161 let hub = &self.hub;
1162 let fid = hub.command_encoders.prepare(id_in);
1163
1164 let device = self.hub.devices.get(device_id);
1165
1166 let error = 'error: {
1167 let cmd_enc = match device.create_command_encoder(&desc.label) {
1168 Ok(cmd_enc) => cmd_enc,
1169 Err(e) => break 'error e,
1170 };
1171
1172 let id = fid.assign(cmd_enc);
1173 api_log!("Device::create_command_encoder -> {id:?}");
1174 return (id, None);
1175 };
1176
1177 let id = fid.assign(Arc::new(CommandEncoder::new_invalid(
1178 &device,
1179 &desc.label,
1180 error.clone().into(),
1181 )));
1182 (id, Some(error))
1183 }
1184
1185 pub fn command_encoder_drop(&self, command_encoder_id: id::CommandEncoderId) {
1186 profiling::scope!("CommandEncoder::drop");
1187 api_log!("CommandEncoder::drop {command_encoder_id:?}");
1188 let _cmd_enc = self.hub.command_encoders.remove(command_encoder_id);
1189 }
1190
1191 pub fn command_buffer_drop(&self, command_buffer_id: id::CommandBufferId) {
1192 profiling::scope!("CommandBuffer::drop");
1193 api_log!("CommandBuffer::drop {command_buffer_id:?}");
1194 let _cmd_buf = self.hub.command_buffers.remove(command_buffer_id);
1195 }
1196
1197 pub fn device_create_render_bundle_encoder(
1198 &self,
1199 device_id: DeviceId,
1200 desc: &command::RenderBundleEncoderDescriptor,
1201 ) -> (
1202 Box<command::RenderBundleEncoder>,
1203 Option<command::CreateRenderBundleError>,
1204 ) {
1205 profiling::scope!("Device::create_render_bundle_encoder");
1206 api_log!("Device::device_create_render_bundle_encoder");
1207 let device = self.hub.devices.get(device_id);
1208 let (encoder, error) =
1209 match command::RenderBundleEncoder::new(desc, Some(&device), device_id) {
1210 Ok(encoder) => (encoder, None),
1211 Err(e) => (command::RenderBundleEncoder::dummy(device_id), Some(e)),
1212 };
1213 (Box::new(encoder), error)
1214 }
1215
1216 pub fn render_bundle_encoder_finish(
1217 &self,
1218 bundle_encoder: Box<command::RenderBundleEncoder>,
1219 desc: &command::RenderBundleDescriptor,
1220 id_in: Option<id::RenderBundleId>,
1221 ) -> (id::RenderBundleId, Option<command::RenderBundleError>) {
1222 profiling::scope!("RenderBundleEncoder::finish");
1223
1224 let hub = &self.hub;
1225
1226 let fid = hub.render_bundles.prepare(id_in);
1227
1228 let error = 'error: {
1229 let device = self.hub.devices.get(bundle_encoder.parent());
1230
1231 #[cfg(feature = "trace")]
1232 let trace_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
1239 let render_bundle = match bundle_encoder.finish(desc, &device, hub) {
1240 Ok(bundle) => bundle,
1241 Err(e) => break 'error e,
1242 };
1243
1244 #[cfg(feature = "trace")]
1245 if let Some(ref mut trace) = *device.trace.lock() {
1246 trace.add(trace::Action::CreateRenderBundle {
1247 id: render_bundle.to_trace(),
1248 desc: trace_desc,
1249 base: render_bundle.to_base_pass().to_trace(),
1250 });
1251 }
1252
1253 let id = fid.assign(Fallible::Valid(render_bundle));
1254 api_log!("RenderBundleEncoder::finish -> {id:?}");
1255
1256 return (id, None);
1257 };
1258
1259 let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
1260 (id, Some(error))
1261 }
1262
1263 pub fn render_bundle_drop(&self, render_bundle_id: id::RenderBundleId) {
1264 profiling::scope!("RenderBundle::drop");
1265 api_log!("RenderBundle::drop {render_bundle_id:?}");
1266
1267 let hub = &self.hub;
1268
1269 let _bundle = hub.render_bundles.remove(render_bundle_id);
1270
1271 #[cfg(feature = "trace")]
1272 if let Ok(bundle) = _bundle.get() {
1273 if let Some(t) = bundle.device.trace.lock().as_mut() {
1274 t.add(trace::Action::DestroyRenderBundle(bundle.to_trace()));
1275 }
1276 }
1277 }
1278
1279 pub fn device_create_query_set(
1280 &self,
1281 device_id: DeviceId,
1282 desc: &resource::QuerySetDescriptor,
1283 id_in: Option<id::QuerySetId>,
1284 ) -> (id::QuerySetId, Option<resource::CreateQuerySetError>) {
1285 profiling::scope!("Device::create_query_set");
1286
1287 let hub = &self.hub;
1288 let fid = hub.query_sets.prepare(id_in);
1289
1290 let error = 'error: {
1291 let device = self.hub.devices.get(device_id);
1292
1293 let query_set = match device.create_query_set(desc) {
1294 Ok(query_set) => query_set,
1295 Err(err) => break 'error err,
1296 };
1297
1298 #[cfg(feature = "trace")]
1299 if let Some(ref mut trace) = *device.trace.lock() {
1300 trace.add(trace::Action::CreateQuerySet {
1301 id: query_set.to_trace(),
1302 desc: desc.clone(),
1303 });
1304 }
1305
1306 let id = fid.assign(Fallible::Valid(query_set));
1307 api_log!("Device::create_query_set -> {id:?}");
1308
1309 return (id, None);
1310 };
1311
1312 let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
1313 (id, Some(error))
1314 }
1315
1316 pub fn query_set_drop(&self, query_set_id: id::QuerySetId) {
1317 profiling::scope!("QuerySet::drop");
1318 api_log!("QuerySet::drop {query_set_id:?}");
1319
1320 let hub = &self.hub;
1321
1322 let _query_set = hub.query_sets.remove(query_set_id);
1323
1324 #[cfg(feature = "trace")]
1325 if let Ok(query_set) = _query_set.get() {
1326 if let Some(trace) = query_set.device.trace.lock().as_mut() {
1327 trace.add(trace::Action::DestroyQuerySet(query_set.to_trace()));
1328 }
1329 }
1330 }
1331
1332 pub fn device_create_render_pipeline(
1333 &self,
1334 device_id: DeviceId,
1335 desc: &pipeline::RenderPipelineDescriptor,
1336 id_in: Option<id::RenderPipelineId>,
1337 ) -> (
1338 id::RenderPipelineId,
1339 Option<pipeline::CreateRenderPipelineError>,
1340 ) {
1341 profiling::scope!("Device::create_render_pipeline");
1342
1343 let hub = &self.hub;
1344
1345 let fid = hub.render_pipelines.prepare(id_in);
1346
1347 let device = self.hub.devices.get(device_id);
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 self.device_create_general_render_pipeline(desc.clone().into(), device, fid)
1367 }
1368
1369 fn device_create_general_render_pipeline(
1370 &self,
1371 desc: pipeline::GeneralRenderPipelineDescriptor,
1372 device: Arc<crate::device::resource::Device>,
1373 fid: crate::registry::FutureId<Fallible<pipeline::RenderPipeline>>,
1374 ) -> (
1375 id::RenderPipelineId,
1376 Option<pipeline::CreateRenderPipelineError>,
1377 ) {
1378 profiling::scope!("Device::create_general_render_pipeline");
1379
1380 let hub = &self.hub;
1381
1382 let error = 'error: {
1383 if let Err(e) = device.check_is_valid() {
1384 break 'error e.into();
1385 }
1386
1387 let layout = desc
1388 .layout
1389 .map(|layout| hub.pipeline_layouts.get(layout).get())
1390 .transpose();
1391 let layout = match layout {
1392 Ok(layout) => layout,
1393 Err(e) => break 'error e.into(),
1394 };
1395
1396 let cache = desc
1397 .cache
1398 .map(|cache| hub.pipeline_caches.get(cache).get())
1399 .transpose();
1400 let cache = match cache {
1401 Ok(cache) => cache,
1402 Err(e) => break 'error e.into(),
1403 };
1404 let mut passthrough_stages = wgt::ShaderStages::empty();
1405
1406 let vertex = match desc.vertex {
1407 RenderPipelineVertexProcessor::Vertex(ref vertex) => {
1408 let module = hub
1409 .shader_modules
1410 .get(vertex.stage.module)
1411 .get()
1412 .map_err(|e| pipeline::CreateRenderPipelineError::Stage {
1413 stage: wgt::ShaderStages::VERTEX,
1414 error: e.into(),
1415 });
1416 let module = match module {
1417 Ok(module) => module,
1418 Err(e) => break 'error e,
1419 };
1420 if module.interface.interface().is_none() {
1421 passthrough_stages |= wgt::ShaderStages::VERTEX;
1422 }
1423 let stage = ResolvedProgrammableStageDescriptor {
1424 module,
1425 entry_point: vertex.stage.entry_point.clone(),
1426 constants: vertex.stage.constants.clone(),
1427 zero_initialize_workgroup_memory: vertex
1428 .stage
1429 .zero_initialize_workgroup_memory,
1430 };
1431 RenderPipelineVertexProcessor::Vertex(ResolvedVertexState {
1432 stage,
1433 buffers: vertex.buffers.clone(),
1434 })
1435 }
1436 RenderPipelineVertexProcessor::Mesh(ref task, ref mesh) => {
1437 let task_module = if let Some(task) = task {
1438 let module = hub
1439 .shader_modules
1440 .get(task.stage.module)
1441 .get()
1442 .map_err(|e| pipeline::CreateRenderPipelineError::Stage {
1443 stage: wgt::ShaderStages::VERTEX,
1444 error: e.into(),
1445 });
1446 let module = match module {
1447 Ok(module) => module,
1448 Err(e) => break 'error e,
1449 };
1450 if module.interface.interface().is_none() {
1451 passthrough_stages |= wgt::ShaderStages::TASK;
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 if mesh_module.interface.interface().is_none() {
1478 passthrough_stages |= wgt::ShaderStages::VERTEX;
1479 }
1480 let mesh_stage = ResolvedProgrammableStageDescriptor {
1481 module: mesh_module,
1482 entry_point: mesh.stage.entry_point.clone(),
1483 constants: mesh.stage.constants.clone(),
1484 zero_initialize_workgroup_memory: mesh
1485 .stage
1486 .zero_initialize_workgroup_memory,
1487 };
1488 RenderPipelineVertexProcessor::Mesh(
1489 task_module,
1490 ResolvedMeshState { stage: mesh_stage },
1491 )
1492 }
1493 };
1494
1495 let fragment = if let Some(ref state) = desc.fragment {
1496 let module = hub
1497 .shader_modules
1498 .get(state.stage.module)
1499 .get()
1500 .map_err(|e| pipeline::CreateRenderPipelineError::Stage {
1501 stage: wgt::ShaderStages::FRAGMENT,
1502 error: e.into(),
1503 });
1504 let module = match module {
1505 Ok(module) => module,
1506 Err(e) => break 'error e,
1507 };
1508 if module.interface.interface().is_none() {
1509 passthrough_stages |= wgt::ShaderStages::FRAGMENT;
1510 }
1511 let stage = ResolvedProgrammableStageDescriptor {
1512 module,
1513 entry_point: state.stage.entry_point.clone(),
1514 constants: state.stage.constants.clone(),
1515 zero_initialize_workgroup_memory: state.stage.zero_initialize_workgroup_memory,
1516 };
1517 Some(ResolvedFragmentState {
1518 stage,
1519 targets: state.targets.clone(),
1520 })
1521 } else {
1522 None
1523 };
1524
1525 if !passthrough_stages.is_empty() && layout.is_none() {
1526 break 'error pipeline::CreateRenderPipelineError::Implicit(
1527 pipeline::ImplicitLayoutError::Passthrough(passthrough_stages),
1528 );
1529 }
1530
1531 let desc = ResolvedGeneralRenderPipelineDescriptor {
1532 label: desc.label.clone(),
1533 layout,
1534 vertex,
1535 primitive: desc.primitive,
1536 depth_stencil: desc.depth_stencil.clone(),
1537 multisample: desc.multisample,
1538 fragment,
1539 multiview_mask: desc.multiview_mask,
1540 cache,
1541 };
1542
1543 #[cfg(feature = "trace")]
1544 let trace_desc = desc.clone().into_trace();
1545
1546 let res = device.create_render_pipeline(desc);
1547
1548 #[cfg(feature = "trace")]
1549 if let Some(ref mut trace) = *device.trace.lock() {
1550 trace.add(trace::Action::CreateGeneralRenderPipeline {
1551 id: res.as_ref().ok().map(IntoTrace::to_trace),
1552 desc: trace_desc,
1553 });
1554 }
1555
1556 let pipeline = match res {
1557 Ok(pair) => pair,
1558 Err(e) => break 'error e,
1559 };
1560
1561 let id = fid.assign(Fallible::Valid(pipeline));
1562 api_log!("Device::create_render_pipeline -> {id:?}");
1563
1564 return (id, None);
1565 };
1566
1567 let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
1568
1569 (id, Some(error))
1570 }
1571
1572 pub fn render_pipeline_get_bind_group_layout(
1575 &self,
1576 pipeline_id: id::RenderPipelineId,
1577 index: u32,
1578 id_in: Option<id::BindGroupLayoutId>,
1579 ) -> (
1580 id::BindGroupLayoutId,
1581 Option<binding_model::GetBindGroupLayoutError>,
1582 ) {
1583 let hub = &self.hub;
1584
1585 let fid = hub.bind_group_layouts.prepare(id_in);
1586
1587 let error = 'error: {
1588 let pipeline = match hub.render_pipelines.get(pipeline_id).get() {
1589 Ok(pipeline) => pipeline,
1590 Err(e) => break 'error e.into(),
1591 };
1592 match pipeline.get_bind_group_layout(index) {
1593 Ok(bgl) => {
1594 #[cfg(feature = "trace")]
1595 if let Some(ref mut trace) = *pipeline.device.trace.lock() {
1596 trace.add(trace::Action::GetRenderPipelineBindGroupLayout {
1597 id: bgl.to_trace(),
1598 pipeline: pipeline.to_trace(),
1599 index,
1600 });
1601 }
1602
1603 let id = fid.assign(Fallible::Valid(bgl.clone()));
1604 return (id, None);
1605 }
1606 Err(err) => break 'error err,
1607 };
1608 };
1609
1610 let id = fid.assign(Fallible::Invalid(Arc::new(String::new())));
1611 (id, Some(error))
1612 }
1613
1614 pub fn render_pipeline_drop(&self, render_pipeline_id: id::RenderPipelineId) {
1615 profiling::scope!("RenderPipeline::drop");
1616 api_log!("RenderPipeline::drop {render_pipeline_id:?}");
1617
1618 let hub = &self.hub;
1619
1620 let _pipeline = hub.render_pipelines.remove(render_pipeline_id);
1621
1622 #[cfg(feature = "trace")]
1623 if let Ok(pipeline) = _pipeline.get() {
1624 if let Some(t) = pipeline.device.trace.lock().as_mut() {
1625 t.add(trace::Action::DestroyRenderPipeline(pipeline.to_trace()));
1626 }
1627 }
1628 }
1629
1630 pub fn device_create_compute_pipeline(
1631 &self,
1632 device_id: DeviceId,
1633 desc: &pipeline::ComputePipelineDescriptor,
1634 id_in: Option<id::ComputePipelineId>,
1635 ) -> (
1636 id::ComputePipelineId,
1637 Option<pipeline::CreateComputePipelineError>,
1638 ) {
1639 profiling::scope!("Device::create_compute_pipeline");
1640
1641 let hub = &self.hub;
1642
1643 let fid = hub.compute_pipelines.prepare(id_in);
1644
1645 let error = 'error: {
1646 let device = self.hub.devices.get(device_id);
1647
1648 if let Err(e) = device.check_is_valid() {
1649 break 'error e.into();
1650 }
1651
1652 let layout = desc
1653 .layout
1654 .map(|layout| hub.pipeline_layouts.get(layout).get())
1655 .transpose();
1656 let layout = match layout {
1657 Ok(layout) => layout,
1658 Err(e) => break 'error e.into(),
1659 };
1660
1661 let cache = desc
1662 .cache
1663 .map(|cache| hub.pipeline_caches.get(cache).get())
1664 .transpose();
1665 let cache = match cache {
1666 Ok(cache) => cache,
1667 Err(e) => break 'error e.into(),
1668 };
1669
1670 let module = hub.shader_modules.get(desc.stage.module).get();
1671 let module = match module {
1672 Ok(module) => module,
1673 Err(e) => break 'error e.into(),
1674 };
1675 if module.interface.interface().is_none() && layout.is_none() {
1676 break 'error pipeline::CreateComputePipelineError::Implicit(
1677 pipeline::ImplicitLayoutError::Passthrough(wgt::ShaderStages::COMPUTE),
1678 );
1679 }
1680 let stage = ResolvedProgrammableStageDescriptor {
1681 module,
1682 entry_point: desc.stage.entry_point.clone(),
1683 constants: desc.stage.constants.clone(),
1684 zero_initialize_workgroup_memory: desc.stage.zero_initialize_workgroup_memory,
1685 };
1686
1687 let desc = ResolvedComputePipelineDescriptor {
1688 label: desc.label.clone(),
1689 layout,
1690 stage,
1691 cache,
1692 };
1693
1694 #[cfg(feature = "trace")]
1695 let trace_desc = desc.clone().into_trace();
1696
1697 let res = device.create_compute_pipeline(desc);
1698
1699 #[cfg(feature = "trace")]
1700 if let Some(ref mut trace) = *device.trace.lock() {
1701 trace.add(trace::Action::CreateComputePipeline {
1702 id: res.as_ref().ok().map(IntoTrace::to_trace),
1703 desc: trace_desc,
1704 });
1705 }
1706
1707 let pipeline = match res {
1708 Ok(pair) => pair,
1709 Err(e) => break 'error e,
1710 };
1711
1712 let id = fid.assign(Fallible::Valid(pipeline));
1713 api_log!("Device::create_compute_pipeline -> {id:?}");
1714
1715 return (id, None);
1716 };
1717
1718 let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
1719
1720 (id, Some(error))
1721 }
1722
1723 pub fn compute_pipeline_get_bind_group_layout(
1726 &self,
1727 pipeline_id: id::ComputePipelineId,
1728 index: u32,
1729 id_in: Option<id::BindGroupLayoutId>,
1730 ) -> (
1731 id::BindGroupLayoutId,
1732 Option<binding_model::GetBindGroupLayoutError>,
1733 ) {
1734 let hub = &self.hub;
1735
1736 let fid = hub.bind_group_layouts.prepare(id_in);
1737
1738 let error = 'error: {
1739 let pipeline = match hub.compute_pipelines.get(pipeline_id).get() {
1740 Ok(pipeline) => pipeline,
1741 Err(e) => break 'error e.into(),
1742 };
1743
1744 match pipeline.get_bind_group_layout(index) {
1745 Ok(bgl) => {
1746 #[cfg(feature = "trace")]
1747 if let Some(ref mut trace) = *pipeline.device.trace.lock() {
1748 trace.add(trace::Action::GetComputePipelineBindGroupLayout {
1749 id: bgl.to_trace(),
1750 pipeline: pipeline.to_trace(),
1751 index,
1752 });
1753 }
1754
1755 let id = fid.assign(Fallible::Valid(bgl.clone()));
1756 return (id, None);
1757 }
1758 Err(err) => break 'error err,
1759 };
1760 };
1761
1762 let id = fid.assign(Fallible::Invalid(Arc::new(String::new())));
1763 (id, Some(error))
1764 }
1765
1766 pub fn compute_pipeline_drop(&self, compute_pipeline_id: id::ComputePipelineId) {
1767 profiling::scope!("ComputePipeline::drop");
1768 api_log!("ComputePipeline::drop {compute_pipeline_id:?}");
1769
1770 let hub = &self.hub;
1771
1772 let _pipeline = hub.compute_pipelines.remove(compute_pipeline_id);
1773
1774 #[cfg(feature = "trace")]
1775 if let Ok(pipeline) = _pipeline.get() {
1776 if let Some(t) = pipeline.device.trace.lock().as_mut() {
1777 t.add(trace::Action::DestroyComputePipeline(pipeline.to_trace()));
1778 }
1779 }
1780 }
1781
1782 pub unsafe fn device_create_pipeline_cache(
1786 &self,
1787 device_id: DeviceId,
1788 desc: &pipeline::PipelineCacheDescriptor<'_>,
1789 id_in: Option<id::PipelineCacheId>,
1790 ) -> (
1791 id::PipelineCacheId,
1792 Option<pipeline::CreatePipelineCacheError>,
1793 ) {
1794 profiling::scope!("Device::create_pipeline_cache");
1795
1796 let hub = &self.hub;
1797
1798 let fid = hub.pipeline_caches.prepare(id_in);
1799 let error: pipeline::CreatePipelineCacheError = 'error: {
1800 let device = self.hub.devices.get(device_id);
1801
1802 let cache = unsafe { device.create_pipeline_cache(desc) };
1803 match cache {
1804 Ok(cache) => {
1805 #[cfg(feature = "trace")]
1806 if let Some(ref mut trace) = *device.trace.lock() {
1807 trace.add(trace::Action::CreatePipelineCache {
1808 id: cache.to_trace(),
1809 desc: desc.clone(),
1810 });
1811 }
1812
1813 let id = fid.assign(Fallible::Valid(cache));
1814 api_log!("Device::create_pipeline_cache -> {id:?}");
1815 return (id, None);
1816 }
1817 Err(e) => break 'error e,
1818 }
1819 };
1820
1821 let id = fid.assign(Fallible::Invalid(Arc::new(desc.label.to_string())));
1822
1823 (id, Some(error))
1824 }
1825
1826 pub fn pipeline_cache_drop(&self, pipeline_cache_id: id::PipelineCacheId) {
1827 profiling::scope!("PipelineCache::drop");
1828 api_log!("PipelineCache::drop {pipeline_cache_id:?}");
1829
1830 let hub = &self.hub;
1831
1832 let _cache = hub.pipeline_caches.remove(pipeline_cache_id);
1833
1834 #[cfg(feature = "trace")]
1835 if let Ok(cache) = _cache.get() {
1836 if let Some(t) = cache.device.trace.lock().as_mut() {
1837 t.add(trace::Action::DestroyPipelineCache(cache.to_trace()));
1838 }
1839 }
1840 }
1841
1842 pub fn surface_configure(
1843 &self,
1844 surface_id: SurfaceId,
1845 device_id: DeviceId,
1846 config: &wgt::SurfaceConfiguration<Vec<TextureFormat>>,
1847 ) -> Option<present::ConfigureSurfaceError> {
1848 let device = self.hub.devices.get(device_id);
1849 let surface = self.surfaces.get(surface_id);
1850
1851 #[cfg(feature = "trace")]
1852 if let Some(ref mut trace) = *device.trace.lock() {
1853 trace.add(trace::Action::ConfigureSurface(
1854 surface.to_trace(),
1855 config.clone(),
1856 ));
1857 }
1858
1859 device.configure_surface(&surface, config)
1860 }
1861
1862 pub fn device_poll(
1866 &self,
1867 device_id: DeviceId,
1868 poll_type: wgt::PollType<crate::SubmissionIndex>,
1869 ) -> Result<wgt::PollStatus, WaitIdleError> {
1870 api_log!("Device::poll {poll_type:?}");
1871
1872 let device = self.hub.devices.get(device_id);
1873
1874 let (closures, result) = device.poll_and_return_closures(poll_type);
1875
1876 closures.fire();
1877
1878 result
1879 }
1880
1881 fn poll_all_devices_of_api(
1888 &self,
1889 force_wait: bool,
1890 closure_list: &mut UserClosures,
1891 ) -> Result<bool, WaitIdleError> {
1892 profiling::scope!("poll_device");
1893
1894 let hub = &self.hub;
1895 let mut all_queue_empty = true;
1896 {
1897 let device_guard = hub.devices.read();
1898
1899 for (_id, device) in device_guard.iter() {
1900 let poll_type = if force_wait {
1901 wgt::PollType::wait_indefinitely()
1903 } else {
1904 wgt::PollType::Poll
1905 };
1906
1907 let (closures, result) = device.poll_and_return_closures(poll_type);
1908
1909 let is_queue_empty = matches!(result, Ok(wgt::PollStatus::QueueEmpty));
1910
1911 all_queue_empty &= is_queue_empty;
1912
1913 closure_list.extend(closures);
1914 }
1915 }
1916
1917 Ok(all_queue_empty)
1918 }
1919
1920 pub fn poll_all_devices(&self, force_wait: bool) -> Result<bool, WaitIdleError> {
1927 api_log!("poll_all_devices");
1928 let mut closures = UserClosures::default();
1929 let all_queue_empty = self.poll_all_devices_of_api(force_wait, &mut closures)?;
1930
1931 closures.fire();
1932
1933 Ok(all_queue_empty)
1934 }
1935
1936 pub unsafe fn device_start_graphics_debugger_capture(&self, device_id: DeviceId) {
1942 unsafe {
1943 self.hub
1944 .devices
1945 .get(device_id)
1946 .start_graphics_debugger_capture();
1947 }
1948 }
1949
1950 pub unsafe fn device_stop_graphics_debugger_capture(&self, device_id: DeviceId) {
1956 unsafe {
1957 self.hub
1958 .devices
1959 .get(device_id)
1960 .stop_graphics_debugger_capture();
1961 }
1962 }
1963
1964 pub fn pipeline_cache_get_data(&self, id: id::PipelineCacheId) -> Option<Vec<u8>> {
1965 use crate::pipeline_cache;
1966 api_log!("PipelineCache::get_data");
1967 let hub = &self.hub;
1968
1969 if let Ok(cache) = hub.pipeline_caches.get(id).get() {
1970 if !cache.device.is_valid() {
1972 return None;
1973 }
1974 let mut vec = unsafe { cache.device.raw().pipeline_cache_get_data(cache.raw()) }?;
1975 let validation_key = cache.device.raw().pipeline_cache_validation_key()?;
1976
1977 let mut header_contents = [0; pipeline_cache::HEADER_LENGTH];
1978 pipeline_cache::add_cache_header(
1979 &mut header_contents,
1980 &vec,
1981 &cache.device.adapter.raw.info,
1982 validation_key,
1983 );
1984
1985 let deleted = vec.splice(..0, header_contents).collect::<Vec<_>>();
1986 debug_assert!(deleted.is_empty());
1987
1988 return Some(vec);
1989 }
1990 None
1991 }
1992
1993 pub fn device_drop(&self, device_id: DeviceId) {
1994 profiling::scope!("Device::drop");
1995 api_log!("Device::drop {device_id:?}");
1996
1997 self.hub.devices.remove(device_id);
1998 }
1999
2000 pub fn device_set_device_lost_closure(
2002 &self,
2003 device_id: DeviceId,
2004 device_lost_closure: DeviceLostClosure,
2005 ) {
2006 let device = self.hub.devices.get(device_id);
2007
2008 device
2009 .device_lost_closure
2010 .lock()
2011 .replace(device_lost_closure);
2012 }
2013
2014 pub fn device_destroy(&self, device_id: DeviceId) {
2015 api_log!("Device::destroy {device_id:?}");
2016
2017 let device = self.hub.devices.get(device_id);
2018
2019 if !device.is_valid() {
2025 return;
2026 }
2027
2028 device.valid.store(false, Ordering::Release);
2036 }
2037
2038 pub fn device_get_internal_counters(&self, device_id: DeviceId) -> wgt::InternalCounters {
2039 let device = self.hub.devices.get(device_id);
2040 wgt::InternalCounters {
2041 hal: device.get_hal_counters(),
2042 core: wgt::CoreCounters {},
2043 }
2044 }
2045
2046 pub fn device_generate_allocator_report(
2047 &self,
2048 device_id: DeviceId,
2049 ) -> Option<wgt::AllocatorReport> {
2050 let device = self.hub.devices.get(device_id);
2051 device.generate_allocator_report()
2052 }
2053
2054 #[cfg(feature = "trace")]
2055 pub fn device_take_trace(
2056 &self,
2057 device_id: DeviceId,
2058 ) -> Option<Box<dyn trace::Trace + Send + Sync + 'static>> {
2059 let device = self.hub.devices.get(device_id);
2060 device.take_trace()
2061 }
2062
2063 pub fn queue_drop(&self, queue_id: QueueId) {
2064 profiling::scope!("Queue::drop");
2065 api_log!("Queue::drop {queue_id:?}");
2066
2067 self.hub.queues.remove(queue_id);
2068 }
2069
2070 pub fn buffer_map_async(
2072 &self,
2073 buffer_id: id::BufferId,
2074 offset: BufferAddress,
2075 size: Option<BufferAddress>,
2076 op: BufferMapOperation,
2077 ) -> Result<crate::SubmissionIndex, BufferAccessError> {
2078 profiling::scope!("Buffer::map_async");
2079 api_log!("Buffer::map_async {buffer_id:?} offset {offset:?} size {size:?} op: {op:?}");
2080
2081 let hub = &self.hub;
2082
2083 let buffer = match hub.buffers.get(buffer_id).get() {
2084 Ok(buffer) => buffer,
2085 Err(err) => {
2086 if let Some(callback) = op.callback {
2087 callback(Err(err.clone().into()));
2088 }
2089 return Err(err.into());
2090 }
2091 };
2092
2093 buffer.map_async(offset, size, op)
2094 }
2095
2096 pub fn buffer_get_mapped_range(
2097 &self,
2098 buffer_id: id::BufferId,
2099 offset: BufferAddress,
2100 size: Option<BufferAddress>,
2101 ) -> Result<(NonNull<u8>, u64), BufferAccessError> {
2102 profiling::scope!("Buffer::get_mapped_range");
2103 api_log!("Buffer::get_mapped_range {buffer_id:?} offset {offset:?} size {size:?}");
2104
2105 let hub = &self.hub;
2106
2107 let buffer = hub.buffers.get(buffer_id).get()?;
2108
2109 buffer.get_mapped_range(offset, size)
2110 }
2111
2112 pub fn buffer_unmap(&self, buffer_id: id::BufferId) -> BufferAccessResult {
2113 profiling::scope!("unmap", "Buffer");
2114 api_log!("Buffer::unmap {buffer_id:?}");
2115
2116 let hub = &self.hub;
2117
2118 let buffer = hub.buffers.get(buffer_id).get()?;
2119
2120 let snatch_guard = buffer.device.snatchable_lock.read();
2121 buffer.check_destroyed(&snatch_guard)?;
2122 drop(snatch_guard);
2123
2124 buffer.device.check_is_valid()?;
2125 buffer.unmap()
2126 }
2127}