@@ -21,7 +21,7 @@ use crate::{
21
21
TextureInitTrackerAction ,
22
22
} ,
23
23
resource:: {
24
- MissingBufferUsageError , MissingTextureUsageError , ParentDevice , RawResourceAccess ,
24
+ Buffer , MissingBufferUsageError , MissingTextureUsageError , ParentDevice , RawResourceAccess ,
25
25
Texture , TextureErrorDimension ,
26
26
} ,
27
27
snatch:: SnatchGuard ,
@@ -33,7 +33,7 @@ pub type TexelCopyBufferInfo = wgt::TexelCopyBufferInfo<BufferId>;
33
33
pub type TexelCopyTextureInfo = wgt:: TexelCopyTextureInfo < TextureId > ;
34
34
pub type CopyExternalImageDestInfo = wgt:: CopyExternalImageDestInfo < TextureId > ;
35
35
36
- #[ derive( Clone , Copy , Debug ) ]
36
+ #[ derive( Clone , Copy , Debug , Eq , PartialEq ) ]
37
37
pub enum CopySide {
38
38
Source ,
39
39
Destination ,
@@ -276,9 +276,11 @@ pub(crate) fn extract_texture_selector<T>(
276
276
///
277
277
/// Copied with some modifications from WebGPU standard.
278
278
///
279
- /// If successful, returns a pair `(bytes, stride)`, where:
279
+ /// If successful, returns a tuple `(bytes, stride, is_contiguous )`, where:
280
280
/// - `bytes` is the number of buffer bytes required for this copy, and
281
281
/// - `stride` number of bytes between array layers.
282
+ /// - `is_contiguous` is true if the linear texture data does not have padding
283
+ /// between rows or between images.
282
284
///
283
285
/// [vltd]: https://gpuweb.github.io/gpuweb/#abstract-opdef-validating-linear-texture-data
284
286
pub ( crate ) fn validate_linear_texture_data (
@@ -288,7 +290,7 @@ pub(crate) fn validate_linear_texture_data(
288
290
buffer_size : BufferAddress ,
289
291
buffer_side : CopySide ,
290
292
copy_size : & Extent3d ,
291
- ) -> Result < ( BufferAddress , BufferAddress ) , TransferError > {
293
+ ) -> Result < ( BufferAddress , BufferAddress , bool ) , TransferError > {
292
294
let wgt:: BufferTextureCopyInfo {
293
295
copy_width,
294
296
copy_height,
@@ -303,14 +305,14 @@ pub(crate) fn validate_linear_texture_data(
303
305
width_blocks : _,
304
306
height_blocks,
305
307
306
- row_bytes_dense : _ ,
308
+ row_bytes_dense,
307
309
row_stride_bytes,
308
310
309
311
image_stride_rows : _,
310
312
image_stride_bytes,
311
313
312
314
image_rows_dense : _,
313
- image_bytes_dense : _ ,
315
+ image_bytes_dense,
314
316
315
317
bytes_in_copy,
316
318
} = layout. get_buffer_texture_copy_info ( format, aspect, copy_size) ?;
@@ -347,7 +349,10 @@ pub(crate) fn validate_linear_texture_data(
347
349
} ) ;
348
350
}
349
351
350
- Ok ( ( bytes_in_copy, image_stride_bytes) )
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) )
351
356
}
352
357
353
358
/// Validate the source format of a texture copy.
@@ -733,6 +738,90 @@ fn handle_dst_texture_init(
733
738
Ok ( ( ) )
734
739
}
735
740
741
+ /// Handle initialization tracking for a transfer's source or destination buffer.
742
+ ///
743
+ /// Ensures that the transfer will not read from uninitialized memory, and updates
744
+ /// the initialization state information to reflect the transfer.
745
+ fn handle_buffer_init (
746
+ cmd_buf_data : & mut CommandBufferMutable ,
747
+ info : & TexelCopyBufferInfo ,
748
+ buffer : & Arc < Buffer > ,
749
+ direction : CopySide ,
750
+ required_buffer_bytes_in_copy : BufferAddress ,
751
+ is_contiguous : bool ,
752
+ ) {
753
+ const ALIGN_SIZE : BufferAddress = wgt:: COPY_BUFFER_ALIGNMENT ;
754
+ const ALIGN_MASK : BufferAddress = wgt:: COPY_BUFFER_ALIGNMENT - 1 ;
755
+
756
+ let start = info. layout . offset ;
757
+ let end = info. layout . offset + required_buffer_bytes_in_copy;
758
+ if !is_contiguous || direction == CopySide :: Source {
759
+ // If the transfer will read the buffer, then the whole region needs to
760
+ // be initialized.
761
+ //
762
+ // If the transfer will not write a contiguous region of the buffer,
763
+ // then we need to make sure the padding areas are initialized. For now,
764
+ // initialize the whole region, although this could be improved to
765
+ // initialize only the necessary parts if doing so is likely to be
766
+ // faster than initializing the whole thing.
767
+ //
768
+ // Adjust the start/end outwards to 4B alignment.
769
+ let aligned_start = start & !ALIGN_MASK ;
770
+ let aligned_end = ( end + ALIGN_MASK ) & !ALIGN_MASK ;
771
+ cmd_buf_data. buffer_memory_init_actions . extend (
772
+ buffer. initialization_status . read ( ) . create_action (
773
+ buffer,
774
+ aligned_start..aligned_end,
775
+ MemoryInitKind :: NeedsInitializedMemory ,
776
+ ) ,
777
+ ) ;
778
+ } else {
779
+ // If the transfer will write a contiguous region of the buffer, then we
780
+ // don't need to initialize that region.
781
+ //
782
+ // However, if the start and end are not 4B aligned, we need to make
783
+ // sure that we don't end up trying to initialize non-4B-aligned regions
784
+ // later.
785
+ //
786
+ // Adjust the start/end inwards to 4B alignment, we will handle the
787
+ // first/last pieces differently.
788
+ let aligned_start = ( start + ALIGN_MASK ) & !ALIGN_MASK ;
789
+ let aligned_end = end & !ALIGN_MASK ;
790
+ if aligned_start != start {
791
+ cmd_buf_data. buffer_memory_init_actions . extend (
792
+ buffer. initialization_status . read ( ) . create_action (
793
+ buffer,
794
+ aligned_start - ALIGN_SIZE ..aligned_start,
795
+ MemoryInitKind :: NeedsInitializedMemory ,
796
+ ) ,
797
+ ) ;
798
+ }
799
+ if aligned_start != aligned_end {
800
+ cmd_buf_data. buffer_memory_init_actions . extend (
801
+ buffer. initialization_status . read ( ) . create_action (
802
+ buffer,
803
+ aligned_start..aligned_end,
804
+ MemoryInitKind :: ImplicitlyInitialized ,
805
+ ) ,
806
+ ) ;
807
+ }
808
+ if aligned_end != end {
809
+ // It is possible that `aligned_end + ALIGN_SIZE > dst_buffer.size`,
810
+ // because `dst_buffer.size` is the user-requested size, not the
811
+ // final size of the buffer. The final size of the buffer is not
812
+ // readily available, but was rounded up to COPY_BUFFER_ALIGNMENT,
813
+ // so no overrun is possible.
814
+ cmd_buf_data. buffer_memory_init_actions . extend (
815
+ buffer. initialization_status . read ( ) . create_action (
816
+ buffer,
817
+ aligned_end..aligned_end + ALIGN_SIZE ,
818
+ MemoryInitKind :: NeedsInitializedMemory ,
819
+ ) ,
820
+ ) ;
821
+ }
822
+ }
823
+ }
824
+
736
825
impl Global {
737
826
pub fn command_encoder_copy_buffer_to_buffer (
738
827
& self ,
@@ -1004,7 +1093,7 @@ impl Global {
1004
1093
true , // alignment required for buffer offset
1005
1094
) ?;
1006
1095
1007
- let ( required_buffer_bytes_in_copy, bytes_per_array_layer) =
1096
+ let ( required_buffer_bytes_in_copy, bytes_per_array_layer, is_contiguous ) =
1008
1097
validate_linear_texture_data (
1009
1098
& source. layout ,
1010
1099
dst_texture. desc . format ,
@@ -1020,12 +1109,13 @@ impl Global {
1020
1109
. map_err ( TransferError :: from) ?;
1021
1110
}
1022
1111
1023
- cmd_buf_data. buffer_memory_init_actions . extend (
1024
- src_buffer. initialization_status . read ( ) . create_action (
1025
- & src_buffer,
1026
- source. layout . offset ..( source. layout . offset + required_buffer_bytes_in_copy) ,
1027
- MemoryInitKind :: NeedsInitializedMemory ,
1028
- ) ,
1112
+ handle_buffer_init (
1113
+ cmd_buf_data,
1114
+ source,
1115
+ & src_buffer,
1116
+ CopySide :: Source ,
1117
+ required_buffer_bytes_in_copy,
1118
+ is_contiguous,
1029
1119
) ;
1030
1120
1031
1121
let regions = ( 0 ..array_layer_count)
@@ -1124,7 +1214,7 @@ impl Global {
1124
1214
true , // alignment required for buffer offset
1125
1215
) ?;
1126
1216
1127
- let ( required_buffer_bytes_in_copy, bytes_per_array_layer) =
1217
+ let ( required_buffer_bytes_in_copy, bytes_per_array_layer, is_contiguous ) =
1128
1218
validate_linear_texture_data (
1129
1219
& destination. layout ,
1130
1220
src_texture. desc . format ,
@@ -1180,13 +1270,13 @@ impl Global {
1180
1270
let dst_barrier =
1181
1271
dst_pending. map ( |pending| pending. into_hal ( & dst_buffer, & snatch_guard) ) ;
1182
1272
1183
- cmd_buf_data . buffer_memory_init_actions . extend (
1184
- dst_buffer . initialization_status . read ( ) . create_action (
1185
- & dst_buffer ,
1186
- destination . layout . offset
1187
- .. ( destination . layout . offset + required_buffer_bytes_in_copy ) ,
1188
- MemoryInitKind :: ImplicitlyInitialized ,
1189
- ) ,
1273
+ handle_buffer_init (
1274
+ cmd_buf_data ,
1275
+ destination ,
1276
+ & dst_buffer ,
1277
+ CopySide :: Destination ,
1278
+ required_buffer_bytes_in_copy ,
1279
+ is_contiguous ,
1190
1280
) ;
1191
1281
1192
1282
let regions = ( 0 ..array_layer_count)
0 commit comments