3 # include <simgear_config.h>
6 #include "Technique.hxx"
9 #include <boost/foreach.hpp>
15 #include <osg/GLExtensions>
16 #include <osg/GL2Extensions>
18 #include <osgUtil/CullVisitor>
20 #include <osgDB/Registry>
21 #include <osgDB/Input>
22 #include <osgDB/ParameterOutput>
24 #include <simgear/props/props.hxx>
25 #include <simgear/structure/OSGUtils.hxx>
30 using namespace osgUtil;
35 struct ValidateOperation : GraphicsOperation
37 ValidateOperation(Technique* technique_)
38 : GraphicsOperation(opName, false), technique(technique_)
41 virtual void operator() (GraphicsContext* gc);
42 osg::ref_ptr<Technique> technique;
43 static const std::string opName;
46 const std::string ValidateOperation::opName("ValidateOperation");
49 void ValidateOperation::operator() (GraphicsContext* gc)
51 technique->validateInContext(gc);
55 Technique::Technique(bool alwaysValid)
56 : _alwaysValid(alwaysValid), _contextIdLocation(-1)
60 Technique::Technique(const Technique& rhs, const osg::CopyOp& copyop) :
61 _contextMap(rhs._contextMap), _alwaysValid(rhs._alwaysValid),
62 _shadowingStateSet(copyop(rhs._shadowingStateSet)),
63 _validExpression(rhs._validExpression),
64 _contextIdLocation(rhs._contextIdLocation)
66 for (std::vector<ref_ptr<Pass> >::const_iterator itr = rhs.passes.begin(),
67 end = rhs.passes.end();
70 passes.push_back(static_cast<Pass*>(copyop(itr->get())));
73 Technique::~Technique()
77 Technique::Status Technique::valid(osg::RenderInfo* renderInfo)
81 unsigned contextID = renderInfo->getContextID();
82 ContextInfo& contextInfo = _contextMap[contextID];
83 Status status = contextInfo.valid();
84 if (status != UNKNOWN)
86 Status newStatus = QUERY_IN_PROGRESS;
87 // lock and spawn validity check.
88 if (!contextInfo.valid.compareAndSwap(status, newStatus)) {
89 // Lost the race with another thread spawning a request
90 return contextInfo.valid();
92 ref_ptr<ValidateOperation> validOp = new ValidateOperation(this);
93 GraphicsContext* context = renderInfo->getState()->getGraphicsContext();
94 GraphicsThread* thread = context->getGraphicsThread();
96 thread->add(validOp.get());
98 context->add(validOp.get());
102 Technique::Status Technique::getValidStatus(const RenderInfo* renderInfo) const
106 ContextInfo& contextInfo = _contextMap[renderInfo->getContextID()];
107 return contextInfo.valid();
110 void Technique::validateInContext(GraphicsContext* gc)
112 unsigned int contextId = gc->getState()->getContextID();
113 ContextInfo& contextInfo = _contextMap[contextId];
114 Status oldVal = contextInfo.valid();
115 Status newVal = INVALID;
116 expression::FixedLengthBinding<1> binding;
117 binding.getBindings()[_contextIdLocation].val.intVal = contextId;
118 if (_validExpression->getValue(&binding))
120 contextInfo.valid.compareAndSwap(oldVal, newVal);
125 enum NumDrawables {NUM_DRAWABLES = 128};
128 EffectGeode::DrawablesIterator
129 Technique::processDrawables(const EffectGeode::DrawablesIterator& begin,
130 const EffectGeode::DrawablesIterator& end,
132 bool isCullingActive)
134 RefMatrix& matrix = *cv->getModelViewMatrix();
135 float depth[NUM_DRAWABLES];
136 EffectGeode::DrawablesIterator itr = begin;
138 = cv->getComputeNearFarMode() != CullVisitor::DO_NOT_COMPUTE_NEAR_FAR;
139 for (int i = 0; i < NUM_DRAWABLES && itr != end; ++itr, ++i) {
140 Drawable* drawable = itr->get();
141 const BoundingBox& bb = drawable->getBound();
142 if ((drawable->getCullCallback()
143 && drawable->getCullCallback()->cull(cv, drawable,
144 &cv->getRenderInfo()))
145 || (isCullingActive && cv->isCulled(bb))) {
149 if (computeNearFar && bb.valid()) {
150 if (!cv->updateCalculatedNearFar(matrix, *drawable, false)) {
155 depth[i] = (bb.valid()
156 ? cv->getDistanceFromEyePoint(bb.center(), false)
161 EffectGeode::DrawablesIterator drawablesEnd = itr;
162 BOOST_FOREACH(ref_ptr<Pass>& pass, passes)
164 cv->pushStateSet(pass.get());
166 for (itr = begin; itr != drawablesEnd; ++itr, ++i) {
167 if (depth[i] != FLT_MAX)
168 cv->addDrawableAndDepth(itr->get(), &matrix, depth[i]);
175 void Technique::resizeGLObjectBuffers(unsigned int maxSize)
177 if (_shadowingStateSet.valid())
178 _shadowingStateSet->resizeGLObjectBuffers(maxSize);
179 BOOST_FOREACH(ref_ptr<Pass>& pass, passes) {
180 pass->resizeGLObjectBuffers(maxSize);
182 _contextMap.resize(maxSize);
185 void Technique::releaseGLObjects(osg::State* state) const
187 if (_shadowingStateSet.valid())
188 _shadowingStateSet->releaseGLObjects(state);
189 BOOST_FOREACH(const ref_ptr<Pass>& pass, passes)
191 pass->releaseGLObjects(state);
194 for (int i = 0; i < (int)_contextMap.size(); ++i) {
195 ContextInfo& info = _contextMap[i];
196 Status oldVal = info.valid();
197 info.valid.compareAndSwap(oldVal, UNKNOWN);
200 ContextInfo& info = _contextMap[state->getContextID()];
201 Status oldVal = info.valid();
202 info.valid.compareAndSwap(oldVal, UNKNOWN);
206 void Technique::setValidExpression(SGExpressionb* exp,
207 const simgear::expression
208 ::BindingLayout& layout)
210 using namespace simgear::expression;
211 _validExpression = exp;
212 VariableBinding binding;
213 if (layout.findBinding("__contextId", binding))
214 _contextIdLocation = binding.location;
217 class GLVersionExpression : public SGExpression<float>
220 void eval(float& value, const expression::Binding*) const
222 #ifdef TECHNIQUE_TEST_EXTENSIONS
225 value = getGLVersionNumber();
230 Expression* glVersionParser(const SGPropertyNode* exp,
231 expression::Parser* parser)
233 return new GLVersionExpression();
236 expression::ExpParserRegistrar glVersionRegistrar("glversion", glVersionParser);
238 class ExtensionSupportedExpression
239 : public GeneralNaryExpression<bool, int>
242 ExtensionSupportedExpression() {}
243 ExtensionSupportedExpression(const string& extString)
244 : _extString(extString)
247 const string& getExtensionString() { return _extString; }
248 void setExtensionString(const string& extString) { _extString = extString; }
249 void eval(bool&value, const expression::Binding* b) const
251 int contextId = getOperand(0)->getValue(b);
252 value = isGLExtensionSupported((unsigned)contextId, _extString.c_str());
258 Expression* extensionSupportedParser(const SGPropertyNode* exp,
259 expression::Parser* parser)
261 if (exp->getType() == props::STRING
262 || exp->getType() == props::UNSPECIFIED) {
263 ExtensionSupportedExpression* esp
264 = new ExtensionSupportedExpression(exp->getStringValue());
265 int location = parser->getBindingLayout().addBinding("__contextId",
267 VariableExpression<int>* contextExp
268 = new VariableExpression<int>(location);
269 esp->addOperand(contextExp);
272 throw expression::ParseError("extension-supported expression has wrong type");
275 expression::ExpParserRegistrar
276 extensionSupportedRegistrar("extension-supported", extensionSupportedParser);
278 class GLShaderLanguageExpression : public GeneralNaryExpression<float, int>
281 void eval(float& value, const expression::Binding* b) const
284 int contextId = getOperand(0)->getValue(b);
285 GL2Extensions* extensions
286 = GL2Extensions::Get(static_cast<unsigned>(contextId), true);
289 if (!extensions->isGlslSupported())
291 value = extensions->getLanguageVersion();
295 Expression* shaderLanguageParser(const SGPropertyNode* exp,
296 expression::Parser* parser)
298 GLShaderLanguageExpression* slexp = new GLShaderLanguageExpression;
299 int location = parser->getBindingLayout().addBinding("__contextId",
301 VariableExpression<int>* contextExp = new VariableExpression<int>(location);
302 slexp->addOperand(contextExp);
306 expression::ExpParserRegistrar shaderLanguageRegistrar("shader-language",
310 void Technique::setGLExtensionsPred(float glVersion,
311 const std::vector<std::string>& extensions)
314 using namespace expression;
315 BindingLayout layout;
316 int contextLoc = layout.addBinding("__contextId", INT);
317 VariableExpression<int>* contextExp
318 = new VariableExpression<int>(contextLoc);
319 SGExpression<bool>* versionTest
320 = makePredicate<std::less_equal>(new SGConstExpression<float>(glVersion),
321 new GLVersionExpression);
322 AndExpression* extensionsExp = 0;
323 for (vector<string>::const_iterator itr = extensions.begin(),
324 e = extensions.end();
328 extensionsExp = new AndExpression;
329 ExtensionSupportedExpression* supported
330 = new ExtensionSupportedExpression(*itr);
331 supported->addOperand(contextExp);
332 extensionsExp->addOperand(supported);
334 SGExpressionb* predicate = 0;
336 OrExpression* orExp = new OrExpression;
337 orExp->addOperand(versionTest);
338 orExp->addOperand(extensionsExp);
341 predicate = versionTest;
343 setValidExpression(predicate, layout);
346 void Technique::refreshValidity()
348 for (int i = 0; i < (int)_contextMap.size(); ++i) {
349 ContextInfo& info = _contextMap[i];
350 Status oldVal = info.valid();
351 // What happens if we lose the race here?
352 info.valid.compareAndSwap(oldVal, UNKNOWN);
356 bool Technique_writeLocalData(const Object& obj, osgDB::Output& fw)
358 const Technique& tniq = static_cast<const Technique&>(obj);
359 fw.indent() << "alwaysValid "
360 << (tniq.getAlwaysValid() ? "TRUE\n" : "FALSE\n");
362 fw.indent() << "glVersion " << tniq.getGLVersion() << "\n";
364 if (tniq.getShadowingStateSet()) {
365 fw.indent() << "shadowingStateSet\n";
366 fw.writeObject(*tniq.getShadowingStateSet());
368 fw.indent() << "num_passes " << tniq.passes.size() << "\n";
369 BOOST_FOREACH(const ref_ptr<Pass>& pass, tniq.passes) {
370 fw.writeObject(*pass);
377 osgDB::RegisterDotOsgWrapperProxy TechniqueProxy
380 "simgear::Technique",
381 "Object simgear::Technique",
383 &Technique_writeLocalData