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:
parent
553239bc12
commit
3a15110898
@ -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();
|
||||
|
@ -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
|
||||
|
||||
|
@ -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[],
|
||||
|
Loading…
Reference in New Issue
Block a user