Add support for blending of LCD for all blend modes.

BUG=skia:

Review URL: https://codereview.chromium.org/1313623002
This commit is contained in:
egdaniel 2015-09-15 09:31:40 -07:00 committed by Commit bot
parent 79bd2aee8c
commit 723b0501e2
8 changed files with 402 additions and 20 deletions

133
gm/lcdblendmodes.cpp Normal file
View File

@ -0,0 +1,133 @@
/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/*
* Tests text rendering with LCD and the various blend modes.
*/
#include "gm.h"
#include "SkCanvas.h"
#include "SkGradientShader.h"
namespace skiagm {
static const int kColWidth = 180;
static const int kNumCols = 4;
static const int kWidth = kColWidth * kNumCols;
static const int kHeight = 750;
static SkShader* make_shader(const SkRect& bounds) {
const SkPoint pts[] = {
{ bounds.left(), bounds.top() },
{ bounds.right(), bounds.bottom() },
};
const SkColor colors[] = {
SK_ColorRED, SK_ColorGREEN,
};
return SkGradientShader::CreateLinear(pts,
colors, nullptr, SK_ARRAY_COUNT(colors),
SkShader::kRepeat_TileMode);
}
class LcdBlendGM : public skiagm::GM {
public:
LcdBlendGM() {
const int kPointSize = 25;
fTextHeight = SkIntToScalar(kPointSize);
}
protected:
SkString onShortName() override {
SkString name("lcdblendmodes");
name.append(sk_tool_utils::major_platform_os_name());
return name;
}
SkISize onISize() override { return SkISize::Make(kWidth, kHeight); }
void onDraw(SkCanvas* canvas) override {
this->drawColumn(canvas, SK_ColorBLACK, SK_ColorWHITE, false);
canvas->translate(SkIntToScalar(kColWidth), 0);
this->drawColumn(canvas, SK_ColorWHITE, SK_ColorBLACK, false);
canvas->translate(SkIntToScalar(kColWidth), 0);
this->drawColumn(canvas, SK_ColorGREEN, SK_ColorMAGENTA, false);
canvas->translate(SkIntToScalar(kColWidth), 0);
this->drawColumn(canvas, SK_ColorCYAN, SK_ColorMAGENTA, true);
}
void drawColumn(SkCanvas* canvas, SkColor backgroundColor, SkColor textColor, bool useGrad) {
const struct {
SkXfermode::Mode fMode;
const char* fLabel;
} gModes[] = {
{ SkXfermode::kClear_Mode, "Clear" },
{ SkXfermode::kSrc_Mode, "Src" },
{ SkXfermode::kDst_Mode, "Dst" },
{ SkXfermode::kSrcOver_Mode, "SrcOver" },
{ SkXfermode::kDstOver_Mode, "DstOver" },
{ SkXfermode::kSrcIn_Mode, "SrcIn" },
{ SkXfermode::kDstIn_Mode, "DstIn" },
{ SkXfermode::kSrcOut_Mode, "SrcOut" },
{ SkXfermode::kDstOut_Mode, "DstOut" },
{ SkXfermode::kSrcATop_Mode, "SrcATop" },
{ SkXfermode::kDstATop_Mode, "DstATop" },
{ SkXfermode::kXor_Mode, "Xor" },
{ SkXfermode::kPlus_Mode, "Plus" },
{ SkXfermode::kModulate_Mode, "Modulate" },
{ SkXfermode::kScreen_Mode, "Screen" },
{ SkXfermode::kOverlay_Mode, "Overlay" },
{ SkXfermode::kDarken_Mode, "Darken" },
{ SkXfermode::kLighten_Mode, "Lighten" },
{ SkXfermode::kColorDodge_Mode, "ColorDodge" },
{ SkXfermode::kColorBurn_Mode, "ColorBurn" },
{ SkXfermode::kHardLight_Mode, "HardLight" },
{ SkXfermode::kSoftLight_Mode, "SoftLight" },
{ SkXfermode::kDifference_Mode, "Difference" },
{ SkXfermode::kExclusion_Mode, "Exclusion" },
{ SkXfermode::kMultiply_Mode, "Multiply" },
{ SkXfermode::kHue_Mode, "Hue" },
{ SkXfermode::kSaturation_Mode, "Saturation" },
{ SkXfermode::kColor_Mode, "Color" },
{ SkXfermode::kLuminosity_Mode, "Luminosity" },
};
// Draw background rect
SkPaint backgroundPaint;
backgroundPaint.setColor(backgroundColor);
canvas->drawRectCoords(0, 0, SkIntToScalar(kColWidth), SkIntToScalar(kHeight),
backgroundPaint);
SkScalar y = fTextHeight;
for (size_t m = 0; m < SK_ARRAY_COUNT(gModes); m++) {
SkAutoTUnref<SkXfermode> xfermode(SkXfermode::Create(gModes[m].fMode));
SkPaint paint;
paint.setColor(textColor);
paint.setAntiAlias(true);
paint.setSubpixelText(true);
paint.setLCDRenderText(true);
paint.setTextSize(fTextHeight);
paint.setXfermode(xfermode);
sk_tool_utils::set_portable_typeface(&paint);
if (useGrad) {
SkRect r;
r.setXYWH(0, y - fTextHeight, SkIntToScalar(kColWidth), fTextHeight);
paint.setShader(make_shader(r))->unref();
}
SkString string(gModes[m].fLabel);
canvas->drawText(gModes[m].fLabel, string.size(), 0, y, paint);
y+=fTextHeight;
}
}
private:
SkScalar fTextHeight;
typedef skiagm::GM INHERITED;
};
//////////////////////////////////////////////////////////////////////////////
DEF_GM( return new LcdBlendGM; )
}

View File

@ -18,7 +18,9 @@ class GrPorterDuffXPFactory : public GrXPFactory {
public:
static GrXPFactory* Create(SkXfermode::Mode mode);
bool supportsRGBCoverage(GrColor knownColor, uint32_t knownColorFlags) const override;
bool supportsRGBCoverage(GrColor /*knownColor*/, uint32_t /*knownColorFlags*/) const override {
return true;
}
void getInvariantBlendedColor(const GrProcOptInfo& colorPOI,
GrXPFactory::InvariantBlendedColor*) const override;

View File

@ -105,3 +105,4 @@ void GrPipelineBuilder::calcCoverageInvariantOutput(const GrDrawBatch* batch) co
fCoverageProcInfo.calcCoverageWithBatch(batch, fCoverageFragmentProcessors.begin(),
this->numCoverageFragmentProcessors());
}

View File

@ -33,11 +33,13 @@ void GrProcOptInfo::calcWithInitialValues(const GrFragmentProcessor * const proc
int cnt,
GrColor startColor,
GrColorComponentFlags flags,
bool areCoverageStages) {
bool areCoverageStages,
bool isLCD) {
GrInitInvariantOutput out;
out.fIsSingleComponent = areCoverageStages;
out.fColor = startColor;
out.fValidFlags = flags;
out.fIsLCDCoverage = isLCD;
fInOut.reset(out);
this->internalCalc(processors, cnt, false);
}

View File

@ -31,7 +31,7 @@ public:
, fReadsFragPosition(false) {}
void calcWithInitialValues(const GrFragmentProcessor* const *, int cnt, GrColor startColor,
GrColorComponentFlags, bool areCoverageStages);
GrColorComponentFlags, bool areCoverageStages, bool isLCD = false);
void calcColorWithBatch(const GrDrawBatch*, const GrFragmentProcessor* const[], int cnt);
void calcCoverageWithBatch(const GrDrawBatch*, const GrFragmentProcessor* const[], int cnt);

View File

@ -80,7 +80,7 @@ void GrTextContext::drawPosText(GrDrawContext* dc, GrRenderTarget* rt,
bool GrTextContext::ShouldDisableLCD(const SkPaint& paint) {
if (paint.getShader() ||
!SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode) ||
!SkXfermode::AsMode(paint.getXfermode(), nullptr) ||
paint.getMaskFilter() ||
paint.getRasterizer() ||
paint.getColorFilter() ||

View File

@ -31,6 +31,7 @@ public:
kNone_OutputType, //<! 0
kCoverage_OutputType, //<! inputCoverage
kModulate_OutputType, //<! inputColor * inputCoverage
kSAModulate_OutputType, //<! inputColor.a * inputCoverage
kISAModulate_OutputType, //<! (1 - inputColor.a) * inputCoverage
kISCModulate_OutputType, //<! (1 - inputColor) * inputCoverage
@ -138,6 +139,15 @@ GR_MAKE_BITFIELD_OPS(BlendFormula::Properties);
BlendFormula::kNone_OutputType, \
kAdd_GrBlendEquation, SRC_COEFF, DST_COEFF)
/**
* Basic coeff formula similar to COEFF_FORMULA but we will make the src f*Sa. This is used in
* LCD dst-out.
*/
#define COEFF_FORMULA_SA_MODULATE(SRC_COEFF, DST_COEFF) \
INIT_BLEND_FORMULA(BlendFormula::kSAModulate_OutputType, \
BlendFormula::kNone_OutputType, \
kAdd_GrBlendEquation, SRC_COEFF, DST_COEFF)
/**
* When the coeffs are (Zero, Zero), we clear the dst. This formula has its own macro so we can set
* the primary output type to none.
@ -289,6 +299,24 @@ static const BlendFormula gBlendTable[2][2][SkXfermode::kLastCoeffMode + 1] = {
/* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff),
}}};
static const BlendFormula gLCDBlendTable[SkXfermode::kLastCoeffMode + 1] = {
/* clear */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_OutputType),
/* src */ COVERAGE_FORMULA(BlendFormula::kCoverage_OutputType, kOne_GrBlendCoeff),
/* dst */ NO_DST_WRITE_FORMULA,
/* src-over */ COVERAGE_FORMULA(BlendFormula::kSAModulate_OutputType, kOne_GrBlendCoeff),
/* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
/* src-in */ COVERAGE_FORMULA(BlendFormula::kCoverage_OutputType, kDA_GrBlendCoeff),
/* dst-in */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISAModulate_OutputType),
/* src-out */ COVERAGE_FORMULA(BlendFormula::kCoverage_OutputType, kIDA_GrBlendCoeff),
/* dst-out */ COEFF_FORMULA_SA_MODULATE( kZero_GrBlendCoeff, kISC_GrBlendCoeff),
/* src-atop */ COVERAGE_FORMULA(BlendFormula::kSAModulate_OutputType, kDA_GrBlendCoeff),
/* dst-atop */ COVERAGE_FORMULA(BlendFormula::kISAModulate_OutputType, kIDA_GrBlendCoeff),
/* xor */ COVERAGE_FORMULA(BlendFormula::kSAModulate_OutputType, kIDA_GrBlendCoeff),
/* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff),
/* modulate */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISCModulate_OutputType),
/* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff),
};
static BlendFormula get_blend_formula(const GrProcOptInfo& colorPOI,
const GrProcOptInfo& coveragePOI,
bool hasMixedSamples,
@ -300,6 +328,14 @@ static BlendFormula get_blend_formula(const GrProcOptInfo& colorPOI,
return gBlendTable[colorPOI.isOpaque()][conflatesCoverage][xfermode];
}
static BlendFormula get_lcd_blend_formula(const GrProcOptInfo& coveragePOI,
SkXfermode::Mode xfermode) {
SkASSERT(xfermode >= 0 && xfermode <= SkXfermode::kLastCoeffMode);
SkASSERT(coveragePOI.isFourChannelOutput());
return gLCDBlendTable[xfermode];
}
///////////////////////////////////////////////////////////////////////////////
class PorterDuffXferProcessor : public GrXferProcessor {
@ -363,6 +399,13 @@ static void append_color_output(const PorterDuffXferProcessor& xp, GrGLXPFragmen
fsBuilder->codeAppendf("%s = %s;", output, inColor);
}
break;
case BlendFormula::kSAModulate_OutputType:
if (xp.readsCoverage()) {
fsBuilder->codeAppendf("%s = %s.a * %s;", output, inColor, inCoverage);
} else {
fsBuilder->codeAppendf("%s = %s;", output, inColor);
}
break;
case BlendFormula::kISAModulate_OutputType:
if (xp.readsCoverage()) {
fsBuilder->codeAppendf("%s = (1.0 - %s.a) * %s;", output, inColor, inCoverage);
@ -444,7 +487,9 @@ PorterDuffXferProcessor::onGetOptimizations(const GrProcOptInfo& colorPOI,
if (coveragePOI.isSolidWhite()) {
optFlags |= GrXferProcessor::kIgnoreCoverage_OptFlag;
}
if (colorPOI.allStagesMultiplyInput() && fBlendFormula.canTweakAlphaForCoverage()) {
if (colorPOI.allStagesMultiplyInput() &&
fBlendFormula.canTweakAlphaForCoverage() &&
!coveragePOI.isFourChannelOutput()) {
optFlags |= GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag;
}
}
@ -579,7 +624,6 @@ public:
private:
void emitOutputsForBlendState(const EmitArgs& args) override {
GrGLXPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
fsBuilder->codeAppendf("%s = %s * %s;", args.fOutputPrimary, args.fInputColor,
args.fInputCoverage);
}
@ -684,12 +728,18 @@ GrPorterDuffXPFactory::onCreateXferProcessor(const GrCaps& caps,
const GrProcOptInfo& covPOI,
bool hasMixedSamples,
const DstTexture* dstTexture) const {
BlendFormula blendFormula;
if (covPOI.isFourChannelOutput()) {
SkASSERT(!dstTexture || !dstTexture->texture());
return PDLCDXferProcessor::Create(fXfermode, colorPOI);
if (SkXfermode::kSrcOver_Mode == fXfermode &&
kRGBA_GrColorComponentFlags == colorPOI.validFlags()) {
SkASSERT(!dstTexture || !dstTexture->texture());
return PDLCDXferProcessor::Create(fXfermode, colorPOI);
}
blendFormula = get_lcd_blend_formula(covPOI, fXfermode);
} else {
blendFormula = get_blend_formula(colorPOI, covPOI, hasMixedSamples, fXfermode);
}
BlendFormula blendFormula = get_blend_formula(colorPOI, covPOI, hasMixedSamples, fXfermode);
if (blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlendingSupport()) {
return new ShaderPDXferProcessor(dstTexture, hasMixedSamples, fXfermode);
}
@ -698,15 +748,6 @@ GrPorterDuffXPFactory::onCreateXferProcessor(const GrCaps& caps,
return new PorterDuffXferProcessor(blendFormula);
}
bool GrPorterDuffXPFactory::supportsRGBCoverage(GrColor /*knownColor*/,
uint32_t knownColorFlags) const {
if (SkXfermode::kSrcOver_Mode == fXfermode &&
kRGBA_GrColorComponentFlags == knownColorFlags) {
return true;
}
return false;
}
void GrPorterDuffXPFactory::getInvariantBlendedColor(const GrProcOptInfo& colorPOI,
InvariantBlendedColor* blendedColor) const {
// Find the blended color info based on the formula that does not have coverage.
@ -745,8 +786,16 @@ bool GrPorterDuffXPFactory::willReadDstColor(const GrCaps& caps,
if (caps.shaderCaps()->dualSourceBlendingSupport()) {
return false;
}
// When we have four channel coverage we always need to read the dst in order to correctly
// blend. The one exception is when we are using srcover mode and we know the input color into
// the XP.
if (covPOI.isFourChannelOutput()) {
return false; // The LCD XP will abort rather than doing a dst read.
if (SkXfermode::kSrcOver_Mode == fXfermode &&
kRGBA_GrColorComponentFlags == colorPOI.validFlags()) {
return false;
}
return get_lcd_blend_formula(covPOI, fXfermode).hasSecondaryOutput();
}
// We fallback on the shader XP when the blend formula would use dual source blending but we
// don't have support for it.

View File

@ -26,6 +26,7 @@ static void test_color_unknown_no_coverage(skiatest::Reporter* reporter, const G
static void test_color_opaque_with_coverage(skiatest::Reporter* reporter, const GrCaps& caps);
static void test_color_opaque_no_coverage(skiatest::Reporter* reporter, const GrCaps& caps);
static void test_lcd_coverage(skiatest::Reporter* reporter, const GrCaps& caps);
static void test_lcd_coverage_fallback_case(skiatest::Reporter* reporter, const GrCaps& caps);
static void test_no_dual_source_blending(skiatest::Reporter* reporter);
DEF_GPUTEST(GrPorterDuff, reporter, factory) {
@ -46,6 +47,7 @@ DEF_GPUTEST(GrPorterDuff, reporter, factory) {
test_color_opaque_with_coverage(reporter, caps);
test_color_opaque_no_coverage(reporter, caps);
test_lcd_coverage(reporter, caps);
test_lcd_coverage_fallback_case(reporter, caps);
test_no_dual_source_blending(reporter);
}
@ -57,6 +59,7 @@ enum {
kNone_OutputType,
kCoverage_OutputType,
kModulate_OutputType,
kSAModulate_OutputType,
kISAModulate_OutputType,
kISCModulate_OutputType
};
@ -98,6 +101,197 @@ public:
}
};
static void test_lcd_coverage(skiatest::Reporter* reporter, const GrCaps& caps) {
GrProcOptInfo colorPOI, covPOI;
colorPOI.calcWithInitialValues(NULL, 0, 0, kNone_GrColorComponentFlags, false);
// Setting 2nd to last value to false and last to true will force covPOI to LCD coverage.
covPOI.calcWithInitialValues(NULL, 0, 0, kNone_GrColorComponentFlags, false, true);
SkASSERT(!colorPOI.isOpaque());
SkASSERT(!colorPOI.isSolidWhite());
SkASSERT(!covPOI.isSolidWhite());
SkASSERT(covPOI.isFourChannelOutput());
for (int m = 0; m <= SkXfermode::kLastCoeffMode; m++) {
SkXfermode::Mode xfermode = static_cast<SkXfermode::Mode>(m);
const GrPorterDuffTest::XPInfo xpi(reporter, xfermode, caps, colorPOI, covPOI);
switch (xfermode) {
case SkXfermode::kClear_Mode:
TEST_ASSERT(!xpi.fBlendedColor.fWillBlendWithDst);
TEST_ASSERT(0 == xpi.fBlendedColor.fKnownColor);
TEST_ASSERT(kRGBA_GrColorComponentFlags == xpi.fBlendedColor.fKnownColorFlags);
TEST_ASSERT((kIgnoreColor_OptFlag) == xpi.fOptFlags);
TEST_ASSERT(kCoverage_OutputType == xpi.fPrimaryOutputType);
TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
TEST_ASSERT(kReverseSubtract_GrBlendEquation == xpi.fBlendInfo.fEquation);
TEST_ASSERT(kDC_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
break;
case SkXfermode::kSrc_Mode:
TEST_ASSERT(!xpi.fBlendedColor.fWillBlendWithDst);
TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fBlendedColor.fKnownColorFlags);
TEST_ASSERT((kNone_OptFlags) == xpi.fOptFlags);
TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
TEST_ASSERT(kCoverage_OutputType == xpi.fSecondaryOutputType);
TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
TEST_ASSERT(kIS2C_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
break;
case SkXfermode::kDst_Mode:
TEST_ASSERT(xpi.fBlendedColor.fWillBlendWithDst);
TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fBlendedColor.fKnownColorFlags);
TEST_ASSERT((kSkipDraw_OptFlag |
kIgnoreColor_OptFlag |
kIgnoreCoverage_OptFlag |
kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
TEST_ASSERT(kNone_OutputType == xpi.fPrimaryOutputType);
TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
TEST_ASSERT(!xpi.fBlendInfo.fWriteColor);
break;
case SkXfermode::kSrcOver_Mode:
TEST_ASSERT(xpi.fBlendedColor.fWillBlendWithDst);
TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fBlendedColor.fKnownColorFlags);
TEST_ASSERT((kNone_OptFlags) == xpi.fOptFlags);
TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
TEST_ASSERT(kSAModulate_OutputType == xpi.fSecondaryOutputType);
TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
TEST_ASSERT(kIS2C_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
break;
case SkXfermode::kDstOver_Mode:
TEST_ASSERT(xpi.fBlendedColor.fWillBlendWithDst);
TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fBlendedColor.fKnownColorFlags);
TEST_ASSERT((kNone_OptFlags) == xpi.fOptFlags);
TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
TEST_ASSERT(kIDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
break;
case SkXfermode::kSrcIn_Mode:
TEST_ASSERT(xpi.fBlendedColor.fWillBlendWithDst);
TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fBlendedColor.fKnownColorFlags);
TEST_ASSERT((kNone_OptFlags) == xpi.fOptFlags);
TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
TEST_ASSERT(kCoverage_OutputType == xpi.fSecondaryOutputType);
TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
TEST_ASSERT(kDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
TEST_ASSERT(kIS2C_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
break;
case SkXfermode::kDstIn_Mode:
TEST_ASSERT(xpi.fBlendedColor.fWillBlendWithDst);
TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fBlendedColor.fKnownColorFlags);
TEST_ASSERT((kNone_OptFlags) == xpi.fOptFlags);
TEST_ASSERT(kISAModulate_OutputType == xpi.fPrimaryOutputType);
TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
TEST_ASSERT(kReverseSubtract_GrBlendEquation == xpi.fBlendInfo.fEquation);
TEST_ASSERT(kDC_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
break;
case SkXfermode::kSrcOut_Mode:
TEST_ASSERT(xpi.fBlendedColor.fWillBlendWithDst);
TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fBlendedColor.fKnownColorFlags);
TEST_ASSERT((kNone_OptFlags) == xpi.fOptFlags);
TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
TEST_ASSERT(kCoverage_OutputType == xpi.fSecondaryOutputType);
TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
TEST_ASSERT(kIDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
TEST_ASSERT(kIS2C_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
break;
case SkXfermode::kDstOut_Mode:
TEST_ASSERT(xpi.fBlendedColor.fWillBlendWithDst);
TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fBlendedColor.fKnownColorFlags);
TEST_ASSERT((kNone_OptFlags) == xpi.fOptFlags);
TEST_ASSERT(kSAModulate_OutputType == xpi.fPrimaryOutputType);
TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
TEST_ASSERT(kISC_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
break;
case SkXfermode::kSrcATop_Mode:
TEST_ASSERT(xpi.fBlendedColor.fWillBlendWithDst);
TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fBlendedColor.fKnownColorFlags);
TEST_ASSERT((kNone_OptFlags) == xpi.fOptFlags);
TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
TEST_ASSERT(kSAModulate_OutputType == xpi.fSecondaryOutputType);
TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
TEST_ASSERT(kDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
TEST_ASSERT(kIS2C_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
break;
case SkXfermode::kDstATop_Mode:
TEST_ASSERT(xpi.fBlendedColor.fWillBlendWithDst);
TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fBlendedColor.fKnownColorFlags);
TEST_ASSERT((kNone_OptFlags) == xpi.fOptFlags);
TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
TEST_ASSERT(kISAModulate_OutputType == xpi.fSecondaryOutputType);
TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
TEST_ASSERT(kIDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
TEST_ASSERT(kIS2C_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
break;
case SkXfermode::kXor_Mode:
TEST_ASSERT(xpi.fBlendedColor.fWillBlendWithDst);
TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fBlendedColor.fKnownColorFlags);
TEST_ASSERT((kNone_OptFlags) == xpi.fOptFlags);
TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
TEST_ASSERT(kSAModulate_OutputType == xpi.fSecondaryOutputType);
TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
TEST_ASSERT(kIDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
TEST_ASSERT(kIS2C_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
break;
case SkXfermode::kPlus_Mode:
TEST_ASSERT(xpi.fBlendedColor.fWillBlendWithDst);
TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fBlendedColor.fKnownColorFlags);
TEST_ASSERT((kNone_OptFlags) == xpi.fOptFlags);
TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
break;
case SkXfermode::kModulate_Mode:
TEST_ASSERT(xpi.fBlendedColor.fWillBlendWithDst);
TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fBlendedColor.fKnownColorFlags);
TEST_ASSERT((kNone_OptFlags) == xpi.fOptFlags);
TEST_ASSERT(kISCModulate_OutputType == xpi.fPrimaryOutputType);
TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
TEST_ASSERT(kReverseSubtract_GrBlendEquation == xpi.fBlendInfo.fEquation);
TEST_ASSERT(kDC_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
break;
case SkXfermode::kScreen_Mode:
TEST_ASSERT(xpi.fBlendedColor.fWillBlendWithDst);
TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fBlendedColor.fKnownColorFlags);
TEST_ASSERT((kNone_OptFlags) == xpi.fOptFlags);
TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
TEST_ASSERT(kOne_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
TEST_ASSERT(kISC_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
break;
default:
ERRORF(reporter, "Invalid xfermode.");
break;
}
}
}
static void test_color_unknown_with_coverage(skiatest::Reporter* reporter, const GrCaps& caps) {
GrProcOptInfo colorPOI, covPOI;
colorPOI.calcWithInitialValues(nullptr, 0, 0, kNone_GrColorComponentFlags, false);
@ -112,6 +306,7 @@ static void test_color_unknown_with_coverage(skiatest::Reporter* reporter, const
SkXfermode::Mode xfermode = static_cast<SkXfermode::Mode>(m);
const GrPorterDuffTest::XPInfo xpi(reporter, xfermode, caps, colorPOI, covPOI);
switch (xfermode) {
case SkXfermode::kClear_Mode:
TEST_ASSERT(!xpi.fBlendedColor.fWillBlendWithDst);
@ -897,7 +1092,7 @@ static void test_color_opaque_no_coverage(skiatest::Reporter* reporter, const Gr
}
}
static void test_lcd_coverage(skiatest::Reporter* reporter, const GrCaps& caps) {
static void test_lcd_coverage_fallback_case(skiatest::Reporter* reporter, const GrCaps& caps) {
class : public GrVertexBatch {
void getInvariantOutputColor(GrInitInvariantOutput* out) const override {
out->setKnownFourComponents(GrColorPackRGBA(123, 45, 67, 221));