KhronosGroup / WebGL

The Official Khronos WebGL Repository
Other
2.66k stars 670 forks source link

row_major qualifier for square matrices works strangely. #3062

Open WJsjtu opened 4 years ago

WJsjtu commented 4 years ago

I just wrote a demo from https://www.khronos.org/registry/webgl/sdk/tests/conformance2/glsl3/matrix-row-major.html?webglVersion=2&dumpShaders=undefined&quiet=0:

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title>Row-major matrix test</title>
  <link rel="stylesheet" href="https://www.khronos.org/registry/webgl/sdk/tests/resources/js-test-style.css" />
  <script src="https://www.khronos.org/registry/webgl/sdk/tests/js/js-test-pre.js"></script>
  <script src="https://www.khronos.org/registry/webgl/sdk/tests/js/webgl-test-utils.js"></script>
  <script src="https://www.khronos.org/registry/webgl/sdk/tests/js/glsl-conformance-test.js"></script>
</head>

<body>
  <div id="description"></div>
  <div id="console"></div>
  <script id="vshaderUniformMatrixRowMajor" type="x-shader/x-vertex">#version 300 es
out vec2 pos;
in vec4 vPosition;
in vec2 texCoord0;
void main()
{
  pos = texCoord0;
  pos.y = 1.0 - pos.y;
  gl_Position = vPosition;
}
</script>
  <script id="fshaderUniformMatrixRowMajor" type="x-shader/x-fragment">#version 300 es
precision mediump float;
in highp vec2 pos;
layout (location = 0) out vec4 my_FragColor;
uniform vec4 m[4];
layout(std140, row_major) uniform type_m2 {
  mat4 mat;
} m2;
void main()
{
  my_FragColor = vec4(m2.mat[int(floor(pos.x * 4.0))][int(floor(pos.y * 4.0))], 0.0, 0.0, 1.0);
}
</script>
  <script type="application/javascript">
    "use strict";
    description("Row-major matrix layouts should work.");

    GLSLConformanceTester.runRenderTests([
      {
        vShaderId: 'vshaderUniformMatrixRowMajor',
        vShaderSuccess: true,
        fShaderId: 'fshaderUniformMatrixRowMajor',
        fShaderSuccess: true,
        linkSuccess: true,
        passMsg: '',
        uniformBlocks: [{
          name: "type_m2", value: new Float32Array([
            0, 0.2, 0.4, 0.6,
            1, 0.1, 0.3, 0.5,
            0, 0, 0, 0,
            1, 1, 1, 1,
          ])
        }]
      }
    ], 2);
  </script>
</body>

</html>

On win10 Chrome 81.0.4044.129

I got the result: Shader with row_major qualifier

Shader with row_major qualifier

I cannot figure out why it looks like this.

When I remove the row_major qualifier, I got another result:

Shader without row_major qualifier ( Do not care about the html wording in the image below, this is column_major )

Shader without row_major qualifier

And this is expected result.


To make things clear: My question is that two result should be transposed from each other since they use the same matrix data. The shader tries to paint each float number in matrix which ranges from 0 to 1 to the red channel. However shader with row_major (the first result) shows that the element in matrix is either 0 or 1, but this is not the fact. And the second result exactly do what is expected.

WJsjtu commented 4 years ago

I've got an answer on stackoverflow ( link ). So can this be concluded that it is really unsafe to use row_major qualifier in WebGL2?

greggman commented 4 years ago

I did some tests and I see this breaks on 3 of the 4 machines I tested on

Here's the test

https://jsfiddle.net/greggman/zymndqec/

And here's the results

on a Macbook Pro (NVidia) I get these wrong results

enter image description here

on Windows 10 PC (NVidia) I get these correct results

enter image description here

on my Android Pixel 2 XL I get these wrong results

enter image description here

On a Macbook Air (Intel) I get these wrong results

enter image description here

Maybe this is not supposed to work. According to the spec

12.30 Dynamic Indexing

For GLSL ES 1.00, support of dynamic indexing of arrays, vectors and matrices was not mandated because it was not directly supported by some implementations. Software solutions (via program transforms) exist for a subset of cases but lead to poor performance.

Should support for dynamic indexing be mandated for GLSL ES 3.00?

RESOLUTION: Mandate support for dynamic indexing of arrays except for sampler arrays, fragment output arrays and uniform block arrays.

Should support for dynamic indexing of vectors and matrices be mandated in GLSL ES 3.00?

RESOLUTION: Yes.

My reading of the spec is it is supposed to work. I would read indexing uniform blocks arrays as not arrays inside the block but arrays of blocks themsevles.

For example if I do this

uniform Lights {
  vec3 u_lightWorldPos;
  vec4 u_lightColor;
} lights[2];

that's declaring 2 uniform blocks, "lights[0]" and "lights1" so apparently according to the spec I can not loop over those with a dynamic index (can with constant index)

But the code above is not doing that. It's indexing vectors and floats in a vector which seems to supposed to be supported?

kenrussell commented 4 years ago

There are known driver bugs with row_major matrices on macOS on both AMD and Intel GPUs that are intended to be worked around in https://bugs.chromium.org/p/angleproject/issues/detail?id=2273 . That work's on the to-do list. NVIDIA GPUs on macOS aren't close to passing WebGL 2.0 conformance, so please discount those results.

The Android failures weren't previously known.

We'll aim to get the conformance tests for this functionality passing by working around the driver bugs and advertise that row_major is working robustly across browsers, operating systems and GPUs.