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