1#[cfg(feature = "trace")]
2use crate::device::trace;
3use crate::{
4 api_log, binding_model, command, conv,
5 device::{
6 bgl, life::WaitIdleError, map_buffer, queue, DeviceError, DeviceLostClosure,
7 DeviceLostReason, HostMap, IMPLICIT_BIND_GROUP_LAYOUT_ERROR_LABEL,
8 },
9 global::Global,
10 hal_api::HalApi,
11 id::{self, AdapterId, DeviceId, QueueId, SurfaceId},
12 init_tracker::TextureInitTracker,
13 instance::{self, Adapter, Surface},
14 lock::{rank, RwLock},
15 pipeline, present,
16 resource::{self, BufferAccessResult},
17 resource::{BufferAccessError, BufferMapOperation, CreateBufferError, Resource},
18 validation::check_buffer_usage,
19 Label, LabelHelpers as _,
20};
21
22use arrayvec::ArrayVec;
23use hal::Device as _;
24
25use wgt::{BufferAddress, TextureFormat};
26
27use std::{
28 borrow::Cow,
29 iter, ptr,
30 sync::{atomic::Ordering, Arc},
31};
32
33use super::{ImplicitPipelineIds, InvalidDevice, UserClosures};
34
35impl Global {
36 pub fn adapter_is_surface_supported<A: HalApi>(
37 &self,
38 adapter_id: AdapterId,
39 surface_id: SurfaceId,
40 ) -> Result<bool, instance::IsSurfaceSupportedError> {
41 let hub = A::hub(self);
42
43 let surface_guard = self.surfaces.read();
44 let adapter_guard = hub.adapters.read();
45 let adapter = adapter_guard
46 .get(adapter_id)
47 .map_err(|_| instance::IsSurfaceSupportedError::InvalidAdapter)?;
48 let surface = surface_guard
49 .get(surface_id)
50 .map_err(|_| instance::IsSurfaceSupportedError::InvalidSurface)?;
51 Ok(adapter.is_surface_supported(surface))
52 }
53
54 pub fn surface_get_capabilities<A: HalApi>(
55 &self,
56 surface_id: SurfaceId,
57 adapter_id: AdapterId,
58 ) -> Result<wgt::SurfaceCapabilities, instance::GetSurfaceSupportError> {
59 profiling::scope!("Surface::get_capabilities");
60 self.fetch_adapter_and_surface::<A, _, _>(surface_id, adapter_id, |adapter, surface| {
61 let mut hal_caps = surface.get_capabilities(adapter)?;
62
63 hal_caps.formats.sort_by_key(|f| !f.is_srgb());
64
65 let usages = conv::map_texture_usage_from_hal(hal_caps.usage);
66
67 Ok(wgt::SurfaceCapabilities {
68 formats: hal_caps.formats,
69 present_modes: hal_caps.present_modes,
70 alpha_modes: hal_caps.composite_alpha_modes,
71 usages,
72 })
73 })
74 }
75
76 fn fetch_adapter_and_surface<
77 A: HalApi,
78 F: FnOnce(&Adapter<A>, &Surface) -> Result<B, instance::GetSurfaceSupportError>,
79 B,
80 >(
81 &self,
82 surface_id: SurfaceId,
83 adapter_id: AdapterId,
84 get_supported_callback: F,
85 ) -> Result<B, instance::GetSurfaceSupportError> {
86 let hub = A::hub(self);
87
88 let surface_guard = self.surfaces.read();
89 let adapter_guard = hub.adapters.read();
90 let adapter = adapter_guard
91 .get(adapter_id)
92 .map_err(|_| instance::GetSurfaceSupportError::InvalidAdapter)?;
93 let surface = surface_guard
94 .get(surface_id)
95 .map_err(|_| instance::GetSurfaceSupportError::InvalidSurface)?;
96
97 get_supported_callback(adapter, surface)
98 }
99
100 pub fn device_features<A: HalApi>(
101 &self,
102 device_id: DeviceId,
103 ) -> Result<wgt::Features, InvalidDevice> {
104 let hub = A::hub(self);
105
106 let device = hub.devices.get(device_id).map_err(|_| InvalidDevice)?;
107 if !device.is_valid() {
108 return Err(InvalidDevice);
109 }
110
111 Ok(device.features)
112 }
113
114 pub fn device_limits<A: HalApi>(
115 &self,
116 device_id: DeviceId,
117 ) -> Result<wgt::Limits, InvalidDevice> {
118 let hub = A::hub(self);
119
120 let device = hub.devices.get(device_id).map_err(|_| InvalidDevice)?;
121 if !device.is_valid() {
122 return Err(InvalidDevice);
123 }
124
125 Ok(device.limits.clone())
126 }
127
128 pub fn device_downlevel_properties<A: HalApi>(
129 &self,
130 device_id: DeviceId,
131 ) -> Result<wgt::DownlevelCapabilities, InvalidDevice> {
132 let hub = A::hub(self);
133
134 let device = hub.devices.get(device_id).map_err(|_| InvalidDevice)?;
135 if !device.is_valid() {
136 return Err(InvalidDevice);
137 }
138
139 Ok(device.downlevel.clone())
140 }
141
142 pub fn device_create_buffer<A: HalApi>(
143 &self,
144 device_id: DeviceId,
145 desc: &resource::BufferDescriptor,
146 id_in: Option<id::BufferId>,
147 ) -> (id::BufferId, Option<CreateBufferError>) {
148 profiling::scope!("Device::create_buffer");
149
150 let hub = A::hub(self);
151 let fid = hub.buffers.prepare(id_in);
152
153 let mut to_destroy: ArrayVec<resource::Buffer<A>, 2> = ArrayVec::new();
154 let error = loop {
155 let device = match hub.devices.get(device_id) {
156 Ok(device) => device,
157 Err(_) => {
158 break DeviceError::Invalid.into();
159 }
160 };
161 if !device.is_valid() {
162 break DeviceError::Lost.into();
163 }
164
165 if desc.usage.is_empty() {
166 break CreateBufferError::InvalidUsage(desc.usage);
168 }
169
170 #[cfg(feature = "trace")]
171 if let Some(ref mut trace) = *device.trace.lock() {
172 let mut desc = desc.clone();
173 let mapped_at_creation = std::mem::replace(&mut desc.mapped_at_creation, false);
174 if mapped_at_creation && !desc.usage.contains(wgt::BufferUsages::MAP_WRITE) {
175 desc.usage |= wgt::BufferUsages::COPY_DST;
176 }
177 trace.add(trace::Action::CreateBuffer(fid.id(), desc));
178 }
179
180 let buffer = match device.create_buffer(desc, false) {
181 Ok(buffer) => buffer,
182 Err(e) => {
183 break e;
184 }
185 };
186
187 let buffer_use = if !desc.mapped_at_creation {
188 hal::BufferUses::empty()
189 } else if desc.usage.contains(wgt::BufferUsages::MAP_WRITE) {
190 let map_size = buffer.size;
192 let ptr = if map_size == 0 {
193 std::ptr::NonNull::dangling()
194 } else {
195 let snatch_guard = device.snatchable_lock.read();
196 match map_buffer(
197 device.raw(),
198 &buffer,
199 0,
200 map_size,
201 HostMap::Write,
202 &snatch_guard,
203 ) {
204 Ok(ptr) => ptr,
205 Err(e) => {
206 to_destroy.push(buffer);
207 break e.into();
208 }
209 }
210 };
211 *buffer.map_state.lock() = resource::BufferMapState::Active {
212 ptr,
213 range: 0..map_size,
214 host: HostMap::Write,
215 };
216 hal::BufferUses::MAP_WRITE
217 } else {
218 let stage_desc = wgt::BufferDescriptor {
220 label: Some(Cow::Borrowed(
221 "(wgpu internal) initializing unmappable buffer",
222 )),
223 size: desc.size,
224 usage: wgt::BufferUsages::MAP_WRITE | wgt::BufferUsages::COPY_SRC,
225 mapped_at_creation: false,
226 };
227 let stage = match device.create_buffer(&stage_desc, true) {
228 Ok(stage) => Arc::new(stage),
229 Err(e) => {
230 to_destroy.push(buffer);
231 break e;
232 }
233 };
234
235 let snatch_guard = device.snatchable_lock.read();
236 let stage_raw = stage.raw(&snatch_guard).unwrap();
237 let mapping = match unsafe { device.raw().map_buffer(stage_raw, 0..stage.size) } {
238 Ok(mapping) => mapping,
239 Err(e) => {
240 to_destroy.push(buffer);
241 break CreateBufferError::Device(e.into());
242 }
243 };
244
245 assert_eq!(buffer.size % wgt::COPY_BUFFER_ALIGNMENT, 0);
246 unsafe { ptr::write_bytes(mapping.ptr.as_ptr(), 0, buffer.size as usize) };
249 buffer.initialization_status.write().drain(0..buffer.size);
250 stage.initialization_status.write().drain(0..buffer.size);
251
252 *buffer.map_state.lock() = resource::BufferMapState::Init {
253 ptr: mapping.ptr,
254 needs_flush: !mapping.is_coherent,
255 stage_buffer: stage,
256 };
257 hal::BufferUses::COPY_DST
258 };
259
260 let (id, resource) = fid.assign(Arc::new(buffer));
261 api_log!("Device::create_buffer({desc:?}) -> {id:?}");
262
263 device
264 .trackers
265 .lock()
266 .buffers
267 .insert_single(resource, buffer_use);
268
269 return (id, None);
270 };
271
272 for buffer in to_destroy {
275 let device = Arc::clone(&buffer.device);
276 device
277 .lock_life()
278 .schedule_resource_destruction(queue::TempResource::Buffer(Arc::new(buffer)), !0);
279 }
280
281 let id = fid.assign_error(desc.label.borrow_or_default());
282 (id, Some(error))
283 }
284
285 pub fn create_buffer_error<A: HalApi>(&self, id_in: Option<id::BufferId>, label: Label) {
314 let hub = A::hub(self);
315 let fid = hub.buffers.prepare(id_in);
316
317 fid.assign_error(label.borrow_or_default());
318 }
319
320 pub fn create_render_bundle_error<A: HalApi>(
321 &self,
322 id_in: Option<id::RenderBundleId>,
323 label: Label,
324 ) {
325 let hub = A::hub(self);
326 let fid = hub.render_bundles.prepare(id_in);
327
328 fid.assign_error(label.borrow_or_default());
329 }
330
331 pub fn create_texture_error<A: HalApi>(&self, id_in: Option<id::TextureId>, label: Label) {
335 let hub = A::hub(self);
336 let fid = hub.textures.prepare(id_in);
337
338 fid.assign_error(label.borrow_or_default());
339 }
340
341 #[cfg(feature = "replay")]
342 pub fn device_wait_for_buffer<A: HalApi>(
343 &self,
344 device_id: DeviceId,
345 buffer_id: id::BufferId,
346 ) -> Result<(), WaitIdleError> {
347 let hub = A::hub(self);
348
349 let last_submission = {
350 let buffer_guard = hub.buffers.write();
351 match buffer_guard.get(buffer_id) {
352 Ok(buffer) => buffer.info.submission_index(),
353 Err(_) => return Ok(()),
354 }
355 };
356
357 hub.devices
358 .get(device_id)
359 .map_err(|_| DeviceError::Invalid)?
360 .wait_for_submit(last_submission)
361 }
362
363 #[doc(hidden)]
364 pub fn device_set_buffer_sub_data<A: HalApi>(
365 &self,
366 device_id: DeviceId,
367 buffer_id: id::BufferId,
368 offset: BufferAddress,
369 data: &[u8],
370 ) -> BufferAccessResult {
371 profiling::scope!("Device::set_buffer_sub_data");
372
373 let hub = A::hub(self);
374
375 let device = hub
376 .devices
377 .get(device_id)
378 .map_err(|_| DeviceError::Invalid)?;
379 let snatch_guard = device.snatchable_lock.read();
380 if !device.is_valid() {
381 return Err(DeviceError::Lost.into());
382 }
383
384 let buffer = hub
385 .buffers
386 .get(buffer_id)
387 .map_err(|_| BufferAccessError::Invalid)?;
388 check_buffer_usage(buffer_id, buffer.usage, wgt::BufferUsages::MAP_WRITE)?;
389 #[cfg(feature = "trace")]
392 if let Some(ref mut trace) = *device.trace.lock() {
393 let data_path = trace.make_binary("bin", data);
394 trace.add(trace::Action::WriteBuffer {
395 id: buffer_id,
396 data: data_path,
397 range: offset..offset + data.len() as BufferAddress,
398 queued: false,
399 });
400 }
401
402 let raw_buf = buffer
403 .raw(&snatch_guard)
404 .ok_or(BufferAccessError::Destroyed)?;
405 unsafe {
406 let mapping = device
407 .raw()
408 .map_buffer(raw_buf, offset..offset + data.len() as u64)
409 .map_err(DeviceError::from)?;
410 ptr::copy_nonoverlapping(data.as_ptr(), mapping.ptr.as_ptr(), data.len());
411 if !mapping.is_coherent {
412 device
413 .raw()
414 .flush_mapped_ranges(raw_buf, iter::once(offset..offset + data.len() as u64));
415 }
416 device
417 .raw()
418 .unmap_buffer(raw_buf)
419 .map_err(DeviceError::from)?;
420 }
421
422 Ok(())
423 }
424
425 #[doc(hidden)]
426 pub fn device_get_buffer_sub_data<A: HalApi>(
427 &self,
428 device_id: DeviceId,
429 buffer_id: id::BufferId,
430 offset: BufferAddress,
431 data: &mut [u8],
432 ) -> BufferAccessResult {
433 profiling::scope!("Device::get_buffer_sub_data");
434
435 let hub = A::hub(self);
436
437 let device = hub
438 .devices
439 .get(device_id)
440 .map_err(|_| DeviceError::Invalid)?;
441 if !device.is_valid() {
442 return Err(DeviceError::Lost.into());
443 }
444
445 let snatch_guard = device.snatchable_lock.read();
446
447 let buffer = hub
448 .buffers
449 .get(buffer_id)
450 .map_err(|_| BufferAccessError::Invalid)?;
451 check_buffer_usage(buffer_id, buffer.usage, wgt::BufferUsages::MAP_READ)?;
452 let raw_buf = buffer
455 .raw(&snatch_guard)
456 .ok_or(BufferAccessError::Destroyed)?;
457 unsafe {
458 let mapping = device
459 .raw()
460 .map_buffer(raw_buf, offset..offset + data.len() as u64)
461 .map_err(DeviceError::from)?;
462 if !mapping.is_coherent {
463 device.raw().invalidate_mapped_ranges(
464 raw_buf,
465 iter::once(offset..offset + data.len() as u64),
466 );
467 }
468 ptr::copy_nonoverlapping(mapping.ptr.as_ptr(), data.as_mut_ptr(), data.len());
469 device
470 .raw()
471 .unmap_buffer(raw_buf)
472 .map_err(DeviceError::from)?;
473 }
474
475 Ok(())
476 }
477
478 pub fn buffer_label<A: HalApi>(&self, id: id::BufferId) -> String {
479 A::hub(self).buffers.label_for_resource(id)
480 }
481
482 pub fn buffer_destroy<A: HalApi>(
483 &self,
484 buffer_id: id::BufferId,
485 ) -> Result<(), resource::DestroyError> {
486 profiling::scope!("Buffer::destroy");
487 api_log!("Buffer::destroy {buffer_id:?}");
488
489 let hub = A::hub(self);
490
491 let buffer = hub
492 .buffers
493 .get(buffer_id)
494 .map_err(|_| resource::DestroyError::Invalid)?;
495
496 let _ = buffer.unmap();
497
498 buffer.destroy()
499 }
500
501 pub fn buffer_drop<A: HalApi>(&self, buffer_id: id::BufferId, wait: bool) {
502 profiling::scope!("Buffer::drop");
503 api_log!("Buffer::drop {buffer_id:?}");
504
505 let hub = A::hub(self);
506
507 let buffer = match hub.buffers.unregister(buffer_id) {
508 Some(buffer) => buffer,
509 None => {
510 return;
511 }
512 };
513
514 let _ = buffer.unmap();
515
516 let last_submit_index = buffer.info.submission_index();
517
518 let device = buffer.device.clone();
519
520 if device
521 .pending_writes
522 .lock()
523 .as_ref()
524 .unwrap()
525 .dst_buffers
526 .contains_key(&buffer_id)
527 {
528 device.lock_life().future_suspected_buffers.push(buffer);
529 } else {
530 device
531 .lock_life()
532 .suspected_resources
533 .buffers
534 .insert(buffer.info.tracker_index(), buffer);
535 }
536
537 if wait {
538 match device.wait_for_submit(last_submit_index) {
539 Ok(()) => (),
540 Err(e) => log::error!("Failed to wait for buffer {:?}: {}", buffer_id, e),
541 }
542 }
543 }
544
545 pub fn device_create_texture<A: HalApi>(
546 &self,
547 device_id: DeviceId,
548 desc: &resource::TextureDescriptor,
549 id_in: Option<id::TextureId>,
550 ) -> (id::TextureId, Option<resource::CreateTextureError>) {
551 profiling::scope!("Device::create_texture");
552
553 let hub = A::hub(self);
554
555 let fid = hub.textures.prepare(id_in);
556
557 let error = loop {
558 let device = match hub.devices.get(device_id) {
559 Ok(device) => device,
560 Err(_) => break DeviceError::Invalid.into(),
561 };
562 if !device.is_valid() {
563 break DeviceError::Lost.into();
564 }
565 #[cfg(feature = "trace")]
566 if let Some(ref mut trace) = *device.trace.lock() {
567 trace.add(trace::Action::CreateTexture(fid.id(), desc.clone()));
568 }
569
570 let texture = match device.create_texture(&device.adapter, desc) {
571 Ok(texture) => texture,
572 Err(error) => break error,
573 };
574
575 let (id, resource) = fid.assign(Arc::new(texture));
576 api_log!("Device::create_texture({desc:?}) -> {id:?}");
577
578 device
579 .trackers
580 .lock()
581 .textures
582 .insert_single(resource, hal::TextureUses::UNINITIALIZED);
583
584 return (id, None);
585 };
586
587 log::error!("Device::create_texture error: {error}");
588
589 let id = fid.assign_error(desc.label.borrow_or_default());
590 (id, Some(error))
591 }
592
593 pub unsafe fn create_texture_from_hal<A: HalApi>(
599 &self,
600 hal_texture: A::Texture,
601 device_id: DeviceId,
602 desc: &resource::TextureDescriptor,
603 id_in: Option<id::TextureId>,
604 ) -> (id::TextureId, Option<resource::CreateTextureError>) {
605 profiling::scope!("Device::create_texture_from_hal");
606
607 let hub = A::hub(self);
608
609 let fid = hub.textures.prepare(id_in);
610
611 let error = loop {
612 let device = match hub.devices.get(device_id) {
613 Ok(device) => device,
614 Err(_) => break DeviceError::Invalid.into(),
615 };
616 if !device.is_valid() {
617 break DeviceError::Lost.into();
618 }
619
620 #[cfg(feature = "trace")]
623 if let Some(ref mut trace) = *device.trace.lock() {
624 trace.add(trace::Action::CreateTexture(fid.id(), desc.clone()));
625 }
626
627 let format_features = match device
628 .describe_format_features(&device.adapter, desc.format)
629 .map_err(|error| resource::CreateTextureError::MissingFeatures(desc.format, error))
630 {
631 Ok(features) => features,
632 Err(error) => break error,
633 };
634
635 let mut texture = device.create_texture_from_hal(
636 hal_texture,
637 conv::map_texture_usage(desc.usage, desc.format.into()),
638 desc,
639 format_features,
640 resource::TextureClearMode::None,
641 );
642 if desc.usage.contains(wgt::TextureUsages::COPY_DST) {
643 texture.hal_usage |= hal::TextureUses::COPY_DST;
644 }
645
646 texture.initialization_status = RwLock::new(
647 rank::TEXTURE_INITIALIZATION_STATUS,
648 TextureInitTracker::new(desc.mip_level_count, 0),
649 );
650
651 let (id, resource) = fid.assign(Arc::new(texture));
652 api_log!("Device::create_texture({desc:?}) -> {id:?}");
653
654 device
655 .trackers
656 .lock()
657 .textures
658 .insert_single(resource, hal::TextureUses::UNINITIALIZED);
659
660 return (id, None);
661 };
662
663 log::error!("Device::create_texture error: {error}");
664
665 let id = fid.assign_error(desc.label.borrow_or_default());
666 (id, Some(error))
667 }
668
669 pub unsafe fn create_buffer_from_hal<A: HalApi>(
675 &self,
676 hal_buffer: A::Buffer,
677 device_id: DeviceId,
678 desc: &resource::BufferDescriptor,
679 id_in: Option<id::BufferId>,
680 ) -> (id::BufferId, Option<CreateBufferError>) {
681 profiling::scope!("Device::create_buffer");
682
683 let hub = A::hub(self);
684 let fid = hub.buffers.prepare(id_in);
685
686 let error = loop {
687 let device = match hub.devices.get(device_id) {
688 Ok(device) => device,
689 Err(_) => break DeviceError::Invalid.into(),
690 };
691 if !device.is_valid() {
692 break DeviceError::Lost.into();
693 }
694
695 #[cfg(feature = "trace")]
698 if let Some(trace) = device.trace.lock().as_mut() {
699 trace.add(trace::Action::CreateBuffer(fid.id(), desc.clone()));
700 }
701
702 let buffer = device.create_buffer_from_hal(hal_buffer, desc);
703
704 let (id, buffer) = fid.assign(Arc::new(buffer));
705 api_log!("Device::create_buffer -> {id:?}");
706
707 device
708 .trackers
709 .lock()
710 .buffers
711 .insert_single(buffer, hal::BufferUses::empty());
712
713 return (id, None);
714 };
715
716 log::error!("Device::create_buffer error: {error}");
717
718 let id = fid.assign_error(desc.label.borrow_or_default());
719 (id, Some(error))
720 }
721
722 pub fn texture_label<A: HalApi>(&self, id: id::TextureId) -> String {
723 A::hub(self).textures.label_for_resource(id)
724 }
725
726 pub fn texture_destroy<A: HalApi>(
727 &self,
728 texture_id: id::TextureId,
729 ) -> Result<(), resource::DestroyError> {
730 profiling::scope!("Texture::destroy");
731 api_log!("Texture::destroy {texture_id:?}");
732
733 let hub = A::hub(self);
734
735 let texture = hub
736 .textures
737 .get(texture_id)
738 .map_err(|_| resource::DestroyError::Invalid)?;
739
740 texture.destroy()
741 }
742
743 pub fn texture_drop<A: HalApi>(&self, texture_id: id::TextureId, wait: bool) {
744 profiling::scope!("Texture::drop");
745 api_log!("Texture::drop {texture_id:?}");
746
747 let hub = A::hub(self);
748
749 if let Some(texture) = hub.textures.unregister(texture_id) {
750 let last_submit_index = texture.info.submission_index();
751
752 let device = &texture.device;
753 {
754 if device
755 .pending_writes
756 .lock()
757 .as_ref()
758 .unwrap()
759 .dst_textures
760 .contains_key(&texture_id)
761 {
762 device
763 .lock_life()
764 .future_suspected_textures
765 .push(texture.clone());
766 } else {
767 device
768 .lock_life()
769 .suspected_resources
770 .textures
771 .insert(texture.info.tracker_index(), texture.clone());
772 }
773 }
774
775 if wait {
776 match device.wait_for_submit(last_submit_index) {
777 Ok(()) => (),
778 Err(e) => log::error!("Failed to wait for texture {texture_id:?}: {e}"),
779 }
780 }
781 }
782 }
783
784 #[allow(unused_unsafe)]
785 pub fn texture_create_view<A: HalApi>(
786 &self,
787 texture_id: id::TextureId,
788 desc: &resource::TextureViewDescriptor,
789 id_in: Option<id::TextureViewId>,
790 ) -> (id::TextureViewId, Option<resource::CreateTextureViewError>) {
791 profiling::scope!("Texture::create_view");
792
793 let hub = A::hub(self);
794
795 let fid = hub.texture_views.prepare(id_in);
796
797 let error = loop {
798 let texture = match hub.textures.get(texture_id) {
799 Ok(texture) => texture,
800 Err(_) => break resource::CreateTextureViewError::InvalidTexture,
801 };
802 let device = &texture.device;
803 {
804 let snatch_guard = device.snatchable_lock.read();
805 if texture.is_destroyed(&snatch_guard) {
806 break resource::CreateTextureViewError::InvalidTexture;
807 }
808 }
809 #[cfg(feature = "trace")]
810 if let Some(ref mut trace) = *device.trace.lock() {
811 trace.add(trace::Action::CreateTextureView {
812 id: fid.id(),
813 parent_id: texture_id,
814 desc: desc.clone(),
815 });
816 }
817
818 let view = match unsafe { device.create_texture_view(&texture, desc) } {
819 Ok(view) => view,
820 Err(e) => break e,
821 };
822
823 let (id, resource) = fid.assign(Arc::new(view));
824
825 {
826 let mut views = texture.views.lock();
827 views.push(Arc::downgrade(&resource));
828 }
829
830 api_log!("Texture::create_view({texture_id:?}) -> {id:?}");
831 device.trackers.lock().views.insert_single(resource);
832 return (id, None);
833 };
834
835 log::error!("Texture::create_view({texture_id:?}) error: {error}");
836 let id = fid.assign_error(desc.label.borrow_or_default());
837 (id, Some(error))
838 }
839
840 pub fn texture_view_label<A: HalApi>(&self, id: id::TextureViewId) -> String {
841 A::hub(self).texture_views.label_for_resource(id)
842 }
843
844 pub fn texture_view_drop<A: HalApi>(
845 &self,
846 texture_view_id: id::TextureViewId,
847 wait: bool,
848 ) -> Result<(), resource::TextureViewDestroyError> {
849 profiling::scope!("TextureView::drop");
850 api_log!("TextureView::drop {texture_view_id:?}");
851
852 let hub = A::hub(self);
853
854 if let Some(view) = hub.texture_views.unregister(texture_view_id) {
855 let last_submit_index = view.info.submission_index();
856
857 view.device
858 .lock_life()
859 .suspected_resources
860 .texture_views
861 .insert(view.info.tracker_index(), view.clone());
862
863 if wait {
864 match view.device.wait_for_submit(last_submit_index) {
865 Ok(()) => (),
866 Err(e) => {
867 log::error!("Failed to wait for texture view {texture_view_id:?}: {e}")
868 }
869 }
870 }
871 }
872 Ok(())
873 }
874
875 pub fn device_create_sampler<A: HalApi>(
876 &self,
877 device_id: DeviceId,
878 desc: &resource::SamplerDescriptor,
879 id_in: Option<id::SamplerId>,
880 ) -> (id::SamplerId, Option<resource::CreateSamplerError>) {
881 profiling::scope!("Device::create_sampler");
882
883 let hub = A::hub(self);
884 let fid = hub.samplers.prepare(id_in);
885
886 let error = loop {
887 let device = match hub.devices.get(device_id) {
888 Ok(device) => device,
889 Err(_) => break DeviceError::Invalid.into(),
890 };
891 if !device.is_valid() {
892 break DeviceError::Lost.into();
893 }
894
895 #[cfg(feature = "trace")]
896 if let Some(ref mut trace) = *device.trace.lock() {
897 trace.add(trace::Action::CreateSampler(fid.id(), desc.clone()));
898 }
899
900 let sampler = match device.create_sampler(desc) {
901 Ok(sampler) => sampler,
902 Err(e) => break e,
903 };
904
905 let (id, resource) = fid.assign(Arc::new(sampler));
906 api_log!("Device::create_sampler -> {id:?}");
907 device.trackers.lock().samplers.insert_single(resource);
908
909 return (id, None);
910 };
911
912 let id = fid.assign_error(desc.label.borrow_or_default());
913 (id, Some(error))
914 }
915
916 pub fn sampler_label<A: HalApi>(&self, id: id::SamplerId) -> String {
917 A::hub(self).samplers.label_for_resource(id)
918 }
919
920 pub fn sampler_drop<A: HalApi>(&self, sampler_id: id::SamplerId) {
921 profiling::scope!("Sampler::drop");
922 api_log!("Sampler::drop {sampler_id:?}");
923
924 let hub = A::hub(self);
925
926 if let Some(sampler) = hub.samplers.unregister(sampler_id) {
927 sampler
928 .device
929 .lock_life()
930 .suspected_resources
931 .samplers
932 .insert(sampler.info.tracker_index(), sampler.clone());
933 }
934 }
935
936 pub fn device_create_bind_group_layout<A: HalApi>(
937 &self,
938 device_id: DeviceId,
939 desc: &binding_model::BindGroupLayoutDescriptor,
940 id_in: Option<id::BindGroupLayoutId>,
941 ) -> (
942 id::BindGroupLayoutId,
943 Option<binding_model::CreateBindGroupLayoutError>,
944 ) {
945 profiling::scope!("Device::create_bind_group_layout");
946
947 let hub = A::hub(self);
948 let fid = hub.bind_group_layouts.prepare(id_in);
949
950 let error = loop {
951 let device = match hub.devices.get(device_id) {
952 Ok(device) => device,
953 Err(_) => break DeviceError::Invalid.into(),
954 };
955 if !device.is_valid() {
956 break DeviceError::Lost.into();
957 }
958
959 #[cfg(feature = "trace")]
960 if let Some(ref mut trace) = *device.trace.lock() {
961 trace.add(trace::Action::CreateBindGroupLayout(fid.id(), desc.clone()));
962 }
963
964 let entry_map = match bgl::EntryMap::from_entries(&device.limits, &desc.entries) {
965 Ok(map) => map,
966 Err(e) => break e,
967 };
968
969 let mut fid = Some(fid);
979
980 let mut id = None;
982
983 let bgl_result = device.bgl_pool.get_or_init(entry_map, |entry_map| {
984 let bgl =
985 device.create_bind_group_layout(&desc.label, entry_map, bgl::Origin::Pool)?;
986
987 let (id_inner, arc) = fid.take().unwrap().assign(Arc::new(bgl));
988 id = Some(id_inner);
989
990 Ok(arc)
991 });
992
993 let layout = match bgl_result {
994 Ok(layout) => layout,
995 Err(e) => break e,
996 };
997
998 if id.is_none() {
1003 id = Some(fid.take().unwrap().assign_existing(&layout))
1004 }
1005
1006 api_log!("Device::create_bind_group_layout -> {id:?}");
1007 return (id.unwrap(), None);
1008 };
1009
1010 let fid = hub.bind_group_layouts.prepare(id_in);
1011 let id = fid.assign_error(desc.label.borrow_or_default());
1012 (id, Some(error))
1013 }
1014
1015 pub fn bind_group_layout_label<A: HalApi>(&self, id: id::BindGroupLayoutId) -> String {
1016 A::hub(self).bind_group_layouts.label_for_resource(id)
1017 }
1018
1019 pub fn bind_group_layout_drop<A: HalApi>(&self, bind_group_layout_id: id::BindGroupLayoutId) {
1020 profiling::scope!("BindGroupLayout::drop");
1021 api_log!("BindGroupLayout::drop {bind_group_layout_id:?}");
1022
1023 let hub = A::hub(self);
1024
1025 if let Some(layout) = hub.bind_group_layouts.unregister(bind_group_layout_id) {
1026 layout
1027 .device
1028 .lock_life()
1029 .suspected_resources
1030 .bind_group_layouts
1031 .insert(layout.info.tracker_index(), layout.clone());
1032 }
1033 }
1034
1035 pub fn device_create_pipeline_layout<A: HalApi>(
1036 &self,
1037 device_id: DeviceId,
1038 desc: &binding_model::PipelineLayoutDescriptor,
1039 id_in: Option<id::PipelineLayoutId>,
1040 ) -> (
1041 id::PipelineLayoutId,
1042 Option<binding_model::CreatePipelineLayoutError>,
1043 ) {
1044 profiling::scope!("Device::create_pipeline_layout");
1045
1046 let hub = A::hub(self);
1047 let fid = hub.pipeline_layouts.prepare(id_in);
1048
1049 let error = loop {
1050 let device = match hub.devices.get(device_id) {
1051 Ok(device) => device,
1052 Err(_) => break DeviceError::Invalid.into(),
1053 };
1054 if !device.is_valid() {
1055 break DeviceError::Lost.into();
1056 }
1057
1058 #[cfg(feature = "trace")]
1059 if let Some(ref mut trace) = *device.trace.lock() {
1060 trace.add(trace::Action::CreatePipelineLayout(fid.id(), desc.clone()));
1061 }
1062
1063 let layout = match device.create_pipeline_layout(desc, &hub.bind_group_layouts) {
1064 Ok(layout) => layout,
1065 Err(e) => break e,
1066 };
1067
1068 let (id, _) = fid.assign(Arc::new(layout));
1069 api_log!("Device::create_pipeline_layout -> {id:?}");
1070 return (id, None);
1071 };
1072
1073 let id = fid.assign_error(desc.label.borrow_or_default());
1074 (id, Some(error))
1075 }
1076
1077 pub fn pipeline_layout_label<A: HalApi>(&self, id: id::PipelineLayoutId) -> String {
1078 A::hub(self).pipeline_layouts.label_for_resource(id)
1079 }
1080
1081 pub fn pipeline_layout_drop<A: HalApi>(&self, pipeline_layout_id: id::PipelineLayoutId) {
1082 profiling::scope!("PipelineLayout::drop");
1083 api_log!("PipelineLayout::drop {pipeline_layout_id:?}");
1084
1085 let hub = A::hub(self);
1086 if let Some(layout) = hub.pipeline_layouts.unregister(pipeline_layout_id) {
1087 layout
1088 .device
1089 .lock_life()
1090 .suspected_resources
1091 .pipeline_layouts
1092 .insert(layout.info.tracker_index(), layout.clone());
1093 }
1094 }
1095
1096 pub fn device_create_bind_group<A: HalApi>(
1097 &self,
1098 device_id: DeviceId,
1099 desc: &binding_model::BindGroupDescriptor,
1100 id_in: Option<id::BindGroupId>,
1101 ) -> (id::BindGroupId, Option<binding_model::CreateBindGroupError>) {
1102 profiling::scope!("Device::create_bind_group");
1103
1104 let hub = A::hub(self);
1105 let fid = hub.bind_groups.prepare(id_in);
1106
1107 let error = loop {
1108 let device = match hub.devices.get(device_id) {
1109 Ok(device) => device,
1110 Err(_) => break DeviceError::Invalid.into(),
1111 };
1112 if !device.is_valid() {
1113 break DeviceError::Lost.into();
1114 }
1115
1116 #[cfg(feature = "trace")]
1117 if let Some(ref mut trace) = *device.trace.lock() {
1118 trace.add(trace::Action::CreateBindGroup(fid.id(), desc.clone()));
1119 }
1120
1121 let bind_group_layout = match hub.bind_group_layouts.get(desc.layout) {
1122 Ok(layout) => layout,
1123 Err(..) => break binding_model::CreateBindGroupError::InvalidLayout,
1124 };
1125
1126 if bind_group_layout.device.as_info().id() != device.as_info().id() {
1127 break DeviceError::WrongDevice.into();
1128 }
1129
1130 let bind_group = match device.create_bind_group(&bind_group_layout, desc, hub) {
1131 Ok(bind_group) => bind_group,
1132 Err(e) => break e,
1133 };
1134
1135 let (id, resource) = fid.assign(Arc::new(bind_group));
1136
1137 let weak_ref = Arc::downgrade(&resource);
1138 for range in &resource.used_texture_ranges {
1139 range.texture.bind_groups.lock().push(weak_ref.clone());
1140 }
1141 for range in &resource.used_buffer_ranges {
1142 range.buffer.bind_groups.lock().push(weak_ref.clone());
1143 }
1144
1145 api_log!("Device::create_bind_group -> {id:?}");
1146
1147 device.trackers.lock().bind_groups.insert_single(resource);
1148 return (id, None);
1149 };
1150
1151 let id = fid.assign_error(desc.label.borrow_or_default());
1152 (id, Some(error))
1153 }
1154
1155 pub fn bind_group_label<A: HalApi>(&self, id: id::BindGroupId) -> String {
1156 A::hub(self).bind_groups.label_for_resource(id)
1157 }
1158
1159 pub fn bind_group_drop<A: HalApi>(&self, bind_group_id: id::BindGroupId) {
1160 profiling::scope!("BindGroup::drop");
1161 api_log!("BindGroup::drop {bind_group_id:?}");
1162
1163 let hub = A::hub(self);
1164
1165 if let Some(bind_group) = hub.bind_groups.unregister(bind_group_id) {
1166 bind_group
1167 .device
1168 .lock_life()
1169 .suspected_resources
1170 .bind_groups
1171 .insert(bind_group.info.tracker_index(), bind_group.clone());
1172 }
1173 }
1174
1175 pub fn device_create_shader_module<A: HalApi>(
1190 &self,
1191 device_id: DeviceId,
1192 desc: &pipeline::ShaderModuleDescriptor,
1193 source: pipeline::ShaderModuleSource,
1194 id_in: Option<id::ShaderModuleId>,
1195 ) -> (
1196 id::ShaderModuleId,
1197 Option<pipeline::CreateShaderModuleError>,
1198 ) {
1199 profiling::scope!("Device::create_shader_module");
1200
1201 let hub = A::hub(self);
1202 let fid = hub.shader_modules.prepare(id_in);
1203
1204 let error = loop {
1205 let device = match hub.devices.get(device_id) {
1206 Ok(device) => device,
1207 Err(_) => break DeviceError::Invalid.into(),
1208 };
1209 if !device.is_valid() {
1210 break DeviceError::Lost.into();
1211 }
1212
1213 #[cfg(feature = "trace")]
1214 if let Some(ref mut trace) = *device.trace.lock() {
1215 let data = match source {
1216 #[cfg(feature = "wgsl")]
1217 pipeline::ShaderModuleSource::Wgsl(ref code) => {
1218 trace.make_binary("wgsl", code.as_bytes())
1219 }
1220 #[cfg(feature = "glsl")]
1221 pipeline::ShaderModuleSource::Glsl(ref code, _) => {
1222 trace.make_binary("glsl", code.as_bytes())
1223 }
1224 #[cfg(feature = "spirv")]
1225 pipeline::ShaderModuleSource::SpirV(ref code, _) => {
1226 trace.make_binary("spirv", bytemuck::cast_slice::<u32, u8>(code))
1227 }
1228 pipeline::ShaderModuleSource::Naga(ref module) => {
1229 let string =
1230 ron::ser::to_string_pretty(module, ron::ser::PrettyConfig::default())
1231 .unwrap();
1232 trace.make_binary("ron", string.as_bytes())
1233 }
1234 pipeline::ShaderModuleSource::Dummy(_) => {
1235 panic!("found `ShaderModuleSource::Dummy`")
1236 }
1237 };
1238 trace.add(trace::Action::CreateShaderModule {
1239 id: fid.id(),
1240 desc: desc.clone(),
1241 data,
1242 });
1243 };
1244
1245 let shader = match device.create_shader_module(desc, source) {
1246 Ok(shader) => shader,
1247 Err(e) => break e,
1248 };
1249
1250 let (id, _) = fid.assign(Arc::new(shader));
1251 api_log!("Device::create_shader_module -> {id:?}");
1252 return (id, None);
1253 };
1254
1255 log::error!("Device::create_shader_module error: {error}");
1256
1257 let id = fid.assign_error(desc.label.borrow_or_default());
1258 (id, Some(error))
1259 }
1260
1261 #[allow(unused_unsafe)]
1263 pub unsafe fn device_create_shader_module_spirv<A: HalApi>(
1268 &self,
1269 device_id: DeviceId,
1270 desc: &pipeline::ShaderModuleDescriptor,
1271 source: Cow<[u32]>,
1272 id_in: Option<id::ShaderModuleId>,
1273 ) -> (
1274 id::ShaderModuleId,
1275 Option<pipeline::CreateShaderModuleError>,
1276 ) {
1277 profiling::scope!("Device::create_shader_module");
1278
1279 let hub = A::hub(self);
1280 let fid = hub.shader_modules.prepare(id_in);
1281
1282 let error = loop {
1283 let device = match hub.devices.get(device_id) {
1284 Ok(device) => device,
1285 Err(_) => break DeviceError::Invalid.into(),
1286 };
1287 if !device.is_valid() {
1288 break DeviceError::Lost.into();
1289 }
1290
1291 #[cfg(feature = "trace")]
1292 if let Some(ref mut trace) = *device.trace.lock() {
1293 let data = trace.make_binary("spv", unsafe {
1294 std::slice::from_raw_parts(source.as_ptr() as *const u8, source.len() * 4)
1295 });
1296 trace.add(trace::Action::CreateShaderModule {
1297 id: fid.id(),
1298 desc: desc.clone(),
1299 data,
1300 });
1301 };
1302
1303 let shader = match unsafe { device.create_shader_module_spirv(desc, &source) } {
1304 Ok(shader) => shader,
1305 Err(e) => break e,
1306 };
1307 let (id, _) = fid.assign(Arc::new(shader));
1308 api_log!("Device::create_shader_module_spirv -> {id:?}");
1309 return (id, None);
1310 };
1311
1312 log::error!("Device::create_shader_module_spirv error: {error}");
1313
1314 let id = fid.assign_error(desc.label.borrow_or_default());
1315 (id, Some(error))
1316 }
1317
1318 pub fn shader_module_label<A: HalApi>(&self, id: id::ShaderModuleId) -> String {
1319 A::hub(self).shader_modules.label_for_resource(id)
1320 }
1321
1322 pub fn shader_module_drop<A: HalApi>(&self, shader_module_id: id::ShaderModuleId) {
1323 profiling::scope!("ShaderModule::drop");
1324 api_log!("ShaderModule::drop {shader_module_id:?}");
1325
1326 let hub = A::hub(self);
1327 hub.shader_modules.unregister(shader_module_id);
1328 }
1329
1330 pub fn device_create_command_encoder<A: HalApi>(
1331 &self,
1332 device_id: DeviceId,
1333 desc: &wgt::CommandEncoderDescriptor<Label>,
1334 id_in: Option<id::CommandEncoderId>,
1335 ) -> (id::CommandEncoderId, Option<DeviceError>) {
1336 profiling::scope!("Device::create_command_encoder");
1337
1338 let hub = A::hub(self);
1339 let fid = hub
1340 .command_buffers
1341 .prepare(id_in.map(|id| id.into_command_buffer_id()));
1342
1343 let error = loop {
1344 let device = match hub.devices.get(device_id) {
1345 Ok(device) => device,
1346 Err(_) => break DeviceError::Invalid,
1347 };
1348 if !device.is_valid() {
1349 break DeviceError::Lost;
1350 }
1351 let Some(queue) = device.get_queue() else {
1352 break DeviceError::InvalidQueueId;
1353 };
1354 let encoder = match device
1355 .command_allocator
1356 .acquire_encoder(device.raw(), queue.raw.as_ref().unwrap())
1357 {
1358 Ok(raw) => raw,
1359 Err(_) => break DeviceError::OutOfMemory,
1360 };
1361 let command_buffer = command::CommandBuffer::new(
1362 encoder,
1363 &device,
1364 #[cfg(feature = "trace")]
1365 device.trace.lock().is_some(),
1366 desc.label
1367 .to_hal(device.instance_flags)
1368 .map(|s| s.to_string()),
1369 );
1370
1371 let (id, _) = fid.assign(Arc::new(command_buffer));
1372 api_log!("Device::create_command_encoder -> {id:?}");
1373 return (id.into_command_encoder_id(), None);
1374 };
1375
1376 let id = fid.assign_error(desc.label.borrow_or_default());
1377 (id.into_command_encoder_id(), Some(error))
1378 }
1379
1380 pub fn command_buffer_label<A: HalApi>(&self, id: id::CommandBufferId) -> String {
1381 A::hub(self).command_buffers.label_for_resource(id)
1382 }
1383
1384 pub fn command_encoder_drop<A: HalApi>(&self, command_encoder_id: id::CommandEncoderId) {
1385 profiling::scope!("CommandEncoder::drop");
1386 api_log!("CommandEncoder::drop {command_encoder_id:?}");
1387
1388 let hub = A::hub(self);
1389
1390 if let Some(cmd_buf) = hub
1391 .command_buffers
1392 .unregister(command_encoder_id.into_command_buffer_id())
1393 {
1394 cmd_buf.data.lock().as_mut().unwrap().encoder.discard();
1395 cmd_buf
1396 .device
1397 .untrack(&cmd_buf.data.lock().as_ref().unwrap().trackers);
1398 }
1399 }
1400
1401 pub fn command_buffer_drop<A: HalApi>(&self, command_buffer_id: id::CommandBufferId) {
1402 profiling::scope!("CommandBuffer::drop");
1403 api_log!("CommandBuffer::drop {command_buffer_id:?}");
1404 self.command_encoder_drop::<A>(command_buffer_id.into_command_encoder_id())
1405 }
1406
1407 pub fn device_create_render_bundle_encoder(
1408 &self,
1409 device_id: DeviceId,
1410 desc: &command::RenderBundleEncoderDescriptor,
1411 ) -> (
1412 *mut command::RenderBundleEncoder,
1413 Option<command::CreateRenderBundleError>,
1414 ) {
1415 profiling::scope!("Device::create_render_bundle_encoder");
1416 api_log!("Device::device_create_render_bundle_encoder");
1417 let (encoder, error) = match command::RenderBundleEncoder::new(desc, device_id, None) {
1418 Ok(encoder) => (encoder, None),
1419 Err(e) => (command::RenderBundleEncoder::dummy(device_id), Some(e)),
1420 };
1421 (Box::into_raw(Box::new(encoder)), error)
1422 }
1423
1424 pub fn render_bundle_encoder_finish<A: HalApi>(
1425 &self,
1426 bundle_encoder: command::RenderBundleEncoder,
1427 desc: &command::RenderBundleDescriptor,
1428 id_in: Option<id::RenderBundleId>,
1429 ) -> (id::RenderBundleId, Option<command::RenderBundleError>) {
1430 profiling::scope!("RenderBundleEncoder::finish");
1431
1432 let hub = A::hub(self);
1433
1434 let fid = hub.render_bundles.prepare(id_in);
1435
1436 let error = loop {
1437 let device = match hub.devices.get(bundle_encoder.parent()) {
1438 Ok(device) => device,
1439 Err(_) => break command::RenderBundleError::INVALID_DEVICE,
1440 };
1441 if !device.is_valid() {
1442 break command::RenderBundleError::INVALID_DEVICE;
1443 }
1444
1445 #[cfg(feature = "trace")]
1446 if let Some(ref mut trace) = *device.trace.lock() {
1447 trace.add(trace::Action::CreateRenderBundle {
1448 id: fid.id(),
1449 desc: trace::new_render_bundle_encoder_descriptor(
1450 desc.label.clone(),
1451 &bundle_encoder.context,
1452 bundle_encoder.is_depth_read_only,
1453 bundle_encoder.is_stencil_read_only,
1454 ),
1455 base: bundle_encoder.to_base_pass(),
1456 });
1457 }
1458
1459 let render_bundle = match bundle_encoder.finish(desc, &device, hub) {
1460 Ok(bundle) => bundle,
1461 Err(e) => break e,
1462 };
1463
1464 let (id, resource) = fid.assign(Arc::new(render_bundle));
1465 api_log!("RenderBundleEncoder::finish -> {id:?}");
1466 device.trackers.lock().bundles.insert_single(resource);
1467 return (id, None);
1468 };
1469
1470 let id = fid.assign_error(desc.label.borrow_or_default());
1471 (id, Some(error))
1472 }
1473
1474 pub fn render_bundle_label<A: HalApi>(&self, id: id::RenderBundleId) -> String {
1475 A::hub(self).render_bundles.label_for_resource(id)
1476 }
1477
1478 pub fn render_bundle_drop<A: HalApi>(&self, render_bundle_id: id::RenderBundleId) {
1479 profiling::scope!("RenderBundle::drop");
1480 api_log!("RenderBundle::drop {render_bundle_id:?}");
1481
1482 let hub = A::hub(self);
1483
1484 if let Some(bundle) = hub.render_bundles.unregister(render_bundle_id) {
1485 bundle
1486 .device
1487 .lock_life()
1488 .suspected_resources
1489 .render_bundles
1490 .insert(bundle.info.tracker_index(), bundle.clone());
1491 }
1492 }
1493
1494 pub fn device_create_query_set<A: HalApi>(
1495 &self,
1496 device_id: DeviceId,
1497 desc: &resource::QuerySetDescriptor,
1498 id_in: Option<id::QuerySetId>,
1499 ) -> (id::QuerySetId, Option<resource::CreateQuerySetError>) {
1500 profiling::scope!("Device::create_query_set");
1501
1502 let hub = A::hub(self);
1503 let fid = hub.query_sets.prepare(id_in);
1504
1505 let error = loop {
1506 let device = match hub.devices.get(device_id) {
1507 Ok(device) => device,
1508 Err(_) => break DeviceError::Invalid.into(),
1509 };
1510 if !device.is_valid() {
1511 break DeviceError::Lost.into();
1512 }
1513
1514 #[cfg(feature = "trace")]
1515 if let Some(ref mut trace) = *device.trace.lock() {
1516 trace.add(trace::Action::CreateQuerySet {
1517 id: fid.id(),
1518 desc: desc.clone(),
1519 });
1520 }
1521
1522 let query_set = match device.create_query_set(desc) {
1523 Ok(query_set) => query_set,
1524 Err(err) => break err,
1525 };
1526
1527 let (id, resource) = fid.assign(Arc::new(query_set));
1528 api_log!("Device::create_query_set -> {id:?}");
1529 device.trackers.lock().query_sets.insert_single(resource);
1530
1531 return (id, None);
1532 };
1533
1534 let id = fid.assign_error("");
1535 (id, Some(error))
1536 }
1537
1538 pub fn query_set_drop<A: HalApi>(&self, query_set_id: id::QuerySetId) {
1539 profiling::scope!("QuerySet::drop");
1540 api_log!("QuerySet::drop {query_set_id:?}");
1541
1542 let hub = A::hub(self);
1543
1544 if let Some(query_set) = hub.query_sets.unregister(query_set_id) {
1545 let device = &query_set.device;
1546
1547 #[cfg(feature = "trace")]
1548 if let Some(ref mut trace) = *device.trace.lock() {
1549 trace.add(trace::Action::DestroyQuerySet(query_set_id));
1550 }
1551
1552 device
1553 .lock_life()
1554 .suspected_resources
1555 .query_sets
1556 .insert(query_set.info.tracker_index(), query_set.clone());
1557 }
1558 }
1559
1560 pub fn query_set_label<A: HalApi>(&self, id: id::QuerySetId) -> String {
1561 A::hub(self).query_sets.label_for_resource(id)
1562 }
1563
1564 pub fn device_create_render_pipeline<A: HalApi>(
1565 &self,
1566 device_id: DeviceId,
1567 desc: &pipeline::RenderPipelineDescriptor,
1568 id_in: Option<id::RenderPipelineId>,
1569 implicit_pipeline_ids: Option<ImplicitPipelineIds<'_>>,
1570 ) -> (
1571 id::RenderPipelineId,
1572 Option<pipeline::CreateRenderPipelineError>,
1573 ) {
1574 profiling::scope!("Device::create_render_pipeline");
1575
1576 let hub = A::hub(self);
1577
1578 let fid = hub.render_pipelines.prepare(id_in);
1579 let implicit_context = implicit_pipeline_ids.map(|ipi| ipi.prepare(hub));
1580 let implicit_error_context = implicit_context.clone();
1581
1582 let error = loop {
1583 let device = match hub.devices.get(device_id) {
1584 Ok(device) => device,
1585 Err(_) => break DeviceError::Invalid.into(),
1586 };
1587 if !device.is_valid() {
1588 break DeviceError::Lost.into();
1589 }
1590 #[cfg(feature = "trace")]
1591 if let Some(ref mut trace) = *device.trace.lock() {
1592 trace.add(trace::Action::CreateRenderPipeline {
1593 id: fid.id(),
1594 desc: desc.clone(),
1595 implicit_context: implicit_context.clone(),
1596 });
1597 }
1598
1599 let pipeline =
1600 match device.create_render_pipeline(&device.adapter, desc, implicit_context, hub) {
1601 Ok(pair) => pair,
1602 Err(e) => break e,
1603 };
1604
1605 let (id, resource) = fid.assign(Arc::new(pipeline));
1606 api_log!("Device::create_render_pipeline -> {id:?}");
1607
1608 device
1609 .trackers
1610 .lock()
1611 .render_pipelines
1612 .insert_single(resource);
1613
1614 return (id, None);
1615 };
1616
1617 let id = fid.assign_error(desc.label.borrow_or_default());
1618
1619 let mut pipeline_layout_guard = hub.pipeline_layouts.write();
1622 let mut bgl_guard = hub.bind_group_layouts.write();
1623 if let Some(ref ids) = implicit_error_context {
1624 if pipeline_layout_guard.contains(ids.root_id) {
1625 pipeline_layout_guard.remove(ids.root_id);
1626 }
1627 pipeline_layout_guard.insert_error(ids.root_id, IMPLICIT_BIND_GROUP_LAYOUT_ERROR_LABEL);
1628 for &bgl_id in ids.group_ids.iter() {
1629 if bgl_guard.contains(bgl_id) {
1630 bgl_guard.remove(bgl_id);
1631 }
1632 bgl_guard.insert_error(bgl_id, IMPLICIT_BIND_GROUP_LAYOUT_ERROR_LABEL);
1633 }
1634 }
1635
1636 log::error!("Device::create_render_pipeline error: {error}");
1637
1638 (id, Some(error))
1639 }
1640
1641 pub fn render_pipeline_get_bind_group_layout<A: HalApi>(
1644 &self,
1645 pipeline_id: id::RenderPipelineId,
1646 index: u32,
1647 id_in: Option<id::BindGroupLayoutId>,
1648 ) -> (
1649 id::BindGroupLayoutId,
1650 Option<binding_model::GetBindGroupLayoutError>,
1651 ) {
1652 let hub = A::hub(self);
1653
1654 let error = loop {
1655 let pipeline = match hub.render_pipelines.get(pipeline_id) {
1656 Ok(pipeline) => pipeline,
1657 Err(_) => break binding_model::GetBindGroupLayoutError::InvalidPipeline,
1658 };
1659 let id = match pipeline.layout.bind_group_layouts.get(index as usize) {
1660 Some(bg) => hub.bind_group_layouts.prepare(id_in).assign_existing(bg),
1661 None => break binding_model::GetBindGroupLayoutError::InvalidGroupIndex(index),
1662 };
1663 return (id, None);
1664 };
1665
1666 let id = hub
1667 .bind_group_layouts
1668 .prepare(id_in)
1669 .assign_error("<derived>");
1670 (id, Some(error))
1671 }
1672
1673 pub fn render_pipeline_label<A: HalApi>(&self, id: id::RenderPipelineId) -> String {
1674 A::hub(self).render_pipelines.label_for_resource(id)
1675 }
1676
1677 pub fn render_pipeline_drop<A: HalApi>(&self, render_pipeline_id: id::RenderPipelineId) {
1678 profiling::scope!("RenderPipeline::drop");
1679 api_log!("RenderPipeline::drop {render_pipeline_id:?}");
1680
1681 let hub = A::hub(self);
1682
1683 if let Some(pipeline) = hub.render_pipelines.unregister(render_pipeline_id) {
1684 let device = &pipeline.device;
1685 let mut life_lock = device.lock_life();
1686 life_lock
1687 .suspected_resources
1688 .render_pipelines
1689 .insert(pipeline.info.tracker_index(), pipeline.clone());
1690
1691 life_lock.suspected_resources.pipeline_layouts.insert(
1692 pipeline.layout.info.tracker_index(),
1693 pipeline.layout.clone(),
1694 );
1695 }
1696 }
1697
1698 pub fn device_create_compute_pipeline<A: HalApi>(
1699 &self,
1700 device_id: DeviceId,
1701 desc: &pipeline::ComputePipelineDescriptor,
1702 id_in: Option<id::ComputePipelineId>,
1703 implicit_pipeline_ids: Option<ImplicitPipelineIds<'_>>,
1704 ) -> (
1705 id::ComputePipelineId,
1706 Option<pipeline::CreateComputePipelineError>,
1707 ) {
1708 profiling::scope!("Device::create_compute_pipeline");
1709
1710 let hub = A::hub(self);
1711
1712 let fid = hub.compute_pipelines.prepare(id_in);
1713 let implicit_context = implicit_pipeline_ids.map(|ipi| ipi.prepare(hub));
1714 let implicit_error_context = implicit_context.clone();
1715
1716 let error = loop {
1717 let device = match hub.devices.get(device_id) {
1718 Ok(device) => device,
1719 Err(_) => break DeviceError::Invalid.into(),
1720 };
1721 if !device.is_valid() {
1722 break DeviceError::Lost.into();
1723 }
1724
1725 #[cfg(feature = "trace")]
1726 if let Some(ref mut trace) = *device.trace.lock() {
1727 trace.add(trace::Action::CreateComputePipeline {
1728 id: fid.id(),
1729 desc: desc.clone(),
1730 implicit_context: implicit_context.clone(),
1731 });
1732 }
1733 let pipeline = match device.create_compute_pipeline(desc, implicit_context, hub) {
1734 Ok(pair) => pair,
1735 Err(e) => break e,
1736 };
1737
1738 let (id, resource) = fid.assign(Arc::new(pipeline));
1739 api_log!("Device::create_compute_pipeline -> {id:?}");
1740
1741 device
1742 .trackers
1743 .lock()
1744 .compute_pipelines
1745 .insert_single(resource);
1746 return (id, None);
1747 };
1748
1749 let id = fid.assign_error(desc.label.borrow_or_default());
1750
1751 let mut pipeline_layout_guard = hub.pipeline_layouts.write();
1754 let mut bgl_guard = hub.bind_group_layouts.write();
1755 if let Some(ref ids) = implicit_error_context {
1756 if pipeline_layout_guard.contains(ids.root_id) {
1757 pipeline_layout_guard.remove(ids.root_id);
1758 }
1759 pipeline_layout_guard.insert_error(ids.root_id, IMPLICIT_BIND_GROUP_LAYOUT_ERROR_LABEL);
1760 for &bgl_id in ids.group_ids.iter() {
1761 if bgl_guard.contains(bgl_id) {
1762 bgl_guard.remove(bgl_id);
1763 }
1764 bgl_guard.insert_error(bgl_id, IMPLICIT_BIND_GROUP_LAYOUT_ERROR_LABEL);
1765 }
1766 }
1767 (id, Some(error))
1768 }
1769
1770 pub fn compute_pipeline_get_bind_group_layout<A: HalApi>(
1773 &self,
1774 pipeline_id: id::ComputePipelineId,
1775 index: u32,
1776 id_in: Option<id::BindGroupLayoutId>,
1777 ) -> (
1778 id::BindGroupLayoutId,
1779 Option<binding_model::GetBindGroupLayoutError>,
1780 ) {
1781 let hub = A::hub(self);
1782
1783 let error = loop {
1784 let pipeline = match hub.compute_pipelines.get(pipeline_id) {
1785 Ok(pipeline) => pipeline,
1786 Err(_) => break binding_model::GetBindGroupLayoutError::InvalidPipeline,
1787 };
1788
1789 let id = match pipeline.layout.bind_group_layouts.get(index as usize) {
1790 Some(bg) => hub.bind_group_layouts.prepare(id_in).assign_existing(bg),
1791 None => break binding_model::GetBindGroupLayoutError::InvalidGroupIndex(index),
1792 };
1793
1794 return (id, None);
1795 };
1796
1797 let id = hub
1798 .bind_group_layouts
1799 .prepare(id_in)
1800 .assign_error("<derived>");
1801 (id, Some(error))
1802 }
1803
1804 pub fn compute_pipeline_label<A: HalApi>(&self, id: id::ComputePipelineId) -> String {
1805 A::hub(self).compute_pipelines.label_for_resource(id)
1806 }
1807
1808 pub fn compute_pipeline_drop<A: HalApi>(&self, compute_pipeline_id: id::ComputePipelineId) {
1809 profiling::scope!("ComputePipeline::drop");
1810 api_log!("ComputePipeline::drop {compute_pipeline_id:?}");
1811
1812 let hub = A::hub(self);
1813
1814 if let Some(pipeline) = hub.compute_pipelines.unregister(compute_pipeline_id) {
1815 let device = &pipeline.device;
1816 let mut life_lock = device.lock_life();
1817 life_lock
1818 .suspected_resources
1819 .compute_pipelines
1820 .insert(pipeline.info.tracker_index(), pipeline.clone());
1821 life_lock.suspected_resources.pipeline_layouts.insert(
1822 pipeline.layout.info.tracker_index(),
1823 pipeline.layout.clone(),
1824 );
1825 }
1826 }
1827
1828 pub fn surface_configure<A: HalApi>(
1829 &self,
1830 surface_id: SurfaceId,
1831 device_id: DeviceId,
1832 config: &wgt::SurfaceConfiguration<Vec<TextureFormat>>,
1833 ) -> Option<present::ConfigureSurfaceError> {
1834 use hal::{Adapter as _, Surface as _};
1835 use present::ConfigureSurfaceError as E;
1836 profiling::scope!("surface_configure");
1837
1838 fn validate_surface_configuration(
1839 config: &mut hal::SurfaceConfiguration,
1840 caps: &hal::SurfaceCapabilities,
1841 max_texture_dimension_2d: u32,
1842 ) -> Result<(), E> {
1843 let width = config.extent.width;
1844 let height = config.extent.height;
1845
1846 if width > max_texture_dimension_2d || height > max_texture_dimension_2d {
1847 return Err(E::TooLarge {
1848 width,
1849 height,
1850 max_texture_dimension_2d,
1851 });
1852 }
1853
1854 if !caps.present_modes.contains(&config.present_mode) {
1855 let new_mode = 'b: loop {
1856 let fallbacks = match config.present_mode {
1860 wgt::PresentMode::AutoVsync => {
1861 &[wgt::PresentMode::FifoRelaxed, wgt::PresentMode::Fifo][..]
1862 }
1863 wgt::PresentMode::AutoNoVsync => &[
1865 wgt::PresentMode::Immediate,
1866 wgt::PresentMode::Mailbox,
1867 wgt::PresentMode::Fifo,
1868 ][..],
1869 _ => {
1870 return Err(E::UnsupportedPresentMode {
1871 requested: config.present_mode,
1872 available: caps.present_modes.clone(),
1873 });
1874 }
1875 };
1876
1877 for &fallback in fallbacks {
1878 if caps.present_modes.contains(&fallback) {
1879 break 'b fallback;
1880 }
1881 }
1882
1883 unreachable!("Fallback system failed to choose present mode. This is a bug. Mode: {:?}, Options: {:?}", config.present_mode, &caps.present_modes);
1884 };
1885
1886 api_log!(
1887 "Automatically choosing presentation mode by rule {:?}. Chose {new_mode:?}",
1888 config.present_mode
1889 );
1890 config.present_mode = new_mode;
1891 }
1892 if !caps.formats.contains(&config.format) {
1893 return Err(E::UnsupportedFormat {
1894 requested: config.format,
1895 available: caps.formats.clone(),
1896 });
1897 }
1898 if !caps
1899 .composite_alpha_modes
1900 .contains(&config.composite_alpha_mode)
1901 {
1902 let new_alpha_mode = 'alpha: loop {
1903 let fallbacks = match config.composite_alpha_mode {
1905 wgt::CompositeAlphaMode::Auto => &[
1906 wgt::CompositeAlphaMode::Opaque,
1907 wgt::CompositeAlphaMode::Inherit,
1908 ][..],
1909 _ => {
1910 return Err(E::UnsupportedAlphaMode {
1911 requested: config.composite_alpha_mode,
1912 available: caps.composite_alpha_modes.clone(),
1913 });
1914 }
1915 };
1916
1917 for &fallback in fallbacks {
1918 if caps.composite_alpha_modes.contains(&fallback) {
1919 break 'alpha fallback;
1920 }
1921 }
1922
1923 unreachable!(
1924 "Fallback system failed to choose alpha mode. This is a bug. \
1925 AlphaMode: {:?}, Options: {:?}",
1926 config.composite_alpha_mode, &caps.composite_alpha_modes
1927 );
1928 };
1929
1930 api_log!(
1931 "Automatically choosing alpha mode by rule {:?}. Chose {new_alpha_mode:?}",
1932 config.composite_alpha_mode
1933 );
1934 config.composite_alpha_mode = new_alpha_mode;
1935 }
1936 if !caps.usage.contains(config.usage) {
1937 return Err(E::UnsupportedUsage);
1938 }
1939 if width == 0 || height == 0 {
1940 return Err(E::ZeroArea);
1941 }
1942 Ok(())
1943 }
1944
1945 log::debug!("configuring surface with {:?}", config);
1946
1947 let error = 'outer: loop {
1948 let user_callbacks;
1950 {
1951 let hub = A::hub(self);
1952 let surface_guard = self.surfaces.read();
1953 let device_guard = hub.devices.read();
1954
1955 let device = match device_guard.get(device_id) {
1956 Ok(device) => device,
1957 Err(_) => break DeviceError::Invalid.into(),
1958 };
1959 if !device.is_valid() {
1960 break DeviceError::Lost.into();
1961 }
1962
1963 #[cfg(feature = "trace")]
1964 if let Some(ref mut trace) = *device.trace.lock() {
1965 trace.add(trace::Action::ConfigureSurface(surface_id, config.clone()));
1966 }
1967
1968 let surface = match surface_guard.get(surface_id) {
1969 Ok(surface) => surface,
1970 Err(_) => break E::InvalidSurface,
1971 };
1972
1973 let caps = unsafe {
1974 let suf = A::surface_as_hal(surface);
1975 let adapter = &device.adapter;
1976 match adapter.raw.adapter.surface_capabilities(suf.unwrap()) {
1977 Some(caps) => caps,
1978 None => break E::UnsupportedQueueFamily,
1979 }
1980 };
1981
1982 let mut hal_view_formats = vec![];
1983 for format in config.view_formats.iter() {
1984 if *format == config.format {
1985 continue;
1986 }
1987 if !caps.formats.contains(&config.format) {
1988 break 'outer E::UnsupportedFormat {
1989 requested: config.format,
1990 available: caps.formats,
1991 };
1992 }
1993 if config.format.remove_srgb_suffix() != format.remove_srgb_suffix() {
1994 break 'outer E::InvalidViewFormat(*format, config.format);
1995 }
1996 hal_view_formats.push(*format);
1997 }
1998
1999 if !hal_view_formats.is_empty() {
2000 if let Err(missing_flag) =
2001 device.require_downlevel_flags(wgt::DownlevelFlags::SURFACE_VIEW_FORMATS)
2002 {
2003 break 'outer E::MissingDownlevelFlags(missing_flag);
2004 }
2005 }
2006
2007 let maximum_frame_latency = config.desired_maximum_frame_latency.clamp(
2008 *caps.maximum_frame_latency.start(),
2009 *caps.maximum_frame_latency.end(),
2010 );
2011 let mut hal_config = hal::SurfaceConfiguration {
2012 maximum_frame_latency,
2013 present_mode: config.present_mode,
2014 composite_alpha_mode: config.alpha_mode,
2015 format: config.format,
2016 extent: wgt::Extent3d {
2017 width: config.width,
2018 height: config.height,
2019 depth_or_array_layers: 1,
2020 },
2021 usage: conv::map_texture_usage(config.usage, hal::FormatAspects::COLOR),
2022 view_formats: hal_view_formats,
2023 };
2024
2025 if let Err(error) = validate_surface_configuration(
2026 &mut hal_config,
2027 &caps,
2028 device.limits.max_texture_dimension_2d,
2029 ) {
2030 break error;
2031 }
2032
2033 let snatch_guard = device.snatchable_lock.read();
2035 let fence = device.fence.read();
2036 let fence = fence.as_ref().unwrap();
2037 match device.maintain(fence, wgt::Maintain::Wait, snatch_guard) {
2038 Ok((closures, _)) => {
2039 user_callbacks = closures;
2040 }
2041 Err(e) => {
2042 break e.into();
2043 }
2044 }
2045
2046 if let Some(present) = surface.presentation.lock().take() {
2048 if present.acquired_texture.is_some() {
2049 break E::PreviousOutputExists;
2050 }
2051 }
2052
2053 match unsafe {
2060 A::surface_as_hal(surface)
2061 .unwrap()
2062 .configure(device.raw(), &hal_config)
2063 } {
2064 Ok(()) => (),
2065 Err(error) => {
2066 break match error {
2067 hal::SurfaceError::Outdated | hal::SurfaceError::Lost => {
2068 E::InvalidSurface
2069 }
2070 hal::SurfaceError::Device(error) => E::Device(error.into()),
2071 hal::SurfaceError::Other(message) => {
2072 log::error!("surface configuration failed: {}", message);
2073 E::InvalidSurface
2074 }
2075 }
2076 }
2077 }
2078
2079 let mut presentation = surface.presentation.lock();
2080 *presentation = Some(present::Presentation {
2081 device: super::any_device::AnyDevice::new(device.clone()),
2082 config: config.clone(),
2083 acquired_texture: None,
2084 });
2085 }
2086
2087 user_callbacks.fire();
2088 return None;
2089 };
2090
2091 Some(error)
2092 }
2093
2094 #[cfg(feature = "replay")]
2095 pub fn device_maintain_ids<A: HalApi>(&self, device_id: DeviceId) -> Result<(), InvalidDevice> {
2098 let hub = A::hub(self);
2099
2100 let device = hub.devices.get(device_id).map_err(|_| InvalidDevice)?;
2101 if !device.is_valid() {
2102 return Err(InvalidDevice);
2103 }
2104 device.lock_life().triage_suspected(&device.trackers);
2105 Ok(())
2106 }
2107
2108 pub fn device_poll<A: HalApi>(
2112 &self,
2113 device_id: DeviceId,
2114 maintain: wgt::Maintain<queue::WrappedSubmissionIndex>,
2115 ) -> Result<bool, WaitIdleError> {
2116 api_log!("Device::poll");
2117
2118 let hub = A::hub(self);
2119 let device = hub
2120 .devices
2121 .get(device_id)
2122 .map_err(|_| DeviceError::Invalid)?;
2123
2124 if let wgt::Maintain::WaitForSubmissionIndex(submission_index) = maintain {
2125 if submission_index.queue_id != device_id.into_queue_id() {
2126 return Err(WaitIdleError::WrongSubmissionIndex(
2127 submission_index.queue_id,
2128 device_id,
2129 ));
2130 }
2131 }
2132
2133 let DevicePoll {
2134 closures,
2135 queue_empty,
2136 } = Self::poll_single_device(&device, maintain)?;
2137
2138 closures.fire();
2139
2140 Ok(queue_empty)
2141 }
2142
2143 fn poll_single_device<A: HalApi>(
2144 device: &crate::device::Device<A>,
2145 maintain: wgt::Maintain<queue::WrappedSubmissionIndex>,
2146 ) -> Result<DevicePoll, WaitIdleError> {
2147 let snatch_guard = device.snatchable_lock.read();
2148 let fence = device.fence.read();
2149 let fence = fence.as_ref().unwrap();
2150 let (closures, queue_empty) = device.maintain(fence, maintain, snatch_guard)?;
2151
2152 device.deferred_resource_destruction();
2155
2156 Ok(DevicePoll {
2157 closures,
2158 queue_empty,
2159 })
2160 }
2161
2162 fn poll_all_devices_of_api<A: HalApi>(
2169 &self,
2170 force_wait: bool,
2171 closures: &mut UserClosures,
2172 ) -> Result<bool, WaitIdleError> {
2173 profiling::scope!("poll_device");
2174
2175 let hub = A::hub(self);
2176 let mut all_queue_empty = true;
2177 {
2178 let device_guard = hub.devices.read();
2179
2180 for (_id, device) in device_guard.iter(A::VARIANT) {
2181 let maintain = if force_wait {
2182 wgt::Maintain::Wait
2183 } else {
2184 wgt::Maintain::Poll
2185 };
2186
2187 let DevicePoll {
2188 closures: cbs,
2189 queue_empty,
2190 } = Self::poll_single_device(device, maintain)?;
2191
2192 all_queue_empty &= queue_empty;
2193
2194 closures.extend(cbs);
2195 }
2196 }
2197
2198 Ok(all_queue_empty)
2199 }
2200
2201 pub fn poll_all_devices(&self, force_wait: bool) -> Result<bool, WaitIdleError> {
2208 api_log!("poll_all_devices");
2209 let mut closures = UserClosures::default();
2210 let mut all_queue_empty = true;
2211
2212 #[cfg(vulkan)]
2213 {
2214 all_queue_empty &=
2215 self.poll_all_devices_of_api::<hal::api::Vulkan>(force_wait, &mut closures)?;
2216 }
2217 #[cfg(metal)]
2218 {
2219 all_queue_empty &=
2220 self.poll_all_devices_of_api::<hal::api::Metal>(force_wait, &mut closures)?;
2221 }
2222 #[cfg(dx12)]
2223 {
2224 all_queue_empty &=
2225 self.poll_all_devices_of_api::<hal::api::Dx12>(force_wait, &mut closures)?;
2226 }
2227 #[cfg(gles)]
2228 {
2229 all_queue_empty &=
2230 self.poll_all_devices_of_api::<hal::api::Gles>(force_wait, &mut closures)?;
2231 }
2232
2233 closures.fire();
2234
2235 Ok(all_queue_empty)
2236 }
2237
2238 pub fn device_label<A: HalApi>(&self, id: DeviceId) -> String {
2239 A::hub(self).devices.label_for_resource(id)
2240 }
2241
2242 pub fn device_start_capture<A: HalApi>(&self, id: DeviceId) {
2243 api_log!("Device::start_capture");
2244
2245 let hub = A::hub(self);
2246
2247 if let Ok(device) = hub.devices.get(id) {
2248 if !device.is_valid() {
2249 return;
2250 }
2251 unsafe { device.raw().start_capture() };
2252 }
2253 }
2254
2255 pub fn device_stop_capture<A: HalApi>(&self, id: DeviceId) {
2256 api_log!("Device::stop_capture");
2257
2258 let hub = A::hub(self);
2259
2260 if let Ok(device) = hub.devices.get(id) {
2261 if !device.is_valid() {
2262 return;
2263 }
2264 unsafe { device.raw().stop_capture() };
2265 }
2266 }
2267
2268 pub fn device_make_invalid<A: HalApi>(&self, device_id: DeviceId) {
2272 let hub = A::hub(self);
2273 hub.devices
2274 .force_replace_with_error(device_id, "Made invalid.");
2275 }
2276
2277 pub fn device_drop<A: HalApi>(&self, device_id: DeviceId) {
2278 profiling::scope!("Device::drop");
2279 api_log!("Device::drop {device_id:?}");
2280
2281 let hub = A::hub(self);
2282 if let Some(device) = hub.devices.unregister(device_id) {
2283 let device_lost_closure = device.lock_life().device_lost_closure.take();
2284 if let Some(closure) = device_lost_closure {
2285 closure.call(DeviceLostReason::Dropped, String::from("Device dropped."));
2286 }
2287
2288 debug_assert!(device.lock_life().queue_empty());
2293 {
2294 let mut pending_writes = device.pending_writes.lock();
2295 let pending_writes = pending_writes.as_mut().unwrap();
2296 pending_writes.deactivate();
2297 }
2298
2299 drop(device);
2300 }
2301 }
2302
2303 pub fn device_set_device_lost_closure<A: HalApi>(
2306 &self,
2307 device_id: DeviceId,
2308 device_lost_closure: DeviceLostClosure,
2309 ) {
2310 let hub = A::hub(self);
2311
2312 if let Ok(Some(device)) = hub.devices.try_get(device_id) {
2313 let mut life_tracker = device.lock_life();
2314 if let Some(existing_closure) = life_tracker.device_lost_closure.take() {
2315 drop(life_tracker);
2317 existing_closure.call(DeviceLostReason::ReplacedCallback, "".to_string());
2318 life_tracker = device.lock_life();
2319 }
2320 life_tracker.device_lost_closure = Some(device_lost_closure);
2321 } else {
2322 device_lost_closure.call(DeviceLostReason::DeviceInvalid, "".to_string());
2327 }
2328 }
2329
2330 pub fn device_destroy<A: HalApi>(&self, device_id: DeviceId) {
2331 api_log!("Device::destroy {device_id:?}");
2332
2333 let hub = A::hub(self);
2334
2335 if let Ok(device) = hub.devices.get(device_id) {
2336 if !device.is_valid() {
2342 return;
2343 }
2344
2345 device.valid.store(false, Ordering::Relaxed);
2353 }
2354 }
2355
2356 pub fn device_mark_lost<A: HalApi>(&self, device_id: DeviceId, message: &str) {
2357 api_log!("Device::mark_lost {device_id:?}");
2358
2359 let hub = A::hub(self);
2360
2361 if let Ok(device) = hub.devices.get(device_id) {
2362 device.lose(message);
2363 }
2364 }
2365
2366 pub fn queue_drop<A: HalApi>(&self, queue_id: QueueId) {
2367 profiling::scope!("Queue::drop");
2368 api_log!("Queue::drop {queue_id:?}");
2369
2370 let hub = A::hub(self);
2371 if let Some(queue) = hub.queues.unregister(queue_id) {
2372 drop(queue);
2373 }
2374 }
2375
2376 pub fn buffer_map_async<A: HalApi>(
2377 &self,
2378 buffer_id: id::BufferId,
2379 offset: BufferAddress,
2380 size: Option<BufferAddress>,
2381 op: BufferMapOperation,
2382 ) -> BufferAccessResult {
2383 api_log!("Buffer::map_async {buffer_id:?} offset {offset:?} size {size:?} op: {op:?}");
2384
2385 if let Err((mut operation, err)) =
2389 self.buffer_map_async_inner::<A>(buffer_id, offset, size, op)
2390 {
2391 if let Some(callback) = operation.callback.take() {
2392 callback.call(Err(err.clone()));
2393 }
2394 log::error!("Buffer::map_async error: {err}");
2395 return Err(err);
2396 }
2397
2398 Ok(())
2399 }
2400
2401 fn buffer_map_async_inner<A: HalApi>(
2404 &self,
2405 buffer_id: id::BufferId,
2406 offset: BufferAddress,
2407 size: Option<BufferAddress>,
2408 op: BufferMapOperation,
2409 ) -> Result<(), (BufferMapOperation, BufferAccessError)> {
2410 profiling::scope!("Buffer::map_async");
2411
2412 let hub = A::hub(self);
2413
2414 let (pub_usage, internal_use) = match op.host {
2415 HostMap::Read => (wgt::BufferUsages::MAP_READ, hal::BufferUses::MAP_READ),
2416 HostMap::Write => (wgt::BufferUsages::MAP_WRITE, hal::BufferUses::MAP_WRITE),
2417 };
2418
2419 let buffer = {
2420 let buffer = hub.buffers.get(buffer_id);
2421
2422 let buffer = match buffer {
2423 Ok(b) => b,
2424 Err(_) => {
2425 return Err((op, BufferAccessError::Invalid));
2426 }
2427 };
2428 {
2429 let snatch_guard = buffer.device.snatchable_lock.read();
2430 if buffer.is_destroyed(&snatch_guard) {
2431 return Err((op, BufferAccessError::Destroyed));
2432 }
2433 }
2434
2435 let range_size = if let Some(size) = size {
2436 size
2437 } else if offset > buffer.size {
2438 0
2439 } else {
2440 buffer.size - offset
2441 };
2442
2443 if offset % wgt::MAP_ALIGNMENT != 0 {
2444 return Err((op, BufferAccessError::UnalignedOffset { offset }));
2445 }
2446 if range_size % wgt::COPY_BUFFER_ALIGNMENT != 0 {
2447 return Err((op, BufferAccessError::UnalignedRangeSize { range_size }));
2448 }
2449
2450 let range = offset..(offset + range_size);
2451
2452 if range.start % wgt::MAP_ALIGNMENT != 0 || range.end % wgt::COPY_BUFFER_ALIGNMENT != 0
2453 {
2454 return Err((op, BufferAccessError::UnalignedRange));
2455 }
2456
2457 let device = &buffer.device;
2458 if !device.is_valid() {
2459 return Err((op, DeviceError::Lost.into()));
2460 }
2461
2462 if let Err(e) = check_buffer_usage(buffer.info.id(), buffer.usage, pub_usage) {
2463 return Err((op, e.into()));
2464 }
2465
2466 if range.start > range.end {
2467 return Err((
2468 op,
2469 BufferAccessError::NegativeRange {
2470 start: range.start,
2471 end: range.end,
2472 },
2473 ));
2474 }
2475 if range.end > buffer.size {
2476 return Err((
2477 op,
2478 BufferAccessError::OutOfBoundsOverrun {
2479 index: range.end,
2480 max: buffer.size,
2481 },
2482 ));
2483 }
2484
2485 {
2486 let map_state = &mut *buffer.map_state.lock();
2487 *map_state = match *map_state {
2488 resource::BufferMapState::Init { .. }
2489 | resource::BufferMapState::Active { .. } => {
2490 return Err((op, BufferAccessError::AlreadyMapped));
2491 }
2492 resource::BufferMapState::Waiting(_) => {
2493 return Err((op, BufferAccessError::MapAlreadyPending));
2494 }
2495 resource::BufferMapState::Idle => {
2496 resource::BufferMapState::Waiting(resource::BufferPendingMapping {
2497 range,
2498 op,
2499 _parent_buffer: buffer.clone(),
2500 })
2501 }
2502 };
2503 }
2504
2505 let snatch_guard = buffer.device.snatchable_lock.read();
2506
2507 {
2508 let mut trackers = buffer.device.as_ref().trackers.lock();
2509 trackers.buffers.set_single(&buffer, internal_use);
2510 let _ = trackers.buffers.drain_transitions(&snatch_guard);
2512 }
2513
2514 drop(snatch_guard);
2515
2516 buffer
2517 };
2518
2519 buffer.device.lock_life().map(&buffer);
2520
2521 Ok(())
2522 }
2523
2524 pub fn buffer_get_mapped_range<A: HalApi>(
2525 &self,
2526 buffer_id: id::BufferId,
2527 offset: BufferAddress,
2528 size: Option<BufferAddress>,
2529 ) -> Result<(*mut u8, u64), BufferAccessError> {
2530 profiling::scope!("Buffer::get_mapped_range");
2531 api_log!("Buffer::get_mapped_range {buffer_id:?} offset {offset:?} size {size:?}");
2532
2533 let hub = A::hub(self);
2534
2535 let buffer = hub
2536 .buffers
2537 .get(buffer_id)
2538 .map_err(|_| BufferAccessError::Invalid)?;
2539
2540 {
2541 let snatch_guard = buffer.device.snatchable_lock.read();
2542 if buffer.is_destroyed(&snatch_guard) {
2543 return Err(BufferAccessError::Destroyed);
2544 }
2545 }
2546
2547 let range_size = if let Some(size) = size {
2548 size
2549 } else if offset > buffer.size {
2550 0
2551 } else {
2552 buffer.size - offset
2553 };
2554
2555 if offset % wgt::MAP_ALIGNMENT != 0 {
2556 return Err(BufferAccessError::UnalignedOffset { offset });
2557 }
2558 if range_size % wgt::COPY_BUFFER_ALIGNMENT != 0 {
2559 return Err(BufferAccessError::UnalignedRangeSize { range_size });
2560 }
2561 let map_state = &*buffer.map_state.lock();
2562 match *map_state {
2563 resource::BufferMapState::Init { ref ptr, .. } => {
2564 if offset + range_size > buffer.size {
2566 return Err(BufferAccessError::OutOfBoundsOverrun {
2567 index: offset + range_size - 1,
2568 max: buffer.size,
2569 });
2570 }
2571 unsafe { Ok((ptr.as_ptr().offset(offset as isize), range_size)) }
2572 }
2573 resource::BufferMapState::Active {
2574 ref ptr, ref range, ..
2575 } => {
2576 if offset < range.start {
2577 return Err(BufferAccessError::OutOfBoundsUnderrun {
2578 index: offset,
2579 min: range.start,
2580 });
2581 }
2582 if offset + range_size > range.end {
2583 return Err(BufferAccessError::OutOfBoundsOverrun {
2584 index: offset + range_size - 1,
2585 max: range.end,
2586 });
2587 }
2588 let relative_offset = (offset - range.start) as isize;
2591 unsafe { Ok((ptr.as_ptr().offset(relative_offset), range_size)) }
2592 }
2593 resource::BufferMapState::Idle | resource::BufferMapState::Waiting(_) => {
2594 Err(BufferAccessError::NotMapped)
2595 }
2596 }
2597 }
2598 pub fn buffer_unmap<A: HalApi>(&self, buffer_id: id::BufferId) -> BufferAccessResult {
2599 profiling::scope!("unmap", "Buffer");
2600 api_log!("Buffer::unmap {buffer_id:?}");
2601
2602 let hub = A::hub(self);
2603
2604 let buffer = hub
2605 .buffers
2606 .get(buffer_id)
2607 .map_err(|_| BufferAccessError::Invalid)?;
2608
2609 let snatch_guard = buffer.device.snatchable_lock.read();
2610 if buffer.is_destroyed(&snatch_guard) {
2611 return Err(BufferAccessError::Destroyed);
2612 }
2613 drop(snatch_guard);
2614
2615 if !buffer.device.is_valid() {
2616 return Err(DeviceError::Lost.into());
2617 }
2618
2619 buffer.unmap()
2620 }
2621}
2622
2623struct DevicePoll {
2624 closures: UserClosures,
2625 queue_empty: bool,
2626}