Plumb dst color space in many places, rather than "mode"
[platform/upstream/libSkiaSharp.git] / src / effects / SkTableColorFilter.cpp
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
17 class SkTable_ColorFilter : public SkColorFilter {
18 public:
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
68 protected:
69     void flatten(SkWriteBuffer&) const override;
70
71 private:
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
82 static 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
117 void 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
161 void 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
191 static 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
200 void 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
210 sk_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
257 bool 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[].
284 static 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
290 sk_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
344 class ColorTableEffect : public GrFragmentProcessor {
345 public:
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
355 private:
356     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
357
358     void onGetGLSLProcessorKey(const GrShaderCaps&, 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     TextureSampler          fTextureSampler;
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
379 class GLColorTableEffect : public GrGLSLFragmentProcessor {
380 public:
381     void emitCode(EmitArgs&) override;
382
383     static void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*) {}
384
385 protected:
386     void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
387
388 private:
389     UniformHandle fRGBAYValuesUni;
390     typedef GrGLSLFragmentProcessor INHERITED;
391 };
392
393 void 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
412 void 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 ///////////////////////////////////////////////////////////////////////////////
462 sk_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(
477             GrRefCachedBitmapTexture(context, bitmap, GrSamplerParams::ClampNoFilter()));
478     } else {
479         texture.reset(SkRef(atlas->getTexture()));
480     }
481
482     return sk_sp<GrFragmentProcessor>(new ColorTableEffect(texture.get(), atlas, row, flags));
483 }
484
485 ColorTableEffect::ColorTableEffect(GrTexture* texture, GrTextureStripAtlas* atlas, int row,
486                                    unsigned flags)
487     : fTextureSampler(texture)
488     , fFlags(flags)
489     , fAtlas(atlas)
490     , fRow(row) {
491     this->initClassID<ColorTableEffect>();
492     this->addTextureSampler(&fTextureSampler);
493 }
494
495 ColorTableEffect::~ColorTableEffect() {
496     if (fAtlas) {
497         fAtlas->unlockRow(fRow);
498     }
499 }
500
501 void ColorTableEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
502                                              GrProcessorKeyBuilder* b) const {
503     GLColorTableEffect::GenKey(*this, caps, b);
504 }
505
506 GrGLSLFragmentProcessor* ColorTableEffect::onCreateGLSLInstance() const {
507     return new GLColorTableEffect;
508 }
509
510 bool 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
520 void 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
541 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ColorTableEffect);
542
543 sk_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
570 sk_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
592 sk_sp<SkColorFilter> SkTableColorFilter::Make(const uint8_t table[256]) {
593     return sk_make_sp<SkTable_ColorFilter>(table, table, table, table);
594 }
595
596 sk_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
603 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkTableColorFilter)
604     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkTable_ColorFilter)
605 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END