1 /* 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 17 #include "egl_cache.h" 18 19 #include "../egl_impl.h" 20 21 #include "egl_display.h" 22 23 #include <private/EGL/cache.h> 24 25 #include <unistd.h> 26 27 #include <thread> 28 29 #include <log/log.h> 30 31 // Cache size limits. 32 static const size_t maxKeySize = 12 * 1024; 33 static const size_t maxValueSize = 64 * 1024; 34 static const size_t maxTotalSize = 2 * 1024 * 1024; 35 36 // The time in seconds to wait before saving newly inserted cache entries. 37 static const unsigned int deferredSaveDelay = 4; 38 39 // ---------------------------------------------------------------------------- 40 namespace android { 41 // ---------------------------------------------------------------------------- 42 43 #define BC_EXT_STR "EGL_ANDROID_blob_cache" 44 45 // called from android_view_ThreadedRenderer.cpp 46 void egl_set_cache_filename(const char* filename) { 47 egl_cache_t::get()->setCacheFilename(filename); 48 } 49 50 // 51 // Callback functions passed to EGL. 52 // 53 static void setBlob(const void* key, EGLsizeiANDROID keySize, 54 const void* value, EGLsizeiANDROID valueSize) { 55 egl_cache_t::get()->setBlob(key, keySize, value, valueSize); 56 } 57 58 static EGLsizeiANDROID getBlob(const void* key, EGLsizeiANDROID keySize, 59 void* value, EGLsizeiANDROID valueSize) { 60 return egl_cache_t::get()->getBlob(key, keySize, value, valueSize); 61 } 62 63 // 64 // egl_cache_t definition 65 // 66 egl_cache_t::egl_cache_t() : 67 mInitialized(false) { 68 } 69 70 egl_cache_t::~egl_cache_t() { 71 } 72 73 egl_cache_t egl_cache_t::sCache; 74 75 egl_cache_t* egl_cache_t::get() { 76 return &sCache; 77 } 78 79 void egl_cache_t::initialize(egl_display_t *display) { 80 std::lock_guard<std::mutex> lock(mMutex); 81 82 egl_connection_t* const cnx = &gEGLImpl; 83 if (cnx->dso && cnx->major >= 0 && cnx->minor >= 0) { 84 const char* exts = display->disp.queryString.extensions; 85 size_t bcExtLen = strlen(BC_EXT_STR); 86 size_t extsLen = strlen(exts); 87 bool equal = !strcmp(BC_EXT_STR, exts); 88 bool atStart = !strncmp(BC_EXT_STR " ", exts, bcExtLen+1); 89 bool atEnd = (bcExtLen+1) < extsLen && 90 !strcmp(" " BC_EXT_STR, exts + extsLen - (bcExtLen+1)); 91 bool inMiddle = strstr(exts, " " BC_EXT_STR " ") != nullptr; 92 if (equal || atStart || atEnd || inMiddle) { 93 PFNEGLSETBLOBCACHEFUNCSANDROIDPROC eglSetBlobCacheFuncsANDROID; 94 eglSetBlobCacheFuncsANDROID = 95 reinterpret_cast<PFNEGLSETBLOBCACHEFUNCSANDROIDPROC>( 96 cnx->egl.eglGetProcAddress( 97 "eglSetBlobCacheFuncsANDROID")); 98 if (eglSetBlobCacheFuncsANDROID == nullptr) { 99 ALOGE("EGL_ANDROID_blob_cache advertised, " 100 "but unable to get eglSetBlobCacheFuncsANDROID"); 101 return; 102 } 103 104 eglSetBlobCacheFuncsANDROID(display->disp.dpy, 105 android::setBlob, android::getBlob); 106 EGLint err = cnx->egl.eglGetError(); 107 if (err != EGL_SUCCESS) { 108 ALOGE("eglSetBlobCacheFuncsANDROID resulted in an error: " 109 "%#x", err); 110 } 111 } 112 } 113 114 mInitialized = true; 115 } 116 117 void egl_cache_t::terminate() { 118 std::lock_guard<std::mutex> lock(mMutex); 119 if (mBlobCache) { 120 mBlobCache->writeToFile(); 121 } 122 mBlobCache = nullptr; 123 } 124 125 void egl_cache_t::setBlob(const void* key, EGLsizeiANDROID keySize, 126 const void* value, EGLsizeiANDROID valueSize) { 127 std::lock_guard<std::mutex> lock(mMutex); 128 129 if (keySize < 0 || valueSize < 0) { 130 ALOGW("EGL_ANDROID_blob_cache set: negative sizes are not allowed"); 131 return; 132 } 133 134 if (mInitialized) { 135 BlobCache* bc = getBlobCacheLocked(); 136 bc->set(key, keySize, value, valueSize); 137 138 if (!mSavePending) { 139 mSavePending = true; 140 std::thread deferredSaveThread([this]() { 141 sleep(deferredSaveDelay); 142 std::lock_guard<std::mutex> lock(mMutex); 143 if (mInitialized && mBlobCache) { 144 mBlobCache->writeToFile(); 145 } 146 mSavePending = false; 147 }); 148 deferredSaveThread.detach(); 149 } 150 } 151 } 152 153 EGLsizeiANDROID egl_cache_t::getBlob(const void* key, EGLsizeiANDROID keySize, 154 void* value, EGLsizeiANDROID valueSize) { 155 std::lock_guard<std::mutex> lock(mMutex); 156 157 if (keySize < 0 || valueSize < 0) { 158 ALOGW("EGL_ANDROID_blob_cache set: negative sizes are not allowed"); 159 return 0; 160 } 161 162 if (mInitialized) { 163 BlobCache* bc = getBlobCacheLocked(); 164 return bc->get(key, keySize, value, valueSize); 165 } 166 return 0; 167 } 168 169 void egl_cache_t::setCacheFilename(const char* filename) { 170 std::lock_guard<std::mutex> lock(mMutex); 171 mFilename = filename; 172 } 173 174 BlobCache* egl_cache_t::getBlobCacheLocked() { 175 if (mBlobCache == nullptr) { 176 mBlobCache.reset(new FileBlobCache(maxKeySize, maxValueSize, maxTotalSize, mFilename)); 177 } 178 return mBlobCache.get(); 179 } 180 181 // ---------------------------------------------------------------------------- 182 }; // namespace android 183 // ---------------------------------------------------------------------------- 184