The open source OpenXR runtime
at prediction-2 209 lines 6.6 kB view raw
1// Copyright 2019-2022, Collabora, Ltd. 2// SPDX-License-Identifier: BSL-1.0 3/*! 4 * @file 5 * @brief Xlib client side glue to compositor implementation. 6 * @author Jakob Bornecrantz <jakob@collabora.com> 7 * @ingroup comp_client 8 */ 9 10#include <stdio.h> 11#include <stdlib.h> 12 13#include "util/u_misc.h" 14#include "util/u_logging.h" 15 16#include "xrt/xrt_gfx_xlib.h" 17 18#include "client/comp_gl_xlib_client.h" 19#include "client/comp_gl_memobj_swapchain.h" 20 21#include "ogl/ogl_api.h" 22#include "ogl/glx_api.h" 23 24/* 25 * 26 * OpenGL context helper. 27 * 28 */ 29 30static inline bool 31context_matches(const struct client_gl_context *a, const struct client_gl_context *b) 32{ 33 return a->ctx == b->ctx && a->draw == b->draw && a->read == b->read && a->dpy == b->dpy; 34} 35 36static inline void 37context_save_current(struct client_gl_context *current_ctx) 38{ 39 current_ctx->dpy = glXGetCurrentDisplay(); 40 current_ctx->ctx = glXGetCurrentContext(); 41 current_ctx->read = glXGetCurrentDrawable(); 42 current_ctx->draw = glXGetCurrentReadDrawable(); 43} 44 45static inline bool 46context_make_current(const struct client_gl_context *ctx_to_make_current) 47{ 48 if (glXMakeContextCurrent(ctx_to_make_current->dpy, ctx_to_make_current->draw, ctx_to_make_current->read, 49 ctx_to_make_current->ctx)) { 50 return true; 51 } 52 return false; 53} 54 55/*! 56 * Down-cast helper. 57 * 58 * @private @memberof client_gl_xlib_compositor 59 */ 60static inline struct client_gl_xlib_compositor * 61client_gl_xlib_compositor(struct xrt_compositor *xc) 62{ 63 return (struct client_gl_xlib_compositor *)xc; 64} 65 66static void 67client_gl_xlib_compositor_destroy(struct xrt_compositor *xc) 68{ 69 struct client_gl_xlib_compositor *c = client_gl_xlib_compositor(xc); 70 71 client_gl_compositor_fini(&c->base); 72 73 free(c); 74} 75 76static xrt_result_t 77client_gl_context_begin_locked(struct xrt_compositor *xc, enum client_gl_context_reason reason) 78{ 79 struct client_gl_xlib_compositor *c = client_gl_xlib_compositor(xc); 80 81 struct client_gl_context *app_ctx = &c->app_context; 82 83 context_save_current(&c->temp_context); 84 85 bool need_make_current = !context_matches(&c->temp_context, app_ctx); 86 87 U_LOG_T("GL Context begin: need makeCurrent: %d (current %p -> app %p)", need_make_current, 88 (void *)c->temp_context.ctx, (void *)app_ctx->ctx); 89 90 if (need_make_current && !context_make_current(app_ctx)) { 91 U_LOG_E("Failed to make GLX context current"); 92 // No need to restore on failure. 93 return XRT_ERROR_OPENGL; 94 } 95 96 return XRT_SUCCESS; 97} 98 99static void 100client_gl_context_end_locked(struct xrt_compositor *xc, enum client_gl_context_reason reason) 101{ 102 struct client_gl_xlib_compositor *c = client_gl_xlib_compositor(xc); 103 104 struct client_gl_context *app_ctx = &c->app_context; 105 106 struct client_gl_context *current_glx_context = &c->temp_context; 107 108 bool need_make_current = !context_matches(&c->temp_context, app_ctx); 109 110 U_LOG_T("GL Context end: need makeCurrent: %d (app %p -> current %p)", need_make_current, (void *)app_ctx->ctx, 111 (void *)c->temp_context.ctx); 112 113 if (need_make_current && !context_make_current(current_glx_context)) { 114 U_LOG_E("Failed to make old GLX context current! (%p, %#lx, %#lx, %p)", 115 (void *)current_glx_context->dpy, (unsigned long)current_glx_context->draw, 116 (unsigned long)current_glx_context->read, (void *)current_glx_context->ctx); 117 // fall through to os_mutex_unlock even if we didn't succeed in restoring the context 118 } 119} 120 121typedef void (*void_ptr_func)(void); 122 123#ifdef __cplusplus 124extern "C" 125#endif 126 void_ptr_func 127 glXGetProcAddress(const char *procName); 128 129struct client_gl_xlib_compositor * 130client_gl_xlib_compositor_create(struct xrt_compositor_native *xcn, 131 Display *xDisplay, 132 uint32_t visualid, 133 GLXFBConfig glxFBConfig, 134 GLXDrawable glxDrawable, 135 GLXContext glxContext) 136{ 137 // We're not using any GLX extensions so screen number is irrelevant. 138 gladLoadGLX(xDisplay, 0, glXGetProcAddress); 139 140 // Save old GLX context. 141 struct client_gl_context current_ctx; 142 context_save_current(&current_ctx); 143 144 // The context and drawables given from the app. 145 struct client_gl_context app_ctx = { 146 .dpy = xDisplay, 147 .ctx = glxContext, 148 .draw = glxDrawable, 149 .read = glxDrawable, 150 }; 151 152 153 bool need_make_current = !context_matches(&current_ctx, &app_ctx); 154 155 U_LOG_T("GL Compositor create: need makeCurrent: %d (current %p -> app %p)", need_make_current, 156 (void *)current_ctx.ctx, (void *)app_ctx.ctx); 157 158 if (need_make_current && !context_make_current(&app_ctx)) { 159 U_LOG_E("Failed to make GLX context current"); 160 // No need to restore on failure. 161 return NULL; 162 } 163 164 gladLoadGL(glXGetProcAddress); 165 166 167 U_LOG_T("GL Compositor create: need makeCurrent: %d (app %p -> current %p)", need_make_current, 168 (void *)app_ctx.ctx, (void *)current_ctx.ctx); 169 170 if (need_make_current && !context_make_current(&current_ctx)) { 171 U_LOG_E("Failed to make old GLX context current! (%p, %#lx, %#lx, %p)", (void *)current_ctx.dpy, 172 (unsigned long)current_ctx.draw, (unsigned long)current_ctx.read, (void *)current_ctx.ctx); 173 } 174 175#define CHECK_REQUIRED_EXTENSION(EXT) \ 176 do { \ 177 if (!GLAD_##EXT) { \ 178 U_LOG_E("%s - Required OpenGL extension " #EXT " not available", __func__); \ 179 return NULL; \ 180 } \ 181 } while (0) 182 183 CHECK_REQUIRED_EXTENSION(GL_EXT_memory_object); 184#ifdef XRT_OS_LINUX 185 CHECK_REQUIRED_EXTENSION(GL_EXT_memory_object_fd); 186#endif 187 188#undef CHECK_REQUIRED_EXTENSION 189 190 struct client_gl_xlib_compositor *c = U_TYPED_CALLOC(struct client_gl_xlib_compositor); 191 192 // Move the app context to the struct. 193 c->app_context = app_ctx; 194 195 if (!client_gl_compositor_init( // 196 &c->base, // 197 xcn, // 198 client_gl_context_begin_locked, // 199 client_gl_context_end_locked, // 200 client_gl_memobj_swapchain_create, // 201 NULL)) { // 202 free(c); 203 return NULL; 204 } 205 206 c->base.base.base.destroy = client_gl_xlib_compositor_destroy; 207 208 return c; 209}