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