Home | History | Annotate | Download | only in gpu
      1 /*
      2  * Copyright 2010 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "SkGr.h"
      9 #include "SkConfig8888.h"
     10 #include "SkMessageBus.h"
     11 #include "SkPixelRef.h"
     12 #include "GrResourceCache.h"
     13 
     14 /*  Fill out buffer with the compressed format Ganesh expects from a colortable
     15  based bitmap. [palette (colortable) + indices].
     16 
     17  At the moment Ganesh only supports 8bit version. If Ganesh allowed we others
     18  we could detect that the colortable.count is <= 16, and then repack the
     19  indices as nibbles to save RAM, but it would take more time (i.e. a lot
     20  slower than memcpy), so skipping that for now.
     21 
     22  Ganesh wants a full 256 palette entry, even though Skia's ctable is only as big
     23  as the colortable.count says it is.
     24  */
     25 static void build_compressed_data(void* buffer, const SkBitmap& bitmap) {
     26     SkASSERT(SkBitmap::kIndex8_Config == bitmap.config());
     27 
     28     SkAutoLockPixels alp(bitmap);
     29     if (!bitmap.readyToDraw()) {
     30         SkDEBUGFAIL("bitmap not ready to draw!");
     31         return;
     32     }
     33 
     34     SkColorTable* ctable = bitmap.getColorTable();
     35     char* dst = (char*)buffer;
     36 
     37     uint32_t* colorTableDst = reinterpret_cast<uint32_t*>(dst);
     38     const uint32_t* colorTableSrc = reinterpret_cast<const uint32_t*>(ctable->lockColors());
     39     SkConvertConfig8888Pixels(colorTableDst, 0, SkCanvas::kRGBA_Premul_Config8888,
     40                               colorTableSrc, 0, SkCanvas::kNative_Premul_Config8888,
     41                               ctable->count(), 1);
     42     ctable->unlockColors();
     43 
     44     // always skip a full 256 number of entries, even if we memcpy'd fewer
     45     dst += kGrColorTableSize;
     46 
     47     if ((unsigned)bitmap.width() == bitmap.rowBytes()) {
     48         memcpy(dst, bitmap.getPixels(), bitmap.getSize());
     49     } else {
     50         // need to trim off the extra bytes per row
     51         size_t width = bitmap.width();
     52         size_t rowBytes = bitmap.rowBytes();
     53         const char* src = (const char*)bitmap.getPixels();
     54         for (int y = 0; y < bitmap.height(); y++) {
     55             memcpy(dst, src, width);
     56             src += rowBytes;
     57             dst += width;
     58         }
     59     }
     60 }
     61 
     62 ////////////////////////////////////////////////////////////////////////////////
     63 
     64 static void generate_bitmap_cache_id(const SkBitmap& bitmap, GrCacheID* id) {
     65     // Our id includes the offset, width, and height so that bitmaps created by extractSubset()
     66     // are unique.
     67     uint32_t genID = bitmap.getGenerationID();
     68     size_t offset = bitmap.pixelRefOffset();
     69     int16_t width = static_cast<int16_t>(bitmap.width());
     70     int16_t height = static_cast<int16_t>(bitmap.height());
     71 
     72     GrCacheID::Key key;
     73     memcpy(key.fData8, &genID, 4);
     74     memcpy(key.fData8 + 4, &width, 2);
     75     memcpy(key.fData8 + 6, &height, 2);
     76     memcpy(key.fData8 + 8, &offset, sizeof(size_t));
     77     static const size_t kKeyDataSize = 8 + sizeof(size_t);
     78     memset(key.fData8 + kKeyDataSize, 0, sizeof(key) - kKeyDataSize);
     79     GR_STATIC_ASSERT(sizeof(key) >= 8 + sizeof(size_t));
     80     static const GrCacheID::Domain gBitmapTextureDomain = GrCacheID::GenerateDomain();
     81     id->reset(gBitmapTextureDomain, key);
     82 }
     83 
     84 static void generate_bitmap_texture_desc(const SkBitmap& bitmap, GrTextureDesc* desc) {
     85     desc->fFlags = kNone_GrTextureFlags;
     86     desc->fWidth = bitmap.width();
     87     desc->fHeight = bitmap.height();
     88     desc->fConfig = SkBitmapConfig2GrPixelConfig(bitmap.config());
     89     desc->fSampleCnt = 0;
     90 }
     91 
     92 namespace {
     93 
     94 // When the SkPixelRef genID changes, invalidate a corresponding GrResource described by key.
     95 class GrResourceInvalidator : public SkPixelRef::GenIDChangeListener {
     96 public:
     97     explicit GrResourceInvalidator(GrResourceKey key) : fKey(key) {}
     98 private:
     99     GrResourceKey fKey;
    100 
    101     virtual void onChange() SK_OVERRIDE {
    102         const GrResourceInvalidatedMessage message = { fKey };
    103         SkMessageBus<GrResourceInvalidatedMessage>::Post(message);
    104     }
    105 };
    106 
    107 }  // namespace
    108 
    109 static void add_genID_listener(GrResourceKey key, SkPixelRef* pixelRef) {
    110     SkASSERT(NULL != pixelRef);
    111     pixelRef->addGenIDChangeListener(SkNEW_ARGS(GrResourceInvalidator, (key)));
    112 }
    113 
    114 static GrTexture* sk_gr_create_bitmap_texture(GrContext* ctx,
    115                                               bool cache,
    116                                               const GrTextureParams* params,
    117                                               const SkBitmap& origBitmap) {
    118     SkBitmap tmpBitmap;
    119 
    120     const SkBitmap* bitmap = &origBitmap;
    121 
    122     GrTextureDesc desc;
    123     generate_bitmap_texture_desc(*bitmap, &desc);
    124 
    125     if (SkBitmap::kIndex8_Config == bitmap->config()) {
    126         // build_compressed_data doesn't do npot->pot expansion
    127         // and paletted textures can't be sub-updated
    128         if (ctx->supportsIndex8PixelConfig(params, bitmap->width(), bitmap->height())) {
    129             size_t imagesize = bitmap->width() * bitmap->height() + kGrColorTableSize;
    130             SkAutoMalloc storage(imagesize);
    131 
    132             build_compressed_data(storage.get(), origBitmap);
    133 
    134             // our compressed data will be trimmed, so pass width() for its
    135             // "rowBytes", since they are the same now.
    136 
    137             if (cache) {
    138                 GrCacheID cacheID;
    139                 generate_bitmap_cache_id(origBitmap, &cacheID);
    140 
    141                 GrResourceKey key;
    142                 GrTexture* result = ctx->createTexture(params, desc, cacheID,
    143                                                        storage.get(), bitmap->width(), &key);
    144                 if (NULL != result) {
    145                     add_genID_listener(key, origBitmap.pixelRef());
    146                 }
    147                 return result;
    148             } else {
    149                 GrTexture* result = ctx->lockAndRefScratchTexture(desc,
    150                                                             GrContext::kExact_ScratchTexMatch);
    151                 result->writePixels(0, 0, bitmap->width(),
    152                                     bitmap->height(), desc.fConfig,
    153                                     storage.get());
    154                 return result;
    155             }
    156         } else {
    157             origBitmap.copyTo(&tmpBitmap, SkBitmap::kARGB_8888_Config);
    158             // now bitmap points to our temp, which has been promoted to 32bits
    159             bitmap = &tmpBitmap;
    160             desc.fConfig = SkBitmapConfig2GrPixelConfig(bitmap->config());
    161         }
    162     }
    163 
    164     SkAutoLockPixels alp(*bitmap);
    165     if (!bitmap->readyToDraw()) {
    166         return NULL;
    167     }
    168     if (cache) {
    169         // This texture is likely to be used again so leave it in the cache
    170         GrCacheID cacheID;
    171         generate_bitmap_cache_id(origBitmap, &cacheID);
    172 
    173         GrResourceKey key;
    174         GrTexture* result = ctx->createTexture(params, desc, cacheID,
    175                                                bitmap->getPixels(), bitmap->rowBytes(), &key);
    176         if (NULL != result) {
    177             add_genID_listener(key, origBitmap.pixelRef());
    178         }
    179         return result;
    180    } else {
    181         // This texture is unlikely to be used again (in its present form) so
    182         // just use a scratch texture. This will remove the texture from the
    183         // cache so no one else can find it. Additionally, once unlocked, the
    184         // scratch texture will go to the end of the list for purging so will
    185         // likely be available for this volatile bitmap the next time around.
    186         GrTexture* result = ctx->lockAndRefScratchTexture(desc, GrContext::kExact_ScratchTexMatch);
    187         result->writePixels(0, 0,
    188                             bitmap->width(), bitmap->height(),
    189                             desc.fConfig,
    190                             bitmap->getPixels(),
    191                             bitmap->rowBytes());
    192         return result;
    193     }
    194 }
    195 
    196 bool GrIsBitmapInCache(const GrContext* ctx,
    197                        const SkBitmap& bitmap,
    198                        const GrTextureParams* params) {
    199     GrCacheID cacheID;
    200     generate_bitmap_cache_id(bitmap, &cacheID);
    201 
    202     GrTextureDesc desc;
    203     generate_bitmap_texture_desc(bitmap, &desc);
    204     return ctx->isTextureInCache(desc, cacheID, params);
    205 }
    206 
    207 GrTexture* GrLockAndRefCachedBitmapTexture(GrContext* ctx,
    208                                            const SkBitmap& bitmap,
    209                                            const GrTextureParams* params) {
    210     GrTexture* result = NULL;
    211 
    212     bool cache = !bitmap.isVolatile();
    213 
    214     if (cache) {
    215         // If the bitmap isn't changing try to find a cached copy first.
    216 
    217         GrCacheID cacheID;
    218         generate_bitmap_cache_id(bitmap, &cacheID);
    219 
    220         GrTextureDesc desc;
    221         generate_bitmap_texture_desc(bitmap, &desc);
    222 
    223         result = ctx->findAndRefTexture(desc, cacheID, params);
    224     }
    225     if (NULL == result) {
    226         result = sk_gr_create_bitmap_texture(ctx, cache, params, bitmap);
    227     }
    228     if (NULL == result) {
    229         GrPrintf("---- failed to create texture for cache [%d %d]\n",
    230                     bitmap.width(), bitmap.height());
    231     }
    232     return result;
    233 }
    234 
    235 void GrUnlockAndUnrefCachedBitmapTexture(GrTexture* texture) {
    236     SkASSERT(NULL != texture->getContext());
    237 
    238     texture->getContext()->unlockScratchTexture(texture);
    239     texture->unref();
    240 }
    241 
    242 ///////////////////////////////////////////////////////////////////////////////
    243 
    244 GrPixelConfig SkBitmapConfig2GrPixelConfig(SkBitmap::Config config) {
    245     switch (config) {
    246         case SkBitmap::kA8_Config:
    247             return kAlpha_8_GrPixelConfig;
    248         case SkBitmap::kIndex8_Config:
    249             return kIndex_8_GrPixelConfig;
    250         case SkBitmap::kRGB_565_Config:
    251             return kRGB_565_GrPixelConfig;
    252         case SkBitmap::kARGB_4444_Config:
    253             return kRGBA_4444_GrPixelConfig;
    254         case SkBitmap::kARGB_8888_Config:
    255             return kSkia8888_GrPixelConfig;
    256         default:
    257             // kNo_Config, kA1_Config missing
    258             return kUnknown_GrPixelConfig;
    259     }
    260 }
    261 
    262 bool GrPixelConfig2ColorType(GrPixelConfig config, SkColorType* ctOut) {
    263     SkColorType ct;
    264     switch (config) {
    265         case kAlpha_8_GrPixelConfig:
    266             ct = kAlpha_8_SkColorType;
    267             break;
    268         case kIndex_8_GrPixelConfig:
    269             ct = kIndex_8_SkColorType;
    270             break;
    271         case kRGB_565_GrPixelConfig:
    272             ct = kRGB_565_SkColorType;
    273             break;
    274         case kRGBA_4444_GrPixelConfig:
    275             ct = kARGB_4444_SkColorType;
    276             break;
    277         case kRGBA_8888_GrPixelConfig:
    278             ct = kRGBA_8888_SkColorType;
    279             break;
    280         case kBGRA_8888_GrPixelConfig:
    281             ct = kBGRA_8888_SkColorType;
    282             break;
    283         default:
    284             return false;
    285     }
    286     if (ctOut) {
    287         *ctOut = ct;
    288     }
    289     return true;
    290 }
    291