blob: d6c3e5f03274b7e772086bcf05ed5ac349efe564 [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
mtklein72c9faa2015-01-09 10:06:39 -080043 bool asComponentTable(SkBitmap* table) const SK_OVERRIDE;
reed8a8d8412015-03-02 13:46:03 -080044 SkColorFilter* newComposed(const SkColorFilter* inner) const SK_OVERRIDE;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +000045
46#if SK_SUPPORT_GPU
mtklein72c9faa2015-01-09 10:06:39 -080047 GrFragmentProcessor* asFragmentProcessor(GrContext* context) const SK_OVERRIDE;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +000048#endif
mike@reedtribe.orgf23f5f72012-01-07 03:48:45 +000049
reed8a8d8412015-03-02 13:46:03 -080050 void filterSpan(const SkPMColor src[], int count, 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:
mtklein72c9faa2015-01-09 10:06:39 -080064 void flatten(SkWriteBuffer&) const SK_OVERRIDE;
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +000065
66private:
bsalomon@google.comb2ad1012012-10-17 15:00:32 +000067 mutable const SkBitmap* fBitmap; // lazily allocated
mike@reedtribe.orgf23f5f72012-01-07 03:48:45 +000068
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +000069 uint8_t fStorage[256 * 4];
70 unsigned fFlags;
71
reed9fa60da2014-08-21 07:59:51 -070072 friend class SkTableColorFilter;
73
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +000074 typedef SkColorFilter INHERITED;
75};
76
77static const uint8_t gIdentityTable[] = {
rmistry@google.comfbfcd562012-08-23 18:09:54 +000078 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
79 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
80 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
81 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
82 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
83 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
84 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
85 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
86 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
87 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
88 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
89 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
90 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
91 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
92 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
93 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
94 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
95 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
96 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
97 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
98 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
99 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
100 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7,
101 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
102 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
103 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
104 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
105 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
106 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
107 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
108 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000109 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
110};
111
reed8a8d8412015-03-02 13:46:03 -0800112void SkTable_ColorFilter::filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const {
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000113 const uint8_t* table = fStorage;
114 const uint8_t* tableA = gIdentityTable;
115 const uint8_t* tableR = gIdentityTable;
116 const uint8_t* tableG = gIdentityTable;
117 const uint8_t* tableB = gIdentityTable;
118 if (fFlags & kA_Flag) {
119 tableA = table; table += 256;
120 }
121 if (fFlags & kR_Flag) {
122 tableR = table; table += 256;
123 }
124 if (fFlags & kG_Flag) {
125 tableG = table; table += 256;
126 }
127 if (fFlags & kB_Flag) {
128 tableB = table;
129 }
130
131 const SkUnPreMultiply::Scale* scaleTable = SkUnPreMultiply::GetScaleTable();
132 for (int i = 0; i < count; ++i) {
133 SkPMColor c = src[i];
134 unsigned a, r, g, b;
135 if (0 == c) {
136 a = r = g = b = 0;
137 } else {
138 a = SkGetPackedA32(c);
139 r = SkGetPackedR32(c);
140 g = SkGetPackedG32(c);
141 b = SkGetPackedB32(c);
142
143 if (a < 255) {
144 SkUnPreMultiply::Scale scale = scaleTable[a];
145 r = SkUnPreMultiply::ApplyScale(scale, r);
146 g = SkUnPreMultiply::ApplyScale(scale, g);
147 b = SkUnPreMultiply::ApplyScale(scale, b);
148 }
149 }
150 dst[i] = SkPremultiplyARGBInline(tableA[a], tableR[r],
151 tableG[g], tableB[b]);
152 }
153}
154
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +0000155#ifndef SK_IGNORE_TO_STRING
robertphillips@google.com1202c2a2013-05-23 14:00:17 +0000156void SkTable_ColorFilter::toString(SkString* str) const {
robertphillipsf3f5bad2014-12-19 13:49:15 -0800157 const uint8_t* table = fStorage;
158 const uint8_t* tableA = gIdentityTable;
159 const uint8_t* tableR = gIdentityTable;
160 const uint8_t* tableG = gIdentityTable;
161 const uint8_t* tableB = gIdentityTable;
162 if (fFlags & kA_Flag) {
163 tableA = table; table += 256;
164 }
165 if (fFlags & kR_Flag) {
166 tableR = table; table += 256;
167 }
168 if (fFlags & kG_Flag) {
169 tableG = table; table += 256;
170 }
171 if (fFlags & kB_Flag) {
172 tableB = table;
173 }
174
175 str->append("SkTable_ColorFilter (");
176
177 for (int i = 0; i < 256; ++i) {
178 str->appendf("%d: %d,%d,%d,%d\n",
179 i, tableR[i], tableG[i], tableB[i], tableA[i]);
180 }
181
182 str->append(")");
robertphillips@google.com1202c2a2013-05-23 14:00:17 +0000183}
184#endif
185
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000186static const uint8_t gCountNibBits[] = {
187 0, 1, 1, 2,
188 1, 2, 2, 3,
189 1, 2, 2, 3,
190 2, 3, 3, 4
191};
192
193#include "SkPackBits.h"
194
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000195void SkTable_ColorFilter::flatten(SkWriteBuffer& buffer) const {
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000196 uint8_t storage[5*256];
197 int count = gCountNibBits[fFlags & 0xF];
198 size_t size = SkPackBits::Pack8(fStorage, count * 256, storage);
199 SkASSERT(size <= sizeof(storage));
200
reed9fa60da2014-08-21 07:59:51 -0700201 buffer.write32(fFlags);
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000202 buffer.writeByteArray(storage, size);
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000203}
204
reed9fa60da2014-08-21 07:59:51 -0700205SkFlattenable* SkTable_ColorFilter::CreateProc(SkReadBuffer& buffer) {
206 const int flags = buffer.read32();
207 const size_t count = gCountNibBits[flags & 0xF];
208 SkASSERT(count <= 4);
209
210 uint8_t packedStorage[5*256];
211 size_t packedSize = buffer.getArrayCount();
212 if (!buffer.validate(packedSize <= sizeof(packedStorage))) {
213 return NULL;
214 }
215 if (!buffer.readByteArray(packedStorage, packedSize)) {
216 return NULL;
217 }
218
219 uint8_t unpackedStorage[4*256];
220 size_t unpackedSize = SkPackBits::Unpack8(packedStorage, packedSize, unpackedStorage);
221 // now check that we got the size we expected
senorblanco91c395a2014-09-25 15:51:35 -0700222 if (!buffer.validate(unpackedSize == count*256)) {
reed9fa60da2014-08-21 07:59:51 -0700223 return NULL;
224 }
225
226 const uint8_t* a = NULL;
227 const uint8_t* r = NULL;
228 const uint8_t* g = NULL;
229 const uint8_t* b = NULL;
230 const uint8_t* ptr = unpackedStorage;
231
232 if (flags & kA_Flag) {
233 a = ptr;
234 ptr += 256;
235 }
236 if (flags & kR_Flag) {
237 r = ptr;
238 ptr += 256;
239 }
240 if (flags & kG_Flag) {
241 g = ptr;
242 ptr += 256;
243 }
244 if (flags & kB_Flag) {
245 b = ptr;
246 ptr += 256;
247 }
248 return SkTableColorFilter::CreateARGB(a, r, g, b);
249}
250
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
reed8a8d8412015-03-02 13:46:03 -0800276// Combines the two lookup tables so that making a lookup using res[] has
277// the same effect as making a lookup through inner[] then outer[].
278static void combine_tables(uint8_t res[256], const uint8_t outer[256], const uint8_t inner[256]) {
279 for (int i = 0; i < 256; i++) {
280 res[i] = outer[inner[i]];
281 }
282}
283
284SkColorFilter* SkTable_ColorFilter::newComposed(const SkColorFilter* innerFilter) const {
285 SkBitmap innerBM;
286 if (!innerFilter->asComponentTable(&innerBM)) {
287 return NULL;
288 }
289
290 innerBM.lockPixels();
291 if (NULL == innerBM.getPixels()) {
292 return NULL;
293 }
294
295 const uint8_t* table = fStorage;
296 const uint8_t* tableA = gIdentityTable;
297 const uint8_t* tableR = gIdentityTable;
298 const uint8_t* tableG = gIdentityTable;
299 const uint8_t* tableB = gIdentityTable;
300 if (fFlags & kA_Flag) {
301 tableA = table; table += 256;
302 }
303 if (fFlags & kR_Flag) {
304 tableR = table; table += 256;
305 }
306 if (fFlags & kG_Flag) {
307 tableG = table; table += 256;
308 }
309 if (fFlags & kB_Flag) {
310 tableB = table;
311 }
312
313 uint8_t concatA[256];
314 uint8_t concatR[256];
315 uint8_t concatG[256];
316 uint8_t concatB[256];
317
318 combine_tables(concatA, tableA, innerBM.getAddr8(0, 0));
319 combine_tables(concatR, tableR, innerBM.getAddr8(0, 1));
320 combine_tables(concatG, tableG, innerBM.getAddr8(0, 2));
321 combine_tables(concatB, tableB, innerBM.getAddr8(0, 3));
322
323 return SkTableColorFilter::CreateARGB(concatA, concatR, concatG, concatB);
324}
325
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000326#if SK_SUPPORT_GPU
327
bsalomon6251d172014-10-15 10:50:36 -0700328#include "GrFragmentProcessor.h"
egdaniel605dd0f2014-11-12 08:35:25 -0800329#include "GrInvariantOutput.h"
bsalomonc6327a82014-10-27 12:53:08 -0700330#include "SkGr.h"
331#include "effects/GrTextureStripAtlas.h"
joshualittb0a8a372014-09-23 09:50:21 -0700332#include "gl/GrGLProcessor.h"
joshualitt30ba4362014-08-21 20:18:45 -0700333#include "gl/builders/GrGLProgramBuilder.h"
bsalomonc6327a82014-10-27 12:53:08 -0700334
joshualittb0a8a372014-09-23 09:50:21 -0700335class ColorTableEffect : public GrFragmentProcessor {
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000336public:
bsalomonc6327a82014-10-27 12:53:08 -0700337 static GrFragmentProcessor* Create(GrContext* context, SkBitmap bitmap, unsigned flags);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000338
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000339 virtual ~ColorTableEffect();
340
mtklein72c9faa2015-01-09 10:06:39 -0800341 const char* name() const SK_OVERRIDE { return "ColorTable"; }
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000342
mtklein72c9faa2015-01-09 10:06:39 -0800343 void getGLProcessorKey(const GrGLCaps&, GrProcessorKeyBuilder*) const SK_OVERRIDE;
joshualitteb2a6762014-12-04 11:35:33 -0800344
mtklein72c9faa2015-01-09 10:06:39 -0800345 GrGLFragmentProcessor* createGLInstance() const SK_OVERRIDE;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000346
bsalomonc6327a82014-10-27 12:53:08 -0700347 const GrTextureStripAtlas* atlas() const { return fAtlas; }
348 int atlasRow() const { return fRow; }
349
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000350private:
mtklein72c9faa2015-01-09 10:06:39 -0800351 bool onIsEqual(const GrFragmentProcessor&) const SK_OVERRIDE;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000352
mtklein72c9faa2015-01-09 10:06:39 -0800353 void onComputeInvariantOutput(GrInvariantOutput* inout) const SK_OVERRIDE;
egdaniel1a8ecdf2014-10-03 06:24:12 -0700354
bsalomonc6327a82014-10-27 12:53:08 -0700355 ColorTableEffect(GrTexture* texture, GrTextureStripAtlas* atlas, int row, unsigned flags);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000356
joshualittb0a8a372014-09-23 09:50:21 -0700357 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000358
bsalomonc6327a82014-10-27 12:53:08 -0700359 GrTextureAccess fTextureAccess;
360
361 // currently not used in shader code, just to assist onComputeInvariantOutput().
mtklein3f3b3d02014-12-01 11:47:08 -0800362 unsigned fFlags;
bsalomonc6327a82014-10-27 12:53:08 -0700363
364 GrTextureStripAtlas* fAtlas;
365 int fRow;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000366
joshualittb0a8a372014-09-23 09:50:21 -0700367 typedef GrFragmentProcessor INHERITED;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000368};
369
joshualittb0a8a372014-09-23 09:50:21 -0700370class GLColorTableEffect : public GrGLFragmentProcessor {
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000371public:
joshualitteb2a6762014-12-04 11:35:33 -0800372 GLColorTableEffect(const GrProcessor&);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000373
joshualitt15988992014-10-09 15:04:05 -0700374 virtual void emitCode(GrGLFPBuilder*,
joshualittb0a8a372014-09-23 09:50:21 -0700375 const GrFragmentProcessor&,
bsalomon@google.com22a800a2012-10-26 19:16:46 +0000376 const char* outputColor,
377 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +0000378 const TransformedCoordsArray&,
bsalomon@google.com22a800a2012-10-26 19:16:46 +0000379 const TextureSamplerArray&) SK_OVERRIDE;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000380
mtklein72c9faa2015-01-09 10:06:39 -0800381 void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000382
joshualittb0a8a372014-09-23 09:50:21 -0700383 static void GenKey(const GrProcessor&, const GrGLCaps&, GrProcessorKeyBuilder* b) {}
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000384
385private:
bsalomonc6327a82014-10-27 12:53:08 -0700386 UniformHandle fRGBAYValuesUni;
joshualittb0a8a372014-09-23 09:50:21 -0700387 typedef GrGLFragmentProcessor INHERITED;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000388};
389
joshualitteb2a6762014-12-04 11:35:33 -0800390GLColorTableEffect::GLColorTableEffect(const GrProcessor&) {
391}
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000392
bsalomonc6327a82014-10-27 12:53:08 -0700393void GLColorTableEffect::setData(const GrGLProgramDataManager& pdm, const GrProcessor& proc) {
394 // The textures are organized in a strip where the rows are ordered a, r, g, b.
395 float rgbaYValues[4];
396 const ColorTableEffect& cte = proc.cast<ColorTableEffect>();
397 if (cte.atlas()) {
398 SkScalar yDelta = cte.atlas()->getNormalizedTexelHeight();
399 rgbaYValues[3] = cte.atlas()->getYOffset(cte.atlasRow()) + SK_ScalarHalf * yDelta;
400 rgbaYValues[0] = rgbaYValues[3] + yDelta;
401 rgbaYValues[1] = rgbaYValues[0] + yDelta;
402 rgbaYValues[2] = rgbaYValues[1] + yDelta;
403 } else {
404 rgbaYValues[3] = 0.125;
405 rgbaYValues[0] = 0.375;
406 rgbaYValues[1] = 0.625;
mtklein3f3b3d02014-12-01 11:47:08 -0800407 rgbaYValues[2] = 0.875;
bsalomonc6327a82014-10-27 12:53:08 -0700408 }
409 pdm.set4fv(fRGBAYValuesUni, 1, rgbaYValues);
410}
411
joshualitt15988992014-10-09 15:04:05 -0700412void GLColorTableEffect::emitCode(GrGLFPBuilder* builder,
joshualittb0a8a372014-09-23 09:50:21 -0700413 const GrFragmentProcessor&,
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000414 const char* outputColor,
415 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +0000416 const TransformedCoordsArray&,
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000417 const TextureSamplerArray& samplers) {
bsalomonc6327a82014-10-27 12:53:08 -0700418 const char* yoffsets;
419 fRGBAYValuesUni = builder->addUniform(GrGLFPBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -0800420 kVec4f_GrSLType, kDefault_GrSLPrecision,
421 "yoffsets", &yoffsets);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000422 static const float kColorScaleFactor = 255.0f / 256.0f;
423 static const float kColorOffsetFactor = 1.0f / 512.0f;
joshualitt15988992014-10-09 15:04:05 -0700424 GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000425 if (NULL == inputColor) {
426 // the input color is solid white (all ones).
427 static const float kMaxValue = kColorScaleFactor + kColorOffsetFactor;
joshualitt30ba4362014-08-21 20:18:45 -0700428 fsBuilder->codeAppendf("\t\tvec4 coord = vec4(%f, %f, %f, %f);\n",
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000429 kMaxValue, kMaxValue, kMaxValue, kMaxValue);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000430
431 } else {
joshualitt30ba4362014-08-21 20:18:45 -0700432 fsBuilder->codeAppendf("\t\tfloat nonZeroAlpha = max(%s.a, .0001);\n", inputColor);
433 fsBuilder->codeAppendf("\t\tvec4 coord = vec4(%s.rgb / nonZeroAlpha, nonZeroAlpha);\n", inputColor);
434 fsBuilder->codeAppendf("\t\tcoord = coord * %f + vec4(%f, %f, %f, %f);\n",
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000435 kColorScaleFactor,
436 kColorOffsetFactor, kColorOffsetFactor,
437 kColorOffsetFactor, kColorOffsetFactor);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000438 }
439
bsalomonc6327a82014-10-27 12:53:08 -0700440 SkString coord;
441
joshualitt30ba4362014-08-21 20:18:45 -0700442 fsBuilder->codeAppendf("\t\t%s.a = ", outputColor);
bsalomonc6327a82014-10-27 12:53:08 -0700443 coord.printf("vec2(coord.a, %s.a)", yoffsets);
444 fsBuilder->appendTextureLookup(samplers[0], coord.c_str());
joshualitt30ba4362014-08-21 20:18:45 -0700445 fsBuilder->codeAppend(";\n");
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000446
joshualitt30ba4362014-08-21 20:18:45 -0700447 fsBuilder->codeAppendf("\t\t%s.r = ", outputColor);
bsalomonc6327a82014-10-27 12:53:08 -0700448 coord.printf("vec2(coord.r, %s.r)", yoffsets);
449 fsBuilder->appendTextureLookup(samplers[0], coord.c_str());
joshualitt30ba4362014-08-21 20:18:45 -0700450 fsBuilder->codeAppend(";\n");
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000451
joshualitt30ba4362014-08-21 20:18:45 -0700452 fsBuilder->codeAppendf("\t\t%s.g = ", outputColor);
bsalomonc6327a82014-10-27 12:53:08 -0700453 coord.printf("vec2(coord.g, %s.g)", yoffsets);
454 fsBuilder->appendTextureLookup(samplers[0], coord.c_str());
joshualitt30ba4362014-08-21 20:18:45 -0700455 fsBuilder->codeAppend(";\n");
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000456
joshualitt30ba4362014-08-21 20:18:45 -0700457 fsBuilder->codeAppendf("\t\t%s.b = ", outputColor);
bsalomonc6327a82014-10-27 12:53:08 -0700458 coord.printf("vec2(coord.b, %s.b)", yoffsets);
459 fsBuilder->appendTextureLookup(samplers[0], coord.c_str());
joshualitt30ba4362014-08-21 20:18:45 -0700460 fsBuilder->codeAppend(";\n");
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000461
joshualitt30ba4362014-08-21 20:18:45 -0700462 fsBuilder->codeAppendf("\t\t%s.rgb *= %s.a;\n", outputColor, outputColor);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000463}
464
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000465///////////////////////////////////////////////////////////////////////////////
bsalomonc6327a82014-10-27 12:53:08 -0700466GrFragmentProcessor* ColorTableEffect::Create(GrContext* context, SkBitmap bitmap, unsigned flags) {
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000467
bsalomonc6327a82014-10-27 12:53:08 -0700468 GrTextureStripAtlas::Desc desc;
469 desc.fWidth = bitmap.width();
470 desc.fHeight = 128;
471 desc.fRowHeight = bitmap.height();
472 desc.fContext = context;
473 desc.fConfig = SkImageInfo2GrPixelConfig(bitmap.info());
474 GrTextureStripAtlas* atlas = GrTextureStripAtlas::GetAtlas(desc);
475 int row = atlas->lockRow(bitmap);
476 SkAutoTUnref<GrTexture> texture;
477 if (-1 == row) {
478 atlas = NULL;
479 // Passing params=NULL because this effect does no tiling or filtering.
480 texture.reset(GrRefCachedBitmapTexture(context, bitmap, NULL));
481 } else {
482 texture.reset(SkRef(atlas->getTexture()));
483 }
484
485 return SkNEW_ARGS(ColorTableEffect, (texture, atlas, row, flags));
486}
487
488ColorTableEffect::ColorTableEffect(GrTexture* texture, GrTextureStripAtlas* atlas, int row,
489 unsigned flags)
bsalomon@google.com371e1052013-01-11 21:08:55 +0000490 : fTextureAccess(texture, "a")
bsalomonc6327a82014-10-27 12:53:08 -0700491 , fFlags(flags)
492 , fAtlas(atlas)
493 , fRow(row) {
joshualitteb2a6762014-12-04 11:35:33 -0800494 this->initClassID<ColorTableEffect>();
bsalomon@google.com50db75c2013-01-11 13:54:30 +0000495 this->addTextureAccess(&fTextureAccess);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000496}
497
498ColorTableEffect::~ColorTableEffect() {
bsalomonc6327a82014-10-27 12:53:08 -0700499 if (fAtlas) {
500 fAtlas->unlockRow(fRow);
501 }
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000502}
503
joshualitteb2a6762014-12-04 11:35:33 -0800504void ColorTableEffect::getGLProcessorKey(const GrGLCaps& caps,
505 GrProcessorKeyBuilder* b) const {
506 GLColorTableEffect::GenKey(*this, caps, b);
507}
508
509GrGLFragmentProcessor* ColorTableEffect::createGLInstance() const {
510 return SkNEW_ARGS(GLColorTableEffect, (*this));
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000511}
512
bsalomonc6327a82014-10-27 12:53:08 -0700513bool ColorTableEffect::onIsEqual(const GrFragmentProcessor& other) const {
514 // For non-atlased instances, the texture (compared by base class) is sufficient to
515 // differentiate different tables. For atlased instances we ensure they are using the
516 // same row.
517 const ColorTableEffect& that = other.cast<ColorTableEffect>();
518 SkASSERT(SkToBool(fAtlas) == SkToBool(that.fAtlas));
519 // Ok to always do this comparison since both would be -1 if non-atlased.
520 return fRow == that.fRow;
521}
522
egdaniel605dd0f2014-11-12 08:35:25 -0800523void ColorTableEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
bsalomon@google.com371e1052013-01-11 21:08:55 +0000524 // If we kept the table in the effect then we could actually run known inputs through the
525 // table.
egdanielccb2e382014-10-13 12:53:46 -0700526 uint8_t invalidateFlags = 0;
bsalomon@google.com371e1052013-01-11 21:08:55 +0000527 if (fFlags & SkTable_ColorFilter::kR_Flag) {
egdanielccb2e382014-10-13 12:53:46 -0700528 invalidateFlags |= kR_GrColorComponentFlag;
bsalomon@google.com371e1052013-01-11 21:08:55 +0000529 }
530 if (fFlags & SkTable_ColorFilter::kG_Flag) {
egdanielccb2e382014-10-13 12:53:46 -0700531 invalidateFlags |= kG_GrColorComponentFlag;
bsalomon@google.com371e1052013-01-11 21:08:55 +0000532 }
533 if (fFlags & SkTable_ColorFilter::kB_Flag) {
egdanielccb2e382014-10-13 12:53:46 -0700534 invalidateFlags |= kB_GrColorComponentFlag;
bsalomon@google.com371e1052013-01-11 21:08:55 +0000535 }
536 if (fFlags & SkTable_ColorFilter::kA_Flag) {
egdanielccb2e382014-10-13 12:53:46 -0700537 invalidateFlags |= kA_GrColorComponentFlag;
bsalomon@google.com371e1052013-01-11 21:08:55 +0000538 }
egdaniel605dd0f2014-11-12 08:35:25 -0800539 inout->invalidateComponents(invalidateFlags, GrInvariantOutput::kWill_ReadInput);
bsalomon@google.com371e1052013-01-11 21:08:55 +0000540}
541
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000542///////////////////////////////////////////////////////////////////////////////
543
joshualittb0a8a372014-09-23 09:50:21 -0700544GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ColorTableEffect);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000545
joshualittb0a8a372014-09-23 09:50:21 -0700546GrFragmentProcessor* ColorTableEffect::TestCreate(SkRandom* random,
547 GrContext* context,
548 const GrDrawTargetCaps&,
549 GrTexture* textures[]) {
bsalomonc6327a82014-10-27 12:53:08 -0700550 int flags = 0;
551 uint8_t luts[256][4];
552 do {
553 for (int i = 0; i < 4; ++i) {
554 flags |= random->nextBool() ? (1 << i): 0;
555 }
556 } while (!flags);
557 for (int i = 0; i < 4; ++i) {
558 if (flags & (1 << i)) {
559 for (int j = 0; j < 256; ++j) {
560 luts[j][i] = SkToU8(random->nextBits(8));
561 }
562 }
563 }
564 SkAutoTUnref<SkColorFilter> filter(SkTableColorFilter::CreateARGB(
565 (flags & (1 << 0)) ? luts[0] : NULL,
566 (flags & (1 << 1)) ? luts[1] : NULL,
567 (flags & (1 << 2)) ? luts[2] : NULL,
568 (flags & (1 << 3)) ? luts[3] : NULL
569 ));
570 return filter->asFragmentProcessor(context);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000571}
572
joshualittb0a8a372014-09-23 09:50:21 -0700573GrFragmentProcessor* SkTable_ColorFilter::asFragmentProcessor(GrContext* context) const {
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000574 SkBitmap bitmap;
575 this->asComponentTable(&bitmap);
bsalomonc6327a82014-10-27 12:53:08 -0700576
577 return ColorTableEffect::Create(context, bitmap, fFlags);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000578}
579
580#endif // SK_SUPPORT_GPU
581
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000582///////////////////////////////////////////////////////////////////////////////
583
584#ifdef SK_CPU_BENDIAN
585#else
586 #define SK_A32_INDEX (3 - (SK_A32_SHIFT >> 3))
587 #define SK_R32_INDEX (3 - (SK_R32_SHIFT >> 3))
588 #define SK_G32_INDEX (3 - (SK_G32_SHIFT >> 3))
589 #define SK_B32_INDEX (3 - (SK_B32_SHIFT >> 3))
590#endif
591
592///////////////////////////////////////////////////////////////////////////////
593
594SkColorFilter* SkTableColorFilter::Create(const uint8_t table[256]) {
595 return SkNEW_ARGS(SkTable_ColorFilter, (table, table, table, table));
596}
597
598SkColorFilter* SkTableColorFilter::CreateARGB(const uint8_t tableA[256],
599 const uint8_t tableR[256],
600 const uint8_t tableG[256],
601 const uint8_t tableB[256]) {
602 return SkNEW_ARGS(SkTable_ColorFilter, (tableA, tableR, tableG, tableB));
603}
djsollen@google.coma2ca41e2012-03-23 19:00:34 +0000604
605SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkTableColorFilter)
606 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkTable_ColorFilter)
607SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END