blob: cbbf7e1fc79977b4ab9bf44c0988e258cad33cbf [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.coma469c282012-10-24 18:28:34 +000044 virtual GrEffect* asNewCustomStage(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.comb2ad1012012-10-17 15:00:32 +0000220#include "gl/GrGLProgramStage.h"
221#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"; }
232 virtual const GrProgramStageFactory& 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
237 typedef GLColorTableEffect GLProgramStage;
238
239private:
240 GR_DECLARE_CUSTOM_STAGE_TEST;
241
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.com374e7592012-10-23 17:30:45 +0000247class GLColorTableEffect : public GrGLLegacyProgramStage {
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000248public:
249 GLColorTableEffect(const GrProgramStageFactory& factory,
bsalomon@google.coma469c282012-10-24 18:28:34 +0000250 const GrEffect& stage);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000251
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
bsalomon@google.coma469c282012-10-24 18:28:34 +0000260 virtual void setData(const GrGLUniformManager&, const GrEffect&) SK_OVERRIDE {}
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000261
bsalomon@google.coma469c282012-10-24 18:28:34 +0000262 static StageKey GenKey(const GrEffect&, const GrGLCaps&);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000263
264private:
265
bsalomon@google.com374e7592012-10-23 17:30:45 +0000266 typedef GrGLLegacyProgramStage INHERITED;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000267};
268
269GLColorTableEffect::GLColorTableEffect(
bsalomon@google.coma469c282012-10-24 18:28:34 +0000270 const GrProgramStageFactory& factory, const GrEffect& stage)
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000271 : INHERITED(factory) {
272 }
273
274void GLColorTableEffect::emitFS(GrGLShaderBuilder* builder,
275 const char* outputColor,
276 const char* inputColor,
277 const TextureSamplerArray& samplers) {
278 static const float kColorScaleFactor = 255.0f / 256.0f;
279 static const float kColorOffsetFactor = 1.0f / 512.0f;
280 SkString* code = &builder->fFSCode;
281 if (NULL == inputColor) {
282 // the input color is solid white (all ones).
283 static const float kMaxValue = kColorScaleFactor + kColorOffsetFactor;
284 code->appendf("\t\tvec4 coord = vec4(%f, %f, %f, %f);\n",
285 kMaxValue, kMaxValue, kMaxValue, kMaxValue);
286
287 } else {
288 code->appendf("\t\tfloat nonZeroAlpha = max(%s.a, .0001);\n", inputColor);
289 code->appendf("\t\tvec4 coord = vec4(%s.rgb / nonZeroAlpha, nonZeroAlpha);\n", inputColor);
290 code->appendf("\t\tcoord = coord * %f + vec4(%f, %f, %f, %f);\n",
291 kColorScaleFactor,
292 kColorOffsetFactor, kColorOffsetFactor,
293 kColorOffsetFactor, kColorOffsetFactor);
294 }
295
296 code->appendf("\t\t%s.a = ", outputColor);
297 builder->appendTextureLookup(code, samplers[0], "vec2(coord.a, 0.125)");
298 code->append(";\n");
299
300 code->appendf("\t\t%s.r = ", outputColor);
301 builder->appendTextureLookup(code, samplers[0], "vec2(coord.r, 0.375)");
302 code->append(";\n");
303
304 code->appendf("\t\t%s.g = ", outputColor);
305 builder->appendTextureLookup(code, samplers[0], "vec2(coord.g, 0.625)");
306 code->append(";\n");
307
308 code->appendf("\t\t%s.b = ", outputColor);
309 builder->appendTextureLookup(code, samplers[0], "vec2(coord.b, 0.875)");
310 code->append(";\n");
311
312 code->appendf("\t\t%s.rgb *= %s.a;\n", outputColor, outputColor);
313}
314
bsalomon@google.coma469c282012-10-24 18:28:34 +0000315GrGLProgramStage::StageKey GLColorTableEffect::GenKey(const GrEffect& s,
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000316 const GrGLCaps& caps) {
317 return 0;
318}
319
320///////////////////////////////////////////////////////////////////////////////
321
322ColorTableEffect::ColorTableEffect(GrTexture* texture)
323 : INHERITED(1)
324 , fTextureAccess(texture, "a") {
325}
326
327ColorTableEffect::~ColorTableEffect() {
328}
329
330const GrProgramStageFactory& ColorTableEffect::getFactory() const {
331 return GrTProgramStageFactory<ColorTableEffect>::getInstance();
332}
333
bsalomon@google.coma469c282012-10-24 18:28:34 +0000334bool ColorTableEffect::isEqual(const GrEffect& sBase) const {
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000335 return INHERITED::isEqual(sBase);
336}
337
338const GrTextureAccess& ColorTableEffect::textureAccess(int index) const {
339 GrAssert(0 == index);
340 return fTextureAccess;
341}
342
343///////////////////////////////////////////////////////////////////////////////
344
345GR_DEFINE_CUSTOM_STAGE_TEST(ColorTableEffect);
346
bsalomon@google.coma469c282012-10-24 18:28:34 +0000347GrEffect* ColorTableEffect::TestCreate(SkRandom* random,
348 GrContext* context,
349 GrTexture* textures[]) {
bsalomon@google.com6f261be2012-10-24 19:07:10 +0000350 return SkNEW_ARGS(ColorTableEffect, (textures[GrEffectUnitTest::kAlphaTextureIdx]));
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000351}
352
bsalomon@google.coma469c282012-10-24 18:28:34 +0000353GrEffect* SkTable_ColorFilter::asNewCustomStage(GrContext* context) const {
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000354 SkBitmap bitmap;
355 this->asComponentTable(&bitmap);
356 // passing NULL because this custom effect does no tiling or filtering.
357 GrTexture* texture = GrLockCachedBitmapTexture(context, bitmap, NULL);
bsalomon@google.coma469c282012-10-24 18:28:34 +0000358 GrEffect* stage = SkNEW_ARGS(ColorTableEffect, (texture));
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000359
360 // Unlock immediately, this is not great, but we don't have a way of
361 // knowing when else to unlock it currently. TODO: Remove this when
362 // unref becomes the unlock replacement for all types of textures.
363 GrUnlockCachedBitmapTexture(texture);
364 return stage;
365}
366
367#endif // SK_SUPPORT_GPU
368
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000369///////////////////////////////////////////////////////////////////////////////
370
371#ifdef SK_CPU_BENDIAN
372#else
373 #define SK_A32_INDEX (3 - (SK_A32_SHIFT >> 3))
374 #define SK_R32_INDEX (3 - (SK_R32_SHIFT >> 3))
375 #define SK_G32_INDEX (3 - (SK_G32_SHIFT >> 3))
376 #define SK_B32_INDEX (3 - (SK_B32_SHIFT >> 3))
377#endif
378
379///////////////////////////////////////////////////////////////////////////////
380
381SkColorFilter* SkTableColorFilter::Create(const uint8_t table[256]) {
382 return SkNEW_ARGS(SkTable_ColorFilter, (table, table, table, table));
383}
384
385SkColorFilter* SkTableColorFilter::CreateARGB(const uint8_t tableA[256],
386 const uint8_t tableR[256],
387 const uint8_t tableG[256],
388 const uint8_t tableB[256]) {
389 return SkNEW_ARGS(SkTable_ColorFilter, (tableA, tableR, tableG, tableB));
390}
djsollen@google.coma2ca41e2012-03-23 19:00:34 +0000391
392SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkTableColorFilter)
393 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkTable_ColorFilter)
394SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END