Skip to content

Commit e46eda2

Browse files
inner-daemonsatlv24cwfitzgerald
authored
Full per_vertex implementation (#9219)
* Some stuff worked on * Works on MSL * Ready for test 2 * Fix for a thing lol * Fixed 2 errors * Fixed DXC * Add changelog * Updated CI to hopefully pass on macOS * Various fixes * Some final fixes * CHanged CI * Update naga/src/front/wgsl/parse/directive/enable_extension.rs Co-authored-by: atlv <email@atlasdostal.com> * Thing --------- Co-authored-by: atlv <email@atlasdostal.com> Co-authored-by: Connor Fitzgerald <connorwadefitzgerald@gmail.com>
1 parent e8afd9a commit e46eda2

31 files changed

Lines changed: 295 additions & 22 deletions

File tree

.github/workflows/shaders.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ jobs:
6767
6868
naga-validate-macos:
6969
name: "Validate: MSL"
70-
runs-on: macos-15
70+
runs-on: macos-26
7171
steps:
7272
- uses: actions/checkout@v6
7373

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ Bottom level categories:
4949
- BLAS support for procedural AABB geometry (`BlasGeometrySizeDescriptors::AABBs`, `BlasAabbGeometry`, and related descriptors). By @dylanblokhuis in [#9290](https://github.com/gfx-rs/wgpu/pull/9290)
5050
- Added "limit bucketing" functionality which can adjust adapter limits and features to match one of several pre-defined buckets. This is controlled by the new `apply_limit_buckets` member in `RequestAdapterOptions`, which is `false` by default. By @andyleiserson in [#9119](https://github.com/gfx-rs/wgpu/pull/9119).
5151
- Make `wgpu_types::texture::format::TextureChannel` accessible as `wgpu::TextureChannel`. By @TornaxO7 in [#9394](https://github.com/gfx-rs/wgpu/pull/9349).
52+
- Add support for `per_vertex` in Metal and DX12, as well as some validation for `per_vertex`, and a new enable extension, `wgpu_per_vertex`. By @inner-daemons in [#9219](https://github.com/gfx-rs/wgpu/pull/9219).
5253

5354
#### Metal
5455

naga/src/back/hlsl/conv.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ impl crate::Interpolation {
222222
Self::Perspective => None,
223223
Self::Linear => Some("noperspective"),
224224
Self::Flat => Some("nointerpolation"),
225-
Self::PerVertex => unreachable!(),
225+
Self::PerVertex => Some("nointerpolation"),
226226
}
227227
}
228228
}

naga/src/back/hlsl/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -821,7 +821,7 @@ pub fn supported_capabilities() -> crate::valid::Capabilities {
821821
| Caps::STORAGE_TEXTURE_BINDING_ARRAY_NON_UNIFORM_INDEXING
822822
| Caps::STORAGE_BUFFER_BINDING_ARRAY_NON_UNIFORM_INDEXING
823823
// No COOPERATIVE_MATRIX
824-
// No PER_VERTEX
824+
| Caps::PER_VERTEX
825825
// No RAY_TRACING_PIPELINE
826826
// No DRAW_INDEX
827827
// No MEMORY_DECORATION_VOLATILE

naga/src/back/hlsl/writer.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -921,6 +921,23 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> {
921921
ep_input.local_invocation_index_name.as_ref().unwrap()
922922
)?;
923923
}
924+
Some(crate::Binding::Location {
925+
interpolation: Some(crate::Interpolation::PerVertex),
926+
..
927+
}) => {
928+
if self.options.shader_model < ShaderModel::V6_1 {
929+
return Err(Error::ShaderModelTooLow(
930+
"per_vertex fragment inputs".to_string(),
931+
ShaderModel::V6_1,
932+
));
933+
}
934+
write!(
935+
self.out,
936+
"{{ GetAttributeAtVertex({0}.{1}, 0), GetAttributeAtVertex({0}.{1}, 1), GetAttributeAtVertex({0}.{1}, 2) }}",
937+
ep_input.arg_name,
938+
fake_member.name,
939+
)?;
940+
}
924941
_ => {
925942
write!(self.out, "{}.{}", ep_input.arg_name, fake_member.name)?;
926943
}

naga/src/back/msl/mod.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ enum ResolvedInterpolation {
189189
SamplePerspective,
190190
SampleNoPerspective,
191191
Flat,
192+
PerVertex,
192193
}
193194

194195
// Note: some of these should be removed in favor of proper IR validation.
@@ -239,6 +240,8 @@ pub enum Error {
239240
ResolveArraySizeError(#[from] crate::proc::ResolveArraySizeError),
240241
#[error("entry point with stage {0:?} and name '{1}' not found")]
241242
EntryPointNotFound(ir::ShaderStage, String),
243+
#[error("Per vertex fragment inputs are not supported prior to MSL 4.0")]
244+
PerVertexNotSupported,
242245
}
243246

244247
#[derive(Clone, Debug, PartialEq, thiserror::Error)]
@@ -792,6 +795,7 @@ impl ResolvedInterpolation {
792795
(I::Linear, S::Centroid) => Self::CentroidNoPerspective,
793796
(I::Linear, S::Sample) => Self::SampleNoPerspective,
794797
(I::Flat, _) => Self::Flat,
798+
(I::PerVertex, S::Center) => Self::PerVertex,
795799
_ => unreachable!(),
796800
}
797801
}
@@ -805,6 +809,7 @@ impl ResolvedInterpolation {
805809
Self::SamplePerspective => "sample_perspective",
806810
Self::SampleNoPerspective => "sample_no_perspective",
807811
Self::Flat => "flat",
812+
Self::PerVertex => unreachable!(),
808813
};
809814
out.write_str(identifier)?;
810815
Ok(())
@@ -871,7 +876,7 @@ pub fn supported_capabilities() -> crate::valid::Capabilities {
871876
| Caps::STORAGE_TEXTURE_BINDING_ARRAY_NON_UNIFORM_INDEXING
872877
| Caps::STORAGE_BUFFER_BINDING_ARRAY_NON_UNIFORM_INDEXING
873878
| Caps::COOPERATIVE_MATRIX
874-
// No PER_VERTEX
879+
| Caps::PER_VERTEX
875880
// No RAY_TRACING_PIPELINE
876881
// No DRAW_INDEX
877882
// No MEMORY_DECORATION_VOLATILE

naga/src/back/msl/writer.rs

Lines changed: 68 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,16 @@ impl TypeContext<'_> {
216216
_ => None,
217217
}
218218
}
219+
220+
fn unwrap_array(self) -> Self {
221+
match self.gctx.types[self.handle].inner {
222+
crate::TypeInner::Array { base, .. } => Self {
223+
handle: base,
224+
..self
225+
},
226+
_ => self,
227+
}
228+
}
219229
}
220230

221231
impl Display for TypeContext<'_> {
@@ -7088,6 +7098,7 @@ template <typename A>
70887098
let stage_in_name = self.namer.call(&format!("{fun_name}Input"));
70897099
let varyings_member_name = self.namer.call("varyings");
70907100
let mut has_varyings = false;
7101+
70917102
if !flattened_arguments.is_empty() {
70927103
if !do_vertex_pulling {
70937104
writeln!(self.out, "struct {stage_in_name} {{")?;
@@ -7129,8 +7140,25 @@ template <typename A>
71297140
);
71307141
} else {
71317142
has_varyings = true;
7132-
write!(self.out, "{}{} {}", back::INDENT, ty_name, name)?;
7133-
resolved.try_fmt(&mut self.out)?;
7143+
if let super::ResolvedBinding::User {
7144+
prefix,
7145+
index,
7146+
interpolation: Some(super::ResolvedInterpolation::PerVertex),
7147+
} = resolved
7148+
{
7149+
if options.lang_version < (4, 0) {
7150+
return Err(Error::PerVertexNotSupported);
7151+
}
7152+
write!(
7153+
self.out,
7154+
"{}{NAMESPACE}::vertex_value<{}> {name} [[user({prefix}{index})]]",
7155+
back::INDENT,
7156+
ty_name.unwrap_array()
7157+
)?;
7158+
} else {
7159+
write!(self.out, "{}{} {}", back::INDENT, ty_name, name)?;
7160+
resolved.try_fmt(&mut self.out)?;
7161+
}
71347162
writeln!(self.out, ";")?;
71357163
}
71367164
}
@@ -7856,16 +7884,51 @@ template <typename A>
78567884
{
78577885
write!(self.out, "{{}}, ")?;
78587886
}
7859-
if let Some(crate::Binding::Location { .. }) = member.binding {
7860-
if has_varyings {
7861-
write!(self.out, "{varyings_member_name}.")?;
7887+
match member.binding {
7888+
Some(crate::Binding::Location {
7889+
interpolation: Some(crate::Interpolation::PerVertex),
7890+
..
7891+
}) => {
7892+
writeln!(
7893+
self.out,
7894+
"{0}{{ {1}.{2}.get({NAMESPACE}::vertex_index::first), {1}.{2}.get({NAMESPACE}::vertex_index::second), {1}.{2}.get({NAMESPACE}::vertex_index::third) }}",
7895+
back::INDENT,
7896+
varyings_member_name,
7897+
arg_name,
7898+
)?;
7899+
continue;
7900+
}
7901+
Some(crate::Binding::Location { .. }) => {
7902+
if has_varyings {
7903+
write!(self.out, "{varyings_member_name}.")?;
7904+
}
78627905
}
7906+
_ => (),
78637907
}
78647908
write!(self.out, "{name}")?;
78657909
}
78667910
writeln!(self.out, " }};")?;
78677911
}
78687912
_ => match arg.binding {
7913+
Some(crate::Binding::Location {
7914+
interpolation: Some(crate::Interpolation::PerVertex),
7915+
..
7916+
}) => {
7917+
let ty_name = TypeContext {
7918+
handle: arg.ty,
7919+
gctx: module.to_ctx(),
7920+
names: &self.names,
7921+
access: crate::StorageAccess::empty(),
7922+
first_time: false,
7923+
};
7924+
writeln!(
7925+
self.out,
7926+
"{0}const {ty_name} {arg_name} = {{ {1}.{2}.get({NAMESPACE}::vertex_index::first), {1}.{2}.get({NAMESPACE}::vertex_index::second), {1}.{2}.get({NAMESPACE}::vertex_index::third) }};",
7927+
back::INDENT,
7928+
varyings_member_name,
7929+
arg_name,
7930+
)?;
7931+
}
78697932
Some(crate::Binding::Location { .. })
78707933
| Some(crate::Binding::BuiltIn(crate::BuiltIn::Barycentric { .. })) => {
78717934
if has_varyings {

naga/src/back/wgsl/writer.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,7 @@ impl<W: Write> Writer<W> {
296296
cooperative_matrix: bool,
297297
draw_index: bool,
298298
ray_tracing_pipeline: bool,
299+
per_vertex: bool,
299300
}
300301
let mut needed = RequiredEnabled {
301302
mesh_shaders: module.uses_mesh_shaders(),
@@ -321,6 +322,12 @@ impl<W: Write> Writer<W> {
321322
} => {
322323
needed.mesh_shaders = true;
323324
}
325+
crate::Binding::Location {
326+
interpolation: Some(crate::Interpolation::PerVertex),
327+
..
328+
} => {
329+
needed.per_vertex = true;
330+
}
324331
crate::Binding::BuiltIn(crate::BuiltIn::DrawIndex) => needed.draw_index = true,
325332
crate::Binding::BuiltIn(
326333
crate::BuiltIn::RayInvocationId
@@ -450,6 +457,10 @@ impl<W: Write> Writer<W> {
450457
writeln!(self.out, "enable wgpu_ray_tracing_pipeline;")?;
451458
any_written = true;
452459
}
460+
if needed.per_vertex {
461+
writeln!(self.out, "enable wgpu_per_vertex;")?;
462+
any_written = true;
463+
}
453464
if any_written {
454465
// Empty line for readability
455466
writeln!(self.out)?;

naga/src/front/wgsl/parse/conv.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,12 +172,19 @@ pub fn map_built_in(
172172
Ok(built_in)
173173
}
174174

175-
pub fn map_interpolation(word: &str, span: Span) -> Result<'_, crate::Interpolation> {
175+
pub fn map_interpolation(
176+
enable_extensions: &EnableExtensions,
177+
word: &str,
178+
span: Span,
179+
) -> Result<'static, crate::Interpolation> {
176180
match word {
177181
"linear" => Ok(crate::Interpolation::Linear),
178182
"flat" => Ok(crate::Interpolation::Flat),
179183
"perspective" => Ok(crate::Interpolation::Perspective),
180-
"per_vertex" => Ok(crate::Interpolation::PerVertex),
184+
"per_vertex" => {
185+
enable_extensions.require(ImplementedEnableExtension::PerVertex, span)?;
186+
Ok(crate::Interpolation::PerVertex)
187+
}
181188
_ => Err(Box::new(Error::UnknownAttribute(span))),
182189
}
183190
}

naga/src/front/wgsl/parse/directive/enable_extension.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ pub(crate) struct EnableExtensions {
2121
wgpu_cooperative_matrix: bool,
2222
draw_index: bool,
2323
primitive_index: bool,
24+
per_vertex: bool,
2425
}
2526

2627
impl EnableExtensions {
@@ -36,6 +37,7 @@ impl EnableExtensions {
3637
wgpu_cooperative_matrix: false,
3738
draw_index: false,
3839
primitive_index: false,
40+
per_vertex: false,
3941
}
4042
}
4143

@@ -56,6 +58,7 @@ impl EnableExtensions {
5658
ImplementedEnableExtension::WgpuCooperativeMatrix => &mut self.wgpu_cooperative_matrix,
5759
ImplementedEnableExtension::DrawIndex => &mut self.draw_index,
5860
ImplementedEnableExtension::PrimitiveIndex => &mut self.primitive_index,
61+
ImplementedEnableExtension::PerVertex => &mut self.per_vertex,
5962
};
6063
*field = true;
6164
}
@@ -75,6 +78,7 @@ impl EnableExtensions {
7578
ImplementedEnableExtension::WgpuCooperativeMatrix => self.wgpu_cooperative_matrix,
7679
ImplementedEnableExtension::DrawIndex => self.draw_index,
7780
ImplementedEnableExtension::PrimitiveIndex => self.primitive_index,
81+
ImplementedEnableExtension::PerVertex => self.per_vertex,
7882
}
7983
}
8084

@@ -127,6 +131,7 @@ impl EnableExtension {
127131
const SUBGROUPS: &'static str = "subgroups";
128132
const PRIMITIVE_INDEX: &'static str = "primitive_index";
129133
const DRAW_INDEX: &'static str = "draw_index";
134+
const PER_VERTEX: &'static str = "wgpu_per_vertex";
130135

131136
/// Convert from a sentinel word in WGSL into its associated [`EnableExtension`], if possible.
132137
pub(crate) fn from_ident(word: &str, span: Span) -> Result<'_, Self> {
@@ -150,6 +155,7 @@ impl EnableExtension {
150155
Self::SUBGROUPS => Self::Unimplemented(UnimplementedEnableExtension::Subgroups),
151156
Self::DRAW_INDEX => Self::Implemented(ImplementedEnableExtension::DrawIndex),
152157
Self::PRIMITIVE_INDEX => Self::Implemented(ImplementedEnableExtension::PrimitiveIndex),
158+
Self::PER_VERTEX => Self::Implemented(ImplementedEnableExtension::PerVertex),
153159
_ => return Err(Box::new(Error::UnknownEnableExtension(span, word))),
154160
})
155161
}
@@ -170,6 +176,7 @@ impl EnableExtension {
170176
ImplementedEnableExtension::DrawIndex => Self::DRAW_INDEX,
171177
ImplementedEnableExtension::PrimitiveIndex => Self::PRIMITIVE_INDEX,
172178
ImplementedEnableExtension::WgpuRayTracingPipeline => Self::RAY_TRACING_PIPELINE,
179+
ImplementedEnableExtension::PerVertex => Self::PER_VERTEX,
173180
},
174181
Self::Unimplemented(kind) => match kind {
175182
UnimplementedEnableExtension::Subgroups => Self::SUBGROUPS,
@@ -218,6 +225,8 @@ pub enum ImplementedEnableExtension {
218225
///
219226
/// [`enable primitive-index;`]: https://www.w3.org/TR/WGSL/#extension-primitive_index
220227
PrimitiveIndex,
228+
/// Enables the `wgpu_per_vertex` extension, allows using `@interpolate(per_vertex)` attribute in WGSL, native only.
229+
PerVertex,
221230
}
222231

223232
impl ImplementedEnableExtension {
@@ -233,6 +242,7 @@ impl ImplementedEnableExtension {
233242
Self::WgpuCooperativeMatrix,
234243
Self::DrawIndex,
235244
Self::PrimitiveIndex,
245+
Self::PerVertex,
236246
];
237247

238248
/// Returns slice of all variants of [`ImplementedEnableExtension`].
@@ -254,6 +264,7 @@ impl ImplementedEnableExtension {
254264
Self::WgpuRayTracingPipeline => C::RAY_TRACING_PIPELINE,
255265
Self::DrawIndex => C::DRAW_INDEX,
256266
Self::PrimitiveIndex => C::PRIMITIVE_INDEX,
267+
Self::PerVertex => C::PER_VERTEX,
257268
}
258269
}
259270
}

0 commit comments

Comments
 (0)