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