Skip to content

Commit

Permalink
feat(wgsl): add first and either sampling for `@interpolate(flat,…
Browse files Browse the repository at this point in the history
… …)` (#6181)
  • Loading branch information
ErichDonGubler authored Aug 30, 2024
1 parent 34bb9e4 commit 04618b3
Show file tree
Hide file tree
Showing 29 changed files with 1,091 additions and 256 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ By @teoxoy [#6134](https://github.com/gfx-rs/wgpu/pull/6134).
#### Naga

- Support constant evaluation for `firstLeadingBit` and `firstTrailingBit` numeric built-ins in WGSL. Front-ends that translate to these built-ins also benefit from constant evaluation. By @ErichDonGubler in [#5101](https://github.com/gfx-rs/wgpu/pull/5101).
- Add `first` and `either` sampling types for `@interpolate(flat, …)` in WGSL. By @ErichDonGubler in [#6181](https://github.com/gfx-rs/wgpu/pull/6181).

#### Vulkan

Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions naga/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ cfg_aliases.workspace = true
[dev-dependencies]
diff = "0.1"
env_logger.workspace = true
itertools.workspace = true
# This _cannot_ have a version specified. If it does, crates.io will look
# for a version of the package on crates when we publish naga. Path dependencies
# are allowed through though.
Expand Down
14 changes: 9 additions & 5 deletions naga/src/back/glsl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,9 @@ pub enum Error {
Custom(String),
#[error("overrides should not be present at this stage")]
Override,
/// [`crate::Sampling::First`] is unsupported.
#[error("`{:?}` sampling is unsupported", crate::Sampling::First)]
FirstSamplingNotSupported,
}

/// Binary operation with a different logic on the GLSL side.
Expand Down Expand Up @@ -1534,7 +1537,7 @@ impl<'a, W: Write> Writer<'a, W> {
// here, regardless of the version.
if let Some(sampling) = sampling {
if emit_interpolation_and_auxiliary {
if let Some(qualifier) = glsl_sampling(sampling) {
if let Some(qualifier) = glsl_sampling(sampling)? {
write!(self.out, "{qualifier} ")?;
}
}
Expand Down Expand Up @@ -4771,14 +4774,15 @@ const fn glsl_interpolation(interpolation: crate::Interpolation) -> &'static str
}

/// Return the GLSL auxiliary qualifier for the given sampling value.
const fn glsl_sampling(sampling: crate::Sampling) -> Option<&'static str> {
const fn glsl_sampling(sampling: crate::Sampling) -> BackendResult<Option<&'static str>> {
use crate::Sampling as S;

match sampling {
S::Center => None,
Ok(match sampling {
S::First => return Err(Error::FirstSamplingNotSupported),
S::Center | S::Either => None,
S::Centroid => Some("centroid"),
S::Sample => Some("sample"),
}
})
}

/// Helper function that returns the glsl dimension string of [`ImageDimension`](crate::ImageDimension)
Expand Down
2 changes: 1 addition & 1 deletion naga/src/back/hlsl/conv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ impl crate::Sampling {
/// Return the HLSL auxiliary qualifier for the given sampling value.
pub(super) const fn to_hlsl_str(self) -> Option<&'static str> {
match self {
Self::Center => None,
Self::Center | Self::First | Self::Either => None,
Self::Centroid => Some("centroid"),
Self::Sample => Some("sample"),
}
Expand Down
1 change: 1 addition & 0 deletions naga/src/back/msl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,7 @@ impl ResolvedInterpolation {
(I::Linear, S::Centroid) => Self::CentroidNoPerspective,
(I::Linear, S::Sample) => Self::SampleNoPerspective,
(I::Flat, _) => Self::Flat,
_ => unreachable!(),
}
}

Expand Down
7 changes: 6 additions & 1 deletion naga/src/back/spv/writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1511,7 +1511,12 @@ impl Writer {
}
match sampling {
// Center sampling is the default in SPIR-V.
None | Some(crate::Sampling::Center) => (),
None
| Some(
crate::Sampling::Center
| crate::Sampling::First
| crate::Sampling::Either,
) => (),
Some(crate::Sampling::Centroid) => {
self.decorate(id, Decoration::Centroid, &[]);
}
Expand Down
2 changes: 2 additions & 0 deletions naga/src/back/wgsl/writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2061,6 +2061,8 @@ const fn sampling_str(sampling: crate::Sampling) -> &'static str {
S::Center => "",
S::Centroid => "centroid",
S::Sample => "sample",
S::First => "first",
S::Either => "either",
}
}

Expand Down
2 changes: 2 additions & 0 deletions naga/src/front/wgsl/parse/conv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ pub fn map_sampling(word: &str, span: Span) -> Result<crate::Sampling, Error<'_>
"center" => Ok(crate::Sampling::Center),
"centroid" => Ok(crate::Sampling::Centroid),
"sample" => Ok(crate::Sampling::Sample),
"first" => Ok(crate::Sampling::First),
"either" => Ok(crate::Sampling::Either),
_ => Err(Error::UnknownAttribute(span)),
}
}
Expand Down
7 changes: 7 additions & 0 deletions naga/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,13 @@ pub enum Sampling {
/// Interpolate the value at each sample location. In multisampling, invoke
/// the fragment shader once per sample.
Sample,

/// Use the value provided by the first vertex of the current primitive.
First,

/// Use the value provided by the first or last vertex of the current primitive. The exact
/// choice is implementation-dependent.
Either,
}

/// Member of a user-defined structure.
Expand Down
30 changes: 30 additions & 0 deletions naga/src/valid/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ pub enum VaryingError {
NotIOShareableType(Handle<crate::Type>),
#[error("Interpolation is not valid")]
InvalidInterpolation,
#[error("Cannot combine {interpolation:?} interpolation with the {sampling:?} sample type")]
InvalidInterpolationSamplingCombination {
interpolation: crate::Interpolation,
sampling: crate::Sampling,
},
#[error("Interpolation must be specified on vertex shader outputs and fragment shader inputs")]
MissingInterpolation,
#[error("Built-in {0:?} is not available at this stage")]
Expand Down Expand Up @@ -339,6 +344,31 @@ impl VaryingContext<'_> {
}
}

if let Some(interpolation) = interpolation {
let invalid_sampling = match (interpolation, sampling) {
(_, None)
| (
crate::Interpolation::Perspective | crate::Interpolation::Linear,
Some(
crate::Sampling::Center
| crate::Sampling::Centroid
| crate::Sampling::Sample,
),
)
| (
crate::Interpolation::Flat,
Some(crate::Sampling::First | crate::Sampling::Either),
) => None,
(_, Some(invalid_sampling)) => Some(invalid_sampling),
};
if let Some(sampling) = invalid_sampling {
return Err(VaryingError::InvalidInterpolationSamplingCombination {
interpolation,
sampling,
});
}
}

let needs_interpolation = match self.stage {
crate::ShaderStage::Vertex => self.output,
crate::ShaderStage::Fragment => !self.output,
Expand Down
18 changes: 12 additions & 6 deletions naga/tests/in/interpolate.wgsl
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
//TODO: merge with "interface"?

// NOTE: invalid combinations are tested in the
// `validation::incompatible_interpolation_and_sampling_types` test.
struct FragmentInput {
@builtin(position) position: vec4<f32>,
@location(0) @interpolate(flat) _flat : u32,
@location(1) @interpolate(linear) _linear : f32,
@location(2) @interpolate(linear, centroid) linear_centroid : vec2<f32>,
@location(3) @interpolate(linear, sample) linear_sample : vec3<f32>,
@location(4) @interpolate(perspective) perspective : vec4<f32>,
@location(5) @interpolate(perspective, centroid) perspective_centroid : f32,
@location(6) @interpolate(perspective, sample) perspective_sample : f32,
@location(1) @interpolate(flat, first) flat_first : u32,
@location(2) @interpolate(flat, either) flat_either : u32,
@location(3) @interpolate(linear) _linear : f32,
@location(4) @interpolate(linear, centroid) linear_centroid : vec2<f32>,
@location(6) @interpolate(linear, sample) linear_sample : vec3<f32>,
@location(7) @interpolate(perspective) perspective : vec4<f32>,
@location(8) @interpolate(perspective, centroid) perspective_centroid : f32,
@location(9) @interpolate(perspective, sample) perspective_sample : f32,
}

@vertex
Expand All @@ -17,6 +21,8 @@ fn vert_main() -> FragmentInput {

out.position = vec4<f32>(2.0, 4.0, 5.0, 6.0);
out._flat = 8u;
out.flat_first = 9u;
out.flat_either = 10u;
out._linear = 27.0;
out.linear_centroid = vec2<f32>(64.0, 125.0);
out.linear_sample = vec3<f32>(216.0, 343.0, 512.0);
Expand Down
15 changes: 15 additions & 0 deletions naga/tests/in/interpolate_compat.param.ron
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
(
spv: (
version: (1, 0),
capabilities: [ Shader, SampleRateShading ],
debug: true,
force_point_size: true,
adjust_coordinate_space: true,
),
glsl: (
version: Desktop(400),
writer_flags: (""),
binding_map: {},
zero_initialize_workgroup_memory: true,
),
)
39 changes: 39 additions & 0 deletions naga/tests/in/interpolate_compat.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// NOTE: This is basically the same as `interpolate.wgsl`, except for the removal of
// `@interpolate(flat, first)`, which is unsupported in GLSL and `compat`.

// NOTE: invalid combinations are tested in the
// `validation::incompatible_interpolation_and_sampling_types` test.
struct FragmentInput {
@builtin(position) position: vec4<f32>,
@location(0) @interpolate(flat) _flat : u32,
// NOTE: not supported in `compat` or GLSL
// // @location(1) @interpolate(flat, first) flat_first : u32,
@location(2) @interpolate(flat, either) flat_either : u32,
@location(3) @interpolate(linear) _linear : f32,
@location(4) @interpolate(linear, centroid) linear_centroid : vec2<f32>,
@location(6) @interpolate(linear, sample) linear_sample : vec3<f32>,
@location(7) @interpolate(perspective) perspective : vec4<f32>,
@location(8) @interpolate(perspective, centroid) perspective_centroid : f32,
@location(9) @interpolate(perspective, sample) perspective_sample : f32,
}

@vertex
fn vert_main() -> FragmentInput {
var out: FragmentInput;

out.position = vec4<f32>(2.0, 4.0, 5.0, 6.0);
out._flat = 8u;
// out.flat_first = 9u;
out.flat_either = 10u;
out._linear = 27.0;
out.linear_centroid = vec2<f32>(64.0, 125.0);
out.linear_sample = vec3<f32>(216.0, 343.0, 512.0);
out.perspective = vec4<f32>(729.0, 1000.0, 1331.0, 1728.0);
out.perspective_centroid = 2197.0;
out.perspective_sample = 2744.0;

return out;
}

@fragment
fn frag_main(val : FragmentInput) { }
18 changes: 11 additions & 7 deletions naga/tests/out/glsl/interpolate.frag_main.Fragment.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
struct FragmentInput {
vec4 position;
uint _flat;
uint flat_first;
uint flat_either;
float _linear;
vec2 linear_centroid;
vec3 linear_sample;
Expand All @@ -10,15 +12,17 @@ struct FragmentInput {
float perspective_sample;
};
flat in uint _vs2fs_location0;
noperspective in float _vs2fs_location1;
noperspective centroid in vec2 _vs2fs_location2;
noperspective sample in vec3 _vs2fs_location3;
smooth in vec4 _vs2fs_location4;
smooth centroid in float _vs2fs_location5;
smooth sample in float _vs2fs_location6;
flat in uint _vs2fs_location1;
flat in uint _vs2fs_location2;
noperspective in float _vs2fs_location3;
noperspective centroid in vec2 _vs2fs_location4;
noperspective sample in vec3 _vs2fs_location6;
smooth in vec4 _vs2fs_location7;
smooth centroid in float _vs2fs_location8;
smooth sample in float _vs2fs_location9;

void main() {
FragmentInput val = FragmentInput(gl_FragCoord, _vs2fs_location0, _vs2fs_location1, _vs2fs_location2, _vs2fs_location3, _vs2fs_location4, _vs2fs_location5, _vs2fs_location6);
FragmentInput val = FragmentInput(gl_FragCoord, _vs2fs_location0, _vs2fs_location1, _vs2fs_location2, _vs2fs_location3, _vs2fs_location4, _vs2fs_location6, _vs2fs_location7, _vs2fs_location8, _vs2fs_location9);
return;
}

40 changes: 24 additions & 16 deletions naga/tests/out/glsl/interpolate.vert_main.Vertex.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
struct FragmentInput {
vec4 position;
uint _flat;
uint flat_first;
uint flat_either;
float _linear;
vec2 linear_centroid;
vec3 linear_sample;
Expand All @@ -10,32 +12,38 @@ struct FragmentInput {
float perspective_sample;
};
flat out uint _vs2fs_location0;
noperspective out float _vs2fs_location1;
noperspective centroid out vec2 _vs2fs_location2;
noperspective sample out vec3 _vs2fs_location3;
smooth out vec4 _vs2fs_location4;
smooth centroid out float _vs2fs_location5;
smooth sample out float _vs2fs_location6;
flat out uint _vs2fs_location1;
flat out uint _vs2fs_location2;
noperspective out float _vs2fs_location3;
noperspective centroid out vec2 _vs2fs_location4;
noperspective sample out vec3 _vs2fs_location6;
smooth out vec4 _vs2fs_location7;
smooth centroid out float _vs2fs_location8;
smooth sample out float _vs2fs_location9;

void main() {
FragmentInput out_ = FragmentInput(vec4(0.0), 0u, 0.0, vec2(0.0), vec3(0.0), vec4(0.0), 0.0, 0.0);
FragmentInput out_ = FragmentInput(vec4(0.0), 0u, 0u, 0u, 0.0, vec2(0.0), vec3(0.0), vec4(0.0), 0.0, 0.0);
out_.position = vec4(2.0, 4.0, 5.0, 6.0);
out_._flat = 8u;
out_.flat_first = 9u;
out_.flat_either = 10u;
out_._linear = 27.0;
out_.linear_centroid = vec2(64.0, 125.0);
out_.linear_sample = vec3(216.0, 343.0, 512.0);
out_.perspective = vec4(729.0, 1000.0, 1331.0, 1728.0);
out_.perspective_centroid = 2197.0;
out_.perspective_sample = 2744.0;
FragmentInput _e30 = out_;
gl_Position = _e30.position;
_vs2fs_location0 = _e30._flat;
_vs2fs_location1 = _e30._linear;
_vs2fs_location2 = _e30.linear_centroid;
_vs2fs_location3 = _e30.linear_sample;
_vs2fs_location4 = _e30.perspective;
_vs2fs_location5 = _e30.perspective_centroid;
_vs2fs_location6 = _e30.perspective_sample;
FragmentInput _e34 = out_;
gl_Position = _e34.position;
_vs2fs_location0 = _e34._flat;
_vs2fs_location1 = _e34.flat_first;
_vs2fs_location2 = _e34.flat_either;
_vs2fs_location3 = _e34._linear;
_vs2fs_location4 = _e34.linear_centroid;
_vs2fs_location6 = _e34.linear_sample;
_vs2fs_location7 = _e34.perspective;
_vs2fs_location8 = _e34.perspective_centroid;
_vs2fs_location9 = _e34.perspective_sample;
return;
}

26 changes: 26 additions & 0 deletions naga/tests/out/glsl/interpolate_compat.frag_main.Fragment.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#version 400 core
struct FragmentInput {
vec4 position;
uint _flat;
uint flat_either;
float _linear;
vec2 linear_centroid;
vec3 linear_sample;
vec4 perspective;
float perspective_centroid;
float perspective_sample;
};
flat in uint _vs2fs_location0;
flat in uint _vs2fs_location2;
noperspective in float _vs2fs_location3;
noperspective centroid in vec2 _vs2fs_location4;
noperspective sample in vec3 _vs2fs_location6;
smooth in vec4 _vs2fs_location7;
smooth centroid in float _vs2fs_location8;
smooth sample in float _vs2fs_location9;

void main() {
FragmentInput val = FragmentInput(gl_FragCoord, _vs2fs_location0, _vs2fs_location2, _vs2fs_location3, _vs2fs_location4, _vs2fs_location6, _vs2fs_location7, _vs2fs_location8, _vs2fs_location9);
return;
}

Loading

0 comments on commit 04618b3

Please sign in to comment.