Skip to content

Commit 27e7408

Browse files
andyleisersonjimblandy
authored andcommitted
Restore the buffer size changes
1 parent 03f1b53 commit 27e7408

File tree

26 files changed

+423
-245
lines changed

26 files changed

+423
-245
lines changed

wgpu-core/src/binding_model.rs

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -95,15 +95,48 @@ impl WebGpuError for CreateBindGroupLayoutError {
9595
}
9696
}
9797

98-
//TODO: refactor this to move out `enum BindingError`.
98+
#[derive(Clone, Debug, Error)]
99+
#[non_exhaustive]
100+
pub enum BindingError {
101+
#[error(transparent)]
102+
DestroyedResource(#[from] DestroyedResourceError),
103+
#[error("Buffer {buffer}: Binding with size {binding_size} at offset {offset} would overflow buffer size of {buffer_size}")]
104+
BindingRangeTooLarge {
105+
buffer: ResourceErrorIdent,
106+
offset: wgt::BufferAddress,
107+
binding_size: u64,
108+
buffer_size: u64,
109+
},
110+
#[error("Buffer {buffer}: Binding offset {offset} is greater than buffer size {buffer_size}")]
111+
BindingOffsetTooLarge {
112+
buffer: ResourceErrorIdent,
113+
offset: wgt::BufferAddress,
114+
buffer_size: u64,
115+
},
116+
}
99117

118+
impl WebGpuError for BindingError {
119+
fn webgpu_error_type(&self) -> ErrorType {
120+
match self {
121+
Self::DestroyedResource(e) => e.webgpu_error_type(),
122+
Self::BindingRangeTooLarge { .. } | Self::BindingOffsetTooLarge { .. } => {
123+
ErrorType::Validation
124+
}
125+
}
126+
}
127+
}
128+
129+
// TODO: there may be additional variants here that can be extracted into
130+
// `BindingError`.
100131
#[derive(Clone, Debug, Error)]
101132
#[non_exhaustive]
102133
pub enum CreateBindGroupError {
103134
#[error(transparent)]
104135
Device(#[from] DeviceError),
105136
#[error(transparent)]
106137
DestroyedResource(#[from] DestroyedResourceError),
138+
#[error(transparent)]
139+
BindingError(#[from] BindingError),
107140
#[error(
108141
"Binding count declared with at most {expected} items, but {actual} items were provided"
109142
)]
@@ -114,12 +147,6 @@ pub enum CreateBindGroupError {
114147
BindingArrayLengthMismatch { actual: usize, expected: usize },
115148
#[error("Array binding provided zero elements")]
116149
BindingArrayZeroLength,
117-
#[error("The bound range {range:?} of {buffer} overflows its size ({size})")]
118-
BindingRangeTooLarge {
119-
buffer: ResourceErrorIdent,
120-
range: Range<wgt::BufferAddress>,
121-
size: u64,
122-
},
123150
#[error("Binding size {actual} of {buffer} is less than minimum {min}")]
124151
BindingSizeTooSmall {
125152
buffer: ResourceErrorIdent,
@@ -234,14 +261,14 @@ impl WebGpuError for CreateBindGroupError {
234261
let e: &dyn WebGpuError = match self {
235262
Self::Device(e) => e,
236263
Self::DestroyedResource(e) => e,
264+
Self::BindingError(e) => e,
237265
Self::MissingBufferUsage(e) => e,
238266
Self::MissingTextureUsage(e) => e,
239267
Self::ResourceUsageCompatibility(e) => e,
240268
Self::InvalidResource(e) => e,
241269
Self::BindingArrayPartialLengthMismatch { .. }
242270
| Self::BindingArrayLengthMismatch { .. }
243271
| Self::BindingArrayZeroLength
244-
| Self::BindingRangeTooLarge { .. }
245272
| Self::BindingSizeTooSmall { .. }
246273
| Self::BindingsNumMismatch { .. }
247274
| Self::BindingZeroSize(_)

wgpu-core/src/command/bundle.rs

Lines changed: 58 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ use core::{
9393
use arrayvec::ArrayVec;
9494
use thiserror::Error;
9595

96+
use wgpu_hal::ShouldBeNonZeroExt;
9697
use wgt::error::{ErrorType, WebGpuError};
9798

9899
use crate::{
@@ -504,7 +505,7 @@ impl RenderBundleEncoder {
504505
buffer_id,
505506
index_format,
506507
offset,
507-
size,
508+
size: size.map(NonZeroU64::get),
508509
});
509510
}
510511
}
@@ -602,13 +603,14 @@ fn set_pipeline(
602603
Ok(())
603604
}
604605

606+
// This function is duplicative of `render::set_index_buffer`.
605607
fn set_index_buffer(
606608
state: &mut State,
607609
buffer_guard: &crate::storage::Storage<Fallible<Buffer>>,
608610
buffer_id: id::Id<id::markers::Buffer>,
609611
index_format: wgt::IndexFormat,
610612
offset: u64,
611-
size: Option<NonZeroU64>,
613+
size: Option<wgt::BufferSizeOrZero>,
612614
) -> Result<(), RenderBundleErrorInner> {
613615
let buffer = buffer_guard.get(buffer_id).get()?;
614616

@@ -620,28 +622,27 @@ fn set_index_buffer(
620622
buffer.same_device(&state.device)?;
621623
buffer.check_usage(wgt::BufferUsages::INDEX)?;
622624

623-
let end = match size {
624-
Some(s) => offset + s.get(),
625-
None => buffer.size,
626-
};
625+
let end = buffer.resolve_binding_size(offset, size)?;
626+
627627
state
628628
.buffer_memory_init_actions
629629
.extend(buffer.initialization_status.read().create_action(
630630
&buffer,
631-
offset..end,
631+
offset..end.get(),
632632
MemoryInitKind::NeedsInitializedMemory,
633633
));
634-
state.set_index_buffer(buffer, index_format, offset..end);
634+
state.set_index_buffer(buffer, index_format, offset..end.get());
635635
Ok(())
636636
}
637637

638+
// This function is duplicative of `render::set_vertex_buffer`.
638639
fn set_vertex_buffer(
639640
state: &mut State,
640641
buffer_guard: &crate::storage::Storage<Fallible<Buffer>>,
641642
slot: u32,
642643
buffer_id: id::Id<id::markers::Buffer>,
643644
offset: u64,
644-
size: Option<NonZeroU64>,
645+
size: Option<wgt::BufferSizeOrZero>,
645646
) -> Result<(), RenderBundleErrorInner> {
646647
let max_vertex_buffers = state.device.limits.max_vertex_buffers;
647648
if slot >= max_vertex_buffers {
@@ -662,18 +663,16 @@ fn set_vertex_buffer(
662663
buffer.same_device(&state.device)?;
663664
buffer.check_usage(wgt::BufferUsages::VERTEX)?;
664665

665-
let end = match size {
666-
Some(s) => offset + s.get(),
667-
None => buffer.size,
668-
};
666+
let end = buffer.resolve_binding_size(offset, size)?;
667+
669668
state
670669
.buffer_memory_init_actions
671670
.extend(buffer.initialization_status.read().create_action(
672671
&buffer,
673-
offset..end,
672+
offset..end.get(),
674673
MemoryInitKind::NeedsInitializedMemory,
675674
));
676-
state.vertex[slot as usize] = Some(VertexState::new(buffer, offset..end));
675+
state.vertex[slot as usize] = Some(VertexState::new(buffer, offset..end.get()));
677676
Ok(())
678677
}
679678

@@ -965,10 +964,14 @@ impl RenderBundle {
965964
size,
966965
} => {
967966
let buffer = buffer.try_raw(snatch_guard)?;
968-
let bb = hal::BufferBinding {
969-
buffer,
970-
offset: *offset,
971-
size: *size,
967+
let bb = unsafe {
968+
// SAFETY: The binding size was checked against the buffer size
969+
// in `set_index_buffer` and again in `IndexState::flush`.
970+
hal::BufferBinding::new_unchecked(
971+
buffer,
972+
*offset,
973+
size.expect("size was resolved in `RenderBundleEncoder::finish`"),
974+
)
972975
};
973976
unsafe { raw.set_index_buffer(bb, *index_format) };
974977
}
@@ -979,10 +982,14 @@ impl RenderBundle {
979982
size,
980983
} => {
981984
let buffer = buffer.try_raw(snatch_guard)?;
982-
let bb = hal::BufferBinding {
983-
buffer,
984-
offset: *offset,
985-
size: *size,
985+
let bb = unsafe {
986+
// SAFETY: The binding size was checked against the buffer size
987+
// in `set_vertex_buffer` and again in `VertexState::flush`.
988+
hal::BufferBinding::new_unchecked(
989+
buffer,
990+
*offset,
991+
size.expect("size was resolved in `RenderBundleEncoder::finish`"),
992+
)
986993
};
987994
unsafe { raw.set_vertex_buffer(*slot, bb) };
988995
}
@@ -1131,6 +1138,9 @@ crate::impl_trackable!(RenderBundle);
11311138
/// [`RenderBundleEncoder::finish`] records the currently set index buffer here,
11321139
/// and calls [`State::flush_index`] before any indexed draw command to produce
11331140
/// a `SetIndexBuffer` command if one is necessary.
1141+
///
1142+
/// Binding ranges must be validated against the size of the buffer before
1143+
/// being stored in `IndexState`.
11341144
#[derive(Debug)]
11351145
struct IndexState {
11361146
buffer: Arc<Buffer>,
@@ -1152,13 +1162,21 @@ impl IndexState {
11521162
/// Generate a `SetIndexBuffer` command to prepare for an indexed draw
11531163
/// command, if needed.
11541164
fn flush(&mut self) -> Option<ArcRenderCommand> {
1165+
// This was all checked before, but let's check again just in case.
1166+
let binding_size = self
1167+
.range
1168+
.end
1169+
.checked_sub(self.range.start)
1170+
.filter(|_| self.range.end <= self.buffer.size)
1171+
.expect("index range must be contained in buffer");
1172+
11551173
if self.is_dirty {
11561174
self.is_dirty = false;
11571175
Some(ArcRenderCommand::SetIndexBuffer {
11581176
buffer: self.buffer.clone(),
11591177
index_format: self.format,
11601178
offset: self.range.start,
1161-
size: wgt::BufferSize::new(self.range.end - self.range.start),
1179+
size: Some(binding_size),
11621180
})
11631181
} else {
11641182
None
@@ -1174,6 +1192,9 @@ impl IndexState {
11741192
/// calls this type's [`flush`] method just before any draw command to
11751193
/// produce a `SetVertexBuffer` commands if one is necessary.
11761194
///
1195+
/// Binding ranges must be validated against the size of the buffer before
1196+
/// being stored in `VertexState`.
1197+
///
11771198
/// [`flush`]: IndexState::flush
11781199
#[derive(Debug)]
11791200
struct VertexState {
@@ -1183,6 +1204,9 @@ struct VertexState {
11831204
}
11841205

11851206
impl VertexState {
1207+
/// Create a new `VertexState`.
1208+
///
1209+
/// The `range` must be contained within `buffer`.
11861210
fn new(buffer: Arc<Buffer>, range: Range<wgt::BufferAddress>) -> Self {
11871211
Self {
11881212
buffer,
@@ -1195,13 +1219,20 @@ impl VertexState {
11951219
///
11961220
/// `slot` is the index of the vertex buffer slot that `self` tracks.
11971221
fn flush(&mut self, slot: u32) -> Option<ArcRenderCommand> {
1222+
let binding_size = self
1223+
.range
1224+
.end
1225+
.checked_sub(self.range.start)
1226+
.filter(|_| self.range.end <= self.buffer.size)
1227+
.expect("vertex range must be contained in buffer");
1228+
11981229
if self.is_dirty {
11991230
self.is_dirty = false;
12001231
Some(ArcRenderCommand::SetVertexBuffer {
12011232
slot,
12021233
buffer: self.buffer.clone(),
12031234
offset: self.range.start,
1204-
size: wgt::BufferSize::new(self.range.end - self.range.start),
1235+
size: Some(binding_size),
12051236
})
12061237
} else {
12071238
None
@@ -1565,7 +1596,7 @@ where
15651596
pub mod bundle_ffi {
15661597
use super::{RenderBundleEncoder, RenderCommand};
15671598
use crate::{id, RawString};
1568-
use core::{convert::TryInto, slice};
1599+
use core::{convert::TryInto, num::NonZeroU64, slice};
15691600
use wgt::{BufferAddress, BufferSize, DynamicOffset, IndexFormat};
15701601

15711602
/// # Safety
@@ -1624,7 +1655,7 @@ pub mod bundle_ffi {
16241655
slot,
16251656
buffer_id,
16261657
offset,
1627-
size,
1658+
size: size.map(NonZeroU64::get),
16281659
});
16291660
}
16301661

wgpu-core/src/command/draw.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use wgt::error::{ErrorType, WebGpuError};
77
use super::bind::BinderError;
88
use crate::command::pass;
99
use crate::{
10-
binding_model::{LateMinBufferBindingSizeMismatch, PushConstantUploadError},
10+
binding_model::{BindingError, LateMinBufferBindingSizeMismatch, PushConstantUploadError},
1111
resource::{
1212
DestroyedResourceError, MissingBufferUsageError, MissingTextureUsageError,
1313
ResourceErrorIdent,
@@ -89,6 +89,8 @@ pub enum RenderCommandError {
8989
MissingTextureUsage(#[from] MissingTextureUsageError),
9090
#[error(transparent)]
9191
PushConstants(#[from] PushConstantUploadError),
92+
#[error(transparent)]
93+
BindingError(#[from] BindingError),
9294
#[error("Viewport size {{ w: {w}, h: {h} }} greater than device's requested `max_texture_dimension_2d` limit {max}, or less than zero")]
9395
InvalidViewportRectSize { w: f32, h: f32, max: u32 },
9496
#[error("Viewport has invalid rect {rect:?} for device's requested `max_texture_dimension_2d` limit; Origin less than -2 * `max_texture_dimension_2d` ({min}), or rect extends past 2 * `max_texture_dimension_2d` - 1 ({max})")]
@@ -110,6 +112,7 @@ impl WebGpuError for RenderCommandError {
110112
Self::MissingBufferUsage(e) => e,
111113
Self::MissingTextureUsage(e) => e,
112114
Self::PushConstants(e) => e,
115+
Self::BindingError(e) => e,
113116

114117
Self::BindGroupIndexOutOfRange { .. }
115118
| Self::VertexBufferIndexOutOfRange { .. }

0 commit comments

Comments
 (0)