1use alloc::{format, string::String, sync::Arc, vec::Vec};
2
3use arrayvec::ArrayVec;
4use thiserror::Error;
5use wgt::{
6 error::{ErrorType, WebGpuError},
7 BufferAddress, BufferTextureCopyInfoError, BufferUsages, Extent3d, TextureSelector,
8 TextureUsages,
9};
10
11use crate::{
12 api_log,
13 command::{
14 clear_texture, encoder::EncodingState, ArcCommand, CommandEncoderError, EncoderStateError,
15 },
16 device::MissingDownlevelFlags,
17 global::Global,
18 id::{BufferId, CommandEncoderId, TextureId},
19 init_tracker::{
20 has_copy_partial_init_tracker_coverage, MemoryInitKind, TextureInitRange,
21 TextureInitTrackerAction,
22 },
23 resource::{
24 Buffer, MissingBufferUsageError, MissingTextureUsageError, ParentDevice, RawResourceAccess,
25 Texture, TextureErrorDimension,
26 },
27};
28
29use super::ClearError;
30
31type TexelCopyBufferInfo = wgt::TexelCopyBufferInfo<BufferId>;
32type TexelCopyTextureInfo = wgt::TexelCopyTextureInfo<Arc<Texture>>;
33
34#[derive(Clone, Copy, Debug, Eq, PartialEq)]
35pub enum CopySide {
36 Source,
37 Destination,
38}
39
40#[derive(Clone, Debug, Error)]
42#[non_exhaustive]
43pub enum TransferError {
44 #[error("Source and destination cannot be the same buffer")]
45 SameSourceDestinationBuffer,
46 #[error(transparent)]
47 MissingBufferUsage(#[from] MissingBufferUsageError),
48 #[error(transparent)]
49 MissingTextureUsage(#[from] MissingTextureUsageError),
50 #[error("Copy of {start_offset}..{end_offset} would end up overrunning the bounds of the {side:?} buffer of size {buffer_size}")]
51 BufferOverrun {
52 start_offset: BufferAddress,
53 end_offset: BufferAddress,
54 buffer_size: BufferAddress,
55 side: CopySide,
56 },
57 #[error("Copy of {dimension:?} {start_offset}..{end_offset} would end up overrunning the bounds of the {side:?} texture of {dimension:?} size {texture_size}")]
58 TextureOverrun {
59 start_offset: u32,
60 end_offset: u32,
61 texture_size: u32,
62 dimension: TextureErrorDimension,
63 side: CopySide,
64 },
65 #[error("Partial copy of {start_offset}..{end_offset} on {dimension:?} dimension with size {texture_size} \
66 is not supported for the {side:?} texture format {format:?} with {sample_count} samples")]
67 UnsupportedPartialTransfer {
68 format: wgt::TextureFormat,
69 sample_count: u32,
70 start_offset: u32,
71 end_offset: u32,
72 texture_size: u32,
73 dimension: TextureErrorDimension,
74 side: CopySide,
75 },
76 #[error(
77 "Copying{} layers {}..{} to{} layers {}..{} of the same texture is not allowed",
78 if *src_aspects == wgt::TextureAspect::All { String::new() } else { format!(" {src_aspects:?}") },
79 src_origin_z,
80 src_origin_z + array_layer_count,
81 if *dst_aspects == wgt::TextureAspect::All { String::new() } else { format!(" {dst_aspects:?}") },
82 dst_origin_z,
83 dst_origin_z + array_layer_count,
84 )]
85 InvalidCopyWithinSameTexture {
86 src_aspects: wgt::TextureAspect,
87 dst_aspects: wgt::TextureAspect,
88 src_origin_z: u32,
89 dst_origin_z: u32,
90 array_layer_count: u32,
91 },
92 #[error("Unable to select texture aspect {aspect:?} from format {format:?}")]
93 InvalidTextureAspect {
94 format: wgt::TextureFormat,
95 aspect: wgt::TextureAspect,
96 },
97 #[error("Unable to select texture mip level {level} out of {total}")]
98 InvalidTextureMipLevel { level: u32, total: u32 },
99 #[error("Texture dimension must be 2D when copying from an external texture")]
100 InvalidDimensionExternal,
101 #[error("Buffer offset {0} is not aligned to block size or `COPY_BUFFER_ALIGNMENT`")]
102 UnalignedBufferOffset(BufferAddress),
103 #[error("Copy size {0} does not respect `COPY_BUFFER_ALIGNMENT`")]
104 UnalignedCopySize(BufferAddress),
105 #[error("Copy width is not a multiple of block width")]
106 UnalignedCopyWidth,
107 #[error("Copy height is not a multiple of block height")]
108 UnalignedCopyHeight,
109 #[error("Copy origin's x component is not a multiple of block width")]
110 UnalignedCopyOriginX,
111 #[error("Copy origin's y component is not a multiple of block height")]
112 UnalignedCopyOriginY,
113 #[error("Bytes per row does not respect `COPY_BYTES_PER_ROW_ALIGNMENT`")]
114 UnalignedBytesPerRow,
115 #[error("Number of bytes per row needs to be specified since more than one row is copied")]
116 UnspecifiedBytesPerRow,
117 #[error("Number of rows per image needs to be specified since more than one image is copied")]
118 UnspecifiedRowsPerImage,
119 #[error("Number of bytes per row is less than the number of bytes in a complete row")]
120 InvalidBytesPerRow,
121 #[error("Number of rows per image is invalid")]
122 InvalidRowsPerImage,
123 #[error("Overflow while computing the size of the copy")]
124 SizeOverflow,
125 #[error("Copy source aspects must refer to all aspects of the source texture format")]
126 CopySrcMissingAspects,
127 #[error(
128 "Copy destination aspects must refer to all aspects of the destination texture format"
129 )]
130 CopyDstMissingAspects,
131 #[error("Copy aspect must refer to a single aspect of texture format")]
132 CopyAspectNotOne,
133 #[error("Copying from textures with format {0:?} is forbidden")]
134 CopyFromForbiddenTextureFormat(wgt::TextureFormat),
135 #[error("Copying from textures with format {format:?} and aspect {aspect:?} is forbidden")]
136 CopyFromForbiddenTextureFormatAspect {
137 format: wgt::TextureFormat,
138 aspect: wgt::TextureAspect,
139 },
140 #[error("Copying to textures with format {0:?} is forbidden")]
141 CopyToForbiddenTextureFormat(wgt::TextureFormat),
142 #[error("Copying to textures with format {format:?} and aspect {aspect:?} is forbidden")]
143 CopyToForbiddenTextureFormatAspect {
144 format: wgt::TextureFormat,
145 aspect: wgt::TextureAspect,
146 },
147 #[error(
148 "Copying to textures with format {0:?} is forbidden when copying from external texture"
149 )]
150 ExternalCopyToForbiddenTextureFormat(wgt::TextureFormat),
151 #[error(
152 "Source format ({src_format:?}) and destination format ({dst_format:?}) are not copy-compatible (they may only differ in srgb-ness)"
153 )]
154 TextureFormatsNotCopyCompatible {
155 src_format: wgt::TextureFormat,
156 dst_format: wgt::TextureFormat,
157 },
158 #[error(transparent)]
159 MemoryInitFailure(#[from] ClearError),
160 #[error("Cannot encode this copy because of a missing downelevel flag")]
161 MissingDownlevelFlags(#[from] MissingDownlevelFlags),
162 #[error("Source texture sample count must be 1, got {sample_count}")]
163 InvalidSampleCount { sample_count: u32 },
164 #[error(
165 "Source sample count ({src_sample_count:?}) and destination sample count ({dst_sample_count:?}) are not equal"
166 )]
167 SampleCountNotEqual {
168 src_sample_count: u32,
169 dst_sample_count: u32,
170 },
171 #[error("Requested mip level {requested} does not exist (count: {count})")]
172 InvalidMipLevel { requested: u32, count: u32 },
173 #[error("Buffer is expected to be unmapped, but was not")]
174 BufferNotAvailable,
175}
176
177impl WebGpuError for TransferError {
178 fn webgpu_error_type(&self) -> ErrorType {
179 let e: &dyn WebGpuError = match self {
180 Self::MissingBufferUsage(e) => e,
181 Self::MissingTextureUsage(e) => e,
182 Self::MemoryInitFailure(e) => e,
183
184 Self::BufferOverrun { .. }
185 | Self::TextureOverrun { .. }
186 | Self::UnsupportedPartialTransfer { .. }
187 | Self::InvalidCopyWithinSameTexture { .. }
188 | Self::InvalidTextureAspect { .. }
189 | Self::InvalidTextureMipLevel { .. }
190 | Self::InvalidDimensionExternal
191 | Self::UnalignedBufferOffset(..)
192 | Self::UnalignedCopySize(..)
193 | Self::UnalignedCopyWidth
194 | Self::UnalignedCopyHeight
195 | Self::UnalignedCopyOriginX
196 | Self::UnalignedCopyOriginY
197 | Self::UnalignedBytesPerRow
198 | Self::UnspecifiedBytesPerRow
199 | Self::UnspecifiedRowsPerImage
200 | Self::InvalidBytesPerRow
201 | Self::InvalidRowsPerImage
202 | Self::SizeOverflow
203 | Self::CopySrcMissingAspects
204 | Self::CopyDstMissingAspects
205 | Self::CopyAspectNotOne
206 | Self::CopyFromForbiddenTextureFormat(..)
207 | Self::CopyFromForbiddenTextureFormatAspect { .. }
208 | Self::CopyToForbiddenTextureFormat(..)
209 | Self::CopyToForbiddenTextureFormatAspect { .. }
210 | Self::ExternalCopyToForbiddenTextureFormat(..)
211 | Self::TextureFormatsNotCopyCompatible { .. }
212 | Self::MissingDownlevelFlags(..)
213 | Self::InvalidSampleCount { .. }
214 | Self::SampleCountNotEqual { .. }
215 | Self::InvalidMipLevel { .. }
216 | Self::SameSourceDestinationBuffer
217 | Self::BufferNotAvailable => return ErrorType::Validation,
218 };
219 e.webgpu_error_type()
220 }
221}
222
223impl From<BufferTextureCopyInfoError> for TransferError {
224 fn from(value: BufferTextureCopyInfoError) -> Self {
225 match value {
226 BufferTextureCopyInfoError::InvalidBytesPerRow => Self::InvalidBytesPerRow,
227 BufferTextureCopyInfoError::InvalidRowsPerImage => Self::InvalidRowsPerImage,
228 BufferTextureCopyInfoError::ImageStrideOverflow
229 | BufferTextureCopyInfoError::ImageBytesOverflow(_)
230 | BufferTextureCopyInfoError::ArraySizeOverflow(_) => Self::SizeOverflow,
231 }
232 }
233}
234
235pub(crate) fn extract_texture_selector<T>(
236 copy_texture: &wgt::TexelCopyTextureInfo<T>,
237 copy_size: &Extent3d,
238 texture: &Texture,
239) -> Result<(TextureSelector, hal::TextureCopyBase), TransferError> {
240 let format = texture.desc.format;
241 let copy_aspect = hal::FormatAspects::new(format, copy_texture.aspect);
242 if copy_aspect.is_empty() {
243 return Err(TransferError::InvalidTextureAspect {
244 format,
245 aspect: copy_texture.aspect,
246 });
247 }
248
249 let (layers, origin_z) = match texture.desc.dimension {
250 wgt::TextureDimension::D1 => (0..1, 0),
251 wgt::TextureDimension::D2 => (
252 copy_texture.origin.z..copy_texture.origin.z + copy_size.depth_or_array_layers,
253 0,
254 ),
255 wgt::TextureDimension::D3 => (0..1, copy_texture.origin.z),
256 };
257 let base = hal::TextureCopyBase {
258 origin: wgt::Origin3d {
259 x: copy_texture.origin.x,
260 y: copy_texture.origin.y,
261 z: origin_z,
262 },
263 array_layer: layers.start,
265 mip_level: copy_texture.mip_level,
266 aspect: copy_aspect,
267 };
268 let selector = TextureSelector {
269 mips: copy_texture.mip_level..copy_texture.mip_level + 1,
270 layers,
271 };
272
273 Ok((selector, base))
274}
275
276pub(crate) fn validate_linear_texture_data(
288 layout: &wgt::TexelCopyBufferLayout,
289 format: wgt::TextureFormat,
290 aspect: wgt::TextureAspect,
291 buffer_size: BufferAddress,
292 buffer_side: CopySide,
293 copy_size: &Extent3d,
294) -> Result<(BufferAddress, BufferAddress, bool), TransferError> {
295 let wgt::BufferTextureCopyInfo {
296 copy_width,
297 copy_height,
298 depth_or_array_layers,
299
300 offset,
301
302 block_size_bytes: _,
303 block_width_texels,
304 block_height_texels,
305
306 width_blocks: _,
307 height_blocks,
308
309 row_bytes_dense,
310 row_stride_bytes,
311
312 image_stride_rows: _,
313 image_stride_bytes,
314
315 image_rows_dense: _,
316 image_bytes_dense,
317
318 bytes_in_copy,
319 } = layout.get_buffer_texture_copy_info(format, aspect, copy_size)?;
320
321 if copy_width % block_width_texels != 0 {
322 return Err(TransferError::UnalignedCopyWidth);
323 }
324 if copy_height % block_height_texels != 0 {
325 return Err(TransferError::UnalignedCopyHeight);
326 }
327
328 let requires_multiple_rows = depth_or_array_layers > 1 || height_blocks > 1;
329 let requires_multiple_images = depth_or_array_layers > 1;
330
331 if layout.bytes_per_row.is_none() && requires_multiple_rows {
336 return Err(TransferError::UnspecifiedBytesPerRow);
337 }
338
339 if layout.rows_per_image.is_none() && requires_multiple_images {
340 return Err(TransferError::UnspecifiedRowsPerImage);
341 };
342
343 if bytes_in_copy > buffer_size || offset > buffer_size - bytes_in_copy {
345 return Err(TransferError::BufferOverrun {
346 start_offset: offset,
347 end_offset: offset.wrapping_add(bytes_in_copy),
348 buffer_size,
349 side: buffer_side,
350 });
351 }
352
353 let is_contiguous = (row_stride_bytes == row_bytes_dense || !requires_multiple_rows)
354 && (image_stride_bytes == image_bytes_dense || !requires_multiple_images);
355
356 Ok((bytes_in_copy, image_stride_bytes, is_contiguous))
357}
358
359pub(crate) fn validate_texture_copy_src_format(
368 format: wgt::TextureFormat,
369 aspect: wgt::TextureAspect,
370) -> Result<(), TransferError> {
371 use wgt::TextureAspect as Ta;
372 use wgt::TextureFormat as Tf;
373 match (format, aspect) {
374 (Tf::Depth24Plus, _) => Err(TransferError::CopyFromForbiddenTextureFormat(format)),
375 (Tf::Depth24PlusStencil8, Ta::DepthOnly) => {
376 Err(TransferError::CopyFromForbiddenTextureFormatAspect { format, aspect })
377 }
378 _ => Ok(()),
379 }
380}
381
382pub(crate) fn validate_texture_copy_dst_format(
391 format: wgt::TextureFormat,
392 aspect: wgt::TextureAspect,
393) -> Result<(), TransferError> {
394 use wgt::TextureAspect as Ta;
395 use wgt::TextureFormat as Tf;
396 match (format, aspect) {
397 (Tf::Depth24Plus | Tf::Depth32Float, _) => {
398 Err(TransferError::CopyToForbiddenTextureFormat(format))
399 }
400 (Tf::Depth24PlusStencil8 | Tf::Depth32FloatStencil8, Ta::DepthOnly) => {
401 Err(TransferError::CopyToForbiddenTextureFormatAspect { format, aspect })
402 }
403 _ => Ok(()),
404 }
405}
406
407pub(crate) fn validate_texture_buffer_copy<T>(
435 texture_copy_view: &wgt::TexelCopyTextureInfo<T>,
436 aspect: hal::FormatAspects,
437 desc: &wgt::TextureDescriptor<(), Vec<wgt::TextureFormat>>,
438 layout: &wgt::TexelCopyBufferLayout,
439 aligned: bool,
440) -> Result<(), TransferError> {
441 if desc.sample_count != 1 {
442 return Err(TransferError::InvalidSampleCount {
443 sample_count: desc.sample_count,
444 });
445 }
446
447 if !aspect.is_one() {
448 return Err(TransferError::CopyAspectNotOne);
449 }
450
451 let offset_alignment = if desc.format.is_depth_stencil_format() {
452 4
453 } else {
454 desc.format
459 .block_copy_size(Some(texture_copy_view.aspect))
460 .expect("non-copyable formats should have been rejected previously")
461 };
462
463 if aligned && layout.offset % u64::from(offset_alignment) != 0 {
464 return Err(TransferError::UnalignedBufferOffset(layout.offset));
465 }
466
467 if let Some(bytes_per_row) = layout.bytes_per_row {
468 if aligned && bytes_per_row % wgt::COPY_BYTES_PER_ROW_ALIGNMENT != 0 {
469 return Err(TransferError::UnalignedBytesPerRow);
470 }
471 }
472
473 Ok(())
474}
475
476pub(crate) fn validate_texture_copy_range<T>(
487 texture_copy_view: &wgt::TexelCopyTextureInfo<T>,
488 desc: &wgt::TextureDescriptor<(), Vec<wgt::TextureFormat>>,
489 texture_side: CopySide,
490 copy_size: &Extent3d,
491) -> Result<(hal::CopyExtent, u32), TransferError> {
492 let (block_width, block_height) = desc.format.block_dimensions();
493
494 let extent_virtual = desc.mip_level_size(texture_copy_view.mip_level).ok_or(
495 TransferError::InvalidTextureMipLevel {
496 level: texture_copy_view.mip_level,
497 total: desc.mip_level_count,
498 },
499 )?;
500 let extent = extent_virtual.physical_size(desc.format);
502
503 let requires_exact_size = desc.format.is_depth_stencil_format() || desc.sample_count > 1;
506
507 let check_dimension = |dimension: TextureErrorDimension,
510 start_offset: u32,
511 size: u32,
512 texture_size: u32,
513 requires_exact_size: bool|
514 -> Result<(), TransferError> {
515 if requires_exact_size && (start_offset != 0 || size != texture_size) {
516 Err(TransferError::UnsupportedPartialTransfer {
517 format: desc.format,
518 sample_count: desc.sample_count,
519 start_offset,
520 end_offset: start_offset.wrapping_add(size),
521 texture_size,
522 dimension,
523 side: texture_side,
524 })
525 } else if start_offset > texture_size || texture_size - start_offset < size {
528 Err(TransferError::TextureOverrun {
529 start_offset,
530 end_offset: start_offset.wrapping_add(size),
531 texture_size,
532 dimension,
533 side: texture_side,
534 })
535 } else {
536 Ok(())
537 }
538 };
539
540 check_dimension(
541 TextureErrorDimension::X,
542 texture_copy_view.origin.x,
543 copy_size.width,
544 extent.width,
545 requires_exact_size,
546 )?;
547 check_dimension(
548 TextureErrorDimension::Y,
549 texture_copy_view.origin.y,
550 copy_size.height,
551 extent.height,
552 requires_exact_size,
553 )?;
554 check_dimension(
555 TextureErrorDimension::Z,
556 texture_copy_view.origin.z,
557 copy_size.depth_or_array_layers,
558 extent.depth_or_array_layers,
559 false, )?;
561
562 if texture_copy_view.origin.x % block_width != 0 {
563 return Err(TransferError::UnalignedCopyOriginX);
564 }
565 if texture_copy_view.origin.y % block_height != 0 {
566 return Err(TransferError::UnalignedCopyOriginY);
567 }
568 if copy_size.width % block_width != 0 {
569 return Err(TransferError::UnalignedCopyWidth);
570 }
571 if copy_size.height % block_height != 0 {
572 return Err(TransferError::UnalignedCopyHeight);
573 }
574
575 let (depth, array_layer_count) = match desc.dimension {
576 wgt::TextureDimension::D1 => (1, 1),
577 wgt::TextureDimension::D2 => (1, copy_size.depth_or_array_layers),
578 wgt::TextureDimension::D3 => (copy_size.depth_or_array_layers, 1),
579 };
580
581 let copy_extent = hal::CopyExtent {
582 width: copy_size.width,
583 height: copy_size.height,
584 depth,
585 };
586 Ok((copy_extent, array_layer_count))
587}
588
589pub(crate) fn validate_copy_within_same_texture<T>(
600 src: &wgt::TexelCopyTextureInfo<T>,
601 dst: &wgt::TexelCopyTextureInfo<T>,
602 format: wgt::TextureFormat,
603 array_layer_count: u32,
604) -> Result<(), TransferError> {
605 let src_aspects = hal::FormatAspects::new(format, src.aspect);
606 let dst_aspects = hal::FormatAspects::new(format, dst.aspect);
607 if (src_aspects & dst_aspects).is_empty() {
608 return Ok(());
610 }
611
612 if src.origin.z >= dst.origin.z + array_layer_count
613 || dst.origin.z >= src.origin.z + array_layer_count
614 {
615 return Ok(());
617 }
618
619 if src.mip_level != dst.mip_level {
620 return Ok(());
622 }
623
624 Err(TransferError::InvalidCopyWithinSameTexture {
625 src_aspects: src.aspect,
626 dst_aspects: dst.aspect,
627 src_origin_z: src.origin.z,
628 dst_origin_z: dst.origin.z,
629 array_layer_count,
630 })
631}
632
633fn handle_texture_init(
634 state: &mut EncodingState,
635 init_kind: MemoryInitKind,
636 copy_texture: &TexelCopyTextureInfo,
637 copy_size: &Extent3d,
638 texture: &Arc<Texture>,
639) -> Result<(), ClearError> {
640 let init_action = TextureInitTrackerAction {
641 texture: texture.clone(),
642 range: TextureInitRange {
643 mip_range: copy_texture.mip_level..copy_texture.mip_level + 1,
644 layer_range: copy_texture.origin.z
645 ..(copy_texture.origin.z + copy_size.depth_or_array_layers),
646 },
647 kind: init_kind,
648 };
649
650 let immediate_inits = state
652 .texture_memory_actions
653 .register_init_action(&{ init_action });
654
655 if !immediate_inits.is_empty() {
657 for init in immediate_inits {
658 clear_texture(
659 &init.texture,
660 TextureInitRange {
661 mip_range: init.mip_level..(init.mip_level + 1),
662 layer_range: init.layer..(init.layer + 1),
663 },
664 state.raw_encoder,
665 &mut state.tracker.textures,
666 &state.device.alignments,
667 state.device.zero_buffer.as_ref(),
668 state.snatch_guard,
669 state.device.instance_flags,
670 )?;
671 }
672 }
673
674 Ok(())
675}
676
677fn handle_src_texture_init(
682 state: &mut EncodingState,
683 source: &TexelCopyTextureInfo,
684 copy_size: &Extent3d,
685 texture: &Arc<Texture>,
686) -> Result<(), TransferError> {
687 handle_texture_init(
688 state,
689 MemoryInitKind::NeedsInitializedMemory,
690 source,
691 copy_size,
692 texture,
693 )?;
694 Ok(())
695}
696
697fn handle_dst_texture_init(
702 state: &mut EncodingState,
703 destination: &wgt::TexelCopyTextureInfo<Arc<Texture>>,
704 copy_size: &Extent3d,
705 texture: &Arc<Texture>,
706) -> Result<(), TransferError> {
707 let dst_init_kind = if has_copy_partial_init_tracker_coverage(
712 copy_size,
713 destination.mip_level,
714 &texture.desc,
715 ) {
716 MemoryInitKind::NeedsInitializedMemory
717 } else {
718 MemoryInitKind::ImplicitlyInitialized
719 };
720
721 handle_texture_init(state, dst_init_kind, destination, copy_size, texture)?;
722 Ok(())
723}
724
725fn handle_buffer_init(
730 state: &mut EncodingState,
731 info: &wgt::TexelCopyBufferInfo<Arc<Buffer>>,
732 direction: CopySide,
733 required_buffer_bytes_in_copy: BufferAddress,
734 is_contiguous: bool,
735) {
736 const ALIGN_SIZE: BufferAddress = wgt::COPY_BUFFER_ALIGNMENT;
737 const ALIGN_MASK: BufferAddress = wgt::COPY_BUFFER_ALIGNMENT - 1;
738
739 let buffer = &info.buffer;
740 let start = info.layout.offset;
741 let end = info.layout.offset + required_buffer_bytes_in_copy;
742 if !is_contiguous || direction == CopySide::Source {
743 let aligned_start = start & !ALIGN_MASK;
754 let aligned_end = (end + ALIGN_MASK) & !ALIGN_MASK;
755 state
756 .buffer_memory_init_actions
757 .extend(buffer.initialization_status.read().create_action(
758 buffer,
759 aligned_start..aligned_end,
760 MemoryInitKind::NeedsInitializedMemory,
761 ));
762 } else {
763 let aligned_start = (start + ALIGN_MASK) & !ALIGN_MASK;
773 let aligned_end = end & !ALIGN_MASK;
774 if aligned_start != start {
775 state.buffer_memory_init_actions.extend(
776 buffer.initialization_status.read().create_action(
777 buffer,
778 aligned_start - ALIGN_SIZE..aligned_start,
779 MemoryInitKind::NeedsInitializedMemory,
780 ),
781 );
782 }
783 if aligned_start != aligned_end {
784 state.buffer_memory_init_actions.extend(
785 buffer.initialization_status.read().create_action(
786 buffer,
787 aligned_start..aligned_end,
788 MemoryInitKind::ImplicitlyInitialized,
789 ),
790 );
791 }
792 if aligned_end != end {
793 state.buffer_memory_init_actions.extend(
799 buffer.initialization_status.read().create_action(
800 buffer,
801 aligned_end..aligned_end + ALIGN_SIZE,
802 MemoryInitKind::NeedsInitializedMemory,
803 ),
804 );
805 }
806 }
807}
808
809impl Global {
810 pub fn command_encoder_copy_buffer_to_buffer(
811 &self,
812 command_encoder_id: CommandEncoderId,
813 source: BufferId,
814 source_offset: BufferAddress,
815 destination: BufferId,
816 destination_offset: BufferAddress,
817 size: Option<BufferAddress>,
818 ) -> Result<(), EncoderStateError> {
819 profiling::scope!("CommandEncoder::copy_buffer_to_buffer");
820 api_log!(
821 "CommandEncoder::copy_buffer_to_buffer {source:?} -> {destination:?} {size:?}bytes"
822 );
823
824 let hub = &self.hub;
825
826 let cmd_enc = hub.command_encoders.get(command_encoder_id);
827 let mut cmd_buf_data = cmd_enc.data.lock();
828
829 cmd_buf_data.push_with(|| -> Result<_, CommandEncoderError> {
830 Ok(ArcCommand::CopyBufferToBuffer {
831 src: self.resolve_buffer_id(source)?,
832 src_offset: source_offset,
833 dst: self.resolve_buffer_id(destination)?,
834 dst_offset: destination_offset,
835 size,
836 })
837 })
838 }
839
840 pub fn command_encoder_copy_buffer_to_texture(
841 &self,
842 command_encoder_id: CommandEncoderId,
843 source: &TexelCopyBufferInfo,
844 destination: &wgt::TexelCopyTextureInfo<TextureId>,
845 copy_size: &Extent3d,
846 ) -> Result<(), EncoderStateError> {
847 profiling::scope!("CommandEncoder::copy_buffer_to_texture");
848 api_log!(
849 "CommandEncoder::copy_buffer_to_texture {:?} -> {:?} {copy_size:?}",
850 source.buffer,
851 destination.texture
852 );
853
854 let cmd_enc = self.hub.command_encoders.get(command_encoder_id);
855 let mut cmd_buf_data = cmd_enc.data.lock();
856
857 cmd_buf_data.push_with(|| -> Result<_, CommandEncoderError> {
858 Ok(ArcCommand::CopyBufferToTexture {
859 src: wgt::TexelCopyBufferInfo::<Arc<Buffer>> {
860 buffer: self.resolve_buffer_id(source.buffer)?,
861 layout: source.layout,
862 },
863 dst: wgt::TexelCopyTextureInfo::<Arc<Texture>> {
864 texture: self.resolve_texture_id(destination.texture)?,
865 mip_level: destination.mip_level,
866 origin: destination.origin,
867 aspect: destination.aspect,
868 },
869 size: *copy_size,
870 })
871 })
872 }
873
874 pub fn command_encoder_copy_texture_to_buffer(
875 &self,
876 command_encoder_id: CommandEncoderId,
877 source: &wgt::TexelCopyTextureInfo<TextureId>,
878 destination: &TexelCopyBufferInfo,
879 copy_size: &Extent3d,
880 ) -> Result<(), EncoderStateError> {
881 profiling::scope!("CommandEncoder::copy_texture_to_buffer");
882 api_log!(
883 "CommandEncoder::copy_texture_to_buffer {:?} -> {:?} {copy_size:?}",
884 source.texture,
885 destination.buffer
886 );
887
888 let cmd_enc = self.hub.command_encoders.get(command_encoder_id);
889 let mut cmd_buf_data = cmd_enc.data.lock();
890
891 cmd_buf_data.push_with(|| -> Result<_, CommandEncoderError> {
892 Ok(ArcCommand::CopyTextureToBuffer {
893 src: wgt::TexelCopyTextureInfo::<Arc<Texture>> {
894 texture: self.resolve_texture_id(source.texture)?,
895 mip_level: source.mip_level,
896 origin: source.origin,
897 aspect: source.aspect,
898 },
899 dst: wgt::TexelCopyBufferInfo::<Arc<Buffer>> {
900 buffer: self.resolve_buffer_id(destination.buffer)?,
901 layout: destination.layout,
902 },
903 size: *copy_size,
904 })
905 })
906 }
907
908 pub fn command_encoder_copy_texture_to_texture(
909 &self,
910 command_encoder_id: CommandEncoderId,
911 source: &wgt::TexelCopyTextureInfo<TextureId>,
912 destination: &wgt::TexelCopyTextureInfo<TextureId>,
913 copy_size: &Extent3d,
914 ) -> Result<(), EncoderStateError> {
915 profiling::scope!("CommandEncoder::copy_texture_to_texture");
916 api_log!(
917 "CommandEncoder::copy_texture_to_texture {:?} -> {:?} {copy_size:?}",
918 source.texture,
919 destination.texture
920 );
921
922 let cmd_enc = self.hub.command_encoders.get(command_encoder_id);
923 let mut cmd_buf_data = cmd_enc.data.lock();
924
925 cmd_buf_data.push_with(|| -> Result<_, CommandEncoderError> {
926 Ok(ArcCommand::CopyTextureToTexture {
927 src: wgt::TexelCopyTextureInfo {
928 texture: self.resolve_texture_id(source.texture)?,
929 mip_level: source.mip_level,
930 origin: source.origin,
931 aspect: source.aspect,
932 },
933 dst: wgt::TexelCopyTextureInfo {
934 texture: self.resolve_texture_id(destination.texture)?,
935 mip_level: destination.mip_level,
936 origin: destination.origin,
937 aspect: destination.aspect,
938 },
939 size: *copy_size,
940 })
941 })
942 }
943}
944
945pub(super) fn copy_buffer_to_buffer(
946 state: &mut EncodingState,
947 src_buffer: &Arc<Buffer>,
948 source_offset: BufferAddress,
949 dst_buffer: &Arc<Buffer>,
950 destination_offset: BufferAddress,
951 size: Option<BufferAddress>,
952) -> Result<(), CommandEncoderError> {
953 if src_buffer.is_equal(dst_buffer) {
954 return Err(TransferError::SameSourceDestinationBuffer.into());
955 }
956
957 src_buffer.same_device(state.device)?;
958
959 let src_pending = state
960 .tracker
961 .buffers
962 .set_single(src_buffer, wgt::BufferUses::COPY_SRC);
963
964 let src_raw = src_buffer.try_raw(state.snatch_guard)?;
965 src_buffer
966 .check_usage(BufferUsages::COPY_SRC)
967 .map_err(TransferError::MissingBufferUsage)?;
968 let src_barrier = src_pending.map(|pending| pending.into_hal(src_buffer, state.snatch_guard));
970
971 dst_buffer.same_device(state.device)?;
972
973 let dst_pending = state
974 .tracker
975 .buffers
976 .set_single(dst_buffer, wgt::BufferUses::COPY_DST);
977
978 let dst_raw = dst_buffer.try_raw(state.snatch_guard)?;
979 dst_buffer
980 .check_usage(BufferUsages::COPY_DST)
981 .map_err(TransferError::MissingBufferUsage)?;
982 let dst_barrier = dst_pending.map(|pending| pending.into_hal(dst_buffer, state.snatch_guard));
983
984 let (size, source_end_offset) = match size {
985 Some(size) => (size, source_offset + size),
986 None => (src_buffer.size - source_offset, src_buffer.size),
987 };
988
989 if size % wgt::COPY_BUFFER_ALIGNMENT != 0 {
990 return Err(TransferError::UnalignedCopySize(size).into());
991 }
992 if source_offset % wgt::COPY_BUFFER_ALIGNMENT != 0 {
993 return Err(TransferError::UnalignedBufferOffset(source_offset).into());
994 }
995 if destination_offset % wgt::COPY_BUFFER_ALIGNMENT != 0 {
996 return Err(TransferError::UnalignedBufferOffset(destination_offset).into());
997 }
998 if !state
999 .device
1000 .downlevel
1001 .flags
1002 .contains(wgt::DownlevelFlags::UNRESTRICTED_INDEX_BUFFER)
1003 && (src_buffer.usage.contains(BufferUsages::INDEX)
1004 || dst_buffer.usage.contains(BufferUsages::INDEX))
1005 {
1006 let forbidden_usages = BufferUsages::VERTEX
1007 | BufferUsages::UNIFORM
1008 | BufferUsages::INDIRECT
1009 | BufferUsages::STORAGE;
1010 if src_buffer.usage.intersects(forbidden_usages)
1011 || dst_buffer.usage.intersects(forbidden_usages)
1012 {
1013 return Err(TransferError::MissingDownlevelFlags(MissingDownlevelFlags(
1014 wgt::DownlevelFlags::UNRESTRICTED_INDEX_BUFFER,
1015 ))
1016 .into());
1017 }
1018 }
1019
1020 let destination_end_offset = destination_offset + size;
1021 if source_end_offset > src_buffer.size {
1022 return Err(TransferError::BufferOverrun {
1023 start_offset: source_offset,
1024 end_offset: source_end_offset,
1025 buffer_size: src_buffer.size,
1026 side: CopySide::Source,
1027 }
1028 .into());
1029 }
1030 if destination_end_offset > dst_buffer.size {
1031 return Err(TransferError::BufferOverrun {
1032 start_offset: destination_offset,
1033 end_offset: destination_end_offset,
1034 buffer_size: dst_buffer.size,
1035 side: CopySide::Destination,
1036 }
1037 .into());
1038 }
1039
1040 if size == 0 {
1043 log::trace!("Ignoring copy_buffer_to_buffer of size 0");
1044 return Ok(());
1045 }
1046
1047 state
1049 .buffer_memory_init_actions
1050 .extend(dst_buffer.initialization_status.read().create_action(
1051 dst_buffer,
1052 destination_offset..(destination_offset + size),
1053 MemoryInitKind::ImplicitlyInitialized,
1054 ));
1055 state
1056 .buffer_memory_init_actions
1057 .extend(src_buffer.initialization_status.read().create_action(
1058 src_buffer,
1059 source_offset..(source_offset + size),
1060 MemoryInitKind::NeedsInitializedMemory,
1061 ));
1062
1063 let region = hal::BufferCopy {
1064 src_offset: source_offset,
1065 dst_offset: destination_offset,
1066 size: wgt::BufferSize::new(size).unwrap(),
1067 };
1068 let barriers = src_barrier
1069 .into_iter()
1070 .chain(dst_barrier)
1071 .collect::<Vec<_>>();
1072 unsafe {
1073 state.raw_encoder.transition_buffers(&barriers);
1074 state
1075 .raw_encoder
1076 .copy_buffer_to_buffer(src_raw, dst_raw, &[region]);
1077 }
1078
1079 Ok(())
1080}
1081
1082pub(super) fn copy_buffer_to_texture(
1083 state: &mut EncodingState,
1084 source: &wgt::TexelCopyBufferInfo<Arc<Buffer>>,
1085 destination: &wgt::TexelCopyTextureInfo<Arc<Texture>>,
1086 copy_size: &Extent3d,
1087) -> Result<(), CommandEncoderError> {
1088 let dst_texture = &destination.texture;
1089 let src_buffer = &source.buffer;
1090
1091 dst_texture.same_device(state.device)?;
1092 src_buffer.same_device(state.device)?;
1093
1094 let (hal_copy_size, array_layer_count) = validate_texture_copy_range(
1095 destination,
1096 &dst_texture.desc,
1097 CopySide::Destination,
1098 copy_size,
1099 )?;
1100
1101 let (dst_range, dst_base) = extract_texture_selector(destination, copy_size, dst_texture)?;
1102
1103 let src_raw = src_buffer.try_raw(state.snatch_guard)?;
1104 src_buffer
1105 .check_usage(BufferUsages::COPY_SRC)
1106 .map_err(TransferError::MissingBufferUsage)?;
1107
1108 let dst_raw = dst_texture.try_raw(state.snatch_guard)?;
1109 dst_texture
1110 .check_usage(TextureUsages::COPY_DST)
1111 .map_err(TransferError::MissingTextureUsage)?;
1112
1113 validate_texture_copy_dst_format(dst_texture.desc.format, destination.aspect)?;
1114
1115 validate_texture_buffer_copy(
1116 destination,
1117 dst_base.aspect,
1118 &dst_texture.desc,
1119 &source.layout,
1120 true, )?;
1122
1123 let (required_buffer_bytes_in_copy, bytes_per_array_layer, is_contiguous) =
1124 validate_linear_texture_data(
1125 &source.layout,
1126 dst_texture.desc.format,
1127 destination.aspect,
1128 src_buffer.size,
1129 CopySide::Source,
1130 copy_size,
1131 )?;
1132
1133 if dst_texture.desc.format.is_depth_stencil_format() {
1134 state
1135 .device
1136 .require_downlevel_flags(wgt::DownlevelFlags::DEPTH_TEXTURE_AND_BUFFER_COPIES)
1137 .map_err(TransferError::from)?;
1138 }
1139
1140 if copy_size.width == 0 || copy_size.height == 0 || copy_size.depth_or_array_layers == 0 {
1143 log::trace!("Ignoring copy_buffer_to_texture of size 0");
1144 return Ok(());
1145 }
1146
1147 handle_dst_texture_init(state, destination, copy_size, dst_texture)?;
1151
1152 let src_pending = state
1153 .tracker
1154 .buffers
1155 .set_single(src_buffer, wgt::BufferUses::COPY_SRC);
1156 let src_barrier = src_pending.map(|pending| pending.into_hal(src_buffer, state.snatch_guard));
1157
1158 let dst_pending =
1159 state
1160 .tracker
1161 .textures
1162 .set_single(dst_texture, dst_range, wgt::TextureUses::COPY_DST);
1163 let dst_barrier = dst_pending
1164 .map(|pending| pending.into_hal(dst_raw))
1165 .collect::<Vec<_>>();
1166
1167 handle_buffer_init(
1168 state,
1169 source,
1170 CopySide::Source,
1171 required_buffer_bytes_in_copy,
1172 is_contiguous,
1173 );
1174
1175 let regions = (0..array_layer_count)
1176 .map(|rel_array_layer| {
1177 let mut texture_base = dst_base.clone();
1178 texture_base.array_layer += rel_array_layer;
1179 let mut buffer_layout = source.layout;
1180 buffer_layout.offset += rel_array_layer as u64 * bytes_per_array_layer;
1181 hal::BufferTextureCopy {
1182 buffer_layout,
1183 texture_base,
1184 size: hal_copy_size,
1185 }
1186 })
1187 .collect::<Vec<_>>();
1188
1189 unsafe {
1190 state.raw_encoder.transition_textures(&dst_barrier);
1191 state.raw_encoder.transition_buffers(src_barrier.as_slice());
1192 state
1193 .raw_encoder
1194 .copy_buffer_to_texture(src_raw, dst_raw, ®ions);
1195 }
1196
1197 Ok(())
1198}
1199
1200pub(super) fn copy_texture_to_buffer(
1201 state: &mut EncodingState,
1202 source: &TexelCopyTextureInfo,
1203 destination: &wgt::TexelCopyBufferInfo<Arc<Buffer>>,
1204 copy_size: &Extent3d,
1205) -> Result<(), CommandEncoderError> {
1206 let src_texture = &source.texture;
1207 let dst_buffer = &destination.buffer;
1208
1209 src_texture.same_device(state.device)?;
1210 dst_buffer.same_device(state.device)?;
1211
1212 let (hal_copy_size, array_layer_count) =
1213 validate_texture_copy_range(source, &src_texture.desc, CopySide::Source, copy_size)?;
1214
1215 let (src_range, src_base) = extract_texture_selector(source, copy_size, src_texture)?;
1216
1217 let src_raw = src_texture.try_raw(state.snatch_guard)?;
1218 src_texture
1219 .check_usage(TextureUsages::COPY_SRC)
1220 .map_err(TransferError::MissingTextureUsage)?;
1221
1222 if source.mip_level >= src_texture.desc.mip_level_count {
1223 return Err(TransferError::InvalidMipLevel {
1224 requested: source.mip_level,
1225 count: src_texture.desc.mip_level_count,
1226 }
1227 .into());
1228 }
1229
1230 validate_texture_copy_src_format(src_texture.desc.format, source.aspect)?;
1231
1232 validate_texture_buffer_copy(
1233 source,
1234 src_base.aspect,
1235 &src_texture.desc,
1236 &destination.layout,
1237 true, )?;
1239
1240 let (required_buffer_bytes_in_copy, bytes_per_array_layer, is_contiguous) =
1241 validate_linear_texture_data(
1242 &destination.layout,
1243 src_texture.desc.format,
1244 source.aspect,
1245 dst_buffer.size,
1246 CopySide::Destination,
1247 copy_size,
1248 )?;
1249
1250 if src_texture.desc.format.is_depth_stencil_format() {
1251 state
1252 .device
1253 .require_downlevel_flags(wgt::DownlevelFlags::DEPTH_TEXTURE_AND_BUFFER_COPIES)
1254 .map_err(TransferError::from)?;
1255 }
1256
1257 let dst_raw = dst_buffer.try_raw(state.snatch_guard)?;
1258 dst_buffer
1259 .check_usage(BufferUsages::COPY_DST)
1260 .map_err(TransferError::MissingBufferUsage)?;
1261
1262 if copy_size.width == 0 || copy_size.height == 0 || copy_size.depth_or_array_layers == 0 {
1265 log::trace!("Ignoring copy_texture_to_buffer of size 0");
1266 return Ok(());
1267 }
1268
1269 handle_src_texture_init(state, source, copy_size, src_texture)?;
1273
1274 let src_pending =
1275 state
1276 .tracker
1277 .textures
1278 .set_single(src_texture, src_range, wgt::TextureUses::COPY_SRC);
1279 let src_barrier = src_pending
1280 .map(|pending| pending.into_hal(src_raw))
1281 .collect::<Vec<_>>();
1282
1283 let dst_pending = state
1284 .tracker
1285 .buffers
1286 .set_single(dst_buffer, wgt::BufferUses::COPY_DST);
1287
1288 let dst_barrier = dst_pending.map(|pending| pending.into_hal(dst_buffer, state.snatch_guard));
1289
1290 handle_buffer_init(
1291 state,
1292 destination,
1293 CopySide::Destination,
1294 required_buffer_bytes_in_copy,
1295 is_contiguous,
1296 );
1297
1298 let regions = (0..array_layer_count)
1299 .map(|rel_array_layer| {
1300 let mut texture_base = src_base.clone();
1301 texture_base.array_layer += rel_array_layer;
1302 let mut buffer_layout = destination.layout;
1303 buffer_layout.offset += rel_array_layer as u64 * bytes_per_array_layer;
1304 hal::BufferTextureCopy {
1305 buffer_layout,
1306 texture_base,
1307 size: hal_copy_size,
1308 }
1309 })
1310 .collect::<Vec<_>>();
1311 unsafe {
1312 state.raw_encoder.transition_buffers(dst_barrier.as_slice());
1313 state.raw_encoder.transition_textures(&src_barrier);
1314 state.raw_encoder.copy_texture_to_buffer(
1315 src_raw,
1316 wgt::TextureUses::COPY_SRC,
1317 dst_raw,
1318 ®ions,
1319 );
1320 }
1321
1322 Ok(())
1323}
1324
1325pub(super) fn copy_texture_to_texture(
1326 state: &mut EncodingState,
1327 source: &TexelCopyTextureInfo,
1328 destination: &TexelCopyTextureInfo,
1329 copy_size: &Extent3d,
1330) -> Result<(), CommandEncoderError> {
1331 let src_texture = &source.texture;
1332 let dst_texture = &destination.texture;
1333
1334 src_texture.same_device(state.device)?;
1335 dst_texture.same_device(state.device)?;
1336
1337 if src_texture.desc.format.remove_srgb_suffix() != dst_texture.desc.format.remove_srgb_suffix()
1340 {
1341 return Err(TransferError::TextureFormatsNotCopyCompatible {
1342 src_format: src_texture.desc.format,
1343 dst_format: dst_texture.desc.format,
1344 }
1345 .into());
1346 }
1347
1348 let (src_copy_size, array_layer_count) =
1349 validate_texture_copy_range(source, &src_texture.desc, CopySide::Source, copy_size)?;
1350 let (dst_copy_size, _) = validate_texture_copy_range(
1351 destination,
1352 &dst_texture.desc,
1353 CopySide::Destination,
1354 copy_size,
1355 )?;
1356
1357 if Arc::as_ptr(src_texture) == Arc::as_ptr(dst_texture) {
1358 validate_copy_within_same_texture(
1359 source,
1360 destination,
1361 src_texture.desc.format,
1362 array_layer_count,
1363 )?;
1364 }
1365
1366 let (src_range, src_tex_base) = extract_texture_selector(source, copy_size, src_texture)?;
1367 let (dst_range, dst_tex_base) = extract_texture_selector(destination, copy_size, dst_texture)?;
1368 let src_texture_aspects = hal::FormatAspects::from(src_texture.desc.format);
1369 let dst_texture_aspects = hal::FormatAspects::from(dst_texture.desc.format);
1370 if src_tex_base.aspect != src_texture_aspects {
1371 return Err(TransferError::CopySrcMissingAspects.into());
1372 }
1373 if dst_tex_base.aspect != dst_texture_aspects {
1374 return Err(TransferError::CopyDstMissingAspects.into());
1375 }
1376
1377 if src_texture.desc.sample_count != dst_texture.desc.sample_count {
1378 return Err(TransferError::SampleCountNotEqual {
1379 src_sample_count: src_texture.desc.sample_count,
1380 dst_sample_count: dst_texture.desc.sample_count,
1381 }
1382 .into());
1383 }
1384
1385 let src_raw = src_texture.try_raw(state.snatch_guard)?;
1386 src_texture
1387 .check_usage(TextureUsages::COPY_SRC)
1388 .map_err(TransferError::MissingTextureUsage)?;
1389 let dst_raw = dst_texture.try_raw(state.snatch_guard)?;
1390 dst_texture
1391 .check_usage(TextureUsages::COPY_DST)
1392 .map_err(TransferError::MissingTextureUsage)?;
1393
1394 if copy_size.width == 0 || copy_size.height == 0 || copy_size.depth_or_array_layers == 0 {
1397 log::trace!("Ignoring copy_texture_to_texture of size 0");
1398 return Ok(());
1399 }
1400
1401 handle_src_texture_init(state, source, copy_size, src_texture)?;
1405 handle_dst_texture_init(state, destination, copy_size, dst_texture)?;
1406
1407 let src_pending =
1408 state
1409 .tracker
1410 .textures
1411 .set_single(src_texture, src_range, wgt::TextureUses::COPY_SRC);
1412
1413 let mut barriers: ArrayVec<_, 2> = src_pending
1416 .map(|pending| pending.into_hal(src_raw))
1417 .collect();
1418
1419 let dst_pending =
1420 state
1421 .tracker
1422 .textures
1423 .set_single(dst_texture, dst_range, wgt::TextureUses::COPY_DST);
1424 barriers.extend(dst_pending.map(|pending| pending.into_hal(dst_raw)));
1425
1426 let hal_copy_size = hal::CopyExtent {
1427 width: src_copy_size.width.min(dst_copy_size.width),
1428 height: src_copy_size.height.min(dst_copy_size.height),
1429 depth: src_copy_size.depth.min(dst_copy_size.depth),
1430 };
1431
1432 let regions = (0..array_layer_count).map(|rel_array_layer| {
1433 let mut src_base = src_tex_base.clone();
1434 let mut dst_base = dst_tex_base.clone();
1435 src_base.array_layer += rel_array_layer;
1436 dst_base.array_layer += rel_array_layer;
1437 hal::TextureCopy {
1438 src_base,
1439 dst_base,
1440 size: hal_copy_size,
1441 }
1442 });
1443
1444 let regions = if dst_tex_base.aspect == hal::FormatAspects::DEPTH_STENCIL {
1445 regions
1446 .flat_map(|region| {
1447 let (mut depth, mut stencil) = (region.clone(), region);
1448 depth.src_base.aspect = hal::FormatAspects::DEPTH;
1449 depth.dst_base.aspect = hal::FormatAspects::DEPTH;
1450 stencil.src_base.aspect = hal::FormatAspects::STENCIL;
1451 stencil.dst_base.aspect = hal::FormatAspects::STENCIL;
1452 [depth, stencil]
1453 })
1454 .collect::<Vec<_>>()
1455 } else {
1456 regions.collect::<Vec<_>>()
1457 };
1458 unsafe {
1459 state.raw_encoder.transition_textures(&barriers);
1460 state.raw_encoder.copy_texture_to_texture(
1461 src_raw,
1462 wgt::TextureUses::COPY_SRC,
1463 dst_raw,
1464 ®ions,
1465 );
1466 }
1467
1468 Ok(())
1469}