The Showbudget panel is an informational panel that measures engine performance. For those familiar with the Half-Life 1 engine, you can think out it as an advanced replacement of the
r_speeds meter. In basic terms, it shows the current performance cost of various engine systems, in measurements of rendering time and framerate.
For level designers, you should use the Showbudget panel instead of framerate to measure the performance at various locations in your map, as well as determine the cause of performance drops.
- 1 Showbudget panel basics
- 2 Showbudget categories
- 2.1 Unaccounted
- 2.2 World rendering
- 2.3 Displacement rendering
- 2.4 Game
- 2.5 NPCs
- 2.6 Server Animations
- 2.7 Client Animations
- 2.8 Physics
- 2.9 Static prop rendering
- 2.10 Other prop rendering
- 2.11 Light cache
- 2.12 Brush model rendering
- 2.13 Shadow rendering
- 2.14 Detail prop rendering
- 2.15 Particle/effect rendering
- 2.16 Ropes
- 2.17 Dynamic light rendering
- 2.18 Networking
- 2.19 Sound
- 2.20 VGUI
- 2.21 FileSystem
- 2.22 Prediction
- 2.23 Interpolation
- 2.24 Swap buffers
- 2.25 AINET
- 2.26 Occlusion
- 2.27 Overlays
- 2.28 CLagCompensationManager
- 2.29 CViewRender::Render
- 2.30 3D Skybox
- 3 Useful console commands
- 4 Techniques not represented by Showbudget
- 5 See also
Showbudget panel basics
Showbudget is toggled on by typing
+showbudget in the console. You toggle it off with
-showbudget. You can bind it to a key by typing
bind <keyname> "+showbudget" in the console. The panel will then be displaying while the <keyname> key is held down. Note that sv_cheats must be enabled ("sv_cheats 1" in the console).
Along with a small FPS indicator, the showbudget panel (seen in the picture to the right) will appear. Above is a graph of the total amount of FPS, and under that are performance measurements for various engine systems. The performance meters are measurements of time spent in that engine system, measured in milliseconds (ms) per frame. Larger amounts of time (ms) have greater impacts on the final framerate of the scene.
To properly measure rendering performance, you must run the engine full-screen, not windowed, and with as few background applications running as possible. Running the Hammer Editor while the engine is running will have a significant impact on performance measurements.
Game, Physics, and Sound bars are all progressive. That means they get more expensive as the framerate goes down. Even if they are the longest bar, they may not be the problem. If you've got other big costs, you may want to experiment with disabling those other features to see if it increases the framerate, and if so how much if affects the Game, Physics, or Sound bars.
Here's a description of each of the Showbudget categories, common causes for performance issues, possible fixes, and console commands that can be useful in diagnosing problems.
The Unaccounted bar is simply a measurement of costs that aren't included in any other category.
A common cause for a high Unaccounted bar is other applications that are running on the system in the background (e.g. a virus scanner, Winamp, Hammer). For proper measure of performance, no other programs should be running, including the Hammer editor.
Also, limiting the framerate with
fps_max can also potentially contribute. If you see a huge Unaccounted bar and aren't running any other applications, the chances are that your
fps_max setting is causing the engine to pause before rendering the next frame. The Showbudget panel counts this controlled delay as Unaccounted.
The rendering time of world (brush) geometry. To remedy this, use various visibility control techniques -- hints, func_areaportals, func_areaportalwindows to make less world geometry visible. You can also use an env_fog_controller to set the max rendering distance (clipping distance) and use the fog to hide the clipping. Reducing or simplifying brush geometry will also lower rendering costs.
The rendering time of Displacement geometry. You can reduce this cost by reducing the amount of displacements, set their "power" to a lower number, or use the same visibility control techniques as you would with brush geometry.
Performance cost caused for all game logic that isn't NPCs. Player movement, triggers, entity I/O, any simulations (fire entities, tracktrains, doors, etc). Reduce the number of entities in the level. Using entity I/O, a single entity can trigger multiple entities. Look for
think_limit spikes - reduce
think_limit to 1 or 2 and see what shows up.
This is measuring time spent in the Artificial Intelligence system. NPC thinking, navigation, and motion planning are the major costs here. Reduce the number of active NPCs, the number or complexity of objects near NPCs (for faster motion planning), improve the node graph.
Time spent in the server-side animation system. Reduce traces against characters. Reduce number of hitboxes on characters. Reduce the number of NPCs. Reduce bones in models, LOD bones, reduce blends, autoplay sequences, etc.
Time spent in the client-side animation system. This is mostly animation of characters, NPCs or players in multiplayer. Reduce the number of NPCs. Reduce bones in models, LOD bones, reduce blends, autoplay sequences, etc.
The performance cost of active physics objects and interactions with the physics system. This is usually caused by too many physics props interacting with each other in a space. Reduce the number of physics props in areas of the map where many props are simultaneously active. Mark small physics objects with the debris flag to reduce collisions. Physics props that cannot break (i.e. metal objects) are some of the most costly because they continue to interact even after being affected by large physics forces. For multiplayer games, make sure you're using prop_physics_multiplayer objects instead of prop_physics.
This is the time spent computing vphysics simulation. The number of prop_physics, prop_ragdoll, func_physbox, and any phys_constraint, hinges, pulleys, springs, etc. all contribute to this cost. Inactive physics objects have a very low cost, other than the rendering cost of the model itself. You can use
physics_report_active to show how many active objects you have at any one time. If you have more than 20 or 30, then you may need to reduce them. Also, reducing the number of collision has a huge effect on performance. Making more objects debris (means they can't collide with each other, players, NPCs, or vehicles) will reduce cost. Reducing the number of convex pieces per object will also help.
ent_bbox (supports physics objects & constraints. Dark green box tells you the object is inactive),
physics_highlight_active (puts a box around all active objects),
physics_report_active (dumps the name of all active physics objects),
physics_budget (dumps active objects with name and position).
Static prop rendering
The rendering time of prop_static geometry. This can be remedied by:
- Using the same visibility control techniques as you would with brush geometry.
- Add func_occluders to hide more prop_static models.
- Set or decrease existing fade distances on prop_static entities.
- Remove expensive props, or find a cheaper replacement.
If you're using custom models:
- Reduce the number of faces.
- Add aggressive levels of detail.
- Reduce the number of skins.
- Make the models single batches (materials) whenever possible.
- Merge multiple static prop models into a single model.
Fade distances on prop_static entities can be set by turning on object helpers in Hammer. They are the two circles surrounding each prop_static. One for the fade to start, the other for fade to end. When the prop is farther away than the max distance, the prop will not be rendered. At any distance below fademax there is no performance gain. You can measure the distances and screen area of props in-engine with the
Other prop rendering
This is the rendering cost of all other models other than static or detail props. This includes NPCs, prop_physics, prop_dynamic, weapon models, characters, etc. You can use the same techniques used for Static prop rendering on these props. Be careful about making fade distances on physics props too low -- the physics prop may be moved to a location that makes the fade distance too noticeable.
Time spent in the light cache system computing lighting for moving entities -- characters, physic props, hierarchically-attached dynamic props, etc. Not brush models or static props. Usually requires low-level code changes to fix. Can be mitigated by reducing the number of simultaneously moving models.
Brush model rendering
Rendering cost of brush-based entities -- func_door, func_brush, func_movelinear, etc. This is very similar in cost to world rendering (it uses the same renderer). See World Rendering above for possible solutions.
This is the time it takes to render the shadow textures and project them on the world. Performance can be increased by reducing the number of rendered shadow surfaces. Disable shadows on some props, or use the model-reduction techniques listed above to reduce the number of visible models with shadows enabled. Reduce the number of bones or triangles in the shadow LODs of visible models. Adding a shadow_control entity with a low shadow distance can also help reduce the number of shadow polygons.
Detail prop rendering
Rendering of detail props (prop_detail and detail sprites generated on displacements with
detail.vbsp. Detail props are not drawn at all on low-end machines. To improve performance, reduce the number of displacements with generated detail sprites, decrease the density of the sprites in
detail.vbsp, or paint out some of the detail objects using the displacement alpha painting tools.
This is all cost of all particles -- beams, sprites, client effects, etc. If this is big and not just a spike for a short period of time, then it's probably some env_fire, env_steam, env_smokestack or smoke effect that's visible in the map.
Time spent in the rendering and updating of rope entities, move_rope and keyframe_rope. Performance can be improved by reducing the number of ropes or by decreasing the number of subdivisions in visible ropes.
Dynamic light rendering
Rendering cost of dynamic lights in the scene. Lightstyles, entities with dlights (scanners, muzzle flashes, explosions). Dynamic lights are quite a heavy load for the engine, and so should be used sparingly and only areas with high performance before dynamic lights are added. Also, the point_spotlight has the "no dynamic light" flag, Make sure the flag is on to avoid a serious impact on performance.
Time spent in the networking system. The Source engine uses a client/server relationship, even when running single-player games. Large amounts of entity data can cause networking spikes. To remedy, reduce the network-traffic your map generates by removing any expensive networks (server-side) entities. For example, it may help to use prop_physics_multiplayer instead of prop_physics and func_physbox.
Time spent in the sound system. Too many sounds playing, or too many high quality sounds.
- Simplify the current soundscape so it is not playing as many simultaneous sounds or using heavy DSP effect values.
- Reduce the number of ambient_generic entities playing sounds in the area.
- Reduce the sounds played by weapons in a custom MOD.
- Change the attenuation of sounds in the script files so the distance sounds are heard is reduced.
- Reduce the length, frequency and/or bit-depth of custom sounds.
Time spent in rendering the Graphical User Interface. You will always see some time added to this category while the Showbudget panel is up, due to its heavy usage of VGUI. Large spikes in this category might appears for very complex window rendering schemes, but is most likely a programming design error.
r_drawvgui 0/1 (be careful, this will turn off the console as well!)
This means you are loading files from disk -- models, sounds, etc. Use
fs_warning_level to see which files.
Time spent in the prediction system. This should never be running in single-player games. For multiplayer, this will be affected by number of players, and number of predictable entities. Not much you can do about this without writing code. See Working With Prediction for more information.
Client-side animation/interpolation of entities. Not much you can do without writing code. See Source Multiplayer Networking for more information.
A lot of time in Swap Buffers is usually a fill-rate problem. Be sure to run full screen and at a lower resolution to test. You can also use
mat_viewportscale to test if you are fill-rate limited. If performance changes as you decrease
mat_viewportscale, you are fill-rate limited.
Here are some useful bindings for changing
mat_viewportscale using the "[" and "]" keys:
bind "[" "incrementvar mat_viewportscale .1 1 -.1" bind "]" "incrementvar mat_viewportscale .1 1 .1"
High fill-rate can be caused by a number of things, but it's usually expensive materials that cover large amounts of screen space. Expensive materials include:
- Water, especially water that overlaps over or under other expensive materials.
- Fire, smoke or steam effects.
- Glass or other transparent textures, especially with refraction.
- Bump, normal-mapped, or specular (reflective) materials.
- Any other material with complicated shader effects.
To solve fill-rate problems, reduce the number of expensive materials in the scene by simplifying the materials themselves or reducing their number by removing geometry.
This bar should only occur when building node graphs. It is of limited usefullness outside engine development and will likely be eliminated in the future.
Time spent in the occlusion system, calculating what objects can be hidden by func_occluder entities in the map. Care should be taken that occluders that are added to a level are removing enough model rendering to be worth the cost of the occluders themselves!
This can be improved by reducing the number of occluders in the map. You can see which occluders are being used by using the
r_visocclusion console variable. You can use this to see how well the system is doing: red boxes are entities that were tested but still needed to be drawn, green are ones that it was able to cull out. The more green you see, the better. You can tweak with minimum screen space area occluders should be in order to be used using the
r_occluderminarea console variable (the argument is a percentage of screen area, like 5%). You can also use the
r_occludeemaxarea console variable to specify the percent of screen space an entity has to cover before it is no longer tested for occlusion (the reasoning being the bigger it is, the less likely it is going to be occluded). These occlusion values can be set on a per-map basis by choosing Map Properties from the Map menu in Hammer.
Rendering cost of any info_overlay objects in the scene. Large overlays covering many surfaces cost more than smaller ones, and overlays cost more than decals. The only solution is to reduce the size or number of overlays visible from this area.
Time spent in Lag Compensation Manager, which compensates for different player positions due to network latency in multiplayer games. This can only be reduced by code changes.
Time spent determining what will be rendered that frame, and time spent sorting translucent objects (rendered back to front). The number of times the world is rendered per frame will directly increase the time spent here. Reduce the number of monitors, reflective water surfaces, and any other special effects that render extra views of the world. Large amounts of detail props will also contribute. Turning off detail props entirely may produce extra performance benefits when the engine does not have to consider sorting any detail props.
The rendering time due to the combined cost of all elements in your 3D skybox. Reducing the rendering cost of objects in the 3D skybox is the only way to improve performance here. You should make the 3D skybox as cost-effective as possible, due to the fact that is rendered behind the other world geometry at all times.
Useful console commands
Some rendering display commands that toggle certain things work well with Showbudget to see their impact.
- Toggles func_occluders on and off, to see the effect of any occluders in the current view. Make sure that the rendering savings (shown in the Static Prop Rendering and Other Model Rendering bars) is worth the cost of the occluders themselves (Occlusion bar).
- Turns off and on bumpmapping, so you can see what kind of impact is has on your map
mat_bumpmap 1to put it back on.
- Turns off and on specular rendering (reflections), so you can see what kind of impact they have on your map
mat_specular 1to put it back on.
- Turns off bumpmapping, without unloading the bumpmap materials themselves from memory.
mat_fastnobump 0to put it turn them back on. Can be useful for quickly testing the appearance of materials without bumpmaps in a location. Does not impact performance, however. You must use
mat_bumpmapfor real performance testing.
- Turns off specular rendering, without unloading the specular materials themselves from memory.
mat_fastspecular 1to put it back on. Can be useful for quickly testing the appearance of materials without speculaity in a location. Does not impact performance, however. You must use
mat_specularfor real performance testing.
Techniques not represented by Showbudget
mat_drawwater 0/1 to enable/disable water rendering to see how much it is costing you.
r_debugcheapwater 0/1 – tells you if you are rendering:
- Cheap water
- Expensive water
- No water
Eye and teeth rendering
r_eyes 0/1 to see how much eyes are costing.
r_teeth 0/1 to see how much teeth rendering are costing.
Stub material system
mat_stub 1 to turn off the material system and below (3D driver, hardware) to see how much impact that part of the system is having on performance.
Visualizing ray traces
- Shows collision model ray traces
- Shows traces for lighting.