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