Different approach to fixing gpu blurs on platforms that "useDrawInsteadOfClear"
This CL reverts https://skia-review.googlesource.com/c/5148/ (Fix gpu blurring on platforms that "useDrawInsteadOfClear") (all the worstCaseWidth/Height stuff) and adds a new GrRenderTargetContext entry point (absClear) to specify clears that can't be discarded or altered. BUG=skia: Change-Id: I18b1373ecf4a153ca8c0f290ab8b1d00770426da Reviewed-on: https://skia-review.googlesource.com/5484 Commit-Queue: Robert Phillips <robertphillips@google.com> Reviewed-by: Brian Salomon <bsalomon@google.com>
This commit is contained in:
parent
e29ce641d3
commit
784b7bf493
@ -382,13 +382,6 @@ public:
|
||||
|
||||
bool isWrapped_ForTesting() const;
|
||||
|
||||
// These two methods return the worst case size of the backing GPU resource when it is
|
||||
// finally allocated. In the approx-match case the allocated size could be smaller than
|
||||
// what is reported by these entry points (i.e., Ganesh could, optionally, return an
|
||||
// exact match)
|
||||
int worstCaseWidth() const { return fRenderTargetProxy->worstCaseWidth(); }
|
||||
int worstCaseHeight() const { return fRenderTargetProxy->worstCaseHeight(); }
|
||||
|
||||
protected:
|
||||
GrRenderTargetContext(GrContext*, GrDrawingManager*, sk_sp<GrRenderTargetProxy>,
|
||||
sk_sp<SkColorSpace>, const SkSurfaceProps* surfaceProps, GrAuditTrail*,
|
||||
|
@ -112,6 +112,8 @@ public:
|
||||
*/
|
||||
sk_sp<GrRenderTarget> wrapBackendRenderTarget(const GrBackendRenderTargetDesc& desc);
|
||||
|
||||
static const int kMinScratchTextureSize;
|
||||
|
||||
protected:
|
||||
GrTextureProvider(GrGpu* gpu, GrResourceCache* cache, GrSingleOwner* singleOwner);
|
||||
|
||||
|
@ -224,9 +224,9 @@ public:
|
||||
* Helper that gets the width and height of the surface as a bounding rectangle.
|
||||
*/
|
||||
SkRect getBoundsRect() const { return SkRect::MakeIWH(this->width(), this->height()); }
|
||||
|
||||
int worstCaseWidth() const;
|
||||
int worstCaseHeight() const;
|
||||
|
||||
int worstCaseWidth(const GrCaps& caps) const;
|
||||
int worstCaseHeight(const GrCaps& caps) const;
|
||||
|
||||
/**
|
||||
* @return the texture proxy associated with the surface proxy, may be NULL.
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "GrContext.h"
|
||||
#include "GrCaps.h"
|
||||
#include "GrRenderTargetContext.h"
|
||||
#include "GrRenderTargetContextPriv.h"
|
||||
#include "GrFixedClip.h"
|
||||
|
||||
#define MAX_BLUR_SIGMA 4.0f
|
||||
@ -311,7 +312,7 @@ sk_sp<GrRenderTargetContext> GaussianBlur(GrContext* context,
|
||||
// X convolution from reading garbage.
|
||||
clearRect = SkIRect::MakeXYWH(srcRect.fRight, srcRect.fTop,
|
||||
radiusX, srcRect.height());
|
||||
srcRenderTargetContext->clear(&clearRect, 0x0, false);
|
||||
srcRenderTargetContext->priv().absClear(&clearRect, 0x0);
|
||||
}
|
||||
|
||||
convolve_gaussian(dstRenderTargetContext.get(), clip, srcRect,
|
||||
@ -336,7 +337,7 @@ sk_sp<GrRenderTargetContext> GaussianBlur(GrContext* context,
|
||||
// convolution from reading garbage.
|
||||
clearRect = SkIRect::MakeXYWH(srcRect.fLeft, srcRect.fBottom,
|
||||
srcRect.width(), radiusY);
|
||||
srcRenderTargetContext->clear(&clearRect, 0x0, false);
|
||||
srcRenderTargetContext->priv().absClear(&clearRect, 0x0);
|
||||
}
|
||||
|
||||
convolve_gaussian(dstRenderTargetContext.get(), clip, srcRect,
|
||||
@ -353,10 +354,12 @@ sk_sp<GrRenderTargetContext> GaussianBlur(GrContext* context,
|
||||
|
||||
if (scaleFactorX > 1 || scaleFactorY > 1) {
|
||||
// Clear one pixel to the right and below, to accommodate bilinear upsampling.
|
||||
// TODO: it seems like we should actually be clamping here rather than darkening
|
||||
// the bottom right edges.
|
||||
clearRect = SkIRect::MakeXYWH(srcRect.fLeft, srcRect.fBottom, srcRect.width() + 1, 1);
|
||||
srcRenderTargetContext->clear(&clearRect, 0x0, false);
|
||||
srcRenderTargetContext->priv().absClear(&clearRect, 0x0);
|
||||
clearRect = SkIRect::MakeXYWH(srcRect.fRight, srcRect.fTop, 1, srcRect.height());
|
||||
srcRenderTargetContext->clear(&clearRect, 0x0, false);
|
||||
srcRenderTargetContext->priv().absClear(&clearRect, 0x0);
|
||||
|
||||
GrPaint paint;
|
||||
paint.setGammaCorrect(dstRenderTargetContext->isGammaCorrect());
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "GrCaps.h"
|
||||
#include "GrContext.h"
|
||||
#include "GrFixedClip.h"
|
||||
#include "GrRenderTargetContextPriv.h"
|
||||
#include "effects/GrSimpleTextureEffect.h"
|
||||
#include "GrStyle.h"
|
||||
#include "GrTexture.h"
|
||||
@ -111,7 +112,7 @@ static sk_sp<GrTextureProxy> create_mask_GPU(GrContext* context,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
rtContext->clear(nullptr, 0x0, true);
|
||||
rtContext->priv().absClear(nullptr, 0x0);
|
||||
|
||||
GrPaint tempPaint;
|
||||
tempPaint.setAntiAlias(doAA);
|
||||
@ -141,8 +142,8 @@ static void draw_path_with_mask_filter(GrContext* context,
|
||||
SkASSERT(maskFilter);
|
||||
|
||||
SkIRect clipBounds;
|
||||
clip.getConservativeBounds(renderTargetContext->worstCaseWidth(),
|
||||
renderTargetContext->worstCaseHeight(),
|
||||
clip.getConservativeBounds(renderTargetContext->width(),
|
||||
renderTargetContext->height(),
|
||||
&clipBounds);
|
||||
SkTLazy<SkPath> tmpPath;
|
||||
SkStrokeRec::InitStyle fillOrHairline;
|
||||
|
@ -268,8 +268,8 @@ bool GrClipStackClip::apply(GrContext* context, GrRenderTargetContext* renderTar
|
||||
return true;
|
||||
}
|
||||
|
||||
SkRect devBounds = SkRect::MakeIWH(renderTargetContext->worstCaseWidth(),
|
||||
renderTargetContext->worstCaseHeight());
|
||||
SkRect devBounds = SkRect::MakeIWH(renderTargetContext->width(),
|
||||
renderTargetContext->height());
|
||||
if (!devBounds.intersect(out->clippedDrawBounds())) {
|
||||
return false;
|
||||
}
|
||||
@ -299,8 +299,8 @@ bool GrClipStackClip::apply(GrContext* context, GrRenderTargetContext* renderTar
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
SkASSERT(reducedClip.hasIBounds());
|
||||
SkIRect rtIBounds = SkIRect::MakeWH(renderTargetContext->worstCaseWidth(),
|
||||
renderTargetContext->worstCaseHeight());
|
||||
SkIRect rtIBounds = SkIRect::MakeWH(renderTargetContext->width(),
|
||||
renderTargetContext->height());
|
||||
SkIRect clipIBounds = reducedClip.ibounds().makeOffset(-fOrigin.x(), -fOrigin.y());
|
||||
SkASSERT(rtIBounds.contains(clipIBounds)); // Mask shouldn't be larger than the RT.
|
||||
#endif
|
||||
|
@ -48,7 +48,7 @@ bool GrFixedClip::isRRect(const SkRect& rtBounds, SkRRect* rr, bool* aa) const {
|
||||
bool GrFixedClip::apply(GrContext*, GrRenderTargetContext* rtc,
|
||||
bool, bool, GrAppliedClip* out) const {
|
||||
if (fScissorState.enabled()) {
|
||||
SkIRect tightScissor = SkIRect::MakeWH(rtc->worstCaseWidth(), rtc->worstCaseHeight());
|
||||
SkIRect tightScissor = SkIRect::MakeWH(rtc->width(), rtc->height());
|
||||
if (!tightScissor.intersect(fScissorState.rect())) {
|
||||
return false;
|
||||
}
|
||||
|
@ -227,6 +227,65 @@ void GrRenderTargetContext::clear(const SkIRect* rect,
|
||||
this->internalClear(rect ? GrFixedClip(*rect) : GrFixedClip::Disabled(), color, canIgnoreRect);
|
||||
}
|
||||
|
||||
void GrRenderTargetContextPriv::absClear(const SkIRect* clearRect, const GrColor color) {
|
||||
ASSERT_SINGLE_OWNER_PRIV
|
||||
RETURN_IF_ABANDONED_PRIV
|
||||
SkDEBUGCODE(fRenderTargetContext->validate();)
|
||||
GR_AUDIT_TRAIL_AUTO_FRAME(fRenderTargetContext->fAuditTrail,
|
||||
"GrRenderTargetContext::absClear");
|
||||
|
||||
AutoCheckFlush acf(fRenderTargetContext->fDrawingManager);
|
||||
|
||||
SkIRect rtRect = SkIRect::MakeWH(fRenderTargetContext->fRenderTargetProxy->worstCaseWidth(
|
||||
*fRenderTargetContext->caps()),
|
||||
fRenderTargetContext->fRenderTargetProxy->worstCaseHeight(
|
||||
*fRenderTargetContext->caps()));
|
||||
|
||||
if (clearRect) {
|
||||
if (clearRect->contains(rtRect)) {
|
||||
clearRect = nullptr; // full screen
|
||||
} else {
|
||||
if (!rtRect.intersect(*clearRect)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: in a post-MDB world this should be handled at the OpList level.
|
||||
// An op-list that is initially cleared and has no other ops should receive an
|
||||
// extra draw.
|
||||
if (fRenderTargetContext->fContext->caps()->useDrawInsteadOfClear()) {
|
||||
// This works around a driver bug with clear by drawing a rect instead.
|
||||
// The driver will ignore a clear if it is the only thing rendered to a
|
||||
// target before the target is read.
|
||||
GrPaint paint;
|
||||
paint.setColor4f(GrColor4f::FromGrColor(color));
|
||||
paint.setXPFactory(GrPorterDuffXPFactory::Make(SkBlendMode::kSrc));
|
||||
|
||||
// We don't call drawRect() here to avoid the cropping to the, possibly smaller,
|
||||
// RenderTargetProxy bounds
|
||||
fRenderTargetContext->drawNonAAFilledRect(GrNoClip(), paint, SkMatrix::I(),
|
||||
SkRect::Make(rtRect),
|
||||
nullptr,nullptr, nullptr, false);
|
||||
|
||||
} else {
|
||||
if (!fRenderTargetContext->accessRenderTarget()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This path doesn't handle coalescing of full screen clears b.c. it
|
||||
// has to clear the entire render target - not just the content area.
|
||||
// It could be done but will take more finagling.
|
||||
sk_sp<GrOp> batch(GrClearBatch::Make(rtRect, color,
|
||||
fRenderTargetContext->accessRenderTarget(),
|
||||
!clearRect));
|
||||
if (!batch) {
|
||||
return;
|
||||
}
|
||||
fRenderTargetContext->getOpList()->addOp(std::move(batch));
|
||||
}
|
||||
}
|
||||
|
||||
void GrRenderTargetContextPriv::clear(const GrFixedClip& clip,
|
||||
const GrColor color,
|
||||
bool canIgnoreClip) {
|
||||
@ -254,7 +313,7 @@ void GrRenderTargetContext::internalClear(const GrFixedClip& clip,
|
||||
// This works around a driver bug with clear by drawing a rect instead.
|
||||
// The driver will ignore a clear if it is the only thing rendered to a
|
||||
// target before the target is read.
|
||||
SkIRect clearRect = SkIRect::MakeWH(this->worstCaseWidth(), this->worstCaseHeight());
|
||||
SkIRect clearRect = SkIRect::MakeWH(this->width(), this->height());
|
||||
if (isFull) {
|
||||
this->discard();
|
||||
} else if (!clearRect.intersect(clip.scissorRect())) {
|
||||
@ -415,8 +474,7 @@ bool GrRenderTargetContext::drawFilledRect(const GrClip& clip,
|
||||
const SkRect& rect,
|
||||
const GrUserStencilSettings* ss) {
|
||||
SkRect croppedRect = rect;
|
||||
if (!crop_filled_rect(this->worstCaseWidth(), this->worstCaseHeight(),
|
||||
clip, viewMatrix, &croppedRect)) {
|
||||
if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix, &croppedRect)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -51,6 +51,19 @@ public:
|
||||
|
||||
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.
|
||||
*
|
||||
* @param rect if (!null) the rect to clear, otherwise it is a full screen clear
|
||||
* @param color the color to clear to
|
||||
*/
|
||||
void absClear(const SkIRect* rect, const GrColor color);
|
||||
|
||||
void stencilRect(const GrClip& clip,
|
||||
const GrUserStencilSettings* ss,
|
||||
bool useHWAA,
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include "GrSurfaceProxy.h"
|
||||
|
||||
#include "GrCaps.h"
|
||||
#include "GrGpuResourcePriv.h"
|
||||
#include "GrOpList.h"
|
||||
#include "GrTextureProvider.h"
|
||||
@ -49,14 +50,14 @@ GrSurface* GrSurfaceProxy::instantiate(GrTextureProvider* texProvider) {
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
if (kInvalidGpuMemorySize != this->getRawGpuMemorySize_debugOnly()) {
|
||||
SkASSERT(fTarget->gpuMemorySize() <= this->getRawGpuMemorySize_debugOnly());
|
||||
SkASSERT(fTarget->gpuMemorySize() <= this->getRawGpuMemorySize_debugOnly());
|
||||
}
|
||||
#endif
|
||||
|
||||
return fTarget;
|
||||
}
|
||||
|
||||
int GrSurfaceProxy::worstCaseWidth() const {
|
||||
int GrSurfaceProxy::worstCaseWidth(const GrCaps& caps) const {
|
||||
if (fTarget) {
|
||||
return fTarget->width();
|
||||
}
|
||||
@ -65,10 +66,14 @@ int GrSurfaceProxy::worstCaseWidth() const {
|
||||
return fDesc.fWidth;
|
||||
}
|
||||
|
||||
return GrNextPow2(fDesc.fWidth);
|
||||
if (caps.reuseScratchTextures() || fDesc.fFlags & kRenderTarget_GrSurfaceFlag) {
|
||||
return SkTMax(GrTextureProvider::kMinScratchTextureSize, GrNextPow2(fDesc.fWidth));
|
||||
}
|
||||
|
||||
return fDesc.fWidth;
|
||||
}
|
||||
|
||||
int GrSurfaceProxy::worstCaseHeight() const {
|
||||
int GrSurfaceProxy::worstCaseHeight(const GrCaps& caps) const {
|
||||
if (fTarget) {
|
||||
return fTarget->height();
|
||||
}
|
||||
@ -77,7 +82,11 @@ int GrSurfaceProxy::worstCaseHeight() const {
|
||||
return fDesc.fHeight;
|
||||
}
|
||||
|
||||
return GrNextPow2(fDesc.fHeight);
|
||||
if (caps.reuseScratchTextures() || fDesc.fFlags & kRenderTarget_GrSurfaceFlag) {
|
||||
return SkTMax(GrTextureProvider::kMinScratchTextureSize, GrNextPow2(fDesc.fHeight));
|
||||
}
|
||||
|
||||
return fDesc.fHeight;
|
||||
}
|
||||
|
||||
void GrSurfaceProxy::setLastOpList(GrOpList* opList) {
|
||||
|
@ -16,6 +16,8 @@
|
||||
#include "SkTArray.h"
|
||||
#include "SkTLazy.h"
|
||||
|
||||
const int GrTextureProvider::kMinScratchTextureSize = 16;
|
||||
|
||||
#define ASSERT_SINGLE_OWNER \
|
||||
SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fSingleOwner);)
|
||||
|
||||
@ -119,10 +121,9 @@ GrTexture* GrTextureProvider::refScratchTexture(const GrSurfaceDesc& inDesc,
|
||||
if (fGpu->caps()->reuseScratchTextures() || (desc->fFlags & kRenderTarget_GrSurfaceFlag)) {
|
||||
if (!(kExact_ScratchTextureFlag & flags)) {
|
||||
// bin by pow2 with a reasonable min
|
||||
const int kMinSize = 16;
|
||||
GrSurfaceDesc* wdesc = desc.writable();
|
||||
wdesc->fWidth = SkTMax(kMinSize, GrNextPow2(desc->fWidth));
|
||||
wdesc->fHeight = SkTMax(kMinSize, GrNextPow2(desc->fHeight));
|
||||
wdesc->fWidth = SkTMax(kMinScratchTextureSize, GrNextPow2(desc->fWidth));
|
||||
wdesc->fHeight = SkTMax(kMinScratchTextureSize, GrNextPow2(desc->fHeight));
|
||||
}
|
||||
|
||||
GrScratchKey key;
|
||||
|
@ -236,10 +236,10 @@ GrRenderTargetContext* SkGpuDevice::accessRenderTargetContext() {
|
||||
|
||||
void SkGpuDevice::clearAll() {
|
||||
ASSERT_SINGLE_OWNER
|
||||
GrColor color = 0;
|
||||
GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "clearAll", fContext.get());
|
||||
|
||||
SkIRect rect = SkIRect::MakeWH(this->width(), this->height());
|
||||
fRenderTargetContext->clear(&rect, color, true);
|
||||
fRenderTargetContext->clear(&rect, 0x0, true);
|
||||
}
|
||||
|
||||
void SkGpuDevice::replaceRenderTargetContext(bool shouldRetainContent) {
|
||||
|
@ -971,8 +971,8 @@ bool GrAAHairLinePathRenderer::onDrawPath(const DrawPathArgs& args) {
|
||||
SkASSERT(!args.fRenderTargetContext->isUnifiedMultisampled());
|
||||
|
||||
SkIRect devClipBounds;
|
||||
args.fClip->getConservativeBounds(args.fRenderTargetContext->worstCaseWidth(),
|
||||
args.fRenderTargetContext->worstCaseHeight(),
|
||||
args.fClip->getConservativeBounds(args.fRenderTargetContext->width(),
|
||||
args.fRenderTargetContext->height(),
|
||||
&devClipBounds);
|
||||
|
||||
SkPath path;
|
||||
|
@ -27,6 +27,12 @@ public:
|
||||
return batch;
|
||||
}
|
||||
|
||||
static sk_sp<GrClearBatch> Make(const SkIRect& rect, GrColor color, GrRenderTarget* rt,
|
||||
bool fullScreen) {
|
||||
sk_sp<GrClearBatch> batch(new GrClearBatch(rect, color, rt, fullScreen));
|
||||
return batch;
|
||||
}
|
||||
|
||||
const char* name() const override { return "Clear"; }
|
||||
|
||||
// TODO: this needs to be updated to return GrSurfaceProxy::UniqueID
|
||||
@ -68,6 +74,17 @@ private:
|
||||
fRenderTarget.reset(rt);
|
||||
}
|
||||
|
||||
GrClearBatch(const SkIRect& rect, GrColor color, GrRenderTarget* rt, bool fullScreen)
|
||||
: INHERITED(ClassID())
|
||||
, fClip(GrFixedClip(rect))
|
||||
, fColor(color)
|
||||
, fRenderTarget(rt) {
|
||||
if (fullScreen) {
|
||||
fClip.disableScissor();
|
||||
}
|
||||
this->setBounds(SkRect::Make(rect), HasAABloat::kNo, IsZeroArea::kNo);
|
||||
}
|
||||
|
||||
bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
|
||||
// This could be much more complicated. Currently we look at cases where the new clear
|
||||
// contains the old clear, or when the new clear is a subset of the old clear and is the
|
||||
|
@ -357,8 +357,8 @@ bool GrTessellatingPathRenderer::onDrawPath(const DrawPathArgs& args) {
|
||||
GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
|
||||
"GrTessellatingPathRenderer::onDrawPath");
|
||||
SkIRect clipBoundsI;
|
||||
args.fClip->getConservativeBounds(args.fRenderTargetContext->worstCaseWidth(),
|
||||
args.fRenderTargetContext->worstCaseHeight(),
|
||||
args.fClip->getConservativeBounds(args.fRenderTargetContext->width(),
|
||||
args.fRenderTargetContext->height(),
|
||||
&clipBoundsI);
|
||||
sk_sp<GrDrawOp> batch(TessellatingPathBatch::Create(args.fPaint->getColor(),
|
||||
*args.fShape,
|
||||
|
Loading…
Reference in New Issue
Block a user