blob: 71b4d16dba1ae7aa712f2c6986a169b368db0d7e [file] [log] [blame]
djsollen@google.comc73dd5c2012-08-07 15:54:32 +00001
reed@google.com02f65f22012-08-06 21:20:05 +00002#include "SkBitmap.h"
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +00003#include "SkTableColorFilter.h"
djsollen@google.comc73dd5c2012-08-07 15:54:32 +00004#include "SkColorPriv.h"
5#include "SkFlattenableBuffers.h"
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +00006#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[]) {
mike@reedtribe.orgf23f5f72012-01-07 03:48:45 +000012 fBitmap = NULL;
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +000013 fFlags = 0;
mike@reedtribe.orgf23f5f72012-01-07 03:48:45 +000014
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +000015 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
tomhudson@google.com1bb4be22012-07-24 17:24:21 +000037 virtual ~SkTable_ColorFilter() {
38 SkDELETE(fBitmap);
39 }
40
bsalomon@google.comb2ad1012012-10-17 15:00:32 +000041 virtual bool asComponentTable(SkBitmap* table) const SK_OVERRIDE;
42
43#if SK_SUPPORT_GPU
bsalomon@google.com8ea78d82012-10-24 20:11:30 +000044 virtual GrEffect* asNewEffect(GrContext* context) const SK_OVERRIDE;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +000045#endif
mike@reedtribe.orgf23f5f72012-01-07 03:48:45 +000046
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +000047 virtual void filterSpan(const SkPMColor src[], int count,
48 SkPMColor dst[]) SK_OVERRIDE;
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +000049
djsollen@google.comba28d032012-03-26 17:57:35 +000050 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkTable_ColorFilter)
mike@reedtribe.orgf23f5f72012-01-07 03:48:45 +000051
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +000052protected:
53 SkTable_ColorFilter(SkFlattenableReadBuffer& buffer);
djsollen@google.com54924242012-03-29 15:18:04 +000054 virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE;
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +000055
56private:
bsalomon@google.comb2ad1012012-10-17 15:00:32 +000057 mutable const SkBitmap* fBitmap; // lazily allocated
mike@reedtribe.orgf23f5f72012-01-07 03:48:45 +000058
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +000059 enum {
60 kA_Flag = 1 << 0,
61 kR_Flag = 1 << 1,
62 kG_Flag = 1 << 2,
63 kB_Flag = 1 << 3,
64 };
65 uint8_t fStorage[256 * 4];
66 unsigned fFlags;
67
68 typedef SkColorFilter INHERITED;
69};
70
71static const uint8_t gIdentityTable[] = {
rmistry@google.comfbfcd562012-08-23 18:09:54 +000072 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
73 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
74 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
75 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
76 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
77 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
78 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
79 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
80 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
81 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
82 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
83 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
84 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
85 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
86 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
87 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
88 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
89 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
90 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
91 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
92 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
93 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
94 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7,
95 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
96 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
97 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
98 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
99 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
100 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
101 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
102 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000103 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
104};
105
106void SkTable_ColorFilter::filterSpan(const SkPMColor src[], int count,
107 SkPMColor dst[]) {
108 const uint8_t* table = fStorage;
109 const uint8_t* tableA = gIdentityTable;
110 const uint8_t* tableR = gIdentityTable;
111 const uint8_t* tableG = gIdentityTable;
112 const uint8_t* tableB = gIdentityTable;
113 if (fFlags & kA_Flag) {
114 tableA = table; table += 256;
115 }
116 if (fFlags & kR_Flag) {
117 tableR = table; table += 256;
118 }
119 if (fFlags & kG_Flag) {
120 tableG = table; table += 256;
121 }
122 if (fFlags & kB_Flag) {
123 tableB = table;
124 }
125
126 const SkUnPreMultiply::Scale* scaleTable = SkUnPreMultiply::GetScaleTable();
127 for (int i = 0; i < count; ++i) {
128 SkPMColor c = src[i];
129 unsigned a, r, g, b;
130 if (0 == c) {
131 a = r = g = b = 0;
132 } else {
133 a = SkGetPackedA32(c);
134 r = SkGetPackedR32(c);
135 g = SkGetPackedG32(c);
136 b = SkGetPackedB32(c);
137
138 if (a < 255) {
139 SkUnPreMultiply::Scale scale = scaleTable[a];
140 r = SkUnPreMultiply::ApplyScale(scale, r);
141 g = SkUnPreMultiply::ApplyScale(scale, g);
142 b = SkUnPreMultiply::ApplyScale(scale, b);
143 }
144 }
145 dst[i] = SkPremultiplyARGBInline(tableA[a], tableR[r],
146 tableG[g], tableB[b]);
147 }
148}
149
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000150static const uint8_t gCountNibBits[] = {
151 0, 1, 1, 2,
152 1, 2, 2, 3,
153 1, 2, 2, 3,
154 2, 3, 3, 4
155};
156
157#include "SkPackBits.h"
158
djsollen@google.com54924242012-03-29 15:18:04 +0000159void SkTable_ColorFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000160 this->INHERITED::flatten(buffer);
161
162 uint8_t storage[5*256];
163 int count = gCountNibBits[fFlags & 0xF];
164 size_t size = SkPackBits::Pack8(fStorage, count * 256, storage);
165 SkASSERT(size <= sizeof(storage));
166
167// SkDebugf("raw %d packed %d\n", count * 256, size);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000168
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000169 buffer.writeInt(fFlags);
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000170 buffer.writeByteArray(storage, size);
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000171}
172
173SkTable_ColorFilter::SkTable_ColorFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
mike@reedtribe.orgf23f5f72012-01-07 03:48:45 +0000174 fBitmap = NULL;
175
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000176 uint8_t storage[5*256];
177
178 fFlags = buffer.readInt();
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000179
180 size_t size = buffer.getArrayCount();
181 SkASSERT(size <= sizeof(storage));
182 buffer.readByteArray(storage);
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000183
184 size_t raw = SkPackBits::Unpack8(storage, size, fStorage);
185
186 SkASSERT(raw <= sizeof(fStorage));
bsalomon@google.comcadbcb82012-01-06 19:22:11 +0000187 size_t count = gCountNibBits[fFlags & 0xF];
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000188 SkASSERT(raw == count * 256);
189}
190
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000191bool SkTable_ColorFilter::asComponentTable(SkBitmap* table) const {
mike@reedtribe.orgf23f5f72012-01-07 03:48:45 +0000192 if (table) {
193 if (NULL == fBitmap) {
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000194 SkBitmap* bmp = SkNEW(SkBitmap);
195 bmp->setConfig(SkBitmap::kA8_Config, 256, 4, 256);
196 bmp->allocPixels();
197 uint8_t* bitmapPixels = bmp->getAddr8(0, 0);
twiz@google.com58071162012-07-18 21:41:50 +0000198 int offset = 0;
199 static const unsigned kFlags[] = { kA_Flag, kR_Flag, kG_Flag, kB_Flag };
200
201 for (int x = 0; x < 4; ++x) {
202 if (!(fFlags & kFlags[x])) {
203 memcpy(bitmapPixels, gIdentityTable, sizeof(gIdentityTable));
204 } else {
205 memcpy(bitmapPixels, fStorage + offset, 256);
206 offset += 256;
207 }
208 bitmapPixels += 256;
209 }
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000210 fBitmap = bmp;
mike@reedtribe.orgf23f5f72012-01-07 03:48:45 +0000211 }
212 *table = *fBitmap;
213 }
214 return true;
215}
216
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000217#if SK_SUPPORT_GPU
218
bsalomon@google.coma469c282012-10-24 18:28:34 +0000219#include "GrEffect.h"
bsalomon@google.comd698f772012-10-25 13:22:00 +0000220#include "gl/GrGLEffect.h"
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000221#include "SkGr.h"
222
223class GLColorTableEffect;
224
bsalomon@google.coma469c282012-10-24 18:28:34 +0000225class ColorTableEffect : public GrEffect {
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000226public:
227
228 explicit ColorTableEffect(GrTexture* texture);
229 virtual ~ColorTableEffect();
230
231 static const char* Name() { return "ColorTable"; }
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000232 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
bsalomon@google.coma469c282012-10-24 18:28:34 +0000233 virtual bool isEqual(const GrEffect&) const SK_OVERRIDE;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000234
235 virtual const GrTextureAccess& textureAccess(int index) const SK_OVERRIDE;
236
bsalomon@google.com422e81a2012-10-25 14:11:03 +0000237 typedef GLColorTableEffect GLEffect;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000238
239private:
bsalomon@google.comf271cc72012-10-24 19:35:13 +0000240 GR_DECLARE_EFFECT_TEST;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000241
242 GrTextureAccess fTextureAccess;
243
bsalomon@google.coma469c282012-10-24 18:28:34 +0000244 typedef GrEffect INHERITED;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000245};
246
bsalomon@google.com22a800a2012-10-26 19:16:46 +0000247class GLColorTableEffect : public GrGLEffect {
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000248public:
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000249 GLColorTableEffect(const GrBackendEffectFactory& factory,
bsalomon@google.com021fc732012-10-25 12:47:42 +0000250 const GrEffect& effect);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000251
bsalomon@google.com22a800a2012-10-26 19:16:46 +0000252 virtual void emitCode(GrGLShaderBuilder*,
253 const GrEffect&,
254 EffectKey,
255 const char* vertexCoords,
256 const char* outputColor,
257 const char* inputColor,
258 const TextureSamplerArray&) SK_OVERRIDE;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000259
bsalomon@google.com28a15fb2012-10-26 17:53:18 +0000260 virtual void setData(const GrGLUniformManager&, const GrEffectStage&) SK_OVERRIDE {}
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000261
bsalomon@google.com46fba0d2012-10-25 21:42:05 +0000262 static EffectKey GenKey(const GrEffect&, const GrGLCaps&);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000263
264private:
265
bsalomon@google.com22a800a2012-10-26 19:16:46 +0000266 typedef GrGLEffect INHERITED;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000267};
268
269GLColorTableEffect::GLColorTableEffect(
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000270 const GrBackendEffectFactory& factory, const GrEffect& effect)
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000271 : INHERITED(factory) {
272 }
273
bsalomon@google.com22a800a2012-10-26 19:16:46 +0000274void GLColorTableEffect::emitCode(GrGLShaderBuilder* builder,
275 const GrEffect&,
276 EffectKey,
277 const char* vertexCoords,
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000278 const char* outputColor,
279 const char* inputColor,
280 const TextureSamplerArray& samplers) {
bsalomon@google.com22a800a2012-10-26 19:16:46 +0000281
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000282 static const float kColorScaleFactor = 255.0f / 256.0f;
283 static const float kColorOffsetFactor = 1.0f / 512.0f;
284 SkString* code = &builder->fFSCode;
285 if (NULL == inputColor) {
286 // the input color is solid white (all ones).
287 static const float kMaxValue = kColorScaleFactor + kColorOffsetFactor;
288 code->appendf("\t\tvec4 coord = vec4(%f, %f, %f, %f);\n",
289 kMaxValue, kMaxValue, kMaxValue, kMaxValue);
290
291 } else {
292 code->appendf("\t\tfloat nonZeroAlpha = max(%s.a, .0001);\n", inputColor);
293 code->appendf("\t\tvec4 coord = vec4(%s.rgb / nonZeroAlpha, nonZeroAlpha);\n", inputColor);
294 code->appendf("\t\tcoord = coord * %f + vec4(%f, %f, %f, %f);\n",
295 kColorScaleFactor,
296 kColorOffsetFactor, kColorOffsetFactor,
297 kColorOffsetFactor, kColorOffsetFactor);
298 }
299
300 code->appendf("\t\t%s.a = ", outputColor);
301 builder->appendTextureLookup(code, samplers[0], "vec2(coord.a, 0.125)");
302 code->append(";\n");
303
304 code->appendf("\t\t%s.r = ", outputColor);
305 builder->appendTextureLookup(code, samplers[0], "vec2(coord.r, 0.375)");
306 code->append(";\n");
307
308 code->appendf("\t\t%s.g = ", outputColor);
309 builder->appendTextureLookup(code, samplers[0], "vec2(coord.g, 0.625)");
310 code->append(";\n");
311
312 code->appendf("\t\t%s.b = ", outputColor);
313 builder->appendTextureLookup(code, samplers[0], "vec2(coord.b, 0.875)");
314 code->append(";\n");
315
316 code->appendf("\t\t%s.rgb *= %s.a;\n", outputColor, outputColor);
317}
318
bsalomon@google.com46fba0d2012-10-25 21:42:05 +0000319GrGLEffect::EffectKey GLColorTableEffect::GenKey(const GrEffect& s,
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000320 const GrGLCaps& caps) {
321 return 0;
322}
323
324///////////////////////////////////////////////////////////////////////////////
325
326ColorTableEffect::ColorTableEffect(GrTexture* texture)
327 : INHERITED(1)
328 , fTextureAccess(texture, "a") {
329}
330
331ColorTableEffect::~ColorTableEffect() {
332}
333
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000334const GrBackendEffectFactory& ColorTableEffect::getFactory() const {
335 return GrTBackendEffectFactory<ColorTableEffect>::getInstance();
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000336}
337
bsalomon@google.coma469c282012-10-24 18:28:34 +0000338bool ColorTableEffect::isEqual(const GrEffect& sBase) const {
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000339 return INHERITED::isEqual(sBase);
340}
341
342const GrTextureAccess& ColorTableEffect::textureAccess(int index) const {
343 GrAssert(0 == index);
344 return fTextureAccess;
345}
346
347///////////////////////////////////////////////////////////////////////////////
348
bsalomon@google.comf271cc72012-10-24 19:35:13 +0000349GR_DEFINE_EFFECT_TEST(ColorTableEffect);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000350
bsalomon@google.coma469c282012-10-24 18:28:34 +0000351GrEffect* ColorTableEffect::TestCreate(SkRandom* random,
352 GrContext* context,
353 GrTexture* textures[]) {
bsalomon@google.com6f261be2012-10-24 19:07:10 +0000354 return SkNEW_ARGS(ColorTableEffect, (textures[GrEffectUnitTest::kAlphaTextureIdx]));
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000355}
356
bsalomon@google.com8ea78d82012-10-24 20:11:30 +0000357GrEffect* SkTable_ColorFilter::asNewEffect(GrContext* context) const {
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000358 SkBitmap bitmap;
359 this->asComponentTable(&bitmap);
bsalomon@google.com8ea78d82012-10-24 20:11:30 +0000360 // passing NULL because this effect does no tiling or filtering.
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000361 GrTexture* texture = GrLockCachedBitmapTexture(context, bitmap, NULL);
bsalomon@google.com021fc732012-10-25 12:47:42 +0000362 GrEffect* effect = SkNEW_ARGS(ColorTableEffect, (texture));
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000363
364 // Unlock immediately, this is not great, but we don't have a way of
365 // knowing when else to unlock it currently. TODO: Remove this when
366 // unref becomes the unlock replacement for all types of textures.
367 GrUnlockCachedBitmapTexture(texture);
bsalomon@google.com021fc732012-10-25 12:47:42 +0000368 return effect;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000369}
370
371#endif // SK_SUPPORT_GPU
372
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000373///////////////////////////////////////////////////////////////////////////////
374
375#ifdef SK_CPU_BENDIAN
376#else
377 #define SK_A32_INDEX (3 - (SK_A32_SHIFT >> 3))
378 #define SK_R32_INDEX (3 - (SK_R32_SHIFT >> 3))
379 #define SK_G32_INDEX (3 - (SK_G32_SHIFT >> 3))
380 #define SK_B32_INDEX (3 - (SK_B32_SHIFT >> 3))
381#endif
382
383///////////////////////////////////////////////////////////////////////////////
384
385SkColorFilter* SkTableColorFilter::Create(const uint8_t table[256]) {
386 return SkNEW_ARGS(SkTable_ColorFilter, (table, table, table, table));
387}
388
389SkColorFilter* SkTableColorFilter::CreateARGB(const uint8_t tableA[256],
390 const uint8_t tableR[256],
391 const uint8_t tableG[256],
392 const uint8_t tableB[256]) {
393 return SkNEW_ARGS(SkTable_ColorFilter, (tableA, tableR, tableG, tableB));
394}
djsollen@google.coma2ca41e2012-03-23 19:00:34 +0000395
396SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkTableColorFilter)
397 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkTable_ColorFilter)
398SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END