Browse Source
Merge pull request #8564 from lat9nq/dinner-fork
Merge pull request #8564 from lat9nq/dinner-fork
yuzu: Streamline broken Vulkan handlingnce_cpp
committed by
GitHub
12 changed files with 181 additions and 124 deletions
-
4src/yuzu/CMakeLists.txt
-
53src/yuzu/check_vulkan.cpp
-
6src/yuzu/check_vulkan.h
-
8src/yuzu/configuration/config.cpp
-
37src/yuzu/configuration/configure_graphics.cpp
-
2src/yuzu/configuration/configure_graphics.h
-
9src/yuzu/configuration/configure_graphics.ui
-
29src/yuzu/main.cpp
-
2src/yuzu/main.h
-
136src/yuzu/startup_checks.cpp
-
17src/yuzu/startup_checks.h
-
2src/yuzu/uisettings.h
@ -1,53 +0,0 @@ |
|||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||
|
|
||||
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
|
||||
|
|
||||
#include <filesystem>
|
|
||||
#include <fstream>
|
|
||||
#include "common/fs/fs.h"
|
|
||||
#include "common/fs/path_util.h"
|
|
||||
#include "common/logging/log.h"
|
|
||||
#include "video_core/vulkan_common/vulkan_instance.h"
|
|
||||
#include "video_core/vulkan_common/vulkan_library.h"
|
|
||||
#include "yuzu/check_vulkan.h"
|
|
||||
#include "yuzu/uisettings.h"
|
|
||||
|
|
||||
constexpr char TEMP_FILE_NAME[] = "vulkan_check"; |
|
||||
|
|
||||
bool CheckVulkan() { |
|
||||
if (UISettings::values.has_broken_vulkan) { |
|
||||
return true; |
|
||||
} |
|
||||
|
|
||||
LOG_DEBUG(Frontend, "Checking presence of Vulkan"); |
|
||||
|
|
||||
const auto fs_config_loc = Common::FS::GetYuzuPath(Common::FS::YuzuPath::ConfigDir); |
|
||||
const auto temp_file_loc = fs_config_loc / TEMP_FILE_NAME; |
|
||||
|
|
||||
if (std::filesystem::exists(temp_file_loc)) { |
|
||||
LOG_WARNING(Frontend, "Detected recovery from previous failed Vulkan initialization"); |
|
||||
|
|
||||
UISettings::values.has_broken_vulkan = true; |
|
||||
std::filesystem::remove(temp_file_loc); |
|
||||
return false; |
|
||||
} |
|
||||
|
|
||||
std::ofstream temp_file_handle(temp_file_loc); |
|
||||
temp_file_handle.close(); |
|
||||
|
|
||||
try { |
|
||||
Vulkan::vk::InstanceDispatch dld; |
|
||||
const Common::DynamicLibrary library = Vulkan::OpenLibrary(); |
|
||||
const Vulkan::vk::Instance instance = |
|
||||
Vulkan::CreateInstance(library, dld, VK_API_VERSION_1_0); |
|
||||
|
|
||||
} catch (const Vulkan::vk::Exception& exception) { |
|
||||
LOG_ERROR(Frontend, "Failed to initialize Vulkan: {}", exception.what()); |
|
||||
// Don't set has_broken_vulkan to true here: we care when loading Vulkan crashes the
|
|
||||
// application, not when we can handle it.
|
|
||||
} |
|
||||
|
|
||||
std::filesystem::remove(temp_file_loc); |
|
||||
return true; |
|
||||
} |
|
||||
@ -1,6 +0,0 @@ |
|||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project |
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
|
|
||||
#pragma once |
|
||||
|
|
||||
bool CheckVulkan(); |
|
||||
@ -0,0 +1,136 @@ |
|||||
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
|
||||
|
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
||||
|
|
||||
|
#ifdef _WIN32
|
||||
|
#include <cstring> // for memset, strncpy
|
||||
|
#include <processthreadsapi.h>
|
||||
|
#include <windows.h>
|
||||
|
#elif defined(YUZU_UNIX)
|
||||
|
#include <errno.h>
|
||||
|
#include <sys/wait.h>
|
||||
|
#include <unistd.h>
|
||||
|
#endif
|
||||
|
|
||||
|
#include <cstdio>
|
||||
|
#include "video_core/vulkan_common/vulkan_instance.h"
|
||||
|
#include "video_core/vulkan_common/vulkan_library.h"
|
||||
|
#include "yuzu/startup_checks.h"
|
||||
|
|
||||
|
void CheckVulkan() { |
||||
|
// Just start the Vulkan loader, this will crash if something is wrong
|
||||
|
try { |
||||
|
Vulkan::vk::InstanceDispatch dld; |
||||
|
const Common::DynamicLibrary library = Vulkan::OpenLibrary(); |
||||
|
const Vulkan::vk::Instance instance = |
||||
|
Vulkan::CreateInstance(library, dld, VK_API_VERSION_1_0); |
||||
|
|
||||
|
} catch (const Vulkan::vk::Exception& exception) { |
||||
|
std::fprintf(stderr, "Failed to initialize Vulkan: %s\n", exception.what()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
bool StartupChecks(const char* arg0, bool* has_broken_vulkan) { |
||||
|
#ifdef _WIN32
|
||||
|
// Check environment variable to see if we are the child
|
||||
|
char variable_contents[8]; |
||||
|
const DWORD startup_check_var = |
||||
|
GetEnvironmentVariableA(STARTUP_CHECK_ENV_VAR, variable_contents, 8); |
||||
|
if (startup_check_var > 0 && std::strncmp(variable_contents, "ON", 8) == 0) { |
||||
|
CheckVulkan(); |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
// Set the startup variable for child processes
|
||||
|
const bool env_var_set = SetEnvironmentVariableA(STARTUP_CHECK_ENV_VAR, "ON"); |
||||
|
if (!env_var_set) { |
||||
|
std::fprintf(stderr, "SetEnvironmentVariableA failed to set %s with error %d\n", |
||||
|
STARTUP_CHECK_ENV_VAR, GetLastError()); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
PROCESS_INFORMATION process_info; |
||||
|
std::memset(&process_info, '\0', sizeof(process_info)); |
||||
|
|
||||
|
if (!SpawnChild(arg0, &process_info)) { |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
// Wait until the processs exits and get exit code from it
|
||||
|
WaitForSingleObject(process_info.hProcess, INFINITE); |
||||
|
DWORD exit_code = STILL_ACTIVE; |
||||
|
const int err = GetExitCodeProcess(process_info.hProcess, &exit_code); |
||||
|
if (err == 0) { |
||||
|
std::fprintf(stderr, "GetExitCodeProcess failed with error %d\n", GetLastError()); |
||||
|
} |
||||
|
|
||||
|
// Vulkan is broken if the child crashed (return value is not zero)
|
||||
|
*has_broken_vulkan = (exit_code != 0); |
||||
|
|
||||
|
if (CloseHandle(process_info.hProcess) == 0) { |
||||
|
std::fprintf(stderr, "CloseHandle failed with error %d\n", GetLastError()); |
||||
|
} |
||||
|
if (CloseHandle(process_info.hThread) == 0) { |
||||
|
std::fprintf(stderr, "CloseHandle failed with error %d\n", GetLastError()); |
||||
|
} |
||||
|
|
||||
|
if (!SetEnvironmentVariableA(STARTUP_CHECK_ENV_VAR, nullptr)) { |
||||
|
std::fprintf(stderr, "SetEnvironmentVariableA failed to clear %s with error %d\n", |
||||
|
STARTUP_CHECK_ENV_VAR, GetLastError()); |
||||
|
} |
||||
|
|
||||
|
#elif defined(YUZU_UNIX)
|
||||
|
const pid_t pid = fork(); |
||||
|
if (pid == 0) { |
||||
|
CheckVulkan(); |
||||
|
return true; |
||||
|
} else if (pid == -1) { |
||||
|
const int err = errno; |
||||
|
std::fprintf(stderr, "fork failed with error %d\n", err); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
// Get exit code from child process
|
||||
|
int status; |
||||
|
const int r_val = wait(&status); |
||||
|
if (r_val == -1) { |
||||
|
const int err = errno; |
||||
|
std::fprintf(stderr, "wait failed with error %d\n", err); |
||||
|
return false; |
||||
|
} |
||||
|
// Vulkan is broken if the child crashed (return value is not zero)
|
||||
|
*has_broken_vulkan = (status != 0); |
||||
|
#endif
|
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
#ifdef _WIN32
|
||||
|
bool SpawnChild(const char* arg0, PROCESS_INFORMATION* pi) { |
||||
|
STARTUPINFOA startup_info; |
||||
|
|
||||
|
std::memset(&startup_info, '\0', sizeof(startup_info)); |
||||
|
startup_info.cb = sizeof(startup_info); |
||||
|
|
||||
|
char p_name[255]; |
||||
|
std::strncpy(p_name, arg0, 255); |
||||
|
|
||||
|
const bool process_created = CreateProcessA(nullptr, // lpApplicationName
|
||||
|
p_name, // lpCommandLine
|
||||
|
nullptr, // lpProcessAttributes
|
||||
|
nullptr, // lpThreadAttributes
|
||||
|
false, // bInheritHandles
|
||||
|
0, // dwCreationFlags
|
||||
|
nullptr, // lpEnvironment
|
||||
|
nullptr, // lpCurrentDirectory
|
||||
|
&startup_info, // lpStartupInfo
|
||||
|
pi // lpProcessInformation
|
||||
|
); |
||||
|
if (!process_created) { |
||||
|
std::fprintf(stderr, "CreateProcessA failed with error %d\n", GetLastError()); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
return true; |
||||
|
} |
||||
|
#endif
|
||||
@ -0,0 +1,17 @@ |
|||||
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project |
||||
|
// SPDX-License-Identifier: GPL-2.0-or-later |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#ifdef _WIN32 |
||||
|
#include <windows.h> |
||||
|
#endif |
||||
|
|
||||
|
constexpr char STARTUP_CHECK_ENV_VAR[] = "YUZU_DO_STARTUP_CHECKS"; |
||||
|
|
||||
|
void CheckVulkan(); |
||||
|
bool StartupChecks(const char* arg0, bool* has_broken_vulkan); |
||||
|
|
||||
|
#ifdef _WIN32 |
||||
|
bool SpawnChild(const char* arg0, PROCESS_INFORMATION* pi); |
||||
|
#endif |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue