Index: src/effects/SkColorFilters.cpp |
diff --git a/src/effects/SkColorFilters.cpp b/src/effects/SkColorFilters.cpp |
index 41a201ef39559fc232e10319c3a9e65f20c39c8c..653981290e5842742ea568ca7469100cfbaebfc4 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,293 @@ 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 "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 (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 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; |
+ |
+ 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 TransformedCoordsArray& coords, |
+ 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); |
+ } |
+ |
+ GrGLSLExpr4 filter = |
+ color_filter_expression(mode, GrGLSLExpr4(colorFilterColorUniName), GrGLSLExpr4(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: |
+ |
+ GrGLUniformManager::UniformHandle fFilterColorUni; |
+ typedef GrGLEffect INHERITED; |
+ }; |
+ |
+ GR_DECLARE_EFFECT_TEST; |
+ |
+private: |
+ ModeColorFilterEffect(GrColor color, SkXfermode::Mode mode) |
+ : fMode(mode), |
+ fColor(color) { |
+ |
+ 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 && !GrBlendCoeffRefsDst(sk_blend_to_grblend(srcCoeff))) { |
+ this->setWillNotUseInputColor(); |
+ } |
+ } |
+ |
+ 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 { |
+ |
+/** 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(GrMax(0.f, GrMin(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::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const { |
+ float inputColor[4]; |
+ GrColorToRGBAFloat(*color, inputColor); |
+ float 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) {} |