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