Busy wait on Vsync with multiple draw calls per frame
Glium seems to be exhibiting some strange flushing/waiting-related behavior if draw() is called more than once. Glium ends up busy-waiting on Vsync rather than allowing the drivers and application to sleep wait until the next frame. This results in high CPU usage even if very few objects are drawn on-screen.
How to reproduce: Run keeshond example "doggymark" and spawn more than 8192 doggos. Notice that the average ms for "draw" jumps considerably. It should instead climb very gradually as more and more doggos are spawned.
I did not have this issue on the previous OpenGL library I used (gfx pre-ll).
@cosmicchipsocket what's keeshond?
Keeshond is my game library: https://crates.io/crates/keeshond
Could be an issue with my own code, but either way it's something I do want to fix.
Almost forgot my system specs.
nVidia GeForce GTX 1060 nVidia binary drivers on Linux (435.21) glium 0.23
IDK maybe there is busy wait code in glium. I'm not familiar enough with it to find it. If you can find it and fix it, PRs welcome. It's also possible that your game engine is spawning too many draw calls.
I batch the draws so that up to 8192 sprites are drawn in one call. That's why drawing more than 8192 doggos causes the issue. Just two draw calls is enough.
Note that this issue doesn't impact graphics performance, only energy efficiency.
Is there a glium chat somewhere so I can work with the current maintainers on this? I'm not familiar with queueing/sync in OpenGL but I'll see what I can do.
I'm not a full maintainer, only doing basic tasks, trying to fix the simple things & keeping the lights on. Except for me, there is nobody. It's a bit sad atm. If you are interested in becoming a maintainer, you can ask tomaka e.g. via e-mail.
So I poked at this a bit. It's not the Frame::draw() that's causing the busy wait but the call to VertexBuffer::write(). Specifically, it's the second call to VertexBuffer::write() on any given frame. The first one doesn't wait. Neither does the third call, or any call afterward for the current frame. It's always the second one. It seems like the access to the VertexBuffer is causing some sort of flush, which is somehow flushing the Vsync wait later than it should.
The VertexBuffer is being created with VertexBuffer::empty_dynamic(). I invalidate and reuse the buffer each time I do another batch. Is this bad practice? And is there a way to 100% ensure that the vertical blank wait is flushed? I'm not even using triple buffering (it's not enabled in the Xorg driver config), but somehow it seems to be getting delayed.
Also, if VertexBuffer::write() is only called once for the instance buffer in a given frame, the busy wait does not occur, which seems to imply that there's some kind of locking/flushing that doesn't actually need to happen.
A minimal reproducible example would help
I recently modified my code so that there are multiple vertex buffers it cycles between for each draw, and this seems to have fixed the issue for me. I'm guessing that the buffer is still in use somehow during the Vsync wait. Might not actually be a glium issue.