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

@ -115,6 +115,7 @@ IF(DYNAMIC_OPENSCENEGRAPH)
ADD_SUBDIRECTORY(osgtexturerectangle)
ADD_SUBDIRECTORY(osgtexturecompression)
ADD_SUBDIRECTORY(osgthirdpersonview)
ADD_SUBDIRECTORY(osguniformbuffer)
ADD_SUBDIRECTORY(osguserstats)
ADD_SUBDIRECTORY(osgvertexprogram)
ADD_SUBDIRECTORY(osgvertexattributes)

View File

@ -0,0 +1,4 @@
SET(TARGET_SRC osguniformbuffer.cpp )
#### end var setup ###
SETUP_EXAMPLE(osguniformbuffer)

View File

@ -0,0 +1,206 @@
#include <iostream>
#include <osg/Array>
#include <osg/BoundingSphere>
#include <osg/BufferIndexBinding>
#include <osg/BufferObject>
#include <osg/Group>
#include <osg/Math>
#include <osg/MatrixTransform>
#include <osg/Program>
#include <osg/Shader>
#include <osgDB/ReadFile>
#include <osgDB/WriteFile>
#include <osgUtil/Optimizer>
#include <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers>
using namespace std;
using namespace osg;
// This example is based on the sample code in the
// ARB_uniform_buffer_object extension specification.
GLfloat colors1[] = {
// block
0.45,0.45,1,1,
0.45,0.45,1,1,
0.75,0.75,0.75,1,
0.0,0.0,1.0,1,
0.0,1.0,0.0,1
};
GLfloat colors2[] = {
// block
0.45,0.45,1,1,
0.45,0.45,1,1,
0.75,0.75,0.75,1,
1.0,0.0,0.0,1,
0.0,1.0,0.0,1,
};
char vertexShaderSource[] =
"// Vertex shader for Gooch shading\n"
"// Author: Randi Rost\n"
"// Copyright (c) 2002-2006 3Dlabs Inc. Ltd.\n"
"// See 3Dlabs-License.txt for license information\n"
"vec3 LightPosition = vec3(0.0, 10.0, 4.0); \n"
"varying float NdotL;\n"
"varying vec3 ReflectVec;\n"
"varying vec3 ViewVec;\n"
"void main(void)\n"
"{\n"
"vec3 ecPos = vec3 (gl_ModelViewMatrix * gl_Vertex);\n"
"vec3 tnorm = normalize(gl_NormalMatrix * gl_Normal);\n"
"vec3 lightVec = normalize(LightPosition - ecPos);\n"
"ReflectVec = normalize(reflect(-lightVec, tnorm));\n"
"ViewVec = normalize(-ecPos);\n"
"NdotL = (dot(lightVec, tnorm) + 1.0) * 0.5;\n"
"gl_Position = ftransform();\n"
"}\n";
char fragmentShaderSource[] =
"// Fragment shader for Gooch shading, adapted for ARB_uniform_buffer_object\n"
"#extension GL_ARB_uniform_buffer_object : enable\n"
"layout(std140) uniform colors0\n"
"{\n"
"float DiffuseCool;\n"
"float DiffuseWarm;\n"
"vec3 SurfaceColor;\n"
"vec3 WarmColor;\n"
"vec3 CoolColor;\n"
"};\n"
"varying float NdotL;\n"
"varying vec3 ReflectVec;\n"
"varying vec3 ViewVec;\n"
"void main (void)\n"
"{\n"
"vec3 kcool = min(CoolColor + DiffuseCool * SurfaceColor, 1.0);\n"
"vec3 kwarm = min(WarmColor + DiffuseWarm * SurfaceColor, 1.0); \n"
"vec3 kfinal = mix(kcool, kwarm, NdotL);\n"
"vec3 nreflect = normalize(ReflectVec);\n"
"vec3 nview = normalize(ViewVec);\n"
"float spec = max(dot(nreflect, nview), 0.0);\n"
"spec = pow(spec, 32.0);\n"
"gl_FragColor = vec4 (min(kfinal + spec, 1.0), 1.0);\n"
"}\n";
// Callback for animating the WarmColor
class UniformCallback : public StateAttributeCallback
{
public:
void operator() (StateAttribute* attr, NodeVisitor* nv)
{
UniformBufferBinding* ubb = static_cast<UniformBufferBinding*>(attr);
UniformBufferObject* ubo
= static_cast<UniformBufferObject*>(ubb->getBufferObject());
FloatArray* array = static_cast<FloatArray*>(ubo->getBufferData(0));
double time = nv->getFrameStamp()->getSimulationTime();
double frac = fmod(time, 1.0);
Vec4f warmColor = (Vec4f(0.0, 0.0, 1.0 ,1) * frac
+ Vec4f(1.0, 0.0, 0.0, 1) * (1 - frac));
// Since we're using the std140 layout, we know where the
// warmColor variable is located in the buffer.
for (int i = 0; i < 4; ++i)
(*array)[12 + i] = warmColor[i];
array->dirty();
}
};
int main(int argc, char** argv)
{
osg::ArgumentParser arguments(&argc,argv);
osgViewer::Viewer viewer(arguments);
if (arguments.argc() <= 1) {
cerr << "Need a scene.\n";
return 1;
}
osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFiles(arguments);
if (!loadedModel) {
cerr << "couldn't load " << argv[1] << "\n";
return 1;
}
osgUtil::Optimizer optimizer;
optimizer.optimize(loadedModel.get());
const BoundingSphere bound = loadedModel->getBound();
const float displacement = 2.25 * bound.radius();
Group* scene = new Group;
StateSet* rootSS = scene->getOrCreateStateSet();
Shader* vertexShader = new Shader(Shader::VERTEX);
vertexShader->setShaderSource(vertexShaderSource);
Shader* fragmentShader = new Shader(Shader::FRAGMENT);
fragmentShader->setShaderSource(fragmentShaderSource);
Program* prog = new Program;
prog->addShader(vertexShader);
prog->addShader(fragmentShader);
prog->addBindUniformBlock("colors0", 0);
rootSS->setAttributeAndModes(prog, StateAttribute::ON);
// Place 3 instances of the loaded model with different uniform
// blocks for each.
//
// The blocksize is known because of the std140 format.
const unsigned blockSize = 20 * sizeof(GLfloat);
ref_ptr<FloatArray> colorArray
= new FloatArray(&colors1[0],
&colors1[sizeof(colors1) / sizeof(GLfloat)]);
ref_ptr<UniformBufferObject> ubo = new UniformBufferObject;
colorArray->setBufferObject(ubo.get());
Group* group1 = new Group;
StateSet* ss1 = group1->getOrCreateStateSet();
group1->addChild(loadedModel.get());
scene->addChild(group1);
ref_ptr<UniformBufferBinding> ubb1
= new UniformBufferBinding(0, ubo.get(), 0, blockSize);
ss1->setAttributeAndModes(ubb1.get(), StateAttribute::ON);
ref_ptr<FloatArray> colorArray2
= new FloatArray(&colors2[0],
&colors2[sizeof(colors2) / sizeof(GLfloat)]);
ref_ptr<UniformBufferObject> ubo2 = new UniformBufferObject;
colorArray2->setBufferObject(ubo2.get());
MatrixTransform* group2 = new MatrixTransform;
Matrix mat2 = Matrix::translate(-displacement, 0.0, 0.0);
group2->setMatrix(mat2);
StateSet* ss2 = group2->getOrCreateStateSet();
group2->addChild(loadedModel.get());
scene->addChild(group2);
ref_ptr<UniformBufferBinding> ubb2
= new UniformBufferBinding(0, ubo2.get(), 0, blockSize);
ss2->setAttributeAndModes(ubb2.get(), StateAttribute::ON);
ref_ptr<FloatArray> colorArray3
= new FloatArray(&colors2[0],
&colors2[sizeof(colors2) / sizeof(GLfloat)]);
ref_ptr<UniformBufferObject> ubo3 = new UniformBufferObject;
colorArray3->setBufferObject(ubo3.get());
MatrixTransform* group3 = new MatrixTransform;
Matrix mat3 = Matrix::translate(displacement, 0.0, 0.0);
group3->setMatrix(mat3);
StateSet* ss3 = group3->getOrCreateStateSet();
group3->addChild(loadedModel.get());
scene->addChild(group3);
ref_ptr<UniformBufferBinding> ubb3
= new UniformBufferBinding(0, ubo3.get(), 0, blockSize);
ubb3->setUpdateCallback(new UniformCallback);
ubb3->setDataVariance(Object::DYNAMIC);
ss3->setAttributeAndModes(ubb3.get(), StateAttribute::ON);
viewer.setSceneData(scene);
viewer.realize();
return viewer.run();
}

View File

@ -0,0 +1,129 @@
/* -*-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.
*/
#ifndef OSG_BUFFERINDEXBINDING
#define OSG_BUFFERINDEXBINDING 1
#include <osg/Export>
#include <osg/BufferObject>
#include <osg/StateAttribute>
namespace osg {
class State;
/** Encapsulate binding buffer objects to index targets. This
* specifically supports the uniform buffer and transform feedback
* targets.
*/
// Common implementation superclass
class OSG_EXPORT BufferIndexBinding : public StateAttribute
{
protected:
BufferIndexBinding(GLenum target, GLuint index);
BufferIndexBinding(GLenum target, GLuint index, BufferObject* bo, GLintptr offset,
GLsizeiptr size);
BufferIndexBinding(const BufferIndexBinding& rhs, const CopyOp& copyop=CopyOp::SHALLOW_COPY);
public:
// The member value is part of the key to this state attribute in
// the State class. Using the index target, we can seperately
// track the bindings for many different index targets.
virtual unsigned getMember() const { return static_cast<unsigned int>(_index); }
GLenum getTarget() const { return _target; }
/** Get the index target.
*/
GLuint getIndex() const { return _index; }
/** Set the buffer object that will be bound to the index target.
*/
void setBufferObject(BufferObject *bo) { _bufferObject = bo; }
/** Get the buffer object to be bound.
*/
BufferObject* getBufferObject() const { return _bufferObject.get(); }
/** Set the starting offset into the buffer object for data for
the indexed target. Note: the required alignment on the offset
may be quite large (e.g., 256 bytes on NVidia 8600M). This
should be checked with glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT...).
*/
void setOffset(GLintptr offset) { _offset = offset; }
GLintptr getOffset() const { return _offset; }
/** Set the size of data for the indexed target.
*/
void setSize(GLsizeiptr size) { _size = size; }
GLsizeiptr getSize() const { return _size; }
virtual void apply(State& state) const;
protected:
virtual ~BufferIndexBinding();
const GLenum _target;
const GLuint _index;
ref_ptr<BufferObject> _bufferObject;
GLintptr _offset;
GLsizeiptr _size;
};
/** StateAttribute for binding a uniform buffer index target.
*/
class OSG_EXPORT UniformBufferBinding : public BufferIndexBinding
{
public:
UniformBufferBinding();
UniformBufferBinding(GLuint index);
/** Create a binding for a uniform buffer index target.
* @param index the index target
* @param bo associated buffer object
* @param offset offset into buffer object
* @param size size of data in buffer object
*/
UniformBufferBinding(GLuint index, BufferObject* bo, GLintptr offset, GLsizeiptr size);
UniformBufferBinding(const UniformBufferBinding& rhs, const CopyOp& copyop=CopyOp::SHALLOW_COPY);
META_StateAttribute(osg, UniformBufferBinding, UNIFORMBUFFERBINDING);
virtual int compare(const StateAttribute& bb) const
{
COMPARE_StateAttribute_Types(UniformBufferBinding, bb)
COMPARE_StateAttribute_Parameter(_target)
COMPARE_StateAttribute_Parameter(_index)
COMPARE_StateAttribute_Parameter(_bufferObject)
COMPARE_StateAttribute_Parameter(_offset)
COMPARE_StateAttribute_Parameter(_size)
return 0;
}
};
/** StateAttribute for binding a transform feedback index target.
*/
class OSG_EXPORT TransformFeedbackBufferBinding : public BufferIndexBinding
{
public:
TransformFeedbackBufferBinding(GLuint index = 0);
TransformFeedbackBufferBinding(GLuint index, BufferObject* bo, GLintptr offset, GLsizeiptr size);
TransformFeedbackBufferBinding(const TransformFeedbackBufferBinding& rhs, const CopyOp& copyop=CopyOp::SHALLOW_COPY);
META_StateAttribute(osg, TransformFeedbackBufferBinding, TRANSFORMFEEDBACKBUFFERBINDING);
virtual int compare(const StateAttribute& bb) const
{
COMPARE_StateAttribute_Types(TransformFeedbackBufferBinding, bb)
COMPARE_StateAttribute_Parameter(_target)
COMPARE_StateAttribute_Parameter(_index)
COMPARE_StateAttribute_Parameter(_bufferObject)
COMPARE_StateAttribute_Parameter(_offset)
COMPARE_StateAttribute_Parameter(_size)
return 0;
}
};
}
#endif

View File

@ -254,6 +254,7 @@ class OSG_EXPORT GLBufferObject : public Referenced
bool isBufferObjectSupported() const { return _glGenBuffers!=0; }
bool isPBOSupported() const { return _isPBOSupported; }
bool isUniformBufferObjectSupported() const { return _isUniformBufferObjectSupported; }
void glGenBuffers (GLsizei n, GLuint *buffers) const;
void glBindBuffer (GLenum target, GLuint buffer) const;
@ -266,6 +267,8 @@ class OSG_EXPORT GLBufferObject : public Referenced
GLboolean glUnmapBuffer (GLenum target) const;
void glGetBufferParameteriv (GLenum target, GLenum pname, GLint *params) const;
void glGetBufferPointerv (GLenum target, GLenum pname, GLvoid* *params) const;
void glBindBufferRange (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);
void glBindBufferBase (GLenum target, GLuint index, GLuint buffer);
protected:
@ -280,6 +283,9 @@ class OSG_EXPORT GLBufferObject : public Referenced
typedef GLboolean (GL_APIENTRY * UnmapBufferProc) (GLenum target);
typedef void (GL_APIENTRY * GetBufferParameterivProc) (GLenum target, GLenum pname, GLint *params);
typedef void (GL_APIENTRY * GetBufferPointervProc) (GLenum target, GLenum pname, GLvoid* *params);
typedef void (GL_APIENTRY * BindBufferRangeProc) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);
typedef void (GL_APIENTRY * BindBufferBaseProc) (GLenum target, GLuint index, GLuint buffer);
GenBuffersProc _glGenBuffers;
BindBufferProc _glBindBuffer;
@ -292,8 +298,11 @@ class OSG_EXPORT GLBufferObject : public Referenced
UnmapBufferProc _glUnmapBuffer;
GetBufferParameterivProc _glGetBufferParameteriv;
GetBufferPointervProc _glGetBufferPointerv;
BindBufferRangeProc _glBindBufferRange;
BindBufferBaseProc _glBindBufferBase;
bool _isPBOSupported;
bool _isUniformBufferObjectSupported;
};
/** Function to call to get the extension of a specified context.
@ -753,6 +762,16 @@ class OSG_EXPORT PixelDataBufferObject : public BufferObject
};
class OSG_EXPORT UniformBufferObject : public BufferObject
{
public:
UniformBufferObject();
UniformBufferObject(const UniformBufferObject& ubo, const CopyOp& copyop=CopyOp::SHALLOW_COPY);
META_Object(osg, UniformBufferObject);
protected:
virtual ~UniformBufferObject();
};
inline void GLBufferObject::bindBuffer()
{
_extensions->glBindBuffer(_profile._target,_glObjectID);

View File

@ -247,6 +247,43 @@ typedef char GLchar;
#define GL_MAX_PROGRAM_TEXEL_OFFSET_EXT 0x8905
#endif
// ARB_uniform_buffer_object
#ifndef GL_UNIFORM_BUFFER
#define GL_UNIFORM_BUFFER 0x8A11
#define GL_UNIFORM_BUFFER_BINDING 0x8A28
#define GL_UNIFORM_BUFFER_START 0x8A29
#define GL_UNIFORM_BUFFER_SIZE 0x8A2A
#define GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B
#define GL_MAX_GEOMETRY_UNIFORM_BLOCKS 0x8A2C
#define GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D
#define GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E
#define GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F
#define GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30
#define GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31
#define GL_MAX_COMBINED_GEOMETRY_UNIFORM_COMPONENTS 0x8A32
#define GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33
#define GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34
#define GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35
#define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36
#define GL_UNIFORM_TYPE 0x8A37
#define GL_UNIFORM_SIZE 0x8A38
#define GL_UNIFORM_NAME_LENGTH 0x8A39
#define GL_UNIFORM_BLOCK_INDEX 0x8A3A
#define GL_UNIFORM_OFFSET 0x8A3B
#define GL_UNIFORM_ARRAY_STRIDE 0x8A3C
#define GL_UNIFORM_MATRIX_STRIDE 0x8A3D
#define GL_UNIFORM_IS_ROW_MAJOR 0x8A3E
#define GL_UNIFORM_BLOCK_BINDING 0x8A3F
#define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40
#define GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41
#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42
#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43
#define GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44
#define GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER 0x8A45
#define GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46
#define GL_INVALID_INDEX 0xFFFFFFFFu
#endif
namespace osg {
@ -287,6 +324,8 @@ class OSG_EXPORT GL2Extensions : public osg::Referenced
void setGpuShader4Supported(bool flag) { _isGpuShader4Supported = flag; }
bool isGpuShader4Supported() const { return _isGpuShader4Supported; }
void setUniformBufferObjectSupported(bool flag) { _isUniformBufferObjectSupported = flag; }
bool isUniformBufferObjectSupported() {return _isUniformBufferObjectSupported; }
/** Function to call to get the extension of a specified context.
* If the Exentsion object for that context has not yet been created then
* and the 'createIfNotInitalized' flag been set to false then returns NULL.
@ -433,6 +472,14 @@ class OSG_EXPORT GL2Extensions : public osg::Referenced
void glUniform3uiv( GLint location, GLsizei count, const GLuint *value ) const;
void glUniform4uiv( GLint location, GLsizei count, const GLuint *value ) const;
// ARB_uniform_buffer_object
void glGetUniformIndices(GLuint program, GLsizei uniformCount, const GLchar* *uniformNames, GLuint *uniformIndices) const;
void glGetActiveUniformsiv(GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params) const;
void glGetActiveUniformName(GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName) const;
GLuint glGetUniformBlockIndex(GLuint program, const GLchar *uniformBlockName) const;
void glGetActiveUniformBlockiv(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params) const;
void glGetActiveUniformBlockName(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const;
void glUniformBlockBinding(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding) const;
protected:
~GL2Extensions() {}
@ -446,6 +493,7 @@ class OSG_EXPORT GL2Extensions : public osg::Referenced
bool _isGeometryShader4Supported;
bool _areTessellationShadersSupported;
bool _isGpuShader4Supported;
bool _isUniformBufferObjectSupported;
typedef void (GL_APIENTRY * BlendEquationSeparateProc)(GLenum modeRGB, GLenum modeAlpha);
typedef void (GL_APIENTRY * DrawBuffersProc)(GLsizei n, const GLenum *bufs);
@ -567,6 +615,13 @@ class OSG_EXPORT GL2Extensions : public osg::Referenced
typedef void (GL_APIENTRY * Uniform3uivProc)( GLint location, GLsizei count, const GLuint *value );
typedef void (GL_APIENTRY * Uniform4uivProc)( GLint location, GLsizei count, const GLuint *value );
typedef GLuint (GL_APIENTRY * GetHandleProc) (GLenum pname);
typedef void (GL_APIENTRY * GetUniformIndicesProc)(GLuint program, GLsizei uniformCount, const GLchar* *uniformNames, GLuint *uniformIndices);
typedef void (GL_APIENTRY * GetActiveUniformsivProc)(GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params);
typedef void (GL_APIENTRY * GetActiveUniformNameProc)(GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName);
typedef GLuint (GL_APIENTRY * GetUniformBlockIndexProc)(GLuint program, const GLchar *uniformBlockName);
typedef void (GL_APIENTRY * GetActiveUniformBlockivProc)(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params);
typedef void (GL_APIENTRY * GetActiveUniformBlockNameProc)(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName);
typedef void (GL_APIENTRY * UniformBlockBindingProc)(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding);
BlendEquationSeparateProc _glBlendEquationSeparate;
DrawBuffersProc _glDrawBuffers;
@ -697,6 +752,15 @@ class OSG_EXPORT GL2Extensions : public osg::Referenced
Uniform2uivProc _glUniform2uiv;
Uniform3uivProc _glUniform3uiv;
Uniform4uivProc _glUniform4uiv;
// ARB_uniform_buffer_object
GetUniformIndicesProc _glGetUniformIndices;
GetActiveUniformsivProc _glGetActiveUniformsiv;
GetActiveUniformNameProc _glGetActiveUniformName;
GetUniformBlockIndexProc _glGetUniformBlockIndex;
GetActiveUniformBlockivProc _glGetActiveUniformBlockiv;
GetActiveUniformBlockNameProc _glGetActiveUniformBlockName;
UniformBlockBindingProc _glUniformBlockBinding;
};
}

View File

@ -113,11 +113,22 @@ class OSG_EXPORT Program : public osg::StateAttribute
/** Remove an frag data location binding. */
void removeBindFragDataLocation( const std::string& name );
/** Add a uniform block binding to an index target. XXX This
* should not be an attribute of the program. It should be a
* pseudo-uniform that can live in StateSet objects because
* it is cheap to set. */
void addBindUniformBlock(const std::string& name, GLuint index);
/** Remove a uniform block binding. */
void removeBindUniformBlock(const std::string& name);
typedef std::map<std::string,GLuint> AttribBindingList;
typedef std::map<std::string,GLuint> FragDataBindingList;
typedef std::map<std::string,GLuint> UniformBlockBindingList;
const AttribBindingList& getAttribBindingList() const { return _attribBindingList; }
const FragDataBindingList& getFragDataBindingList() const { return _fragDataBindingList; }
const UniformBlockBindingList& getUniformBlockBindingList() const { return _uniformBlockBindingList; }
/** Return true if this Program represents "fixed-functionality" rendering */
bool isFixedFunction() const;
@ -151,7 +162,18 @@ class OSG_EXPORT Program : public osg::StateAttribute
typedef std::map< std::string, ActiveVarInfo > ActiveVarInfoMap;
const ActiveUniformMap& getActiveUniforms(unsigned int contextID) const;
const ActiveVarInfoMap& getActiveAttribs(unsigned int contextID) const;
struct UniformBlockInfo
{
UniformBlockInfo() : _index(GL_INVALID_INDEX), _size(0) {}
UniformBlockInfo(GLuint index, GLsizei size)
: _index(index), _size(size)
{
}
GLuint _index;
GLsizei _size;
};
typedef std::map<std::string, UniformBlockInfo> UniformBlockMap;
const UniformBlockMap& getUniformBlocks(unsigned contextID) const;
public:
// make PerContextProgram a friend to allow it access Program's protected
@ -214,7 +236,7 @@ class OSG_EXPORT Program : public osg::StateAttribute
const ActiveUniformMap& getActiveUniforms() const {return _uniformInfoMap;}
const ActiveVarInfoMap& getActiveAttribs() const {return _attribInfoMap;}
const UniformBlockMap& getUniformBlocks() const {return _uniformBlockMap; }
inline GLint getUniformLocation( unsigned int uniformNameID ) const { ActiveUniformMap::const_iterator itr = _uniformInfoMap.find(uniformNameID); return (itr!=_uniformInfoMap.end()) ? itr->second._location : -1; }
inline GLint getAttribLocation( const std::string& name ) const { ActiveVarInfoMap::const_iterator itr = _attribInfoMap.find(name); return (itr!=_attribInfoMap.end()) ? itr->second._location : -1; }
@ -246,6 +268,7 @@ class OSG_EXPORT Program : public osg::StateAttribute
ActiveUniformMap _uniformInfoMap;
ActiveVarInfoMap _attribInfoMap;
UniformBlockMap _uniformBlockMap;
typedef std::pair<osg::ref_ptr<const osg::Uniform>, unsigned int> UniformModifiedCountPair;
typedef std::vector<UniformModifiedCountPair> LastAppliedUniformList;
@ -272,6 +295,7 @@ class OSG_EXPORT Program : public osg::StateAttribute
mutable osg::buffered_value< osg::ref_ptr<PerContextProgram> > _pcpList;
AttribBindingList _attribBindingList;
FragDataBindingList _fragDataBindingList;
UniformBlockBindingList _uniformBlockBindingList;
typedef std::vector< ref_ptr<Shader> > ShaderList;
ShaderList _shaderList;

View File

@ -184,7 +184,10 @@ class OSG_EXPORT StateAttribute : public Object
OSGNVSLANG_PROGRAM,
// osgNVParse
OSGNVPARSE_PROGRAM_PARSER
OSGNVPARSE_PROGRAM_PARSER,
UNIFORMBUFFERBINDING,
TRANSFORMFEEDBACKBUFFERBINDING
};
/** Simple pairing between an attribute type and the member within that attribute type group.*/

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;