Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 10 of 10

Thread: Render one scene to multiple windows with same context

  1. #1
    Intern Contributor
    Join Date
    Dec 2011
    Posts
    64

    Lightbulb Render one scene to multiple windows with same context

    Hello,

    I read some articles how to draw for example in my case one triangle to two different top-level windows. They are both sharing context.
    My hierarchy is following:
    > Application > MainWindow > GraphicsWindow1 > Triangle
    > GraphicsWindow2 (contains link to GraphicsWindow1)

    Problem:
    When GraphicsWindow2 renders he take Triangle from GW1 and calls Draw. I suppose that should be all. But there is not drawed triangle in GW2.

    My goals: render in GW2 same thing as in GW1 but with different camera. Also I tried to build this with some efficient like few lines of code.

    Source code is available on github: https://github.com/glararan/Qt-OpenGL

    GraphicsWindow inherits from GLWindow which inherits from QOpenGLWindow.

    GraphicsWindow location: https://github.com/glararan/Qt-OpenG...hicswindow.cpp
    Triangle location: https://github.com/glararan/Qt-OpenG...e/triangle.cpp
    Shaders are located here: https://github.com/glararan/Qt-OpenG.../shaders/basic

    I have to missing something, just I don't know what.

    Thanks for help!

  2. #2
    Intern Contributor
    Join Date
    Dec 2011
    Posts
    64
    Well I figured out, that problem is located in Triangle.cpp file in Draw function. It seems VAO can't be shared for multiple windows?

    Code :
    void Triangle::Draw(const QMatrix4x4& mvp){
        qDebug() << "Triangle target1:\t" << QOpenGLContext::currentContext()->surface() << "\t" << functions->glGetError(); // returns Triangle target1:	 0x10d6a98 	 0
     
     
        shader->bind();
        qDebug() << "Triangle target2:\t" << QOpenGLContext::currentContext()->surface() << "\t" << functions->glGetError(); // returns Triangle target2:	 0x10d6a98 	 0
        {
            shader->setUniformValue(mvpLoc, mvp);
     
     
            qDebug() << "Triangle target3:\t" << QOpenGLContext::currentContext()->surface() << "\t" << functions->glGetError(); // returns Triangle target3:	 0x10d6a98 	 0
            //glBindVertexArray(vao);
            vao.bind(); // when I move qDebug() "target3" it returns glGetErrors() 1282
     
     
            functions->glDrawArrays(GL_TRIANGLES, 0, 3);
            vao.release();
     
     
            qDebug() << "Triangle target4:\t" << QOpenGLContext::currentContext()->surface() << "\t" << functions->glGetError(); // returns Triangle target4:	 0x10d6a98 	 1282
        }
        shader->release();
    }

    How would you solve this?

    When I want to draw same scene in two windows.. always create vao for each sub-object?

    Thanks

  3. #3
    Senior Member OpenGL Guru
    Join Date
    Jun 2013
    Posts
    2,402
    Quote Originally Posted by glararan View Post
    It seems VAO can't be shared for multiple windows?
    VAOs aren't shared between contexts. More generally, objects which contain references to other objects aren't shared (more details here).

    Quote Originally Posted by glararan View Post
    How would you solve this?
    The simplest way is not to use a different context for each window. But that isn't an option if the windows may be on different physical displays, or if you need to render from multiple threads concurrently.

    If you need to use multiple contexts, then create a copy of the VAO for each context. Note that you can't force them to have the same name (handle) in different contexts, so you'll need some way to find the correct VAO for a given context.

  4. #4
    Intern Contributor
    Join Date
    Dec 2011
    Posts
    64
    Quote Originally Posted by GClements View Post
    VAOs aren't shared between contexts. More generally, objects which contain references to other objects aren't shared (more details here).


    The simplest way is not to use a different context for each window. But that isn't an option if the windows may be on different physical displays, or if you need to render from multiple threads concurrently.

    If you need to use multiple contexts, then create a copy of the VAO for each context. Note that you can't force them to have the same name (handle) in different contexts, so you'll need some way to find the correct VAO for a given context.
    Ok so, I'm currently sharing context so I have to recreate for second window vao.

    EDIT:

    So for let this working I had to make this edit:
    Code :
    void Triangle::Draw(const QMatrix4x4& mvp, bool copy){
        shader->bind();
        {
            shader->setUniformValue(mvpLoc, mvp);
     
     
            if(!copy)
            {
                //glBindVertexArray(vao);
                vao.bind();
     
     
                functions->glDrawArrays(GL_TRIANGLES, 0, 3);
                vao.release();
            }
            else
            {
                vbo.bind();
     
     
                QOpenGLVertexArrayObject _vao;
                _vao.create();
                _vao.bind();
     
     
                shader->enableAttributeArray(0);
                shader->enableAttributeArray(1);
                shader->setAttributeBuffer(0, GL_FLOAT, 0, 2, 0);
                shader->setAttributeBuffer(1, GL_FLOAT, 6 * sizeof(GLfloat), 3, 0);
     
     
                _vao.bind();
     
     
                functions->glDrawArrays(GL_TRIANGLES, 0, 3);
     
     
                _vao.release();
                vbo.release();
            }
        }
        shader->release();
    [FONT=Verdana]}[/FONT][COLOR=#000000][/COLOR]


    Any idea how to make this better?
    Last edited by glararan; 07-18-2016 at 08:28 AM.

  5. #5
    Senior Member OpenGL Guru
    Join Date
    Jun 2013
    Posts
    2,402
    Quote Originally Posted by glararan View Post
    Code :
                vbo.bind();
     
                QOpenGLVertexArrayObject _vao;
                _vao.create();
                _vao.bind();
    First, binding the VBO serves no purpose here, because attribute array bindings are stored in the current VAO.

    Second, you shouldn't be creating a new VAO for each call to the Draw method; you should be storing it. Currently, GLObject has a member variable, vao of type QOpenGLVertexArrayObject, whereas it should probably have a vector/map/etc of such, with the context (or some context-related property) as the key. Or the window class should have a vector/map/etc, with the object as a key.

    But unless you actually need multiple contexts, you should just use a single context for all windows. Ignore the context which Qt creates and explicitly use makeCurrent() to make the global context current.

  6. #6
    Intern Contributor
    Join Date
    Dec 2011
    Posts
    64
    Quote Originally Posted by GClements View Post
    First, binding the VBO serves no purpose here, because attribute array bindings are stored in the current VAO.

    Second, you shouldn't be creating a new VAO for each call to the Draw method; you should be storing it. Currently, GLObject has a member variable, vao of type QOpenGLVertexArrayObject, whereas it should probably have a vector/map/etc of such, with the context (or some context-related property) as the key. Or the window class should have a vector/map/etc, with the object as a key.

    But unless you actually need multiple contexts, you should just use a single context for all windows. Ignore the context which Qt creates and explicitly use makeCurrent() to make the global context current.

    1) When I dont bind VBO while creating VAO app crashes. But I dont want to have multiple vao
    2) Yes I know but it was fast debug, sorry GLObject variable vao is for main window where scene is rendered correctly, while I bind same vao while drawing on second window, nothing is rendered.
    3) I am using single context, the one created by main window. makeCurrent using in GLWindow::renderNow() look below.

    Code :
    void GLWindow::renderNow(){
        if(!isExposed())
            return;
     
     
        if(!painted)
            return;
     
     
        painted = false;
     
     
        QOpenGLWindow::makeCurrent();
     
     
        QOpenGLWindow::update();
     
     
        context()->swapBuffers(this);
     
     
        if(draw && !pendingUpdate)
        {
            pendingUpdate = false;
     
     
            QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest));
        }
    }

    So if I correct understand, I should create one global context before I even create mainwindow and use it for both windows.

  7. #7
    Senior Member OpenGL Guru
    Join Date
    Jun 2013
    Posts
    2,402
    Quote Originally Posted by glararan View Post
    Code :
    void GLWindow::renderNow(){
    ...
        QOpenGLWindow::makeCurrent();
    This just calls the superclass' makeCurrent() method. you'd need to use something like
    Code :
    mainwindow->context()->makeCurrent(this);.

    Quote Originally Posted by glararan View Post
    So if I correct understand, I should create one global context before I even create mainwindow and use it for both windows.
    You should be able to use the context created for the main window everywhere. But you'll need to ensure that you don't implicitly use the context created for the second window. Personally, I'd suggest deriving from QPaintDeviceWindow rather than QOpenGLWindow so that you can do it right. That's likely to be easier than trying to explicitly work around all of QOpenGLWindow's mistakes.

  8. #8
    Intern Contributor
    Join Date
    Dec 2011
    Posts
    64
    Quote Originally Posted by GClements View Post
    This just calls the superclass' makeCurrent() method. you'd need to use something like
    Code :
    mainwindow->context()->makeCurrent(this);.


    You should be able to use the context created for the main window everywhere. But you'll need to ensure that you don't implicitly use the context created for the second window. Personally, I'd suggest deriving from QPaintDeviceWindow rather than QOpenGLWindow so that you can do it right. That's likely to be easier than trying to explicitly work around all of QOpenGLWindow's mistakes.
    Last night I read this article: https://blog.qt.io/blog/2014/11/20/q...qrasterwindow/
    If I would deriving just from QWindow this should work like QPaintDeviceWindow

    EDIT: Ok I'm inheriting from QPaintDeviceWindow
    EDIT2: Ok I basically took QOpenGLWindow code and removed creating context on init, instead I give him already created to use, working for now, just I have to clean code and fix swapBuffers error, so for now its solved, thank you!
    Last edited by glararan; 07-19-2016 at 07:11 AM.

  9. #9
    Senior Member OpenGL Guru
    Join Date
    Jun 2013
    Posts
    2,402
    Quote Originally Posted by dungdn93 View Post
    It seems VAO can't be shared for multiple windows?
    VAOs can't be shared between contexts (nor can FBOs, program pipeline objects or transform feedback objects).

    You can use a single context on multiple windows, provided that all windows are compatible with the context (typically this means that they must be on the same screen or on screens which correspond to the same video device, and use the same or similar formats).

    The issue here is with QOpenGLWindow, which "conveniently" creates a context for the window and ensures that it's current before invoking methods which are likely to use the context. That approach may have been fine for OpenGL up to version 2 (where contexts which shared data shared all objects), but doesn't really work for OpenGL 3 or later due to container objects being non-shareable.

    Of course, you can just re-create any container objects for each context, but then an application-defined class can't be associated with a single container (e.g. VAO), it needs one container per context.

  10. #10
    Intern Contributor
    Join Date
    Dec 2011
    Posts
    64
    Well, there is final code: https://github.com/glararan/Qt-OpenG...affc6e092530a8 but I forgot to remove isCopy.. but compiler let you know what to remove.
    There is currently just one more limitation, maximum fps is based on your monitor. But when you close second window, you regain power and FPS is around 2 thousand.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •