Rewrite TripleBuffer as a true lockless, flipping, triple buffer #6319
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
What made me do this is over the last couple of days I encountered an assert in song select using a debug o!f:
It can be repro'ed via:
Which is pretty scary. Either one of the two asserts in
getPendingReadBuffer()
can trigger. We've also been seeing some intermittent CI failures though I can't point to one immediately (happens once in a blue moon), likely related to this.Separately from the above, I became unconvinced of the existing implementation while reading through the code. As for the immediate issue above, I can't figure out why it's happening, but even more - I've been saying for a long time now that I want
TripleBuffer
to evenly distribute occupancy across all buffers. I wrote a test (TestSceneTripleBufferOccupancy
) to test this and found that the existing implementation breaks down almost as soon as both producers/consumers aren't running at absolute unlimited rate:So instead of fumbling around with the existing implementation, I chose to reimplement it hopefully following the existing principles of triple buffering in graphics: a front/back buffer with an intermediate flip buffer.
The write buffer is flipped onto the flip buffer after the write completes, and the flip buffer is flipped onto the read buffer when a read is requested. This is also completely lockless now, compared to the current implementation which locks between the two threads.
Note that this is a custom implementation so I'm not sure if this is exactly how this is supposed to be implemented, but it makes sense in my head and seems to work in practice, so... /shrug?