Skip to content

Commit

Permalink
Modify the GLObjectPool to defer GL object deletion by a frame in ord…
Browse files Browse the repository at this point in the history
…er to ensure that objects don't get deleted before their final use in the rendering thread
  • Loading branch information
gwaldron committed Jan 5, 2024
1 parent 379c985 commit fdf7210
Show file tree
Hide file tree
Showing 7 changed files with 49 additions and 28 deletions.
9 changes: 6 additions & 3 deletions src/osgEarth/GLUtils
Original file line number Diff line number Diff line change
Expand Up @@ -563,12 +563,14 @@ namespace osgEarth

/**
* Mechanism that will automatically delete a GL object
* when its container goes out of scope
* when its container goes out of scope. The object pool uses
* a deferred deletion policy (of one frame) to ensure an object
* is not deleted before the GL pipeline has finished using it.
*/
class OSGEARTH_EXPORT GLObjectPool : public osg::GraphicsObjectManager
{
public:
using Collection = std::vector< GLObject::Ptr >;
using Collection = std::vector<GLObject::Ptr>;

//! construct an object pool under the given graphics context ID
GLObjectPool(unsigned contextID);
Expand Down Expand Up @@ -627,7 +629,8 @@ namespace osgEarth
protected:

mutable Mutex _mutex;
Collection _objects;
Collection _objects; // objects being monitored
Collection _orphans; // objects whose refcount has dropped to 1
GLsizeiptr _totalBytes;
unsigned _hits;
unsigned _misses;
Expand Down
35 changes: 24 additions & 11 deletions src/osgEarth/GLUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -726,30 +726,43 @@ GLObjectPool::releaseOrphans(const osg::GraphicsContext* gc)
{
ScopedMutexLock lock(_mutex);

GLsizeiptr bytes = 0;
unsigned maxNumToRelease = std::max(1u, (unsigned)pow(4.0f, _avarice));
unsigned numReleased = 0u;

for (unsigned int i = 0; i < _objects.size();)
// first go thru and release some orphans.
Collection orphans_to_keep;
for (unsigned i = 0; i < _orphans.size() && numReleased < maxNumToRelease; ++i)
{
GLObject::Ptr& object = _objects[i];

if (object->gc() == gc && object.use_count() == 1 && numReleased < maxNumToRelease)
GLObject::Ptr& object = _orphans[i];
if (object->gc() == gc)
{
// Release the object
object->release();
++numReleased;
// Move the object at the end of the vector into this slot, making sure not to increment i as we want this object processed next.
_objects[i] = std::move(_objects.back());
// Reduce the size of the vector by 1.
_objects.resize(_objects.size() - 1);
}
else
{
orphans_to_keep.push_back(object);
}
}
_orphans.swap(orphans_to_keep);

// then check for objects to add to the orphan list:
GLsizeiptr bytes = 0;
Collection objects_to_keep;
objects_to_keep.reserve(_objects.size());
for(auto& object : _objects)
{
if (object->gc() == gc && object.use_count() == 1)
{
_orphans.push_back(object);
}
else
{
objects_to_keep.push_back(object);
bytes += object->size();
++i;
}
}
_objects.swap(objects_to_keep);
_totalBytes = bytes;
}

Expand Down
2 changes: 1 addition & 1 deletion src/osgEarth/TextureArena
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ namespace osgEarth
mutable osg::buffered_object<GLObjects> _globjects;

mutable TextureVector _textures;
mutable std::unordered_map<Texture::Ptr, unsigned int> _textureIndices;
mutable std::unordered_map<Texture*, unsigned> _textureIndices;
mutable std::unordered_set<unsigned> _dynamicTextures;

bool _autoRelease = false;
Expand Down
13 changes: 6 additions & 7 deletions src/osgEarth/TextureArena.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -568,7 +568,7 @@ TextureArena::find_no_lock(Texture::Ptr tex) const
if (tex == nullptr)
return -1;

auto itr = _textureIndices.find(tex);
auto itr = _textureIndices.find(tex.get());
if (itr != _textureIndices.end())
{
return itr->second;
Expand Down Expand Up @@ -690,7 +690,7 @@ TextureArena::add(Texture::Ptr tex, const osgDB::Options* readOptions)
int index = -1;

// find an open slot if one is available:
if (_autoRelease == true)
//if (_autoRelease == true)
{
for (int i = 0; i < _textures.size(); ++i)
{
Expand Down Expand Up @@ -720,7 +720,7 @@ TextureArena::add(Texture::Ptr tex, const osgDB::Options* readOptions)
else
_textures.push_back(tex);

_textureIndices[tex] = index;
_textureIndices[tex.get()] = index;

if (tex->osgTexture()->getDataVariance() == osg::Object::DYNAMIC)
{
Expand All @@ -737,12 +737,11 @@ TextureArena::purgeTextureIfOrphaned_no_lock(unsigned index)

Texture::Ptr& tex = _textures[index];

// Check for use_count() == 2.
// 1 for the _textures vector and 1 for the _textureIndices map.
if (tex && tex.use_count() == 2)
// Check for use_count() == 1, meaning that the only reference to this
if (tex && tex.use_count() == 1)
{
// Remove this texture from the texture indices map
_textureIndices.erase(tex);
_textureIndices.erase(tex.get());

// Remove this texture from the collection of dynamic textures
_dynamicTextures.erase(index);
Expand Down
10 changes: 5 additions & 5 deletions src/osgEarthDrivers/engine_rex/LayerDrawable
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ namespace osgEarth { namespace REX
bool supports(const osg::PrimitiveIndexFunctor&) const override { return true; }
void accept(osg::PrimitiveIndexFunctor&) const override;

virtual void accept(osg::NodeVisitor& nv) override {
void accept(osg::NodeVisitor& nv) override {
osg::Drawable::accept(nv);
}

Expand Down Expand Up @@ -143,10 +143,10 @@ namespace osgEarth { namespace REX

public: // osg::Drawable

virtual void drawImplementation(osg::RenderInfo& ri) const override;
virtual void releaseGLObjects(osg::State*) const override;
virtual void resizeGLObjectBuffers(unsigned size) override;
virtual void accept(osg::NodeVisitor& nv) override;
void drawImplementation(osg::RenderInfo& ri) const override;
void releaseGLObjects(osg::State*) const override;
void resizeGLObjectBuffers(unsigned size) override;
void accept(osg::NodeVisitor& nv) override;

protected:

Expand Down
6 changes: 5 additions & 1 deletion src/osgEarthDrivers/engine_rex/LayerDrawable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,10 @@ LayerDrawableNVGL::LayerDrawableNVGL() :
LayerDrawable()
{
setName("LayerDrawableNVGL");

// Make sure our structures are aligned to 16 bytes
OE_HARD_ASSERT(sizeof(GL4GlobalData) % 16 == 0);
OE_HARD_ASSERT(sizeof(GL4Tile) % 16 == 0);
}
LayerDrawableNVGL::~LayerDrawableNVGL()
{
Expand Down Expand Up @@ -503,7 +507,7 @@ LayerDrawableNVGL::drawImplementation(osg::RenderInfo& ri) const
GLenum element_type =
sizeof(DrawElementsBase::value_type) == sizeof(short) ?
GL_UNSIGNED_SHORT : GL_UNSIGNED_INT;

gl.glMultiDrawElementsIndirectBindlessNV(
primitive_type,
element_type,
Expand Down
2 changes: 2 additions & 0 deletions src/osgEarthDrivers/engine_rex/RexTerrainEngineNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1027,10 +1027,12 @@ RexTerrainEngineNode::update_traverse(osg::NodeVisitor& nv)
}
_persistent.unlock();

#if 1
// traverse the texture arena since it's not in the scene graph.
auto* arena = getEngineContext()->textures();
if (arena)
arena->update(nv);
#endif
}

void
Expand Down

0 comments on commit fdf7210

Please sign in to comment.