From 6e020a079e9a512a7465252c238c5a85b1177fc5 Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Mon, 29 Jan 2024 14:01:03 +0100 Subject: [PATCH] Fix the validation for vertex limits for regular render passes (#5156) --- CHANGELOG.md | 1 + wgpu-core/src/command/render.rs | 29 ++++++++++++++++++++++------- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5074fb597f..902a1bd1b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -76,6 +76,7 @@ Bottom level categories: #### General - Fix `panic!` when dropping `Instance` without `InstanceFlags::VALIDATION`. By @hakolao in [#5134](https://github.com/gfx-rs/wgpu/pull/5134) - Fix `serde` feature not compiling for `wgpu-types`. By @KirmesBude in [#5149](https://github.com/gfx-rs/wgpu/pull/5149) +- Fix the validation of vertex and index ranges. By @nical in [#5144](https://github.com/gfx-rs/wgpu/pull/5144) and [#5156](https://github.com/gfx-rs/wgpu/pull/5156) #### WGL diff --git a/wgpu-core/src/command/render.rs b/wgpu-core/src/command/render.rs index 933e00824b..786342a901 100644 --- a/wgpu-core/src/command/render.rs +++ b/wgpu-core/src/command/render.rs @@ -378,18 +378,33 @@ struct VertexState { impl VertexState { fn update_limits(&mut self) { - // TODO: This isn't entirely spec-compliant. - // We currently require that the buffer range can fit `stride` * count bytes. - // The spec, however, lets a buffer be a bit smaller as long as the size of the - // last element fits in it (the last element can be smaller than the stride between - // elements). + // Implements the validation from https://gpuweb.github.io/gpuweb/#dom-gpurendercommandsmixin-draw + // Except that the formula is shuffled to extract the number of vertices in order + // to carry the bulk of the computation when changing states intead of when producing + // draws. Draw calls tend to happen at a higher frequency. Here we determine vertex + // limits that can be cheaply checked for each draw call. self.vertex_limit = u32::MAX as u64; self.instance_limit = u32::MAX as u64; for (idx, vbs) in self.inputs.iter().enumerate() { - if vbs.step.stride == 0 || !vbs.bound { + if !vbs.bound { continue; } - let limit = vbs.total_size / vbs.step.stride; + + let limit = if vbs.total_size < vbs.step.last_stride { + // The buffer cannot fit the last vertex. + 0 + } else { + if vbs.step.stride == 0 { + // We already checked that the last stride fits, the same + // vertex will be repeated so this slot can accomodate any number of + // vertices. + continue; + } + + // The general case. + (vbs.total_size - vbs.step.last_stride) / vbs.step.stride + 1 + }; + match vbs.step.mode { VertexStepMode::Vertex => { if limit < self.vertex_limit {