Gfx: ConstantBuffer handling.

Created on 3 Oct 2017  路  2Comments  路  Source: gfx-rs/gfx

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?

pre-ll OpenGL average hal bug medium

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 mat4 for 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):

  • mat2 is a matrix so we have to apply rule 5 or 7
  • Which leads us to .. stored identically to an array of C column vectors with R components each, according to rule (4)
  • Rule 4 defines the alignment for such arrays of vectors: rounded up to the base alignment of a vec4.
  • So we actually have [[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):

  • Use gfx::Global which might not be that portable but shouldn't cause any issue
  • Use mat4 for your matrices, which avoids alignment issues. (easiest way!)
  • Workaround of it with padding and 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);

All 2 comments

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 mat4 for 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):

  • mat2 is a matrix so we have to apply rule 5 or 7
  • Which leads us to .. stored identically to an array of C column vectors with R components each, according to rule (4)
  • Rule 4 defines the alignment for such arrays of vectors: rounded up to the base alignment of a vec4.
  • So we actually have [[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):

  • Use gfx::Global which might not be that portable but shouldn't cause any issue
  • Use mat4 for your matrices, which avoids alignment issues. (easiest way!)
  • Workaround of it with padding and 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);

Triaged. Sounds like we still need to enforce alignment in Rust.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

kvark picture kvark  路  3Comments

kvark picture kvark  路  3Comments

torkleyy picture torkleyy  路  4Comments

Limeth picture Limeth  路  3Comments

clevijoki picture clevijoki  路  3Comments