diff options
Diffstat (limited to '')
| -rw-r--r-- | src/yuzu/startup_checks.cpp | 82 | ||||
| -rw-r--r-- | src/yuzu/startup_checks.h | 4 |
2 files changed, 64 insertions, 22 deletions
diff --git a/src/yuzu/startup_checks.cpp b/src/yuzu/startup_checks.cpp index 6a91212e2..ccdcf10fa 100644 --- a/src/yuzu/startup_checks.cpp +++ b/src/yuzu/startup_checks.cpp | |||
| @@ -4,16 +4,19 @@ | |||
| 4 | #include "video_core/vulkan_common/vulkan_wrapper.h" | 4 | #include "video_core/vulkan_common/vulkan_wrapper.h" |
| 5 | 5 | ||
| 6 | #ifdef _WIN32 | 6 | #ifdef _WIN32 |
| 7 | #include <cstring> // for memset, strncpy | 7 | #include <cstring> |
| 8 | #include <processthreadsapi.h> | 8 | #include <processthreadsapi.h> |
| 9 | #include <windows.h> | 9 | #include <windows.h> |
| 10 | #elif defined(YUZU_UNIX) | 10 | #elif defined(YUZU_UNIX) |
| 11 | #include <cstring> | ||
| 11 | #include <errno.h> | 12 | #include <errno.h> |
| 13 | #include <spawn.h> | ||
| 14 | #include <sys/types.h> | ||
| 12 | #include <sys/wait.h> | 15 | #include <sys/wait.h> |
| 13 | #include <unistd.h> | 16 | #include <unistd.h> |
| 14 | #endif | 17 | #endif |
| 15 | 18 | ||
| 16 | #include <cstdio> | 19 | #include <fmt/core.h> |
| 17 | #include "video_core/vulkan_common/vulkan_instance.h" | 20 | #include "video_core/vulkan_common/vulkan_instance.h" |
| 18 | #include "video_core/vulkan_common/vulkan_library.h" | 21 | #include "video_core/vulkan_common/vulkan_library.h" |
| 19 | #include "yuzu/startup_checks.h" | 22 | #include "yuzu/startup_checks.h" |
| @@ -27,7 +30,7 @@ void CheckVulkan() { | |||
| 27 | Vulkan::CreateInstance(library, dld, VK_API_VERSION_1_0); | 30 | Vulkan::CreateInstance(library, dld, VK_API_VERSION_1_0); |
| 28 | 31 | ||
| 29 | } catch (const Vulkan::vk::Exception& exception) { | 32 | } catch (const Vulkan::vk::Exception& exception) { |
| 30 | std::fprintf(stderr, "Failed to initialize Vulkan: %s\n", exception.what()); | 33 | fmt::print(stderr, "Failed to initialize Vulkan: {}\n", exception.what()); |
| 31 | } | 34 | } |
| 32 | } | 35 | } |
| 33 | 36 | ||
| @@ -49,8 +52,15 @@ bool CheckEnvVars(bool* is_child) { | |||
| 49 | *is_child = true; | 52 | *is_child = true; |
| 50 | return false; | 53 | return false; |
| 51 | } else if (!SetEnvironmentVariableA(IS_CHILD_ENV_VAR, ENV_VAR_ENABLED_TEXT)) { | 54 | } else if (!SetEnvironmentVariableA(IS_CHILD_ENV_VAR, ENV_VAR_ENABLED_TEXT)) { |
| 52 | std::fprintf(stderr, "SetEnvironmentVariableA failed to set %s with error %lu\n", | 55 | fmt::print(stderr, "SetEnvironmentVariableA failed to set {} with error {}\n", |
| 53 | IS_CHILD_ENV_VAR, GetLastError()); | 56 | IS_CHILD_ENV_VAR, GetLastError()); |
| 57 | return true; | ||
| 58 | } | ||
| 59 | #elif defined(YUZU_UNIX) | ||
| 60 | const char* startup_check_var = getenv(STARTUP_CHECK_ENV_VAR); | ||
| 61 | if (startup_check_var != nullptr && | ||
| 62 | std::strncmp(startup_check_var, ENV_VAR_ENABLED_TEXT, 8) == 0) { | ||
| 63 | CheckVulkan(); | ||
| 54 | return true; | 64 | return true; |
| 55 | } | 65 | } |
| 56 | #endif | 66 | #endif |
| @@ -62,8 +72,8 @@ bool StartupChecks(const char* arg0, bool* has_broken_vulkan, bool perform_vulka | |||
| 62 | // Set the startup variable for child processes | 72 | // Set the startup variable for child processes |
| 63 | const bool env_var_set = SetEnvironmentVariableA(STARTUP_CHECK_ENV_VAR, ENV_VAR_ENABLED_TEXT); | 73 | const bool env_var_set = SetEnvironmentVariableA(STARTUP_CHECK_ENV_VAR, ENV_VAR_ENABLED_TEXT); |
| 64 | if (!env_var_set) { | 74 | if (!env_var_set) { |
| 65 | std::fprintf(stderr, "SetEnvironmentVariableA failed to set %s with error %lu\n", | 75 | fmt::print(stderr, "SetEnvironmentVariableA failed to set {} with error {}\n", |
| 66 | STARTUP_CHECK_ENV_VAR, GetLastError()); | 76 | STARTUP_CHECK_ENV_VAR, GetLastError()); |
| 67 | return false; | 77 | return false; |
| 68 | } | 78 | } |
| 69 | 79 | ||
| @@ -81,48 +91,57 @@ bool StartupChecks(const char* arg0, bool* has_broken_vulkan, bool perform_vulka | |||
| 81 | DWORD exit_code = STILL_ACTIVE; | 91 | DWORD exit_code = STILL_ACTIVE; |
| 82 | const int err = GetExitCodeProcess(process_info.hProcess, &exit_code); | 92 | const int err = GetExitCodeProcess(process_info.hProcess, &exit_code); |
| 83 | if (err == 0) { | 93 | if (err == 0) { |
| 84 | std::fprintf(stderr, "GetExitCodeProcess failed with error %lu\n", GetLastError()); | 94 | fmt::print(stderr, "GetExitCodeProcess failed with error {}\n", GetLastError()); |
| 85 | } | 95 | } |
| 86 | 96 | ||
| 87 | // Vulkan is broken if the child crashed (return value is not zero) | 97 | // Vulkan is broken if the child crashed (return value is not zero) |
| 88 | *has_broken_vulkan = (exit_code != 0); | 98 | *has_broken_vulkan = (exit_code != 0); |
| 89 | 99 | ||
| 90 | if (CloseHandle(process_info.hProcess) == 0) { | 100 | if (CloseHandle(process_info.hProcess) == 0) { |
| 91 | std::fprintf(stderr, "CloseHandle failed with error %lu\n", GetLastError()); | 101 | fmt::print(stderr, "CloseHandle failed with error {}\n", GetLastError()); |
| 92 | } | 102 | } |
| 93 | if (CloseHandle(process_info.hThread) == 0) { | 103 | if (CloseHandle(process_info.hThread) == 0) { |
| 94 | std::fprintf(stderr, "CloseHandle failed with error %lu\n", GetLastError()); | 104 | fmt::print(stderr, "CloseHandle failed with error {}\n", GetLastError()); |
| 95 | } | 105 | } |
| 96 | } | 106 | } |
| 97 | 107 | ||
| 98 | if (!SetEnvironmentVariableA(STARTUP_CHECK_ENV_VAR, nullptr)) { | 108 | if (!SetEnvironmentVariableA(STARTUP_CHECK_ENV_VAR, nullptr)) { |
| 99 | std::fprintf(stderr, "SetEnvironmentVariableA failed to clear %s with error %lu\n", | 109 | fmt::print(stderr, "SetEnvironmentVariableA failed to clear {} with error {}\n", |
| 100 | STARTUP_CHECK_ENV_VAR, GetLastError()); | 110 | STARTUP_CHECK_ENV_VAR, GetLastError()); |
| 101 | } | 111 | } |
| 102 | 112 | ||
| 103 | #elif defined(YUZU_UNIX) | 113 | #elif defined(YUZU_UNIX) |
| 114 | const int env_var_set = setenv(STARTUP_CHECK_ENV_VAR, ENV_VAR_ENABLED_TEXT, 1); | ||
| 115 | if (env_var_set == -1) { | ||
| 116 | const int err = errno; | ||
| 117 | fmt::print(stderr, "setenv failed to set {} with error {}\n", STARTUP_CHECK_ENV_VAR, err); | ||
| 118 | return false; | ||
| 119 | } | ||
| 120 | |||
| 104 | if (perform_vulkan_check) { | 121 | if (perform_vulkan_check) { |
| 105 | const pid_t pid = fork(); | 122 | const pid_t pid = SpawnChild(arg0); |
| 106 | if (pid == 0) { | 123 | if (pid == -1) { |
| 107 | CheckVulkan(); | ||
| 108 | return true; | ||
| 109 | } else if (pid == -1) { | ||
| 110 | const int err = errno; | ||
| 111 | std::fprintf(stderr, "fork failed with error %d\n", err); | ||
| 112 | return false; | 124 | return false; |
| 113 | } | 125 | } |
| 114 | 126 | ||
| 115 | // Get exit code from child process | 127 | // Get exit code from child process |
| 116 | int status; | 128 | int status; |
| 117 | const int r_val = wait(&status); | 129 | const int r_val = waitpid(pid, &status, 0); |
| 118 | if (r_val == -1) { | 130 | if (r_val == -1) { |
| 119 | const int err = errno; | 131 | const int err = errno; |
| 120 | std::fprintf(stderr, "wait failed with error %d\n", err); | 132 | fmt::print(stderr, "wait failed with error {}\n", err); |
| 121 | return false; | 133 | return false; |
| 122 | } | 134 | } |
| 123 | // Vulkan is broken if the child crashed (return value is not zero) | 135 | // Vulkan is broken if the child crashed (return value is not zero) |
| 124 | *has_broken_vulkan = (status != 0); | 136 | *has_broken_vulkan = (status != 0); |
| 125 | } | 137 | } |
| 138 | |||
| 139 | const int env_var_cleared = unsetenv(STARTUP_CHECK_ENV_VAR); | ||
| 140 | if (env_var_cleared == -1) { | ||
| 141 | const int err = errno; | ||
| 142 | fmt::print(stderr, "unsetenv failed to clear {} with error {}\n", STARTUP_CHECK_ENV_VAR, | ||
| 143 | err); | ||
| 144 | } | ||
| 126 | #endif | 145 | #endif |
| 127 | return false; | 146 | return false; |
| 128 | } | 147 | } |
| @@ -150,10 +169,29 @@ bool SpawnChild(const char* arg0, PROCESS_INFORMATION* pi, int flags) { | |||
| 150 | pi // lpProcessInformation | 169 | pi // lpProcessInformation |
| 151 | ); | 170 | ); |
| 152 | if (!process_created) { | 171 | if (!process_created) { |
| 153 | std::fprintf(stderr, "CreateProcessA failed with error %lu\n", GetLastError()); | 172 | fmt::print(stderr, "CreateProcessA failed with error {}\n", GetLastError()); |
| 154 | return false; | 173 | return false; |
| 155 | } | 174 | } |
| 156 | 175 | ||
| 157 | return true; | 176 | return true; |
| 158 | } | 177 | } |
| 178 | #elif defined(YUZU_UNIX) | ||
| 179 | pid_t SpawnChild(const char* arg0) { | ||
| 180 | const pid_t pid = fork(); | ||
| 181 | |||
| 182 | if (pid == -1) { | ||
| 183 | // error | ||
| 184 | const int err = errno; | ||
| 185 | fmt::print(stderr, "fork failed with error {}\n", err); | ||
| 186 | return pid; | ||
| 187 | } else if (pid == 0) { | ||
| 188 | // child | ||
| 189 | execl(arg0, arg0, nullptr); | ||
| 190 | const int err = errno; | ||
| 191 | fmt::print(stderr, "execl failed with error {}\n", err); | ||
| 192 | _exit(0); | ||
| 193 | } | ||
| 194 | |||
| 195 | return pid; | ||
| 196 | } | ||
| 159 | #endif | 197 | #endif |
diff --git a/src/yuzu/startup_checks.h b/src/yuzu/startup_checks.h index d8e563be6..2f86fb843 100644 --- a/src/yuzu/startup_checks.h +++ b/src/yuzu/startup_checks.h | |||
| @@ -5,6 +5,8 @@ | |||
| 5 | 5 | ||
| 6 | #ifdef _WIN32 | 6 | #ifdef _WIN32 |
| 7 | #include <windows.h> | 7 | #include <windows.h> |
| 8 | #elif defined(YUZU_UNIX) | ||
| 9 | #include <sys/types.h> | ||
| 8 | #endif | 10 | #endif |
| 9 | 11 | ||
| 10 | constexpr char IS_CHILD_ENV_VAR[] = "YUZU_IS_CHILD"; | 12 | constexpr char IS_CHILD_ENV_VAR[] = "YUZU_IS_CHILD"; |
| @@ -17,4 +19,6 @@ bool StartupChecks(const char* arg0, bool* has_broken_vulkan, bool perform_vulka | |||
| 17 | 19 | ||
| 18 | #ifdef _WIN32 | 20 | #ifdef _WIN32 |
| 19 | bool SpawnChild(const char* arg0, PROCESS_INFORMATION* pi, int flags); | 21 | bool SpawnChild(const char* arg0, PROCESS_INFORMATION* pi, int flags); |
| 22 | #elif defined(YUZU_UNIX) | ||
| 23 | pid_t SpawnChild(const char* arg0); | ||
| 20 | #endif | 24 | #endif |