// Copyright 2019-2022, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 /*! * @file * @brief Xlib client side glue to compositor implementation. * @author Jakob Bornecrantz * @ingroup comp_client */ #include #include #include "util/u_misc.h" #include "util/u_logging.h" #include "xrt/xrt_gfx_xlib.h" #include "client/comp_gl_xlib_client.h" #include "client/comp_gl_memobj_swapchain.h" #include "ogl/ogl_api.h" #include "ogl/glx_api.h" /* * * OpenGL context helper. * */ static inline bool context_matches(const struct client_gl_context *a, const struct client_gl_context *b) { return a->ctx == b->ctx && a->draw == b->draw && a->read == b->read && a->dpy == b->dpy; } static inline void context_save_current(struct client_gl_context *current_ctx) { current_ctx->dpy = glXGetCurrentDisplay(); current_ctx->ctx = glXGetCurrentContext(); current_ctx->read = glXGetCurrentDrawable(); current_ctx->draw = glXGetCurrentReadDrawable(); } static inline bool context_make_current(const struct client_gl_context *ctx_to_make_current) { if (glXMakeContextCurrent(ctx_to_make_current->dpy, ctx_to_make_current->draw, ctx_to_make_current->read, ctx_to_make_current->ctx)) { return true; } return false; } /*! * Down-cast helper. * * @private @memberof client_gl_xlib_compositor */ static inline struct client_gl_xlib_compositor * client_gl_xlib_compositor(struct xrt_compositor *xc) { return (struct client_gl_xlib_compositor *)xc; } static void client_gl_xlib_compositor_destroy(struct xrt_compositor *xc) { struct client_gl_xlib_compositor *c = client_gl_xlib_compositor(xc); client_gl_compositor_fini(&c->base); free(c); } static xrt_result_t client_gl_context_begin_locked(struct xrt_compositor *xc, enum client_gl_context_reason reason) { struct client_gl_xlib_compositor *c = client_gl_xlib_compositor(xc); struct client_gl_context *app_ctx = &c->app_context; context_save_current(&c->temp_context); bool need_make_current = !context_matches(&c->temp_context, app_ctx); U_LOG_T("GL Context begin: need makeCurrent: %d (current %p -> app %p)", need_make_current, (void *)c->temp_context.ctx, (void *)app_ctx->ctx); if (need_make_current && !context_make_current(app_ctx)) { U_LOG_E("Failed to make GLX context current"); // No need to restore on failure. return XRT_ERROR_OPENGL; } return XRT_SUCCESS; } static void client_gl_context_end_locked(struct xrt_compositor *xc, enum client_gl_context_reason reason) { struct client_gl_xlib_compositor *c = client_gl_xlib_compositor(xc); struct client_gl_context *app_ctx = &c->app_context; struct client_gl_context *current_glx_context = &c->temp_context; bool need_make_current = !context_matches(&c->temp_context, app_ctx); U_LOG_T("GL Context end: need makeCurrent: %d (app %p -> current %p)", need_make_current, (void *)app_ctx->ctx, (void *)c->temp_context.ctx); if (need_make_current && !context_make_current(current_glx_context)) { U_LOG_E("Failed to make old GLX context current! (%p, %#lx, %#lx, %p)", (void *)current_glx_context->dpy, (unsigned long)current_glx_context->draw, (unsigned long)current_glx_context->read, (void *)current_glx_context->ctx); // fall through to os_mutex_unlock even if we didn't succeed in restoring the context } } typedef void (*void_ptr_func)(void); #ifdef __cplusplus extern "C" #endif void_ptr_func glXGetProcAddress(const char *procName); struct client_gl_xlib_compositor * client_gl_xlib_compositor_create(struct xrt_compositor_native *xcn, Display *xDisplay, uint32_t visualid, GLXFBConfig glxFBConfig, GLXDrawable glxDrawable, GLXContext glxContext) { // We're not using any GLX extensions so screen number is irrelevant. gladLoadGLX(xDisplay, 0, glXGetProcAddress); // Save old GLX context. struct client_gl_context current_ctx; context_save_current(¤t_ctx); // The context and drawables given from the app. struct client_gl_context app_ctx = { .dpy = xDisplay, .ctx = glxContext, .draw = glxDrawable, .read = glxDrawable, }; bool need_make_current = !context_matches(¤t_ctx, &app_ctx); U_LOG_T("GL Compositor create: need makeCurrent: %d (current %p -> app %p)", need_make_current, (void *)current_ctx.ctx, (void *)app_ctx.ctx); if (need_make_current && !context_make_current(&app_ctx)) { U_LOG_E("Failed to make GLX context current"); // No need to restore on failure. return NULL; } gladLoadGL(glXGetProcAddress); U_LOG_T("GL Compositor create: need makeCurrent: %d (app %p -> current %p)", need_make_current, (void *)app_ctx.ctx, (void *)current_ctx.ctx); if (need_make_current && !context_make_current(¤t_ctx)) { U_LOG_E("Failed to make old GLX context current! (%p, %#lx, %#lx, %p)", (void *)current_ctx.dpy, (unsigned long)current_ctx.draw, (unsigned long)current_ctx.read, (void *)current_ctx.ctx); } #define CHECK_REQUIRED_EXTENSION(EXT) \ do { \ if (!GLAD_##EXT) { \ U_LOG_E("%s - Required OpenGL extension " #EXT " not available", __func__); \ return NULL; \ } \ } while (0) CHECK_REQUIRED_EXTENSION(GL_EXT_memory_object); #ifdef XRT_OS_LINUX CHECK_REQUIRED_EXTENSION(GL_EXT_memory_object_fd); #endif #undef CHECK_REQUIRED_EXTENSION struct client_gl_xlib_compositor *c = U_TYPED_CALLOC(struct client_gl_xlib_compositor); // Move the app context to the struct. c->app_context = app_ctx; if (!client_gl_compositor_init( // &c->base, // xcn, // client_gl_context_begin_locked, // client_gl_context_end_locked, // client_gl_memobj_swapchain_create, // NULL)) { // free(c); return NULL; } c->base.base.base.destroy = client_gl_xlib_compositor_destroy; return c; }