1 #include "Technique.hxx"
4 #include <boost/bind.hpp>
5 #include <boost/foreach.hpp>
10 #include <osg/GLExtensions>
12 #include <osgUtil/CullVisitor>
14 #include <osgDB/Registry>
15 #include <osgDB/Input>
16 #include <osgDB/ParameterOutput>
18 #include <simgear/props/props.hxx>
19 #include <simgear/structure/OSGUtils.hxx>
24 using namespace osgUtil;
29 struct ValidateOperation : GraphicsOperation
31 ValidateOperation(Technique* technique_)
32 : GraphicsOperation(opName, false), technique(technique_)
35 virtual void operator() (GraphicsContext* gc);
36 osg::ref_ptr<Technique> technique;
37 static const std::string opName;
40 const std::string ValidateOperation::opName("ValidateOperation");
43 void ValidateOperation::operator() (GraphicsContext* gc)
45 technique->validateInContext(gc);
49 Technique::Technique(bool alwaysValid)
50 : _alwaysValid(alwaysValid), _contextIdLocation(-1)
54 Technique::Technique(const Technique& rhs, const osg::CopyOp& copyop) :
55 _contextMap(rhs._contextMap), _alwaysValid(rhs._alwaysValid),
56 _shadowingStateSet(rhs._shadowingStateSet),
57 _validExpression(rhs._validExpression),
58 _contextIdLocation(rhs._contextIdLocation)
61 using namespace boost;
62 transform(rhs.passes.begin(), rhs.passes.end(),
63 backRefInsertIterator(passes),
64 bind(simgear::clone_ref<Pass>, _1, copyop));
68 Technique::~Technique()
72 Technique::Status Technique::valid(osg::RenderInfo* renderInfo)
76 unsigned contextID = renderInfo->getContextID();
77 ContextInfo& contextInfo = _contextMap[contextID];
78 Status status = contextInfo.valid();
79 if (status != UNKNOWN)
81 Status newStatus = QUERY_IN_PROGRESS;
82 // lock and spawn validity check.
83 if (!contextInfo.valid.compareAndSwap(status, newStatus)) {
84 // Lost the race with another thread spawning a request
85 return contextInfo.valid();
87 ref_ptr<ValidateOperation> validOp = new ValidateOperation(this);
88 GraphicsContext* context = renderInfo->getState()->getGraphicsContext();
89 GraphicsThread* thread = context->getGraphicsThread();
91 thread->add(validOp.get());
93 context->add(validOp.get());
97 Technique::Status Technique::getValidStatus(const RenderInfo* renderInfo) const
101 ContextInfo& contextInfo = _contextMap[renderInfo->getContextID()];
102 return contextInfo.valid();
105 void Technique::validateInContext(GraphicsContext* gc)
107 unsigned int contextId = gc->getState()->getContextID();
108 ContextInfo& contextInfo = _contextMap[contextId];
109 Status oldVal = contextInfo.valid();
110 Status newVal = INVALID;
111 expression::FixedLengthBinding<1> binding;
112 binding.getBindings()[_contextIdLocation].val.intVal = contextId;
113 if (_validExpression->getValue(&binding))
115 contextInfo.valid.compareAndSwap(oldVal, newVal);
120 enum NumDrawables {NUM_DRAWABLES = 128};
123 EffectGeode::DrawablesIterator
124 Technique::processDrawables(const EffectGeode::DrawablesIterator& begin,
125 const EffectGeode::DrawablesIterator& end,
127 bool isCullingActive)
129 RefMatrix& matrix = *cv->getModelViewMatrix();
130 float depth[NUM_DRAWABLES];
131 EffectGeode::DrawablesIterator itr = begin;
133 = cv->getComputeNearFarMode() != CullVisitor::DO_NOT_COMPUTE_NEAR_FAR;
134 for (int i = 0; i < NUM_DRAWABLES && itr != end; ++itr, ++i) {
135 Drawable* drawable = itr->get();
136 const BoundingBox& bb = drawable->getBound();
137 if ((drawable->getCullCallback()
138 && drawable->getCullCallback()->cull(cv, drawable,
139 &cv->getRenderInfo()))
140 || (isCullingActive && cv->isCulled(bb))) {
144 if (computeNearFar && bb.valid()) {
145 if (!cv->updateCalculatedNearFar(matrix, *drawable, false)) {
150 depth[i] = (bb.valid()
151 ? cv->getDistanceFromEyePoint(bb.center(), false)
156 EffectGeode::DrawablesIterator drawablesEnd = itr;
157 BOOST_FOREACH(ref_ptr<Pass>& pass, passes)
159 cv->pushStateSet(pass.get());
161 for (itr = begin; itr != drawablesEnd; ++itr, ++i) {
162 if (depth[i] != FLT_MAX)
163 cv->addDrawableAndDepth(itr->get(), &matrix, depth[i]);
170 void Technique::resizeGLObjectBuffers(unsigned int maxSize)
172 if (_shadowingStateSet.valid())
173 _shadowingStateSet->resizeGLObjectBuffers(maxSize);
174 BOOST_FOREACH(ref_ptr<Pass>& pass, passes) {
175 pass->resizeGLObjectBuffers(maxSize);
177 _contextMap.resize(maxSize);
180 void Technique::releaseGLObjects(osg::State* state) const
182 if (_shadowingStateSet.valid())
183 _shadowingStateSet->releaseGLObjects(state);
184 BOOST_FOREACH(const ref_ptr<Pass>& pass, passes)
186 pass->releaseGLObjects(state);
189 for (int i = 0; i < _contextMap.size(); ++i) {
190 ContextInfo& info = _contextMap[i];
191 Status oldVal = info.valid();
192 info.valid.compareAndSwap(oldVal, UNKNOWN);
195 ContextInfo& info = _contextMap[state->getContextID()];
196 Status oldVal = info.valid();
197 info.valid.compareAndSwap(oldVal, UNKNOWN);
201 void Technique::setValidExpression(SGExpressionb* exp,
202 const simgear::expression
203 ::BindingLayout& layout)
205 using namespace simgear::expression;
206 _validExpression = exp;
207 VariableBinding binding;
208 if (layout.findBinding("__contextId", binding))
209 _contextIdLocation = binding.location;
212 class GLVersionExpression : public SGExpression<float>
215 void eval(float& value, const expression::Binding*) const
217 #ifdef TECHNIQUE_TEST_EXTENSIONS
220 value = getGLVersionNumber();
225 Expression* glVersionParser(const SGPropertyNode* exp,
226 expression::Parser* parser)
228 return new GLVersionExpression();
231 expression::ExpParserRegistrar glVersionRegistrar("glversion", glVersionParser);
233 class ExtensionSupportedExpression
234 : public GeneralNaryExpression<bool, int>
237 ExtensionSupportedExpression() {}
238 ExtensionSupportedExpression(const string& extString)
239 : _extString(extString)
242 const string& getExtensionString() { return _extString; }
243 void setExtensionString(const string& extString) { _extString = extString; }
244 void eval(bool&value, const expression::Binding* b) const
246 int contextId = getOperand(0)->getValue(b);
247 value = isGLExtensionSupported((unsigned)contextId, _extString.c_str());
253 Expression* extensionSupportedParser(const SGPropertyNode* exp,
254 expression::Parser* parser)
256 if (exp->getType() == props::STRING
257 || exp->getType() == props::UNSPECIFIED) {
258 ExtensionSupportedExpression* esp
259 = new ExtensionSupportedExpression(exp->getStringValue());
260 int location = parser->getBindingLayout().addBinding("__contextId",
262 VariableExpression<int>* contextExp
263 = new VariableExpression<int>(location);
264 esp->addOperand(contextExp);
267 throw expression::ParseError("extension-supported expression has wrong type");
270 expression::ExpParserRegistrar
271 extensionSupportedRegistrar("extension-supported", extensionSupportedParser);
273 void Technique::setGLExtensionsPred(float glVersion,
274 const std::vector<std::string>& extensions)
277 using namespace expression;
278 BindingLayout layout;
279 int contextLoc = layout.addBinding("__contextId", INT);
280 VariableExpression<int>* contextExp
281 = new VariableExpression<int>(contextLoc);
282 SGExpression<bool>* versionTest
283 = makePredicate<std::less_equal>(new SGConstExpression<float>(glVersion),
284 new GLVersionExpression);
285 AndExpression* extensionsExp = 0;
286 for (vector<string>::const_iterator itr = extensions.begin(),
287 e = extensions.end();
291 extensionsExp = new AndExpression;
292 ExtensionSupportedExpression* supported
293 = new ExtensionSupportedExpression(*itr);
294 supported->addOperand(contextExp);
295 extensionsExp->addOperand(supported);
297 SGExpressionb* predicate = 0;
299 OrExpression* orExp = new OrExpression;
300 orExp->addOperand(versionTest);
301 orExp->addOperand(extensionsExp);
304 predicate = versionTest;
306 setValidExpression(predicate, layout);
309 void Technique::refreshValidity()
311 for (int i = 0; i < _contextMap.size(); ++i) {
312 ContextInfo& info = _contextMap[i];
313 Status oldVal = info.valid();
314 // What happens if we lose the race here?
315 info.valid.compareAndSwap(oldVal, UNKNOWN);
319 bool Technique_writeLocalData(const Object& obj, osgDB::Output& fw)
321 const Technique& tniq = static_cast<const Technique&>(obj);
322 fw.indent() << "alwaysValid "
323 << (tniq.getAlwaysValid() ? "TRUE\n" : "FALSE\n");
325 fw.indent() << "glVersion " << tniq.getGLVersion() << "\n";
327 if (tniq.getShadowingStateSet()) {
328 fw.indent() << "shadowingStateSet\n";
329 fw.writeObject(*tniq.getShadowingStateSet());
331 fw.indent() << "num_passes " << tniq.passes.size() << "\n";
332 BOOST_FOREACH(const ref_ptr<Pass>& pass, tniq.passes) {
333 fw.writeObject(*pass);
340 osgDB::RegisterDotOsgWrapperProxy TechniqueProxy
343 "simgear::Technique",
344 "Object simgear::Technique",
346 &Technique_writeLocalData