Example #1
0
static inline void
dumpProgram(JSONWriter &json, GLint program)
{
    GLint attached_shaders = 0;
    glGetProgramiv(program, GL_ATTACHED_SHADERS, &attached_shaders);
    if (!attached_shaders) {
        return;
    }

    ShaderMap shaderMap;

    GLuint *shaders = new GLuint[attached_shaders];
    GLsizei count = 0;
    glGetAttachedShaders(program, attached_shaders, &count, shaders);
    std::sort(shaders, shaders + count);
    for (GLsizei i = 0; i < count; ++ i) {
        getShaderSource(shaderMap, shaders[i]);
    }
    delete [] shaders;

    for (ShaderMap::const_iterator it = shaderMap.begin(); it != shaderMap.end(); ++it) {
        json.beginMember(it->first);
        json.writeString(it->second);
        json.endMember();
    }
}
Example #2
0
/**
* Adds a new shader entry to the accumulated shader map, respecting the
* override policy of both the existing entry (if there is one) and the 
* new entry.
*/
void 
VirtualProgram::addToAccumulatedMap(ShaderMap&         accumShaderMap,
                                    const std::string& shaderID,
                                    const ShaderEntry& newEntry) const
{
    const osg::StateAttribute::OverrideValue& ov = newEntry.second;

    // see if we're trying to disable a previous entry:
    if ((ov & osg::StateAttribute::ON) == 0 ) //TODO: check for higher override
    {
        // yes? remove it!
        accumShaderMap.erase( shaderID );
    }

    else
    {
        // see if there's a higher-up entry with the same ID:
        ShaderEntry& accumEntry = accumShaderMap[ shaderID ]; 

        // make sure we can add the new one:
        if ((accumEntry.first.get() == 0L ) ||                           // empty slot, fill it
            ((ov & osg::StateAttribute::PROTECTED) != 0) ||              // new entry is protected
            ((accumEntry.second & osg::StateAttribute::OVERRIDE) == 0) ) // old entry does NOT override
        {
            accumEntry = newEntry;
        }
    }
}
Example #3
0
void
VirtualProgram::accumulateShaders(const osg::State&  state, 
                                  unsigned           mask,
                                  ShaderMap&         accumShaderMap,
                                  AttribBindingList& accumAttribBindings,
                                  AttribAliasMap&    accumAttribAliases)
{
    const StateHack::AttributeVec* av = StateHack::GetAttributeVec(state, VirtualProgram::SA_TYPE);
    if ( av && av->size() > 0 )
    {
        // find the deepest VP that doesn't inherit:
        unsigned start = 0;
        for( start = (int)av->size()-1; start > 0; --start )
        {
            const VirtualProgram* vp = dynamic_cast<const VirtualProgram*>( (*av)[start].first );
            if ( vp && (vp->_mask & mask) && vp->_inherit == false )
                break;
        }

        // collect shaders from there to here:
        for( unsigned i=start; i<av->size(); ++i )
        {
            const VirtualProgram* vp = dynamic_cast<const VirtualProgram*>( (*av)[i].first );
            if ( vp && (vp->_mask && mask) )
            {
                ShaderMap vpShaderMap;
                vp->getShaderMap( vpShaderMap );

                for( ShaderMap::const_iterator i = vpShaderMap.begin(); i != vpShaderMap.end(); ++i )
                {
                    if ( i->second.accept(state) )
                    {
                        addToAccumulatedMap( accumShaderMap, i->first, i->second );
                    }
                }

                const AttribBindingList& abl = vp->getAttribBindingList();
                accumAttribBindings.insert( abl.begin(), abl.end() );

#ifdef USE_ATTRIB_ALIASES
                const AttribAliasMap& aliases = vp->getAttribAliases();
                accumAttribAliases.insert( aliases.begin(), aliases.end() );
#endif
            }
        }
    }
}
Example #4
0
void
VirtualProgram::getShaders(const osg::State&                        state,
                           std::vector<osg::ref_ptr<osg::Shader> >& output)
{
    ShaderMap         shaders;
    AttribBindingList bindings;
    AttribAliasMap    aliases;

    // build the collection:
    accumulateShaders(state, ~0, shaders, bindings, aliases);

    // pre-allocate space:
    output.reserve( shaders.size() );

    // copy to output.
    for(ShaderMap::iterator i = shaders.begin(); i != shaders.end(); ++i)
    {
        output.push_back( i->second._shader.get() );
    }
}
static inline void
dumpProgram(StateWriter &writer, Context &context, GLint program)
{
    if (program <= 0) {
        return;
    }

    GLint attached_shaders = 0;
    glGetProgramiv(program, GL_ATTACHED_SHADERS, &attached_shaders);
    if (!attached_shaders) {
        return;
    }

    ShaderMap shaderMap;

    GLuint *shaders = new GLuint[attached_shaders];
    GLsizei count = 0;
    glGetAttachedShaders(program, attached_shaders, &count, shaders);
    std::sort(shaders, shaders + count);
    for (GLsizei i = 0; i < count; ++ i) {
        getShaderSource(shaderMap, shaders[i]);
    }
    delete [] shaders;

    for (ShaderMap::const_iterator it = shaderMap.begin(); it != shaderMap.end(); ++it) {
        writer.beginMember(it->first);
        writer.writeString(it->second);
        writer.endMember();
    }

    // Dump NVIDIA GPU programs via GL_ARB_get_program_binary
    if (context.ARB_get_program_binary) {
        GLint binaryLength = 0;
        glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &binaryLength);
        if (binaryLength > 0) {
            std::vector<char> binary(binaryLength);
            GLenum format = GL_NONE;
            glGetProgramBinary(program, binaryLength, NULL, &format, &binary[0]);
            if (format == 0x8e21) {
                if (0) {
                    FILE *fp = fopen("program.bin", "wb");
                    if (fp) {
                        fwrite(&binary[0], 1, binaryLength, fp);
                        fclose(fp);
                    }
                }

                // Extract NVIDIA GPU programs
                std::string str(binary.begin(), binary.end());
                size_t end = 0;
                while (true) {
                    // Each program starts with a !!NV header token
                    size_t start = str.find("!!NV", end);
                    if (start == std::string::npos) {
                        break;
                    }

                    // And is preceeded by a length DWORD
                    assert(start >= end + 4);
                    if (start < end + 4) {
                        break;
                    }
                    uint32_t length;
                    str.copy(reinterpret_cast<char *>(&length), 4, start - 4);
                    assert(start + length <= binaryLength);
                    if (start + length > binaryLength) {
                        break;
                    }

                    std::string nvProg = str.substr(start, length);

                    size_t eol = nvProg.find('\n');
                    std::string nvHeader = nvProg.substr(2, eol - 2);

                    writer.beginMember(nvHeader);
                    writer.writeString(nvProg);
                    writer.endMember();

                    end = start + length;
                }
            }
        }
    }
}
Example #6
0
void
VirtualProgram::apply( osg::State & state ) const
{
    if( _shaderMap.empty() ) // Virtual Program works as normal Program
        return Program::apply( state );

    // first, find and collect all the VirtualProgram attributes:
    ShaderMap shaderMap;
    const StateHack::AttributeVec* av = StateHack::GetAttributeVec( state, this );
    if ( av )
    {
        for( StateHack::AttributeVec::const_iterator i = av->begin(); i != av->end(); ++i )
        {
            const osg::StateAttribute* sa = i->first;
            const VirtualProgram* vp = dynamic_cast< const VirtualProgram* >( sa );
            if( vp && ( vp->_mask & _mask ) )
            {
                for( ShaderMap::const_iterator i = vp->_shaderMap.begin(); i != vp->_shaderMap.end(); ++i )
                {
                    shaderMap[ i->first ] = i->second;
                }
            }
        }
    }

    // next add the local shader components to the map:
    for( ShaderMap::const_iterator i = _shaderMap.begin(); i != _shaderMap.end(); ++i )
        shaderMap[ i->first ] = i->second;

    if( shaderMap.size() )
    {
        // next, assemble a list of the shaders in the map so we can compare it:
        ShaderList sl;
        for( ShaderMap::iterator i = shaderMap.begin(); i != shaderMap.end(); ++i )
            sl.push_back( i->second );

        // see if there's already a program associated with this list:
        osg::Program* program = 0L;
        ProgramMap::iterator p = _programMap.find( sl );
        if ( p != _programMap.end() )
        {
            program = p->second.get();
        }
        else
        {
            ShaderFactory* sf = osgEarth::Registry::instance()->getShaderFactory();

            // build a new set of accumulated functions, to support the creation of main()
            const_cast<VirtualProgram*>(this)->refreshAccumulatedFunctions( state );
                
            osg::Shader* vert_main = sf->createVertexShaderMain( _accumulatedFunctions );
            const_cast<VirtualProgram*>(this)->setShader( "osgearth_vert_main", vert_main );
            shaderMap[ ShaderSemantic("osgearth_vert_main", osg::Shader::VERTEX) ] = vert_main;

            osg::Shader* frag_main = sf->createFragmentShaderMain( _accumulatedFunctions );
            const_cast<VirtualProgram*>(this)->setShader( "osgearth_frag_main", frag_main );
            shaderMap[ ShaderSemantic("osgearth_frag_main", osg::Shader::FRAGMENT) ] = frag_main;
            
            // rebuild the shader list now that we've changed the shader map.
            sl.clear();
            for( ShaderMap::iterator i = shaderMap.begin(); i != shaderMap.end(); ++i )
                sl.push_back( i->second );

            // Create a new program and add all our shaders.
            program = new osg::Program();

#if !MERGE_SHADERS
            for( ShaderList::iterator i = sl.begin(); i != sl.end(); ++i )
            {
                program->addShader( i->get() );
            }
#else
            std::string strFragment;
            std::string strVertex;
            std::string strGeometry;
            
            for( ShaderList::iterator i = sl.begin(); i != sl.end(); ++i )
            {
                if( i->get()->getType() == osg::Shader::FRAGMENT )
                    strFragment += i->get()->getShaderSource();
                else if ( i->get()->getType() == osg::Shader::VERTEX )
                    strVertex += i->get()->getShaderSource();
                else if ( i->get()->getType() == osg::Shader::GEOMETRY )
                    strGeometry += i->get()->getShaderSource();
            }

            if( strFragment.length() > 0 )
            {
                program->addShader( new osg::Shader( osg::Shader::FRAGMENT, strFragment ) );
            }

            if( strVertex.length() > 0  )
            {
                program->addShader( new osg::Shader( osg::Shader::VERTEX, strVertex ) );
            }

            if( strGeometry.length() > 0  )
            {
                program->addShader( new osg::Shader( osg::Shader::GEOMETRY, strGeometry ) );
            }
#endif
            // finally, cache the program so we only regenerate it when it changes.
            _programMap[ sl ] = program;
        }

        // finally, apply the program attribute.
        program->apply( state );
    }
    else
    {
        Program::apply( state );
    }
}
Example #7
0
void
VirtualProgram::apply( osg::State& state ) const
{
    if (_shaderMap.empty() && !_inheritSet)
    {
        // If there's no data in the VP, and never has been, unload any existing program.
        // NOTE: OSG's State processor creates a "global default attribute" for each type.
        // Sine we have no way of knowing whether the user created the VP or OSG created it
        // as the default fallback, we use the "_inheritSet" flag to differeniate. This
        // prevents any shader leakage from a VP-enabled node.
        const unsigned int contextID = state.getContextID();
        const osg::GL2Extensions* extensions = osg::GL2Extensions::Get(contextID,true);
        if( ! extensions->isGlslSupported() ) return;

        extensions->glUseProgram( 0 );
        state.setLastAppliedProgramObject(0);
        return;
    }

    // first, find and collect all the VirtualProgram attributes:
    ShaderMap         accumShaderMap;
    AttribBindingList accumAttribBindings;
    AttribAliasMap    accumAttribAliases;
    
    if ( _inherit )
    {
        const StateHack::AttributeVec* av = StateHack::GetAttributeVec( state, this );
        if ( av && av->size() > 0 )
        {
            // find the deepest VP that doesn't inherit:
            unsigned start = 0;
            for( start = (int)av->size()-1; start > 0; --start )
            {
                const VirtualProgram* vp = dynamic_cast<const VirtualProgram*>( (*av)[start].first );
                if ( vp && (vp->_mask & _mask) && vp->_inherit == false )
                    break;
            }
            
            // collect shaders from there to here:
            for( unsigned i=start; i<av->size(); ++i )
            {
                const VirtualProgram* vp = dynamic_cast<const VirtualProgram*>( (*av)[i].first );
                if ( vp && (vp->_mask && _mask) )
                {
                    for( ShaderMap::const_iterator i = vp->_shaderMap.begin(); i != vp->_shaderMap.end(); ++i )
                    {
                        addToAccumulatedMap( accumShaderMap, i->first, i->second );
                    }

                    const AttribBindingList& abl = vp->getAttribBindingList();
                    accumAttribBindings.insert( abl.begin(), abl.end() );

                    const AttribAliasMap& aliases = vp->getAttribAliases();
                    accumAttribAliases.insert( aliases.begin(), aliases.end() );
                }
            }
        }
    }
    
    // next add the local shader components to the map, respecting the override values:
    for( ShaderMap::const_iterator i = _shaderMap.begin(); i != _shaderMap.end(); ++i )
    {
        addToAccumulatedMap( accumShaderMap, i->first, i->second );
    }
    const AttribBindingList& abl = this->getAttribBindingList();
    accumAttribBindings.insert( abl.begin(), abl.end() );

    const AttribAliasMap& aliases = this->getAttribAliases();
    accumAttribAliases.insert( aliases.begin(), aliases.end() );


    if ( true ) //even with nothing in the map, we still want mains! -gw  //accumShaderMap.size() )
    {
        // next, assemble a list of the shaders in the map so we can use it as our
        // program cache key.
        // (Note: at present, the "cache key" does not include any information on the vertex
        // attribute bindings. Technically it should, but in practice this might not be an
        // issue; it is unlikely one would have two identical shader programs with different
        // bindings.)
        ShaderVector vec;
        vec.reserve( accumShaderMap.size() );
        for( ShaderMap::iterator i = accumShaderMap.begin(); i != accumShaderMap.end(); ++i )
        {
            ShaderEntry& entry = i->second;
            vec.push_back( entry.first.get() );
        }
        
        // see if there's already a program associated with this list:
        osg::Program* program = 0L;
        
        // look up the program:
        {
            Threading::ScopedReadLock shared( _programCacheMutex );
            
            ProgramMap::const_iterator p = _programCache.find( vec );
            if ( p != _programCache.end() )
            {
                program = p->second.get();
            }
        }
        
        // if not found, lock and build it:
        if ( !program )
        {
            Threading::ScopedWriteLock exclusive( _programCacheMutex );
            
            // look again in case of contention:
            ProgramMap::const_iterator p = _programCache.find( vec );
            if ( p != _programCache.end() )
            {
                program = p->second.get();
            }
            else
            {
                VirtualProgram* nc = const_cast<VirtualProgram*>(this);
                program = nc->buildProgram( state, accumShaderMap, accumAttribBindings, accumAttribAliases);
            }
        }
        
        // finally, apply the program attribute.
        program->apply( state );
    }
}
Example #8
0
void VirtualProgram::apply( osg::State & state ) const
{
    if( _shaderMap.empty() ) // Virtual Program works as normal Program
        return Program::apply( state );

    State::AttributeVec *av = &state.getAttributeVec(this);

#if NOTIFICATION_MESSAGES
    std::ostream &os  = osg::notify( osg::NOTICE );
    os << "VirtualProgram cumulate Begin" << std::endl;
#endif

    ShaderMap shaderMap;
    for( State::AttributeVec::iterator i = av->begin(); i != av->end(); ++i )
    {
        const osg::StateAttribute * sa = i->first;
        const VirtualProgram * vp = dynamic_cast< const VirtualProgram *>( sa );
        if( vp && ( vp->_mask & _mask ) ) {

#if NOTIFICATION_MESSAGES
            if( vp->getName().empty() )
                os << "VirtualProgram cumulate [ Unnamed VP ] apply" << std::endl;
            else 
                os << "VirtualProgram cumulate ["<< vp->getName() << "] apply" << std::endl;
#endif

            for( ShaderMap::const_iterator i = vp->_shaderMap.begin();
                                           i != vp->_shaderMap.end(); ++i )
            {
                                                    shaderMap[ i->first ] = i->second;
            }

        } else {
#if NOTIFICATION_MESSAGES
            os << "VirtualProgram cumulate ( not VP or mask not match ) ignored" << std::endl;
#endif
            continue; // ignore osg::Programs
        }
    }

    for( ShaderMap::const_iterator i = this->_shaderMap.begin();
                                   i != this->_shaderMap.end(); ++i )
                                        shaderMap[ i->first ] = i->second;

#if NOTIFICATION_MESSAGES
    os << "VirtualProgram cumulate End" << std::endl;
#endif

    if( shaderMap.size() ) {

        ShaderList sl;
        for( ShaderMap::iterator i = shaderMap.begin(); i != shaderMap.end(); ++i )
            sl.push_back( i->second );

        osg::ref_ptr< osg::Program > & program = _programMap[ sl ];

        if( !program.valid() ) {
            program = new osg::Program;
#if !MERGE_SHADERS
            for( ShaderList::iterator i = sl.begin(); i != sl.end(); ++i )
                program->addShader( i->get() );
#else
            std::string strFragment;
            std::string strVertex;
            std::string strGeometry;
            
            for( ShaderList::iterator i = sl.begin(); i != sl.end(); ++i )
            {
                if( i->get()->getType() == osg::Shader::FRAGMENT )
                    strFragment += i->get()->getShaderSource();
                else if ( i->get()->getType() == osg::Shader::VERTEX )
                    strVertex += i->get()->getShaderSource();
                else if ( i->get()->getType() == osg::Shader::GEOMETRY )
                    strGeometry += i->get()->getShaderSource();
            }

            if( strFragment.length() > 0 ) {
                program->addShader( new osg::Shader( osg::Shader::FRAGMENT, strFragment ) );
#if NOTIFICATION_MESSAGES
                os << "====VirtualProgram merged Fragment Shader:"  << std::endl << strFragment << "====" << std::endl;
#endif
            }

            if( strVertex.length() > 0  ) {
                program->addShader( new osg::Shader( osg::Shader::VERTEX, strVertex ) );
#if NOTIFICATION_MESSAGES
                os << "VirtualProgram merged Vertex Shader:"  << std::endl << strVertex << "====" << std::endl;
#endif
            }

            if( strGeometry.length() > 0  ) {
                program->addShader( new osg::Shader( osg::Shader::GEOMETRY, strGeometry ) );
#if NOTIFICATION_MESSAGES
                os << "VirtualProgram merged Geometry Shader:"  << std::endl << strGeometry << "====" << std::endl;
#endif
            }
#endif
        }

        state.applyAttribute( program.get() );
    } else {
        Program::apply( state );
    }

#if NOTIFICATION_MESSAGES
    os << "VirtualProgram Apply" << std::endl;
#endif

}
Example #9
0
void
VirtualProgram::apply( osg::State& state ) const
{
    if (_shaderMap.empty() && !_inheritSet)
    {
        // If there's no data in the VP, and never has been, unload any existing program.
        // NOTE: OSG's State processor creates a "global default attribute" for each type.
        // Sine we have no way of knowing whether the user created the VP or OSG created it
        // as the default fallback, we use the "_inheritSet" flag to differeniate. This
        // prevents any shader leakage from a VP-enabled node.
        const unsigned int contextID = state.getContextID();
        const osg::GL2Extensions* extensions = osg::GL2Extensions::Get(contextID,true);
        if( ! extensions->isGlslSupported() ) return;

        extensions->glUseProgram( 0 );
        state.setLastAppliedProgramObject(0);
        return;
    }

    // first, find and collect all the VirtualProgram attributes:
    ShaderMap         accumShaderMap;
    AttribBindingList accumAttribBindings;
    AttribAliasMap    accumAttribAliases;
    
    // Build the active shader map up to this point:
    if ( _inherit )
    {
        accumulateShaders(state, _mask, accumShaderMap, accumAttribBindings, accumAttribAliases);
    }

    // next add the local shader components to the map, respecting the override values:
    {
        Threading::ScopedReadLock readonly(_dataModelMutex);

        for( ShaderMap::const_iterator i = _shaderMap.begin(); i != _shaderMap.end(); ++i )
        {
            if ( i->second.accept(state) )
            {
                addToAccumulatedMap( accumShaderMap, i->first, i->second );
            }
        }

        const AttribBindingList& abl = this->getAttribBindingList();
        accumAttribBindings.insert( abl.begin(), abl.end() );

#ifdef USE_ATTRIB_ALIASES
        const AttribAliasMap& aliases = this->getAttribAliases();
        accumAttribAliases.insert( aliases.begin(), aliases.end() );
#endif
    }


    // next, assemble a list of the shaders in the map so we can use it as our
    // program cache key.
    // (Note: at present, the "cache key" does not include any information on the vertex
    // attribute bindings. Technically it should, but in practice this might not be an
    // issue; it is unlikely one would have two identical shader programs with different
    // bindings.)
    ShaderVector vec;
    vec.reserve( accumShaderMap.size() );
    for( ShaderMap::iterator i = accumShaderMap.begin(); i != accumShaderMap.end(); ++i )
    {
        ShaderEntry& entry = i->second;
        if ( i->second.accept(state) )
        {
            vec.push_back( entry._shader.get() );
        }
    }

    // see if there's already a program associated with this list:
    osg::ref_ptr<osg::Program> program;

    // look up the program:
    {
        Threading::ScopedReadLock shared( _programCacheMutex );

        ProgramMap::const_iterator p = _programCache.find( vec );
        if ( p != _programCache.end() )
        {
            program = p->second.get();
        }
    }

    // if not found, lock and build it:
    if ( !program.valid() )
    {
        // build a new set of accumulated functions, to support the creation of main()
        ShaderComp::FunctionLocationMap accumFunctions;
        accumulateFunctions( state, accumFunctions );

        // now double-check the program cache, and failing that, build the
        // new shader Program.
        {
            Threading::ScopedWriteLock exclusive( _programCacheMutex );

            // double-check: look again ito negate race conditions
            ProgramMap::const_iterator p = _programCache.find( vec );
            if ( p != _programCache.end() )
            {
                program = p->second.get();
            }
            else
            {
                ShaderVector keyVector;

                //OE_NOTICE << LC << "Building new Program for VP " << getName() << std::endl;

                program = buildProgram(
                    getName(),
                    state,
                    accumFunctions,
                    accumShaderMap, 
                    accumAttribBindings, 
                    accumAttribAliases, 
                    _template.get(),
                    keyVector);

                // global sharing.
                s_programRepo.share(program);

                // finally, put own new program in the cache.
                _programCache[ keyVector ] = program;
            }
        }
    }

    // finally, apply the program attribute.
    if ( program.valid() )
    {
        const unsigned int contextID = state.getContextID();
        const osg::GL2Extensions* extensions = osg::GL2Extensions::Get(contextID,true);

        osg::Program::PerContextProgram* pcp = program->getPCP( contextID );
        bool useProgram = state.getLastAppliedProgramObject() != pcp;

#ifdef DEBUG_APPLY_COUNTS
        {
            // debugging

            static int s_framenum = 0;
            static Threading::Mutex s_mutex;
            static std::map< const VirtualProgram*, std::pair<int,int> > s_counts;

            Threading::ScopedMutexLock lock(s_mutex);

            int framenum = state.getFrameStamp()->getFrameNumber();
            if ( framenum > s_framenum )
            {
                OE_NOTICE << LC << "Applies in last frame: " << std::endl;
                for(std::map<const VirtualProgram*,std::pair<int,int> >::iterator i = s_counts.begin(); i != s_counts.end(); ++i)
                {
                    std::pair<int,int>& counts = i->second;
                    OE_NOTICE << LC << "  " 
                        << i->first->getName() << " : " << counts.second << "/" << counts.first << std::endl;
                }
                s_framenum = framenum;
                s_counts.clear();
            }
            s_counts[this].first++;
            if ( useProgram )
                s_counts[this].second++;
        }
#endif

        if ( useProgram )
        {
            if( pcp->needsLink() )
                program->compileGLObjects( state );

            if( pcp->isLinked() )
            {
                if( osg::isNotifyEnabled(osg::INFO) )
                    pcp->validateProgram();

                pcp->useProgram();
                state.setLastAppliedProgramObject( pcp );
            }
            else
            {
                // program not usable, fallback to fixed function.
                extensions->glUseProgram( 0 );
                state.setLastAppliedProgramObject(0);
                OE_WARN << LC << "Program link failure!" << std::endl;
            }
        }

        //program->apply( state );

#if 0 // test code for detecting race conditions
        for(int i=0; i<10000; ++i) {
            state.setLastAppliedProgramObject(0L);
            program->apply( state );
        }
#endif
    }
}
Example #10
0
void
VirtualProgram::apply( osg::State& state ) const
{
    if (_shaderMap.empty() && !_inheritSet)
    {
        // If there's no data in the VP, and never has been, unload any existing program.
        // NOTE: OSG's State processor creates a "global default attribute" for each type.
        // Sine we have no way of knowing whether the user created the VP or OSG created it
        // as the default fallback, we use the "_inheritSet" flag to differeniate. This
        // prevents any shader leakage from a VP-enabled node.
        const unsigned int contextID = state.getContextID();
        const osg::GL2Extensions* extensions = osg::GL2Extensions::Get(contextID,true);
        if( ! extensions->isGlslSupported() ) return;

        extensions->glUseProgram( 0 );
        state.setLastAppliedProgramObject(0);
        return;
    }

    // first, find and collect all the VirtualProgram attributes:
    ShaderMap         accumShaderMap;
    AttribBindingList accumAttribBindings;
    AttribAliasMap    accumAttribAliases;
    
    if ( _inherit )
    {
        const StateHack::AttributeVec* av = StateHack::GetAttributeVec( state, this );
        if ( av && av->size() > 0 )
        {
            // find the deepest VP that doesn't inherit:
            unsigned start = 0;
            for( start = (int)av->size()-1; start > 0; --start )
            {
                const VirtualProgram* vp = dynamic_cast<const VirtualProgram*>( (*av)[start].first );
                if ( vp && (vp->_mask & _mask) && vp->_inherit == false )
                    break;
            }
            
            // collect shaders from there to here:
            for( unsigned i=start; i<av->size(); ++i )
            {
                const VirtualProgram* vp = dynamic_cast<const VirtualProgram*>( (*av)[i].first );
                if ( vp && (vp->_mask && _mask) )
                {
                    ShaderMap vpShaderMap;
                    vp->getShaderMap( vpShaderMap );

                    for( ShaderMap::const_iterator i = vpShaderMap.begin(); i != vpShaderMap.end(); ++i )
                    {
                        addToAccumulatedMap( accumShaderMap, i->first, i->second );
                    }

                    const AttribBindingList& abl = vp->getAttribBindingList();
                    accumAttribBindings.insert( abl.begin(), abl.end() );

#ifdef USE_ATTRIB_ALIASES
                    const AttribAliasMap& aliases = vp->getAttribAliases();
                    accumAttribAliases.insert( aliases.begin(), aliases.end() );
#endif
                }
            }
        }
    }

    // next add the local shader components to the map, respecting the override values:
    {
        Threading::ScopedReadLock readonly(_dataModelMutex);

        for( ShaderMap::const_iterator i = _shaderMap.begin(); i != _shaderMap.end(); ++i )
        {
            addToAccumulatedMap( accumShaderMap, i->first, i->second );
        }

        const AttribBindingList& abl = this->getAttribBindingList();
        accumAttribBindings.insert( abl.begin(), abl.end() );

#ifdef USE_ATTRIB_ALIASES
        const AttribAliasMap& aliases = this->getAttribAliases();
        accumAttribAliases.insert( aliases.begin(), aliases.end() );
#endif
    }


    if ( true ) //even with nothing in the map, we still want mains! -gw  //accumShaderMap.size() )
    {
        // next, assemble a list of the shaders in the map so we can use it as our
        // program cache key.
        // (Note: at present, the "cache key" does not include any information on the vertex
        // attribute bindings. Technically it should, but in practice this might not be an
        // issue; it is unlikely one would have two identical shader programs with different
        // bindings.)
        ShaderVector vec;
        vec.reserve( accumShaderMap.size() );
        for( ShaderMap::iterator i = accumShaderMap.begin(); i != accumShaderMap.end(); ++i )
        {
            ShaderEntry& entry = i->second;
            vec.push_back( entry.first.get() );
        }
        
        // see if there's already a program associated with this list:
        osg::ref_ptr<osg::Program> program;
        
        // look up the program:
        {
            Threading::ScopedReadLock shared( _programCacheMutex );
            
            ProgramMap::const_iterator p = _programCache.find( vec );
            if ( p != _programCache.end() )
            {
                program = p->second.get();
            }
        }
        
        // if not found, lock and build it:
        if ( !program.valid() )
        {
            // build a new set of accumulated functions, to support the creation of main()
            ShaderComp::FunctionLocationMap accumFunctions;
            accumulateFunctions( state, accumFunctions );

            // now double-check the program cache, and failing that, build the
            // new shader Program.
            {
                Threading::ScopedWriteLock exclusive( _programCacheMutex );
                
                // double-check: look again ito negate race conditions
                ProgramMap::const_iterator p = _programCache.find( vec );
                if ( p != _programCache.end() )
                {
                    program = p->second.get();
                }
                else
                {
                    ShaderVector keyVector;

                    //OE_NOTICE << LC << "Building new Program for VP " << getName() << std::endl;

                    program = buildProgram(
                        getName(),
                        state,
                        accumFunctions,
                        accumShaderMap, 
                        accumAttribBindings, 
                        accumAttribAliases, 
                        _template.get(),
                        keyVector);

                    // finally, put own new program in the cache.
                    _programCache[ keyVector ] = program;
                }
            }
        }
        
        // finally, apply the program attribute.
        if ( program.valid() )
        {
            program->apply( state );

#if 0 // test code for detecting race conditions
            for(int i=0; i<10000; ++i) {
                state.setLastAppliedProgramObject(0L);
                program->apply( state );
            }
#endif
        }
    }
}
Example #11
0
/* Called when a drawing pass has ended
 */
void D3DRenderer::OnDrawEnd()
{
	mDeviceLost = false;

	mD3DDevice->SetSamplerState(0, D3DSAMP_MIPMAPLODBIAS, 0);
	mD3DDevice->EndScene();

	HRESULT result = 0;

	result = mD3DDevice->TestCooperativeLevel();
	if(result == D3DERR_DEVICELOST)
		return;

	if(result == D3DERR_DEVICENOTRESET)
	{
		mDeviceLost = true;

		// Release the existing swap chains
		SwapChainMap::iterator swapChainIt = mSwapChains.begin();
		for(; swapChainIt != mSwapChains.end(); swapChainIt++)
		{
			IDirect3DSwapChain9* pSwapChain = swapChainIt->second.mD3DSwapChain;
			if(pSwapChain)
			{
				pSwapChain->Release();
			}
		}

		// Release the shaders
		ShaderMap::iterator shaderIt = mShaders.begin();
		for(; shaderIt != mShaders.end(); shaderIt++)
		{
			(*shaderIt).second.mEffect->Release();
		}

		// Release the vbuffer
		mVertexBuffer->Release();
		mVertexBuffer = NULL;

		// Release the vertex decl
		mVertexDeclaration->Release();
		mVertexDeclaration = NULL;

		// Reset the device
		D3DPRESENT_PARAMETERS d3dpp;
		GetPresentParams(d3dpp);   
		HRESULT hr = mD3DDevice->Reset(&d3dpp);
		if(FAILED(hr))
		{
			printf("FAILED\n");
		}

		// Recreate the swap chains
		swapChainIt = mSwapChains.begin();
		for(; swapChainIt != mSwapChains.end(); swapChainIt++)
		{
			SwapChain swapChain = swapChainIt->second;
			CreateContext(swapChain.mWindow, swapChain.mWidth, swapChain.mHeight, swapChainIt->first);
		}

		// Create the Vertex Buffer
		CreateBuffers();

		// Recreate the shaders
		ShaderMap tmp = mShaders;
		mShaders.clear();

		CreateShaders();

		shaderIt = tmp.begin();
		for(; shaderIt != tmp.end(); shaderIt++)
		{
			Shader& shader = shaderIt->second;
			if(shader.mSource != "")
				LoadShader(shader.mName.c_str(), shader.mSource.c_str());
		}

		// By setting mContext to zero, we force the back-buffer changes in the next frame
		long oldContext = mContext;
		mContext = 0;
		SetContext(oldContext);
	}

	SwapChainMap::iterator it = mSwapChains.find(mContext);
	if(it != mSwapChains.end())
	{
		IDirect3DSwapChain9* pSwapChain = it->second.mD3DSwapChain;
		if(pSwapChain)
			result = pSwapChain->Present(NULL, NULL, NULL, NULL, 0);
	}
}