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:
parent
cd7f035974
commit
ae4738f677
@ -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',
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
@ -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 {
|
||||
|
@ -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()
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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 ||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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:
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
124
src/gpu/GrBlend.cpp
Normal 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();
|
||||
}
|
@ -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;
|
||||
|
||||
|
@ -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)) {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
435
src/gpu/gl/GrGLSLBlend.cpp
Normal 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);
|
||||
}
|
||||
}
|
@ -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
|
@ -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
|
||||
|
@ -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());
|
||||
|
102
tests/GrGetCoeffBlendKnownComponentsTest.cpp
Normal file
102
tests/GrGetCoeffBlendKnownComponentsTest.cpp
Normal 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
|
Loading…
Reference in New Issue
Block a user