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