blob: 83049f29c6c29dcb2cab9ff1040a4862277f79b3 [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
44 virtual GrCustomStage* asNewCustomStage(GrContext* context) const SK_OVERRIDE;
45#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
219#include "GrCustomStage.h"
220#include "gl/GrGLProgramStage.h"
221#include "SkGr.h"
222
223class GLColorTableEffect;
224
225class ColorTableEffect : public GrCustomStage {
226public:
227
228 explicit ColorTableEffect(GrTexture* texture);
229 virtual ~ColorTableEffect();
230
231 static const char* Name() { return "ColorTable"; }
232 virtual const GrProgramStageFactory& getFactory() const SK_OVERRIDE;
233 virtual bool isEqual(const GrCustomStage&) const SK_OVERRIDE;
234
235 virtual const GrTextureAccess& textureAccess(int index) const SK_OVERRIDE;
236
237 typedef GLColorTableEffect GLProgramStage;
238
239private:
240 GR_DECLARE_CUSTOM_STAGE_TEST;
241
242 GrTextureAccess fTextureAccess;
243
244 typedef GrCustomStage INHERITED;
245};
246
247class GLColorTableEffect : public GrGLProgramStage {
248public:
249 GLColorTableEffect(const GrProgramStageFactory& factory,
250 const GrCustomStage& stage);
251
252 virtual void setupVariables(GrGLShaderBuilder* state) SK_OVERRIDE {}
253 virtual void emitVS(GrGLShaderBuilder* state,
254 const char* vertexCoords) SK_OVERRIDE {}
255 virtual void emitFS(GrGLShaderBuilder* state,
256 const char* outputColor,
257 const char* inputColor,
258 const TextureSamplerArray&) SK_OVERRIDE;
259
260 virtual void setData(const GrGLUniformManager&,
261 const GrCustomStage&,
262 const GrRenderTarget*,
263 int stageNum) SK_OVERRIDE {}
264
265 static StageKey GenKey(const GrCustomStage&, const GrGLCaps&);
266
267private:
268
269 typedef GrGLProgramStage INHERITED;
270};
271
272GLColorTableEffect::GLColorTableEffect(
273 const GrProgramStageFactory& factory, const GrCustomStage& stage)
274 : INHERITED(factory) {
275 }
276
277void GLColorTableEffect::emitFS(GrGLShaderBuilder* builder,
278 const char* outputColor,
279 const char* inputColor,
280 const TextureSamplerArray& samplers) {
281 static const float kColorScaleFactor = 255.0f / 256.0f;
282 static const float kColorOffsetFactor = 1.0f / 512.0f;
283 SkString* code = &builder->fFSCode;
284 if (NULL == inputColor) {
285 // the input color is solid white (all ones).
286 static const float kMaxValue = kColorScaleFactor + kColorOffsetFactor;
287 code->appendf("\t\tvec4 coord = vec4(%f, %f, %f, %f);\n",
288 kMaxValue, kMaxValue, kMaxValue, kMaxValue);
289
290 } else {
291 code->appendf("\t\tfloat nonZeroAlpha = max(%s.a, .0001);\n", inputColor);
292 code->appendf("\t\tvec4 coord = vec4(%s.rgb / nonZeroAlpha, nonZeroAlpha);\n", inputColor);
293 code->appendf("\t\tcoord = coord * %f + vec4(%f, %f, %f, %f);\n",
294 kColorScaleFactor,
295 kColorOffsetFactor, kColorOffsetFactor,
296 kColorOffsetFactor, kColorOffsetFactor);
297 }
298
299 code->appendf("\t\t%s.a = ", outputColor);
300 builder->appendTextureLookup(code, samplers[0], "vec2(coord.a, 0.125)");
301 code->append(";\n");
302
303 code->appendf("\t\t%s.r = ", outputColor);
304 builder->appendTextureLookup(code, samplers[0], "vec2(coord.r, 0.375)");
305 code->append(";\n");
306
307 code->appendf("\t\t%s.g = ", outputColor);
308 builder->appendTextureLookup(code, samplers[0], "vec2(coord.g, 0.625)");
309 code->append(";\n");
310
311 code->appendf("\t\t%s.b = ", outputColor);
312 builder->appendTextureLookup(code, samplers[0], "vec2(coord.b, 0.875)");
313 code->append(";\n");
314
315 code->appendf("\t\t%s.rgb *= %s.a;\n", outputColor, outputColor);
316}
317
318GrGLProgramStage::StageKey GLColorTableEffect::GenKey(const GrCustomStage& s,
319 const GrGLCaps& caps) {
320 return 0;
321}
322
323///////////////////////////////////////////////////////////////////////////////
324
325ColorTableEffect::ColorTableEffect(GrTexture* texture)
326 : INHERITED(1)
327 , fTextureAccess(texture, "a") {
328}
329
330ColorTableEffect::~ColorTableEffect() {
331}
332
333const GrProgramStageFactory& ColorTableEffect::getFactory() const {
334 return GrTProgramStageFactory<ColorTableEffect>::getInstance();
335}
336
337bool ColorTableEffect::isEqual(const GrCustomStage& sBase) const {
338 return INHERITED::isEqual(sBase);
339}
340
341const GrTextureAccess& ColorTableEffect::textureAccess(int index) const {
342 GrAssert(0 == index);
343 return fTextureAccess;
344}
345
346///////////////////////////////////////////////////////////////////////////////
347
348GR_DEFINE_CUSTOM_STAGE_TEST(ColorTableEffect);
349
350GrCustomStage* ColorTableEffect::TestCreate(SkRandom* random,
351 GrContext* context,
352 GrTexture* textures[]) {
353 return SkNEW_ARGS(ColorTableEffect, (textures[GrCustomStageUnitTest::kAlphaTextureIdx]));
354}
355
356GrCustomStage* SkTable_ColorFilter::asNewCustomStage(GrContext* context) const {
357 SkBitmap bitmap;
358 this->asComponentTable(&bitmap);
359 // passing NULL because this custom effect does no tiling or filtering.
360 GrTexture* texture = GrLockCachedBitmapTexture(context, bitmap, NULL);
361 GrCustomStage* stage = SkNEW_ARGS(ColorTableEffect, (texture));
362
363 // Unlock immediately, this is not great, but we don't have a way of
364 // knowing when else to unlock it currently. TODO: Remove this when
365 // unref becomes the unlock replacement for all types of textures.
366 GrUnlockCachedBitmapTexture(texture);
367 return stage;
368}
369
370#endif // SK_SUPPORT_GPU
371
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000372///////////////////////////////////////////////////////////////////////////////
373
374#ifdef SK_CPU_BENDIAN
375#else
376 #define SK_A32_INDEX (3 - (SK_A32_SHIFT >> 3))
377 #define SK_R32_INDEX (3 - (SK_R32_SHIFT >> 3))
378 #define SK_G32_INDEX (3 - (SK_G32_SHIFT >> 3))
379 #define SK_B32_INDEX (3 - (SK_B32_SHIFT >> 3))
380#endif
381
382///////////////////////////////////////////////////////////////////////////////
383
384SkColorFilter* SkTableColorFilter::Create(const uint8_t table[256]) {
385 return SkNEW_ARGS(SkTable_ColorFilter, (table, table, table, table));
386}
387
388SkColorFilter* SkTableColorFilter::CreateARGB(const uint8_t tableA[256],
389 const uint8_t tableR[256],
390 const uint8_t tableG[256],
391 const uint8_t tableB[256]) {
392 return SkNEW_ARGS(SkTable_ColorFilter, (tableA, tableR, tableG, tableB));
393}
djsollen@google.coma2ca41e2012-03-23 19:00:34 +0000394
395SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkTableColorFilter)
396 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkTable_ColorFilter)
397SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END