/* OpenSceneGraph example, osganimate. * * 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. */ #include #include #include #include #include #include #include #include #include #include #include class MemoryTest : public osg::Referenced { public: }; class GLObject : public osg::Referenced { public: virtual void apply(osg::RenderInfo& renderInfo) = 0; }; class GLMemoryTest : public MemoryTest { public: virtual GLObject* allocate() = 0; }; ///////////////////////////////////////////////////////////////////////// // // Context test class ContextTest : public MemoryTest { public: ContextTest(int width, int height, bool pbuffer): _width(width), _height(height), _pbuffer(pbuffer) {} virtual osg::GraphicsContext* allocate() { osg::ref_ptr traits = new osg::GraphicsContext::Traits; traits->width = _width; traits->height = _height; traits->windowDecoration = true; traits->pbuffer = _pbuffer; osg::ref_ptr window = osg::GraphicsContext::createGraphicsContext(traits.get()); if (window.valid()) { if (window->realize()) { return window.release(); } else { if (_pbuffer) throw "Failed to realize PixelBuffer"; else throw "Failed to realize GraphicsWindow"; } } else { std::cerr<<"Error: Unable to create graphics context, problem with running osgViewer-"<apply(*renderInfo.getState()); if (renderInfo.getState()->checkGLErrors(_attribute.get())) { throw "OpenGL error"; } } osg::ref_ptr _attribute; }; ///////////////////////////////////////////////////////////////////////// // // Texture test class TextureTest : public GLMemoryTest { public: TextureTest(int width=256, int height=256, int depth=1): _width(width), _height(height), _depth(depth) {} virtual GLObject* allocate() { if (_depth>1) { osg::ref_ptr image = new osg::Image; image->allocateImage(_width, _height, _depth, GL_RGBA, GL_UNSIGNED_BYTE); osg::ref_ptr texture = new osg::Texture3D; texture->setImage(image.get()); texture->setResizeNonPowerOfTwoHint(false); return new StateAttributeObject(texture.get()); } if (_height>1) { osg::ref_ptr image = new osg::Image; image->allocateImage(_width, _height, 1, GL_RGBA, GL_UNSIGNED_BYTE); osg::ref_ptr texture = new osg::Texture2D; texture->setImage(image.get()); texture->setResizeNonPowerOfTwoHint(false); return new StateAttributeObject(texture.get()); } if (_width>1) { osg::ref_ptr image = new osg::Image; image->allocateImage(_width, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE); osg::ref_ptr texture = new osg::Texture1D; texture->setImage(image.get()); texture->setResizeNonPowerOfTwoHint(false); return new StateAttributeObject(texture.get()); } else { throw "Invalid texture size of 0,0,0"; } } protected: int _width; int _height; int _depth; }; ///////////////////////////////////////////////////////////////////////// // // FrameBufferObject test class FboTest : public GLMemoryTest { public: FboTest(int width=1024, int height=1024, int depth=2): _width(width), _height(height), _depth(depth) {} virtual GLObject* allocate() { osg::ref_ptr fbo = new osg::FrameBufferObject; if (_depth>=1) fbo->setAttachment(osg::Camera::COLOR_BUFFER, osg::FrameBufferAttachment(new osg::RenderBuffer(_width, _height, GL_RGBA))); if (_depth>=2) fbo->setAttachment(osg::Camera::DEPTH_BUFFER, osg::FrameBufferAttachment(new osg::RenderBuffer(_width, _height, GL_DEPTH_COMPONENT24))); return new StateAttributeObject(fbo.get()); } protected: int _width; int _height; int _depth; }; //////////////////////////////////////////////////////////////////////// // // Wrap Drawable class DrawableObject : public GLObject { public: DrawableObject(osg::Drawable* drawable): _drawable(drawable) {} void apply(osg::RenderInfo& renderInfo) { _drawable->draw(renderInfo); if (renderInfo.getState()->checkGLErrors("Drawable")) { throw "OpenGL error"; } } osg::ref_ptr _drawable; }; ///////////////////////////////////////////////////////////////////////// // // Geometry test class GeometryTest : public GLMemoryTest { public: enum GLObjectType { VERTEX_ARRAY, DISPLAY_LIST, VERTEX_BUFFER_OBJECT }; GeometryTest(GLObjectType type, int width=64, int height=64): _glObjectType(type), _width(width), _height(height) {} virtual GLObject* allocate() { unsigned int numVertices = _width * _height; osg::Vec3Array* vertices = new osg::Vec3Array(numVertices); for(int j=0; j<_height; ++j) { for(int i=0; i<_width; ++i) { (*vertices)[i+j*_width].set(float(i),float(j),0.0f); } } unsigned int numIndices = (_width-1) * (_height-1) * 4; osg::DrawElementsUShort* quads = new osg::DrawElementsUShort(GL_QUADS); quads->reserve(numIndices); for(int j=0; j<_height-1; ++j) { for(int i=0; i<_width-1; ++i) { quads->push_back(i + j*_width); quads->push_back(i+1 + j*_width); quads->push_back(i+1 + (j+1)*_width); quads->push_back(i + (j+1)*_width); } } osg::Geometry* geometry = new osg::Geometry; geometry->setVertexArray(vertices); geometry->addPrimitiveSet(quads); switch(_glObjectType) { case(VERTEX_ARRAY): geometry->setUseDisplayList(false); geometry->setUseVertexBufferObjects(false); break; case(DISPLAY_LIST): geometry->setUseDisplayList(true); geometry->setUseVertexBufferObjects(false); break; case(VERTEX_BUFFER_OBJECT): geometry->setUseDisplayList(false); geometry->setUseVertexBufferObjects(true); break; } return new DrawableObject(geometry); } protected: GLObjectType _glObjectType; int _width; int _height; }; int main( int argc, char **argv ) { osg::ArgumentParser arguments(&argc,argv); arguments.getApplicationUsage()->setApplicationName(arguments.getApplicationName()); arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" tests OpenGL and Windowing memory scalability.."); arguments.getApplicationUsage()->addCommandLineOption("-h or --help","List command line options."); arguments.getApplicationUsage()->addCommandLineOption("--pbuffer","Create a 512x512 pixel buffer."); arguments.getApplicationUsage()->addCommandLineOption("--pbuffer ","Create a pixel buffer of specified dimensions."); arguments.getApplicationUsage()->addCommandLineOption("--window","Create a 512x512 graphics window."); arguments.getApplicationUsage()->addCommandLineOption("--window ","Create a graphics window of specified dimensions."); arguments.getApplicationUsage()->addCommandLineOption("--delay ","Set a delay in microseconds before all OpenGL object operations."); arguments.getApplicationUsage()->addCommandLineOption("--texture ","Allocate a 3D texture of specified dimensions."); arguments.getApplicationUsage()->addCommandLineOption("--texture ","Allocate a 2D texture of specified dimensions."); arguments.getApplicationUsage()->addCommandLineOption("--texture ","Allocate a 1D texture of specified dimensions."); arguments.getApplicationUsage()->addCommandLineOption("--geometry ","Allocate a osg::Geometry representing a grid of specified size, using OpenGL Dislay Lists."); arguments.getApplicationUsage()->addCommandLineOption("--geometry-va ","Allocate a osg::Geometry representing a grid of specified size, using Vertex Arrays."); arguments.getApplicationUsage()->addCommandLineOption("--geometry-vbo ","Allocate a osg::Geometry representing a grid of specified size, using Vertex Buffer Objects."); arguments.getApplicationUsage()->addCommandLineOption("--fbo ","Allocate a FrameBufferObject of specified dimensions."); arguments.getApplicationUsage()->addCommandLineOption("-c ","Set the number of contexts to create of each type specified."); arguments.getApplicationUsage()->addCommandLineOption("-g ","Set the number of GL objects to create of each type specified."); if (arguments.read("-h") || arguments.read("--help")) { arguments.getApplicationUsage()->write(std::cout, osg::ApplicationUsage::COMMAND_LINE_OPTION); return 1; } if (arguments.argc()<=1) { arguments.getApplicationUsage()->write(std::cout,osg::ApplicationUsage::COMMAND_LINE_OPTION); return 1; } typedef std::list< osg::ref_ptr > GLMemoryTests; typedef std::list< osg::ref_ptr > ContextTests; ContextTests contextTests; GLMemoryTests glMemoryTests; int width, height, depth; while(arguments.read("--pbuffer",width,height)) { contextTests.push_back(new ContextTest(width, height, true)); } while(arguments.read("--pbuffer")) { contextTests.push_back(new ContextTest(512, 512, true)); } while(arguments.read("--window",width,height)) { contextTests.push_back(new ContextTest(width, height, false)); } while(arguments.read("--window")) { contextTests.push_back(new ContextTest(512,512, false)); } while(arguments.read("--texture",width,height,depth)) { glMemoryTests.push_back(new TextureTest(width,height,depth)); } while(arguments.read("--texture",width,height)) { glMemoryTests.push_back(new TextureTest(width,height,1)); } while(arguments.read("--texture",width)) { glMemoryTests.push_back(new TextureTest(width,1,1)); } while(arguments.read("--fbo",width,height,depth)) { glMemoryTests.push_back(new FboTest(width,height,depth)); } while(arguments.read("--fbo",width,height)) { glMemoryTests.push_back(new FboTest(width,height,2)); } while(arguments.read("--fbo")) { glMemoryTests.push_back(new FboTest(1024,1024,2)); } while(arguments.read("--geometry",width,height)) { glMemoryTests.push_back(new GeometryTest(GeometryTest::DISPLAY_LIST,width,height)); } while(arguments.read("--geometry")) { glMemoryTests.push_back(new GeometryTest(GeometryTest::DISPLAY_LIST,64,64)); } while(arguments.read("--geometry-vbo",width,height)) { glMemoryTests.push_back(new GeometryTest(GeometryTest::VERTEX_BUFFER_OBJECT,width,height)); } while(arguments.read("--geometry-vbo")) { glMemoryTests.push_back(new GeometryTest(GeometryTest::VERTEX_BUFFER_OBJECT,64,64)); } while(arguments.read("--geometry-va",width,height)) { glMemoryTests.push_back(new GeometryTest(GeometryTest::VERTEX_ARRAY,width,height)); } while(arguments.read("--geometry-va")) { glMemoryTests.push_back(new GeometryTest(GeometryTest::VERTEX_ARRAY,64,64)); } unsigned int sleepTime = 0; while(arguments.read("--delay",sleepTime)) {} int maxNumContextIterations = 1; while(arguments.read("-c",maxNumContextIterations)) {} int maxNumGLIterations = 1000; while(arguments.read("-g",maxNumGLIterations)) {} #if 0 // any option left unread are converted into errors to write out later. arguments.reportRemainingOptionsAsUnrecognized(); // report any errors if they have occurred when parsing the program arguments. if (arguments.errors()) { arguments.writeErrorMessages(std::cout); return 1; } #endif typedef std::list< osg::ref_ptr > Contexts; typedef std::list< osg::ref_ptr > GLObjects; Contexts allocatedContexts; GLObjects glObjects; if (contextTests.empty()) { if (glMemoryTests.empty()) { std::cout<<"No tests specified, please specify test using the command line options below."<write(std::cout,osg::ApplicationUsage::COMMAND_LINE_OPTION); return 1; } else { contextTests.push_back(new ContextTest(512,512, false)); } } osg::Timer_t startTick = osg::Timer::instance()->tick(); // use printf's below as C++'s ostream classes use more memory and are more likely to fail when everything // goes wrong with memory allocations. int numContextIterations = 0; int numGLObjectIterations = 0; int numGLObjectsApplied = 0; try { for(; numGLObjectIterations glObject = (*itr)->allocate(); if (glObject.valid()) glObjects.push_back(glObject.get()); } } for(;numContextIterations context = (*itr)->allocate(); if (context.valid()) { allocatedContexts.push_back(context); context->makeCurrent(); osg::RenderInfo renderInfo; renderInfo.setState(context->getState()); for(GLObjects::iterator gitr = glObjects.begin(); gitr != glObjects.end(); ++gitr) { if (sleepTime>0) OpenThreads::Thread::microSleep( sleepTime ); printf("%i ",numGLObjectsApplied);fflush(stdout); (*gitr)->apply(renderInfo); ++numGLObjectsApplied; } context->releaseContext(); printf("\n\n"); fflush(stdout); } } } } catch(const char* errorString) { printf("\nException caught, contexts completed = %i, gl objects successfully applied = %i, error = %s\n\n",numContextIterations, numGLObjectsApplied, errorString); return 1; } catch(...) { printf("\nException caught, contexts completed = %i, gl objects successfully applied = %i\n\n",numContextIterations, numGLObjectsApplied); return 1; } osg::Timer_t endTick = osg::Timer::instance()->tick(); printf("\nSuccessful completion, contexts created = %i, gl objects applied = %i\n",numContextIterations, numGLObjectsApplied); printf("Duration = %f seconds.\n\n",osg::Timer::instance()->delta_s(startTick, endTick)); return 0; }