Home | History | Annotate | Download | only in lazy
      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