Revert "Abolish absClear"
This reverts commit f948db6228fd8dce2ba2a6ff2dfec53ff95d3f90.
Reason for revert: Vulkan assertion on Nexus5
Original change's description:
> Abolish absClear
>
> Bug: skia:
> Change-Id: Ic4a0e640623677c06112d0735ffc5682049baf11
> Reviewed-on: https://skia-review.googlesource.com/c/skia/+/240771
> Commit-Queue: Chris Dalton <csmartdalton@google.com>
> Reviewed-by: Michael Ludwig <michaelludwig@google.com>
TBR=egdaniel@google.com,bsalomon@google.com,robertphillips@google.com,csmartdalton@google.com,michaelludwig@google.com
Change-Id: I071c9878d26ce0f1d91473ada48e9a702bb472de
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: skia:
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/242480
Reviewed-by: Chris Dalton <csmartdalton@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
diff --git a/src/core/SkGpuBlurUtils.cpp b/src/core/SkGpuBlurUtils.cpp
index 93f6814..038ab9c 100644
--- a/src/core/SkGpuBlurUtils.cpp
+++ b/src/core/SkGpuBlurUtils.cpp
@@ -274,15 +274,14 @@
return dstRenderTargetContext;
}
-// Returns a high quality scaled-down version of src. This is used to create an intermediate,
-// shrunken version of the source image in the event that the requested blur sigma exceeds
-// MAX_BLUR_SIGMA.
+// Note: despite its name this function does not kill every tenth legionnaire.
static sk_sp<GrTextureProxy> decimate(GrRecordingContext* context,
sk_sp<GrTextureProxy> src,
const SkIPoint& proxyOffset,
SkIPoint* srcOffset,
SkIRect* contentRect,
int scaleFactorX, int scaleFactorY,
+ bool willBeXFiltering, bool willBeYFiltering,
int radiusX, int radiusY,
GrTextureDomain::Mode mode,
int finalW,
@@ -381,6 +380,24 @@
SkASSERT(dstRenderTargetContext);
+ if (willBeXFiltering) {
+ if (scaleFactorX > 1) {
+ // Clear out a radius to the right of the contentRect to prevent the
+ // X convolution from reading garbage.
+ SkIRect clearRect = SkIRect::MakeXYWH(contentRect->fRight, contentRect->fTop,
+ radiusX, contentRect->height());
+ dstRenderTargetContext->priv().absClear(&clearRect);
+ }
+ } else {
+ if (scaleFactorY > 1) {
+ // Clear out a radius below the contentRect to prevent the Y
+ // convolution from reading garbage.
+ SkIRect clearRect = SkIRect::MakeXYWH(contentRect->fLeft, contentRect->fBottom,
+ contentRect->width(), radiusY);
+ dstRenderTargetContext->priv().absClear(&clearRect);
+ }
+ }
+
return dstRenderTargetContext->asTextureProxyRef();
}
@@ -489,20 +506,14 @@
xFit = SkBackingFit::kApprox; // the y-pass will be last
}
- GrTextureDomain::Mode currDomainMode = mode;
if (scaleFactorX > 1 || scaleFactorY > 1) {
srcProxy = decimate(context, std::move(srcProxy), localProxyOffset, &srcOffset,
- &localSrcBounds, scaleFactorX, scaleFactorY, radiusX, radiusY,
- currDomainMode, finalW, finalH, colorSpace);
+ &localSrcBounds, scaleFactorX, scaleFactorY, sigmaX > 0.0f,
+ sigmaY > 0.0f, radiusX, radiusY, mode, finalW, finalH, colorSpace);
+ localProxyOffset.set(0, 0);
if (!srcProxy) {
return nullptr;
}
- localProxyOffset.set(0, 0);
- if (GrTextureDomain::kIgnore_Mode == currDomainMode) {
- // decimate() always returns an approx texture, possibly with garbage after the image.
- // We can't ignore the domain anymore.
- currDomainMode = GrTextureDomain::kClamp_Mode;
- }
}
std::unique_ptr<GrRenderTargetContext> dstRenderTargetContext;
@@ -512,11 +523,19 @@
if (sigmaX > 0.0f) {
dstRenderTargetContext = convolve_gaussian(
context, std::move(srcProxy), localProxyOffset, srcRect, srcOffset, Direction::kX,
- radiusX, sigmaX, &localSrcBounds, currDomainMode, finalW, finalH, colorSpace, xFit);
+ radiusX, sigmaX, &localSrcBounds, mode, finalW, finalH, colorSpace, xFit);
if (!dstRenderTargetContext) {
return nullptr;
}
+ if (sigmaY > 0.0f) {
+ // Clear out a radius below the srcRect to prevent the Y
+ // convolution from reading garbage.
+ SkIRect clearRect = SkIRect::MakeXYWH(srcRect.fLeft, srcRect.fBottom,
+ srcRect.width(), radiusY);
+ dstRenderTargetContext->priv().absClear(&clearRect);
+ }
+
srcProxy = dstRenderTargetContext->asTextureProxyRef();
if (!srcProxy) {
return nullptr;
@@ -525,17 +544,12 @@
srcRect.offsetTo(0, 0);
srcOffset.set(0, 0);
localProxyOffset.set(0, 0);
- if (SkBackingFit::kApprox == xFit && GrTextureDomain::kIgnore_Mode == currDomainMode) {
- // srcProxy is now an approx texture, possibly with garbage after the image. We can't
- // ignore the domain anymore.
- currDomainMode = GrTextureDomain::kClamp_Mode;
- }
}
if (sigmaY > 0.0f) {
dstRenderTargetContext = convolve_gaussian(
context, std::move(srcProxy), localProxyOffset, srcRect, srcOffset, Direction::kY,
- radiusY, sigmaY, &localSrcBounds, currDomainMode, finalW, finalH, colorSpace, yFit);
+ radiusY, sigmaY, &localSrcBounds, mode, finalW, finalH, colorSpace, yFit);
if (!dstRenderTargetContext) {
return nullptr;
}
diff --git a/src/gpu/GrOpsTask.cpp b/src/gpu/GrOpsTask.cpp
index cab3e8e..86bcf9b 100644
--- a/src/gpu/GrOpsTask.cpp
+++ b/src/gpu/GrOpsTask.cpp
@@ -507,6 +507,12 @@
}
bool GrOpsTask::resetForFullscreenClear(CanDiscardPreviousOps canDiscardPreviousOps) {
+ // Mark the color load op as discard (this may be followed by a clearColorOnLoad call to make
+ // the load op kClear, or it may be followed by an explicit op). In the event of an absClear()
+ // after a regular clear(), we could end up with a clear load op and a real clear op in the task
+ // if the load op were not reset here.
+ fColorLoadOp = GrLoadOp::kDiscard;
+
// If we previously recorded a wait op, we cannot delete the wait op. Until we track the wait
// ops separately from normal ops, we have to avoid clearing out any ops in this case as well.
if (fHasWaitOp) {
diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp
index def18a3..dd3472c 100644
--- a/src/gpu/GrRenderTargetContext.cpp
+++ b/src/gpu/GrRenderTargetContext.cpp
@@ -341,6 +341,81 @@
}
}
+void GrRenderTargetContextPriv::absClear(const SkIRect* clearRect) {
+ ASSERT_SINGLE_OWNER_PRIV
+ RETURN_IF_ABANDONED_PRIV
+ SkDEBUGCODE(fRenderTargetContext->validate();)
+ GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "absClear",
+ fRenderTargetContext->fContext);
+
+ AutoCheckFlush acf(fRenderTargetContext->drawingManager());
+
+ SkIRect rtRect = SkIRect::MakeWH(fRenderTargetContext->fRenderTargetProxy->worstCaseWidth(),
+ fRenderTargetContext->fRenderTargetProxy->worstCaseHeight());
+
+ if (clearRect) {
+ if (clearRect->contains(rtRect)) {
+ clearRect = nullptr; // full screen
+ } else {
+ if (!rtRect.intersect(*clearRect)) {
+ return;
+ }
+ }
+ }
+
+ static const SkPMColor4f kColor = SK_PMColor4fTRANSPARENT;
+
+ // TODO: in a post-MDB world this should be handled at the OpsTask level.
+ // This makes sure to always add an op to the list, instead of marking the clear as a load op.
+ // This code follows very similar logic to internalClear() below, but critical differences are
+ // highlighted in line related to absClear()'s unique behavior.
+ if (clearRect) {
+ if (fRenderTargetContext->caps()->performPartialClearsAsDraws()) {
+ GrPaint paint;
+ clear_to_grpaint(kColor, &paint);
+
+ // Use the disabled clip; the rect geometry already matches the clear rectangle and
+ // if it were added to a scissor, that would be intersected with the logical surface
+ // bounds and not the worst case dimensions required here.
+ fRenderTargetContext->addDrawOp(
+ GrFixedClip::Disabled(),
+ GrFillRectOp::MakeNonAARect(fRenderTargetContext->fContext, std::move(paint),
+ SkMatrix::I(), SkRect::Make(rtRect)));
+ } else {
+ // Must use the ClearOp factory that takes a boolean (false) instead of a surface
+ // proxy. The surface proxy variant would intersect the clip rect with its logical
+ // bounds, which is not desired in this special case.
+ fRenderTargetContext->addOp(GrClearOp::Make(
+ fRenderTargetContext->fContext, rtRect, kColor, /* fullscreen */ false));
+ }
+ } else {
+ if (fRenderTargetContext->getOpsTask()->resetForFullscreenClear(
+ fRenderTargetContext->canDiscardPreviousOpsOnFullClear()) &&
+ !fRenderTargetContext->caps()->performColorClearsAsDraws()) {
+ fRenderTargetContext->getOpsTask()->setColorLoadOp(GrLoadOp::kClear, kColor);
+ } else {
+ fRenderTargetContext->getOpsTask()->setColorLoadOp(GrLoadOp::kDiscard);
+
+ if (fRenderTargetContext->caps()->performColorClearsAsDraws()) {
+ // This draws a quad covering the worst case dimensions instead of just the logical
+ // width and height like in internalClear().
+ GrPaint paint;
+ clear_to_grpaint(kColor, &paint);
+ fRenderTargetContext->addDrawOp(
+ GrFixedClip::Disabled(),
+ GrFillRectOp::MakeNonAARect(fRenderTargetContext->fContext,
+ std::move(paint), SkMatrix::I(),
+ SkRect::Make(rtRect)));
+ } else {
+ // Nothing special about this path in absClear compared to internalClear()
+ fRenderTargetContext->addOp(GrClearOp::Make(
+ fRenderTargetContext->fContext, SkIRect::MakeEmpty(), kColor,
+ /* fullscreen */ true));
+ }
+ }
+ }
+}
+
void GrRenderTargetContext::drawPaint(const GrClip& clip,
GrPaint&& paint,
const SkMatrix& viewMatrix) {
diff --git a/src/gpu/GrRenderTargetContextPriv.h b/src/gpu/GrRenderTargetContextPriv.h
index 4a12ba0..b29011d 100644
--- a/src/gpu/GrRenderTargetContextPriv.h
+++ b/src/gpu/GrRenderTargetContextPriv.h
@@ -49,6 +49,20 @@
void clearStencilClip(const GrFixedClip&, bool insideStencilMask);
+ /*
+ * Some portions of the code, which use approximate-match rendertargets (i.e., ImageFilters),
+ * rely on clears that lie outside of the content region to still have an effect.
+ * For example, when sampling a decimated blurred image back up to full size, the GaussianBlur
+ * code draws 1-pixel rects along the left and bottom edges to be able to use bilerp for
+ * upsampling. The "absClear" entry point ignores the content bounds but does use the
+ * worst case (instantiated) bounds.
+ *
+ * This call will always clear to transparent black.
+ *
+ * @param rect if (!null) the rect to clear, otherwise it is a full screen clear
+ */
+ void absClear(const SkIRect* rect);
+
// While this can take a general clip, since GrReducedClip relies on this function, it must take
// care to only provide hard clips or we could get stuck in a loop. The general clip is needed
// so that path renderers can use this function.