blob: e4daf20b006e11d92a59a681bd15409b8365c0a3 [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"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00005#include "SkReadBuffer.h"
6#include "SkWriteBuffer.h"
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +00007#include "SkUnPreMultiply.h"
robertphillips@google.com1202c2a2013-05-23 14:00:17 +00008#include "SkString.h"
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +00009
10class SkTable_ColorFilter : public SkColorFilter {
11public:
12 SkTable_ColorFilter(const uint8_t tableA[], const uint8_t tableR[],
13 const uint8_t tableG[], const uint8_t tableB[]) {
mike@reedtribe.orgf23f5f72012-01-07 03:48:45 +000014 fBitmap = NULL;
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +000015 fFlags = 0;
mike@reedtribe.orgf23f5f72012-01-07 03:48:45 +000016
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +000017 uint8_t* dst = fStorage;
18 if (tableA) {
19 memcpy(dst, tableA, 256);
20 dst += 256;
21 fFlags |= kA_Flag;
22 }
23 if (tableR) {
24 memcpy(dst, tableR, 256);
25 dst += 256;
26 fFlags |= kR_Flag;
27 }
28 if (tableG) {
29 memcpy(dst, tableG, 256);
30 dst += 256;
31 fFlags |= kG_Flag;
32 }
33 if (tableB) {
34 memcpy(dst, tableB, 256);
35 fFlags |= kB_Flag;
36 }
37 }
38
tomhudson@google.com1bb4be22012-07-24 17:24:21 +000039 virtual ~SkTable_ColorFilter() {
40 SkDELETE(fBitmap);
41 }
42
bsalomon@google.comb2ad1012012-10-17 15:00:32 +000043 virtual bool asComponentTable(SkBitmap* table) const SK_OVERRIDE;
44
45#if SK_SUPPORT_GPU
joshualittb0a8a372014-09-23 09:50:21 -070046 virtual GrFragmentProcessor* asFragmentProcessor(GrContext* context) const SK_OVERRIDE;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +000047#endif
mike@reedtribe.orgf23f5f72012-01-07 03:48:45 +000048
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +000049 virtual void filterSpan(const SkPMColor src[], int count,
reed@google.combada6442012-12-17 20:21:44 +000050 SkPMColor dst[]) const SK_OVERRIDE;
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +000051
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +000052 SK_TO_STRING_OVERRIDE()
robertphillips@google.com1202c2a2013-05-23 14:00:17 +000053
djsollen@google.comba28d032012-03-26 17:57:35 +000054 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkTable_ColorFilter)
mike@reedtribe.orgf23f5f72012-01-07 03:48:45 +000055
bsalomon@google.com371e1052013-01-11 21:08:55 +000056 enum {
57 kA_Flag = 1 << 0,
58 kR_Flag = 1 << 1,
59 kG_Flag = 1 << 2,
60 kB_Flag = 1 << 3,
61 };
62
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +000063protected:
reed9fa60da2014-08-21 07:59:51 -070064#ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000065 SkTable_ColorFilter(SkReadBuffer& buffer);
reed9fa60da2014-08-21 07:59:51 -070066#endif
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000067 virtual void flatten(SkWriteBuffer&) const SK_OVERRIDE;
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +000068
69private:
bsalomon@google.comb2ad1012012-10-17 15:00:32 +000070 mutable const SkBitmap* fBitmap; // lazily allocated
mike@reedtribe.orgf23f5f72012-01-07 03:48:45 +000071
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +000072 uint8_t fStorage[256 * 4];
73 unsigned fFlags;
74
reed9fa60da2014-08-21 07:59:51 -070075 friend class SkTableColorFilter;
76
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +000077 typedef SkColorFilter INHERITED;
78};
79
80static const uint8_t gIdentityTable[] = {
rmistry@google.comfbfcd562012-08-23 18:09:54 +000081 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,
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000112 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
113};
114
115void SkTable_ColorFilter::filterSpan(const SkPMColor src[], int count,
reed@google.combada6442012-12-17 20:21:44 +0000116 SkPMColor dst[]) const {
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000117 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;
124 }
125 if (fFlags & kR_Flag) {
126 tableR = table; table += 256;
127 }
128 if (fFlags & kG_Flag) {
129 tableG = table; table += 256;
130 }
131 if (fFlags & kB_Flag) {
132 tableB = table;
133 }
134
135 const SkUnPreMultiply::Scale* scaleTable = SkUnPreMultiply::GetScaleTable();
136 for (int i = 0; i < count; ++i) {
137 SkPMColor c = src[i];
138 unsigned a, r, g, b;
139 if (0 == c) {
140 a = r = g = b = 0;
141 } else {
142 a = SkGetPackedA32(c);
143 r = SkGetPackedR32(c);
144 g = SkGetPackedG32(c);
145 b = SkGetPackedB32(c);
146
147 if (a < 255) {
148 SkUnPreMultiply::Scale scale = scaleTable[a];
149 r = SkUnPreMultiply::ApplyScale(scale, r);
150 g = SkUnPreMultiply::ApplyScale(scale, g);
151 b = SkUnPreMultiply::ApplyScale(scale, b);
152 }
153 }
154 dst[i] = SkPremultiplyARGBInline(tableA[a], tableR[r],
155 tableG[g], tableB[b]);
156 }
157}
158
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +0000159#ifndef SK_IGNORE_TO_STRING
robertphillips@google.com1202c2a2013-05-23 14:00:17 +0000160void SkTable_ColorFilter::toString(SkString* str) const {
161 str->append("SkTable_ColorFilter");
162}
163#endif
164
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000165static const uint8_t gCountNibBits[] = {
166 0, 1, 1, 2,
167 1, 2, 2, 3,
168 1, 2, 2, 3,
169 2, 3, 3, 4
170};
171
172#include "SkPackBits.h"
173
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000174void SkTable_ColorFilter::flatten(SkWriteBuffer& buffer) const {
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000175 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));
179
reed9fa60da2014-08-21 07:59:51 -0700180 buffer.write32(fFlags);
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000181 buffer.writeByteArray(storage, size);
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000182}
183
reed9fa60da2014-08-21 07:59:51 -0700184SkFlattenable* SkTable_ColorFilter::CreateProc(SkReadBuffer& buffer) {
185 const int flags = buffer.read32();
186 const size_t count = gCountNibBits[flags & 0xF];
187 SkASSERT(count <= 4);
188
189 uint8_t packedStorage[5*256];
190 size_t packedSize = buffer.getArrayCount();
191 if (!buffer.validate(packedSize <= sizeof(packedStorage))) {
192 return NULL;
193 }
194 if (!buffer.readByteArray(packedStorage, packedSize)) {
195 return NULL;
196 }
197
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
senorblanco91c395a2014-09-25 15:51:35 -0700201 if (!buffer.validate(unpackedSize == count*256)) {
reed9fa60da2014-08-21 07:59:51 -0700202 return NULL;
203 }
204
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;
210
211 if (flags & kA_Flag) {
212 a = ptr;
213 ptr += 256;
214 }
215 if (flags & kR_Flag) {
216 r = ptr;
217 ptr += 256;
218 }
219 if (flags & kG_Flag) {
220 g = ptr;
221 ptr += 256;
222 }
223 if (flags & kB_Flag) {
224 b = ptr;
225 ptr += 256;
226 }
227 return SkTableColorFilter::CreateARGB(a, r, g, b);
228}
229
230#ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000231SkTable_ColorFilter::SkTable_ColorFilter(SkReadBuffer& buffer) : INHERITED(buffer) {
mike@reedtribe.orgf23f5f72012-01-07 03:48:45 +0000232 fBitmap = NULL;
233
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000234 uint8_t storage[5*256];
235
236 fFlags = buffer.readInt();
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000237
238 size_t size = buffer.getArrayCount();
239 SkASSERT(size <= sizeof(storage));
commit-bot@chromium.orgef74fa12013-12-17 20:49:46 +0000240 buffer.validate(size <= sizeof(storage));
commit-bot@chromium.org02512882013-10-31 18:37:50 +0000241 buffer.readByteArray(storage, size);
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000242
humper@google.com0e515772013-01-07 19:54:40 +0000243 SkDEBUGCODE(size_t raw = ) SkPackBits::Unpack8(storage, size, fStorage);
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000244
245 SkASSERT(raw <= sizeof(fStorage));
humper@google.com0e515772013-01-07 19:54:40 +0000246 SkDEBUGCODE(size_t count = gCountNibBits[fFlags & 0xF]);
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000247 SkASSERT(raw == count * 256);
248}
reed9fa60da2014-08-21 07:59:51 -0700249#endif
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000250
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000251bool SkTable_ColorFilter::asComponentTable(SkBitmap* table) const {
mike@reedtribe.orgf23f5f72012-01-07 03:48:45 +0000252 if (table) {
253 if (NULL == fBitmap) {
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000254 SkBitmap* bmp = SkNEW(SkBitmap);
reed@google.com9ebcac52014-01-24 18:53:42 +0000255 bmp->allocPixels(SkImageInfo::MakeA8(256, 4));
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000256 uint8_t* bitmapPixels = bmp->getAddr8(0, 0);
twiz@google.com58071162012-07-18 21:41:50 +0000257 int offset = 0;
258 static const unsigned kFlags[] = { kA_Flag, kR_Flag, kG_Flag, kB_Flag };
259
260 for (int x = 0; x < 4; ++x) {
261 if (!(fFlags & kFlags[x])) {
262 memcpy(bitmapPixels, gIdentityTable, sizeof(gIdentityTable));
263 } else {
264 memcpy(bitmapPixels, fStorage + offset, 256);
265 offset += 256;
266 }
267 bitmapPixels += 256;
268 }
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000269 fBitmap = bmp;
mike@reedtribe.orgf23f5f72012-01-07 03:48:45 +0000270 }
271 *table = *fBitmap;
272 }
273 return true;
274}
275
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000276#if SK_SUPPORT_GPU
277
bsalomon6251d172014-10-15 10:50:36 -0700278#include "GrFragmentProcessor.h"
joshualittb0a8a372014-09-23 09:50:21 -0700279#include "GrTBackendProcessorFactory.h"
bsalomonc6327a82014-10-27 12:53:08 -0700280#include "SkGr.h"
281#include "effects/GrTextureStripAtlas.h"
joshualittb0a8a372014-09-23 09:50:21 -0700282#include "gl/GrGLProcessor.h"
joshualitt30ba4362014-08-21 20:18:45 -0700283#include "gl/builders/GrGLProgramBuilder.h"
bsalomonc6327a82014-10-27 12:53:08 -0700284
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000285
286class GLColorTableEffect;
287
joshualittb0a8a372014-09-23 09:50:21 -0700288class ColorTableEffect : public GrFragmentProcessor {
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000289public:
bsalomonc6327a82014-10-27 12:53:08 -0700290 static GrFragmentProcessor* Create(GrContext* context, SkBitmap bitmap, unsigned flags);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000291
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000292 virtual ~ColorTableEffect();
293
294 static const char* Name() { return "ColorTable"; }
joshualittb0a8a372014-09-23 09:50:21 -0700295 virtual const GrBackendFragmentProcessorFactory& getFactory() const SK_OVERRIDE;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000296
joshualittb0a8a372014-09-23 09:50:21 -0700297 typedef GLColorTableEffect GLProcessor;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000298
bsalomonc6327a82014-10-27 12:53:08 -0700299 const GrTextureStripAtlas* atlas() const { return fAtlas; }
300 int atlasRow() const { return fRow; }
301
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000302private:
bsalomonc6327a82014-10-27 12:53:08 -0700303 virtual bool onIsEqual(const GrFragmentProcessor&) const SK_OVERRIDE;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000304
egdaniel1a8ecdf2014-10-03 06:24:12 -0700305 virtual void onComputeInvariantOutput(InvariantOutput* inout) const SK_OVERRIDE;
306
bsalomonc6327a82014-10-27 12:53:08 -0700307 ColorTableEffect(GrTexture* texture, GrTextureStripAtlas* atlas, int row, unsigned flags);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000308
joshualittb0a8a372014-09-23 09:50:21 -0700309 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000310
bsalomonc6327a82014-10-27 12:53:08 -0700311 GrTextureAccess fTextureAccess;
312
313 // currently not used in shader code, just to assist onComputeInvariantOutput().
314 unsigned fFlags;
315
316 GrTextureStripAtlas* fAtlas;
317 int fRow;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000318
joshualittb0a8a372014-09-23 09:50:21 -0700319 typedef GrFragmentProcessor INHERITED;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000320};
321
joshualittb0a8a372014-09-23 09:50:21 -0700322class GLColorTableEffect : public GrGLFragmentProcessor {
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000323public:
joshualittb0a8a372014-09-23 09:50:21 -0700324 GLColorTableEffect(const GrBackendProcessorFactory&, const GrProcessor&);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000325
joshualitt15988992014-10-09 15:04:05 -0700326 virtual void emitCode(GrGLFPBuilder*,
joshualittb0a8a372014-09-23 09:50:21 -0700327 const GrFragmentProcessor&,
328 const GrProcessorKey&,
bsalomon@google.com22a800a2012-10-26 19:16:46 +0000329 const char* outputColor,
330 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +0000331 const TransformedCoordsArray&,
bsalomon@google.com22a800a2012-10-26 19:16:46 +0000332 const TextureSamplerArray&) SK_OVERRIDE;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000333
bsalomonc6327a82014-10-27 12:53:08 -0700334 virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000335
joshualittb0a8a372014-09-23 09:50:21 -0700336 static void GenKey(const GrProcessor&, const GrGLCaps&, GrProcessorKeyBuilder* b) {}
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000337
338private:
bsalomonc6327a82014-10-27 12:53:08 -0700339 UniformHandle fRGBAYValuesUni;
joshualittb0a8a372014-09-23 09:50:21 -0700340 typedef GrGLFragmentProcessor INHERITED;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000341};
342
joshualittb0a8a372014-09-23 09:50:21 -0700343GLColorTableEffect::GLColorTableEffect(const GrBackendProcessorFactory& factory, const GrProcessor&)
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000344 : INHERITED(factory) {
345 }
346
bsalomonc6327a82014-10-27 12:53:08 -0700347void GLColorTableEffect::setData(const GrGLProgramDataManager& pdm, const GrProcessor& proc) {
348 // The textures are organized in a strip where the rows are ordered a, r, g, b.
349 float rgbaYValues[4];
350 const ColorTableEffect& cte = proc.cast<ColorTableEffect>();
351 if (cte.atlas()) {
352 SkScalar yDelta = cte.atlas()->getNormalizedTexelHeight();
353 rgbaYValues[3] = cte.atlas()->getYOffset(cte.atlasRow()) + SK_ScalarHalf * yDelta;
354 rgbaYValues[0] = rgbaYValues[3] + yDelta;
355 rgbaYValues[1] = rgbaYValues[0] + yDelta;
356 rgbaYValues[2] = rgbaYValues[1] + yDelta;
357 } else {
358 rgbaYValues[3] = 0.125;
359 rgbaYValues[0] = 0.375;
360 rgbaYValues[1] = 0.625;
361 rgbaYValues[2] = 0.875;
362 }
363 pdm.set4fv(fRGBAYValuesUni, 1, rgbaYValues);
364}
365
joshualitt15988992014-10-09 15:04:05 -0700366void GLColorTableEffect::emitCode(GrGLFPBuilder* builder,
joshualittb0a8a372014-09-23 09:50:21 -0700367 const GrFragmentProcessor&,
368 const GrProcessorKey&,
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000369 const char* outputColor,
370 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +0000371 const TransformedCoordsArray&,
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000372 const TextureSamplerArray& samplers) {
bsalomonc6327a82014-10-27 12:53:08 -0700373 const char* yoffsets;
374 fRGBAYValuesUni = builder->addUniform(GrGLFPBuilder::kFragment_Visibility,
375 kVec4f_GrSLType, "yoffsets", &yoffsets);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000376 static const float kColorScaleFactor = 255.0f / 256.0f;
377 static const float kColorOffsetFactor = 1.0f / 512.0f;
joshualitt15988992014-10-09 15:04:05 -0700378 GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000379 if (NULL == inputColor) {
380 // the input color is solid white (all ones).
381 static const float kMaxValue = kColorScaleFactor + kColorOffsetFactor;
joshualitt30ba4362014-08-21 20:18:45 -0700382 fsBuilder->codeAppendf("\t\tvec4 coord = vec4(%f, %f, %f, %f);\n",
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000383 kMaxValue, kMaxValue, kMaxValue, kMaxValue);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000384
385 } else {
joshualitt30ba4362014-08-21 20:18:45 -0700386 fsBuilder->codeAppendf("\t\tfloat nonZeroAlpha = max(%s.a, .0001);\n", inputColor);
387 fsBuilder->codeAppendf("\t\tvec4 coord = vec4(%s.rgb / nonZeroAlpha, nonZeroAlpha);\n", inputColor);
388 fsBuilder->codeAppendf("\t\tcoord = coord * %f + vec4(%f, %f, %f, %f);\n",
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000389 kColorScaleFactor,
390 kColorOffsetFactor, kColorOffsetFactor,
391 kColorOffsetFactor, kColorOffsetFactor);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000392 }
393
bsalomonc6327a82014-10-27 12:53:08 -0700394 SkString coord;
395
joshualitt30ba4362014-08-21 20:18:45 -0700396 fsBuilder->codeAppendf("\t\t%s.a = ", outputColor);
bsalomonc6327a82014-10-27 12:53:08 -0700397 coord.printf("vec2(coord.a, %s.a)", yoffsets);
398 fsBuilder->appendTextureLookup(samplers[0], coord.c_str());
joshualitt30ba4362014-08-21 20:18:45 -0700399 fsBuilder->codeAppend(";\n");
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000400
joshualitt30ba4362014-08-21 20:18:45 -0700401 fsBuilder->codeAppendf("\t\t%s.r = ", outputColor);
bsalomonc6327a82014-10-27 12:53:08 -0700402 coord.printf("vec2(coord.r, %s.r)", yoffsets);
403 fsBuilder->appendTextureLookup(samplers[0], coord.c_str());
joshualitt30ba4362014-08-21 20:18:45 -0700404 fsBuilder->codeAppend(";\n");
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000405
joshualitt30ba4362014-08-21 20:18:45 -0700406 fsBuilder->codeAppendf("\t\t%s.g = ", outputColor);
bsalomonc6327a82014-10-27 12:53:08 -0700407 coord.printf("vec2(coord.g, %s.g)", yoffsets);
408 fsBuilder->appendTextureLookup(samplers[0], coord.c_str());
joshualitt30ba4362014-08-21 20:18:45 -0700409 fsBuilder->codeAppend(";\n");
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000410
joshualitt30ba4362014-08-21 20:18:45 -0700411 fsBuilder->codeAppendf("\t\t%s.b = ", outputColor);
bsalomonc6327a82014-10-27 12:53:08 -0700412 coord.printf("vec2(coord.b, %s.b)", yoffsets);
413 fsBuilder->appendTextureLookup(samplers[0], coord.c_str());
joshualitt30ba4362014-08-21 20:18:45 -0700414 fsBuilder->codeAppend(";\n");
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000415
joshualitt30ba4362014-08-21 20:18:45 -0700416 fsBuilder->codeAppendf("\t\t%s.rgb *= %s.a;\n", outputColor, outputColor);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000417}
418
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000419///////////////////////////////////////////////////////////////////////////////
bsalomonc6327a82014-10-27 12:53:08 -0700420GrFragmentProcessor* ColorTableEffect::Create(GrContext* context, SkBitmap bitmap, unsigned flags) {
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000421
bsalomonc6327a82014-10-27 12:53:08 -0700422 GrTextureStripAtlas::Desc desc;
423 desc.fWidth = bitmap.width();
424 desc.fHeight = 128;
425 desc.fRowHeight = bitmap.height();
426 desc.fContext = context;
427 desc.fConfig = SkImageInfo2GrPixelConfig(bitmap.info());
428 GrTextureStripAtlas* atlas = GrTextureStripAtlas::GetAtlas(desc);
429 int row = atlas->lockRow(bitmap);
430 SkAutoTUnref<GrTexture> texture;
431 if (-1 == row) {
432 atlas = NULL;
433 // Passing params=NULL because this effect does no tiling or filtering.
434 texture.reset(GrRefCachedBitmapTexture(context, bitmap, NULL));
435 } else {
436 texture.reset(SkRef(atlas->getTexture()));
437 }
438
439 return SkNEW_ARGS(ColorTableEffect, (texture, atlas, row, flags));
440}
441
442ColorTableEffect::ColorTableEffect(GrTexture* texture, GrTextureStripAtlas* atlas, int row,
443 unsigned flags)
bsalomon@google.com371e1052013-01-11 21:08:55 +0000444 : fTextureAccess(texture, "a")
bsalomonc6327a82014-10-27 12:53:08 -0700445 , fFlags(flags)
446 , fAtlas(atlas)
447 , fRow(row) {
448
bsalomon@google.com50db75c2013-01-11 13:54:30 +0000449 this->addTextureAccess(&fTextureAccess);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000450}
451
452ColorTableEffect::~ColorTableEffect() {
bsalomonc6327a82014-10-27 12:53:08 -0700453 if (fAtlas) {
454 fAtlas->unlockRow(fRow);
455 }
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000456}
457
joshualittb0a8a372014-09-23 09:50:21 -0700458const GrBackendFragmentProcessorFactory& ColorTableEffect::getFactory() const {
459 return GrTBackendFragmentProcessorFactory<ColorTableEffect>::getInstance();
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000460}
461
bsalomonc6327a82014-10-27 12:53:08 -0700462bool ColorTableEffect::onIsEqual(const GrFragmentProcessor& other) const {
463 // For non-atlased instances, the texture (compared by base class) is sufficient to
464 // differentiate different tables. For atlased instances we ensure they are using the
465 // same row.
466 const ColorTableEffect& that = other.cast<ColorTableEffect>();
467 SkASSERT(SkToBool(fAtlas) == SkToBool(that.fAtlas));
468 // Ok to always do this comparison since both would be -1 if non-atlased.
469 return fRow == that.fRow;
470}
471
egdaniel1a8ecdf2014-10-03 06:24:12 -0700472void ColorTableEffect::onComputeInvariantOutput(InvariantOutput* inout) const {
bsalomon@google.com371e1052013-01-11 21:08:55 +0000473 // If we kept the table in the effect then we could actually run known inputs through the
474 // table.
egdanielccb2e382014-10-13 12:53:46 -0700475 uint8_t invalidateFlags = 0;
bsalomon@google.com371e1052013-01-11 21:08:55 +0000476 if (fFlags & SkTable_ColorFilter::kR_Flag) {
egdanielccb2e382014-10-13 12:53:46 -0700477 invalidateFlags |= kR_GrColorComponentFlag;
bsalomon@google.com371e1052013-01-11 21:08:55 +0000478 }
479 if (fFlags & SkTable_ColorFilter::kG_Flag) {
egdanielccb2e382014-10-13 12:53:46 -0700480 invalidateFlags |= kG_GrColorComponentFlag;
bsalomon@google.com371e1052013-01-11 21:08:55 +0000481 }
482 if (fFlags & SkTable_ColorFilter::kB_Flag) {
egdanielccb2e382014-10-13 12:53:46 -0700483 invalidateFlags |= kB_GrColorComponentFlag;
bsalomon@google.com371e1052013-01-11 21:08:55 +0000484 }
485 if (fFlags & SkTable_ColorFilter::kA_Flag) {
egdanielccb2e382014-10-13 12:53:46 -0700486 invalidateFlags |= kA_GrColorComponentFlag;
bsalomon@google.com371e1052013-01-11 21:08:55 +0000487 }
egdaniel9e4d6d12014-10-15 13:49:02 -0700488 inout->invalidateComponents(invalidateFlags, InvariantOutput::kWill_ReadInput);
bsalomon@google.com371e1052013-01-11 21:08:55 +0000489}
490
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000491///////////////////////////////////////////////////////////////////////////////
492
joshualittb0a8a372014-09-23 09:50:21 -0700493GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ColorTableEffect);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000494
joshualittb0a8a372014-09-23 09:50:21 -0700495GrFragmentProcessor* ColorTableEffect::TestCreate(SkRandom* random,
496 GrContext* context,
497 const GrDrawTargetCaps&,
498 GrTexture* textures[]) {
bsalomonc6327a82014-10-27 12:53:08 -0700499 int flags = 0;
500 uint8_t luts[256][4];
501 do {
502 for (int i = 0; i < 4; ++i) {
503 flags |= random->nextBool() ? (1 << i): 0;
504 }
505 } while (!flags);
506 for (int i = 0; i < 4; ++i) {
507 if (flags & (1 << i)) {
508 for (int j = 0; j < 256; ++j) {
509 luts[j][i] = SkToU8(random->nextBits(8));
510 }
511 }
512 }
513 SkAutoTUnref<SkColorFilter> filter(SkTableColorFilter::CreateARGB(
514 (flags & (1 << 0)) ? luts[0] : NULL,
515 (flags & (1 << 1)) ? luts[1] : NULL,
516 (flags & (1 << 2)) ? luts[2] : NULL,
517 (flags & (1 << 3)) ? luts[3] : NULL
518 ));
519 return filter->asFragmentProcessor(context);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000520}
521
joshualittb0a8a372014-09-23 09:50:21 -0700522GrFragmentProcessor* SkTable_ColorFilter::asFragmentProcessor(GrContext* context) const {
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000523 SkBitmap bitmap;
524 this->asComponentTable(&bitmap);
bsalomonc6327a82014-10-27 12:53:08 -0700525
526 return ColorTableEffect::Create(context, bitmap, fFlags);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000527}
528
529#endif // SK_SUPPORT_GPU
530
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000531///////////////////////////////////////////////////////////////////////////////
532
533#ifdef SK_CPU_BENDIAN
534#else
535 #define SK_A32_INDEX (3 - (SK_A32_SHIFT >> 3))
536 #define SK_R32_INDEX (3 - (SK_R32_SHIFT >> 3))
537 #define SK_G32_INDEX (3 - (SK_G32_SHIFT >> 3))
538 #define SK_B32_INDEX (3 - (SK_B32_SHIFT >> 3))
539#endif
540
541///////////////////////////////////////////////////////////////////////////////
542
543SkColorFilter* SkTableColorFilter::Create(const uint8_t table[256]) {
544 return SkNEW_ARGS(SkTable_ColorFilter, (table, table, table, table));
545}
546
547SkColorFilter* SkTableColorFilter::CreateARGB(const uint8_t tableA[256],
548 const uint8_t tableR[256],
549 const uint8_t tableG[256],
550 const uint8_t tableB[256]) {
551 return SkNEW_ARGS(SkTable_ColorFilter, (tableA, tableR, tableG, tableB));
552}
djsollen@google.coma2ca41e2012-03-23 19:00:34 +0000553
554SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkTableColorFilter)
555 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkTable_ColorFilter)
556SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END