SkTableColorFilter.cpp revision 0067ff5e0f85084dd2b5ad9886b526482b89a116
1/*
2* Copyright 2015 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 "SkBitmap.h"
9#include "SkTableColorFilter.h"
10#include "SkColorPriv.h"
11#include "SkReadBuffer.h"
12#include "SkWriteBuffer.h"
13#include "SkUnPreMultiply.h"
14#include "SkString.h"
15
16class SkTable_ColorFilter : public SkColorFilter {
17public:
18    SkTable_ColorFilter(const uint8_t tableA[], const uint8_t tableR[],
19                        const uint8_t tableG[], const uint8_t tableB[]) {
20        fBitmap = NULL;
21        fFlags = 0;
22
23        uint8_t* dst = fStorage;
24        if (tableA) {
25            memcpy(dst, tableA, 256);
26            dst += 256;
27            fFlags |= kA_Flag;
28        }
29        if (tableR) {
30            memcpy(dst, tableR, 256);
31            dst += 256;
32            fFlags |= kR_Flag;
33        }
34        if (tableG) {
35            memcpy(dst, tableG, 256);
36            dst += 256;
37            fFlags |= kG_Flag;
38        }
39        if (tableB) {
40            memcpy(dst, tableB, 256);
41            fFlags |= kB_Flag;
42        }
43    }
44
45    virtual ~SkTable_ColorFilter() {
46        SkDELETE(fBitmap);
47    }
48
49    bool asComponentTable(SkBitmap* table) const override;
50    SkColorFilter* newComposed(const SkColorFilter* inner) const override;
51
52#if SK_SUPPORT_GPU
53    bool asFragmentProcessors(GrContext*, GrShaderDataManager*,
54                              SkTDArray<GrFragmentProcessor*>*) const override;
55#endif
56
57    void filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const override;
58
59    SK_TO_STRING_OVERRIDE()
60
61    SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkTable_ColorFilter)
62
63    enum {
64        kA_Flag = 1 << 0,
65        kR_Flag = 1 << 1,
66        kG_Flag = 1 << 2,
67        kB_Flag = 1 << 3,
68    };
69
70protected:
71    void flatten(SkWriteBuffer&) const override;
72
73private:
74    mutable const SkBitmap* fBitmap; // lazily allocated
75
76    uint8_t fStorage[256 * 4];
77    unsigned fFlags;
78
79    friend class SkTableColorFilter;
80
81    typedef SkColorFilter INHERITED;
82};
83
84static const uint8_t gIdentityTable[] = {
85    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
86    0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
87    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
88    0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
89    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
90    0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
91    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
92    0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
93    0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
94    0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
95    0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
96    0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
97    0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
98    0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
99    0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
100    0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
101    0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
102    0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
103    0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
104    0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
105    0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
106    0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
107    0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7,
108    0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
109    0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
110    0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
111    0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
112    0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
113    0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
114    0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
115    0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
116    0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
117};
118
119void SkTable_ColorFilter::filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const {
120    const uint8_t* table = fStorage;
121    const uint8_t* tableA = gIdentityTable;
122    const uint8_t* tableR = gIdentityTable;
123    const uint8_t* tableG = gIdentityTable;
124    const uint8_t* tableB = gIdentityTable;
125    if (fFlags & kA_Flag) {
126        tableA = table; table += 256;
127    }
128    if (fFlags & kR_Flag) {
129        tableR = table; table += 256;
130    }
131    if (fFlags & kG_Flag) {
132        tableG = table; table += 256;
133    }
134    if (fFlags & kB_Flag) {
135        tableB = table;
136    }
137
138    const SkUnPreMultiply::Scale* scaleTable = SkUnPreMultiply::GetScaleTable();
139    for (int i = 0; i < count; ++i) {
140        SkPMColor c = src[i];
141        unsigned a, r, g, b;
142        if (0 == c) {
143            a = r = g = b = 0;
144        } else {
145            a = SkGetPackedA32(c);
146            r = SkGetPackedR32(c);
147            g = SkGetPackedG32(c);
148            b = SkGetPackedB32(c);
149
150            if (a < 255) {
151                SkUnPreMultiply::Scale scale = scaleTable[a];
152                r = SkUnPreMultiply::ApplyScale(scale, r);
153                g = SkUnPreMultiply::ApplyScale(scale, g);
154                b = SkUnPreMultiply::ApplyScale(scale, b);
155            }
156        }
157        dst[i] = SkPremultiplyARGBInline(tableA[a], tableR[r],
158                                         tableG[g], tableB[b]);
159    }
160}
161
162#ifndef SK_IGNORE_TO_STRING
163void SkTable_ColorFilter::toString(SkString* str) const {
164    const uint8_t* table = fStorage;
165    const uint8_t* tableA = gIdentityTable;
166    const uint8_t* tableR = gIdentityTable;
167    const uint8_t* tableG = gIdentityTable;
168    const uint8_t* tableB = gIdentityTable;
169    if (fFlags & kA_Flag) {
170        tableA = table; table += 256;
171    }
172    if (fFlags & kR_Flag) {
173        tableR = table; table += 256;
174    }
175    if (fFlags & kG_Flag) {
176        tableG = table; table += 256;
177    }
178    if (fFlags & kB_Flag) {
179        tableB = table;
180    }
181
182    str->append("SkTable_ColorFilter (");
183
184    for (int i = 0; i < 256; ++i) {
185        str->appendf("%d: %d,%d,%d,%d\n",
186                     i, tableR[i], tableG[i], tableB[i], tableA[i]);
187    }
188
189    str->append(")");
190}
191#endif
192
193static const uint8_t gCountNibBits[] = {
194    0, 1, 1, 2,
195    1, 2, 2, 3,
196    1, 2, 2, 3,
197    2, 3, 3, 4
198};
199
200#include "SkPackBits.h"
201
202void SkTable_ColorFilter::flatten(SkWriteBuffer& buffer) const {
203    uint8_t storage[5*256];
204    int count = gCountNibBits[fFlags & 0xF];
205    size_t size = SkPackBits::Pack8(fStorage, count * 256, storage,
206                                    sizeof(storage));
207
208    buffer.write32(fFlags);
209    buffer.writeByteArray(storage, size);
210}
211
212SkFlattenable* SkTable_ColorFilter::CreateProc(SkReadBuffer& buffer) {
213    const int flags = buffer.read32();
214    const size_t count = gCountNibBits[flags & 0xF];
215    SkASSERT(count <= 4);
216
217    uint8_t packedStorage[5*256];
218    size_t packedSize = buffer.getArrayCount();
219    if (!buffer.validate(packedSize <= sizeof(packedStorage))) {
220        return NULL;
221    }
222    if (!buffer.readByteArray(packedStorage, packedSize)) {
223        return NULL;
224    }
225
226    uint8_t unpackedStorage[4*256];
227    size_t unpackedSize = SkPackBits::Unpack8(packedStorage, packedSize,
228                              unpackedStorage, sizeof(unpackedStorage));
229    // now check that we got the size we expected
230    if (!buffer.validate(unpackedSize == count*256)) {
231        return NULL;
232    }
233
234    const uint8_t* a = NULL;
235    const uint8_t* r = NULL;
236    const uint8_t* g = NULL;
237    const uint8_t* b = NULL;
238    const uint8_t* ptr = unpackedStorage;
239
240    if (flags & kA_Flag) {
241        a = ptr;
242        ptr += 256;
243    }
244    if (flags & kR_Flag) {
245        r = ptr;
246        ptr += 256;
247    }
248    if (flags & kG_Flag) {
249        g = ptr;
250        ptr += 256;
251    }
252    if (flags & kB_Flag) {
253        b = ptr;
254        ptr += 256;
255    }
256    return SkTableColorFilter::CreateARGB(a, r, g, b);
257}
258
259bool SkTable_ColorFilter::asComponentTable(SkBitmap* table) const {
260    if (table) {
261        if (NULL == fBitmap) {
262            SkBitmap* bmp = SkNEW(SkBitmap);
263            bmp->allocPixels(SkImageInfo::MakeA8(256, 4));
264            uint8_t* bitmapPixels = bmp->getAddr8(0, 0);
265            int offset = 0;
266            static const unsigned kFlags[] = { kA_Flag, kR_Flag, kG_Flag, kB_Flag };
267
268            for (int x = 0; x < 4; ++x) {
269                if (!(fFlags & kFlags[x])) {
270                    memcpy(bitmapPixels, gIdentityTable, sizeof(gIdentityTable));
271                } else {
272                    memcpy(bitmapPixels, fStorage + offset, 256);
273                    offset += 256;
274                }
275                bitmapPixels += 256;
276            }
277            fBitmap = bmp;
278        }
279        *table = *fBitmap;
280    }
281    return true;
282}
283
284// Combines the two lookup tables so that making a lookup using res[] has
285// the same effect as making a lookup through inner[] then outer[].
286static void combine_tables(uint8_t res[256], const uint8_t outer[256], const uint8_t inner[256]) {
287    for (int i = 0; i < 256; i++) {
288        res[i] = outer[inner[i]];
289    }
290}
291
292SkColorFilter* SkTable_ColorFilter::newComposed(const SkColorFilter* innerFilter) const {
293    SkBitmap innerBM;
294    if (!innerFilter->asComponentTable(&innerBM)) {
295        return NULL;
296    }
297
298    innerBM.lockPixels();
299    if (NULL == innerBM.getPixels()) {
300        return NULL;
301    }
302
303    const uint8_t* table = fStorage;
304    const uint8_t* tableA = gIdentityTable;
305    const uint8_t* tableR = gIdentityTable;
306    const uint8_t* tableG = gIdentityTable;
307    const uint8_t* tableB = gIdentityTable;
308    if (fFlags & kA_Flag) {
309        tableA = table; table += 256;
310    }
311    if (fFlags & kR_Flag) {
312        tableR = table; table += 256;
313    }
314    if (fFlags & kG_Flag) {
315        tableG = table; table += 256;
316    }
317    if (fFlags & kB_Flag) {
318        tableB = table;
319    }
320
321    uint8_t concatA[256];
322    uint8_t concatR[256];
323    uint8_t concatG[256];
324    uint8_t concatB[256];
325
326    combine_tables(concatA, tableA, innerBM.getAddr8(0, 0));
327    combine_tables(concatR, tableR, innerBM.getAddr8(0, 1));
328    combine_tables(concatG, tableG, innerBM.getAddr8(0, 2));
329    combine_tables(concatB, tableB, innerBM.getAddr8(0, 3));
330
331    return SkTableColorFilter::CreateARGB(concatA, concatR, concatG, concatB);
332}
333
334#if SK_SUPPORT_GPU
335
336#include "GrFragmentProcessor.h"
337#include "GrInvariantOutput.h"
338#include "SkGr.h"
339#include "effects/GrTextureStripAtlas.h"
340#include "gl/GrGLProcessor.h"
341#include "gl/builders/GrGLProgramBuilder.h"
342
343class ColorTableEffect : public GrFragmentProcessor {
344public:
345    static GrFragmentProcessor* Create(GrContext* context, SkBitmap bitmap, unsigned flags);
346
347    virtual ~ColorTableEffect();
348
349    const char* name() const override { return "ColorTable"; }
350
351    void getGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
352
353    GrGLFragmentProcessor* createGLInstance() const override;
354
355    const GrTextureStripAtlas* atlas() const { return fAtlas; }
356    int atlasRow() const { return fRow; }
357
358private:
359    bool onIsEqual(const GrFragmentProcessor&) const override;
360
361    void onComputeInvariantOutput(GrInvariantOutput* inout) const override;
362
363    ColorTableEffect(GrTexture* texture, GrTextureStripAtlas* atlas, int row, unsigned flags);
364
365    GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
366
367    GrTextureAccess         fTextureAccess;
368
369    // currently not used in shader code, just to assist onComputeInvariantOutput().
370    unsigned                fFlags;
371
372    GrTextureStripAtlas*    fAtlas;
373    int                     fRow;
374
375    typedef GrFragmentProcessor INHERITED;
376};
377
378class GLColorTableEffect : public GrGLFragmentProcessor {
379public:
380    GLColorTableEffect(const GrProcessor&);
381
382    virtual void emitCode(GrGLFPBuilder*,
383                          const GrFragmentProcessor&,
384                          const char* outputColor,
385                          const char* inputColor,
386                          const TransformedCoordsArray&,
387                          const TextureSamplerArray&) override;
388
389    void setData(const GrGLProgramDataManager&, const GrProcessor&) override;
390
391    static void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder* b) {}
392
393private:
394    UniformHandle fRGBAYValuesUni;
395    typedef GrGLFragmentProcessor INHERITED;
396};
397
398GLColorTableEffect::GLColorTableEffect(const GrProcessor&) {
399}
400
401void GLColorTableEffect::setData(const GrGLProgramDataManager& pdm, const GrProcessor& proc) {
402    // The textures are organized in a strip where the rows are ordered a, r, g, b.
403    float rgbaYValues[4];
404    const ColorTableEffect& cte = proc.cast<ColorTableEffect>();
405    if (cte.atlas()) {
406        SkScalar yDelta = cte.atlas()->getNormalizedTexelHeight();
407        rgbaYValues[3] = cte.atlas()->getYOffset(cte.atlasRow()) + SK_ScalarHalf * yDelta;
408        rgbaYValues[0] = rgbaYValues[3] + yDelta;
409        rgbaYValues[1] = rgbaYValues[0] + yDelta;
410        rgbaYValues[2] = rgbaYValues[1] + yDelta;
411    } else {
412        rgbaYValues[3] = 0.125;
413        rgbaYValues[0] = 0.375;
414        rgbaYValues[1] = 0.625;
415        rgbaYValues[2] = 0.875;
416    }
417    pdm.set4fv(fRGBAYValuesUni, 1, rgbaYValues);
418}
419
420void GLColorTableEffect::emitCode(GrGLFPBuilder* builder,
421                                  const GrFragmentProcessor&,
422                                  const char* outputColor,
423                                  const char* inputColor,
424                                  const TransformedCoordsArray&,
425                                  const TextureSamplerArray& samplers) {
426    const char* yoffsets;
427    fRGBAYValuesUni = builder->addUniform(GrGLFPBuilder::kFragment_Visibility,
428                                          kVec4f_GrSLType, kDefault_GrSLPrecision,
429                                          "yoffsets", &yoffsets);
430    static const float kColorScaleFactor = 255.0f / 256.0f;
431    static const float kColorOffsetFactor = 1.0f / 512.0f;
432    GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
433    if (NULL == inputColor) {
434        // the input color is solid white (all ones).
435        static const float kMaxValue = kColorScaleFactor + kColorOffsetFactor;
436        fsBuilder->codeAppendf("\t\tvec4 coord = vec4(%f, %f, %f, %f);\n",
437                               kMaxValue, kMaxValue, kMaxValue, kMaxValue);
438
439    } else {
440        fsBuilder->codeAppendf("\t\tfloat nonZeroAlpha = max(%s.a, .0001);\n", inputColor);
441        fsBuilder->codeAppendf("\t\tvec4 coord = vec4(%s.rgb / nonZeroAlpha, nonZeroAlpha);\n", inputColor);
442        fsBuilder->codeAppendf("\t\tcoord = coord * %f + vec4(%f, %f, %f, %f);\n",
443                              kColorScaleFactor,
444                              kColorOffsetFactor, kColorOffsetFactor,
445                              kColorOffsetFactor, kColorOffsetFactor);
446    }
447
448    SkString coord;
449
450    fsBuilder->codeAppendf("\t\t%s.a = ", outputColor);
451    coord.printf("vec2(coord.a, %s.a)", yoffsets);
452    fsBuilder->appendTextureLookup(samplers[0], coord.c_str());
453    fsBuilder->codeAppend(";\n");
454
455    fsBuilder->codeAppendf("\t\t%s.r = ", outputColor);
456    coord.printf("vec2(coord.r, %s.r)", yoffsets);
457    fsBuilder->appendTextureLookup(samplers[0], coord.c_str());
458    fsBuilder->codeAppend(";\n");
459
460    fsBuilder->codeAppendf("\t\t%s.g = ", outputColor);
461    coord.printf("vec2(coord.g, %s.g)", yoffsets);
462    fsBuilder->appendTextureLookup(samplers[0], coord.c_str());
463    fsBuilder->codeAppend(";\n");
464
465    fsBuilder->codeAppendf("\t\t%s.b = ", outputColor);
466    coord.printf("vec2(coord.b, %s.b)", yoffsets);
467    fsBuilder->appendTextureLookup(samplers[0], coord.c_str());
468    fsBuilder->codeAppend(";\n");
469
470    fsBuilder->codeAppendf("\t\t%s.rgb *= %s.a;\n", outputColor, outputColor);
471}
472
473///////////////////////////////////////////////////////////////////////////////
474GrFragmentProcessor* ColorTableEffect::Create(GrContext* context, SkBitmap bitmap, unsigned flags) {
475
476    GrTextureStripAtlas::Desc desc;
477    desc.fWidth  = bitmap.width();
478    desc.fHeight = 128;
479    desc.fRowHeight = bitmap.height();
480    desc.fContext = context;
481    desc.fConfig = SkImageInfo2GrPixelConfig(bitmap.info());
482    GrTextureStripAtlas* atlas = GrTextureStripAtlas::GetAtlas(desc);
483    int row = atlas->lockRow(bitmap);
484    SkAutoTUnref<GrTexture> texture;
485    if (-1 == row) {
486        atlas = NULL;
487        // Passing params=NULL because this effect does no tiling or filtering.
488        texture.reset(GrRefCachedBitmapTexture(context, bitmap, NULL));
489    } else {
490        texture.reset(SkRef(atlas->getTexture()));
491    }
492
493    return SkNEW_ARGS(ColorTableEffect, (texture, atlas, row, flags));
494}
495
496ColorTableEffect::ColorTableEffect(GrTexture* texture, GrTextureStripAtlas* atlas, int row,
497                                   unsigned flags)
498    : fTextureAccess(texture, "a")
499    , fFlags(flags)
500    , fAtlas(atlas)
501    , fRow(row) {
502    this->initClassID<ColorTableEffect>();
503    this->addTextureAccess(&fTextureAccess);
504}
505
506ColorTableEffect::~ColorTableEffect() {
507    if (fAtlas) {
508        fAtlas->unlockRow(fRow);
509    }
510}
511
512void ColorTableEffect::getGLProcessorKey(const GrGLSLCaps& caps,
513                                         GrProcessorKeyBuilder* b) const {
514    GLColorTableEffect::GenKey(*this, caps, b);
515}
516
517GrGLFragmentProcessor* ColorTableEffect::createGLInstance() const {
518    return SkNEW_ARGS(GLColorTableEffect, (*this));
519}
520
521bool ColorTableEffect::onIsEqual(const GrFragmentProcessor& other) const {
522    // For non-atlased instances, the texture (compared by base class) is sufficient to
523    // differentiate different tables. For atlased instances we ensure they are using the
524    // same row.
525    const ColorTableEffect& that = other.cast<ColorTableEffect>();
526    SkASSERT(SkToBool(fAtlas) == SkToBool(that.fAtlas));
527    // Ok to always do this comparison since both would be -1 if non-atlased.
528    return fRow == that.fRow;
529}
530
531void ColorTableEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
532    // If we kept the table in the effect then we could actually run known inputs through the
533    // table.
534    uint8_t invalidateFlags = 0;
535    if (fFlags & SkTable_ColorFilter::kR_Flag) {
536        invalidateFlags |= kR_GrColorComponentFlag;
537    }
538    if (fFlags & SkTable_ColorFilter::kG_Flag) {
539        invalidateFlags |= kG_GrColorComponentFlag;
540    }
541    if (fFlags & SkTable_ColorFilter::kB_Flag) {
542        invalidateFlags |= kB_GrColorComponentFlag;
543    }
544    if (fFlags & SkTable_ColorFilter::kA_Flag) {
545        invalidateFlags |= kA_GrColorComponentFlag;
546    }
547    inout->invalidateComponents(invalidateFlags, GrInvariantOutput::kWill_ReadInput);
548}
549
550///////////////////////////////////////////////////////////////////////////////
551
552GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ColorTableEffect);
553
554GrFragmentProcessor* ColorTableEffect::TestCreate(GrProcessorTestData* d) {
555    int flags = 0;
556    uint8_t luts[256][4];
557    do {
558        for (int i = 0; i < 4; ++i) {
559            flags |= d->fRandom->nextBool() ? (1  << i): 0;
560        }
561    } while (!flags);
562    for (int i = 0; i < 4; ++i) {
563        if (flags & (1 << i)) {
564            for (int j = 0; j < 256; ++j) {
565                luts[j][i] = SkToU8(d->fRandom->nextBits(8));
566            }
567        }
568    }
569    SkAutoTUnref<SkColorFilter> filter(SkTableColorFilter::CreateARGB(
570        (flags & (1 << 0)) ? luts[0] : NULL,
571        (flags & (1 << 1)) ? luts[1] : NULL,
572        (flags & (1 << 2)) ? luts[2] : NULL,
573        (flags & (1 << 3)) ? luts[3] : NULL
574    ));
575
576    SkTDArray<GrFragmentProcessor*> array;
577    if (filter->asFragmentProcessors(d->fContext, d->fShaderDataManager, &array)) {
578        SkASSERT(1 == array.count());   // TableColorFilter only returns 1
579        return array[0];
580    }
581    return NULL;
582}
583
584bool SkTable_ColorFilter::asFragmentProcessors(GrContext* context,
585                                               GrShaderDataManager*,
586                                               SkTDArray<GrFragmentProcessor*>* array) const {
587    SkBitmap bitmap;
588    this->asComponentTable(&bitmap);
589
590    GrFragmentProcessor* frag = ColorTableEffect::Create(context, bitmap, fFlags);
591    if (frag) {
592        if (array) {
593            *array->append() = frag;
594        } else {
595            frag->unref();
596            SkDEBUGCODE(frag = NULL;)
597        }
598        return true;
599    }
600    return false;
601}
602
603#endif // SK_SUPPORT_GPU
604
605///////////////////////////////////////////////////////////////////////////////
606
607#ifdef SK_CPU_BENDIAN
608#else
609    #define SK_A32_INDEX    (3 - (SK_A32_SHIFT >> 3))
610    #define SK_R32_INDEX    (3 - (SK_R32_SHIFT >> 3))
611    #define SK_G32_INDEX    (3 - (SK_G32_SHIFT >> 3))
612    #define SK_B32_INDEX    (3 - (SK_B32_SHIFT >> 3))
613#endif
614
615///////////////////////////////////////////////////////////////////////////////
616
617SkColorFilter* SkTableColorFilter::Create(const uint8_t table[256]) {
618    return SkNEW_ARGS(SkTable_ColorFilter, (table, table, table, table));
619}
620
621SkColorFilter* SkTableColorFilter::CreateARGB(const uint8_t tableA[256],
622                                              const uint8_t tableR[256],
623                                              const uint8_t tableG[256],
624                                              const uint8_t tableB[256]) {
625    return SkNEW_ARGS(SkTable_ColorFilter, (tableA, tableR, tableG, tableB));
626}
627
628SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkTableColorFilter)
629    SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkTable_ColorFilter)
630SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
631