1use alloc::{
2 borrow::Cow,
3 boxed::Box,
4 string::{String, ToString as _},
5 sync::{Arc, Weak},
6 vec::Vec,
7};
8use core::{
9 fmt,
10 mem::{self, ManuallyDrop},
11 num::NonZeroU32,
12 sync::atomic::{AtomicBool, Ordering},
13};
14use hal::ShouldBeNonZeroExt;
15
16use arrayvec::ArrayVec;
17use bitflags::Flags;
18use smallvec::SmallVec;
19use wgt::{
20 math::align_to, DeviceLostReason, TextureFormat, TextureSampleType, TextureSelector,
21 TextureViewDimension,
22};
23
24#[cfg(feature = "trace")]
25use crate::device::trace;
26use crate::{
27 api_log,
28 binding_model::{
29 self, BindGroup, BindGroupLateBufferBindingInfo, BindGroupLayout, BindGroupLayoutEntryError,
30 },
31 command, conv,
32 device::{
33 bgl, create_validator, life::WaitIdleError, map_buffer, AttachmentData,
34 DeviceLostInvocation, HostMap, MissingDownlevelFlags, MissingFeatures, RenderPassContext,
35 },
36 hal_label,
37 init_tracker::{
38 BufferInitTracker, BufferInitTrackerAction, MemoryInitKind, TextureInitRange,
39 TextureInitTrackerAction,
40 },
41 instance::{Adapter, RequestDeviceError},
42 lock::{rank, Mutex, RwLock},
43 pipeline,
44 pool::ResourcePool,
45 present,
46 resource::{
47 self, Buffer, ExternalTexture, Fallible, Labeled, ParentDevice, QuerySet,
48 RawResourceAccess, Sampler, StagingBuffer, Texture, TextureView,
49 TextureViewNotRenderableReason, Tlas, TrackingData,
50 },
51 resource_log,
52 snatch::{SnatchGuard, SnatchLock, Snatchable},
53 timestamp_normalization::TIMESTAMP_NORMALIZATION_BUFFER_USES,
54 track::{BindGroupStates, DeviceTracker, TrackerIndexAllocators, UsageScope, UsageScopePool},
55 validation,
56 weak_vec::WeakVec,
57 FastHashMap, LabelHelpers, OnceCellOrLock,
58};
59
60use super::{
61 queue::Queue, DeviceDescriptor, DeviceError, DeviceLostClosure, UserClosures,
62 ENTRYPOINT_FAILURE_ERROR, ZERO_BUFFER_SIZE,
63};
64
65#[cfg(supports_64bit_atomics)]
66use core::sync::atomic::AtomicU64;
67#[cfg(not(supports_64bit_atomics))]
68use portable_atomic::AtomicU64;
69
70pub(crate) struct CommandIndices {
71 pub(crate) active_submission_index: hal::FenceValue,
79 pub(crate) next_acceleration_structure_build_command_index: u64,
80}
81
82#[repr(C)]
89#[derive(Copy, Clone, bytemuck::Zeroable, bytemuck::Pod)]
90pub struct ExternalTextureParams {
91 pub yuv_conversion_matrix: [f32; 16],
96
97 pub gamut_conversion_matrix: [f32; 12],
110
111 pub src_transfer_function: wgt::ExternalTextureTransferFunction,
115
116 pub dst_transfer_function: wgt::ExternalTextureTransferFunction,
119
120 pub sample_transform: [f32; 6],
133
134 pub load_transform: [f32; 6],
150
151 pub size: [u32; 2],
164
165 pub num_planes: u32,
169 pub _padding: [u8; 4],
171}
172
173impl ExternalTextureParams {
174 pub fn from_desc<L>(desc: &wgt::ExternalTextureDescriptor<L>) -> Self {
175 let gamut_conversion_matrix = [
176 desc.gamut_conversion_matrix[0],
177 desc.gamut_conversion_matrix[1],
178 desc.gamut_conversion_matrix[2],
179 0.0, desc.gamut_conversion_matrix[3],
181 desc.gamut_conversion_matrix[4],
182 desc.gamut_conversion_matrix[5],
183 0.0, desc.gamut_conversion_matrix[6],
185 desc.gamut_conversion_matrix[7],
186 desc.gamut_conversion_matrix[8],
187 0.0, ];
189
190 Self {
191 yuv_conversion_matrix: desc.yuv_conversion_matrix,
192 gamut_conversion_matrix,
193 src_transfer_function: desc.src_transfer_function,
194 dst_transfer_function: desc.dst_transfer_function,
195 size: [desc.width, desc.height],
196 sample_transform: desc.sample_transform,
197 load_transform: desc.load_transform,
198 num_planes: desc.num_planes() as u32,
199 _padding: Default::default(),
200 }
201 }
202}
203
204pub struct Device {
207 raw: Box<dyn hal::DynDevice>,
208 pub(crate) adapter: Arc<Adapter>,
209 pub(crate) queue: OnceCellOrLock<Weak<Queue>>,
210 pub(crate) zero_buffer: ManuallyDrop<Box<dyn hal::DynBuffer>>,
211 label: String,
213
214 pub(crate) command_allocator: command::CommandAllocator,
215
216 pub(crate) command_indices: RwLock<CommandIndices>,
217
218 pub(crate) last_successful_submission_index: hal::AtomicFenceValue,
228
229 pub(crate) fence: RwLock<ManuallyDrop<Box<dyn hal::DynFence>>>,
232 pub(crate) snatchable_lock: SnatchLock,
233
234 pub(crate) valid: AtomicBool,
246
247 pub(crate) device_lost_closure: Mutex<Option<DeviceLostClosure>>,
251
252 pub(crate) trackers: Mutex<DeviceTracker>,
254 pub(crate) tracker_indices: TrackerIndexAllocators,
255 pub(crate) bgl_pool: ResourcePool<bgl::EntryMap, BindGroupLayout>,
257 pub(crate) alignments: hal::Alignments,
258 pub(crate) limits: wgt::Limits,
259 pub(crate) features: wgt::Features,
260 pub(crate) downlevel: wgt::DownlevelCapabilities,
261 pub(crate) instance_flags: wgt::InstanceFlags,
262 pub(crate) deferred_destroy: Mutex<Vec<DeferredDestroy>>,
263 pub(crate) usage_scopes: UsageScopePool,
264 pub(crate) indirect_validation: Option<crate::indirect_validation::IndirectValidation>,
265 pub(crate) timestamp_normalizer:
267 OnceCellOrLock<crate::timestamp_normalization::TimestampNormalizer>,
268 pub(crate) default_external_texture_params_buffer: ManuallyDrop<Box<dyn hal::DynBuffer>>,
273 #[cfg(feature = "trace")]
275 pub(crate) trace: Mutex<Option<trace::Trace>>,
276}
277
278pub(crate) enum DeferredDestroy {
279 TextureViews(WeakVec<TextureView>),
280 BindGroups(WeakVec<BindGroup>),
281}
282
283impl fmt::Debug for Device {
284 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
285 f.debug_struct("Device")
286 .field("label", &self.label())
287 .field("limits", &self.limits)
288 .field("features", &self.features)
289 .field("downlevel", &self.downlevel)
290 .finish()
291 }
292}
293
294impl Drop for Device {
295 fn drop(&mut self) {
296 resource_log!("Drop {}", self.error_ident());
297
298 let zero_buffer = unsafe { ManuallyDrop::take(&mut self.zero_buffer) };
300 let default_external_texture_params_buffer =
303 unsafe { ManuallyDrop::take(&mut self.default_external_texture_params_buffer) };
304 let fence = unsafe { ManuallyDrop::take(&mut self.fence.write()) };
306 if let Some(indirect_validation) = self.indirect_validation.take() {
307 indirect_validation.dispose(self.raw.as_ref());
308 }
309 if let Some(timestamp_normalizer) = self.timestamp_normalizer.take() {
310 timestamp_normalizer.dispose(self.raw.as_ref());
311 }
312 unsafe {
313 self.raw.destroy_buffer(zero_buffer);
314 self.raw
315 .destroy_buffer(default_external_texture_params_buffer);
316 self.raw.destroy_fence(fence);
317 }
318 }
319}
320
321impl Device {
322 pub(crate) fn raw(&self) -> &dyn hal::DynDevice {
323 self.raw.as_ref()
324 }
325 pub(crate) fn require_features(&self, feature: wgt::Features) -> Result<(), MissingFeatures> {
326 if self.features.contains(feature) {
327 Ok(())
328 } else {
329 Err(MissingFeatures(feature))
330 }
331 }
332
333 pub(crate) fn require_downlevel_flags(
334 &self,
335 flags: wgt::DownlevelFlags,
336 ) -> Result<(), MissingDownlevelFlags> {
337 if self.downlevel.flags.contains(flags) {
338 Ok(())
339 } else {
340 Err(MissingDownlevelFlags(flags))
341 }
342 }
343
344 pub unsafe fn start_graphics_debugger_capture(&self) {
350 api_log!("Device::start_graphics_debugger_capture");
351
352 if !self.is_valid() {
353 return;
354 }
355 unsafe { self.raw().start_graphics_debugger_capture() };
356 }
357
358 pub unsafe fn stop_graphics_debugger_capture(&self) {
364 api_log!("Device::stop_graphics_debugger_capture");
365
366 if !self.is_valid() {
367 return;
368 }
369 unsafe { self.raw().stop_graphics_debugger_capture() };
370 }
371}
372
373impl Device {
374 pub(crate) fn new(
375 raw_device: Box<dyn hal::DynDevice>,
376 adapter: &Arc<Adapter>,
377 desc: &DeviceDescriptor,
378 instance_flags: wgt::InstanceFlags,
379 ) -> Result<Self, DeviceError> {
380 #[cfg(not(feature = "trace"))]
381 match &desc.trace {
382 wgt::Trace::Off => {}
383 _ => {
384 log::error!("wgpu-core feature 'trace' is not enabled");
385 }
386 };
387 #[cfg(feature = "trace")]
388 let trace_dir_name: Option<&std::path::PathBuf> = match &desc.trace {
389 wgt::Trace::Off => None,
390 wgt::Trace::Directory(d) => Some(d),
391 t => {
394 log::error!("unimplemented wgpu_types::Trace variant {t:?}");
395 None
396 }
397 };
398
399 let fence = unsafe { raw_device.create_fence() }.map_err(DeviceError::from_hal)?;
400
401 let command_allocator = command::CommandAllocator::new();
402
403 let rt_uses = if desc
404 .required_features
405 .intersects(wgt::Features::EXPERIMENTAL_RAY_QUERY)
406 {
407 wgt::BufferUses::TOP_LEVEL_ACCELERATION_STRUCTURE_INPUT
408 } else {
409 wgt::BufferUses::empty()
410 };
411
412 let zero_buffer = unsafe {
414 raw_device.create_buffer(&hal::BufferDescriptor {
415 label: hal_label(Some("(wgpu internal) zero init buffer"), instance_flags),
416 size: ZERO_BUFFER_SIZE,
417 usage: wgt::BufferUses::COPY_SRC | wgt::BufferUses::COPY_DST | rt_uses,
418 memory_flags: hal::MemoryFlags::empty(),
419 })
420 }
421 .map_err(DeviceError::from_hal)?;
422
423 let default_external_texture_params_buffer = unsafe {
424 raw_device.create_buffer(&hal::BufferDescriptor {
425 label: hal_label(
426 Some("(wgpu internal) default external texture params buffer"),
427 instance_flags,
428 ),
429 size: size_of::<ExternalTextureParams>() as _,
430 usage: wgt::BufferUses::COPY_DST | wgt::BufferUses::UNIFORM,
431 memory_flags: hal::MemoryFlags::empty(),
432 })
433 }
434 .map_err(DeviceError::from_hal)?;
435
436 let alignments = adapter.raw.capabilities.alignments.clone();
438 let downlevel = adapter.raw.capabilities.downlevel.clone();
439 let limits = &adapter.raw.capabilities.limits;
440
441 let enable_indirect_validation = instance_flags
442 .contains(wgt::InstanceFlags::VALIDATION_INDIRECT_CALL)
443 && downlevel.flags.contains(
444 wgt::DownlevelFlags::INDIRECT_EXECUTION | wgt::DownlevelFlags::COMPUTE_SHADERS,
445 )
446 && limits.max_storage_buffers_per_shader_stage >= 2;
447
448 let indirect_validation = if enable_indirect_validation {
449 Some(crate::indirect_validation::IndirectValidation::new(
450 raw_device.as_ref(),
451 &desc.required_limits,
452 &desc.required_features,
453 adapter.backend(),
454 )?)
455 } else {
456 None
457 };
458
459 Ok(Self {
460 raw: raw_device,
461 adapter: adapter.clone(),
462 queue: OnceCellOrLock::new(),
463 zero_buffer: ManuallyDrop::new(zero_buffer),
464 default_external_texture_params_buffer: ManuallyDrop::new(
465 default_external_texture_params_buffer,
466 ),
467 label: desc.label.to_string(),
468 command_allocator,
469 command_indices: RwLock::new(
470 rank::DEVICE_COMMAND_INDICES,
471 CommandIndices {
472 active_submission_index: 0,
473 next_acceleration_structure_build_command_index: 1,
475 },
476 ),
477 last_successful_submission_index: AtomicU64::new(0),
478 fence: RwLock::new(rank::DEVICE_FENCE, ManuallyDrop::new(fence)),
479 snatchable_lock: unsafe { SnatchLock::new(rank::DEVICE_SNATCHABLE_LOCK) },
480 valid: AtomicBool::new(true),
481 device_lost_closure: Mutex::new(rank::DEVICE_LOST_CLOSURE, None),
482 trackers: Mutex::new(rank::DEVICE_TRACKERS, DeviceTracker::new()),
483 tracker_indices: TrackerIndexAllocators::new(),
484 bgl_pool: ResourcePool::new(),
485 #[cfg(feature = "trace")]
486 trace: Mutex::new(
487 rank::DEVICE_TRACE,
488 trace_dir_name.and_then(|path| match trace::Trace::new(path.clone()) {
489 Ok(mut trace) => {
490 trace.add(trace::Action::Init {
491 desc: wgt::DeviceDescriptor {
492 trace: wgt::Trace::Off,
493 ..desc.clone()
494 },
495 backend: adapter.backend(),
496 });
497 Some(trace)
498 }
499 Err(e) => {
500 log::error!("Unable to start a trace in '{path:?}': {e}");
501 None
502 }
503 }),
504 ),
505 alignments,
506 limits: desc.required_limits.clone(),
507 features: desc.required_features,
508 downlevel,
509 instance_flags,
510 deferred_destroy: Mutex::new(rank::DEVICE_DEFERRED_DESTROY, Vec::new()),
511 usage_scopes: Mutex::new(rank::DEVICE_USAGE_SCOPES, Default::default()),
512 timestamp_normalizer: OnceCellOrLock::new(),
513 indirect_validation,
514 })
515 }
516
517 fn init_default_external_texture_params_buffer(self: &Arc<Self>) -> Result<(), DeviceError> {
522 let data = ExternalTextureParams {
523 #[rustfmt::skip]
524 yuv_conversion_matrix: [
525 1.0, 0.0, 0.0, 0.0,
526 0.0, 1.0, 0.0, 0.0,
527 0.0, 0.0, 1.0, 0.0,
528 0.0, 0.0, 0.0, 1.0,
529 ],
530 #[rustfmt::skip]
531 gamut_conversion_matrix: [
532 1.0, 0.0, 0.0, 0.0,
533 0.0, 1.0, 0.0, 0.0,
534 0.0, 0.0, 1.0, 0.0,
535 ],
536 src_transfer_function: Default::default(),
537 dst_transfer_function: Default::default(),
538 size: [0, 0],
539 #[rustfmt::skip]
540 sample_transform: [
541 1.0, 0.0,
542 0.0, 1.0,
543 0.0, 0.0
544 ],
545 #[rustfmt::skip]
546 load_transform: [
547 1.0, 0.0,
548 0.0, 1.0,
549 0.0, 0.0
550 ],
551 num_planes: 1,
552 _padding: Default::default(),
553 };
554 let mut staging_buffer =
555 StagingBuffer::new(self, wgt::BufferSize::new(size_of_val(&data) as _).unwrap())?;
556 staging_buffer.write(bytemuck::bytes_of(&data));
557 let staging_buffer = staging_buffer.flush();
558
559 let params_buffer = self.default_external_texture_params_buffer.as_ref();
560 let queue = self.get_queue().unwrap();
561 let mut pending_writes = queue.pending_writes.lock();
562
563 unsafe {
564 pending_writes
565 .command_encoder
566 .transition_buffers(&[hal::BufferBarrier {
567 buffer: params_buffer,
568 usage: hal::StateTransition {
569 from: wgt::BufferUses::MAP_WRITE,
570 to: wgt::BufferUses::COPY_SRC,
571 },
572 }]);
573 pending_writes.command_encoder.copy_buffer_to_buffer(
574 staging_buffer.raw(),
575 params_buffer,
576 &[hal::BufferCopy {
577 src_offset: 0,
578 dst_offset: 0,
579 size: staging_buffer.size,
580 }],
581 );
582 pending_writes.consume(staging_buffer);
583 pending_writes
584 .command_encoder
585 .transition_buffers(&[hal::BufferBarrier {
586 buffer: params_buffer,
587 usage: hal::StateTransition {
588 from: wgt::BufferUses::COPY_DST,
589 to: wgt::BufferUses::UNIFORM,
590 },
591 }]);
592 }
593
594 Ok(())
595 }
596
597 pub fn late_init_resources_with_queue(self: &Arc<Self>) -> Result<(), RequestDeviceError> {
598 let queue = self.get_queue().unwrap();
599
600 let timestamp_normalizer = crate::timestamp_normalization::TimestampNormalizer::new(
601 self,
602 queue.get_timestamp_period(),
603 )?;
604
605 self.timestamp_normalizer
606 .set(timestamp_normalizer)
607 .unwrap_or_else(|_| panic!("Called late_init_resources_with_queue twice"));
608
609 self.init_default_external_texture_params_buffer()?;
610
611 Ok(())
612 }
613
614 pub fn backend(&self) -> wgt::Backend {
616 self.adapter.backend()
617 }
618
619 pub fn is_valid(&self) -> bool {
620 self.valid.load(Ordering::Acquire)
621 }
622
623 pub fn check_is_valid(&self) -> Result<(), DeviceError> {
624 if self.is_valid() {
625 Ok(())
626 } else {
627 Err(DeviceError::Lost)
628 }
629 }
630
631 pub fn lose_if_oom(&self) {
638 let _ = self
639 .raw()
640 .check_if_oom()
641 .map_err(|e| self.handle_hal_error(e));
642 }
643
644 pub fn handle_hal_error(&self, error: hal::DeviceError) -> DeviceError {
645 match error {
646 hal::DeviceError::OutOfMemory
647 | hal::DeviceError::Lost
648 | hal::DeviceError::Unexpected => {
649 self.lose(&error.to_string());
650 }
651 }
652 DeviceError::from_hal(error)
653 }
654
655 pub fn handle_hal_error_with_nonfatal_oom(&self, error: hal::DeviceError) -> DeviceError {
656 match error {
657 hal::DeviceError::OutOfMemory => DeviceError::from_hal(error),
658 error => self.handle_hal_error(error),
659 }
660 }
661
662 pub(crate) fn deferred_resource_destruction(&self) {
670 let deferred_destroy = mem::take(&mut *self.deferred_destroy.lock());
671 for item in deferred_destroy {
672 match item {
673 DeferredDestroy::TextureViews(views) => {
674 for view in views {
675 let Some(view) = view.upgrade() else {
676 continue;
677 };
678 let Some(raw_view) = view.raw.snatch(&mut self.snatchable_lock.write())
679 else {
680 continue;
681 };
682
683 resource_log!("Destroy raw {}", view.error_ident());
684
685 unsafe {
686 self.raw().destroy_texture_view(raw_view);
687 }
688 }
689 }
690 DeferredDestroy::BindGroups(bind_groups) => {
691 for bind_group in bind_groups {
692 let Some(bind_group) = bind_group.upgrade() else {
693 continue;
694 };
695 let Some(raw_bind_group) =
696 bind_group.raw.snatch(&mut self.snatchable_lock.write())
697 else {
698 continue;
699 };
700
701 resource_log!("Destroy raw {}", bind_group.error_ident());
702
703 unsafe {
704 self.raw().destroy_bind_group(raw_bind_group);
705 }
706 }
707 }
708 }
709 }
710 }
711
712 pub fn get_queue(&self) -> Option<Arc<Queue>> {
713 self.queue.get().as_ref()?.upgrade()
714 }
715
716 pub fn set_queue(&self, queue: &Arc<Queue>) {
717 assert!(self.queue.set(Arc::downgrade(queue)).is_ok());
718 }
719
720 pub fn poll(
721 &self,
722 poll_type: wgt::PollType<crate::SubmissionIndex>,
723 ) -> Result<wgt::PollStatus, WaitIdleError> {
724 let (user_closures, result) = self.poll_and_return_closures(poll_type);
725 user_closures.fire();
726 result
727 }
728
729 pub(crate) fn poll_and_return_closures(
736 &self,
737 poll_type: wgt::PollType<crate::SubmissionIndex>,
738 ) -> (UserClosures, Result<wgt::PollStatus, WaitIdleError>) {
739 let snatch_guard = self.snatchable_lock.read();
740 let fence = self.fence.read();
741 let maintain_result = self.maintain(fence, poll_type, snatch_guard);
742
743 self.lose_if_oom();
744
745 self.deferred_resource_destruction();
748
749 maintain_result
750 }
751
752 pub(crate) fn maintain<'this>(
770 &'this self,
771 fence: crate::lock::RwLockReadGuard<ManuallyDrop<Box<dyn hal::DynFence>>>,
772 poll_type: wgt::PollType<crate::SubmissionIndex>,
773 snatch_guard: SnatchGuard,
774 ) -> (UserClosures, Result<wgt::PollStatus, WaitIdleError>) {
775 profiling::scope!("Device::maintain");
776
777 let mut user_closures = UserClosures::default();
778
779 let wait_submission_index = match poll_type {
781 wgt::PollType::Wait {
782 submission_index: Some(submission_index),
783 ..
784 } => {
785 let last_successful_submission_index = self
786 .last_successful_submission_index
787 .load(Ordering::Acquire);
788
789 if submission_index > last_successful_submission_index {
790 let result = Err(WaitIdleError::WrongSubmissionIndex(
791 submission_index,
792 last_successful_submission_index,
793 ));
794
795 return (user_closures, result);
796 }
797
798 Some(submission_index)
799 }
800 wgt::PollType::Wait {
801 submission_index: None,
802 ..
803 } => Some(
804 self.last_successful_submission_index
805 .load(Ordering::Acquire),
806 ),
807 wgt::PollType::Poll => None,
808 };
809
810 if let Some(target_submission_index) = wait_submission_index {
812 log::trace!("Device::maintain: waiting for submission index {target_submission_index}");
813
814 let wait_timeout = match poll_type {
815 wgt::PollType::Wait { timeout, .. } => timeout,
816 wgt::PollType::Poll => unreachable!(
817 "`wait_submission_index` index for poll type `Poll` should be None"
818 ),
819 };
820
821 let wait_result = unsafe {
822 self.raw()
823 .wait(fence.as_ref(), target_submission_index, wait_timeout)
824 };
825
826 if let Err(e) = wait_result {
829 let hal_error: WaitIdleError = self.handle_hal_error(e).into();
830 return (user_closures, Err(hal_error));
831 }
832 }
833
834 let fence_value_result = unsafe { self.raw().get_fence_value(fence.as_ref()) };
837 let current_finished_submission = match fence_value_result {
838 Ok(fence_value) => fence_value,
839 Err(e) => {
840 let hal_error: WaitIdleError = self.handle_hal_error(e).into();
841 return (user_closures, Err(hal_error));
842 }
843 };
844
845 let mut queue_empty = false;
850 if let Some(queue) = self.get_queue() {
851 let queue_result = queue.maintain(current_finished_submission, &snatch_guard);
852 (
853 user_closures.submissions,
854 user_closures.mappings,
855 user_closures.blas_compact_ready,
856 queue_empty,
857 ) = queue_result;
858 drop(snatch_guard);
869 } else {
870 drop(snatch_guard);
871 };
872
873 let result = if queue_empty {
875 if let Some(wait_submission_index) = wait_submission_index {
876 assert!(
879 current_finished_submission >= wait_submission_index,
880 "If the queue is empty, the current submission index ({current_finished_submission}) should be at least the wait submission index ({wait_submission_index})"
881 );
882 }
883
884 Ok(wgt::PollStatus::QueueEmpty)
885 } else if let Some(wait_submission_index) = wait_submission_index {
886 if current_finished_submission >= wait_submission_index {
890 Ok(wgt::PollStatus::WaitSucceeded)
891 } else {
892 Err(WaitIdleError::Timeout)
893 }
894 } else {
895 Ok(wgt::PollStatus::Poll)
896 };
897
898 let mut should_release_gpu_resource = false;
905 if !self.is_valid() && queue_empty {
906 should_release_gpu_resource = true;
909
910 if let Some(device_lost_closure) = self.device_lost_closure.lock().take() {
913 user_closures
914 .device_lost_invocations
915 .push(DeviceLostInvocation {
916 closure: device_lost_closure,
917 reason: DeviceLostReason::Destroyed,
918 message: String::new(),
919 });
920 }
921 }
922
923 drop(fence);
925
926 if should_release_gpu_resource {
927 self.release_gpu_resources();
928 }
929
930 (user_closures, result)
931 }
932
933 pub fn create_buffer(
934 self: &Arc<Self>,
935 desc: &resource::BufferDescriptor,
936 ) -> Result<Arc<Buffer>, resource::CreateBufferError> {
937 self.check_is_valid()?;
938
939 if desc.size > self.limits.max_buffer_size {
940 return Err(resource::CreateBufferError::MaxBufferSize {
941 requested: desc.size,
942 maximum: self.limits.max_buffer_size,
943 });
944 }
945
946 if desc
947 .usage
948 .intersects(wgt::BufferUsages::BLAS_INPUT | wgt::BufferUsages::TLAS_INPUT)
949 {
950 self.require_features(wgt::Features::EXPERIMENTAL_RAY_QUERY)?;
951 }
952
953 if desc.usage.contains(wgt::BufferUsages::INDEX)
954 && desc.usage.contains(
955 wgt::BufferUsages::VERTEX
956 | wgt::BufferUsages::UNIFORM
957 | wgt::BufferUsages::INDIRECT
958 | wgt::BufferUsages::STORAGE,
959 )
960 {
961 self.require_downlevel_flags(wgt::DownlevelFlags::UNRESTRICTED_INDEX_BUFFER)?;
962 }
963
964 if desc.usage.is_empty() || desc.usage.contains_unknown_bits() {
965 return Err(resource::CreateBufferError::InvalidUsage(desc.usage));
966 }
967
968 if !self
969 .features
970 .contains(wgt::Features::MAPPABLE_PRIMARY_BUFFERS)
971 {
972 use wgt::BufferUsages as Bu;
973 let write_mismatch = desc.usage.contains(Bu::MAP_WRITE)
974 && !(Bu::MAP_WRITE | Bu::COPY_SRC).contains(desc.usage);
975 let read_mismatch = desc.usage.contains(Bu::MAP_READ)
976 && !(Bu::MAP_READ | Bu::COPY_DST).contains(desc.usage);
977 if write_mismatch || read_mismatch {
978 return Err(resource::CreateBufferError::UsageMismatch(desc.usage));
979 }
980 }
981
982 let mut usage = conv::map_buffer_usage(desc.usage);
983
984 if desc.usage.contains(wgt::BufferUsages::INDIRECT) {
985 self.require_downlevel_flags(wgt::DownlevelFlags::INDIRECT_EXECUTION)?;
986 usage |= wgt::BufferUses::STORAGE_READ_ONLY | wgt::BufferUses::STORAGE_READ_WRITE;
989 }
990
991 if desc.usage.contains(wgt::BufferUsages::QUERY_RESOLVE) {
992 usage |= TIMESTAMP_NORMALIZATION_BUFFER_USES;
993 }
994
995 if desc.mapped_at_creation {
996 if desc.size % wgt::COPY_BUFFER_ALIGNMENT != 0 {
997 return Err(resource::CreateBufferError::UnalignedSize);
998 }
999 if !desc.usage.contains(wgt::BufferUsages::MAP_WRITE) {
1000 usage |= wgt::BufferUses::COPY_DST;
1002 }
1003 } else {
1004 usage |= wgt::BufferUses::COPY_DST;
1007 }
1008
1009 let actual_size = if desc.size == 0 {
1010 wgt::COPY_BUFFER_ALIGNMENT
1011 } else if desc.usage.contains(wgt::BufferUsages::VERTEX) {
1012 desc.size + 1
1015 } else {
1016 desc.size
1017 };
1018 let clear_remainder = actual_size % wgt::COPY_BUFFER_ALIGNMENT;
1019 let aligned_size = if clear_remainder != 0 {
1020 actual_size + wgt::COPY_BUFFER_ALIGNMENT - clear_remainder
1021 } else {
1022 actual_size
1023 };
1024
1025 let hal_desc = hal::BufferDescriptor {
1026 label: desc.label.to_hal(self.instance_flags),
1027 size: aligned_size,
1028 usage,
1029 memory_flags: hal::MemoryFlags::empty(),
1030 };
1031 let buffer = unsafe { self.raw().create_buffer(&hal_desc) }
1032 .map_err(|e| self.handle_hal_error_with_nonfatal_oom(e))?;
1033
1034 let timestamp_normalization_bind_group = Snatchable::new(unsafe {
1035 self.timestamp_normalizer
1037 .get()
1038 .unwrap()
1039 .create_normalization_bind_group(
1040 self,
1041 &*buffer,
1042 desc.label.as_deref(),
1043 wgt::BufferSize::new(hal_desc.size).unwrap(),
1044 desc.usage,
1045 )
1046 }?);
1047
1048 let indirect_validation_bind_groups =
1049 self.create_indirect_validation_bind_groups(buffer.as_ref(), desc.size, desc.usage)?;
1050
1051 let buffer = Buffer {
1052 raw: Snatchable::new(buffer),
1053 device: self.clone(),
1054 usage: desc.usage,
1055 size: desc.size,
1056 initialization_status: RwLock::new(
1057 rank::BUFFER_INITIALIZATION_STATUS,
1058 BufferInitTracker::new(aligned_size),
1059 ),
1060 map_state: Mutex::new(rank::BUFFER_MAP_STATE, resource::BufferMapState::Idle),
1061 label: desc.label.to_string(),
1062 tracking_data: TrackingData::new(self.tracker_indices.buffers.clone()),
1063 bind_groups: Mutex::new(rank::BUFFER_BIND_GROUPS, WeakVec::new()),
1064 timestamp_normalization_bind_group,
1065 indirect_validation_bind_groups,
1066 };
1067
1068 let buffer = Arc::new(buffer);
1069
1070 let buffer_use = if !desc.mapped_at_creation {
1071 wgt::BufferUses::empty()
1072 } else if desc.usage.contains(wgt::BufferUsages::MAP_WRITE) {
1073 let map_size = buffer.size;
1075 let mapping = if map_size == 0 {
1076 hal::BufferMapping {
1077 ptr: core::ptr::NonNull::dangling(),
1078 is_coherent: true,
1079 }
1080 } else {
1081 let snatch_guard: SnatchGuard = self.snatchable_lock.read();
1082 map_buffer(&buffer, 0, map_size, HostMap::Write, &snatch_guard)?
1083 };
1084 *buffer.map_state.lock() = resource::BufferMapState::Active {
1085 mapping,
1086 range: 0..map_size,
1087 host: HostMap::Write,
1088 };
1089 wgt::BufferUses::MAP_WRITE
1090 } else {
1091 let mut staging_buffer =
1092 StagingBuffer::new(self, wgt::BufferSize::new(aligned_size).unwrap())?;
1093
1094 staging_buffer.write_zeros();
1097 buffer.initialization_status.write().drain(0..aligned_size);
1098
1099 *buffer.map_state.lock() = resource::BufferMapState::Init { staging_buffer };
1100 wgt::BufferUses::COPY_DST
1101 };
1102
1103 self.trackers
1104 .lock()
1105 .buffers
1106 .insert_single(&buffer, buffer_use);
1107
1108 Ok(buffer)
1109 }
1110
1111 #[cfg(feature = "replay")]
1112 pub fn set_buffer_data(
1113 self: &Arc<Self>,
1114 buffer: &Arc<Buffer>,
1115 offset: wgt::BufferAddress,
1116 data: &[u8],
1117 ) -> resource::BufferAccessResult {
1118 use crate::resource::RawResourceAccess;
1119
1120 let device = &buffer.device;
1121
1122 device.check_is_valid()?;
1123 buffer.check_usage(wgt::BufferUsages::MAP_WRITE)?;
1124
1125 let last_submission = device
1126 .get_queue()
1127 .and_then(|queue| queue.lock_life().get_buffer_latest_submission_index(buffer));
1128
1129 if let Some(last_submission) = last_submission {
1130 device.wait_for_submit(last_submission)?;
1131 }
1132
1133 let snatch_guard = device.snatchable_lock.read();
1134 let raw_buf = buffer.try_raw(&snatch_guard)?;
1135
1136 let mapping = unsafe {
1137 device
1138 .raw()
1139 .map_buffer(raw_buf, offset..offset + data.len() as u64)
1140 }
1141 .map_err(|e| device.handle_hal_error(e))?;
1142
1143 unsafe { core::ptr::copy_nonoverlapping(data.as_ptr(), mapping.ptr.as_ptr(), data.len()) };
1144
1145 if !mapping.is_coherent {
1146 #[allow(clippy::single_range_in_vec_init)]
1147 unsafe {
1148 device
1149 .raw()
1150 .flush_mapped_ranges(raw_buf, &[offset..offset + data.len() as u64])
1151 };
1152 }
1153
1154 unsafe { device.raw().unmap_buffer(raw_buf) };
1155
1156 Ok(())
1157 }
1158
1159 pub(crate) fn create_texture_from_hal(
1160 self: &Arc<Self>,
1161 hal_texture: Box<dyn hal::DynTexture>,
1162 desc: &resource::TextureDescriptor,
1163 ) -> Result<Arc<Texture>, resource::CreateTextureError> {
1164 let format_features = self
1165 .describe_format_features(desc.format)
1166 .map_err(|error| resource::CreateTextureError::MissingFeatures(desc.format, error))?;
1167
1168 unsafe { self.raw().add_raw_texture(&*hal_texture) };
1169
1170 let texture = Texture::new(
1171 self,
1172 resource::TextureInner::Native { raw: hal_texture },
1173 conv::map_texture_usage(desc.usage, desc.format.into(), format_features.flags),
1174 desc,
1175 format_features,
1176 resource::TextureClearMode::None,
1177 false,
1178 );
1179
1180 let texture = Arc::new(texture);
1181
1182 self.trackers
1183 .lock()
1184 .textures
1185 .insert_single(&texture, wgt::TextureUses::UNINITIALIZED);
1186
1187 Ok(texture)
1188 }
1189
1190 pub(crate) unsafe fn create_buffer_from_hal(
1197 self: &Arc<Self>,
1198 hal_buffer: Box<dyn hal::DynBuffer>,
1199 desc: &resource::BufferDescriptor,
1200 ) -> (Fallible<Buffer>, Option<resource::CreateBufferError>) {
1201 let timestamp_normalization_bind_group = unsafe {
1202 match self
1203 .timestamp_normalizer
1204 .get()
1205 .unwrap()
1206 .create_normalization_bind_group(
1207 self,
1208 &*hal_buffer,
1209 desc.label.as_deref(),
1210 wgt::BufferSize::new(desc.size).unwrap(),
1211 desc.usage,
1212 ) {
1213 Ok(bg) => Snatchable::new(bg),
1214 Err(e) => {
1215 return (
1216 Fallible::Invalid(Arc::new(desc.label.to_string())),
1217 Some(e.into()),
1218 )
1219 }
1220 }
1221 };
1222
1223 let indirect_validation_bind_groups = match self.create_indirect_validation_bind_groups(
1224 hal_buffer.as_ref(),
1225 desc.size,
1226 desc.usage,
1227 ) {
1228 Ok(ok) => ok,
1229 Err(e) => return (Fallible::Invalid(Arc::new(desc.label.to_string())), Some(e)),
1230 };
1231
1232 unsafe { self.raw().add_raw_buffer(&*hal_buffer) };
1233
1234 let buffer = Buffer {
1235 raw: Snatchable::new(hal_buffer),
1236 device: self.clone(),
1237 usage: desc.usage,
1238 size: desc.size,
1239 initialization_status: RwLock::new(
1240 rank::BUFFER_INITIALIZATION_STATUS,
1241 BufferInitTracker::new(0),
1242 ),
1243 map_state: Mutex::new(rank::BUFFER_MAP_STATE, resource::BufferMapState::Idle),
1244 label: desc.label.to_string(),
1245 tracking_data: TrackingData::new(self.tracker_indices.buffers.clone()),
1246 bind_groups: Mutex::new(rank::BUFFER_BIND_GROUPS, WeakVec::new()),
1247 timestamp_normalization_bind_group,
1248 indirect_validation_bind_groups,
1249 };
1250
1251 let buffer = Arc::new(buffer);
1252
1253 self.trackers
1254 .lock()
1255 .buffers
1256 .insert_single(&buffer, wgt::BufferUses::empty());
1257
1258 (Fallible::Valid(buffer), None)
1259 }
1260
1261 fn create_indirect_validation_bind_groups(
1262 &self,
1263 raw_buffer: &dyn hal::DynBuffer,
1264 buffer_size: u64,
1265 usage: wgt::BufferUsages,
1266 ) -> Result<Snatchable<crate::indirect_validation::BindGroups>, resource::CreateBufferError>
1267 {
1268 if !usage.contains(wgt::BufferUsages::INDIRECT) {
1269 return Ok(Snatchable::empty());
1270 }
1271
1272 let Some(ref indirect_validation) = self.indirect_validation else {
1273 return Ok(Snatchable::empty());
1274 };
1275
1276 let bind_groups = crate::indirect_validation::BindGroups::new(
1277 indirect_validation,
1278 self,
1279 buffer_size,
1280 raw_buffer,
1281 )
1282 .map_err(resource::CreateBufferError::IndirectValidationBindGroup)?;
1283
1284 if let Some(bind_groups) = bind_groups {
1285 Ok(Snatchable::new(bind_groups))
1286 } else {
1287 Ok(Snatchable::empty())
1288 }
1289 }
1290
1291 pub fn create_texture(
1292 self: &Arc<Self>,
1293 desc: &resource::TextureDescriptor,
1294 ) -> Result<Arc<Texture>, resource::CreateTextureError> {
1295 use resource::{CreateTextureError, TextureDimensionError};
1296
1297 self.check_is_valid()?;
1298
1299 if desc.usage.is_empty() || desc.usage.contains_unknown_bits() {
1300 return Err(CreateTextureError::InvalidUsage(desc.usage));
1301 }
1302
1303 conv::check_texture_dimension_size(
1304 desc.dimension,
1305 desc.size,
1306 desc.sample_count,
1307 &self.limits,
1308 )?;
1309
1310 if desc.dimension != wgt::TextureDimension::D2 {
1311 if desc.format.is_depth_stencil_format() {
1313 return Err(CreateTextureError::InvalidDepthDimension(
1314 desc.dimension,
1315 desc.format,
1316 ));
1317 }
1318 }
1319
1320 if desc.dimension != wgt::TextureDimension::D2
1321 && desc.dimension != wgt::TextureDimension::D3
1322 {
1323 if desc.format.is_compressed() {
1325 return Err(CreateTextureError::InvalidCompressedDimension(
1326 desc.dimension,
1327 desc.format,
1328 ));
1329 }
1330
1331 if desc.usage.contains(wgt::TextureUsages::RENDER_ATTACHMENT) {
1333 return Err(CreateTextureError::InvalidDimensionUsages(
1334 wgt::TextureUsages::RENDER_ATTACHMENT,
1335 desc.dimension,
1336 ));
1337 }
1338 }
1339
1340 if desc.format.is_compressed() {
1341 let (block_width, block_height) = desc.format.block_dimensions();
1342
1343 if desc.size.width % block_width != 0 {
1344 return Err(CreateTextureError::InvalidDimension(
1345 TextureDimensionError::NotMultipleOfBlockWidth {
1346 width: desc.size.width,
1347 block_width,
1348 format: desc.format,
1349 },
1350 ));
1351 }
1352
1353 if desc.size.height % block_height != 0 {
1354 return Err(CreateTextureError::InvalidDimension(
1355 TextureDimensionError::NotMultipleOfBlockHeight {
1356 height: desc.size.height,
1357 block_height,
1358 format: desc.format,
1359 },
1360 ));
1361 }
1362
1363 if desc.dimension == wgt::TextureDimension::D3 {
1364 if desc.format.is_bcn() {
1366 self.require_features(wgt::Features::TEXTURE_COMPRESSION_BC_SLICED_3D)
1367 .map_err(|error| CreateTextureError::MissingFeatures(desc.format, error))?;
1368 } else if desc.format.is_astc() {
1369 self.require_features(wgt::Features::TEXTURE_COMPRESSION_ASTC_SLICED_3D)
1370 .map_err(|error| CreateTextureError::MissingFeatures(desc.format, error))?;
1371 } else {
1372 return Err(CreateTextureError::InvalidCompressedDimension(
1373 desc.dimension,
1374 desc.format,
1375 ));
1376 }
1377 }
1378 }
1379
1380 let mips = desc.mip_level_count;
1381 let max_levels_allowed = desc.size.max_mips(desc.dimension).min(hal::MAX_MIP_LEVELS);
1382 if mips == 0 || mips > max_levels_allowed {
1383 return Err(CreateTextureError::InvalidMipLevelCount {
1384 requested: mips,
1385 maximum: max_levels_allowed,
1386 });
1387 }
1388
1389 {
1390 let (mut width_multiple, mut height_multiple) = desc.format.size_multiple_requirement();
1391
1392 if desc.format.is_multi_planar_format() {
1393 width_multiple <<= desc.mip_level_count.saturating_sub(1);
1397 height_multiple <<= desc.mip_level_count.saturating_sub(1);
1398 }
1399
1400 if desc.size.width % width_multiple != 0 {
1401 return Err(CreateTextureError::InvalidDimension(
1402 TextureDimensionError::WidthNotMultipleOf {
1403 width: desc.size.width,
1404 multiple: width_multiple,
1405 format: desc.format,
1406 },
1407 ));
1408 }
1409
1410 if desc.size.height % height_multiple != 0 {
1411 return Err(CreateTextureError::InvalidDimension(
1412 TextureDimensionError::HeightNotMultipleOf {
1413 height: desc.size.height,
1414 multiple: height_multiple,
1415 format: desc.format,
1416 },
1417 ));
1418 }
1419 }
1420
1421 if desc.usage.contains(wgt::TextureUsages::TRANSIENT) {
1422 if !desc.usage.contains(wgt::TextureUsages::RENDER_ATTACHMENT) {
1423 return Err(CreateTextureError::InvalidUsage(
1424 wgt::TextureUsages::TRANSIENT,
1425 ));
1426 }
1427 let extra_usage =
1428 desc.usage - wgt::TextureUsages::TRANSIENT - wgt::TextureUsages::RENDER_ATTACHMENT;
1429 if !extra_usage.is_empty() {
1430 return Err(CreateTextureError::IncompatibleUsage(
1431 wgt::TextureUsages::TRANSIENT,
1432 extra_usage,
1433 ));
1434 }
1435 }
1436
1437 let format_features = self
1438 .describe_format_features(desc.format)
1439 .map_err(|error| CreateTextureError::MissingFeatures(desc.format, error))?;
1440
1441 if desc.sample_count > 1 {
1442 if desc.mip_level_count != 1 {
1448 return Err(CreateTextureError::InvalidMipLevelCount {
1449 requested: desc.mip_level_count,
1450 maximum: 1,
1451 });
1452 }
1453
1454 if desc.size.depth_or_array_layers != 1
1455 && !self.features.contains(wgt::Features::MULTISAMPLE_ARRAY)
1456 {
1457 return Err(CreateTextureError::InvalidDimension(
1458 TextureDimensionError::MultisampledDepthOrArrayLayer(
1459 desc.size.depth_or_array_layers,
1460 ),
1461 ));
1462 }
1463
1464 if desc.usage.contains(wgt::TextureUsages::STORAGE_BINDING) {
1465 return Err(CreateTextureError::InvalidMultisampledStorageBinding);
1466 }
1467
1468 if !desc.usage.contains(wgt::TextureUsages::RENDER_ATTACHMENT) {
1469 return Err(CreateTextureError::MultisampledNotRenderAttachment);
1470 }
1471
1472 if !format_features.flags.intersects(
1473 wgt::TextureFormatFeatureFlags::MULTISAMPLE_X4
1474 | wgt::TextureFormatFeatureFlags::MULTISAMPLE_X2
1475 | wgt::TextureFormatFeatureFlags::MULTISAMPLE_X8
1476 | wgt::TextureFormatFeatureFlags::MULTISAMPLE_X16,
1477 ) {
1478 return Err(CreateTextureError::InvalidMultisampledFormat(desc.format));
1479 }
1480
1481 if !format_features
1482 .flags
1483 .sample_count_supported(desc.sample_count)
1484 {
1485 return Err(CreateTextureError::InvalidSampleCount(
1486 desc.sample_count,
1487 desc.format,
1488 desc.format
1489 .guaranteed_format_features(self.features)
1490 .flags
1491 .supported_sample_counts(),
1492 self.adapter
1493 .get_texture_format_features(desc.format)
1494 .flags
1495 .supported_sample_counts(),
1496 ));
1497 };
1498 }
1499
1500 let missing_allowed_usages = match desc.format.planes() {
1501 Some(planes) => {
1502 let mut planes_usages = wgt::TextureUsages::all();
1503 for plane in 0..planes {
1504 let aspect = wgt::TextureAspect::from_plane(plane).unwrap();
1505 let format = desc.format.aspect_specific_format(aspect).unwrap();
1506 let format_features = self
1507 .describe_format_features(format)
1508 .map_err(|error| CreateTextureError::MissingFeatures(desc.format, error))?;
1509
1510 planes_usages &= format_features.allowed_usages;
1511 }
1512
1513 desc.usage - planes_usages
1514 }
1515 None => desc.usage - format_features.allowed_usages,
1516 };
1517
1518 if !missing_allowed_usages.is_empty() {
1519 let wgpu_allowed_usages = desc
1521 .format
1522 .guaranteed_format_features(self.features)
1523 .allowed_usages;
1524 let wgpu_missing_usages = desc.usage - wgpu_allowed_usages;
1525 return Err(CreateTextureError::InvalidFormatUsages(
1526 missing_allowed_usages,
1527 desc.format,
1528 wgpu_missing_usages.is_empty(),
1529 ));
1530 }
1531
1532 let mut hal_view_formats = Vec::new();
1533 for format in desc.view_formats.iter() {
1534 if desc.format == *format {
1535 continue;
1536 }
1537 if desc.format.remove_srgb_suffix() != format.remove_srgb_suffix() {
1538 return Err(CreateTextureError::InvalidViewFormat(*format, desc.format));
1539 }
1540 hal_view_formats.push(*format);
1541 }
1542 if !hal_view_formats.is_empty() {
1543 self.require_downlevel_flags(wgt::DownlevelFlags::VIEW_FORMATS)?;
1544 }
1545
1546 let hal_usage = conv::map_texture_usage_for_texture(desc, &format_features);
1547
1548 let hal_desc = hal::TextureDescriptor {
1549 label: desc.label.to_hal(self.instance_flags),
1550 size: desc.size,
1551 mip_level_count: desc.mip_level_count,
1552 sample_count: desc.sample_count,
1553 dimension: desc.dimension,
1554 format: desc.format,
1555 usage: hal_usage,
1556 memory_flags: hal::MemoryFlags::empty(),
1557 view_formats: hal_view_formats,
1558 };
1559
1560 let raw_texture = unsafe { self.raw().create_texture(&hal_desc) }
1561 .map_err(|e| self.handle_hal_error_with_nonfatal_oom(e))?;
1562
1563 let clear_mode = if hal_usage
1564 .intersects(wgt::TextureUses::DEPTH_STENCIL_WRITE | wgt::TextureUses::COLOR_TARGET)
1565 && desc.dimension == wgt::TextureDimension::D2
1566 {
1567 let (is_color, usage) = if desc.format.is_depth_stencil_format() {
1568 (false, wgt::TextureUses::DEPTH_STENCIL_WRITE)
1569 } else {
1570 (true, wgt::TextureUses::COLOR_TARGET)
1571 };
1572
1573 let clear_label = hal_label(
1574 Some("(wgpu internal) clear texture view"),
1575 self.instance_flags,
1576 );
1577
1578 let mut clear_views = SmallVec::new();
1579 for mip_level in 0..desc.mip_level_count {
1580 for array_layer in 0..desc.size.depth_or_array_layers {
1581 macro_rules! push_clear_view {
1582 ($format:expr, $aspect:expr) => {
1583 let desc = hal::TextureViewDescriptor {
1584 label: clear_label,
1585 format: $format,
1586 dimension: TextureViewDimension::D2,
1587 usage,
1588 range: wgt::ImageSubresourceRange {
1589 aspect: $aspect,
1590 base_mip_level: mip_level,
1591 mip_level_count: Some(1),
1592 base_array_layer: array_layer,
1593 array_layer_count: Some(1),
1594 },
1595 };
1596 clear_views.push(ManuallyDrop::new(
1597 unsafe {
1598 self.raw().create_texture_view(raw_texture.as_ref(), &desc)
1599 }
1600 .map_err(|e| self.handle_hal_error(e))?,
1601 ));
1602 };
1603 }
1604
1605 if let Some(planes) = desc.format.planes() {
1606 for plane in 0..planes {
1607 let aspect = wgt::TextureAspect::from_plane(plane).unwrap();
1608 let format = desc.format.aspect_specific_format(aspect).unwrap();
1609 push_clear_view!(format, aspect);
1610 }
1611 } else {
1612 push_clear_view!(desc.format, wgt::TextureAspect::All);
1613 }
1614 }
1615 }
1616 resource::TextureClearMode::RenderPass {
1617 clear_views,
1618 is_color,
1619 }
1620 } else {
1621 resource::TextureClearMode::BufferCopy
1622 };
1623
1624 let texture = Texture::new(
1625 self,
1626 resource::TextureInner::Native { raw: raw_texture },
1627 hal_usage,
1628 desc,
1629 format_features,
1630 clear_mode,
1631 true,
1632 );
1633
1634 let texture = Arc::new(texture);
1635
1636 self.trackers
1637 .lock()
1638 .textures
1639 .insert_single(&texture, wgt::TextureUses::UNINITIALIZED);
1640
1641 Ok(texture)
1642 }
1643
1644 pub fn create_texture_view(
1645 self: &Arc<Self>,
1646 texture: &Arc<Texture>,
1647 desc: &resource::TextureViewDescriptor,
1648 ) -> Result<Arc<TextureView>, resource::CreateTextureViewError> {
1649 self.check_is_valid()?;
1650
1651 let snatch_guard = texture.device.snatchable_lock.read();
1652
1653 let texture_raw = texture.try_raw(&snatch_guard)?;
1654
1655 let resolved_format = desc.format.unwrap_or_else(|| {
1658 texture
1659 .desc
1660 .format
1661 .aspect_specific_format(desc.range.aspect)
1662 .unwrap_or(texture.desc.format)
1663 });
1664
1665 let resolved_dimension = desc
1666 .dimension
1667 .unwrap_or_else(|| match texture.desc.dimension {
1668 wgt::TextureDimension::D1 => TextureViewDimension::D1,
1669 wgt::TextureDimension::D2 => {
1670 if texture.desc.array_layer_count() == 1 {
1671 TextureViewDimension::D2
1672 } else {
1673 TextureViewDimension::D2Array
1674 }
1675 }
1676 wgt::TextureDimension::D3 => TextureViewDimension::D3,
1677 });
1678
1679 let resolved_mip_level_count = desc.range.mip_level_count.unwrap_or_else(|| {
1680 texture
1681 .desc
1682 .mip_level_count
1683 .saturating_sub(desc.range.base_mip_level)
1684 });
1685
1686 let resolved_array_layer_count =
1687 desc.range
1688 .array_layer_count
1689 .unwrap_or_else(|| match resolved_dimension {
1690 TextureViewDimension::D1
1691 | TextureViewDimension::D2
1692 | TextureViewDimension::D3 => 1,
1693 TextureViewDimension::Cube => 6,
1694 TextureViewDimension::D2Array | TextureViewDimension::CubeArray => texture
1695 .desc
1696 .array_layer_count()
1697 .saturating_sub(desc.range.base_array_layer),
1698 });
1699
1700 let resolved_usage = {
1701 let usage = desc.usage.unwrap_or(wgt::TextureUsages::empty());
1702 if usage.is_empty() {
1703 texture.desc.usage
1704 } else if texture.desc.usage.contains(usage) {
1705 usage
1706 } else {
1707 return Err(resource::CreateTextureViewError::InvalidTextureViewUsage {
1708 view: usage,
1709 texture: texture.desc.usage,
1710 });
1711 }
1712 };
1713
1714 let format_features = self.describe_format_features(resolved_format)?;
1715 let allowed_format_usages = format_features.allowed_usages;
1716 if resolved_usage.contains(wgt::TextureUsages::RENDER_ATTACHMENT)
1717 && !allowed_format_usages.contains(wgt::TextureUsages::RENDER_ATTACHMENT)
1718 {
1719 return Err(
1720 resource::CreateTextureViewError::TextureViewFormatNotRenderable(resolved_format),
1721 );
1722 }
1723
1724 if resolved_usage.contains(wgt::TextureUsages::STORAGE_BINDING)
1725 && !allowed_format_usages.contains(wgt::TextureUsages::STORAGE_BINDING)
1726 {
1727 return Err(
1728 resource::CreateTextureViewError::TextureViewFormatNotStorage(resolved_format),
1729 );
1730 }
1731
1732 let aspects = hal::FormatAspects::new(texture.desc.format, desc.range.aspect);
1735 if aspects.is_empty() {
1736 return Err(resource::CreateTextureViewError::InvalidAspect {
1737 texture_format: texture.desc.format,
1738 requested_aspect: desc.range.aspect,
1739 });
1740 }
1741
1742 let format_is_good = if desc.range.aspect == wgt::TextureAspect::All {
1743 resolved_format == texture.desc.format
1744 || texture.desc.view_formats.contains(&resolved_format)
1745 } else {
1746 Some(resolved_format)
1747 == texture
1748 .desc
1749 .format
1750 .aspect_specific_format(desc.range.aspect)
1751 };
1752 if !format_is_good {
1753 return Err(resource::CreateTextureViewError::FormatReinterpretation {
1754 texture: texture.desc.format,
1755 view: resolved_format,
1756 });
1757 }
1758
1759 if texture.desc.sample_count > 1 && resolved_dimension != TextureViewDimension::D2 {
1761 let multisample_array_exception = resolved_dimension == TextureViewDimension::D2Array
1763 && self.features.contains(wgt::Features::MULTISAMPLE_ARRAY);
1764
1765 if !multisample_array_exception {
1766 return Err(
1767 resource::CreateTextureViewError::InvalidMultisampledTextureViewDimension(
1768 resolved_dimension,
1769 ),
1770 );
1771 }
1772 }
1773
1774 if texture.desc.dimension != resolved_dimension.compatible_texture_dimension() {
1776 return Err(
1777 resource::CreateTextureViewError::InvalidTextureViewDimension {
1778 view: resolved_dimension,
1779 texture: texture.desc.dimension,
1780 },
1781 );
1782 }
1783
1784 match resolved_dimension {
1785 TextureViewDimension::D1 | TextureViewDimension::D2 | TextureViewDimension::D3 => {
1786 if resolved_array_layer_count != 1 {
1787 return Err(resource::CreateTextureViewError::InvalidArrayLayerCount {
1788 requested: resolved_array_layer_count,
1789 dim: resolved_dimension,
1790 });
1791 }
1792 }
1793 TextureViewDimension::Cube => {
1794 if resolved_array_layer_count != 6 {
1795 return Err(
1796 resource::CreateTextureViewError::InvalidCubemapTextureDepth {
1797 depth: resolved_array_layer_count,
1798 },
1799 );
1800 }
1801 }
1802 TextureViewDimension::CubeArray => {
1803 if resolved_array_layer_count % 6 != 0 {
1804 return Err(
1805 resource::CreateTextureViewError::InvalidCubemapArrayTextureDepth {
1806 depth: resolved_array_layer_count,
1807 },
1808 );
1809 }
1810 }
1811 _ => {}
1812 }
1813
1814 match resolved_dimension {
1815 TextureViewDimension::Cube | TextureViewDimension::CubeArray => {
1816 if texture.desc.size.width != texture.desc.size.height {
1817 return Err(resource::CreateTextureViewError::InvalidCubeTextureViewSize);
1818 }
1819 }
1820 _ => {}
1821 }
1822
1823 if resolved_mip_level_count == 0 {
1824 return Err(resource::CreateTextureViewError::ZeroMipLevelCount);
1825 }
1826
1827 let mip_level_end = desc
1828 .range
1829 .base_mip_level
1830 .saturating_add(resolved_mip_level_count);
1831
1832 let level_end = texture.desc.mip_level_count;
1833 if mip_level_end > level_end {
1834 return Err(resource::CreateTextureViewError::TooManyMipLevels {
1835 base_mip_level: desc.range.base_mip_level,
1836 mip_level_count: resolved_mip_level_count,
1837 total: level_end,
1838 });
1839 }
1840
1841 if resolved_array_layer_count == 0 {
1842 return Err(resource::CreateTextureViewError::ZeroArrayLayerCount);
1843 }
1844
1845 let array_layer_end = desc
1846 .range
1847 .base_array_layer
1848 .saturating_add(resolved_array_layer_count);
1849
1850 let layer_end = texture.desc.array_layer_count();
1851 if array_layer_end > layer_end {
1852 return Err(resource::CreateTextureViewError::TooManyArrayLayers {
1853 base_array_layer: desc.range.base_array_layer,
1854 array_layer_count: resolved_array_layer_count,
1855 total: layer_end,
1856 });
1857 };
1858
1859 let render_extent = 'error: {
1861 if !resolved_usage.contains(wgt::TextureUsages::RENDER_ATTACHMENT) {
1862 break 'error Err(TextureViewNotRenderableReason::Usage(resolved_usage));
1863 }
1864
1865 let allowed_view_dimensions = [
1866 TextureViewDimension::D2,
1867 TextureViewDimension::D2Array,
1868 TextureViewDimension::D3,
1869 ];
1870 if !allowed_view_dimensions.contains(&resolved_dimension) {
1871 break 'error Err(TextureViewNotRenderableReason::Dimension(
1872 resolved_dimension,
1873 ));
1874 }
1875
1876 if resolved_mip_level_count != 1 {
1877 break 'error Err(TextureViewNotRenderableReason::MipLevelCount(
1878 resolved_mip_level_count,
1879 ));
1880 }
1881
1882 if resolved_array_layer_count != 1
1883 && !(self.features.contains(wgt::Features::MULTIVIEW))
1884 {
1885 break 'error Err(TextureViewNotRenderableReason::ArrayLayerCount(
1886 resolved_array_layer_count,
1887 ));
1888 }
1889
1890 if !texture.desc.format.is_multi_planar_format()
1891 && aspects != hal::FormatAspects::from(texture.desc.format)
1892 {
1893 break 'error Err(TextureViewNotRenderableReason::Aspects(aspects));
1894 }
1895
1896 Ok(texture
1897 .desc
1898 .compute_render_extent(desc.range.base_mip_level, desc.range.aspect.to_plane()))
1899 };
1900
1901 let usage = {
1903 let resolved_hal_usage = conv::map_texture_usage(
1904 resolved_usage,
1905 resolved_format.into(),
1906 format_features.flags,
1907 );
1908 let mask_copy = !(wgt::TextureUses::COPY_SRC | wgt::TextureUses::COPY_DST);
1909 let mask_dimension = match resolved_dimension {
1910 TextureViewDimension::Cube | TextureViewDimension::CubeArray => {
1911 wgt::TextureUses::RESOURCE
1912 }
1913 TextureViewDimension::D3 => {
1914 wgt::TextureUses::RESOURCE
1915 | wgt::TextureUses::STORAGE_READ_ONLY
1916 | wgt::TextureUses::STORAGE_WRITE_ONLY
1917 | wgt::TextureUses::STORAGE_READ_WRITE
1918 }
1919 _ => wgt::TextureUses::all(),
1920 };
1921 let mask_mip_level = if resolved_mip_level_count == 1 {
1922 wgt::TextureUses::all()
1923 } else {
1924 wgt::TextureUses::RESOURCE
1925 };
1926 resolved_hal_usage & mask_copy & mask_dimension & mask_mip_level
1927 };
1928
1929 let format = if resolved_format.is_depth_stencil_component(texture.desc.format) {
1931 texture.desc.format
1932 } else {
1933 resolved_format
1934 };
1935
1936 let resolved_range = wgt::ImageSubresourceRange {
1937 aspect: desc.range.aspect,
1938 base_mip_level: desc.range.base_mip_level,
1939 mip_level_count: Some(resolved_mip_level_count),
1940 base_array_layer: desc.range.base_array_layer,
1941 array_layer_count: Some(resolved_array_layer_count),
1942 };
1943
1944 let hal_desc = hal::TextureViewDescriptor {
1945 label: desc.label.to_hal(self.instance_flags),
1946 format,
1947 dimension: resolved_dimension,
1948 usage,
1949 range: resolved_range,
1950 };
1951
1952 let raw = unsafe { self.raw().create_texture_view(texture_raw, &hal_desc) }
1953 .map_err(|e| self.handle_hal_error(e))?;
1954
1955 let selector = TextureSelector {
1956 mips: desc.range.base_mip_level..mip_level_end,
1957 layers: desc.range.base_array_layer..array_layer_end,
1958 };
1959
1960 let view = TextureView {
1961 raw: Snatchable::new(raw),
1962 parent: texture.clone(),
1963 device: self.clone(),
1964 desc: resource::HalTextureViewDescriptor {
1965 texture_format: texture.desc.format,
1966 format: resolved_format,
1967 dimension: resolved_dimension,
1968 usage: resolved_usage,
1969 range: resolved_range,
1970 },
1971 format_features: texture.format_features,
1972 render_extent,
1973 samples: texture.desc.sample_count,
1974 selector,
1975 label: desc.label.to_string(),
1976 };
1977
1978 let view = Arc::new(view);
1979
1980 {
1981 let mut views = texture.views.lock();
1982 views.push(Arc::downgrade(&view));
1983 }
1984
1985 Ok(view)
1986 }
1987
1988 pub fn create_external_texture(
1989 self: &Arc<Self>,
1990 desc: &resource::ExternalTextureDescriptor,
1991 planes: &[Arc<TextureView>],
1992 ) -> Result<Arc<ExternalTexture>, resource::CreateExternalTextureError> {
1993 use resource::CreateExternalTextureError;
1994 self.require_features(wgt::Features::EXTERNAL_TEXTURE)?;
1995 self.check_is_valid()?;
1996
1997 if desc.num_planes() != planes.len() {
1998 return Err(CreateExternalTextureError::IncorrectPlaneCount {
1999 format: desc.format,
2000 expected: desc.num_planes(),
2001 provided: planes.len(),
2002 });
2003 }
2004
2005 let planes = planes
2006 .iter()
2007 .enumerate()
2008 .map(|(i, plane)| {
2009 if plane.samples != 1 {
2010 return Err(CreateExternalTextureError::InvalidPlaneMultisample(
2011 plane.samples,
2012 ));
2013 }
2014
2015 let sample_type = plane
2016 .desc
2017 .format
2018 .sample_type(Some(plane.desc.range.aspect), Some(self.features))
2019 .unwrap();
2020 if !matches!(sample_type, TextureSampleType::Float { filterable: true }) {
2021 return Err(CreateExternalTextureError::InvalidPlaneSampleType {
2022 format: plane.desc.format,
2023 sample_type,
2024 });
2025 }
2026
2027 if plane.desc.dimension != TextureViewDimension::D2 {
2028 return Err(CreateExternalTextureError::InvalidPlaneDimension(
2029 plane.desc.dimension,
2030 ));
2031 }
2032
2033 let expected_components = match desc.format {
2034 wgt::ExternalTextureFormat::Rgba => 4,
2035 wgt::ExternalTextureFormat::Nv12 => match i {
2036 0 => 1,
2037 1 => 2,
2038 _ => unreachable!(),
2039 },
2040 wgt::ExternalTextureFormat::Yu12 => 1,
2041 };
2042 if plane.desc.format.components() != expected_components {
2043 return Err(CreateExternalTextureError::InvalidPlaneFormat {
2044 format: desc.format,
2045 plane: i,
2046 expected: expected_components,
2047 provided: plane.desc.format,
2048 });
2049 }
2050
2051 plane.check_usage(wgt::TextureUsages::TEXTURE_BINDING)?;
2052 Ok(plane.clone())
2053 })
2054 .collect::<Result<_, _>>()?;
2055
2056 let params_data = ExternalTextureParams::from_desc(desc);
2057 let label = desc.label.as_ref().map(|l| alloc::format!("{l} params"));
2058 let params_desc = resource::BufferDescriptor {
2059 label: label.map(Cow::Owned),
2060 size: size_of_val(¶ms_data) as wgt::BufferAddress,
2061 usage: wgt::BufferUsages::UNIFORM | wgt::BufferUsages::COPY_DST,
2062 mapped_at_creation: false,
2063 };
2064 let params = self.create_buffer(¶ms_desc)?;
2065 self.get_queue().unwrap().write_buffer(
2066 params.clone(),
2067 0,
2068 bytemuck::bytes_of(¶ms_data),
2069 )?;
2070
2071 let external_texture = ExternalTexture {
2072 device: self.clone(),
2073 planes,
2074 params,
2075 label: desc.label.to_string(),
2076 tracking_data: TrackingData::new(self.tracker_indices.external_textures.clone()),
2077 };
2078 let external_texture = Arc::new(external_texture);
2079
2080 Ok(external_texture)
2081 }
2082
2083 pub fn create_sampler(
2084 self: &Arc<Self>,
2085 desc: &resource::SamplerDescriptor,
2086 ) -> Result<Arc<Sampler>, resource::CreateSamplerError> {
2087 self.check_is_valid()?;
2088
2089 if desc
2090 .address_modes
2091 .iter()
2092 .any(|am| am == &wgt::AddressMode::ClampToBorder)
2093 {
2094 self.require_features(wgt::Features::ADDRESS_MODE_CLAMP_TO_BORDER)?;
2095 }
2096
2097 if desc.border_color == Some(wgt::SamplerBorderColor::Zero) {
2098 self.require_features(wgt::Features::ADDRESS_MODE_CLAMP_TO_ZERO)?;
2099 }
2100
2101 if desc.lod_min_clamp < 0.0 {
2102 return Err(resource::CreateSamplerError::InvalidLodMinClamp(
2103 desc.lod_min_clamp,
2104 ));
2105 }
2106 if desc.lod_max_clamp < desc.lod_min_clamp {
2107 return Err(resource::CreateSamplerError::InvalidLodMaxClamp {
2108 lod_min_clamp: desc.lod_min_clamp,
2109 lod_max_clamp: desc.lod_max_clamp,
2110 });
2111 }
2112
2113 if desc.anisotropy_clamp < 1 {
2114 return Err(resource::CreateSamplerError::InvalidAnisotropy(
2115 desc.anisotropy_clamp,
2116 ));
2117 }
2118
2119 if desc.anisotropy_clamp != 1 {
2120 if !matches!(desc.min_filter, wgt::FilterMode::Linear) {
2121 return Err(
2122 resource::CreateSamplerError::InvalidFilterModeWithAnisotropy {
2123 filter_type: resource::SamplerFilterErrorType::MinFilter,
2124 filter_mode: desc.min_filter,
2125 anisotropic_clamp: desc.anisotropy_clamp,
2126 },
2127 );
2128 }
2129 if !matches!(desc.mag_filter, wgt::FilterMode::Linear) {
2130 return Err(
2131 resource::CreateSamplerError::InvalidFilterModeWithAnisotropy {
2132 filter_type: resource::SamplerFilterErrorType::MagFilter,
2133 filter_mode: desc.mag_filter,
2134 anisotropic_clamp: desc.anisotropy_clamp,
2135 },
2136 );
2137 }
2138 if !matches!(desc.mipmap_filter, wgt::MipmapFilterMode::Linear) {
2139 return Err(
2140 resource::CreateSamplerError::InvalidMipmapFilterModeWithAnisotropy {
2141 filter_type: resource::SamplerFilterErrorType::MipmapFilter,
2142 filter_mode: desc.mipmap_filter,
2143 anisotropic_clamp: desc.anisotropy_clamp,
2144 },
2145 );
2146 }
2147 }
2148
2149 let anisotropy_clamp = if self
2150 .downlevel
2151 .flags
2152 .contains(wgt::DownlevelFlags::ANISOTROPIC_FILTERING)
2153 {
2154 desc.anisotropy_clamp.min(16)
2156 } else {
2157 1
2159 };
2160
2161 let hal_desc = hal::SamplerDescriptor {
2164 label: desc.label.to_hal(self.instance_flags),
2165 address_modes: desc.address_modes,
2166 mag_filter: desc.mag_filter,
2167 min_filter: desc.min_filter,
2168 mipmap_filter: desc.mipmap_filter,
2169 lod_clamp: desc.lod_min_clamp..desc.lod_max_clamp,
2170 compare: desc.compare,
2171 anisotropy_clamp,
2172 border_color: desc.border_color,
2173 };
2174
2175 let raw = unsafe { self.raw().create_sampler(&hal_desc) }
2176 .map_err(|e| self.handle_hal_error_with_nonfatal_oom(e))?;
2177
2178 let sampler = Sampler {
2179 raw: ManuallyDrop::new(raw),
2180 device: self.clone(),
2181 label: desc.label.to_string(),
2182 tracking_data: TrackingData::new(self.tracker_indices.samplers.clone()),
2183 comparison: desc.compare.is_some(),
2184 filtering: desc.min_filter == wgt::FilterMode::Linear
2185 || desc.mag_filter == wgt::FilterMode::Linear
2186 || desc.mipmap_filter == wgt::MipmapFilterMode::Linear,
2187 };
2188
2189 let sampler = Arc::new(sampler);
2190
2191 Ok(sampler)
2192 }
2193
2194 pub fn create_shader_module<'a>(
2195 self: &Arc<Self>,
2196 desc: &pipeline::ShaderModuleDescriptor<'a>,
2197 source: pipeline::ShaderModuleSource<'a>,
2198 ) -> Result<Arc<pipeline::ShaderModule>, pipeline::CreateShaderModuleError> {
2199 self.check_is_valid()?;
2200
2201 let (module, source) = match source {
2202 #[cfg(feature = "wgsl")]
2203 pipeline::ShaderModuleSource::Wgsl(code) => {
2204 profiling::scope!("naga::front::wgsl::parse_str");
2205 let module = naga::front::wgsl::parse_str(&code).map_err(|inner| {
2206 pipeline::CreateShaderModuleError::Parsing(naga::error::ShaderError {
2207 source: code.to_string(),
2208 label: desc.label.as_ref().map(|l| l.to_string()),
2209 inner: Box::new(inner),
2210 })
2211 })?;
2212 (Cow::Owned(module), code.into_owned())
2213 }
2214 #[cfg(feature = "spirv")]
2215 pipeline::ShaderModuleSource::SpirV(spv, options) => {
2216 let parser = naga::front::spv::Frontend::new(spv.iter().cloned(), &options);
2217 profiling::scope!("naga::front::spv::Frontend");
2218 let module = parser.parse().map_err(|inner| {
2219 pipeline::CreateShaderModuleError::ParsingSpirV(naga::error::ShaderError {
2220 source: String::new(),
2221 label: desc.label.as_ref().map(|l| l.to_string()),
2222 inner: Box::new(inner),
2223 })
2224 })?;
2225 (Cow::Owned(module), String::new())
2226 }
2227 #[cfg(feature = "glsl")]
2228 pipeline::ShaderModuleSource::Glsl(code, options) => {
2229 let mut parser = naga::front::glsl::Frontend::default();
2230 profiling::scope!("naga::front::glsl::Frontend.parse");
2231 let module = parser.parse(&options, &code).map_err(|inner| {
2232 pipeline::CreateShaderModuleError::ParsingGlsl(naga::error::ShaderError {
2233 source: code.to_string(),
2234 label: desc.label.as_ref().map(|l| l.to_string()),
2235 inner: Box::new(inner),
2236 })
2237 })?;
2238 (Cow::Owned(module), code.into_owned())
2239 }
2240 pipeline::ShaderModuleSource::Naga(module) => (module, String::new()),
2241 pipeline::ShaderModuleSource::Dummy(_) => panic!("found `ShaderModuleSource::Dummy`"),
2242 };
2243 for (_, var) in module.global_variables.iter() {
2244 match var.binding {
2245 Some(br) if br.group >= self.limits.max_bind_groups => {
2246 return Err(pipeline::CreateShaderModuleError::InvalidGroupIndex {
2247 bind: br,
2248 group: br.group,
2249 limit: self.limits.max_bind_groups,
2250 });
2251 }
2252 _ => continue,
2253 };
2254 }
2255
2256 profiling::scope!("naga::validate");
2257 let debug_source =
2258 if self.instance_flags.contains(wgt::InstanceFlags::DEBUG) && !source.is_empty() {
2259 Some(hal::DebugSource {
2260 file_name: Cow::Owned(
2261 desc.label
2262 .as_ref()
2263 .map_or("shader".to_string(), |l| l.to_string()),
2264 ),
2265 source_code: Cow::Owned(source.clone()),
2266 })
2267 } else {
2268 None
2269 };
2270
2271 let info = create_validator(
2272 self.features,
2273 self.downlevel.flags,
2274 naga::valid::ValidationFlags::all(),
2275 )
2276 .validate(&module)
2277 .map_err(|inner| {
2278 pipeline::CreateShaderModuleError::Validation(naga::error::ShaderError {
2279 source,
2280 label: desc.label.as_ref().map(|l| l.to_string()),
2281 inner: Box::new(inner),
2282 })
2283 })?;
2284
2285 let interface = validation::Interface::new(&module, &info, self.limits.clone());
2286 let hal_shader = hal::ShaderInput::Naga(hal::NagaShader {
2287 module,
2288 info,
2289 debug_source,
2290 });
2291 let hal_desc = hal::ShaderModuleDescriptor {
2292 label: desc.label.to_hal(self.instance_flags),
2293 runtime_checks: desc.runtime_checks,
2294 };
2295 let raw = match unsafe { self.raw().create_shader_module(&hal_desc, hal_shader) } {
2296 Ok(raw) => raw,
2297 Err(error) => {
2298 return Err(match error {
2299 hal::ShaderError::Device(error) => {
2300 pipeline::CreateShaderModuleError::Device(self.handle_hal_error(error))
2301 }
2302 hal::ShaderError::Compilation(ref msg) => {
2303 log::error!("Shader error: {msg}");
2304 pipeline::CreateShaderModuleError::Generation
2305 }
2306 })
2307 }
2308 };
2309
2310 let module = pipeline::ShaderModule {
2311 raw: ManuallyDrop::new(raw),
2312 device: self.clone(),
2313 interface: Some(interface),
2314 label: desc.label.to_string(),
2315 };
2316
2317 let module = Arc::new(module);
2318
2319 Ok(module)
2320 }
2321
2322 #[allow(unused_unsafe)]
2324 #[doc(hidden)]
2325 pub unsafe fn create_shader_module_passthrough<'a>(
2326 self: &Arc<Self>,
2327 descriptor: &pipeline::ShaderModuleDescriptorPassthrough<'a>,
2328 ) -> Result<Arc<pipeline::ShaderModule>, pipeline::CreateShaderModuleError> {
2329 self.check_is_valid()?;
2330 self.require_features(wgt::Features::EXPERIMENTAL_PASSTHROUGH_SHADERS)?;
2331
2332 let hal_shader = match self.backend() {
2333 wgt::Backend::Vulkan => hal::ShaderInput::SpirV(
2334 descriptor
2335 .spirv
2336 .as_ref()
2337 .ok_or(pipeline::CreateShaderModuleError::NotCompiledForBackend)?,
2338 ),
2339 wgt::Backend::Dx12 => {
2340 if let Some(dxil) = &descriptor.dxil {
2341 hal::ShaderInput::Dxil {
2342 shader: dxil,
2343 entry_point: descriptor.entry_point.clone(),
2344 num_workgroups: descriptor.num_workgroups,
2345 }
2346 } else if let Some(hlsl) = &descriptor.hlsl {
2347 hal::ShaderInput::Hlsl {
2348 shader: hlsl,
2349 entry_point: descriptor.entry_point.clone(),
2350 num_workgroups: descriptor.num_workgroups,
2351 }
2352 } else {
2353 return Err(pipeline::CreateShaderModuleError::NotCompiledForBackend);
2354 }
2355 }
2356 wgt::Backend::Metal => hal::ShaderInput::Msl {
2357 shader: descriptor
2358 .msl
2359 .as_ref()
2360 .ok_or(pipeline::CreateShaderModuleError::NotCompiledForBackend)?,
2361 entry_point: descriptor.entry_point.clone(),
2362 num_workgroups: descriptor.num_workgroups,
2363 },
2364 wgt::Backend::Gl => hal::ShaderInput::Glsl {
2365 shader: descriptor
2366 .glsl
2367 .as_ref()
2368 .ok_or(pipeline::CreateShaderModuleError::NotCompiledForBackend)?,
2369 entry_point: descriptor.entry_point.clone(),
2370 num_workgroups: descriptor.num_workgroups,
2371 },
2372 wgt::Backend::Noop => {
2373 return Err(pipeline::CreateShaderModuleError::NotCompiledForBackend)
2374 }
2375 wgt::Backend::BrowserWebGpu => unreachable!(),
2376 };
2377
2378 let hal_desc = hal::ShaderModuleDescriptor {
2379 label: descriptor.label.to_hal(self.instance_flags),
2380 runtime_checks: wgt::ShaderRuntimeChecks::unchecked(),
2381 };
2382
2383 let raw = match unsafe { self.raw().create_shader_module(&hal_desc, hal_shader) } {
2384 Ok(raw) => raw,
2385 Err(error) => {
2386 return Err(match error {
2387 hal::ShaderError::Device(error) => {
2388 pipeline::CreateShaderModuleError::Device(self.handle_hal_error(error))
2389 }
2390 hal::ShaderError::Compilation(ref msg) => {
2391 log::error!("Shader error: {msg}");
2392 pipeline::CreateShaderModuleError::Generation
2393 }
2394 })
2395 }
2396 };
2397
2398 let module = pipeline::ShaderModule {
2399 raw: ManuallyDrop::new(raw),
2400 device: self.clone(),
2401 interface: None,
2402 label: descriptor.label.to_string(),
2403 };
2404
2405 Ok(Arc::new(module))
2406 }
2407
2408 pub(crate) fn create_command_encoder(
2409 self: &Arc<Self>,
2410 label: &crate::Label,
2411 ) -> Result<Arc<command::CommandEncoder>, DeviceError> {
2412 self.check_is_valid()?;
2413
2414 let queue = self.get_queue().unwrap();
2415
2416 let encoder = self
2417 .command_allocator
2418 .acquire_encoder(self.raw(), queue.raw())
2419 .map_err(|e| self.handle_hal_error(e))?;
2420
2421 let cmd_enc = command::CommandEncoder::new(encoder, self, label);
2422
2423 let cmd_enc = Arc::new(cmd_enc);
2424
2425 Ok(cmd_enc)
2426 }
2427
2428 fn make_late_sized_buffer_groups(
2431 shader_binding_sizes: &FastHashMap<naga::ResourceBinding, wgt::BufferSize>,
2432 layout: &binding_model::PipelineLayout,
2433 ) -> ArrayVec<pipeline::LateSizedBufferGroup, { hal::MAX_BIND_GROUPS }> {
2434 layout
2438 .bind_group_layouts
2439 .iter()
2440 .enumerate()
2441 .map(|(group_index, bgl)| pipeline::LateSizedBufferGroup {
2442 shader_sizes: bgl
2443 .entries
2444 .values()
2445 .filter_map(|entry| match entry.ty {
2446 wgt::BindingType::Buffer {
2447 min_binding_size: None,
2448 ..
2449 } => {
2450 let rb = naga::ResourceBinding {
2451 group: group_index as u32,
2452 binding: entry.binding,
2453 };
2454 let shader_size =
2455 shader_binding_sizes.get(&rb).map_or(0, |nz| nz.get());
2456 Some(shader_size)
2457 }
2458 _ => None,
2459 })
2460 .collect(),
2461 })
2462 .collect()
2463 }
2464
2465 pub fn create_bind_group_layout(
2466 self: &Arc<Self>,
2467 desc: &binding_model::BindGroupLayoutDescriptor,
2468 ) -> Result<Arc<BindGroupLayout>, binding_model::CreateBindGroupLayoutError> {
2469 self.check_is_valid()?;
2470
2471 let entry_map = bgl::EntryMap::from_entries(&desc.entries)?;
2472
2473 let bgl_result = self.bgl_pool.get_or_init(entry_map, |entry_map| {
2474 let bgl =
2475 self.create_bind_group_layout_internal(&desc.label, entry_map, bgl::Origin::Pool)?;
2476 bgl.exclusive_pipeline
2477 .set(binding_model::ExclusivePipeline::None)
2478 .unwrap();
2479 Ok(bgl)
2480 });
2481
2482 match bgl_result {
2483 Ok(layout) => Ok(layout),
2484 Err(e) => Err(e),
2485 }
2486 }
2487
2488 #[doc(hidden)]
2490 pub fn create_bind_group_layout_internal(
2491 self: &Arc<Self>,
2492 label: &crate::Label,
2493 entry_map: bgl::EntryMap,
2494 origin: bgl::Origin,
2495 ) -> Result<Arc<BindGroupLayout>, binding_model::CreateBindGroupLayoutError> {
2496 #[derive(PartialEq)]
2497 enum WritableStorage {
2498 Yes,
2499 No,
2500 }
2501
2502 for entry in entry_map.values() {
2503 if entry.binding >= self.limits.max_bindings_per_bind_group {
2504 return Err(
2505 binding_model::CreateBindGroupLayoutError::InvalidBindingIndex {
2506 binding: entry.binding,
2507 maximum: self.limits.max_bindings_per_bind_group,
2508 },
2509 );
2510 }
2511
2512 use wgt::BindingType as Bt;
2513
2514 let mut required_features = wgt::Features::empty();
2515 let mut required_downlevel_flags = wgt::DownlevelFlags::empty();
2516 let (array_feature, writable_storage) = match entry.ty {
2517 Bt::Buffer {
2518 ty: wgt::BufferBindingType::Uniform,
2519 has_dynamic_offset: false,
2520 min_binding_size: _,
2521 } => (
2522 Some(wgt::Features::BUFFER_BINDING_ARRAY),
2523 WritableStorage::No,
2524 ),
2525 Bt::Buffer {
2526 ty: wgt::BufferBindingType::Uniform,
2527 has_dynamic_offset: true,
2528 min_binding_size: _,
2529 } => (
2530 Some(wgt::Features::BUFFER_BINDING_ARRAY),
2531 WritableStorage::No,
2532 ),
2533 Bt::Buffer {
2534 ty: wgt::BufferBindingType::Storage { read_only },
2535 ..
2536 } => (
2537 Some(
2538 wgt::Features::BUFFER_BINDING_ARRAY
2539 | wgt::Features::STORAGE_RESOURCE_BINDING_ARRAY,
2540 ),
2541 match read_only {
2542 true => WritableStorage::No,
2543 false => WritableStorage::Yes,
2544 },
2545 ),
2546 Bt::Sampler { .. } => (
2547 Some(wgt::Features::TEXTURE_BINDING_ARRAY),
2548 WritableStorage::No,
2549 ),
2550 Bt::Texture {
2551 multisampled: true,
2552 sample_type: TextureSampleType::Float { filterable: true },
2553 ..
2554 } => {
2555 return Err(binding_model::CreateBindGroupLayoutError::Entry {
2556 binding: entry.binding,
2557 error:
2558 BindGroupLayoutEntryError::SampleTypeFloatFilterableBindingMultisampled,
2559 });
2560 }
2561 Bt::Texture {
2562 multisampled,
2563 view_dimension,
2564 ..
2565 } => {
2566 if multisampled && view_dimension != TextureViewDimension::D2 {
2567 return Err(binding_model::CreateBindGroupLayoutError::Entry {
2568 binding: entry.binding,
2569 error: BindGroupLayoutEntryError::Non2DMultisampled(view_dimension),
2570 });
2571 }
2572
2573 (
2574 Some(wgt::Features::TEXTURE_BINDING_ARRAY),
2575 WritableStorage::No,
2576 )
2577 }
2578 Bt::StorageTexture {
2579 access,
2580 view_dimension,
2581 format: _,
2582 } => {
2583 match view_dimension {
2584 TextureViewDimension::Cube | TextureViewDimension::CubeArray => {
2585 return Err(binding_model::CreateBindGroupLayoutError::Entry {
2586 binding: entry.binding,
2587 error: BindGroupLayoutEntryError::StorageTextureCube,
2588 })
2589 }
2590 _ => (),
2591 }
2592 match access {
2593 wgt::StorageTextureAccess::Atomic
2594 if !self.features.contains(wgt::Features::TEXTURE_ATOMIC) =>
2595 {
2596 return Err(binding_model::CreateBindGroupLayoutError::Entry {
2597 binding: entry.binding,
2598 error: BindGroupLayoutEntryError::StorageTextureAtomic,
2599 });
2600 }
2601 _ => (),
2602 }
2603 (
2604 Some(
2605 wgt::Features::TEXTURE_BINDING_ARRAY
2606 | wgt::Features::STORAGE_RESOURCE_BINDING_ARRAY,
2607 ),
2608 match access {
2609 wgt::StorageTextureAccess::WriteOnly => WritableStorage::Yes,
2610 wgt::StorageTextureAccess::ReadOnly => WritableStorage::No,
2611 wgt::StorageTextureAccess::ReadWrite => WritableStorage::Yes,
2612 wgt::StorageTextureAccess::Atomic => {
2613 required_features |= wgt::Features::TEXTURE_ATOMIC;
2614 WritableStorage::Yes
2615 }
2616 },
2617 )
2618 }
2619 Bt::AccelerationStructure { vertex_return } => {
2620 self.require_features(wgt::Features::EXPERIMENTAL_RAY_QUERY)
2621 .map_err(|e| binding_model::CreateBindGroupLayoutError::Entry {
2622 binding: entry.binding,
2623 error: e.into(),
2624 })?;
2625 if vertex_return {
2626 self.require_features(wgt::Features::EXPERIMENTAL_RAY_HIT_VERTEX_RETURN)
2627 .map_err(|e| binding_model::CreateBindGroupLayoutError::Entry {
2628 binding: entry.binding,
2629 error: e.into(),
2630 })?;
2631 }
2632
2633 (None, WritableStorage::No)
2634 }
2635 Bt::ExternalTexture => {
2636 self.require_features(wgt::Features::EXTERNAL_TEXTURE)
2637 .map_err(|e| binding_model::CreateBindGroupLayoutError::Entry {
2638 binding: entry.binding,
2639 error: e.into(),
2640 })?;
2641 (None, WritableStorage::No)
2642 }
2643 };
2644
2645 if entry.count.is_some() {
2647 required_features |= array_feature
2648 .ok_or(BindGroupLayoutEntryError::ArrayUnsupported)
2649 .map_err(|error| binding_model::CreateBindGroupLayoutError::Entry {
2650 binding: entry.binding,
2651 error,
2652 })?;
2653 }
2654
2655 if entry.visibility.contains_unknown_bits() {
2656 return Err(
2657 binding_model::CreateBindGroupLayoutError::InvalidVisibility(entry.visibility),
2658 );
2659 }
2660
2661 if entry.visibility.contains(wgt::ShaderStages::VERTEX) {
2662 if writable_storage == WritableStorage::Yes {
2663 required_features |= wgt::Features::VERTEX_WRITABLE_STORAGE;
2664 }
2665 if let Bt::Buffer {
2666 ty: wgt::BufferBindingType::Storage { .. },
2667 ..
2668 } = entry.ty
2669 {
2670 required_downlevel_flags |= wgt::DownlevelFlags::VERTEX_STORAGE;
2671 }
2672 }
2673 if writable_storage == WritableStorage::Yes
2674 && entry.visibility.contains(wgt::ShaderStages::FRAGMENT)
2675 {
2676 required_downlevel_flags |= wgt::DownlevelFlags::FRAGMENT_WRITABLE_STORAGE;
2677 }
2678
2679 self.require_features(required_features)
2680 .map_err(BindGroupLayoutEntryError::MissingFeatures)
2681 .map_err(|error| binding_model::CreateBindGroupLayoutError::Entry {
2682 binding: entry.binding,
2683 error,
2684 })?;
2685 self.require_downlevel_flags(required_downlevel_flags)
2686 .map_err(BindGroupLayoutEntryError::MissingDownlevelFlags)
2687 .map_err(|error| binding_model::CreateBindGroupLayoutError::Entry {
2688 binding: entry.binding,
2689 error,
2690 })?;
2691 }
2692
2693 let bgl_flags = conv::bind_group_layout_flags(self.features);
2694
2695 let hal_bindings = entry_map.values().copied().collect::<Vec<_>>();
2696 let hal_desc = hal::BindGroupLayoutDescriptor {
2697 label: label.to_hal(self.instance_flags),
2698 flags: bgl_flags,
2699 entries: &hal_bindings,
2700 };
2701
2702 let mut count_validator = binding_model::BindingTypeMaxCountValidator::default();
2703 for entry in entry_map.values() {
2704 count_validator.add_binding(entry);
2705 }
2706 count_validator
2709 .validate(&self.limits)
2710 .map_err(binding_model::CreateBindGroupLayoutError::TooManyBindings)?;
2711
2712 count_validator.validate_binding_arrays()?;
2714
2715 let raw = unsafe { self.raw().create_bind_group_layout(&hal_desc) }
2716 .map_err(|e| self.handle_hal_error(e))?;
2717
2718 let bgl = BindGroupLayout {
2719 raw: ManuallyDrop::new(raw),
2720 device: self.clone(),
2721 entries: entry_map,
2722 origin,
2723 exclusive_pipeline: OnceCellOrLock::new(),
2724 binding_count_validator: count_validator,
2725 label: label.to_string(),
2726 };
2727
2728 let bgl = Arc::new(bgl);
2729
2730 Ok(bgl)
2731 }
2732
2733 fn create_buffer_binding<'a>(
2734 &self,
2735 bb: &'a binding_model::ResolvedBufferBinding,
2736 binding: u32,
2737 decl: &wgt::BindGroupLayoutEntry,
2738 used_buffer_ranges: &mut Vec<BufferInitTrackerAction>,
2739 dynamic_binding_info: &mut Vec<binding_model::BindGroupDynamicBindingData>,
2740 late_buffer_binding_sizes: &mut FastHashMap<u32, wgt::BufferSize>,
2741 used: &mut BindGroupStates,
2742 snatch_guard: &'a SnatchGuard<'a>,
2743 ) -> Result<hal::BufferBinding<'a, dyn hal::DynBuffer>, binding_model::CreateBindGroupError>
2744 {
2745 use crate::binding_model::CreateBindGroupError as Error;
2746
2747 let (binding_ty, dynamic, min_size) = match decl.ty {
2748 wgt::BindingType::Buffer {
2749 ty,
2750 has_dynamic_offset,
2751 min_binding_size,
2752 } => (ty, has_dynamic_offset, min_binding_size),
2753 _ => {
2754 return Err(Error::WrongBindingType {
2755 binding,
2756 actual: decl.ty,
2757 expected: "UniformBuffer, StorageBuffer or ReadonlyStorageBuffer",
2758 })
2759 }
2760 };
2761
2762 let (pub_usage, internal_use, range_limit) = match binding_ty {
2763 wgt::BufferBindingType::Uniform => (
2764 wgt::BufferUsages::UNIFORM,
2765 wgt::BufferUses::UNIFORM,
2766 self.limits.max_uniform_buffer_binding_size,
2767 ),
2768 wgt::BufferBindingType::Storage { read_only } => (
2769 wgt::BufferUsages::STORAGE,
2770 if read_only {
2771 wgt::BufferUses::STORAGE_READ_ONLY
2772 } else {
2773 wgt::BufferUses::STORAGE_READ_WRITE
2774 },
2775 self.limits.max_storage_buffer_binding_size,
2776 ),
2777 };
2778
2779 let (align, align_limit_name) =
2780 binding_model::buffer_binding_type_alignment(&self.limits, binding_ty);
2781 if bb.offset % align as u64 != 0 {
2782 return Err(Error::UnalignedBufferOffset(
2783 bb.offset,
2784 align_limit_name,
2785 align,
2786 ));
2787 }
2788
2789 let buffer = &bb.buffer;
2790
2791 used.buffers.insert_single(buffer.clone(), internal_use);
2792
2793 buffer.same_device(self)?;
2794
2795 buffer.check_usage(pub_usage)?;
2796
2797 let (bb, bind_size) = buffer.binding(bb.offset, bb.size, snatch_guard)?;
2798
2799 if matches!(binding_ty, wgt::BufferBindingType::Storage { .. })
2800 && bind_size % u64::from(wgt::STORAGE_BINDING_SIZE_ALIGNMENT) != 0
2801 {
2802 return Err(Error::UnalignedEffectiveBufferBindingSizeForStorage {
2803 alignment: wgt::STORAGE_BINDING_SIZE_ALIGNMENT,
2804 size: bind_size,
2805 });
2806 }
2807
2808 let bind_end = bb.offset + bind_size;
2809
2810 if bind_size > range_limit as u64 {
2811 return Err(Error::BufferRangeTooLarge {
2812 binding,
2813 given: bind_size as u32,
2814 limit: range_limit,
2815 });
2816 }
2817
2818 if dynamic {
2820 dynamic_binding_info.push(binding_model::BindGroupDynamicBindingData {
2821 binding_idx: binding,
2822 buffer_size: buffer.size,
2823 binding_range: bb.offset..bind_end,
2824 maximum_dynamic_offset: buffer.size - bind_end,
2825 binding_type: binding_ty,
2826 });
2827 }
2828
2829 if let Some(non_zero) = min_size {
2830 let min_size = non_zero.get();
2831 if min_size > bind_size {
2832 return Err(Error::BindingSizeTooSmall {
2833 buffer: buffer.error_ident(),
2834 actual: bind_size,
2835 min: min_size,
2836 });
2837 }
2838 } else {
2839 let late_size = wgt::BufferSize::new(bind_size)
2840 .ok_or_else(|| Error::BindingZeroSize(buffer.error_ident()))?;
2841 late_buffer_binding_sizes.insert(binding, late_size);
2842 }
2843
2844 assert_eq!(bb.offset % wgt::COPY_BUFFER_ALIGNMENT, 0);
2847
2848 let bounds_check_alignment =
2853 binding_model::buffer_binding_type_bounds_check_alignment(&self.alignments, binding_ty);
2854 let visible_size = align_to(bind_size, bounds_check_alignment);
2855
2856 used_buffer_ranges.extend(buffer.initialization_status.read().create_action(
2857 buffer,
2858 bb.offset..bb.offset + visible_size,
2859 MemoryInitKind::NeedsInitializedMemory,
2860 ));
2861
2862 Ok(bb)
2863 }
2864
2865 fn create_sampler_binding<'a>(
2866 &self,
2867 used: &mut BindGroupStates,
2868 binding: u32,
2869 decl: &wgt::BindGroupLayoutEntry,
2870 sampler: &'a Arc<Sampler>,
2871 ) -> Result<&'a dyn hal::DynSampler, binding_model::CreateBindGroupError> {
2872 use crate::binding_model::CreateBindGroupError as Error;
2873
2874 used.samplers.insert_single(sampler.clone());
2875
2876 sampler.same_device(self)?;
2877
2878 match decl.ty {
2879 wgt::BindingType::Sampler(ty) => {
2880 let (allowed_filtering, allowed_comparison) = match ty {
2881 wgt::SamplerBindingType::Filtering => (None, false),
2882 wgt::SamplerBindingType::NonFiltering => (Some(false), false),
2883 wgt::SamplerBindingType::Comparison => (None, true),
2884 };
2885 if let Some(allowed_filtering) = allowed_filtering {
2886 if allowed_filtering != sampler.filtering {
2887 return Err(Error::WrongSamplerFiltering {
2888 binding,
2889 layout_flt: allowed_filtering,
2890 sampler_flt: sampler.filtering,
2891 });
2892 }
2893 }
2894 if allowed_comparison != sampler.comparison {
2895 return Err(Error::WrongSamplerComparison {
2896 binding,
2897 layout_cmp: allowed_comparison,
2898 sampler_cmp: sampler.comparison,
2899 });
2900 }
2901 }
2902 _ => {
2903 return Err(Error::WrongBindingType {
2904 binding,
2905 actual: decl.ty,
2906 expected: "Sampler",
2907 })
2908 }
2909 }
2910
2911 Ok(sampler.raw())
2912 }
2913
2914 fn create_texture_binding<'a>(
2915 &self,
2916 binding: u32,
2917 decl: &wgt::BindGroupLayoutEntry,
2918 view: &'a Arc<TextureView>,
2919 used: &mut BindGroupStates,
2920 used_texture_ranges: &mut Vec<TextureInitTrackerAction>,
2921 snatch_guard: &'a SnatchGuard<'a>,
2922 ) -> Result<hal::TextureBinding<'a, dyn hal::DynTextureView>, binding_model::CreateBindGroupError>
2923 {
2924 view.same_device(self)?;
2925
2926 let internal_use = self.texture_use_parameters(
2927 binding,
2928 decl,
2929 view,
2930 "SampledTexture, ReadonlyStorageTexture or WriteonlyStorageTexture",
2931 )?;
2932
2933 used.views.insert_single(view.clone(), internal_use);
2934
2935 let texture = &view.parent;
2936
2937 used_texture_ranges.push(TextureInitTrackerAction {
2938 texture: texture.clone(),
2939 range: TextureInitRange {
2940 mip_range: view.desc.range.mip_range(texture.desc.mip_level_count),
2941 layer_range: view
2942 .desc
2943 .range
2944 .layer_range(texture.desc.array_layer_count()),
2945 },
2946 kind: MemoryInitKind::NeedsInitializedMemory,
2947 });
2948
2949 Ok(hal::TextureBinding {
2950 view: view.try_raw(snatch_guard)?,
2951 usage: internal_use,
2952 })
2953 }
2954
2955 fn create_tlas_binding<'a>(
2956 self: &Arc<Self>,
2957 used: &mut BindGroupStates,
2958 binding: u32,
2959 decl: &wgt::BindGroupLayoutEntry,
2960 tlas: &'a Arc<Tlas>,
2961 snatch_guard: &'a SnatchGuard<'a>,
2962 ) -> Result<&'a dyn hal::DynAccelerationStructure, binding_model::CreateBindGroupError> {
2963 use crate::binding_model::CreateBindGroupError as Error;
2964
2965 used.acceleration_structures.insert_single(tlas.clone());
2966
2967 tlas.same_device(self)?;
2968
2969 match decl.ty {
2970 wgt::BindingType::AccelerationStructure { vertex_return } => {
2971 if vertex_return
2972 && !tlas.flags.contains(
2973 wgpu_types::AccelerationStructureFlags::ALLOW_RAY_HIT_VERTEX_RETURN,
2974 )
2975 {
2976 return Err(Error::MissingTLASVertexReturn { binding });
2977 }
2978 }
2979 _ => {
2980 return Err(Error::WrongBindingType {
2981 binding,
2982 actual: decl.ty,
2983 expected: "Tlas",
2984 });
2985 }
2986 }
2987
2988 Ok(tlas.try_raw(snatch_guard)?)
2989 }
2990
2991 fn create_external_texture_binding<'a>(
2992 &'a self,
2993 binding: u32,
2994 decl: &wgt::BindGroupLayoutEntry,
2995 external_texture: &'a Arc<ExternalTexture>,
2996 used: &mut BindGroupStates,
2997 snatch_guard: &'a SnatchGuard,
2998 ) -> Result<
2999 hal::ExternalTextureBinding<'a, dyn hal::DynBuffer, dyn hal::DynTextureView>,
3000 binding_model::CreateBindGroupError,
3001 > {
3002 use crate::binding_model::CreateBindGroupError as Error;
3003
3004 external_texture.same_device(self)?;
3005
3006 used.external_textures
3007 .insert_single(external_texture.clone());
3008
3009 match decl.ty {
3010 wgt::BindingType::ExternalTexture => {}
3011 _ => {
3012 return Err(Error::WrongBindingType {
3013 binding,
3014 actual: decl.ty,
3015 expected: "ExternalTexture",
3016 });
3017 }
3018 }
3019
3020 let planes = (0..3)
3021 .map(|i| {
3022 let plane = external_texture
3026 .planes
3027 .get(i)
3028 .unwrap_or(&external_texture.planes[0]);
3029 let internal_use = wgt::TextureUses::RESOURCE;
3030 used.views.insert_single(plane.clone(), internal_use);
3031 let view = plane.try_raw(snatch_guard)?;
3032 Ok(hal::TextureBinding {
3033 view,
3034 usage: internal_use,
3035 })
3036 })
3037 .collect::<Result<Vec<_>, Error>>()?;
3040 let planes = planes.try_into().unwrap();
3041
3042 used.buffers
3043 .insert_single(external_texture.params.clone(), wgt::BufferUses::UNIFORM);
3044 let params = external_texture.params.binding(0, None, snatch_guard)?.0;
3045
3046 Ok(hal::ExternalTextureBinding { planes, params })
3047 }
3048
3049 fn create_external_texture_binding_from_view<'a>(
3050 &'a self,
3051 binding: u32,
3052 decl: &wgt::BindGroupLayoutEntry,
3053 view: &'a Arc<TextureView>,
3054 used: &mut BindGroupStates,
3055 snatch_guard: &'a SnatchGuard,
3056 ) -> Result<
3057 hal::ExternalTextureBinding<'a, dyn hal::DynBuffer, dyn hal::DynTextureView>,
3058 binding_model::CreateBindGroupError,
3059 > {
3060 use crate::binding_model::CreateBindGroupError as Error;
3061
3062 view.same_device(self)?;
3063
3064 let internal_use = self.texture_use_parameters(binding, decl, view, "SampledTexture")?;
3065 used.views.insert_single(view.clone(), internal_use);
3066
3067 match decl.ty {
3068 wgt::BindingType::ExternalTexture => {}
3069 _ => {
3070 return Err(Error::WrongBindingType {
3071 binding,
3072 actual: decl.ty,
3073 expected: "ExternalTexture",
3074 });
3075 }
3076 }
3077
3078 let planes = [
3080 hal::TextureBinding {
3081 view: view.try_raw(snatch_guard)?,
3082 usage: internal_use,
3083 },
3084 hal::TextureBinding {
3085 view: view.try_raw(snatch_guard)?,
3086 usage: internal_use,
3087 },
3088 hal::TextureBinding {
3089 view: view.try_raw(snatch_guard)?,
3090 usage: internal_use,
3091 },
3092 ];
3093 let params = hal::BufferBinding::new_unchecked(
3094 self.default_external_texture_params_buffer.as_ref(),
3095 0,
3096 None,
3097 );
3098
3099 Ok(hal::ExternalTextureBinding { planes, params })
3100 }
3101
3102 pub fn create_bind_group(
3105 self: &Arc<Self>,
3106 desc: binding_model::ResolvedBindGroupDescriptor,
3107 ) -> Result<Arc<BindGroup>, binding_model::CreateBindGroupError> {
3108 use crate::binding_model::{CreateBindGroupError as Error, ResolvedBindingResource as Br};
3109
3110 let layout = desc.layout;
3111
3112 self.check_is_valid()?;
3113 layout.same_device(self)?;
3114
3115 {
3116 let actual = desc.entries.len();
3119 let expected = layout.entries.len();
3120 if actual != expected {
3121 return Err(Error::BindingsNumMismatch { expected, actual });
3122 }
3123 }
3124
3125 let mut dynamic_binding_info = Vec::new();
3128 let mut late_buffer_binding_sizes = FastHashMap::default();
3132 let mut used = BindGroupStates::new();
3134
3135 let mut used_buffer_ranges = Vec::new();
3136 let mut used_texture_ranges = Vec::new();
3137 let mut hal_entries = Vec::with_capacity(desc.entries.len());
3138 let mut hal_buffers = Vec::new();
3139 let mut hal_samplers = Vec::new();
3140 let mut hal_textures = Vec::new();
3141 let mut hal_tlas_s = Vec::new();
3142 let mut hal_external_textures = Vec::new();
3143 let snatch_guard = self.snatchable_lock.read();
3144 for entry in desc.entries.iter() {
3145 let binding = entry.binding;
3146 let decl = layout
3148 .entries
3149 .get(binding)
3150 .ok_or(Error::MissingBindingDeclaration(binding))?;
3151 let (res_index, count) = match entry.resource {
3152 Br::Buffer(ref bb) => {
3153 let bb = self.create_buffer_binding(
3154 bb,
3155 binding,
3156 decl,
3157 &mut used_buffer_ranges,
3158 &mut dynamic_binding_info,
3159 &mut late_buffer_binding_sizes,
3160 &mut used,
3161 &snatch_guard,
3162 )?;
3163
3164 let res_index = hal_buffers.len();
3165 hal_buffers.push(bb);
3166 (res_index, 1)
3167 }
3168 Br::BufferArray(ref bindings_array) => {
3169 let num_bindings = bindings_array.len();
3170 Self::check_array_binding(self.features, decl.count, num_bindings)?;
3171
3172 let res_index = hal_buffers.len();
3173 for bb in bindings_array.iter() {
3174 let bb = self.create_buffer_binding(
3175 bb,
3176 binding,
3177 decl,
3178 &mut used_buffer_ranges,
3179 &mut dynamic_binding_info,
3180 &mut late_buffer_binding_sizes,
3181 &mut used,
3182 &snatch_guard,
3183 )?;
3184 hal_buffers.push(bb);
3185 }
3186 (res_index, num_bindings)
3187 }
3188 Br::Sampler(ref sampler) => {
3189 let sampler = self.create_sampler_binding(&mut used, binding, decl, sampler)?;
3190
3191 let res_index = hal_samplers.len();
3192 hal_samplers.push(sampler);
3193 (res_index, 1)
3194 }
3195 Br::SamplerArray(ref samplers) => {
3196 let num_bindings = samplers.len();
3197 Self::check_array_binding(self.features, decl.count, num_bindings)?;
3198
3199 let res_index = hal_samplers.len();
3200 for sampler in samplers.iter() {
3201 let sampler =
3202 self.create_sampler_binding(&mut used, binding, decl, sampler)?;
3203
3204 hal_samplers.push(sampler);
3205 }
3206
3207 (res_index, num_bindings)
3208 }
3209 Br::TextureView(ref view) => match decl.ty {
3210 wgt::BindingType::ExternalTexture => {
3211 let et = self.create_external_texture_binding_from_view(
3212 binding,
3213 decl,
3214 view,
3215 &mut used,
3216 &snatch_guard,
3217 )?;
3218 let res_index = hal_external_textures.len();
3219 hal_external_textures.push(et);
3220 (res_index, 1)
3221 }
3222 _ => {
3223 let tb = self.create_texture_binding(
3224 binding,
3225 decl,
3226 view,
3227 &mut used,
3228 &mut used_texture_ranges,
3229 &snatch_guard,
3230 )?;
3231 let res_index = hal_textures.len();
3232 hal_textures.push(tb);
3233 (res_index, 1)
3234 }
3235 },
3236 Br::TextureViewArray(ref views) => {
3237 let num_bindings = views.len();
3238 Self::check_array_binding(self.features, decl.count, num_bindings)?;
3239
3240 let res_index = hal_textures.len();
3241 for view in views.iter() {
3242 let tb = self.create_texture_binding(
3243 binding,
3244 decl,
3245 view,
3246 &mut used,
3247 &mut used_texture_ranges,
3248 &snatch_guard,
3249 )?;
3250
3251 hal_textures.push(tb);
3252 }
3253
3254 (res_index, num_bindings)
3255 }
3256 Br::AccelerationStructure(ref tlas) => {
3257 let tlas =
3258 self.create_tlas_binding(&mut used, binding, decl, tlas, &snatch_guard)?;
3259 let res_index = hal_tlas_s.len();
3260 hal_tlas_s.push(tlas);
3261 (res_index, 1)
3262 }
3263 Br::ExternalTexture(ref et) => {
3264 let et = self.create_external_texture_binding(
3265 binding,
3266 decl,
3267 et,
3268 &mut used,
3269 &snatch_guard,
3270 )?;
3271 let res_index = hal_external_textures.len();
3272 hal_external_textures.push(et);
3273 (res_index, 1)
3274 }
3275 };
3276
3277 hal_entries.push(hal::BindGroupEntry {
3278 binding,
3279 resource_index: res_index as u32,
3280 count: count as u32,
3281 });
3282 }
3283
3284 used.optimize();
3285
3286 hal_entries.sort_by_key(|entry| entry.binding);
3287 for (a, b) in hal_entries.iter().zip(hal_entries.iter().skip(1)) {
3288 if a.binding == b.binding {
3289 return Err(Error::DuplicateBinding(a.binding));
3290 }
3291 }
3292 let hal_desc = hal::BindGroupDescriptor {
3293 label: desc.label.to_hal(self.instance_flags),
3294 layout: layout.raw(),
3295 entries: &hal_entries,
3296 buffers: &hal_buffers,
3297 samplers: &hal_samplers,
3298 textures: &hal_textures,
3299 acceleration_structures: &hal_tlas_s,
3300 external_textures: &hal_external_textures,
3301 };
3302 let raw = unsafe { self.raw().create_bind_group(&hal_desc) }
3303 .map_err(|e| self.handle_hal_error(e))?;
3304
3305 let late_buffer_binding_infos = layout
3307 .entries
3308 .indices()
3309 .flat_map(|binding| {
3310 let size = late_buffer_binding_sizes.get(&binding).cloned()?;
3311 Some(BindGroupLateBufferBindingInfo {
3312 binding_index: binding,
3313 size,
3314 })
3315 })
3316 .collect();
3317
3318 let bind_group = BindGroup {
3319 raw: Snatchable::new(raw),
3320 device: self.clone(),
3321 layout,
3322 label: desc.label.to_string(),
3323 tracking_data: TrackingData::new(self.tracker_indices.bind_groups.clone()),
3324 used,
3325 used_buffer_ranges,
3326 used_texture_ranges,
3327 dynamic_binding_info,
3328 late_buffer_binding_infos,
3329 };
3330
3331 let bind_group = Arc::new(bind_group);
3332
3333 let weak_ref = Arc::downgrade(&bind_group);
3334 for range in &bind_group.used_texture_ranges {
3335 let mut bind_groups = range.texture.bind_groups.lock();
3336 bind_groups.push(weak_ref.clone());
3337 }
3338 for range in &bind_group.used_buffer_ranges {
3339 let mut bind_groups = range.buffer.bind_groups.lock();
3340 bind_groups.push(weak_ref.clone());
3341 }
3342
3343 Ok(bind_group)
3344 }
3345
3346 fn check_array_binding(
3347 features: wgt::Features,
3348 count: Option<NonZeroU32>,
3349 num_bindings: usize,
3350 ) -> Result<(), binding_model::CreateBindGroupError> {
3351 use super::binding_model::CreateBindGroupError as Error;
3352
3353 if let Some(count) = count {
3354 let count = count.get() as usize;
3355 if count < num_bindings {
3356 return Err(Error::BindingArrayPartialLengthMismatch {
3357 actual: num_bindings,
3358 expected: count,
3359 });
3360 }
3361 if count != num_bindings
3362 && !features.contains(wgt::Features::PARTIALLY_BOUND_BINDING_ARRAY)
3363 {
3364 return Err(Error::BindingArrayLengthMismatch {
3365 actual: num_bindings,
3366 expected: count,
3367 });
3368 }
3369 if num_bindings == 0 {
3370 return Err(Error::BindingArrayZeroLength);
3371 }
3372 } else {
3373 return Err(Error::SingleBindingExpected);
3374 };
3375
3376 Ok(())
3377 }
3378
3379 fn texture_use_parameters(
3380 &self,
3381 binding: u32,
3382 decl: &wgt::BindGroupLayoutEntry,
3383 view: &TextureView,
3384 expected: &'static str,
3385 ) -> Result<wgt::TextureUses, binding_model::CreateBindGroupError> {
3386 use crate::binding_model::CreateBindGroupError as Error;
3387 if view
3388 .desc
3389 .aspects()
3390 .contains(hal::FormatAspects::DEPTH | hal::FormatAspects::STENCIL)
3391 {
3392 return Err(Error::DepthStencilAspect);
3393 }
3394 match decl.ty {
3395 wgt::BindingType::Texture {
3396 sample_type,
3397 view_dimension,
3398 multisampled,
3399 } => {
3400 use wgt::TextureSampleType as Tst;
3401 if multisampled != (view.samples != 1) {
3402 return Err(Error::InvalidTextureMultisample {
3403 binding,
3404 layout_multisampled: multisampled,
3405 view_samples: view.samples,
3406 });
3407 }
3408 let compat_sample_type = view
3409 .desc
3410 .format
3411 .sample_type(Some(view.desc.range.aspect), Some(self.features))
3412 .unwrap();
3413 match (sample_type, compat_sample_type) {
3414 (Tst::Uint, Tst::Uint) |
3415 (Tst::Sint, Tst::Sint) |
3416 (Tst::Depth, Tst::Depth) |
3417 (Tst::Float { filterable: false }, Tst::Float { .. }) |
3419 (Tst::Float { filterable: true }, Tst::Float { filterable: true }) |
3421 (Tst::Float { filterable: false }, Tst::Depth) => {}
3423 (Tst::Float { filterable: true }, Tst::Float { .. }) if view.format_features.flags.contains(wgt::TextureFormatFeatureFlags::FILTERABLE) => {}
3428 _ => {
3429 return Err(Error::InvalidTextureSampleType {
3430 binding,
3431 layout_sample_type: sample_type,
3432 view_format: view.desc.format,
3433 view_sample_type: compat_sample_type,
3434 })
3435 }
3436 }
3437 if view_dimension != view.desc.dimension {
3438 return Err(Error::InvalidTextureDimension {
3439 binding,
3440 layout_dimension: view_dimension,
3441 view_dimension: view.desc.dimension,
3442 });
3443 }
3444 view.check_usage(wgt::TextureUsages::TEXTURE_BINDING)?;
3445 Ok(wgt::TextureUses::RESOURCE)
3446 }
3447 wgt::BindingType::StorageTexture {
3448 access,
3449 format,
3450 view_dimension,
3451 } => {
3452 if format != view.desc.format {
3453 return Err(Error::InvalidStorageTextureFormat {
3454 binding,
3455 layout_format: format,
3456 view_format: view.desc.format,
3457 });
3458 }
3459 if view_dimension != view.desc.dimension {
3460 return Err(Error::InvalidTextureDimension {
3461 binding,
3462 layout_dimension: view_dimension,
3463 view_dimension: view.desc.dimension,
3464 });
3465 }
3466
3467 let mip_level_count = view.selector.mips.end - view.selector.mips.start;
3468 if mip_level_count != 1 {
3469 return Err(Error::InvalidStorageTextureMipLevelCount {
3470 binding,
3471 mip_level_count,
3472 });
3473 }
3474
3475 let internal_use = match access {
3476 wgt::StorageTextureAccess::WriteOnly => {
3477 if !view
3478 .format_features
3479 .flags
3480 .contains(wgt::TextureFormatFeatureFlags::STORAGE_WRITE_ONLY)
3481 {
3482 return Err(Error::StorageWriteNotSupported(view.desc.format));
3483 }
3484 wgt::TextureUses::STORAGE_WRITE_ONLY
3485 }
3486 wgt::StorageTextureAccess::ReadOnly => {
3487 if !view
3488 .format_features
3489 .flags
3490 .contains(wgt::TextureFormatFeatureFlags::STORAGE_READ_ONLY)
3491 {
3492 return Err(Error::StorageReadNotSupported(view.desc.format));
3493 }
3494 wgt::TextureUses::STORAGE_READ_ONLY
3495 }
3496 wgt::StorageTextureAccess::ReadWrite => {
3497 if !view
3498 .format_features
3499 .flags
3500 .contains(wgt::TextureFormatFeatureFlags::STORAGE_READ_WRITE)
3501 {
3502 return Err(Error::StorageReadWriteNotSupported(view.desc.format));
3503 }
3504
3505 wgt::TextureUses::STORAGE_READ_WRITE
3506 }
3507 wgt::StorageTextureAccess::Atomic => {
3508 if !view
3509 .format_features
3510 .flags
3511 .contains(wgt::TextureFormatFeatureFlags::STORAGE_ATOMIC)
3512 {
3513 return Err(Error::StorageAtomicNotSupported(view.desc.format));
3514 }
3515
3516 wgt::TextureUses::STORAGE_ATOMIC
3517 }
3518 };
3519 view.check_usage(wgt::TextureUsages::STORAGE_BINDING)?;
3520 Ok(internal_use)
3521 }
3522 wgt::BindingType::ExternalTexture => {
3523 if view.desc.dimension != TextureViewDimension::D2 {
3524 return Err(Error::InvalidTextureDimension {
3525 binding,
3526 layout_dimension: TextureViewDimension::D2,
3527 view_dimension: view.desc.dimension,
3528 });
3529 }
3530 let mip_level_count = view.selector.mips.end - view.selector.mips.start;
3531 if mip_level_count != 1 {
3532 return Err(Error::InvalidExternalTextureMipLevelCount {
3533 binding,
3534 mip_level_count,
3535 });
3536 }
3537 if view.desc.format != TextureFormat::Rgba8Unorm
3538 && view.desc.format != TextureFormat::Bgra8Unorm
3539 && view.desc.format != TextureFormat::Rgba16Float
3540 {
3541 return Err(Error::InvalidExternalTextureFormat {
3542 binding,
3543 format: view.desc.format,
3544 });
3545 }
3546 if view.samples != 1 {
3547 return Err(Error::InvalidTextureMultisample {
3548 binding,
3549 layout_multisampled: false,
3550 view_samples: view.samples,
3551 });
3552 }
3553
3554 view.check_usage(wgt::TextureUsages::TEXTURE_BINDING)?;
3555 Ok(wgt::TextureUses::RESOURCE)
3556 }
3557 _ => Err(Error::WrongBindingType {
3558 binding,
3559 actual: decl.ty,
3560 expected,
3561 }),
3562 }
3563 }
3564
3565 pub fn create_pipeline_layout(
3566 self: &Arc<Self>,
3567 desc: &binding_model::ResolvedPipelineLayoutDescriptor,
3568 ) -> Result<Arc<binding_model::PipelineLayout>, binding_model::CreatePipelineLayoutError> {
3569 use crate::binding_model::CreatePipelineLayoutError as Error;
3570
3571 self.check_is_valid()?;
3572
3573 let bind_group_layouts_count = desc.bind_group_layouts.len();
3574 let device_max_bind_groups = self.limits.max_bind_groups as usize;
3575 if bind_group_layouts_count > device_max_bind_groups {
3576 return Err(Error::TooManyGroups {
3577 actual: bind_group_layouts_count,
3578 max: device_max_bind_groups,
3579 });
3580 }
3581
3582 if !desc.immediates_ranges.is_empty() {
3583 self.require_features(wgt::Features::IMMEDIATES)?;
3584 }
3585
3586 let mut used_stages = wgt::ShaderStages::empty();
3587 for (index, pc) in desc.immediates_ranges.iter().enumerate() {
3588 if pc.stages.intersects(used_stages) {
3589 return Err(Error::MoreThanOneImmediateRangePerStage {
3590 index,
3591 provided: pc.stages,
3592 intersected: pc.stages & used_stages,
3593 });
3594 }
3595 used_stages |= pc.stages;
3596
3597 let device_max_pc_size = self.limits.max_immediate_size;
3598 if device_max_pc_size < pc.range.end {
3599 return Err(Error::ImmediateRangeTooLarge {
3600 index,
3601 range: pc.range.clone(),
3602 max: device_max_pc_size,
3603 });
3604 }
3605
3606 if pc.range.start % wgt::IMMEDIATES_ALIGNMENT != 0 {
3607 return Err(Error::MisalignedImmediateRange {
3608 index,
3609 bound: pc.range.start,
3610 });
3611 }
3612 if pc.range.end % wgt::IMMEDIATES_ALIGNMENT != 0 {
3613 return Err(Error::MisalignedImmediateRange {
3614 index,
3615 bound: pc.range.end,
3616 });
3617 }
3618 }
3619
3620 let mut count_validator = binding_model::BindingTypeMaxCountValidator::default();
3621
3622 for bgl in desc.bind_group_layouts.iter() {
3623 bgl.same_device(self)?;
3624 count_validator.merge(&bgl.binding_count_validator);
3625 }
3626
3627 count_validator
3628 .validate(&self.limits)
3629 .map_err(Error::TooManyBindings)?;
3630
3631 let bind_group_layouts = desc
3632 .bind_group_layouts
3633 .iter()
3634 .cloned()
3635 .collect::<ArrayVec<_, { hal::MAX_BIND_GROUPS }>>();
3636
3637 let raw_bind_group_layouts = desc
3638 .bind_group_layouts
3639 .iter()
3640 .map(|bgl| bgl.raw())
3641 .collect::<ArrayVec<_, { hal::MAX_BIND_GROUPS }>>();
3642
3643 let additional_flags = if self.indirect_validation.is_some() {
3644 hal::PipelineLayoutFlags::INDIRECT_BUILTIN_UPDATE
3645 } else {
3646 hal::PipelineLayoutFlags::empty()
3647 };
3648
3649 let hal_desc = hal::PipelineLayoutDescriptor {
3650 label: desc.label.to_hal(self.instance_flags),
3651 flags: hal::PipelineLayoutFlags::FIRST_VERTEX_INSTANCE
3652 | hal::PipelineLayoutFlags::NUM_WORK_GROUPS
3653 | additional_flags,
3654 bind_group_layouts: &raw_bind_group_layouts,
3655 immediates_ranges: desc.immediates_ranges.as_ref(),
3656 };
3657
3658 let raw = unsafe { self.raw().create_pipeline_layout(&hal_desc) }
3659 .map_err(|e| self.handle_hal_error(e))?;
3660
3661 drop(raw_bind_group_layouts);
3662
3663 let layout = binding_model::PipelineLayout {
3664 raw: ManuallyDrop::new(raw),
3665 device: self.clone(),
3666 label: desc.label.to_string(),
3667 bind_group_layouts,
3668 immediates_ranges: desc.immediates_ranges.iter().cloned().collect(),
3669 };
3670
3671 let layout = Arc::new(layout);
3672
3673 Ok(layout)
3674 }
3675
3676 pub(crate) fn derive_pipeline_layout(
3677 self: &Arc<Self>,
3678 mut derived_group_layouts: Box<ArrayVec<bgl::EntryMap, { hal::MAX_BIND_GROUPS }>>,
3679 ) -> Result<Arc<binding_model::PipelineLayout>, pipeline::ImplicitLayoutError> {
3680 while derived_group_layouts
3681 .last()
3682 .is_some_and(|map| map.is_empty())
3683 {
3684 derived_group_layouts.pop();
3685 }
3686
3687 let mut unique_bind_group_layouts = FastHashMap::default();
3688
3689 let bind_group_layouts = derived_group_layouts
3690 .into_iter()
3691 .map(|mut bgl_entry_map| {
3692 bgl_entry_map.sort();
3693 match unique_bind_group_layouts.entry(bgl_entry_map) {
3694 hashbrown::hash_map::Entry::Occupied(v) => Ok(Arc::clone(v.get())),
3695 hashbrown::hash_map::Entry::Vacant(e) => {
3696 match self.create_bind_group_layout_internal(
3697 &None,
3698 e.key().clone(),
3699 bgl::Origin::Derived,
3700 ) {
3701 Ok(bgl) => {
3702 e.insert(bgl.clone());
3703 Ok(bgl)
3704 }
3705 Err(e) => Err(e),
3706 }
3707 }
3708 }
3709 })
3710 .collect::<Result<Vec<_>, _>>()?;
3711
3712 let layout_desc = binding_model::ResolvedPipelineLayoutDescriptor {
3713 label: None,
3714 bind_group_layouts: Cow::Owned(bind_group_layouts),
3715 immediates_ranges: Cow::Borrowed(&[]), };
3717
3718 let layout = self.create_pipeline_layout(&layout_desc)?;
3719 Ok(layout)
3720 }
3721
3722 pub fn create_compute_pipeline(
3723 self: &Arc<Self>,
3724 desc: pipeline::ResolvedComputePipelineDescriptor,
3725 ) -> Result<Arc<pipeline::ComputePipeline>, pipeline::CreateComputePipelineError> {
3726 self.check_is_valid()?;
3727
3728 self.require_downlevel_flags(wgt::DownlevelFlags::COMPUTE_SHADERS)?;
3729
3730 let shader_module = desc.stage.module;
3731
3732 shader_module.same_device(self)?;
3733
3734 let is_auto_layout = desc.layout.is_none();
3735
3736 let pipeline_layout = match desc.layout {
3738 Some(pipeline_layout) => {
3739 pipeline_layout.same_device(self)?;
3740 Some(pipeline_layout)
3741 }
3742 None => None,
3743 };
3744
3745 let mut binding_layout_source = match pipeline_layout {
3746 Some(ref pipeline_layout) => {
3747 validation::BindingLayoutSource::Provided(pipeline_layout.get_binding_maps())
3748 }
3749 None => validation::BindingLayoutSource::new_derived(&self.limits),
3750 };
3751 let mut shader_binding_sizes = FastHashMap::default();
3752 let io = validation::StageIo::default();
3753
3754 let final_entry_point_name;
3755
3756 {
3757 let stage = wgt::ShaderStages::COMPUTE;
3758
3759 final_entry_point_name = shader_module.finalize_entry_point_name(
3760 stage,
3761 desc.stage.entry_point.as_ref().map(|ep| ep.as_ref()),
3762 )?;
3763
3764 if let Some(ref interface) = shader_module.interface {
3765 let _ = interface.check_stage(
3766 &mut binding_layout_source,
3767 &mut shader_binding_sizes,
3768 &final_entry_point_name,
3769 stage,
3770 io,
3771 None,
3772 )?;
3773 }
3774 }
3775
3776 let pipeline_layout = match binding_layout_source {
3777 validation::BindingLayoutSource::Provided(_) => {
3778 drop(binding_layout_source);
3779 pipeline_layout.unwrap()
3780 }
3781 validation::BindingLayoutSource::Derived(entries) => {
3782 self.derive_pipeline_layout(entries)?
3783 }
3784 };
3785
3786 let late_sized_buffer_groups =
3787 Device::make_late_sized_buffer_groups(&shader_binding_sizes, &pipeline_layout);
3788
3789 let cache = match desc.cache {
3790 Some(cache) => {
3791 cache.same_device(self)?;
3792 Some(cache)
3793 }
3794 None => None,
3795 };
3796
3797 let pipeline_desc = hal::ComputePipelineDescriptor {
3798 label: desc.label.to_hal(self.instance_flags),
3799 layout: pipeline_layout.raw(),
3800 stage: hal::ProgrammableStage {
3801 module: shader_module.raw(),
3802 entry_point: final_entry_point_name.as_ref(),
3803 constants: &desc.stage.constants,
3804 zero_initialize_workgroup_memory: desc.stage.zero_initialize_workgroup_memory,
3805 },
3806 cache: cache.as_ref().map(|it| it.raw()),
3807 };
3808
3809 let raw =
3810 unsafe { self.raw().create_compute_pipeline(&pipeline_desc) }.map_err(
3811 |err| match err {
3812 hal::PipelineError::Device(error) => {
3813 pipeline::CreateComputePipelineError::Device(self.handle_hal_error(error))
3814 }
3815 hal::PipelineError::Linkage(_stages, msg) => {
3816 pipeline::CreateComputePipelineError::Internal(msg)
3817 }
3818 hal::PipelineError::EntryPoint(_stage) => {
3819 pipeline::CreateComputePipelineError::Internal(
3820 ENTRYPOINT_FAILURE_ERROR.to_string(),
3821 )
3822 }
3823 hal::PipelineError::PipelineConstants(_stages, msg) => {
3824 pipeline::CreateComputePipelineError::PipelineConstants(msg)
3825 }
3826 },
3827 )?;
3828
3829 let pipeline = pipeline::ComputePipeline {
3830 raw: ManuallyDrop::new(raw),
3831 layout: pipeline_layout,
3832 device: self.clone(),
3833 _shader_module: shader_module,
3834 late_sized_buffer_groups,
3835 label: desc.label.to_string(),
3836 tracking_data: TrackingData::new(self.tracker_indices.compute_pipelines.clone()),
3837 };
3838
3839 let pipeline = Arc::new(pipeline);
3840
3841 if is_auto_layout {
3842 for bgl in pipeline.layout.bind_group_layouts.iter() {
3843 let _ = bgl
3845 .exclusive_pipeline
3846 .set(binding_model::ExclusivePipeline::Compute(Arc::downgrade(
3847 &pipeline,
3848 )));
3849 }
3850 }
3851
3852 Ok(pipeline)
3853 }
3854
3855 pub fn create_render_pipeline(
3856 self: &Arc<Self>,
3857 desc: pipeline::ResolvedGeneralRenderPipelineDescriptor,
3858 ) -> Result<Arc<pipeline::RenderPipeline>, pipeline::CreateRenderPipelineError> {
3859 use wgt::TextureFormatFeatureFlags as Tfff;
3860
3861 self.check_is_valid()?;
3862
3863 let mut shader_binding_sizes = FastHashMap::default();
3864
3865 let num_attachments = desc.fragment.as_ref().map(|f| f.targets.len()).unwrap_or(0);
3866 let max_attachments = self.limits.max_color_attachments as usize;
3867 if num_attachments > max_attachments {
3868 return Err(pipeline::CreateRenderPipelineError::ColorAttachment(
3869 command::ColorAttachmentError::TooMany {
3870 given: num_attachments,
3871 limit: max_attachments,
3872 },
3873 ));
3874 }
3875
3876 let color_targets = desc
3877 .fragment
3878 .as_ref()
3879 .map_or(&[][..], |fragment| &fragment.targets);
3880 let depth_stencil_state = desc.depth_stencil.as_ref();
3881
3882 {
3883 let cts: ArrayVec<_, { hal::MAX_COLOR_ATTACHMENTS }> =
3884 color_targets.iter().filter_map(|x| x.as_ref()).collect();
3885 if !cts.is_empty() && {
3886 let first = &cts[0];
3887 cts[1..]
3888 .iter()
3889 .any(|ct| ct.write_mask != first.write_mask || ct.blend != first.blend)
3890 } {
3891 self.require_downlevel_flags(wgt::DownlevelFlags::INDEPENDENT_BLEND)?;
3892 }
3893 }
3894
3895 let mut io = validation::StageIo::default();
3896 let mut validated_stages = wgt::ShaderStages::empty();
3897
3898 let mut vertex_steps;
3899 let mut vertex_buffers;
3900 let mut total_attributes;
3901 let mut shader_expects_dual_source_blending = false;
3902 let mut pipeline_expects_dual_source_blending = false;
3903 if let pipeline::RenderPipelineVertexProcessor::Vertex(ref vertex) = desc.vertex {
3904 vertex_steps = Vec::with_capacity(vertex.buffers.len());
3905 vertex_buffers = Vec::with_capacity(vertex.buffers.len());
3906 total_attributes = 0;
3907 shader_expects_dual_source_blending = false;
3908 pipeline_expects_dual_source_blending = false;
3909 for (i, vb_state) in vertex.buffers.iter().enumerate() {
3910 if vb_state.array_stride > self.limits.max_vertex_buffer_array_stride as u64 {
3913 return Err(pipeline::CreateRenderPipelineError::VertexStrideTooLarge {
3914 index: i as u32,
3915 given: vb_state.array_stride as u32,
3916 limit: self.limits.max_vertex_buffer_array_stride,
3917 });
3918 }
3919 if vb_state.array_stride % wgt::VERTEX_ALIGNMENT != 0 {
3920 return Err(pipeline::CreateRenderPipelineError::UnalignedVertexStride {
3921 index: i as u32,
3922 stride: vb_state.array_stride,
3923 });
3924 }
3925
3926 let max_stride = if vb_state.array_stride == 0 {
3927 self.limits.max_vertex_buffer_array_stride as u64
3928 } else {
3929 vb_state.array_stride
3930 };
3931 let mut last_stride = 0;
3932 for attribute in vb_state.attributes.iter() {
3933 let attribute_stride = attribute.offset + attribute.format.size();
3934 if attribute_stride > max_stride {
3935 return Err(
3936 pipeline::CreateRenderPipelineError::VertexAttributeStrideTooLarge {
3937 location: attribute.shader_location,
3938 given: attribute_stride as u32,
3939 limit: max_stride as u32,
3940 },
3941 );
3942 }
3943
3944 let required_offset_alignment = attribute.format.size().min(4);
3945 if attribute.offset % required_offset_alignment != 0 {
3946 return Err(
3947 pipeline::CreateRenderPipelineError::InvalidVertexAttributeOffset {
3948 location: attribute.shader_location,
3949 offset: attribute.offset,
3950 },
3951 );
3952 }
3953
3954 if attribute.shader_location >= self.limits.max_vertex_attributes {
3955 return Err(
3956 pipeline::CreateRenderPipelineError::VertexAttributeLocationTooLarge {
3957 given: attribute.shader_location,
3958 limit: self.limits.max_vertex_attributes,
3959 },
3960 );
3961 }
3962
3963 last_stride = last_stride.max(attribute_stride);
3964 }
3965 vertex_steps.push(pipeline::VertexStep {
3966 stride: vb_state.array_stride,
3967 last_stride,
3968 mode: vb_state.step_mode,
3969 });
3970 if vb_state.attributes.is_empty() {
3971 continue;
3972 }
3973 vertex_buffers.push(hal::VertexBufferLayout {
3974 array_stride: vb_state.array_stride,
3975 step_mode: vb_state.step_mode,
3976 attributes: vb_state.attributes.as_ref(),
3977 });
3978
3979 for attribute in vb_state.attributes.iter() {
3980 if attribute.offset >= 0x10000000 {
3981 return Err(
3982 pipeline::CreateRenderPipelineError::InvalidVertexAttributeOffset {
3983 location: attribute.shader_location,
3984 offset: attribute.offset,
3985 },
3986 );
3987 }
3988
3989 if let wgt::VertexFormat::Float64
3990 | wgt::VertexFormat::Float64x2
3991 | wgt::VertexFormat::Float64x3
3992 | wgt::VertexFormat::Float64x4 = attribute.format
3993 {
3994 self.require_features(wgt::Features::VERTEX_ATTRIBUTE_64BIT)?;
3995 }
3996
3997 let previous = io.insert(
3998 attribute.shader_location,
3999 validation::InterfaceVar::vertex_attribute(attribute.format),
4000 );
4001
4002 if previous.is_some() {
4003 return Err(pipeline::CreateRenderPipelineError::ShaderLocationClash(
4004 attribute.shader_location,
4005 ));
4006 }
4007 }
4008 total_attributes += vb_state.attributes.len();
4009 }
4010
4011 if vertex_buffers.len() > self.limits.max_vertex_buffers as usize {
4012 return Err(pipeline::CreateRenderPipelineError::TooManyVertexBuffers {
4013 given: vertex_buffers.len() as u32,
4014 limit: self.limits.max_vertex_buffers,
4015 });
4016 }
4017 if total_attributes > self.limits.max_vertex_attributes as usize {
4018 return Err(
4019 pipeline::CreateRenderPipelineError::TooManyVertexAttributes {
4020 given: total_attributes as u32,
4021 limit: self.limits.max_vertex_attributes,
4022 },
4023 );
4024 }
4025 } else {
4026 vertex_steps = Vec::new();
4027 vertex_buffers = Vec::new();
4028 };
4029
4030 if desc.primitive.strip_index_format.is_some() && !desc.primitive.topology.is_strip() {
4031 return Err(
4032 pipeline::CreateRenderPipelineError::StripIndexFormatForNonStripTopology {
4033 strip_index_format: desc.primitive.strip_index_format,
4034 topology: desc.primitive.topology,
4035 },
4036 );
4037 }
4038
4039 if desc.primitive.unclipped_depth {
4040 self.require_features(wgt::Features::DEPTH_CLIP_CONTROL)?;
4041 }
4042
4043 if desc.primitive.polygon_mode == wgt::PolygonMode::Line {
4044 self.require_features(wgt::Features::POLYGON_MODE_LINE)?;
4045 }
4046 if desc.primitive.polygon_mode == wgt::PolygonMode::Point {
4047 self.require_features(wgt::Features::POLYGON_MODE_POINT)?;
4048 }
4049
4050 if desc.primitive.conservative {
4051 self.require_features(wgt::Features::CONSERVATIVE_RASTERIZATION)?;
4052 }
4053
4054 if desc.primitive.conservative && desc.primitive.polygon_mode != wgt::PolygonMode::Fill {
4055 return Err(
4056 pipeline::CreateRenderPipelineError::ConservativeRasterizationNonFillPolygonMode,
4057 );
4058 }
4059
4060 let mut target_specified = false;
4061
4062 for (i, cs) in color_targets.iter().enumerate() {
4063 if let Some(cs) = cs.as_ref() {
4064 target_specified = true;
4065 let error = 'error: {
4066 if cs.write_mask.contains_unknown_bits() {
4067 break 'error Some(pipeline::ColorStateError::InvalidWriteMask(
4068 cs.write_mask,
4069 ));
4070 }
4071
4072 let format_features = self.describe_format_features(cs.format)?;
4073 if !format_features
4074 .allowed_usages
4075 .contains(wgt::TextureUsages::RENDER_ATTACHMENT)
4076 {
4077 break 'error Some(pipeline::ColorStateError::FormatNotRenderable(
4078 cs.format,
4079 ));
4080 }
4081 let blendable = format_features.flags.contains(Tfff::BLENDABLE);
4082 let filterable = format_features.flags.contains(Tfff::FILTERABLE);
4083 let adapter_specific = self
4084 .features
4085 .contains(wgt::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES);
4086 if cs.blend.is_some() && (!blendable || (!filterable && !adapter_specific)) {
4091 break 'error Some(pipeline::ColorStateError::FormatNotBlendable(
4092 cs.format,
4093 ));
4094 }
4095 if !hal::FormatAspects::from(cs.format).contains(hal::FormatAspects::COLOR) {
4096 break 'error Some(pipeline::ColorStateError::FormatNotColor(cs.format));
4097 }
4098
4099 if desc.multisample.count > 1
4100 && !format_features
4101 .flags
4102 .sample_count_supported(desc.multisample.count)
4103 {
4104 break 'error Some(pipeline::ColorStateError::InvalidSampleCount(
4105 desc.multisample.count,
4106 cs.format,
4107 cs.format
4108 .guaranteed_format_features(self.features)
4109 .flags
4110 .supported_sample_counts(),
4111 self.adapter
4112 .get_texture_format_features(cs.format)
4113 .flags
4114 .supported_sample_counts(),
4115 ));
4116 }
4117
4118 if let Some(blend_mode) = cs.blend {
4119 for factor in [
4120 blend_mode.color.src_factor,
4121 blend_mode.color.dst_factor,
4122 blend_mode.alpha.src_factor,
4123 blend_mode.alpha.dst_factor,
4124 ] {
4125 if factor.ref_second_blend_source() {
4126 self.require_features(wgt::Features::DUAL_SOURCE_BLENDING)?;
4127 if i == 0 {
4128 pipeline_expects_dual_source_blending = true;
4129 break;
4130 } else {
4131 return Err(pipeline::CreateRenderPipelineError
4132 ::BlendFactorOnUnsupportedTarget { factor, target: i as u32 });
4133 }
4134 }
4135 }
4136 }
4137
4138 break 'error None;
4139 };
4140 if let Some(e) = error {
4141 return Err(pipeline::CreateRenderPipelineError::ColorState(i as u8, e));
4142 }
4143 }
4144 }
4145
4146 validation::validate_color_attachment_bytes_per_sample(
4147 color_targets.iter().flatten().map(|cs| cs.format),
4148 self.limits.max_color_attachment_bytes_per_sample,
4149 )
4150 .map_err(pipeline::CreateRenderPipelineError::ColorAttachment)?;
4151
4152 if let Some(ds) = depth_stencil_state {
4153 target_specified = true;
4154 let error = 'error: {
4155 let format_features = self.describe_format_features(ds.format)?;
4156 if !format_features
4157 .allowed_usages
4158 .contains(wgt::TextureUsages::RENDER_ATTACHMENT)
4159 {
4160 break 'error Some(pipeline::DepthStencilStateError::FormatNotRenderable(
4161 ds.format,
4162 ));
4163 }
4164
4165 let aspect = hal::FormatAspects::from(ds.format);
4166 if ds.is_depth_enabled() && !aspect.contains(hal::FormatAspects::DEPTH) {
4167 break 'error Some(pipeline::DepthStencilStateError::FormatNotDepth(ds.format));
4168 }
4169 if ds.stencil.is_enabled() && !aspect.contains(hal::FormatAspects::STENCIL) {
4170 break 'error Some(pipeline::DepthStencilStateError::FormatNotStencil(
4171 ds.format,
4172 ));
4173 }
4174 if desc.multisample.count > 1
4175 && !format_features
4176 .flags
4177 .sample_count_supported(desc.multisample.count)
4178 {
4179 break 'error Some(pipeline::DepthStencilStateError::InvalidSampleCount(
4180 desc.multisample.count,
4181 ds.format,
4182 ds.format
4183 .guaranteed_format_features(self.features)
4184 .flags
4185 .supported_sample_counts(),
4186 self.adapter
4187 .get_texture_format_features(ds.format)
4188 .flags
4189 .supported_sample_counts(),
4190 ));
4191 }
4192
4193 break 'error None;
4194 };
4195 if let Some(e) = error {
4196 return Err(pipeline::CreateRenderPipelineError::DepthStencilState(e));
4197 }
4198
4199 if ds.bias.clamp != 0.0 {
4200 self.require_downlevel_flags(wgt::DownlevelFlags::DEPTH_BIAS_CLAMP)?;
4201 }
4202 }
4203
4204 if !target_specified {
4205 return Err(pipeline::CreateRenderPipelineError::NoTargetSpecified);
4206 }
4207
4208 let is_auto_layout = desc.layout.is_none();
4209
4210 let pipeline_layout = match desc.layout {
4212 Some(pipeline_layout) => {
4213 pipeline_layout.same_device(self)?;
4214 Some(pipeline_layout)
4215 }
4216 None => None,
4217 };
4218
4219 let mut binding_layout_source = match pipeline_layout {
4220 Some(ref pipeline_layout) => {
4221 validation::BindingLayoutSource::Provided(pipeline_layout.get_binding_maps())
4222 }
4223 None => validation::BindingLayoutSource::new_derived(&self.limits),
4224 };
4225
4226 let samples = {
4227 let sc = desc.multisample.count;
4228 if sc == 0 || sc > 32 || !sc.is_power_of_two() {
4229 return Err(pipeline::CreateRenderPipelineError::InvalidSampleCount(sc));
4230 }
4231 sc
4232 };
4233
4234 let mut vertex_stage = None;
4235 let mut task_stage = None;
4236 let mut mesh_stage = None;
4237 let mut _vertex_entry_point_name = String::new();
4238 let mut _task_entry_point_name = String::new();
4239 let mut _mesh_entry_point_name = String::new();
4240 match desc.vertex {
4241 pipeline::RenderPipelineVertexProcessor::Vertex(ref vertex) => {
4242 vertex_stage = {
4243 let stage_desc = &vertex.stage;
4244 let stage = wgt::ShaderStages::VERTEX;
4245
4246 let vertex_shader_module = &stage_desc.module;
4247 vertex_shader_module.same_device(self)?;
4248
4249 let stage_err =
4250 |error| pipeline::CreateRenderPipelineError::Stage { stage, error };
4251
4252 _vertex_entry_point_name = vertex_shader_module
4253 .finalize_entry_point_name(
4254 stage,
4255 stage_desc.entry_point.as_ref().map(|ep| ep.as_ref()),
4256 )
4257 .map_err(stage_err)?;
4258
4259 if let Some(ref interface) = vertex_shader_module.interface {
4260 io = interface
4261 .check_stage(
4262 &mut binding_layout_source,
4263 &mut shader_binding_sizes,
4264 &_vertex_entry_point_name,
4265 stage,
4266 io,
4267 desc.depth_stencil.as_ref().map(|d| d.depth_compare),
4268 )
4269 .map_err(stage_err)?;
4270 validated_stages |= stage;
4271 }
4272 Some(hal::ProgrammableStage {
4273 module: vertex_shader_module.raw(),
4274 entry_point: &_vertex_entry_point_name,
4275 constants: &stage_desc.constants,
4276 zero_initialize_workgroup_memory: stage_desc
4277 .zero_initialize_workgroup_memory,
4278 })
4279 };
4280 }
4281 pipeline::RenderPipelineVertexProcessor::Mesh(ref task, ref mesh) => {
4282 self.require_features(wgt::Features::EXPERIMENTAL_MESH_SHADER)?;
4283
4284 task_stage = if let Some(task) = task {
4285 let stage_desc = &task.stage;
4286 let stage = wgt::ShaderStages::TASK;
4287 let task_shader_module = &stage_desc.module;
4288 task_shader_module.same_device(self)?;
4289
4290 let stage_err =
4291 |error| pipeline::CreateRenderPipelineError::Stage { stage, error };
4292
4293 _task_entry_point_name = task_shader_module
4294 .finalize_entry_point_name(
4295 stage,
4296 stage_desc.entry_point.as_ref().map(|ep| ep.as_ref()),
4297 )
4298 .map_err(stage_err)?;
4299
4300 if let Some(ref interface) = task_shader_module.interface {
4301 io = interface
4302 .check_stage(
4303 &mut binding_layout_source,
4304 &mut shader_binding_sizes,
4305 &_task_entry_point_name,
4306 stage,
4307 io,
4308 desc.depth_stencil.as_ref().map(|d| d.depth_compare),
4309 )
4310 .map_err(stage_err)?;
4311 validated_stages |= stage;
4312 }
4313 Some(hal::ProgrammableStage {
4314 module: task_shader_module.raw(),
4315 entry_point: &_task_entry_point_name,
4316 constants: &stage_desc.constants,
4317 zero_initialize_workgroup_memory: stage_desc
4318 .zero_initialize_workgroup_memory,
4319 })
4320 } else {
4321 None
4322 };
4323 mesh_stage = {
4324 let stage_desc = &mesh.stage;
4325 let stage = wgt::ShaderStages::MESH;
4326 let mesh_shader_module = &stage_desc.module;
4327 mesh_shader_module.same_device(self)?;
4328
4329 let stage_err =
4330 |error| pipeline::CreateRenderPipelineError::Stage { stage, error };
4331
4332 _mesh_entry_point_name = mesh_shader_module
4333 .finalize_entry_point_name(
4334 stage,
4335 stage_desc.entry_point.as_ref().map(|ep| ep.as_ref()),
4336 )
4337 .map_err(stage_err)?;
4338
4339 if let Some(ref interface) = mesh_shader_module.interface {
4340 io = interface
4341 .check_stage(
4342 &mut binding_layout_source,
4343 &mut shader_binding_sizes,
4344 &_mesh_entry_point_name,
4345 stage,
4346 io,
4347 desc.depth_stencil.as_ref().map(|d| d.depth_compare),
4348 )
4349 .map_err(stage_err)?;
4350 validated_stages |= stage;
4351 }
4352 Some(hal::ProgrammableStage {
4353 module: mesh_shader_module.raw(),
4354 entry_point: &_mesh_entry_point_name,
4355 constants: &stage_desc.constants,
4356 zero_initialize_workgroup_memory: stage_desc
4357 .zero_initialize_workgroup_memory,
4358 })
4359 };
4360 }
4361 }
4362
4363 let fragment_entry_point_name;
4364 let fragment_stage = match desc.fragment {
4365 Some(ref fragment_state) => {
4366 let stage = wgt::ShaderStages::FRAGMENT;
4367
4368 let shader_module = &fragment_state.stage.module;
4369 shader_module.same_device(self)?;
4370
4371 let stage_err = |error| pipeline::CreateRenderPipelineError::Stage { stage, error };
4372
4373 fragment_entry_point_name = shader_module
4374 .finalize_entry_point_name(
4375 stage,
4376 fragment_state
4377 .stage
4378 .entry_point
4379 .as_ref()
4380 .map(|ep| ep.as_ref()),
4381 )
4382 .map_err(stage_err)?;
4383
4384 if validated_stages == wgt::ShaderStages::VERTEX {
4385 if let Some(ref interface) = shader_module.interface {
4386 io = interface
4387 .check_stage(
4388 &mut binding_layout_source,
4389 &mut shader_binding_sizes,
4390 &fragment_entry_point_name,
4391 stage,
4392 io,
4393 desc.depth_stencil.as_ref().map(|d| d.depth_compare),
4394 )
4395 .map_err(stage_err)?;
4396 validated_stages |= stage;
4397 }
4398 }
4399
4400 if let Some(ref interface) = shader_module.interface {
4401 shader_expects_dual_source_blending = interface
4402 .fragment_uses_dual_source_blending(&fragment_entry_point_name)
4403 .map_err(|error| pipeline::CreateRenderPipelineError::Stage {
4404 stage,
4405 error,
4406 })?;
4407 }
4408
4409 Some(hal::ProgrammableStage {
4410 module: shader_module.raw(),
4411 entry_point: &fragment_entry_point_name,
4412 constants: &fragment_state.stage.constants,
4413 zero_initialize_workgroup_memory: fragment_state
4414 .stage
4415 .zero_initialize_workgroup_memory,
4416 })
4417 }
4418 None => None,
4419 };
4420
4421 if !pipeline_expects_dual_source_blending && shader_expects_dual_source_blending {
4422 return Err(
4423 pipeline::CreateRenderPipelineError::ShaderExpectsPipelineToUseDualSourceBlending,
4424 );
4425 }
4426 if pipeline_expects_dual_source_blending && !shader_expects_dual_source_blending {
4427 return Err(
4428 pipeline::CreateRenderPipelineError::PipelineExpectsShaderToUseDualSourceBlending,
4429 );
4430 }
4431
4432 if validated_stages.contains(wgt::ShaderStages::FRAGMENT) {
4433 for (i, output) in io.iter() {
4434 match color_targets.get(*i as usize) {
4435 Some(Some(state)) => {
4436 validation::check_texture_format(state.format, &output.ty).map_err(
4437 |pipeline| {
4438 pipeline::CreateRenderPipelineError::ColorState(
4439 *i as u8,
4440 pipeline::ColorStateError::IncompatibleFormat {
4441 pipeline,
4442 shader: output.ty,
4443 },
4444 )
4445 },
4446 )?;
4447 }
4448 _ => {
4449 log::debug!(
4450 "The fragment stage {:?} output @location({}) values are ignored",
4451 fragment_stage
4452 .as_ref()
4453 .map_or("", |stage| stage.entry_point),
4454 i
4455 );
4456 }
4457 }
4458 }
4459 }
4460 let last_stage = match desc.fragment {
4461 Some(_) => wgt::ShaderStages::FRAGMENT,
4462 None => wgt::ShaderStages::VERTEX,
4463 };
4464 if is_auto_layout && !validated_stages.contains(last_stage) {
4465 return Err(pipeline::ImplicitLayoutError::ReflectionError(last_stage).into());
4466 }
4467
4468 let pipeline_layout = match binding_layout_source {
4469 validation::BindingLayoutSource::Provided(_) => {
4470 drop(binding_layout_source);
4471 pipeline_layout.unwrap()
4472 }
4473 validation::BindingLayoutSource::Derived(entries) => {
4474 self.derive_pipeline_layout(entries)?
4475 }
4476 };
4477
4478 if let Some(mv_mask) = desc.multiview_mask {
4480 self.require_features(wgt::Features::MULTIVIEW)?;
4481 if !(mv_mask.get() + 1).is_power_of_two() {
4482 self.require_features(wgt::Features::SELECTIVE_MULTIVIEW)?;
4483 }
4484 }
4485
4486 if !self
4487 .downlevel
4488 .flags
4489 .contains(wgt::DownlevelFlags::BUFFER_BINDINGS_NOT_16_BYTE_ALIGNED)
4490 {
4491 for (binding, size) in shader_binding_sizes.iter() {
4492 if size.get() % 16 != 0 {
4493 return Err(pipeline::CreateRenderPipelineError::UnalignedShader {
4494 binding: binding.binding,
4495 group: binding.group,
4496 size: size.get(),
4497 });
4498 }
4499 }
4500 }
4501
4502 let late_sized_buffer_groups =
4503 Device::make_late_sized_buffer_groups(&shader_binding_sizes, &pipeline_layout);
4504
4505 let cache = match desc.cache {
4506 Some(cache) => {
4507 cache.same_device(self)?;
4508 Some(cache)
4509 }
4510 None => None,
4511 };
4512
4513 let is_mesh = mesh_stage.is_some();
4514 let raw = {
4515 let pipeline_desc = hal::RenderPipelineDescriptor {
4516 label: desc.label.to_hal(self.instance_flags),
4517 layout: pipeline_layout.raw(),
4518 vertex_processor: match vertex_stage {
4519 Some(vertex_stage) => hal::VertexProcessor::Standard {
4520 vertex_buffers: &vertex_buffers,
4521 vertex_stage,
4522 },
4523 None => hal::VertexProcessor::Mesh {
4524 task_stage,
4525 mesh_stage: mesh_stage.unwrap(),
4526 },
4527 },
4528 primitive: desc.primitive,
4529 depth_stencil: desc.depth_stencil.clone(),
4530 multisample: desc.multisample,
4531 fragment_stage,
4532 color_targets,
4533 multiview_mask: desc.multiview_mask,
4534 cache: cache.as_ref().map(|it| it.raw()),
4535 };
4536 unsafe { self.raw().create_render_pipeline(&pipeline_desc) }.map_err(
4537 |err| match err {
4538 hal::PipelineError::Device(error) => {
4539 pipeline::CreateRenderPipelineError::Device(self.handle_hal_error(error))
4540 }
4541 hal::PipelineError::Linkage(stage, msg) => {
4542 pipeline::CreateRenderPipelineError::Internal { stage, error: msg }
4543 }
4544 hal::PipelineError::EntryPoint(stage) => {
4545 pipeline::CreateRenderPipelineError::Internal {
4546 stage: hal::auxil::map_naga_stage(stage),
4547 error: ENTRYPOINT_FAILURE_ERROR.to_string(),
4548 }
4549 }
4550 hal::PipelineError::PipelineConstants(stage, error) => {
4551 pipeline::CreateRenderPipelineError::PipelineConstants { stage, error }
4552 }
4553 },
4554 )?
4555 };
4556
4557 let pass_context = RenderPassContext {
4558 attachments: AttachmentData {
4559 colors: color_targets
4560 .iter()
4561 .map(|state| state.as_ref().map(|s| s.format))
4562 .collect(),
4563 resolves: ArrayVec::new(),
4564 depth_stencil: depth_stencil_state.as_ref().map(|state| state.format),
4565 },
4566 sample_count: samples,
4567 multiview_mask: desc.multiview_mask,
4568 };
4569
4570 let mut flags = pipeline::PipelineFlags::empty();
4571 for state in color_targets.iter().filter_map(|s| s.as_ref()) {
4572 if let Some(ref bs) = state.blend {
4573 if bs.color.uses_constant() | bs.alpha.uses_constant() {
4574 flags |= pipeline::PipelineFlags::BLEND_CONSTANT;
4575 }
4576 }
4577 }
4578 if let Some(ds) = depth_stencil_state.as_ref() {
4579 if ds.stencil.is_enabled() && ds.stencil.needs_ref_value() {
4580 flags |= pipeline::PipelineFlags::STENCIL_REFERENCE;
4581 }
4582 if !ds.is_depth_read_only() {
4583 flags |= pipeline::PipelineFlags::WRITES_DEPTH;
4584 }
4585 if !ds.is_stencil_read_only(desc.primitive.cull_mode) {
4586 flags |= pipeline::PipelineFlags::WRITES_STENCIL;
4587 }
4588 }
4589 let shader_modules = {
4590 let mut shader_modules = ArrayVec::new();
4591 match desc.vertex {
4592 pipeline::RenderPipelineVertexProcessor::Vertex(vertex) => {
4593 shader_modules.push(vertex.stage.module)
4594 }
4595 pipeline::RenderPipelineVertexProcessor::Mesh(task, mesh) => {
4596 if let Some(task) = task {
4597 shader_modules.push(task.stage.module);
4598 }
4599 shader_modules.push(mesh.stage.module);
4600 }
4601 }
4602 shader_modules.extend(desc.fragment.map(|f| f.stage.module));
4603 shader_modules
4604 };
4605
4606 let pipeline = pipeline::RenderPipeline {
4607 raw: ManuallyDrop::new(raw),
4608 layout: pipeline_layout,
4609 device: self.clone(),
4610 pass_context,
4611 _shader_modules: shader_modules,
4612 flags,
4613 strip_index_format: desc.primitive.strip_index_format,
4614 vertex_steps,
4615 late_sized_buffer_groups,
4616 label: desc.label.to_string(),
4617 tracking_data: TrackingData::new(self.tracker_indices.render_pipelines.clone()),
4618 is_mesh,
4619 };
4620
4621 let pipeline = Arc::new(pipeline);
4622
4623 if is_auto_layout {
4624 for bgl in pipeline.layout.bind_group_layouts.iter() {
4625 let _ = bgl
4627 .exclusive_pipeline
4628 .set(binding_model::ExclusivePipeline::Render(Arc::downgrade(
4629 &pipeline,
4630 )));
4631 }
4632 }
4633
4634 Ok(pipeline)
4635 }
4636
4637 pub unsafe fn create_pipeline_cache(
4640 self: &Arc<Self>,
4641 desc: &pipeline::PipelineCacheDescriptor,
4642 ) -> Result<Arc<pipeline::PipelineCache>, pipeline::CreatePipelineCacheError> {
4643 use crate::pipeline_cache;
4644
4645 self.check_is_valid()?;
4646
4647 self.require_features(wgt::Features::PIPELINE_CACHE)?;
4648 let data = if let Some((data, validation_key)) = desc
4649 .data
4650 .as_ref()
4651 .zip(self.raw().pipeline_cache_validation_key())
4652 {
4653 let data = pipeline_cache::validate_pipeline_cache(
4654 data,
4655 &self.adapter.raw.info,
4656 validation_key,
4657 );
4658 match data {
4659 Ok(data) => Some(data),
4660 Err(e) if e.was_avoidable() || !desc.fallback => return Err(e.into()),
4661 Err(_) => None,
4663 }
4664 } else {
4665 None
4666 };
4667 let cache_desc = hal::PipelineCacheDescriptor {
4668 data,
4669 label: desc.label.to_hal(self.instance_flags),
4670 };
4671 let raw = match unsafe { self.raw().create_pipeline_cache(&cache_desc) } {
4672 Ok(raw) => raw,
4673 Err(e) => match e {
4674 hal::PipelineCacheError::Device(e) => return Err(self.handle_hal_error(e).into()),
4675 },
4676 };
4677 let cache = pipeline::PipelineCache {
4678 device: self.clone(),
4679 label: desc.label.to_string(),
4680 raw: ManuallyDrop::new(raw),
4682 };
4683
4684 let cache = Arc::new(cache);
4685
4686 Ok(cache)
4687 }
4688
4689 fn get_texture_format_features(&self, format: TextureFormat) -> wgt::TextureFormatFeatures {
4690 use wgt::TextureFormatFeatureFlags as tfsc;
4692 let mut format_features = self.adapter.get_texture_format_features(format);
4693 if (format == TextureFormat::R32Float
4694 || format == TextureFormat::Rg32Float
4695 || format == TextureFormat::Rgba32Float)
4696 && !self.features.contains(wgt::Features::FLOAT32_FILTERABLE)
4697 {
4698 format_features.flags.set(tfsc::FILTERABLE, false);
4699 }
4700 format_features
4701 }
4702
4703 fn describe_format_features(
4704 &self,
4705 format: TextureFormat,
4706 ) -> Result<wgt::TextureFormatFeatures, MissingFeatures> {
4707 self.require_features(format.required_features())?;
4708
4709 let using_device_features = self
4710 .features
4711 .contains(wgt::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES);
4712 let downlevel = !self
4715 .downlevel
4716 .flags
4717 .contains(wgt::DownlevelFlags::WEBGPU_TEXTURE_FORMAT_SUPPORT);
4718
4719 if using_device_features || downlevel {
4720 Ok(self.get_texture_format_features(format))
4721 } else {
4722 Ok(format.guaranteed_format_features(self.features))
4723 }
4724 }
4725
4726 #[cfg(feature = "replay")]
4727 pub(crate) fn wait_for_submit(
4728 &self,
4729 submission_index: crate::SubmissionIndex,
4730 ) -> Result<(), DeviceError> {
4731 let fence = self.fence.read();
4732 let last_done_index = unsafe { self.raw().get_fence_value(fence.as_ref()) }
4733 .map_err(|e| self.handle_hal_error(e))?;
4734 if last_done_index < submission_index {
4735 unsafe { self.raw().wait(fence.as_ref(), submission_index, None) }
4736 .map_err(|e| self.handle_hal_error(e))?;
4737 drop(fence);
4738 if let Some(queue) = self.get_queue() {
4739 let closures = queue.lock_life().triage_submissions(submission_index);
4740 assert!(
4741 closures.is_empty(),
4742 "wait_for_submit is not expected to work with closures"
4743 );
4744 }
4745 }
4746 Ok(())
4747 }
4748
4749 pub fn create_query_set(
4750 self: &Arc<Self>,
4751 desc: &resource::QuerySetDescriptor,
4752 ) -> Result<Arc<QuerySet>, resource::CreateQuerySetError> {
4753 use resource::CreateQuerySetError as Error;
4754
4755 self.check_is_valid()?;
4756
4757 match desc.ty {
4758 wgt::QueryType::Occlusion => {}
4759 wgt::QueryType::Timestamp => {
4760 self.require_features(wgt::Features::TIMESTAMP_QUERY)?;
4761 }
4762 wgt::QueryType::PipelineStatistics(..) => {
4763 self.require_features(wgt::Features::PIPELINE_STATISTICS_QUERY)?;
4764 }
4765 }
4766
4767 if desc.count == 0 {
4768 return Err(Error::ZeroCount);
4769 }
4770
4771 if desc.count > wgt::QUERY_SET_MAX_QUERIES {
4772 return Err(Error::TooManyQueries {
4773 count: desc.count,
4774 maximum: wgt::QUERY_SET_MAX_QUERIES,
4775 });
4776 }
4777
4778 let hal_desc = desc.map_label(|label| label.to_hal(self.instance_flags));
4779
4780 let raw = unsafe { self.raw().create_query_set(&hal_desc) }
4781 .map_err(|e| self.handle_hal_error_with_nonfatal_oom(e))?;
4782
4783 let query_set = QuerySet {
4784 raw: ManuallyDrop::new(raw),
4785 device: self.clone(),
4786 label: desc.label.to_string(),
4787 tracking_data: TrackingData::new(self.tracker_indices.query_sets.clone()),
4788 desc: desc.map_label(|_| ()),
4789 };
4790
4791 let query_set = Arc::new(query_set);
4792
4793 Ok(query_set)
4794 }
4795
4796 pub fn configure_surface(
4797 self: &Arc<Self>,
4798 surface: &crate::instance::Surface,
4799 config: &wgt::SurfaceConfiguration<Vec<TextureFormat>>,
4800 ) -> Option<present::ConfigureSurfaceError> {
4801 use present::ConfigureSurfaceError as E;
4802 profiling::scope!("surface_configure");
4803
4804 fn validate_surface_configuration(
4805 config: &mut hal::SurfaceConfiguration,
4806 caps: &hal::SurfaceCapabilities,
4807 max_texture_dimension_2d: u32,
4808 ) -> Result<(), E> {
4809 let width = config.extent.width;
4810 let height = config.extent.height;
4811
4812 if width > max_texture_dimension_2d || height > max_texture_dimension_2d {
4813 return Err(E::TooLarge {
4814 width,
4815 height,
4816 max_texture_dimension_2d,
4817 });
4818 }
4819
4820 if !caps.present_modes.contains(&config.present_mode) {
4821 let fallbacks = match config.present_mode {
4825 wgt::PresentMode::AutoVsync => {
4826 &[wgt::PresentMode::FifoRelaxed, wgt::PresentMode::Fifo][..]
4827 }
4828 wgt::PresentMode::AutoNoVsync => &[
4830 wgt::PresentMode::Immediate,
4831 wgt::PresentMode::Mailbox,
4832 wgt::PresentMode::Fifo,
4833 ][..],
4834 _ => {
4835 return Err(E::UnsupportedPresentMode {
4836 requested: config.present_mode,
4837 available: caps.present_modes.clone(),
4838 });
4839 }
4840 };
4841
4842 let new_mode = fallbacks
4843 .iter()
4844 .copied()
4845 .find(|fallback| caps.present_modes.contains(fallback))
4846 .unwrap_or_else(|| {
4847 unreachable!(
4848 "Fallback system failed to choose present mode. \
4849 This is a bug. Mode: {:?}, Options: {:?}",
4850 config.present_mode, &caps.present_modes
4851 );
4852 });
4853
4854 api_log!(
4855 "Automatically choosing presentation mode by rule {:?}. Chose {new_mode:?}",
4856 config.present_mode
4857 );
4858 config.present_mode = new_mode;
4859 }
4860 if !caps.formats.contains(&config.format) {
4861 return Err(E::UnsupportedFormat {
4862 requested: config.format,
4863 available: caps.formats.clone(),
4864 });
4865 }
4866 if !caps
4867 .composite_alpha_modes
4868 .contains(&config.composite_alpha_mode)
4869 {
4870 let new_alpha_mode = 'alpha: {
4871 let fallbacks = match config.composite_alpha_mode {
4873 wgt::CompositeAlphaMode::Auto => &[
4874 wgt::CompositeAlphaMode::Opaque,
4875 wgt::CompositeAlphaMode::Inherit,
4876 ][..],
4877 _ => {
4878 return Err(E::UnsupportedAlphaMode {
4879 requested: config.composite_alpha_mode,
4880 available: caps.composite_alpha_modes.clone(),
4881 });
4882 }
4883 };
4884
4885 for &fallback in fallbacks {
4886 if caps.composite_alpha_modes.contains(&fallback) {
4887 break 'alpha fallback;
4888 }
4889 }
4890
4891 unreachable!(
4892 "Fallback system failed to choose alpha mode. This is a bug. \
4893 AlphaMode: {:?}, Options: {:?}",
4894 config.composite_alpha_mode, &caps.composite_alpha_modes
4895 );
4896 };
4897
4898 api_log!(
4899 "Automatically choosing alpha mode by rule {:?}. Chose {new_alpha_mode:?}",
4900 config.composite_alpha_mode
4901 );
4902 config.composite_alpha_mode = new_alpha_mode;
4903 }
4904 if !caps.usage.contains(config.usage) {
4905 return Err(E::UnsupportedUsage {
4906 requested: config.usage,
4907 available: caps.usage,
4908 });
4909 }
4910 if width == 0 || height == 0 {
4911 return Err(E::ZeroArea);
4912 }
4913 Ok(())
4914 }
4915
4916 log::debug!("configuring surface with {config:?}");
4917
4918 let error = 'error: {
4919 let user_callbacks;
4921 {
4922 if let Err(e) = self.check_is_valid() {
4923 break 'error e.into();
4924 }
4925
4926 let caps = match surface.get_capabilities(&self.adapter) {
4927 Ok(caps) => caps,
4928 Err(_) => break 'error E::UnsupportedQueueFamily,
4929 };
4930
4931 let mut hal_view_formats = Vec::new();
4932 for format in config.view_formats.iter() {
4933 if *format == config.format {
4934 continue;
4935 }
4936 if !caps.formats.contains(&config.format) {
4937 break 'error E::UnsupportedFormat {
4938 requested: config.format,
4939 available: caps.formats,
4940 };
4941 }
4942 if config.format.remove_srgb_suffix() != format.remove_srgb_suffix() {
4943 break 'error E::InvalidViewFormat(*format, config.format);
4944 }
4945 hal_view_formats.push(*format);
4946 }
4947
4948 if !hal_view_formats.is_empty() {
4949 if let Err(missing_flag) =
4950 self.require_downlevel_flags(wgt::DownlevelFlags::SURFACE_VIEW_FORMATS)
4951 {
4952 break 'error E::MissingDownlevelFlags(missing_flag);
4953 }
4954 }
4955
4956 let maximum_frame_latency = config.desired_maximum_frame_latency.clamp(
4957 *caps.maximum_frame_latency.start(),
4958 *caps.maximum_frame_latency.end(),
4959 );
4960 let mut hal_config = hal::SurfaceConfiguration {
4961 maximum_frame_latency,
4962 present_mode: config.present_mode,
4963 composite_alpha_mode: config.alpha_mode,
4964 format: config.format,
4965 extent: wgt::Extent3d {
4966 width: config.width,
4967 height: config.height,
4968 depth_or_array_layers: 1,
4969 },
4970 usage: conv::map_texture_usage(
4971 config.usage,
4972 hal::FormatAspects::COLOR,
4973 wgt::TextureFormatFeatureFlags::STORAGE_READ_ONLY
4974 | wgt::TextureFormatFeatureFlags::STORAGE_WRITE_ONLY
4975 | wgt::TextureFormatFeatureFlags::STORAGE_READ_WRITE,
4976 ),
4977 view_formats: hal_view_formats,
4978 };
4979
4980 if let Err(error) = validate_surface_configuration(
4981 &mut hal_config,
4982 &caps,
4983 self.limits.max_texture_dimension_2d,
4984 ) {
4985 break 'error error;
4986 }
4987
4988 let snatch_guard = self.snatchable_lock.read();
4990 let fence = self.fence.read();
4991
4992 let maintain_result;
4993 (user_callbacks, maintain_result) =
4994 self.maintain(fence, wgt::PollType::wait_indefinitely(), snatch_guard);
4995
4996 match maintain_result {
4997 Ok(wgt::PollStatus::QueueEmpty) => {}
4999 Ok(wgt::PollStatus::WaitSucceeded) => {
5000 break 'error E::GpuWaitTimeout;
5003 }
5004 Ok(wgt::PollStatus::Poll) => {
5005 unreachable!("Cannot get a Poll result from a Wait action.")
5006 }
5007 Err(WaitIdleError::Timeout) if cfg!(target_arch = "wasm32") => {
5008 }
5012 Err(e) => {
5013 break 'error e.into();
5014 }
5015 }
5016
5017 if let Some(present) = surface.presentation.lock().take() {
5019 if present.acquired_texture.is_some() {
5020 break 'error E::PreviousOutputExists;
5021 }
5022 }
5023
5024 let surface_raw = surface.raw(self.backend()).unwrap();
5031 match unsafe { surface_raw.configure(self.raw(), &hal_config) } {
5032 Ok(()) => (),
5033 Err(error) => {
5034 break 'error match error {
5035 hal::SurfaceError::Outdated | hal::SurfaceError::Lost => {
5036 E::InvalidSurface
5037 }
5038 hal::SurfaceError::Device(error) => {
5039 E::Device(self.handle_hal_error(error))
5040 }
5041 hal::SurfaceError::Other(message) => {
5042 log::error!("surface configuration failed: {message}");
5043 E::InvalidSurface
5044 }
5045 }
5046 }
5047 }
5048
5049 let mut presentation = surface.presentation.lock();
5050 *presentation = Some(present::Presentation {
5051 device: Arc::clone(self),
5052 config: config.clone(),
5053 acquired_texture: None,
5054 });
5055 }
5056
5057 user_callbacks.fire();
5058 return None;
5059 };
5060
5061 Some(error)
5062 }
5063
5064 fn lose(&self, message: &str) {
5065 self.valid.store(false, Ordering::Release);
5070
5071 if let Some(device_lost_closure) = self.device_lost_closure.lock().take() {
5073 device_lost_closure(DeviceLostReason::Unknown, message.to_string());
5074 }
5075
5076 }
5084
5085 fn release_gpu_resources(&self) {
5086 let trackers = self.trackers.lock();
5096 for buffer in trackers.buffers.used_resources() {
5097 if let Some(buffer) = Weak::upgrade(buffer) {
5098 buffer.destroy();
5099 }
5100 }
5101 for texture in trackers.textures.used_resources() {
5102 if let Some(texture) = Weak::upgrade(texture) {
5103 texture.destroy();
5104 }
5105 }
5106 }
5107
5108 pub(crate) fn new_usage_scope(&self) -> UsageScope<'_> {
5109 UsageScope::new_pooled(&self.usage_scopes, &self.tracker_indices)
5110 }
5111
5112 pub fn get_hal_counters(&self) -> wgt::HalCounters {
5113 self.raw().get_internal_counters()
5114 }
5115
5116 pub fn generate_allocator_report(&self) -> Option<wgt::AllocatorReport> {
5117 self.raw().generate_allocator_report()
5118 }
5119}
5120
5121crate::impl_resource_type!(Device);
5122crate::impl_labeled!(Device);
5123crate::impl_storage_item!(Device);