withSaveLayer

Function

Common
inline fun Canvas.withSaveLayer(bounds: Rect, paint: Paint, block: () -> Unit)

Saves a copy of the current transform and clip on the save stack, and then creates a new group which subsequent calls will become a part of. When the lambda is executed and the save stack is popped, the group will be flattened into a layer and have the given paint's Paint.colorFilter and Paint.blendMode applied.

This lets you create composite effects, for example making a group of drawing commands semi-transparent. Without using Canvas.saveLayer, each part of the group would be painted individually, so where they overlap would be darker than where they do not. By using Canvas.saveLayer to group them together, they can be drawn with an opaque color at first, and then the entire group can be made transparent using the Canvas.saveLayer's paint.

Using saveLayer with clips

When a rectangular clip operation (from Canvas.clipRect) is not axis-aligned with the raster buffer, or when the clip operation is not rectalinear (e.g. because it is a rounded rectangle clip created by Canvas.clipPath), the edge of the clip needs to be anti-aliased.

If two draw calls overlap at the edge of such a clipped region, without using Canvas.saveLayer, the first drawing will be anti-aliased with the background first, and then the second will be anti-aliased with the result of blending the first drawing and the background. On the other hand, if Canvas.saveLayer is used immediately after establishing the clip, the second drawing will cover the first in the layer, and thus the second alone will be anti-aliased with the background when the layer is clipped and composited (when lambda is finished executing).

Performance considerations

Generally speaking, Canvas.saveLayer is relatively expensive.

There are a several different hardware architectures for GPUs (graphics processing units, the hardware that handles graphics), but most of them involve batching commands and reordering them for performance. When layers are used, they cause the rendering pipeline to have to switch render target (from one layer to another). Render target switches can flush the GPU's command buffer, which typically means that optimizations that one could get with larger batching are lost. Render target switches also generate a lot of memory churn because the GPU needs to copy out the current frame buffer contents from the part of memory that's optimized for writing, and then needs to copy it back in once the previous render target (layer) is restored.

See also:

  • Canvas.save, which saves the current state, but does not create a new layer for subsequent commands.
  • BlendMode, which discusses the use of Paint.blendMode with saveLayer.