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