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 SkBitmapProcShader::SkBitmapProcShader(SkReadBuffer& buffer)
     43         : INHERITED(buffer) {
     44     buffer.readBitmap(&fRawBitmap);
     45     fRawBitmap.setImmutable();
     46     fTileModeX = buffer.readUInt();
     47     fTileModeY = buffer.readUInt();
     48 }
     49 
     50 SkShader::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 
     66 void 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 
     74 static 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 
     79 bool SkBitmapProcShader::isOpaque() const {
     80     return fRawBitmap.isOpaque();
     81 }
     82 
     83 static 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 
    100 SkShader::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 
    126 size_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 
    132 SkBitmapProcShader::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 
    180 SkBitmapProcShader::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 
    197 void 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 
    242 SkShader::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 
    250 void 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)
    291 static 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 
    317 static 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 
    327 SkShader* 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
    357 void 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 
    385 bool 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 
    472 bool 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