Skip to content

Commit

Permalink
GLUtils: add GLBuffer::create_shared to prevent shared buffers from b…
Browse files Browse the repository at this point in the history
…eing released when a GC closes
  • Loading branch information
gwaldron committed Apr 3, 2024
1 parent ea4e757 commit b04b7ce
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 53 deletions.
37 changes: 2 additions & 35 deletions src/osgEarth/Chonk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -571,12 +571,12 @@ Chonk::getOrCreateCommands(osg::State& state) const

if (gs.vbo == nullptr || !gs.vbo->valid())
{
gs.vbo = GLBuffer::create(GL_ARRAY_BUFFER_ARB, state);
gs.vbo = GLBuffer::create_shared(GL_ARRAY_BUFFER_ARB, state);
gs.vbo->bind();
gs.vbo->debugLabel("Chonk geometry", "VBO " + _name);
gs.vbo->bufferStorage(_vbo_store.size() * sizeof(VertexGPU), _vbo_store.data(), IMMUTABLE);

gs.ebo = GLBuffer::create(GL_ELEMENT_ARRAY_BUFFER_ARB, state);
gs.ebo = GLBuffer::create_shared(GL_ELEMENT_ARRAY_BUFFER_ARB, state);
gs.ebo->bind();
gs.ebo->debugLabel("Chonk geometry", "EBO " + _name);
gs.ebo->bufferStorage(_ebo_store.size() * sizeof(element_t), _ebo_store.data(), IMMUTABLE);
Expand Down Expand Up @@ -1058,39 +1058,6 @@ ChonkDrawable::GLObjects::initialize(const osg::Object* host, osg::State& state)
void(GL_APIENTRY * gl_VertexAttribLFormat)(GLuint, GLint, GLenum, GLuint);
osg::setGLExtensionFuncPtr(gl_VertexAttribLFormat, "glVertexAttribLFormatNV");

#if 0
// DrawElementsCommand buffer:
_commandBuf = GLBuffer::create(GL_SHADER_STORAGE_BUFFER, state);
_commandBuf->bind();
_commandBuf->debugLabel("Chonk drawable", "commands " + host->getName());
_commandBuf->unbind();
_commandBuf->setBufferDataAllocMultiple(COMMAND_BUF_CHUNK_SIZE);

// Per-culling instances:
_instanceInputBuf = GLBuffer::create(GL_SHADER_STORAGE_BUFFER, state);
_instanceInputBuf->bind();
_instanceInputBuf->debugLabel("Chonk drawable", "input " +host->getName());
_instanceInputBuf->unbind();
_instanceInputBuf->setBufferDataAllocMultiple(INPUT_BUF_CHUNK_SIZE);

if (_gpucull)
{
// Culled instances (GPU only)
_instanceOutputBuf = GLBuffer::create(GL_SHADER_STORAGE_BUFFER, state);
_instanceOutputBuf->bind();
_instanceOutputBuf->debugLabel("Chonk drawable", "output " + host->getName());
_instanceOutputBuf->unbind();
_instanceOutputBuf->setBufferDataAllocMultiple(OUTPUT_BUF_CHUNK_SIZE);

// Chonk data
_chonkBuf = GLBuffer::create(GL_SHADER_STORAGE_BUFFER, state);
_chonkBuf->bind();
_chonkBuf->debugLabel("Chonk drawable", "chonkbuf " + host->getName());
_chonkBuf->unbind();
_instanceOutputBuf->setBufferDataAllocMultiple(CHONK_BUF_CHUNK_SIZE);
}
#endif

// Multidraw command:
osg::setGLExtensionFuncPtr(
_glMultiDrawElementsIndirectBindlessNV,
Expand Down
18 changes: 16 additions & 2 deletions src/osgEarth/GLUtils
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ namespace osgEarth
bool recyclable() const { return _recyclable; }

//! whether this object can be shared between shared GCs
bool shareable() const { return _shareable; }
bool shared() const { return _shared; }

//! number of times this object's been recycled
unsigned recycles() const { return _recycles; }
Expand Down Expand Up @@ -254,7 +254,7 @@ namespace osgEarth
std::string _uid; // debugging unique id (optional)
std::string _category; // debugging category (optional)
GLenum _ns = (GLenum)0; // object namespace
bool _shareable = false; // can this object be shared between GCs?
bool _shared = false; // is this object shared by all GCs?
bool _recyclable = false; // can this object by re-used?
unsigned _recycles = 0u; // number of times this object has been recycled
osg::GLExtensions* _ext = nullptr;
Expand Down Expand Up @@ -331,12 +331,23 @@ namespace osgEarth
//! Creates a new unallocated buffer.
static Ptr create(GLenum target, osg::State& state);

//! Creates a new unallocated buffer that can be shared across
//! all graphics contexts/states.
static Ptr create_shared(GLenum target, osg::State& state);

//! Creates a new unallocated buffer.
//! The "size hint" allows it to potentially be created from recycled
//! The "chunk size" is an alignment value to improve recycling efficiency
//! GPU memory.
static Ptr create(GLenum target, osg::State& state, GLsizei sizeHint, GLsizei chunkSize = 1);

//! Creates a new unallocated buffer that can be shared across
//! all graphics contexts/states.
//! The "size hint" allows it to potentially be created from recycled
//! The "chunk size" is an alignment value to improve recycling efficiency
//! GPU memory.
static Ptr create_shared(GLenum target, osg::State& state, GLsizei sizeHint, GLsizei chunkSize = 1);

//! Bind this buffer to target() in the active context.
void bind() const;

Expand Down Expand Up @@ -595,6 +606,9 @@ namespace osgEarth
//! by the state object
static GLObjectPool* get(osg::State& state);

//! Fetch the object pool for graphics objects shared across contexts/states
static GLObjectPool* get_shared();

//! Release all GL objects that were created in the given state's
//! graphics context
static void releaseGLObjects(osg::State* state);
Expand Down
44 changes: 33 additions & 11 deletions src/osgEarth/GLUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -668,7 +668,7 @@ GLObjectPool::releaseAll(const osg::GraphicsContext* gc)

for (auto& object : _objects)
{
if (object->gc() == gc || (gc == nullptr))
if (object->gc() == gc && object->shared() == false)
{
object->release();
}
Expand Down Expand Up @@ -704,17 +704,16 @@ GLObjectPool::releaseOrphans(const osg::GraphicsContext* gc)
continue;
}

// either the object is not in use, or it's been decommisioned and the GC set to null:
if (object.use_count() == 1)
// the object is not in use:
// timeslice (by limiting deallocations per frame), and
// delay deletion in the event of multithreaded draw
if (object.use_count() == 1 &&
bytes_remaining > 0 &&
object->_orphan_frames++ >= _frames_to_delay_deletion)
{
// timeslice (by limiting deallocations per frame), and
// delay deletion in the event of multithreaded draw
if (bytes_remaining > 0 && object->_orphan_frames++ >= _frames_to_delay_deletion)
{
object->release();
bytes_remaining -= object->size();
continue;
}
object->release();
bytes_remaining -= object->size();
continue;
}

bytes += object->size();
Expand Down Expand Up @@ -860,6 +859,14 @@ GLBuffer::create(GLenum target, osg::State& state)
return object;
}

GLBuffer::Ptr
GLBuffer::create_shared(GLenum target, osg::State& state)
{
auto ptr = create(target, state);
if (ptr) ptr->_shared = true;
return ptr;
}

#define NEXT_MULTIPLE(X, Y) (((X+Y-1)/Y)*Y)

GLBuffer::Ptr
Expand Down Expand Up @@ -895,17 +902,31 @@ GLBuffer::create(GLenum target, osg::State& state, GLsizei sizeHint, GLsizei chu
#endif
}

GLBuffer::Ptr
GLBuffer::create_shared(GLenum target, osg::State& state, GLsizei sizeHint, GLsizei chunkSize)
{
auto ptr = create(target, state, sizeHint, chunkSize);
if (ptr) ptr->_shared = true;
return ptr;
}

void
GLBuffer::bind() const
{
//OE_DEVEL << LC << "GLBuffer::bind, name=" << name() << std::endl;
if (_name == 0) {
OE_WARN << "Catch" << std::endl;
}
OE_SOFT_ASSERT_AND_RETURN(_name != 0, void(), "bind() called on invalid/deleted name: " + _name << );
ext()->glBindBuffer(_target, _name);
}

void
GLBuffer::bind(GLenum otherTarget) const
{
if (_name == 0) {
OE_WARN << "Catch" << std::endl;
}
//OE_DEVEL << LC << "GLBuffer::bind, name=" << name() << std::endl;
OE_SOFT_ASSERT_AND_RETURN(_name != 0, void(), "bind() called on invalid/deleted name: " + label() << );
ext()->glBindBuffer(otherTarget, _name);
Expand Down Expand Up @@ -1247,6 +1268,7 @@ GLTexture::GLTexture(GLenum target, osg::State& state) :
_profile(target)
{
glGenTextures(1, &_name);
_shared = true;
}

GLTexture::Ptr
Expand Down
4 changes: 2 additions & 2 deletions src/osgEarth/TextureArena.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -875,9 +875,9 @@ TextureArena::apply(osg::State& state) const
if (gc._handleBuffer == nullptr || !gc._handleBuffer->valid())
{
if (_useUBO)
gc._handleBuffer = GLBuffer::create(GL_UNIFORM_BUFFER, state);
gc._handleBuffer = GLBuffer::create_shared(GL_UNIFORM_BUFFER, state);
else
gc._handleBuffer = GLBuffer::create(GL_SHADER_STORAGE_BUFFER, state);
gc._handleBuffer = GLBuffer::create_shared(GL_SHADER_STORAGE_BUFFER, state);

gc._handleBuffer->bind();
gc._handleBuffer->debugLabel("TextureArena", "Handle LUT");
Expand Down
6 changes: 3 additions & 3 deletions src/osgEarthDrivers/engine_rex/GeometryPool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ SharedGeometry::getOrCreateNVGLCommand(osg::State& state)

if (de._ebo == nullptr || !de._ebo->valid())
{
de._ebo = GLBuffer::create(GL_ELEMENT_ARRAY_BUFFER_ARB, state);
de._ebo = GLBuffer::create_shared(GL_ELEMENT_ARRAY_BUFFER_ARB, state);
de._ebo->bind();
de._ebo->debugLabel("REX geometry", "Shared EBO");
de._ebo->bufferStorage(_drawElements->getTotalDataSize(), _drawElements->getDataPointer(), 0);
Expand All @@ -359,9 +359,9 @@ SharedGeometry::getOrCreateNVGLCommand(osg::State& state)
// supply a "size hint" for unconstrained tiles to the GLBuffer so it can try to re-use
GLsizei size = _verts.size() * sizeof(GL4Vertex);
if (_hasConstraints)
gs._vbo = GLBuffer::create(GL_ARRAY_BUFFER_ARB, state);
gs._vbo = GLBuffer::create_shared(GL_ARRAY_BUFFER_ARB, state);
else
gs._vbo = GLBuffer::create(GL_ARRAY_BUFFER_ARB, state, size);
gs._vbo = GLBuffer::create_shared(GL_ARRAY_BUFFER_ARB, state, size);

gs._vbo->bind();
gs._vbo->debugLabel("REX geometry", "Shared VBO");
Expand Down

0 comments on commit b04b7ce

Please sign in to comment.