SkLumaColorFilter.cpp revision 824c346b6e0e114063c1a8ad4ba7c3a669ee2cff
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Copyright 2013 Google Inc.
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Use of this source code is governed by a BSD-style license that can be
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * found in the LICENSE file.
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "SkLumaColorFilter.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "SkColorPriv.h"
117dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "SkString.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "SkUnPreMultiply.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#if SK_SUPPORT_GPU
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "gl/GrGLEffect.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "GrContext.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "GrTBackendEffectFactory.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void SkLumaColorFilter::filterSpan(const SkPMColor src[], int count,
21868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                   SkPMColor dst[]) const {
22868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleTable();
23868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
24868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    for (int i = 0; i < count; ++i) {
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SkPMColor c = src[i];
26eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        unsigned r = SkGetPackedR32(c);
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        unsigned g = SkGetPackedG32(c);
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        unsigned b = SkGetPackedB32(c);
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        unsigned a = SkGetPackedA32(c);
317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       // No need to do anything for white (luminance == 1.0)
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       if (a != r || a != g || a != b) {
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            /*
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             *  To avoid un-premultiplying multiple components, we can start
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             *  with the luminance computed in PM space:
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             *
3890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)             *    Lum = i * (r / a) + j * (g / a) + k * (b / a)
3990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)             *    Lum = (i * r + j * g + k * b) / a
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             *    Lum = Lum'(PM) / a
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             *
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)             *  Then the filter function is:
43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)             *
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             *    C' = [ Lum * a, Lum * r, Lum * g, Lum * b ]
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             *
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             *  which is equivalent to:
4790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)             *
487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch             *    C' = [ Lum'(PM), Lum * r, Lum * g, Lum * b ]
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             */
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            unsigned pm_lum = SkComputeLuminance(r, g, b);
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            unsigned lum = SkUnPreMultiply::ApplyScale(table[a], pm_lum);
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
53a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)            c = SkPackARGB32(pm_lum,
54a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                             SkMulDiv255Round(r, lum),
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                             SkMulDiv255Round(g, lum),
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             SkMulDiv255Round(b, lum));
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        dst[i] = c;
60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SkColorFilter* SkLumaColorFilter::Create() {
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SkNEW(SkLumaColorFilter);
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SkLumaColorFilter::SkLumaColorFilter()
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : INHERITED() {
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SkLumaColorFilter::SkLumaColorFilter(SkFlattenableReadBuffer& buffer)
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : INHERITED(buffer) {
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void SkLumaColorFilter::flatten(SkFlattenableWriteBuffer&) const {
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef SK_DEVELOPER
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SkLumaColorFilter::toString(SkString* str) const {
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    str->append("SkLumaColorFilter ");
81a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if SK_SUPPORT_GPU
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class LumaColorFilterEffect : public GrEffect {
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)public:
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static GrEffectRef* Create() {
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        AutoEffectUnref effect(SkNEW(LumaColorFilterEffect));
89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        return CreateEffectRef(effect);
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static const char* Name() { return "Luminance-to-Alpha"; }
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return GrTBackendEffectFactory<LumaColorFilterEffect>::getInstance();
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
97ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    virtual void getConstantColorComponents(GrColor* color,
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            uint32_t* validFlags) const SK_OVERRIDE {
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        *validFlags = 0;
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
102ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    class GLEffect : public GrGLEffect {
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public:
105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        GLEffect(const GrBackendEffectFactory& factory,
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 const GrDrawEffect&)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        : INHERITED(factory) {
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        static EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&) {
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            // this class always generates the same code.
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return 0;
113c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        }
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        virtual void emitCode(GrGLShaderBuilder* builder,
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              const GrDrawEffect&,
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              EffectKey,
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              const char* outputColor,
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              const char* inputColor,
1207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                              const TransformedCoordsArray&,
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              const TextureSamplerArray&) SK_OVERRIDE {
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if (NULL == inputColor) {
123eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                inputColor = "vec4(1)";
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            }
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            // The max() is to guard against 0 / 0 during unpremul when the incoming color is
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            // transparent black.
128868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            builder->fsCodeAppendf("\tfloat nonZeroAlpha = max(%s.a, 0.00001);\n", inputColor);
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            builder->fsCodeAppendf("\tfloat luma = dot(vec3(%f, %f, %f), %s.rgb);\n",
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   SK_ITU_BT709_LUM_COEFF_R,
131868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                   SK_ITU_BT709_LUM_COEFF_G,
132868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                   SK_ITU_BT709_LUM_COEFF_B,
133a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                                   inputColor);
134ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch            builder->fsCodeAppendf("\t%s = vec4(%s.rgb * luma / nonZeroAlpha, luma);\n",
135ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch                                   outputColor, inputColor);
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
139c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    private:
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        typedef GrGLEffect INHERITED;
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    };
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)private:
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE {
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return true;
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GrEffectRef* SkLumaColorFilter::asNewEffect(GrContext*) const {
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return LumaColorFilterEffect::Create();
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)