1 2#include "SkBitmap.h" 3#include "SkTableColorFilter.h" 4#include "SkColorPriv.h" 5#include "SkReadBuffer.h" 6#include "SkWriteBuffer.h" 7#include "SkUnPreMultiply.h" 8#include "SkString.h" 9 10class SkTable_ColorFilter : public SkColorFilter { 11public: 12 SkTable_ColorFilter(const uint8_t tableA[], const uint8_t tableR[], 13 const uint8_t tableG[], const uint8_t tableB[]) { 14 fBitmap = NULL; 15 fFlags = 0; 16 17 uint8_t* dst = fStorage; 18 if (tableA) { 19 memcpy(dst, tableA, 256); 20 dst += 256; 21 fFlags |= kA_Flag; 22 } 23 if (tableR) { 24 memcpy(dst, tableR, 256); 25 dst += 256; 26 fFlags |= kR_Flag; 27 } 28 if (tableG) { 29 memcpy(dst, tableG, 256); 30 dst += 256; 31 fFlags |= kG_Flag; 32 } 33 if (tableB) { 34 memcpy(dst, tableB, 256); 35 fFlags |= kB_Flag; 36 } 37 } 38 39 virtual ~SkTable_ColorFilter() { 40 SkDELETE(fBitmap); 41 } 42 43 virtual bool asComponentTable(SkBitmap* table) const SK_OVERRIDE; 44 45#if SK_SUPPORT_GPU 46 virtual GrEffectRef* asNewEffect(GrContext* context) const SK_OVERRIDE; 47#endif 48 49 virtual void filterSpan(const SkPMColor src[], int count, 50 SkPMColor dst[]) const SK_OVERRIDE; 51 52 SK_TO_STRING_OVERRIDE() 53 54 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkTable_ColorFilter) 55 56 enum { 57 kA_Flag = 1 << 0, 58 kR_Flag = 1 << 1, 59 kG_Flag = 1 << 2, 60 kB_Flag = 1 << 3, 61 }; 62 63protected: 64 SkTable_ColorFilter(SkReadBuffer& buffer); 65 virtual void flatten(SkWriteBuffer&) const SK_OVERRIDE; 66 67private: 68 mutable const SkBitmap* fBitmap; // lazily allocated 69 70 uint8_t fStorage[256 * 4]; 71 unsigned fFlags; 72 73 typedef SkColorFilter INHERITED; 74}; 75 76static const uint8_t gIdentityTable[] = { 77 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 78 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 79 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 80 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 81 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 82 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 83 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 84 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 85 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 86 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 87 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 88 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 89 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 90 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 91 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 92 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 93 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 94 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 95 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 96 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 97 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 98 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 99 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 100 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 101 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 102 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 103 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 104 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 105 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 106 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 107 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 108 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF 109}; 110 111void SkTable_ColorFilter::filterSpan(const SkPMColor src[], int count, 112 SkPMColor dst[]) const { 113 const uint8_t* table = fStorage; 114 const uint8_t* tableA = gIdentityTable; 115 const uint8_t* tableR = gIdentityTable; 116 const uint8_t* tableG = gIdentityTable; 117 const uint8_t* tableB = gIdentityTable; 118 if (fFlags & kA_Flag) { 119 tableA = table; table += 256; 120 } 121 if (fFlags & kR_Flag) { 122 tableR = table; table += 256; 123 } 124 if (fFlags & kG_Flag) { 125 tableG = table; table += 256; 126 } 127 if (fFlags & kB_Flag) { 128 tableB = table; 129 } 130 131 const SkUnPreMultiply::Scale* scaleTable = SkUnPreMultiply::GetScaleTable(); 132 for (int i = 0; i < count; ++i) { 133 SkPMColor c = src[i]; 134 unsigned a, r, g, b; 135 if (0 == c) { 136 a = r = g = b = 0; 137 } else { 138 a = SkGetPackedA32(c); 139 r = SkGetPackedR32(c); 140 g = SkGetPackedG32(c); 141 b = SkGetPackedB32(c); 142 143 if (a < 255) { 144 SkUnPreMultiply::Scale scale = scaleTable[a]; 145 r = SkUnPreMultiply::ApplyScale(scale, r); 146 g = SkUnPreMultiply::ApplyScale(scale, g); 147 b = SkUnPreMultiply::ApplyScale(scale, b); 148 } 149 } 150 dst[i] = SkPremultiplyARGBInline(tableA[a], tableR[r], 151 tableG[g], tableB[b]); 152 } 153} 154 155#ifndef SK_IGNORE_TO_STRING 156void SkTable_ColorFilter::toString(SkString* str) const { 157 str->append("SkTable_ColorFilter"); 158} 159#endif 160 161static const uint8_t gCountNibBits[] = { 162 0, 1, 1, 2, 163 1, 2, 2, 3, 164 1, 2, 2, 3, 165 2, 3, 3, 4 166}; 167 168#include "SkPackBits.h" 169 170void SkTable_ColorFilter::flatten(SkWriteBuffer& buffer) const { 171 this->INHERITED::flatten(buffer); 172 173 uint8_t storage[5*256]; 174 int count = gCountNibBits[fFlags & 0xF]; 175 size_t size = SkPackBits::Pack8(fStorage, count * 256, storage); 176 SkASSERT(size <= sizeof(storage)); 177 178// SkDebugf("raw %d packed %d\n", count * 256, size); 179 180 buffer.writeInt(fFlags); 181 buffer.writeByteArray(storage, size); 182} 183 184SkTable_ColorFilter::SkTable_ColorFilter(SkReadBuffer& buffer) : INHERITED(buffer) { 185 fBitmap = NULL; 186 187 uint8_t storage[5*256]; 188 189 fFlags = buffer.readInt(); 190 191 size_t size = buffer.getArrayCount(); 192 SkASSERT(size <= sizeof(storage)); 193 buffer.validate(size <= sizeof(storage)); 194 buffer.readByteArray(storage, size); 195 196 SkDEBUGCODE(size_t raw = ) SkPackBits::Unpack8(storage, size, fStorage); 197 198 SkASSERT(raw <= sizeof(fStorage)); 199 SkDEBUGCODE(size_t count = gCountNibBits[fFlags & 0xF]); 200 SkASSERT(raw == count * 256); 201} 202 203bool SkTable_ColorFilter::asComponentTable(SkBitmap* table) const { 204 if (table) { 205 if (NULL == fBitmap) { 206 SkBitmap* bmp = SkNEW(SkBitmap); 207 bmp->allocPixels(SkImageInfo::MakeA8(256, 4)); 208 uint8_t* bitmapPixels = bmp->getAddr8(0, 0); 209 int offset = 0; 210 static const unsigned kFlags[] = { kA_Flag, kR_Flag, kG_Flag, kB_Flag }; 211 212 for (int x = 0; x < 4; ++x) { 213 if (!(fFlags & kFlags[x])) { 214 memcpy(bitmapPixels, gIdentityTable, sizeof(gIdentityTable)); 215 } else { 216 memcpy(bitmapPixels, fStorage + offset, 256); 217 offset += 256; 218 } 219 bitmapPixels += 256; 220 } 221 fBitmap = bmp; 222 } 223 *table = *fBitmap; 224 } 225 return true; 226} 227 228#if SK_SUPPORT_GPU 229 230#include "GrEffect.h" 231#include "GrTBackendEffectFactory.h" 232#include "gl/GrGLEffect.h" 233#include "SkGr.h" 234 235class GLColorTableEffect; 236 237class ColorTableEffect : public GrEffect { 238public: 239 static GrEffectRef* Create(GrTexture* texture, unsigned flags) { 240 AutoEffectUnref effect(SkNEW_ARGS(ColorTableEffect, (texture, flags))); 241 return CreateEffectRef(effect); 242 } 243 244 virtual ~ColorTableEffect(); 245 246 static const char* Name() { return "ColorTable"; } 247 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE; 248 249 virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE; 250 251 typedef GLColorTableEffect GLEffect; 252 253private: 254 virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE; 255 256 explicit ColorTableEffect(GrTexture* texture, unsigned flags); 257 258 GR_DECLARE_EFFECT_TEST; 259 260 GrTextureAccess fTextureAccess; 261 unsigned fFlags; // currently not used in shader code, just to assist 262 // getConstantColorComponents(). 263 264 typedef GrEffect INHERITED; 265}; 266 267class GLColorTableEffect : public GrGLEffect { 268public: 269 GLColorTableEffect(const GrBackendEffectFactory&, const GrDrawEffect&); 270 271 virtual void emitCode(GrGLShaderBuilder*, 272 const GrDrawEffect&, 273 EffectKey, 274 const char* outputColor, 275 const char* inputColor, 276 const TransformedCoordsArray&, 277 const TextureSamplerArray&) SK_OVERRIDE; 278 279 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE {} 280 281 static EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&); 282 283private: 284 285 typedef GrGLEffect INHERITED; 286}; 287 288GLColorTableEffect::GLColorTableEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&) 289 : INHERITED(factory) { 290 } 291 292void GLColorTableEffect::emitCode(GrGLShaderBuilder* builder, 293 const GrDrawEffect&, 294 EffectKey, 295 const char* outputColor, 296 const char* inputColor, 297 const TransformedCoordsArray&, 298 const TextureSamplerArray& samplers) { 299 300 static const float kColorScaleFactor = 255.0f / 256.0f; 301 static const float kColorOffsetFactor = 1.0f / 512.0f; 302 if (NULL == inputColor) { 303 // the input color is solid white (all ones). 304 static const float kMaxValue = kColorScaleFactor + kColorOffsetFactor; 305 builder->fsCodeAppendf("\t\tvec4 coord = vec4(%f, %f, %f, %f);\n", 306 kMaxValue, kMaxValue, kMaxValue, kMaxValue); 307 308 } else { 309 builder->fsCodeAppendf("\t\tfloat nonZeroAlpha = max(%s.a, .0001);\n", inputColor); 310 builder->fsCodeAppendf("\t\tvec4 coord = vec4(%s.rgb / nonZeroAlpha, nonZeroAlpha);\n", inputColor); 311 builder->fsCodeAppendf("\t\tcoord = coord * %f + vec4(%f, %f, %f, %f);\n", 312 kColorScaleFactor, 313 kColorOffsetFactor, kColorOffsetFactor, 314 kColorOffsetFactor, kColorOffsetFactor); 315 } 316 317 builder->fsCodeAppendf("\t\t%s.a = ", outputColor); 318 builder->fsAppendTextureLookup(samplers[0], "vec2(coord.a, 0.125)"); 319 builder->fsCodeAppend(";\n"); 320 321 builder->fsCodeAppendf("\t\t%s.r = ", outputColor); 322 builder->fsAppendTextureLookup(samplers[0], "vec2(coord.r, 0.375)"); 323 builder->fsCodeAppend(";\n"); 324 325 builder->fsCodeAppendf("\t\t%s.g = ", outputColor); 326 builder->fsAppendTextureLookup(samplers[0], "vec2(coord.g, 0.625)"); 327 builder->fsCodeAppend(";\n"); 328 329 builder->fsCodeAppendf("\t\t%s.b = ", outputColor); 330 builder->fsAppendTextureLookup(samplers[0], "vec2(coord.b, 0.875)"); 331 builder->fsCodeAppend(";\n"); 332 333 builder->fsCodeAppendf("\t\t%s.rgb *= %s.a;\n", outputColor, outputColor); 334} 335 336GrGLEffect::EffectKey GLColorTableEffect::GenKey(const GrDrawEffect&, const GrGLCaps&) { 337 return 0; 338} 339 340/////////////////////////////////////////////////////////////////////////////// 341 342ColorTableEffect::ColorTableEffect(GrTexture* texture, unsigned flags) 343 : fTextureAccess(texture, "a") 344 , fFlags(flags) { 345 this->addTextureAccess(&fTextureAccess); 346} 347 348ColorTableEffect::~ColorTableEffect() { 349} 350 351const GrBackendEffectFactory& ColorTableEffect::getFactory() const { 352 return GrTBackendEffectFactory<ColorTableEffect>::getInstance(); 353} 354 355bool ColorTableEffect::onIsEqual(const GrEffect& sBase) const { 356 return this->texture(0) == sBase.texture(0); 357} 358 359void ColorTableEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const { 360 // If we kept the table in the effect then we could actually run known inputs through the 361 // table. 362 if (fFlags & SkTable_ColorFilter::kR_Flag) { 363 *validFlags &= ~kR_GrColorComponentFlag; 364 } 365 if (fFlags & SkTable_ColorFilter::kG_Flag) { 366 *validFlags &= ~kG_GrColorComponentFlag; 367 } 368 if (fFlags & SkTable_ColorFilter::kB_Flag) { 369 *validFlags &= ~kB_GrColorComponentFlag; 370 } 371 if (fFlags & SkTable_ColorFilter::kA_Flag) { 372 *validFlags &= ~kA_GrColorComponentFlag; 373 } 374} 375 376 377/////////////////////////////////////////////////////////////////////////////// 378 379GR_DEFINE_EFFECT_TEST(ColorTableEffect); 380 381GrEffectRef* ColorTableEffect::TestCreate(SkRandom* random, 382 GrContext* context, 383 const GrDrawTargetCaps&, 384 GrTexture* textures[]) { 385 static unsigned kAllFlags = SkTable_ColorFilter::kR_Flag | SkTable_ColorFilter::kG_Flag | 386 SkTable_ColorFilter::kB_Flag | SkTable_ColorFilter::kA_Flag; 387 return ColorTableEffect::Create(textures[GrEffectUnitTest::kAlphaTextureIdx], kAllFlags); 388} 389 390GrEffectRef* SkTable_ColorFilter::asNewEffect(GrContext* context) const { 391 SkBitmap bitmap; 392 GrEffectRef* effect = NULL; 393 this->asComponentTable(&bitmap); 394 // passing NULL because this effect does no tiling or filtering. 395 GrTexture* texture = GrLockAndRefCachedBitmapTexture(context, bitmap, NULL); 396 if (NULL != texture) { 397 effect = ColorTableEffect::Create(texture, fFlags); 398 399 // Unlock immediately, this is not great, but we don't have a way of 400 // knowing when else to unlock it currently. TODO: Remove this when 401 // unref becomes the unlock replacement for all types of textures. 402 GrUnlockAndUnrefCachedBitmapTexture(texture); 403 } 404 return effect; 405} 406 407#endif // SK_SUPPORT_GPU 408 409/////////////////////////////////////////////////////////////////////////////// 410 411#ifdef SK_CPU_BENDIAN 412#else 413 #define SK_A32_INDEX (3 - (SK_A32_SHIFT >> 3)) 414 #define SK_R32_INDEX (3 - (SK_R32_SHIFT >> 3)) 415 #define SK_G32_INDEX (3 - (SK_G32_SHIFT >> 3)) 416 #define SK_B32_INDEX (3 - (SK_B32_SHIFT >> 3)) 417#endif 418 419/////////////////////////////////////////////////////////////////////////////// 420 421SkColorFilter* SkTableColorFilter::Create(const uint8_t table[256]) { 422 return SkNEW_ARGS(SkTable_ColorFilter, (table, table, table, table)); 423} 424 425SkColorFilter* SkTableColorFilter::CreateARGB(const uint8_t tableA[256], 426 const uint8_t tableR[256], 427 const uint8_t tableG[256], 428 const uint8_t tableB[256]) { 429 return SkNEW_ARGS(SkTable_ColorFilter, (tableA, tableR, tableG, tableB)); 430} 431 432SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkTableColorFilter) 433 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkTable_ColorFilter) 434SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END 435