Opengl Unsynchronized / Non-blocking Map

I just found the following OpenGL specification for ARB_map_buffer_range .

I am wondering if it is possible to make non-blocking card calls with this extension?

Currently in my application im rendering for FBO, which I then map to the host PBO buffer.

 glMapBuffer(target_, GL_READ_ONLY); 

However, the problem is that it blocks the rendering stream during data transfer.

I could reduce this problem by pipelining the rendering, but latency is a big problem in my application.

My question is, can I use map_buffer_range with MAP_UNSYNCHRONIZED_BIT and wait for the map operation to finish in another thread or to delay the map operation in the same thread while the rendering stream displays the next frame.

eg.

 thread 1: map(); render_next_frame(); thread 2: wait_for_map 

or

 thread 1: map(); while(!is_map_ready()) do_some_rendering_for_next_frame(); 

That I am not sure how I know when a card operation is ready, the specification only mentions “other synchronization methods to ensure proper operation”.

Any ideas?

+6
source share
2 answers

In the general case, it is impossible to make a "non-blocking card", but you can display it without blocking.

The reason that there can be no "non-blocking card" is that at the moment when the function call returns, you can access the data, so the driver must make sure that he is there, positively. If the data has not been transferred, what else can the driver do, but block.
Threads don't do it better, and maybe make it worse (adding synchronization and context issues). Threads cannot magically remove the need for data transfer.

And this leads to how not to block the display: only the card when you are sure that the transfer is complete. One safe way to do this is to display the buffer after flipping the buffers or after glFinish or after waiting for the request / fencing object. Using a fence is the preferred method if you cannot wait for the buffers to be replaced. The fence will not stop the pipeline, but will tell you if your transfer will be completed ( glFinish may or may not, but will probably stop). Reading after replacing buffers is also 100% safe, but it may not be acceptable if you need data in the same frame (works great for screenshots or for calculating a histogram for creating tones).

A less secure way is to insert “some other things” and hope that the transfer is complete at this time.


Regarding the following comment:
This answer is not incorrect. It is impossible to do better than access to data after its availability (this should be obvious). This means that you have to synchronize / block, anyway, there is no choice.
Although from a very pedantic point of view, you can, of course, use GL_MAP_UNSYNCHRONIZED_BIT to get a non-blocking map operation, it does not matter at all, since it does not work unless you explicitly reproduce implicit synchronization, as described above. A display that you cannot safely receive is unsuitable.

Matching and accessing the buffer that OpenGL passes data without synchronization / blocking (implicitly or explicitly) means "undefined behavior", which is only a more pleasant formulation for "probably garbage results, maybe a crash."
If, on the other hand, you are explicitly synchronizing (say, with a fence, as described above), then it does not matter if you use the unsynchronized flag, since in any case you no longer need implicit synchronization.

+5
source

If you map the buffer to GL_MAP_UNSYNCHRONIZED_BIT , the driver will not wait until OpenGL completes with this memory before displaying it for you. Thus, you will get more or less direct access to it.

The problem is that this does not mean that you can just read and write this memory perforce. If OpenGL reads or writes this buffer, and you change it ... welcome to undefined behavior. Which may include a failure.

Therefore, in order to actually use unsynchronized mapping, you must synchronize your behavior with the OpenGL access of this buffer. This will be due to the use of ARB_sync objects (or NV_fence, if you are only on NVIDIA and have not updated your drivers recently).

However, if you use a fence object to synchronize access to the buffer, you really do not need GL_MAP_UNSYNCHRONIZED_BIT at all. As soon as you finish the fence or find that it is completed, you can display the buffer normally and it should finish immediately (except when another operation is also being read / written).

In general, unsynchronized access is best used when you need fine-grained write access to the buffer. In this case, a good use of the synchronization objects will give you what you really need (the ability to indicate when the card operation is completed).


Application: the above is deprecated (depending on your equipment). Thanks to OpenGL 4.4 / ARB_buffer_storage, now you can not only display unsynchronized information, you can save the displayed buffer indefinitely. Yes, you can have a buffer displayed while using it.

This is done by creating an immutable storage and providing this storage (among other things) GL_MAP_PERSISTENT_BIT . Then you glMapBufferRange , also providing the same bit.

Now, technically, it practically does not change anything. You still need to sync your actions with OpenGL. If you are writing material to the buffer region, you need to either issue a barrier or explicitly disable this buffer region . And if you are reading, you still need to use the fence synchronization object to make sure that the data is actually there before it is read (and if you use GL_MAP_COHERENT_BIT too, you will need to issue a barrier before reading).

+5
source

Source: https://habr.com/ru/post/894442/


All Articles