Home | History | Annotate | Download | only in EGL
      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 == NULL) {
     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 = NULL;
    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