Back to Tech Blog

Draw Calls: What They Actually Are and Why Everyone Tells You to Reduce Them

Draw calls — CPU to GPU rendering pipeline

You've heard it a thousand times: reduce your draw calls. It's handed out like universal advice in every optimization conversation. But most people saying it couldn't tell you what a draw call actually is at the hardware level — or why reducing them matters, and when it doesn't.

This post fixes that.

What Is a Draw Call

A draw call is a command the CPU sends to the GPU telling it to render something.

Every time the CPU says "hey GPU, draw this mesh with this material using these settings" — that's one draw call. The GPU then executes it: it reads the vertex data, runs the vertex shader, rasterizes the triangles, runs the pixel shader, and writes the result to the render target.

The GPU is extremely good at doing this work. The problem is never the GPU doing the actual rendering. The problem is the CPU setting up for it.

Why Draw Calls Are a CPU Problem, Not a GPU Problem

This is the part most people get wrong.

Before the GPU can render anything, the CPU has to:

  • Bind the vertex buffer
  • Bind the index buffer
  • Set the shader
  • Upload shader constants (transform matrices, material parameters)
  • Set render state (blend mode, depth test, etc.)
  • Issue the actual draw command

All of that has to happen every single draw call, every single frame, on the CPU. And the GPU has to wait until the CPU is done setting up before it can start rendering.

At 60fps you have roughly 16.6ms per frame. If your CPU spends 12ms just issuing draw calls, you have almost nothing left for game logic, physics, or anything else — even if your GPU is only at 40% utilization.

This is why you can have a GPU that's barely working and still tank your frame rate. The bottleneck is the CPU feeding the GPU, not the GPU doing the work.

What Generates a Draw Call in UE5

Each of the following is typically one draw call:

  • Each static mesh component with a unique material
  • Each skeletal mesh (plus extra per-section if it has multiple materials)
  • Each dynamic shadow — in legacy shadow maps, a depth pass per light per mesh. In UE5's default Virtual Shadow Maps, only dirty pages re-render, so static geometry is cached and only dynamic objects invalidate their shadow pages each frame.
  • Each translucent object (rendered in a separate pass, no batching)
  • Each decal
  • Each particle emitter (depending on renderer type)

The key factor isn't really the mesh — it's the material state change. Two meshes using the exact same material instance can sometimes be batched together. Two meshes using different materials always generate separate draw calls.

How to Actually Measure Draw Calls in UE5

Open the console and type:

stat RHI

This gives you DrawPrimitive calls — the draw call count for non-Nanite geometry per frame. Note that Nanite geometry bypasses the traditional draw call path and won't show up here, so this stat tells part of the story, not all of it.

As for thresholds: Epic's official documentation puts the mobile limit at 700 draw calls or fewer for mid-range devices, and 500 or fewer on lower-end hardware. Console is more forgiving, but no single number applies — it depends on the target platform, frame rate target, and shader complexity. Profile on your actual hardware.

Also useful:

stat InitViews

This shows Visible Static Mesh Elements and Visible Dynamic Primitives separately — far more diagnostic than stat SceneRendering for understanding what's driving your draw call count. For a full per-pass breakdown, use the GPU Visualizer (profilegpu in console, or Ctrl+Shift+, in editor).

How to Reduce Draw Calls in UE5

1. Instanced Static Meshes (ISM / HISM)

If you have the same mesh appearing many times in the scene — rocks, trees, fence posts — use Instanced Static Mesh components instead of individual static mesh actors. All instances of the same mesh + material are batched using GPU instancing, collapsing what would be hundreds of draw calls down to very few.

One caveat: ISM uses a single bounding box for the entire component. If any part of it is in the camera frustum, all instances render — even those out of view. For large-scale foliage or anything spanning a wide area, use Hierarchical Instanced Static Mesh (HISM) instead. HISM adds a spatial hierarchy for per-cluster frustum culling, so only visible clusters issue draw calls. It may still produce multiple draw calls, but far fewer than individual actors.

2. Merge Actors

UE5's Merge Actors tool (under Window → Developer Tools) combines multiple static meshes into a single mesh with a single material. One mesh, one draw call. Useful for environmental clutter that never changes.

Trade-off: merged meshes lose individual culling, so a large merged mesh may render even when only a small part of it is visible.

3. Nanite

For opaque static geometry, Nanite eliminates the traditional draw call concern. Nanite's culling operates at the cluster level rather than the object level, and its rendering path bypasses the standard draw call pipeline entirely. For hero props and environment geometry, it's the most effective single change you can make.

That said, Nanite has a meaningful list of limitations. It does not support:

  • Translucent or fully masked materials
  • Skeletal meshes or animated geometry (partial support in UE5.5, but not general)
  • Materials using World Position Offset (WPO) — these fall back to traditional draw calls in shadow passes
  • Foliage, grass, hair, or aggregate geometry that benefits from traditional instancing
  • Forward rendering, VR, split-screen, or MSAA targets

All non-Nanite assets — translucency, skeletal meshes, WPO materials — still generate standard draw calls. And even with Nanite, the bottleneck doesn't disappear: it shifts to shading bins, where each distinct material permutation becomes its own cost. A scene full of unique Nanite materials still suffers, just differently.

4. Keep Materials Consistent

Two meshes sharing the same material instance can be batched. Two meshes with different material instances cannot — even if the materials are nearly identical.

Where possible, use material parameters to vary appearance rather than creating separate material instances. A single master material with a few parameter tweaks is always cheaper than multiple distinct materials.

5. Cull Aggressively

A draw call that never gets issued is the cheapest draw call. Use:

  • Cull Distance Volumes to stop rendering small objects at distance
  • Occlusion Culling (enabled by default, but verify it's working in dense interior scenes)
  • Level of Detail (LOD) to reduce mesh complexity at distance, which also helps batching

The Number That Actually Matters

Draw call counts are a symptom, not a root cause. The real question is always: is my game CPU-bound or GPU-bound?

If your GPU utilization is low and your frame time is high, you're likely CPU-bound — and draw calls are a probable cause. If your GPU is pegged at 99% and your CPU is comfortable, reducing draw calls won't help. You have a different problem entirely.

Profile first. Optimize what the data tells you to optimize.


Concept What to Remember
Draw call CPU command to render one object with one material
Why it hurts CPU overhead, not GPU rendering cost
Measure with stat RHI, stat InitViews, GPU Visualizer
Reduce with ISM/HISM, Nanite, material consistency, culling
Real question Am I CPU-bound or GPU-bound?

Next up: textures are one of the biggest contributors to draw call overhead — and there are three very different solutions to that problem. That's a full post on its own.


Found this useful? Share it:


Giuseppe Boschiero

Giuseppe Boschiero

Principal Technical Artist with 8 years across computer graphics, 3D art, and tech art — specialising in Unreal Engine 4 and 5. Shaders, VFX, tools, and optimization.