Rendering in Retrospect · #8 of 12
Rendering Under Tight Budgets: Small Devices, Big Constraints
Retrospective — written in 2026, looking back.
On a large machine, rendering budgets feel abstract. There is headroom, and headroom forgives. On a small device — a handheld, a battery-powered prototype board, a modest integrated GPU in a thin laptop — every budget is physical, immediate, and connected to every other budget. Spend power and you make heat; make heat and the device slows itself down; slow down and the frame you budgeted for is no longer the frame you get. This post is about what building and testing small personal prototypes under those conditions taught me about rendering as an exercise in constraint management. Everything here is general engineering: the constraints belong to physics and arithmetic, not to any particular product.
The Frame Budget Is an Energy Budget
The usual way to state a frame target is in milliseconds — at 60 frames per second, each frame gets about 16.7 milliseconds. On a plugged-in machine that framing is adequate. On a battery-powered device it is incomplete, because the real currency is not time but energy:
Energy per frame ≈ average power draw × frame time
Sustaining a frame rate means sustaining a power draw, and a small device can only sustain a limited power draw before its temperature reaches the point where the system protects itself by throttling — reducing clock speeds, which reduces the very performance the budget assumed. This creates the defining dynamic of tight-budget rendering: peak performance and sustained performance are different numbers, and only the sustained one is real for anything longer than a short burst.
I learned to feel this in prototype testing by simply running a scene for a long time instead of a short one. A demo that holds its frame rate for thirty seconds and degrades over ten minutes is not a demo that holds its frame rate. Long soak tests, on the actual small hardware, with the device unplugged and at a realistic ambient temperature, are the only honest measurement — and they routinely contradict the quick benchmark that came before them. Designing to a thermal ceiling also inverts some instincts: a technique that is slightly slower per frame but draws notably less power can deliver more sustained performance, because it never triggers the throttle that the faster, hotter technique provokes.
Fill Rate and Bandwidth: The Two Hard Walls
Small GPUs are rarely limited first by arithmetic. They are limited by how many pixels they can touch and how much data they can move, because both scale with hardware that small devices have little of.
Fill rate is the cost of writing and blending pixels. Its arithmetic is merciless and easy to compute. The pixels shaded per second are roughly:
pixels/sec ≈ resolution × frame rate × average overdraw
Every term is a lever. Resolution enters linearly per dimension, so it enters quadratically overall — a modest step down in each dimension removes a surprisingly large fraction of the pixels. Overdraw — transparent layers, particles, large blended quads stacked on the same pixels — multiplies whatever resolution you chose. On a big machine an overdraw factor that doubles pixel work is a shrug; on a small device it can be the entire budget.
Memory bandwidth is the second wall, and it compounds the first. Every pixel written to a framebuffer, every texture sampled, every intermediate render target read back is traffic across a memory system that, on small devices, is shared between CPU and GPU and sized for frugality. This is why multi-pass rendering gets expensive so fast in this world: each intermediate target is written and re-read at full bandwidth cost, and tile-based mobile architectures — which keep a tile of the framebuffer in fast on-chip memory precisely to avoid that traffic — penalize designs that force the tile to be flushed to main memory mid-frame. The general principle travels well beyond any one architecture: data movement is a cost on the same footing as computation, and on small devices it is usually the larger one.
Resolution Scaling: The Honest Dial
Given the equations above, the most effective single lever under a tight budget is render resolution, and the modern form of it is dynamic resolution scaling: render the 3D scene to a target smaller than the display, upscale it for presentation, and adjust the scale continuously to hold the frame target.
// Illustrative control loop — adjust scale toward the frame target,
// in small steps, with clamps so quality stays in a sane range.
if (frameTimeAvg > targetTime) scale = max(scale * 0.95f, minScale);
else if (frameTimeAvg < targetTime * 0.9f)
scale = min(scale * 1.02f, 1.0f);
renderScene(resolution * scale); // 3D pass at scaled resolution
upscaleAndCompositeUI(); // UI stays at native resolution
A few design points make this respectable rather than desperate. Text and UI are rendered at native resolution after the upscale, so the image parts the eye judges most harshly stay crisp. The scale moves in small steps with some hysteresis, because a resolution that visibly pumps up and down every frame is worse than a slightly lower stable one. And the floor matters: below some scale the image degrades enough that reducing other costs — overdraw, pass count, texture sizes — is the better trade. Dynamic resolution is a dial for absorbing variance (a busy moment, a warm device), not a substitute for a scene that fits its budget at a reasonable scale.
Foveation: Spending Pixels Where Eyes Look
Foveated rendering starts from a fact about vision rather than hardware: human acuity is high only in a small central region of the visual field and falls off steeply toward the periphery. If a display system knows where the viewer is looking — or, in fixed foveation, can assume the center of the display is where attention lives — it can render the periphery at lower resolution and spend the saved pixels nowhere at all. The saving is the point.
Even without eye tracking, the concept shaped how I think about small-device budgets in my prototypes. It is the general principle of non-uniform effort: pixel cost does not have to be uniform across the image, texture detail does not have to be uniform across a surface, and update rates do not have to be uniform across a scene. Distant, peripheral, and slow-moving content can all be rendered more cheaply than the focal point, and a budget-constrained renderer is largely the art of deciding, systematically, what gets less. Variable-rate shading — shading blocks of pixels at different rates across the frame — is the same idea expressed in hardware terms.
The caution is equally general: these techniques trade against artifacts at the boundaries, and the viewer's sensitivity to those artifacts varies with content and motion. A foveation scheme, like a resolution scale, needs a conservative floor set by looking at the worst case, not the average one.
A Budget Is a System, Not a Checklist
The mistake I made early in small-device experiments was treating each constraint as a separate problem: fix the thermals, then the fill rate, then the battery life. They are one problem. A scene that shades fewer pixels moves less data, draws less power, generates less heat, throttles later or never, and lasts longer on battery — a single improvement cascading through every budget at once. The reverse cascade is just as real, which is why one "small" addition — one more fullscreen pass, one more layer of transparency — can degrade a small-device build out of all proportion to its size.
So the working method I settled on is boring and effective. Define the budgets numerically before optimizing: a sustained frame target, a resolution floor, a memory ceiling, a session length the device must survive without throttling. Test on the smallest hardware, unplugged, for a long time, at the worst scene you have — not the average one. Reach for the structural levers first (resolution, overdraw, pass count, data movement) before micro-optimizing shaders, because the structural terms are the ones in the equations. And treat every technique — scaling, foveation, non-uniform effort of any kind — as a trade with a floor, chosen deliberately, not a free win.
Tight budgets, I have come to think, are not an unfortunate special case of rendering. They are rendering with the forgiveness removed. The same costs exist on the largest machine; they are simply easier to ignore there. Learning to see them on a small device — where physics sends the bill immediately — made every renderer I have built since more honest, wherever it runs.