Double Buffer

Intent: Cause a series of sequential operations to appear instantaneous or simultaneous.

Acron Mapping

Context

Acron approach

Rendering (primary use)

Acron’s renderer already double-buffers the display — handled automatically

Render-to-texture

base.win.makeTextureBuffer() — write a scene to an off-screen buffer, swap by updating a texture

Game state (logic)

Two Python dicts/lists; write to “back”, swap at end of frame

You almost never need to implement rendering double-buffering manually. Focus on game-state double-buffering when read and write must not interleave within a frame (e.g., cellular automata, simultaneous AI moves in a strategy game).

How to Implement (game-state double buffer)

  1. Maintain two state containers: _front (read-only this frame) and _back (write-only this frame).

  2. At the start of each frame, game logic reads from _front.

  3. All writes go to _back.

  4. At the end of the frame task, swap: self._front, self._back = self._back, self._front.

Code Sketch (Python) — game-state double buffer

class BattleGrid:
    def __init__(self, w, h):
        self._w, self._h = w, h
        self._front = [[None] * w for _ in range(h)]
        self._back  = [[None] * w for _ in range(h)]
        taskMgr.add(self._tick, 'gridTick', sort=5)

    def get(self, x, y):
        return self._front[y][x]

    def set(self, x, y, value):
        self._back[y][x] = value

    def _tick(self, task):
        self._simulate()                              # writes to _back
        self._front, self._back = self._back, self._front  # swap
        self._clear_back()                            # prepare for next frame
        return task.cont

    def _simulate(self):
        for y in range(self._h):
            for x in range(self._w):
                cell = self.get(x, y)                # reads _front
                if cell:
                    self.set(x, y + 1, cell)         # writes _back

    def _clear_back(self):
        for row in self._back:
            row[:] = [None] * self._w

Code Sketch (Python) — render-to-texture ping-pong

# Two off-screen buffers for post-processing ping-pong
buf_a = base.win.makeTextureBuffer('bufA', 512, 512)
buf_b = base.win.makeTextureBuffer('bufB', 512, 512)
tex_a = buf_a.getTexture()
tex_b = buf_b.getTexture()

# Render scene to buf_a, apply shader reading tex_a into buf_b, display tex_b

Pitfalls

  • Don’t double-buffer NodePath positions: Acron’s scene graph updates are already safe within a single-threaded frame. Double-buffering positions adds overhead for no benefit unless you use task chains (threads).

  • Swap timing: swap must happen after all reads and writes for the frame are complete. Place the swap at the end of a high-sort task (sort=40, just before the render task at sort=50).

  • Memory: two full copies of large state arrays double memory usage. Only double-buffer state that is actually read and written within the same frame.