diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index d695fe86f..9d54ac9ca 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -20,6 +20,7 @@ ELSE(ANDROID) IF(DYNAMIC_OPENSCENEGRAPH) + ADD_SUBDIRECTORY(osgsimpleMDI) ADD_SUBDIRECTORY(osg2cpp) ADD_SUBDIRECTORY(osganalysis) ADD_SUBDIRECTORY(osganimate) diff --git a/examples/osggpucull/CMakeLists.txt b/examples/osggpucull/CMakeLists.txt index 11d3b0463..6cfe7a646 100644 --- a/examples/osggpucull/CMakeLists.txt +++ b/examples/osggpucull/CMakeLists.txt @@ -1,13 +1,11 @@ SET(TARGET_SRC ShapeToGeometry.cpp - DrawIndirectPrimitiveSet.cpp AggregateGeometryVisitor.cpp osggpucull.cpp ) SET(TARGET_H ShapeToGeometry.h - DrawIndirectPrimitiveSet.h AggregateGeometryVisitor.h GpuCullShaders.h ) diff --git a/examples/osggpucull/DrawIndirectPrimitiveSet.cpp b/examples/osggpucull/DrawIndirectPrimitiveSet.cpp deleted file mode 100644 index bbb5ff45b..000000000 --- a/examples/osggpucull/DrawIndirectPrimitiveSet.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2014 Robert Osfield - * Copyright (C) 2014 Pawel Ksiezopolski - * - * This library is open source and may be redistributed and/or modified under - * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or - * (at your option) any later version. The full license is in LICENSE file - * included with this distribution, and on the openscenegraph.org website. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * OpenSceneGraph Public License for more details. - * -*/ -#include "DrawIndirectPrimitiveSet.h" -#include -#include -#include -#include -#include - -void DrawArraysIndirect::draw(osg::State& state, bool /*useVertexBufferObjects*/) const -{ -// if you want to see how many primitives were rendered - uncomment code below, but -// be warned : it is a serious performance killer ( because of GPU->CPU roundtrip ) - -// osg::Drawable::Extensions *dext = osg::Drawable::getExtensions( state.getContextID(),true ); -// int* tab = (int*)dext->glMapBuffer(GL_DRAW_INDIRECT_BUFFER,GL_READ_ONLY); -// int val = _indirect/sizeof(int); -// OSG_WARN<<"DrawArraysIndirect ("<glUnmapBuffer(GL_DRAW_INDIRECT_BUFFER); - - state.get()->glDrawArraysIndirect( _mode, reinterpret_cast(_indirect) ); - -} - -void MultiDrawArraysIndirect::draw(osg::State& state, bool /*useVertexBufferObjects*/) const -{ - // DrawIndirectGLExtensions *ext = DrawIndirectGLExtensions::getExtensions( state.getContextID(),true ); - state.get()->glMultiDrawArraysIndirect( _mode, reinterpret_cast(_indirect), _drawcount, _stride ); -} diff --git a/examples/osggpucull/DrawIndirectPrimitiveSet.h b/examples/osggpucull/DrawIndirectPrimitiveSet.h deleted file mode 100644 index 8a6c7b777..000000000 --- a/examples/osggpucull/DrawIndirectPrimitiveSet.h +++ /dev/null @@ -1,63 +0,0 @@ -/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2014 Robert Osfield - * Copyright (C) 2014 Pawel Ksiezopolski - * - * This library is open source and may be redistributed and/or modified under - * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or - * (at your option) any later version. The full license is in LICENSE file - * included with this distribution, and on the openscenegraph.org website. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * OpenSceneGraph Public License for more details. - * -*/ - -#ifndef OSG_DRAWINDIRECTPRIMITIVESET -#define OSG_DRAWINDIRECTPRIMITIVESET 1 - -#include -#include -#include - - -class DrawArraysIndirect : public osg::DrawArrays -{ -public: - DrawArraysIndirect(GLenum mode=0, unsigned int indirect=0) - : osg::DrawArrays(mode), _indirect(indirect) - { - } - virtual osg::Object* cloneType() const { return new DrawArraysIndirect(); } - virtual osg::Object* clone(const osg::CopyOp& /*copyop*/) const { return NULL; } - virtual bool isSameKindAs(const osg::Object* obj) const { return dynamic_cast(obj)!=NULL; } - virtual const char* libraryName() const { return "osg"; } - virtual const char* className() const { return "DrawArraysIndirect"; } - - virtual void draw(osg::State& state, bool useVertexBufferObjects) const; -protected: - unsigned int _indirect; -}; - -class MultiDrawArraysIndirect : public osg::DrawArrays -{ -public: - MultiDrawArraysIndirect(GLenum mode=0, unsigned int indirect=0, GLsizei drawcount=0, GLsizei stride=0) - : osg::DrawArrays(mode), _indirect(indirect), _drawcount(drawcount), _stride(stride) - { - } - virtual osg::Object* cloneType() const { return new MultiDrawArraysIndirect(); } - virtual osg::Object* clone(const osg::CopyOp& /*copyop*/) const { return NULL; } - virtual bool isSameKindAs(const osg::Object* obj) const { return dynamic_cast(obj)!=NULL; } - virtual const char* libraryName() const { return "osg"; } - virtual const char* className() const { return "MultiDrawArraysIndirect"; } - - virtual void draw(osg::State& state, bool useVertexBufferObjects) const; -protected: - unsigned int _indirect; - GLsizei _drawcount; - GLsizei _stride; -}; - - -#endif diff --git a/examples/osggpucull/osggpucull.cpp b/examples/osggpucull/osggpucull.cpp index 2abad3b7f..906a0f59f 100644 --- a/examples/osggpucull/osggpucull.cpp +++ b/examples/osggpucull/osggpucull.cpp @@ -36,14 +36,12 @@ #include #include #include +#include #include "ShapeToGeometry.h" #include "AggregateGeometryVisitor.h" #include "DrawIndirectPrimitiveSet.h" #include "GpuCullShaders.h" -#ifndef GL_RASTERIZER_DISCARD - #define GL_RASTERIZER_DISCARD 0x8C89 -#endif // each instance type may have max 8 LODs ( if you change // this value, don't forget to change it in vertex shaders accordingly ) @@ -178,21 +176,19 @@ struct IndirectTarget IndirectTarget() : maxTargetQuantity(0) { - indirectCommands = new osg::BufferTemplate< std::vector >; + indirectCommands = new osg::DrawArraysIndirectCommandArray ; } IndirectTarget( AggregateGeometryVisitor* agv, osg::Program* program ) : geometryAggregator(agv), drawProgram(program), maxTargetQuantity(0) { - indirectCommands = new osg::BufferTemplate< std::vector >; + indirectCommands = new osg::DrawArraysIndirectCommandArray; } void endRegister(unsigned int index, unsigned int rowsPerInstance, GLenum pixelFormat, GLenum type, GLint internalFormat, bool useMultiDrawArraysIndirect ) { - // osg::Image* indirectCommandImage = new osg::Image; - //indirectCommandImage->setImage( indirectCommands->getTotalDataSize()/sizeof(unsigned int), 1, 1, GL_R32I, GL_RED, GL_UNSIGNED_INT, (unsigned char*)indirectCommands->getDataPointer(), osg::Image::NO_DELETE ); - osg::VertexBufferObject * indirectCommandImagebuffer=new osg::VertexBufferObject(); - indirectCommandImagebuffer->setUsage(GL_DYNAMIC_DRAW); - indirectCommands->setBufferObject(indirectCommandImagebuffer); + osg::DrawIndirectBufferObject * indirectCommandbuffer=new osg::DrawIndirectBufferObject(); + indirectCommandbuffer->setUsage(GL_DYNAMIC_DRAW); + indirectCommands->setBufferObject(indirectCommandbuffer); indirectCommandTextureBuffer = new osg::TextureBuffer(indirectCommands); indirectCommandTextureBuffer->setInternalFormat( GL_R32I ); @@ -205,26 +201,28 @@ struct IndirectTarget { std::vector newPrimitiveSets; - for(unsigned int j=0;jgetData().size(); ++j) - newPrimitiveSets.push_back( new DrawArraysIndirect( GL_TRIANGLES, j*sizeof( DrawArraysIndirectCommand ) ) ); + for(unsigned int j=0;jsize(); ++j) + newPrimitiveSets.push_back( new DrawArraysIndirect( GL_TRIANGLES, j*sizeof( osg::DrawArraysIndirectCommand ), indirectCommands ) ); geometryAggregator->getAggregatedGeometry()->removePrimitiveSet(0,geometryAggregator->getAggregatedGeometry()->getNumPrimitiveSets() ); - for(unsigned int j=0;jgetData().size(); ++j) + for(unsigned int j=0;jsize(); ++j) geometryAggregator->getAggregatedGeometry()->addPrimitiveSet( newPrimitiveSets[j] ); - - + /*DrawIndirectBufferBinding should be deprecated + ///attach a DrawIndirect buffer binding to the stateset for non builtin primset DrawArraysIndirect + osg::ref_ptr bb=new osg::DrawIndirectBufferBinding(); + bb->setBufferObject(indirectCommandbuffer ); + geometryAggregator->getAggregatedGeometry()->getOrCreateStateSet()->setAttribute(bb );*/ } else // use glMultiDrawArraysIndirect() { + osg::MultiDrawArraysIndirect * mdi=new osg::MultiDrawArraysIndirect(GL_TRIANGLES); + mdi->setIndirectCommandArray(indirectCommands); geometryAggregator->getAggregatedGeometry()->removePrimitiveSet(0,geometryAggregator->getAggregatedGeometry()->getNumPrimitiveSets() ); - geometryAggregator->getAggregatedGeometry()->addPrimitiveSet( new MultiDrawArraysIndirect( GL_TRIANGLES, 0, indirectCommands->getData().size(), 0 ) ); + geometryAggregator->getAggregatedGeometry()->addPrimitiveSet(mdi ); + } - ///attach a DrawIndirect buffer binding to the stateset - osg::ref_ptr bb=new osg::DrawIndirectBufferBinding(indirectCommands); - - geometryAggregator->getAggregatedGeometry()->getOrCreateStateSet()->setAttributeAndModes(bb ); geometryAggregator->getAggregatedGeometry()->setUseDisplayList(false); geometryAggregator->getAggregatedGeometry()->setUseVertexBufferObjects(true); @@ -268,7 +266,7 @@ struct IndirectTarget stateset->setAttributeAndModes( drawProgram.get(), osg::StateAttribute::ON ); } - osg::ref_ptr< osg::BufferTemplate< std::vector > > indirectCommands; + osg::ref_ptr< osg::DrawArraysIndirectCommandArray > indirectCommands; osg::ref_ptr indirectCommandTextureBuffer; osg::ref_ptr< AggregateGeometryVisitor > geometryAggregator; osg::ref_ptr drawProgram; @@ -318,7 +316,7 @@ struct GPUCullData // AggregateGeometryVisitor creates single osg::Geometry from all objects used by specific indirect target AggregateGeometryVisitor::AddObjectResult aoResult = target->second.geometryAggregator->addObject( node , typeID, lodNumber ); // Information about first vertex and a number of vertices is stored for later primitiveset creation - target->second.indirectCommands->getData().push_back( DrawArraysIndirectCommand( aoResult.first, aoResult.count ) ); + target->second.indirectCommands->push_back( osg::DrawArraysIndirectCommand( aoResult.count,1,aoResult.first ) ); osg::ComputeBoundsVisitor cbv; node->accept(cbv); @@ -360,10 +358,10 @@ struct GPUCullData std::map::iterator it,eit; for(it=targets.begin(), eit=targets.end(); it!=eit; ++it) { - for(unsigned j=0; jsecond.indirectCommands->getData().size(); ++j) + for(unsigned j=0; jsecond.indirectCommands->size(); ++j) { - DrawArraysIndirectCommand& iComm = it->second.indirectCommands->getData().at(j); - OSG_INFO<<"("<second.indirectCommands->at(j); + OSG_INFO<<"("<second.maxTargetQuantity * sizeof(osg::Vec4); OSG_INFO<<" => Maximum elements in target : "<< it->second.maxTargetQuantity <<" ( "<< sizeInBytes <<" bytes, " << sizeInBytes/1024<< " kB )" << std::endl; @@ -727,9 +725,9 @@ struct ResetTexturesCallback : public osg::StateSet::Callback osg::TextureBuffer* tex = dynamic_cast( stateset->getTextureAttribute(*it,osg::StateAttribute::TEXTURE) ); if(tex==NULL) continue; - osg::BufferData* img = const_cast(tex->getBufferData()); - if(img!=NULL) - img->dirty(); + osg::BufferData* drawcmds = tex->getBufferData(); + if(drawcmds!=NULL) + drawcmds->dirty(); } for(it=texUnitsDirtyParams.begin(), eit=texUnitsDirtyParams.end(); it!=eit; ++it) { diff --git a/examples/osgsimpleMDI/CMakeLists.txt b/examples/osgsimpleMDI/CMakeLists.txt new file mode 100644 index 000000000..3c14efece --- /dev/null +++ b/examples/osgsimpleMDI/CMakeLists.txt @@ -0,0 +1,7 @@ +#this file is automatically generated + + +SET(TARGET_SRC osgsimpleMDI.cpp ) + +#### end var setup ### +SETUP_EXAMPLE(osgsimpleMDI) diff --git a/examples/osgsimpleMDI/osgsimpleMDI.cpp b/examples/osgsimpleMDI/osgsimpleMDI.cpp new file mode 100644 index 000000000..be7bd2c31 --- /dev/null +++ b/examples/osgsimpleMDI/osgsimpleMDI.cpp @@ -0,0 +1,141 @@ +/* OpenSceneGraph example, osgtransformfeedback +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +* THE SOFTWARE. +*/ + +/* file: examples/osgsimpleMDI/osgsimpleMDI.cpp +* author: Julien Valentin 2017-08-01 +* copyright: (C) 2013 +* license: OpenSceneGraph Public License (OSGPL) +* +* A simple example of mdi with basevertex +* +*/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + + + +int main( int argc, char**argv ) +{ + + osg::ArgumentParser arguments(&argc,argv); + arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the example which demonstrates Multi Indirect Draw with basevertex"); + arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] "); + arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information"); + arguments.getApplicationUsage()->addCommandLineOption("--numX","square count on X"); + arguments.getApplicationUsage()->addCommandLineOption("--numY","square count on Y"); + arguments.getApplicationUsage()->addCommandLineOption("--classic","disable MDI and use classic DrawElements"); + + if (arguments.read("-h") || arguments.read("--help")) + { + arguments.getApplicationUsage()->write(std::cout); + return 1; + } + + int MAXX=200; + int MAXY=200; + arguments.read("--numX",MAXX); + arguments.read("--numY",MAXY); + + bool MDIenable=true; + if(arguments.read("--classic")) + { MDIenable=false; + OSG_WARN<<"disabling MDI"< ebo=new osg::ElementBufferObject; + + ///create empty mdi + osg::MultiDrawElementsIndirectUShort* mdi=new osg::MultiDrawElementsIndirectUShort(osg::PrimitiveSet::TRIANGLE_STRIP); + osg::DefaultIndirectCommandDrawElements* mdicommands= new osg::DefaultIndirectCommandDrawElements(); + mdi->setIndirectCommandArray(mdicommands); + + osg::ref_ptr geom=new osg::Geometry(); + geom->setUseVertexBufferObjects(true); + osg::BoundingBox bb; + bb.set(0,0,0,MAXX,0,MAXY); + //set bounds by hand cause of the lack of support of basevertex in PrimitiveFunctors + geom->setInitialBound(bb); + + osg::Vec3 myCoords[] = + { + osg::Vec3(0,0.0f,0.7f), + osg::Vec3(0,0.0f,0), + osg::Vec3(0.7,0.0f,0), + osg::Vec3(0.7f,0.0f,0.7f) + }; + + unsigned short myIndices[] = { 0, 1, 3, 2 }; + unsigned int myIndicesUI[] = { 0, 1, 3, 2 }; + + osg::Vec3Array * verts=new osg::Vec3Array(); + + + for(int j =0 ; jsize(); + cmd.baseVertex=verts->size(); + mdicommands->push_back(cmd); + + for(int z=0; z<4; z++) { + verts->push_back(osg::Vec3(i,0,j)+myCoords[z]); + mdi->addElement(myIndices[z]); + } + } + } + geom->setVertexArray(verts); + if(MDIenable) { + geom->addPrimitiveSet(mdi); + + } else + for(int i=0; isetElementBufferObject(ebo); + geom->addPrimitiveSet(dre); + for(int z=0; z<4; z++)myIndicesUI[z]+=4; + } + root->addChild(geom); + osgViewer::Viewer viewer; + viewer.addEventHandler(new osgViewer::StatsHandler); + viewer.setSceneData( root ); + return viewer.run(); +} diff --git a/include/osg/BufferIndexBinding b/include/osg/BufferIndexBinding index 95c71df24..98548b8c3 100644 --- a/include/osg/BufferIndexBinding +++ b/include/osg/BufferIndexBinding @@ -213,30 +213,6 @@ class OSG_EXPORT ShaderStorageBufferBinding : public BufferIndexBinding } }; - -class OSG_EXPORT DrawIndirectBufferBinding : public BufferIndexBinding -{ - public: - DrawIndirectBufferBinding(); - /** Create a binding for a draw indirect buffer target. - * @param bd associated buffer data - */ - DrawIndirectBufferBinding( BufferData* bd); - DrawIndirectBufferBinding(const DrawIndirectBufferBinding& rhs, const CopyOp& copyop=CopyOp::SHALLOW_COPY); - META_StateAttribute(osg, DrawIndirectBufferBinding, INDIRECTDRAWBUFFERBINDING); - - virtual void apply(State& state) const; - - virtual int compare(const StateAttribute& bb) const - { - COMPARE_StateAttribute_Types(DrawIndirectBufferBinding, bb) - COMPARE_StateAttribute_Parameter(_target) - COMPARE_StateAttribute_Parameter(_bufferData) - return 0; - } -}; - - } // namespace osg #endif diff --git a/include/osg/BufferObject b/include/osg/BufferObject index c542e4121..37ae19a55 100644 --- a/include/osg/BufferObject +++ b/include/osg/BufferObject @@ -635,6 +635,28 @@ class OSG_EXPORT ElementBufferObject : public BufferObject virtual ~ElementBufferObject(); }; +class OSG_EXPORT DrawIndirectBufferObject : public BufferObject +{ + public: + + DrawIndirectBufferObject(); + + /** Copy constructor using CopyOp to manage deep vs shallow copy.*/ + DrawIndirectBufferObject(const DrawIndirectBufferObject& vbo,const CopyOp& copyop=CopyOp::SHALLOW_COPY); + + META_Object(osg,DrawIndirectBufferObject); + + unsigned int addArray(osg::Array* array); + void removeArray(osg::Array* array); + + void setArray(unsigned int i, Array* array); + Array* getArray(unsigned int i); + const Array* getArray(unsigned int i) const; + + protected: + virtual ~DrawIndirectBufferObject(); +}; + class Image; class OSG_EXPORT PixelBufferObject : public BufferObject { diff --git a/include/osg/GLDefines b/include/osg/GLDefines index 5a8f21958..ce32acf6c 100644 --- a/include/osg/GLDefines +++ b/include/osg/GLDefines @@ -435,6 +435,8 @@ typedef char GLchar; #define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW 0x900D #define GL_INT_SAMPLER_CUBE_MAP_ARRAY 0x900E #define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY 0x900F +#define GL_DRAW_INDIRECT_BUFFER 0x8F3F +#define GL_DRAW_INDIRECT_BUFFER_BINDING 0x8F43 #endif // ARB_shader_atomic_counters @@ -556,14 +558,14 @@ typedef char GLchar; #define GL_MAP_UNSYNCHRONIZED_BIT 0x0020 #endif -#define GL_INT64_ARB 0x140E -#define GL_UNSIGNED_INT64_ARB 0x140F -#define GL_INT64_VEC2_ARB 0x8FE9 -#define GL_INT64_VEC3_ARB 0x8FEA -#define GL_INT64_VEC4_ARB 0x8FEB -#define GL_UNSIGNED_INT64_VEC2_ARB 0x8FF5 -#define GL_UNSIGNED_INT64_VEC3_ARB 0x8FF6 -#define GL_UNSIGNED_INT64_VEC4_ARB 0x8FF7 +#define GL_INT64_ARB 0x140E +#define GL_UNSIGNED_INT64_ARB 0x140F +#define GL_INT64_VEC2_ARB 0x8FE9 +#define GL_INT64_VEC3_ARB 0x8FEA +#define GL_INT64_VEC4_ARB 0x8FEB +#define GL_UNSIGNED_INT64_VEC2_ARB 0x8FF5 +#define GL_UNSIGNED_INT64_VEC3_ARB 0x8FF6 +#define GL_UNSIGNED_INT64_VEC4_ARB 0x8FF7 /* ------------------------------ GL_KHR_debug ----------------------------- */ #ifndef GL_KHR_debug #define GL_KHR_debug 1 diff --git a/include/osg/PrimitiveSet b/include/osg/PrimitiveSet index aee28712b..0524de177 100644 --- a/include/osg/PrimitiveSet +++ b/include/osg/PrimitiveSet @@ -133,7 +133,15 @@ class OSG_EXPORT PrimitiveSet : public BufferData DrawElementsUBytePrimitiveType, DrawElementsUShortPrimitiveType, DrawElementsUIntPrimitiveType, - MultiDrawArraysPrimitiveType + MultiDrawArraysPrimitiveType, + DrawArraysIndirectPrimitiveType, + DrawElementsUByteIndirectPrimitiveType, + DrawElementsUShortIndirectPrimitiveType, + DrawElementsUIntIndirectPrimitiveType, + MultiDrawArraysIndirectPrimitiveType, + MultiDrawElementsUByteIndirectPrimitiveType, + MultiDrawElementsUShortIndirectPrimitiveType, + MultiDrawElementsUIntIndirectPrimitiveType }; enum Mode diff --git a/include/osg/PrimitiveSetIndirect b/include/osg/PrimitiveSetIndirect new file mode 100644 index 000000000..2ce5c1d8d --- /dev/null +++ b/include/osg/PrimitiveSetIndirect @@ -0,0 +1,671 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. + * + * osg/PrimitiveSetIndirect + * Author: Julien Valentin 2016-2017 +*/ + +#ifndef OSG_INDIRECTPRIMITIVESET +#define OSG_INDIRECTPRIMITIVESET 1 + +#include + + +namespace osg { + +///common interface for IndirectCommandDrawArrayss +class OSG_EXPORT IndirectCommandDrawArrays: public BufferData +{ +public: + IndirectCommandDrawArrays() : BufferData() { setBufferObject(new DrawIndirectBufferObject()); } + + IndirectCommandDrawArrays(const IndirectCommandDrawArrays& copy,const CopyOp& copyop/*=CopyOp::SHALLOW_COPY*/) : + BufferData(copy, copyop) {} + + virtual unsigned int getTotalDataSize() const { return getNumElements()*getElementSize(); } + + virtual unsigned int & count(const unsigned int&index)=0; + virtual unsigned int & instanceCount(const unsigned int&index)=0; + virtual unsigned int & first(const unsigned int&index)=0; + virtual unsigned int & baseInstance(const unsigned int&index)=0; + + virtual unsigned int getElementSize() const = 0; + virtual unsigned int getNumElements() const = 0; + virtual void reserveElements(const unsigned int) = 0; + virtual void resizeElements(const unsigned int) = 0; +}; + +class OSG_EXPORT IndirectCommandDrawElements: public BufferData +{ +public: + IndirectCommandDrawElements() : BufferData() { setBufferObject(new DrawIndirectBufferObject()); } + + IndirectCommandDrawElements(const IndirectCommandDrawElements& copy,const CopyOp& copyop/*=CopyOp::SHALLOW_COPY*/) + : BufferData(copy, copyop) {} + + virtual unsigned int getTotalDataSize() const { return getNumElements()*getElementSize(); } + + virtual unsigned int & count(const unsigned int&index)=0; + virtual unsigned int & instanceCount(const unsigned int&index)=0; + virtual unsigned int & firstIndex(const unsigned int&index)=0; + virtual unsigned int & baseVertex(const unsigned int&index)=0; + virtual unsigned int & baseInstance(const unsigned int&index)=0; + + virtual unsigned int getElementSize()const = 0; + virtual unsigned int getNumElements() const = 0; + virtual void reserveElements(const unsigned int) = 0; + virtual void resizeElements(const unsigned int) = 0; +}; + + + +/// DrawArraysCommand +struct DrawArraysIndirectCommand +{ + DrawArraysIndirectCommand(unsigned int pcount = 0, unsigned int pinstanceCount = 0, unsigned int pfirst = 0, unsigned int pbaseInstance = 0) : + count(pcount), instanceCount(pinstanceCount), first(pfirst), baseInstance(pbaseInstance) {} + + unsigned int count; + unsigned int instanceCount; + unsigned int first; + unsigned int baseInstance; +}; + +/// default implementation of IndirectCommandDrawArrays +/// DefaultIndirectCommandDrawArrays to be hosted on GPU +class OSG_EXPORT DefaultIndirectCommandDrawArrays: public IndirectCommandDrawArrays, public MixinVector +{ +public: + META_Object(osg,DefaultIndirectCommandDrawArrays) + + DefaultIndirectCommandDrawArrays() : IndirectCommandDrawArrays(), MixinVector() {} + DefaultIndirectCommandDrawArrays(const DefaultIndirectCommandDrawArrays& copy,const CopyOp& copyop/*=CopyOp::SHALLOW_COPY*/) : + IndirectCommandDrawArrays(copy, copyop),MixinVector() {} + + virtual const GLvoid* getDataPointer() const { return empty()?0:&front(); } + virtual unsigned int getElementSize()const { return 16u; }; + virtual unsigned int getNumElements() const { return static_cast(size()); } + virtual void reserveElements(const unsigned int n) {reserve(n);} + virtual void resizeElements(const unsigned int n) {resize(n);} + + virtual unsigned int & count(const unsigned int&index) { return at(index).count; } + virtual unsigned int & instanceCount(const unsigned int&index) { return at(index).instanceCount; } + virtual unsigned int & first(const unsigned int&index) { return at(index).first; } + virtual unsigned int & baseInstance(const unsigned int&index) { return at(index).baseInstance; } + +}; + + +/// default implementation of IndirectCommandDrawElements +/// DrawElementsCommand +struct DrawElementsIndirectCommand +{ + DrawElementsIndirectCommand(unsigned int pcount = 0, unsigned int pinstanceCount = 0, unsigned int pfirstIndex = 0, unsigned int pbaseVertex = 0, unsigned int pbaseInstance = 0) : + count(pcount), instanceCount(pinstanceCount), firstIndex(pfirstIndex), baseVertex(pbaseVertex), baseInstance(pbaseInstance) {} + + unsigned int count; + unsigned int instanceCount; + unsigned int firstIndex; + unsigned int baseVertex; + unsigned int baseInstance; +}; + +/// vector of DrawElementsCommand to be hosted on GPU +class OSG_EXPORT DefaultIndirectCommandDrawElements: public IndirectCommandDrawElements, public MixinVector +{ +public: + META_Object(osg,DefaultIndirectCommandDrawElements) + + DefaultIndirectCommandDrawElements() : IndirectCommandDrawElements(), MixinVector() {} + + DefaultIndirectCommandDrawElements(const DefaultIndirectCommandDrawElements& copy,const CopyOp& copyop/*=CopyOp::SHALLOW_COPY*/) : + IndirectCommandDrawElements(copy, copyop), MixinVector() {} + + virtual const GLvoid* getDataPointer() const { return empty()?0:&front(); } + virtual unsigned int getNumElements() const { return static_cast(size()); } + virtual unsigned int getElementSize()const { return 20u; }; + virtual void reserveElements(const unsigned int n) {reserve(n);} + virtual void resizeElements(const unsigned int n) {resize(n);} + + virtual unsigned int & count(const unsigned int&index) { return at(index).count; } + virtual unsigned int & instanceCount(const unsigned int&index) { return at(index).instanceCount; } + virtual unsigned int & firstIndex(const unsigned int&index) { return at(index).firstIndex; } + virtual unsigned int & baseVertex(const unsigned int&index) { return at(index).baseVertex; } + virtual unsigned int & baseInstance(const unsigned int&index) { return at(index).baseInstance; } + + +}; + +/////////////////////////////////////////////////////////////////////////////////////// +/// \brief The DrawElementsIndirect base PrimitiveSet +/// +class OSG_EXPORT DrawElementsIndirect : public DrawElements +{ +public: + + DrawElementsIndirect(Type primType=PrimitiveType, GLenum mode = 0,unsigned int firstCommand = 0, GLsizei stride = 0) : + DrawElements(primType,mode, 0),_firstCommand(firstCommand),_stride(stride) { setIndirectCommandArray(new DefaultIndirectCommandDrawElements()); } + + DrawElementsIndirect(const DrawElementsIndirect& rhs,const CopyOp& copyop=CopyOp::SHALLOW_COPY) : + DrawElements(rhs,copyop),_firstCommand(rhs._firstCommand), _stride(rhs._stride) { _indirectCommandArray=(DefaultIndirectCommandDrawElements*)copyop(rhs._indirectCommandArray.get()); } + + /// set command array of this indirect primitive set + inline void setIndirectCommandArray(IndirectCommandDrawElements*idc) + { + _indirectCommandArray = idc; + //ensure bo of idc is of the correct type + if(!dynamic_cast(_indirectCommandArray->getBufferObject())) + _indirectCommandArray->setBufferObject(new DrawIndirectBufferObject()); + } + + /// get command array of this indirect primitive set + inline IndirectCommandDrawElements* getIndirectCommandArray() { return _indirectCommandArray; } + inline const IndirectCommandDrawElements* getIndirectCommandArray() const { return _indirectCommandArray; } + + ///Further methods are for advanced DI when you plan to use your own IndirectCommandElement (stride) + ///or if you want to draw a particular command index of the IndirectCommandElement(FirstCommandToDraw) + + /// set offset of the first command to draw in the IndirectCommandDrawArrays + inline void setFirstCommandToDraw( unsigned int i) { _firstCommand = i; } + + /// get offset of the first command in the IndirectCommandDrawArrays + inline unsigned int getFirstCommandToDraw() const { return _firstCommand; } + + /// stride (to set if you use custom CommandArray) + inline void setStride( GLsizei i) { _stride=i; } + + /// stride (to set if you use custom CommandArray) + inline GLsizei getStride() const { return _stride; } + + virtual unsigned int getNumPrimitives() const=0; + +protected: + virtual ~DrawElementsIndirect() {} + + unsigned int _firstCommand; + GLsizei _stride; + ref_ptr _indirectCommandArray; +}; + +/////////////////////////////////////////////////////////////////////////////////////// +/// \brief The DrawElementsIndirectUByte PrimitiveSet +/// +class OSG_EXPORT DrawElementsIndirectUByte : public DrawElementsIndirect, public VectorGLubyte +{ +public: + + typedef VectorGLubyte vector_type; + + DrawElementsIndirectUByte(GLenum mode = 0/*,unsigned int firstCommand = 0, GLsizei stride = 0*/) : + DrawElementsIndirect(DrawElementsUByteIndirectPrimitiveType,mode) {} + + DrawElementsIndirectUByte(const DrawElementsIndirectUByte& array, const CopyOp& copyop=CopyOp::SHALLOW_COPY) : + DrawElementsIndirect(array,copyop), + vector_type(array) {} + + /** + * \param mode One of osg::PrimitiveSet::Mode. Determines the type of primitives used. + * \param no Number of intended elements. This will be the size of the underlying vector. + * \param ptr Pointer to a GLubyte to copy index data from. + */ + DrawElementsIndirectUByte(GLenum mode, unsigned int no, const GLubyte* ptr) : + DrawElementsIndirect(DrawElementsUByteIndirectPrimitiveType,mode), + vector_type(ptr,ptr+no) {} + + /** + * \param mode One of osg::PrimitiveSet::Mode. Determines the type of primitives used. + * \param no Number of intended elements. This will be the size of the underlying vector. + */ + DrawElementsIndirectUByte(GLenum mode, unsigned int no) : + DrawElementsIndirect(DrawElementsUByteIndirectPrimitiveType,mode), + vector_type(no) {} + + virtual Object* cloneType() const { return new DrawElementsIndirectUByte(); } + virtual Object* clone(const CopyOp& copyop) const { return new DrawElementsIndirectUByte(*this,copyop); } + virtual bool isSameKindAs(const Object* obj) const { return dynamic_cast(obj)!=NULL; } + virtual const char* libraryName() const { return "osg"; } + virtual const char* className() const { return "DrawElementsIndirectUByte"; } + + virtual const GLvoid* getDataPointer() const { return empty()?0:&front(); } + virtual unsigned int getTotalDataSize() const { return static_cast(size()); } + virtual bool supportsBufferObject() const { return false; } + + virtual void draw(State& state, bool useVertexBufferObjects) const; + + virtual void accept(PrimitiveFunctor& functor) const; + virtual void accept(PrimitiveIndexFunctor& functor) const; + + virtual unsigned int getNumIndices() const { return static_cast(size()); } + virtual unsigned int index(unsigned int pos) const { return (*this)[pos]; } + virtual void offsetIndices(int offset); + + virtual GLenum getDataType() { return GL_UNSIGNED_BYTE; } + + virtual void resizeElements(unsigned int numIndices) { resize(numIndices); } + virtual void reserveElements(unsigned int numIndices) { reserve(numIndices); } + + virtual void setElement(unsigned int i, unsigned int v) { (*this)[i] = v; } + virtual unsigned int getElement(unsigned int i) { return (*this)[i]; } + + virtual void addElement(unsigned int v) { push_back(GLubyte(v)); } + virtual unsigned int getNumPrimitives() const; + +protected: + + virtual ~DrawElementsIndirectUByte(); +}; + + +/////////////////////////////////////////////////////////////////////////////////////// +/// \brief The DrawElementsIndirectUShort PrimitiveSet +/// +class OSG_EXPORT DrawElementsIndirectUShort : public DrawElementsIndirect, public VectorGLushort +{ +public: + + typedef VectorGLushort vector_type; + + DrawElementsIndirectUShort(GLenum mode = 0/*,unsigned int firstCommand = 0, GLsizei stride = 0*/) : + DrawElementsIndirect(DrawElementsUShortIndirectPrimitiveType,mode) {} + + DrawElementsIndirectUShort(const DrawElementsIndirectUShort& array,const CopyOp& copyop=CopyOp::SHALLOW_COPY) : + DrawElementsIndirect(array,copyop), + vector_type(array) {} + + /** + * \param mode One of osg::PrimitiveSet::Mode. Determines the type of primitives used. + * \param no Number of intended elements. This will be the size of the underlying vector. + * \param ptr Pointer to a GLushort to copy index data from. + */ + DrawElementsIndirectUShort(GLenum mode, unsigned int no, const GLushort* ptr) : + DrawElementsIndirect(DrawElementsUShortIndirectPrimitiveType,mode), + vector_type(ptr,ptr+no) {} + + /** + * \param mode One of osg::PrimitiveSet::Mode. Determines the type of primitives used. + * \param no Number of intended elements. This will be the size of the underlying vector. + */ + DrawElementsIndirectUShort(GLenum mode, unsigned int no) : + DrawElementsIndirect(DrawElementsUShortIndirectPrimitiveType,mode), + vector_type(no) {} + + template + DrawElementsIndirectUShort(GLenum mode, InputIterator first,InputIterator last) : + DrawElementsIndirect(DrawElementsUShortIndirectPrimitiveType,mode), + vector_type(first,last) {} + + virtual Object* cloneType() const { return new DrawElementsIndirectUShort(); } + virtual Object* clone(const CopyOp& copyop) const { return new DrawElementsIndirectUShort(*this,copyop); } + virtual bool isSameKindAs(const Object* obj) const { return dynamic_cast(obj)!=NULL; } + virtual const char* libraryName() const { return "osg"; } + virtual const char* className() const { return "DrawElementsIndirectUShort"; } + + virtual const GLvoid* getDataPointer() const { return empty()?0:&front(); } + virtual unsigned int getTotalDataSize() const { return 2u*static_cast(size()); } + virtual bool supportsBufferObject() const { return false; } + + virtual void draw(State& state, bool useVertexBufferObjects) const; + + virtual void accept(PrimitiveFunctor& functor) const; + virtual void accept(PrimitiveIndexFunctor& functor) const; + + virtual unsigned int getNumIndices() const { return static_cast(size()); } + virtual unsigned int index(unsigned int pos) const { return (*this)[pos]; } + virtual void offsetIndices(int offset); + + virtual GLenum getDataType() { return GL_UNSIGNED_SHORT; } + virtual void resizeElements(unsigned int numIndices) { resize(numIndices); } + virtual void reserveElements(unsigned int numIndices) { reserve(numIndices); } + + virtual void setElement(unsigned int i, unsigned int v) { (*this)[i] = v; } + virtual unsigned int getElement(unsigned int i) { return (*this)[i]; } + + virtual void addElement(unsigned int v) { push_back(GLushort(v)); } + virtual unsigned int getNumPrimitives() const; + +protected: + + virtual ~DrawElementsIndirectUShort(); +}; + +/////////////////////////////////////////////////////////////////////////////////////// +/// \brief The DrawElementsIndirectUInt PrimitiveSet +/// +class OSG_EXPORT DrawElementsIndirectUInt : public DrawElementsIndirect, public VectorGLuint +{ +public: + + typedef VectorGLuint vector_type; + + DrawElementsIndirectUInt(GLenum mode = 0/*,unsigned int firstCommand = 0, GLsizei stride = 0*/) : + DrawElementsIndirect(DrawElementsUIntIndirectPrimitiveType,mode) {} + + DrawElementsIndirectUInt(const DrawElementsIndirectUInt& array,const CopyOp& copyop=CopyOp::SHALLOW_COPY) : + DrawElementsIndirect(array,copyop), + vector_type(array) {} + + /** + * \param mode One of osg::PrimitiveSet::Mode. Determines the type of primitives used. + * \param no Number of intended elements. This will be the size of the underlying vector. + * \param ptr Pointer to a GLunsigned int to copy index data from. + */ + DrawElementsIndirectUInt(GLenum mode, unsigned int no, const GLuint* ptr) : + DrawElementsIndirect(DrawElementsUIntIndirectPrimitiveType,mode), + vector_type(ptr,ptr+no) {} + + /** + * \param mode One of osg::PrimitiveSet::Mode. Determines the type of primitives used. + * \param no Number of intended elements. This will be the size of the underlying vector. + */ + DrawElementsIndirectUInt(GLenum mode, unsigned int no) : + DrawElementsIndirect(DrawElementsUIntIndirectPrimitiveType,mode), + vector_type(no) {} + + template + DrawElementsIndirectUInt(GLenum mode, InputIterator first,InputIterator last) : + DrawElementsIndirect(DrawElementsUIntIndirectPrimitiveType,mode), + vector_type(first,last) {} + + virtual Object* cloneType() const { return new DrawElementsIndirectUInt(); } + virtual Object* clone(const CopyOp& copyop) const { return new DrawElementsIndirectUInt(*this,copyop); } + virtual bool isSameKindAs(const Object* obj) const { return dynamic_cast(obj)!=NULL; } + virtual const char* libraryName() const { return "osg"; } + virtual const char* className() const { return "DrawElementsIndirectUInt"; } + + virtual const GLvoid* getDataPointer() const { return empty()?0:&front(); } + virtual unsigned int getTotalDataSize() const { return 4u*static_cast(size()); } + virtual bool supportsBufferObject() const { return false; } + + virtual void draw(State& state, bool useVertexBufferObjects) const; + + virtual void accept(PrimitiveFunctor& functor) const; + virtual void accept(PrimitiveIndexFunctor& functor) const; + + virtual unsigned int getNumIndices() const { return static_cast(size()); } + virtual unsigned int index(unsigned int pos) const { return (*this)[pos]; } + virtual void offsetIndices(int offset); + + virtual GLenum getDataType() { return GL_UNSIGNED_INT; } + virtual void resizeElements(unsigned int numIndices) { resize(numIndices); } + virtual void reserveElements(unsigned int numIndices) { reserve(numIndices); } + virtual void setElement(unsigned int i, unsigned int v) { (*this)[i] = v; } + virtual unsigned int getElement(unsigned int i) { return (*this)[i]; } + virtual void addElement(unsigned int v) { push_back(GLuint(v)); } + + virtual unsigned int getNumPrimitives() const; + +protected: + + virtual ~DrawElementsIndirectUInt(); +}; + +/////////////////////////////////////////////////////////////////////////////////////// +/// \brief The MultiDrawElementsIndirect PrimitiveSets +/// +class OSG_EXPORT MultiDrawElementsIndirectUShort : public DrawElementsIndirectUShort +{ +public: + MultiDrawElementsIndirectUShort(GLenum mode = 0/*,unsigned int firstCommand = 0, GLsizei stride = 0*/) : + DrawElementsIndirectUShort(mode),_count(0) { _primitiveType=(Type(MultiDrawElementsUShortIndirectPrimitiveType)); } + + MultiDrawElementsIndirectUShort(const MultiDrawElementsIndirectUShort& mdi,const CopyOp& copyop=CopyOp::SHALLOW_COPY) : + DrawElementsIndirectUShort(mdi,copyop),_count(mdi._count) {} + /** + * \param mode One of osg::PrimitiveSet::Mode. Determines the type of primitives used. + * \param no Number of intended elements. This will be the size of the underlying vector. + * \param ptr Pointer to a GLunsigned int to copy index data from. + */ + MultiDrawElementsIndirectUShort(GLenum mode, unsigned int no, const GLushort* ptr) : + DrawElementsIndirectUShort(mode,no,ptr) + {_primitiveType=(Type(MultiDrawElementsUShortIndirectPrimitiveType));} + + /** + * \param mode One of osg::PrimitiveSet::Mode. Determines the type of primitives used. + * \param no Number of intended elements. This will be the size of the underlying vector. + */ + MultiDrawElementsIndirectUShort(GLenum mode, unsigned int no) : + DrawElementsIndirectUShort(mode,no) + {_primitiveType=(Type(MultiDrawElementsUShortIndirectPrimitiveType));} + + template + MultiDrawElementsIndirectUShort(GLenum mode, InputIterator first,InputIterator last) : + DrawElementsIndirectUShort(mode,first,last) + {_primitiveType=(Type(MultiDrawElementsUShortIndirectPrimitiveType));} + + virtual osg::Object* cloneType() const { return new MultiDrawElementsIndirectUShort(); } + virtual osg::Object* clone(const osg::CopyOp& copyop) const { return new MultiDrawElementsIndirectUShort(*this,copyop); } + virtual bool isSameKindAs(const osg::Object* obj) const { return dynamic_cast(obj)!=NULL; } + virtual const char* className() const { return "MultiDrawElementsIndirectUShort"; } + + virtual void draw(State& state, bool useVertexBufferObjects) const; + virtual void accept(PrimitiveFunctor& functor) const; + virtual void accept(PrimitiveIndexFunctor& functor) const; + virtual unsigned int getNumPrimitives() const; + + ///if you want to draw a subset of the IndirectCommandElement(FirstCommandToDraw,NumCommandsToDraw) + + /// count of Indirect Command to execute + inline void setNumCommandsToDraw( unsigned int i) { _count=i; } + /// count of Indirect Command to execute + inline unsigned int getNumCommandsToDraw()const { return _count; } + +protected: + unsigned int _count; + virtual ~MultiDrawElementsIndirectUShort(); +}; + +class OSG_EXPORT MultiDrawElementsIndirectUByte : public DrawElementsIndirectUByte +{ +public: + MultiDrawElementsIndirectUByte(GLenum mode = 0) : + DrawElementsIndirectUByte(mode),_count(0) { _primitiveType=(Type(MultiDrawElementsUByteIndirectPrimitiveType)); } + + MultiDrawElementsIndirectUByte(const MultiDrawElementsIndirectUByte& mdi,const CopyOp& copyop=CopyOp::SHALLOW_COPY) : + DrawElementsIndirectUByte(mdi,copyop),_count(mdi._count) {} + /** + * \param mode One of osg::PrimitiveSet::Mode. Determines the type of primitives used. + * \param no Number of intended elements. This will be the size of the underlying vector. + * \param ptr Pointer to a GLunsigned int to copy index data from. + */ + MultiDrawElementsIndirectUByte(GLenum mode, unsigned int no, const GLubyte* ptr) : + DrawElementsIndirectUByte(mode,no,ptr) + {_primitiveType=(Type(MultiDrawElementsUByteIndirectPrimitiveType));} + + /** + * \param mode One of osg::PrimitiveSet::Mode. Determines the type of primitives used. + * \param no Number of intended elements. This will be the size of the underlying vector. + */ + MultiDrawElementsIndirectUByte(GLenum mode, unsigned int no) : + DrawElementsIndirectUByte(mode,no) + {_primitiveType=(Type(MultiDrawElementsUByteIndirectPrimitiveType));} + + template + MultiDrawElementsIndirectUByte(GLenum mode, InputIterator first,InputIterator last) : + DrawElementsIndirectUByte(mode,first,last) + {_primitiveType=(Type(MultiDrawElementsUByteIndirectPrimitiveType));} + + virtual osg::Object* cloneType() const { return new MultiDrawElementsIndirectUByte(); } + virtual osg::Object* clone(const osg::CopyOp& copyop) const { return new MultiDrawElementsIndirectUByte(*this,copyop); } + virtual bool isSameKindAs(const osg::Object* obj) const { return dynamic_cast(obj)!=NULL; } + virtual const char* className() const { return "MultiDrawElementsIndirectUByte"; } + + virtual void draw(State& state, bool useVertexBufferObjects) const; + virtual void accept(PrimitiveFunctor& functor) const; + virtual void accept(PrimitiveIndexFunctor& functor) const; + virtual unsigned int getNumPrimitives() const; + + /// count of Indirect Command to execute + inline void setNumCommandsToDraw( unsigned int i) { _count=i; } + /// count of Indirect Command to execute + inline unsigned int getNumCommandsToDraw()const { return _count; } + +protected: + unsigned int _count; + virtual ~MultiDrawElementsIndirectUByte(); +}; + +class OSG_EXPORT MultiDrawElementsIndirectUInt : public DrawElementsIndirectUInt +{ +public: + MultiDrawElementsIndirectUInt(GLenum mode = 0) : + DrawElementsIndirectUInt(mode),_count(0) { _primitiveType=(Type(MultiDrawElementsUIntIndirectPrimitiveType)); } + + MultiDrawElementsIndirectUInt(const MultiDrawElementsIndirectUInt& mdi,const CopyOp& copyop=CopyOp::SHALLOW_COPY) : + DrawElementsIndirectUInt(mdi,copyop),_count(mdi._count) {} + /** + * \param mode One of osg::PrimitiveSet::Mode. Determines the type of primitives used. + * \param no Number of intended elements. This will be the size of the underlying vector. + * \param ptr Pointer to a GLunsigned int to copy index data from. + */ + MultiDrawElementsIndirectUInt(GLenum mode, unsigned int no, const GLuint* ptr) : + DrawElementsIndirectUInt(mode,no,ptr) + {_primitiveType=(Type(MultiDrawElementsUIntIndirectPrimitiveType));} + + /** + * \param mode One of osg::PrimitiveSet::Mode. Determines the type of primitives used. + * \param no Number of intended elements. This will be the size of the underlying vector. + */ + MultiDrawElementsIndirectUInt(GLenum mode, unsigned int no) : + DrawElementsIndirectUInt(mode,no) + {_primitiveType=(Type(MultiDrawElementsUIntIndirectPrimitiveType));} + + template + MultiDrawElementsIndirectUInt(GLenum mode, InputIterator first,InputIterator last) : + DrawElementsIndirectUInt(mode,first,last) + {_primitiveType=(Type(MultiDrawElementsUIntIndirectPrimitiveType));} + + virtual osg::Object* cloneType() const { return new MultiDrawElementsIndirectUInt(); } + virtual osg::Object* clone(const osg::CopyOp& copyop) const { return new MultiDrawElementsIndirectUInt(*this,copyop); } + virtual bool isSameKindAs(const osg::Object* obj) const { return dynamic_cast(obj)!=NULL; } + virtual const char* className() const { return "MultiDrawElementsIndirectUInt"; } + + virtual void draw(State& state, bool useVertexBufferObjects) const; + virtual void accept(PrimitiveFunctor& functor) const; + virtual void accept(PrimitiveIndexFunctor& functor) const; + virtual unsigned int getNumPrimitives() const; + + /// count of Indirect Command to execute + inline void setNumCommandsToDraw( unsigned int i) { _count=i; } + /// count of Indirect Command to execute + inline unsigned int getNumCommandsToDraw()const { return _count; } + +protected: + unsigned int _count; + virtual ~MultiDrawElementsIndirectUInt(); +}; + +/////////////////////////////////////////////////////////////////////////////////////// +/// \brief The MultiDrawArraysIndirect PrimitiveSet +/// +class OSG_EXPORT DrawArraysIndirect : public osg::PrimitiveSet +{ +public: + + DrawArraysIndirect(GLenum mode=0, unsigned int firstcommand = 0, GLsizei stride = 0) : + osg::PrimitiveSet(Type(DrawArraysIndirectPrimitiveType), mode), + _firstCommand(firstcommand), _stride(stride) { setIndirectCommandArray(new DefaultIndirectCommandDrawArrays); } + + DrawArraysIndirect(const DrawArraysIndirect& dal,const CopyOp& copyop=CopyOp::SHALLOW_COPY) : + osg::PrimitiveSet(dal,copyop), + _firstCommand(dal._firstCommand), + _stride(dal._stride), + _indirectCommandArray((DefaultIndirectCommandDrawArrays*)copyop( dal._indirectCommandArray.get())) {} + + virtual osg::Object* cloneType() const { return new DrawArraysIndirect(); } + virtual osg::Object* clone(const osg::CopyOp& copyop) const { return new DrawArraysIndirect(*this,copyop); } + virtual bool isSameKindAs(const osg::Object* obj) const { return dynamic_cast(obj)!=NULL; } + virtual const char* libraryName() const { return "osg"; } + virtual const char* className() const { return "DrawArraysIndirect"; } + + virtual void draw(State& state, bool useVertexBufferObjects) const; + + virtual void accept(PrimitiveFunctor& functor) const; + virtual void accept(PrimitiveIndexFunctor& functor) const; + + virtual unsigned int getNumIndices() const; + virtual unsigned int index(unsigned int pos) const; + virtual void offsetIndices(int offset); + + virtual unsigned int getNumPrimitives() const; + + /// stride (to set if you use custom CommandArray) + inline void setStride( GLsizei i) { _stride=i; } + + /// stride (to set if you use custom CommandArray) + inline GLsizei getStride()const { return _stride; } + + /// set offset of the first command in the IndirectCommandDrawArrays + inline void setFirstCommandToDraw( unsigned int i) { _firstCommand=i; } + + /// get offset of the first command in the IndirectCommandDrawArrays + inline unsigned int getFirstCommandToDraw() const { return _firstCommand; } + + inline void setIndirectCommandArray(IndirectCommandDrawArrays*idc) + { + _indirectCommandArray = idc; + //ensure bo of idc is of the correct type + if(!dynamic_cast(_indirectCommandArray->getBufferObject())) + _indirectCommandArray->setBufferObject(new DrawIndirectBufferObject()); + } + inline const IndirectCommandDrawArrays* getIndirectCommandArray() const { return _indirectCommandArray; } + inline IndirectCommandDrawArrays* getIndirectCommandArray() { return _indirectCommandArray; } + +protected: + + unsigned int _firstCommand; + GLsizei _stride; + ref_ptr _indirectCommandArray; + +}; + +/////////////////////////////////////////////////////////////////////////////////////// +/// \brief The MultiDrawArraysIndirect PrimitiveSet +/// +class OSG_EXPORT MultiDrawArraysIndirect : public DrawArraysIndirect +{ +public: + + MultiDrawArraysIndirect(GLenum mode=0, unsigned int firstcommand = 0, unsigned int count = 0, GLsizei stride = 0) : + osg::DrawArraysIndirect(mode, firstcommand, stride), _count(count) { _primitiveType=Type(MultiDrawArraysIndirectPrimitiveType); } + + MultiDrawArraysIndirect(const MultiDrawArraysIndirect& dal,const CopyOp& copyop=CopyOp::SHALLOW_COPY) : + osg::DrawArraysIndirect(dal,copyop), _count(dal._count) {} + + virtual osg::Object* cloneType() const { return new MultiDrawArraysIndirect(); } + virtual osg::Object* clone(const osg::CopyOp& copyop) const { return new MultiDrawArraysIndirect(*this,copyop); } + virtual bool isSameKindAs(const osg::Object* obj) const { return dynamic_cast(obj)!=NULL; } + virtual const char* className() const { return "MultiDrawArraysIndirect"; } + + virtual void draw(State& state, bool useVertexBufferObjects) const; + + virtual void accept(PrimitiveFunctor& functor) const; + virtual void accept(PrimitiveIndexFunctor& functor) const; + + virtual unsigned int getNumIndices() const; + virtual unsigned int index(unsigned int pos) const; + virtual void offsetIndices(int offset); + + virtual unsigned int getNumPrimitives() const; + + /// count of Indirect Command to execute + inline void setNumCommandsToDraw( unsigned int i) { _count=i; } + /// count of Indirect Command to execute + inline unsigned int getNumCommandsToDraw()const { return _count; } + +protected: + unsigned int _count; + +}; + +} + +#endif diff --git a/include/osg/State b/include/osg/State index ec20b479d..ee5415660 100644 --- a/include/osg/State +++ b/include/osg/State @@ -591,6 +591,27 @@ class OSG_EXPORT State : public Referenced } + inline void bindDrawIndirectBufferObject(osg::GLBufferObject* ibo) + { + if (ibo->isDirty()) + { + ibo->compileBuffer(); + _currentDIBO = ibo; + } + else if (ibo != _currentDIBO) + { + ibo->bindBuffer(); + _currentDIBO = ibo; + } + } + + inline void unbindDrawIndirectBufferObject() + { + if (!_currentDIBO) return; + _glBindBuffer(GL_DRAW_INDIRECT_BUFFER,0); + _currentDIBO = 0; + } + void setCurrentVertexArrayObject(GLuint vao) { _currentVAO = vao; } GLuint getCurrentVertexArrayObject() const { return _currentVAO; } @@ -1259,6 +1280,7 @@ class OSG_EXPORT State : public Referenced unsigned int _currentActiveTextureUnit; unsigned int _currentClientActiveTextureUnit; GLBufferObject* _currentPBO; + GLBufferObject* _currentDIBO; GLuint _currentVAO; diff --git a/src/osg/BufferIndexBinding.cpp b/src/osg/BufferIndexBinding.cpp index 28c7b466d..418f208b2 100644 --- a/src/osg/BufferIndexBinding.cpp +++ b/src/osg/BufferIndexBinding.cpp @@ -174,34 +174,4 @@ ShaderStorageBufferBinding::ShaderStorageBufferBinding(const ShaderStorageBuffer } -DrawIndirectBufferBinding::DrawIndirectBufferBinding( ) - : BufferIndexBinding(GL_DRAW_INDIRECT_BUFFER, 0) -{ -} -void DrawIndirectBufferBinding::apply(State& state) const -{ - if (_bufferData.valid()) - { - BufferObject * bo = _bufferData->getBufferObject(); - GLBufferObject* glObject - = bo->getOrCreateGLBufferObject(state.getContextID()); - if (!glObject->_extensions->isUniformBufferObjectSupported) - return; - if (glObject->isDirty()) glObject->compileBuffer(); - glObject->_extensions->glBindBuffer (_target, glObject->getGLObjectID()); - } -} -DrawIndirectBufferBinding::DrawIndirectBufferBinding( BufferData* bo) - : BufferIndexBinding(GL_DRAW_INDIRECT_BUFFER, 0, bo, 0, 0) -{ - -} - -DrawIndirectBufferBinding::DrawIndirectBufferBinding(const DrawIndirectBufferBinding& rhs, - const CopyOp& copyop) - : BufferIndexBinding(rhs, copyop) -{ -} - - } // namespace osg diff --git a/src/osg/BufferObject.cpp b/src/osg/BufferObject.cpp index 9e2199911..46fa4e869 100644 --- a/src/osg/BufferObject.cpp +++ b/src/osg/BufferObject.cpp @@ -1358,6 +1358,50 @@ const DrawElements* ElementBufferObject::getDrawElements(unsigned int i) const return dynamic_cast(getBufferData(i)); } +////////////////////////////////////////////////////////////////////////////////// +// +// DrawIndirectBufferObject +// +DrawIndirectBufferObject::DrawIndirectBufferObject() +{ + setTarget(GL_DRAW_INDIRECT_BUFFER); + setUsage(GL_STATIC_DRAW_ARB); +// setUsage(GL_STREAM_DRAW_ARB); +} + +DrawIndirectBufferObject::DrawIndirectBufferObject(const DrawIndirectBufferObject& vbo,const CopyOp& copyop): + BufferObject(vbo,copyop) +{ +} + +DrawIndirectBufferObject::~DrawIndirectBufferObject() +{ +} + +unsigned int DrawIndirectBufferObject::addArray(osg::Array* array) +{ + return addBufferData(array); +} + +void DrawIndirectBufferObject::removeArray(osg::Array* array) +{ + removeBufferData(array); +} + +void DrawIndirectBufferObject::setArray(unsigned int i, Array* array) +{ + setBufferData(i,array); +} + +Array* DrawIndirectBufferObject::getArray(unsigned int i) +{ + return dynamic_cast(getBufferData(i)); +} + +const Array* DrawIndirectBufferObject::getArray(unsigned int i) const +{ + return dynamic_cast(getBufferData(i)); +} ////////////////////////////////////////////////////////////////////////////////// // diff --git a/src/osg/CMakeLists.txt b/src/osg/CMakeLists.txt index aa1561869..845306551 100644 --- a/src/osg/CMakeLists.txt +++ b/src/osg/CMakeLists.txt @@ -136,6 +136,7 @@ SET(TARGET_H ${HEADER_PATH}/Polytope ${HEADER_PATH}/PositionAttitudeTransform ${HEADER_PATH}/PrimitiveSet + ${HEADER_PATH}/PrimitiveSetIndirect ${HEADER_PATH}/PrimitiveRestartIndex ${HEADER_PATH}/Program ${HEADER_PATH}/Projection @@ -342,6 +343,7 @@ SET(TARGET_SRC Polytope.cpp PositionAttitudeTransform.cpp PrimitiveSet.cpp + PrimitiveSetIndirect.cpp PrimitiveRestartIndex.cpp Program.cpp Projection.cpp diff --git a/src/osg/PrimitiveSetIndirect.cpp b/src/osg/PrimitiveSetIndirect.cpp new file mode 100644 index 000000000..424c946e5 --- /dev/null +++ b/src/osg/PrimitiveSetIndirect.cpp @@ -0,0 +1,618 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * OpenSceneGraph Public License for more details. + * + * osg/PrimitiveSetIndirect.cpp + * Author: Julien Valentin 2016-2017 +*/ + +#include +#include +#include +#include +#include + +/// TODO: add base vertex feature to PrimitiveFunctor and PrimitiveIndexFunctor +//#define PRIMFUNCTORBASEVERTEX 1 + +using namespace osg; +//////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// DrawElementsIndirect +// +template +inline unsigned int getNumPrimitivesDI( const T&_this ) +{ + unsigned int offset= _this.getFirstCommandToDraw(); + IndirectCommandDrawElements *cmd=const_cast(_this.getIndirectCommandArray()); + unsigned int total=0; + switch(_this.getMode()) + { + case(PrimitiveSet::POINTS): + return cmd->count(offset); + case(PrimitiveSet::LINES): + return cmd->count(offset)/2; + case(PrimitiveSet::TRIANGLES): + return cmd->count(offset)/3; + case(PrimitiveSet::QUADS): + return cmd->count(offset)/4; + case(PrimitiveSet::LINE_STRIP): + case(PrimitiveSet::LINE_LOOP): + case(PrimitiveSet::TRIANGLE_STRIP): + case(PrimitiveSet::TRIANGLE_FAN): + case(PrimitiveSet::QUAD_STRIP): + case(PrimitiveSet::PATCHES): + case(PrimitiveSet::POLYGON): + { + return 1; + } + } + return total; +} + +unsigned int DrawElementsIndirectUInt::getNumPrimitives() const { return getNumPrimitivesDI(*this); } +unsigned int DrawElementsIndirectUByte::getNumPrimitives() const { return getNumPrimitivesDI(*this); } +unsigned int DrawElementsIndirectUShort::getNumPrimitives() const { return getNumPrimitivesDI(*this); } + +void DrawElementsIndirectUInt::draw(State& state, bool useVertexBufferObjects) const +{ GLBufferObject* dibo = _indirectCommandArray->getBufferObject()->getOrCreateGLBufferObject( state.getContextID() ); + state.bindDrawIndirectBufferObject(dibo); + + GLenum mode = _mode; +#if defined(OSG_GLES1_AVAILABLE) || defined(OSG_GLES2_AVAILABLE) + if (mode==GL_POLYGON) mode = GL_TRIANGLE_FAN; + if (mode==GL_QUAD_STRIP) mode = GL_TRIANGLE_STRIP; +#endif + + GLBufferObject* ebo = getOrCreateGLBufferObject(state.getContextID()); + + assert (useVertexBufferObjects && ebo); + + state.bindElementBufferObject(ebo); + + state.get()-> glDrawElementsIndirect(mode, GL_UNSIGNED_INT, + (const GLvoid *)(dibo->getOffset(_indirectCommandArray->getBufferIndex()) //command array adress + +_firstCommand* _indirectCommandArray->getElementSize())// runtime offset computaion can be sizeof(*_indirectCommandArray->begin()) + ); +} + +DrawElementsIndirectUInt::~DrawElementsIndirectUInt() +{ + releaseGLObjects(); +} +void DrawElementsIndirectUInt::offsetIndices(int offset) +{ + for(iterator itr=begin(); + itr!=end(); + ++itr) + { + *itr += offset; + } +} +void DrawElementsIndirectUInt::accept(PrimitiveFunctor& functor) const +{ +#ifdef PRIMFUNCTORBASEVERTEX + // TODO: add base vertex parameter in PrimitiveFunctor and PrimitiveIndexFunctor drawelements method + if (!empty()) + functor.drawElements(_mode,_indirectCommandArray->count(_firstCommand), + &(*this)[_indirectCommandArray->firstIndex(_firstCommand)], + _indirectCommandArray->baseVertex(_firstCommand)); +#endif +} + +void DrawElementsIndirectUInt::accept(PrimitiveIndexFunctor& functor) const +{ +#ifdef PRIMFUNCTORBASEVERTEX + // TODO: add base vertex parameter in PrimitiveFunctor and PrimitiveIndexFunctor drawelements method + if (!empty()) + functor.drawElements(_mode,_indirectCommandArray->count(_firstCommand), + &(*this)[_indirectCommandArray->firstIndex(_firstCommand)], + _indirectCommandArray->baseVertex(_firstCommand)); +#endif + +} + +void DrawElementsIndirectUByte::draw(State& state, bool useVertexBufferObjects) const +{ GLBufferObject* dibo = _indirectCommandArray->getBufferObject()->getOrCreateGLBufferObject( state.getContextID() ); + state.bindDrawIndirectBufferObject(dibo); + + GLenum mode = _mode; +#if defined(OSG_GLES1_AVAILABLE) || defined(OSG_GLES2_AVAILABLE) + if (mode==GL_POLYGON) mode = GL_TRIANGLE_FAN; + if (mode==GL_QUAD_STRIP) mode = GL_TRIANGLE_STRIP; +#endif + + GLBufferObject* ebo = getOrCreateGLBufferObject(state.getContextID()); + + assert (useVertexBufferObjects && ebo); + + state.bindElementBufferObject(ebo); + + state.get()-> glDrawElementsIndirect(mode, GL_UNSIGNED_BYTE, + (const GLvoid *)(dibo->getOffset(_indirectCommandArray->getBufferIndex())+_firstCommand* _indirectCommandArray->getElementSize())); +} + +DrawElementsIndirectUByte::~DrawElementsIndirectUByte() +{ + releaseGLObjects(); +} + +void DrawElementsIndirectUByte::offsetIndices(int offset) +{ + for(iterator itr=begin(); + itr!=end(); + ++itr) + { + *itr += offset; + } +} +void DrawElementsIndirectUByte::accept(PrimitiveFunctor& functor) const +{ +#ifdef PRIMFUNCTORBASEVERTEX + // TODO: add base vertex parameter in PrimitiveFunctor and PrimitiveIndexFunctor drawelements method + if (!empty()) + functor.drawElements(_mode,_indirectCommandArray->count(_firstCommand), + &(*this)[_indirectCommandArray->firstIndex(_firstCommand)], + _indirectCommandArray->baseVertex(_firstCommand)); +#endif +} + +void DrawElementsIndirectUByte::accept(PrimitiveIndexFunctor& functor) const +{ +#ifdef PRIMFUNCTORBASEVERTEX + // TODO: add base vertex parameter in PrimitiveFunctor and PrimitiveIndexFunctor drawelements method + if (!empty()) + functor.drawElements(_mode,_indirectCommandArray->count(_firstCommand), + &(*this)[_indirectCommandArray->firstIndex(_firstCommand)], + _indirectCommandArray->baseVertex(_firstCommand)); +#endif +} + +void DrawElementsIndirectUShort::draw(State& state, bool useVertexBufferObjects) const +{ + GLBufferObject* dibo = _indirectCommandArray->getBufferObject()->getOrCreateGLBufferObject( state.getContextID() ); + state.bindDrawIndirectBufferObject(dibo); + + GLenum mode = _mode; +#if defined(OSG_GLES1_AVAILABLE) || defined(OSG_GLES2_AVAILABLE) + if (mode==GL_POLYGON) mode = GL_TRIANGLE_FAN; + if (mode==GL_QUAD_STRIP) mode = GL_TRIANGLE_STRIP; +#endif + + GLBufferObject* ebo = getOrCreateGLBufferObject(state.getContextID()); + + assert (useVertexBufferObjects && ebo); + + state.bindElementBufferObject(ebo); + + state.get()-> glDrawElementsIndirect(mode, GL_UNSIGNED_SHORT, + (const GLvoid *)(dibo->getOffset(_indirectCommandArray->getBufferIndex())+_firstCommand* _indirectCommandArray->getElementSize())); +} + +DrawElementsIndirectUShort::~DrawElementsIndirectUShort() +{ + releaseGLObjects(); +} + +void DrawElementsIndirectUShort::offsetIndices(int offset) +{ + for(iterator itr=begin(); + itr!=end(); + ++itr) + { + *itr += offset; + } +} +void DrawElementsIndirectUShort::accept(PrimitiveFunctor& functor) const +{ +#ifdef PRIMFUNCTORBASEVERTEX + // TODO: add base vertex parameter in PrimitiveFunctor and PrimitiveIndexFunctor drawelements method + if (!empty()) + functor.drawElements(_mode,_indirectCommandArray->count(_firstCommand), + &(*this)[_indirectCommandArray->firstIndex(_firstCommand)], + _indirectCommandArray->baseVertex(_firstCommand)); +#endif +} + +void DrawElementsIndirectUShort::accept(PrimitiveIndexFunctor& functor) const +{ +#ifdef PRIMFUNCTORBASEVERTEX + // TODO: add base vertex parameter in PrimitiveFunctor and PrimitiveIndexFunctor drawelements method + if (!empty()) + functor.drawElements(_mode,_indirectCommandArray->count(_firstCommand), + &(*this)[_indirectCommandArray->firstIndex(_firstCommand)], + _indirectCommandArray->baseVertex(_firstCommand)); +#endif + +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// MultiDrawElementsIndirect +// +template inline +unsigned int getNumPrimitivesMDI( const T&_this) +{ + IndirectCommandDrawElements *_indirectCommandArray=const_cast(_this.getIndirectCommandArray()); + unsigned int total=0; + switch(_this.getMode()) + { + case(PrimitiveSet::POINTS): + for(unsigned int i=0;i<_indirectCommandArray->getNumElements();++i) + total+=_indirectCommandArray->count(i); + break; + case(PrimitiveSet::LINES): + for(unsigned int i=0;i<_indirectCommandArray->getNumElements();++i) + total+=_indirectCommandArray->count(i)/2; + break; + case(PrimitiveSet::TRIANGLES): + for(unsigned int i=0;i<_indirectCommandArray->getNumElements();++i) + total+=_indirectCommandArray->count(i)/3; + break; + case(PrimitiveSet::QUADS): + for(unsigned int i=0;i<_indirectCommandArray->getNumElements();++i) + total+=_indirectCommandArray->count(i)/4; + break; + case(PrimitiveSet::LINE_STRIP): + case(PrimitiveSet::LINE_LOOP): + case(PrimitiveSet::TRIANGLE_STRIP): + case(PrimitiveSet::TRIANGLE_FAN): + case(PrimitiveSet::QUAD_STRIP): + case(PrimitiveSet::PATCHES): + case(PrimitiveSet::POLYGON): + { + unsigned int primcount = _indirectCommandArray->getNumElements(); + return primcount; + } + } + return total; +} + +unsigned int MultiDrawElementsIndirectUInt::getNumPrimitives() const { return getNumPrimitivesMDI(*this); } +unsigned int MultiDrawElementsIndirectUByte::getNumPrimitives() const { return getNumPrimitivesMDI(*this); } +unsigned int MultiDrawElementsIndirectUShort::getNumPrimitives() const { return getNumPrimitivesMDI(*this); } + +//////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// MultiDrawElementsIndirectUByte +// +MultiDrawElementsIndirectUByte::~MultiDrawElementsIndirectUByte() +{ + releaseGLObjects(); +} + +void MultiDrawElementsIndirectUByte::draw(State& state, bool useVertexBufferObjects) const +{ + GLBufferObject* dibo = _indirectCommandArray->getBufferObject()->getOrCreateGLBufferObject( state.getContextID() ); + + state.bindDrawIndirectBufferObject(dibo); + GLenum mode = _mode; +#if defined(OSG_GLES1_AVAILABLE) || defined(OSG_GLES2_AVAILABLE) + if (mode==GL_POLYGON) mode = GL_TRIANGLE_FAN; + if (mode==GL_QUAD_STRIP) mode = GL_TRIANGLE_STRIP; +#endif + + GLBufferObject* ebo = getOrCreateGLBufferObject(state.getContextID()); + + assert (useVertexBufferObjects && ebo); + + state.bindElementBufferObject(ebo); + + state.get()-> glMultiDrawElementsIndirect(mode, GL_UNSIGNED_BYTE, + (const GLvoid *)(dibo->getOffset(_indirectCommandArray->getBufferIndex())),_indirectCommandArray->getNumElements(), _stride); +} + +void MultiDrawElementsIndirectUByte::accept(PrimitiveFunctor& functor) const +{ +#ifdef PRIMFUNCTORBASEVERTEX + //TODO: add base vertex parameter in PrimitiveFunctor and PrimitiveIndexFunctor drawelements method + unsigned int maxindex= (_count>0) ? _firstCommand + _count : _indirectCommandArray->getNumElements() - _firstCommand; + if (!empty() ) + for(unsigned int i = _firstCommand; icount(i), + &(*this)[_indirectCommandArray->firstIndex(i)], + _indirectCommandArray->baseVertex(i)); +#endif +} + +void MultiDrawElementsIndirectUByte::accept(PrimitiveIndexFunctor& functor) const +{ +#ifdef PRIMFUNCTORBASEVERTEX + //TODO: add base vertex parameter in PrimitiveFunctor and PrimitiveIndexFunctor drawelements method + unsigned int maxindex= (_count>0) ? _firstCommand + _count : _indirectCommandArray->getNumElements() - _firstCommand; + if (!empty() ) + for(unsigned int i = _firstCommand; icount(i), + &(*this)[_indirectCommandArray->firstIndex(i)], + _indirectCommandArray->baseVertex(i)); +#endif +} + + + + +//////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// MultiDrawElementsIndirectUShort +// +MultiDrawElementsIndirectUShort::~MultiDrawElementsIndirectUShort() +{ + releaseGLObjects(); +} + +void MultiDrawElementsIndirectUShort::draw(State& state, bool useVertexBufferObjects) const +{ GLBufferObject* dibo = _indirectCommandArray->getBufferObject()->getOrCreateGLBufferObject( state.getContextID() ); + state.bindDrawIndirectBufferObject(dibo); + + GLenum mode = _mode; +#if defined(OSG_GLES1_AVAILABLE) || defined(OSG_GLES2_AVAILABLE) + if (mode==GL_POLYGON) mode = GL_TRIANGLE_FAN; + if (mode==GL_QUAD_STRIP) mode = GL_TRIANGLE_STRIP; +#endif + + GLBufferObject* ebo = getOrCreateGLBufferObject(state.getContextID()); + + assert (useVertexBufferObjects && ebo); + + state.bindElementBufferObject(ebo); + + state.get()-> glMultiDrawElementsIndirect(mode, GL_UNSIGNED_SHORT, (const GLvoid *)(dibo->getOffset(_indirectCommandArray->getBufferIndex())), + (_count>0) ?_count:_indirectCommandArray->getNumElements(),_stride); +} + +void MultiDrawElementsIndirectUShort::accept(PrimitiveFunctor& functor) const +{ +#ifdef PRIMFUNCTORBASEVERTEX + //TODO: add base vertex parameter in PrimitiveFunctor and PrimitiveIndexFunctor drawelements method + unsigned int maxindex= (_count>0) ? _firstCommand + _count : _indirectCommandArray->getNumElements() - _firstCommand; + if (!empty() ) + for(unsigned int i = _firstCommand; icount(i), + &(*this)[_indirectCommandArray->firstIndex(i)], + _indirectCommandArray->baseVertex(i)); +#endif +} + +void MultiDrawElementsIndirectUShort::accept(PrimitiveIndexFunctor& functor) const +{ +#ifdef PRIMFUNCTORBASEVERTEX + //TODO: add base vertex parameter in PrimitiveFunctor and PrimitiveIndexFunctor drawelements method + unsigned int maxindex = (_count>0) ?_firstCommand + _count : _indirectCommandArray->getNumElements() - _firstCommand; + if (!empty() ) + for(unsigned int i = _firstCommand; icount(i), + &(*this)[_indirectCommandArray->firstIndex(i)], + _indirectCommandArray->baseVertex(i)); +#endif +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// MultiDrawElementsIndirectUInt +// +MultiDrawElementsIndirectUInt::~MultiDrawElementsIndirectUInt() +{ + releaseGLObjects(); +} + +void MultiDrawElementsIndirectUInt::draw(State& state, bool useVertexBufferObjects) const +{ + GLBufferObject* dibo = _indirectCommandArray->getBufferObject()->getOrCreateGLBufferObject( state.getContextID() ); + state.bindDrawIndirectBufferObject(dibo); + GLenum mode = _mode; +#if defined(OSG_GLES1_AVAILABLE) || defined(OSG_GLES2_AVAILABLE) + if (mode==GL_POLYGON) mode = GL_TRIANGLE_FAN; + if (mode==GL_QUAD_STRIP) mode = GL_TRIANGLE_STRIP; +#endif + + GLBufferObject* ebo = getOrCreateGLBufferObject(state.getContextID()); + + assert (useVertexBufferObjects && ebo); + + state.bindElementBufferObject(ebo); + + state.get()-> glMultiDrawElementsIndirect(mode, GL_UNSIGNED_INT, (const GLvoid *)(dibo->getOffset(_indirectCommandArray->getBufferIndex())), + (_count>0) ? _count:_indirectCommandArray->getNumElements(), _stride); +} + +void MultiDrawElementsIndirectUInt::accept(PrimitiveFunctor& functor) const +{ +#ifdef PRIMFUNCTORBASEVERTEX + //TODO: add base vertex parameter in PrimitiveFunctor and PrimitiveIndexFunctor drawelements method + unsigned int maxindex= (_count>0) ? _firstCommand + _count : _indirectCommandArray->getNumElements() - _firstCommand; + if (!empty() ) + for(unsigned int i = _firstCommand; icount(i), + &(*this)[_indirectCommandArray->firstIndex(i)], + _indirectCommandArray->baseVertex(i)); +#endif +} + +void MultiDrawElementsIndirectUInt::accept(PrimitiveIndexFunctor& functor) const +{ +#ifdef PRIMFUNCTORBASEVERTEX + //TODO: add base vertex parameter in PrimitiveFunctor and PrimitiveIndexFunctor drawelements method + unsigned int maxindex = (_count>0) ?_firstCommand + _count : _indirectCommandArray->getNumElements() - _firstCommand; + if (!empty() ) + for(unsigned int i = _firstCommand; icount(i), + &(*this)[_indirectCommandArray->firstIndex(i)], + _indirectCommandArray->baseVertex(i)); +#endif +} + + +//////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// MultiDrawArrays +// +void DrawArraysIndirect::draw(osg::State& state, bool) const +{ + GLBufferObject* dibo = _indirectCommandArray->getBufferObject()->getOrCreateGLBufferObject( state.getContextID() ); + state.bindDrawIndirectBufferObject(dibo); + + GLExtensions* ext = state.get(); + + ext->glDrawArraysIndirect(_mode, (const GLvoid *)(dibo->getOffset(_indirectCommandArray->getBufferIndex())+_firstCommand* _indirectCommandArray->getElementSize())); +} + +void DrawArraysIndirect::accept(PrimitiveFunctor& functor) const +{ + functor.drawArrays(_mode, _indirectCommandArray->first(_firstCommand), _indirectCommandArray->count(_firstCommand)); +} + +void DrawArraysIndirect::accept(PrimitiveIndexFunctor& functor) const +{ + functor.drawArrays(_mode, _indirectCommandArray->first(_firstCommand), _indirectCommandArray->count(_firstCommand)); +} + +unsigned int DrawArraysIndirect::getNumIndices() const +{ + return _indirectCommandArray->count(_firstCommand); +} + +unsigned int DrawArraysIndirect::index(unsigned int pos) const +{ + return _indirectCommandArray->first(_firstCommand)+ pos; +} + +void DrawArraysIndirect::offsetIndices(int offset) +{ + _indirectCommandArray->first(_firstCommand)+= offset; +} + +unsigned int DrawArraysIndirect::getNumPrimitives() const +{ + switch(_mode) + { + case(POINTS): + return _indirectCommandArray->count(_firstCommand); + case(LINES): + return _indirectCommandArray->count(_firstCommand)/2; + case(TRIANGLES): + return _indirectCommandArray->count(_firstCommand)/3; + case(QUADS): + return _indirectCommandArray->count(_firstCommand)/4; + case(LINE_STRIP): + case(LINE_LOOP): + case(TRIANGLE_STRIP): + case(TRIANGLE_FAN): + case(QUAD_STRIP): + case(PATCHES): + case(POLYGON): + { + return 1; + } + } + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// MultiDrawArrays +// +void MultiDrawArraysIndirect::draw(osg::State& state, bool) const +{ + GLBufferObject* dibo = _indirectCommandArray->getBufferObject()->getOrCreateGLBufferObject( state.getContextID() ); + state.bindDrawIndirectBufferObject(dibo); + + GLExtensions* ext = state.get(); + + ext->glMultiDrawArraysIndirect(_mode, (const GLvoid *)(dibo->getOffset(_indirectCommandArray->getBufferIndex())+_firstCommand*_indirectCommandArray->getElementSize()), + (_count>0) ?_count:_indirectCommandArray->getNumElements(), _stride); + +} + +void MultiDrawArraysIndirect::accept(PrimitiveFunctor& functor) const +{ + unsigned int maxindex= (_count>0) ? _firstCommand + _count : _indirectCommandArray->getNumElements() - _firstCommand; + for(unsigned int i = _firstCommand; ifirst(i), _indirectCommandArray->count(i)); + } +} + +void MultiDrawArraysIndirect::accept(PrimitiveIndexFunctor& functor) const +{ + unsigned int maxindex= (_count>0) ? _firstCommand + _count : _indirectCommandArray->getNumElements() - _firstCommand; + for(unsigned int i = _firstCommand; ifirst(i), _indirectCommandArray->count(i)); + } +} + +unsigned int MultiDrawArraysIndirect::getNumIndices() const +{ + unsigned int total=0; + unsigned int maxindex= (_count>0) ? _firstCommand + _count : _indirectCommandArray->getNumElements() - _firstCommand; + for(unsigned int i = _firstCommand; icount(i); + + return total; +} + +unsigned int MultiDrawArraysIndirect::index(unsigned int pos) const +{ + unsigned int i = 0, maxindex= (_count>0) ? _firstCommand + _count : _indirectCommandArray->getNumElements() - _firstCommand; + for(i=_firstCommand; icount(i); + if (pos=maxindex) return 0; + return _indirectCommandArray->first(maxindex-1) + pos; + +} + +void MultiDrawArraysIndirect::offsetIndices(int offset) +{ + unsigned int maxindex= (_count>0) ? _firstCommand + _count : _indirectCommandArray->getNumElements() - _firstCommand; + for(unsigned int i = _firstCommand; ifirst(i) += offset; +} + +unsigned int MultiDrawArraysIndirect::getNumPrimitives() const +{ + unsigned int total=0;unsigned int maxindex= (_count>0) ? _firstCommand + _count : _indirectCommandArray->getNumElements() - _firstCommand; + + switch(_mode) + { + case(POINTS): + for(unsigned int i = _firstCommand; icount(i); + break; + case(LINES): + for(unsigned int i = _firstCommand; icount(i)/2; + break; + case(TRIANGLES): + for(unsigned int i = _firstCommand; icount(i)/3; + break; + case(QUADS): + for(unsigned int i = _firstCommand; icount(i)/4; + break; + case(LINE_STRIP): + case(LINE_LOOP): + case(TRIANGLE_STRIP): + case(TRIANGLE_FAN): + case(QUAD_STRIP): + case(PATCHES): + case(POLYGON): + { + unsigned int primcount = _indirectCommandArray->getNumElements(); + return primcount; + } + } + return total; +} diff --git a/src/osg/State.cpp b/src/osg/State.cpp index e8c2446ca..c652d4cc6 100644 --- a/src/osg/State.cpp +++ b/src/osg/State.cpp @@ -89,6 +89,7 @@ State::State(): _currentClientActiveTextureUnit=0; _currentPBO = 0; + _currentDIBO = 0; _currentVAO = 0; _isSecondaryColorSupported = false; diff --git a/src/osgUtil/DrawElementTypeSimplifier.cpp b/src/osgUtil/DrawElementTypeSimplifier.cpp index 6397f8e06..14f359649 100644 --- a/src/osgUtil/DrawElementTypeSimplifier.cpp +++ b/src/osgUtil/DrawElementTypeSimplifier.cpp @@ -1,3 +1,4 @@ +#include #include #include @@ -61,6 +62,44 @@ void DrawElementTypeSimplifier::simplify(osg::Geometry & geometry) const break; } + case osg::PrimitiveSet::DrawElementsUShortIndirectPrimitiveType: + { + osg::DrawElementsIndirectUShort & de = *static_cast(it->get()); + + max = getMax(de); + if (max < 255) *it = copy(de); + + break; + } + case osg::PrimitiveSet::DrawElementsUIntIndirectPrimitiveType: + { + osg::DrawElementsIndirectUInt & de = *static_cast(it->get()); + + max = getMax(de); + if (max < 256) *it = copy(de); + else if (max < 65536) *it = copy(de); + + break; + } + case osg::PrimitiveSet::MultiDrawElementsUShortIndirectPrimitiveType: + { + osg::MultiDrawElementsIndirectUShort & de = *static_cast(it->get()); + + max = getMax(de); + if (max < 255) *it = copy(de); + + break; + } + case osg::PrimitiveSet::MultiDrawElementsUIntIndirectPrimitiveType: + { + osg::MultiDrawElementsIndirectUInt & de = *static_cast(it->get()); + + max = getMax(de); + if (max < 256) *it = copy(de); + else if (max < 65536) *it = copy(de); + + break; + } default: break; } } diff --git a/src/osgWrappers/serializers/osg/PrimitiveSetIndirect.cpp b/src/osgWrappers/serializers/osg/PrimitiveSetIndirect.cpp new file mode 100644 index 000000000..867f57162 --- /dev/null +++ b/src/osgWrappers/serializers/osg/PrimitiveSetIndirect.cpp @@ -0,0 +1,188 @@ +#include +#include +#include +#include +#include + +namespace DACommandsArrays { +REGISTER_OBJECT_WRAPPER( IndirectCommandDrawArrays, + 0, + osg::IndirectCommandDrawArrays, + "osg::Object osg::BufferData osg::IndirectCommandDrawArrays" ) +{ + { + UPDATE_TO_VERSION_SCOPED( 147 ) + ADDED_ASSOCIATE("osg::BufferData") + } +} +} +namespace DECommandsArrays { +REGISTER_OBJECT_WRAPPER( IndirectCommandDrawElements, + 0, + osg::IndirectCommandDrawElements, + "osg::Object osg::BufferData osg::IndirectCommandDrawElements" ) +{ + { + UPDATE_TO_VERSION_SCOPED( 147 ) + ADDED_ASSOCIATE("osg::BufferData") + } +} +} +namespace DefaultDACommandsArrays { + + +static bool checkDACommands( const osg::DefaultIndirectCommandDrawArrays& node ) +{ + return node.size()>0; +} + +static bool readDACommands( osgDB::InputStream& is, osg::DefaultIndirectCommandDrawArrays& node ) +{ + unsigned int elmt, size = 0; is >> size >> is.BEGIN_BRACKET; + node.resize(size); + for ( unsigned int i=0; i>elmt; node.count(i) = elmt; + is >>elmt; node.instanceCount(i) = elmt; + is >>elmt; node.first(i) = elmt; + is >>elmt; node.baseInstance(i) = elmt; + } + is >> is.END_BRACKET; + return true; +} + +static bool writeDACommands( osgDB::OutputStream& os, const osg::DefaultIndirectCommandDrawArrays& node ) +{ + unsigned int size = node.getNumElements(); + osg::DefaultIndirectCommandDrawArrays& nonconstnode =const_cast(node); + os << size << os.BEGIN_BRACKET << std::endl; + for ( unsigned int i=0; i0; +} + +static bool readDECommands( osgDB::InputStream& is, osg::DefaultIndirectCommandDrawElements& node ) +{ + unsigned int elmt, size = 0; is >> size >> is.BEGIN_BRACKET; + node.resize(size); + for ( unsigned int i=0; i>elmt; node.count(i) = elmt; + is >>elmt; node.instanceCount(i) = elmt; + is >>elmt; node.firstIndex(i) = elmt; + is >>elmt; node.baseVertex(i) = elmt; + is >>elmt; node.baseInstance(i) = elmt; + } + is >> is.END_BRACKET; + return true; +} + +static bool writeDECommands( osgDB::OutputStream& os, const osg::DefaultIndirectCommandDrawElements& node ) +{ + unsigned int size = node.getNumElements(); + osg::DefaultIndirectCommandDrawElements& nonconstnode =const_cast(node); + os << size << os.BEGIN_BRACKET << std::endl; + for ( unsigned int i=0; i