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 {
1041 log::trace!("Ignoring copy_buffer_to_buffer of size 0");
1042 return Ok(());
1043 }
1044
1045 state
1047 .buffer_memory_init_actions
1048 .extend(dst_buffer.initialization_status.read().create_action(
1049 dst_buffer,
1050 destination_offset..(destination_offset + size),
1051 MemoryInitKind::ImplicitlyInitialized,
1052 ));
1053 state
1054 .buffer_memory_init_actions
1055 .extend(src_buffer.initialization_status.read().create_action(
1056 src_buffer,
1057 source_offset..(source_offset + size),
1058 MemoryInitKind::NeedsInitializedMemory,
1059 ));
1060
1061 let region = hal::BufferCopy {
1062 src_offset: source_offset,
1063 dst_offset: destination_offset,
1064 size: wgt::BufferSize::new(size).unwrap(),
1065 };
1066 let barriers = src_barrier
1067 .into_iter()
1068 .chain(dst_barrier)
1069 .collect::<Vec<_>>();
1070 unsafe {
1071 state.raw_encoder.transition_buffers(&barriers);
1072 state
1073 .raw_encoder
1074 .copy_buffer_to_buffer(src_raw, dst_raw, &[region]);
1075 }
1076
1077 Ok(())
1078}
1079
1080pub(super) fn copy_buffer_to_texture(
1081 state: &mut EncodingState,
1082 source: &wgt::TexelCopyBufferInfo<Arc<Buffer>>,
1083 destination: &wgt::TexelCopyTextureInfo<Arc<Texture>>,
1084 copy_size: &Extent3d,
1085) -> Result<(), CommandEncoderError> {
1086 let dst_texture = &destination.texture;
1087 let src_buffer = &source.buffer;
1088
1089 dst_texture.same_device(state.device)?;
1090 src_buffer.same_device(state.device)?;
1091
1092 let (hal_copy_size, array_layer_count) = validate_texture_copy_range(
1093 destination,
1094 &dst_texture.desc,
1095 CopySide::Destination,
1096 copy_size,
1097 )?;
1098
1099 let (dst_range, dst_base) = extract_texture_selector(destination, copy_size, dst_texture)?;
1100
1101 let src_raw = src_buffer.try_raw(state.snatch_guard)?;
1102 let dst_raw = dst_texture.try_raw(state.snatch_guard)?;
1103
1104 if copy_size.width == 0 || copy_size.height == 0 || copy_size.depth_or_array_layers == 0 {
1105 log::trace!("Ignoring copy_buffer_to_texture of size 0");
1106 return Ok(());
1107 }
1108
1109 handle_dst_texture_init(state, destination, copy_size, dst_texture)?;
1113
1114 let src_pending = state
1115 .tracker
1116 .buffers
1117 .set_single(src_buffer, wgt::BufferUses::COPY_SRC);
1118
1119 src_buffer
1120 .check_usage(BufferUsages::COPY_SRC)
1121 .map_err(TransferError::MissingBufferUsage)?;
1122 let src_barrier = src_pending.map(|pending| pending.into_hal(src_buffer, state.snatch_guard));
1123
1124 let dst_pending =
1125 state
1126 .tracker
1127 .textures
1128 .set_single(dst_texture, dst_range, wgt::TextureUses::COPY_DST);
1129 dst_texture
1130 .check_usage(TextureUsages::COPY_DST)
1131 .map_err(TransferError::MissingTextureUsage)?;
1132 let dst_barrier = dst_pending
1133 .map(|pending| pending.into_hal(dst_raw))
1134 .collect::<Vec<_>>();
1135
1136 validate_texture_copy_dst_format(dst_texture.desc.format, destination.aspect)?;
1137
1138 validate_texture_buffer_copy(
1139 destination,
1140 dst_base.aspect,
1141 &dst_texture.desc,
1142 &source.layout,
1143 true, )?;
1145
1146 let (required_buffer_bytes_in_copy, bytes_per_array_layer, is_contiguous) =
1147 validate_linear_texture_data(
1148 &source.layout,
1149 dst_texture.desc.format,
1150 destination.aspect,
1151 src_buffer.size,
1152 CopySide::Source,
1153 copy_size,
1154 )?;
1155
1156 if dst_texture.desc.format.is_depth_stencil_format() {
1157 state
1158 .device
1159 .require_downlevel_flags(wgt::DownlevelFlags::DEPTH_TEXTURE_AND_BUFFER_COPIES)
1160 .map_err(TransferError::from)?;
1161 }
1162
1163 handle_buffer_init(
1164 state,
1165 source,
1166 CopySide::Source,
1167 required_buffer_bytes_in_copy,
1168 is_contiguous,
1169 );
1170
1171 let regions = (0..array_layer_count)
1172 .map(|rel_array_layer| {
1173 let mut texture_base = dst_base.clone();
1174 texture_base.array_layer += rel_array_layer;
1175 let mut buffer_layout = source.layout;
1176 buffer_layout.offset += rel_array_layer as u64 * bytes_per_array_layer;
1177 hal::BufferTextureCopy {
1178 buffer_layout,
1179 texture_base,
1180 size: hal_copy_size,
1181 }
1182 })
1183 .collect::<Vec<_>>();
1184
1185 unsafe {
1186 state.raw_encoder.transition_textures(&dst_barrier);
1187 state.raw_encoder.transition_buffers(src_barrier.as_slice());
1188 state
1189 .raw_encoder
1190 .copy_buffer_to_texture(src_raw, dst_raw, ®ions);
1191 }
1192
1193 Ok(())
1194}
1195
1196pub(super) fn copy_texture_to_buffer(
1197 state: &mut EncodingState,
1198 source: &TexelCopyTextureInfo,
1199 destination: &wgt::TexelCopyBufferInfo<Arc<Buffer>>,
1200 copy_size: &Extent3d,
1201) -> Result<(), CommandEncoderError> {
1202 let src_texture = &source.texture;
1203 let dst_buffer = &destination.buffer;
1204
1205 src_texture.same_device(state.device)?;
1206 dst_buffer.same_device(state.device)?;
1207
1208 let (hal_copy_size, array_layer_count) =
1209 validate_texture_copy_range(source, &src_texture.desc, CopySide::Source, copy_size)?;
1210
1211 let (src_range, src_base) = extract_texture_selector(source, copy_size, src_texture)?;
1212
1213 let src_raw = src_texture.try_raw(state.snatch_guard)?;
1214 src_texture
1215 .check_usage(TextureUsages::COPY_SRC)
1216 .map_err(TransferError::MissingTextureUsage)?;
1217
1218 if source.mip_level >= src_texture.desc.mip_level_count {
1219 return Err(TransferError::InvalidMipLevel {
1220 requested: source.mip_level,
1221 count: src_texture.desc.mip_level_count,
1222 }
1223 .into());
1224 }
1225
1226 validate_texture_copy_src_format(src_texture.desc.format, source.aspect)?;
1227
1228 validate_texture_buffer_copy(
1229 source,
1230 src_base.aspect,
1231 &src_texture.desc,
1232 &destination.layout,
1233 true, )?;
1235
1236 let (required_buffer_bytes_in_copy, bytes_per_array_layer, is_contiguous) =
1237 validate_linear_texture_data(
1238 &destination.layout,
1239 src_texture.desc.format,
1240 source.aspect,
1241 dst_buffer.size,
1242 CopySide::Destination,
1243 copy_size,
1244 )?;
1245
1246 if src_texture.desc.format.is_depth_stencil_format() {
1247 state
1248 .device
1249 .require_downlevel_flags(wgt::DownlevelFlags::DEPTH_TEXTURE_AND_BUFFER_COPIES)
1250 .map_err(TransferError::from)?;
1251 }
1252
1253 let dst_raw = dst_buffer.try_raw(state.snatch_guard)?;
1254 dst_buffer
1255 .check_usage(BufferUsages::COPY_DST)
1256 .map_err(TransferError::MissingBufferUsage)?;
1257
1258 if copy_size.width == 0 || copy_size.height == 0 || copy_size.depth_or_array_layers == 0 {
1259 log::trace!("Ignoring copy_texture_to_buffer of size 0");
1260 return Ok(());
1261 }
1262
1263 handle_src_texture_init(state, source, copy_size, src_texture)?;
1267
1268 let src_pending =
1269 state
1270 .tracker
1271 .textures
1272 .set_single(src_texture, src_range, wgt::TextureUses::COPY_SRC);
1273 let src_barrier = src_pending
1274 .map(|pending| pending.into_hal(src_raw))
1275 .collect::<Vec<_>>();
1276
1277 let dst_pending = state
1278 .tracker
1279 .buffers
1280 .set_single(dst_buffer, wgt::BufferUses::COPY_DST);
1281
1282 let dst_barrier = dst_pending.map(|pending| pending.into_hal(dst_buffer, state.snatch_guard));
1283
1284 handle_buffer_init(
1285 state,
1286 destination,
1287 CopySide::Destination,
1288 required_buffer_bytes_in_copy,
1289 is_contiguous,
1290 );
1291
1292 let regions = (0..array_layer_count)
1293 .map(|rel_array_layer| {
1294 let mut texture_base = src_base.clone();
1295 texture_base.array_layer += rel_array_layer;
1296 let mut buffer_layout = destination.layout;
1297 buffer_layout.offset += rel_array_layer as u64 * bytes_per_array_layer;
1298 hal::BufferTextureCopy {
1299 buffer_layout,
1300 texture_base,
1301 size: hal_copy_size,
1302 }
1303 })
1304 .collect::<Vec<_>>();
1305 unsafe {
1306 state.raw_encoder.transition_buffers(dst_barrier.as_slice());
1307 state.raw_encoder.transition_textures(&src_barrier);
1308 state.raw_encoder.copy_texture_to_buffer(
1309 src_raw,
1310 wgt::TextureUses::COPY_SRC,
1311 dst_raw,
1312 ®ions,
1313 );
1314 }
1315
1316 Ok(())
1317}
1318
1319pub(super) fn copy_texture_to_texture(
1320 state: &mut EncodingState,
1321 source: &TexelCopyTextureInfo,
1322 destination: &TexelCopyTextureInfo,
1323 copy_size: &Extent3d,
1324) -> Result<(), CommandEncoderError> {
1325 let src_texture = &source.texture;
1326 let dst_texture = &destination.texture;
1327
1328 src_texture.same_device(state.device)?;
1329 dst_texture.same_device(state.device)?;
1330
1331 if src_texture.desc.format.remove_srgb_suffix() != dst_texture.desc.format.remove_srgb_suffix()
1334 {
1335 return Err(TransferError::TextureFormatsNotCopyCompatible {
1336 src_format: src_texture.desc.format,
1337 dst_format: dst_texture.desc.format,
1338 }
1339 .into());
1340 }
1341
1342 let (src_copy_size, array_layer_count) =
1343 validate_texture_copy_range(source, &src_texture.desc, CopySide::Source, copy_size)?;
1344 let (dst_copy_size, _) = validate_texture_copy_range(
1345 destination,
1346 &dst_texture.desc,
1347 CopySide::Destination,
1348 copy_size,
1349 )?;
1350
1351 if Arc::as_ptr(src_texture) == Arc::as_ptr(dst_texture) {
1352 validate_copy_within_same_texture(
1353 source,
1354 destination,
1355 src_texture.desc.format,
1356 array_layer_count,
1357 )?;
1358 }
1359
1360 let (src_range, src_tex_base) = extract_texture_selector(source, copy_size, src_texture)?;
1361 let (dst_range, dst_tex_base) = extract_texture_selector(destination, copy_size, dst_texture)?;
1362 let src_texture_aspects = hal::FormatAspects::from(src_texture.desc.format);
1363 let dst_texture_aspects = hal::FormatAspects::from(dst_texture.desc.format);
1364 if src_tex_base.aspect != src_texture_aspects {
1365 return Err(TransferError::CopySrcMissingAspects.into());
1366 }
1367 if dst_tex_base.aspect != dst_texture_aspects {
1368 return Err(TransferError::CopyDstMissingAspects.into());
1369 }
1370
1371 if src_texture.desc.sample_count != dst_texture.desc.sample_count {
1372 return Err(TransferError::SampleCountNotEqual {
1373 src_sample_count: src_texture.desc.sample_count,
1374 dst_sample_count: dst_texture.desc.sample_count,
1375 }
1376 .into());
1377 }
1378
1379 handle_src_texture_init(state, source, copy_size, src_texture)?;
1383 handle_dst_texture_init(state, destination, copy_size, dst_texture)?;
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 {
1395 log::trace!("Ignoring copy_texture_to_texture of size 0");
1396 return Ok(());
1397 }
1398
1399 let src_pending =
1400 state
1401 .tracker
1402 .textures
1403 .set_single(src_texture, src_range, wgt::TextureUses::COPY_SRC);
1404
1405 let mut barriers: ArrayVec<_, 2> = src_pending
1408 .map(|pending| pending.into_hal(src_raw))
1409 .collect();
1410
1411 let dst_pending =
1412 state
1413 .tracker
1414 .textures
1415 .set_single(dst_texture, dst_range, wgt::TextureUses::COPY_DST);
1416 barriers.extend(dst_pending.map(|pending| pending.into_hal(dst_raw)));
1417
1418 let hal_copy_size = hal::CopyExtent {
1419 width: src_copy_size.width.min(dst_copy_size.width),
1420 height: src_copy_size.height.min(dst_copy_size.height),
1421 depth: src_copy_size.depth.min(dst_copy_size.depth),
1422 };
1423
1424 let regions = (0..array_layer_count).map(|rel_array_layer| {
1425 let mut src_base = src_tex_base.clone();
1426 let mut dst_base = dst_tex_base.clone();
1427 src_base.array_layer += rel_array_layer;
1428 dst_base.array_layer += rel_array_layer;
1429 hal::TextureCopy {
1430 src_base,
1431 dst_base,
1432 size: hal_copy_size,
1433 }
1434 });
1435
1436 let regions = if dst_tex_base.aspect == hal::FormatAspects::DEPTH_STENCIL {
1437 regions
1438 .flat_map(|region| {
1439 let (mut depth, mut stencil) = (region.clone(), region);
1440 depth.src_base.aspect = hal::FormatAspects::DEPTH;
1441 depth.dst_base.aspect = hal::FormatAspects::DEPTH;
1442 stencil.src_base.aspect = hal::FormatAspects::STENCIL;
1443 stencil.dst_base.aspect = hal::FormatAspects::STENCIL;
1444 [depth, stencil]
1445 })
1446 .collect::<Vec<_>>()
1447 } else {
1448 regions.collect::<Vec<_>>()
1449 };
1450 unsafe {
1451 state.raw_encoder.transition_textures(&barriers);
1452 state.raw_encoder.copy_texture_to_texture(
1453 src_raw,
1454 wgt::TextureUses::COPY_SRC,
1455 dst_raw,
1456 ®ions,
1457 );
1458 }
1459
1460 Ok(())
1461}