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