summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Jackson <ajax@redhat.com>2017-06-29 09:16:51 -0400
committerAdam Jackson <ajax@redhat.com>2017-07-14 14:35:13 -0400
commit130bd1e499153984b602af2b0555d764b59a3097 (patch)
tree8f089b4841d04f5e9730b1c60abc5737fec90083
parent91ad98c950411ae03d1a3d05f9363749bf13b340 (diff)
xwayland: Add glamor-egl backed GLX provider
Signed-off-by: Adam Jackson <ajax@redhat.com>
-rw-r--r--glamor/glamor_glx_provider.c353
-rw-r--r--glamor/meson.build10
-rw-r--r--hw/xwayland/meson.build3
-rw-r--r--hw/xwayland/xwayland.c8
4 files changed, 372 insertions, 2 deletions
diff --git a/glamor/glamor_glx_provider.c b/glamor/glamor_glx_provider.c
new file mode 100644
index 000000000..3fefe22a7
--- /dev/null
+++ b/glamor/glamor_glx_provider.c
@@ -0,0 +1,353 @@
+/*
+ * Copyright © 2017 Red Hat, Inc.
+ *
+ * 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 (including the next
+ * paragraph) 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.
+ *
+ * Authors:
+ * Adam Jackson <ajax@redhat.com>
+ */
+
+/*
+ * GLX on EGL
+ *
+ * TODO:
+ *
+ * - make pbuffers actually work
+ * - EXT_texture_from_pixmap
+ * - MESA_copy_sub_buffer
+ * - swap interval
+ * - ARB_create_context
+ */
+
+#define MESA_EGL_NO_X11_HEADERS
+#include <dix-config.h>
+#include "glxserver.h"
+#include <epoxy/egl.h>
+#include "glxutil.h"
+
+/* Can't get these from <epoxy/glx.h> since it pulls in client headers */
+#define GLX_RGBA_BIT 0x00000001
+#define GLX_WINDOW_BIT 0x00000001
+#define GLX_PIXMAP_BIT 0x00000002
+#define GLX_PBUFFER_BIT 0x00000004
+#define GLX_TRUE_COLOR 0x8002
+#define GLX_NONE 0x8000
+#define GLX_SLOW_CONFIG 0x8001
+#define GLX_NON_CONFORMANT_CONFIG 0x800D
+#define GLX_TEXTURE_1D_BIT_EXT 0x00000001
+#define GLX_TEXTURE_2D_BIT_EXT 0x00000002
+#define GLX_TEXTURE_RECTANGLE_BIT_EXT 0x00000004
+
+struct egl_config {
+ __GLXconfig base;
+ EGLConfig config;
+};
+
+struct egl_context {
+ __GLXcontext base;
+ EGLContext ctx;
+
+ /* what this context previously thought was current */
+ __GLXdrawable *draw;
+ __GLXdrawable *read;
+};
+
+struct egl_drawable {
+ __GLXdrawable base;
+ EGLSurface draw;
+};
+
+struct egl_screen {
+ __GLXscreen base;
+ EGLDisplay display;
+ EGLConfig *configs;
+};
+
+static void
+egl_screen_destroy(__GLXscreen *screen)
+{
+}
+
+static void
+egl_destroy_context(__GLXcontext *ctx)
+{
+}
+
+static int
+egl_make_current(__GLXcontext *current)
+{
+ return TRUE;
+}
+
+static int
+egl_lose_current(__GLXcontext *current)
+{
+ return TRUE;
+}
+
+static __GLXcontext *
+egl_screen_create_context(__GLXscreen *_screen, __GLXconfig *_cfg,
+ __GLXcontext *_share, unsigned num_attribs,
+ const uint32_t *attribs, int *error)
+{
+ __GLXcontext *ctx;
+
+ if (!(ctx = calloc(1, sizeof(__GLXcontext)))) {
+ *error = BadAlloc;
+ return NULL;
+ }
+
+ ctx->destroy = egl_destroy_context;
+ ctx->makeCurrent = egl_make_current;
+ ctx->loseCurrent = egl_lose_current;
+
+ return ctx;
+}
+
+static void
+egl_drawable_destroy(__GLXdrawable *_draw)
+{
+}
+
+static GLboolean
+egl_swap_buffers(ClientPtr client, __GLXdrawable *_draw)
+{
+ /*
+ * technically this can be hit for the stupid sgi compat case of
+ * SwapBuffers without a context, the assumption is that the
+ * server knows how to do it. and when you make an assumption, you
+ * make an ass out of u and mption.
+ */
+ return FALSE;
+}
+
+static __GLXdrawable *
+egl_screen_create_drawable(ClientPtr client, __GLXscreen *gs,
+ DrawablePtr pDraw, XID drawId, int type,
+ XID glxDrawId, __GLXconfig *config)
+{
+ struct egl_drawable *draw = NULL;
+
+ if (!(draw = calloc(1, sizeof *draw)))
+ return NULL;
+
+ /* XXX probably need to do more, yeah? */
+
+ __glXDrawableInit(&draw->base, gs, pDraw, type, glxDrawId, config);
+
+ draw->base.destroy = egl_drawable_destroy;
+ draw->base.swapBuffers = egl_swap_buffers;
+ /* copySubBuffer */
+
+ return &draw->base;
+}
+
+static __GLXconfig *
+egl_mirror_configs(ScreenPtr pScreen, struct egl_screen *screen)
+{
+ int i, nconfigs;
+ struct egl_config *c, *configs = NULL;
+ EGLConfig *host_configs = NULL;
+
+ eglGetConfigs(screen->display, NULL, 0, &nconfigs);
+ if (!(host_configs = calloc(nconfigs, sizeof *host_configs)))
+ goto bail;
+
+ if (!(configs = calloc(nconfigs, sizeof *configs)))
+ goto bail;
+
+ eglGetConfigs(screen->display, host_configs, nconfigs, &nconfigs);
+
+ /* translate from EGL config attrib to GLX fbconfig attrib */
+ for (i = 0; i < nconfigs; i++) {
+ EGLConfig hc = host_configs[i];
+ EGLint value;
+
+ /* XXX skip EGL_LUMINANCE_BUFFER? */
+
+ if (i > 0)
+ configs[i-1].base.next = &configs[i].base;
+ c = &configs[i];
+
+ /* constants. changing these requires (at least) new EGL extensions */
+ c->base.doubleBufferMode = GL_TRUE;
+ c->base.stereoMode = GL_FALSE;
+ c->base.numAuxBuffers = 0;
+ c->base.level = 0;
+ c->base.transparentAlpha = 0;
+ c->base.transparentIndex = 0;
+ c->base.visualSelectGroup = 0;
+ c->base.indexBits = 0;
+ c->base.renderType = GLX_RGBA_BIT;
+ c->base.optimalPbufferWidth = 0;
+ c->base.optimalPbufferHeight = 0;
+ /*
+ * EGL has this as a property of context, in EGL_KHR_gl_colorspace.
+ * Let's just say we can't for now.
+ */
+ c->base.sRGBCapable = 0;
+
+ /* these are potentially variable, depending on the ddx */
+ c->base.drawableType = GLX_WINDOW_BIT |
+ GLX_PIXMAP_BIT |
+ GLX_PBUFFER_BIT;
+ c->base.yInverted = 0;
+ c->base.visualType = GLX_TRUE_COLOR;
+
+ /*
+ * glx conformance failure: there's no such thing as accumulation
+ * buffers in EGL. they should be emulable with shaders and fbos,
+ * but i'm pretty sure nobody's using this feature since it's
+ * entirely software. note that glx conformance merely requres
+ * that an accum buffer _exist_, not a minimum bitness.
+ *
+ * future glx specs make accumulation buffers optional so yay.
+ */
+ c->base.accumRedBits = 0;
+ c->base.accumGreenBits = 0;
+ c->base.accumBlueBits = 0;
+ c->base.accumAlphaBits = 0;
+
+ /* stuff that directly translates */
+#define GET(attr, slot) \
+ eglGetConfigAttrib(screen->display, hc, attr, &c->base.slot)
+ GET(EGL_RED_SIZE, redBits);
+ GET(EGL_GREEN_SIZE, greenBits);
+ GET(EGL_BLUE_SIZE, blueBits);
+ GET(EGL_ALPHA_SIZE, alphaBits);
+ GET(EGL_BUFFER_SIZE, rgbBits);
+ GET(EGL_DEPTH_SIZE, depthBits);
+ GET(EGL_STENCIL_SIZE, stencilBits);
+ GET(EGL_TRANSPARENT_RED_VALUE, transparentRed);
+ GET(EGL_TRANSPARENT_GREEN_VALUE, transparentGreen);
+ GET(EGL_TRANSPARENT_BLUE_VALUE, transparentBlue);
+ GET(EGL_SAMPLE_BUFFERS, sampleBuffers);
+ GET(EGL_SAMPLES, samples);
+ if (c->base.renderType & GLX_PBUFFER_BIT) {
+ GET(EGL_MAX_PBUFFER_WIDTH, maxPbufferWidth);
+ GET(EGL_MAX_PBUFFER_HEIGHT, maxPbufferHeight);
+ GET(EGL_MAX_PBUFFER_PIXELS, maxPbufferPixels);
+ }
+
+ /*
+ * These aren't really properties of the config, but of our
+ * implementation. Here I'm just hardcoding what's correct
+ * for Mesa.
+ */
+#if 0
+ GET(EGL_BIND_TO_TEXTURE_RGB, bindToTextureRgb);
+ GET(EGL_BIND_TO_TEXTURE_RGBA, bindToTextureRgba);
+#endif
+ c->base.bindToTextureRgb = GL_TRUE;
+ c->base.bindToTextureRgba = GL_TRUE;
+ c->base.bindToMipmapTexture = GL_FALSE;
+ c->base.bindToTextureTargets = GLX_TEXTURE_1D_BIT_EXT |
+ GLX_TEXTURE_2D_BIT_EXT |
+ GLX_TEXTURE_RECTANGLE_BIT_EXT;
+#undef GET
+
+ /* derived state */
+ eglGetConfigAttrib(screen->display, hc, EGL_CONFIG_CAVEAT, &value);
+ if (value == EGL_NONE)
+ c->base.visualRating = GLX_NONE;
+ else if (value == EGL_SLOW_CONFIG)
+ c->base.visualRating = GLX_SLOW_CONFIG;
+ else if (value == EGL_NON_CONFORMANT_CONFIG)
+ c->base.visualRating = GLX_NON_CONFORMANT_CONFIG;
+ /* XXX else scream */
+
+ // GET(GLX_CONFIG_CAVEAT, visualRating);
+ // GET(GLX_SWAP_METHOD_OML, swapMethod);
+
+ /* map to the backend's config */
+ c->config = hc;
+
+ /*
+ * XXX do something less ugly. probably we should look at the
+ * existing visual and copy that.
+ */
+ if (1) {
+ c->base.redMask = 0xff0000;
+ c->base.greenMask = 0x00ff00;
+ c->base.blueMask = 0x0000ff;
+ if (c->base.alphaBits)
+ /* assume all remaining bits are alpha */
+ c->base.alphaMask = 0xff000000;
+ }
+ }
+
+ screen->configs = host_configs;
+ return &configs->base;
+
+bail:
+ free(configs);
+ free(host_configs);
+ return NULL;
+}
+
+static __GLXscreen *
+egl_screen_probe(ScreenPtr pScreen)
+{
+ struct egl_screen *screen;
+ EGLDisplay dpy;
+
+ if (!(screen = calloc(1, sizeof *screen)))
+ return NULL;
+
+ screen->base.destroy = egl_screen_destroy;
+ screen->base.createContext = egl_screen_create_context;
+ screen->base.createDrawable = egl_screen_create_drawable;
+ /* screen->base.swapInterval = NULL; */
+
+ __glXInitExtensionEnableBits(screen->base.glx_enable_bits);
+
+ dpy = screen->display = eglGetCurrentDisplay(); /* XXX */
+
+ screen->base.fbconfigs = egl_mirror_configs(pScreen, screen);
+ if (!screen->base.fbconfigs) {
+ free(screen);
+ return NULL;
+ }
+
+ /* extension setup */
+#if 0
+ if (epoxy_has_egl_extension(dpy, "EGL_KHR_create_context")) {
+ __glXEnableExtension(screen->glx_enable_bits,
+ "GLX_ARB_create_context");
+ /* XXX check client APIs */
+ __glXEnableExtension(screen->glx_enable_bits,
+ "GLX_ARB_create_context_profile");
+ __glXEnableExtension(screen->glx_enable_bits,
+ "GLX_EXT_create_context_es_profile");
+ __glXEnableExtension(screen->glx_enable_bits,
+ "GLX_EXT_create_context_es2_profile");
+ }
+#endif
+
+ __glXScreenInit(&screen->base, pScreen);
+
+ return &screen->base;
+}
+
+__GLXprovider glamor_glx_provider = {
+ egl_screen_probe,
+ "EGL",
+ NULL
+};
diff --git a/glamor/meson.build b/glamor/meson.build
index 0b963275e..6699527df 100644
--- a/glamor/meson.build
+++ b/glamor/meson.build
@@ -47,6 +47,16 @@ glamor = static_library('glamor',
],
)
+glamor_glx_provider = static_library('glamor_glx_provider',
+ 'glamor_glx_provider.c',
+ include_directories: [ inc, glx_inc ],
+ dependencies: [
+ common_dep,
+ dependency('epoxy'),
+ ],
+ pic: true,
+)
+
glamor_egl_stubs = static_library('glamor_egl_stubs',
'glamor_egl_stubs.c',
include_directories: inc,
diff --git a/hw/xwayland/meson.build b/hw/xwayland/meson.build
index d2791fe14..99256d852 100644
--- a/hw/xwayland/meson.build
+++ b/hw/xwayland/meson.build
@@ -50,7 +50,7 @@ endif
executable(
'Xwayland',
srcs,
- include_directories: inc,
+ include_directories: [ inc, glx_inc ],
dependencies: [
common_dep,
xwayland_dep,
@@ -58,6 +58,7 @@ executable(
link_with: [
libxserver_main,
xwayland_glamor,
+ glamor_glx_provider,
libxserver_fb,
libxserver,
libxserver_xext_vidmode,
diff --git a/hw/xwayland/xwayland.c b/hw/xwayland/xwayland.c
index 551443f93..fc2393245 100644
--- a/hw/xwayland/xwayland.c
+++ b/hw/xwayland/xwayland.c
@@ -36,6 +36,7 @@
#include <os.h>
#include <xserver_poll.h>
#include <propertyst.h>
+#include "glxserver.h"
#ifdef XF86VIDMODE
#include <X11/extensions/xf86vmproto.h>
@@ -1044,9 +1045,14 @@ InitOutput(ScreenInfo * screen_info, int argc, char **argv)
screen_info->bitmapBitOrder = BITMAP_BIT_ORDER;
screen_info->numPixmapFormats = ARRAY_SIZE(depths);
- if (serverGeneration == 1)
+ if (serverGeneration == 1) {
+#if defined(GLXEXT) && defined(GLAMOR)
+ extern __GLXprovider glamor_glx_provider;
+ GlxPushProvider(&glamor_glx_provider);
+#endif
LoadExtensionList(xwayland_extensions,
ARRAY_SIZE(xwayland_extensions), FALSE);
+ }
/* Cast away warning from missing printf annotation for
* wl_log_func_t. Wayland 1.5 will have the annotation, so we can