Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(wgsl): add first and either sampling for @interpolate(flat, …) #6181

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading