aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar egdaniel <egdaniel@google.com>2014-12-17 13:37:13 -0800
committerGravatar Commit bot <commit-bot@chromium.org>2014-12-17 13:37:13 -0800
commit8750924a1470e8215b2a344155259b93062d3fa2 (patch)
tree5a9756c583b04dd0e6248eb45ec219910c9c91e7 /src
parent3739913b6a5590336ede1a9b262556a516839f17 (diff)
Add Coverage Drawing XP
Diffstat (limited to 'src')
-rw-r--r--src/gpu/GrClipMaskManager.cpp79
-rw-r--r--src/gpu/GrClipMaskManager.h1
-rw-r--r--src/gpu/GrDrawState.cpp20
-rw-r--r--src/gpu/GrDrawState.h22
-rw-r--r--src/gpu/GrOptDrawState.cpp1
-rw-r--r--src/gpu/GrProcessor.cpp2
-rw-r--r--src/gpu/effects/GrCoverageSetOpXP.cpp235
-rw-r--r--src/gpu/effects/GrCoverageSetOpXP.h109
-rw-r--r--src/gpu/effects/GrPorterDuffXferProcessor.cpp73
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,