what is proper way to update vao/vbo between thread? - opengl

Here is the problem I came across:
I read 3d model data in a thread and render it in main thread.
What is the proper way to create or update vao/vbo data?
Currently I set a bool value to indicate that whether main thread need to update vbo data, like this:
void RenderModel(){
if(isNeedUpdateVBO){
updateVBOData();
isNeedUpdateVBO = false
}
// render models here
}
I think there may be more efficient way to do that.

Related

How to load mesh in new thread

I am making my first game and I am stuck with one problem. I have a world where you can walk free, but then when you meet the enemy you will switch to battle and when you are switching to battle, I need to load all the models that will be rendered in the battle scene. The loading takes about ~5 seconds and I want to make the loading screen. So, I rendered the loading screen in the main thread, but how can I load 3d models and build different VAO and VBO at the same time? I made a new thread for this loading, but I read online "don't use threads for generating VAOs". What is the best solution to make this loading? Should I just preload all the models in the main thread before the game starts? Personally, for me it seems not right to load all the 3d models in the beginning of the game.
Assuming you have two windows, you can bind each context of the window to separate threads. Problems will arise if you share data between them (proper locking is mandatory).
See glfwMakeContextCurrent:
This function makes the OpenGL or OpenGL ES context of the specified window current on the calling thread. A context must only be made current on a single thread at a time and each thread can have only a single current context at a time.
Thread safety:This function may be called from any thread.
See glfwSwapBuffers:
This function swaps the front and back buffers of the specified window when rendering with OpenGL or OpenGL ES.
Thread safety:This function may be called from any thread.
Some functions in GLFW can only be called from the 'main' thread (nor from callbacks), e.g. glfwPollEvents, but other than that, bind the context to a thread, perform your OpenGl calls and swap the buffers. As said before, as long as you don't share any buffers, there should be no problem.

Creating OpenGL structures in a multithreaded program?

I am attempting to do the following in a physics engine I am building:
Have 2 threads, one for world logic, one for rendering.
The main thread (the thread from which the other threads are created) is the render thread, and then the world thread is forked from it.
On the render thread there is a global data structure called rendering handler declared as:
class Renderer
{
private:
/*
shader stuff
*/
mutex busy_queue;
vector<Render_Info*> render_queue;
public:
/*
Bunch of methods
*/
void add_data(Render_Info*);
void render();
};
And a Render_Info structure is declared as:
struct Render_Info
{
mutex info_lock;
GLuint VAO;
vector<GLuint> VBOs;
vector<GLuint> types;
uint layouts;
uint render_instances;
Mesh* geometry;
};
extern Renderer *Rendering_Handler;
The idea here was as follows. Any thread that wishes to render something, must handle it's own data an put it into OpenGL primitives. it then puts that information into a Render_Info object, which acts as a message between the thread and the rendering thread.
The thread then uses the add_data() method, to send a pointer to it's data message that gets appended to the render_queue as:
void Renderer::add_data(Render_Info* data)
{
busy_queue.lock();
render_queue.push_back(data);
busy_queue.unlock();
}
And finally, when the render thread would choose to render something, it would lock the queue (preventing anything from being added to the queue) render everything, then clear the queue.
Now of course some more thread coordination is needed but that is the gist of the idea.
The issue is, I get segmentation faults just from trying to create OpenGL VAOs and VBOs, let alone filling them with data.
From what I have read OpenGL is as far away from being thread safe as a
Giraffe is from being a dolphin.
And the cause of the problem seems to be that the OpenGL context belongs to the main thread, so when I try to create the VAOs and VBOs on the world thread OpenGL simply crashes as it has no idea what is going on.
What can I do do multi thread the program then?
I'd like to stay as close to the design I have described unless someone provides a good justification of why it would not work.
The requirement for OpenGL is that the context created for rendering should be owned by single thread at any given point and the thread that owns context should make it current and then call any gl related function. If you do that without owning and making context current then you get segmentation faults. By default the context will be current for the main thread. So to make your program multi threaded you have two options.
Create two contexts and share resources like texture objects VAOs between them.Advantage of this approach is you can refer in thread 2 to any VAO created in thread 1 and it wont crash.
Thread_1:
glrc1=wglCreateContext(dc);
glrc2=wglCreateContext(dc);
BOOL error=wglShareLists(glrc1, glrc2);
if(error == FALSE)
{
//Unable to share contexts so delete context and safe return
}
wglMakeCurrent(dc, glrc1);
DoWork();
Thread_2:
wglMakeCurrent(dc, glrc2);
DoWork();
Other option is to make one context per thread and make it current when thread starts. Like following
Thread_1:
wglMakeCurrent(NULL, NULL);
WaitForThread2(); OrDoSomeCPUJob();
wglMakeCurrent(dc, glrc);
Thread_2:
wglMakeCurrent(dc, glrc);
DoSome_GL_Work();
wglMakeCurrent(NULL, NULL);
Hope this clears up the thing.
From what I have read OpenGL is as far away from being thread safe as a Giraffe is from being a dolphin.
Then you're misinformed. OpenGL is perfectly thread safe. You just have to keep in mind that OpenGL contexts act a bit like thread local storage. I.e. when you make a OpenGL context current, then this is localized to the thread that makes that call.
Also extended OpenGL function pointers may be specific to a OpenGL context (but not to a context binding). However OpenGL function loaders keep a thread→context cache. So when you call an extended OpenGL function (i.e. one that must be loaded at runtime) from a thread without a context bound, you'll likely end up calling an invalid function pointer and get a crash.
However despite being perfectly thread safe, OpenGL does not necessarily gain performance when being used multithreaded. OpenGL thread zygote contexts are very useful if you need to update texture and buffer object data from a worker thread, but you should be careful not to tough things that might be in use by the main rendering thread. In programs where I have to do this, the usual approach is, that the data generating thread is creating a pool of texture/buffer objects, updates the data in them and then "surrenders" ownership of the object to the render thread. Eventually the render thread does its thing with these objects and once its done it passes the ownership back to the update thread and takes the next object from its own pool that gets filled with what the data thread sends over.
What can I do do multi thread the program then?
Create zygote OpenGL contexts and configure them to share their texture and buffer objects with the other thread(s) by the mechanism of display list sharing. You can have an arbitrary number of OpenGL contexts in your program and each thread can have its very own context active (while the other threads use different contexts).

How to make QOpenGLContext current without surface in Qt5?

I am working on a project that will use OpenCL to render graphics for display in a QOpenGLWidget. The recommended way to do this seems to be creating a second QOpenGLContext beside the one already present in the QOpenGLWidget, then create a thread where this secondary context can live together with the OpenCL code.
This way Qt can go about it's day as usual with the eventloop running in the main thread. And whenever the QOpenGLWidget decides to paint it will simply fetch data from a buffer prepared in the second thread by the secondary context and the OpenCL inter-op set up there.
This all sounds great on paper, but I am having some problems getting this to work. My question is about how to make the secondary QOpenGLContext "current" in the thread. Because QOpenGLContext::makeCurrent() takes a mandatory QSurface as parameter, and the only surface I have is the one that is available from my QOpenGLWidget, but using that in the secondary thread does not work. I get the following error:
Cannot make QOpenGLContext current in a different thread
So what surface should I use? Or, is there something I missed, or should do differently?
You can create and use a QOffscreenSurface for this purpose.

Get only one QOpenGLContext for different QT widgets

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.
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.
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.

Initializing OpenGL Context in another thread than the rendering

I'm initializing my OpenGL context(SDL/GLEW) in the main thread. But rendering is done in a different thread(things like SDL_GL_SwapWindow or glDrawElements).
The thing is, that nothing happens if I call SDL_GL_SwapWindow. I was trying to simply change the clear color after every swap, but nothing happens.
void render(){
// Rendering...
}
int main(){
// Initialization...
thread rendering(render);
}
Could this be problem?
Not going to work as you expect. OpenGL Context is thread local. Whichever thread you create the context is where the actual OpenGL rendering calls will have to be made from.