3 # include <simgear_config.h>
6 #include "Technique.hxx"
9 #include <boost/bind.hpp>
10 #include <boost/foreach.hpp>
16 #include <osg/GLExtensions>
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(rhs._shadowingStateSet),
63 _validExpression(rhs._validExpression),
64 _contextIdLocation(rhs._contextIdLocation)
67 using namespace boost;
68 transform(rhs.passes.begin(), rhs.passes.end(),
69 back_inserter(passes),
70 bind(simgear::clone_ref<Pass>, _1, copyop));
74 Technique::~Technique()
78 Technique::Status Technique::valid(osg::RenderInfo* renderInfo)
82 unsigned contextID = renderInfo->getContextID();
83 ContextInfo& contextInfo = _contextMap[contextID];
84 Status status = contextInfo.valid();
85 if (status != UNKNOWN)
87 Status newStatus = QUERY_IN_PROGRESS;
88 // lock and spawn validity check.
89 if (!contextInfo.valid.compareAndSwap(status, newStatus)) {
90 // Lost the race with another thread spawning a request
91 return contextInfo.valid();
93 ref_ptr<ValidateOperation> validOp = new ValidateOperation(this);
94 GraphicsContext* context = renderInfo->getState()->getGraphicsContext();
95 GraphicsThread* thread = context->getGraphicsThread();
97 thread->add(validOp.get());
99 context->add(validOp.get());
103 Technique::Status Technique::getValidStatus(const RenderInfo* renderInfo) const
107 ContextInfo& contextInfo = _contextMap[renderInfo->getContextID()];
108 return contextInfo.valid();
111 void Technique::validateInContext(GraphicsContext* gc)
113 unsigned int contextId = gc->getState()->getContextID();
114 ContextInfo& contextInfo = _contextMap[contextId];
115 Status oldVal = contextInfo.valid();
116 Status newVal = INVALID;
117 expression::FixedLengthBinding<1> binding;
118 binding.getBindings()[_contextIdLocation].val.intVal = contextId;
119 if (_validExpression->getValue(&binding))
121 contextInfo.valid.compareAndSwap(oldVal, newVal);
126 enum NumDrawables {NUM_DRAWABLES = 128};
129 EffectGeode::DrawablesIterator
130 Technique::processDrawables(const EffectGeode::DrawablesIterator& begin,
131 const EffectGeode::DrawablesIterator& end,
133 bool isCullingActive)
135 RefMatrix& matrix = *cv->getModelViewMatrix();
136 float depth[NUM_DRAWABLES];
137 EffectGeode::DrawablesIterator itr = begin;
139 = cv->getComputeNearFarMode() != CullVisitor::DO_NOT_COMPUTE_NEAR_FAR;
140 for (int i = 0; i < NUM_DRAWABLES && itr != end; ++itr, ++i) {
141 Drawable* drawable = itr->get();
142 const BoundingBox& bb = drawable->getBound();
143 if ((drawable->getCullCallback()
144 && drawable->getCullCallback()->cull(cv, drawable,
145 &cv->getRenderInfo()))
146 || (isCullingActive && cv->isCulled(bb))) {
150 if (computeNearFar && bb.valid()) {
151 if (!cv->updateCalculatedNearFar(matrix, *drawable, false)) {
156 depth[i] = (bb.valid()
157 ? cv->getDistanceFromEyePoint(bb.center(), false)
162 EffectGeode::DrawablesIterator drawablesEnd = itr;
163 BOOST_FOREACH(ref_ptr<Pass>& pass, passes)
165 cv->pushStateSet(pass.get());
167 for (itr = begin; itr != drawablesEnd; ++itr, ++i) {
168 if (depth[i] != FLT_MAX)
169 cv->addDrawableAndDepth(itr->get(), &matrix, depth[i]);
176 void Technique::resizeGLObjectBuffers(unsigned int maxSize)
178 if (_shadowingStateSet.valid())
179 _shadowingStateSet->resizeGLObjectBuffers(maxSize);
180 BOOST_FOREACH(ref_ptr<Pass>& pass, passes) {
181 pass->resizeGLObjectBuffers(maxSize);
183 _contextMap.resize(maxSize);
186 void Technique::releaseGLObjects(osg::State* state) const
188 if (_shadowingStateSet.valid())
189 _shadowingStateSet->releaseGLObjects(state);
190 BOOST_FOREACH(const ref_ptr<Pass>& pass, passes)
192 pass->releaseGLObjects(state);
195 for (int i = 0; i < (int)_contextMap.size(); ++i) {
196 ContextInfo& info = _contextMap[i];
197 Status oldVal = info.valid();
198 info.valid.compareAndSwap(oldVal, UNKNOWN);
201 ContextInfo& info = _contextMap[state->getContextID()];
202 Status oldVal = info.valid();
203 info.valid.compareAndSwap(oldVal, UNKNOWN);
207 void Technique::setValidExpression(SGExpressionb* exp,
208 const simgear::expression
209 ::BindingLayout& layout)
211 using namespace simgear::expression;
212 _validExpression = exp;
213 VariableBinding binding;
214 if (layout.findBinding("__contextId", binding))
215 _contextIdLocation = binding.location;
218 class GLVersionExpression : public SGExpression<float>
221 void eval(float& value, const expression::Binding*) const
223 #ifdef TECHNIQUE_TEST_EXTENSIONS
226 value = getGLVersionNumber();
231 Expression* glVersionParser(const SGPropertyNode* exp,
232 expression::Parser* parser)
234 return new GLVersionExpression();
237 expression::ExpParserRegistrar glVersionRegistrar("glversion", glVersionParser);
239 class ExtensionSupportedExpression
240 : public GeneralNaryExpression<bool, int>
243 ExtensionSupportedExpression() {}
244 ExtensionSupportedExpression(const string& extString)
245 : _extString(extString)
248 const string& getExtensionString() { return _extString; }
249 void setExtensionString(const string& extString) { _extString = extString; }
250 void eval(bool&value, const expression::Binding* b) const
252 int contextId = getOperand(0)->getValue(b);
253 value = isGLExtensionSupported((unsigned)contextId, _extString.c_str());
259 Expression* extensionSupportedParser(const SGPropertyNode* exp,
260 expression::Parser* parser)
262 if (exp->getType() == props::STRING
263 || exp->getType() == props::UNSPECIFIED) {
264 ExtensionSupportedExpression* esp
265 = new ExtensionSupportedExpression(exp->getStringValue());
266 int location = parser->getBindingLayout().addBinding("__contextId",
268 VariableExpression<int>* contextExp
269 = new VariableExpression<int>(location);
270 esp->addOperand(contextExp);
273 throw expression::ParseError("extension-supported expression has wrong type");
276 expression::ExpParserRegistrar
277 extensionSupportedRegistrar("extension-supported", extensionSupportedParser);
279 void Technique::setGLExtensionsPred(float glVersion,
280 const std::vector<std::string>& extensions)
283 using namespace expression;
284 BindingLayout layout;
285 int contextLoc = layout.addBinding("__contextId", INT);
286 VariableExpression<int>* contextExp
287 = new VariableExpression<int>(contextLoc);
288 SGExpression<bool>* versionTest
289 = makePredicate<std::less_equal>(new SGConstExpression<float>(glVersion),
290 new GLVersionExpression);
291 AndExpression* extensionsExp = 0;
292 for (vector<string>::const_iterator itr = extensions.begin(),
293 e = extensions.end();
297 extensionsExp = new AndExpression;
298 ExtensionSupportedExpression* supported
299 = new ExtensionSupportedExpression(*itr);
300 supported->addOperand(contextExp);
301 extensionsExp->addOperand(supported);
303 SGExpressionb* predicate = 0;
305 OrExpression* orExp = new OrExpression;
306 orExp->addOperand(versionTest);
307 orExp->addOperand(extensionsExp);
310 predicate = versionTest;
312 setValidExpression(predicate, layout);
315 void Technique::refreshValidity()
317 for (int i = 0; i < (int)_contextMap.size(); ++i) {
318 ContextInfo& info = _contextMap[i];
319 Status oldVal = info.valid();
320 // What happens if we lose the race here?
321 info.valid.compareAndSwap(oldVal, UNKNOWN);
325 bool Technique_writeLocalData(const Object& obj, osgDB::Output& fw)
327 const Technique& tniq = static_cast<const Technique&>(obj);
328 fw.indent() << "alwaysValid "
329 << (tniq.getAlwaysValid() ? "TRUE\n" : "FALSE\n");
331 fw.indent() << "glVersion " << tniq.getGLVersion() << "\n";
333 if (tniq.getShadowingStateSet()) {
334 fw.indent() << "shadowingStateSet\n";
335 fw.writeObject(*tniq.getShadowingStateSet());
337 fw.indent() << "num_passes " << tniq.passes.size() << "\n";
338 BOOST_FOREACH(const ref_ptr<Pass>& pass, tniq.passes) {
339 fw.writeObject(*pass);
346 osgDB::RegisterDotOsgWrapperProxy TechniqueProxy
349 "simgear::Technique",
350 "Object simgear::Technique",
352 &Technique_writeLocalData