One OpenGLContext with multiple OpenGLRenderers?

I would also like to know the answer to this question. Can you use multiple OpenGLRenderers with a single OpenGLContext?

From the JUCE source code, it seems that any OpenGLContext can only have a single OpenGLRenderer.

Yet, from @fr810’s prior suggestion in the forum:

If you have multiple components requiring opengl and you want to render all GUI components with OpenGL, then I strongly advise that you attach an OpenGLContext to the top-level component only . The top-level component can then keep track of all the subcomponents which require renderOpenGL callbacks and simply forward the renderOpenGL callback to them.

Here, Fabian suggests that a top-level component attached to an OpenGLContext could be used to keep track of multiple Components, some of which may be OpenGLRenderers that have the renderOpenGL() callback. This makes it sound like a single OpenGLContext can be used for multiple OpenGLRenderers.

From what I understand, this “keeping track of subcomponents that require renderOpenGL() callbacks” is NOT automatic since an OpenGLContext can only be associated with a single OpenGLRenderer. Therefore, I believe the renderOpenGL() callbacks must then be manually called by a top-level OpenGLRenderer attached to the OpenGLContext.

Here is a stubbed out idea of how I believe this might work. @fr810 is this a correct interpretation of your suggestion?

/** The Top-most component of the application which we wish to be
    rendered using OpenGL. It contains any JUCE Components
    (or hierarchy of Components) which we wish to be rendered using
    OpenGL as well as any custom OpenGL-based JUCE Components
    which will render by calling lower-level OpenGL commands and using
    shader programs.
 */
class TopLevelComponent : public Component,
                          private OpenGLRenderer
{
public:
    TopLevelComponent()
        : myGLComponentA (&openGLContext),
          myGLComponentB (&openGLContext)
    {
        // Sets the OpenGL version to 3.2 and above
        openGLContext.setOpenGLVersionRequired (OpenGLContext::OpenGLVersion::openGL3_2);

        openGLContext.setRenderer (this);
        openGLContext.attachTo (*this);     
        openGLContext.setContinuousRepainting (true);   

        // Add custom OpenGL Components 
        renderers.push_back (dynamic_cast<OpenGLRenderer *> (&myGLComponentA));
        renderers.push_back (dynamic_cast<OpenGLRenderer *> (&myGLComponentB));
        addAndMakeVisible (myGLComponentA);
        addAndMakeVisible (myGLComponentB);

        // Add regular JUCE Components
        addAndMakeVisible (slider);
        addAndMakeVisible (button);
    }

    ~TopLevelComponent()
    {
        openGLContext.setContinuousRepainting (false);
        openGLContext.detach();
    }

    void newOpenGLContextCreated() override
    {
        for (auto * renderer : renderers)
            renderer->newOpenGLContextCreated();
    }


    void openGLContextClosing() override
    {
        for (auto * renderer : renderers)
            renderer->openGLContextClosing();
    }
    
    
    void renderOpenGL() override
    {
        for (auto * renderer : renderers)
            renderer->renderOpenGL();
    }

private:
    OpenGLContext openGLContext; // Single shared context

    // Custom OpenGL Components
    std::vector<OpenGLRenderer *> renderers;
    MyOpenGLComponent myGLComponentA;
    MyOpenGLComponent myGLComponentB;

    // Normal JUCE Components (get rendered with OpenGL due to context
    // attachment to this parent Component)
    Slider slider;
    Button button;
};

//=================================================================

/** An OpenGL-based JUCE Component that has custom OpenGL rendering.
   
     There could by any number of different custom OpenGL-based
     Components similar to this one which could all be set as
     children of the TopLevelComponent and be added to the
     `renderers` vector to be driven by the top level OpenGLRenderer.
 */
class MyOpenGLComponent : public Component,
                          public OpenGLRenderer
{
    MyOpenGLComponent (OpenGLContext * externalOpenGLContext)
    {
        context = externalOpenGLContext;
    }

    void newOpenGLContextCreated() override
    {
        // Compile shader programs . . .
        // Needs access to the OpenGLContext context member to 
        // constructing a OpenGLShaderProgram.

        // Setup any needed OpenGL buffers . . .
        // Needs access to the OpenGLContext context member to 
        // generate/bind buffers.
        // Ex: context->extensions.glGenVertexArrays (1, &VAO);
        //     context->extensions.glBindVertexArray (VAO);
    }


    void openGLContextClosing() override
    {
        // Cleanup any OpenGL buffers . . .
        // Needs access to the OpenGLContext context member to deallocate
        // Ex: context->extensions.glDeleteVertexArrays (1, &VAO);
        //     context->extensions.glDeleteBuffers (1, &VBO);
    }
    
    
    void renderOpenGL() override
    {
        // Do some custom rendering . . .
        // Needs access to the OpenGLContext context member for things
        // like rendering scale: context->getRenderingScale()
    }

private:
    OpenGLContext * context; 
};

I am unsure if this helps solve @YetAnotherGuy’s multi-window issue, but I was at least hoping to answer this thread’s main question for the case of a single window.