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