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 (NULL != 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    this->INHERITED::flatten(buffer);
307    SkASSERT(sizeof(fMatrix.fMat)/sizeof(SkScalar) == 20);
308    buffer.writeScalarArray(fMatrix.fMat, 20);
309}
310
311SkColorMatrixFilter::SkColorMatrixFilter(SkReadBuffer& buffer)
312        : INHERITED(buffer) {
313    SkASSERT(buffer.getArrayCount() == 20);
314    if (buffer.readScalarArray(fMatrix.fMat, 20)) {
315        this->initState(fMatrix.fMat);
316    }
317}
318
319bool SkColorMatrixFilter::asColorMatrix(SkScalar matrix[20]) const {
320    if (matrix) {
321        memcpy(matrix, fMatrix.fMat, 20 * sizeof(SkScalar));
322    }
323    return true;
324}
325
326#if SK_SUPPORT_GPU
327#include "GrEffect.h"
328#include "GrTBackendEffectFactory.h"
329#include "gl/GrGLEffect.h"
330
331class ColorMatrixEffect : public GrEffect {
332public:
333    static GrEffectRef* Create(const SkColorMatrix& matrix) {
334        AutoEffectUnref effect(SkNEW_ARGS(ColorMatrixEffect, (matrix)));
335        return CreateEffectRef(effect);
336    }
337
338    static const char* Name() { return "Color Matrix"; }
339
340    virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
341        return GrTBackendEffectFactory<ColorMatrixEffect>::getInstance();
342    }
343
344    virtual void getConstantColorComponents(GrColor* color,
345                                            uint32_t* validFlags) const SK_OVERRIDE {
346        // We only bother to check whether the alpha channel will be constant. If SkColorMatrix had
347        // type flags it might be worth checking the other components.
348
349        // The matrix is defined such the 4th row determines the output alpha. The first four
350        // columns of that row multiply the input r, g, b, and a, respectively, and the last column
351        // is the "translation".
352        static const uint32_t kRGBAFlags[] = {
353            kR_GrColorComponentFlag,
354            kG_GrColorComponentFlag,
355            kB_GrColorComponentFlag,
356            kA_GrColorComponentFlag
357        };
358        static const int kShifts[] = {
359            GrColor_SHIFT_R, GrColor_SHIFT_G, GrColor_SHIFT_B, GrColor_SHIFT_A,
360        };
361        enum {
362            kAlphaRowStartIdx = 15,
363            kAlphaRowTranslateIdx = 19,
364        };
365
366        SkScalar outputA = 0;
367        for (int i = 0; i < 4; ++i) {
368            // If any relevant component of the color to be passed through the matrix is non-const
369            // then we can't know the final result.
370            if (0 != fMatrix.fMat[kAlphaRowStartIdx + i]) {
371                if (!(*validFlags & kRGBAFlags[i])) {
372                    *validFlags = 0;
373                    return;
374                } else {
375                    uint32_t component = (*color >> kShifts[i]) & 0xFF;
376                    outputA += fMatrix.fMat[kAlphaRowStartIdx + i] * component;
377                }
378            }
379        }
380        outputA += fMatrix.fMat[kAlphaRowTranslateIdx];
381        *validFlags = kA_GrColorComponentFlag;
382        // We pin the color to [0,1]. This would happen to the *final* color output from the frag
383        // shader but currently the effect does not pin its own output. So in the case of over/
384        // underflow this may deviate from the actual result. Maybe the effect should pin its
385        // result if the matrix could over/underflow for any component?
386        *color = static_cast<uint8_t>(SkScalarPin(outputA, 0, 255)) << GrColor_SHIFT_A;
387    }
388
389    GR_DECLARE_EFFECT_TEST;
390
391    class GLEffect : public GrGLEffect {
392    public:
393        // this class always generates the same code.
394        static EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&) { return 0; }
395
396        GLEffect(const GrBackendEffectFactory& factory,
397                 const GrDrawEffect&)
398        : INHERITED(factory) {
399        }
400
401        virtual void emitCode(GrGLShaderBuilder* builder,
402                              const GrDrawEffect&,
403                              EffectKey,
404                              const char* outputColor,
405                              const char* inputColor,
406                              const TransformedCoordsArray&,
407                              const TextureSamplerArray&) SK_OVERRIDE {
408            fMatrixHandle = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
409                                                kMat44f_GrSLType,
410                                                "ColorMatrix");
411            fVectorHandle = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
412                                                kVec4f_GrSLType,
413                                                "ColorMatrixVector");
414
415            if (NULL == inputColor) {
416                // could optimize this case, but we aren't for now.
417                inputColor = "vec4(1)";
418            }
419            // The max() is to guard against 0 / 0 during unpremul when the incoming color is
420            // transparent black.
421            builder->fsCodeAppendf("\tfloat nonZeroAlpha = max(%s.a, 0.00001);\n", inputColor);
422            builder->fsCodeAppendf("\t%s = %s * vec4(%s.rgb / nonZeroAlpha, nonZeroAlpha) + %s;\n",
423                                   outputColor,
424                                   builder->getUniformCStr(fMatrixHandle),
425                                   inputColor,
426                                   builder->getUniformCStr(fVectorHandle));
427            builder->fsCodeAppendf("\t%s = clamp(%s, 0.0, 1.0);\n", outputColor, outputColor);
428            builder->fsCodeAppendf("\t%s.rgb *= %s.a;\n", outputColor, outputColor);
429        }
430
431        virtual void setData(const GrGLUniformManager& uniManager,
432                             const GrDrawEffect& drawEffect) SK_OVERRIDE {
433            const ColorMatrixEffect& cme = drawEffect.castEffect<ColorMatrixEffect>();
434            const float* m = cme.fMatrix.fMat;
435            // The GL matrix is transposed from SkColorMatrix.
436            GrGLfloat mt[]  = {
437                m[0], m[5], m[10], m[15],
438                m[1], m[6], m[11], m[16],
439                m[2], m[7], m[12], m[17],
440                m[3], m[8], m[13], m[18],
441            };
442            static const float kScale = 1.0f / 255.0f;
443            GrGLfloat vec[] = {
444                m[4] * kScale, m[9] * kScale, m[14] * kScale, m[19] * kScale,
445            };
446            uniManager.setMatrix4fv(fMatrixHandle, 1, mt);
447            uniManager.set4fv(fVectorHandle, 1, vec);
448        }
449
450    private:
451        GrGLUniformManager::UniformHandle fMatrixHandle;
452        GrGLUniformManager::UniformHandle fVectorHandle;
453
454        typedef GrGLEffect INHERITED;
455    };
456
457private:
458    ColorMatrixEffect(const SkColorMatrix& matrix) : fMatrix(matrix) {}
459
460    virtual bool onIsEqual(const GrEffect& s) const {
461        const ColorMatrixEffect& cme = CastEffect<ColorMatrixEffect>(s);
462        return cme.fMatrix == fMatrix;
463    }
464
465    SkColorMatrix fMatrix;
466
467    typedef GrEffect INHERITED;
468};
469
470GR_DEFINE_EFFECT_TEST(ColorMatrixEffect);
471
472GrEffectRef* ColorMatrixEffect::TestCreate(SkRandom* random,
473                                           GrContext*,
474                                           const GrDrawTargetCaps&,
475                                           GrTexture* dummyTextures[2]) {
476    SkColorMatrix colorMatrix;
477    for (size_t i = 0; i < SK_ARRAY_COUNT(colorMatrix.fMat); ++i) {
478        colorMatrix.fMat[i] = random->nextSScalar1();
479    }
480    return ColorMatrixEffect::Create(colorMatrix);
481}
482
483GrEffectRef* SkColorMatrixFilter::asNewEffect(GrContext*) const {
484    return ColorMatrixEffect::Create(fMatrix);
485}
486
487#endif
488
489#ifndef SK_IGNORE_TO_STRING
490void SkColorMatrixFilter::toString(SkString* str) const {
491    str->append("SkColorMatrixFilter: ");
492
493    str->append("matrix: (");
494    for (int i = 0; i < 20; ++i) {
495        str->appendScalar(fMatrix.fMat[i]);
496        if (i < 19) {
497            str->append(", ");
498        }
499    }
500    str->append(")");
501}
502#endif
503