aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gm/aaxfermodes.cpp236
-rw-r--r--gyp/gpu.gypi1
-rw-r--r--include/gpu/GrColor.h4
-rw-r--r--include/gpu/GrContextOptions.h6
-rw-r--r--include/gpu/GrXferProcessor.h8
-rw-r--r--include/gpu/effects/GrPorterDuffXferProcessor.h9
-rw-r--r--src/gpu/GrBlend.cpp154
-rw-r--r--src/gpu/GrBlend.h125
-rw-r--r--src/gpu/GrCaps.cpp4
-rw-r--r--src/gpu/effects/GrPorterDuffXferProcessor.cpp1065
-rw-r--r--tests/GrPorterDuffTest.cpp1011
11 files changed, 1929 insertions, 694 deletions
diff --git a/gm/aaxfermodes.cpp b/gm/aaxfermodes.cpp
new file mode 100644
index 0000000000..9970c4fd6d
--- /dev/null
+++ b/gm/aaxfermodes.cpp
@@ -0,0 +1,236 @@
+
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "gm.h"
+#include "SkArithmeticMode.h"
+#include "SkShader.h"
+#include "SkXfermode.h"
+
+enum {
+ kXfermodeCount = SkXfermode::kLastMode + 2, // All xfermodes plus arithmetic mode.
+ kShapeSize = 22,
+ kShapeSpacing = 36,
+ kShapeTypeSpacing = 4 * kShapeSpacing / 3,
+ kPaintSpacing = 3 * kShapeTypeSpacing,
+ kLabelSpacing = 3 * kShapeSize,
+ kMargin = kShapeSpacing / 2,
+ kXfermodeTypeSpacing = kLabelSpacing + 2 * kPaintSpacing + kShapeTypeSpacing,
+ kTitleSpacing = 3 * kShapeSpacing / 4,
+ kSubtitleSpacing = 5 * kShapeSpacing / 8
+};
+
+static const SkColor kBGColor = SkColorSetARGB(200, 210, 184, 135);
+
+static const SkColor kShapeColors[2] = {
+ SkColorSetARGB(130, 255, 0, 128), // input color unknown
+ SkColorSetARGB(255, 0, 255, 255) // input color opaque
+};
+
+enum Shape {
+ kSquare_Shape,
+ kDiamond_Shape,
+ kOval_Shape,
+
+ kLast_Shape = kOval_Shape
+};
+
+namespace skiagm {
+
+/**
+ * Verifies AA works properly on all Xfermodes, including arithmetic, with both opaque and unknown
+ * src colors.
+ */
+class AAXfermodesGM : public GM {
+public:
+ AAXfermodesGM() {}
+
+protected:
+ SkString onShortName() override {
+ return SkString("aaxfermodes");
+ }
+
+ SkISize onISize() override {
+ return SkISize::Make(2 * kMargin + 2 * kXfermodeTypeSpacing -
+ (kXfermodeTypeSpacing - (kLabelSpacing + 2 * kPaintSpacing)),
+ 2 * kMargin + kTitleSpacing + kSubtitleSpacing +
+ (1 + SkXfermode::kLastCoeffMode) * kShapeSpacing);
+ }
+
+ void onOnceBeforeDraw() override {
+ fLabelPaint.setAntiAlias(true);
+ sk_tool_utils::set_portable_typeface(&fLabelPaint);
+ fLabelPaint.setTextSize(5 * kShapeSize/8);
+ fLabelPaint.setSubpixelText(true);
+
+ static const SkScalar radius = -1.4f * kShapeSize/2;
+ SkPoint pts[4] = {
+ {-radius, 0},
+ {0, -1.33f * radius},
+ {radius, 0},
+ {0, 1.33f * radius}
+ };
+ fPath.moveTo(pts[0]);
+ fPath.quadTo(pts[1], pts[2]);
+ fPath.quadTo(pts[3], pts[0]);
+ }
+
+ void onDraw(SkCanvas* canvas) override {
+ sk_tool_utils::draw_checkerboard(canvas, 0xffffffff, 0xffc0c0c0, 10);
+
+ canvas->saveLayer(NULL, NULL);
+ canvas->drawColor(kBGColor, SkXfermode::kSrc_Mode);
+
+ canvas->translate(kMargin, kMargin);
+
+ SkPaint titlePaint(fLabelPaint);
+ titlePaint.setTextSize(9 * titlePaint.getTextSize() / 8);
+ titlePaint.setFakeBoldText(true);
+ titlePaint.setTextAlign(SkPaint::kCenter_Align);
+ canvas->drawText("Porter Duff", sizeof("Porter Duff") - 1,
+ kLabelSpacing + 3 * kShapeTypeSpacing,
+ kTitleSpacing / 2 + titlePaint.getTextSize() / 3, titlePaint);
+ canvas->drawText("Advanced", sizeof("Advanced") - 1,
+ kXfermodeTypeSpacing + kLabelSpacing + 3 * kShapeTypeSpacing,
+ kTitleSpacing / 2 + titlePaint.getTextSize() / 3, titlePaint);
+
+ canvas->translate(0, kTitleSpacing);
+
+ for (size_t xfermodeSet = 0; xfermodeSet < 2; xfermodeSet++) {
+ size_t firstMode = (SkXfermode::kLastCoeffMode + 1) * xfermodeSet;
+ canvas->save();
+
+ fLabelPaint.setTextAlign(SkPaint::kCenter_Align);
+ canvas->drawText("Src Unknown", sizeof("Src Unknown") - 1,
+ kLabelSpacing + kShapeSpacing / 2 + kShapeTypeSpacing,
+ kSubtitleSpacing / 2 + fLabelPaint.getTextSize() / 3, fLabelPaint);
+ canvas->drawText("Src Opaque", sizeof("Src Opaque") - 1,
+ kLabelSpacing + kShapeSpacing / 2 + kShapeTypeSpacing + kPaintSpacing,
+ kSubtitleSpacing / 2 + fLabelPaint.getTextSize() / 3, fLabelPaint);
+
+ canvas->translate(0, kSubtitleSpacing + kShapeSpacing/2);
+
+ for (size_t m = 0; m <= SkXfermode::kLastCoeffMode; m++) {
+ SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(firstMode + m);
+ canvas->save();
+
+ this->drawModeName(canvas, mode);
+ canvas->translate(kLabelSpacing + kShapeSpacing/2, 0);
+
+ for (size_t colorIdx = 0; colorIdx < SK_ARRAY_COUNT(kShapeColors); colorIdx++) {
+ SkPaint paint;
+ this->setupShapePaint(canvas, kShapeColors[colorIdx], mode, &paint);
+ SkASSERT(colorIdx == 0 || 255 == paint.getAlpha());
+ canvas->save();
+
+ for (size_t shapeIdx = 0; shapeIdx <= kLast_Shape; shapeIdx++) {
+ this->drawShape(canvas, static_cast<Shape>(shapeIdx), paint, mode);
+ canvas->translate(kShapeTypeSpacing, 0);
+ }
+
+ canvas->restore();
+ canvas->translate(kPaintSpacing, 0);
+ }
+
+ canvas->restore();
+ canvas->translate(0, kShapeSpacing);
+ }
+
+ canvas->restore();
+ canvas->translate(kXfermodeTypeSpacing, 0);
+ }
+
+ canvas->restore();
+ }
+
+ void drawModeName(SkCanvas* canvas, SkXfermode::Mode mode) {
+ const char* modeName = mode <= SkXfermode::kLastMode ? SkXfermode::ModeName(mode)
+ : "Arithmetic";
+ fLabelPaint.setTextAlign(SkPaint::kRight_Align);
+ canvas->drawText(modeName, strlen(modeName), kLabelSpacing - kShapeSize / 4,
+ fLabelPaint.getTextSize() / 3, fLabelPaint);
+ }
+
+ void setupShapePaint(SkCanvas* canvas, GrColor color, SkXfermode::Mode mode, SkPaint* paint) {
+ paint->setColor(color);
+
+ if (mode == SkXfermode::kPlus_Mode) {
+ // Check for overflow, otherwise we might get confusing AA artifacts.
+ int maxSum = SkTMax(SkTMax(SkColorGetA(kBGColor) + SkColorGetA(color),
+ SkColorGetR(kBGColor) + SkColorGetR(color)),
+ SkTMax(SkColorGetG(kBGColor) + SkColorGetG(color),
+ SkColorGetB(kBGColor) + SkColorGetB(color)));
+
+ if (maxSum > 255) {
+ SkPaint dimPaint;
+ dimPaint.setAntiAlias(false);
+ dimPaint.setXfermode(SkXfermode::Create(SkXfermode::kDstIn_Mode));
+ if (255 != paint->getAlpha()) {
+ // Dim the src and dst colors.
+ dimPaint.setARGB(255 * 255 / maxSum, 0, 0, 0);
+ paint->setAlpha(255 * paint->getAlpha() / maxSum);
+ } else {
+ // Just clear the dst, we need to preserve the paint's opacity.
+ dimPaint.setARGB(0, 0, 0, 0);
+ }
+ canvas->drawRectCoords(-kShapeSpacing/2, -kShapeSpacing/2,
+ kShapeSpacing/2 + 2 * kShapeTypeSpacing,
+ kShapeSpacing/2, dimPaint);
+ }
+ }
+ }
+
+ void drawShape(SkCanvas* canvas, Shape shape, const SkPaint& paint, SkXfermode::Mode mode) {
+ SkPaint shapePaint(paint);
+ shapePaint.setAntiAlias(kSquare_Shape != shape);
+
+ SkAutoTUnref<SkXfermode> xfermode;
+ if (mode <= SkXfermode::kLastMode) {
+ xfermode.reset(SkXfermode::Create(mode));
+ } else {
+ xfermode.reset(SkArithmeticMode::Create(+1.0f, +0.25f, -0.5f, +0.1f));
+ }
+ shapePaint.setXfermode(xfermode);
+
+ switch (shape) {
+ case kSquare_Shape:
+ canvas->drawRectCoords(-kShapeSize/2, -kShapeSize/2, kShapeSize/2, kShapeSize/2,
+ shapePaint);
+ break;
+
+ case kDiamond_Shape:
+ canvas->save();
+ canvas->rotate(45);
+ canvas->drawRectCoords(-kShapeSize/2, -kShapeSize/2, kShapeSize/2, kShapeSize/2,
+ shapePaint);
+ canvas->restore();
+ break;
+
+ case kOval_Shape:
+ canvas->save();
+ canvas->rotate(static_cast<SkScalar>((511 * mode + 257) % 360));
+ canvas->drawPath(fPath, shapePaint);
+ canvas->restore();
+ break;
+
+ default:
+ SkFAIL("Invalid shape.");
+ }
+ }
+
+private:
+ SkPaint fLabelPaint;
+ SkPath fPath;
+
+ typedef GM INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static GM* MyFactory(void*) { return new AAXfermodesGM; }
+static GMRegistry reg(MyFactory);
+
+}
diff --git a/gyp/gpu.gypi b/gyp/gpu.gypi
index 8a93bf8264..6a93a7c7d9 100644
--- a/gyp/gpu.gypi
+++ b/gyp/gpu.gypi
@@ -81,7 +81,6 @@
'<(skia_src_path)/gpu/GrBatchTarget.h',
'<(skia_src_path)/gpu/GrBatchTest.cpp',
'<(skia_src_path)/gpu/GrBatchTest.h',
- '<(skia_src_path)/gpu/GrBlend.cpp',
'<(skia_src_path)/gpu/GrBlend.h',
'<(skia_src_path)/gpu/GrBlurUtils.cpp',
'<(skia_src_path)/gpu/GrBlurUtils.h',
diff --git a/include/gpu/GrColor.h b/include/gpu/GrColor.h
index f5757b93f5..9ccc638fc9 100644
--- a/include/gpu/GrColor.h
+++ b/include/gpu/GrColor.h
@@ -142,6 +142,8 @@ enum GrColorComponentFlags {
kB_GrColorComponentFlag = 1 << (GrColor_SHIFT_B / 8),
kA_GrColorComponentFlag = 1 << (GrColor_SHIFT_A / 8),
+ kNone_GrColorComponentFlags = 0,
+
kRGB_GrColorComponentFlags = (kR_GrColorComponentFlag | kG_GrColorComponentFlag |
kB_GrColorComponentFlag),
@@ -149,6 +151,8 @@ enum GrColorComponentFlags {
kB_GrColorComponentFlag | kA_GrColorComponentFlag)
};
+GR_MAKE_BITFIELD_OPS(GrColorComponentFlags)
+
static inline char GrColorComponentFlagToChar(GrColorComponentFlags component) {
SkASSERT(SkIsPow2(component));
switch (component) {
diff --git a/include/gpu/GrContextOptions.h b/include/gpu/GrContextOptions.h
index 686d6a9ac0..dfb352b507 100644
--- a/include/gpu/GrContextOptions.h
+++ b/include/gpu/GrContextOptions.h
@@ -14,7 +14,8 @@ struct GrContextOptions {
GrContextOptions()
: fDrawPathToCompressedTexture(false)
, fSuppressPrints(false)
- , fMaxTextureSizeOverride(SK_MaxS32) {}
+ , fMaxTextureSizeOverride(SK_MaxS32)
+ , fSuppressDualSourceBlending(false) {}
// EXPERIMENTAL
// May be removed in the future, or may become standard depending
@@ -28,7 +29,8 @@ struct GrContextOptions {
overrides can only reduce the feature set or limits, never increase them beyond the
detected values. */
- int fMaxTextureSizeOverride;
+ int fMaxTextureSizeOverride;
+ bool fSuppressDualSourceBlending;
};
#endif
diff --git a/include/gpu/GrXferProcessor.h b/include/gpu/GrXferProcessor.h
index a9faad016c..812a9b32ab 100644
--- a/include/gpu/GrXferProcessor.h
+++ b/include/gpu/GrXferProcessor.h
@@ -51,10 +51,6 @@ enum GrBlendEquation {
static const int kGrBlendEquationCnt = kLast_GrBlendEquation + 1;
-inline bool GrBlendEquationIsAdvanced(GrBlendEquation equation) {
- return equation >= kFirstAdvancedGrBlendEquation;
-}
-
/**
* Coeffecients for alpha-blending.
*/
@@ -184,10 +180,6 @@ public:
*/
kOverrideColor_OptFlag = 0x8,
/**
- * Set CoverageDrawing_StateBit
- */
- kSetCoverageDrawing_OptFlag = 0x10,
- /**
* Can tweak alpha for coverage. Currently this flag should only be used by a batch
*/
kCanTweakAlphaForCoverage_OptFlag = 0x20,
diff --git a/include/gpu/effects/GrPorterDuffXferProcessor.h b/include/gpu/effects/GrPorterDuffXferProcessor.h
index f8fc1a38cc..e4f72203f6 100644
--- a/include/gpu/effects/GrPorterDuffXferProcessor.h
+++ b/include/gpu/effects/GrPorterDuffXferProcessor.h
@@ -24,7 +24,7 @@ public:
GrXPFactory::InvariantOutput*) const override;
private:
- GrPorterDuffXPFactory(GrBlendCoeff src, GrBlendCoeff dst);
+ GrPorterDuffXPFactory(SkXfermode::Mode);
GrXferProcessor* onCreateXferProcessor(const GrCaps& caps,
const GrProcOptInfo& colorPOI,
@@ -37,14 +37,15 @@ private:
bool onIsEqual(const GrXPFactory& xpfBase) const override {
const GrPorterDuffXPFactory& xpf = xpfBase.cast<GrPorterDuffXPFactory>();
- return (fSrcCoeff == xpf.fSrcCoeff && fDstCoeff == xpf.fDstCoeff);
+ return fXfermode == xpf.fXfermode;
}
GR_DECLARE_XP_FACTORY_TEST;
+ static void TestGetXPOutputTypes(const GrXferProcessor*, int* outPrimary, int* outSecondary);
- GrBlendCoeff fSrcCoeff;
- GrBlendCoeff fDstCoeff;
+ SkXfermode::Mode fXfermode;
+ friend class GrPorterDuffTest; // for TestGetXPOutputTypes()
typedef GrXPFactory INHERITED;
};
diff --git a/src/gpu/GrBlend.cpp b/src/gpu/GrBlend.cpp
deleted file mode 100644
index 52e335e9b0..0000000000
--- a/src/gpu/GrBlend.cpp
+++ /dev/null
@@ -1,154 +0,0 @@
-
-/*
- * Copyright 2013 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "GrBlend.h"
-
-static inline GrBlendCoeff swap_coeff_src_dst(GrBlendCoeff coeff) {
- switch (coeff) {
- case kDC_GrBlendCoeff:
- return kSC_GrBlendCoeff;
- case kIDC_GrBlendCoeff:
- return kISC_GrBlendCoeff;
- case kDA_GrBlendCoeff:
- return kSA_GrBlendCoeff;
- case kIDA_GrBlendCoeff:
- return kISA_GrBlendCoeff;
- case kSC_GrBlendCoeff:
- return kDC_GrBlendCoeff;
- case kISC_GrBlendCoeff:
- return kIDC_GrBlendCoeff;
- case kSA_GrBlendCoeff:
- return kDA_GrBlendCoeff;
- case kISA_GrBlendCoeff:
- return kIDA_GrBlendCoeff;
- default:
- return coeff;
- }
-}
-
-static inline unsigned saturated_add(unsigned a, unsigned b) {
- SkASSERT(a <= 255);
- SkASSERT(b <= 255);
- unsigned sum = a + b;
- if (sum > 255) {
- sum = 255;
- }
- return sum;
-}
-
-static GrColor add_colors(GrColor src, GrColor dst) {
- unsigned r = saturated_add(GrColorUnpackR(src), GrColorUnpackR(dst));
- unsigned g = saturated_add(GrColorUnpackG(src), GrColorUnpackG(dst));
- unsigned b = saturated_add(GrColorUnpackB(src), GrColorUnpackB(dst));
- unsigned a = saturated_add(GrColorUnpackA(src), GrColorUnpackA(dst));
- return GrColorPackRGBA(r, g, b, a);
-}
-
-static inline bool valid_color(uint32_t compFlags) {
- return (kRGBA_GrColorComponentFlags & compFlags) == kRGBA_GrColorComponentFlags;
-}
-
-static GrColor simplify_blend_term(GrBlendCoeff* srcCoeff,
- GrColor srcColor, uint32_t srcCompFlags,
- GrColor dstColor, uint32_t dstCompFlags,
- GrColor constantColor) {
-
- SkASSERT(!GrBlendCoeffRefsSrc(*srcCoeff));
- SkASSERT(srcCoeff);
-
- // Check whether srcCoeff can be reduced to kOne or kZero based on known color inputs.
- // We could pick out the coeff r,g,b,a values here and use them to compute the blend term color,
- // if possible, below but that is not implemented now.
- switch (*srcCoeff) {
- case kIDC_GrBlendCoeff:
- dstColor = ~dstColor; // fallthrough
- case kDC_GrBlendCoeff:
- if (valid_color(dstCompFlags)) {
- if (0xffffffff == dstColor) {
- *srcCoeff = kOne_GrBlendCoeff;
- } else if (0 == dstColor) {
- *srcCoeff = kZero_GrBlendCoeff;
- }
- }
- break;
-
- case kIDA_GrBlendCoeff:
- dstColor = ~dstColor; // fallthrough
- case kDA_GrBlendCoeff:
- if (kA_GrColorComponentFlag & dstCompFlags) {
- if (0xff == GrColorUnpackA(dstColor)) {
- *srcCoeff = kOne_GrBlendCoeff;
- } else if (0 == GrColorUnpackA(dstColor)) {
- *srcCoeff = kZero_GrBlendCoeff;
- }
- }
- break;
-
- case kIConstC_GrBlendCoeff:
- constantColor = ~constantColor; // fallthrough
- case kConstC_GrBlendCoeff:
- if (0xffffffff == constantColor) {
- *srcCoeff = kOne_GrBlendCoeff;
- } else if (0 == constantColor) {
- *srcCoeff = kZero_GrBlendCoeff;
- }
- break;
-
- case kIConstA_GrBlendCoeff:
- constantColor = ~constantColor; // fallthrough
- case kConstA_GrBlendCoeff:
- if (0xff == GrColorUnpackA(constantColor)) {
- *srcCoeff = kOne_GrBlendCoeff;
- } else if (0 == GrColorUnpackA(constantColor)) {
- *srcCoeff = kZero_GrBlendCoeff;
- }
- break;
-
- default:
- break;
- }
- // We may have invalidated these above and shouldn't read them again.
- SkDEBUGCODE(dstColor = constantColor = GrColor_ILLEGAL;)
-
- if (kZero_GrBlendCoeff == *srcCoeff || (valid_color(srcCompFlags) && 0 == srcColor)) {
- *srcCoeff = kZero_GrBlendCoeff;
- return 0;
- }
-
- if (kOne_GrBlendCoeff == *srcCoeff && valid_color(srcCompFlags)) {
- return srcColor;
- } else {
- return GrColor_ILLEGAL;
- }
-}
-
-GrColor GrSimplifyBlend(GrBlendCoeff* srcCoeff,
- GrBlendCoeff* dstCoeff,
- GrColor srcColor, uint32_t srcCompFlags,
- GrColor dstColor, uint32_t dstCompFlags,
- GrColor constantColor) {
- GrColor srcTermColor = simplify_blend_term(srcCoeff,
- srcColor, srcCompFlags,
- dstColor, dstCompFlags,
- constantColor);
-
- // We call the same function to simplify the dst blend coeff. We trick it out by swapping the
- // src and dst.
- GrBlendCoeff spoofedCoeff = swap_coeff_src_dst(*dstCoeff);
- GrColor dstTermColor = simplify_blend_term(&spoofedCoeff,
- dstColor, dstCompFlags,
- srcColor, srcCompFlags,
- constantColor);
- *dstCoeff = swap_coeff_src_dst(spoofedCoeff);
-
- if (GrColor_ILLEGAL != srcTermColor && GrColor_ILLEGAL != dstTermColor) {
- return add_colors(srcTermColor, dstTermColor);
- } else {
- return GrColor_ILLEGAL;
- }
-}
diff --git a/src/gpu/GrBlend.h b/src/gpu/GrBlend.h
index e5b8993377..7021902765 100644
--- a/src/gpu/GrBlend.h
+++ b/src/gpu/GrBlend.h
@@ -7,13 +7,22 @@
*/
#include "GrTypes.h"
-#include "GrColor.h"
+#include "SkTLogic.h"
#include "GrXferProcessor.h"
#ifndef GrBlend_DEFINED
#define GrBlend_DEFINED
-static inline bool GrBlendCoeffRefsSrc(GrBlendCoeff coeff) {
+template<GrBlendCoeff Coeff>
+struct GrTBlendCoeffRefsSrc : SkTBool<kSC_GrBlendCoeff == Coeff ||
+ kISC_GrBlendCoeff == Coeff ||
+ kSA_GrBlendCoeff == Coeff ||
+ kISA_GrBlendCoeff == Coeff> {};
+
+#define GR_BLEND_COEFF_REFS_SRC(COEFF) \
+ GrTBlendCoeffRefsSrc<COEFF>::value
+
+inline bool GrBlendCoeffRefsSrc(GrBlendCoeff coeff) {
switch (coeff) {
case kSC_GrBlendCoeff:
case kISC_GrBlendCoeff:
@@ -25,7 +34,17 @@ static inline bool GrBlendCoeffRefsSrc(GrBlendCoeff coeff) {
}
}
-static inline bool GrBlendCoeffRefsDst(GrBlendCoeff coeff) {
+
+template<GrBlendCoeff Coeff>
+struct GrTBlendCoeffRefsDst : SkTBool<kDC_GrBlendCoeff == Coeff ||
+ kIDC_GrBlendCoeff == Coeff ||
+ kDA_GrBlendCoeff == Coeff ||
+ kIDA_GrBlendCoeff == Coeff> {};
+
+#define GR_BLEND_COEFF_REFS_DST(COEFF) \
+ GrTBlendCoeffRefsDst<COEFF>::value
+
+inline bool GrBlendCoeffRefsDst(GrBlendCoeff coeff) {
switch (coeff) {
case kDC_GrBlendCoeff:
case kIDC_GrBlendCoeff:
@@ -37,10 +56,100 @@ static inline bool GrBlendCoeffRefsDst(GrBlendCoeff coeff) {
}
}
-GrColor GrSimplifyBlend(GrBlendCoeff* srcCoeff,
- GrBlendCoeff* dstCoeff,
- GrColor srcColor, uint32_t srcCompFlags,
- GrColor dstColor, uint32_t dstCompFlags,
- GrColor constantColor);
+
+template<GrBlendCoeff Coeff>
+struct GrTBlendCoeffRefsSrc2 : SkTBool<kS2C_GrBlendCoeff == Coeff ||
+ kIS2C_GrBlendCoeff == Coeff ||
+ kS2A_GrBlendCoeff == Coeff ||
+ kIS2A_GrBlendCoeff == Coeff> {};
+
+#define GR_BLEND_COEFF_REFS_SRC2(COEFF) \
+ GrTBlendCoeffRefsSrc2<COEFF>::value
+
+inline bool GrBlendCoeffRefsSrc2(GrBlendCoeff coeff) {
+ switch (coeff) {
+ case kS2C_GrBlendCoeff:
+ case kIS2C_GrBlendCoeff:
+ case kS2A_GrBlendCoeff:
+ case kIS2A_GrBlendCoeff:
+ return true;
+ default:
+ return false;
+ }
+}
+
+
+template<GrBlendCoeff SrcCoeff, GrBlendCoeff DstCoeff>
+struct GrTBlendCoeffsUseSrcColor : SkTBool<kZero_GrBlendCoeff != SrcCoeff ||
+ GR_BLEND_COEFF_REFS_SRC(DstCoeff)> {};
+
+#define GR_BLEND_COEFFS_USE_SRC_COLOR(SRC_COEFF, DST_COEFF) \
+ GrTBlendCoeffsUseSrcColor<SRC_COEFF, DST_COEFF>::value
+
+
+template<GrBlendCoeff SrcCoeff, GrBlendCoeff DstCoeff>
+struct GrTBlendCoeffsUseDstColor : SkTBool<GR_BLEND_COEFF_REFS_DST(SrcCoeff) ||
+ kZero_GrBlendCoeff != DstCoeff> {};
+
+#define GR_BLEND_COEFFS_USE_DST_COLOR(SRC_COEFF, DST_COEFF) \
+ GrTBlendCoeffsUseDstColor<SRC_COEFF, DST_COEFF>::value
+
+
+template<GrBlendEquation Equation>
+struct GrTBlendEquationIsAdvanced : SkTBool<Equation >= kFirstAdvancedGrBlendEquation> {};
+
+#define GR_BLEND_EQUATION_IS_ADVANCED(EQUATION) \
+ GrTBlendEquationIsAdvanced<EQUATION>::value
+
+inline bool GrBlendEquationIsAdvanced(GrBlendEquation equation) {
+ return equation >= kFirstAdvancedGrBlendEquation;
+}
+
+
+template<GrBlendEquation BlendEquation, GrBlendCoeff SrcCoeff, GrBlendCoeff DstCoeff>
+struct GrTBlendModifiesDst : SkTBool<(kAdd_GrBlendEquation != BlendEquation &&
+ kReverseSubtract_GrBlendEquation != BlendEquation) ||
+ kZero_GrBlendCoeff != SrcCoeff ||
+ kOne_GrBlendCoeff != DstCoeff> {};
+
+#define GR_BLEND_MODIFIES_DST(EQUATION, SRC_COEFF, DST_COEFF) \
+ GrTBlendModifiesDst<EQUATION, SRC_COEFF, DST_COEFF>::value
+
+
+/**
+ * Advanced blend equations can always tweak alpha for coverage. (See GrCustomXfermode.cpp)
+ *
+ * For "add" and "reverse subtract" the blend equation with f=coverage is:
+ *
+ * D' = f * (S * srcCoeff + D * dstCoeff) + (1-f) * D
+ * = f * S * srcCoeff + D * (f * dstCoeff + (1 - f))
+ *
+ * (Let srcCoeff be negative for reverse subtract.) We can tweak alpha for coverage when the
+ * following relationship holds:
+ *
+ * (f*S) * srcCoeff' + D * dstCoeff' == f * S * srcCoeff + D * (f * dstCoeff + (1 - f))
+ *
+ * (Where srcCoeff' and dstCoeff' have any reference to S pre-multiplied by f.)
+ *
+ * It's easy to see this works for the src term as long as srcCoeff' == srcCoeff (meaning srcCoeff
+ * does not reference S). For the dst term, this will work as long as the following is true:
+ *|
+ * dstCoeff' == f * dstCoeff + (1 - f)
+ * dstCoeff' == 1 - f * (1 - dstCoeff)
+ *
+ * By inspection we can see this will work as long as dstCoeff has a 1, and any other term in
+ * dstCoeff references S.
+ */
+template<GrBlendEquation Equation, GrBlendCoeff SrcCoeff, GrBlendCoeff DstCoeff>
+struct GrTBlendCanTweakAlphaForCoverage : SkTBool<GR_BLEND_EQUATION_IS_ADVANCED(Equation) ||
+ ((kAdd_GrBlendEquation == Equation ||
+ kReverseSubtract_GrBlendEquation == Equation) &&
+ !GR_BLEND_COEFF_REFS_SRC(SrcCoeff) &&
+ (kOne_GrBlendCoeff == DstCoeff ||
+ kISC_GrBlendCoeff == DstCoeff ||
+ kISA_GrBlendCoeff == DstCoeff))> {};
+
+#define GR_BLEND_CAN_TWEAK_ALPHA_FOR_COVERAGE(EQUATION, SRC_COEFF, DST_COEFF) \
+ GrTBlendCanTweakAlphaForCoverage<EQUATION, SRC_COEFF, DST_COEFF>::value
#endif
diff --git a/src/gpu/GrCaps.cpp b/src/gpu/GrCaps.cpp
index 625bd90e8f..f078fad9fb 100644
--- a/src/gpu/GrCaps.cpp
+++ b/src/gpu/GrCaps.cpp
@@ -73,8 +73,8 @@ SkString GrShaderCaps::dump() const {
return r;
}
-void GrShaderCaps::applyOptionsOverrides(const GrContextOptions&) {
- // Currently no overrides apply to shader caps.
+void GrShaderCaps::applyOptionsOverrides(const GrContextOptions& options) {
+ fDualSourceBlendingSupport = fDualSourceBlendingSupport && !options.fSuppressDualSourceBlending;
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/src/gpu/effects/GrPorterDuffXferProcessor.cpp b/src/gpu/effects/GrPorterDuffXferProcessor.cpp
index d1e02d2c2b..812cfeaaa4 100644
--- a/src/gpu/effects/GrPorterDuffXferProcessor.cpp
+++ b/src/gpu/effects/GrPorterDuffXferProcessor.cpp
@@ -17,79 +17,305 @@
#include "gl/builders/GrGLFragmentShaderBuilder.h"
#include "gl/builders/GrGLProgramBuilder.h"
-static bool can_tweak_alpha_for_coverage(GrBlendCoeff dstCoeff) {
- /*
- The fractional coverage is f.
- The src and dst coeffs are Cs and Cd.
- The dst and src colors are S and D.
- We want the blend to compute: f*Cs*S + (f*Cd + (1-f))D. By tweaking the source color's alpha
- 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.
+/**
+ * Wraps the shader outputs and HW blend state that comprise a Porter Duff blend mode with coverage.
+ */
+struct BlendFormula {
+public:
+ /**
+ * Values the shader can write to primary and secondary outputs. These must all be modulated by
+ * coverage to support mixed samples. The XP will ignore the multiplies when not using coverage.
*/
- return kOne_GrBlendCoeff == dstCoeff ||
- kISA_GrBlendCoeff == dstCoeff ||
- kISC_GrBlendCoeff == dstCoeff;
-}
+ enum OutputType {
+ kNone_OutputType, //<! 0
+ kCoverage_OutputType, //<! inputCoverage
+ kModulate_OutputType, //<! inputColor * inputCoverage
+ kISAModulate_OutputType, //<! (1 - inputColor.a) * inputCoverage
+ kISCModulate_OutputType, //<! (1 - inputColor) * inputCoverage
+
+ kLast_OutputType = kISCModulate_OutputType
+ };
-class PorterDuffXferProcessor : public GrXferProcessor {
-public:
- static GrXferProcessor* Create(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend,
- GrColor constant, const DstTexture* dstTexture,
- bool willReadDstColor) {
- return SkNEW_ARGS(PorterDuffXferProcessor, (srcBlend, dstBlend, constant, dstTexture,
- willReadDstColor));
- }
+ enum Properties {
+ kModifiesDst_Property = 1,
+ kUsesDstColor_Property = 1 << 1,
+ kUsesInputColor_Property = 1 << 2,
+ kCanTweakAlphaForCoverage_Property = 1 << 3,
+
+ kLast_Property = kCanTweakAlphaForCoverage_Property
+ };
- ~PorterDuffXferProcessor() override;
+ BlendFormula& operator =(const BlendFormula& other) {
+ fData = other.fData;
+ return *this;
+ }
- const char* name() const override { return "Porter Duff"; }
+ bool operator ==(const BlendFormula& other) const {
+ return fData == other.fData;
+ }
- GrGLXferProcessor* createGLInstance() const override;
+ bool hasSecondaryOutput() const { return kNone_OutputType != fSecondaryOutputType; }
+ bool modifiesDst() const { return SkToBool(fProps & kModifiesDst_Property); }
+ bool usesDstColor() const { return SkToBool(fProps & kUsesDstColor_Property); }
+ bool usesInputColor() const { return SkToBool(fProps & kUsesInputColor_Property); }
+ bool canTweakAlphaForCoverage() const {
+ return SkToBool(fProps & kCanTweakAlphaForCoverage_Property);
+ }
- bool hasSecondaryOutput() const override;
-
- ///////////////////////////////////////////////////////////////////////////
- /// @name Stage Output Types
- ////
-
- enum PrimaryOutputType {
- kNone_PrimaryOutputType,
- kColor_PrimaryOutputType,
- kCoverage_PrimaryOutputType,
- // Modulate color and coverage, write result as the color output.
- kModulate_PrimaryOutputType,
- // Custom Porter-Duff output, used for when we explictly are reading the dst and blending
- // in the shader. Secondary Output must be none if you use this. The custom blend uses the
- // equation: cov * (coeffS * S + coeffD * D) + (1 - cov) * D
- kCustom_PrimaryOutputType
+ /**
+ * Deduce the properties of a compile-time constant BlendFormula.
+ */
+ template<OutputType PrimaryOut, OutputType SecondaryOut,
+ GrBlendEquation BlendEquation, GrBlendCoeff SrcCoeff, GrBlendCoeff DstCoeff>
+ struct get_properties : SkTIntegralConstant<Properties, static_cast<Properties>(
+
+ (GR_BLEND_MODIFIES_DST(BlendEquation, SrcCoeff, DstCoeff) ?
+ kModifiesDst_Property : 0) |
+
+ (GR_BLEND_COEFFS_USE_DST_COLOR(SrcCoeff, DstCoeff) ?
+ kUsesDstColor_Property : 0) |
+
+ ((PrimaryOut >= kModulate_OutputType && GR_BLEND_COEFFS_USE_SRC_COLOR(SrcCoeff,DstCoeff)) ||
+ (SecondaryOut >= kModulate_OutputType && GR_BLEND_COEFF_REFS_SRC2(DstCoeff)) ?
+ kUsesInputColor_Property : 0) | // We assert later that SrcCoeff doesn't ref src2.
+
+ (kModulate_OutputType == PrimaryOut &&
+ kNone_OutputType == SecondaryOut &&
+ GR_BLEND_CAN_TWEAK_ALPHA_FOR_COVERAGE(BlendEquation, SrcCoeff, DstCoeff) ?
+ kCanTweakAlphaForCoverage_Property : 0))> {
+
+ // The provided formula should already be optimized.
+ GR_STATIC_ASSERT((kNone_OutputType == PrimaryOut) ==
+ !GR_BLEND_COEFFS_USE_SRC_COLOR(SrcCoeff, DstCoeff));
+ GR_STATIC_ASSERT(!GR_BLEND_COEFF_REFS_SRC2(SrcCoeff));
+ GR_STATIC_ASSERT((kNone_OutputType == SecondaryOut) ==
+ !GR_BLEND_COEFF_REFS_SRC2(DstCoeff));
+ GR_STATIC_ASSERT(PrimaryOut != SecondaryOut || kNone_OutputType == PrimaryOut);
+ GR_STATIC_ASSERT(kNone_OutputType != PrimaryOut || kNone_OutputType == SecondaryOut);
};
- enum SecondaryOutputType {
- // There is no secondary output
- kNone_SecondaryOutputType,
- // Writes coverage as the secondary output. Only set if dual source blending is supported
- // and primary output is kModulate.
- kCoverage_SecondaryOutputType,
- // Writes coverage * (1 - colorA) as the secondary output. Only set if dual source blending
- // is supported and primary output is kModulate.
- kCoverageISA_SecondaryOutputType,
- // Writes coverage * (1 - colorRGBA) as the secondary output. Only set if dual source
- // blending is supported and primary output is kModulate.
- kCoverageISC_SecondaryOutputType,
-
- kSecondaryOutputTypeCnt,
+ union {
+ struct {
+ // We allot the enums one more bit than they require because MSVC seems to sign-extend
+ // them when the top bit is set. (This is in violation of the C++03 standard 9.6/4)
+ OutputType fPrimaryOutputType : 4;
+ OutputType fSecondaryOutputType : 4;
+ GrBlendEquation fBlendEquation : 6;
+ GrBlendCoeff fSrcCoeff : 6;
+ GrBlendCoeff fDstCoeff : 6;
+ Properties fProps : 32 - (4 + 4 + 6 + 6 + 6);
+ };
+ uint32_t fData;
};
- PrimaryOutputType primaryOutputType() const { return fPrimaryOutputType; }
- SecondaryOutputType secondaryOutputType() const { return fSecondaryOutputType; }
+ GR_STATIC_ASSERT(kLast_OutputType < (1 << 3));
+ GR_STATIC_ASSERT(kLast_GrBlendEquation < (1 << 5));
+ GR_STATIC_ASSERT(kLast_GrBlendCoeff < (1 << 5));
+ GR_STATIC_ASSERT(kLast_Property < (1 << 6));
+};
+
+GR_STATIC_ASSERT(4 == sizeof(BlendFormula));
+
+GR_MAKE_BITFIELD_OPS(BlendFormula::Properties);
+
+/**
+ * Initialize a compile-time constant BlendFormula and automatically deduce fProps.
+ */
+#define INIT_BLEND_FORMULA(PRIMARY_OUT, SECONDARY_OUT, BLEND_EQUATION, SRC_COEFF, DST_COEFF) \
+ {{{PRIMARY_OUT, \
+ SECONDARY_OUT, \
+ BLEND_EQUATION, SRC_COEFF, DST_COEFF, \
+ BlendFormula::get_properties<PRIMARY_OUT, SECONDARY_OUT, \
+ BLEND_EQUATION, SRC_COEFF, DST_COEFF>::value}}}
+
+/**
+ * When there is no coverage, or the blend mode can tweak alpha for coverage, we use the standard
+ * Porter Duff formula.
+ */
+#define COEFF_FORMULA(SRC_COEFF, DST_COEFF) \
+ INIT_BLEND_FORMULA(BlendFormula::kModulate_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.
+ */
+#define DST_CLEAR_FORMULA \
+ INIT_BLEND_FORMULA(BlendFormula::kNone_OutputType, \
+ BlendFormula::kNone_OutputType, \
+ kAdd_GrBlendEquation, kZero_GrBlendCoeff, kZero_GrBlendCoeff)
+
+/**
+ * When the coeffs are (Zero, One), we don't write to the dst at all. This formula has its own macro
+ * so we can set the primary output type to none.
+ */
+#define NO_DST_WRITE_FORMULA \
+ INIT_BLEND_FORMULA(BlendFormula::kNone_OutputType, \
+ BlendFormula::kNone_OutputType, \
+ kAdd_GrBlendEquation, kZero_GrBlendCoeff, kOne_GrBlendCoeff)
- GrBlendCoeff getSrcBlend() const { return fSrcBlend; }
- GrBlendCoeff getDstBlend() const { return fDstBlend; }
+/**
+ * When there is coverage, the equation with f=coverage is:
+ *
+ * D' = f * (S * srcCoeff + D * dstCoeff) + (1-f) * D
+ *
+ * This can be rewritten as:
+ *
+ * D' = f * S * srcCoeff + D * (1 - [f * (1 - dstCoeff)])
+ *
+ * To implement this formula, we output [f * (1 - dstCoeff)] for the secondary color and replace the
+ * HW dst coeff with IS2C.
+ *
+ * Xfer modes: dst-atop (Sa!=1)
+ */
+#define COVERAGE_FORMULA(ONE_MINUS_DST_COEFF_MODULATE_OUTPUT, SRC_COEFF) \
+ INIT_BLEND_FORMULA(BlendFormula::kModulate_OutputType, \
+ ONE_MINUS_DST_COEFF_MODULATE_OUTPUT, \
+ kAdd_GrBlendEquation, SRC_COEFF, kIS2C_GrBlendCoeff)
+
+/**
+ * When there is coverage and the src coeff is Zero, the equation with f=coverage becomes:
+ *
+ * D' = f * D * dstCoeff + (1-f) * D
+ *
+ * This can be rewritten as:
+ *
+ * D' = D - D * [f * (1 - dstCoeff)]
+ *
+ * To implement this formula, we output [f * (1 - dstCoeff)] for the primary color and use a reverse
+ * subtract HW blend equation with coeffs of (DC, One).
+ *
+ * Xfer modes: clear, dst-out (Sa=1), dst-in (Sa!=1), modulate (Sc!=1)
+ */
+#define COVERAGE_SRC_COEFF_ZERO_FORMULA(ONE_MINUS_DST_COEFF_MODULATE_OUTPUT) \
+ INIT_BLEND_FORMULA(ONE_MINUS_DST_COEFF_MODULATE_OUTPUT, \
+ BlendFormula::kNone_OutputType, \
+ kReverseSubtract_GrBlendEquation, kDC_GrBlendCoeff, kOne_GrBlendCoeff)
+
+/**
+ * When there is coverage and the dst coeff is Zero, the equation with f=coverage becomes:
+ *
+ * D' = f * S * srcCoeff + (1-f) * D
+ *
+ * To implement this formula, we output [f] for the secondary color and replace the HW dst coeff
+ * with IS2A. (Note that we can avoid dual source blending when Sa=1 by using ISA.)
+ *
+ * Xfer modes (Sa!=1): src, src-in, src-out
+ */
+#define COVERAGE_DST_COEFF_ZERO_FORMULA(SRC_COEFF) \
+ INIT_BLEND_FORMULA(BlendFormula::kModulate_OutputType, \
+ BlendFormula::kCoverage_OutputType, \
+ kAdd_GrBlendEquation, SRC_COEFF, kIS2A_GrBlendCoeff)
+
+/**
+ * This table outlines the blend formulas we will use with each xfermode, with and without coverage,
+ * with and without an opaque input color. Optimization properties are deduced at compile time so we
+ * can make runtime decisions quickly. RGB coverage is not supported.
+ */
+static const BlendFormula gBlendTable[2][2][SkXfermode::kLastCoeffMode + 1] = {
+
+ /*>> No coverage, input color unknown <<*/ {{
+
+ /* clear */ DST_CLEAR_FORMULA,
+ /* src */ COEFF_FORMULA( kOne_GrBlendCoeff, kZero_GrBlendCoeff),
+ /* dst */ NO_DST_WRITE_FORMULA,
+ /* src-over */ COEFF_FORMULA( kOne_GrBlendCoeff, kISA_GrBlendCoeff),
+ /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
+ /* src-in */ COEFF_FORMULA( kDA_GrBlendCoeff, kZero_GrBlendCoeff),
+ /* dst-in */ COEFF_FORMULA( kZero_GrBlendCoeff, kSA_GrBlendCoeff),
+ /* src-out */ COEFF_FORMULA( kIDA_GrBlendCoeff, kZero_GrBlendCoeff),
+ /* dst-out */ COEFF_FORMULA( kZero_GrBlendCoeff, kISA_GrBlendCoeff),
+ /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff),
+ /* dst-atop */ COEFF_FORMULA( kIDA_GrBlendCoeff, kSA_GrBlendCoeff),
+ /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff),
+ /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff),
+ /* modulate */ COEFF_FORMULA( kZero_GrBlendCoeff, kSC_GrBlendCoeff),
+ /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff),
+
+ }, /*>> Has coverage, input color unknown <<*/ {
+
+ /* clear */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_OutputType),
+ /* src */ COVERAGE_DST_COEFF_ZERO_FORMULA(kOne_GrBlendCoeff),
+ /* dst */ NO_DST_WRITE_FORMULA,
+ /* src-over */ COEFF_FORMULA( kOne_GrBlendCoeff, kISA_GrBlendCoeff),
+ /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
+ /* src-in */ COVERAGE_DST_COEFF_ZERO_FORMULA(kDA_GrBlendCoeff),
+ /* dst-in */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISAModulate_OutputType),
+ /* src-out */ COVERAGE_DST_COEFF_ZERO_FORMULA(kIDA_GrBlendCoeff),
+ /* dst-out */ COEFF_FORMULA( kZero_GrBlendCoeff, kISA_GrBlendCoeff),
+ /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff),
+ /* dst-atop */ COVERAGE_FORMULA(BlendFormula::kISAModulate_OutputType, kIDA_GrBlendCoeff),
+ /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff),
+ /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff),
+ /* modulate */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kISCModulate_OutputType),
+ /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff),
+
+ }}, /*>> No coverage, input color opaque <<*/ {{
+
+ /* clear */ DST_CLEAR_FORMULA,
+ /* src */ COEFF_FORMULA( kOne_GrBlendCoeff, kZero_GrBlendCoeff),
+ /* dst */ NO_DST_WRITE_FORMULA,
+ /* src-over */ COEFF_FORMULA( kOne_GrBlendCoeff, kZero_GrBlendCoeff),
+ /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
+ /* src-in */ COEFF_FORMULA( kDA_GrBlendCoeff, kZero_GrBlendCoeff),
+ /* dst-in */ NO_DST_WRITE_FORMULA,
+ /* src-out */ COEFF_FORMULA( kIDA_GrBlendCoeff, kZero_GrBlendCoeff),
+ /* dst-out */ DST_CLEAR_FORMULA,
+ /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kZero_GrBlendCoeff),
+ /* dst-atop */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
+ /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kZero_GrBlendCoeff),
+ /* plus */ COEFF_FORMULA( kOne_GrBlendCoeff, kOne_GrBlendCoeff),
+ /* modulate */ COEFF_FORMULA( kZero_GrBlendCoeff, kSC_GrBlendCoeff),
+ /* screen */ COEFF_FORMULA( kOne_GrBlendCoeff, kISC_GrBlendCoeff),
+
+ }, /*>> Has coverage, input color opaque <<*/ {
+
+ /* clear */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_OutputType),
+ /* src */ COEFF_FORMULA( kOne_GrBlendCoeff, kISA_GrBlendCoeff),
+ /* dst */ NO_DST_WRITE_FORMULA,
+ /* src-over */ COEFF_FORMULA( kOne_GrBlendCoeff, kISA_GrBlendCoeff),
+ /* dst-over */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
+ /* src-in */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff),
+ /* dst-in */ NO_DST_WRITE_FORMULA,
+ /* src-out */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_GrBlendCoeff),
+ /* dst-out */ COVERAGE_SRC_COEFF_ZERO_FORMULA(BlendFormula::kCoverage_OutputType),
+ /* src-atop */ COEFF_FORMULA( kDA_GrBlendCoeff, kISA_GrBlendCoeff),
+ /* dst-atop */ COEFF_FORMULA( kIDA_GrBlendCoeff, kOne_GrBlendCoeff),
+ /* xor */ COEFF_FORMULA( kIDA_GrBlendCoeff, kISA_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(SkXfermode::Mode xfermode,
+ const GrProcOptInfo& colorPOI,
+ const GrProcOptInfo& coveragePOI) {
+ SkASSERT(xfermode >= 0 && xfermode <= SkXfermode::kLastCoeffMode);
+ SkASSERT(!coveragePOI.isFourChannelOutput());
+
+ return gBlendTable[colorPOI.isOpaque()][!coveragePOI.isSolidWhite()][xfermode];
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+class PorterDuffXferProcessor : public GrXferProcessor {
+public:
+ static GrXferProcessor* Create(BlendFormula blendFormula) {
+ return SkNEW_ARGS(PorterDuffXferProcessor, (blendFormula));
+ }
+
+ const char* name() const override { return "Porter Duff"; }
+ bool hasSecondaryOutput() const override { return fBlendFormula.hasSecondaryOutput(); }
+
+ GrGLXferProcessor* createGLInstance() const override;
+
+ BlendFormula getBlendFormula() const { return fBlendFormula; }
private:
- PorterDuffXferProcessor(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend, GrColor constant,
- const DstTexture*, bool willReadDstColor);
+ PorterDuffXferProcessor(BlendFormula blendFormula) : fBlendFormula(blendFormula) {
+ this->initClassID<PorterDuffXferProcessor>();
+ }
GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo& colorPOI,
const GrProcOptInfo& coveragePOI,
@@ -100,204 +326,100 @@ private:
void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
void onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) const override {
- if (!this->willReadDstColor()) {
- blendInfo->fSrcBlend = fSrcBlend;
- blendInfo->fDstBlend = fDstBlend;
- } else {
- blendInfo->fSrcBlend = kOne_GrBlendCoeff;
- blendInfo->fDstBlend = kZero_GrBlendCoeff;
- }
- blendInfo->fBlendConstant = fBlendConstant;
+ blendInfo->fEquation = fBlendFormula.fBlendEquation;
+ blendInfo->fSrcBlend = fBlendFormula.fSrcCoeff;
+ blendInfo->fDstBlend = fBlendFormula.fDstCoeff;
+ blendInfo->fWriteColor = fBlendFormula.modifiesDst();
}
bool onIsEqual(const GrXferProcessor& xpBase) const override {
const PorterDuffXferProcessor& xp = xpBase.cast<PorterDuffXferProcessor>();
- if (fSrcBlend != xp.fSrcBlend ||
- fDstBlend != xp.fDstBlend ||
- fBlendConstant != xp.fBlendConstant ||
- fPrimaryOutputType != xp.fPrimaryOutputType ||
- fSecondaryOutputType != xp.fSecondaryOutputType) {
- return false;
- }
- return true;
+ return fBlendFormula == xp.fBlendFormula;
}
- GrXferProcessor::OptFlags internalGetOptimizations(const GrProcOptInfo& colorPOI,
- const GrProcOptInfo& coveragePOI,
- bool doesStencilWrite);
-
- void calcOutputTypes(GrXferProcessor::OptFlags blendOpts, const GrCaps& caps,
- bool hasSolidCoverage);
-
- GrBlendCoeff fSrcBlend;
- GrBlendCoeff fDstBlend;
- GrColor fBlendConstant;
- PrimaryOutputType fPrimaryOutputType;
- SecondaryOutputType fSecondaryOutputType;
+ const BlendFormula fBlendFormula;
typedef GrXferProcessor INHERITED;
};
///////////////////////////////////////////////////////////////////////////////
-bool append_porterduff_term(GrGLXPFragmentBuilder* fsBuilder, GrBlendCoeff coeff,
- const char* colorName, const char* srcColorName,
- const char* dstColorName, bool hasPrevious) {
- if (kZero_GrBlendCoeff == coeff) {
- return hasPrevious;
- } else {
- if (hasPrevious) {
- fsBuilder->codeAppend(" + ");
- }
- fsBuilder->codeAppendf("%s", colorName);
- switch (coeff) {
- case kOne_GrBlendCoeff:
- break;
- case kSC_GrBlendCoeff:
- fsBuilder->codeAppendf(" * %s", srcColorName);
- break;
- case kISC_GrBlendCoeff:
- fsBuilder->codeAppendf(" * (vec4(1.0) - %s)", srcColorName);
- break;
- case kDC_GrBlendCoeff:
- fsBuilder->codeAppendf(" * %s", dstColorName);
- break;
- case kIDC_GrBlendCoeff:
- fsBuilder->codeAppendf(" * (vec4(1.0) - %s)", dstColorName);
- break;
- case kSA_GrBlendCoeff:
- fsBuilder->codeAppendf(" * %s.a", srcColorName);
- break;
- case kISA_GrBlendCoeff:
- fsBuilder->codeAppendf(" * (1.0 - %s.a)", srcColorName);
- break;
- case kDA_GrBlendCoeff:
- fsBuilder->codeAppendf(" * %s.a", dstColorName);
- break;
- case kIDA_GrBlendCoeff:
- fsBuilder->codeAppendf(" * (1.0 - %s.a)", dstColorName);
- break;
- default:
- SkFAIL("Unsupported Blend Coeff");
- }
- return true;
+static void append_color_output(const PorterDuffXferProcessor& xp, GrGLXPFragmentBuilder* fsBuilder,
+ BlendFormula::OutputType outputType, const char* output,
+ const char* inColor, const char* inCoverage) {
+ switch (outputType) {
+ case BlendFormula::kNone_OutputType:
+ fsBuilder->codeAppendf("%s = vec4(0.0);", output);
+ break;
+ case BlendFormula::kCoverage_OutputType:
+ fsBuilder->codeAppendf("%s = %s;",
+ output, xp.readsCoverage() ? inCoverage : "vec4(1.0)");
+ break;
+ case BlendFormula::kModulate_OutputType:
+ if (xp.readsCoverage()) {
+ fsBuilder->codeAppendf("%s = %s * %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);
+ } else {
+ fsBuilder->codeAppendf("%s = vec4(1.0 - %s.a);", output, inColor);
+ }
+ break;
+ case BlendFormula::kISCModulate_OutputType:
+ if (xp.readsCoverage()) {
+ fsBuilder->codeAppendf("%s = (vec4(1.0) - %s) * %s;", output, inColor, inCoverage);
+ } else {
+ fsBuilder->codeAppendf("%s = vec4(1.0) - %s;", output, inColor);
+ }
+ break;
+ default:
+ SkFAIL("Unsupported output type.");
+ break;
}
}
class GLPorterDuffXferProcessor : public GrGLXferProcessor {
public:
- GLPorterDuffXferProcessor(const GrProcessor&) {}
-
- virtual ~GLPorterDuffXferProcessor() {}
-
- static void GenKey(const GrProcessor& processor, const GrGLSLCaps& caps,
- GrProcessorKeyBuilder* b) {
+ static void GenKey(const GrProcessor& processor, GrProcessorKeyBuilder* b) {
const PorterDuffXferProcessor& xp = processor.cast<PorterDuffXferProcessor>();
- b->add32(xp.primaryOutputType());
- b->add32(xp.secondaryOutputType());
- if (xp.willReadDstColor()) {
- b->add32(xp.getSrcBlend());
- b->add32(xp.getDstBlend());
- }
+ b->add32(SkToInt(xp.readsCoverage()) |
+ (xp.getBlendFormula().fPrimaryOutputType << 1) |
+ (xp.getBlendFormula().fSecondaryOutputType << 4));
+ GR_STATIC_ASSERT(BlendFormula::kLast_OutputType < 8);
};
private:
void onEmitCode(const EmitArgs& args) override {
const PorterDuffXferProcessor& xp = args.fXP.cast<PorterDuffXferProcessor>();
GrGLXPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
- if (PorterDuffXferProcessor::kCustom_PrimaryOutputType != xp.primaryOutputType()) {
- SkASSERT(!xp.willReadDstColor());
- switch(xp.secondaryOutputType()) {
- case PorterDuffXferProcessor::kNone_SecondaryOutputType:
- break;
- case PorterDuffXferProcessor::kCoverage_SecondaryOutputType:
- fsBuilder->codeAppendf("%s = %s;", args.fOutputSecondary,
- args.fInputCoverage);
- break;
- case PorterDuffXferProcessor::kCoverageISA_SecondaryOutputType:
- fsBuilder->codeAppendf("%s = (1.0 - %s.a) * %s;",
- args.fOutputSecondary, args.fInputColor,
- args.fInputCoverage);
- break;
- case PorterDuffXferProcessor::kCoverageISC_SecondaryOutputType:
- fsBuilder->codeAppendf("%s = (vec4(1.0) - %s) * %s;",
- args.fOutputSecondary, args.fInputColor,
- args.fInputCoverage);
- break;
- default:
- SkFAIL("Unexpected Secondary Output");
- }
- switch (xp.primaryOutputType()) {
- case PorterDuffXferProcessor::kNone_PrimaryOutputType:
- fsBuilder->codeAppendf("%s = vec4(0);", args.fOutputPrimary);
- break;
- case PorterDuffXferProcessor::kColor_PrimaryOutputType:
- fsBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, args.fInputColor);
- break;
- case PorterDuffXferProcessor::kCoverage_PrimaryOutputType:
- fsBuilder->codeAppendf("%s = %s;", args.fOutputPrimary, args.fInputCoverage);
- break;
- case PorterDuffXferProcessor::kModulate_PrimaryOutputType:
- fsBuilder->codeAppendf("%s = %s * %s;", args.fOutputPrimary, args.fInputColor,
- args.fInputCoverage);
- break;
- default:
- SkFAIL("Unexpected Primary Output");
- }
- } else {
- SkASSERT(xp.willReadDstColor());
-
- const char* dstColor = fsBuilder->dstColor();
-
- fsBuilder->codeAppend("vec4 colorBlend =");
- // append src blend
- bool didAppend = append_porterduff_term(fsBuilder, xp.getSrcBlend(),
- args.fInputColor, args.fInputColor,
- dstColor, false);
- // append dst blend
- SkAssertResult(append_porterduff_term(fsBuilder, xp.getDstBlend(),
- dstColor, args.fInputColor,
- dstColor, didAppend));
- fsBuilder->codeAppend(";");
-
- fsBuilder->codeAppendf("%s = %s * colorBlend + (vec4(1.0) - %s) * %s;",
- args.fOutputPrimary, args.fInputCoverage, args.fInputCoverage,
- dstColor);
+ BlendFormula blendFormula = xp.getBlendFormula();
+ if (blendFormula.hasSecondaryOutput()) {
+ append_color_output(xp, fsBuilder, blendFormula.fSecondaryOutputType,
+ args.fOutputSecondary, args.fInputColor, args.fInputCoverage);
}
+ append_color_output(xp, fsBuilder, blendFormula.fPrimaryOutputType,
+ args.fOutputPrimary, args.fInputColor, args.fInputCoverage);
}
- void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) override {};
+ void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) override {}
typedef GrGLXferProcessor INHERITED;
};
///////////////////////////////////////////////////////////////////////////////
-PorterDuffXferProcessor::PorterDuffXferProcessor(GrBlendCoeff srcBlend,
- GrBlendCoeff dstBlend,
- GrColor constant,
- const DstTexture* dstTexture,
- bool willReadDstColor)
- : INHERITED(dstTexture, willReadDstColor)
- , fSrcBlend(srcBlend)
- , fDstBlend(dstBlend)
- , fBlendConstant(constant)
- , fPrimaryOutputType(kModulate_PrimaryOutputType)
- , fSecondaryOutputType(kNone_SecondaryOutputType) {
- this->initClassID<PorterDuffXferProcessor>();
-}
-
-PorterDuffXferProcessor::~PorterDuffXferProcessor() {
-}
-
-void PorterDuffXferProcessor::onGetGLProcessorKey(const GrGLSLCaps& caps,
+void PorterDuffXferProcessor::onGetGLProcessorKey(const GrGLSLCaps&,
GrProcessorKeyBuilder* b) const {
- GLPorterDuffXferProcessor::GenKey(*this, caps, b);
+ GLPorterDuffXferProcessor::GenKey(*this, b);
}
GrGLXferProcessor* PorterDuffXferProcessor::createGLInstance() const {
- return SkNEW_ARGS(GLPorterDuffXferProcessor, (*this));
+ return SkNEW(GLPorterDuffXferProcessor);
}
GrXferProcessor::OptFlags
@@ -306,168 +428,167 @@ PorterDuffXferProcessor::onGetOptimizations(const GrProcOptInfo& colorPOI,
bool doesStencilWrite,
GrColor* overrideColor,
const GrCaps& caps) {
- GrXferProcessor::OptFlags optFlags = this->internalGetOptimizations(colorPOI,
- coveragePOI,
- doesStencilWrite);
- this->calcOutputTypes(optFlags, caps, coveragePOI.isSolidWhite());
+ GrXferProcessor::OptFlags optFlags = GrXferProcessor::kNone_Opt;
+ if (!fBlendFormula.modifiesDst()) {
+ if (!doesStencilWrite) {
+ optFlags |= GrXferProcessor::kSkipDraw_OptFlag;
+ }
+ optFlags |= (GrXferProcessor::kIgnoreColor_OptFlag |
+ GrXferProcessor::kIgnoreCoverage_OptFlag |
+ GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag);
+ } else {
+ if (!fBlendFormula.usesInputColor()) {
+ optFlags |= GrXferProcessor::kIgnoreColor_OptFlag;
+ }
+ if (coveragePOI.isSolidWhite()) {
+ optFlags |= GrXferProcessor::kIgnoreCoverage_OptFlag;
+ }
+ if (colorPOI.allStagesMultiplyInput() && fBlendFormula.canTweakAlphaForCoverage()) {
+ optFlags |= GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag;
+ }
+ }
return optFlags;
}
-void PorterDuffXferProcessor::calcOutputTypes(GrXferProcessor::OptFlags optFlags,
- const GrCaps& caps,
- bool hasSolidCoverage) {
- if (this->willReadDstColor()) {
- fPrimaryOutputType = kCustom_PrimaryOutputType;
- return;
+///////////////////////////////////////////////////////////////////////////////
+
+class ShaderPDXferProcessor : public GrXferProcessor {
+public:
+ static GrXferProcessor* Create(SkXfermode::Mode xfermode, const DstTexture* dstTexture) {
+ return SkNEW_ARGS(ShaderPDXferProcessor, (xfermode, dstTexture));
}
- if (optFlags & kIgnoreColor_OptFlag) {
- if (optFlags & kIgnoreCoverage_OptFlag) {
- fPrimaryOutputType = kNone_PrimaryOutputType;
- return;
- } else {
- fPrimaryOutputType = kCoverage_PrimaryOutputType;
- return;
- }
- } else if (optFlags & kIgnoreCoverage_OptFlag) {
- fPrimaryOutputType = kColor_PrimaryOutputType;
- return;
+ const char* name() const override { return "Porter Duff Shader"; }
+ bool hasSecondaryOutput() const override { return false; }
+
+ GrGLXferProcessor* createGLInstance() const override;
+
+ SkXfermode::Mode getXfermode() const { return fXfermode; }
+
+private:
+ ShaderPDXferProcessor(SkXfermode::Mode xfermode, const DstTexture* dstTexture)
+ : INHERITED(dstTexture, true)
+ , fXfermode(xfermode) {
+ this->initClassID<ShaderPDXferProcessor>();
}
- // If we do have coverage determine whether it matters. Dual source blending is expensive so
- // we don't do it if we are doing coverage drawing. If we aren't then We always do dual source
- // blending if we have any effective coverage stages OR the geometry processor doesn't emits
- // solid coverage.
- if (!(optFlags & kSetCoverageDrawing_OptFlag) && !hasSolidCoverage) {
- if (caps.shaderCaps()->dualSourceBlendingSupport()) {
- if (kZero_GrBlendCoeff == fDstBlend) {
- // write the coverage value to second color
- fSecondaryOutputType = kCoverage_SecondaryOutputType;
- fDstBlend = kIS2C_GrBlendCoeff;
- } else if (kSA_GrBlendCoeff == fDstBlend) {
- // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
- fSecondaryOutputType = kCoverageISA_SecondaryOutputType;
- fDstBlend = kIS2C_GrBlendCoeff;
- } else if (kSC_GrBlendCoeff == fDstBlend) {
- // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
- fSecondaryOutputType = kCoverageISC_SecondaryOutputType;
- fDstBlend = kIS2C_GrBlendCoeff;
- }
- }
+ GrXferProcessor::OptFlags onGetOptimizations(const GrProcOptInfo&, const GrProcOptInfo&,
+ bool, GrColor*, const GrCaps&) override {
+ return kNone_Opt;
}
-}
-GrXferProcessor::OptFlags
-PorterDuffXferProcessor::internalGetOptimizations(const GrProcOptInfo& colorPOI,
- const GrProcOptInfo& coveragePOI,
- bool doesStencilWrite) {
- if (this->willReadDstColor()) {
- return GrXferProcessor::kNone_Opt;
+ void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
+
+ bool onIsEqual(const GrXferProcessor& xpBase) const override {
+ const ShaderPDXferProcessor& xp = xpBase.cast<ShaderPDXferProcessor>();
+ return fXfermode == xp.fXfermode;
}
- bool srcAIsOne = colorPOI.isOpaque();
- bool hasCoverage = !coveragePOI.isSolidWhite();
-
- bool dstCoeffIsOne = kOne_GrBlendCoeff == fDstBlend ||
- (kSA_GrBlendCoeff == fDstBlend && srcAIsOne);
- bool dstCoeffIsZero = kZero_GrBlendCoeff == fDstBlend ||
- (kISA_GrBlendCoeff == fDstBlend && srcAIsOne);
-
- // When coeffs are (0,1) there is no reason to draw at all, unless
- // stenciling is enabled. Having color writes disabled is effectively
- // (0,1).
- if ((kZero_GrBlendCoeff == fSrcBlend && dstCoeffIsOne)) {
- if (doesStencilWrite) {
- return GrXferProcessor::kIgnoreColor_OptFlag |
- GrXferProcessor::kSetCoverageDrawing_OptFlag;
- } else {
- fDstBlend = kOne_GrBlendCoeff;
- return GrXferProcessor::kSkipDraw_OptFlag;
+ const SkXfermode::Mode fXfermode;
+
+ typedef GrXferProcessor INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static bool append_porterduff_term(GrGLXPFragmentBuilder* fsBuilder, SkXfermode::Coeff coeff,
+ const char* colorName, const char* srcColorName,
+ const char* dstColorName, bool hasPrevious) {
+ if (SkXfermode::kZero_Coeff == coeff) {
+ return hasPrevious;
+ } else {
+ if (hasPrevious) {
+ fsBuilder->codeAppend(" + ");
+ }
+ fsBuilder->codeAppendf("%s", colorName);
+ switch (coeff) {
+ case SkXfermode::kOne_Coeff:
+ break;
+ case SkXfermode::kSC_Coeff:
+ fsBuilder->codeAppendf(" * %s", srcColorName);
+ break;
+ case SkXfermode::kISC_Coeff:
+ fsBuilder->codeAppendf(" * (vec4(1.0) - %s)", srcColorName);
+ break;
+ case SkXfermode::kDC_Coeff:
+ fsBuilder->codeAppendf(" * %s", dstColorName);
+ break;
+ case SkXfermode::kIDC_Coeff:
+ fsBuilder->codeAppendf(" * (vec4(1.0) - %s)", dstColorName);
+ break;
+ case SkXfermode::kSA_Coeff:
+ fsBuilder->codeAppendf(" * %s.a", srcColorName);
+ break;
+ case SkXfermode::kISA_Coeff:
+ fsBuilder->codeAppendf(" * (1.0 - %s.a)", srcColorName);
+ break;
+ case SkXfermode::kDA_Coeff:
+ fsBuilder->codeAppendf(" * %s.a", dstColorName);
+ break;
+ case SkXfermode::kIDA_Coeff:
+ fsBuilder->codeAppendf(" * (1.0 - %s.a)", dstColorName);
+ break;
+ default:
+ SkFAIL("Unsupported Blend Coeff");
}
+ return true;
}
+}
- // if we don't have coverage we can check whether the dst
- // has to read at all. If not, we'll disable blending.
- if (!hasCoverage) {
- if (dstCoeffIsZero) {
- if (kOne_GrBlendCoeff == fSrcBlend) {
- // if there is no coverage and coeffs are (1,0) then we
- // won't need to read the dst at all, it gets replaced by src
- fDstBlend = kZero_GrBlendCoeff;
- return GrXferProcessor::kNone_Opt |
- GrXferProcessor::kIgnoreCoverage_OptFlag;
- } else if (kZero_GrBlendCoeff == fSrcBlend) {
- // if the op is "clear" then we don't need to emit a color
- // or blend, just write transparent black into the dst.
- fSrcBlend = kOne_GrBlendCoeff;
- fDstBlend = kZero_GrBlendCoeff;
- return GrXferProcessor::kIgnoreColor_OptFlag |
- GrXferProcessor::kIgnoreCoverage_OptFlag;
- }
- }
- return GrXferProcessor::kIgnoreCoverage_OptFlag;
+class GLShaderPDXferProcessor : public GrGLXferProcessor {
+public:
+ static void GenKey(const GrProcessor& processor, GrProcessorKeyBuilder* b) {
+ const ShaderPDXferProcessor& xp = processor.cast<ShaderPDXferProcessor>();
+ b->add32(xp.getXfermode());
}
- // 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)) {
- if (colorPOI.allStagesMultiplyInput()) {
- return GrXferProcessor::kSetCoverageDrawing_OptFlag |
- GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag;
- } else {
- return GrXferProcessor::kSetCoverageDrawing_OptFlag;
+private:
+ void onEmitCode(const EmitArgs& args) override {
+ const ShaderPDXferProcessor& xp = args.fXP.cast<ShaderPDXferProcessor>();
+ GrGLXPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
- }
+ SkXfermode::Coeff srcCoeff, dstCoeff;
+ SkXfermode::ModeAsCoeff(xp.getXfermode(), &srcCoeff, &dstCoeff);
+
+ const char* dstColor = fsBuilder->dstColor();
+
+ fsBuilder->codeAppend("vec4 colorBlend =");
+ // append src blend
+ bool didAppend = append_porterduff_term(fsBuilder, srcCoeff,
+ args.fInputColor, args.fInputColor,
+ dstColor, false);
+ // append dst blend
+ SkAssertResult(append_porterduff_term(fsBuilder, dstCoeff,
+ dstColor, args.fInputColor,
+ dstColor, didAppend));
+ fsBuilder->codeAppend(";");
+
+ fsBuilder->codeAppendf("%s = %s * colorBlend + (vec4(1.0) - %s) * %s;",
+ args.fOutputPrimary, args.fInputCoverage, args.fInputCoverage,
+ dstColor);
}
- if (dstCoeffIsZero) {
- if (kZero_GrBlendCoeff == fSrcBlend) {
- // the source color is not included in the blend
- // the dst coeff is effectively zero so blend works out to:
- // (c)(0)D + (1-c)D = (1-c)D.
- fDstBlend = kISA_GrBlendCoeff;
- return GrXferProcessor::kIgnoreColor_OptFlag |
- GrXferProcessor::kSetCoverageDrawing_OptFlag;
- } else if (srcAIsOne) {
- // the dst coeff is effectively zero so blend works out to:
- // cS + (c)(0)D + (1-c)D = cS + (1-c)D.
- // If Sa is 1 then we can replace Sa with c
- // and set dst coeff to 1-Sa.
- fDstBlend = kISA_GrBlendCoeff;
- if (colorPOI.allStagesMultiplyInput()) {
- return GrXferProcessor::kSetCoverageDrawing_OptFlag |
- GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag;
- } else {
- return GrXferProcessor::kSetCoverageDrawing_OptFlag;
- }
- }
- } else if (dstCoeffIsOne) {
- // the dst coeff is effectively one so blend works out to:
- // cS + (c)(1)D + (1-c)D = cS + D.
- fDstBlend = kOne_GrBlendCoeff;
- if (colorPOI.allStagesMultiplyInput()) {
- return GrXferProcessor::kSetCoverageDrawing_OptFlag |
- GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag;
- } else {
- return GrXferProcessor::kSetCoverageDrawing_OptFlag;
+ void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) override {}
- }
- return GrXferProcessor::kSetCoverageDrawing_OptFlag;
- }
+ typedef GrGLXferProcessor INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
- return GrXferProcessor::kNone_Opt;
+void ShaderPDXferProcessor::onGetGLProcessorKey(const GrGLSLCaps&,
+ GrProcessorKeyBuilder* b) const {
+ GLShaderPDXferProcessor::GenKey(*this, b);
}
-bool PorterDuffXferProcessor::hasSecondaryOutput() const {
- return kNone_SecondaryOutputType != fSecondaryOutputType;
+GrGLXferProcessor* ShaderPDXferProcessor::createGLInstance() const {
+ return SkNEW(GLShaderPDXferProcessor);
}
///////////////////////////////////////////////////////////////////////////////
class PDLCDXferProcessor : public GrXferProcessor {
public:
- static GrXferProcessor* Create(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend,
- const GrProcOptInfo& colorPOI);
+ static GrXferProcessor* Create(SkXfermode::Mode xfermode, const GrProcOptInfo& colorPOI);
~PDLCDXferProcessor() override;
@@ -541,9 +662,9 @@ PDLCDXferProcessor::PDLCDXferProcessor(GrColor blendConstant, uint8_t alpha)
this->initClassID<PDLCDXferProcessor>();
}
-GrXferProcessor* PDLCDXferProcessor::Create(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend,
+GrXferProcessor* PDLCDXferProcessor::Create(SkXfermode::Mode xfermode,
const GrProcOptInfo& colorPOI) {
- if (kOne_GrBlendCoeff != srcBlend || kISA_GrBlendCoeff != dstBlend) {
+ if (SkXfermode::kSrcOver_Mode != xfermode) {
return NULL;
}
@@ -585,91 +706,40 @@ PDLCDXferProcessor::onGetOptimizations(const GrProcOptInfo& colorPOI,
}
///////////////////////////////////////////////////////////////////////////////
-GrPorterDuffXPFactory::GrPorterDuffXPFactory(GrBlendCoeff src, GrBlendCoeff dst)
- : fSrcCoeff(src), fDstCoeff(dst) {
+
+GrPorterDuffXPFactory::GrPorterDuffXPFactory(SkXfermode::Mode xfermode)
+ : fXfermode(xfermode) {
this->initClassID<GrPorterDuffXPFactory>();
}
-GrXPFactory* GrPorterDuffXPFactory::Create(SkXfermode::Mode mode) {
- switch (mode) {
- case SkXfermode::kClear_Mode: {
- static GrPorterDuffXPFactory gClearPDXPF(kZero_GrBlendCoeff, kZero_GrBlendCoeff);
- return SkRef(&gClearPDXPF);
- break;
- }
- case SkXfermode::kSrc_Mode: {
- static GrPorterDuffXPFactory gSrcPDXPF(kOne_GrBlendCoeff, kZero_GrBlendCoeff);
- return SkRef(&gSrcPDXPF);
- break;
- }
- case SkXfermode::kDst_Mode: {
- static GrPorterDuffXPFactory gDstPDXPF(kZero_GrBlendCoeff, kOne_GrBlendCoeff);
- return SkRef(&gDstPDXPF);
- break;
- }
- case SkXfermode::kSrcOver_Mode: {
- static GrPorterDuffXPFactory gSrcOverPDXPF(kOne_GrBlendCoeff, kISA_GrBlendCoeff);
- return SkRef(&gSrcOverPDXPF);
- break;
- }
- case SkXfermode::kDstOver_Mode: {
- static GrPorterDuffXPFactory gDstOverPDXPF(kIDA_GrBlendCoeff, kOne_GrBlendCoeff);
- return SkRef(&gDstOverPDXPF);
- break;
- }
- case SkXfermode::kSrcIn_Mode: {
- static GrPorterDuffXPFactory gSrcInPDXPF(kDA_GrBlendCoeff, kZero_GrBlendCoeff);
- return SkRef(&gSrcInPDXPF);
- break;
- }
- case SkXfermode::kDstIn_Mode: {
- static GrPorterDuffXPFactory gDstInPDXPF(kZero_GrBlendCoeff, kSA_GrBlendCoeff);
- return SkRef(&gDstInPDXPF);
- break;
- }
- case SkXfermode::kSrcOut_Mode: {
- static GrPorterDuffXPFactory gSrcOutPDXPF(kIDA_GrBlendCoeff, kZero_GrBlendCoeff);
- return SkRef(&gSrcOutPDXPF);
- break;
- }
- case SkXfermode::kDstOut_Mode: {
- static GrPorterDuffXPFactory gDstOutPDXPF(kZero_GrBlendCoeff, kISA_GrBlendCoeff);
- return SkRef(&gDstOutPDXPF);
- break;
- }
- case SkXfermode::kSrcATop_Mode: {
- static GrPorterDuffXPFactory gSrcATopPDXPF(kDA_GrBlendCoeff, kISA_GrBlendCoeff);
- return SkRef(&gSrcATopPDXPF);
- break;
- }
- case SkXfermode::kDstATop_Mode: {
- static GrPorterDuffXPFactory gDstATopPDXPF(kIDA_GrBlendCoeff, kSA_GrBlendCoeff);
- return SkRef(&gDstATopPDXPF);
- break;
- }
- case SkXfermode::kXor_Mode: {
- static GrPorterDuffXPFactory gXorPDXPF(kIDA_GrBlendCoeff, kISA_GrBlendCoeff);
- return SkRef(&gXorPDXPF);
- break;
- }
- case SkXfermode::kPlus_Mode: {
- static GrPorterDuffXPFactory gPlusPDXPF(kOne_GrBlendCoeff, kOne_GrBlendCoeff);
- return SkRef(&gPlusPDXPF);
- break;
- }
- case SkXfermode::kModulate_Mode: {
- static GrPorterDuffXPFactory gModulatePDXPF(kZero_GrBlendCoeff, kSC_GrBlendCoeff);
- return SkRef(&gModulatePDXPF);
- break;
- }
- case SkXfermode::kScreen_Mode: {
- static GrPorterDuffXPFactory gScreenPDXPF(kOne_GrBlendCoeff, kISC_GrBlendCoeff);
- return SkRef(&gScreenPDXPF);
- break;
- }
- default:
- return NULL;
+GrXPFactory* GrPorterDuffXPFactory::Create(SkXfermode::Mode xfermode) {
+ static GrPorterDuffXPFactory gClearPDXPF(SkXfermode::kClear_Mode);
+ static GrPorterDuffXPFactory gSrcPDXPF(SkXfermode::kSrc_Mode);
+ static GrPorterDuffXPFactory gDstPDXPF(SkXfermode::kDst_Mode);
+ static GrPorterDuffXPFactory gSrcOverPDXPF(SkXfermode::kSrcOver_Mode);
+ static GrPorterDuffXPFactory gDstOverPDXPF(SkXfermode::kDstOver_Mode);
+ static GrPorterDuffXPFactory gSrcInPDXPF(SkXfermode::kSrcIn_Mode);
+ static GrPorterDuffXPFactory gDstInPDXPF(SkXfermode::kDstIn_Mode);
+ static GrPorterDuffXPFactory gSrcOutPDXPF(SkXfermode::kSrcOut_Mode);
+ static GrPorterDuffXPFactory gDstOutPDXPF(SkXfermode::kDstOut_Mode);
+ static GrPorterDuffXPFactory gSrcATopPDXPF(SkXfermode::kSrcATop_Mode);
+ static GrPorterDuffXPFactory gDstATopPDXPF(SkXfermode::kDstATop_Mode);
+ static GrPorterDuffXPFactory gXorPDXPF(SkXfermode::kXor_Mode);
+ static GrPorterDuffXPFactory gPlusPDXPF(SkXfermode::kPlus_Mode);
+ static GrPorterDuffXPFactory gModulatePDXPF(SkXfermode::kModulate_Mode);
+ static GrPorterDuffXPFactory gScreenPDXPF(SkXfermode::kScreen_Mode);
+
+ static GrPorterDuffXPFactory* gFactories[] = {
+ &gClearPDXPF, &gSrcPDXPF, &gDstPDXPF, &gSrcOverPDXPF, &gDstOverPDXPF, &gSrcInPDXPF,
+ &gDstInPDXPF, &gSrcOutPDXPF, &gDstOutPDXPF, &gSrcATopPDXPF, &gDstATopPDXPF, &gXorPDXPF,
+ &gPlusPDXPF, &gModulatePDXPF, &gScreenPDXPF
+ };
+ GR_STATIC_ASSERT(SK_ARRAY_COUNT(gFactories) == SkXfermode::kLastCoeffMode + 1);
+
+ if (xfermode < 0 || xfermode > SkXfermode::kLastCoeffMode) {
+ return NULL;
}
+ return SkRef(gFactories[xfermode]);
}
GrXferProcessor*
@@ -678,16 +748,22 @@ GrPorterDuffXPFactory::onCreateXferProcessor(const GrCaps& caps,
const GrProcOptInfo& covPOI,
const DstTexture* dstTexture) const {
if (covPOI.isFourChannelOutput()) {
- return PDLCDXferProcessor::Create(fSrcCoeff, fDstCoeff, colorPOI);
- } else {
- return PorterDuffXferProcessor::Create(fSrcCoeff, fDstCoeff, 0, dstTexture,
- this->willReadDstColor(caps, colorPOI, covPOI));
+ SkASSERT(!dstTexture || !dstTexture->texture());
+ return PDLCDXferProcessor::Create(fXfermode, colorPOI);
+ }
+
+ BlendFormula blendFormula = get_blend_formula(fXfermode, colorPOI, covPOI);
+ if (blendFormula.hasSecondaryOutput() && !caps.shaderCaps()->dualSourceBlendingSupport()) {
+ return ShaderPDXferProcessor::Create(fXfermode, dstTexture);
}
+
+ SkASSERT(!dstTexture || !dstTexture->texture());
+ return PorterDuffXferProcessor::Create(blendFormula);
}
bool GrPorterDuffXPFactory::supportsRGBCoverage(GrColor /*knownColor*/,
uint32_t knownColorFlags) const {
- if (kOne_GrBlendCoeff == fSrcCoeff && kISA_GrBlendCoeff == fDstCoeff &&
+ if (SkXfermode::kSrcOver_Mode == fXfermode &&
kRGBA_GrColorComponentFlags == knownColorFlags) {
return true;
}
@@ -697,103 +773,50 @@ bool GrPorterDuffXPFactory::supportsRGBCoverage(GrColor /*knownColor*/,
void GrPorterDuffXPFactory::getInvariantOutput(const GrProcOptInfo& colorPOI,
const GrProcOptInfo& coveragePOI,
GrXPFactory::InvariantOutput* output) const {
- if (!coveragePOI.isSolidWhite()) {
- output->fWillBlendWithDst = true;
- output->fBlendedColorFlags = 0;
- return;
- }
+ output->fWillBlendWithDst = true;
+ output->fBlendedColorFlags = kNone_GrColorComponentFlags;
- GrBlendCoeff srcCoeff = fSrcCoeff;
- GrBlendCoeff dstCoeff = fDstCoeff;
-
- // TODO: figure out to merge this simplify with other current optimization code paths and
- // eventually remove from GrBlend
- GrSimplifyBlend(&srcCoeff, &dstCoeff, colorPOI.color(), colorPOI.validFlags(),
- 0, 0, 0);
-
- if (GrBlendCoeffRefsDst(srcCoeff)) {
- output->fWillBlendWithDst = true;
- output->fBlendedColorFlags = 0;
+ // The blend table doesn't support LCD coverage, but these formulas never have invariant output.
+ if (coveragePOI.isFourChannelOutput()) {
return;
}
- if (kZero_GrBlendCoeff != dstCoeff) {
- bool srcAIsOne = colorPOI.isOpaque();
- if (kISA_GrBlendCoeff != dstCoeff || !srcAIsOne) {
- output->fWillBlendWithDst = true;
- }
- output->fBlendedColorFlags = 0;
+ const BlendFormula& blendFormula = get_blend_formula(fXfermode, colorPOI, coveragePOI);
+ if (blendFormula.usesDstColor()) {
return;
}
- switch (srcCoeff) {
+ SkASSERT(coveragePOI.isSolidWhite());
+ SkASSERT(kAdd_GrBlendEquation == blendFormula.fBlendEquation);
+
+ output->fWillBlendWithDst = false;
+
+ switch (blendFormula.fSrcCoeff) {
case kZero_GrBlendCoeff:
output->fBlendedColor = 0;
output->fBlendedColorFlags = kRGBA_GrColorComponentFlags;
- break;
+ return;
case kOne_GrBlendCoeff:
output->fBlendedColor = colorPOI.color();
output->fBlendedColorFlags = colorPOI.validFlags();
- break;
-
- // The src coeff should never refer to the src and if it refers to dst then opaque
- // should have been false.
- case kSC_GrBlendCoeff:
- case kISC_GrBlendCoeff:
- case kDC_GrBlendCoeff:
- case kIDC_GrBlendCoeff:
- case kSA_GrBlendCoeff:
- case kISA_GrBlendCoeff:
- case kDA_GrBlendCoeff:
- case kIDA_GrBlendCoeff:
- default:
- SkFAIL("srcCoeff should not refer to src or dst.");
- break;
+ return;
- // TODO: update this once GrPaint actually has a const color.
- case kConstC_GrBlendCoeff:
- case kIConstC_GrBlendCoeff:
- case kConstA_GrBlendCoeff:
- case kIConstA_GrBlendCoeff:
- output->fBlendedColorFlags = 0;
- break;
+ default: return;
}
-
- output->fWillBlendWithDst = false;
}
bool GrPorterDuffXPFactory::willReadDstColor(const GrCaps& caps,
const GrProcOptInfo& colorPOI,
const GrProcOptInfo& coveragePOI) const {
- // We can always blend correctly if we have dual source blending.
- if (caps.shaderCaps()->dualSourceBlendingSupport()) {
- return false;
+ if (coveragePOI.isFourChannelOutput()) {
+ return false; // The LCD XP never does a dst read.
}
- if (can_tweak_alpha_for_coverage(fDstCoeff)) {
- return false;
- }
-
- bool srcAIsOne = colorPOI.isOpaque();
-
- if (kZero_GrBlendCoeff == fDstCoeff) {
- if (kZero_GrBlendCoeff == fSrcCoeff || srcAIsOne) {
- return false;
- }
- }
-
- // Reduces to: coeffS * (Cov*S) + D
- if (kSA_GrBlendCoeff == fDstCoeff && srcAIsOne) {
- return false;
- }
-
- // We can always blend correctly if we have solid coverage.
- if (coveragePOI.isSolidWhite()) {
- return false;
- }
-
- return true;
+ // We fallback on the shader XP when the blend formula would use dual source blending but we
+ // don't have support for it.
+ return !caps.shaderCaps()->dualSourceBlendingSupport() &&
+ get_blend_formula(fXfermode, colorPOI, coveragePOI).hasSecondaryOutput();
}
GR_DEFINE_XP_FACTORY_TEST(GrPorterDuffXPFactory);
@@ -806,3 +829,15 @@ GrXPFactory* GrPorterDuffXPFactory::TestCreate(SkRandom* random,
return GrPorterDuffXPFactory::Create(mode);
}
+void GrPorterDuffXPFactory::TestGetXPOutputTypes(const GrXferProcessor* xp,
+ int* outPrimary,
+ int* outSecondary) {
+ if (!!strcmp(xp->name(), "Porter Duff")) {
+ *outPrimary = *outSecondary = -1;
+ return;
+ }
+ BlendFormula blendFormula = static_cast<const PorterDuffXferProcessor*>(xp)->getBlendFormula();
+ *outPrimary = blendFormula.fPrimaryOutputType;
+ *outSecondary = blendFormula.fSecondaryOutputType;
+}
+
diff --git a/tests/GrPorterDuffTest.cpp b/tests/GrPorterDuffTest.cpp
new file mode 100644
index 0000000000..314671200f
--- /dev/null
+++ b/tests/GrPorterDuffTest.cpp
@@ -0,0 +1,1011 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkXfermode.h"
+#include "Test.h"
+
+#if SK_SUPPORT_GPU
+
+#include "GrBatch.h"
+#include "GrContextFactory.h"
+#include "GrContextOptions.h"
+#include "GrGpu.h"
+#include "GrResourceProvider.h"
+#include "GrXferProcessor.h"
+#include "effects/GrPorterDuffXferProcessor.h"
+#include "gl/GrGLCaps.h"
+
+////////////////////////////////////////////////////////////////////////////////
+
+static void test_color_unknown_with_coverage(skiatest::Reporter* reporter, const GrCaps& caps);
+static void test_color_unknown_no_coverage(skiatest::Reporter* reporter, const GrCaps& caps);
+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_no_dual_source_blending(skiatest::Reporter* reporter);
+
+DEF_GPUTEST(GrPorterDuff, reporter, factory) {
+ GrContext* ctx = factory->get(GrContextFactory::kNull_GLContextType);
+ if (!ctx) {
+ SkFAIL("Failed to create null context.");
+ return;
+ }
+
+ const GrCaps& caps = *ctx->getGpu()->caps();
+ if (!caps.shaderCaps()->dualSourceBlendingSupport()) {
+ SkFAIL("Null context does not support dual source blending.");
+ return;
+ }
+
+ test_color_unknown_with_coverage(reporter, caps);
+ test_color_unknown_no_coverage(reporter, caps);
+ test_color_opaque_with_coverage(reporter, caps);
+ test_color_opaque_no_coverage(reporter, caps);
+ test_lcd_coverage(reporter, caps);
+ test_no_dual_source_blending(reporter);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+#define TEST_ASSERT(...) REPORTER_ASSERT(reporter, __VA_ARGS__)
+
+enum {
+ kNone_OutputType,
+ kCoverage_OutputType,
+ kModulate_OutputType,
+ kISAModulate_OutputType,
+ kISCModulate_OutputType
+};
+
+enum {
+ kNone_Opt = GrXferProcessor::kNone_Opt,
+ kSkipDraw_OptFlag = GrXferProcessor::kSkipDraw_OptFlag,
+ kIgnoreColor_OptFlag = GrXferProcessor::kIgnoreColor_OptFlag,
+ kIgnoreCoverage_OptFlag = GrXferProcessor::kIgnoreCoverage_OptFlag,
+ kCanTweakAlphaForCoverage_OptFlag = GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag
+};
+
+class GrPorterDuffTest {
+public:
+ struct XPInfo {
+ XPInfo(skiatest::Reporter* reporter, SkXfermode::Mode xfermode, const GrCaps& caps,
+ const GrProcOptInfo& colorPOI, const GrProcOptInfo& covPOI) {
+ SkAutoTUnref<GrXPFactory> xpf(GrPorterDuffXPFactory::Create(xfermode));
+ SkAutoTUnref<GrXferProcessor> xp(xpf->createXferProcessor(colorPOI, covPOI, 0, caps));
+ TEST_ASSERT(!xpf->willNeedDstTexture(caps, colorPOI, covPOI));
+ xpf->getInvariantOutput(colorPOI, covPOI, &fInvariantOutput);
+ fOptFlags = xp->getOptimizations(colorPOI, covPOI, false, 0, caps);
+ GetXPOutputTypes(xp, &fPrimaryOutputType, &fSecondaryOutputType);
+ xp->getBlendInfo(&fBlendInfo);
+ TEST_ASSERT(!xp->willReadDstColor());
+ TEST_ASSERT(xp->hasSecondaryOutput() == GrBlendCoeffRefsSrc2(fBlendInfo.fDstBlend));
+ }
+
+ GrXPFactory::InvariantOutput fInvariantOutput;
+ int fOptFlags;
+ int fPrimaryOutputType;
+ int fSecondaryOutputType;
+ GrXferProcessor::BlendInfo fBlendInfo;
+ };
+
+ static void GetXPOutputTypes(const GrXferProcessor* xp, int* outPrimary, int* outSecondary) {
+ GrPorterDuffXPFactory::TestGetXPOutputTypes(xp, outPrimary, outSecondary);
+ }
+};
+
+static void test_color_unknown_with_coverage(skiatest::Reporter* reporter, const GrCaps& caps) {
+ GrProcOptInfo colorPOI, covPOI;
+ colorPOI.calcWithInitialValues(NULL, 0, 0, kNone_GrColorComponentFlags, false);
+ covPOI.calcWithInitialValues(NULL, 0, 0, kNone_GrColorComponentFlags, 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.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ 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.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kNone_Opt) == 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(kIS2A_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+ TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
+ break;
+ case SkXfermode::kDst_Mode:
+ TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ 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.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kCanTweakAlphaForCoverage_OptFlag) == 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(kISA_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+ TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
+ break;
+ case SkXfermode::kDstOver_Mode:
+ TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kCanTweakAlphaForCoverage_OptFlag) == 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.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kNone_Opt) == 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(kIS2A_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+ TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
+ break;
+ case SkXfermode::kDstIn_Mode:
+ TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kNone_Opt) == 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.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kNone_Opt) == 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(kIS2A_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+ TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
+ break;
+ case SkXfermode::kDstOut_Mode:
+ TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
+ TEST_ASSERT(kModulate_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(kISA_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+ TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
+ break;
+ case SkXfermode::kSrcATop_Mode:
+ TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
+ TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
+ TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
+ TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
+ TEST_ASSERT(kDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
+ TEST_ASSERT(kISA_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+ TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
+ break;
+ case SkXfermode::kDstATop_Mode:
+ TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kNone_Opt) == 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.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kCanTweakAlphaForCoverage_OptFlag) == 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(kISA_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+ TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
+ break;
+ case SkXfermode::kPlus_Mode:
+ TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kCanTweakAlphaForCoverage_OptFlag) == 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.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kNone_Opt) == 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.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kCanTweakAlphaForCoverage_OptFlag) == 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_no_coverage(skiatest::Reporter* reporter, const GrCaps& caps) {
+ GrProcOptInfo colorPOI, covPOI;
+ colorPOI.calcWithInitialValues(NULL, 0, GrColorPackRGBA(229, 0, 154, 0),
+ kR_GrColorComponentFlag | kB_GrColorComponentFlag, false);
+ covPOI.calcWithInitialValues(NULL, 0, GrColorPackA4(255), kRGBA_GrColorComponentFlags, 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.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(0 == xpi.fInvariantOutput.fBlendedColor);
+ TEST_ASSERT(kRGBA_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kIgnoreColor_OptFlag |
+ kIgnoreCoverage_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(kZero_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+ TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
+ break;
+ case SkXfermode::kSrc_Mode:
+ TEST_ASSERT(!xpi.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(229 == GrColorUnpackR(xpi.fInvariantOutput.fBlendedColor));
+ TEST_ASSERT(154 == GrColorUnpackB(xpi.fInvariantOutput.fBlendedColor));
+ TEST_ASSERT((kR_GrColorComponentFlag |
+ kB_GrColorComponentFlag) == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kIgnoreCoverage_OptFlag) == 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(kZero_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+ TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
+ break;
+ case SkXfermode::kDst_Mode:
+ TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ 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.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kIgnoreCoverage_OptFlag |
+ kCanTweakAlphaForCoverage_OptFlag) == 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(kISA_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+ TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
+ break;
+ case SkXfermode::kDstOver_Mode:
+ TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kIgnoreCoverage_OptFlag |
+ kCanTweakAlphaForCoverage_OptFlag) == 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.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kIgnoreCoverage_OptFlag) == xpi.fOptFlags);
+ TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
+ TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
+ TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
+ TEST_ASSERT(kDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
+ TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+ TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
+ break;
+ case SkXfermode::kDstIn_Mode:
+ TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kIgnoreCoverage_OptFlag) == xpi.fOptFlags);
+ TEST_ASSERT(kModulate_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(kSA_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+ TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
+ break;
+ case SkXfermode::kSrcOut_Mode:
+ TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kIgnoreCoverage_OptFlag) == 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(kZero_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+ TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
+ break;
+ case SkXfermode::kDstOut_Mode:
+ TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kIgnoreCoverage_OptFlag |
+ kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
+ TEST_ASSERT(kModulate_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(kISA_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+ TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
+ break;
+ case SkXfermode::kSrcATop_Mode:
+ TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kIgnoreCoverage_OptFlag |
+ kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
+ TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
+ TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
+ TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
+ TEST_ASSERT(kDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
+ TEST_ASSERT(kISA_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+ TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
+ break;
+ case SkXfermode::kDstATop_Mode:
+ TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kIgnoreCoverage_OptFlag) == 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(kSA_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+ TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
+ break;
+ case SkXfermode::kXor_Mode:
+ TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kIgnoreCoverage_OptFlag |
+ kCanTweakAlphaForCoverage_OptFlag) == 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(kISA_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+ TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
+ break;
+ case SkXfermode::kPlus_Mode:
+ TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kIgnoreCoverage_OptFlag |
+ kCanTweakAlphaForCoverage_OptFlag) == 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.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kIgnoreCoverage_OptFlag) == xpi.fOptFlags);
+ TEST_ASSERT(kModulate_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(kSC_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+ TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
+ break;
+ case SkXfermode::kScreen_Mode:
+ TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kIgnoreCoverage_OptFlag |
+ kCanTweakAlphaForCoverage_OptFlag) == 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_opaque_with_coverage(skiatest::Reporter* reporter, const GrCaps& caps) {
+ GrProcOptInfo colorPOI, covPOI;
+ colorPOI.calcWithInitialValues(NULL, 0, GrColorPackA4(255), kA_GrColorComponentFlag, false);
+ covPOI.calcWithInitialValues(NULL, 0, 0, kNone_GrColorComponentFlags, 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.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ 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.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kCanTweakAlphaForCoverage_OptFlag) == 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(kISA_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+ TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
+ break;
+ case SkXfermode::kDst_Mode:
+ TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ 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.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kCanTweakAlphaForCoverage_OptFlag) == 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(kISA_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+ TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
+ break;
+ case SkXfermode::kDstOver_Mode:
+ TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kCanTweakAlphaForCoverage_OptFlag) == 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.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
+ TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
+ TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
+ TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
+ TEST_ASSERT(kDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
+ TEST_ASSERT(kISA_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+ TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
+ break;
+ case SkXfermode::kDstIn_Mode:
+ TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ 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::kSrcOut_Mode:
+ TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kCanTweakAlphaForCoverage_OptFlag) == 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(kISA_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+ TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
+ break;
+ case SkXfermode::kDstOut_Mode:
+ TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ 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::kSrcATop_Mode:
+ TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kCanTweakAlphaForCoverage_OptFlag) == xpi.fOptFlags);
+ TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
+ TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
+ TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
+ TEST_ASSERT(kDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
+ TEST_ASSERT(kISA_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+ TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
+ break;
+ case SkXfermode::kDstATop_Mode:
+ TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kCanTweakAlphaForCoverage_OptFlag) == 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::kXor_Mode:
+ TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kCanTweakAlphaForCoverage_OptFlag) == 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(kISA_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+ TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
+ break;
+ case SkXfermode::kPlus_Mode:
+ TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kCanTweakAlphaForCoverage_OptFlag) == 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.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kNone_Opt) == 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.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kCanTweakAlphaForCoverage_OptFlag) == 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_opaque_no_coverage(skiatest::Reporter* reporter, const GrCaps& caps) {
+ GrProcOptInfo colorPOI, covPOI;
+ colorPOI.calcWithInitialValues(NULL, 0, GrColorPackRGBA(0, 82, 0, 255),
+ kG_GrColorComponentFlag | kA_GrColorComponentFlag, false);
+ covPOI.calcWithInitialValues(NULL, 0, GrColorPackA4(255), kRGBA_GrColorComponentFlags, 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.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(0 == xpi.fInvariantOutput.fBlendedColor);
+ TEST_ASSERT(kRGBA_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kIgnoreColor_OptFlag |
+ kIgnoreCoverage_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(kZero_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+ TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
+ break;
+ case SkXfermode::kSrc_Mode:
+ TEST_ASSERT(!xpi.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(82 == GrColorUnpackG(xpi.fInvariantOutput.fBlendedColor));
+ TEST_ASSERT(255 == GrColorUnpackA(xpi.fInvariantOutput.fBlendedColor));
+ TEST_ASSERT((kG_GrColorComponentFlag |
+ kA_GrColorComponentFlag) == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kIgnoreCoverage_OptFlag) == 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(kZero_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+ TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
+ break;
+ case SkXfermode::kDst_Mode:
+ TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ 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.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(82 == GrColorUnpackG(xpi.fInvariantOutput.fBlendedColor));
+ TEST_ASSERT(255 == GrColorUnpackA(xpi.fInvariantOutput.fBlendedColor));
+ TEST_ASSERT((kG_GrColorComponentFlag |
+ kA_GrColorComponentFlag) == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kIgnoreCoverage_OptFlag) == 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(kZero_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+ TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
+ break;
+ case SkXfermode::kDstOver_Mode:
+ TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kIgnoreCoverage_OptFlag |
+ kCanTweakAlphaForCoverage_OptFlag) == 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.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kIgnoreCoverage_OptFlag) == xpi.fOptFlags);
+ TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
+ TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
+ TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
+ TEST_ASSERT(kDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
+ TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+ TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
+ break;
+ case SkXfermode::kDstIn_Mode:
+ TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ 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::kSrcOut_Mode:
+ TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kIgnoreCoverage_OptFlag) == 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(kZero_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+ TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
+ break;
+ case SkXfermode::kDstOut_Mode:
+ TEST_ASSERT(!xpi.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(0 == xpi.fInvariantOutput.fBlendedColor);
+ TEST_ASSERT(kRGBA_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kIgnoreColor_OptFlag |
+ kIgnoreCoverage_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(kZero_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+ TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
+ break;
+ case SkXfermode::kSrcATop_Mode:
+ TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kIgnoreCoverage_OptFlag) == xpi.fOptFlags);
+ TEST_ASSERT(kModulate_OutputType == xpi.fPrimaryOutputType);
+ TEST_ASSERT(kNone_OutputType == xpi.fSecondaryOutputType);
+ TEST_ASSERT(kAdd_GrBlendEquation == xpi.fBlendInfo.fEquation);
+ TEST_ASSERT(kDA_GrBlendCoeff == xpi.fBlendInfo.fSrcBlend);
+ TEST_ASSERT(kZero_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+ TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
+ break;
+ case SkXfermode::kDstATop_Mode:
+ TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kIgnoreCoverage_OptFlag |
+ kCanTweakAlphaForCoverage_OptFlag) == 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::kXor_Mode:
+ TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kIgnoreCoverage_OptFlag) == 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(kZero_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+ TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
+ break;
+ case SkXfermode::kPlus_Mode:
+ TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kIgnoreCoverage_OptFlag |
+ kCanTweakAlphaForCoverage_OptFlag) == 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.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kIgnoreCoverage_OptFlag) == xpi.fOptFlags);
+ TEST_ASSERT(kModulate_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(kSC_GrBlendCoeff == xpi.fBlendInfo.fDstBlend);
+ TEST_ASSERT(xpi.fBlendInfo.fWriteColor);
+ break;
+ case SkXfermode::kScreen_Mode:
+ TEST_ASSERT(xpi.fInvariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == xpi.fInvariantOutput.fBlendedColorFlags);
+ TEST_ASSERT((kIgnoreCoverage_OptFlag |
+ kCanTweakAlphaForCoverage_OptFlag) == 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_lcd_coverage(skiatest::Reporter* reporter, const GrCaps& caps) {
+ class : public GrBatch {
+ void getInvariantOutputColor(GrInitInvariantOutput* out) const override {
+ out->setKnownFourComponents(GrColorPackRGBA(123, 45, 67, 221));
+ }
+
+ void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override {
+ out->setUnknownFourComponents();
+ out->setUsingLCDCoverage();
+ }
+
+ const char* name() const override { return "Test LCD Text Batch"; }
+ void initBatchTracker(const GrPipelineInfo&) override {}
+ bool onCombineIfPossible(GrBatch*) override { return false; }
+ void generateGeometry(GrBatchTarget*, const GrPipeline*) override {}
+
+ } testLCDCoverageBatch;
+
+ GrProcOptInfo colorPOI, covPOI;
+ colorPOI.calcColorWithBatch(&testLCDCoverageBatch, NULL, 0);
+ covPOI.calcCoverageWithBatch(&testLCDCoverageBatch, NULL, 0);
+
+ SkASSERT(kRGBA_GrColorComponentFlags == colorPOI.validFlags());
+ SkASSERT(covPOI.isFourChannelOutput());
+
+ SkAutoTUnref<GrXPFactory> xpf(GrPorterDuffXPFactory::Create(SkXfermode::kSrcOver_Mode));
+ TEST_ASSERT(!xpf->willNeedDstTexture(caps, colorPOI, covPOI));
+
+ SkAutoTUnref<GrXferProcessor> xp(xpf->createXferProcessor(colorPOI, covPOI, 0, caps));
+ if (!xp) {
+ ERRORF(reporter, "Failed to create an XP with LCD coverage.");
+ return;
+ }
+
+ GrXPFactory::InvariantOutput invariantOutput;
+ xpf->getInvariantOutput(colorPOI, covPOI, &invariantOutput);
+ TEST_ASSERT(invariantOutput.fWillBlendWithDst);
+ TEST_ASSERT(kNone_GrColorComponentFlags == invariantOutput.fBlendedColorFlags);
+
+ GrColor overrideColor;
+ xp->getOptimizations(colorPOI, covPOI, false, &overrideColor, caps);
+
+ GrXferProcessor::BlendInfo blendInfo;
+ xp->getBlendInfo(&blendInfo);
+ TEST_ASSERT(blendInfo.fWriteColor);
+}
+
+static void test_no_dual_source_blending(skiatest::Reporter* reporter) {
+ GrContextOptions opts;
+ opts.fSuppressDualSourceBlending = true;
+ GrContextFactory factory(opts);
+ factory.get(GrContextFactory::kNull_GLContextType);
+ GrContext* ctx = factory.get(GrContextFactory::kNull_GLContextType);
+ if (!ctx) {
+ SkFAIL("Failed to create null context without ARB_blend_func_extended.");
+ return;
+ }
+
+ const GrCaps& caps = *ctx->getGpu()->caps();
+ if (caps.shaderCaps()->dualSourceBlendingSupport()) {
+ SkFAIL("Null context failed to honor request for no ARB_blend_func_extended.");
+ return;
+ }
+
+ GrBackendTextureDesc fakeDesc;
+ fakeDesc.fConfig = kRGBA_8888_GrPixelConfig;
+ fakeDesc.fWidth = fakeDesc.fHeight = 100;
+ fakeDesc.fTextureHandle = 1;
+ SkAutoTUnref<GrTexture> fakeTexture(ctx->resourceProvider()->wrapBackendTexture(fakeDesc));
+ GrXferProcessor::DstTexture fakeDstTexture;
+ fakeDstTexture.setTexture(fakeTexture);
+
+ static const GrColor testColors[] = {
+ 0,
+ GrColorPackRGBA(0, 82, 0, 255),
+ GrColorPackA4(255)
+ };
+ static const GrColorComponentFlags testColorFlags[] = {
+ kNone_GrColorComponentFlags,
+ kG_GrColorComponentFlag | kA_GrColorComponentFlag,
+ kRGBA_GrColorComponentFlags
+ };
+ GR_STATIC_ASSERT(SK_ARRAY_COUNT(testColors) == SK_ARRAY_COUNT(testColorFlags));
+
+ for (size_t c = 0; c < SK_ARRAY_COUNT(testColors); c++) {
+ GrProcOptInfo colorPOI;
+ colorPOI.calcWithInitialValues(NULL, 0, testColors[c], testColorFlags[c], false);
+ for (int f = 0; f <= 1; f++) {
+ GrProcOptInfo covPOI;
+ if (!f) {
+ covPOI.calcWithInitialValues(NULL, 0, 0, kNone_GrColorComponentFlags, true);
+ } else {
+ covPOI.calcWithInitialValues(NULL, 0, GrColorPackA4(255),
+ kRGBA_GrColorComponentFlags, true);
+ }
+ for (int m = 0; m <= SkXfermode::kLastCoeffMode; m++) {
+ SkXfermode::Mode xfermode = static_cast<SkXfermode::Mode>(m);
+ SkAutoTUnref<GrXPFactory> xpf(GrPorterDuffXPFactory::Create(xfermode));
+ SkAutoTUnref<GrXferProcessor> xp;
+ if (xpf->willNeedDstTexture(caps, colorPOI, covPOI)) {
+ xp.reset(xpf->createXferProcessor(colorPOI, covPOI, &fakeDstTexture, caps));
+ } else {
+ xp.reset(xpf->createXferProcessor(colorPOI, covPOI, NULL, caps));
+ }
+ if (!xp) {
+ ERRORF(reporter, "Failed to create an XP without dual source blending.");
+ return;
+ }
+ TEST_ASSERT(!xp->hasSecondaryOutput());
+ xp->getOptimizations(colorPOI, covPOI, false, 0, caps);
+ TEST_ASSERT(!xp->hasSecondaryOutput());
+ }
+ }
+ }
+}
+
+#endif
+