Don't fail clip atlas instantiation when the access is out of bounds
This means the draw is entirely clipped out, so we just don't even
create the FP to begin with.
Change-Id: I6d8a2a2e18be07c8a1408437c4bcc3d9349b77a2
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/387057
Commit-Queue: Chris Dalton <csmartdalton@google.com>
Reviewed-by: Adlai Holler <adlai@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
diff --git a/src/gpu/GrClipStack.cpp b/src/gpu/GrClipStack.cpp
index 166693d..257bee8 100644
--- a/src/gpu/GrClipStack.cpp
+++ b/src/gpu/GrClipStack.cpp
@@ -234,13 +234,13 @@
// TODO: Currently this only works with CCPR because CCPR owns and manages the clip atlas. The
// high-level concept should be generalized to support any path renderer going into a shared atlas.
-static std::unique_ptr<GrFragmentProcessor> clip_atlas_fp(GrCoverageCountingPathRenderer* ccpr,
- uint32_t opsTaskID,
- const SkIRect& bounds,
- const GrClipStack::Element& e,
- SkPath* devicePath,
- const GrCaps& caps,
- std::unique_ptr<GrFragmentProcessor> fp) {
+static GrFPResult clip_atlas_fp(GrCoverageCountingPathRenderer* ccpr,
+ uint32_t opsTaskID,
+ const SkIRect& bounds,
+ const GrClipStack::Element& e,
+ SkPath* devicePath,
+ const GrCaps& caps,
+ std::unique_ptr<GrFragmentProcessor> fp) {
// TODO: Currently the atlas manages device-space paths, so we have to transform by the ctm.
// In the future, the atlas manager should see the local path and the ctm so that it can
// cache across integer-only translations (internally, it already does this, just not exposed).
@@ -261,10 +261,15 @@
// (1-sample(ccpr, input.rgb1).a) * sample(fp, input.rgb1) * input.a
// - Since clips only care about the alpha channel, these are both equivalent to the
// desired product of (1-ccpr) * fp * input.a.
- return GrBlendFragmentProcessor::Make(
- ccpr->makeClipProcessor(nullptr, opsTaskID, *devicePath, bounds, caps), // src
- std::move(fp), // dst
- SkBlendMode::kDstOut);
+ auto [success, atlasFP] = ccpr->makeClipProcessor(nullptr, opsTaskID, *devicePath, bounds,
+ caps);
+ if (!success) {
+ // "Difference" draws that don't intersect the clip need to be drawn "wide open".
+ return GrFPSuccess(nullptr);
+ }
+ return GrFPSuccess(GrBlendFragmentProcessor::Make(std::move(atlasFP), // src
+ std::move(fp), // dst
+ SkBlendMode::kDstOut));
}
}
@@ -1494,8 +1499,14 @@
uint32_t opsTaskID = rtc->getOpsTask()->uniqueID();
for (int i = 0; i < elementsForAtlas.count(); ++i) {
SkASSERT(elementsForAtlas[i]->aa() == GrAA::kYes);
- clipFP = clip_atlas_fp(ccpr, opsTaskID, scissorBounds, elementsForAtlas[i]->asElement(),
- elementsForAtlas[i]->devicePath(), *caps, std::move(clipFP));
+ bool success;
+ std::tie(success, clipFP) = clip_atlas_fp(ccpr, opsTaskID, scissorBounds,
+ elementsForAtlas[i]->asElement(),
+ elementsForAtlas[i]->devicePath(), *caps,
+ std::move(clipFP));
+ if (!success) {
+ return Effect::kClippedOut;
+ }
}
}