blob: 710cdd9286e8b17d8c5703d56d8644803b003d96 [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"
Tom Hudson2dc236b2014-10-15 15:46:42 -040022#include "Texture.h"
Romain Guyce0537b2010-06-29 21:05:21 -070023#include "TextureCache.h"
Romain Guyfb8b7632010-08-23 21:05:08 -070024#include "Properties.h"
Chris Craik70850ea2014-11-18 10:49:23 -080025#include "utils/TraceUtils.h"
sergeyvec4a4b12016-10-20 18:39:04 -070026#include "hwui/Bitmap.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)
Chris Craik48a8f432016-02-05 15:59:29 -080038 , mMaxSize(Properties::textureCacheSize)
Romain Guy253f2c22016-09-28 17:34:42 -070039 , mFlushRate(Properties::textureCacheFlushRate) {
Romain Guyfb8b7632010-08-23 21:05:08 -070040 mCache.setOnEntryRemovedListener(this);
41
42 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
Romain Guyf6834472011-01-23 13:32:12 -080043 INIT_LOGD(" Maximum texture dimension is %d pixels", mMaxTextureSize);
Romain Guye190aa62010-11-10 19:01:29 -080044
Chris Craik2507c342015-05-04 14:36:49 -070045 mDebugEnabled = Properties::debugLevel & kDebugCaches;
Romain Guyfb8b7632010-08-23 21:05:08 -070046}
47
Chris Craik117bdbc2015-02-05 10:12:38 -080048TextureCache::~TextureCache() {
sergeyv83809fe2017-02-01 10:27:33 -080049 this->clear();
Chris Craik117bdbc2015-02-05 10:12:38 -080050}
51
Romain Guy121e22422010-07-01 18:26:52 -070052///////////////////////////////////////////////////////////////////////////////
53// Size management
54///////////////////////////////////////////////////////////////////////////////
55
Romain Guy7d139ba2010-07-02 11:20:34 -070056uint32_t TextureCache::getSize() {
Romain Guy121e22422010-07-01 18:26:52 -070057 return mSize;
58}
59
Romain Guy7d139ba2010-07-02 11:20:34 -070060uint32_t TextureCache::getMaxSize() {
Romain Guy121e22422010-07-01 18:26:52 -070061 return mMaxSize;
62}
63
Romain Guy121e22422010-07-01 18:26:52 -070064///////////////////////////////////////////////////////////////////////////////
65// Callbacks
66///////////////////////////////////////////////////////////////////////////////
67
John Reck71d08a02014-11-24 15:21:28 -080068void TextureCache::operator()(uint32_t&, Texture*& texture) {
Romain Guy9aaa8262010-09-08 15:15:43 -070069 // This will be called already locked
Romain Guy121e22422010-07-01 18:26:52 -070070 if (texture) {
Romain Guy9aaa8262010-09-08 15:15:43 -070071 mSize -= texture->bitmapSize;
Romain Guy9e108412010-11-09 14:35:20 -080072 TEXTURE_LOGD("TextureCache::callback: name, removed size, mSize = %d, %d, %d",
73 texture->id, texture->bitmapSize, mSize);
Romain Guye190aa62010-11-10 19:01:29 -080074 if (mDebugEnabled) {
Steve Block5baa3a62011-12-20 16:23:08 +000075 ALOGD("Texture deleted, size = %d", texture->bitmapSize);
Romain Guye190aa62010-11-10 19:01:29 -080076 }
Romain Guybe1b1272013-06-06 14:02:54 -070077 texture->deleteTexture();
Romain Guy121e22422010-07-01 18:26:52 -070078 delete texture;
79 }
80}
81
82///////////////////////////////////////////////////////////////////////////////
83// Caching
84///////////////////////////////////////////////////////////////////////////////
85
John Reck00e79c92015-07-21 10:23:59 -070086void TextureCache::resetMarkInUse(void* ownerToken) {
John Reck71d08a02014-11-24 15:21:28 -080087 LruCache<uint32_t, Texture*>::Iterator iter(mCache);
John Reck860d1552014-04-11 19:15:05 -070088 while (iter.next()) {
John Reck00e79c92015-07-21 10:23:59 -070089 if (iter.value()->isInUse == ownerToken) {
90 iter.value()->isInUse = nullptr;
91 }
John Reck860d1552014-04-11 19:15:05 -070092 }
93}
94
sergeyvec4a4b12016-10-20 18:39:04 -070095bool TextureCache::canMakeTextureFromBitmap(Bitmap* bitmap) {
John Reck860d1552014-04-11 19:15:05 -070096 if (bitmap->width() > mMaxTextureSize || bitmap->height() > mMaxTextureSize) {
97 ALOGW("Bitmap too large to be uploaded into a texture (%dx%d, max=%dx%d)",
98 bitmap->width(), bitmap->height(), mMaxTextureSize, mMaxTextureSize);
99 return false;
100 }
101 return true;
102}
103
sergeyv00783be2017-01-30 14:24:48 -0800104Texture* TextureCache::createTexture(Bitmap* bitmap) {
105 Texture* texture = new Texture(Caches::getInstance());
106 texture->bitmapSize = bitmap->rowBytes() * bitmap->height();
107 texture->generation = bitmap->getGenerationID();
108 texture->upload(*bitmap);
109 return texture;
110}
111
John Reck860d1552014-04-11 19:15:05 -0700112// Returns a prepared Texture* that either is already in the cache or can fit
113// in the cache (and is thus added to the cache)
sergeyvec4a4b12016-10-20 18:39:04 -0700114Texture* TextureCache::getCachedTexture(Bitmap* bitmap) {
sergeyv00783be2017-01-30 14:24:48 -0800115 if (bitmap->isHardware()) {
116 auto textureIterator = mHardwareTextures.find(bitmap->getStableID());
117 if (textureIterator == mHardwareTextures.end()) {
118 Texture* texture = createTexture(bitmap);
119 mHardwareTextures.insert(std::make_pair(bitmap->getStableID(),
120 std::unique_ptr<Texture>(texture)));
121 if (mDebugEnabled) {
122 ALOGD("Texture created for hw bitmap size = %d", texture->bitmapSize);
123 }
124 return texture;
125 }
126 return textureIterator->second.get();
127 }
128
sergeyvec4a4b12016-10-20 18:39:04 -0700129 Texture* texture = mCache.get(bitmap->getStableID());
Romain Guya2341a92010-09-08 18:04:33 -0700130
Romain Guyce0537b2010-06-29 21:05:21 -0700131 if (!texture) {
John Reck860d1552014-04-11 19:15:05 -0700132 if (!canMakeTextureFromBitmap(bitmap)) {
Chris Craikd41c4d82015-01-05 15:51:13 -0800133 return nullptr;
Romain Guy9cccc2b92010-08-07 23:46:15 -0700134 }
135
Romain Guy7d139ba2010-07-02 11:20:34 -0700136 const uint32_t size = bitmap->rowBytes() * bitmap->height();
John Reck860d1552014-04-11 19:15:05 -0700137 bool canCache = size < mMaxSize;
Romain Guy121e22422010-07-01 18:26:52 -0700138 // Don't even try to cache a bitmap that's bigger than the cache
John Reck860d1552014-04-11 19:15:05 -0700139 while (canCache && mSize + size > mMaxSize) {
140 Texture* oldest = mCache.peekOldestValue();
141 if (oldest && !oldest->isInUse) {
Romain Guy121e22422010-07-01 18:26:52 -0700142 mCache.removeOldest();
John Reck860d1552014-04-11 19:15:05 -0700143 } else {
144 canCache = false;
Romain Guy121e22422010-07-01 18:26:52 -0700145 }
146 }
147
John Reck860d1552014-04-11 19:15:05 -0700148 if (canCache) {
sergeyv00783be2017-01-30 14:24:48 -0800149 texture = createTexture(bitmap);
Romain Guy121e22422010-07-01 18:26:52 -0700150 mSize += size;
Romain Guy9e108412010-11-09 14:35:20 -0800151 TEXTURE_LOGD("TextureCache::get: create texture(%p): name, size, mSize = %d, %d, %d",
152 bitmap, texture->id, size, mSize);
Romain Guye190aa62010-11-10 19:01:29 -0800153 if (mDebugEnabled) {
Steve Block5baa3a62011-12-20 16:23:08 +0000154 ALOGD("Texture created, size = %d", size);
Romain Guye190aa62010-11-10 19:01:29 -0800155 }
sergeyvec4a4b12016-10-20 18:39:04 -0700156 mCache.put(bitmap->getStableID(), texture);
Romain Guy121e22422010-07-01 18:26:52 -0700157 }
John Reck860d1552014-04-11 19:15:05 -0700158 } else if (!texture->isInUse && bitmap->getGenerationID() != texture->generation) {
159 // Texture was in the cache but is dirty, re-upload
160 // TODO: Re-adjust the cache size if the bitmap's dimensions have changed
sergeyv98fa4f92016-10-24 15:35:21 -0700161 texture->upload(*bitmap);
John Reck38e0c322015-11-10 12:19:17 -0800162 texture->generation = bitmap->getGenerationID();
Romain Guyce0537b2010-06-29 21:05:21 -0700163 }
Romain Guy22158e12010-08-06 11:18:34 -0700164
Romain Guyce0537b2010-06-29 21:05:21 -0700165 return texture;
166}
167
sergeyvec4a4b12016-10-20 18:39:04 -0700168bool TextureCache::prefetchAndMarkInUse(void* ownerToken, Bitmap* bitmap) {
Romain Guy253f2c22016-09-28 17:34:42 -0700169 Texture* texture = getCachedTexture(bitmap);
John Reck860d1552014-04-11 19:15:05 -0700170 if (texture) {
John Reck00e79c92015-07-21 10:23:59 -0700171 texture->isInUse = ownerToken;
John Reck860d1552014-04-11 19:15:05 -0700172 }
173 return texture;
174}
175
sergeyvec4a4b12016-10-20 18:39:04 -0700176bool TextureCache::prefetch(Bitmap* bitmap) {
Romain Guy253f2c22016-09-28 17:34:42 -0700177 return getCachedTexture(bitmap);
John Reck43871902016-08-01 14:39:24 -0700178}
179
sergeyvec4a4b12016-10-20 18:39:04 -0700180Texture* TextureCache::get(Bitmap* bitmap) {
Romain Guy253f2c22016-09-28 17:34:42 -0700181 Texture* texture = getCachedTexture(bitmap);
John Reck860d1552014-04-11 19:15:05 -0700182
183 if (!texture) {
184 if (!canMakeTextureFromBitmap(bitmap)) {
Chris Craikd41c4d82015-01-05 15:51:13 -0800185 return nullptr;
John Reck860d1552014-04-11 19:15:05 -0700186 }
sergeyv00783be2017-01-30 14:24:48 -0800187 texture = createTexture(bitmap);
John Reck860d1552014-04-11 19:15:05 -0700188 texture->cleanup = true;
189 }
190
191 return texture;
192}
193
John Reck9a814872017-05-22 15:04:21 -0700194bool TextureCache::destroyTexture(uint32_t pixelRefStableID) {
195 auto hardwareIter = mHardwareTextures.find(pixelRefStableID);
196 if (hardwareIter != mHardwareTextures.end()) {
197 hardwareIter->second->deleteTexture();
198 mHardwareTextures.erase(hardwareIter);
199 return true;
Romain Guyfe48f652010-11-11 15:36:56 -0800200 }
John Reck9a814872017-05-22 15:04:21 -0700201 return mCache.remove(pixelRefStableID);
Romain Guyfe48f652010-11-11 15:36:56 -0800202}
203
204void TextureCache::clear() {
Romain Guyce0537b2010-06-29 21:05:21 -0700205 mCache.clear();
sergeyv83809fe2017-02-01 10:27:33 -0800206 for(auto& iter: mHardwareTextures) {
207 iter.second->deleteTexture();
208 }
209 mHardwareTextures.clear();
Romain Guy912a7b32011-07-26 18:57:28 -0700210 TEXTURE_LOGD("TextureCache:clear(), mSize = %d", mSize);
Romain Guyce0537b2010-06-29 21:05:21 -0700211}
212
Romain Guyeca0ca22011-11-04 15:12:29 -0700213void TextureCache::flush() {
214 if (mFlushRate >= 1.0f || mCache.size() == 0) return;
215 if (mFlushRate <= 0.0f) {
216 clear();
217 return;
218 }
219
220 uint32_t targetSize = uint32_t(mSize * mFlushRate);
221 TEXTURE_LOGD("TextureCache::flush: target size: %d", targetSize);
222
223 while (mSize > targetSize) {
224 mCache.removeOldest();
225 }
226}
227
Romain Guyce0537b2010-06-29 21:05:21 -0700228}; // namespace uirenderer
229}; // namespace android