blob: 5e729ef47cf4cbeb172d6386004ac9f922f26566 [file] [log] [blame]
Jamie Gennisaca51c02011-11-03 17:42:43 -07001/*
2 ** Copyright 2011, 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
Mathias Agopian311b4792017-02-28 15:00:49 -080017#include "egl_cache.h"
18
Cody Northropc4524992022-12-12 11:35:54 -070019#include <android-base/properties.h>
20#include <inttypes.h>
Yiwei Zhang8af03062020-08-12 21:28:15 -070021#include <log/log.h>
Mathias Agopianb7f9a242017-03-08 22:29:31 -080022#include <private/EGL/cache.h>
Jiyong Parka243e5d2017-06-21 12:26:51 +090023#include <unistd.h>
Mathias Agopian311b4792017-02-28 15:00:49 -080024
Mathias Agopian65421432017-03-08 11:49:05 -080025#include <thread>
26
Yiwei Zhang8af03062020-08-12 21:28:15 -070027#include "../egl_impl.h"
Cody Northropc4524992022-12-12 11:35:54 -070028#include "egl_cache_multifile.h"
Yiwei Zhang8af03062020-08-12 21:28:15 -070029#include "egl_display.h"
Jamie Gennis98c63832011-11-07 17:03:54 -080030
Jamie Gennis76601082011-11-06 14:14:33 -080031// Cache size limits.
Dan Willemsenbace39e2016-10-11 15:42:59 -070032static const size_t maxKeySize = 12 * 1024;
33static const size_t maxValueSize = 64 * 1024;
Trevor David Black94764682022-09-26 20:31:28 +000034static const size_t maxTotalSize = 32 * 1024 * 1024;
Jamie Gennis76601082011-11-06 14:14:33 -080035
Jamie Gennis99c3d702011-11-08 17:59:36 -080036// The time in seconds to wait before saving newly inserted cache entries.
37static const unsigned int deferredSaveDelay = 4;
38
Cody Northropc4524992022-12-12 11:35:54 -070039// Delay before cleaning up multifile cache entries
40static const unsigned int deferredMultifileCleanupDelaySeconds = 1;
41
Jamie Gennisaca51c02011-11-03 17:42:43 -070042namespace android {
Jamie Gennisaca51c02011-11-03 17:42:43 -070043
44#define BC_EXT_STR "EGL_ANDROID_blob_cache"
45
Mathias Agopianb7f9a242017-03-08 22:29:31 -080046// called from android_view_ThreadedRenderer.cpp
47void egl_set_cache_filename(const char* filename) {
48 egl_cache_t::get()->setCacheFilename(filename);
49}
50
Jamie Gennisaca51c02011-11-03 17:42:43 -070051//
Jamie Gennis76601082011-11-06 14:14:33 -080052// Callback functions passed to EGL.
Jamie Gennisaca51c02011-11-03 17:42:43 -070053//
Yiwei Zhang8af03062020-08-12 21:28:15 -070054static void setBlob(const void* key, EGLsizeiANDROID keySize, const void* value,
55 EGLsizeiANDROID valueSize) {
Jamie Gennis76601082011-11-06 14:14:33 -080056 egl_cache_t::get()->setBlob(key, keySize, value, valueSize);
Jamie Gennisaca51c02011-11-03 17:42:43 -070057}
58
Yiwei Zhang8af03062020-08-12 21:28:15 -070059static EGLsizeiANDROID getBlob(const void* key, EGLsizeiANDROID keySize, void* value,
60 EGLsizeiANDROID valueSize) {
Jamie Gennis76601082011-11-06 14:14:33 -080061 return egl_cache_t::get()->getBlob(key, keySize, value, valueSize);
62}
63
64//
65// egl_cache_t definition
66//
Cody Northropc4524992022-12-12 11:35:54 -070067egl_cache_t::egl_cache_t()
68 : mInitialized(false), mMultifileMode(true), mCacheByteLimit(maxTotalSize) {}
Jamie Gennis76601082011-11-06 14:14:33 -080069
Yiwei Zhang8af03062020-08-12 21:28:15 -070070egl_cache_t::~egl_cache_t() {}
Jamie Gennisaca51c02011-11-03 17:42:43 -070071
Jamie Gennis98c63832011-11-07 17:03:54 -080072egl_cache_t egl_cache_t::sCache;
73
Jamie Gennisaca51c02011-11-03 17:42:43 -070074egl_cache_t* egl_cache_t::get() {
Jamie Gennis98c63832011-11-07 17:03:54 -080075 return &sCache;
Jamie Gennisaca51c02011-11-03 17:42:43 -070076}
77
Yiwei Zhang8af03062020-08-12 21:28:15 -070078void egl_cache_t::initialize(egl_display_t* display) {
Mathias Agopian65421432017-03-08 11:49:05 -080079 std::lock_guard<std::mutex> lock(mMutex);
Mathias Agopianada798b2012-02-13 17:09:30 -080080
81 egl_connection_t* const cnx = &gEGLImpl;
82 if (cnx->dso && cnx->major >= 0 && cnx->minor >= 0) {
83 const char* exts = display->disp.queryString.extensions;
84 size_t bcExtLen = strlen(BC_EXT_STR);
85 size_t extsLen = strlen(exts);
86 bool equal = !strcmp(BC_EXT_STR, exts);
Yiwei Zhang8af03062020-08-12 21:28:15 -070087 bool atStart = !strncmp(BC_EXT_STR " ", exts, bcExtLen + 1);
88 bool atEnd = (bcExtLen + 1) < extsLen &&
89 !strcmp(" " BC_EXT_STR, exts + extsLen - (bcExtLen + 1));
Mathias Agopian311b4792017-02-28 15:00:49 -080090 bool inMiddle = strstr(exts, " " BC_EXT_STR " ") != nullptr;
Mathias Agopianada798b2012-02-13 17:09:30 -080091 if (equal || atStart || atEnd || inMiddle) {
92 PFNEGLSETBLOBCACHEFUNCSANDROIDPROC eglSetBlobCacheFuncsANDROID;
Yiwei Zhang8af03062020-08-12 21:28:15 -070093 eglSetBlobCacheFuncsANDROID = reinterpret_cast<PFNEGLSETBLOBCACHEFUNCSANDROIDPROC>(
94 cnx->egl.eglGetProcAddress("eglSetBlobCacheFuncsANDROID"));
Yi Kong48a6cd22018-07-18 10:07:09 -070095 if (eglSetBlobCacheFuncsANDROID == nullptr) {
Mathias Agopianada798b2012-02-13 17:09:30 -080096 ALOGE("EGL_ANDROID_blob_cache advertised, "
Yiwei Zhang8af03062020-08-12 21:28:15 -070097 "but unable to get eglSetBlobCacheFuncsANDROID");
Mathias Agopianada798b2012-02-13 17:09:30 -080098 return;
99 }
Jamie Gennisaca51c02011-11-03 17:42:43 -0700100
Yiwei Zhang8af03062020-08-12 21:28:15 -0700101 eglSetBlobCacheFuncsANDROID(display->disp.dpy, android::setBlob, android::getBlob);
Mathias Agopianada798b2012-02-13 17:09:30 -0800102 EGLint err = cnx->egl.eglGetError();
103 if (err != EGL_SUCCESS) {
104 ALOGE("eglSetBlobCacheFuncsANDROID resulted in an error: "
Yiwei Zhang8af03062020-08-12 21:28:15 -0700105 "%#x",
106 err);
Jamie Gennisaca51c02011-11-03 17:42:43 -0700107 }
108 }
109 }
Mathias Agopianada798b2012-02-13 17:09:30 -0800110
Cody Northropc4524992022-12-12 11:35:54 -0700111 mMultifileMode = true;
112
113 // Allow forcing monolithic cache for debug purposes
114 if (base::GetProperty("debug.egl.blobcache.multifilemode", "") == "false") {
115 ALOGD("Forcing monolithic cache due to debug.egl.blobcache.multifilemode == \"false\"");
116 mMultifileMode = false;
117 }
118
Jamie Gennis76601082011-11-06 14:14:33 -0800119 mInitialized = true;
120}
121
122void egl_cache_t::terminate() {
Mathias Agopian65421432017-03-08 11:49:05 -0800123 std::lock_guard<std::mutex> lock(mMutex);
Stan Iliev9e7cd072017-10-09 15:56:10 -0400124 if (mBlobCache) {
125 mBlobCache->writeToFile();
126 }
Yi Kong48a6cd22018-07-18 10:07:09 -0700127 mBlobCache = nullptr;
Cody Northropc4524992022-12-12 11:35:54 -0700128 if (mMultifileMode) {
129 checkMultifileCacheSize(mCacheByteLimit);
130 }
131 mMultifileMode = false;
132 mInitialized = false;
Jamie Gennis76601082011-11-06 14:14:33 -0800133}
134
Yiwei Zhang8af03062020-08-12 21:28:15 -0700135void egl_cache_t::setBlob(const void* key, EGLsizeiANDROID keySize, const void* value,
136 EGLsizeiANDROID valueSize) {
Mathias Agopian65421432017-03-08 11:49:05 -0800137 std::lock_guard<std::mutex> lock(mMutex);
Jamie Gennis76601082011-11-06 14:14:33 -0800138
139 if (keySize < 0 || valueSize < 0) {
Steve Block32397c12012-01-05 23:22:43 +0000140 ALOGW("EGL_ANDROID_blob_cache set: negative sizes are not allowed");
Jamie Gennis76601082011-11-06 14:14:33 -0800141 return;
142 }
143
144 if (mInitialized) {
Cody Northropc4524992022-12-12 11:35:54 -0700145 if (mMultifileMode) {
146 setBlobMultifile(key, keySize, value, valueSize, mFilename);
Jamie Gennis99c3d702011-11-08 17:59:36 -0800147
Cody Northropc4524992022-12-12 11:35:54 -0700148 if (!mMultifileCleanupPending) {
149 mMultifileCleanupPending = true;
150 // Kick off a thread to cull cache files below limit
151 std::thread deferredMultifileCleanupThread([this]() {
152 sleep(deferredMultifileCleanupDelaySeconds);
153 std::lock_guard<std::mutex> lock(mMutex);
154 // Check the size of cache and remove entries to stay under limit
155 checkMultifileCacheSize(mCacheByteLimit);
156 mMultifileCleanupPending = false;
157 });
158 deferredMultifileCleanupThread.detach();
159 }
160 } else {
161 BlobCache* bc = getBlobCacheLocked();
162 bc->set(key, keySize, value, valueSize);
163
164 if (!mSavePending) {
165 mSavePending = true;
166 std::thread deferredSaveThread([this]() {
167 sleep(deferredSaveDelay);
168 std::lock_guard<std::mutex> lock(mMutex);
169 if (mInitialized && mBlobCache) {
170 mBlobCache->writeToFile();
171 }
172 mSavePending = false;
173 });
174 deferredSaveThread.detach();
175 }
Jamie Gennis99c3d702011-11-08 17:59:36 -0800176 }
Jamie Gennis76601082011-11-06 14:14:33 -0800177 }
178}
179
Yiwei Zhang8af03062020-08-12 21:28:15 -0700180EGLsizeiANDROID egl_cache_t::getBlob(const void* key, EGLsizeiANDROID keySize, void* value,
181 EGLsizeiANDROID valueSize) {
Mathias Agopian65421432017-03-08 11:49:05 -0800182 std::lock_guard<std::mutex> lock(mMutex);
Jamie Gennis76601082011-11-06 14:14:33 -0800183
184 if (keySize < 0 || valueSize < 0) {
Cody Northropc4524992022-12-12 11:35:54 -0700185 ALOGW("EGL_ANDROID_blob_cache get: negative sizes are not allowed");
Jamie Gennis76601082011-11-06 14:14:33 -0800186 return 0;
187 }
188
189 if (mInitialized) {
Cody Northropc4524992022-12-12 11:35:54 -0700190 if (mMultifileMode) {
191 return getBlobMultifile(key, keySize, value, valueSize, mFilename);
192 } else {
193 BlobCache* bc = getBlobCacheLocked();
194 return bc->get(key, keySize, value, valueSize);
195 }
Jamie Gennis76601082011-11-06 14:14:33 -0800196 }
197 return 0;
198}
199
Jamie Gennis98c63832011-11-07 17:03:54 -0800200void egl_cache_t::setCacheFilename(const char* filename) {
Mathias Agopian65421432017-03-08 11:49:05 -0800201 std::lock_guard<std::mutex> lock(mMutex);
Jamie Gennis98c63832011-11-07 17:03:54 -0800202 mFilename = filename;
203}
204
Cody Northropc4524992022-12-12 11:35:54 -0700205void egl_cache_t::setCacheLimit(int64_t cacheByteLimit) {
206 std::lock_guard<std::mutex> lock(mMutex);
207
208 if (!mMultifileMode) {
209 // If we're not in multifile mode, ensure the cache limit is only being lowered,
210 // not increasing above the hard coded platform limit
211 if (cacheByteLimit > maxTotalSize) {
212 return;
213 }
214 }
215
216 mCacheByteLimit = cacheByteLimit;
217}
218
219size_t egl_cache_t::getCacheSize() {
220 std::lock_guard<std::mutex> lock(mMutex);
221 if (mMultifileMode) {
222 return getMultifileCacheSize();
223 }
224 if (mBlobCache) {
225 return mBlobCache->getSize();
226 }
227 return 0;
228}
229
Mathias Agopianb7f9a242017-03-08 22:29:31 -0800230BlobCache* egl_cache_t::getBlobCacheLocked() {
231 if (mBlobCache == nullptr) {
Cody Northropc4524992022-12-12 11:35:54 -0700232 mBlobCache.reset(new FileBlobCache(maxKeySize, maxValueSize, mCacheByteLimit, mFilename));
Jamie Gennis76601082011-11-06 14:14:33 -0800233 }
Mathias Agopianb7f9a242017-03-08 22:29:31 -0800234 return mBlobCache.get();
Jamie Gennis76601082011-11-06 14:14:33 -0800235}
236
Jamie Gennisaca51c02011-11-03 17:42:43 -0700237}; // namespace android