blob: 9d365fb29ebe02dedba6476b2be6bb97e1fbac1c [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
Romain Guy713e1bb2012-10-16 18:44:09 -070021#include "Caches.h"
John Reck1bcacfd2017-11-03 10:12:19 -070022#include "DeviceInfo.h"
23#include "Properties.h"
Tom Hudson2dc236b2014-10-15 15:46:42 -040024#include "Texture.h"
Romain Guyce0537b2010-06-29 21:05:21 -070025#include "TextureCache.h"
sergeyvec4a4b12016-10-20 18:39:04 -070026#include "hwui/Bitmap.h"
John Reck1bcacfd2017-11-03 10:12:19 -070027#include "utils/TraceUtils.h"
Romain Guyce0537b2010-06-29 21:05:21 -070028
29namespace android {
30namespace uirenderer {
31
Romain Guy121e2242010-07-01 18:26:52 -070032///////////////////////////////////////////////////////////////////////////////
33// Constructors/destructor
34///////////////////////////////////////////////////////////////////////////////
35
Chris Craik117bdbc2015-02-05 10:12:38 -080036TextureCache::TextureCache()
37 : mCache(LruCache<uint32_t, Texture*>::kUnlimitedCapacity)
38 , mSize(0)
John Reck1bcacfd2017-11-03 10:12:19 -070039 , mMaxSize(DeviceInfo::multiplyByResolution(4 * 6)) // 6 screen-sized RGBA_8888 bitmaps
John Reck8dc02f92017-07-17 09:55:02 -070040 , mFlushRate(.4f) {
Romain Guyfb8b7632010-08-23 21:05:08 -070041 mCache.setOnEntryRemovedListener(this);
John Reck8dc02f92017-07-17 09:55:02 -070042 mMaxTextureSize = DeviceInfo::get()->maxTextureSize();
Chris Craik2507c342015-05-04 14:36:49 -070043 mDebugEnabled = Properties::debugLevel & kDebugCaches;
Romain Guyfb8b7632010-08-23 21:05:08 -070044}
45
Chris Craik117bdbc2015-02-05 10:12:38 -080046TextureCache::~TextureCache() {
sergeyv83809fe2017-02-01 10:27:33 -080047 this->clear();
Chris Craik117bdbc2015-02-05 10:12:38 -080048}
49
Romain Guy121e2242010-07-01 18:26:52 -070050///////////////////////////////////////////////////////////////////////////////
51// Size management
52///////////////////////////////////////////////////////////////////////////////
53
Romain Guy7d139ba2010-07-02 11:20:34 -070054uint32_t TextureCache::getSize() {
Romain Guy121e2242010-07-01 18:26:52 -070055 return mSize;
56}
57
Romain Guy7d139ba2010-07-02 11:20:34 -070058uint32_t TextureCache::getMaxSize() {
Romain Guy121e2242010-07-01 18:26:52 -070059 return mMaxSize;
60}
61
Romain Guy121e2242010-07-01 18:26:52 -070062///////////////////////////////////////////////////////////////////////////////
63// Callbacks
64///////////////////////////////////////////////////////////////////////////////
65
John Reck71d08a02014-11-24 15:21:28 -080066void TextureCache::operator()(uint32_t&, Texture*& texture) {
Romain Guy9aaa8262010-09-08 15:15:43 -070067 // This will be called already locked
Romain Guy121e2242010-07-01 18:26:52 -070068 if (texture) {
Romain Guy9aaa8262010-09-08 15:15:43 -070069 mSize -= texture->bitmapSize;
John Reck1bcacfd2017-11-03 10:12:19 -070070 TEXTURE_LOGD("TextureCache::callback: name, removed size, mSize = %d, %d, %d", texture->id,
71 texture->bitmapSize, mSize);
Romain Guye190aa62010-11-10 19:01:29 -080072 if (mDebugEnabled) {
Steve Block5baa3a62011-12-20 16:23:08 +000073 ALOGD("Texture deleted, size = %d", texture->bitmapSize);
Romain Guye190aa62010-11-10 19:01:29 -080074 }
Romain Guybe1b1272013-06-06 14:02:54 -070075 texture->deleteTexture();
Romain Guy121e2242010-07-01 18:26:52 -070076 delete texture;
77 }
78}
79
80///////////////////////////////////////////////////////////////////////////////
81// Caching
82///////////////////////////////////////////////////////////////////////////////
83
John Reck00e79c92015-07-21 10:23:59 -070084void TextureCache::resetMarkInUse(void* ownerToken) {
John Reck71d08a02014-11-24 15:21:28 -080085 LruCache<uint32_t, Texture*>::Iterator iter(mCache);
John Reck860d1552014-04-11 19:15:05 -070086 while (iter.next()) {
John Reck00e79c92015-07-21 10:23:59 -070087 if (iter.value()->isInUse == ownerToken) {
88 iter.value()->isInUse = nullptr;
89 }
John Reck860d1552014-04-11 19:15:05 -070090 }
91}
92
sergeyvec4a4b12016-10-20 18:39:04 -070093bool TextureCache::canMakeTextureFromBitmap(Bitmap* bitmap) {
John Reck860d1552014-04-11 19:15:05 -070094 if (bitmap->width() > mMaxTextureSize || bitmap->height() > mMaxTextureSize) {
John Reck1bcacfd2017-11-03 10:12:19 -070095 ALOGW("Bitmap too large to be uploaded into a texture (%dx%d, max=%dx%d)", bitmap->width(),
96 bitmap->height(), mMaxTextureSize, mMaxTextureSize);
John Reck860d1552014-04-11 19:15:05 -070097 return false;
98 }
99 return true;
100}
101
sergeyv00783be2017-01-30 14:24:48 -0800102Texture* TextureCache::createTexture(Bitmap* bitmap) {
John Reck1bcacfd2017-11-03 10:12:19 -0700103 Texture* texture = new Texture(Caches::getInstance());
104 texture->bitmapSize = bitmap->rowBytes() * bitmap->height();
105 texture->generation = bitmap->getGenerationID();
106 texture->upload(*bitmap);
107 return texture;
sergeyv00783be2017-01-30 14:24:48 -0800108}
109
John Reck860d1552014-04-11 19:15:05 -0700110// Returns a prepared Texture* that either is already in the cache or can fit
111// in the cache (and is thus added to the cache)
sergeyvec4a4b12016-10-20 18:39:04 -0700112Texture* TextureCache::getCachedTexture(Bitmap* bitmap) {
sergeyv00783be2017-01-30 14:24:48 -0800113 if (bitmap->isHardware()) {
114 auto textureIterator = mHardwareTextures.find(bitmap->getStableID());
115 if (textureIterator == mHardwareTextures.end()) {
John Reck1bcacfd2017-11-03 10:12:19 -0700116 Texture* texture = createTexture(bitmap);
117 mHardwareTextures.insert(
118 std::make_pair(bitmap->getStableID(), std::unique_ptr<Texture>(texture)));
sergeyv00783be2017-01-30 14:24:48 -0800119 if (mDebugEnabled) {
120 ALOGD("Texture created for hw bitmap size = %d", texture->bitmapSize);
121 }
122 return texture;
123 }
124 return textureIterator->second.get();
125 }
126
sergeyvec4a4b12016-10-20 18:39:04 -0700127 Texture* texture = mCache.get(bitmap->getStableID());
Romain Guya2341a92010-09-08 18:04:33 -0700128
Romain Guyce0537b2010-06-29 21:05:21 -0700129 if (!texture) {
John Reck860d1552014-04-11 19:15:05 -0700130 if (!canMakeTextureFromBitmap(bitmap)) {
Chris Craikd41c4d82015-01-05 15:51:13 -0800131 return nullptr;
Romain Guy9cccc2b2010-08-07 23:46:15 -0700132 }
133
Romain Guy7d139ba2010-07-02 11:20:34 -0700134 const uint32_t size = bitmap->rowBytes() * bitmap->height();
John Reck860d1552014-04-11 19:15:05 -0700135 bool canCache = size < mMaxSize;
Romain Guy121e2242010-07-01 18:26:52 -0700136 // Don't even try to cache a bitmap that's bigger than the cache
John Reck860d1552014-04-11 19:15:05 -0700137 while (canCache && mSize + size > mMaxSize) {
138 Texture* oldest = mCache.peekOldestValue();
139 if (oldest && !oldest->isInUse) {
Romain Guy121e2242010-07-01 18:26:52 -0700140 mCache.removeOldest();
John Reck860d1552014-04-11 19:15:05 -0700141 } else {
142 canCache = false;
Romain Guy121e2242010-07-01 18:26:52 -0700143 }
144 }
145
John Reck860d1552014-04-11 19:15:05 -0700146 if (canCache) {
sergeyv00783be2017-01-30 14:24:48 -0800147 texture = createTexture(bitmap);
Romain Guy121e2242010-07-01 18:26:52 -0700148 mSize += size;
Romain Guy9e108412010-11-09 14:35:20 -0800149 TEXTURE_LOGD("TextureCache::get: create texture(%p): name, size, mSize = %d, %d, %d",
John Reck1bcacfd2017-11-03 10:12:19 -0700150 bitmap, texture->id, size, mSize);
Romain Guye190aa62010-11-10 19:01:29 -0800151 if (mDebugEnabled) {
Steve Block5baa3a62011-12-20 16:23:08 +0000152 ALOGD("Texture created, size = %d", size);
Romain Guye190aa62010-11-10 19:01:29 -0800153 }
sergeyvec4a4b12016-10-20 18:39:04 -0700154 mCache.put(bitmap->getStableID(), texture);
Romain Guy121e2242010-07-01 18:26:52 -0700155 }
John Reck860d1552014-04-11 19:15:05 -0700156 } else if (!texture->isInUse && bitmap->getGenerationID() != texture->generation) {
157 // Texture was in the cache but is dirty, re-upload
158 // TODO: Re-adjust the cache size if the bitmap's dimensions have changed
sergeyv98fa4f92016-10-24 15:35:21 -0700159 texture->upload(*bitmap);
John Reck38e0c322015-11-10 12:19:17 -0800160 texture->generation = bitmap->getGenerationID();
Romain Guyce0537b2010-06-29 21:05:21 -0700161 }
Romain Guy22158e12010-08-06 11:18:34 -0700162
Romain Guyce0537b2010-06-29 21:05:21 -0700163 return texture;
164}
165
sergeyvec4a4b12016-10-20 18:39:04 -0700166bool TextureCache::prefetchAndMarkInUse(void* ownerToken, Bitmap* bitmap) {
Romain Guy253f2c22016-09-28 17:34:42 -0700167 Texture* texture = getCachedTexture(bitmap);
John Reck860d1552014-04-11 19:15:05 -0700168 if (texture) {
John Reck00e79c92015-07-21 10:23:59 -0700169 texture->isInUse = ownerToken;
John Reck860d1552014-04-11 19:15:05 -0700170 }
171 return texture;
172}
173
sergeyvec4a4b12016-10-20 18:39:04 -0700174bool TextureCache::prefetch(Bitmap* bitmap) {
Romain Guy253f2c22016-09-28 17:34:42 -0700175 return getCachedTexture(bitmap);
John Reck43871902016-08-01 14:39:24 -0700176}
177
sergeyvec4a4b12016-10-20 18:39:04 -0700178Texture* TextureCache::get(Bitmap* bitmap) {
Romain Guy253f2c22016-09-28 17:34:42 -0700179 Texture* texture = getCachedTexture(bitmap);
John Reck860d1552014-04-11 19:15:05 -0700180
181 if (!texture) {
182 if (!canMakeTextureFromBitmap(bitmap)) {
Chris Craikd41c4d82015-01-05 15:51:13 -0800183 return nullptr;
John Reck860d1552014-04-11 19:15:05 -0700184 }
sergeyv00783be2017-01-30 14:24:48 -0800185 texture = createTexture(bitmap);
John Reck860d1552014-04-11 19:15:05 -0700186 texture->cleanup = true;
187 }
188
189 return texture;
190}
191
John Reck9a814872017-05-22 15:04:21 -0700192bool TextureCache::destroyTexture(uint32_t pixelRefStableID) {
193 auto hardwareIter = mHardwareTextures.find(pixelRefStableID);
194 if (hardwareIter != mHardwareTextures.end()) {
195 hardwareIter->second->deleteTexture();
196 mHardwareTextures.erase(hardwareIter);
197 return true;
Romain Guyfe48f652010-11-11 15:36:56 -0800198 }
John Reck9a814872017-05-22 15:04:21 -0700199 return mCache.remove(pixelRefStableID);
Romain Guyfe48f652010-11-11 15:36:56 -0800200}
201
202void TextureCache::clear() {
Romain Guyce0537b2010-06-29 21:05:21 -0700203 mCache.clear();
John Reck1bcacfd2017-11-03 10:12:19 -0700204 for (auto& iter : mHardwareTextures) {
sergeyv83809fe2017-02-01 10:27:33 -0800205 iter.second->deleteTexture();
206 }
207 mHardwareTextures.clear();
Romain Guy912a7b32011-07-26 18:57:28 -0700208 TEXTURE_LOGD("TextureCache:clear(), mSize = %d", mSize);
Romain Guyce0537b2010-06-29 21:05:21 -0700209}
210
Romain Guyeca0ca22011-11-04 15:12:29 -0700211void TextureCache::flush() {
212 if (mFlushRate >= 1.0f || mCache.size() == 0) return;
213 if (mFlushRate <= 0.0f) {
214 clear();
215 return;
216 }
217
218 uint32_t targetSize = uint32_t(mSize * mFlushRate);
219 TEXTURE_LOGD("TextureCache::flush: target size: %d", targetSize);
220
221 while (mSize > targetSize) {
222 mCache.removeOldest();
223 }
224}
225
John Reck1bcacfd2017-11-03 10:12:19 -0700226}; // namespace uirenderer
227}; // namespace android