[naga glsl-out] Differentiate between support for std140 and std430 (#7579)

* [naga glsl-out] Differentiate between support for `std140` and `std430` layout, and emit `std140` in Uniforms when possible

* [naga glsl-out] Remove storage buffer std140 layout fallback, and error when we are unable to assign an explicit memory layout for uniform and storage globals

Co-authored-by: teoxoy <28601907+teoxoy@users.noreply.github.com>

---------

Co-authored-by: teoxoy <28601907+teoxoy@users.noreply.github.com>
This commit is contained in:
Wouter de Bruijn 2025-04-26 13:55:02 +02:00 committed by GitHub
parent 273072d82c
commit 30b247a8d1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 92 additions and 49 deletions

View File

@ -46,6 +46,10 @@ Bottom level categories:
- Add support for rendering to slices of 3D texture views and single layered 2D-Array texture views (this requires `VK_KHR_maintenance1` which should be widely available on newer drivers). By @teoxoy in [#7596](https://github.com/gfx-rs/wgpu/pull/7596)
#### Naga
- When emitting GLSL, Uniform and Storage Buffer memory layouts are now emitted even if no explicit binding is given. By @cloone8 in [#7579](https://github.com/gfx-rs/wgpu/pull/7579).
### Bug Fixes
#### Naga

View File

@ -211,6 +211,10 @@ impl Version {
*self >= Version::Desktop(130) || *self >= Version::new_gles(310)
}
fn supports_std140_layout(&self) -> bool {
*self >= Version::Desktop(140) || *self >= Version::new_gles(300)
}
fn supports_std430_layout(&self) -> bool {
*self >= Version::Desktop(430) || *self >= Version::new_gles(310)
}
@ -1186,6 +1190,68 @@ impl<'a, W: Write> Writer<'a, W> {
Ok(())
}
/// Helper method used by [Self::write_global] to write just the layout part of
/// a non image/sampler global variable, if applicable.
///
/// # Notes
///
/// Adds trailing whitespace if any layout qualifier is written
fn write_global_layout(&mut self, global: &crate::GlobalVariable) -> BackendResult {
// Determine which (if any) explicit memory layout to use, and whether we support it
let layout = match global.space {
crate::AddressSpace::Uniform => {
if !self.options.version.supports_std140_layout() {
return Err(Error::Custom(
"Uniform address space requires std140 layout support".to_string(),
));
}
Some("std140")
}
crate::AddressSpace::Storage { .. } => {
if !self.options.version.supports_std430_layout() {
return Err(Error::Custom(
"Storage address space requires std430 layout support".to_string(),
));
}
Some("std430")
}
_ => None,
};
// If our version supports explicit layouts, we can also output the explicit binding
// if we have it
if self.options.version.supports_explicit_locations() {
if let Some(ref br) = global.binding {
match self.options.binding_map.get(br) {
Some(binding) => {
write!(self.out, "layout(")?;
if let Some(layout) = layout {
write!(self.out, "{}, ", layout)?;
}
write!(self.out, "binding = {binding}) ")?;
return Ok(());
}
None => {
log::debug!("unassigned binding for {:?}", global.name);
}
}
}
}
// Either no explicit bindings are supported or we didn't have any.
// Write just the memory layout.
if let Some(layout) = layout {
write!(self.out, "layout({}) ", layout)?;
}
Ok(())
}
/// Helper method used to write non images/sampler globals
///
/// # Notes
@ -1198,34 +1264,7 @@ impl<'a, W: Write> Writer<'a, W> {
handle: Handle<crate::GlobalVariable>,
global: &crate::GlobalVariable,
) -> BackendResult {
if self.options.version.supports_explicit_locations() {
if let Some(ref br) = global.binding {
match self.options.binding_map.get(br) {
Some(binding) => {
let layout = match global.space {
crate::AddressSpace::Storage { .. } => {
if self.options.version.supports_std430_layout() {
"std430, "
} else {
"std140, "
}
}
crate::AddressSpace::Uniform => "std140, ",
_ => "",
};
write!(self.out, "layout({layout}binding = {binding}) ")?
}
None => {
log::debug!("unassigned binding for {:?}", global.name);
if let crate::AddressSpace::Storage { .. } = global.space {
if self.options.version.supports_std430_layout() {
write!(self.out, "layout(std430) ")?
}
}
}
}
}
}
self.write_global_layout(global)?;
if let crate::AddressSpace::Storage { access } = global.space {
self.write_storage_access(access)?;

View File

@ -39,11 +39,11 @@ layout(std430) buffer Bar_block_0Vertex {
AlignedWrapper data[];
} _group_0_binding_0_vs;
uniform Baz_block_1Vertex { Baz _group_0_binding_1_vs; };
layout(std140) uniform Baz_block_1Vertex { Baz _group_0_binding_1_vs; };
layout(std430) buffer type_13_block_2Vertex { ivec2 _group_0_binding_2_vs; };
uniform MatCx2InArray_block_3Vertex { MatCx2InArray _group_0_binding_3_vs; };
layout(std140) uniform MatCx2InArray_block_3Vertex { MatCx2InArray _group_0_binding_3_vs; };
void test_matrix_within_struct_accesses() {

View File

@ -20,7 +20,7 @@ struct SimParams {
};
const uint NUM_PARTICLES = 1500u;
uniform SimParams_block_0Compute { SimParams _group_0_binding_0_cs; };
layout(std140) uniform SimParams_block_0Compute { SimParams _group_0_binding_0_cs; };
layout(std430) readonly buffer Particles_block_1Compute {
Particle particles[];

View File

@ -19,15 +19,15 @@ layout(std430) buffer FooStruct_block_0Compute { FooStruct _group_0_binding_1_cs
layout(std430) readonly buffer type_6_block_1Compute { vec2 _group_0_binding_2_cs[]; };
uniform type_8_block_2Compute { vec4 _group_0_binding_3_cs[20]; };
layout(std140) uniform type_8_block_2Compute { vec4 _group_0_binding_3_cs[20]; };
uniform type_4_block_3Compute { vec3 _group_0_binding_4_cs; };
layout(std140) uniform type_4_block_3Compute { vec3 _group_0_binding_4_cs; };
uniform type_9_block_4Compute { mat3x2 _group_0_binding_5_cs; };
layout(std140) uniform type_9_block_4Compute { mat3x2 _group_0_binding_5_cs; };
uniform type_12_block_5Compute { mat2x4 _group_0_binding_6_cs[2][2]; };
layout(std140) uniform type_12_block_5Compute { mat2x4 _group_0_binding_6_cs[2][2]; };
uniform type_15_block_6Compute { mat4x2 _group_0_binding_7_cs[2][2]; };
layout(std140) uniform type_15_block_6Compute { mat4x2 _group_0_binding_7_cs[2][2]; };
void test_msl_packed_vec3_as_arg(vec3 arg) {

View File

@ -18,11 +18,11 @@ struct Test3_ {
mat4x3 a;
float b;
};
uniform Test_block_0Vertex { Test _group_0_binding_0_vs; };
layout(std140) uniform Test_block_0Vertex { Test _group_0_binding_0_vs; };
uniform Test2_block_1Vertex { Test2_ _group_0_binding_1_vs; };
layout(std140) uniform Test2_block_1Vertex { Test2_ _group_0_binding_1_vs; };
uniform Test3_block_2Vertex { Test3_ _group_0_binding_2_vs; };
layout(std140) uniform Test3_block_2Vertex { Test3_ _group_0_binding_2_vs; };
void main() {

View File

@ -5,7 +5,7 @@ precision highp int;
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
uniform type_block_0Compute { float _group_0_binding_0_cs; };
layout(std140) uniform type_block_0Compute { float _group_0_binding_0_cs; };
int five() {

View File

@ -24,9 +24,9 @@ struct Light {
const vec3 c_ambient = vec3(0.05, 0.05, 0.05);
const uint c_max_lights = 10u;
uniform Globals_block_0Fragment { Globals _group_0_binding_0_fs; };
layout(std140) uniform Globals_block_0Fragment { Globals _group_0_binding_0_fs; };
uniform Entity_block_1Fragment { Entity _group_1_binding_0_fs; };
layout(std140) uniform Entity_block_1Fragment { Entity _group_1_binding_0_fs; };
layout(std430) readonly buffer type_8_block_2Fragment { Light _group_0_binding_1_fs[]; };

View File

@ -24,11 +24,11 @@ struct Light {
const vec3 c_ambient = vec3(0.05, 0.05, 0.05);
const uint c_max_lights = 10u;
uniform Globals_block_0Fragment { Globals _group_0_binding_0_fs; };
layout(std140) uniform Globals_block_0Fragment { Globals _group_0_binding_0_fs; };
uniform Entity_block_1Fragment { Entity _group_1_binding_0_fs; };
layout(std140) uniform Entity_block_1Fragment { Entity _group_1_binding_0_fs; };
uniform type_9_block_2Fragment { Light _group_0_binding_1_fs[10]; };
layout(std140) uniform type_9_block_2Fragment { Light _group_0_binding_1_fs[10]; };
uniform highp sampler2DArrayShadow _group_0_binding_2_fs;

View File

@ -24,9 +24,9 @@ struct Light {
const vec3 c_ambient = vec3(0.05, 0.05, 0.05);
const uint c_max_lights = 10u;
uniform Globals_block_0Vertex { Globals _group_0_binding_0_vs; };
layout(std140) uniform Globals_block_0Vertex { Globals _group_0_binding_0_vs; };
uniform Entity_block_1Vertex { Entity _group_1_binding_0_vs; };
layout(std140) uniform Entity_block_1Vertex { Entity _group_1_binding_0_vs; };
layout(location = 0) in ivec4 _p2vs_location0;
layout(location = 1) in ivec4 _p2vs_location1;

View File

@ -14,7 +14,7 @@ struct NeedsPadding {
vec3 v3_needs_padding;
float f3_;
};
uniform NeedsPadding_block_0Compute { NeedsPadding _group_0_binding_2_cs; };
layout(std140) uniform NeedsPadding_block_0Compute { NeedsPadding _group_0_binding_2_cs; };
layout(std430) buffer NeedsPadding_block_1Compute { NeedsPadding _group_0_binding_3_cs; };

View File

@ -14,7 +14,7 @@ struct NeedsPadding {
vec3 v3_needs_padding;
float f3_;
};
uniform NoPadding_block_0Compute { NoPadding _group_0_binding_0_cs; };
layout(std140) uniform NoPadding_block_0Compute { NoPadding _group_0_binding_0_cs; };
layout(std430) buffer NoPadding_block_1Compute { NoPadding _group_0_binding_1_cs; };