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