Blob Blame History Raw
/*
 * Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

#include "wayland-eglhandle.h"
#include "wayland-egldisplay.h"
#include "wayland-eglsurface.h"
#include "wayland-thread.h"
#include <stdlib.h>
#include <errno.h>
#include <assert.h>

WlEglPlatformData*
wlEglCreatePlatformData(int apiMajor, int apiMinor, const EGLExtDriver *driver)
{
    const char        *exts = NULL;
    WlEglPlatformData *res  = NULL;

    assert((driver != NULL) && (driver->getProcAddress != NULL));

    /* Allocate platform data and fetch EGL functions */
    res = calloc(1, sizeof(WlEglPlatformData));
    if (res == NULL) {
        return NULL;
    }

    wl_list_init(&res->deviceDpyList);

    /* Cache the EGL driver version */
#if EGL_EXTERNAL_PLATFORM_HAS(DRIVER_VERSION)
    if (EGL_EXTERNAL_PLATFORM_SUPPORTS(apiMajor, apiMinor, DRIVER_VERSION)) {
        res->egl.major = driver->major;
        res->egl.minor = driver->minor;
    }
#endif

    /* Fetch all required driver functions */
#define GET_PROC(_FIELD_, _NAME_)                           \
    do {                                                    \
        res->egl._FIELD_ = driver->getProcAddress(#_NAME_); \
        if (res->egl._FIELD_ == NULL) {                     \
            goto fail;                                      \
        }                                                   \
    } while (0)

    /* Core and basic stream functionality */
    GET_PROC(queryString,                 eglQueryString);
    GET_PROC(queryDevices,                eglQueryDevicesEXT);

    /* TODO: use eglGetPlatformDisplay instead of eglGetPlatformDisplayEXT
             if EGL 1.5 is available                                      */
    GET_PROC(getPlatformDisplay,          eglGetPlatformDisplayEXT);
    GET_PROC(initialize,                  eglInitialize);
    GET_PROC(terminate,                   eglTerminate);
    GET_PROC(chooseConfig,                eglChooseConfig);
    GET_PROC(getConfigAttrib,             eglGetConfigAttrib);

    GET_PROC(getCurrentContext,           eglGetCurrentContext);
    GET_PROC(getCurrentSurface,           eglGetCurrentSurface);
    GET_PROC(makeCurrent,                 eglMakeCurrent);

    GET_PROC(createStream,                eglCreateStreamKHR);
    GET_PROC(createStreamFromFD,          eglCreateStreamFromFileDescriptorKHR);
    GET_PROC(createStreamAttrib,          eglCreateStreamAttribNV);
    GET_PROC(getStreamFileDescriptor,     eglGetStreamFileDescriptorKHR);
    GET_PROC(createStreamProducerSurface, eglCreateStreamProducerSurfaceKHR);
    GET_PROC(createPbufferSurface,        eglCreatePbufferSurface);
    GET_PROC(destroyStream,               eglDestroyStreamKHR);
    GET_PROC(destroySurface,              eglDestroySurface);

    GET_PROC(swapBuffers,                 eglSwapBuffers);
    GET_PROC(swapBuffersWithDamage,       eglSwapBuffersWithDamageKHR);
    GET_PROC(swapInterval,                eglSwapInterval);

    GET_PROC(getError,                    eglGetError);
    GET_PROC(releaseThread,               eglReleaseThread);

#undef GET_PROC

    /* Fetch all optional driver functions */
#define GET_PROC(_FIELD_, _NAME_) \
    res->egl._FIELD_ = driver->getProcAddress(#_NAME_)

    /* Used by damage thread */
    GET_PROC(queryStream,                 eglQueryStreamKHR);
    GET_PROC(queryStreamu64,              eglQueryStreamu64KHR);
    GET_PROC(createStreamSync,            eglCreateStreamSyncNV);
    GET_PROC(clientWaitSync,              eglClientWaitSyncKHR);
    GET_PROC(signalSync,                  eglSignalSyncKHR);
    GET_PROC(destroySync,                 eglDestroySyncKHR);

    /* Stream flush */
    GET_PROC(streamFlush,                 eglStreamFlushNV);

    GET_PROC(queryDisplayAttrib,          eglQueryDisplayAttribKHR);

#undef GET_PROC

    /* Check for required EGL client extensions */
    exts = res->egl.queryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
    if (exts == NULL) {
        goto fail;
    }
    if (!wlEglFindExtension("EGL_EXT_platform_base",   exts) ||
        !wlEglFindExtension("EGL_EXT_platform_device", exts)) {
        goto fail;
    }
    res->supportsDisplayReference = wlEglFindExtension("EGL_KHR_display_reference", exts);

    /* Cache driver imports */
    res->callbacks.setError           = driver->setError;
    res->callbacks.streamSwapInterval = driver->streamSwapInterval;

    return res;

fail:
    free(res);
    return NULL;
}

void wlEglDestroyPlatformData(WlEglPlatformData *data)
{
    free(data);
}

void* wlEglGetInternalHandleExport(EGLDisplay dpy, EGLenum type, void *handle)
{
    wlExternalApiLock();

    if ((type == EGL_OBJECT_DISPLAY_KHR) &&
        wlEglIsWlEglDisplay((WlEglDisplay *)handle)) {
        handle = (void *)(((WlEglDisplay *)handle)->devDpy->eglDisplay);
    } else if ((type == EGL_OBJECT_SURFACE_KHR) &&
               wlEglIsWlEglSurface((WlEglSurface *)handle)) {
        WlEglSurface *surface = (WlEglSurface *)handle;
        if (dpy == surface->wlEglDpy) {
            handle = (void *)(surface->ctx.eglSurface);
        } else {
            handle = NULL;
        }
    }

    wlExternalApiUnlock();

    return handle;
}