Skip to content

Commit 1bafb3a

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 0c13dd6 commit 1bafb3a

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
@@ -70,6 +70,7 @@ By @Vecvec in [#7913](https://github.com/gfx-rs/wgpu/pull/7913).
7070
- Copies within the same texture must not overlap.
7171
- Copies of multisampled or depth/stencil formats must span an entire subresource (layer).
7272
- Copies of depth/stencil formats must be 4B aligned.
73+
- For texture-buffer copies, `bytes_per_row` on the buffer side must be 256B-aligned, even if the transfer is a single row.
7374
- 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).
7475
- 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).
7576
- 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
@@ -68,6 +68,8 @@ fails-if(dx12) webgpu:api,validation,image_copy,buffer_texture_copies:depth_sten
6868
webgpu:api,validation,image_copy,buffer_texture_copies:sample_count:*
6969
webgpu:api,validation,image_copy,buffer_texture_copies:texture_buffer_usages:*
7070
webgpu:api,validation,image_copy,buffer_texture_copies:device_mismatch:*
71+
fails-if(dx12) webgpu:api,validation,image_copy,buffer_texture_copies:offset_and_bytesPerRow:format="rgba32float";copyType="CopyB2T";dimension="1d"
72+
fails-if(dx12) webgpu:api,validation,image_copy,buffer_texture_copies:offset_and_bytesPerRow:format="rgba32float";copyType="CopyT2B";dimension="1d"
7173
fails-if(dx12) webgpu:api,validation,image_copy,buffer_texture_copies:offset_and_bytesPerRow:format="rgba8unorm";copyType="CopyB2T";dimension="2d"
7274
fails-if(dx12) webgpu:api,validation,image_copy,buffer_texture_copies:offset_and_bytesPerRow:format="rgba8unorm";copyType="CopyT2B";dimension="2d"
7375
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
@@ -283,7 +283,6 @@ pub(crate) fn validate_linear_texture_data(
283283
buffer_size: BufferAddress,
284284
buffer_side: CopySide,
285285
copy_size: &Extent3d,
286-
need_copy_aligned_rows: bool,
287286
) -> Result<(BufferAddress, BufferAddress), TransferError> {
288287
let wgt::BufferTextureCopyInfo {
289288
copy_width,
@@ -292,7 +291,7 @@ pub(crate) fn validate_linear_texture_data(
292291

293292
offset,
294293

295-
block_size_bytes,
294+
block_size_bytes: _,
296295
block_width_texels,
297296
block_height_texels,
298297

@@ -333,24 +332,6 @@ pub(crate) fn validate_linear_texture_data(
333332
return Err(TransferError::UnspecifiedRowsPerImage);
334333
};
335334

336-
if need_copy_aligned_rows {
337-
let bytes_per_row_alignment = wgt::COPY_BYTES_PER_ROW_ALIGNMENT as BufferAddress;
338-
339-
let mut offset_alignment = block_size_bytes;
340-
if format.is_depth_stencil_format() {
341-
offset_alignment = 4
342-
}
343-
if offset % offset_alignment != 0 {
344-
return Err(TransferError::UnalignedBufferOffset(offset));
345-
}
346-
347-
// The alignment of row_stride_bytes is only required if there are
348-
// multiple rows
349-
if requires_multiple_rows && row_stride_bytes % bytes_per_row_alignment != 0 {
350-
return Err(TransferError::UnalignedBytesPerRow);
351-
}
352-
}
353-
354335
// Avoid underflow in the subtraction by checking bytes_in_copy against buffer_size first.
355336
if bytes_in_copy > buffer_size || offset > buffer_size - bytes_in_copy {
356337
return Err(TransferError::BufferOverrun {
@@ -372,7 +353,15 @@ pub(crate) fn validate_linear_texture_data(
372353
/// * The copy must be from/to a single aspect of the texture.
373354
/// * If `aligned` is true, the buffer offset must be aligned appropriately.
374355
///
375-
/// The following steps in the algorithm are implemented elsewhere:
356+
/// And implements the following check from WebGPU's [validating GPUTexelCopyBufferInfo][vtcbi]
357+
/// algorithm:
358+
/// * If `aligned` is true, `bytesPerRow` must be a multiple of 256.
359+
///
360+
/// Note that the `bytesPerRow` alignment check is enforced whenever
361+
/// `bytesPerRow` is specified, even if the transfer is not multiple rows and
362+
/// `bytesPerRow` could have been omitted.
363+
///
364+
/// The following steps in [validating texture buffer copy][vtbc] are implemented elsewhere:
376365
/// * Invocation of other validation algorithms.
377366
/// * The texture usage (COPY_DST / COPY_SRC) check.
378367
/// * The check for non-copyable depth/stencil formats. The caller must perform
@@ -382,11 +371,12 @@ pub(crate) fn validate_linear_texture_data(
382371
/// non-copyable format.
383372
///
384373
/// [vtbc]: https://gpuweb.github.io/gpuweb/#abstract-opdef-validating-texture-buffer-copy
374+
/// [vtcbi]: https://www.w3.org/TR/webgpu/#abstract-opdef-validating-gputexelcopybufferinfo
385375
pub(crate) fn validate_texture_buffer_copy<T>(
386376
texture_copy_view: &wgt::TexelCopyTextureInfo<T>,
387377
aspect: hal::FormatAspects,
388378
desc: &wgt::TextureDescriptor<(), Vec<wgt::TextureFormat>>,
389-
offset: BufferAddress,
379+
layout: &wgt::TexelCopyBufferLayout,
390380
aligned: bool,
391381
) -> Result<(), TransferError> {
392382
if desc.sample_count != 1 {
@@ -411,8 +401,14 @@ pub(crate) fn validate_texture_buffer_copy<T>(
411401
.expect("non-copyable formats should have been rejected previously")
412402
};
413403

414-
if aligned && offset % u64::from(offset_alignment) != 0 {
415-
return Err(TransferError::UnalignedBufferOffset(offset));
404+
if aligned && layout.offset % u64::from(offset_alignment) != 0 {
405+
return Err(TransferError::UnalignedBufferOffset(layout.offset));
406+
}
407+
408+
if let Some(bytes_per_row) = layout.bytes_per_row {
409+
if aligned && bytes_per_row % wgt::COPY_BYTES_PER_ROW_ALIGNMENT != 0 {
410+
return Err(TransferError::UnalignedBytesPerRow);
411+
}
416412
}
417413

418414
Ok(())
@@ -958,7 +954,7 @@ impl Global {
958954
destination,
959955
dst_base.aspect,
960956
&dst_texture.desc,
961-
source.layout.offset,
957+
&source.layout,
962958
true, // alignment required for buffer offset
963959
)?;
964960

@@ -970,7 +966,6 @@ impl Global {
970966
src_buffer.size,
971967
CopySide::Source,
972968
copy_size,
973-
true,
974969
)?;
975970

976971
if dst_texture.desc.format.is_depth_stencil_format() {
@@ -1085,7 +1080,7 @@ impl Global {
10851080
source,
10861081
src_base.aspect,
10871082
&src_texture.desc,
1088-
destination.layout.offset,
1083+
&destination.layout,
10891084
true, // alignment required for buffer offset
10901085
)?;
10911086

@@ -1097,7 +1092,6 @@ impl Global {
10971092
dst_buffer.size,
10981093
CopySide::Destination,
10991094
copy_size,
1100-
true,
11011095
)?;
11021096

11031097
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
@@ -759,8 +759,8 @@ impl Queue {
759759
&destination,
760760
dst_base.aspect,
761761
&dst.desc,
762-
data_layout.offset,
763-
false, // alignment not required for buffer offset
762+
&data_layout,
763+
false, // alignment not required for buffer offset or bytes per row
764764
)?;
765765

766766
// Note: `_source_bytes_per_array_layer` is ignored since we
@@ -772,7 +772,6 @@ impl Queue {
772772
data.len() as wgt::BufferAddress,
773773
CopySide::Source,
774774
size,
775-
false,
776775
)?;
777776

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

0 commit comments

Comments
 (0)