3 # include <simgear_config.h>
6 #include "Technique.hxx"
8 #include "EffectCullVisitor.hxx"
10 #include <boost/foreach.hpp>
16 #include <osg/GLExtensions>
17 #include <osg/GL2Extensions>
19 #include <osg/Texture2D>
21 #include <osgUtil/CullVisitor>
23 #include <osgDB/Registry>
24 #include <osgDB/Input>
25 #include <osgDB/ParameterOutput>
27 #include <simgear/props/props.hxx>
28 #include <simgear/structure/OSGUtils.hxx>
33 using namespace osgUtil;
38 struct ValidateOperation : GraphicsOperation
40 ValidateOperation(Technique* technique_)
41 : GraphicsOperation(opName, false), technique(technique_)
44 virtual void operator() (GraphicsContext* gc);
45 osg::ref_ptr<Technique> technique;
46 static const std::string opName;
49 const std::string ValidateOperation::opName("ValidateOperation");
52 void ValidateOperation::operator() (GraphicsContext* gc)
54 technique->validateInContext(gc);
58 Technique::Technique(bool alwaysValid)
59 : _alwaysValid(alwaysValid), _contextIdLocation(-1)
63 Technique::Technique(const Technique& rhs, const osg::CopyOp& copyop) :
64 osg::Object(rhs,copyop),
65 _contextMap(rhs._contextMap), _alwaysValid(rhs._alwaysValid),
66 _shadowingStateSet(copyop(rhs._shadowingStateSet.get())),
67 _validExpression(rhs._validExpression),
68 _contextIdLocation(rhs._contextIdLocation)
70 for (std::vector<ref_ptr<Pass> >::const_iterator itr = rhs.passes.begin(),
71 end = rhs.passes.end();
74 passes.push_back(static_cast<Pass*>(copyop(itr->get())));
77 Technique::~Technique()
81 Technique::Status Technique::valid(osg::RenderInfo* renderInfo)
85 unsigned contextID = renderInfo->getContextID();
86 ContextInfo& contextInfo = _contextMap[contextID];
87 Status status = contextInfo.valid();
88 if (status != UNKNOWN)
90 Status newStatus = QUERY_IN_PROGRESS;
91 // lock and spawn validity check.
92 if (!contextInfo.valid.compareAndSwap(status, newStatus)) {
93 // Lost the race with another thread spawning a request
94 return contextInfo.valid();
96 ref_ptr<ValidateOperation> validOp = new ValidateOperation(this);
97 GraphicsContext* context = renderInfo->getState()->getGraphicsContext();
98 GraphicsThread* thread = context->getGraphicsThread();
100 thread->add(validOp.get());
102 context->add(validOp.get());
106 Technique::Status Technique::getValidStatus(const RenderInfo* renderInfo) const
110 ContextInfo& contextInfo = _contextMap[renderInfo->getContextID()];
111 return contextInfo.valid();
114 void Technique::validateInContext(GraphicsContext* gc)
116 unsigned int contextId = gc->getState()->getContextID();
117 ContextInfo& contextInfo = _contextMap[contextId];
118 Status oldVal = contextInfo.valid();
119 Status newVal = INVALID;
120 expression::FixedLengthBinding<1> binding;
121 binding.getBindings()[_contextIdLocation] = expression::Value((int) contextId);
122 if (_validExpression->getValue(&binding))
124 contextInfo.valid.compareAndSwap(oldVal, newVal);
129 enum NumDrawables {NUM_DRAWABLES = 128};
132 EffectGeode::DrawablesIterator
133 Technique::processDrawables(const EffectGeode::DrawablesIterator& begin,
134 const EffectGeode::DrawablesIterator& end,
136 bool isCullingActive)
138 RefMatrix& matrix = *cv->getModelViewMatrix();
139 float depth[NUM_DRAWABLES];
140 EffectGeode::DrawablesIterator itr = begin;
142 = cv->getComputeNearFarMode() != CullVisitor::DO_NOT_COMPUTE_NEAR_FAR;
143 for (int i = 0; i < NUM_DRAWABLES && itr != end; ++itr, ++i)
145 Drawable* drawable = itr->get();
147 #if OSG_VERSION_LESS_THAN(3,3,2)
148 const BoundingBox& bb = drawable->getBound();
149 osg::Drawable::CullCallback* cull = drawable->getCullCallback();
151 const BoundingBox& bb = drawable->getBoundingBox();
152 osg::Drawable::CullCallback* cull =
153 dynamic_cast<osg::Drawable::CullCallback*>(drawable->getCullCallback());
156 if( (cull && cull->cull(cv, drawable, &cv->getRenderInfo()))
157 || (isCullingActive && cv->isCulled(bb)) )
163 if( computeNearFar && bb.valid() )
165 if( !cv->updateCalculatedNearFar(matrix, *drawable, false) )
172 depth[i] = bb.valid()
173 ? cv->getDistanceFromEyePoint(bb.center(), false)
175 if( isNaN(depth[i]) )
178 EffectCullVisitor* ecv = dynamic_cast<EffectCullVisitor*>( cv );
179 EffectGeode::DrawablesIterator drawablesEnd = itr;
180 BOOST_FOREACH(ref_ptr<Pass>& pass, passes)
182 osg::ref_ptr<osg::StateSet> ss = pass;
183 if (ecv && ( ! pass->getBufferUnitList().empty() || ! pass->getPositionedUniformMap().empty() ) ) {
184 ss = static_cast<osg::StateSet*>(
185 pass->clone( osg::CopyOp( ( ! pass->getBufferUnitList().empty() ?
186 osg::CopyOp::DEEP_COPY_TEXTURES :
187 osg::CopyOp::SHALLOW_COPY ) |
188 ( ! pass->getPositionedUniformMap().empty() ?
189 osg::CopyOp::DEEP_COPY_UNIFORMS :
190 osg::CopyOp::SHALLOW_COPY ) )
193 for (Pass::BufferUnitList::const_iterator ii = pass->getBufferUnitList().begin();
194 ii != pass->getBufferUnitList().end();
196 osg::Texture2D* tex = ecv->getBuffer(ii->second);
198 ss->setTextureAttributeAndModes( ii->first, tex );
200 for (Pass::PositionedUniformMap::const_iterator ii = pass->getPositionedUniformMap().begin();
201 ii != pass->getPositionedUniformMap().end();
203 osg::RefMatrix* mv = cv->getModelViewMatrix();
204 osg::Vec4 v = ii->second * *mv;
205 ss->getUniform(ii->first)->set( v );
208 cv->pushStateSet(ss);
210 for (itr = begin; itr != drawablesEnd; ++itr, ++i) {
211 if (depth[i] != FLT_MAX)
212 cv->addDrawableAndDepth(itr->get(), &matrix, depth[i]);
219 void Technique::resizeGLObjectBuffers(unsigned int maxSize)
221 if (_shadowingStateSet.valid())
222 _shadowingStateSet->resizeGLObjectBuffers(maxSize);
223 BOOST_FOREACH(ref_ptr<Pass>& pass, passes) {
224 pass->resizeGLObjectBuffers(maxSize);
226 _contextMap.resize(maxSize);
229 void Technique::releaseGLObjects(osg::State* state) const
231 if (_shadowingStateSet.valid())
232 _shadowingStateSet->releaseGLObjects(state);
233 BOOST_FOREACH(const ref_ptr<Pass>& pass, passes)
235 pass->releaseGLObjects(state);
238 for (int i = 0; i < (int)_contextMap.size(); ++i) {
239 ContextInfo& info = _contextMap[i];
240 Status oldVal = info.valid();
241 info.valid.compareAndSwap(oldVal, UNKNOWN);
244 ContextInfo& info = _contextMap[state->getContextID()];
245 Status oldVal = info.valid();
246 info.valid.compareAndSwap(oldVal, UNKNOWN);
250 void Technique::setValidExpression(SGExpressionb* exp,
251 const simgear::expression
252 ::BindingLayout& layout)
254 using namespace simgear::expression;
255 _validExpression = exp;
256 VariableBinding binding;
257 if (layout.findBinding("__contextId", binding))
258 _contextIdLocation = binding.location;
261 class GLVersionExpression : public SGExpression<float>
264 void eval(float& value, const expression::Binding*) const
266 value = getGLVersionNumber();
270 Expression* glVersionParser(const SGPropertyNode* exp,
271 expression::Parser* parser)
273 return new GLVersionExpression();
276 expression::ExpParserRegistrar glVersionRegistrar("glversion", glVersionParser);
278 class ExtensionSupportedExpression
279 : public GeneralNaryExpression<bool, int>
282 ExtensionSupportedExpression() {}
283 ExtensionSupportedExpression(const std::string& extString)
284 : _extString(extString)
287 const std::string& getExtensionString() { return _extString; }
288 void setExtensionString(const std::string& extString) { _extString = extString; }
289 void eval(bool&value, const expression::Binding* b) const
291 int contextId = getOperand(0)->getValue(b);
292 value = isGLExtensionSupported((unsigned)contextId, _extString.c_str());
295 std::string _extString;
298 Expression* extensionSupportedParser(const SGPropertyNode* exp,
299 expression::Parser* parser)
301 if (exp->getType() == props::STRING
302 || exp->getType() == props::UNSPECIFIED) {
303 ExtensionSupportedExpression* esp
304 = new ExtensionSupportedExpression(exp->getStringValue());
305 int location = parser->getBindingLayout().addBinding("__contextId",
307 VariableExpression<int>* contextExp
308 = new VariableExpression<int>(location);
309 esp->addOperand(contextExp);
312 throw expression::ParseError("extension-supported expression has wrong type");
315 expression::ExpParserRegistrar
316 extensionSupportedRegistrar("extension-supported", extensionSupportedParser);
318 class GLShaderLanguageExpression : public GeneralNaryExpression<float, int>
321 void eval(float& value, const expression::Binding* b) const
324 int contextId = getOperand(0)->getValue(b);
325 GL2Extensions* extensions
326 = GL2Extensions::Get(static_cast<unsigned>(contextId), true);
329 #if OSG_VERSION_LESS_THAN(3,3,4)
330 if (!extensions->isGlslSupported())
332 value = extensions->getLanguageVersion();
334 if (!extensions->isGlslSupported)
336 value = extensions->glslLanguageVersion;
341 Expression* shaderLanguageParser(const SGPropertyNode* exp,
342 expression::Parser* parser)
344 GLShaderLanguageExpression* slexp = new GLShaderLanguageExpression;
345 int location = parser->getBindingLayout().addBinding("__contextId",
347 VariableExpression<int>* contextExp = new VariableExpression<int>(location);
348 slexp->addOperand(contextExp);
352 expression::ExpParserRegistrar shaderLanguageRegistrar("shader-language",
353 shaderLanguageParser);
355 class GLSLSupportedExpression : public GeneralNaryExpression<bool, int>
358 void eval(bool& value, const expression::Binding* b) const
361 int contextId = getOperand(0)->getValue(b);
362 GL2Extensions* extensions
363 = GL2Extensions::Get(static_cast<unsigned>(contextId), true);
366 #if OSG_VERSION_LESS_THAN(3,3,4)
367 value = extensions->isGlslSupported();
369 value = extensions->isGlslSupported;
374 Expression* glslSupportedParser(const SGPropertyNode* exp,
375 expression::Parser* parser)
377 GLSLSupportedExpression* sexp = new GLSLSupportedExpression;
378 int location = parser->getBindingLayout().addBinding("__contextId",
380 VariableExpression<int>* contextExp = new VariableExpression<int>(location);
381 sexp->addOperand(contextExp);
385 expression::ExpParserRegistrar glslSupportedRegistrar("glsl-supported",
386 glslSupportedParser);
388 void Technique::setGLExtensionsPred(float glVersion,
389 const std::vector<std::string>& extensions)
392 using namespace expression;
393 BindingLayout layout;
394 int contextLoc = layout.addBinding("__contextId", INT);
395 VariableExpression<int>* contextExp
396 = new VariableExpression<int>(contextLoc);
397 SGExpression<bool>* versionTest
398 = makePredicate<std::less_equal>(new SGConstExpression<float>(glVersion),
399 new GLVersionExpression);
400 AndExpression* extensionsExp = 0;
401 for (vector<string>::const_iterator itr = extensions.begin(),
402 e = extensions.end();
406 extensionsExp = new AndExpression;
407 ExtensionSupportedExpression* supported
408 = new ExtensionSupportedExpression(*itr);
409 supported->addOperand(contextExp);
410 extensionsExp->addOperand(supported);
412 SGExpressionb* predicate = 0;
414 OrExpression* orExp = new OrExpression;
415 orExp->addOperand(versionTest);
416 orExp->addOperand(extensionsExp);
419 predicate = versionTest;
421 setValidExpression(predicate, layout);
424 void Technique::refreshValidity()
426 for (int i = 0; i < (int)_contextMap.size(); ++i) {
427 ContextInfo& info = _contextMap[i];
428 Status oldVal = info.valid();
429 // What happens if we lose the race here?
430 info.valid.compareAndSwap(oldVal, UNKNOWN);
434 bool Technique_writeLocalData(const Object& obj, osgDB::Output& fw)
436 const Technique& tniq = static_cast<const Technique&>(obj);
437 fw.indent() << "alwaysValid "
438 << (tniq.getAlwaysValid() ? "TRUE\n" : "FALSE\n");
440 fw.indent() << "glVersion " << tniq.getGLVersion() << "\n";
442 if (tniq.getShadowingStateSet()) {
443 fw.indent() << "shadowingStateSet\n";
444 fw.writeObject(*tniq.getShadowingStateSet());
446 fw.indent() << "num_passes " << tniq.passes.size() << "\n";
447 BOOST_FOREACH(const ref_ptr<Pass>& pass, tniq.passes) {
448 fw.writeObject(*pass);
455 osgDB::RegisterDotOsgWrapperProxy TechniqueProxy
458 "simgear::Technique",
459 "Object simgear::Technique",
461 &Technique_writeLocalData