I am using glMapBufferRange with the GL_MAP_UNSYNCHRONIZED_BIT to map a buffer object. I then pass the returned pointer to a worker thread to compute the new vertices asynchronously. The Object is doubly buffered so I can render one object while the other is written to. Using GL_MAP_UNSYNCHRONIZED_BIT gives me significantly better performance (mainly because glUnmapBuffer returns sooner), but I am getting some visual artifacts (despite the double buffering) - so I assume either the GPU starts rendering while the DMA upload is still in progress, or the worker thread starts writing to the vertices too early. If I understand glFenceSync, glWaitSync and glClientWaitSync correctly, then I am supposed to address these issues in the following way:
A: avoid having the GPU render the buffer object before the DMA process completed: directly after glUnmapBufferRange, call on the main thread
GLsync uploadSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
glFlush();
glWaitSync(uploadSync, 0, GL_TIMEOUT_IGNORED);
B: avoid writing to the buffer from the worker thread before the GPU has finished rendering it: direclty after glDrawElements, call on the main thread
GLsync renderSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
and on the worker thread, right before starting to write data to the pointer that has previously been returned from glMapBufferRange
glClientWaitSync(renderSync,0,100000000);
...start writing to the mapped pointer
1: Is my approach to the explicit syncing correct?
2: How can I handle the second case? I want to wait in the worker thread (I don't want to make my main thread stall), but I cannot issue glCommands from the worker thread. Is there another way to check if the GLsync has been signalled other than the gl call?
What you could do is create an OpenGL context in the worker thread, and then share it with the main thread. Next:
Run on the main thread:
GLsync renderSync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); glFlush();
then
Run on the worker thread:
glClientWaitSync(renderSync,0,100000000);
The glFlush
on the main thread is important, since otherwise you could have an infinite wait. See also the OpenGL docs:
4.1.2 Signaling
Footnote 3: The simple flushing behavior defined by SYNC_FLUSH_COMMANDS_BIT will not help when waiting for a fence command issued in another context’s command stream to complete. Applications which block on a fence sync object must take additional steps to assure that the context from which the corresponding fence command was issued has flushed that command to the graphics pipeline.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With