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