SkBitmapProcShader.cpp revision f9ed6fe6c5a1d05d49925de3798397e2fbb1c185
1
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8#include "SkBitmapProcShader.h"
9#include "SkColorPriv.h"
10#include "SkFlattenableBuffers.h"
11#include "SkPixelRef.h"
12#include "SkErrorInternals.h"
13
14bool SkBitmapProcShader::CanDo(const SkBitmap& bm, TileMode tx, TileMode ty) {
15    switch (bm.config()) {
16        case SkBitmap::kA8_Config:
17        case SkBitmap::kRGB_565_Config:
18        case SkBitmap::kIndex8_Config:
19        case SkBitmap::kARGB_8888_Config:
20    //        if (tx == ty && (kClamp_TileMode == tx || kRepeat_TileMode == tx))
21                return true;
22        default:
23            break;
24    }
25    return false;
26}
27
28SkBitmapProcShader::SkBitmapProcShader(const SkBitmap& src,
29                                       TileMode tmx, TileMode tmy) {
30    fRawBitmap = src;
31    fState.fTileModeX = (uint8_t)tmx;
32    fState.fTileModeY = (uint8_t)tmy;
33    fFlags = 0; // computed in setContext
34}
35
36SkBitmapProcShader::SkBitmapProcShader(SkFlattenableReadBuffer& buffer)
37        : INHERITED(buffer) {
38    buffer.readBitmap(&fRawBitmap);
39    fRawBitmap.setImmutable();
40    fState.fTileModeX = buffer.readUInt();
41    fState.fTileModeY = buffer.readUInt();
42    fFlags = 0; // computed in setContext
43}
44
45SkShader::BitmapType SkBitmapProcShader::asABitmap(SkBitmap* texture,
46                                                   SkMatrix* texM,
47                                                   TileMode xy[]) const {
48    if (texture) {
49        *texture = fRawBitmap;
50    }
51    if (texM) {
52        texM->reset();
53    }
54    if (xy) {
55        xy[0] = (TileMode)fState.fTileModeX;
56        xy[1] = (TileMode)fState.fTileModeY;
57    }
58    return kDefault_BitmapType;
59}
60
61void SkBitmapProcShader::flatten(SkFlattenableWriteBuffer& buffer) const {
62    this->INHERITED::flatten(buffer);
63
64    buffer.writeBitmap(fRawBitmap);
65    buffer.writeUInt(fState.fTileModeX);
66    buffer.writeUInt(fState.fTileModeY);
67}
68
69static bool only_scale_and_translate(const SkMatrix& matrix) {
70    unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
71    return (matrix.getType() & ~mask) == 0;
72}
73
74bool SkBitmapProcShader::isOpaque() const {
75    return fRawBitmap.isOpaque();
76}
77
78bool SkBitmapProcShader::setContext(const SkBitmap& device,
79                                    const SkPaint& paint,
80                                    const SkMatrix& matrix) {
81    // do this first, so we have a correct inverse matrix
82    if (!this->INHERITED::setContext(device, paint, matrix)) {
83        return false;
84    }
85
86    fState.fOrigBitmap = fRawBitmap;
87    fState.fOrigBitmap.lockPixels();
88    if (!fState.fOrigBitmap.getTexture() && !fState.fOrigBitmap.readyToDraw()) {
89        fState.fOrigBitmap.unlockPixels();
90        this->INHERITED::endContext();
91        return false;
92    }
93
94    if (!fState.chooseProcs(this->getTotalInverse(), paint)) {
95        fState.fOrigBitmap.unlockPixels();
96        this->INHERITED::endContext();
97        return false;
98    }
99
100    const SkBitmap& bitmap = *fState.fBitmap;
101    bool bitmapIsOpaque = bitmap.isOpaque();
102
103    // update fFlags
104    uint32_t flags = 0;
105    if (bitmapIsOpaque && (255 == this->getPaintAlpha())) {
106        flags |= kOpaqueAlpha_Flag;
107    }
108
109    switch (bitmap.config()) {
110        case SkBitmap::kRGB_565_Config:
111            flags |= (kHasSpan16_Flag | kIntrinsicly16_Flag);
112            break;
113        case SkBitmap::kIndex8_Config:
114        case SkBitmap::kARGB_8888_Config:
115            if (bitmapIsOpaque) {
116                flags |= kHasSpan16_Flag;
117            }
118            break;
119        case SkBitmap::kA8_Config:
120            break;  // never set kHasSpan16_Flag
121        default:
122            break;
123    }
124
125    if (paint.isDither() && bitmap.config() != SkBitmap::kRGB_565_Config) {
126        // gradients can auto-dither in their 16bit sampler, but we don't so
127        // we clear the flag here.
128        flags &= ~kHasSpan16_Flag;
129    }
130
131    // if we're only 1-pixel high, and we don't rotate, then we can claim this
132    if (1 == bitmap.height() &&
133            only_scale_and_translate(this->getTotalInverse())) {
134        flags |= kConstInY32_Flag;
135        if (flags & kHasSpan16_Flag) {
136            flags |= kConstInY16_Flag;
137        }
138    }
139
140    fFlags = flags;
141    return true;
142}
143
144void SkBitmapProcShader::endContext() {
145    fState.fOrigBitmap.unlockPixels();
146    fState.endContext();
147    this->INHERITED::endContext();
148}
149
150#define BUF_MAX     128
151
152#define TEST_BUFFER_OVERRITEx
153
154#ifdef TEST_BUFFER_OVERRITE
155    #define TEST_BUFFER_EXTRA   32
156    #define TEST_PATTERN    0x88888888
157#else
158    #define TEST_BUFFER_EXTRA   0
159#endif
160
161void SkBitmapProcShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
162    const SkBitmapProcState& state = fState;
163    if (state.getShaderProc32()) {
164        state.getShaderProc32()(state, x, y, dstC, count);
165        return;
166    }
167
168    uint32_t buffer[BUF_MAX + TEST_BUFFER_EXTRA];
169    SkBitmapProcState::MatrixProc   mproc = state.getMatrixProc();
170    SkBitmapProcState::SampleProc32 sproc = state.getSampleProc32();
171    int max = fState.maxCountForBufferSize(sizeof(buffer[0]) * BUF_MAX);
172
173    SkASSERT(state.fBitmap->getPixels());
174    SkASSERT(state.fBitmap->pixelRef() == NULL ||
175             state.fBitmap->pixelRef()->isLocked());
176
177    for (;;) {
178        int n = count;
179        if (n > max) {
180            n = max;
181        }
182        SkASSERT(n > 0 && n < BUF_MAX*2);
183#ifdef TEST_BUFFER_OVERRITE
184        for (int i = 0; i < TEST_BUFFER_EXTRA; i++) {
185            buffer[BUF_MAX + i] = TEST_PATTERN;
186        }
187#endif
188        mproc(state, buffer, n, x, y);
189#ifdef TEST_BUFFER_OVERRITE
190        for (int j = 0; j < TEST_BUFFER_EXTRA; j++) {
191            SkASSERT(buffer[BUF_MAX + j] == TEST_PATTERN);
192        }
193#endif
194        sproc(state, buffer, n, dstC);
195
196        if ((count -= n) == 0) {
197            break;
198        }
199        SkASSERT(count > 0);
200        x += n;
201        dstC += n;
202    }
203}
204
205SkShader::ShadeProc SkBitmapProcShader::asAShadeProc(void** ctx) {
206    if (fState.getShaderProc32()) {
207        *ctx = &fState;
208        return (ShadeProc)fState.getShaderProc32();
209    }
210    return NULL;
211}
212
213void SkBitmapProcShader::shadeSpan16(int x, int y, uint16_t dstC[], int count) {
214    const SkBitmapProcState& state = fState;
215    if (state.getShaderProc16()) {
216        state.getShaderProc16()(state, x, y, dstC, count);
217        return;
218    }
219
220    uint32_t buffer[BUF_MAX];
221    SkBitmapProcState::MatrixProc   mproc = state.getMatrixProc();
222    SkBitmapProcState::SampleProc16 sproc = state.getSampleProc16();
223    int max = fState.maxCountForBufferSize(sizeof(buffer));
224
225    SkASSERT(state.fBitmap->getPixels());
226    SkASSERT(state.fBitmap->pixelRef() == NULL ||
227             state.fBitmap->pixelRef()->isLocked());
228
229    for (;;) {
230        int n = count;
231        if (n > max) {
232            n = max;
233        }
234        mproc(state, buffer, n, x, y);
235        sproc(state, buffer, n, dstC);
236
237        if ((count -= n) == 0) {
238            break;
239        }
240        x += n;
241        dstC += n;
242    }
243}
244
245///////////////////////////////////////////////////////////////////////////////
246
247#include "SkUnPreMultiply.h"
248#include "SkColorShader.h"
249#include "SkEmptyShader.h"
250
251// returns true and set color if the bitmap can be drawn as a single color
252// (for efficiency)
253static bool canUseColorShader(const SkBitmap& bm, SkColor* color) {
254    if (1 != bm.width() || 1 != bm.height()) {
255        return false;
256    }
257
258    SkAutoLockPixels alp(bm);
259    if (!bm.readyToDraw()) {
260        return false;
261    }
262
263    switch (bm.config()) {
264        case SkBitmap::kARGB_8888_Config:
265            *color = SkUnPreMultiply::PMColorToColor(*bm.getAddr32(0, 0));
266            return true;
267        case SkBitmap::kRGB_565_Config:
268            *color = SkPixel16ToColor(*bm.getAddr16(0, 0));
269            return true;
270        case SkBitmap::kIndex8_Config:
271            *color = SkUnPreMultiply::PMColorToColor(bm.getIndex8Color(0, 0));
272            return true;
273        default: // just skip the other configs for now
274            break;
275    }
276    return false;
277}
278
279#include "SkTemplatesPriv.h"
280
281static bool bitmapIsTooBig(const SkBitmap& bm) {
282    // SkBitmapProcShader stores bitmap coordinates in a 16bit buffer, as it
283    // communicates between its matrix-proc and its sampler-proc. Until we can
284    // widen that, we have to reject bitmaps that are larger.
285    //
286    const int maxSize = 65535;
287
288    return bm.width() > maxSize || bm.height() > maxSize;
289}
290
291SkShader* SkShader::CreateBitmapShader(const SkBitmap& src,
292                                       TileMode tmx, TileMode tmy,
293                                       void* storage, size_t storageSize) {
294    SkShader* shader;
295    SkColor color;
296    if (src.isNull() || bitmapIsTooBig(src)) {
297        SK_PLACEMENT_NEW(shader, SkEmptyShader, storage, storageSize);
298    }
299    else if (canUseColorShader(src, &color)) {
300        SK_PLACEMENT_NEW_ARGS(shader, SkColorShader, storage, storageSize,
301                              (color));
302    } else {
303        SK_PLACEMENT_NEW_ARGS(shader, SkBitmapProcShader, storage,
304                              storageSize, (src, tmx, tmy));
305    }
306    return shader;
307}
308
309///////////////////////////////////////////////////////////////////////////////
310
311#ifdef SK_DEVELOPER
312void SkBitmapProcShader::toString(SkString* str) const {
313    static const char* gTileModeName[SkShader::kTileModeCount] = {
314        "clamp", "repeat", "mirror"
315    };
316
317    str->append("BitmapShader: (");
318
319    str->appendf("(%s, %s)",
320                 gTileModeName[fState.fTileModeX],
321                 gTileModeName[fState.fTileModeY]);
322
323    str->append(" ");
324    fRawBitmap.toString(str);
325
326    this->INHERITED::toString(str);
327
328    str->append(")");
329}
330#endif
331
332///////////////////////////////////////////////////////////////////////////////
333
334#if SK_SUPPORT_GPU
335
336#include "GrTextureAccess.h"
337#include "effects/GrSimpleTextureEffect.h"
338#include "SkGr.h"
339
340GrEffectRef* SkBitmapProcShader::asNewEffect(GrContext* context, const SkPaint& paint) const {
341    SkMatrix matrix;
342    matrix.setIDiv(fRawBitmap.width(), fRawBitmap.height());
343
344    if (this->hasLocalMatrix()) {
345        SkMatrix inverse;
346        if (!this->getLocalMatrix().invert(&inverse)) {
347            return NULL;
348        }
349        matrix.preConcat(inverse);
350    }
351    SkShader::TileMode tm[] = {
352        (TileMode)fState.fTileModeX,
353        (TileMode)fState.fTileModeY,
354    };
355
356    // Must set wrap and filter on the sampler before requesting a texture.
357    SkPaint::FilterLevel paintFilterLevel = paint.getFilterLevel();
358    GrTextureParams::FilterMode textureFilterMode;
359    switch(paintFilterLevel) {
360        case SkPaint::kNone_FilterLevel:
361            textureFilterMode = GrTextureParams::kNone_FilterMode;
362            break;
363        case SkPaint::kLow_FilterLevel:
364            textureFilterMode = GrTextureParams::kBilerp_FilterMode;
365            break;
366        case SkPaint::kMedium_FilterLevel:
367            textureFilterMode = GrTextureParams::kMipMap_FilterMode;
368            break;
369        case SkPaint::kHigh_FilterLevel:
370            SkErrorInternals::SetError( kInvalidPaint_SkError,
371                                        "Sorry, I don't yet support high quality "
372                                        "filtering on the GPU; falling back to "
373                                        "MIPMaps.");
374            textureFilterMode = GrTextureParams::kMipMap_FilterMode;
375            break;
376        default:
377            SkErrorInternals::SetError( kInvalidPaint_SkError,
378                                        "Sorry, I don't understand the filtering "
379                                        "mode you asked for.  Falling back to "
380                                        "MIPMaps.");
381            textureFilterMode = GrTextureParams::kMipMap_FilterMode;
382            break;
383
384    }
385    GrTextureParams params(tm, textureFilterMode);
386    GrTexture* texture = GrLockAndRefCachedBitmapTexture(context, fRawBitmap, &params);
387
388    if (NULL == texture) {
389        SkDebugf("Couldn't convert bitmap to texture.\n");
390        return NULL;
391    }
392
393    GrEffectRef* effect = GrSimpleTextureEffect::Create(texture, matrix, params);
394    GrUnlockAndUnrefCachedBitmapTexture(texture);
395    return effect;
396}
397#endif
398