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].val.intVal = 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) {
144 Drawable* drawable = itr->get();
145 const BoundingBox& bb = drawable->getBound();
146 if ((drawable->getCullCallback()
147 && drawable->getCullCallback()->cull(cv, drawable,
148 &cv->getRenderInfo()))
149 || (isCullingActive && cv->isCulled(bb))) {
153 if (computeNearFar && bb.valid()) {
154 if (!cv->updateCalculatedNearFar(matrix, *drawable, false)) {
159 depth[i] = (bb.valid()
160 ? cv->getDistanceFromEyePoint(bb.center(), false)
165 EffectCullVisitor* ecv = dynamic_cast<EffectCullVisitor*>( cv );
166 EffectGeode::DrawablesIterator drawablesEnd = itr;
167 BOOST_FOREACH(ref_ptr<Pass>& pass, passes)
169 osg::ref_ptr<osg::StateSet> ss = pass;
170 if (ecv && ( pass->getBufferUnitList().size() != 0 || pass->getPositionedUniformMap().size() != 0 ) ) {
171 ss = static_cast<osg::StateSet*>(
172 pass->clone( osg::CopyOp( ( pass->getBufferUnitList().size() != 0 ?
173 osg::CopyOp::DEEP_COPY_TEXTURES :
174 osg::CopyOp::SHALLOW_COPY ) |
175 ( pass->getPositionedUniformMap().size() != 0 ?
176 osg::CopyOp::DEEP_COPY_UNIFORMS :
177 osg::CopyOp::SHALLOW_COPY ) )
180 for (Pass::BufferUnitList::const_iterator ii = pass->getBufferUnitList().begin();
181 ii != pass->getBufferUnitList().end();
183 osg::Texture2D* tex = ecv->getBuffer(ii->second);
185 ss->setTextureAttributeAndModes( ii->first, tex );
187 for (Pass::PositionedUniformMap::const_iterator ii = pass->getPositionedUniformMap().begin();
188 ii != pass->getPositionedUniformMap().end();
190 osg::RefMatrix* mv = cv->getModelViewMatrix();
191 osg::Vec4 v = ii->second * *mv;
192 ss->getUniform(ii->first)->set( v );
195 cv->pushStateSet(ss);
197 for (itr = begin; itr != drawablesEnd; ++itr, ++i) {
198 if (depth[i] != FLT_MAX)
199 cv->addDrawableAndDepth(itr->get(), &matrix, depth[i]);
206 void Technique::resizeGLObjectBuffers(unsigned int maxSize)
208 if (_shadowingStateSet.valid())
209 _shadowingStateSet->resizeGLObjectBuffers(maxSize);
210 BOOST_FOREACH(ref_ptr<Pass>& pass, passes) {
211 pass->resizeGLObjectBuffers(maxSize);
213 _contextMap.resize(maxSize);
216 void Technique::releaseGLObjects(osg::State* state) const
218 if (_shadowingStateSet.valid())
219 _shadowingStateSet->releaseGLObjects(state);
220 BOOST_FOREACH(const ref_ptr<Pass>& pass, passes)
222 pass->releaseGLObjects(state);
225 for (int i = 0; i < (int)_contextMap.size(); ++i) {
226 ContextInfo& info = _contextMap[i];
227 Status oldVal = info.valid();
228 info.valid.compareAndSwap(oldVal, UNKNOWN);
231 ContextInfo& info = _contextMap[state->getContextID()];
232 Status oldVal = info.valid();
233 info.valid.compareAndSwap(oldVal, UNKNOWN);
237 void Technique::setValidExpression(SGExpressionb* exp,
238 const simgear::expression
239 ::BindingLayout& layout)
241 using namespace simgear::expression;
242 _validExpression = exp;
243 VariableBinding binding;
244 if (layout.findBinding("__contextId", binding))
245 _contextIdLocation = binding.location;
248 class GLVersionExpression : public SGExpression<float>
251 void eval(float& value, const expression::Binding*) const
253 #ifdef TECHNIQUE_TEST_EXTENSIONS
256 value = getGLVersionNumber();
261 Expression* glVersionParser(const SGPropertyNode* exp,
262 expression::Parser* parser)
264 return new GLVersionExpression();
267 expression::ExpParserRegistrar glVersionRegistrar("glversion", glVersionParser);
269 class ExtensionSupportedExpression
270 : public GeneralNaryExpression<bool, int>
273 ExtensionSupportedExpression() {}
274 ExtensionSupportedExpression(const string& extString)
275 : _extString(extString)
278 const string& getExtensionString() { return _extString; }
279 void setExtensionString(const string& extString) { _extString = extString; }
280 void eval(bool&value, const expression::Binding* b) const
282 int contextId = getOperand(0)->getValue(b);
283 value = isGLExtensionSupported((unsigned)contextId, _extString.c_str());
289 Expression* extensionSupportedParser(const SGPropertyNode* exp,
290 expression::Parser* parser)
292 if (exp->getType() == props::STRING
293 || exp->getType() == props::UNSPECIFIED) {
294 ExtensionSupportedExpression* esp
295 = new ExtensionSupportedExpression(exp->getStringValue());
296 int location = parser->getBindingLayout().addBinding("__contextId",
298 VariableExpression<int>* contextExp
299 = new VariableExpression<int>(location);
300 esp->addOperand(contextExp);
303 throw expression::ParseError("extension-supported expression has wrong type");
306 expression::ExpParserRegistrar
307 extensionSupportedRegistrar("extension-supported", extensionSupportedParser);
309 class GLShaderLanguageExpression : public GeneralNaryExpression<float, int>
312 void eval(float& value, const expression::Binding* b) const
315 int contextId = getOperand(0)->getValue(b);
316 GL2Extensions* extensions
317 = GL2Extensions::Get(static_cast<unsigned>(contextId), true);
320 if (!extensions->isGlslSupported())
322 value = extensions->getLanguageVersion();
326 Expression* shaderLanguageParser(const SGPropertyNode* exp,
327 expression::Parser* parser)
329 GLShaderLanguageExpression* slexp = new GLShaderLanguageExpression;
330 int location = parser->getBindingLayout().addBinding("__contextId",
332 VariableExpression<int>* contextExp = new VariableExpression<int>(location);
333 slexp->addOperand(contextExp);
337 expression::ExpParserRegistrar shaderLanguageRegistrar("shader-language",
341 void Technique::setGLExtensionsPred(float glVersion,
342 const std::vector<std::string>& extensions)
345 using namespace expression;
346 BindingLayout layout;
347 int contextLoc = layout.addBinding("__contextId", INT);
348 VariableExpression<int>* contextExp
349 = new VariableExpression<int>(contextLoc);
350 SGExpression<bool>* versionTest
351 = makePredicate<std::less_equal>(new SGConstExpression<float>(glVersion),
352 new GLVersionExpression);
353 AndExpression* extensionsExp = 0;
354 for (vector<string>::const_iterator itr = extensions.begin(),
355 e = extensions.end();
359 extensionsExp = new AndExpression;
360 ExtensionSupportedExpression* supported
361 = new ExtensionSupportedExpression(*itr);
362 supported->addOperand(contextExp);
363 extensionsExp->addOperand(supported);
365 SGExpressionb* predicate = 0;
367 OrExpression* orExp = new OrExpression;
368 orExp->addOperand(versionTest);
369 orExp->addOperand(extensionsExp);
372 predicate = versionTest;
374 setValidExpression(predicate, layout);
377 void Technique::refreshValidity()
379 for (int i = 0; i < (int)_contextMap.size(); ++i) {
380 ContextInfo& info = _contextMap[i];
381 Status oldVal = info.valid();
382 // What happens if we lose the race here?
383 info.valid.compareAndSwap(oldVal, UNKNOWN);
387 bool Technique_writeLocalData(const Object& obj, osgDB::Output& fw)
389 const Technique& tniq = static_cast<const Technique&>(obj);
390 fw.indent() << "alwaysValid "
391 << (tniq.getAlwaysValid() ? "TRUE\n" : "FALSE\n");
393 fw.indent() << "glVersion " << tniq.getGLVersion() << "\n";
395 if (tniq.getShadowingStateSet()) {
396 fw.indent() << "shadowingStateSet\n";
397 fw.writeObject(*tniq.getShadowingStateSet());
399 fw.indent() << "num_passes " << tniq.passes.size() << "\n";
400 BOOST_FOREACH(const ref_ptr<Pass>& pass, tniq.passes) {
401 fw.writeObject(*pass);
408 osgDB::RegisterDotOsgWrapperProxy TechniqueProxy
411 "simgear::Technique",
412 "Object simgear::Technique",
414 &Technique_writeLocalData