From 723b0501e22373bb3e6c306daaceae02cda8a124 Mon Sep 17 00:00:00 2001 From: egdaniel Date: Tue, 15 Sep 2015 09:31:40 -0700 Subject: [PATCH] Add support for blending of LCD for all blend modes. BUG=skia: Review URL: https://codereview.chromium.org/1313623002 --- gm/lcdblendmodes.cpp | 133 ++++++++++++ .../gpu/effects/GrPorterDuffXferProcessor.h | 4 +- src/gpu/GrPipelineBuilder.cpp | 1 + src/gpu/GrProcOptInfo.cpp | 4 +- src/gpu/GrProcOptInfo.h | 2 +- src/gpu/GrTextContext.cpp | 2 +- src/gpu/effects/GrPorterDuffXferProcessor.cpp | 79 +++++-- tests/GrPorterDuffTest.cpp | 197 +++++++++++++++++- 8 files changed, 402 insertions(+), 20 deletions(-) create mode 100644 gm/lcdblendmodes.cpp diff --git a/gm/lcdblendmodes.cpp b/gm/lcdblendmodes.cpp new file mode 100644 index 0000000000..a2494cc343 --- /dev/null +++ b/gm/lcdblendmodes.cpp @@ -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 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; ) +} diff --git a/include/gpu/effects/GrPorterDuffXferProcessor.h b/include/gpu/effects/GrPorterDuffXferProcessor.h index a26a89293e..d297e32908 100644 --- a/include/gpu/effects/GrPorterDuffXferProcessor.h +++ b/include/gpu/effects/GrPorterDuffXferProcessor.h @@ -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; diff --git a/src/gpu/GrPipelineBuilder.cpp b/src/gpu/GrPipelineBuilder.cpp index cb3b4af77e..dbef6e8755 100644 --- a/src/gpu/GrPipelineBuilder.cpp +++ b/src/gpu/GrPipelineBuilder.cpp @@ -105,3 +105,4 @@ void GrPipelineBuilder::calcCoverageInvariantOutput(const GrDrawBatch* batch) co fCoverageProcInfo.calcCoverageWithBatch(batch, fCoverageFragmentProcessors.begin(), this->numCoverageFragmentProcessors()); } + diff --git a/src/gpu/GrProcOptInfo.cpp b/src/gpu/GrProcOptInfo.cpp index d7f2d7f312..6a2584d5f9 100644 --- a/src/gpu/GrProcOptInfo.cpp +++ b/src/gpu/GrProcOptInfo.cpp @@ -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); } diff --git a/src/gpu/GrProcOptInfo.h b/src/gpu/GrProcOptInfo.h index b46957e7a0..dd9374dd3a 100644 --- a/src/gpu/GrProcOptInfo.h +++ b/src/gpu/GrProcOptInfo.h @@ -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); diff --git a/src/gpu/GrTextContext.cpp b/src/gpu/GrTextContext.cpp index 92a851bc5a..be62619783 100644 --- a/src/gpu/GrTextContext.cpp +++ b/src/gpu/GrTextContext.cpp @@ -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() || diff --git a/src/gpu/effects/GrPorterDuffXferProcessor.cpp b/src/gpu/effects/GrPorterDuffXferProcessor.cpp index 5f34f75854..4c50e47ab9 100644 --- a/src/gpu/effects/GrPorterDuffXferProcessor.cpp +++ b/src/gpu/effects/GrPorterDuffXferProcessor.cpp @@ -31,6 +31,7 @@ public: kNone_OutputType, //= 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. diff --git a/tests/GrPorterDuffTest.cpp b/tests/GrPorterDuffTest.cpp index 87b7a2edfa..1328272a6a 100644 --- a/tests/GrPorterDuffTest.cpp +++ b/tests/GrPorterDuffTest.cpp @@ -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(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(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));