diff --git a/hw/xwayland/meson.build b/hw/xwayland/meson.build index 36bf213..c8746e5 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 48e330a..dcfc7f1 100644 --- a/hw/xwayland/xwayland-glamor.c +++ b/hw/xwayland/xwayland-glamor.c @@ -31,6 +31,9 @@ #include #include +#ifdef GLXEXT +#include "glx_extinit.h" +#endif static void glamor_egl_make_current(struct glamor_context *glamor_ctx) @@ -262,5 +265,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 0000000..71c9aad --- /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 0854df4..a4804fe 100644 --- a/hw/xwayland/xwayland.h +++ b/hw/xwayland/xwayland.h @@ -488,4 +488,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