diff --git a/gfx/drivers_context/wgl_ctx.c b/gfx/drivers_context/wgl_ctx.c index 35d41adf2c..151725fbdf 100644 --- a/gfx/drivers_context/wgl_ctx.c +++ b/gfx/drivers_context/wgl_ctx.c @@ -242,7 +242,7 @@ static void create_gl_context(HWND hwnd, bool *quit) if (core_context || debug) { - int attribs[16]; + int attribs[16] = {0}; int *aptr = attribs; if (core_context) @@ -274,29 +274,71 @@ static void create_gl_context(HWND hwnd, bool *quit) if (!pcreate_context) pcreate_context = (wglCreateContextAttribsProc)gfx_ctx_wgl_get_proc_address("wglCreateContextAttribsARB"); + /* In order to support the core info "required_hw_api" field correctly, we should try to init the highest available + * version GL context possible. This means trying successively lower versions until it works, because GL has + * no facility for determining the highest possible supported version. + */ if (pcreate_context) { - HGLRC context = pcreate_context(win32_hdc, NULL, attribs); + int i; + int gl_versions[][2] = {{4, 6}, {4, 3}, {4, 0}, {3, 3}, {3, 2}, {0, 0}}; + int gl_version_rows = ARRAY_SIZE(gl_versions); + int (*versions)[2]; + int version_rows = 0; + HGLRC context = NULL; - if (context) - { - wglMakeCurrent(NULL, NULL); - wglDeleteContext(win32_hrc); - win32_hrc = context; - if (!wglMakeCurrent(win32_hdc, win32_hrc)) - *quit = true; - } - else - RARCH_ERR("[WGL]: Failed to create core context. Falling back to legacy context.\n"); + versions = gl_versions; + version_rows = gl_version_rows; - if (win32_use_hw_ctx) + /* try each version, starting with the highest first */ + for (i = 0; i < version_rows; i++) { - win32_hw_hrc = pcreate_context(win32_hdc, context, attribs); - if (!win32_hw_hrc) + if (versions[i][0] == 0 && versions[i][1] == 0) { - RARCH_ERR("[WGL]: Failed to create shared context.\n"); - *quit = true; + /* use the actual requested version last */ + versions[i][0] = win32_major; + versions[i][1] = win32_minor; } + + attribs[1] = versions[i][0]; + attribs[3] = versions[i][1]; + + context = pcreate_context(win32_hdc, NULL, attribs); + + if (context) + { + wglMakeCurrent(NULL, NULL); + wglDeleteContext(win32_hrc); + win32_hrc = context; + + if (!wglMakeCurrent(win32_hdc, win32_hrc)) + { + *quit = true; + break; + } + } + else + continue; + + if (win32_use_hw_ctx) + { + win32_hw_hrc = pcreate_context(win32_hdc, context, attribs); + + if (!win32_hw_hrc) + { + RARCH_ERR("[WGL]: Failed to create shared context.\n"); + *quit = true; + break; + } + } + + break; + } + + if (!context) + { + RARCH_ERR("[WGL]: Failed to create core context. Falling back to legacy context.\n"); + *quit = true; } } else @@ -725,7 +767,7 @@ static bool gfx_ctx_wgl_suppress_screensaver(void *data, bool enable) } static bool gfx_ctx_wgl_get_metrics(void *data, - enum display_metric_types type, float *value) + enum display_metric_types type, float *value) { return win32_get_metrics(data, type, value); } diff --git a/gfx/drivers_context/x_ctx.c b/gfx/drivers_context/x_ctx.c index 4916f651e0..c6ae94ea2a 100644 --- a/gfx/drivers_context/x_ctx.c +++ b/gfx/drivers_context/x_ctx.c @@ -176,6 +176,19 @@ static int GLXExtensionSupported(Display *dpy, const char *extension) } #endif +static int x_gl_version_error_handler(Display *dpy, XErrorEvent *event) +{ + (void)dpy; + + if (event->error_code == BadMatch && event->request_code == 151 && event->minor_code == 34) + { + RARCH_WARN("[GLX]: Version %d.%d not supported, trying a lower version.\n", g_major, g_minor); + return 0; + } + + exit(1); +} + static int x_nul_handler(Display *dpy, XErrorEvent *event) { (void)dpy; @@ -816,7 +829,7 @@ static bool gfx_ctx_x_set_video_mode(void *data, { if (x->g_core_es || x->g_debug) { - int attribs[16]; + int attribs[16] = {0}; int *aptr = attribs; if (x->g_core_es) @@ -848,18 +861,75 @@ static bool gfx_ctx_x_set_video_mode(void *data, } *aptr = None; - x->g_ctx = glx_create_context_attribs(g_x11_dpy, - x->g_fbc, NULL, True, attribs); - if (x->g_use_hw_ctx) + /* silently ignore failures when requesting GL versions that are too high */ + old_handler = XSetErrorHandler(x_gl_version_error_handler); + + /* In order to support the core info "required_hw_api" field correctly, we should try to init the highest available + * version GL context possible. This means trying successively lower versions until it works, because GL has + * no facility for determining the highest possible supported version. + */ { - RARCH_LOG("[GLX]: Creating shared HW context.\n"); - x->g_hw_ctx = glx_create_context_attribs(g_x11_dpy, - x->g_fbc, x->g_ctx, True, attribs); + int i; + int gl_versions[][2] = {{4, 6}, {4, 3}, {4, 0}, {3, 3}, {3, 2}, {0, 0}}; +#ifdef HAVE_OPENGLES3 + int gles_versions[][2] = {{3, 2}, {3, 1}, {3, 0}, {0, 0}}; +#else + int gles_versions[][2] = {{2, 1}, {2, 0}, {1, 1}, {1, 0}, {0, 0}}; +#endif + int gl_version_rows = ARRAY_SIZE(gl_versions); + int gles_version_rows = ARRAY_SIZE(gles_versions); + int (*versions)[2]; + int version_rows = 0; - if (!x->g_hw_ctx) - RARCH_ERR("[GLX]: Failed to create new shared context.\n"); + if (x_api == GFX_CTX_OPENGL_API) + { + versions = gl_versions; + version_rows = gl_version_rows; + } + else if (x_api == GFX_CTX_OPENGL_ES_API) + { + versions = gles_versions; + version_rows = gles_version_rows; + } + + /* try each version, starting with the highest first */ + for (i = 0; i < version_rows; i++) + { + if (versions[i][0] == 0 && versions[i][1] == 0) + { + /* use the actual requested version last */ + versions[i][0] = g_major; + versions[i][1] = g_minor; + } + + attribs[1] = versions[i][0]; + attribs[3] = versions[i][1]; + + x->g_ctx = glx_create_context_attribs(g_x11_dpy, + x->g_fbc, NULL, True, attribs); + + if (!x->g_ctx) + continue; + + if (x->g_use_hw_ctx) + { + RARCH_LOG("[GLX]: Creating shared HW context.\n"); + x->g_hw_ctx = glx_create_context_attribs(g_x11_dpy, + x->g_fbc, x->g_ctx, True, attribs); + + if (!x->g_hw_ctx) + RARCH_ERR("[GLX]: Failed to create new shared context.\n"); + } + + g_major = versions[i][0]; + g_minor = versions[i][1]; + + break; + } } + + XSetErrorHandler(old_handler); } else { diff --git a/tasks/task_content.c b/tasks/task_content.c index 00326d5e6d..00da8a53d0 100644 --- a/tasks/task_content.c +++ b/tasks/task_content.c @@ -584,33 +584,46 @@ static void content_load_init_wrap( **/ static bool content_load(content_ctx_info_t *info) { - unsigned i; + unsigned i = 0; int rarch_argc = 0; char *rarch_argv[MAX_ARGS] = {NULL}; char *argv_copy [MAX_ARGS] = {NULL}; char **rarch_argv_ptr = (char**)info->argv; int *rarch_argc_ptr = (int*)&info->argc; - struct rarch_main_wrap *wrap_args; - core_info_t core_info = {0}; - core_info_list_t *core_info_list = NULL; + struct rarch_main_wrap *wrap_args = NULL; + core_info_t core_info = {0}; + core_info_list_t *core_info_list = NULL; + gfx_ctx_ident_t ident_info = {0}; - core_info_get_list(&core_info_list); + video_context_driver_get_ident(&ident_info); - if (core_info_list) + /* only check for supported hw api on X11/GLX and Windows since that is where it is currently implemented */ +#ifdef HAVE_X11 + if (!string_is_empty(ident_info.ident) && string_is_equal(ident_info.ident, "x")) +#else +#if defined(_WIN32) && !defined(_XBOX) + if (!string_is_empty(ident_info.ident) && string_is_equal(ident_info.ident, "wgl")) +#endif +#endif { - if (core_info_list_get_info(core_info_list, &core_info, path_get(RARCH_PATH_CORE))) + core_info_get_list(&core_info_list); + + if (core_info_list) { - if (!core_info_hw_api_supported(&core_info)) + if (core_info_list_get_info(core_info_list, &core_info, path_get(RARCH_PATH_CORE))) { - RARCH_ERR("This core is not compatible with the current video driver.\n"); - runloop_msg_queue_push( - msg_hash_to_str(MSG_INCOMPATIBLE_CORE_FOR_VIDEO_DRIVER), - 100, 250, true, NULL, - MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); - return false; + if (!core_info_hw_api_supported(&core_info)) + { + RARCH_ERR("This core is not compatible with the current video driver.\n"); + runloop_msg_queue_push( + msg_hash_to_str(MSG_INCOMPATIBLE_CORE_FOR_VIDEO_DRIVER), + 100, 250, true, NULL, + MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); + return false; + } + else + RARCH_LOG("This core is compatible with the current video driver.\n"); } - else - RARCH_LOG("This core is compatible with the current video driver.\n"); } }