Skip to content

[Impeller] Geometry overdraw protection should be handled by the clip depth #178951

@flar

Description

@flar

Currently Impeller uses the depth buffer to implement clipping, rendering primitives with a Z clip function of z < clip-op-depth so that rendering operations can only affect pixels with smaller Z values than the nearest enclosing clip operation.

Some primitives generate overlapping triangles in their tessellation. Generally we try to avoid this and it is easy to do for simple primitives like lines, as well as filled rects, circles, ovals, arcs, and round-rects, but it can be hard if not possible for stroked paths and some arcs. To handle these cases we provide a mode in the tessellated geometry that requests "overdraw protection" and which uses a mechanism that comes with some performance penalties.

This issue proposes a solution that can provide that overdraw protection for tessellated geometry without any performance penalties by using the existing depth buffer mechanism that performs clipping.

It is important to know that the depth (Z) value for all previously rendered drawing primitives are less than the current rendering op's render depth. The depth value for all clip operations that should restrict the current rendering primitive are greater than the current rendering op's render depth. There should be no depth values in the Z buffer when a rendering op starts that are greater than the previous op's render depth and less than the next clip op's depth. After the rendering op renders then the state should be similar, but the lower bound will be the current render op's depth. It will fill in its own depth as it renders. Depth values for clip operations that happen between this rendering op and the one that we need to honor will not be in the buffer yet as they are due to clips that we haven't encountered yet. Depth values for clip operations that have already expired (because we did a Restore() operation that took them out of scope) should always be less than the current rendering op's depth.

The same setting can also provide overdraw protection for primitives that can't easily compute non-overlapping triangles for their geometry. Consider:

z < limit can be used with the following ranges:

  • If limit is in the range (previous-render-op-depth < limit <= clip-op-depth) then clipping occurs because it can't render past the clip depth, and previous rendering ops do not block it as their depth is too low. But, overdraw for the current rendering primitive at current-render-op-depth may or may not happen.
  • The latter part of that range - (current-render-op-depth < limit <= clip-op-depth) - will perform clipping and also allow overdraw. This is the behavior we currently have as we use clip-op-depth for our limit.
  • The beginning part of that range - (previous-render-op-depth < limit <= current-render-op-depth) - will both perform clipping and prevent overdraw of the triangles in the current render op.

This method only covers the case of geometry tessellations where every triangle encloses pixels that are inside the required shape and does not provide a solution for cases that require analysis of filling modes like EvenOdd or NonZeroWinding.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Important issues not at the top of the work liste: impellerImpeller rendering backend issues and features requestsengineflutter/engine related. See also e: labels.team-engineOwned by Engine teamtriaged-engineTriaged by Engine team

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions