Skip to content

Commit 1115dc8

Browse files
WIP: refactor(core)!: factor out BufferOverrunError type
1 parent 7e35342 commit 1115dc8

2 files changed

Lines changed: 73 additions & 60 deletions

File tree

wgpu-core/src/command/transfer.rs

Lines changed: 57 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -37,34 +37,68 @@ pub enum CopySide {
3737
Destination,
3838
}
3939

40-
/// Error encountered while attempting a data transfer.
40+
/// Error encountered while checking offsets against a buffer.
4141
#[derive(Clone, Debug, Error)]
4242
#[non_exhaustive]
43-
pub enum TransferError {
44-
#[error("Source and destination cannot be the same buffer")]
45-
SameSourceDestinationBuffer,
46-
#[error(transparent)]
47-
MissingBufferUsage(#[from] MissingBufferUsageError),
48-
#[error(transparent)]
49-
MissingTextureUsage(#[from] MissingTextureUsageError),
50-
#[error("Start offset ({offset}) is out-of-bounds for buffer of size {buffer_size}")]
51-
BufferStartOffsetOverrun {
43+
pub enum BufferOverrunError {
44+
#[error("start offset ({offset}) is out-of-bounds for buffer of size {buffer_size}")]
45+
StartOffset {
5246
offset: BufferAddress,
5347
buffer_size: BufferAddress,
54-
side: CopySide,
5548
},
5649
#[error(
57-
"End offset (start at {} + size of {}) is out-of-bounds for buffer of size {}",
50+
"end offset (start at {} + size of {}) is out-of-bounds for buffer of size {}",
5851
offset,
5952
size,
6053
buffer_size
6154
)]
62-
BufferEndOffsetOverrun {
55+
EndOffset {
6356
offset: BufferAddress,
6457
size: BufferAddress,
6558
buffer_size: BufferAddress,
66-
side: CopySide,
6759
},
60+
}
61+
62+
impl BufferOverrunError {
63+
/// Returns the end offset if everything is validated.
64+
///
65+
/// TODO: more
66+
pub(crate) fn check(
67+
offset: BufferAddress,
68+
size: BufferAddress,
69+
buffer_size: BufferAddress,
70+
) -> Result<BufferAddress, Self> {
71+
if offset >= buffer_size {
72+
return Err(Self::StartOffset {
73+
offset,
74+
buffer_size,
75+
});
76+
}
77+
// NOTE: Should never underflow because of our earlier check.
78+
if size > buffer_size - offset {
79+
return Err(Self::EndOffset {
80+
offset,
81+
size,
82+
buffer_size,
83+
});
84+
}
85+
// NOTE: Should never overflow because of our earlier check.
86+
Ok(offset + size)
87+
}
88+
}
89+
90+
/// Error encountered while attempting a data transfer.
91+
#[derive(Clone, Debug, Error)]
92+
#[non_exhaustive]
93+
pub enum TransferError {
94+
#[error("Source and destination cannot be the same buffer")]
95+
SameSourceDestinationBuffer,
96+
#[error(transparent)]
97+
MissingBufferUsage(#[from] MissingBufferUsageError),
98+
#[error(transparent)]
99+
MissingTextureUsage(#[from] MissingTextureUsageError),
100+
#[error("Transfer {_0}")]
101+
BufferOverrun(BufferOverrunError),
68102
#[error("Copy of {dimension:?} {start_offset}..{end_offset} would end up overrunning the bounds of the {side:?} texture of {dimension:?} size {texture_size}")]
69103
TextureOverrun {
70104
start_offset: u32,
@@ -244,6 +278,12 @@ impl From<BufferTextureCopyInfoError> for TransferError {
244278
}
245279
}
246280

281+
impl BufferOverrunError {
282+
fn to_transfer_error(&self, side: CopySide) -> TransferError {
283+
todo!()
284+
}
285+
}
286+
247287
pub(crate) fn extract_texture_selector<T>(
248288
copy_texture: &wgt::TexelCopyTextureInfo<T>,
249289
copy_size: &Extent3d,
@@ -352,22 +392,9 @@ pub(crate) fn validate_linear_texture_data(
352392
return Err(TransferError::UnspecifiedRowsPerImage);
353393
};
354394

355-
if offset > buffer_size {
356-
return Err(TransferError::BufferStartOffsetOverrun {
357-
start_offset: offset,
358-
buffer_size: bytes_in_copy,
359-
side: buffer_side,
360-
});
361-
}
362-
// NOTE: Should never underflow because of our earlier check.
363-
if bytes_in_copy > buffer_size - offset {
364-
return Err(TransferError::BufferEndOffsetOverrun {
365-
offset,
366-
size: bytes_in_copy,
367-
buffer_size,
368-
side: buffer_side,
369-
});
370-
}
395+
// Avoid underflow in the subtraction by checking bytes_in_copy against buffer_size first.
396+
let _ = BufferOverrunError::check(offset, bytes_in_copy, buffer_size)
397+
.map_err(|e| e.to_transfer_error(buffer_side))?;
371398

372399
let is_contiguous = (row_stride_bytes == row_bytes_dense || !requires_multiple_rows)
373400
&& (image_stride_bytes == image_bytes_dense || !requires_multiple_images);

wgpu-core/src/resource.rs

Lines changed: 16 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -301,22 +301,8 @@ pub enum BufferAccessError {
301301
MapAborted,
302302
#[error(transparent)]
303303
InvalidResource(#[from] InvalidResourceError),
304-
#[error("Map start offset ({offset}) is out-of-bounds for buffer of size {buffer_size}")]
305-
MapStartOffsetOverrun {
306-
offset: wgt::BufferAddress,
307-
buffer_size: wgt::BufferAddress,
308-
},
309-
#[error(
310-
"Map end offset (start at {} + size of {}) is out-of-bounds for buffer of size {}",
311-
offset,
312-
size,
313-
buffer_size
314-
)]
315-
MapEndOffsetOverrun {
316-
offset: wgt::BufferAddress,
317-
size: wgt::BufferAddress,
318-
buffer_size: wgt::BufferAddress,
319-
},
304+
#[error("Map {_0}")]
305+
MapOverrun(BufferOverrunError),
320306
}
321307

322308
impl WebGpuError for BufferAccessError {
@@ -743,20 +729,20 @@ impl Buffer {
743729
let map_state = &*self.map_state.lock();
744730
match *map_state {
745731
BufferMapState::Init { ref staging_buffer } => {
746-
if offset > self.size {
747-
return Err(BufferAccessError::MapStartOffsetOverrun {
748-
offset,
749-
buffer_size: self.size,
750-
});
751-
}
752-
// NOTE: Should never underflow because of our earlier check.
753-
if range_size > self.size - offset {
754-
return Err(BufferAccessError::MapEndOffsetOverrun {
755-
offset,
756-
size: range_size,
757-
buffer_size: self.size,
758-
});
759-
}
732+
(??) if offset >= self.size {
733+
(??) return Err(BufferAccessError::MapStartOffsetOverrun {
734+
(??) offset,
735+
(??) buffer_size: self.size,
736+
(??) });
737+
(??) }
738+
(??) // NOTE: Should never underflow because of our earlier check.
739+
(??) if range_size > self.size - offset {
740+
(??) return Err(BufferAccessError::MapEndOffsetOverrun {
741+
(??) offset,
742+
(??) size: range_size,
743+
(??) buffer_size: self.size,
744+
(??) });
745+
(??) }
760746
let ptr = unsafe { staging_buffer.ptr() };
761747
let ptr = unsafe { NonNull::new_unchecked(ptr.as_ptr().offset(offset as isize)) };
762748
Ok((ptr, range_size))

0 commit comments

Comments
 (0)