blob: 14ffc85a4f687ea4cee95ae0beded1fe02cb83e5 [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 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)
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() {
49 mCache.clear();
50}
51
Romain Guy121e2242010-07-01 18:26:52 -070052///////////////////////////////////////////////////////////////////////////////
53// Size management
54///////////////////////////////////////////////////////////////////////////////
55
Romain Guy7d139ba2010-07-02 11:20:34 -070056uint32_t TextureCache::getSize() {
Romain Guy121e2242010-07-01 18:26:52 -070057 return mSize;
58}
59
Romain Guy7d139ba2010-07-02 11:20:34 -070060uint32_t TextureCache::getMaxSize() {
Romain Guy121e2242010-07-01 18:26:52 -070061 return mMaxSize;
62}
63
Romain Guy121e2242010-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 Guy121e2242010-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 Guy121e2242010-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
104// Returns a prepared Texture* that either is already in the cache or can fit
105// in the cache (and is thus added to the cache)
sergeyvec4a4b12016-10-20 18:39:04 -0700106Texture* TextureCache::getCachedTexture(Bitmap* bitmap) {
107 Texture* texture = mCache.get(bitmap->getStableID());
Romain Guya2341a92010-09-08 18:04:33 -0700108
Romain Guyce0537b2010-06-29 21:05:21 -0700109 if (!texture) {
John Reck860d1552014-04-11 19:15:05 -0700110 if (!canMakeTextureFromBitmap(bitmap)) {
Chris Craikd41c4d82015-01-05 15:51:13 -0800111 return nullptr;
Romain Guy9cccc2b2010-08-07 23:46:15 -0700112 }
113
Romain Guy7d139ba2010-07-02 11:20:34 -0700114 const uint32_t size = bitmap->rowBytes() * bitmap->height();
John Reck860d1552014-04-11 19:15:05 -0700115 bool canCache = size < mMaxSize;
Romain Guy121e2242010-07-01 18:26:52 -0700116 // Don't even try to cache a bitmap that's bigger than the cache
John Reck860d1552014-04-11 19:15:05 -0700117 while (canCache && mSize + size > mMaxSize) {
118 Texture* oldest = mCache.peekOldestValue();
119 if (oldest && !oldest->isInUse) {
Romain Guy121e2242010-07-01 18:26:52 -0700120 mCache.removeOldest();
John Reck860d1552014-04-11 19:15:05 -0700121 } else {
122 canCache = false;
Romain Guy121e2242010-07-01 18:26:52 -0700123 }
124 }
125
John Reck860d1552014-04-11 19:15:05 -0700126 if (canCache) {
Chris Craik8e93a7c2015-02-23 13:07:57 -0800127 texture = new Texture(Caches::getInstance());
John Reck860d1552014-04-11 19:15:05 -0700128 texture->bitmapSize = size;
John Reck38e0c322015-11-10 12:19:17 -0800129 texture->generation = bitmap->getGenerationID();
sergeyv98fa4f92016-10-24 15:35:21 -0700130 texture->upload(*bitmap);
Romain Guy121e2242010-07-01 18:26:52 -0700131
Romain Guy121e2242010-07-01 18:26:52 -0700132 mSize += size;
Romain Guy9e108412010-11-09 14:35:20 -0800133 TEXTURE_LOGD("TextureCache::get: create texture(%p): name, size, mSize = %d, %d, %d",
134 bitmap, texture->id, size, mSize);
Romain Guye190aa62010-11-10 19:01:29 -0800135 if (mDebugEnabled) {
Steve Block5baa3a62011-12-20 16:23:08 +0000136 ALOGD("Texture created, size = %d", size);
Romain Guye190aa62010-11-10 19:01:29 -0800137 }
sergeyvec4a4b12016-10-20 18:39:04 -0700138 mCache.put(bitmap->getStableID(), texture);
Romain Guy121e2242010-07-01 18:26:52 -0700139 }
John Reck860d1552014-04-11 19:15:05 -0700140 } else if (!texture->isInUse && bitmap->getGenerationID() != texture->generation) {
141 // Texture was in the cache but is dirty, re-upload
142 // TODO: Re-adjust the cache size if the bitmap's dimensions have changed
sergeyv98fa4f92016-10-24 15:35:21 -0700143 texture->upload(*bitmap);
John Reck38e0c322015-11-10 12:19:17 -0800144 texture->generation = bitmap->getGenerationID();
Romain Guyce0537b2010-06-29 21:05:21 -0700145 }
Romain Guy22158e12010-08-06 11:18:34 -0700146
Romain Guyce0537b2010-06-29 21:05:21 -0700147 return texture;
148}
149
sergeyvec4a4b12016-10-20 18:39:04 -0700150bool TextureCache::prefetchAndMarkInUse(void* ownerToken, Bitmap* bitmap) {
Romain Guy253f2c22016-09-28 17:34:42 -0700151 Texture* texture = getCachedTexture(bitmap);
John Reck860d1552014-04-11 19:15:05 -0700152 if (texture) {
John Reck00e79c92015-07-21 10:23:59 -0700153 texture->isInUse = ownerToken;
John Reck860d1552014-04-11 19:15:05 -0700154 }
155 return texture;
156}
157
sergeyvec4a4b12016-10-20 18:39:04 -0700158bool TextureCache::prefetch(Bitmap* bitmap) {
Romain Guy253f2c22016-09-28 17:34:42 -0700159 return getCachedTexture(bitmap);
John Reck43871902016-08-01 14:39:24 -0700160}
161
sergeyvec4a4b12016-10-20 18:39:04 -0700162Texture* TextureCache::get(Bitmap* bitmap) {
Romain Guy253f2c22016-09-28 17:34:42 -0700163 Texture* texture = getCachedTexture(bitmap);
John Reck860d1552014-04-11 19:15:05 -0700164
165 if (!texture) {
166 if (!canMakeTextureFromBitmap(bitmap)) {
Chris Craikd41c4d82015-01-05 15:51:13 -0800167 return nullptr;
John Reck860d1552014-04-11 19:15:05 -0700168 }
169
170 const uint32_t size = bitmap->rowBytes() * bitmap->height();
Chris Craik8e93a7c2015-02-23 13:07:57 -0800171 texture = new Texture(Caches::getInstance());
John Reck860d1552014-04-11 19:15:05 -0700172 texture->bitmapSize = size;
sergeyv98fa4f92016-10-24 15:35:21 -0700173 texture->upload(*bitmap);
John Reck38e0c322015-11-10 12:19:17 -0800174 texture->generation = bitmap->getGenerationID();
John Reck860d1552014-04-11 19:15:05 -0700175 texture->cleanup = true;
176 }
177
178 return texture;
179}
180
Derek Sollenberger3d4eed72014-12-04 15:20:29 -0500181void TextureCache::releaseTexture(uint32_t pixelRefStableID) {
Romain Guy9aaa8262010-09-08 15:15:43 -0700182 Mutex::Autolock _l(mLock);
John Reck272a6852015-07-29 16:48:58 -0700183 mGarbage.push_back(pixelRefStableID);
Romain Guyfe48f652010-11-11 15:36:56 -0800184}
185
186void TextureCache::clearGarbage() {
187 Mutex::Autolock _l(mLock);
188 size_t count = mGarbage.size();
189 for (size_t i = 0; i < count; i++) {
John Reck272a6852015-07-29 16:48:58 -0700190 uint32_t pixelRefId = mGarbage[i];
John Reck71d08a02014-11-24 15:21:28 -0800191 mCache.remove(pixelRefId);
Romain Guyfe48f652010-11-11 15:36:56 -0800192 }
193 mGarbage.clear();
194}
195
196void TextureCache::clear() {
Romain Guyce0537b2010-06-29 21:05:21 -0700197 mCache.clear();
Romain Guy912a7b32011-07-26 18:57:28 -0700198 TEXTURE_LOGD("TextureCache:clear(), mSize = %d", mSize);
Romain Guyce0537b2010-06-29 21:05:21 -0700199}
200
Romain Guyeca0ca22011-11-04 15:12:29 -0700201void TextureCache::flush() {
202 if (mFlushRate >= 1.0f || mCache.size() == 0) return;
203 if (mFlushRate <= 0.0f) {
204 clear();
205 return;
206 }
207
208 uint32_t targetSize = uint32_t(mSize * mFlushRate);
209 TEXTURE_LOGD("TextureCache::flush: target size: %d", targetSize);
210
211 while (mSize > targetSize) {
212 mCache.removeOldest();
213 }
214}
215
Romain Guyce0537b2010-06-29 21:05:21 -0700216}; // namespace uirenderer
217}; // namespace android