<p>If by bundles you mean secondary command buffers, I think the answer is that people generally don't use them, or at least not in the sense you mean. They might be used to parallelize command recording across threads, but not to reduce draw-call-related overhead because, as you mention, the set of things to be drawn in a frame changes constantly, due to both frustum/occlusion and also LOD switching, as well as any moving objects or other changes that may be happening in the rendered world.</p>
<p>There are other ways to address draw-call overhead, including:</p>
<ul>
<li>Pull together vertex and index buffers for different objects into larger buffers, so you're not constantly having to switch between buffers. You can issue draw calls with the starting vertex offset and index offset parameters to draw a subset of vertices/triangles from a larger buffer.</li>
<li>Similar things can be done for constant buffers, bindless textures,
etc. Usually it's not the individual draw calls that create CPU
overhead so much as the state changes between them.</li>
<li>Use instancing and/or indirect draws (ExecuteIndirect, vkCmdDrawIndirect, etc) to execute a large number of draw calls with one API-level command.</li>
<li>Move culling and LOD selection to the GPU (&quot;GPU-driven rendering&quot;), taking advantage of GPU compute to offload those tasks from the CPU.</li>
</ul>

CC BY-SA 4.0
2022-10-07T19:36:12.210Z
Thanks! This list is very useful. I misunderstood what people actually use bundling (a dx12 term?) for. And the vulkan term "secondary command buffers" got me a bunch of helpful web results.
Daryl
CC BY-SA 4.0
2022-10-07T18:37:54.563Z
2022-10-07T18:37:54.563Z
Nathan Reed
<p>If I'm understanding things correctly (please correct me if I'm wrong):</p>
<ul>
<li>All modern graphics APIs (vulkan, dx12, metal, webgpu) provide ways to <strong>bundle</strong> and replay draw calls. The bundle includes which vertices + indices for all bundled draw calls, so frame to frame you're <em>not changing which triangles are drawn</em> in the bundle. This saves a ton of CPU work.</li>
<li>With <strong>frustum/occlusion culling</strong>, each frame, you would typically test each object against the view pyramid and skip the draw calls for objects that are outside the view.</li>
</ul>
<p><strong>How should these work together?</strong>
With bundling, you lose the fine-grain ability to decide which sets of triangles to draw, so how do you achieve frustum culling?</p>
<p>The only option I can think of is to have many bundles, ideally of co-located objects, and maintain some bounding volume for the whole bundle and frustum cull at the bundle level.</p>
<p>But it seems difficult to maintain co-located sets of objects. Are the bundles anchored to a region of space and objects move in and out of that bundle? That seems like it'd cause a lot of rebundling.</p>
<p>How do people solve this, or what part of the problem am I misunderstanding?</p>
<p><strong>Edit, more context</strong>: I'm building my first renderer using WebGPU which calls this &quot;bundling&quot;[0][1] and since this sits on top of {DX12,Metal,Vulkan}, I assume all these APIs can implement this. My understanding is that bundling is one of the big performance wins in webgpu over webgl. (Note: there doesn't seem to be a webgpu tag on this site yet.)</p>
<p>[0] <a href="https://gpuweb.github.io/gpuweb/#bundles" rel="nofollow noreferrer">https://gpuweb.github.io/gpuweb/#bundles</a></p>
<p>[1] <a href="https://austin-eng.com/webgpu-samples/samples/animometer" rel="nofollow noreferrer">https://austin-eng.com/webgpu-samples/samples/animometer</a> (Chrome only; see &quot;bundle&quot; option)</p>

<vulkan><performance>
How to do frustum culling with draw call bundling?
Daryl
# How to do frustum culling with draw call bundling?

(Asked by: username_0 on 2022-10-07)

If I'm understanding things correctly (please correct me if I'm wrong):

* All modern graphics APIs (vulkan, dx12, metal, webgpu) provide ways to **bundle** and replay draw calls. The bundle includes which vertices + indices for all bundled draw calls, so frame to frame you're *not changing which triangles are drawn* in the bundle. This saves a ton of CPU work.
* With **frustum/occlusion culling**, each frame, you would typically test each object against the view pyramid and skip the draw calls for objects that are outside the view.

**How should these work together?**
With bundling, you lose the fine-grain ability to decide which sets of triangles to draw, so how do you achieve frustum culling?

The only option I can think of is to have many bundles, ideally of co-located objects, and maintain some bounding volume for the whole bundle and frustum cull at the bundle level.

But it seems difficult to maintain co-located sets of objects. Are the bundles anchored to a region of space and objects move in and out of that bundle? That seems like it'd cause a lot of rebundling.

How do people solve this, or what part of the problem am I misunderstanding?

**Edit, more context**: I'm building my first renderer using WebGPU which calls this "bundling"[0][1] and since this sits on top of {DX12,Metal,Vulkan}, I assume all these APIs can implement this. My understanding is that bundling is one of the big performance wins in webgpu over webgl. (Note: there doesn't seem to be a webgpu tag on this site yet.)

[0] <https://gpuweb.github.io/gpuweb/#bundles>

[1] <https://austin-eng.com/webgpu-samples/samples/animometer> (Chrome only; see "bundle" option)

**Tags:** vulkan, performance


---

## 1 answers

### Answer by username_1 on 2022-10-07. Score: 2 | Accepted answer

If by bundles you mean secondary command buffers, I think the answer is that people generally don't use them, or at least not in the sense you mean. They might be used to parallelize command recording across threads, but not to reduce draw-call-related overhead because, as you mention, the set of things to be drawn in a frame changes constantly, due to both frustum/occlusion and also LOD switching, as well as any moving objects or other changes that may be happening in the rendered world.

There are other ways to address draw-call overhead, including:

* Pull together vertex and index buffers for different objects into larger buffers, so you're not constantly having to switch between buffers. You can issue draw calls with the starting vertex offset and index offset parameters to draw a subset of vertices/triangles from a larger buffer.
* Similar things can be done for constant buffers, bindless textures,
  etc. Usually it's not the individual draw calls that create CPU
  overhead so much as the state changes between them.
* Use instancing and/or indirect draws (ExecuteIndirect, vkCmdDrawIndirect, etc) to execute a large number of draw calls with one API-level command.
* Move culling and LOD selection to the GPU ("GPU-driven rendering"), taking advantage of GPU compute to offload those tasks from the CPU.

> **Comments:**
> **username_0**: Thanks! This list is very useful. I misunderstood what people actually use bundling (a dx12 term?) for. And the vulkan term "secondary command buffers" got me a bunch of helpful web results.  

---

