blob: 870056091f13c1d045ebed092045298187aabdf6 [file] [log] [blame]
scroggo@google.comf8d7d272013-02-22 21:38:35 +00001/*
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
scroggo@google.comcc690202013-03-04 19:56:21 +000015#if LAZY_CACHE_STATS
16#include "SkThread.h"
17
18int32_t SkLazyPixelRef::gCacheHits;
19int32_t SkLazyPixelRef::gCacheMisses;
20#endif
21
scroggo@google.comf8d7d272013-02-22 21:38:35 +000022SkLazyPixelRef::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)
scroggo@google.combb281f72013-03-18 21:37:39 +000027 , fCacheId(SkImageCache::UNINITIALIZED_ID)
28 , fRowBytes(0) {
scroggo@google.comf8d7d272013-02-22 21:38:35 +000029 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
44SkLazyPixelRef::~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
54static 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) {
scroggo@google.come5f48242013-02-25 21:47:41 +000060 safeSize.setMul(info.fHeight, SkToS32(*rowBytes));
scroggo@google.comf8d7d272013-02-22 21:38:35 +000061 }
62 SkASSERT(!safeSize.isNeg());
63 return safeSize.is32() ? safeSize.get32() : 0;
64}
65
66void* 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.
scroggo@google.comcc690202013-03-04 19:56:21 +000072 if (SkImageCache::UNINITIALIZED_ID == fCacheId) {
73 target.fAddr = NULL;
74 } else {
scroggo@google.combb281f72013-03-18 21:37:39 +000075 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) {
scroggo@google.comcc690202013-03-04 19:56:21 +000081#if LAZY_CACHE_STATS
scroggo@google.combb281f72013-03-18 21:37:39 +000082 sk_atomic_inc(&gCacheHits);
scroggo@google.comcc690202013-03-04 19:56:21 +000083#endif
scroggo@google.combb281f72013-03-18 21:37:39 +000084 return target.fAddr;
85 }
86 SkASSERT(SkImageCache::kUninitialized_DataStatus == status);
scroggo@google.comf8d7d272013-02-22 21:38:35 +000087 }
scroggo@google.combb281f72013-03-18 21:37:39 +000088 // Cache miss. Either pinCache returned NULL or it returned a memory address without the old
89 // data
scroggo@google.comcc690202013-03-04 19:56:21 +000090#if LAZY_CACHE_STATS
91 sk_atomic_inc(&gCacheMisses);
92#endif
93 }
scroggo@google.comcc690202013-03-04 19:56:21 +000094 SkImage::Info info;
95 SkASSERT(fData != NULL && fData->size() > 0);
scroggo@google.comcc690202013-03-04 19:56:21 +000096 if (NULL == target.fAddr) {
scroggo@google.combb281f72013-03-18 21:37:39 +000097 // 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.
scroggo@google.comcc690202013-03-04 19:56:21 +0000121 }
scroggo@google.combb281f72013-03-18 21:37:39 +0000122 SkASSERT(target.fAddr != NULL);
scroggo@google.comcc690202013-03-04 19:56:21 +0000123 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;
scroggo@google.comf8d7d272013-02-22 21:38:35 +0000129 }
scroggo@google.combb281f72013-03-18 21:37:39 +0000130 // Upon success, store fRowBytes so it can be used in case pinCache later returns purged memory.
131 fRowBytes = target.fRowBytes;
scroggo@google.comf8d7d272013-02-22 21:38:35 +0000132 return target.fAddr;
133}
134
135void SkLazyPixelRef::onUnlockPixels() {
136 if (fErrorInDecoding) {
137 return;
138 }
139 if (fCacheId != SkImageCache::UNINITIALIZED_ID) {
140 fImageCache->releaseCache(fCacheId);
141 }
142}
143
144SkData* SkLazyPixelRef::onRefEncodedData() {
145 fData->ref();
146 return fData;
147}
reed@google.comcee9dcb2013-09-13 16:04:49 +0000148
149#include "SkImagePriv.h"
150
151static bool init_from_info(SkBitmap* bm, const SkImage::Info& info,
152 size_t rowBytes) {
153 bool isOpaque;
154 SkBitmap::Config config = SkImageInfoToBitmapConfig(info, &isOpaque);
155 if (SkBitmap::kNo_Config == config) {
156 return false;
157 }
158
159 bm->setConfig(config, info.fWidth, info.fHeight, rowBytes);
160 bm->setIsOpaque(isOpaque);
161 return bm->allocPixels();
162}
163
164bool SkLazyPixelRef::onImplementsDecodeInto() {
165 return true;
166}
167
168bool SkLazyPixelRef::onDecodeInto(int pow2, SkBitmap* bitmap) {
169 SkASSERT(fData != NULL && fData->size() > 0);
170 if (fErrorInDecoding) {
171 return false;
172 }
173
174 SkImage::Info info;
175 // Determine the size of the image in order to determine how much memory to allocate.
176 // FIXME: As an optimization, only do this part once.
177 fErrorInDecoding = !fDecodeProc(fData->data(), fData->size(), &info, NULL);
178 if (fErrorInDecoding) {
179 return false;
180 }
robertphillips@google.com24ddde92013-09-16 14:04:05 +0000181
reed@google.comcee9dcb2013-09-13 16:04:49 +0000182 SkBitmapFactory::Target target;
183 (void)ComputeMinRowBytesAndSize(info, &target.fRowBytes);
robertphillips@google.com24ddde92013-09-16 14:04:05 +0000184
reed@google.comcee9dcb2013-09-13 16:04:49 +0000185 SkBitmap tmp;
186 if (!init_from_info(&tmp, info, target.fRowBytes)) {
187 return false;
188 }
robertphillips@google.com24ddde92013-09-16 14:04:05 +0000189
reed@google.comcee9dcb2013-09-13 16:04:49 +0000190 target.fAddr = tmp.getPixels();
191 fErrorInDecoding = !fDecodeProc(fData->data(), fData->size(), &info, &target);
192 if (fErrorInDecoding) {
193 return false;
194 }
195
196 *bitmap = tmp;
197 return true;
198}
robertphillips@google.com24ddde92013-09-16 14:04:05 +0000199
200