Add Coverage Drawing XP

BUG=skia:

Review URL: https://codereview.chromium.org/808813002
This commit is contained in:
egdaniel 2014-12-17 13:37:13 -08:00 committed by Commit bot
parent 3739913b6a
commit 8750924a14
12 changed files with 417 additions and 158 deletions

View File

@ -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',

View File

@ -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,

View File

@ -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,

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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 {

View File

@ -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"
@ -82,11 +83,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); }

View File

@ -55,7 +55,6 @@ GrOptDrawState::GrOptDrawState(const GrDrawState& drawState,
optFlags = xferProcessor->getOptimizations(colorPOI,
coveragePOI,
drawState.isCoverageDrawing(),
drawState.isColorWriteDisabled(),
drawState.getStencil().doesWrite(),
&overrideColor,

View File

@ -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() {

View File

@ -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);
}

View File

@ -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

View File

@ -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,