slint-ui / slint

Slint is a declarative GUI toolkit to build native user interfaces for Rust, C++, or JavaScript apps.
https://slint.dev
Other
17.42k stars 595 forks source link

Optimization / GL backend: Create layer needed for non-rectangular clip lazily #1053

Open tronical opened 2 years ago

tronical commented 2 years ago

Olivier had a great idea for the path clipping feature:

When using clip: true on a Rectangle that also has a non-zero border-radius declared, we are facing the situation that we need to clip the contents (including children) against a non-rectangular clip region. However femtovg only supports the scissor clip, which is strictly rectangular.

What the GL backend does to implement the non-rectangular clip is to render the content into an intermediate texture, then declare a "rounded rect path" (with said border radius) and fills it with that texture. That femtovg supports via stencil clip.

The rendering into an intermediate texture however comes at a cost, which could be avoided if we knew that none of the children intersect with this clip. This might happen after all, dynamically at run-time.

Olivier's idea is that if we detect such a clipping scenario we do optimistically continue rendering children without an intermediate texture. If during the rendering of any children, or grand children, etc. we detect that we /do/ intersect with said region, we lazily switch to layered rendering. Since we render strictly back-to-front, switching in-between /should/ still give the correct visual result.

tronical commented 2 years ago

Even if we can't create this lazily anymore, we can still achieve a similar effect of optimization:

When rendering a Clip element with a border radius:

  1. Check if any of the children intersect with the region covered by the radius (so inner rect with radius minus outer rect, gives four rectangles, any intersection with these).
  2. If they do not intersect, then we can do a rectangular scissor clip and don't have to do indirect layer rendering.

Note: For Rectangle { clip: true; @children } the hierarchy created is Rectangle { Clip { @children } }