Skip to content

Instantly share code, notes, and snippets.

@mthuurne
Last active December 20, 2019 14:39
Show Gist options
  • Save mthuurne/203dbb74d0959ff0a461e6cae27be32e to your computer and use it in GitHub Desktop.
Save mthuurne/203dbb74d0959ff0a461e6cae27be32e to your computer and use it in GitHub Desktop.
Rotating framebuffers

Goals:

  • support vsynced double and triple buffering
  • zero buffer copies

User space execution flow:

  1. acquire buffer handle (can block if none is available yet)
  2. map buffer into virtual memory region
  3. draw into buffer
  4. unmap buffer
  5. queue buffer for display

Kernel execution flow:

  1. scanout current foreground buffer
  2. at end of frame, if no new buffer is queued, repeat same buffer (goto 1)
  3. new buffer becomes the foreground buffer
  4. the previous foreground buffer becomes available to be acquired by user space

Buffer states:

  1. waiting for scanout: 0-2 buffers
  2. currently being scanned: 1 buffer
  3. waiting to be acquired by user space: 0-2 buffers
  4. owned by user space: 0-1 buffers

The total number of buffers is 2 for double buffering and 3 for triple buffering. The mechanism would work with more than 3 buffers, but you'd be adding latency then with no clear benefit.

A buffer is put into "waiting for scanout" when user space hands it back to the kernel; this operation doesn't block. A buffer is put into "waiting to be acquired" on the vblank interrupt, assuming a new buffer was waiting to replace it as the front buffer.

Notes on buffer mapping:

  • the buffer can be mapped into user space virtual memory with any cache setting
  • cache flush happens on unmap
  • mapping could use a huge page, so it needs fewer TLB entries
  • the buffer doesn't need to be mapped while it's owned by the kernel, since we only DMA from it
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment