3 #include "SkTableColorFilter.h"
4 #include "SkColorPriv.h"
5 #include "SkReadBuffer.h"
6 #include "SkWriteBuffer.h"
7 #include "SkUnPreMultiply.h"
10 class SkTable_ColorFilter : public SkColorFilter {
12 SkTable_ColorFilter(const uint8_t tableA[], const uint8_t tableR[],
13 const uint8_t tableG[], const uint8_t tableB[]) {
17 uint8_t* dst = fStorage;
19 memcpy(dst, tableA, 256);
24 memcpy(dst, tableR, 256);
29 memcpy(dst, tableG, 256);
34 memcpy(dst, tableB, 256);
39 virtual ~SkTable_ColorFilter() {
43 virtual bool asComponentTable(SkBitmap* table) const SK_OVERRIDE;
46 virtual GrFragmentProcessor* asFragmentProcessor(GrContext* context) const SK_OVERRIDE;
49 virtual void filterSpan(const SkPMColor src[], int count,
50 SkPMColor dst[]) const SK_OVERRIDE;
52 SK_TO_STRING_OVERRIDE()
54 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkTable_ColorFilter)
64 #ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
65 SkTable_ColorFilter(SkReadBuffer& buffer);
67 virtual void flatten(SkWriteBuffer&) const SK_OVERRIDE;
70 mutable const SkBitmap* fBitmap; // lazily allocated
72 uint8_t fStorage[256 * 4];
75 friend class SkTableColorFilter;
77 typedef SkColorFilter INHERITED;
80 static const uint8_t gIdentityTable[] = {
81 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
82 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
83 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
84 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
85 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
86 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
87 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
88 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
89 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
90 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
91 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
92 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
93 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
94 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
95 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
96 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
97 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
98 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
99 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
100 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
101 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
102 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
103 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7,
104 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
105 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
106 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
107 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
108 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
109 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
110 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
111 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
112 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
115 void SkTable_ColorFilter::filterSpan(const SkPMColor src[], int count,
116 SkPMColor dst[]) const {
117 const uint8_t* table = fStorage;
118 const uint8_t* tableA = gIdentityTable;
119 const uint8_t* tableR = gIdentityTable;
120 const uint8_t* tableG = gIdentityTable;
121 const uint8_t* tableB = gIdentityTable;
122 if (fFlags & kA_Flag) {
123 tableA = table; table += 256;
125 if (fFlags & kR_Flag) {
126 tableR = table; table += 256;
128 if (fFlags & kG_Flag) {
129 tableG = table; table += 256;
131 if (fFlags & kB_Flag) {
135 const SkUnPreMultiply::Scale* scaleTable = SkUnPreMultiply::GetScaleTable();
136 for (int i = 0; i < count; ++i) {
137 SkPMColor c = src[i];
142 a = SkGetPackedA32(c);
143 r = SkGetPackedR32(c);
144 g = SkGetPackedG32(c);
145 b = SkGetPackedB32(c);
148 SkUnPreMultiply::Scale scale = scaleTable[a];
149 r = SkUnPreMultiply::ApplyScale(scale, r);
150 g = SkUnPreMultiply::ApplyScale(scale, g);
151 b = SkUnPreMultiply::ApplyScale(scale, b);
154 dst[i] = SkPremultiplyARGBInline(tableA[a], tableR[r],
155 tableG[g], tableB[b]);
159 #ifndef SK_IGNORE_TO_STRING
160 void SkTable_ColorFilter::toString(SkString* str) const {
161 str->append("SkTable_ColorFilter");
165 static const uint8_t gCountNibBits[] = {
172 #include "SkPackBits.h"
174 void SkTable_ColorFilter::flatten(SkWriteBuffer& buffer) const {
175 uint8_t storage[5*256];
176 int count = gCountNibBits[fFlags & 0xF];
177 size_t size = SkPackBits::Pack8(fStorage, count * 256, storage);
178 SkASSERT(size <= sizeof(storage));
180 buffer.write32(fFlags);
181 buffer.writeByteArray(storage, size);
184 SkFlattenable* SkTable_ColorFilter::CreateProc(SkReadBuffer& buffer) {
185 const int flags = buffer.read32();
186 const size_t count = gCountNibBits[flags & 0xF];
187 SkASSERT(count <= 4);
189 uint8_t packedStorage[5*256];
190 size_t packedSize = buffer.getArrayCount();
191 if (!buffer.validate(packedSize <= sizeof(packedStorage))) {
194 if (!buffer.readByteArray(packedStorage, packedSize)) {
198 uint8_t unpackedStorage[4*256];
199 size_t unpackedSize = SkPackBits::Unpack8(packedStorage, packedSize, unpackedStorage);
200 // now check that we got the size we expected
201 if (!buffer.validate(unpackedSize == count*256)) {
205 const uint8_t* a = NULL;
206 const uint8_t* r = NULL;
207 const uint8_t* g = NULL;
208 const uint8_t* b = NULL;
209 const uint8_t* ptr = unpackedStorage;
211 if (flags & kA_Flag) {
215 if (flags & kR_Flag) {
219 if (flags & kG_Flag) {
223 if (flags & kB_Flag) {
227 return SkTableColorFilter::CreateARGB(a, r, g, b);
230 #ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
231 SkTable_ColorFilter::SkTable_ColorFilter(SkReadBuffer& buffer) : INHERITED(buffer) {
234 uint8_t storage[5*256];
236 fFlags = buffer.readInt();
238 size_t size = buffer.getArrayCount();
239 SkASSERT(size <= sizeof(storage));
240 buffer.validate(size <= sizeof(storage));
241 buffer.readByteArray(storage, size);
243 SkDEBUGCODE(size_t raw = ) SkPackBits::Unpack8(storage, size, fStorage);
245 SkASSERT(raw <= sizeof(fStorage));
246 SkDEBUGCODE(size_t count = gCountNibBits[fFlags & 0xF]);
247 SkASSERT(raw == count * 256);
251 bool SkTable_ColorFilter::asComponentTable(SkBitmap* table) const {
253 if (NULL == fBitmap) {
254 SkBitmap* bmp = SkNEW(SkBitmap);
255 bmp->allocPixels(SkImageInfo::MakeA8(256, 4));
256 uint8_t* bitmapPixels = bmp->getAddr8(0, 0);
258 static const unsigned kFlags[] = { kA_Flag, kR_Flag, kG_Flag, kB_Flag };
260 for (int x = 0; x < 4; ++x) {
261 if (!(fFlags & kFlags[x])) {
262 memcpy(bitmapPixels, gIdentityTable, sizeof(gIdentityTable));
264 memcpy(bitmapPixels, fStorage + offset, 256);
278 #include "GrFragmentProcessor.h"
279 #include "GrTBackendProcessorFactory.h"
281 #include "effects/GrTextureStripAtlas.h"
282 #include "gl/GrGLProcessor.h"
283 #include "gl/builders/GrGLProgramBuilder.h"
286 class GLColorTableEffect;
288 class ColorTableEffect : public GrFragmentProcessor {
290 static GrFragmentProcessor* Create(GrContext* context, SkBitmap bitmap, unsigned flags);
292 virtual ~ColorTableEffect();
294 static const char* Name() { return "ColorTable"; }
295 virtual const GrBackendFragmentProcessorFactory& getFactory() const SK_OVERRIDE;
297 typedef GLColorTableEffect GLProcessor;
299 const GrTextureStripAtlas* atlas() const { return fAtlas; }
300 int atlasRow() const { return fRow; }
303 virtual bool onIsEqual(const GrFragmentProcessor&) const SK_OVERRIDE;
305 virtual void onComputeInvariantOutput(InvariantOutput* inout) const SK_OVERRIDE;
307 ColorTableEffect(GrTexture* texture, GrTextureStripAtlas* atlas, int row, unsigned flags);
309 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
311 GrTextureAccess fTextureAccess;
313 // currently not used in shader code, just to assist onComputeInvariantOutput().
316 GrTextureStripAtlas* fAtlas;
319 typedef GrFragmentProcessor INHERITED;
322 class GLColorTableEffect : public GrGLFragmentProcessor {
324 GLColorTableEffect(const GrBackendProcessorFactory&, const GrProcessor&);
326 virtual void emitCode(GrGLFPBuilder*,
327 const GrFragmentProcessor&,
328 const GrProcessorKey&,
329 const char* outputColor,
330 const char* inputColor,
331 const TransformedCoordsArray&,
332 const TextureSamplerArray&) SK_OVERRIDE;
334 virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE;
336 static void GenKey(const GrProcessor&, const GrGLCaps&, GrProcessorKeyBuilder* b) {}
339 UniformHandle fRGBAYValuesUni;
340 typedef GrGLFragmentProcessor INHERITED;
343 GLColorTableEffect::GLColorTableEffect(const GrBackendProcessorFactory& factory, const GrProcessor&)
344 : INHERITED(factory) {
347 void GLColorTableEffect::setData(const GrGLProgramDataManager& pdm, const GrProcessor& proc) {
348 // The textures are organized in a strip where the rows are ordered a, r, g, b.
349 float rgbaYValues[4];
350 const ColorTableEffect& cte = proc.cast<ColorTableEffect>();
352 SkScalar yDelta = cte.atlas()->getNormalizedTexelHeight();
353 rgbaYValues[3] = cte.atlas()->getYOffset(cte.atlasRow()) + SK_ScalarHalf * yDelta;
354 rgbaYValues[0] = rgbaYValues[3] + yDelta;
355 rgbaYValues[1] = rgbaYValues[0] + yDelta;
356 rgbaYValues[2] = rgbaYValues[1] + yDelta;
358 rgbaYValues[3] = 0.125;
359 rgbaYValues[0] = 0.375;
360 rgbaYValues[1] = 0.625;
361 rgbaYValues[2] = 0.875;
363 pdm.set4fv(fRGBAYValuesUni, 1, rgbaYValues);
366 void GLColorTableEffect::emitCode(GrGLFPBuilder* builder,
367 const GrFragmentProcessor&,
368 const GrProcessorKey&,
369 const char* outputColor,
370 const char* inputColor,
371 const TransformedCoordsArray&,
372 const TextureSamplerArray& samplers) {
373 const char* yoffsets;
374 fRGBAYValuesUni = builder->addUniform(GrGLFPBuilder::kFragment_Visibility,
375 kVec4f_GrSLType, "yoffsets", &yoffsets);
376 static const float kColorScaleFactor = 255.0f / 256.0f;
377 static const float kColorOffsetFactor = 1.0f / 512.0f;
378 GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
379 if (NULL == inputColor) {
380 // the input color is solid white (all ones).
381 static const float kMaxValue = kColorScaleFactor + kColorOffsetFactor;
382 fsBuilder->codeAppendf("\t\tvec4 coord = vec4(%f, %f, %f, %f);\n",
383 kMaxValue, kMaxValue, kMaxValue, kMaxValue);
386 fsBuilder->codeAppendf("\t\tfloat nonZeroAlpha = max(%s.a, .0001);\n", inputColor);
387 fsBuilder->codeAppendf("\t\tvec4 coord = vec4(%s.rgb / nonZeroAlpha, nonZeroAlpha);\n", inputColor);
388 fsBuilder->codeAppendf("\t\tcoord = coord * %f + vec4(%f, %f, %f, %f);\n",
390 kColorOffsetFactor, kColorOffsetFactor,
391 kColorOffsetFactor, kColorOffsetFactor);
396 fsBuilder->codeAppendf("\t\t%s.a = ", outputColor);
397 coord.printf("vec2(coord.a, %s.a)", yoffsets);
398 fsBuilder->appendTextureLookup(samplers[0], coord.c_str());
399 fsBuilder->codeAppend(";\n");
401 fsBuilder->codeAppendf("\t\t%s.r = ", outputColor);
402 coord.printf("vec2(coord.r, %s.r)", yoffsets);
403 fsBuilder->appendTextureLookup(samplers[0], coord.c_str());
404 fsBuilder->codeAppend(";\n");
406 fsBuilder->codeAppendf("\t\t%s.g = ", outputColor);
407 coord.printf("vec2(coord.g, %s.g)", yoffsets);
408 fsBuilder->appendTextureLookup(samplers[0], coord.c_str());
409 fsBuilder->codeAppend(";\n");
411 fsBuilder->codeAppendf("\t\t%s.b = ", outputColor);
412 coord.printf("vec2(coord.b, %s.b)", yoffsets);
413 fsBuilder->appendTextureLookup(samplers[0], coord.c_str());
414 fsBuilder->codeAppend(";\n");
416 fsBuilder->codeAppendf("\t\t%s.rgb *= %s.a;\n", outputColor, outputColor);
419 ///////////////////////////////////////////////////////////////////////////////
420 GrFragmentProcessor* ColorTableEffect::Create(GrContext* context, SkBitmap bitmap, unsigned flags) {
422 GrTextureStripAtlas::Desc desc;
423 desc.fWidth = bitmap.width();
425 desc.fRowHeight = bitmap.height();
426 desc.fContext = context;
427 desc.fConfig = SkImageInfo2GrPixelConfig(bitmap.info());
428 GrTextureStripAtlas* atlas = GrTextureStripAtlas::GetAtlas(desc);
429 int row = atlas->lockRow(bitmap);
430 SkAutoTUnref<GrTexture> texture;
433 // Passing params=NULL because this effect does no tiling or filtering.
434 texture.reset(GrRefCachedBitmapTexture(context, bitmap, NULL));
436 texture.reset(SkRef(atlas->getTexture()));
439 return SkNEW_ARGS(ColorTableEffect, (texture, atlas, row, flags));
442 ColorTableEffect::ColorTableEffect(GrTexture* texture, GrTextureStripAtlas* atlas, int row,
444 : fTextureAccess(texture, "a")
449 this->addTextureAccess(&fTextureAccess);
452 ColorTableEffect::~ColorTableEffect() {
454 fAtlas->unlockRow(fRow);
458 const GrBackendFragmentProcessorFactory& ColorTableEffect::getFactory() const {
459 return GrTBackendFragmentProcessorFactory<ColorTableEffect>::getInstance();
462 bool ColorTableEffect::onIsEqual(const GrFragmentProcessor& other) const {
463 // For non-atlased instances, the texture (compared by base class) is sufficient to
464 // differentiate different tables. For atlased instances we ensure they are using the
466 const ColorTableEffect& that = other.cast<ColorTableEffect>();
467 SkASSERT(SkToBool(fAtlas) == SkToBool(that.fAtlas));
468 // Ok to always do this comparison since both would be -1 if non-atlased.
469 return fRow == that.fRow;
472 void ColorTableEffect::onComputeInvariantOutput(InvariantOutput* inout) const {
473 // If we kept the table in the effect then we could actually run known inputs through the
475 uint8_t invalidateFlags = 0;
476 if (fFlags & SkTable_ColorFilter::kR_Flag) {
477 invalidateFlags |= kR_GrColorComponentFlag;
479 if (fFlags & SkTable_ColorFilter::kG_Flag) {
480 invalidateFlags |= kG_GrColorComponentFlag;
482 if (fFlags & SkTable_ColorFilter::kB_Flag) {
483 invalidateFlags |= kB_GrColorComponentFlag;
485 if (fFlags & SkTable_ColorFilter::kA_Flag) {
486 invalidateFlags |= kA_GrColorComponentFlag;
488 inout->invalidateComponents(invalidateFlags, InvariantOutput::kWill_ReadInput);
491 ///////////////////////////////////////////////////////////////////////////////
493 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ColorTableEffect);
495 GrFragmentProcessor* ColorTableEffect::TestCreate(SkRandom* random,
497 const GrDrawTargetCaps&,
498 GrTexture* textures[]) {
500 uint8_t luts[256][4];
502 for (int i = 0; i < 4; ++i) {
503 flags |= random->nextBool() ? (1 << i): 0;
506 for (int i = 0; i < 4; ++i) {
507 if (flags & (1 << i)) {
508 for (int j = 0; j < 256; ++j) {
509 luts[j][i] = SkToU8(random->nextBits(8));
513 SkAutoTUnref<SkColorFilter> filter(SkTableColorFilter::CreateARGB(
514 (flags & (1 << 0)) ? luts[0] : NULL,
515 (flags & (1 << 1)) ? luts[1] : NULL,
516 (flags & (1 << 2)) ? luts[2] : NULL,
517 (flags & (1 << 3)) ? luts[3] : NULL
519 return filter->asFragmentProcessor(context);
522 GrFragmentProcessor* SkTable_ColorFilter::asFragmentProcessor(GrContext* context) const {
524 this->asComponentTable(&bitmap);
526 return ColorTableEffect::Create(context, bitmap, fFlags);
529 #endif // SK_SUPPORT_GPU
531 ///////////////////////////////////////////////////////////////////////////////
533 #ifdef SK_CPU_BENDIAN
535 #define SK_A32_INDEX (3 - (SK_A32_SHIFT >> 3))
536 #define SK_R32_INDEX (3 - (SK_R32_SHIFT >> 3))
537 #define SK_G32_INDEX (3 - (SK_G32_SHIFT >> 3))
538 #define SK_B32_INDEX (3 - (SK_B32_SHIFT >> 3))
541 ///////////////////////////////////////////////////////////////////////////////
543 SkColorFilter* SkTableColorFilter::Create(const uint8_t table[256]) {
544 return SkNEW_ARGS(SkTable_ColorFilter, (table, table, table, table));
547 SkColorFilter* SkTableColorFilter::CreateARGB(const uint8_t tableA[256],
548 const uint8_t tableR[256],
549 const uint8_t tableG[256],
550 const uint8_t tableB[256]) {
551 return SkNEW_ARGS(SkTable_ColorFilter, (tableA, tableR, tableG, tableB));
554 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkTableColorFilter)
555 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkTable_ColorFilter)
556 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END