Skip to content

Commit c0f04c8

Browse files
beicausejimblandy
authored andcommitted
Validate strip_index_format equals index buffer format for indexed drawing with strip topology
1 parent b9c0962 commit c0f04c8

7 files changed

Lines changed: 47 additions & 35 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ Bottom level categories:
8585
- Tracing support has been restored. By @andyleiserson in [#8429](https://github.com/gfx-rs/wgpu/pull/8429).
8686
- Pipelines using passthrough shaders now correctly require explicit pipeline layout. By @inner-daemons in #8881.
8787
- Allow using a shader that defines I/O for dual-source blending in a pipeline that does not make use of it. By @andyleiserson in [#8856](https://github.com/gfx-rs/wgpu/pull/8856).
88+
- Validate `strip_index_format` isn't None and equals index buffer format for indexed drawing with strip topology. By @beicause in [#8850](https://github.com/gfx-rs/wgpu/pull/8850).
8889

8990
#### naga
9091

wgpu-core/src/command/bundle.rs

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -718,7 +718,7 @@ fn draw(
718718
first_vertex: u32,
719719
first_instance: u32,
720720
) -> Result<(), RenderBundleErrorInner> {
721-
state.is_ready()?;
721+
state.is_ready(DrawCommandFamily::Draw)?;
722722
let pipeline = state.pipeline()?;
723723

724724
let vertex_limits = super::VertexLimits::new(state.vertex_buffer_sizes(), &pipeline.steps);
@@ -746,13 +746,10 @@ fn draw_indexed(
746746
base_vertex: i32,
747747
first_instance: u32,
748748
) -> Result<(), RenderBundleErrorInner> {
749-
state.is_ready()?;
749+
state.is_ready(DrawCommandFamily::DrawIndexed)?;
750750
let pipeline = state.pipeline()?;
751751

752-
let index = match state.index {
753-
Some(ref index) => index,
754-
None => return Err(DrawError::MissingIndexBuffer.into()),
755-
};
752+
let index = state.index.as_ref().unwrap();
756753

757754
let vertex_limits = super::VertexLimits::new(state.vertex_buffer_sizes(), &pipeline.steps);
758755

@@ -788,7 +785,7 @@ fn draw_mesh_tasks(
788785
group_count_y: u32,
789786
group_count_z: u32,
790787
) -> Result<(), RenderBundleErrorInner> {
791-
state.is_ready()?;
788+
state.is_ready(DrawCommandFamily::DrawMeshTasks)?;
792789

793790
let groups_size_limit = state.device.limits.max_task_mesh_workgroups_per_dimension;
794791
let max_groups = state.device.limits.max_task_mesh_workgroup_total_count;
@@ -822,7 +819,7 @@ fn multi_draw_indirect(
822819
offset: u64,
823820
family: DrawCommandFamily,
824821
) -> Result<(), RenderBundleErrorInner> {
825-
state.is_ready()?;
822+
state.is_ready(family)?;
826823
state
827824
.device
828825
.require_downlevel_flags(wgt::DownlevelFlags::INDIRECT_EXECUTION)?;
@@ -846,10 +843,7 @@ fn multi_draw_indirect(
846843
));
847844

848845
let vertex_or_index_limit = if family == DrawCommandFamily::DrawIndexed {
849-
let index = match state.index {
850-
Some(ref mut index) => index,
851-
None => return Err(DrawError::MissingIndexBuffer.into()),
852-
};
846+
let index = state.index.as_mut().unwrap();
853847
state.commands.extend(index.flush());
854848
index.limit()
855849
} else {
@@ -1408,11 +1402,29 @@ impl State {
14081402
/// Validation for a draw command.
14091403
///
14101404
/// This should be further deduplicated with similar validation on render/compute passes.
1411-
fn is_ready(&mut self) -> Result<(), DrawError> {
1405+
fn is_ready(&mut self, family: DrawCommandFamily) -> Result<(), DrawError> {
14121406
if let Some(pipeline) = self.pipeline.as_ref() {
14131407
self.binder
14141408
.check_compatibility(pipeline.pipeline.as_ref())?;
14151409
self.binder.check_late_buffer_bindings()?;
1410+
1411+
if family == DrawCommandFamily::DrawIndexed {
1412+
let pipeline = &pipeline.pipeline;
1413+
let index_format = match &self.index {
1414+
Some(index) => index.format,
1415+
None => return Err(DrawError::MissingIndexBuffer),
1416+
};
1417+
1418+
if pipeline.topology.is_strip() && pipeline.strip_index_format != Some(index_format)
1419+
{
1420+
return Err(DrawError::UnmatchedStripIndexFormat {
1421+
pipeline: pipeline.error_ident(),
1422+
strip_index_format: pipeline.strip_index_format,
1423+
buffer_format: index_format,
1424+
});
1425+
}
1426+
}
1427+
14161428
Ok(())
14171429
} else {
14181430
Err(DrawError::MissingPipeline(pass::MissingPipeline))

wgpu-core/src/command/draw.rs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,17 +46,14 @@ pub enum DrawError {
4646
},
4747
#[error("Index {last_index} extends beyond limit {index_limit}. Did you bind the correct index buffer?")]
4848
IndexBeyondLimit { last_index: u64, index_limit: u64 },
49-
#[error(
50-
"Index buffer format {buffer_format:?} doesn't match {pipeline}'s index format {pipeline_format:?}"
51-
)]
52-
UnmatchedIndexFormats {
49+
#[error("For indexed drawing with strip topology, {pipeline}'s strip index format {strip_index_format:?} must match index buffer format {buffer_format:?}")]
50+
UnmatchedStripIndexFormat {
5351
pipeline: ResourceErrorIdent,
54-
pipeline_format: wgt::IndexFormat,
52+
strip_index_format: Option<wgt::IndexFormat>,
5553
buffer_format: wgt::IndexFormat,
5654
},
5755
#[error(transparent)]
5856
BindingSizeTooSmall(#[from] LateMinBufferBindingSizeMismatch),
59-
6057
#[error(
6158
"Wrong pipeline type for this draw command. Attempted to call {} draw command on {} pipeline",
6259
if *wanted_mesh_pipeline {"mesh shader"} else {"standard"},

wgpu-core/src/command/render.rs

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -559,21 +559,20 @@ impl<'scope, 'snatch_guard, 'cmd_enc> State<'scope, 'snatch_guard, 'cmd_enc> {
559559

560560
if family == DrawCommandFamily::DrawIndexed {
561561
// Pipeline expects an index buffer
562-
if let Some(pipeline_index_format) = pipeline.strip_index_format {
563-
// We have a buffer bound
564-
let buffer_index_format = self
565-
.index
566-
.buffer_format
567-
.ok_or(DrawError::MissingIndexBuffer)?;
568-
569-
// The buffers are different formats
570-
if pipeline_index_format != buffer_index_format {
571-
return Err(DrawError::UnmatchedIndexFormats {
572-
pipeline: pipeline.error_ident(),
573-
pipeline_format: pipeline_index_format,
574-
buffer_format: buffer_index_format,
575-
});
576-
}
562+
// We have a buffer bound
563+
let buffer_index_format = self
564+
.index
565+
.buffer_format
566+
.ok_or(DrawError::MissingIndexBuffer)?;
567+
568+
if pipeline.topology.is_strip()
569+
&& pipeline.strip_index_format != Some(buffer_index_format)
570+
{
571+
return Err(DrawError::UnmatchedStripIndexFormat {
572+
pipeline: pipeline.error_ident(),
573+
strip_index_format: pipeline.strip_index_format,
574+
buffer_format: buffer_index_format,
575+
});
577576
}
578577
}
579578
if (family == DrawCommandFamily::DrawMeshTasks) != pipeline.is_mesh {

wgpu-core/src/device/resource.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4632,6 +4632,7 @@ impl Device {
46324632
pass_context,
46334633
_shader_modules: shader_modules,
46344634
flags,
4635+
topology: desc.primitive.topology,
46354636
strip_index_format: desc.primitive.strip_index_format,
46364637
vertex_steps,
46374638
late_sized_buffer_groups,

wgpu-core/src/pipeline.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -807,6 +807,7 @@ pub struct RenderPipeline {
807807
pub(crate) _shader_modules: ArrayVec<Arc<ShaderModule>, { hal::MAX_CONCURRENT_SHADER_STAGES }>,
808808
pub(crate) pass_context: RenderPassContext,
809809
pub(crate) flags: PipelineFlags,
810+
pub(crate) topology: wgt::PrimitiveTopology,
810811
pub(crate) strip_index_format: Option<wgt::IndexFormat>,
811812
pub(crate) vertex_steps: Vec<VertexStep>,
812813
pub(crate) late_sized_buffer_groups: ArrayVec<LateSizedBufferGroup, { hal::MAX_BIND_GROUPS }>,

wgpu-types/src/render.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,8 @@ pub struct PrimitiveState {
374374
/// When drawing strip topologies with indices, this is the required format for the index buffer.
375375
/// This has no effect on non-indexed or non-strip draws.
376376
///
377-
/// Specifying this value enables primitive restart, allowing individual strips to be separated
377+
/// This is required for indexed drawing with strip topology and must match index buffer format, as primitive restart is always enabled
378+
/// in all backends and individual strips will be separated
378379
/// with the index value `0xFFFF` when using `Uint16`, or `0xFFFFFFFF` when using `Uint32`.
379380
#[cfg_attr(feature = "serde", serde(default))]
380381
pub strip_index_format: Option<IndexFormat>,

0 commit comments

Comments
 (0)