diff options
Diffstat (limited to 'src/egl/main/egldisplay.c')
-rw-r--r-- | src/egl/main/egldisplay.c | 337 |
1 files changed, 306 insertions, 31 deletions
diff --git a/src/egl/main/egldisplay.c b/src/egl/main/egldisplay.c index 47a2323eaf..feae1d6040 100644 --- a/src/egl/main/egldisplay.c +++ b/src/egl/main/egldisplay.c @@ -1,4 +1,3 @@ - /** * Functions related to EGLDisplay. */ @@ -7,11 +6,73 @@ #include <stdlib.h> #include <string.h> #include "eglcontext.h" +#include "eglsurface.h" #include "egldisplay.h" #include "egldriver.h" #include "eglglobals.h" #include "eglhash.h" #include "eglstring.h" +#include "eglmutex.h" +#include "egllog.h" + + +static _EGL_DECLARE_MUTEX(_eglDisplayInitMutex); +static _EGLHashtable *_eglDisplayHash; +/* TODO surface hash table should be per-display */ +static _EGLHashtable *_eglSurfaceHash; + + +/** + * Finish display management. + */ +static void +_eglFiniDisplay(void) +{ + _eglLockMutex(&_eglDisplayInitMutex); + if (_eglDisplayHash) { + EGLuint key = _eglHashFirstEntry(_eglDisplayHash); + + while (key) { + _EGLDisplay *dpy = (_EGLDisplay *) + _eglHashLookup(_eglDisplayHash, key); + assert(dpy); + + if (dpy->ContextList || dpy->SurfaceList) + _eglLog(_EGL_DEBUG, "Display %u is destroyed with resources", key); + + _eglCleanupDisplay(dpy); + free(dpy); + + key = _eglHashNextEntry(_eglDisplayHash, key); + } + + _eglDeleteHashTable(_eglDisplayHash); + _eglDisplayHash = NULL; + _eglDeleteHashTable(_eglSurfaceHash); + _eglSurfaceHash = NULL; + } + _eglUnlockMutex(&_eglDisplayInitMutex); +} + + +/* This can be avoided if hash table can be statically initialized */ +static INLINE void +_eglInitDisplay(void) +{ + if (!_eglDisplayHash) { + _eglLockMutex(&_eglDisplayInitMutex); + + /* check again after acquiring lock */ + if (!_eglDisplayHash) { + _eglDisplayHash = _eglNewHashTable(); + _eglSurfaceHash = _eglNewHashTable(); + + _eglAddAtExitCall(_eglFiniDisplay); + } + + _eglUnlockMutex(&_eglDisplayInitMutex); + } +} /** @@ -25,16 +86,14 @@ _eglNewDisplay(NativeDisplayType nativeDisplay) { _EGLDisplay *dpy = (_EGLDisplay *) calloc(1, sizeof(_EGLDisplay)); if (dpy) { - EGLuint key = _eglHashGenKey(_eglGlobal.Displays); - - dpy->Handle = (EGLDisplay) key; - _eglHashInsert(_eglGlobal.Displays, key, dpy); - dpy->NativeDisplay = nativeDisplay; #if defined(_EGL_PLATFORM_X) dpy->Xdpy = (Display *) nativeDisplay; #endif + _eglInitDisplay(); + dpy->SurfaceHash = _eglSurfaceHash; + dpy->DriverName = _eglChooseDriver(dpy); if (!dpy->DriverName) { free(dpy); @@ -46,8 +105,44 @@ _eglNewDisplay(NativeDisplayType nativeDisplay) /** - * Return the public handle for an internal _EGLDisplay. - * This is the inverse of _eglLookupDisplay(). + * Link a display to itself and return the handle of the link. + * The handle can be passed to client directly. + */ +EGLDisplay +_eglLinkDisplay(_EGLDisplay *dpy) +{ + EGLuint key; + + _eglInitDisplay(); + + key = _eglHashGenKey(_eglDisplayHash); + assert(key); + /* "link" the display to the hash table */ + _eglHashInsert(_eglDisplayHash, key, dpy); + dpy->Handle = (EGLDisplay) _eglUIntToPointer(key); + + return dpy->Handle; +} + + +/** + * Unlink a linked display from itself. + * Accessing an unlinked display should generate EGL_BAD_DISPLAY error. + */ +void +_eglUnlinkDisplay(_EGLDisplay *dpy) +{ + EGLuint key = _eglPointerToUInt((void *) dpy->Handle); + + _eglInitDisplay(); + + _eglHashRemove(_eglDisplayHash, key); + dpy->Handle = EGL_NO_DISPLAY; +} + + +/** + * Return the handle of a linked display, or EGL_NO_DISPLAY. */ EGLDisplay _eglGetDisplayHandle(_EGLDisplay *display) @@ -58,42 +153,78 @@ _eglGetDisplayHandle(_EGLDisplay *display) return EGL_NO_DISPLAY; } - + /** - * Return the _EGLDisplay object that corresponds to the given public/ - * opaque display handle. - * This is the inverse of _eglGetDisplayHandle(). + * Lookup a handle to find the linked display. + * Return NULL if the handle has no corresponding linked display. */ _EGLDisplay * _eglLookupDisplay(EGLDisplay dpy) { - EGLuint key = (EGLuint) dpy; - if (!_eglGlobal.Displays) - return NULL; - return (_EGLDisplay *) _eglHashLookup(_eglGlobal.Displays, key); + EGLuint key = _eglPointerToUInt((void *) dpy); + + _eglInitDisplay(); + + return (_EGLDisplay *) _eglHashLookup(_eglDisplayHash, key); } -void -_eglSaveDisplay(_EGLDisplay *dpy) +/** + * Find the display corresponding to the specified native display id in all + * linked displays. + */ +_EGLDisplay * +_eglFindDisplay(NativeDisplayType nativeDisplay) { - EGLuint key = _eglHashGenKey(_eglGlobal.Displays); - assert(dpy); - assert(!dpy->Handle); - dpy->Handle = (EGLDisplay) key; - assert(dpy->Handle); - _eglHashInsert(_eglGlobal.Displays, key, dpy); + EGLuint key; + + _eglInitDisplay(); + + /* Walk the hash table. Should switch to list if it is a problem. */ + key = _eglHashFirstEntry(_eglDisplayHash); + while (key) { + _EGLDisplay *dpy = (_EGLDisplay *) + _eglHashLookup(_eglDisplayHash, key); + assert(dpy); + + if (dpy->NativeDisplay == nativeDisplay) + return dpy; + key = _eglHashNextEntry(_eglDisplayHash, key); + } + + return NULL; } -_EGLDisplay * -_eglGetCurrentDisplay(void) +/** + * Destroy the contexts and surfaces that are linked to the display. + */ +void +_eglReleaseDisplayResources(_EGLDriver *drv, EGLDisplay dpy) { - _EGLContext *ctx = _eglGetCurrentContext(); - if (ctx) - return ctx->Display; - else - return NULL; + _EGLDisplay *display; + _EGLContext *contexts; + _EGLSurface *surfaces; + + display = _eglLookupDisplay(dpy); + if (!display) + return; + contexts = display->ContextList; + surfaces = display->SurfaceList; + + while (contexts) { + EGLContext handle = _eglGetContextHandle(contexts); + contexts = contexts->Next; + drv->API.DestroyContext(drv, dpy, handle); + } + assert(!display->ContextList); + + while (surfaces) { + EGLSurface handle = _eglGetSurfaceHandle(surfaces); + surfaces = surfaces->Next; + drv->API.DestroySurface(drv, dpy, handle); + } + assert(!display->SurfaceList); } @@ -119,3 +250,147 @@ _eglCleanupDisplay(_EGLDisplay *disp) /* driver deletes the _EGLDisplay object */ } + + +/** + * Link a context to a display and return the handle of the link. + * The handle can be passed to client directly. + */ +EGLContext +_eglLinkContext(_EGLContext *ctx, _EGLDisplay *dpy) +{ + ctx->Display = dpy; + ctx->Next = dpy->ContextList; + dpy->ContextList = ctx; + return (EGLContext) ctx; +} + + +/** + * Unlink a linked context from its display. + * Accessing an unlinked context should generate EGL_BAD_CONTEXT error. + */ +void +_eglUnlinkContext(_EGLContext *ctx) +{ + _EGLContext *prev; + + prev = ctx->Display->ContextList; + if (prev != ctx) { + while (prev) { + if (prev->Next == ctx) + break; + prev = prev->Next; + } + assert(prev); + prev->Next = ctx->Next; + } + else { + ctx->Display->ContextList = ctx->Next; + } + + ctx->Next = NULL; + ctx->Display = NULL; +} + + +/** + * Return the handle of a linked context, or EGL_NO_CONTEXT. + */ +EGLContext +_eglGetContextHandle(_EGLContext *ctx) +{ + return (EGLContext) ((ctx && ctx->Display) ? ctx : EGL_NO_CONTEXT); +} + + +/** + * Lookup a handle to find the linked context. + * Return NULL if the handle has no corresponding linked context. + */ +_EGLContext * +_eglLookupContext(EGLContext ctx) +{ + _EGLContext *context = (_EGLContext *) ctx; + return (context && context->Display) ? context : NULL; +} + + +/** + * Link a surface to a display and return the handle of the link. + * The handle can be passed to client directly. + */ +EGLSurface +_eglLinkSurface(_EGLSurface *surf, _EGLDisplay *dpy) +{ + EGLuint key; + + surf->Display = dpy; + surf->Next = dpy->SurfaceList; + dpy->SurfaceList = surf; + + key = _eglHashGenKey(dpy->SurfaceHash); + assert(key); + _eglHashInsert(dpy->SurfaceHash, key, surf); + + surf->Handle = (EGLSurface) _eglUIntToPointer(key); + return surf->Handle; +} + + +/** + * Unlink a linked surface from its display. + * Accessing an unlinked surface should generate EGL_BAD_SURFACE error. + */ +void +_eglUnlinkSurface(_EGLSurface *surf) +{ + _EGLSurface *prev; + EGLuint key = _eglPointerToUInt((void *) surf->Handle); + + _eglHashRemove(surf->Display->SurfaceHash, key); + surf->Handle = EGL_NO_SURFACE; + + prev = surf->Display->SurfaceList; + if (prev != surf) { + while (prev) { + if (prev->Next == surf) + break; + prev = prev->Next; + } + assert(prev); + prev->Next = surf->Next; + } + else { + prev = NULL; + surf->Display->SurfaceList = surf->Next; + } + + surf->Next = NULL; + surf->Display = NULL; +} + + +/** + * Return the handle of a linked surface, or EGL_NO_SURFACE. + */ +EGLSurface +_eglGetSurfaceHandle(_EGLSurface *surface) +{ + if (surface) + return surface->Handle; + else + return EGL_NO_SURFACE; +} + + +/** + * Lookup a handle to find the linked surface. + * Return NULL if the handle has no corresponding linked surface. + */ +_EGLSurface * +_eglLookupSurface(EGLSurface surf) +{ + EGLuint key = _eglPointerToUInt((void *) surf); + return (_EGLSurface *) _eglHashLookup(_eglSurfaceHash, key); +} |