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

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

eglTerminate() now actually frees up all active egl objects

as specified by the EGL specification, terminated objects's
handles become invalid, the objects themselves are destroyed
when they're not current to some thread.

Change-Id: Id3a4a5736a5bbc3926a9ae8385d43772edb88eeb
parent 7adf4ef0
Loading
Loading
Loading
Loading
+18 −35
Original line number Diff line number Diff line
@@ -173,21 +173,21 @@ static int sEarlyInitState = pthread_once(&once_control, &early_egl_init);

// ----------------------------------------------------------------------------

egl_display_t* validate_display(EGLDisplay dpy)
{
egl_display_t* validate_display(EGLDisplay dpy) {
    egl_display_t * const dp = get_display(dpy);
    if (!dp) return setError(EGL_BAD_DISPLAY, (egl_display_t*)NULL);
    if (!dp->isReady()) return setError(EGL_NOT_INITIALIZED, (egl_display_t*)NULL);
    if (!dp)
        return setError(EGL_BAD_DISPLAY, (egl_display_t*)NULL);
    if (!dp->isReady())
        return setError(EGL_NOT_INITIALIZED, (egl_display_t*)NULL);

    return dp;
}

egl_connection_t* validate_display_config(
        EGLDisplay dpy, EGLConfig config,
        egl_display_t const*& dp)
{
egl_connection_t* validate_display_config(EGLDisplay dpy, EGLConfig config,
        egl_display_t const*& dp) {
    dp = validate_display(dpy);
    if (!dp) return (egl_connection_t*) NULL;
    if (!dp)
        return (egl_connection_t*) NULL;

    if (intptr_t(config) >= dp->numTotalConfigs) {
        return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL);
@@ -199,43 +199,26 @@ egl_connection_t* validate_display_config(
    return cnx;
}

EGLBoolean validate_display_context(EGLDisplay dpy, EGLContext ctx)
{
    egl_display_t const * const dp = validate_display(dpy);
    if (!dp) return EGL_FALSE;
    if (!dp->isAlive())
        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
    if (!get_context(ctx)->isAlive())
        return setError(EGL_BAD_CONTEXT, EGL_FALSE);
    return EGL_TRUE;
}

EGLBoolean validate_display_surface(EGLDisplay dpy, EGLSurface surface)
{
    egl_display_t const * const dp = validate_display(dpy);
    if (!dp) return EGL_FALSE;
    if (!dp->isAlive())
        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
    if (!get_surface(surface)->isAlive())
        return setError(EGL_BAD_SURFACE, EGL_FALSE);
    return EGL_TRUE;
}

// ----------------------------------------------------------------------------

EGLImageKHR egl_get_image_for_current_context(EGLImageKHR image)
{
    ImageRef _i(image);
    if (!_i.get()) return EGL_NO_IMAGE_KHR;
    if (!_i.get())
        return EGL_NO_IMAGE_KHR;

    EGLContext context = egl_tls_t::getContext();
    if (context == EGL_NO_CONTEXT || image == EGL_NO_IMAGE_KHR)
        return EGL_NO_IMAGE_KHR;

    egl_context_t const * const c = get_context(context);
    if (!c->isAlive())
    if (c == NULL) // this should never happen
        return EGL_NO_IMAGE_KHR;

    // here we don't validate the context because if it's been marked for
    // termination, this call should still succeed since it's internal to
    // EGL.

    egl_image_t const * const i = get_image(image);
    return i->images[c->impl];
}
+42 −66
Original line number Diff line number Diff line
@@ -431,10 +431,8 @@ EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface)
    if (!dp) return EGL_FALSE;

    SurfaceRef _s(surface);
    if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);

    if (!validate_display_surface(dpy, surface))
        return EGL_FALSE;    
    if (!_s.get())
        return setError(EGL_BAD_SURFACE, EGL_FALSE);

    egl_surface_t * const s = get_surface(surface);
    EGLBoolean result = s->cnx->egl.eglDestroySurface(
@@ -457,12 +455,10 @@ EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface,
    if (!dp) return EGL_FALSE;

    SurfaceRef _s(surface);
    if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
    if (!_s.get())
        return setError(EGL_BAD_SURFACE, EGL_FALSE);

    if (!validate_display_surface(dpy, surface))
        return EGL_FALSE;    
    egl_surface_t const * const s = get_surface(surface);

    EGLBoolean result(EGL_TRUE);
    if (attribute == EGL_CONFIG_ID) {
        // We need to remap EGL_CONFIG_IDs
@@ -524,13 +520,13 @@ EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
    clearError();

    egl_display_t const * const dp = validate_display(dpy);
    if (!dp) return EGL_FALSE;
    if (!dp)
        return EGL_FALSE;

    ContextRef _c(ctx);
    if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
    if (!_c.get())
        return setError(EGL_BAD_CONTEXT, EGL_FALSE);
    
    if (!validate_display_context(dpy, ctx))
        return EGL_FALSE;
    egl_context_t * const c = get_context(ctx);
    EGLBoolean result = c->cnx->egl.eglDestroyContext(
            dp->disp[c->impl].dpy, c->context);
@@ -569,9 +565,9 @@ EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
    egl_display_t const * const dp = get_display(dpy);
    if (!dp) return setError(EGL_BAD_DISPLAY, EGL_FALSE);

    /* If ctx is not EGL_NO_CONTEXT, read is not EGL_NO_SURFACE, or draw is not
       EGL_NO_SURFACE, then an EGL_NOT_INITIALIZED error is generated if dpy is
       a valid but uninitialized display. */
    // If ctx is not EGL_NO_CONTEXT, read is not EGL_NO_SURFACE, or draw is not
    // EGL_NO_SURFACE, then an EGL_NOT_INITIALIZED error is generated if dpy is
    // a valid but uninitialized display.
    if ( (ctx != EGL_NO_CONTEXT) || (read != EGL_NO_SURFACE) ||
         (draw != EGL_NO_SURFACE) ) {
        if (!dp->isReady()) return setError(EGL_NOT_INITIALIZED, EGL_FALSE);
@@ -583,7 +579,7 @@ EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
    SurfaceRef _r(read);

    // validate the context (if not EGL_NO_CONTEXT)
    if ((ctx != EGL_NO_CONTEXT) && (!validate_display_context(dpy, ctx))) {
    if ((ctx != EGL_NO_CONTEXT) && !_c.get()) {
        // EGL_NO_CONTEXT is valid
        return EGL_FALSE;
    }
@@ -682,9 +678,6 @@ EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
    ContextRef _c(ctx);
    if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);

    if (!validate_display_context(dpy, ctx))
        return EGL_FALSE;    
    
    egl_context_t * const c = get_context(ctx);

    EGLBoolean result(EGL_TRUE);
@@ -924,10 +917,9 @@ EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
    if (!dp) return EGL_FALSE;

    SurfaceRef _s(draw);
    if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
    if (!_s.get())
        return setError(EGL_BAD_SURFACE, EGL_FALSE);

    if (!validate_display_surface(dpy, draw))
        return EGL_FALSE;    
    egl_surface_t const * const s = get_surface(draw);
    return s->cnx->egl.eglSwapBuffers(dp->disp[s->impl].dpy, s->surface);
}
@@ -941,10 +933,9 @@ EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface,
    if (!dp) return EGL_FALSE;

    SurfaceRef _s(surface);
    if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
    if (!_s.get())
        return setError(EGL_BAD_SURFACE, EGL_FALSE);

    if (!validate_display_surface(dpy, surface))
        return EGL_FALSE;    
    egl_surface_t const * const s = get_surface(surface);
    return s->cnx->egl.eglCopyBuffers(
            dp->disp[s->impl].dpy, s->surface, target);
@@ -984,10 +975,9 @@ EGLBoolean eglSurfaceAttrib(
    if (!dp) return EGL_FALSE;

    SurfaceRef _s(surface);
    if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
    if (!_s.get())
        return setError(EGL_BAD_SURFACE, EGL_FALSE);

    if (!validate_display_surface(dpy, surface))
        return EGL_FALSE;    
    egl_surface_t const * const s = get_surface(surface);
    if (s->cnx->egl.eglSurfaceAttrib) {
        return s->cnx->egl.eglSurfaceAttrib(
@@ -1005,10 +995,9 @@ EGLBoolean eglBindTexImage(
    if (!dp) return EGL_FALSE;

    SurfaceRef _s(surface);
    if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
    if (!_s.get())
        return setError(EGL_BAD_SURFACE, EGL_FALSE);

    if (!validate_display_surface(dpy, surface))
        return EGL_FALSE;    
    egl_surface_t const * const s = get_surface(surface);
    if (s->cnx->egl.eglBindTexImage) {
        return s->cnx->egl.eglBindTexImage(
@@ -1026,10 +1015,9 @@ EGLBoolean eglReleaseTexImage(
    if (!dp) return EGL_FALSE;

    SurfaceRef _s(surface);
    if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
    if (!_s.get())
        return setError(EGL_BAD_SURFACE, EGL_FALSE);

    if (!validate_display_surface(dpy, surface))
        return EGL_FALSE;    
    egl_surface_t const * const s = get_surface(surface);
    if (s->cnx->egl.eglReleaseTexImage) {
        return s->cnx->egl.eglReleaseTexImage(
@@ -1186,13 +1174,10 @@ EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface,
    if (!dp) return EGL_FALSE;

    SurfaceRef _s(surface);
    if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);

    if (!validate_display_surface(dpy, surface))
        return EGL_FALSE;
    if (!_s.get())
        return setError(EGL_BAD_SURFACE, EGL_FALSE);

    egl_surface_t const * const s = get_surface(surface);

    if (s->cnx->egl.eglLockSurfaceKHR) {
        return s->cnx->egl.eglLockSurfaceKHR(
                dp->disp[s->impl].dpy, s->surface, attrib_list);
@@ -1208,13 +1193,10 @@ EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
    if (!dp) return EGL_FALSE;

    SurfaceRef _s(surface);
    if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);

    if (!validate_display_surface(dpy, surface))
        return EGL_FALSE;
    if (!_s.get())
        return setError(EGL_BAD_SURFACE, EGL_FALSE);

    egl_surface_t const * const s = get_surface(surface);

    if (s->cnx->egl.eglUnlockSurfaceKHR) {
        return s->cnx->egl.eglUnlockSurfaceKHR(
                dp->disp[s->impl].dpy, s->surface);
@@ -1232,9 +1214,8 @@ EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,

    if (ctx != EGL_NO_CONTEXT) {
        ContextRef _c(ctx);
        if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR);
        if (!validate_display_context(dpy, ctx))
            return EGL_NO_IMAGE_KHR;
        if (!_c.get())
            return setError(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR);
        egl_context_t * const c = get_context(ctx);
        // since we have an EGLContext, we know which implementation to use
        EGLImageKHR image = c->cnx->egl.eglCreateImageKHR(
@@ -1341,9 +1322,9 @@ EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_l

    EGLContext ctx = eglGetCurrentContext();
    ContextRef _c(ctx);
    if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_NO_SYNC_KHR);
    if (!validate_display_context(dpy, ctx))
        return EGL_NO_SYNC_KHR;
    if (!_c.get())
        return setError(EGL_BAD_CONTEXT, EGL_NO_SYNC_KHR);

    egl_context_t * const c = get_context(ctx);
    EGLSyncKHR result = EGL_NO_SYNC_KHR;
    if (c->cnx->egl.eglCreateSyncKHR) {
@@ -1369,9 +1350,8 @@ EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync)

    EGLContext ctx = syncObject->context;
    ContextRef _c(ctx);
    if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
    if (!validate_display_context(dpy, ctx))
        return EGL_FALSE;
    if (!_c.get())
        return setError(EGL_BAD_CONTEXT, EGL_FALSE);

    EGLBoolean result = EGL_FALSE;
    egl_context_t * const c = get_context(ctx);
@@ -1397,12 +1377,10 @@ EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTi

    EGLContext ctx = syncObject->context;
    ContextRef _c(ctx);
    if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
    if (!validate_display_context(dpy, ctx))
        return EGL_FALSE;
    if (!_c.get())
        return setError(EGL_BAD_CONTEXT, EGL_FALSE);

    egl_context_t * const c = get_context(ctx);

    if (c->cnx->egl.eglClientWaitSyncKHR) {
        return c->cnx->egl.eglClientWaitSyncKHR(
                dp->disp[c->impl].dpy, syncObject->sync, flags, timeout);
@@ -1419,17 +1397,16 @@ EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute
    if (!dp) return EGL_FALSE;

    SyncRef _s(sync);
    if (!_s.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
    egl_sync_t* syncObject = get_sync(sync);
    if (!_s.get())
        return setError(EGL_BAD_PARAMETER, EGL_FALSE);

    egl_sync_t* syncObject = get_sync(sync);
    EGLContext ctx = syncObject->context;
    ContextRef _c(ctx);
    if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
    if (!validate_display_context(dpy, ctx))
        return EGL_FALSE;
    if (!_c.get())
        return setError(EGL_BAD_CONTEXT, EGL_FALSE);

    egl_context_t * const c = get_context(ctx);

    if (c->cnx->egl.eglGetSyncAttribKHR) {
        return c->cnx->egl.eglGetSyncAttribKHR(
                dp->disp[c->impl].dpy, syncObject->sync, attribute, value);
@@ -1451,10 +1428,9 @@ EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw,
    if (!dp) return EGL_FALSE;

    SurfaceRef _s(draw);
    if (!_s.get()) return setError(EGL_BAD_SURFACE, EGL_FALSE);
    if (!_s.get())
        return setError(EGL_BAD_SURFACE, EGL_FALSE);

    if (!validate_display_surface(dpy, draw))
        return EGL_FALSE;    
    egl_surface_t const * const s = get_surface(draw);
    if (s->cnx->egl.eglSetSwapRectangleANDROID) {
        return s->cnx->egl.eglSetSwapRectangleANDROID(
+17 −10
Original line number Diff line number Diff line
@@ -55,19 +55,15 @@ void egl_display_t::addObject(egl_object_t* object) {
    objects.add(object);
}

bool egl_display_t::getObject(egl_object_t* object) {
void egl_display_t::removeObject(egl_object_t* object) {
    Mutex::Autolock _l(lock);
    if (objects.indexOf(object) >= 0) {
        object->incRef();
        return true;
    }
    return false;
    objects.remove(object);
}

bool egl_display_t::removeObject(egl_object_t* object) {
bool egl_display_t::getObject(egl_object_t* object) {
    Mutex::Autolock _l(lock);
    if (object->decRef() == 1) {
        objects.remove(object);
    if (objects.indexOf(object) >= 0) {
        object->incRef();
        return true;
    }
    return false;
@@ -255,7 +251,18 @@ EGLBoolean egl_display_t::terminate() {
        }
    }

    // TODO: all egl_object_t should be marked for termination
    // Mark all objects remaining in the list as terminated, unless
    // there are no reference to them, it which case, we're free to
    // delete them.
    size_t count = objects.size();
    LOGW_IF(count, "eglTerminate() called w/ %d objects remaining", count);
    for (size_t i=0 ; i<count ; i++) {
        egl_object_t* o = objects.itemAt(i);
        o->destroy();
    }

    // this marks all object handles are "terminated"
    objects.clear();

    refs--;
    numTotalConfigs = 0;
+3 −3
Original line number Diff line number Diff line
@@ -77,12 +77,12 @@ public:

    // add object to this display's list
    void addObject(egl_object_t* object);
    // remove object from this display's list if it has no reference.
    // returns true if object was removed.
    bool removeObject(egl_object_t* object);
    // remove object from this display's list
    void removeObject(egl_object_t* object);
    // add reference to this object. returns true if this is a valid object.
    bool getObject(egl_object_t* object);


    static egl_display_t* get(EGLDisplay dpy);
    static EGLDisplay getFromNativeDisplay(EGLNativeDisplayType disp);

+22 −5
Original line number Diff line number Diff line
@@ -32,16 +32,33 @@ namespace android {
// ----------------------------------------------------------------------------

egl_object_t::egl_object_t(egl_display_t* disp) :
    display(disp), terminated(0), count(1) {
    display(disp), count(1) {
    // NOTE: this does an implicit incRef
    display->addObject(this);
}

bool egl_object_t::get() {
    return display->getObject(this);
egl_object_t::~egl_object_t() {
}

void egl_object_t::terminate() {
    // this marks the object as "terminated"
    display->removeObject(this);
    if (decRef() == 1) {
        // shouldn't happen because this is called from LocalRef
        LOGE("egl_object_t::terminate() removed the last reference!");
    }
}

bool egl_object_t::put() {
    return display->removeObject(this);
void egl_object_t::destroy() {
    if (decRef() == 1) {
        delete this;
    }
}

bool egl_object_t::get() {
    // used by LocalRef, this does an incRef() atomically with
    // checking that the object is valid.
    return display->getObject(this);
}

// ----------------------------------------------------------------------------
Loading