blob: a6c72a38080513d5e365744145eca17d905b1767 [file] [log] [blame]
Romain Guyce0537b2010-06-29 21:05:21 -07001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <GLES2/gl2.h>
18
Romain Guyca89e2a2013-03-08 17:44:20 -080019#include <utils/Mutex.h>
Romain Guy9aaa8262010-09-08 15:15:43 -070020
John Reckebd52612014-12-10 16:47:36 -080021#include "AssetAtlas.h"
Romain Guy713e1bb2012-10-16 18:44:09 -070022#include "Caches.h"
Tom Hudson2dc236b2014-10-15 15:46:42 -040023#include "Texture.h"
Romain Guyce0537b2010-06-29 21:05:21 -070024#include "TextureCache.h"
Romain Guyfb8b7632010-08-23 21:05:08 -070025#include "Properties.h"
Chris Craik70850ea2014-11-18 10:49:23 -080026#include "utils/TraceUtils.h"
Romain Guyce0537b2010-06-29 21:05:21 -070027
28namespace android {
29namespace uirenderer {
30
Romain Guy121e22422010-07-01 18:26:52 -070031///////////////////////////////////////////////////////////////////////////////
32// Constructors/destructor
33///////////////////////////////////////////////////////////////////////////////
34
Chris Craik117bdbc2015-02-05 10:12:38 -080035TextureCache::TextureCache()
36 : mCache(LruCache<uint32_t, Texture*>::kUnlimitedCapacity)
37 , mSize(0)
38 , mMaxSize(MB(DEFAULT_TEXTURE_CACHE_SIZE))
39 , mFlushRate(DEFAULT_TEXTURE_CACHE_FLUSH_RATE)
40 , mAssetAtlas(nullptr) {
Romain Guyfb8b7632010-08-23 21:05:08 -070041 char property[PROPERTY_VALUE_MAX];
Chris Craikd41c4d82015-01-05 15:51:13 -080042 if (property_get(PROPERTY_TEXTURE_CACHE_SIZE, property, nullptr) > 0) {
Romain Guyc9855a52011-01-21 21:14:15 -080043 INIT_LOGD(" Setting texture cache size to %sMB", property);
Romain Guyfb8b7632010-08-23 21:05:08 -070044 setMaxSize(MB(atof(property)));
45 } else {
Romain Guyc9855a52011-01-21 21:14:15 -080046 INIT_LOGD(" Using default texture cache size of %.2fMB", DEFAULT_TEXTURE_CACHE_SIZE);
Romain Guyfb8b7632010-08-23 21:05:08 -070047 }
48
Chris Craikd41c4d82015-01-05 15:51:13 -080049 if (property_get(PROPERTY_TEXTURE_CACHE_FLUSH_RATE, property, nullptr) > 0) {
Romain Guyeca0ca22011-11-04 15:12:29 -070050 float flushRate = atof(property);
51 INIT_LOGD(" Setting texture cache flush rate to %.2f%%", flushRate * 100.0f);
52 setFlushRate(flushRate);
53 } else {
54 INIT_LOGD(" Using default texture cache flush rate of %.2f%%",
55 DEFAULT_TEXTURE_CACHE_FLUSH_RATE * 100.0f);
56 }
57
Romain Guyfb8b7632010-08-23 21:05:08 -070058 mCache.setOnEntryRemovedListener(this);
59
60 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
Romain Guyf6834472011-01-23 13:32:12 -080061 INIT_LOGD(" Maximum texture dimension is %d pixels", mMaxTextureSize);
Romain Guye190aa62010-11-10 19:01:29 -080062
Chris Craik2507c342015-05-04 14:36:49 -070063 mDebugEnabled = Properties::debugLevel & kDebugCaches;
Romain Guyfb8b7632010-08-23 21:05:08 -070064}
65
Chris Craik117bdbc2015-02-05 10:12:38 -080066TextureCache::~TextureCache() {
67 mCache.clear();
68}
69
Romain Guy121e22422010-07-01 18:26:52 -070070///////////////////////////////////////////////////////////////////////////////
71// Size management
72///////////////////////////////////////////////////////////////////////////////
73
Romain Guy7d139ba2010-07-02 11:20:34 -070074uint32_t TextureCache::getSize() {
Romain Guy121e22422010-07-01 18:26:52 -070075 return mSize;
76}
77
Romain Guy7d139ba2010-07-02 11:20:34 -070078uint32_t TextureCache::getMaxSize() {
Romain Guy121e22422010-07-01 18:26:52 -070079 return mMaxSize;
80}
81
Romain Guy7d139ba2010-07-02 11:20:34 -070082void TextureCache::setMaxSize(uint32_t maxSize) {
Romain Guy121e22422010-07-01 18:26:52 -070083 mMaxSize = maxSize;
84 while (mSize > mMaxSize) {
85 mCache.removeOldest();
Romain Guyce0537b2010-06-29 21:05:21 -070086 }
87}
88
Romain Guyeca0ca22011-11-04 15:12:29 -070089void TextureCache::setFlushRate(float flushRate) {
Chris Craikdf72b632015-06-30 17:56:13 -070090 mFlushRate = std::max(0.0f, std::min(1.0f, flushRate));
Romain Guyeca0ca22011-11-04 15:12:29 -070091}
92
Romain Guy121e22422010-07-01 18:26:52 -070093///////////////////////////////////////////////////////////////////////////////
94// Callbacks
95///////////////////////////////////////////////////////////////////////////////
96
John Reck71d08a02014-11-24 15:21:28 -080097void TextureCache::operator()(uint32_t&, Texture*& texture) {
Romain Guy9aaa8262010-09-08 15:15:43 -070098 // This will be called already locked
Romain Guy121e22422010-07-01 18:26:52 -070099 if (texture) {
Romain Guy9aaa8262010-09-08 15:15:43 -0700100 mSize -= texture->bitmapSize;
Romain Guy9e108412010-11-09 14:35:20 -0800101 TEXTURE_LOGD("TextureCache::callback: name, removed size, mSize = %d, %d, %d",
102 texture->id, texture->bitmapSize, mSize);
Romain Guye190aa62010-11-10 19:01:29 -0800103 if (mDebugEnabled) {
Steve Block5baa3a62011-12-20 16:23:08 +0000104 ALOGD("Texture deleted, size = %d", texture->bitmapSize);
Romain Guye190aa62010-11-10 19:01:29 -0800105 }
Romain Guybe1b1272013-06-06 14:02:54 -0700106 texture->deleteTexture();
Romain Guy121e22422010-07-01 18:26:52 -0700107 delete texture;
108 }
109}
110
111///////////////////////////////////////////////////////////////////////////////
112// Caching
113///////////////////////////////////////////////////////////////////////////////
114
John Reckebd52612014-12-10 16:47:36 -0800115void TextureCache::setAssetAtlas(AssetAtlas* assetAtlas) {
116 mAssetAtlas = assetAtlas;
117}
118
John Reck00e79c92015-07-21 10:23:59 -0700119void TextureCache::resetMarkInUse(void* ownerToken) {
John Reck71d08a02014-11-24 15:21:28 -0800120 LruCache<uint32_t, Texture*>::Iterator iter(mCache);
John Reck860d1552014-04-11 19:15:05 -0700121 while (iter.next()) {
John Reck00e79c92015-07-21 10:23:59 -0700122 if (iter.value()->isInUse == ownerToken) {
123 iter.value()->isInUse = nullptr;
124 }
John Reck860d1552014-04-11 19:15:05 -0700125 }
126}
127
128bool TextureCache::canMakeTextureFromBitmap(const SkBitmap* bitmap) {
129 if (bitmap->width() > mMaxTextureSize || bitmap->height() > mMaxTextureSize) {
130 ALOGW("Bitmap too large to be uploaded into a texture (%dx%d, max=%dx%d)",
131 bitmap->width(), bitmap->height(), mMaxTextureSize, mMaxTextureSize);
132 return false;
133 }
134 return true;
135}
136
137// Returns a prepared Texture* that either is already in the cache or can fit
138// in the cache (and is thus added to the cache)
Chris Craik6ad690e2015-07-17 15:51:36 -0700139Texture* TextureCache::getCachedTexture(const SkBitmap* bitmap, AtlasUsageType atlasUsageType) {
140 if (CC_LIKELY(mAssetAtlas != nullptr) && atlasUsageType == AtlasUsageType::Use) {
John Reckebd52612014-12-10 16:47:36 -0800141 AssetAtlas::Entry* entry = mAssetAtlas->getEntry(bitmap);
142 if (CC_UNLIKELY(entry)) {
143 return entry->texture;
144 }
145 }
146
John Reck71d08a02014-11-24 15:21:28 -0800147 Texture* texture = mCache.get(bitmap->pixelRef()->getStableID());
Romain Guya2341a92010-09-08 18:04:33 -0700148
Romain Guyce0537b2010-06-29 21:05:21 -0700149 if (!texture) {
John Reck860d1552014-04-11 19:15:05 -0700150 if (!canMakeTextureFromBitmap(bitmap)) {
Chris Craikd41c4d82015-01-05 15:51:13 -0800151 return nullptr;
Romain Guy9cccc2b92010-08-07 23:46:15 -0700152 }
153
Romain Guy7d139ba2010-07-02 11:20:34 -0700154 const uint32_t size = bitmap->rowBytes() * bitmap->height();
John Reck860d1552014-04-11 19:15:05 -0700155 bool canCache = size < mMaxSize;
Romain Guy121e22422010-07-01 18:26:52 -0700156 // Don't even try to cache a bitmap that's bigger than the cache
John Reck860d1552014-04-11 19:15:05 -0700157 while (canCache && mSize + size > mMaxSize) {
158 Texture* oldest = mCache.peekOldestValue();
159 if (oldest && !oldest->isInUse) {
Romain Guy121e22422010-07-01 18:26:52 -0700160 mCache.removeOldest();
John Reck860d1552014-04-11 19:15:05 -0700161 } else {
162 canCache = false;
Romain Guy121e22422010-07-01 18:26:52 -0700163 }
164 }
165
John Reck860d1552014-04-11 19:15:05 -0700166 if (canCache) {
Chris Craik8e93a7c2015-02-23 13:07:57 -0800167 texture = new Texture(Caches::getInstance());
John Reck860d1552014-04-11 19:15:05 -0700168 texture->bitmapSize = size;
Chris Craik68f5b8a2015-09-09 13:23:09 -0700169 Caches::getInstance().textureState().generateTexture(bitmap, texture, false);
Romain Guy121e22422010-07-01 18:26:52 -0700170
Romain Guy121e22422010-07-01 18:26:52 -0700171 mSize += size;
Romain Guy9e108412010-11-09 14:35:20 -0800172 TEXTURE_LOGD("TextureCache::get: create texture(%p): name, size, mSize = %d, %d, %d",
173 bitmap, texture->id, size, mSize);
Romain Guye190aa62010-11-10 19:01:29 -0800174 if (mDebugEnabled) {
Steve Block5baa3a62011-12-20 16:23:08 +0000175 ALOGD("Texture created, size = %d", size);
Romain Guye190aa62010-11-10 19:01:29 -0800176 }
John Reck71d08a02014-11-24 15:21:28 -0800177 mCache.put(bitmap->pixelRef()->getStableID(), texture);
Romain Guy121e22422010-07-01 18:26:52 -0700178 }
John Reck860d1552014-04-11 19:15:05 -0700179 } else if (!texture->isInUse && bitmap->getGenerationID() != texture->generation) {
180 // Texture was in the cache but is dirty, re-upload
181 // TODO: Re-adjust the cache size if the bitmap's dimensions have changed
Chris Craik68f5b8a2015-09-09 13:23:09 -0700182 Caches::getInstance().textureState().generateTexture(bitmap, texture, true);
Romain Guyce0537b2010-06-29 21:05:21 -0700183 }
Romain Guy22158e12010-08-06 11:18:34 -0700184
Romain Guyce0537b2010-06-29 21:05:21 -0700185 return texture;
186}
187
John Reck00e79c92015-07-21 10:23:59 -0700188bool TextureCache::prefetchAndMarkInUse(void* ownerToken, const SkBitmap* bitmap) {
Chris Craik6ad690e2015-07-17 15:51:36 -0700189 Texture* texture = getCachedTexture(bitmap, AtlasUsageType::Use);
John Reck860d1552014-04-11 19:15:05 -0700190 if (texture) {
John Reck00e79c92015-07-21 10:23:59 -0700191 texture->isInUse = ownerToken;
John Reck860d1552014-04-11 19:15:05 -0700192 }
193 return texture;
194}
195
Chris Craik6ad690e2015-07-17 15:51:36 -0700196Texture* TextureCache::get(const SkBitmap* bitmap, AtlasUsageType atlasUsageType) {
197 Texture* texture = getCachedTexture(bitmap, atlasUsageType);
John Reck860d1552014-04-11 19:15:05 -0700198
199 if (!texture) {
200 if (!canMakeTextureFromBitmap(bitmap)) {
Chris Craikd41c4d82015-01-05 15:51:13 -0800201 return nullptr;
John Reck860d1552014-04-11 19:15:05 -0700202 }
203
204 const uint32_t size = bitmap->rowBytes() * bitmap->height();
Chris Craik8e93a7c2015-02-23 13:07:57 -0800205 texture = new Texture(Caches::getInstance());
John Reck860d1552014-04-11 19:15:05 -0700206 texture->bitmapSize = size;
Chris Craik68f5b8a2015-09-09 13:23:09 -0700207 Caches::getInstance().textureState().generateTexture(bitmap, texture, false);
John Reck860d1552014-04-11 19:15:05 -0700208 texture->cleanup = true;
209 }
210
211 return texture;
212}
213
Derek Sollenberger3d4eed72014-12-04 15:20:29 -0500214void TextureCache::releaseTexture(uint32_t pixelRefStableID) {
Romain Guy9aaa8262010-09-08 15:15:43 -0700215 Mutex::Autolock _l(mLock);
John Reck272a6852015-07-29 16:48:58 -0700216 mGarbage.push_back(pixelRefStableID);
Romain Guyfe48f652010-11-11 15:36:56 -0800217}
218
219void TextureCache::clearGarbage() {
220 Mutex::Autolock _l(mLock);
221 size_t count = mGarbage.size();
222 for (size_t i = 0; i < count; i++) {
John Reck272a6852015-07-29 16:48:58 -0700223 uint32_t pixelRefId = mGarbage[i];
John Reck71d08a02014-11-24 15:21:28 -0800224 mCache.remove(pixelRefId);
Romain Guyfe48f652010-11-11 15:36:56 -0800225 }
226 mGarbage.clear();
227}
228
229void TextureCache::clear() {
Romain Guyce0537b2010-06-29 21:05:21 -0700230 mCache.clear();
Romain Guy912a7b32011-07-26 18:57:28 -0700231 TEXTURE_LOGD("TextureCache:clear(), mSize = %d", mSize);
Romain Guyce0537b2010-06-29 21:05:21 -0700232}
233
Romain Guyeca0ca22011-11-04 15:12:29 -0700234void TextureCache::flush() {
235 if (mFlushRate >= 1.0f || mCache.size() == 0) return;
236 if (mFlushRate <= 0.0f) {
237 clear();
238 return;
239 }
240
241 uint32_t targetSize = uint32_t(mSize * mFlushRate);
242 TEXTURE_LOGD("TextureCache::flush: target size: %d", targetSize);
243
244 while (mSize > targetSize) {
245 mCache.removeOldest();
246 }
247}
248
Romain Guyce0537b2010-06-29 21:05:21 -0700249}; // namespace uirenderer
250}; // namespace android