PDA

View Full Version : Can I render and update VBO at the same time?



zacharmarz
06-03-2011, 04:35 PM
I have simple application. It has two threads. Each thread has it's own rendering context, but they share one VBO (this is working, I tested it).

Now what I want: One thread is rendering some data from first half of VBO and the second thread is updating second part of VBO.

When I don't update VBO, it's working fine.

But I have some weird issues when updating. When I use glMapBuffer to update VBO (in second thread), it's most time rendering nothing (in first thread) - whole screen is clear (after glClear call). It looks like it can't touch data from VBO (this is understandable, because whole buffer is mapped and so it can be locked somehow).

I tried to use glMapBufferRange, which has flag GL_MAP_UNSYNCHRONIZED_BIT. This should mean: don't wait and use VBO as you want, I will synchronize it by myself. Also - when I map only range of VBO and render data from other part, it shouldn't be waiting. But there are the same issues as with glMapBuffer.

Can anybody explain why or help me, how to fix this? This is my first multi-thread OpenGL app :\

Alfonse Reinheart
06-03-2011, 04:56 PM
OpenGL's multithreading rules are quite simple. OpenGL is reentrant. That's all it guarantees.

That is, you can have two separate contexts. You can mess with non-object state in two separate contexts. You can call the same functions in different contexts without problems. However, you cannot modify object state that is shared across contexts unless you ensure that the two sides are not simultaneously reading/modifying it. If you do, undefined behavior ensues.


This should mean: don't wait and use VBO as you want, I will synchronize it by myself.

No, it means "the mapping will start now, regardless of whether the buffer object is currently being used as source/destination data." It does not cause the API to bypass the fact that you cannot use a buffer that is currently mapped as a source or destination. While the buffer is mapped, from whichever thread, you cannot initiate an operation that reads from or writes to it. That is part of the object's state (whether it is mapped or not); mapping it in one thread means that the object is mapped.


Can anybody explain why or help me, how to fix this?

Stop trying to use the buffer after you've mapped it. On thread A, do your rendering. After you're finished rendering for the current frame, have thread B start doing its poking at the data with UNSYNCHRONIZED. Thread A cannot start rendering again until thread B is finished.

zacharmarz
06-04-2011, 01:38 AM
Thanks for your answer. I really appreciate it.

What I'm trying to do is to benchmark glMapBuffer vs. glMapBufferRange in multi-threaded application. So I hoped it would work (read some part and write to other part at the same time).

So there is no way to do this? Why should I use glMapBufferRange instead of glMapBuffer? Only advantage is not to map the whole buffer?

Alfonse Reinheart
06-04-2011, 02:09 AM
So there is no way to do this?

I told you how to do it: "Stop trying to use the buffer after you've mapped it." You use the buffer before you map it.

What you were doing looks like this:



Thread A: |----[glDraw*]--------|----[glDraw*]--------|
Thread B: |-[glMap* ]-|-[glMap* ]-|


The [ ] represent the time you spend calling these functions. When mapping, the unmap happens with the ]. The | represents the start of a frame.

This is not allowed. What you need to do is this:



Thread A: |----[glDraw*]--------|----[glDraw*]--------|
Thread B: |-------------[glMap* | ]---------[glMap* |


You don't even have to map the buffers on thread B. Thread A can map them and pass the pointers to thread B.

zacharmarz
06-04-2011, 10:56 AM
Thanks. I will try it :)

Dark Photon
06-05-2011, 11:47 AM
I tried to use glMapBufferRange, which has flag GL_MAP_UNSYNCHRONIZED_BIT. This should mean: don't wait and use VBO as you want, I will synchronize it by myself. Also - when I map only range of VBO and render data from other part, it shouldn't be waiting. But there are the same issues as with glMapBuffer.
As an aside, this works single-thread beautifully. Yes, you can be updating one part while the GPU is rendering out of another part.

Can't comment on the multithread though. May need to use some sync objects to ensure that commands stay well-ordered.