OpenGLTexture release on render thread

I’m trying to ensure that the OpenGLTexture release function is called properly on the OpenGL render thread. I have a Cable class with an OpenGLImageComponent that handles OpenGL textures and rendering.

From what I understand, OpenGLTextures must be released on the OpenGL render thread, while JUCE components need to be deleted on the message thread. I’m unsure how to manage this without blocking. If I set the Cable object to nullptr, the OpenGLImageComponent destructor will eventually be called, which triggers juce::OpenGLTexture::release, but this function needs to be on the render thread:

cpp

Copy code

// If the texture is deleted while the owner context is not active, it's
// impossible to delete it, so this will be a leak until the context itself
// is deleted.
jassert (ownerContext == OpenGLContext::getCurrentContext());

How can I handle this without blocking? Ideally, I’d like to delete the component immediately on the message thread and schedule OpenGL-related cleanup separately. Would using shared_ptr for OpenGLImageComponent help?

Maybe OpenGLContext::executeOnGLThread could be useful. In the destructor of your component, you could call executeOnGLThread, passing a lambda that releases the texture. Be careful with ownership: OpenGLTexture isn’t copyable or moveable, so you might need to use a shared_ptr<OpenGLTexture> in order to reference the texture from the releaser-lambda without danger of dangling.

Oh I didn’t even notice that there is an executeonGLThread function I had created that functionality using a concurrentqueue of lambda functions.

Perhaps I’ll move to that function!

I ended up just adding a shared_ptr functionality to the whole openglcomponent and then sending function to the openglthread.

void SynthSection::destroyOpenGlComponent(OpenGlComponent const& open_gl_component, OpenGlWrapper& open_gl)
{
    //moves the component to the end of the array
    //erases it from the vector
    const MessageManagerLock mmLock;
    auto new_logical_end = std::remove_if(open_gl_components_.begin(), open_gl_components_.end(), [&](std::shared_ptr<OpenGlComponent> const& p)
    {
        return *p == open_gl_component;
    });

    open_gl_components_.erase(new_logical_end,open_gl_components_.end());


}

I am concerned that this isn’t the best implementation because this lock is annoying since this function is always sent from the messagemanager thread anyway so I would like to delete the component there.

Do you think for the shared_ptr<OpenGLTexture> method I could avoid this lock ?

I imagine I could have a class such as

struct OpenGLComponent public : juce::Component {
...
std::shared_ptr<OpenGlTexture> text; 

...
}

and then in a delete function

//keypress delete on MessageThread

OpenGLContect::executeOnGLThread( [glTexture=openglcomponent->text](){ glTexture->release(); }, false);
openglComponent = nullptr; 

this would trigger the component destructor to happen on the Message thread but the texture would remain alive since a copy of it has been made and that release() call would get made on the GLThread.

Now that I write this all out I think that actually I could solve my messageManager lock issue in the current implementation by calling

removeChildComponent() before queuing up the destroyOpenGlComponent() that way the JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED_OR_OFFSCREEN call is satisfied and then when the destructor of the OpenGlComponent is called on the renderthread we won’t hit that assert. Perhaps this is still more work than necessary on the render thread with all the destruction of objects and what not. So maybe the texture ptr method is probably still the better of the two