blob: 27a5def5e527d8057c9f82f927bb8537625f0719 [file] [log] [blame]
jvanverthcfc18862015-04-28 08:48:20 -07001/*
2* Copyright 2015 Google Inc.
3*
4* Use of this source code is governed by a BSD-style license that can be
5* found in the LICENSE file.
6*/
djsollen@google.comc73dd5c2012-08-07 15:54:32 +00007
reed@google.com02f65f22012-08-06 21:20:05 +00008#include "SkBitmap.h"
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +00009#include "SkTableColorFilter.h"
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000010#include "SkColorPriv.h"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000011#include "SkReadBuffer.h"
12#include "SkWriteBuffer.h"
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +000013#include "SkUnPreMultiply.h"
robertphillips@google.com1202c2a2013-05-23 14:00:17 +000014#include "SkString.h"
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +000015
16class SkTable_ColorFilter : public SkColorFilter {
17public:
18 SkTable_ColorFilter(const uint8_t tableA[], const uint8_t tableR[],
19 const uint8_t tableG[], const uint8_t tableB[]) {
mike@reedtribe.orgf23f5f72012-01-07 03:48:45 +000020 fBitmap = NULL;
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +000021 fFlags = 0;
mike@reedtribe.orgf23f5f72012-01-07 03:48:45 +000022
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +000023 uint8_t* dst = fStorage;
24 if (tableA) {
25 memcpy(dst, tableA, 256);
26 dst += 256;
27 fFlags |= kA_Flag;
28 }
29 if (tableR) {
30 memcpy(dst, tableR, 256);
31 dst += 256;
32 fFlags |= kR_Flag;
33 }
34 if (tableG) {
35 memcpy(dst, tableG, 256);
36 dst += 256;
37 fFlags |= kG_Flag;
38 }
39 if (tableB) {
40 memcpy(dst, tableB, 256);
41 fFlags |= kB_Flag;
42 }
43 }
44
tomhudson@google.com1bb4be22012-07-24 17:24:21 +000045 virtual ~SkTable_ColorFilter() {
46 SkDELETE(fBitmap);
47 }
48
mtklein36352bf2015-03-25 18:17:31 -070049 bool asComponentTable(SkBitmap* table) const override;
50 SkColorFilter* newComposed(const SkColorFilter* inner) const override;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +000051
52#if SK_SUPPORT_GPU
mtklein36352bf2015-03-25 18:17:31 -070053 bool asFragmentProcessors(GrContext*, SkTDArray<GrFragmentProcessor*>*) const override;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +000054#endif
mike@reedtribe.orgf23f5f72012-01-07 03:48:45 +000055
mtklein36352bf2015-03-25 18:17:31 -070056 void filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const override;
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +000057
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +000058 SK_TO_STRING_OVERRIDE()
robertphillips@google.com1202c2a2013-05-23 14:00:17 +000059
djsollen@google.comba28d032012-03-26 17:57:35 +000060 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkTable_ColorFilter)
mike@reedtribe.orgf23f5f72012-01-07 03:48:45 +000061
bsalomon@google.com371e1052013-01-11 21:08:55 +000062 enum {
63 kA_Flag = 1 << 0,
64 kR_Flag = 1 << 1,
65 kG_Flag = 1 << 2,
66 kB_Flag = 1 << 3,
67 };
68
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +000069protected:
mtklein36352bf2015-03-25 18:17:31 -070070 void flatten(SkWriteBuffer&) const override;
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +000071
72private:
bsalomon@google.comb2ad1012012-10-17 15:00:32 +000073 mutable const SkBitmap* fBitmap; // lazily allocated
mike@reedtribe.orgf23f5f72012-01-07 03:48:45 +000074
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +000075 uint8_t fStorage[256 * 4];
76 unsigned fFlags;
77
reed9fa60da2014-08-21 07:59:51 -070078 friend class SkTableColorFilter;
79
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +000080 typedef SkColorFilter INHERITED;
81};
82
83static const uint8_t gIdentityTable[] = {
rmistry@google.comfbfcd562012-08-23 18:09:54 +000084 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
85 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
86 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
87 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
88 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
89 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
90 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
91 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
92 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
93 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
94 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
95 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
96 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
97 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
98 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
99 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
100 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
101 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
102 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
103 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
104 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
105 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
106 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7,
107 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
108 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
109 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
110 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
111 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
112 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
113 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
114 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000115 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
116};
117
reed8a8d8412015-03-02 13:46:03 -0800118void SkTable_ColorFilter::filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const {
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000119 const uint8_t* table = fStorage;
120 const uint8_t* tableA = gIdentityTable;
121 const uint8_t* tableR = gIdentityTable;
122 const uint8_t* tableG = gIdentityTable;
123 const uint8_t* tableB = gIdentityTable;
124 if (fFlags & kA_Flag) {
125 tableA = table; table += 256;
126 }
127 if (fFlags & kR_Flag) {
128 tableR = table; table += 256;
129 }
130 if (fFlags & kG_Flag) {
131 tableG = table; table += 256;
132 }
133 if (fFlags & kB_Flag) {
134 tableB = table;
135 }
136
137 const SkUnPreMultiply::Scale* scaleTable = SkUnPreMultiply::GetScaleTable();
138 for (int i = 0; i < count; ++i) {
139 SkPMColor c = src[i];
140 unsigned a, r, g, b;
141 if (0 == c) {
142 a = r = g = b = 0;
143 } else {
144 a = SkGetPackedA32(c);
145 r = SkGetPackedR32(c);
146 g = SkGetPackedG32(c);
147 b = SkGetPackedB32(c);
148
149 if (a < 255) {
150 SkUnPreMultiply::Scale scale = scaleTable[a];
151 r = SkUnPreMultiply::ApplyScale(scale, r);
152 g = SkUnPreMultiply::ApplyScale(scale, g);
153 b = SkUnPreMultiply::ApplyScale(scale, b);
154 }
155 }
156 dst[i] = SkPremultiplyARGBInline(tableA[a], tableR[r],
157 tableG[g], tableB[b]);
158 }
159}
160
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +0000161#ifndef SK_IGNORE_TO_STRING
robertphillips@google.com1202c2a2013-05-23 14:00:17 +0000162void SkTable_ColorFilter::toString(SkString* str) const {
robertphillipsf3f5bad2014-12-19 13:49:15 -0800163 const uint8_t* table = fStorage;
164 const uint8_t* tableA = gIdentityTable;
165 const uint8_t* tableR = gIdentityTable;
166 const uint8_t* tableG = gIdentityTable;
167 const uint8_t* tableB = gIdentityTable;
168 if (fFlags & kA_Flag) {
169 tableA = table; table += 256;
170 }
171 if (fFlags & kR_Flag) {
172 tableR = table; table += 256;
173 }
174 if (fFlags & kG_Flag) {
175 tableG = table; table += 256;
176 }
177 if (fFlags & kB_Flag) {
178 tableB = table;
179 }
180
181 str->append("SkTable_ColorFilter (");
182
183 for (int i = 0; i < 256; ++i) {
184 str->appendf("%d: %d,%d,%d,%d\n",
185 i, tableR[i], tableG[i], tableB[i], tableA[i]);
186 }
187
188 str->append(")");
robertphillips@google.com1202c2a2013-05-23 14:00:17 +0000189}
190#endif
191
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000192static const uint8_t gCountNibBits[] = {
193 0, 1, 1, 2,
194 1, 2, 2, 3,
195 1, 2, 2, 3,
196 2, 3, 3, 4
197};
198
199#include "SkPackBits.h"
200
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000201void SkTable_ColorFilter::flatten(SkWriteBuffer& buffer) const {
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000202 uint8_t storage[5*256];
203 int count = gCountNibBits[fFlags & 0xF];
jschuh699b8522015-06-04 15:10:37 -0700204 size_t size = SkPackBits::Pack8(fStorage, count * 256, storage,
205 sizeof(storage));
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000206
reed9fa60da2014-08-21 07:59:51 -0700207 buffer.write32(fFlags);
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000208 buffer.writeByteArray(storage, size);
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000209}
210
reed9fa60da2014-08-21 07:59:51 -0700211SkFlattenable* SkTable_ColorFilter::CreateProc(SkReadBuffer& buffer) {
212 const int flags = buffer.read32();
213 const size_t count = gCountNibBits[flags & 0xF];
214 SkASSERT(count <= 4);
215
216 uint8_t packedStorage[5*256];
217 size_t packedSize = buffer.getArrayCount();
218 if (!buffer.validate(packedSize <= sizeof(packedStorage))) {
219 return NULL;
220 }
221 if (!buffer.readByteArray(packedStorage, packedSize)) {
222 return NULL;
223 }
224
225 uint8_t unpackedStorage[4*256];
jschuh699b8522015-06-04 15:10:37 -0700226 size_t unpackedSize = SkPackBits::Unpack8(packedStorage, packedSize,
227 unpackedStorage, sizeof(unpackedStorage));
reed9fa60da2014-08-21 07:59:51 -0700228 // now check that we got the size we expected
senorblanco91c395a2014-09-25 15:51:35 -0700229 if (!buffer.validate(unpackedSize == count*256)) {
reed9fa60da2014-08-21 07:59:51 -0700230 return NULL;
231 }
232
233 const uint8_t* a = NULL;
234 const uint8_t* r = NULL;
235 const uint8_t* g = NULL;
236 const uint8_t* b = NULL;
237 const uint8_t* ptr = unpackedStorage;
238
239 if (flags & kA_Flag) {
240 a = ptr;
241 ptr += 256;
242 }
243 if (flags & kR_Flag) {
244 r = ptr;
245 ptr += 256;
246 }
247 if (flags & kG_Flag) {
248 g = ptr;
249 ptr += 256;
250 }
251 if (flags & kB_Flag) {
252 b = ptr;
253 ptr += 256;
254 }
255 return SkTableColorFilter::CreateARGB(a, r, g, b);
256}
257
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000258bool SkTable_ColorFilter::asComponentTable(SkBitmap* table) const {
mike@reedtribe.orgf23f5f72012-01-07 03:48:45 +0000259 if (table) {
260 if (NULL == fBitmap) {
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000261 SkBitmap* bmp = SkNEW(SkBitmap);
reed@google.com9ebcac52014-01-24 18:53:42 +0000262 bmp->allocPixels(SkImageInfo::MakeA8(256, 4));
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000263 uint8_t* bitmapPixels = bmp->getAddr8(0, 0);
twiz@google.com58071162012-07-18 21:41:50 +0000264 int offset = 0;
265 static const unsigned kFlags[] = { kA_Flag, kR_Flag, kG_Flag, kB_Flag };
266
267 for (int x = 0; x < 4; ++x) {
268 if (!(fFlags & kFlags[x])) {
269 memcpy(bitmapPixels, gIdentityTable, sizeof(gIdentityTable));
270 } else {
271 memcpy(bitmapPixels, fStorage + offset, 256);
272 offset += 256;
273 }
274 bitmapPixels += 256;
275 }
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000276 fBitmap = bmp;
mike@reedtribe.orgf23f5f72012-01-07 03:48:45 +0000277 }
278 *table = *fBitmap;
279 }
280 return true;
281}
282
reed8a8d8412015-03-02 13:46:03 -0800283// Combines the two lookup tables so that making a lookup using res[] has
284// the same effect as making a lookup through inner[] then outer[].
285static void combine_tables(uint8_t res[256], const uint8_t outer[256], const uint8_t inner[256]) {
286 for (int i = 0; i < 256; i++) {
287 res[i] = outer[inner[i]];
288 }
289}
290
291SkColorFilter* SkTable_ColorFilter::newComposed(const SkColorFilter* innerFilter) const {
292 SkBitmap innerBM;
293 if (!innerFilter->asComponentTable(&innerBM)) {
294 return NULL;
295 }
296
297 innerBM.lockPixels();
298 if (NULL == innerBM.getPixels()) {
299 return NULL;
300 }
301
302 const uint8_t* table = fStorage;
303 const uint8_t* tableA = gIdentityTable;
304 const uint8_t* tableR = gIdentityTable;
305 const uint8_t* tableG = gIdentityTable;
306 const uint8_t* tableB = gIdentityTable;
307 if (fFlags & kA_Flag) {
308 tableA = table; table += 256;
309 }
310 if (fFlags & kR_Flag) {
311 tableR = table; table += 256;
312 }
313 if (fFlags & kG_Flag) {
314 tableG = table; table += 256;
315 }
316 if (fFlags & kB_Flag) {
317 tableB = table;
318 }
319
320 uint8_t concatA[256];
321 uint8_t concatR[256];
322 uint8_t concatG[256];
323 uint8_t concatB[256];
324
325 combine_tables(concatA, tableA, innerBM.getAddr8(0, 0));
326 combine_tables(concatR, tableR, innerBM.getAddr8(0, 1));
327 combine_tables(concatG, tableG, innerBM.getAddr8(0, 2));
328 combine_tables(concatB, tableB, innerBM.getAddr8(0, 3));
329
330 return SkTableColorFilter::CreateARGB(concatA, concatR, concatG, concatB);
331}
332
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000333#if SK_SUPPORT_GPU
334
bsalomon6251d172014-10-15 10:50:36 -0700335#include "GrFragmentProcessor.h"
egdaniel605dd0f2014-11-12 08:35:25 -0800336#include "GrInvariantOutput.h"
bsalomonc6327a82014-10-27 12:53:08 -0700337#include "SkGr.h"
338#include "effects/GrTextureStripAtlas.h"
joshualittb0a8a372014-09-23 09:50:21 -0700339#include "gl/GrGLProcessor.h"
joshualitt30ba4362014-08-21 20:18:45 -0700340#include "gl/builders/GrGLProgramBuilder.h"
bsalomonc6327a82014-10-27 12:53:08 -0700341
joshualittb0a8a372014-09-23 09:50:21 -0700342class ColorTableEffect : public GrFragmentProcessor {
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000343public:
bsalomonc6327a82014-10-27 12:53:08 -0700344 static GrFragmentProcessor* Create(GrContext* context, SkBitmap bitmap, unsigned flags);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000345
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000346 virtual ~ColorTableEffect();
347
mtklein36352bf2015-03-25 18:17:31 -0700348 const char* name() const override { return "ColorTable"; }
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000349
jvanverthcfc18862015-04-28 08:48:20 -0700350 void getGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
joshualitteb2a6762014-12-04 11:35:33 -0800351
mtklein36352bf2015-03-25 18:17:31 -0700352 GrGLFragmentProcessor* createGLInstance() const override;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000353
bsalomonc6327a82014-10-27 12:53:08 -0700354 const GrTextureStripAtlas* atlas() const { return fAtlas; }
355 int atlasRow() const { return fRow; }
356
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000357private:
mtklein36352bf2015-03-25 18:17:31 -0700358 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000359
mtklein36352bf2015-03-25 18:17:31 -0700360 void onComputeInvariantOutput(GrInvariantOutput* inout) const override;
egdaniel1a8ecdf2014-10-03 06:24:12 -0700361
bsalomonc6327a82014-10-27 12:53:08 -0700362 ColorTableEffect(GrTexture* texture, GrTextureStripAtlas* atlas, int row, unsigned flags);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000363
joshualittb0a8a372014-09-23 09:50:21 -0700364 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000365
bsalomonc6327a82014-10-27 12:53:08 -0700366 GrTextureAccess fTextureAccess;
367
368 // currently not used in shader code, just to assist onComputeInvariantOutput().
mtklein3f3b3d02014-12-01 11:47:08 -0800369 unsigned fFlags;
bsalomonc6327a82014-10-27 12:53:08 -0700370
371 GrTextureStripAtlas* fAtlas;
372 int fRow;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000373
joshualittb0a8a372014-09-23 09:50:21 -0700374 typedef GrFragmentProcessor INHERITED;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000375};
376
joshualittb0a8a372014-09-23 09:50:21 -0700377class GLColorTableEffect : public GrGLFragmentProcessor {
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000378public:
joshualitteb2a6762014-12-04 11:35:33 -0800379 GLColorTableEffect(const GrProcessor&);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000380
joshualitt15988992014-10-09 15:04:05 -0700381 virtual void emitCode(GrGLFPBuilder*,
joshualittb0a8a372014-09-23 09:50:21 -0700382 const GrFragmentProcessor&,
bsalomon@google.com22a800a2012-10-26 19:16:46 +0000383 const char* outputColor,
384 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +0000385 const TransformedCoordsArray&,
mtklein36352bf2015-03-25 18:17:31 -0700386 const TextureSamplerArray&) override;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000387
mtklein36352bf2015-03-25 18:17:31 -0700388 void setData(const GrGLProgramDataManager&, const GrProcessor&) override;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000389
jvanverthcfc18862015-04-28 08:48:20 -0700390 static void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder* b) {}
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000391
392private:
bsalomonc6327a82014-10-27 12:53:08 -0700393 UniformHandle fRGBAYValuesUni;
joshualittb0a8a372014-09-23 09:50:21 -0700394 typedef GrGLFragmentProcessor INHERITED;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000395};
396
joshualitteb2a6762014-12-04 11:35:33 -0800397GLColorTableEffect::GLColorTableEffect(const GrProcessor&) {
398}
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000399
bsalomonc6327a82014-10-27 12:53:08 -0700400void GLColorTableEffect::setData(const GrGLProgramDataManager& pdm, const GrProcessor& proc) {
401 // The textures are organized in a strip where the rows are ordered a, r, g, b.
402 float rgbaYValues[4];
403 const ColorTableEffect& cte = proc.cast<ColorTableEffect>();
404 if (cte.atlas()) {
405 SkScalar yDelta = cte.atlas()->getNormalizedTexelHeight();
406 rgbaYValues[3] = cte.atlas()->getYOffset(cte.atlasRow()) + SK_ScalarHalf * yDelta;
407 rgbaYValues[0] = rgbaYValues[3] + yDelta;
408 rgbaYValues[1] = rgbaYValues[0] + yDelta;
409 rgbaYValues[2] = rgbaYValues[1] + yDelta;
410 } else {
411 rgbaYValues[3] = 0.125;
412 rgbaYValues[0] = 0.375;
413 rgbaYValues[1] = 0.625;
mtklein3f3b3d02014-12-01 11:47:08 -0800414 rgbaYValues[2] = 0.875;
bsalomonc6327a82014-10-27 12:53:08 -0700415 }
416 pdm.set4fv(fRGBAYValuesUni, 1, rgbaYValues);
417}
418
joshualitt15988992014-10-09 15:04:05 -0700419void GLColorTableEffect::emitCode(GrGLFPBuilder* builder,
joshualittb0a8a372014-09-23 09:50:21 -0700420 const GrFragmentProcessor&,
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000421 const char* outputColor,
422 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +0000423 const TransformedCoordsArray&,
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000424 const TextureSamplerArray& samplers) {
bsalomonc6327a82014-10-27 12:53:08 -0700425 const char* yoffsets;
426 fRGBAYValuesUni = builder->addUniform(GrGLFPBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -0800427 kVec4f_GrSLType, kDefault_GrSLPrecision,
428 "yoffsets", &yoffsets);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000429 static const float kColorScaleFactor = 255.0f / 256.0f;
430 static const float kColorOffsetFactor = 1.0f / 512.0f;
egdaniel29bee0f2015-04-29 11:54:42 -0700431 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000432 if (NULL == inputColor) {
433 // the input color is solid white (all ones).
434 static const float kMaxValue = kColorScaleFactor + kColorOffsetFactor;
joshualitt30ba4362014-08-21 20:18:45 -0700435 fsBuilder->codeAppendf("\t\tvec4 coord = vec4(%f, %f, %f, %f);\n",
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000436 kMaxValue, kMaxValue, kMaxValue, kMaxValue);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000437
438 } else {
joshualitt30ba4362014-08-21 20:18:45 -0700439 fsBuilder->codeAppendf("\t\tfloat nonZeroAlpha = max(%s.a, .0001);\n", inputColor);
440 fsBuilder->codeAppendf("\t\tvec4 coord = vec4(%s.rgb / nonZeroAlpha, nonZeroAlpha);\n", inputColor);
441 fsBuilder->codeAppendf("\t\tcoord = coord * %f + vec4(%f, %f, %f, %f);\n",
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000442 kColorScaleFactor,
443 kColorOffsetFactor, kColorOffsetFactor,
444 kColorOffsetFactor, kColorOffsetFactor);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000445 }
446
bsalomonc6327a82014-10-27 12:53:08 -0700447 SkString coord;
448
joshualitt30ba4362014-08-21 20:18:45 -0700449 fsBuilder->codeAppendf("\t\t%s.a = ", outputColor);
bsalomonc6327a82014-10-27 12:53:08 -0700450 coord.printf("vec2(coord.a, %s.a)", yoffsets);
451 fsBuilder->appendTextureLookup(samplers[0], coord.c_str());
joshualitt30ba4362014-08-21 20:18:45 -0700452 fsBuilder->codeAppend(";\n");
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000453
joshualitt30ba4362014-08-21 20:18:45 -0700454 fsBuilder->codeAppendf("\t\t%s.r = ", outputColor);
bsalomonc6327a82014-10-27 12:53:08 -0700455 coord.printf("vec2(coord.r, %s.r)", yoffsets);
456 fsBuilder->appendTextureLookup(samplers[0], coord.c_str());
joshualitt30ba4362014-08-21 20:18:45 -0700457 fsBuilder->codeAppend(";\n");
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000458
joshualitt30ba4362014-08-21 20:18:45 -0700459 fsBuilder->codeAppendf("\t\t%s.g = ", outputColor);
bsalomonc6327a82014-10-27 12:53:08 -0700460 coord.printf("vec2(coord.g, %s.g)", yoffsets);
461 fsBuilder->appendTextureLookup(samplers[0], coord.c_str());
joshualitt30ba4362014-08-21 20:18:45 -0700462 fsBuilder->codeAppend(";\n");
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000463
joshualitt30ba4362014-08-21 20:18:45 -0700464 fsBuilder->codeAppendf("\t\t%s.b = ", outputColor);
bsalomonc6327a82014-10-27 12:53:08 -0700465 coord.printf("vec2(coord.b, %s.b)", yoffsets);
466 fsBuilder->appendTextureLookup(samplers[0], coord.c_str());
joshualitt30ba4362014-08-21 20:18:45 -0700467 fsBuilder->codeAppend(";\n");
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000468
joshualitt30ba4362014-08-21 20:18:45 -0700469 fsBuilder->codeAppendf("\t\t%s.rgb *= %s.a;\n", outputColor, outputColor);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000470}
471
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000472///////////////////////////////////////////////////////////////////////////////
bsalomonc6327a82014-10-27 12:53:08 -0700473GrFragmentProcessor* ColorTableEffect::Create(GrContext* context, SkBitmap bitmap, unsigned flags) {
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000474
bsalomonc6327a82014-10-27 12:53:08 -0700475 GrTextureStripAtlas::Desc desc;
476 desc.fWidth = bitmap.width();
477 desc.fHeight = 128;
478 desc.fRowHeight = bitmap.height();
479 desc.fContext = context;
480 desc.fConfig = SkImageInfo2GrPixelConfig(bitmap.info());
481 GrTextureStripAtlas* atlas = GrTextureStripAtlas::GetAtlas(desc);
482 int row = atlas->lockRow(bitmap);
483 SkAutoTUnref<GrTexture> texture;
484 if (-1 == row) {
485 atlas = NULL;
486 // Passing params=NULL because this effect does no tiling or filtering.
487 texture.reset(GrRefCachedBitmapTexture(context, bitmap, NULL));
488 } else {
489 texture.reset(SkRef(atlas->getTexture()));
490 }
491
492 return SkNEW_ARGS(ColorTableEffect, (texture, atlas, row, flags));
493}
494
495ColorTableEffect::ColorTableEffect(GrTexture* texture, GrTextureStripAtlas* atlas, int row,
496 unsigned flags)
bsalomon@google.com371e1052013-01-11 21:08:55 +0000497 : fTextureAccess(texture, "a")
bsalomonc6327a82014-10-27 12:53:08 -0700498 , fFlags(flags)
499 , fAtlas(atlas)
500 , fRow(row) {
joshualitteb2a6762014-12-04 11:35:33 -0800501 this->initClassID<ColorTableEffect>();
bsalomon@google.com50db75c2013-01-11 13:54:30 +0000502 this->addTextureAccess(&fTextureAccess);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000503}
504
505ColorTableEffect::~ColorTableEffect() {
bsalomonc6327a82014-10-27 12:53:08 -0700506 if (fAtlas) {
507 fAtlas->unlockRow(fRow);
508 }
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000509}
510
jvanverthcfc18862015-04-28 08:48:20 -0700511void ColorTableEffect::getGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -0800512 GrProcessorKeyBuilder* b) const {
513 GLColorTableEffect::GenKey(*this, caps, b);
514}
515
516GrGLFragmentProcessor* ColorTableEffect::createGLInstance() const {
517 return SkNEW_ARGS(GLColorTableEffect, (*this));
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000518}
519
bsalomonc6327a82014-10-27 12:53:08 -0700520bool ColorTableEffect::onIsEqual(const GrFragmentProcessor& other) const {
521 // For non-atlased instances, the texture (compared by base class) is sufficient to
522 // differentiate different tables. For atlased instances we ensure they are using the
523 // same row.
524 const ColorTableEffect& that = other.cast<ColorTableEffect>();
525 SkASSERT(SkToBool(fAtlas) == SkToBool(that.fAtlas));
526 // Ok to always do this comparison since both would be -1 if non-atlased.
527 return fRow == that.fRow;
528}
529
egdaniel605dd0f2014-11-12 08:35:25 -0800530void ColorTableEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
bsalomon@google.com371e1052013-01-11 21:08:55 +0000531 // If we kept the table in the effect then we could actually run known inputs through the
532 // table.
egdanielccb2e382014-10-13 12:53:46 -0700533 uint8_t invalidateFlags = 0;
bsalomon@google.com371e1052013-01-11 21:08:55 +0000534 if (fFlags & SkTable_ColorFilter::kR_Flag) {
egdanielccb2e382014-10-13 12:53:46 -0700535 invalidateFlags |= kR_GrColorComponentFlag;
bsalomon@google.com371e1052013-01-11 21:08:55 +0000536 }
537 if (fFlags & SkTable_ColorFilter::kG_Flag) {
egdanielccb2e382014-10-13 12:53:46 -0700538 invalidateFlags |= kG_GrColorComponentFlag;
bsalomon@google.com371e1052013-01-11 21:08:55 +0000539 }
540 if (fFlags & SkTable_ColorFilter::kB_Flag) {
egdanielccb2e382014-10-13 12:53:46 -0700541 invalidateFlags |= kB_GrColorComponentFlag;
bsalomon@google.com371e1052013-01-11 21:08:55 +0000542 }
543 if (fFlags & SkTable_ColorFilter::kA_Flag) {
egdanielccb2e382014-10-13 12:53:46 -0700544 invalidateFlags |= kA_GrColorComponentFlag;
bsalomon@google.com371e1052013-01-11 21:08:55 +0000545 }
egdaniel605dd0f2014-11-12 08:35:25 -0800546 inout->invalidateComponents(invalidateFlags, GrInvariantOutput::kWill_ReadInput);
bsalomon@google.com371e1052013-01-11 21:08:55 +0000547}
548
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000549///////////////////////////////////////////////////////////////////////////////
550
joshualittb0a8a372014-09-23 09:50:21 -0700551GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ColorTableEffect);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000552
joshualittb0a8a372014-09-23 09:50:21 -0700553GrFragmentProcessor* ColorTableEffect::TestCreate(SkRandom* random,
554 GrContext* context,
bsalomon4b91f762015-05-19 09:29:46 -0700555 const GrCaps&,
joshualittb0a8a372014-09-23 09:50:21 -0700556 GrTexture* textures[]) {
bsalomonc6327a82014-10-27 12:53:08 -0700557 int flags = 0;
558 uint8_t luts[256][4];
559 do {
560 for (int i = 0; i < 4; ++i) {
561 flags |= random->nextBool() ? (1 << i): 0;
562 }
563 } while (!flags);
564 for (int i = 0; i < 4; ++i) {
565 if (flags & (1 << i)) {
566 for (int j = 0; j < 256; ++j) {
567 luts[j][i] = SkToU8(random->nextBits(8));
568 }
569 }
570 }
571 SkAutoTUnref<SkColorFilter> filter(SkTableColorFilter::CreateARGB(
572 (flags & (1 << 0)) ? luts[0] : NULL,
573 (flags & (1 << 1)) ? luts[1] : NULL,
574 (flags & (1 << 2)) ? luts[2] : NULL,
575 (flags & (1 << 3)) ? luts[3] : NULL
576 ));
reedcff10b22015-03-03 06:41:45 -0800577
578 SkTDArray<GrFragmentProcessor*> array;
579 if (filter->asFragmentProcessors(context, &array)) {
580 SkASSERT(1 == array.count()); // TableColorFilter only returns 1
581 return array[0];
582 }
583 return NULL;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000584}
585
reedcff10b22015-03-03 06:41:45 -0800586bool SkTable_ColorFilter::asFragmentProcessors(GrContext* context,
587 SkTDArray<GrFragmentProcessor*>* array) const {
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000588 SkBitmap bitmap;
589 this->asComponentTable(&bitmap);
bsalomonc6327a82014-10-27 12:53:08 -0700590
reedcff10b22015-03-03 06:41:45 -0800591 GrFragmentProcessor* frag = ColorTableEffect::Create(context, bitmap, fFlags);
592 if (frag) {
593 if (array) {
594 *array->append() = frag;
595 }
596 return true;
597 }
598 return false;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000599}
600
601#endif // SK_SUPPORT_GPU
602
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000603///////////////////////////////////////////////////////////////////////////////
604
605#ifdef SK_CPU_BENDIAN
606#else
607 #define SK_A32_INDEX (3 - (SK_A32_SHIFT >> 3))
608 #define SK_R32_INDEX (3 - (SK_R32_SHIFT >> 3))
609 #define SK_G32_INDEX (3 - (SK_G32_SHIFT >> 3))
610 #define SK_B32_INDEX (3 - (SK_B32_SHIFT >> 3))
611#endif
612
613///////////////////////////////////////////////////////////////////////////////
614
615SkColorFilter* SkTableColorFilter::Create(const uint8_t table[256]) {
616 return SkNEW_ARGS(SkTable_ColorFilter, (table, table, table, table));
617}
618
619SkColorFilter* SkTableColorFilter::CreateARGB(const uint8_t tableA[256],
620 const uint8_t tableR[256],
621 const uint8_t tableG[256],
622 const uint8_t tableB[256]) {
623 return SkNEW_ARGS(SkTable_ColorFilter, (tableA, tableR, tableG, tableB));
624}
djsollen@google.coma2ca41e2012-03-23 19:00:34 +0000625
626SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkTableColorFilter)
627 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkTable_ColorFilter)
628SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END