diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index eb54ffe3b..b8e62cea1 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -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) diff --git a/examples/osguniformbuffer/CMakeLists.txt b/examples/osguniformbuffer/CMakeLists.txt new file mode 100644 index 000000000..8b60bf455 --- /dev/null +++ b/examples/osguniformbuffer/CMakeLists.txt @@ -0,0 +1,4 @@ +SET(TARGET_SRC osguniformbuffer.cpp ) + +#### end var setup ### +SETUP_EXAMPLE(osguniformbuffer) diff --git a/examples/osguniformbuffer/osguniformbuffer.cpp b/examples/osguniformbuffer/osguniformbuffer.cpp new file mode 100644 index 000000000..06d2b85b3 --- /dev/null +++ b/examples/osguniformbuffer/osguniformbuffer.cpp @@ -0,0 +1,206 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +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(attr); + UniformBufferObject* ubo + = static_cast(ubb->getBufferObject()); + FloatArray* array = static_cast(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 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 colorArray + = new FloatArray(&colors1[0], + &colors1[sizeof(colors1) / sizeof(GLfloat)]); + ref_ptr ubo = new UniformBufferObject; + colorArray->setBufferObject(ubo.get()); + Group* group1 = new Group; + StateSet* ss1 = group1->getOrCreateStateSet(); + group1->addChild(loadedModel.get()); + scene->addChild(group1); + ref_ptr ubb1 + = new UniformBufferBinding(0, ubo.get(), 0, blockSize); + ss1->setAttributeAndModes(ubb1.get(), StateAttribute::ON); + + ref_ptr colorArray2 + = new FloatArray(&colors2[0], + &colors2[sizeof(colors2) / sizeof(GLfloat)]); + ref_ptr 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 ubb2 + = new UniformBufferBinding(0, ubo2.get(), 0, blockSize); + ss2->setAttributeAndModes(ubb2.get(), StateAttribute::ON); + + ref_ptr colorArray3 + = new FloatArray(&colors2[0], + &colors2[sizeof(colors2) / sizeof(GLfloat)]); + ref_ptr 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 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(); +} diff --git a/include/osg/BufferIndexBinding b/include/osg/BufferIndexBinding new file mode 100644 index 000000000..2e9e1273b --- /dev/null +++ b/include/osg/BufferIndexBinding @@ -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 +#include +#include + +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(_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; + 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 diff --git a/include/osg/BufferObject b/include/osg/BufferObject index 68681c9d5..563598275 100644 --- a/include/osg/BufferObject +++ b/include/osg/BufferObject @@ -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); diff --git a/include/osg/GL2Extensions b/include/osg/GL2Extensions index 5135403c4..b999288ac 100644 --- a/include/osg/GL2Extensions +++ b/include/osg/GL2Extensions @@ -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; }; } diff --git a/include/osg/Program b/include/osg/Program index f57d0130c..b4979f477 100644 --- a/include/osg/Program +++ b/include/osg/Program @@ -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 AttribBindingList; typedef std::map FragDataBindingList; + typedef std::map 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 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, unsigned int> UniformModifiedCountPair; typedef std::vector LastAppliedUniformList; @@ -272,6 +295,7 @@ class OSG_EXPORT Program : public osg::StateAttribute mutable osg::buffered_value< osg::ref_ptr > _pcpList; AttribBindingList _attribBindingList; FragDataBindingList _fragDataBindingList; + UniformBlockBindingList _uniformBlockBindingList; typedef std::vector< ref_ptr > ShaderList; ShaderList _shaderList; diff --git a/include/osg/StateAttribute b/include/osg/StateAttribute index 97136c3e4..b867b774a 100644 --- a/include/osg/StateAttribute +++ b/include/osg/StateAttribute @@ -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.*/ diff --git a/src/osg/BufferIndexBinding.cpp b/src/osg/BufferIndexBinding.cpp new file mode 100644 index 000000000..f4b1fa4d9 --- /dev/null +++ b/src/osg/BufferIndexBinding.cpp @@ -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 +#include + +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(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) +{ +} + +} diff --git a/src/osg/BufferObject.cpp b/src/osg/BufferObject.cpp index 78e3a1b52..bba71b187 100644 --- a/src/osg/BufferObject.cpp +++ b/src/osg/BufferObject.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -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"<isUniformBufferObjectSupported()) + { + GLuint activeUniformBlocks = 0; + GLsizei maxBlockNameLen = 0; + _extensions->glGetProgramiv(_glProgramHandle, GL_ACTIVE_UNIFORM_BLOCKS, + reinterpret_cast(&activeUniformBlocks)); + _extensions->glGetProgramiv(_glProgramHandle, + GL_ACTIVE_UNIFORM_MAX_LENGTH, + &maxBlockNameLen); + if (maxBlockNameLen > 0) + { + std::vector 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;