From 4f3b1baee44c31361802dffc6cd8e02e43bed405 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Tue, 6 Jan 2009 14:55:49 +0000 Subject: [PATCH] Added support for primitive instancing --- include/osg/PrimitiveSet | 28 +++++--- include/osg/State | 21 +++++- src/osg/PrimitiveSet.cpp | 32 ++++++--- src/osg/State.cpp | 5 ++ src/osgPlugins/ive/IveVersion.h | 3 +- src/osgPlugins/ive/PrimitiveSet.cpp | 10 +++ src/osgPlugins/osg/Geometry.cpp | 102 +++++++++++++++++++++++----- 7 files changed, 158 insertions(+), 43 deletions(-) diff --git a/include/osg/PrimitiveSet b/include/osg/PrimitiveSet index 9d179aac8..e43257c73 100644 --- a/include/osg/PrimitiveSet +++ b/include/osg/PrimitiveSet @@ -175,8 +175,9 @@ class OSG_EXPORT PrimitiveSet : public Object POLYGON = GL_POLYGON }; - PrimitiveSet(Type primType=PrimitiveType,GLenum mode=0): + PrimitiveSet(Type primType=PrimitiveType,GLenum mode=0, int numInstances=0): _primitiveType(primType), + _numInstances(numInstances), _mode(mode), _modifiedCount(0), _rangeModifiedCount(0) {} @@ -184,6 +185,7 @@ class OSG_EXPORT PrimitiveSet : public Object PrimitiveSet(const PrimitiveSet& prim,const CopyOp& copyop=CopyOp::SHALLOW_COPY): Object(prim,copyop), _primitiveType(prim._primitiveType), + _numInstances(prim._numInstances), _mode(prim._mode), _modifiedCount(0), _rangeModifiedCount(0) {} @@ -200,6 +202,9 @@ class OSG_EXPORT PrimitiveSet : public Object virtual DrawElements* getDrawElements() { return 0; } virtual const DrawElements* getDrawElements() const { return 0; } + void setNumInstances(int n) { _numInstances = n; } + int getNumInstances() const { return _numInstances; } + void setMode(GLenum mode) { _mode = mode; } GLenum getMode() const { return _mode; } @@ -238,6 +243,7 @@ class OSG_EXPORT PrimitiveSet : public Object virtual ~PrimitiveSet() {} Type _primitiveType; + int _numInstances; GLenum _mode; unsigned int _modifiedCount; mutable unsigned int _rangeModifiedCount; @@ -275,8 +281,8 @@ class OSG_EXPORT DrawArrays : public PrimitiveSet _first(0), _count(0) {} - DrawArrays(GLenum mode, GLint first, GLsizei count): - PrimitiveSet(DrawArraysPrimitiveType,mode), + DrawArrays(GLenum mode, GLint first, GLsizei count, int numInstances=0): + PrimitiveSet(DrawArraysPrimitiveType, mode, numInstances), _first(first), _count(count) {} @@ -385,8 +391,8 @@ class DrawElements : public PrimitiveSet { public: - DrawElements(Type primType=PrimitiveType, GLenum mode=0): - PrimitiveSet(primType,mode), + DrawElements(Type primType=PrimitiveType, GLenum mode=0, int numInstances=0): + PrimitiveSet(primType,mode, numInstances), _eboOffset(0) {} DrawElements(const DrawElements& copy,const CopyOp& copyop=CopyOp::SHALLOW_COPY): @@ -472,8 +478,8 @@ class OSG_EXPORT DrawElementsUByte : public DrawElements, public VectorGLubyte DrawElements(array,copyop), vector_type(array) {} - DrawElementsUByte(GLenum mode, unsigned int no, const GLubyte* ptr) : - DrawElements(DrawElementsUBytePrimitiveType,mode), + DrawElementsUByte(GLenum mode, unsigned int no, const GLubyte* ptr, int numInstances=0) : + DrawElements(DrawElementsUBytePrimitiveType,mode,numInstances), vector_type(ptr,ptr+no) {} DrawElementsUByte(GLenum mode, unsigned int no) : @@ -542,8 +548,8 @@ class OSG_EXPORT DrawElementsUShort : public DrawElements, public VectorGLushort DrawElements(array,copyop), vector_type(array) {} - DrawElementsUShort(GLenum mode, unsigned int no, const GLushort* ptr) : - DrawElements(DrawElementsUShortPrimitiveType,mode), + DrawElementsUShort(GLenum mode, unsigned int no, const GLushort* ptr, int numInstances=0) : + DrawElements(DrawElementsUShortPrimitiveType,mode,numInstances), vector_type(ptr,ptr+no) {} DrawElementsUShort(GLenum mode, unsigned int no) : @@ -616,8 +622,8 @@ class OSG_EXPORT DrawElementsUInt : public DrawElements, public VectorGLuint DrawElements(array,copyop), vector_type(array) {} - DrawElementsUInt(GLenum mode, unsigned int no, const GLuint* ptr) : - DrawElements(DrawElementsUIntPrimitiveType,mode), + DrawElementsUInt(GLenum mode, unsigned int no, const GLuint* ptr, int numInstances=0) : + DrawElements(DrawElementsUIntPrimitiveType,mode,numInstances), vector_type(ptr,ptr+no) {} DrawElementsUInt(GLenum mode, unsigned int no) : diff --git a/include/osg/State b/include/osg/State index ee118ddb7..194168505 100644 --- a/include/osg/State +++ b/include/osg/State @@ -459,6 +459,20 @@ class OSG_EXPORT State : public Referenced _glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB,0); _currentPBO = 0; } + + + inline void glDrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei primcount) + { + if (primcount>=1 && _glDrawArraysInstanced!=0) _glDrawArraysInstanced(mode, first, count, primcount); + else glDrawArrays(mode, first, count); + } + + inline void glDrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount ) + { + if (primcount>=1 && _glDrawElementsInstanced!=0) _glDrawElementsInstanced(mode, count, type, indices, primcount); + else glDrawElements(mode, count, type, indices); + } + /** Wrapper around glInterleavedArrays(..). * also resets the internal array points and modes within osg::State to keep the other @@ -1293,7 +1307,9 @@ class OSG_EXPORT State : public Referenced typedef void (APIENTRY * EnableVertexAttribProc) (unsigned int); typedef void (APIENTRY * DisableVertexAttribProc) (unsigned int); typedef void (APIENTRY * BindBufferProc) (GLenum target, GLuint buffer); - + + typedef void (APIENTRY * DrawArraysInstancedProc)( GLenum mode, GLint first, GLsizei count, GLsizei primcount ); + typedef void (APIENTRY * DrawElementsInstancedProc)( GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount ); bool _extensionProcsInitialized; GLint _glMaxTextureCoords; @@ -1306,7 +1322,8 @@ class OSG_EXPORT State : public Referenced EnableVertexAttribProc _glEnableVertexAttribArray; DisableVertexAttribProc _glDisableVertexAttribArray; BindBufferProc _glBindBuffer; - + DrawArraysInstancedProc _glDrawArraysInstanced; + DrawElementsInstancedProc _glDrawElementsInstanced; unsigned int _dynamicObjectCount; osg::ref_ptr _completeDynamicObjectRenderingCallback; diff --git a/src/osg/PrimitiveSet.cpp b/src/osg/PrimitiveSet.cpp index 3ab5f00a2..9cfb5ce76 100644 --- a/src/osg/PrimitiveSet.cpp +++ b/src/osg/PrimitiveSet.cpp @@ -35,9 +35,10 @@ unsigned int PrimitiveSet::getNumPrimitives() const return 0; } -void DrawArrays::draw(State&, bool) const +void DrawArrays::draw(State& state, bool) const { - glDrawArrays(_mode,_first,_count); + if (_numInstances>=1) state.glDrawArraysInstanced(_mode,_first,_count, _numInstances); + else glDrawArrays(_mode,_first,_count); } void DrawArrays::accept(PrimitiveFunctor& functor) const @@ -129,16 +130,19 @@ void DrawElementsUByte::draw(State& state, bool useVertexBufferObjects) const state.bindElementBufferObject(ebo); if (ebo) { - glDrawElements(_mode, size(), GL_UNSIGNED_BYTE, getElementBufferObjectOffset()); + if (_numInstances>=1) state.glDrawElementsInstanced(_mode, size(), GL_UNSIGNED_BYTE, getElementBufferObjectOffset(), _numInstances); + else glDrawElements(_mode, size(), GL_UNSIGNED_BYTE, getElementBufferObjectOffset()); } else { - glDrawElements(_mode, size(), GL_UNSIGNED_BYTE, &front()); + if (_numInstances>=1) state.glDrawElementsInstanced(_mode, size(), GL_UNSIGNED_BYTE, &front(), _numInstances); + else glDrawElements(_mode, size(), GL_UNSIGNED_BYTE, &front()); } } else { - glDrawElements(_mode, size(), GL_UNSIGNED_BYTE, &front()); + if (_numInstances>=1) state.glDrawElementsInstanced(_mode, size(), GL_UNSIGNED_BYTE, &front(), _numInstances); + else glDrawElements(_mode, size(), GL_UNSIGNED_BYTE, &front()); } } @@ -176,16 +180,19 @@ void DrawElementsUShort::draw(State& state, bool useVertexBufferObjects) const state.bindElementBufferObject(ebo); if (ebo) { - glDrawElements(_mode, size(), GL_UNSIGNED_SHORT, getElementBufferObjectOffset()); + if (_numInstances>=1) state.glDrawElementsInstanced(_mode, size(), GL_UNSIGNED_BYTE, getElementBufferObjectOffset(), _numInstances); + else glDrawElements(_mode, size(), GL_UNSIGNED_SHORT, getElementBufferObjectOffset()); } else { - glDrawElements(_mode, size(), GL_UNSIGNED_SHORT, &front()); + if (_numInstances>=1) state.glDrawElementsInstanced(_mode, size(), GL_UNSIGNED_BYTE, &front(), _numInstances); + else glDrawElements(_mode, size(), GL_UNSIGNED_SHORT, &front()); } } else { - glDrawElements(_mode, size(), GL_UNSIGNED_SHORT, &front()); + if (_numInstances>=1) state.glDrawElementsInstanced(_mode, size(), GL_UNSIGNED_BYTE, &front(), _numInstances); + else glDrawElements(_mode, size(), GL_UNSIGNED_SHORT, &front()); } } @@ -223,16 +230,19 @@ void DrawElementsUInt::draw(State& state, bool useVertexBufferObjects) const state.bindElementBufferObject(ebo); if (ebo) { - glDrawElements(_mode, size(), GL_UNSIGNED_INT, getElementBufferObjectOffset()); + if (_numInstances>=1) state.glDrawElementsInstanced(_mode, size(), GL_UNSIGNED_BYTE, getElementBufferObjectOffset(), _numInstances); + else glDrawElements(_mode, size(), GL_UNSIGNED_INT, getElementBufferObjectOffset()); } else { - glDrawElements(_mode, size(), GL_UNSIGNED_INT, &front()); + if (_numInstances>=1) state.glDrawElementsInstanced(_mode, size(), GL_UNSIGNED_BYTE, &front(), _numInstances); + else glDrawElements(_mode, size(), GL_UNSIGNED_INT, &front()); } } else { - glDrawElements(_mode, size(), GL_UNSIGNED_INT, &front()); + if (_numInstances>=1) state.glDrawElementsInstanced(_mode, size(), GL_UNSIGNED_BYTE, &front(), _numInstances); + else glDrawElements(_mode, size(), GL_UNSIGNED_INT, &front()); } } diff --git a/src/osg/State.cpp b/src/osg/State.cpp index 6aa5848dc..cf6d0a826 100644 --- a/src/osg/State.cpp +++ b/src/osg/State.cpp @@ -79,6 +79,8 @@ State::State(): _glVertexAttribPointer = 0; _glEnableVertexAttribArray = 0; _glDisableVertexAttribArray = 0; + _glDrawArraysInstanced = 0; + _glDrawElementsInstanced = 0; _dynamicObjectCount = 0; @@ -754,6 +756,9 @@ void State::initializeExtensionProcs() setGLExtensionFuncPtr(_glDisableVertexAttribArray, "glDisableVertexAttribArray","glDisableVertexAttribArrayARB"); setGLExtensionFuncPtr(_glBindBuffer, "glBindBuffer","glBindBufferARB"); + setGLExtensionFuncPtr(_glDrawArraysInstanced, "glDrawArraysInstanced","glDrawArraysInstancedEXT"); + setGLExtensionFuncPtr(_glDrawElementsInstanced, "glDrawElementsInstanced","glDrawElementsInstancedEXT"); + if ( osg::getGLVersionNumber() >= 2.0 || osg::isGLExtensionSupported(_contextID,"GL_ARB_vertex_shader") ) { glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS,&_glMaxTextureUnits); diff --git a/src/osgPlugins/ive/IveVersion.h b/src/osgPlugins/ive/IveVersion.h index 16346e32c..0b3b73ec1 100644 --- a/src/osgPlugins/ive/IveVersion.h +++ b/src/osgPlugins/ive/IveVersion.h @@ -46,8 +46,9 @@ #define VERSION_0035 35 #define VERSION_0036 36 #define VERSION_0037 37 +#define VERSION_0038 38 -#define VERSION VERSION_0037 +#define VERSION VERSION_0038 /* The BYTE_SEX tag is used to check the endian of the IVE file being read in. The IVE format diff --git a/src/osgPlugins/ive/PrimitiveSet.cpp b/src/osgPlugins/ive/PrimitiveSet.cpp index 375ed7d3b..221dedaf0 100644 --- a/src/osgPlugins/ive/PrimitiveSet.cpp +++ b/src/osgPlugins/ive/PrimitiveSet.cpp @@ -30,6 +30,11 @@ void PrimitiveSet::write(DataOutputStream* out){ throw Exception("PrimitiveSet::write(): Could not cast this osg::PrimitiveSet to an osg::Object."); + if ( out->getVersion() >= VERSION_0038 ) + { + out->writeInt(getNumInstances()); + } + // Write PrimitiveSet's properties. out->writeInt(getMode()); } @@ -49,6 +54,11 @@ void PrimitiveSet::read(DataInputStream* in){ throw Exception("PrimitiveSet::read(): Could not cast this osg::PrimitiveSet to an osg::Object."); + if ( in->getVersion() >= VERSION_0038 ) + { + setNumInstances(in->readInt()); + } + // Read in primitiveset properties. setMode(in->readInt()); } diff --git a/src/osgPlugins/osg/Geometry.cpp b/src/osgPlugins/osg/Geometry.cpp index ce119834b..67eab1119 100644 --- a/src/osgPlugins/osg/Geometry.cpp +++ b/src/osgPlugins/osg/Geometry.cpp @@ -1003,7 +1003,9 @@ bool Array_writeLocalData(const Array& array,Output& fw) bool Primitive_readLocalData(Input& fr,osg::Geometry& geom) { bool iteratorAdvanced = false; - if (fr.matchSequence("DrawArrays %w %i %i")) + bool firstMatched = false; + if ((firstMatched = fr.matchSequence("DrawArrays %w %i %i %i")) || + fr.matchSequence("DrawArrays %w %i %i") ) { GLenum mode; @@ -1015,14 +1017,25 @@ bool Primitive_readLocalData(Input& fr,osg::Geometry& geom) int count; fr[3].getInt(count); - geom.addPrimitiveSet(new DrawArrays(mode,first,count)); + int numInstances = 0; + if (firstMatched) + { + fr[4].getInt(numInstances); + fr += 5; + } + else + { + fr += 4; + } + + geom.addPrimitiveSet(new DrawArrays(mode, first, count, numInstances)); - fr += 4; iteratorAdvanced = true; } - else if (fr.matchSequence("DrawArrayLengths %w %i %i {")) + else if ((firstMatched = fr.matchSequence("DrawArrayLengths %w %i %i %i {")) || + fr.matchSequence("DrawArrayLengths %w %i %i {") ) { int entry = fr[1].getNoNestedBrackets(); @@ -1035,10 +1048,20 @@ bool Primitive_readLocalData(Input& fr,osg::Geometry& geom) int capacity; fr[3].getInt(capacity); - fr += 5; - + int numInstances = 0; + if (firstMatched) + { + fr[4].getInt(numInstances); + fr += 6; + } + else + { + fr += 5; + } + DrawArrayLengths* prim = new DrawArrayLengths; prim->setMode(mode); + prim->setNumInstances(numInstances); prim->setFirst(first); prim->reserve(capacity); @@ -1057,7 +1080,8 @@ bool Primitive_readLocalData(Input& fr,osg::Geometry& geom) iteratorAdvanced = true; } - else if (fr.matchSequence("DrawElementsUByte %w %i {")) + else if ((firstMatched = fr.matchSequence("DrawElementsUByte %w %i %i {")) || + fr.matchSequence("DrawElementsUByte %w %i {")) { int entry = fr[1].getNoNestedBrackets(); @@ -1067,10 +1091,20 @@ bool Primitive_readLocalData(Input& fr,osg::Geometry& geom) int capacity; fr[2].getInt(capacity); - fr += 4; - + int numInstances = 0; + if (firstMatched) + { + fr[3].getInt(numInstances); + fr += 5; + } + else + { + fr += 4; + } + DrawElementsUByte* prim = new DrawElementsUByte; prim->setMode(mode); + prim->setNumInstances(numInstances); prim->reserve(capacity); while (!fr.eof() && fr[0].getNoNestedBrackets()>entry) @@ -1088,7 +1122,8 @@ bool Primitive_readLocalData(Input& fr,osg::Geometry& geom) iteratorAdvanced = true; } - else if (fr.matchSequence("DrawElementsUShort %w %i {")) + else if ((firstMatched = fr.matchSequence("DrawElementsUShort %w %i %i {")) || + fr.matchSequence("DrawElementsUShort %w %i {")) { int entry = fr[1].getNoNestedBrackets(); @@ -1098,10 +1133,20 @@ bool Primitive_readLocalData(Input& fr,osg::Geometry& geom) int capacity; fr[2].getInt(capacity); - fr += 4; + int numInstances = 0; + if (firstMatched) + { + fr[3].getInt(numInstances); + fr += 5; + } + else + { + fr += 4; + } DrawElementsUShort* prim = new DrawElementsUShort; prim->setMode(mode); + prim->setNumInstances(numInstances); prim->reserve(capacity); while (!fr.eof() && fr[0].getNoNestedBrackets()>entry) @@ -1119,7 +1164,8 @@ bool Primitive_readLocalData(Input& fr,osg::Geometry& geom) iteratorAdvanced = true; } - else if (fr.matchSequence("DrawElementsUInt %w %i {")) + else if ((firstMatched = fr.matchSequence("DrawElementsUInt %w %i %i {")) || + fr.matchSequence("DrawElementsUInt %w %i {")) { int entry = fr[1].getNoNestedBrackets(); @@ -1129,10 +1175,20 @@ bool Primitive_readLocalData(Input& fr,osg::Geometry& geom) int capacity; fr[2].getInt(capacity); - fr += 4; + int numInstances = 0; + if (firstMatched) + { + fr[3].getInt(numInstances); + fr += 5; + } + else + { + fr += 4; + } DrawElementsUInt* prim = new DrawElementsUInt; prim->setMode(mode); + prim->setNumInstances(numInstances); prim->reserve(capacity); while (!fr.eof() && fr[0].getNoNestedBrackets()>entry) @@ -1162,14 +1218,18 @@ bool Primitive_writeLocalData(const PrimitiveSet& prim,Output& fw) case(PrimitiveSet::DrawArraysPrimitiveType): { const DrawArrays& cprim = static_cast(prim); - fw<0) fw<<" "<(prim); - fw<0) fw<<" "<(prim); - fw<0) fw<<" "<(prim); - fw<0) fw<<" "<(prim); - fw<0) fw<<" "<