Skip to content

Commit 309ffdc

Browse files
committed
Tweak the bytes_per_row alignment check
Previously, the check was skipped if the copy was a single row, which is not correct. The check should be made whenever bytes_per_row is specified. It is permissible not to specify bytes_per_row if the copy is a single row, but if it is specified, it must be aligned. Also removes a redundant check of the `offset` alignment. Since the offset and bytesPerRow alignment checks are not part of "validating linear texture data", I chose to remove that instance of them. These checks are now in `validate_texture_buffer_copy`, which does not correspond 1:1 with the spec, but has a comment explaining how it does correspond.
1 parent 188a8cb commit 309ffdc

File tree

4 files changed

+27
-31
lines changed

4 files changed

+27
-31
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ By @cwfitzgerald in [#8162](https://github.com/gfx-rs/wgpu/pull/8162).
118118
- Copies within the same texture must not overlap.
119119
- Copies of multisampled or depth/stencil formats must span an entire subresource (layer).
120120
- Copies of depth/stencil formats must be 4B aligned.
121+
- For texture-buffer copies, `bytes_per_row` on the buffer side must be 256B-aligned, even if the transfer is a single row.
121122
- The offset for `set_vertex_buffer` and `set_index_buffer` must be 4B aligned. By @andyleiserson in [#7929](https://github.com/gfx-rs/wgpu/pull/7929).
122123
- The offset and size of bindings are validated as fitting within the underlying buffer in more cases. By @andyleiserson in [#7911](https://github.com/gfx-rs/wgpu/pull/7911).
123124
- The function you pass to `Device::on_uncaptured_error()` must now implement `Sync` in addition to `Send`, and be wrapped in `Arc` instead of `Box`.

cts_runner/test.lst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ fails-if(dx12) webgpu:api,validation,image_copy,buffer_texture_copies:depth_sten
8282
webgpu:api,validation,image_copy,buffer_texture_copies:sample_count:*
8383
webgpu:api,validation,image_copy,buffer_texture_copies:texture_buffer_usages:*
8484
webgpu:api,validation,image_copy,buffer_texture_copies:device_mismatch:*
85+
fails-if(dx12) webgpu:api,validation,image_copy,buffer_texture_copies:offset_and_bytesPerRow:format="rgba32float";copyType="CopyB2T";dimension="1d"
86+
fails-if(dx12) webgpu:api,validation,image_copy,buffer_texture_copies:offset_and_bytesPerRow:format="rgba32float";copyType="CopyT2B";dimension="1d"
8587
fails-if(dx12) webgpu:api,validation,image_copy,buffer_texture_copies:offset_and_bytesPerRow:format="rgba8unorm";copyType="CopyB2T";dimension="2d"
8688
fails-if(dx12) webgpu:api,validation,image_copy,buffer_texture_copies:offset_and_bytesPerRow:format="rgba8unorm";copyType="CopyT2B";dimension="2d"
8789
fails-if(dx12) webgpu:api,validation,image_copy,buffer_texture_copies:offset_and_bytesPerRow:format="rgba8unorm";copyType="CopyB2T";dimension="3d"

wgpu-core/src/command/transfer.rs

Lines changed: 22 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,6 @@ pub(crate) fn validate_linear_texture_data(
288288
buffer_size: BufferAddress,
289289
buffer_side: CopySide,
290290
copy_size: &Extent3d,
291-
need_copy_aligned_rows: bool,
292291
) -> Result<(BufferAddress, BufferAddress), TransferError> {
293292
let wgt::BufferTextureCopyInfo {
294293
copy_width,
@@ -297,7 +296,7 @@ pub(crate) fn validate_linear_texture_data(
297296

298297
offset,
299298

300-
block_size_bytes,
299+
block_size_bytes: _,
301300
block_width_texels,
302301
block_height_texels,
303302

@@ -338,24 +337,6 @@ pub(crate) fn validate_linear_texture_data(
338337
return Err(TransferError::UnspecifiedRowsPerImage);
339338
};
340339

341-
if need_copy_aligned_rows {
342-
let bytes_per_row_alignment = wgt::COPY_BYTES_PER_ROW_ALIGNMENT as BufferAddress;
343-
344-
let mut offset_alignment = block_size_bytes;
345-
if format.is_depth_stencil_format() {
346-
offset_alignment = 4
347-
}
348-
if offset % offset_alignment != 0 {
349-
return Err(TransferError::UnalignedBufferOffset(offset));
350-
}
351-
352-
// The alignment of row_stride_bytes is only required if there are
353-
// multiple rows
354-
if requires_multiple_rows && row_stride_bytes % bytes_per_row_alignment != 0 {
355-
return Err(TransferError::UnalignedBytesPerRow);
356-
}
357-
}
358-
359340
// Avoid underflow in the subtraction by checking bytes_in_copy against buffer_size first.
360341
if bytes_in_copy > buffer_size || offset > buffer_size - bytes_in_copy {
361342
return Err(TransferError::BufferOverrun {
@@ -425,7 +406,15 @@ pub(crate) fn validate_texture_copy_dst_format(
425406
/// * The copy must be from/to a single aspect of the texture.
426407
/// * If `aligned` is true, the buffer offset must be aligned appropriately.
427408
///
428-
/// The following steps in the algorithm are implemented elsewhere:
409+
/// And implements the following check from WebGPU's [validating GPUTexelCopyBufferInfo][vtcbi]
410+
/// algorithm:
411+
/// * If `aligned` is true, `bytesPerRow` must be a multiple of 256.
412+
///
413+
/// Note that the `bytesPerRow` alignment check is enforced whenever
414+
/// `bytesPerRow` is specified, even if the transfer is not multiple rows and
415+
/// `bytesPerRow` could have been omitted.
416+
///
417+
/// The following steps in [validating texture buffer copy][vtbc] are implemented elsewhere:
429418
/// * Invocation of other validation algorithms.
430419
/// * The texture usage (COPY_DST / COPY_SRC) check.
431420
/// * The check for non-copyable depth/stencil formats. The caller must perform
@@ -435,11 +424,12 @@ pub(crate) fn validate_texture_copy_dst_format(
435424
/// non-copyable format.
436425
///
437426
/// [vtbc]: https://gpuweb.github.io/gpuweb/#abstract-opdef-validating-texture-buffer-copy
427+
/// [vtcbi]: https://www.w3.org/TR/webgpu/#abstract-opdef-validating-gputexelcopybufferinfo
438428
pub(crate) fn validate_texture_buffer_copy<T>(
439429
texture_copy_view: &wgt::TexelCopyTextureInfo<T>,
440430
aspect: hal::FormatAspects,
441431
desc: &wgt::TextureDescriptor<(), Vec<wgt::TextureFormat>>,
442-
offset: BufferAddress,
432+
layout: &wgt::TexelCopyBufferLayout,
443433
aligned: bool,
444434
) -> Result<(), TransferError> {
445435
if desc.sample_count != 1 {
@@ -464,8 +454,14 @@ pub(crate) fn validate_texture_buffer_copy<T>(
464454
.expect("non-copyable formats should have been rejected previously")
465455
};
466456

467-
if aligned && offset % u64::from(offset_alignment) != 0 {
468-
return Err(TransferError::UnalignedBufferOffset(offset));
457+
if aligned && layout.offset % u64::from(offset_alignment) != 0 {
458+
return Err(TransferError::UnalignedBufferOffset(layout.offset));
459+
}
460+
461+
if let Some(bytes_per_row) = layout.bytes_per_row {
462+
if aligned && bytes_per_row % wgt::COPY_BYTES_PER_ROW_ALIGNMENT != 0 {
463+
return Err(TransferError::UnalignedBytesPerRow);
464+
}
469465
}
470466

471467
Ok(())
@@ -1004,7 +1000,7 @@ impl Global {
10041000
destination,
10051001
dst_base.aspect,
10061002
&dst_texture.desc,
1007-
source.layout.offset,
1003+
&source.layout,
10081004
true, // alignment required for buffer offset
10091005
)?;
10101006

@@ -1016,7 +1012,6 @@ impl Global {
10161012
src_buffer.size,
10171013
CopySide::Source,
10181014
copy_size,
1019-
true,
10201015
)?;
10211016

10221017
if dst_texture.desc.format.is_depth_stencil_format() {
@@ -1125,7 +1120,7 @@ impl Global {
11251120
source,
11261121
src_base.aspect,
11271122
&src_texture.desc,
1128-
destination.layout.offset,
1123+
&destination.layout,
11291124
true, // alignment required for buffer offset
11301125
)?;
11311126

@@ -1137,7 +1132,6 @@ impl Global {
11371132
dst_buffer.size,
11381133
CopySide::Destination,
11391134
copy_size,
1140-
true,
11411135
)?;
11421136

11431137
if src_texture.desc.format.is_depth_stencil_format() {

wgpu-core/src/device/queue.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -763,8 +763,8 @@ impl Queue {
763763
&destination,
764764
dst_base.aspect,
765765
&dst.desc,
766-
data_layout.offset,
767-
false, // alignment not required for buffer offset
766+
&data_layout,
767+
false, // alignment not required for buffer offset or bytes per row
768768
)?;
769769

770770
// Note: `_source_bytes_per_array_layer` is ignored since we
@@ -776,7 +776,6 @@ impl Queue {
776776
data.len() as wgt::BufferAddress,
777777
CopySide::Source,
778778
size,
779-
false,
780779
)?;
781780

782781
if dst.desc.format.is_depth_stencil_format() {

0 commit comments

Comments
 (0)