PDA

View Full Version : Uniform Buffer Object and some issues with it



sajis997
10-16-2014, 10:51 AM
Hello forum,

I have implemented a uniform buffer object with simpler settings and now i am confused once i started to try with something complex. And i need some hint to get around this issue. Lets start with simpler setting that i have implemented with the shared layout.



uniform blobSettings
{
vec4 innerColor;
vec4 outerColor;
float innerRadius;
float outerRadius;
} blob;


The uniform block is defined inside the fragment shader. Then in the application side , i get the uniform block index with the following snippet:



//get the index of the named uniform block
GLuint blockIndex = glGetUniformBlockIndex(programHandle,"blobSettings");


Now I get the size of the uniform block buffer with the following snippet:



//get the space for the buffer
GLint blockSize;
glGetActiveUniformBlockiv(programHandle,blockIndex ,GL_UNIFORM_BLOCK_DATA_SIZE,&blockSize);


Then allocate the buffer on the application side with the buffer size we have extracted :



//allocate memory with the buffer size
GLubyte *blockBuffer = NULL;
blockBuffer = (GLubyte*) malloc(blockSize);


I need to query the offset of the each member of the uniform block as follows:



//query the offsets of each block variable
const GLchar *names[] = {"blobSettings.innerColor",
"blobSettings.outerColor",
"blobSettings.innerRadius",
"blobSettings.outerRadius"};




We are using the shared layout, so we can determine the offsets
that OpenGL assigned for the block members.
Each member of the uniform block has an index that is used to
refer to it to find its size and location within the block



GLuint indices[4];
//retrieve the indices of the uniform block members
glGetUniformIndices(programHandle,4,names,indices) ;


now i have the indices, so next we can use
the indices to find the locations of the block
members within the buffer



GLint offset[4];

//the following function gives a lot of information
//about specific uniform block members
glGetActiveUniformsiv(programHandle,4,indices,GL_U NIFORM_OFFSET,offset);



Now I copied the data from the application to the uniform buffer object.



//store the data within the buffer at appropriate offsets
GLfloat outerColor[] = {0.0f,0.0f,0.0f,0.0f};
GLfloat innerColor[] = {1.0f,0.0f,0.75f,1.0f};
GLfloat innerRadius = 0.25f,outerRadius = 0.45f;

//place the data into the buffer at appropriate offsets
memcpy(blockBuffer + offset[0],innerColor,4 * sizeof(GLfloat));
memcpy(blockBuffer + offset[1],outerColor,4 * sizeof(GLfloat));
memcpy(blockBuffer + offset[2],&innerRadius,sizeof(GLfloat));
memcpy(blockBuffer + offset[3],&outerRadius,sizeof(GLfloat));

//create the buffer object and copy the data
GLuint uboHandle;
glGenBuffers(1,&uboHandle);
glBindBuffer(GL_UNIFORM_BUFFER,uboHandle);
glBufferData(GL_UNIFORM_BUFFER,blockSize,blockBuff er,GL_DYNAMIC_DRAW);

glUniformBlockBinding(programHandle,blockIndex,0);

//bind the buffer object to the uniform block
//so that the data in the buffers appear in the uniform blocks
glBindBufferBase(GL_UNIFORM_BUFFER,0,uboHandle);


The above uniform block was pretty simpler. Now i have some thing different data layout in the shared manner and i am having trouble to do the data transfer. The uniform block is as follows:



struct droplet_t
{
float x_offset;
float y_offset;
float orientation;
float unused;
};

uniform Droplets
{
droplet_t droplet[256];
} droplets;


Then I followed the similar procedure to get the index,offset, stirde for the block member:



//pull out necessary information to create the uniform buffer object
//get the program handle
GLuint programHandle = textureRainShader->GetProgramHandle();

//get the index of the named uniform block
GLuint blockIndex = glGetUniformBlockIndex(programHandle,"Droplets");

//get the space for the buffer
GLint blockSize;
glGetActiveUniformBlockiv(programHandle,blockIndex ,GL_UNIFORM_BLOCK_DATA_SIZE,&blockSize);

//allocate memory with the buffer size
GLubyte *blockBuffer = NULL;
blockBuffer = (GLubyte*) malloc(blockSize);

//query the offsets of each block variable
const GLchar *names[] = {"Droplets.droplet"};

/*
* We are using the shared layout, so we can determine the offsets
* that OpenGL assigned for the block members.
* Each member of the uniform block has an index that is used to
* refer to it to find its size and location within the block
*/

GLuint index;
//retrieve the index of the uniform block member
glGetUniformIndices(programHandle,1,names,&index);

//now i have the index, so next we can use
//the index to find the location of the uniform
//block member within the buffer
GLint offset,arrayStride;

//the following function gives a lot of information
//about specific uniform block members
glGetActiveUniformsiv(programHandle,1,&index,GL_UNIFORM_OFFSET,&offset);
glGetActiveUniformsiv(programHandle,1,&index,GL_UNIFORM_ARRAY_STRIDE,&arrayStride);


Now i am in dilemma on how to copy the data from the application buffer to the uniform buffer object . I initialized the data in the application side as follows:



float *dropletXOffset = NULL;
float *dropletRotSpeed = NULL;
float *dropletFallSpeed = NULL;
...............................
...............................

dropletXOffset = new float[256];
dropletRotSpeed = new float[256];
dropletFallSpeed = new float[256];

.................................
.................................

//initialize with the random data to populate
//the buffer with it
for(unsigned int i = 0; i < 256; i++)
{
dropletXOffset[i] = random_float() * 2.0 - 1.0f;
dropletRotSpeed[i] = (random_float() + 0.5f) * ((i & 1) ? -3.0f : 3.0f);
dropletFallSpeed[i] = random_float() + 0.2f;
}


Now how to transfer the data to the blockBuffer ? Any hint folks ?

I guessed the following , but not sure about it.



for(unsigned int i = 0; i < 256;i++)
{
*((float*) (blockBuffer + offset[0])) = dropletXOffset[i];
*((float*) (blockBuffer + offset[1])) = 2.0f - fmodf((t + float(i)) * dropletFallSpeed[i], 4.31f);
*((float*) (blockBuffer + offset[2])) = t * dropletRotSpeed[i]; // t is the current time here
*((float*) (blockBuffer + offset[3])) = 0.0;

offset += arrayStride;
}


Please check the last code block and make some suggestion for me. The type we are dealing with is basically droplet_t type. Is casting to float to one of its members are valid ?


Thanks
Sajjad

mhagain
10-16-2014, 04:18 PM
In cases like this you're really better off just using std140. I know that doesn't answer your question, but IMO unless you have a really good reason to not use std140 (and experimenting with and learning about other layouts might be such a reason) then you should be using it.