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