Display message boxes for RT64 initialization errors

This commit is contained in:
Mr-Wiseguy 2024-05-18 18:01:57 -04:00
parent 70204430b2
commit cda63b8806
5 changed files with 83 additions and 3 deletions

View file

@ -8,6 +8,7 @@
namespace recomp {
constexpr std::u8string_view program_id = u8"Zelda64Recompiled";
constexpr std::u8string_view mm_game_id = u8"mm.n64.us.1.0";
constexpr std::string_view program_name = "Zelda 64: Recompiled";
void load_config();
void save_config();

View file

@ -9,12 +9,21 @@ namespace RT64 {
}
namespace ultramodern {
enum class RT64SetupResult {
Success,
DynamicLibrariesNotFound,
InvalidGraphicsAPI,
GraphicsAPINotFound,
GraphicsDeviceNotFound
};
struct WindowHandle;
struct RT64Context {
public:
~RT64Context();
RT64Context(uint8_t* rdram, WindowHandle window_handle, bool developer_mode);
bool valid() { return static_cast<bool>(app); }
RT64SetupResult get_setup_result() { return setup_result; }
void update_config(const GraphicsConfig& old_config, const GraphicsConfig& new_config);
void enable_instant_present();
@ -25,6 +34,7 @@ namespace ultramodern {
uint32_t get_display_framerate();
void load_shader_cache(std::span<const char> cache_binary);
private:
RT64SetupResult setup_result;
std::unique_ptr<RT64::Application> app;
};

View file

@ -8,6 +8,7 @@
#include "recomp_ui.h"
#include "recomp_input.h"
#include "recomp_game.h"
#include "recomp_config.h"
#include "ui_rml_hacks.hpp"
#include "concurrentqueue.h"
@ -1464,5 +1465,5 @@ recomp::Menu recomp::get_current_menu() {
}
void recomp::message_box(const char* msg) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Error", msg, nullptr);
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, recomp::program_name.data(), msg, nullptr);
}

View file

@ -16,6 +16,7 @@
#include "config.hpp"
#include "rt64_layer.h"
#include "recomp.h"
#include "recomp_game.h"
#include "recomp_ui.h"
#include "recomp_input.h"
#include "rsp.h"
@ -301,6 +302,8 @@ void ultramodern::load_shader_cache(std::span<const char> cache_data) {
events_context.action_queue.enqueue(LoadShaderCacheAction{cache_data});
}
std::atomic<ultramodern::RT64SetupResult> rt64_setup_result = ultramodern::RT64SetupResult::Success;
void gfx_thread_func(uint8_t* rdram, moodycamel::LightweightSemaphore* thread_ready, ultramodern::WindowHandle window_handle) {
bool enabled_instant_present = false;
using namespace std::chrono_literals;
@ -313,7 +316,11 @@ void gfx_thread_func(uint8_t* rdram, moodycamel::LightweightSemaphore* thread_re
ultramodern::RT64Context rt64{rdram, window_handle, cur_config.load().developer_mode};
if (!rt64.valid()) {
throw std::runtime_error("Failed to initialize RT64!");
// TODO move recomp code out of ultramodern.
rt64_setup_result.store(rt64.get_setup_result());
// Notify the caller thread that this thread is ready.
thread_ready->signal();
return;
}
// TODO move recomp code out of ultramodern.
@ -537,6 +544,27 @@ void ultramodern::send_si_message(RDRAM_ARG1) {
osSendMesg(PASS_RDRAM events_context.si.mq, events_context.si.msg, OS_MESG_NOBLOCK);
}
std::string get_graphics_api_name(ultramodern::GraphicsApi api) {
if (api == ultramodern::GraphicsApi::Auto) {
#if defined(_WIN32)
api = ultramodern::GraphicsApi::D3D12;
#elif defined(__gnu_linux__)
api = ultramodern::GraphicsApi::Vulkan;
#else
static_assert(false && "Unimplemented")
#endif
}
switch (api) {
case ultramodern::GraphicsApi::D3D12:
return "D3D12";
case ultramodern::GraphicsApi::Vulkan:
return "Vulkan";
default:
return "[Unknown graphics API]";
}
}
void ultramodern::init_events(RDRAM_ARG ultramodern::WindowHandle window_handle) {
moodycamel::LightweightSemaphore gfx_thread_ready;
moodycamel::LightweightSemaphore task_thread_ready;
@ -549,6 +577,30 @@ void ultramodern::init_events(RDRAM_ARG ultramodern::WindowHandle window_handle)
gfx_thread_ready.wait();
task_thread_ready.wait();
ultramodern::RT64SetupResult setup_result = rt64_setup_result.load();
if (rt64_setup_result != ultramodern::RT64SetupResult::Success) {
auto show_rt64_error = [](const std::string& msg) {
// TODO move recomp code out of ultramodern (message boxes).
recomp::message_box(("An error has been encountered on startup: " + msg).c_str());
};
const std::string driver_os_suffix = "\nPlease make sure your GPU drivers and your OS are up to date.";
switch (rt64_setup_result) {
case ultramodern::RT64SetupResult::DynamicLibrariesNotFound:
show_rt64_error("Failed to load dynamic libraries. Make sure the DLLs are next to the recomp executable.");
break;
case ultramodern::RT64SetupResult::InvalidGraphicsAPI:
show_rt64_error(get_graphics_api_name(cur_config.load().api_option) + " is not supported on this platform. Please select a different graphics API.");
break;
case ultramodern::RT64SetupResult::GraphicsAPINotFound:
show_rt64_error("Unable to initialize " + get_graphics_api_name(cur_config.load().api_option) + "." + driver_os_suffix);
break;
case ultramodern::RT64SetupResult::GraphicsDeviceNotFound:
show_rt64_error("Unable to find compatible graphics device." + driver_os_suffix);
break;
}
throw std::runtime_error("Failed to initialize RT64");
}
events_context.vi.thread = std::thread{ vi_thread_func };
}

View file

@ -97,6 +97,21 @@ void set_application_user_config(RT64::Application* application, const ultramode
application->userConfig.refreshRateTarget = config.rr_manual_value;
}
ultramodern::RT64SetupResult map_setup_result(RT64::Application::SetupResult rt64_result) {
switch (rt64_result) {
case RT64::Application::SetupResult::Success:
return ultramodern::RT64SetupResult::Success;
case RT64::Application::SetupResult::DynamicLibrariesNotFound:
return ultramodern::RT64SetupResult::DynamicLibrariesNotFound;
case RT64::Application::SetupResult::InvalidGraphicsAPI:
return ultramodern::RT64SetupResult::InvalidGraphicsAPI;
case RT64::Application::SetupResult::GraphicsAPINotFound:
return ultramodern::RT64SetupResult::GraphicsAPINotFound;
case RT64::Application::SetupResult::GraphicsDeviceNotFound:
return ultramodern::RT64SetupResult::GraphicsDeviceNotFound;
}
}
ultramodern::RT64Context::RT64Context(uint8_t* rdram, ultramodern::WindowHandle window_handle, bool debug) {
static unsigned char dummy_rom_header[0x40];
set_rt64_hooks();
@ -179,7 +194,8 @@ ultramodern::RT64Context::RT64Context(uint8_t* rdram, ultramodern::WindowHandle
#ifdef _WIN32
thread_id = window_handle.thread_id;
#endif
if (app->setup(thread_id) != RT64::Application::SetupResult::Success) {
setup_result = map_setup_result(app->setup(thread_id));
if (setup_result != ultramodern::RT64SetupResult::Success) {
app = nullptr;
return;
}