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/structure/OSGUtils.hxx>
23 using namespace osgUtil;
28 struct ValidateOperation : GraphicsOperation
30 ValidateOperation(Technique* technique_)
31 : GraphicsOperation(opName, false), technique(technique_)
34 virtual void operator() (GraphicsContext* gc);
35 osg::ref_ptr<Technique> technique;
36 static const std::string opName;
39 const std::string ValidateOperation::opName("ValidateOperation");
42 void ValidateOperation::operator() (GraphicsContext* gc)
44 technique->validateInContext(gc);
48 Technique::Technique(bool alwaysValid)
49 : _alwaysValid(alwaysValid), _contextIdLocation(-1)
53 Technique::Technique(const Technique& rhs, const osg::CopyOp& copyop) :
54 _contextMap(rhs._contextMap), _alwaysValid(rhs._alwaysValid),
55 _shadowingStateSet(rhs._shadowingStateSet),
56 _validExpression(rhs._validExpression),
57 _contextIdLocation(rhs._contextIdLocation)
60 using namespace boost;
61 transform(rhs.passes.begin(), rhs.passes.end(),
62 backRefInsertIterator(passes),
63 bind(simgear::clone_ref<Pass>, _1, copyop));
67 Technique::~Technique()
71 Technique::Status Technique::valid(osg::RenderInfo* renderInfo)
75 unsigned contextID = renderInfo->getContextID();
76 ContextInfo& contextInfo = _contextMap[contextID];
77 Status status = contextInfo.valid();
78 if (status != UNKNOWN)
80 Status newStatus = QUERY_IN_PROGRESS;
81 // lock and spawn validity check.
82 if (!contextInfo.valid.compareAndSwap(status, newStatus)) {
83 // Lost the race with another thread spawning a request
84 return contextInfo.valid();
86 ref_ptr<ValidateOperation> validOp = new ValidateOperation(this);
87 GraphicsContext* context = renderInfo->getState()->getGraphicsContext();
88 GraphicsThread* thread = context->getGraphicsThread();
90 thread->add(validOp.get());
92 context->add(validOp.get());
96 Technique::Status Technique::getValidStatus(const RenderInfo* renderInfo) const
100 ContextInfo& contextInfo = _contextMap[renderInfo->getContextID()];
101 return contextInfo.valid();
104 void Technique::validateInContext(GraphicsContext* gc)
106 unsigned int contextId = gc->getState()->getContextID();
107 ContextInfo& contextInfo = _contextMap[contextId];
108 Status oldVal = contextInfo.valid();
109 Status newVal = INVALID;
110 expression::FixedLengthBinding<1> binding;
111 binding.getBindings()[_contextIdLocation].val.intVal = contextId;
112 if (_validExpression->getValue(&binding))
114 contextInfo.valid.compareAndSwap(oldVal, newVal);
119 enum NumDrawables {NUM_DRAWABLES = 128};
122 EffectGeode::DrawablesIterator
123 Technique::processDrawables(const EffectGeode::DrawablesIterator& begin,
124 const EffectGeode::DrawablesIterator& end,
126 bool isCullingActive)
128 RefMatrix& matrix = *cv->getModelViewMatrix();
129 float depth[NUM_DRAWABLES];
130 EffectGeode::DrawablesIterator itr = begin;
132 = cv->getComputeNearFarMode() != CullVisitor::DO_NOT_COMPUTE_NEAR_FAR;
133 for (int i = 0; i < NUM_DRAWABLES && itr != end; ++itr, ++i) {
134 Drawable* drawable = itr->get();
135 const BoundingBox& bb = drawable->getBound();
136 if ((drawable->getCullCallback()
137 && drawable->getCullCallback()->cull(cv, drawable,
138 &cv->getRenderInfo()))
139 || (isCullingActive && cv->isCulled(bb))) {
143 if (computeNearFar && bb.valid()) {
144 if (!cv->updateCalculatedNearFar(matrix, *drawable, false)) {
149 depth[i] = (bb.valid()
150 ? cv->getDistanceFromEyePoint(bb.center(), false)
155 EffectGeode::DrawablesIterator drawablesEnd = itr;
156 BOOST_FOREACH(ref_ptr<Pass>& pass, passes)
158 cv->pushStateSet(pass.get());
160 for (itr = begin; itr != drawablesEnd; ++itr, ++i) {
161 if (depth[i] != FLT_MAX)
162 cv->addDrawableAndDepth(itr->get(), &matrix, depth[i]);
169 void Technique::resizeGLObjectBuffers(unsigned int maxSize)
171 if (_shadowingStateSet.valid())
172 _shadowingStateSet->resizeGLObjectBuffers(maxSize);
173 BOOST_FOREACH(ref_ptr<Pass>& pass, passes) {
174 pass->resizeGLObjectBuffers(maxSize);
176 _contextMap.resize(maxSize);
179 void Technique::releaseGLObjects(osg::State* state) const
181 if (_shadowingStateSet.valid())
182 _shadowingStateSet->releaseGLObjects(state);
183 BOOST_FOREACH(const ref_ptr<Pass>& pass, passes)
185 pass->releaseGLObjects(state);
188 for (int i = 0; i < _contextMap.size(); ++i) {
189 ContextInfo& info = _contextMap[i];
190 Status oldVal = info.valid();
191 info.valid.compareAndSwap(oldVal, UNKNOWN);
194 ContextInfo& info = _contextMap[state->getContextID()];
195 Status oldVal = info.valid();
196 info.valid.compareAndSwap(oldVal, UNKNOWN);
200 void Technique::setValidExpression(SGExpressionb* exp,
201 const simgear::expression
202 ::BindingLayout& layout)
204 using namespace simgear::expression;
205 _validExpression = exp;
206 VariableBinding binding;
207 if (layout.findBinding("__contextId", binding))
208 _contextIdLocation = binding.location;
211 class GLVersionExpression : public SGExpression<float>
214 void eval(float& value, const expression::Binding*) const
216 value = getGLVersionNumber();
220 class ExtensionSupportedExpression
221 : public GeneralNaryExpression<bool, int>
224 ExtensionSupportedExpression() {}
225 ExtensionSupportedExpression(const string& extString)
226 : _extString(extString)
229 const string& getExtensionString() { return _extString; }
230 void setExtensionString(const string& extString) { _extString = extString; }
231 void eval(bool&value, const expression::Binding* b) const
233 int contextId = getOperand(0)->getValue(b);
234 value = isGLExtensionSupported((unsigned)contextId, _extString.c_str());
240 void Technique::setGLExtensionsPred(float glVersion,
241 const std::vector<std::string>& extensions)
244 using namespace expression;
245 BindingLayout layout;
246 int contextLoc = layout.addBinding("__contextId", INT);
247 VariableExpression<int>* contextExp
248 = new VariableExpression<int>(contextLoc);
249 LessEqualExpression<float>* versionTest
250 = new LessEqualExpression<float>(new SGConstExpression<float>(glVersion),
251 new GLVersionExpression);
252 AndExpression* extensionsExp = 0;
253 for (vector<string>::const_iterator itr = extensions.begin(),
254 e = extensions.end();
258 extensionsExp = new AndExpression;
259 ExtensionSupportedExpression* supported
260 = new ExtensionSupportedExpression(*itr);
261 supported->addOperand(contextExp);
262 extensionsExp->addOperand(supported);
264 SGExpressionb* predicate = 0;
266 OrExpression* orExp = new OrExpression;
267 orExp->addOperand(versionTest);
268 orExp->addOperand(extensionsExp);
271 predicate = versionTest;
273 setValidExpression(predicate, layout);
276 bool Technique_writeLocalData(const Object& obj, osgDB::Output& fw)
278 const Technique& tniq = static_cast<const Technique&>(obj);
279 fw.indent() << "alwaysValid "
280 << (tniq.getAlwaysValid() ? "TRUE\n" : "FALSE\n");
282 fw.indent() << "glVersion " << tniq.getGLVersion() << "\n";
284 if (tniq.getShadowingStateSet()) {
285 fw.indent() << "shadowingStateSet\n";
286 fw.writeObject(*tniq.getShadowingStateSet());
288 fw.indent() << "passes\n";
289 BOOST_FOREACH(const ref_ptr<Pass>& pass, tniq.passes) {
290 fw.writeObject(*pass);
297 osgDB::RegisterDotOsgWrapperProxy TechniqueProxy
300 "simgear::Technique",
301 "Object simgear::Technique",
303 &Technique_writeLocalData