3

I've the following problem :

I want to get an application composed of many view which render a common OpenGL scene from a different point of view, illumination, and others options.

Basically, my question is what is the best way to do that with qt ?

My first attempt was to create multiple QOpenGLWidget and get a common QOpenGLContext where I stored the textures but also the meshes and shaders. But it didn't work for meshes because Vertex Array Objects seem to not be shareable. After lot of tries, a possible solution is to store one VAO for each widget that need the mesh but this look really awful.

So, I wonder if there is a good alternative for this kind of problem, or maybe a good documentation to understand how these QOpenGLContext work.

The simplest idea that I've imagined is to create only one QOpenGLContext and use it in the different widgets. But I don't know how to just create a QOpenGLContext alone nor what kind of QWidgets is able to display these renderings.

It's my first post so I don't know if it's clear enough or if I need to describe my whole architecture.

rocambille
  • 15,398
  • 12
  • 50
  • 68
  • 1
    The `QOpenGLContext` wraps the OpenGL context. Its limitations have everything to do with how OpenGL contexts work. Qt has nothing much to do with it. The documentation you want is OpenGL documentation and tutorials, not `QOpenGLContext` documentation. – Kuba hasn't forgotten Monica Aug 23 '16 at 13:29
  • I know the liminations of OpenGL context, that why I want to use only one for my whole application but the point is to know how to do that with qt. – Boris RAYMOND Aug 23 '16 at 14:00

2 Answers2

-1

You already tried, so I pass the word about shared contexts.

An OpenGL context is bound to a window: if you want only one context, the straight answer is to have only one window.

Using the widgets module, you can have multiple views of a same scene using multiple viewports in a same QOpenGLWidget. Something like:

void myWidget::paintGL() {
    //...

    glViewport(
        0, 0,
        this->width()/2, this->height()/2
    );

    // draw scene from one point of view

    glViewport(
        this->width()/2, this->height()/2,
        this->width()/2, this->height()/2
    );

    // draw scene from an other point of view

    //...
}

You should probably design a viewport class to store and manage the rendering parameters for each viewport.

The drawback is that you will have to detect in which viewport the user is clicking to handle interactions: some kind of if event.pos.x is between 0 and this->width()/2 ....


An other way could be to let down the widgets module and use Qt Quick and QML: a quick window declares a unique OpenGL context, where each quick item is like a viewport, but encapsulated in its own object so you don't have to think about where the user is interacting.

Inherit QQuickItem instead of QOpenGLWidget and export your class to QML using the qmlRegisterType() macro. You can then create a QQuickView in your program to load a QML code where you declare your items. An example from Qt's documentation here.

rocambille
  • 15,398
  • 12
  • 50
  • 68
  • I've never consider this solution because I thought that is better to not reinvent the wheel. But actually it's probably the simplest solution to keep the control of my resources and renderings. – Boris RAYMOND Aug 23 '16 at 15:08
  • I guess that by reinventing the wheel, you speak of the multiple viewport solution. You should really consider using the QML solution: it's the same with a wheel already invented – rocambille Aug 23 '16 at 15:27
  • Ok, I've look a bit of what is qt quick and it look really easier to use than the old method. Nethertheless, before I go a step further in my documentation step, can you already tell me if the qml will permit me to dynamically change the size or the number of viewport ? – Boris RAYMOND Aug 24 '16 at 08:56
  • To dynamically change the size of viewports, you can take a look at [SplitView](http://doc.qt.io/qt-5/qml-qtquick-controls-splitview.html) which is the QML version of QSplitter. Changing the number of viewport can be achieved with buttons and signals and slots as in C++. If you want a more complex layout, e.g. to make a tile-based UI, it's also possible. I made something like that last year. It was a bit more difficult, but it can be done in a clean way (unfortunately, the code is not open source, so I can't show you the result) – rocambille Aug 24 '16 at 09:21
  • I've tried some things from the opengl qtquick example but it's not that simple to integrate with my architecture. I think I'll just use the multiple viewport solution with only one QOpenGLWidget to manage the rendering. If one day somebody get an elegant solution that permit to draw in multiple widget using only one QOpenGLContext, I hope he will see this post to explain how he has done this ! – Boris RAYMOND Aug 24 '16 at 15:39
  • I don't see how "suggestion to use single scene and split up the gl viewport" is the answer to a question that clearly asks "how to re-use a QOpenGLContext in multiple QT Widgets?" – Harish Aug 26 '16 at 06:19
  • 2
    @Harish That's because you didn't understand the question is an [XY problem](http://xyproblem.info/) – rocambille Aug 26 '16 at 07:08
  • @wasthishelpful Quite like the http://xyproblem.info/ link. I still feel the title of the question is misleading. I think both X and Y solve the problem but X is what he ended up using. – Harish Aug 26 '16 at 07:15
-1

I think since multiple views/surfces can update independently, unfortunately its not possible to have one single QOpenGLContext that does the job. And sharing contexts have the limitation you already point out in your question.

QOpenGLContext can be moved to a different thread with moveToThread(). Do not call makeCurrent() from a different thread than the one to which the QOpenGLContext object belongs. A context can only be current in one thread and against one surface at a time, and a thread only has one context current at a time.

Link : http://doc.qt.io/qt-5/qopenglcontext.html

So one way you can get it working is have independent updates to your views in a sequential order and make the context current one by one and render before moving on to the next view. This will guarantee that the context is current in only one view at any given time. Perhaps use a QMutex to serialize the updates.

Alternatively you can also pass the context around among threads and serialize their updates, but this is a bad approach.

Harish
  • 964
  • 6
  • 17
  • If the updates are sequential, what is the point of using threads? – rocambille Aug 23 '16 at 14:41
  • If there is some cpu side stuff that needs to be done pre rendering that part can be parallel, only the rendering needs to be synchronized. – Harish Aug 23 '16 at 15:08
  • FYI, I use a classical SIGNAL/SLOT combo to refresh my displays. I don't know if it's sequential or not. – Boris RAYMOND Aug 23 '16 at 15:10
  • Its sequential if both are on the same thread. I am guessing both are on the GUI thread so in that case they are sequential. – Harish Aug 23 '16 at 15:13
  • I'm not really confortable with this kind of multi threading but I'm afraid that it yield a huge pain in the ass to maintain this, isn't it ? – Boris RAYMOND Aug 23 '16 at 15:24
  • Yes maintaining multiple threads is pain. You can use single thread and serialize the updates using signal-slot. Alternatively you can also use VBO's across shared contexts if you can switch to them, that is what I use anyways. – Harish Aug 23 '16 at 15:35