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 "SkColorPriv.h"
9#include "SkReadBuffer.h"
10#include "SkWriteBuffer.h"
11#include "SkPixelRef.h"
12#include "SkErrorInternals.h"
13#include "SkBitmapProcShader.h"
14
15#if SK_SUPPORT_GPU
16#include "effects/GrSimpleTextureEffect.h"
17#include "effects/GrBicubicEffect.h"
18#endif
19
20bool SkBitmapProcShader::CanDo(const SkBitmap& bm, TileMode tx, TileMode ty) {
21    switch (bm.colorType()) {
22        case kAlpha_8_SkColorType:
23        case kRGB_565_SkColorType:
24        case kIndex_8_SkColorType:
25        case kN32_SkColorType:
26    //        if (tx == ty && (kClamp_TileMode == tx || kRepeat_TileMode == tx))
27                return true;
28        default:
29            break;
30    }
31    return false;
32}
33
34SkBitmapProcShader::SkBitmapProcShader(const SkBitmap& src, TileMode tmx, TileMode tmy,
35                                       const SkMatrix* localMatrix)
36        : INHERITED(localMatrix) {
37    fRawBitmap = src;
38    fTileModeX = (uint8_t)tmx;
39    fTileModeY = (uint8_t)tmy;
40}
41
42SkBitmapProcShader::SkBitmapProcShader(SkReadBuffer& buffer)
43        : INHERITED(buffer) {
44    buffer.readBitmap(&fRawBitmap);
45    fRawBitmap.setImmutable();
46    fTileModeX = buffer.readUInt();
47    fTileModeY = buffer.readUInt();
48}
49
50SkShader::BitmapType SkBitmapProcShader::asABitmap(SkBitmap* texture,
51                                                   SkMatrix* texM,
52                                                   TileMode xy[]) const {
53    if (texture) {
54        *texture = fRawBitmap;
55    }
56    if (texM) {
57        texM->reset();
58    }
59    if (xy) {
60        xy[0] = (TileMode)fTileModeX;
61        xy[1] = (TileMode)fTileModeY;
62    }
63    return kDefault_BitmapType;
64}
65
66void SkBitmapProcShader::flatten(SkWriteBuffer& buffer) const {
67    this->INHERITED::flatten(buffer);
68
69    buffer.writeBitmap(fRawBitmap);
70    buffer.writeUInt(fTileModeX);
71    buffer.writeUInt(fTileModeY);
72}
73
74static bool only_scale_and_translate(const SkMatrix& matrix) {
75    unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
76    return (matrix.getType() & ~mask) == 0;
77}
78
79bool SkBitmapProcShader::isOpaque() const {
80    return fRawBitmap.isOpaque();
81}
82
83static bool valid_for_drawing(const SkBitmap& bm) {
84    if (0 == bm.width() || 0 == bm.height()) {
85        return false;   // nothing to draw
86    }
87    if (NULL == bm.pixelRef()) {
88        return false;   // no pixels to read
89    }
90    if (kIndex_8_SkColorType == bm.colorType()) {
91        // ugh, I have to lock-pixels to inspect the colortable
92        SkAutoLockPixels alp(bm);
93        if (!bm.getColorTable()) {
94            return false;
95        }
96    }
97    return true;
98}
99
100SkShader::Context* SkBitmapProcShader::onCreateContext(const ContextRec& rec, void* storage) const {
101    if (!fRawBitmap.getTexture() && !valid_for_drawing(fRawBitmap)) {
102        return NULL;
103    }
104
105    SkMatrix totalInverse;
106    // Do this first, so we know the matrix can be inverted.
107    if (!this->computeTotalInverse(rec, &totalInverse)) {
108        return NULL;
109    }
110
111    void* stateStorage = (char*)storage + sizeof(BitmapProcShaderContext);
112    SkBitmapProcState* state = SkNEW_PLACEMENT(stateStorage, SkBitmapProcState);
113
114    SkASSERT(state);
115    state->fTileModeX = fTileModeX;
116    state->fTileModeY = fTileModeY;
117    state->fOrigBitmap = fRawBitmap;
118    if (!state->chooseProcs(totalInverse, *rec.fPaint)) {
119        state->~SkBitmapProcState();
120        return NULL;
121    }
122
123    return SkNEW_PLACEMENT_ARGS(storage, BitmapProcShaderContext, (*this, rec, state));
124}
125
126size_t SkBitmapProcShader::contextSize() const {
127    // The SkBitmapProcState is stored outside of the context object, with the context holding
128    // a pointer to it.
129    return sizeof(BitmapProcShaderContext) + sizeof(SkBitmapProcState);
130}
131
132SkBitmapProcShader::BitmapProcShaderContext::BitmapProcShaderContext(
133        const SkBitmapProcShader& shader, const ContextRec& rec, SkBitmapProcState* state)
134    : INHERITED(shader, rec)
135    , fState(state)
136{
137    const SkBitmap& bitmap = *fState->fBitmap;
138    bool bitmapIsOpaque = bitmap.isOpaque();
139
140    // update fFlags
141    uint32_t flags = 0;
142    if (bitmapIsOpaque && (255 == this->getPaintAlpha())) {
143        flags |= kOpaqueAlpha_Flag;
144    }
145
146    switch (bitmap.colorType()) {
147        case kRGB_565_SkColorType:
148            flags |= (kHasSpan16_Flag | kIntrinsicly16_Flag);
149            break;
150        case kIndex_8_SkColorType:
151        case kN32_SkColorType:
152            if (bitmapIsOpaque) {
153                flags |= kHasSpan16_Flag;
154            }
155            break;
156        case kAlpha_8_SkColorType:
157            break;  // never set kHasSpan16_Flag
158        default:
159            break;
160    }
161
162    if (rec.fPaint->isDither() && bitmap.colorType() != kRGB_565_SkColorType) {
163        // gradients can auto-dither in their 16bit sampler, but we don't so
164        // we clear the flag here.
165        flags &= ~kHasSpan16_Flag;
166    }
167
168    // if we're only 1-pixel high, and we don't rotate, then we can claim this
169    if (1 == bitmap.height() &&
170            only_scale_and_translate(this->getTotalInverse())) {
171        flags |= kConstInY32_Flag;
172        if (flags & kHasSpan16_Flag) {
173            flags |= kConstInY16_Flag;
174        }
175    }
176
177    fFlags = flags;
178}
179
180SkBitmapProcShader::BitmapProcShaderContext::~BitmapProcShaderContext() {
181    // The bitmap proc state has been created outside of the context on memory that will be freed
182    // elsewhere. Only call the destructor but leave the freeing of the memory to the caller.
183    fState->~SkBitmapProcState();
184}
185
186#define BUF_MAX     128
187
188#define TEST_BUFFER_OVERRITEx
189
190#ifdef TEST_BUFFER_OVERRITE
191    #define TEST_BUFFER_EXTRA   32
192    #define TEST_PATTERN    0x88888888
193#else
194    #define TEST_BUFFER_EXTRA   0
195#endif
196
197void SkBitmapProcShader::BitmapProcShaderContext::shadeSpan(int x, int y, SkPMColor dstC[],
198                                                            int count) {
199    const SkBitmapProcState& state = *fState;
200    if (state.getShaderProc32()) {
201        state.getShaderProc32()(state, x, y, dstC, count);
202        return;
203    }
204
205    uint32_t buffer[BUF_MAX + TEST_BUFFER_EXTRA];
206    SkBitmapProcState::MatrixProc   mproc = state.getMatrixProc();
207    SkBitmapProcState::SampleProc32 sproc = state.getSampleProc32();
208    int max = state.maxCountForBufferSize(sizeof(buffer[0]) * BUF_MAX);
209
210    SkASSERT(state.fBitmap->getPixels());
211    SkASSERT(state.fBitmap->pixelRef() == NULL ||
212             state.fBitmap->pixelRef()->isLocked());
213
214    for (;;) {
215        int n = count;
216        if (n > max) {
217            n = max;
218        }
219        SkASSERT(n > 0 && n < BUF_MAX*2);
220#ifdef TEST_BUFFER_OVERRITE
221        for (int i = 0; i < TEST_BUFFER_EXTRA; i++) {
222            buffer[BUF_MAX + i] = TEST_PATTERN;
223        }
224#endif
225        mproc(state, buffer, n, x, y);
226#ifdef TEST_BUFFER_OVERRITE
227        for (int j = 0; j < TEST_BUFFER_EXTRA; j++) {
228            SkASSERT(buffer[BUF_MAX + j] == TEST_PATTERN);
229        }
230#endif
231        sproc(state, buffer, n, dstC);
232
233        if ((count -= n) == 0) {
234            break;
235        }
236        SkASSERT(count > 0);
237        x += n;
238        dstC += n;
239    }
240}
241
242SkShader::Context::ShadeProc SkBitmapProcShader::BitmapProcShaderContext::asAShadeProc(void** ctx) {
243    if (fState->getShaderProc32()) {
244        *ctx = fState;
245        return (ShadeProc)fState->getShaderProc32();
246    }
247    return NULL;
248}
249
250void SkBitmapProcShader::BitmapProcShaderContext::shadeSpan16(int x, int y, uint16_t dstC[],
251                                                              int count) {
252    const SkBitmapProcState& state = *fState;
253    if (state.getShaderProc16()) {
254        state.getShaderProc16()(state, x, y, dstC, count);
255        return;
256    }
257
258    uint32_t buffer[BUF_MAX];
259    SkBitmapProcState::MatrixProc   mproc = state.getMatrixProc();
260    SkBitmapProcState::SampleProc16 sproc = state.getSampleProc16();
261    int max = state.maxCountForBufferSize(sizeof(buffer));
262
263    SkASSERT(state.fBitmap->getPixels());
264    SkASSERT(state.fBitmap->pixelRef() == NULL ||
265             state.fBitmap->pixelRef()->isLocked());
266
267    for (;;) {
268        int n = count;
269        if (n > max) {
270            n = max;
271        }
272        mproc(state, buffer, n, x, y);
273        sproc(state, buffer, n, dstC);
274
275        if ((count -= n) == 0) {
276            break;
277        }
278        x += n;
279        dstC += n;
280    }
281}
282
283///////////////////////////////////////////////////////////////////////////////
284
285#include "SkUnPreMultiply.h"
286#include "SkColorShader.h"
287#include "SkEmptyShader.h"
288
289// returns true and set color if the bitmap can be drawn as a single color
290// (for efficiency)
291static bool canUseColorShader(const SkBitmap& bm, SkColor* color) {
292    if (1 != bm.width() || 1 != bm.height()) {
293        return false;
294    }
295
296    SkAutoLockPixels alp(bm);
297    if (!bm.readyToDraw()) {
298        return false;
299    }
300
301    switch (bm.colorType()) {
302        case kN32_SkColorType:
303            *color = SkUnPreMultiply::PMColorToColor(*bm.getAddr32(0, 0));
304            return true;
305        case kRGB_565_SkColorType:
306            *color = SkPixel16ToColor(*bm.getAddr16(0, 0));
307            return true;
308        case kIndex_8_SkColorType:
309            *color = SkUnPreMultiply::PMColorToColor(bm.getIndex8Color(0, 0));
310            return true;
311        default: // just skip the other configs for now
312            break;
313    }
314    return false;
315}
316
317static bool bitmapIsTooBig(const SkBitmap& bm) {
318    // SkBitmapProcShader stores bitmap coordinates in a 16bit buffer, as it
319    // communicates between its matrix-proc and its sampler-proc. Until we can
320    // widen that, we have to reject bitmaps that are larger.
321    //
322    const int maxSize = 65535;
323
324    return bm.width() > maxSize || bm.height() > maxSize;
325}
326
327SkShader* CreateBitmapShader(const SkBitmap& src, SkShader::TileMode tmx,
328        SkShader::TileMode tmy, const SkMatrix* localMatrix, SkTBlitterAllocator* allocator) {
329    SkShader* shader;
330    SkColor color;
331    if (src.isNull() || bitmapIsTooBig(src)) {
332        if (NULL == allocator) {
333            shader = SkNEW(SkEmptyShader);
334        } else {
335            shader = allocator->createT<SkEmptyShader>();
336        }
337    }
338    else if (canUseColorShader(src, &color)) {
339        if (NULL == allocator) {
340            shader = SkNEW_ARGS(SkColorShader, (color));
341        } else {
342            shader = allocator->createT<SkColorShader>(color);
343        }
344    } else {
345        if (NULL == allocator) {
346            shader = SkNEW_ARGS(SkBitmapProcShader, (src, tmx, tmy, localMatrix));
347        } else {
348            shader = allocator->createT<SkBitmapProcShader>(src, tmx, tmy, localMatrix);
349        }
350    }
351    return shader;
352}
353
354///////////////////////////////////////////////////////////////////////////////
355
356#ifndef SK_IGNORE_TO_STRING
357void SkBitmapProcShader::toString(SkString* str) const {
358    static const char* gTileModeName[SkShader::kTileModeCount] = {
359        "clamp", "repeat", "mirror"
360    };
361
362    str->append("BitmapShader: (");
363
364    str->appendf("(%s, %s)",
365                 gTileModeName[fTileModeX],
366                 gTileModeName[fTileModeY]);
367
368    str->append(" ");
369    fRawBitmap.toString(str);
370
371    this->INHERITED::toString(str);
372
373    str->append(")");
374}
375#endif
376
377///////////////////////////////////////////////////////////////////////////////
378
379#if SK_SUPPORT_GPU
380
381#include "GrTextureAccess.h"
382#include "effects/GrSimpleTextureEffect.h"
383#include "SkGr.h"
384
385bool SkBitmapProcShader::asNewEffect(GrContext* context, const SkPaint& paint,
386                                     const SkMatrix* localMatrix, GrColor* grColor,
387                                     GrEffectRef** grEffect) const {
388    SkMatrix matrix;
389    matrix.setIDiv(fRawBitmap.width(), fRawBitmap.height());
390
391    SkMatrix lmInverse;
392    if (!this->getLocalMatrix().invert(&lmInverse)) {
393        return false;
394    }
395    if (localMatrix) {
396        SkMatrix inv;
397        if (!localMatrix->invert(&inv)) {
398            return false;
399        }
400        lmInverse.postConcat(inv);
401    }
402    matrix.preConcat(lmInverse);
403
404    SkShader::TileMode tm[] = {
405        (TileMode)fTileModeX,
406        (TileMode)fTileModeY,
407    };
408
409    // Must set wrap and filter on the sampler before requesting a texture. In two places below
410    // we check the matrix scale factors to determine how to interpret the filter quality setting.
411    // This completely ignores the complexity of the drawVertices case where explicit local coords
412    // are provided by the caller.
413    bool useBicubic = false;
414    GrTextureParams::FilterMode textureFilterMode;
415    switch(paint.getFilterLevel()) {
416        case SkPaint::kNone_FilterLevel:
417            textureFilterMode = GrTextureParams::kNone_FilterMode;
418            break;
419        case SkPaint::kLow_FilterLevel:
420            textureFilterMode = GrTextureParams::kBilerp_FilterMode;
421            break;
422        case SkPaint::kMedium_FilterLevel: {
423            SkMatrix matrix;
424            matrix.setConcat(context->getMatrix(), this->getLocalMatrix());
425            if (matrix.getMinScale() < SK_Scalar1) {
426                textureFilterMode = GrTextureParams::kMipMap_FilterMode;
427            } else {
428                // Don't trigger MIP level generation unnecessarily.
429                textureFilterMode = GrTextureParams::kBilerp_FilterMode;
430            }
431            break;
432        }
433        case SkPaint::kHigh_FilterLevel: {
434            SkMatrix matrix;
435            matrix.setConcat(context->getMatrix(), this->getLocalMatrix());
436            useBicubic = GrBicubicEffect::ShouldUseBicubic(matrix, &textureFilterMode);
437            break;
438        }
439        default:
440            SkErrorInternals::SetError( kInvalidPaint_SkError,
441                                        "Sorry, I don't understand the filtering "
442                                        "mode you asked for.  Falling back to "
443                                        "MIPMaps.");
444            textureFilterMode = GrTextureParams::kMipMap_FilterMode;
445            break;
446
447    }
448    GrTextureParams params(tm, textureFilterMode);
449    GrTexture* texture = GrLockAndRefCachedBitmapTexture(context, fRawBitmap, &params);
450
451    if (NULL == texture) {
452        SkErrorInternals::SetError( kInternalError_SkError,
453                                    "Couldn't convert bitmap to texture.");
454        return false;
455    }
456
457    *grColor = (kAlpha_8_SkColorType == fRawBitmap.colorType()) ? SkColor2GrColor(paint.getColor())
458                                        : SkColor2GrColorJustAlpha(paint.getColor());
459
460    if (useBicubic) {
461        *grEffect = GrBicubicEffect::Create(texture, matrix, tm);
462    } else {
463        *grEffect = GrSimpleTextureEffect::Create(texture, matrix, params);
464    }
465    GrUnlockAndUnrefCachedBitmapTexture(texture);
466
467    return true;
468}
469
470#else
471
472bool SkBitmapProcShader::asNewEffect(GrContext* context, const SkPaint& paint,
473                                     const SkMatrix* localMatrix, GrColor* grColor,
474                                     GrEffectRef** grEffect) const {
475    SkDEBUGFAIL("Should not call in GPU-less build");
476    return false;
477}
478
479#endif
480