Home | History | Annotate | Download | only in gpu
      1 
      2 /*
      3  * Copyright 2010 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 
      9 
     10 
     11 #include "SkGr.h"
     12 
     13 /*  Fill out buffer with the compressed format Ganesh expects from a colortable
     14  based bitmap. [palette (colortable) + indices].
     15 
     16  At the moment Ganesh only supports 8bit version. If Ganesh allowed we others
     17  we could detect that the colortable.count is <= 16, and then repack the
     18  indices as nibbles to save RAM, but it would take more time (i.e. a lot
     19  slower than memcpy), so skipping that for now.
     20 
     21  Ganesh wants a full 256 palette entry, even though Skia's ctable is only as big
     22  as the colortable.count says it is.
     23  */
     24 static void build_compressed_data(void* buffer, const SkBitmap& bitmap) {
     25     SkASSERT(SkBitmap::kIndex8_Config == bitmap.config());
     26 
     27     SkAutoLockPixels apl(bitmap);
     28     if (!bitmap.readyToDraw()) {
     29         SkDEBUGFAIL("bitmap not ready to draw!");
     30         return;
     31     }
     32 
     33     SkColorTable* ctable = bitmap.getColorTable();
     34     char* dst = (char*)buffer;
     35 
     36     memcpy(dst, ctable->lockColors(), ctable->count() * sizeof(SkPMColor));
     37     ctable->unlockColors(false);
     38 
     39     // always skip a full 256 number of entries, even if we memcpy'd fewer
     40     dst += kGrColorTableSize;
     41 
     42     if (bitmap.width() == bitmap.rowBytes()) {
     43         memcpy(dst, bitmap.getPixels(), bitmap.getSize());
     44     } else {
     45         // need to trim off the extra bytes per row
     46         size_t width = bitmap.width();
     47         size_t rowBytes = bitmap.rowBytes();
     48         const char* src = (const char*)bitmap.getPixels();
     49         for (int y = 0; y < bitmap.height(); y++) {
     50             memcpy(dst, src, width);
     51             src += rowBytes;
     52             dst += width;
     53         }
     54     }
     55 }
     56 
     57 ////////////////////////////////////////////////////////////////////////////////
     58 
     59 static void generate_bitmap_cache_id(const SkBitmap& bitmap, GrCacheID* id) {
     60     // Our id includes the offset, width, and height so that bitmaps created by extractSubset()
     61     // are unique.
     62     uint32_t genID = bitmap.getGenerationID();
     63     size_t offset = bitmap.pixelRefOffset();
     64     int16_t width = static_cast<int16_t>(bitmap.width());
     65     int16_t height = static_cast<int16_t>(bitmap.height());
     66 
     67     GrCacheID::Key key;
     68     memcpy(key.fData8, &genID, 4);
     69     memcpy(key.fData8 + 4, &width, 2);
     70     memcpy(key.fData8 + 6, &height, 2);
     71     memcpy(key.fData8 + 8, &offset, sizeof(size_t));
     72     static const size_t kKeyDataSize = 8 + sizeof(size_t);
     73     memset(key.fData8 + kKeyDataSize, 0, sizeof(key) - kKeyDataSize);
     74     GR_STATIC_ASSERT(sizeof(key) >= 8 + sizeof(size_t));
     75     static const GrCacheID::Domain gBitmapTextureDomain = GrCacheID::GenerateDomain();
     76     id->reset(gBitmapTextureDomain, key);
     77 }
     78 
     79 static void generate_bitmap_texture_desc(const SkBitmap& bitmap, GrTextureDesc* desc) {
     80     desc->fFlags = kNone_GrTextureFlags;
     81     desc->fWidth = bitmap.width();
     82     desc->fHeight = bitmap.height();
     83     desc->fConfig = SkBitmapConfig2GrPixelConfig(bitmap.config());
     84     desc->fSampleCnt = 0;
     85 }
     86 
     87 static GrTexture* sk_gr_create_bitmap_texture(GrContext* ctx,
     88                                               bool cache,
     89                                               const GrTextureParams* params,
     90                                               const SkBitmap& origBitmap) {
     91     SkAutoLockPixels alp(origBitmap);
     92 
     93     if (!origBitmap.readyToDraw()) {
     94         return NULL;
     95     }
     96 
     97     SkBitmap tmpBitmap;
     98 
     99     const SkBitmap* bitmap = &origBitmap;
    100 
    101     GrTextureDesc desc;
    102     generate_bitmap_texture_desc(*bitmap, &desc);
    103 
    104     if (SkBitmap::kIndex8_Config == bitmap->config()) {
    105         // build_compressed_data doesn't do npot->pot expansion
    106         // and paletted textures can't be sub-updated
    107         if (ctx->supportsIndex8PixelConfig(params,
    108                                            bitmap->width(), bitmap->height())) {
    109             size_t imagesize = bitmap->width() * bitmap->height() +
    110                                 kGrColorTableSize;
    111             SkAutoMalloc storage(imagesize);
    112 
    113             build_compressed_data(storage.get(), origBitmap);
    114 
    115             // our compressed data will be trimmed, so pass width() for its
    116             // "rowBytes", since they are the same now.
    117 
    118             if (cache) {
    119                 GrCacheID cacheID;
    120                 generate_bitmap_cache_id(origBitmap, &cacheID);
    121                 return ctx->createTexture(params, desc, cacheID, storage.get(), bitmap->width());
    122             } else {
    123                 GrTexture* result = ctx->lockAndRefScratchTexture(desc,
    124                                                             GrContext::kExact_ScratchTexMatch);
    125                 result->writePixels(0, 0, bitmap->width(),
    126                                     bitmap->height(), desc.fConfig,
    127                                     storage.get());
    128                 return result;
    129             }
    130         } else {
    131             origBitmap.copyTo(&tmpBitmap, SkBitmap::kARGB_8888_Config);
    132             // now bitmap points to our temp, which has been promoted to 32bits
    133             bitmap = &tmpBitmap;
    134             desc.fConfig = SkBitmapConfig2GrPixelConfig(bitmap->config());
    135         }
    136     }
    137 
    138     if (cache) {
    139         // This texture is likely to be used again so leave it in the cache
    140         GrCacheID cacheID;
    141         generate_bitmap_cache_id(origBitmap, &cacheID);
    142         return ctx->createTexture(params, desc, cacheID, bitmap->getPixels(), bitmap->rowBytes());
    143     } else {
    144         // This texture is unlikely to be used again (in its present form) so
    145         // just use a scratch texture. This will remove the texture from the
    146         // cache so no one else can find it. Additionally, once unlocked, the
    147         // scratch texture will go to the end of the list for purging so will
    148         // likely be available for this volatile bitmap the next time around.
    149         GrTexture* result = ctx->lockAndRefScratchTexture(desc, GrContext::kExact_ScratchTexMatch);
    150         result->writePixels(0, 0,
    151                             bitmap->width(), bitmap->height(),
    152                             desc.fConfig,
    153                             bitmap->getPixels(),
    154                             bitmap->rowBytes());
    155         return result;
    156     }
    157 }
    158 
    159 bool GrIsBitmapInCache(const GrContext* ctx,
    160                        const SkBitmap& bitmap,
    161                        const GrTextureParams* params) {
    162     GrCacheID cacheID;
    163     generate_bitmap_cache_id(bitmap, &cacheID);
    164 
    165     GrTextureDesc desc;
    166     generate_bitmap_texture_desc(bitmap, &desc);
    167     return ctx->isTextureInCache(desc, cacheID, params);
    168 }
    169 
    170 GrTexture* GrLockAndRefCachedBitmapTexture(GrContext* ctx,
    171                                            const SkBitmap& bitmap,
    172                                            const GrTextureParams* params) {
    173     GrTexture* result = NULL;
    174 
    175     bool cache = !bitmap.isVolatile();
    176 
    177     if (cache) {
    178         // If the bitmap isn't changing try to find a cached copy first.
    179 
    180         GrCacheID cacheID;
    181         generate_bitmap_cache_id(bitmap, &cacheID);
    182 
    183         GrTextureDesc desc;
    184         generate_bitmap_texture_desc(bitmap, &desc);
    185 
    186         result = ctx->findAndRefTexture(desc, cacheID, params);
    187     }
    188     if (NULL == result) {
    189         result = sk_gr_create_bitmap_texture(ctx, cache, params, bitmap);
    190     }
    191     if (NULL == result) {
    192         GrPrintf("---- failed to create texture for cache [%d %d]\n",
    193                     bitmap.width(), bitmap.height());
    194     }
    195     return result;
    196 }
    197 
    198 void GrUnlockAndUnrefCachedBitmapTexture(GrTexture* texture) {
    199     GrAssert(NULL != texture->getContext());
    200 
    201     texture->getContext()->unlockScratchTexture(texture);
    202     texture->unref();
    203 }
    204 
    205 ///////////////////////////////////////////////////////////////////////////////
    206 
    207 GrPixelConfig SkBitmapConfig2GrPixelConfig(SkBitmap::Config config) {
    208     switch (config) {
    209         case SkBitmap::kA8_Config:
    210             return kAlpha_8_GrPixelConfig;
    211         case SkBitmap::kIndex8_Config:
    212             return kIndex_8_GrPixelConfig;
    213         case SkBitmap::kRGB_565_Config:
    214             return kRGB_565_GrPixelConfig;
    215         case SkBitmap::kARGB_4444_Config:
    216             return kRGBA_4444_GrPixelConfig;
    217         case SkBitmap::kARGB_8888_Config:
    218             return kSkia8888_PM_GrPixelConfig;
    219         default:
    220             // kNo_Config, kA1_Config missing, and kRLE_Index8_Config
    221             return kUnknown_GrPixelConfig;
    222     }
    223 }
    224