Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 65421435 authored by Mathias Agopian's avatar Mathias Agopian
Browse files

Remove dependency to most of libutils

Most of libutils is replaced by using the STL,
this is fine in this case because none of it
leaks out of EGL’s internals.

Test: compiled & run
Bug: vndk-stable

Change-Id: I42ded4043ddc98ed7eaa975fbbb2e754cd3219af
parent 4e67f0f8
Loading
Loading
Loading
Loading
+30 −32
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@

#include "Loader.h"

#include <string>

#include <dirent.h>
#include <dlfcn.h>

@@ -26,11 +28,9 @@
#include <cutils/properties.h>
#include <log/log.h>

#include <utils/String8.h>
#include <utils/Trace.h>

#include <ui/GraphicsEnv.h>

#include "egl_trace.h"
#include "egldefs.h"

// ----------------------------------------------------------------------------
@@ -61,7 +61,10 @@ namespace android {
 *
 */

ANDROID_SINGLETON_STATIC_INSTANCE( Loader )
Loader& Loader::getInstance() {
    static Loader loader;
    return loader;
}

/* This function is called to check whether we run inside the emulator,
 * and if this is the case whether GLES GPU emulation is supported.
@@ -122,7 +125,7 @@ Loader::driver_t::~driver_t()
    }
}

status_t Loader::driver_t::set(void* hnd, int32_t api)
int Loader::driver_t::set(void* hnd, int32_t api)
{
    switch (api) {
        case EGL:
@@ -135,9 +138,9 @@ status_t Loader::driver_t::set(void* hnd, int32_t api)
            dso[2] = hnd;
            break;
        default:
            return BAD_INDEX;
            return -EOVERFLOW;
    }
    return NO_ERROR;
    return 0;
}

// ----------------------------------------------------------------------------
@@ -233,11 +236,10 @@ void* Loader::open(egl_connection_t* cnx)
    return (void*)hnd;
}

status_t Loader::close(void* driver)
void Loader::close(void* driver)
{
    driver_t* hnd = (driver_t*)driver;
    delete hnd;
    return NO_ERROR;
}

void Loader::init_api(void* dso,
@@ -302,23 +304,23 @@ static void* load_system_driver(const char* kind) {
    ATRACE_CALL();
    class MatchFile {
    public:
        static String8 find(const char* kind) {
            String8 result;
        static std::string find(const char* kind) {
            std::string result;
            int emulationStatus = checkGlesEmulationStatus();
            switch (emulationStatus) {
                case 0:
#if defined(__LP64__)
                    result.setTo("/system/lib64/egl/libGLES_android.so");
                    result = "/system/lib64/egl/libGLES_android.so";
#else
                    result.setTo("/system/lib/egl/libGLES_android.so");
                    result = "/system/lib/egl/libGLES_android.so";
#endif
                    return result;
                case 1:
                    // Use host-side OpenGL through the "emulation" library
#if defined(__LP64__)
                    result.appendFormat("/system/lib64/egl/lib%s_emulation.so", kind);
                    result = std::string("/system/lib64/egl/lib") + kind + "_emulation.so";
#else
                    result.appendFormat("/system/lib/egl/lib%s_emulation.so", kind);
                    result = std::string("/system/lib/egl/lib") + kind + "_emulation.so";
#endif
                    return result;
                default:
@@ -326,8 +328,7 @@ static void* load_system_driver(const char* kind) {
                    break;
            }

            String8 pattern;
            pattern.appendFormat("lib%s", kind);
            std::string pattern = std::string("lib") + kind;
            const char* const searchPaths[] = {
#if defined(__LP64__)
                    "/vendor/lib64/egl",
@@ -368,12 +369,11 @@ static void* load_system_driver(const char* kind) {
        }

    private:
        static bool find(String8& result,
                const String8& pattern, const char* const search, bool exact) {
        static bool find(std::string& result,
                const std::string& pattern, const char* const search, bool exact) {
            if (exact) {
                String8 absolutePath;
                absolutePath.appendFormat("%s/%s.so", search, pattern.string());
                if (!access(absolutePath.string(), R_OK)) {
                std::string absolutePath = std::string(search) + "/" + pattern;
                if (!access(absolutePath.c_str(), R_OK)) {
                    result = absolutePath;
                    return true;
                }
@@ -392,10 +392,9 @@ static void* load_system_driver(const char* kind) {
                        // always skip the software renderer
                        continue;
                    }
                    if (strstr(e->d_name, pattern.string()) == e->d_name) {
                    if (strstr(e->d_name, pattern.c_str()) == e->d_name) {
                        if (!strcmp(e->d_name + strlen(e->d_name) - 3, ".so")) {
                            result.clear();
                            result.appendFormat("%s/%s", search, e->d_name);
                            result = std::string(search) + "/" + e->d_name;
                            closedir(d);
                            return true;
                        }
@@ -408,12 +407,12 @@ static void* load_system_driver(const char* kind) {
    };


    String8 absolutePath = MatchFile::find(kind);
    if (absolutePath.isEmpty()) {
    std::string absolutePath = MatchFile::find(kind);
    if (absolutePath.empty()) {
        // this happens often, we don't want to log an error
        return 0;
    }
    const char* const driver_absolute_path = absolutePath.string();
    const char* const driver_absolute_path = absolutePath.c_str();

    void* dso = do_dlopen(driver_absolute_path, RTLD_NOW | RTLD_LOCAL);
    if (dso == 0) {
@@ -447,9 +446,8 @@ static void* load_updated_driver(const char* kind, android_namespace_t* ns) {
    char prop[PROPERTY_VALUE_MAX + 1];
    for (auto key : HAL_SUBNAME_KEY_PROPERTIES) {
        if (property_get(key, prop, nullptr) > 0) {
            String8 name;
            name.appendFormat("lib%s_%s.so", kind, prop);
            so = do_android_dlopen_ext(name.string(), RTLD_LOCAL | RTLD_NOW, &dlextinfo);
            std::string name = std::string("lib") + kind + "_" + prop + ".so";
            so = do_android_dlopen_ext(name.c_str(), RTLD_LOCAL | RTLD_NOW, &dlextinfo);
            if (so) {
                return so;
            }
+5 −8
Original line number Diff line number Diff line
@@ -19,9 +19,6 @@

#include <stdint.h>

#include <utils/Errors.h>
#include <utils/Singleton.h>

#include <EGL/egl.h>

// ----------------------------------------------------------------------------
@@ -30,9 +27,7 @@ namespace android {

struct egl_connection_t;

class Loader : public Singleton<Loader> {
    friend class Singleton<Loader>;

class Loader {
    typedef __eglMustCastToProperFunctionPointerType (* getProcAddressType)(const char*);
   
    enum {
@@ -43,17 +38,19 @@ class Loader : public Singleton<Loader> {
    struct driver_t {
        explicit driver_t(void* gles);
        ~driver_t();
        status_t set(void* hnd, int32_t api);
        // returns -errno
        int set(void* hnd, int32_t api);
        void* dso[3];
    };
    
    getProcAddressType getProcAddress;

public:
    static Loader& getInstance();
    ~Loader();
    
    void* open(egl_connection_t* cnx);
    status_t close(void* driver);
    void close(void* driver);
    
private:
    Loader();
+6 −7
Original line number Diff line number Diff line
@@ -20,7 +20,6 @@

#include <EGL/egl.h>

#include <cutils/atomic.h>
#include <cutils/properties.h>

#include <log/log.h>
@@ -128,7 +127,7 @@ const GLubyte * egl_get_string_for_current_context(GLenum name) {
    if (name != GL_EXTENSIONS)
        return NULL;

    return (const GLubyte *)c->gl_extensions.string();
    return (const GLubyte *)c->gl_extensions.c_str();
}

const GLubyte * egl_get_string_for_current_context(GLenum name, GLuint index) {
@@ -151,7 +150,7 @@ const GLubyte * egl_get_string_for_current_context(GLenum name, GLuint index) {
    if (index >= c->tokenized_gl_extensions.size())
        return NULL;

    return (const GLubyte *)c->tokenized_gl_extensions.itemAt(index).string();
    return (const GLubyte *)c->tokenized_gl_extensions[index].c_str();
}

GLint egl_get_num_extensions_for_current_context() {
@@ -208,14 +207,14 @@ EGLBoolean egl_init_drivers() {
}

static pthread_mutex_t sLogPrintMutex = PTHREAD_MUTEX_INITIALIZER;
static nsecs_t sLogPrintTime = 0;
#define NSECS_DURATION 1000000000
static std::chrono::steady_clock::time_point sLogPrintTime;
static constexpr std::chrono::seconds DURATION(1);

void gl_unimplemented() {
    bool printLog = false;
    nsecs_t now = systemTime();
    auto now = std::chrono::steady_clock::now();
    pthread_mutex_lock(&sLogPrintMutex);
    if ((now - sLogPrintTime) > NSECS_DURATION) {
    if ((now - sLogPrintTime) > DURATION) {
        sLogPrintTime = now;
        printLog = true;
    }
+82 −63
Original line number Diff line number Diff line
@@ -33,16 +33,19 @@
#include <cutils/properties.h>
#include <log/log.h>

#include <utils/KeyedVector.h>
#include <utils/String8.h>
#include <utils/Trace.h>
#include <utils/Thread.h>
#include <condition_variable>
#include <deque>
#include <mutex>
#include <unordered_map>
#include <string>
#include <thread>

#include "../egl_impl.h"

#include "egl_display.h"
#include "egl_object.h"
#include "egl_tls.h"
#include "egl_trace.h"

using namespace android;

@@ -50,6 +53,8 @@ using namespace android;

namespace android {

using nsecs_t = int64_t;

struct extention_map_t {
    const char* name;
    __eglMustCastToProperFunctionPointerType address;
@@ -233,7 +238,8 @@ static const extention_map_t sExtensionMap[] = {


// accesses protected by sExtensionMapMutex
static DefaultKeyedVector<String8, __eglMustCastToProperFunctionPointerType> sGLExtentionMap;
static std::unordered_map<std::string, __eglMustCastToProperFunctionPointerType> sGLExtentionMap;

static int sGLExtentionSlot = 0;
static pthread_mutex_t sExtensionMapMutex = PTHREAD_MUTEX_INITIALIZER;

@@ -475,7 +481,7 @@ EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config,
        }

        int result = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
        if (result != OK) {
        if (result < 0) {
            ALOGE("eglCreateWindowSurface: native_window_api_connect (win=%p) "
                    "failed (%#x) (already connected to another API?)",
                    window, result);
@@ -988,8 +994,11 @@ __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
         *
         */

        const String8 name(procname);
        addr = sGLExtentionMap.valueFor(name);
        const std::string name(procname);

    auto& extentionMap = sGLExtentionMap;
    auto pos = extentionMap.find(name);
        addr = (pos != extentionMap.end()) ? pos->second : nullptr;
        const int slot = sGLExtentionSlot;

        ALOGE_IF(slot >= MAX_NUMBER_OF_GL_EXTENSIONS,
@@ -1011,7 +1020,7 @@ __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)

            if (found) {
                addr = gExtensionForwarders[slot];
                sGLExtentionMap.add(name, addr);
                extentionMap[name] = addr;
                sGLExtentionSlot++;
            }
        }
@@ -1020,45 +1029,57 @@ __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
    return addr;
}

class FrameCompletionThread : public Thread {
class FrameCompletionThread {
public:

    static void queueSync(EGLSyncKHR sync) {
        static sp<FrameCompletionThread> thread(new FrameCompletionThread);
        static bool running = false;
        if (!running) {
            thread->run("GPUFrameCompletion");
            running = true;
        }
        {
            Mutex::Autolock lock(thread->mMutex);
            ScopedTrace st(ATRACE_TAG, String8::format("kicked off frame %d",
                    thread->mFramesQueued).string());
            thread->mQueue.push_back(sync);
            thread->mCondition.signal();
            thread->mFramesQueued++;
            ATRACE_INT("GPU Frames Outstanding", int32_t(thread->mQueue.size()));
        }
        static FrameCompletionThread thread;

        char name[64];

        std::lock_guard<std::mutex> lock(thread.mMutex);
        snprintf(name, sizeof(name), "kicked off frame %u", (unsigned int)thread.mFramesQueued);
        ATRACE_NAME(name);

        thread.mQueue.push_back(sync);
        thread.mCondition.notify_one();
        thread.mFramesQueued++;
        ATRACE_INT("GPU Frames Outstanding", int32_t(thread.mQueue.size()));
    }

private:
    FrameCompletionThread() : mFramesQueued(0), mFramesCompleted(0) {}

    virtual bool threadLoop() {
    FrameCompletionThread() : mFramesQueued(0), mFramesCompleted(0) {
        std::thread thread(&FrameCompletionThread::loop, this);
        thread.detach();
    }

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wmissing-noreturn"
    void loop() {
        while (true) {
            threadLoop();
        }
    }
#pragma clang diagnostic pop

    void threadLoop() {
        EGLSyncKHR sync;
        uint32_t frameNum;
        {
            Mutex::Autolock lock(mMutex);
            while (mQueue.isEmpty()) {
                mCondition.wait(mMutex);
            std::unique_lock<std::mutex> lock(mMutex);
            while (mQueue.empty()) {
                mCondition.wait(lock);
            }
            sync = mQueue[0];
            frameNum = mFramesCompleted;
        }
        EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
        {
            ScopedTrace st(ATRACE_TAG, String8::format("waiting for frame %d",
                    frameNum).string());
            char name[64];
            snprintf(name, sizeof(name), "waiting for frame %u", (unsigned int)frameNum);
            ATRACE_NAME(name);

            EGLint result = eglClientWaitSyncKHR(dpy, sync, 0, EGL_FOREVER_KHR);
            if (result == EGL_FALSE) {
                ALOGE("FrameCompletion: error waiting for fence: %#x", eglGetError());
@@ -1068,19 +1089,18 @@ private:
            eglDestroySyncKHR(dpy, sync);
        }
        {
            Mutex::Autolock lock(mMutex);
            mQueue.removeAt(0);
            std::lock_guard<std::mutex> lock(mMutex);
            mQueue.pop_front();
            mFramesCompleted++;
            ATRACE_INT("GPU Frames Outstanding", int32_t(mQueue.size()));
        }
        return true;
    }

    uint32_t mFramesQueued;
    uint32_t mFramesCompleted;
    Vector<EGLSyncKHR> mQueue;
    Condition mCondition;
    Mutex mMutex;
    std::deque<EGLSyncKHR> mQueue;
    std::condition_variable mCondition;
    std::mutex mMutex;
};

EGLBoolean eglSwapBuffersWithDamageKHR(EGLDisplay dpy, EGLSurface draw,
@@ -1119,7 +1139,7 @@ EGLBoolean eglSwapBuffersWithDamageKHR(EGLDisplay dpy, EGLSurface draw,
        return s->cnx->egl.eglSwapBuffers(dp->disp.dpy, s->surface);
    }

    Vector<android_native_rect_t> androidRects;
    std::vector<android_native_rect_t> androidRects((size_t)n_rects);
    for (int r = 0; r < n_rects; ++r) {
        int offset = r * 4;
        int x = rects[offset];
@@ -1133,8 +1153,7 @@ EGLBoolean eglSwapBuffersWithDamageKHR(EGLDisplay dpy, EGLSurface draw,
        androidRect.bottom = y;
        androidRects.push_back(androidRect);
    }
    native_window_set_surface_damage(s->win.get(), androidRects.array(),
            androidRects.size());
    native_window_set_surface_damage(s->getNativeWindow(), androidRects.data(), androidRects.size());

    if (s->cnx->egl.eglSwapBuffersWithDamageKHR) {
        return s->cnx->egl.eglSwapBuffersWithDamageKHR(dp->disp.dpy, s->surface,
@@ -1238,19 +1257,19 @@ EGLBoolean eglSurfaceAttrib(
    egl_surface_t * const s = get_surface(surface);

    if (attribute == EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID) {
        if (!s->win.get()) {
        if (!s->getNativeWindow()) {
            setError(EGL_BAD_SURFACE, EGL_FALSE);
        }
        int err = native_window_set_auto_refresh(s->win.get(), value ? true : false);
        return (err == NO_ERROR) ? EGL_TRUE : setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
        int err = native_window_set_auto_refresh(s->getNativeWindow(), value != 0);
        return (err == 0) ? EGL_TRUE : setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
    }

    if (attribute == EGL_TIMESTAMPS_ANDROID) {
        if (!s->win.get()) {
        if (!s->getNativeWindow()) {
            return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
        }
        int err = native_window_enable_frame_timestamps(s->win.get(), value ? true : false);
        return (err == NO_ERROR) ? EGL_TRUE : setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
        int err = native_window_enable_frame_timestamps(s->getNativeWindow(), value != 0);
        return (err == 0) ? EGL_TRUE : setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
    }

    if (s->cnx->egl.eglSurfaceAttrib) {
@@ -1825,7 +1844,7 @@ EGLBoolean eglPresentationTimeANDROID(EGLDisplay dpy, EGLSurface surface,
    }

    egl_surface_t const * const s = get_surface(surface);
    native_window_set_buffers_timestamp(s->win.get(), time);
    native_window_set_buffers_timestamp(s->getNativeWindow(), time);

    return EGL_TRUE;
}
@@ -1920,14 +1939,14 @@ EGLBoolean eglGetNextFrameIdANDROID(EGLDisplay dpy, EGLSurface surface,

    egl_surface_t const * const s = get_surface(surface);

    if (!s->win.get()) {
    if (!s->getNativeWindow()) {
        return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
    }

    uint64_t nextFrameId = 0;
    status_t ret = native_window_get_next_frame_id(s->win.get(), &nextFrameId);
    int ret = native_window_get_next_frame_id(s->getNativeWindow(), &nextFrameId);

    if (ret != NO_ERROR) {
    if (ret != 0) {
        // This should not happen. Return an error that is not in the spec
        // so it's obvious something is very wrong.
        ALOGE("eglGetNextFrameId: Unexpected error.");
@@ -1955,7 +1974,7 @@ EGLBoolean eglGetCompositorTimingANDROID(EGLDisplay dpy, EGLSurface surface,

    egl_surface_t const * const s = get_surface(surface);

    if (!s->win.get()) {
    if (!s->getNativeWindow()) {
        return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
    }

@@ -1979,13 +1998,13 @@ EGLBoolean eglGetCompositorTimingANDROID(EGLDisplay dpy, EGLSurface surface,
        }
    }

    status_t ret = native_window_get_compositor_timing(s->win.get(),
    int ret = native_window_get_compositor_timing(s->getNativeWindow(),
            compositeDeadline, compositeInterval, compositeToPresentLatency);

    switch (ret) {
      case NO_ERROR:
      case 0:
        return EGL_TRUE;
      case INVALID_OPERATION:
      case -ENOSYS:
        return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
      default:
        // This should not happen. Return an error that is not in the spec
@@ -2012,7 +2031,7 @@ EGLBoolean eglGetCompositorTimingSupportedANDROID(

    egl_surface_t const * const s = get_surface(surface);

    ANativeWindow* window = s->win.get();
    ANativeWindow* window = s->getNativeWindow();
    if (!window) {
        return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
    }
@@ -2045,7 +2064,7 @@ EGLBoolean eglGetFrameTimestampsANDROID(EGLDisplay dpy, EGLSurface surface,

    egl_surface_t const * const s = get_surface(surface);

    if (!s->win.get()) {
    if (!s->getNativeWindow()) {
        return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
    }

@@ -2097,19 +2116,19 @@ EGLBoolean eglGetFrameTimestampsANDROID(EGLDisplay dpy, EGLSurface surface,
        }
    }

    status_t ret = native_window_get_frame_timestamps(s->win.get(), frameId,
    int ret = native_window_get_frame_timestamps(s->getNativeWindow(), frameId,
            requestedPresentTime, acquireTime, latchTime, firstRefreshStartTime,
            lastRefreshStartTime, gpuCompositionDoneTime, displayPresentTime,
            displayRetireTime, dequeueReadyTime, releaseTime);

    switch (ret) {
        case NO_ERROR:
        case 0:
            return EGL_TRUE;
        case NAME_NOT_FOUND:
        case -ENOENT:
            return setError(EGL_BAD_ACCESS, (EGLBoolean)EGL_FALSE);
        case INVALID_OPERATION:
        case -ENOSYS:
            return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
        case BAD_VALUE:
        case -EINVAL:
            return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE);
        default:
            // This should not happen. Return an error that is not in the spec
@@ -2136,7 +2155,7 @@ EGLBoolean eglGetFrameTimestampSupportedANDROID(

    egl_surface_t const * const s = get_surface(surface);

    ANativeWindow* window = s->win.get();
    ANativeWindow* window = s->getNativeWindow();
    if (!window) {
        return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
    }
+24 −33
Original line number Diff line number Diff line
@@ -24,7 +24,9 @@
#include <sys/mman.h>
#include <sys/stat.h>

#include <utils/Thread.h>
#include <thread>

#include <log/log.h>

// Cache size limits.
static const size_t maxKeySize = 12 * 1024;
@@ -75,7 +77,7 @@ egl_cache_t* egl_cache_t::get() {
}

void egl_cache_t::initialize(egl_display_t *display) {
    Mutex::Autolock lock(mMutex);
    std::lock_guard<std::mutex> lock(mMutex);

    egl_connection_t* const cnx = &gEGLImpl;
    if (cnx->dso && cnx->major >= 0 && cnx->minor >= 0) {
@@ -113,14 +115,14 @@ void egl_cache_t::initialize(egl_display_t *display) {
}

void egl_cache_t::terminate() {
    Mutex::Autolock lock(mMutex);
    std::lock_guard<std::mutex> lock(mMutex);
    saveBlobCacheLocked();
    mBlobCache = NULL;
}

void egl_cache_t::setBlob(const void* key, EGLsizeiANDROID keySize,
        const void* value, EGLsizeiANDROID valueSize) {
    Mutex::Autolock lock(mMutex);
    std::lock_guard<std::mutex> lock(mMutex);

    if (keySize < 0 || valueSize < 0) {
        ALOGW("EGL_ANDROID_blob_cache set: negative sizes are not allowed");
@@ -132,34 +134,23 @@ void egl_cache_t::setBlob(const void* key, EGLsizeiANDROID keySize,
        bc->set(key, keySize, value, valueSize);

        if (!mSavePending) {
            class DeferredSaveThread : public Thread {
            public:
                DeferredSaveThread() : Thread(false) {}

                virtual bool threadLoop() {
            mSavePending = true;
            std::thread deferredSaveThread([this]() {
                sleep(deferredSaveDelay);
                    egl_cache_t* c = egl_cache_t::get();
                    Mutex::Autolock lock(c->mMutex);
                    if (c->mInitialized) {
                        c->saveBlobCacheLocked();
                    }
                    c->mSavePending = false;
                    return false;
                std::lock_guard<std::mutex> lock(mMutex);
                if (mInitialized) {
                    saveBlobCacheLocked();
                }
            };

            // The thread will hold a strong ref to itself until it has finished
            // running, so there's no need to keep a ref around.
            sp<Thread> deferredSaveThread(new DeferredSaveThread());
            mSavePending = true;
            deferredSaveThread->run("DeferredSaveThread");
                mSavePending = false;
            });
            deferredSaveThread.detach();
        }
    }
}

EGLsizeiANDROID egl_cache_t::getBlob(const void* key, EGLsizeiANDROID keySize,
        void* value, EGLsizeiANDROID valueSize) {
    Mutex::Autolock lock(mMutex);
    std::lock_guard<std::mutex> lock(mMutex);

    if (keySize < 0 || valueSize < 0) {
        ALOGW("EGL_ANDROID_blob_cache set: negative sizes are not allowed");
@@ -174,7 +165,7 @@ EGLsizeiANDROID egl_cache_t::getBlob(const void* key, EGLsizeiANDROID keySize,
}

void egl_cache_t::setCacheFilename(const char* filename) {
    Mutex::Autolock lock(mMutex);
    std::lock_guard<std::mutex> lock(mMutex);
    mFilename = filename;
}

@@ -206,7 +197,7 @@ void egl_cache_t::saveBlobCacheLocked() {
    if (mFilename.length() > 0 && mBlobCache != NULL) {
        size_t cacheSize = mBlobCache->getFlattenedSize();
        size_t headerSize = cacheFileHeaderSize;
        const char* fname = mFilename.string();
        const char* fname = mFilename.c_str();

        // Try to create the file with no permissions so we can write it
        // without anyone trying to read it.
@@ -241,8 +232,8 @@ void egl_cache_t::saveBlobCacheLocked() {
            return;
        }

        status_t err = mBlobCache->flatten(buf + headerSize, cacheSize);
        if (err != OK) {
        int err = mBlobCache->flatten(buf + headerSize, cacheSize);
        if (err < 0) {
            ALOGE("error writing cache contents: %s (%d)", strerror(-err),
                    -err);
            delete [] buf;
@@ -275,10 +266,10 @@ void egl_cache_t::loadBlobCacheLocked() {
    if (mFilename.length() > 0) {
        size_t headerSize = cacheFileHeaderSize;

        int fd = open(mFilename.string(), O_RDONLY, 0);
        int fd = open(mFilename.c_str(), O_RDONLY, 0);
        if (fd == -1) {
            if (errno != ENOENT) {
                ALOGE("error opening cache file %s: %s (%d)", mFilename.string(),
                ALOGE("error opening cache file %s: %s (%d)", mFilename.c_str(),
                        strerror(errno), errno);
            }
            return;
@@ -323,8 +314,8 @@ void egl_cache_t::loadBlobCacheLocked() {
            return;
        }

        status_t err = mBlobCache->unflatten(buf + headerSize, cacheSize);
        if (err != OK) {
        int err = mBlobCache->unflatten(buf + headerSize, cacheSize);
        if (err < 0) {
            ALOGE("error reading cache contents: %s (%d)", strerror(-err),
                    -err);
            munmap(buf, fileSize);
Loading