stevenlovegrove / Pangolin

Pangolin is a lightweight portable rapid development library for managing OpenGL display / interaction and abstracting video input.
MIT License
2.35k stars 849 forks source link

Shared Context Between Multiple Windows? #845

Open robin-read opened 1 year ago

robin-read commented 1 year ago

Hi Folks,

I need a bit of help. I'd like to be able to open two windows and have them share the same GLContext so that I can load some Textures and render these in both windows.

I'm not sure how to go about doing this. Any help welcome!

Thanks!

stevenlovegrove commented 1 year ago

OpenGL can actually share resources like textures across contexts - you just have to construct the context that way. I'd recommend this based on your description. Pangolin actually does this automatically with X11, but it hasn't been implemented for other platforms.

See https://github.com/stevenlovegrove/Pangolin/blob/master/components/pango_windowing/src/display_x11.cpp#L492 where global_gl_context is the first context created and the one shared when creating other contexts. If you need it for other platforms, it should be possible on Windows, but MacOS can be trickier due to some GUI thread restrictions it enforces.

robin-read commented 1 year ago

Thanks for the reply. I've continued to tinker around but am still struggling. I've put together a bare-bones example of what I'm trying to do. Clearly I'm going wrong but can't really tell.

#include <pangolin/display/display.h>
#include <pangolin/display/view.h>
#include <pangolin/handler/handler.h>
#include <pangolin/gl/gldraw.h>

void render(const std::string &contextName,
            pangolin::WindowInterface &window,
            pangolin::View &view,
            pangolin::GlTexture &texture)
{
    window.MakeCurrent();
    pangolin::BindToContext(contextName);
    view.Activate();

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glEnable(GL_DEPTH_TEST);

    if (!texture.IsValid())
    {
        throw std::runtime_error("Texture is not valid!");
    }

    glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
    texture.RenderToViewport();

    pangolin::FinishFrame();
    window.RemoveCurrent();
}

int main(int argc, char *argv[])
{
    // Setup the first Window
    pangolin::WindowInterface &window1 = pangolin::CreateWindowAndBind("First", 640, 480);
    pangolin::OpenGlRenderState s_cam1(pangolin::ProjectionMatrix(640, 480, 420, 420, 320, 240, 0.2, 100),
                                       pangolin::ModelViewLookAt(-2, 2, -2, 0, 0, 0, pangolin::AxisY));
    pangolin::View &d_cam1 = pangolin::CreateDisplay().SetBounds(0.0, 1.0, 0.0, 1.0, -640.0f / 480.0f);

    // Setup the second Window
    pangolin::WindowInterface &window2 = pangolin::CreateWindowAndBind("Second", 640, 480);
    pangolin::OpenGlRenderState s_cam2(pangolin::ProjectionMatrix(640, 480, 420, 420, 320, 240, 0.2, 100),
                                       pangolin::ModelViewLookAt(-2, 2, -2, 0, 0, 0, pangolin::AxisY));
    pangolin::View &d_cam2 = pangolin::CreateDisplay().SetBounds(0.0, 1.0, 0.0, 1.0, -640.0f / 480.0f);

    // Load the texture, this is sensitive to which window it is created after.
    pangolin::GlTexture texture;
    texture.LoadFromFile("/home/host_user/Desktop/arrow.png");

    while (!pangolin::ShouldQuit())
    {
        render("First", window1, d_cam1, texture);
        render("Second", window2, d_cam2, texture);
    }

    return 0;
}

The result I get is below:

Texture Screenshot

What I've noticed is that if I move where I load the Texture (e.g. before or after creating window2) the result of the rendering flips (e.g. "First" has the correct texture and "Second" shows a white texture). Moreover, if I create a texture for each window and pass the respective texture to the render() function all works well. However I'd like to load the texture only once and use to render the texture in each window.

// Create window1...
 pangolin::GlTexture texture1;
 texture1.LoadFromFile("/home/host_user/Desktop/arrow.png");

// Create window2...
 pangolin::GlTexture texture2;
 texture2.LoadFromFile("/home/host_user/Desktop/arrow.png");

while (!pangolin::ShouldQuit())
{
    render("First", window1, d_cam1, texture1);
    render("Second", window2, d_cam2, texture2);
}

Am I trying to do something that's not possible or am I missing something? Also, I'm on v0.8 on Ubuntu 22.04.

Thanks!

P.S. I'm very new to OpenGL, so probably missing some core knowledge too!