From ac61535d2ca65e3ddfba3954da472e63e69bac49 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 19 Jan 2017 03:17:49 +0100 Subject: [PATCH] optimize OSGVertexBuffer by double buffering the vertex array instead of recreating it on every modification --- .../myguiplatform/myguirendermanager.cpp | 95 +++++++++---------- 1 file changed, 47 insertions(+), 48 deletions(-) diff --git a/components/myguiplatform/myguirendermanager.cpp b/components/myguiplatform/myguirendermanager.cpp index 9d1f7100f..5ab7ab736 100644 --- a/components/myguiplatform/myguirendermanager.cpp +++ b/components/myguiplatform/myguirendermanager.cpp @@ -210,7 +210,7 @@ public: osg::ref_ptr mVertexBuffer; // need to hold on to this too as the mVertexBuffer does not hold a ref to its own array - osg::ref_ptr mArray; + osg::ref_ptr mArray; // optional osg::ref_ptr mStateSet; @@ -244,21 +244,25 @@ private: class OSGVertexBuffer : public MyGUI::IVertexBuffer { - osg::ref_ptr mBuffer; - osg::ref_ptr mVertexArray; + osg::ref_ptr mBuffer[2]; + osg::ref_ptr mVertexArray[2]; size_t mNeedVertexCount; - bool mQueuedForDrawing; + unsigned int mCurrentBuffer; + bool mUsed; // has the mCurrentBuffer been submitted to the rendering thread void destroy(); - void create(); + osg::UByteArray* create(); public: OSGVertexBuffer(); - virtual ~OSGVertexBuffer(); + virtual ~OSGVertexBuffer() {} - void markAsQueuedForDrawing(); + void markUsed(); + + osg::Array* getVertexArray(); + osg::VertexBufferObject* getVertexBuffer(); virtual void setVertexCount(size_t count); virtual size_t getVertexCount(); @@ -266,26 +270,18 @@ public: virtual MyGUI::Vertex *lock(); virtual void unlock(); -/*internal:*/ - - osg::VertexBufferObject *getBuffer() const { return mBuffer.get(); } - osg::UByteArray *getArray() const { return mVertexArray.get(); } }; OSGVertexBuffer::OSGVertexBuffer() : mNeedVertexCount(0) - , mQueuedForDrawing(false) -{ -} - -OSGVertexBuffer::~OSGVertexBuffer() + , mCurrentBuffer(0) + , mUsed(false) { - destroy(); } -void OSGVertexBuffer::markAsQueuedForDrawing() +void OSGVertexBuffer::markUsed() { - mQueuedForDrawing = true; + mUsed = true; } void OSGVertexBuffer::setVertexCount(size_t count) @@ -303,48 +299,51 @@ size_t OSGVertexBuffer::getVertexCount() MyGUI::Vertex *OSGVertexBuffer::lock() { - if (mQueuedForDrawing || !mVertexArray) + if (mUsed) { - // Force recreating the buffer, to make sure we are not modifying a buffer currently - // queued for rendering in the last frame's draw thread. - // a more efficient solution might be double buffering - destroy(); - create(); - mQueuedForDrawing = false; + mCurrentBuffer = (mCurrentBuffer+1)%2; + mUsed = false; } - else + osg::UByteArray* array = mVertexArray[mCurrentBuffer]; + if (!array) { - mVertexArray->resize(mNeedVertexCount * sizeof(MyGUI::Vertex)); + array = create(); + } + else if (array->size() != mNeedVertexCount * sizeof(MyGUI::Vertex)) + { + array->resize(mNeedVertexCount * sizeof(MyGUI::Vertex)); } - MYGUI_PLATFORM_ASSERT(mBuffer.valid(), "Vertex buffer is not created"); - - return (MyGUI::Vertex*)&(*mVertexArray)[0]; + return (MyGUI::Vertex*)&(*array)[0]; } void OSGVertexBuffer::unlock() { - mVertexArray->dirty(); - mBuffer->dirty(); + mVertexArray[mCurrentBuffer]->dirty(); + mBuffer[mCurrentBuffer]->dirty(); } -void OSGVertexBuffer::destroy() +osg::UByteArray* OSGVertexBuffer::create() { - mBuffer = nullptr; - mVertexArray = nullptr; + mVertexArray[mCurrentBuffer] = new osg::UByteArray(mNeedVertexCount*sizeof(MyGUI::Vertex)); + + mBuffer[mCurrentBuffer] = new osg::VertexBufferObject; + mBuffer[mCurrentBuffer]->setDataVariance(osg::Object::DYNAMIC); + mBuffer[mCurrentBuffer]->setUsage(GL_DYNAMIC_DRAW); + // NB mBuffer does not own the array + mBuffer[mCurrentBuffer]->setArray(0, mVertexArray[mCurrentBuffer].get()); + + return mVertexArray[mCurrentBuffer]; } -void OSGVertexBuffer::create() +osg::Array* OSGVertexBuffer::getVertexArray() { - MYGUI_PLATFORM_ASSERT(!mBuffer.valid(), "Vertex buffer already exist"); - - mVertexArray = new osg::UByteArray(mNeedVertexCount*sizeof(MyGUI::Vertex)); + return mVertexArray[mCurrentBuffer]; +} - mBuffer = new osg::VertexBufferObject; - mBuffer->setDataVariance(osg::Object::DYNAMIC); - mBuffer->setUsage(GL_DYNAMIC_DRAW); - // NB mBuffer does not own the array - mBuffer->setArray(0, mVertexArray.get()); +osg::VertexBufferObject* OSGVertexBuffer::getVertexBuffer() +{ + return mBuffer[mCurrentBuffer]; } // --------------------------------------------------------------------------- @@ -438,9 +437,9 @@ void RenderManager::doRender(MyGUI::IVertexBuffer *buffer, MyGUI::ITexture *text { Drawable::Batch batch; batch.mVertexCount = count; - batch.mVertexBuffer = static_cast(buffer)->getBuffer(); - static_cast(buffer)->markAsQueuedForDrawing(); - batch.mArray = static_cast(buffer)->getArray(); + batch.mVertexBuffer = static_cast(buffer)->getVertexBuffer(); + batch.mArray = static_cast(buffer)->getVertexArray(); + static_cast(buffer)->markUsed(); if (texture) { batch.mTexture = static_cast(texture)->getTexture();