blob: 7cd628fd2d08b3ba35071777a75b9073ab450566 [file] [log] [blame]
djsollen@google.comc73dd5c2012-08-07 15:54:32 +00001
reed@google.com02f65f22012-08-06 21:20:05 +00002#include "SkBitmap.h"
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +00003#include "SkTableColorFilter.h"
djsollen@google.comc73dd5c2012-08-07 15:54:32 +00004#include "SkColorPriv.h"
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +00005#include "SkReadBuffer.h"
6#include "SkWriteBuffer.h"
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +00007#include "SkUnPreMultiply.h"
robertphillips@google.com1202c2a2013-05-23 14:00:17 +00008#include "SkString.h"
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +00009
10class SkTable_ColorFilter : public SkColorFilter {
11public:
12 SkTable_ColorFilter(const uint8_t tableA[], const uint8_t tableR[],
13 const uint8_t tableG[], const uint8_t tableB[]) {
mike@reedtribe.orgf23f5f72012-01-07 03:48:45 +000014 fBitmap = NULL;
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +000015 fFlags = 0;
mike@reedtribe.orgf23f5f72012-01-07 03:48:45 +000016
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +000017 uint8_t* dst = fStorage;
18 if (tableA) {
19 memcpy(dst, tableA, 256);
20 dst += 256;
21 fFlags |= kA_Flag;
22 }
23 if (tableR) {
24 memcpy(dst, tableR, 256);
25 dst += 256;
26 fFlags |= kR_Flag;
27 }
28 if (tableG) {
29 memcpy(dst, tableG, 256);
30 dst += 256;
31 fFlags |= kG_Flag;
32 }
33 if (tableB) {
34 memcpy(dst, tableB, 256);
35 fFlags |= kB_Flag;
36 }
37 }
38
tomhudson@google.com1bb4be22012-07-24 17:24:21 +000039 virtual ~SkTable_ColorFilter() {
40 SkDELETE(fBitmap);
41 }
42
bsalomon@google.comb2ad1012012-10-17 15:00:32 +000043 virtual bool asComponentTable(SkBitmap* table) const SK_OVERRIDE;
44
45#if SK_SUPPORT_GPU
joshualittb0a8a372014-09-23 09:50:21 -070046 virtual GrFragmentProcessor* asFragmentProcessor(GrContext* context) const SK_OVERRIDE;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +000047#endif
mike@reedtribe.orgf23f5f72012-01-07 03:48:45 +000048
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +000049 virtual void filterSpan(const SkPMColor src[], int count,
reed@google.combada6442012-12-17 20:21:44 +000050 SkPMColor dst[]) const SK_OVERRIDE;
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +000051
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +000052 SK_TO_STRING_OVERRIDE()
robertphillips@google.com1202c2a2013-05-23 14:00:17 +000053
djsollen@google.comba28d032012-03-26 17:57:35 +000054 SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkTable_ColorFilter)
mike@reedtribe.orgf23f5f72012-01-07 03:48:45 +000055
bsalomon@google.com371e1052013-01-11 21:08:55 +000056 enum {
57 kA_Flag = 1 << 0,
58 kR_Flag = 1 << 1,
59 kG_Flag = 1 << 2,
60 kB_Flag = 1 << 3,
61 };
62
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +000063protected:
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +000064 virtual void flatten(SkWriteBuffer&) const SK_OVERRIDE;
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +000065
66private:
bsalomon@google.comb2ad1012012-10-17 15:00:32 +000067 mutable const SkBitmap* fBitmap; // lazily allocated
mike@reedtribe.orgf23f5f72012-01-07 03:48:45 +000068
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +000069 uint8_t fStorage[256 * 4];
70 unsigned fFlags;
71
reed9fa60da2014-08-21 07:59:51 -070072 friend class SkTableColorFilter;
73
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +000074 typedef SkColorFilter INHERITED;
75};
76
77static const uint8_t gIdentityTable[] = {
rmistry@google.comfbfcd562012-08-23 18:09:54 +000078 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
79 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
80 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
81 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
82 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
83 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
84 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
85 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
86 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
87 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
88 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
89 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
90 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
91 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
92 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
93 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
94 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
95 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
96 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
97 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
98 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
99 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
100 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7,
101 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
102 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
103 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
104 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
105 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
106 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
107 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
108 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000109 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
110};
111
112void SkTable_ColorFilter::filterSpan(const SkPMColor src[], int count,
reed@google.combada6442012-12-17 20:21:44 +0000113 SkPMColor dst[]) const {
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000114 const uint8_t* table = fStorage;
115 const uint8_t* tableA = gIdentityTable;
116 const uint8_t* tableR = gIdentityTable;
117 const uint8_t* tableG = gIdentityTable;
118 const uint8_t* tableB = gIdentityTable;
119 if (fFlags & kA_Flag) {
120 tableA = table; table += 256;
121 }
122 if (fFlags & kR_Flag) {
123 tableR = table; table += 256;
124 }
125 if (fFlags & kG_Flag) {
126 tableG = table; table += 256;
127 }
128 if (fFlags & kB_Flag) {
129 tableB = table;
130 }
131
132 const SkUnPreMultiply::Scale* scaleTable = SkUnPreMultiply::GetScaleTable();
133 for (int i = 0; i < count; ++i) {
134 SkPMColor c = src[i];
135 unsigned a, r, g, b;
136 if (0 == c) {
137 a = r = g = b = 0;
138 } else {
139 a = SkGetPackedA32(c);
140 r = SkGetPackedR32(c);
141 g = SkGetPackedG32(c);
142 b = SkGetPackedB32(c);
143
144 if (a < 255) {
145 SkUnPreMultiply::Scale scale = scaleTable[a];
146 r = SkUnPreMultiply::ApplyScale(scale, r);
147 g = SkUnPreMultiply::ApplyScale(scale, g);
148 b = SkUnPreMultiply::ApplyScale(scale, b);
149 }
150 }
151 dst[i] = SkPremultiplyARGBInline(tableA[a], tableR[r],
152 tableG[g], tableB[b]);
153 }
154}
155
commit-bot@chromium.org0f10f7b2014-03-13 18:02:17 +0000156#ifndef SK_IGNORE_TO_STRING
robertphillips@google.com1202c2a2013-05-23 14:00:17 +0000157void SkTable_ColorFilter::toString(SkString* str) const {
158 str->append("SkTable_ColorFilter");
159}
160#endif
161
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000162static const uint8_t gCountNibBits[] = {
163 0, 1, 1, 2,
164 1, 2, 2, 3,
165 1, 2, 2, 3,
166 2, 3, 3, 4
167};
168
169#include "SkPackBits.h"
170
commit-bot@chromium.org8b0e8ac2014-01-30 18:58:24 +0000171void SkTable_ColorFilter::flatten(SkWriteBuffer& buffer) const {
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000172 uint8_t storage[5*256];
173 int count = gCountNibBits[fFlags & 0xF];
174 size_t size = SkPackBits::Pack8(fStorage, count * 256, storage);
175 SkASSERT(size <= sizeof(storage));
176
reed9fa60da2014-08-21 07:59:51 -0700177 buffer.write32(fFlags);
djsollen@google.comc73dd5c2012-08-07 15:54:32 +0000178 buffer.writeByteArray(storage, size);
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000179}
180
reed9fa60da2014-08-21 07:59:51 -0700181SkFlattenable* SkTable_ColorFilter::CreateProc(SkReadBuffer& buffer) {
182 const int flags = buffer.read32();
183 const size_t count = gCountNibBits[flags & 0xF];
184 SkASSERT(count <= 4);
185
186 uint8_t packedStorage[5*256];
187 size_t packedSize = buffer.getArrayCount();
188 if (!buffer.validate(packedSize <= sizeof(packedStorage))) {
189 return NULL;
190 }
191 if (!buffer.readByteArray(packedStorage, packedSize)) {
192 return NULL;
193 }
194
195 uint8_t unpackedStorage[4*256];
196 size_t unpackedSize = SkPackBits::Unpack8(packedStorage, packedSize, unpackedStorage);
197 // now check that we got the size we expected
senorblanco91c395a2014-09-25 15:51:35 -0700198 if (!buffer.validate(unpackedSize == count*256)) {
reed9fa60da2014-08-21 07:59:51 -0700199 return NULL;
200 }
201
202 const uint8_t* a = NULL;
203 const uint8_t* r = NULL;
204 const uint8_t* g = NULL;
205 const uint8_t* b = NULL;
206 const uint8_t* ptr = unpackedStorage;
207
208 if (flags & kA_Flag) {
209 a = ptr;
210 ptr += 256;
211 }
212 if (flags & kR_Flag) {
213 r = ptr;
214 ptr += 256;
215 }
216 if (flags & kG_Flag) {
217 g = ptr;
218 ptr += 256;
219 }
220 if (flags & kB_Flag) {
221 b = ptr;
222 ptr += 256;
223 }
224 return SkTableColorFilter::CreateARGB(a, r, g, b);
225}
226
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000227bool SkTable_ColorFilter::asComponentTable(SkBitmap* table) const {
mike@reedtribe.orgf23f5f72012-01-07 03:48:45 +0000228 if (table) {
229 if (NULL == fBitmap) {
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000230 SkBitmap* bmp = SkNEW(SkBitmap);
reed@google.com9ebcac52014-01-24 18:53:42 +0000231 bmp->allocPixels(SkImageInfo::MakeA8(256, 4));
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000232 uint8_t* bitmapPixels = bmp->getAddr8(0, 0);
twiz@google.com58071162012-07-18 21:41:50 +0000233 int offset = 0;
234 static const unsigned kFlags[] = { kA_Flag, kR_Flag, kG_Flag, kB_Flag };
235
236 for (int x = 0; x < 4; ++x) {
237 if (!(fFlags & kFlags[x])) {
238 memcpy(bitmapPixels, gIdentityTable, sizeof(gIdentityTable));
239 } else {
240 memcpy(bitmapPixels, fStorage + offset, 256);
241 offset += 256;
242 }
243 bitmapPixels += 256;
244 }
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000245 fBitmap = bmp;
mike@reedtribe.orgf23f5f72012-01-07 03:48:45 +0000246 }
247 *table = *fBitmap;
248 }
249 return true;
250}
251
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000252#if SK_SUPPORT_GPU
253
bsalomon6251d172014-10-15 10:50:36 -0700254#include "GrFragmentProcessor.h"
egdaniel605dd0f2014-11-12 08:35:25 -0800255#include "GrInvariantOutput.h"
joshualittb0a8a372014-09-23 09:50:21 -0700256#include "GrTBackendProcessorFactory.h"
bsalomonc6327a82014-10-27 12:53:08 -0700257#include "SkGr.h"
258#include "effects/GrTextureStripAtlas.h"
joshualittb0a8a372014-09-23 09:50:21 -0700259#include "gl/GrGLProcessor.h"
joshualitt30ba4362014-08-21 20:18:45 -0700260#include "gl/builders/GrGLProgramBuilder.h"
bsalomonc6327a82014-10-27 12:53:08 -0700261
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000262
263class GLColorTableEffect;
264
joshualittb0a8a372014-09-23 09:50:21 -0700265class ColorTableEffect : public GrFragmentProcessor {
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000266public:
bsalomonc6327a82014-10-27 12:53:08 -0700267 static GrFragmentProcessor* Create(GrContext* context, SkBitmap bitmap, unsigned flags);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000268
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000269 virtual ~ColorTableEffect();
270
271 static const char* Name() { return "ColorTable"; }
joshualittb0a8a372014-09-23 09:50:21 -0700272 virtual const GrBackendFragmentProcessorFactory& getFactory() const SK_OVERRIDE;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000273
joshualittb0a8a372014-09-23 09:50:21 -0700274 typedef GLColorTableEffect GLProcessor;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000275
bsalomonc6327a82014-10-27 12:53:08 -0700276 const GrTextureStripAtlas* atlas() const { return fAtlas; }
277 int atlasRow() const { return fRow; }
278
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000279private:
bsalomonc6327a82014-10-27 12:53:08 -0700280 virtual bool onIsEqual(const GrFragmentProcessor&) const SK_OVERRIDE;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000281
egdaniel605dd0f2014-11-12 08:35:25 -0800282 virtual void onComputeInvariantOutput(GrInvariantOutput* inout) const SK_OVERRIDE;
egdaniel1a8ecdf2014-10-03 06:24:12 -0700283
bsalomonc6327a82014-10-27 12:53:08 -0700284 ColorTableEffect(GrTexture* texture, GrTextureStripAtlas* atlas, int row, unsigned flags);
bsalomon@google.com0ac6af42013-01-16 15:16:18 +0000285
joshualittb0a8a372014-09-23 09:50:21 -0700286 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000287
bsalomonc6327a82014-10-27 12:53:08 -0700288 GrTextureAccess fTextureAccess;
289
290 // currently not used in shader code, just to assist onComputeInvariantOutput().
mtklein3f3b3d02014-12-01 11:47:08 -0800291 unsigned fFlags;
bsalomonc6327a82014-10-27 12:53:08 -0700292
293 GrTextureStripAtlas* fAtlas;
294 int fRow;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000295
joshualittb0a8a372014-09-23 09:50:21 -0700296 typedef GrFragmentProcessor INHERITED;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000297};
298
joshualittb0a8a372014-09-23 09:50:21 -0700299class GLColorTableEffect : public GrGLFragmentProcessor {
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000300public:
joshualittb0a8a372014-09-23 09:50:21 -0700301 GLColorTableEffect(const GrBackendProcessorFactory&, const GrProcessor&);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000302
joshualitt15988992014-10-09 15:04:05 -0700303 virtual void emitCode(GrGLFPBuilder*,
joshualittb0a8a372014-09-23 09:50:21 -0700304 const GrFragmentProcessor&,
bsalomon@google.com22a800a2012-10-26 19:16:46 +0000305 const char* outputColor,
306 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +0000307 const TransformedCoordsArray&,
bsalomon@google.com22a800a2012-10-26 19:16:46 +0000308 const TextureSamplerArray&) SK_OVERRIDE;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000309
bsalomonc6327a82014-10-27 12:53:08 -0700310 virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000311
joshualittb0a8a372014-09-23 09:50:21 -0700312 static void GenKey(const GrProcessor&, const GrGLCaps&, GrProcessorKeyBuilder* b) {}
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000313
314private:
bsalomonc6327a82014-10-27 12:53:08 -0700315 UniformHandle fRGBAYValuesUni;
joshualittb0a8a372014-09-23 09:50:21 -0700316 typedef GrGLFragmentProcessor INHERITED;
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000317};
318
joshualittb0a8a372014-09-23 09:50:21 -0700319GLColorTableEffect::GLColorTableEffect(const GrBackendProcessorFactory& factory, const GrProcessor&)
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000320 : INHERITED(factory) {
321 }
322
bsalomonc6327a82014-10-27 12:53:08 -0700323void GLColorTableEffect::setData(const GrGLProgramDataManager& pdm, const GrProcessor& proc) {
324 // The textures are organized in a strip where the rows are ordered a, r, g, b.
325 float rgbaYValues[4];
326 const ColorTableEffect& cte = proc.cast<ColorTableEffect>();
327 if (cte.atlas()) {
328 SkScalar yDelta = cte.atlas()->getNormalizedTexelHeight();
329 rgbaYValues[3] = cte.atlas()->getYOffset(cte.atlasRow()) + SK_ScalarHalf * yDelta;
330 rgbaYValues[0] = rgbaYValues[3] + yDelta;
331 rgbaYValues[1] = rgbaYValues[0] + yDelta;
332 rgbaYValues[2] = rgbaYValues[1] + yDelta;
333 } else {
334 rgbaYValues[3] = 0.125;
335 rgbaYValues[0] = 0.375;
336 rgbaYValues[1] = 0.625;
mtklein3f3b3d02014-12-01 11:47:08 -0800337 rgbaYValues[2] = 0.875;
bsalomonc6327a82014-10-27 12:53:08 -0700338 }
339 pdm.set4fv(fRGBAYValuesUni, 1, rgbaYValues);
340}
341
joshualitt15988992014-10-09 15:04:05 -0700342void GLColorTableEffect::emitCode(GrGLFPBuilder* builder,
joshualittb0a8a372014-09-23 09:50:21 -0700343 const GrFragmentProcessor&,
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000344 const char* outputColor,
345 const char* inputColor,
bsalomon@google.com77af6802013-10-02 13:04:56 +0000346 const TransformedCoordsArray&,
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000347 const TextureSamplerArray& samplers) {
bsalomonc6327a82014-10-27 12:53:08 -0700348 const char* yoffsets;
349 fRGBAYValuesUni = builder->addUniform(GrGLFPBuilder::kFragment_Visibility,
350 kVec4f_GrSLType, "yoffsets", &yoffsets);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000351 static const float kColorScaleFactor = 255.0f / 256.0f;
352 static const float kColorOffsetFactor = 1.0f / 512.0f;
joshualitt15988992014-10-09 15:04:05 -0700353 GrGLFPFragmentBuilder* fsBuilder = builder->getFragmentShaderBuilder();
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000354 if (NULL == inputColor) {
355 // the input color is solid white (all ones).
356 static const float kMaxValue = kColorScaleFactor + kColorOffsetFactor;
joshualitt30ba4362014-08-21 20:18:45 -0700357 fsBuilder->codeAppendf("\t\tvec4 coord = vec4(%f, %f, %f, %f);\n",
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000358 kMaxValue, kMaxValue, kMaxValue, kMaxValue);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000359
360 } else {
joshualitt30ba4362014-08-21 20:18:45 -0700361 fsBuilder->codeAppendf("\t\tfloat nonZeroAlpha = max(%s.a, .0001);\n", inputColor);
362 fsBuilder->codeAppendf("\t\tvec4 coord = vec4(%s.rgb / nonZeroAlpha, nonZeroAlpha);\n", inputColor);
363 fsBuilder->codeAppendf("\t\tcoord = coord * %f + vec4(%f, %f, %f, %f);\n",
bsalomon@google.comf910d3b2013-03-07 17:06:57 +0000364 kColorScaleFactor,
365 kColorOffsetFactor, kColorOffsetFactor,
366 kColorOffsetFactor, kColorOffsetFactor);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000367 }
368
bsalomonc6327a82014-10-27 12:53:08 -0700369 SkString coord;
370
joshualitt30ba4362014-08-21 20:18:45 -0700371 fsBuilder->codeAppendf("\t\t%s.a = ", outputColor);
bsalomonc6327a82014-10-27 12:53:08 -0700372 coord.printf("vec2(coord.a, %s.a)", yoffsets);
373 fsBuilder->appendTextureLookup(samplers[0], coord.c_str());
joshualitt30ba4362014-08-21 20:18:45 -0700374 fsBuilder->codeAppend(";\n");
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000375
joshualitt30ba4362014-08-21 20:18:45 -0700376 fsBuilder->codeAppendf("\t\t%s.r = ", outputColor);
bsalomonc6327a82014-10-27 12:53:08 -0700377 coord.printf("vec2(coord.r, %s.r)", yoffsets);
378 fsBuilder->appendTextureLookup(samplers[0], coord.c_str());
joshualitt30ba4362014-08-21 20:18:45 -0700379 fsBuilder->codeAppend(";\n");
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000380
joshualitt30ba4362014-08-21 20:18:45 -0700381 fsBuilder->codeAppendf("\t\t%s.g = ", outputColor);
bsalomonc6327a82014-10-27 12:53:08 -0700382 coord.printf("vec2(coord.g, %s.g)", yoffsets);
383 fsBuilder->appendTextureLookup(samplers[0], coord.c_str());
joshualitt30ba4362014-08-21 20:18:45 -0700384 fsBuilder->codeAppend(";\n");
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000385
joshualitt30ba4362014-08-21 20:18:45 -0700386 fsBuilder->codeAppendf("\t\t%s.b = ", outputColor);
bsalomonc6327a82014-10-27 12:53:08 -0700387 coord.printf("vec2(coord.b, %s.b)", yoffsets);
388 fsBuilder->appendTextureLookup(samplers[0], coord.c_str());
joshualitt30ba4362014-08-21 20:18:45 -0700389 fsBuilder->codeAppend(";\n");
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000390
joshualitt30ba4362014-08-21 20:18:45 -0700391 fsBuilder->codeAppendf("\t\t%s.rgb *= %s.a;\n", outputColor, outputColor);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000392}
393
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000394///////////////////////////////////////////////////////////////////////////////
bsalomonc6327a82014-10-27 12:53:08 -0700395GrFragmentProcessor* ColorTableEffect::Create(GrContext* context, SkBitmap bitmap, unsigned flags) {
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000396
bsalomonc6327a82014-10-27 12:53:08 -0700397 GrTextureStripAtlas::Desc desc;
398 desc.fWidth = bitmap.width();
399 desc.fHeight = 128;
400 desc.fRowHeight = bitmap.height();
401 desc.fContext = context;
402 desc.fConfig = SkImageInfo2GrPixelConfig(bitmap.info());
403 GrTextureStripAtlas* atlas = GrTextureStripAtlas::GetAtlas(desc);
404 int row = atlas->lockRow(bitmap);
405 SkAutoTUnref<GrTexture> texture;
406 if (-1 == row) {
407 atlas = NULL;
408 // Passing params=NULL because this effect does no tiling or filtering.
409 texture.reset(GrRefCachedBitmapTexture(context, bitmap, NULL));
410 } else {
411 texture.reset(SkRef(atlas->getTexture()));
412 }
413
414 return SkNEW_ARGS(ColorTableEffect, (texture, atlas, row, flags));
415}
416
417ColorTableEffect::ColorTableEffect(GrTexture* texture, GrTextureStripAtlas* atlas, int row,
418 unsigned flags)
bsalomon@google.com371e1052013-01-11 21:08:55 +0000419 : fTextureAccess(texture, "a")
bsalomonc6327a82014-10-27 12:53:08 -0700420 , fFlags(flags)
421 , fAtlas(atlas)
422 , fRow(row) {
423
bsalomon@google.com50db75c2013-01-11 13:54:30 +0000424 this->addTextureAccess(&fTextureAccess);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000425}
426
427ColorTableEffect::~ColorTableEffect() {
bsalomonc6327a82014-10-27 12:53:08 -0700428 if (fAtlas) {
429 fAtlas->unlockRow(fRow);
430 }
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000431}
432
joshualittb0a8a372014-09-23 09:50:21 -0700433const GrBackendFragmentProcessorFactory& ColorTableEffect::getFactory() const {
434 return GrTBackendFragmentProcessorFactory<ColorTableEffect>::getInstance();
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000435}
436
bsalomonc6327a82014-10-27 12:53:08 -0700437bool ColorTableEffect::onIsEqual(const GrFragmentProcessor& other) const {
438 // For non-atlased instances, the texture (compared by base class) is sufficient to
439 // differentiate different tables. For atlased instances we ensure they are using the
440 // same row.
441 const ColorTableEffect& that = other.cast<ColorTableEffect>();
442 SkASSERT(SkToBool(fAtlas) == SkToBool(that.fAtlas));
443 // Ok to always do this comparison since both would be -1 if non-atlased.
444 return fRow == that.fRow;
445}
446
egdaniel605dd0f2014-11-12 08:35:25 -0800447void ColorTableEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
bsalomon@google.com371e1052013-01-11 21:08:55 +0000448 // If we kept the table in the effect then we could actually run known inputs through the
449 // table.
egdanielccb2e382014-10-13 12:53:46 -0700450 uint8_t invalidateFlags = 0;
bsalomon@google.com371e1052013-01-11 21:08:55 +0000451 if (fFlags & SkTable_ColorFilter::kR_Flag) {
egdanielccb2e382014-10-13 12:53:46 -0700452 invalidateFlags |= kR_GrColorComponentFlag;
bsalomon@google.com371e1052013-01-11 21:08:55 +0000453 }
454 if (fFlags & SkTable_ColorFilter::kG_Flag) {
egdanielccb2e382014-10-13 12:53:46 -0700455 invalidateFlags |= kG_GrColorComponentFlag;
bsalomon@google.com371e1052013-01-11 21:08:55 +0000456 }
457 if (fFlags & SkTable_ColorFilter::kB_Flag) {
egdanielccb2e382014-10-13 12:53:46 -0700458 invalidateFlags |= kB_GrColorComponentFlag;
bsalomon@google.com371e1052013-01-11 21:08:55 +0000459 }
460 if (fFlags & SkTable_ColorFilter::kA_Flag) {
egdanielccb2e382014-10-13 12:53:46 -0700461 invalidateFlags |= kA_GrColorComponentFlag;
bsalomon@google.com371e1052013-01-11 21:08:55 +0000462 }
egdaniel605dd0f2014-11-12 08:35:25 -0800463 inout->invalidateComponents(invalidateFlags, GrInvariantOutput::kWill_ReadInput);
bsalomon@google.com371e1052013-01-11 21:08:55 +0000464}
465
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000466///////////////////////////////////////////////////////////////////////////////
467
joshualittb0a8a372014-09-23 09:50:21 -0700468GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ColorTableEffect);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000469
joshualittb0a8a372014-09-23 09:50:21 -0700470GrFragmentProcessor* ColorTableEffect::TestCreate(SkRandom* random,
471 GrContext* context,
472 const GrDrawTargetCaps&,
473 GrTexture* textures[]) {
bsalomonc6327a82014-10-27 12:53:08 -0700474 int flags = 0;
475 uint8_t luts[256][4];
476 do {
477 for (int i = 0; i < 4; ++i) {
478 flags |= random->nextBool() ? (1 << i): 0;
479 }
480 } while (!flags);
481 for (int i = 0; i < 4; ++i) {
482 if (flags & (1 << i)) {
483 for (int j = 0; j < 256; ++j) {
484 luts[j][i] = SkToU8(random->nextBits(8));
485 }
486 }
487 }
488 SkAutoTUnref<SkColorFilter> filter(SkTableColorFilter::CreateARGB(
489 (flags & (1 << 0)) ? luts[0] : NULL,
490 (flags & (1 << 1)) ? luts[1] : NULL,
491 (flags & (1 << 2)) ? luts[2] : NULL,
492 (flags & (1 << 3)) ? luts[3] : NULL
493 ));
494 return filter->asFragmentProcessor(context);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000495}
496
joshualittb0a8a372014-09-23 09:50:21 -0700497GrFragmentProcessor* SkTable_ColorFilter::asFragmentProcessor(GrContext* context) const {
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000498 SkBitmap bitmap;
499 this->asComponentTable(&bitmap);
bsalomonc6327a82014-10-27 12:53:08 -0700500
501 return ColorTableEffect::Create(context, bitmap, fFlags);
bsalomon@google.comb2ad1012012-10-17 15:00:32 +0000502}
503
504#endif // SK_SUPPORT_GPU
505
mike@reedtribe.orga69b48c2011-12-28 20:31:00 +0000506///////////////////////////////////////////////////////////////////////////////
507
508#ifdef SK_CPU_BENDIAN
509#else
510 #define SK_A32_INDEX (3 - (SK_A32_SHIFT >> 3))
511 #define SK_R32_INDEX (3 - (SK_R32_SHIFT >> 3))
512 #define SK_G32_INDEX (3 - (SK_G32_SHIFT >> 3))
513 #define SK_B32_INDEX (3 - (SK_B32_SHIFT >> 3))
514#endif
515
516///////////////////////////////////////////////////////////////////////////////
517
518SkColorFilter* SkTableColorFilter::Create(const uint8_t table[256]) {
519 return SkNEW_ARGS(SkTable_ColorFilter, (table, table, table, table));
520}
521
522SkColorFilter* SkTableColorFilter::CreateARGB(const uint8_t tableA[256],
523 const uint8_t tableR[256],
524 const uint8_t tableG[256],
525 const uint8_t tableB[256]) {
526 return SkNEW_ARGS(SkTable_ColorFilter, (tableA, tableR, tableG, tableB));
527}
djsollen@google.coma2ca41e2012-03-23 19:00:34 +0000528
529SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkTableColorFilter)
530 SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkTable_ColorFilter)
531SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END