1 /* 2 * Copyright 2012 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 "Sk64.h" 9 #include "SkLazyPixelRef.h" 10 #include "SkColorTable.h" 11 #include "SkData.h" 12 #include "SkImageCache.h" 13 #include "SkImagePriv.h" 14 15 #if LAZY_CACHE_STATS 16 #include "SkThread.h" 17 18 int32_t SkLazyPixelRef::gCacheHits; 19 int32_t SkLazyPixelRef::gCacheMisses; 20 #endif 21 22 SkLazyPixelRef::SkLazyPixelRef(SkData* data, SkBitmapFactory::DecodeProc proc, SkImageCache* cache) 23 // Pass NULL for the Mutex so that the default (ring buffer) will be used. 24 : INHERITED(NULL) 25 , fDecodeProc(proc) 26 , fImageCache(cache) 27 , fCacheId(SkImageCache::UNINITIALIZED_ID) 28 , fRowBytes(0) { 29 SkASSERT(fDecodeProc != NULL); 30 if (NULL == data) { 31 fData = SkData::NewEmpty(); 32 fErrorInDecoding = true; 33 } else { 34 fData = data; 35 fData->ref(); 36 fErrorInDecoding = data->size() == 0; 37 } 38 SkASSERT(cache != NULL); 39 cache->ref(); 40 // Since this pixel ref bases its data on encoded data, it should never change. 41 this->setImmutable(); 42 } 43 44 SkLazyPixelRef::~SkLazyPixelRef() { 45 SkASSERT(fData != NULL); 46 fData->unref(); 47 SkASSERT(fImageCache); 48 if (fCacheId != SkImageCache::UNINITIALIZED_ID) { 49 fImageCache->throwAwayCache(fCacheId); 50 } 51 fImageCache->unref(); 52 } 53 54 static size_t ComputeMinRowBytesAndSize(const SkImage::Info& info, size_t* rowBytes) { 55 *rowBytes = SkImageMinRowBytes(info); 56 57 Sk64 safeSize; 58 safeSize.setZero(); 59 if (info.fHeight > 0) { 60 safeSize.setMul(info.fHeight, SkToS32(*rowBytes)); 61 } 62 SkASSERT(!safeSize.isNeg()); 63 return safeSize.is32() ? safeSize.get32() : 0; 64 } 65 66 void* SkLazyPixelRef::onLockPixels(SkColorTable**) { 67 if (fErrorInDecoding) { 68 return NULL; 69 } 70 SkBitmapFactory::Target target; 71 // Check to see if the pixels still exist in the cache. 72 if (SkImageCache::UNINITIALIZED_ID == fCacheId) { 73 target.fAddr = NULL; 74 } else { 75 SkImageCache::DataStatus status; 76 target.fAddr = fImageCache->pinCache(fCacheId, &status); 77 if (target.fAddr == NULL) { 78 fCacheId = SkImageCache::UNINITIALIZED_ID; 79 } else { 80 if (SkImageCache::kRetained_DataStatus == status) { 81 #if LAZY_CACHE_STATS 82 sk_atomic_inc(&gCacheHits); 83 #endif 84 return target.fAddr; 85 } 86 SkASSERT(SkImageCache::kUninitialized_DataStatus == status); 87 } 88 // Cache miss. Either pinCache returned NULL or it returned a memory address without the old 89 // data 90 #if LAZY_CACHE_STATS 91 sk_atomic_inc(&gCacheMisses); 92 #endif 93 } 94 SkImage::Info info; 95 SkASSERT(fData != NULL && fData->size() > 0); 96 if (NULL == target.fAddr) { 97 // Determine the size of the image in order to determine how much memory to allocate. 98 // FIXME: As an optimization, only do this part once. 99 fErrorInDecoding = !fDecodeProc(fData->data(), fData->size(), &info, NULL); 100 if (fErrorInDecoding) { 101 // We can only reach here if fCacheId was already set to UNINITIALIZED_ID, or if 102 // pinCache returned NULL, in which case it was reset to UNINITIALIZED_ID. 103 SkASSERT(SkImageCache::UNINITIALIZED_ID == fCacheId); 104 return NULL; 105 } 106 107 size_t bytes = ComputeMinRowBytesAndSize(info, &target.fRowBytes); 108 target.fAddr = fImageCache->allocAndPinCache(bytes, &fCacheId); 109 if (NULL == target.fAddr) { 110 // Space could not be allocated. 111 // Just like the last assert, fCacheId must be UNINITIALIZED_ID. 112 SkASSERT(SkImageCache::UNINITIALIZED_ID == fCacheId); 113 return NULL; 114 } 115 } else { 116 // pinCache returned purged memory to which target.fAddr already points. Set 117 // target.fRowBytes properly. 118 target.fRowBytes = fRowBytes; 119 // Assume that the size is correct, since it was determined by this same function 120 // previously. 121 } 122 SkASSERT(target.fAddr != NULL); 123 SkASSERT(SkImageCache::UNINITIALIZED_ID != fCacheId); 124 fErrorInDecoding = !fDecodeProc(fData->data(), fData->size(), &info, &target); 125 if (fErrorInDecoding) { 126 fImageCache->throwAwayCache(fCacheId); 127 fCacheId = SkImageCache::UNINITIALIZED_ID; 128 return NULL; 129 } 130 // Upon success, store fRowBytes so it can be used in case pinCache later returns purged memory. 131 fRowBytes = target.fRowBytes; 132 return target.fAddr; 133 } 134 135 void SkLazyPixelRef::onUnlockPixels() { 136 if (fErrorInDecoding) { 137 return; 138 } 139 if (fCacheId != SkImageCache::UNINITIALIZED_ID) { 140 fImageCache->releaseCache(fCacheId); 141 } 142 } 143 144 SkData* SkLazyPixelRef::onRefEncodedData() { 145 fData->ref(); 146 return fData; 147 } 148