Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 42 additions & 3 deletions UnleashedRecomp/gpu/video.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include <user/config.h>
#include <sdl_listener.h>
#include <xxHashMap.h>
#include <os/process.h>

#if defined(ASYNC_PSO_DEBUG) || defined(PSO_CACHING)
#include <magic_enum/magic_enum.hpp>
Expand Down Expand Up @@ -1651,7 +1652,7 @@ static void ApplyLowEndDefaults()
}
}

bool Video::CreateHostDevice(const char *sdlVideoDriver)
bool Video::CreateHostDevice(const char *sdlVideoDriver, bool graphicsApiRetry)
{
for (uint32_t i = 0; i < 16; i++)
g_inputSlots[i].index = i;
Expand All @@ -1671,6 +1672,12 @@ bool Video::CreateHostDevice(const char *sdlVideoDriver)
std::vector<RenderInterfaceFunction *> interfaceFunctions;

#ifdef UNLEASHED_RECOMP_D3D12
if (graphicsApiRetry)
{
// If we are attempting to create again after a reboot due to a crash, swap the order.
g_vulkan = !g_vulkan;
}

interfaceFunctions.push_back(g_vulkan ? CreateVulkanInterfaceWrapper : CreateD3D12Interface);
interfaceFunctions.push_back(g_vulkan ? CreateD3D12Interface : CreateVulkanInterfaceWrapper);
#else
Expand All @@ -1679,9 +1686,17 @@ bool Video::CreateHostDevice(const char *sdlVideoDriver)

for (RenderInterfaceFunction *interfaceFunction : interfaceFunctions)
{
g_interface = interfaceFunction();
if (g_interface != nullptr)
#ifdef UNLEASHED_RECOMP_D3D12
// Wrap the device creation in __try/__except to survive from driver crashes.
__try
#endif
{
g_interface = interfaceFunction();
if (g_interface == nullptr)
{
continue;
}

g_device = g_interface->createDevice(Config::GraphicsDevice);
if (g_device != nullptr)
{
Expand Down Expand Up @@ -1718,13 +1733,37 @@ bool Video::CreateHostDevice(const char *sdlVideoDriver)
break;
}
}
#ifdef UNLEASHED_RECOMP_D3D12
__except (EXCEPTION_EXECUTE_HANDLER)
{
if (graphicsApiRetry)
{
// If we were retrying, and this also failed, then we'll show the user neither of the graphics APIs succeeded.
return false;
}
else
{
// If this is the first crash we ran into, reboot and try the other graphics API.
os::process::StartProcess(os::process::GetExecutablePath(), { "--graphics-api-retry" });
std::_Exit(0);
}
}
#endif
}

if (g_device == nullptr)
{
return false;
}

#ifdef UNLEASHED_RECOMP_D3D12
if (graphicsApiRetry)
{
// If we managed to create a device after retrying it in a reboot, remember the one we picked.
Config::GraphicsAPI = g_vulkan ? EGraphicsAPI::Vulkan : EGraphicsAPI::D3D12;
}
#endif

g_capabilities = g_device->getCapabilities();

LoadEmbeddedResources();
Expand Down
2 changes: 1 addition & 1 deletion UnleashedRecomp/gpu/video.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ struct Video
static inline uint32_t s_viewportWidth;
static inline uint32_t s_viewportHeight;

static bool CreateHostDevice(const char *sdlVideoDriver);
static bool CreateHostDevice(const char *sdlVideoDriver, bool graphicsApiRetry);
static void WaitOnSwapChain();
static void Present();
static void StartPipelinePrecompilation();
Expand Down
6 changes: 4 additions & 2 deletions UnleashedRecomp/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ int main(int argc, char *argv[])
bool forceDLCInstaller = false;
bool useDefaultWorkingDirectory = false;
bool forceInstallationCheck = false;
bool graphicsApiRetry = false;
const char *sdlVideoDriver = nullptr;

for (uint32_t i = 1; i < argc; i++)
Expand All @@ -210,6 +211,7 @@ int main(int argc, char *argv[])
forceDLCInstaller = forceDLCInstaller || (strcmp(argv[i], "--install-dlc") == 0);
useDefaultWorkingDirectory = useDefaultWorkingDirectory || (strcmp(argv[i], "--use-cwd") == 0);
forceInstallationCheck = forceInstallationCheck || (strcmp(argv[i], "--install-check") == 0);
graphicsApiRetry = graphicsApiRetry || (strcmp(argv[i], "--graphics-api-retry") == 0);

if (strcmp(argv[i], "--sdl-video-driver") == 0)
{
Expand Down Expand Up @@ -320,7 +322,7 @@ int main(int argc, char *argv[])
bool runInstallerWizard = forceInstaller || forceDLCInstaller || !isGameInstalled;
if (runInstallerWizard)
{
if (!Video::CreateHostDevice(sdlVideoDriver))
if (!Video::CreateHostDevice(sdlVideoDriver, graphicsApiRetry))
{
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, GameWindow::GetTitle(), Localise("Video_BackendError").c_str(), GameWindow::s_pWindow);
std::_Exit(1);
Expand All @@ -340,7 +342,7 @@ int main(int argc, char *argv[])

if (!runInstallerWizard)
{
if (!Video::CreateHostDevice(sdlVideoDriver))
if (!Video::CreateHostDevice(sdlVideoDriver, graphicsApiRetry))
{
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, GameWindow::GetTitle(), Localise("Video_BackendError").c_str(), GameWindow::s_pWindow);
std::_Exit(1);
Expand Down