The open source OpenXR runtime
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

c/client: Improve creation of shared EGL context

To create a shared context we need to provide the same options (usually)
when the original context was created. But not all of those options can be
retrieved from an already created context.

This commit adds more ways to create a shared EGL context by trying multiple times.

Co-authored-by: korejan <korcan_h@hotmail.com>
Part-of: <https://gitlab.freedesktop.org/monado/monado/-/merge_requests/2599>

authored by

lightofmysoul
korejan
and committed by
Marge Bot
19335a8a 719bcd4b

+189 -19
+189 -19
src/xrt/compositor/client/comp_egl_client.c
··· 200 200 #endif 201 201 } 202 202 203 + struct egl_attrs 204 + { 205 + EGLint api; 206 + EGLint major; 207 + EGLint minor; 208 + bool compat_profile; // Only for desktop OpenGL 209 + bool robust; 210 + bool lose_context_on_reset; 211 + EGLint image_prio; 212 + }; 213 + 214 + static int 215 + make_egl_attrs(EGLint *attrs, size_t len, const struct egl_attrs *params) 216 + { 217 + if (params->api != EGL_OPENGL_API && params->api != EGL_OPENGL_ES_API) { 218 + U_LOG_E("make_egl_attrs: only OpenGL and OpenGL ES is supported"); 219 + return -1; 220 + } 221 + 222 + size_t attrc = 0; 223 + 224 + #define ADD_ATTR(v) \ 225 + do { \ 226 + if (!len) { \ 227 + return -1; \ 228 + } \ 229 + len--; \ 230 + attrs[attrc++] = (v); \ 231 + } while (0) 232 + 233 + #define ADD_PAIR(k, v) \ 234 + do { \ 235 + ADD_ATTR(k); \ 236 + ADD_ATTR(v); \ 237 + } while (0) 238 + 239 + EGLint khr_flags = 0; 240 + 241 + ADD_PAIR(EGL_CONTEXT_MAJOR_VERSION, params->major); 242 + ADD_PAIR(EGL_CONTEXT_MINOR_VERSION, params->minor); 243 + 244 + if (params->api == EGL_OPENGL_API && params->compat_profile) { 245 + ADD_PAIR(EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT); 246 + } 247 + 248 + if (params->robust) { 249 + if (params->api == EGL_OPENGL_ES_API) { 250 + ADD_PAIR(EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT, EGL_TRUE); 251 + } else if (params->api == EGL_OPENGL_API) { 252 + khr_flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR; 253 + } 254 + } 255 + 256 + if (params->lose_context_on_reset) { 257 + if (params->api == EGL_OPENGL_ES_API) { 258 + ADD_PAIR(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT, EGL_LOSE_CONTEXT_ON_RESET_EXT); 259 + } else if (params->api == EGL_OPENGL_API) { 260 + ADD_PAIR(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, EGL_LOSE_CONTEXT_ON_RESET_KHR); 261 + } 262 + } 263 + 264 + if (params->api == EGL_OPENGL_API && khr_flags) { 265 + ADD_PAIR(EGL_CONTEXT_FLAGS_KHR, khr_flags); 266 + } 267 + 268 + if (params->image_prio && params->image_prio != EGL_CONTEXT_PRIORITY_MEDIUM_IMG) { 269 + ADD_PAIR(EGL_CONTEXT_PRIORITY_LEVEL_IMG, params->image_prio); 270 + } 271 + 272 + ADD_ATTR(EGL_NONE); 273 + 274 + #undef ADD_ATTR 275 + #undef ADD_PAIR 276 + 277 + return attrc; 278 + } 279 + 280 + static void 281 + print_egl_attrs(EGLint *attrs) 282 + { 283 + int i = 0; 284 + EGL_DEBUG("egl attributes:"); 285 + do { 286 + EGL_DEBUG("> attr: %d 0x%x", i, attrs[i]); 287 + } while (attrs[i++] != EGL_NONE); 288 + } 289 + 290 + static EGLint 291 + get_reset_strategy(EGLint api_type, EGLDisplay display, EGLContext app_context) 292 + { 293 + EGLint ext; 294 + switch (api_type) { 295 + case EGL_OPENGL_ES_API: ext = EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT; break; 296 + case EGL_OPENGL_API: 297 + /* This is non-standard, but supported in mesa */ 298 + ext = EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR; 299 + break; 300 + default: return 0; 301 + } 302 + 303 + EGLint strategy = 0; 304 + if (!eglQueryContext(display, app_context, ext, &strategy)) { 305 + return 0; 306 + } 307 + return strategy; 308 + } 309 + 203 310 static xrt_result_t 204 311 create_context( 205 312 EGLDisplay display, EGLConfig config, EGLContext app_context, EGLint api_type, EGLContext *out_our_context) ··· 207 314 EGLint old_api_type = eglQueryAPI(); 208 315 209 316 eglBindAPI(api_type); 317 + const char *api_string = 318 + api_type == EGL_OPENGL_API ? "opengl" : (api_type == EGL_OPENGL_ES_API ? "opengl_es" : ""); 210 319 211 - size_t attrc = 0; 212 - EGLint attrs[9] = {0}; 213 - 214 - attrs[attrc++] = EGL_CONTEXT_MAJOR_VERSION; 215 - attrs[attrc++] = 3; 216 320 // Panfrost only supports 3.1 217 - attrs[attrc++] = EGL_CONTEXT_MINOR_VERSION; 218 - attrs[attrc++] = 1; 321 + const EGLint major = 3; 322 + const EGLint minor = 1; 219 323 220 - if (api_type == EGL_OPENGL_API) { 221 - attrs[attrc++] = EGL_CONTEXT_OPENGL_PROFILE_MASK; 222 - attrs[attrc++] = EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT; 324 + EGLint image_prio; 325 + if (!eglQueryContext(display, app_context, EGL_CONTEXT_PRIORITY_LEVEL_IMG, &image_prio)) { 326 + image_prio = 0; 223 327 } 224 328 225 - EGLint strategy; 226 - if (api_type == EGL_OPENGL_ES_API && 227 - eglQueryContext(display, app_context, EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT, &strategy)) { 228 - attrs[attrc++] = EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT; 229 - attrs[attrc++] = strategy; 329 + const size_t attrs_len = 21; 330 + EGLint attrs[4][attrs_len]; 331 + int attrc = 0; 332 + 333 + struct egl_attrs build_attrs = { 334 + .api = api_type, 335 + .major = major, 336 + .minor = minor, 337 + .compat_profile = true, 338 + .image_prio = image_prio, 339 + }; 340 + 341 + /* If the source context was created with robust and/or lose notify enabled, 342 + * then we need to enable it too or we get EGL_BAD_MATCH. 343 + * 344 + * Problems with those options: 345 + * 1. Different way to activate them for OpenGL and OpenGL ES. 346 + * 2. No standard way to know if the options were used to create the original context. 347 + * (with an exception for OpenGL ES) 348 + * 349 + * So, the most reliable way to create our shared context is to try all those combinations... 350 + */ 351 + EGLint reset_strategy = get_reset_strategy(api_type, display, app_context); 352 + EGL_DEBUG("Current reset strategy (%s): 0x%x", api_string, reset_strategy); 353 + if (reset_strategy) { 354 + build_attrs.lose_context_on_reset = (reset_strategy == EGL_LOSE_CONTEXT_ON_RESET); 355 + 356 + if (make_egl_attrs(attrs[attrc++], attrs_len, &build_attrs) == -1) { 357 + return XRT_ERROR_OPENGL; 358 + } 359 + 360 + build_attrs.robust = true; 361 + if (make_egl_attrs(attrs[attrc++], attrs_len, &build_attrs) == -1) { 362 + return XRT_ERROR_OPENGL; 363 + } 364 + } else { 365 + /* Try context with all optional features disabled first */ 366 + if (make_egl_attrs(attrs[attrc++], attrs_len, &build_attrs) == -1) { 367 + return XRT_ERROR_OPENGL; 368 + } 369 + 370 + /* Then, try all combination of robustness and lose notification */ 371 + build_attrs.robust = false; 372 + build_attrs.lose_context_on_reset = true; 373 + if (make_egl_attrs(attrs[attrc++], attrs_len, &build_attrs) == -1) { 374 + return XRT_ERROR_OPENGL; 375 + } 376 + 377 + build_attrs.robust = true; 378 + build_attrs.lose_context_on_reset = false; 379 + if (make_egl_attrs(attrs[attrc++], attrs_len, &build_attrs) == -1) { 380 + return XRT_ERROR_OPENGL; 381 + } 382 + 383 + build_attrs.robust = true; 384 + build_attrs.lose_context_on_reset = true; 385 + if (make_egl_attrs(attrs[attrc++], attrs_len, &build_attrs) == -1) { 386 + return XRT_ERROR_OPENGL; 387 + } 230 388 } 231 389 232 - attrs[attrc++] = EGL_NONE; 233 - assert(attrc <= ARRAY_SIZE(attrs)); 390 + assert((unsigned)attrc <= ARRAY_SIZE(attrs)); 234 391 235 - EGLContext our_context = eglCreateContext(display, config, app_context, attrs); 392 + EGLContext our_context = EGL_NO_CONTEXT; 393 + const char *last_error = ""; 394 + for (int i = 0; i != attrc; i++) { 395 + our_context = eglCreateContext(display, config, app_context, attrs[i]); 396 + if (our_context != EGL_NO_CONTEXT) { 397 + EGL_DEBUG("eglCreateContext (%s): try %d, context created", api_string, i); 398 + print_egl_attrs(attrs[i]); 399 + break; 400 + } 401 + 402 + last_error = egl_error_str(eglGetError()); 403 + EGL_DEBUG("eglCreateContext (%s): try %d, %s", api_string, i, last_error); 404 + print_egl_attrs(attrs[i]); 405 + } 236 406 237 407 // Restore old API type. 238 408 if (old_api_type == EGL_NONE) { ··· 240 410 } 241 411 242 412 if (our_context == EGL_NO_CONTEXT) { 243 - EGL_ERROR("eglCreateContext: %s", egl_error_str(eglGetError())); 413 + EGL_ERROR("eglCreateContext (%s): %s", api_string, last_error); 244 414 return XRT_ERROR_OPENGL; 245 415 } 246 416