SkTableColorFilter.cpp revision c7d624ec535adcc388cad35b3475872b08cd90c0
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); 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 TextureSamplerArray&) SK_OVERRIDE; 276 277 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE {} 278 279 static EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&); 280 281private: 282 283 typedef GrGLEffect INHERITED; 284}; 285 286GLColorTableEffect::GLColorTableEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&) 287 : INHERITED(factory) { 288 } 289 290void GLColorTableEffect::emitCode(GrGLShaderBuilder* builder, 291 const GrDrawEffect&, 292 EffectKey, 293 const char* outputColor, 294 const char* inputColor, 295 const TextureSamplerArray& samplers) { 296 297 static const float kColorScaleFactor = 255.0f / 256.0f; 298 static const float kColorOffsetFactor = 1.0f / 512.0f; 299 if (NULL == inputColor) { 300 // the input color is solid white (all ones). 301 static const float kMaxValue = kColorScaleFactor + kColorOffsetFactor; 302 builder->fsCodeAppendf("\t\tvec4 coord = vec4(%f, %f, %f, %f);\n", 303 kMaxValue, kMaxValue, kMaxValue, kMaxValue); 304 305 } else { 306 builder->fsCodeAppendf("\t\tfloat nonZeroAlpha = max(%s.a, .0001);\n", inputColor); 307 builder->fsCodeAppendf("\t\tvec4 coord = vec4(%s.rgb / nonZeroAlpha, nonZeroAlpha);\n", inputColor); 308 builder->fsCodeAppendf("\t\tcoord = coord * %f + vec4(%f, %f, %f, %f);\n", 309 kColorScaleFactor, 310 kColorOffsetFactor, kColorOffsetFactor, 311 kColorOffsetFactor, kColorOffsetFactor); 312 } 313 314 builder->fsCodeAppendf("\t\t%s.a = ", outputColor); 315 builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType, samplers[0], "vec2(coord.a, 0.125)"); 316 builder->fsCodeAppend(";\n"); 317 318 builder->fsCodeAppendf("\t\t%s.r = ", outputColor); 319 builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType, samplers[0], "vec2(coord.r, 0.375)"); 320 builder->fsCodeAppend(";\n"); 321 322 builder->fsCodeAppendf("\t\t%s.g = ", outputColor); 323 builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType, samplers[0], "vec2(coord.g, 0.625)"); 324 builder->fsCodeAppend(";\n"); 325 326 builder->fsCodeAppendf("\t\t%s.b = ", outputColor); 327 builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType, samplers[0], "vec2(coord.b, 0.875)"); 328 builder->fsCodeAppend(";\n"); 329 330 builder->fsCodeAppendf("\t\t%s.rgb *= %s.a;\n", outputColor, outputColor); 331} 332 333GrGLEffect::EffectKey GLColorTableEffect::GenKey(const GrDrawEffect&, const GrGLCaps&) { 334 return 0; 335} 336 337/////////////////////////////////////////////////////////////////////////////// 338 339ColorTableEffect::ColorTableEffect(GrTexture* texture, unsigned flags) 340 : fTextureAccess(texture, "a") 341 , fFlags(flags) { 342 this->addTextureAccess(&fTextureAccess); 343} 344 345ColorTableEffect::~ColorTableEffect() { 346} 347 348const GrBackendEffectFactory& ColorTableEffect::getFactory() const { 349 return GrTBackendEffectFactory<ColorTableEffect>::getInstance(); 350} 351 352bool ColorTableEffect::onIsEqual(const GrEffect& sBase) const { 353 return this->texture(0) == sBase.texture(0); 354} 355 356void ColorTableEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const { 357 // If we kept the table in the effect then we could actually run known inputs through the 358 // table. 359 if (fFlags & SkTable_ColorFilter::kR_Flag) { 360 *validFlags &= ~kR_GrColorComponentFlag; 361 } 362 if (fFlags & SkTable_ColorFilter::kG_Flag) { 363 *validFlags &= ~kG_GrColorComponentFlag; 364 } 365 if (fFlags & SkTable_ColorFilter::kB_Flag) { 366 *validFlags &= ~kB_GrColorComponentFlag; 367 } 368 if (fFlags & SkTable_ColorFilter::kA_Flag) { 369 *validFlags &= ~kA_GrColorComponentFlag; 370 } 371} 372 373 374/////////////////////////////////////////////////////////////////////////////// 375 376GR_DEFINE_EFFECT_TEST(ColorTableEffect); 377 378GrEffectRef* ColorTableEffect::TestCreate(SkMWCRandom* random, 379 GrContext* context, 380 const GrDrawTargetCaps&, 381 GrTexture* textures[]) { 382 static unsigned kAllFlags = SkTable_ColorFilter::kR_Flag | SkTable_ColorFilter::kG_Flag | 383 SkTable_ColorFilter::kB_Flag | SkTable_ColorFilter::kA_Flag; 384 return ColorTableEffect::Create(textures[GrEffectUnitTest::kAlphaTextureIdx], kAllFlags); 385} 386 387GrEffectRef* SkTable_ColorFilter::asNewEffect(GrContext* context) const { 388 SkBitmap bitmap; 389 GrEffectRef* effect = NULL; 390 this->asComponentTable(&bitmap); 391 // passing NULL because this effect does no tiling or filtering. 392 GrTexture* texture = GrLockAndRefCachedBitmapTexture(context, bitmap, NULL); 393 if (NULL != texture) { 394 effect = ColorTableEffect::Create(texture, fFlags); 395 396 // Unlock immediately, this is not great, but we don't have a way of 397 // knowing when else to unlock it currently. TODO: Remove this when 398 // unref becomes the unlock replacement for all types of textures. 399 GrUnlockAndUnrefCachedBitmapTexture(texture); 400 } 401 return effect; 402} 403 404#endif // SK_SUPPORT_GPU 405 406/////////////////////////////////////////////////////////////////////////////// 407 408#ifdef SK_CPU_BENDIAN 409#else 410 #define SK_A32_INDEX (3 - (SK_A32_SHIFT >> 3)) 411 #define SK_R32_INDEX (3 - (SK_R32_SHIFT >> 3)) 412 #define SK_G32_INDEX (3 - (SK_G32_SHIFT >> 3)) 413 #define SK_B32_INDEX (3 - (SK_B32_SHIFT >> 3)) 414#endif 415 416/////////////////////////////////////////////////////////////////////////////// 417 418SkColorFilter* SkTableColorFilter::Create(const uint8_t table[256]) { 419 return SkNEW_ARGS(SkTable_ColorFilter, (table, table, table, table)); 420} 421 422SkColorFilter* SkTableColorFilter::CreateARGB(const uint8_t tableA[256], 423 const uint8_t tableR[256], 424 const uint8_t tableG[256], 425 const uint8_t tableB[256]) { 426 return SkNEW_ARGS(SkTable_ColorFilter, (tableA, tableR, tableG, tableB)); 427} 428 429SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkTableColorFilter) 430 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkTable_ColorFilter) 431SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END 432