From c1cdf21ab88b63c07990e6bbce559397bf207b47 Mon Sep 17 00:00:00 2001 From: "commit-bot@chromium.org" Date: Tue, 6 Aug 2013 15:07:23 +0000 Subject: Add blend optimization helpers and use to convert rect draws to clears. Committed: http://code.google.com/p/skia/source/detail?r=10537 R=robertphillips@google.com, jvanverth@google.com, reed@google.com Author: bsalomon@google.com Review URL: https://chromiumcodereview.appspot.com/21877006 git-svn-id: http://skia.googlecode.com/svn/trunk@10562 2bbb7eff-a529-9590-31e7-b0007b416f81 --- src/gpu/GrBlend.cpp | 154 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/gpu/GrBlend.h | 45 +++++++++++++++ src/gpu/GrContext.cpp | 90 ++++++++++++++++------------- src/gpu/GrDrawState.h | 25 ++------ src/gpu/GrPaint.cpp | 57 +++++++++++++++++++ 5 files changed, 313 insertions(+), 58 deletions(-) create mode 100644 src/gpu/GrBlend.cpp create mode 100644 src/gpu/GrBlend.h (limited to 'src') diff --git a/src/gpu/GrBlend.cpp b/src/gpu/GrBlend.cpp new file mode 100644 index 0000000000..c0621a9b3f --- /dev/null +++ b/src/gpu/GrBlend.cpp @@ -0,0 +1,154 @@ + +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrBlend.h" + +static inline GrBlendCoeff swap_coeff_src_dst(GrBlendCoeff coeff) { + switch (coeff) { + case kDC_GrBlendCoeff: + return kSC_GrBlendCoeff; + case kIDC_GrBlendCoeff: + return kISC_GrBlendCoeff; + case kDA_GrBlendCoeff: + return kSA_GrBlendCoeff; + case kIDA_GrBlendCoeff: + return kISA_GrBlendCoeff; + case kSC_GrBlendCoeff: + return kDC_GrBlendCoeff; + case kISC_GrBlendCoeff: + return kIDC_GrBlendCoeff; + case kSA_GrBlendCoeff: + return kDA_GrBlendCoeff; + case kISA_GrBlendCoeff: + return kIDA_GrBlendCoeff; + default: + return coeff; + } +} + +static inline unsigned saturated_add(unsigned a, unsigned b) { + SkASSERT(a <= 255); + SkASSERT(b <= 255); + unsigned sum = a + b; + if (sum > 255) { + sum = 255; + } + return sum; +} + +static GrColor add_colors(GrColor src, GrColor dst) { + unsigned r = saturated_add(GrColorUnpackR(src), GrColorUnpackR(dst)); + unsigned g = saturated_add(GrColorUnpackG(src), GrColorUnpackG(dst)); + unsigned b = saturated_add(GrColorUnpackB(src), GrColorUnpackB(dst)); + unsigned a = saturated_add(GrColorUnpackA(src), GrColorUnpackA(dst)); + return GrColorPackRGBA(r, g, b, a); +} + +static inline bool valid_color(uint32_t compFlags) { + return (kRGBA_GrColorComponentFlags & compFlags) == kRGBA_GrColorComponentFlags; +} + +static GrColor simplify_blend_term(GrBlendCoeff* srcCoeff, + GrColor srcColor, uint32_t srcCompFlags, + GrColor dstColor, uint32_t dstCompFlags, + GrColor constantColor) { + + GrAssert(!GrBlendCoeffRefsSrc(*srcCoeff)); + GrAssert(NULL != srcCoeff); + + // Check whether srcCoeff can be reduced to kOne or kZero based on known color inputs. + // We could pick out the coeff r,g,b,a values here and use them to compute the blend term color, + // if possible, below but that is not implemented now. + switch (*srcCoeff) { + case kIDC_GrBlendCoeff: + dstColor = ~dstColor; // fallthrough + case kDC_GrBlendCoeff: + if (valid_color(dstCompFlags)) { + if (0xffffffff == dstColor) { + *srcCoeff = kOne_GrBlendCoeff; + } else if (0 == dstColor) { + *srcCoeff = kZero_GrBlendCoeff; + } + } + break; + + case kIDA_GrBlendCoeff: + dstColor = ~dstColor; // fallthrough + case kDA_GrBlendCoeff: + if (kA_GrColorComponentFlag & dstCompFlags) { + if (0xff == GrColorUnpackA(dstColor)) { + *srcCoeff = kOne_GrBlendCoeff; + } else if (0 == GrColorUnpackA(dstColor)) { + *srcCoeff = kZero_GrBlendCoeff; + } + } + break; + + case kIConstC_GrBlendCoeff: + constantColor = ~constantColor; // fallthrough + case kConstC_GrBlendCoeff: + if (0xffffffff == constantColor) { + *srcCoeff = kOne_GrBlendCoeff; + } else if (0 == constantColor) { + *srcCoeff = kZero_GrBlendCoeff; + } + break; + + case kIConstA_GrBlendCoeff: + constantColor = ~constantColor; // fallthrough + case kConstA_GrBlendCoeff: + if (0xff == GrColorUnpackA(constantColor)) { + *srcCoeff = kOne_GrBlendCoeff; + } else if (0 == GrColorUnpackA(constantColor)) { + *srcCoeff = kZero_GrBlendCoeff; + } + break; + + default: + break; + } + // We may have invalidated these above and shouldn't read them again. + GR_DEBUGCODE(dstColor = constantColor = GrColor_ILLEGAL;) + + if (kZero_GrBlendCoeff == *srcCoeff || (valid_color(srcCompFlags) && 0 == srcColor)) { + *srcCoeff = kZero_GrBlendCoeff; + return 0; + } + + if (kOne_GrBlendCoeff == *srcCoeff && valid_color(srcCompFlags)) { + return srcColor; + } else { + return GrColor_ILLEGAL; + } +} + +GrColor GrSimplifyBlend(GrBlendCoeff* srcCoeff, + GrBlendCoeff* dstCoeff, + GrColor srcColor, uint32_t srcCompFlags, + GrColor dstColor, uint32_t dstCompFlags, + GrColor constantColor) { + GrColor srcTermColor = simplify_blend_term(srcCoeff, + srcColor, srcCompFlags, + dstColor, dstCompFlags, + constantColor); + + // We call the same function to simplify the dst blend coeff. We trick it out by swapping the + // src and dst. + GrBlendCoeff spoofedCoeff = swap_coeff_src_dst(*dstCoeff); + GrColor dstTermColor = simplify_blend_term(&spoofedCoeff, + dstColor, dstCompFlags, + srcColor, srcCompFlags, + constantColor); + *dstCoeff = swap_coeff_src_dst(spoofedCoeff); + + if (GrColor_ILLEGAL != srcTermColor && GrColor_ILLEGAL != dstTermColor) { + return add_colors(srcTermColor, dstTermColor); + } else { + return GrColor_ILLEGAL; + } +} diff --git a/src/gpu/GrBlend.h b/src/gpu/GrBlend.h new file mode 100644 index 0000000000..e70d945777 --- /dev/null +++ b/src/gpu/GrBlend.h @@ -0,0 +1,45 @@ + +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrTypes.h" +#include "GrColor.h" + +#ifndef GrBlend_DEFINED +#define GrBlend_DEFINED + +static inline bool GrBlendCoeffRefsSrc(GrBlendCoeff coeff) { + switch (coeff) { + case kSC_GrBlendCoeff: + case kISC_GrBlendCoeff: + case kSA_GrBlendCoeff: + case kISA_GrBlendCoeff: + return true; + default: + return false; + } +} + +static inline bool GrBlendCoeffRefsDst(GrBlendCoeff coeff) { + switch (coeff) { + case kDC_GrBlendCoeff: + case kIDC_GrBlendCoeff: + case kDA_GrBlendCoeff: + case kIDA_GrBlendCoeff: + return true; + default: + return false; + } +} + +GrColor GrSimplifyBlend(GrBlendCoeff* srcCoeff, + GrBlendCoeff* dstCoeff, + GrColor srcColor, uint32_t srcCompFlags, + GrColor dstColor, uint32_t dstCompFlags, + GrColor constantColor); + +#endif diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp index 20c633dc67..20320e8ce0 100644 --- a/src/gpu/GrContext.cpp +++ b/src/gpu/GrContext.cpp @@ -681,9 +681,8 @@ static bool isIRect(const SkRect& r) { static bool apply_aa_to_rect(GrDrawTarget* target, const SkRect& rect, SkScalar strokeWidth, - const SkMatrix* matrix, - SkMatrix* combinedMatrix, - SkRect* devRect, + const SkMatrix& combinedMatrix, + SkRect* devBoundRect, bool* useVertexCoverage) { // we use a simple coverage ramp to do aa on axis-aligned rects // we check if the rect will be axis-aligned, and the rect won't land on @@ -716,52 +715,32 @@ static bool apply_aa_to_rect(GrDrawTarget* target, #if defined(SHADER_AA_FILL_RECT) || !defined(IGNORE_ROT_AA_RECT_OPT) if (strokeWidth >= 0) { #endif - if (!drawState.getViewMatrix().preservesAxisAlignment()) { + if (!combinedMatrix.preservesAxisAlignment()) { return false; } - if (NULL != matrix && !matrix->preservesAxisAlignment()) { - return false; - } #if defined(SHADER_AA_FILL_RECT) || !defined(IGNORE_ROT_AA_RECT_OPT) } else { - if (!drawState.getViewMatrix().preservesAxisAlignment() && - !drawState.getViewMatrix().preservesRightAngles()) { - return false; - } - - if (NULL != matrix && !matrix->preservesRightAngles()) { + if (!combinedMatrix.preservesRightAngles()) { return false; } } #endif - *combinedMatrix = drawState.getViewMatrix(); - if (NULL != matrix) { - combinedMatrix->preConcat(*matrix); - -#if GR_DEBUG -#if defined(SHADER_AA_FILL_RECT) || !defined(IGNORE_ROT_AA_RECT_OPT) - if (strokeWidth >= 0) { -#endif - GrAssert(combinedMatrix->preservesAxisAlignment()); -#if defined(SHADER_AA_FILL_RECT) || !defined(IGNORE_ROT_AA_RECT_OPT) - } else { - GrAssert(combinedMatrix->preservesRightAngles()); - } -#endif -#endif - } - - combinedMatrix->mapRect(devRect, rect); + combinedMatrix.mapRect(devBoundRect, rect); if (strokeWidth < 0) { - return !isIRect(*devRect); + return !isIRect(*devBoundRect); } else { return true; } } +static inline bool rect_contains_inclusive(const SkRect& rect, const SkPoint& point) { + return point.fX >= rect.fLeft && point.fX <= rect.fRight && + point.fY >= rect.fTop && point.fY <= rect.fBottom; +} + void GrContext::drawRect(const GrPaint& paint, const SkRect& rect, SkScalar width, @@ -771,13 +750,48 @@ void GrContext::drawRect(const GrPaint& paint, AutoRestoreEffects are; GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW, &are); - SkRect devRect; - SkMatrix combinedMatrix; + SkMatrix combinedMatrix = target->drawState()->getViewMatrix(); + if (NULL != matrix) { + combinedMatrix.preConcat(*matrix); + } + + // Check if this is a full RT draw and can be replaced with a clear. + SkRect rtRect; + target->getDrawState().getRenderTarget()->getBoundsRect(&rtRect); + SkRect clipSpaceRTRect = rtRect; + bool checkClip = false; + if (NULL != this->getClip()) { + checkClip = true; + clipSpaceRTRect.offset(SkIntToScalar(this->getClip()->fOrigin.fX), + SkIntToScalar(this->getClip()->fOrigin.fY)); + } + // Does the clip contain the entire RT? + if (!checkClip || target->getClip()->fClipStack->quickContains(clipSpaceRTRect)) { + SkMatrix invM; + if (!combinedMatrix.invert(&invM)) { + return; + } + // Does the rect bound the RT? + SkPoint srcSpaceRTQuad[4]; + invM.mapRectToQuad(srcSpaceRTQuad, rtRect); + if (rect_contains_inclusive(rect, srcSpaceRTQuad[0]) && + rect_contains_inclusive(rect, srcSpaceRTQuad[1]) && + rect_contains_inclusive(rect, srcSpaceRTQuad[2]) && + rect_contains_inclusive(rect, srcSpaceRTQuad[3])) { + // Will it blend? + GrColor clearColor; + if (paint.isOpaqueAndConstantColor(&clearColor)) { + target->clear(NULL, clearColor); + return; + } + } + } + + SkRect devBoundRect; bool useVertexCoverage; bool needAA = paint.isAntiAlias() && !target->getDrawState().getRenderTarget()->isMultisampled(); - bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix, - &combinedMatrix, &devRect, + bool doAA = needAA && apply_aa_to_rect(target, rect, width, combinedMatrix, &devBoundRect, &useVertexCoverage); if (doAA) { GrDrawState::AutoViewMatrixRestore avmr; @@ -786,12 +800,12 @@ void GrContext::drawRect(const GrPaint& paint, } if (width >= 0) { fAARectRenderer->strokeAARect(this->getGpu(), target, - rect, combinedMatrix, devRect, + rect, combinedMatrix, devBoundRect, width, useVertexCoverage); } else { // filled AA rect fAARectRenderer->fillAARect(this->getGpu(), target, - rect, combinedMatrix, devRect, + rect, combinedMatrix, devBoundRect, useVertexCoverage); } return; diff --git a/src/gpu/GrDrawState.h b/src/gpu/GrDrawState.h index c006e6c5dd..785be77f58 100644 --- a/src/gpu/GrDrawState.h +++ b/src/gpu/GrDrawState.h @@ -9,6 +9,7 @@ #define GrDrawState_DEFINED #include "GrBackendEffectFactory.h" +#include "GrBlend.h" #include "GrColor.h" #include "GrEffectStage.h" #include "GrPaint.h" @@ -469,27 +470,11 @@ public: fCommon.fSrcBlend = srcCoeff; fCommon.fDstBlend = dstCoeff; #if GR_DEBUG - switch (dstCoeff) { - case kDC_GrBlendCoeff: - case kIDC_GrBlendCoeff: - case kDA_GrBlendCoeff: - case kIDA_GrBlendCoeff: - GrPrintf("Unexpected dst blend coeff. Won't work correctly with" - "coverage stages.\n"); - break; - default: - break; + if (GrBlendCoeffRefsDst(dstCoeff)) { + GrPrintf("Unexpected dst blend coeff. Won't work correctly with coverage stages.\n"); } - switch (srcCoeff) { - case kSC_GrBlendCoeff: - case kISC_GrBlendCoeff: - case kSA_GrBlendCoeff: - case kISA_GrBlendCoeff: - GrPrintf("Unexpected src blend coeff. Won't work correctly with" - "coverage stages.\n"); - break; - default: - break; + if (GrBlendCoeffRefsSrc(srcCoeff)) { + GrPrintf("Unexpected src blend coeff. Won't work correctly with coverage stages.\n"); } #endif } diff --git a/src/gpu/GrPaint.cpp b/src/gpu/GrPaint.cpp index d67f2e8707..0522e25085 100644 --- a/src/gpu/GrPaint.cpp +++ b/src/gpu/GrPaint.cpp @@ -8,6 +8,7 @@ #include "GrPaint.h" +#include "GrBlend.h" #include "effects/GrSimpleTextureEffect.h" void GrPaint::addColorTextureEffect(GrTexture* texture, const SkMatrix& matrix) { @@ -33,3 +34,59 @@ void GrPaint::addCoverageTextureEffect(GrTexture* texture, GrEffectRef* effect = GrSimpleTextureEffect::Create(texture, matrix, params); this->addCoverageEffect(effect)->unref(); } + +bool GrPaint::isOpaque() const { + return this->getOpaqueAndKnownColor(NULL, NULL); +} + +bool GrPaint::isOpaqueAndConstantColor(GrColor* color) const { + GrColor tempColor; + uint32_t colorComps; + if (this->getOpaqueAndKnownColor(&tempColor, &colorComps)) { + if (kRGBA_GrColorComponentFlags == colorComps) { + *color = tempColor; + return true; + } + } + return false; +} + +bool GrPaint::getOpaqueAndKnownColor(GrColor* solidColor, + uint32_t* solidColorKnownComponents) const { + + // TODO: Share this implementation with GrDrawState + + // Since fColorFilterXfermode is going away soon, we aren't attempting to handle anything but + // the default setting. + if (SkXfermode::kDst_Mode != fColorFilterXfermode) { + return false; + } + + GrColor coverage = GrColorPackRGBA(fCoverage, fCoverage, fCoverage, fCoverage); + uint32_t coverageComps = kRGBA_GrColorComponentFlags; + int count = fCoverageStages.count(); + for (int i = 0; i < count; ++i) { + (*fCoverageStages[i].getEffect())->getConstantColorComponents(&coverage, &coverageComps); + } + if (kRGBA_GrColorComponentFlags != coverageComps || 0xffffffff != coverage) { + return false; + } + + GrColor color = fColor; + uint32_t colorComps = kRGBA_GrColorComponentFlags; + count = fColorStages.count(); + for (int i = 0; i < count; ++i) { + (*fColorStages[i].getEffect())->getConstantColorComponents(&color, &colorComps); + } + + GrAssert((NULL == solidColor) == (NULL == solidColorKnownComponents)); + if (NULL != solidColor) { + *solidColor = color; + *solidColorKnownComponents = colorComps; + } + + GrBlendCoeff srcCoeff = fSrcBlendCoeff; + GrBlendCoeff dstCoeff = fDstBlendCoeff; + GrSimplifyBlend(&srcCoeff, &dstCoeff, color, colorComps, 0, 0, 0); + return kZero_GrBlendCoeff == dstCoeff && !GrBlendCoeffRefsDst(srcCoeff); +} -- cgit v1.2.3