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