diff options
| -rw-r--r-- | src/common/settings.h | 2 | ||||
| -rw-r--r-- | src/video_core/vulkan_common/vulkan_library.cpp | 4 | ||||
| -rw-r--r-- | src/yuzu/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/yuzu/check_vulkan.cpp | 53 | ||||
| -rw-r--r-- | src/yuzu/check_vulkan.h | 6 | ||||
| -rw-r--r-- | src/yuzu/configuration/config.cpp | 8 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_graphics.cpp | 36 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_graphics.h | 2 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_graphics.ui | 91 | ||||
| -rw-r--r-- | src/yuzu/main.cpp | 24 | ||||
| -rw-r--r-- | src/yuzu/uisettings.h | 2 | ||||
| -rw-r--r-- | src/yuzu_cmd/default_ini.h | 2 | 
12 files changed, 184 insertions, 48 deletions
| diff --git a/src/common/settings.h b/src/common/settings.h index a7bbfb0da..a507744a2 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -496,7 +496,7 @@ struct Values {      // Renderer      RangedSetting<RendererBackend> renderer_backend{ -        RendererBackend::OpenGL, RendererBackend::OpenGL, RendererBackend::Vulkan, "backend"}; +        RendererBackend::Vulkan, RendererBackend::OpenGL, RendererBackend::Vulkan, "backend"};      BasicSetting<bool> renderer_debug{false, "debug"};      BasicSetting<bool> renderer_shader_feedback{false, "shader_feedback"};      BasicSetting<bool> enable_nsight_aftermath{false, "nsight_aftermath"}; diff --git a/src/video_core/vulkan_common/vulkan_library.cpp b/src/video_core/vulkan_common/vulkan_library.cpp index a5dd33fb2..4eb3913ee 100644 --- a/src/video_core/vulkan_common/vulkan_library.cpp +++ b/src/video_core/vulkan_common/vulkan_library.cpp @@ -5,11 +5,13 @@  #include "common/dynamic_library.h"  #include "common/fs/path_util.h" +#include "common/logging/log.h"  #include "video_core/vulkan_common/vulkan_library.h"  namespace Vulkan {  Common::DynamicLibrary OpenLibrary() { +    LOG_DEBUG(Render_Vulkan, "Looking for a Vulkan library");      Common::DynamicLibrary library;  #ifdef __APPLE__      // Check if a path to a specific Vulkan library has been specified. @@ -22,9 +24,11 @@ Common::DynamicLibrary OpenLibrary() {      }  #else      std::string filename = Common::DynamicLibrary::GetVersionedFilename("vulkan", 1); +    LOG_DEBUG(Render_Vulkan, "Trying Vulkan library: {}", filename);      if (!library.Open(filename.c_str())) {          // Android devices may not have libvulkan.so.1, only libvulkan.so.          filename = Common::DynamicLibrary::GetVersionedFilename("vulkan"); +        LOG_DEBUG(Render_Vulkan, "Trying Vulkan library (second attempt): {}", filename);          void(library.Open(filename.c_str()));      }  #endif diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 1c50295c1..9259ca15e 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -30,6 +30,8 @@ add_executable(yuzu      applets/qt_web_browser_scripts.h      bootmanager.cpp      bootmanager.h +    check_vulkan.cpp +    check_vulkan.h      compatdb.ui      compatibility_list.cpp      compatibility_list.h diff --git a/src/yuzu/check_vulkan.cpp b/src/yuzu/check_vulkan.cpp new file mode 100644 index 000000000..e6d66ab34 --- /dev/null +++ b/src/yuzu/check_vulkan.cpp @@ -0,0 +1,53 @@ +// 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; +} diff --git a/src/yuzu/check_vulkan.h b/src/yuzu/check_vulkan.h new file mode 100644 index 000000000..e4ea93582 --- /dev/null +++ b/src/yuzu/check_vulkan.h @@ -0,0 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +bool CheckVulkan(); diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index fffbfab02..9df4752be 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -682,6 +682,12 @@ void Config::ReadRendererValues() {      ReadGlobalSetting(Settings::values.bg_green);      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) {          ReadBasicSetting(Settings::values.renderer_debug);          ReadBasicSetting(Settings::values.renderer_shader_feedback); @@ -801,6 +807,7 @@ void Config::ReadUIValues() {      ReadBasicSetting(UISettings::values.pause_when_in_background);      ReadBasicSetting(UISettings::values.mute_when_in_background);      ReadBasicSetting(UISettings::values.hide_mouse); +    ReadBasicSetting(UISettings::values.has_broken_vulkan);      ReadBasicSetting(UISettings::values.disable_web_applet);      qt_config->endGroup(); @@ -1348,6 +1355,7 @@ void Config::SaveUIValues() {      WriteBasicSetting(UISettings::values.pause_when_in_background);      WriteBasicSetting(UISettings::values.mute_when_in_background);      WriteBasicSetting(UISettings::values.hide_mouse); +    WriteBasicSetting(UISettings::values.has_broken_vulkan);      WriteBasicSetting(UISettings::values.disable_web_applet);      qt_config->endGroup(); diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp index 2f1435b10..85f34dc35 100644 --- a/src/yuzu/configuration/configure_graphics.cpp +++ b/src/yuzu/configuration/configure_graphics.cpp @@ -17,6 +17,7 @@  #include "video_core/vulkan_common/vulkan_library.h"  #include "yuzu/configuration/configuration_shared.h"  #include "yuzu/configuration/configure_graphics.h" +#include "yuzu/uisettings.h"  ConfigureGraphics::ConfigureGraphics(const Core::System& system_, QWidget* parent)      : QWidget(parent), ui{std::make_unique<Ui::ConfigureGraphics>()}, system{system_} { @@ -57,6 +58,24 @@ ConfigureGraphics::ConfigureGraphics(const Core::System& system_, QWidget* paren          UpdateBackgroundColorButton(new_bg_color);      }); +    connect(ui->button_check_vulkan, &QAbstractButton::clicked, this, [this] { +        UISettings::values.has_broken_vulkan = false; + +        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_combobox->setVisible(!Settings::IsConfiguringGlobal());  } @@ -296,7 +315,7 @@ void ConfigureGraphics::UpdateAPILayout() {          vulkan_device = Settings::values.vulkan_device.GetValue(true);          shader_backend = Settings::values.shader_backend.GetValue(true);          ui->device_widget->setEnabled(false); -        ui->backend_widget->setEnabled(false); +        ui->backend_widget->setEnabled(UISettings::values.has_broken_vulkan.GetValue());      } else {          vulkan_device = Settings::values.vulkan_device.GetValue();          shader_backend = Settings::values.shader_backend.GetValue(); @@ -318,7 +337,11 @@ void ConfigureGraphics::UpdateAPILayout() {      }  } -void ConfigureGraphics::RetrieveVulkanDevices() try { +bool ConfigureGraphics::RetrieveVulkanDevices() try { +    if (UISettings::values.has_broken_vulkan) { +        return false; +    } +      using namespace Vulkan;      vk::InstanceDispatch dld; @@ -333,8 +356,10 @@ void ConfigureGraphics::RetrieveVulkanDevices() try {          vulkan_devices.push_back(QString::fromStdString(name));      } +    return true;  } catch (const Vulkan::vk::Exception& exception) {      LOG_ERROR(Frontend, "Failed to enumerate devices with error: {}", exception.what()); +    return false;  }  Settings::RendererBackend ConfigureGraphics::GetCurrentGraphicsBackend() const { @@ -415,4 +440,11 @@ void ConfigureGraphics::SetupPerGameUI() {          ui->api, static_cast<int>(Settings::values.renderer_backend.GetValue(true)));      ConfigurationShared::InsertGlobalItem(          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))); +    }  } diff --git a/src/yuzu/configuration/configure_graphics.h b/src/yuzu/configuration/configure_graphics.h index 1b101c940..8438f0187 100644 --- a/src/yuzu/configuration/configure_graphics.h +++ b/src/yuzu/configuration/configure_graphics.h @@ -41,7 +41,7 @@ private:      void UpdateDeviceSelection(int device);      void UpdateShaderBackendSelection(int backend); -    void RetrieveVulkanDevices(); +    bool RetrieveVulkanDevices();      void SetupPerGameUI(); diff --git a/src/yuzu/configuration/configure_graphics.ui b/src/yuzu/configuration/configure_graphics.ui index 74f0e0b79..2f94c94bc 100644 --- a/src/yuzu/configuration/configure_graphics.ui +++ b/src/yuzu/configuration/configure_graphics.ui @@ -6,8 +6,8 @@     <rect>      <x>0</x>      <y>0</y> -    <width>437</width> -    <height>482</height> +    <width>471</width> +    <height>759</height>     </rect>    </property>    <property name="windowTitle"> @@ -171,11 +171,11 @@           </widget>          </item>          <item> -          <widget class="QCheckBox" name="accelerate_astc"> -            <property name="text"> -              <string>Accelerate ASTC texture decoding</string> -            </property> -          </widget> +         <widget class="QCheckBox" name="accelerate_astc"> +          <property name="text"> +           <string>Accelerate ASTC texture decoding</string> +          </property> +         </widget>          </item>          <item>           <widget class="QWidget" name="nvdec_emulation_widget" native="true"> @@ -438,43 +438,43 @@           </widget>          </item>          <item> -          <widget class="QWidget" name="anti_aliasing_layout" native="true"> -            <layout class="QHBoxLayout" name="horizontalLayout_7"> -              <property name="leftMargin"> -                <number>0</number> -              </property> -              <property name="topMargin"> -                <number>0</number> -              </property> -              <property name="rightMargin"> -                <number>0</number> +         <widget class="QWidget" name="anti_aliasing_layout" native="true"> +          <layout class="QHBoxLayout" name="horizontalLayout_7"> +           <property name="leftMargin"> +            <number>0</number> +           </property> +           <property name="topMargin"> +            <number>0</number> +           </property> +           <property name="rightMargin"> +            <number>0</number> +           </property> +           <property name="bottomMargin"> +            <number>0</number> +           </property> +           <item> +            <widget class="QLabel" name="anti_aliasing_label"> +             <property name="text"> +              <string>Anti-Aliasing Method:</string> +             </property> +            </widget> +           </item> +           <item> +            <widget class="QComboBox" name="anti_aliasing_combobox"> +             <item> +              <property name="text"> +               <string>None</string>                </property> -              <property name="bottomMargin"> -                <number>0</number> +             </item> +             <item> +              <property name="text"> +               <string>FXAA</string>                </property> -              <item> -                <widget class="QLabel" name="anti_aliasing_label"> -                  <property name="text"> -                    <string>Anti-Aliasing Method:</string> -                  </property> -                </widget> -              </item> -              <item> -                <widget class="QComboBox" name="anti_aliasing_combobox"> -                  <item> -                    <property name="text"> -                      <string>None</string> -                    </property> -                  </item> -                  <item> -                    <property name="text"> -                      <string>FXAA</string> -                    </property> -                  </item> -                </widget> -              </item> -            </layout> -          </widget> +             </item> +            </widget> +           </item> +          </layout> +         </widget>          </item>          <item>           <widget class="QWidget" name="bg_layout" native="true"> @@ -574,6 +574,13 @@       </property>      </spacer>     </item> +   <item> +    <widget class="QPushButton" name="button_check_vulkan"> +     <property name="text"> +      <string>Check for Working Vulkan</string> +     </property> +    </widget> +   </item>    </layout>   </widget>   <resources/> diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index cbfcba9ef..4d7634184 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -115,6 +115,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual  #include "video_core/shader_notify.h"  #include "yuzu/about_dialog.h"  #include "yuzu/bootmanager.h" +#include "yuzu/check_vulkan.h"  #include "yuzu/compatdb.h"  #include "yuzu/compatibility_list.h"  #include "yuzu/configuration/config.h" @@ -322,6 +323,23 @@ GMainWindow::GMainWindow()      MigrateConfigFiles(); +    if (!CheckVulkan()) { +        config->Save(); + +        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; + +        renderer_status_button->setDisabled(true); +        renderer_status_button->setChecked(false); +    } +  #if defined(HAVE_SDL2) && !defined(_WIN32)      SDL_InitSubSystem(SDL_INIT_VIDEO);      // SDL disables the screen saver by default, and setting the hint @@ -1591,7 +1609,7 @@ void GMainWindow::ShutdownGame() {      emu_speed_label->setVisible(false);      game_fps_label->setVisible(false);      emu_frametime_label->setVisible(false); -    renderer_status_button->setEnabled(true); +    renderer_status_button->setEnabled(!UISettings::values.has_broken_vulkan);      game_path.clear(); @@ -2801,6 +2819,10 @@ void GMainWindow::OnConfigure() {          mouse_hide_timer.start();      } +    if (!UISettings::values.has_broken_vulkan) { +        renderer_status_button->setEnabled(!emulation_running); +    } +      UpdateStatusButtons();      controller_dialog->refreshConfiguration();  } diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h index 15ba9ea17..c64d87ace 100644 --- a/src/yuzu/uisettings.h +++ b/src/yuzu/uisettings.h @@ -77,6 +77,8 @@ struct Values {      Settings::BasicSetting<bool> pause_when_in_background{false, "pauseWhenInBackground"};      Settings::BasicSetting<bool> mute_when_in_background{false, "muteWhenInBackground"};      Settings::BasicSetting<bool> hide_mouse{true, "hideInactiveMouse"}; +    // Set when Vulkan is known to crash the application +    Settings::BasicSetting<bool> has_broken_vulkan{false, "has_broken_vulkan"};      Settings::BasicSetting<bool> select_user_on_boot{false, "select_user_on_boot"}; diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h index f34d6b728..39063e32b 100644 --- a/src/yuzu_cmd/default_ini.h +++ b/src/yuzu_cmd/default_ini.h @@ -218,7 +218,7 @@ cpuopt_unsafe_ignore_global_monitor =  [Renderer]  # Which backend API to use. -# 0 (default): OpenGL, 1: Vulkan +# 0: OpenGL, 1 (default): Vulkan  backend =  # Enable graphics API debugging mode. | 
