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