Downgrade giant clip ops' AA in SkRasterClipStack

Anti-aliased path rendering in the software backend has an internal
limit of +/-16384 per coordinate. Path rendering is triggered by draws
and clips. Draws are tiled at a high-level before entering the blitter,
so this limit will not be encountered. Coverage mask generation for
AA clips, however, is not tiled. Normally, it relies on the path being
clipped by the underlying device dimensions. When the device itself
is larger than 16384, then the clip ops can reach the blitter and
exceed the internal limit.

When this happens, SkScan::FillPath adds a hard rect clip, which is
what caused the mis-applied clip seen in the attached bug report.

This CL detects when the canvas/device dimensions are large enough to
cause this problem and forcefully disables anti-aliasing for all clips.
This shouldn't really be a visual behavior change since the blitter
already was downgrading from AA. The main advantage is that the clip
stack will use SkRegion for BW clips exclusively instead of switching
to use SkAAClip.

It was decided to handle this at the clip stack level vs. a per-op
decision since a non-AA large clip element used with SkAAClip (
triggered by a smaller non-problematic op) would still show the bug.

This is only a mitigation. The long-term solution is to use tiling for
clipping as well as drawing (possibly by requiring the tiling to be
handled by clients, with surface creation failing at sizes > 16k).

Bug: chromium:1240718, skia:7998
Change-Id: I1f4cae540bec4d44c6e1d8032ded9e95ff32b82f
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/441456
Reviewed-by: Mike Reed <reed@google.com>
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
This commit is contained in:
Michael Ludwig 2021-08-23 15:53:47 -04:00 committed by SkCQ
parent 553239bc12
commit 3a15110898
3 changed files with 18 additions and 3 deletions

View File

@ -11,6 +11,7 @@
#include "include/core/SkClipOp.h"
#include "include/private/SkDeque.h"
#include "src/core/SkRasterClip.h"
#include "src/core/SkScan.h"
#include <new>
template <typename T> class SkTStack {
@ -66,6 +67,7 @@ public:
SkRasterClipStack(int width, int height)
: fStack(fStorage, sizeof(fStorage))
, fRootBounds(SkIRect::MakeWH(width, height))
, fDisableAA(SkScan::DowngradeClipAA(fRootBounds))
{
Rec& rec = fStack.push();
rec.fRC.setRect(fRootBounds);
@ -100,19 +102,19 @@ public:
}
void clipRect(const SkMatrix& ctm, const SkRect& rect, SkClipOp op, bool aa) {
this->writable_rc().op(rect, ctm, fRootBounds, (SkRegion::Op)op, aa);
this->writable_rc().op(rect, ctm, fRootBounds, (SkRegion::Op)op, this->finalAA(aa));
this->trimIfExpanding(op);
this->validate();
}
void clipRRect(const SkMatrix& ctm, const SkRRect& rrect, SkClipOp op, bool aa) {
this->writable_rc().op(rrect, ctm, fRootBounds, (SkRegion::Op)op, aa);
this->writable_rc().op(rrect, ctm, fRootBounds, (SkRegion::Op)op, this->finalAA(aa));
this->trimIfExpanding(op);
this->validate();
}
void clipPath(const SkMatrix& ctm, const SkPath& path, SkClipOp op, bool aa) {
this->writable_rc().op(path, ctm, fRootBounds, (SkRegion::Op)op, aa);
this->writable_rc().op(path, ctm, fRootBounds, (SkRegion::Op)op, this->finalAA(aa));
this->trimIfExpanding(op);
this->validate();
}
@ -161,6 +163,7 @@ private:
void* fStorage[PTR_COUNT];
SkTStack<Rec> fStack;
SkIRect fRootBounds;
bool fDisableAA;
SkRasterClip& writable_rc() {
SkASSERT(fStack.top().fDeferredCount >= 0);
@ -172,6 +175,8 @@ private:
return fStack.top().fRC;
}
bool finalAA(bool aa) const { return aa && !fDisableAA; }
void trimIfExpanding(SkClipOp op) {
if ((int)op > (int)SkClipOp::kIntersect) {
Rec& rec = fStack.top();

View File

@ -41,6 +41,11 @@ public:
static void FillPath(const SkPath&, const SkIRect&, SkBlitter*);
// Paths of a certain size cannot be anti-aliased unless externally tiled (handled by SkDraw).
// AA clipping doesn't do that, so it's better for the clip stack to adjust AA state early
// rather than clip to the internal limits of the blitter.
static bool DowngradeClipAA(const SkIRect& bounds);
///////////////////////////////////////////////////////////////////////////
// rasterclip

View File

@ -676,6 +676,11 @@ void SkScan::FillPath(const SkPath& path, const SkIRect& ir,
FillPath(path, rgn, blitter);
}
bool SkScan::DowngradeClipAA(const SkIRect& bounds) {
SkRegion out; // ignored
return clip_to_limit(SkRegion(bounds), &out);
}
///////////////////////////////////////////////////////////////////////////////
static int build_tri_edges(SkEdge edge[], const SkPoint pts[],