Main Menu

Uniform blocks

Started by xenoliss, August 04, 2018, 18:52:16

Previous topic - Next topic

xenoliss

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  ::).

KaiHH

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.

xenoliss

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  ?


xenoliss

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 ?