From 9f13e2fcb95ad8bbe11be243ce33114567b0d877 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Thu, 27 Jun 2013 16:44:32 +0000 Subject: [PATCH] From Lionel Lagarde, "Support for paging and shared PBO" "The attached file contains: - a per-context read counter in GLBufferObject::BufferEntry - a global client counter in BufferData - the glue between Texture* and Image client counter " --- include/osg/BufferObject | 25 ++++++++++++++++++++--- src/osg/BufferObject.cpp | 32 ++++++++++++++++++++++++++--- src/osg/Texture.cpp | 8 ++++++-- src/osg/Texture1D.cpp | 25 ++++++++++++++++------- src/osg/Texture2D.cpp | 25 ++++++++++++++++------- src/osg/Texture2DArray.cpp | 18 +++++++++++++++-- src/osg/Texture3D.cpp | 27 +++++++++++++++++-------- src/osg/TextureBuffer.cpp | 14 +++++++++++-- src/osg/TextureCubeMap.cpp | 39 ++++++++++++++++++++---------------- src/osg/TextureRectangle.cpp | 25 ++++++++++++++++------- 10 files changed, 180 insertions(+), 58 deletions(-) diff --git a/include/osg/BufferObject b/include/osg/BufferObject index f5c98cbae..ae00000a0 100644 --- a/include/osg/BufferObject +++ b/include/osg/BufferObject @@ -194,9 +194,10 @@ class OSG_EXPORT GLBufferObject : public Referenced struct BufferEntry { - BufferEntry(): modifiedCount(0),dataSize(0),offset(0),dataSource(0) {} + BufferEntry(): numRead(0), modifiedCount(0),dataSize(0),offset(0),dataSource(0) {} BufferEntry(const BufferEntry& rhs): + numRead(rhs.numRead), modifiedCount(rhs.modifiedCount), dataSize(rhs.dataSize), offset(rhs.offset), @@ -205,6 +206,7 @@ class OSG_EXPORT GLBufferObject : public Referenced BufferEntry& operator = (const BufferEntry& rhs) { if (&rhs==this) return *this; + numRead = rhs.numRead; modifiedCount = rhs.modifiedCount; dataSize = rhs.dataSize; offset = rhs.offset; @@ -212,6 +214,9 @@ class OSG_EXPORT GLBufferObject : public Referenced return *this; } + unsigned int getNumClients() const; + + unsigned int numRead; unsigned int modifiedCount; unsigned int dataSize; unsigned int offset; @@ -339,6 +344,10 @@ class OSG_EXPORT GLBufferObject : public Referenced * but need to ensure that they all use the same low common denominator extensions.*/ static void setExtensions(unsigned int contextID,Extensions* extensions); + bool hasAllBufferDataBeenRead() const; + + void setBufferDataHasBeenRead(const osg::BufferData* bd); + protected: virtual ~GLBufferObject(); @@ -610,14 +619,16 @@ class OSG_EXPORT BufferData : public Object BufferData(): Object(true), _modifiedCount(0), - _bufferIndex(0) {} + _bufferIndex(0), + _numClients(0) {} /** Copy constructor using CopyOp to manage deep vs shallow copy.*/ BufferData(const BufferData& bd,const CopyOp& copyop=CopyOp::SHALLOW_COPY): osg::Object(bd,copyop), _modifiedCount(0), _bufferIndex(0), - _modifiedCallback(bd._modifiedCallback) {} + _modifiedCallback(bd._modifiedCallback), + _numClients(0) {} virtual bool isSameKindAs(const Object* obj) const { return dynamic_cast(obj)!=NULL; } virtual const char* libraryName() const { return "osg"; } @@ -683,6 +694,12 @@ class OSG_EXPORT BufferData : public Object * for all graphics contexts. */ void releaseGLObjects(State* state=0) const; + unsigned int getNumClients() const { return _numClients; } + + void addClient(osg::Object *client) { ++_numClients; } + + void removeClient(osg::Object *client) { --_numClients; } + protected: virtual ~BufferData(); @@ -692,6 +709,8 @@ protected: unsigned int _bufferIndex; osg::ref_ptr _bufferObject; osg::ref_ptr _modifiedCallback; + + unsigned int _numClients; }; diff --git a/src/osg/BufferObject.cpp b/src/osg/BufferObject.cpp index 2ef8d2c3e..33112525f 100644 --- a/src/osg/BufferObject.cpp +++ b/src/osg/BufferObject.cpp @@ -36,6 +36,15 @@ using namespace osg; +////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// GLBufferObject::BufferEntry +// +unsigned int GLBufferObject::BufferEntry::getNumClients() const +{ + return dataSource->getNumClients(); +} + ////////////////////////////////////////////////////////////////////////////////////////////////////// // // GLBufferObject @@ -129,9 +138,9 @@ void GLBufferObject::compileBuffer() // OSG_NOTICE<<"GLBufferObject::compileBuffer(..) updating BufferEntry"<getTotalDataSize(); entry.dataSource = bd; @@ -203,6 +212,7 @@ void GLBufferObject::compileBuffer() if (entry.dataSource && (compileAll || entry.modifiedCount != entry.dataSource->getModifiedCount())) { // OSG_NOTICE<<"GLBufferObject::compileBuffer(..) downloading BufferEntry "<<&entry<getModifiedCount(); const osg::Image* image = entry.dataSource->asImage(); @@ -220,7 +230,6 @@ void GLBufferObject::compileBuffer() { _extensions->glBufferSubData(_profile._target, (GLintptrARB)entry.offset, (GLsizeiptrARB)entry.dataSize, entry.dataSource->getDataPointer()); } - } } } @@ -238,6 +247,23 @@ void GLBufferObject::deleteGLObject() } } +bool GLBufferObject::hasAllBufferDataBeenRead() const +{ + for (BufferEntries::const_iterator it=_bufferEntries.begin(); it!=_bufferEntries.end(); ++it) + { + if (it->numRead < it->getNumClients()) + return false; + } + + return true; +} + +void GLBufferObject::setBufferDataHasBeenRead(const osg::BufferData* bd) +{ + BufferEntry &entry = _bufferEntries[bd->getBufferIndex()]; + ++entry.numRead; +} + ////////////////////////////////////////////////////////////////////////////// // // Extension support diff --git a/src/osg/Texture.cpp b/src/osg/Texture.cpp index 0a31700e4..e2d2de9d9 100644 --- a/src/osg/Texture.cpp +++ b/src/osg/Texture.cpp @@ -2089,8 +2089,12 @@ void Texture::applyTexImage2D_load(State& state, GLenum target, const Image* ima const BufferObject* bo = image->getBufferObject(); if (bo->getCopyDataAndReleaseGLBufferObject()) { - //OSG_NOTICE<<"Release PBO"<releaseGLObjects(&state); + pbo->setBufferDataHasBeenRead(image); + if (pbo->hasAllBufferDataBeenRead()) + { + //OSG_NOTICE<<"Release PBO"<releaseGLObjects(&state); + } } } diff --git a/src/osg/Texture1D.cpp b/src/osg/Texture1D.cpp index 4cf39bfb1..798088ab8 100644 --- a/src/osg/Texture1D.cpp +++ b/src/osg/Texture1D.cpp @@ -34,15 +34,16 @@ Texture1D::Texture1D(osg::Image* image): Texture1D::Texture1D(const Texture1D& text,const CopyOp& copyop): Texture(text,copyop), - _image(copyop(text._image.get())), _textureWidth(text._textureWidth), _numMipmapLevels(text._numMipmapLevels), _subloadCallback(text._subloadCallback) { + setImage(copyop(text._image.get())); } Texture1D::~Texture1D() { + setImage(NULL); } int Texture1D::compare(const StateAttribute& sa) const @@ -96,10 +97,15 @@ void Texture1D::setImage(Image* image) { if (_image == image) return; - if (_image.valid() && _image->requiresUpdateCall()) + if (_image.valid()) { - setUpdateCallback(0); - setDataVariance(osg::Object::STATIC); + _image->removeClient(this); + + if (_image->requiresUpdateCall()) + { + setUpdateCallback(0); + setDataVariance(osg::Object::STATIC); + } } // delete old texture objects. @@ -108,10 +114,15 @@ void Texture1D::setImage(Image* image) _image = image; _modifiedCount.setAllElementsTo(0); - if (_image.valid() && _image->requiresUpdateCall()) + if (_image.valid()) { - setUpdateCallback(new Image::UpdateCallback()); - setDataVariance(osg::Object::DYNAMIC); + _image->addClient(this); + + if (_image->requiresUpdateCall()) + { + setUpdateCallback(new Image::UpdateCallback()); + setDataVariance(osg::Object::DYNAMIC); + } } } diff --git a/src/osg/Texture2D.cpp b/src/osg/Texture2D.cpp index 9964dcc54..3984064ee 100644 --- a/src/osg/Texture2D.cpp +++ b/src/osg/Texture2D.cpp @@ -37,16 +37,17 @@ Texture2D::Texture2D(Image* image): Texture2D::Texture2D(const Texture2D& text,const CopyOp& copyop): Texture(text,copyop), - _image(copyop(text._image.get())), _textureWidth(text._textureWidth), _textureHeight(text._textureHeight), _numMipmapLevels(text._numMipmapLevels), _subloadCallback(text._subloadCallback) { + setImage(copyop(text._image.get())); } Texture2D::~Texture2D() { + setImage(NULL); } int Texture2D::compare(const StateAttribute& sa) const @@ -109,19 +110,29 @@ void Texture2D::setImage(Image* image) { if (_image == image) return; - if (_image.valid() && _image->requiresUpdateCall()) + if (_image.valid()) { - setUpdateCallback(0); - setDataVariance(osg::Object::STATIC); + _image->removeClient(this); + + if (_image->requiresUpdateCall()) + { + setUpdateCallback(0); + setDataVariance(osg::Object::STATIC); + } } _image = image; _modifiedCount.setAllElementsTo(0); - if (_image.valid() && _image->requiresUpdateCall()) + if (_image.valid()) { - setUpdateCallback(new Image::UpdateCallback()); - setDataVariance(osg::Object::DYNAMIC); + _image->addClient(this); + + if (_image->requiresUpdateCall()) + { + setUpdateCallback(new Image::UpdateCallback()); + setDataVariance(osg::Object::DYNAMIC); + } } } diff --git a/src/osg/Texture2DArray.cpp b/src/osg/Texture2DArray.cpp index 53593f241..ac388b855 100644 --- a/src/osg/Texture2DArray.cpp +++ b/src/osg/Texture2DArray.cpp @@ -39,13 +39,17 @@ Texture2DArray::Texture2DArray(const Texture2DArray& text,const CopyOp& copyop): // copy all images by iterating through all of them for (int i=0; i < text._textureDepth; i++) { - _images.push_back(copyop(text._images[i].get())); + setImage(i, copyop(text._images[i].get())); _modifiedCount.push_back(ImageModifiedCount()); } } Texture2DArray::~Texture2DArray() { + for (int i=0; i<_textureDepth; ++i) + { + setImage(i, NULL); + } } int Texture2DArray::compare(const StateAttribute& sa) const @@ -118,9 +122,19 @@ void Texture2DArray::setImage(unsigned int layer, Image* image) if (_images[i].valid() && _images[i]->requiresUpdateCall()) ++numImageRequireUpdateBefore; } + if (_images[layer].valid()) + { + _images[layer]->removeClient(this); + } + // set image _images[layer] = image; - _modifiedCount[layer].setAllElementsTo(0); + _modifiedCount[layer].setAllElementsTo(0); + + if (_images[layer].valid()) + { + _images[layer]->addClient(this); + } // find out if we need to reset the update callback to handle the animation of image unsigned numImageRequireUpdateAfter = 0; diff --git a/src/osg/Texture3D.cpp b/src/osg/Texture3D.cpp index adb29c61f..dee678c7b 100644 --- a/src/osg/Texture3D.cpp +++ b/src/osg/Texture3D.cpp @@ -42,17 +42,18 @@ Texture3D::Texture3D(Image* image): Texture3D::Texture3D(const Texture3D& text,const CopyOp& copyop): Texture(text,copyop), - _image(copyop(text._image.get())), _textureWidth(text._textureWidth), _textureHeight(text._textureHeight), _textureDepth(text._textureDepth), _numMipmapLevels(text._numMipmapLevels), _subloadCallback(text._subloadCallback) { + setImage(copyop(text._image.get())); } Texture3D::~Texture3D() -{ +{ + setImage(NULL); } int Texture3D::compare(const StateAttribute& sa) const @@ -108,10 +109,15 @@ void Texture3D::setImage(Image* image) { if (_image == image) return; - if (_image.valid() && _image->requiresUpdateCall()) + if (_image.valid()) { - setUpdateCallback(0); - setDataVariance(osg::Object::STATIC); + _image->removeClient(this); + + if (_image->requiresUpdateCall()) + { + setUpdateCallback(0); + setDataVariance(osg::Object::STATIC); + } } // delete old texture objects. @@ -121,10 +127,15 @@ void Texture3D::setImage(Image* image) _image = image; - if (_image.valid() && _image->requiresUpdateCall()) + if (_image.valid()) { - setUpdateCallback(new Image::UpdateCallback()); - setDataVariance(osg::Object::DYNAMIC); + _image->addClient(this); + + if (_image->requiresUpdateCall()) + { + setUpdateCallback(new Image::UpdateCallback()); + setDataVariance(osg::Object::DYNAMIC); + } } } diff --git a/src/osg/TextureBuffer.cpp b/src/osg/TextureBuffer.cpp index 6af11bd19..7977c6b1b 100644 --- a/src/osg/TextureBuffer.cpp +++ b/src/osg/TextureBuffer.cpp @@ -28,14 +28,15 @@ TextureBuffer::TextureBuffer(osg::Image* image): TextureBuffer::TextureBuffer(const TextureBuffer& text,const CopyOp& copyop): Texture(text,copyop), - _image(copyop(text._image.get())), _textureWidth(text._textureWidth), _usageHint(text._usageHint) { + setImage(copyop(text._image.get())); } TextureBuffer::~TextureBuffer() { + setImage(NULL); } int TextureBuffer::compare(const StateAttribute& sa) const @@ -84,10 +85,19 @@ void TextureBuffer::setImage(Image* image) { if (_image == image) return; + if (_image.valid()) + { + _image->removeClient(this); + } + _image = image; _modifiedCount.setAllElementsTo(0); -} + if (_image.valid()) + { + _image->addClient(this); + } +} void TextureBuffer::apply(State& state) const { diff --git a/src/osg/TextureCubeMap.cpp b/src/osg/TextureCubeMap.cpp index 5ab37343d..4ae4c96c0 100644 --- a/src/osg/TextureCubeMap.cpp +++ b/src/osg/TextureCubeMap.cpp @@ -48,28 +48,24 @@ TextureCubeMap::TextureCubeMap(const TextureCubeMap& text,const CopyOp& copyop): _numMipmapLevels(text._numMipmapLevels), _subloadCallback(text._subloadCallback) { - _images[0] = copyop(text._images[0].get()); - _images[1] = copyop(text._images[1].get()); - _images[2] = copyop(text._images[2].get()); - _images[3] = copyop(text._images[3].get()); - _images[4] = copyop(text._images[4].get()); - _images[5] = copyop(text._images[5].get()); - - _modifiedCount[0].setAllElementsTo(0); - _modifiedCount[1].setAllElementsTo(0); - _modifiedCount[2].setAllElementsTo(0); - _modifiedCount[3].setAllElementsTo(0); - _modifiedCount[4].setAllElementsTo(0); - _modifiedCount[5].setAllElementsTo(0); - + setImage(0, copyop(text._images[0].get())); + setImage(1, copyop(text._images[1].get())); + setImage(2, copyop(text._images[2].get())); + setImage(3, copyop(text._images[3].get())); + setImage(4, copyop(text._images[4].get())); + setImage(5, copyop(text._images[5].get())); } - TextureCubeMap::~TextureCubeMap() { + setImage(0, NULL); + setImage(1, NULL); + setImage(2, NULL); + setImage(3, NULL); + setImage(4, NULL); + setImage(5, NULL); } - int TextureCubeMap::compare(const StateAttribute& sa) const { // check the types are equal and then create the rhs variable @@ -126,7 +122,7 @@ int TextureCubeMap::compare(const StateAttribute& sa) const } -void TextureCubeMap::setImage( unsigned int face, Image* image) +void TextureCubeMap::setImage(unsigned int face, Image* image) { if (_images[face] == image) return; @@ -136,9 +132,18 @@ void TextureCubeMap::setImage( unsigned int face, Image* image) if (_images[i].valid() && _images[i]->requiresUpdateCall()) ++numImageRequireUpdateBefore; } + if (_images[face].valid()) + { + _images[face]->removeClient(this); + } + _images[face] = image; _modifiedCount[face].setAllElementsTo(0); + if (_images[face].valid()) + { + _images[face]->addClient(this); + } // find out if we need to reset the update callback to handle the animation of image unsigned numImageRequireUpdateAfter = 0; diff --git a/src/osg/TextureRectangle.cpp b/src/osg/TextureRectangle.cpp index c3c1627b9..43e87777c 100644 --- a/src/osg/TextureRectangle.cpp +++ b/src/osg/TextureRectangle.cpp @@ -62,15 +62,16 @@ TextureRectangle::TextureRectangle(Image* image): TextureRectangle::TextureRectangle(const TextureRectangle& text,const CopyOp& copyop): Texture(text,copyop), - _image(copyop(text._image.get())), _textureWidth(text._textureWidth), _textureHeight(text._textureHeight), _subloadCallback(text._subloadCallback) { + setImage(copyop(text._image.get())); } TextureRectangle::~TextureRectangle() { + setImage(NULL); } int TextureRectangle::compare(const StateAttribute& sa) const @@ -125,10 +126,15 @@ void TextureRectangle::setImage(Image* image) { if (_image == image) return; - if (_image.valid() && _image->requiresUpdateCall()) + if (_image.valid()) { - setUpdateCallback(0); - setDataVariance(osg::Object::STATIC); + _image->removeClient(this); + + if (_image->requiresUpdateCall()) + { + setUpdateCallback(0); + setDataVariance(osg::Object::STATIC); + } } // delete old texture objects. @@ -136,10 +142,15 @@ void TextureRectangle::setImage(Image* image) _image = image; - if (_image.valid() && _image->requiresUpdateCall()) + if (_image.valid()) { - setUpdateCallback(new Image::UpdateCallback()); - setDataVariance(osg::Object::DYNAMIC); + _image->addClient(this); + + if (_image->requiresUpdateCall()) + { + setUpdateCallback(new Image::UpdateCallback()); + setDataVariance(osg::Object::DYNAMIC); + } } }