Source: https://shadowfrag.com/blog/vulkan-and-the-input-loop/

# A fast frame is only half the story

By the SHADOWFRAG developer · Engineering · Oct 21, 2026 · 3 min read

Drawing a frame quickly does not tell me how long an action waited to be processed. I separated those jobs, then measured a smaller rendering change on its own.

[Windwalk, captured in SHADOWFRAG's Vulkan renderer](https://shadowfrag.com/_astro/596fd351983109da6bdd27e7af66ba7e82461d7b0a7893435a5dd780c9c4fd16.CkS-VCfX.png)

Actual engine render · Development build · 22 October 2026

A frame can finish quickly even though the player's latest action spent time waiting behind it. During the [Vulkan](https://shadowfrag.com/glossary/#term-vulkan) rendering work, I needed to account for both. Waiting for the display, or waiting to enforce a frame-rate cap, should not also hold up input processing and incoming server results.

I gave that work its own service. It reads input, predicts the player's movement and consumes the server's results independently of drawing. The renderer receives completed [snapshots](https://shadowfrag.com/glossary/#term-snapshot) of that work, which it can read but cannot change.

A shot also needs a stable reference to the world it was aimed at. The timing rules select that scene reference and then lock it; a newer rendered frame cannot quietly replace it afterward. For a rail shot, the server checks both the historical scene and the position the player was allowed to fire from. Keeping the aim attached to the right scene matters even when displaying the next frame has to wait.

## Removing an unnecessary rendering step

The October 21 optimization addressed a separate cost. At [native resolution](https://shadowfrag.com/glossary/#term-native-resolution), with the [FXAA](https://shadowfrag.com/glossary/#term-fxaa) [edge-smoothing filter](https://shadowfrag.com/glossary/#term-fxaa) disabled, I could draw the scene directly. There was no need to first draw it into an intermediate image and then combine that image into the full screen when neither scaling nor that filter was required. [Scaled scenes](https://shadowfrag.com/glossary/#term-native-resolution), previews and [FXAA](https://shadowfrag.com/glossary/#term-fxaa) still use their intermediate rendering targets.

I compared the two paths with the same eight-player Windwalk test scene at **3440 × 1440**. The mean time to complete a frame fell from **1.554 ms to 1.419 ms**, a reduction of about **8.7%**. Crowded scenes at 1080p showed much smaller changes. Keeping those results together shows where the optimization helped and where it made little difference.

This [benchmark](https://shadowfrag.com/glossary/#term-benchmark) draws a fixed scene and waits for the [graphics processor](https://shadowfrag.com/glossary/#term-gpu) to finish. It does not run live input, the [heads-up display](https://shadowfrag.com/glossary/#term-hud), audio or networking. Dividing a second by its [frame time](https://shadowfrag.com/glossary/#term-frame-time) would produce a number, but that number would not be a measured live-game [frame rate](https://shadowfrag.com/glossary/#term-frames-per-second). It would not tell us how long a physical mouse movement takes to reach the display either.

## Checking the response path separately

I checked native builds with rendering capped and uncapped, both implementations of the [QUIC](https://shadowfrag.com/glossary/#term-quic) network [transport](https://shadowfrag.com/glossary/#term-transport-backend), delayed service work, and renderer startup and shutdown behavior. Broader tests of hardware input events, display timing and Internet conditions remained separate work.

The rendering comparison tells me that one scene became cheaper to draw. The input work addresses a different requirement: processing an action against the correct state of the fight while presentation continues at its own pace. [The netcode page](https://shadowfrag.com/netcode/) follows that path and the evidence behind it.

[Back to blog](https://shadowfrag.com/blog/)[Browse the glossary](https://shadowfrag.com/glossary/)

## Request an _invite code._

SHADOWFRAG is opening by invitation. Request a code and receive development updates. [Shadow Council](https://shadowfrag.com/glossary/#term-shadow-council) contributors receive priority when invitations begin.

Enable JavaScript to request an invite code and confirm your email address.

Email confirmation required. Codes will be issued later; a request does not guarantee access. Unsubscribe at any time. [Privacy](https://shadowfrag.com/privacy/)

Confirm your email to join the invitation list. Codes will be issued in a future round; a request does not guarantee access. Unsubscribe at any time.

Anyone can request a code. For [Shadow Council](https://shadowfrag.com/shadow-council/) priority, introduce yourself on Discord with your role, experience, region and time zone. Include examples of your maps or content if you have them.

[Join Discord](https://discord.gg/EHj7rZDNj)
