3 # include <simgear_config.h>
6 #include "Technique.hxx"
9 #include <boost/foreach.hpp>
15 #include <osg/GLExtensions>
17 #include <osgUtil/CullVisitor>
19 #include <osgDB/Registry>
20 #include <osgDB/Input>
21 #include <osgDB/ParameterOutput>
23 #include <simgear/props/props.hxx>
24 #include <simgear/structure/OSGUtils.hxx>
29 using namespace osgUtil;
34 struct ValidateOperation : GraphicsOperation
36 ValidateOperation(Technique* technique_)
37 : GraphicsOperation(opName, false), technique(technique_)
40 virtual void operator() (GraphicsContext* gc);
41 osg::ref_ptr<Technique> technique;
42 static const std::string opName;
45 const std::string ValidateOperation::opName("ValidateOperation");
48 void ValidateOperation::operator() (GraphicsContext* gc)
50 technique->validateInContext(gc);
54 Technique::Technique(bool alwaysValid)
55 : _alwaysValid(alwaysValid), _contextIdLocation(-1)
59 Technique::Technique(const Technique& rhs, const osg::CopyOp& copyop) :
60 _contextMap(rhs._contextMap), _alwaysValid(rhs._alwaysValid),
61 _shadowingStateSet(copyop(rhs._shadowingStateSet)),
62 _validExpression(rhs._validExpression),
63 _contextIdLocation(rhs._contextIdLocation)
65 for (std::vector<ref_ptr<Pass> >::const_iterator itr = rhs.passes.begin(),
66 end = rhs.passes.end();
69 passes.push_back(static_cast<Pass*>(copyop(itr->get())));
72 Technique::~Technique()
76 Technique::Status Technique::valid(osg::RenderInfo* renderInfo)
80 unsigned contextID = renderInfo->getContextID();
81 ContextInfo& contextInfo = _contextMap[contextID];
82 Status status = contextInfo.valid();
83 if (status != UNKNOWN)
85 Status newStatus = QUERY_IN_PROGRESS;
86 // lock and spawn validity check.
87 if (!contextInfo.valid.compareAndSwap(status, newStatus)) {
88 // Lost the race with another thread spawning a request
89 return contextInfo.valid();
91 ref_ptr<ValidateOperation> validOp = new ValidateOperation(this);
92 GraphicsContext* context = renderInfo->getState()->getGraphicsContext();
93 GraphicsThread* thread = context->getGraphicsThread();
95 thread->add(validOp.get());
97 context->add(validOp.get());
101 Technique::Status Technique::getValidStatus(const RenderInfo* renderInfo) const
105 ContextInfo& contextInfo = _contextMap[renderInfo->getContextID()];
106 return contextInfo.valid();
109 void Technique::validateInContext(GraphicsContext* gc)
111 unsigned int contextId = gc->getState()->getContextID();
112 ContextInfo& contextInfo = _contextMap[contextId];
113 Status oldVal = contextInfo.valid();
114 Status newVal = INVALID;
115 expression::FixedLengthBinding<1> binding;
116 binding.getBindings()[_contextIdLocation].val.intVal = contextId;
117 if (_validExpression->getValue(&binding))
119 contextInfo.valid.compareAndSwap(oldVal, newVal);
124 enum NumDrawables {NUM_DRAWABLES = 128};
127 EffectGeode::DrawablesIterator
128 Technique::processDrawables(const EffectGeode::DrawablesIterator& begin,
129 const EffectGeode::DrawablesIterator& end,
131 bool isCullingActive)
133 RefMatrix& matrix = *cv->getModelViewMatrix();
134 float depth[NUM_DRAWABLES];
135 EffectGeode::DrawablesIterator itr = begin;
137 = cv->getComputeNearFarMode() != CullVisitor::DO_NOT_COMPUTE_NEAR_FAR;
138 for (int i = 0; i < NUM_DRAWABLES && itr != end; ++itr, ++i) {
139 Drawable* drawable = itr->get();
140 const BoundingBox& bb = drawable->getBound();
141 if ((drawable->getCullCallback()
142 && drawable->getCullCallback()->cull(cv, drawable,
143 &cv->getRenderInfo()))
144 || (isCullingActive && cv->isCulled(bb))) {
148 if (computeNearFar && bb.valid()) {
149 if (!cv->updateCalculatedNearFar(matrix, *drawable, false)) {
154 depth[i] = (bb.valid()
155 ? cv->getDistanceFromEyePoint(bb.center(), false)
160 EffectGeode::DrawablesIterator drawablesEnd = itr;
161 BOOST_FOREACH(ref_ptr<Pass>& pass, passes)
163 cv->pushStateSet(pass.get());
165 for (itr = begin; itr != drawablesEnd; ++itr, ++i) {
166 if (depth[i] != FLT_MAX)
167 cv->addDrawableAndDepth(itr->get(), &matrix, depth[i]);
174 void Technique::resizeGLObjectBuffers(unsigned int maxSize)
176 if (_shadowingStateSet.valid())
177 _shadowingStateSet->resizeGLObjectBuffers(maxSize);
178 BOOST_FOREACH(ref_ptr<Pass>& pass, passes) {
179 pass->resizeGLObjectBuffers(maxSize);
181 _contextMap.resize(maxSize);
184 void Technique::releaseGLObjects(osg::State* state) const
186 if (_shadowingStateSet.valid())
187 _shadowingStateSet->releaseGLObjects(state);
188 BOOST_FOREACH(const ref_ptr<Pass>& pass, passes)
190 pass->releaseGLObjects(state);
193 for (int i = 0; i < (int)_contextMap.size(); ++i) {
194 ContextInfo& info = _contextMap[i];
195 Status oldVal = info.valid();
196 info.valid.compareAndSwap(oldVal, UNKNOWN);
199 ContextInfo& info = _contextMap[state->getContextID()];
200 Status oldVal = info.valid();
201 info.valid.compareAndSwap(oldVal, UNKNOWN);
205 void Technique::setValidExpression(SGExpressionb* exp,
206 const simgear::expression
207 ::BindingLayout& layout)
209 using namespace simgear::expression;
210 _validExpression = exp;
211 VariableBinding binding;
212 if (layout.findBinding("__contextId", binding))
213 _contextIdLocation = binding.location;
216 class GLVersionExpression : public SGExpression<float>
219 void eval(float& value, const expression::Binding*) const
221 #ifdef TECHNIQUE_TEST_EXTENSIONS
224 value = getGLVersionNumber();
229 Expression* glVersionParser(const SGPropertyNode* exp,
230 expression::Parser* parser)
232 return new GLVersionExpression();
235 expression::ExpParserRegistrar glVersionRegistrar("glversion", glVersionParser);
237 class ExtensionSupportedExpression
238 : public GeneralNaryExpression<bool, int>
241 ExtensionSupportedExpression() {}
242 ExtensionSupportedExpression(const string& extString)
243 : _extString(extString)
246 const string& getExtensionString() { return _extString; }
247 void setExtensionString(const string& extString) { _extString = extString; }
248 void eval(bool&value, const expression::Binding* b) const
250 int contextId = getOperand(0)->getValue(b);
251 value = isGLExtensionSupported((unsigned)contextId, _extString.c_str());
257 Expression* extensionSupportedParser(const SGPropertyNode* exp,
258 expression::Parser* parser)
260 if (exp->getType() == props::STRING
261 || exp->getType() == props::UNSPECIFIED) {
262 ExtensionSupportedExpression* esp
263 = new ExtensionSupportedExpression(exp->getStringValue());
264 int location = parser->getBindingLayout().addBinding("__contextId",
266 VariableExpression<int>* contextExp
267 = new VariableExpression<int>(location);
268 esp->addOperand(contextExp);
271 throw expression::ParseError("extension-supported expression has wrong type");
274 expression::ExpParserRegistrar
275 extensionSupportedRegistrar("extension-supported", extensionSupportedParser);
277 void Technique::setGLExtensionsPred(float glVersion,
278 const std::vector<std::string>& extensions)
281 using namespace expression;
282 BindingLayout layout;
283 int contextLoc = layout.addBinding("__contextId", INT);
284 VariableExpression<int>* contextExp
285 = new VariableExpression<int>(contextLoc);
286 SGExpression<bool>* versionTest
287 = makePredicate<std::less_equal>(new SGConstExpression<float>(glVersion),
288 new GLVersionExpression);
289 AndExpression* extensionsExp = 0;
290 for (vector<string>::const_iterator itr = extensions.begin(),
291 e = extensions.end();
295 extensionsExp = new AndExpression;
296 ExtensionSupportedExpression* supported
297 = new ExtensionSupportedExpression(*itr);
298 supported->addOperand(contextExp);
299 extensionsExp->addOperand(supported);
301 SGExpressionb* predicate = 0;
303 OrExpression* orExp = new OrExpression;
304 orExp->addOperand(versionTest);
305 orExp->addOperand(extensionsExp);
308 predicate = versionTest;
310 setValidExpression(predicate, layout);
313 void Technique::refreshValidity()
315 for (int i = 0; i < (int)_contextMap.size(); ++i) {
316 ContextInfo& info = _contextMap[i];
317 Status oldVal = info.valid();
318 // What happens if we lose the race here?
319 info.valid.compareAndSwap(oldVal, UNKNOWN);
323 bool Technique_writeLocalData(const Object& obj, osgDB::Output& fw)
325 const Technique& tniq = static_cast<const Technique&>(obj);
326 fw.indent() << "alwaysValid "
327 << (tniq.getAlwaysValid() ? "TRUE\n" : "FALSE\n");
329 fw.indent() << "glVersion " << tniq.getGLVersion() << "\n";
331 if (tniq.getShadowingStateSet()) {
332 fw.indent() << "shadowingStateSet\n";
333 fw.writeObject(*tniq.getShadowingStateSet());
335 fw.indent() << "num_passes " << tniq.passes.size() << "\n";
336 BOOST_FOREACH(const ref_ptr<Pass>& pass, tniq.passes) {
337 fw.writeObject(*pass);
344 osgDB::RegisterDotOsgWrapperProxy TechniqueProxy
347 "simgear::Technique",
348 "Object simgear::Technique",
350 &Technique_writeLocalData