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(); } }
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 } } } }
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; } } } } }
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 ); } }
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 ); } }
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 }
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 } }
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 } } }
/* 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); } }