aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/effects/SkLumaColorFilter.cpp
blob: f0e58c06f8ed114fb232253cbd5a463bb56a5a56 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/*
 * 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 "SkLumaColorFilter.h"
#include "SkPM4f.h"
#include "SkColorPriv.h"
#include "SkRasterPipeline.h"
#include "SkString.h"

#if SK_SUPPORT_GPU
#include "GrContext.h"
#include "glsl/GrGLSLFragmentProcessor.h"
#include "glsl/GrGLSLFragmentShaderBuilder.h"
#endif

void SkLumaColorFilter::filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const {
    for (int i = 0; i < count; ++i) {
        SkPMColor c = src[i];

        /*
         * While LuminanceToAlpha is defined to operate on un-premultiplied
         * inputs, due to the final alpha scaling it can be computed based on
         * premultipled components:
         *
         *   LumA = (k1 * r / a + k2 * g / a + k3 * b / a) * a
         *   LumA = (k1 * r + k2 * g + k3 * b)
         */
        unsigned luma = SkComputeLuminance(SkGetPackedR32(c),
                                           SkGetPackedG32(c),
                                           SkGetPackedB32(c));
        dst[i] = SkPackARGB32(luma, 0, 0, 0);
    }
}

void SkLumaColorFilter::filterSpan4f(const SkPM4f src[], int count, SkPM4f dst[]) const {
    for (int i = 0; i < count; ++i) {
        /*
         * While LuminanceToAlpha is defined to operate on un-premultiplied
         * inputs, due to the final alpha scaling it can be computed based on
         * premultipled components:
         *
         *   LumA = (k1 * r / a + k2 * g / a + k3 * b / a) * a
         *   LumA = (k1 * r + k2 * g + k3 * b)
         */
        dst[i].fVec[SkPM4f::R] = 0;
        dst[i].fVec[SkPM4f::G] = 0;
        dst[i].fVec[SkPM4f::B] = 0;
        dst[i].fVec[SkPM4f::A] = src[i].r() * SK_LUM_COEFF_R +
                                 src[i].g() * SK_LUM_COEFF_G +
                                 src[i].b() * SK_LUM_COEFF_B;
    }
}

void SkLumaColorFilter::onAppendStages(SkRasterPipeline* p,
                                       SkColorSpace* dst,
                                       SkArenaAlloc* scratch,
                                       bool shaderIsOpaque) const {
    p->append(SkRasterPipeline::luminance_to_alpha);
}

sk_sp<SkColorFilter> SkLumaColorFilter::Make() {
    return sk_sp<SkColorFilter>(new SkLumaColorFilter);
}

SkLumaColorFilter::SkLumaColorFilter() : INHERITED() {}

sk_sp<SkFlattenable> SkLumaColorFilter::CreateProc(SkReadBuffer&) {
    return Make();
}

void SkLumaColorFilter::flatten(SkWriteBuffer&) const {}

#ifndef SK_IGNORE_TO_STRING
void SkLumaColorFilter::toString(SkString* str) const {
    str->append("SkLumaColorFilter ");
}
#endif

#if SK_SUPPORT_GPU
class LumaColorFilterEffect : public GrFragmentProcessor {
public:
    static sk_sp<GrFragmentProcessor> Make() {
        return sk_sp<GrFragmentProcessor>(new LumaColorFilterEffect);
    }

    const char* name() const override { return "Luminance-to-Alpha"; }

    class GLSLProcessor : public GrGLSLFragmentProcessor {
    public:
        static void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*) {}

        void emitCode(EmitArgs& args) override {
            if (nullptr == args.fInputColor) {
                args.fInputColor = "vec4(1)";
            }

            GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
            fragBuilder->codeAppendf("\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,
                                     args.fInputColor);
            fragBuilder->codeAppendf("\t%s = vec4(0, 0, 0, luma);\n",
                                     args.fOutputColor);

        }

    private:
        typedef GrGLSLFragmentProcessor INHERITED;
    };

private:
    LumaColorFilterEffect() : INHERITED(kConstantOutputForConstantInput_OptimizationFlag) {
        this->initClassID<LumaColorFilterEffect>();
    }

    GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
        return new GLSLProcessor;
    }

    virtual void onGetGLSLProcessorKey(const GrShaderCaps& caps,
                                       GrProcessorKeyBuilder* b) const override {
        GLSLProcessor::GenKey(*this, caps, b);
    }

    bool onIsEqual(const GrFragmentProcessor&) const override { return true; }

    GrColor4f constantOutputForConstantInput(GrColor4f input) const override {
        float luma = SK_ITU_BT709_LUM_COEFF_R * input.fRGBA[0] +
                     SK_ITU_BT709_LUM_COEFF_G * input.fRGBA[1] +
                     SK_ITU_BT709_LUM_COEFF_B * input.fRGBA[2];
        return GrColor4f(0, 0, 0, luma);
    }

    typedef GrFragmentProcessor INHERITED;
};

sk_sp<GrFragmentProcessor> SkLumaColorFilter::asFragmentProcessor(GrContext*, SkColorSpace*) const {
    return LumaColorFilterEffect::Make();
}
#endif