The open source OpenXR runtime
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(¤t_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(¤t_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(¤t_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}