diff --git a/audio/audio_driver.c b/audio/audio_driver.c index b7ff161681..e149e3f35c 100644 --- a/audio/audio_driver.c +++ b/audio/audio_driver.c @@ -1801,3 +1801,11 @@ bool *audio_get_bool_ptr(enum audio_action action) return NULL; } + +const char* audio_driver_get_ident(void) +{ + if (!current_audio) + return NULL; + + return current_audio->ident; +} diff --git a/audio/audio_driver.h b/audio/audio_driver.h index 277350125e..624ca6a453 100644 --- a/audio/audio_driver.h +++ b/audio/audio_driver.h @@ -282,6 +282,8 @@ bool compute_audio_buffer_statistics(audio_statistics_t *stats); void audio_driver_load_menu_sounds(void); +const char* audio_driver_get_ident(void); + extern audio_driver_t audio_rsound; extern audio_driver_t audio_audioio; extern audio_driver_t audio_oss; diff --git a/gfx/common/d3d10_common.h b/gfx/common/d3d10_common.h index 112fdd4b41..3431244fd3 100644 --- a/gfx/common/d3d10_common.h +++ b/gfx/common/d3d10_common.h @@ -1154,6 +1154,12 @@ typedef struct bool resize_render_targets; bool init_history; d3d10_shader_t shaders[GFX_MAX_SHADERS]; +#ifdef __WINRT__ + DXGIFactory2 factory; +#else + DXGIFactory factory; +#endif + DXGIAdapter adapter; struct { diff --git a/gfx/common/d3d11_common.h b/gfx/common/d3d11_common.h index db6254e8c1..a88336dfc7 100644 --- a/gfx/common/d3d11_common.h +++ b/gfx/common/d3d11_common.h @@ -2523,6 +2523,12 @@ typedef struct bool resize_render_targets; bool init_history; d3d11_shader_t shaders[GFX_MAX_SHADERS]; +#ifdef __WINRT__ + DXGIFactory2 factory; +#else + DXGIFactory factory; +#endif + DXGIAdapter adapter; struct { diff --git a/gfx/common/d3d12_common.c b/gfx/common/d3d12_common.c index c89c4bf732..f221d8ca58 100644 --- a/gfx/common/d3d12_common.c +++ b/gfx/common/d3d12_common.c @@ -14,6 +14,7 @@ */ #define CINTERFACE +#define COBJMACROS #include @@ -28,6 +29,9 @@ #include #endif +#include +#include + #ifdef __MINGW32__ /* clang-format off */ #ifdef __cplusplus @@ -180,7 +184,20 @@ bool d3d12_init_base(d3d12_video_t* d3d12) #endif if (SUCCEEDED(D3D12CreateDevice_(d3d12->adapter, D3D_FEATURE_LEVEL_11_0, &d3d12->device))) + { + char str[128]; + DXGI_ADAPTER_DESC desc = {0}; + + IDXGIAdapter_GetDesc(d3d12->adapter, &desc); + + utf16_to_char_string(desc.Description, str, sizeof(str)); + + RARCH_LOG("[D3D12]: Using GPU: %s\n", str); + + video_driver_set_gpu_device_string(str); + break; + } Release(d3d12->adapter); } diff --git a/gfx/common/vulkan_common.c b/gfx/common/vulkan_common.c index 9de79fb7f0..95faa57fa8 100644 --- a/gfx/common/vulkan_common.c +++ b/gfx/common/vulkan_common.c @@ -1738,6 +1738,44 @@ static bool vulkan_context_init_device(gfx_ctx_vulkan_data_t *vk) RARCH_LOG("[Vulkan]: Using GPU: %s\n", vk->context.gpu_properties.deviceName); + { + char device_str[128]; + char driver_version[64]; + char api_version[64]; + char version_str[128]; + int pos = 0; + + device_str[0] = driver_version[0] = api_version[0] = version_str[0] = '\0'; + + strlcpy(device_str, vk->context.gpu_properties.deviceName, sizeof(device_str)); + strlcat(device_str, " ", sizeof(device_str)); + + pos += snprintf(driver_version + pos, sizeof(driver_version) - pos, "%u", VK_VERSION_MAJOR(vk->context.gpu_properties.driverVersion)); + strlcat(driver_version, ".", sizeof(driver_version)); + pos++; + pos += snprintf(driver_version + pos, sizeof(driver_version) - pos, "%u", VK_VERSION_MINOR(vk->context.gpu_properties.driverVersion)); + pos++; + strlcat(driver_version, ".", sizeof(driver_version)); + pos += snprintf(driver_version + pos, sizeof(driver_version) - pos, "%u", VK_VERSION_PATCH(vk->context.gpu_properties.driverVersion)); + + strlcat(device_str, driver_version, sizeof(device_str)); + + pos = 0; + + pos += snprintf(api_version + pos, sizeof(api_version) - pos, "%u", VK_VERSION_MAJOR(vk->context.gpu_properties.apiVersion)); + strlcat(api_version, ".", sizeof(api_version)); + pos++; + pos += snprintf(api_version + pos, sizeof(api_version) - pos, "%u", VK_VERSION_MINOR(vk->context.gpu_properties.apiVersion)); + pos++; + strlcat(api_version, ".", sizeof(api_version)); + pos += snprintf(api_version + pos, sizeof(api_version) - pos, "%u", VK_VERSION_PATCH(vk->context.gpu_properties.apiVersion)); + + strlcat(version_str, api_version, sizeof(device_str)); + + video_driver_set_gpu_device_string(device_str); + video_driver_set_gpu_api_version_string(version_str); + } + if (vk->context.device == VK_NULL_HANDLE) { VkQueueFamilyProperties *queue_properties = NULL; diff --git a/gfx/common/win32_common.c b/gfx/common/win32_common.c index 9b486b89ff..29717d1b86 100644 --- a/gfx/common/win32_common.c +++ b/gfx/common/win32_common.c @@ -1059,6 +1059,12 @@ bool win32_get_metrics(void *data, switch (type) { + case DISPLAY_METRIC_PIXEL_WIDTH: + *value = pixels_x; + return true; + case DISPLAY_METRIC_PIXEL_HEIGHT: + *value = pixels_y; + return true; case DISPLAY_METRIC_MM_WIDTH: *value = physical_width; return true; diff --git a/gfx/common/x11_common.c b/gfx/common/x11_common.c index 7a93378b6b..3a7b0d9709 100644 --- a/gfx/common/x11_common.c +++ b/gfx/common/x11_common.c @@ -57,6 +57,8 @@ #define MOVERESIZE_X_SHIFT 8 #define MOVERESIZE_Y_SHIFT 9 +#define V_DBLSCAN 0x20 + static XF86VidModeModeInfo desktop_mode; static bool xdg_screensaver_available = true; bool g_x11_entered = false; @@ -243,6 +245,7 @@ float x11_get_refresh_rate(void *data) Screen *screen; int screenid; int dotclock; + float refresh; if (!g_x11_dpy || g_x11_win == None) return 0.0f; @@ -255,7 +258,13 @@ float x11_get_refresh_rate(void *data) XF86VidModeGetModeLine(g_x11_dpy, screenid, &dotclock, &modeline); - return (float) dotclock * 1000.0f / modeline.htotal / modeline.vtotal; + /* non-native modes like 1080p on a 4K display might use DoubleScan */ + if (modeline.flags & V_DBLSCAN) + dotclock /= 2; + + refresh = (float)dotclock * 1000.0f / modeline.htotal / modeline.vtotal; + + return refresh; } static bool get_video_mode(video_frame_info_t *video_info, @@ -389,6 +398,12 @@ bool x11_get_metrics(void *data, switch (type) { + case DISPLAY_METRIC_PIXEL_WIDTH: + *value = (float)pixels_x; + break; + case DISPLAY_METRIC_PIXEL_HEIGHT: + *value = (float)pixels_y; + break; case DISPLAY_METRIC_MM_WIDTH: *value = (float)physical_width; break; diff --git a/gfx/drivers/d3d10.c b/gfx/drivers/d3d10.c index d2c5b00477..81cc3719ee 100644 --- a/gfx/drivers/d3d10.c +++ b/gfx/drivers/d3d10.c @@ -14,11 +14,14 @@ */ #define CINTERFACE +#define COBJMACROS #include #include #include +#include +#include #include "../../driver.h" #include "../../verbosity.h" @@ -631,6 +634,7 @@ d3d10_gfx_init(const video_info_t* video, RARCH_ERR("[D3D10]: win32_set_video_mode failed.\n"); goto error; } + d3d_input_driver(settings->arrays.input_driver, settings->arrays.input_joypad_driver, input, input_data); { @@ -968,6 +972,44 @@ d3d10_gfx_init(const video_info_t* video, } #endif +#ifdef __WINRT__ + DXGICreateFactory2(&d3d10->factory); +#else + DXGICreateFactory(&d3d10->factory); +#endif + + { + int i = 0; + DXGI_ADAPTER_DESC desc = {0}; + char str[128]; + + str[0] = '\0'; + + while (true) + { +#ifdef __WINRT__ + if (FAILED(DXGIEnumAdapters2(d3d10->factory, i++, &d3d10->adapter))) + break; +#else + if (FAILED(DXGIEnumAdapters(d3d10->factory, i++, &d3d10->adapter))) + break; +#endif + + IDXGIAdapter_GetDesc(d3d10->adapter, &desc); + + utf16_to_char_string(desc.Description, str, sizeof(str)); + + RARCH_LOG("[D3D10]: Using GPU: %s\n", str); + + video_driver_set_gpu_device_string(str); + + Release(d3d10->adapter); + + /* We only care about the first adapter for now */ + break; + } + } + return d3d10; error: diff --git a/gfx/drivers/d3d11.c b/gfx/drivers/d3d11.c index 1d1b5246ca..49e689222e 100644 --- a/gfx/drivers/d3d11.c +++ b/gfx/drivers/d3d11.c @@ -14,6 +14,7 @@ */ #define CINTERFACE +#define COBJMACROS #include @@ -21,6 +22,8 @@ #include #include #include +#include +#include #ifdef HAVE_MENU #include "../../menu/menu_driver.h" @@ -1041,6 +1044,44 @@ d3d11_gfx_init(const video_info_t* video, const input_driver_t** input, void** i d3d11->hw.iface.D3DCompile = D3DCompile; } +#ifdef __WINRT__ + DXGICreateFactory2(&d3d11->factory); +#else + DXGICreateFactory(&d3d11->factory); +#endif + + { + int i = 0; + DXGI_ADAPTER_DESC desc = {0}; + char str[128]; + + str[0] = '\0'; + + while (true) + { +#ifdef __WINRT__ + if (FAILED(DXGIEnumAdapters2(d3d11->factory, i++, &d3d11->adapter))) + break; +#else + if (FAILED(DXGIEnumAdapters(d3d11->factory, i++, &d3d11->adapter))) + break; +#endif + + IDXGIAdapter_GetDesc(d3d11->adapter, &desc); + + utf16_to_char_string(desc.Description, str, sizeof(str)); + + RARCH_LOG("[D3D11]: Using GPU: %s\n", str); + + video_driver_set_gpu_device_string(str); + + Release(d3d11->adapter); + + /* We only care about the first adapter for now */ + break; + } + } + return d3d11; error: diff --git a/gfx/drivers/d3d9.c b/gfx/drivers/d3d9.c index 49b826586a..2793ce8570 100644 --- a/gfx/drivers/d3d9.c +++ b/gfx/drivers/d3d9.c @@ -1303,6 +1303,22 @@ static bool d3d9_init_internal(d3d9_video_t *d3d, d3d_input_driver(settings->arrays.input_joypad_driver, settings->arrays.input_joypad_driver, input, input_data); + { + D3DADAPTER_IDENTIFIER9 ident = {0}; + IDirect3D9_GetAdapterIdentifier(g_pD3D9, 0, 0, &ident); + char version_str[128]; + + version_str[0] = '\0'; + + snprintf(version_str, sizeof(version_str), "%u.%u.%u.%u", HIWORD(ident.DriverVersion.HighPart), LOWORD(ident.DriverVersion.HighPart), HIWORD(ident.DriverVersion.LowPart), LOWORD(ident.DriverVersion.LowPart)); + + RARCH_LOG("[D3D9]: Using GPU: %s\n", ident.Description); + RARCH_LOG("[D3D9]: GPU API Version: %s\n", version_str); + + video_driver_set_gpu_device_string(ident.Description); + video_driver_set_gpu_api_version_string(version_str); + } + RARCH_LOG("[D3D9]: Init complete.\n"); return true; } diff --git a/gfx/drivers/gl.c b/gfx/drivers/gl.c index 8db33be4de..707d291994 100644 --- a/gfx/drivers/gl.c +++ b/gfx/drivers/gl.c @@ -3326,6 +3326,19 @@ static void *gl2_init(const video_info_t *video, if (!string_is_empty(version)) sscanf(version, "%d.%d", &gl->version_major, &gl->version_minor); + { + char device_str[128]; + + device_str[0] = '\0'; + + strlcpy(device_str, vendor, sizeof(device_str)); + strlcat(device_str, " ", sizeof(device_str)); + strlcat(device_str, renderer, sizeof(device_str)); + + video_driver_set_gpu_device_string(device_str); + video_driver_set_gpu_api_version_string(version); + } + #ifdef _WIN32 if (string_is_equal(vendor, "Microsoft Corporation")) if (string_is_equal(renderer, "GDI Generic")) diff --git a/gfx/drivers/gl1.c b/gfx/drivers/gl1.c index 9349c3c355..257ffab960 100644 --- a/gfx/drivers/gl1.c +++ b/gfx/drivers/gl1.c @@ -187,6 +187,19 @@ static void *gl1_gfx_init(const video_info_t *video, if (!string_is_empty(version)) sscanf(version, "%d.%d", &gl1->version_major, &gl1->version_minor); + { + char device_str[128]; + + device_str[0] = '\0'; + + strlcpy(device_str, vendor, sizeof(device_str)); + strlcat(device_str, " ", sizeof(device_str)); + strlcat(device_str, renderer, sizeof(device_str)); + + video_driver_set_gpu_device_string(device_str); + video_driver_set_gpu_api_version_string(version); + } + RARCH_LOG("[GL1]: Detecting screen resolution %ux%u.\n", full_x, full_y); win_width = video->width; diff --git a/gfx/video_driver.c b/gfx/video_driver.c index 5bdc03814c..52c40c0a87 100644 --- a/gfx/video_driver.c +++ b/gfx/video_driver.c @@ -230,6 +230,9 @@ static bool video_started_fullscreen = false; static shader_backend_t *current_shader = NULL; static void *current_shader_data = NULL; +static char video_driver_gpu_device_string[128] = {0}; +static char video_driver_gpu_api_version_string[128] = {0}; + struct aspect_ratio_elem aspectratio_lut[ASPECT_RATIO_END] = { { "4:3", 1.3333f }, { "16:9", 1.7778f }, @@ -3547,3 +3550,23 @@ bool video_driver_has_widgets(void) && current_video->menu_widgets_enabled(video_driver_data); } #endif + +void video_driver_set_gpu_device_string(const char *str) +{ + strlcpy(video_driver_gpu_device_string, str, sizeof(video_driver_gpu_device_string)); +} + +const char* video_driver_get_gpu_device_string(void) +{ + return video_driver_gpu_device_string; +} + +void video_driver_set_gpu_api_version_string(const char *str) +{ + strlcpy(video_driver_gpu_api_version_string, str, sizeof(video_driver_gpu_api_version_string)); +} + +const char* video_driver_get_gpu_api_version_string(void) +{ + return video_driver_gpu_api_version_string; +} diff --git a/gfx/video_driver.h b/gfx/video_driver.h index 5589709df8..11a693ce25 100644 --- a/gfx/video_driver.h +++ b/gfx/video_driver.h @@ -106,7 +106,9 @@ enum display_metric_types DISPLAY_METRIC_NONE = 0, DISPLAY_METRIC_MM_WIDTH, DISPLAY_METRIC_MM_HEIGHT, - DISPLAY_METRIC_DPI + DISPLAY_METRIC_DPI, + DISPLAY_METRIC_PIXEL_WIDTH, + DISPLAY_METRIC_PIXEL_HEIGHT }; enum display_flags @@ -1205,6 +1207,14 @@ bool video_driver_is_threaded(void); bool video_driver_get_all_flags(gfx_ctx_flags_t *flags, enum display_flags flag); +void video_driver_set_gpu_device_string(const char *str); + +const char* video_driver_get_gpu_device_string(void); + +void video_driver_set_gpu_api_version_string(const char *str); + +const char* video_driver_get_gpu_api_version_string(void); + extern video_driver_t video_gl2; extern video_driver_t video_gl1; extern video_driver_t video_vulkan; diff --git a/input/input_driver.c b/input/input_driver.c index 1a6dc9afdc..75e9679b85 100644 --- a/input/input_driver.c +++ b/input/input_driver.c @@ -278,6 +278,7 @@ static uint16_t input_config_pid[MAX_USERS]; static char input_device_display_names[MAX_INPUT_DEVICES][64]; static char input_device_config_names [MAX_INPUT_DEVICES][64]; +static char input_device_config_paths [MAX_INPUT_DEVICES][64]; char input_device_names [MAX_INPUT_DEVICES][64]; uint64_t lifecycle_state; @@ -2792,6 +2793,13 @@ const char *input_config_get_device_display_name(unsigned port) return input_device_display_names[port]; } +const char *input_config_get_device_config_path(unsigned port) +{ + if (string_is_empty(input_device_config_paths[port])) + return NULL; + return input_device_config_paths[port]; +} + const char *input_config_get_device_config_name(unsigned port) { if (string_is_empty(input_device_config_names[port])) @@ -2811,6 +2819,21 @@ void input_config_set_device_name(unsigned port, const char *name) } } +void input_config_set_device_config_path(unsigned port, const char *path) +{ + if (!string_is_empty(path)) + { + fill_pathname_parent_dir_name(input_device_config_paths[port], + path, sizeof(input_device_config_paths[port])); + strlcat(input_device_config_paths[port], + "/", + sizeof(input_device_config_paths[port])); + strlcat(input_device_config_paths[port], + path_basename(path), + sizeof(input_device_config_paths[port])); + } +} + void input_config_set_device_config_name(unsigned port, const char *name) { if (!string_is_empty(name)) @@ -2842,6 +2865,11 @@ void input_config_clear_device_display_name(unsigned port) input_device_display_names[port][0] = '\0'; } +void input_config_clear_device_config_path(unsigned port) +{ + input_device_config_paths[port][0] = '\0'; +} + void input_config_clear_device_config_name(unsigned port) { input_device_config_names[port][0] = '\0'; diff --git a/input/input_driver.h b/input/input_driver.h index 7ace12e3e3..b808d2eebb 100644 --- a/input/input_driver.h +++ b/input/input_driver.h @@ -760,12 +760,16 @@ void input_config_set_device_display_name(unsigned port, const char *name); void input_config_set_device_config_name(unsigned port, const char *name); +void input_config_set_device_config_path(unsigned port, const char *path); + void input_config_clear_device_name(unsigned port); void input_config_clear_device_display_name(unsigned port); void input_config_clear_device_config_name(unsigned port); +void input_config_clear_device_config_path(unsigned port); + unsigned input_config_get_device_count(void); unsigned *input_config_get_device_ptr(unsigned port); @@ -780,6 +784,10 @@ const char *input_config_get_device_display_name(unsigned port); const char *input_config_get_device_config_name(unsigned port); +const char *input_config_get_device_config_path(unsigned port); + +const char *input_config_get_device_config_port(unsigned port); + const struct retro_keybind *input_config_get_bind_auto(unsigned port, unsigned id); void input_config_set_pid(unsigned port, uint16_t pid); diff --git a/intl/msg_hash_lbl.h b/intl/msg_hash_lbl.h index 7fe4bdbf9c..252218bdfb 100644 --- a/intl/msg_hash_lbl.h +++ b/intl/msg_hash_lbl.h @@ -1795,3 +1795,5 @@ MSG_HASH(MENU_ENUM_LABEL_PLAYLIST_SORT_ALPHABETICAL, "playlist_sort_alphabetical") MSG_HASH(MENU_ENUM_LABEL_PLAYLIST_SHOW_SUBLABELS, "playlist_show_sublabels") +MSG_HASH(MENU_ENUM_LABEL_HELP_SEND_DEBUG_INFO, + "help_send_debug_info") diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index daf0544f1e..40cae2dcf3 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -8338,3 +8338,27 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_PLAYLIST_SUBLABEL_LAST_PLAYED, "Last Played:" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_HELP_SEND_DEBUG_INFO, + "Send Debug Info" + ) +MSG_HASH( + MSG_FAILED_TO_SAVE_DEBUG_INFO, + "Failed to save debug info." + ) +MSG_HASH( + MSG_FAILED_TO_SEND_DEBUG_INFO, + "Failed to send debug info to server." + ) +MSG_HASH( + MSG_SENDING_DEBUG_INFO, + "Sending debug info..." + ) +MSG_HASH( + MSG_SENT_DEBUG_INFO, + "Sent debug info to server successfully. Your ID number is %u." + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_HELP_SEND_DEBUG_INFO, + "Sends diagnostic info about your device and RetroArch configuration to our servers for analysis." + ) diff --git a/menu/cbs/menu_cbs_ok.c b/menu/cbs/menu_cbs_ok.c index 9a58bc44ba..eefe52c13d 100644 --- a/menu/cbs/menu_cbs_ok.c +++ b/menu/cbs/menu_cbs_ok.c @@ -4907,6 +4907,12 @@ static int (funcname)(const char *path, const char *label, unsigned type, size_t return generic_action_ok_help(path, label, type, idx, entry_idx, _id, _id2); \ } +static int action_ok_help_send_debug_info(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx) +{ + rarch_send_debug_info(); + return 0; +} + default_action_ok_help(action_ok_help_audio_video_troubleshooting, MENU_ENUM_LABEL_HELP_AUDIO_VIDEO_TROUBLESHOOTING, MENU_DIALOG_HELP_AUDIO_VIDEO_TROUBLESHOOTING) default_action_ok_help(action_ok_help, MENU_ENUM_LABEL_HELP, MENU_DIALOG_WELCOME) default_action_ok_help(action_ok_help_controls, MENU_ENUM_LABEL_HELP_CONTROLS, MENU_DIALOG_HELP_CONTROLS) @@ -5348,6 +5354,9 @@ static int menu_cbs_init_bind_ok_compare_label(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_HELP_AUDIO_VIDEO_TROUBLESHOOTING: BIND_ACTION_OK(cbs, action_ok_help_audio_video_troubleshooting); break; + case MENU_ENUM_LABEL_HELP_SEND_DEBUG_INFO: + BIND_ACTION_OK(cbs, action_ok_help_send_debug_info); + break; case MENU_ENUM_LABEL_HELP_SCANNING_CONTENT: BIND_ACTION_OK(cbs, action_ok_help_scanning_content); break; diff --git a/menu/cbs/menu_cbs_sublabel.c b/menu/cbs/menu_cbs_sublabel.c index 7071270c82..f66e5bb55f 100644 --- a/menu/cbs/menu_cbs_sublabel.c +++ b/menu/cbs/menu_cbs_sublabel.c @@ -528,6 +528,7 @@ default_sublabel_macro(action_bind_sublabel_menu_ticker_speed, default_sublabel_macro(action_bind_sublabel_playlist_show_core_name, MENU_ENUM_SUBLABEL_PLAYLIST_SHOW_CORE_NAME) default_sublabel_macro(action_bind_sublabel_playlist_sort_alphabetical, MENU_ENUM_SUBLABEL_PLAYLIST_SORT_ALPHABETICAL) default_sublabel_macro(action_bind_sublabel_menu_rgui_full_width_layout, MENU_ENUM_SUBLABEL_MENU_RGUI_FULL_WIDTH_LAYOUT) +default_sublabel_macro(action_bind_sublabel_help_send_debug_info, MENU_ENUM_SUBLABEL_HELP_SEND_DEBUG_INFO) static int action_bind_sublabel_systeminfo_controller_entry( file_list_t *list, @@ -2394,6 +2395,9 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_MENU_RGUI_FULL_WIDTH_LAYOUT: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_menu_rgui_full_width_layout); break; + case MENU_ENUM_LABEL_HELP_SEND_DEBUG_INFO: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_help_send_debug_info); + break; default: case MSG_UNKNOWN: return -1; diff --git a/menu/drivers/menu_generic.c b/menu/drivers/menu_generic.c index b43f2433f3..64fbc3091a 100644 --- a/menu/drivers/menu_generic.c +++ b/menu/drivers/menu_generic.c @@ -41,6 +41,7 @@ static enum action_iterate_type action_iterate_type(const char *label) string_is_equal(label, "help_scanning_content") || string_is_equal(label, "help_change_virtual_gamepad") || string_is_equal(label, "help_audio_video_troubleshooting") || + string_is_equal(label, "help_send_debug_info") || string_is_equal(label, "cheevos_description") ) return ITERATE_TYPE_HELP; diff --git a/menu/drivers/ozone/ozone_texture.c b/menu/drivers/ozone/ozone_texture.c index d64363aa82..e8b65f9bd2 100644 --- a/menu/drivers/ozone/ozone_texture.c +++ b/menu/drivers/ozone/ozone_texture.c @@ -147,6 +147,7 @@ menu_texture_item ozone_entries_icon_get_texture(ozone_handle_t *ozone, case MENU_ENUM_LABEL_HELP_WHAT_IS_A_CORE: case MENU_ENUM_LABEL_HELP_CHANGE_VIRTUAL_GAMEPAD: case MENU_ENUM_LABEL_HELP_AUDIO_VIDEO_TROUBLESHOOTING: + case MENU_ENUM_LABEL_HELP_SEND_DEBUG_INFO: return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_HELP]; case MENU_ENUM_LABEL_QUIT_RETROARCH: case MENU_ENUM_LABEL_BLOCK_SRAM_OVERWRITE: diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index e0d10cdf49..362dbcead8 100644 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -2412,6 +2412,7 @@ static uintptr_t xmb_icon_get_id(xmb_handle_t *xmb, case MENU_ENUM_LABEL_HELP_WHAT_IS_A_CORE: case MENU_ENUM_LABEL_HELP_CHANGE_VIRTUAL_GAMEPAD: case MENU_ENUM_LABEL_HELP_AUDIO_VIDEO_TROUBLESHOOTING: + case MENU_ENUM_LABEL_HELP_SEND_DEBUG_INFO: return xmb->textures.list[XMB_TEXTURE_HELP]; case MENU_ENUM_LABEL_QUIT_RETROARCH: case MENU_ENUM_LABEL_BLOCK_SRAM_OVERWRITE: diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index 438e7ce2c6..5499f64d80 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -459,7 +459,6 @@ static int menu_displaylist_parse_system_info(menu_displaylist_info_t *info) char cpu_str[8192]; char cpu_arch_str[PATH_MAX_LENGTH]; char cpu_text_str[PATH_MAX_LENGTH]; - enum frontend_architecture arch = frontend_driver_get_cpu_architecture(); cpu_str[0] = cpu_arch_str[0] = cpu_text_str[0] = '\0'; @@ -467,39 +466,7 @@ static int menu_displaylist_parse_system_info(menu_displaylist_info_t *info) msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CPU_ARCHITECTURE), sizeof(cpu_text_str)); - switch (arch) - { - case FRONTEND_ARCH_X86: - strlcpy(cpu_arch_str, "x86", sizeof(cpu_arch_str)); - break; - case FRONTEND_ARCH_X86_64: - strlcpy(cpu_arch_str, "x64", sizeof(cpu_arch_str)); - break; - case FRONTEND_ARCH_PPC: - strlcpy(cpu_arch_str, "PPC", sizeof(cpu_arch_str)); - break; - case FRONTEND_ARCH_ARM: - strlcpy(cpu_arch_str, "ARM", sizeof(cpu_arch_str)); - break; - case FRONTEND_ARCH_ARMV7: - strlcpy(cpu_arch_str, "ARMv7", sizeof(cpu_arch_str)); - break; - case FRONTEND_ARCH_ARMV8: - strlcpy(cpu_arch_str, "ARMv8", sizeof(cpu_arch_str)); - break; - case FRONTEND_ARCH_MIPS: - strlcpy(cpu_arch_str, "MIPS", sizeof(cpu_arch_str)); - break; - case FRONTEND_ARCH_TILE: - strlcpy(cpu_arch_str, "Tilera", sizeof(cpu_arch_str)); - break; - case FRONTEND_ARCH_NONE: - default: - strlcpy(cpu_arch_str, - msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE), - sizeof(cpu_arch_str)); - break; - } + rarch_get_cpu_architecture_string(cpu_arch_str, sizeof(cpu_arch_str)); snprintf(cpu_str, sizeof(cpu_str), "%s %s", cpu_text_str, cpu_arch_str); @@ -521,38 +488,38 @@ static int menu_displaylist_parse_system_info(menu_displaylist_info_t *info) MENU_ENUM_LABEL_CPU_CORES, MENU_SETTINGS_CORE_INFO_NONE, 0, 0); } - for(controller = 0; controller < MAX_USERS; controller++) + for (controller = 0; controller < MAX_USERS; controller++) { if (input_is_autoconfigured(controller)) { - snprintf(tmp, sizeof(tmp), "Port #%d device name: %s (#%d)", - controller, - input_config_get_device_name(controller), - input_autoconfigure_get_device_name_index(controller)); + snprintf(tmp, sizeof(tmp), "Port #%d device name: %s (#%d)", + controller, + input_config_get_device_name(controller), + input_autoconfigure_get_device_name_index(controller)); + menu_entries_append_enum(info->list, tmp, "", + MENU_ENUM_LABEL_SYSTEM_INFO_CONTROLLER_ENTRY, + MENU_SETTINGS_CORE_INFO_NONE, 0, 0); + if (string_is_equal(settings->arrays.menu_driver, "rgui")) + { + snprintf(tmp, sizeof(tmp), " Device display name: %s", + input_config_get_device_display_name(controller) ? + input_config_get_device_display_name(controller) : "N/A"); menu_entries_append_enum(info->list, tmp, "", MENU_ENUM_LABEL_SYSTEM_INFO_CONTROLLER_ENTRY, MENU_SETTINGS_CORE_INFO_NONE, 0, 0); - if (string_is_equal(settings->arrays.menu_driver, "rgui")) - { - snprintf(tmp, sizeof(tmp), " Device display name: %s", - input_config_get_device_display_name(controller) ? - input_config_get_device_display_name(controller) : "N/A"); - menu_entries_append_enum(info->list, tmp, "", - MENU_ENUM_LABEL_SYSTEM_INFO_CONTROLLER_ENTRY, - MENU_SETTINGS_CORE_INFO_NONE, 0, 0); - snprintf(tmp, sizeof(tmp), " Device config name: %s", - input_config_get_device_display_name(controller) ? - input_config_get_device_config_name(controller) : "N/A"); - menu_entries_append_enum(info->list, tmp, "", - MENU_ENUM_LABEL_SYSTEM_INFO_CONTROLLER_ENTRY, - MENU_SETTINGS_CORE_INFO_NONE, 0, 0); - snprintf(tmp, sizeof(tmp), " Device VID/PID: %d/%d", - input_config_get_vid(controller), - input_config_get_pid(controller)); - menu_entries_append_enum(info->list, tmp, "", - MENU_ENUM_LABEL_SYSTEM_INFO_CONTROLLER_ENTRY, - MENU_SETTINGS_CORE_INFO_NONE, 0, 0); - } + snprintf(tmp, sizeof(tmp), " Device config name: %s", + input_config_get_device_display_name(controller) ? + input_config_get_device_config_name(controller) : "N/A"); + menu_entries_append_enum(info->list, tmp, "", + MENU_ENUM_LABEL_SYSTEM_INFO_CONTROLLER_ENTRY, + MENU_SETTINGS_CORE_INFO_NONE, 0, 0); + snprintf(tmp, sizeof(tmp), " Device VID/PID: %d/%d", + input_config_get_vid(controller), + input_config_get_pid(controller)); + menu_entries_append_enum(info->list, tmp, "", + MENU_ENUM_LABEL_SYSTEM_INFO_CONTROLLER_ENTRY, + MENU_SETTINGS_CORE_INFO_NONE, 0, 0); + } } } @@ -3484,7 +3451,7 @@ static int menu_displaylist_parse_options_remappings( if (device == RETRO_DEVICE_JOYPAD || device == RETRO_DEVICE_ANALOG) { - for (retro_id = 0; retro_id < RARCH_FIRST_CUSTOM_BIND + 8; retro_id++) + for (retro_id = 0; retro_id < RARCH_ANALOG_BIND_LIST_END; retro_id++) { char desc_label[400]; char descriptor[300]; @@ -7821,6 +7788,11 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, menu_displaylist msg_hash_to_str(MENU_ENUM_LABEL_HELP_AUDIO_VIDEO_TROUBLESHOOTING), MENU_ENUM_LABEL_HELP_AUDIO_VIDEO_TROUBLESHOOTING, 0, 0, 0); + menu_entries_append_enum(info->list, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_HELP_SEND_DEBUG_INFO), + msg_hash_to_str(MENU_ENUM_LABEL_HELP_SEND_DEBUG_INFO), + MENU_ENUM_LABEL_HELP_SEND_DEBUG_INFO, + 0, 0, 0); info->need_refresh = true; info->need_push = true; break; diff --git a/menu/widgets/menu_dialog.c b/menu/widgets/menu_dialog.c index cd541b84b1..2fbd65d0b0 100644 --- a/menu/widgets/menu_dialog.c +++ b/menu/widgets/menu_dialog.c @@ -198,6 +198,11 @@ int menu_dialog_iterate(char *s, size_t len, const char *label) MENU_ENUM_LABEL_VALUE_HELP_AUDIO_VIDEO_TROUBLESHOOTING_DESC, s, len); break; + case MENU_DIALOG_HELP_SEND_DEBUG_INFO: + menu_hash_get_help_enum( + MENU_ENUM_LABEL_VALUE_HELP_SEND_DEBUG_INFO_DESC, + s, len); + break; case MENU_DIALOG_HELP_SCANNING_CONTENT: menu_hash_get_help_enum(MENU_ENUM_LABEL_VALUE_HELP_SCANNING_CONTENT_DESC, s, len); diff --git a/menu/widgets/menu_dialog.h b/menu/widgets/menu_dialog.h index 88532feb7d..73e34ee248 100644 --- a/menu/widgets/menu_dialog.h +++ b/menu/widgets/menu_dialog.h @@ -38,6 +38,7 @@ enum menu_dialog_type MENU_DIALOG_HELP_WHAT_IS_A_CORE, MENU_DIALOG_HELP_CHANGE_VIRTUAL_GAMEPAD, MENU_DIALOG_HELP_AUDIO_VIDEO_TROUBLESHOOTING, + MENU_DIALOG_HELP_SEND_DEBUG_INFO, MENU_DIALOG_HELP_SCANNING_CONTENT, MENU_DIALOG_QUIT_CONFIRM, MENU_DIALOG_INFORMATION, diff --git a/msg_hash.h b/msg_hash.h index 91867422b8..8fef96cbe5 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -2285,6 +2285,14 @@ enum msg_hash_enums MENU_ENUM_LABEL_VALUE_PLAYLIST_SUBLABEL_RUNTIME, MENU_ENUM_LABEL_VALUE_PLAYLIST_SUBLABEL_LAST_PLAYED, + MENU_LABEL(HELP_SEND_DEBUG_INFO), + MENU_ENUM_LABEL_VALUE_HELP_SEND_DEBUG_INFO_DESC, + + MSG_FAILED_TO_SAVE_DEBUG_INFO, + MSG_FAILED_TO_SEND_DEBUG_INFO, + MSG_SENDING_DEBUG_INFO, + MSG_SENT_DEBUG_INFO, + MSG_LAST }; diff --git a/retroarch.c b/retroarch.c index 2db2cc35aa..3433251b58 100644 --- a/retroarch.c +++ b/retroarch.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -53,6 +54,9 @@ #include #include #include +#include +#include + #include "runtime_file.h" #ifdef HAVE_CONFIG_H @@ -111,6 +115,9 @@ #include "frontend/frontend_driver.h" #include "audio/audio_driver.h" +#ifdef HAVE_THREADS +#include "../gfx/video_thread_wrapper.h" +#endif #include "gfx/video_driver.h" #include "camera/camera_driver.h" #include "record/record_driver.h" @@ -155,6 +162,8 @@ #define QUIT_DELAY_USEC 3 * 1000000 /* 3 seconds */ +#define DEBUG_INFO_FILENAME "debug_info.txt" + /* Descriptive names for options without short variant. * * Please keep the name in sync with the option name. @@ -4486,3 +4495,576 @@ void rarch_force_video_driver_fallback(const char *driver) exit(1); } + +void rarch_get_cpu_architecture_string(char *cpu_arch_str, size_t len) +{ + enum frontend_architecture arch = frontend_driver_get_cpu_architecture(); + + if (!cpu_arch_str || !len) + return; + + switch (arch) + { + case FRONTEND_ARCH_X86: + strlcpy(cpu_arch_str, "x86", len); + break; + case FRONTEND_ARCH_X86_64: + strlcpy(cpu_arch_str, "x64", len); + break; + case FRONTEND_ARCH_PPC: + strlcpy(cpu_arch_str, "PPC", len); + break; + case FRONTEND_ARCH_ARM: + strlcpy(cpu_arch_str, "ARM", len); + break; + case FRONTEND_ARCH_ARMV7: + strlcpy(cpu_arch_str, "ARMv7", len); + break; + case FRONTEND_ARCH_ARMV8: + strlcpy(cpu_arch_str, "ARMv8", len); + break; + case FRONTEND_ARCH_MIPS: + strlcpy(cpu_arch_str, "MIPS", len); + break; + case FRONTEND_ARCH_TILE: + strlcpy(cpu_arch_str, "Tilera", len); + break; + case FRONTEND_ARCH_NONE: + default: + strlcpy(cpu_arch_str, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE), + len); + break; + } +} + +bool rarch_write_debug_info(void) +{ + settings_t *settings = config_get_ptr(); + gfx_ctx_mode_t mode_info = {0}; + char str[PATH_MAX_LENGTH]; + char debug_filepath[PATH_MAX_LENGTH]; + const frontend_ctx_driver_t *frontend = frontend_get_ptr(); + const char *cpu_model = NULL; + const char *path_config = path_get(RARCH_PATH_CONFIG); + RFILE *file; + unsigned lang = *msg_hash_get_uint(MSG_HASH_USER_LANGUAGE); + int i; + + str[0] = debug_filepath[0] = '\0'; + + if (lang != RETRO_LANGUAGE_ENGLISH) + { + /* Only print our debug info in English */ + msg_hash_set_uint(MSG_HASH_USER_LANGUAGE, RETRO_LANGUAGE_ENGLISH); + } + + fill_pathname_resolve_relative( + debug_filepath, + path_config, + DEBUG_INFO_FILENAME, + sizeof(debug_filepath)); + + file = filestream_open(debug_filepath, RETRO_VFS_FILE_ACCESS_WRITE, RETRO_VFS_FILE_ACCESS_HINT_NONE); + + if (!file) + { + RARCH_ERR("Could not open debug info file for writing: %s\n", debug_filepath); + goto error; + } + +#ifdef HAVE_MENU + { + time_t time_; + char timedate[255]; + + timedate[0] = '\0'; + + time(&time_); + + setlocale(LC_TIME, ""); + + strftime(timedate, sizeof(timedate), + "%Y-%m-%d %H:%M:%S", localtime(&time_)); + + filestream_printf(file, "Log Date/Time: %s\n", timedate); + } +#endif + filestream_printf(file, "RetroArch Version: %s\n", PACKAGE_VERSION); + +#ifdef HAVE_LAKKA + if (frontend->get_lakka_version) + { + frontend->get_lakka_version(str, sizeof(str)); + filestream_printf(file, "Lakka Version: %s\n", str); + str[0] = '\0'; + } +#endif + + filestream_printf(file, "RetroArch Build Date: %s\n", __DATE__); +#ifdef HAVE_GIT_VERSION + filestream_printf(file, "RetroArch Git Commit: %s\n", retroarch_git_version); +#endif + + filestream_printf(file, "\n"); + + cpu_model = frontend_driver_get_cpu_model_name(); + + if (!string_is_empty(cpu_model)) + filestream_printf(file, "CPU Model Name: %s\n", cpu_model); + + retroarch_get_capabilities(RARCH_CAPABILITIES_CPU, str, sizeof(str)); + filestream_printf(file, "CPU Capabilities: %s\n", str); + + str[0] = '\0'; + + rarch_get_cpu_architecture_string(str, sizeof(str)); + + filestream_printf(file, "CPU Architecture: %s\n", str); + filestream_printf(file, "CPU Cores: %u\n", cpu_features_get_core_amount()); + + { + uint64_t memory_used = frontend_driver_get_used_memory(); + uint64_t memory_total = frontend_driver_get_total_memory(); + + filestream_printf(file, "Memory: %" PRIu64 "/%" PRIu64 " MB\n", memory_used / 1024 / 1024, memory_total / 1024 / 1024); + } + + filestream_printf(file, "GPU Device: %s\n", !string_is_empty(video_driver_get_gpu_device_string()) ? + video_driver_get_gpu_device_string() : "n/a"); + filestream_printf(file, "GPU API/Driver Version: %s\n", !string_is_empty(video_driver_get_gpu_api_version_string()) ? + video_driver_get_gpu_api_version_string() : "n/a"); + + filestream_printf(file, "\n"); + + video_context_driver_get_video_size(&mode_info); + + filestream_printf(file, "Window Resolution: %u x %u\n", mode_info.width, mode_info.height); + + { + float width = 0, height = 0, refresh = 0.0f; + gfx_ctx_metrics_t metrics = {0}; + + metrics.type = DISPLAY_METRIC_PIXEL_WIDTH; + metrics.value = &width; + video_context_driver_get_metrics(&metrics); + + metrics.type = DISPLAY_METRIC_PIXEL_HEIGHT; + metrics.value = &height; + video_context_driver_get_metrics(&metrics); + + video_context_driver_get_refresh_rate(&refresh); + + filestream_printf(file, "Monitor Resolution: %d x %d @ %.2f Hz (configured for %.2f Hz)\n", (int)width, (int)height, refresh, settings->floats.video_refresh_rate); + } + + filestream_printf(file, "\n"); + + str[0] = '\0'; + + retroarch_get_capabilities(RARCH_CAPABILITIES_COMPILER, str, sizeof(str)); + filestream_printf(file, "%s\n", str); + + str[0] = '\0'; + + filestream_printf(file, "Frontend Identifier: %s\n", frontend->ident); + + if (frontend->get_name) + { + frontend->get_name(str, sizeof(str)); + filestream_printf(file, "Frontend Name: %s\n", str); + str[0] = '\0'; + } + + if (frontend->get_os) + { + int major = 0, minor = 0; + const char *warning = ""; + + frontend->get_os(str, sizeof(str), &major, &minor); + + if (strstr(str, "Build 16299")) + warning = " (WARNING: Fall Creator's Update detected... OpenGL performance may be low)"; + + filestream_printf(file, "Frontend OS: %s (v%d.%d)%s\n", str, major, minor, warning); + + str[0] = '\0'; + } + + filestream_printf(file, "\n"); + filestream_printf(file, "Input Devices (autoconfig is %s):\n", settings->bools.input_autodetect_enable ? "enabled" : "disabled"); + + for (i = 0; i < 4; i++) + { + if (input_is_autoconfigured(i)) + { + unsigned rebind = 0; + unsigned retro_id; + unsigned device = settings->uints.input_libretro_device[i]; + + device &= RETRO_DEVICE_MASK; + + if (device == RETRO_DEVICE_JOYPAD || device == RETRO_DEVICE_ANALOG) + { + for (retro_id = 0; retro_id < RARCH_ANALOG_BIND_LIST_END; retro_id++) + { + char desc_label[400]; + char descriptor[300]; + const struct retro_keybind *auto_bind = NULL; + const struct retro_keybind *keybind = NULL; + + keybind = &input_config_binds[i][retro_id]; + auto_bind = (const struct retro_keybind*) + input_config_get_bind_auto(i, retro_id); + + input_config_get_bind_string(descriptor, + keybind, auto_bind, sizeof(descriptor)); + + if(!strstr(descriptor, "Auto") && auto_bind && !auto_bind->valid && auto_bind->joykey != 0xFFFF && !string_is_empty(auto_bind->joykey_label)) + rebind++; + } + } + + if (rebind) + filestream_printf(file, " - Port #%d autoconfigured (WARNING: %u keys rebinded):\n", i, rebind); + else + filestream_printf(file, " - Port #%d autoconfigured:\n", i); + + filestream_printf(file, " - Device name: %s (#%d)\n", + input_config_get_device_name(i), + input_autoconfigure_get_device_name_index(i)); + filestream_printf(file, " - Display name: %s\n", + input_config_get_device_display_name(i) ? + input_config_get_device_display_name(i) : "N/A"); + filestream_printf(file, " - Config path: %s\n", + input_config_get_device_display_name(i) ? + input_config_get_device_config_path(i) : "N/A"); + filestream_printf(file, " - VID/PID: %d/%d (0x%04X/0x%04X)\n", + input_config_get_vid(i), input_config_get_pid(i), + input_config_get_vid(i), input_config_get_pid(i)); + } + else + filestream_printf(file, " - Port #%d not autoconfigured\n", i); + } + + filestream_printf(file, "\n"); + + filestream_printf(file, "Drivers:\n"); + + { + gfx_ctx_ident_t ident_info = {0}; + const input_driver_t *input_driver; + const input_device_driver_t *joypad_driver; + const char *driver = menu_driver_ident(); + + if (string_is_equal(driver, settings->arrays.menu_driver)) + filestream_printf(file, " - Menu: %s\n", !string_is_empty(driver) ? driver : "n/a"); + else + filestream_printf(file, " - Menu: %s (configured for %s)\n", !string_is_empty(driver) ? driver : "n/a", !string_is_empty(settings->arrays.menu_driver) ? settings->arrays.menu_driver : "n/a"); + + driver = +#ifdef HAVE_THREADS + (video_driver_is_threaded()) ? + video_thread_get_ident() : +#endif + video_driver_get_ident(); + + if (string_is_equal(driver, settings->arrays.video_driver)) + filestream_printf(file, " - Video: %s\n", !string_is_empty(driver) ? driver : "n/a"); + else + filestream_printf(file, " - Video: %s (configured for %s)\n", !string_is_empty(driver) ? driver : "n/a", !string_is_empty(settings->arrays.video_driver) ? settings->arrays.video_driver : "n/a"); + + video_context_driver_get_ident(&ident_info); + filestream_printf(file, " - Video Context: %s\n", ident_info.ident ? ident_info.ident : "n/a"); + + driver = audio_driver_get_ident(); + + if (string_is_equal(driver, settings->arrays.audio_driver)) + filestream_printf(file, " - Audio: %s\n", !string_is_empty(driver) ? driver : "n/a"); + else + filestream_printf(file, " - Audio: %s (configured for %s)\n", !string_is_empty(driver) ? driver : "n/a", !string_is_empty(settings->arrays.audio_driver) ? settings->arrays.audio_driver : "n/a"); + + input_driver = input_get_ptr(); + + if (input_driver && string_is_equal(input_driver->ident, settings->arrays.input_driver)) + filestream_printf(file, " - Input: %s\n", !string_is_empty(input_driver->ident) ? input_driver->ident : "n/a"); + else + filestream_printf(file, " - Input: %s (configured for %s)\n", !string_is_empty(input_driver->ident) ? input_driver->ident : "n/a", !string_is_empty(settings->arrays.input_driver) ? settings->arrays.input_driver : "n/a"); + + joypad_driver = (input_driver->get_joypad_driver ? input_driver->get_joypad_driver(input_driver_get_data()) : NULL); + + if (joypad_driver && string_is_equal(joypad_driver->ident, settings->arrays.input_joypad_driver)) + filestream_printf(file, " - Joypad: %s\n", !string_is_empty(joypad_driver->ident) ? joypad_driver->ident : "n/a"); + else + filestream_printf(file, " - Input: %s (configured for %s)\n", !string_is_empty(joypad_driver->ident) ? joypad_driver->ident : "n/a", !string_is_empty(settings->arrays.input_joypad_driver) ? settings->arrays.input_joypad_driver : "n/a"); + } + + filestream_printf(file, "\n"); + + filestream_printf(file, "Configuration related settings:\n"); + filestream_printf(file, " - Save on exit: %s\n", settings->bools.config_save_on_exit ? "yes" : "no"); + filestream_printf(file, " - Load content-specific core options automatically: %s\n", settings->bools.game_specific_options ? "yes" : "no"); + filestream_printf(file, " - Load override files automatically: %s\n", settings->bools.auto_overrides_enable ? "yes" : "no"); + filestream_printf(file, " - Load remap files automatically: %s\n", settings->bools.auto_remaps_enable ? "yes" : "no"); + filestream_printf(file, " - Sort saves in folders: %s\n", settings->bools.sort_savefiles_enable ? "yes" : "no"); + filestream_printf(file, " - Sort states in folders: %s\n", settings->bools.sort_savestates_enable ? "yes" : "no"); + filestream_printf(file, " - Write saves in content dir: %s\n", settings->bools.savefiles_in_content_dir ? "yes" : "no"); + filestream_printf(file, " - Write savestates in content dir: %s\n", settings->bools.savestates_in_content_dir ? "yes" : "no"); + + filestream_printf(file, "\n"); + + filestream_printf(file, "Auto load state: %s\n", settings->bools.savestate_auto_load ? "yes (WARNING: not compatible with all cores)" : "no"); + filestream_printf(file, "Auto save state: %s\n", settings->bools.savestate_auto_save ? "yes" : "no"); + + filestream_printf(file, "\n"); + + filestream_printf(file, "Buildbot cores URL: %s\n", settings->paths.network_buildbot_url); + filestream_printf(file, "Auto-extract downloaded archives: %s\n", settings->bools.network_buildbot_auto_extract_archive ? "yes" : "no"); + + { + size_t count = 0; + core_info_list_t *core_info_list = NULL; + struct string_list *list = NULL; + const char *ext = file_path_str(FILE_PATH_RDB_EXTENSION); + + /* remove dot */ + if (!string_is_empty(ext) && ext[0] == '.' && strlen(ext) > 1) + ext++; + + core_info_get_list(&core_info_list); + + if (core_info_list) + count = core_info_list->count; + + filestream_printf(file, "Core info: %u entries\n", count); + + count = 0; + + list = dir_list_new(settings->paths.path_content_database, ext, false, true, false, true); + + if (list) + { + count = list->size; + string_list_free(list); + } + + filestream_printf(file, "Databases: %u entries\n", count); + } + + filestream_printf(file, "\n"); + + filestream_printf(file, "Performance and latency-sensitive features (may have a large impact depending on the core):\n"); + filestream_printf(file, " - Video:\n"); + filestream_printf(file, " - Runahead: %s\n", settings->bools.run_ahead_enabled ? "yes (WARNING: not compatible with all cores)" : "no"); + filestream_printf(file, " - Rewind: %s\n", settings->bools.rewind_enable ? "yes (WARNING: not compatible with all cores)" : "no"); + filestream_printf(file, " - Hard GPU Sync: %s\n", settings->bools.video_hard_sync ? "yes" : "no"); + filestream_printf(file, " - Frame Delay: %u frames\n", settings->uints.video_frame_delay); + filestream_printf(file, " - Max Swapchain Images: %u\n", settings->uints.video_max_swapchain_images); + filestream_printf(file, " - Max Run Speed: %.1f x\n", settings->floats.fastforward_ratio); + filestream_printf(file, " - Sync to exact content framerate: %s\n", settings->bools.vrr_runloop_enable ? "yes (note: designed for G-Sync/FreeSync displays only)" : "no"); + filestream_printf(file, " - Fullscreen: %s\n", settings->bools.video_fullscreen ? "yes" : "no"); + filestream_printf(file, " - Windowed Fullscreen: %s\n", settings->bools.video_windowed_fullscreen ? "yes" : "no"); + filestream_printf(file, " - Threaded Video: %s\n", settings->bools.video_threaded ? "yes" : "no"); + filestream_printf(file, " - Vsync: %s\n", settings->bools.video_vsync ? "yes" : "no"); + filestream_printf(file, " - Vsync Swap Interval: %u frames\n", settings->uints.video_swap_interval); + filestream_printf(file, " - Black Frame Insertion: %s\n", settings->bools.video_black_frame_insertion ? "yes" : "no"); + filestream_printf(file, " - Bilinear Filtering: %s\n", settings->bools.video_smooth ? "yes" : "no"); + filestream_printf(file, " - Video CPU Filter: %s\n", !string_is_empty(settings->paths.path_softfilter_plugin) ? settings->paths.path_softfilter_plugin : "n/a"); + filestream_printf(file, " - CRT SwitchRes: %s\n", (settings->uints.crt_switch_resolution > CRT_SWITCH_NONE) ? "yes" : "no"); + filestream_printf(file, " - Video Shared Context: %s\n", settings->bools.video_shared_context ? "yes" : "no"); + + { + video_shader_ctx_t shader_info = {0}; + + video_shader_driver_get_current_shader(&shader_info); + + if (shader_info.data) + { + if (string_is_equal(shader_info.data->path, settings->paths.path_shader)) + filestream_printf(file, " - Video Shader: %s\n", !string_is_empty(settings->paths.path_shader) ? settings->paths.path_shader : "n/a"); + else + filestream_printf(file, " - Video Shader: %s (configured for %s)\n", !string_is_empty(shader_info.data->path) ? shader_info.data->path : "n/a", !string_is_empty(settings->paths.path_shader) ? settings->paths.path_shader : "n/a"); + } + else + filestream_printf(file, " - Video Shader: n/a\n"); + } + + filestream_printf(file, " - Audio:\n"); + filestream_printf(file, " - Audio Enabled: %s\n", settings->bools.audio_enable ? "yes" : "no (WARNING: content framerate will be incorrect)"); + filestream_printf(file, " - Audio Sync: %s\n", settings->bools.audio_sync ? "yes" : "no (WARNING: content framerate will be incorrect)"); + + { + const char *s = NULL; + + switch (settings->uints.audio_resampler_quality) + { + case RESAMPLER_QUALITY_DONTCARE: + s = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DONT_CARE); + break; + case RESAMPLER_QUALITY_LOWEST: + s = msg_hash_to_str(MSG_RESAMPLER_QUALITY_LOWEST); + break; + case RESAMPLER_QUALITY_LOWER: + s = msg_hash_to_str(MSG_RESAMPLER_QUALITY_LOWER); + break; + case RESAMPLER_QUALITY_HIGHER: + s = msg_hash_to_str(MSG_RESAMPLER_QUALITY_HIGHER); + break; + case RESAMPLER_QUALITY_HIGHEST: + s = msg_hash_to_str(MSG_RESAMPLER_QUALITY_HIGHEST); + break; + case RESAMPLER_QUALITY_NORMAL: + s = msg_hash_to_str(MSG_RESAMPLER_QUALITY_NORMAL); + break; + } + + filestream_printf(file, " - Resampler Quality: %s\n", !string_is_empty(s) ? s : "n/a"); + } + + filestream_printf(file, " - Audio Latency: %u ms\n", settings->uints.audio_latency); + filestream_printf(file, " - Dynamic Rate Control (DRC): %.3f\n", *audio_get_float_ptr(AUDIO_ACTION_RATE_CONTROL_DELTA)); + filestream_printf(file, " - Max Timing Skew: %.2f\n", settings->floats.audio_max_timing_skew); + filestream_printf(file, " - Output Rate: %u Hz\n", settings->uints.audio_out_rate); + filestream_printf(file, " - DSP Plugin: %s\n", !string_is_empty(settings->paths.path_audio_dsp_plugin) ? settings->paths.path_audio_dsp_plugin : "n/a"); + + filestream_close(file); + + RARCH_LOG("Wrote debug info to %s\n", debug_filepath); + + msg_hash_set_uint(MSG_HASH_USER_LANGUAGE, lang); + + return true; + +error: + return false; +} + +static void send_debug_info_cb(retro_task_t *task, + void *task_data, void *user_data, const char *error) +{ + if (task_data) + { + http_transfer_data_t *data = (http_transfer_data_t*)task_data; + + if (!data || data->len == 0) + { + RARCH_LOG("%s\n", msg_hash_to_str(MSG_FAILED_TO_SEND_DEBUG_INFO)); + + runloop_msg_queue_push( + msg_hash_to_str(MSG_FAILED_TO_SEND_DEBUG_INFO), + 2, 180, true, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_ERROR); + free(task_data); + return; + } + + /* don't use string_is_equal() here instead of the memcmp() because the data isn't NULL-terminated */ + if (!string_is_empty(data->data) && data->len >= 2 && !memcmp(data->data, "OK", 2)) + { + char buf[32] = {0}; + struct string_list *list; + + memcpy(buf, data->data, data->len); + + list = string_split(buf, " "); + + if (list && list->size > 1) + { + unsigned id = 0; + char msg[PATH_MAX_LENGTH]; + + msg[0] = '\0'; + + sscanf(list->elems[1].data, "%u", &id); + + snprintf(msg, sizeof(msg), msg_hash_to_str(MSG_SENT_DEBUG_INFO), id); + + RARCH_LOG("%s\n", msg); + + runloop_msg_queue_push( + msg, + 2, 600, true, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); + } + + if (list) + string_list_free(list); + } + else + { + RARCH_LOG("%s\n", msg_hash_to_str(MSG_FAILED_TO_SEND_DEBUG_INFO)); + + runloop_msg_queue_push( + msg_hash_to_str(MSG_FAILED_TO_SEND_DEBUG_INFO), + 2, 180, true, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_ERROR); + } + + free(task_data); + } + else + { + RARCH_LOG("%s\n", msg_hash_to_str(MSG_FAILED_TO_SEND_DEBUG_INFO)); + + runloop_msg_queue_push( + msg_hash_to_str(MSG_FAILED_TO_SEND_DEBUG_INFO), + 2, 180, true, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_ERROR); + } +} + +void rarch_send_debug_info(void) +{ + const char *url = "http://lobby.libretro.com/debuginfo/add/"; + char *info_buf = NULL; + const size_t param_buf_size = 65535; + char *param_buf = (char*)malloc(param_buf_size); + char *param_buf_tmp = NULL; + int param_buf_pos = 0; + int64_t len = 0; + char debug_filepath[PATH_MAX_LENGTH]; + const char *path_config = path_get(RARCH_PATH_CONFIG); + bool info_written = rarch_write_debug_info(); + + debug_filepath[0] = param_buf[0] = '\0'; + + fill_pathname_resolve_relative( + debug_filepath, + path_config, + DEBUG_INFO_FILENAME, + sizeof(debug_filepath)); + + if (info_written) + filestream_read_file(debug_filepath, (void**)&info_buf, &len); + + if (string_is_empty(info_buf) || len == 0 || !info_written) + { + runloop_msg_queue_push( + msg_hash_to_str(MSG_FAILED_TO_SAVE_DEBUG_INFO), + 2, 180, true, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_ERROR); + goto finish; + } + + RARCH_LOG("%s\n", msg_hash_to_str(MSG_SENDING_DEBUG_INFO)); + + runloop_msg_queue_push( + msg_hash_to_str(MSG_SENDING_DEBUG_INFO), + 2, 180, true, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); + + param_buf_pos = strlcpy(param_buf, "info=", param_buf_size); + param_buf_tmp = param_buf + param_buf_pos; + + net_http_urlencode(¶m_buf_tmp, info_buf); + + strlcat(param_buf, param_buf_tmp, param_buf_size - param_buf_pos); + + task_push_http_post_transfer(url, param_buf, true, NULL, send_debug_info_cb, NULL); + +finish: + if (param_buf) + free(param_buf); + if (info_buf) + free(info_buf); +} diff --git a/retroarch.h b/retroarch.h index 1727ef6ac7..721938f379 100644 --- a/retroarch.h +++ b/retroarch.h @@ -422,6 +422,12 @@ void rarch_force_video_driver_fallback(const char *driver); void rarch_core_runtime_tick(void); +void rarch_send_debug_info(void); + +bool rarch_write_debug_info(void); + +void rarch_get_cpu_architecture_string(char *cpu_arch_str, size_t len); + RETRO_END_DECLS #endif diff --git a/tasks/task_autodetect.c b/tasks/task_autodetect.c index cefce201df..ae4a3d7685 100644 --- a/tasks/task_autodetect.c +++ b/tasks/task_autodetect.c @@ -303,9 +303,15 @@ static void input_autoconfigure_joypad_add(config_file_t *conf, else input_config_set_device_display_name(params->idx, params->name); if (!string_is_empty(conf->path)) + { input_config_set_device_config_name(params->idx, path_basename(conf->path)); + input_config_set_device_config_path(params->idx, conf->path); + } else + { input_config_set_device_config_name(params->idx, "N/A"); + input_config_set_device_config_path(params->idx, "N/A"); + } input_autoconfigure_joypad_reindex_devices(); } @@ -862,7 +868,7 @@ static void input_autoconfigure_connect_handler(retro_task_t *task) free(params->name); params->name = strdup("Android Gamepad"); - if(input_autoconfigure_joypad_from_conf_internal(params, task)) + if (input_autoconfigure_joypad_from_conf_internal(params, task)) { RARCH_LOG("[Autoconf]: no profiles found for %s (%d/%d). Using fallback\n", !string_is_empty(params->name) ? params->name : "N/A", @@ -933,6 +939,7 @@ bool input_autoconfigure_disconnect(unsigned i, const char *ident) input_config_clear_device_name(state->idx); input_config_clear_device_display_name(state->idx); input_config_clear_device_config_name(state->idx); + input_config_clear_device_config_path(state->idx); task->state = state; task->handler = input_autoconfigure_disconnect_handler;