@@ -22,7 +22,7 @@ use crate::{
22
22
TextureInitTrackerAction ,
23
23
} ,
24
24
resource:: {
25
- MissingBufferUsageError , MissingTextureUsageError , ParentDevice , RawResourceAccess ,
25
+ Buffer , MissingBufferUsageError , MissingTextureUsageError , ParentDevice , RawResourceAccess ,
26
26
Texture , TextureErrorDimension ,
27
27
} ,
28
28
snatch:: SnatchGuard ,
@@ -34,7 +34,7 @@ pub type TexelCopyBufferInfo = wgt::TexelCopyBufferInfo<BufferId>;
34
34
pub type TexelCopyTextureInfo = wgt:: TexelCopyTextureInfo < TextureId > ;
35
35
pub type CopyExternalImageDestInfo = wgt:: CopyExternalImageDestInfo < TextureId > ;
36
36
37
- #[ derive( Clone , Copy , Debug ) ]
37
+ #[ derive( Clone , Copy , Debug , Eq , PartialEq ) ]
38
38
pub enum CopySide {
39
39
Source ,
40
40
Destination ,
@@ -271,9 +271,11 @@ pub(crate) fn extract_texture_selector<T>(
271
271
///
272
272
/// Copied with some modifications from WebGPU standard.
273
273
///
274
- /// If successful, returns a pair `(bytes, stride)`, where:
274
+ /// If successful, returns a pair `(bytes, stride, is_contiguous )`, where:
275
275
/// - `bytes` is the number of buffer bytes required for this copy, and
276
276
/// - `stride` number of bytes between array layers.
277
+ /// - `is_contiguous` is true if the linear texture data does not have padding
278
+ /// between rows or between images.
277
279
///
278
280
/// [vltd]: https://gpuweb.github.io/gpuweb/#abstract-opdef-validating-linear-texture-data
279
281
pub ( crate ) fn validate_linear_texture_data (
@@ -283,7 +285,7 @@ pub(crate) fn validate_linear_texture_data(
283
285
buffer_size : BufferAddress ,
284
286
buffer_side : CopySide ,
285
287
copy_size : & Extent3d ,
286
- ) -> Result < ( BufferAddress , BufferAddress ) , TransferError > {
288
+ ) -> Result < ( BufferAddress , BufferAddress , bool ) , TransferError > {
287
289
let wgt:: BufferTextureCopyInfo {
288
290
copy_width,
289
291
copy_height,
@@ -298,14 +300,14 @@ pub(crate) fn validate_linear_texture_data(
298
300
width_blocks : _,
299
301
height_blocks,
300
302
301
- row_bytes_dense : _ ,
303
+ row_bytes_dense,
302
304
row_stride_bytes,
303
305
304
306
image_stride_rows : _,
305
307
image_stride_bytes,
306
308
307
309
image_rows_dense : _,
308
- image_bytes_dense : _ ,
310
+ image_bytes_dense,
309
311
310
312
bytes_in_copy,
311
313
} = layout. get_buffer_texture_copy_info ( format, aspect, copy_size) ?;
@@ -342,7 +344,10 @@ pub(crate) fn validate_linear_texture_data(
342
344
} ) ;
343
345
}
344
346
345
- Ok ( ( bytes_in_copy, image_stride_bytes) )
347
+ let is_contiguous = ( row_stride_bytes == row_bytes_dense || !requires_multiple_rows)
348
+ && ( image_stride_bytes == image_bytes_dense || !requires_multiple_images) ;
349
+
350
+ Ok ( ( bytes_in_copy, image_stride_bytes, is_contiguous) )
346
351
}
347
352
348
353
/// Validation for texture/buffer copies.
@@ -680,6 +685,90 @@ fn handle_dst_texture_init(
680
685
Ok ( ( ) )
681
686
}
682
687
688
+ /// Handle initialization tracking for a transfer's source or destination buffer.
689
+ ///
690
+ /// Ensures that the transfer will not read from uninitialized memory, and updates
691
+ /// the initialization state information to reflect the transfer.
692
+ fn handle_buffer_init (
693
+ cmd_buf_data : & mut CommandBufferMutable ,
694
+ info : & TexelCopyBufferInfo ,
695
+ buffer : & Arc < Buffer > ,
696
+ direction : CopySide ,
697
+ required_buffer_bytes_in_copy : BufferAddress ,
698
+ is_contiguous : bool ,
699
+ ) {
700
+ const ALIGN_SIZE : BufferAddress = wgt:: COPY_BUFFER_ALIGNMENT ;
701
+ const ALIGN_MASK : BufferAddress = wgt:: COPY_BUFFER_ALIGNMENT - 1 ;
702
+
703
+ let start = info. layout . offset ;
704
+ let end = info. layout . offset + required_buffer_bytes_in_copy;
705
+ if !is_contiguous || direction == CopySide :: Source {
706
+ // If the transfer will read the buffer, then the whole region needs to
707
+ // be initialized.
708
+ //
709
+ // If the transfer will not write a contiguous region of the buffer,
710
+ // then we need to make sure the padding areas are initialized. For now,
711
+ // initialize the whole region, although this could be improved to
712
+ // initialize only the necessary parts if doing so is likely to be
713
+ // faster than initializing the whole thing.
714
+ //
715
+ // Adjust the start/end outwards to 4B alignment.
716
+ let aligned_start = start & !ALIGN_MASK ;
717
+ let aligned_end = ( end + ALIGN_MASK ) & !ALIGN_MASK ;
718
+ cmd_buf_data. buffer_memory_init_actions . extend (
719
+ buffer. initialization_status . read ( ) . create_action (
720
+ buffer,
721
+ aligned_start..aligned_end,
722
+ MemoryInitKind :: NeedsInitializedMemory ,
723
+ ) ,
724
+ ) ;
725
+ } else {
726
+ // If the transfer will write a contiguous region of the buffer, then we
727
+ // don't need to initialize that region.
728
+ //
729
+ // However, if the start and end are not 4B aligned, we need to make
730
+ // sure that we don't end up trying to initialize non-4B-aligned regions
731
+ // later.
732
+ //
733
+ // Adjust the start/end inwards to 4B alignment, we will handle the
734
+ // first/last pieces differently.
735
+ let aligned_start = ( start + ALIGN_MASK ) & !ALIGN_MASK ;
736
+ let aligned_end = end & !ALIGN_MASK ;
737
+ if aligned_start != start {
738
+ cmd_buf_data. buffer_memory_init_actions . extend (
739
+ buffer. initialization_status . read ( ) . create_action (
740
+ buffer,
741
+ aligned_start - ALIGN_SIZE ..aligned_start,
742
+ MemoryInitKind :: NeedsInitializedMemory ,
743
+ ) ,
744
+ ) ;
745
+ }
746
+ if aligned_start != aligned_end {
747
+ cmd_buf_data. buffer_memory_init_actions . extend (
748
+ buffer. initialization_status . read ( ) . create_action (
749
+ buffer,
750
+ aligned_start..aligned_end,
751
+ MemoryInitKind :: ImplicitlyInitialized ,
752
+ ) ,
753
+ ) ;
754
+ }
755
+ if aligned_end != end {
756
+ // It is possible that `aligned_end + ALIGN_SIZE > dst_buffer.size`,
757
+ // because `dst_buffer.size` is the user-requested size, not the
758
+ // final size of the buffer. The final size of the buffer is not
759
+ // readily available, but was rounded up to COPY_BUFFER_ALIGNMENT,
760
+ // so no overrun is possible.
761
+ cmd_buf_data. buffer_memory_init_actions . extend (
762
+ buffer. initialization_status . read ( ) . create_action (
763
+ buffer,
764
+ aligned_end..aligned_end + ALIGN_SIZE ,
765
+ MemoryInitKind :: NeedsInitializedMemory ,
766
+ ) ,
767
+ ) ;
768
+ }
769
+ }
770
+ }
771
+
683
772
impl Global {
684
773
pub fn command_encoder_copy_buffer_to_buffer (
685
774
& self ,
@@ -958,7 +1047,7 @@ impl Global {
958
1047
true , // alignment required for buffer offset
959
1048
) ?;
960
1049
961
- let ( required_buffer_bytes_in_copy, bytes_per_array_layer) =
1050
+ let ( required_buffer_bytes_in_copy, bytes_per_array_layer, is_contiguous ) =
962
1051
validate_linear_texture_data (
963
1052
& source. layout ,
964
1053
dst_texture. desc . format ,
@@ -974,12 +1063,13 @@ impl Global {
974
1063
. map_err ( TransferError :: from) ?;
975
1064
}
976
1065
977
- cmd_buf_data. buffer_memory_init_actions . extend (
978
- src_buffer. initialization_status . read ( ) . create_action (
979
- & src_buffer,
980
- source. layout . offset ..( source. layout . offset + required_buffer_bytes_in_copy) ,
981
- MemoryInitKind :: NeedsInitializedMemory ,
982
- ) ,
1066
+ handle_buffer_init (
1067
+ cmd_buf_data,
1068
+ source,
1069
+ & src_buffer,
1070
+ CopySide :: Source ,
1071
+ required_buffer_bytes_in_copy,
1072
+ is_contiguous,
983
1073
) ;
984
1074
985
1075
let regions = ( 0 ..array_layer_count)
@@ -1084,7 +1174,7 @@ impl Global {
1084
1174
true , // alignment required for buffer offset
1085
1175
) ?;
1086
1176
1087
- let ( required_buffer_bytes_in_copy, bytes_per_array_layer) =
1177
+ let ( required_buffer_bytes_in_copy, bytes_per_array_layer, is_contiguous ) =
1088
1178
validate_linear_texture_data (
1089
1179
& destination. layout ,
1090
1180
src_texture. desc . format ,
@@ -1140,13 +1230,13 @@ impl Global {
1140
1230
let dst_barrier =
1141
1231
dst_pending. map ( |pending| pending. into_hal ( & dst_buffer, & snatch_guard) ) ;
1142
1232
1143
- cmd_buf_data . buffer_memory_init_actions . extend (
1144
- dst_buffer . initialization_status . read ( ) . create_action (
1145
- & dst_buffer ,
1146
- destination . layout . offset
1147
- .. ( destination . layout . offset + required_buffer_bytes_in_copy ) ,
1148
- MemoryInitKind :: ImplicitlyInitialized ,
1149
- ) ,
1233
+ handle_buffer_init (
1234
+ cmd_buf_data ,
1235
+ destination ,
1236
+ & dst_buffer ,
1237
+ CopySide :: Destination ,
1238
+ required_buffer_bytes_in_copy ,
1239
+ is_contiguous ,
1150
1240
) ;
1151
1241
1152
1242
let regions = ( 0 ..array_layer_count)
0 commit comments