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