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