The open source OpenXR runtime
at prediction-2 242 lines 6.8 kB view raw
1// Copyright 2019-2022, Collabora, Ltd. 2// SPDX-License-Identifier: BSL-1.0 3/*! 4 * @file 5 * @brief Win32 client side glue to compositor implementation. 6 * @author Rylie Pavlik <rylie.pavlik@collabora.com> 7 * @author Milan Jaros <milan.jaros@vsb.cz> 8 * @author Jakob Bornecrantz <jakob@collabora.com> 9 * @ingroup comp_client 10 */ 11 12#include <stdio.h> 13#include <stdlib.h> 14 15#include "client/comp_gl_client.h" 16#include "util/u_misc.h" 17#include "util/u_logging.h" 18 19#include "xrt/xrt_gfx_win32.h" 20 21#include "client/comp_gl_win32_client.h" 22#include "client/comp_gl_memobj_swapchain.h" 23 24#include "ogl/ogl_api.h" 25#include "ogl/wgl_api.h" 26 27/* 28 * 29 * OpenGL context helper. 30 * 31 */ 32 33static inline bool 34context_matches(const struct client_gl_context *a, const struct client_gl_context *b) 35{ 36 return a->hDC == b->hDC && a->hGLRC == b->hGLRC; 37} 38 39static inline void 40context_save_current(struct client_gl_context *current_ctx) 41{ 42 current_ctx->hDC = wglGetCurrentDC(); 43 current_ctx->hGLRC = wglGetCurrentContext(); 44} 45 46static inline bool 47context_make_current(const struct client_gl_context *ctx_to_make_current) 48{ 49 if (wglMakeCurrent(ctx_to_make_current->hDC, ctx_to_make_current->hGLRC)) { 50 return true; 51 } 52 return false; 53} 54 55/*! 56 * Down-cast helper. 57 * 58 * @private @memberof client_gl_win32_compositor 59 */ 60static inline struct client_gl_win32_compositor * 61client_gl_win32_compositor(struct xrt_compositor *xc) 62{ 63 return (struct client_gl_win32_compositor *)xc; 64} 65 66static void 67client_gl_win32_compositor_destroy(struct xrt_compositor *xc) 68{ 69 struct client_gl_win32_compositor *c = client_gl_win32_compositor(xc); 70 71 client_gl_compositor_fini(&c->base); 72 73 FreeLibrary(c->opengl); 74 c->opengl = NULL; 75 76 free(c); 77} 78 79static xrt_result_t 80client_gl_context_begin_locked(struct xrt_compositor *xc, enum client_gl_context_reason reason) 81{ 82 struct client_gl_win32_compositor *c = client_gl_win32_compositor(xc); 83 84 struct client_gl_context *app_ctx = &c->app_context; 85 86 context_save_current(&c->temp_context); 87 88 bool need_make_current = !context_matches(&c->temp_context, app_ctx); 89 90 U_LOG_T("GL Context begin: need makeCurrent: %d (current %p -> app %p)", need_make_current, 91 (void *)c->temp_context.hGLRC, (void *)app_ctx->hGLRC); 92 93 if (need_make_current && !context_make_current(app_ctx)) { 94 U_LOG_E("Failed to make WGL context current"); 95 // No need to restore on failure. 96 return XRT_ERROR_OPENGL; 97 } 98 99 return XRT_SUCCESS; 100} 101 102static void 103client_gl_context_end_locked(struct xrt_compositor *xc, enum client_gl_context_reason reason) 104{ 105 struct client_gl_win32_compositor *c = client_gl_win32_compositor(xc); 106 107 struct client_gl_context *app_ctx = &c->app_context; 108 109 struct client_gl_context *current_wgl_context = &c->temp_context; 110 111 bool need_make_current = !context_matches(&c->temp_context, app_ctx); 112 113 U_LOG_T("GL Context end: need makeCurrent: %d (app %p -> current %p)", need_make_current, 114 (void *)app_ctx->hGLRC, (void *)c->temp_context.hGLRC); 115 116 if (need_make_current && !context_make_current(current_wgl_context)) { 117 U_LOG_E("Failed to make old WGL context current!"); 118 // fall through to os_mutex_unlock even if we didn't succeed in restoring the context 119 } 120} 121 122static GLADapiproc 123client_gl_get_proc_addr(void *userptr, const char *name) 124{ 125 GLADapiproc ret = (GLADapiproc)wglGetProcAddress(name); 126 if (ret == NULL) { 127 ret = (GLADapiproc)GetProcAddress((HMODULE)userptr, name); 128 } 129 return ret; 130} 131 132struct client_gl_win32_compositor * 133client_gl_win32_compositor_create(struct xrt_compositor_native *xcn, void *hDC, void *hGLRC) 134{ 135 // Save old GLX context. 136 struct client_gl_context current_ctx; 137 context_save_current(&current_ctx); 138 139 // The context and drawables given from the app. 140 struct client_gl_context app_ctx = { 141 .hDC = hDC, 142 .hGLRC = hGLRC, 143 }; 144 145 146 /* 147 * Make given context current if needed. 148 */ 149 150 bool need_make_current = !context_matches(&current_ctx, &app_ctx); 151 152 if (need_make_current && !context_make_current(&app_ctx)) { 153 U_LOG_E("Failed to make WGL context current"); 154 // No need to restore on failure. 155 return NULL; 156 } 157 158 159 /* 160 * Load functions. 161 */ 162 163 HMODULE opengl = LoadLibraryW(L"opengl32.dll"); 164 165 int wgl_result = gladLoadWGLUserPtr(hDC, client_gl_get_proc_addr, opengl); 166 int gl_result = gladLoadGLUserPtr(client_gl_get_proc_addr, opengl); 167 168 if (glGetString != NULL) { 169 U_LOG_D( // 170 "OpenGL context:" // 171 "\n\tGL_VERSION: %s" // 172 "\n\tGL_RENDERER: %s" // 173 "\n\tGL_VENDOR: %s", // 174 glGetString(GL_VERSION), // 175 glGetString(GL_RENDERER), // 176 glGetString(GL_VENDOR)); // 177 } 178 179 180 /* 181 * Return to app context. 182 */ 183 184 if (need_make_current && !context_make_current(&current_ctx)) { 185 U_LOG_E("Failed to make old WGL context current!"); 186 } 187 188 189 /* 190 * Checking of context. 191 */ 192 193 // Only do error checking here. 194 if (wgl_result == 0 || gl_result == 0) { 195 U_LOG_E("Failed to load GLAD functions gladLoadWGL: 0x%08x, gladLoadGL: 0x%08x", wgl_result, gl_result); 196 FreeLibrary(opengl); 197 return NULL; 198 } 199 200#define CHECK_REQUIRED_EXTENSION(EXT) \ 201 do { \ 202 if (!GLAD_GL_##EXT) { \ 203 U_LOG_E("%s - Required OpenGL extension GL_" #EXT " not available", __func__); \ 204 FreeLibrary(opengl); \ 205 return NULL; \ 206 } \ 207 } while (0) 208 209 CHECK_REQUIRED_EXTENSION(EXT_memory_object); // why is this failing? the gpuinfo.org tool says I have it. 210 CHECK_REQUIRED_EXTENSION(EXT_memory_object_win32); 211 212#undef CHECK_REQUIRED_EXTENSION 213 214 215 /* 216 * Checking complete, create client compositor here. 217 */ 218 219 struct client_gl_win32_compositor *c = U_TYPED_CALLOC(struct client_gl_win32_compositor); 220 221 // Move the app context to the struct. 222 c->app_context = app_ctx; 223 // Same for the opengl library handle 224 c->opengl = opengl; 225 226 if (!client_gl_compositor_init( // 227 &c->base, // 228 xcn, // 229 client_gl_context_begin_locked, // 230 client_gl_context_end_locked, // 231 client_gl_memobj_swapchain_create, // 232 NULL)) { // 233 U_LOG_E("Failed to init parent GL client compositor!"); 234 FreeLibrary(opengl); 235 free(c); 236 return NULL; 237 } 238 239 c->base.base.base.destroy = client_gl_win32_compositor_destroy; 240 241 return c; 242}