blob: ebf646b99968a6f48657de520feb0bf299b9aaac [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
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +00008#include "SkTableColorFilter.h"
bsalomonf276ac52015-10-09 13:36:42 -07009
10#include "SkBitmap.h"
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000011#include "SkColorPriv.h"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000012#include "SkReadBuffer.h"
robertphillips@google.com1202c2a2013-05-23 14:00:17 +000013#include "SkString.h"
bsalomonf276ac52015-10-09 13:36:42 -070014#include "SkUnPreMultiply.h"
15#include "SkWriteBuffer.h"
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +000016
17class SkTable_ColorFilter : public SkColorFilter {
18public:
19 SkTable_ColorFilter(const uint8_t tableA[], const uint8_t tableR[],
20 const uint8_t tableG[], const uint8_t tableB[]) {
halcanary96fcdcc2015-08-27 07:41:13 -070021 fBitmap = nullptr;
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +000022 fFlags = 0;
mike@reedtribe.orgf23f5f72012-01-07 03:48:45 +000023
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +000024 uint8_t* dst = fStorage;
25 if (tableA) {
26 memcpy(dst, tableA, 256);
27 dst += 256;
28 fFlags |= kA_Flag;
29 }
30 if (tableR) {
31 memcpy(dst, tableR, 256);
32 dst += 256;
33 fFlags |= kR_Flag;
34 }
35 if (tableG) {
36 memcpy(dst, tableG, 256);
37 dst += 256;
38 fFlags |= kG_Flag;
39 }
40 if (tableB) {
41 memcpy(dst, tableB, 256);
42 fFlags |= kB_Flag;
43 }
44 }
45
halcanary385fe4d2015-08-26 13:07:48 -070046 virtual ~SkTable_ColorFilter() { delete fBitmap; }
tomhudson@google.com1bb4be22012-07-24 17:24:21 +000047
mtklein36352bf2015-03-25 18:17:31 -070048 bool asComponentTable(SkBitmap* table) const override;
reedd053ce92016-03-22 10:17:23 -070049 sk_sp<SkColorFilter> makeComposed(sk_sp<SkColorFilter> inner) const override;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +000050
51#if SK_SUPPORT_GPU
bungeman06ca8ec2016-06-09 08:01:03 -070052 sk_sp<GrFragmentProcessor> asFragmentProcessor(GrContext*) 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
reed60c9b582016-04-03 09:11:13 -0700210sk_sp<SkFlattenable> SkTable_ColorFilter::CreateProc(SkReadBuffer& buffer) {
reed9fa60da2014-08-21 07:59:51 -0700211 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))) {
halcanary96fcdcc2015-08-27 07:41:13 -0700218 return nullptr;
reed9fa60da2014-08-21 07:59:51 -0700219 }
220 if (!buffer.readByteArray(packedStorage, packedSize)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700221 return nullptr;
reed9fa60da2014-08-21 07:59:51 -0700222 }
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)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700229 return nullptr;
reed9fa60da2014-08-21 07:59:51 -0700230 }
231
halcanary96fcdcc2015-08-27 07:41:13 -0700232 const uint8_t* a = nullptr;
233 const uint8_t* r = nullptr;
234 const uint8_t* g = nullptr;
235 const uint8_t* b = nullptr;
reed9fa60da2014-08-21 07:59:51 -0700236 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 }
reed60c9b582016-04-03 09:11:13 -0700254 return SkTableColorFilter::MakeARGB(a, r, g, b);
reed9fa60da2014-08-21 07:59:51 -0700255}
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) {
halcanary96fcdcc2015-08-27 07:41:13 -0700259 if (nullptr == 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
reedd053ce92016-03-22 10:17:23 -0700290sk_sp<SkColorFilter> SkTable_ColorFilter::makeComposed(sk_sp<SkColorFilter> innerFilter) const {
reed8a8d8412015-03-02 13:46:03 -0800291 SkBitmap innerBM;
292 if (!innerFilter->asComponentTable(&innerBM)) {
halcanary96fcdcc2015-08-27 07:41:13 -0700293 return nullptr;
reed8a8d8412015-03-02 13:46:03 -0800294 }
295
296 innerBM.lockPixels();
halcanary96fcdcc2015-08-27 07:41:13 -0700297 if (nullptr == innerBM.getPixels()) {
298 return nullptr;
reed8a8d8412015-03-02 13:46:03 -0800299 }
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
reedd053ce92016-03-22 10:17:23 -0700329 return SkTableColorFilter::MakeARGB(concatA, concatR, concatG, concatB);
reed8a8d8412015-03-02 13:46:03 -0800330}
331
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000332#if SK_SUPPORT_GPU
333
brianosmana6359362016-03-21 06:55:37 -0700334#include "GrContext.h"
bsalomon6251d172014-10-15 10:50:36 -0700335#include "GrFragmentProcessor.h"
egdaniel605dd0f2014-11-12 08:35:25 -0800336#include "GrInvariantOutput.h"
ajuma95243eb2016-08-24 08:19:02 -0700337#include "GrTextureStripAtlas.h"
bsalomonc6327a82014-10-27 12:53:08 -0700338#include "SkGr.h"
egdaniel64c47282015-11-13 06:54:19 -0800339#include "glsl/GrGLSLFragmentProcessor.h"
egdaniel2d721d32015-11-11 13:06:05 -0800340#include "glsl/GrGLSLFragmentShaderBuilder.h"
egdaniel018fb622015-10-28 07:26:40 -0700341#include "glsl/GrGLSLProgramDataManager.h"
egdaniel7ea439b2015-12-03 09:20:44 -0800342#include "glsl/GrGLSLUniformHandler.h"
bsalomonc6327a82014-10-27 12:53:08 -0700343
joshualittb0a8a372014-09-23 09:50:21 -0700344class ColorTableEffect : public GrFragmentProcessor {
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000345public:
bungeman06ca8ec2016-06-09 08:01:03 -0700346 static sk_sp<GrFragmentProcessor> Make(GrContext* context, SkBitmap bitmap, unsigned flags);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000347
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000348 virtual ~ColorTableEffect();
349
mtklein36352bf2015-03-25 18:17:31 -0700350 const char* name() const override { return "ColorTable"; }
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000351
bsalomonc6327a82014-10-27 12:53:08 -0700352 const GrTextureStripAtlas* atlas() const { return fAtlas; }
353 int atlasRow() const { return fRow; }
354
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000355private:
egdaniel57d3b032015-11-13 11:57:27 -0800356 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
wangyixb1daa862015-08-18 11:29:31 -0700357
egdaniel57d3b032015-11-13 11:57:27 -0800358 void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
wangyix4b3050b2015-08-04 07:59:37 -0700359
mtklein36352bf2015-03-25 18:17:31 -0700360 bool onIsEqual(const GrFragmentProcessor&) const override;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000361
mtklein36352bf2015-03-25 18:17:31 -0700362 void onComputeInvariantOutput(GrInvariantOutput* inout) const override;
egdaniel1a8ecdf2014-10-03 06:24:12 -0700363
bsalomonc6327a82014-10-27 12:53:08 -0700364 ColorTableEffect(GrTexture* texture, GrTextureStripAtlas* atlas, int row, unsigned flags);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000365
joshualittb0a8a372014-09-23 09:50:21 -0700366 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000367
bsalomonc6327a82014-10-27 12:53:08 -0700368 GrTextureAccess fTextureAccess;
369
370 // currently not used in shader code, just to assist onComputeInvariantOutput().
mtklein3f3b3d02014-12-01 11:47:08 -0800371 unsigned fFlags;
bsalomonc6327a82014-10-27 12:53:08 -0700372
373 GrTextureStripAtlas* fAtlas;
374 int fRow;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000375
joshualittb0a8a372014-09-23 09:50:21 -0700376 typedef GrFragmentProcessor INHERITED;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000377};
378
egdaniel64c47282015-11-13 06:54:19 -0800379class GLColorTableEffect : public GrGLSLFragmentProcessor {
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000380public:
robertphillips9cdb9922016-02-03 12:25:40 -0800381 void emitCode(EmitArgs&) override;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000382
robertphillipsbf536af2016-02-04 06:11:53 -0800383 static void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder*) {}
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000384
wangyixb1daa862015-08-18 11:29:31 -0700385protected:
egdaniel018fb622015-10-28 07:26:40 -0700386 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -0700387
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000388private:
bsalomonc6327a82014-10-27 12:53:08 -0700389 UniformHandle fRGBAYValuesUni;
egdaniel64c47282015-11-13 06:54:19 -0800390 typedef GrGLSLFragmentProcessor INHERITED;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000391};
392
egdaniel018fb622015-10-28 07:26:40 -0700393void GLColorTableEffect::onSetData(const GrGLSLProgramDataManager& pdm, const GrProcessor& proc) {
bsalomonc6327a82014-10-27 12:53:08 -0700394 // 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
wangyix7c157a92015-07-22 15:08:53 -0700412void GLColorTableEffect::emitCode(EmitArgs& args) {
bsalomonc6327a82014-10-27 12:53:08 -0700413 const char* yoffsets;
cdalton5e58cee2016-02-11 12:49:47 -0800414 fRGBAYValuesUni = args.fUniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -0800415 kVec4f_GrSLType, kDefault_GrSLPrecision,
416 "yoffsets", &yoffsets);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000417 static const float kColorScaleFactor = 255.0f / 256.0f;
418 static const float kColorOffsetFactor = 1.0f / 512.0f;
cdalton85285412016-02-18 12:37:07 -0800419 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
halcanary96fcdcc2015-08-27 07:41:13 -0700420 if (nullptr == args.fInputColor) {
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000421 // the input color is solid white (all ones).
422 static const float kMaxValue = kColorScaleFactor + kColorOffsetFactor;
egdaniel4ca2e602015-11-18 08:01:26 -0800423 fragBuilder->codeAppendf("\t\tvec4 coord = vec4(%f, %f, %f, %f);\n",
424 kMaxValue, kMaxValue, kMaxValue, kMaxValue);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000425
426 } else {
egdaniel4ca2e602015-11-18 08:01:26 -0800427 fragBuilder->codeAppendf("\t\tfloat nonZeroAlpha = max(%s.a, .0001);\n", args.fInputColor);
428 fragBuilder->codeAppendf("\t\tvec4 coord = vec4(%s.rgb / nonZeroAlpha, nonZeroAlpha);\n",
429 args.fInputColor);
430 fragBuilder->codeAppendf("\t\tcoord = coord * %f + vec4(%f, %f, %f, %f);\n",
431 kColorScaleFactor,
432 kColorOffsetFactor, kColorOffsetFactor,
433 kColorOffsetFactor, kColorOffsetFactor);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000434 }
435
bsalomonc6327a82014-10-27 12:53:08 -0700436 SkString coord;
437
egdaniel4ca2e602015-11-18 08:01:26 -0800438 fragBuilder->codeAppendf("\t\t%s.a = ", args.fOutputColor);
bsalomonc6327a82014-10-27 12:53:08 -0700439 coord.printf("vec2(coord.a, %s.a)", yoffsets);
cdalton3f6f76f2016-04-11 12:18:09 -0700440 fragBuilder->appendTextureLookup(args.fTexSamplers[0], coord.c_str());
bsalomoncdee0092016-01-08 13:20:12 -0800441 fragBuilder->codeAppend(".a;\n");
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000442
egdaniel4ca2e602015-11-18 08:01:26 -0800443 fragBuilder->codeAppendf("\t\t%s.r = ", args.fOutputColor);
bsalomonc6327a82014-10-27 12:53:08 -0700444 coord.printf("vec2(coord.r, %s.r)", yoffsets);
cdalton3f6f76f2016-04-11 12:18:09 -0700445 fragBuilder->appendTextureLookup(args.fTexSamplers[0], coord.c_str());
bsalomoncdee0092016-01-08 13:20:12 -0800446 fragBuilder->codeAppend(".a;\n");
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000447
egdaniel4ca2e602015-11-18 08:01:26 -0800448 fragBuilder->codeAppendf("\t\t%s.g = ", args.fOutputColor);
bsalomonc6327a82014-10-27 12:53:08 -0700449 coord.printf("vec2(coord.g, %s.g)", yoffsets);
cdalton3f6f76f2016-04-11 12:18:09 -0700450 fragBuilder->appendTextureLookup(args.fTexSamplers[0], coord.c_str());
bsalomoncdee0092016-01-08 13:20:12 -0800451 fragBuilder->codeAppend(".a;\n");
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000452
egdaniel4ca2e602015-11-18 08:01:26 -0800453 fragBuilder->codeAppendf("\t\t%s.b = ", args.fOutputColor);
bsalomonc6327a82014-10-27 12:53:08 -0700454 coord.printf("vec2(coord.b, %s.b)", yoffsets);
cdalton3f6f76f2016-04-11 12:18:09 -0700455 fragBuilder->appendTextureLookup(args.fTexSamplers[0], coord.c_str());
bsalomoncdee0092016-01-08 13:20:12 -0800456 fragBuilder->codeAppend(".a;\n");
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000457
egdaniel4ca2e602015-11-18 08:01:26 -0800458 fragBuilder->codeAppendf("\t\t%s.rgb *= %s.a;\n", args.fOutputColor, args.fOutputColor);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000459}
460
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000461///////////////////////////////////////////////////////////////////////////////
bungeman06ca8ec2016-06-09 08:01:03 -0700462sk_sp<GrFragmentProcessor> ColorTableEffect::Make(GrContext* context, SkBitmap bitmap,
463 unsigned flags) {
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000464
bsalomonc6327a82014-10-27 12:53:08 -0700465 GrTextureStripAtlas::Desc desc;
466 desc.fWidth = bitmap.width();
467 desc.fHeight = 128;
468 desc.fRowHeight = bitmap.height();
469 desc.fContext = context;
brianosmana6359362016-03-21 06:55:37 -0700470 desc.fConfig = SkImageInfo2GrPixelConfig(bitmap.info(), *context->caps());
bsalomonc6327a82014-10-27 12:53:08 -0700471 GrTextureStripAtlas* atlas = GrTextureStripAtlas::GetAtlas(desc);
472 int row = atlas->lockRow(bitmap);
473 SkAutoTUnref<GrTexture> texture;
474 if (-1 == row) {
halcanary96fcdcc2015-08-27 07:41:13 -0700475 atlas = nullptr;
brianosman982eb7f2016-06-06 13:10:58 -0700476 texture.reset(GrRefCachedBitmapTexture(context, bitmap, GrTextureParams::ClampNoFilter(),
477 SkSourceGammaTreatment::kRespect));
bsalomonc6327a82014-10-27 12:53:08 -0700478 } else {
479 texture.reset(SkRef(atlas->getTexture()));
480 }
481
bungeman06ca8ec2016-06-09 08:01:03 -0700482 return sk_sp<GrFragmentProcessor>(new ColorTableEffect(texture, atlas, row, flags));
bsalomonc6327a82014-10-27 12:53:08 -0700483}
484
485ColorTableEffect::ColorTableEffect(GrTexture* texture, GrTextureStripAtlas* atlas, int row,
486 unsigned flags)
bsalomoncdee0092016-01-08 13:20:12 -0800487 : fTextureAccess(texture)
bsalomonc6327a82014-10-27 12:53:08 -0700488 , fFlags(flags)
489 , fAtlas(atlas)
490 , fRow(row) {
joshualitteb2a6762014-12-04 11:35:33 -0800491 this->initClassID<ColorTableEffect>();
bsalomon@google.com50db75c2013-01-11 13:54:30 +0000492 this->addTextureAccess(&fTextureAccess);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000493}
494
495ColorTableEffect::~ColorTableEffect() {
bsalomonc6327a82014-10-27 12:53:08 -0700496 if (fAtlas) {
497 fAtlas->unlockRow(fRow);
498 }
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000499}
500
egdaniel57d3b032015-11-13 11:57:27 -0800501void ColorTableEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps,
502 GrProcessorKeyBuilder* b) const {
joshualitteb2a6762014-12-04 11:35:33 -0800503 GLColorTableEffect::GenKey(*this, caps, b);
504}
505
egdaniel57d3b032015-11-13 11:57:27 -0800506GrGLSLFragmentProcessor* ColorTableEffect::onCreateGLSLInstance() const {
robertphillips9cdb9922016-02-03 12:25:40 -0800507 return new GLColorTableEffect;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000508}
509
bsalomonc6327a82014-10-27 12:53:08 -0700510bool ColorTableEffect::onIsEqual(const GrFragmentProcessor& other) const {
511 // For non-atlased instances, the texture (compared by base class) is sufficient to
512 // differentiate different tables. For atlased instances we ensure they are using the
513 // same row.
514 const ColorTableEffect& that = other.cast<ColorTableEffect>();
515 SkASSERT(SkToBool(fAtlas) == SkToBool(that.fAtlas));
516 // Ok to always do this comparison since both would be -1 if non-atlased.
517 return fRow == that.fRow;
518}
519
egdaniel605dd0f2014-11-12 08:35:25 -0800520void ColorTableEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
bsalomon@google.com371e1052013-01-11 21:08:55 +0000521 // If we kept the table in the effect then we could actually run known inputs through the
522 // table.
bsalomonae4738f2015-09-15 15:33:27 -0700523 GrColorComponentFlags invalidateFlags = kNone_GrColorComponentFlags;
bsalomon@google.com371e1052013-01-11 21:08:55 +0000524 if (fFlags & SkTable_ColorFilter::kR_Flag) {
egdanielccb2e382014-10-13 12:53:46 -0700525 invalidateFlags |= kR_GrColorComponentFlag;
bsalomon@google.com371e1052013-01-11 21:08:55 +0000526 }
527 if (fFlags & SkTable_ColorFilter::kG_Flag) {
egdanielccb2e382014-10-13 12:53:46 -0700528 invalidateFlags |= kG_GrColorComponentFlag;
bsalomon@google.com371e1052013-01-11 21:08:55 +0000529 }
530 if (fFlags & SkTable_ColorFilter::kB_Flag) {
egdanielccb2e382014-10-13 12:53:46 -0700531 invalidateFlags |= kB_GrColorComponentFlag;
bsalomon@google.com371e1052013-01-11 21:08:55 +0000532 }
533 if (fFlags & SkTable_ColorFilter::kA_Flag) {
egdanielccb2e382014-10-13 12:53:46 -0700534 invalidateFlags |= kA_GrColorComponentFlag;
bsalomon@google.com371e1052013-01-11 21:08:55 +0000535 }
egdaniel605dd0f2014-11-12 08:35:25 -0800536 inout->invalidateComponents(invalidateFlags, GrInvariantOutput::kWill_ReadInput);
bsalomon@google.com371e1052013-01-11 21:08:55 +0000537}
538
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000539///////////////////////////////////////////////////////////////////////////////
540
joshualittb0a8a372014-09-23 09:50:21 -0700541GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ColorTableEffect);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000542
bungeman06ca8ec2016-06-09 08:01:03 -0700543sk_sp<GrFragmentProcessor> ColorTableEffect::TestCreate(GrProcessorTestData* d) {
bsalomonc6327a82014-10-27 12:53:08 -0700544 int flags = 0;
545 uint8_t luts[256][4];
546 do {
547 for (int i = 0; i < 4; ++i) {
joshualitt0067ff52015-07-08 14:26:19 -0700548 flags |= d->fRandom->nextBool() ? (1 << i): 0;
bsalomonc6327a82014-10-27 12:53:08 -0700549 }
550 } while (!flags);
551 for (int i = 0; i < 4; ++i) {
552 if (flags & (1 << i)) {
553 for (int j = 0; j < 256; ++j) {
joshualitt0067ff52015-07-08 14:26:19 -0700554 luts[j][i] = SkToU8(d->fRandom->nextBits(8));
bsalomonc6327a82014-10-27 12:53:08 -0700555 }
556 }
557 }
reedd053ce92016-03-22 10:17:23 -0700558 auto filter(SkTableColorFilter::MakeARGB(
halcanary96fcdcc2015-08-27 07:41:13 -0700559 (flags & (1 << 0)) ? luts[0] : nullptr,
560 (flags & (1 << 1)) ? luts[1] : nullptr,
561 (flags & (1 << 2)) ? luts[2] : nullptr,
562 (flags & (1 << 3)) ? luts[3] : nullptr
bsalomonc6327a82014-10-27 12:53:08 -0700563 ));
reedcff10b22015-03-03 06:41:45 -0800564
bungeman06ca8ec2016-06-09 08:01:03 -0700565 sk_sp<GrFragmentProcessor> fp = filter->asFragmentProcessor(d->fContext);
bsalomone25eea42015-09-29 06:38:55 -0700566 SkASSERT(fp);
567 return fp;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000568}
569
bungeman06ca8ec2016-06-09 08:01:03 -0700570sk_sp<GrFragmentProcessor> SkTable_ColorFilter::asFragmentProcessor(GrContext* context) const {
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000571 SkBitmap bitmap;
572 this->asComponentTable(&bitmap);
bsalomonc6327a82014-10-27 12:53:08 -0700573
bungeman06ca8ec2016-06-09 08:01:03 -0700574 return ColorTableEffect::Make(context, bitmap, fFlags);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000575}
576
577#endif // SK_SUPPORT_GPU
578
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000579///////////////////////////////////////////////////////////////////////////////
580
581#ifdef SK_CPU_BENDIAN
582#else
583 #define SK_A32_INDEX (3 - (SK_A32_SHIFT >> 3))
584 #define SK_R32_INDEX (3 - (SK_R32_SHIFT >> 3))
585 #define SK_G32_INDEX (3 - (SK_G32_SHIFT >> 3))
586 #define SK_B32_INDEX (3 - (SK_B32_SHIFT >> 3))
587#endif
588
589///////////////////////////////////////////////////////////////////////////////
590
reedd053ce92016-03-22 10:17:23 -0700591sk_sp<SkColorFilter> SkTableColorFilter::Make(const uint8_t table[256]) {
592 return sk_make_sp<SkTable_ColorFilter>(table, table, table, table);
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000593}
594
reedd053ce92016-03-22 10:17:23 -0700595sk_sp<SkColorFilter> SkTableColorFilter::MakeARGB(const uint8_t tableA[256],
596 const uint8_t tableR[256],
597 const uint8_t tableG[256],
598 const uint8_t tableB[256]) {
599 return sk_make_sp<SkTable_ColorFilter>(tableA, tableR, tableG, tableB);
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000600}
djsollen@google.coma2ca41e2012-03-23 19:00:34 +0000601
602SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkTableColorFilter)
603 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkTable_ColorFilter)
604SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END