diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/common/fs/fs_util.cpp | 14 | ||||
| -rw-r--r-- | src/common/fs/fs_util.h | 33 | ||||
| -rw-r--r-- | src/common/fs/path_util.cpp | 6 | ||||
| -rw-r--r-- | src/common/fs/path_util.h | 9 | ||||
| -rw-r--r-- | src/input_common/sdl/sdl_impl.cpp | 281 | ||||
| -rw-r--r-- | src/input_common/sdl/sdl_impl.h | 37 | ||||
| -rw-r--r-- | src/video_core/vulkan_common/vulkan_memory_allocator.cpp | 67 | ||||
| -rw-r--r-- | src/video_core/vulkan_common/vulkan_memory_allocator.h | 7 | ||||
| -rw-r--r-- | src/yuzu/configuration/config.cpp | 4 | ||||
| -rw-r--r-- | src/yuzu/configuration/config.h | 4 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_per_game.cpp | 9 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_per_game.h | 3 | ||||
| -rw-r--r-- | src/yuzu/game_list.cpp | 8 | ||||
| -rw-r--r-- | src/yuzu/game_list.h | 3 | ||||
| -rw-r--r-- | src/yuzu/main.cpp | 21 | ||||
| -rw-r--r-- | src/yuzu/main.h | 5 |
16 files changed, 383 insertions, 128 deletions
diff --git a/src/common/fs/fs_util.cpp b/src/common/fs/fs_util.cpp index 0ddfc3131..357cf5855 100644 --- a/src/common/fs/fs_util.cpp +++ b/src/common/fs/fs_util.cpp | |||
| @@ -2,6 +2,8 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <algorithm> | ||
| 6 | |||
| 5 | #include "common/fs/fs_util.h" | 7 | #include "common/fs/fs_util.h" |
| 6 | 8 | ||
| 7 | namespace Common::FS { | 9 | namespace Common::FS { |
| @@ -10,4 +12,16 @@ std::u8string ToU8String(std::string_view utf8_string) { | |||
| 10 | return std::u8string{utf8_string.begin(), utf8_string.end()}; | 12 | return std::u8string{utf8_string.begin(), utf8_string.end()}; |
| 11 | } | 13 | } |
| 12 | 14 | ||
| 15 | std::u8string BufferToU8String(std::span<const u8> buffer) { | ||
| 16 | return std::u8string{buffer.begin(), std::ranges::find(buffer, u8{0})}; | ||
| 17 | } | ||
| 18 | |||
| 19 | std::string ToUTF8String(std::u8string_view u8_string) { | ||
| 20 | return std::string{u8_string.begin(), u8_string.end()}; | ||
| 21 | } | ||
| 22 | |||
| 23 | std::string PathToUTF8String(const std::filesystem::path& path) { | ||
| 24 | return ToUTF8String(path.u8string()); | ||
| 25 | } | ||
| 26 | |||
| 13 | } // namespace Common::FS | 27 | } // namespace Common::FS |
diff --git a/src/common/fs/fs_util.h b/src/common/fs/fs_util.h index 951df53b6..ec9950ee7 100644 --- a/src/common/fs/fs_util.h +++ b/src/common/fs/fs_util.h | |||
| @@ -5,9 +5,13 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <concepts> | 7 | #include <concepts> |
| 8 | #include <filesystem> | ||
| 9 | #include <span> | ||
| 8 | #include <string> | 10 | #include <string> |
| 9 | #include <string_view> | 11 | #include <string_view> |
| 10 | 12 | ||
| 13 | #include "common/common_types.h" | ||
| 14 | |||
| 11 | namespace Common::FS { | 15 | namespace Common::FS { |
| 12 | 16 | ||
| 13 | template <typename T> | 17 | template <typename T> |
| @@ -22,4 +26,33 @@ concept IsChar = std::same_as<T, char>; | |||
| 22 | */ | 26 | */ |
| 23 | [[nodiscard]] std::u8string ToU8String(std::string_view utf8_string); | 27 | [[nodiscard]] std::u8string ToU8String(std::string_view utf8_string); |
| 24 | 28 | ||
| 29 | /** | ||
| 30 | * Converts a buffer of bytes to a UTF8-encoded std::u8string. | ||
| 31 | * This converts from the start of the buffer until the first encountered null-terminator. | ||
| 32 | * If no null-terminator is found, this converts the entire buffer instead. | ||
| 33 | * | ||
| 34 | * @param buffer Buffer of bytes | ||
| 35 | * | ||
| 36 | * @returns UTF-8 encoded std::u8string. | ||
| 37 | */ | ||
| 38 | [[nodiscard]] std::u8string BufferToU8String(std::span<const u8> buffer); | ||
| 39 | |||
| 40 | /** | ||
| 41 | * Converts a std::u8string or std::u8string_view to a UTF-8 encoded std::string. | ||
| 42 | * | ||
| 43 | * @param u8_string UTF-8 encoded u8string | ||
| 44 | * | ||
| 45 | * @returns UTF-8 encoded std::string. | ||
| 46 | */ | ||
| 47 | [[nodiscard]] std::string ToUTF8String(std::u8string_view u8_string); | ||
| 48 | |||
| 49 | /** | ||
| 50 | * Converts a filesystem path to a UTF-8 encoded std::string. | ||
| 51 | * | ||
| 52 | * @param path Filesystem path | ||
| 53 | * | ||
| 54 | * @returns UTF-8 encoded std::string. | ||
| 55 | */ | ||
| 56 | [[nodiscard]] std::string PathToUTF8String(const std::filesystem::path& path); | ||
| 57 | |||
| 25 | } // namespace Common::FS | 58 | } // namespace Common::FS |
diff --git a/src/common/fs/path_util.cpp b/src/common/fs/path_util.cpp index 8b732a21c..6cdd14f13 100644 --- a/src/common/fs/path_util.cpp +++ b/src/common/fs/path_util.cpp | |||
| @@ -129,12 +129,6 @@ private: | |||
| 129 | std::unordered_map<YuzuPath, fs::path> yuzu_paths; | 129 | std::unordered_map<YuzuPath, fs::path> yuzu_paths; |
| 130 | }; | 130 | }; |
| 131 | 131 | ||
| 132 | std::string PathToUTF8String(const fs::path& path) { | ||
| 133 | const auto utf8_string = path.u8string(); | ||
| 134 | |||
| 135 | return std::string{utf8_string.begin(), utf8_string.end()}; | ||
| 136 | } | ||
| 137 | |||
| 138 | bool ValidatePath(const fs::path& path) { | 132 | bool ValidatePath(const fs::path& path) { |
| 139 | if (path.empty()) { | 133 | if (path.empty()) { |
| 140 | LOG_ERROR(Common_Filesystem, "Input path is empty, path={}", PathToUTF8String(path)); | 134 | LOG_ERROR(Common_Filesystem, "Input path is empty, path={}", PathToUTF8String(path)); |
diff --git a/src/common/fs/path_util.h b/src/common/fs/path_util.h index a9fadbceb..14e8c35d7 100644 --- a/src/common/fs/path_util.h +++ b/src/common/fs/path_util.h | |||
| @@ -26,15 +26,6 @@ enum class YuzuPath { | |||
| 26 | }; | 26 | }; |
| 27 | 27 | ||
| 28 | /** | 28 | /** |
| 29 | * Converts a filesystem path to a UTF-8 encoded std::string. | ||
| 30 | * | ||
| 31 | * @param path Filesystem path | ||
| 32 | * | ||
| 33 | * @returns UTF-8 encoded std::string. | ||
| 34 | */ | ||
| 35 | [[nodiscard]] std::string PathToUTF8String(const std::filesystem::path& path); | ||
| 36 | |||
| 37 | /** | ||
| 38 | * Validates a given path. | 29 | * Validates a given path. |
| 39 | * | 30 | * |
| 40 | * A given path is valid if it meets these conditions: | 31 | * A given path is valid if it meets these conditions: |
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp index b9b584b2a..68672a92b 100644 --- a/src/input_common/sdl/sdl_impl.cpp +++ b/src/input_common/sdl/sdl_impl.cpp | |||
| @@ -18,16 +18,6 @@ | |||
| 18 | #include <utility> | 18 | #include <utility> |
| 19 | #include <vector> | 19 | #include <vector> |
| 20 | 20 | ||
| 21 | // Ignore -Wimplicit-fallthrough due to https://github.com/libsdl-org/SDL/issues/4307 | ||
| 22 | #ifdef __clang__ | ||
| 23 | #pragma clang diagnostic push | ||
| 24 | #pragma clang diagnostic ignored "-Wimplicit-fallthrough" | ||
| 25 | #endif | ||
| 26 | #include <SDL.h> | ||
| 27 | #ifdef __clang__ | ||
| 28 | #pragma clang diagnostic pop | ||
| 29 | #endif | ||
| 30 | |||
| 31 | #include "common/logging/log.h" | 21 | #include "common/logging/log.h" |
| 32 | #include "common/math_util.h" | 22 | #include "common/math_util.h" |
| 33 | #include "common/param_package.h" | 23 | #include "common/param_package.h" |
| @@ -214,6 +204,40 @@ public: | |||
| 214 | sdl_controller.reset(controller); | 204 | sdl_controller.reset(controller); |
| 215 | } | 205 | } |
| 216 | 206 | ||
| 207 | bool IsJoyconLeft() const { | ||
| 208 | return std::strstr(GetControllerName().c_str(), "Joy-Con Left") != nullptr; | ||
| 209 | } | ||
| 210 | |||
| 211 | bool IsJoyconRight() const { | ||
| 212 | return std::strstr(GetControllerName().c_str(), "Joy-Con Right") != nullptr; | ||
| 213 | } | ||
| 214 | |||
| 215 | std::string GetControllerName() const { | ||
| 216 | if (sdl_controller) { | ||
| 217 | switch (SDL_GameControllerGetType(sdl_controller.get())) { | ||
| 218 | case SDL_CONTROLLER_TYPE_XBOX360: | ||
| 219 | return "XBox 360 Controller"; | ||
| 220 | case SDL_CONTROLLER_TYPE_XBOXONE: | ||
| 221 | return "XBox One Controller"; | ||
| 222 | default: | ||
| 223 | break; | ||
| 224 | } | ||
| 225 | const auto name = SDL_GameControllerName(sdl_controller.get()); | ||
| 226 | if (name) { | ||
| 227 | return name; | ||
| 228 | } | ||
| 229 | } | ||
| 230 | |||
| 231 | if (sdl_joystick) { | ||
| 232 | const auto name = SDL_JoystickName(sdl_joystick.get()); | ||
| 233 | if (name) { | ||
| 234 | return name; | ||
| 235 | } | ||
| 236 | } | ||
| 237 | |||
| 238 | return "Unknown"; | ||
| 239 | } | ||
| 240 | |||
| 217 | private: | 241 | private: |
| 218 | struct State { | 242 | struct State { |
| 219 | std::unordered_map<int, bool> buttons; | 243 | std::unordered_map<int, bool> buttons; |
| @@ -858,23 +882,42 @@ SDLState::~SDLState() { | |||
| 858 | std::vector<Common::ParamPackage> SDLState::GetInputDevices() { | 882 | std::vector<Common::ParamPackage> SDLState::GetInputDevices() { |
| 859 | std::scoped_lock lock(joystick_map_mutex); | 883 | std::scoped_lock lock(joystick_map_mutex); |
| 860 | std::vector<Common::ParamPackage> devices; | 884 | std::vector<Common::ParamPackage> devices; |
| 885 | std::unordered_map<int, std::shared_ptr<SDLJoystick>> joycon_pairs; | ||
| 886 | for (const auto& [key, value] : joystick_map) { | ||
| 887 | for (const auto& joystick : value) { | ||
| 888 | if (!joystick->GetSDLJoystick()) { | ||
| 889 | continue; | ||
| 890 | } | ||
| 891 | std::string name = | ||
| 892 | fmt::format("{} {}", joystick->GetControllerName(), joystick->GetPort()); | ||
| 893 | devices.emplace_back(Common::ParamPackage{ | ||
| 894 | {"class", "sdl"}, | ||
| 895 | {"display", std::move(name)}, | ||
| 896 | {"guid", joystick->GetGUID()}, | ||
| 897 | {"port", std::to_string(joystick->GetPort())}, | ||
| 898 | }); | ||
| 899 | if (joystick->IsJoyconLeft()) { | ||
| 900 | joycon_pairs.insert_or_assign(joystick->GetPort(), joystick); | ||
| 901 | } | ||
| 902 | } | ||
| 903 | } | ||
| 904 | |||
| 905 | // Add dual controllers | ||
| 861 | for (const auto& [key, value] : joystick_map) { | 906 | for (const auto& [key, value] : joystick_map) { |
| 862 | for (const auto& joystick : value) { | 907 | for (const auto& joystick : value) { |
| 863 | if (auto* const controller = joystick->GetSDLGameController()) { | 908 | if (joystick->IsJoyconRight()) { |
| 909 | if (!joycon_pairs.contains(joystick->GetPort())) { | ||
| 910 | continue; | ||
| 911 | } | ||
| 912 | const auto joystick2 = joycon_pairs.at(joystick->GetPort()); | ||
| 913 | |||
| 864 | std::string name = | 914 | std::string name = |
| 865 | fmt::format("{} {}", GetControllerName(controller), joystick->GetPort()); | 915 | fmt::format("{} {}", "Nintendo Dual Joy-Con", joystick->GetPort()); |
| 866 | devices.emplace_back(Common::ParamPackage{ | ||
| 867 | {"class", "sdl"}, | ||
| 868 | {"display", std::move(name)}, | ||
| 869 | {"guid", joystick->GetGUID()}, | ||
| 870 | {"port", std::to_string(joystick->GetPort())}, | ||
| 871 | }); | ||
| 872 | } else if (auto* const joy = joystick->GetSDLJoystick()) { | ||
| 873 | std::string name = fmt::format("{} {}", SDL_JoystickName(joy), joystick->GetPort()); | ||
| 874 | devices.emplace_back(Common::ParamPackage{ | 916 | devices.emplace_back(Common::ParamPackage{ |
| 875 | {"class", "sdl"}, | 917 | {"class", "sdl"}, |
| 876 | {"display", std::move(name)}, | 918 | {"display", std::move(name)}, |
| 877 | {"guid", joystick->GetGUID()}, | 919 | {"guid", joystick->GetGUID()}, |
| 920 | {"guid2", joystick2->GetGUID()}, | ||
| 878 | {"port", std::to_string(joystick->GetPort())}, | 921 | {"port", std::to_string(joystick->GetPort())}, |
| 879 | }); | 922 | }); |
| 880 | } | 923 | } |
| @@ -883,17 +926,6 @@ std::vector<Common::ParamPackage> SDLState::GetInputDevices() { | |||
| 883 | return devices; | 926 | return devices; |
| 884 | } | 927 | } |
| 885 | 928 | ||
| 886 | std::string SDLState::GetControllerName(SDL_GameController* controller) const { | ||
| 887 | switch (SDL_GameControllerGetType(controller)) { | ||
| 888 | case SDL_CONTROLLER_TYPE_XBOX360: | ||
| 889 | return "XBox 360 Controller"; | ||
| 890 | case SDL_CONTROLLER_TYPE_XBOXONE: | ||
| 891 | return "XBox One Controller"; | ||
| 892 | default: | ||
| 893 | return SDL_GameControllerName(controller); | ||
| 894 | } | ||
| 895 | } | ||
| 896 | |||
| 897 | namespace { | 929 | namespace { |
| 898 | Common::ParamPackage BuildAnalogParamPackageForButton(int port, std::string guid, s32 axis, | 930 | Common::ParamPackage BuildAnalogParamPackageForButton(int port, std::string guid, s32 axis, |
| 899 | float value = 0.1f) { | 931 | float value = 0.1f) { |
| @@ -1073,24 +1105,48 @@ ButtonMapping SDLState::GetButtonMappingForDevice(const Common::ParamPackage& pa | |||
| 1073 | return {}; | 1105 | return {}; |
| 1074 | } | 1106 | } |
| 1075 | const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0)); | 1107 | const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0)); |
| 1108 | |||
| 1076 | auto* controller = joystick->GetSDLGameController(); | 1109 | auto* controller = joystick->GetSDLGameController(); |
| 1077 | if (controller == nullptr) { | 1110 | if (controller == nullptr) { |
| 1078 | return {}; | 1111 | return {}; |
| 1079 | } | 1112 | } |
| 1080 | 1113 | ||
| 1081 | const bool invert = | ||
| 1082 | SDL_GameControllerGetType(controller) != SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO; | ||
| 1083 | |||
| 1084 | // This list is missing ZL/ZR since those are not considered buttons in SDL GameController. | 1114 | // This list is missing ZL/ZR since those are not considered buttons in SDL GameController. |
| 1085 | // We will add those afterwards | 1115 | // We will add those afterwards |
| 1086 | // This list also excludes Screenshot since theres not really a mapping for that | 1116 | // This list also excludes Screenshot since theres not really a mapping for that |
| 1087 | using ButtonBindings = | 1117 | ButtonBindings switch_to_sdl_button; |
| 1088 | std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerButton>, 17>; | 1118 | |
| 1089 | const ButtonBindings switch_to_sdl_button{{ | 1119 | if (SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO) { |
| 1090 | {Settings::NativeButton::A, invert ? SDL_CONTROLLER_BUTTON_B : SDL_CONTROLLER_BUTTON_A}, | 1120 | switch_to_sdl_button = GetNintendoButtonBinding(joystick); |
| 1091 | {Settings::NativeButton::B, invert ? SDL_CONTROLLER_BUTTON_A : SDL_CONTROLLER_BUTTON_B}, | 1121 | } else { |
| 1092 | {Settings::NativeButton::X, invert ? SDL_CONTROLLER_BUTTON_Y : SDL_CONTROLLER_BUTTON_X}, | 1122 | switch_to_sdl_button = GetDefaultButtonBinding(); |
| 1093 | {Settings::NativeButton::Y, invert ? SDL_CONTROLLER_BUTTON_X : SDL_CONTROLLER_BUTTON_Y}, | 1123 | } |
| 1124 | |||
| 1125 | // Add the missing bindings for ZL/ZR | ||
| 1126 | static constexpr ZButtonBindings switch_to_sdl_axis{{ | ||
| 1127 | {Settings::NativeButton::ZL, SDL_CONTROLLER_AXIS_TRIGGERLEFT}, | ||
| 1128 | {Settings::NativeButton::ZR, SDL_CONTROLLER_AXIS_TRIGGERRIGHT}, | ||
| 1129 | }}; | ||
| 1130 | |||
| 1131 | // Parameters contain two joysticks return dual | ||
| 1132 | if (params.Has("guid2")) { | ||
| 1133 | const auto joystick2 = GetSDLJoystickByGUID(params.Get("guid2", ""), params.Get("port", 0)); | ||
| 1134 | |||
| 1135 | if (joystick2->GetSDLGameController() != nullptr) { | ||
| 1136 | return GetDualControllerMapping(joystick, joystick2, switch_to_sdl_button, | ||
| 1137 | switch_to_sdl_axis); | ||
| 1138 | } | ||
| 1139 | } | ||
| 1140 | |||
| 1141 | return GetSingleControllerMapping(joystick, switch_to_sdl_button, switch_to_sdl_axis); | ||
| 1142 | } | ||
| 1143 | |||
| 1144 | ButtonBindings SDLState::GetDefaultButtonBinding() const { | ||
| 1145 | return { | ||
| 1146 | std::pair{Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_B}, | ||
| 1147 | {Settings::NativeButton::B, SDL_CONTROLLER_BUTTON_A}, | ||
| 1148 | {Settings::NativeButton::X, SDL_CONTROLLER_BUTTON_Y}, | ||
| 1149 | {Settings::NativeButton::Y, SDL_CONTROLLER_BUTTON_X}, | ||
| 1094 | {Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK}, | 1150 | {Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK}, |
| 1095 | {Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK}, | 1151 | {Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK}, |
| 1096 | {Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER}, | 1152 | {Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER}, |
| @@ -1104,18 +1160,51 @@ ButtonMapping SDLState::GetButtonMappingForDevice(const Common::ParamPackage& pa | |||
| 1104 | {Settings::NativeButton::SL, SDL_CONTROLLER_BUTTON_LEFTSHOULDER}, | 1160 | {Settings::NativeButton::SL, SDL_CONTROLLER_BUTTON_LEFTSHOULDER}, |
| 1105 | {Settings::NativeButton::SR, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER}, | 1161 | {Settings::NativeButton::SR, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER}, |
| 1106 | {Settings::NativeButton::Home, SDL_CONTROLLER_BUTTON_GUIDE}, | 1162 | {Settings::NativeButton::Home, SDL_CONTROLLER_BUTTON_GUIDE}, |
| 1107 | }}; | 1163 | }; |
| 1164 | } | ||
| 1108 | 1165 | ||
| 1109 | // Add the missing bindings for ZL/ZR | 1166 | ButtonBindings SDLState::GetNintendoButtonBinding( |
| 1110 | using ZBindings = | 1167 | const std::shared_ptr<SDLJoystick>& joystick) const { |
| 1111 | std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerAxis>, 2>; | 1168 | // Default SL/SR mapping for pro controllers |
| 1112 | static constexpr ZBindings switch_to_sdl_axis{{ | 1169 | auto sl_button = SDL_CONTROLLER_BUTTON_LEFTSHOULDER; |
| 1113 | {Settings::NativeButton::ZL, SDL_CONTROLLER_AXIS_TRIGGERLEFT}, | 1170 | auto sr_button = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER; |
| 1114 | {Settings::NativeButton::ZR, SDL_CONTROLLER_AXIS_TRIGGERRIGHT}, | 1171 | |
| 1115 | }}; | 1172 | if (joystick->IsJoyconLeft()) { |
| 1173 | sl_button = SDL_CONTROLLER_BUTTON_PADDLE2; | ||
| 1174 | sr_button = SDL_CONTROLLER_BUTTON_PADDLE4; | ||
| 1175 | } | ||
| 1176 | if (joystick->IsJoyconRight()) { | ||
| 1177 | sl_button = SDL_CONTROLLER_BUTTON_PADDLE3; | ||
| 1178 | sr_button = SDL_CONTROLLER_BUTTON_PADDLE1; | ||
| 1179 | } | ||
| 1116 | 1180 | ||
| 1181 | return { | ||
| 1182 | std::pair{Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_A}, | ||
| 1183 | {Settings::NativeButton::B, SDL_CONTROLLER_BUTTON_B}, | ||
| 1184 | {Settings::NativeButton::X, SDL_CONTROLLER_BUTTON_X}, | ||
| 1185 | {Settings::NativeButton::Y, SDL_CONTROLLER_BUTTON_Y}, | ||
| 1186 | {Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK}, | ||
| 1187 | {Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK}, | ||
| 1188 | {Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER}, | ||
| 1189 | {Settings::NativeButton::R, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER}, | ||
| 1190 | {Settings::NativeButton::Plus, SDL_CONTROLLER_BUTTON_START}, | ||
| 1191 | {Settings::NativeButton::Minus, SDL_CONTROLLER_BUTTON_BACK}, | ||
| 1192 | {Settings::NativeButton::DLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT}, | ||
| 1193 | {Settings::NativeButton::DUp, SDL_CONTROLLER_BUTTON_DPAD_UP}, | ||
| 1194 | {Settings::NativeButton::DRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT}, | ||
| 1195 | {Settings::NativeButton::DDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN}, | ||
| 1196 | {Settings::NativeButton::SL, sl_button}, | ||
| 1197 | {Settings::NativeButton::SR, sr_button}, | ||
| 1198 | {Settings::NativeButton::Home, SDL_CONTROLLER_BUTTON_GUIDE}, | ||
| 1199 | }; | ||
| 1200 | } | ||
| 1201 | |||
| 1202 | ButtonMapping SDLState::GetSingleControllerMapping( | ||
| 1203 | const std::shared_ptr<SDLJoystick>& joystick, const ButtonBindings& switch_to_sdl_button, | ||
| 1204 | const ZButtonBindings& switch_to_sdl_axis) const { | ||
| 1117 | ButtonMapping mapping; | 1205 | ButtonMapping mapping; |
| 1118 | mapping.reserve(switch_to_sdl_button.size() + switch_to_sdl_axis.size()); | 1206 | mapping.reserve(switch_to_sdl_button.size() + switch_to_sdl_axis.size()); |
| 1207 | auto* controller = joystick->GetSDLGameController(); | ||
| 1119 | 1208 | ||
| 1120 | for (const auto& [switch_button, sdl_button] : switch_to_sdl_button) { | 1209 | for (const auto& [switch_button, sdl_button] : switch_to_sdl_button) { |
| 1121 | const auto& binding = SDL_GameControllerGetBindForButton(controller, sdl_button); | 1210 | const auto& binding = SDL_GameControllerGetBindForButton(controller, sdl_button); |
| @@ -1133,11 +1222,68 @@ ButtonMapping SDLState::GetButtonMappingForDevice(const Common::ParamPackage& pa | |||
| 1133 | return mapping; | 1222 | return mapping; |
| 1134 | } | 1223 | } |
| 1135 | 1224 | ||
| 1225 | ButtonMapping SDLState::GetDualControllerMapping(const std::shared_ptr<SDLJoystick>& joystick, | ||
| 1226 | const std::shared_ptr<SDLJoystick>& joystick2, | ||
| 1227 | const ButtonBindings& switch_to_sdl_button, | ||
| 1228 | const ZButtonBindings& switch_to_sdl_axis) const { | ||
| 1229 | ButtonMapping mapping; | ||
| 1230 | mapping.reserve(switch_to_sdl_button.size() + switch_to_sdl_axis.size()); | ||
| 1231 | auto* controller = joystick->GetSDLGameController(); | ||
| 1232 | auto* controller2 = joystick2->GetSDLGameController(); | ||
| 1233 | |||
| 1234 | for (const auto& [switch_button, sdl_button] : switch_to_sdl_button) { | ||
| 1235 | if (IsButtonOnLeftSide(switch_button)) { | ||
| 1236 | const auto& binding = SDL_GameControllerGetBindForButton(controller2, sdl_button); | ||
| 1237 | mapping.insert_or_assign( | ||
| 1238 | switch_button, | ||
| 1239 | BuildParamPackageForBinding(joystick2->GetPort(), joystick2->GetGUID(), binding)); | ||
| 1240 | continue; | ||
| 1241 | } | ||
| 1242 | const auto& binding = SDL_GameControllerGetBindForButton(controller, sdl_button); | ||
| 1243 | mapping.insert_or_assign( | ||
| 1244 | switch_button, | ||
| 1245 | BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding)); | ||
| 1246 | } | ||
| 1247 | for (const auto& [switch_button, sdl_axis] : switch_to_sdl_axis) { | ||
| 1248 | if (IsButtonOnLeftSide(switch_button)) { | ||
| 1249 | const auto& binding = SDL_GameControllerGetBindForAxis(controller2, sdl_axis); | ||
| 1250 | mapping.insert_or_assign( | ||
| 1251 | switch_button, | ||
| 1252 | BuildParamPackageForBinding(joystick2->GetPort(), joystick2->GetGUID(), binding)); | ||
| 1253 | continue; | ||
| 1254 | } | ||
| 1255 | const auto& binding = SDL_GameControllerGetBindForAxis(controller, sdl_axis); | ||
| 1256 | mapping.insert_or_assign( | ||
| 1257 | switch_button, | ||
| 1258 | BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding)); | ||
| 1259 | } | ||
| 1260 | |||
| 1261 | return mapping; | ||
| 1262 | } | ||
| 1263 | |||
| 1264 | bool SDLState::IsButtonOnLeftSide(Settings::NativeButton::Values button) const { | ||
| 1265 | switch (button) { | ||
| 1266 | case Settings::NativeButton::DDown: | ||
| 1267 | case Settings::NativeButton::DLeft: | ||
| 1268 | case Settings::NativeButton::DRight: | ||
| 1269 | case Settings::NativeButton::DUp: | ||
| 1270 | case Settings::NativeButton::L: | ||
| 1271 | case Settings::NativeButton::LStick: | ||
| 1272 | case Settings::NativeButton::Minus: | ||
| 1273 | case Settings::NativeButton::Screenshot: | ||
| 1274 | case Settings::NativeButton::ZL: | ||
| 1275 | return true; | ||
| 1276 | default: | ||
| 1277 | return false; | ||
| 1278 | } | ||
| 1279 | } | ||
| 1280 | |||
| 1136 | AnalogMapping SDLState::GetAnalogMappingForDevice(const Common::ParamPackage& params) { | 1281 | AnalogMapping SDLState::GetAnalogMappingForDevice(const Common::ParamPackage& params) { |
| 1137 | if (!params.Has("guid") || !params.Has("port")) { | 1282 | if (!params.Has("guid") || !params.Has("port")) { |
| 1138 | return {}; | 1283 | return {}; |
| 1139 | } | 1284 | } |
| 1140 | const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0)); | 1285 | const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0)); |
| 1286 | const auto joystick2 = GetSDLJoystickByGUID(params.Get("guid2", ""), params.Get("port", 0)); | ||
| 1141 | auto* controller = joystick->GetSDLGameController(); | 1287 | auto* controller = joystick->GetSDLGameController(); |
| 1142 | if (controller == nullptr) { | 1288 | if (controller == nullptr) { |
| 1143 | return {}; | 1289 | return {}; |
| @@ -1148,10 +1294,17 @@ AnalogMapping SDLState::GetAnalogMappingForDevice(const Common::ParamPackage& pa | |||
| 1148 | SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX); | 1294 | SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX); |
| 1149 | const auto& binding_left_y = | 1295 | const auto& binding_left_y = |
| 1150 | SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY); | 1296 | SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY); |
| 1151 | mapping.insert_or_assign(Settings::NativeAnalog::LStick, | 1297 | if (params.Has("guid2")) { |
| 1152 | BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(), | 1298 | mapping.insert_or_assign( |
| 1153 | binding_left_x.value.axis, | 1299 | Settings::NativeAnalog::LStick, |
| 1154 | binding_left_y.value.axis)); | 1300 | BuildParamPackageForAnalog(joystick2->GetPort(), joystick2->GetGUID(), |
| 1301 | binding_left_x.value.axis, binding_left_y.value.axis)); | ||
| 1302 | } else { | ||
| 1303 | mapping.insert_or_assign( | ||
| 1304 | Settings::NativeAnalog::LStick, | ||
| 1305 | BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(), | ||
| 1306 | binding_left_x.value.axis, binding_left_y.value.axis)); | ||
| 1307 | } | ||
| 1155 | const auto& binding_right_x = | 1308 | const auto& binding_right_x = |
| 1156 | SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX); | 1309 | SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX); |
| 1157 | const auto& binding_right_y = | 1310 | const auto& binding_right_y = |
| @@ -1168,20 +1321,32 @@ MotionMapping SDLState::GetMotionMappingForDevice(const Common::ParamPackage& pa | |||
| 1168 | return {}; | 1321 | return {}; |
| 1169 | } | 1322 | } |
| 1170 | const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0)); | 1323 | const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0)); |
| 1324 | const auto joystick2 = GetSDLJoystickByGUID(params.Get("guid2", ""), params.Get("port", 0)); | ||
| 1171 | auto* controller = joystick->GetSDLGameController(); | 1325 | auto* controller = joystick->GetSDLGameController(); |
| 1172 | if (controller == nullptr) { | 1326 | if (controller == nullptr) { |
| 1173 | return {}; | 1327 | return {}; |
| 1174 | } | 1328 | } |
| 1175 | 1329 | ||
| 1330 | MotionMapping mapping = {}; | ||
| 1176 | joystick->EnableMotion(); | 1331 | joystick->EnableMotion(); |
| 1177 | 1332 | ||
| 1178 | if (!joystick->HasGyro() && !joystick->HasAccel()) { | 1333 | if (joystick->HasGyro() || joystick->HasAccel()) { |
| 1179 | return {}; | 1334 | mapping.insert_or_assign(Settings::NativeMotion::MotionRight, |
| 1335 | BuildMotionParam(joystick->GetPort(), joystick->GetGUID())); | ||
| 1336 | } | ||
| 1337 | if (params.Has("guid2")) { | ||
| 1338 | joystick2->EnableMotion(); | ||
| 1339 | if (joystick2->HasGyro() || joystick2->HasAccel()) { | ||
| 1340 | mapping.insert_or_assign(Settings::NativeMotion::MotionLeft, | ||
| 1341 | BuildMotionParam(joystick2->GetPort(), joystick2->GetGUID())); | ||
| 1342 | } | ||
| 1343 | } else { | ||
| 1344 | if (joystick->HasGyro() || joystick->HasAccel()) { | ||
| 1345 | mapping.insert_or_assign(Settings::NativeMotion::MotionLeft, | ||
| 1346 | BuildMotionParam(joystick->GetPort(), joystick->GetGUID())); | ||
| 1347 | } | ||
| 1180 | } | 1348 | } |
| 1181 | 1349 | ||
| 1182 | MotionMapping mapping = {}; | ||
| 1183 | mapping.insert_or_assign(Settings::NativeMotion::MotionLeft, | ||
| 1184 | BuildMotionParam(joystick->GetPort(), joystick->GetGUID())); | ||
| 1185 | return mapping; | 1350 | return mapping; |
| 1186 | } | 1351 | } |
| 1187 | namespace Polling { | 1352 | namespace Polling { |
diff --git a/src/input_common/sdl/sdl_impl.h b/src/input_common/sdl/sdl_impl.h index 121e01913..b77afcbd8 100644 --- a/src/input_common/sdl/sdl_impl.h +++ b/src/input_common/sdl/sdl_impl.h | |||
| @@ -9,6 +9,17 @@ | |||
| 9 | #include <mutex> | 9 | #include <mutex> |
| 10 | #include <thread> | 10 | #include <thread> |
| 11 | #include <unordered_map> | 11 | #include <unordered_map> |
| 12 | |||
| 13 | // Ignore -Wimplicit-fallthrough due to https://github.com/libsdl-org/SDL/issues/4307 | ||
| 14 | #ifdef __GNUC__ | ||
| 15 | #pragma GCC diagnostic push | ||
| 16 | #pragma GCC diagnostic ignored "-Wimplicit-fallthrough" | ||
| 17 | #endif | ||
| 18 | #include <SDL.h> | ||
| 19 | #ifdef __GNUC__ | ||
| 20 | #pragma GCC diagnostic pop | ||
| 21 | #endif | ||
| 22 | |||
| 12 | #include "common/common_types.h" | 23 | #include "common/common_types.h" |
| 13 | #include "common/threadsafe_queue.h" | 24 | #include "common/threadsafe_queue.h" |
| 14 | #include "input_common/sdl/sdl.h" | 25 | #include "input_common/sdl/sdl.h" |
| @@ -18,6 +29,11 @@ using SDL_GameController = struct _SDL_GameController; | |||
| 18 | using SDL_Joystick = struct _SDL_Joystick; | 29 | using SDL_Joystick = struct _SDL_Joystick; |
| 19 | using SDL_JoystickID = s32; | 30 | using SDL_JoystickID = s32; |
| 20 | 31 | ||
| 32 | using ButtonBindings = | ||
| 33 | std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerButton>, 17>; | ||
| 34 | using ZButtonBindings = | ||
| 35 | std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerAxis>, 2>; | ||
| 36 | |||
| 21 | namespace InputCommon::SDL { | 37 | namespace InputCommon::SDL { |
| 22 | 38 | ||
| 23 | class SDLAnalogFactory; | 39 | class SDLAnalogFactory; |
| @@ -66,8 +82,25 @@ private: | |||
| 66 | /// Needs to be called before SDL_QuitSubSystem. | 82 | /// Needs to be called before SDL_QuitSubSystem. |
| 67 | void CloseJoysticks(); | 83 | void CloseJoysticks(); |
| 68 | 84 | ||
| 69 | /// Returns a custom name for specific controllers because the default name is not correct | 85 | /// Returns the default button bindings list for generic controllers |
| 70 | std::string GetControllerName(SDL_GameController* controller) const; | 86 | ButtonBindings GetDefaultButtonBinding() const; |
| 87 | |||
| 88 | /// Returns the default button bindings list for nintendo controllers | ||
| 89 | ButtonBindings GetNintendoButtonBinding(const std::shared_ptr<SDLJoystick>& joystick) const; | ||
| 90 | |||
| 91 | /// Returns the button mappings from a single controller | ||
| 92 | ButtonMapping GetSingleControllerMapping(const std::shared_ptr<SDLJoystick>& joystick, | ||
| 93 | const ButtonBindings& switch_to_sdl_button, | ||
| 94 | const ZButtonBindings& switch_to_sdl_axis) const; | ||
| 95 | |||
| 96 | /// Returns the button mappings from two different controllers | ||
| 97 | ButtonMapping GetDualControllerMapping(const std::shared_ptr<SDLJoystick>& joystick, | ||
| 98 | const std::shared_ptr<SDLJoystick>& joystick2, | ||
| 99 | const ButtonBindings& switch_to_sdl_button, | ||
| 100 | const ZButtonBindings& switch_to_sdl_axis) const; | ||
| 101 | |||
| 102 | /// Returns true if the button is on the left joycon | ||
| 103 | bool IsButtonOnLeftSide(Settings::NativeButton::Values button) const; | ||
| 71 | 104 | ||
| 72 | // Set to true if SDL supports game controller subsystem | 105 | // Set to true if SDL supports game controller subsystem |
| 73 | bool has_gamecontroller = false; | 106 | bool has_gamecontroller = false; |
diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp index fa37aa79a..5edd06ebc 100644 --- a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp +++ b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp | |||
| @@ -53,6 +53,18 @@ struct Range { | |||
| 53 | UNREACHABLE_MSG("Invalid memory usage={}", usage); | 53 | UNREACHABLE_MSG("Invalid memory usage={}", usage); |
| 54 | return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; | 54 | return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; |
| 55 | } | 55 | } |
| 56 | |||
| 57 | constexpr VkExportMemoryAllocateInfo EXPORT_ALLOCATE_INFO{ | ||
| 58 | .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO, | ||
| 59 | .pNext = nullptr, | ||
| 60 | #ifdef _WIN32 | ||
| 61 | .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT, | ||
| 62 | #elif __unix__ | ||
| 63 | .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT, | ||
| 64 | #else | ||
| 65 | .handleTypes = 0, | ||
| 66 | #endif | ||
| 67 | }; | ||
| 56 | } // Anonymous namespace | 68 | } // Anonymous namespace |
| 57 | 69 | ||
| 58 | class MemoryAllocation { | 70 | class MemoryAllocation { |
| @@ -131,7 +143,7 @@ public: | |||
| 131 | 143 | ||
| 132 | /// Returns whether this allocation is compatible with the arguments. | 144 | /// Returns whether this allocation is compatible with the arguments. |
| 133 | [[nodiscard]] bool IsCompatible(VkMemoryPropertyFlags flags, u32 type_mask) const { | 145 | [[nodiscard]] bool IsCompatible(VkMemoryPropertyFlags flags, u32 type_mask) const { |
| 134 | return (flags & property_flags) && (type_mask & shifted_memory_type) != 0; | 146 | return (flags & property_flags) == property_flags && (type_mask & shifted_memory_type) != 0; |
| 135 | } | 147 | } |
| 136 | 148 | ||
| 137 | private: | 149 | private: |
| @@ -217,14 +229,18 @@ MemoryAllocator::~MemoryAllocator() = default; | |||
| 217 | 229 | ||
| 218 | MemoryCommit MemoryAllocator::Commit(const VkMemoryRequirements& requirements, MemoryUsage usage) { | 230 | MemoryCommit MemoryAllocator::Commit(const VkMemoryRequirements& requirements, MemoryUsage usage) { |
| 219 | // Find the fastest memory flags we can afford with the current requirements | 231 | // Find the fastest memory flags we can afford with the current requirements |
| 220 | const VkMemoryPropertyFlags flags = MemoryPropertyFlags(requirements.memoryTypeBits, usage); | 232 | const u32 type_mask = requirements.memoryTypeBits; |
| 233 | const VkMemoryPropertyFlags usage_flags = MemoryUsagePropertyFlags(usage); | ||
| 234 | const VkMemoryPropertyFlags flags = MemoryPropertyFlags(type_mask, usage_flags); | ||
| 221 | if (std::optional<MemoryCommit> commit = TryCommit(requirements, flags)) { | 235 | if (std::optional<MemoryCommit> commit = TryCommit(requirements, flags)) { |
| 222 | return std::move(*commit); | 236 | return std::move(*commit); |
| 223 | } | 237 | } |
| 224 | // Commit has failed, allocate more memory. | 238 | // Commit has failed, allocate more memory. |
| 225 | // TODO(Rodrigo): Handle out of memory situations in some way like flushing to guest memory. | 239 | const u64 chunk_size = AllocationChunkSize(requirements.size); |
| 226 | AllocMemory(flags, requirements.memoryTypeBits, AllocationChunkSize(requirements.size)); | 240 | if (!TryAllocMemory(flags, type_mask, chunk_size)) { |
| 227 | 241 | // TODO(Rodrigo): Handle out of memory situations in some way like flushing to guest memory. | |
| 242 | throw vk::Exception(VK_ERROR_OUT_OF_DEVICE_MEMORY); | ||
| 243 | } | ||
| 228 | // Commit again, this time it won't fail since there's a fresh allocation above. | 244 | // Commit again, this time it won't fail since there's a fresh allocation above. |
| 229 | // If it does, there's a bug. | 245 | // If it does, there's a bug. |
| 230 | return TryCommit(requirements, flags).value(); | 246 | return TryCommit(requirements, flags).value(); |
| @@ -242,26 +258,25 @@ MemoryCommit MemoryAllocator::Commit(const vk::Image& image, MemoryUsage usage) | |||
| 242 | return commit; | 258 | return commit; |
| 243 | } | 259 | } |
| 244 | 260 | ||
| 245 | void MemoryAllocator::AllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size) { | 261 | bool MemoryAllocator::TryAllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size) { |
| 246 | const u32 type = FindType(flags, type_mask).value(); | 262 | const u32 type = FindType(flags, type_mask).value(); |
| 247 | const VkExportMemoryAllocateInfo export_allocate_info{ | 263 | vk::DeviceMemory memory = device.GetLogical().TryAllocateMemory({ |
| 248 | .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO, | ||
| 249 | .pNext = nullptr, | ||
| 250 | #ifdef _WIN32 | ||
| 251 | .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT, | ||
| 252 | #elif __unix__ | ||
| 253 | .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT, | ||
| 254 | #else | ||
| 255 | .handleTypes = 0, | ||
| 256 | #endif | ||
| 257 | }; | ||
| 258 | vk::DeviceMemory memory = device.GetLogical().AllocateMemory({ | ||
| 259 | .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, | 264 | .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, |
| 260 | .pNext = export_allocations ? &export_allocate_info : nullptr, | 265 | .pNext = export_allocations ? &EXPORT_ALLOCATE_INFO : nullptr, |
| 261 | .allocationSize = size, | 266 | .allocationSize = size, |
| 262 | .memoryTypeIndex = type, | 267 | .memoryTypeIndex = type, |
| 263 | }); | 268 | }); |
| 269 | if (!memory) { | ||
| 270 | if ((flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0) { | ||
| 271 | // Try to allocate non device local memory | ||
| 272 | return TryAllocMemory(flags & ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, type_mask, size); | ||
| 273 | } else { | ||
| 274 | // RIP | ||
| 275 | return false; | ||
| 276 | } | ||
| 277 | } | ||
| 264 | allocations.push_back(std::make_unique<MemoryAllocation>(std::move(memory), flags, size, type)); | 278 | allocations.push_back(std::make_unique<MemoryAllocation>(std::move(memory), flags, size, type)); |
| 279 | return true; | ||
| 265 | } | 280 | } |
| 266 | 281 | ||
| 267 | std::optional<MemoryCommit> MemoryAllocator::TryCommit(const VkMemoryRequirements& requirements, | 282 | std::optional<MemoryCommit> MemoryAllocator::TryCommit(const VkMemoryRequirements& requirements, |
| @@ -274,24 +289,24 @@ std::optional<MemoryCommit> MemoryAllocator::TryCommit(const VkMemoryRequirement | |||
| 274 | return commit; | 289 | return commit; |
| 275 | } | 290 | } |
| 276 | } | 291 | } |
| 292 | if ((flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0) { | ||
| 293 | // Look for non device local commits on failure | ||
| 294 | return TryCommit(requirements, flags & ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); | ||
| 295 | } | ||
| 277 | return std::nullopt; | 296 | return std::nullopt; |
| 278 | } | 297 | } |
| 279 | 298 | ||
| 280 | VkMemoryPropertyFlags MemoryAllocator::MemoryPropertyFlags(u32 type_mask, MemoryUsage usage) const { | ||
| 281 | return MemoryPropertyFlags(type_mask, MemoryUsagePropertyFlags(usage)); | ||
| 282 | } | ||
| 283 | |||
| 284 | VkMemoryPropertyFlags MemoryAllocator::MemoryPropertyFlags(u32 type_mask, | 299 | VkMemoryPropertyFlags MemoryAllocator::MemoryPropertyFlags(u32 type_mask, |
| 285 | VkMemoryPropertyFlags flags) const { | 300 | VkMemoryPropertyFlags flags) const { |
| 286 | if (FindType(flags, type_mask)) { | 301 | if (FindType(flags, type_mask)) { |
| 287 | // Found a memory type with those requirements | 302 | // Found a memory type with those requirements |
| 288 | return flags; | 303 | return flags; |
| 289 | } | 304 | } |
| 290 | if (flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) { | 305 | if ((flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) != 0) { |
| 291 | // Remove host cached bit in case it's not supported | 306 | // Remove host cached bit in case it's not supported |
| 292 | return MemoryPropertyFlags(type_mask, flags & ~VK_MEMORY_PROPERTY_HOST_CACHED_BIT); | 307 | return MemoryPropertyFlags(type_mask, flags & ~VK_MEMORY_PROPERTY_HOST_CACHED_BIT); |
| 293 | } | 308 | } |
| 294 | if (flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) { | 309 | if ((flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0) { |
| 295 | // Remove device local, if it's not supported by the requested resource | 310 | // Remove device local, if it's not supported by the requested resource |
| 296 | return MemoryPropertyFlags(type_mask, flags & ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); | 311 | return MemoryPropertyFlags(type_mask, flags & ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); |
| 297 | } | 312 | } |
| @@ -302,7 +317,7 @@ VkMemoryPropertyFlags MemoryAllocator::MemoryPropertyFlags(u32 type_mask, | |||
| 302 | std::optional<u32> MemoryAllocator::FindType(VkMemoryPropertyFlags flags, u32 type_mask) const { | 317 | std::optional<u32> MemoryAllocator::FindType(VkMemoryPropertyFlags flags, u32 type_mask) const { |
| 303 | for (u32 type_index = 0; type_index < properties.memoryTypeCount; ++type_index) { | 318 | for (u32 type_index = 0; type_index < properties.memoryTypeCount; ++type_index) { |
| 304 | const VkMemoryPropertyFlags type_flags = properties.memoryTypes[type_index].propertyFlags; | 319 | const VkMemoryPropertyFlags type_flags = properties.memoryTypes[type_index].propertyFlags; |
| 305 | if ((type_mask & (1U << type_index)) && (type_flags & flags)) { | 320 | if ((type_mask & (1U << type_index)) != 0 && (type_flags & flags) == flags) { |
| 306 | // The type matches in type and in the wanted properties. | 321 | // The type matches in type and in the wanted properties. |
| 307 | return type_index; | 322 | return type_index; |
| 308 | } | 323 | } |
diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.h b/src/video_core/vulkan_common/vulkan_memory_allocator.h index d1ce29450..db12d02f4 100644 --- a/src/video_core/vulkan_common/vulkan_memory_allocator.h +++ b/src/video_core/vulkan_common/vulkan_memory_allocator.h | |||
| @@ -101,16 +101,13 @@ public: | |||
| 101 | MemoryCommit Commit(const vk::Image& image, MemoryUsage usage); | 101 | MemoryCommit Commit(const vk::Image& image, MemoryUsage usage); |
| 102 | 102 | ||
| 103 | private: | 103 | private: |
| 104 | /// Allocates a chunk of memory. | 104 | /// Tries to allocate a chunk of memory. |
| 105 | void AllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size); | 105 | bool TryAllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size); |
| 106 | 106 | ||
| 107 | /// Tries to allocate a memory commit. | 107 | /// Tries to allocate a memory commit. |
| 108 | std::optional<MemoryCommit> TryCommit(const VkMemoryRequirements& requirements, | 108 | std::optional<MemoryCommit> TryCommit(const VkMemoryRequirements& requirements, |
| 109 | VkMemoryPropertyFlags flags); | 109 | VkMemoryPropertyFlags flags); |
| 110 | 110 | ||
| 111 | /// Returns the fastest compatible memory property flags from a wanted usage. | ||
| 112 | VkMemoryPropertyFlags MemoryPropertyFlags(u32 type_mask, MemoryUsage usage) const; | ||
| 113 | |||
| 114 | /// Returns the fastest compatible memory property flags from the wanted flags. | 111 | /// Returns the fastest compatible memory property flags from the wanted flags. |
| 115 | VkMemoryPropertyFlags MemoryPropertyFlags(u32 type_mask, VkMemoryPropertyFlags flags) const; | 112 | VkMemoryPropertyFlags MemoryPropertyFlags(u32 type_mask, VkMemoryPropertyFlags flags) const; |
| 116 | 113 | ||
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index eb58bfa5b..552454acf 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp | |||
| @@ -16,7 +16,7 @@ | |||
| 16 | 16 | ||
| 17 | namespace FS = Common::FS; | 17 | namespace FS = Common::FS; |
| 18 | 18 | ||
| 19 | Config::Config(const std::string& config_name, ConfigType config_type) : type(config_type) { | 19 | Config::Config(std::string_view config_name, ConfigType config_type) : type(config_type) { |
| 20 | global = config_type == ConfigType::GlobalConfig; | 20 | global = config_type == ConfigType::GlobalConfig; |
| 21 | 21 | ||
| 22 | Initialize(config_name); | 22 | Initialize(config_name); |
| @@ -242,7 +242,7 @@ const std::array<UISettings::Shortcut, 17> Config::default_hotkeys{{ | |||
| 242 | }}; | 242 | }}; |
| 243 | // clang-format on | 243 | // clang-format on |
| 244 | 244 | ||
| 245 | void Config::Initialize(const std::string& config_name) { | 245 | void Config::Initialize(std::string_view config_name) { |
| 246 | const auto fs_config_loc = FS::GetYuzuPath(FS::YuzuPath::ConfigDir); | 246 | const auto fs_config_loc = FS::GetYuzuPath(FS::YuzuPath::ConfigDir); |
| 247 | const auto config_file = fmt::format("{}.ini", config_name); | 247 | const auto config_file = fmt::format("{}.ini", config_name); |
| 248 | 248 | ||
diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h index ce3355588..114a2eaa7 100644 --- a/src/yuzu/configuration/config.h +++ b/src/yuzu/configuration/config.h | |||
| @@ -22,7 +22,7 @@ public: | |||
| 22 | InputProfile, | 22 | InputProfile, |
| 23 | }; | 23 | }; |
| 24 | 24 | ||
| 25 | explicit Config(const std::string& config_name = "qt-config", | 25 | explicit Config(std::string_view config_name = "qt-config", |
| 26 | ConfigType config_type = ConfigType::GlobalConfig); | 26 | ConfigType config_type = ConfigType::GlobalConfig); |
| 27 | ~Config(); | 27 | ~Config(); |
| 28 | 28 | ||
| @@ -45,7 +45,7 @@ public: | |||
| 45 | static const std::array<UISettings::Shortcut, 17> default_hotkeys; | 45 | static const std::array<UISettings::Shortcut, 17> default_hotkeys; |
| 46 | 46 | ||
| 47 | private: | 47 | private: |
| 48 | void Initialize(const std::string& config_name); | 48 | void Initialize(std::string_view config_name); |
| 49 | 49 | ||
| 50 | void ReadValues(); | 50 | void ReadValues(); |
| 51 | void ReadPlayerValue(std::size_t player_index); | 51 | void ReadPlayerValue(std::size_t player_index); |
diff --git a/src/yuzu/configuration/configure_per_game.cpp b/src/yuzu/configuration/configure_per_game.cpp index d89f1ad4b..7dfcf150c 100644 --- a/src/yuzu/configuration/configure_per_game.cpp +++ b/src/yuzu/configuration/configure_per_game.cpp | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | #include <memory> | 6 | #include <memory> |
| 7 | #include <string> | ||
| 7 | #include <utility> | 8 | #include <utility> |
| 8 | 9 | ||
| 9 | #include <QAbstractButton> | 10 | #include <QAbstractButton> |
| @@ -17,6 +18,7 @@ | |||
| 17 | #include <QTimer> | 18 | #include <QTimer> |
| 18 | #include <QTreeView> | 19 | #include <QTreeView> |
| 19 | 20 | ||
| 21 | #include "common/fs/path_util.h" | ||
| 20 | #include "core/core.h" | 22 | #include "core/core.h" |
| 21 | #include "core/file_sys/control_metadata.h" | 23 | #include "core/file_sys/control_metadata.h" |
| 22 | #include "core/file_sys/patch_manager.h" | 24 | #include "core/file_sys/patch_manager.h" |
| @@ -29,10 +31,11 @@ | |||
| 29 | #include "yuzu/uisettings.h" | 31 | #include "yuzu/uisettings.h" |
| 30 | #include "yuzu/util/util.h" | 32 | #include "yuzu/util/util.h" |
| 31 | 33 | ||
| 32 | ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id) | 34 | ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id, std::string_view file_name) |
| 33 | : QDialog(parent), ui(std::make_unique<Ui::ConfigurePerGame>()), title_id(title_id) { | 35 | : QDialog(parent), ui(std::make_unique<Ui::ConfigurePerGame>()), title_id(title_id) { |
| 34 | game_config = std::make_unique<Config>(fmt::format("{:016X}", title_id), | 36 | const auto config_file_name = |
| 35 | Config::ConfigType::PerGameConfig); | 37 | title_id == 0 ? Common::FS::GetFilename(file_name) : fmt::format("{:016X}", title_id); |
| 38 | game_config = std::make_unique<Config>(config_file_name, Config::ConfigType::PerGameConfig); | ||
| 36 | 39 | ||
| 37 | Settings::SetConfiguringGlobal(false); | 40 | Settings::SetConfiguringGlobal(false); |
| 38 | 41 | ||
diff --git a/src/yuzu/configuration/configure_per_game.h b/src/yuzu/configuration/configure_per_game.h index f6e6ab7c4..dc6b68763 100644 --- a/src/yuzu/configuration/configure_per_game.h +++ b/src/yuzu/configuration/configure_per_game.h | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <memory> | 7 | #include <memory> |
| 8 | #include <string> | ||
| 8 | #include <vector> | 9 | #include <vector> |
| 9 | 10 | ||
| 10 | #include <QDialog> | 11 | #include <QDialog> |
| @@ -27,7 +28,7 @@ class ConfigurePerGame : public QDialog { | |||
| 27 | Q_OBJECT | 28 | Q_OBJECT |
| 28 | 29 | ||
| 29 | public: | 30 | public: |
| 30 | explicit ConfigurePerGame(QWidget* parent, u64 title_id); | 31 | explicit ConfigurePerGame(QWidget* parent, u64 title_id, std::string_view file_name); |
| 31 | ~ConfigurePerGame() override; | 32 | ~ConfigurePerGame() override; |
| 32 | 33 | ||
| 33 | /// Save all button configurations to settings file | 34 | /// Save all button configurations to settings file |
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index 63cf82f7d..aa3bd5e34 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp | |||
| @@ -561,11 +561,11 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri | |||
| 561 | connect(remove_dlc, &QAction::triggered, [this, program_id]() { | 561 | connect(remove_dlc, &QAction::triggered, [this, program_id]() { |
| 562 | emit RemoveInstalledEntryRequested(program_id, InstalledEntryType::AddOnContent); | 562 | emit RemoveInstalledEntryRequested(program_id, InstalledEntryType::AddOnContent); |
| 563 | }); | 563 | }); |
| 564 | connect(remove_shader_cache, &QAction::triggered, [this, program_id]() { | 564 | connect(remove_shader_cache, &QAction::triggered, [this, program_id, path]() { |
| 565 | emit RemoveFileRequested(program_id, GameListRemoveTarget::ShaderCache); | 565 | emit RemoveFileRequested(program_id, GameListRemoveTarget::ShaderCache, path); |
| 566 | }); | 566 | }); |
| 567 | connect(remove_custom_config, &QAction::triggered, [this, program_id]() { | 567 | connect(remove_custom_config, &QAction::triggered, [this, program_id, path]() { |
| 568 | emit RemoveFileRequested(program_id, GameListRemoveTarget::CustomConfiguration); | 568 | emit RemoveFileRequested(program_id, GameListRemoveTarget::CustomConfiguration, path); |
| 569 | }); | 569 | }); |
| 570 | connect(dump_romfs, &QAction::triggered, | 570 | connect(dump_romfs, &QAction::triggered, |
| 571 | [this, program_id, path]() { emit DumpRomFSRequested(program_id, path); }); | 571 | [this, program_id, path]() { emit DumpRomFSRequested(program_id, path); }); |
diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h index 9c0a1a482..2867f6653 100644 --- a/src/yuzu/game_list.h +++ b/src/yuzu/game_list.h | |||
| @@ -88,7 +88,8 @@ signals: | |||
| 88 | const std::string& game_path); | 88 | const std::string& game_path); |
| 89 | void OpenTransferableShaderCacheRequested(u64 program_id); | 89 | void OpenTransferableShaderCacheRequested(u64 program_id); |
| 90 | void RemoveInstalledEntryRequested(u64 program_id, InstalledEntryType type); | 90 | void RemoveInstalledEntryRequested(u64 program_id, InstalledEntryType type); |
| 91 | void RemoveFileRequested(u64 program_id, GameListRemoveTarget target); | 91 | void RemoveFileRequested(u64 program_id, GameListRemoveTarget target, |
| 92 | std::string_view game_path); | ||
| 92 | void DumpRomFSRequested(u64 program_id, const std::string& game_path); | 93 | void DumpRomFSRequested(u64 program_id, const std::string& game_path); |
| 93 | void CopyTIDRequested(u64 program_id); | 94 | void CopyTIDRequested(u64 program_id); |
| 94 | void NavigateToGamedbEntryRequested(u64 program_id, | 95 | void NavigateToGamedbEntryRequested(u64 program_id, |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 0f0e228b0..dd8dd3233 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -1334,7 +1334,10 @@ void GMainWindow::BootGame(const QString& filename, std::size_t program_index) { | |||
| 1334 | 1334 | ||
| 1335 | if (!(loader == nullptr || loader->ReadProgramId(title_id) != Loader::ResultStatus::Success)) { | 1335 | if (!(loader == nullptr || loader->ReadProgramId(title_id) != Loader::ResultStatus::Success)) { |
| 1336 | // Load per game settings | 1336 | // Load per game settings |
| 1337 | Config per_game_config(fmt::format("{:016X}", title_id), Config::ConfigType::PerGameConfig); | 1337 | const auto config_file_name = title_id == 0 |
| 1338 | ? Common::FS::GetFilename(filename.toStdString()) | ||
| 1339 | : fmt::format("{:016X}", title_id); | ||
| 1340 | Config per_game_config(config_file_name, Config::ConfigType::PerGameConfig); | ||
| 1338 | } | 1341 | } |
| 1339 | 1342 | ||
| 1340 | ConfigureVibration::SetAllVibrationDevices(); | 1343 | ConfigureVibration::SetAllVibrationDevices(); |
| @@ -1795,7 +1798,8 @@ void GMainWindow::RemoveAddOnContent(u64 program_id, const QString& entry_type) | |||
| 1795 | tr("Successfully removed %1 installed DLC.").arg(count)); | 1798 | tr("Successfully removed %1 installed DLC.").arg(count)); |
| 1796 | } | 1799 | } |
| 1797 | 1800 | ||
| 1798 | void GMainWindow::OnGameListRemoveFile(u64 program_id, GameListRemoveTarget target) { | 1801 | void GMainWindow::OnGameListRemoveFile(u64 program_id, GameListRemoveTarget target, |
| 1802 | std::string_view game_path) { | ||
| 1799 | const QString question = [this, target] { | 1803 | const QString question = [this, target] { |
| 1800 | switch (target) { | 1804 | switch (target) { |
| 1801 | case GameListRemoveTarget::ShaderCache: | 1805 | case GameListRemoveTarget::ShaderCache: |
| @@ -1817,7 +1821,7 @@ void GMainWindow::OnGameListRemoveFile(u64 program_id, GameListRemoveTarget targ | |||
| 1817 | RemoveTransferableShaderCache(program_id); | 1821 | RemoveTransferableShaderCache(program_id); |
| 1818 | break; | 1822 | break; |
| 1819 | case GameListRemoveTarget::CustomConfiguration: | 1823 | case GameListRemoveTarget::CustomConfiguration: |
| 1820 | RemoveCustomConfiguration(program_id); | 1824 | RemoveCustomConfiguration(program_id, game_path); |
| 1821 | break; | 1825 | break; |
| 1822 | } | 1826 | } |
| 1823 | } | 1827 | } |
| @@ -1842,9 +1846,12 @@ void GMainWindow::RemoveTransferableShaderCache(u64 program_id) { | |||
| 1842 | } | 1846 | } |
| 1843 | } | 1847 | } |
| 1844 | 1848 | ||
| 1845 | void GMainWindow::RemoveCustomConfiguration(u64 program_id) { | 1849 | void GMainWindow::RemoveCustomConfiguration(u64 program_id, std::string_view game_path) { |
| 1846 | const auto custom_config_file_path = Common::FS::GetYuzuPath(Common::FS::YuzuPath::ConfigDir) / | 1850 | const auto config_file_name = program_id == 0 |
| 1847 | "custom" / fmt::format("{:016X}.ini", program_id); | 1851 | ? fmt::format("{:s}.ini", Common::FS::GetFilename(game_path)) |
| 1852 | : fmt::format("{:016X}.ini", program_id); | ||
| 1853 | const auto custom_config_file_path = | ||
| 1854 | Common::FS::GetYuzuPath(Common::FS::YuzuPath::ConfigDir) / "custom" / config_file_name; | ||
| 1848 | 1855 | ||
| 1849 | if (!Common::FS::Exists(custom_config_file_path)) { | 1856 | if (!Common::FS::Exists(custom_config_file_path)) { |
| 1850 | QMessageBox::warning(this, tr("Error Removing Custom Configuration"), | 1857 | QMessageBox::warning(this, tr("Error Removing Custom Configuration"), |
| @@ -2635,7 +2642,7 @@ void GMainWindow::OpenPerGameConfiguration(u64 title_id, const std::string& file | |||
| 2635 | const auto v_file = Core::GetGameFileFromPath(vfs, file_name); | 2642 | const auto v_file = Core::GetGameFileFromPath(vfs, file_name); |
| 2636 | const auto& system = Core::System::GetInstance(); | 2643 | const auto& system = Core::System::GetInstance(); |
| 2637 | 2644 | ||
| 2638 | ConfigurePerGame dialog(this, title_id); | 2645 | ConfigurePerGame dialog(this, title_id, file_name); |
| 2639 | dialog.LoadFromFile(v_file); | 2646 | dialog.LoadFromFile(v_file); |
| 2640 | const auto result = dialog.exec(); | 2647 | const auto result = dialog.exec(); |
| 2641 | 2648 | ||
diff --git a/src/yuzu/main.h b/src/yuzu/main.h index b3a5033ce..135681d41 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h | |||
| @@ -236,7 +236,8 @@ private slots: | |||
| 236 | const std::string& game_path); | 236 | const std::string& game_path); |
| 237 | void OnTransferableShaderCacheOpenFile(u64 program_id); | 237 | void OnTransferableShaderCacheOpenFile(u64 program_id); |
| 238 | void OnGameListRemoveInstalledEntry(u64 program_id, InstalledEntryType type); | 238 | void OnGameListRemoveInstalledEntry(u64 program_id, InstalledEntryType type); |
| 239 | void OnGameListRemoveFile(u64 program_id, GameListRemoveTarget target); | 239 | void OnGameListRemoveFile(u64 program_id, GameListRemoveTarget target, |
| 240 | std::string_view game_path); | ||
| 240 | void OnGameListDumpRomFS(u64 program_id, const std::string& game_path); | 241 | void OnGameListDumpRomFS(u64 program_id, const std::string& game_path); |
| 241 | void OnGameListCopyTID(u64 program_id); | 242 | void OnGameListCopyTID(u64 program_id); |
| 242 | void OnGameListNavigateToGamedbEntry(u64 program_id, | 243 | void OnGameListNavigateToGamedbEntry(u64 program_id, |
| @@ -275,7 +276,7 @@ private: | |||
| 275 | void RemoveUpdateContent(u64 program_id, const QString& entry_type); | 276 | void RemoveUpdateContent(u64 program_id, const QString& entry_type); |
| 276 | void RemoveAddOnContent(u64 program_id, const QString& entry_type); | 277 | void RemoveAddOnContent(u64 program_id, const QString& entry_type); |
| 277 | void RemoveTransferableShaderCache(u64 program_id); | 278 | void RemoveTransferableShaderCache(u64 program_id); |
| 278 | void RemoveCustomConfiguration(u64 program_id); | 279 | void RemoveCustomConfiguration(u64 program_id, std::string_view game_path); |
| 279 | std::optional<u64> SelectRomFSDumpTarget(const FileSys::ContentProvider&, u64 program_id); | 280 | std::optional<u64> SelectRomFSDumpTarget(const FileSys::ContentProvider&, u64 program_id); |
| 280 | InstallResult InstallNSPXCI(const QString& filename); | 281 | InstallResult InstallNSPXCI(const QString& filename); |
| 281 | InstallResult InstallNCA(const QString& filename); | 282 | InstallResult InstallNCA(const QString& filename); |