diff --git a/include/osg/GL2Extensions b/include/osg/GL2Extensions index b999288ac..8137951bf 100644 --- a/include/osg/GL2Extensions +++ b/include/osg/GL2Extensions @@ -284,6 +284,13 @@ typedef char GLchar; #define GL_INVALID_INDEX 0xFFFFFFFFu #endif +//ARB_get_program_binary +#ifndef GL_PROGRAM_BINARY_RETRIEVABLE_HINT +#define GL_PROGRAM_BINARY_RETRIEVABLE_HINT 0x8257 +#define GL_PROGRAM_BINARY_LENGTH 0x8741 +#define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE +#define GL_PROGRAM_BINARY_FORMATS 0x87FF +#endif namespace osg { @@ -326,6 +333,10 @@ class OSG_EXPORT GL2Extensions : public osg::Referenced void setUniformBufferObjectSupported(bool flag) { _isUniformBufferObjectSupported = flag; } bool isUniformBufferObjectSupported() {return _isUniformBufferObjectSupported; } + + void setGetProgramBinarySupported(bool flag) { _isGetProgramBinarySupported = flag; } + bool isGetProgramBinarySupported() {return _isGetProgramBinarySupported; } + /** 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. @@ -480,6 +491,11 @@ class OSG_EXPORT GL2Extensions : public osg::Referenced 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; + + // ARB_get_program_binary + void glGetProgramBinary(GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary) const; + void glProgramBinary(GLuint program, GLenum binaryFormat, const GLvoid *binary, GLsizei length) const; + protected: ~GL2Extensions() {} @@ -494,6 +510,7 @@ class OSG_EXPORT GL2Extensions : public osg::Referenced bool _areTessellationShadersSupported; bool _isGpuShader4Supported; bool _isUniformBufferObjectSupported; + bool _isGetProgramBinarySupported; typedef void (GL_APIENTRY * BlendEquationSeparateProc)(GLenum modeRGB, GLenum modeAlpha); typedef void (GL_APIENTRY * DrawBuffersProc)(GLsizei n, const GLenum *bufs); @@ -622,6 +639,8 @@ class OSG_EXPORT GL2Extensions : public osg::Referenced 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); + typedef void (GL_APIENTRY * GetProgramBinaryProc)(GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary); + typedef void (GL_APIENTRY * ProgramBinaryProc)(GLuint program, GLenum binaryFormat, const GLvoid *binary, GLsizei length); BlendEquationSeparateProc _glBlendEquationSeparate; DrawBuffersProc _glDrawBuffers; @@ -761,6 +780,10 @@ class OSG_EXPORT GL2Extensions : public osg::Referenced GetActiveUniformBlockivProc _glGetActiveUniformBlockiv; GetActiveUniformBlockNameProc _glGetActiveUniformBlockName; UniformBlockBindingProc _glUniformBlockBinding; + + //ARB_get_program_binary + GetProgramBinaryProc _glGetProgramBinary; + ProgramBinaryProc _glProgramBinary; }; } diff --git a/include/osg/Program b/include/osg/Program index 75be77a2b..173b99bf6 100644 --- a/include/osg/Program +++ b/include/osg/Program @@ -35,6 +35,51 @@ namespace osg { class State; +/** Simple class for wrapping up the data used in glProgramBinary and glGetProgramBinary. + * On the first run of your application Programs should be assigned an empty ProgramBinary. + * Before your application exits it should retrieve the program binary via + * Program::PerContextProgram::compileProgramBinary and save it to disk. + * When your application is run subsequently, load your binary from disk and use it to set + * the data of a ProgramBinary, and set the ProgramBinary on the associated Program. + * This will typically result in Program::compileGLObjects executing much faster.*/ +class OSG_EXPORT ProgramBinary : public osg::Object +{ + public: + + ProgramBinary(); + + /** Copy constructor using CopyOp to manage deep vs shallow copy.*/ + ProgramBinary(const ProgramBinary& rhs, const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY); + + META_Object(osg, ProgramBinary); + + /** Allocated a data buffer of specified size/*/ + void allocate(unsigned int size); + + /** Assign program binary data, copying the specified data into locally stored data buffer, the original data can then be deleted.*/ + void assign(unsigned int size, const unsigned char* data); + + /** Set the format of the program binary data.*/ + void setFormat(GLenum format) {_format = format;} + + /** Get the format of the program binary data.*/ + GLenum getFormat() const {return _format;} + + /** Get the size of the program binary data.*/ + unsigned int getSize() const { return _data.size(); } + + /** Get a ptr to the program binary data.*/ + unsigned char* getData() { return _data.empty() ? 0 : &(_data.front()); } + + /** Get a const ptr to the program binary data.*/ + const unsigned char* getData() const { return _data.empty() ? 0 : &(_data.front()); } + + protected: + std::vector _data; + GLenum _format; +}; + + /////////////////////////////////////////////////////////////////////////// /** osg::Program is an application-level abstraction of an OpenGL glProgram. * It is an osg::StateAttribute that, when applied, will activate a @@ -122,6 +167,17 @@ class OSG_EXPORT Program : public osg::StateAttribute /** Remove a uniform block binding. */ void removeBindUniformBlock(const std::string& name); + /** Set the Program using a ProgramBinary. If a ProgramBinary is not yet + * available then setting an empty one signals that compileProgramBinary + * will be called later.*/ + void setProgramBinary(ProgramBinary* programBinary) { _programBinary = programBinary; } + + /** Get the Program's ProgramBinary, return NULL if none is assigned. */ + ProgramBinary* getProgramBinary() { return _programBinary.get(); } + + /** Get the const Program's ProgramBinary, return NULL if none is assigned. */ + const ProgramBinary* getProgramBinary() const { return _programBinary.get(); } + typedef std::map AttribBindingList; typedef std::map FragDataBindingList; typedef std::map UniformBlockBindingList; @@ -196,6 +252,17 @@ class OSG_EXPORT Program : public osg::StateAttribute bool isLinked() const {return _isLinked;} bool getInfoLog( std::string& infoLog ) const; + /** Was glProgramBinary called successfully? */ + bool loadedBinary() const {return _loadedBinary;} + + /** Compile a program binary. For this to work setProgramBinary must have + * been called on the osg::Program with an empty ProgramBinary prior to + * compileGLObjects being called. + * compileProgramBinary should be called after the program has been + * "exercised" by rendering with it. The ProgramBinary can then be saved + * to disk for faster subsequent compiling. */ + ProgramBinary* compileProgramBinary(osg::State& state); + void useProgram() const; void resetAppliedUniforms() const @@ -275,6 +342,8 @@ class OSG_EXPORT Program : public osg::StateAttribute bool _needsLink; /** Is our glProgram successfully linked? */ bool _isLinked; + /** Was glProgramBinary called successfully? */ + bool _loadedBinary; const unsigned int _contextID; ActiveUniformMap _uniformInfoMap; @@ -311,6 +380,8 @@ class OSG_EXPORT Program : public osg::StateAttribute typedef std::vector< ref_ptr > ShaderList; ShaderList _shaderList; + osg::ref_ptr _programBinary; + /** Parameters maintained with glProgramParameteriEXT */ GLint _geometryVerticesOut; GLint _geometryInputType; diff --git a/include/osg/StateSet b/include/osg/StateSet index 2bbe260ad..5b4752bcd 100644 --- a/include/osg/StateSet +++ b/include/osg/StateSet @@ -17,10 +17,7 @@ #include #include #include - #include -#include - #include #include diff --git a/src/osg/GL2Extensions.cpp b/src/osg/GL2Extensions.cpp index 9f837b6ac..030ca6851 100644 --- a/src/osg/GL2Extensions.cpp +++ b/src/osg/GL2Extensions.cpp @@ -48,6 +48,7 @@ GL2Extensions::GL2Extensions(const GL2Extensions& rhs) : osg::Referenced() _isGeometryShader4Supported = rhs._isGeometryShader4Supported; _isGpuShader4Supported = rhs._isGpuShader4Supported; _isUniformBufferObjectSupported = rhs._isUniformBufferObjectSupported; + _isGetProgramBinarySupported = rhs._isGetProgramBinarySupported; _glBlendEquationSeparate = rhs._glBlendEquationSeparate; _glDrawBuffers = rhs._glDrawBuffers; @@ -183,6 +184,10 @@ GL2Extensions::GL2Extensions(const GL2Extensions& rhs) : osg::Referenced() _glGetActiveUniformBlockiv = rhs._glGetActiveUniformBlockiv; _glGetActiveUniformBlockName = rhs._glGetActiveUniformBlockName; _glUniformBlockBinding = rhs._glUniformBlockBinding; + + // ARB_get_program_binary + _glGetProgramBinary = rhs._glGetProgramBinary; + _glProgramBinary = rhs._glProgramBinary; } @@ -338,6 +343,9 @@ void GL2Extensions::lowestCommonDenominator(const GL2Extensions& rhs) if (!rhs._glGetActiveUniformBlockName) _glGetActiveUniformBlockName = 0; if (!rhs._glUniformBlockBinding) _glUniformBlockBinding = 0; + // ARB_get_program_binary + if (!rhs._glGetProgramBinary) _glGetProgramBinary = 0; + if (!rhs._glProgramBinary) _glProgramBinary = 0; } @@ -362,7 +370,8 @@ 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"); + _isUniformBufferObjectSupported = osg::isGLExtensionSupported(contextID,"GL_ARB_uniform_buffer_object"); + _isGetProgramBinarySupported = osg::isGLExtensionSupported(contextID,"GL_ARB_get_program_binary"); if( isGlslSupported() ) { @@ -520,7 +529,9 @@ void GL2Extensions::setupGL2Extensions(unsigned int contextID) setGLExtensionFuncPtr(_glGetActiveUniformBlockiv, "glGetActiveUniformBlockiv"); setGLExtensionFuncPtr(_glGetActiveUniformBlockName, "glGetActiveUniformBlockName"); setGLExtensionFuncPtr(_glUniformBlockBinding, "glUniformBlockBinding"); - + //ARB_get_program_binary + setGLExtensionFuncPtr(_glGetProgramBinary, "glGetProgramBinary"); + setGLExtensionFuncPtr(_glProgramBinary, "glProgramBinary"); } @@ -2287,6 +2298,38 @@ void GL2Extensions::glUniformBlockBinding(GLuint program, } } +//ARB_get_program_binary +void GL2Extensions::glGetProgramBinary(GLuint program, + GLsizei bufSize, + GLsizei *length, + GLenum *binaryFormat, + GLvoid *binary) const +{ + if (_glGetProgramBinary) + { + _glGetProgramBinary(program, bufSize, length, binaryFormat, binary); + } + else + { + NotSupported("glGetProgramBinary"); + } +} + +void GL2Extensions::glProgramBinary(GLuint program, + GLenum binaryFormat, + const GLvoid *binary, + GLsizei length) const +{ + if (_glProgramBinary) + { + _glProgramBinary(program, binaryFormat, binary, length); + } + else + { + NotSupported("glProgramBinary"); + } +} + /////////////////////////////////////////////////////////////////////////// // C++-friendly convenience methods diff --git a/src/osg/Program.cpp b/src/osg/Program.cpp index 7baff3833..ccbe3b25a 100644 --- a/src/osg/Program.cpp +++ b/src/osg/Program.cpp @@ -20,6 +20,7 @@ */ #include +#include #include #include @@ -93,6 +94,38 @@ void Program::discardDeletedGlPrograms(unsigned int contextID) } +/////////////////////////////////////////////////////////////////////////// +// osg::ProgramBinary +/////////////////////////////////////////////////////////////////////////// + +ProgramBinary::ProgramBinary() : _format(0) +{ +} + +ProgramBinary::ProgramBinary(const ProgramBinary& rhs, const osg::CopyOp&) : + _data(rhs._data), _format(rhs._format) +{ +} + +void ProgramBinary::allocate(unsigned int size) +{ + _data.clear(); + _data.resize(size); +} + +void ProgramBinary::assign(unsigned int size, const unsigned char* data) +{ + allocate(size); + if (data) + { + for(unsigned int i=0; isecond<<", "<first<glBindAttribLocation( _glProgramHandle, itr->second, reinterpret_cast(itr->first.c_str()) ); - } - - // set any explicit vertex attribute bindings that are set up via osg::State, such as the vertex arrays - // that have been aliase to vertex attrib arrays - if (state.getUseVertexAttributeAliasing()) - { - const AttribBindingList& stateBindlist = state.getAttributeBindingList(); - for( AttribBindingList::const_iterator itr = stateBindlist.begin(); - itr != stateBindlist.end(); ++itr ) + // set any explicit vertex attribute bindings + const AttribBindingList& programBindlist = _program->getAttribBindingList(); + for( AttribBindingList::const_iterator itr = programBindlist.begin(); + itr != programBindlist.end(); ++itr ) { - OSG_INFO<<"State's vertex attrib binding "<second<<", "<first<second<<", "<first<glBindAttribLocation( _glProgramHandle, itr->second, reinterpret_cast(itr->first.c_str()) ); } + + // set any explicit vertex attribute bindings that are set up via osg::State, such as the vertex arrays + // that have been aliase to vertex attrib arrays + if (state.getUseVertexAttributeAliasing()) + { + const AttribBindingList& stateBindlist = state.getAttributeBindingList(); + for( AttribBindingList::const_iterator itr = stateBindlist.begin(); + itr != stateBindlist.end(); ++itr ) + { + OSG_INFO<<"State's vertex attrib binding "<second<<", "<first<glBindAttribLocation( _glProgramHandle, itr->second, reinterpret_cast(itr->first.c_str()) ); + } + } + + // set any explicit frag data bindings + const FragDataBindingList& fdbindlist = _program->getFragDataBindingList(); + for( FragDataBindingList::const_iterator itr = fdbindlist.begin(); + itr != fdbindlist.end(); ++itr ) + { + _extensions->glBindFragDataLocation( _glProgramHandle, itr->second, reinterpret_cast(itr->first.c_str()) ); + } + + // if any program binary has been set then assume we want to retrieve a binary later. + if (programBinary) + { + _extensions->glProgramParameteri( _glProgramHandle, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE ); + } + + // link the glProgram + GLint linked = GL_FALSE; + _extensions->glLinkProgram( _glProgramHandle ); + _extensions->glGetProgramiv( _glProgramHandle, GL_LINK_STATUS, &linked ); + _isLinked = (linked == GL_TRUE); } - // set any explicit frag data bindings - const FragDataBindingList& fdbindlist = _program->getFragDataBindingList(); - for( FragDataBindingList::const_iterator itr = fdbindlist.begin(); - itr != fdbindlist.end(); ++itr ) - { - _extensions->glBindFragDataLocation( _glProgramHandle, itr->second, reinterpret_cast(itr->first.c_str()) ); - } - - // link the glProgram - GLint linked = GL_FALSE; - _extensions->glLinkProgram( _glProgramHandle ); - _extensions->glGetProgramiv( _glProgramHandle, GL_LINK_STATUS, &linked ); - _isLinked = (linked == GL_TRUE); if( ! _isLinked ) { OSG_WARN << "glLinkProgram \""<< _program->getName() << "\" FAILED" << std::endl; @@ -600,7 +661,7 @@ void Program::PerContextProgram::linkProgram(osg::State& state) if( getInfoLog(infoLog) ) { OSG_INFO << "Program \""<< _program->getName() << "\" "<< - "link succeded, infolog:\n" << infoLog << std::endl; + "link succeeded, infolog:\n" << infoLog << std::endl; } } @@ -747,6 +808,23 @@ bool Program::PerContextProgram::getInfoLog( std::string& infoLog ) const return _extensions->getProgramInfoLog( _glProgramHandle, infoLog ); } +ProgramBinary* Program::PerContextProgram::compileProgramBinary(osg::State& state) +{ + linkProgram(state); + GLint binaryLength = 0; + _extensions->glGetProgramiv( _glProgramHandle, GL_PROGRAM_BINARY_LENGTH, &binaryLength ); + if (binaryLength) + { + ProgramBinary* programBinary = new ProgramBinary; + programBinary->allocate(binaryLength); + GLenum binaryFormat = 0; + _extensions->glGetProgramBinary( _glProgramHandle, binaryLength, 0, &binaryFormat, reinterpret_cast(programBinary->getData()) ); + programBinary->setFormat(binaryFormat); + return programBinary; + } + return 0; +} + void Program::PerContextProgram::useProgram() const { _extensions->glUseProgram( _glProgramHandle );