LWJGL Forum

Programming => OpenGL => Topic started by: xenoliss on August 04, 2018, 18:52:16

Title: Uniform blocks
Post by: xenoliss on August 04, 2018, 18:52:16
Hello,

I'm trying to figure out how do uniform blocks work and I can't understand the results I get.

In my fragment shader code I have this uniform block :

layout (std140, binding = 0) uniform BlobSettings {
                        // Base alignment   // Aligned Offset (MUST BE multiple of base alignment, in std140)
    vec4 innerColor;    // 16               // 0 - 16
    vec4 outerColor;    // 16               // 16 - 32
    float radiusInner;  // 4                // 32 - 36
    float radiusOuter;  // 4                // 36 - 40
};


So when I ask in my application the size of this block I'm expecting to see 40 but actually I get 48 ... Where does it come from ? Here is my code to get the uniform block size :

public int getUniformBlockSize(int shaderProgramID, String uniformBlockName) {
int uniformBlockIndex = uniformBlockIndices.get(uniformBlockName).getBlockIndex();
int uboSize = GL31.glGetActiveUniformBlocki(shaderProgramID, uniformBlockIndex, GL31.GL_UNIFORM_BLOCK_DATA_SIZE);

return uboSize;
}



Furthermore in a lot of code (C++ or C) they're using malloc after retrieving the uniform block size to allocate the memory of their buffer, but we can't in Java... I paste my entire code here dealing with uniform buffer and if some benevolent spirits could have a look and give me some feedback (if I'm doing wrong or if I could do better) I would really appreciate :


public class ShaderUniformBlockComponent {

private Hashtable<String, UniformBufferObjectInfos>uniformBlockIndices;

public ShaderUniformBlockComponent() {
uniformBlockIndices = new Hashtable<String, UniformBufferObjectInfos>();
}

public void prepareUniformBuffer(String uniformBlockName, int sizeToAllocate) {

// Prepare a uniform buffer, allocating memory
int uboID = GL15.glGenBuffers();
GL15.glBindBuffer(GL31.GL_UNIFORM_BUFFER, uboID);
GL44.glBufferStorage(GL31.GL_UNIFORM_BUFFER, sizeToAllocate, GL44.GL_DYNAMIC_STORAGE_BIT);
GL15.glBindBuffer(GL31.GL_UNIFORM_BUFFER, 0);


UniformBufferObjectInfos uniformBufferObjectInfo = new UniformBufferObjectInfos();
uniformBufferObjectInfo.setUboID(uboID);
uniformBufferObjectInfo.setAllocatedSize(sizeToAllocate);

uniformBlockIndices.put(uniformBlockName, uniformBufferObjectInfo);

}

public void bindUniformBlockIndex(int shaderProgramID, String uniformBlockName, int bindingPoint) {
/*
* Retrieving the uniform block index, and binding it to a specific binding point (0 here)
* NOTE USED SINCE 4.2 IF IT'S SPECIFIED THE BINDING POINT IN SHADER with "layout(binding = n)"
*/

int uniformBlockIndex = GL31.glGetUniformBlockIndex(shaderProgramID, uniformBlockName);
GL31.glUniformBlockBinding(shaderProgramID, uniformBlockIndex, bindingPoint);

uniformBlockIndices.get(uniformBlockName).setBindingPoint(bindingPoint);
uniformBlockIndices.get(uniformBlockName).setBlockIndex(uniformBlockIndex);
}

public void updateUniformBlock(String uniformBlockName, float[] values, int offset) {

int uboID = uniformBlockIndices.get(uniformBlockName).getUboID();
int bindingPoint = uniformBlockIndices.get(uniformBlockName).getBindingPoint();
int allocatedSize = uniformBlockIndices.get(uniformBlockName).getAllocatedSize();

/*
* Finaly bind the uniform buffer object to the same binding point to acctualy link
* the uniform buffer to the uniform block (pointing each to the same binding point)
*/

GL30.glBindBufferBase(GL31.GL_UNIFORM_BUFFER, bindingPoint, uboID);


/*
* Fill the buffer object to update the uniform block
*/

FloatBuffer floatBuffer = BufferUtils.createFloatBuffer(allocatedSize - offset);
floatBuffer.put(values);
floatBuffer.flip();
GL15.glBindBuffer(GL31.GL_UNIFORM_BUFFER, uboID);
GL15.glBufferSubData(GL31.GL_UNIFORM_BUFFER, offset, floatBuffer);
GL15.glBindBuffer(GL31.GL_UNIFORM_BUFFER, 0);
}

// Not used ==> std140
public int getUniformBlockSize(int shaderProgramID, String uniformBlockName) {
int uniformBlockIndex = uniformBlockIndices.get(uniformBlockName).getBlockIndex();
int uboSize = GL31.glGetActiveUniformBlocki(shaderProgramID, uniformBlockIndex, GL31.GL_UNIFORM_BLOCK_DATA_SIZE);

return uboSize;
}

private class UniformBufferObjectInfos {

private static final int NONE = -1;

private int uboID;
private int blockIndex;
private int allocatedSize;
private int bindingPoint;

private UniformBufferObjectInfos() {
this.uboID = NONE;
this.allocatedSize = NONE;
this.bindingPoint = NONE;
this.blockIndex = NONE;
}

public int getUboID() {
return uboID;
}

public void setUboID(int uboID) {
this.uboID = uboID;
}
public int getBlockIndex() {
return blockIndex;
}

public void setBlockIndex(int blockIndex) {
this.blockIndex = blockIndex;
}

public int getAllocatedSize() {
return allocatedSize;
}

public void setAllocatedSize(int allocatedSize) {
this.allocatedSize = allocatedSize;
}

public int getBindingPoint() {
return bindingPoint;
}

public void setBindingPoint(int bindingPoint) {
this.bindingPoint = bindingPoint;
}
}
}


and in my application :


shader = new ShaderProgram("src/shaders/vertexShader.glsl", "src/shaders/fragmentShader.glsl");

float[] uniformValues = {
1, 0, 0, 1,
0, 0, 0, 1,
0.25f,
0.45f
};

shader.prepareUniformBuffer("BlobSettings", 40);
shader.bindUniformBlockIndex("BlobSettings", 0);
shader.updateUniformBlock("BlobSettings", uniformValues, 0);


Thanks for your help !  :D and sorry for my bad english  :-[
And if someone could redirect me (or explain here) to tutorials explaining how does memory in openGL work (like when to use glMap ? vs vpBufferData ? vs glBufferStorage etc... ). I'm 1000% a beginner so it would be great if it could be explain so that I won't be drowned in highly technical terms  ::).
Title: Re: Uniform blocks
Post by: KaiHH on August 04, 2018, 18:56:44
You get 48 bytes because your uniform block has an alignment of vec4 and therefore gets an additional padding of 8 bytes at the end. This means your uniform block layout actually consists of three vec4's, of which the last one contains the radiusInner in the X and radiusOuter in the Y component.
Title: Re: Uniform blocks
Post by: xenoliss on August 04, 2018, 19:08:22
Thanks for your quick answer  :) but :

Quote from: KaiHH on August 04, 2018, 18:56:44
because your uniform block has an alignment of vec4

Why is it  ?
Title: Re: Uniform blocks
Post by: KaiHH on August 04, 2018, 19:09:18
Because: https://www.khronos.org/registry/OpenGL/specs/gl/glspec45.core.pdf#page=159
Title: Re: Uniform blocks
Post by: xenoliss on August 04, 2018, 19:31:52
Ok, afte reading it severals times I can't understand it 100% but it seems to be because  :

"The members of a toplevel uniform block are laid out in buffer storage by treating the uniform block as a structure with a base offset of zero."
and
"If the member is a two- or four-component vector with components consuming N basic machine units, the base alignment is 2N or 4N, respectively."

Can you confirm that please ?