root/OpenSceneGraph/trunk/src/osg/Program.cpp @ 13853

Revision 13853, 29.9 kB (checked in by robert, 21 hours ago)

Release OpenSceneGraph-3.3.3

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
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/GL2Extensions>
34
35#include <OpenThreads/ScopedLock>
36#include <OpenThreads/Mutex>
37
38#include <string.h>
39
40using namespace osg;
41
42///////////////////////////////////////////////////////////////////////////
43// static cache of glPrograms flagged for deletion, which will actually
44// be deleted in the correct GL context.
45
46typedef std::list<GLuint> GlProgramHandleList;
47typedef osg::buffered_object<GlProgramHandleList> DeletedGlProgramCache;
48
49static OpenThreads::Mutex    s_mutex_deletedGlProgramCache;
50static DeletedGlProgramCache s_deletedGlProgramCache;
51
52void 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
63void 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 GL2Extensions* extensions = GL2Extensions::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
92void 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
104Program::ProgramBinary::ProgramBinary() : _format(0)
105{
106}
107
108Program::ProgramBinary::ProgramBinary(const ProgramBinary& rhs, const osg::CopyOp& copyop) :
109    osg::Object(rhs, copyop),
110    _data(rhs._data), _format(rhs._format)
111{
112}
113
114void Program::ProgramBinary::allocate(unsigned int size)
115{
116    _data.clear();
117    _data.resize(size);
118}
119
120void 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
137Program::Program() :
138    _geometryVerticesOut(1), _geometryInputType(GL_TRIANGLES),
139    _geometryOutputType(GL_TRIANGLE_STRIP),
140    _numGroupsX(0), _numGroupsY(0), _numGroupsZ(0)
141{
142}
143
144
145Program::Program(const Program& rhs, const osg::CopyOp& copyop):
146    osg::StateAttribute(rhs, copyop)
147{
148    for( unsigned int shaderIndex=0; shaderIndex < rhs.getNumShaders(); ++shaderIndex )
149    {
150        addShader( new osg::Shader( *rhs.getShader( shaderIndex ), copyop ) );
151    }
152
153    const osg::Program::AttribBindingList &abl = rhs.getAttribBindingList();
154    for( osg::Program::AttribBindingList::const_iterator attribute = abl.begin(); attribute != abl.end(); ++attribute )
155    {
156        addBindAttribLocation( attribute->first, attribute->second );
157    }
158
159    const osg::Program::FragDataBindingList &fdl = rhs.getFragDataBindingList();
160    for( osg::Program::FragDataBindingList::const_iterator fragdata = fdl.begin(); fragdata != fdl.end(); ++fragdata )
161    {
162        addBindFragDataLocation( fragdata->first, fragdata->second );
163    }
164
165    _geometryVerticesOut = rhs._geometryVerticesOut;
166    _geometryInputType = rhs._geometryInputType;
167    _geometryOutputType = rhs._geometryOutputType;
168
169    _numGroupsX = rhs._numGroupsX;
170    _numGroupsY = rhs._numGroupsY;
171    _numGroupsZ = rhs._numGroupsZ;
172}
173
174
175Program::~Program()
176{
177    // inform any attached Shaders that we're going away
178    for( unsigned int i=0; i < _shaderList.size(); ++i )
179    {
180        _shaderList[i]->removeProgramRef( this );
181    }
182}
183
184
185int Program::compare(const osg::StateAttribute& sa) const
186{
187    // check the types are equal and then create the rhs variable
188    // used by the COMPARE_StateAttribute_Parameter macros below.
189    COMPARE_StateAttribute_Types(Program,sa)
190
191    if( _shaderList.size() < rhs._shaderList.size() ) return -1;
192    if( rhs._shaderList.size() < _shaderList.size() ) return 1;
193
194    if( getName() < rhs.getName() ) return -1;
195    if( rhs.getName() < getName() ) return 1;
196
197    if( _geometryVerticesOut < rhs._geometryVerticesOut ) return -1;
198    if( rhs._geometryVerticesOut < _geometryVerticesOut ) return 1;
199
200    if( _geometryInputType < rhs._geometryInputType ) return -1;
201    if( rhs._geometryInputType < _geometryInputType ) return 1;
202
203    if( _geometryOutputType < rhs._geometryOutputType ) return -1;
204    if( rhs._geometryOutputType < _geometryOutputType ) return 1;
205
206    if( _numGroupsX < rhs._numGroupsX ) return -1;
207    if( rhs._numGroupsX < _numGroupsX ) return 1;
208
209    if( _numGroupsY < rhs._numGroupsY ) return -1;
210    if( rhs._numGroupsY < _numGroupsY ) return 1;
211
212    if( _numGroupsZ < rhs._numGroupsZ ) return -1;
213    if( rhs._numGroupsZ < _numGroupsZ ) return 1;
214
215    ShaderList::const_iterator litr=_shaderList.begin();
216    ShaderList::const_iterator ritr=rhs._shaderList.begin();
217    for(;
218        litr!=_shaderList.end();
219        ++litr,++ritr)
220    {
221        int result = (*litr)->compare(*(*ritr));
222        if (result!=0) return result;
223    }
224
225    return 0; // passed all the above comparison macros, must be equal.
226}
227
228
229void Program::compileGLObjects( osg::State& state ) const
230{
231    if( isFixedFunction() ) return;
232
233    const unsigned int contextID = state.getContextID();
234
235    for( unsigned int i=0; i < _shaderList.size(); ++i )
236    {
237        _shaderList[i]->compileShader( state );
238    }
239
240    getPCP( contextID )->linkProgram(state);
241}
242
243void Program::setThreadSafeRefUnref(bool threadSafe)
244{
245    StateAttribute::setThreadSafeRefUnref(threadSafe);
246
247    for( unsigned int i=0; i < _shaderList.size(); ++i )
248    {
249        if (_shaderList[i].valid()) _shaderList[i]->setThreadSafeRefUnref(threadSafe);
250    }
251}
252
253void Program::dirtyProgram()
254{
255    // mark our PCPs as needing relink
256    for( unsigned int cxt=0; cxt < _pcpList.size(); ++cxt )
257    {
258        if( _pcpList[cxt].valid() ) _pcpList[cxt]->requestLink();
259    }
260}
261
262
263void Program::resizeGLObjectBuffers(unsigned int maxSize)
264{
265    for( unsigned int i=0; i < _shaderList.size(); ++i )
266    {
267        if (_shaderList[i].valid()) _shaderList[i]->resizeGLObjectBuffers(maxSize);
268    }
269
270    _pcpList.resize(maxSize);
271}
272
273void Program::releaseGLObjects(osg::State* state) const
274{
275    for( unsigned int i=0; i < _shaderList.size(); ++i )
276    {
277        if (_shaderList[i].valid()) _shaderList[i]->releaseGLObjects(state);
278    }
279
280    if (!state) _pcpList.setAllElementsTo(0);
281    else
282    {
283        unsigned int contextID = state->getContextID();
284        _pcpList[contextID] = 0;
285    }
286}
287
288bool Program::addShader( Shader* shader )
289{
290    if( !shader ) return false;
291
292    // Shader can only be added once to a Program
293    for( unsigned int i=0; i < _shaderList.size(); ++i )
294    {
295        if( shader == _shaderList[i].get() ) return false;
296    }
297
298    // Add shader to PCPs
299    for( unsigned int cxt=0; cxt < _pcpList.size(); ++cxt )
300    {
301        if( _pcpList[cxt].valid() ) _pcpList[cxt]->addShaderToAttach( shader );
302    }
303
304    shader->addProgramRef( this );
305    _shaderList.push_back( shader );
306    dirtyProgram();
307    return true;
308}
309
310
311bool Program::removeShader( Shader* shader )
312{
313    if( !shader ) return false;
314
315    // Shader must exist to be removed.
316    for( ShaderList::iterator itr = _shaderList.begin();
317         itr != _shaderList.end();
318         ++itr)
319    {
320        if( shader == itr->get() )
321        {
322            // Remove shader from PCPs
323            for( unsigned int cxt=0; cxt < _pcpList.size(); ++cxt )
324            {
325                if( _pcpList[cxt].valid() ) _pcpList[cxt]->addShaderToDetach( shader );
326            }
327
328            shader->removeProgramRef( this );
329            _shaderList.erase(itr);
330
331            dirtyProgram();
332            return true;
333        }
334    }
335
336    return false;
337}
338
339
340void Program::setParameter( GLenum pname, GLint value )
341{
342    switch( pname )
343    {
344        case GL_GEOMETRY_VERTICES_OUT_EXT:
345            _geometryVerticesOut = value;
346            dirtyProgram();
347            break;
348        case GL_GEOMETRY_INPUT_TYPE_EXT:
349            _geometryInputType = value;
350            dirtyProgram();    // needed?
351            break;
352        case GL_GEOMETRY_OUTPUT_TYPE_EXT:
353            _geometryOutputType = value;
354            //dirtyProgram();    // needed?
355            break;
356        case GL_PATCH_VERTICES:
357            OSG_WARN << "Program::setParameter invalid param " << GL_PATCH_VERTICES << ", use osg::PatchParameter when setting GL_PATCH_VERTICES."<<std::endl;
358            break;
359        default:
360            OSG_WARN << "Program::setParameter invalid param " << pname << std::endl;
361            break;
362    }
363}
364
365GLint Program::getParameter( GLenum pname ) const
366{
367    switch( pname )
368    {
369        case GL_GEOMETRY_VERTICES_OUT_EXT: return _geometryVerticesOut;
370        case GL_GEOMETRY_INPUT_TYPE_EXT:   return _geometryInputType;
371        case GL_GEOMETRY_OUTPUT_TYPE_EXTreturn _geometryOutputType;
372    }
373    OSG_WARN << "getParameter invalid param " << pname << std::endl;
374    return 0;
375}
376
377void Program::setComputeGroups( GLint numGroupsX, GLint numGroupsY, GLint numGroupsZ )
378{
379    _numGroupsX = numGroupsX;
380    _numGroupsY = numGroupsY;
381    _numGroupsZ = numGroupsZ;
382}
383
384void Program::getComputeGroups( GLint& numGroupsX, GLint& numGroupsY, GLint& numGroupsZ ) const
385{
386    numGroupsX = _numGroupsX;
387    numGroupsY = _numGroupsY;
388    numGroupsZ = _numGroupsZ;
389}
390
391void Program::addBindAttribLocation( const std::string& name, GLuint index )
392{
393    _attribBindingList[name] = index;
394    dirtyProgram();
395}
396
397void Program::removeBindAttribLocation( const std::string& name )
398{
399    _attribBindingList.erase(name);
400    dirtyProgram();
401}
402
403void Program::addBindFragDataLocation( const std::string& name, GLuint index )
404{
405    _fragDataBindingList[name] = index;
406    dirtyProgram();
407}
408
409void Program::removeBindFragDataLocation( const std::string& name )
410{
411    _fragDataBindingList.erase(name);
412    dirtyProgram();
413}
414
415void Program::addBindUniformBlock(const std::string& name, GLuint index)
416{
417    _uniformBlockBindingList[name] = index;
418    dirtyProgram(); // XXX
419}
420
421void Program::removeBindUniformBlock(const std::string& name)
422{
423    _uniformBlockBindingList.erase(name);
424    dirtyProgram(); // XXX
425}
426
427
428
429
430void Program::apply( osg::State& state ) const
431{
432    const unsigned int contextID = state.getContextID();
433    const GL2Extensions* extensions = GL2Extensions::Get(contextID,true);
434    if( ! extensions->isGlslSupported() ) return;
435
436    if( isFixedFunction() )
437    {
438        extensions->glUseProgram( 0 );
439        state.setLastAppliedProgramObject(0);
440        return;
441    }
442
443    PerContextProgram* pcp = getPCP( contextID );
444    if( pcp->needsLink() ) compileGLObjects( state );
445    if( pcp->isLinked() )
446    {
447        // for shader debugging: to minimize performance impact,
448        // optionally validate based on notify level.
449        // TODO: enable this using notify level, or perhaps its own getenv()?
450        if( osg::isNotifyEnabled(osg::INFO) )
451            pcp->validateProgram();
452
453        pcp->useProgram();
454        state.setLastAppliedProgramObject(pcp);
455    }
456    else
457    {
458        // program not usable, fallback to fixed function.
459        extensions->glUseProgram( 0 );
460        state.setLastAppliedProgramObject(0);
461    }
462}
463
464
465Program::PerContextProgram* Program::getPCP(unsigned int contextID) const
466{
467    if( ! _pcpList[contextID].valid() )
468    {
469        _pcpList[contextID] = new PerContextProgram( this, contextID );
470
471        // attach all PCSs to this new PCP
472        for( unsigned int i=0; i < _shaderList.size(); ++i )
473        {
474            _pcpList[contextID]->addShaderToAttach( _shaderList[i].get() );
475        }
476    }
477
478    return _pcpList[contextID].get();
479}
480
481
482bool Program::isFixedFunction() const
483{
484    // A Program object having no attached Shaders is a special case:
485    // it indicates that programmable shading is to be disabled,
486    // and thus use GL 1.x "fixed functionality" rendering.
487    return _shaderList.empty();
488}
489
490
491bool Program::getGlProgramInfoLog(unsigned int contextID, std::string& log) const
492{
493    return getPCP( contextID )->getInfoLog( log );
494}
495
496const Program::ActiveUniformMap& Program::getActiveUniforms(unsigned int contextID) const
497{
498    return getPCP( contextID )->getActiveUniforms();
499}
500
501const Program::ActiveVarInfoMap& Program::getActiveAttribs(unsigned int contextID) const
502{
503    return getPCP( contextID )->getActiveAttribs();
504}
505
506const Program::UniformBlockMap& Program::getUniformBlocks(unsigned contextID) const
507{
508    return getPCP( contextID )->getUniformBlocks();
509}
510
511///////////////////////////////////////////////////////////////////////////
512// osg::Program::PerContextProgram
513// PCP is an OSG abstraction of the per-context glProgram
514///////////////////////////////////////////////////////////////////////////
515
516Program::PerContextProgram::PerContextProgram(const Program* program, unsigned int contextID, GLuint programHandle ) :
517        osg::Referenced(),
518        _glProgramHandle(programHandle),
519        _loadedBinary(false),
520        _contextID( contextID ),
521        _ownsProgramHandle(false)
522{
523    _program = program;
524    _extensions = GL2Extensions::Get( _contextID, true );
525    if (_glProgramHandle == 0)
526    {
527        _glProgramHandle = _extensions->glCreateProgram();
528        _ownsProgramHandle = true;
529    }
530    requestLink();
531}
532
533Program::PerContextProgram::~PerContextProgram()
534{
535    if (_ownsProgramHandle)
536    {
537        Program::deleteGlProgram( _contextID, _glProgramHandle );
538    }
539}
540
541
542void Program::PerContextProgram::requestLink()
543{
544    _needsLink = true;
545    _isLinked = false;
546}
547
548
549void Program::PerContextProgram::linkProgram(osg::State& state)
550{
551    if( ! _needsLink ) return;
552    _needsLink = false;
553
554    OSG_INFO << "Linking osg::Program \"" << _program->getName() << "\""
555             << " id=" << _glProgramHandle
556             << " contextID=" << _contextID
557             <<  std::endl;
558
559    const ProgramBinary* programBinary = _program->getProgramBinary();
560
561    _loadedBinary = false;
562    if (programBinary && programBinary->getSize())
563    {
564        GLint linked = GL_FALSE;
565        _extensions->glProgramBinary( _glProgramHandle, programBinary->getFormat(),
566            reinterpret_cast<const GLvoid*>(programBinary->getData()), programBinary->getSize() );
567        _extensions->glGetProgramiv( _glProgramHandle, GL_LINK_STATUS, &linked );
568        _loadedBinary = _isLinked = (linked == GL_TRUE);
569    }
570
571    if (!_loadedBinary)
572    {
573        if (_extensions->isGeometryShader4Supported())
574        {
575            _extensions->glProgramParameteri( _glProgramHandle, GL_GEOMETRY_VERTICES_OUT_EXT, _program->_geometryVerticesOut );
576            _extensions->glProgramParameteri( _glProgramHandle, GL_GEOMETRY_INPUT_TYPE_EXT, _program->_geometryInputType );
577            _extensions->glProgramParameteri( _glProgramHandle, GL_GEOMETRY_OUTPUT_TYPE_EXT, _program->_geometryOutputType );
578        }
579
580        // Detach removed shaders
581        for( unsigned int i=0; i < _shadersToDetach.size(); ++i )
582        {
583            _shadersToDetach[i]->detachShader( _contextID, _glProgramHandle );
584        }
585    }
586    _shadersToDetach.clear();
587
588    if (!_loadedBinary)
589    {
590        // Attach new shaders
591        for( unsigned int i=0; i < _shadersToAttach.size(); ++i )
592        {
593            _shadersToAttach[i]->attachShader( _contextID, _glProgramHandle );
594        }
595    }
596    _shadersToAttach.clear();
597
598    _uniformInfoMap.clear();
599    _attribInfoMap.clear();
600    _lastAppliedUniformList.clear();
601
602    if (!_loadedBinary)
603    {
604        // set any explicit vertex attribute bindings
605        const AttribBindingList& programBindlist = _program->getAttribBindingList();
606        for( AttribBindingList::const_iterator itr = programBindlist.begin();
607            itr != programBindlist.end(); ++itr )
608        {
609            OSG_INFO<<"Program's vertex attrib binding "<<itr->second<<", "<<itr->first<<std::endl;
610            _extensions->glBindAttribLocation( _glProgramHandle, itr->second, reinterpret_cast<const GLchar*>(itr->first.c_str()) );
611        }
612
613        // set any explicit vertex attribute bindings that are set up via osg::State, such as the vertex arrays
614        //  that have been aliase to vertex attrib arrays
615        if (state.getUseVertexAttributeAliasing())
616        {
617            const AttribBindingList& stateBindlist = state.getAttributeBindingList();
618            for( AttribBindingList::const_iterator itr = stateBindlist.begin();
619                itr != stateBindlist.end(); ++itr )
620            {
621                OSG_INFO<<"State's vertex attrib binding "<<itr->second<<", "<<itr->first<<std::endl;
622                _extensions->glBindAttribLocation( _glProgramHandle, itr->second, reinterpret_cast<const GLchar*>(itr->first.c_str()) );
623            }
624        }
625
626        // set any explicit frag data bindings
627        const FragDataBindingList& fdbindlist = _program->getFragDataBindingList();
628        for( FragDataBindingList::const_iterator itr = fdbindlist.begin();
629            itr != fdbindlist.end(); ++itr )
630        {
631            _extensions->glBindFragDataLocation( _glProgramHandle, itr->second, reinterpret_cast<const GLchar*>(itr->first.c_str()) );
632        }
633
634        // if any program binary has been set then assume we want to retrieve a binary later.
635        if (programBinary)
636        {
637            _extensions->glProgramParameteri( _glProgramHandle, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE );
638        }
639
640        // link the glProgram
641        GLint linked = GL_FALSE;
642        _extensions->glLinkProgram( _glProgramHandle );
643        _extensions->glGetProgramiv( _glProgramHandle, GL_LINK_STATUS, &linked );
644        _isLinked = (linked == GL_TRUE);
645    }
646
647    if( ! _isLinked )
648    {
649        OSG_WARN << "glLinkProgram \""<< _program->getName() << "\" FAILED" << std::endl;
650
651        std::string infoLog;
652        if( getInfoLog(infoLog) )
653        {
654            OSG_WARN << "Program \""<< _program->getName() << "\" "
655                                      "infolog:\n" << infoLog << std::endl;
656        }
657
658        return;
659    }
660    else
661    {
662        std::string infoLog;
663        if( getInfoLog(infoLog) )
664        {
665            OSG_INFO << "Program \""<< _program->getName() << "\" "<<
666                                      "link succeeded, infolog:\n" << infoLog << std::endl;
667        }
668    }
669
670    if (_extensions->isUniformBufferObjectSupported())
671    {
672        GLuint activeUniformBlocks = 0;
673        GLsizei maxBlockNameLen = 0;
674        _extensions->glGetProgramiv(_glProgramHandle, GL_ACTIVE_UNIFORM_BLOCKS,
675                                    reinterpret_cast<GLint*>(&activeUniformBlocks));
676        _extensions->glGetProgramiv(_glProgramHandle,
677                                    GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH,
678                                    &maxBlockNameLen);
679        if (maxBlockNameLen > 0)
680        {
681            std::vector<GLchar> blockName(maxBlockNameLen);
682            for (GLuint i = 0; i < activeUniformBlocks; ++i)
683            {
684                GLsizei len = 0;
685                GLint blockSize = 0;
686                _extensions->glGetActiveUniformBlockName(_glProgramHandle, i,
687                                                         maxBlockNameLen, &len,
688                                                         &blockName[0]);
689                _extensions->glGetActiveUniformBlockiv(_glProgramHandle, i,
690                                                       GL_UNIFORM_BLOCK_DATA_SIZE,
691                                                       &blockSize);
692                _uniformBlockMap
693                    .insert(UniformBlockMap::value_type(&blockName[0],
694                                                        UniformBlockInfo(i, blockSize)));
695            }
696        }
697        // Bind any uniform blocks
698        const UniformBlockBindingList& bindingList = _program->getUniformBlockBindingList();
699        for (UniformBlockMap::iterator itr = _uniformBlockMap.begin(),
700                 end = _uniformBlockMap.end();
701             itr != end;
702            ++itr)
703        {
704            const std::string& blockName = itr->first;
705            UniformBlockBindingList::const_iterator bitr = bindingList.find(blockName);
706            if (bitr != bindingList.end())
707            {
708                _extensions->glUniformBlockBinding(_glProgramHandle, itr->second._index,
709                                                   bitr->second);
710                OSG_INFO << "uniform block " << blockName << ": " << itr->second._index
711                         << " binding: " << bitr->second << "\n";
712            }
713            else
714            {
715                OSG_WARN << "uniform block " << blockName << " has no binding.\n";
716            }
717        }
718    }
719
720    typedef std::map<GLuint, std::string> AtomicCounterMap;
721    AtomicCounterMap atomicCounterMap;
722
723    // build _uniformInfoMap
724    GLint numUniforms = 0;
725    GLsizei maxLen = 0;
726    _extensions->glGetProgramiv( _glProgramHandle, GL_ACTIVE_UNIFORMS, &numUniforms );
727    _extensions->glGetProgramiv( _glProgramHandle, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxLen );
728    if( (numUniforms > 0) && (maxLen > 1) )
729    {
730        GLint size = 0;
731        GLenum type = 0;
732        GLchar* name = new GLchar[maxLen];
733
734        for( GLint i = 0; i < numUniforms; ++i )
735        {
736            _extensions->glGetActiveUniform( _glProgramHandle,
737                    i, maxLen, 0, &size, &type, name );
738
739            int pos = strlen(name);
740            if (pos>0 && name[pos-1]==']')
741            {
742                // need to trim [..] from end of name as some drivers append this causing problems with look up.
743                --pos;
744                while(pos>0 && name[pos]!='[') { --pos; }
745                name[pos] = 0;
746            }
747
748            if (type == GL_UNSIGNED_INT_ATOMIC_COUNTER)
749            {
750                atomicCounterMap[i] = name;
751            }
752
753            GLint loc = _extensions->glGetUniformLocation( _glProgramHandle, name );
754
755            if( loc != -1 )
756            {
757                _uniformInfoMap[Uniform::getNameID(reinterpret_cast<const char*>(name))] = ActiveVarInfo(loc,type,size);
758
759                OSG_INFO << "\tUniform \"" << name << "\""
760                    << " loc="<< loc
761                    << " size="<< size
762                    << " type=" << Uniform::getTypename((Uniform::Type)type)
763                    << std::endl;
764            }
765        }
766        delete [] name;
767    }
768
769    // print atomic counter
770
771    if (_extensions->isShaderAtomicCounterSupported() && !atomicCounterMap.empty())
772    {
773        std::vector<GLint> bufferIndex( atomicCounterMap.size(), 0 );
774        std::vector<GLuint> uniformIndex;
775        for (AtomicCounterMap::iterator it = atomicCounterMap.begin(), end = atomicCounterMap.end();
776             it != end; ++it)
777        {
778            uniformIndex.push_back(it->first);
779        }
780
781        _extensions->glGetActiveUniformsiv( _glProgramHandle, uniformIndex.size(),
782                                            &(uniformIndex[0]), GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX,
783                                            &(bufferIndex[0]) );
784
785        for (unsigned int j = 0; j < uniformIndex.size(); ++j)
786        {
787            OSG_INFO << "\tUniform atomic counter \""<<atomicCounterMap[ uniformIndex[j] ] <<"\""
788                     <<" buffer bind= " << bufferIndex[j] << ".\n";
789        }
790
791        std::map<int, std::vector<int> > bufferIndexToUniformIndices;
792        for (unsigned int i=0; i<bufferIndex.size(); ++i)
793        {
794            bufferIndexToUniformIndices[ bufferIndex[i] ].push_back( uniformIndex[i] );
795        }
796
797        GLuint activeAtomicCounterBuffers = 0;
798        _extensions->glGetProgramiv(_glProgramHandle, GL_ACTIVE_ATOMIC_COUNTER_BUFFERS,
799                                    reinterpret_cast<GLint*>(&activeAtomicCounterBuffers));
800        if (activeAtomicCounterBuffers > 0)
801        {
802            for (GLuint i = 0; i < activeAtomicCounterBuffers; ++i)
803            {
804                GLint bindID = 0;
805                _extensions->glGetActiveAtomicCounterBufferiv(_glProgramHandle, i,
806                                                              GL_ATOMIC_COUNTER_BUFFER_BINDING,
807                                                              &bindID);
808
809                GLsizei num = 0;
810                _extensions->glGetActiveAtomicCounterBufferiv(_glProgramHandle, i,
811                                                              GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS,
812                                                              &num);
813                GLsizei minSize = 0;
814                _extensions->glGetActiveAtomicCounterBufferiv(_glProgramHandle, i,
815                                                              GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE,
816                                                              &minSize);
817
818
819                OSG_INFO << "\tUniform atomic counter buffer bind \"" << bindID << "\""
820                         << " num active atomic counter= "<< num
821                         << " min size= " << minSize << "\n";
822
823                if (num)
824                {
825                    std::vector<GLint> indices(num);
826                    _extensions->glGetActiveAtomicCounterBufferiv(_glProgramHandle, i,
827                                                                  GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES,
828                                                                  &(indices[0]));
829                    OSG_INFO << "\t\tindices used= ";
830                    for (GLint j = 0; j < num; ++j)
831                    {
832                        OSG_INFO << indices[j];
833                        if (j < (num-1))
834                        {
835                            OSG_INFO <<  ", ";
836                        }
837                        else
838                        {
839                            OSG_INFO <<  ".\n";
840                        }
841                    }
842                }
843            }
844        }
845    }
846
847    // build _attribInfoMap
848    GLint numAttrib = 0;
849    _extensions->glGetProgramiv( _glProgramHandle, GL_ACTIVE_ATTRIBUTES, &numAttrib );
850    _extensions->glGetProgramiv( _glProgramHandle, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxLen );
851    if( (numAttrib > 0) && (maxLen > 1) )
852    {
853        GLint size = 0;
854        GLenum type = 0;
855        GLchar* name = new GLchar[maxLen];
856
857        for( GLint i = 0; i < numAttrib; ++i )
858        {
859            _extensions->glGetActiveAttrib( _glProgramHandle,
860                    i, maxLen, 0, &size, &type, name );
861
862            GLint loc = _extensions->glGetAttribLocation( _glProgramHandle, name );
863
864            if( loc != -1 )
865            {
866                _attribInfoMap[reinterpret_cast<char*>(name)] = ActiveVarInfo(loc,type,size);
867
868                OSG_INFO << "\tAttrib \"" << name << "\""
869                         << " loc=" << loc
870                         << " size=" << size
871                         << std::endl;
872            }
873        }
874        delete [] name;
875    }
876    OSG_INFO << std::endl;
877}
878
879bool Program::PerContextProgram::validateProgram()
880{
881    GLint validated = GL_FALSE;
882    _extensions->glValidateProgram( _glProgramHandle );
883    _extensions->glGetProgramiv( _glProgramHandle, GL_VALIDATE_STATUS, &validated );
884    if( validated == GL_TRUE)
885        return true;
886
887    OSG_WARN << "glValidateProgram FAILED \"" << _program->getName() << "\""
888             << " id=" << _glProgramHandle
889             << " contextID=" << _contextID
890             <<  std::endl;
891
892    std::string infoLog;
893    if( getInfoLog(infoLog) )
894        OSG_WARN << "infolog:\n" << infoLog << std::endl;
895
896    OSG_WARN << std::endl;
897
898    return false;
899}
900
901bool Program::PerContextProgram::getInfoLog( std::string& infoLog ) const
902{
903    return _extensions->getProgramInfoLog( _glProgramHandle, infoLog );
904}
905
906Program::ProgramBinary* Program::PerContextProgram::compileProgramBinary(osg::State& state)
907{
908    linkProgram(state);
909    GLint binaryLength = 0;
910    _extensions->glGetProgramiv( _glProgramHandle, GL_PROGRAM_BINARY_LENGTH, &binaryLength );
911    if (binaryLength)
912    {
913        ProgramBinary* programBinary = new ProgramBinary;
914        programBinary->allocate(binaryLength);
915        GLenum binaryFormat = 0;
916        _extensions->glGetProgramBinary( _glProgramHandle, binaryLength, 0, &binaryFormat, reinterpret_cast<GLvoid*>(programBinary->getData()) );
917        programBinary->setFormat(binaryFormat);
918        return programBinary;
919    }
920    return 0;
921}
922
923void Program::PerContextProgram::useProgram() const
924{
925    _extensions->glUseProgram( _glProgramHandle  );
926    if ( _program->_numGroupsX>0 && _program->_numGroupsY>0 && _program->_numGroupsZ>0 )
927    {
928        _extensions->glDispatchCompute( _program->_numGroupsX, _program->_numGroupsY, _program->_numGroupsZ );
929    }
930}
Note: See TracBrowser for help on using the browser.