1
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8#include "SkColorMatrixFilter.h"
9#include "SkColorMatrix.h"
10#include "SkColorPriv.h"
11#include "SkReadBuffer.h"
12#include "SkWriteBuffer.h"
13#include "SkUnPreMultiply.h"
14#include "SkString.h"
15
16static int32_t rowmul4(const int32_t array[], unsigned r, unsigned g,
17                          unsigned b, unsigned a) {
18    return array[0] * r + array[1] * g  + array[2] * b + array[3] * a + array[4];
19}
20
21static int32_t rowmul3(const int32_t array[], unsigned r, unsigned g,
22                       unsigned b) {
23    return array[0] * r + array[1] * g  + array[2] * b + array[4];
24}
25
26static void General(const SkColorMatrixFilter::State& state,
27                    unsigned r, unsigned g, unsigned b, unsigned a,
28                    int32_t* SK_RESTRICT result) {
29    const int32_t* SK_RESTRICT array = state.fArray;
30    const int shift = state.fShift;
31
32    result[0] = rowmul4(&array[0], r, g, b, a) >> shift;
33    result[1] = rowmul4(&array[5], r, g, b, a) >> shift;
34    result[2] = rowmul4(&array[10], r, g, b, a) >> shift;
35    result[3] = rowmul4(&array[15], r, g, b, a) >> shift;
36}
37
38static void General16(const SkColorMatrixFilter::State& state,
39                      unsigned r, unsigned g, unsigned b, unsigned a,
40                      int32_t* SK_RESTRICT result) {
41    const int32_t* SK_RESTRICT array = state.fArray;
42
43    result[0] = rowmul4(&array[0], r, g, b, a) >> 16;
44    result[1] = rowmul4(&array[5], r, g, b, a) >> 16;
45    result[2] = rowmul4(&array[10], r, g, b, a) >> 16;
46    result[3] = rowmul4(&array[15], r, g, b, a) >> 16;
47}
48
49static void AffineAdd(const SkColorMatrixFilter::State& state,
50                      unsigned r, unsigned g, unsigned b, unsigned a,
51                      int32_t* SK_RESTRICT result) {
52    const int32_t* SK_RESTRICT array = state.fArray;
53    const int shift = state.fShift;
54
55    result[0] = rowmul3(&array[0], r, g, b) >> shift;
56    result[1] = rowmul3(&array[5], r, g, b) >> shift;
57    result[2] = rowmul3(&array[10], r, g, b) >> shift;
58    result[3] = a;
59}
60
61static void AffineAdd16(const SkColorMatrixFilter::State& state,
62                        unsigned r, unsigned g, unsigned b, unsigned a,
63                        int32_t* SK_RESTRICT result) {
64    const int32_t* SK_RESTRICT array = state.fArray;
65
66    result[0] = rowmul3(&array[0], r, g, b) >> 16;
67    result[1] = rowmul3(&array[5], r, g, b) >> 16;
68    result[2] = rowmul3(&array[10], r, g, b) >> 16;
69    result[3] = a;
70}
71
72static void ScaleAdd(const SkColorMatrixFilter::State& state,
73                     unsigned r, unsigned g, unsigned b, unsigned a,
74                     int32_t* SK_RESTRICT result) {
75    const int32_t* SK_RESTRICT array = state.fArray;
76    const int shift = state.fShift;
77
78    // cast to (int) to keep the expression signed for the shift
79    result[0] = (array[SkColorMatrix::kR_Scale] * (int)r + array[4]) >> shift;
80    result[1] = (array[SkColorMatrix::kG_Scale] * (int)g + array[9]) >> shift;
81    result[2] = (array[SkColorMatrix::kB_Scale] * (int)b + array[14]) >> shift;
82    result[3] = a;
83}
84
85static void ScaleAdd16(const SkColorMatrixFilter::State& state,
86                       unsigned r, unsigned g, unsigned b, unsigned a,
87                       int32_t* SK_RESTRICT result) {
88    const int32_t* SK_RESTRICT array = state.fArray;
89
90    // cast to (int) to keep the expression signed for the shift
91    result[0] = (array[SkColorMatrix::kR_Scale] * (int)r + array[4]) >> 16;
92    result[1] = (array[SkColorMatrix::kG_Scale] * (int)g + array[9]) >> 16;
93    result[2] = (array[SkColorMatrix::kB_Scale] * (int)b + array[14]) >> 16;
94    result[3] = a;
95}
96
97static void Add(const SkColorMatrixFilter::State& state,
98                unsigned r, unsigned g, unsigned b, unsigned a,
99                int32_t* SK_RESTRICT result) {
100    const int32_t* SK_RESTRICT array = state.fArray;
101    const int shift = state.fShift;
102
103    result[0] = r + (array[SkColorMatrix::kR_Trans] >> shift);
104    result[1] = g + (array[SkColorMatrix::kG_Trans] >> shift);
105    result[2] = b + (array[SkColorMatrix::kB_Trans] >> shift);
106    result[3] = a;
107}
108
109static void Add16(const SkColorMatrixFilter::State& state,
110                  unsigned r, unsigned g, unsigned b, unsigned a,
111                  int32_t* SK_RESTRICT result) {
112    const int32_t* SK_RESTRICT array = state.fArray;
113
114    result[0] = r + (array[SkColorMatrix::kR_Trans] >> 16);
115    result[1] = g + (array[SkColorMatrix::kG_Trans] >> 16);
116    result[2] = b + (array[SkColorMatrix::kB_Trans] >> 16);
117    result[3] = a;
118}
119
120#define kNO_ALPHA_FLAGS (SkColorFilter::kAlphaUnchanged_Flag |  \
121                         SkColorFilter::kHasFilter16_Flag)
122
123// src is [20] but some compilers won't accept __restrict__ on anything
124// but an raw pointer or reference
125void SkColorMatrixFilter::initState(const SkScalar* SK_RESTRICT src) {
126    int32_t* array = fState.fArray;
127    SkFixed max = 0;
128    for (int i = 0; i < 20; i++) {
129        SkFixed value = SkScalarToFixed(src[i]);
130        array[i] = value;
131        value = SkAbs32(value);
132        max = SkMax32(max, value);
133    }
134
135    /*  All of fArray[] values must fit in 23 bits, to safely allow me to
136        multiply them by 8bit unsigned values, and get a signed answer without
137        overflow. This means clz needs to be 9 or bigger
138    */
139    int bits = SkCLZ(max);
140    int32_t one = SK_Fixed1;
141
142    fState.fShift = 16; // we are starting out as fixed 16.16
143    if (bits < 9) {
144        bits = 9 - bits;
145        fState.fShift -= bits;
146        for (int i = 0; i < 20; i++) {
147            array[i] >>= bits;
148        }
149        one >>= bits;
150    }
151
152    // check if we have to munge Alpha
153    int32_t changesAlpha = (array[15] | array[16] | array[17] |
154                            (array[18] - one) | array[19]);
155    int32_t usesAlpha = (array[3] | array[8] | array[13]);
156    bool shiftIs16 = (16 == fState.fShift);
157
158    if (changesAlpha | usesAlpha) {
159        fProc = shiftIs16 ? General16 : General;
160        fFlags = changesAlpha ? 0 : SkColorFilter::kAlphaUnchanged_Flag;
161    } else {
162        fFlags = kNO_ALPHA_FLAGS;
163
164        int32_t needsScale = (array[SkColorMatrix::kR_Scale] - one) |
165                             (array[SkColorMatrix::kG_Scale] - one) |
166                             (array[SkColorMatrix::kB_Scale] - one);
167
168        int32_t needs3x3 =  array[1] | array[2] |     // red off-axis
169                            array[5] | array[7] |     // green off-axis
170                            array[10] | array[11];    // blue off-axis
171
172        if (needs3x3) {
173            fProc = shiftIs16 ? AffineAdd16 : AffineAdd;
174        } else if (needsScale) {
175            fProc = shiftIs16 ? ScaleAdd16 : ScaleAdd;
176        } else if (array[SkColorMatrix::kR_Trans] |
177                   array[SkColorMatrix::kG_Trans] |
178                   array[SkColorMatrix::kB_Trans]) {
179            fProc = shiftIs16 ? Add16 : Add;
180        } else {
181            fProc = NULL;   // identity
182        }
183    }
184
185    /*  preround our add values so we get a rounded shift. We do this after we
186        analyze the array, so we don't miss the case where the caller has zeros
187        which could make us accidentally take the General or Add case.
188    */
189    if (fProc) {
190        int32_t add = 1 << (fState.fShift - 1);
191        array[4] += add;
192        array[9] += add;
193        array[14] += add;
194        array[19] += add;
195    }
196}
197
198///////////////////////////////////////////////////////////////////////////////
199
200static int32_t pin(int32_t value, int32_t max) {
201    if (value < 0) {
202        value = 0;
203    }
204    if (value > max) {
205        value = max;
206    }
207    return value;
208}
209
210SkColorMatrixFilter::SkColorMatrixFilter(const SkColorMatrix& cm) : fMatrix(cm) {
211    this->initState(cm.fMat);
212}
213
214SkColorMatrixFilter::SkColorMatrixFilter(const SkScalar array[20]) {
215    memcpy(fMatrix.fMat, array, 20 * sizeof(SkScalar));
216    this->initState(array);
217}
218
219uint32_t SkColorMatrixFilter::getFlags() const {
220    return this->INHERITED::getFlags() | fFlags;
221}
222
223void SkColorMatrixFilter::filterSpan(const SkPMColor src[], int count,
224                                     SkPMColor dst[]) const {
225    Proc proc = fProc;
226    const State& state = fState;
227    int32_t result[4];
228
229    if (NULL == proc) {
230        if (src != dst) {
231            memcpy(dst, src, count * sizeof(SkPMColor));
232        }
233        return;
234    }
235
236    const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleTable();
237
238    for (int i = 0; i < count; i++) {
239        SkPMColor c = src[i];
240
241        unsigned r = SkGetPackedR32(c);
242        unsigned g = SkGetPackedG32(c);
243        unsigned b = SkGetPackedB32(c);
244        unsigned a = SkGetPackedA32(c);
245
246        // need our components to be un-premultiplied
247        if (255 != a) {
248            SkUnPreMultiply::Scale scale = table[a];
249            r = SkUnPreMultiply::ApplyScale(scale, r);
250            g = SkUnPreMultiply::ApplyScale(scale, g);
251            b = SkUnPreMultiply::ApplyScale(scale, b);
252
253            SkASSERT(r <= 255);
254            SkASSERT(g <= 255);
255            SkASSERT(b <= 255);
256        }
257
258        proc(state, r, g, b, a, result);
259
260        r = pin(result[0], SK_R32_MASK);
261        g = pin(result[1], SK_G32_MASK);
262        b = pin(result[2], SK_B32_MASK);
263        a = pin(result[3], SK_A32_MASK);
264        // re-prepremultiply if needed
265        dst[i] = SkPremultiplyARGBInline(a, r, g, b);
266    }
267}
268
269void SkColorMatrixFilter::filterSpan16(const uint16_t src[], int count,
270                                       uint16_t dst[]) const {
271    SkASSERT(fFlags & SkColorFilter::kHasFilter16_Flag);
272
273    Proc   proc = fProc;
274    const State& state = fState;
275    int32_t result[4];
276
277    if (NULL == proc) {
278        if (src != dst) {
279            memcpy(dst, src, count * sizeof(uint16_t));
280        }
281        return;
282    }
283
284    for (int i = 0; i < count; i++) {
285        uint16_t c = src[i];
286
287        // expand to 8bit components (since our matrix translate is 8bit biased
288        unsigned r = SkPacked16ToR32(c);
289        unsigned g = SkPacked16ToG32(c);
290        unsigned b = SkPacked16ToB32(c);
291
292        proc(state, r, g, b, 0, result);
293
294        r = pin(result[0], SK_R32_MASK);
295        g = pin(result[1], SK_G32_MASK);
296        b = pin(result[2], SK_B32_MASK);
297
298        // now packed it back down to 16bits (hmmm, could dither...)
299        dst[i] = SkPack888ToRGB16(r, g, b);
300    }
301}
302
303///////////////////////////////////////////////////////////////////////////////
304
305void SkColorMatrixFilter::flatten(SkWriteBuffer& buffer) const {
306    SkASSERT(sizeof(fMatrix.fMat)/sizeof(SkScalar) == 20);
307    buffer.writeScalarArray(fMatrix.fMat, 20);
308}
309
310#ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
311SkColorMatrixFilter::SkColorMatrixFilter(SkReadBuffer& buffer) : INHERITED(buffer) {
312    SkASSERT(buffer.getArrayCount() == 20);
313    if (buffer.readScalarArray(fMatrix.fMat, 20)) {
314        this->initState(fMatrix.fMat);
315    }
316}
317#endif
318
319SkFlattenable* SkColorMatrixFilter::CreateProc(SkReadBuffer& buffer) {
320    SkColorMatrix matrix;
321    if (buffer.readScalarArray(matrix.fMat, 20)) {
322        return Create(matrix);
323    }
324    return NULL;
325}
326
327bool SkColorMatrixFilter::asColorMatrix(SkScalar matrix[20]) const {
328    if (matrix) {
329        memcpy(matrix, fMatrix.fMat, 20 * sizeof(SkScalar));
330    }
331    return true;
332}
333
334#if SK_SUPPORT_GPU
335#include "GrProcessor.h"
336#include "GrTBackendProcessorFactory.h"
337#include "gl/GrGLProcessor.h"
338#include "gl/builders/GrGLProgramBuilder.h"
339
340class ColorMatrixEffect : public GrFragmentProcessor {
341public:
342    static GrFragmentProcessor* Create(const SkColorMatrix& matrix) {
343        return SkNEW_ARGS(ColorMatrixEffect, (matrix));
344    }
345
346    static const char* Name() { return "Color Matrix"; }
347
348    virtual const GrBackendFragmentProcessorFactory& getFactory() const SK_OVERRIDE {
349        return GrTBackendFragmentProcessorFactory<ColorMatrixEffect>::getInstance();
350    }
351
352    virtual void getConstantColorComponents(GrColor* color,
353                                            uint32_t* validFlags) const SK_OVERRIDE {
354        // We only bother to check whether the alpha channel will be constant. If SkColorMatrix had
355        // type flags it might be worth checking the other components.
356
357        // The matrix is defined such the 4th row determines the output alpha. The first four
358        // columns of that row multiply the input r, g, b, and a, respectively, and the last column
359        // is the "translation".
360        static const uint32_t kRGBAFlags[] = {
361            kR_GrColorComponentFlag,
362            kG_GrColorComponentFlag,
363            kB_GrColorComponentFlag,
364            kA_GrColorComponentFlag
365        };
366        static const int kShifts[] = {
367            GrColor_SHIFT_R, GrColor_SHIFT_G, GrColor_SHIFT_B, GrColor_SHIFT_A,
368        };
369        enum {
370            kAlphaRowStartIdx = 15,
371            kAlphaRowTranslateIdx = 19,
372        };
373
374        SkScalar outputA = 0;
375        for (int i = 0; i < 4; ++i) {
376            // If any relevant component of the color to be passed through the matrix is non-const
377            // then we can't know the final result.
378            if (0 != fMatrix.fMat[kAlphaRowStartIdx + i]) {
379                if (!(*validFlags & kRGBAFlags[i])) {
380                    *validFlags = 0;
381                    return;
382                } else {
383                    uint32_t component = (*color >> kShifts[i]) & 0xFF;
384                    outputA += fMatrix.fMat[kAlphaRowStartIdx + i] * component;
385                }
386            }
387        }
388        outputA += fMatrix.fMat[kAlphaRowTranslateIdx];
389        *validFlags = kA_GrColorComponentFlag;
390        // We pin the color to [0,1]. This would happen to the *final* color output from the frag
391        // shader but currently the effect does not pin its own output. So in the case of over/
392        // underflow this may deviate from the actual result. Maybe the effect should pin its
393        // result if the matrix could over/underflow for any component?
394        *color = static_cast<uint8_t>(SkScalarPin(outputA, 0, 255)) << GrColor_SHIFT_A;
395    }
396
397    GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
398
399    class GLProcessor : public GrGLFragmentProcessor {
400    public:
401        // this class always generates the same code.
402        static void GenKey(const GrProcessor&, const GrGLCaps&, GrProcessorKeyBuilder* b) {}
403
404        GLProcessor(const GrBackendProcessorFactory& factory,
405                 const GrProcessor&)
406        : INHERITED(factory) {
407        }
408
409        virtual void emitCode(GrGLProgramBuilder* builder,
410                              const GrFragmentProcessor&,
411                              const GrProcessorKey&,
412                              const char* outputColor,
413                              const char* inputColor,
414                              const TransformedCoordsArray&,
415                              const TextureSamplerArray&) SK_OVERRIDE {
416            fMatrixHandle = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
417                                                kMat44f_GrSLType,
418                                                "ColorMatrix");
419            fVectorHandle = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
420                                                kVec4f_GrSLType,
421                                                "ColorMatrixVector");
422
423            if (NULL == inputColor) {
424                // could optimize this case, but we aren't for now.
425                inputColor = "vec4(1)";
426            }
427            GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
428            // The max() is to guard against 0 / 0 during unpremul when the incoming color is
429            // transparent black.
430            fsBuilder->codeAppendf("\tfloat nonZeroAlpha = max(%s.a, 0.00001);\n", inputColor);
431            fsBuilder->codeAppendf("\t%s = %s * vec4(%s.rgb / nonZeroAlpha, nonZeroAlpha) + %s;\n",
432                                   outputColor,
433                                   builder->getUniformCStr(fMatrixHandle),
434                                   inputColor,
435                                   builder->getUniformCStr(fVectorHandle));
436            fsBuilder->codeAppendf("\t%s = clamp(%s, 0.0, 1.0);\n", outputColor, outputColor);
437            fsBuilder->codeAppendf("\t%s.rgb *= %s.a;\n", outputColor, outputColor);
438        }
439
440        virtual void setData(const GrGLProgramDataManager& uniManager,
441                             const GrProcessor& proc) SK_OVERRIDE {
442            const ColorMatrixEffect& cme = proc.cast<ColorMatrixEffect>();
443            const float* m = cme.fMatrix.fMat;
444            // The GL matrix is transposed from SkColorMatrix.
445            GrGLfloat mt[]  = {
446                m[0], m[5], m[10], m[15],
447                m[1], m[6], m[11], m[16],
448                m[2], m[7], m[12], m[17],
449                m[3], m[8], m[13], m[18],
450            };
451            static const float kScale = 1.0f / 255.0f;
452            GrGLfloat vec[] = {
453                m[4] * kScale, m[9] * kScale, m[14] * kScale, m[19] * kScale,
454            };
455            uniManager.setMatrix4fv(fMatrixHandle, 1, mt);
456            uniManager.set4fv(fVectorHandle, 1, vec);
457        }
458
459    private:
460        GrGLProgramDataManager::UniformHandle fMatrixHandle;
461        GrGLProgramDataManager::UniformHandle fVectorHandle;
462
463        typedef GrGLFragmentProcessor INHERITED;
464    };
465
466private:
467    ColorMatrixEffect(const SkColorMatrix& matrix) : fMatrix(matrix) {}
468
469    virtual bool onIsEqual(const GrProcessor& s) const {
470        const ColorMatrixEffect& cme = s.cast<ColorMatrixEffect>();
471        return cme.fMatrix == fMatrix;
472    }
473
474    SkColorMatrix fMatrix;
475
476    typedef GrFragmentProcessor INHERITED;
477};
478
479GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ColorMatrixEffect);
480
481GrFragmentProcessor* ColorMatrixEffect::TestCreate(SkRandom* random,
482                                                   GrContext*,
483                                                   const GrDrawTargetCaps&,
484                                                   GrTexture* dummyTextures[2]) {
485    SkColorMatrix colorMatrix;
486    for (size_t i = 0; i < SK_ARRAY_COUNT(colorMatrix.fMat); ++i) {
487        colorMatrix.fMat[i] = random->nextSScalar1();
488    }
489    return ColorMatrixEffect::Create(colorMatrix);
490}
491
492GrFragmentProcessor* SkColorMatrixFilter::asFragmentProcessor(GrContext*) const {
493    return ColorMatrixEffect::Create(fMatrix);
494}
495
496#endif
497
498#ifndef SK_IGNORE_TO_STRING
499void SkColorMatrixFilter::toString(SkString* str) const {
500    str->append("SkColorMatrixFilter: ");
501
502    str->append("matrix: (");
503    for (int i = 0; i < 20; ++i) {
504        str->appendScalar(fMatrix.fMat[i]);
505        if (i < 19) {
506            str->append(", ");
507        }
508    }
509    str->append(")");
510}
511#endif
512