Skip to content
daniel@cosenza:~/blog
RetrogamingDeep Dive June 22, 2026 3 min read

Controller Input Latency: Tracing the Path From Button to Pixel

The time between pressing a button and seeing the result on screen passes through more stages than most players realize — and emulation adds a few of its own on top of the ones a real console already had.

“Input lag” gets treated as one number, but it’s really the sum of several independent delays stacked in sequence — each one small, each one real, and each one an emulator setup has at least some ability to influence.

The full chain, stage by stage

button press

   ▼  controller polling interval
   │  (how often the controller reports its state — USB polls
   │   at a fixed rate; wireless/Bluetooth adds its own delay)
   ▼  OS input stack
   │  (buffering and processing before an application ever sees the event)
   ▼  emulator core: this frame or next?
   │  (if the poll lands after this frame's input read, it waits
   │   a full frame before it's even seen)
   ▼  core simulation
   │  (the emulated game logic processes the input)
   ▼  video output buffering
   │  (double or triple buffering delays a completed frame's
   │   actual display by one or more additional frames)
   ▼  display panel response + processing
      (pixel response time, plus any post-processing the
       display itself applies — upscaling, motion smoothing)


visible result on screen

Every stage adds real, measurable time, and the stages compound — a setup with several small delays stacked back to back can add up to something clearly noticeable, even if no single stage looks bad in isolation.

Where emulation adds delay a real console didn’t have

A real, original console has most of this chain too — controller polling and display response time are physical realities regardless of platform — but emulation introduces its own additional links: the host OS’s input stack sits between the controller and the emulator core in a way the original hardware’s dedicated controller port never did, and video output typically passes through an extra buffering/compositing layer (the host OS’s window manager or display server) that the console’s direct video-out signal path didn’t have to cross.

Run-ahead: borrowing the rollback-netcode trick, applied locally

Run-ahead is a technique built directly on the same mechanism as rollback netcode, but solving latency within a single machine instead of across a network: the core simulates a few frames ahead of what’s actually displayed, using input that hasn’t been read yet as its best guess (typically “assume no new input”), and — if a real button press turns out to land in that window — rolls back to a saved state and re-simulates using the true input, discarding the guessed frames. Because several frames of simulation happen “invisibly” ahead of what’s shown, the frame the player actually sees reflects their input sooner than a naive one-frame-at-a-time pipeline would allow. Like rollback netcode, this depends entirely on fast, deterministic save-state serialization — an emulator core has to be able to save, resimulate, and discard several frames’ worth of state well within a single frame’s time budget for run-ahead to help rather than hurt.

What’s actually adjustable in practice

Of the whole chain, an emulator setup typically has direct control over: which buffering mode the video output uses (single/double/triple — fewer buffers means less inherent delay, at higher risk of visible tearing without it), whether run-ahead is enabled (and how many frames deep), and audio/video sync settings that can otherwise silently add a frame or more of latency to keep audio and video aligned. Controller polling rate and display response time are hardware properties outside the emulator’s control entirely — which is why serious low-latency setups pay attention to both the software configuration and the physical controller and display being used, since neither one alone determines the final result.