Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OpenGL: glClientWaitSync on separate thread

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?

like image 398
matthias_buehlmann Avatar asked Oct 31 '22 15:10

matthias_buehlmann


1 Answers

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.

like image 69
Jan Rüegg Avatar answered Nov 15 '22 07:11

Jan Rüegg