blob: faffa4a43dea2d8af2998fc022c445cc96d418e9 [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
joshualitt2cff1762015-07-08 07:58:18 -070053 bool asFragmentProcessors(GrContext*, GrShaderDataManager*,
54 SkTDArray<GrFragmentProcessor*>*) const override;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +000055#endif
mike@reedtribe.orgf23f5f72012-01-07 03:48:45 +000056
mtklein36352bf2015-03-25 18:17:31 -070057 void filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const override;
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +000058
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +000059 SK_TO_STRING_OVERRIDE()
robertphillips@google.com1202c2a2013-05-23 14:00:17 +000060
djsollen@google.comba28d032012-03-26 17:57:35 +000061 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkTable_ColorFilter)
mike@reedtribe.orgf23f5f72012-01-07 03:48:45 +000062
bsalomon@google.com371e1052013-01-11 21:08:55 +000063 enum {
64 kA_Flag = 1 << 0,
65 kR_Flag = 1 << 1,
66 kG_Flag = 1 << 2,
67 kB_Flag = 1 << 3,
68 };
69
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +000070protected:
mtklein36352bf2015-03-25 18:17:31 -070071 void flatten(SkWriteBuffer&) const override;
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +000072
73private:
bsalomon@google.comb2ad1012012-10-17 15:00:32 +000074 mutable const SkBitmap* fBitmap; // lazily allocated
mike@reedtribe.orgf23f5f72012-01-07 03:48:45 +000075
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +000076 uint8_t fStorage[256 * 4];
77 unsigned fFlags;
78
reed9fa60da2014-08-21 07:59:51 -070079 friend class SkTableColorFilter;
80
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +000081 typedef SkColorFilter INHERITED;
82};
83
84static const uint8_t gIdentityTable[] = {
rmistry@google.comfbfcd562012-08-23 18:09:54 +000085 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
86 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
87 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
88 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
89 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
90 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
91 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
92 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
93 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
94 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
95 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
96 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
97 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
98 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
99 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
100 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
101 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
102 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
103 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
104 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
105 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
106 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
107 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7,
108 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
109 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
110 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
111 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
112 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
113 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
114 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
115 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000116 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
117};
118
reed8a8d8412015-03-02 13:46:03 -0800119void SkTable_ColorFilter::filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const {
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000120 const uint8_t* table = fStorage;
121 const uint8_t* tableA = gIdentityTable;
122 const uint8_t* tableR = gIdentityTable;
123 const uint8_t* tableG = gIdentityTable;
124 const uint8_t* tableB = gIdentityTable;
125 if (fFlags & kA_Flag) {
126 tableA = table; table += 256;
127 }
128 if (fFlags & kR_Flag) {
129 tableR = table; table += 256;
130 }
131 if (fFlags & kG_Flag) {
132 tableG = table; table += 256;
133 }
134 if (fFlags & kB_Flag) {
135 tableB = table;
136 }
137
138 const SkUnPreMultiply::Scale* scaleTable = SkUnPreMultiply::GetScaleTable();
139 for (int i = 0; i < count; ++i) {
140 SkPMColor c = src[i];
141 unsigned a, r, g, b;
142 if (0 == c) {
143 a = r = g = b = 0;
144 } else {
145 a = SkGetPackedA32(c);
146 r = SkGetPackedR32(c);
147 g = SkGetPackedG32(c);
148 b = SkGetPackedB32(c);
149
150 if (a < 255) {
151 SkUnPreMultiply::Scale scale = scaleTable[a];
152 r = SkUnPreMultiply::ApplyScale(scale, r);
153 g = SkUnPreMultiply::ApplyScale(scale, g);
154 b = SkUnPreMultiply::ApplyScale(scale, b);
155 }
156 }
157 dst[i] = SkPremultiplyARGBInline(tableA[a], tableR[r],
158 tableG[g], tableB[b]);
159 }
160}
161
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +0000162#ifndef SK_IGNORE_TO_STRING
robertphillips@google.com1202c2a2013-05-23 14:00:17 +0000163void SkTable_ColorFilter::toString(SkString* str) const {
robertphillipsf3f5bad2014-12-19 13:49:15 -0800164 const uint8_t* table = fStorage;
165 const uint8_t* tableA = gIdentityTable;
166 const uint8_t* tableR = gIdentityTable;
167 const uint8_t* tableG = gIdentityTable;
168 const uint8_t* tableB = gIdentityTable;
169 if (fFlags & kA_Flag) {
170 tableA = table; table += 256;
171 }
172 if (fFlags & kR_Flag) {
173 tableR = table; table += 256;
174 }
175 if (fFlags & kG_Flag) {
176 tableG = table; table += 256;
177 }
178 if (fFlags & kB_Flag) {
179 tableB = table;
180 }
181
182 str->append("SkTable_ColorFilter (");
183
184 for (int i = 0; i < 256; ++i) {
185 str->appendf("%d: %d,%d,%d,%d\n",
186 i, tableR[i], tableG[i], tableB[i], tableA[i]);
187 }
188
189 str->append(")");
robertphillips@google.com1202c2a2013-05-23 14:00:17 +0000190}
191#endif
192
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000193static const uint8_t gCountNibBits[] = {
194 0, 1, 1, 2,
195 1, 2, 2, 3,
196 1, 2, 2, 3,
197 2, 3, 3, 4
198};
199
200#include "SkPackBits.h"
201
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000202void SkTable_ColorFilter::flatten(SkWriteBuffer& buffer) const {
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000203 uint8_t storage[5*256];
204 int count = gCountNibBits[fFlags & 0xF];
jschuh699b8522015-06-04 15:10:37 -0700205 size_t size = SkPackBits::Pack8(fStorage, count * 256, storage,
206 sizeof(storage));
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000207
reed9fa60da2014-08-21 07:59:51 -0700208 buffer.write32(fFlags);
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000209 buffer.writeByteArray(storage, size);
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000210}
211
reed9fa60da2014-08-21 07:59:51 -0700212SkFlattenable* SkTable_ColorFilter::CreateProc(SkReadBuffer& buffer) {
213 const int flags = buffer.read32();
214 const size_t count = gCountNibBits[flags & 0xF];
215 SkASSERT(count <= 4);
216
217 uint8_t packedStorage[5*256];
218 size_t packedSize = buffer.getArrayCount();
219 if (!buffer.validate(packedSize <= sizeof(packedStorage))) {
220 return NULL;
221 }
222 if (!buffer.readByteArray(packedStorage, packedSize)) {
223 return NULL;
224 }
225
226 uint8_t unpackedStorage[4*256];
jschuh699b8522015-06-04 15:10:37 -0700227 size_t unpackedSize = SkPackBits::Unpack8(packedStorage, packedSize,
228 unpackedStorage, sizeof(unpackedStorage));
reed9fa60da2014-08-21 07:59:51 -0700229 // now check that we got the size we expected
senorblanco91c395a2014-09-25 15:51:35 -0700230 if (!buffer.validate(unpackedSize == count*256)) {
reed9fa60da2014-08-21 07:59:51 -0700231 return NULL;
232 }
233
234 const uint8_t* a = NULL;
235 const uint8_t* r = NULL;
236 const uint8_t* g = NULL;
237 const uint8_t* b = NULL;
238 const uint8_t* ptr = unpackedStorage;
239
240 if (flags & kA_Flag) {
241 a = ptr;
242 ptr += 256;
243 }
244 if (flags & kR_Flag) {
245 r = ptr;
246 ptr += 256;
247 }
248 if (flags & kG_Flag) {
249 g = ptr;
250 ptr += 256;
251 }
252 if (flags & kB_Flag) {
253 b = ptr;
254 ptr += 256;
255 }
256 return SkTableColorFilter::CreateARGB(a, r, g, b);
257}
258
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000259bool SkTable_ColorFilter::asComponentTable(SkBitmap* table) const {
mike@reedtribe.orgf23f5f72012-01-07 03:48:45 +0000260 if (table) {
261 if (NULL == fBitmap) {
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000262 SkBitmap* bmp = SkNEW(SkBitmap);
reed@google.com9ebcac52014-01-24 18:53:42 +0000263 bmp->allocPixels(SkImageInfo::MakeA8(256, 4));
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000264 uint8_t* bitmapPixels = bmp->getAddr8(0, 0);
twiz@google.com58071162012-07-18 21:41:50 +0000265 int offset = 0;
266 static const unsigned kFlags[] = { kA_Flag, kR_Flag, kG_Flag, kB_Flag };
267
268 for (int x = 0; x < 4; ++x) {
269 if (!(fFlags & kFlags[x])) {
270 memcpy(bitmapPixels, gIdentityTable, sizeof(gIdentityTable));
271 } else {
272 memcpy(bitmapPixels, fStorage + offset, 256);
273 offset += 256;
274 }
275 bitmapPixels += 256;
276 }
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000277 fBitmap = bmp;
mike@reedtribe.orgf23f5f72012-01-07 03:48:45 +0000278 }
279 *table = *fBitmap;
280 }
281 return true;
282}
283
reed8a8d8412015-03-02 13:46:03 -0800284// Combines the two lookup tables so that making a lookup using res[] has
285// the same effect as making a lookup through inner[] then outer[].
286static void combine_tables(uint8_t res[256], const uint8_t outer[256], const uint8_t inner[256]) {
287 for (int i = 0; i < 256; i++) {
288 res[i] = outer[inner[i]];
289 }
290}
291
292SkColorFilter* SkTable_ColorFilter::newComposed(const SkColorFilter* innerFilter) const {
293 SkBitmap innerBM;
294 if (!innerFilter->asComponentTable(&innerBM)) {
295 return NULL;
296 }
297
298 innerBM.lockPixels();
299 if (NULL == innerBM.getPixels()) {
300 return NULL;
301 }
302
303 const uint8_t* table = fStorage;
304 const uint8_t* tableA = gIdentityTable;
305 const uint8_t* tableR = gIdentityTable;
306 const uint8_t* tableG = gIdentityTable;
307 const uint8_t* tableB = gIdentityTable;
308 if (fFlags & kA_Flag) {
309 tableA = table; table += 256;
310 }
311 if (fFlags & kR_Flag) {
312 tableR = table; table += 256;
313 }
314 if (fFlags & kG_Flag) {
315 tableG = table; table += 256;
316 }
317 if (fFlags & kB_Flag) {
318 tableB = table;
319 }
320
321 uint8_t concatA[256];
322 uint8_t concatR[256];
323 uint8_t concatG[256];
324 uint8_t concatB[256];
325
326 combine_tables(concatA, tableA, innerBM.getAddr8(0, 0));
327 combine_tables(concatR, tableR, innerBM.getAddr8(0, 1));
328 combine_tables(concatG, tableG, innerBM.getAddr8(0, 2));
329 combine_tables(concatB, tableB, innerBM.getAddr8(0, 3));
330
331 return SkTableColorFilter::CreateARGB(concatA, concatR, concatG, concatB);
332}
333
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000334#if SK_SUPPORT_GPU
335
bsalomon6251d172014-10-15 10:50:36 -0700336#include "GrFragmentProcessor.h"
egdaniel605dd0f2014-11-12 08:35:25 -0800337#include "GrInvariantOutput.h"
bsalomonc6327a82014-10-27 12:53:08 -0700338#include "SkGr.h"
339#include "effects/GrTextureStripAtlas.h"
joshualittb0a8a372014-09-23 09:50:21 -0700340#include "gl/GrGLProcessor.h"
joshualitt30ba4362014-08-21 20:18:45 -0700341#include "gl/builders/GrGLProgramBuilder.h"
bsalomonc6327a82014-10-27 12:53:08 -0700342
joshualittb0a8a372014-09-23 09:50:21 -0700343class ColorTableEffect : public GrFragmentProcessor {
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000344public:
bsalomonc6327a82014-10-27 12:53:08 -0700345 static GrFragmentProcessor* Create(GrContext* context, SkBitmap bitmap, unsigned flags);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000346
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000347 virtual ~ColorTableEffect();
348
mtklein36352bf2015-03-25 18:17:31 -0700349 const char* name() const override { return "ColorTable"; }
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000350
jvanverthcfc18862015-04-28 08:48:20 -0700351 void getGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
joshualitteb2a6762014-12-04 11:35:33 -0800352
mtklein36352bf2015-03-25 18:17:31 -0700353 GrGLFragmentProcessor* createGLInstance() const override;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000354
bsalomonc6327a82014-10-27 12:53:08 -0700355 const GrTextureStripAtlas* atlas() const { return fAtlas; }
356 int atlasRow() const { return fRow; }
357
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000358private:
mtklein36352bf2015-03-25 18:17:31 -0700359 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000360
mtklein36352bf2015-03-25 18:17:31 -0700361 void onComputeInvariantOutput(GrInvariantOutput* inout) const override;
egdaniel1a8ecdf2014-10-03 06:24:12 -0700362
bsalomonc6327a82014-10-27 12:53:08 -0700363 ColorTableEffect(GrTexture* texture, GrTextureStripAtlas* atlas, int row, unsigned flags);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000364
joshualittb0a8a372014-09-23 09:50:21 -0700365 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000366
bsalomonc6327a82014-10-27 12:53:08 -0700367 GrTextureAccess fTextureAccess;
368
369 // currently not used in shader code, just to assist onComputeInvariantOutput().
mtklein3f3b3d02014-12-01 11:47:08 -0800370 unsigned fFlags;
bsalomonc6327a82014-10-27 12:53:08 -0700371
372 GrTextureStripAtlas* fAtlas;
373 int fRow;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000374
joshualittb0a8a372014-09-23 09:50:21 -0700375 typedef GrFragmentProcessor INHERITED;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000376};
377
joshualittb0a8a372014-09-23 09:50:21 -0700378class GLColorTableEffect : public GrGLFragmentProcessor {
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000379public:
joshualitteb2a6762014-12-04 11:35:33 -0800380 GLColorTableEffect(const GrProcessor&);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000381
joshualitt15988992014-10-09 15:04:05 -0700382 virtual void emitCode(GrGLFPBuilder*,
joshualittb0a8a372014-09-23 09:50:21 -0700383 const GrFragmentProcessor&,
bsalomon@google.com22a800a2012-10-26 19:16:46 +0000384 const char* outputColor,
385 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +0000386 const TransformedCoordsArray&,
mtklein36352bf2015-03-25 18:17:31 -0700387 const TextureSamplerArray&) override;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000388
mtklein36352bf2015-03-25 18:17:31 -0700389 void setData(const GrGLProgramDataManager&, const GrProcessor&) override;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000390
jvanverthcfc18862015-04-28 08:48:20 -0700391 static void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder* b) {}
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000392
393private:
bsalomonc6327a82014-10-27 12:53:08 -0700394 UniformHandle fRGBAYValuesUni;
joshualittb0a8a372014-09-23 09:50:21 -0700395 typedef GrGLFragmentProcessor INHERITED;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000396};
397
joshualitteb2a6762014-12-04 11:35:33 -0800398GLColorTableEffect::GLColorTableEffect(const GrProcessor&) {
399}
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000400
bsalomonc6327a82014-10-27 12:53:08 -0700401void GLColorTableEffect::setData(const GrGLProgramDataManager& pdm, const GrProcessor& proc) {
402 // The textures are organized in a strip where the rows are ordered a, r, g, b.
403 float rgbaYValues[4];
404 const ColorTableEffect& cte = proc.cast<ColorTableEffect>();
405 if (cte.atlas()) {
406 SkScalar yDelta = cte.atlas()->getNormalizedTexelHeight();
407 rgbaYValues[3] = cte.atlas()->getYOffset(cte.atlasRow()) + SK_ScalarHalf * yDelta;
408 rgbaYValues[0] = rgbaYValues[3] + yDelta;
409 rgbaYValues[1] = rgbaYValues[0] + yDelta;
410 rgbaYValues[2] = rgbaYValues[1] + yDelta;
411 } else {
412 rgbaYValues[3] = 0.125;
413 rgbaYValues[0] = 0.375;
414 rgbaYValues[1] = 0.625;
mtklein3f3b3d02014-12-01 11:47:08 -0800415 rgbaYValues[2] = 0.875;
bsalomonc6327a82014-10-27 12:53:08 -0700416 }
417 pdm.set4fv(fRGBAYValuesUni, 1, rgbaYValues);
418}
419
joshualitt15988992014-10-09 15:04:05 -0700420void GLColorTableEffect::emitCode(GrGLFPBuilder* builder,
joshualittb0a8a372014-09-23 09:50:21 -0700421 const GrFragmentProcessor&,
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000422 const char* outputColor,
423 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +0000424 const TransformedCoordsArray&,
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000425 const TextureSamplerArray& samplers) {
bsalomonc6327a82014-10-27 12:53:08 -0700426 const char* yoffsets;
427 fRGBAYValuesUni = builder->addUniform(GrGLFPBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -0800428 kVec4f_GrSLType, kDefault_GrSLPrecision,
429 "yoffsets", &yoffsets);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000430 static const float kColorScaleFactor = 255.0f / 256.0f;
431 static const float kColorOffsetFactor = 1.0f / 512.0f;
egdaniel29bee0f2015-04-29 11:54:42 -0700432 GrGLFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000433 if (NULL == inputColor) {
434 // the input color is solid white (all ones).
435 static const float kMaxValue = kColorScaleFactor + kColorOffsetFactor;
joshualitt30ba4362014-08-21 20:18:45 -0700436 fsBuilder->codeAppendf("\t\tvec4 coord = vec4(%f, %f, %f, %f);\n",
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000437 kMaxValue, kMaxValue, kMaxValue, kMaxValue);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000438
439 } else {
joshualitt30ba4362014-08-21 20:18:45 -0700440 fsBuilder->codeAppendf("\t\tfloat nonZeroAlpha = max(%s.a, .0001);\n", inputColor);
441 fsBuilder->codeAppendf("\t\tvec4 coord = vec4(%s.rgb / nonZeroAlpha, nonZeroAlpha);\n", inputColor);
442 fsBuilder->codeAppendf("\t\tcoord = coord * %f + vec4(%f, %f, %f, %f);\n",
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000443 kColorScaleFactor,
444 kColorOffsetFactor, kColorOffsetFactor,
445 kColorOffsetFactor, kColorOffsetFactor);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000446 }
447
bsalomonc6327a82014-10-27 12:53:08 -0700448 SkString coord;
449
joshualitt30ba4362014-08-21 20:18:45 -0700450 fsBuilder->codeAppendf("\t\t%s.a = ", outputColor);
bsalomonc6327a82014-10-27 12:53:08 -0700451 coord.printf("vec2(coord.a, %s.a)", yoffsets);
452 fsBuilder->appendTextureLookup(samplers[0], coord.c_str());
joshualitt30ba4362014-08-21 20:18:45 -0700453 fsBuilder->codeAppend(";\n");
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000454
joshualitt30ba4362014-08-21 20:18:45 -0700455 fsBuilder->codeAppendf("\t\t%s.r = ", outputColor);
bsalomonc6327a82014-10-27 12:53:08 -0700456 coord.printf("vec2(coord.r, %s.r)", yoffsets);
457 fsBuilder->appendTextureLookup(samplers[0], coord.c_str());
joshualitt30ba4362014-08-21 20:18:45 -0700458 fsBuilder->codeAppend(";\n");
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000459
joshualitt30ba4362014-08-21 20:18:45 -0700460 fsBuilder->codeAppendf("\t\t%s.g = ", outputColor);
bsalomonc6327a82014-10-27 12:53:08 -0700461 coord.printf("vec2(coord.g, %s.g)", yoffsets);
462 fsBuilder->appendTextureLookup(samplers[0], coord.c_str());
joshualitt30ba4362014-08-21 20:18:45 -0700463 fsBuilder->codeAppend(";\n");
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000464
joshualitt30ba4362014-08-21 20:18:45 -0700465 fsBuilder->codeAppendf("\t\t%s.b = ", outputColor);
bsalomonc6327a82014-10-27 12:53:08 -0700466 coord.printf("vec2(coord.b, %s.b)", yoffsets);
467 fsBuilder->appendTextureLookup(samplers[0], coord.c_str());
joshualitt30ba4362014-08-21 20:18:45 -0700468 fsBuilder->codeAppend(";\n");
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000469
joshualitt30ba4362014-08-21 20:18:45 -0700470 fsBuilder->codeAppendf("\t\t%s.rgb *= %s.a;\n", outputColor, outputColor);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000471}
472
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000473///////////////////////////////////////////////////////////////////////////////
bsalomonc6327a82014-10-27 12:53:08 -0700474GrFragmentProcessor* ColorTableEffect::Create(GrContext* context, SkBitmap bitmap, unsigned flags) {
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000475
bsalomonc6327a82014-10-27 12:53:08 -0700476 GrTextureStripAtlas::Desc desc;
477 desc.fWidth = bitmap.width();
478 desc.fHeight = 128;
479 desc.fRowHeight = bitmap.height();
480 desc.fContext = context;
481 desc.fConfig = SkImageInfo2GrPixelConfig(bitmap.info());
482 GrTextureStripAtlas* atlas = GrTextureStripAtlas::GetAtlas(desc);
483 int row = atlas->lockRow(bitmap);
484 SkAutoTUnref<GrTexture> texture;
485 if (-1 == row) {
486 atlas = NULL;
487 // Passing params=NULL because this effect does no tiling or filtering.
488 texture.reset(GrRefCachedBitmapTexture(context, bitmap, NULL));
489 } else {
490 texture.reset(SkRef(atlas->getTexture()));
491 }
492
493 return SkNEW_ARGS(ColorTableEffect, (texture, atlas, row, flags));
494}
495
496ColorTableEffect::ColorTableEffect(GrTexture* texture, GrTextureStripAtlas* atlas, int row,
497 unsigned flags)
bsalomon@google.com371e1052013-01-11 21:08:55 +0000498 : fTextureAccess(texture, "a")
bsalomonc6327a82014-10-27 12:53:08 -0700499 , fFlags(flags)
500 , fAtlas(atlas)
501 , fRow(row) {
joshualitteb2a6762014-12-04 11:35:33 -0800502 this->initClassID<ColorTableEffect>();
bsalomon@google.com50db75c2013-01-11 13:54:30 +0000503 this->addTextureAccess(&fTextureAccess);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000504}
505
506ColorTableEffect::~ColorTableEffect() {
bsalomonc6327a82014-10-27 12:53:08 -0700507 if (fAtlas) {
508 fAtlas->unlockRow(fRow);
509 }
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000510}
511
jvanverthcfc18862015-04-28 08:48:20 -0700512void ColorTableEffect::getGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -0800513 GrProcessorKeyBuilder* b) const {
514 GLColorTableEffect::GenKey(*this, caps, b);
515}
516
517GrGLFragmentProcessor* ColorTableEffect::createGLInstance() const {
518 return SkNEW_ARGS(GLColorTableEffect, (*this));
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000519}
520
bsalomonc6327a82014-10-27 12:53:08 -0700521bool ColorTableEffect::onIsEqual(const GrFragmentProcessor& other) const {
522 // For non-atlased instances, the texture (compared by base class) is sufficient to
523 // differentiate different tables. For atlased instances we ensure they are using the
524 // same row.
525 const ColorTableEffect& that = other.cast<ColorTableEffect>();
526 SkASSERT(SkToBool(fAtlas) == SkToBool(that.fAtlas));
527 // Ok to always do this comparison since both would be -1 if non-atlased.
528 return fRow == that.fRow;
529}
530
egdaniel605dd0f2014-11-12 08:35:25 -0800531void ColorTableEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
bsalomon@google.com371e1052013-01-11 21:08:55 +0000532 // If we kept the table in the effect then we could actually run known inputs through the
533 // table.
egdanielccb2e382014-10-13 12:53:46 -0700534 uint8_t invalidateFlags = 0;
bsalomon@google.com371e1052013-01-11 21:08:55 +0000535 if (fFlags & SkTable_ColorFilter::kR_Flag) {
egdanielccb2e382014-10-13 12:53:46 -0700536 invalidateFlags |= kR_GrColorComponentFlag;
bsalomon@google.com371e1052013-01-11 21:08:55 +0000537 }
538 if (fFlags & SkTable_ColorFilter::kG_Flag) {
egdanielccb2e382014-10-13 12:53:46 -0700539 invalidateFlags |= kG_GrColorComponentFlag;
bsalomon@google.com371e1052013-01-11 21:08:55 +0000540 }
541 if (fFlags & SkTable_ColorFilter::kB_Flag) {
egdanielccb2e382014-10-13 12:53:46 -0700542 invalidateFlags |= kB_GrColorComponentFlag;
bsalomon@google.com371e1052013-01-11 21:08:55 +0000543 }
544 if (fFlags & SkTable_ColorFilter::kA_Flag) {
egdanielccb2e382014-10-13 12:53:46 -0700545 invalidateFlags |= kA_GrColorComponentFlag;
bsalomon@google.com371e1052013-01-11 21:08:55 +0000546 }
egdaniel605dd0f2014-11-12 08:35:25 -0800547 inout->invalidateComponents(invalidateFlags, GrInvariantOutput::kWill_ReadInput);
bsalomon@google.com371e1052013-01-11 21:08:55 +0000548}
549
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000550///////////////////////////////////////////////////////////////////////////////
551
joshualittb0a8a372014-09-23 09:50:21 -0700552GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ColorTableEffect);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000553
joshualitt0067ff52015-07-08 14:26:19 -0700554GrFragmentProcessor* ColorTableEffect::TestCreate(GrProcessorTestData* d) {
bsalomonc6327a82014-10-27 12:53:08 -0700555 int flags = 0;
556 uint8_t luts[256][4];
557 do {
558 for (int i = 0; i < 4; ++i) {
joshualitt0067ff52015-07-08 14:26:19 -0700559 flags |= d->fRandom->nextBool() ? (1 << i): 0;
bsalomonc6327a82014-10-27 12:53:08 -0700560 }
561 } while (!flags);
562 for (int i = 0; i < 4; ++i) {
563 if (flags & (1 << i)) {
564 for (int j = 0; j < 256; ++j) {
joshualitt0067ff52015-07-08 14:26:19 -0700565 luts[j][i] = SkToU8(d->fRandom->nextBits(8));
bsalomonc6327a82014-10-27 12:53:08 -0700566 }
567 }
568 }
569 SkAutoTUnref<SkColorFilter> filter(SkTableColorFilter::CreateARGB(
570 (flags & (1 << 0)) ? luts[0] : NULL,
571 (flags & (1 << 1)) ? luts[1] : NULL,
572 (flags & (1 << 2)) ? luts[2] : NULL,
573 (flags & (1 << 3)) ? luts[3] : NULL
574 ));
reedcff10b22015-03-03 06:41:45 -0800575
576 SkTDArray<GrFragmentProcessor*> array;
joshualitt0067ff52015-07-08 14:26:19 -0700577 if (filter->asFragmentProcessors(d->fContext, d->fShaderDataManager, &array)) {
reedcff10b22015-03-03 06:41:45 -0800578 SkASSERT(1 == array.count()); // TableColorFilter only returns 1
579 return array[0];
580 }
581 return NULL;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000582}
583
reedcff10b22015-03-03 06:41:45 -0800584bool SkTable_ColorFilter::asFragmentProcessors(GrContext* context,
joshualitt2cff1762015-07-08 07:58:18 -0700585 GrShaderDataManager*,
reedcff10b22015-03-03 06:41:45 -0800586 SkTDArray<GrFragmentProcessor*>* array) const {
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000587 SkBitmap bitmap;
588 this->asComponentTable(&bitmap);
bsalomonc6327a82014-10-27 12:53:08 -0700589
reedcff10b22015-03-03 06:41:45 -0800590 GrFragmentProcessor* frag = ColorTableEffect::Create(context, bitmap, fFlags);
591 if (frag) {
592 if (array) {
593 *array->append() = frag;
bsalomona0f1a182015-06-12 08:32:52 -0700594 } else {
595 frag->unref();
596 SkDEBUGCODE(frag = NULL;)
reedcff10b22015-03-03 06:41:45 -0800597 }
598 return true;
599 }
600 return false;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000601}
602
603#endif // SK_SUPPORT_GPU
604
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000605///////////////////////////////////////////////////////////////////////////////
606
607#ifdef SK_CPU_BENDIAN
608#else
609 #define SK_A32_INDEX (3 - (SK_A32_SHIFT >> 3))
610 #define SK_R32_INDEX (3 - (SK_R32_SHIFT >> 3))
611 #define SK_G32_INDEX (3 - (SK_G32_SHIFT >> 3))
612 #define SK_B32_INDEX (3 - (SK_B32_SHIFT >> 3))
613#endif
614
615///////////////////////////////////////////////////////////////////////////////
616
617SkColorFilter* SkTableColorFilter::Create(const uint8_t table[256]) {
618 return SkNEW_ARGS(SkTable_ColorFilter, (table, table, table, table));
619}
620
621SkColorFilter* SkTableColorFilter::CreateARGB(const uint8_t tableA[256],
622 const uint8_t tableR[256],
623 const uint8_t tableG[256],
624 const uint8_t tableB[256]) {
625 return SkNEW_ARGS(SkTable_ColorFilter, (tableA, tableR, tableG, tableB));
626}
djsollen@google.coma2ca41e2012-03-23 19:00:34 +0000627
628SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkTableColorFilter)
629 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkTable_ColorFilter)
630SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END