diff options
author | 2014-12-17 13:37:13 -0800 | |
---|---|---|
committer | 2014-12-17 13:37:13 -0800 | |
commit | 8750924a1470e8215b2a344155259b93062d3fa2 (patch) | |
tree | 5a9756c583b04dd0e6248eb45ec219910c9c91e7 /src | |
parent | 3739913b6a5590336ede1a9b262556a516839f17 (diff) |
Add Coverage Drawing XP
BUG=skia:
Review URL: https://codereview.chromium.org/808813002
Diffstat (limited to 'src')
-rw-r--r-- | src/gpu/GrClipMaskManager.cpp | 79 | ||||
-rw-r--r-- | src/gpu/GrClipMaskManager.h | 1 | ||||
-rw-r--r-- | src/gpu/GrDrawState.cpp | 20 | ||||
-rw-r--r-- | src/gpu/GrDrawState.h | 22 | ||||
-rw-r--r-- | src/gpu/GrOptDrawState.cpp | 1 | ||||
-rw-r--r-- | src/gpu/GrProcessor.cpp | 2 | ||||
-rw-r--r-- | src/gpu/effects/GrCoverageSetOpXP.cpp | 235 | ||||
-rw-r--r-- | src/gpu/effects/GrCoverageSetOpXP.h | 109 | ||||
-rw-r--r-- | src/gpu/effects/GrPorterDuffXferProcessor.cpp | 73 |
9 files changed, 407 insertions, 135 deletions
diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipMaskManager.cpp index 5af6fb69ff..d663c7939a 100644 --- a/src/gpu/GrClipMaskManager.cpp +++ b/src/gpu/GrClipMaskManager.cpp @@ -330,39 +330,15 @@ bool GrClipMaskManager::setupClipping(GrDrawState* drawState, namespace { //////////////////////////////////////////////////////////////////////////////// -// set up the OpenGL blend function to perform the specified -// boolean operation for alpha clip mask creation -void setup_boolean_blendcoeffs(SkRegion::Op op, GrDrawState* drawState) { - // TODO: once we have a coverageDrawing XP this will all use that instead of PD - switch (op) { - case SkRegion::kReplace_Op: - drawState->setPorterDuffXPFactory(kOne_GrBlendCoeff, kZero_GrBlendCoeff); - break; - case SkRegion::kIntersect_Op: - drawState->setPorterDuffXPFactory(kDC_GrBlendCoeff, kZero_GrBlendCoeff); - break; - case SkRegion::kUnion_Op: - drawState->setPorterDuffXPFactory(kOne_GrBlendCoeff, kISC_GrBlendCoeff); - break; - case SkRegion::kXOR_Op: - drawState->setPorterDuffXPFactory(kIDC_GrBlendCoeff, kISC_GrBlendCoeff); - break; - case SkRegion::kDifference_Op: - drawState->setPorterDuffXPFactory(kZero_GrBlendCoeff, kISC_GrBlendCoeff); - break; - case SkRegion::kReverseDifference_Op: - drawState->setPorterDuffXPFactory(kIDC_GrBlendCoeff, kZero_GrBlendCoeff); - break; - default: - SkASSERT(false); - break; - } +// Set a coverage drawing XPF on the drawState for the given op and invertCoverage mode +void set_coverage_drawing_xpf(SkRegion::Op op, bool invertCoverage, GrDrawState* drawState) { + SkASSERT(op <= SkRegion::kLastOp); + drawState->setCoverageSetOpXPFactory(op, invertCoverage); } } //////////////////////////////////////////////////////////////////////////////// bool GrClipMaskManager::drawElement(GrDrawState* drawState, - GrColor color, GrTexture* target, const SkClipStack::Element* element, GrPathRenderer* pr) { @@ -370,6 +346,10 @@ bool GrClipMaskManager::drawElement(GrDrawState* drawState, drawState->setRenderTarget(target->asRenderTarget()); + // The color we use to draw does not matter since we will always be using a GrCoverageSetOpXP + // which ignores color. + GrColor color = GrColor_WHITE; + // TODO: Draw rrects directly here. switch (element->getType()) { case Element::kEmpty_Type: @@ -451,17 +431,19 @@ void GrClipMaskManager::mergeMask(GrDrawState* drawState, drawState->setRenderTarget(dstMask->asRenderTarget()); - setup_boolean_blendcoeffs(op, drawState); + // We want to invert the coverage here + set_coverage_drawing_xpf(op, false, drawState); SkMatrix sampleM; sampleM.setIDiv(srcMask->width(), srcMask->height()); - drawState->addColorProcessor( + drawState->addCoverageProcessor( GrTextureDomainEffect::Create(srcMask, sampleM, GrTextureDomain::MakeTexelDomain(srcMask, srcBound), GrTextureDomain::kDecal_Mode, GrTextureParams::kNone_FilterMode))->unref(); + // The color passed in here does not matter since the coverageSetOpXP won't read it. fClipTarget->drawSimpleRect(drawState, GrColor_WHITE, SkRect::Make(dstBound)); } @@ -567,9 +549,7 @@ GrTexture* GrClipMaskManager::createAlphaClipMask(int32_t elementsGenID, bool invert = element->isInverseFilled(); if (invert || SkRegion::kIntersect_Op == op || SkRegion::kReverseDifference_Op == op) { GrDrawState drawState(translate); - // We're drawing a coverage mask and want coverage to be run through the blend function. - drawState.enableState(GrDrawState::kCoverageDrawing_StateBit | - GrDrawState::kClip_StateBit); + drawState.enableState(GrDrawState::kClip_StateBit); GrPathRenderer* pr = NULL; bool useTemp = !this->canStencilAndDrawElement(&drawState, result, &pr, element); @@ -603,7 +583,7 @@ GrTexture* GrClipMaskManager::createAlphaClipMask(int32_t elementsGenID, invert ? 0xffffffff : 0x00000000, true, dst->asRenderTarget()); - setup_boolean_blendcoeffs(SkRegion::kReplace_Op, &drawState); + set_coverage_drawing_xpf(SkRegion::kReplace_Op, invert, &drawState); } else { // draw directly into the result with the stencil set to make the pixels affected // by the clip shape be non-zero. @@ -616,29 +596,29 @@ GrTexture* GrClipMaskManager::createAlphaClipMask(int32_t elementsGenID, 0xffff, 0xffff); drawState.setStencil(kStencilInElement); - setup_boolean_blendcoeffs(op, &drawState); + set_coverage_drawing_xpf(op, invert, &drawState); } - // We have to backup the drawstate because the drawElement call may call into - // renderers which consume it. - GrDrawState backupDrawState(drawState); - - if (!this->drawElement(&drawState, invert ? GrColor_TRANS_BLACK : - GrColor_WHITE, dst, element, pr)) { + if (!this->drawElement(&drawState, dst, element, pr)) { fAACache.reset(); return NULL; } + GrDrawState backgroundDrawState(translate); + backgroundDrawState.enableState(GrDrawState::kClip_StateBit); + backgroundDrawState.setRenderTarget(result->asRenderTarget()); + if (useTemp) { // Now draw into the accumulator using the real operation and the temp buffer as a // texture - this->mergeMask(&backupDrawState, + this->mergeMask(&backgroundDrawState, result, temp, op, maskSpaceIBounds, maskSpaceElementIBounds); } else { + set_coverage_drawing_xpf(op, !invert, &backgroundDrawState); // Draw to the exterior pixels (those with a zero stencil value). GR_STATIC_CONST_SAME_STENCIL(kDrawOutsideElement, kZero_StencilOp, @@ -647,19 +627,18 @@ GrTexture* GrClipMaskManager::createAlphaClipMask(int32_t elementsGenID, 0xffff, 0x0000, 0xffff); - backupDrawState.setStencil(kDrawOutsideElement); - fClipTarget->drawSimpleRect(&backupDrawState, - invert ? GrColor_WHITE : GrColor_TRANS_BLACK, - clipSpaceIBounds); + backgroundDrawState.setStencil(kDrawOutsideElement); + // The color passed in here does not matter since the coverageSetOpXP won't read it. + fClipTarget->drawSimpleRect(&backgroundDrawState, GrColor_WHITE, clipSpaceIBounds); } } else { GrDrawState drawState(translate); - drawState.enableState(GrDrawState::kCoverageDrawing_StateBit | - GrDrawState::kClip_StateBit); + drawState.enableState(GrDrawState::kClip_StateBit); // all the remaining ops can just be directly draw into the accumulation buffer - setup_boolean_blendcoeffs(op, &drawState); - this->drawElement(&drawState, GrColor_WHITE, result, element); + set_coverage_drawing_xpf(op, false, &drawState); + // The color passed in here does not matter since the coverageSetOpXP won't read it. + this->drawElement(&drawState, result, element); } } diff --git a/src/gpu/GrClipMaskManager.h b/src/gpu/GrClipMaskManager.h index f93fa4af0d..3aec257075 100644 --- a/src/gpu/GrClipMaskManager.h +++ b/src/gpu/GrClipMaskManager.h @@ -152,7 +152,6 @@ private: // desired blend operation. Optionally if the caller already selected a path renderer it can // be passed. Otherwise the function will select one if the element is a path. bool drawElement(GrDrawState*, - GrColor, GrTexture* target, const SkClipStack::Element*, GrPathRenderer* pr = NULL); diff --git a/src/gpu/GrDrawState.cpp b/src/gpu/GrDrawState.cpp index ebabb43ad2..711fdcb23a 100644 --- a/src/gpu/GrDrawState.cpp +++ b/src/gpu/GrDrawState.cpp @@ -185,21 +185,7 @@ bool GrDrawState::canUseFracCoveragePrimProc(GrColor color, const GrDrawTargetCa // so we don't have to pass in a seemingly known coverage this->calcCoverageInvariantOutput(GrColor_WHITE); return fXPFactory->canApplyCoverage(fColorProcInfo, fCoverageProcInfo, - this->isCoverageDrawing(), this->isColorWriteDisabled()); -} - -bool GrDrawState::hasSolidCoverage(const GrPrimitiveProcessor* pp) const { - // If we're drawing coverage directly then coverage is effectively treated as color. - if (this->isCoverageDrawing()) { - return true; - } - - if (this->numCoverageStages() > 0) { - return false; - } - - this->calcCoverageInvariantOutput(pp); - return fCoverageProcInfo.isSolidWhite(); + this->isColorWriteDisabled()); } //////////////////////////////////////////////////////////////////////////////s @@ -252,7 +238,7 @@ void GrDrawState::AutoRestoreEffects::set(GrDrawState* ds) { // Some blend modes allow folding a fractional coverage value into the color's alpha channel, while // others will blend incorrectly. bool GrDrawState::canTweakAlphaForCoverage() const { - return fXPFactory->canTweakAlphaForCoverage(this->isCoverageDrawing()); + return fXPFactory->canTweakAlphaForCoverage(); } //////////////////////////////////////////////////////////////////////////////// @@ -354,7 +340,7 @@ bool GrDrawState::willBlendWithDst(const GrPrimitiveProcessor* pp) const { this->calcColorInvariantOutput(pp); this->calcCoverageInvariantOutput(pp); return fXPFactory->willBlendWithDst(fColorProcInfo, fCoverageProcInfo, - this->isCoverageDrawing(), this->isColorWriteDisabled()); + this->isColorWriteDisabled()); } void GrDrawState::calcColorInvariantOutput(const GrPrimitiveProcessor* pp) const { diff --git a/src/gpu/GrDrawState.h b/src/gpu/GrDrawState.h index 8d7ec9891e..7d3c1e9843 100644 --- a/src/gpu/GrDrawState.h +++ b/src/gpu/GrDrawState.h @@ -19,6 +19,7 @@ #include "GrStencil.h" #include "GrXferProcessor.h" #include "SkMatrix.h" +#include "effects/GrCoverageSetOpXP.h" #include "effects/GrPorterDuffXferProcessor.h" #include "effects/GrSimpleTextureEffect.h" @@ -83,11 +84,6 @@ public: bool canUseFracCoveragePrimProc(GrColor color, const GrDrawTargetCaps& caps) const; /** - * Determines whether the output coverage is guaranteed to be one for all pixels hit by a draw. - */ - bool hasSolidCoverage(const GrPrimitiveProcessor*) const; - - /** * This function returns true if the render target destination pixel values will be read for * blending during draw. */ @@ -144,6 +140,10 @@ public: fXPFactory.reset(GrPorterDuffXPFactory::Create(src, dst)); } + void setCoverageSetOpXPFactory(SkRegion::Op regionOp, bool invertCoverage = false) { + fXPFactory.reset(GrCoverageSetOpXPFactory::Create(regionOp, invertCoverage)); + } + const GrFragmentProcessor* addColorProcessor(const GrFragmentProcessor* effect) { SkASSERT(effect); SkNEW_APPEND_TO_TARRAY(&fColorStages, GrFragmentStage, (effect)); @@ -416,21 +416,11 @@ public: */ kNoColorWrites_StateBit = 0x08, - /** - * Usually coverage is applied after color blending. The color is blended using the coeffs - * specified by setBlendFunc(). The blended color is then combined with dst using coeffs - * of src_coverage, 1-src_coverage. Sometimes we are explicitly drawing a coverage mask. In - * this case there is no distinction between coverage and color and the caller needs direct - * control over the blend coeffs. When set, there will be a single blend step controlled by - * setBlendFunc() which will use coverage*color as the src color. - */ - kCoverageDrawing_StateBit = 0x10, - kLast_StateBit = kCoverageDrawing_StateBit, + kLast_StateBit = kNoColorWrites_StateBit, }; bool isClipState() const { return 0 != (fFlagBits & kClip_StateBit); } bool isColorWriteDisabled() const { return 0 != (fFlagBits & kNoColorWrites_StateBit); } - bool isCoverageDrawing() const { return 0 != (fFlagBits & kCoverageDrawing_StateBit); } bool isDither() const { return 0 != (fFlagBits & kDither_StateBit); } bool isHWAntialias() const { return 0 != (fFlagBits & kHWAntialias_StateBit); } diff --git a/src/gpu/GrOptDrawState.cpp b/src/gpu/GrOptDrawState.cpp index b5fe8d5b60..93d90b0a25 100644 --- a/src/gpu/GrOptDrawState.cpp +++ b/src/gpu/GrOptDrawState.cpp @@ -55,7 +55,6 @@ GrOptDrawState::GrOptDrawState(const GrDrawState& drawState, optFlags = xferProcessor->getOptimizations(colorPOI, coveragePOI, - drawState.isCoverageDrawing(), drawState.isColorWriteDisabled(), drawState.getStencil().doesWrite(), &overrideColor, diff --git a/src/gpu/GrProcessor.cpp b/src/gpu/GrProcessor.cpp index d2ad7a5293..4f27404797 100644 --- a/src/gpu/GrProcessor.cpp +++ b/src/gpu/GrProcessor.cpp @@ -52,7 +52,7 @@ GrProcessorTestFactory<GrGeometryProcessor>::GetFactories() { */ static const int kFPFactoryCount = 37; static const int kGPFactoryCount = 14; -static const int kXPFactoryCount = 1; +static const int kXPFactoryCount = 2; template<> void GrProcessorTestFactory<GrFragmentProcessor>::VerifyFactoryCount() { diff --git a/src/gpu/effects/GrCoverageSetOpXP.cpp b/src/gpu/effects/GrCoverageSetOpXP.cpp new file mode 100644 index 0000000000..cddbbfb49e --- /dev/null +++ b/src/gpu/effects/GrCoverageSetOpXP.cpp @@ -0,0 +1,235 @@ + +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "effects/GrCoverageSetOpXP.h" +#include "GrColor.h" +#include "GrDrawTargetCaps.h" +#include "GrInvariantOutput.h" +#include "GrProcessor.h" +#include "GrProcOptInfo.h" +#include "gl/GrGLXferProcessor.h" +#include "gl/builders/GrGLFragmentShaderBuilder.h" +#include "gl/builders/GrGLProgramBuilder.h" + +class GrGLCoverageSetOpXP : public GrGLXferProcessor { +public: + GrGLCoverageSetOpXP(const GrProcessor&) {} + + ~GrGLCoverageSetOpXP() SK_OVERRIDE {} + + void emitCode(const EmitArgs& args) SK_OVERRIDE { + const GrCoverageSetOpXP& xp = args.fXP.cast<GrCoverageSetOpXP>(); + GrGLFPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder(); + + if (xp.invertCoverage()) { + fsBuilder->codeAppendf("%s = 1.0 - %s;", args.fOutputPrimary, args.fInputCoverage); + } else { + fsBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, args.fInputCoverage); + } + } + + void setData(const GrGLProgramDataManager&, const GrXferProcessor&) SK_OVERRIDE {}; + + static void GenKey(const GrProcessor& processor, const GrGLCaps& caps, + GrProcessorKeyBuilder* b) { + const GrCoverageSetOpXP& xp = processor.cast<GrCoverageSetOpXP>(); + uint32_t key = xp.invertCoverage() ? 0x0 : 0x1; + b->add32(key); + }; + +private: + typedef GrGLXferProcessor INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +GrCoverageSetOpXP::GrCoverageSetOpXP(SkRegion::Op regionOp, bool invertCoverage) + : fRegionOp(regionOp) + , fInvertCoverage(invertCoverage) { + this->initClassID<GrCoverageSetOpXP>(); +} + +GrCoverageSetOpXP::~GrCoverageSetOpXP() { +} + +void GrCoverageSetOpXP::getGLProcessorKey(const GrGLCaps& caps, GrProcessorKeyBuilder* b) const { + GrGLCoverageSetOpXP::GenKey(*this, caps, b); +} + +GrGLXferProcessor* GrCoverageSetOpXP::createGLInstance() const { + return SkNEW_ARGS(GrGLCoverageSetOpXP, (*this)); +} + +GrXferProcessor::OptFlags +GrCoverageSetOpXP::getOptimizations(const GrProcOptInfo& colorPOI, + const GrProcOptInfo& coveragePOI, + bool colorWriteDisabled, + bool doesStencilWrite, + GrColor* color, + const GrDrawTargetCaps& caps) { + // We never look at the color input + return GrXferProcessor::kIgnoreColor_OptFlag; +} + +void GrCoverageSetOpXP::getBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const { + switch (fRegionOp) { + case SkRegion::kReplace_Op: + blendInfo->fSrcBlend = kOne_GrBlendCoeff; + blendInfo->fDstBlend = kZero_GrBlendCoeff; + break; + case SkRegion::kIntersect_Op: + blendInfo->fSrcBlend = kDC_GrBlendCoeff; + blendInfo->fDstBlend = kZero_GrBlendCoeff; + break; + case SkRegion::kUnion_Op: + blendInfo->fSrcBlend = kOne_GrBlendCoeff; + blendInfo->fDstBlend = kISC_GrBlendCoeff; + break; + case SkRegion::kXOR_Op: + blendInfo->fSrcBlend = kIDC_GrBlendCoeff; + blendInfo->fDstBlend = kISC_GrBlendCoeff; + break; + case SkRegion::kDifference_Op: + blendInfo->fSrcBlend = kZero_GrBlendCoeff; + blendInfo->fDstBlend = kISC_GrBlendCoeff; + break; + case SkRegion::kReverseDifference_Op: + blendInfo->fSrcBlend = kIDC_GrBlendCoeff; + blendInfo->fDstBlend = kZero_GrBlendCoeff; + break; + } + blendInfo->fBlendConstant = 0; +} + +/////////////////////////////////////////////////////////////////////////////// + +GrCoverageSetOpXPFactory::GrCoverageSetOpXPFactory(SkRegion::Op regionOp, bool invertCoverage) + : fRegionOp(regionOp) + , fInvertCoverage(invertCoverage) { + this->initClassID<GrCoverageSetOpXPFactory>(); +} + +GrXPFactory* GrCoverageSetOpXPFactory::Create(SkRegion::Op regionOp, bool invertCoverage) { + switch (regionOp) { + case SkRegion::kReplace_Op: { + if (invertCoverage) { + static GrCoverageSetOpXPFactory gReplaceCDXPFI(regionOp, invertCoverage); + return SkRef(&gReplaceCDXPFI); + } else { + static GrCoverageSetOpXPFactory gReplaceCDXPF(regionOp, invertCoverage); + return SkRef(&gReplaceCDXPF); + } + break; + } + case SkRegion::kIntersect_Op: { + if (invertCoverage) { + static GrCoverageSetOpXPFactory gIntersectCDXPFI(regionOp, invertCoverage); + return SkRef(&gIntersectCDXPFI); + } else { + static GrCoverageSetOpXPFactory gIntersectCDXPF(regionOp, invertCoverage); + return SkRef(&gIntersectCDXPF); + } + break; + } + case SkRegion::kUnion_Op: { + if (invertCoverage) { + static GrCoverageSetOpXPFactory gUnionCDXPFI(regionOp, invertCoverage); + return SkRef(&gUnionCDXPFI); + } else { + static GrCoverageSetOpXPFactory gUnionCDXPF(regionOp, invertCoverage); + return SkRef(&gUnionCDXPF); + } + break; + } + case SkRegion::kXOR_Op: { + if (invertCoverage) { + static GrCoverageSetOpXPFactory gXORCDXPFI(regionOp, invertCoverage); + return SkRef(&gXORCDXPFI); + } else { + static GrCoverageSetOpXPFactory gXORCDXPF(regionOp, invertCoverage); + return SkRef(&gXORCDXPF); + } + break; + } + case SkRegion::kDifference_Op: { + if (invertCoverage) { + static GrCoverageSetOpXPFactory gDifferenceCDXPFI(regionOp, invertCoverage); + return SkRef(&gDifferenceCDXPFI); + } else { + static GrCoverageSetOpXPFactory gDifferenceCDXPF(regionOp, invertCoverage); + return SkRef(&gDifferenceCDXPF); + } + break; + } + case SkRegion::kReverseDifference_Op: { + if (invertCoverage) { + static GrCoverageSetOpXPFactory gRevDiffCDXPFI(regionOp, invertCoverage); + return SkRef(&gRevDiffCDXPFI); + } else { + static GrCoverageSetOpXPFactory gRevDiffCDXPF(regionOp, invertCoverage); + return SkRef(&gRevDiffCDXPF); + } + break; + } + default: + return NULL; + } +} + +GrXferProcessor* GrCoverageSetOpXPFactory::createXferProcessor(const GrProcOptInfo& /* colorPOI*/, + const GrProcOptInfo& covPOI) const { + return GrCoverageSetOpXP::Create(fRegionOp, fInvertCoverage); +} + +bool GrCoverageSetOpXPFactory::willBlendWithDst(const GrProcOptInfo& colorPOI, + const GrProcOptInfo& coveragePOI, + bool colorWriteDisabled) const { + // TODO: once all SkXferEffects are XP's then we will never reads dst here since only XP's + // will readDst and this XP doesn't read dst. + if (coveragePOI.readsDst()) { + return true; + } + + // Besides Replace all other SkRegion ops will either have a src coeff that references dst or a + // non zero dst coeff + return SkRegion::kReplace_Op != fRegionOp; +} + +bool GrCoverageSetOpXPFactory::getOpaqueAndKnownColor(const GrProcOptInfo& colorPOI, + const GrProcOptInfo& coveragePOI, + GrColor* solidColor, + uint32_t* solidColorKnownComponents) const { + if (!coveragePOI.isSolidWhite()) { + return false; + } + + SkASSERT((NULL == solidColor) == (NULL == solidColorKnownComponents)); + + bool opaque = SkRegion::kReplace_Op == fRegionOp; + if (solidColor) { + if (opaque) { + *solidColor = GrColor_WHITE; + *solidColorKnownComponents = kRGBA_GrColorComponentFlags; + } else { + solidColorKnownComponents = 0; + } + } + return opaque; +} + +GR_DEFINE_XP_FACTORY_TEST(GrCoverageSetOpXPFactory); + +GrXPFactory* GrCoverageSetOpXPFactory::TestCreate(SkRandom* random, + GrContext*, + const GrDrawTargetCaps&, + GrTexture*[]) { + SkRegion::Op regionOp = SkRegion::Op(random->nextULessThan(SkRegion::kLastOp + 1)); + bool invertCoverage = random->nextBool(); + return GrCoverageSetOpXPFactory::Create(regionOp, invertCoverage); +} + diff --git a/src/gpu/effects/GrCoverageSetOpXP.h b/src/gpu/effects/GrCoverageSetOpXP.h new file mode 100644 index 0000000000..8f85d0688e --- /dev/null +++ b/src/gpu/effects/GrCoverageSetOpXP.h @@ -0,0 +1,109 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrCoverageSetOpXP_DEFINED +#define GrCoverageSetOpXP_DEFINED + +#include "GrTypes.h" +#include "GrXferProcessor.h" +#include "SkRegion.h" + +class GrInvariantOutput; +class GrProcOptInfo; + +/** + * This xfer processor directly blends the the src coverage with the dst using a set operator. It is + * useful for rendering coverage masks using CSG. It can optionally invert the src coverage before + * applying the set operator. + * */ +class GrCoverageSetOpXP : public GrXferProcessor { +public: + static GrXferProcessor* Create(SkRegion::Op regionOp, bool invertCoverage) { + return SkNEW_ARGS(GrCoverageSetOpXP, (regionOp, invertCoverage)); + } + + ~GrCoverageSetOpXP() SK_OVERRIDE; + + virtual const char* name() const { return "Coverage Set Op"; } + + void getGLProcessorKey(const GrGLCaps& caps, GrProcessorKeyBuilder* b) const SK_OVERRIDE; + + GrGLXferProcessor* createGLInstance() const SK_OVERRIDE; + + bool hasSecondaryOutput() const SK_OVERRIDE { return false; } + + GrXferProcessor::OptFlags getOptimizations(const GrProcOptInfo& colorPOI, + const GrProcOptInfo& coveragePOI, + bool colorWriteDisabled, + bool doesStencilWrite, + GrColor* color, + const GrDrawTargetCaps& caps) SK_OVERRIDE; + + void getBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const SK_OVERRIDE; + + bool invertCoverage() const { return fInvertCoverage; } + +private: + GrCoverageSetOpXP(SkRegion::Op regionOp, bool fInvertCoverage); + + bool onIsEqual(const GrXferProcessor& xpBase) const SK_OVERRIDE { + const GrCoverageSetOpXP& xp = xpBase.cast<GrCoverageSetOpXP>(); + return (fRegionOp == xp.fRegionOp && + fInvertCoverage == xp.fInvertCoverage); + } + + SkRegion::Op fRegionOp; + bool fInvertCoverage; + + typedef GrXferProcessor INHERITED; +}; + +/////////////////////////////////////////////////////////////////////////////// + +class GrCoverageSetOpXPFactory : public GrXPFactory { +public: + static GrXPFactory* Create(SkRegion::Op regionOp, bool invertCoverage = false); + + GrXferProcessor* createXferProcessor(const GrProcOptInfo& colorPOI, + const GrProcOptInfo& coveragePOI) const SK_OVERRIDE; + + bool supportsRGBCoverage(GrColor knownColor, uint32_t knownColorFlags) const SK_OVERRIDE { + return true; + } + + bool canApplyCoverage(const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI, + bool colorWriteDisabled) const SK_OVERRIDE { + return true; + } + + bool willBlendWithDst(const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI, + bool colorWriteDisabled) const SK_OVERRIDE; + + bool canTweakAlphaForCoverage() const SK_OVERRIDE { return false; } + + bool getOpaqueAndKnownColor(const GrProcOptInfo& colorPOI, + const GrProcOptInfo& coveragePOI, + GrColor* solidColor, + uint32_t* solidColorKnownComponents) const SK_OVERRIDE; + +private: + GrCoverageSetOpXPFactory(SkRegion::Op regionOp, bool invertCoverage); + + bool onIsEqual(const GrXPFactory& xpfBase) const SK_OVERRIDE { + const GrCoverageSetOpXPFactory& xpf = xpfBase.cast<GrCoverageSetOpXPFactory>(); + return fRegionOp == xpf.fRegionOp; + } + + GR_DECLARE_XP_FACTORY_TEST; + + SkRegion::Op fRegionOp; + bool fInvertCoverage; + + typedef GrXPFactory INHERITED; +}; +#endif + diff --git a/src/gpu/effects/GrPorterDuffXferProcessor.cpp b/src/gpu/effects/GrPorterDuffXferProcessor.cpp index bf48379bda..a091a48b08 100644 --- a/src/gpu/effects/GrPorterDuffXferProcessor.cpp +++ b/src/gpu/effects/GrPorterDuffXferProcessor.cpp @@ -8,17 +8,17 @@ #include "effects/GrPorterDuffXferProcessor.h" #include "GrBlend.h" -#include "GrDrawState.h" #include "GrDrawTargetCaps.h" #include "GrInvariantOutput.h" #include "GrProcessor.h" +#include "GrProcOptInfo.h" #include "GrTypes.h" #include "GrXferProcessor.h" #include "gl/GrGLXferProcessor.h" #include "gl/builders/GrGLFragmentShaderBuilder.h" #include "gl/builders/GrGLProgramBuilder.h" -static bool can_tweak_alpha_for_coverage(GrBlendCoeff dstCoeff, bool isCoverageDrawing) { +static bool can_tweak_alpha_for_coverage(GrBlendCoeff dstCoeff) { /* The fractional coverage is f. The src and dst coeffs are Cs and Cd. @@ -27,14 +27,10 @@ static bool can_tweak_alpha_for_coverage(GrBlendCoeff dstCoeff, bool isCoverageD we're replacing S with S'=fS. It's obvious that that first term will always be ok. The second term can be rearranged as [1-(1-Cd)f]D. By substituting in the various possibilities for Cd we find that only 1, ISA, and ISC produce the correct destination when applied to S' and D. - Also, if we're directly rendering coverage (isCoverageDrawing) then coverage is treated as - color by definition. */ - // TODO: Once we have a CoverageDrawing XP, we don't need to check is CoverageDrawing here return kOne_GrBlendCoeff == dstCoeff || kISA_GrBlendCoeff == dstCoeff || - kISC_GrBlendCoeff == dstCoeff || - isCoverageDrawing; + kISC_GrBlendCoeff == dstCoeff; } class GrGLPorterDuffXferProcessor : public GrGLXferProcessor { @@ -128,14 +124,9 @@ GrGLXferProcessor* GrPorterDuffXferProcessor::createGLInstance() const { return SkNEW_ARGS(GrGLPorterDuffXferProcessor, (*this)); } -void GrPorterDuffXferProcessor::onComputeInvariantOutput(GrInvariantOutput* inout) const { - inout->setToUnknown(GrInvariantOutput::kWill_ReadInput); -} - GrXferProcessor::OptFlags GrPorterDuffXferProcessor::getOptimizations(const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI, - bool isCoverageDrawing, bool colorWriteDisabled, bool doesStencilWrite, GrColor* overrideColor, @@ -153,11 +144,10 @@ GrPorterDuffXferProcessor::getOptimizations(const GrProcOptInfo& colorPOI, } else { optFlags = this->internalGetOptimizations(colorPOI, coveragePOI, - isCoverageDrawing, colorWriteDisabled, doesStencilWrite); } - this->calcOutputTypes(optFlags, caps, isCoverageDrawing || coveragePOI.isSolidWhite(), + this->calcOutputTypes(optFlags, caps, coveragePOI.isSolidWhite(), colorPOI.readsDst() || coveragePOI.readsDst()); return optFlags; } @@ -208,7 +198,6 @@ void GrPorterDuffXferProcessor::calcOutputTypes(GrXferProcessor::OptFlags optFla GrXferProcessor::OptFlags GrPorterDuffXferProcessor::internalGetOptimizations(const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI, - bool isCoverageDrawing, bool colorWriteDisabled, bool doesStencilWrite) { if (colorWriteDisabled) { @@ -218,13 +207,9 @@ GrPorterDuffXferProcessor::internalGetOptimizations(const GrProcOptInfo& colorPO bool srcAIsOne; bool hasCoverage; - if (isCoverageDrawing) { - srcAIsOne = colorPOI.isOpaque() && coveragePOI.isOpaque(); - hasCoverage = false; - } else { - srcAIsOne = colorPOI.isOpaque(); - hasCoverage = !coveragePOI.isSolidWhite(); - } + + srcAIsOne = colorPOI.isOpaque(); + hasCoverage = !coveragePOI.isSolidWhite(); bool dstCoeffIsOne = kOne_GrBlendCoeff == fDstBlend || (kSA_GrBlendCoeff == fDstBlend && srcAIsOne); @@ -262,13 +247,10 @@ GrPorterDuffXferProcessor::internalGetOptimizations(const GrProcOptInfo& colorPO GrXferProcessor::kIgnoreCoverage_OptFlag; } } - } else if (isCoverageDrawing) { - // we have coverage but we aren't distinguishing it from alpha by request. - return GrXferProcessor::kSetCoverageDrawing_OptFlag; - } else { + } else { // check whether coverage can be safely rolled into alpha // of if we can skip color computation and just emit coverage - if (can_tweak_alpha_for_coverage(fDstBlend, isCoverageDrawing)) { + if (can_tweak_alpha_for_coverage(fDstBlend)) { return GrXferProcessor::kSetCoverageDrawing_OptFlag; } if (dstCoeffIsZero) { @@ -418,9 +400,8 @@ bool GrPorterDuffXPFactory::supportsRGBCoverage(GrColor /*knownColor*/, bool GrPorterDuffXPFactory::canApplyCoverage(const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI, - bool isCoverageDrawing, bool colorWriteDisabled) const { - bool srcAIsOne = colorPOI.isOpaque() && (!isCoverageDrawing || coveragePOI.isOpaque()); + bool srcAIsOne = colorPOI.isOpaque(); if (colorWriteDisabled) { return true; @@ -437,24 +418,19 @@ bool GrPorterDuffXPFactory::canApplyCoverage(const GrProcOptInfo& colorPOI, // if we don't have coverage we can check whether the dst // has to read at all. - if (isCoverageDrawing) { - // we have coverage but we aren't distinguishing it from alpha by request. + // check whether coverage can be safely rolled into alpha + // of if we can skip color computation and just emit coverage + if (this->canTweakAlphaForCoverage()) { return true; - } else { - // check whether coverage can be safely rolled into alpha - // of if we can skip color computation and just emit coverage - if (this->canTweakAlphaForCoverage(isCoverageDrawing)) { - return true; - } - if (dstCoeffIsZero) { - if (kZero_GrBlendCoeff == fSrcCoeff) { - return true; - } else if (srcAIsOne) { - return true; - } - } else if (dstCoeffIsOne) { + } + if (dstCoeffIsZero) { + if (kZero_GrBlendCoeff == fSrcCoeff) { return true; + } else if (srcAIsOne) { + return true; } + } else if (dstCoeffIsOne) { + return true; } // TODO: once all SkXferEffects are XP's then we will never reads dst here since only XP's @@ -469,9 +445,8 @@ bool GrPorterDuffXPFactory::canApplyCoverage(const GrProcOptInfo& colorPOI, bool GrPorterDuffXPFactory::willBlendWithDst(const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI, - bool isCoverageDrawing, bool colorWriteDisabled) const { - if (!(isCoverageDrawing || coveragePOI.isSolidWhite())) { + if (!coveragePOI.isSolidWhite()) { return true; } @@ -485,7 +460,7 @@ bool GrPorterDuffXPFactory::willBlendWithDst(const GrProcOptInfo& colorPOI, return true; } - bool srcAIsOne = colorPOI.isOpaque() && (!isCoverageDrawing || coveragePOI.isOpaque()); + bool srcAIsOne = colorPOI.isOpaque(); if (!(kZero_GrBlendCoeff == fDstCoeff || (kISA_GrBlendCoeff == fDstCoeff && srcAIsOne))) { @@ -495,8 +470,8 @@ bool GrPorterDuffXPFactory::willBlendWithDst(const GrProcOptInfo& colorPOI, return false; } -bool GrPorterDuffXPFactory::canTweakAlphaForCoverage(bool isCoverageDrawing) const { - return can_tweak_alpha_for_coverage(fDstCoeff, isCoverageDrawing); +bool GrPorterDuffXPFactory::canTweakAlphaForCoverage() const { + return can_tweak_alpha_for_coverage(fDstCoeff); } bool GrPorterDuffXPFactory::getOpaqueAndKnownColor(const GrProcOptInfo& colorPOI, |