1/*
2 * Copyright 2013 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkLumaColorFilter.h"
9
10#include "SkColorPriv.h"
11#include "SkRasterPipeline.h"
12#include "SkString.h"
13
14#if SK_SUPPORT_GPU
15#include "GrContext.h"
16#include "glsl/GrGLSLFragmentProcessor.h"
17#include "glsl/GrGLSLFragmentShaderBuilder.h"
18#endif
19
20void SkLumaColorFilter::filterSpan(const SkPMColor src[], int count,
21                                   SkPMColor dst[]) const {
22    for (int i = 0; i < count; ++i) {
23        SkPMColor c = src[i];
24
25        /*
26         * While LuminanceToAlpha is defined to operate on un-premultiplied
27         * inputs, due to the final alpha scaling it can be computed based on
28         * premultipled components:
29         *
30         *   LumA = (k1 * r / a + k2 * g / a + k3 * b / a) * a
31         *   LumA = (k1 * r + k2 * g + k3 * b)
32         */
33        unsigned luma = SkComputeLuminance(SkGetPackedR32(c),
34                                           SkGetPackedG32(c),
35                                           SkGetPackedB32(c));
36        dst[i] = SkPackARGB32(luma, 0, 0, 0);
37    }
38}
39
40bool SkLumaColorFilter::onAppendStages(SkRasterPipeline* p,
41                                       SkColorSpace* dst,
42                                       SkArenaAlloc* scratch,
43                                       bool shaderIsOpaque) const {
44    p->append(SkRasterPipeline::luminance_to_alpha);
45    return true;
46}
47
48sk_sp<SkColorFilter> SkLumaColorFilter::Make() {
49    return sk_sp<SkColorFilter>(new SkLumaColorFilter);
50}
51
52SkLumaColorFilter::SkLumaColorFilter() : INHERITED() {}
53
54sk_sp<SkFlattenable> SkLumaColorFilter::CreateProc(SkReadBuffer&) {
55    return Make();
56}
57
58void SkLumaColorFilter::flatten(SkWriteBuffer&) const {}
59
60#ifndef SK_IGNORE_TO_STRING
61void SkLumaColorFilter::toString(SkString* str) const {
62    str->append("SkLumaColorFilter ");
63}
64#endif
65
66#if SK_SUPPORT_GPU
67class LumaColorFilterEffect : public GrFragmentProcessor {
68public:
69    static sk_sp<GrFragmentProcessor> Make() {
70        return sk_sp<GrFragmentProcessor>(new LumaColorFilterEffect);
71    }
72
73    const char* name() const override { return "Luminance-to-Alpha"; }
74
75    class GLSLProcessor : public GrGLSLFragmentProcessor {
76    public:
77        static void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*) {}
78
79        void emitCode(EmitArgs& args) override {
80            if (nullptr == args.fInputColor) {
81                args.fInputColor = "vec4(1)";
82            }
83
84            GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
85            fragBuilder->codeAppendf("\tfloat luma = dot(vec3(%f, %f, %f), %s.rgb);\n",
86                                     SK_ITU_BT709_LUM_COEFF_R,
87                                     SK_ITU_BT709_LUM_COEFF_G,
88                                     SK_ITU_BT709_LUM_COEFF_B,
89                                     args.fInputColor);
90            fragBuilder->codeAppendf("\t%s = vec4(0, 0, 0, luma);\n",
91                                     args.fOutputColor);
92
93        }
94
95    private:
96        typedef GrGLSLFragmentProcessor INHERITED;
97    };
98
99private:
100    LumaColorFilterEffect() : INHERITED(kConstantOutputForConstantInput_OptimizationFlag) {
101        this->initClassID<LumaColorFilterEffect>();
102    }
103
104    GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
105        return new GLSLProcessor;
106    }
107
108    virtual void onGetGLSLProcessorKey(const GrShaderCaps& caps,
109                                       GrProcessorKeyBuilder* b) const override {
110        GLSLProcessor::GenKey(*this, caps, b);
111    }
112
113    bool onIsEqual(const GrFragmentProcessor&) const override { return true; }
114
115    GrColor4f constantOutputForConstantInput(GrColor4f input) const override {
116        float luma = SK_ITU_BT709_LUM_COEFF_R * input.fRGBA[0] +
117                     SK_ITU_BT709_LUM_COEFF_G * input.fRGBA[1] +
118                     SK_ITU_BT709_LUM_COEFF_B * input.fRGBA[2];
119        return GrColor4f(0, 0, 0, luma);
120    }
121
122    typedef GrFragmentProcessor INHERITED;
123};
124
125sk_sp<GrFragmentProcessor> SkLumaColorFilter::asFragmentProcessor(GrContext*, SkColorSpace*) const {
126    return LumaColorFilterEffect::Make();
127}
128#endif
129