-
Notifications
You must be signed in to change notification settings - Fork 24
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
Round Up Size of All Structures to Structure Alignment #29
Comments
I'm not sure if this works in all cases but this seems to work in at least some cases: fn padded_size<T: AsStd140>() -> usize {
(T::std140_size_static() + <T as AsStd140>::Std140Type::ALIGNMENT - 1)
& !(<T as AsStd140>::Std140Type::ALIGNMENT - 1)
} |
I made a PR for the above as it seems to work, though I'm not certain it is fully correct as I just don't know enough about all of this stuff yet. :) #30 |
Copying from cart/bevy#18 Looking at the wgsl spec: https://www.w3.org/TR/WGSL/#alignment-and-size For wgsl: it looks like a struct's alignment is the maximum alignment of its members. And a struct's size is the offset of the last member of the struct, plus the size of the last member of the struct (which is what std140_size_static() returns, unless I am mistaken) rounded up to the alignment of the struct, which is what the Std140Type::ALIGNMENT is. So I think this should be correct for structs. I think implicit-stride arrays work the same way as glsl arrays, except that glsl seems to say things about aligning to vec4 unconditionally in some situations:
(...more rules follow these. Read more here: https://www.khronos.org/registry/OpenGL/specs/gl/glspec45.core.pdf#page=159 ) It's not exactly clear to me what the |
Well... it seems it doesn't work in all cases. We're using #27 and with: #[repr(C)]
#[derive(Copy, Clone, AsStd140, Default, Debug)]
pub struct GpuOmniLight {
view_proj: Mat4,
color: Vec4,
position: Vec3,
range: f32,
radius: f32,
shadow_bias_min: f32,
shadow_bias_max: f32,
}
#[repr(C)]
#[derive(Copy, Clone, AsStd140, Default, Debug)]
pub struct GpuDirectionalLight {
view_projection: Mat4,
color: Vec4,
dir_to_light: Vec3,
shadow_bias_min: f32,
shadow_bias_max: f32,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, AsStd140)]
pub struct GpuLights {
omni_lights: [GpuOmniLight; MAX_OMNI_LIGHTS],
directional_lights: [GpuDirectionalLight; MAX_DIRECTIONAL_LIGHTS],
ambient_color: Vec4,
n_omni_lights: u32,
n_directional_lights: u32,
}
pub const MAX_OMNI_LIGHTS: usize = 10;
pub const MAX_DIRECTIONAL_LIGHTS: usize = 1; I get
I wonder what the difference is... |
For reference:
|
I have tried to do the calculations manually:
Where am I incorrect such that wgpu/naga says that wgsl expects 1280 and I get 1264? |
Ok, the 1280 is a false alarm. It's an old bug in naga pre-0.5.0. bevy depends on wgpu 0.8.1 at the moment, which depends on naga 0.4.2, which reports a size of 1280 for this struct, where naga 0.5.0 and later (I checked master too) report 1264 as expected. |
I have updated #30 with what should be recursive padding. The use bevy_math::{Mat4, Vec3};
use crevice::{
internal::bytemuck::try_cast_slice,
std140::{AsStd140, Std140, Std140Convertible},
};
#[derive(AsStd140, Clone, Debug)]
struct Bleh {
a: Mat4,
b: Vec3,
}
#[derive(AsStd140, Debug)]
struct Other {
a: Bleh,
b: f32,
}
fn main() {
let bleh = Bleh {
a: Mat4::from_cols_array(&[1.0f32; 16]),
b: Vec3::ONE,
};
let other = Other {
a: bleh.clone(),
b: 1.0,
};
println!(
"Bleh size {} padded size {}",
Bleh::std140_size_static(),
Bleh::std140_padded_size_static()
);
println!(
"Other size {} padded size {}",
Other::std140_size_static(),
Other::std140_padded_size_static()
);
println!("\nbleh: {:?}", bleh);
println!("other: {:?}", other);
let bleh_value = bleh.as_padded_std140();
let bleh_bytes = bleh_value.as_bytes();
let bleh_f32 = try_cast_slice::<u8, f32>(bleh_bytes).unwrap();
println!("\nbleh_f32: {}", bleh_f32.len() * 4);
println!("mat4: {:?}", &bleh_f32[0..(16)]);
println!("vec3: {:?}", &bleh_f32[(16)..(16 + 3)]);
println!("padding: {:?}", &bleh_f32[(16 + 3)..(16 + 4)]);
let other_value = other.as_padded_std140();
let other_bytes = other_value.as_bytes();
let other_f32 = try_cast_slice::<u8, f32>(other_bytes).unwrap();
println!("\nother_f32: {}", other_f32.len() * 4);
println!("mat4: {:?}", &other_f32[0..(16)]);
println!("vec3: {:?}", &other_f32[(16)..(16 + 3)]);
println!("padding: {:?}", &other_f32[(16 + 3)..(16 + 4)]);
println!("f32: {:?}", &other_f32[(16 + 4)..(16 + 4 + 1)]);
println!("padding: {:?}", &other_f32[(16 + 4 + 1)..(16 + 4 + 1 + 3)]);
} gives:
I haven't implemented more tests, nor the changes to |
Some discussion around this happened here #20 (comment) |
Be ready to split some hairs :).
Take the following struct
Crevice interprets this struct as being of size 76, via calling
std140_size_static
.This goes against what both the wgsl and GL spec specify, asking for a size of 80 (
roundUp(16, 64 + 12)
). It also interprets this struct as size80
instead of the proper size96
.struct Other { Bleh a; f32 b; }
wgsl:
GL:
This GL spec rules only applies to the context of it being a member. Wgsl specifies this for both being a member and a top level struct. The GL spec does not say the size of the struct when it is a top level struct. Because of this omission, it should be valid to always interpret the size of this struct as 80.
This should make everyone agree, then we can live a happy life away from all this hair splitting and spec reading.
The text was updated successfully, but these errors were encountered: