Create fragment processor for performing input color blend with child processor

The new FP is used to implement SkXM::Mode color filters and SkXM::Mode image filters. Also, these now support all advanced SkXM::Mode xfermodes.

Review URL: https://codereview.chromium.org/1334293003
This commit is contained in:
bsalomon 2015-09-15 15:33:27 -07:00 committed by Commit bot
parent cd7f035974
commit ae4738f677
40 changed files with 1126 additions and 1095 deletions

View File

@ -72,6 +72,7 @@
'<(skia_src_path)/gpu/GrBatchFlushState.h',
'<(skia_src_path)/gpu/GrBatchTest.cpp',
'<(skia_src_path)/gpu/GrBatchTest.h',
'<(skia_src_path)/gpu/GrBlend.cpp',
'<(skia_src_path)/gpu/GrBlurUtils.cpp',
'<(skia_src_path)/gpu/GrBlurUtils.h',
'<(skia_src_path)/gpu/GrBufferAllocPool.cpp',
@ -138,6 +139,7 @@
'<(skia_src_path)/gpu/GrProcessor.cpp',
'<(skia_src_path)/gpu/GrProcessorUnitTest.cpp',
'<(skia_src_path)/gpu/GrProcessorDataManager.cpp',
'<(skia_src_path)/gpu/GrProcessorUnitTest.cpp',
'<(skia_src_path)/gpu/GrProcOptInfo.cpp',
'<(skia_src_path)/gpu/GrProcOptInfo.h',
'<(skia_src_path)/gpu/GrGpuResourceRef.cpp',
@ -245,7 +247,6 @@
'<(skia_src_path)/gpu/effects/GrExtractAlphaFragmentProcessor.cpp',
'<(skia_src_path)/gpu/effects/GrCoverageSetOpXP.cpp',
'<(skia_src_path)/gpu/effects/GrCustomXfermode.cpp',
'<(skia_src_path)/gpu/effects/GrCustomXfermodePriv.h',
'<(skia_src_path)/gpu/effects/GrBezierEffect.cpp',
'<(skia_src_path)/gpu/effects/GrBezierEffect.h',
'<(skia_src_path)/gpu/effects/GrConvolutionEffect.cpp',
@ -285,8 +286,8 @@
'<(skia_src_path)/gpu/gl/GrGLAssembleInterface.cpp',
'<(skia_src_path)/gpu/gl/GrGLAssembleInterface.h',
'<(skia_src_path)/gpu/gl/GrGLBlend.cpp',
'<(skia_src_path)/gpu/gl/GrGLBlend.h',
'<(skia_src_path)/gpu/gl/GrGLSLBlend.cpp',
'<(skia_src_path)/gpu/gl/GrGLSLBlend.h',
'<(skia_src_path)/gpu/gl/GrGLBufferImpl.cpp',
'<(skia_src_path)/gpu/gl/GrGLBufferImpl.h',
'<(skia_src_path)/gpu/gl/GrGLCaps.cpp',

View File

@ -136,7 +136,7 @@ public:
* If the subclass returns false, then it should not modify the array at all.
*/
virtual bool asFragmentProcessors(GrContext*, GrProcessorDataManager*,
SkTDArray<GrFragmentProcessor*>*) const {
SkTDArray<const GrFragmentProcessor*>*) const {
return false;
}

View File

@ -194,15 +194,15 @@ public:
*/
static bool IsOpaque(const SkXfermode* xfer, SrcColorOpacity opacityType);
/** Implemented by a subclass to support use as an image filter in the GPU backend. When used as
an image filter the xfer mode blends the source color against a background texture rather
than the destination. It is implemented as a fragment processor. This can be called with
both params set to NULL to query whether it would succeed. Otherwise, both params are
required. Upon success the function returns true and the caller owns a ref to the fragment
parameter. Upon failure false is returned and the processor param is not written to.
/** Used to do in-shader blending between two colors computed in the shader via a
GrFragmentProcessor. The input to the returned FP is the src color. The dst color is
provided by the dst param which becomes a child FP of the returned FP. If the params are
null then this is just a query of whether the SkXfermode could support this functionality.
It is legal for the function to succeed but return a null output. This indicates that
the output of the blend is simply the src color.
*/
virtual bool asFragmentProcessor(GrFragmentProcessor**, GrProcessorDataManager*,
GrTexture* background) const;
virtual bool asFragmentProcessor(const GrFragmentProcessor** output, GrProcessorDataManager*,
const GrFragmentProcessor* dst) const;
/** A subclass may implement this factory function to work with the GPU backend. It is legal
to call this with xpf NULL to simply test the return value. If xpf is non-NULL then the
@ -226,7 +226,7 @@ protected:
SkXfermode() {}
/** The default implementation of xfer32/xfer16/xferA8 in turn call this
method, 1 color at a time (upscaled to a SkPMColor). The default
implmentation of this method just returns dst. If performance is
implementation of this method just returns dst. If performance is
important, your subclass should override xfer32/xfer16/xferA8 directly.
This method will not be called directly by the client, so it need not

View File

@ -26,7 +26,7 @@ public:
#if SK_SUPPORT_GPU
bool asFragmentProcessors(GrContext*, GrProcessorDataManager*,
SkTDArray<GrFragmentProcessor*>*) const override;
SkTDArray<const GrFragmentProcessor*>*) const override;
#endif
SK_TO_STRING_OVERRIDE()

View File

@ -27,7 +27,7 @@ public:
#if SK_SUPPORT_GPU
bool asFragmentProcessors(GrContext*, GrProcessorDataManager*,
SkTDArray<GrFragmentProcessor*>*) const override;
SkTDArray<const GrFragmentProcessor*>*) const override;
#endif
struct State {

View File

@ -29,7 +29,7 @@ public:
#if SK_SUPPORT_GPU
bool asFragmentProcessors(GrContext*, GrProcessorDataManager*,
SkTDArray<GrFragmentProcessor*>*) const override;
SkTDArray<const GrFragmentProcessor*>*) const override;
#endif
SK_TO_STRING_OVERRIDE()

View File

@ -40,7 +40,7 @@ public:
#if SK_SUPPORT_GPU
bool asFragmentProcessors(GrContext*, GrProcessorDataManager*,
SkTDArray<GrFragmentProcessor*>*) const override;
SkTDArray<const GrFragmentProcessor*>*) const override;
#endif
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkModeColorFilter)

View File

@ -6,12 +6,12 @@
* found in the LICENSE file.
*/
#include "GrTypes.h"
#include "../private/SkTLogic.h"
#ifndef GrBlend_DEFINED
#define GrBlend_DEFINED
#include "GrColor.h"
#include "../private/SkTLogic.h"
/**
* Equations for alpha-blending.
*/
@ -46,7 +46,7 @@ static const int kGrBlendEquationCnt = kLast_GrBlendEquation + 1;
/**
* Coeffecients for alpha-blending.
* Coefficients for alpha-blending.
*/
enum GrBlendCoeff {
kZero_GrBlendCoeff, //<! 0
@ -73,6 +73,19 @@ enum GrBlendCoeff {
static const int kGrBlendCoeffCnt = kLast_GrBlendCoeff + 1;
/**
* Given a known blend equation in the form of srcCoeff * srcColor + dstCoeff * dstColor where
* there may be partial knowledge of the srcColor and dstColor component values, determine what
* components of the blended output color are known. Coeffs must not refer to the constant or
* secondary src color.
*/
void GrGetCoeffBlendKnownComponents(GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff,
GrColor srcColor,
GrColorComponentFlags srcColorFlags,
GrColor dstColor,
GrColorComponentFlags dstColorFlags,
GrColor* outColor,
GrColorComponentFlags* outFlags);
template<GrBlendCoeff Coeff>
struct GrTBlendCoeffRefsSrc : skstd::bool_constant<kSC_GrBlendCoeff == Coeff ||
@ -95,7 +108,6 @@ inline bool GrBlendCoeffRefsSrc(GrBlendCoeff coeff) {
}
}
template<GrBlendCoeff Coeff>
struct GrTBlendCoeffRefsDst : skstd::bool_constant<kDC_GrBlendCoeff == Coeff ||
kIDC_GrBlendCoeff == Coeff ||

View File

@ -77,7 +77,7 @@ static inline GrColor GrColorPackA4(unsigned a) {
#define GrColor_ILLEGAL (~(0xFF << GrColor_SHIFT_A))
#define GrColor_WHITE 0xFFFFFFFF
#define GrColor_TRANS_BLACK 0x0
#define GrColor_TRANSPARENT_BLACK 0x0
/**
* Assert in debug builds that a GrColor is premultiplied.
@ -95,6 +95,31 @@ static inline void GrColorIsPMAssert(GrColor SkDEBUGCODE(c)) {
#endif
}
/** Inverts each color channel. */
static inline GrColor GrInvertColor(GrColor c) {
U8CPU a = GrColorUnpackA(c);
U8CPU r = GrColorUnpackR(c);
U8CPU g = GrColorUnpackG(c);
U8CPU b = GrColorUnpackB(c);
return GrColorPackRGBA(0xff - r, 0xff - g, 0xff - b, 0xff - a);
}
static inline GrColor GrColorMul(GrColor c0, GrColor c1) {
U8CPU r = SkMulDiv255Round(GrColorUnpackR(c0), GrColorUnpackR(c1));
U8CPU g = SkMulDiv255Round(GrColorUnpackG(c0), GrColorUnpackG(c1));
U8CPU b = SkMulDiv255Round(GrColorUnpackB(c0), GrColorUnpackB(c1));
U8CPU a = SkMulDiv255Round(GrColorUnpackA(c0), GrColorUnpackA(c1));
return GrColorPackRGBA(r, g, b, a);
}
static inline GrColor GrColorSatAdd(GrColor c0, GrColor c1) {
unsigned r = SkTMin<unsigned>(GrColorUnpackR(c0) + GrColorUnpackR(c1), 0xff);
unsigned g = SkTMin<unsigned>(GrColorUnpackG(c0) + GrColorUnpackG(c1), 0xff);
unsigned b = SkTMin<unsigned>(GrColorUnpackB(c0) + GrColorUnpackB(c1), 0xff);
unsigned a = SkTMin<unsigned>(GrColorUnpackA(c0) + GrColorUnpackA(c1), 0xff);
return GrColorPackRGBA(r, g, b, a);
}
/** Converts a GrColor to an rgba array of GrGLfloat */
static inline void GrColorToRGBAFloat(GrColor color, float rgba[4]) {
static const float ONE_OVER_255 = 1.f / 255.f;
@ -115,8 +140,20 @@ static inline bool GrColorIsOpaque(GrColor color) {
return (color & (0xFFU << GrColor_SHIFT_A)) == (0xFFU << GrColor_SHIFT_A);
}
static inline GrColor GrPremulColor(GrColor color) {
unsigned r = GrColorUnpackR(color);
unsigned g = GrColorUnpackG(color);
unsigned b = GrColorUnpackB(color);
unsigned a = GrColorUnpackA(color);
return GrColorPackRGBA(SkMulDiv255Round(r, a),
SkMulDiv255Round(g, a),
SkMulDiv255Round(b, a),
a);
}
/** Returns an unpremuled version of the GrColor. */
static inline GrColor GrUnPreMulColor(GrColor color) {
static inline GrColor GrUnpremulColor(GrColor color) {
GrColorIsPMAssert(color);
unsigned r = GrColorUnpackR(color);
unsigned g = GrColorUnpackG(color);
unsigned b = GrColorUnpackB(color);

View File

@ -12,7 +12,7 @@
struct GrInitInvariantOutput {
GrInitInvariantOutput()
: fValidFlags(0)
: fValidFlags(kNone_GrColorComponentFlags)
, fColor(0)
, fIsSingleComponent(false)
, fIsLCDCoverage(false) {}
@ -24,7 +24,7 @@ struct GrInitInvariantOutput {
}
void setUnknownFourComponents() {
fValidFlags = 0;
fValidFlags = kNone_GrColorComponentFlags;
fIsSingleComponent = false;
}
@ -41,16 +41,17 @@ struct GrInitInvariantOutput {
}
void setUnknownSingleComponent() {
fValidFlags = 0;
fValidFlags = kNone_GrColorComponentFlags;
fIsSingleComponent = true;
}
void setUsingLCDCoverage() { fIsLCDCoverage = true; }
uint32_t fValidFlags;
GrColor fColor;
bool fIsSingleComponent;
bool fIsLCDCoverage; // Temorary data member until texture pixel configs are updated
GrColorComponentFlags fValidFlags;
GrColor fColor;
bool fIsSingleComponent;
bool fIsLCDCoverage; // Temorary data member until texture pixel configs are
// updated
};
class GrInvariantOutput {
@ -107,7 +108,7 @@ public:
this->internalSetToTransparentBlack();
} else {
// We don't need to change fIsSingleComponent in this case
fValidFlags = 0;
fValidFlags = kNone_GrColorComponentFlags;
}
SkDEBUGCODE(this->validate());
}
@ -171,7 +172,7 @@ public:
}
} else {
fIsSingleComponent = false;
fValidFlags = 0;
fValidFlags = kNone_GrColorComponentFlags;
}
SkDEBUGCODE(this->validate());
}
@ -189,16 +190,16 @@ public:
fColor = GrColorPackRGBA(a, a, a, a);
fValidFlags = kRGBA_GrColorComponentFlags;
} else {
fValidFlags = 0;
fValidFlags = kNone_GrColorComponentFlags;
}
fIsSingleComponent = true;
}
SkDEBUGCODE(this->validate());
}
void invalidateComponents(uint8_t invalidateFlags, ReadInput readsInput) {
void invalidateComponents(GrColorComponentFlags invalidateFlags, ReadInput readsInput) {
SkDEBUGCODE(this->validate());
fValidFlags &= ~invalidateFlags;
fValidFlags = (fValidFlags & ~invalidateFlags);
fIsSingleComponent = false;
fNonMulStageFound = true;
if (kWillNot_ReadInput == readsInput) {
@ -207,7 +208,7 @@ public:
SkDEBUGCODE(this->validate());
}
void setToOther(uint8_t validFlags, GrColor color, ReadInput readsInput) {
void setToOther(GrColorComponentFlags validFlags, GrColor color, ReadInput readsInput) {
SkDEBUGCODE(this->validate());
fValidFlags = validFlags;
fColor = color;
@ -247,7 +248,7 @@ public:
}
GrColor color() const { return fColor; }
uint8_t validFlags() const { return fValidFlags; }
GrColorComponentFlags validFlags() const { return fValidFlags; }
/**
* If isSingleComponent is true, then the flag values for r, g, b, and a must all be the
@ -289,7 +290,7 @@ private:
}
void internalSetToUnknown() {
fValidFlags = 0;
fValidFlags = kNone_GrColorComponentFlags;
fIsSingleComponent = false;
}
@ -322,7 +323,7 @@ private:
SkDEBUGCODE(bool validPreMulColor() const;)
GrColor fColor;
uint32_t fValidFlags;
GrColorComponentFlags fValidFlags;
bool fIsSingleComponent;
bool fNonMulStageFound;
bool fWillUseInputColor;

View File

@ -38,8 +38,9 @@ GR_STATIC_ASSERT((int)kSA_GrBlendCoeff == (int)SkXfermode::kSA_Coeff);
GR_STATIC_ASSERT((int)kISA_GrBlendCoeff == (int)SkXfermode::kISA_Coeff);
GR_STATIC_ASSERT((int)kDA_GrBlendCoeff == (int)SkXfermode::kDA_Coeff);
GR_STATIC_ASSERT((int)kIDA_GrBlendCoeff == (int)SkXfermode::kIDA_Coeff);
GR_STATIC_ASSERT(SkXfermode::kCoeffCount == 10);
#define sk_blend_to_grblend(X) ((GrBlendCoeff)(X))
#define SkXfermodeCoeffToGrBlendCoeff(X) ((GrBlendCoeff)(X))
///////////////////////////////////////////////////////////////////////////////
@ -67,6 +68,16 @@ static inline GrColor SkColor2GrColorJustAlpha(SkColor c) {
return GrColorPackRGBA(a, a, a, a);
}
static inline SkPMColor GrColorToSkPMColor(GrColor c) {
GrColorIsPMAssert(c);
return SkPackARGB32(GrColorUnpackA(c), GrColorUnpackR(c), GrColorUnpackG(c), GrColorUnpackB(c));
}
static inline GrColor SkPMColorToGrColor(SkPMColor c) {
return GrColorPackRGBA(SkGetPackedR32(c), SkGetPackedG32(c), SkGetPackedB32(c),
SkGetPackedA32(c));
}
////////////////////////////////////////////////////////////////////////////////
/**

View File

@ -10,21 +10,14 @@
#include "SkXfermode.h"
class GrFragmentProcessor;
class GrTexture;
/**
* Custom Xfer modes are used for blending when the blend mode cannot be represented using blend
* coefficients. It is assumed that all blending is done within the processors' emit code. For each
* blend mode there should be a matching fragment processor (used when blending with a background
* texture) and xfer processor.
* coefficients.
*/
namespace GrCustomXfermode {
bool IsSupportedMode(SkXfermode::Mode mode);
GrFragmentProcessor* CreateFP(GrProcessorDataManager*, SkXfermode::Mode mode,
GrTexture* background);
bool IsSupportedMode(SkXfermode::Mode mode);
GrXPFactory* CreateXPFactory(SkXfermode::Mode mode);
};

View File

@ -13,6 +13,16 @@
class GrFragmentProcessor;
namespace GrXfermodeFragmentProcessor {
/** The color input to the returned processor is treated as the src and the passed in processor
is the dst. */
const GrFragmentProcessor* CreateFromDstProcessor(const GrFragmentProcessor* dst,
SkXfermode::Mode mode);
/** The color input to the returned processor is treated as the dst and the passed in processor
is the src. */
const GrFragmentProcessor* CreateFromSrcProcessor(const GrFragmentProcessor* src,
SkXfermode::Mode mode);
const GrFragmentProcessor* CreateFromTwoProcessors(const GrFragmentProcessor* src,
const GrFragmentProcessor* dst,
SkXfermode::Mode mode);

View File

@ -68,7 +68,7 @@ public:
#if SK_SUPPORT_GPU
bool asFragmentProcessors(GrContext* context, GrProcessorDataManager* procDataManager,
SkTDArray<GrFragmentProcessor*>* array) const override {
SkTDArray<const GrFragmentProcessor*>* array) const override {
bool hasFrags = fInner->asFragmentProcessors(context, procDataManager, array);
hasFrags |= fOuter->asFragmentProcessors(context, procDataManager, array);
return hasFrags;

View File

@ -207,17 +207,15 @@ const GrFragmentProcessor* SkComposeShader::asFragmentProcessor(GrContext* conte
SkFilterQuality fq,
GrProcessorDataManager* procDataManager
) const {
// Fragment processor will only support coefficient modes. This is because
// GrGLBlend::AppendPorterDuffBlend(), which emits the blend code in the shader,
// only supports those modes.
// Fragment processor will only support SkXfermode::Mode modes currently.
SkXfermode::Mode mode;
if (!(SkXfermode::AsMode(fMode, &mode) && SkXfermode::kLastCoeffMode >= mode)) {
if (!(SkXfermode::AsMode(fMode, &mode))) {
return nullptr;
}
switch (mode) {
case SkXfermode::kClear_Mode:
return GrConstColorProcessor::Create(GrColor_TRANS_BLACK,
return GrConstColorProcessor::Create(GrColor_TRANSPARENT_BLACK,
GrConstColorProcessor::kIgnore_InputMode);
break;
case SkXfermode::kSrc_Mode:

View File

@ -651,8 +651,8 @@ bool SkXfermode::asMode(Mode* mode) const {
return false;
}
bool SkXfermode::asFragmentProcessor(GrFragmentProcessor**, GrProcessorDataManager*,
GrTexture*) const {
bool SkXfermode::asFragmentProcessor(const GrFragmentProcessor**, GrProcessorDataManager*,
const GrFragmentProcessor*) const {
return false;
}
@ -920,19 +920,18 @@ void SkProcCoeffXfermode::xferA8(SkAlpha* SK_RESTRICT dst,
#if SK_SUPPORT_GPU
#include "effects/GrCustomXfermode.h"
#include "effects/GrXfermodeFragmentProcessor.h"
bool SkProcCoeffXfermode::asFragmentProcessor(GrFragmentProcessor** fp,
bool SkProcCoeffXfermode::asFragmentProcessor(const GrFragmentProcessor** fp,
GrProcessorDataManager* procDataManager,
GrTexture* background) const {
if (GrCustomXfermode::IsSupportedMode(fMode)) {
if (fp) {
SkASSERT(procDataManager);
*fp = GrCustomXfermode::CreateFP(procDataManager, fMode, background);
SkASSERT(*fp);
}
return true;
const GrFragmentProcessor* dst) const {
if (fp) {
SkASSERT(dst);
SkASSERT(procDataManager);
*fp = GrXfermodeFragmentProcessor::CreateFromDstProcessor(dst, fMode);
SkASSERT(*fp || kSrc_Mode == fMode);
}
return false;
return true;
}
bool SkProcCoeffXfermode::asXPFactory(GrXPFactory** xp) const {

View File

@ -44,8 +44,8 @@ public:
bool isOpaque(SkXfermode::SrcColorOpacity opacityType) const override;
#if SK_SUPPORT_GPU
bool asFragmentProcessor(GrFragmentProcessor**, GrProcessorDataManager*,
GrTexture* background) const override;
bool asFragmentProcessor(const GrFragmentProcessor**, GrProcessorDataManager*,
const GrFragmentProcessor*) const override;
bool asXPFactory(GrXPFactory**) const override;
#endif

View File

@ -31,8 +31,8 @@ public:
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkArithmeticMode_scalar)
#if SK_SUPPORT_GPU
bool asFragmentProcessor(GrFragmentProcessor**, GrProcessorDataManager*,
GrTexture* background) const override;
bool asFragmentProcessor(const GrFragmentProcessor**, GrProcessorDataManager*,
const GrFragmentProcessor* dst) const override;
bool asXPFactory(GrXPFactory**) const override;
#endif
@ -235,9 +235,9 @@ SkXfermode* SkArithmeticMode::Create(SkScalar k1, SkScalar k2,
//////////////////////////////////////////////////////////////////////////////
#if SK_SUPPORT_GPU
bool SkArithmeticMode_scalar::asFragmentProcessor(GrFragmentProcessor** fp,
bool SkArithmeticMode_scalar::asFragmentProcessor(const GrFragmentProcessor** fp,
GrProcessorDataManager* procDataManager,
GrTexture* background) const {
const GrFragmentProcessor* dst) const {
if (fp) {
*fp = GrArithmeticFP::Create(procDataManager,
SkScalarToFloat(fK[0]),
@ -245,7 +245,7 @@ bool SkArithmeticMode_scalar::asFragmentProcessor(GrFragmentProcessor** fp,
SkScalarToFloat(fK[2]),
SkScalarToFloat(fK[3]),
fEnforcePMColor,
background);
dst);
}
return true;
}

View File

@ -21,16 +21,16 @@
static const bool gUseUnpremul = false;
static void add_arithmetic_code(GrGLFragmentBuilder* fsBuilder,
const char* inputColor,
const char* srcColor,
const char* dstColor,
const char* outputColor,
const char* kUni,
bool enforcePMColor) {
// We don't try to optimize for this case at all
if (nullptr == inputColor) {
if (nullptr == srcColor) {
fsBuilder->codeAppend("const vec4 src = vec4(1);");
} else {
fsBuilder->codeAppendf("vec4 src = %s;", inputColor);
fsBuilder->codeAppendf("vec4 src = %s;", srcColor);
if (gUseUnpremul) {
fsBuilder->codeAppend("src.rgb = clamp(src.rgb / src.a, 0.0, 1.0);");
}
@ -54,26 +54,21 @@ static void add_arithmetic_code(GrGLFragmentBuilder* fsBuilder,
class GLArithmeticFP : public GrGLFragmentProcessor {
public:
GLArithmeticFP(const GrProcessor&)
: fEnforcePMColor(true) {
}
GLArithmeticFP(const GrProcessor&) : fEnforcePMColor(true) {}
~GLArithmeticFP() override {}
void emitCode(EmitArgs& args) override {
GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();
fsBuilder->codeAppend("vec4 bgColor = ");
fsBuilder->appendTextureLookup(args.fSamplers[0], args.fCoords[0].c_str(),
args.fCoords[0].getType());
fsBuilder->codeAppendf(";");
const char* dstColor = "bgColor";
fsBuilder->codeAppend("vec4 _dstColor;");
this->emitChild(0, nullptr, "_dstColor", args);
fKUni = args.fBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
kVec4f_GrSLType, kDefault_GrSLPrecision,
"k");
kVec4f_GrSLType, kDefault_GrSLPrecision,
"k");
const char* kUni = args.fBuilder->getUniformCStr(fKUni);
add_arithmetic_code(fsBuilder, args.fInputColor, dstColor, args.fOutputColor, kUni,
add_arithmetic_code(fsBuilder, args.fInputColor, "_dstColor", args.fOutputColor, kUni,
fEnforcePMColor);
}
@ -100,17 +95,13 @@ private:
///////////////////////////////////////////////////////////////////////////////
GrArithmeticFP::GrArithmeticFP(GrProcessorDataManager*, float k1, float k2, float k3, float k4,
bool enforcePMColor, GrTexture* background)
bool enforcePMColor, const GrFragmentProcessor* dst)
: fK1(k1), fK2(k2), fK3(k3), fK4(k4), fEnforcePMColor(enforcePMColor) {
this->initClassID<GrArithmeticFP>();
SkASSERT(background);
fBackgroundTransform.reset(kLocal_GrCoordSet, background,
GrTextureParams::kNone_FilterMode);
this->addCoordTransform(&fBackgroundTransform);
fBackgroundAccess.reset(background);
this->addTextureAccess(&fBackgroundAccess);
SkASSERT(dst);
SkDEBUGCODE(int dstIndex = )this->registerChildProcessor(dst);
SkASSERT(0 == dstIndex);
}
void GrArithmeticFP::onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const {
@ -144,7 +135,8 @@ const GrFragmentProcessor* GrArithmeticFP::TestCreate(GrProcessorTestData* d) {
float k4 = d->fRandom->nextF();
bool enforcePMColor = d->fRandom->nextBool();
return new GrArithmeticFP(d->fProcDataManager, k1, k2, k3, k4, enforcePMColor, d->fTextures[0]);
SkAutoTUnref<const GrFragmentProcessor> dst(GrProcessorUnitTest::CreateChildFP(d));
return new GrArithmeticFP(d->fProcDataManager, k1, k2, k3, k4, enforcePMColor, dst);
}
GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrArithmeticFP);

View File

@ -31,10 +31,10 @@ class GrGLArtithmeticFP;
class GrArithmeticFP : public GrFragmentProcessor {
public:
static GrFragmentProcessor* Create(GrProcessorDataManager* procDataManager, float k1, float k2,
float k3, float k4, bool enforcePMColor,
GrTexture* background) {
return new GrArithmeticFP(procDataManager, k1, k2, k3, k4, enforcePMColor, background);
static const GrFragmentProcessor* Create(GrProcessorDataManager* procDataManager,
float k1, float k2, float k3, float k4,
bool enforcePMColor, const GrFragmentProcessor* dst) {
return new GrArithmeticFP(procDataManager, k1, k2, k3, k4, enforcePMColor, dst);
}
~GrArithmeticFP() override {};
@ -57,12 +57,10 @@ private:
void onComputeInvariantOutput(GrInvariantOutput* inout) const override;
GrArithmeticFP(GrProcessorDataManager*, float k1, float k2, float k3, float k4,
bool enforcePMColor, GrTexture* background);
bool enforcePMColor, const GrFragmentProcessor* dst);
float fK1, fK2, fK3, fK4;
bool fEnforcePMColor;
GrCoordTransform fBackgroundTransform;
GrTextureAccess fBackgroundAccess;
GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
typedef GrFragmentProcessor INHERITED;

View File

@ -304,7 +304,7 @@ void GrColorCubeEffect::GLProcessor::GenKey(const GrProcessor& proc,
}
bool SkColorCubeFilter::asFragmentProcessors(GrContext* context, GrProcessorDataManager*,
SkTDArray<GrFragmentProcessor*>* array) const {
SkTDArray<const GrFragmentProcessor*>* array) const {
static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
GrUniqueKey key;
GrUniqueKey::Builder builder(&key, kDomain, 2);

View File

@ -65,305 +65,36 @@ SkFlattenable* SkModeColorFilter::CreateProc(SkReadBuffer& buffer) {
///////////////////////////////////////////////////////////////////////////////
#if SK_SUPPORT_GPU
#include "GrBlend.h"
#include "GrFragmentProcessor.h"
#include "GrInvariantOutput.h"
#include "GrProcessorUnitTest.h"
#include "effects/GrXfermodeFragmentProcessor.h"
#include "effects/GrConstColorProcessor.h"
#include "SkGr.h"
#include "gl/GrGLFragmentProcessor.h"
#include "gl/builders/GrGLProgramBuilder.h"
namespace {
/**
* A definition of blend equation for one coefficient. Generates a
* blend_coeff * value "expression".
*/
template<typename ColorExpr>
static inline ColorExpr blend_term(SkXfermode::Coeff coeff,
const ColorExpr& src,
const ColorExpr& dst,
const ColorExpr& value) {
switch (coeff) {
default:
SkFAIL("Unexpected xfer coeff.");
case SkXfermode::kZero_Coeff: /** 0 */
return ColorExpr(0);
case SkXfermode::kOne_Coeff: /** 1 */
return value;
case SkXfermode::kSC_Coeff:
return src * value;
case SkXfermode::kISC_Coeff:
return (ColorExpr(1) - src) * dst;
case SkXfermode::kDC_Coeff:
return dst * value;
case SkXfermode::kIDC_Coeff:
return (ColorExpr(1) - dst) * value;
case SkXfermode::kSA_Coeff: /** src alpha */
return src.a() * value;
case SkXfermode::kISA_Coeff: /** inverse src alpha (i.e. 1 - sa) */
return (typename ColorExpr::AExpr(1) - src.a()) * value;
case SkXfermode::kDA_Coeff: /** dst alpha */
return dst.a() * value;
case SkXfermode::kIDA_Coeff: /** inverse dst alpha (i.e. 1 - da) */
return (typename ColorExpr::AExpr(1) - dst.a()) * value;
}
}
/**
* Creates a color filter expression which modifies the color by
* the specified color filter.
*/
template <typename ColorExpr>
static inline ColorExpr color_filter_expression(const SkXfermode::Mode& mode,
const ColorExpr& filterColor,
const ColorExpr& inColor) {
SkXfermode::Coeff colorCoeff;
SkXfermode::Coeff filterColorCoeff;
SkAssertResult(SkXfermode::ModeAsCoeff(mode, &filterColorCoeff, &colorCoeff));
return blend_term(colorCoeff, filterColor, inColor, inColor) +
blend_term(filterColorCoeff, filterColor, inColor, filterColor);
}
}
class ModeColorFilterEffect : public GrFragmentProcessor {
public:
static GrFragmentProcessor* Create(const GrColor& c, SkXfermode::Mode mode) {
// TODO: Make the effect take the coeffs rather than mode since we already do the
// conversion here.
SkXfermode::Coeff srcCoeff, dstCoeff;
if (!SkXfermode::ModeAsCoeff(mode, &srcCoeff, &dstCoeff)) {
// SkDebugf("Failing to create color filter for mode %d\n", mode);
return nullptr;
}
return new ModeColorFilterEffect(c, mode);
}
bool willUseFilterColor() const {
SkXfermode::Coeff dstCoeff;
SkXfermode::Coeff srcCoeff;
SkAssertResult(SkXfermode::ModeAsCoeff(fMode, &srcCoeff, &dstCoeff));
if (SkXfermode::kZero_Coeff == srcCoeff) {
return GrBlendCoeffRefsSrc(sk_blend_to_grblend(dstCoeff));
}
return true;
}
const char* name() const override { return "ModeColorFilterEffect"; }
SkXfermode::Mode mode() const { return fMode; }
GrColor color() const { return fColor; }
class GLProcessor : public GrGLFragmentProcessor {
public:
GLProcessor(const GrProcessor&) {
}
virtual void emitCode(EmitArgs& args) override {
SkXfermode::Mode mode = args.fFp.cast<ModeColorFilterEffect>().mode();
SkASSERT(SkXfermode::kDst_Mode != mode);
const char* colorFilterColorUniName = nullptr;
if (args.fFp.cast<ModeColorFilterEffect>().willUseFilterColor()) {
fFilterColorUni = args.fBuilder->addUniform(
GrGLProgramBuilder::kFragment_Visibility,
kVec4f_GrSLType, kDefault_GrSLPrecision,
"FilterColor",
&colorFilterColorUniName);
}
GrGLSLExpr4 filter =
color_filter_expression(mode, GrGLSLExpr4(colorFilterColorUniName),
GrGLSLExpr4(args.fInputColor));
args.fBuilder->getFragmentShaderBuilder()->
codeAppendf("\t%s = %s;\n", args.fOutputColor, filter.c_str());
}
static void GenKey(const GrProcessor& fp, const GrGLSLCaps&,
GrProcessorKeyBuilder* b) {
const ModeColorFilterEffect& colorModeFilter = fp.cast<ModeColorFilterEffect>();
// The SL code does not depend on filter color at the moment, so no need to represent it
// in the key.
b->add32(colorModeFilter.mode());
}
protected:
virtual void onSetData(const GrGLProgramDataManager& pdman,
const GrProcessor& fp) override {
if (fFilterColorUni.isValid()) {
const ModeColorFilterEffect& colorModeFilter = fp.cast<ModeColorFilterEffect>();
GrGLfloat c[4];
GrColorToRGBAFloat(colorModeFilter.color(), c);
pdman.set4fv(fFilterColorUni, 1, c);
}
}
private:
GrGLProgramDataManager::UniformHandle fFilterColorUni;
typedef GrGLFragmentProcessor INHERITED;
};
GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
private:
ModeColorFilterEffect(GrColor color, SkXfermode::Mode mode)
: fMode(mode),
fColor(color) {
this->initClassID<ModeColorFilterEffect>();
}
GrGLFragmentProcessor* onCreateGLInstance() const override { return new GLProcessor(*this); }
virtual void onGetGLProcessorKey(const GrGLSLCaps& caps,
GrProcessorKeyBuilder* b) const override {
GLProcessor::GenKey(*this, caps, b);
}
bool onIsEqual(const GrFragmentProcessor& other) const override {
const ModeColorFilterEffect& s = other.cast<ModeColorFilterEffect>();
return fMode == s.fMode && fColor == s.fColor;
}
void onComputeInvariantOutput(GrInvariantOutput* inout) const override;
SkXfermode::Mode fMode;
GrColor fColor;
typedef GrFragmentProcessor INHERITED;
};
namespace {
/** Function color_component_to_int tries to reproduce the GLSL rounding. The spec doesn't specify
* to which direction the 0.5 goes.
*/
static inline int color_component_to_int(float value) {
return sk_float_round2int(SkTMax(0.f, SkTMin(1.f, value)) * 255.f);
}
/** MaskedColorExpr is used to evaluate the color and valid color component flags through the
* blending equation. It has members similar to GrGLSLExpr so that it can be used with the
* templated helpers above.
*/
class MaskedColorExpr {
public:
MaskedColorExpr(const float color[], uint32_t flags)
: fFlags(flags) {
fColor[0] = color[0];
fColor[1] = color[1];
fColor[2] = color[2];
fColor[3] = color[3];
}
MaskedColorExpr(float v, uint32_t flags = kRGBA_GrColorComponentFlags)
: fFlags(flags) {
fColor[0] = v;
fColor[1] = v;
fColor[2] = v;
fColor[3] = v;
}
MaskedColorExpr operator*(const MaskedColorExpr& other) const {
float tmp[4];
tmp[0] = fColor[0] * other.fColor[0];
tmp[1] = fColor[1] * other.fColor[1];
tmp[2] = fColor[2] * other.fColor[2];
tmp[3] = fColor[3] * other.fColor[3];
return MaskedColorExpr(tmp, fFlags & other.fFlags);
}
MaskedColorExpr operator+(const MaskedColorExpr& other) const {
float tmp[4];
tmp[0] = fColor[0] + other.fColor[0];
tmp[1] = fColor[1] + other.fColor[1];
tmp[2] = fColor[2] + other.fColor[2];
tmp[3] = fColor[3] + other.fColor[3];
return MaskedColorExpr(tmp, fFlags & other.fFlags);
}
MaskedColorExpr operator-(const MaskedColorExpr& other) const {
float tmp[4];
tmp[0] = fColor[0] - other.fColor[0];
tmp[1] = fColor[1] - other.fColor[1];
tmp[2] = fColor[2] - other.fColor[2];
tmp[3] = fColor[3] - other.fColor[3];
return MaskedColorExpr(tmp, fFlags & other.fFlags);
}
MaskedColorExpr a() const {
uint32_t flags = (fFlags & kA_GrColorComponentFlag) ? kRGBA_GrColorComponentFlags : 0;
return MaskedColorExpr(fColor[3], flags);
}
GrColor getColor() const {
return GrColorPackRGBA(color_component_to_int(fColor[0]),
color_component_to_int(fColor[1]),
color_component_to_int(fColor[2]),
color_component_to_int(fColor[3]));
}
uint32_t getValidComponents() const { return fFlags; }
typedef MaskedColorExpr AExpr;
private:
float fColor[4];
uint32_t fFlags;
};
}
void ModeColorFilterEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
float inputColor[4];
GrColorToRGBAFloat(inout->color(), inputColor);
float filterColor[4];
GrColorToRGBAFloat(fColor, filterColor);
MaskedColorExpr result =
color_filter_expression(fMode,
MaskedColorExpr(filterColor, kRGBA_GrColorComponentFlags),
MaskedColorExpr(inputColor, inout->validFlags()));
// Check if we will use the input color
SkXfermode::Coeff dstCoeff;
SkXfermode::Coeff srcCoeff;
SkAssertResult(SkXfermode::ModeAsCoeff(fMode, &srcCoeff, &dstCoeff));
GrInvariantOutput::ReadInput readInput = GrInvariantOutput::kWill_ReadInput;
// These could be calculated from the blend equation with template trickery..
if (SkXfermode::kZero_Coeff == dstCoeff &&
!GrBlendCoeffRefsDst(sk_blend_to_grblend(srcCoeff))) {
readInput = GrInvariantOutput::kWillNot_ReadInput;
}
inout->setToOther(result.getValidComponents(), result.getColor(), readInput);
}
GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ModeColorFilterEffect);
const GrFragmentProcessor* ModeColorFilterEffect::TestCreate(GrProcessorTestData* d) {
SkXfermode::Mode mode = SkXfermode::kDst_Mode;
while (SkXfermode::kDst_Mode == mode) {
mode = static_cast<SkXfermode::Mode>(d->fRandom->nextRangeU(0, SkXfermode::kLastCoeffMode));
}
// pick a random premul color
uint8_t alpha = d->fRandom->nextULessThan(256);
GrColor color = GrColorPackRGBA(d->fRandom->nextRangeU(0, alpha),
d->fRandom->nextRangeU(0, alpha),
d->fRandom->nextRangeU(0, alpha),
alpha);
return ModeColorFilterEffect::Create(color, mode);
}
bool SkModeColorFilter::asFragmentProcessors(GrContext*, GrProcessorDataManager*,
SkTDArray<GrFragmentProcessor*>* array) const {
SkTDArray<const GrFragmentProcessor*>* array) const {
if (SkXfermode::kDst_Mode != fMode) {
GrFragmentProcessor* frag = ModeColorFilterEffect::Create(SkColor2GrColor(fColor), fMode);
if (frag) {
SkAutoTUnref<const GrFragmentProcessor> constFP(
GrConstColorProcessor::Create(SkColor2GrColor(fColor),
GrConstColorProcessor::kIgnore_InputMode));
const GrFragmentProcessor* fp =
GrXfermodeFragmentProcessor::CreateFromSrcProcessor(constFP, fMode);
if (fp) {
#ifdef SK_DEBUG
// With a solid color input this should always be able to compute the blended color
// (at least for coeff modes)
if (fMode <= SkXfermode::kLastCoeffMode) {
static SkRandom gRand;
GrInvariantOutput io(GrPremulColor(gRand.nextU()), kRGBA_GrColorComponentFlags,
false);
fp->computeInvariantOutput(&io);
SkASSERT(io.validFlags() == kRGBA_GrColorComponentFlags);
}
#endif
if (array) {
*array->append() = frag;
*array->append() = fp;
} else {
frag->unref();
SkDEBUGCODE(frag = nullptr;)
fp->unref();
SkDEBUGCODE(fp = nullptr;)
}
return true;
}

View File

@ -537,7 +537,7 @@ const GrFragmentProcessor* ColorMatrixEffect::TestCreate(GrProcessorTestData* d)
}
bool SkColorMatrixFilter::asFragmentProcessors(GrContext*, GrProcessorDataManager*,
SkTDArray<GrFragmentProcessor*>* array) const {
SkTDArray<const GrFragmentProcessor*>* array) const {
GrFragmentProcessor* frag = ColorMatrixEffect::Create(fMatrix);
if (frag) {
if (array) {

View File

@ -109,7 +109,7 @@ private:
};
bool SkLumaColorFilter::asFragmentProcessors(GrContext*, GrProcessorDataManager*,
SkTDArray<GrFragmentProcessor*>* array) const {
SkTDArray<const GrFragmentProcessor*>* array) const {
GrFragmentProcessor* frag = LumaColorFilterEffect::Create();
if (frag) {

View File

@ -49,7 +49,7 @@ public:
#if SK_SUPPORT_GPU
bool asFragmentProcessors(GrContext*, GrProcessorDataManager*,
SkTDArray<GrFragmentProcessor*>*) const override;
SkTDArray<const GrFragmentProcessor*>*) const override;
#endif
void filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const override;
@ -521,7 +521,7 @@ bool ColorTableEffect::onIsEqual(const GrFragmentProcessor& other) const {
void ColorTableEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
// If we kept the table in the effect then we could actually run known inputs through the
// table.
uint8_t invalidateFlags = 0;
GrColorComponentFlags invalidateFlags = kNone_GrColorComponentFlags;
if (fFlags & SkTable_ColorFilter::kR_Flag) {
invalidateFlags |= kR_GrColorComponentFlag;
}
@ -563,7 +563,7 @@ const GrFragmentProcessor* ColorTableEffect::TestCreate(GrProcessorTestData* d)
(flags & (1 << 3)) ? luts[3] : nullptr
));
SkTDArray<GrFragmentProcessor*> array;
SkTDArray<const GrFragmentProcessor*> array;
if (filter->asFragmentProcessors(d->fContext, d->fProcDataManager, &array)) {
SkASSERT(1 == array.count()); // TableColorFilter only returns 1
return array[0];
@ -573,7 +573,7 @@ const GrFragmentProcessor* ColorTableEffect::TestCreate(GrProcessorTestData* d)
bool SkTable_ColorFilter::asFragmentProcessors(GrContext* context,
GrProcessorDataManager*,
SkTDArray<GrFragmentProcessor*>* array) const {
SkTDArray<const GrFragmentProcessor*>* array) const {
SkBitmap bitmap;
this->asComponentTable(&bitmap);

View File

@ -16,6 +16,7 @@
#include "GrContext.h"
#include "GrDrawContext.h"
#include "effects/GrTextureDomain.h"
#include "effects/GrSimpleTextureEffect.h"
#include "SkGr.h"
#endif
@ -153,7 +154,7 @@ bool SkXfermodeImageFilter::filterImageGPU(Proxy* proxy,
GrTexture* foregroundTex = foreground.getTexture();
GrContext* context = foregroundTex->getContext();
GrFragmentProcessor* xferProcessor = nullptr;
const GrFragmentProcessor* xferFP = nullptr;
GrSurfaceDesc desc;
desc.fFlags = kRenderTarget_GrSurfaceFlag;
@ -166,8 +167,11 @@ bool SkXfermodeImageFilter::filterImageGPU(Proxy* proxy,
}
GrPaint paint;
if (!fMode || !fMode->asFragmentProcessor(&xferProcessor, paint.getProcessorDataManager(),
backgroundTex)) {
SkMatrix bgMatrix;
bgMatrix.setIDiv(backgroundTex->width(), backgroundTex->height());
SkAutoTUnref<const GrFragmentProcessor> bgFP(
GrSimpleTextureEffect::Create(paint.getProcessorDataManager(), backgroundTex, bgMatrix));
if (!fMode || !fMode->asFragmentProcessor(&xferFP, paint.getProcessorDataManager(), bgFP)) {
// canFilterImageGPU() should've taken care of this
SkASSERT(false);
return false;
@ -190,7 +194,9 @@ bool SkXfermodeImageFilter::filterImageGPU(Proxy* proxy,
);
paint.addColorFragmentProcessor(foregroundDomain.get());
paint.addColorFragmentProcessor(xferProcessor)->unref();
if (xferFP) {
paint.addColorFragmentProcessor(xferFP)->unref();
}
SkAutoTUnref<GrDrawContext> drawContext(context->drawContext());
if (!drawContext) {

124
src/gpu/GrBlend.cpp Normal file
View File

@ -0,0 +1,124 @@
/*
* 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 "GrBlend.h"
/**
* MaskedColor is used to evaluate the color and valid color component flags through the
* blending equation. Could possibly extend this to be used more broadly.
*/
class MaskedColor {
public:
MaskedColor(GrColor color, GrColorComponentFlags flags)
: fColor(color)
, fFlags(flags) {}
MaskedColor() {}
void set(GrColor color, GrColorComponentFlags flags) {
fColor = color;
fFlags = flags;
}
static MaskedColor Invert(const MaskedColor& in) {
return MaskedColor(GrInvertColor(in.fColor), in.fFlags);
}
static MaskedColor ExtractAlpha(const MaskedColor& in) {
GrColorComponentFlags flags = (in.fFlags & kA_GrColorComponentFlag) ?
kRGBA_GrColorComponentFlags : kNone_GrColorComponentFlags;
return MaskedColor(GrColorPackA4(GrColorUnpackA(in.fColor)), flags);
}
static MaskedColor ExtractInverseAlpha(const MaskedColor& in) {
GrColorComponentFlags flags = (in.fFlags & kA_GrColorComponentFlag) ?
kRGBA_GrColorComponentFlags : kNone_GrColorComponentFlags;
return MaskedColor(GrColorPackA4(0xFF - GrColorUnpackA(in.fColor)), flags);
}
static MaskedColor Mul(const MaskedColor& a, const MaskedColor& b) {
GrColorComponentFlags outFlags = (a.fFlags & b.fFlags) | a.componentsWithValue(0) |
b.componentsWithValue(0);
return MaskedColor(GrColorMul(a.fColor, b.fColor), outFlags);
}
static MaskedColor SatAdd(const MaskedColor& a, const MaskedColor& b) {
GrColorComponentFlags outFlags = (a.fFlags & b.fFlags) | a.componentsWithValue(0xFF) |
b.componentsWithValue(0xFF);
return MaskedColor(GrColorSatAdd(a.fColor, b.fColor), outFlags);
}
GrColor color() const { return fColor; }
GrColorComponentFlags validFlags () const { return fFlags; }
private:
GrColorComponentFlags componentsWithValue(unsigned value) const {
GrColorComponentFlags flags = kNone_GrColorComponentFlags;
if ((kR_GrColorComponentFlag & fFlags) && value == GrColorUnpackR(fColor)) {
flags |= kR_GrColorComponentFlag;
}
if ((kG_GrColorComponentFlag & fFlags) && value == GrColorUnpackG(fColor)) {
flags |= kG_GrColorComponentFlag;
}
if ((kB_GrColorComponentFlag & fFlags) && value == GrColorUnpackB(fColor)) {
flags |= kB_GrColorComponentFlag;
}
if ((kA_GrColorComponentFlag & fFlags) && value == GrColorUnpackA(fColor)) {
flags |= kA_GrColorComponentFlag;
}
return flags;
}
GrColor fColor;
GrColorComponentFlags fFlags;
};
static MaskedColor get_term(GrBlendCoeff coeff, const MaskedColor& src, const MaskedColor& dst,
const MaskedColor& value) {
switch (coeff) {
case kZero_GrBlendCoeff:
return MaskedColor(0, kRGBA_GrColorComponentFlags);
case kOne_GrBlendCoeff:
return value;
case kDC_GrBlendCoeff:
return MaskedColor::Mul(dst, value);
case kIDC_GrBlendCoeff:
return MaskedColor::Mul(MaskedColor::Invert(dst), value);
case kDA_GrBlendCoeff:
return MaskedColor::Mul(MaskedColor::ExtractAlpha(dst), value);
case kIDA_GrBlendCoeff:
return MaskedColor::Mul(MaskedColor::ExtractInverseAlpha(dst), value);
case kSC_GrBlendCoeff:
return MaskedColor::Mul(src, value);
case kISC_GrBlendCoeff:
return MaskedColor::Mul(MaskedColor::Invert(src), value);
case kSA_GrBlendCoeff:
return MaskedColor::Mul(MaskedColor::ExtractAlpha(src), value);
case kISA_GrBlendCoeff:
return MaskedColor::Mul(MaskedColor::ExtractInverseAlpha(src), value);
default:
SkFAIL("Illegal coefficient");
return MaskedColor();
}
}
void GrGetCoeffBlendKnownComponents(GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff,
GrColor srcColor, GrColorComponentFlags srcColorFlags,
GrColor dstColor, GrColorComponentFlags dstColorFlags,
GrColor* outColor,
GrColorComponentFlags* outFlags) {
MaskedColor src(srcColor, srcColorFlags);
MaskedColor dst(dstColor, dstColorFlags);
MaskedColor srcTerm = get_term(srcCoeff, src, dst, src);
MaskedColor dstTerm = get_term(dstCoeff, src, dst, dst);
MaskedColor output = MaskedColor::SatAdd(srcTerm, dstTerm);
*outColor = output.color();
*outFlags = output.validFlags();
}

View File

@ -50,7 +50,7 @@ GrProcessorTestFactory<GrGeometryProcessor>::GetFactories() {
* we verify the count is as expected. If a new factory is added, then these numbers must be
* manually adjusted.
*/
static const int kFPFactoryCount = 40;
static const int kFPFactoryCount = 39;
static const int kGPFactoryCount = 14;
static const int kXPFactoryCount = 5;

View File

@ -734,7 +734,7 @@ bool SkPaint2GrPaintNoShader(GrContext* context, GrRenderTarget* rt, const SkPai
SkColor filtered = colorFilter->filterColor(skPaint.getColor());
grPaint->setColor(SkColor2GrColor(filtered));
} else {
SkTDArray<GrFragmentProcessor*> array;
SkTDArray<const GrFragmentProcessor*> array;
// return false if failed?
if (colorFilter->asFragmentProcessors(context, grPaint->getProcessorDataManager(),
&array)) {

View File

@ -6,7 +6,6 @@
*/
#include "effects/GrCustomXfermode.h"
#include "effects/GrCustomXfermodePriv.h"
#include "GrCoordTransform.h"
#include "GrContext.h"
@ -18,6 +17,7 @@
#include "SkXfermode.h"
#include "gl/GrGLCaps.h"
#include "gl/GrGLGpu.h"
#include "gl/GrGLSLBlend.h"
#include "gl/GrGLFragmentProcessor.h"
#include "gl/GrGLProgramDataManager.h"
#include "gl/builders/GrGLProgramBuilder.h"
@ -67,452 +67,6 @@ static bool can_use_hw_blend_equation(GrBlendEquation equation,
return true;
}
static void hard_light(GrGLFragmentBuilder* fsBuilder,
const char* final,
const char* src,
const char* dst) {
static const char kComponents[] = {'r', 'g', 'b'};
for (size_t i = 0; i < SK_ARRAY_COUNT(kComponents); ++i) {
char component = kComponents[i];
fsBuilder->codeAppendf("if (2.0 * %s.%c <= %s.a) {", src, component, src);
fsBuilder->codeAppendf("%s.%c = 2.0 * %s.%c * %s.%c;",
final, component, src, component, dst, component);
fsBuilder->codeAppend("} else {");
fsBuilder->codeAppendf("%s.%c = %s.a * %s.a - 2.0 * (%s.a - %s.%c) * (%s.a - %s.%c);",
final, component, src, dst, dst, dst, component, src, src,
component);
fsBuilder->codeAppend("}");
}
fsBuilder->codeAppendf("%s.rgb += %s.rgb * (1.0 - %s.a) + %s.rgb * (1.0 - %s.a);",
final, src, dst, dst, src);
}
// Does one component of color-dodge
static void color_dodge_component(GrGLFragmentBuilder* fsBuilder,
const char* final,
const char* src,
const char* dst,
const char component) {
fsBuilder->codeAppendf("if (0.0 == %s.%c) {", dst, component);
fsBuilder->codeAppendf("%s.%c = %s.%c * (1.0 - %s.a);",
final, component, src, component, dst);
fsBuilder->codeAppend("} else {");
fsBuilder->codeAppendf("float d = %s.a - %s.%c;", src, src, component);
fsBuilder->codeAppend("if (0.0 == d) {");
fsBuilder->codeAppendf("%s.%c = %s.a * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);",
final, component, src, dst, src, component, dst, dst, component,
src);
fsBuilder->codeAppend("} else {");
fsBuilder->codeAppendf("d = min(%s.a, %s.%c * %s.a / d);",
dst, dst, component, src);
fsBuilder->codeAppendf("%s.%c = d * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);",
final, component, src, src, component, dst, dst, component, src);
fsBuilder->codeAppend("}");
fsBuilder->codeAppend("}");
}
// Does one component of color-burn
static void color_burn_component(GrGLFragmentBuilder* fsBuilder,
const char* final,
const char* src,
const char* dst,
const char component) {
fsBuilder->codeAppendf("if (%s.a == %s.%c) {", dst, dst, component);
fsBuilder->codeAppendf("%s.%c = %s.a * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);",
final, component, src, dst, src, component, dst, dst, component,
src);
fsBuilder->codeAppendf("} else if (0.0 == %s.%c) {", src, component);
fsBuilder->codeAppendf("%s.%c = %s.%c * (1.0 - %s.a);",
final, component, dst, component, src);
fsBuilder->codeAppend("} else {");
fsBuilder->codeAppendf("float d = max(0.0, %s.a - (%s.a - %s.%c) * %s.a / %s.%c);",
dst, dst, dst, component, src, src, component);
fsBuilder->codeAppendf("%s.%c = %s.a * d + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);",
final, component, src, src, component, dst, dst, component, src);
fsBuilder->codeAppend("}");
}
// Does one component of soft-light. Caller should have already checked that dst alpha > 0.
static void soft_light_component_pos_dst_alpha(GrGLFragmentBuilder* fsBuilder,
const char* final,
const char* src,
const char* dst,
const char component) {
// if (2S < Sa)
fsBuilder->codeAppendf("if (2.0 * %s.%c <= %s.a) {", src, component, src);
// (D^2 (Sa-2 S))/Da+(1-Da) S+D (-Sa+2 S+1)
fsBuilder->codeAppendf("%s.%c = (%s.%c*%s.%c*(%s.a - 2.0*%s.%c)) / %s.a +"
"(1.0 - %s.a) * %s.%c + %s.%c*(-%s.a + 2.0*%s.%c + 1.0);",
final, component, dst, component, dst, component, src, src,
component, dst, dst, src, component, dst, component, src, src,
component);
// else if (4D < Da)
fsBuilder->codeAppendf("} else if (4.0 * %s.%c <= %s.a) {",
dst, component, dst);
fsBuilder->codeAppendf("float DSqd = %s.%c * %s.%c;",
dst, component, dst, component);
fsBuilder->codeAppendf("float DCub = DSqd * %s.%c;", dst, component);
fsBuilder->codeAppendf("float DaSqd = %s.a * %s.a;", dst, dst);
fsBuilder->codeAppendf("float DaCub = DaSqd * %s.a;", dst);
// (Da^3 (-S)+Da^2 (S-D (3 Sa-6 S-1))+12 Da D^2 (Sa-2 S)-16 D^3 (Sa-2 S))/Da^2
fsBuilder->codeAppendf("%s.%c ="
"(DaSqd*(%s.%c - %s.%c * (3.0*%s.a - 6.0*%s.%c - 1.0)) +"
" 12.0*%s.a*DSqd*(%s.a - 2.0*%s.%c) - 16.0*DCub * (%s.a - 2.0*%s.%c) -"
" DaCub*%s.%c) / DaSqd;",
final, component, src, component, dst, component,
src, src, component, dst, src, src, component, src, src,
component, src, component);
fsBuilder->codeAppendf("} else {");
// -sqrt(Da * D) (Sa-2 S)-Da S+D (Sa-2 S+1)+S
fsBuilder->codeAppendf("%s.%c = %s.%c*(%s.a - 2.0*%s.%c + 1.0) + %s.%c -"
" sqrt(%s.a*%s.%c)*(%s.a - 2.0*%s.%c) - %s.a*%s.%c;",
final, component, dst, component, src, src, component, src, component,
dst, dst, component, src, src, component, dst, src, component);
fsBuilder->codeAppendf("}");
}
// Adds a function that takes two colors and an alpha as input. It produces a color with the
// hue and saturation of the first color, the luminosity of the second color, and the input
// alpha. It has this signature:
// vec3 set_luminance(vec3 hueSatColor, float alpha, vec3 lumColor).
static void add_lum_function(GrGLFragmentBuilder* fsBuilder, SkString* setLumFunction) {
// Emit a helper that gets the luminance of a color.
SkString getFunction;
GrGLShaderVar getLumArgs[] = {
GrGLShaderVar("color", kVec3f_GrSLType),
};
SkString getLumBody("return dot(vec3(0.3, 0.59, 0.11), color);");
fsBuilder->emitFunction(kFloat_GrSLType,
"luminance",
SK_ARRAY_COUNT(getLumArgs), getLumArgs,
getLumBody.c_str(),
&getFunction);
// Emit the set luminance function.
GrGLShaderVar setLumArgs[] = {
GrGLShaderVar("hueSat", kVec3f_GrSLType),
GrGLShaderVar("alpha", kFloat_GrSLType),
GrGLShaderVar("lumColor", kVec3f_GrSLType),
};
SkString setLumBody;
setLumBody.printf("float diff = %s(lumColor - hueSat);", getFunction.c_str());
setLumBody.append("vec3 outColor = hueSat + diff;");
setLumBody.appendf("float outLum = %s(outColor);", getFunction.c_str());
setLumBody.append("float minComp = min(min(outColor.r, outColor.g), outColor.b);"
"float maxComp = max(max(outColor.r, outColor.g), outColor.b);"
"if (minComp < 0.0 && outLum != minComp) {"
"outColor = outLum + ((outColor - vec3(outLum, outLum, outLum)) * outLum) /"
"(outLum - minComp);"
"}"
"if (maxComp > alpha && maxComp != outLum) {"
"outColor = outLum +"
"((outColor - vec3(outLum, outLum, outLum)) * (alpha - outLum)) /"
"(maxComp - outLum);"
"}"
"return outColor;");
fsBuilder->emitFunction(kVec3f_GrSLType,
"set_luminance",
SK_ARRAY_COUNT(setLumArgs), setLumArgs,
setLumBody.c_str(),
setLumFunction);
}
// Adds a function that creates a color with the hue and luminosity of one input color and
// the saturation of another color. It will have this signature:
// float set_saturation(vec3 hueLumColor, vec3 satColor)
static void add_sat_function(GrGLFragmentBuilder* fsBuilder, SkString* setSatFunction) {
// Emit a helper that gets the saturation of a color
SkString getFunction;
GrGLShaderVar getSatArgs[] = { GrGLShaderVar("color", kVec3f_GrSLType) };
SkString getSatBody;
getSatBody.printf("return max(max(color.r, color.g), color.b) - "
"min(min(color.r, color.g), color.b);");
fsBuilder->emitFunction(kFloat_GrSLType,
"saturation",
SK_ARRAY_COUNT(getSatArgs), getSatArgs,
getSatBody.c_str(),
&getFunction);
// Emit a helper that sets the saturation given sorted input channels. This used
// to use inout params for min, mid, and max components but that seems to cause
// problems on PowerVR drivers. So instead it returns a vec3 where r, g ,b are the
// adjusted min, mid, and max inputs, respectively.
SkString helperFunction;
GrGLShaderVar helperArgs[] = {
GrGLShaderVar("minComp", kFloat_GrSLType),
GrGLShaderVar("midComp", kFloat_GrSLType),
GrGLShaderVar("maxComp", kFloat_GrSLType),
GrGLShaderVar("sat", kFloat_GrSLType),
};
static const char kHelperBody[] = "if (minComp < maxComp) {"
"vec3 result;"
"result.r = 0.0;"
"result.g = sat * (midComp - minComp) / (maxComp - minComp);"
"result.b = sat;"
"return result;"
"} else {"
"return vec3(0, 0, 0);"
"}";
fsBuilder->emitFunction(kVec3f_GrSLType,
"set_saturation_helper",
SK_ARRAY_COUNT(helperArgs), helperArgs,
kHelperBody,
&helperFunction);
GrGLShaderVar setSatArgs[] = {
GrGLShaderVar("hueLumColor", kVec3f_GrSLType),
GrGLShaderVar("satColor", kVec3f_GrSLType),
};
const char* helpFunc = helperFunction.c_str();
SkString setSatBody;
setSatBody.appendf("float sat = %s(satColor);"
"if (hueLumColor.r <= hueLumColor.g) {"
"if (hueLumColor.g <= hueLumColor.b) {"
"hueLumColor.rgb = %s(hueLumColor.r, hueLumColor.g, hueLumColor.b, sat);"
"} else if (hueLumColor.r <= hueLumColor.b) {"
"hueLumColor.rbg = %s(hueLumColor.r, hueLumColor.b, hueLumColor.g, sat);"
"} else {"
"hueLumColor.brg = %s(hueLumColor.b, hueLumColor.r, hueLumColor.g, sat);"
"}"
"} else if (hueLumColor.r <= hueLumColor.b) {"
"hueLumColor.grb = %s(hueLumColor.g, hueLumColor.r, hueLumColor.b, sat);"
"} else if (hueLumColor.g <= hueLumColor.b) {"
"hueLumColor.gbr = %s(hueLumColor.g, hueLumColor.b, hueLumColor.r, sat);"
"} else {"
"hueLumColor.bgr = %s(hueLumColor.b, hueLumColor.g, hueLumColor.r, sat);"
"}"
"return hueLumColor;",
getFunction.c_str(), helpFunc, helpFunc, helpFunc, helpFunc,
helpFunc, helpFunc);
fsBuilder->emitFunction(kVec3f_GrSLType,
"set_saturation",
SK_ARRAY_COUNT(setSatArgs), setSatArgs,
setSatBody.c_str(),
setSatFunction);
}
static void emit_custom_xfermode_code(SkXfermode::Mode mode,
GrGLFragmentBuilder* fsBuilder,
const char* outputColor,
const char* inputColor,
const char* dstColor) {
// We don't try to optimize for this case at all
if (nullptr == inputColor) {
fsBuilder->codeAppendf("const vec4 ones = vec4(1);");
inputColor = "ones";
}
fsBuilder->codeAppendf("// SkXfermode::Mode: %s\n", SkXfermode::ModeName(mode));
// These all perform src-over on the alpha channel.
fsBuilder->codeAppendf("%s.a = %s.a + (1.0 - %s.a) * %s.a;",
outputColor, inputColor, inputColor, dstColor);
switch (mode) {
case SkXfermode::kOverlay_Mode:
// Overlay is Hard-Light with the src and dst reversed
hard_light(fsBuilder, outputColor, dstColor, inputColor);
break;
case SkXfermode::kDarken_Mode:
fsBuilder->codeAppendf("%s.rgb = min((1.0 - %s.a) * %s.rgb + %s.rgb, "
"(1.0 - %s.a) * %s.rgb + %s.rgb);",
outputColor,
inputColor, dstColor, inputColor,
dstColor, inputColor, dstColor);
break;
case SkXfermode::kLighten_Mode:
fsBuilder->codeAppendf("%s.rgb = max((1.0 - %s.a) * %s.rgb + %s.rgb, "
"(1.0 - %s.a) * %s.rgb + %s.rgb);",
outputColor,
inputColor, dstColor, inputColor,
dstColor, inputColor, dstColor);
break;
case SkXfermode::kColorDodge_Mode:
color_dodge_component(fsBuilder, outputColor, inputColor, dstColor, 'r');
color_dodge_component(fsBuilder, outputColor, inputColor, dstColor, 'g');
color_dodge_component(fsBuilder, outputColor, inputColor, dstColor, 'b');
break;
case SkXfermode::kColorBurn_Mode:
color_burn_component(fsBuilder, outputColor, inputColor, dstColor, 'r');
color_burn_component(fsBuilder, outputColor, inputColor, dstColor, 'g');
color_burn_component(fsBuilder, outputColor, inputColor, dstColor, 'b');
break;
case SkXfermode::kHardLight_Mode:
hard_light(fsBuilder, outputColor, inputColor, dstColor);
break;
case SkXfermode::kSoftLight_Mode:
fsBuilder->codeAppendf("if (0.0 == %s.a) {", dstColor);
fsBuilder->codeAppendf("%s.rgba = %s;", outputColor, inputColor);
fsBuilder->codeAppendf("} else {");
soft_light_component_pos_dst_alpha(fsBuilder, outputColor, inputColor, dstColor, 'r');
soft_light_component_pos_dst_alpha(fsBuilder, outputColor, inputColor, dstColor, 'g');
soft_light_component_pos_dst_alpha(fsBuilder, outputColor, inputColor, dstColor, 'b');
fsBuilder->codeAppendf("}");
break;
case SkXfermode::kDifference_Mode:
fsBuilder->codeAppendf("%s.rgb = %s.rgb + %s.rgb -"
"2.0 * min(%s.rgb * %s.a, %s.rgb * %s.a);",
outputColor, inputColor, dstColor, inputColor, dstColor,
dstColor, inputColor);
break;
case SkXfermode::kExclusion_Mode:
fsBuilder->codeAppendf("%s.rgb = %s.rgb + %s.rgb - "
"2.0 * %s.rgb * %s.rgb;",
outputColor, dstColor, inputColor, dstColor, inputColor);
break;
case SkXfermode::kMultiply_Mode:
fsBuilder->codeAppendf("%s.rgb = (1.0 - %s.a) * %s.rgb + "
"(1.0 - %s.a) * %s.rgb + "
"%s.rgb * %s.rgb;",
outputColor, inputColor, dstColor, dstColor, inputColor,
inputColor, dstColor);
break;
case SkXfermode::kHue_Mode: {
// SetLum(SetSat(S * Da, Sat(D * Sa)), Sa*Da, D*Sa) + (1 - Sa) * D + (1 - Da) * S
SkString setSat, setLum;
add_sat_function(fsBuilder, &setSat);
add_lum_function(fsBuilder, &setLum);
fsBuilder->codeAppendf("vec4 dstSrcAlpha = %s * %s.a;",
dstColor, inputColor);
fsBuilder->codeAppendf("%s.rgb = %s(%s(%s.rgb * %s.a, dstSrcAlpha.rgb),"
"dstSrcAlpha.a, dstSrcAlpha.rgb);",
outputColor, setLum.c_str(), setSat.c_str(), inputColor,
dstColor);
fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;",
outputColor, inputColor, dstColor, dstColor, inputColor);
break;
}
case SkXfermode::kSaturation_Mode: {
// SetLum(SetSat(D * Sa, Sat(S * Da)), Sa*Da, D*Sa)) + (1 - Sa) * D + (1 - Da) * S
SkString setSat, setLum;
add_sat_function(fsBuilder, &setSat);
add_lum_function(fsBuilder, &setLum);
fsBuilder->codeAppendf("vec4 dstSrcAlpha = %s * %s.a;",
dstColor, inputColor);
fsBuilder->codeAppendf("%s.rgb = %s(%s(dstSrcAlpha.rgb, %s.rgb * %s.a),"
"dstSrcAlpha.a, dstSrcAlpha.rgb);",
outputColor, setLum.c_str(), setSat.c_str(), inputColor,
dstColor);
fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;",
outputColor, inputColor, dstColor, dstColor, inputColor);
break;
}
case SkXfermode::kColor_Mode: {
// SetLum(S * Da, Sa* Da, D * Sa) + (1 - Sa) * D + (1 - Da) * S
SkString setLum;
add_lum_function(fsBuilder, &setLum);
fsBuilder->codeAppendf("vec4 srcDstAlpha = %s * %s.a;",
inputColor, dstColor);
fsBuilder->codeAppendf("%s.rgb = %s(srcDstAlpha.rgb, srcDstAlpha.a, %s.rgb * %s.a);",
outputColor, setLum.c_str(), dstColor, inputColor);
fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;",
outputColor, inputColor, dstColor, dstColor, inputColor);
break;
}
case SkXfermode::kLuminosity_Mode: {
// SetLum(D * Sa, Sa* Da, S * Da) + (1 - Sa) * D + (1 - Da) * S
SkString setLum;
add_lum_function(fsBuilder, &setLum);
fsBuilder->codeAppendf("vec4 srcDstAlpha = %s * %s.a;",
inputColor, dstColor);
fsBuilder->codeAppendf("%s.rgb = %s(%s.rgb * %s.a, srcDstAlpha.a, srcDstAlpha.rgb);",
outputColor, setLum.c_str(), dstColor, inputColor);
fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;",
outputColor, inputColor, dstColor, dstColor, inputColor);
break;
}
default:
SkFAIL("Unknown Custom Xfer mode.");
break;
}
}
///////////////////////////////////////////////////////////////////////////////
// Fragment Processor
///////////////////////////////////////////////////////////////////////////////
GrFragmentProcessor* GrCustomXfermode::CreateFP(GrProcessorDataManager* procDataManager,
SkXfermode::Mode mode, GrTexture* background) {
if (!GrCustomXfermode::IsSupportedMode(mode)) {
return nullptr;
} else {
return new GrCustomXferFP(procDataManager, mode, background);
}
}
///////////////////////////////////////////////////////////////////////////////
class GLCustomXferFP : public GrGLFragmentProcessor {
public:
GLCustomXferFP(const GrFragmentProcessor&) {}
~GLCustomXferFP() override {};
void emitCode(EmitArgs& args) override {
SkXfermode::Mode mode = args.fFp.cast<GrCustomXferFP>().mode();
GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();
const char* dstColor = "bgColor";
fsBuilder->codeAppendf("vec4 %s = ", dstColor);
fsBuilder->appendTextureLookup(args.fSamplers[0], args.fCoords[0].c_str(),
args.fCoords[0].getType());
fsBuilder->codeAppendf(";");
emit_custom_xfermode_code(mode, fsBuilder, args.fOutputColor, args.fInputColor, dstColor);
}
static void GenKey(const GrFragmentProcessor& proc, const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
// The background may come from the dst or from a texture.
uint32_t key = proc.numTextures();
SkASSERT(key <= 1);
key |= proc.cast<GrCustomXferFP>().mode() << 1;
b->add32(key);
}
protected:
void onSetData(const GrGLProgramDataManager&, const GrProcessor&) override {}
private:
typedef GrGLFragmentProcessor INHERITED;
};
///////////////////////////////////////////////////////////////////////////////
GrCustomXferFP::GrCustomXferFP(GrProcessorDataManager*, SkXfermode::Mode mode, GrTexture* background)
: fMode(mode) {
this->initClassID<GrCustomXferFP>();
SkASSERT(background);
fBackgroundTransform.reset(kLocal_GrCoordSet, background,
GrTextureParams::kNone_FilterMode);
this->addCoordTransform(&fBackgroundTransform);
fBackgroundAccess.reset(background);
this->addTextureAccess(&fBackgroundAccess);
}
void GrCustomXferFP::onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const {
GLCustomXferFP::GenKey(*this, caps, b);
}
GrGLFragmentProcessor* GrCustomXferFP::onCreateGLInstance() const {
return new GLCustomXferFP(*this);
}
bool GrCustomXferFP::onIsEqual(const GrFragmentProcessor& other) const {
const GrCustomXferFP& s = other.cast<GrCustomXferFP>();
return fMode == s.fMode;
}
void GrCustomXferFP::onComputeInvariantOutput(GrInvariantOutput* inout) const {
inout->setToUnknown(GrInvariantOutput::kWill_ReadInput);
}
GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrCustomXferFP);
const GrFragmentProcessor* GrCustomXferFP::TestCreate(GrProcessorTestData* d) {
int mode = d->fRandom->nextRangeU(SkXfermode::kLastCoeffMode + 1, SkXfermode::kLastSeparableMode);
return new GrCustomXferFP(d->fProcDataManager, static_cast<SkXfermode::Mode>(mode),
d->fTextures[0]);
}
///////////////////////////////////////////////////////////////////////////////
// Xfer Processor
///////////////////////////////////////////////////////////////////////////////
@ -567,16 +121,6 @@ private:
///////////////////////////////////////////////////////////////////////////////
GrXPFactory* GrCustomXfermode::CreateXPFactory(SkXfermode::Mode mode) {
if (!GrCustomXfermode::IsSupportedMode(mode)) {
return nullptr;
} else {
return new GrCustomXPFactory(mode);
}
}
///////////////////////////////////////////////////////////////////////////////
class GLCustomXP : public GrGLXferProcessor {
public:
GLCustomXP(const GrXferProcessor&) {}
@ -621,7 +165,7 @@ private:
SkASSERT(!xp.hasHWBlendEquation());
GrGLXPFragmentBuilder* fsBuilder = pb->getFragmentShaderBuilder();
emit_custom_xfermode_code(xp.mode(), fsBuilder, outColor, srcColor, dstColor);
GrGLSLBlend::AppendMode(fsBuilder, srcColor, dstColor, outColor, xp.mode());
}
void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) override {}
@ -770,20 +314,54 @@ void CustomXP::onGetBlendInfo(BlendInfo* blendInfo) const {
}
///////////////////////////////////////////////////////////////////////////////
class CustomXPFactory : public GrXPFactory {
public:
CustomXPFactory(SkXfermode::Mode mode);
GrCustomXPFactory::GrCustomXPFactory(SkXfermode::Mode mode)
bool supportsRGBCoverage(GrColor knownColor, uint32_t knownColorFlags) const override {
return true;
}
void getInvariantBlendedColor(const GrProcOptInfo& colorPOI,
GrXPFactory::InvariantBlendedColor*) const override;
private:
GrXferProcessor* onCreateXferProcessor(const GrCaps& caps,
const GrProcOptInfo& colorPOI,
const GrProcOptInfo& coveragePOI,
bool hasMixedSamples,
const DstTexture*) const override;
bool willReadDstColor(const GrCaps& caps,
const GrProcOptInfo& colorPOI,
const GrProcOptInfo& coveragePOI,
bool hasMixedSamples) const override;
bool onIsEqual(const GrXPFactory& xpfBase) const override {
const CustomXPFactory& xpf = xpfBase.cast<CustomXPFactory>();
return fMode == xpf.fMode;
}
GR_DECLARE_XP_FACTORY_TEST;
SkXfermode::Mode fMode;
GrBlendEquation fHWBlendEquation;
typedef GrXPFactory INHERITED;
};
CustomXPFactory::CustomXPFactory(SkXfermode::Mode mode)
: fMode(mode),
fHWBlendEquation(hw_blend_equation(mode)) {
SkASSERT(GrCustomXfermode::IsSupportedMode(fMode));
this->initClassID<GrCustomXPFactory>();
this->initClassID<CustomXPFactory>();
}
GrXferProcessor*
GrCustomXPFactory::onCreateXferProcessor(const GrCaps& caps,
const GrProcOptInfo& colorPOI,
const GrProcOptInfo& coveragePOI,
bool hasMixedSamples,
const DstTexture* dstTexture) const {
GrXferProcessor* CustomXPFactory::onCreateXferProcessor(const GrCaps& caps,
const GrProcOptInfo& colorPOI,
const GrProcOptInfo& coveragePOI,
bool hasMixedSamples,
const DstTexture* dstTexture) const {
if (can_use_hw_blend_equation(fHWBlendEquation, coveragePOI, caps)) {
SkASSERT(!dstTexture || !dstTexture->texture());
return new CustomXP(fMode, fHWBlendEquation);
@ -791,24 +369,33 @@ GrCustomXPFactory::onCreateXferProcessor(const GrCaps& caps,
return new CustomXP(dstTexture, hasMixedSamples, fMode);
}
bool GrCustomXPFactory::willReadDstColor(const GrCaps& caps,
const GrProcOptInfo& colorPOI,
const GrProcOptInfo& coveragePOI,
bool hasMixedSamples) const {
bool CustomXPFactory::willReadDstColor(const GrCaps& caps,
const GrProcOptInfo& colorPOI,
const GrProcOptInfo& coveragePOI,
bool hasMixedSamples) const {
return !can_use_hw_blend_equation(fHWBlendEquation, coveragePOI, caps);
}
void GrCustomXPFactory::getInvariantBlendedColor(const GrProcOptInfo& colorPOI,
InvariantBlendedColor* blendedColor) const {
void CustomXPFactory::getInvariantBlendedColor(const GrProcOptInfo& colorPOI,
InvariantBlendedColor* blendedColor) const {
blendedColor->fWillBlendWithDst = true;
blendedColor->fKnownColorFlags = kNone_GrColorComponentFlags;
}
GR_DEFINE_XP_FACTORY_TEST(GrCustomXPFactory);
const GrXPFactory* GrCustomXPFactory::TestCreate(GrProcessorTestData* d) {
GR_DEFINE_XP_FACTORY_TEST(CustomXPFactory);
const GrXPFactory* CustomXPFactory::TestCreate(GrProcessorTestData* d) {
int mode = d->fRandom->nextRangeU(SkXfermode::kLastCoeffMode + 1,
SkXfermode::kLastSeparableMode);
return new GrCustomXPFactory(static_cast<SkXfermode::Mode>(mode));
return new CustomXPFactory(static_cast<SkXfermode::Mode>(mode));
}
///////////////////////////////////////////////////////////////////////////////
GrXPFactory* GrCustomXfermode::CreateXPFactory(SkXfermode::Mode mode) {
if (!GrCustomXfermode::IsSupportedMode(mode)) {
return nullptr;
} else {
return new CustomXPFactory(mode);
}
}

View File

@ -1,95 +0,0 @@
/*
* Copyright 2015 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef GrCustomXfermodePriv_DEFINED
#define GrCustomXfermodePriv_DEFINED
#include "GrCaps.h"
#include "GrCoordTransform.h"
#include "GrFragmentProcessor.h"
#include "GrTextureAccess.h"
#include "GrXferProcessor.h"
#include "SkXfermode.h"
class GrGLCaps;
class GrGLFragmentProcessor;
class GrInvariantOutput;
class GrProcessorKeyBuilder;
class GrTexture;
///////////////////////////////////////////////////////////////////////////////
// Fragment Processor
///////////////////////////////////////////////////////////////////////////////
class GrCustomXferFP : public GrFragmentProcessor {
public:
GrCustomXferFP(GrProcessorDataManager*, SkXfermode::Mode mode, GrTexture* background);
const char* name() const override { return "Custom Xfermode"; }
SkXfermode::Mode mode() const { return fMode; }
const GrTextureAccess& backgroundAccess() const { return fBackgroundAccess; }
private:
GrGLFragmentProcessor* onCreateGLInstance() const override;
void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
bool onIsEqual(const GrFragmentProcessor& other) const override;
void onComputeInvariantOutput(GrInvariantOutput* inout) const override;
GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
SkXfermode::Mode fMode;
GrCoordTransform fBackgroundTransform;
GrTextureAccess fBackgroundAccess;
typedef GrFragmentProcessor INHERITED;
};
///////////////////////////////////////////////////////////////////////////////
// Xfer Processor
///////////////////////////////////////////////////////////////////////////////
class GrCustomXPFactory : public GrXPFactory {
public:
GrCustomXPFactory(SkXfermode::Mode mode);
bool supportsRGBCoverage(GrColor knownColor, uint32_t knownColorFlags) const override {
return true;
}
void getInvariantBlendedColor(const GrProcOptInfo& colorPOI,
GrXPFactory::InvariantBlendedColor*) const override;
private:
GrXferProcessor* onCreateXferProcessor(const GrCaps& caps,
const GrProcOptInfo& colorPOI,
const GrProcOptInfo& coveragePOI,
bool hasMixedSamples,
const DstTexture*) const override;
bool willReadDstColor(const GrCaps& caps,
const GrProcOptInfo& colorPOI,
const GrProcOptInfo& coveragePOI,
bool hasMixedSamples) const override;
bool onIsEqual(const GrXPFactory& xpfBase) const override {
const GrCustomXPFactory& xpf = xpfBase.cast<GrCustomXPFactory>();
return fMode == xpf.fMode;
}
GR_DECLARE_XP_FACTORY_TEST;
SkXfermode::Mode fMode;
GrBlendEquation fHWBlendEquation;
typedef GrXPFactory INHERITED;
};
#endif

View File

@ -13,7 +13,7 @@
#include "GrProcOptInfo.h"
#include "GrTypes.h"
#include "GrXferProcessor.h"
#include "gl/GrGLBlend.h"
#include "gl/GrGLSLBlend.h"
#include "gl/GrGLXferProcessor.h"
#include "gl/builders/GrGLFragmentShaderBuilder.h"
#include "gl/builders/GrGLProgramBuilder.h"
@ -547,7 +547,7 @@ private:
const ShaderPDXferProcessor& xp = proc.cast<ShaderPDXferProcessor>();
GrGLXPFragmentBuilder* fsBuilder = pb->getFragmentShaderBuilder();
GrGLBlend::AppendPorterDuffBlend(fsBuilder, srcColor, dstColor, outColor, xp.getXfermode());
GrGLSLBlend::AppendMode(fsBuilder, srcColor, dstColor, outColor, xp.getXfermode());
}
void onSetData(const GrGLProgramDataManager&, const GrXferProcessor&) override {}
@ -651,7 +651,7 @@ GrXferProcessor* PDLCDXferProcessor::Create(SkXfermode::Mode xfermode,
return nullptr;
}
GrColor blendConstant = GrUnPreMulColor(colorPOI.color());
GrColor blendConstant = GrUnpremulColor(colorPOI.color());
uint8_t alpha = GrColorUnpackA(blendConstant);
blendConstant |= (0xff << GrColor_SHIFT_A);

View File

@ -15,18 +15,16 @@ class GrInvariantOutput;
/**
* The output color of this effect is a modulation of the input color and a sample from a texture.
* It allows explicit specification of the filtering and wrap modes (GrTextureParams). It can use
* local coords, positions, or a custom vertex attribute as input texture coords. The input coords
* can have a matrix applied in the VS in both the local and position cases but not with a custom
* attribute coords at this time. It will add a varying to input interpolate texture coords to the
* FS.
* local coords or device space coords as input texture coords. The input coords may be transformed
* by a matrix.
*/
class GrSimpleTextureEffect : public GrSingleTextureEffect {
public:
/* unfiltered, clamp mode */
static GrFragmentProcessor* Create(GrProcessorDataManager* procDataManager,
GrTexture* tex,
const SkMatrix& matrix,
GrCoordSet coordSet = kLocal_GrCoordSet) {
static const GrFragmentProcessor* Create(GrProcessorDataManager* procDataManager,
GrTexture* tex,
const SkMatrix& matrix,
GrCoordSet coordSet = kLocal_GrCoordSet) {
return new GrSimpleTextureEffect(procDataManager, tex, matrix,
GrTextureParams::kNone_FilterMode, coordSet);
}

View File

@ -9,25 +9,23 @@
#include "GrFragmentProcessor.h"
#include "effects/GrConstColorProcessor.h"
#include "gl/GrGLBlend.h"
#include "gl/GrGLSLBlend.h"
#include "gl/builders/GrGLProgramBuilder.h"
#include "SkGr.h"
class GrComposeTwoFragmentProcessor : public GrFragmentProcessor {
class ComposeTwoFragmentProcessor : public GrFragmentProcessor {
public:
GrComposeTwoFragmentProcessor(const GrFragmentProcessor* src, const GrFragmentProcessor* dst,
ComposeTwoFragmentProcessor(const GrFragmentProcessor* src, const GrFragmentProcessor* dst,
SkXfermode::Mode mode)
: fMode(mode) {
// Only coefficient xfer modes are supported
SkASSERT(SkXfermode::kLastCoeffMode >= mode);
this->initClassID<GrComposeTwoFragmentProcessor>();
this->initClassID<ComposeTwoFragmentProcessor>();
SkDEBUGCODE(int shaderAChildIndex = )this->registerChildProcessor(src);
SkDEBUGCODE(int shaderBChildIndex = )this->registerChildProcessor(dst);
SkASSERT(0 == shaderAChildIndex);
SkASSERT(1 == shaderBChildIndex);
}
const char* name() const override { return "ComposeShader"; }
const char* name() const override { return "ComposeTwo"; }
void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override {
b->add32(fMode);
@ -37,7 +35,7 @@ public:
protected:
bool onIsEqual(const GrFragmentProcessor& other) const override {
const GrComposeTwoFragmentProcessor& cs = other.cast<GrComposeTwoFragmentProcessor>();
const ComposeTwoFragmentProcessor& cs = other.cast<ComposeTwoFragmentProcessor>();
return fMode == cs.fMode;
}
@ -57,9 +55,9 @@ private:
/////////////////////////////////////////////////////////////////////
class GrGLComposeTwoFragmentProcessor : public GrGLFragmentProcessor {
class GLComposeTwoFragmentProcessor : public GrGLFragmentProcessor {
public:
GrGLComposeTwoFragmentProcessor(const GrProcessor& processor) {}
GLComposeTwoFragmentProcessor(const GrProcessor& processor) {}
void emitCode(EmitArgs&) override;
@ -69,28 +67,28 @@ private:
/////////////////////////////////////////////////////////////////////
GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrComposeTwoFragmentProcessor);
GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ComposeTwoFragmentProcessor);
const GrFragmentProcessor* GrComposeTwoFragmentProcessor::TestCreate(GrProcessorTestData* d) {
const GrFragmentProcessor* ComposeTwoFragmentProcessor::TestCreate(GrProcessorTestData* d) {
// Create two random frag procs.
SkAutoTUnref<const GrFragmentProcessor> fpA(GrProcessorUnitTest::CreateChildFP(d));
SkAutoTUnref<const GrFragmentProcessor> fpB(GrProcessorUnitTest::CreateChildFP(d));
SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(
d->fRandom->nextRangeU(0, SkXfermode::kLastCoeffMode));
return SkNEW_ARGS(GrComposeTwoFragmentProcessor, (fpA, fpB, mode));
d->fRandom->nextRangeU(0, SkXfermode::kLastMode));
return new ComposeTwoFragmentProcessor(fpA, fpB, mode);
}
GrGLFragmentProcessor* GrComposeTwoFragmentProcessor::onCreateGLInstance() const{
return SkNEW_ARGS(GrGLComposeTwoFragmentProcessor, (*this));
GrGLFragmentProcessor* ComposeTwoFragmentProcessor::onCreateGLInstance() const{
return new GLComposeTwoFragmentProcessor(*this);
}
/////////////////////////////////////////////////////////////////////
void GrGLComposeTwoFragmentProcessor::emitCode(EmitArgs& args) {
void GLComposeTwoFragmentProcessor::emitCode(EmitArgs& args) {
GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();
const GrComposeTwoFragmentProcessor& cs = args.fFp.cast<GrComposeTwoFragmentProcessor>();
const ComposeTwoFragmentProcessor& cs = args.fFp.cast<ComposeTwoFragmentProcessor>();
// Store alpha of input color and un-premultiply the input color by its alpha. We will
// re-multiply by this alpha after blending the output colors of the two child procs.
@ -122,8 +120,8 @@ void GrGLComposeTwoFragmentProcessor::emitCode(EmitArgs& args) {
SkXfermode::Mode mode = cs.getMode();
fsBuilder->codeAppend("{");
fsBuilder->codeAppendf("// Compose Xfer Mode: %s\n", SkXfermode::ModeName(mode));
GrGLBlend::AppendPorterDuffBlend(fsBuilder, outputColorSrc.c_str(),
outputColorDst.c_str(), args.fOutputColor, mode);
GrGLSLBlend::AppendMode(fsBuilder, outputColorSrc.c_str(),
outputColorDst.c_str(), args.fOutputColor, mode);
fsBuilder->codeAppend("}");
// re-multiply the output color by the input color's alpha
@ -134,21 +132,184 @@ void GrGLComposeTwoFragmentProcessor::emitCode(EmitArgs& args) {
const GrFragmentProcessor* GrXfermodeFragmentProcessor::CreateFromTwoProcessors(
const GrFragmentProcessor* src, const GrFragmentProcessor* dst, SkXfermode::Mode mode) {
if (SkXfermode::kLastCoeffMode < mode) {
return nullptr;
}
switch (mode) {
case SkXfermode::kClear_Mode:
return GrConstColorProcessor::Create(GrColor_TRANS_BLACK,
return GrConstColorProcessor::Create(GrColor_TRANSPARENT_BLACK,
GrConstColorProcessor::kIgnore_InputMode);
break;
case SkXfermode::kSrc_Mode:
return SkRef(src);
break;
case SkXfermode::kDst_Mode:
return SkRef(dst);
break;
default:
return new GrComposeTwoFragmentProcessor(src, dst, mode);
return new ComposeTwoFragmentProcessor(src, dst, mode);
}
}
//////////////////////////////////////////////////////////////////////////////
class ComposeOneFragmentProcessor : public GrFragmentProcessor {
public:
enum Child {
kDst_Child,
kSrc_Child,
};
ComposeOneFragmentProcessor(const GrFragmentProcessor* dst, SkXfermode::Mode mode, Child child)
: fMode(mode)
, fChild(child) {
this->initClassID<ComposeOneFragmentProcessor>();
SkDEBUGCODE(int dstIndex = )this->registerChildProcessor(dst);
SkASSERT(0 == dstIndex);
}
const char* name() const override { return "ComposeOne"; }
void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override {
GR_STATIC_ASSERT((SkXfermode::kLastMode & SK_MaxU16) == SkXfermode::kLastMode);
b->add32(fMode | (fChild << 16));
}
SkXfermode::Mode mode() const { return fMode; }
Child child() const { return fChild; }
protected:
bool onIsEqual(const GrFragmentProcessor& that) const override {
return fMode == that.cast<ComposeOneFragmentProcessor>().fMode;
}
void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
SkXfermode::Coeff skSrcCoeff, skDstCoeff;
if (SkXfermode::ModeAsCoeff(fMode, &skSrcCoeff, &skDstCoeff)) {
GrBlendCoeff srcCoeff = SkXfermodeCoeffToGrBlendCoeff(skSrcCoeff);
GrBlendCoeff dstCoeff = SkXfermodeCoeffToGrBlendCoeff(skDstCoeff);
GrInvariantOutput childOutput(0xFFFFFFFF, kRGBA_GrColorComponentFlags, false);
this->childProcessor(0).computeInvariantOutput(&childOutput);
GrColor blendColor;
GrColorComponentFlags blendFlags;
if (kDst_Child == fChild) {
GrGetCoeffBlendKnownComponents(srcCoeff, dstCoeff,
inout->color(), inout->validFlags(),
childOutput.color(), childOutput.validFlags(),
&blendColor, &blendFlags);
} else {
GrGetCoeffBlendKnownComponents(srcCoeff, dstCoeff,
childOutput.color(), childOutput.validFlags(),
inout->color(), inout->validFlags(),
&blendColor, &blendFlags);
}
// will the shader code reference the input color?
GrInvariantOutput::ReadInput readsInput = GrInvariantOutput::kWillNot_ReadInput;
if (kDst_Child == fChild) {
if (kZero_GrBlendCoeff != srcCoeff || GrBlendCoeffRefsSrc(dstCoeff)) {
readsInput = GrInvariantOutput::kWill_ReadInput;
}
} else {
if (kZero_GrBlendCoeff != dstCoeff || GrBlendCoeffRefsDst(srcCoeff)) {
readsInput = GrInvariantOutput::kWill_ReadInput;
}
}
inout->setToOther(blendFlags, blendColor, readsInput);
} else {
inout->setToUnknown(GrInvariantOutput::kWill_ReadInput);
}
}
private:
GrGLFragmentProcessor* onCreateGLInstance() const override;
SkXfermode::Mode fMode;
Child fChild;
GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
typedef GrFragmentProcessor INHERITED;
};
//////////////////////////////////////////////////////////////////////////////
class GLComposeOneFragmentProcessor : public GrGLFragmentProcessor {
public:
GLComposeOneFragmentProcessor(const GrProcessor& processor) {}
void emitCode(EmitArgs& args) override {
GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();
SkXfermode::Mode mode = args.fFp.cast<ComposeOneFragmentProcessor>().mode();
ComposeOneFragmentProcessor::Child child =
args.fFp.cast<ComposeOneFragmentProcessor>().child();
// declare _dstColor and emit the code for the two child
fsBuilder->codeAppendf("vec4 _child;");
this->emitChild(0, nullptr, "_child", args);
const char* inputColor = args.fInputColor;
// We don't try to optimize for this case at all
if (!inputColor) {
fsBuilder->codeAppendf("const vec4 ones = vec4(1);");
inputColor = "ones";
}
// emit blend code
fsBuilder->codeAppend("{");
fsBuilder->codeAppendf("// Compose Xfer Mode: %s\n", SkXfermode::ModeName(mode));
if (ComposeOneFragmentProcessor::kDst_Child == child) {
GrGLSLBlend::AppendMode(fsBuilder, inputColor, "_child", args.fOutputColor, mode);
} else {
GrGLSLBlend::AppendMode(fsBuilder, "_child", inputColor, args.fOutputColor, mode);
}
fsBuilder->codeAppend("}");
}
private:
typedef GrGLFragmentProcessor INHERITED;
};
/////////////////////////////////////////////////////////////////////
GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ComposeOneFragmentProcessor);
const GrFragmentProcessor* ComposeOneFragmentProcessor::TestCreate(GrProcessorTestData* d) {
// Create one random frag procs.
// For now, we'll prevent either children from being a shader with children to prevent the
// possibility of an arbitrarily large tree of procs.
SkAutoTUnref<const GrFragmentProcessor> dst(GrProcessorUnitTest::CreateChildFP(d));
SkXfermode::Mode mode = static_cast<SkXfermode::Mode>(
d->fRandom->nextRangeU(0, SkXfermode::kLastMode));
ComposeOneFragmentProcessor::Child child = d->fRandom->nextBool() ?
ComposeOneFragmentProcessor::kDst_Child :
ComposeOneFragmentProcessor::kSrc_Child;
return new ComposeOneFragmentProcessor(dst, mode, child);
}
GrGLFragmentProcessor* ComposeOneFragmentProcessor::onCreateGLInstance() const {
return new GLComposeOneFragmentProcessor(*this);
}
//////////////////////////////////////////////////////////////////////////////
const GrFragmentProcessor* GrXfermodeFragmentProcessor::CreateFromDstProcessor(
const GrFragmentProcessor* dst, SkXfermode::Mode mode) {
switch (mode) {
case SkXfermode::kClear_Mode:
return GrConstColorProcessor::Create(GrColor_TRANSPARENT_BLACK,
GrConstColorProcessor::kIgnore_InputMode);
case SkXfermode::kSrc_Mode:
return nullptr;
default:
return new ComposeOneFragmentProcessor(dst, mode,
ComposeOneFragmentProcessor::kDst_Child);
}
}
const GrFragmentProcessor* GrXfermodeFragmentProcessor::CreateFromSrcProcessor(
const GrFragmentProcessor* src, SkXfermode::Mode mode) {
switch (mode) {
case SkXfermode::kClear_Mode:
return GrConstColorProcessor::Create(GrColor_TRANSPARENT_BLACK,
GrConstColorProcessor::kIgnore_InputMode);
case SkXfermode::kDst_Mode:
return nullptr;
default:
return new ComposeOneFragmentProcessor(src, mode,
ComposeOneFragmentProcessor::kSrc_Child);
}
}

View File

@ -1,70 +0,0 @@
/*
* 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 "GrGLBlend.h"
#include "gl/builders/GrGLFragmentShaderBuilder.h"
static bool append_porterduff_term(GrGLFragmentBuilder* 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;
}
}
void GrGLBlend::AppendPorterDuffBlend(GrGLFragmentBuilder* fsBuilder, const char* srcColor,
const char* dstColor, const char* outColor,
SkXfermode::Mode mode) {
SkXfermode::Coeff srcCoeff, dstCoeff;
SkXfermode::ModeAsCoeff(mode, &srcCoeff, &dstCoeff);
fsBuilder->codeAppendf("%s = ", outColor);
// append src blend
bool didAppend = append_porterduff_term(fsBuilder, srcCoeff, srcColor, srcColor, dstColor,
false);
// append dst blend
if(!append_porterduff_term(fsBuilder, dstCoeff, dstColor, srcColor, dstColor, didAppend)) {
fsBuilder->codeAppend("vec4(0, 0, 0, 0)");
}
fsBuilder->codeAppend(";");
}

435
src/gpu/gl/GrGLSLBlend.cpp Normal file
View File

@ -0,0 +1,435 @@
/*
* 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 "GrGLSLBlend.h"
#include "gl/builders/GrGLFragmentShaderBuilder.h"
//////////////////////////////////////////////////////////////////////////////
// Advanced (non-coeff) blend helpers
//////////////////////////////////////////////////////////////////////////////
static void hard_light(GrGLFragmentBuilder* fsBuilder,
const char* final,
const char* src,
const char* dst) {
static const char kComponents[] = { 'r', 'g', 'b' };
for (size_t i = 0; i < SK_ARRAY_COUNT(kComponents); ++i) {
char component = kComponents[i];
fsBuilder->codeAppendf("if (2.0 * %s.%c <= %s.a) {", src, component, src);
fsBuilder->codeAppendf("%s.%c = 2.0 * %s.%c * %s.%c;",
final, component, src, component, dst, component);
fsBuilder->codeAppend("} else {");
fsBuilder->codeAppendf("%s.%c = %s.a * %s.a - 2.0 * (%s.a - %s.%c) * (%s.a - %s.%c);",
final, component, src, dst, dst, dst, component, src, src,
component);
fsBuilder->codeAppend("}");
}
fsBuilder->codeAppendf("%s.rgb += %s.rgb * (1.0 - %s.a) + %s.rgb * (1.0 - %s.a);",
final, src, dst, dst, src);
}
// Does one component of color-dodge
static void color_dodge_component(GrGLFragmentBuilder* fsBuilder,
const char* final,
const char* src,
const char* dst,
const char component) {
fsBuilder->codeAppendf("if (0.0 == %s.%c) {", dst, component);
fsBuilder->codeAppendf("%s.%c = %s.%c * (1.0 - %s.a);",
final, component, src, component, dst);
fsBuilder->codeAppend("} else {");
fsBuilder->codeAppendf("float d = %s.a - %s.%c;", src, src, component);
fsBuilder->codeAppend("if (0.0 == d) {");
fsBuilder->codeAppendf("%s.%c = %s.a * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);",
final, component, src, dst, src, component, dst, dst, component,
src);
fsBuilder->codeAppend("} else {");
fsBuilder->codeAppendf("d = min(%s.a, %s.%c * %s.a / d);",
dst, dst, component, src);
fsBuilder->codeAppendf("%s.%c = d * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);",
final, component, src, src, component, dst, dst, component, src);
fsBuilder->codeAppend("}");
fsBuilder->codeAppend("}");
}
// Does one component of color-burn
static void color_burn_component(GrGLFragmentBuilder* fsBuilder,
const char* final,
const char* src,
const char* dst,
const char component) {
fsBuilder->codeAppendf("if (%s.a == %s.%c) {", dst, dst, component);
fsBuilder->codeAppendf("%s.%c = %s.a * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);",
final, component, src, dst, src, component, dst, dst, component,
src);
fsBuilder->codeAppendf("} else if (0.0 == %s.%c) {", src, component);
fsBuilder->codeAppendf("%s.%c = %s.%c * (1.0 - %s.a);",
final, component, dst, component, src);
fsBuilder->codeAppend("} else {");
fsBuilder->codeAppendf("float d = max(0.0, %s.a - (%s.a - %s.%c) * %s.a / %s.%c);",
dst, dst, dst, component, src, src, component);
fsBuilder->codeAppendf("%s.%c = %s.a * d + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);",
final, component, src, src, component, dst, dst, component, src);
fsBuilder->codeAppend("}");
}
// Does one component of soft-light. Caller should have already checked that dst alpha > 0.
static void soft_light_component_pos_dst_alpha(GrGLFragmentBuilder* fsBuilder,
const char* final,
const char* src,
const char* dst,
const char component) {
// if (2S < Sa)
fsBuilder->codeAppendf("if (2.0 * %s.%c <= %s.a) {", src, component, src);
// (D^2 (Sa-2 S))/Da+(1-Da) S+D (-Sa+2 S+1)
fsBuilder->codeAppendf("%s.%c = (%s.%c*%s.%c*(%s.a - 2.0*%s.%c)) / %s.a +"
"(1.0 - %s.a) * %s.%c + %s.%c*(-%s.a + 2.0*%s.%c + 1.0);",
final, component, dst, component, dst, component, src, src,
component, dst, dst, src, component, dst, component, src, src,
component);
// else if (4D < Da)
fsBuilder->codeAppendf("} else if (4.0 * %s.%c <= %s.a) {",
dst, component, dst);
fsBuilder->codeAppendf("float DSqd = %s.%c * %s.%c;",
dst, component, dst, component);
fsBuilder->codeAppendf("float DCub = DSqd * %s.%c;", dst, component);
fsBuilder->codeAppendf("float DaSqd = %s.a * %s.a;", dst, dst);
fsBuilder->codeAppendf("float DaCub = DaSqd * %s.a;", dst);
// (Da^3 (-S)+Da^2 (S-D (3 Sa-6 S-1))+12 Da D^2 (Sa-2 S)-16 D^3 (Sa-2 S))/Da^2
fsBuilder->codeAppendf("%s.%c ="
"(DaSqd*(%s.%c - %s.%c * (3.0*%s.a - 6.0*%s.%c - 1.0)) +"
" 12.0*%s.a*DSqd*(%s.a - 2.0*%s.%c) - 16.0*DCub * (%s.a - 2.0*%s.%c) -"
" DaCub*%s.%c) / DaSqd;",
final, component, src, component, dst, component,
src, src, component, dst, src, src, component, src, src,
component, src, component);
fsBuilder->codeAppendf("} else {");
// -sqrt(Da * D) (Sa-2 S)-Da S+D (Sa-2 S+1)+S
fsBuilder->codeAppendf("%s.%c = %s.%c*(%s.a - 2.0*%s.%c + 1.0) + %s.%c -"
" sqrt(%s.a*%s.%c)*(%s.a - 2.0*%s.%c) - %s.a*%s.%c;",
final, component, dst, component, src, src, component, src, component,
dst, dst, component, src, src, component, dst, src, component);
fsBuilder->codeAppendf("}");
}
// Adds a function that takes two colors and an alpha as input. It produces a color with the
// hue and saturation of the first color, the luminosity of the second color, and the input
// alpha. It has this signature:
// vec3 set_luminance(vec3 hueSatColor, float alpha, vec3 lumColor).
static void add_lum_function(GrGLFragmentBuilder* fsBuilder, SkString* setLumFunction) {
// Emit a helper that gets the luminance of a color.
SkString getFunction;
GrGLShaderVar getLumArgs[] = {
GrGLShaderVar("color", kVec3f_GrSLType),
};
SkString getLumBody("return dot(vec3(0.3, 0.59, 0.11), color);");
fsBuilder->emitFunction(kFloat_GrSLType,
"luminance",
SK_ARRAY_COUNT(getLumArgs), getLumArgs,
getLumBody.c_str(),
&getFunction);
// Emit the set luminance function.
GrGLShaderVar setLumArgs[] = {
GrGLShaderVar("hueSat", kVec3f_GrSLType),
GrGLShaderVar("alpha", kFloat_GrSLType),
GrGLShaderVar("lumColor", kVec3f_GrSLType),
};
SkString setLumBody;
setLumBody.printf("float diff = %s(lumColor - hueSat);", getFunction.c_str());
setLumBody.append("vec3 outColor = hueSat + diff;");
setLumBody.appendf("float outLum = %s(outColor);", getFunction.c_str());
setLumBody.append("float minComp = min(min(outColor.r, outColor.g), outColor.b);"
"float maxComp = max(max(outColor.r, outColor.g), outColor.b);"
"if (minComp < 0.0 && outLum != minComp) {"
"outColor = outLum + ((outColor - vec3(outLum, outLum, outLum)) * outLum) /"
"(outLum - minComp);"
"}"
"if (maxComp > alpha && maxComp != outLum) {"
"outColor = outLum +"
"((outColor - vec3(outLum, outLum, outLum)) * (alpha - outLum)) /"
"(maxComp - outLum);"
"}"
"return outColor;");
fsBuilder->emitFunction(kVec3f_GrSLType,
"set_luminance",
SK_ARRAY_COUNT(setLumArgs), setLumArgs,
setLumBody.c_str(),
setLumFunction);
}
// Adds a function that creates a color with the hue and luminosity of one input color and
// the saturation of another color. It will have this signature:
// float set_saturation(vec3 hueLumColor, vec3 satColor)
static void add_sat_function(GrGLFragmentBuilder* fsBuilder, SkString* setSatFunction) {
// Emit a helper that gets the saturation of a color
SkString getFunction;
GrGLShaderVar getSatArgs[] = { GrGLShaderVar("color", kVec3f_GrSLType) };
SkString getSatBody;
getSatBody.printf("return max(max(color.r, color.g), color.b) - "
"min(min(color.r, color.g), color.b);");
fsBuilder->emitFunction(kFloat_GrSLType,
"saturation",
SK_ARRAY_COUNT(getSatArgs), getSatArgs,
getSatBody.c_str(),
&getFunction);
// Emit a helper that sets the saturation given sorted input channels. This used
// to use inout params for min, mid, and max components but that seems to cause
// problems on PowerVR drivers. So instead it returns a vec3 where r, g ,b are the
// adjusted min, mid, and max inputs, respectively.
SkString helperFunction;
GrGLShaderVar helperArgs[] = {
GrGLShaderVar("minComp", kFloat_GrSLType),
GrGLShaderVar("midComp", kFloat_GrSLType),
GrGLShaderVar("maxComp", kFloat_GrSLType),
GrGLShaderVar("sat", kFloat_GrSLType),
};
static const char kHelperBody[] = "if (minComp < maxComp) {"
"vec3 result;"
"result.r = 0.0;"
"result.g = sat * (midComp - minComp) / (maxComp - minComp);"
"result.b = sat;"
"return result;"
"} else {"
"return vec3(0, 0, 0);"
"}";
fsBuilder->emitFunction(kVec3f_GrSLType,
"set_saturation_helper",
SK_ARRAY_COUNT(helperArgs), helperArgs,
kHelperBody,
&helperFunction);
GrGLShaderVar setSatArgs[] = {
GrGLShaderVar("hueLumColor", kVec3f_GrSLType),
GrGLShaderVar("satColor", kVec3f_GrSLType),
};
const char* helpFunc = helperFunction.c_str();
SkString setSatBody;
setSatBody.appendf("float sat = %s(satColor);"
"if (hueLumColor.r <= hueLumColor.g) {"
"if (hueLumColor.g <= hueLumColor.b) {"
"hueLumColor.rgb = %s(hueLumColor.r, hueLumColor.g, hueLumColor.b, sat);"
"} else if (hueLumColor.r <= hueLumColor.b) {"
"hueLumColor.rbg = %s(hueLumColor.r, hueLumColor.b, hueLumColor.g, sat);"
"} else {"
"hueLumColor.brg = %s(hueLumColor.b, hueLumColor.r, hueLumColor.g, sat);"
"}"
"} else if (hueLumColor.r <= hueLumColor.b) {"
"hueLumColor.grb = %s(hueLumColor.g, hueLumColor.r, hueLumColor.b, sat);"
"} else if (hueLumColor.g <= hueLumColor.b) {"
"hueLumColor.gbr = %s(hueLumColor.g, hueLumColor.b, hueLumColor.r, sat);"
"} else {"
"hueLumColor.bgr = %s(hueLumColor.b, hueLumColor.g, hueLumColor.r, sat);"
"}"
"return hueLumColor;",
getFunction.c_str(), helpFunc, helpFunc, helpFunc, helpFunc,
helpFunc, helpFunc);
fsBuilder->emitFunction(kVec3f_GrSLType,
"set_saturation",
SK_ARRAY_COUNT(setSatArgs), setSatArgs,
setSatBody.c_str(),
setSatFunction);
}
static void emit_advanced_xfermode_code(GrGLFragmentBuilder* fsBuilder, const char* srcColor,
const char* dstColor, const char* outputColor,
SkXfermode::Mode mode) {
SkASSERT(srcColor);
SkASSERT(dstColor);
SkASSERT(outputColor);
// These all perform src-over on the alpha channel.
fsBuilder->codeAppendf("%s.a = %s.a + (1.0 - %s.a) * %s.a;",
outputColor, srcColor, srcColor, dstColor);
switch (mode) {
case SkXfermode::kOverlay_Mode:
// Overlay is Hard-Light with the src and dst reversed
hard_light(fsBuilder, outputColor, dstColor, srcColor);
break;
case SkXfermode::kDarken_Mode:
fsBuilder->codeAppendf("%s.rgb = min((1.0 - %s.a) * %s.rgb + %s.rgb, "
"(1.0 - %s.a) * %s.rgb + %s.rgb);",
outputColor,
srcColor, dstColor, srcColor,
dstColor, srcColor, dstColor);
break;
case SkXfermode::kLighten_Mode:
fsBuilder->codeAppendf("%s.rgb = max((1.0 - %s.a) * %s.rgb + %s.rgb, "
"(1.0 - %s.a) * %s.rgb + %s.rgb);",
outputColor,
srcColor, dstColor, srcColor,
dstColor, srcColor, dstColor);
break;
case SkXfermode::kColorDodge_Mode:
color_dodge_component(fsBuilder, outputColor, srcColor, dstColor, 'r');
color_dodge_component(fsBuilder, outputColor, srcColor, dstColor, 'g');
color_dodge_component(fsBuilder, outputColor, srcColor, dstColor, 'b');
break;
case SkXfermode::kColorBurn_Mode:
color_burn_component(fsBuilder, outputColor, srcColor, dstColor, 'r');
color_burn_component(fsBuilder, outputColor, srcColor, dstColor, 'g');
color_burn_component(fsBuilder, outputColor, srcColor, dstColor, 'b');
break;
case SkXfermode::kHardLight_Mode:
hard_light(fsBuilder, outputColor, srcColor, dstColor);
break;
case SkXfermode::kSoftLight_Mode:
fsBuilder->codeAppendf("if (0.0 == %s.a) {", dstColor);
fsBuilder->codeAppendf("%s.rgba = %s;", outputColor, srcColor);
fsBuilder->codeAppendf("} else {");
soft_light_component_pos_dst_alpha(fsBuilder, outputColor, srcColor, dstColor, 'r');
soft_light_component_pos_dst_alpha(fsBuilder, outputColor, srcColor, dstColor, 'g');
soft_light_component_pos_dst_alpha(fsBuilder, outputColor, srcColor, dstColor, 'b');
fsBuilder->codeAppendf("}");
break;
case SkXfermode::kDifference_Mode:
fsBuilder->codeAppendf("%s.rgb = %s.rgb + %s.rgb -"
"2.0 * min(%s.rgb * %s.a, %s.rgb * %s.a);",
outputColor, srcColor, dstColor, srcColor, dstColor,
dstColor, srcColor);
break;
case SkXfermode::kExclusion_Mode:
fsBuilder->codeAppendf("%s.rgb = %s.rgb + %s.rgb - "
"2.0 * %s.rgb * %s.rgb;",
outputColor, dstColor, srcColor, dstColor, srcColor);
break;
case SkXfermode::kMultiply_Mode:
fsBuilder->codeAppendf("%s.rgb = (1.0 - %s.a) * %s.rgb + "
"(1.0 - %s.a) * %s.rgb + "
"%s.rgb * %s.rgb;",
outputColor, srcColor, dstColor, dstColor, srcColor,
srcColor, dstColor);
break;
case SkXfermode::kHue_Mode: {
// SetLum(SetSat(S * Da, Sat(D * Sa)), Sa*Da, D*Sa) + (1 - Sa) * D + (1 - Da) * S
SkString setSat, setLum;
add_sat_function(fsBuilder, &setSat);
add_lum_function(fsBuilder, &setLum);
fsBuilder->codeAppendf("vec4 dstSrcAlpha = %s * %s.a;",
dstColor, srcColor);
fsBuilder->codeAppendf("%s.rgb = %s(%s(%s.rgb * %s.a, dstSrcAlpha.rgb),"
"dstSrcAlpha.a, dstSrcAlpha.rgb);",
outputColor, setLum.c_str(), setSat.c_str(), srcColor,
dstColor);
fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;",
outputColor, srcColor, dstColor, dstColor, srcColor);
break;
}
case SkXfermode::kSaturation_Mode: {
// SetLum(SetSat(D * Sa, Sat(S * Da)), Sa*Da, D*Sa)) + (1 - Sa) * D + (1 - Da) * S
SkString setSat, setLum;
add_sat_function(fsBuilder, &setSat);
add_lum_function(fsBuilder, &setLum);
fsBuilder->codeAppendf("vec4 dstSrcAlpha = %s * %s.a;",
dstColor, srcColor);
fsBuilder->codeAppendf("%s.rgb = %s(%s(dstSrcAlpha.rgb, %s.rgb * %s.a),"
"dstSrcAlpha.a, dstSrcAlpha.rgb);",
outputColor, setLum.c_str(), setSat.c_str(), srcColor,
dstColor);
fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;",
outputColor, srcColor, dstColor, dstColor, srcColor);
break;
}
case SkXfermode::kColor_Mode: {
// SetLum(S * Da, Sa* Da, D * Sa) + (1 - Sa) * D + (1 - Da) * S
SkString setLum;
add_lum_function(fsBuilder, &setLum);
fsBuilder->codeAppendf("vec4 srcDstAlpha = %s * %s.a;",
srcColor, dstColor);
fsBuilder->codeAppendf("%s.rgb = %s(srcDstAlpha.rgb, srcDstAlpha.a, %s.rgb * %s.a);",
outputColor, setLum.c_str(), dstColor, srcColor);
fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;",
outputColor, srcColor, dstColor, dstColor, srcColor);
break;
}
case SkXfermode::kLuminosity_Mode: {
// SetLum(D * Sa, Sa* Da, S * Da) + (1 - Sa) * D + (1 - Da) * S
SkString setLum;
add_lum_function(fsBuilder, &setLum);
fsBuilder->codeAppendf("vec4 srcDstAlpha = %s * %s.a;",
srcColor, dstColor);
fsBuilder->codeAppendf("%s.rgb = %s(%s.rgb * %s.a, srcDstAlpha.a, srcDstAlpha.rgb);",
outputColor, setLum.c_str(), dstColor, srcColor);
fsBuilder->codeAppendf("%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;",
outputColor, srcColor, dstColor, dstColor, srcColor);
break;
}
default:
SkFAIL("Unknown Custom Xfer mode.");
break;
}
}
//////////////////////////////////////////////////////////////////////////////
// Porter-Duff blend helper
//////////////////////////////////////////////////////////////////////////////
static bool append_porterduff_term(GrGLFragmentBuilder* 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;
}
}
//////////////////////////////////////////////////////////////////////////////
void GrGLSLBlend::AppendMode(GrGLFragmentBuilder* fsBuilder, const char* srcColor,
const char* dstColor, const char* outColor,
SkXfermode::Mode mode) {
SkXfermode::Coeff srcCoeff, dstCoeff;
if (SkXfermode::ModeAsCoeff(mode, &srcCoeff, &dstCoeff)) {
fsBuilder->codeAppendf("%s = ", outColor);
// append src blend
bool didAppend = append_porterduff_term(fsBuilder, srcCoeff, srcColor, srcColor, dstColor,
false);
// append dst blend
if(!append_porterduff_term(fsBuilder, dstCoeff, dstColor, srcColor, dstColor, didAppend)) {
fsBuilder->codeAppend("vec4(0, 0, 0, 0)");
}
fsBuilder->codeAppend(";");
} else {
emit_advanced_xfermode_code(fsBuilder, srcColor, dstColor, outColor, mode);
}
}

View File

@ -12,13 +12,13 @@
class GrGLFragmentBuilder;
namespace GrGLBlend {
namespace GrGLSLBlend {
/*
* Appends GLSL code to fsBuilder that assigns a specified blend of the srcColor and dstColor
* variables to the outColor variable.
*/
void AppendPorterDuffBlend(GrGLFragmentBuilder* fsBuilder, const char* srcColor,
const char* dstColor, const char* outColor, SkXfermode::Mode mode);
void AppendMode(GrGLFragmentBuilder* fsBuilder, const char* srcColor,
const char* dstColor, const char* outColor, SkXfermode::Mode mode);
};
#endif

View File

@ -248,7 +248,7 @@ static void set_random_color_coverage_stages(GrPipelineBuilder* pipelineBuilder,
for (int s = 0; s < numProcs;) {
SkAutoTUnref<const GrFragmentProcessor> fp(
GrProcessorTestFactory<GrFragmentProcessor>::Create(d));
GrProcessorTestFactory<GrFragmentProcessor>::Create(d));
SkASSERT(fp);
// finally add the stage to the correct pipeline in the drawstate

View File

@ -101,7 +101,7 @@ static void test_getConstantColorComponents(skiatest::Reporter* reporter, GrCont
for (size_t i = 0; i < SK_ARRAY_COUNT(filterTests); ++i) {
const GetConstantComponentTestCase& test = filterTests[i];
SkAutoTUnref<SkColorFilter> cf(SkColorFilter::CreateModeFilter(test.filterColor, test.filterMode));
SkTDArray<GrFragmentProcessor*> array;
SkTDArray<const GrFragmentProcessor*> array;
bool hasFrag = cf->asFragmentProcessors(grContext, paint.getProcessorDataManager(), &array);
REPORTER_ASSERT(reporter, hasFrag);
REPORTER_ASSERT(reporter, 1 == array.count());

View File

@ -0,0 +1,102 @@
/*
* 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 "Test.h"
#if SK_SUPPORT_GPU
#include "GrBlend.h"
#include "SkGr.h"
#include "SkRandom.h"
#include "SkXfermode.h"
static GrColor make_baseline_color(GrColor src, GrColor dst, const SkXfermode* xm) {
SkPMColor skSrc = GrColorToSkPMColor(src);
SkPMColor skDst = GrColorToSkPMColor(dst);
if (xm) {
xm->xfer32(&skDst, &skSrc, 1, nullptr);
} else {
// null means src-over
skDst = SkPMSrcOver(skSrc, skDst);
}
return SkPMColorToGrColor(skDst);
}
DEF_TEST(GrGetCoeffBlendKnownComponents, reporter) {
SkRandom random;
for (int i = 0; i < SkXfermode::kLastCoeffMode; ++i) {
SkXfermode::Mode mode = (SkXfermode::Mode)i;
SkAutoTUnref<SkXfermode> xm(SkXfermode::Create(mode));
SkXfermode::Coeff srcCoeff, dstCoeff;
SkAssertResult(SkXfermode::ModeAsCoeff(mode, &srcCoeff, &dstCoeff));
for (int j = 0; j < 1000; ++j) {
GrColor src = GrPremulColor(random.nextU());
GrColor dst = GrPremulColor(random.nextU());
GrColor outColor;
GrColorComponentFlags outFlags;
GrGetCoeffBlendKnownComponents(SkXfermodeCoeffToGrBlendCoeff(srcCoeff),
SkXfermodeCoeffToGrBlendCoeff(dstCoeff),
src, kRGBA_GrColorComponentFlags,
dst, kRGBA_GrColorComponentFlags,
&outColor, &outFlags);
GrColor baselineColor = make_baseline_color(src, dst, xm);
if (SkAbs32(GrColorUnpackA(baselineColor) - GrColorUnpackA(outColor)) > 1 ||
SkAbs32(GrColorUnpackR(baselineColor) - GrColorUnpackR(outColor)) > 1 ||
SkAbs32(GrColorUnpackG(baselineColor) - GrColorUnpackG(outColor)) > 1 ||
SkAbs32(GrColorUnpackB(baselineColor) - GrColorUnpackB(outColor)) > 1) {
ERRORF(reporter, "Blended color is 0x%08x, expected 0x%08x", outColor,
baselineColor);
}
GrColorIsPMAssert(outColor);
}
}
GrColor outColor;
GrColorComponentFlags outFlags;
GrGetCoeffBlendKnownComponents(kZero_GrBlendCoeff, kZero_GrBlendCoeff,
0xFFFFFFFF, kNone_GrColorComponentFlags,
0xFFFFFFFF, kNone_GrColorComponentFlags,
&outColor, &outFlags);
REPORTER_ASSERT(reporter, GrColor_TRANSPARENT_BLACK == outColor &&
kRGBA_GrColorComponentFlags == outFlags);
GrGetCoeffBlendKnownComponents(
kOne_GrBlendCoeff, kOne_GrBlendCoeff,
0x80FF0100, (kG_GrColorComponentFlag | kB_GrColorComponentFlag | kA_GrColorComponentFlag),
0x7F00FFFF, (kR_GrColorComponentFlag | kG_GrColorComponentFlag | kA_GrColorComponentFlag),
&outColor, &outFlags);
REPORTER_ASSERT(reporter, GrColor_WHITE == outColor && kRGBA_GrColorComponentFlags == outFlags);
GrGetCoeffBlendKnownComponents(
kOne_GrBlendCoeff, kISA_GrBlendCoeff,
0x0000000, kRGBA_GrColorComponentFlags,
0x80010203, kRGBA_GrColorComponentFlags,
&outColor, &outFlags);
REPORTER_ASSERT(reporter, 0x80010203 == outColor && kRGBA_GrColorComponentFlags == outFlags);
GrGetCoeffBlendKnownComponents(kZero_GrBlendCoeff, kISA_GrBlendCoeff,
0x0000000, kA_GrColorComponentFlag,
0x80010203, kRGBA_GrColorComponentFlags,
&outColor, &outFlags);
REPORTER_ASSERT(reporter, 0x80010203 == outColor && kRGBA_GrColorComponentFlags == outFlags);
GrGetCoeffBlendKnownComponents(
kIDC_GrBlendCoeff, kSC_GrBlendCoeff,
0x0, kNone_GrColorComponentFlags,
0x0, kRGBA_GrColorComponentFlags,
&outColor, &outFlags);
REPORTER_ASSERT(reporter, kNone_GrColorComponentFlags == outFlags);
GrGetCoeffBlendKnownComponents(
kOne_GrBlendCoeff, kISA_GrBlendCoeff,
0xFF808080, (kG_GrColorComponentFlag | kB_GrColorComponentFlag | kA_GrColorComponentFlag),
0xFF606060, kRGBA_GrColorComponentFlags,
&outColor, &outFlags);
REPORTER_ASSERT(reporter,
(kG_GrColorComponentFlag | kB_GrColorComponentFlag | kA_GrColorComponentFlag) == outFlags &&
(outColor & 0xFFFFFF00) == 0xFF808000);
}
#endif