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