Skip to content

Commit ef5adc9

Browse files
committed
Extract texture <-> buffer copy logic to wgpu-types
1 parent d2ab981 commit ef5adc9

File tree

4 files changed

+387
-68
lines changed

4 files changed

+387
-68
lines changed

wgpu-core/src/command/transfer.rs

+49-57
Original file line numberDiff line numberDiff line change
@@ -235,96 +235,88 @@ pub(crate) fn validate_linear_texture_data(
235235
copy_size: &Extent3d,
236236
need_copy_aligned_rows: bool,
237237
) -> Result<(BufferAddress, BufferAddress), TransferError> {
238-
// Convert all inputs to BufferAddress (u64) to avoid some of the overflow issues
239-
// Note: u64 is not always enough to prevent overflow, especially when multiplying
240-
// something with a potentially large depth value, so it is preferable to validate
241-
// the copy size before calling this function (for example via `validate_texture_copy_range`).
242-
let copy_width = copy_size.width as BufferAddress;
243-
let copy_height = copy_size.height as BufferAddress;
244-
let depth_or_array_layers = copy_size.depth_or_array_layers as BufferAddress;
245-
246-
let offset = layout.offset;
247-
248-
let block_size = format.block_copy_size(Some(aspect)).unwrap() as BufferAddress;
249-
let (block_width, block_height) = format.block_dimensions();
250-
let block_width = block_width as BufferAddress;
251-
let block_height = block_height as BufferAddress;
252-
253-
if copy_width % block_width != 0 {
238+
let wgt::BufferTextureCopyInfo {
239+
copy_width,
240+
copy_height,
241+
depth_or_array_layers,
242+
243+
offset,
244+
245+
block_size_bytes,
246+
block_width_texels,
247+
block_height_texels,
248+
249+
width_blocks: _,
250+
height_blocks,
251+
252+
row_bytes_dense,
253+
row_stride_bytes,
254+
255+
image_stride_rows: _,
256+
image_stride_bytes,
257+
258+
image_rows_dense: _,
259+
image_bytes_dense: _,
260+
261+
bytes_in_copy,
262+
} = layout.get_buffer_texture_copy_info(format, aspect, copy_size);
263+
264+
if copy_width % block_width_texels != 0 {
254265
return Err(TransferError::UnalignedCopyWidth);
255266
}
256-
if copy_height % block_height != 0 {
267+
if copy_height % block_height_texels != 0 {
257268
return Err(TransferError::UnalignedCopyHeight);
258269
}
259270

260-
let width_in_blocks = copy_width / block_width;
261-
let height_in_blocks = copy_height / block_height;
262-
263-
let bytes_in_last_row = width_in_blocks * block_size;
271+
let requires_multiple_rows = depth_or_array_layers > 1 || height_blocks > 1;
272+
let requires_multiple_images = depth_or_array_layers > 1;
264273

265-
let bytes_per_row = if let Some(bytes_per_row) = layout.bytes_per_row {
266-
let bytes_per_row = bytes_per_row as BufferAddress;
267-
if bytes_per_row < bytes_in_last_row {
274+
if let Some(raw_bytes_per_row) = layout.bytes_per_row {
275+
let raw_bytes_per_row = raw_bytes_per_row as BufferAddress;
276+
if raw_bytes_per_row < row_bytes_dense {
268277
return Err(TransferError::InvalidBytesPerRow);
269278
}
270-
bytes_per_row
271-
} else {
272-
if depth_or_array_layers > 1 || height_in_blocks > 1 {
273-
return Err(TransferError::UnspecifiedBytesPerRow);
274-
}
275-
0
276-
};
277-
let rows_per_image = if let Some(rows_per_image) = layout.rows_per_image {
278-
let rows_per_image = rows_per_image as BufferAddress;
279-
if rows_per_image < height_in_blocks {
279+
} else if requires_multiple_rows {
280+
return Err(TransferError::UnspecifiedBytesPerRow);
281+
}
282+
283+
if let Some(raw_rows_per_image) = layout.rows_per_image {
284+
let raw_rows_per_image = raw_rows_per_image as BufferAddress;
285+
if raw_rows_per_image < height_blocks {
280286
return Err(TransferError::InvalidRowsPerImage);
281287
}
282-
rows_per_image
283-
} else {
284-
if depth_or_array_layers > 1 {
285-
return Err(TransferError::UnspecifiedRowsPerImage);
286-
}
287-
0
288+
} else if requires_multiple_images {
289+
return Err(TransferError::UnspecifiedRowsPerImage);
288290
};
289291

290292
if need_copy_aligned_rows {
291293
let bytes_per_row_alignment = wgt::COPY_BYTES_PER_ROW_ALIGNMENT as BufferAddress;
292294

293-
let mut offset_alignment = block_size;
295+
let mut offset_alignment = block_size_bytes;
294296
if format.is_depth_stencil_format() {
295297
offset_alignment = 4
296298
}
297299
if offset % offset_alignment != 0 {
298300
return Err(TransferError::UnalignedBufferOffset(offset));
299301
}
300302

301-
if bytes_per_row % bytes_per_row_alignment != 0 {
303+
// The alignment of row_stride_bytes is only required if there are
304+
// multiple rows
305+
if requires_multiple_rows && row_stride_bytes % bytes_per_row_alignment != 0 {
302306
return Err(TransferError::UnalignedBytesPerRow);
303307
}
304308
}
305309

306-
let bytes_per_image = bytes_per_row * rows_per_image;
307-
308-
let required_bytes_in_copy = if depth_or_array_layers == 0 {
309-
0
310-
} else {
311-
let mut required_bytes_in_copy = bytes_per_image * (depth_or_array_layers - 1);
312-
if height_in_blocks > 0 {
313-
required_bytes_in_copy += bytes_per_row * (height_in_blocks - 1) + bytes_in_last_row;
314-
}
315-
required_bytes_in_copy
316-
};
317-
318-
if offset + required_bytes_in_copy > buffer_size {
310+
if offset + bytes_in_copy > buffer_size {
319311
return Err(TransferError::BufferOverrun {
320312
start_offset: offset,
321-
end_offset: offset + required_bytes_in_copy,
313+
end_offset: offset + bytes_in_copy,
322314
buffer_size,
323315
side: buffer_side,
324316
});
325317
}
326318

327-
Ok((required_bytes_in_copy, bytes_per_image))
319+
Ok((bytes_in_copy, image_stride_bytes))
328320
}
329321

330322
/// WebGPU's [validating texture copy range][vtcr] algorithm.

wgpu-types/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,12 @@ mod env;
3939
mod features;
4040
pub mod instance;
4141
pub mod math;
42+
mod transfers;
4243

4344
pub use counters::*;
4445
pub use features::*;
4546
pub use instance::*;
47+
pub use transfers::*;
4648

4749
/// Integral type used for [`Buffer`] offsets and sizes.
4850
///

0 commit comments

Comments
 (0)