I'm just started using Gfx and faced with problem passing [[f32; 2]; 2] array in ConstantBuffer to shader as uniform block. Minimal code showing the problem is here. In that code I'm trying to pass [[1.0,1.0],[1.0,1.0]] to the shader as view uniform mat2 and for debug purposes apply its values as vertices color. I expected to see white (1.0,1.0,1.0,1.0) rectangle, but the color is magenta (1.0,0.0,1.0,1.0). RenderDoc confirms that view uniform value is not that I'm trying to pass. Is it me using gfx incorrect or is a bug?
Welcome!
If it doesn't work it's for sure a bug on our side :) Unfortunately this issue is caused by aligment differences between OpenGL and Rust, which is non-trivial to fix.
Use mat4 for your matrices, which avoids alignment issues.
Regarding your issue it's related to alignment of uniform blocks in OpenGL (https://www.khronos.org/registry/OpenGL/specs/gl/glspec44.core.pdf, page 131):
mat2 is a matrix so we have to apply rule 5 or 7.. stored identically to an array of C column vectors with R components each, according to rule (4)rounded up to the base alignment of a vec4.[[f32; 4]; 2] in terms of alignment but we can't specify the alignment in Rust!gfx::Global which might not be that portable but shouldn't cause any issuemat4 for your matrices, which avoids alignment issues. (easiest way!)mem::transmute (tricky!):// Specify the values according to the alignment of OpenGL, padding with 0.0 at the end
const GLOBALS: [[f32; 4]; 2] = [
[1.0, 1.0, 0.0, 0.0],
[1.0, 1.0, 0.0, 0.0],
];
// Can't pass GLOBALS as value for the constant buffer, need to transmute it first, which is unsafe ofc!
let globals: Globals = unsafe {
std::mem::transmute(GLOBALS)
};
encoder.update_constant_buffer(&data.globals, &globals);
Triaged. Sounds like we still need to enforce alignment in Rust.
Most helpful comment
Welcome!
If it doesn't work it's for sure a bug on our side :) Unfortunately this issue is caused by aligment differences between OpenGL and Rust, which is non-trivial to fix.
Easiest workaround:
Use
mat4for your matrices, which avoids alignment issues.In-depth details:
Regarding your issue it's related to alignment of uniform blocks in OpenGL (https://www.khronos.org/registry/OpenGL/specs/gl/glspec44.core.pdf, page 131):
mat2is a matrix so we have to apply rule 5 or 7.. stored identically to an array of C column vectors with R components each, according to rule (4)rounded up to the base alignment of a vec4.[[f32; 4]; 2]in terms of alignment but we can't specify the alignment in Rust!How to deal with this (there are multiple ways):
gfx::Globalwhich might not be that portable but shouldn't cause any issuemat4for your matrices, which avoids alignment issues. (easiest way!)mem::transmute(tricky!):```Rust
constant Globals {
view: [[f32; 2]; 2] = "view",
_pad: [f32; 4] = "", // Additional padding to ensure size compatibility + alignment of following elements
}
// Specify the values according to the alignment of OpenGL, padding with 0.0 at the end
const GLOBALS: [[f32; 4]; 2] = [
[1.0, 1.0, 0.0, 0.0],
[1.0, 1.0, 0.0, 0.0],
];
// Can't pass GLOBALS as value for the constant buffer, need to transmute it first, which is unsafe ofc!
let globals: Globals = unsafe {
std::mem::transmute(GLOBALS)
};
encoder.update_constant_buffer(&data.globals, &globals);