1#[cfg(feature = "trace")]
2use crate::device::trace;
3use crate::{
4 device::{
5 queue::{EncoderInFlight, SubmittedWorkDoneClosure, TempResource},
6 DeviceError,
7 },
8 hal_api::HalApi,
9 hub::{Hub, Token},
10 id,
11 identity::GlobalIdentityHandlerFactory,
12 resource,
13 track::{BindGroupStates, RenderBundleScope, Tracker},
14 RefCount, Stored, SubmissionIndex,
15};
16use smallvec::SmallVec;
17
18use hal::Device as _;
19use parking_lot::Mutex;
20use thiserror::Error;
21
22use std::mem;
23
24#[derive(Debug, Default)]
26pub(super) struct SuspectedResources {
27 pub(super) buffers: Vec<id::Valid<id::BufferId>>,
28 pub(super) textures: Vec<id::Valid<id::TextureId>>,
29 pub(super) texture_views: Vec<id::Valid<id::TextureViewId>>,
30 pub(super) samplers: Vec<id::Valid<id::SamplerId>>,
31 pub(super) bind_groups: Vec<id::Valid<id::BindGroupId>>,
32 pub(super) compute_pipelines: Vec<id::Valid<id::ComputePipelineId>>,
33 pub(super) render_pipelines: Vec<id::Valid<id::RenderPipelineId>>,
34 pub(super) bind_group_layouts: Vec<id::Valid<id::BindGroupLayoutId>>,
35 pub(super) pipeline_layouts: Vec<Stored<id::PipelineLayoutId>>,
36 pub(super) render_bundles: Vec<id::Valid<id::RenderBundleId>>,
37 pub(super) query_sets: Vec<id::Valid<id::QuerySetId>>,
38}
39
40impl SuspectedResources {
41 pub(super) fn clear(&mut self) {
42 self.buffers.clear();
43 self.textures.clear();
44 self.texture_views.clear();
45 self.samplers.clear();
46 self.bind_groups.clear();
47 self.compute_pipelines.clear();
48 self.render_pipelines.clear();
49 self.bind_group_layouts.clear();
50 self.pipeline_layouts.clear();
51 self.render_bundles.clear();
52 self.query_sets.clear();
53 }
54
55 pub(super) fn extend(&mut self, other: &Self) {
56 self.buffers.extend_from_slice(&other.buffers);
57 self.textures.extend_from_slice(&other.textures);
58 self.texture_views.extend_from_slice(&other.texture_views);
59 self.samplers.extend_from_slice(&other.samplers);
60 self.bind_groups.extend_from_slice(&other.bind_groups);
61 self.compute_pipelines
62 .extend_from_slice(&other.compute_pipelines);
63 self.render_pipelines
64 .extend_from_slice(&other.render_pipelines);
65 self.bind_group_layouts
66 .extend_from_slice(&other.bind_group_layouts);
67 self.pipeline_layouts
68 .extend_from_slice(&other.pipeline_layouts);
69 self.render_bundles.extend_from_slice(&other.render_bundles);
70 self.query_sets.extend_from_slice(&other.query_sets);
71 }
72
73 pub(super) fn add_render_bundle_scope<A: HalApi>(&mut self, trackers: &RenderBundleScope<A>) {
74 self.buffers.extend(trackers.buffers.used());
75 self.textures.extend(trackers.textures.used());
76 self.bind_groups.extend(trackers.bind_groups.used());
77 self.render_pipelines
78 .extend(trackers.render_pipelines.used());
79 self.query_sets.extend(trackers.query_sets.used());
80 }
81
82 pub(super) fn add_bind_group_states<A: HalApi>(&mut self, trackers: &BindGroupStates<A>) {
83 self.buffers.extend(trackers.buffers.used());
84 self.textures.extend(trackers.textures.used());
85 self.texture_views.extend(trackers.views.used());
86 self.samplers.extend(trackers.samplers.used());
87 }
88}
89
90#[derive(Debug)]
92struct NonReferencedResources<A: hal::Api> {
93 buffers: Vec<A::Buffer>,
94 textures: Vec<A::Texture>,
95 texture_views: Vec<A::TextureView>,
96 samplers: Vec<A::Sampler>,
97 bind_groups: Vec<A::BindGroup>,
98 compute_pipes: Vec<A::ComputePipeline>,
99 render_pipes: Vec<A::RenderPipeline>,
100 bind_group_layouts: Vec<A::BindGroupLayout>,
101 pipeline_layouts: Vec<A::PipelineLayout>,
102 query_sets: Vec<A::QuerySet>,
103}
104
105impl<A: hal::Api> NonReferencedResources<A> {
106 fn new() -> Self {
107 Self {
108 buffers: Vec::new(),
109 textures: Vec::new(),
110 texture_views: Vec::new(),
111 samplers: Vec::new(),
112 bind_groups: Vec::new(),
113 compute_pipes: Vec::new(),
114 render_pipes: Vec::new(),
115 bind_group_layouts: Vec::new(),
116 pipeline_layouts: Vec::new(),
117 query_sets: Vec::new(),
118 }
119 }
120
121 fn extend(&mut self, other: Self) {
122 self.buffers.extend(other.buffers);
123 self.textures.extend(other.textures);
124 self.texture_views.extend(other.texture_views);
125 self.samplers.extend(other.samplers);
126 self.bind_groups.extend(other.bind_groups);
127 self.compute_pipes.extend(other.compute_pipes);
128 self.render_pipes.extend(other.render_pipes);
129 self.query_sets.extend(other.query_sets);
130 assert!(other.bind_group_layouts.is_empty());
131 assert!(other.pipeline_layouts.is_empty());
132 }
133
134 unsafe fn clean(&mut self, device: &A::Device) {
135 if !self.buffers.is_empty() {
136 profiling::scope!("destroy_buffers");
137 for raw in self.buffers.drain(..) {
138 unsafe { device.destroy_buffer(raw) };
139 }
140 }
141 if !self.textures.is_empty() {
142 profiling::scope!("destroy_textures");
143 for raw in self.textures.drain(..) {
144 unsafe { device.destroy_texture(raw) };
145 }
146 }
147 if !self.texture_views.is_empty() {
148 profiling::scope!("destroy_texture_views");
149 for raw in self.texture_views.drain(..) {
150 unsafe { device.destroy_texture_view(raw) };
151 }
152 }
153 if !self.samplers.is_empty() {
154 profiling::scope!("destroy_samplers");
155 for raw in self.samplers.drain(..) {
156 unsafe { device.destroy_sampler(raw) };
157 }
158 }
159 if !self.bind_groups.is_empty() {
160 profiling::scope!("destroy_bind_groups");
161 for raw in self.bind_groups.drain(..) {
162 unsafe { device.destroy_bind_group(raw) };
163 }
164 }
165 if !self.compute_pipes.is_empty() {
166 profiling::scope!("destroy_compute_pipelines");
167 for raw in self.compute_pipes.drain(..) {
168 unsafe { device.destroy_compute_pipeline(raw) };
169 }
170 }
171 if !self.render_pipes.is_empty() {
172 profiling::scope!("destroy_render_pipelines");
173 for raw in self.render_pipes.drain(..) {
174 unsafe { device.destroy_render_pipeline(raw) };
175 }
176 }
177 if !self.bind_group_layouts.is_empty() {
178 profiling::scope!("destroy_bind_group_layouts");
179 for raw in self.bind_group_layouts.drain(..) {
180 unsafe { device.destroy_bind_group_layout(raw) };
181 }
182 }
183 if !self.pipeline_layouts.is_empty() {
184 profiling::scope!("destroy_pipeline_layouts");
185 for raw in self.pipeline_layouts.drain(..) {
186 unsafe { device.destroy_pipeline_layout(raw) };
187 }
188 }
189 if !self.query_sets.is_empty() {
190 profiling::scope!("destroy_query_sets");
191 for raw in self.query_sets.drain(..) {
192 unsafe { device.destroy_query_set(raw) };
193 }
194 }
195 }
196}
197
198struct ActiveSubmission<A: hal::Api> {
200 index: SubmissionIndex,
205
206 last_resources: NonReferencedResources<A>,
217
218 mapped: Vec<id::Valid<id::BufferId>>,
220
221 encoders: Vec<EncoderInFlight<A>>,
222 work_done_closures: SmallVec<[SubmittedWorkDoneClosure; 1]>,
223}
224
225#[derive(Clone, Debug, Error)]
226#[non_exhaustive]
227pub enum WaitIdleError {
228 #[error(transparent)]
229 Device(#[from] DeviceError),
230 #[error("Tried to wait using a submission index from the wrong device. Submission index is from device {0:?}. Called poll on device {1:?}.")]
231 WrongSubmissionIndex(id::QueueId, id::DeviceId),
232 #[error("GPU got stuck :(")]
233 StuckGpu,
234}
235
236pub(super) struct LifetimeTracker<A: hal::Api> {
274 mapped: Vec<Stored<id::BufferId>>,
277
278 pub future_suspected_buffers: Vec<Stored<id::BufferId>>,
281
282 pub future_suspected_textures: Vec<Stored<id::TextureId>>,
284
285 pub suspected_resources: SuspectedResources,
288
289 active: Vec<ActiveSubmission<A>>,
296
297 free_resources: NonReferencedResources<A>,
303
304 ready_to_map: Vec<id::Valid<id::BufferId>>,
307}
308
309impl<A: hal::Api> LifetimeTracker<A> {
310 pub fn new() -> Self {
311 Self {
312 mapped: Vec::new(),
313 future_suspected_buffers: Vec::new(),
314 future_suspected_textures: Vec::new(),
315 suspected_resources: SuspectedResources::default(),
316 active: Vec::new(),
317 free_resources: NonReferencedResources::new(),
318 ready_to_map: Vec::new(),
319 }
320 }
321
322 pub fn queue_empty(&self) -> bool {
324 self.active.is_empty()
325 }
326
327 pub fn track_submission(
329 &mut self,
330 index: SubmissionIndex,
331 temp_resources: impl Iterator<Item = TempResource<A>>,
332 encoders: Vec<EncoderInFlight<A>>,
333 ) {
334 let mut last_resources = NonReferencedResources::new();
335 for res in temp_resources {
336 match res {
337 TempResource::Buffer(raw) => last_resources.buffers.push(raw),
338 TempResource::Texture(raw, views) => {
339 last_resources.textures.push(raw);
340 last_resources.texture_views.extend(views);
341 }
342 }
343 }
344
345 self.active.push(ActiveSubmission {
346 index,
347 last_resources,
348 mapped: Vec::new(),
349 encoders,
350 work_done_closures: SmallVec::new(),
351 });
352 }
353
354 pub fn post_submit(&mut self) {
355 self.suspected_resources.buffers.extend(
356 self.future_suspected_buffers
357 .drain(..)
358 .map(|stored| stored.value),
359 );
360 self.suspected_resources.textures.extend(
361 self.future_suspected_textures
362 .drain(..)
363 .map(|stored| stored.value),
364 );
365 }
366
367 pub(crate) fn map(&mut self, value: id::Valid<id::BufferId>, ref_count: RefCount) {
368 self.mapped.push(Stored { value, ref_count });
369 }
370
371 #[must_use]
393 pub fn triage_submissions(
394 &mut self,
395 last_done: SubmissionIndex,
396 command_allocator: &Mutex<super::CommandAllocator<A>>,
397 ) -> SmallVec<[SubmittedWorkDoneClosure; 1]> {
398 profiling::scope!("triage_submissions");
399
400 let done_count = self
403 .active
404 .iter()
405 .position(|a| a.index > last_done)
406 .unwrap_or(self.active.len());
407
408 let mut work_done_closures = SmallVec::new();
409 for a in self.active.drain(..done_count) {
410 log::trace!("Active submission {} is done", a.index);
411 self.free_resources.extend(a.last_resources);
412 self.ready_to_map.extend(a.mapped);
413 for encoder in a.encoders {
414 let raw = unsafe { encoder.land() };
415 command_allocator.lock().release_encoder(raw);
416 }
417 work_done_closures.extend(a.work_done_closures);
418 }
419 work_done_closures
420 }
421
422 pub fn cleanup(&mut self, device: &A::Device) {
423 profiling::scope!("LifetimeTracker::cleanup");
424 unsafe {
425 self.free_resources.clean(device);
426 }
427 }
428
429 pub fn schedule_resource_destruction(
430 &mut self,
431 temp_resource: TempResource<A>,
432 last_submit_index: SubmissionIndex,
433 ) {
434 let resources = self
435 .active
436 .iter_mut()
437 .find(|a| a.index == last_submit_index)
438 .map_or(&mut self.free_resources, |a| &mut a.last_resources);
439 match temp_resource {
440 TempResource::Buffer(raw) => resources.buffers.push(raw),
441 TempResource::Texture(raw, views) => {
442 resources.texture_views.extend(views);
443 resources.textures.push(raw);
444 }
445 }
446 }
447
448 pub fn add_work_done_closure(
449 &mut self,
450 closure: SubmittedWorkDoneClosure,
451 ) -> Option<SubmittedWorkDoneClosure> {
452 match self.active.last_mut() {
453 Some(active) => {
454 active.work_done_closures.push(closure);
455 None
456 }
457 None => Some(closure),
460 }
461 }
462}
463
464impl<A: HalApi> LifetimeTracker<A> {
465 pub(super) fn triage_suspected<G: GlobalIdentityHandlerFactory>(
505 &mut self,
506 hub: &Hub<A, G>,
507 trackers: &Mutex<Tracker<A>>,
508 #[cfg(feature = "trace")] trace: Option<&Mutex<trace::Trace>>,
509 token: &mut Token<super::Device<A>>,
510 ) {
511 profiling::scope!("triage_suspected");
512
513 if !self.suspected_resources.render_bundles.is_empty() {
514 let (mut guard, _) = hub.render_bundles.write(token);
515 let mut trackers = trackers.lock();
516
517 while let Some(id) = self.suspected_resources.render_bundles.pop() {
518 if trackers.bundles.remove_abandoned(id) {
519 log::debug!("Bundle {:?} will be destroyed", id);
520 #[cfg(feature = "trace")]
521 if let Some(t) = trace {
522 t.lock().add(trace::Action::DestroyRenderBundle(id.0));
523 }
524
525 if let Some(res) = hub.render_bundles.unregister_locked(id.0, &mut *guard) {
526 self.suspected_resources.add_render_bundle_scope(&res.used);
527 }
528 }
529 }
530 }
531
532 if !self.suspected_resources.bind_groups.is_empty() {
533 let (mut guard, _) = hub.bind_groups.write(token);
534 let mut trackers = trackers.lock();
535
536 while let Some(id) = self.suspected_resources.bind_groups.pop() {
537 if trackers.bind_groups.remove_abandoned(id) {
538 log::debug!("Bind group {:?} will be destroyed", id);
539 #[cfg(feature = "trace")]
540 if let Some(t) = trace {
541 t.lock().add(trace::Action::DestroyBindGroup(id.0));
542 }
543
544 if let Some(res) = hub.bind_groups.unregister_locked(id.0, &mut *guard) {
545 self.suspected_resources.add_bind_group_states(&res.used);
546
547 self.suspected_resources
548 .bind_group_layouts
549 .push(res.layout_id);
550
551 let submit_index = res.life_guard.life_count();
552 self.active
553 .iter_mut()
554 .find(|a| a.index == submit_index)
555 .map_or(&mut self.free_resources, |a| &mut a.last_resources)
556 .bind_groups
557 .push(res.raw);
558 }
559 }
560 }
561 }
562
563 if !self.suspected_resources.texture_views.is_empty() {
564 let (mut guard, _) = hub.texture_views.write(token);
565 let mut trackers = trackers.lock();
566
567 let mut list = mem::take(&mut self.suspected_resources.texture_views);
568 for id in list.drain(..) {
569 if trackers.views.remove_abandoned(id) {
570 log::debug!("Texture view {:?} will be destroyed", id);
571 #[cfg(feature = "trace")]
572 if let Some(t) = trace {
573 t.lock().add(trace::Action::DestroyTextureView(id.0));
574 }
575
576 if let Some(res) = hub.texture_views.unregister_locked(id.0, &mut *guard) {
577 self.suspected_resources.textures.push(res.parent_id.value);
578 let submit_index = res.life_guard.life_count();
579 self.active
580 .iter_mut()
581 .find(|a| a.index == submit_index)
582 .map_or(&mut self.free_resources, |a| &mut a.last_resources)
583 .texture_views
584 .push(res.raw);
585 }
586 }
587 }
588 self.suspected_resources.texture_views = list;
589 }
590
591 if !self.suspected_resources.textures.is_empty() {
592 let (mut guard, _) = hub.textures.write(token);
593 let mut trackers = trackers.lock();
594
595 for id in self.suspected_resources.textures.drain(..) {
596 if trackers.textures.remove_abandoned(id) {
597 log::debug!("Texture {:?} will be destroyed", id);
598 #[cfg(feature = "trace")]
599 if let Some(t) = trace {
600 t.lock().add(trace::Action::DestroyTexture(id.0));
601 }
602
603 if let Some(res) = hub.textures.unregister_locked(id.0, &mut *guard) {
604 let submit_index = res.life_guard.life_count();
605 let raw = match res.inner {
606 resource::TextureInner::Native { raw: Some(raw) } => raw,
607 _ => continue,
608 };
609 let non_referenced_resources = self
610 .active
611 .iter_mut()
612 .find(|a| a.index == submit_index)
613 .map_or(&mut self.free_resources, |a| &mut a.last_resources);
614
615 non_referenced_resources.textures.push(raw);
616 if let resource::TextureClearMode::RenderPass { clear_views, .. } =
617 res.clear_mode
618 {
619 non_referenced_resources
620 .texture_views
621 .extend(clear_views.into_iter());
622 }
623 }
624 }
625 }
626 }
627
628 if !self.suspected_resources.samplers.is_empty() {
629 let (mut guard, _) = hub.samplers.write(token);
630 let mut trackers = trackers.lock();
631
632 for id in self.suspected_resources.samplers.drain(..) {
633 if trackers.samplers.remove_abandoned(id) {
634 log::debug!("Sampler {:?} will be destroyed", id);
635 #[cfg(feature = "trace")]
636 if let Some(t) = trace {
637 t.lock().add(trace::Action::DestroySampler(id.0));
638 }
639
640 if let Some(res) = hub.samplers.unregister_locked(id.0, &mut *guard) {
641 let submit_index = res.life_guard.life_count();
642 self.active
643 .iter_mut()
644 .find(|a| a.index == submit_index)
645 .map_or(&mut self.free_resources, |a| &mut a.last_resources)
646 .samplers
647 .push(res.raw);
648 }
649 }
650 }
651 }
652
653 if !self.suspected_resources.buffers.is_empty() {
654 let (mut guard, _) = hub.buffers.write(token);
655 let mut trackers = trackers.lock();
656
657 for id in self.suspected_resources.buffers.drain(..) {
658 if trackers.buffers.remove_abandoned(id) {
659 log::debug!("Buffer {:?} will be destroyed", id);
660 #[cfg(feature = "trace")]
661 if let Some(t) = trace {
662 t.lock().add(trace::Action::DestroyBuffer(id.0));
663 }
664
665 if let Some(res) = hub.buffers.unregister_locked(id.0, &mut *guard) {
666 let submit_index = res.life_guard.life_count();
667 if let resource::BufferMapState::Init { stage_buffer, .. } = res.map_state {
668 self.free_resources.buffers.push(stage_buffer);
669 }
670 self.active
671 .iter_mut()
672 .find(|a| a.index == submit_index)
673 .map_or(&mut self.free_resources, |a| &mut a.last_resources)
674 .buffers
675 .extend(res.raw);
676 }
677 }
678 }
679 }
680
681 if !self.suspected_resources.compute_pipelines.is_empty() {
682 let (mut guard, _) = hub.compute_pipelines.write(token);
683 let mut trackers = trackers.lock();
684
685 for id in self.suspected_resources.compute_pipelines.drain(..) {
686 if trackers.compute_pipelines.remove_abandoned(id) {
687 log::debug!("Compute pipeline {:?} will be destroyed", id);
688 #[cfg(feature = "trace")]
689 if let Some(t) = trace {
690 t.lock().add(trace::Action::DestroyComputePipeline(id.0));
691 }
692
693 if let Some(res) = hub.compute_pipelines.unregister_locked(id.0, &mut *guard) {
694 let submit_index = res.life_guard.life_count();
695 self.active
696 .iter_mut()
697 .find(|a| a.index == submit_index)
698 .map_or(&mut self.free_resources, |a| &mut a.last_resources)
699 .compute_pipes
700 .push(res.raw);
701 }
702 }
703 }
704 }
705
706 if !self.suspected_resources.render_pipelines.is_empty() {
707 let (mut guard, _) = hub.render_pipelines.write(token);
708 let mut trackers = trackers.lock();
709
710 for id in self.suspected_resources.render_pipelines.drain(..) {
711 if trackers.render_pipelines.remove_abandoned(id) {
712 log::debug!("Render pipeline {:?} will be destroyed", id);
713 #[cfg(feature = "trace")]
714 if let Some(t) = trace {
715 t.lock().add(trace::Action::DestroyRenderPipeline(id.0));
716 }
717
718 if let Some(res) = hub.render_pipelines.unregister_locked(id.0, &mut *guard) {
719 let submit_index = res.life_guard.life_count();
720 self.active
721 .iter_mut()
722 .find(|a| a.index == submit_index)
723 .map_or(&mut self.free_resources, |a| &mut a.last_resources)
724 .render_pipes
725 .push(res.raw);
726 }
727 }
728 }
729 }
730
731 if !self.suspected_resources.pipeline_layouts.is_empty() {
732 let (mut guard, _) = hub.pipeline_layouts.write(token);
733
734 for Stored {
735 value: id,
736 ref_count,
737 } in self.suspected_resources.pipeline_layouts.drain(..)
738 {
739 if ref_count.load() == 1 {
741 log::debug!("Pipeline layout {:?} will be destroyed", id);
742 #[cfg(feature = "trace")]
743 if let Some(t) = trace {
744 t.lock().add(trace::Action::DestroyPipelineLayout(id.0));
745 }
746
747 if let Some(lay) = hub.pipeline_layouts.unregister_locked(id.0, &mut *guard) {
748 self.suspected_resources
749 .bind_group_layouts
750 .extend_from_slice(&lay.bind_group_layout_ids);
751 self.free_resources.pipeline_layouts.push(lay.raw);
752 }
753 }
754 }
755 }
756
757 if !self.suspected_resources.bind_group_layouts.is_empty() {
758 let (mut guard, _) = hub.bind_group_layouts.write(token);
759
760 for id in self.suspected_resources.bind_group_layouts.drain(..) {
761 if guard[id].multi_ref_count.dec_and_check_empty() {
766 log::debug!("Bind group layout {:?} will be destroyed", id);
767 #[cfg(feature = "trace")]
768 if let Some(t) = trace {
769 t.lock().add(trace::Action::DestroyBindGroupLayout(id.0));
770 }
771 if let Some(lay) = hub.bind_group_layouts.unregister_locked(id.0, &mut *guard) {
772 self.free_resources.bind_group_layouts.push(lay.raw);
773 }
774 }
775 }
776 }
777
778 if !self.suspected_resources.query_sets.is_empty() {
779 let (mut guard, _) = hub.query_sets.write(token);
780 let mut trackers = trackers.lock();
781
782 for id in self.suspected_resources.query_sets.drain(..) {
783 if trackers.query_sets.remove_abandoned(id) {
784 log::debug!("Query set {:?} will be destroyed", id);
785 if let Some(res) = hub.query_sets.unregister_locked(id.0, &mut *guard) {
788 let submit_index = res.life_guard.life_count();
789 self.active
790 .iter_mut()
791 .find(|a| a.index == submit_index)
792 .map_or(&mut self.free_resources, |a| &mut a.last_resources)
793 .query_sets
794 .push(res.raw);
795 }
796 }
797 }
798 }
799 }
800
801 pub(super) fn triage_mapped<G: GlobalIdentityHandlerFactory>(
806 &mut self,
807 hub: &Hub<A, G>,
808 token: &mut Token<super::Device<A>>,
809 ) {
810 if self.mapped.is_empty() {
811 return;
812 }
813 let (buffer_guard, _) = hub.buffers.read(token);
814
815 for stored in self.mapped.drain(..) {
816 let resource_id = stored.value;
817 let buf = &buffer_guard[resource_id];
818
819 let submit_index = buf.life_guard.life_count();
820 log::trace!(
821 "Mapping of {:?} at submission {:?} gets assigned to active {:?}",
822 resource_id,
823 submit_index,
824 self.active.iter().position(|a| a.index == submit_index)
825 );
826
827 self.active
828 .iter_mut()
829 .find(|a| a.index == submit_index)
830 .map_or(&mut self.ready_to_map, |a| &mut a.mapped)
831 .push(resource_id);
832 }
833 }
834
835 #[must_use]
841 pub(super) fn handle_mapping<G: GlobalIdentityHandlerFactory>(
842 &mut self,
843 hub: &Hub<A, G>,
844 raw: &A::Device,
845 trackers: &Mutex<Tracker<A>>,
846 token: &mut Token<super::Device<A>>,
847 ) -> Vec<super::BufferMapPendingClosure> {
848 if self.ready_to_map.is_empty() {
849 return Vec::new();
850 }
851 let (mut buffer_guard, _) = hub.buffers.write(token);
852 let mut pending_callbacks: Vec<super::BufferMapPendingClosure> =
853 Vec::with_capacity(self.ready_to_map.len());
854 let mut trackers = trackers.lock();
855 for buffer_id in self.ready_to_map.drain(..) {
856 let buffer = &mut buffer_guard[buffer_id];
857 if buffer.life_guard.ref_count.is_none() && trackers.buffers.remove_abandoned(buffer_id)
858 {
859 buffer.map_state = resource::BufferMapState::Idle;
860 log::debug!("Mapping request is dropped because the buffer is destroyed.");
861 if let Some(buf) = hub
862 .buffers
863 .unregister_locked(buffer_id.0, &mut *buffer_guard)
864 {
865 self.free_resources.buffers.extend(buf.raw);
866 }
867 } else {
868 let mapping = match std::mem::replace(
869 &mut buffer.map_state,
870 resource::BufferMapState::Idle,
871 ) {
872 resource::BufferMapState::Waiting(pending_mapping) => pending_mapping,
873 resource::BufferMapState::Idle => continue,
875 active @ resource::BufferMapState::Active { .. } => {
878 buffer.map_state = active;
879 continue;
880 }
881 _ => panic!("No pending mapping."),
882 };
883 let status = if mapping.range.start != mapping.range.end {
884 log::debug!("Buffer {:?} map state -> Active", buffer_id);
885 let host = mapping.op.host;
886 let size = mapping.range.end - mapping.range.start;
887 match super::map_buffer(raw, buffer, mapping.range.start, size, host) {
888 Ok(ptr) => {
889 buffer.map_state = resource::BufferMapState::Active {
890 ptr,
891 range: mapping.range.start..mapping.range.start + size,
892 host,
893 };
894 Ok(())
895 }
896 Err(e) => {
897 log::error!("Mapping failed {:?}", e);
898 Err(e)
899 }
900 }
901 } else {
902 buffer.map_state = resource::BufferMapState::Active {
903 ptr: std::ptr::NonNull::dangling(),
904 range: mapping.range,
905 host: mapping.op.host,
906 };
907 Ok(())
908 };
909 pending_callbacks.push((mapping.op, status));
910 }
911 }
912 pending_callbacks
913 }
914}