summaryrefslogtreecommitdiffstats
path: root/src/VBox/Additions/common/crOpenGL/egl.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Additions/common/crOpenGL/egl.c')
-rw-r--r--src/VBox/Additions/common/crOpenGL/egl.c967
1 files changed, 967 insertions, 0 deletions
diff --git a/src/VBox/Additions/common/crOpenGL/egl.c b/src/VBox/Additions/common/crOpenGL/egl.c
new file mode 100644
index 00000000..3d8a636d
--- /dev/null
+++ b/src/VBox/Additions/common/crOpenGL/egl.c
@@ -0,0 +1,967 @@
+/* $Id: egl.c $ */
+
+/** @file
+ * VBox OpenGL EGL implentation.
+ */
+
+/*
+ * Copyright (C) 2009-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <iprt/cdefs.h>
+#include <iprt/types.h>
+
+#include <EGL/egl.h>
+#include <GL/glx.h>
+#include <X11/Xlib.h>
+
+#include <dlfcn.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define EGL_ASSERT(expr) \
+ if (!(expr)) { printf("Assertion failed: %s\n", #expr); exit(1); }
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+
+struct VBEGLTLS
+{
+ /** The last EGL error. */
+ EGLint cErr;
+ /** The EGL API currently bound to this thread. */
+ EGLenum enmAPI;
+ /** The current context. */
+ EGLContext hCurrent;
+ /** The display bound to the current context. */
+ EGLDisplay hCurrentDisplay;
+ /** The draw surface bound to the current context. */
+ EGLSurface hCurrentDraw;
+ /** The read surface bound to the current context. */
+ EGLSurface hCurrentRead;
+};
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+/** @note IDs returned for surfaces should always be lower than these constants.
+ */
+/** This is OR-ed with a surface ID to mark it as a window, as GLX needs to
+ * know. */
+#define VBEGL_WINDOW_SURFACE 0x20000000
+/** This is OR-ed with a surface ID to mark it as a pbuffer, as GLX needs to
+ * know. */
+#define VBEGL_PBUFFER_SURFACE 0x40000000
+/** This is OR-ed with a surface ID to mark it as a pixmap, as GLX needs to
+ * know. */
+#define VBEGL_PIXMAP_SURFACE 0x80000000
+#define VBEGL_ANY_SURFACE (VBEGL_WINDOW_SURFACE | VBEGL_PBUFFER_SURFACE | VBEGL_PIXMAP_SURFACE)
+
+
+/*********************************************************************************************************************************
+* Global variables *
+*********************************************************************************************************************************/
+
+static pthread_key_t g_tls;
+static pthread_once_t g_tlsOnce = PTHREAD_ONCE_INIT;
+static Display *g_pDefaultDisplay = NULL;
+static pthread_once_t g_defaultDisplayOnce = PTHREAD_ONCE_INIT;
+
+static void tlsInitOnce(void)
+{
+ pthread_key_create(&g_tls, NULL);
+}
+
+static struct VBEGLTLS *getTls(void)
+{
+ struct VBEGLTLS *pTls;
+
+ pthread_once(&g_tlsOnce, tlsInitOnce);
+ pTls = (struct VBEGLTLS *)pthread_getspecific(g_tls);
+ if (RT_LIKELY(pTls))
+ return pTls;
+ pTls = (struct VBEGLTLS *)malloc(sizeof(*pTls));
+ if (!pTls)
+ return NULL;
+ pTls->cErr = EGL_SUCCESS;
+ pTls->enmAPI = EGL_NONE;
+ pTls->hCurrent = EGL_NO_CONTEXT;
+ pTls->hCurrentDisplay = EGL_NO_DISPLAY;
+ pTls->hCurrentDraw = EGL_NO_SURFACE;
+ pTls->hCurrentRead = EGL_NO_SURFACE;
+ if (pthread_setspecific(g_tls, pTls) == 0)
+ return pTls;
+ free(pTls);
+ return NULL;
+}
+
+static void defaultDisplayInitOnce(void)
+{
+ g_pDefaultDisplay = XOpenDisplay(NULL);
+}
+
+static EGLBoolean clearEGLError(void)
+{
+ struct VBEGLTLS *pTls = getTls();
+
+ if (!VALID_PTR(pTls))
+ return EGL_FALSE;
+ pTls->cErr = EGL_SUCCESS;
+ return EGL_TRUE;
+}
+
+static EGLBoolean setEGLError(EGLint cErr)
+{
+ struct VBEGLTLS *pTls = getTls();
+
+ if (pTls)
+ pTls->cErr = cErr;
+ return EGL_FALSE;
+}
+
+static EGLBoolean testValidDisplay(EGLNativeDisplayType hDisplay)
+{
+ void *pSymbol = dlsym(NULL, "gbm_create_device");
+
+ if (hDisplay == EGL_DEFAULT_DISPLAY)
+ return EGL_TRUE;
+ if ((void *)hDisplay == NULL)
+ return EGL_FALSE;
+ /* This is the test that Mesa uses to see if this is a GBM "display". Not
+ * very pretty, but since no one can afford to break Mesa it should be
+ * safe. We need this to detect when the X server tries to load us. */
+ if (pSymbol != NULL && *(void **)hDisplay == pSymbol)
+ return EGL_FALSE;
+ return EGL_TRUE;
+}
+
+DECLEXPORT(EGLDisplay) eglGetDisplay(EGLNativeDisplayType hDisplay)
+{
+ Display *pDisplay;
+
+ if (!testValidDisplay(hDisplay))
+ return EGL_NO_DISPLAY;
+ if (!clearEGLError()) /* Set up our tls. */
+ return EGL_NO_DISPLAY;
+ if (hDisplay != EGL_DEFAULT_DISPLAY)
+ pDisplay = hDisplay;
+ else
+ {
+ pthread_once(&g_defaultDisplayOnce, defaultDisplayInitOnce);
+ pDisplay = g_pDefaultDisplay;
+ }
+ if (pDisplay && !strcmp(glXGetClientString(pDisplay, GLX_VENDOR), "Chromium"))
+ return (EGLDisplay) pDisplay;
+ return EGL_NO_DISPLAY;
+}
+
+DECLEXPORT(EGLint) eglGetError(void)
+{
+ struct VBEGLTLS *pTls = getTls();
+
+ if (pTls)
+ return pTls->cErr;
+ return EGL_NOT_INITIALIZED;
+}
+
+DECLEXPORT(EGLBoolean) eglInitialize (EGLDisplay hDisplay, EGLint *pcMajor, EGLint *pcMinor)
+{
+ if (hDisplay == EGL_NO_DISPLAY)
+ return EGL_FALSE;
+ if (!VALID_PTR(hDisplay))
+ return setEGLError(EGL_BAD_DISPLAY);
+ if (pcMajor)
+ *pcMajor = 1;
+ if (pcMinor)
+ *pcMinor = 4;
+ return clearEGLError();
+}
+
+/** @todo This function should terminate all allocated resources. */
+DECLEXPORT(EGLBoolean) eglTerminate(EGLDisplay hDisplay)
+{
+ if (!VALID_PTR(hDisplay))
+ return EGL_FALSE;
+ return EGL_TRUE;
+}
+
+DECLEXPORT(const char *) eglQueryString(EGLDisplay hDisplay, EGLint name)
+{
+ RT_NOREF(hDisplay);
+ switch (name)
+ {
+ case EGL_CLIENT_APIS:
+ return "OpenGL";
+ case EGL_VENDOR:
+ return "Chromium";
+ case EGL_VERSION:
+ return "1.4 Chromium";
+ case EGL_EXTENSIONS:
+ return "";
+ default:
+ return NULL;
+ }
+}
+
+DECLEXPORT(EGLBoolean) eglGetConfigs (EGLDisplay hDisplay, EGLConfig *paConfigs, EGLint caConfigs, EGLint *pcaConfigs)
+{
+ Display *pDisplay = (Display *)hDisplay;
+ GLXFBConfig *paFBConfigs;
+ int caFBConfigs, i;
+
+ if (!VALID_PTR(pDisplay))
+ return setEGLError(EGL_NOT_INITIALIZED);
+ if (!VALID_PTR(pcaConfigs))
+ return setEGLError(EGL_BAD_PARAMETER);
+ if (caConfigs > 0 && !VALID_PTR(paConfigs))
+ return setEGLError(EGL_BAD_PARAMETER);
+ paFBConfigs = glXGetFBConfigs(pDisplay, DefaultScreen(pDisplay), &caFBConfigs);
+ if (!VALID_PTR(paFBConfigs))
+ return setEGLError(EGL_BAD_PARAMETER);
+ if (caFBConfigs > caConfigs)
+ caFBConfigs = caConfigs;
+ *pcaConfigs = caFBConfigs;
+ for (i = 0; i < caFBConfigs; ++i)
+ paConfigs[i] = (EGLConfig)paFBConfigs[i];
+ XFree(paFBConfigs);
+ return clearEGLError();
+}
+
+static int convertEGLAttribToGLX(EGLint a_EGLAttrib)
+{
+ switch (a_EGLAttrib)
+ {
+ case EGL_BUFFER_SIZE:
+ return GLX_BUFFER_SIZE;
+ case EGL_RED_SIZE:
+ return GLX_RED_SIZE;
+ case EGL_GREEN_SIZE:
+ return GLX_GREEN_SIZE;
+ case EGL_BLUE_SIZE:
+ return GLX_BLUE_SIZE;
+ case EGL_LUMINANCE_SIZE:
+ return GLX_RED_SIZE;
+ case EGL_ALPHA_SIZE:
+ return GLX_ALPHA_SIZE;
+ /* case EGL_ALPHA_MASK_SIZE: */
+ /* case EGL_BIND_TO_TEXTURE_RGB: */
+ /* case EGL_BIND_TO_TEXTURE_RGBA: */
+ /* case EGL_COLOR_BUFFER_TYPE: */
+ /* case EGL_CONFIG_CAVEAT: */
+ case EGL_CONFIG_ID:
+ return GLX_FBCONFIG_ID;
+ /* case EGL_CONFORMANT: */
+ case EGL_DEPTH_SIZE:
+ return GLX_DEPTH_SIZE;
+ case EGL_LEVEL:
+ return GLX_LEVEL;
+ case EGL_MAX_PBUFFER_WIDTH:
+ return GLX_MAX_PBUFFER_WIDTH;
+ case EGL_MAX_PBUFFER_HEIGHT:
+ return GLX_MAX_PBUFFER_HEIGHT;
+ case EGL_MAX_PBUFFER_PIXELS:
+ return GLX_MAX_PBUFFER_PIXELS;
+ /* case EGL_MATCH_NATIVE_PIXMAP: */
+ /* case EGL_MAX_SWAP_INTERVAL: */
+ /* case EGL_MIN_SWAP_INTERVAL: */
+ case EGL_NATIVE_RENDERABLE:
+ return GLX_X_RENDERABLE;
+ case EGL_NATIVE_VISUAL_ID:
+ return GLX_VISUAL_ID;
+ /* case EGL_NATIVE_VISUAL_TYPE: */
+ /* case EGL_RENDERABLE_TYPE: */
+ case EGL_SAMPLE_BUFFERS:
+ return GLX_SAMPLE_BUFFERS;
+ case EGL_SAMPLES:
+ return GLX_SAMPLES;
+ case EGL_STENCIL_SIZE:
+ return GLX_STENCIL_SIZE;
+ /* case EGL_SURFACE_TYPE: */
+ /* case EGL_TRANSPARENT_TYPE: */
+ case EGL_TRANSPARENT_RED_VALUE:
+ return GLX_TRANSPARENT_RED_VALUE;
+ case EGL_TRANSPARENT_GREEN_VALUE:
+ return GLX_TRANSPARENT_GREEN_VALUE;
+ case EGL_TRANSPARENT_BLUE_VALUE:
+ return GLX_TRANSPARENT_BLUE_VALUE;
+ default:
+ return None;
+ }
+}
+
+DECLEXPORT(EGLBoolean) eglChooseConfig (EGLDisplay hDisplay, const EGLint *paAttribs, EGLConfig *paConfigs, EGLint caConfigs,
+ EGLint *pcConfigs)
+{
+ Display *pDisplay = (Display *)hDisplay;
+ int aAttribList[256]; /* The list cannot be this long. */
+ unsigned cAttribs = 0, i;
+ const EGLint *pAttrib, *pAttrib2;
+ EGLint cRenderableType = EGL_OPENGL_ES_BIT;
+ unsigned cConfigCaveat = GLX_DONT_CARE, cConformant = GLX_DONT_CARE;
+ GLXFBConfig *paFBConfigs;
+ int caFBConfigs;
+
+ if (!VALID_PTR(hDisplay))
+ return setEGLError(EGL_NOT_INITIALIZED);
+ if (!VALID_PTR(pcConfigs))
+ return setEGLError(EGL_BAD_PARAMETER);
+ if (caConfigs > 0 && !VALID_PTR(paConfigs))
+ return setEGLError(EGL_BAD_PARAMETER);
+ for (pAttrib = paAttribs; pAttrib != NULL && *pAttrib != EGL_NONE; pAttrib += 2)
+ {
+ bool fSkip = false;
+ int cGLXAttrib;
+
+ /* Check for illegal values. */
+ if ((*pAttrib == EGL_LEVEL || *pAttrib == EGL_MATCH_NATIVE_PIXMAP) && pAttrib[1] == EGL_DONT_CARE)
+ return setEGLError(EGL_BAD_ATTRIBUTE);
+ /* Check for values we can't handle. */
+ if ( (*pAttrib == EGL_ALPHA_MASK_SIZE)
+ && pAttrib[1] != EGL_DONT_CARE && pAttrib[1] != 0)
+ return setEGLError(EGL_BAD_ACCESS);
+ /** @todo try creating a pixmap from a native one with the configurations returned. */
+ if (*pAttrib == EGL_MATCH_NATIVE_PIXMAP)
+ return setEGLError(EGL_BAD_ACCESS);
+ if ( ( *pAttrib == EGL_MIN_SWAP_INTERVAL || *pAttrib == EGL_MAX_SWAP_INTERVAL
+ || *pAttrib == EGL_BIND_TO_TEXTURE_RGB || *pAttrib == EGL_BIND_TO_TEXTURE_RGBA)
+ && pAttrib[1] != EGL_DONT_CARE)
+ return setEGLError(EGL_BAD_ACCESS);
+ /* Ignore attributes which are repeated later. */
+ for (pAttrib2 = pAttrib + 2; *pAttrib2 != EGL_NONE; pAttrib2 += 2)
+ if (*pAttrib2 == *pAttrib)
+ {
+ fSkip = true;
+ break;
+ }
+
+ if (fSkip)
+ continue;
+ cGLXAttrib = convertEGLAttribToGLX(*pAttrib);
+ if (cGLXAttrib != None)
+ {
+ aAttribList[cAttribs] = cGLXAttrib;
+ if (pAttrib[1] == EGL_DONT_CARE)
+ aAttribList[cAttribs + 1] = GLX_DONT_CARE;
+ else
+ aAttribList[cAttribs + 1] = pAttrib[1];
+ cAttribs += 2;
+ }
+ else
+ {
+ switch (*pAttrib)
+ {
+ case EGL_COLOR_BUFFER_TYPE:
+ aAttribList[cAttribs] = GLX_X_VISUAL_TYPE;
+ aAttribList[cAttribs + 1] = pAttrib[1] == EGL_DONT_CARE ? GLX_DONT_CARE
+ : pAttrib[1] == EGL_RGB_BUFFER ? GLX_TRUE_COLOR
+ : pAttrib[1] == EGL_LUMINANCE_BUFFER ? GLX_GRAY_SCALE
+ : GL_FALSE;
+ if ( *pAttrib == EGL_COLOR_BUFFER_TYPE
+ && pAttrib[1] != EGL_DONT_CARE && pAttrib[1] != EGL_RGB_BUFFER)
+ return setEGLError(EGL_BAD_ACCESS);
+ break;
+ case EGL_CONFIG_CAVEAT:
+ cConfigCaveat = pAttrib[1] == EGL_DONT_CARE ? GLX_DONT_CARE
+ : pAttrib[1] == EGL_NONE ? GLX_NONE
+ : pAttrib[1] == EGL_SLOW_CONFIG ? GLX_SLOW_CONFIG
+ : pAttrib[1] == EGL_NON_CONFORMANT_CONFIG ? GLX_NON_CONFORMANT_CONFIG
+ : GL_FALSE;
+ if (!cConfigCaveat)
+ return setEGLError(EGL_BAD_ATTRIBUTE);
+ cAttribs -= 2;
+ break;
+ case EGL_CONFORMANT:
+ if (pAttrib[1] != EGL_OPENGL_BIT && pAttrib[1] != 0)
+ return setEGLError(EGL_BAD_ACCESS);
+ cConformant = pAttrib[1] == EGL_OPENGL_BIT ? GL_TRUE : GL_FALSE;
+ cAttribs -= 2;
+ break;
+ case EGL_NATIVE_VISUAL_TYPE:
+ aAttribList[cAttribs] = GLX_X_VISUAL_TYPE;
+ aAttribList[cAttribs + 1] = pAttrib[1] == EGL_DONT_CARE ? GLX_DONT_CARE
+ : pAttrib[1] == StaticGray ? GLX_STATIC_GRAY
+ : pAttrib[1] == StaticColor ? GLX_STATIC_COLOR
+ : pAttrib[1] == TrueColor ? GLX_TRUE_COLOR
+ : pAttrib[1] == GrayScale ? GLX_GRAY_SCALE
+ : pAttrib[1] == PseudoColor ? GLX_PSEUDO_COLOR
+ : pAttrib[1] == DirectColor ? GLX_DIRECT_COLOR
+ : GL_FALSE;
+ break;
+ case EGL_RENDERABLE_TYPE:
+ cRenderableType = pAttrib[1];
+ cAttribs -= 2; /* We did not add anything to the list. */
+ break;
+ case EGL_SURFACE_TYPE:
+ if (pAttrib[1] & ~(EGL_PBUFFER_BIT | EGL_PIXMAP_BIT | EGL_WINDOW_BIT))
+ return setEGLError(EGL_BAD_ACCESS);
+ aAttribList[cAttribs] = GLX_DRAWABLE_TYPE;
+ aAttribList[cAttribs + 1] = (pAttrib[1] & EGL_PBUFFER_BIT ? GLX_PBUFFER_BIT : 0)
+ | (pAttrib[1] & EGL_PIXMAP_BIT ? GLX_PIXMAP_BIT : 0)
+ | (pAttrib[1] & EGL_WINDOW_BIT ? GLX_WINDOW_BIT : 0);
+ break;
+ case EGL_TRANSPARENT_TYPE:
+ aAttribList[cAttribs] = GLX_TRANSPARENT_TYPE;
+ aAttribList[cAttribs + 1] = pAttrib[1] == EGL_DONT_CARE ? GLX_DONT_CARE
+ : pAttrib[1] == EGL_NONE ? GLX_NONE
+ : pAttrib[1] == EGL_TRANSPARENT_RGB ? GLX_TRANSPARENT_RGB
+ : GL_FALSE;
+ break;
+ default:
+ return setEGLError(EGL_BAD_ATTRIBUTE);
+ }
+ cAttribs += 2;
+ }
+ }
+ if (cConfigCaveat != GLX_DONT_CARE || cConformant != GLX_DONT_CARE)
+ {
+ aAttribList[cAttribs] = GLX_CONFIG_CAVEAT;
+ aAttribList[cAttribs + 1] = cConformant == GL_FALSE ? GLX_NON_CONFORMANT_CONFIG
+ : cConfigCaveat == EGL_SLOW_CONFIG ? GLX_SLOW_CONFIG
+ : GLX_NONE;
+ cAttribs += 2;
+ }
+ aAttribList[cAttribs] = GLX_RENDER_TYPE;
+ aAttribList[cAttribs + 1] = GLX_RGBA_BIT;
+ cAttribs += 2;
+ if (paAttribs != NULL)
+ {
+ aAttribList[cAttribs] = None;
+ EGL_ASSERT(cAttribs < RT_ELEMENTS(aAttribList));
+ if (!(cRenderableType & EGL_OPENGL_BIT))
+ return setEGLError(EGL_BAD_ACCESS);
+ }
+ paFBConfigs = glXChooseFBConfig(pDisplay, DefaultScreen(pDisplay), paAttribs != NULL ? aAttribList : NULL, &caFBConfigs);
+ if (paFBConfigs == NULL)
+ return setEGLError(EGL_BAD_ACCESS);
+ *pcConfigs = caFBConfigs;
+ for (i = 0; (GLint)i < caConfigs && (GLint)i < caFBConfigs; ++i)
+ paConfigs[i] = (EGLConfig)paFBConfigs[i];
+ XFree(paFBConfigs);
+ return clearEGLError();
+}
+
+DECLEXPORT(EGLBoolean) eglGetConfigAttrib (EGLDisplay hDisplay, EGLConfig cConfig, EGLint cAttribute, EGLint *pValue)
+{
+ Display *pDisplay = (Display *)hDisplay;
+ int cGLXAttribute = convertEGLAttribToGLX(cAttribute);
+ int cValue;
+
+ if (!VALID_PTR(hDisplay))
+ return setEGLError(EGL_NOT_INITIALIZED);
+ if (!VALID_PTR(pValue))
+ return setEGLError(EGL_BAD_PARAMETER);
+ if (glXGetFBConfigAttrib(pDisplay, (GLXFBConfig)cConfig, GLX_FBCONFIG_ID, &cValue))
+ return setEGLError(EGL_BAD_CONFIG);
+ if (cGLXAttribute != None)
+ {
+ if (glXGetFBConfigAttrib(pDisplay, (GLXFBConfig)cConfig, cGLXAttribute, &cValue))
+ return setEGLError(EGL_BAD_ACCESS);
+ *pValue = cValue;
+ return clearEGLError();
+ }
+ switch (cAttribute)
+ {
+ case EGL_ALPHA_MASK_SIZE:
+ *pValue = 0;
+ return clearEGLError();
+ case EGL_LUMINANCE_SIZE:
+ if (glXGetFBConfigAttrib(pDisplay, (GLXFBConfig)cConfig, GLX_X_VISUAL_TYPE, &cValue))
+ return setEGLError(EGL_BAD_ACCESS);
+ if (cValue == GLX_STATIC_GRAY || cValue == GLX_GRAY_SCALE)
+ {
+ if (glXGetFBConfigAttrib(pDisplay, (GLXFBConfig)cConfig, GLX_RED_SIZE, &cValue))
+ return setEGLError(EGL_BAD_ACCESS);
+ *pValue = cValue;
+ }
+ else
+ *pValue = 0;
+ return clearEGLError();
+ case EGL_COLOR_BUFFER_TYPE:
+ if (glXGetFBConfigAttrib(pDisplay, (GLXFBConfig)cConfig, GLX_X_VISUAL_TYPE, &cValue))
+ return setEGLError(EGL_BAD_ACCESS);
+ if (cValue == GLX_STATIC_GRAY || cValue == GLX_GRAY_SCALE)
+ *pValue = EGL_LUMINANCE_BUFFER;
+ else
+ *pValue = EGL_RGB_BUFFER;
+ return clearEGLError();
+ case EGL_CONFIG_CAVEAT:
+ if (glXGetFBConfigAttrib(pDisplay, (GLXFBConfig)cConfig, GLX_CONFIG_CAVEAT, &cValue))
+ return setEGLError(EGL_BAD_ACCESS);
+ *pValue = cValue == GLX_NONE ? EGL_NONE : cValue == GLX_SLOW_CONFIG ? EGL_SLOW_CONFIG : GLX_NON_CONFORMANT_CONFIG;
+ return clearEGLError();
+ case EGL_CONFORMANT:
+ if (glXGetFBConfigAttrib(pDisplay, (GLXFBConfig)cConfig, GLX_CONFIG_CAVEAT, &cValue))
+ return setEGLError(EGL_BAD_ACCESS);
+ *pValue = cValue == GLX_NON_CONFORMANT_CONFIG ? 0 : EGL_OPENGL_BIT;
+ return clearEGLError();
+ case EGL_MATCH_NATIVE_PIXMAP:
+ case EGL_MIN_SWAP_INTERVAL:
+ case EGL_MAX_SWAP_INTERVAL:
+ return setEGLError(EGL_BAD_ACCESS);
+ case EGL_NATIVE_VISUAL_TYPE:
+ if (glXGetFBConfigAttrib(pDisplay, (GLXFBConfig)cConfig, GLX_X_VISUAL_TYPE, &cValue))
+ return setEGLError(EGL_BAD_ACCESS);
+ *pValue = cValue == GLX_STATIC_GRAY ? StaticGray
+ : cValue == GLX_STATIC_COLOR ? StaticColor
+ : cValue == GLX_TRUE_COLOR ? TrueColor
+ : cValue == GLX_GRAY_SCALE ? GrayScale
+ : cValue == GLX_PSEUDO_COLOR ? PseudoColor
+ : cValue == GLX_DIRECT_COLOR ? DirectColor
+ : -1;
+ return clearEGLError();
+ case EGL_RENDERABLE_TYPE:
+ *pValue = EGL_OPENGL_BIT;
+ return clearEGLError();
+ case EGL_SURFACE_TYPE:
+ if (glXGetFBConfigAttrib(pDisplay, (GLXFBConfig)cConfig, GLX_DRAWABLE_TYPE, &cValue))
+ return setEGLError(EGL_BAD_ACCESS);
+ *pValue = (cValue & GLX_PBUFFER_BIT ? EGL_PBUFFER_BIT : 0)
+ | (cValue & GLX_PIXMAP_BIT ? EGL_PIXMAP_BIT : 0)
+ | (cValue & GLX_WINDOW_BIT ? EGL_WINDOW_BIT : 0);
+ return clearEGLError();
+ case EGL_TRANSPARENT_TYPE:
+ if (glXGetFBConfigAttrib(pDisplay, (GLXFBConfig)cConfig, GLX_TRANSPARENT_TYPE, &cValue))
+ return setEGLError(EGL_BAD_ACCESS);
+ *pValue = cValue == GLX_NONE ? EGL_NONE
+ : cValue == GLX_TRANSPARENT_RGB ? EGL_TRANSPARENT_RGB
+ : EGL_FALSE;
+ return *pValue != EGL_FALSE ? clearEGLError() : setEGLError(EGL_BAD_ACCESS);
+ default:
+ return setEGLError(EGL_BAD_ATTRIBUTE);
+ }
+ return clearEGLError();
+}
+
+DECLEXPORT(EGLSurface) eglCreateWindowSurface(EGLDisplay hDisplay, EGLConfig config, EGLNativeWindowType hWindow,
+ const EGLint *paAttributes)
+{
+ Display *pDisplay = (Display *)hDisplay;
+ GLXWindow hGLXWindow;
+
+ if (!VALID_PTR(hDisplay))
+ {
+ setEGLError(EGL_NOT_INITIALIZED);
+ return EGL_NO_SURFACE;
+ }
+ if (paAttributes != NULL) /* Sanity test only. */
+ while (*paAttributes != EGL_NONE)
+ {
+ if (*paAttributes != EGL_RENDER_BUFFER)
+ {
+ setEGLError(EGL_BAD_MATCH);
+ return EGL_NO_SURFACE;
+ }
+ paAttributes += 2;
+ }
+ hGLXWindow = glXCreateWindow(pDisplay, (GLXFBConfig)config, (Window)hWindow, NULL);
+ if (hGLXWindow == None)
+ {
+ setEGLError(EGL_BAD_ALLOC);
+ return EGL_NO_SURFACE;
+ }
+ EGL_ASSERT(hGLXWindow < VBEGL_WINDOW_SURFACE); /* Greater than the maximum XID. */
+ clearEGLError();
+ return (EGLSurface)(hGLXWindow | VBEGL_WINDOW_SURFACE);
+}
+
+static void setAttribute(int *pcStoreIndex, int *pcCurIndex, int *paGLXAttributes, int cAttribute, int cValue)
+{
+ if (*pcStoreIndex < 0)
+ {
+ *pcStoreIndex = *pcCurIndex;
+ *pcCurIndex += 2;
+ paGLXAttributes[*pcStoreIndex] = cAttribute;
+ }
+ paGLXAttributes[*pcStoreIndex + 1] = cValue;
+}
+
+DECLEXPORT(EGLSurface) eglCreatePbufferSurface(EGLDisplay hDisplay, EGLConfig config, EGLint const *paAttributes)
+{
+ Display *pDisplay = (Display *)hDisplay;
+ enum { CPS_WIDTH = 0, CPS_HEIGHT, CPS_LARGEST, CPS_PRESERVED, CPS_TEX_FORMAT, CPS_TEX_TARGET, CPS_MIPMAP_TEX, CPS_END };
+ int acIndices[CPS_END];
+ int aAttributes[CPS_END * 2];
+ int cIndex = 0;
+ unsigned i;
+ GLXPbuffer hPbuffer;
+
+ if (!VALID_PTR(hDisplay))
+ {
+ setEGLError(EGL_NOT_INITIALIZED);
+ return EGL_NO_SURFACE;
+ }
+ for (i = 0; i < RT_ELEMENTS(acIndices); ++i)
+ acIndices[i] = -1;
+ if (paAttributes != NULL)
+ while (*paAttributes != EGL_NONE)
+ {
+ switch (*paAttributes)
+ {
+ case EGL_WIDTH:
+ setAttribute(&acIndices[CPS_WIDTH], &cIndex, aAttributes, GLX_PBUFFER_WIDTH, paAttributes[1]);
+ break;
+ case EGL_HEIGHT:
+ setAttribute(&acIndices[CPS_HEIGHT], &cIndex, aAttributes, GLX_LARGEST_PBUFFER, paAttributes[1]);
+ break;
+ case EGL_LARGEST_PBUFFER:
+ setAttribute(&acIndices[CPS_LARGEST], &cIndex, aAttributes, GLX_PBUFFER_HEIGHT, paAttributes[1]);
+ break;
+ case EGL_BUFFER_PRESERVED:
+ setAttribute(&acIndices[CPS_PRESERVED], &cIndex, aAttributes, GLX_PRESERVED_CONTENTS, paAttributes[1]);
+ break;
+ case EGL_TEXTURE_FORMAT:
+ setAttribute(&acIndices[CPS_TEX_FORMAT], &cIndex, aAttributes, GLX_TEXTURE_FORMAT_EXT, paAttributes[1]);
+ break;
+ case EGL_TEXTURE_TARGET:
+ setAttribute(&acIndices[CPS_TEX_TARGET], &cIndex, aAttributes, GLX_TEXTURE_TARGET_EXT, paAttributes[1]);
+ break;
+ case EGL_MIPMAP_TEXTURE:
+ setAttribute(&acIndices[CPS_MIPMAP_TEX], &cIndex, aAttributes, GLX_MIPMAP_TEXTURE_EXT, paAttributes[1]);
+ break;
+ case EGL_VG_ALPHA_FORMAT:
+ case EGL_VG_COLORSPACE:
+ {
+ setEGLError(EGL_BAD_MATCH);
+ return EGL_NO_SURFACE;
+ }
+ }
+ paAttributes += 2;
+ }
+ EGL_ASSERT((unsigned)cIndex < RT_ELEMENTS(aAttributes) - 1U);
+ aAttributes[cIndex + 1] = None;
+ hPbuffer = glXCreatePbuffer(pDisplay, (GLXFBConfig)config, aAttributes);
+ if (hPbuffer == None)
+ {
+ setEGLError(EGL_BAD_ALLOC);
+ return EGL_NO_SURFACE;
+ }
+ EGL_ASSERT(hPbuffer < VBEGL_WINDOW_SURFACE); /* Greater than the maximum XID. */
+ clearEGLError();
+ return (EGLSurface)(hPbuffer | VBEGL_PBUFFER_SURFACE);
+}
+
+DECLEXPORT(EGLSurface) eglCreatePixmapSurface(EGLDisplay hDisplay, EGLConfig config, EGLNativePixmapType hPixmap,
+ const EGLint *paAttributes)
+{
+ Display *pDisplay = (Display *)hDisplay;
+ GLXPixmap hGLXPixmap;
+
+ if (!VALID_PTR(hDisplay))
+ {
+ setEGLError(EGL_NOT_INITIALIZED);
+ return EGL_NO_SURFACE;
+ }
+ if (paAttributes != NULL) /* Sanity test only. */
+ if (*paAttributes != EGL_NONE)
+ {
+ if (*paAttributes == EGL_VG_COLORSPACE || *paAttributes == EGL_VG_ALPHA_FORMAT)
+ {
+ setEGLError(EGL_BAD_MATCH);
+ return EGL_NO_SURFACE;
+ }
+ else
+ {
+ setEGLError(EGL_BAD_ATTRIBUTE);
+ return EGL_NO_SURFACE;
+ }
+ }
+ hGLXPixmap = glXCreatePixmap(pDisplay, (GLXFBConfig)config, (Pixmap)hPixmap, NULL);
+ if (hGLXPixmap == None)
+ {
+ setEGLError(EGL_BAD_MATCH);
+ return EGL_NO_SURFACE;
+ }
+ EGL_ASSERT(hGLXPixmap < VBEGL_WINDOW_SURFACE); /* Greater than the maximum XID. */
+ clearEGLError();
+ return (EGLSurface)(hGLXPixmap | VBEGL_PIXMAP_SURFACE);
+}
+
+DECLEXPORT(EGLBoolean) eglDestroySurface(EGLDisplay hDisplay, EGLSurface hSurface)
+{
+ Display *pDisplay = (Display *)hDisplay;
+
+ if (!VALID_PTR(hDisplay))
+ return setEGLError(EGL_NOT_INITIALIZED);
+ switch ((GLXDrawable)hSurface & VBEGL_ANY_SURFACE)
+ {
+ case VBEGL_WINDOW_SURFACE:
+ glXDestroyWindow(pDisplay, (GLXWindow)hSurface & ~VBEGL_WINDOW_SURFACE);
+ return clearEGLError();
+ case VBEGL_PBUFFER_SURFACE:
+ glXDestroyPbuffer(pDisplay, (GLXPbuffer)hSurface & ~VBEGL_PBUFFER_SURFACE);
+ return clearEGLError();
+ case VBEGL_PIXMAP_SURFACE:
+ glXDestroyPixmap(pDisplay, (GLXPixmap)hSurface & ~VBEGL_PIXMAP_SURFACE);
+ return clearEGLError();
+ default:
+ return setEGLError(EGL_BAD_SURFACE);
+ }
+}
+
+DECLEXPORT(EGLBoolean) eglSurfaceAttrib(EGLDisplay hDisplay, EGLSurface hSurface, EGLint cAttribute, EGLint cValue)
+{
+ NOREF(hDisplay);
+ NOREF(hSurface);
+ NOREF(cValue);
+ switch (cAttribute)
+ {
+ case EGL_MIPMAP_LEVEL:
+ case EGL_MULTISAMPLE_RESOLVE:
+ case EGL_SWAP_BEHAVIOR:
+ return setEGLError(EGL_BAD_MATCH);
+ default:
+ return setEGLError(EGL_BAD_ATTRIBUTE);
+ }
+}
+
+DECLEXPORT(EGLBoolean) eglQuerySurface(EGLDisplay hDisplay, EGLSurface hSurface, EGLint cAttribute, EGLint *cValue)
+{
+ NOREF(hDisplay);
+ NOREF(hSurface);
+ NOREF(cAttribute);
+ NOREF(cValue);
+ return setEGLError(EGL_BAD_MATCH);
+}
+
+DECLEXPORT(EGLBoolean) eglBindTexImage(EGLDisplay hDisplay, EGLSurface hSurface, EGLint cBuffer)
+{
+ NOREF(hDisplay);
+ NOREF(hSurface);
+ NOREF(cBuffer);
+ return setEGLError(EGL_BAD_MATCH);
+}
+
+DECLEXPORT(EGLBoolean) eglReleaseTexImage(EGLDisplay hDisplay, EGLSurface hSurface, EGLint cBuffer)
+{
+ NOREF(hDisplay);
+ NOREF(hSurface);
+ NOREF(cBuffer);
+ return setEGLError(EGL_BAD_MATCH);
+}
+
+DECLEXPORT(EGLBoolean) eglBindAPI(EGLenum enmApi)
+{
+ return enmApi == EGL_OPENGL_API ? clearEGLError() : setEGLError(EGL_BAD_PARAMETER);
+}
+
+DECLEXPORT(EGLenum) eglQueryAPI(void)
+{
+ return EGL_OPENGL_API;
+}
+
+DECLEXPORT(EGLContext) eglCreateContext(EGLDisplay hDisplay, EGLConfig hConfig, EGLContext hSharedContext,
+ const EGLint *paAttribs)
+{
+ Display *pDisplay = (Display *)hDisplay;
+ GLXContext hNewContext;
+
+ if (!VALID_PTR(hDisplay))
+ {
+ setEGLError(EGL_NOT_INITIALIZED);
+ return EGL_NO_CONTEXT;
+ }
+ if (paAttribs != NULL && *paAttribs != EGL_NONE)
+ {
+ setEGLError(EGL_BAD_ATTRIBUTE);
+ return EGL_NO_CONTEXT;
+ }
+ hNewContext = glXCreateNewContext(pDisplay, (GLXFBConfig)hConfig, GLX_RGBA_TYPE, (GLXContext)hSharedContext, true);
+ if (hNewContext)
+ {
+ clearEGLError();
+ return (EGLContext)hNewContext;
+ }
+ setEGLError(EGL_BAD_MATCH);
+ return EGL_NO_CONTEXT;
+}
+
+DECLEXPORT(EGLBoolean) eglDestroyContext(EGLDisplay hDisplay, EGLContext hContext)
+{
+ Display *pDisplay = (Display *)hDisplay;
+
+ if (!VALID_PTR(hDisplay))
+ return setEGLError(EGL_NOT_INITIALIZED);
+ glXDestroyContext(pDisplay, (GLXContext) hContext);
+ return clearEGLError();
+}
+
+DECLEXPORT(EGLBoolean) eglMakeCurrent(EGLDisplay hDisplay, EGLSurface hDraw, EGLSurface hRead, EGLContext hContext)
+{
+ Display *pDisplay = (Display *)hDisplay;
+ GLXDrawable hGLXDraw = hDraw == EGL_NO_SURFACE ? None : (GLXDrawable)hDraw & ~VBEGL_ANY_SURFACE;
+ GLXDrawable hGLXRead = hRead == EGL_NO_SURFACE ? None : (GLXDrawable)hRead & ~VBEGL_ANY_SURFACE;
+ GLXContext hGLXContext = hContext == EGL_NO_CONTEXT ? None : (GLXContext)hContext;
+ struct VBEGLTLS *pTls = getTls();
+
+ if (!VALID_PTR(hDisplay) || !VALID_PTR(pTls))
+ return setEGLError(EGL_NOT_INITIALIZED);
+ if (glXMakeContextCurrent(pDisplay, hGLXDraw, hGLXRead, hGLXContext))
+ {
+ pTls->hCurrent = hContext;
+ pTls->hCurrentDraw = hDraw;
+ pTls->hCurrentRead = hRead;
+ return clearEGLError();
+ }
+ else
+ return setEGLError(EGL_BAD_MATCH);
+}
+
+DECLEXPORT(EGLContext) eglGetCurrentContext(void)
+{
+ struct VBEGLTLS *pTls = getTls();
+
+ if (!VALID_PTR(pTls))
+ return EGL_NO_CONTEXT;
+ clearEGLError();
+ return pTls->hCurrent;
+}
+
+DECLEXPORT(EGLSurface) eglGetCurrentSurface(EGLint cOp)
+{
+ struct VBEGLTLS *pTls = getTls();
+
+ if (!VALID_PTR(pTls))
+ return EGL_NO_SURFACE;
+ clearEGLError();
+ switch (cOp)
+ {
+ case EGL_DRAW:
+ return pTls->hCurrentDraw;
+ case EGL_READ:
+ return pTls->hCurrentRead;
+ default:
+ setEGLError(EGL_BAD_PARAMETER);
+ return EGL_NO_SURFACE;
+ }
+}
+
+DECLEXPORT(EGLDisplay) eglGetCurrentDisplay(void)
+{
+ struct VBEGLTLS *pTls;
+
+ pTls = getTls();
+ if (!VALID_PTR(pTls))
+ return EGL_NO_DISPLAY;
+ clearEGLError();
+ return pTls->hCurrentDisplay;
+}
+
+DECLEXPORT(EGLBoolean) eglQueryContext(EGLDisplay hDisplay, EGLContext hContext, EGLint cAttribute, EGLint *pcValue)
+{
+ Display *pDisplay = (Display *)hDisplay;
+
+ if (!VALID_PTR(hDisplay))
+ return setEGLError(EGL_NOT_INITIALIZED);
+ if (!VALID_PTR(pcValue))
+ return setEGLError(EGL_BAD_PARAMETER);
+ switch (cAttribute)
+ {
+ case EGL_CONFIG_ID:
+ {
+ int cValue = 0;
+
+ if (glXQueryContext(pDisplay, (GLXContext)hContext, GLX_FBCONFIG_ID, &cValue) == Success)
+ {
+ *pcValue = cValue;
+ return clearEGLError();
+ }
+ return setEGLError(EGL_BAD_MATCH);
+ }
+ case EGL_CONTEXT_CLIENT_TYPE:
+ *pcValue = EGL_OPENGL_API;
+ return clearEGLError();
+ case EGL_CONTEXT_CLIENT_VERSION:
+ *pcValue = 0;
+ return clearEGLError();
+ case EGL_RENDER_BUFFER:
+ *pcValue = EGL_BACK_BUFFER;
+ return clearEGLError();
+ default:
+ return setEGLError(EGL_BAD_ATTRIBUTE);
+ }
+}
+
+DECLEXPORT(EGLBoolean) eglWaitClient(void)
+{
+ glXWaitGL();
+ return clearEGLError();
+}
+
+DECLEXPORT(EGLBoolean) eglWaitGL(void)
+{
+ return setEGLError(EGL_BAD_PARAMETER); /* OpenGL ES only. */
+}
+
+DECLEXPORT(EGLBoolean) eglWaitNative(EGLint cEngine)
+{
+ if (cEngine != EGL_CORE_NATIVE_ENGINE)
+ return setEGLError(EGL_BAD_PARAMETER);
+ glXWaitX();
+ return clearEGLError();
+}
+
+DECLEXPORT(EGLBoolean) eglSwapBuffers(EGLDisplay hDisplay, EGLSurface hSurface)
+{
+ Display *pDisplay = (Display *)hDisplay;
+
+ if (!VALID_PTR(hDisplay))
+ return setEGLError(EGL_NOT_INITIALIZED);
+ glXSwapBuffers(pDisplay, (GLXDrawable)hSurface & ~VBEGL_ANY_SURFACE);
+ return clearEGLError();
+}
+
+/** @todo Work out how this fits over what Chromium has to offer. */
+DECLEXPORT(EGLBoolean) eglCopyBuffers(EGLDisplay hDisplay, EGLSurface hSurface, EGLNativePixmapType hPixmap)
+{
+ Display *pDisplay = (Display *)hDisplay;
+
+ if (!VALID_PTR(pDisplay))
+ return setEGLError(EGL_NOT_INITIALIZED);
+
+ NOREF(hSurface);
+ NOREF(hPixmap);
+ return setEGLError(EGL_BAD_MATCH);
+}
+
+DECLEXPORT(EGLBoolean) eglSwapInterval (EGLDisplay dpy, EGLint interval)
+{
+ NOREF(dpy);
+ NOREF(interval);
+ return EGL_TRUE;
+}
+
+typedef void (*VBEGLFuncPtr)(void);
+DECLEXPORT(VBEGLFuncPtr)eglGetProcAddress(const char *pszName)
+{
+ clearEGLError();
+ return glXGetProcAddress((const GLubyte *)pszName);
+}
+
+DECLEXPORT(EGLBoolean) eglReleaseThread()
+{
+ struct VBEGLTLS *pTls = getTls();
+
+ if (!(pTls))
+ return EGL_TRUE;
+ free(pTls);
+ /* Can this fail with ENOMEM? */
+ pthread_setspecific(g_tls, NULL);
+ return EGL_TRUE;
+}