From 8469241592b94b002a975274a596ca0dcdd9563f Mon Sep 17 00:00:00 2001 From: Adam Jackson Date: Wed, 8 May 2019 14:09:00 -0400 Subject: [PATCH] xwayland: Add EGL-backed GLX provider Without this we're using driswrast to set up GLX visuals. This is unfortunate because llvmpipe does not expose multisample configs, so various apps that expect them will fail. With this we just query the capabilities of the EGL that's backing glamor, and reflect that to the GLX clients. This also paves the way for xserver to stop being a DRI driver loader, which is nice. Fixes: xorg/xserver#640 Fixes: xorg/xserver#643 Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=98272 Reviewed-by: Olivier Fourdan Signed-off-by: Adam Jackson --- hw/xwayland/Makefile.am | 4 + hw/xwayland/meson.build | 10 +- hw/xwayland/xwayland-glamor.c | 7 + hw/xwayland/xwayland-glx.c | 344 ++++++++++++++++++++++++++++++++++ hw/xwayland/xwayland.h | 5 + 5 files changed, 369 insertions(+), 1 deletion(-) create mode 100644 hw/xwayland/xwayland-glx.c diff --git a/hw/xwayland/Makefile.am b/hw/xwayland/Makefile.am index 502879e2a..282da58f9 100644 --- a/hw/xwayland/Makefile.am +++ b/hw/xwayland/Makefile.am @@ -22,6 +22,10 @@ Xwayland_SOURCES = \ $(top_srcdir)/mi/miinitext.c if GLX +Xwayland_SOURCES += \ + xwayland-glx.c +Xwayland_CFLAGS += \ + -I$(top_srcdir)/glx GLXVND_LIB = $(top_builddir)/glx/libglxvnd.la endif diff --git a/hw/xwayland/meson.build b/hw/xwayland/meson.build index 36bf2133a..c8746e591 100644 --- a/hw/xwayland/meson.build +++ b/hw/xwayland/meson.build @@ -54,6 +54,9 @@ xwayland_glamor = [] eglstream_srcs = [] if build_glamor srcs += 'xwayland-glamor.c' + if build_glx + srcs += 'xwayland-glx.c' + endif if gbm_dep.found() srcs += 'xwayland-glamor-gbm.c' endif @@ -80,10 +83,15 @@ if build_glamor xwayland_glamor += glamor endif +wayland_inc = [ inc, ] +if build_glx + wayland_inc += glx_inc +endif + executable( 'Xwayland', srcs, - include_directories: inc, + include_directories: wayland_inc, dependencies: [ common_dep, xwayland_dep, diff --git a/hw/xwayland/xwayland-glamor.c b/hw/xwayland/xwayland-glamor.c index f4bd561ea..dc07f7933 100644 --- a/hw/xwayland/xwayland-glamor.c +++ b/hw/xwayland/xwayland-glamor.c @@ -30,6 +30,9 @@ #include #include +#ifdef GLXEXT +#include "glx_extinit.h" +#endif static void glamor_egl_make_current(struct glamor_context *glamor_ctx) @@ -264,5 +267,9 @@ xwl_glamor_init(struct xwl_screen *xwl_screen) ErrorF("Failed to initialize glamor Xv extension\n"); #endif +#ifdef GLXEXT + GlxPushProvider(&glamor_provider); +#endif + return TRUE; } diff --git a/hw/xwayland/xwayland-glx.c b/hw/xwayland/xwayland-glx.c new file mode 100644 index 000000000..71c9aad23 --- /dev/null +++ b/hw/xwayland/xwayland-glx.c @@ -0,0 +1,344 @@ +/* + * Copyright © 2019 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 + */ + +/* + * Sets up GLX capabilities based on the EGL capabilities of the glamor + * renderer for the screen. Without this you will get whatever swrast + * can do, which often does not include things like multisample visuals. + */ + +#include +#include "xwayland.h" +#define MESA_EGL_NO_X11_HEADERS +// #include +#include +#include "glxserver.h" +#include "glxutil.h" +#include "compint.h" +#include +#include "glamor_context.h" +#include "glamor.h" + +/* Can't get these from 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_NONE 0x8000 +#define GLX_SLOW_CONFIG 0x8001 +#define GLX_TRUE_COLOR 0x8002 +#define GLX_DIRECT_COLOR 0x8003 +#define GLX_NON_CONFORMANT_CONFIG 0x800D +#define GLX_DONT_CARE 0xFFFFFFFF +#define GLX_RGBA_FLOAT_BIT_ARB 0x00000004 +#define GLX_SWAP_UNDEFINED_OML 0x8063 + +struct egl_config { + __GLXconfig base; + EGLConfig config; +}; + +struct egl_screen { + __GLXscreen base; + EGLDisplay display; + EGLConfig *configs; +}; + +static void +egl_screen_destroy(__GLXscreen *_screen) +{ + struct egl_screen *screen = (struct egl_screen *)_screen; + + /* XXX do we leak the fbconfig list? */ + + free(screen->configs); + __glXScreenDestroy(_screen); + free(_screen); +} + +static void +egl_drawable_destroy(__GLXdrawable *draw) +{ + free(draw); +} + +static GLboolean +egl_drawable_swap_buffers(ClientPtr client, __GLXdrawable *draw) +{ + return GL_FALSE; +} + +static void +egl_drawable_copy_sub_buffer(__GLXdrawable *draw, int x, int y, int w, int h) +{ +} + +static void +egl_drawable_wait_x(__GLXdrawable *draw) +{ + glamor_block_handler(draw->pDraw->pScreen); +} + +static void +egl_drawable_wait_gl(__GLXdrawable *draw) +{ +} + +static __GLXdrawable * +egl_create_glx_drawable(ClientPtr client, __GLXscreen *screen, + DrawablePtr draw, XID drawid, int type, + XID glxdrawid, __GLXconfig *modes) +{ + __GLXdrawable *ret; + + ret = calloc(1, sizeof *ret); + if (!ret) + return NULL; + + if (!__glXDrawableInit(ret, screen, draw, type, glxdrawid, modes)) { + free(ret); + return NULL; + } + + ret->destroy = egl_drawable_destroy; + ret->swapBuffers = egl_drawable_swap_buffers; + ret->copySubBuffer = egl_drawable_copy_sub_buffer; + ret->waitX = egl_drawable_wait_x; + ret->waitGL = egl_drawable_wait_gl; + + return ret; +} + +/* + * TODO: + * + * - figure out sRGB + * - bindToTextureTargets is suspicious + * - better channel mask setup + * - drawable type masks is suspicious + */ +static struct egl_config * +translate_eglconfig(struct egl_screen *screen, EGLConfig hc, + struct egl_config *chain, Bool direct_color, + Bool double_buffer) +{ + EGLint value; + struct egl_config *c = calloc(1, sizeof *c); + + if (!c) + return chain; + + /* constants. changing these requires (at least) new EGL extensions */ + c->base.stereoMode = GL_FALSE; + c->base.numAuxBuffers = 0; + c->base.level = 0; + c->base.transparentAlpha = 0; + c->base.transparentIndex = 0; + c->base.transparentPixel = GLX_NONE; + c->base.visualSelectGroup = 0; + c->base.indexBits = 0; + c->base.optimalPbufferWidth = 0; + c->base.optimalPbufferHeight = 0; + c->base.bindToMipmapTexture = 0; + c->base.bindToTextureTargets = GLX_DONT_CARE; + c->base.sRGBCapable = 0; + c->base.swapMethod = GLX_SWAP_UNDEFINED_OML; + + /* this is... suspect */ + c->base.drawableType = GLX_WINDOW_BIT | GLX_PIXMAP_BIT | GLX_PBUFFER_BIT; + + /* hmm */ + c->base.bindToTextureRgb = GL_TRUE; + c->base.bindToTextureRgba = GL_TRUE; + + /* + * 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 requires + * that an accum buffer _exist_, not a minimum bitness. + */ + c->base.accumRedBits = 0; + c->base.accumGreenBits = 0; + c->base.accumBlueBits = 0; + c->base.accumAlphaBits = 0; + + /* parametric state */ + if (direct_color) + c->base.visualType = GLX_DIRECT_COLOR; + else + c->base.visualType = GLX_TRUE_COLOR; + + if (double_buffer) + c->base.doubleBufferMode = GL_TRUE; + else + c->base.doubleBufferMode = GL_FALSE; + + /* direct-mapped state */ +#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); + } +#undef GET + + /* derived state: config caveats */ + 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; + /* else panic */ + + /* derived state: float configs */ + c->base.renderType = GLX_RGBA_BIT; + if (eglGetConfigAttrib(screen->display, hc, EGL_COLOR_COMPONENT_TYPE_EXT, + &value) == EGL_TRUE) { + if (value == EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT) { + c->base.renderType = GLX_RGBA_FLOAT_BIT_ARB; + } + /* else panic */ + } + + /* map to the backend's config */ + c->config = hc; + + /* + * XXX do something less ugly + */ + if (c->base.renderType == GLX_RGBA_BIT) { + if (c->base.rgbBits == 24 || c->base.rgbBits == 32) { + 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; + } + } + + c->base.next = chain ? &chain->base : NULL; + return c; +} + +static __GLXconfig * +egl_mirror_configs(ScreenPtr pScreen, struct egl_screen *screen) +{ + int i, j, k, nconfigs; + struct egl_config *c = NULL; + EGLConfig *host_configs = NULL; + Bool offon[] = { FALSE, TRUE }; + + eglGetConfigs(screen->display, NULL, 0, &nconfigs); + if (!(host_configs = calloc(nconfigs, sizeof *host_configs))) + return NULL; + + eglGetConfigs(screen->display, host_configs, nconfigs, &nconfigs); + + /* We walk the EGL configs backwards to make building the + * ->next chain easier. + */ + for (i = nconfigs - 1; i > 0; i--) + for (j = 0; j < 2; j++) /* direct_color */ + for (k = 0; k < 2; k++) /* direct_color */ + c = translate_eglconfig(screen, host_configs[i], c, + /* direct_color */ offon[j], + /* double_buffer */ offon[k] + ); + + screen->configs = host_configs; + return c ? &c->base : NULL; +} + +static __GLXscreen * +egl_screen_probe(ScreenPtr pScreen) +{ + struct egl_screen *screen; + struct xwl_screen *xwl_screen = xwl_screen_get(pScreen); + __GLXscreen *base; + + if (enableIndirectGLX) + return NULL; /* not implemented */ + + if (!(screen = calloc(1, sizeof *screen))) + return NULL; + + base = &screen->base; + base->destroy = egl_screen_destroy; + base->createDrawable = egl_create_glx_drawable; + /* base.swapInterval = NULL; */ + + screen->display = xwl_screen->glamor_ctx->display; + + __glXInitExtensionEnableBits(screen->base.glx_enable_bits); + __glXEnableExtension(base->glx_enable_bits, "GLX_ARB_context_flush_control"); + __glXEnableExtension(base->glx_enable_bits, "GLX_ARB_create_context"); + __glXEnableExtension(base->glx_enable_bits, "GLX_ARB_create_context_no_error"); + __glXEnableExtension(base->glx_enable_bits, "GLX_ARB_create_context_profile"); + __glXEnableExtension(base->glx_enable_bits, "GLX_ARB_create_context_robustness"); + __glXEnableExtension(base->glx_enable_bits, "GLX_ARB_fbconfig_float"); + __glXEnableExtension(base->glx_enable_bits, "GLX_EXT_create_context_es2_profile"); + __glXEnableExtension(base->glx_enable_bits, "GLX_EXT_create_context_es_profile"); + __glXEnableExtension(base->glx_enable_bits, "GLX_EXT_fbconfig_packed_float"); + __glXEnableExtension(base->glx_enable_bits, "GLX_EXT_framebuffer_sRGB"); + __glXEnableExtension(base->glx_enable_bits, "GLX_EXT_no_config_context"); + __glXEnableExtension(base->glx_enable_bits, "GLX_EXT_texture_from_pixmap"); + __glXEnableExtension(base->glx_enable_bits, "GLX_MESA_copy_sub_buffer"); + // __glXEnableExtension(base->glx_enable_bits, "GLX_SGI_swap_control"); + + base->fbconfigs = egl_mirror_configs(pScreen, screen); + if (!base->fbconfigs) { + free(screen); + return NULL; + } + + __glXScreenInit(base, pScreen); + __glXsetGetProcAddress(eglGetProcAddress); + + return base; +} + +__GLXprovider glamor_provider = { + egl_screen_probe, + "glamor", + NULL +}; diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h index 92664e812..85691d9d4 100644 --- a/hw/xwayland/xwayland.h +++ b/hw/xwayland/xwayland.h @@ -485,4 +485,9 @@ static inline void xwl_glamor_init_eglstream(struct xwl_screen *xwl_screen) } #endif +#ifdef GLXEXT +#include "glx_extinit.h" +extern __GLXprovider glamor_provider; +#endif + #endif