1 #include "Technique.hxx"
4 #include <boost/bind.hpp>
5 #include <boost/foreach.hpp>
11 #include <osg/GLExtensions>
13 #include <osgUtil/CullVisitor>
15 #include <osgDB/Registry>
16 #include <osgDB/Input>
17 #include <osgDB/ParameterOutput>
19 #include <simgear/props/props.hxx>
20 #include <simgear/structure/OSGUtils.hxx>
25 using namespace osgUtil;
30 struct ValidateOperation : GraphicsOperation
32 ValidateOperation(Technique* technique_)
33 : GraphicsOperation(opName, false), technique(technique_)
36 virtual void operator() (GraphicsContext* gc);
37 osg::ref_ptr<Technique> technique;
38 static const std::string opName;
41 const std::string ValidateOperation::opName("ValidateOperation");
44 void ValidateOperation::operator() (GraphicsContext* gc)
46 technique->validateInContext(gc);
50 Technique::Technique(bool alwaysValid)
51 : _alwaysValid(alwaysValid), _contextIdLocation(-1)
55 Technique::Technique(const Technique& rhs, const osg::CopyOp& copyop) :
56 _contextMap(rhs._contextMap), _alwaysValid(rhs._alwaysValid),
57 _shadowingStateSet(rhs._shadowingStateSet),
58 _validExpression(rhs._validExpression),
59 _contextIdLocation(rhs._contextIdLocation)
62 using namespace boost;
63 transform(rhs.passes.begin(), rhs.passes.end(),
64 back_inserter(passes),
65 bind(simgear::clone_ref<Pass>, _1, copyop));
69 Technique::~Technique()
73 Technique::Status Technique::valid(osg::RenderInfo* renderInfo)
77 unsigned contextID = renderInfo->getContextID();
78 ContextInfo& contextInfo = _contextMap[contextID];
79 Status status = contextInfo.valid();
80 if (status != UNKNOWN)
82 Status newStatus = QUERY_IN_PROGRESS;
83 // lock and spawn validity check.
84 if (!contextInfo.valid.compareAndSwap(status, newStatus)) {
85 // Lost the race with another thread spawning a request
86 return contextInfo.valid();
88 ref_ptr<ValidateOperation> validOp = new ValidateOperation(this);
89 GraphicsContext* context = renderInfo->getState()->getGraphicsContext();
90 GraphicsThread* thread = context->getGraphicsThread();
92 thread->add(validOp.get());
94 context->add(validOp.get());
98 Technique::Status Technique::getValidStatus(const RenderInfo* renderInfo) const
102 ContextInfo& contextInfo = _contextMap[renderInfo->getContextID()];
103 return contextInfo.valid();
106 void Technique::validateInContext(GraphicsContext* gc)
108 unsigned int contextId = gc->getState()->getContextID();
109 ContextInfo& contextInfo = _contextMap[contextId];
110 Status oldVal = contextInfo.valid();
111 Status newVal = INVALID;
112 expression::FixedLengthBinding<1> binding;
113 binding.getBindings()[_contextIdLocation].val.intVal = contextId;
114 if (_validExpression->getValue(&binding))
116 contextInfo.valid.compareAndSwap(oldVal, newVal);
121 enum NumDrawables {NUM_DRAWABLES = 128};
124 EffectGeode::DrawablesIterator
125 Technique::processDrawables(const EffectGeode::DrawablesIterator& begin,
126 const EffectGeode::DrawablesIterator& end,
128 bool isCullingActive)
130 RefMatrix& matrix = *cv->getModelViewMatrix();
131 float depth[NUM_DRAWABLES];
132 EffectGeode::DrawablesIterator itr = begin;
134 = cv->getComputeNearFarMode() != CullVisitor::DO_NOT_COMPUTE_NEAR_FAR;
135 for (int i = 0; i < NUM_DRAWABLES && itr != end; ++itr, ++i) {
136 Drawable* drawable = itr->get();
137 const BoundingBox& bb = drawable->getBound();
138 if ((drawable->getCullCallback()
139 && drawable->getCullCallback()->cull(cv, drawable,
140 &cv->getRenderInfo()))
141 || (isCullingActive && cv->isCulled(bb))) {
145 if (computeNearFar && bb.valid()) {
146 if (!cv->updateCalculatedNearFar(matrix, *drawable, false)) {
151 depth[i] = (bb.valid()
152 ? cv->getDistanceFromEyePoint(bb.center(), false)
157 EffectGeode::DrawablesIterator drawablesEnd = itr;
158 BOOST_FOREACH(ref_ptr<Pass>& pass, passes)
160 cv->pushStateSet(pass.get());
162 for (itr = begin; itr != drawablesEnd; ++itr, ++i) {
163 if (depth[i] != FLT_MAX)
164 cv->addDrawableAndDepth(itr->get(), &matrix, depth[i]);
171 void Technique::resizeGLObjectBuffers(unsigned int maxSize)
173 if (_shadowingStateSet.valid())
174 _shadowingStateSet->resizeGLObjectBuffers(maxSize);
175 BOOST_FOREACH(ref_ptr<Pass>& pass, passes) {
176 pass->resizeGLObjectBuffers(maxSize);
178 _contextMap.resize(maxSize);
181 void Technique::releaseGLObjects(osg::State* state) const
183 if (_shadowingStateSet.valid())
184 _shadowingStateSet->releaseGLObjects(state);
185 BOOST_FOREACH(const ref_ptr<Pass>& pass, passes)
187 pass->releaseGLObjects(state);
190 for (int i = 0; i < _contextMap.size(); ++i) {
191 ContextInfo& info = _contextMap[i];
192 Status oldVal = info.valid();
193 info.valid.compareAndSwap(oldVal, UNKNOWN);
196 ContextInfo& info = _contextMap[state->getContextID()];
197 Status oldVal = info.valid();
198 info.valid.compareAndSwap(oldVal, UNKNOWN);
202 void Technique::setValidExpression(SGExpressionb* exp,
203 const simgear::expression
204 ::BindingLayout& layout)
206 using namespace simgear::expression;
207 _validExpression = exp;
208 VariableBinding binding;
209 if (layout.findBinding("__contextId", binding))
210 _contextIdLocation = binding.location;
213 class GLVersionExpression : public SGExpression<float>
216 void eval(float& value, const expression::Binding*) const
218 #ifdef TECHNIQUE_TEST_EXTENSIONS
221 value = getGLVersionNumber();
226 Expression* glVersionParser(const SGPropertyNode* exp,
227 expression::Parser* parser)
229 return new GLVersionExpression();
232 expression::ExpParserRegistrar glVersionRegistrar("glversion", glVersionParser);
234 class ExtensionSupportedExpression
235 : public GeneralNaryExpression<bool, int>
238 ExtensionSupportedExpression() {}
239 ExtensionSupportedExpression(const string& extString)
240 : _extString(extString)
243 const string& getExtensionString() { return _extString; }
244 void setExtensionString(const string& extString) { _extString = extString; }
245 void eval(bool&value, const expression::Binding* b) const
247 int contextId = getOperand(0)->getValue(b);
248 value = isGLExtensionSupported((unsigned)contextId, _extString.c_str());
254 Expression* extensionSupportedParser(const SGPropertyNode* exp,
255 expression::Parser* parser)
257 if (exp->getType() == props::STRING
258 || exp->getType() == props::UNSPECIFIED) {
259 ExtensionSupportedExpression* esp
260 = new ExtensionSupportedExpression(exp->getStringValue());
261 int location = parser->getBindingLayout().addBinding("__contextId",
263 VariableExpression<int>* contextExp
264 = new VariableExpression<int>(location);
265 esp->addOperand(contextExp);
268 throw expression::ParseError("extension-supported expression has wrong type");
271 expression::ExpParserRegistrar
272 extensionSupportedRegistrar("extension-supported", extensionSupportedParser);
274 void Technique::setGLExtensionsPred(float glVersion,
275 const std::vector<std::string>& extensions)
278 using namespace expression;
279 BindingLayout layout;
280 int contextLoc = layout.addBinding("__contextId", INT);
281 VariableExpression<int>* contextExp
282 = new VariableExpression<int>(contextLoc);
283 SGExpression<bool>* versionTest
284 = makePredicate<std::less_equal>(new SGConstExpression<float>(glVersion),
285 new GLVersionExpression);
286 AndExpression* extensionsExp = 0;
287 for (vector<string>::const_iterator itr = extensions.begin(),
288 e = extensions.end();
292 extensionsExp = new AndExpression;
293 ExtensionSupportedExpression* supported
294 = new ExtensionSupportedExpression(*itr);
295 supported->addOperand(contextExp);
296 extensionsExp->addOperand(supported);
298 SGExpressionb* predicate = 0;
300 OrExpression* orExp = new OrExpression;
301 orExp->addOperand(versionTest);
302 orExp->addOperand(extensionsExp);
305 predicate = versionTest;
307 setValidExpression(predicate, layout);
310 void Technique::refreshValidity()
312 for (int i = 0; i < _contextMap.size(); ++i) {
313 ContextInfo& info = _contextMap[i];
314 Status oldVal = info.valid();
315 // What happens if we lose the race here?
316 info.valid.compareAndSwap(oldVal, UNKNOWN);
320 bool Technique_writeLocalData(const Object& obj, osgDB::Output& fw)
322 const Technique& tniq = static_cast<const Technique&>(obj);
323 fw.indent() << "alwaysValid "
324 << (tniq.getAlwaysValid() ? "TRUE\n" : "FALSE\n");
326 fw.indent() << "glVersion " << tniq.getGLVersion() << "\n";
328 if (tniq.getShadowingStateSet()) {
329 fw.indent() << "shadowingStateSet\n";
330 fw.writeObject(*tniq.getShadowingStateSet());
332 fw.indent() << "num_passes " << tniq.passes.size() << "\n";
333 BOOST_FOREACH(const ref_ptr<Pass>& pass, tniq.passes) {
334 fw.writeObject(*pass);
341 osgDB::RegisterDotOsgWrapperProxy TechniqueProxy
344 "simgear::Technique",
345 "Object simgear::Technique",
347 &Technique_writeLocalData