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:
SkTable_ColorFilter(const uint8_t tableA[],const uint8_t tableR[],const uint8_t tableG[],const uint8_t tableB[])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
~SkTable_ColorFilter()46 virtual ~SkTable_ColorFilter() { delete fBitmap; }
47
48 bool asComponentTable(SkBitmap* table) const override;
49 SkColorFilter* newComposed(const SkColorFilter* inner) const override;
50
51 #if SK_SUPPORT_GPU
52 const GrFragmentProcessor* asFragmentProcessor(GrContext*) 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
filterSpan(const SkPMColor src[],int count,SkPMColor dst[]) const117 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
toString(SkString * str) const161 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
flatten(SkWriteBuffer & buffer) const200 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
CreateProc(SkReadBuffer & buffer)210 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::CreateARGB(a, r, g, b);
255 }
256
asComponentTable(SkBitmap * table) const257 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[].
combine_tables(uint8_t res[256],const uint8_t outer[256],const uint8_t inner[256])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
newComposed(const SkColorFilter * innerFilter) const290 SkColorFilter* SkTable_ColorFilter::newComposed(const 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::CreateARGB(concatA, concatR, concatG, concatB);
330 }
331
332 #if SK_SUPPORT_GPU
333
334 #include "GrFragmentProcessor.h"
335 #include "GrInvariantOutput.h"
336 #include "SkGr.h"
337 #include "effects/GrTextureStripAtlas.h"
338 #include "glsl/GrGLSLFragmentProcessor.h"
339 #include "glsl/GrGLSLFragmentShaderBuilder.h"
340 #include "glsl/GrGLSLProgramDataManager.h"
341 #include "glsl/GrGLSLUniformHandler.h"
342
343 class ColorTableEffect : public GrFragmentProcessor {
344 public:
345 static const GrFragmentProcessor* Create(GrContext* context, SkBitmap bitmap, unsigned flags);
346
347 virtual ~ColorTableEffect();
348
name() const349 const char* name() const override { return "ColorTable"; }
350
atlas() const351 const GrTextureStripAtlas* atlas() const { return fAtlas; }
atlasRow() const352 int atlasRow() const { return fRow; }
353
354 private:
355 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
356
357 void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
358
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
378 class GLColorTableEffect : public GrGLSLFragmentProcessor {
379 public:
380 void emitCode(EmitArgs&) override;
381
GenKey(const GrProcessor &,const GrGLSLCaps &,GrProcessorKeyBuilder *)382 static void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder*) {}
383
384 protected:
385 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
386
387 private:
388 UniformHandle fRGBAYValuesUni;
389 typedef GrGLSLFragmentProcessor INHERITED;
390 };
391
onSetData(const GrGLSLProgramDataManager & pdm,const GrProcessor & proc)392 void GLColorTableEffect::onSetData(const GrGLSLProgramDataManager& pdm, const GrProcessor& proc) {
393 // The textures are organized in a strip where the rows are ordered a, r, g, b.
394 float rgbaYValues[4];
395 const ColorTableEffect& cte = proc.cast<ColorTableEffect>();
396 if (cte.atlas()) {
397 SkScalar yDelta = cte.atlas()->getNormalizedTexelHeight();
398 rgbaYValues[3] = cte.atlas()->getYOffset(cte.atlasRow()) + SK_ScalarHalf * yDelta;
399 rgbaYValues[0] = rgbaYValues[3] + yDelta;
400 rgbaYValues[1] = rgbaYValues[0] + yDelta;
401 rgbaYValues[2] = rgbaYValues[1] + yDelta;
402 } else {
403 rgbaYValues[3] = 0.125;
404 rgbaYValues[0] = 0.375;
405 rgbaYValues[1] = 0.625;
406 rgbaYValues[2] = 0.875;
407 }
408 pdm.set4fv(fRGBAYValuesUni, 1, rgbaYValues);
409 }
410
emitCode(EmitArgs & args)411 void GLColorTableEffect::emitCode(EmitArgs& args) {
412 const char* yoffsets;
413 fRGBAYValuesUni = args.fUniformHandler->addUniform(kFragment_GrShaderFlag,
414 kVec4f_GrSLType, kDefault_GrSLPrecision,
415 "yoffsets", &yoffsets);
416 static const float kColorScaleFactor = 255.0f / 256.0f;
417 static const float kColorOffsetFactor = 1.0f / 512.0f;
418 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
419 if (nullptr == args.fInputColor) {
420 // the input color is solid white (all ones).
421 static const float kMaxValue = kColorScaleFactor + kColorOffsetFactor;
422 fragBuilder->codeAppendf("\t\tvec4 coord = vec4(%f, %f, %f, %f);\n",
423 kMaxValue, kMaxValue, kMaxValue, kMaxValue);
424
425 } else {
426 fragBuilder->codeAppendf("\t\tfloat nonZeroAlpha = max(%s.a, .0001);\n", args.fInputColor);
427 fragBuilder->codeAppendf("\t\tvec4 coord = vec4(%s.rgb / nonZeroAlpha, nonZeroAlpha);\n",
428 args.fInputColor);
429 fragBuilder->codeAppendf("\t\tcoord = coord * %f + vec4(%f, %f, %f, %f);\n",
430 kColorScaleFactor,
431 kColorOffsetFactor, kColorOffsetFactor,
432 kColorOffsetFactor, kColorOffsetFactor);
433 }
434
435 SkString coord;
436
437 fragBuilder->codeAppendf("\t\t%s.a = ", args.fOutputColor);
438 coord.printf("vec2(coord.a, %s.a)", yoffsets);
439 fragBuilder->appendTextureLookup(args.fSamplers[0], coord.c_str());
440 fragBuilder->codeAppend(".a;\n");
441
442 fragBuilder->codeAppendf("\t\t%s.r = ", args.fOutputColor);
443 coord.printf("vec2(coord.r, %s.r)", yoffsets);
444 fragBuilder->appendTextureLookup(args.fSamplers[0], coord.c_str());
445 fragBuilder->codeAppend(".a;\n");
446
447 fragBuilder->codeAppendf("\t\t%s.g = ", args.fOutputColor);
448 coord.printf("vec2(coord.g, %s.g)", yoffsets);
449 fragBuilder->appendTextureLookup(args.fSamplers[0], coord.c_str());
450 fragBuilder->codeAppend(".a;\n");
451
452 fragBuilder->codeAppendf("\t\t%s.b = ", args.fOutputColor);
453 coord.printf("vec2(coord.b, %s.b)", yoffsets);
454 fragBuilder->appendTextureLookup(args.fSamplers[0], coord.c_str());
455 fragBuilder->codeAppend(".a;\n");
456
457 fragBuilder->codeAppendf("\t\t%s.rgb *= %s.a;\n", args.fOutputColor, args.fOutputColor);
458 }
459
460 ///////////////////////////////////////////////////////////////////////////////
Create(GrContext * context,SkBitmap bitmap,unsigned flags)461 const GrFragmentProcessor* ColorTableEffect::Create(GrContext* context, SkBitmap bitmap,
462 unsigned flags) {
463
464 GrTextureStripAtlas::Desc desc;
465 desc.fWidth = bitmap.width();
466 desc.fHeight = 128;
467 desc.fRowHeight = bitmap.height();
468 desc.fContext = context;
469 desc.fConfig = SkImageInfo2GrPixelConfig(bitmap.info());
470 GrTextureStripAtlas* atlas = GrTextureStripAtlas::GetAtlas(desc);
471 int row = atlas->lockRow(bitmap);
472 SkAutoTUnref<GrTexture> texture;
473 if (-1 == row) {
474 atlas = nullptr;
475 texture.reset(GrRefCachedBitmapTexture(context, bitmap, GrTextureParams::ClampNoFilter()));
476 } else {
477 texture.reset(SkRef(atlas->getTexture()));
478 }
479
480 return new ColorTableEffect(texture, atlas, row, flags);
481 }
482
ColorTableEffect(GrTexture * texture,GrTextureStripAtlas * atlas,int row,unsigned flags)483 ColorTableEffect::ColorTableEffect(GrTexture* texture, GrTextureStripAtlas* atlas, int row,
484 unsigned flags)
485 : fTextureAccess(texture)
486 , fFlags(flags)
487 , fAtlas(atlas)
488 , fRow(row) {
489 this->initClassID<ColorTableEffect>();
490 this->addTextureAccess(&fTextureAccess);
491 }
492
~ColorTableEffect()493 ColorTableEffect::~ColorTableEffect() {
494 if (fAtlas) {
495 fAtlas->unlockRow(fRow);
496 }
497 }
498
onGetGLSLProcessorKey(const GrGLSLCaps & caps,GrProcessorKeyBuilder * b) const499 void ColorTableEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps,
500 GrProcessorKeyBuilder* b) const {
501 GLColorTableEffect::GenKey(*this, caps, b);
502 }
503
onCreateGLSLInstance() const504 GrGLSLFragmentProcessor* ColorTableEffect::onCreateGLSLInstance() const {
505 return new GLColorTableEffect;
506 }
507
onIsEqual(const GrFragmentProcessor & other) const508 bool ColorTableEffect::onIsEqual(const GrFragmentProcessor& other) const {
509 // For non-atlased instances, the texture (compared by base class) is sufficient to
510 // differentiate different tables. For atlased instances we ensure they are using the
511 // same row.
512 const ColorTableEffect& that = other.cast<ColorTableEffect>();
513 SkASSERT(SkToBool(fAtlas) == SkToBool(that.fAtlas));
514 // Ok to always do this comparison since both would be -1 if non-atlased.
515 return fRow == that.fRow;
516 }
517
onComputeInvariantOutput(GrInvariantOutput * inout) const518 void ColorTableEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
519 // If we kept the table in the effect then we could actually run known inputs through the
520 // table.
521 GrColorComponentFlags invalidateFlags = kNone_GrColorComponentFlags;
522 if (fFlags & SkTable_ColorFilter::kR_Flag) {
523 invalidateFlags |= kR_GrColorComponentFlag;
524 }
525 if (fFlags & SkTable_ColorFilter::kG_Flag) {
526 invalidateFlags |= kG_GrColorComponentFlag;
527 }
528 if (fFlags & SkTable_ColorFilter::kB_Flag) {
529 invalidateFlags |= kB_GrColorComponentFlag;
530 }
531 if (fFlags & SkTable_ColorFilter::kA_Flag) {
532 invalidateFlags |= kA_GrColorComponentFlag;
533 }
534 inout->invalidateComponents(invalidateFlags, GrInvariantOutput::kWill_ReadInput);
535 }
536
537 ///////////////////////////////////////////////////////////////////////////////
538
539 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ColorTableEffect);
540
TestCreate(GrProcessorTestData * d)541 const GrFragmentProcessor* ColorTableEffect::TestCreate(GrProcessorTestData* d) {
542 int flags = 0;
543 uint8_t luts[256][4];
544 do {
545 for (int i = 0; i < 4; ++i) {
546 flags |= d->fRandom->nextBool() ? (1 << i): 0;
547 }
548 } while (!flags);
549 for (int i = 0; i < 4; ++i) {
550 if (flags & (1 << i)) {
551 for (int j = 0; j < 256; ++j) {
552 luts[j][i] = SkToU8(d->fRandom->nextBits(8));
553 }
554 }
555 }
556 SkAutoTUnref<SkColorFilter> filter(SkTableColorFilter::CreateARGB(
557 (flags & (1 << 0)) ? luts[0] : nullptr,
558 (flags & (1 << 1)) ? luts[1] : nullptr,
559 (flags & (1 << 2)) ? luts[2] : nullptr,
560 (flags & (1 << 3)) ? luts[3] : nullptr
561 ));
562
563 const GrFragmentProcessor* fp = filter->asFragmentProcessor(d->fContext);
564 SkASSERT(fp);
565 return fp;
566 }
567
asFragmentProcessor(GrContext * context) const568 const GrFragmentProcessor* SkTable_ColorFilter::asFragmentProcessor(GrContext* context) const {
569 SkBitmap bitmap;
570 this->asComponentTable(&bitmap);
571
572 return ColorTableEffect::Create(context, bitmap, fFlags);
573 }
574
575 #endif // SK_SUPPORT_GPU
576
577 ///////////////////////////////////////////////////////////////////////////////
578
579 #ifdef SK_CPU_BENDIAN
580 #else
581 #define SK_A32_INDEX (3 - (SK_A32_SHIFT >> 3))
582 #define SK_R32_INDEX (3 - (SK_R32_SHIFT >> 3))
583 #define SK_G32_INDEX (3 - (SK_G32_SHIFT >> 3))
584 #define SK_B32_INDEX (3 - (SK_B32_SHIFT >> 3))
585 #endif
586
587 ///////////////////////////////////////////////////////////////////////////////
588
Create(const uint8_t table[256])589 SkColorFilter* SkTableColorFilter::Create(const uint8_t table[256]) {
590 return new SkTable_ColorFilter(table, table, table, table);
591 }
592
CreateARGB(const uint8_t tableA[256],const uint8_t tableR[256],const uint8_t tableG[256],const uint8_t tableB[256])593 SkColorFilter* SkTableColorFilter::CreateARGB(const uint8_t tableA[256],
594 const uint8_t tableR[256],
595 const uint8_t tableG[256],
596 const uint8_t tableB[256]) {
597 return new SkTable_ColorFilter(tableA, tableR, tableG, tableB);
598 }
599
600 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkTableColorFilter)
601 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkTable_ColorFilter)
602 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
603