Pages

Apr 9, 2014

Don't Alpha That Pixel!!

In my travels, I’ve started seeing more texture atlases that waste hordes of texture space. The dominant waste comes from alpha textures being interspersed with opaque textures, effectively keeping around an extra channel of pixels for an image that isn’t needed.. Most games seem to dump all the textures into a single atlas in order to reduce the number texture swaps on the CPU. Sadly, they are wasting space by pushing all those blank pixels into memory. Because both opaque and transparent sprites are adjacent to each other in a given atlas it’s difficult to know, (unless you add a separate file listing it), what sprites need alpha blending, and which ones don’t. The end result of this, is that without extra overhead required to know when to turn on and off alpha functions, there’s a large chance that the majority of sprites you’re rendering are being done with alpha turned on, even the opaque ones.

But for the mobile devices, that might be a horrible idea.



Let’s talk about Alpha



Any sort of alpha (blending and testing) must be rendered back-to-front in order to get the desired visual result (aka, you must render the object/pixel farthest from the camera first, and the closest one last). The reason for this, is that to properly shade an alpha blended pixel, it must read from the frame buffer, do the blend, and write a new value (aka a read-modify-write or ROP: Raster Operation). As such, there must already be a depth-resident pixel color in the frame buffer before doing alpha.


On the other side of that coin, opaque surfaces are generally rendered in front-to-back (ie closest to the camera first) order. This process allows fragments closer to the camera to fill the z-buffer first, such that subsequent, farther-from-the-camera pixels can be discarded at the post vertex transform stage before needing to be shaded (which is typically a heavy performance issue).


Let’s be clear : In order to maximize your GPU performance, you need to minimize the number of non-visible pixels you’re wasting time shading. Proper removal of useless fragment processing was a bane to the early 2000’s console developers, and single handedly gave rise the art of Deferred Lighting, which quickly became one of the hottest rendering trends for FPS games in the early part of this century.



Mobile GPUs and Tile-Based-Rendering
In the mobile ecosystem, there’s a majority of GPU chips out there that are known as Tile Based Rendering (TBR). These GPUs work by dividing the render buffer into a regular grid in order to exploit spatial coherence, hardware parallelism, and other hardware operations that allow for improved performance.


One of the more important performance  features is a per-pixel hidden surface removal during fragment shading. For a given tile, Before running any fragment shaders, the polygons are pre processed to determine which fragments potentially contribute to the final result, and only those are shaded. This removes the need to sort opaque geometry on the CPU.


On hardware with this feature (not all TBR chips have this special advantage...), using alpha-textures (beyond 1 bit alpha) causes a horde of performance problems. Directly, any pixel using alpha eliminates much of the optimizations that come from the deferred rendering portion of the TBR hardware.


As such, the presence of the GLSL DISCARD keyword, alpha testing, alpha-to-coverage, and alpha blending will all disable the hidden surface optimization as the occluded pixel may potentially impact the final image. The result is full processing of every pixel of every polygon in a tile, regardless if it contributes to the final image.


Thus, these features should only be enabled for the objects that require them, even at the cost of an extra state change.



Don’t Alpha That Pixel!
The truth is that alpha functions have a plethora of performance implications in order to achieve the visual looks they are known for. At the end of the day, you want to be very judicious about what pixels you alpha blend. From a memory standpoint, storing opaque textures in alpha formats is a wasteful bloat of gpu space. From a performance standpoint, z rejection is critical to reduce the number of fragments being shaded, and overdraw is a serious performance concern on all hardware. Not keeping track of what layers are opaque, and properly rendering them in the right order, means wasting lots of fill rate on raster-op constrained devices.

~Main


You can find Colt McAnlis here:

  

3 comments: