Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Values for certain types of uniforms within UBOs are shown incorrectly #277

Open
mixtur opened this issue Aug 23, 2023 · 5 comments
Open

Comments

@mixtur
Copy link

mixtur commented Aug 23, 2023

I was using Spector.js Chrome extension to debug our migration to UBOs and stumbled upon this.

We have the following uniform block:

layout(std140) uniform DirectLightShadowCastersUBO {
    float frustumSplits[3];
    int directShadowCastersMask[1];
    mat4 directShadowCastersTransforms[3];
};

And spector shows the following for frustumSplits
image

The displayed value is 0.1683, 0, 0 which is wrong. The last two values shouldn't be zeroes.
I think Spector is ignoring arrayStride here, because when I put some numbers into the buffer one after another I can actually see them in Spector.

@JannikGM
Copy link
Contributor

JannikGM commented Aug 23, 2023

Yes, looks like it gets ignored (note how the offset is used without respecting arrayStride and matrixStride):

uniformState.offset = offsets[i];
uniformState.arrayStride = arrayStrides[i];
uniformState.matrixStride = matrixStrides[i];
uniformState.rowMajor = rowMajors[i];
if (uniformState.blockIndice > -1) {
const bindingPoint = uniformBlockState[blockIndices[i]].bindingPoint;
uniformState.value = this.drawCallUboInputState.getUboValue(bindingPoint,
uniformState.offset,
uniformState.size,
typeValues[i]);
}

Edit: This might be part of offsets[i] retrieved from GL; I'm not sure about the specifics here, so I might be wrong. Even with the bug, the second and third element wouldn't be read as zero I believe. Did you try it on another machine with a different GL implementation already?

@mixtur
Copy link
Author

mixtur commented Aug 23, 2023

Note layout(std140) in the shader code - it should make the layout implementation independent, but if you want, you can try it yourself https://cib3.webgears.app/3D-Engine/228e665dc1d4cd9fd12ab71a4dbcf5abd64e26e3/shadows.html (look for draw calls with PBR_MESH_SHADER in shader names) The link is only going to be alive for a few days maximum.

Though judging by the implementation of getUboValue it is expected that there are zeroes.

public getUboValue(bindingPoint: number, offset: number, size: number, type: number): any {
const uboType = DrawCallUboInputState.uboTypes[type];
if (!uboType) {
return undefined;
}
const destination = new uboType.arrayBufferView(size * uboType.lengthMultiplier);
const context2 = this.context as WebGL2RenderingContext;
const ownerbuffer = context2.getIndexedParameter(WebGlConstants.UNIFORM_BUFFER_BINDING.value, bindingPoint);
if (ownerbuffer) {
const startOffset = context2.getIndexedParameter(WebGlConstants.UNIFORM_BUFFER_START.value, bindingPoint);
const boundBuffer = context2.getParameter(WebGlConstants.UNIFORM_BUFFER_BINDING.value);
try {
context2.bindBuffer(WebGlConstants.UNIFORM_BUFFER.value, ownerbuffer);
context2.getBufferSubData(WebGlConstants.UNIFORM_BUFFER.value, startOffset + offset, destination);
}
catch (e) {
// Prevent back fromats to break the capture.
return undefined;
}
if (boundBuffer) {
context2.bindBuffer(WebGlConstants.UNIFORM_BUFFER.value, boundBuffer);
}
}
return Array.prototype.slice.call(destination);

In case of float x[3] the layout is the following:

[ 4 bytes x[0], 12 bytes to satisfy alignment,
  4 bytes x[1], 12 bytes to satisfy alignment,
  4 bytes x[2], 12 bytes padding,
  ]

The implementation simply does getBufferSubdata and then seems to do nothing with it. Assuming uboType.lengthMultiplier is 1 and size is 3. It should indeed read the first float and two zero-paddings immediately following it.

@JannikGM
Copy link
Contributor

I've tried to fix it, but it's still broken for matrices: https://github.com/JannikGM/Spector.js/tree/strides (and it still needs to be cleaned up). There's also a lack of optimizations still (like auto-reading objects with stride==0 / stride==elementSize)

@mixtur
Copy link
Author

mixtur commented Aug 23, 2023

According to the spec https://registry.khronos.org/OpenGL/extensions/ARB/ARB_uniform_buffer_object.txt column-major matrices are treated as arrays of columns regardless of the dimensions. And array elements are vec4-aligned. So mat4x2 is taking as much space as mat4.

Row-major matrices are the same except they should be treated as arrays of rows.

Although today I discovered that when on NVidia GPUs + Chrome row-major case does something else. As well as Android on Mali G68. So yeah. It seems that this stuff is still implementation-defined to some extent. Or maybe I am using the wrong spec :)

@sebavan
Copy link
Member

sebavan commented Aug 30, 2023

This is a really interesting one indeed :-)

@JannikGM, thanks a lot for your proposal here, this is going in the right direction and yes it was a complete oversight on my side.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants