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