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