From Tim Moore, "Here is initial support for uniform buffer objects. The binding between a buffer object and an indexed target is implemented as a new StateAttribute, UniformBufferBinding. I've included an example program based on the code in the ARB_uniform_buffer_object specification.

A few things remain to do:
* The binding between a uniform block in a shader program and a buffer indexed target number is fixed, like a vertex attribute binding. This is too restrictive because that binding can be changed without relinking the program. This mapping should be done by name in the same way that uniform values are handled i.e., like a pseudo state attribute;

* There's no direct way yet to query for the offset of uniforms in uniform block, so only the std140 layout is really usable. A helper class that implemented the std140 rules would be quite helpful for setting up uniform blocks without having to link a program first;

* There's no direct support for querying parameters such as the maximum block length, minimum offset alignment, etc. Having that information available outside of the draw thread would make certain instancing techniques easier to implement."
This commit is contained in:
Robert Osfield
2010-11-29 17:43:27 +00:00
parent 0739c15e0a
commit e5a9eaa711
13 changed files with 789 additions and 3 deletions

View File

@@ -0,0 +1,98 @@
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
* Copyright (C) 2010 Tim Moore
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* OpenSceneGraph Public License for more details.
*/
#include <osg/BufferIndexBinding>
#include <osg/State>
namespace osg {
BufferIndexBinding::BufferIndexBinding(GLenum target, GLuint index)
: _target(target), _index(index), _offset(0), _size(0)
{
}
BufferIndexBinding::BufferIndexBinding(GLenum target, GLuint index, BufferObject* bo,
GLintptr offset, GLsizeiptr size)
: _target(target), _index(index), _bufferObject(bo), _offset(offset), _size(size)
{
}
BufferIndexBinding::BufferIndexBinding(const BufferIndexBinding& rhs, const CopyOp& copyop)
: StateAttribute(rhs, copyop),
_target(rhs._target), _index(rhs._index),
_bufferObject(static_cast<BufferObject*>(copyop(rhs._bufferObject.get()))),
_offset(rhs._offset),
_size(rhs._size)
{
}
BufferIndexBinding::~BufferIndexBinding()
{
}
void BufferIndexBinding::apply(State& state) const
{
if (_bufferObject.valid())
{
GLBufferObject* glObject
= _bufferObject->getOrCreateGLBufferObject(state.getContextID());
if (!glObject->_extensions->isUniformBufferObjectSupported())
return;
if (glObject->isDirty()) glObject->compileBuffer();
glObject->_extensions->glBindBufferRange(_target, _index,
glObject->getGLObjectID(), _offset, _size);
}
}
UniformBufferBinding::UniformBufferBinding()
: BufferIndexBinding(GL_UNIFORM_BUFFER, 0)
{
}
UniformBufferBinding::UniformBufferBinding(GLuint index)
: BufferIndexBinding(GL_UNIFORM_BUFFER, index)
{
}
UniformBufferBinding::UniformBufferBinding(GLuint index, BufferObject* bo, GLintptr offset,
GLsizeiptr size)
: BufferIndexBinding(GL_UNIFORM_BUFFER, index, bo, offset, size)
{
}
UniformBufferBinding::UniformBufferBinding(const UniformBufferBinding& rhs,
const CopyOp& copyop)
: BufferIndexBinding(rhs, copyop)
{
}
TransformFeedbackBufferBinding::TransformFeedbackBufferBinding(GLuint index)
: BufferIndexBinding(GL_TRANSFORM_FEEDBACK_BUFFER, index)
{
}
TransformFeedbackBufferBinding::TransformFeedbackBufferBinding(GLuint index, BufferObject* bo, GLintptr offset, GLsizeiptr size)
: BufferIndexBinding(GL_TRANSFORM_FEEDBACK_BUFFER, index, bo, offset, size)
{
}
TransformFeedbackBufferBinding::TransformFeedbackBufferBinding(const TransformFeedbackBufferBinding& rhs, const CopyOp& copyop)
: BufferIndexBinding(rhs, copyop)
{
}
}

View File

@@ -17,6 +17,7 @@
#include <osg/BufferObject>
#include <osg/Notify>
#include <osg/GLExtensions>
#include <osg/GL2Extensions>
#include <osg/Timer>
#include <osg/Image>
#include <osg/State>
@@ -275,6 +276,9 @@ GLBufferObject::Extensions::Extensions(const Extensions& rhs):
_glUnmapBuffer = rhs._glUnmapBuffer;
_glGetBufferParameteriv = rhs._glGetBufferParameteriv;
_glGetBufferPointerv = rhs._glGetBufferPointerv;
_glBindBufferRange = rhs._glBindBufferRange;
_glBindBufferBase = rhs._glBindBufferBase;
}
@@ -291,6 +295,8 @@ void GLBufferObject::Extensions::lowestCommonDenominator(const Extensions& rhs)
if (!rhs._glUnmapBuffer) _glUnmapBuffer = rhs._glUnmapBuffer;
if (!rhs._glGetBufferParameteriv) _glGetBufferParameteriv = rhs._glGetBufferParameteriv;
if (!rhs._glGetBufferParameteriv) _glGetBufferPointerv = rhs._glGetBufferPointerv;
if (!rhs._glBindBufferRange) _glBindBufferRange = rhs._glBindBufferRange;
if (!rhs._glBindBufferBase) _glBindBufferBase = rhs._glBindBufferBase;
}
void GLBufferObject::Extensions::setupGLExtensions(unsigned int contextID)
@@ -307,6 +313,10 @@ void GLBufferObject::Extensions::setupGLExtensions(unsigned int contextID)
setGLExtensionFuncPtr(_glGetBufferParameteriv, "glGetBufferParameteriv","glGetBufferParameterivARB");
setGLExtensionFuncPtr(_glGetBufferPointerv, "glGetBufferPointerv","glGetBufferPointervARB");
_isPBOSupported = OSG_GL3_FEATURES || osg::isGLExtensionSupported(contextID,"GL_ARB_pixel_buffer_object");
setGLExtensionFuncPtr(_glBindBufferRange, "glBindBufferRange");
setGLExtensionFuncPtr(_glBindBufferBase, "glBindBufferBase");
_isUniformBufferObjectSupported
= osg::isGLExtensionSupported(contextID, "GL_ARB_uniform_buffer_object");
}
void GLBufferObject::Extensions::glGenBuffers(GLsizei n, GLuint *buffers) const
@@ -387,6 +397,17 @@ void GLBufferObject::Extensions::glGetBufferPointerv (GLenum target, GLenum pnam
else OSG_WARN<<"Error: glGetBufferPointerv not supported by OpenGL driver"<<std::endl;
}
void GLBufferObject::Extensions::glBindBufferRange (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size)
{
if (_glBindBufferRange) _glBindBufferRange(target, index, buffer, offset, size);
else OSG_WARN<<"Error: glBindBufferRange not supported by OpenGL driver\n";
}
void GLBufferObject::Extensions::glBindBufferBase (GLenum target, GLuint index, GLuint buffer)
{
if (_glBindBufferBase) _glBindBufferBase(target, index, buffer);
else OSG_WARN<<"Error: glBindBufferBase not supported by OpenGL driver\n";
}
//////////////////////////////////////////////////////////////////////////////////////////////////////
//
// GLBufferObjectSet
@@ -1539,3 +1560,17 @@ void PixelDataBufferObject::resizeGLObjectBuffers(unsigned int maxSize)
_mode.resize(maxSize);
}
UniformBufferObject::UniformBufferObject()
{
setTarget(GL_UNIFORM_BUFFER);
setUsage(GL_STREAM_DRAW_ARB);
}
UniformBufferObject::UniformBufferObject(const UniformBufferObject& ubo, const CopyOp& copyop)
: BufferObject(ubo, copyop)
{
}
UniformBufferObject::~UniformBufferObject()
{
}

View File

@@ -36,6 +36,7 @@ SET(LIB_PUBLIC_HEADERS
${HEADER_PATH}/BoundingSphere
${HEADER_PATH}/BoundsChecking
${HEADER_PATH}/buffered_value
${HEADER_PATH}/BufferIndexBinding
${HEADER_PATH}/BufferObject
${HEADER_PATH}/Camera
${HEADER_PATH}/CameraNode
@@ -209,6 +210,7 @@ ADD_LIBRARY(${LIB_NAME}
BlendColor.cpp
BlendEquation.cpp
BlendFunc.cpp
BufferIndexBinding.cpp
BufferObject.cpp
Camera.cpp
CameraView.cpp

View File

@@ -47,6 +47,7 @@ GL2Extensions::GL2Extensions(const GL2Extensions& rhs) : osg::Referenced()
_isLanguage100Supported = rhs._isLanguage100Supported;
_isGeometryShader4Supported = rhs._isGeometryShader4Supported;
_isGpuShader4Supported = rhs._isGpuShader4Supported;
_isUniformBufferObjectSupported = rhs._isUniformBufferObjectSupported;
_glBlendEquationSeparate = rhs._glBlendEquationSeparate;
_glDrawBuffers = rhs._glDrawBuffers;
@@ -173,6 +174,15 @@ GL2Extensions::GL2Extensions(const GL2Extensions& rhs) : osg::Referenced()
_glUniform2uiv = rhs._glUniform2uiv;
_glUniform3uiv = rhs._glUniform3uiv;
_glUniform4uiv = rhs._glUniform4uiv;
// ARB_uniform_buffer_object
_glGetUniformIndices = rhs._glGetUniformIndices;
_glGetActiveUniformsiv = rhs._glGetActiveUniformsiv;
_glGetActiveUniformName = rhs._glGetActiveUniformName;
_glGetUniformBlockIndex = rhs._glGetUniformBlockIndex;
_glGetActiveUniformBlockiv = rhs._glGetActiveUniformBlockiv;
_glGetActiveUniformBlockName = rhs._glGetActiveUniformBlockName;
_glUniformBlockBinding = rhs._glUniformBlockBinding;
}
@@ -318,6 +328,16 @@ void GL2Extensions::lowestCommonDenominator(const GL2Extensions& rhs)
if (!rhs._glUniform2uiv) _glUniform2uiv = 0;
if (!rhs._glUniform3uiv) _glUniform3uiv = 0;
if (!rhs._glUniform4uiv) _glUniform4uiv = 0;
// ARB_uniform_buffer_object
if (!rhs._glGetUniformIndices) _glGetUniformIndices = 0;
if (!rhs._glGetActiveUniformsiv) _glGetActiveUniformsiv = 0;
if (!rhs._glGetActiveUniformName) _glGetActiveUniformName = 0;
if (!rhs._glGetUniformBlockIndex) _glGetUniformBlockIndex = 0;
if (!rhs._glGetActiveUniformBlockiv) _glGetActiveUniformBlockiv = 0;
if (!rhs._glGetActiveUniformBlockName) _glGetActiveUniformBlockName = 0;
if (!rhs._glUniformBlockBinding) _glUniformBlockBinding = 0;
}
@@ -342,6 +362,7 @@ void GL2Extensions::setupGL2Extensions(unsigned int contextID)
_isGeometryShader4Supported = osg::isGLExtensionSupported(contextID,"GL_EXT_geometry_shader4");
_isGpuShader4Supported = osg::isGLExtensionSupported(contextID,"GL_EXT_gpu_shader4");
_areTessellationShadersSupported = osg::isGLExtensionSupported(contextID, "GL_ARB_tessellation_shader");
_isUniformBufferObjectSupported = osg::isGLExtensionSupported(contextID,"ARB_uniform_buffer_object");
if( isGlslSupported() )
{
@@ -491,6 +512,15 @@ void GL2Extensions::setupGL2Extensions(unsigned int contextID)
setGLExtensionFuncPtr(_glUniform2uiv, "glUniform2uiv", "glUniform2uivEXT" );
setGLExtensionFuncPtr(_glUniform3uiv, "glUniform3uiv", "glUniform3uivEXT" );
setGLExtensionFuncPtr(_glUniform4uiv, "glUniform4uiv", "glUniform4uivEXT" );
// ARB_uniform_buffer_object
setGLExtensionFuncPtr(_glGetUniformIndices, "glGetUniformIndices");
setGLExtensionFuncPtr(_glGetActiveUniformsiv, "glGetActiveUniformsiv");
setGLExtensionFuncPtr(_glGetActiveUniformName, "glGetActiveUniformName");
setGLExtensionFuncPtr(_glGetUniformBlockIndex, "glGetUniformBlockIndex");
setGLExtensionFuncPtr(_glGetActiveUniformBlockiv, "glGetActiveUniformBlockiv");
setGLExtensionFuncPtr(_glGetActiveUniformBlockName, "glGetActiveUniformBlockName");
setGLExtensionFuncPtr(_glUniformBlockBinding, "glUniformBlockBinding");
}
@@ -2152,6 +2182,110 @@ void GL2Extensions::glUniform4uiv( GLint location, GLsizei count, const GLuint *
}
}
// ARB_uniform_buffer_object
void GL2Extensions::glGetUniformIndices(GLuint program, GLsizei uniformCount,
const GLchar* *uniformNames,
GLuint *uniformIndices) const
{
if (_glGetUniformIndices)
{
_glGetUniformIndices(program, uniformCount, uniformNames,
uniformIndices);
}
else
{
NotSupported("glGetUniformIndices");
}
}
void GL2Extensions::glGetActiveUniformsiv(GLuint program, GLsizei uniformCount,
const GLuint *uniformIndices,
GLenum pname, GLint *params) const
{
if (_glGetActiveUniformsiv)
{
_glGetActiveUniformsiv(program, uniformCount, uniformIndices, pname,
params);
}
else
{
NotSupported("glGetActiveUniformsiv");
}
}
void GL2Extensions::glGetActiveUniformName(GLuint program, GLuint uniformIndex,
GLsizei bufSize, GLsizei *length,
GLchar *uniformName) const
{
if (_glGetActiveUniformName)
{
_glGetActiveUniformName(program, uniformIndex, bufSize, length,
uniformName);
}
else
{
NotSupported("glGetActiveUniformName");
}
}
GLuint GL2Extensions::glGetUniformBlockIndex(GLuint program,
const GLchar *uniformBlockName) const
{
if (_glGetUniformBlockIndex)
{
return _glGetUniformBlockIndex(program, uniformBlockName);
}
else
{
NotSupported("glGetUniformBlockIndex");
return GL_INVALID_INDEX;
}
}
void GL2Extensions::glGetActiveUniformBlockiv(GLuint program,
GLuint uniformBlockIndex,
GLenum pname, GLint *params) const
{
if (_glGetActiveUniformBlockiv)
{
_glGetActiveUniformBlockiv(program, uniformBlockIndex, pname, params);
}
else
{
NotSupported("glGetActiveUniformBlockiv");
}
}
void GL2Extensions::glGetActiveUniformBlockName(GLuint program,
GLuint uniformBlockIndex,
GLsizei bufSize,
GLsizei *length,
GLchar *uniformBlockName) const
{
if (_glGetActiveUniformBlockName)
{
_glGetActiveUniformBlockName(program, uniformBlockIndex, bufSize,
length, uniformBlockName);
}
else
{
NotSupported("glGetActiveUniformBlockName");
}
}
void GL2Extensions::glUniformBlockBinding(GLuint program,
GLuint uniformBlockIndex,
GLuint uniformBlockBinding) const
{
if (_glUniformBlockBinding)
{
_glUniformBlockBinding(program, uniformBlockIndex, uniformBlockBinding);
}
else
{
NotSupported("glUniformBlockBinding");
}
}
///////////////////////////////////////////////////////////////////////////
// C++-friendly convenience methods

View File

@@ -386,6 +386,21 @@ void Program::removeBindFragDataLocation( const std::string& name )
dirtyProgram();
}
void Program::addBindUniformBlock(const std::string& name, GLuint index)
{
_uniformBlockBindingList[name] = index;
dirtyProgram(); // XXX
}
void Program::removeBindUniformBlock(const std::string& name)
{
_uniformBlockBindingList.erase(name);
dirtyProgram(); // XXX
}
void Program::apply( osg::State& state ) const
{
const unsigned int contextID = state.getContextID();
@@ -589,6 +604,58 @@ void Program::PerContextProgram::linkProgram(osg::State& state)
}
}
if (_extensions->isUniformBufferObjectSupported())
{
GLuint activeUniformBlocks = 0;
GLsizei maxBlockNameLen = 0;
_extensions->glGetProgramiv(_glProgramHandle, GL_ACTIVE_UNIFORM_BLOCKS,
reinterpret_cast<GLint*>(&activeUniformBlocks));
_extensions->glGetProgramiv(_glProgramHandle,
GL_ACTIVE_UNIFORM_MAX_LENGTH,
&maxBlockNameLen);
if (maxBlockNameLen > 0)
{
std::vector<GLchar> blockName(maxBlockNameLen);
for (GLuint i = 0; i < activeUniformBlocks; ++i)
{
GLsizei len = 0;
GLint blockSize = 0;
_extensions->glGetActiveUniformBlockName(_glProgramHandle, i,
maxBlockNameLen, &len,
&blockName[0]);
_extensions->glGetActiveUniformBlockiv(_glProgramHandle, i,
GL_UNIFORM_BLOCK_DATA_SIZE,
&blockSize);
_uniformBlockMap
.insert(UniformBlockMap::value_type(&blockName[0],
UniformBlockInfo(i, blockSize)));
}
}
// Bind any uniform blocks
const UniformBlockBindingList& bindingList = _program->getUniformBlockBindingList();
for (UniformBlockMap::iterator itr = _uniformBlockMap.begin(),
end = _uniformBlockMap.end();
itr != end;
++itr)
{
const std::string& blockName = itr->first;
UniformBlockBindingList::const_iterator bitr = bindingList.find(blockName);
if (bitr != bindingList.end())
{
_extensions->glUniformBlockBinding(_glProgramHandle, itr->second._index,
bitr->second);
OSG_INFO << "uniform block " << blockName << ": " << itr->second._index
<< " binding: " << bitr->second << "\n";
}
else
{
OSG_WARN << "uniform block " << blockName << " has no binding.\n";
}
}
}
// build _uniformInfoMap
GLint numUniforms = 0;
GLsizei maxLen = 0;