1 /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2  * Copyright (C) 2003-2005 3Dlabs Inc. Ltd.
3  * Copyright (C) 2004-2005 Nathan Cournia
4  * Copyright (C) 2008 Zebra Imaging
5  * Copyright (C) 2010 VIRES Simulationstechnologie GmbH
6  * Copyright (C) 2012 David Callu
7  *
8  * This application is open source and may be redistributed and/or modified
9  * freely and without restriction, both in commercial and non commercial
10  * applications, as long as this copyright notice is maintained.
11  *
12  * This application is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15  *
16 */
17 
18 /* file:        src/osg/Program.cpp
19  * author:      Mike Weiblen 2008-01-19
20  *              Holger Helmich 2010-10-21
21 */
22 
23 #include <list>
24 #include <fstream>
25 
26 #include <osg/Notify>
27 #include <osg/State>
28 #include <osg/Timer>
29 #include <osg/buffered_value>
30 #include <osg/ref_ptr>
31 #include <osg/Program>
32 #include <osg/Shader>
33 #include <osg/GLExtensions>
34 
35 #include <OpenThreads/ScopedLock>
36 #include <OpenThreads/Mutex>
37 
38 #include <string.h>
39 
40 using namespace osg;
41 
42 ///////////////////////////////////////////////////////////////////////////
43 // static cache of glPrograms flagged for deletion, which will actually
44 // be deleted in the correct GL context.
45 
46 typedef std::list<GLuint> GlProgramHandleList;
47 typedef osg::buffered_object<GlProgramHandleList> DeletedGlProgramCache;
48 
49 static OpenThreads::Mutex    s_mutex_deletedGlProgramCache;
50 static DeletedGlProgramCache s_deletedGlProgramCache;
51 
deleteGlProgram(unsigned int contextID,GLuint program)52 void Program::deleteGlProgram(unsigned int contextID, GLuint program)
53 {
54     if( program )
55     {
56         OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_mutex_deletedGlProgramCache);
57 
58         // add glProgram to the cache for the appropriate context.
59         s_deletedGlProgramCache[contextID].push_back(program);
60     }
61 }
62 
flushDeletedGlPrograms(unsigned int contextID,double,double & availableTime)63 void Program::flushDeletedGlPrograms(unsigned int contextID,double /*currentTime*/, double& availableTime)
64 {
65     // if no time available don't try to flush objects.
66     if (availableTime<=0.0) return;
67 
68     OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_mutex_deletedGlProgramCache);
69     const GLExtensions* extensions = GLExtensions::Get(contextID,true);
70     if( ! extensions->isGlslSupported ) return;
71 
72     const osg::Timer& timer = *osg::Timer::instance();
73     osg::Timer_t start_tick = timer.tick();
74     double elapsedTime = 0.0;
75 
76     {
77 
78         GlProgramHandleList& pList = s_deletedGlProgramCache[contextID];
79         for(GlProgramHandleList::iterator titr=pList.begin();
80             titr!=pList.end() && elapsedTime<availableTime;
81             )
82         {
83             extensions->glDeleteProgram( *titr );
84             titr = pList.erase( titr );
85             elapsedTime = timer.delta_s(start_tick,timer.tick());
86         }
87     }
88 
89     availableTime -= elapsedTime;
90 }
91 
discardDeletedGlPrograms(unsigned int contextID)92 void Program::discardDeletedGlPrograms(unsigned int contextID)
93 {
94     OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_mutex_deletedGlProgramCache);
95     GlProgramHandleList& pList = s_deletedGlProgramCache[contextID];
96     pList.clear();
97 }
98 
99 
100 ///////////////////////////////////////////////////////////////////////////
101 // osg::Program::ProgramBinary
102 ///////////////////////////////////////////////////////////////////////////
103 
ProgramBinary()104 Program::ProgramBinary::ProgramBinary() : _format(0)
105 {
106 }
107 
ProgramBinary(const ProgramBinary & rhs,const osg::CopyOp & copyop)108 Program::ProgramBinary::ProgramBinary(const ProgramBinary& rhs, const osg::CopyOp& copyop) :
109     osg::Object(rhs, copyop),
110     _data(rhs._data), _format(rhs._format)
111 {
112 }
113 
allocate(unsigned int size)114 void Program::ProgramBinary::allocate(unsigned int size)
115 {
116     _data.clear();
117     _data.resize(size);
118 }
119 
assign(unsigned int size,const unsigned char * data)120 void Program::ProgramBinary::assign(unsigned int size, const unsigned char* data)
121 {
122     allocate(size);
123     if (data)
124     {
125         for(unsigned int i=0; i<size; ++i)
126         {
127             _data[i] = data[i];
128         }
129     }
130 }
131 
132 
133 ///////////////////////////////////////////////////////////////////////////
134 // osg::Program
135 ///////////////////////////////////////////////////////////////////////////
136 
Program()137 Program::Program() :
138     _geometryVerticesOut(1), _geometryInputType(GL_TRIANGLES),
139     _geometryOutputType(GL_TRIANGLE_STRIP),
140     _numGroupsX(0), _numGroupsY(0), _numGroupsZ(0), _feedbackmode(GL_SEPARATE_ATTRIBS)
141 {
142 }
143 
144 
Program(const Program & rhs,const osg::CopyOp & copyop)145 Program::Program(const Program& rhs, const osg::CopyOp& copyop):
146     osg::StateAttribute(rhs, copyop)
147 {
148 
149     if ((copyop.getCopyFlags()&osg::CopyOp::DEEP_COPY_STATEATTRIBUTES)!=0)
150     {
151         for( unsigned int shaderIndex=0; shaderIndex < rhs.getNumShaders(); ++shaderIndex )
152         {
153             addShader( new osg::Shader( *rhs.getShader( shaderIndex ), copyop ) );
154         }
155     }
156     else
157     {
158         for( unsigned int shaderIndex=0; shaderIndex < rhs.getNumShaders(); ++shaderIndex )
159         {
160             addShader( const_cast<osg::Shader*>(rhs.getShader( shaderIndex )) );
161         }
162     }
163 
164     const osg::Program::AttribBindingList &abl = rhs.getAttribBindingList();
165     for( osg::Program::AttribBindingList::const_iterator attribute = abl.begin(); attribute != abl.end(); ++attribute )
166     {
167         addBindAttribLocation( attribute->first, attribute->second );
168     }
169 
170     const osg::Program::FragDataBindingList &fdl = rhs.getFragDataBindingList();
171     for( osg::Program::FragDataBindingList::const_iterator fragdata = fdl.begin(); fragdata != fdl.end(); ++fragdata )
172     {
173         addBindFragDataLocation( fragdata->first, fragdata->second );
174     }
175 
176     _geometryVerticesOut = rhs._geometryVerticesOut;
177     _geometryInputType = rhs._geometryInputType;
178     _geometryOutputType = rhs._geometryOutputType;
179 
180     _numGroupsX = rhs._numGroupsX;
181     _numGroupsY = rhs._numGroupsY;
182     _numGroupsZ = rhs._numGroupsZ;
183 
184     _feedbackmode=rhs._feedbackmode;
185     _feedbackout=rhs._feedbackout;
186 }
187 
188 
~Program()189 Program::~Program()
190 {
191     // inform any attached Shaders that we're going away
192     for( unsigned int i=0; i < _shaderList.size(); ++i )
193     {
194         _shaderList[i]->removeProgramRef( this );
195     }
196 }
197 
198 
compare(const osg::StateAttribute & sa) const199 int Program::compare(const osg::StateAttribute& sa) const
200 {
201     // check the types are equal and then create the rhs variable
202     // used by the COMPARE_StateAttribute_Parameter macros below.
203     COMPARE_StateAttribute_Types(Program,sa)
204 
205     if( _shaderList.size() < rhs._shaderList.size() ) return -1;
206     if( rhs._shaderList.size() < _shaderList.size() ) return 1;
207 
208     if( getName() < rhs.getName() ) return -1;
209     if( rhs.getName() < getName() ) return 1;
210 
211     if( _geometryVerticesOut < rhs._geometryVerticesOut ) return -1;
212     if( rhs._geometryVerticesOut < _geometryVerticesOut ) return 1;
213 
214     if( _geometryInputType < rhs._geometryInputType ) return -1;
215     if( rhs._geometryInputType < _geometryInputType ) return 1;
216 
217     if( _geometryOutputType < rhs._geometryOutputType ) return -1;
218     if( rhs._geometryOutputType < _geometryOutputType ) return 1;
219 
220     if( _numGroupsX < rhs._numGroupsX ) return -1;
221     if( rhs._numGroupsX < _numGroupsX ) return 1;
222 
223     if( _numGroupsY < rhs._numGroupsY ) return -1;
224     if( rhs._numGroupsY < _numGroupsY ) return 1;
225 
226     if( _numGroupsZ < rhs._numGroupsZ ) return -1;
227     if( rhs._numGroupsZ < _numGroupsZ ) return 1;
228 
229     if(_feedbackout<rhs._feedbackout) return -1;
230     if(_feedbackmode<rhs._feedbackmode) return -1;
231 
232     ShaderList::const_iterator litr=_shaderList.begin();
233     ShaderList::const_iterator ritr=rhs._shaderList.begin();
234     for(;
235         litr!=_shaderList.end();
236         ++litr,++ritr)
237     {
238         int result = (*litr)->compare(*(*ritr));
239         if (result!=0) return result;
240     }
241 
242     return 0; // passed all the above comparison macros, must be equal.
243 }
244 
245 
compileGLObjects(osg::State & state) const246 void Program::compileGLObjects( osg::State& state ) const
247 {
248     if( isFixedFunction() ) return;
249 
250     for( unsigned int i=0; i < _shaderList.size(); ++i )
251     {
252         _shaderList[i]->compileShader( state );
253     }
254 
255     if(!_feedbackout.empty())
256     {
257         const PerContextProgram* pcp = getPCP(state);
258         const GLExtensions* extensions = state.get<GLExtensions>();
259 
260         unsigned int numfeedback = _feedbackout.size();
261         const char**varyings = new const char*[numfeedback];
262         const char **varyingsptr = varyings;
263         for(std::vector<std::string>::const_iterator it=_feedbackout.begin();
264             it!=_feedbackout.end();
265             it++)
266         {
267             *varyingsptr++=(*it).c_str();
268         }
269 
270         extensions->glTransformFeedbackVaryings( pcp->getHandle(), numfeedback, varyings, _feedbackmode);
271         delete [] varyings;
272     }
273     getPCP( state )->linkProgram(state);
274 }
275 
setThreadSafeRefUnref(bool threadSafe)276 void Program::setThreadSafeRefUnref(bool threadSafe)
277 {
278     StateAttribute::setThreadSafeRefUnref(threadSafe);
279 
280     for( unsigned int i=0; i < _shaderList.size(); ++i )
281     {
282         if (_shaderList[i].valid()) _shaderList[i]->setThreadSafeRefUnref(threadSafe);
283     }
284 }
285 
dirtyProgram()286 void Program::dirtyProgram()
287 {
288     // mark our PCPs as needing relink
289     for( unsigned int cxt=0; cxt < _pcpList.size(); ++cxt )
290     {
291         if( _pcpList[cxt].valid() ) _pcpList[cxt]->requestLink();
292     }
293 
294     // update list of defines required.
295     _shaderDefines.clear();
296     for(ShaderList::iterator itr = _shaderList.begin();
297         itr != _shaderList.end();
298         ++itr)
299     {
300         Shader* shader = itr->get();
301         ShaderDefines& sd = shader->getShaderDefines();
302         _shaderDefines.insert(sd.begin(), sd.end());
303 
304         ShaderDefines& sr = shader->getShaderRequirements();
305         _shaderDefines.insert(sr.begin(), sr.end());
306     }
307 }
308 
309 
resizeGLObjectBuffers(unsigned int maxSize)310 void Program::resizeGLObjectBuffers(unsigned int maxSize)
311 {
312     for( unsigned int i=0; i < _shaderList.size(); ++i )
313     {
314         if (_shaderList[i].valid()) _shaderList[i]->resizeGLObjectBuffers(maxSize);
315     }
316 
317     _pcpList.resize(maxSize);
318 }
319 
releaseGLObjects(osg::State * state) const320 void Program::releaseGLObjects(osg::State* state) const
321 {
322     for( unsigned int i=0; i < _shaderList.size(); ++i )
323     {
324         if (_shaderList[i].valid()) _shaderList[i]->releaseGLObjects(state);
325     }
326 
327     if (!state) _pcpList.setAllElementsTo(0);
328     else
329     {
330         unsigned int contextID = state->getContextID();
331         _pcpList[contextID] = 0;
332     }
333 }
334 
addShader(Shader * shader)335 bool Program::addShader( Shader* shader )
336 {
337     if( !shader ) return false;
338 
339     // Shader can only be added once to a Program
340     for( unsigned int i=0; i < _shaderList.size(); ++i )
341     {
342         if( shader == _shaderList[i].get() ) return false;
343     }
344 
345     // Add shader to PCPs
346     for( unsigned int cxt=0; cxt < _pcpList.size(); ++cxt )
347     {
348         if( _pcpList[cxt].valid() ) _pcpList[cxt]->addShaderToAttach( shader );
349     }
350 
351     shader->addProgramRef( this );
352     _shaderList.push_back( shader );
353     dirtyProgram();
354     return true;
355 }
356 
357 
removeShader(Shader * shader)358 bool Program::removeShader( Shader* shader )
359 {
360     if( !shader ) return false;
361 
362     // Shader must exist to be removed.
363     for( ShaderList::iterator itr = _shaderList.begin();
364          itr != _shaderList.end();
365          ++itr)
366     {
367         if( shader == itr->get() )
368         {
369             // Remove shader from PCPs
370             for( unsigned int cxt=0; cxt < _pcpList.size(); ++cxt )
371             {
372                 if( _pcpList[cxt].valid() ) _pcpList[cxt]->addShaderToDetach( shader );
373             }
374 
375             shader->removeProgramRef( this );
376             _shaderList.erase(itr);
377 
378             dirtyProgram();
379             return true;
380         }
381     }
382 
383     return false;
384 }
385 
386 
setParameter(GLenum pname,GLint value)387 void Program::setParameter( GLenum pname, GLint value )
388 {
389     switch( pname )
390     {
391         case GL_GEOMETRY_VERTICES_OUT:
392         case GL_GEOMETRY_VERTICES_OUT_EXT:
393             _geometryVerticesOut = value;
394             dirtyProgram();
395             break;
396         case GL_GEOMETRY_INPUT_TYPE:
397         case GL_GEOMETRY_INPUT_TYPE_EXT:
398             _geometryInputType = value;
399             dirtyProgram();    // needed?
400             break;
401         case GL_GEOMETRY_OUTPUT_TYPE:
402         case GL_GEOMETRY_OUTPUT_TYPE_EXT:
403             _geometryOutputType = value;
404             //dirtyProgram();    // needed?
405             break;
406         case GL_PATCH_VERTICES:
407             OSG_WARN << "Program::setParameter invalid param " << GL_PATCH_VERTICES << ", use osg::PatchParameter when setting GL_PATCH_VERTICES."<<std::endl;
408             break;
409         default:
410             OSG_WARN << "Program::setParameter invalid param " << pname << std::endl;
411             break;
412     }
413 }
414 
getParameter(GLenum pname) const415 GLint Program::getParameter( GLenum pname ) const
416 {
417     switch( pname )
418     {
419         case GL_GEOMETRY_VERTICES_OUT:
420         case GL_GEOMETRY_VERTICES_OUT_EXT:
421             return _geometryVerticesOut;
422         case GL_GEOMETRY_INPUT_TYPE:
423         case GL_GEOMETRY_INPUT_TYPE_EXT:
424             return _geometryInputType;
425         case GL_GEOMETRY_OUTPUT_TYPE:
426         case GL_GEOMETRY_OUTPUT_TYPE_EXT:
427             return _geometryOutputType;
428     }
429     OSG_WARN << "getParameter invalid param " << pname << std::endl;
430     return 0;
431 }
432 
setComputeGroups(GLint numGroupsX,GLint numGroupsY,GLint numGroupsZ)433 void Program::setComputeGroups( GLint numGroupsX, GLint numGroupsY, GLint numGroupsZ )
434 {
435     _numGroupsX = numGroupsX;
436     _numGroupsY = numGroupsY;
437     _numGroupsZ = numGroupsZ;
438 }
439 
getComputeGroups(GLint & numGroupsX,GLint & numGroupsY,GLint & numGroupsZ) const440 void Program::getComputeGroups( GLint& numGroupsX, GLint& numGroupsY, GLint& numGroupsZ ) const
441 {
442     numGroupsX = _numGroupsX;
443     numGroupsY = _numGroupsY;
444     numGroupsZ = _numGroupsZ;
445 }
446 
addBindAttribLocation(const std::string & name,GLuint index)447 void Program::addBindAttribLocation( const std::string& name, GLuint index )
448 {
449     _attribBindingList[name] = index;
450     dirtyProgram();
451 }
452 
removeBindAttribLocation(const std::string & name)453 void Program::removeBindAttribLocation( const std::string& name )
454 {
455     _attribBindingList.erase(name);
456     dirtyProgram();
457 }
458 
addBindFragDataLocation(const std::string & name,GLuint index)459 void Program::addBindFragDataLocation( const std::string& name, GLuint index )
460 {
461     _fragDataBindingList[name] = index;
462     dirtyProgram();
463 }
464 
removeBindFragDataLocation(const std::string & name)465 void Program::removeBindFragDataLocation( const std::string& name )
466 {
467     _fragDataBindingList.erase(name);
468     dirtyProgram();
469 }
470 
addBindUniformBlock(const std::string & name,GLuint index)471 void Program::addBindUniformBlock(const std::string& name, GLuint index)
472 {
473     _uniformBlockBindingList[name] = index;
474     dirtyProgram(); // XXX
475 }
476 
removeBindUniformBlock(const std::string & name)477 void Program::removeBindUniformBlock(const std::string& name)
478 {
479     _uniformBlockBindingList.erase(name);
480     dirtyProgram(); // XXX
481 }
482 
483 
484 
485 #include <iostream>
apply(osg::State & state) const486 void Program::apply( osg::State& state ) const
487 {
488     const GLExtensions* extensions = state.get<GLExtensions>();
489     if( ! extensions->isGlslSupported ) return;
490 
491     if( isFixedFunction() )
492     {
493         extensions->glUseProgram( 0 );
494         state.setLastAppliedProgramObject(0);
495         return;
496     }
497 
498 #if 0
499     State::DefineMap& defMap = state.getDefineMap();
500 
501     OSG_NOTICE<<"Program::apply() defMap.changed="<<defMap.changed<<std::endl;
502     for(State::DefineMap::DefineStackMap::const_iterator itr = defMap.map.begin();
503         itr != defMap.map.end();
504         ++itr)
505     {
506         const State::DefineStack& ds = itr->second;
507         OSG_NOTICE<<"  define ["<<itr->first<<"] ds.changed="<<ds.changed<<" ";
508         if (ds.defineVec.empty())
509         {
510             OSG_NOTICE<<" DefineStack empty "<<std::endl;
511         }
512         else
513         {
514             const StateSet::DefinePair& dp = ds.defineVec.back();
515             OSG_NOTICE<<"  value = ["<<dp.first<<"], overridevalue = ["<<dp.second<<"]"<< std::endl;
516         }
517     }
518 
519     if (defMap.changed) defMap.updateCurrentDefines();
520 
521     std::string shaderDefineStr = state.getDefineString(getShaderDefines());
522     OSG_NOTICE<<"TailoredShaderDefineStr={"<<std::endl;
523     OSG_NOTICE<<shaderDefineStr;
524     OSG_NOTICE<<"}"<<std::endl;
525 
526 
527     shaderDefineStr.clear();
528     const StateSet::DefineList& currentDefines = defMap.currentDefines;
529     for(StateSet::DefineList::const_iterator itr = currentDefines.begin();
530         itr != currentDefines.end();
531         ++itr)
532     {
533         const StateSet::DefinePair& dp = itr->second;
534         shaderDefineStr += "#define ";
535         shaderDefineStr += itr->first;
536         if (itr->second.first.empty())
537         {
538             shaderDefineStr += "\n";
539         }
540         else
541         {
542             shaderDefineStr += " ";
543             shaderDefineStr += itr->second.first;
544             shaderDefineStr += "\n";
545         }
546         OSG_NOTICE<<"  active-define = ["<<itr->first<<"], value="<<itr->second.first<<", overridevalue = ["<<itr->second.second<<"]"<< std::endl;
547     }
548 
549     OSG_NOTICE<<"FullShaderDefineStr={"<<std::endl;
550     OSG_NOTICE<<shaderDefineStr;
551     OSG_NOTICE<<"}"<<std::endl;
552 
553 
554 #endif
555 
556 
557     PerContextProgram* pcp = getPCP( state );
558     if( pcp->needsLink() ) compileGLObjects( state );
559     if( pcp->isLinked() )
560     {
561         // for shader debugging: to minimize performance impact,
562         // optionally validate based on notify level.
563         // TODO: enable this using notify level, or perhaps its own getenv()?
564         if( osg::isNotifyEnabled(osg::INFO) )
565             pcp->validateProgram();
566 
567         pcp->useProgram();
568         state.setLastAppliedProgramObject(pcp);
569     }
570     else
571     {
572         // program not usable, fallback to fixed function.
573         extensions->glUseProgram( 0 );
574         state.setLastAppliedProgramObject(0);
575     }
576 }
577 
578 
ProgramObjects(const osg::Program * program,unsigned int contextID)579 Program::ProgramObjects::ProgramObjects(const osg::Program* program, unsigned int contextID):
580     _contextID(contextID),
581     _program(program)
582 {
583 }
584 
585 
getPCP(const std::string & defineStr) const586 Program::PerContextProgram* Program::ProgramObjects::getPCP(const std::string& defineStr) const
587 {
588     for(PerContextPrograms::const_iterator itr = _perContextPrograms.begin();
589         itr != _perContextPrograms.end();
590         ++itr)
591     {
592         if ((*itr)->getDefineString()==defineStr)
593         {
594             // OSG_NOTICE<<"Returning PCP "<<itr->get()<<" DefineString = "<<(*itr)->getDefineString()<<std::endl;
595             return itr->get();
596         }
597     }
598     return 0;
599 }
600 
createPerContextProgram(const std::string & defineStr)601 Program::PerContextProgram* Program::ProgramObjects::createPerContextProgram(const std::string& defineStr)
602 {
603     Program::PerContextProgram* pcp = new PerContextProgram( _program, _contextID );
604     _perContextPrograms.push_back( pcp );
605     pcp->setDefineString(defineStr);
606     // OSG_NOTICE<<"Creating PCP "<<pcp<<" PCP DefineString = ["<<pcp->getDefineString()<<"]"<<std::endl;
607     return pcp;
608 }
609 
requestLink()610 void Program::ProgramObjects::requestLink()
611 {
612     for(PerContextPrograms::iterator itr = _perContextPrograms.begin();
613         itr != _perContextPrograms.end();
614         ++itr)
615     {
616         (*itr)->requestLink();
617     }
618 }
619 
addShaderToAttach(Shader * shader)620 void Program::ProgramObjects::addShaderToAttach(Shader* shader)
621 {
622     for(PerContextPrograms::iterator itr = _perContextPrograms.begin();
623         itr != _perContextPrograms.end();
624         ++itr)
625     {
626         (*itr)->addShaderToAttach(shader);
627     }
628 }
629 
addShaderToDetach(Shader * shader)630 void Program::ProgramObjects::addShaderToDetach(Shader* shader)
631 {
632     for(PerContextPrograms::iterator itr = _perContextPrograms.begin();
633         itr != _perContextPrograms.end();
634         ++itr)
635     {
636         (*itr)->addShaderToDetach(shader);
637     }
638 }
639 
640 
getGlProgramInfoLog(std::string & log) const641 bool Program::ProgramObjects::getGlProgramInfoLog(std::string& log) const
642 {
643     bool result = false;
644     for(PerContextPrograms::const_iterator itr = _perContextPrograms.begin();
645         itr != _perContextPrograms.end();
646         ++itr)
647     {
648         result = (*itr)->getInfoLog( log ) | result;
649     }
650     return result;
651 }
652 
getPCP(State & state) const653 Program::PerContextProgram* Program::getPCP(State& state) const
654 {
655     unsigned int contextID = state.getContextID();
656     const std::string defineStr = state.getDefineString(getShaderDefines());
657 
658     if( ! _pcpList[contextID].valid() )
659     {
660         _pcpList[contextID] = new ProgramObjects( this, contextID );
661     }
662 
663     Program::PerContextProgram* pcp = _pcpList[contextID]->getPCP(defineStr);
664     if (pcp) return pcp;
665 
666     pcp = _pcpList[contextID]->createPerContextProgram(defineStr);
667 
668     // attach all PCSs to this new PCP
669     for( unsigned int i=0; i < _shaderList.size(); ++i )
670     {
671         pcp->addShaderToAttach( _shaderList[i].get() );
672     }
673 
674     return pcp;
675 }
676 
677 
isFixedFunction() const678 bool Program::isFixedFunction() const
679 {
680     // A Program object having no attached Shaders is a special case:
681     // it indicates that programmable shading is to be disabled,
682     // and thus use GL 1.x "fixed functionality" rendering.
683     return _shaderList.empty();
684 }
685 
686 
getGlProgramInfoLog(unsigned int contextID,std::string & log) const687 bool Program::getGlProgramInfoLog(unsigned int contextID, std::string& log) const
688 {
689     if (contextID<_pcpList.size()) return (_pcpList[ contextID ])->getGlProgramInfoLog( log );
690     else return false;
691 }
692 
693 #if 0
694 const Program::ActiveUniformMap& Program::getActiveUniforms(unsigned int contextID) const
695 {
696     return getPCP( contextID )->getActiveUniforms();
697 }
698 
699 const Program::ActiveVarInfoMap& Program::getActiveAttribs(unsigned int contextID) const
700 {
701     return getPCP( contextID )->getActiveAttribs();
702 }
703 
704 const Program::UniformBlockMap& Program::getUniformBlocks(unsigned contextID) const
705 {
706     return getPCP( contextID )->getUniformBlocks();
707 }
708 #endif
709 
710 ///////////////////////////////////////////////////////////////////////////
711 // osg::Program::PerContextProgram
712 // PCP is an OSG abstraction of the per-context glProgram
713 ///////////////////////////////////////////////////////////////////////////
714 
PerContextProgram(const Program * program,unsigned int contextID,GLuint programHandle)715 Program::PerContextProgram::PerContextProgram(const Program* program, unsigned int contextID, GLuint programHandle ) :
716         osg::Referenced(),
717         _glProgramHandle(programHandle),
718         _loadedBinary(false),
719         _contextID( contextID ),
720         _ownsProgramHandle(false)
721 {
722     _program = program;
723     if (_glProgramHandle == 0)
724     {
725         _extensions = GLExtensions::Get( _contextID, true );
726         _glProgramHandle = _extensions->glCreateProgram();
727         _ownsProgramHandle = true;
728     }
729     requestLink();
730 }
731 
~PerContextProgram()732 Program::PerContextProgram::~PerContextProgram()
733 {
734     if (_ownsProgramHandle)
735     {
736         Program::deleteGlProgram( _contextID, _glProgramHandle );
737     }
738 }
739 
740 
requestLink()741 void Program::PerContextProgram::requestLink()
742 {
743     _needsLink = true;
744     _isLinked = false;
745 }
746 
747 
linkProgram(osg::State & state)748 void Program::PerContextProgram::linkProgram(osg::State& state)
749 {
750     if( ! _needsLink ) return;
751     _needsLink = false;
752 
753     OSG_INFO << "Linking osg::Program \"" << _program->getName() << "\""
754              << " id=" << _glProgramHandle
755              << " contextID=" << _contextID
756              <<  std::endl;
757 
758     const ProgramBinary* programBinary = _program->getProgramBinary();
759 
760     _loadedBinary = false;
761     if (programBinary && programBinary->getSize())
762     {
763         GLint linked = GL_FALSE;
764         _extensions->glProgramBinary( _glProgramHandle, programBinary->getFormat(),
765             reinterpret_cast<const GLvoid*>(programBinary->getData()), programBinary->getSize() );
766         _extensions->glGetProgramiv( _glProgramHandle, GL_LINK_STATUS, &linked );
767         _loadedBinary = _isLinked = (linked == GL_TRUE);
768     }
769 
770     if (!_loadedBinary && _extensions->isGeometryShader4Supported)
771     {
772         _extensions->glProgramParameteri( _glProgramHandle, GL_GEOMETRY_VERTICES_OUT_EXT, _program->_geometryVerticesOut );
773         _extensions->glProgramParameteri( _glProgramHandle, GL_GEOMETRY_INPUT_TYPE_EXT, _program->_geometryInputType );
774         _extensions->glProgramParameteri( _glProgramHandle, GL_GEOMETRY_OUTPUT_TYPE_EXT, _program->_geometryOutputType );
775     }
776 
777     if (!_loadedBinary)
778     {
779         const GLsizei shaderMaxCount = 20;
780         GLsizei shadersCount;
781         GLuint shaderObjectHandle[shaderMaxCount];
782         _extensions->glGetAttachedShaders(_glProgramHandle, shaderMaxCount, &shadersCount, shaderObjectHandle);
783 
784         typedef std::map<GLuint, int> ShaderSet;
785         ShaderSet shadersRequired;
786 
787         for(GLsizei i=0; i<shadersCount; ++i)
788         {
789             shadersRequired[shaderObjectHandle[i]]--;
790         }
791 
792         for(unsigned int i=0; i < getProgram()->getNumShaders(); ++i)
793         {
794             const Shader* shader = getProgram()->getShader( i );
795             Shader::PerContextShader* pcs = shader->getPCS(state);
796             if (pcs) shadersRequired[ pcs->getHandle() ]++;
797         }
798 
799         for(ShaderSet::iterator itr = shadersRequired.begin();
800             itr != shadersRequired.end();
801             ++itr)
802         {
803             if (itr->second>0)
804             {
805                 _extensions->glAttachShader( _glProgramHandle, itr->first );
806             }
807             else if (itr->second<0)
808             {
809                 _extensions->glDetachShader( _glProgramHandle, itr->first );
810             }
811         }
812 
813     }
814     _shadersToDetach.clear();
815     _shadersToAttach.clear();
816 
817     _uniformInfoMap.clear();
818     _attribInfoMap.clear();
819     _lastAppliedUniformList.clear();
820 
821     if (!_loadedBinary)
822     {
823         // set any explicit vertex attribute bindings
824         const AttribBindingList& programBindlist = _program->getAttribBindingList();
825         for( AttribBindingList::const_iterator itr = programBindlist.begin();
826             itr != programBindlist.end(); ++itr )
827         {
828             OSG_INFO<<"Program's vertex attrib binding "<<itr->second<<", "<<itr->first<<std::endl;
829             _extensions->glBindAttribLocation( _glProgramHandle, itr->second, reinterpret_cast<const GLchar*>(itr->first.c_str()) );
830         }
831 
832         // set any explicit vertex attribute bindings that are set up via osg::State, such as the vertex arrays
833         //  that have been aliase to vertex attrib arrays
834         if (state.getUseVertexAttributeAliasing())
835         {
836             const AttribBindingList& stateBindlist = state.getAttributeBindingList();
837             for( AttribBindingList::const_iterator itr = stateBindlist.begin();
838                 itr != stateBindlist.end(); ++itr )
839             {
840                 OSG_INFO<<"State's vertex attrib binding "<<itr->second<<", "<<itr->first<<std::endl;
841                 _extensions->glBindAttribLocation( _glProgramHandle, itr->second, reinterpret_cast<const GLchar*>(itr->first.c_str()) );
842             }
843         }
844 
845         // set any explicit frag data bindings
846         const FragDataBindingList& fdbindlist = _program->getFragDataBindingList();
847         for( FragDataBindingList::const_iterator itr = fdbindlist.begin();
848             itr != fdbindlist.end(); ++itr )
849         {
850             _extensions->glBindFragDataLocation( _glProgramHandle, itr->second, reinterpret_cast<const GLchar*>(itr->first.c_str()) );
851         }
852 
853         // if any program binary has been set then assume we want to retrieve a binary later.
854         if (programBinary)
855         {
856             _extensions->glProgramParameteri( _glProgramHandle, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE );
857         }
858 
859         // link the glProgram
860         GLint linked = GL_FALSE;
861         _extensions->glLinkProgram( _glProgramHandle );
862         _extensions->glGetProgramiv( _glProgramHandle, GL_LINK_STATUS, &linked );
863         _isLinked = (linked == GL_TRUE);
864     }
865 
866     if( ! _isLinked )
867     {
868         OSG_NOTICE << "glLinkProgram "<<this<<"\""<< _program->getName() << "\" FAILED" << std::endl;
869 
870         std::string infoLog;
871         if( getInfoLog(infoLog) )
872         {
873             OSG_NOTICE << "Program \""<< _program->getName() << "\" "
874                                       "infolog:\n" << infoLog << std::endl;
875         }
876 
877         return;
878     }
879     else
880     {
881         std::string infoLog;
882         if( getInfoLog(infoLog) )
883         {
884             OSG_INFO << "Program \""<< _program->getName() << "\" "<<
885                                       "link succeeded, infolog:\n" << infoLog << std::endl;
886         }
887     }
888 
889     if (_extensions->isUniformBufferObjectSupported)
890     {
891         GLuint activeUniformBlocks = 0;
892         GLsizei maxBlockNameLen = 0;
893         _extensions->glGetProgramiv(_glProgramHandle, GL_ACTIVE_UNIFORM_BLOCKS,
894                                     reinterpret_cast<GLint*>(&activeUniformBlocks));
895         _extensions->glGetProgramiv(_glProgramHandle,
896                                     GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH,
897                                     &maxBlockNameLen);
898         if (maxBlockNameLen > 0)
899         {
900             std::vector<GLchar> blockName(maxBlockNameLen);
901             for (GLuint i = 0; i < activeUniformBlocks; ++i)
902             {
903                 GLsizei len = 0;
904                 GLint blockSize = 0;
905                 _extensions->glGetActiveUniformBlockName(_glProgramHandle, i,
906                                                          maxBlockNameLen, &len,
907                                                          &blockName[0]);
908                 _extensions->glGetActiveUniformBlockiv(_glProgramHandle, i,
909                                                        GL_UNIFORM_BLOCK_DATA_SIZE,
910                                                        &blockSize);
911                 _uniformBlockMap
912                     .insert(UniformBlockMap::value_type(&blockName[0],
913                                                         UniformBlockInfo(i, blockSize)));
914             }
915         }
916         // Bind any uniform blocks
917         const UniformBlockBindingList& bindingList = _program->getUniformBlockBindingList();
918         for (UniformBlockMap::iterator itr = _uniformBlockMap.begin(),
919                  end = _uniformBlockMap.end();
920              itr != end;
921             ++itr)
922         {
923             const std::string& blockName = itr->first;
924             UniformBlockBindingList::const_iterator bitr = bindingList.find(blockName);
925             if (bitr != bindingList.end())
926             {
927                 _extensions->glUniformBlockBinding(_glProgramHandle, itr->second._index,
928                                                    bitr->second);
929                 OSG_INFO << "uniform block " << blockName << ": " << itr->second._index
930                          << " binding: " << bitr->second << "\n";
931             }
932             else
933             {
934                 OSG_WARN << "uniform block " << blockName << " has no binding.\n";
935             }
936         }
937     }
938 
939     typedef std::map<GLuint, std::string> AtomicCounterMap;
940     AtomicCounterMap atomicCounterMap;
941 
942     // build _uniformInfoMap
943     GLint numUniforms = 0;
944     GLsizei maxLen = 0;
945     _extensions->glGetProgramiv( _glProgramHandle, GL_ACTIVE_UNIFORMS, &numUniforms );
946     _extensions->glGetProgramiv( _glProgramHandle, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxLen );
947     if( (numUniforms > 0) && (maxLen > 1) )
948     {
949         GLint size = 0;
950         GLenum type = 0;
951         GLchar* name = new GLchar[maxLen];
952 
953         for( GLint i = 0; i < numUniforms; ++i )
954         {
955             _extensions->glGetActiveUniform( _glProgramHandle,
956                     i, maxLen, 0, &size, &type, name );
957 
958             int pos = strlen(name);
959             if (pos>0 && name[pos-1]==']')
960             {
961                 // need to trim [..] from end of name as some drivers append this causing problems with look up.
962                 --pos;
963                 while(pos>0 && name[pos]!='[') { --pos; }
964                 name[pos] = 0;
965             }
966 
967             if (type == GL_UNSIGNED_INT_ATOMIC_COUNTER)
968             {
969                 atomicCounterMap[i] = name;
970             }
971 
972             GLint loc = _extensions->glGetUniformLocation( _glProgramHandle, name );
973 
974             if( loc != -1 )
975             {
976                 _uniformInfoMap[Uniform::getNameID(reinterpret_cast<const char*>(name))] = ActiveVarInfo(loc,type,size);
977 
978                 OSG_INFO << "\tUniform \"" << name << "\""
979                     << " loc="<< loc
980                     << " size="<< size
981                     << " type=" << Uniform::getTypename((Uniform::Type)type)
982                     << std::endl;
983             }
984         }
985         delete [] name;
986     }
987 
988     // print atomic counter
989 
990     if (_extensions->isShaderAtomicCountersSupported && !atomicCounterMap.empty())
991     {
992         std::vector<GLint> bufferIndex( atomicCounterMap.size(), 0 );
993         std::vector<GLuint> uniformIndex;
994         for (AtomicCounterMap::iterator it = atomicCounterMap.begin(), end = atomicCounterMap.end();
995              it != end; ++it)
996         {
997             uniformIndex.push_back(it->first);
998         }
999 
1000         _extensions->glGetActiveUniformsiv( _glProgramHandle, uniformIndex.size(),
1001                                             &(uniformIndex[0]), GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX,
1002                                             &(bufferIndex[0]) );
1003 
1004         for (unsigned int j = 0; j < uniformIndex.size(); ++j)
1005         {
1006             OSG_INFO << "\tUniform atomic counter \""<<atomicCounterMap[ uniformIndex[j] ] <<"\""
1007                      <<" buffer bind= " << bufferIndex[j] << ".\n";
1008         }
1009 
1010         std::map<int, std::vector<int> > bufferIndexToUniformIndices;
1011         for (unsigned int i=0; i<bufferIndex.size(); ++i)
1012         {
1013             bufferIndexToUniformIndices[ bufferIndex[i] ].push_back( uniformIndex[i] );
1014         }
1015 
1016         GLuint activeAtomicCounterBuffers = 0;
1017         _extensions->glGetProgramiv(_glProgramHandle, GL_ACTIVE_ATOMIC_COUNTER_BUFFERS,
1018                                     reinterpret_cast<GLint*>(&activeAtomicCounterBuffers));
1019         if (activeAtomicCounterBuffers > 0)
1020         {
1021             for (GLuint i = 0; i < activeAtomicCounterBuffers; ++i)
1022             {
1023                 GLint bindID = 0;
1024                 _extensions->glGetActiveAtomicCounterBufferiv(_glProgramHandle, i,
1025                                                               GL_ATOMIC_COUNTER_BUFFER_BINDING,
1026                                                               &bindID);
1027 
1028                 GLsizei num = 0;
1029                 _extensions->glGetActiveAtomicCounterBufferiv(_glProgramHandle, i,
1030                                                               GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS,
1031                                                               &num);
1032                 GLsizei minSize = 0;
1033                 _extensions->glGetActiveAtomicCounterBufferiv(_glProgramHandle, i,
1034                                                               GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE,
1035                                                               &minSize);
1036 
1037 
1038                 OSG_INFO << "\tUniform atomic counter buffer bind \"" << bindID << "\""
1039                          << " num active atomic counter= "<< num
1040                          << " min size= " << minSize << "\n";
1041 
1042                 if (num)
1043                 {
1044                     std::vector<GLint> indices(num);
1045                     _extensions->glGetActiveAtomicCounterBufferiv(_glProgramHandle, i,
1046                                                                   GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES,
1047                                                                   &(indices[0]));
1048                     OSG_INFO << "\t\tindices used= ";
1049                     for (GLint j = 0; j < num; ++j)
1050                     {
1051                         OSG_INFO << indices[j];
1052                         if (j < (num-1))
1053                         {
1054                             OSG_INFO <<  ", ";
1055                         }
1056                         else
1057                         {
1058                             OSG_INFO <<  ".\n";
1059                         }
1060                     }
1061                 }
1062             }
1063         }
1064     }
1065 
1066     // build _attribInfoMap
1067     GLint numAttrib = 0;
1068     _extensions->glGetProgramiv( _glProgramHandle, GL_ACTIVE_ATTRIBUTES, &numAttrib );
1069     _extensions->glGetProgramiv( _glProgramHandle, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxLen );
1070     if( (numAttrib > 0) && (maxLen > 1) )
1071     {
1072         GLint size = 0;
1073         GLenum type = 0;
1074         GLchar* name = new GLchar[maxLen];
1075 
1076         for( GLint i = 0; i < numAttrib; ++i )
1077         {
1078             _extensions->glGetActiveAttrib( _glProgramHandle,
1079                     i, maxLen, 0, &size, &type, name );
1080 
1081             GLint loc = _extensions->glGetAttribLocation( _glProgramHandle, name );
1082 
1083             if( loc != -1 )
1084             {
1085                 _attribInfoMap[reinterpret_cast<char*>(name)] = ActiveVarInfo(loc,type,size);
1086 
1087                 OSG_INFO << "\tAttrib \"" << name << "\""
1088                          << " loc=" << loc
1089                          << " size=" << size
1090                          << std::endl;
1091             }
1092         }
1093         delete [] name;
1094     }
1095     OSG_INFO << std::endl;
1096 
1097 
1098     //state.checkGLErrors("After Program::PerContextProgram::linkProgram.");
1099 
1100 }
1101 
validateProgram()1102 bool Program::PerContextProgram::validateProgram()
1103 {
1104     GLint validated = GL_FALSE;
1105     _extensions->glValidateProgram( _glProgramHandle );
1106     _extensions->glGetProgramiv( _glProgramHandle, GL_VALIDATE_STATUS, &validated );
1107     if( validated == GL_TRUE)
1108         return true;
1109 
1110     OSG_WARN << "glValidateProgram FAILED \"" << _program->getName() << "\""
1111              << " id=" << _glProgramHandle
1112              << " contextID=" << _contextID
1113              <<  std::endl;
1114 
1115     std::string infoLog;
1116     if( getInfoLog(infoLog) )
1117         OSG_WARN << "infolog:\n" << infoLog << std::endl;
1118 
1119     OSG_WARN << std::endl;
1120 
1121     return false;
1122 }
1123 
getInfoLog(std::string & infoLog) const1124 bool Program::PerContextProgram::getInfoLog( std::string& infoLog ) const
1125 {
1126     return _extensions->getProgramInfoLog( _glProgramHandle, infoLog );
1127 }
1128 
compileProgramBinary(osg::State & state)1129 Program::ProgramBinary* Program::PerContextProgram::compileProgramBinary(osg::State& state)
1130 {
1131     linkProgram(state);
1132     GLint binaryLength = 0;
1133     _extensions->glGetProgramiv( _glProgramHandle, GL_PROGRAM_BINARY_LENGTH, &binaryLength );
1134     if (binaryLength)
1135     {
1136         ProgramBinary* programBinary = new ProgramBinary;
1137         programBinary->allocate(binaryLength);
1138         GLenum binaryFormat = 0;
1139         _extensions->glGetProgramBinary( _glProgramHandle, binaryLength, 0, &binaryFormat, reinterpret_cast<GLvoid*>(programBinary->getData()) );
1140         programBinary->setFormat(binaryFormat);
1141         return programBinary;
1142     }
1143     return 0;
1144 }
1145 
useProgram() const1146 void Program::PerContextProgram::useProgram() const
1147 {
1148     _extensions->glUseProgram( _glProgramHandle  );
1149     if ( _program->_numGroupsX>0 && _program->_numGroupsY>0 && _program->_numGroupsZ>0 )
1150     {
1151         _extensions->glDispatchCompute( _program->_numGroupsX, _program->_numGroupsY, _program->_numGroupsZ );
1152     }
1153 }
1154