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