SkLumaColorFilter.cpp revision 6c1ee2d4e727357451c8a6fcf4a08e75890b5d6d
16c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org/*
26c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org * Copyright 2013 Google Inc.
36c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org *
46c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org * Use of this source code is governed by a BSD-style license that can be
56c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org * found in the LICENSE file.
66c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org */
76c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org
86c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org#include "SkLumaColorFilter.h"
96c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org
106c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org#include "SkColorPriv.h"
116c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org#include "SkString.h"
126c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org#include "SkUnPreMultiply.h"
136c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org
146c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org#if SK_SUPPORT_GPU
156c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org#include "gl/GrGLEffect.h"
166c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org#include "GrContext.h"
176c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org#include "GrTBackendEffectFactory.h"
186c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org#endif
196c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org
206c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.orgvoid SkLumaColorFilter::filterSpan(const SkPMColor src[], int count,
216c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org                                   SkPMColor dst[]) const {
226c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org    const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleTable();
236c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org
246c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org    for (int i = 0; i < count; ++i) {
256c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org        SkPMColor c = src[i];
266c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org
276c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org        unsigned r = SkGetPackedR32(c);
286c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org        unsigned g = SkGetPackedG32(c);
296c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org        unsigned b = SkGetPackedB32(c);
306c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org        unsigned a = SkGetPackedA32(c);
316c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org
326c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org       // No need to do anything for white (luminance == 1.0)
336c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org       if (a != r || a != g || a != b) {
346c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org            /*
356c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org             *  To avoid un-premultiplying multiple components, we can start
366c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org             *  with the luminance computed in PM space:
376c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org             *
386c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org             *    Lum = i * (r / a) + j * (g / a) + k * (b / a)
396c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org             *    Lum = (i * r + j * g + k * b) / a
406c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org             *    Lum = Lum'(PM) / a
416c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org             *
426c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org             *  Then the filter function is:
436c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org             *
446c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org             *    C' = [ Lum * a, Lum * r, Lum * g, Lum * b ]
456c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org             *
466c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org             *  which is equivalent to:
476c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org             *
486c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org             *    C' = [ Lum'(PM), Lum * r, Lum * g, Lum * b ]
496c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org             */
506c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org            unsigned pm_lum = SkComputeLuminance(r, g, b);
516c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org            unsigned lum = SkUnPreMultiply::ApplyScale(table[a], pm_lum);
526c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org
536c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org            c = SkPackARGB32(pm_lum,
546c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org                             SkMulDiv255Round(r, lum),
556c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org                             SkMulDiv255Round(g, lum),
566c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org                             SkMulDiv255Round(b, lum));
576c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org        }
586c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org
596c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org        dst[i] = c;
606c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org    }
616c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org}
626c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org
636c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.orgSkColorFilter* SkLumaColorFilter::Create() {
646c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org    return SkNEW(SkLumaColorFilter);
656c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org}
666c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org
676c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.orgSkLumaColorFilter::SkLumaColorFilter()
686c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org    : INHERITED() {
696c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org}
706c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org
716c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.orgSkLumaColorFilter::SkLumaColorFilter(SkFlattenableReadBuffer& buffer)
726c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org    : INHERITED(buffer) {
736c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org}
746c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org
756c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.orgvoid SkLumaColorFilter::flatten(SkFlattenableWriteBuffer&) const {
766c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org}
776c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org
786c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org#ifdef SK_DEVELOPER
796c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.orgvoid SkLumaColorFilter::toString(SkString* str) const {
806c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org    str->append("SkLumaColorFilter ");
816c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org}
826c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org#endif
836c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org
846c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org#if SK_SUPPORT_GPU
856c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.orgclass LumaColorFilterEffect : public GrEffect {
866c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.orgpublic:
876c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org    static GrEffectRef* Create() {
886c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org        AutoEffectUnref effect(SkNEW(LumaColorFilterEffect));
896c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org        return CreateEffectRef(effect);
906c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org    }
916c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org
926c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org    static const char* Name() { return "Luminance-to-Alpha"; }
936c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org
946c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org    virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
956c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org        return GrTBackendEffectFactory<LumaColorFilterEffect>::getInstance();
966c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org    }
976c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org
986c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org    virtual void getConstantColorComponents(GrColor* color,
996c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org                                            uint32_t* validFlags) const SK_OVERRIDE {
1006c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org        *validFlags = 0;
1016c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org    }
1026c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org
1036c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org    class GLEffect : public GrGLEffect {
1046c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org    public:
1056c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org        GLEffect(const GrBackendEffectFactory& factory,
1066c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org                 const GrDrawEffect&)
1076c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org        : INHERITED(factory) {
1086c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org        }
1096c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org
1106c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org        static EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&) {
1116c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org            // this class always generates the same code.
1126c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org            return 0;
1136c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org        }
1146c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org
1156c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org        virtual void emitCode(GrGLShaderBuilder* builder,
1166c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org                              const GrDrawEffect&,
1176c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org                              EffectKey,
1186c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org                              const char* outputColor,
1196c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org                              const char* inputColor,
1206c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org                              const TransformedCoordsArray&,
1216c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org                              const TextureSamplerArray&) SK_OVERRIDE {
1226c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org            if (NULL == inputColor) {
1236c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org                inputColor = GrGLSLOnesVecf(4);
1246c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org            }
1256c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org
1266c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org            // The max() is to guard against 0 / 0 during unpremul when the incoming color is
1276c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org            // transparent black.
1286c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org            builder->fsCodeAppendf("\tfloat nonZeroAlpha = max(%s.a, 0.00001);\n", inputColor);
1296c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org            builder->fsCodeAppendf("\tfloat luma = dot(vec3(%f, %f, %f), %s.rgb);\n",
1306c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org                                   SK_ITU_BT709_LUM_COEFF_R,
1316c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org                                   SK_ITU_BT709_LUM_COEFF_G,
1326c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org                                   SK_ITU_BT709_LUM_COEFF_B,
1336c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org                                   inputColor);
1346c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org            builder->fsCodeAppendf("\t%s = vec4(%s.rgb * luma / nonZeroAlpha, luma);\n",
1356c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org                                   outputColor, inputColor);
1366c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org
1376c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org        }
1386c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org
1396c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org    private:
1406c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org        typedef GrGLEffect INHERITED;
1416c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org    };
1426c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org
1436c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.orgprivate:
1446c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org    virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE {
1456c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org        return true;
1466c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org    }
1476c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org};
1486c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org
1496c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.orgGrEffectRef* SkLumaColorFilter::asNewEffect(GrContext*) const {
1506c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org    return LumaColorFilterEffect::Create();
1516c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org}
1526c1ee2d4e727357451c8a6fcf4a08e75890b5d6dcommit-bot@chromium.org#endif
153