SkTableColorFilter.cpp revision 025128811219dc45fd99b6c4d1d14f833cf7a26e
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, size);
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 TransformedCoordsArray&,
276                          const TextureSamplerArray&) SK_OVERRIDE;
277
278    virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE {}
279
280    static EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
281
282private:
283
284    typedef GrGLEffect INHERITED;
285};
286
287GLColorTableEffect::GLColorTableEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
288    : INHERITED(factory) {
289 }
290
291void GLColorTableEffect::emitCode(GrGLShaderBuilder* builder,
292                                  const GrDrawEffect&,
293                                  EffectKey,
294                                  const char* outputColor,
295                                  const char* inputColor,
296                                  const TransformedCoordsArray&,
297                                  const TextureSamplerArray& samplers) {
298
299    static const float kColorScaleFactor = 255.0f / 256.0f;
300    static const float kColorOffsetFactor = 1.0f / 512.0f;
301    if (NULL == inputColor) {
302        // the input color is solid white (all ones).
303        static const float kMaxValue = kColorScaleFactor + kColorOffsetFactor;
304        builder->fsCodeAppendf("\t\tvec4 coord = vec4(%f, %f, %f, %f);\n",
305                               kMaxValue, kMaxValue, kMaxValue, kMaxValue);
306
307    } else {
308        builder->fsCodeAppendf("\t\tfloat nonZeroAlpha = max(%s.a, .0001);\n", inputColor);
309        builder->fsCodeAppendf("\t\tvec4 coord = vec4(%s.rgb / nonZeroAlpha, nonZeroAlpha);\n", inputColor);
310        builder->fsCodeAppendf("\t\tcoord = coord * %f + vec4(%f, %f, %f, %f);\n",
311                              kColorScaleFactor,
312                              kColorOffsetFactor, kColorOffsetFactor,
313                              kColorOffsetFactor, kColorOffsetFactor);
314    }
315
316    builder->fsCodeAppendf("\t\t%s.a = ", outputColor);
317    builder->fsAppendTextureLookup(samplers[0], "vec2(coord.a, 0.125)");
318    builder->fsCodeAppend(";\n");
319
320    builder->fsCodeAppendf("\t\t%s.r = ", outputColor);
321    builder->fsAppendTextureLookup(samplers[0], "vec2(coord.r, 0.375)");
322    builder->fsCodeAppend(";\n");
323
324    builder->fsCodeAppendf("\t\t%s.g = ", outputColor);
325    builder->fsAppendTextureLookup(samplers[0], "vec2(coord.g, 0.625)");
326    builder->fsCodeAppend(";\n");
327
328    builder->fsCodeAppendf("\t\t%s.b = ", outputColor);
329    builder->fsAppendTextureLookup(samplers[0], "vec2(coord.b, 0.875)");
330    builder->fsCodeAppend(";\n");
331
332    builder->fsCodeAppendf("\t\t%s.rgb *= %s.a;\n", outputColor, outputColor);
333}
334
335GrGLEffect::EffectKey GLColorTableEffect::GenKey(const GrDrawEffect&, const GrGLCaps&) {
336    return 0;
337}
338
339///////////////////////////////////////////////////////////////////////////////
340
341ColorTableEffect::ColorTableEffect(GrTexture* texture, unsigned flags)
342    : fTextureAccess(texture, "a")
343    , fFlags(flags) {
344    this->addTextureAccess(&fTextureAccess);
345}
346
347ColorTableEffect::~ColorTableEffect() {
348}
349
350const GrBackendEffectFactory&  ColorTableEffect::getFactory() const {
351    return GrTBackendEffectFactory<ColorTableEffect>::getInstance();
352}
353
354bool ColorTableEffect::onIsEqual(const GrEffect& sBase) const {
355    return this->texture(0) == sBase.texture(0);
356}
357
358void ColorTableEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
359    // If we kept the table in the effect then we could actually run known inputs through the
360    // table.
361    if (fFlags & SkTable_ColorFilter::kR_Flag) {
362        *validFlags &= ~kR_GrColorComponentFlag;
363    }
364    if (fFlags & SkTable_ColorFilter::kG_Flag) {
365        *validFlags &= ~kG_GrColorComponentFlag;
366    }
367    if (fFlags & SkTable_ColorFilter::kB_Flag) {
368        *validFlags &= ~kB_GrColorComponentFlag;
369    }
370    if (fFlags & SkTable_ColorFilter::kA_Flag) {
371        *validFlags &= ~kA_GrColorComponentFlag;
372    }
373}
374
375
376///////////////////////////////////////////////////////////////////////////////
377
378GR_DEFINE_EFFECT_TEST(ColorTableEffect);
379
380GrEffectRef* ColorTableEffect::TestCreate(SkRandom* random,
381                                          GrContext* context,
382                                          const GrDrawTargetCaps&,
383                                          GrTexture* textures[]) {
384    static unsigned kAllFlags = SkTable_ColorFilter::kR_Flag | SkTable_ColorFilter::kG_Flag |
385                                SkTable_ColorFilter::kB_Flag | SkTable_ColorFilter::kA_Flag;
386    return ColorTableEffect::Create(textures[GrEffectUnitTest::kAlphaTextureIdx], kAllFlags);
387}
388
389GrEffectRef* SkTable_ColorFilter::asNewEffect(GrContext* context) const {
390    SkBitmap bitmap;
391    GrEffectRef* effect = NULL;
392    this->asComponentTable(&bitmap);
393    // passing NULL because this effect does no tiling or filtering.
394    GrTexture* texture = GrLockAndRefCachedBitmapTexture(context, bitmap, NULL);
395    if (NULL != texture) {
396        effect = ColorTableEffect::Create(texture, fFlags);
397
398        // Unlock immediately, this is not great, but we don't have a way of
399        // knowing when else to unlock it currently. TODO: Remove this when
400        // unref becomes the unlock replacement for all types of textures.
401        GrUnlockAndUnrefCachedBitmapTexture(texture);
402    }
403    return effect;
404}
405
406#endif // SK_SUPPORT_GPU
407
408///////////////////////////////////////////////////////////////////////////////
409
410#ifdef SK_CPU_BENDIAN
411#else
412    #define SK_A32_INDEX    (3 - (SK_A32_SHIFT >> 3))
413    #define SK_R32_INDEX    (3 - (SK_R32_SHIFT >> 3))
414    #define SK_G32_INDEX    (3 - (SK_G32_SHIFT >> 3))
415    #define SK_B32_INDEX    (3 - (SK_B32_SHIFT >> 3))
416#endif
417
418///////////////////////////////////////////////////////////////////////////////
419
420SkColorFilter* SkTableColorFilter::Create(const uint8_t table[256]) {
421    return SkNEW_ARGS(SkTable_ColorFilter, (table, table, table, table));
422}
423
424SkColorFilter* SkTableColorFilter::CreateARGB(const uint8_t tableA[256],
425                                              const uint8_t tableR[256],
426                                              const uint8_t tableG[256],
427                                              const uint8_t tableB[256]) {
428    return SkNEW_ARGS(SkTable_ColorFilter, (tableA, tableR, tableG, tableB));
429}
430
431SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkTableColorFilter)
432    SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkTable_ColorFilter)
433SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
434