Geometry is being drawn properly now but only as long as I don’t use uniforms contained in uniform buffers.
This is how I set up uniform buffers:
shared_ptr<UniformBuffer> OGL3GraphicsEngine::createUniformBuffer( const string &blockName, unsigned long blockSize, const void *data )
{
// setup a new uniform buffer
shared_ptr<UniformBuffer> uniformBuffer = shared_ptr<UniformBuffer>( new UniformBuffer() );
uniformBuffer->blockSize = blockSize;
uniformBuffer->blockName = blockName;
// register uniform buffer with OpenGL
glGenBuffers( 1, &uniformBuffer->id );
// define a new slot for this uniform block
uniformBuffer->slot = m_uniformBuffers.size();
// associate uniform block to its binding point (=slot)
glBindBufferBase( GL_UNIFORM_BUFFER, uniformBuffer->slot, uniformBuffer->id );
// upload data (if provided)
updateUniformBuffer( uniformBuffer, data, "" );
// register uniform block with all programs
for( uint i = 0; i < m_programs.size(); i++ )
{
registerUniformBlock( m_programs.at(i), uniformBuffer );
}
m_uniformBuffers.push_back( uniformBuffer );
return uniformBuffer;
}
bool OGL3GraphicsEngine::updateUniformBuffer( shared_ptr<UniformBuffer> uniformBuffer, const void *data, const string &element )
{
if( !uniformBuffer )
return false;
if( m_activeUniformBuffer != uniformBuffer )
{
glBindBuffer( GL_UNIFORM_BUFFER, uniformBuffer->id );
m_activeUniformBuffer = uniformBuffer;
}
if( element.length() )
{
const int &size = uniformBuffer->blockElements[element].first;
const int &offset = uniformBuffer->blockElements[element].second;
glBufferSubData( GL_UNIFORM_BUFFER, offset, size, data );
}
else
{
glBufferData( GL_UNIFORM_BUFFER, uniformBuffer->blockSize, data, GL_DYNAMIC_DRAW );
}
return true;
}
bool OGL3GraphicsEngine::registerUniformBlock( shared_ptr<Program> program, shared_ptr<UniformBuffer> uniformBuffer )
{
static unordered_map<int, int> datatypeSizes = initializeDatatypeSizes();
// check whether uniform block is used in program; get its index if it is
uint index = glGetUniformBlockIndex( program->id, uniformBuffer->blockName.c_str() );
if( index == GL_INVALID_INDEX )
return false;
// assign uniform block to associated slot in program
glUniformBlockBinding( program->id, index, uniformBuffer->slot );
// get number of uniforms
int activeUniformsInBlock;
glGetActiveUniformBlockiv( program->id, index, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &activeUniformsInBlock );
// retrieve the associated indices
int *indices = new int[activeUniformsInBlock];
glGetActiveUniformBlockiv( program->id, index, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, indices );
int type, offset;
char uniformName[256];
for( uint i = 0; i < activeUniformsInBlock; i++ )
{
const uint &index = (uint)indices[i];
// get uniform's name
glGetActiveUniformName( program->id, index, 256, 0, uniformName );
// get uniform's data type and its offset from the block's beginning
glGetActiveUniformsiv( program->id, 1, &index, GL_UNIFORM_TYPE, &type );
glGetActiveUniformsiv( program->id, 1, &index, GL_UNIFORM_OFFSET, &offset );
// retrieve data type size of uniform
const int &size = datatypeSizes[type];
// store uniform's size and offset inside the program (for packed uniform buffers)
program->uniformBlocks[uniformBuffer->blockName].elements[uniformName].first = size;
program->uniformBlocks[uniformBuffer->blockName].elements[uniformName].second = offset;
// store the same information in the uniform buffer
// itself, possibly overwriting previous information!
uniformBuffer->blockElements[uniformName].first = size;
uniformBuffer->blockElements[uniformName].second = offset;
}
return true;
}
And this is how I use it in my sample program:
struct ProjectionBlock
{
mat4 perspective;
mat4 orthographic;
};
ProjectionBlock projection;
projection.perspective = glm::perspective( 60.0f, 800.0f/600.0f, 1.0f, 100.0f );
projection.orthographic = glm::ortho( 0.0f, 800.0f, 0.0f, 600.0f, -1.0f, 1.0f );
m_projectionBuffer = Engine::getGraphicsEngine()->createUniformBuffer( "Projection", sizeof(ProjectionBlock), &projection );
On my NVIDIA card, this successfully creates a uniform buffer and uploads the two matrices. On my ATI card, the uniform buffer is created as well but no data is being uploaded; gDebugger lists the uniform buffer and the two matrices it contains but lists their values as “N/A”.
Am I creating/updating uniform blocks properly?