floooh / oryol

A small, portable and extensible C++ 3D coding framework
MIT License
1.99k stars 200 forks source link

Incorrect uniform layout with mat2 #308

Open Ohmnivore opened 6 years ago

Ohmnivore commented 6 years ago

Summary

I added a mat2 uniform to my vertex shader. I assigned it an identity matrix so I was surprised when my mesh stopped displaying. I replaced the uniform by the literal identity mat2(vec2(1, 0), vec2(0, 1)) and the mesh displayed correctly.

So I checked with Nvidia Nsight and I found the issue.

My uniform declaration:

uniform params {
    mat4 viewProj;
    mat2 model;
};

My uniform data looks like this (params[0] on the GPU):

Address Data
0x00000000         0.00250         0.00000         0.00000         0.00000
0x00000010         0.00000         0.00333         0.00000         0.00000
0x00000020         0.00000         0.00000        -0.00100         0.00000
0x00000030         0.00000         0.00000         0.00150         1.00000
0x00000040         1.00000         0.00000         0.00000         1.00000
0x00000050         0.00000         0.00000         0.00000         0.00000

The generated vertex shader tries to initialize the mat2 like this: mat2(params[4].xy, params[5].xy)

According to the data it should be: mat2(params[4].xy, params[4].zw)

Test case

https://github.com/Ohmnivore/battle/tree/5c88e270fef19618425dbfa82b6217bc87c7dafc

Overview (the project only has two source files):

// Render Gfx::ApplyDrawState(this->mainDrawState); Gfx::ApplyUniformBlock(this->mainVSParams); Gfx::Draw(0);



## Generated files
* [shaders.h](https://gist.github.com/Ohmnivore/0d4a8eaf1cc850ea607867dedd5d27fb#file-shaders-h)
* [shaders.cc](https://gist.github.com/Ohmnivore/0d4a8eaf1cc850ea607867dedd5d27fb#file-shaders-cc)
* [Vertex shader contents](https://gist.github.com/Ohmnivore/0d4a8eaf1cc850ea607867dedd5d27fb#file-mainvs-glsl)
Ohmnivore commented 6 years ago

Using target win64-vstudio-debug btw

Ohmnivore commented 6 years ago

Digging deeper. Here's shaders_mainVS.glsl330.json:

{
  "stage":  "vs",
  "uniform_blocks": [{
      "type": "params",
      "name": "_15",
      "slot": 0,
      "size": 96,
      "members":  [{
          "name": "viewProj",
          "type": "mat4",
          "num":  1,
          "offset": 0,
          "matrix_stride":  16
        }, {
          "name": "model",
          "type": "mat2",
          "num":  1,
          "offset": 64,
          "matrix_stride":  16
        }]
    }],
  "textures": [],
  "inputs": [{
      "name": "position",
      "type": "vec4",
      "slot": 0
    }, {
      "name": "texcoord0",
      "type": "vec2",
      "slot": 2
    }],
  "outputs":  [{
      "name": "uv",
      "type": "vec2"
    }]
}
Ohmnivore commented 6 years ago

I tried putting the mat2 into its own separate uniform block (gba) but it's still the same.

gba[0]

Address Data
0x00000000         1.00000         0.00000         0.00000         1.00000
0x00000010         0.00000         0.00000         0.00000         0.00000

It's using gba[0].xy, gba[1].xy instead of gba[0].xyzw.

floooh commented 6 years ago

Thanks for the detailed bug report :) This might be a bug in one of those places:

I guess I need to update the shader toolchain to the latest version SPIRVCross first so that I can drop my own fork. This will be quite a bit of work, and I probably won't get around to this in the next few weeks.

Can you workaround the problem for now?

Ohmnivore commented 6 years ago

It turned out that I needed a mat3 (to include 2D translation) instead of a mat2.

I tried mat3 but I got an error:

shaders.glsl(2): error : invalid uniform block member type 'mat3', must be (mat4,mat2,vec4,vec3,vec2,float)

I don't remember where I read it but I know that mat3 arrays aren't supported. Gfx/doc/Shaders.md says that simple mat3 should be fine though.

So I used a mat4 uniform instead. I cast to and from, using glm::mat4(myMat3CPU) and mat3(myMat4GPU) to get desired behavior. It's my workaround. I think the same could be done for mat2.

No worries and thanks for the libraries! I'm really enjoying using Oryol and its ecosystem.