diff options
-rw-r--r-- | gyp/gpu.gypi | 2 | ||||
-rw-r--r-- | include/gpu/GrXferProcessor.h | 19 | ||||
-rw-r--r-- | include/gpu/effects/GrPorterDuffXferProcessor.h | 12 | ||||
-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 |
12 files changed, 417 insertions, 158 deletions
diff --git a/gyp/gpu.gypi b/gyp/gpu.gypi index 16ff3aeae0..a16617f4e5 100644 --- a/gyp/gpu.gypi +++ b/gyp/gpu.gypi @@ -177,6 +177,8 @@ '<(skia_src_path)/gpu/effects/Gr1DKernelEffect.h', '<(skia_src_path)/gpu/effects/GrConfigConversionEffect.cpp', '<(skia_src_path)/gpu/effects/GrConfigConversionEffect.h', + '<(skia_src_path)/gpu/effects/GrCoverageSetOpXP.cpp', + '<(skia_src_path)/gpu/effects/GrCoverageSetOpXP.h', '<(skia_src_path)/gpu/effects/GrBezierEffect.cpp', '<(skia_src_path)/gpu/effects/GrBezierEffect.h', '<(skia_src_path)/gpu/effects/GrConvolutionEffect.cpp', diff --git a/include/gpu/GrXferProcessor.h b/include/gpu/GrXferProcessor.h index bab6141f44..80e375c03c 100644 --- a/include/gpu/GrXferProcessor.h +++ b/include/gpu/GrXferProcessor.h @@ -86,11 +86,9 @@ public: * A caller who calls this function on a XP is required to honor the returned OptFlags * and color values for its draw. */ - // TODO: remove need for isCoverageDrawing once coverageDrawing is its own XP. // TODO: remove need for colorWriteDisabled once colorWriteDisabled is its own XP. virtual OptFlags getOptimizations(const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI, - bool isCoverageDrawing, bool colorWriteDisabled, bool doesStencilWrite, GrColor* overrideColor, @@ -127,7 +125,6 @@ public: return this->onIsEqual(that); } - protected: GrXferProcessor() : fWillReadDstColor(false) {} @@ -138,11 +135,6 @@ protected: */ void setWillReadDstColor() { fWillReadDstColor = true; } - /** - * Subclass implements this to support getConstantColorComponents(...). - */ - virtual void onComputeInvariantOutput(GrInvariantOutput* inout) const = 0; - private: virtual bool onIsEqual(const GrXferProcessor&) const = 0; @@ -181,30 +173,27 @@ public: * fractional pixel coverage generated by the fragment shader. * * This function considers the known color and coverage input into the xfer processor and - * certain state information (isCoverageDrawing and colorWriteDisabled) to determine whether + * certain state information (colorWriteDisabled) to determine whether * coverage can be handled correctly. */ - // TODO: remove need for isCoverageDrawing once coverageDrawing is its own XP. // TODO: remove need for colorWriteDisabled once colorWriteDisabled is its own XP. virtual bool canApplyCoverage(const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI, - bool isCoverageDrawing, bool colorWriteDisabled) const = 0; + bool colorWriteDisabled) const = 0; /** * This function returns true if the destination pixel values will be read for blending during * draw. */ - // TODO: remove need for isCoverageDrawing once coverageDrawing is its own XP. // TODO: remove need for colorWriteDisabled once only XP can read dst. virtual bool willBlendWithDst(const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI, - bool isCoverageDrawing, bool colorWriteDisabled) const = 0; + bool colorWriteDisabled) const = 0; /** * Determines whether multiplying the computed per-pixel color by the pixel's fractional * coverage before the blend will give the correct final destination color. In general it * will not as coverage is applied after blending. */ - // TODO: remove need for isCoverageDrawing once coverageDrawing is its own XP. - virtual bool canTweakAlphaForCoverage(bool isCoverageDrawing) const = 0; + virtual bool canTweakAlphaForCoverage() const = 0; virtual bool getOpaqueAndKnownColor(const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI, GrColor* solidColor, diff --git a/include/gpu/effects/GrPorterDuffXferProcessor.h b/include/gpu/effects/GrPorterDuffXferProcessor.h index a348a0255b..bcfd935bf2 100644 --- a/include/gpu/effects/GrPorterDuffXferProcessor.h +++ b/include/gpu/effects/GrPorterDuffXferProcessor.h @@ -12,8 +12,8 @@ #include "GrXferProcessor.h" #include "SkXfermode.h" -class GrDrawState; class GrInvariantOutput; +class GrProcOptInfo; class GrPorterDuffXferProcessor : public GrXferProcessor { public: @@ -68,7 +68,6 @@ public: GrXferProcessor::OptFlags getOptimizations(const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI, - bool isCoverageDrawing, bool colorWriteDisabled, bool doesStencilWrite, GrColor* overrideColor, @@ -95,11 +94,8 @@ private: return true; } - void onComputeInvariantOutput(GrInvariantOutput* inout) const SK_OVERRIDE; - GrXferProcessor::OptFlags internalGetOptimizations(const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI, - bool isCoverageDrawing, bool colorWriteDisabled, bool doesStencilWrite); @@ -135,12 +131,12 @@ public: bool supportsRGBCoverage(GrColor knownColor, uint32_t knownColorFlags) const SK_OVERRIDE; bool canApplyCoverage(const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI, - bool isCoverageDrawing, bool colorWriteDisabled) const SK_OVERRIDE; + bool colorWriteDisabled) const SK_OVERRIDE; bool willBlendWithDst(const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI, - bool isCoverageDrawing, bool colorWriteDisabled) const SK_OVERRIDE; + bool colorWriteDisabled) const SK_OVERRIDE; - bool canTweakAlphaForCoverage(bool isCoverageDrawing) const SK_OVERRIDE; + bool canTweakAlphaForCoverage() const SK_OVERRIDE; bool getOpaqueAndKnownColor(const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI, 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, |