1,295
edits
| Line 195: | Line 195: | ||
For example, suppose we have some normal content, covered by an opacity:0.5 element, covered by some more normal content. Currently we'd render the bottommost content directly to the destination (actually to a backbuffer, but that's irrelevant here), then we'd create a temporary surface, render in the translucent content, composite that onto the destination, and then render the topmost content directly to the destination. A naive layers implementation would render the bottommost content directly to a temporary surface, render the translucent content to another temporary surface, render the topmost content to another temporary surface, and then composite them each onto the destination. That would be an unacceptable performance hit when compositing must be done on the CPU, especially if the buffers will not be saved and used again, because animation is not present or memory is scarce. (Also, since the topmost content layer is likely to not have a transparent background, we are likely to disable subpixel antialiasing for the topmost content, which we would like to avoid if possible.) | For example, suppose we have some normal content, covered by an opacity:0.5 element, covered by some more normal content. Currently we'd render the bottommost content directly to the destination (actually to a backbuffer, but that's irrelevant here), then we'd create a temporary surface, render in the translucent content, composite that onto the destination, and then render the topmost content directly to the destination. A naive layers implementation would render the bottommost content directly to a temporary surface, render the translucent content to another temporary surface, render the topmost content to another temporary surface, and then composite them each onto the destination. That would be an unacceptable performance hit when compositing must be done on the CPU, especially if the buffers will not be saved and used again, because animation is not present or memory is scarce. (Also, since the topmost content layer is likely to not have a transparent background, we are likely to disable subpixel antialiasing for the topmost content, which we would like to avoid if possible.) | ||
To enable an efficient immediate-mode implementation, we impose some constraints on the use of the layers API. First, define "mutation" as a call to any setter method on Layer, or a call to beginDraw or copyFrom on RenderedLayer, or a call to insertBefore or removeChild on ContainerLayer (when we add layer APIs, they may need to be added to this list). Then we impose the following | To enable an efficient immediate-mode implementation, we impose some constraints on the use of the layers API. First, define "mutation" as a call to any setter method on Layer, or a call to beginDraw or copyFrom on RenderedLayer, or a call to insertBefore or removeChild on ContainerLayer (when we add layer APIs, they may need to be added to this list). Then we impose the following rules: | ||
# After calling RenderedLayer::beginDraw, you are not allowed to mutate any layer before or equal to the RenderedLayer in a pre-order traversal of the layer tree. | |||
# The layer parameter to RenderedLayer::copyFrom must not be before this layer in a pre-order traversal of the layer tree. | |||
Then we can have an immediate-mode layer implementation which works just like our current code. | Then we can have an immediate-mode layer implementation which works just like our current code. Rule 1 means that when we call beginDraw, everything before the RenderedLayer has already been drawn, and we know the final values of the properties controlling rendering of this layer and its ancestors. If conditions are right, i.e. the opacity of this layer is 1.0, transform is affine, etc, we can avoid creating a buffer for this layer, and just return a gfxContext that renders directly into some ancestor buffer. The fact that we don't have this layer's contents stored anywhere is reflected by setting the layer's valid region to empty at the end of the transaction. Rule 2 ensures that no other layer can try to use an already-drawn RenderedLayer as the source of a copy. | ||
Note that | Note that rule 1 means you must add all children to a ContainerLayer before rendering into any of them, and in particular you must add a RenderedLayer to its parent before rendering into it. These constraints are easy enough for the display list subsystem to satisfy. | ||
= Jeff = | = Jeff = | ||
edits