blob: ade8600ab78b365b6d79aadfc0300ec02a568bd0 [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 Guy121e2242010-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)
Chris Craik48a8f432016-02-05 15:59:29 -080038 , mMaxSize(Properties::textureCacheSize)
39 , mFlushRate(Properties::textureCacheFlushRate)
Chris Craik117bdbc2015-02-05 10:12:38 -080040 , mAssetAtlas(nullptr) {
Romain Guyfb8b7632010-08-23 21:05:08 -070041 mCache.setOnEntryRemovedListener(this);
42
43 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
Romain Guyf6834472011-01-23 13:32:12 -080044 INIT_LOGD(" Maximum texture dimension is %d pixels", mMaxTextureSize);
Romain Guye190aa62010-11-10 19:01:29 -080045
Chris Craik2507c342015-05-04 14:36:49 -070046 mDebugEnabled = Properties::debugLevel & kDebugCaches;
Romain Guyfb8b7632010-08-23 21:05:08 -070047}
48
Chris Craik117bdbc2015-02-05 10:12:38 -080049TextureCache::~TextureCache() {
50 mCache.clear();
51}
52
Romain Guy121e2242010-07-01 18:26:52 -070053///////////////////////////////////////////////////////////////////////////////
54// Size management
55///////////////////////////////////////////////////////////////////////////////
56
Romain Guy7d139ba2010-07-02 11:20:34 -070057uint32_t TextureCache::getSize() {
Romain Guy121e2242010-07-01 18:26:52 -070058 return mSize;
59}
60
Romain Guy7d139ba2010-07-02 11:20:34 -070061uint32_t TextureCache::getMaxSize() {
Romain Guy121e2242010-07-01 18:26:52 -070062 return mMaxSize;
63}
64
Romain Guy121e2242010-07-01 18:26:52 -070065///////////////////////////////////////////////////////////////////////////////
66// Callbacks
67///////////////////////////////////////////////////////////////////////////////
68
John Reck71d08a02014-11-24 15:21:28 -080069void TextureCache::operator()(uint32_t&, Texture*& texture) {
Romain Guy9aaa8262010-09-08 15:15:43 -070070 // This will be called already locked
Romain Guy121e2242010-07-01 18:26:52 -070071 if (texture) {
Romain Guy9aaa8262010-09-08 15:15:43 -070072 mSize -= texture->bitmapSize;
Romain Guy9e108412010-11-09 14:35:20 -080073 TEXTURE_LOGD("TextureCache::callback: name, removed size, mSize = %d, %d, %d",
74 texture->id, texture->bitmapSize, mSize);
Romain Guye190aa62010-11-10 19:01:29 -080075 if (mDebugEnabled) {
Steve Block5baa3a62011-12-20 16:23:08 +000076 ALOGD("Texture deleted, size = %d", texture->bitmapSize);
Romain Guye190aa62010-11-10 19:01:29 -080077 }
Romain Guybe1b1272013-06-06 14:02:54 -070078 texture->deleteTexture();
Romain Guy121e2242010-07-01 18:26:52 -070079 delete texture;
80 }
81}
82
83///////////////////////////////////////////////////////////////////////////////
84// Caching
85///////////////////////////////////////////////////////////////////////////////
86
John Reckebd52612014-12-10 16:47:36 -080087void TextureCache::setAssetAtlas(AssetAtlas* assetAtlas) {
88 mAssetAtlas = assetAtlas;
89}
90
John Reck00e79c92015-07-21 10:23:59 -070091void TextureCache::resetMarkInUse(void* ownerToken) {
John Reck71d08a02014-11-24 15:21:28 -080092 LruCache<uint32_t, Texture*>::Iterator iter(mCache);
John Reck860d1552014-04-11 19:15:05 -070093 while (iter.next()) {
John Reck00e79c92015-07-21 10:23:59 -070094 if (iter.value()->isInUse == ownerToken) {
95 iter.value()->isInUse = nullptr;
96 }
John Reck860d1552014-04-11 19:15:05 -070097 }
98}
99
100bool TextureCache::canMakeTextureFromBitmap(const SkBitmap* bitmap) {
101 if (bitmap->width() > mMaxTextureSize || bitmap->height() > mMaxTextureSize) {
102 ALOGW("Bitmap too large to be uploaded into a texture (%dx%d, max=%dx%d)",
103 bitmap->width(), bitmap->height(), mMaxTextureSize, mMaxTextureSize);
104 return false;
105 }
106 return true;
107}
108
109// Returns a prepared Texture* that either is already in the cache or can fit
110// in the cache (and is thus added to the cache)
Chris Craik6ad690e2015-07-17 15:51:36 -0700111Texture* TextureCache::getCachedTexture(const SkBitmap* bitmap, AtlasUsageType atlasUsageType) {
112 if (CC_LIKELY(mAssetAtlas != nullptr) && atlasUsageType == AtlasUsageType::Use) {
Chris Craik15c3f192015-12-03 12:16:56 -0800113 AssetAtlas::Entry* entry = mAssetAtlas->getEntry(bitmap->pixelRef());
John Reckebd52612014-12-10 16:47:36 -0800114 if (CC_UNLIKELY(entry)) {
115 return entry->texture;
116 }
117 }
118
John Reck71d08a02014-11-24 15:21:28 -0800119 Texture* texture = mCache.get(bitmap->pixelRef()->getStableID());
Romain Guya2341a92010-09-08 18:04:33 -0700120
Romain Guyce0537b2010-06-29 21:05:21 -0700121 if (!texture) {
John Reck860d1552014-04-11 19:15:05 -0700122 if (!canMakeTextureFromBitmap(bitmap)) {
Chris Craikd41c4d82015-01-05 15:51:13 -0800123 return nullptr;
Romain Guy9cccc2b2010-08-07 23:46:15 -0700124 }
125
Romain Guy7d139ba2010-07-02 11:20:34 -0700126 const uint32_t size = bitmap->rowBytes() * bitmap->height();
John Reck860d1552014-04-11 19:15:05 -0700127 bool canCache = size < mMaxSize;
Romain Guy121e2242010-07-01 18:26:52 -0700128 // Don't even try to cache a bitmap that's bigger than the cache
John Reck860d1552014-04-11 19:15:05 -0700129 while (canCache && mSize + size > mMaxSize) {
130 Texture* oldest = mCache.peekOldestValue();
131 if (oldest && !oldest->isInUse) {
Romain Guy121e2242010-07-01 18:26:52 -0700132 mCache.removeOldest();
John Reck860d1552014-04-11 19:15:05 -0700133 } else {
134 canCache = false;
Romain Guy121e2242010-07-01 18:26:52 -0700135 }
136 }
137
John Reck860d1552014-04-11 19:15:05 -0700138 if (canCache) {
Chris Craik8e93a7c2015-02-23 13:07:57 -0800139 texture = new Texture(Caches::getInstance());
John Reck860d1552014-04-11 19:15:05 -0700140 texture->bitmapSize = size;
John Reck38e0c322015-11-10 12:19:17 -0800141 texture->generation = bitmap->getGenerationID();
142 texture->upload(*bitmap);
Romain Guy121e2242010-07-01 18:26:52 -0700143
Romain Guy121e2242010-07-01 18:26:52 -0700144 mSize += size;
Romain Guy9e108412010-11-09 14:35:20 -0800145 TEXTURE_LOGD("TextureCache::get: create texture(%p): name, size, mSize = %d, %d, %d",
146 bitmap, texture->id, size, mSize);
Romain Guye190aa62010-11-10 19:01:29 -0800147 if (mDebugEnabled) {
Steve Block5baa3a62011-12-20 16:23:08 +0000148 ALOGD("Texture created, size = %d", size);
Romain Guye190aa62010-11-10 19:01:29 -0800149 }
John Reck71d08a02014-11-24 15:21:28 -0800150 mCache.put(bitmap->pixelRef()->getStableID(), texture);
Romain Guy121e2242010-07-01 18:26:52 -0700151 }
John Reck860d1552014-04-11 19:15:05 -0700152 } else if (!texture->isInUse && bitmap->getGenerationID() != texture->generation) {
153 // Texture was in the cache but is dirty, re-upload
154 // TODO: Re-adjust the cache size if the bitmap's dimensions have changed
John Reck38e0c322015-11-10 12:19:17 -0800155 texture->upload(*bitmap);
156 texture->generation = bitmap->getGenerationID();
Romain Guyce0537b2010-06-29 21:05:21 -0700157 }
Romain Guy22158e12010-08-06 11:18:34 -0700158
Romain Guyce0537b2010-06-29 21:05:21 -0700159 return texture;
160}
161
John Reck00e79c92015-07-21 10:23:59 -0700162bool TextureCache::prefetchAndMarkInUse(void* ownerToken, const SkBitmap* bitmap) {
Chris Craik6ad690e2015-07-17 15:51:36 -0700163 Texture* texture = getCachedTexture(bitmap, AtlasUsageType::Use);
John Reck860d1552014-04-11 19:15:05 -0700164 if (texture) {
John Reck00e79c92015-07-21 10:23:59 -0700165 texture->isInUse = ownerToken;
John Reck860d1552014-04-11 19:15:05 -0700166 }
167 return texture;
168}
169
Chris Craik6ad690e2015-07-17 15:51:36 -0700170Texture* TextureCache::get(const SkBitmap* bitmap, AtlasUsageType atlasUsageType) {
171 Texture* texture = getCachedTexture(bitmap, atlasUsageType);
John Reck860d1552014-04-11 19:15:05 -0700172
173 if (!texture) {
174 if (!canMakeTextureFromBitmap(bitmap)) {
Chris Craikd41c4d82015-01-05 15:51:13 -0800175 return nullptr;
John Reck860d1552014-04-11 19:15:05 -0700176 }
177
178 const uint32_t size = bitmap->rowBytes() * bitmap->height();
Chris Craik8e93a7c2015-02-23 13:07:57 -0800179 texture = new Texture(Caches::getInstance());
John Reck860d1552014-04-11 19:15:05 -0700180 texture->bitmapSize = size;
John Reck38e0c322015-11-10 12:19:17 -0800181 texture->upload(*bitmap);
182 texture->generation = bitmap->getGenerationID();
John Reck860d1552014-04-11 19:15:05 -0700183 texture->cleanup = true;
184 }
185
186 return texture;
187}
188
Derek Sollenberger3d4eed72014-12-04 15:20:29 -0500189void TextureCache::releaseTexture(uint32_t pixelRefStableID) {
Romain Guy9aaa8262010-09-08 15:15:43 -0700190 Mutex::Autolock _l(mLock);
John Reck272a6852015-07-29 16:48:58 -0700191 mGarbage.push_back(pixelRefStableID);
Romain Guyfe48f652010-11-11 15:36:56 -0800192}
193
194void TextureCache::clearGarbage() {
195 Mutex::Autolock _l(mLock);
196 size_t count = mGarbage.size();
197 for (size_t i = 0; i < count; i++) {
John Reck272a6852015-07-29 16:48:58 -0700198 uint32_t pixelRefId = mGarbage[i];
John Reck71d08a02014-11-24 15:21:28 -0800199 mCache.remove(pixelRefId);
Romain Guyfe48f652010-11-11 15:36:56 -0800200 }
201 mGarbage.clear();
202}
203
204void TextureCache::clear() {
Romain Guyce0537b2010-06-29 21:05:21 -0700205 mCache.clear();
Romain Guy912a7b32011-07-26 18:57:28 -0700206 TEXTURE_LOGD("TextureCache:clear(), mSize = %d", mSize);
Romain Guyce0537b2010-06-29 21:05:21 -0700207}
208
Romain Guyeca0ca22011-11-04 15:12:29 -0700209void TextureCache::flush() {
210 if (mFlushRate >= 1.0f || mCache.size() == 0) return;
211 if (mFlushRate <= 0.0f) {
212 clear();
213 return;
214 }
215
216 uint32_t targetSize = uint32_t(mSize * mFlushRate);
217 TEXTURE_LOGD("TextureCache::flush: target size: %d", targetSize);
218
219 while (mSize > targetSize) {
220 mCache.removeOldest();
221 }
222}
223
Romain Guyce0537b2010-06-29 21:05:21 -0700224}; // namespace uirenderer
225}; // namespace android