From 61ab9249fc892962b676e3f1533c0bbedf4ba2e2 Mon Sep 17 00:00:00 2001 From: Brad Parker <cbparker@gmail.com> Date: Tue, 23 Jul 2019 22:44:45 -0400 Subject: [PATCH] add "required hw api" to core info files, block content loading if core is incompatible with current graphics API/version --- core_info.c | 293 +++++++++++++++++++++++++++++++++++++++- core_info.h | 7 + intl/msg_hash_ja.h | 4 + intl/msg_hash_us.h | 8 ++ menu/menu_displaylist.c | 12 ++ msg_hash.h | 2 + tasks/task_content.c | 26 +++- 7 files changed, 350 insertions(+), 2 deletions(-) diff --git a/core_info.c b/core_info.c index 2f41f85f91..3579014071 100644 --- a/core_info.c +++ b/core_info.c @@ -27,6 +27,7 @@ #include "config.h" #endif +#include "retroarch.h" #include "verbosity.h" #include "core_info.h" @@ -41,6 +42,16 @@ static const struct string_list *core_info_tmp_list = NULL; static core_info_t *core_info_current = NULL; static core_info_list_t *core_info_curr_list = NULL; +enum compare_op +{ + COMPARE_OP_EQUAL, + COMPARE_OP_NOT_EQUAL, + COMPARE_OP_LESS, + COMPARE_OP_LESS_EQUAL, + COMPARE_OP_GREATER, + COMPARE_OP_GREATER_EQUAL +}; + static void core_info_list_resolve_all_extensions( core_info_list_t *core_info_list) { @@ -163,6 +174,7 @@ static void core_info_list_free(core_info_list_t *core_info_list) free(info->categories); free(info->databases); free(info->notes); + free(info->required_hw_api); string_list_free(info->supported_extensions_list); string_list_free(info->authors_list); string_list_free(info->note_list); @@ -170,6 +182,7 @@ static void core_info_list_free(core_info_list_t *core_info_list) string_list_free(info->licenses_list); string_list_free(info->categories_list); string_list_free(info->databases_list); + string_list_free(info->required_hw_api_list); config_file_free((config_file_t*)info->config_data); for (j = 0; j < info->firmware_count; j++) @@ -420,6 +433,16 @@ static core_info_list_t *core_info_list_new(const char *path, tmp = NULL; } + if (config_get_string(conf, "required_hw_api", &tmp) + && !string_is_empty(tmp)) + { + core_info[i].required_hw_api = strdup(tmp); + core_info[i].required_hw_api_list = string_split(core_info[i].required_hw_api, "|"); + + free(tmp); + tmp = NULL; + } + if (tmp) free(tmp); tmp = NULL; @@ -460,7 +483,7 @@ static core_info_list_t *core_info_list_new(const char *path, * * Data in *info is invalidated when the * core_info_list is freed. */ -static bool core_info_list_get_info(core_info_list_t *core_info_list, +bool core_info_list_get_info(core_info_list_t *core_info_list, core_info_t *out_info, const char *path) { size_t i; @@ -1008,3 +1031,271 @@ void core_info_qsort(core_info_list_t *core_info_list, enum core_info_list_qsort return; } } + +static bool core_info_compare_api_version(int sys_major, int sys_minor, int major, int minor, enum compare_op op) +{ + switch (op) + { + case COMPARE_OP_EQUAL: + if (sys_major == major && sys_minor == minor) + return true; + break; + case COMPARE_OP_NOT_EQUAL: + if (!(sys_major == major && sys_minor == minor)) + return true; + break; + case COMPARE_OP_LESS: + if (sys_major < major || (sys_major == major && sys_minor < minor)) + return true; + break; + case COMPARE_OP_LESS_EQUAL: + if (sys_major < major || (sys_major == major && sys_minor <= minor)) + return true; + break; + case COMPARE_OP_GREATER: + if (sys_major > major || (sys_major == major && sys_minor > minor)) + return true; + break; + case COMPARE_OP_GREATER_EQUAL: + if (sys_major > major || (sys_major == major && sys_minor >= minor)) + return true; + break; + default: + break; + } + + return false; +} + +bool core_info_hw_api_supported(core_info_t *info) +{ + enum gfx_ctx_api sys_api; + gfx_ctx_flags_t sys_flags = {0}; + int i; + const char *sys_api_version_str = video_driver_get_gpu_api_version_string(); + int sys_api_version_major = 0; + int sys_api_version_minor = 0; + + enum api_parse_state + { + STATE_API_NAME, + STATE_API_COMPARE_OP, + STATE_API_VERSION + }; + + if (!info || !info->required_hw_api_list || info->required_hw_api_list->size == 0) + return true; + + sys_api = video_context_driver_get_api(); + video_context_driver_get_flags(&sys_flags); + + for (i = 0; i < info->required_hw_api_list->size; i++) + { + char api_str[32] = {0}; + char version[16] = {0}; + char major_str[16] = {0}; + char minor_str[16] = {0}; + const char *cur_api = info->required_hw_api_list->elems[i].data; + int api_pos = 0; + int major_str_pos = 0; + int minor_str_pos = 0; + int cur_api_len = 0; + int j = 0; + int major = 0; + int minor = 0; + bool found_major = false; + bool found_minor = false; + enum compare_op op = COMPARE_OP_GREATER_EQUAL; + enum api_parse_state state = STATE_API_NAME; + + if (string_is_empty(cur_api)) + continue; + + cur_api_len = strlen(cur_api); + + for (j = 0; j < cur_api_len; j++) + { + if (cur_api[j] == ' ') + continue; + + switch (state) + { + case STATE_API_NAME: + { + if (isupper(cur_api[j]) || islower(cur_api[j])) + api_str[api_pos++] = cur_api[j]; + else + { + j--; + state = STATE_API_COMPARE_OP; + break; + } + + break; + } + case STATE_API_COMPARE_OP: + { + if (j < cur_api_len - 1 && !(cur_api[j] >= '0' && cur_api[j] <= '9')) + { + if (cur_api[j] == '=' && cur_api[j + 1] == '=') + { + op = COMPARE_OP_EQUAL; + j++; + } + else if (cur_api[j] == '=') + { + op = COMPARE_OP_EQUAL; + } + else if (cur_api[j] == '!' && cur_api[j + 1] == '=') + { + op = COMPARE_OP_NOT_EQUAL; + j++; + } + else if (cur_api[j] == '<' && cur_api[j + 1] == '=') + { + op = COMPARE_OP_LESS_EQUAL; + j++; + } + else if (cur_api[j] == '>' && cur_api[j + 1] == '=') + { + op = COMPARE_OP_GREATER_EQUAL; + j++; + } + else if (cur_api[j] == '<') + { + op = COMPARE_OP_LESS; + } + else if (cur_api[j] == '>') + { + op = COMPARE_OP_GREATER; + } + } + + state = STATE_API_VERSION; + + break; + } + case STATE_API_VERSION: + { + if (!found_minor && cur_api[j] >= '0' && cur_api[j] <= '9' && cur_api[j] != '.') + { + found_major = true; + + if (major_str_pos < sizeof(major_str) - 1) + major_str[major_str_pos++] = cur_api[j]; + } + else if (found_major && found_minor && cur_api[j] >= '0' && cur_api[j] <= '9') + { + if (minor_str_pos < sizeof(minor_str) - 1) + minor_str[minor_str_pos++] = cur_api[j]; + } + else if (cur_api[j] == '.') + { + found_minor = true; + } + + break; + } + default: + break; + } + } + + sscanf(major_str, "%d", &major); + sscanf(minor_str, "%d", &minor); + snprintf(version, sizeof(version), "%d.%d", major, minor); +#if 0 + printf("Major: %d\n", major); + printf("Minor: %d\n", minor); + printf("API: %s\n", api_str); + printf("Version: %s\n", version); + fflush(stdout); +#endif + + if ((string_is_equal_noncase(api_str, "opengl") && sys_api == GFX_CTX_OPENGL_API) || + (string_is_equal_noncase(api_str, "openglcompat") && sys_api == GFX_CTX_OPENGL_API) || + (string_is_equal_noncase(api_str, "openglcompatibility") && sys_api == GFX_CTX_OPENGL_API)) + { + if (!(sys_flags.flags & (1 << GFX_CTX_FLAGS_GL_CORE_CONTEXT))) + { + /* system is running a core context while compat is requested */ + return false; + } + + sscanf(sys_api_version_str, "%d.%d", &sys_api_version_major, &sys_api_version_minor); + + if (core_info_compare_api_version(sys_api_version_major, sys_api_version_minor, major, minor, op)) + return true; + } + else if (string_is_equal_noncase(api_str, "openglcore") && sys_api == GFX_CTX_OPENGL_API) + { + sscanf(sys_api_version_str, "%d.%d", &sys_api_version_major, &sys_api_version_minor); + + if (core_info_compare_api_version(sys_api_version_major, sys_api_version_minor, major, minor, op)) + return true; + } + else if (string_is_equal_noncase(api_str, "opengles") && sys_api == GFX_CTX_OPENGL_ES_API) + { + sscanf(sys_api_version_str, "OpenGL ES %d.%d", &sys_api_version_major, &sys_api_version_minor); + + if (core_info_compare_api_version(sys_api_version_major, sys_api_version_minor, major, minor, op)) + return true; + } + else if (string_is_equal_noncase(api_str, "direct3d8") && sys_api == GFX_CTX_DIRECT3D8_API) + { + sys_api_version_major = 8; + sys_api_version_minor = 0; + + if (core_info_compare_api_version(sys_api_version_major, sys_api_version_minor, major, minor, op)) + return true; + } + else if (string_is_equal_noncase(api_str, "direct3d9") && sys_api == GFX_CTX_DIRECT3D9_API) + { + sys_api_version_major = 9; + sys_api_version_minor = 0; + + if (core_info_compare_api_version(sys_api_version_major, sys_api_version_minor, major, minor, op)) + return true; + } + else if (string_is_equal_noncase(api_str, "direct3d10") && sys_api == GFX_CTX_DIRECT3D10_API) + { + sys_api_version_major = 10; + sys_api_version_minor = 0; + + if (core_info_compare_api_version(sys_api_version_major, sys_api_version_minor, major, minor, op)) + return true; + } + else if (string_is_equal_noncase(api_str, "direct3d11") && sys_api == GFX_CTX_DIRECT3D11_API) + { + sys_api_version_major = 11; + sys_api_version_minor = 0; + + if (core_info_compare_api_version(sys_api_version_major, sys_api_version_minor, major, minor, op)) + return true; + } + else if (string_is_equal_noncase(api_str, "direct3d12") && sys_api == GFX_CTX_DIRECT3D12_API) + { + sys_api_version_major = 12; + sys_api_version_minor = 0; + + if (core_info_compare_api_version(sys_api_version_major, sys_api_version_minor, major, minor, op)) + return true; + } + else if (string_is_equal_noncase(api_str, "vulkan") && sys_api == GFX_CTX_VULKAN_API) + { + sscanf(sys_api_version_str, "%d.%d", &sys_api_version_major, &sys_api_version_minor); + + if (core_info_compare_api_version(sys_api_version_major, sys_api_version_minor, major, minor, op)) + return true; + } + else if (string_is_equal_noncase(api_str, "metal") && sys_api == GFX_CTX_METAL_API) + { + sscanf(sys_api_version_str, "%d.%d", &sys_api_version_major, &sys_api_version_minor); + + if (core_info_compare_api_version(sys_api_version_major, sys_api_version_minor, major, minor, op)) + return true; + } + } + + return false; +} diff --git a/core_info.h b/core_info.h index bee6035564..eb4c4a5463 100644 --- a/core_info.h +++ b/core_info.h @@ -55,6 +55,7 @@ typedef struct char *categories; char *databases; char *notes; + char *required_hw_api; struct string_list *categories_list; struct string_list *databases_list; struct string_list *note_list; @@ -62,6 +63,7 @@ typedef struct struct string_list *authors_list; struct string_list *permissions_list; struct string_list *licenses_list; + struct string_list *required_hw_api_list; core_info_firmware_t *firmware; void *userdata; } core_info_t; @@ -142,6 +144,11 @@ bool core_info_unsupported_content_path(const char *path); void core_info_qsort(core_info_list_t *core_info_list, enum core_info_list_qsort_type qsort_type); +bool core_info_list_get_info(core_info_list_t *core_info_list, + core_info_t *out_info, const char *path); + +bool core_info_hw_api_supported(core_info_t *info); + RETRO_END_DECLS #endif /* CORE_INFO_H_ */ diff --git a/intl/msg_hash_ja.h b/intl/msg_hash_ja.h index 327c7d7a6a..e1fba83d25 100644 --- a/intl/msg_hash_ja.h +++ b/intl/msg_hash_ja.h @@ -9027,3 +9027,7 @@ MSG_HASH( MENU_ENUM_SUBLABEL_DISC_INFORMATION, "挿入されたディスクの情報を表示します。" ) +MSG_HASH( + MSG_INCOMPATIBLE_CORE_FOR_VIDEO_DRIVER, + "このコアは設定されたビデオドライバに対応しません。" + ) diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index bfd918e650..ed13497a41 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -677,6 +677,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INFO_SYSTEM_NAME, "System name" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_CORE_INFO_REQUIRED_HW_API, + "Required graphics API" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_CORE_INPUT_REMAPPING_OPTIONS, "Controls" @@ -8975,3 +8979,7 @@ MSG_HASH( MENU_ENUM_SUBLABEL_DISC_INFORMATION, "View information about inserted media discs." ) +MSG_HASH( + MSG_INCOMPATIBLE_CORE_FOR_VIDEO_DRIVER, + "This core is not compatible with the current video driver." + ) diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index 645327801d..7ed9cbacfd 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -241,6 +241,18 @@ static int menu_displaylist_parse_core_info(menu_displaylist_info_t *info) MENU_ENUM_LABEL_CORE_INFO_ENTRY, MENU_SETTINGS_CORE_INFO_NONE, 0, 0); } + if (core_info->required_hw_api) + { + fill_pathname_noext(tmp, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_INFO_REQUIRED_HW_API), + ": ", + sizeof(tmp)); + string_list_join_concat(tmp, sizeof(tmp), + core_info->required_hw_api_list, ", "); + menu_entries_append_enum(info->list, tmp, "", + MENU_ENUM_LABEL_CORE_INFO_ENTRY, MENU_SETTINGS_CORE_INFO_NONE, 0, 0); + } + if (core_info->firmware_count > 0) { core_info_ctx_firmware_t firmware_info; diff --git a/msg_hash.h b/msg_hash.h index cad170904c..58c4060799 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -1914,6 +1914,7 @@ enum msg_hash_enums MENU_ENUM_LABEL_VALUE_CORE_INFO_LICENSES, MENU_ENUM_LABEL_VALUE_CORE_INFO_SUPPORTED_EXTENSIONS, MENU_ENUM_LABEL_VALUE_CORE_INFO_FIRMWARE, + MENU_ENUM_LABEL_VALUE_CORE_INFO_REQUIRED_HW_API, /* System information */ @@ -2446,6 +2447,7 @@ enum msg_hash_enums MSG_DISC_DUMP_FAILED_TO_READ_FROM_DRIVE, MSG_DISC_DUMP_FAILED_TO_WRITE_TO_DISK, MSG_NO_DISC_INSERTED, + MSG_INCOMPATIBLE_CORE_FOR_VIDEO_DRIVER, MSG_LAST }; diff --git a/tasks/task_content.c b/tasks/task_content.c index 06392dd37c..5bd97ba14f 100644 --- a/tasks/task_content.c +++ b/tasks/task_content.c @@ -590,7 +590,31 @@ static bool content_load(content_ctx_info_t *info) 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 = (struct rarch_main_wrap*) + struct rarch_main_wrap *wrap_args; + core_info_t core_info = {0}; + core_info_list_t *core_info_list = NULL; + + core_info_get_list(&core_info_list); + + if (core_info_list) + { + if (core_info_list_get_info(core_info_list, &core_info, path_get(RARCH_PATH_CORE))) + { + 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"); + } + } + + wrap_args = (struct rarch_main_wrap*) calloc(1, sizeof(*wrap_args)); if (!wrap_args)