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 "SkFlattenableBuffers.h"
     10 #include "SkPixelRef.h"
     11 #include "SkErrorInternals.h"
     12 #include "SkBitmapProcShader.h"
     13 
     14 #if SK_SUPPORT_GPU
     15 #include "effects/GrSimpleTextureEffect.h"
     16 #include "effects/GrBicubicEffect.h"
     17 #endif
     18 
     19 bool SkBitmapProcShader::CanDo(const SkBitmap& bm, TileMode tx, TileMode ty) {
     20     switch (bm.config()) {
     21         case SkBitmap::kA8_Config:
     22         case SkBitmap::kRGB_565_Config:
     23         case SkBitmap::kIndex8_Config:
     24         case SkBitmap::kARGB_8888_Config:
     25     //        if (tx == ty && (kClamp_TileMode == tx || kRepeat_TileMode == tx))
     26                 return true;
     27         default:
     28             break;
     29     }
     30     return false;
     31 }
     32 
     33 SkBitmapProcShader::SkBitmapProcShader(const SkBitmap& src,
     34                                        TileMode tmx, TileMode tmy) {
     35     fRawBitmap = src;
     36     fState.fTileModeX = (uint8_t)tmx;
     37     fState.fTileModeY = (uint8_t)tmy;
     38     fFlags = 0; // computed in setContext
     39 }
     40 
     41 SkBitmapProcShader::SkBitmapProcShader(SkFlattenableReadBuffer& buffer)
     42         : INHERITED(buffer) {
     43     buffer.readBitmap(&fRawBitmap);
     44     fRawBitmap.setImmutable();
     45     fState.fTileModeX = buffer.readUInt();
     46     fState.fTileModeY = buffer.readUInt();
     47     fFlags = 0; // computed in setContext
     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)fState.fTileModeX;
     61         xy[1] = (TileMode)fState.fTileModeY;
     62     }
     63     return kDefault_BitmapType;
     64 }
     65 
     66 void SkBitmapProcShader::flatten(SkFlattenableWriteBuffer& buffer) const {
     67     this->INHERITED::flatten(buffer);
     68 
     69     buffer.writeBitmap(fRawBitmap);
     70     buffer.writeUInt(fState.fTileModeX);
     71     buffer.writeUInt(fState.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 (SkBitmap::kIndex8_Config == bm.config()) {
     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 bool SkBitmapProcShader::setContext(const SkBitmap& device,
    101                                     const SkPaint& paint,
    102                                     const SkMatrix& matrix) {
    103     if (!fRawBitmap.getTexture() && !valid_for_drawing(fRawBitmap)) {
    104         return false;
    105     }
    106 
    107     // do this first, so we have a correct inverse matrix
    108     if (!this->INHERITED::setContext(device, paint, matrix)) {
    109         return false;
    110     }
    111 
    112     fState.fOrigBitmap = fRawBitmap;
    113     if (!fState.chooseProcs(this->getTotalInverse(), paint)) {
    114         this->INHERITED::endContext();
    115         return false;
    116     }
    117 
    118     const SkBitmap& bitmap = *fState.fBitmap;
    119     bool bitmapIsOpaque = bitmap.isOpaque();
    120 
    121     // update fFlags
    122     uint32_t flags = 0;
    123     if (bitmapIsOpaque && (255 == this->getPaintAlpha())) {
    124         flags |= kOpaqueAlpha_Flag;
    125     }
    126 
    127     switch (bitmap.config()) {
    128         case SkBitmap::kRGB_565_Config:
    129             flags |= (kHasSpan16_Flag | kIntrinsicly16_Flag);
    130             break;
    131         case SkBitmap::kIndex8_Config:
    132         case SkBitmap::kARGB_8888_Config:
    133             if (bitmapIsOpaque) {
    134                 flags |= kHasSpan16_Flag;
    135             }
    136             break;
    137         case SkBitmap::kA8_Config:
    138             break;  // never set kHasSpan16_Flag
    139         default:
    140             break;
    141     }
    142 
    143     if (paint.isDither() && bitmap.config() != SkBitmap::kRGB_565_Config) {
    144         // gradients can auto-dither in their 16bit sampler, but we don't so
    145         // we clear the flag here.
    146         flags &= ~kHasSpan16_Flag;
    147     }
    148 
    149     // if we're only 1-pixel high, and we don't rotate, then we can claim this
    150     if (1 == bitmap.height() &&
    151             only_scale_and_translate(this->getTotalInverse())) {
    152         flags |= kConstInY32_Flag;
    153         if (flags & kHasSpan16_Flag) {
    154             flags |= kConstInY16_Flag;
    155         }
    156     }
    157 
    158     fFlags = flags;
    159     return true;
    160 }
    161 
    162 void SkBitmapProcShader::endContext() {
    163     fState.endContext();
    164     this->INHERITED::endContext();
    165 }
    166 
    167 #define BUF_MAX     128
    168 
    169 #define TEST_BUFFER_OVERRITEx
    170 
    171 #ifdef TEST_BUFFER_OVERRITE
    172     #define TEST_BUFFER_EXTRA   32
    173     #define TEST_PATTERN    0x88888888
    174 #else
    175     #define TEST_BUFFER_EXTRA   0
    176 #endif
    177 
    178 void SkBitmapProcShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
    179     const SkBitmapProcState& state = fState;
    180     if (state.getShaderProc32()) {
    181         state.getShaderProc32()(state, x, y, dstC, count);
    182         return;
    183     }
    184 
    185     uint32_t buffer[BUF_MAX + TEST_BUFFER_EXTRA];
    186     SkBitmapProcState::MatrixProc   mproc = state.getMatrixProc();
    187     SkBitmapProcState::SampleProc32 sproc = state.getSampleProc32();
    188     int max = fState.maxCountForBufferSize(sizeof(buffer[0]) * BUF_MAX);
    189 
    190     SkASSERT(state.fBitmap->getPixels());
    191     SkASSERT(state.fBitmap->pixelRef() == NULL ||
    192              state.fBitmap->pixelRef()->isLocked());
    193 
    194     for (;;) {
    195         int n = count;
    196         if (n > max) {
    197             n = max;
    198         }
    199         SkASSERT(n > 0 && n < BUF_MAX*2);
    200 #ifdef TEST_BUFFER_OVERRITE
    201         for (int i = 0; i < TEST_BUFFER_EXTRA; i++) {
    202             buffer[BUF_MAX + i] = TEST_PATTERN;
    203         }
    204 #endif
    205         mproc(state, buffer, n, x, y);
    206 #ifdef TEST_BUFFER_OVERRITE
    207         for (int j = 0; j < TEST_BUFFER_EXTRA; j++) {
    208             SkASSERT(buffer[BUF_MAX + j] == TEST_PATTERN);
    209         }
    210 #endif
    211         sproc(state, buffer, n, dstC);
    212 
    213         if ((count -= n) == 0) {
    214             break;
    215         }
    216         SkASSERT(count > 0);
    217         x += n;
    218         dstC += n;
    219     }
    220 }
    221 
    222 SkShader::ShadeProc SkBitmapProcShader::asAShadeProc(void** ctx) {
    223     if (fState.getShaderProc32()) {
    224         *ctx = &fState;
    225         return (ShadeProc)fState.getShaderProc32();
    226     }
    227     return NULL;
    228 }
    229 
    230 void SkBitmapProcShader::shadeSpan16(int x, int y, uint16_t dstC[], int count) {
    231     const SkBitmapProcState& state = fState;
    232     if (state.getShaderProc16()) {
    233         state.getShaderProc16()(state, x, y, dstC, count);
    234         return;
    235     }
    236 
    237     uint32_t buffer[BUF_MAX];
    238     SkBitmapProcState::MatrixProc   mproc = state.getMatrixProc();
    239     SkBitmapProcState::SampleProc16 sproc = state.getSampleProc16();
    240     int max = fState.maxCountForBufferSize(sizeof(buffer));
    241 
    242     SkASSERT(state.fBitmap->getPixels());
    243     SkASSERT(state.fBitmap->pixelRef() == NULL ||
    244              state.fBitmap->pixelRef()->isLocked());
    245 
    246     for (;;) {
    247         int n = count;
    248         if (n > max) {
    249             n = max;
    250         }
    251         mproc(state, buffer, n, x, y);
    252         sproc(state, buffer, n, dstC);
    253 
    254         if ((count -= n) == 0) {
    255             break;
    256         }
    257         x += n;
    258         dstC += n;
    259     }
    260 }
    261 
    262 ///////////////////////////////////////////////////////////////////////////////
    263 
    264 #include "SkUnPreMultiply.h"
    265 #include "SkColorShader.h"
    266 #include "SkEmptyShader.h"
    267 
    268 // returns true and set color if the bitmap can be drawn as a single color
    269 // (for efficiency)
    270 static bool canUseColorShader(const SkBitmap& bm, SkColor* color) {
    271     if (1 != bm.width() || 1 != bm.height()) {
    272         return false;
    273     }
    274 
    275     SkAutoLockPixels alp(bm);
    276     if (!bm.readyToDraw()) {
    277         return false;
    278     }
    279 
    280     switch (bm.config()) {
    281         case SkBitmap::kARGB_8888_Config:
    282             *color = SkUnPreMultiply::PMColorToColor(*bm.getAddr32(0, 0));
    283             return true;
    284         case SkBitmap::kRGB_565_Config:
    285             *color = SkPixel16ToColor(*bm.getAddr16(0, 0));
    286             return true;
    287         case SkBitmap::kIndex8_Config:
    288             *color = SkUnPreMultiply::PMColorToColor(bm.getIndex8Color(0, 0));
    289             return true;
    290         default: // just skip the other configs for now
    291             break;
    292     }
    293     return false;
    294 }
    295 
    296 #include "SkTemplatesPriv.h"
    297 
    298 static bool bitmapIsTooBig(const SkBitmap& bm) {
    299     // SkBitmapProcShader stores bitmap coordinates in a 16bit buffer, as it
    300     // communicates between its matrix-proc and its sampler-proc. Until we can
    301     // widen that, we have to reject bitmaps that are larger.
    302     //
    303     const int maxSize = 65535;
    304 
    305     return bm.width() > maxSize || bm.height() > maxSize;
    306 }
    307 
    308 SkShader* SkShader::CreateBitmapShader(const SkBitmap& src,
    309                                        TileMode tmx, TileMode tmy,
    310                                        void* storage, size_t storageSize) {
    311     SkShader* shader;
    312     SkColor color;
    313     if (src.isNull() || bitmapIsTooBig(src)) {
    314         SK_PLACEMENT_NEW(shader, SkEmptyShader, storage, storageSize);
    315     }
    316     else if (canUseColorShader(src, &color)) {
    317         SK_PLACEMENT_NEW_ARGS(shader, SkColorShader, storage, storageSize,
    318                               (color));
    319     } else {
    320         SK_PLACEMENT_NEW_ARGS(shader, SkBitmapProcShader, storage,
    321                               storageSize, (src, tmx, tmy));
    322     }
    323     return shader;
    324 }
    325 
    326 ///////////////////////////////////////////////////////////////////////////////
    327 
    328 #ifdef SK_DEVELOPER
    329 void SkBitmapProcShader::toString(SkString* str) const {
    330     static const char* gTileModeName[SkShader::kTileModeCount] = {
    331         "clamp", "repeat", "mirror"
    332     };
    333 
    334     str->append("BitmapShader: (");
    335 
    336     str->appendf("(%s, %s)",
    337                  gTileModeName[fState.fTileModeX],
    338                  gTileModeName[fState.fTileModeY]);
    339 
    340     str->append(" ");
    341     fRawBitmap.toString(str);
    342 
    343     this->INHERITED::toString(str);
    344 
    345     str->append(")");
    346 }
    347 #endif
    348 
    349 ///////////////////////////////////////////////////////////////////////////////
    350 
    351 #if SK_SUPPORT_GPU
    352 
    353 #include "GrTextureAccess.h"
    354 #include "effects/GrSimpleTextureEffect.h"
    355 #include "SkGr.h"
    356 
    357 GrEffectRef* SkBitmapProcShader::asNewEffect(GrContext* context, const SkPaint& paint) const {
    358     SkMatrix matrix;
    359     matrix.setIDiv(fRawBitmap.width(), fRawBitmap.height());
    360 
    361     SkMatrix inverse;
    362     if (!this->getLocalMatrix().invert(&inverse)) {
    363         return NULL;
    364     }
    365     matrix.preConcat(inverse);
    366 
    367     SkShader::TileMode tm[] = {
    368         (TileMode)fState.fTileModeX,
    369         (TileMode)fState.fTileModeY,
    370     };
    371 
    372     // Must set wrap and filter on the sampler before requesting a texture.
    373     SkPaint::FilterLevel paintFilterLevel = paint.getFilterLevel();
    374     GrTextureParams::FilterMode textureFilterMode;
    375     switch(paintFilterLevel) {
    376         case SkPaint::kNone_FilterLevel:
    377             textureFilterMode = GrTextureParams::kNone_FilterMode;
    378             break;
    379         case SkPaint::kLow_FilterLevel:
    380             textureFilterMode = GrTextureParams::kBilerp_FilterMode;
    381             break;
    382         case SkPaint::kMedium_FilterLevel:
    383             textureFilterMode = GrTextureParams::kMipMap_FilterMode;
    384             break;
    385         case SkPaint::kHigh_FilterLevel:
    386             // Minification can look bad with the bicubic effect. This is an overly aggressive
    387             // check for MIP fallbacks. It doesn't consider the fact that minification in the local
    388             // matrix could be offset by the view matrix and vice versa. We also don't know whether
    389             // the draw has explicit local coords (e.g. drawVertices) where the scale factor is
    390             // unknown and varies.
    391             if (context->getMatrix().getMinStretch() >= SK_Scalar1 &&
    392                 this->getLocalMatrix().getMaxStretch() <= SK_Scalar1) {
    393                 // fall back to no filtering here; we will install another
    394                 // shader that will do the HQ filtering.
    395                 textureFilterMode = GrTextureParams::kNone_FilterMode;
    396             } else {
    397                 // Fall back to mip-mapping.
    398                 paintFilterLevel = SkPaint::kMedium_FilterLevel;
    399                 textureFilterMode = GrTextureParams::kMipMap_FilterMode;
    400             }
    401             break;
    402         default:
    403             SkErrorInternals::SetError( kInvalidPaint_SkError,
    404                                         "Sorry, I don't understand the filtering "
    405                                         "mode you asked for.  Falling back to "
    406                                         "MIPMaps.");
    407             textureFilterMode = GrTextureParams::kMipMap_FilterMode;
    408             break;
    409 
    410     }
    411     GrTextureParams params(tm, textureFilterMode);
    412     GrTexture* texture = GrLockAndRefCachedBitmapTexture(context, fRawBitmap, &params);
    413 
    414     if (NULL == texture) {
    415         SkErrorInternals::SetError( kInternalError_SkError,
    416                                     "Couldn't convert bitmap to texture.");
    417         return NULL;
    418     }
    419 
    420     GrEffectRef* effect = NULL;
    421     if (paintFilterLevel == SkPaint::kHigh_FilterLevel) {
    422         effect = GrBicubicEffect::Create(texture, matrix, tm);
    423     } else {
    424         effect = GrSimpleTextureEffect::Create(texture, matrix, params);
    425     }
    426     GrUnlockAndUnrefCachedBitmapTexture(texture);
    427     return effect;
    428 }
    429 #endif
    430