/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2005 Robert Osfield * Copyright (C) 2003-2005 3Dlabs Inc. Ltd. * Copyright (C) 2004-2005 Nathan Cournia * * This application is open source and may be redistributed and/or modified * freely and without restriction, both in commericial and non commericial * applications, as long as this copyright notice is maintained. * * This application 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. * */ /* file: src/osg/Program.cpp * author: Mike Weiblen 2005-07-01 */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace osg; /////////////////////////////////////////////////////////////////////////// // Extension function pointers for OpenGL v2.0 GL2Extensions::GL2Extensions(unsigned int contextID) { setupGL2Extensions(contextID); } GL2Extensions::GL2Extensions(const GL2Extensions& rhs) : osg::Referenced() { _glVersion = rhs._glVersion; _glslLanguageVersion = rhs._glslLanguageVersion; _isShaderObjectsSupported = rhs._isShaderObjectsSupported; _isVertexShaderSupported = rhs._isVertexShaderSupported; _isFragmentShaderSupported = rhs._isFragmentShaderSupported; _isLanguage100Supported = rhs._isLanguage100Supported; _glBlendEquationSeparate = rhs._glBlendEquationSeparate; _glDrawBuffers = rhs._glDrawBuffers; _glStencilOpSeparate = rhs._glStencilOpSeparate; _glStencilFuncSeparate = rhs._glStencilFuncSeparate; _glStencilMaskSeparate = rhs._glStencilMaskSeparate; _glAttachShader = rhs._glAttachShader; _glBindAttribLocation = rhs._glBindAttribLocation; _glCompileShader = rhs._glCompileShader; _glCreateProgram = rhs._glCreateProgram; _glCreateShader = rhs._glCreateShader; _glDeleteProgram = rhs._glDeleteProgram; _glDeleteShader = rhs._glDeleteShader; _glDetachShader = rhs._glDetachShader; _glDisableVertexAttribArray = rhs._glDisableVertexAttribArray; _glEnableVertexAttribArray = rhs._glEnableVertexAttribArray; _glGetActiveAttrib = rhs._glGetActiveAttrib; _glGetActiveUniform = rhs._glGetActiveUniform; _glGetAttachedShaders = rhs._glGetAttachedShaders; _glGetAttribLocation = rhs._glGetAttribLocation; _glGetProgramiv = rhs._glGetProgramiv; _glGetProgramInfoLog = rhs._glGetProgramInfoLog; _glGetShaderiv = rhs._glGetShaderiv; _glGetShaderInfoLog = rhs._glGetShaderInfoLog; _glGetShaderSource = rhs._glGetShaderSource; _glGetUniformLocation = rhs._glGetUniformLocation; _glGetUniformfv = rhs._glGetUniformfv; _glGetUniformiv = rhs._glGetUniformiv; _glGetVertexAttribdv = rhs._glGetVertexAttribdv; _glGetVertexAttribfv = rhs._glGetVertexAttribfv; _glGetVertexAttribiv = rhs._glGetVertexAttribiv; _glGetVertexAttribPointerv = rhs._glGetVertexAttribPointerv; _glIsProgram = rhs._glIsProgram; _glIsShader = rhs._glIsShader; _glLinkProgram = rhs._glLinkProgram; _glShaderSource = rhs._glShaderSource; _glUseProgram = rhs._glUseProgram; _glUniform1f = rhs._glUniform1f; _glUniform2f = rhs._glUniform2f; _glUniform3f = rhs._glUniform3f; _glUniform4f = rhs._glUniform4f; _glUniform1i = rhs._glUniform1i; _glUniform2i = rhs._glUniform2i; _glUniform3i = rhs._glUniform3i; _glUniform4i = rhs._glUniform4i; _glUniform1fv = rhs._glUniform1fv; _glUniform2fv = rhs._glUniform2fv; _glUniform3fv = rhs._glUniform3fv; _glUniform4fv = rhs._glUniform4fv; _glUniform1iv = rhs._glUniform1iv; _glUniform2iv = rhs._glUniform2iv; _glUniform3iv = rhs._glUniform3iv; _glUniform4iv = rhs._glUniform4iv; _glUniformMatrix2fv = rhs._glUniformMatrix2fv; _glUniformMatrix3fv = rhs._glUniformMatrix3fv; _glUniformMatrix4fv = rhs._glUniformMatrix4fv; _glValidateProgram = rhs._glValidateProgram; _glVertexAttrib1d = rhs._glVertexAttrib1d; _glVertexAttrib1dv = rhs._glVertexAttrib1dv; _glVertexAttrib1f = rhs._glVertexAttrib1f; _glVertexAttrib1fv = rhs._glVertexAttrib1fv; _glVertexAttrib1s = rhs._glVertexAttrib1s; _glVertexAttrib1sv = rhs._glVertexAttrib1sv; _glVertexAttrib2d = rhs._glVertexAttrib2d; _glVertexAttrib2dv = rhs._glVertexAttrib2dv; _glVertexAttrib2f = rhs._glVertexAttrib2f; _glVertexAttrib2fv = rhs._glVertexAttrib2fv; _glVertexAttrib2s = rhs._glVertexAttrib2s; _glVertexAttrib2sv = rhs._glVertexAttrib2sv; _glVertexAttrib3d = rhs._glVertexAttrib3d; _glVertexAttrib3dv = rhs._glVertexAttrib3dv; _glVertexAttrib3f = rhs._glVertexAttrib3f; _glVertexAttrib3fv = rhs._glVertexAttrib3fv; _glVertexAttrib3s = rhs._glVertexAttrib3s; _glVertexAttrib3sv = rhs._glVertexAttrib3sv; _glVertexAttrib4Nbv = rhs._glVertexAttrib4Nbv; _glVertexAttrib4Niv = rhs._glVertexAttrib4Niv; _glVertexAttrib4Nsv = rhs._glVertexAttrib4Nsv; _glVertexAttrib4Nub = rhs._glVertexAttrib4Nub; _glVertexAttrib4Nubv = rhs._glVertexAttrib4Nubv; _glVertexAttrib4Nuiv = rhs._glVertexAttrib4Nuiv; _glVertexAttrib4Nusv = rhs._glVertexAttrib4Nusv; _glVertexAttrib4bv = rhs._glVertexAttrib4bv; _glVertexAttrib4d = rhs._glVertexAttrib4d; _glVertexAttrib4dv = rhs._glVertexAttrib4dv; _glVertexAttrib4f = rhs._glVertexAttrib4f; _glVertexAttrib4fv = rhs._glVertexAttrib4fv; _glVertexAttrib4iv = rhs._glVertexAttrib4iv; _glVertexAttrib4s = rhs._glVertexAttrib4s; _glVertexAttrib4sv = rhs._glVertexAttrib4sv; _glVertexAttrib4ubv = rhs._glVertexAttrib4ubv; _glVertexAttrib4uiv = rhs._glVertexAttrib4uiv; _glVertexAttrib4usv = rhs._glVertexAttrib4usv; _glVertexAttribPointer = rhs._glVertexAttribPointer; _glGetInfoLogARB = rhs._glGetInfoLogARB; _glGetObjectParameterivARB = rhs._glGetObjectParameterivARB; _glDeleteObjectARB = rhs._glDeleteObjectARB; _glGetHandleARB = rhs._glGetHandleARB; } void GL2Extensions::lowestCommonDenominator(const GL2Extensions& rhs) { if (rhs._glVersion < _glVersion) _glVersion = rhs._glVersion; if (rhs._glslLanguageVersion < _glslLanguageVersion) _glslLanguageVersion = rhs._glslLanguageVersion; if (!rhs._isShaderObjectsSupported) _isShaderObjectsSupported = false; if (!rhs._isVertexShaderSupported) _isVertexShaderSupported = false; if (!rhs._isFragmentShaderSupported) _isFragmentShaderSupported = false; if (!rhs._isLanguage100Supported) _isLanguage100Supported = false; if (!rhs._glBlendEquationSeparate) _glBlendEquationSeparate = 0; if (!rhs._glDrawBuffers) _glDrawBuffers = 0; if (!rhs._glStencilOpSeparate) _glStencilOpSeparate = 0; if (!rhs._glStencilFuncSeparate) _glStencilFuncSeparate = 0; if (!rhs._glStencilMaskSeparate) _glStencilMaskSeparate = 0; if (!rhs._glAttachShader) _glAttachShader = 0; if (!rhs._glBindAttribLocation) _glBindAttribLocation = 0; if (!rhs._glCompileShader) _glCompileShader = 0; if (!rhs._glCreateProgram) _glCreateProgram = 0; if (!rhs._glCreateShader) _glCreateShader = 0; if (!rhs._glDeleteProgram) _glDeleteProgram = 0; if (!rhs._glDeleteShader) _glDeleteShader = 0; if (!rhs._glDetachShader) _glDetachShader = 0; if (!rhs._glDisableVertexAttribArray) _glDisableVertexAttribArray = 0; if (!rhs._glEnableVertexAttribArray) _glEnableVertexAttribArray = 0; if (!rhs._glGetActiveAttrib) _glGetActiveAttrib = 0; if (!rhs._glGetActiveUniform) _glGetActiveUniform = 0; if (!rhs._glGetAttachedShaders) _glGetAttachedShaders = 0; if (!rhs._glGetAttribLocation) _glGetAttribLocation = 0; if (!rhs._glGetProgramiv) _glGetProgramiv = 0; if (!rhs._glGetProgramInfoLog) _glGetProgramInfoLog = 0; if (!rhs._glGetShaderiv) _glGetShaderiv = 0; if (!rhs._glGetShaderInfoLog) _glGetShaderInfoLog = 0; if (!rhs._glGetShaderSource) _glGetShaderSource = 0; if (!rhs._glGetUniformLocation) _glGetUniformLocation = 0; if (!rhs._glGetUniformfv) _glGetUniformfv = 0; if (!rhs._glGetUniformiv) _glGetUniformiv = 0; if (!rhs._glGetVertexAttribdv) _glGetVertexAttribdv = 0; if (!rhs._glGetVertexAttribfv) _glGetVertexAttribfv = 0; if (!rhs._glGetVertexAttribiv) _glGetVertexAttribiv = 0; if (!rhs._glGetVertexAttribPointerv) _glGetVertexAttribPointerv = 0; if (!rhs._glIsProgram) _glIsProgram = 0; if (!rhs._glIsShader) _glIsShader = 0; if (!rhs._glLinkProgram) _glLinkProgram = 0; if (!rhs._glShaderSource) _glShaderSource = 0; if (!rhs._glUseProgram) _glUseProgram = 0; if (!rhs._glUniform1f) _glUniform1f = 0; if (!rhs._glUniform2f) _glUniform2f = 0; if (!rhs._glUniform3f) _glUniform3f = 0; if (!rhs._glUniform4f) _glUniform4f = 0; if (!rhs._glUniform1i) _glUniform1i = 0; if (!rhs._glUniform2i) _glUniform2i = 0; if (!rhs._glUniform3i) _glUniform3i = 0; if (!rhs._glUniform4i) _glUniform4i = 0; if (!rhs._glUniform1fv) _glUniform1fv = 0; if (!rhs._glUniform2fv) _glUniform2fv = 0; if (!rhs._glUniform3fv) _glUniform3fv = 0; if (!rhs._glUniform4fv) _glUniform4fv = 0; if (!rhs._glUniform1iv) _glUniform1iv = 0; if (!rhs._glUniform2iv) _glUniform2iv = 0; if (!rhs._glUniform3iv) _glUniform3iv = 0; if (!rhs._glUniform4iv) _glUniform4iv = 0; if (!rhs._glUniformMatrix2fv) _glUniformMatrix2fv = 0; if (!rhs._glUniformMatrix3fv) _glUniformMatrix3fv = 0; if (!rhs._glUniformMatrix4fv) _glUniformMatrix4fv = 0; if (!rhs._glValidateProgram) _glValidateProgram = 0; if (!rhs._glVertexAttrib1d) _glVertexAttrib1d = 0; if (!rhs._glVertexAttrib1dv) _glVertexAttrib1dv = 0; if (!rhs._glVertexAttrib1f) _glVertexAttrib1f = 0; if (!rhs._glVertexAttrib1fv) _glVertexAttrib1fv = 0; if (!rhs._glVertexAttrib1s) _glVertexAttrib1s = 0; if (!rhs._glVertexAttrib1sv) _glVertexAttrib1sv = 0; if (!rhs._glVertexAttrib2d) _glVertexAttrib2d = 0; if (!rhs._glVertexAttrib2dv) _glVertexAttrib2dv = 0; if (!rhs._glVertexAttrib2f) _glVertexAttrib2f = 0; if (!rhs._glVertexAttrib2fv) _glVertexAttrib2fv = 0; if (!rhs._glVertexAttrib2s) _glVertexAttrib2s = 0; if (!rhs._glVertexAttrib2sv) _glVertexAttrib2sv = 0; if (!rhs._glVertexAttrib3d) _glVertexAttrib3d = 0; if (!rhs._glVertexAttrib3dv) _glVertexAttrib3dv = 0; if (!rhs._glVertexAttrib3f) _glVertexAttrib3f = 0; if (!rhs._glVertexAttrib3fv) _glVertexAttrib3fv = 0; if (!rhs._glVertexAttrib3s) _glVertexAttrib3s = 0; if (!rhs._glVertexAttrib3sv) _glVertexAttrib3sv = 0; if (!rhs._glVertexAttrib4Nbv) _glVertexAttrib4Nbv = 0; if (!rhs._glVertexAttrib4Niv) _glVertexAttrib4Niv = 0; if (!rhs._glVertexAttrib4Nsv) _glVertexAttrib4Nsv = 0; if (!rhs._glVertexAttrib4Nub) _glVertexAttrib4Nub = 0; if (!rhs._glVertexAttrib4Nubv) _glVertexAttrib4Nubv = 0; if (!rhs._glVertexAttrib4Nuiv) _glVertexAttrib4Nuiv = 0; if (!rhs._glVertexAttrib4Nusv) _glVertexAttrib4Nusv = 0; if (!rhs._glVertexAttrib4bv) _glVertexAttrib4bv = 0; if (!rhs._glVertexAttrib4d) _glVertexAttrib4d = 0; if (!rhs._glVertexAttrib4dv) _glVertexAttrib4dv = 0; if (!rhs._glVertexAttrib4f) _glVertexAttrib4f = 0; if (!rhs._glVertexAttrib4fv) _glVertexAttrib4fv = 0; if (!rhs._glVertexAttrib4iv) _glVertexAttrib4iv = 0; if (!rhs._glVertexAttrib4s) _glVertexAttrib4s = 0; if (!rhs._glVertexAttrib4sv) _glVertexAttrib4sv = 0; if (!rhs._glVertexAttrib4ubv) _glVertexAttrib4ubv = 0; if (!rhs._glVertexAttrib4uiv) _glVertexAttrib4uiv = 0; if (!rhs._glVertexAttrib4usv) _glVertexAttrib4usv = 0; if (!rhs._glVertexAttribPointer) _glVertexAttribPointer = 0; if (!rhs._glGetInfoLogARB) _glGetInfoLogARB = 0; if (!rhs._glGetObjectParameterivARB) _glGetObjectParameterivARB = 0; if (!rhs._glDeleteObjectARB) _glDeleteObjectARB = 0; if (!rhs._glGetHandleARB) _glGetHandleARB = 0; } void GL2Extensions::setupGL2Extensions(unsigned int contextID) { const char* version = (const char*) glGetString( GL_VERSION ); if (!version) { osg::notify(osg::FATAL)<<"Error: OpenGL version test failed, requires valid graphics context."<= 2.0f ) || ( _isShaderObjectsSupported && _isVertexShaderSupported && _isFragmentShaderSupported && _isLanguage100Supported ); } /////////////////////////////////////////////////////////////////////////// // Static array of per-context osg::GL2Extensions instances typedef osg::buffered_value< osg::ref_ptr > BufferedExtensions; static BufferedExtensions s_extensions; GL2Extensions* GL2Extensions::Get(unsigned int contextID, bool createIfNotInitalized) { if (!s_extensions[contextID] && createIfNotInitalized) s_extensions[contextID] = new GL2Extensions(contextID); return s_extensions[contextID].get(); } void GL2Extensions::Set(unsigned int contextID, GL2Extensions* extensions) { s_extensions[contextID] = extensions; } /////////////////////////////////////////////////////////////////////////// static void NotSupported( const char* funcName ) { osg::notify(osg::WARN) <<"Error: "<= 2.0f ) { // GLSL as GL v2.0 core functionality GLint result = 0; glGetIntegerv( GL_CURRENT_PROGRAM, &result ); return static_cast(result); } else if (_glGetHandleARB) { // fallback for GLSL as GL v1.5 ARB extension #ifndef GL_PROGRAM_OBJECT_ARB #define GL_PROGRAM_OBJECT_ARB 0x8B40 #endif typedef GLuint (APIENTRY * GetHandleProc) (GLenum pname); return ((GetHandleProc)_glGetHandleARB)( GL_PROGRAM_OBJECT_ARB ); } else { NotSupported( "getCurrentProgram" ); return 0; } } bool GL2Extensions::getProgramInfoLog( GLuint program, std::string& result ) const { GLsizei bufLen = 0; // length of buffer to allocate GLsizei strLen = 0; // strlen GL actually wrote to buffer glGetProgramiv( program, GL_INFO_LOG_LENGTH, &bufLen ); if( bufLen > 1 ) { GLchar* infoLog = new GLchar[bufLen]; glGetProgramInfoLog( program, bufLen, &strLen, infoLog ); if( strLen > 0 ) result = infoLog; delete [] infoLog; } return (strLen > 0); } bool GL2Extensions::getShaderInfoLog( GLuint shader, std::string& result ) const { GLsizei bufLen = 0; // length of buffer to allocate GLsizei strLen = 0; // strlen GL actually wrote to buffer glGetShaderiv( shader, GL_INFO_LOG_LENGTH, &bufLen ); if( bufLen > 1 ) { GLchar* infoLog = new GLchar[bufLen]; glGetShaderInfoLog( shader, bufLen, &strLen, infoLog ); if( strLen > 0 ) result = infoLog; delete [] infoLog; } return (strLen > 0); } bool GL2Extensions::getAttribLocation( const char* attribName, GLuint& location ) const { // is there an active GLSL program? GLuint program = getCurrentProgram(); if( glIsProgram(program) == GL_FALSE ) return false; // has that program been successfully linked? GLint linked = GL_FALSE; glGetProgramiv( program, GL_LINK_STATUS, &linked ); if( linked == GL_FALSE ) return false; // is there such a named attribute? GLint loc = glGetAttribLocation( program, attribName ); if( loc < 0 ) return false; location = loc; return true; } /////////////////////////////////////////////////////////////////////////// // static cache of glPrograms flagged for deletion, which will actually // be deleted in the correct GL context. typedef std::list GlProgramHandleList; typedef std::map DeletedGlProgramCache; static OpenThreads::Mutex s_mutex_deletedGlProgramCache; static DeletedGlProgramCache s_deletedGlProgramCache; void Program::deleteGlProgram(unsigned int contextID, GLuint program) { if( program ) { OpenThreads::ScopedLock lock(s_mutex_deletedGlProgramCache); // add glProgram to the cache for the appropriate context. s_deletedGlProgramCache[contextID].push_back(program); } } void Program::flushDeletedGlPrograms(unsigned int contextID,double /*currentTime*/, double& availableTime) { // if no time available don't try to flush objects. if (availableTime<=0.0) return; const GL2Extensions* extensions = GL2Extensions::Get(contextID,true); if( ! extensions->isGlslSupported() ) return; const osg::Timer& timer = *osg::Timer::instance(); osg::Timer_t start_tick = timer.tick(); double elapsedTime = 0.0; { OpenThreads::ScopedLock lock(s_mutex_deletedGlProgramCache); DeletedGlProgramCache::iterator citr = s_deletedGlProgramCache.find(contextID); if( citr != s_deletedGlProgramCache.end() ) { GlProgramHandleList& pList = citr->second; for(GlProgramHandleList::iterator titr=pList.begin(); titr!=pList.end() && elapsedTimeglDeleteProgram( *titr ); titr = pList.erase( titr ); elapsedTime = timer.delta_s(start_tick,timer.tick()); } } } availableTime -= elapsedTime; } /////////////////////////////////////////////////////////////////////////// // osg::Program /////////////////////////////////////////////////////////////////////////// Program::Program() { } Program::Program(const Program& rhs, const osg::CopyOp& copyop): osg::StateAttribute(rhs, copyop) { osg::notify(osg::FATAL) << "how got here?" << std::endl; } Program::~Program() { // inform any attached Shaders that we're going away for( unsigned int i=0; i < _shaderList.size(); ++i ) { _shaderList[i]->removeProgramRef( this ); } } int Program::compare(const osg::StateAttribute& sa) const { // check the types are equal and then create the rhs variable // used by the COMPARE_StateAttribute_Paramter macro's below. COMPARE_StateAttribute_Types(Program,sa) if( _shaderList.size() < rhs._shaderList.size() ) return -1; if( rhs._shaderList.size() < _shaderList.size() ) return 1; if( getName() < rhs.getName() ) return -1; if( rhs.getName() < getName() ) return 1; ShaderList::const_iterator litr=_shaderList.begin(); ShaderList::const_iterator ritr=rhs._shaderList.begin(); for(; litr!=_shaderList.end(); ++litr,++ritr) { int result = (*litr)->compare(*(*ritr)); if (result!=0) return result; } return 0; // passed all the above comparison macro's, must be equal. } void Program::compileGLObjects( osg::State& state ) const { if( isFixedFunction() ) return; const unsigned int contextID = state.getContextID(); for( unsigned int i=0; i < _shaderList.size(); ++i ) { _shaderList[i]->compileShader( contextID ); } getPCP( contextID )->linkProgram(); } void Program::dirtyProgram() { // mark our PCPs as needing relink for( unsigned int cxt=0; cxt < _pcpList.size(); ++cxt ) { if( _pcpList[cxt].valid() ) _pcpList[cxt]->requestLink(); } } void Program::releaseGLObjects(osg::State* /*state*/) const { // TODO } bool Program::addShader( Shader* shader ) { if( !shader ) return false; // Shader can only be added once to a Program for( unsigned int i=0; i < _shaderList.size(); ++i ) { if( shader == _shaderList[i].get() ) return false; } shader->addProgramRef( this ); _shaderList.push_back( shader ); dirtyProgram(); return true; } bool Program::removeShader( Shader* shader ) { if( !shader ) return false; // Shader must exist to be removed. for( unsigned int i=0; i < _shaderList.size(); ++i ) { if( shader == _shaderList[i].get() ) { shader->removeProgramRef( this ); _shaderList[i] = 0; dirtyProgram(); return true; } } return false; } void Program::addBindAttribLocation( const std::string& name, GLuint index ) { _attribBindingList[name] = index; dirtyProgram(); } void Program::removeBindAttribLocation( const std::string& name ) { _attribBindingList.erase(name); dirtyProgram(); } void Program::apply( osg::State& state ) const { const unsigned int contextID = state.getContextID(); const GL2Extensions* extensions = GL2Extensions::Get(contextID,true); if( ! extensions->isGlslSupported() ) return; if( isFixedFunction() ) { extensions->glUseProgram( 0 ); state.setLastAppliedProgramObject(0); return; } PerContextProgram* pcp = getPCP( contextID ); if( pcp->needsLink() ) compileGLObjects( state ); if( pcp->isLinked() ) { // for shader debugging: to minimize performance impact, // optionally validate based on notify level. // TODO: enable this using notify level, or perhaps its own getenv()? if( osg::isNotifyEnabled(osg::INFO) ) pcp->validateProgram(); pcp->useProgram(); state.setLastAppliedProgramObject(pcp); } else { // program not usable, fallback to fixed function. extensions->glUseProgram( 0 ); state.setLastAppliedProgramObject(0); } } Program::PerContextProgram* Program::getPCP(unsigned int contextID) const { if( ! _pcpList[contextID].valid() ) { _pcpList[contextID] = new PerContextProgram( this, contextID ); // attach all PCSs to this new PCP for( unsigned int i=0; i < _shaderList.size(); ++i ) { _shaderList[i]->attachShader( contextID, _pcpList[contextID]->getHandle() ); } } return _pcpList[contextID].get(); } bool Program::isFixedFunction() const { // A Program object having no attached Shaders is a special case: // it indicates that programmable shading is to be disabled, // and thus use GL 1.x "fixed functionality" rendering. return _shaderList.empty(); } bool Program::getGlProgramInfoLog(unsigned int contextID, std::string& log) const { return getPCP( contextID )->getInfoLog( log ); } const Program::NameInfoMap& Program::getActiveUniforms(unsigned int contextID) const { return getPCP( contextID )->getActiveUniforms(); } const Program::NameInfoMap& Program::getActiveAttribs(unsigned int contextID) const { return getPCP( contextID )->getActiveAttribs(); } /////////////////////////////////////////////////////////////////////////// // osg::Program::PerContextProgram // PCP is an OSG abstraction of the per-context glProgram /////////////////////////////////////////////////////////////////////////// Program::PerContextProgram::PerContextProgram(const Program* program, unsigned int contextID ) : osg::Referenced(), _contextID( contextID ) { _program = program; _extensions = GL2Extensions::Get( _contextID, true ); _glProgramHandle = _extensions->glCreateProgram(); requestLink(); } Program::PerContextProgram::~PerContextProgram() { Program::deleteGlProgram( _contextID, _glProgramHandle ); } void Program::PerContextProgram::requestLink() { _needsLink = true; _isLinked = false; } void Program::PerContextProgram::linkProgram() { if( ! _needsLink ) return; _needsLink = false; osg::notify(osg::INFO) << "Linking osg::Program \"" << _program->getName() << "\"" << " id=" << _glProgramHandle << " contextID=" << _contextID << std::endl; _uniformInfoMap.clear(); _attribInfoMap.clear(); _lastAppliedUniformList.clear(); // set any explicit vertex attribute bindings const AttribBindingList& bindlist = _program->getAttribBindingList(); for( AttribBindingList::const_iterator itr = bindlist.begin(); itr != bindlist.end(); ++itr ) { _extensions->glBindAttribLocation( _glProgramHandle, itr->second, 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::notify(osg::WARN) << "glLinkProgram \""<< _program->getName() << "\" FAILED" << std::endl; std::string infoLog; if( getInfoLog(infoLog) ) { osg::notify(osg::WARN) << "Program \""<< _program->getName() << "\" " "infolog:\n" << infoLog << std::endl; } return; } else { std::string infoLog; if( getInfoLog(infoLog) ) { osg::notify(osg::INFO) << "Program \""<< _program->getName() << "\" "<< "link succeded, infolog:\n" << infoLog << std::endl; } } // build _uniformInfoMap GLint numUniforms = 0; GLsizei maxLen = 0; _extensions->glGetProgramiv( _glProgramHandle, GL_ACTIVE_UNIFORMS, &numUniforms ); _extensions->glGetProgramiv( _glProgramHandle, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxLen ); if( (numUniforms > 0) && (maxLen > 1) ) { GLint size = 0; GLenum type = 0; GLchar* name = new GLchar[maxLen]; for( GLint i = 0; i < numUniforms; ++i ) { _extensions->glGetActiveUniform( _glProgramHandle, i, maxLen, 0, &size, &type, name ); GLint loc = _extensions->glGetUniformLocation( _glProgramHandle, name ); if( loc != -1 ) { _uniformInfoMap[name] = std::pair(loc,type); osg::notify(osg::INFO) << "\tUniform \"" << name << "\"" << " loc="<< loc << " type=" << Uniform::getTypename((Uniform::Type)type) << std::endl; } } delete [] name; } // build _attribInfoMap GLint numAttrib = 0; _extensions->glGetProgramiv( _glProgramHandle, GL_ACTIVE_ATTRIBUTES, &numAttrib ); _extensions->glGetProgramiv( _glProgramHandle, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxLen ); if( (numAttrib > 0) && (maxLen > 1) ) { GLint size = 0; GLenum type = 0; GLchar* name = new GLchar[maxLen]; for( GLint i = 0; i < numAttrib; ++i ) { _extensions->glGetActiveAttrib( _glProgramHandle, i, maxLen, 0, &size, &type, name ); GLint loc = _extensions->glGetAttribLocation( _glProgramHandle, name ); if( loc != -1 ) { _attribInfoMap[name] = std::pair(loc,type); osg::notify(osg::INFO) << "\tAttrib \"" << name << "\"" << " loc=" << loc << std::endl; } } delete [] name; } osg::notify(osg::INFO) << std::endl; } void Program::PerContextProgram::validateProgram() { GLint validated = GL_FALSE; _extensions->glValidateProgram( _glProgramHandle ); _extensions->glGetProgramiv( _glProgramHandle, GL_VALIDATE_STATUS, &validated ); if( validated == GL_TRUE) return; osg::notify(osg::INFO) << "glValidateProgram FAILED \"" << _program->getName() << "\"" << " id=" << _glProgramHandle << " contextID=" << _contextID << std::endl; std::string infoLog; if( getInfoLog(infoLog) ) osg::notify(osg::INFO) << "infolog:\n" << infoLog << std::endl; osg::notify(osg::INFO) << std::endl; } bool Program::PerContextProgram::getInfoLog( std::string& infoLog ) const { return _extensions->getProgramInfoLog( _glProgramHandle, infoLog ); } void Program::PerContextProgram::useProgram() const { _extensions->glUseProgram( _glProgramHandle ); } /*EOF*/