SkTableColorFilter.cpp revision 73a9694b4ceb67547e5863db5315488e7d5294f7
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        AutoEffectUnref effect(SkNEW_ARGS(ColorTableEffect, (texture, flags)));
231        return CreateEffectRef(effect);
232    }
233
234    virtual ~ColorTableEffect();
235
236    static const char* Name() { return "ColorTable"; }
237    virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
238
239    virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
240
241    typedef GLColorTableEffect GLEffect;
242
243private:
244    virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
245
246    explicit ColorTableEffect(GrTexture* texture, unsigned flags);
247
248    GR_DECLARE_EFFECT_TEST;
249
250    GrTextureAccess fTextureAccess;
251    unsigned        fFlags; // currently not used in shader code, just to assist
252                            // getConstantColorComponents().
253
254    typedef GrEffect INHERITED;
255};
256
257class GLColorTableEffect : public GrGLEffect {
258public:
259    GLColorTableEffect(const GrBackendEffectFactory&, const GrEffectRef&);
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(const GrBackendEffectFactory& factory, const GrEffectRef&)
279    : INHERITED(factory) {
280 }
281
282void GLColorTableEffect::emitCode(GrGLShaderBuilder* builder,
283                                  const GrEffectStage&,
284                                  EffectKey,
285                                  const char* vertexCoords,
286                                  const char* outputColor,
287                                  const char* inputColor,
288                                  const TextureSamplerArray& samplers) {
289
290    static const float kColorScaleFactor = 255.0f / 256.0f;
291    static const float kColorOffsetFactor = 1.0f / 512.0f;
292    SkString* code = &builder->fFSCode;
293    if (NULL == inputColor) {
294        // the input color is solid white (all ones).
295        static const float kMaxValue = kColorScaleFactor + kColorOffsetFactor;
296        code->appendf("\t\tvec4 coord = vec4(%f, %f, %f, %f);\n",
297                      kMaxValue, kMaxValue, kMaxValue, kMaxValue);
298
299    } else {
300        code->appendf("\t\tfloat nonZeroAlpha = max(%s.a, .0001);\n", inputColor);
301        code->appendf("\t\tvec4 coord = vec4(%s.rgb / nonZeroAlpha, nonZeroAlpha);\n", inputColor);
302        code->appendf("\t\tcoord = coord * %f + vec4(%f, %f, %f, %f);\n",
303                      kColorScaleFactor,
304                      kColorOffsetFactor, kColorOffsetFactor,
305                      kColorOffsetFactor, kColorOffsetFactor);
306    }
307
308    code->appendf("\t\t%s.a = ", outputColor);
309    builder->appendTextureLookup(code, samplers[0], "vec2(coord.a, 0.125)");
310    code->append(";\n");
311
312    code->appendf("\t\t%s.r = ", outputColor);
313    builder->appendTextureLookup(code, samplers[0], "vec2(coord.r, 0.375)");
314    code->append(";\n");
315
316    code->appendf("\t\t%s.g = ", outputColor);
317    builder->appendTextureLookup(code, samplers[0], "vec2(coord.g, 0.625)");
318    code->append(";\n");
319
320    code->appendf("\t\t%s.b = ", outputColor);
321    builder->appendTextureLookup(code, samplers[0], "vec2(coord.b, 0.875)");
322    code->append(";\n");
323
324    code->appendf("\t\t%s.rgb *= %s.a;\n", outputColor, outputColor);
325}
326
327GrGLEffect::EffectKey GLColorTableEffect::GenKey(const GrEffectStage&, const GrGLCaps&) {
328    return 0;
329}
330
331///////////////////////////////////////////////////////////////////////////////
332
333ColorTableEffect::ColorTableEffect(GrTexture* texture, unsigned flags)
334    : fTextureAccess(texture, "a")
335    , fFlags(flags) {
336    this->addTextureAccess(&fTextureAccess);
337}
338
339ColorTableEffect::~ColorTableEffect() {
340}
341
342const GrBackendEffectFactory&  ColorTableEffect::getFactory() const {
343    return GrTBackendEffectFactory<ColorTableEffect>::getInstance();
344}
345
346bool ColorTableEffect::onIsEqual(const GrEffect& sBase) const {
347    return this->texture(0) == sBase.texture(0);
348}
349
350void ColorTableEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
351    // If we kept the table in the effect then we could actually run known inputs through the
352    // table.
353    if (fFlags & SkTable_ColorFilter::kR_Flag) {
354        *validFlags &= ~kR_ValidComponentFlag;
355    }
356    if (fFlags & SkTable_ColorFilter::kG_Flag) {
357        *validFlags &= ~kG_ValidComponentFlag;
358    }
359    if (fFlags & SkTable_ColorFilter::kB_Flag) {
360        *validFlags &= ~kB_ValidComponentFlag;
361    }
362    if (fFlags & SkTable_ColorFilter::kA_Flag) {
363        *validFlags &= ~kA_ValidComponentFlag;
364    }
365}
366
367
368///////////////////////////////////////////////////////////////////////////////
369
370GR_DEFINE_EFFECT_TEST(ColorTableEffect);
371
372GrEffectRef* ColorTableEffect::TestCreate(SkMWCRandom* random,
373                                          GrContext* context,
374                                          GrTexture* textures[]) {
375    static unsigned kAllFlags = SkTable_ColorFilter::kR_Flag | SkTable_ColorFilter::kG_Flag |
376                                SkTable_ColorFilter::kB_Flag | SkTable_ColorFilter::kA_Flag;
377    return ColorTableEffect::Create(textures[GrEffectUnitTest::kAlphaTextureIdx], kAllFlags);
378}
379
380GrEffectRef* SkTable_ColorFilter::asNewEffect(GrContext* context) const {
381    SkBitmap bitmap;
382    this->asComponentTable(&bitmap);
383    // passing NULL because this effect does no tiling or filtering.
384    GrTexture* texture = GrLockAndRefCachedBitmapTexture(context, bitmap, NULL);
385    GrEffectRef* effect = ColorTableEffect::Create(texture, fFlags);
386
387    // Unlock immediately, this is not great, but we don't have a way of
388    // knowing when else to unlock it currently. TODO: Remove this when
389    // unref becomes the unlock replacement for all types of textures.
390    GrUnlockAndUnrefCachedBitmapTexture(texture);
391    return effect;
392}
393
394#endif // SK_SUPPORT_GPU
395
396///////////////////////////////////////////////////////////////////////////////
397
398#ifdef SK_CPU_BENDIAN
399#else
400    #define SK_A32_INDEX    (3 - (SK_A32_SHIFT >> 3))
401    #define SK_R32_INDEX    (3 - (SK_R32_SHIFT >> 3))
402    #define SK_G32_INDEX    (3 - (SK_G32_SHIFT >> 3))
403    #define SK_B32_INDEX    (3 - (SK_B32_SHIFT >> 3))
404#endif
405
406///////////////////////////////////////////////////////////////////////////////
407
408SkColorFilter* SkTableColorFilter::Create(const uint8_t table[256]) {
409    return SkNEW_ARGS(SkTable_ColorFilter, (table, table, table, table));
410}
411
412SkColorFilter* SkTableColorFilter::CreateARGB(const uint8_t tableA[256],
413                                              const uint8_t tableR[256],
414                                              const uint8_t tableG[256],
415                                              const uint8_t tableB[256]) {
416    return SkNEW_ARGS(SkTable_ColorFilter, (tableA, tableR, tableG, tableB));
417}
418
419SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkTableColorFilter)
420    SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkTable_ColorFilter)
421SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
422