luciusDXL / TheForceEngine

Modern "Jedi Engine" replacement supporting Dark Forces, mods, and in the future Outlaws.
https://TheForceEngine.github.io
GNU General Public License v2.0
976 stars 71 forks source link

Add glFinish() before buffer swap #413

Closed JakeSmarter closed 4 months ago

JakeSmarter commented 4 months ago

Just for the sake of completeness (SDL_GL_SwapWindow() does not call glFinish() for you). In my understanding, OpenGL commands are latently asynchronous by design but please correct if I am wrong. So far, I have not come across any visible negative side effects because of glFinish() being absent on SoC (CPU and GPU integrated) systems but could imagine on systems with dedicated GPUs.

mlauss2 commented 4 months ago

From Khronos: glFinish does not return until the effects of all previously called GL commands are complete. Such effects include all changes to GL state, all changes to connection state, and all changes to the frame buffer contents.

It blocks the CPU until GPU has finished rendering. That time could be used to prepare the next frame.

glFinish requires a round trip to the server. also a perf killer.

JakeSmarter commented 4 months ago

It blocks the CPU until GPU has finished rendering. That time could be used to prepare the next frame.

That’s right. However, how do know when rendering has finished before you swap buffers? Note that swapping buffers is not a GL command and therefor does not go into the GL command queue but is an OS function with immediate effects on the GL context. Hence, in my understanding every frame needs to synchronize with the CPU at some point in time, unless you are absolutely sure that the GPU is always going to be ahead of the CPU. Unfortunately, due to OpenGL’s design and because other apps can stall the GPU, you cannot be sure of that. Again, unless you know for sure the CPU speed, GPU speed, and that the GPU has not been stalled by other apps, you cannot avoid using glFinish(). Usually, a natural point to synchronize would be right before buffer swap or after all drawing commands for the frame have been issued.

glFinish requires a round trip to the server. also a perf killer.

It is a synchronization tool, not a GL command to “kill perf”. :wink:

mlauss2 commented 4 months ago

It blocks the CPU until GPU has finished rendering. That time could be used to prepare the next frame.

That’s right. However, how do know when rendering has finished before you swap buffers? Note that

I think SDL (at least glXSwapInterval()) will do a glFlush() when you call SDL_SwapBuffers(), which works like glFinish() but the app can immediately start submitting new GL commands (which only take effect after the buffer swap has completed).

glFinish requires a round trip to the server. also a perf killer.

It is a synchronization tool, not a GL command to “kill perf”. 😉

I think even if there is nothing to do/render, it will take comparatively large amount of time.

JakeSmarter commented 4 months ago

Excerpt from glxswapbuffers man page:

glXSwapBuffers performs an implicit glFlush before it returns. Subsequent OpenGL commands may be issued immediately after calling glXSwapBuffers, but are not executed until the buffer exchange is completed.

Alright, so it looks like glXSwapBuffers() basically puts itself on the GL command queue. However, Windows’ SwapBuffers() description is not as conclusive as glXSwapBuffer()’s but potentially equivalent in behavior when issuing GL commands on a single thread. Apparently, SwapBuffers() behaves the same way as glXSwapBuffers() when issuing GL commands on mutiple threads:

With multithread applications, flush the drawing commands in any other threads drawing to the same window before calling SwapBuffers.

Close #413.