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