From 54d5588d7976bb224001e8d418e3c6b4d361ddb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dar=C3=ADo?= Date: Fri, 31 Jan 2025 09:45:48 -0300 Subject: [PATCH] Add fallback for creating other video backends. (#254) * Add fallback for creating other video backends. * Update video.cpp --- UnleashedRecomp/gpu/video.cpp | 55 ++++++++++++++++++++++++------- UnleashedRecomp/gpu/video.h | 2 +- UnleashedRecomp/locale/locale.cpp | 6 ++++ UnleashedRecomp/main.cpp | 15 +++++++-- UnleashedRecomp/ui/game_window.h | 2 +- 5 files changed, 65 insertions(+), 15 deletions(-) diff --git a/UnleashedRecomp/gpu/video.cpp b/UnleashedRecomp/gpu/video.cpp index 9baf2f61..3547b08a 100644 --- a/UnleashedRecomp/gpu/video.cpp +++ b/UnleashedRecomp/gpu/video.cpp @@ -95,6 +95,14 @@ namespace plume #else extern std::unique_ptr CreateVulkanInterface(); #endif + + static std::unique_ptr CreateVulkanInterfaceWrapper() { +#ifdef SDL_VULKAN_ENABLED + return CreateVulkanInterface(GameWindow::s_renderWindow); +#else + return CreateVulkanInterface(); +#endif + } } #pragma pack(push, 1) @@ -1472,7 +1480,7 @@ static void BeginCommandList() commandList->setGraphicsDescriptorSet(g_samplerDescriptorSet.get(), 3); } -void Video::CreateHostDevice(const char *sdlVideoDriver) +bool Video::CreateHostDevice(const char *sdlVideoDriver) { for (uint32_t i = 0; i < 16; i++) g_inputSlots[i].index = i; @@ -1487,20 +1495,39 @@ void Video::CreateHostDevice(const char *sdlVideoDriver) g_vulkan = DetectWine() || Config::GraphicsAPI == EGraphicsAPI::Vulkan; #endif - LoadEmbeddedResources(); + // Attempt to create the possible backends using a vector of function pointers. Whichever succeeds first will be the chosen API. + using RenderInterfaceFunction = std::unique_ptr(void); + std::vector interfaceFunctions; - if (g_vulkan) -#ifdef SDL_VULKAN_ENABLED - g_interface = CreateVulkanInterface(GameWindow::s_renderWindow); -#else - g_interface = CreateVulkanInterface(); -#endif #ifdef UNLEASHED_RECOMP_D3D12 - else - g_interface = CreateD3D12Interface(); + interfaceFunctions.push_back(g_vulkan ? CreateVulkanInterfaceWrapper : CreateD3D12Interface); + interfaceFunctions.push_back(g_vulkan ? CreateD3D12Interface : CreateVulkanInterfaceWrapper); +#else + interfaceFunctions.push_back(CreateVulkanInterfaceWrapper); #endif - g_device = g_interface->createDevice(); + for (RenderInterfaceFunction *interfaceFunction : interfaceFunctions) + { + g_interface = interfaceFunction(); + if (g_interface != nullptr) + { + g_device = g_interface->createDevice(); + if (g_device != nullptr) + { +#ifdef UNLEASHED_RECOMP_D3D12 + g_vulkan = (interfaceFunction == CreateVulkanInterfaceWrapper); +#endif + break; + } + } + } + + if (g_device == nullptr) + { + return false; + } + + LoadEmbeddedResources(); g_capabilities = g_device->getCapabilities(); @@ -1712,6 +1739,8 @@ void Video::CreateHostDevice(const char *sdlVideoDriver) blankTextureBarriers[i] = RenderTextureBarrier(g_blankTextures[i].get(), RenderTextureLayout::SHADER_READ); g_commandLists[g_frame]->barriers(RenderBarrierStage::NONE, blankTextureBarriers, std::size(blankTextureBarriers)); + + return true; } void Video::WaitForGPU() @@ -2068,6 +2097,10 @@ static void DrawProfiler() ImGui::Text("Triangle Fan: %s", g_capabilities.triangleFan ? "Supported" : "Unsupported"); ImGui::NewLine(); + ImGui::Text("API: %s", g_vulkan ? "Vulkan" : "D3D12"); + ImGui::Text("Device: %s", g_device->getDescription().name.c_str()); + ImGui::Text("VRAM: %.2f MiB", (double)(g_device->getDescription().dedicatedVideoMemory) / (1024.0 * 1024.0)); + const char* sdlVideoDriver = SDL_GetCurrentVideoDriver(); if (sdlVideoDriver != nullptr) ImGui::Text("SDL Video Driver: %s", sdlVideoDriver); diff --git a/UnleashedRecomp/gpu/video.h b/UnleashedRecomp/gpu/video.h index ae5c0653..43376031 100644 --- a/UnleashedRecomp/gpu/video.h +++ b/UnleashedRecomp/gpu/video.h @@ -18,7 +18,7 @@ struct Video static inline uint32_t s_viewportWidth; static inline uint32_t s_viewportHeight; - static void CreateHostDevice(const char *sdlVideoDriver); + static bool CreateHostDevice(const char *sdlVideoDriver); static void WaitOnSwapChain(); static void Present(); static void StartPipelinePrecompilation(); diff --git a/UnleashedRecomp/locale/locale.cpp b/UnleashedRecomp/locale/locale.cpp index cd8dc643..c72f78c7 100644 --- a/UnleashedRecomp/locale/locale.cpp +++ b/UnleashedRecomp/locale/locale.cpp @@ -377,6 +377,12 @@ std::unordered_map> g_lo { ELanguage::English, "The achievement data could not be loaded.\nYour achievements will not be saved." } } }, + { + "Video_BackendError", + { + { ELanguage::English, "Unable to create a D3D12 (Windows) or Vulkan backend.\n\nPlease make sure that:\n\n- Your system meets the minimum requirements.\n- Your GPU drivers are up to date.\n- Your operating system is on the latest version available." }, + } + }, { "Common_On", { diff --git a/UnleashedRecomp/main.cpp b/UnleashedRecomp/main.cpp index 65aaab3e..96355e9f 100644 --- a/UnleashedRecomp/main.cpp +++ b/UnleashedRecomp/main.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -182,7 +183,11 @@ int main(int argc, char *argv[]) bool runInstallerWizard = forceInstaller || forceDLCInstaller || !isGameInstalled; if (runInstallerWizard) { - Video::CreateHostDevice(sdlVideoDriver); + if (!Video::CreateHostDevice(sdlVideoDriver)) + { + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, GameWindow::GetTitle(), Localise("Video_BackendError").c_str(), GameWindow::s_pWindow); + return 1; + } if (!InstallerWizard::Run(GAME_INSTALL_DIRECTORY, isGameInstalled && forceDLCInstaller)) { @@ -197,7 +202,13 @@ int main(int argc, char *argv[]) uint32_t entry = LdrLoadModule(modulePath); if (!runInstallerWizard) - Video::CreateHostDevice(sdlVideoDriver); + { + if (!Video::CreateHostDevice(sdlVideoDriver)) + { + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, GameWindow::GetTitle(), Localise("Video_BackendError").c_str(), GameWindow::s_pWindow); + return 1; + } + } Video::StartPipelinePrecompilation(); diff --git a/UnleashedRecomp/ui/game_window.h b/UnleashedRecomp/ui/game_window.h index 0ede5c12..5f51b2fd 100644 --- a/UnleashedRecomp/ui/game_window.h +++ b/UnleashedRecomp/ui/game_window.h @@ -12,7 +12,7 @@ class GameWindow { public: - static inline SDL_Window* s_pWindow; + static inline SDL_Window* s_pWindow = nullptr; static inline plume::RenderWindow s_renderWindow; static inline int s_x;