Index: src/effects/SkLumaXfermode.cpp |
diff --git a/src/effects/SkLumaXfermode.cpp b/src/effects/SkLumaXfermode.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..c2f29009b79fddf7f0a99820df17508210ea0f5c |
--- /dev/null |
+++ b/src/effects/SkLumaXfermode.cpp |
@@ -0,0 +1,271 @@ |
+/* |
+ * Copyright 2013 Google Inc. |
+ * |
+ * Use of this source code is governed by a BSD-style license that can be |
+ * found in the LICENSE file. |
+ */ |
+ |
+#include "SkLumaXfermode.h" |
+#include "SkColorPriv.h" |
+#include "SkFlattenableBuffers.h" |
+#include "SkString.h" |
+ |
+#if SK_SUPPORT_GPU |
+#include "gl/GrGLEffect.h" |
+#include "gl/GrGLEffectMatrix.h" |
+#include "GrContext.h" |
+#include "GrTBackendEffectFactory.h" |
+#endif |
+ |
+static inline SkPMColor luma_proc(const SkPMColor a, const SkPMColor b) { |
+ unsigned luma = SkComputeLuminance(SkGetPackedR32(b), |
reed1
2013/08/22 18:35:51
Is the spec cool with computing luminance on the p
f(malita)
2013/08/22 19:25:52
Actually they explicitly mention non-premultiplied
|
+ SkGetPackedG32(b), |
+ SkGetPackedB32(b)); |
+ return SkAlphaMulQ(a, SkAlpha255To256(luma)); |
+} |
+ |
+template <typename T> |
+static inline const T* lumaOpA(SkXfermode::Mode mode, |
+ const T* src, const T* dst) { |
+ return SkXfermode::kSrcIn_Mode == mode ? src : dst; |
+} |
+ |
+template <typename T> |
+static inline const T* lumaOpB(SkXfermode::Mode mode, |
+ const T* src, const T* dst) { |
+ return SkXfermode::kSrcIn_Mode == mode ? dst : src; |
+} |
+ |
+SkXfermode* SkLumaMaskXfermode::Create(SkXfermode::Mode mode) { |
+ return SkNEW_ARGS(SkLumaMaskXfermode, (mode)); |
+} |
+ |
+SkLumaMaskXfermode::SkLumaMaskXfermode(SkXfermode::Mode mode) |
+ : fMode(mode) { |
+ SkASSERT(kSrcIn_Mode == mode || kDstIn_Mode == mode); |
+} |
+ |
+SkLumaMaskXfermode::SkLumaMaskXfermode(SkFlattenableReadBuffer& buffer) |
+ : INHERITED(buffer) |
+ , fMode((SkXfermode::Mode)buffer.readUInt()) { |
+ SkASSERT(kSrcIn_Mode == fMode || kDstIn_Mode == fMode); |
+} |
+ |
+void SkLumaMaskXfermode::flatten(SkFlattenableWriteBuffer& buffer) const { |
+ INHERITED::flatten(buffer); |
+ buffer.writeUInt(fMode); |
+} |
+ |
+SkPMColor SkLumaMaskXfermode::xferColor(SkPMColor src, SkPMColor dst) const { |
+ const SkPMColor* a = lumaOpA<SkPMColor>(fMode, &src, &dst); |
+ const SkPMColor* b = lumaOpB<SkPMColor>(fMode, &src, &dst); |
+ return luma_proc(*a, *b); |
+} |
+ |
+void SkLumaMaskXfermode::xfer32(SkPMColor dst[], const SkPMColor src[], |
+ int count, const SkAlpha aa[]) const { |
+ const SkPMColor* a = lumaOpA<SkPMColor>(fMode, src, dst); |
+ const SkPMColor* b = lumaOpB<SkPMColor>(fMode, src, dst); |
+ |
+ if (aa) { |
+ for (int i = 0; i < count; ++i) { |
+ unsigned cov = aa[i]; |
+ if (cov) { |
+ unsigned resC = luma_proc(a[i], b[i]); |
+ if (cov < 255) { |
+ resC = SkAlphaMulQ(resC, SkAlpha255To256(cov)); |
+ } |
+ dst[i] = resC; |
+ } |
+ } |
+ } else { |
+ for (int i = 0; i < count; ++i) { |
+ dst[i] = luma_proc(a[i], b[i]); |
+ } |
+ } |
+} |
+ |
+#ifdef SK_DEVELOPER |
+void SkLumaMaskXfermode::toString(SkString* str) const { |
+ str->printf("SkLumaMaskXfermode: mode: %s", |
+ fMode == kSrcIn_Mode ? "SRC_IN" : "DST_IN"); |
+} |
+#endif |
+ |
+#if SK_SUPPORT_GPU |
+////////////////////////////////////////////////////////////////////////////// |
+ |
+class GrGLLumaMaskEffect : public GrGLEffect { |
+public: |
+ GrGLLumaMaskEffect(const GrBackendEffectFactory&, const GrDrawEffect&); |
+ virtual ~GrGLLumaMaskEffect(); |
+ |
+ virtual void emitCode(GrGLShaderBuilder*, |
+ const GrDrawEffect&, |
+ EffectKey, |
+ const char* outputColor, |
+ const char* inputColor, |
+ const TextureSamplerArray&) SK_OVERRIDE; |
+ |
+ static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&); |
+ virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE; |
+ |
+private: |
+ static const GrEffect::CoordsType kCoordsType = GrEffect::kLocal_CoordsType; |
+ GrGLEffectMatrix fBackgroundEffectMatrix; |
+ |
+ typedef GrGLEffect INHERITED; |
+}; |
+ |
+class GrLumaMaskEffect : public GrEffect { |
+public: |
+ static GrEffectRef* Create(SkXfermode::Mode mode, GrTexture* background) { |
+ AutoEffectUnref effect(SkNEW_ARGS(GrLumaMaskEffect, (mode, background))); |
+ return CreateEffectRef(effect); |
+ } |
+ |
+ virtual ~GrLumaMaskEffect(); |
+ |
+ typedef GrGLLumaMaskEffect GLEffect; |
+ static const char* Name() { return "LumaMask"; } |
+ GrTexture* backgroundTexture() const { return fBackgroundAccess.getTexture(); } |
+ |
+ virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE; |
+ virtual void getConstantColorComponents(GrColor*, uint32_t*) const SK_OVERRIDE; |
+ |
+ SkXfermode::Mode getMode() const { return fMode; } |
+ |
+private: |
+ GrLumaMaskEffect(SkXfermode::Mode, GrTexture*); |
+ |
+ virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE; |
+ |
+ SkXfermode::Mode fMode; |
+ GrTextureAccess fBackgroundAccess; |
+}; |
+ |
+////////////////////////////////////////////////////////////////////////////// |
+ |
+GrGLLumaMaskEffect::GrGLLumaMaskEffect(const GrBackendEffectFactory& factory, |
+ const GrDrawEffect&) |
+ : INHERITED(factory) |
+ , fBackgroundEffectMatrix(kCoordsType) { |
+} |
+ |
+GrGLLumaMaskEffect::~GrGLLumaMaskEffect() { |
+} |
+ |
+void GrGLLumaMaskEffect::emitCode(GrGLShaderBuilder* builder, |
+ const GrDrawEffect& drawEffect, |
+ EffectKey key, |
+ const char* outputColor, |
+ const char* inputColor, |
+ const TextureSamplerArray& samplers) { |
+ |
+ const GrLumaMaskEffect& lumaEffect = drawEffect.castEffect<GrLumaMaskEffect>(); |
+ GrTexture* backgroundTex = lumaEffect.backgroundTexture(); |
+ const char* dstColor; |
+ if (backgroundTex) { |
+ const char* bgCoords; |
+ GrSLType bgCoordsType = fBackgroundEffectMatrix.emitCode(builder, |
+ key, |
+ &bgCoords, |
+ NULL, |
+ "BG"); |
+ builder->fsCodeAppend("\t\tvec4 bgColor = "); |
+ builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType, |
+ samplers[0], |
+ bgCoords, |
+ bgCoordsType); |
+ builder->fsCodeAppendf(";\n"); |
+ dstColor = "bgColor"; |
+ } else { |
+ dstColor = builder->dstColor(); |
+ } |
+ |
+ SkASSERT(NULL != dstColor); |
+ |
+ if (NULL == inputColor) { |
+ inputColor = GrGLSLOnesVecf(4); |
+ } |
+ |
+ const char *opA = lumaOpA<char>(lumaEffect.getMode(), inputColor, dstColor); |
+ const char *opB = lumaOpB<char>(lumaEffect.getMode(), inputColor, dstColor); |
+ |
+ builder->fsCodeAppendf("\t\tfloat luma = dot(vec3(%f, %f, %f), %s.rgb); \n", |
+ SK_ITU_BT709_LUM_COEFF_R, |
+ SK_ITU_BT709_LUM_COEFF_G, |
+ SK_ITU_BT709_LUM_COEFF_B, |
+ opB); |
+ builder->fsCodeAppendf("\t\t%s = %s * luma;\n", outputColor, opA); |
+} |
+ |
+GrGLEffect::EffectKey GrGLLumaMaskEffect::GenKey(const GrDrawEffect& drawEffect, |
+ const GrGLCaps&) { |
+ const GrLumaMaskEffect& effect = drawEffect.castEffect<GrLumaMaskEffect>(); |
+ EffectKey modeKey = effect.getMode(); |
+ GrTexture* bgTex = effect.backgroundTexture(); |
+ EffectKey matrixKey = 0; |
+ if (bgTex) { |
+ matrixKey = GrGLEffectMatrix::GenKey(GrEffect::MakeDivByTextureWHMatrix(bgTex), |
+ drawEffect, |
+ GrGLLumaMaskEffect::kCoordsType, |
+ bgTex); |
+ } |
+ |
+ return (modeKey << GrGLEffectMatrix::kKeyBits) | matrixKey; |
+} |
+ |
+void GrGLLumaMaskEffect::setData(const GrGLUniformManager& uman, |
+ const GrDrawEffect& drawEffect) { |
+ const GrLumaMaskEffect& luma = drawEffect.castEffect<GrLumaMaskEffect>(); |
+ GrTexture* bgTex = luma.backgroundTexture(); |
+ if (bgTex) { |
+ fBackgroundEffectMatrix.setData(uman, |
+ GrEffect::MakeDivByTextureWHMatrix(bgTex), |
+ drawEffect, |
+ bgTex); |
+ } |
+} |
+ |
+////////////////////////////////////////////////////////////////////////////// |
+ |
+GrLumaMaskEffect::GrLumaMaskEffect(SkXfermode::Mode mode, GrTexture* bg) |
+ : fMode(mode) { |
+ if (bg) { |
+ fBackgroundAccess.reset(bg); |
+ this->addTextureAccess(&fBackgroundAccess); |
+ } else { |
+ this->setWillReadDstColor(); |
+ } |
+} |
+ |
+GrLumaMaskEffect::~GrLumaMaskEffect() { |
+} |
+ |
+const GrBackendEffectFactory& GrLumaMaskEffect::getFactory() const { |
+ return GrTBackendEffectFactory<GrLumaMaskEffect>::getInstance(); |
+} |
+ |
+void GrLumaMaskEffect::getConstantColorComponents(GrColor*, uint32_t *validFlags) const { |
+ *validFlags = 0; |
+} |
+ |
+bool GrLumaMaskEffect::onIsEqual(const GrEffect& sBase) const { |
+ const GrLumaMaskEffect& s = CastEffect<GrLumaMaskEffect>(sBase); |
+ return fMode == s.fMode && |
+ fBackgroundAccess.getTexture() == s.fBackgroundAccess.getTexture(); |
+} |
+ |
+////////////////////////////////////////////////////////////////////////////// |
+ |
+bool SkLumaMaskXfermode::asNewEffectOrCoeff(GrContext*, GrEffectRef** effect, |
+ Coeff*, Coeff*, |
+ GrTexture* background) const { |
+ if (effect) { |
+ *effect = GrLumaMaskEffect::Create(fMode, background); |
+ } |
+ return true; |
+} |
+ |
+#endif // SK_SUPPORT_GPU |