Chromium Code Reviews| Index: src/effects/SkColorFilters.cpp |
| diff --git a/src/effects/SkColorFilters.cpp b/src/effects/SkColorFilters.cpp |
| index 41a201ef39559fc232e10319c3a9e65f20c39c8c..229e02cf63fb31a2bcfc4a50b7a3f4841ebe7a62 100644 |
| --- a/src/effects/SkColorFilters.cpp |
| +++ b/src/effects/SkColorFilters.cpp |
| @@ -85,6 +85,9 @@ public: |
| } |
| #endif |
| +#if SK_SUPPORT_GPU |
| + virtual GrEffectRef* asNewEffect(GrContext*) const SK_OVERRIDE; |
| +#endif |
| SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkModeColorFilter) |
| protected: |
| @@ -117,6 +120,285 @@ private: |
| typedef SkColorFilter INHERITED; |
| }; |
| +/////////////////////////////////////////////////////////////////////////////// |
| +#if SK_SUPPORT_GPU |
| +#include "GrBlend.h" |
| +#include "GrEffect.h" |
| +#include "GrEffectUnitTest.h" |
| +#include "GrTBackendEffectFactory.h" |
| +#include "gl/GrGLEffect.h" |
| +#include "gl/GrGLEffectMatrix.h" |
| +#include "SkGr.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: |
| + GrCrash("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 (1 - src) * dst; |
| + case SkXfermode::kDC_Coeff: |
| + return dst * value; |
| + case SkXfermode::kIDC_Coeff: |
| + return (1 - dst) * value; |
| + case SkXfermode::kSA_Coeff: /** src alpha */ |
| + return value * src.a(); |
| + case SkXfermode::kISA_Coeff: /** inverse src alpha (i.e. 1 - sa) */ |
| + return value * (1 - src.a()); |
| + case SkXfermode::kDA_Coeff: /** dst alpha */ |
| + return value * dst.a(); |
| + case SkXfermode::kIDA_Coeff: /** inverse dst alpha (i.e. 1 - da) */ |
| + return value * (1 - dst.a()); |
| + } |
| +} |
| +/** |
| + * Creates a color filter expression which modifies the color by |
| + * the specified color filter. |
| + */ |
| +template <typename ColorExpr> |
| +static inline ColorExpr color_filter_expression(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 GrEffect { |
| +public: |
| + static GrEffectRef* Create(const GrColor& c, SkXfermode::Mode mode) { |
| + AutoEffectUnref effect(SkNEW_ARGS(ModeColorFilterEffect, (c, mode))); |
| + return CreateEffectRef(effect); |
| + } |
| + |
| + virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE; |
| + |
| + virtual bool willUseInputColor() const { |
| + SkXfermode::Coeff dstCoeff; |
| + SkXfermode::Coeff srcCoeff; |
| + SkAssertResult(SkXfermode::ModeAsCoeff(fMode, &srcCoeff, &dstCoeff)); |
| + // These could be calculated from the blend equation with template trickery.. |
| + if (SkXfermode::kZero_Coeff == dstCoeff) { |
| + return GrBlendCoeffRefsDst(sk_blend_to_grblend(srcCoeff)); |
| + } |
| + return true; |
| + } |
| + |
| + 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; |
| + } |
| + |
| + virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE { |
| + return GrTBackendEffectFactory<ModeColorFilterEffect>::getInstance(); |
| + } |
| + |
| + static const char* Name() { return "ModeColorFilterEffect"; } |
| + |
| + SkXfermode::Mode mode() const { return fMode; } |
| + GrColor color() const { return fColor; } |
| + |
| + class GLEffect : public GrGLEffect { |
| + public: |
| + GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&) |
| + : INHERITED(factory) { |
| + } |
| + |
| + virtual void emitCode(GrGLShaderBuilder* builder, |
| + const GrDrawEffect& drawEffect, |
| + EffectKey key, |
| + const char* outputColor, |
| + const char* inputColor, |
| + const TextureSamplerArray& samplers) SK_OVERRIDE { |
| + SkXfermode::Mode mode = drawEffect.castEffect<ModeColorFilterEffect>().mode(); |
| + |
| + SkASSERT(SkXfermode::kDst_Mode != mode); |
| + const char* colorFilterColorUniName = NULL; |
| + if (drawEffect.castEffect<ModeColorFilterEffect>().willUseFilterColor()) { |
| + fFilterColorUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, |
| + kVec4f_GrSLType, "FilterColor", |
| + &colorFilterColorUniName); |
| + } |
| + |
| + GrGLSLExpr<4> filter = color_filter_expression(mode, |
| + GrGLSLExpr<4>(colorFilterColorUniName), |
| + GrGLSLExpr<4>(inputColor)); |
| + builder->fsCodeAppendf("\t%s = %s;\n", outputColor, filter.c_str()); |
| + } |
| + |
| + static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) { |
| + const ModeColorFilterEffect& colorModeFilter = drawEffect.castEffect<ModeColorFilterEffect>(); |
| + // The SL code does not depend on filter color at the moment, so no need to represent it |
| + // in the key. |
| + EffectKey modeKey = colorModeFilter.mode(); |
| + return modeKey; |
| + } |
| + |
| + virtual void setData(const GrGLUniformManager& uman, const GrDrawEffect& drawEffect) SK_OVERRIDE { |
| + if (fFilterColorUni.isValid()) { |
| + const ModeColorFilterEffect& colorModeFilter = drawEffect.castEffect<ModeColorFilterEffect>(); |
| + GrGLfloat c[4]; |
| + GrColorToRGBAFloat(colorModeFilter.color(), c); |
| + uman.set4fv(fFilterColorUni, 0, 1, c); |
| + } |
| + } |
| + |
| + private: |
| + |
| + static const GrEffect::CoordsType kCoordsType = GrEffect::kLocal_CoordsType; |
| + GrGLUniformManager::UniformHandle fFilterColorUni; |
| + typedef GrGLEffect INHERITED; |
| + }; |
| + |
| + GR_DECLARE_EFFECT_TEST; |
| + |
| +private: |
| + ModeColorFilterEffect(GrColor color, SkXfermode::Mode mode) |
| + : fMode(mode), |
| + fColor(color) { |
| + } |
| + |
| + virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE { |
| + const ModeColorFilterEffect& s = CastEffect<ModeColorFilterEffect>(other); |
| + return fMode == s.fMode && fColor == s.fColor; |
| + } |
| + |
| + SkXfermode::Mode fMode; |
| + GrColor fColor; |
| + |
| + typedef GrEffect INHERITED; |
| +}; |
| + |
| +namespace { |
| +/** MaskedColorExpr is used to evaluate the color and valid color component |
| + * flags through the blending equation. |
| + */ |
| +class MaskedColorExpr { |
| +public: |
| + MaskedColorExpr(const GrGLfloat 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) |
| + : fFlags(kRGBA_GrColorComponentFlags) { |
| + fColor[0] = v; |
| + fColor[1] = v; |
| + fColor[2] = v; |
| + fColor[3] = v; |
| + } |
| + |
| + MaskedColorExpr operator*(const MaskedColorExpr& other) const { |
| + GrGLfloat tmp[4]; |
| + tmp[0] = GrMax(0.f, GrMin(1.f, fColor[0] * other.fColor[0])); |
| + tmp[1] = GrMax(0.f, GrMin(1.f, fColor[1] * other.fColor[1])); |
| + tmp[2] = GrMax(0.f, GrMin(1.f, fColor[2] * other.fColor[2])); |
| + tmp[3] = GrMax(0.f, GrMin(1.f, fColor[3] * other.fColor[3])); |
| + |
| + return MaskedColorExpr(tmp, fFlags & other.fFlags); |
| + } |
| + |
| + MaskedColorExpr operator+(const MaskedColorExpr& other) const { |
| + GrGLfloat tmp[4]; |
| + tmp[0] = GrMax(0.f, GrMin(1.f, fColor[0] + other.fColor[0])); |
| + tmp[1] = GrMax(0.f, GrMin(1.f, fColor[1] + other.fColor[1])); |
| + tmp[2] = GrMax(0.f, GrMin(1.f, fColor[2] + other.fColor[2])); |
| + tmp[3] = GrMax(0.f, GrMin(1.f, fColor[3] + other.fColor[3])); |
| + |
| + return MaskedColorExpr(tmp, fFlags & other.fFlags); |
| + } |
| + |
| + MaskedColorExpr operator-(const MaskedColorExpr& other) const { |
| + GrGLfloat tmp[4]; |
| + tmp[0] = GrMax(0.f, GrMin(1.f, fColor[0] - other.fColor[0])); |
| + tmp[1] = GrMax(0.f, GrMin(1.f, fColor[1] - other.fColor[1])); |
| + tmp[2] = GrMax(0.f, GrMin(1.f, fColor[2] - other.fColor[2])); |
| + tmp[3] = GrMax(0.f, GrMin(1.f, fColor[3] - other.fColor[3])); |
| + |
| + return MaskedColorExpr(tmp, fFlags & other.fFlags); |
| + } |
| + |
| + MaskedColorExpr a() const { |
| + return MaskedColorExpr(fColor[3]); |
| + } |
| + |
| + GrColor getColor() const { |
| + return GrColorPackRGBA(fColor[0] * 255.f, fColor[1] * 255.f, |
| + fColor[2] * 255.f, fColor[3] * 255.f); |
| + } |
| + |
| + uint32_t getValidComponents() const { return fFlags; } |
| + |
| +private: |
| + GrGLfloat fColor[4]; |
| + uint32_t fFlags; |
| +}; |
| + |
| +MaskedColorExpr operator-(int v, const MaskedColorExpr& other) { |
| + return MaskedColorExpr(v) - other; |
| +} |
| +} |
| + |
| +void ModeColorFilterEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const { |
|
Kimmo Kinnunen
2013/10/01 12:55:46
Btw: It'd be great to be able to unit test these s
|
| + GrGLfloat inputColor[4]; |
| + GrColorToRGBAFloat(*color, inputColor); |
| + GrGLfloat filterColor[4]; |
| + GrColorToRGBAFloat(fColor, filterColor); |
| + MaskedColorExpr result = |
| + color_filter_expression(fMode, |
| + MaskedColorExpr(filterColor, kRGBA_GrColorComponentFlags), |
| + MaskedColorExpr(inputColor, *validFlags)); |
| + |
| + *color = result.getColor(); |
| + *validFlags = result.getValidComponents(); |
| +} |
| + |
| +GR_DEFINE_EFFECT_TEST(ModeColorFilterEffect); |
| +GrEffectRef* ModeColorFilterEffect::TestCreate(SkRandom* rand, |
| + GrContext*, |
| + const GrDrawTargetCaps&, |
| + GrTexture*[]) { |
| + int mode = rand->nextRangeU(0, SkXfermode::kLastCoeffMode); |
| + GrColor color = rand->nextU(); |
| + static AutoEffectUnref gEffect(SkNEW_ARGS(ModeColorFilterEffect, (color, static_cast<SkXfermode::Mode>(mode)))); |
| + return CreateEffectRef(gEffect); |
| +} |
| + |
| +GrEffectRef* SkModeColorFilter::asNewEffect(GrContext*) const { |
| + if (SkXfermode::kDst_Mode != fMode) { |
| + return ModeColorFilterEffect::Create(SkColor2GrColor(fColor), fMode); |
| + } |
| + return NULL; |
| +} |
| + |
| +#endif |
| + |
| +/////////////////////////////////////////////////////////////////////////////// |
| + |
| class Src_SkModeColorFilter : public SkModeColorFilter { |
| public: |
| Src_SkModeColorFilter(SkColor color) : INHERITED(color, SkXfermode::kSrc_Mode) {} |