/* * 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 #define EGL_NO_X11 // #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.redBits == 5 && (c->base.rgbBits == 15 || c->base.rgbBits == 16)) { c->base.blueMask = 0x0000001f; if (c->base.alphaBits) { c->base.greenMask = 0x000003e0; c->base.redMask = 0x00007c00; c->base.alphaMask = 0x00008000; } else { c->base.greenMask = 0x000007e0; c->base.redMask = 0x0000f800; c->base.alphaMask = 0x00000000; } } else if (c->base.redBits == 8 && (c->base.rgbBits == 24 || c->base.rgbBits == 32)) { c->base.blueMask = 0x000000ff; c->base.greenMask = 0x0000ff00; c->base.redMask = 0x00ff0000; if (c->base.alphaBits) /* assume all remaining bits are alpha */ c->base.alphaMask = 0xff000000; } else if (c->base.redBits == 10 && (c->base.rgbBits == 30 || c->base.rgbBits == 32)) { c->base.blueMask = 0x000003ff; c->base.greenMask = 0x000ffc00; c->base.redMask = 0x3ff00000; if (c->base.alphaBits) /* assume all remaining bits are alpha */ c->base.alphaMask = 0xc000000; } } 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 };