SkTableColorFilter.cpp revision c7d624ec535adcc388cad35b3475872b08cd90c0
1
2#include "SkBitmap.h"
3#include "SkTableColorFilter.h"
4#include "SkColorPriv.h"
5#include "SkFlattenableBuffers.h"
6#include "SkUnPreMultiply.h"
7#include "SkString.h"
8
9class SkTable_ColorFilter : public SkColorFilter {
10public:
11    SkTable_ColorFilter(const uint8_t tableA[], const uint8_t tableR[],
12                        const uint8_t tableG[], const uint8_t tableB[]) {
13        fBitmap = NULL;
14        fFlags = 0;
15
16        uint8_t* dst = fStorage;
17        if (tableA) {
18            memcpy(dst, tableA, 256);
19            dst += 256;
20            fFlags |= kA_Flag;
21        }
22        if (tableR) {
23            memcpy(dst, tableR, 256);
24            dst += 256;
25            fFlags |= kR_Flag;
26        }
27        if (tableG) {
28            memcpy(dst, tableG, 256);
29            dst += 256;
30            fFlags |= kG_Flag;
31        }
32        if (tableB) {
33            memcpy(dst, tableB, 256);
34            fFlags |= kB_Flag;
35        }
36    }
37
38    virtual ~SkTable_ColorFilter() {
39        SkDELETE(fBitmap);
40    }
41
42    virtual bool asComponentTable(SkBitmap* table) const SK_OVERRIDE;
43
44#if SK_SUPPORT_GPU
45    virtual GrEffectRef* asNewEffect(GrContext* context) const SK_OVERRIDE;
46#endif
47
48    virtual void filterSpan(const SkPMColor src[], int count,
49                            SkPMColor dst[]) const SK_OVERRIDE;
50
51    SkDEVCODE(virtual void toString(SkString* str) const SK_OVERRIDE;)
52
53    SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkTable_ColorFilter)
54
55    enum {
56        kA_Flag = 1 << 0,
57        kR_Flag = 1 << 1,
58        kG_Flag = 1 << 2,
59        kB_Flag = 1 << 3,
60    };
61
62protected:
63    SkTable_ColorFilter(SkFlattenableReadBuffer& buffer);
64    virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE;
65
66private:
67    mutable const SkBitmap* fBitmap; // lazily allocated
68
69    uint8_t fStorage[256 * 4];
70    unsigned fFlags;
71
72    typedef SkColorFilter INHERITED;
73};
74
75static const uint8_t gIdentityTable[] = {
76    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
77    0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
78    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
79    0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
80    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
81    0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
82    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
83    0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
84    0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
85    0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
86    0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
87    0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
88    0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
89    0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
90    0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
91    0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
92    0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
93    0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
94    0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
95    0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
96    0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
97    0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
98    0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7,
99    0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
100    0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
101    0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
102    0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
103    0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
104    0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
105    0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
106    0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
107    0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
108};
109
110void SkTable_ColorFilter::filterSpan(const SkPMColor src[], int count,
111                                     SkPMColor dst[]) const {
112    const uint8_t* table = fStorage;
113    const uint8_t* tableA = gIdentityTable;
114    const uint8_t* tableR = gIdentityTable;
115    const uint8_t* tableG = gIdentityTable;
116    const uint8_t* tableB = gIdentityTable;
117    if (fFlags & kA_Flag) {
118        tableA = table; table += 256;
119    }
120    if (fFlags & kR_Flag) {
121        tableR = table; table += 256;
122    }
123    if (fFlags & kG_Flag) {
124        tableG = table; table += 256;
125    }
126    if (fFlags & kB_Flag) {
127        tableB = table;
128    }
129
130    const SkUnPreMultiply::Scale* scaleTable = SkUnPreMultiply::GetScaleTable();
131    for (int i = 0; i < count; ++i) {
132        SkPMColor c = src[i];
133        unsigned a, r, g, b;
134        if (0 == c) {
135            a = r = g = b = 0;
136        } else {
137            a = SkGetPackedA32(c);
138            r = SkGetPackedR32(c);
139            g = SkGetPackedG32(c);
140            b = SkGetPackedB32(c);
141
142            if (a < 255) {
143                SkUnPreMultiply::Scale scale = scaleTable[a];
144                r = SkUnPreMultiply::ApplyScale(scale, r);
145                g = SkUnPreMultiply::ApplyScale(scale, g);
146                b = SkUnPreMultiply::ApplyScale(scale, b);
147            }
148        }
149        dst[i] = SkPremultiplyARGBInline(tableA[a], tableR[r],
150                                         tableG[g], tableB[b]);
151    }
152}
153
154#ifdef SK_DEVELOPER
155void SkTable_ColorFilter::toString(SkString* str) const {
156    str->append("SkTable_ColorFilter");
157}
158#endif
159
160static const uint8_t gCountNibBits[] = {
161    0, 1, 1, 2,
162    1, 2, 2, 3,
163    1, 2, 2, 3,
164    2, 3, 3, 4
165};
166
167#include "SkPackBits.h"
168
169void SkTable_ColorFilter::flatten(SkFlattenableWriteBuffer& buffer) const {
170    this->INHERITED::flatten(buffer);
171
172    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
177//    SkDebugf("raw %d packed %d\n", count * 256, size);
178
179    buffer.writeInt(fFlags);
180    buffer.writeByteArray(storage, size);
181}
182
183SkTable_ColorFilter::SkTable_ColorFilter(SkFlattenableReadBuffer& buffer) : INHERITED(buffer) {
184    fBitmap = NULL;
185
186    uint8_t storage[5*256];
187
188    fFlags = buffer.readInt();
189
190    size_t size = buffer.getArrayCount();
191    SkASSERT(size <= sizeof(storage));
192    buffer.readByteArray(storage);
193
194    SkDEBUGCODE(size_t raw = ) SkPackBits::Unpack8(storage, size, fStorage);
195
196    SkASSERT(raw <= sizeof(fStorage));
197    SkDEBUGCODE(size_t count = gCountNibBits[fFlags & 0xF]);
198    SkASSERT(raw == count * 256);
199}
200
201bool SkTable_ColorFilter::asComponentTable(SkBitmap* table) const {
202    if (table) {
203        if (NULL == fBitmap) {
204            SkBitmap* bmp = SkNEW(SkBitmap);
205            bmp->setConfig(SkBitmap::kA8_Config, 256, 4, 256);
206            bmp->allocPixels();
207            uint8_t* bitmapPixels = bmp->getAddr8(0, 0);
208            int offset = 0;
209            static const unsigned kFlags[] = { kA_Flag, kR_Flag, kG_Flag, kB_Flag };
210
211            for (int x = 0; x < 4; ++x) {
212                if (!(fFlags & kFlags[x])) {
213                    memcpy(bitmapPixels, gIdentityTable, sizeof(gIdentityTable));
214                } else {
215                    memcpy(bitmapPixels, fStorage + offset, 256);
216                    offset += 256;
217                }
218                bitmapPixels += 256;
219            }
220            fBitmap = bmp;
221        }
222        *table = *fBitmap;
223    }
224    return true;
225}
226
227#if SK_SUPPORT_GPU
228
229#include "GrEffect.h"
230#include "GrTBackendEffectFactory.h"
231#include "gl/GrGLEffect.h"
232#include "SkGr.h"
233
234class GLColorTableEffect;
235
236class ColorTableEffect : public GrEffect {
237public:
238    static GrEffectRef* Create(GrTexture* texture, unsigned flags) {
239        AutoEffectUnref effect(SkNEW_ARGS(ColorTableEffect, (texture, flags)));
240        return CreateEffectRef(effect);
241    }
242
243    virtual ~ColorTableEffect();
244
245    static const char* Name() { return "ColorTable"; }
246    virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
247
248    virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
249
250    typedef GLColorTableEffect GLEffect;
251
252private:
253    virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
254
255    explicit ColorTableEffect(GrTexture* texture, unsigned flags);
256
257    GR_DECLARE_EFFECT_TEST;
258
259    GrTextureAccess fTextureAccess;
260    unsigned        fFlags; // currently not used in shader code, just to assist
261                            // getConstantColorComponents().
262
263    typedef GrEffect INHERITED;
264};
265
266class GLColorTableEffect : public GrGLEffect {
267public:
268    GLColorTableEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
269
270    virtual void emitCode(GrGLShaderBuilder*,
271                          const GrDrawEffect&,
272                          EffectKey,
273                          const char* outputColor,
274                          const char* inputColor,
275                          const TextureSamplerArray&) SK_OVERRIDE;
276
277    virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE {}
278
279    static EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
280
281private:
282
283    typedef GrGLEffect INHERITED;
284};
285
286GLColorTableEffect::GLColorTableEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
287    : INHERITED(factory) {
288 }
289
290void GLColorTableEffect::emitCode(GrGLShaderBuilder* builder,
291                                  const GrDrawEffect&,
292                                  EffectKey,
293                                  const char* outputColor,
294                                  const char* inputColor,
295                                  const TextureSamplerArray& samplers) {
296
297    static const float kColorScaleFactor = 255.0f / 256.0f;
298    static const float kColorOffsetFactor = 1.0f / 512.0f;
299    if (NULL == inputColor) {
300        // the input color is solid white (all ones).
301        static const float kMaxValue = kColorScaleFactor + kColorOffsetFactor;
302        builder->fsCodeAppendf("\t\tvec4 coord = vec4(%f, %f, %f, %f);\n",
303                               kMaxValue, kMaxValue, kMaxValue, kMaxValue);
304
305    } else {
306        builder->fsCodeAppendf("\t\tfloat nonZeroAlpha = max(%s.a, .0001);\n", inputColor);
307        builder->fsCodeAppendf("\t\tvec4 coord = vec4(%s.rgb / nonZeroAlpha, nonZeroAlpha);\n", inputColor);
308        builder->fsCodeAppendf("\t\tcoord = coord * %f + vec4(%f, %f, %f, %f);\n",
309                              kColorScaleFactor,
310                              kColorOffsetFactor, kColorOffsetFactor,
311                              kColorOffsetFactor, kColorOffsetFactor);
312    }
313
314    builder->fsCodeAppendf("\t\t%s.a = ", outputColor);
315    builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType, samplers[0], "vec2(coord.a, 0.125)");
316    builder->fsCodeAppend(";\n");
317
318    builder->fsCodeAppendf("\t\t%s.r = ", outputColor);
319    builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType, samplers[0], "vec2(coord.r, 0.375)");
320    builder->fsCodeAppend(";\n");
321
322    builder->fsCodeAppendf("\t\t%s.g = ", outputColor);
323    builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType, samplers[0], "vec2(coord.g, 0.625)");
324    builder->fsCodeAppend(";\n");
325
326    builder->fsCodeAppendf("\t\t%s.b = ", outputColor);
327    builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType, samplers[0], "vec2(coord.b, 0.875)");
328    builder->fsCodeAppend(";\n");
329
330    builder->fsCodeAppendf("\t\t%s.rgb *= %s.a;\n", outputColor, outputColor);
331}
332
333GrGLEffect::EffectKey GLColorTableEffect::GenKey(const GrDrawEffect&, const GrGLCaps&) {
334    return 0;
335}
336
337///////////////////////////////////////////////////////////////////////////////
338
339ColorTableEffect::ColorTableEffect(GrTexture* texture, unsigned flags)
340    : fTextureAccess(texture, "a")
341    , fFlags(flags) {
342    this->addTextureAccess(&fTextureAccess);
343}
344
345ColorTableEffect::~ColorTableEffect() {
346}
347
348const GrBackendEffectFactory&  ColorTableEffect::getFactory() const {
349    return GrTBackendEffectFactory<ColorTableEffect>::getInstance();
350}
351
352bool ColorTableEffect::onIsEqual(const GrEffect& sBase) const {
353    return this->texture(0) == sBase.texture(0);
354}
355
356void ColorTableEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
357    // If we kept the table in the effect then we could actually run known inputs through the
358    // table.
359    if (fFlags & SkTable_ColorFilter::kR_Flag) {
360        *validFlags &= ~kR_GrColorComponentFlag;
361    }
362    if (fFlags & SkTable_ColorFilter::kG_Flag) {
363        *validFlags &= ~kG_GrColorComponentFlag;
364    }
365    if (fFlags & SkTable_ColorFilter::kB_Flag) {
366        *validFlags &= ~kB_GrColorComponentFlag;
367    }
368    if (fFlags & SkTable_ColorFilter::kA_Flag) {
369        *validFlags &= ~kA_GrColorComponentFlag;
370    }
371}
372
373
374///////////////////////////////////////////////////////////////////////////////
375
376GR_DEFINE_EFFECT_TEST(ColorTableEffect);
377
378GrEffectRef* ColorTableEffect::TestCreate(SkMWCRandom* random,
379                                          GrContext* context,
380                                          const GrDrawTargetCaps&,
381                                          GrTexture* textures[]) {
382    static unsigned kAllFlags = SkTable_ColorFilter::kR_Flag | SkTable_ColorFilter::kG_Flag |
383                                SkTable_ColorFilter::kB_Flag | SkTable_ColorFilter::kA_Flag;
384    return ColorTableEffect::Create(textures[GrEffectUnitTest::kAlphaTextureIdx], kAllFlags);
385}
386
387GrEffectRef* SkTable_ColorFilter::asNewEffect(GrContext* context) const {
388    SkBitmap bitmap;
389    GrEffectRef* effect = NULL;
390    this->asComponentTable(&bitmap);
391    // passing NULL because this effect does no tiling or filtering.
392    GrTexture* texture = GrLockAndRefCachedBitmapTexture(context, bitmap, NULL);
393    if (NULL != texture) {
394        effect = ColorTableEffect::Create(texture, fFlags);
395
396        // Unlock immediately, this is not great, but we don't have a way of
397        // knowing when else to unlock it currently. TODO: Remove this when
398        // unref becomes the unlock replacement for all types of textures.
399        GrUnlockAndUnrefCachedBitmapTexture(texture);
400    }
401    return effect;
402}
403
404#endif // SK_SUPPORT_GPU
405
406///////////////////////////////////////////////////////////////////////////////
407
408#ifdef SK_CPU_BENDIAN
409#else
410    #define SK_A32_INDEX    (3 - (SK_A32_SHIFT >> 3))
411    #define SK_R32_INDEX    (3 - (SK_R32_SHIFT >> 3))
412    #define SK_G32_INDEX    (3 - (SK_G32_SHIFT >> 3))
413    #define SK_B32_INDEX    (3 - (SK_B32_SHIFT >> 3))
414#endif
415
416///////////////////////////////////////////////////////////////////////////////
417
418SkColorFilter* SkTableColorFilter::Create(const uint8_t table[256]) {
419    return SkNEW_ARGS(SkTable_ColorFilter, (table, table, table, table));
420}
421
422SkColorFilter* SkTableColorFilter::CreateARGB(const uint8_t tableA[256],
423                                              const uint8_t tableR[256],
424                                              const uint8_t tableG[256],
425                                              const uint8_t tableB[256]) {
426    return SkNEW_ARGS(SkTable_ColorFilter, (tableA, tableR, tableG, tableB));
427}
428
429SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkTableColorFilter)
430    SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkTable_ColorFilter)
431SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
432