1#[cfg(feature = "trace")]
2use crate::device::trace;
3use crate::{
4 binding_model::{self, BindGroup, BindGroupLayout, BindGroupLayoutEntryError},
5 command, conv,
6 device::{
7 bgl, create_validator,
8 life::{LifetimeTracker, WaitIdleError},
9 map_buffer,
10 queue::PendingWrites,
11 AttachmentData, DeviceLostInvocation, HostMap, MissingDownlevelFlags, MissingFeatures,
12 RenderPassContext, CLEANUP_WAIT_MS,
13 },
14 hal_label,
15 init_tracker::{
16 BufferInitTracker, BufferInitTrackerAction, MemoryInitKind, TextureInitRange,
17 TextureInitTrackerAction,
18 },
19 instance::Adapter,
20 lock::{rank, Mutex, MutexGuard, RwLock},
21 pipeline,
22 pool::ResourcePool,
23 resource::{
24 self, Buffer, Fallible, Labeled, ParentDevice, QuerySet, Sampler, StagingBuffer, Texture,
25 TextureView, TextureViewNotRenderableReason, TrackingData,
26 },
27 resource_log,
28 snatch::{SnatchGuard, SnatchLock, Snatchable},
29 track::{
30 BindGroupStates, DeviceTracker, TextureSelector, TrackerIndexAllocators, UsageScope,
31 UsageScopePool,
32 },
33 validation::{self, validate_color_attachment_bytes_per_sample},
34 weak_vec::WeakVec,
35 FastHashMap, LabelHelpers, PreHashedKey, PreHashedMap,
36};
37
38use arrayvec::ArrayVec;
39use smallvec::SmallVec;
40use wgt::{
41 math::align_to, DeviceLostReason, TextureFormat, TextureSampleType, TextureViewDimension,
42};
43
44use std::{
45 borrow::Cow,
46 mem::{self, ManuallyDrop},
47 num::NonZeroU32,
48 sync::{
49 atomic::{AtomicBool, AtomicU64, Ordering},
50 Arc, OnceLock, Weak,
51 },
52};
53
54use super::{
55 queue::Queue, DeviceDescriptor, DeviceError, UserClosures, ENTRYPOINT_FAILURE_ERROR,
56 ZERO_BUFFER_SIZE,
57};
58
59pub struct Device {
80 raw: ManuallyDrop<Box<dyn hal::DynDevice>>,
81 pub(crate) adapter: Arc<Adapter>,
82 pub(crate) queue: OnceLock<Weak<Queue>>,
83 queue_to_drop: OnceLock<Box<dyn hal::DynQueue>>,
84 pub(crate) zero_buffer: ManuallyDrop<Box<dyn hal::DynBuffer>>,
85 label: String,
87
88 pub(crate) command_allocator: command::CommandAllocator,
89
90 pub(crate) active_submission_index: hal::AtomicFenceValue,
98
99 pub(crate) last_successful_submission_index: hal::AtomicFenceValue,
109
110 pub(crate) fence: RwLock<ManuallyDrop<Box<dyn hal::DynFence>>>,
113 pub(crate) snatchable_lock: SnatchLock,
114
115 pub(crate) valid: AtomicBool,
127
128 pub(crate) trackers: Mutex<DeviceTracker>,
133 pub(crate) tracker_indices: TrackerIndexAllocators,
134 life_tracker: Mutex<LifetimeTracker>,
136 pub(crate) bgl_pool: ResourcePool<bgl::EntryMap, BindGroupLayout>,
138 pub(crate) alignments: hal::Alignments,
139 pub(crate) limits: wgt::Limits,
140 pub(crate) features: wgt::Features,
141 pub(crate) downlevel: wgt::DownlevelCapabilities,
142 pub(crate) instance_flags: wgt::InstanceFlags,
143 pub(crate) pending_writes: Mutex<ManuallyDrop<PendingWrites>>,
144 pub(crate) deferred_destroy: Mutex<Vec<DeferredDestroy>>,
145 #[cfg(feature = "trace")]
146 pub(crate) trace: Mutex<Option<trace::Trace>>,
147 pub(crate) usage_scopes: UsageScopePool,
148
149 #[cfg(feature = "indirect-validation")]
150 pub(crate) indirect_validation: Option<crate::indirect_validation::IndirectValidation>,
151}
152
153pub(crate) enum DeferredDestroy {
154 TextureViews(WeakVec<TextureView>),
155 BindGroups(WeakVec<BindGroup>),
156}
157
158impl std::fmt::Debug for Device {
159 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
160 f.debug_struct("Device")
161 .field("label", &self.label())
162 .field("limits", &self.limits)
163 .field("features", &self.features)
164 .field("downlevel", &self.downlevel)
165 .finish()
166 }
167}
168
169impl Drop for Device {
170 fn drop(&mut self) {
171 resource_log!("Drop {}", self.error_ident());
172 let raw = unsafe { ManuallyDrop::take(&mut self.raw) };
174 let zero_buffer = unsafe { ManuallyDrop::take(&mut self.zero_buffer) };
176 let pending_writes = unsafe { ManuallyDrop::take(&mut self.pending_writes.lock()) };
178 let fence = unsafe { ManuallyDrop::take(&mut self.fence.write()) };
180 pending_writes.dispose(raw.as_ref());
181 self.command_allocator.dispose(raw.as_ref());
182 #[cfg(feature = "indirect-validation")]
183 self.indirect_validation
184 .take()
185 .unwrap()
186 .dispose(raw.as_ref());
187 unsafe {
188 raw.destroy_buffer(zero_buffer);
189 raw.destroy_fence(fence);
190 let queue = self.queue_to_drop.take().unwrap();
191 raw.exit(queue);
192 }
193 }
194}
195
196impl Device {
197 pub(crate) fn raw(&self) -> &dyn hal::DynDevice {
198 self.raw.as_ref()
199 }
200 pub(crate) fn require_features(&self, feature: wgt::Features) -> Result<(), MissingFeatures> {
201 if self.features.contains(feature) {
202 Ok(())
203 } else {
204 Err(MissingFeatures(feature))
205 }
206 }
207
208 pub(crate) fn require_downlevel_flags(
209 &self,
210 flags: wgt::DownlevelFlags,
211 ) -> Result<(), MissingDownlevelFlags> {
212 if self.downlevel.flags.contains(flags) {
213 Ok(())
214 } else {
215 Err(MissingDownlevelFlags(flags))
216 }
217 }
218}
219
220impl Device {
221 pub(crate) fn new(
222 raw_device: Box<dyn hal::DynDevice>,
223 raw_queue: &dyn hal::DynQueue,
224 adapter: &Arc<Adapter>,
225 desc: &DeviceDescriptor,
226 trace_path: Option<&std::path::Path>,
227 instance_flags: wgt::InstanceFlags,
228 ) -> Result<Self, DeviceError> {
229 #[cfg(not(feature = "trace"))]
230 if let Some(_) = trace_path {
231 log::error!("Feature 'trace' is not enabled");
232 }
233 let fence = unsafe { raw_device.create_fence() }.map_err(DeviceError::from_hal)?;
234
235 let command_allocator = command::CommandAllocator::new();
236 let pending_encoder = command_allocator
237 .acquire_encoder(raw_device.as_ref(), raw_queue)
238 .map_err(DeviceError::from_hal)?;
239 let mut pending_writes = PendingWrites::new(pending_encoder);
240
241 let zero_buffer = unsafe {
243 raw_device.create_buffer(&hal::BufferDescriptor {
244 label: hal_label(Some("(wgpu internal) zero init buffer"), instance_flags),
245 size: ZERO_BUFFER_SIZE,
246 usage: hal::BufferUses::COPY_SRC | hal::BufferUses::COPY_DST,
247 memory_flags: hal::MemoryFlags::empty(),
248 })
249 }
250 .map_err(DeviceError::from_hal)?;
251 pending_writes.activate();
252 unsafe {
253 pending_writes
254 .command_encoder
255 .transition_buffers(&[hal::BufferBarrier {
256 buffer: zero_buffer.as_ref(),
257 usage: hal::BufferUses::empty()..hal::BufferUses::COPY_DST,
258 }]);
259 pending_writes
260 .command_encoder
261 .clear_buffer(zero_buffer.as_ref(), 0..ZERO_BUFFER_SIZE);
262 pending_writes
263 .command_encoder
264 .transition_buffers(&[hal::BufferBarrier {
265 buffer: zero_buffer.as_ref(),
266 usage: hal::BufferUses::COPY_DST..hal::BufferUses::COPY_SRC,
267 }]);
268 }
269
270 let alignments = adapter.raw.capabilities.alignments.clone();
271 let downlevel = adapter.raw.capabilities.downlevel.clone();
272
273 #[cfg(feature = "indirect-validation")]
274 let indirect_validation = if downlevel
275 .flags
276 .contains(wgt::DownlevelFlags::INDIRECT_EXECUTION)
277 {
278 match crate::indirect_validation::IndirectValidation::new(
279 raw_device.as_ref(),
280 &desc.required_limits,
281 ) {
282 Ok(indirect_validation) => Some(indirect_validation),
283 Err(e) => {
284 log::error!("indirect-validation error: {e:?}");
285 return Err(DeviceError::Lost);
286 }
287 }
288 } else {
289 None
290 };
291
292 Ok(Self {
293 raw: ManuallyDrop::new(raw_device),
294 adapter: adapter.clone(),
295 queue: OnceLock::new(),
296 queue_to_drop: OnceLock::new(),
297 zero_buffer: ManuallyDrop::new(zero_buffer),
298 label: desc.label.to_string(),
299 command_allocator,
300 active_submission_index: AtomicU64::new(0),
301 last_successful_submission_index: AtomicU64::new(0),
302 fence: RwLock::new(rank::DEVICE_FENCE, ManuallyDrop::new(fence)),
303 snatchable_lock: unsafe { SnatchLock::new(rank::DEVICE_SNATCHABLE_LOCK) },
304 valid: AtomicBool::new(true),
305 trackers: Mutex::new(rank::DEVICE_TRACKERS, DeviceTracker::new()),
306 tracker_indices: TrackerIndexAllocators::new(),
307 life_tracker: Mutex::new(rank::DEVICE_LIFE_TRACKER, LifetimeTracker::new()),
308 bgl_pool: ResourcePool::new(),
309 #[cfg(feature = "trace")]
310 trace: Mutex::new(
311 rank::DEVICE_TRACE,
312 trace_path.and_then(|path| match trace::Trace::new(path) {
313 Ok(mut trace) => {
314 trace.add(trace::Action::Init {
315 desc: desc.clone(),
316 backend: adapter.backend(),
317 });
318 Some(trace)
319 }
320 Err(e) => {
321 log::error!("Unable to start a trace in '{path:?}': {e}");
322 None
323 }
324 }),
325 ),
326 alignments,
327 limits: desc.required_limits.clone(),
328 features: desc.required_features,
329 downlevel,
330 instance_flags,
331 pending_writes: Mutex::new(
332 rank::DEVICE_PENDING_WRITES,
333 ManuallyDrop::new(pending_writes),
334 ),
335 deferred_destroy: Mutex::new(rank::DEVICE_DEFERRED_DESTROY, Vec::new()),
336 usage_scopes: Mutex::new(rank::DEVICE_USAGE_SCOPES, Default::default()),
337 #[cfg(feature = "indirect-validation")]
338 indirect_validation,
339 })
340 }
341
342 pub fn backend(&self) -> wgt::Backend {
344 self.adapter.backend()
345 }
346
347 pub fn is_valid(&self) -> bool {
348 self.valid.load(Ordering::Acquire)
349 }
350
351 pub fn check_is_valid(&self) -> Result<(), DeviceError> {
352 if self.is_valid() {
353 Ok(())
354 } else {
355 Err(DeviceError::Invalid(self.error_ident()))
356 }
357 }
358
359 pub fn handle_hal_error(&self, error: hal::DeviceError) -> DeviceError {
360 match error {
361 hal::DeviceError::OutOfMemory => {}
362 hal::DeviceError::Lost
363 | hal::DeviceError::ResourceCreationFailed
364 | hal::DeviceError::Unexpected => {
365 self.lose(&error.to_string());
366 }
367 }
368 DeviceError::from_hal(error)
369 }
370
371 pub(crate) fn release_queue(&self, queue: Box<dyn hal::DynQueue>) {
372 assert!(self.queue_to_drop.set(queue).is_ok());
373 }
374
375 #[track_caller]
376 pub(crate) fn lock_life<'a>(&'a self) -> MutexGuard<'a, LifetimeTracker> {
377 self.life_tracker.lock()
378 }
379
380 pub(crate) fn deferred_resource_destruction(&self) {
388 let deferred_destroy = mem::take(&mut *self.deferred_destroy.lock());
389 for item in deferred_destroy {
390 match item {
391 DeferredDestroy::TextureViews(views) => {
392 for view in views {
393 let Some(view) = view.upgrade() else {
394 continue;
395 };
396 let Some(raw_view) = view.raw.snatch(&mut self.snatchable_lock.write())
397 else {
398 continue;
399 };
400
401 resource_log!("Destroy raw {}", view.error_ident());
402
403 unsafe {
404 self.raw().destroy_texture_view(raw_view);
405 }
406 }
407 }
408 DeferredDestroy::BindGroups(bind_groups) => {
409 for bind_group in bind_groups {
410 let Some(bind_group) = bind_group.upgrade() else {
411 continue;
412 };
413 let Some(raw_bind_group) =
414 bind_group.raw.snatch(&mut self.snatchable_lock.write())
415 else {
416 continue;
417 };
418
419 resource_log!("Destroy raw {}", bind_group.error_ident());
420
421 unsafe {
422 self.raw().destroy_bind_group(raw_bind_group);
423 }
424 }
425 }
426 }
427 }
428 }
429
430 pub fn get_queue(&self) -> Option<Arc<Queue>> {
431 self.queue.get().as_ref()?.upgrade()
432 }
433
434 pub fn set_queue(&self, queue: &Arc<Queue>) {
435 assert!(self.queue.set(Arc::downgrade(queue)).is_ok());
436 }
437
438 pub(crate) fn maintain<'this>(
452 &'this self,
453 fence: crate::lock::RwLockReadGuard<ManuallyDrop<Box<dyn hal::DynFence>>>,
454 maintain: wgt::Maintain<crate::SubmissionIndex>,
455 snatch_guard: SnatchGuard,
456 ) -> Result<(UserClosures, bool), WaitIdleError> {
457 profiling::scope!("Device::maintain");
458
459 let submission_index = match maintain {
461 wgt::Maintain::WaitForSubmissionIndex(submission_index) => {
462 let last_successful_submission_index = self
463 .last_successful_submission_index
464 .load(Ordering::Acquire);
465
466 if submission_index > last_successful_submission_index {
467 return Err(WaitIdleError::WrongSubmissionIndex(
468 submission_index,
469 last_successful_submission_index,
470 ));
471 }
472
473 submission_index
474 }
475 wgt::Maintain::Wait => self
476 .last_successful_submission_index
477 .load(Ordering::Acquire),
478 wgt::Maintain::Poll => unsafe { self.raw().get_fence_value(fence.as_ref()) }
479 .map_err(|e| self.handle_hal_error(e))?,
480 };
481
482 if maintain.is_wait() {
484 log::trace!("Device::maintain: waiting for submission index {submission_index}");
485 unsafe {
486 self.raw()
487 .wait(fence.as_ref(), submission_index, CLEANUP_WAIT_MS)
488 }
489 .map_err(|e| self.handle_hal_error(e))?;
490 }
491
492 let mut life_tracker = self.lock_life();
493 let submission_closures =
494 life_tracker.triage_submissions(submission_index, &self.command_allocator);
495
496 life_tracker.triage_mapped();
497
498 let mapping_closures = life_tracker.handle_mapping(self.raw(), &snatch_guard);
499
500 let queue_empty = life_tracker.queue_empty();
501
502 let mut device_lost_invocations = SmallVec::new();
508 let mut should_release_gpu_resource = false;
509 if !self.is_valid() && queue_empty {
510 should_release_gpu_resource = true;
513
514 if life_tracker.device_lost_closure.is_some() {
517 device_lost_invocations.push(DeviceLostInvocation {
518 closure: life_tracker.device_lost_closure.take().unwrap(),
519 reason: DeviceLostReason::Destroyed,
520 message: String::new(),
521 });
522 }
523 }
524
525 drop(life_tracker);
527 drop(fence);
528 drop(snatch_guard);
529
530 if should_release_gpu_resource {
531 self.release_gpu_resources();
532 }
533
534 let closures = UserClosures {
535 mappings: mapping_closures,
536 submissions: submission_closures,
537 device_lost_invocations,
538 };
539 Ok((closures, queue_empty))
540 }
541
542 pub(crate) fn create_buffer(
543 self: &Arc<Self>,
544 desc: &resource::BufferDescriptor,
545 ) -> Result<Arc<Buffer>, resource::CreateBufferError> {
546 self.check_is_valid()?;
547
548 if desc.size > self.limits.max_buffer_size {
549 return Err(resource::CreateBufferError::MaxBufferSize {
550 requested: desc.size,
551 maximum: self.limits.max_buffer_size,
552 });
553 }
554
555 if desc.usage.contains(wgt::BufferUsages::INDEX)
556 && desc.usage.contains(
557 wgt::BufferUsages::VERTEX
558 | wgt::BufferUsages::UNIFORM
559 | wgt::BufferUsages::INDIRECT
560 | wgt::BufferUsages::STORAGE,
561 )
562 {
563 self.require_downlevel_flags(wgt::DownlevelFlags::UNRESTRICTED_INDEX_BUFFER)?;
564 }
565
566 if desc.usage.is_empty() || desc.usage.contains_invalid_bits() {
567 return Err(resource::CreateBufferError::InvalidUsage(desc.usage));
568 }
569
570 if !self
571 .features
572 .contains(wgt::Features::MAPPABLE_PRIMARY_BUFFERS)
573 {
574 use wgt::BufferUsages as Bu;
575 let write_mismatch = desc.usage.contains(Bu::MAP_WRITE)
576 && !(Bu::MAP_WRITE | Bu::COPY_SRC).contains(desc.usage);
577 let read_mismatch = desc.usage.contains(Bu::MAP_READ)
578 && !(Bu::MAP_READ | Bu::COPY_DST).contains(desc.usage);
579 if write_mismatch || read_mismatch {
580 return Err(resource::CreateBufferError::UsageMismatch(desc.usage));
581 }
582 }
583
584 let mut usage = conv::map_buffer_usage(desc.usage);
585
586 if desc.usage.contains(wgt::BufferUsages::INDIRECT) {
587 self.require_downlevel_flags(wgt::DownlevelFlags::INDIRECT_EXECUTION)?;
588 usage |= hal::BufferUses::STORAGE_READ | hal::BufferUses::STORAGE_READ_WRITE;
591 }
592
593 if desc.mapped_at_creation {
594 if desc.size % wgt::COPY_BUFFER_ALIGNMENT != 0 {
595 return Err(resource::CreateBufferError::UnalignedSize);
596 }
597 if !desc.usage.contains(wgt::BufferUsages::MAP_WRITE) {
598 usage |= hal::BufferUses::COPY_DST;
600 }
601 } else {
602 usage |= hal::BufferUses::COPY_DST;
605 }
606
607 let actual_size = if desc.size == 0 {
608 wgt::COPY_BUFFER_ALIGNMENT
609 } else if desc.usage.contains(wgt::BufferUsages::VERTEX) {
610 desc.size + 1
613 } else {
614 desc.size
615 };
616 let clear_remainder = actual_size % wgt::COPY_BUFFER_ALIGNMENT;
617 let aligned_size = if clear_remainder != 0 {
618 actual_size + wgt::COPY_BUFFER_ALIGNMENT - clear_remainder
619 } else {
620 actual_size
621 };
622
623 let hal_desc = hal::BufferDescriptor {
624 label: desc.label.to_hal(self.instance_flags),
625 size: aligned_size,
626 usage,
627 memory_flags: hal::MemoryFlags::empty(),
628 };
629 let buffer =
630 unsafe { self.raw().create_buffer(&hal_desc) }.map_err(|e| self.handle_hal_error(e))?;
631
632 #[cfg(feature = "indirect-validation")]
633 let raw_indirect_validation_bind_group =
634 self.create_indirect_validation_bind_group(buffer.as_ref(), desc.size, desc.usage)?;
635
636 let buffer = Buffer {
637 raw: Snatchable::new(buffer),
638 device: self.clone(),
639 usage: desc.usage,
640 size: desc.size,
641 initialization_status: RwLock::new(
642 rank::BUFFER_INITIALIZATION_STATUS,
643 BufferInitTracker::new(aligned_size),
644 ),
645 map_state: Mutex::new(rank::BUFFER_MAP_STATE, resource::BufferMapState::Idle),
646 label: desc.label.to_string(),
647 tracking_data: TrackingData::new(self.tracker_indices.buffers.clone()),
648 bind_groups: Mutex::new(rank::BUFFER_BIND_GROUPS, WeakVec::new()),
649 #[cfg(feature = "indirect-validation")]
650 raw_indirect_validation_bind_group,
651 };
652
653 let buffer = Arc::new(buffer);
654
655 let buffer_use = if !desc.mapped_at_creation {
656 hal::BufferUses::empty()
657 } else if desc.usage.contains(wgt::BufferUsages::MAP_WRITE) {
658 let map_size = buffer.size;
660 let mapping = if map_size == 0 {
661 hal::BufferMapping {
662 ptr: std::ptr::NonNull::dangling(),
663 is_coherent: true,
664 }
665 } else {
666 let snatch_guard: SnatchGuard = self.snatchable_lock.read();
667 map_buffer(
668 self.raw(),
669 &buffer,
670 0,
671 map_size,
672 HostMap::Write,
673 &snatch_guard,
674 )?
675 };
676 *buffer.map_state.lock() = resource::BufferMapState::Active {
677 mapping,
678 range: 0..map_size,
679 host: HostMap::Write,
680 };
681 hal::BufferUses::MAP_WRITE
682 } else {
683 let mut staging_buffer =
684 StagingBuffer::new(self, wgt::BufferSize::new(aligned_size).unwrap())?;
685
686 staging_buffer.write_zeros();
689 buffer.initialization_status.write().drain(0..aligned_size);
690
691 *buffer.map_state.lock() = resource::BufferMapState::Init { staging_buffer };
692 hal::BufferUses::COPY_DST
693 };
694
695 self.trackers
696 .lock()
697 .buffers
698 .insert_single(&buffer, buffer_use);
699
700 Ok(buffer)
701 }
702
703 pub(crate) fn create_texture_from_hal(
704 self: &Arc<Self>,
705 hal_texture: Box<dyn hal::DynTexture>,
706 desc: &resource::TextureDescriptor,
707 ) -> Result<Arc<Texture>, resource::CreateTextureError> {
708 let format_features = self
709 .describe_format_features(desc.format)
710 .map_err(|error| resource::CreateTextureError::MissingFeatures(desc.format, error))?;
711
712 unsafe { self.raw().add_raw_texture(&*hal_texture) };
713
714 let texture = Texture::new(
715 self,
716 resource::TextureInner::Native { raw: hal_texture },
717 conv::map_texture_usage(desc.usage, desc.format.into()),
718 desc,
719 format_features,
720 resource::TextureClearMode::None,
721 false,
722 );
723
724 let texture = Arc::new(texture);
725
726 self.trackers
727 .lock()
728 .textures
729 .insert_single(&texture, hal::TextureUses::UNINITIALIZED);
730
731 Ok(texture)
732 }
733
734 pub(crate) fn create_buffer_from_hal(
735 self: &Arc<Self>,
736 hal_buffer: Box<dyn hal::DynBuffer>,
737 desc: &resource::BufferDescriptor,
738 ) -> (Fallible<Buffer>, Option<resource::CreateBufferError>) {
739 #[cfg(feature = "indirect-validation")]
740 let raw_indirect_validation_bind_group = match self.create_indirect_validation_bind_group(
741 hal_buffer.as_ref(),
742 desc.size,
743 desc.usage,
744 ) {
745 Ok(ok) => ok,
746 Err(e) => return (Fallible::Invalid(Arc::new(desc.label.to_string())), Some(e)),
747 };
748
749 unsafe { self.raw().add_raw_buffer(&*hal_buffer) };
750
751 let buffer = Buffer {
752 raw: Snatchable::new(hal_buffer),
753 device: self.clone(),
754 usage: desc.usage,
755 size: desc.size,
756 initialization_status: RwLock::new(
757 rank::BUFFER_INITIALIZATION_STATUS,
758 BufferInitTracker::new(0),
759 ),
760 map_state: Mutex::new(rank::BUFFER_MAP_STATE, resource::BufferMapState::Idle),
761 label: desc.label.to_string(),
762 tracking_data: TrackingData::new(self.tracker_indices.buffers.clone()),
763 bind_groups: Mutex::new(rank::BUFFER_BIND_GROUPS, WeakVec::new()),
764 #[cfg(feature = "indirect-validation")]
765 raw_indirect_validation_bind_group,
766 };
767
768 let buffer = Arc::new(buffer);
769
770 self.trackers
771 .lock()
772 .buffers
773 .insert_single(&buffer, hal::BufferUses::empty());
774
775 (Fallible::Valid(buffer), None)
776 }
777
778 #[cfg(feature = "indirect-validation")]
779 fn create_indirect_validation_bind_group(
780 &self,
781 raw_buffer: &dyn hal::DynBuffer,
782 buffer_size: u64,
783 usage: wgt::BufferUsages,
784 ) -> Result<Snatchable<Box<dyn hal::DynBindGroup>>, resource::CreateBufferError> {
785 if usage.contains(wgt::BufferUsages::INDIRECT) {
786 let indirect_validation = self.indirect_validation.as_ref().unwrap();
787 let bind_group = indirect_validation
788 .create_src_bind_group(self.raw(), &self.limits, buffer_size, raw_buffer)
789 .map_err(resource::CreateBufferError::IndirectValidationBindGroup)?;
790 match bind_group {
791 Some(bind_group) => Ok(Snatchable::new(bind_group)),
792 None => Ok(Snatchable::empty()),
793 }
794 } else {
795 Ok(Snatchable::empty())
796 }
797 }
798
799 pub(crate) fn create_texture(
800 self: &Arc<Self>,
801 desc: &resource::TextureDescriptor,
802 ) -> Result<Arc<Texture>, resource::CreateTextureError> {
803 use resource::{CreateTextureError, TextureDimensionError};
804
805 self.check_is_valid()?;
806
807 if desc.usage.is_empty() || desc.usage.contains_invalid_bits() {
808 return Err(CreateTextureError::InvalidUsage(desc.usage));
809 }
810
811 conv::check_texture_dimension_size(
812 desc.dimension,
813 desc.size,
814 desc.sample_count,
815 &self.limits,
816 )?;
817
818 if desc.dimension != wgt::TextureDimension::D2 {
819 if desc.format.is_depth_stencil_format() {
821 return Err(CreateTextureError::InvalidDepthDimension(
822 desc.dimension,
823 desc.format,
824 ));
825 }
826 if desc.usage.contains(wgt::TextureUsages::RENDER_ATTACHMENT) {
828 return Err(CreateTextureError::InvalidDimensionUsages(
829 wgt::TextureUsages::RENDER_ATTACHMENT,
830 desc.dimension,
831 ));
832 }
833 }
834
835 if desc.dimension != wgt::TextureDimension::D2
836 && desc.dimension != wgt::TextureDimension::D3
837 {
838 if desc.format.is_compressed() {
840 return Err(CreateTextureError::InvalidCompressedDimension(
841 desc.dimension,
842 desc.format,
843 ));
844 }
845 }
846
847 if desc.format.is_compressed() {
848 let (block_width, block_height) = desc.format.block_dimensions();
849
850 if desc.size.width % block_width != 0 {
851 return Err(CreateTextureError::InvalidDimension(
852 TextureDimensionError::NotMultipleOfBlockWidth {
853 width: desc.size.width,
854 block_width,
855 format: desc.format,
856 },
857 ));
858 }
859
860 if desc.size.height % block_height != 0 {
861 return Err(CreateTextureError::InvalidDimension(
862 TextureDimensionError::NotMultipleOfBlockHeight {
863 height: desc.size.height,
864 block_height,
865 format: desc.format,
866 },
867 ));
868 }
869
870 if desc.dimension == wgt::TextureDimension::D3 {
871 if desc.format.is_bcn() {
873 self.require_features(wgt::Features::TEXTURE_COMPRESSION_BC_SLICED_3D)
874 .map_err(|error| CreateTextureError::MissingFeatures(desc.format, error))?;
875 } else {
876 return Err(CreateTextureError::InvalidCompressedDimension(
877 desc.dimension,
878 desc.format,
879 ));
880 }
881 }
882 }
883
884 {
885 let (width_multiple, height_multiple) = desc.format.size_multiple_requirement();
886
887 if desc.size.width % width_multiple != 0 {
888 return Err(CreateTextureError::InvalidDimension(
889 TextureDimensionError::WidthNotMultipleOf {
890 width: desc.size.width,
891 multiple: width_multiple,
892 format: desc.format,
893 },
894 ));
895 }
896
897 if desc.size.height % height_multiple != 0 {
898 return Err(CreateTextureError::InvalidDimension(
899 TextureDimensionError::HeightNotMultipleOf {
900 height: desc.size.height,
901 multiple: height_multiple,
902 format: desc.format,
903 },
904 ));
905 }
906 }
907
908 let format_features = self
909 .describe_format_features(desc.format)
910 .map_err(|error| CreateTextureError::MissingFeatures(desc.format, error))?;
911
912 if desc.sample_count > 1 {
913 if desc.mip_level_count != 1 {
914 return Err(CreateTextureError::InvalidMipLevelCount {
915 requested: desc.mip_level_count,
916 maximum: 1,
917 });
918 }
919
920 if desc.size.depth_or_array_layers != 1 {
921 return Err(CreateTextureError::InvalidDimension(
922 TextureDimensionError::MultisampledDepthOrArrayLayer(
923 desc.size.depth_or_array_layers,
924 ),
925 ));
926 }
927
928 if desc.usage.contains(wgt::TextureUsages::STORAGE_BINDING) {
929 return Err(CreateTextureError::InvalidMultisampledStorageBinding);
930 }
931
932 if !desc.usage.contains(wgt::TextureUsages::RENDER_ATTACHMENT) {
933 return Err(CreateTextureError::MultisampledNotRenderAttachment);
934 }
935
936 if !format_features.flags.intersects(
937 wgt::TextureFormatFeatureFlags::MULTISAMPLE_X4
938 | wgt::TextureFormatFeatureFlags::MULTISAMPLE_X2
939 | wgt::TextureFormatFeatureFlags::MULTISAMPLE_X8
940 | wgt::TextureFormatFeatureFlags::MULTISAMPLE_X16,
941 ) {
942 return Err(CreateTextureError::InvalidMultisampledFormat(desc.format));
943 }
944
945 if !format_features
946 .flags
947 .sample_count_supported(desc.sample_count)
948 {
949 return Err(CreateTextureError::InvalidSampleCount(
950 desc.sample_count,
951 desc.format,
952 desc.format
953 .guaranteed_format_features(self.features)
954 .flags
955 .supported_sample_counts(),
956 self.adapter
957 .get_texture_format_features(desc.format)
958 .flags
959 .supported_sample_counts(),
960 ));
961 };
962 }
963
964 let mips = desc.mip_level_count;
965 let max_levels_allowed = desc.size.max_mips(desc.dimension).min(hal::MAX_MIP_LEVELS);
966 if mips == 0 || mips > max_levels_allowed {
967 return Err(CreateTextureError::InvalidMipLevelCount {
968 requested: mips,
969 maximum: max_levels_allowed,
970 });
971 }
972
973 let missing_allowed_usages = desc.usage - format_features.allowed_usages;
974 if !missing_allowed_usages.is_empty() {
975 let wgpu_allowed_usages = desc
977 .format
978 .guaranteed_format_features(self.features)
979 .allowed_usages;
980 let wgpu_missing_usages = desc.usage - wgpu_allowed_usages;
981 return Err(CreateTextureError::InvalidFormatUsages(
982 missing_allowed_usages,
983 desc.format,
984 wgpu_missing_usages.is_empty(),
985 ));
986 }
987
988 let mut hal_view_formats = vec![];
989 for format in desc.view_formats.iter() {
990 if desc.format == *format {
991 continue;
992 }
993 if desc.format.remove_srgb_suffix() != format.remove_srgb_suffix() {
994 return Err(CreateTextureError::InvalidViewFormat(*format, desc.format));
995 }
996 hal_view_formats.push(*format);
997 }
998 if !hal_view_formats.is_empty() {
999 self.require_downlevel_flags(wgt::DownlevelFlags::VIEW_FORMATS)?;
1000 }
1001
1002 let hal_usage = conv::map_texture_usage_for_texture(desc, &format_features);
1003
1004 let hal_desc = hal::TextureDescriptor {
1005 label: desc.label.to_hal(self.instance_flags),
1006 size: desc.size,
1007 mip_level_count: desc.mip_level_count,
1008 sample_count: desc.sample_count,
1009 dimension: desc.dimension,
1010 format: desc.format,
1011 usage: hal_usage,
1012 memory_flags: hal::MemoryFlags::empty(),
1013 view_formats: hal_view_formats,
1014 };
1015
1016 let raw_texture = unsafe { self.raw().create_texture(&hal_desc) }
1017 .map_err(|e| self.handle_hal_error(e))?;
1018
1019 let clear_mode = if hal_usage
1020 .intersects(hal::TextureUses::DEPTH_STENCIL_WRITE | hal::TextureUses::COLOR_TARGET)
1021 {
1022 let (is_color, usage) = if desc.format.is_depth_stencil_format() {
1023 (false, hal::TextureUses::DEPTH_STENCIL_WRITE)
1024 } else {
1025 (true, hal::TextureUses::COLOR_TARGET)
1026 };
1027 let dimension = match desc.dimension {
1028 wgt::TextureDimension::D1 => TextureViewDimension::D1,
1029 wgt::TextureDimension::D2 => TextureViewDimension::D2,
1030 wgt::TextureDimension::D3 => unreachable!(),
1031 };
1032
1033 let clear_label = hal_label(
1034 Some("(wgpu internal) clear texture view"),
1035 self.instance_flags,
1036 );
1037
1038 let mut clear_views = SmallVec::new();
1039 for mip_level in 0..desc.mip_level_count {
1040 for array_layer in 0..desc.size.depth_or_array_layers {
1041 macro_rules! push_clear_view {
1042 ($format:expr, $aspect:expr) => {
1043 let desc = hal::TextureViewDescriptor {
1044 label: clear_label,
1045 format: $format,
1046 dimension,
1047 usage,
1048 range: wgt::ImageSubresourceRange {
1049 aspect: $aspect,
1050 base_mip_level: mip_level,
1051 mip_level_count: Some(1),
1052 base_array_layer: array_layer,
1053 array_layer_count: Some(1),
1054 },
1055 };
1056 clear_views.push(ManuallyDrop::new(
1057 unsafe {
1058 self.raw().create_texture_view(raw_texture.as_ref(), &desc)
1059 }
1060 .map_err(|e| self.handle_hal_error(e))?,
1061 ));
1062 };
1063 }
1064
1065 if let Some(planes) = desc.format.planes() {
1066 for plane in 0..planes {
1067 let aspect = wgt::TextureAspect::from_plane(plane).unwrap();
1068 let format = desc.format.aspect_specific_format(aspect).unwrap();
1069 push_clear_view!(format, aspect);
1070 }
1071 } else {
1072 push_clear_view!(desc.format, wgt::TextureAspect::All);
1073 }
1074 }
1075 }
1076 resource::TextureClearMode::RenderPass {
1077 clear_views,
1078 is_color,
1079 }
1080 } else {
1081 resource::TextureClearMode::BufferCopy
1082 };
1083
1084 let texture = Texture::new(
1085 self,
1086 resource::TextureInner::Native { raw: raw_texture },
1087 hal_usage,
1088 desc,
1089 format_features,
1090 clear_mode,
1091 true,
1092 );
1093
1094 let texture = Arc::new(texture);
1095
1096 self.trackers
1097 .lock()
1098 .textures
1099 .insert_single(&texture, hal::TextureUses::UNINITIALIZED);
1100
1101 Ok(texture)
1102 }
1103
1104 pub(crate) fn create_texture_view(
1105 self: &Arc<Self>,
1106 texture: &Arc<Texture>,
1107 desc: &resource::TextureViewDescriptor,
1108 ) -> Result<Arc<TextureView>, resource::CreateTextureViewError> {
1109 self.check_is_valid()?;
1110
1111 let snatch_guard = texture.device.snatchable_lock.read();
1112
1113 let texture_raw = texture.try_raw(&snatch_guard)?;
1114
1115 let resolved_format = desc.format.unwrap_or_else(|| {
1118 texture
1119 .desc
1120 .format
1121 .aspect_specific_format(desc.range.aspect)
1122 .unwrap_or(texture.desc.format)
1123 });
1124
1125 let resolved_dimension = desc
1126 .dimension
1127 .unwrap_or_else(|| match texture.desc.dimension {
1128 wgt::TextureDimension::D1 => TextureViewDimension::D1,
1129 wgt::TextureDimension::D2 => {
1130 if texture.desc.array_layer_count() == 1 {
1131 TextureViewDimension::D2
1132 } else {
1133 TextureViewDimension::D2Array
1134 }
1135 }
1136 wgt::TextureDimension::D3 => TextureViewDimension::D3,
1137 });
1138
1139 let resolved_mip_level_count = desc.range.mip_level_count.unwrap_or_else(|| {
1140 texture
1141 .desc
1142 .mip_level_count
1143 .saturating_sub(desc.range.base_mip_level)
1144 });
1145
1146 let resolved_array_layer_count =
1147 desc.range
1148 .array_layer_count
1149 .unwrap_or_else(|| match resolved_dimension {
1150 TextureViewDimension::D1
1151 | TextureViewDimension::D2
1152 | TextureViewDimension::D3 => 1,
1153 TextureViewDimension::Cube => 6,
1154 TextureViewDimension::D2Array | TextureViewDimension::CubeArray => texture
1155 .desc
1156 .array_layer_count()
1157 .saturating_sub(desc.range.base_array_layer),
1158 });
1159
1160 let aspects = hal::FormatAspects::new(texture.desc.format, desc.range.aspect);
1163 if aspects.is_empty() {
1164 return Err(resource::CreateTextureViewError::InvalidAspect {
1165 texture_format: texture.desc.format,
1166 requested_aspect: desc.range.aspect,
1167 });
1168 }
1169
1170 let format_is_good = if desc.range.aspect == wgt::TextureAspect::All {
1171 resolved_format == texture.desc.format
1172 || texture.desc.view_formats.contains(&resolved_format)
1173 } else {
1174 Some(resolved_format)
1175 == texture
1176 .desc
1177 .format
1178 .aspect_specific_format(desc.range.aspect)
1179 };
1180 if !format_is_good {
1181 return Err(resource::CreateTextureViewError::FormatReinterpretation {
1182 texture: texture.desc.format,
1183 view: resolved_format,
1184 });
1185 }
1186
1187 if texture.desc.sample_count > 1 && resolved_dimension != TextureViewDimension::D2 {
1189 return Err(
1190 resource::CreateTextureViewError::InvalidMultisampledTextureViewDimension(
1191 resolved_dimension,
1192 ),
1193 );
1194 }
1195
1196 if texture.desc.dimension != resolved_dimension.compatible_texture_dimension() {
1198 return Err(
1199 resource::CreateTextureViewError::InvalidTextureViewDimension {
1200 view: resolved_dimension,
1201 texture: texture.desc.dimension,
1202 },
1203 );
1204 }
1205
1206 match resolved_dimension {
1207 TextureViewDimension::D1 | TextureViewDimension::D2 | TextureViewDimension::D3 => {
1208 if resolved_array_layer_count != 1 {
1209 return Err(resource::CreateTextureViewError::InvalidArrayLayerCount {
1210 requested: resolved_array_layer_count,
1211 dim: resolved_dimension,
1212 });
1213 }
1214 }
1215 TextureViewDimension::Cube => {
1216 if resolved_array_layer_count != 6 {
1217 return Err(
1218 resource::CreateTextureViewError::InvalidCubemapTextureDepth {
1219 depth: resolved_array_layer_count,
1220 },
1221 );
1222 }
1223 }
1224 TextureViewDimension::CubeArray => {
1225 if resolved_array_layer_count % 6 != 0 {
1226 return Err(
1227 resource::CreateTextureViewError::InvalidCubemapArrayTextureDepth {
1228 depth: resolved_array_layer_count,
1229 },
1230 );
1231 }
1232 }
1233 _ => {}
1234 }
1235
1236 match resolved_dimension {
1237 TextureViewDimension::Cube | TextureViewDimension::CubeArray => {
1238 if texture.desc.size.width != texture.desc.size.height {
1239 return Err(resource::CreateTextureViewError::InvalidCubeTextureViewSize);
1240 }
1241 }
1242 _ => {}
1243 }
1244
1245 if resolved_mip_level_count == 0 {
1246 return Err(resource::CreateTextureViewError::ZeroMipLevelCount);
1247 }
1248
1249 let mip_level_end = desc
1250 .range
1251 .base_mip_level
1252 .saturating_add(resolved_mip_level_count);
1253
1254 let level_end = texture.desc.mip_level_count;
1255 if mip_level_end > level_end {
1256 return Err(resource::CreateTextureViewError::TooManyMipLevels {
1257 requested: mip_level_end,
1258 total: level_end,
1259 });
1260 }
1261
1262 if resolved_array_layer_count == 0 {
1263 return Err(resource::CreateTextureViewError::ZeroArrayLayerCount);
1264 }
1265
1266 let array_layer_end = desc
1267 .range
1268 .base_array_layer
1269 .saturating_add(resolved_array_layer_count);
1270
1271 let layer_end = texture.desc.array_layer_count();
1272 if array_layer_end > layer_end {
1273 return Err(resource::CreateTextureViewError::TooManyArrayLayers {
1274 requested: array_layer_end,
1275 total: layer_end,
1276 });
1277 };
1278
1279 let render_extent = 'error: {
1281 if !texture
1282 .desc
1283 .usage
1284 .contains(wgt::TextureUsages::RENDER_ATTACHMENT)
1285 {
1286 break 'error Err(TextureViewNotRenderableReason::Usage(texture.desc.usage));
1287 }
1288
1289 if !(resolved_dimension == TextureViewDimension::D2
1290 || (self.features.contains(wgt::Features::MULTIVIEW)
1291 && resolved_dimension == TextureViewDimension::D2Array))
1292 {
1293 break 'error Err(TextureViewNotRenderableReason::Dimension(
1294 resolved_dimension,
1295 ));
1296 }
1297
1298 if resolved_mip_level_count != 1 {
1299 break 'error Err(TextureViewNotRenderableReason::MipLevelCount(
1300 resolved_mip_level_count,
1301 ));
1302 }
1303
1304 if resolved_array_layer_count != 1
1305 && !(self.features.contains(wgt::Features::MULTIVIEW))
1306 {
1307 break 'error Err(TextureViewNotRenderableReason::ArrayLayerCount(
1308 resolved_array_layer_count,
1309 ));
1310 }
1311
1312 if aspects != hal::FormatAspects::from(texture.desc.format) {
1313 break 'error Err(TextureViewNotRenderableReason::Aspects(aspects));
1314 }
1315
1316 Ok(texture
1317 .desc
1318 .compute_render_extent(desc.range.base_mip_level))
1319 };
1320
1321 let usage = {
1323 let mask_copy = !(hal::TextureUses::COPY_SRC | hal::TextureUses::COPY_DST);
1324 let mask_dimension = match resolved_dimension {
1325 TextureViewDimension::Cube | TextureViewDimension::CubeArray => {
1326 hal::TextureUses::RESOURCE
1327 }
1328 TextureViewDimension::D3 => {
1329 hal::TextureUses::RESOURCE
1330 | hal::TextureUses::STORAGE_READ
1331 | hal::TextureUses::STORAGE_READ_WRITE
1332 }
1333 _ => hal::TextureUses::all(),
1334 };
1335 let mask_mip_level = if resolved_mip_level_count == 1 {
1336 hal::TextureUses::all()
1337 } else {
1338 hal::TextureUses::RESOURCE
1339 };
1340 texture.hal_usage & mask_copy & mask_dimension & mask_mip_level
1341 };
1342
1343 let format = if resolved_format.is_depth_stencil_component(texture.desc.format) {
1345 texture.desc.format
1346 } else {
1347 resolved_format
1348 };
1349
1350 let resolved_range = wgt::ImageSubresourceRange {
1351 aspect: desc.range.aspect,
1352 base_mip_level: desc.range.base_mip_level,
1353 mip_level_count: Some(resolved_mip_level_count),
1354 base_array_layer: desc.range.base_array_layer,
1355 array_layer_count: Some(resolved_array_layer_count),
1356 };
1357
1358 let hal_desc = hal::TextureViewDescriptor {
1359 label: desc.label.to_hal(self.instance_flags),
1360 format,
1361 dimension: resolved_dimension,
1362 usage,
1363 range: resolved_range,
1364 };
1365
1366 let raw = unsafe { self.raw().create_texture_view(texture_raw, &hal_desc) }
1367 .map_err(|e| self.handle_hal_error(e))?;
1368
1369 let selector = TextureSelector {
1370 mips: desc.range.base_mip_level..mip_level_end,
1371 layers: desc.range.base_array_layer..array_layer_end,
1372 };
1373
1374 let view = TextureView {
1375 raw: Snatchable::new(raw),
1376 parent: texture.clone(),
1377 device: self.clone(),
1378 desc: resource::HalTextureViewDescriptor {
1379 texture_format: texture.desc.format,
1380 format: resolved_format,
1381 dimension: resolved_dimension,
1382 range: resolved_range,
1383 },
1384 format_features: texture.format_features,
1385 render_extent,
1386 samples: texture.desc.sample_count,
1387 selector,
1388 label: desc.label.to_string(),
1389 tracking_data: TrackingData::new(self.tracker_indices.texture_views.clone()),
1390 };
1391
1392 let view = Arc::new(view);
1393
1394 {
1395 let mut views = texture.views.lock();
1396 views.push(Arc::downgrade(&view));
1397 }
1398
1399 Ok(view)
1400 }
1401
1402 pub(crate) fn create_sampler(
1403 self: &Arc<Self>,
1404 desc: &resource::SamplerDescriptor,
1405 ) -> Result<Arc<Sampler>, resource::CreateSamplerError> {
1406 self.check_is_valid()?;
1407
1408 if desc
1409 .address_modes
1410 .iter()
1411 .any(|am| am == &wgt::AddressMode::ClampToBorder)
1412 {
1413 self.require_features(wgt::Features::ADDRESS_MODE_CLAMP_TO_BORDER)?;
1414 }
1415
1416 if desc.border_color == Some(wgt::SamplerBorderColor::Zero) {
1417 self.require_features(wgt::Features::ADDRESS_MODE_CLAMP_TO_ZERO)?;
1418 }
1419
1420 if desc.lod_min_clamp < 0.0 {
1421 return Err(resource::CreateSamplerError::InvalidLodMinClamp(
1422 desc.lod_min_clamp,
1423 ));
1424 }
1425 if desc.lod_max_clamp < desc.lod_min_clamp {
1426 return Err(resource::CreateSamplerError::InvalidLodMaxClamp {
1427 lod_min_clamp: desc.lod_min_clamp,
1428 lod_max_clamp: desc.lod_max_clamp,
1429 });
1430 }
1431
1432 if desc.anisotropy_clamp < 1 {
1433 return Err(resource::CreateSamplerError::InvalidAnisotropy(
1434 desc.anisotropy_clamp,
1435 ));
1436 }
1437
1438 if desc.anisotropy_clamp != 1 {
1439 if !matches!(desc.min_filter, wgt::FilterMode::Linear) {
1440 return Err(
1441 resource::CreateSamplerError::InvalidFilterModeWithAnisotropy {
1442 filter_type: resource::SamplerFilterErrorType::MinFilter,
1443 filter_mode: desc.min_filter,
1444 anisotropic_clamp: desc.anisotropy_clamp,
1445 },
1446 );
1447 }
1448 if !matches!(desc.mag_filter, wgt::FilterMode::Linear) {
1449 return Err(
1450 resource::CreateSamplerError::InvalidFilterModeWithAnisotropy {
1451 filter_type: resource::SamplerFilterErrorType::MagFilter,
1452 filter_mode: desc.mag_filter,
1453 anisotropic_clamp: desc.anisotropy_clamp,
1454 },
1455 );
1456 }
1457 if !matches!(desc.mipmap_filter, wgt::FilterMode::Linear) {
1458 return Err(
1459 resource::CreateSamplerError::InvalidFilterModeWithAnisotropy {
1460 filter_type: resource::SamplerFilterErrorType::MipmapFilter,
1461 filter_mode: desc.mipmap_filter,
1462 anisotropic_clamp: desc.anisotropy_clamp,
1463 },
1464 );
1465 }
1466 }
1467
1468 let anisotropy_clamp = if self
1469 .downlevel
1470 .flags
1471 .contains(wgt::DownlevelFlags::ANISOTROPIC_FILTERING)
1472 {
1473 desc.anisotropy_clamp.min(16)
1475 } else {
1476 1
1478 };
1479
1480 let hal_desc = hal::SamplerDescriptor {
1483 label: desc.label.to_hal(self.instance_flags),
1484 address_modes: desc.address_modes,
1485 mag_filter: desc.mag_filter,
1486 min_filter: desc.min_filter,
1487 mipmap_filter: desc.mipmap_filter,
1488 lod_clamp: desc.lod_min_clamp..desc.lod_max_clamp,
1489 compare: desc.compare,
1490 anisotropy_clamp,
1491 border_color: desc.border_color,
1492 };
1493
1494 let raw = unsafe { self.raw().create_sampler(&hal_desc) }
1495 .map_err(|e| self.handle_hal_error(e))?;
1496
1497 let sampler = Sampler {
1498 raw: ManuallyDrop::new(raw),
1499 device: self.clone(),
1500 label: desc.label.to_string(),
1501 tracking_data: TrackingData::new(self.tracker_indices.samplers.clone()),
1502 comparison: desc.compare.is_some(),
1503 filtering: desc.min_filter == wgt::FilterMode::Linear
1504 || desc.mag_filter == wgt::FilterMode::Linear
1505 || desc.mipmap_filter == wgt::FilterMode::Linear,
1506 };
1507
1508 let sampler = Arc::new(sampler);
1509
1510 Ok(sampler)
1511 }
1512
1513 pub(crate) fn create_shader_module<'a>(
1514 self: &Arc<Self>,
1515 desc: &pipeline::ShaderModuleDescriptor<'a>,
1516 source: pipeline::ShaderModuleSource<'a>,
1517 ) -> Result<Arc<pipeline::ShaderModule>, pipeline::CreateShaderModuleError> {
1518 self.check_is_valid()?;
1519
1520 let (module, source) = match source {
1521 #[cfg(feature = "wgsl")]
1522 pipeline::ShaderModuleSource::Wgsl(code) => {
1523 profiling::scope!("naga::front::wgsl::parse_str");
1524 let module = naga::front::wgsl::parse_str(&code).map_err(|inner| {
1525 pipeline::CreateShaderModuleError::Parsing(naga::error::ShaderError {
1526 source: code.to_string(),
1527 label: desc.label.as_ref().map(|l| l.to_string()),
1528 inner: Box::new(inner),
1529 })
1530 })?;
1531 (Cow::Owned(module), code.into_owned())
1532 }
1533 #[cfg(feature = "spirv")]
1534 pipeline::ShaderModuleSource::SpirV(spv, options) => {
1535 let parser = naga::front::spv::Frontend::new(spv.iter().cloned(), &options);
1536 profiling::scope!("naga::front::spv::Frontend");
1537 let module = parser.parse().map_err(|inner| {
1538 pipeline::CreateShaderModuleError::ParsingSpirV(naga::error::ShaderError {
1539 source: String::new(),
1540 label: desc.label.as_ref().map(|l| l.to_string()),
1541 inner: Box::new(inner),
1542 })
1543 })?;
1544 (Cow::Owned(module), String::new())
1545 }
1546 #[cfg(feature = "glsl")]
1547 pipeline::ShaderModuleSource::Glsl(code, options) => {
1548 let mut parser = naga::front::glsl::Frontend::default();
1549 profiling::scope!("naga::front::glsl::Frontend.parse");
1550 let module = parser.parse(&options, &code).map_err(|inner| {
1551 pipeline::CreateShaderModuleError::ParsingGlsl(naga::error::ShaderError {
1552 source: code.to_string(),
1553 label: desc.label.as_ref().map(|l| l.to_string()),
1554 inner: Box::new(inner),
1555 })
1556 })?;
1557 (Cow::Owned(module), code.into_owned())
1558 }
1559 pipeline::ShaderModuleSource::Naga(module) => (module, String::new()),
1560 pipeline::ShaderModuleSource::Dummy(_) => panic!("found `ShaderModuleSource::Dummy`"),
1561 };
1562 for (_, var) in module.global_variables.iter() {
1563 match var.binding {
1564 Some(ref br) if br.group >= self.limits.max_bind_groups => {
1565 return Err(pipeline::CreateShaderModuleError::InvalidGroupIndex {
1566 bind: br.clone(),
1567 group: br.group,
1568 limit: self.limits.max_bind_groups,
1569 });
1570 }
1571 _ => continue,
1572 };
1573 }
1574
1575 profiling::scope!("naga::validate");
1576 let debug_source =
1577 if self.instance_flags.contains(wgt::InstanceFlags::DEBUG) && !source.is_empty() {
1578 Some(hal::DebugSource {
1579 file_name: Cow::Owned(
1580 desc.label
1581 .as_ref()
1582 .map_or("shader".to_string(), |l| l.to_string()),
1583 ),
1584 source_code: Cow::Owned(source.clone()),
1585 })
1586 } else {
1587 None
1588 };
1589
1590 let info = create_validator(
1591 self.features,
1592 self.downlevel.flags,
1593 naga::valid::ValidationFlags::all(),
1594 )
1595 .validate(&module)
1596 .map_err(|inner| {
1597 pipeline::CreateShaderModuleError::Validation(naga::error::ShaderError {
1598 source,
1599 label: desc.label.as_ref().map(|l| l.to_string()),
1600 inner: Box::new(inner),
1601 })
1602 })?;
1603
1604 let interface = validation::Interface::new(&module, &info, self.limits.clone());
1605 let hal_shader = hal::ShaderInput::Naga(hal::NagaShader {
1606 module,
1607 info,
1608 debug_source,
1609 });
1610 let hal_desc = hal::ShaderModuleDescriptor {
1611 label: desc.label.to_hal(self.instance_flags),
1612 runtime_checks: desc.shader_bound_checks.runtime_checks(),
1613 };
1614 let raw = match unsafe { self.raw().create_shader_module(&hal_desc, hal_shader) } {
1615 Ok(raw) => raw,
1616 Err(error) => {
1617 return Err(match error {
1618 hal::ShaderError::Device(error) => {
1619 pipeline::CreateShaderModuleError::Device(self.handle_hal_error(error))
1620 }
1621 hal::ShaderError::Compilation(ref msg) => {
1622 log::error!("Shader error: {}", msg);
1623 pipeline::CreateShaderModuleError::Generation
1624 }
1625 })
1626 }
1627 };
1628
1629 let module = pipeline::ShaderModule {
1630 raw: ManuallyDrop::new(raw),
1631 device: self.clone(),
1632 interface: Some(interface),
1633 label: desc.label.to_string(),
1634 };
1635
1636 let module = Arc::new(module);
1637
1638 Ok(module)
1639 }
1640
1641 #[allow(unused_unsafe)]
1642 pub(crate) unsafe fn create_shader_module_spirv<'a>(
1643 self: &Arc<Self>,
1644 desc: &pipeline::ShaderModuleDescriptor<'a>,
1645 source: &'a [u32],
1646 ) -> Result<Arc<pipeline::ShaderModule>, pipeline::CreateShaderModuleError> {
1647 self.check_is_valid()?;
1648
1649 self.require_features(wgt::Features::SPIRV_SHADER_PASSTHROUGH)?;
1650 let hal_desc = hal::ShaderModuleDescriptor {
1651 label: desc.label.to_hal(self.instance_flags),
1652 runtime_checks: desc.shader_bound_checks.runtime_checks(),
1653 };
1654 let hal_shader = hal::ShaderInput::SpirV(source);
1655 let raw = match unsafe { self.raw().create_shader_module(&hal_desc, hal_shader) } {
1656 Ok(raw) => raw,
1657 Err(error) => {
1658 return Err(match error {
1659 hal::ShaderError::Device(error) => {
1660 pipeline::CreateShaderModuleError::Device(self.handle_hal_error(error))
1661 }
1662 hal::ShaderError::Compilation(ref msg) => {
1663 log::error!("Shader error: {}", msg);
1664 pipeline::CreateShaderModuleError::Generation
1665 }
1666 })
1667 }
1668 };
1669
1670 let module = pipeline::ShaderModule {
1671 raw: ManuallyDrop::new(raw),
1672 device: self.clone(),
1673 interface: None,
1674 label: desc.label.to_string(),
1675 };
1676
1677 let module = Arc::new(module);
1678
1679 Ok(module)
1680 }
1681
1682 pub(crate) fn create_command_encoder(
1683 self: &Arc<Self>,
1684 label: &crate::Label,
1685 ) -> Result<Arc<command::CommandBuffer>, DeviceError> {
1686 self.check_is_valid()?;
1687
1688 let queue = self.get_queue().unwrap();
1689
1690 let encoder = self
1691 .command_allocator
1692 .acquire_encoder(self.raw(), queue.raw())
1693 .map_err(|e| self.handle_hal_error(e))?;
1694
1695 let command_buffer = command::CommandBuffer::new(encoder, self, label);
1696
1697 let command_buffer = Arc::new(command_buffer);
1698
1699 Ok(command_buffer)
1700 }
1701
1702 fn make_late_sized_buffer_groups(
1705 shader_binding_sizes: &FastHashMap<naga::ResourceBinding, wgt::BufferSize>,
1706 layout: &binding_model::PipelineLayout,
1707 ) -> ArrayVec<pipeline::LateSizedBufferGroup, { hal::MAX_BIND_GROUPS }> {
1708 layout
1712 .bind_group_layouts
1713 .iter()
1714 .enumerate()
1715 .map(|(group_index, bgl)| pipeline::LateSizedBufferGroup {
1716 shader_sizes: bgl
1717 .entries
1718 .values()
1719 .filter_map(|entry| match entry.ty {
1720 wgt::BindingType::Buffer {
1721 min_binding_size: None,
1722 ..
1723 } => {
1724 let rb = naga::ResourceBinding {
1725 group: group_index as u32,
1726 binding: entry.binding,
1727 };
1728 let shader_size =
1729 shader_binding_sizes.get(&rb).map_or(0, |nz| nz.get());
1730 Some(shader_size)
1731 }
1732 _ => None,
1733 })
1734 .collect(),
1735 })
1736 .collect()
1737 }
1738
1739 pub(crate) fn create_bind_group_layout(
1740 self: &Arc<Self>,
1741 label: &crate::Label,
1742 entry_map: bgl::EntryMap,
1743 origin: bgl::Origin,
1744 ) -> Result<Arc<BindGroupLayout>, binding_model::CreateBindGroupLayoutError> {
1745 #[derive(PartialEq)]
1746 enum WritableStorage {
1747 Yes,
1748 No,
1749 }
1750
1751 for entry in entry_map.values() {
1752 use wgt::BindingType as Bt;
1753
1754 let mut required_features = wgt::Features::empty();
1755 let mut required_downlevel_flags = wgt::DownlevelFlags::empty();
1756 let (array_feature, writable_storage) = match entry.ty {
1757 Bt::Buffer {
1758 ty: wgt::BufferBindingType::Uniform,
1759 has_dynamic_offset: false,
1760 min_binding_size: _,
1761 } => (
1762 Some(wgt::Features::BUFFER_BINDING_ARRAY),
1763 WritableStorage::No,
1764 ),
1765 Bt::Buffer {
1766 ty: wgt::BufferBindingType::Uniform,
1767 has_dynamic_offset: true,
1768 min_binding_size: _,
1769 } => (
1770 Some(wgt::Features::BUFFER_BINDING_ARRAY),
1771 WritableStorage::No,
1772 ),
1773 Bt::Buffer {
1774 ty: wgt::BufferBindingType::Storage { read_only },
1775 ..
1776 } => (
1777 Some(
1778 wgt::Features::BUFFER_BINDING_ARRAY
1779 | wgt::Features::STORAGE_RESOURCE_BINDING_ARRAY,
1780 ),
1781 match read_only {
1782 true => WritableStorage::No,
1783 false => WritableStorage::Yes,
1784 },
1785 ),
1786 Bt::Sampler { .. } => (
1787 Some(wgt::Features::TEXTURE_BINDING_ARRAY),
1788 WritableStorage::No,
1789 ),
1790 Bt::Texture {
1791 multisampled: true,
1792 sample_type: TextureSampleType::Float { filterable: true },
1793 ..
1794 } => {
1795 return Err(binding_model::CreateBindGroupLayoutError::Entry {
1796 binding: entry.binding,
1797 error:
1798 BindGroupLayoutEntryError::SampleTypeFloatFilterableBindingMultisampled,
1799 });
1800 }
1801 Bt::Texture {
1802 multisampled,
1803 view_dimension,
1804 ..
1805 } => {
1806 if multisampled && view_dimension != TextureViewDimension::D2 {
1807 return Err(binding_model::CreateBindGroupLayoutError::Entry {
1808 binding: entry.binding,
1809 error: BindGroupLayoutEntryError::Non2DMultisampled(view_dimension),
1810 });
1811 }
1812
1813 (
1814 Some(wgt::Features::TEXTURE_BINDING_ARRAY),
1815 WritableStorage::No,
1816 )
1817 }
1818 Bt::StorageTexture {
1819 access,
1820 view_dimension,
1821 format: _,
1822 } => {
1823 match view_dimension {
1824 TextureViewDimension::Cube | TextureViewDimension::CubeArray => {
1825 return Err(binding_model::CreateBindGroupLayoutError::Entry {
1826 binding: entry.binding,
1827 error: BindGroupLayoutEntryError::StorageTextureCube,
1828 })
1829 }
1830 _ => (),
1831 }
1832 match access {
1833 wgt::StorageTextureAccess::ReadOnly
1834 | wgt::StorageTextureAccess::ReadWrite
1835 if !self.features.contains(
1836 wgt::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES,
1837 ) =>
1838 {
1839 return Err(binding_model::CreateBindGroupLayoutError::Entry {
1840 binding: entry.binding,
1841 error: BindGroupLayoutEntryError::StorageTextureReadWrite,
1842 });
1843 }
1844 _ => (),
1845 }
1846 (
1847 Some(
1848 wgt::Features::TEXTURE_BINDING_ARRAY
1849 | wgt::Features::STORAGE_RESOURCE_BINDING_ARRAY,
1850 ),
1851 match access {
1852 wgt::StorageTextureAccess::WriteOnly => WritableStorage::Yes,
1853 wgt::StorageTextureAccess::ReadOnly => {
1854 required_features |=
1855 wgt::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES;
1856 WritableStorage::No
1857 }
1858 wgt::StorageTextureAccess::ReadWrite => {
1859 required_features |=
1860 wgt::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES;
1861 WritableStorage::Yes
1862 }
1863 },
1864 )
1865 }
1866 Bt::AccelerationStructure => todo!(),
1867 };
1868
1869 if entry.count.is_some() {
1871 required_features |= array_feature
1872 .ok_or(BindGroupLayoutEntryError::ArrayUnsupported)
1873 .map_err(|error| binding_model::CreateBindGroupLayoutError::Entry {
1874 binding: entry.binding,
1875 error,
1876 })?;
1877 }
1878
1879 if entry.visibility.contains_invalid_bits() {
1880 return Err(
1881 binding_model::CreateBindGroupLayoutError::InvalidVisibility(entry.visibility),
1882 );
1883 }
1884
1885 if entry.visibility.contains(wgt::ShaderStages::VERTEX) {
1886 if writable_storage == WritableStorage::Yes {
1887 required_features |= wgt::Features::VERTEX_WRITABLE_STORAGE;
1888 }
1889 if let Bt::Buffer {
1890 ty: wgt::BufferBindingType::Storage { .. },
1891 ..
1892 } = entry.ty
1893 {
1894 required_downlevel_flags |= wgt::DownlevelFlags::VERTEX_STORAGE;
1895 }
1896 }
1897 if writable_storage == WritableStorage::Yes
1898 && entry.visibility.contains(wgt::ShaderStages::FRAGMENT)
1899 {
1900 required_downlevel_flags |= wgt::DownlevelFlags::FRAGMENT_WRITABLE_STORAGE;
1901 }
1902
1903 self.require_features(required_features)
1904 .map_err(BindGroupLayoutEntryError::MissingFeatures)
1905 .map_err(|error| binding_model::CreateBindGroupLayoutError::Entry {
1906 binding: entry.binding,
1907 error,
1908 })?;
1909 self.require_downlevel_flags(required_downlevel_flags)
1910 .map_err(BindGroupLayoutEntryError::MissingDownlevelFlags)
1911 .map_err(|error| binding_model::CreateBindGroupLayoutError::Entry {
1912 binding: entry.binding,
1913 error,
1914 })?;
1915 }
1916
1917 let bgl_flags = conv::bind_group_layout_flags(self.features);
1918
1919 let hal_bindings = entry_map.values().copied().collect::<Vec<_>>();
1920 let hal_desc = hal::BindGroupLayoutDescriptor {
1921 label: label.to_hal(self.instance_flags),
1922 flags: bgl_flags,
1923 entries: &hal_bindings,
1924 };
1925
1926 let raw = unsafe { self.raw().create_bind_group_layout(&hal_desc) }
1927 .map_err(|e| self.handle_hal_error(e))?;
1928
1929 let mut count_validator = binding_model::BindingTypeMaxCountValidator::default();
1930 for entry in entry_map.values() {
1931 count_validator.add_binding(entry);
1932 }
1933 count_validator
1936 .validate(&self.limits)
1937 .map_err(binding_model::CreateBindGroupLayoutError::TooManyBindings)?;
1938
1939 let bgl = BindGroupLayout {
1940 raw: ManuallyDrop::new(raw),
1941 device: self.clone(),
1942 entries: entry_map,
1943 origin,
1944 exclusive_pipeline: OnceLock::new(),
1945 binding_count_validator: count_validator,
1946 label: label.to_string(),
1947 };
1948
1949 let bgl = Arc::new(bgl);
1950
1951 Ok(bgl)
1952 }
1953
1954 fn create_buffer_binding<'a>(
1955 &self,
1956 bb: &'a binding_model::ResolvedBufferBinding,
1957 binding: u32,
1958 decl: &wgt::BindGroupLayoutEntry,
1959 used_buffer_ranges: &mut Vec<BufferInitTrackerAction>,
1960 dynamic_binding_info: &mut Vec<binding_model::BindGroupDynamicBindingData>,
1961 late_buffer_binding_sizes: &mut FastHashMap<u32, wgt::BufferSize>,
1962 used: &mut BindGroupStates,
1963 snatch_guard: &'a SnatchGuard<'a>,
1964 ) -> Result<hal::BufferBinding<'a, dyn hal::DynBuffer>, binding_model::CreateBindGroupError>
1965 {
1966 use crate::binding_model::CreateBindGroupError as Error;
1967
1968 let (binding_ty, dynamic, min_size) = match decl.ty {
1969 wgt::BindingType::Buffer {
1970 ty,
1971 has_dynamic_offset,
1972 min_binding_size,
1973 } => (ty, has_dynamic_offset, min_binding_size),
1974 _ => {
1975 return Err(Error::WrongBindingType {
1976 binding,
1977 actual: decl.ty,
1978 expected: "UniformBuffer, StorageBuffer or ReadonlyStorageBuffer",
1979 })
1980 }
1981 };
1982
1983 let (pub_usage, internal_use, range_limit) = match binding_ty {
1984 wgt::BufferBindingType::Uniform => (
1985 wgt::BufferUsages::UNIFORM,
1986 hal::BufferUses::UNIFORM,
1987 self.limits.max_uniform_buffer_binding_size,
1988 ),
1989 wgt::BufferBindingType::Storage { read_only } => (
1990 wgt::BufferUsages::STORAGE,
1991 if read_only {
1992 hal::BufferUses::STORAGE_READ
1993 } else {
1994 hal::BufferUses::STORAGE_READ_WRITE
1995 },
1996 self.limits.max_storage_buffer_binding_size,
1997 ),
1998 };
1999
2000 let (align, align_limit_name) =
2001 binding_model::buffer_binding_type_alignment(&self.limits, binding_ty);
2002 if bb.offset % align as u64 != 0 {
2003 return Err(Error::UnalignedBufferOffset(
2004 bb.offset,
2005 align_limit_name,
2006 align,
2007 ));
2008 }
2009
2010 let buffer = &bb.buffer;
2011
2012 used.buffers.insert_single(buffer.clone(), internal_use);
2013
2014 buffer.same_device(self)?;
2015
2016 buffer.check_usage(pub_usage)?;
2017 let raw_buffer = buffer.try_raw(snatch_guard)?;
2018
2019 let (bind_size, bind_end) = match bb.size {
2020 Some(size) => {
2021 let end = bb.offset + size.get();
2022 if end > buffer.size {
2023 return Err(Error::BindingRangeTooLarge {
2024 buffer: buffer.error_ident(),
2025 range: bb.offset..end,
2026 size: buffer.size,
2027 });
2028 }
2029 (size.get(), end)
2030 }
2031 None => {
2032 if buffer.size < bb.offset {
2033 return Err(Error::BindingRangeTooLarge {
2034 buffer: buffer.error_ident(),
2035 range: bb.offset..bb.offset,
2036 size: buffer.size,
2037 });
2038 }
2039 (buffer.size - bb.offset, buffer.size)
2040 }
2041 };
2042
2043 if bind_size > range_limit as u64 {
2044 return Err(Error::BufferRangeTooLarge {
2045 binding,
2046 given: bind_size as u32,
2047 limit: range_limit,
2048 });
2049 }
2050
2051 if dynamic {
2053 dynamic_binding_info.push(binding_model::BindGroupDynamicBindingData {
2054 binding_idx: binding,
2055 buffer_size: buffer.size,
2056 binding_range: bb.offset..bind_end,
2057 maximum_dynamic_offset: buffer.size - bind_end,
2058 binding_type: binding_ty,
2059 });
2060 }
2061
2062 if let Some(non_zero) = min_size {
2063 let min_size = non_zero.get();
2064 if min_size > bind_size {
2065 return Err(Error::BindingSizeTooSmall {
2066 buffer: buffer.error_ident(),
2067 actual: bind_size,
2068 min: min_size,
2069 });
2070 }
2071 } else {
2072 let late_size = wgt::BufferSize::new(bind_size)
2073 .ok_or_else(|| Error::BindingZeroSize(buffer.error_ident()))?;
2074 late_buffer_binding_sizes.insert(binding, late_size);
2075 }
2076
2077 assert_eq!(bb.offset % wgt::COPY_BUFFER_ALIGNMENT, 0);
2080
2081 let bounds_check_alignment =
2086 binding_model::buffer_binding_type_bounds_check_alignment(&self.alignments, binding_ty);
2087 let visible_size = align_to(bind_size, bounds_check_alignment);
2088
2089 used_buffer_ranges.extend(buffer.initialization_status.read().create_action(
2090 buffer,
2091 bb.offset..bb.offset + visible_size,
2092 MemoryInitKind::NeedsInitializedMemory,
2093 ));
2094
2095 Ok(hal::BufferBinding {
2096 buffer: raw_buffer,
2097 offset: bb.offset,
2098 size: bb.size,
2099 })
2100 }
2101
2102 fn create_sampler_binding<'a>(
2103 &self,
2104 used: &mut BindGroupStates,
2105 binding: u32,
2106 decl: &wgt::BindGroupLayoutEntry,
2107 sampler: &'a Arc<Sampler>,
2108 ) -> Result<&'a dyn hal::DynSampler, binding_model::CreateBindGroupError> {
2109 use crate::binding_model::CreateBindGroupError as Error;
2110
2111 used.samplers.insert_single(sampler.clone());
2112
2113 sampler.same_device(self)?;
2114
2115 match decl.ty {
2116 wgt::BindingType::Sampler(ty) => {
2117 let (allowed_filtering, allowed_comparison) = match ty {
2118 wgt::SamplerBindingType::Filtering => (None, false),
2119 wgt::SamplerBindingType::NonFiltering => (Some(false), false),
2120 wgt::SamplerBindingType::Comparison => (None, true),
2121 };
2122 if let Some(allowed_filtering) = allowed_filtering {
2123 if allowed_filtering != sampler.filtering {
2124 return Err(Error::WrongSamplerFiltering {
2125 binding,
2126 layout_flt: allowed_filtering,
2127 sampler_flt: sampler.filtering,
2128 });
2129 }
2130 }
2131 if allowed_comparison != sampler.comparison {
2132 return Err(Error::WrongSamplerComparison {
2133 binding,
2134 layout_cmp: allowed_comparison,
2135 sampler_cmp: sampler.comparison,
2136 });
2137 }
2138 }
2139 _ => {
2140 return Err(Error::WrongBindingType {
2141 binding,
2142 actual: decl.ty,
2143 expected: "Sampler",
2144 })
2145 }
2146 }
2147
2148 Ok(sampler.raw())
2149 }
2150
2151 fn create_texture_binding<'a>(
2152 &self,
2153 binding: u32,
2154 decl: &wgt::BindGroupLayoutEntry,
2155 view: &'a Arc<TextureView>,
2156 used: &mut BindGroupStates,
2157 used_texture_ranges: &mut Vec<TextureInitTrackerAction>,
2158 snatch_guard: &'a SnatchGuard<'a>,
2159 ) -> Result<hal::TextureBinding<'a, dyn hal::DynTextureView>, binding_model::CreateBindGroupError>
2160 {
2161 view.same_device(self)?;
2162
2163 let (pub_usage, internal_use) = self.texture_use_parameters(
2164 binding,
2165 decl,
2166 view,
2167 "SampledTexture, ReadonlyStorageTexture or WriteonlyStorageTexture",
2168 )?;
2169
2170 used.views.insert_single(view.clone(), internal_use);
2171
2172 let texture = &view.parent;
2173 texture.check_usage(pub_usage)?;
2174
2175 used_texture_ranges.push(TextureInitTrackerAction {
2176 texture: texture.clone(),
2177 range: TextureInitRange {
2178 mip_range: view.desc.range.mip_range(texture.desc.mip_level_count),
2179 layer_range: view
2180 .desc
2181 .range
2182 .layer_range(texture.desc.array_layer_count()),
2183 },
2184 kind: MemoryInitKind::NeedsInitializedMemory,
2185 });
2186
2187 Ok(hal::TextureBinding {
2188 view: view.try_raw(snatch_guard)?,
2189 usage: internal_use,
2190 })
2191 }
2192
2193 pub(crate) fn create_bind_group(
2196 self: &Arc<Self>,
2197 desc: binding_model::ResolvedBindGroupDescriptor,
2198 ) -> Result<Arc<BindGroup>, binding_model::CreateBindGroupError> {
2199 use crate::binding_model::{CreateBindGroupError as Error, ResolvedBindingResource as Br};
2200
2201 let layout = desc.layout;
2202
2203 self.check_is_valid()?;
2204 layout.same_device(self)?;
2205
2206 {
2207 let actual = desc.entries.len();
2210 let expected = layout.entries.len();
2211 if actual != expected {
2212 return Err(Error::BindingsNumMismatch { expected, actual });
2213 }
2214 }
2215
2216 let mut dynamic_binding_info = Vec::new();
2219 let mut late_buffer_binding_sizes = FastHashMap::default();
2223 let mut used = BindGroupStates::new();
2225
2226 let mut used_buffer_ranges = Vec::new();
2227 let mut used_texture_ranges = Vec::new();
2228 let mut hal_entries = Vec::with_capacity(desc.entries.len());
2229 let mut hal_buffers = Vec::new();
2230 let mut hal_samplers = Vec::new();
2231 let mut hal_textures = Vec::new();
2232 let snatch_guard = self.snatchable_lock.read();
2233 for entry in desc.entries.iter() {
2234 let binding = entry.binding;
2235 let decl = layout
2237 .entries
2238 .get(binding)
2239 .ok_or(Error::MissingBindingDeclaration(binding))?;
2240 let (res_index, count) = match entry.resource {
2241 Br::Buffer(ref bb) => {
2242 let bb = self.create_buffer_binding(
2243 bb,
2244 binding,
2245 decl,
2246 &mut used_buffer_ranges,
2247 &mut dynamic_binding_info,
2248 &mut late_buffer_binding_sizes,
2249 &mut used,
2250 &snatch_guard,
2251 )?;
2252
2253 let res_index = hal_buffers.len();
2254 hal_buffers.push(bb);
2255 (res_index, 1)
2256 }
2257 Br::BufferArray(ref bindings_array) => {
2258 let num_bindings = bindings_array.len();
2259 Self::check_array_binding(self.features, decl.count, num_bindings)?;
2260
2261 let res_index = hal_buffers.len();
2262 for bb in bindings_array.iter() {
2263 let bb = self.create_buffer_binding(
2264 bb,
2265 binding,
2266 decl,
2267 &mut used_buffer_ranges,
2268 &mut dynamic_binding_info,
2269 &mut late_buffer_binding_sizes,
2270 &mut used,
2271 &snatch_guard,
2272 )?;
2273 hal_buffers.push(bb);
2274 }
2275 (res_index, num_bindings)
2276 }
2277 Br::Sampler(ref sampler) => {
2278 let sampler = self.create_sampler_binding(&mut used, binding, decl, sampler)?;
2279
2280 let res_index = hal_samplers.len();
2281 hal_samplers.push(sampler);
2282 (res_index, 1)
2283 }
2284 Br::SamplerArray(ref samplers) => {
2285 let num_bindings = samplers.len();
2286 Self::check_array_binding(self.features, decl.count, num_bindings)?;
2287
2288 let res_index = hal_samplers.len();
2289 for sampler in samplers.iter() {
2290 let sampler =
2291 self.create_sampler_binding(&mut used, binding, decl, sampler)?;
2292
2293 hal_samplers.push(sampler);
2294 }
2295
2296 (res_index, num_bindings)
2297 }
2298 Br::TextureView(ref view) => {
2299 let tb = self.create_texture_binding(
2300 binding,
2301 decl,
2302 view,
2303 &mut used,
2304 &mut used_texture_ranges,
2305 &snatch_guard,
2306 )?;
2307 let res_index = hal_textures.len();
2308 hal_textures.push(tb);
2309 (res_index, 1)
2310 }
2311 Br::TextureViewArray(ref views) => {
2312 let num_bindings = views.len();
2313 Self::check_array_binding(self.features, decl.count, num_bindings)?;
2314
2315 let res_index = hal_textures.len();
2316 for view in views.iter() {
2317 let tb = self.create_texture_binding(
2318 binding,
2319 decl,
2320 view,
2321 &mut used,
2322 &mut used_texture_ranges,
2323 &snatch_guard,
2324 )?;
2325
2326 hal_textures.push(tb);
2327 }
2328
2329 (res_index, num_bindings)
2330 }
2331 };
2332
2333 hal_entries.push(hal::BindGroupEntry {
2334 binding,
2335 resource_index: res_index as u32,
2336 count: count as u32,
2337 });
2338 }
2339
2340 used.optimize();
2341
2342 hal_entries.sort_by_key(|entry| entry.binding);
2343 for (a, b) in hal_entries.iter().zip(hal_entries.iter().skip(1)) {
2344 if a.binding == b.binding {
2345 return Err(Error::DuplicateBinding(a.binding));
2346 }
2347 }
2348 let hal_desc = hal::BindGroupDescriptor {
2349 label: desc.label.to_hal(self.instance_flags),
2350 layout: layout.raw(),
2351 entries: &hal_entries,
2352 buffers: &hal_buffers,
2353 samplers: &hal_samplers,
2354 textures: &hal_textures,
2355 acceleration_structures: &[],
2356 };
2357 let raw = unsafe { self.raw().create_bind_group(&hal_desc) }
2358 .map_err(|e| self.handle_hal_error(e))?;
2359
2360 let late_buffer_binding_sizes = layout
2362 .entries
2363 .indices()
2364 .flat_map(|binding| late_buffer_binding_sizes.get(&binding).cloned())
2365 .collect();
2366
2367 let bind_group = BindGroup {
2368 raw: Snatchable::new(raw),
2369 device: self.clone(),
2370 layout,
2371 label: desc.label.to_string(),
2372 tracking_data: TrackingData::new(self.tracker_indices.bind_groups.clone()),
2373 used,
2374 used_buffer_ranges,
2375 used_texture_ranges,
2376 dynamic_binding_info,
2377 late_buffer_binding_sizes,
2378 };
2379
2380 let bind_group = Arc::new(bind_group);
2381
2382 let weak_ref = Arc::downgrade(&bind_group);
2383 for range in &bind_group.used_texture_ranges {
2384 let mut bind_groups = range.texture.bind_groups.lock();
2385 bind_groups.push(weak_ref.clone());
2386 }
2387 for range in &bind_group.used_buffer_ranges {
2388 let mut bind_groups = range.buffer.bind_groups.lock();
2389 bind_groups.push(weak_ref.clone());
2390 }
2391
2392 Ok(bind_group)
2393 }
2394
2395 fn check_array_binding(
2396 features: wgt::Features,
2397 count: Option<NonZeroU32>,
2398 num_bindings: usize,
2399 ) -> Result<(), binding_model::CreateBindGroupError> {
2400 use super::binding_model::CreateBindGroupError as Error;
2401
2402 if let Some(count) = count {
2403 let count = count.get() as usize;
2404 if count < num_bindings {
2405 return Err(Error::BindingArrayPartialLengthMismatch {
2406 actual: num_bindings,
2407 expected: count,
2408 });
2409 }
2410 if count != num_bindings
2411 && !features.contains(wgt::Features::PARTIALLY_BOUND_BINDING_ARRAY)
2412 {
2413 return Err(Error::BindingArrayLengthMismatch {
2414 actual: num_bindings,
2415 expected: count,
2416 });
2417 }
2418 if num_bindings == 0 {
2419 return Err(Error::BindingArrayZeroLength);
2420 }
2421 } else {
2422 return Err(Error::SingleBindingExpected);
2423 };
2424
2425 Ok(())
2426 }
2427
2428 fn texture_use_parameters(
2429 &self,
2430 binding: u32,
2431 decl: &wgt::BindGroupLayoutEntry,
2432 view: &TextureView,
2433 expected: &'static str,
2434 ) -> Result<(wgt::TextureUsages, hal::TextureUses), binding_model::CreateBindGroupError> {
2435 use crate::binding_model::CreateBindGroupError as Error;
2436 if view
2437 .desc
2438 .aspects()
2439 .contains(hal::FormatAspects::DEPTH | hal::FormatAspects::STENCIL)
2440 {
2441 return Err(Error::DepthStencilAspect);
2442 }
2443 match decl.ty {
2444 wgt::BindingType::Texture {
2445 sample_type,
2446 view_dimension,
2447 multisampled,
2448 } => {
2449 use wgt::TextureSampleType as Tst;
2450 if multisampled != (view.samples != 1) {
2451 return Err(Error::InvalidTextureMultisample {
2452 binding,
2453 layout_multisampled: multisampled,
2454 view_samples: view.samples,
2455 });
2456 }
2457 let compat_sample_type = view
2458 .desc
2459 .format
2460 .sample_type(Some(view.desc.range.aspect), Some(self.features))
2461 .unwrap();
2462 match (sample_type, compat_sample_type) {
2463 (Tst::Uint, Tst::Uint) |
2464 (Tst::Sint, Tst::Sint) |
2465 (Tst::Depth, Tst::Depth) |
2466 (Tst::Float { filterable: false }, Tst::Float { .. }) |
2468 (Tst::Float { filterable: true }, Tst::Float { filterable: true }) |
2470 (Tst::Float { filterable: false }, Tst::Depth) => {}
2472 (Tst::Float { filterable: true }, Tst::Float { .. }) if view.format_features.flags.contains(wgt::TextureFormatFeatureFlags::FILTERABLE) => {}
2477 _ => {
2478 return Err(Error::InvalidTextureSampleType {
2479 binding,
2480 layout_sample_type: sample_type,
2481 view_format: view.desc.format,
2482 })
2483 }
2484 }
2485 if view_dimension != view.desc.dimension {
2486 return Err(Error::InvalidTextureDimension {
2487 binding,
2488 layout_dimension: view_dimension,
2489 view_dimension: view.desc.dimension,
2490 });
2491 }
2492 Ok((
2493 wgt::TextureUsages::TEXTURE_BINDING,
2494 hal::TextureUses::RESOURCE,
2495 ))
2496 }
2497 wgt::BindingType::StorageTexture {
2498 access,
2499 format,
2500 view_dimension,
2501 } => {
2502 if format != view.desc.format {
2503 return Err(Error::InvalidStorageTextureFormat {
2504 binding,
2505 layout_format: format,
2506 view_format: view.desc.format,
2507 });
2508 }
2509 if view_dimension != view.desc.dimension {
2510 return Err(Error::InvalidTextureDimension {
2511 binding,
2512 layout_dimension: view_dimension,
2513 view_dimension: view.desc.dimension,
2514 });
2515 }
2516
2517 let mip_level_count = view.selector.mips.end - view.selector.mips.start;
2518 if mip_level_count != 1 {
2519 return Err(Error::InvalidStorageTextureMipLevelCount {
2520 binding,
2521 mip_level_count,
2522 });
2523 }
2524
2525 let internal_use = match access {
2526 wgt::StorageTextureAccess::WriteOnly => hal::TextureUses::STORAGE_READ_WRITE,
2527 wgt::StorageTextureAccess::ReadOnly => {
2528 if !view
2529 .format_features
2530 .flags
2531 .contains(wgt::TextureFormatFeatureFlags::STORAGE_READ_WRITE)
2532 {
2533 return Err(Error::StorageReadNotSupported(view.desc.format));
2534 }
2535 hal::TextureUses::STORAGE_READ
2536 }
2537 wgt::StorageTextureAccess::ReadWrite => {
2538 if !view
2539 .format_features
2540 .flags
2541 .contains(wgt::TextureFormatFeatureFlags::STORAGE_READ_WRITE)
2542 {
2543 return Err(Error::StorageReadNotSupported(view.desc.format));
2544 }
2545
2546 hal::TextureUses::STORAGE_READ_WRITE
2547 }
2548 };
2549 Ok((wgt::TextureUsages::STORAGE_BINDING, internal_use))
2550 }
2551 _ => Err(Error::WrongBindingType {
2552 binding,
2553 actual: decl.ty,
2554 expected,
2555 }),
2556 }
2557 }
2558
2559 pub(crate) fn create_pipeline_layout(
2560 self: &Arc<Self>,
2561 desc: &binding_model::ResolvedPipelineLayoutDescriptor,
2562 ) -> Result<Arc<binding_model::PipelineLayout>, binding_model::CreatePipelineLayoutError> {
2563 use crate::binding_model::CreatePipelineLayoutError as Error;
2564
2565 self.check_is_valid()?;
2566
2567 let bind_group_layouts_count = desc.bind_group_layouts.len();
2568 let device_max_bind_groups = self.limits.max_bind_groups as usize;
2569 if bind_group_layouts_count > device_max_bind_groups {
2570 return Err(Error::TooManyGroups {
2571 actual: bind_group_layouts_count,
2572 max: device_max_bind_groups,
2573 });
2574 }
2575
2576 if !desc.push_constant_ranges.is_empty() {
2577 self.require_features(wgt::Features::PUSH_CONSTANTS)?;
2578 }
2579
2580 let mut used_stages = wgt::ShaderStages::empty();
2581 for (index, pc) in desc.push_constant_ranges.iter().enumerate() {
2582 if pc.stages.intersects(used_stages) {
2583 return Err(Error::MoreThanOnePushConstantRangePerStage {
2584 index,
2585 provided: pc.stages,
2586 intersected: pc.stages & used_stages,
2587 });
2588 }
2589 used_stages |= pc.stages;
2590
2591 let device_max_pc_size = self.limits.max_push_constant_size;
2592 if device_max_pc_size < pc.range.end {
2593 return Err(Error::PushConstantRangeTooLarge {
2594 index,
2595 range: pc.range.clone(),
2596 max: device_max_pc_size,
2597 });
2598 }
2599
2600 if pc.range.start % wgt::PUSH_CONSTANT_ALIGNMENT != 0 {
2601 return Err(Error::MisalignedPushConstantRange {
2602 index,
2603 bound: pc.range.start,
2604 });
2605 }
2606 if pc.range.end % wgt::PUSH_CONSTANT_ALIGNMENT != 0 {
2607 return Err(Error::MisalignedPushConstantRange {
2608 index,
2609 bound: pc.range.end,
2610 });
2611 }
2612 }
2613
2614 let mut count_validator = binding_model::BindingTypeMaxCountValidator::default();
2615
2616 for bgl in desc.bind_group_layouts.iter() {
2617 bgl.same_device(self)?;
2618 count_validator.merge(&bgl.binding_count_validator);
2619 }
2620
2621 count_validator
2622 .validate(&self.limits)
2623 .map_err(Error::TooManyBindings)?;
2624
2625 let bind_group_layouts = desc
2626 .bind_group_layouts
2627 .iter()
2628 .cloned()
2629 .collect::<ArrayVec<_, { hal::MAX_BIND_GROUPS }>>();
2630
2631 let raw_bind_group_layouts = desc
2632 .bind_group_layouts
2633 .iter()
2634 .map(|bgl| bgl.raw())
2635 .collect::<ArrayVec<_, { hal::MAX_BIND_GROUPS }>>();
2636
2637 let hal_desc = hal::PipelineLayoutDescriptor {
2638 label: desc.label.to_hal(self.instance_flags),
2639 flags: hal::PipelineLayoutFlags::FIRST_VERTEX_INSTANCE
2640 | hal::PipelineLayoutFlags::NUM_WORK_GROUPS,
2641 bind_group_layouts: &raw_bind_group_layouts,
2642 push_constant_ranges: desc.push_constant_ranges.as_ref(),
2643 };
2644
2645 let raw = unsafe { self.raw().create_pipeline_layout(&hal_desc) }
2646 .map_err(|e| self.handle_hal_error(e))?;
2647
2648 drop(raw_bind_group_layouts);
2649
2650 let layout = binding_model::PipelineLayout {
2651 raw: ManuallyDrop::new(raw),
2652 device: self.clone(),
2653 label: desc.label.to_string(),
2654 bind_group_layouts,
2655 push_constant_ranges: desc.push_constant_ranges.iter().cloned().collect(),
2656 };
2657
2658 let layout = Arc::new(layout);
2659
2660 Ok(layout)
2661 }
2662
2663 pub(crate) fn derive_pipeline_layout(
2664 self: &Arc<Self>,
2665 mut derived_group_layouts: ArrayVec<bgl::EntryMap, { hal::MAX_BIND_GROUPS }>,
2666 ) -> Result<Arc<binding_model::PipelineLayout>, pipeline::ImplicitLayoutError> {
2667 while derived_group_layouts
2668 .last()
2669 .map_or(false, |map| map.is_empty())
2670 {
2671 derived_group_layouts.pop();
2672 }
2673
2674 let mut unique_bind_group_layouts = PreHashedMap::default();
2675
2676 let bind_group_layouts = derived_group_layouts
2677 .into_iter()
2678 .map(|mut bgl_entry_map| {
2679 bgl_entry_map.sort();
2680 match unique_bind_group_layouts.entry(PreHashedKey::from_key(&bgl_entry_map)) {
2681 std::collections::hash_map::Entry::Occupied(v) => Ok(Arc::clone(v.get())),
2682 std::collections::hash_map::Entry::Vacant(e) => {
2683 match self.create_bind_group_layout(
2684 &None,
2685 bgl_entry_map,
2686 bgl::Origin::Derived,
2687 ) {
2688 Ok(bgl) => {
2689 e.insert(bgl.clone());
2690 Ok(bgl)
2691 }
2692 Err(e) => Err(e),
2693 }
2694 }
2695 }
2696 })
2697 .collect::<Result<Vec<_>, _>>()?;
2698
2699 let layout_desc = binding_model::ResolvedPipelineLayoutDescriptor {
2700 label: None,
2701 bind_group_layouts: Cow::Owned(bind_group_layouts),
2702 push_constant_ranges: Cow::Borrowed(&[]), };
2704
2705 let layout = self.create_pipeline_layout(&layout_desc)?;
2706 Ok(layout)
2707 }
2708
2709 pub(crate) fn create_compute_pipeline(
2710 self: &Arc<Self>,
2711 desc: pipeline::ResolvedComputePipelineDescriptor,
2712 ) -> Result<Arc<pipeline::ComputePipeline>, pipeline::CreateComputePipelineError> {
2713 self.check_is_valid()?;
2714
2715 self.require_downlevel_flags(wgt::DownlevelFlags::COMPUTE_SHADERS)?;
2716
2717 let shader_module = desc.stage.module;
2718
2719 shader_module.same_device(self)?;
2720
2721 let is_auto_layout = desc.layout.is_none();
2722
2723 let pipeline_layout = match desc.layout {
2725 Some(pipeline_layout) => {
2726 pipeline_layout.same_device(self)?;
2727 Some(pipeline_layout)
2728 }
2729 None => None,
2730 };
2731
2732 let mut binding_layout_source = match pipeline_layout {
2733 Some(ref pipeline_layout) => {
2734 validation::BindingLayoutSource::Provided(pipeline_layout.get_binding_maps())
2735 }
2736 None => validation::BindingLayoutSource::new_derived(&self.limits),
2737 };
2738 let mut shader_binding_sizes = FastHashMap::default();
2739 let io = validation::StageIo::default();
2740
2741 let final_entry_point_name;
2742
2743 {
2744 let stage = wgt::ShaderStages::COMPUTE;
2745
2746 final_entry_point_name = shader_module.finalize_entry_point_name(
2747 stage,
2748 desc.stage.entry_point.as_ref().map(|ep| ep.as_ref()),
2749 )?;
2750
2751 if let Some(ref interface) = shader_module.interface {
2752 let _ = interface.check_stage(
2753 &mut binding_layout_source,
2754 &mut shader_binding_sizes,
2755 &final_entry_point_name,
2756 stage,
2757 io,
2758 None,
2759 )?;
2760 }
2761 }
2762
2763 let pipeline_layout = match binding_layout_source {
2764 validation::BindingLayoutSource::Provided(_) => {
2765 drop(binding_layout_source);
2766 pipeline_layout.unwrap()
2767 }
2768 validation::BindingLayoutSource::Derived(entries) => {
2769 self.derive_pipeline_layout(entries)?
2770 }
2771 };
2772
2773 let late_sized_buffer_groups =
2774 Device::make_late_sized_buffer_groups(&shader_binding_sizes, &pipeline_layout);
2775
2776 let cache = match desc.cache {
2777 Some(cache) => {
2778 cache.same_device(self)?;
2779 Some(cache)
2780 }
2781 None => None,
2782 };
2783
2784 let pipeline_desc = hal::ComputePipelineDescriptor {
2785 label: desc.label.to_hal(self.instance_flags),
2786 layout: pipeline_layout.raw(),
2787 stage: hal::ProgrammableStage {
2788 module: shader_module.raw(),
2789 entry_point: final_entry_point_name.as_ref(),
2790 constants: desc.stage.constants.as_ref(),
2791 zero_initialize_workgroup_memory: desc.stage.zero_initialize_workgroup_memory,
2792 },
2793 cache: cache.as_ref().map(|it| it.raw()),
2794 };
2795
2796 let raw =
2797 unsafe { self.raw().create_compute_pipeline(&pipeline_desc) }.map_err(
2798 |err| match err {
2799 hal::PipelineError::Device(error) => {
2800 pipeline::CreateComputePipelineError::Device(self.handle_hal_error(error))
2801 }
2802 hal::PipelineError::Linkage(_stages, msg) => {
2803 pipeline::CreateComputePipelineError::Internal(msg)
2804 }
2805 hal::PipelineError::EntryPoint(_stage) => {
2806 pipeline::CreateComputePipelineError::Internal(
2807 ENTRYPOINT_FAILURE_ERROR.to_string(),
2808 )
2809 }
2810 hal::PipelineError::PipelineConstants(_stages, msg) => {
2811 pipeline::CreateComputePipelineError::PipelineConstants(msg)
2812 }
2813 },
2814 )?;
2815
2816 let pipeline = pipeline::ComputePipeline {
2817 raw: ManuallyDrop::new(raw),
2818 layout: pipeline_layout,
2819 device: self.clone(),
2820 _shader_module: shader_module,
2821 late_sized_buffer_groups,
2822 label: desc.label.to_string(),
2823 tracking_data: TrackingData::new(self.tracker_indices.compute_pipelines.clone()),
2824 };
2825
2826 let pipeline = Arc::new(pipeline);
2827
2828 if is_auto_layout {
2829 for bgl in pipeline.layout.bind_group_layouts.iter() {
2830 let _ = bgl
2832 .exclusive_pipeline
2833 .set(binding_model::ExclusivePipeline::Compute(Arc::downgrade(
2834 &pipeline,
2835 )));
2836 }
2837 }
2838
2839 Ok(pipeline)
2840 }
2841
2842 pub(crate) fn create_render_pipeline(
2843 self: &Arc<Self>,
2844 desc: pipeline::ResolvedRenderPipelineDescriptor,
2845 ) -> Result<Arc<pipeline::RenderPipeline>, pipeline::CreateRenderPipelineError> {
2846 use wgt::TextureFormatFeatureFlags as Tfff;
2847
2848 self.check_is_valid()?;
2849
2850 let mut shader_binding_sizes = FastHashMap::default();
2851
2852 let num_attachments = desc.fragment.as_ref().map(|f| f.targets.len()).unwrap_or(0);
2853 let max_attachments = self.limits.max_color_attachments as usize;
2854 if num_attachments > max_attachments {
2855 return Err(pipeline::CreateRenderPipelineError::ColorAttachment(
2856 command::ColorAttachmentError::TooMany {
2857 given: num_attachments,
2858 limit: max_attachments,
2859 },
2860 ));
2861 }
2862
2863 let color_targets = desc
2864 .fragment
2865 .as_ref()
2866 .map_or(&[][..], |fragment| &fragment.targets);
2867 let depth_stencil_state = desc.depth_stencil.as_ref();
2868
2869 {
2870 let cts: ArrayVec<_, { hal::MAX_COLOR_ATTACHMENTS }> =
2871 color_targets.iter().filter_map(|x| x.as_ref()).collect();
2872 if !cts.is_empty() && {
2873 let first = &cts[0];
2874 cts[1..]
2875 .iter()
2876 .any(|ct| ct.write_mask != first.write_mask || ct.blend != first.blend)
2877 } {
2878 self.require_downlevel_flags(wgt::DownlevelFlags::INDEPENDENT_BLEND)?;
2879 }
2880 }
2881
2882 let mut io = validation::StageIo::default();
2883 let mut validated_stages = wgt::ShaderStages::empty();
2884
2885 let mut vertex_steps = Vec::with_capacity(desc.vertex.buffers.len());
2886 let mut vertex_buffers = Vec::with_capacity(desc.vertex.buffers.len());
2887 let mut total_attributes = 0;
2888 let mut shader_expects_dual_source_blending = false;
2889 let mut pipeline_expects_dual_source_blending = false;
2890 for (i, vb_state) in desc.vertex.buffers.iter().enumerate() {
2891 let mut last_stride = 0;
2892 for attribute in vb_state.attributes.iter() {
2893 last_stride = last_stride.max(attribute.offset + attribute.format.size());
2894 }
2895 vertex_steps.push(pipeline::VertexStep {
2896 stride: vb_state.array_stride,
2897 last_stride,
2898 mode: vb_state.step_mode,
2899 });
2900 if vb_state.attributes.is_empty() {
2901 continue;
2902 }
2903 if vb_state.array_stride > self.limits.max_vertex_buffer_array_stride as u64 {
2904 return Err(pipeline::CreateRenderPipelineError::VertexStrideTooLarge {
2905 index: i as u32,
2906 given: vb_state.array_stride as u32,
2907 limit: self.limits.max_vertex_buffer_array_stride,
2908 });
2909 }
2910 if vb_state.array_stride % wgt::VERTEX_STRIDE_ALIGNMENT != 0 {
2911 return Err(pipeline::CreateRenderPipelineError::UnalignedVertexStride {
2912 index: i as u32,
2913 stride: vb_state.array_stride,
2914 });
2915 }
2916 vertex_buffers.push(hal::VertexBufferLayout {
2917 array_stride: vb_state.array_stride,
2918 step_mode: vb_state.step_mode,
2919 attributes: vb_state.attributes.as_ref(),
2920 });
2921
2922 for attribute in vb_state.attributes.iter() {
2923 if attribute.offset >= 0x10000000 {
2924 return Err(
2925 pipeline::CreateRenderPipelineError::InvalidVertexAttributeOffset {
2926 location: attribute.shader_location,
2927 offset: attribute.offset,
2928 },
2929 );
2930 }
2931
2932 if let wgt::VertexFormat::Float64
2933 | wgt::VertexFormat::Float64x2
2934 | wgt::VertexFormat::Float64x3
2935 | wgt::VertexFormat::Float64x4 = attribute.format
2936 {
2937 self.require_features(wgt::Features::VERTEX_ATTRIBUTE_64BIT)?;
2938 }
2939
2940 let previous = io.insert(
2941 attribute.shader_location,
2942 validation::InterfaceVar::vertex_attribute(attribute.format),
2943 );
2944
2945 if previous.is_some() {
2946 return Err(pipeline::CreateRenderPipelineError::ShaderLocationClash(
2947 attribute.shader_location,
2948 ));
2949 }
2950 }
2951 total_attributes += vb_state.attributes.len();
2952 }
2953
2954 if vertex_buffers.len() > self.limits.max_vertex_buffers as usize {
2955 return Err(pipeline::CreateRenderPipelineError::TooManyVertexBuffers {
2956 given: vertex_buffers.len() as u32,
2957 limit: self.limits.max_vertex_buffers,
2958 });
2959 }
2960 if total_attributes > self.limits.max_vertex_attributes as usize {
2961 return Err(
2962 pipeline::CreateRenderPipelineError::TooManyVertexAttributes {
2963 given: total_attributes as u32,
2964 limit: self.limits.max_vertex_attributes,
2965 },
2966 );
2967 }
2968
2969 if desc.primitive.strip_index_format.is_some() && !desc.primitive.topology.is_strip() {
2970 return Err(
2971 pipeline::CreateRenderPipelineError::StripIndexFormatForNonStripTopology {
2972 strip_index_format: desc.primitive.strip_index_format,
2973 topology: desc.primitive.topology,
2974 },
2975 );
2976 }
2977
2978 if desc.primitive.unclipped_depth {
2979 self.require_features(wgt::Features::DEPTH_CLIP_CONTROL)?;
2980 }
2981
2982 if desc.primitive.polygon_mode == wgt::PolygonMode::Line {
2983 self.require_features(wgt::Features::POLYGON_MODE_LINE)?;
2984 }
2985 if desc.primitive.polygon_mode == wgt::PolygonMode::Point {
2986 self.require_features(wgt::Features::POLYGON_MODE_POINT)?;
2987 }
2988
2989 if desc.primitive.conservative {
2990 self.require_features(wgt::Features::CONSERVATIVE_RASTERIZATION)?;
2991 }
2992
2993 if desc.primitive.conservative && desc.primitive.polygon_mode != wgt::PolygonMode::Fill {
2994 return Err(
2995 pipeline::CreateRenderPipelineError::ConservativeRasterizationNonFillPolygonMode,
2996 );
2997 }
2998
2999 let mut target_specified = false;
3000
3001 for (i, cs) in color_targets.iter().enumerate() {
3002 if let Some(cs) = cs.as_ref() {
3003 target_specified = true;
3004 let error = 'error: {
3005 if cs.write_mask.contains_invalid_bits() {
3006 break 'error Some(pipeline::ColorStateError::InvalidWriteMask(
3007 cs.write_mask,
3008 ));
3009 }
3010
3011 let format_features = self.describe_format_features(cs.format)?;
3012 if !format_features
3013 .allowed_usages
3014 .contains(wgt::TextureUsages::RENDER_ATTACHMENT)
3015 {
3016 break 'error Some(pipeline::ColorStateError::FormatNotRenderable(
3017 cs.format,
3018 ));
3019 }
3020 let blendable = format_features.flags.contains(Tfff::BLENDABLE);
3021 let filterable = format_features.flags.contains(Tfff::FILTERABLE);
3022 let adapter_specific = self
3023 .features
3024 .contains(wgt::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES);
3025 if cs.blend.is_some() && (!blendable || (!filterable && !adapter_specific)) {
3030 break 'error Some(pipeline::ColorStateError::FormatNotBlendable(
3031 cs.format,
3032 ));
3033 }
3034 if !hal::FormatAspects::from(cs.format).contains(hal::FormatAspects::COLOR) {
3035 break 'error Some(pipeline::ColorStateError::FormatNotColor(cs.format));
3036 }
3037
3038 if desc.multisample.count > 1
3039 && !format_features
3040 .flags
3041 .sample_count_supported(desc.multisample.count)
3042 {
3043 break 'error Some(pipeline::ColorStateError::InvalidSampleCount(
3044 desc.multisample.count,
3045 cs.format,
3046 cs.format
3047 .guaranteed_format_features(self.features)
3048 .flags
3049 .supported_sample_counts(),
3050 self.adapter
3051 .get_texture_format_features(cs.format)
3052 .flags
3053 .supported_sample_counts(),
3054 ));
3055 }
3056
3057 if let Some(blend_mode) = cs.blend {
3058 for factor in [
3059 blend_mode.color.src_factor,
3060 blend_mode.color.dst_factor,
3061 blend_mode.alpha.src_factor,
3062 blend_mode.alpha.dst_factor,
3063 ] {
3064 if factor.ref_second_blend_source() {
3065 self.require_features(wgt::Features::DUAL_SOURCE_BLENDING)?;
3066 if i == 0 {
3067 pipeline_expects_dual_source_blending = true;
3068 break;
3069 } else {
3070 return Err(pipeline::CreateRenderPipelineError
3071 ::BlendFactorOnUnsupportedTarget { factor, target: i as u32 });
3072 }
3073 }
3074 }
3075 }
3076
3077 break 'error None;
3078 };
3079 if let Some(e) = error {
3080 return Err(pipeline::CreateRenderPipelineError::ColorState(i as u8, e));
3081 }
3082 }
3083 }
3084
3085 let limit = self.limits.max_color_attachment_bytes_per_sample;
3086 let formats = color_targets
3087 .iter()
3088 .map(|cs| cs.as_ref().map(|cs| cs.format));
3089 if let Err(total) = validate_color_attachment_bytes_per_sample(formats, limit) {
3090 return Err(pipeline::CreateRenderPipelineError::ColorAttachment(
3091 command::ColorAttachmentError::TooManyBytesPerSample { total, limit },
3092 ));
3093 }
3094
3095 if let Some(ds) = depth_stencil_state {
3096 target_specified = true;
3097 let error = 'error: {
3098 let format_features = self.describe_format_features(ds.format)?;
3099 if !format_features
3100 .allowed_usages
3101 .contains(wgt::TextureUsages::RENDER_ATTACHMENT)
3102 {
3103 break 'error Some(pipeline::DepthStencilStateError::FormatNotRenderable(
3104 ds.format,
3105 ));
3106 }
3107
3108 let aspect = hal::FormatAspects::from(ds.format);
3109 if ds.is_depth_enabled() && !aspect.contains(hal::FormatAspects::DEPTH) {
3110 break 'error Some(pipeline::DepthStencilStateError::FormatNotDepth(ds.format));
3111 }
3112 if ds.stencil.is_enabled() && !aspect.contains(hal::FormatAspects::STENCIL) {
3113 break 'error Some(pipeline::DepthStencilStateError::FormatNotStencil(
3114 ds.format,
3115 ));
3116 }
3117 if desc.multisample.count > 1
3118 && !format_features
3119 .flags
3120 .sample_count_supported(desc.multisample.count)
3121 {
3122 break 'error Some(pipeline::DepthStencilStateError::InvalidSampleCount(
3123 desc.multisample.count,
3124 ds.format,
3125 ds.format
3126 .guaranteed_format_features(self.features)
3127 .flags
3128 .supported_sample_counts(),
3129 self.adapter
3130 .get_texture_format_features(ds.format)
3131 .flags
3132 .supported_sample_counts(),
3133 ));
3134 }
3135
3136 break 'error None;
3137 };
3138 if let Some(e) = error {
3139 return Err(pipeline::CreateRenderPipelineError::DepthStencilState(e));
3140 }
3141
3142 if ds.bias.clamp != 0.0 {
3143 self.require_downlevel_flags(wgt::DownlevelFlags::DEPTH_BIAS_CLAMP)?;
3144 }
3145 }
3146
3147 if !target_specified {
3148 return Err(pipeline::CreateRenderPipelineError::NoTargetSpecified);
3149 }
3150
3151 let is_auto_layout = desc.layout.is_none();
3152
3153 let pipeline_layout = match desc.layout {
3155 Some(pipeline_layout) => {
3156 pipeline_layout.same_device(self)?;
3157 Some(pipeline_layout)
3158 }
3159 None => None,
3160 };
3161
3162 let mut binding_layout_source = match pipeline_layout {
3163 Some(ref pipeline_layout) => {
3164 validation::BindingLayoutSource::Provided(pipeline_layout.get_binding_maps())
3165 }
3166 None => validation::BindingLayoutSource::new_derived(&self.limits),
3167 };
3168
3169 let samples = {
3170 let sc = desc.multisample.count;
3171 if sc == 0 || sc > 32 || !sc.is_power_of_two() {
3172 return Err(pipeline::CreateRenderPipelineError::InvalidSampleCount(sc));
3173 }
3174 sc
3175 };
3176
3177 let vertex_entry_point_name;
3178 let vertex_stage = {
3179 let stage_desc = &desc.vertex.stage;
3180 let stage = wgt::ShaderStages::VERTEX;
3181
3182 let vertex_shader_module = &stage_desc.module;
3183 vertex_shader_module.same_device(self)?;
3184
3185 let stage_err = |error| pipeline::CreateRenderPipelineError::Stage { stage, error };
3186
3187 vertex_entry_point_name = vertex_shader_module
3188 .finalize_entry_point_name(
3189 stage,
3190 stage_desc.entry_point.as_ref().map(|ep| ep.as_ref()),
3191 )
3192 .map_err(stage_err)?;
3193
3194 if let Some(ref interface) = vertex_shader_module.interface {
3195 io = interface
3196 .check_stage(
3197 &mut binding_layout_source,
3198 &mut shader_binding_sizes,
3199 &vertex_entry_point_name,
3200 stage,
3201 io,
3202 desc.depth_stencil.as_ref().map(|d| d.depth_compare),
3203 )
3204 .map_err(stage_err)?;
3205 validated_stages |= stage;
3206 }
3207
3208 hal::ProgrammableStage {
3209 module: vertex_shader_module.raw(),
3210 entry_point: &vertex_entry_point_name,
3211 constants: stage_desc.constants.as_ref(),
3212 zero_initialize_workgroup_memory: stage_desc.zero_initialize_workgroup_memory,
3213 }
3214 };
3215
3216 let fragment_entry_point_name;
3217 let fragment_stage = match desc.fragment {
3218 Some(ref fragment_state) => {
3219 let stage = wgt::ShaderStages::FRAGMENT;
3220
3221 let shader_module = &fragment_state.stage.module;
3222 shader_module.same_device(self)?;
3223
3224 let stage_err = |error| pipeline::CreateRenderPipelineError::Stage { stage, error };
3225
3226 fragment_entry_point_name = shader_module
3227 .finalize_entry_point_name(
3228 stage,
3229 fragment_state
3230 .stage
3231 .entry_point
3232 .as_ref()
3233 .map(|ep| ep.as_ref()),
3234 )
3235 .map_err(stage_err)?;
3236
3237 if validated_stages == wgt::ShaderStages::VERTEX {
3238 if let Some(ref interface) = shader_module.interface {
3239 io = interface
3240 .check_stage(
3241 &mut binding_layout_source,
3242 &mut shader_binding_sizes,
3243 &fragment_entry_point_name,
3244 stage,
3245 io,
3246 desc.depth_stencil.as_ref().map(|d| d.depth_compare),
3247 )
3248 .map_err(stage_err)?;
3249 validated_stages |= stage;
3250 }
3251 }
3252
3253 if let Some(ref interface) = shader_module.interface {
3254 shader_expects_dual_source_blending = interface
3255 .fragment_uses_dual_source_blending(&fragment_entry_point_name)
3256 .map_err(|error| pipeline::CreateRenderPipelineError::Stage {
3257 stage,
3258 error,
3259 })?;
3260 }
3261
3262 Some(hal::ProgrammableStage {
3263 module: shader_module.raw(),
3264 entry_point: &fragment_entry_point_name,
3265 constants: fragment_state.stage.constants.as_ref(),
3266 zero_initialize_workgroup_memory: fragment_state
3267 .stage
3268 .zero_initialize_workgroup_memory,
3269 })
3270 }
3271 None => None,
3272 };
3273
3274 if !pipeline_expects_dual_source_blending && shader_expects_dual_source_blending {
3275 return Err(
3276 pipeline::CreateRenderPipelineError::ShaderExpectsPipelineToUseDualSourceBlending,
3277 );
3278 }
3279 if pipeline_expects_dual_source_blending && !shader_expects_dual_source_blending {
3280 return Err(
3281 pipeline::CreateRenderPipelineError::PipelineExpectsShaderToUseDualSourceBlending,
3282 );
3283 }
3284
3285 if validated_stages.contains(wgt::ShaderStages::FRAGMENT) {
3286 for (i, output) in io.iter() {
3287 match color_targets.get(*i as usize) {
3288 Some(Some(state)) => {
3289 validation::check_texture_format(state.format, &output.ty).map_err(
3290 |pipeline| {
3291 pipeline::CreateRenderPipelineError::ColorState(
3292 *i as u8,
3293 pipeline::ColorStateError::IncompatibleFormat {
3294 pipeline,
3295 shader: output.ty,
3296 },
3297 )
3298 },
3299 )?;
3300 }
3301 _ => {
3302 log::warn!(
3303 "The fragment stage {:?} output @location({}) values are ignored",
3304 fragment_stage
3305 .as_ref()
3306 .map_or("", |stage| stage.entry_point),
3307 i
3308 );
3309 }
3310 }
3311 }
3312 }
3313 let last_stage = match desc.fragment {
3314 Some(_) => wgt::ShaderStages::FRAGMENT,
3315 None => wgt::ShaderStages::VERTEX,
3316 };
3317 if is_auto_layout && !validated_stages.contains(last_stage) {
3318 return Err(pipeline::ImplicitLayoutError::ReflectionError(last_stage).into());
3319 }
3320
3321 let pipeline_layout = match binding_layout_source {
3322 validation::BindingLayoutSource::Provided(_) => {
3323 drop(binding_layout_source);
3324 pipeline_layout.unwrap()
3325 }
3326 validation::BindingLayoutSource::Derived(entries) => {
3327 self.derive_pipeline_layout(entries)?
3328 }
3329 };
3330
3331 if desc.multiview.is_some() {
3333 self.require_features(wgt::Features::MULTIVIEW)?;
3334 }
3335
3336 if !self
3337 .downlevel
3338 .flags
3339 .contains(wgt::DownlevelFlags::BUFFER_BINDINGS_NOT_16_BYTE_ALIGNED)
3340 {
3341 for (binding, size) in shader_binding_sizes.iter() {
3342 if size.get() % 16 != 0 {
3343 return Err(pipeline::CreateRenderPipelineError::UnalignedShader {
3344 binding: binding.binding,
3345 group: binding.group,
3346 size: size.get(),
3347 });
3348 }
3349 }
3350 }
3351
3352 let late_sized_buffer_groups =
3353 Device::make_late_sized_buffer_groups(&shader_binding_sizes, &pipeline_layout);
3354
3355 let cache = match desc.cache {
3356 Some(cache) => {
3357 cache.same_device(self)?;
3358 Some(cache)
3359 }
3360 None => None,
3361 };
3362
3363 let pipeline_desc = hal::RenderPipelineDescriptor {
3364 label: desc.label.to_hal(self.instance_flags),
3365 layout: pipeline_layout.raw(),
3366 vertex_buffers: &vertex_buffers,
3367 vertex_stage,
3368 primitive: desc.primitive,
3369 depth_stencil: desc.depth_stencil.clone(),
3370 multisample: desc.multisample,
3371 fragment_stage,
3372 color_targets,
3373 multiview: desc.multiview,
3374 cache: cache.as_ref().map(|it| it.raw()),
3375 };
3376 let raw =
3377 unsafe { self.raw().create_render_pipeline(&pipeline_desc) }.map_err(
3378 |err| match err {
3379 hal::PipelineError::Device(error) => {
3380 pipeline::CreateRenderPipelineError::Device(self.handle_hal_error(error))
3381 }
3382 hal::PipelineError::Linkage(stage, msg) => {
3383 pipeline::CreateRenderPipelineError::Internal { stage, error: msg }
3384 }
3385 hal::PipelineError::EntryPoint(stage) => {
3386 pipeline::CreateRenderPipelineError::Internal {
3387 stage: hal::auxil::map_naga_stage(stage),
3388 error: ENTRYPOINT_FAILURE_ERROR.to_string(),
3389 }
3390 }
3391 hal::PipelineError::PipelineConstants(stage, error) => {
3392 pipeline::CreateRenderPipelineError::PipelineConstants { stage, error }
3393 }
3394 },
3395 )?;
3396
3397 let pass_context = RenderPassContext {
3398 attachments: AttachmentData {
3399 colors: color_targets
3400 .iter()
3401 .map(|state| state.as_ref().map(|s| s.format))
3402 .collect(),
3403 resolves: ArrayVec::new(),
3404 depth_stencil: depth_stencil_state.as_ref().map(|state| state.format),
3405 },
3406 sample_count: samples,
3407 multiview: desc.multiview,
3408 };
3409
3410 let mut flags = pipeline::PipelineFlags::empty();
3411 for state in color_targets.iter().filter_map(|s| s.as_ref()) {
3412 if let Some(ref bs) = state.blend {
3413 if bs.color.uses_constant() | bs.alpha.uses_constant() {
3414 flags |= pipeline::PipelineFlags::BLEND_CONSTANT;
3415 }
3416 }
3417 }
3418 if let Some(ds) = depth_stencil_state.as_ref() {
3419 if ds.stencil.is_enabled() && ds.stencil.needs_ref_value() {
3420 flags |= pipeline::PipelineFlags::STENCIL_REFERENCE;
3421 }
3422 if !ds.is_depth_read_only() {
3423 flags |= pipeline::PipelineFlags::WRITES_DEPTH;
3424 }
3425 if !ds.is_stencil_read_only(desc.primitive.cull_mode) {
3426 flags |= pipeline::PipelineFlags::WRITES_STENCIL;
3427 }
3428 }
3429
3430 let shader_modules = {
3431 let mut shader_modules = ArrayVec::new();
3432 shader_modules.push(desc.vertex.stage.module);
3433 shader_modules.extend(desc.fragment.map(|f| f.stage.module));
3434 shader_modules
3435 };
3436
3437 let pipeline = pipeline::RenderPipeline {
3438 raw: ManuallyDrop::new(raw),
3439 layout: pipeline_layout,
3440 device: self.clone(),
3441 pass_context,
3442 _shader_modules: shader_modules,
3443 flags,
3444 strip_index_format: desc.primitive.strip_index_format,
3445 vertex_steps,
3446 late_sized_buffer_groups,
3447 label: desc.label.to_string(),
3448 tracking_data: TrackingData::new(self.tracker_indices.render_pipelines.clone()),
3449 };
3450
3451 let pipeline = Arc::new(pipeline);
3452
3453 if is_auto_layout {
3454 for bgl in pipeline.layout.bind_group_layouts.iter() {
3455 let _ = bgl
3457 .exclusive_pipeline
3458 .set(binding_model::ExclusivePipeline::Render(Arc::downgrade(
3459 &pipeline,
3460 )));
3461 }
3462 }
3463
3464 Ok(pipeline)
3465 }
3466
3467 pub unsafe fn create_pipeline_cache(
3470 self: &Arc<Self>,
3471 desc: &pipeline::PipelineCacheDescriptor,
3472 ) -> Result<Arc<pipeline::PipelineCache>, pipeline::CreatePipelineCacheError> {
3473 use crate::pipeline_cache;
3474
3475 self.check_is_valid()?;
3476
3477 self.require_features(wgt::Features::PIPELINE_CACHE)?;
3478 let data = if let Some((data, validation_key)) = desc
3479 .data
3480 .as_ref()
3481 .zip(self.raw().pipeline_cache_validation_key())
3482 {
3483 let data = pipeline_cache::validate_pipeline_cache(
3484 data,
3485 &self.adapter.raw.info,
3486 validation_key,
3487 );
3488 match data {
3489 Ok(data) => Some(data),
3490 Err(e) if e.was_avoidable() || !desc.fallback => return Err(e.into()),
3491 Err(_) => None,
3493 }
3494 } else {
3495 None
3496 };
3497 let cache_desc = hal::PipelineCacheDescriptor {
3498 data,
3499 label: desc.label.to_hal(self.instance_flags),
3500 };
3501 let raw = match unsafe { self.raw().create_pipeline_cache(&cache_desc) } {
3502 Ok(raw) => raw,
3503 Err(e) => match e {
3504 hal::PipelineCacheError::Device(e) => return Err(self.handle_hal_error(e).into()),
3505 },
3506 };
3507 let cache = pipeline::PipelineCache {
3508 device: self.clone(),
3509 label: desc.label.to_string(),
3510 raw: ManuallyDrop::new(raw),
3512 };
3513
3514 let cache = Arc::new(cache);
3515
3516 Ok(cache)
3517 }
3518
3519 fn get_texture_format_features(&self, format: TextureFormat) -> wgt::TextureFormatFeatures {
3520 use wgt::TextureFormatFeatureFlags as tfsc;
3522 let mut format_features = self.adapter.get_texture_format_features(format);
3523 if (format == TextureFormat::R32Float
3524 || format == TextureFormat::Rg32Float
3525 || format == TextureFormat::Rgba32Float)
3526 && !self.features.contains(wgt::Features::FLOAT32_FILTERABLE)
3527 {
3528 format_features.flags.set(tfsc::FILTERABLE, false);
3529 }
3530 format_features
3531 }
3532
3533 fn describe_format_features(
3534 &self,
3535 format: TextureFormat,
3536 ) -> Result<wgt::TextureFormatFeatures, MissingFeatures> {
3537 self.require_features(format.required_features())?;
3538
3539 let using_device_features = self
3540 .features
3541 .contains(wgt::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES);
3542 let downlevel = !self
3545 .downlevel
3546 .flags
3547 .contains(wgt::DownlevelFlags::WEBGPU_TEXTURE_FORMAT_SUPPORT);
3548
3549 if using_device_features || downlevel {
3550 Ok(self.get_texture_format_features(format))
3551 } else {
3552 Ok(format.guaranteed_format_features(self.features))
3553 }
3554 }
3555
3556 #[cfg(feature = "replay")]
3557 pub(crate) fn wait_for_submit(
3558 &self,
3559 submission_index: crate::SubmissionIndex,
3560 ) -> Result<(), DeviceError> {
3561 let fence = self.fence.read();
3562 let last_done_index = unsafe { self.raw().get_fence_value(fence.as_ref()) }
3563 .map_err(|e| self.handle_hal_error(e))?;
3564 if last_done_index < submission_index {
3565 unsafe { self.raw().wait(fence.as_ref(), submission_index, !0) }
3566 .map_err(|e| self.handle_hal_error(e))?;
3567 drop(fence);
3568 let closures = self
3569 .lock_life()
3570 .triage_submissions(submission_index, &self.command_allocator);
3571 assert!(
3572 closures.is_empty(),
3573 "wait_for_submit is not expected to work with closures"
3574 );
3575 }
3576 Ok(())
3577 }
3578
3579 pub(crate) fn create_query_set(
3580 self: &Arc<Self>,
3581 desc: &resource::QuerySetDescriptor,
3582 ) -> Result<Arc<QuerySet>, resource::CreateQuerySetError> {
3583 use resource::CreateQuerySetError as Error;
3584
3585 self.check_is_valid()?;
3586
3587 match desc.ty {
3588 wgt::QueryType::Occlusion => {}
3589 wgt::QueryType::Timestamp => {
3590 self.require_features(wgt::Features::TIMESTAMP_QUERY)?;
3591 }
3592 wgt::QueryType::PipelineStatistics(..) => {
3593 self.require_features(wgt::Features::PIPELINE_STATISTICS_QUERY)?;
3594 }
3595 }
3596
3597 if desc.count == 0 {
3598 return Err(Error::ZeroCount);
3599 }
3600
3601 if desc.count > wgt::QUERY_SET_MAX_QUERIES {
3602 return Err(Error::TooManyQueries {
3603 count: desc.count,
3604 maximum: wgt::QUERY_SET_MAX_QUERIES,
3605 });
3606 }
3607
3608 let hal_desc = desc.map_label(|label| label.to_hal(self.instance_flags));
3609
3610 let raw = unsafe { self.raw().create_query_set(&hal_desc).unwrap() };
3611
3612 let query_set = QuerySet {
3613 raw: ManuallyDrop::new(raw),
3614 device: self.clone(),
3615 label: desc.label.to_string(),
3616 tracking_data: TrackingData::new(self.tracker_indices.query_sets.clone()),
3617 desc: desc.map_label(|_| ()),
3618 };
3619
3620 let query_set = Arc::new(query_set);
3621
3622 Ok(query_set)
3623 }
3624
3625 fn lose(&self, message: &str) {
3626 self.valid.store(false, Ordering::Release);
3631
3632 let mut life_lock = self.lock_life();
3634 let closure = life_lock.device_lost_closure.take();
3635 drop(life_lock);
3638
3639 if let Some(device_lost_closure) = closure {
3640 device_lost_closure.call(DeviceLostReason::Unknown, message.to_string());
3641 }
3642
3643 self.release_gpu_resources();
3653 }
3654
3655 pub(crate) fn release_gpu_resources(&self) {
3656 let trackers = self.trackers.lock();
3666 for buffer in trackers.buffers.used_resources() {
3667 if let Some(buffer) = Weak::upgrade(&buffer) {
3668 let _ = buffer.destroy();
3669 }
3670 }
3671 for texture in trackers.textures.used_resources() {
3672 if let Some(texture) = Weak::upgrade(&texture) {
3673 let _ = texture.destroy();
3674 }
3675 }
3676 }
3677
3678 pub(crate) fn new_usage_scope(&self) -> UsageScope<'_> {
3679 UsageScope::new_pooled(&self.usage_scopes, &self.tracker_indices)
3680 }
3681
3682 pub fn get_hal_counters(&self) -> wgt::HalCounters {
3683 self.raw().get_internal_counters()
3684 }
3685
3686 pub fn generate_allocator_report(&self) -> Option<wgt::AllocatorReport> {
3687 self.raw().generate_allocator_report()
3688 }
3689}
3690
3691impl Device {
3692 pub(crate) fn prepare_to_die(&self) {
3694 self.pending_writes.lock().deactivate();
3695 let current_index = self
3696 .last_successful_submission_index
3697 .load(Ordering::Acquire);
3698 if let Err(error) = unsafe {
3699 let fence = self.fence.read();
3700 self.raw()
3701 .wait(fence.as_ref(), current_index, CLEANUP_WAIT_MS)
3702 } {
3703 log::error!("failed to wait for the device: {error}");
3704 }
3705 let mut life_tracker = self.lock_life();
3706 let _ = life_tracker.triage_submissions(current_index, &self.command_allocator);
3707 if let Some(device_lost_closure) = life_tracker.device_lost_closure.take() {
3708 drop(life_tracker);
3710 device_lost_closure.call(DeviceLostReason::Dropped, "Device is dying.".to_string());
3711 }
3712 #[cfg(feature = "trace")]
3713 {
3714 *self.trace.lock() = None;
3715 }
3716 }
3717}
3718
3719crate::impl_resource_type!(Device);
3720crate::impl_labeled!(Device);
3721crate::impl_storage_item!(Device);