blob: 5ccdbda67e74b770c1873c56abcc20bd86f1eba3 [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"
Romain Guyce0537b2010-06-29 21:05:21 -070026
27namespace android {
28namespace uirenderer {
29
Romain Guy121e22422010-07-01 18:26:52 -070030///////////////////////////////////////////////////////////////////////////////
31// Constructors/destructor
32///////////////////////////////////////////////////////////////////////////////
33
Chris Craik117bdbc2015-02-05 10:12:38 -080034TextureCache::TextureCache()
35 : mCache(LruCache<uint32_t, Texture*>::kUnlimitedCapacity)
36 , mSize(0)
Chris Craik48a8f432016-02-05 15:59:29 -080037 , mMaxSize(Properties::textureCacheSize)
Romain Guy253f2c22016-09-28 17:34:42 -070038 , mFlushRate(Properties::textureCacheFlushRate) {
Romain Guyfb8b7632010-08-23 21:05:08 -070039 mCache.setOnEntryRemovedListener(this);
40
41 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
Romain Guyf6834472011-01-23 13:32:12 -080042 INIT_LOGD(" Maximum texture dimension is %d pixels", mMaxTextureSize);
Romain Guye190aa62010-11-10 19:01:29 -080043
Chris Craik2507c342015-05-04 14:36:49 -070044 mDebugEnabled = Properties::debugLevel & kDebugCaches;
Romain Guyfb8b7632010-08-23 21:05:08 -070045}
46
Chris Craik117bdbc2015-02-05 10:12:38 -080047TextureCache::~TextureCache() {
48 mCache.clear();
49}
50
Romain Guy121e22422010-07-01 18:26:52 -070051///////////////////////////////////////////////////////////////////////////////
52// Size management
53///////////////////////////////////////////////////////////////////////////////
54
Romain Guy7d139ba2010-07-02 11:20:34 -070055uint32_t TextureCache::getSize() {
Romain Guy121e22422010-07-01 18:26:52 -070056 return mSize;
57}
58
Romain Guy7d139ba2010-07-02 11:20:34 -070059uint32_t TextureCache::getMaxSize() {
Romain Guy121e22422010-07-01 18:26:52 -070060 return mMaxSize;
61}
62
Romain Guy121e22422010-07-01 18:26:52 -070063///////////////////////////////////////////////////////////////////////////////
64// Callbacks
65///////////////////////////////////////////////////////////////////////////////
66
John Reck71d08a02014-11-24 15:21:28 -080067void TextureCache::operator()(uint32_t&, Texture*& texture) {
Romain Guy9aaa8262010-09-08 15:15:43 -070068 // This will be called already locked
Romain Guy121e22422010-07-01 18:26:52 -070069 if (texture) {
Romain Guy9aaa8262010-09-08 15:15:43 -070070 mSize -= texture->bitmapSize;
Romain Guy9e108412010-11-09 14:35:20 -080071 TEXTURE_LOGD("TextureCache::callback: name, removed size, mSize = %d, %d, %d",
72 texture->id, texture->bitmapSize, mSize);
Romain Guye190aa62010-11-10 19:01:29 -080073 if (mDebugEnabled) {
Steve Block5baa3a62011-12-20 16:23:08 +000074 ALOGD("Texture deleted, size = %d", texture->bitmapSize);
Romain Guye190aa62010-11-10 19:01:29 -080075 }
Romain Guybe1b1272013-06-06 14:02:54 -070076 texture->deleteTexture();
Romain Guy121e22422010-07-01 18:26:52 -070077 delete texture;
78 }
79}
80
81///////////////////////////////////////////////////////////////////////////////
82// Caching
83///////////////////////////////////////////////////////////////////////////////
84
John Reck00e79c92015-07-21 10:23:59 -070085void TextureCache::resetMarkInUse(void* ownerToken) {
John Reck71d08a02014-11-24 15:21:28 -080086 LruCache<uint32_t, Texture*>::Iterator iter(mCache);
John Reck860d1552014-04-11 19:15:05 -070087 while (iter.next()) {
John Reck00e79c92015-07-21 10:23:59 -070088 if (iter.value()->isInUse == ownerToken) {
89 iter.value()->isInUse = nullptr;
90 }
John Reck860d1552014-04-11 19:15:05 -070091 }
92}
93
94bool TextureCache::canMakeTextureFromBitmap(const SkBitmap* bitmap) {
95 if (bitmap->width() > mMaxTextureSize || bitmap->height() > mMaxTextureSize) {
96 ALOGW("Bitmap too large to be uploaded into a texture (%dx%d, max=%dx%d)",
97 bitmap->width(), bitmap->height(), mMaxTextureSize, mMaxTextureSize);
98 return false;
99 }
100 return true;
101}
102
103// Returns a prepared Texture* that either is already in the cache or can fit
104// in the cache (and is thus added to the cache)
Romain Guy253f2c22016-09-28 17:34:42 -0700105Texture* TextureCache::getCachedTexture(const SkBitmap* bitmap) {
John Reck71d08a02014-11-24 15:21:28 -0800106 Texture* texture = mCache.get(bitmap->pixelRef()->getStableID());
Romain Guya2341a92010-09-08 18:04:33 -0700107
Romain Guyce0537b2010-06-29 21:05:21 -0700108 if (!texture) {
John Reck860d1552014-04-11 19:15:05 -0700109 if (!canMakeTextureFromBitmap(bitmap)) {
Chris Craikd41c4d82015-01-05 15:51:13 -0800110 return nullptr;
Romain Guy9cccc2b92010-08-07 23:46:15 -0700111 }
112
Romain Guy7d139ba2010-07-02 11:20:34 -0700113 const uint32_t size = bitmap->rowBytes() * bitmap->height();
John Reck860d1552014-04-11 19:15:05 -0700114 bool canCache = size < mMaxSize;
Romain Guy121e22422010-07-01 18:26:52 -0700115 // Don't even try to cache a bitmap that's bigger than the cache
John Reck860d1552014-04-11 19:15:05 -0700116 while (canCache && mSize + size > mMaxSize) {
117 Texture* oldest = mCache.peekOldestValue();
118 if (oldest && !oldest->isInUse) {
Romain Guy121e22422010-07-01 18:26:52 -0700119 mCache.removeOldest();
John Reck860d1552014-04-11 19:15:05 -0700120 } else {
121 canCache = false;
Romain Guy121e22422010-07-01 18:26:52 -0700122 }
123 }
124
John Reck860d1552014-04-11 19:15:05 -0700125 if (canCache) {
Chris Craik8e93a7c2015-02-23 13:07:57 -0800126 texture = new Texture(Caches::getInstance());
John Reck860d1552014-04-11 19:15:05 -0700127 texture->bitmapSize = size;
John Reck38e0c322015-11-10 12:19:17 -0800128 texture->generation = bitmap->getGenerationID();
129 texture->upload(*bitmap);
Romain Guy121e22422010-07-01 18:26:52 -0700130
Romain Guy121e22422010-07-01 18:26:52 -0700131 mSize += size;
Romain Guy9e108412010-11-09 14:35:20 -0800132 TEXTURE_LOGD("TextureCache::get: create texture(%p): name, size, mSize = %d, %d, %d",
133 bitmap, texture->id, size, mSize);
Romain Guye190aa62010-11-10 19:01:29 -0800134 if (mDebugEnabled) {
Steve Block5baa3a62011-12-20 16:23:08 +0000135 ALOGD("Texture created, size = %d", size);
Romain Guye190aa62010-11-10 19:01:29 -0800136 }
John Reck71d08a02014-11-24 15:21:28 -0800137 mCache.put(bitmap->pixelRef()->getStableID(), texture);
Romain Guy121e22422010-07-01 18:26:52 -0700138 }
John Reck860d1552014-04-11 19:15:05 -0700139 } else if (!texture->isInUse && bitmap->getGenerationID() != texture->generation) {
140 // Texture was in the cache but is dirty, re-upload
141 // TODO: Re-adjust the cache size if the bitmap's dimensions have changed
John Reck38e0c322015-11-10 12:19:17 -0800142 texture->upload(*bitmap);
143 texture->generation = bitmap->getGenerationID();
Romain Guyce0537b2010-06-29 21:05:21 -0700144 }
Romain Guy22158e12010-08-06 11:18:34 -0700145
Romain Guyce0537b2010-06-29 21:05:21 -0700146 return texture;
147}
148
John Reck00e79c92015-07-21 10:23:59 -0700149bool TextureCache::prefetchAndMarkInUse(void* ownerToken, const SkBitmap* bitmap) {
Romain Guy253f2c22016-09-28 17:34:42 -0700150 Texture* texture = getCachedTexture(bitmap);
John Reck860d1552014-04-11 19:15:05 -0700151 if (texture) {
John Reck00e79c92015-07-21 10:23:59 -0700152 texture->isInUse = ownerToken;
John Reck860d1552014-04-11 19:15:05 -0700153 }
154 return texture;
155}
156
John Reck43871902016-08-01 14:39:24 -0700157bool TextureCache::prefetch(const SkBitmap* bitmap) {
Romain Guy253f2c22016-09-28 17:34:42 -0700158 return getCachedTexture(bitmap);
John Reck43871902016-08-01 14:39:24 -0700159}
160
Romain Guy253f2c22016-09-28 17:34:42 -0700161Texture* TextureCache::get(const SkBitmap* bitmap) {
162 Texture* texture = getCachedTexture(bitmap);
John Reck860d1552014-04-11 19:15:05 -0700163
164 if (!texture) {
165 if (!canMakeTextureFromBitmap(bitmap)) {
Chris Craikd41c4d82015-01-05 15:51:13 -0800166 return nullptr;
John Reck860d1552014-04-11 19:15:05 -0700167 }
168
169 const uint32_t size = bitmap->rowBytes() * bitmap->height();
Chris Craik8e93a7c2015-02-23 13:07:57 -0800170 texture = new Texture(Caches::getInstance());
John Reck860d1552014-04-11 19:15:05 -0700171 texture->bitmapSize = size;
John Reck38e0c322015-11-10 12:19:17 -0800172 texture->upload(*bitmap);
173 texture->generation = bitmap->getGenerationID();
John Reck860d1552014-04-11 19:15:05 -0700174 texture->cleanup = true;
175 }
176
177 return texture;
178}
179
Derek Sollenberger3d4eed72014-12-04 15:20:29 -0500180void TextureCache::releaseTexture(uint32_t pixelRefStableID) {
Romain Guy9aaa8262010-09-08 15:15:43 -0700181 Mutex::Autolock _l(mLock);
John Reck272a6852015-07-29 16:48:58 -0700182 mGarbage.push_back(pixelRefStableID);
Romain Guyfe48f652010-11-11 15:36:56 -0800183}
184
185void TextureCache::clearGarbage() {
186 Mutex::Autolock _l(mLock);
187 size_t count = mGarbage.size();
188 for (size_t i = 0; i < count; i++) {
John Reck272a6852015-07-29 16:48:58 -0700189 uint32_t pixelRefId = mGarbage[i];
John Reck71d08a02014-11-24 15:21:28 -0800190 mCache.remove(pixelRefId);
Romain Guyfe48f652010-11-11 15:36:56 -0800191 }
192 mGarbage.clear();
193}
194
195void TextureCache::clear() {
Romain Guyce0537b2010-06-29 21:05:21 -0700196 mCache.clear();
Romain Guy912a7b32011-07-26 18:57:28 -0700197 TEXTURE_LOGD("TextureCache:clear(), mSize = %d", mSize);
Romain Guyce0537b2010-06-29 21:05:21 -0700198}
199
Romain Guyeca0ca22011-11-04 15:12:29 -0700200void TextureCache::flush() {
201 if (mFlushRate >= 1.0f || mCache.size() == 0) return;
202 if (mFlushRate <= 0.0f) {
203 clear();
204 return;
205 }
206
207 uint32_t targetSize = uint32_t(mSize * mFlushRate);
208 TEXTURE_LOGD("TextureCache::flush: target size: %d", targetSize);
209
210 while (mSize > targetSize) {
211 mCache.removeOldest();
212 }
213}
214
Romain Guyce0537b2010-06-29 21:05:21 -0700215}; // namespace uirenderer
216}; // namespace android