SkGr.cpp revision 50a3043194cf278a74ff51c33c6cdb52cbe1f8f9
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 */ 25static 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 64static 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 84static 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 92namespace { 93 94// When the SkPixelRef genID changes, invalidate a corresponding GrResource described by key. 95class GrResourceInvalidator : public SkPixelRef::GenIDChangeListener { 96public: 97 explicit GrResourceInvalidator(GrResourceKey key) : fKey(key) {} 98private: 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 109static void add_genID_listener(GrResourceKey key, SkPixelRef* pixelRef) { 110 SkASSERT(NULL != pixelRef); 111 pixelRef->addGenIDChangeListener(SkNEW_ARGS(GrResourceInvalidator, (key))); 112} 113 114static 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 add_genID_listener(key, origBitmap.pixelRef()); 145 return result; 146 } else { 147 GrTexture* result = ctx->lockAndRefScratchTexture(desc, 148 GrContext::kExact_ScratchTexMatch); 149 result->writePixels(0, 0, bitmap->width(), 150 bitmap->height(), desc.fConfig, 151 storage.get()); 152 return result; 153 } 154 } else { 155 origBitmap.copyTo(&tmpBitmap, SkBitmap::kARGB_8888_Config); 156 // now bitmap points to our temp, which has been promoted to 32bits 157 bitmap = &tmpBitmap; 158 desc.fConfig = SkBitmapConfig2GrPixelConfig(bitmap->config()); 159 } 160 } 161 162 SkAutoLockPixels alp(*bitmap); 163 if (!bitmap->readyToDraw()) { 164 return NULL; 165 } 166 if (cache) { 167 // This texture is likely to be used again so leave it in the cache 168 GrCacheID cacheID; 169 generate_bitmap_cache_id(origBitmap, &cacheID); 170 171 GrResourceKey key; 172 GrTexture* result = ctx->createTexture(params, desc, cacheID, 173 bitmap->getPixels(), bitmap->rowBytes(), &key); 174 add_genID_listener(key, origBitmap.pixelRef()); 175 return result; 176 } else { 177 // This texture is unlikely to be used again (in its present form) so 178 // just use a scratch texture. This will remove the texture from the 179 // cache so no one else can find it. Additionally, once unlocked, the 180 // scratch texture will go to the end of the list for purging so will 181 // likely be available for this volatile bitmap the next time around. 182 GrTexture* result = ctx->lockAndRefScratchTexture(desc, GrContext::kExact_ScratchTexMatch); 183 result->writePixels(0, 0, 184 bitmap->width(), bitmap->height(), 185 desc.fConfig, 186 bitmap->getPixels(), 187 bitmap->rowBytes()); 188 return result; 189 } 190} 191 192bool GrIsBitmapInCache(const GrContext* ctx, 193 const SkBitmap& bitmap, 194 const GrTextureParams* params) { 195 GrCacheID cacheID; 196 generate_bitmap_cache_id(bitmap, &cacheID); 197 198 GrTextureDesc desc; 199 generate_bitmap_texture_desc(bitmap, &desc); 200 return ctx->isTextureInCache(desc, cacheID, params); 201} 202 203GrTexture* GrLockAndRefCachedBitmapTexture(GrContext* ctx, 204 const SkBitmap& bitmap, 205 const GrTextureParams* params) { 206 GrTexture* result = NULL; 207 208 bool cache = !bitmap.isVolatile(); 209 210 if (cache) { 211 // If the bitmap isn't changing try to find a cached copy first. 212 213 GrCacheID cacheID; 214 generate_bitmap_cache_id(bitmap, &cacheID); 215 216 GrTextureDesc desc; 217 generate_bitmap_texture_desc(bitmap, &desc); 218 219 result = ctx->findAndRefTexture(desc, cacheID, params); 220 } 221 if (NULL == result) { 222 result = sk_gr_create_bitmap_texture(ctx, cache, params, bitmap); 223 } 224 if (NULL == result) { 225 GrPrintf("---- failed to create texture for cache [%d %d]\n", 226 bitmap.width(), bitmap.height()); 227 } 228 return result; 229} 230 231void GrUnlockAndUnrefCachedBitmapTexture(GrTexture* texture) { 232 SkASSERT(NULL != texture->getContext()); 233 234 texture->getContext()->unlockScratchTexture(texture); 235 texture->unref(); 236} 237 238/////////////////////////////////////////////////////////////////////////////// 239 240GrPixelConfig SkBitmapConfig2GrPixelConfig(SkBitmap::Config config) { 241 switch (config) { 242 case SkBitmap::kA8_Config: 243 return kAlpha_8_GrPixelConfig; 244 case SkBitmap::kIndex8_Config: 245 return kIndex_8_GrPixelConfig; 246 case SkBitmap::kRGB_565_Config: 247 return kRGB_565_GrPixelConfig; 248 case SkBitmap::kARGB_4444_Config: 249 return kRGBA_4444_GrPixelConfig; 250 case SkBitmap::kARGB_8888_Config: 251 return kSkia8888_GrPixelConfig; 252 default: 253 // kNo_Config, kA1_Config missing 254 return kUnknown_GrPixelConfig; 255 } 256} 257