Implement Porter Duff XP with a blend table

Removes the runtime logic used by PorterDuffXferProcessor to decide
blend coeffs and shader outputs, and instead uses a compile-time
constant table of pre-selected blend formulas. Separates out the dst
read fallback into its own XP.

Introduces a new blend strategy for srcCoeff=0 that can apply coverage
with a reverse subtract blend equation instead of dual source
blending.

Adds new macros in GrBlend.h to analyze blend formulas both runtime.

Removes kSetCoverageDrawing_OptFlag and GrSimplifyBlend as they are no
longer used.

Adds a GM that verifies all xfermodes, including arithmetic, with the
color/coverage invariants used by Porter Duff.

Adds a unit test that verifies each Porter Duff formula with every
color/coverage invariant.

Major changes:

 * Uses a reverse subtract blend equation for coverage when srcCoeff=0
   (clear, dst-out [Sa=1], dst-in, modulate). Platforms that don't
   support dual source blending no longer require a dst copy for
   dst-in and modulate.

 * Sets BlendInfo::fWriteColor to false when the blend does not modify
   the dst. GrGLGpu will now use glColorMask instead of blending for
   these modes (dst, dst-in [Sa=1], modulate ignored for [Sc=1]).

 * Converts all SA blend coeffs to One for opaque inputs, and ISA to
   Zero if there is also no coverage. (We keep ISA around when there
   is coverage because we use it to tweak alpha for coverage.)

 * Abandons solid white optimizations for the sake of simplicity
   (screen was the only mode that previous had solid white opts).

Minor differences:

 * Inconsequential differences in opt flags (e.g. we now return
   kCanTweakAlphaForCoverage_OptFlag even when there is no coverage).

 * Src coeffs when the shader outputs 0.

 * IS2C vs IS2A when the secondary output is scalar.

BUG=skia:

Committed: https://skia.googlesource.com/skia/+/9a70920db22b6309c671f8e5d519bb95570e4414

Review URL: https://codereview.chromium.org/1124373002
This commit is contained in:
cdalton 2015-05-27 15:08:33 -07:00 committed by Commit bot
parent 3098a752ef
commit 6fd158ea47
11 changed files with 1930 additions and 695 deletions

236
gm/aaxfermodes.cpp Normal file
View File

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

View File

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

View File

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

View File

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

View File

@ -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.
*/
@ -183,10 +179,6 @@ public:
* Clear color stages and override input color to that returned by getOptimizations
*/
kOverrideColor_OptFlag = 0x8,
/**
* Set CoverageDrawing_StateBit
*/
kSetCoverageDrawing_OptFlag = 0x10,
/**
* Can tweak alpha for coverage. Currently this flag should only be used by a batch
*/

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

1011
tests/GrPorterDuffTest.cpp Normal file

File diff suppressed because it is too large Load Diff