VBO and Multithreading

Started by
6 comments, last by CoreMeltdown 17 years, 10 months ago
Hi everybody. --- <Short description> --- The application consists of two threads, "Renderer" and "Loader". "Renderer" draws objects with VBO and "Loader" update VBO's contents. If "Renderer" is calling some gl commands (drawing or state updating), can "Loader" modify VBO content without blocking "Renderer" ? --- <Long description> --- Consider this situation: 1) there are a fixed number of VBO; 2) thread "Renderer" is the main, rendering thread: 2-a) in a first visit, selects the objects to draw and ask thread "Loader" to load their associate data from disk; 2-b) for each of the previously selected objects, asks the "Loader" to get a the vbo ID in which object's data has been loaded and if so draws it, otherwise proceeds to the next object (well, in effect some vbo ID is always returned, even if it is associated to a lower resolution of the requested data); 3) thread "Loader" is the loader: reads requests from thread "Renderer" and, accordingly to some kind of priority, selects an unlocked victim from cache, lock it, loads in it new data from disk, put it in cache and unlock it. 4) I omitted all other shared data exclusive access (queues, cache etc.) for simplicity. Typical situation: -- "Renderer" can be calling state commands like glClear(...), glEnable(...), etc. or vbo-binding/drawing commands like glBindBuffer(...) and GLDrawArrays(...); --- "Loader" can be calling vbo-binding/updating commands like glBindBuffer(...) and glBufferSubData(...); If I can guarantee (in effect it is done) that the vbo currently used by "Renderer" is different from the one used by "Loader", can these commands be executed without the two threads blocking each other? If not, is a solution If I can guarantee that every group of call to vbo stuff is done in mutual exclusion even if not referring the same vbo? And more in general (even if my question regards only vbo management), can non-interfering gl commands be called on the same gl-context without the need for synchronization? In effect, a solution for this problem is that the "Loader" can put the data loaded in a temporary buffer associated with every vbo and the vbo marked as "dirty". Then when the "Renderer" wants to use it, if it is dirty then upload the data from the vbo's temporary buffer, and finally renders it. However, I don't want to keep a temporary buffer for each vbo thus duplicating the total system + video memory. In addition, It is preferable even not to using a single temporary buffer in the "Loader", but instead specifying the memory mapped pointer returned by glMapBuffer(...) as the destination address of a fread(...) or memcpy(...) (if the file is memory mapped). I am very sorry for the very long post, but the situation required it to eliminate possible doubts about problem and solution. Thanks in advance!!! :) Marco
Advertisement
The only concern is that an opengl context can only be active in one thread at a time.

So if you use one context, one of the thread will have to block before calling opengl functions if the other one is also calling gl functions.

You can use 2 contexts, one for each thread and use wglShareList so they can share their objects. Then as long they are not both trying to use a vbo id at the same time you will be fine.

So the most portable solution is your dirty vbo.

If you map the memory of the vbo to a pointer, then you can simply pass this address and let the loader write to it. Obviously the render thread will have to do the unmap. But you have to understand, this is the same thing as creating a tempory buffer and sending it using glBufferSubData because the driver will create a temporary region in memory for you to write to.

If you are worried about memory, you can just allocate on updates.

[Edited by - Gorg on June 1, 2006 12:51:11 AM]
Thanks for your reply! :)

However:

Quote:Original post by Gorg
... If you map the memory of the vbo to a pointer, then you can simply pass this address and let the loader write to it.


But concurrent gl commands issue still holds...

Quote:Original post by Gorg
... But you have to understand, this is the same thing as creating a tempory buffer and sending it using glBufferSubData because the driver will create a temporary region in memory for you to write to.


Well, not always true. If the driver uses the memory mapped I/O mechanism provided by the underlying O.S. (and we expect this from modern drivers/O.S.s), then the returned address refers to a location in video memory, mapped in the process's addressing space.
Last night I was trying to ma
"Hard work pays off for the future; laziness pays off now"
I have also tried the multiple context approach, but when I made a call to glBufferSubData(...) (preceded by the lock mechanism and glBindBuffer(...) ) I get a GL_INVALID_VALUE error even if the parameters I passed to it are correct.
The two context shares objects (wglShareLists).

The actual order of operations is:

1) Create renderer GL context.
2) Create VBOs.
3) Launch loader thread:
3-a) create updater GL context.
3-b) call wglShareLists(renderer_ctx, loader_ctx) and make loader_ctx current to the loader thread.
4) Whenever the renderer wants to draw a vbo, locks, binds, draws it and release it.
5) Whenever the loader wants to update a vbo content, locks, binds, update and release it.

What is wrong?
Quote:Original post by CoreMeltdown
The actual order of operations is:

1) Create renderer GL context.
2) Create VBOs.
3) Launch loader thread:
3-a) create updater GL context.
3-b) call wglShareLists(renderer_ctx, loader_ctx) and make loader_ctx current to the loader thread.


If you are actually creating and sharing the second context in the loader thread, are you 100% certain both calls succeed? In my own testing this week with two contexts and sharing resources I found that both contexts need to be created in the main thread, and the call to wglShareLists also needs to happen in the main thread.
Ah, it was discovered in another thread that inorder to share two contexts they need to both be created in the same thread.

So, I'd change your setup to;

1) Create renderer GL context.
1a) Create updater GL context
1b) share contexts
1c) make renderer context current again
2) Create VBOs.
3) Launch loader thread:
3-a) make loader_ctx current to the loader thread.
4) Whenever the renderer wants to draw a vbo, locks, binds, draws it and release it.
5) Whenever the loader wants to update a vbo content, locks, binds, update and release it.


If my understanding from the other thread is right that should work
Quote:Original post by phantom
Ah, it was discovered in another thread that inorder to share two contexts they need to both be created in the same thread. ...


YES!!!

I just find a similar thread on opengl.org, tried it and now it works! I was posting that the problem was solved and I foud your replies :)

The key was creating a sharing the secondary context on the main thread.

Thanks a lot!!!

Marco.

This topic is closed to new replies.

Advertisement