From Mike Weiblen,

"updates for GLSL core integration:
Code compiles and runs on win32.
Basic functionality of Program and Shader in place.
Program derived from StateAttribute.
Uniform value propagation is not yet functional (in development)
Includes some patches by Nathan Cournia.
includes example testcase to demo use of new classes."
This commit is contained in:
Robert Osfield
2005-03-24 09:37:45 +00:00
parent 2ab78cfe38
commit 7883574d28
9 changed files with 492 additions and 314 deletions

View File

@@ -1,5 +1,6 @@
/* -*-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
@@ -11,7 +12,7 @@
*/
/* file: include/osg/Program
* author: Mike Weiblen 2005-02-20
* author: Mike Weiblen 2005-03-23
*/
// NOTICE: This code is CLOSED during construction and/or renovation!
@@ -24,22 +25,20 @@
#ifndef OSG_PROGRAM
#define OSG_PROGRAM 1
#include <osg/buffered_value>
#include <osg/ref_ptr>
#include <osg/Vec2>
#include <osg/Vec3>
#include <osg/Vec4>
#include <osg/Referenced>
#include <osg/GL>
#include <osg/Uniform>
#include <string>
#include <vector>
#include <osg/buffered_value>
#include <osg/ref_ptr>
#include <osg/Referenced>
#include <osg/GL>
#include <osg/Uniform>
#include <osg/StateAttribute>
namespace osg {
class State;
class Shader;
class SG_EXPORT GL2Extensions : public osg::Referenced
{
@@ -293,13 +292,6 @@ class SG_EXPORT GL2Extensions : public osg::Referenced
void* _glGetHandleARB;
};
class Program;
typedef osg::ref_ptr<Program> ProgramPtr;
class Shader;
typedef osg::ref_ptr<Shader> ShaderPtr;
typedef std::vector< ShaderPtr > ShaderList;
///////////////////////////////////////////////////////////////////////////
/** osg::Program is an application-level abstraction of an OpenGL glProgram.
* It is an osg::StateAttribute that, when applied, will activate a
@@ -307,12 +299,12 @@ typedef std::vector< ShaderPtr > ShaderList;
* osg::Shaders containing the actual shader source code are
* attached to a Program, which will then manage the compilation,
* linking, and activation of the GLSL program.
* Program will automatically manage per-context instancing of the
* OpenGL objects, if that is necessary for a particular display
* osg::Program will automatically manage per-context instancing of the
* OpenGL glPrograms, if that is necessary for a particular display
* configuration.
*/
class SG_EXPORT Program : public osg::Object
class SG_EXPORT Program : public osg::StateAttribute
{
public:
Program();
@@ -320,10 +312,10 @@ class SG_EXPORT Program : public osg::Object
/** Copy constructor using CopyOp to manage deep vs shallow copy.*/
Program(const Program& rhs, const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY);
META_Object(osg, Program);
META_StateAttribute(osg, Program, PROGRAM);
/** return -1 if *this < *rhs, 0 if *this==*rhs, 1 if *this>*rhs.*/
virtual int compare(const osg::Program& sa) const;
virtual int compare(const osg::StateAttribute& sa) const;
/** If enabled, activate our program in the GL pipeline,
* performing any rebuild operations that might be pending. */
@@ -336,30 +328,30 @@ class SG_EXPORT Program : public osg::Object
State object pointer NULL.*/
virtual void releaseGLObjects(osg::State* state=0) const;
// data access methods.
/** Mark us as "dirty" and in need of relinking. */
/** Mark our PCSOs as needing relink */
void dirtyProgram();
/** Mark our attached Shaders as "dirty" and in need of recompilation. */
void dirtyShaders();
/** Attach an osg::Shader to this osg::Program.
* Mark Program as needing relink. Return true for success */
bool addShader( Shader* shader );
/** Attach a Shader to this Program */
void addShader( Shader* shader );
/** Remove osg::Shader from this osg::Program.
* Mark Program as needing relink. Return true for success */
bool removeShader( Shader* shader );
/** Mark internal GL glProgram for deletion.
* Deletion requests are queued until they can be executed
* in the proper GL context. */
static void deleteProgram(unsigned int contextID, GLuint program);
/** */
void bindAttribLocation( GLuint index, const char* name );
/** flush all the cached glPrograms which need to be deleted
* in the OpenGL context related to contextID.*/
static void flushDeletedGlslObjects(unsigned int contextID,double currentTime, double& availableTime);
/** Return true if this Program represents "fixed-functionality" rendering */
bool isFixedFunction() const;
/** An annotation/comment for use by the application */
void setComment( const std::string& comment ) { _comment = comment; }
void setComment( const char* comment ) { _comment = comment; }
const std::string& getComment() const { return _comment; }
/** Query InfoLog from a glProgram */
void getGlProgramInfoLog(unsigned int contextID, std::string& log) const;
/** A name for use by the application */
void setName( const std::string& name ) { _name = name; }
void setName( const char* name ) { _name = name; }
const std::string& getName() const { return _name; }
/** should Uniform values be tested to avoid redundant setting? */
void setAvoidRedundantUniformSetting( bool flag ) { _avoidRedundantUniformSetting = flag; }
@@ -367,6 +359,15 @@ class SG_EXPORT Program : public osg::Object
// TODO glBindAttribLocation
/** Mark internal glProgram for deletion.
* Deletion requests are queued until they can be executed
* in the proper GL context. */
static void deleteGlProgram(unsigned int contextID, GLuint program);
/** flush all the cached glPrograms which need to be deleted
* in the OpenGL context related to contextID.*/
static void flushDeletedGlPrograms(unsigned int contextID,double currentTime, double& availableTime);
protected:
/** An OSG-internal encapsulation of glProgram's active uniforms */
@@ -389,25 +390,26 @@ class SG_EXPORT Program : public osg::Object
protected:
/** PCPO is an OSG-internal encapsulation of glPrograms per-GL context. */
class PerContextProgObj : public osg::Referenced
/** PerContextProgram (PCP) is an OSG-internal encapsulation of glPrograms per-GL context. */
class PerContextProgram : public osg::Referenced
{
public:
PerContextProgObj(const Program* program, unsigned int contextID);
PerContextProgObj(const PerContextProgObj& rhs);
PerContextProgram(const Program* program, unsigned int contextID);
const GLuint getHandle() {return _glProgramHandle;}
GLuint getHandle() const {return _glProgramHandle;}
bool isDirty() const {return _dirty;}
void markAsDirty();
void requestLink();
void linkProgram();
bool needsLink() const {return _needsLink;}
bool isLinked() const {return _isLinked;}
void getInfoLog( std::string& infoLog ) const;
void useProgram() const;
void applyUniforms( osg::State& state ) const;
protected: /*methods*/
PerContextProgObj();
~PerContextProgObj();
~PerContextProgram();
protected: /*data*/
/** Pointer to our parent Program */
@@ -416,30 +418,36 @@ class SG_EXPORT Program : public osg::Object
osg::ref_ptr<GL2Extensions> _extensions;
/** Handle to the actual OpenGL glProgram */
GLuint _glProgramHandle;
/** Do we need to be linked? */
bool _dirty;
/** Queue of UniformValues awaiting assignment */
/** Does our glProgram need to be linked? */
bool _needsLink;
/** Is our glProgram successfully linked? */
bool _isLinked;
const unsigned int _contextID;
/** List of PCPO's active uniforms */
/** List of PCP's active uniforms */
ActiveUniformList _activeUniformList;
private:
PerContextProgram(); // disallowed
PerContextProgram(const PerContextProgram&); // disallowed
PerContextProgram& operator=(const PerContextProgram&); // disallowed
};
protected: /*methods*/
virtual ~Program();
/** Get the PCPO for a particular GL context */
PerContextProgObj* getPCPO(unsigned int contextID) const;
/** Get the PCP for a particular GL context */
PerContextProgram* getPCP(unsigned int contextID) const;
protected: /*data*/
bool _avoidRedundantUniformSetting;
std::string _comment;
std::string _name;
typedef std::vector< ref_ptr<Shader> > ShaderList;
ShaderList _shaderList;
mutable osg::buffered_value< osg::ref_ptr<PerContextProgObj> > _pcpoList;
mutable osg::buffered_value< osg::ref_ptr<PerContextProgram> > _pcpList;
private:
const Program& operator=(const Program&);
Program& operator=(const Program&); // disallowed
};
}
#endif

View File

@@ -1,5 +1,6 @@
/* -*-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
@@ -10,8 +11,8 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
/* file: include/osg/Program
* author: Mike Weiblen 2005-02-20
/* file: include/osg/Shader
* author: Mike Weiblen 2005-03-23
*/
// NOTICE: This code is CLOSED during construction and/or renovation!
@@ -24,6 +25,9 @@
#ifndef OSG_SHADER
#define OSG_SHADER 1
#include <set>
#include <string>
#include <osg/Program>
namespace osg {
@@ -32,7 +36,7 @@ namespace osg {
/** osg::Shader is an application-level abstraction of an OpenGL glShader.
* It is a container to load the shader source code text and manage its
* compilation.
* A Shader may be attached to more than one osg::Program.
* An osg::Shader may be attached to more than one osg::Program.
* Shader will automatically manage per-context instancing of the
* internal objects, if that is necessary for a particular display
* configuration.
@@ -44,7 +48,7 @@ class SG_EXPORT Shader : public osg::Object
enum Type {
VERTEX = GL_VERTEX_SHADER,
FRAGMENT = GL_FRAGMENT_SHADER,
FRAGMENT = GL_FRAGMENT_SHADER
};
Shader( Type type, const char* sourceText = 0 );
@@ -52,6 +56,8 @@ class SG_EXPORT Shader : public osg::Object
/** Copy constructor using CopyOp to manage deep vs shallow copy.*/
Shader(const Shader& rhs, const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY);
META_Object(osg, Shader); // see note in Shader.cpp Shader()
int compare(const Shader& rhs) const;
// data access methods.
@@ -71,80 +77,97 @@ class SG_EXPORT Shader : public osg::Object
/** Get the Shader type as a descriptive string. */
const char* getTypename() const;
/** Mark us as "dirty" and in need of recompilation */
/** Mark our PCSs as needing recompilation.
* Also mark Programs that depend on us as needing relink */
void dirtyShader();
/** Mark internal GL glShader for deletion.
* Deletion requests are queued until they can be executed
* in the proper GL context. */
static void deleteShader(unsigned int contextID, GLuint shader);
/** Perform a recompilation of all our PCSOs */
/** If needed, compile the PCS's glShader */
void compileShader(unsigned int contextID) const;
/** For a given GL context, attach a glShader to a glProgram */
void attachShader(unsigned int contextID, GLuint program) const;
/** An annotation/comment for use by the application */
void setComment( const std::string& comment ) { _comment = comment; }
void setComment( const char* comment ) { _comment = comment; }
const std::string& getComment() const { return _comment; };
/** Query InfoLog from a glShader */
void getGlShaderInfoLog(unsigned int contextID, std::string& log) const;
/** A name for use by the application */
void setName( const std::string& name ) { _name = name; }
void setName( const char* name ) { _name = name; }
const std::string& getName() const { return _name; };
/** Mark internal glShader for deletion.
* Deletion requests are queued tuntil they can be executed
* in the proper GL context. */
static void deleteGlShader(unsigned int contextID, GLuint shader);
/** flush all the cached glShaders which need to be deleted
* in the OpenGL context related to contextID.*/
static void flushDeletedGlShaders(unsigned int contextID,double currentTime, double& availableTime);
protected:
/** PCSO is an OSG-internal encapsulation of glShader per-GL context. */
class PerContextShaderObj : public osg::Referenced
/** PerContextShader (PCS) is an OSG-internal encapsulation of glShader per-GL context. */
class PerContextShader : public osg::Referenced
{
public:
PerContextShaderObj(const Shader* shader, unsigned int contextID);
PerContextShaderObj(const PerContextShaderObj& rhs);
PerContextShader(const Shader* shader, unsigned int contextID);
const GLuint getHandle() {return _glShaderHandle;}
GLuint getHandle() const {return _glShaderHandle;}
bool isDirty() const {return _dirty;}
void markAsDirty() {_dirty = true; }
void requestCompile();
void compileShader();
void getInfoLog( std::string& infoLog ) const;
/** Attach our glShader to a glProgram */
void attachShader(GLuint program) const;
/** Detach our glShader from a glProgram */
void detachShader(GLuint program) const;
protected: /*methods*/
PerContextShaderObj();
~PerContextShaderObj();
~PerContextShader();
protected: /*data*/
/** Pointer to our parent Shader */
/** Pointer to our parent osg::Shader */
const Shader* _shader;
/** Pointer to this context's extension functions. */
osg::ref_ptr<GL2Extensions> _extensions;
osg::ref_ptr<osg::GL2Extensions> _extensions;
/** Handle to the actual glShader. */
GLuint _glShaderHandle;
/** Do we need to be recompiled? */
bool _dirty;
/** Does our glShader need to be recompiled? */
bool _needsCompile;
/** Is our glShader successfully compiled? */
bool _isCompiled;
const unsigned int _contextID;
private:
PerContextShader(); // disallowed
PerContextShader(const PerContextShader&); // disallowed
PerContextShader& operator=(const PerContextShader&); // disallowed
};
protected: /*methods*/
Shader(); // undesired, temporarily required by META_Object.
virtual ~Shader();
PerContextShaderObj* getPCSO(unsigned int contextID) const;
friend void Program::addShader( Shader* shader ); // to access addProgObjRef()
void addProgObjRef( Program* program );
PerContextShader* getPCS(unsigned int contextID) const;
friend class Program;
bool addProgramRef( Program* program );
bool removeProgramRef( Program* program );
protected: /*data*/
const Type _type;
std::string _comment;
std::string _name;
std::string _shaderSource;
/** list of Programs that this Shader is attached to */
std::vector< ProgramPtr > _programList;
mutable osg::buffered_value< osg::ref_ptr<PerContextShaderObj> > _pcsoList;
/** osg::Programs that this osg::Shader is attached to */
typedef std::set< Program* > ProgramSet;
ProgramSet _programSet;
mutable osg::buffered_value< osg::ref_ptr<PerContextShader> > _pcsList;
private:
Shader(); // disallowed
Shader& operator=(const Shader&); // disallowed
};
}
#endif

View File

@@ -184,6 +184,9 @@ class SG_EXPORT StateAttribute : public Object
// osgNVParse
OSGNVPARSE_PROGRAM_PARSER,
/// core GLSL support
PROGRAM
};
/** Simple pairing between an attribute type and the member within that attribute type group.*/

View File

@@ -259,31 +259,31 @@ class SG_EXPORT StateSet : public Object
/** Simple pairing between an attribute and its override flag.*/
/** Simple pairing between a Uniform and its override flag.*/
typedef std::pair<ref_ptr<Uniform>,StateAttribute::OverrideValue> RefUniformPair;
/** a container to map <StateAttribyte::Types,Member> to their respective RefAttributePair.*/
/** a container to map Uniform name to its respective RefUniformPair.*/
typedef std::map<std::string,RefUniformPair> UniformList;
/** Set this StateSet to contain specified uniform and override flag.*/
void setUniform(Uniform* uniform, StateAttribute::OverrideValue value=StateAttribute::OFF);
void addUniform(Uniform* uniform, StateAttribute::OverrideValue value=StateAttribute::ON);
/** remove uniform of specified name from StateSet.*/
void removeUniform(const std::string& name);
/** remove attribute from StateSet.*/
void removeUniform(Uniform* attribute);
/** remove Uniform from StateSet.*/
void removeUniform(Uniform* uniform);
/** Get Uniform for specified name.
* Returns NULL if no matching uniform is contained within StateSet.*/
* Returns NULL if no matching Uniform is contained within StateSet.*/
Uniform* getUniform(const std::string& name);
/** Get const Uniform for specified name.
* Returns NULL if no matching uniform is contained within StateSet.*/
* Returns NULL if no matching Uniform is contained within StateSet.*/
const Uniform* getUniform(const std::string& name) const;
/** Get specified RefUniformPair for specified type.
* Returns NULL if no type is contained within StateSet.*/
/** Get specified RefUniformPair for specified Uniform name.
* Returns NULL if no Uniform is contained within StateSet.*/
const RefUniformPair* getUniformPair(const std::string& name) const;
/** set the list of all Uniforms contained in this StateSet.*/

View File

@@ -11,7 +11,7 @@
*/
/* file: include/osg/Uniform
* author: Mike Weiblen 2005-02-20
* author: Mike Weiblen 2005-03-23
*/
// NOTICE: This code is CLOSED during construction and/or renovation!
@@ -190,13 +190,13 @@ class SG_EXPORT Uniform : public Object
//TODO void set( const osg::Matrix3& m3 );
void set( const osg::Matrix& m4 );
void set( int i );
//TODO void set( int i0, int i1 );
//TODO void set( int i0, int i1, int i2 );
//TODO void set( int i0, int i1, int i2, int i3 );
//TODO void set( bool b );
//TODO void set( bool b0, bool b1 );
//TODO void set( bool b0, bool b1, bool b2 );
//TODO void set( bool b0, bool b1, bool b2, bool b3 );
void set( int i0, int i1 );
void set( int i0, int i1, int i2 );
void set( int i0, int i1, int i2, int i3 );
void set( bool b );
void set( bool b0, bool b1 );
void set( bool b0, bool b1, bool b2 );
void set( bool b0, bool b1, bool b2, bool b3 );
protected:
@@ -231,21 +231,21 @@ class SG_EXPORT Uniform : public Object
Uniform( const char* name, Value::Type type );
/** convenient construction w/ assignment */
Uniform( const char* name, float f );
explicit Uniform( const char* name, float f );
explicit Uniform( const char* name, int i );
explicit Uniform( const char* name, bool b );
Uniform( const char* name, const osg::Vec2& v2 );
Uniform( const char* name, const osg::Vec3& v3 );
Uniform( const char* name, const osg::Vec4& v4 );
//TODO Uniform( const char* name, const osg::Matrix2& m2 );
//TODO Uniform( const char* name, const osg::Matrix3& m3 );
Uniform( const char* name, const osg::Matrix& m4 );
Uniform( const char* name, int i );
//TODO Uniform( const char* name, int i0, int i1 );
//TODO Uniform( const char* name, int i0, int i1, int i2 );
//TODO Uniform( const char* name, int i0, int i1, int i2, int i3 );
//TODO Uniform( const char* name, bool b );
//TODO Uniform( const char* name, bool b0, bool b1 );
//TODO Uniform( const char* name, bool b0, bool b1, bool b2 );
//TODO Uniform( const char* name, bool b0, bool b1, bool b2, bool b3 );
Uniform( const char* name, int i0, int i1 );
Uniform( const char* name, int i0, int i1, int i2 );
Uniform( const char* name, int i0, int i1, int i2, int i3 );
Uniform( const char* name, bool b0, bool b1 );
Uniform( const char* name, bool b0, bool b1, bool b2 );
Uniform( const char* name, bool b0, bool b1, bool b2, bool b3 );
/** Copy constructor using CopyOp to manage deep vs shallow copy. */
Uniform(const Uniform& gu,const CopyOp& copyop=CopyOp::SHALLOW_COPY);
@@ -268,20 +268,20 @@ class SG_EXPORT Uniform : public Object
/** assignment */
bool set( float f );
bool set( int i );
bool set( bool b );
bool set( const osg::Vec2& v2 );
bool set( const osg::Vec3& v3 );
bool set( const osg::Vec4& v4 );
//TODO bool set( const osg::Matrix2& m2 );
//TODO bool set( const osg::Matrix3& m3 );
bool set( const osg::Matrix& m4 );
bool set( int i );
//TODO bool set( int i0, int i1 );
//TODO bool set( int i0, int i1, int i2 );
//TODO bool set( int i0, int i1, int i2, int i3 );
//TODO bool set( bool b );
//TODO bool set( bool b0, bool b1 );
//TODO bool set( bool b0, bool b1, bool b2 );
//TODO bool set( bool b0, bool b1, bool b2, bool b3 );
bool set( int i0, int i1 );
bool set( int i0, int i1, int i2 );
bool set( int i0, int i1, int i2, int i3 );
bool set( bool b0, bool b1 );
bool set( bool b0, bool b1, bool b2 );
bool set( bool b0, bool b1, bool b2, bool b3 );
protected:
virtual ~Uniform() {}

View File

@@ -1,5 +1,6 @@
/* -*-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
@@ -12,7 +13,7 @@
*/
/* file: src/osg/Program.cpp
* author: Mike Weiblen 2005-02-20
* author: Mike Weiblen 2005-03-23
*/
// NOTICE: This code is CLOSED during construction and/or renovation!
@@ -28,11 +29,11 @@
#include <osg/Notify>
#include <osg/State>
#include <osg/Timer>
#include <osg/FrameStamp>
#include <osg/buffered_value>
#include <osg/ref_ptr>
#include <osg/Program>
#include <osg/Shader>
#include <osg/Uniform>
#include <osg/GLExtensions>
#include <OpenThreads/ScopedLock>
@@ -41,15 +42,7 @@
using namespace osg;
///////////////////////////////////////////////////////////////////////////
// static cache of GL objects flagged for deletion, which will actually
// be deleted in the correct GL context.
typedef std::list<GLuint> GlProgramHandleList;
typedef std::map<unsigned int, GlProgramHandleList> DeletedGlProgramCache;
static OpenThreads::Mutex s_mutex_deletedGL2ObjectCache;
static DeletedGlProgramCache s_deletedGlProgramCache;
// Extension function pointers for OpenGL v2.0
GL2Extensions::GL2Extensions()
{
@@ -1855,19 +1848,28 @@ bool GL2Extensions::getShaderInfoLog( GLuint shader, std::string& result ) const
return (strLen > 0);
}
///////////////////////////////////////////////////////////////////////////
// static cache of glPrograms flagged for deletion, which will actually
// be deleted in the correct GL context.
void Program::deleteProgram(unsigned int contextID, GLuint program)
typedef std::list<GLuint> GlProgramHandleList;
typedef std::map<unsigned int, GlProgramHandleList> DeletedGlProgramCache;
static OpenThreads::Mutex s_mutex_deletedGlProgramCache;
static DeletedGlProgramCache s_deletedGlProgramCache;
void Program::deleteGlProgram(unsigned int contextID, GLuint program)
{
if( program )
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_mutex_deletedGL2ObjectCache);
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_mutex_deletedGlProgramCache);
// add program to the cache for the appropriate context.
// add glProgram to the cache for the appropriate context.
s_deletedGlProgramCache[contextID].push_back(program);
}
}
void Program::flushDeletedGlslObjects(unsigned int contextID,double /*currentTime*/, double& availableTime)
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;
@@ -1880,7 +1882,7 @@ void Program::flushDeletedGlslObjects(unsigned int contextID,double /*currentTim
double elapsedTime = 0.0;
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_mutex_deletedGL2ObjectCache);
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_mutex_deletedGlProgramCache);
DeletedGlProgramCache::iterator citr = s_deletedGlProgramCache.find(contextID);
if( citr != s_deletedGlProgramCache.end() )
@@ -1912,7 +1914,7 @@ Program::Program()
Program::Program(const Program& rhs, const osg::CopyOp& copyop):
osg::Object(rhs, copyop)
osg::StateAttribute(rhs, copyop)
{
osg::notify(osg::FATAL) << "how got here?" << std::endl;
}
@@ -1920,19 +1922,15 @@ Program::Program(const Program& rhs, const osg::CopyOp& copyop):
Program::~Program()
{
for( unsigned int cxt=0; cxt < _pcpoList.size(); ++cxt )
// inform any attached Shaders that we're going away
for( unsigned int i=0; i < _shaderList.size(); ++i )
{
if( ! _pcpoList[cxt] ) continue;
PerContextProgObj* pcpo = _pcpoList[cxt].get();
deleteProgram( cxt, pcpo->getHandle() );
// TODO add shader objects to delete list.
_pcpoList[cxt] = 0;
_shaderList[i]->removeProgramRef( this );
}
}
int Program::compare(const osg::Program& sa) const
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.
@@ -1941,8 +1939,8 @@ int Program::compare(const osg::Program& sa) const
if( _shaderList.size() < rhs._shaderList.size() ) return -1;
if( rhs._shaderList.size() < _shaderList.size() ) return 1;
if( getComment() < rhs.getComment() ) return -1;
if( rhs.getComment() < getComment() ) 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();
@@ -1954,73 +1952,79 @@ int Program::compare(const osg::Program& sa) const
if (result!=0) return result;
}
// TODO should Program comparison depend on the values of
// its uniforms? I'd assert not.
return 0; // passed all the above comparison macro's, must be equal.
}
void Program::compileGLObjects( osg::State& state ) const
{
if( _shaderList.empty() ) return;
if( isFixedFunction() ) return;
const unsigned int contextID = state.getContextID();
const GL2Extensions* extensions = GL2Extensions::Get(contextID,true);
if( ! extensions->isGlslSupported() )
{
osg::notify(osg::WARN) << "GLSL not supported by OpenGL driver" << std::endl;
return;
}
PerContextProgObj* pcpo = getPCPO( contextID );
for( unsigned int i=0; i < _shaderList.size() ; ++i )
for( unsigned int i=0; i < _shaderList.size(); ++i )
{
_shaderList[i]->compileShader( contextID );
}
pcpo->linkProgram();
// TODO pcpo->releaseActiveUniformList();
// TODO pcpo->buildActiveUniformList;
// TODO regenerate pcpo->_activeAttribList;
getPCP( contextID )->linkProgram();
}
void Program::dirtyProgram()
{
// mark all PCPOs as needing a relink
for( unsigned int cxt=0; cxt < _pcpoList.size(); ++cxt )
// mark our PCPs as needing relink
for( unsigned int cxt=0; cxt < _pcpList.size(); ++cxt )
{
if( ! _pcpoList[cxt] ) continue;
PerContextProgObj* pcpo = _pcpoList[cxt].get();
pcpo->markAsDirty();
if( _pcpList[cxt].valid() ) _pcpList[cxt]->requestLink();
}
}
void Program::dirtyShaders()
{
// mark all attached Shaders as needing a rebuild
for( unsigned int i=0; i < _shaderList.size() ; ++i )
{
_shaderList[i]->dirtyShader();
}
}
void Program::releaseGLObjects(osg::State* state) const
{
if (!state) const_cast<Program*>(this)->dirtyShaders();
else
{
unsigned int contextID = state->getContextID();
const_cast<Program*>(this)->_shaderList[contextID]->dirtyShader();
}
// TODO
}
void Program::addShader( Shader* shader )
bool Program::addShader( Shader* shader )
{
// 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 );
shader->addProgObjRef( this );
dirtyProgram();
return true;
}
bool Program::removeShader( Shader* shader )
{
// 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::bindAttribLocation( GLuint index, const char* name )
{
// TODO add to binding list
dirtyProgram();
}
@@ -2031,44 +2035,55 @@ void Program::apply( osg::State& state ) const
const GL2Extensions* extensions = GL2Extensions::Get(contextID,true);
if( ! extensions->isGlslSupported() ) return;
// 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.
if( _shaderList.empty() )
if( isFixedFunction() )
{
extensions->glUseProgram( 0 );
return;
}
PerContextProgObj* pcpo = getPCPO( contextID );
if( pcpo->isDirty() ) compileGLObjects( state );
if( pcpo->isDirty() )
PerContextProgram* pcp = getPCP( contextID );
if( pcp->needsLink() ) compileGLObjects( state );
if( pcp->isLinked() )
{
// _still_ dirty, something went wrong
extensions->glUseProgram( 0 );
pcp->useProgram();
pcp->applyUniforms( state );
}
else
{
pcpo->useProgram();
pcpo->applyUniforms( state );
// program not usable, fallback to fixed function.
extensions->glUseProgram( 0 );
}
}
Program::PerContextProgObj* Program::getPCPO(unsigned int contextID) const
Program::PerContextProgram* Program::getPCP(unsigned int contextID) const
{
if( ! _pcpoList[contextID].valid() )
if( ! _pcpList[contextID].valid() )
{
_pcpoList[contextID] = new PerContextProgObj( this, contextID );
_pcpList[contextID] = new PerContextProgram( this, contextID );
// attach all PCSOs to this new PCPO
for( unsigned int i=0; i < _shaderList.size() ; ++i )
// attach all PCSs to this new PCP
for( unsigned int i=0; i < _shaderList.size(); ++i )
{
_shaderList[i]->attachShader( contextID, _pcpoList[contextID]->getHandle() );
_shaderList[i]->attachShader( contextID, _pcpList[contextID]->getHandle() );
}
}
return _pcpoList[contextID].get();
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();
}
void Program::getGlProgramInfoLog(unsigned int contextID, std::string& log) const
{
getPCP( contextID )->getInfoLog( log );
}
@@ -2083,67 +2098,69 @@ Program::ActiveUniform::ActiveUniform( const GLchar* name, GLenum type ) :
///////////////////////////////////////////////////////////////////////////
// osg::Program::PerContextProgObj
// PCPO is an OSG abstraction of the per-context glProgram
// osg::Program::PerContextProgram
// PCP is an OSG abstraction of the per-context glProgram
///////////////////////////////////////////////////////////////////////////
Program::PerContextProgObj::PerContextProgObj(const Program* program, unsigned int contextID ) :
Program::PerContextProgram::PerContextProgram(const Program* program, unsigned int contextID ) :
osg::Referenced(),
_contextID( contextID )
{
_program = program;
_extensions = GL2Extensions::Get( _contextID, true );
_glProgramHandle = _extensions->glCreateProgram();
markAsDirty();
requestLink();
}
Program::PerContextProgObj::PerContextProgObj(const PerContextProgObj& rhs) :
osg::Referenced(),
_contextID( rhs._contextID )
{
_program = rhs._program;
_extensions = rhs._extensions;
_glProgramHandle = rhs._glProgramHandle ;
_dirty = rhs._dirty;
}
Program::PerContextProgObj::~PerContextProgObj()
Program::PerContextProgram::~PerContextProgram()
{
Program::deleteGlProgram( _contextID, _glProgramHandle );
}
void Program::PerContextProgObj::markAsDirty()
void Program::PerContextProgram::requestLink()
{
// TODO releaseActiveUniformList();
_dirty = true;
_needsLink = true;
_isLinked = false;
}
void Program::PerContextProgObj::linkProgram()
void Program::PerContextProgram::linkProgram()
{
if( ! _needsLink ) return;
_needsLink = false;
// TODO for( each itr in binding list )
// {
// _extensions->glBindAttribLocation( _glProgramHandle, index, name );
// }
GLint linked;
_extensions->glLinkProgram( _glProgramHandle );
_extensions->glGetProgramiv( _glProgramHandle, GL_LINK_STATUS, &linked );
_dirty = (linked == 0);
if( _dirty )
_isLinked = (linked == GL_TRUE);
if( ! _isLinked )
{
// _still_ dirty, something went wrong
// link failed
std::string infoLog;
_extensions->getProgramInfoLog( _glProgramHandle, infoLog );
getInfoLog( infoLog );
osg::notify(osg::WARN) << "glLinkProgram FAILED:\n" << infoLog << std::endl;
}
}
void Program::PerContextProgram::getInfoLog( std::string& infoLog ) const
{
_extensions->getProgramInfoLog( _glProgramHandle, infoLog );
}
void Program::PerContextProgObj::useProgram() const
void Program::PerContextProgram::useProgram() const
{
_extensions->glUseProgram( _glProgramHandle );
}
void Program::PerContextProgObj::applyUniforms( osg::State& /*state*/ ) const
void Program::PerContextProgram::applyUniforms( osg::State& /*state*/ ) const
{
bool uniformDoesNeedSetting = true;
@@ -2161,3 +2178,5 @@ void Program::PerContextProgObj::applyUniforms( osg::State& /*state*/ ) const
// TODO set the uniform value on the currently active glProgram.
}
}
/*EOF*/

View File

@@ -1,5 +1,6 @@
/* -*-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
@@ -11,8 +12,8 @@
*
*/
/* file: src/osg/Program.cpp
* author: Mike Weiblen 2005-02-20
/* file: src/osg/Shader.cpp
* author: Mike Weiblen 2005-03-23
*/
// NOTICE: This code is CLOSED during construction and/or renovation!
@@ -39,12 +40,61 @@
using namespace osg;
///////////////////////////////////////////////////////////////////////////
// static cache of glShaders flagged for deletion, which will actually
// be deleted in the correct GL context.
typedef std::list<GLuint> GlShaderHandleList;
typedef std::map<unsigned int, GlShaderHandleList> DeletedGlShaderCache;
static OpenThreads::Mutex s_mutex_deletedGL2ShaderCache;
static OpenThreads::Mutex s_mutex_deletedGlShaderCache;
static DeletedGlShaderCache s_deletedGlShaderCache;
void Shader::deleteGlShader(unsigned int contextID, GLuint shader)
{
if( shader )
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_mutex_deletedGlShaderCache);
// add glShader to the cache for the appropriate context.
s_deletedGlShaderCache[contextID].push_back(shader);
}
}
void Shader::flushDeletedGlShaders(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<OpenThreads::Mutex> lock(s_mutex_deletedGlShaderCache);
DeletedGlShaderCache::iterator citr = s_deletedGlShaderCache.find(contextID);
if( citr != s_deletedGlShaderCache.end() )
{
GlShaderHandleList& pList = citr->second;
for(GlShaderHandleList::iterator titr=pList.begin();
titr!=pList.end() && elapsedTime<availableTime;
)
{
extensions->glDeleteShader( *titr );
titr = pList.erase( titr );
elapsedTime = timer.delta_s(start_tick,timer.tick());
}
}
}
availableTime -= elapsedTime;
}
///////////////////////////////////////////////////////////////////////////
// osg::Shader
///////////////////////////////////////////////////////////////////////////
@@ -55,54 +105,49 @@ Shader::Shader(Type type, const char* sourceText) :
setShaderSource( sourceText );
}
Shader::Shader(const Shader& rhs, const osg::CopyOp& copyop):
Object( rhs, copyop ),
_type(rhs._type)
Shader::Shader() :
_type(VERTEX)
{
// TODO this default constructor is inappropriate for the Shader class.
// It exists for now because it is required by META_OBject
osg::notify(osg::FATAL) << "how got here?" << std::endl;
}
Shader::Shader(const Shader& rhs, const osg::CopyOp& copyop):
osg::Object( rhs, copyop ),
_type(rhs._type),
_name(rhs._name),
_shaderSource(rhs._shaderSource)
{
/*TODO*/
}
Shader::~Shader()
{
/*TODO*/
}
int Shader::compare(const Shader& rhs) const
{
if( this == &rhs ) return 0;
if( getComment() < rhs.getComment() ) return -1;
if( rhs.getComment() < getComment() ) return 1;
if( getType() < rhs.getType() ) return -1;
if( rhs.getType() < getType() ) return 1;
if( getName() < rhs.getName() ) return -1;
if( rhs.getName() < getName() ) return 1;
if( getShaderSource() < rhs.getShaderSource() ) return -1;
if( rhs.getShaderSource() < getShaderSource() ) return 1;
return 0;
}
void Shader::dirtyShader()
{
// mark each PCSO as needing a recompile
for( unsigned int cxt=0; cxt < _pcsoList.size(); ++cxt )
{
if( ! _pcsoList[cxt] ) continue;
PerContextShaderObj* pcso = _pcsoList[cxt].get();
pcso->markAsDirty();
}
// also mark-as-dirty the Programs we're attach to
for( unsigned int i=0; i < _programList.size(); ++i )
{
_programList[i]->dirtyProgram();
}
}
void Shader::setShaderSource( const char* sourceText )
{
_shaderSource = ( sourceText ? sourceText : "" );
dirtyShader();
}
bool Shader::loadShaderSourceFromFile( const char* fileName )
{
std::ifstream sourceFile;
@@ -143,97 +188,138 @@ const char* Shader::getTypename() const
void Shader::compileShader( unsigned int contextID ) const
{
PerContextShaderObj* pcso = getPCSO( contextID );
if( pcso->isDirty() ) pcso->compileShader();
getPCS( contextID )->compileShader();
}
Shader::PerContextShaderObj* Shader::getPCSO(unsigned int contextID) const
Shader::PerContextShader* Shader::getPCS(unsigned int contextID) const
{
if( ! _pcsoList[contextID].valid() )
if( ! _pcsList[contextID].valid() )
{
_pcsoList[contextID] = new PerContextShaderObj( this, contextID );
_pcsList[contextID] = new PerContextShader( this, contextID );
}
return _pcsoList[contextID].get();
return _pcsList[contextID].get();
}
void Shader::attachShader(unsigned int contextID, GLuint program) const
{
getPCSO( contextID )->attachShader( program );
getPCS( contextID )->attachShader( program );
}
void Shader::addProgObjRef( Program* program )
void Shader::getGlShaderInfoLog(unsigned int contextID, std::string& log) const
{
_programList.push_back( program );
getPCS( contextID )->getInfoLog( log );
}
void Shader::deleteShader(unsigned int contextID, GLuint shader)
/////////////////////////////////////////////////////////////////////////
// A Shader stores pointers to the osg::Programs to which it is attached,
// so that if the Shader is marked for recompilation with
// Shader::dirtyShader(), the upstream Program can be marked for relinking.
// _programSet does not use ref_ptrs, as that would cause a cyclical
// dependency, and neither the Program nor the Shader would be deleted.
bool Shader::addProgramRef( Program* program )
{
if( shader )
ProgramSet::iterator itr = _programSet.find(program);
if( itr != _programSet.end() ) return false;
_programSet.insert( program );
return true;
}
bool Shader::removeProgramRef( Program* program )
{
ProgramSet::iterator itr = _programSet.find(program);
if( itr == _programSet.end() ) return false;
_programSet.erase( itr );
return true;
}
void Shader::dirtyShader()
{
// Mark our PCSs as needing recompilation.
for( unsigned int cxt=0; cxt < _pcsList.size(); ++cxt )
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_mutex_deletedGL2ShaderCache);
if( _pcsList[cxt].valid() ) _pcsList[cxt]->requestCompile();
}
// add shader to the cache for the appropriate context.
s_deletedGlShaderCache[contextID].push_back(shader);
// Also mark Programs that depend on us as needing relink.
for( ProgramSet::iterator itr = _programSet.begin();
itr != _programSet.end(); ++itr )
{
(*itr)->dirtyProgram();
}
}
///////////////////////////////////////////////////////////////////////////
// osg::Shader::PerContextShaderObj
// PCSO is the OSG abstraction of the per-context glShader
/////////////////////////////////////////////////////////////////////////
// osg::Shader::PerContextShader
// PCS is the OSG abstraction of the per-context glShader
///////////////////////////////////////////////////////////////////////////
Shader::PerContextShaderObj::PerContextShaderObj(const Shader* shader, unsigned int contextID) :
Shader::PerContextShader::PerContextShader(const Shader* shader, unsigned int contextID) :
osg::Referenced(),
_contextID( contextID )
{
_shader = shader;
_extensions = GL2Extensions::Get( _contextID, true );
_glShaderHandle = _extensions->glCreateShader( shader->getType() );
markAsDirty();
requestCompile();
}
Shader::PerContextShaderObj::PerContextShaderObj(const PerContextShaderObj& rhs) :
osg::Referenced(),
_contextID( rhs._contextID )
Shader::PerContextShader::~PerContextShader()
{
_shader = rhs._shader;
_extensions = rhs._extensions;
_glShaderHandle = rhs._glShaderHandle;
_dirty = rhs._dirty;
Shader::deleteGlShader( _contextID, _glShaderHandle );
}
Shader::PerContextShaderObj::~PerContextShaderObj()
void Shader::PerContextShader::requestCompile()
{
_needsCompile = true;
_isCompiled = false;
}
void Shader::PerContextShaderObj::compileShader()
void Shader::PerContextShader::compileShader()
{
if( ! _needsCompile ) return;
_needsCompile = false;
GLint compiled;
const char* sourceText = _shader->getShaderSource().c_str();
_extensions->glShaderSource( _glShaderHandle, 1, &sourceText, NULL );
_extensions->glCompileShader( _glShaderHandle );
_extensions->glGetShaderiv( _glShaderHandle, GL_COMPILE_STATUS, &compiled );
_dirty = (compiled == 0);
if( _dirty )
_isCompiled = (compiled == GL_TRUE);
if( ! _isCompiled )
{
// _still_ dirty, something went wrong
// compile failed
std::string infoLog;
_extensions->getShaderInfoLog( _glShaderHandle, infoLog );
getInfoLog( infoLog );
osg::notify(osg::WARN) << _shader->getTypename() <<
" glCompileShader FAILED:\n" << infoLog << std::endl;
}
}
void Shader::PerContextShaderObj::attachShader(GLuint program) const
void Shader::PerContextShader::getInfoLog( std::string& infoLog ) const
{
_extensions->getShaderInfoLog( _glShaderHandle, infoLog );
}
void Shader::PerContextShader::attachShader(GLuint program) const
{
_extensions->glAttachShader( program, _glShaderHandle );
}
void Shader::PerContextShader::detachShader(GLuint program) const
{
_extensions->glDetachShader( program, _glShaderHandle );
}
/*EOF*/

View File

@@ -29,7 +29,6 @@
#include <set>
using namespace osg;
// local class to help porting from OSG0.8.x to 0.9.x
@@ -113,7 +112,22 @@ StateSet::StateSet(const StateSet& rhs,const CopyOp& copyop):Object(rhs,copyop)
if (attr) lhs_attributeList[typemember]=RefAttributePair(attr,rap.second);
}
}
#if 0 //[ TODO
// copy uniform values
for(UniformList::const_iterator rhs_uitr = rhs._uniformList.begin();
rhs_uitr != rhs._uniformList.end();
++rhs_uitr)
{
const std::string& name = rhs_uitr->first;
const RefUniformPair& rup = rhs_uitr->second;
Uniform* uni = copyop(rup.first.get());
if( uni ) _uniformList[name] = RefUniformPair(uni, rup.second);
}
Program* prog = copyop( rhs._program );
if( prog ) _program = prog;
#endif //]
_renderingHint = rhs._renderingHint;
@@ -410,6 +424,9 @@ void StateSet::clear()
_textureModeList.clear();
_textureAttributeList.clear();
_uniformList.clear();
_program = 0;
}
@@ -521,6 +538,29 @@ void StateSet::merge(const StateSet& rhs)
}
}
// merge the uniforms of rhs into this,
// this overrides rhs if OVERRIDE defined in this.
for(UniformList::const_iterator rhs_uitr = rhs._uniformList.begin();
rhs_uitr != rhs._uniformList.end();
++rhs_uitr)
{
UniformList::iterator lhs_uitr = _uniformList.find(rhs_uitr->first);
if (lhs_uitr!=_uniformList.end())
{
if (!(lhs_uitr->second.second & StateAttribute::OVERRIDE))
{
// override isn't on in rhs, so overrite it with incomming
// value.
lhs_uitr->second = rhs_uitr->second;
}
}
else
{
// entry doesn't exist so insert it.
_uniformList.insert(*rhs_uitr);
}
}
// need to merge rendering hints
// but will need to think how best to do this first
// RO, Nov. 2001.
@@ -662,7 +702,7 @@ const StateSet::RefAttributePair* StateSet::getAttributePair(StateAttribute::Typ
return getAttributePair(_attributeList,type,member);
}
void StateSet::setUniform(Uniform* uniform, StateAttribute::OverrideValue value)
void StateSet::addUniform(Uniform* uniform, StateAttribute::OverrideValue value)
{
if (uniform)
{

View File

@@ -11,7 +11,7 @@
*/
/* file: src/osg/Uniform.cpp
* author: Mike Weiblen 2005-02-20
* author: Mike Weiblen 2005-03-23
*/
// NOTICE: This code is CLOSED during construction and/or renovation!
@@ -368,6 +368,13 @@ Uniform::Uniform( const char* name, Value::Type type ) :
{}
Uniform::Uniform( const Uniform& gu, const CopyOp& copyop ) :
Object(gu,copyop),
_value( gu._value )
{
}
Uniform::Uniform( const char* name, float f ) :
_value( name, Value::FLOAT )
{
@@ -423,13 +430,6 @@ Uniform::Uniform( const char* name, int i ) :
//TODO Uniform::Uniform( const char* name, bool b0, bool b1, bool b2, bool b3 )
Uniform::Uniform( const Uniform& gu, const CopyOp& copyop ) :
Object(gu,copyop),
_value( gu._value )
{
}
bool Uniform::set( float f )
{
if( ! isCompatibleType( Value::FLOAT ) ) return false;
@@ -503,5 +503,4 @@ bool Uniform::isCompatibleType( Value::Type t ) const
return false;
}
/*EOF*/