# THREE.DrawCallInspector - visualize draw call cost (experimental)

**URL:** <https://discourse.threejs.org/t/three-drawcallinspector-visualize-draw-call-cost-experimental/22503>\
**Category:** Resources\
**Tags:** helpers, performance\
**Created:** [January 16, 2021, 11:56pm UTC](https://discourse.threejs.org/t/three-drawcallinspector-visualize-draw-call-cost-experimental/22503 "2021-01-16T23:56:34Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![Fyrestar](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/fyrestar/32/52793_2.png) [@Fyrestar](https://discourse.threejs.org/u/Fyrestar)\
**Post date:** [January 16, 2021, 11:56pm UTC](https://discourse.threejs.org/t/three-drawcallinspector-visualize-draw-call-cost-experimental/22503/1 "2021-01-16T23:56:34Z")

</div>

![DCI-01](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/4/f/4f86ec4519ce138bf2f9c0e2c3a1d51515fe7032.png)

This is a quick experimental attempt of a helper to monitor draw call costs. It could help spotting expensive draw calls caused by costly shaders and geometries. For WebGL1 using a blocking method and for WebGL2 the timer API.

 ![image](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/a/4/a416a177642c3e957b4a53b1f2aeede78105fb74.png)

_(A test gltf scene from sketchfab)_

**The output** :

The output is a map that renders all objects tinted as a heatmap by how much time they took relative to each other. This means a average scene with equally expensive meshes in view is likely going to be mostly blueish, while if there is a more expensive objectt with an expensive shader it will be more red while the cheapest go towards solid blue.

**Usage** :

Create the inspector, **call mount** in order to attach the UI and add the hooks into THREE.

```
const dci = new THREE.DrawCallInspector( renderer, scene, camera );
dci.mount();

```

In your render loop right at the beginning call `dci.update()` for the overlay output. And at your scene draw call, call `dci.begin()` before and `dci.end()` after your scene is rendered to the screen or a render target.

```
dci.update();

dci.begin();
renderer.render( scene, camera );
dci.end();

```

For WebGL1: Click on the overlay for a capture or enter a number of frames in the input, so it will automatically take a snapshot after that number of frames.

**Parameters** :

- `renderer`
- `scene`
- `camera`
- `options`

**Options**

- `enabled (bool)`  
A flag to disable the tool, it’s wont create UI or do anything, to leave it in the code but enable it when required.

- `record (constant)`  
Either THREE.DrawCallInspector.RecordDraw (default) or THREE.DrawCallInspector.RecordRange, RecordDraw will measure right before and right after the actual WebGL drawcall, while RecordRender will measure before and after renderBufferDirect.

- `wait (bool)`  
For WebGL2, will wait till all timing queries finished before making the next so the timings of the same draw call are available.

- `enableMaterials (bool)`  
You have the option to let the plugin extend your scenes original materials which are going to be extended, this is only useful for custom and special shaders where the transformation otherwise would make it not visible without.

- `overlayStrength (float , 0-1)`  
When `enableMaterials` is enabled, this is how much the heat coloring is mixed with it’s original rendered color, default is 0.5.

- `skipFrames (number)`  
For WebGL1 this should be set to manual (-1) to render by clicking on it, or a higher number as the blocking methods will cause a lagg when measuring, for WebGL2 the measurments can be done in realtime, however timings are fluctuating so it makes sense to use some delay before the next time queries are issued.

- `scale (float , 0-1)`  
The size of the overlay relative to the screen.

- `fade (float, 0+-1 )`  
The results are lerped across captures to get closer to some average viewable result, with a value of 1 the measured delta time is instantly used for the next capture preview.

- `bias (float, 0+-1 )`  
When the results are lerped and they were shorter they will decrease slower by this factor, if an object really doesn’t take long it should be able to cool down then.

**Compatibility** :

This should work with all most recent 113+ revisions.

> **[GitHub - Fyrestar/THREE.DrawCallInspector: Visualize draw call cost.](https://github.com/Fyrestar/THREE.DrawCallInspector)**
>
> Visualize draw call cost. Contribute to Fyrestar/THREE.DrawCallInspector development by creating an account on GitHub.

**Demo**

You see a sphere with a expensive shader, a high-poly sphere in the middle and boxes, when going close you see the boxes become hotter even if the spheres are in view, as the boxes cover more pixels on the screen.

https://codepen.io/Fyrestar/embed/preview/PoGXVZv?default-tabs=js%2Cresult&height=300&host=https%3A%2F%2Fcodepen.io&slug-hash=PoGXVZv

---

<div class="post-metadata">

**Author:** ![gkjohnson](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/gkjohnson/32/2298_2.png) [@gkjohnson](https://discourse.threejs.org/u/gkjohnson)\
**Post date:** [January 18, 2021, 2:57am UTC](https://discourse.threejs.org/t/three-drawcallinspector-visualize-draw-call-cost-experimental/22503/2 "2021-01-18T02:57:45Z")

</div>

This is great! Love seeing debug tools like this. I see you’re calling `gl.finish` as well as `gl.readPixels` to ensure the draw commands have finished. Is there a reason you need both? Shouldn’t gl.finish guarantee that the drawing has finished? And would it make sense to call `gl.finish` before calling the original `renderBufferDirect` to ensure there are no lingering commands that may inadvertently be measured?

Awesome work!

---

<div class="post-metadata">

**Author:** ![Fyrestar](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/fyrestar/32/52793_2.png) [@Fyrestar](https://discourse.threejs.org/u/Fyrestar)\
**Post date:** [January 18, 2021, 11:18am UTC](https://discourse.threejs.org/t/three-drawcallinspector-visualize-draw-call-cost-experimental/22503/3 "2021-01-18T11:18:54Z")

</div>

> [@gkjohnson](#):
>
> Shouldn’t gl.finish guarantee that the drawing has finished?

Unfortunately no (but apparently `gl.readPixels`), even though it literally says it waits and blocks till all commands are finished, this isn’t the case in the WebGL implementation and is afaik actually the same as `gl.flush`, however this likely would be browser/driver dependent anyway. I think `gl.readPixels` does actually wait then for the commands to finish, at least it seems to give less fluctuating timings when `gl.finish` is called before, and `gl.readPixels` seems to be the only real blocking method.

> [@gkjohnson](#):
>
> And would it make sense to call `gl.finish` before calling the original `renderBufferDirect` to ensure there are no lingering commands that may inadvertently be measured?

It is actually, this is where the start time is measured, in the original method isMesh is tested which is modified with a getter on all relevant classes, which when recording is enabled will try to finish/block first then take the first timestamp, this property is tested right before the real draw call - it is also tested one time before (before uniforms/vertex buffers handled) which i first skipped, but it tuned out to only give a reliable result when this is done here too, as otherwise the uniforms or geometry setup gives a longer delay to the first object being drawn with it.

I’ll see if i can improve it further. Since this is about relative weighting of cost it might help repeating draw calls a couple times to get a more significant result to compare with. Or optionally using reference weights such as a average low cost poly-count and material and a highly poly-count with costly material so get some general heat-map. But the weighting has the advantage that it highlights cost-proportions, more independent of how powerful the GPU used is.

---

<div class="post-metadata">

**Author:** ![Fyrestar](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/fyrestar/32/52793_2.png) [@Fyrestar](https://discourse.threejs.org/u/Fyrestar)\
**Post date:** [March 11, 2022, 2:17am UTC](https://discourse.threejs.org/t/three-drawcallinspector-visualize-draw-call-cost-experimental/22503/5 "2022-03-11T02:17:36Z")

</div>

I’ve made a update now adding the timer API of WebGL2 for more precise and non-blocking results. Also the measurements are made straight at before/after the WebGL API draw call now.

I’m going to extend this further soon with different analysis options, multiple inspector views etc. Especially to clean handle removed meshes.

Demo in the first post.

(Demo scene from sketchfab not in the codepen. That one chair has color write disabled or such)

---

<div class="post-metadata">

**Author:** ![iefreer](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/iefreer/32/28788_2.png) [@iefreer](https://discourse.threejs.org/u/iefreer)\
**Post date:** [August 16, 2022, 1:43am UTC](https://discourse.threejs.org/t/three-drawcallinspector-visualize-draw-call-cost-experimental/22503/6 "2022-08-16T01:43:06Z")

</div>

awesome, is there an es6 module version package?
