Home | History | Annotate | Download | only in core
      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 
     20 bool 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 
     34 SkBitmapProcShader::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 
     42 SkShader::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 
     58 SkFlattenable* 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 
     71 void SkBitmapProcShader::flatten(SkWriteBuffer& buffer) const {
     72     buffer.writeMatrix(this->getLocalMatrix());
     73     buffer.writeBitmap(fRawBitmap);
     74     buffer.writeUInt(fTileModeX);
     75     buffer.writeUInt(fTileModeY);
     76 }
     77 
     78 static 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 
     83 bool SkBitmapProcShader::isOpaque() const {
     84     return fRawBitmap.isOpaque();
     85 }
     86 
     87 SkShader::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 
    109 size_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 
    115 SkBitmapProcShader::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 
    163 SkBitmapProcShader::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 
    180 void 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 
    225 SkShader::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 
    233 void 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)
    274 static 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 
    306 static 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 
    316 SkShader* 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
    347 void 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 
    375 bool 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 
    463 bool 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