3 #include "SkTableColorFilter.h"
4 #include "SkColorPriv.h"
5 #include "SkReadBuffer.h"
6 #include "SkWriteBuffer.h"
7 #include "SkUnPreMultiply.h"
10 class SkTable_ColorFilter : public SkColorFilter {
12 SkTable_ColorFilter(const uint8_t tableA[], const uint8_t tableR[],
13 const uint8_t tableG[], const uint8_t tableB[]) {
17 uint8_t* dst = fStorage;
19 memcpy(dst, tableA, 256);
24 memcpy(dst, tableR, 256);
29 memcpy(dst, tableG, 256);
34 memcpy(dst, tableB, 256);
39 virtual ~SkTable_ColorFilter() {
43 virtual bool asComponentTable(SkBitmap* table) const SK_OVERRIDE;
46 virtual GrFragmentProcessor* asFragmentProcessor(GrContext* context) const SK_OVERRIDE;
49 virtual void filterSpan(const SkPMColor src[], int count,
50 SkPMColor dst[]) const SK_OVERRIDE;
52 SK_TO_STRING_OVERRIDE()
54 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkTable_ColorFilter)
64 #ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
65 SkTable_ColorFilter(SkReadBuffer& buffer);
67 virtual void flatten(SkWriteBuffer&) const SK_OVERRIDE;
70 mutable const SkBitmap* fBitmap; // lazily allocated
72 uint8_t fStorage[256 * 4];
75 friend class SkTableColorFilter;
77 typedef SkColorFilter INHERITED;
80 static const uint8_t gIdentityTable[] = {
81 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
82 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
83 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
84 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
85 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
86 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
87 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
88 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
89 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
90 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
91 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
92 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
93 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
94 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
95 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
96 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
97 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
98 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
99 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
100 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
101 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
102 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
103 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7,
104 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
105 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
106 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
107 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
108 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
109 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
110 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
111 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
112 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
115 void SkTable_ColorFilter::filterSpan(const SkPMColor src[], int count,
116 SkPMColor dst[]) const {
117 const uint8_t* table = fStorage;
118 const uint8_t* tableA = gIdentityTable;
119 const uint8_t* tableR = gIdentityTable;
120 const uint8_t* tableG = gIdentityTable;
121 const uint8_t* tableB = gIdentityTable;
122 if (fFlags & kA_Flag) {
123 tableA = table; table += 256;
125 if (fFlags & kR_Flag) {
126 tableR = table; table += 256;
128 if (fFlags & kG_Flag) {
129 tableG = table; table += 256;
131 if (fFlags & kB_Flag) {
135 const SkUnPreMultiply::Scale* scaleTable = SkUnPreMultiply::GetScaleTable();
136 for (int i = 0; i < count; ++i) {
137 SkPMColor c = src[i];
142 a = SkGetPackedA32(c);
143 r = SkGetPackedR32(c);
144 g = SkGetPackedG32(c);
145 b = SkGetPackedB32(c);
148 SkUnPreMultiply::Scale scale = scaleTable[a];
149 r = SkUnPreMultiply::ApplyScale(scale, r);
150 g = SkUnPreMultiply::ApplyScale(scale, g);
151 b = SkUnPreMultiply::ApplyScale(scale, b);
154 dst[i] = SkPremultiplyARGBInline(tableA[a], tableR[r],
155 tableG[g], tableB[b]);
159 #ifndef SK_IGNORE_TO_STRING
160 void SkTable_ColorFilter::toString(SkString* str) const {
161 str->append("SkTable_ColorFilter");
165 static const uint8_t gCountNibBits[] = {
172 #include "SkPackBits.h"
174 void SkTable_ColorFilter::flatten(SkWriteBuffer& buffer) const {
175 uint8_t storage[5*256];
176 int count = gCountNibBits[fFlags & 0xF];
177 size_t size = SkPackBits::Pack8(fStorage, count * 256, storage);
178 SkASSERT(size <= sizeof(storage));
180 buffer.write32(fFlags);
181 buffer.writeByteArray(storage, size);
184 SkFlattenable* SkTable_ColorFilter::CreateProc(SkReadBuffer& buffer) {
185 const int flags = buffer.read32();
186 const size_t count = gCountNibBits[flags & 0xF];
187 SkASSERT(count <= 4);
189 uint8_t packedStorage[5*256];
190 size_t packedSize = buffer.getArrayCount();
191 if (!buffer.validate(packedSize <= sizeof(packedStorage))) {
194 if (!buffer.readByteArray(packedStorage, packedSize)) {
198 uint8_t unpackedStorage[4*256];
199 size_t unpackedSize = SkPackBits::Unpack8(packedStorage, packedSize, unpackedStorage);
200 // now check that we got the size we expected
201 if (!buffer.validate(unpackedSize == count*256)) {
205 const uint8_t* a = NULL;
206 const uint8_t* r = NULL;
207 const uint8_t* g = NULL;
208 const uint8_t* b = NULL;
209 const uint8_t* ptr = unpackedStorage;
211 if (flags & kA_Flag) {
215 if (flags & kR_Flag) {
219 if (flags & kG_Flag) {
223 if (flags & kB_Flag) {
227 return SkTableColorFilter::CreateARGB(a, r, g, b);
230 #ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
231 SkTable_ColorFilter::SkTable_ColorFilter(SkReadBuffer& buffer) : INHERITED(buffer) {
234 uint8_t storage[5*256];
236 fFlags = buffer.readInt();
238 size_t size = buffer.getArrayCount();
239 SkASSERT(size <= sizeof(storage));
240 buffer.validate(size <= sizeof(storage));
241 buffer.readByteArray(storage, size);
243 SkDEBUGCODE(size_t raw = ) SkPackBits::Unpack8(storage, size, fStorage);
245 SkASSERT(raw <= sizeof(fStorage));
246 SkDEBUGCODE(size_t count = gCountNibBits[fFlags & 0xF]);
247 SkASSERT(raw == count * 256);
251 bool SkTable_ColorFilter::asComponentTable(SkBitmap* table) const {
253 if (NULL == fBitmap) {
254 SkBitmap* bmp = SkNEW(SkBitmap);
255 bmp->allocPixels(SkImageInfo::MakeA8(256, 4));
256 uint8_t* bitmapPixels = bmp->getAddr8(0, 0);
258 static const unsigned kFlags[] = { kA_Flag, kR_Flag, kG_Flag, kB_Flag };
260 for (int x = 0; x < 4; ++x) {
261 if (!(fFlags & kFlags[x])) {
262 memcpy(bitmapPixels, gIdentityTable, sizeof(gIdentityTable));
264 memcpy(bitmapPixels, fStorage + offset, 256);
278 #include "GrProcessor.h"
279 #include "GrTBackendProcessorFactory.h"
280 #include "gl/GrGLProcessor.h"
281 #include "gl/builders/GrGLProgramBuilder.h"
284 class GLColorTableEffect;
286 class ColorTableEffect : public GrFragmentProcessor {
288 static GrFragmentProcessor* Create(GrTexture* texture, unsigned flags) {
289 return SkNEW_ARGS(ColorTableEffect, (texture, flags));
292 virtual ~ColorTableEffect();
294 static const char* Name() { return "ColorTable"; }
295 virtual const GrBackendFragmentProcessorFactory& getFactory() const SK_OVERRIDE;
297 virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
299 typedef GLColorTableEffect GLProcessor;
302 virtual bool onIsEqual(const GrProcessor&) const SK_OVERRIDE;
304 explicit ColorTableEffect(GrTexture* texture, unsigned flags);
306 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
308 GrTextureAccess fTextureAccess;
309 unsigned fFlags; // currently not used in shader code, just to assist
310 // getConstantColorComponents().
312 typedef GrFragmentProcessor INHERITED;
315 class GLColorTableEffect : public GrGLFragmentProcessor {
317 GLColorTableEffect(const GrBackendProcessorFactory&, const GrProcessor&);
319 virtual void emitCode(GrGLProgramBuilder*,
320 const GrFragmentProcessor&,
321 const GrProcessorKey&,
322 const char* outputColor,
323 const char* inputColor,
324 const TransformedCoordsArray&,
325 const TextureSamplerArray&) SK_OVERRIDE;
327 virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE {}
329 static void GenKey(const GrProcessor&, const GrGLCaps&, GrProcessorKeyBuilder* b) {}
333 typedef GrGLFragmentProcessor INHERITED;
336 GLColorTableEffect::GLColorTableEffect(const GrBackendProcessorFactory& factory, const GrProcessor&)
337 : INHERITED(factory) {
340 void GLColorTableEffect::emitCode(GrGLProgramBuilder* builder,
341 const GrFragmentProcessor&,
342 const GrProcessorKey&,
343 const char* outputColor,
344 const char* inputColor,
345 const TransformedCoordsArray&,
346 const TextureSamplerArray& samplers) {
348 static const float kColorScaleFactor = 255.0f / 256.0f;
349 static const float kColorOffsetFactor = 1.0f / 512.0f;
350 GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
351 if (NULL == inputColor) {
352 // the input color is solid white (all ones).
353 static const float kMaxValue = kColorScaleFactor + kColorOffsetFactor;
354 fsBuilder->codeAppendf("\t\tvec4 coord = vec4(%f, %f, %f, %f);\n",
355 kMaxValue, kMaxValue, kMaxValue, kMaxValue);
358 fsBuilder->codeAppendf("\t\tfloat nonZeroAlpha = max(%s.a, .0001);\n", inputColor);
359 fsBuilder->codeAppendf("\t\tvec4 coord = vec4(%s.rgb / nonZeroAlpha, nonZeroAlpha);\n", inputColor);
360 fsBuilder->codeAppendf("\t\tcoord = coord * %f + vec4(%f, %f, %f, %f);\n",
362 kColorOffsetFactor, kColorOffsetFactor,
363 kColorOffsetFactor, kColorOffsetFactor);
366 fsBuilder->codeAppendf("\t\t%s.a = ", outputColor);
367 fsBuilder->appendTextureLookup(samplers[0], "vec2(coord.a, 0.125)");
368 fsBuilder->codeAppend(";\n");
370 fsBuilder->codeAppendf("\t\t%s.r = ", outputColor);
371 fsBuilder->appendTextureLookup(samplers[0], "vec2(coord.r, 0.375)");
372 fsBuilder->codeAppend(";\n");
374 fsBuilder->codeAppendf("\t\t%s.g = ", outputColor);
375 fsBuilder->appendTextureLookup(samplers[0], "vec2(coord.g, 0.625)");
376 fsBuilder->codeAppend(";\n");
378 fsBuilder->codeAppendf("\t\t%s.b = ", outputColor);
379 fsBuilder->appendTextureLookup(samplers[0], "vec2(coord.b, 0.875)");
380 fsBuilder->codeAppend(";\n");
382 fsBuilder->codeAppendf("\t\t%s.rgb *= %s.a;\n", outputColor, outputColor);
385 ///////////////////////////////////////////////////////////////////////////////
387 ColorTableEffect::ColorTableEffect(GrTexture* texture, unsigned flags)
388 : fTextureAccess(texture, "a")
390 this->addTextureAccess(&fTextureAccess);
393 ColorTableEffect::~ColorTableEffect() {
396 const GrBackendFragmentProcessorFactory& ColorTableEffect::getFactory() const {
397 return GrTBackendFragmentProcessorFactory<ColorTableEffect>::getInstance();
400 bool ColorTableEffect::onIsEqual(const GrProcessor& sBase) const {
401 return this->texture(0) == sBase.texture(0);
404 void ColorTableEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
405 // If we kept the table in the effect then we could actually run known inputs through the
407 if (fFlags & SkTable_ColorFilter::kR_Flag) {
408 *validFlags &= ~kR_GrColorComponentFlag;
410 if (fFlags & SkTable_ColorFilter::kG_Flag) {
411 *validFlags &= ~kG_GrColorComponentFlag;
413 if (fFlags & SkTable_ColorFilter::kB_Flag) {
414 *validFlags &= ~kB_GrColorComponentFlag;
416 if (fFlags & SkTable_ColorFilter::kA_Flag) {
417 *validFlags &= ~kA_GrColorComponentFlag;
422 ///////////////////////////////////////////////////////////////////////////////
424 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ColorTableEffect);
426 GrFragmentProcessor* ColorTableEffect::TestCreate(SkRandom* random,
428 const GrDrawTargetCaps&,
429 GrTexture* textures[]) {
430 static unsigned kAllFlags = SkTable_ColorFilter::kR_Flag | SkTable_ColorFilter::kG_Flag |
431 SkTable_ColorFilter::kB_Flag | SkTable_ColorFilter::kA_Flag;
432 return ColorTableEffect::Create(textures[GrProcessorUnitTest::kAlphaTextureIdx], kAllFlags);
435 GrFragmentProcessor* SkTable_ColorFilter::asFragmentProcessor(GrContext* context) const {
437 GrFragmentProcessor* fp = NULL;
438 this->asComponentTable(&bitmap);
439 // passing NULL because this effect does no tiling or filtering.
440 GrTexture* texture = GrLockAndRefCachedBitmapTexture(context, bitmap, NULL);
442 fp = ColorTableEffect::Create(texture, fFlags);
444 // Unlock immediately, this is not great, but we don't have a way of
445 // knowing when else to unlock it currently. TODO: Remove this when
446 // unref becomes the unlock replacement for all types of textures.
447 GrUnlockAndUnrefCachedBitmapTexture(texture);
452 #endif // SK_SUPPORT_GPU
454 ///////////////////////////////////////////////////////////////////////////////
456 #ifdef SK_CPU_BENDIAN
458 #define SK_A32_INDEX (3 - (SK_A32_SHIFT >> 3))
459 #define SK_R32_INDEX (3 - (SK_R32_SHIFT >> 3))
460 #define SK_G32_INDEX (3 - (SK_G32_SHIFT >> 3))
461 #define SK_B32_INDEX (3 - (SK_B32_SHIFT >> 3))
464 ///////////////////////////////////////////////////////////////////////////////
466 SkColorFilter* SkTableColorFilter::Create(const uint8_t table[256]) {
467 return SkNEW_ARGS(SkTable_ColorFilter, (table, table, table, table));
470 SkColorFilter* SkTableColorFilter::CreateARGB(const uint8_t tableA[256],
471 const uint8_t tableR[256],
472 const uint8_t tableG[256],
473 const uint8_t tableB[256]) {
474 return SkNEW_ARGS(SkTable_ColorFilter, (tableA, tableR, tableG, tableB));
477 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkTableColorFilter)
478 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkTable_ColorFilter)
479 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END