blob: e20f92292a4217ea9551e9f0156c1f8e76784647 [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
halcanary385fe4d2015-08-26 13:07:48 -070045 virtual ~SkTable_ColorFilter() { delete fBitmap; }
tomhudson@google.com1bb4be22012-07-24 17:24:21 +000046
mtklein36352bf2015-03-25 18:17:31 -070047 bool asComponentTable(SkBitmap* table) const override;
48 SkColorFilter* newComposed(const SkColorFilter* inner) const override;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +000049
50#if SK_SUPPORT_GPU
joshualitt9cc17752015-07-09 06:28:14 -070051 bool asFragmentProcessors(GrContext*, GrProcessorDataManager*,
joshualitt2cff1762015-07-08 07:58:18 -070052 SkTDArray<GrFragmentProcessor*>*) const override;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +000053#endif
mike@reedtribe.orgf23f5f72012-01-07 03:48:45 +000054
mtklein36352bf2015-03-25 18:17:31 -070055 void filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const override;
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +000056
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +000057 SK_TO_STRING_OVERRIDE()
robertphillips@google.com1202c2a2013-05-23 14:00:17 +000058
djsollen@google.comba28d032012-03-26 17:57:35 +000059 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkTable_ColorFilter)
mike@reedtribe.orgf23f5f72012-01-07 03:48:45 +000060
bsalomon@google.com371e1052013-01-11 21:08:55 +000061 enum {
62 kA_Flag = 1 << 0,
63 kR_Flag = 1 << 1,
64 kG_Flag = 1 << 2,
65 kB_Flag = 1 << 3,
66 };
67
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +000068protected:
mtklein36352bf2015-03-25 18:17:31 -070069 void flatten(SkWriteBuffer&) const override;
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +000070
71private:
bsalomon@google.comb2ad1012012-10-17 15:00:32 +000072 mutable const SkBitmap* fBitmap; // lazily allocated
mike@reedtribe.orgf23f5f72012-01-07 03:48:45 +000073
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +000074 uint8_t fStorage[256 * 4];
75 unsigned fFlags;
76
reed9fa60da2014-08-21 07:59:51 -070077 friend class SkTableColorFilter;
78
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +000079 typedef SkColorFilter INHERITED;
80};
81
82static const uint8_t gIdentityTable[] = {
rmistry@google.comfbfcd562012-08-23 18:09:54 +000083 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
84 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
85 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
86 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
87 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
88 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
89 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
90 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
91 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
92 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
93 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
94 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
95 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
96 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
97 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
98 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
99 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
100 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
101 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
102 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
103 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
104 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
105 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7,
106 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
107 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
108 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
109 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
110 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
111 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
112 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
113 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000114 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
115};
116
reed8a8d8412015-03-02 13:46:03 -0800117void SkTable_ColorFilter::filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const {
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000118 const uint8_t* table = fStorage;
119 const uint8_t* tableA = gIdentityTable;
120 const uint8_t* tableR = gIdentityTable;
121 const uint8_t* tableG = gIdentityTable;
122 const uint8_t* tableB = gIdentityTable;
123 if (fFlags & kA_Flag) {
124 tableA = table; table += 256;
125 }
126 if (fFlags & kR_Flag) {
127 tableR = table; table += 256;
128 }
129 if (fFlags & kG_Flag) {
130 tableG = table; table += 256;
131 }
132 if (fFlags & kB_Flag) {
133 tableB = table;
134 }
135
136 const SkUnPreMultiply::Scale* scaleTable = SkUnPreMultiply::GetScaleTable();
137 for (int i = 0; i < count; ++i) {
138 SkPMColor c = src[i];
139 unsigned a, r, g, b;
140 if (0 == c) {
141 a = r = g = b = 0;
142 } else {
143 a = SkGetPackedA32(c);
144 r = SkGetPackedR32(c);
145 g = SkGetPackedG32(c);
146 b = SkGetPackedB32(c);
147
148 if (a < 255) {
149 SkUnPreMultiply::Scale scale = scaleTable[a];
150 r = SkUnPreMultiply::ApplyScale(scale, r);
151 g = SkUnPreMultiply::ApplyScale(scale, g);
152 b = SkUnPreMultiply::ApplyScale(scale, b);
153 }
154 }
155 dst[i] = SkPremultiplyARGBInline(tableA[a], tableR[r],
156 tableG[g], tableB[b]);
157 }
158}
159
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +0000160#ifndef SK_IGNORE_TO_STRING
robertphillips@google.com1202c2a2013-05-23 14:00:17 +0000161void SkTable_ColorFilter::toString(SkString* str) const {
robertphillipsf3f5bad2014-12-19 13:49:15 -0800162 const uint8_t* table = fStorage;
163 const uint8_t* tableA = gIdentityTable;
164 const uint8_t* tableR = gIdentityTable;
165 const uint8_t* tableG = gIdentityTable;
166 const uint8_t* tableB = gIdentityTable;
167 if (fFlags & kA_Flag) {
168 tableA = table; table += 256;
169 }
170 if (fFlags & kR_Flag) {
171 tableR = table; table += 256;
172 }
173 if (fFlags & kG_Flag) {
174 tableG = table; table += 256;
175 }
176 if (fFlags & kB_Flag) {
177 tableB = table;
178 }
179
180 str->append("SkTable_ColorFilter (");
181
182 for (int i = 0; i < 256; ++i) {
183 str->appendf("%d: %d,%d,%d,%d\n",
184 i, tableR[i], tableG[i], tableB[i], tableA[i]);
185 }
186
187 str->append(")");
robertphillips@google.com1202c2a2013-05-23 14:00:17 +0000188}
189#endif
190
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000191static const uint8_t gCountNibBits[] = {
192 0, 1, 1, 2,
193 1, 2, 2, 3,
194 1, 2, 2, 3,
195 2, 3, 3, 4
196};
197
198#include "SkPackBits.h"
199
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000200void SkTable_ColorFilter::flatten(SkWriteBuffer& buffer) const {
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000201 uint8_t storage[5*256];
202 int count = gCountNibBits[fFlags & 0xF];
jschuh699b8522015-06-04 15:10:37 -0700203 size_t size = SkPackBits::Pack8(fStorage, count * 256, storage,
204 sizeof(storage));
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000205
reed9fa60da2014-08-21 07:59:51 -0700206 buffer.write32(fFlags);
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000207 buffer.writeByteArray(storage, size);
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000208}
209
reed9fa60da2014-08-21 07:59:51 -0700210SkFlattenable* SkTable_ColorFilter::CreateProc(SkReadBuffer& buffer) {
211 const int flags = buffer.read32();
212 const size_t count = gCountNibBits[flags & 0xF];
213 SkASSERT(count <= 4);
214
215 uint8_t packedStorage[5*256];
216 size_t packedSize = buffer.getArrayCount();
217 if (!buffer.validate(packedSize <= sizeof(packedStorage))) {
218 return NULL;
219 }
220 if (!buffer.readByteArray(packedStorage, packedSize)) {
221 return NULL;
222 }
223
224 uint8_t unpackedStorage[4*256];
jschuh699b8522015-06-04 15:10:37 -0700225 size_t unpackedSize = SkPackBits::Unpack8(packedStorage, packedSize,
226 unpackedStorage, sizeof(unpackedStorage));
reed9fa60da2014-08-21 07:59:51 -0700227 // now check that we got the size we expected
senorblanco91c395a2014-09-25 15:51:35 -0700228 if (!buffer.validate(unpackedSize == count*256)) {
reed9fa60da2014-08-21 07:59:51 -0700229 return NULL;
230 }
231
232 const uint8_t* a = NULL;
233 const uint8_t* r = NULL;
234 const uint8_t* g = NULL;
235 const uint8_t* b = NULL;
236 const uint8_t* ptr = unpackedStorage;
237
238 if (flags & kA_Flag) {
239 a = ptr;
240 ptr += 256;
241 }
242 if (flags & kR_Flag) {
243 r = ptr;
244 ptr += 256;
245 }
246 if (flags & kG_Flag) {
247 g = ptr;
248 ptr += 256;
249 }
250 if (flags & kB_Flag) {
251 b = ptr;
252 ptr += 256;
253 }
254 return SkTableColorFilter::CreateARGB(a, r, g, b);
255}
256
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000257bool SkTable_ColorFilter::asComponentTable(SkBitmap* table) const {
mike@reedtribe.orgf23f5f72012-01-07 03:48:45 +0000258 if (table) {
259 if (NULL == fBitmap) {
halcanary385fe4d2015-08-26 13:07:48 -0700260 SkBitmap* bmp = new SkBitmap;
reed@google.com9ebcac52014-01-24 18:53:42 +0000261 bmp->allocPixels(SkImageInfo::MakeA8(256, 4));
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000262 uint8_t* bitmapPixels = bmp->getAddr8(0, 0);
twiz@google.com58071162012-07-18 21:41:50 +0000263 int offset = 0;
264 static const unsigned kFlags[] = { kA_Flag, kR_Flag, kG_Flag, kB_Flag };
265
266 for (int x = 0; x < 4; ++x) {
267 if (!(fFlags & kFlags[x])) {
268 memcpy(bitmapPixels, gIdentityTable, sizeof(gIdentityTable));
269 } else {
270 memcpy(bitmapPixels, fStorage + offset, 256);
271 offset += 256;
272 }
273 bitmapPixels += 256;
274 }
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000275 fBitmap = bmp;
mike@reedtribe.orgf23f5f72012-01-07 03:48:45 +0000276 }
277 *table = *fBitmap;
278 }
279 return true;
280}
281
reed8a8d8412015-03-02 13:46:03 -0800282// Combines the two lookup tables so that making a lookup using res[] has
283// the same effect as making a lookup through inner[] then outer[].
284static void combine_tables(uint8_t res[256], const uint8_t outer[256], const uint8_t inner[256]) {
285 for (int i = 0; i < 256; i++) {
286 res[i] = outer[inner[i]];
287 }
288}
289
290SkColorFilter* SkTable_ColorFilter::newComposed(const SkColorFilter* innerFilter) const {
291 SkBitmap innerBM;
292 if (!innerFilter->asComponentTable(&innerBM)) {
293 return NULL;
294 }
295
296 innerBM.lockPixels();
297 if (NULL == innerBM.getPixels()) {
298 return NULL;
299 }
300
301 const uint8_t* table = fStorage;
302 const uint8_t* tableA = gIdentityTable;
303 const uint8_t* tableR = gIdentityTable;
304 const uint8_t* tableG = gIdentityTable;
305 const uint8_t* tableB = gIdentityTable;
306 if (fFlags & kA_Flag) {
307 tableA = table; table += 256;
308 }
309 if (fFlags & kR_Flag) {
310 tableR = table; table += 256;
311 }
312 if (fFlags & kG_Flag) {
313 tableG = table; table += 256;
314 }
315 if (fFlags & kB_Flag) {
316 tableB = table;
317 }
318
319 uint8_t concatA[256];
320 uint8_t concatR[256];
321 uint8_t concatG[256];
322 uint8_t concatB[256];
323
324 combine_tables(concatA, tableA, innerBM.getAddr8(0, 0));
325 combine_tables(concatR, tableR, innerBM.getAddr8(0, 1));
326 combine_tables(concatG, tableG, innerBM.getAddr8(0, 2));
327 combine_tables(concatB, tableB, innerBM.getAddr8(0, 3));
328
329 return SkTableColorFilter::CreateARGB(concatA, concatR, concatG, concatB);
330}
331
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000332#if SK_SUPPORT_GPU
333
bsalomon6251d172014-10-15 10:50:36 -0700334#include "GrFragmentProcessor.h"
egdaniel605dd0f2014-11-12 08:35:25 -0800335#include "GrInvariantOutput.h"
bsalomonc6327a82014-10-27 12:53:08 -0700336#include "SkGr.h"
337#include "effects/GrTextureStripAtlas.h"
wangyix6af0c932015-07-22 10:21:17 -0700338#include "gl/GrGLFragmentProcessor.h"
joshualitt30ba4362014-08-21 20:18:45 -0700339#include "gl/builders/GrGLProgramBuilder.h"
bsalomonc6327a82014-10-27 12:53:08 -0700340
joshualittb0a8a372014-09-23 09:50:21 -0700341class ColorTableEffect : public GrFragmentProcessor {
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000342public:
bsalomonc6327a82014-10-27 12:53:08 -0700343 static GrFragmentProcessor* Create(GrContext* context, SkBitmap bitmap, unsigned flags);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000344
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000345 virtual ~ColorTableEffect();
346
mtklein36352bf2015-03-25 18:17:31 -0700347 const char* name() const override { return "ColorTable"; }
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000348
bsalomonc6327a82014-10-27 12:53:08 -0700349 const GrTextureStripAtlas* atlas() const { return fAtlas; }
350 int atlasRow() const { return fRow; }
351
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000352private:
wangyixb1daa862015-08-18 11:29:31 -0700353 GrGLFragmentProcessor* onCreateGLInstance() const override;
354
wangyix4b3050b2015-08-04 07:59:37 -0700355 void onGetGLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
356
mtklein36352bf2015-03-25 18:17:31 -0700357 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000358
mtklein36352bf2015-03-25 18:17:31 -0700359 void onComputeInvariantOutput(GrInvariantOutput* inout) const override;
egdaniel1a8ecdf2014-10-03 06:24:12 -0700360
bsalomonc6327a82014-10-27 12:53:08 -0700361 ColorTableEffect(GrTexture* texture, GrTextureStripAtlas* atlas, int row, unsigned flags);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000362
joshualittb0a8a372014-09-23 09:50:21 -0700363 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000364
bsalomonc6327a82014-10-27 12:53:08 -0700365 GrTextureAccess fTextureAccess;
366
367 // currently not used in shader code, just to assist onComputeInvariantOutput().
mtklein3f3b3d02014-12-01 11:47:08 -0800368 unsigned fFlags;
bsalomonc6327a82014-10-27 12:53:08 -0700369
370 GrTextureStripAtlas* fAtlas;
371 int fRow;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000372
joshualittb0a8a372014-09-23 09:50:21 -0700373 typedef GrFragmentProcessor INHERITED;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000374};
375
joshualittb0a8a372014-09-23 09:50:21 -0700376class GLColorTableEffect : public GrGLFragmentProcessor {
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000377public:
joshualitteb2a6762014-12-04 11:35:33 -0800378 GLColorTableEffect(const GrProcessor&);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000379
wangyix7c157a92015-07-22 15:08:53 -0700380 virtual void emitCode(EmitArgs&) override;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000381
jvanverthcfc18862015-04-28 08:48:20 -0700382 static void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder* b) {}
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000383
wangyixb1daa862015-08-18 11:29:31 -0700384protected:
385 void onSetData(const GrGLProgramDataManager&, const GrProcessor&) override;
386
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000387private:
bsalomonc6327a82014-10-27 12:53:08 -0700388 UniformHandle fRGBAYValuesUni;
joshualittb0a8a372014-09-23 09:50:21 -0700389 typedef GrGLFragmentProcessor INHERITED;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000390};
391
joshualitteb2a6762014-12-04 11:35:33 -0800392GLColorTableEffect::GLColorTableEffect(const GrProcessor&) {
393}
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000394
wangyixb1daa862015-08-18 11:29:31 -0700395void GLColorTableEffect::onSetData(const GrGLProgramDataManager& pdm, const GrProcessor& proc) {
bsalomonc6327a82014-10-27 12:53:08 -0700396 // The textures are organized in a strip where the rows are ordered a, r, g, b.
397 float rgbaYValues[4];
398 const ColorTableEffect& cte = proc.cast<ColorTableEffect>();
399 if (cte.atlas()) {
400 SkScalar yDelta = cte.atlas()->getNormalizedTexelHeight();
401 rgbaYValues[3] = cte.atlas()->getYOffset(cte.atlasRow()) + SK_ScalarHalf * yDelta;
402 rgbaYValues[0] = rgbaYValues[3] + yDelta;
403 rgbaYValues[1] = rgbaYValues[0] + yDelta;
404 rgbaYValues[2] = rgbaYValues[1] + yDelta;
405 } else {
406 rgbaYValues[3] = 0.125;
407 rgbaYValues[0] = 0.375;
408 rgbaYValues[1] = 0.625;
mtklein3f3b3d02014-12-01 11:47:08 -0800409 rgbaYValues[2] = 0.875;
bsalomonc6327a82014-10-27 12:53:08 -0700410 }
411 pdm.set4fv(fRGBAYValuesUni, 1, rgbaYValues);
412}
413
wangyix7c157a92015-07-22 15:08:53 -0700414void GLColorTableEffect::emitCode(EmitArgs& args) {
bsalomonc6327a82014-10-27 12:53:08 -0700415 const char* yoffsets;
wangyix7c157a92015-07-22 15:08:53 -0700416 fRGBAYValuesUni = args.fBuilder->addUniform(GrGLFPBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -0800417 kVec4f_GrSLType, kDefault_GrSLPrecision,
418 "yoffsets", &yoffsets);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000419 static const float kColorScaleFactor = 255.0f / 256.0f;
420 static const float kColorOffsetFactor = 1.0f / 512.0f;
wangyix7c157a92015-07-22 15:08:53 -0700421 GrGLFragmentBuilder* fsBuilder = args.fBuilder->getFragmentShaderBuilder();
422 if (NULL == args.fInputColor) {
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000423 // the input color is solid white (all ones).
424 static const float kMaxValue = kColorScaleFactor + kColorOffsetFactor;
joshualitt30ba4362014-08-21 20:18:45 -0700425 fsBuilder->codeAppendf("\t\tvec4 coord = vec4(%f, %f, %f, %f);\n",
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000426 kMaxValue, kMaxValue, kMaxValue, kMaxValue);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000427
428 } else {
wangyix7c157a92015-07-22 15:08:53 -0700429 fsBuilder->codeAppendf("\t\tfloat nonZeroAlpha = max(%s.a, .0001);\n", args.fInputColor);
430 fsBuilder->codeAppendf("\t\tvec4 coord = vec4(%s.rgb / nonZeroAlpha, nonZeroAlpha);\n",
431 args.fInputColor);
joshualitt30ba4362014-08-21 20:18:45 -0700432 fsBuilder->codeAppendf("\t\tcoord = coord * %f + vec4(%f, %f, %f, %f);\n",
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000433 kColorScaleFactor,
434 kColorOffsetFactor, kColorOffsetFactor,
435 kColorOffsetFactor, kColorOffsetFactor);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000436 }
437
bsalomonc6327a82014-10-27 12:53:08 -0700438 SkString coord;
439
wangyix7c157a92015-07-22 15:08:53 -0700440 fsBuilder->codeAppendf("\t\t%s.a = ", args.fOutputColor);
bsalomonc6327a82014-10-27 12:53:08 -0700441 coord.printf("vec2(coord.a, %s.a)", yoffsets);
wangyix7c157a92015-07-22 15:08:53 -0700442 fsBuilder->appendTextureLookup(args.fSamplers[0], coord.c_str());
joshualitt30ba4362014-08-21 20:18:45 -0700443 fsBuilder->codeAppend(";\n");
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000444
wangyix7c157a92015-07-22 15:08:53 -0700445 fsBuilder->codeAppendf("\t\t%s.r = ", args.fOutputColor);
bsalomonc6327a82014-10-27 12:53:08 -0700446 coord.printf("vec2(coord.r, %s.r)", yoffsets);
wangyix7c157a92015-07-22 15:08:53 -0700447 fsBuilder->appendTextureLookup(args.fSamplers[0], coord.c_str());
joshualitt30ba4362014-08-21 20:18:45 -0700448 fsBuilder->codeAppend(";\n");
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000449
wangyix7c157a92015-07-22 15:08:53 -0700450 fsBuilder->codeAppendf("\t\t%s.g = ", args.fOutputColor);
bsalomonc6327a82014-10-27 12:53:08 -0700451 coord.printf("vec2(coord.g, %s.g)", yoffsets);
wangyix7c157a92015-07-22 15:08:53 -0700452 fsBuilder->appendTextureLookup(args.fSamplers[0], coord.c_str());
joshualitt30ba4362014-08-21 20:18:45 -0700453 fsBuilder->codeAppend(";\n");
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000454
wangyix7c157a92015-07-22 15:08:53 -0700455 fsBuilder->codeAppendf("\t\t%s.b = ", args.fOutputColor);
bsalomonc6327a82014-10-27 12:53:08 -0700456 coord.printf("vec2(coord.b, %s.b)", yoffsets);
wangyix7c157a92015-07-22 15:08:53 -0700457 fsBuilder->appendTextureLookup(args.fSamplers[0], coord.c_str());
joshualitt30ba4362014-08-21 20:18:45 -0700458 fsBuilder->codeAppend(";\n");
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000459
wangyix7c157a92015-07-22 15:08:53 -0700460 fsBuilder->codeAppendf("\t\t%s.rgb *= %s.a;\n", args.fOutputColor, args.fOutputColor);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000461}
462
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000463///////////////////////////////////////////////////////////////////////////////
bsalomonc6327a82014-10-27 12:53:08 -0700464GrFragmentProcessor* ColorTableEffect::Create(GrContext* context, SkBitmap bitmap, unsigned flags) {
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000465
bsalomonc6327a82014-10-27 12:53:08 -0700466 GrTextureStripAtlas::Desc desc;
467 desc.fWidth = bitmap.width();
468 desc.fHeight = 128;
469 desc.fRowHeight = bitmap.height();
470 desc.fContext = context;
471 desc.fConfig = SkImageInfo2GrPixelConfig(bitmap.info());
472 GrTextureStripAtlas* atlas = GrTextureStripAtlas::GetAtlas(desc);
473 int row = atlas->lockRow(bitmap);
474 SkAutoTUnref<GrTexture> texture;
475 if (-1 == row) {
476 atlas = NULL;
477 // Passing params=NULL because this effect does no tiling or filtering.
478 texture.reset(GrRefCachedBitmapTexture(context, bitmap, NULL));
479 } else {
480 texture.reset(SkRef(atlas->getTexture()));
481 }
482
halcanary385fe4d2015-08-26 13:07:48 -0700483 return new ColorTableEffect(texture, atlas, row, flags);
bsalomonc6327a82014-10-27 12:53:08 -0700484}
485
486ColorTableEffect::ColorTableEffect(GrTexture* texture, GrTextureStripAtlas* atlas, int row,
487 unsigned flags)
bsalomon@google.com371e1052013-01-11 21:08:55 +0000488 : fTextureAccess(texture, "a")
bsalomonc6327a82014-10-27 12:53:08 -0700489 , fFlags(flags)
490 , fAtlas(atlas)
491 , fRow(row) {
joshualitteb2a6762014-12-04 11:35:33 -0800492 this->initClassID<ColorTableEffect>();
bsalomon@google.com50db75c2013-01-11 13:54:30 +0000493 this->addTextureAccess(&fTextureAccess);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000494}
495
496ColorTableEffect::~ColorTableEffect() {
bsalomonc6327a82014-10-27 12:53:08 -0700497 if (fAtlas) {
498 fAtlas->unlockRow(fRow);
499 }
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000500}
501
wangyix4b3050b2015-08-04 07:59:37 -0700502void ColorTableEffect::onGetGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -0800503 GrProcessorKeyBuilder* b) const {
504 GLColorTableEffect::GenKey(*this, caps, b);
505}
506
wangyixb1daa862015-08-18 11:29:31 -0700507GrGLFragmentProcessor* ColorTableEffect::onCreateGLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -0700508 return new GLColorTableEffect(*this);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000509}
510
bsalomonc6327a82014-10-27 12:53:08 -0700511bool ColorTableEffect::onIsEqual(const GrFragmentProcessor& other) const {
512 // For non-atlased instances, the texture (compared by base class) is sufficient to
513 // differentiate different tables. For atlased instances we ensure they are using the
514 // same row.
515 const ColorTableEffect& that = other.cast<ColorTableEffect>();
516 SkASSERT(SkToBool(fAtlas) == SkToBool(that.fAtlas));
517 // Ok to always do this comparison since both would be -1 if non-atlased.
518 return fRow == that.fRow;
519}
520
egdaniel605dd0f2014-11-12 08:35:25 -0800521void ColorTableEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
bsalomon@google.com371e1052013-01-11 21:08:55 +0000522 // If we kept the table in the effect then we could actually run known inputs through the
523 // table.
egdanielccb2e382014-10-13 12:53:46 -0700524 uint8_t invalidateFlags = 0;
bsalomon@google.com371e1052013-01-11 21:08:55 +0000525 if (fFlags & SkTable_ColorFilter::kR_Flag) {
egdanielccb2e382014-10-13 12:53:46 -0700526 invalidateFlags |= kR_GrColorComponentFlag;
bsalomon@google.com371e1052013-01-11 21:08:55 +0000527 }
528 if (fFlags & SkTable_ColorFilter::kG_Flag) {
egdanielccb2e382014-10-13 12:53:46 -0700529 invalidateFlags |= kG_GrColorComponentFlag;
bsalomon@google.com371e1052013-01-11 21:08:55 +0000530 }
531 if (fFlags & SkTable_ColorFilter::kB_Flag) {
egdanielccb2e382014-10-13 12:53:46 -0700532 invalidateFlags |= kB_GrColorComponentFlag;
bsalomon@google.com371e1052013-01-11 21:08:55 +0000533 }
534 if (fFlags & SkTable_ColorFilter::kA_Flag) {
egdanielccb2e382014-10-13 12:53:46 -0700535 invalidateFlags |= kA_GrColorComponentFlag;
bsalomon@google.com371e1052013-01-11 21:08:55 +0000536 }
egdaniel605dd0f2014-11-12 08:35:25 -0800537 inout->invalidateComponents(invalidateFlags, GrInvariantOutput::kWill_ReadInput);
bsalomon@google.com371e1052013-01-11 21:08:55 +0000538}
539
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000540///////////////////////////////////////////////////////////////////////////////
541
joshualittb0a8a372014-09-23 09:50:21 -0700542GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ColorTableEffect);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000543
joshualitt0067ff52015-07-08 14:26:19 -0700544GrFragmentProcessor* ColorTableEffect::TestCreate(GrProcessorTestData* d) {
bsalomonc6327a82014-10-27 12:53:08 -0700545 int flags = 0;
546 uint8_t luts[256][4];
547 do {
548 for (int i = 0; i < 4; ++i) {
joshualitt0067ff52015-07-08 14:26:19 -0700549 flags |= d->fRandom->nextBool() ? (1 << i): 0;
bsalomonc6327a82014-10-27 12:53:08 -0700550 }
551 } while (!flags);
552 for (int i = 0; i < 4; ++i) {
553 if (flags & (1 << i)) {
554 for (int j = 0; j < 256; ++j) {
joshualitt0067ff52015-07-08 14:26:19 -0700555 luts[j][i] = SkToU8(d->fRandom->nextBits(8));
bsalomonc6327a82014-10-27 12:53:08 -0700556 }
557 }
558 }
559 SkAutoTUnref<SkColorFilter> filter(SkTableColorFilter::CreateARGB(
560 (flags & (1 << 0)) ? luts[0] : NULL,
561 (flags & (1 << 1)) ? luts[1] : NULL,
562 (flags & (1 << 2)) ? luts[2] : NULL,
563 (flags & (1 << 3)) ? luts[3] : NULL
564 ));
reedcff10b22015-03-03 06:41:45 -0800565
566 SkTDArray<GrFragmentProcessor*> array;
joshualitt9cc17752015-07-09 06:28:14 -0700567 if (filter->asFragmentProcessors(d->fContext, d->fProcDataManager, &array)) {
reedcff10b22015-03-03 06:41:45 -0800568 SkASSERT(1 == array.count()); // TableColorFilter only returns 1
569 return array[0];
570 }
571 return NULL;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000572}
573
reedcff10b22015-03-03 06:41:45 -0800574bool SkTable_ColorFilter::asFragmentProcessors(GrContext* context,
joshualitt9cc17752015-07-09 06:28:14 -0700575 GrProcessorDataManager*,
reedcff10b22015-03-03 06:41:45 -0800576 SkTDArray<GrFragmentProcessor*>* array) const {
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000577 SkBitmap bitmap;
578 this->asComponentTable(&bitmap);
bsalomonc6327a82014-10-27 12:53:08 -0700579
reedcff10b22015-03-03 06:41:45 -0800580 GrFragmentProcessor* frag = ColorTableEffect::Create(context, bitmap, fFlags);
581 if (frag) {
582 if (array) {
583 *array->append() = frag;
bsalomona0f1a182015-06-12 08:32:52 -0700584 } else {
585 frag->unref();
586 SkDEBUGCODE(frag = NULL;)
reedcff10b22015-03-03 06:41:45 -0800587 }
588 return true;
589 }
590 return false;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000591}
592
593#endif // SK_SUPPORT_GPU
594
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000595///////////////////////////////////////////////////////////////////////////////
596
597#ifdef SK_CPU_BENDIAN
598#else
599 #define SK_A32_INDEX (3 - (SK_A32_SHIFT >> 3))
600 #define SK_R32_INDEX (3 - (SK_R32_SHIFT >> 3))
601 #define SK_G32_INDEX (3 - (SK_G32_SHIFT >> 3))
602 #define SK_B32_INDEX (3 - (SK_B32_SHIFT >> 3))
603#endif
604
605///////////////////////////////////////////////////////////////////////////////
606
607SkColorFilter* SkTableColorFilter::Create(const uint8_t table[256]) {
halcanary385fe4d2015-08-26 13:07:48 -0700608 return new SkTable_ColorFilter(table, table, table, table);
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000609}
610
611SkColorFilter* SkTableColorFilter::CreateARGB(const uint8_t tableA[256],
612 const uint8_t tableR[256],
613 const uint8_t tableG[256],
614 const uint8_t tableB[256]) {
halcanary385fe4d2015-08-26 13:07:48 -0700615 return new SkTable_ColorFilter(tableA, tableR, tableG, tableB);
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000616}
djsollen@google.coma2ca41e2012-03-23 19:00:34 +0000617
618SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkTableColorFilter)
619 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkTable_ColorFilter)
620SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END