20

I am trying to make function for setting shader uniforms, but when I try to compile it I get this error :

Error 2 error C2719: 'value': formal parameter with __declspec(align('16')) won't be aligned

Here is code of function:

void Shader::setUniform(std::string name, const glm::mat4 value){
    GLint uniform = glGetUniformLocation(m_program, name.c_str());
    glUniformMatrix4fv(uniform, 1, GL_FALSE, (GLfloat*)&value);
}

I am using Visual studio 2013.

genpfault
  • 51,148
  • 11
  • 85
  • 139
Jozef Culen
  • 344
  • 1
  • 2
  • 10
  • 4
    `const std::string &name, const glm::mat4 &value`. – Valeri Atamaniouk Feb 12 '15 at 22:24
  • 2
    GLM needs 16-byte alignment for its SIMD optimizations to work, so it tells the compiler this and that's where the problem is coming from. GL, on the other hand, does not care at all whether `value` is aligned on a 16-byte boundary. You should pass these by reference anyway, there is no reason to make a copy of a matrix to send to OpenGL. – Andon M. Coleman Feb 12 '15 at 22:35

3 Answers3

27

From Microsoft's documentation on that error:

The align __declspec modifier is not permitted on function parameters.

Don't copy the parameter to an unaligned location. Pass a constant reference to the existing, already-aligned data.

void Shader::setUniform(const std::string &name, const glm::mat4 & value)
//                                               ^^^^^           ^
Drew Dormann
  • 59,987
  • 13
  • 123
  • 180
0

I'm not sure about the implementation of glm::mat4, but it is not set up in a way that puts the data within it on a complete 'word' location within memory or it was created in a misaligned location (you reading from a file? Doing some pointer arithmetic tricks somewhere?)

http://virtrev.blogspot.com/2010/09/memory-alignment-theory-and-c-examples.html

If you want a hack to 'get it working' you can try:

void Shader::setUniform(std::string name, const glm::mat4 value){
    // This assumes your copy constructor works correctly
    glm::mat4 alignedMat = value;
    GLint uniform = glGetUniformLocation(m_program, name.c_str());
    glUniformMatrix4fv(uniform, 1, GL_FALSE, (GLfloat*)&value);
}

I have used this trick to force align data before. You can also do a memcpy into alignedMat to force align things at times. DO NOT ASSUME this is the right way to do it. You should be creating elements with proper alignment. It's merely for seeing what is out of alignment, testing, and debugging.

Also if you ARE using the __declspec modifier on the parameter in the method definition. Don't.

Diniden
  • 1,005
  • 6
  • 14
  • 2
    It is actually the copy made when calling this function that is the problem. `glUniformMatrix4fv (...)` does not require a 16-byte aligned address, but instantiation of a `glm::mat4` does. You can see where this problem comes from [here](https://github.com/g-truc/glm/blob/3226580a361742115b7f131ecd9e5249029a036b/glm/detail/type_vec4.hpp), `__m128` intrinsics are implicitly `__declspec(align(16))`. In theory, this limitation only applies when compiling for x86 - x64 always aligns the top of the stack on a 16-byte boundary. – Andon M. Coleman Feb 12 '15 at 23:51
-2

Pass your parameter by reference (here a 3D vector named "color"), to get rid of the alignment error:

void SetColor(btVector3 color) { m_color = color; }   // does give the error

void SetColor(btVector3 &color) { m_color = color; }  // does not
LastBlow
  • 617
  • 9
  • 16