mirror of
https://github.com/yuzu-emu/yuzu.git
synced 2024-07-04 23:31:19 +01:00
Merge pull request #8564 from lat9nq/dinner-fork
yuzu: Streamline broken Vulkan handling
This commit is contained in:
commit
1bcde9dd98
12 changed files with 181 additions and 124 deletions
|
@ -30,8 +30,6 @@ add_executable(yuzu
|
||||||
applets/qt_web_browser_scripts.h
|
applets/qt_web_browser_scripts.h
|
||||||
bootmanager.cpp
|
bootmanager.cpp
|
||||||
bootmanager.h
|
bootmanager.h
|
||||||
check_vulkan.cpp
|
|
||||||
check_vulkan.h
|
|
||||||
compatdb.ui
|
compatdb.ui
|
||||||
compatibility_list.cpp
|
compatibility_list.cpp
|
||||||
compatibility_list.h
|
compatibility_list.h
|
||||||
|
@ -158,6 +156,8 @@ add_executable(yuzu
|
||||||
main.cpp
|
main.cpp
|
||||||
main.h
|
main.h
|
||||||
main.ui
|
main.ui
|
||||||
|
startup_checks.cpp
|
||||||
|
startup_checks.h
|
||||||
uisettings.cpp
|
uisettings.cpp
|
||||||
uisettings.h
|
uisettings.h
|
||||||
util/controller_navigation.cpp
|
util/controller_navigation.cpp
|
||||||
|
|
|
@ -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();
|
|
|
@ -688,12 +688,6 @@ void Config::ReadRendererValues() {
|
||||||
ReadGlobalSetting(Settings::values.bg_green);
|
ReadGlobalSetting(Settings::values.bg_green);
|
||||||
ReadGlobalSetting(Settings::values.bg_blue);
|
ReadGlobalSetting(Settings::values.bg_blue);
|
||||||
|
|
||||||
if (!global && UISettings::values.has_broken_vulkan &&
|
|
||||||
Settings::values.renderer_backend.GetValue() == Settings::RendererBackend::Vulkan &&
|
|
||||||
!Settings::values.renderer_backend.UsingGlobal()) {
|
|
||||||
Settings::values.renderer_backend.SetGlobal(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (global) {
|
if (global) {
|
||||||
ReadBasicSetting(Settings::values.renderer_debug);
|
ReadBasicSetting(Settings::values.renderer_debug);
|
||||||
ReadBasicSetting(Settings::values.renderer_shader_feedback);
|
ReadBasicSetting(Settings::values.renderer_shader_feedback);
|
||||||
|
@ -813,7 +807,6 @@ void Config::ReadUIValues() {
|
||||||
ReadBasicSetting(UISettings::values.pause_when_in_background);
|
ReadBasicSetting(UISettings::values.pause_when_in_background);
|
||||||
ReadBasicSetting(UISettings::values.mute_when_in_background);
|
ReadBasicSetting(UISettings::values.mute_when_in_background);
|
||||||
ReadBasicSetting(UISettings::values.hide_mouse);
|
ReadBasicSetting(UISettings::values.hide_mouse);
|
||||||
ReadBasicSetting(UISettings::values.has_broken_vulkan);
|
|
||||||
ReadBasicSetting(UISettings::values.disable_web_applet);
|
ReadBasicSetting(UISettings::values.disable_web_applet);
|
||||||
|
|
||||||
qt_config->endGroup();
|
qt_config->endGroup();
|
||||||
|
@ -1367,7 +1360,6 @@ void Config::SaveUIValues() {
|
||||||
WriteBasicSetting(UISettings::values.pause_when_in_background);
|
WriteBasicSetting(UISettings::values.pause_when_in_background);
|
||||||
WriteBasicSetting(UISettings::values.mute_when_in_background);
|
WriteBasicSetting(UISettings::values.mute_when_in_background);
|
||||||
WriteBasicSetting(UISettings::values.hide_mouse);
|
WriteBasicSetting(UISettings::values.hide_mouse);
|
||||||
WriteBasicSetting(UISettings::values.has_broken_vulkan);
|
|
||||||
WriteBasicSetting(UISettings::values.disable_web_applet);
|
WriteBasicSetting(UISettings::values.disable_web_applet);
|
||||||
|
|
||||||
qt_config->endGroup();
|
qt_config->endGroup();
|
||||||
|
|
|
@ -58,24 +58,9 @@ ConfigureGraphics::ConfigureGraphics(const Core::System& system_, QWidget* paren
|
||||||
UpdateBackgroundColorButton(new_bg_color);
|
UpdateBackgroundColorButton(new_bg_color);
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(ui->button_check_vulkan, &QAbstractButton::clicked, this, [this] {
|
ui->api->setEnabled(!UISettings::values.has_broken_vulkan);
|
||||||
UISettings::values.has_broken_vulkan = false;
|
ui->api_widget->setEnabled(!UISettings::values.has_broken_vulkan ||
|
||||||
|
Settings::IsConfiguringGlobal());
|
||||||
if (RetrieveVulkanDevices()) {
|
|
||||||
ui->api->setEnabled(true);
|
|
||||||
ui->button_check_vulkan->hide();
|
|
||||||
|
|
||||||
for (const auto& device : vulkan_devices) {
|
|
||||||
ui->device->addItem(device);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
UISettings::values.has_broken_vulkan = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
ui->api->setEnabled(!UISettings::values.has_broken_vulkan.GetValue());
|
|
||||||
ui->button_check_vulkan->setVisible(UISettings::values.has_broken_vulkan.GetValue());
|
|
||||||
|
|
||||||
ui->bg_label->setVisible(Settings::IsConfiguringGlobal());
|
ui->bg_label->setVisible(Settings::IsConfiguringGlobal());
|
||||||
ui->bg_combobox->setVisible(!Settings::IsConfiguringGlobal());
|
ui->bg_combobox->setVisible(!Settings::IsConfiguringGlobal());
|
||||||
}
|
}
|
||||||
|
@ -315,7 +300,7 @@ void ConfigureGraphics::UpdateAPILayout() {
|
||||||
vulkan_device = Settings::values.vulkan_device.GetValue(true);
|
vulkan_device = Settings::values.vulkan_device.GetValue(true);
|
||||||
shader_backend = Settings::values.shader_backend.GetValue(true);
|
shader_backend = Settings::values.shader_backend.GetValue(true);
|
||||||
ui->device_widget->setEnabled(false);
|
ui->device_widget->setEnabled(false);
|
||||||
ui->backend_widget->setEnabled(UISettings::values.has_broken_vulkan.GetValue());
|
ui->backend_widget->setEnabled(false);
|
||||||
} else {
|
} else {
|
||||||
vulkan_device = Settings::values.vulkan_device.GetValue();
|
vulkan_device = Settings::values.vulkan_device.GetValue();
|
||||||
shader_backend = Settings::values.shader_backend.GetValue();
|
shader_backend = Settings::values.shader_backend.GetValue();
|
||||||
|
@ -337,9 +322,9 @@ void ConfigureGraphics::UpdateAPILayout() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ConfigureGraphics::RetrieveVulkanDevices() try {
|
void ConfigureGraphics::RetrieveVulkanDevices() try {
|
||||||
if (UISettings::values.has_broken_vulkan) {
|
if (UISettings::values.has_broken_vulkan) {
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
using namespace Vulkan;
|
using namespace Vulkan;
|
||||||
|
@ -355,11 +340,8 @@ bool ConfigureGraphics::RetrieveVulkanDevices() try {
|
||||||
const std::string name = vk::PhysicalDevice(device, dld).GetProperties().deviceName;
|
const std::string name = vk::PhysicalDevice(device, dld).GetProperties().deviceName;
|
||||||
vulkan_devices.push_back(QString::fromStdString(name));
|
vulkan_devices.push_back(QString::fromStdString(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
} catch (const Vulkan::vk::Exception& exception) {
|
} catch (const Vulkan::vk::Exception& exception) {
|
||||||
LOG_ERROR(Frontend, "Failed to enumerate devices with error: {}", exception.what());
|
LOG_ERROR(Frontend, "Failed to enumerate devices with error: {}", exception.what());
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Settings::RendererBackend ConfigureGraphics::GetCurrentGraphicsBackend() const {
|
Settings::RendererBackend ConfigureGraphics::GetCurrentGraphicsBackend() const {
|
||||||
|
@ -440,11 +422,4 @@ void ConfigureGraphics::SetupPerGameUI() {
|
||||||
ui->api, static_cast<int>(Settings::values.renderer_backend.GetValue(true)));
|
ui->api, static_cast<int>(Settings::values.renderer_backend.GetValue(true)));
|
||||||
ConfigurationShared::InsertGlobalItem(
|
ConfigurationShared::InsertGlobalItem(
|
||||||
ui->nvdec_emulation, static_cast<int>(Settings::values.nvdec_emulation.GetValue(true)));
|
ui->nvdec_emulation, static_cast<int>(Settings::values.nvdec_emulation.GetValue(true)));
|
||||||
|
|
||||||
if (UISettings::values.has_broken_vulkan) {
|
|
||||||
ui->backend_widget->setEnabled(true);
|
|
||||||
ConfigurationShared::SetColoredComboBox(
|
|
||||||
ui->backend, ui->backend_widget,
|
|
||||||
static_cast<int>(Settings::values.shader_backend.GetValue(true)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ private:
|
||||||
void UpdateDeviceSelection(int device);
|
void UpdateDeviceSelection(int device);
|
||||||
void UpdateShaderBackendSelection(int backend);
|
void UpdateShaderBackendSelection(int backend);
|
||||||
|
|
||||||
bool RetrieveVulkanDevices();
|
void RetrieveVulkanDevices();
|
||||||
|
|
||||||
void SetupPerGameUI();
|
void SetupPerGameUI();
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>471</width>
|
<width>541</width>
|
||||||
<height>759</height>
|
<height>759</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
|
@ -574,13 +574,6 @@
|
||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="button_check_vulkan">
|
|
||||||
<property name="text">
|
|
||||||
<string>Check for Working Vulkan</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<resources/>
|
<resources/>
|
||||||
|
|
|
@ -115,7 +115,6 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
|
||||||
#include "video_core/shader_notify.h"
|
#include "video_core/shader_notify.h"
|
||||||
#include "yuzu/about_dialog.h"
|
#include "yuzu/about_dialog.h"
|
||||||
#include "yuzu/bootmanager.h"
|
#include "yuzu/bootmanager.h"
|
||||||
#include "yuzu/check_vulkan.h"
|
|
||||||
#include "yuzu/compatdb.h"
|
#include "yuzu/compatdb.h"
|
||||||
#include "yuzu/compatibility_list.h"
|
#include "yuzu/compatibility_list.h"
|
||||||
#include "yuzu/configuration/config.h"
|
#include "yuzu/configuration/config.h"
|
||||||
|
@ -131,6 +130,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
|
||||||
#include "yuzu/install_dialog.h"
|
#include "yuzu/install_dialog.h"
|
||||||
#include "yuzu/loading_screen.h"
|
#include "yuzu/loading_screen.h"
|
||||||
#include "yuzu/main.h"
|
#include "yuzu/main.h"
|
||||||
|
#include "yuzu/startup_checks.h"
|
||||||
#include "yuzu/uisettings.h"
|
#include "yuzu/uisettings.h"
|
||||||
|
|
||||||
using namespace Common::Literals;
|
using namespace Common::Literals;
|
||||||
|
@ -252,7 +252,7 @@ static QString PrettyProductName() {
|
||||||
return QSysInfo::prettyProductName();
|
return QSysInfo::prettyProductName();
|
||||||
}
|
}
|
||||||
|
|
||||||
GMainWindow::GMainWindow()
|
GMainWindow::GMainWindow(bool has_broken_vulkan)
|
||||||
: ui{std::make_unique<Ui::MainWindow>()}, system{std::make_unique<Core::System>()},
|
: ui{std::make_unique<Ui::MainWindow>()}, system{std::make_unique<Core::System>()},
|
||||||
input_subsystem{std::make_shared<InputCommon::InputSubsystem>()},
|
input_subsystem{std::make_shared<InputCommon::InputSubsystem>()},
|
||||||
config{std::make_unique<Config>(*system)},
|
config{std::make_unique<Config>(*system)},
|
||||||
|
@ -352,17 +352,15 @@ GMainWindow::GMainWindow()
|
||||||
|
|
||||||
MigrateConfigFiles();
|
MigrateConfigFiles();
|
||||||
|
|
||||||
if (!CheckVulkan()) {
|
if (has_broken_vulkan) {
|
||||||
config->Save();
|
UISettings::values.has_broken_vulkan = true;
|
||||||
|
|
||||||
|
QMessageBox::warning(this, tr("Broken Vulkan Installation Detected"),
|
||||||
|
tr("Vulkan initialization failed during boot.<br><br>Click <a "
|
||||||
|
"href='https://yuzu-emu.org/wiki/faq/"
|
||||||
|
"#yuzu-starts-with-the-error-broken-vulkan-installation-detected'>"
|
||||||
|
"here for instructions to fix the issue</a>."));
|
||||||
|
|
||||||
QMessageBox::warning(
|
|
||||||
this, tr("Broken Vulkan Installation Detected"),
|
|
||||||
tr("Vulkan initialization failed on the previous boot.<br><br>Click <a "
|
|
||||||
"href='https://yuzu-emu.org/wiki/faq/"
|
|
||||||
"#yuzu-starts-with-the-error-broken-vulkan-installation-detected'>here for "
|
|
||||||
"instructions to fix the issue</a>."));
|
|
||||||
}
|
|
||||||
if (UISettings::values.has_broken_vulkan) {
|
|
||||||
Settings::values.renderer_backend = Settings::RendererBackend::OpenGL;
|
Settings::values.renderer_backend = Settings::RendererBackend::OpenGL;
|
||||||
|
|
||||||
renderer_status_button->setDisabled(true);
|
renderer_status_button->setDisabled(true);
|
||||||
|
@ -3879,6 +3877,11 @@ void GMainWindow::SetDiscordEnabled([[maybe_unused]] bool state) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
|
bool has_broken_vulkan = false;
|
||||||
|
if (StartupChecks(argv[0], &has_broken_vulkan)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
Common::DetachedTasks detached_tasks;
|
Common::DetachedTasks detached_tasks;
|
||||||
MicroProfileOnThreadCreate("Frontend");
|
MicroProfileOnThreadCreate("Frontend");
|
||||||
SCOPE_EXIT({ MicroProfileShutdown(); });
|
SCOPE_EXIT({ MicroProfileShutdown(); });
|
||||||
|
@ -3918,7 +3921,7 @@ int main(int argc, char* argv[]) {
|
||||||
// generating shaders
|
// generating shaders
|
||||||
setlocale(LC_ALL, "C");
|
setlocale(LC_ALL, "C");
|
||||||
|
|
||||||
GMainWindow main_window{};
|
GMainWindow main_window{has_broken_vulkan};
|
||||||
// After settings have been loaded by GMainWindow, apply the filter
|
// After settings have been loaded by GMainWindow, apply the filter
|
||||||
main_window.show();
|
main_window.show();
|
||||||
|
|
||||||
|
|
|
@ -118,7 +118,7 @@ class GMainWindow : public QMainWindow {
|
||||||
public:
|
public:
|
||||||
void filterBarSetChecked(bool state);
|
void filterBarSetChecked(bool state);
|
||||||
void UpdateUITheme();
|
void UpdateUITheme();
|
||||||
explicit GMainWindow();
|
explicit GMainWindow(bool has_broken_vulkan);
|
||||||
~GMainWindow() override;
|
~GMainWindow() override;
|
||||||
|
|
||||||
bool DropAction(QDropEvent* event);
|
bool DropAction(QDropEvent* event);
|
||||||
|
|
136
src/yuzu/startup_checks.cpp
Normal file
136
src/yuzu/startup_checks.cpp
Normal file
|
@ -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
|
17
src/yuzu/startup_checks.h
Normal file
17
src/yuzu/startup_checks.h
Normal file
|
@ -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
|
|
@ -78,7 +78,7 @@ struct Values {
|
||||||
Settings::Setting<bool> mute_when_in_background{false, "muteWhenInBackground"};
|
Settings::Setting<bool> mute_when_in_background{false, "muteWhenInBackground"};
|
||||||
Settings::Setting<bool> hide_mouse{true, "hideInactiveMouse"};
|
Settings::Setting<bool> hide_mouse{true, "hideInactiveMouse"};
|
||||||
// Set when Vulkan is known to crash the application
|
// Set when Vulkan is known to crash the application
|
||||||
Settings::Setting<bool> has_broken_vulkan{false, "has_broken_vulkan"};
|
bool has_broken_vulkan = false;
|
||||||
|
|
||||||
Settings::Setting<bool> select_user_on_boot{false, "select_user_on_boot"};
|
Settings::Setting<bool> select_user_on_boot{false, "select_user_on_boot"};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue