Hello Guest

Uniform blocks

  • 4 Replies
  • 4342 Views
Uniform blocks
« 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 :
Code: [Select]
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 :
Code: [Select]
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 :

Code: [Select]
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 :

Code: [Select]
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  ::).
« Last Edit: August 04, 2018, 19:13:36 by xenoliss »

*

Offline KaiHH

  • ****
  • 334
Re: Uniform blocks
« Reply #1 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.

Re: Uniform blocks
« Reply #2 on: August 04, 2018, 19:08:22 »
Thanks for your quick answer  :) but :

because your uniform block has an alignment of vec4

Why is it  ?

*

Offline KaiHH

  • ****
  • 334

Re: Uniform blocks
« Reply #4 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 ?