Hi,
I've added VAO support to osg Geometry.
It need to be discussed:
First I was thinking it was not a great deal:
-Add a flag in osg::Geometry
-Do the stuff done in drawimplementation in compileGLObjects.
However , I ran into the problem that Primitiveset (DrawElements) embed their
BO and so bind it even if it is already bound by VAO
So I had to add a virtual method in DrawElements (arbitrary named
indexLessDraw).
It seams to work but don't know if I didn't break stuff
Need reviews and critisms
Thank you!
Cheers,
Julien
------------------
Read this topic online here:
http://forum.openscenegraph.org/viewtopic.php?p=63137#63137
Index: include/osg/Geometry
===================================================================
--- include/osg/Geometry (revision 14800)
+++ include/osg/Geometry (working copy)
@@ -140,6 +140,14 @@
method to use OpenGL vertex buffer objects for rendering.*/
virtual void setUseVertexBufferObjects(bool flag);
+
+ /**use VertexBufferArray For Drawing*/
+ bool getUseVertexArrayObjects()const{return
_useVAO&&getUseVertexBufferObjects();}
+
+ void setUseVertexArrayObjects(bool flag){
+ setUseVertexBufferObjects(flag);_useVAO=flag;
+ }
+
/** Force a recompile on next draw() of any OpenGL display list
associated with this geoset.*/
virtual void dirtyDisplayList();
@@ -217,6 +225,9 @@
void addVertexBufferObjectIfRequired(osg::Array* array);
void addElementBufferObjectIfRequired(osg::PrimitiveSet* primitiveSet);
+ bool _useVAO;
+ typedef std::pair<unsigned int, const PrimitiveSet*> VAOKey;
+ mutable std::map<VAOKey ,unsigned int> _contextID2VAO; ///per
context per primset vertex array object
PrimitiveSetList _primitives;
osg::ref_ptr<Array> _vertexArray;
Index: include/osg/PrimitiveSet
===================================================================
--- include/osg/PrimitiveSet (revision 14800)
+++ include/osg/PrimitiveSet (working copy)
@@ -395,7 +395,8 @@
virtual void setElement(unsigned int, unsigned int) = 0;
virtual unsigned int getElement(unsigned int) = 0;
virtual void addElement(unsigned int) = 0;
-
+ ///use it in order not to bind index and give a start index
+ virtual void indexLessDraw(State& state, GLsizeiptr indexstart)
const =0;
protected:
virtual ~DrawElements() {}
@@ -439,6 +440,7 @@
virtual bool supportsBufferObject() const { return false; }
virtual void draw(State& state, bool useVertexBufferObjects) const ;
+ virtual void indexLessDraw(State& state, GLsizeiptr indexstart)
const ;
virtual void accept(PrimitiveFunctor& functor) const;
virtual void accept(PrimitiveIndexFunctor& functor) const;
@@ -503,6 +505,7 @@
virtual bool supportsBufferObject() const { return false; }
virtual void draw(State& state, bool useVertexBufferObjects) const;
+ virtual void indexLessDraw(State& state, GLsizeiptr indexstart)
const ;
virtual void accept(PrimitiveFunctor& functor) const;
virtual void accept(PrimitiveIndexFunctor& functor) const;
@@ -567,6 +570,7 @@
virtual bool supportsBufferObject() const { return false; }
virtual void draw(State& state, bool useVertexBufferObjects) const;
+ virtual void indexLessDraw(State& state, GLsizeiptr indexstart)
const ;
virtual void accept(PrimitiveFunctor& functor) const;
virtual void accept(PrimitiveIndexFunctor& functor) const;
Index: src/osg/Geometry.cpp
===================================================================
--- src/osg/Geometry.cpp (revision 14800)
+++ src/osg/Geometry.cpp (working copy)
@@ -23,8 +23,10 @@
_containsDeprecatedData(false)
{
_supportsVertexBufferObjects = true;
+ setSupportsDisplayList(false);
// temporary test
- // setSupportsDisplayList(false);
+
+ ///default 4 DEBUGsetUseVertexArrayObjects(true);
}
Geometry::Geometry(const Geometry& geometry,const CopyOp& copyop):
@@ -716,6 +718,50 @@
extensions->glBindBuffer(GL_ARRAY_BUFFER_ARB,0);
extensions->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB,0);
+ if (_useVAO){
+ State& state = *renderInfo.getState();
+ for (unsigned int primitiveSetNum = 0;
primitiveSetNum != _primitives.size(); ++primitiveSetNum)
+ {
+ // ArrayDispatchers& arrayDispatchers =
state.getArrayDispatchers();
+
+ const PrimitiveSet* primitiveset =
_primitives[primitiveSetNum].get();
+
+ ///create VAO for this context and
primitiveset
+ std::map<VAOKey, unsigned
int>::iterator itm = _contextID2VAO.find(VAOKey(contextID, primitiveset));
+ if (itm != _contextID2VAO.end())
//delete vao if already created
+
extensions->glDeleteVertexArrays(1, &(*itm).second);
+
+ ///create new VAO
+ _contextID2VAO[VAOKey(contextID,
primitiveset)] = 0;
+ itm =
_contextID2VAO.find(VAOKey(contextID, primitiveset));
+
+
+ extensions->glGenVertexArrays(1,
&(*itm).second);
+
+ ///setup VAO
+
extensions->glBindVertexArray((*itm).second);
+
+ //bind vertex buffers
+
drawVertexArraysImplementation(renderInfo);
+
+
+ //bind element buffer
+ GLBufferObject* ebo =
primitiveset->getOrCreateGLBufferObject(state.getContextID());
+ state.bindElementBufferObject(ebo);
+
+ ///end VAO setup
+ extensions->glBindVertexArray(NULL);
+
+ state.lazyDisablingOfVertexAttributes();
+
state.applyDisablingOfVertexAttributes();
+
+
+ }
+ state.unbindVertexBufferObject();
+ state.unbindElementBufferObject();
+
+ }
+
}
else
{
@@ -733,23 +779,68 @@
State& state = *renderInfo.getState();
+
bool checkForGLErrors =
state.getCheckForGLErrors()==osg::State::ONCE_PER_ATTRIBUTE;
if (checkForGLErrors) state.checkGLErrors("start of
Geometry::drawImplementation()");
+ if (_useVAO){
- drawVertexArraysImplementation(renderInfo);
+ //drawVertexArraysImplementation(renderInfo);
+ ArrayDispatchers& arrayDispatchers =
state.getArrayDispatchers();
+ GLExtensions* extensions = state.get<GLExtensions>();
+ //HACK
+ //reset candidates to osg::Array::BIND_OVERALL as glColor can't
be embed in VAOs
+ arrayDispatchers.activateColorArray(_colorArray.get());
+
arrayDispatchers.activateSecondaryColorArray(_secondaryColorArray.get());
- if (checkForGLErrors) state.checkGLErrors("Geometry::drawImplementation()
after vertex arrays setup.");
+ // dispatch any attributes that are bound overall
+ arrayDispatchers.dispatch(osg::Array::BIND_OVERALL, 0);
+
+
+ for (unsigned int primitiveSetNum = 0; primitiveSetNum !=
_primitives.size(); ++primitiveSetNum)
+ {
+ // dispatch any attributes that are bound per primitive
+ bool bindPerPrimitiveSetActive =
arrayDispatchers.active(osg::Array::BIND_PER_PRIMITIVE_SET);
+ if (bindPerPrimitiveSetActive)
arrayDispatchers.dispatch(osg::Array::BIND_PER_PRIMITIVE_SET, primitiveSetNum);
+ const PrimitiveSet* primitiveset =
_primitives[primitiveSetNum].get();
+
+
extensions->glBindVertexArray(_contextID2VAO[VAOKey(state.getContextID(),
primitiveset)]);
+
+ //HACK
+ //problem with primitiveset embedding element buffer
(we're here to avoid this using VAO)
+ //:( binding->draw(state,true/*
usingVertexBufferObjects*/);
+ //so I add a new method in DrawElements
+ GLBufferObject* ebo =
primitiveset->getOrCreateGLBufferObject(state.getContextID());
+ if (ebo)//assume DrawElements
+ ((DrawElements*)primitiveset)->indexLessDraw(state,
ebo->getOffset(primitiveset->getBufferIndex()));
+ else primitiveset->draw(state, true);//drawArray
+
-
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- //
- // draw the primitives themselves.
- //
- drawPrimitivesImplementation(renderInfo);
+ extensions->glBindVertexArray(NULL);
+
+ }
- // unbind the VBO's if any are used.
- state.unbindVertexBufferObject();
- state.unbindElementBufferObject();
+ state.lazyDisablingOfVertexAttributes();
+ state.applyDisablingOfVertexAttributes();
+
+ }
+ else{
+ drawVertexArraysImplementation(renderInfo);
+
+ if (checkForGLErrors)
state.checkGLErrors("Geometry::drawImplementation() after vertex arrays
setup.");
+
+
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ //
+ // draw the primitives themselves.
+ //
+ drawPrimitivesImplementation(renderInfo);
+
+ // unbind the VBO's if any are used.
+ state.unbindVertexBufferObject();
+ state.unbindElementBufferObject();
+
+
+ }
if (checkForGLErrors) state.checkGLErrors("end of
Geometry::drawImplementation().");
}
@@ -850,6 +941,49 @@
}
}
+class AttributeFunctorArrayVisitor : public ArrayVisitor
+{
+ public:
+
+ AttributeFunctorArrayVisitor(Drawable::AttributeFunctor& af):
+ _af(af),
+ _type(0) {}
+
+ virtual ~AttributeFunctorArrayVisitor() {}
+
+ virtual void apply(ByteArray& array) { if (!array.empty())
_af.apply(_type,array.size(),&(array.front())); }
+ virtual void apply(ShortArray& array) { if (!array.empty())
_af.apply(_type,array.size(),&(array.front())); }
+ virtual void apply(IntArray& array) { if (!array.empty())
_af.apply(_type,array.size(),&(array.front())); }
+ virtual void apply(UByteArray& array) { if (!array.empty())
_af.apply(_type,array.size(),&(array.front())); }
+ virtual void apply(UShortArray& array) { if (!array.empty())
_af.apply(_type,array.size(),&(array.front())); }
+ virtual void apply(UIntArray& array) { if (!array.empty())
_af.apply(_type,array.size(),&(array.front())); }
+ virtual void apply(Vec4ubArray& array) { if (!array.empty())
_af.apply(_type,array.size(),&(array.front())); }
+ virtual void apply(FloatArray& array) { if (!array.empty())
_af.apply(_type,array.size(),&(array.front())); }
+ virtual void apply(Vec2Array& array) { if (!array.empty())
_af.apply(_type,array.size(),&(array.front())); }
+ virtual void apply(Vec3Array& array) { if (!array.empty())
_af.apply(_type,array.size(),&(array.front())); }
+ virtual void apply(Vec4Array& array) { if (!array.empty())
_af.apply(_type,array.size(),&(array.front())); }
+ virtual void apply(DoubleArray& array) { if (!array.empty())
_af.apply(_type,array.size(),&(array.front())); }
+ virtual void apply(Vec2dArray& array) { if (!array.empty())
_af.apply(_type,array.size(),&(array.front())); }
+ virtual void apply(Vec3dArray& array) { if (!array.empty())
_af.apply(_type,array.size(),&(array.front())); }
+ virtual void apply(Vec4dArray& array) { if (!array.empty())
_af.apply(_type,array.size(),&(array.front())); }
+
+
+ inline void applyArray(Drawable::AttributeType type,Array* array)
+ {
+ if (array)
+ {
+ _type = type;
+ array->accept(*this);
+ }
+ }
+
+ protected:
+
+ AttributeFunctorArrayVisitor& operator = (const
AttributeFunctorArrayVisitor&) { return *this; }
+ Drawable::AttributeFunctor& _af;
+ Drawable::AttributeType _type;
+};
+
void Geometry::accept(AttributeFunctor& af)
{
AttributeFunctorArrayVisitor afav(af);
@@ -880,7 +1014,50 @@
}
}
+class ConstAttributeFunctorArrayVisitor : public ConstArrayVisitor
+{
+ public:
+ ConstAttributeFunctorArrayVisitor(Drawable::ConstAttributeFunctor& af):
+ _af(af),
+ _type(0) {}
+
+ virtual ~ConstAttributeFunctorArrayVisitor() {}
+
+ virtual void apply(const ByteArray& array) { if (!array.empty())
_af.apply(_type,array.size(),&(array.front())); }
+ virtual void apply(const ShortArray& array) { if (!array.empty())
_af.apply(_type,array.size(),&(array.front())); }
+ virtual void apply(const IntArray& array) { if (!array.empty())
_af.apply(_type,array.size(),&(array.front())); }
+ virtual void apply(const UByteArray& array) { if (!array.empty())
_af.apply(_type,array.size(),&(array.front())); }
+ virtual void apply(const UShortArray& array) { if (!array.empty())
_af.apply(_type,array.size(),&(array.front())); }
+ virtual void apply(const UIntArray& array) { if (!array.empty())
_af.apply(_type,array.size(),&(array.front())); }
+ virtual void apply(const Vec4ubArray& array) { if (!array.empty())
_af.apply(_type,array.size(),&(array.front())); }
+ virtual void apply(const FloatArray& array) { if (!array.empty())
_af.apply(_type,array.size(),&(array.front())); }
+ virtual void apply(const Vec2Array& array) { if (!array.empty())
_af.apply(_type,array.size(),&(array.front())); }
+ virtual void apply(const Vec3Array& array) { if (!array.empty())
_af.apply(_type,array.size(),&(array.front())); }
+ virtual void apply(const Vec4Array& array) { if (!array.empty())
_af.apply(_type,array.size(),&(array.front())); }
+ virtual void apply(const DoubleArray& array) { if (!array.empty())
_af.apply(_type,array.size(),&(array.front())); }
+ virtual void apply(const Vec2dArray& array) { if (!array.empty())
_af.apply(_type,array.size(),&(array.front())); }
+ virtual void apply(const Vec3dArray& array) { if (!array.empty())
_af.apply(_type,array.size(),&(array.front())); }
+ virtual void apply(const Vec4dArray& array) { if (!array.empty())
_af.apply(_type,array.size(),&(array.front())); }
+
+
+ inline void applyArray(Drawable::AttributeType type,const Array* array)
+ {
+ if (array)
+ {
+ _type = type;
+ array->accept(*this);
+ }
+ }
+
+protected:
+
+ ConstAttributeFunctorArrayVisitor& operator = (const
ConstAttributeFunctorArrayVisitor&) { return *this; }
+
+ Drawable::ConstAttributeFunctor& _af;
+ Drawable::AttributeType _type;
+};
+
void Geometry::accept(ConstAttributeFunctor& af) const
{
ConstAttributeFunctorArrayVisitor afav(af);
Index: src/osg/PrimitiveSet.cpp
===================================================================
--- src/osg/PrimitiveSet.cpp (revision 14800)
+++ src/osg/PrimitiveSet.cpp (working copy)
@@ -164,6 +164,13 @@
releaseGLObjects();
}
+void DrawElementsUByte::indexLessDraw(State& state, GLsizeiptr indexstart)
const{
+
+ if (_numInstances >= 1) state.glDrawElementsInstanced(_mode,
size(), GL_UNSIGNED_BYTE, (const GLvoid
*)indexstart/*ebo->getOffset(getBufferIndex()))*/, _numInstances);
+ else glDrawElements(_mode, size(), GL_UNSIGNED_BYTE, (const
GLvoid *)indexstart/*ebo->getOffset(getBufferIndex()))*/);
+
+
+}
void DrawElementsUByte::draw(State& state, bool useVertexBufferObjects) const
{
GLenum mode = _mode;
@@ -219,7 +226,13 @@
{
releaseGLObjects();
}
+void DrawElementsUShort::indexLessDraw(State& state, GLsizeiptr indexstart)
const{
+ if (_numInstances >= 1) state.glDrawElementsInstanced(_mode,
size(), GL_UNSIGNED_SHORT, (const GLvoid
*)indexstart/*ebo->getOffset(getBufferIndex()))*/, _numInstances);
+ else glDrawElements(_mode, size(), GL_UNSIGNED_SHORT, (const
GLvoid *)indexstart/*ebo->getOffset(getBufferIndex()))*/);
+
+
+}
void DrawElementsUShort::draw(State& state, bool useVertexBufferObjects) const
{
GLenum mode = _mode;
@@ -275,7 +288,13 @@
{
releaseGLObjects();
}
+void DrawElementsUInt::indexLessDraw(State& state, GLsizeiptr indexstart)
const{
+ if (_numInstances >= 1) state.glDrawElementsInstanced(_mode,
size(), GL_UNSIGNED_INT, (const GLvoid
*)indexstart/*ebo->getOffset(getBufferIndex()))*/, _numInstances);
+ else glDrawElements(_mode, size(), GL_UNSIGNED_INT, (const
GLvoid *)indexstart/*ebo->getOffset(getBufferIndex()))*/);
+
+
+}
void DrawElementsUInt::draw(State& state, bool useVertexBufferObjects) const
{
GLenum mode = _mode;
_______________________________________________
osg-submissions mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org