1096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger/*
2096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger * Copyright 2012 Google Inc.
3096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger *
4096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger * Use of this source code is governed by a BSD-style license that can be
5096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger * found in the LICENSE file.
6096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger */
7096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
8096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger#include "Sk64.h"
9096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger#include "SkLazyPixelRef.h"
10096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger#include "SkColorTable.h"
11096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger#include "SkData.h"
12096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger#include "SkImageCache.h"
13096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger#include "SkImagePriv.h"
14096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
15096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger#if LAZY_CACHE_STATS
16096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger#include "SkThread.h"
17096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
18096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenbergerint32_t SkLazyPixelRef::gCacheHits;
19096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenbergerint32_t SkLazyPixelRef::gCacheMisses;
20096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger#endif
21096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
22096defe64d408e54474fe19f418c95bf1a554fc7Derek SollenbergerSkLazyPixelRef::SkLazyPixelRef(SkData* data, SkBitmapFactory::DecodeProc proc, SkImageCache* cache)
23096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    // Pass NULL for the Mutex so that the default (ring buffer) will be used.
24096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    : INHERITED(NULL)
25096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    , fDecodeProc(proc)
26096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    , fImageCache(cache)
27096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    , fCacheId(SkImageCache::UNINITIALIZED_ID)
28096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    , fRowBytes(0) {
29096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    SkASSERT(fDecodeProc != NULL);
30096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    if (NULL == data) {
31096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        fData = SkData::NewEmpty();
32096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        fErrorInDecoding = true;
33096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    } else {
34096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        fData = data;
35096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        fData->ref();
36096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        fErrorInDecoding = data->size() == 0;
37096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    }
38096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    SkASSERT(cache != NULL);
39096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    cache->ref();
40096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    // Since this pixel ref bases its data on encoded data, it should never change.
41096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    this->setImmutable();
42096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger}
43096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
44096defe64d408e54474fe19f418c95bf1a554fc7Derek SollenbergerSkLazyPixelRef::~SkLazyPixelRef() {
45096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    SkASSERT(fData != NULL);
46096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    fData->unref();
47096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    SkASSERT(fImageCache);
48096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    if (fCacheId != SkImageCache::UNINITIALIZED_ID) {
49096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        fImageCache->throwAwayCache(fCacheId);
50096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    }
51096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    fImageCache->unref();
52096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger}
53096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
54096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenbergerstatic size_t ComputeMinRowBytesAndSize(const SkImage::Info& info, size_t* rowBytes) {
55096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    *rowBytes = SkImageMinRowBytes(info);
56096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
57096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    Sk64 safeSize;
58096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    safeSize.setZero();
59096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    if (info.fHeight > 0) {
60096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        safeSize.setMul(info.fHeight, SkToS32(*rowBytes));
61096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    }
62096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    SkASSERT(!safeSize.isNeg());
63096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    return safeSize.is32() ? safeSize.get32() : 0;
64096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger}
65096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
66096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenbergervoid* SkLazyPixelRef::onLockPixels(SkColorTable**) {
67096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    if (fErrorInDecoding) {
68096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        return NULL;
69096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    }
70096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    SkBitmapFactory::Target target;
71096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    // Check to see if the pixels still exist in the cache.
72096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    if (SkImageCache::UNINITIALIZED_ID == fCacheId) {
73096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        target.fAddr = NULL;
74096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    } else {
75096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        SkImageCache::DataStatus status;
76096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        target.fAddr = fImageCache->pinCache(fCacheId, &status);
77096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        if (target.fAddr == NULL) {
78096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            fCacheId = SkImageCache::UNINITIALIZED_ID;
79096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        } else {
80096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            if (SkImageCache::kRetained_DataStatus == status) {
81096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger#if LAZY_CACHE_STATS
82096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger                sk_atomic_inc(&gCacheHits);
83096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger#endif
84096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger                return target.fAddr;
85096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            }
86096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            SkASSERT(SkImageCache::kUninitialized_DataStatus == status);
87096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        }
88096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        // Cache miss. Either pinCache returned NULL or it returned a memory address without the old
89096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        // data
90096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger#if LAZY_CACHE_STATS
91096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        sk_atomic_inc(&gCacheMisses);
92096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger#endif
93096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    }
94096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    SkImage::Info info;
95096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    SkASSERT(fData != NULL && fData->size() > 0);
96096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    if (NULL == target.fAddr) {
97096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        // Determine the size of the image in order to determine how much memory to allocate.
98096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        // FIXME: As an optimization, only do this part once.
99096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        fErrorInDecoding = !fDecodeProc(fData->data(), fData->size(), &info, NULL);
100096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        if (fErrorInDecoding) {
101096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            // We can only reach here if fCacheId was already set to UNINITIALIZED_ID, or if
102096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            // pinCache returned NULL, in which case it was reset to UNINITIALIZED_ID.
103096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            SkASSERT(SkImageCache::UNINITIALIZED_ID == fCacheId);
104096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            return NULL;
105096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        }
106096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
107096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        size_t bytes = ComputeMinRowBytesAndSize(info, &target.fRowBytes);
108096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        target.fAddr = fImageCache->allocAndPinCache(bytes, &fCacheId);
109096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        if (NULL == target.fAddr) {
110096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            // Space could not be allocated.
111096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            // Just like the last assert, fCacheId must be UNINITIALIZED_ID.
112096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            SkASSERT(SkImageCache::UNINITIALIZED_ID == fCacheId);
113096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger            return NULL;
114096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        }
115096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    } else {
116096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        // pinCache returned purged memory to which target.fAddr already points. Set
117096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        // target.fRowBytes properly.
118096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        target.fRowBytes = fRowBytes;
119096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        // Assume that the size is correct, since it was determined by this same function
120096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        // previously.
121096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    }
122096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    SkASSERT(target.fAddr != NULL);
123096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    SkASSERT(SkImageCache::UNINITIALIZED_ID != fCacheId);
124096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    fErrorInDecoding = !fDecodeProc(fData->data(), fData->size(), &info, &target);
125096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    if (fErrorInDecoding) {
126096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        fImageCache->throwAwayCache(fCacheId);
127096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        fCacheId = SkImageCache::UNINITIALIZED_ID;
128096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        return NULL;
129096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    }
130096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    // Upon success, store fRowBytes so it can be used in case pinCache later returns purged memory.
131096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    fRowBytes = target.fRowBytes;
132096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    return target.fAddr;
133096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger}
134096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
135096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenbergervoid SkLazyPixelRef::onUnlockPixels() {
136096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    if (fErrorInDecoding) {
137096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        return;
138096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    }
139096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    if (fCacheId != SkImageCache::UNINITIALIZED_ID) {
140096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger        fImageCache->releaseCache(fCacheId);
141096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    }
142096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger}
143096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger
144096defe64d408e54474fe19f418c95bf1a554fc7Derek SollenbergerSkData* SkLazyPixelRef::onRefEncodedData() {
145096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    fData->ref();
146096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger    return fData;
147096defe64d408e54474fe19f418c95bf1a554fc7Derek Sollenberger}
148