backends/stage-impl: Clamp the redraw clips to the framebuffer size
From the main commit:
When computing the redraw clips rectangles we were using graphene
extents rounding (via "grow" Mtk rounding strategy) to be sure that
each area is properly covering the unscaled space.
However graphene's extents rounding has not any concept of maximum
allocation space and thus it may lead to generate rectangles that don't
fully fit in the framebuffer area.
Assuming of having a framebuffer 3840x2160 scaled @ 2,2018349170684814453125
An example is this rounding rectangle:
969x1734 at 12x3 (in the framebuffer scaled space)
With the current code it becomes once re-scaled:
2135x3819 at 26x6 (in the framebuffer unscaled (e.g. monitor) space
And clearly this rectangle doesn't properly fit in the framebuffer,
since its x2 would be positioned at 2135+26 (=2161, so a pixel outside).
This is not something that is generally problematic for the receiver
code, since most KMS drivers handle this properly (even though it's still
conceptually wrong to damage an area bigger than the plane size), but it
becomes a problem once such rectangle also get transformed, because due
to the nature of meta_rectangle_transform() the rectangle will also be
offset.
Following the previous example, applying a 90° rotation, it will become:
3819x2135 at 6x-1 (in the monitor space)
And now this is really a problem, because we're ending up sending to the
driver a swap region with offscreen coordinates, and that's something that
most driver do not really support, causing the KMS commit to fail with:
Failed to post KMS update: drmModeAtomicCommit: Invalid argument
So, when scaling the regions, also clamp the rectangles so that they
will fit into the framebuffer area.
In the scale_offset_and_clamp_region() case we also need to rescale the
framebuffer go to back into framebuffer space.
Then adding few optimizations commits.
Fixes: #3509