Tips for High Performance Art
While performance is often thought of as a programmers problem, the truth is that even some simple changes to how art is authored can have a drastic affect on a games performance. Unfortunately programmers suck at divulging much of this information – something I hope to remedy somewhat in this post. As with anything performance related, this isn’t an absolute list of rules to live by – some will depend on the architecture of the engine you’re working with, others on the particular scene, and yet others on the artistic look and style of the game. It’s also by no means comprehensive; I think this will likely spill over into another blog post. It’s best to discuss with your rendering team how (and if) each of these impact your game.
Pixel Quads and Pixie Dust
A few days ago an artist asked me for information on specular behaviour for materials, to which I sent him a link to the post Everything is Shiny over on the excellent Filmic Games blog. While browsing the site, he came across the post Where are my sub-pixel triangles???, which discusses performance issues arising from small triangles in meshes. Amazed that he’d never heard of such issues he came back and asked me if it really was true – and it is. It’s just never really discussed beyond the programming tracks at GDC, Gamefest, and so on. By the time it gets to artists it probably has been reduced to "make sure there are LODs", with not further details on what this means or why they need to exist. After all, LODs just reduce the vertex count – that couldn’t possibly affect the pixel shading performance! Right? It turns out that this is absolutely incorrect, and LODs have in fact a dramatic affect on pixel shading performance.
What. The. Hell. Yeah, it sounds odd. Your LOD is half the vertex count of the full-resolution mesh but still takes up exactly the same number of pixels on screen as the full mesh at the same distance from the camera, however the pixel shading performance of the full mesh is much lower than that of the LOD?! This is because there is a trade-off in the hardware between the size of triangles and pixel shader performance. The trade-off varies between hardware, and in some cases can be very extreme, but it never doesn’t exist.
Being a hardware trade-off this does mean that I have to explain a bit about how the hardware works when a triangle is rendered.
The process of rendering a mesh goes something like this:
Vertex processing (vertex shader) -> MAGIC –> Pixel processing (pixel shader)
What is the MAGIC step? That depends on the platform, but the general formula is that each triangle is broken into 2×2 blocks of pixels called quads, and then some (potentially large) number of quads are run through the pixel shader at once. As the X360 has a lot of great documentation on this publicly available from Gamefest, let’s take that as an example (the PS3 isn’t all that different anyway).
Putting this together, we get:
Vertex processing –> Triangles –> Quads -> 16-Quads –> Pixel processing
This might start to ring alarm bells as to why small triangles are expensive. To take the worst-case that you have a single 1 pixel triangle, for that single pixel you might as well be executing the pixel shader 64 (2*2*16) times! If you have 64 single-pixel triangles so there are enough quads generated to fill a full pixel vector, you will still at best have 25% pixel shading efficiency due to the 2×2 quads. To put this another way, the lighting, texture filtering, and all-round shiny-awesomeness of the pixels could be FOUR times as complex if we avoid these cases. There’s nothing that anybody but the artist creating the mesh can do about this either (other than a programmer running some ugly automatic decimation algorithm on the mesh in the pipeline, which I’ve never seen any artist happy about – for good reason). You won’t be able to make a perfect mesh, but it’s important to make a good one.
This can be distilled down to a simple ratio for easy comparison: vertex to pixel quad density. Ask a rendering programmer to show you how to figure this out for your art, or see the presentations listed in the References section at the end of this post.
A few other random stats pulled from various Gamefest presentations:
- Triangles that cover 2×2 pixels waste 60% or more of the pixel shading performance
- Going from 2×2 pixel triangles to 4×4 can increase the pixel shading performance by 33%
The cost of overdraw is proportional to the speed at which memory can be written to of the platform and the size of the screen. It may come as a surprise to many, but the PS2 actually performed better in this area than the X360 and PS3 (or even most modern PC graphics cards). As such, overdraw is actually quite significantly more expensive for this generation of consoles than it was for the previous (at least, on the PS2). We are saved somewhat by more flexible hardware with optimizations to fight the cost of overdraw, but those unfortunately don’t help when the overdraw consists of alpha-blended geometry (particles are obviously the worst for this).
So uh… that’s about it – overdraw is still a terrible problem for alpha-blended geometry, so try to reduce the number of layers of overdraw as much as possible.
Light, Shadow and Their Dark Interactions
Low-angle light directions are the enemy of efficient shadows, as they require far more objects to be classified as casting shadows for a frame than otherwise. The easiest way to look at this is that the length of the shadow that an object casts directly relates to how expensive it will be to be shadowed. This isn’t about the actual cost of calculating the shadow for the particular object, but about the cost to include it in the shadow calculations because the longer a shadow than an object can cast, the further outside of the current cameras view it must still be evaluated since it could be casting a shadow over something that is visible to the camera.
It doesn’t help that these low-angle light directions make for the most interesting lighting environments of course, so a compromise will probably have to be reached between the art and programming teams.
Death by Draw Calls
Everyone hates unnecessary bookkeeping; it’s red tape in the way of getting things done, and pulls you away from what you really want to be doing. Generally speaking, if you have different materials (shaders, textures, lighting values, etc.) applied to different parts of a mesh, it will have to be split up by the engine and each piece rendered individually. When you have multiple meshes on multiple objects split into multiple parts, you’re cutting down the amount of useful work that the GPU and engine can do as it’s having to do a lot of bookkeeping instead.
Try to use texture pages wherever possible, UV some parts of a mesh to a black part of the specular texture rather than a separate material with no specular, and weld together any meshes that can be.
This is about half of the items that I wanted to cover in this post, so it’ll definitely be covered further in my next blog post. But for now that should be plenty to chew on, and certainly covers a lot of the bigger issues affecting performance of art.
Technical Art Reviews: Getting the Most Out of your Content, Cameron Egbert, Gamefest 2010
PIX for Artists, Alan Murphy, Gamefest 2010
Xbox Textures – Formats, Conversion, Fetching, and Performance, David Cook and Jason Gould, Gamefest 2008
Xbox 360 Shaders and Performance: How Not to Upset the GPU, Cody Pritchard, Gamefest 2010
Building an Über-Fast Crowd Renderer for Your Next Xbox 360 Engine, Tomas Vykruta, Gamefest 2010
Past Gamefest Presentations