diff options
52 files changed, 490 insertions, 326 deletions
diff --git a/externals/dynarmic b/externals/dynarmic | |||
| Subproject 82417da7803e2cf18efc28a1cd3f3d0a4b6045a | Subproject 0e1112b7df77ae55a62a51622940d5c8f9e8c84 | ||
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 78c3bfb3b..5d54516eb 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt | |||
| @@ -172,7 +172,6 @@ add_library(common STATIC | |||
| 172 | virtual_buffer.h | 172 | virtual_buffer.h |
| 173 | wall_clock.cpp | 173 | wall_clock.cpp |
| 174 | wall_clock.h | 174 | wall_clock.h |
| 175 | web_result.h | ||
| 176 | zstd_compression.cpp | 175 | zstd_compression.cpp |
| 177 | zstd_compression.h | 176 | zstd_compression.h |
| 178 | ) | 177 | ) |
diff --git a/src/common/color.h b/src/common/color.h index 381d6332e..bbcac858e 100644 --- a/src/common/color.h +++ b/src/common/color.h | |||
| @@ -10,7 +10,7 @@ | |||
| 10 | #include "common/swap.h" | 10 | #include "common/swap.h" |
| 11 | #include "common/vector_math.h" | 11 | #include "common/vector_math.h" |
| 12 | 12 | ||
| 13 | namespace Color { | 13 | namespace Common::Color { |
| 14 | 14 | ||
| 15 | /// Convert a 1-bit color component to 8 bit | 15 | /// Convert a 1-bit color component to 8 bit |
| 16 | [[nodiscard]] constexpr u8 Convert1To8(u8 value) { | 16 | [[nodiscard]] constexpr u8 Convert1To8(u8 value) { |
| @@ -268,4 +268,4 @@ inline void EncodeX24S8(u8 stencil, u8* bytes) { | |||
| 268 | bytes[3] = stencil; | 268 | bytes[3] = stencil; |
| 269 | } | 269 | } |
| 270 | 270 | ||
| 271 | } // namespace Color | 271 | } // namespace Common::Color |
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index 443ca72eb..b5f28a86e 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp | |||
| @@ -143,7 +143,7 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable& | |||
| 143 | config.wall_clock_cntpct = uses_wall_clock; | 143 | config.wall_clock_cntpct = uses_wall_clock; |
| 144 | 144 | ||
| 145 | // Safe optimizations | 145 | // Safe optimizations |
| 146 | if (Settings::values.cpu_accuracy != Settings::CPUAccuracy::Accurate) { | 146 | if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::DebugMode) { |
| 147 | if (!Settings::values.cpuopt_page_tables) { | 147 | if (!Settings::values.cpuopt_page_tables) { |
| 148 | config.page_table = nullptr; | 148 | config.page_table = nullptr; |
| 149 | } | 149 | } |
| @@ -170,6 +170,17 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable& | |||
| 170 | } | 170 | } |
| 171 | } | 171 | } |
| 172 | 172 | ||
| 173 | // Unsafe optimizations | ||
| 174 | if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::Unsafe) { | ||
| 175 | config.unsafe_optimizations = true; | ||
| 176 | if (Settings::values.cpuopt_unsafe_unfuse_fma) { | ||
| 177 | config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA; | ||
| 178 | } | ||
| 179 | if (Settings::values.cpuopt_unsafe_reduce_fp_error) { | ||
| 180 | config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP; | ||
| 181 | } | ||
| 182 | } | ||
| 183 | |||
| 173 | return std::make_unique<Dynarmic::A32::Jit>(config); | 184 | return std::make_unique<Dynarmic::A32::Jit>(config); |
| 174 | } | 185 | } |
| 175 | 186 | ||
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index a63a04a25..ce9968724 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp | |||
| @@ -195,7 +195,7 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable& | |||
| 195 | config.wall_clock_cntpct = uses_wall_clock; | 195 | config.wall_clock_cntpct = uses_wall_clock; |
| 196 | 196 | ||
| 197 | // Safe optimizations | 197 | // Safe optimizations |
| 198 | if (Settings::values.cpu_accuracy != Settings::CPUAccuracy::Accurate) { | 198 | if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::DebugMode) { |
| 199 | if (!Settings::values.cpuopt_page_tables) { | 199 | if (!Settings::values.cpuopt_page_tables) { |
| 200 | config.page_table = nullptr; | 200 | config.page_table = nullptr; |
| 201 | } | 201 | } |
| @@ -222,6 +222,17 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable& | |||
| 222 | } | 222 | } |
| 223 | } | 223 | } |
| 224 | 224 | ||
| 225 | // Unsafe optimizations | ||
| 226 | if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::Unsafe) { | ||
| 227 | config.unsafe_optimizations = true; | ||
| 228 | if (Settings::values.cpuopt_unsafe_unfuse_fma) { | ||
| 229 | config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA; | ||
| 230 | } | ||
| 231 | if (Settings::values.cpuopt_unsafe_reduce_fp_error) { | ||
| 232 | config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP; | ||
| 233 | } | ||
| 234 | } | ||
| 235 | |||
| 225 | return std::make_shared<Dynarmic::A64::Jit>(config); | 236 | return std::make_shared<Dynarmic::A64::Jit>(config); |
| 226 | } | 237 | } |
| 227 | 238 | ||
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index 71af26ec5..e6c8461a5 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp | |||
| @@ -7,14 +7,14 @@ | |||
| 7 | #include <string> | 7 | #include <string> |
| 8 | #include <tuple> | 8 | #include <tuple> |
| 9 | 9 | ||
| 10 | #include "common/assert.h" | ||
| 11 | #include "common/microprofile.h" | 10 | #include "common/microprofile.h" |
| 12 | #include "core/core_timing.h" | 11 | #include "core/core_timing.h" |
| 13 | #include "core/core_timing_util.h" | 12 | #include "core/core_timing_util.h" |
| 13 | #include "core/hardware_properties.h" | ||
| 14 | 14 | ||
| 15 | namespace Core::Timing { | 15 | namespace Core::Timing { |
| 16 | 16 | ||
| 17 | constexpr u64 MAX_SLICE_LENGTH = 4000; | 17 | constexpr s64 MAX_SLICE_LENGTH = 4000; |
| 18 | 18 | ||
| 19 | std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callback) { | 19 | std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callback) { |
| 20 | return std::make_shared<EventType>(std::move(callback), std::move(name)); | 20 | return std::make_shared<EventType>(std::move(callback), std::move(name)); |
| @@ -37,10 +37,8 @@ struct CoreTiming::Event { | |||
| 37 | } | 37 | } |
| 38 | }; | 38 | }; |
| 39 | 39 | ||
| 40 | CoreTiming::CoreTiming() { | 40 | CoreTiming::CoreTiming() |
| 41 | clock = | 41 | : clock{Common::CreateBestMatchingClock(Hardware::BASE_CLOCK_RATE, Hardware::CNTFREQ)} {} |
| 42 | Common::CreateBestMatchingClock(Core::Hardware::BASE_CLOCK_RATE, Core::Hardware::CNTFREQ); | ||
| 43 | } | ||
| 44 | 42 | ||
| 45 | CoreTiming::~CoreTiming() = default; | 43 | CoreTiming::~CoreTiming() = default; |
| 46 | 44 | ||
| @@ -136,7 +134,7 @@ void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type, | |||
| 136 | 134 | ||
| 137 | void CoreTiming::AddTicks(u64 ticks) { | 135 | void CoreTiming::AddTicks(u64 ticks) { |
| 138 | this->ticks += ticks; | 136 | this->ticks += ticks; |
| 139 | downcount -= ticks; | 137 | downcount -= static_cast<s64>(ticks); |
| 140 | } | 138 | } |
| 141 | 139 | ||
| 142 | void CoreTiming::Idle() { | 140 | void CoreTiming::Idle() { |
diff --git a/src/core/core_timing_util.cpp b/src/core/core_timing_util.cpp index aefc63663..8ce8e602e 100644 --- a/src/core/core_timing_util.cpp +++ b/src/core/core_timing_util.cpp | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include <limits> | 8 | #include <limits> |
| 9 | #include "common/logging/log.h" | 9 | #include "common/logging/log.h" |
| 10 | #include "common/uint128.h" | 10 | #include "common/uint128.h" |
| 11 | #include "core/hardware_properties.h" | ||
| 11 | 12 | ||
| 12 | namespace Core::Timing { | 13 | namespace Core::Timing { |
| 13 | 14 | ||
diff --git a/src/core/core_timing_util.h b/src/core/core_timing_util.h index 2ed979e14..e4a046bf9 100644 --- a/src/core/core_timing_util.h +++ b/src/core/core_timing_util.h | |||
| @@ -6,7 +6,6 @@ | |||
| 6 | 6 | ||
| 7 | #include <chrono> | 7 | #include <chrono> |
| 8 | #include "common/common_types.h" | 8 | #include "common/common_types.h" |
| 9 | #include "core/hardware_properties.h" | ||
| 10 | 9 | ||
| 11 | namespace Core::Timing { | 10 | namespace Core::Timing { |
| 12 | 11 | ||
diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp index 358943429..ef0bae556 100644 --- a/src/core/cpu_manager.cpp +++ b/src/core/cpu_manager.cpp | |||
| @@ -41,9 +41,9 @@ void CpuManager::Shutdown() { | |||
| 41 | running_mode = false; | 41 | running_mode = false; |
| 42 | Pause(false); | 42 | Pause(false); |
| 43 | if (is_multicore) { | 43 | if (is_multicore) { |
| 44 | for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { | 44 | for (auto& data : core_data) { |
| 45 | core_data[core].host_thread->join(); | 45 | data.host_thread->join(); |
| 46 | core_data[core].host_thread.reset(); | 46 | data.host_thread.reset(); |
| 47 | } | 47 | } |
| 48 | } else { | 48 | } else { |
| 49 | core_data[0].host_thread->join(); | 49 | core_data[0].host_thread->join(); |
| @@ -166,25 +166,23 @@ void CpuManager::MultiCorePause(bool paused) { | |||
| 166 | bool all_not_barrier = false; | 166 | bool all_not_barrier = false; |
| 167 | while (!all_not_barrier) { | 167 | while (!all_not_barrier) { |
| 168 | all_not_barrier = true; | 168 | all_not_barrier = true; |
| 169 | for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { | 169 | for (const auto& data : core_data) { |
| 170 | all_not_barrier &= | 170 | all_not_barrier &= !data.is_running.load() && data.initialized.load(); |
| 171 | !core_data[core].is_running.load() && core_data[core].initialized.load(); | ||
| 172 | } | 171 | } |
| 173 | } | 172 | } |
| 174 | for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { | 173 | for (auto& data : core_data) { |
| 175 | core_data[core].enter_barrier->Set(); | 174 | data.enter_barrier->Set(); |
| 176 | } | 175 | } |
| 177 | if (paused_state.load()) { | 176 | if (paused_state.load()) { |
| 178 | bool all_barrier = false; | 177 | bool all_barrier = false; |
| 179 | while (!all_barrier) { | 178 | while (!all_barrier) { |
| 180 | all_barrier = true; | 179 | all_barrier = true; |
| 181 | for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { | 180 | for (const auto& data : core_data) { |
| 182 | all_barrier &= | 181 | all_barrier &= data.is_paused.load() && data.initialized.load(); |
| 183 | core_data[core].is_paused.load() && core_data[core].initialized.load(); | ||
| 184 | } | 182 | } |
| 185 | } | 183 | } |
| 186 | for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { | 184 | for (auto& data : core_data) { |
| 187 | core_data[core].exit_barrier->Set(); | 185 | data.exit_barrier->Set(); |
| 188 | } | 186 | } |
| 189 | } | 187 | } |
| 190 | } else { | 188 | } else { |
| @@ -192,9 +190,8 @@ void CpuManager::MultiCorePause(bool paused) { | |||
| 192 | bool all_barrier = false; | 190 | bool all_barrier = false; |
| 193 | while (!all_barrier) { | 191 | while (!all_barrier) { |
| 194 | all_barrier = true; | 192 | all_barrier = true; |
| 195 | for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { | 193 | for (const auto& data : core_data) { |
| 196 | all_barrier &= | 194 | all_barrier &= data.is_paused.load() && data.initialized.load(); |
| 197 | core_data[core].is_paused.load() && core_data[core].initialized.load(); | ||
| 198 | } | 195 | } |
| 199 | } | 196 | } |
| 200 | /// Don't release the barrier | 197 | /// Don't release the barrier |
diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp index 8783d1ac2..dc591c730 100644 --- a/src/core/crypto/key_manager.cpp +++ b/src/core/crypto/key_manager.cpp | |||
| @@ -36,6 +36,7 @@ | |||
| 36 | #include "core/settings.h" | 36 | #include "core/settings.h" |
| 37 | 37 | ||
| 38 | namespace Core::Crypto { | 38 | namespace Core::Crypto { |
| 39 | namespace { | ||
| 39 | 40 | ||
| 40 | constexpr u64 CURRENT_CRYPTO_REVISION = 0x5; | 41 | constexpr u64 CURRENT_CRYPTO_REVISION = 0x5; |
| 41 | constexpr u64 FULL_TICKET_SIZE = 0x400; | 42 | constexpr u64 FULL_TICKET_SIZE = 0x400; |
| @@ -49,7 +50,72 @@ constexpr std::array eticket_source_hashes{ | |||
| 49 | }; | 50 | }; |
| 50 | // clang-format on | 51 | // clang-format on |
| 51 | 52 | ||
| 52 | const std::map<std::pair<S128KeyType, u64>, std::string> KEYS_VARIABLE_LENGTH{ | 53 | constexpr std::array<std::pair<std::string_view, KeyIndex<S128KeyType>>, 30> s128_file_id{{ |
| 54 | {"eticket_rsa_kek", {S128KeyType::ETicketRSAKek, 0, 0}}, | ||
| 55 | {"eticket_rsa_kek_source", | ||
| 56 | {S128KeyType::Source, static_cast<u64>(SourceKeyType::ETicketKek), 0}}, | ||
| 57 | {"eticket_rsa_kekek_source", | ||
| 58 | {S128KeyType::Source, static_cast<u64>(SourceKeyType::ETicketKekek), 0}}, | ||
| 59 | {"rsa_kek_mask_0", {S128KeyType::RSAKek, static_cast<u64>(RSAKekType::Mask0), 0}}, | ||
| 60 | {"rsa_kek_seed_3", {S128KeyType::RSAKek, static_cast<u64>(RSAKekType::Seed3), 0}}, | ||
| 61 | {"rsa_oaep_kek_generation_source", | ||
| 62 | {S128KeyType::Source, static_cast<u64>(SourceKeyType::RSAOaepKekGeneration), 0}}, | ||
| 63 | {"sd_card_kek_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::SDKek), 0}}, | ||
| 64 | {"aes_kek_generation_source", | ||
| 65 | {S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKekGeneration), 0}}, | ||
| 66 | {"aes_key_generation_source", | ||
| 67 | {S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKeyGeneration), 0}}, | ||
| 68 | {"package2_key_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::Package2), 0}}, | ||
| 69 | {"master_key_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::Master), 0}}, | ||
| 70 | {"header_kek_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::HeaderKek), 0}}, | ||
| 71 | {"key_area_key_application_source", | ||
| 72 | {S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyAreaKey), | ||
| 73 | static_cast<u64>(KeyAreaKeyType::Application)}}, | ||
| 74 | {"key_area_key_ocean_source", | ||
| 75 | {S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyAreaKey), | ||
| 76 | static_cast<u64>(KeyAreaKeyType::Ocean)}}, | ||
| 77 | {"key_area_key_system_source", | ||
| 78 | {S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyAreaKey), | ||
| 79 | static_cast<u64>(KeyAreaKeyType::System)}}, | ||
| 80 | {"titlekek_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::Titlekek), 0}}, | ||
| 81 | {"keyblob_mac_key_source", | ||
| 82 | {S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyblobMAC), 0}}, | ||
| 83 | {"tsec_key", {S128KeyType::TSEC, 0, 0}}, | ||
| 84 | {"secure_boot_key", {S128KeyType::SecureBoot, 0, 0}}, | ||
| 85 | {"sd_seed", {S128KeyType::SDSeed, 0, 0}}, | ||
| 86 | {"bis_key_0_crypt", {S128KeyType::BIS, 0, static_cast<u64>(BISKeyType::Crypto)}}, | ||
| 87 | {"bis_key_0_tweak", {S128KeyType::BIS, 0, static_cast<u64>(BISKeyType::Tweak)}}, | ||
| 88 | {"bis_key_1_crypt", {S128KeyType::BIS, 1, static_cast<u64>(BISKeyType::Crypto)}}, | ||
| 89 | {"bis_key_1_tweak", {S128KeyType::BIS, 1, static_cast<u64>(BISKeyType::Tweak)}}, | ||
| 90 | {"bis_key_2_crypt", {S128KeyType::BIS, 2, static_cast<u64>(BISKeyType::Crypto)}}, | ||
| 91 | {"bis_key_2_tweak", {S128KeyType::BIS, 2, static_cast<u64>(BISKeyType::Tweak)}}, | ||
| 92 | {"bis_key_3_crypt", {S128KeyType::BIS, 3, static_cast<u64>(BISKeyType::Crypto)}}, | ||
| 93 | {"bis_key_3_tweak", {S128KeyType::BIS, 3, static_cast<u64>(BISKeyType::Tweak)}}, | ||
| 94 | {"header_kek", {S128KeyType::HeaderKek, 0, 0}}, | ||
| 95 | {"sd_card_kek", {S128KeyType::SDKek, 0, 0}}, | ||
| 96 | }}; | ||
| 97 | |||
| 98 | auto Find128ByName(std::string_view name) { | ||
| 99 | return std::find_if(s128_file_id.begin(), s128_file_id.end(), | ||
| 100 | [&name](const auto& pair) { return pair.first == name; }); | ||
| 101 | } | ||
| 102 | |||
| 103 | constexpr std::array<std::pair<std::string_view, KeyIndex<S256KeyType>>, 6> s256_file_id{{ | ||
| 104 | {"header_key", {S256KeyType::Header, 0, 0}}, | ||
| 105 | {"sd_card_save_key_source", {S256KeyType::SDKeySource, static_cast<u64>(SDKeyType::Save), 0}}, | ||
| 106 | {"sd_card_nca_key_source", {S256KeyType::SDKeySource, static_cast<u64>(SDKeyType::NCA), 0}}, | ||
| 107 | {"header_key_source", {S256KeyType::HeaderSource, 0, 0}}, | ||
| 108 | {"sd_card_save_key", {S256KeyType::SDKey, static_cast<u64>(SDKeyType::Save), 0}}, | ||
| 109 | {"sd_card_nca_key", {S256KeyType::SDKey, static_cast<u64>(SDKeyType::NCA), 0}}, | ||
| 110 | }}; | ||
| 111 | |||
| 112 | auto Find256ByName(std::string_view name) { | ||
| 113 | return std::find_if(s256_file_id.begin(), s256_file_id.end(), | ||
| 114 | [&name](const auto& pair) { return pair.first == name; }); | ||
| 115 | } | ||
| 116 | |||
| 117 | using KeyArray = std::array<std::pair<std::pair<S128KeyType, u64>, std::string_view>, 7>; | ||
| 118 | constexpr KeyArray KEYS_VARIABLE_LENGTH{{ | ||
| 53 | {{S128KeyType::Master, 0}, "master_key_"}, | 119 | {{S128KeyType::Master, 0}, "master_key_"}, |
| 54 | {{S128KeyType::Package1, 0}, "package1_key_"}, | 120 | {{S128KeyType::Package1, 0}, "package1_key_"}, |
| 55 | {{S128KeyType::Package2, 0}, "package2_key_"}, | 121 | {{S128KeyType::Package2, 0}, "package2_key_"}, |
| @@ -57,14 +123,13 @@ const std::map<std::pair<S128KeyType, u64>, std::string> KEYS_VARIABLE_LENGTH{ | |||
| 57 | {{S128KeyType::Source, static_cast<u64>(SourceKeyType::Keyblob)}, "keyblob_key_source_"}, | 123 | {{S128KeyType::Source, static_cast<u64>(SourceKeyType::Keyblob)}, "keyblob_key_source_"}, |
| 58 | {{S128KeyType::Keyblob, 0}, "keyblob_key_"}, | 124 | {{S128KeyType::Keyblob, 0}, "keyblob_key_"}, |
| 59 | {{S128KeyType::KeyblobMAC, 0}, "keyblob_mac_key_"}, | 125 | {{S128KeyType::KeyblobMAC, 0}, "keyblob_mac_key_"}, |
| 60 | }; | 126 | }}; |
| 61 | 127 | ||
| 62 | namespace { | ||
| 63 | template <std::size_t Size> | 128 | template <std::size_t Size> |
| 64 | bool IsAllZeroArray(const std::array<u8, Size>& array) { | 129 | bool IsAllZeroArray(const std::array<u8, Size>& array) { |
| 65 | return std::all_of(array.begin(), array.end(), [](const auto& elem) { return elem == 0; }); | 130 | return std::all_of(array.begin(), array.end(), [](const auto& elem) { return elem == 0; }); |
| 66 | } | 131 | } |
| 67 | } // namespace | 132 | } // Anonymous namespace |
| 68 | 133 | ||
| 69 | u64 GetSignatureTypeDataSize(SignatureType type) { | 134 | u64 GetSignatureTypeDataSize(SignatureType type) { |
| 70 | switch (type) { | 135 | switch (type) { |
| @@ -564,13 +629,13 @@ void KeyManager::LoadFromFile(const std::string& filename, bool is_title_keys) { | |||
| 564 | s128_keys[{S128KeyType::Titlekey, rights_id[1], rights_id[0]}] = key; | 629 | s128_keys[{S128KeyType::Titlekey, rights_id[1], rights_id[0]}] = key; |
| 565 | } else { | 630 | } else { |
| 566 | out[0] = Common::ToLower(out[0]); | 631 | out[0] = Common::ToLower(out[0]); |
| 567 | if (s128_file_id.find(out[0]) != s128_file_id.end()) { | 632 | if (const auto iter128 = Find128ByName(out[0]); iter128 != s128_file_id.end()) { |
| 568 | const auto index = s128_file_id.at(out[0]); | 633 | const auto& index = iter128->second; |
| 569 | Key128 key = Common::HexStringToArray<16>(out[1]); | 634 | const Key128 key = Common::HexStringToArray<16>(out[1]); |
| 570 | s128_keys[{index.type, index.field1, index.field2}] = key; | 635 | s128_keys[{index.type, index.field1, index.field2}] = key; |
| 571 | } else if (s256_file_id.find(out[0]) != s256_file_id.end()) { | 636 | } else if (const auto iter256 = Find256ByName(out[0]); iter256 != s256_file_id.end()) { |
| 572 | const auto index = s256_file_id.at(out[0]); | 637 | const auto& index = iter256->second; |
| 573 | Key256 key = Common::HexStringToArray<32>(out[1]); | 638 | const Key256 key = Common::HexStringToArray<32>(out[1]); |
| 574 | s256_keys[{index.type, index.field1, index.field2}] = key; | 639 | s256_keys[{index.type, index.field1, index.field2}] = key; |
| 575 | } else if (out[0].compare(0, 8, "keyblob_") == 0 && | 640 | } else if (out[0].compare(0, 8, "keyblob_") == 0 && |
| 576 | out[0].compare(0, 9, "keyblob_k") != 0) { | 641 | out[0].compare(0, 9, "keyblob_k") != 0) { |
| @@ -742,8 +807,7 @@ void KeyManager::SetKey(S128KeyType id, Key128 key, u64 field1, u64 field2) { | |||
| 742 | } | 807 | } |
| 743 | 808 | ||
| 744 | const auto iter2 = std::find_if( | 809 | const auto iter2 = std::find_if( |
| 745 | s128_file_id.begin(), s128_file_id.end(), | 810 | s128_file_id.begin(), s128_file_id.end(), [&id, &field1, &field2](const auto& elem) { |
| 746 | [&id, &field1, &field2](const std::pair<std::string, KeyIndex<S128KeyType>> elem) { | ||
| 747 | return std::tie(elem.second.type, elem.second.field1, elem.second.field2) == | 811 | return std::tie(elem.second.type, elem.second.field1, elem.second.field2) == |
| 748 | std::tie(id, field1, field2); | 812 | std::tie(id, field1, field2); |
| 749 | }); | 813 | }); |
| @@ -753,9 +817,11 @@ void KeyManager::SetKey(S128KeyType id, Key128 key, u64 field1, u64 field2) { | |||
| 753 | 817 | ||
| 754 | // Variable cases | 818 | // Variable cases |
| 755 | if (id == S128KeyType::KeyArea) { | 819 | if (id == S128KeyType::KeyArea) { |
| 756 | static constexpr std::array<const char*, 3> kak_names = {"key_area_key_application_{:02X}", | 820 | static constexpr std::array<const char*, 3> kak_names = { |
| 757 | "key_area_key_ocean_{:02X}", | 821 | "key_area_key_application_{:02X}", |
| 758 | "key_area_key_system_{:02X}"}; | 822 | "key_area_key_ocean_{:02X}", |
| 823 | "key_area_key_system_{:02X}", | ||
| 824 | }; | ||
| 759 | WriteKeyToFile(category, fmt::format(kak_names.at(field2), field1), key); | 825 | WriteKeyToFile(category, fmt::format(kak_names.at(field2), field1), key); |
| 760 | } else if (id == S128KeyType::Master) { | 826 | } else if (id == S128KeyType::Master) { |
| 761 | WriteKeyToFile(category, fmt::format("master_key_{:02X}", field1), key); | 827 | WriteKeyToFile(category, fmt::format("master_key_{:02X}", field1), key); |
| @@ -781,8 +847,7 @@ void KeyManager::SetKey(S256KeyType id, Key256 key, u64 field1, u64 field2) { | |||
| 781 | return; | 847 | return; |
| 782 | } | 848 | } |
| 783 | const auto iter = std::find_if( | 849 | const auto iter = std::find_if( |
| 784 | s256_file_id.begin(), s256_file_id.end(), | 850 | s256_file_id.begin(), s256_file_id.end(), [&id, &field1, &field2](const auto& elem) { |
| 785 | [&id, &field1, &field2](const std::pair<std::string, KeyIndex<S256KeyType>> elem) { | ||
| 786 | return std::tie(elem.second.type, elem.second.field1, elem.second.field2) == | 851 | return std::tie(elem.second.type, elem.second.field1, elem.second.field2) == |
| 787 | std::tie(id, field1, field2); | 852 | std::tie(id, field1, field2); |
| 788 | }); | 853 | }); |
| @@ -1245,58 +1310,4 @@ bool KeyManager::AddTicketPersonalized(Ticket raw) { | |||
| 1245 | SetKey(S128KeyType::Titlekey, key, rights_id[1], rights_id[0]); | 1310 | SetKey(S128KeyType::Titlekey, key, rights_id[1], rights_id[0]); |
| 1246 | return true; | 1311 | return true; |
| 1247 | } | 1312 | } |
| 1248 | |||
| 1249 | const boost::container::flat_map<std::string, KeyIndex<S128KeyType>> KeyManager::s128_file_id = { | ||
| 1250 | {"eticket_rsa_kek", {S128KeyType::ETicketRSAKek, 0, 0}}, | ||
| 1251 | {"eticket_rsa_kek_source", | ||
| 1252 | {S128KeyType::Source, static_cast<u64>(SourceKeyType::ETicketKek), 0}}, | ||
| 1253 | {"eticket_rsa_kekek_source", | ||
| 1254 | {S128KeyType::Source, static_cast<u64>(SourceKeyType::ETicketKekek), 0}}, | ||
| 1255 | {"rsa_kek_mask_0", {S128KeyType::RSAKek, static_cast<u64>(RSAKekType::Mask0), 0}}, | ||
| 1256 | {"rsa_kek_seed_3", {S128KeyType::RSAKek, static_cast<u64>(RSAKekType::Seed3), 0}}, | ||
| 1257 | {"rsa_oaep_kek_generation_source", | ||
| 1258 | {S128KeyType::Source, static_cast<u64>(SourceKeyType::RSAOaepKekGeneration), 0}}, | ||
| 1259 | {"sd_card_kek_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::SDKek), 0}}, | ||
| 1260 | {"aes_kek_generation_source", | ||
| 1261 | {S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKekGeneration), 0}}, | ||
| 1262 | {"aes_key_generation_source", | ||
| 1263 | {S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKeyGeneration), 0}}, | ||
| 1264 | {"package2_key_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::Package2), 0}}, | ||
| 1265 | {"master_key_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::Master), 0}}, | ||
| 1266 | {"header_kek_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::HeaderKek), 0}}, | ||
| 1267 | {"key_area_key_application_source", | ||
| 1268 | {S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyAreaKey), | ||
| 1269 | static_cast<u64>(KeyAreaKeyType::Application)}}, | ||
| 1270 | {"key_area_key_ocean_source", | ||
| 1271 | {S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyAreaKey), | ||
| 1272 | static_cast<u64>(KeyAreaKeyType::Ocean)}}, | ||
| 1273 | {"key_area_key_system_source", | ||
| 1274 | {S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyAreaKey), | ||
| 1275 | static_cast<u64>(KeyAreaKeyType::System)}}, | ||
| 1276 | {"titlekek_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::Titlekek), 0}}, | ||
| 1277 | {"keyblob_mac_key_source", | ||
| 1278 | {S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyblobMAC), 0}}, | ||
| 1279 | {"tsec_key", {S128KeyType::TSEC, 0, 0}}, | ||
| 1280 | {"secure_boot_key", {S128KeyType::SecureBoot, 0, 0}}, | ||
| 1281 | {"sd_seed", {S128KeyType::SDSeed, 0, 0}}, | ||
| 1282 | {"bis_key_0_crypt", {S128KeyType::BIS, 0, static_cast<u64>(BISKeyType::Crypto)}}, | ||
| 1283 | {"bis_key_0_tweak", {S128KeyType::BIS, 0, static_cast<u64>(BISKeyType::Tweak)}}, | ||
| 1284 | {"bis_key_1_crypt", {S128KeyType::BIS, 1, static_cast<u64>(BISKeyType::Crypto)}}, | ||
| 1285 | {"bis_key_1_tweak", {S128KeyType::BIS, 1, static_cast<u64>(BISKeyType::Tweak)}}, | ||
| 1286 | {"bis_key_2_crypt", {S128KeyType::BIS, 2, static_cast<u64>(BISKeyType::Crypto)}}, | ||
| 1287 | {"bis_key_2_tweak", {S128KeyType::BIS, 2, static_cast<u64>(BISKeyType::Tweak)}}, | ||
| 1288 | {"bis_key_3_crypt", {S128KeyType::BIS, 3, static_cast<u64>(BISKeyType::Crypto)}}, | ||
| 1289 | {"bis_key_3_tweak", {S128KeyType::BIS, 3, static_cast<u64>(BISKeyType::Tweak)}}, | ||
| 1290 | {"header_kek", {S128KeyType::HeaderKek, 0, 0}}, | ||
| 1291 | {"sd_card_kek", {S128KeyType::SDKek, 0, 0}}, | ||
| 1292 | }; | ||
| 1293 | |||
| 1294 | const boost::container::flat_map<std::string, KeyIndex<S256KeyType>> KeyManager::s256_file_id = { | ||
| 1295 | {"header_key", {S256KeyType::Header, 0, 0}}, | ||
| 1296 | {"sd_card_save_key_source", {S256KeyType::SDKeySource, static_cast<u64>(SDKeyType::Save), 0}}, | ||
| 1297 | {"sd_card_nca_key_source", {S256KeyType::SDKeySource, static_cast<u64>(SDKeyType::NCA), 0}}, | ||
| 1298 | {"header_key_source", {S256KeyType::HeaderSource, 0, 0}}, | ||
| 1299 | {"sd_card_save_key", {S256KeyType::SDKey, static_cast<u64>(SDKeyType::Save), 0}}, | ||
| 1300 | {"sd_card_nca_key", {S256KeyType::SDKey, static_cast<u64>(SDKeyType::NCA), 0}}, | ||
| 1301 | }; | ||
| 1302 | } // namespace Core::Crypto | 1313 | } // namespace Core::Crypto |
diff --git a/src/core/crypto/key_manager.h b/src/core/crypto/key_manager.h index bdca3770a..321b75323 100644 --- a/src/core/crypto/key_manager.h +++ b/src/core/crypto/key_manager.h | |||
| @@ -10,7 +10,6 @@ | |||
| 10 | #include <string> | 10 | #include <string> |
| 11 | 11 | ||
| 12 | #include <variant> | 12 | #include <variant> |
| 13 | #include <boost/container/flat_map.hpp> | ||
| 14 | #include <fmt/format.h> | 13 | #include <fmt/format.h> |
| 15 | #include "common/common_funcs.h" | 14 | #include "common/common_funcs.h" |
| 16 | #include "common/common_types.h" | 15 | #include "common/common_types.h" |
| @@ -293,9 +292,6 @@ private: | |||
| 293 | 292 | ||
| 294 | void SetKeyWrapped(S128KeyType id, Key128 key, u64 field1 = 0, u64 field2 = 0); | 293 | void SetKeyWrapped(S128KeyType id, Key128 key, u64 field1 = 0, u64 field2 = 0); |
| 295 | void SetKeyWrapped(S256KeyType id, Key256 key, u64 field1 = 0, u64 field2 = 0); | 294 | void SetKeyWrapped(S256KeyType id, Key256 key, u64 field1 = 0, u64 field2 = 0); |
| 296 | |||
| 297 | static const boost::container::flat_map<std::string, KeyIndex<S128KeyType>> s128_file_id; | ||
| 298 | static const boost::container::flat_map<std::string, KeyIndex<S256KeyType>> s256_file_id; | ||
| 299 | }; | 295 | }; |
| 300 | 296 | ||
| 301 | Key128 GenerateKeyEncryptionKey(Key128 source, Key128 master, Key128 kek_seed, Key128 key_seed); | 297 | Key128 GenerateKeyEncryptionKey(Key128 source, Key128 master, Key128 kek_seed, Key128 key_seed); |
diff --git a/src/core/file_sys/vfs_real.cpp b/src/core/file_sys/vfs_real.cpp index 1dbf632c1..488687ba9 100644 --- a/src/core/file_sys/vfs_real.cpp +++ b/src/core/file_sys/vfs_real.cpp | |||
| @@ -72,8 +72,10 @@ VfsEntryType RealVfsFilesystem::GetEntryType(std::string_view path_) const { | |||
| 72 | 72 | ||
| 73 | VirtualFile RealVfsFilesystem::OpenFile(std::string_view path_, Mode perms) { | 73 | VirtualFile RealVfsFilesystem::OpenFile(std::string_view path_, Mode perms) { |
| 74 | const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault); | 74 | const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault); |
| 75 | if (cache.find(path) != cache.end()) { | 75 | |
| 76 | auto weak = cache[path]; | 76 | if (const auto weak_iter = cache.find(path); weak_iter != cache.cend()) { |
| 77 | const auto& weak = weak_iter->second; | ||
| 78 | |||
| 77 | if (!weak.expired()) { | 79 | if (!weak.expired()) { |
| 78 | return std::shared_ptr<RealVfsFile>(new RealVfsFile(*this, weak.lock(), path, perms)); | 80 | return std::shared_ptr<RealVfsFile>(new RealVfsFile(*this, weak.lock(), path, perms)); |
| 79 | } | 81 | } |
| @@ -84,7 +86,7 @@ VirtualFile RealVfsFilesystem::OpenFile(std::string_view path_, Mode perms) { | |||
| 84 | } | 86 | } |
| 85 | 87 | ||
| 86 | auto backing = std::make_shared<FS::IOFile>(path, ModeFlagsToString(perms).c_str()); | 88 | auto backing = std::make_shared<FS::IOFile>(path, ModeFlagsToString(perms).c_str()); |
| 87 | cache[path] = backing; | 89 | cache.insert_or_assign(path, backing); |
| 88 | 90 | ||
| 89 | // Cannot use make_shared as RealVfsFile constructor is private | 91 | // Cannot use make_shared as RealVfsFile constructor is private |
| 90 | return std::shared_ptr<RealVfsFile>(new RealVfsFile(*this, backing, path, perms)); | 92 | return std::shared_ptr<RealVfsFile>(new RealVfsFile(*this, backing, path, perms)); |
| @@ -116,11 +118,12 @@ VirtualFile RealVfsFilesystem::CopyFile(std::string_view old_path_, std::string_ | |||
| 116 | VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_view new_path_) { | 118 | VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_view new_path_) { |
| 117 | const auto old_path = FS::SanitizePath(old_path_, FS::DirectorySeparator::PlatformDefault); | 119 | const auto old_path = FS::SanitizePath(old_path_, FS::DirectorySeparator::PlatformDefault); |
| 118 | const auto new_path = FS::SanitizePath(new_path_, FS::DirectorySeparator::PlatformDefault); | 120 | const auto new_path = FS::SanitizePath(new_path_, FS::DirectorySeparator::PlatformDefault); |
| 121 | const auto cached_file_iter = cache.find(old_path); | ||
| 119 | 122 | ||
| 120 | if (cache.find(old_path) != cache.end()) { | 123 | if (cached_file_iter != cache.cend()) { |
| 121 | auto file = cache[old_path].lock(); | 124 | auto file = cached_file_iter->second.lock(); |
| 122 | 125 | ||
| 123 | if (!cache[old_path].expired()) { | 126 | if (!cached_file_iter->second.expired()) { |
| 124 | file->Close(); | 127 | file->Close(); |
| 125 | } | 128 | } |
| 126 | 129 | ||
| @@ -131,7 +134,7 @@ VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_ | |||
| 131 | 134 | ||
| 132 | cache.erase(old_path); | 135 | cache.erase(old_path); |
| 133 | file->Open(new_path, "r+b"); | 136 | file->Open(new_path, "r+b"); |
| 134 | cache[new_path] = file; | 137 | cache.insert_or_assign(new_path, std::move(file)); |
| 135 | } else { | 138 | } else { |
| 136 | UNREACHABLE(); | 139 | UNREACHABLE(); |
| 137 | return nullptr; | 140 | return nullptr; |
| @@ -142,12 +145,15 @@ VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_ | |||
| 142 | 145 | ||
| 143 | bool RealVfsFilesystem::DeleteFile(std::string_view path_) { | 146 | bool RealVfsFilesystem::DeleteFile(std::string_view path_) { |
| 144 | const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault); | 147 | const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault); |
| 145 | if (cache.find(path) != cache.end()) { | 148 | const auto cached_iter = cache.find(path); |
| 146 | if (!cache[path].expired()) { | 149 | |
| 147 | cache[path].lock()->Close(); | 150 | if (cached_iter != cache.cend()) { |
| 151 | if (!cached_iter->second.expired()) { | ||
| 152 | cached_iter->second.lock()->Close(); | ||
| 148 | } | 153 | } |
| 149 | cache.erase(path); | 154 | cache.erase(path); |
| 150 | } | 155 | } |
| 156 | |||
| 151 | return FS::Delete(path); | 157 | return FS::Delete(path); |
| 152 | } | 158 | } |
| 153 | 159 | ||
| @@ -192,21 +198,25 @@ VirtualDir RealVfsFilesystem::MoveDirectory(std::string_view old_path_, | |||
| 192 | } | 198 | } |
| 193 | 199 | ||
| 194 | for (auto& kv : cache) { | 200 | for (auto& kv : cache) { |
| 195 | // Path in cache starts with old_path | 201 | // If the path in the cache doesn't start with old_path, then bail on this file. |
| 196 | if (kv.first.rfind(old_path, 0) == 0) { | 202 | if (kv.first.rfind(old_path, 0) != 0) { |
| 197 | const auto file_old_path = | 203 | continue; |
| 198 | FS::SanitizePath(kv.first, FS::DirectorySeparator::PlatformDefault); | 204 | } |
| 199 | const auto file_new_path = | 205 | |
| 200 | FS::SanitizePath(new_path + DIR_SEP + kv.first.substr(old_path.size()), | 206 | const auto file_old_path = |
| 201 | FS::DirectorySeparator::PlatformDefault); | 207 | FS::SanitizePath(kv.first, FS::DirectorySeparator::PlatformDefault); |
| 202 | auto cached = cache[file_old_path]; | 208 | auto file_new_path = FS::SanitizePath(new_path + DIR_SEP + kv.first.substr(old_path.size()), |
| 203 | if (!cached.expired()) { | 209 | FS::DirectorySeparator::PlatformDefault); |
| 204 | auto file = cached.lock(); | 210 | const auto& cached = cache[file_old_path]; |
| 205 | file->Open(file_new_path, "r+b"); | 211 | |
| 206 | cache.erase(file_old_path); | 212 | if (cached.expired()) { |
| 207 | cache[file_new_path] = file; | 213 | continue; |
| 208 | } | ||
| 209 | } | 214 | } |
| 215 | |||
| 216 | auto file = cached.lock(); | ||
| 217 | file->Open(file_new_path, "r+b"); | ||
| 218 | cache.erase(file_old_path); | ||
| 219 | cache.insert_or_assign(std::move(file_new_path), std::move(file)); | ||
| 210 | } | 220 | } |
| 211 | 221 | ||
| 212 | return OpenDirectory(new_path, Mode::ReadWrite); | 222 | return OpenDirectory(new_path, Mode::ReadWrite); |
| @@ -214,15 +224,21 @@ VirtualDir RealVfsFilesystem::MoveDirectory(std::string_view old_path_, | |||
| 214 | 224 | ||
| 215 | bool RealVfsFilesystem::DeleteDirectory(std::string_view path_) { | 225 | bool RealVfsFilesystem::DeleteDirectory(std::string_view path_) { |
| 216 | const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault); | 226 | const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault); |
| 227 | |||
| 217 | for (auto& kv : cache) { | 228 | for (auto& kv : cache) { |
| 218 | // Path in cache starts with old_path | 229 | // If the path in the cache doesn't start with path, then bail on this file. |
| 219 | if (kv.first.rfind(path, 0) == 0) { | 230 | if (kv.first.rfind(path, 0) != 0) { |
| 220 | if (!cache[kv.first].expired()) { | 231 | continue; |
| 221 | cache[kv.first].lock()->Close(); | ||
| 222 | } | ||
| 223 | cache.erase(kv.first); | ||
| 224 | } | 232 | } |
| 233 | |||
| 234 | const auto& entry = cache[kv.first]; | ||
| 235 | if (!entry.expired()) { | ||
| 236 | entry.lock()->Close(); | ||
| 237 | } | ||
| 238 | |||
| 239 | cache.erase(kv.first); | ||
| 225 | } | 240 | } |
| 241 | |||
| 226 | return FS::DeleteDirRecursively(path); | 242 | return FS::DeleteDirRecursively(path); |
| 227 | } | 243 | } |
| 228 | 244 | ||
| @@ -260,14 +276,14 @@ bool RealVfsFile::IsReadable() const { | |||
| 260 | } | 276 | } |
| 261 | 277 | ||
| 262 | std::size_t RealVfsFile::Read(u8* data, std::size_t length, std::size_t offset) const { | 278 | std::size_t RealVfsFile::Read(u8* data, std::size_t length, std::size_t offset) const { |
| 263 | if (!backing->Seek(offset, SEEK_SET)) { | 279 | if (!backing->Seek(static_cast<s64>(offset), SEEK_SET)) { |
| 264 | return 0; | 280 | return 0; |
| 265 | } | 281 | } |
| 266 | return backing->ReadBytes(data, length); | 282 | return backing->ReadBytes(data, length); |
| 267 | } | 283 | } |
| 268 | 284 | ||
| 269 | std::size_t RealVfsFile::Write(const u8* data, std::size_t length, std::size_t offset) { | 285 | std::size_t RealVfsFile::Write(const u8* data, std::size_t length, std::size_t offset) { |
| 270 | if (!backing->Seek(offset, SEEK_SET)) { | 286 | if (!backing->Seek(static_cast<s64>(offset), SEEK_SET)) { |
| 271 | return 0; | 287 | return 0; |
| 272 | } | 288 | } |
| 273 | return backing->WriteBytes(data, length); | 289 | return backing->WriteBytes(data, length); |
diff --git a/src/core/settings.h b/src/core/settings.h index bb145f193..3681b5e9d 100644 --- a/src/core/settings.h +++ b/src/core/settings.h | |||
| @@ -359,7 +359,8 @@ enum class GPUAccuracy : u32 { | |||
| 359 | 359 | ||
| 360 | enum class CPUAccuracy { | 360 | enum class CPUAccuracy { |
| 361 | Accurate = 0, | 361 | Accurate = 0, |
| 362 | DebugMode = 1, | 362 | Unsafe = 1, |
| 363 | DebugMode = 2, | ||
| 363 | }; | 364 | }; |
| 364 | 365 | ||
| 365 | extern bool configuring_global; | 366 | extern bool configuring_global; |
| @@ -419,6 +420,9 @@ struct Values { | |||
| 419 | bool cpuopt_misc_ir; | 420 | bool cpuopt_misc_ir; |
| 420 | bool cpuopt_reduce_misalign_checks; | 421 | bool cpuopt_reduce_misalign_checks; |
| 421 | 422 | ||
| 423 | bool cpuopt_unsafe_unfuse_fma; | ||
| 424 | bool cpuopt_unsafe_reduce_fp_error; | ||
| 425 | |||
| 422 | // Renderer | 426 | // Renderer |
| 423 | Setting<RendererBackend> renderer_backend; | 427 | Setting<RendererBackend> renderer_backend; |
| 424 | bool renderer_debug; | 428 | bool renderer_debug; |
diff --git a/src/video_core/engines/fermi_2d.cpp b/src/video_core/engines/fermi_2d.cpp index ff10ff40d..6e50661a3 100644 --- a/src/video_core/engines/fermi_2d.cpp +++ b/src/video_core/engines/fermi_2d.cpp | |||
| @@ -10,7 +10,13 @@ | |||
| 10 | 10 | ||
| 11 | namespace Tegra::Engines { | 11 | namespace Tegra::Engines { |
| 12 | 12 | ||
| 13 | Fermi2D::Fermi2D(VideoCore::RasterizerInterface& rasterizer) : rasterizer{rasterizer} {} | 13 | Fermi2D::Fermi2D() = default; |
| 14 | |||
| 15 | Fermi2D::~Fermi2D() = default; | ||
| 16 | |||
| 17 | void Fermi2D::BindRasterizer(VideoCore::RasterizerInterface& rasterizer_) { | ||
| 18 | rasterizer = &rasterizer_; | ||
| 19 | } | ||
| 14 | 20 | ||
| 15 | void Fermi2D::CallMethod(u32 method, u32 method_argument, bool is_last_call) { | 21 | void Fermi2D::CallMethod(u32 method, u32 method_argument, bool is_last_call) { |
| 16 | ASSERT_MSG(method < Regs::NUM_REGS, | 22 | ASSERT_MSG(method < Regs::NUM_REGS, |
| @@ -87,7 +93,7 @@ void Fermi2D::HandleSurfaceCopy() { | |||
| 87 | copy_config.src_rect = src_rect; | 93 | copy_config.src_rect = src_rect; |
| 88 | copy_config.dst_rect = dst_rect; | 94 | copy_config.dst_rect = dst_rect; |
| 89 | 95 | ||
| 90 | if (!rasterizer.AccelerateSurfaceCopy(regs.src, regs.dst, copy_config)) { | 96 | if (!rasterizer->AccelerateSurfaceCopy(regs.src, regs.dst, copy_config)) { |
| 91 | UNIMPLEMENTED(); | 97 | UNIMPLEMENTED(); |
| 92 | } | 98 | } |
| 93 | } | 99 | } |
diff --git a/src/video_core/engines/fermi_2d.h b/src/video_core/engines/fermi_2d.h index 8f37d053f..213abfaae 100644 --- a/src/video_core/engines/fermi_2d.h +++ b/src/video_core/engines/fermi_2d.h | |||
| @@ -34,8 +34,11 @@ namespace Tegra::Engines { | |||
| 34 | 34 | ||
| 35 | class Fermi2D final : public EngineInterface { | 35 | class Fermi2D final : public EngineInterface { |
| 36 | public: | 36 | public: |
| 37 | explicit Fermi2D(VideoCore::RasterizerInterface& rasterizer); | 37 | explicit Fermi2D(); |
| 38 | ~Fermi2D() = default; | 38 | ~Fermi2D(); |
| 39 | |||
| 40 | /// Binds a rasterizer to this engine. | ||
| 41 | void BindRasterizer(VideoCore::RasterizerInterface& rasterizer); | ||
| 39 | 42 | ||
| 40 | /// Write the value to the register identified by method. | 43 | /// Write the value to the register identified by method. |
| 41 | void CallMethod(u32 method, u32 method_argument, bool is_last_call) override; | 44 | void CallMethod(u32 method, u32 method_argument, bool is_last_call) override; |
| @@ -149,7 +152,7 @@ public: | |||
| 149 | }; | 152 | }; |
| 150 | 153 | ||
| 151 | private: | 154 | private: |
| 152 | VideoCore::RasterizerInterface& rasterizer; | 155 | VideoCore::RasterizerInterface* rasterizer; |
| 153 | 156 | ||
| 154 | /// Performs the copy from the source surface to the destination surface as configured in the | 157 | /// Performs the copy from the source surface to the destination surface as configured in the |
| 155 | /// registers. | 158 | /// registers. |
diff --git a/src/video_core/engines/kepler_compute.cpp b/src/video_core/engines/kepler_compute.cpp index a82b06a38..898370739 100644 --- a/src/video_core/engines/kepler_compute.cpp +++ b/src/video_core/engines/kepler_compute.cpp | |||
| @@ -16,14 +16,15 @@ | |||
| 16 | 16 | ||
| 17 | namespace Tegra::Engines { | 17 | namespace Tegra::Engines { |
| 18 | 18 | ||
| 19 | KeplerCompute::KeplerCompute(Core::System& system, VideoCore::RasterizerInterface& rasterizer, | 19 | KeplerCompute::KeplerCompute(Core::System& system_, MemoryManager& memory_manager_) |
| 20 | MemoryManager& memory_manager) | 20 | : system{system_}, memory_manager{memory_manager_}, upload_state{memory_manager, regs.upload} {} |
| 21 | : system{system}, rasterizer{rasterizer}, memory_manager{memory_manager}, upload_state{ | ||
| 22 | memory_manager, | ||
| 23 | regs.upload} {} | ||
| 24 | 21 | ||
| 25 | KeplerCompute::~KeplerCompute() = default; | 22 | KeplerCompute::~KeplerCompute() = default; |
| 26 | 23 | ||
| 24 | void KeplerCompute::BindRasterizer(VideoCore::RasterizerInterface& rasterizer_) { | ||
| 25 | rasterizer = &rasterizer_; | ||
| 26 | } | ||
| 27 | |||
| 27 | void KeplerCompute::CallMethod(u32 method, u32 method_argument, bool is_last_call) { | 28 | void KeplerCompute::CallMethod(u32 method, u32 method_argument, bool is_last_call) { |
| 28 | ASSERT_MSG(method < Regs::NUM_REGS, | 29 | ASSERT_MSG(method < Regs::NUM_REGS, |
| 29 | "Invalid KeplerCompute register, increase the size of the Regs structure"); | 30 | "Invalid KeplerCompute register, increase the size of the Regs structure"); |
| @@ -104,11 +105,11 @@ SamplerDescriptor KeplerCompute::AccessSampler(u32 handle) const { | |||
| 104 | } | 105 | } |
| 105 | 106 | ||
| 106 | VideoCore::GuestDriverProfile& KeplerCompute::AccessGuestDriverProfile() { | 107 | VideoCore::GuestDriverProfile& KeplerCompute::AccessGuestDriverProfile() { |
| 107 | return rasterizer.AccessGuestDriverProfile(); | 108 | return rasterizer->AccessGuestDriverProfile(); |
| 108 | } | 109 | } |
| 109 | 110 | ||
| 110 | const VideoCore::GuestDriverProfile& KeplerCompute::AccessGuestDriverProfile() const { | 111 | const VideoCore::GuestDriverProfile& KeplerCompute::AccessGuestDriverProfile() const { |
| 111 | return rasterizer.AccessGuestDriverProfile(); | 112 | return rasterizer->AccessGuestDriverProfile(); |
| 112 | } | 113 | } |
| 113 | 114 | ||
| 114 | void KeplerCompute::ProcessLaunch() { | 115 | void KeplerCompute::ProcessLaunch() { |
| @@ -119,7 +120,7 @@ void KeplerCompute::ProcessLaunch() { | |||
| 119 | const GPUVAddr code_addr = regs.code_loc.Address() + launch_description.program_start; | 120 | const GPUVAddr code_addr = regs.code_loc.Address() + launch_description.program_start; |
| 120 | LOG_TRACE(HW_GPU, "Compute invocation launched at address 0x{:016x}", code_addr); | 121 | LOG_TRACE(HW_GPU, "Compute invocation launched at address 0x{:016x}", code_addr); |
| 121 | 122 | ||
| 122 | rasterizer.DispatchCompute(code_addr); | 123 | rasterizer->DispatchCompute(code_addr); |
| 123 | } | 124 | } |
| 124 | 125 | ||
| 125 | Texture::TICEntry KeplerCompute::GetTICEntry(u32 tic_index) const { | 126 | Texture::TICEntry KeplerCompute::GetTICEntry(u32 tic_index) const { |
diff --git a/src/video_core/engines/kepler_compute.h b/src/video_core/engines/kepler_compute.h index b7f668d88..7f2500aab 100644 --- a/src/video_core/engines/kepler_compute.h +++ b/src/video_core/engines/kepler_compute.h | |||
| @@ -42,10 +42,12 @@ namespace Tegra::Engines { | |||
| 42 | 42 | ||
| 43 | class KeplerCompute final : public ConstBufferEngineInterface, public EngineInterface { | 43 | class KeplerCompute final : public ConstBufferEngineInterface, public EngineInterface { |
| 44 | public: | 44 | public: |
| 45 | explicit KeplerCompute(Core::System& system, VideoCore::RasterizerInterface& rasterizer, | 45 | explicit KeplerCompute(Core::System& system, MemoryManager& memory_manager); |
| 46 | MemoryManager& memory_manager); | ||
| 47 | ~KeplerCompute(); | 46 | ~KeplerCompute(); |
| 48 | 47 | ||
| 48 | /// Binds a rasterizer to this engine. | ||
| 49 | void BindRasterizer(VideoCore::RasterizerInterface& rasterizer); | ||
| 50 | |||
| 49 | static constexpr std::size_t NumConstBuffers = 8; | 51 | static constexpr std::size_t NumConstBuffers = 8; |
| 50 | 52 | ||
| 51 | struct Regs { | 53 | struct Regs { |
| @@ -230,11 +232,6 @@ public: | |||
| 230 | const VideoCore::GuestDriverProfile& AccessGuestDriverProfile() const override; | 232 | const VideoCore::GuestDriverProfile& AccessGuestDriverProfile() const override; |
| 231 | 233 | ||
| 232 | private: | 234 | private: |
| 233 | Core::System& system; | ||
| 234 | VideoCore::RasterizerInterface& rasterizer; | ||
| 235 | MemoryManager& memory_manager; | ||
| 236 | Upload::State upload_state; | ||
| 237 | |||
| 238 | void ProcessLaunch(); | 235 | void ProcessLaunch(); |
| 239 | 236 | ||
| 240 | /// Retrieves information about a specific TIC entry from the TIC buffer. | 237 | /// Retrieves information about a specific TIC entry from the TIC buffer. |
| @@ -242,6 +239,11 @@ private: | |||
| 242 | 239 | ||
| 243 | /// Retrieves information about a specific TSC entry from the TSC buffer. | 240 | /// Retrieves information about a specific TSC entry from the TSC buffer. |
| 244 | Texture::TSCEntry GetTSCEntry(u32 tsc_index) const; | 241 | Texture::TSCEntry GetTSCEntry(u32 tsc_index) const; |
| 242 | |||
| 243 | Core::System& system; | ||
| 244 | MemoryManager& memory_manager; | ||
| 245 | VideoCore::RasterizerInterface* rasterizer = nullptr; | ||
| 246 | Upload::State upload_state; | ||
| 245 | }; | 247 | }; |
| 246 | 248 | ||
| 247 | #define ASSERT_REG_POSITION(field_name, position) \ | 249 | #define ASSERT_REG_POSITION(field_name, position) \ |
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index c01436295..33854445f 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp | |||
| @@ -22,14 +22,19 @@ using VideoCore::QueryType; | |||
| 22 | /// First register id that is actually a Macro call. | 22 | /// First register id that is actually a Macro call. |
| 23 | constexpr u32 MacroRegistersStart = 0xE00; | 23 | constexpr u32 MacroRegistersStart = 0xE00; |
| 24 | 24 | ||
| 25 | Maxwell3D::Maxwell3D(Core::System& system, VideoCore::RasterizerInterface& rasterizer, | 25 | Maxwell3D::Maxwell3D(Core::System& system_, MemoryManager& memory_manager_) |
| 26 | MemoryManager& memory_manager) | 26 | : system{system_}, memory_manager{memory_manager_}, macro_engine{GetMacroEngine(*this)}, |
| 27 | : system{system}, rasterizer{rasterizer}, memory_manager{memory_manager}, | 27 | upload_state{memory_manager, regs.upload} { |
| 28 | macro_engine{GetMacroEngine(*this)}, upload_state{memory_manager, regs.upload} { | ||
| 29 | dirty.flags.flip(); | 28 | dirty.flags.flip(); |
| 30 | InitializeRegisterDefaults(); | 29 | InitializeRegisterDefaults(); |
| 31 | } | 30 | } |
| 32 | 31 | ||
| 32 | Maxwell3D::~Maxwell3D() = default; | ||
| 33 | |||
| 34 | void Maxwell3D::BindRasterizer(VideoCore::RasterizerInterface& rasterizer_) { | ||
| 35 | rasterizer = &rasterizer_; | ||
| 36 | } | ||
| 37 | |||
| 33 | void Maxwell3D::InitializeRegisterDefaults() { | 38 | void Maxwell3D::InitializeRegisterDefaults() { |
| 34 | // Initializes registers to their default values - what games expect them to be at boot. This is | 39 | // Initializes registers to their default values - what games expect them to be at boot. This is |
| 35 | // for certain registers that may not be explicitly set by games. | 40 | // for certain registers that may not be explicitly set by games. |
| @@ -192,7 +197,7 @@ void Maxwell3D::CallMethod(u32 method, u32 method_argument, bool is_last_call) { | |||
| 192 | 197 | ||
| 193 | switch (method) { | 198 | switch (method) { |
| 194 | case MAXWELL3D_REG_INDEX(wait_for_idle): { | 199 | case MAXWELL3D_REG_INDEX(wait_for_idle): { |
| 195 | rasterizer.WaitForIdle(); | 200 | rasterizer->WaitForIdle(); |
| 196 | break; | 201 | break; |
| 197 | } | 202 | } |
| 198 | case MAXWELL3D_REG_INDEX(shadow_ram_control): { | 203 | case MAXWELL3D_REG_INDEX(shadow_ram_control): { |
| @@ -402,7 +407,7 @@ void Maxwell3D::FlushMMEInlineDraw() { | |||
| 402 | 407 | ||
| 403 | const bool is_indexed = mme_draw.current_mode == MMEDrawMode::Indexed; | 408 | const bool is_indexed = mme_draw.current_mode == MMEDrawMode::Indexed; |
| 404 | if (ShouldExecute()) { | 409 | if (ShouldExecute()) { |
| 405 | rasterizer.Draw(is_indexed, true); | 410 | rasterizer->Draw(is_indexed, true); |
| 406 | } | 411 | } |
| 407 | 412 | ||
| 408 | // TODO(bunnei): Below, we reset vertex count so that we can use these registers to determine if | 413 | // TODO(bunnei): Below, we reset vertex count so that we can use these registers to determine if |
| @@ -465,7 +470,7 @@ void Maxwell3D::ProcessQueryGet() { | |||
| 465 | switch (regs.query.query_get.operation) { | 470 | switch (regs.query.query_get.operation) { |
| 466 | case Regs::QueryOperation::Release: | 471 | case Regs::QueryOperation::Release: |
| 467 | if (regs.query.query_get.fence == 1) { | 472 | if (regs.query.query_get.fence == 1) { |
| 468 | rasterizer.SignalSemaphore(regs.query.QueryAddress(), regs.query.query_sequence); | 473 | rasterizer->SignalSemaphore(regs.query.QueryAddress(), regs.query.query_sequence); |
| 469 | } else { | 474 | } else { |
| 470 | StampQueryResult(regs.query.query_sequence, regs.query.query_get.short_query == 0); | 475 | StampQueryResult(regs.query.query_sequence, regs.query.query_get.short_query == 0); |
| 471 | } | 476 | } |
| @@ -533,7 +538,7 @@ void Maxwell3D::ProcessQueryCondition() { | |||
| 533 | void Maxwell3D::ProcessCounterReset() { | 538 | void Maxwell3D::ProcessCounterReset() { |
| 534 | switch (regs.counter_reset) { | 539 | switch (regs.counter_reset) { |
| 535 | case Regs::CounterReset::SampleCnt: | 540 | case Regs::CounterReset::SampleCnt: |
| 536 | rasterizer.ResetCounter(QueryType::SamplesPassed); | 541 | rasterizer->ResetCounter(QueryType::SamplesPassed); |
| 537 | break; | 542 | break; |
| 538 | default: | 543 | default: |
| 539 | LOG_DEBUG(Render_OpenGL, "Unimplemented counter reset={}", | 544 | LOG_DEBUG(Render_OpenGL, "Unimplemented counter reset={}", |
| @@ -547,7 +552,7 @@ void Maxwell3D::ProcessSyncPoint() { | |||
| 547 | const u32 increment = regs.sync_info.increment.Value(); | 552 | const u32 increment = regs.sync_info.increment.Value(); |
| 548 | [[maybe_unused]] const u32 cache_flush = regs.sync_info.unknown.Value(); | 553 | [[maybe_unused]] const u32 cache_flush = regs.sync_info.unknown.Value(); |
| 549 | if (increment) { | 554 | if (increment) { |
| 550 | rasterizer.SignalSyncPoint(sync_point); | 555 | rasterizer->SignalSyncPoint(sync_point); |
| 551 | } | 556 | } |
| 552 | } | 557 | } |
| 553 | 558 | ||
| @@ -570,7 +575,7 @@ void Maxwell3D::DrawArrays() { | |||
| 570 | 575 | ||
| 571 | const bool is_indexed{regs.index_array.count && !regs.vertex_buffer.count}; | 576 | const bool is_indexed{regs.index_array.count && !regs.vertex_buffer.count}; |
| 572 | if (ShouldExecute()) { | 577 | if (ShouldExecute()) { |
| 573 | rasterizer.Draw(is_indexed, false); | 578 | rasterizer->Draw(is_indexed, false); |
| 574 | } | 579 | } |
| 575 | 580 | ||
| 576 | // TODO(bunnei): Below, we reset vertex count so that we can use these registers to determine if | 581 | // TODO(bunnei): Below, we reset vertex count so that we can use these registers to determine if |
| @@ -590,8 +595,8 @@ std::optional<u64> Maxwell3D::GetQueryResult() { | |||
| 590 | return 0; | 595 | return 0; |
| 591 | case Regs::QuerySelect::SamplesPassed: | 596 | case Regs::QuerySelect::SamplesPassed: |
| 592 | // Deferred. | 597 | // Deferred. |
| 593 | rasterizer.Query(regs.query.QueryAddress(), VideoCore::QueryType::SamplesPassed, | 598 | rasterizer->Query(regs.query.QueryAddress(), VideoCore::QueryType::SamplesPassed, |
| 594 | system.GPU().GetTicks()); | 599 | system.GPU().GetTicks()); |
| 595 | return {}; | 600 | return {}; |
| 596 | default: | 601 | default: |
| 597 | LOG_DEBUG(HW_GPU, "Unimplemented query select type {}", | 602 | LOG_DEBUG(HW_GPU, "Unimplemented query select type {}", |
| @@ -718,7 +723,7 @@ void Maxwell3D::ProcessClearBuffers() { | |||
| 718 | regs.clear_buffers.R == regs.clear_buffers.B && | 723 | regs.clear_buffers.R == regs.clear_buffers.B && |
| 719 | regs.clear_buffers.R == regs.clear_buffers.A); | 724 | regs.clear_buffers.R == regs.clear_buffers.A); |
| 720 | 725 | ||
| 721 | rasterizer.Clear(); | 726 | rasterizer->Clear(); |
| 722 | } | 727 | } |
| 723 | 728 | ||
| 724 | u32 Maxwell3D::AccessConstBuffer32(ShaderType stage, u64 const_buffer, u64 offset) const { | 729 | u32 Maxwell3D::AccessConstBuffer32(ShaderType stage, u64 const_buffer, u64 offset) const { |
| @@ -752,11 +757,11 @@ SamplerDescriptor Maxwell3D::AccessSampler(u32 handle) const { | |||
| 752 | } | 757 | } |
| 753 | 758 | ||
| 754 | VideoCore::GuestDriverProfile& Maxwell3D::AccessGuestDriverProfile() { | 759 | VideoCore::GuestDriverProfile& Maxwell3D::AccessGuestDriverProfile() { |
| 755 | return rasterizer.AccessGuestDriverProfile(); | 760 | return rasterizer->AccessGuestDriverProfile(); |
| 756 | } | 761 | } |
| 757 | 762 | ||
| 758 | const VideoCore::GuestDriverProfile& Maxwell3D::AccessGuestDriverProfile() const { | 763 | const VideoCore::GuestDriverProfile& Maxwell3D::AccessGuestDriverProfile() const { |
| 759 | return rasterizer.AccessGuestDriverProfile(); | 764 | return rasterizer->AccessGuestDriverProfile(); |
| 760 | } | 765 | } |
| 761 | 766 | ||
| 762 | } // namespace Tegra::Engines | 767 | } // namespace Tegra::Engines |
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index c97eeb792..bc289c55d 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h | |||
| @@ -51,9 +51,11 @@ namespace Tegra::Engines { | |||
| 51 | 51 | ||
| 52 | class Maxwell3D final : public ConstBufferEngineInterface, public EngineInterface { | 52 | class Maxwell3D final : public ConstBufferEngineInterface, public EngineInterface { |
| 53 | public: | 53 | public: |
| 54 | explicit Maxwell3D(Core::System& system, VideoCore::RasterizerInterface& rasterizer, | 54 | explicit Maxwell3D(Core::System& system, MemoryManager& memory_manager); |
| 55 | MemoryManager& memory_manager); | 55 | ~Maxwell3D(); |
| 56 | ~Maxwell3D() = default; | 56 | |
| 57 | /// Binds a rasterizer to this engine. | ||
| 58 | void BindRasterizer(VideoCore::RasterizerInterface& rasterizer); | ||
| 57 | 59 | ||
| 58 | /// Register structure of the Maxwell3D engine. | 60 | /// Register structure of the Maxwell3D engine. |
| 59 | /// TODO(Subv): This structure will need to be made bigger as more registers are discovered. | 61 | /// TODO(Subv): This structure will need to be made bigger as more registers are discovered. |
| @@ -1418,12 +1420,12 @@ public: | |||
| 1418 | return execute_on; | 1420 | return execute_on; |
| 1419 | } | 1421 | } |
| 1420 | 1422 | ||
| 1421 | VideoCore::RasterizerInterface& GetRasterizer() { | 1423 | VideoCore::RasterizerInterface& Rasterizer() { |
| 1422 | return rasterizer; | 1424 | return *rasterizer; |
| 1423 | } | 1425 | } |
| 1424 | 1426 | ||
| 1425 | const VideoCore::RasterizerInterface& GetRasterizer() const { | 1427 | const VideoCore::RasterizerInterface& Rasterizer() const { |
| 1426 | return rasterizer; | 1428 | return *rasterizer; |
| 1427 | } | 1429 | } |
| 1428 | 1430 | ||
| 1429 | /// Notify a memory write has happened. | 1431 | /// Notify a memory write has happened. |
| @@ -1460,11 +1462,10 @@ private: | |||
| 1460 | void InitializeRegisterDefaults(); | 1462 | void InitializeRegisterDefaults(); |
| 1461 | 1463 | ||
| 1462 | Core::System& system; | 1464 | Core::System& system; |
| 1463 | |||
| 1464 | VideoCore::RasterizerInterface& rasterizer; | ||
| 1465 | |||
| 1466 | MemoryManager& memory_manager; | 1465 | MemoryManager& memory_manager; |
| 1467 | 1466 | ||
| 1467 | VideoCore::RasterizerInterface* rasterizer = nullptr; | ||
| 1468 | |||
| 1468 | /// Start offsets of each macro in macro_memory | 1469 | /// Start offsets of each macro in macro_memory |
| 1469 | std::array<u32, 0x80> macro_positions = {}; | 1470 | std::array<u32, 0x80> macro_positions = {}; |
| 1470 | 1471 | ||
diff --git a/src/video_core/fence_manager.h b/src/video_core/fence_manager.h index 8b2a6a42c..06cc12d5a 100644 --- a/src/video_core/fence_manager.h +++ b/src/video_core/fence_manager.h | |||
| @@ -5,15 +5,10 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <algorithm> | 7 | #include <algorithm> |
| 8 | #include <array> | ||
| 9 | #include <memory> | ||
| 10 | #include <queue> | 8 | #include <queue> |
| 11 | 9 | ||
| 12 | #include "common/assert.h" | ||
| 13 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 14 | #include "core/core.h" | 11 | #include "core/core.h" |
| 15 | #include "core/memory.h" | ||
| 16 | #include "core/settings.h" | ||
| 17 | #include "video_core/gpu.h" | 12 | #include "video_core/gpu.h" |
| 18 | #include "video_core/memory_manager.h" | 13 | #include "video_core/memory_manager.h" |
| 19 | #include "video_core/rasterizer_interface.h" | 14 | #include "video_core/rasterizer_interface.h" |
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp index 512578c8b..acb6e6d46 100644 --- a/src/video_core/gpu.cpp +++ b/src/video_core/gpu.cpp | |||
| @@ -27,21 +27,28 @@ namespace Tegra { | |||
| 27 | 27 | ||
| 28 | MICROPROFILE_DEFINE(GPU_wait, "GPU", "Wait for the GPU", MP_RGB(128, 128, 192)); | 28 | MICROPROFILE_DEFINE(GPU_wait, "GPU", "Wait for the GPU", MP_RGB(128, 128, 192)); |
| 29 | 29 | ||
| 30 | GPU::GPU(Core::System& system, std::unique_ptr<VideoCore::RendererBase>&& renderer_, bool is_async) | 30 | GPU::GPU(Core::System& system_, bool is_async_) |
| 31 | : system{system}, renderer{std::move(renderer_)}, is_async{is_async} { | 31 | : system{system_}, dma_pusher{std::make_unique<Tegra::DmaPusher>(system, *this)}, |
| 32 | auto& rasterizer{renderer->Rasterizer()}; | 32 | memory_manager{std::make_unique<Tegra::MemoryManager>(system)}, |
| 33 | memory_manager = std::make_unique<Tegra::MemoryManager>(system, rasterizer); | 33 | maxwell_3d{std::make_unique<Engines::Maxwell3D>(system, *memory_manager)}, |
| 34 | dma_pusher = std::make_unique<Tegra::DmaPusher>(system, *this); | 34 | fermi_2d{std::make_unique<Engines::Fermi2D>()}, |
| 35 | maxwell_3d = std::make_unique<Engines::Maxwell3D>(system, rasterizer, *memory_manager); | 35 | kepler_compute{std::make_unique<Engines::KeplerCompute>(system, *memory_manager)}, |
| 36 | fermi_2d = std::make_unique<Engines::Fermi2D>(rasterizer); | 36 | maxwell_dma{std::make_unique<Engines::MaxwellDMA>(system, *memory_manager)}, |
| 37 | kepler_compute = std::make_unique<Engines::KeplerCompute>(system, rasterizer, *memory_manager); | 37 | kepler_memory{std::make_unique<Engines::KeplerMemory>(system, *memory_manager)}, |
| 38 | maxwell_dma = std::make_unique<Engines::MaxwellDMA>(system, *memory_manager); | 38 | shader_notify{std::make_unique<VideoCore::ShaderNotify>()}, is_async{is_async_} {} |
| 39 | kepler_memory = std::make_unique<Engines::KeplerMemory>(system, *memory_manager); | ||
| 40 | shader_notify = std::make_unique<VideoCore::ShaderNotify>(); | ||
| 41 | } | ||
| 42 | 39 | ||
| 43 | GPU::~GPU() = default; | 40 | GPU::~GPU() = default; |
| 44 | 41 | ||
| 42 | void GPU::BindRenderer(std::unique_ptr<VideoCore::RendererBase> renderer_) { | ||
| 43 | renderer = std::move(renderer_); | ||
| 44 | |||
| 45 | VideoCore::RasterizerInterface& rasterizer = renderer->Rasterizer(); | ||
| 46 | memory_manager->BindRasterizer(rasterizer); | ||
| 47 | maxwell_3d->BindRasterizer(rasterizer); | ||
| 48 | fermi_2d->BindRasterizer(rasterizer); | ||
| 49 | kepler_compute->BindRasterizer(rasterizer); | ||
| 50 | } | ||
| 51 | |||
| 45 | Engines::Maxwell3D& GPU::Maxwell3D() { | 52 | Engines::Maxwell3D& GPU::Maxwell3D() { |
| 46 | return *maxwell_3d; | 53 | return *maxwell_3d; |
| 47 | } | 54 | } |
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h index ebfc7b0c7..c7d11deb2 100644 --- a/src/video_core/gpu.h +++ b/src/video_core/gpu.h | |||
| @@ -142,11 +142,6 @@ class MemoryManager; | |||
| 142 | 142 | ||
| 143 | class GPU { | 143 | class GPU { |
| 144 | public: | 144 | public: |
| 145 | explicit GPU(Core::System& system, std::unique_ptr<VideoCore::RendererBase>&& renderer, | ||
| 146 | bool is_async); | ||
| 147 | |||
| 148 | virtual ~GPU(); | ||
| 149 | |||
| 150 | struct MethodCall { | 145 | struct MethodCall { |
| 151 | u32 method{}; | 146 | u32 method{}; |
| 152 | u32 argument{}; | 147 | u32 argument{}; |
| @@ -162,6 +157,12 @@ public: | |||
| 162 | method_count(method_count) {} | 157 | method_count(method_count) {} |
| 163 | }; | 158 | }; |
| 164 | 159 | ||
| 160 | explicit GPU(Core::System& system, bool is_async); | ||
| 161 | virtual ~GPU(); | ||
| 162 | |||
| 163 | /// Binds a renderer to the GPU. | ||
| 164 | void BindRenderer(std::unique_ptr<VideoCore::RendererBase> renderer); | ||
| 165 | |||
| 165 | /// Calls a GPU method. | 166 | /// Calls a GPU method. |
| 166 | void CallMethod(const MethodCall& method_call); | 167 | void CallMethod(const MethodCall& method_call); |
| 167 | 168 | ||
| @@ -345,8 +346,8 @@ private: | |||
| 345 | bool ExecuteMethodOnEngine(u32 method); | 346 | bool ExecuteMethodOnEngine(u32 method); |
| 346 | 347 | ||
| 347 | protected: | 348 | protected: |
| 348 | std::unique_ptr<Tegra::DmaPusher> dma_pusher; | ||
| 349 | Core::System& system; | 349 | Core::System& system; |
| 350 | std::unique_ptr<Tegra::DmaPusher> dma_pusher; | ||
| 350 | std::unique_ptr<VideoCore::RendererBase> renderer; | 351 | std::unique_ptr<VideoCore::RendererBase> renderer; |
| 351 | 352 | ||
| 352 | private: | 353 | private: |
diff --git a/src/video_core/gpu_asynch.cpp b/src/video_core/gpu_asynch.cpp index 7b855f63e..70a3d5738 100644 --- a/src/video_core/gpu_asynch.cpp +++ b/src/video_core/gpu_asynch.cpp | |||
| @@ -10,16 +10,14 @@ | |||
| 10 | 10 | ||
| 11 | namespace VideoCommon { | 11 | namespace VideoCommon { |
| 12 | 12 | ||
| 13 | GPUAsynch::GPUAsynch(Core::System& system, std::unique_ptr<VideoCore::RendererBase>&& renderer_, | 13 | GPUAsynch::GPUAsynch(Core::System& system) : GPU{system, true}, gpu_thread{system} {} |
| 14 | std::unique_ptr<Core::Frontend::GraphicsContext>&& context) | ||
| 15 | : GPU(system, std::move(renderer_), true), gpu_thread{system}, | ||
| 16 | cpu_context(renderer->GetRenderWindow().CreateSharedContext()), | ||
| 17 | gpu_context(std::move(context)) {} | ||
| 18 | 14 | ||
| 19 | GPUAsynch::~GPUAsynch() = default; | 15 | GPUAsynch::~GPUAsynch() = default; |
| 20 | 16 | ||
| 21 | void GPUAsynch::Start() { | 17 | void GPUAsynch::Start() { |
| 22 | gpu_thread.StartThread(*renderer, *gpu_context, *dma_pusher); | 18 | gpu_thread.StartThread(*renderer, renderer->Context(), *dma_pusher); |
| 19 | cpu_context = renderer->GetRenderWindow().CreateSharedContext(); | ||
| 20 | cpu_context->MakeCurrent(); | ||
| 23 | } | 21 | } |
| 24 | 22 | ||
| 25 | void GPUAsynch::ObtainContext() { | 23 | void GPUAsynch::ObtainContext() { |
diff --git a/src/video_core/gpu_asynch.h b/src/video_core/gpu_asynch.h index 15e9f1d38..f89c855a5 100644 --- a/src/video_core/gpu_asynch.h +++ b/src/video_core/gpu_asynch.h | |||
| @@ -20,8 +20,7 @@ namespace VideoCommon { | |||
| 20 | /// Implementation of GPU interface that runs the GPU asynchronously | 20 | /// Implementation of GPU interface that runs the GPU asynchronously |
| 21 | class GPUAsynch final : public Tegra::GPU { | 21 | class GPUAsynch final : public Tegra::GPU { |
| 22 | public: | 22 | public: |
| 23 | explicit GPUAsynch(Core::System& system, std::unique_ptr<VideoCore::RendererBase>&& renderer, | 23 | explicit GPUAsynch(Core::System& system); |
| 24 | std::unique_ptr<Core::Frontend::GraphicsContext>&& context); | ||
| 25 | ~GPUAsynch() override; | 24 | ~GPUAsynch() override; |
| 26 | 25 | ||
| 27 | void Start() override; | 26 | void Start() override; |
| @@ -42,7 +41,6 @@ protected: | |||
| 42 | private: | 41 | private: |
| 43 | GPUThread::ThreadManager gpu_thread; | 42 | GPUThread::ThreadManager gpu_thread; |
| 44 | std::unique_ptr<Core::Frontend::GraphicsContext> cpu_context; | 43 | std::unique_ptr<Core::Frontend::GraphicsContext> cpu_context; |
| 45 | std::unique_ptr<Core::Frontend::GraphicsContext> gpu_context; | ||
| 46 | }; | 44 | }; |
| 47 | 45 | ||
| 48 | } // namespace VideoCommon | 46 | } // namespace VideoCommon |
diff --git a/src/video_core/gpu_synch.cpp b/src/video_core/gpu_synch.cpp index aaeb9811d..1ca47ddef 100644 --- a/src/video_core/gpu_synch.cpp +++ b/src/video_core/gpu_synch.cpp | |||
| @@ -7,20 +7,18 @@ | |||
| 7 | 7 | ||
| 8 | namespace VideoCommon { | 8 | namespace VideoCommon { |
| 9 | 9 | ||
| 10 | GPUSynch::GPUSynch(Core::System& system, std::unique_ptr<VideoCore::RendererBase>&& renderer, | 10 | GPUSynch::GPUSynch(Core::System& system) : GPU{system, false} {} |
| 11 | std::unique_ptr<Core::Frontend::GraphicsContext>&& context) | ||
| 12 | : GPU(system, std::move(renderer), false), context{std::move(context)} {} | ||
| 13 | 11 | ||
| 14 | GPUSynch::~GPUSynch() = default; | 12 | GPUSynch::~GPUSynch() = default; |
| 15 | 13 | ||
| 16 | void GPUSynch::Start() {} | 14 | void GPUSynch::Start() {} |
| 17 | 15 | ||
| 18 | void GPUSynch::ObtainContext() { | 16 | void GPUSynch::ObtainContext() { |
| 19 | context->MakeCurrent(); | 17 | renderer->Context().MakeCurrent(); |
| 20 | } | 18 | } |
| 21 | 19 | ||
| 22 | void GPUSynch::ReleaseContext() { | 20 | void GPUSynch::ReleaseContext() { |
| 23 | context->DoneCurrent(); | 21 | renderer->Context().DoneCurrent(); |
| 24 | } | 22 | } |
| 25 | 23 | ||
| 26 | void GPUSynch::PushGPUEntries(Tegra::CommandList&& entries) { | 24 | void GPUSynch::PushGPUEntries(Tegra::CommandList&& entries) { |
diff --git a/src/video_core/gpu_synch.h b/src/video_core/gpu_synch.h index 762c20aa5..297258cb1 100644 --- a/src/video_core/gpu_synch.h +++ b/src/video_core/gpu_synch.h | |||
| @@ -19,8 +19,7 @@ namespace VideoCommon { | |||
| 19 | /// Implementation of GPU interface that runs the GPU synchronously | 19 | /// Implementation of GPU interface that runs the GPU synchronously |
| 20 | class GPUSynch final : public Tegra::GPU { | 20 | class GPUSynch final : public Tegra::GPU { |
| 21 | public: | 21 | public: |
| 22 | explicit GPUSynch(Core::System& system, std::unique_ptr<VideoCore::RendererBase>&& renderer, | 22 | explicit GPUSynch(Core::System& system); |
| 23 | std::unique_ptr<Core::Frontend::GraphicsContext>&& context); | ||
| 24 | ~GPUSynch() override; | 23 | ~GPUSynch() override; |
| 25 | 24 | ||
| 26 | void Start() override; | 25 | void Start() override; |
| @@ -36,9 +35,6 @@ public: | |||
| 36 | protected: | 35 | protected: |
| 37 | void TriggerCpuInterrupt([[maybe_unused]] u32 syncpoint_id, | 36 | void TriggerCpuInterrupt([[maybe_unused]] u32 syncpoint_id, |
| 38 | [[maybe_unused]] u32 value) const override {} | 37 | [[maybe_unused]] u32 value) const override {} |
| 39 | |||
| 40 | private: | ||
| 41 | std::unique_ptr<Core::Frontend::GraphicsContext> context; | ||
| 42 | }; | 38 | }; |
| 43 | 39 | ||
| 44 | } // namespace VideoCommon | 40 | } // namespace VideoCommon |
diff --git a/src/video_core/macro/macro_hle.cpp b/src/video_core/macro/macro_hle.cpp index 0c9ff59a4..df00b57df 100644 --- a/src/video_core/macro/macro_hle.cpp +++ b/src/video_core/macro/macro_hle.cpp | |||
| @@ -24,7 +24,7 @@ void HLE_771BB18C62444DA0(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& | |||
| 24 | maxwell3d.regs.index_array.first = parameters[4]; | 24 | maxwell3d.regs.index_array.first = parameters[4]; |
| 25 | 25 | ||
| 26 | if (maxwell3d.ShouldExecute()) { | 26 | if (maxwell3d.ShouldExecute()) { |
| 27 | maxwell3d.GetRasterizer().Draw(true, true); | 27 | maxwell3d.Rasterizer().Draw(true, true); |
| 28 | } | 28 | } |
| 29 | maxwell3d.regs.index_array.count = 0; | 29 | maxwell3d.regs.index_array.count = 0; |
| 30 | maxwell3d.mme_draw.instance_count = 0; | 30 | maxwell3d.mme_draw.instance_count = 0; |
| @@ -42,7 +42,7 @@ void HLE_0D61FC9FAAC9FCAD(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& | |||
| 42 | maxwell3d.mme_draw.instance_count = count; | 42 | maxwell3d.mme_draw.instance_count = count; |
| 43 | 43 | ||
| 44 | if (maxwell3d.ShouldExecute()) { | 44 | if (maxwell3d.ShouldExecute()) { |
| 45 | maxwell3d.GetRasterizer().Draw(false, true); | 45 | maxwell3d.Rasterizer().Draw(false, true); |
| 46 | } | 46 | } |
| 47 | maxwell3d.regs.vertex_buffer.count = 0; | 47 | maxwell3d.regs.vertex_buffer.count = 0; |
| 48 | maxwell3d.mme_draw.instance_count = 0; | 48 | maxwell3d.mme_draw.instance_count = 0; |
| @@ -65,7 +65,7 @@ void HLE_0217920100488FF7(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& | |||
| 65 | maxwell3d.regs.draw.topology.Assign( | 65 | maxwell3d.regs.draw.topology.Assign( |
| 66 | static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0])); | 66 | static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0])); |
| 67 | if (maxwell3d.ShouldExecute()) { | 67 | if (maxwell3d.ShouldExecute()) { |
| 68 | maxwell3d.GetRasterizer().Draw(true, true); | 68 | maxwell3d.Rasterizer().Draw(true, true); |
| 69 | } | 69 | } |
| 70 | maxwell3d.regs.reg_array[0x446] = 0x0; // vertex id base? | 70 | maxwell3d.regs.reg_array[0x446] = 0x0; // vertex id base? |
| 71 | maxwell3d.regs.index_array.count = 0; | 71 | maxwell3d.regs.index_array.count = 0; |
diff --git a/src/video_core/macro/macro_interpreter.cpp b/src/video_core/macro/macro_interpreter.cpp index aa5256419..bd01fd1f2 100644 --- a/src/video_core/macro/macro_interpreter.cpp +++ b/src/video_core/macro/macro_interpreter.cpp | |||
| @@ -34,7 +34,6 @@ void MacroInterpreterImpl::Execute(const std::vector<u32>& parameters, u32 metho | |||
| 34 | this->parameters = std::make_unique<u32[]>(num_parameters); | 34 | this->parameters = std::make_unique<u32[]>(num_parameters); |
| 35 | } | 35 | } |
| 36 | std::memcpy(this->parameters.get(), parameters.data(), num_parameters * sizeof(u32)); | 36 | std::memcpy(this->parameters.get(), parameters.data(), num_parameters * sizeof(u32)); |
| 37 | this->num_parameters = num_parameters; | ||
| 38 | 37 | ||
| 39 | // Execute the code until we hit an exit condition. | 38 | // Execute the code until we hit an exit condition. |
| 40 | bool keep_executing = true; | 39 | bool keep_executing = true; |
diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp index 844164645..c217f5bb2 100644 --- a/src/video_core/memory_manager.cpp +++ b/src/video_core/memory_manager.cpp | |||
| @@ -14,11 +14,15 @@ | |||
| 14 | 14 | ||
| 15 | namespace Tegra { | 15 | namespace Tegra { |
| 16 | 16 | ||
| 17 | MemoryManager::MemoryManager(Core::System& system, VideoCore::RasterizerInterface& rasterizer) | 17 | MemoryManager::MemoryManager(Core::System& system_) |
| 18 | : system{system}, rasterizer{rasterizer}, page_table(page_table_size) {} | 18 | : system{system_}, page_table(page_table_size) {} |
| 19 | 19 | ||
| 20 | MemoryManager::~MemoryManager() = default; | 20 | MemoryManager::~MemoryManager() = default; |
| 21 | 21 | ||
| 22 | void MemoryManager::BindRasterizer(VideoCore::RasterizerInterface& rasterizer_) { | ||
| 23 | rasterizer = &rasterizer_; | ||
| 24 | } | ||
| 25 | |||
| 22 | GPUVAddr MemoryManager::UpdateRange(GPUVAddr gpu_addr, PageEntry page_entry, std::size_t size) { | 26 | GPUVAddr MemoryManager::UpdateRange(GPUVAddr gpu_addr, PageEntry page_entry, std::size_t size) { |
| 23 | u64 remaining_size{size}; | 27 | u64 remaining_size{size}; |
| 24 | for (u64 offset{}; offset < size; offset += page_size) { | 28 | for (u64 offset{}; offset < size; offset += page_size) { |
| @@ -217,7 +221,7 @@ void MemoryManager::ReadBlock(GPUVAddr gpu_src_addr, void* dest_buffer, std::siz | |||
| 217 | 221 | ||
| 218 | // Flush must happen on the rasterizer interface, such that memory is always synchronous | 222 | // Flush must happen on the rasterizer interface, such that memory is always synchronous |
| 219 | // when it is read (even when in asynchronous GPU mode). Fixes Dead Cells title menu. | 223 | // when it is read (even when in asynchronous GPU mode). Fixes Dead Cells title menu. |
| 220 | rasterizer.FlushRegion(src_addr, copy_amount); | 224 | rasterizer->FlushRegion(src_addr, copy_amount); |
| 221 | system.Memory().ReadBlockUnsafe(src_addr, dest_buffer, copy_amount); | 225 | system.Memory().ReadBlockUnsafe(src_addr, dest_buffer, copy_amount); |
| 222 | } | 226 | } |
| 223 | 227 | ||
| @@ -266,7 +270,7 @@ void MemoryManager::WriteBlock(GPUVAddr gpu_dest_addr, const void* src_buffer, s | |||
| 266 | 270 | ||
| 267 | // Invalidate must happen on the rasterizer interface, such that memory is always | 271 | // Invalidate must happen on the rasterizer interface, such that memory is always |
| 268 | // synchronous when it is written (even when in asynchronous GPU mode). | 272 | // synchronous when it is written (even when in asynchronous GPU mode). |
| 269 | rasterizer.InvalidateRegion(dest_addr, copy_amount); | 273 | rasterizer->InvalidateRegion(dest_addr, copy_amount); |
| 270 | system.Memory().WriteBlockUnsafe(dest_addr, src_buffer, copy_amount); | 274 | system.Memory().WriteBlockUnsafe(dest_addr, src_buffer, copy_amount); |
| 271 | } | 275 | } |
| 272 | 276 | ||
diff --git a/src/video_core/memory_manager.h b/src/video_core/memory_manager.h index 681bd9588..8953fcb53 100644 --- a/src/video_core/memory_manager.h +++ b/src/video_core/memory_manager.h | |||
| @@ -68,9 +68,12 @@ static_assert(sizeof(PageEntry) == 4, "PageEntry is too large"); | |||
| 68 | 68 | ||
| 69 | class MemoryManager final { | 69 | class MemoryManager final { |
| 70 | public: | 70 | public: |
| 71 | explicit MemoryManager(Core::System& system, VideoCore::RasterizerInterface& rasterizer); | 71 | explicit MemoryManager(Core::System& system); |
| 72 | ~MemoryManager(); | 72 | ~MemoryManager(); |
| 73 | 73 | ||
| 74 | /// Binds a renderer to the memory manager. | ||
| 75 | void BindRasterizer(VideoCore::RasterizerInterface& rasterizer); | ||
| 76 | |||
| 74 | std::optional<VAddr> GpuToCpuAddress(GPUVAddr addr) const; | 77 | std::optional<VAddr> GpuToCpuAddress(GPUVAddr addr) const; |
| 75 | 78 | ||
| 76 | template <typename T> | 79 | template <typename T> |
| @@ -141,7 +144,7 @@ private: | |||
| 141 | 144 | ||
| 142 | Core::System& system; | 145 | Core::System& system; |
| 143 | 146 | ||
| 144 | VideoCore::RasterizerInterface& rasterizer; | 147 | VideoCore::RasterizerInterface* rasterizer = nullptr; |
| 145 | 148 | ||
| 146 | std::vector<PageEntry> page_table; | 149 | std::vector<PageEntry> page_table; |
| 147 | }; | 150 | }; |
diff --git a/src/video_core/renderer_base.cpp b/src/video_core/renderer_base.cpp index dfb06e87e..a93a1732c 100644 --- a/src/video_core/renderer_base.cpp +++ b/src/video_core/renderer_base.cpp | |||
| @@ -9,7 +9,9 @@ | |||
| 9 | 9 | ||
| 10 | namespace VideoCore { | 10 | namespace VideoCore { |
| 11 | 11 | ||
| 12 | RendererBase::RendererBase(Core::Frontend::EmuWindow& window) : render_window{window} { | 12 | RendererBase::RendererBase(Core::Frontend::EmuWindow& window_, |
| 13 | std::unique_ptr<Core::Frontend::GraphicsContext> context_) | ||
| 14 | : render_window{window_}, context{std::move(context_)} { | ||
| 13 | RefreshBaseSettings(); | 15 | RefreshBaseSettings(); |
| 14 | } | 16 | } |
| 15 | 17 | ||
diff --git a/src/video_core/renderer_base.h b/src/video_core/renderer_base.h index 1d85219b6..649074acd 100644 --- a/src/video_core/renderer_base.h +++ b/src/video_core/renderer_base.h | |||
| @@ -15,7 +15,8 @@ | |||
| 15 | 15 | ||
| 16 | namespace Core::Frontend { | 16 | namespace Core::Frontend { |
| 17 | class EmuWindow; | 17 | class EmuWindow; |
| 18 | } | 18 | class GraphicsContext; |
| 19 | } // namespace Core::Frontend | ||
| 19 | 20 | ||
| 20 | namespace VideoCore { | 21 | namespace VideoCore { |
| 21 | 22 | ||
| @@ -25,14 +26,15 @@ struct RendererSettings { | |||
| 25 | 26 | ||
| 26 | // Screenshot | 27 | // Screenshot |
| 27 | std::atomic<bool> screenshot_requested{false}; | 28 | std::atomic<bool> screenshot_requested{false}; |
| 28 | void* screenshot_bits; | 29 | void* screenshot_bits{}; |
| 29 | std::function<void()> screenshot_complete_callback; | 30 | std::function<void()> screenshot_complete_callback; |
| 30 | Layout::FramebufferLayout screenshot_framebuffer_layout; | 31 | Layout::FramebufferLayout screenshot_framebuffer_layout; |
| 31 | }; | 32 | }; |
| 32 | 33 | ||
| 33 | class RendererBase : NonCopyable { | 34 | class RendererBase : NonCopyable { |
| 34 | public: | 35 | public: |
| 35 | explicit RendererBase(Core::Frontend::EmuWindow& window); | 36 | explicit RendererBase(Core::Frontend::EmuWindow& window, |
| 37 | std::unique_ptr<Core::Frontend::GraphicsContext> context); | ||
| 36 | virtual ~RendererBase(); | 38 | virtual ~RendererBase(); |
| 37 | 39 | ||
| 38 | /// Initialize the renderer | 40 | /// Initialize the renderer |
| @@ -68,6 +70,14 @@ public: | |||
| 68 | return *rasterizer; | 70 | return *rasterizer; |
| 69 | } | 71 | } |
| 70 | 72 | ||
| 73 | Core::Frontend::GraphicsContext& Context() { | ||
| 74 | return *context; | ||
| 75 | } | ||
| 76 | |||
| 77 | const Core::Frontend::GraphicsContext& Context() const { | ||
| 78 | return *context; | ||
| 79 | } | ||
| 80 | |||
| 71 | Core::Frontend::EmuWindow& GetRenderWindow() { | 81 | Core::Frontend::EmuWindow& GetRenderWindow() { |
| 72 | return render_window; | 82 | return render_window; |
| 73 | } | 83 | } |
| @@ -94,6 +104,7 @@ public: | |||
| 94 | protected: | 104 | protected: |
| 95 | Core::Frontend::EmuWindow& render_window; ///< Reference to the render window handle. | 105 | Core::Frontend::EmuWindow& render_window; ///< Reference to the render window handle. |
| 96 | std::unique_ptr<RasterizerInterface> rasterizer; | 106 | std::unique_ptr<RasterizerInterface> rasterizer; |
| 107 | std::unique_ptr<Core::Frontend::GraphicsContext> context; | ||
| 97 | f32 m_current_fps = 0.0f; ///< Current framerate, should be set by the renderer | 108 | f32 m_current_fps = 0.0f; ///< Current framerate, should be set by the renderer |
| 98 | int m_current_frame = 0; ///< Current frame, should be set by the renderer | 109 | int m_current_frame = 0; ///< Current frame, should be set by the renderer |
| 99 | 110 | ||
diff --git a/src/video_core/renderer_opengl/gl_fence_manager.cpp b/src/video_core/renderer_opengl/gl_fence_manager.cpp index ec5421afa..3d2588dd2 100644 --- a/src/video_core/renderer_opengl/gl_fence_manager.cpp +++ b/src/video_core/renderer_opengl/gl_fence_manager.cpp | |||
| @@ -4,16 +4,17 @@ | |||
| 4 | 4 | ||
| 5 | #include "common/assert.h" | 5 | #include "common/assert.h" |
| 6 | 6 | ||
| 7 | #include <glad/glad.h> | ||
| 8 | |||
| 7 | #include "video_core/renderer_opengl/gl_buffer_cache.h" | 9 | #include "video_core/renderer_opengl/gl_buffer_cache.h" |
| 8 | #include "video_core/renderer_opengl/gl_fence_manager.h" | 10 | #include "video_core/renderer_opengl/gl_fence_manager.h" |
| 9 | 11 | ||
| 10 | namespace OpenGL { | 12 | namespace OpenGL { |
| 11 | 13 | ||
| 12 | GLInnerFence::GLInnerFence(u32 payload, bool is_stubbed) | 14 | GLInnerFence::GLInnerFence(u32 payload, bool is_stubbed) : FenceBase(payload, is_stubbed) {} |
| 13 | : VideoCommon::FenceBase(payload, is_stubbed), sync_object{} {} | ||
| 14 | 15 | ||
| 15 | GLInnerFence::GLInnerFence(GPUVAddr address, u32 payload, bool is_stubbed) | 16 | GLInnerFence::GLInnerFence(GPUVAddr address, u32 payload, bool is_stubbed) |
| 16 | : VideoCommon::FenceBase(address, payload, is_stubbed), sync_object{} {} | 17 | : FenceBase(address, payload, is_stubbed) {} |
| 17 | 18 | ||
| 18 | GLInnerFence::~GLInnerFence() = default; | 19 | GLInnerFence::~GLInnerFence() = default; |
| 19 | 20 | ||
diff --git a/src/video_core/renderer_opengl/gl_fence_manager.h b/src/video_core/renderer_opengl/gl_fence_manager.h index c917b3343..1686cf5c8 100644 --- a/src/video_core/renderer_opengl/gl_fence_manager.h +++ b/src/video_core/renderer_opengl/gl_fence_manager.h | |||
| @@ -5,7 +5,6 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <memory> | 7 | #include <memory> |
| 8 | #include <glad/glad.h> | ||
| 9 | 8 | ||
| 10 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 11 | #include "video_core/fence_manager.h" | 10 | #include "video_core/fence_manager.h" |
diff --git a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp index 52fbab3c1..40c0877c1 100644 --- a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp | |||
| @@ -214,20 +214,20 @@ std::optional<std::vector<ShaderDiskCacheEntry>> ShaderDiskCacheOpenGL::LoadTran | |||
| 214 | // Skip games without title id | 214 | // Skip games without title id |
| 215 | const bool has_title_id = system.CurrentProcess()->GetTitleID() != 0; | 215 | const bool has_title_id = system.CurrentProcess()->GetTitleID() != 0; |
| 216 | if (!Settings::values.use_disk_shader_cache.GetValue() || !has_title_id) { | 216 | if (!Settings::values.use_disk_shader_cache.GetValue() || !has_title_id) { |
| 217 | return {}; | 217 | return std::nullopt; |
| 218 | } | 218 | } |
| 219 | 219 | ||
| 220 | Common::FS::IOFile file(GetTransferablePath(), "rb"); | 220 | Common::FS::IOFile file(GetTransferablePath(), "rb"); |
| 221 | if (!file.IsOpen()) { | 221 | if (!file.IsOpen()) { |
| 222 | LOG_INFO(Render_OpenGL, "No transferable shader cache found"); | 222 | LOG_INFO(Render_OpenGL, "No transferable shader cache found"); |
| 223 | is_usable = true; | 223 | is_usable = true; |
| 224 | return {}; | 224 | return std::nullopt; |
| 225 | } | 225 | } |
| 226 | 226 | ||
| 227 | u32 version{}; | 227 | u32 version{}; |
| 228 | if (file.ReadBytes(&version, sizeof(version)) != sizeof(version)) { | 228 | if (file.ReadBytes(&version, sizeof(version)) != sizeof(version)) { |
| 229 | LOG_ERROR(Render_OpenGL, "Failed to get transferable cache version, skipping it"); | 229 | LOG_ERROR(Render_OpenGL, "Failed to get transferable cache version, skipping it"); |
| 230 | return {}; | 230 | return std::nullopt; |
| 231 | } | 231 | } |
| 232 | 232 | ||
| 233 | if (version < NativeVersion) { | 233 | if (version < NativeVersion) { |
| @@ -235,12 +235,12 @@ std::optional<std::vector<ShaderDiskCacheEntry>> ShaderDiskCacheOpenGL::LoadTran | |||
| 235 | file.Close(); | 235 | file.Close(); |
| 236 | InvalidateTransferable(); | 236 | InvalidateTransferable(); |
| 237 | is_usable = true; | 237 | is_usable = true; |
| 238 | return {}; | 238 | return std::nullopt; |
| 239 | } | 239 | } |
| 240 | if (version > NativeVersion) { | 240 | if (version > NativeVersion) { |
| 241 | LOG_WARNING(Render_OpenGL, "Transferable shader cache was generated with a newer version " | 241 | LOG_WARNING(Render_OpenGL, "Transferable shader cache was generated with a newer version " |
| 242 | "of the emulator, skipping"); | 242 | "of the emulator, skipping"); |
| 243 | return {}; | 243 | return std::nullopt; |
| 244 | } | 244 | } |
| 245 | 245 | ||
| 246 | // Version is valid, load the shaders | 246 | // Version is valid, load the shaders |
| @@ -249,7 +249,7 @@ std::optional<std::vector<ShaderDiskCacheEntry>> ShaderDiskCacheOpenGL::LoadTran | |||
| 249 | ShaderDiskCacheEntry& entry = entries.emplace_back(); | 249 | ShaderDiskCacheEntry& entry = entries.emplace_back(); |
| 250 | if (!entry.Load(file)) { | 250 | if (!entry.Load(file)) { |
| 251 | LOG_ERROR(Render_OpenGL, "Failed to load transferable raw entry, skipping"); | 251 | LOG_ERROR(Render_OpenGL, "Failed to load transferable raw entry, skipping"); |
| 252 | return {}; | 252 | return std::nullopt; |
| 253 | } | 253 | } |
| 254 | } | 254 | } |
| 255 | 255 | ||
| @@ -290,12 +290,12 @@ std::optional<std::vector<ShaderDiskCachePrecompiled>> ShaderDiskCacheOpenGL::Lo | |||
| 290 | ShaderCacheVersionHash file_hash{}; | 290 | ShaderCacheVersionHash file_hash{}; |
| 291 | if (!LoadArrayFromPrecompiled(file_hash.data(), file_hash.size())) { | 291 | if (!LoadArrayFromPrecompiled(file_hash.data(), file_hash.size())) { |
| 292 | precompiled_cache_virtual_file_offset = 0; | 292 | precompiled_cache_virtual_file_offset = 0; |
| 293 | return {}; | 293 | return std::nullopt; |
| 294 | } | 294 | } |
| 295 | if (GetShaderCacheVersionHash() != file_hash) { | 295 | if (GetShaderCacheVersionHash() != file_hash) { |
| 296 | LOG_INFO(Render_OpenGL, "Precompiled cache is from another version of the emulator"); | 296 | LOG_INFO(Render_OpenGL, "Precompiled cache is from another version of the emulator"); |
| 297 | precompiled_cache_virtual_file_offset = 0; | 297 | precompiled_cache_virtual_file_offset = 0; |
| 298 | return {}; | 298 | return std::nullopt; |
| 299 | } | 299 | } |
| 300 | 300 | ||
| 301 | std::vector<ShaderDiskCachePrecompiled> entries; | 301 | std::vector<ShaderDiskCachePrecompiled> entries; |
| @@ -305,15 +305,16 @@ std::optional<std::vector<ShaderDiskCachePrecompiled>> ShaderDiskCacheOpenGL::Lo | |||
| 305 | if (!LoadObjectFromPrecompiled(entry.unique_identifier) || | 305 | if (!LoadObjectFromPrecompiled(entry.unique_identifier) || |
| 306 | !LoadObjectFromPrecompiled(entry.binary_format) || | 306 | !LoadObjectFromPrecompiled(entry.binary_format) || |
| 307 | !LoadObjectFromPrecompiled(binary_size)) { | 307 | !LoadObjectFromPrecompiled(binary_size)) { |
| 308 | return {}; | 308 | return std::nullopt; |
| 309 | } | 309 | } |
| 310 | 310 | ||
| 311 | entry.binary.resize(binary_size); | 311 | entry.binary.resize(binary_size); |
| 312 | if (!LoadArrayFromPrecompiled(entry.binary.data(), entry.binary.size())) { | 312 | if (!LoadArrayFromPrecompiled(entry.binary.data(), entry.binary.size())) { |
| 313 | return {}; | 313 | return std::nullopt; |
| 314 | } | 314 | } |
| 315 | } | 315 | } |
| 316 | return entries; | 316 | |
| 317 | return std::move(entries); | ||
| 317 | } | 318 | } |
| 318 | 319 | ||
| 319 | void ShaderDiskCacheOpenGL::InvalidateTransferable() { | 320 | void ShaderDiskCacheOpenGL::InvalidateTransferable() { |
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp index 0a7bc9e2b..f403f388a 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.cpp +++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp | |||
| @@ -403,7 +403,7 @@ void CachedSurface::DecorateSurfaceName() { | |||
| 403 | LabelGLObject(GL_TEXTURE, texture.handle, GetGpuAddr(), params.TargetName()); | 403 | LabelGLObject(GL_TEXTURE, texture.handle, GetGpuAddr(), params.TargetName()); |
| 404 | } | 404 | } |
| 405 | 405 | ||
| 406 | void CachedSurfaceView::DecorateViewName(GPUVAddr gpu_addr, std::string prefix) { | 406 | void CachedSurfaceView::DecorateViewName(GPUVAddr gpu_addr, const std::string& prefix) { |
| 407 | LabelGLObject(GL_TEXTURE, main_view.handle, gpu_addr, prefix); | 407 | LabelGLObject(GL_TEXTURE, main_view.handle, gpu_addr, prefix); |
| 408 | } | 408 | } |
| 409 | 409 | ||
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h index bfc4ddf5d..de8f18489 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.h +++ b/src/video_core/renderer_opengl/gl_texture_cache.h | |||
| @@ -90,7 +90,7 @@ public: | |||
| 90 | Tegra::Texture::SwizzleSource z_source, | 90 | Tegra::Texture::SwizzleSource z_source, |
| 91 | Tegra::Texture::SwizzleSource w_source); | 91 | Tegra::Texture::SwizzleSource w_source); |
| 92 | 92 | ||
| 93 | void DecorateViewName(GPUVAddr gpu_addr, std::string prefix); | 93 | void DecorateViewName(GPUVAddr gpu_addr, const std::string& prefix); |
| 94 | 94 | ||
| 95 | void MarkAsModified(u64 tick) { | 95 | void MarkAsModified(u64 tick) { |
| 96 | surface.MarkAsModified(true, tick); | 96 | surface.MarkAsModified(true, tick); |
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 14bbc3a1c..c39663db7 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp | |||
| @@ -313,10 +313,11 @@ public: | |||
| 313 | } | 313 | } |
| 314 | }; | 314 | }; |
| 315 | 315 | ||
| 316 | RendererOpenGL::RendererOpenGL(Core::Frontend::EmuWindow& emu_window, Core::System& system, | 316 | RendererOpenGL::RendererOpenGL(Core::System& system_, Core::Frontend::EmuWindow& emu_window_, |
| 317 | Core::Frontend::GraphicsContext& context) | 317 | Tegra::GPU& gpu_, |
| 318 | : RendererBase{emu_window}, emu_window{emu_window}, system{system}, context{context}, | 318 | std::unique_ptr<Core::Frontend::GraphicsContext> context_) |
| 319 | program_manager{device}, has_debug_tool{HasDebugTool()} {} | 319 | : RendererBase{emu_window_, std::move(context_)}, system{system_}, |
| 320 | emu_window{emu_window_}, gpu{gpu_}, program_manager{device}, has_debug_tool{HasDebugTool()} {} | ||
| 320 | 321 | ||
| 321 | RendererOpenGL::~RendererOpenGL() = default; | 322 | RendererOpenGL::~RendererOpenGL() = default; |
| 322 | 323 | ||
| @@ -384,7 +385,7 @@ void RendererOpenGL::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { | |||
| 384 | if (has_debug_tool) { | 385 | if (has_debug_tool) { |
| 385 | glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); | 386 | glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); |
| 386 | Present(0); | 387 | Present(0); |
| 387 | context.SwapBuffers(); | 388 | context->SwapBuffers(); |
| 388 | } | 389 | } |
| 389 | } | 390 | } |
| 390 | 391 | ||
diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h index 8b18d32e6..52ea76b7d 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.h +++ b/src/video_core/renderer_opengl/renderer_opengl.h | |||
| @@ -56,8 +56,9 @@ class FrameMailbox; | |||
| 56 | 56 | ||
| 57 | class RendererOpenGL final : public VideoCore::RendererBase { | 57 | class RendererOpenGL final : public VideoCore::RendererBase { |
| 58 | public: | 58 | public: |
| 59 | explicit RendererOpenGL(Core::Frontend::EmuWindow& emu_window, Core::System& system, | 59 | explicit RendererOpenGL(Core::System& system, Core::Frontend::EmuWindow& emu_window, |
| 60 | Core::Frontend::GraphicsContext& context); | 60 | Tegra::GPU& gpu, |
| 61 | std::unique_ptr<Core::Frontend::GraphicsContext> context); | ||
| 61 | ~RendererOpenGL() override; | 62 | ~RendererOpenGL() override; |
| 62 | 63 | ||
| 63 | bool Init() override; | 64 | bool Init() override; |
| @@ -93,9 +94,9 @@ private: | |||
| 93 | 94 | ||
| 94 | bool Present(int timeout_ms); | 95 | bool Present(int timeout_ms); |
| 95 | 96 | ||
| 96 | Core::Frontend::EmuWindow& emu_window; | ||
| 97 | Core::System& system; | 97 | Core::System& system; |
| 98 | Core::Frontend::GraphicsContext& context; | 98 | Core::Frontend::EmuWindow& emu_window; |
| 99 | Tegra::GPU& gpu; | ||
| 99 | const Device device; | 100 | const Device device; |
| 100 | 101 | ||
| 101 | StateTracker state_tracker{system}; | 102 | StateTracker state_tracker{system}; |
| @@ -120,7 +121,7 @@ private: | |||
| 120 | std::vector<u8> gl_framebuffer_data; | 121 | std::vector<u8> gl_framebuffer_data; |
| 121 | 122 | ||
| 122 | /// Used for transforming the framebuffer orientation | 123 | /// Used for transforming the framebuffer orientation |
| 123 | Tegra::FramebufferConfig::TransformFlags framebuffer_transform_flags; | 124 | Tegra::FramebufferConfig::TransformFlags framebuffer_transform_flags{}; |
| 124 | Common::Rectangle<int> framebuffer_crop_rect; | 125 | Common::Rectangle<int> framebuffer_crop_rect; |
| 125 | 126 | ||
| 126 | /// Frame presentation mailbox | 127 | /// Frame presentation mailbox |
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index 6e49699d0..ae46e0444 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp | |||
| @@ -237,8 +237,10 @@ std::string BuildCommaSeparatedExtensions(std::vector<std::string> available_ext | |||
| 237 | 237 | ||
| 238 | } // Anonymous namespace | 238 | } // Anonymous namespace |
| 239 | 239 | ||
| 240 | RendererVulkan::RendererVulkan(Core::Frontend::EmuWindow& window, Core::System& system) | 240 | RendererVulkan::RendererVulkan(Core::System& system_, Core::Frontend::EmuWindow& emu_window, |
| 241 | : RendererBase(window), system{system} {} | 241 | Tegra::GPU& gpu_, |
| 242 | std::unique_ptr<Core::Frontend::GraphicsContext> context) | ||
| 243 | : RendererBase{emu_window, std::move(context)}, system{system_}, gpu{gpu_} {} | ||
| 242 | 244 | ||
| 243 | RendererVulkan::~RendererVulkan() { | 245 | RendererVulkan::~RendererVulkan() { |
| 244 | ShutDown(); | 246 | ShutDown(); |
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h index 522b5bff8..13debbbc0 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.h +++ b/src/video_core/renderer_vulkan/renderer_vulkan.h | |||
| @@ -38,7 +38,9 @@ struct VKScreenInfo { | |||
| 38 | 38 | ||
| 39 | class RendererVulkan final : public VideoCore::RendererBase { | 39 | class RendererVulkan final : public VideoCore::RendererBase { |
| 40 | public: | 40 | public: |
| 41 | explicit RendererVulkan(Core::Frontend::EmuWindow& window, Core::System& system); | 41 | explicit RendererVulkan(Core::System& system, Core::Frontend::EmuWindow& emu_window, |
| 42 | Tegra::GPU& gpu, | ||
| 43 | std::unique_ptr<Core::Frontend::GraphicsContext> context); | ||
| 42 | ~RendererVulkan() override; | 44 | ~RendererVulkan() override; |
| 43 | 45 | ||
| 44 | bool Init() override; | 46 | bool Init() override; |
| @@ -58,6 +60,7 @@ private: | |||
| 58 | void Report() const; | 60 | void Report() const; |
| 59 | 61 | ||
| 60 | Core::System& system; | 62 | Core::System& system; |
| 63 | Tegra::GPU& gpu; | ||
| 61 | 64 | ||
| 62 | Common::DynamicLibrary library; | 65 | Common::DynamicLibrary library; |
| 63 | vk::InstanceDispatch dld; | 66 | vk::InstanceDispatch dld; |
diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp index 45f360bdd..4e3a092c7 100644 --- a/src/video_core/video_core.cpp +++ b/src/video_core/video_core.cpp | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <memory> | 5 | #include <memory> |
| 6 | |||
| 6 | #include "common/logging/log.h" | 7 | #include "common/logging/log.h" |
| 7 | #include "core/core.h" | 8 | #include "core/core.h" |
| 8 | #include "core/settings.h" | 9 | #include "core/settings.h" |
| @@ -16,37 +17,46 @@ | |||
| 16 | #include "video_core/video_core.h" | 17 | #include "video_core/video_core.h" |
| 17 | 18 | ||
| 18 | namespace { | 19 | namespace { |
| 19 | std::unique_ptr<VideoCore::RendererBase> CreateRenderer(Core::Frontend::EmuWindow& emu_window, | 20 | |
| 20 | Core::System& system, | 21 | std::unique_ptr<VideoCore::RendererBase> CreateRenderer( |
| 21 | Core::Frontend::GraphicsContext& context) { | 22 | Core::System& system, Core::Frontend::EmuWindow& emu_window, Tegra::GPU& gpu, |
| 23 | std::unique_ptr<Core::Frontend::GraphicsContext> context) { | ||
| 22 | switch (Settings::values.renderer_backend.GetValue()) { | 24 | switch (Settings::values.renderer_backend.GetValue()) { |
| 23 | case Settings::RendererBackend::OpenGL: | 25 | case Settings::RendererBackend::OpenGL: |
| 24 | return std::make_unique<OpenGL::RendererOpenGL>(emu_window, system, context); | 26 | return std::make_unique<OpenGL::RendererOpenGL>(system, emu_window, gpu, |
| 27 | std::move(context)); | ||
| 25 | #ifdef HAS_VULKAN | 28 | #ifdef HAS_VULKAN |
| 26 | case Settings::RendererBackend::Vulkan: | 29 | case Settings::RendererBackend::Vulkan: |
| 27 | return std::make_unique<Vulkan::RendererVulkan>(emu_window, system); | 30 | return std::make_unique<Vulkan::RendererVulkan>(system, emu_window, gpu, |
| 31 | std::move(context)); | ||
| 28 | #endif | 32 | #endif |
| 29 | default: | 33 | default: |
| 30 | return nullptr; | 34 | return nullptr; |
| 31 | } | 35 | } |
| 32 | } | 36 | } |
| 37 | |||
| 33 | } // Anonymous namespace | 38 | } // Anonymous namespace |
| 34 | 39 | ||
| 35 | namespace VideoCore { | 40 | namespace VideoCore { |
| 36 | 41 | ||
| 37 | std::unique_ptr<Tegra::GPU> CreateGPU(Core::Frontend::EmuWindow& emu_window, Core::System& system) { | 42 | std::unique_ptr<Tegra::GPU> CreateGPU(Core::Frontend::EmuWindow& emu_window, Core::System& system) { |
| 43 | std::unique_ptr<Tegra::GPU> gpu; | ||
| 44 | if (Settings::values.use_asynchronous_gpu_emulation.GetValue()) { | ||
| 45 | gpu = std::make_unique<VideoCommon::GPUAsynch>(system); | ||
| 46 | } else { | ||
| 47 | gpu = std::make_unique<VideoCommon::GPUSynch>(system); | ||
| 48 | } | ||
| 49 | |||
| 38 | auto context = emu_window.CreateSharedContext(); | 50 | auto context = emu_window.CreateSharedContext(); |
| 39 | const auto scope = context->Acquire(); | 51 | const auto scope = context->Acquire(); |
| 40 | auto renderer = CreateRenderer(emu_window, system, *context); | 52 | |
| 53 | auto renderer = CreateRenderer(system, emu_window, *gpu, std::move(context)); | ||
| 41 | if (!renderer->Init()) { | 54 | if (!renderer->Init()) { |
| 42 | return nullptr; | 55 | return nullptr; |
| 43 | } | 56 | } |
| 44 | 57 | ||
| 45 | if (Settings::values.use_asynchronous_gpu_emulation.GetValue()) { | 58 | gpu->BindRenderer(std::move(renderer)); |
| 46 | return std::make_unique<VideoCommon::GPUAsynch>(system, std::move(renderer), | 59 | return gpu; |
| 47 | std::move(context)); | ||
| 48 | } | ||
| 49 | return std::make_unique<VideoCommon::GPUSynch>(system, std::move(renderer), std::move(context)); | ||
| 50 | } | 60 | } |
| 51 | 61 | ||
| 52 | u16 GetResolutionScaleFactor(const RendererBase& renderer) { | 62 | u16 GetResolutionScaleFactor(const RendererBase& renderer) { |
diff --git a/src/web_service/CMakeLists.txt b/src/web_service/CMakeLists.txt index 06ab7c59d..7e484b906 100644 --- a/src/web_service/CMakeLists.txt +++ b/src/web_service/CMakeLists.txt | |||
| @@ -5,6 +5,7 @@ add_library(web_service STATIC | |||
| 5 | verify_login.h | 5 | verify_login.h |
| 6 | web_backend.cpp | 6 | web_backend.cpp |
| 7 | web_backend.h | 7 | web_backend.h |
| 8 | web_result.h | ||
| 8 | ) | 9 | ) |
| 9 | 10 | ||
| 10 | create_target_directory_groups(web_service) | 11 | create_target_directory_groups(web_service) |
diff --git a/src/web_service/telemetry_json.cpp b/src/web_service/telemetry_json.cpp index c89a3a0db..6215c914f 100644 --- a/src/web_service/telemetry_json.cpp +++ b/src/web_service/telemetry_json.cpp | |||
| @@ -4,9 +4,9 @@ | |||
| 4 | 4 | ||
| 5 | #include <nlohmann/json.hpp> | 5 | #include <nlohmann/json.hpp> |
| 6 | #include "common/detached_tasks.h" | 6 | #include "common/detached_tasks.h" |
| 7 | #include "common/web_result.h" | ||
| 8 | #include "web_service/telemetry_json.h" | 7 | #include "web_service/telemetry_json.h" |
| 9 | #include "web_service/web_backend.h" | 8 | #include "web_service/web_backend.h" |
| 9 | #include "web_service/web_result.h" | ||
| 10 | 10 | ||
| 11 | namespace WebService { | 11 | namespace WebService { |
| 12 | 12 | ||
| @@ -125,7 +125,7 @@ bool TelemetryJson::SubmitTestcase() { | |||
| 125 | Client client(impl->host, impl->username, impl->token); | 125 | Client client(impl->host, impl->username, impl->token); |
| 126 | auto value = client.PostJson("/gamedb/testcase", content, false); | 126 | auto value = client.PostJson("/gamedb/testcase", content, false); |
| 127 | 127 | ||
| 128 | return value.result_code == Common::WebResult::Code::Success; | 128 | return value.result_code == WebResult::Code::Success; |
| 129 | } | 129 | } |
| 130 | 130 | ||
| 131 | } // namespace WebService | 131 | } // namespace WebService |
diff --git a/src/web_service/verify_login.cpp b/src/web_service/verify_login.cpp index bfaa5b70a..ceb55ca6b 100644 --- a/src/web_service/verify_login.cpp +++ b/src/web_service/verify_login.cpp | |||
| @@ -3,9 +3,9 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <nlohmann/json.hpp> | 5 | #include <nlohmann/json.hpp> |
| 6 | #include "common/web_result.h" | ||
| 7 | #include "web_service/verify_login.h" | 6 | #include "web_service/verify_login.h" |
| 8 | #include "web_service/web_backend.h" | 7 | #include "web_service/web_backend.h" |
| 8 | #include "web_service/web_result.h" | ||
| 9 | 9 | ||
| 10 | namespace WebService { | 10 | namespace WebService { |
| 11 | 11 | ||
diff --git a/src/web_service/web_backend.cpp b/src/web_service/web_backend.cpp index 09d1651ac..74e287045 100644 --- a/src/web_service/web_backend.cpp +++ b/src/web_service/web_backend.cpp | |||
| @@ -6,13 +6,14 @@ | |||
| 6 | #include <cstdlib> | 6 | #include <cstdlib> |
| 7 | #include <mutex> | 7 | #include <mutex> |
| 8 | #include <string> | 8 | #include <string> |
| 9 | |||
| 9 | #include <LUrlParser.h> | 10 | #include <LUrlParser.h> |
| 10 | #include <fmt/format.h> | 11 | #include <fmt/format.h> |
| 11 | #include <httplib.h> | 12 | #include <httplib.h> |
| 12 | #include "common/common_types.h" | 13 | |
| 13 | #include "common/logging/log.h" | 14 | #include "common/logging/log.h" |
| 14 | #include "common/web_result.h" | ||
| 15 | #include "web_service/web_backend.h" | 15 | #include "web_service/web_backend.h" |
| 16 | #include "web_service/web_result.h" | ||
| 16 | 17 | ||
| 17 | namespace WebService { | 18 | namespace WebService { |
| 18 | 19 | ||
| @@ -33,17 +34,16 @@ struct Client::Impl { | |||
| 33 | } | 34 | } |
| 34 | 35 | ||
| 35 | /// A generic function handles POST, GET and DELETE request together | 36 | /// A generic function handles POST, GET and DELETE request together |
| 36 | Common::WebResult GenericRequest(const std::string& method, const std::string& path, | 37 | WebResult GenericRequest(const std::string& method, const std::string& path, |
| 37 | const std::string& data, bool allow_anonymous, | 38 | const std::string& data, bool allow_anonymous, |
| 38 | const std::string& accept) { | 39 | const std::string& accept) { |
| 39 | if (jwt.empty()) { | 40 | if (jwt.empty()) { |
| 40 | UpdateJWT(); | 41 | UpdateJWT(); |
| 41 | } | 42 | } |
| 42 | 43 | ||
| 43 | if (jwt.empty() && !allow_anonymous) { | 44 | if (jwt.empty() && !allow_anonymous) { |
| 44 | LOG_ERROR(WebService, "Credentials must be provided for authenticated requests"); | 45 | LOG_ERROR(WebService, "Credentials must be provided for authenticated requests"); |
| 45 | return Common::WebResult{Common::WebResult::Code::CredentialsMissing, | 46 | return WebResult{WebResult::Code::CredentialsMissing, "Credentials needed", ""}; |
| 46 | "Credentials needed", ""}; | ||
| 47 | } | 47 | } |
| 48 | 48 | ||
| 49 | auto result = GenericRequest(method, path, data, accept, jwt); | 49 | auto result = GenericRequest(method, path, data, accept, jwt); |
| @@ -62,10 +62,10 @@ struct Client::Impl { | |||
| 62 | * username + token is used if jwt is empty but username and token are | 62 | * username + token is used if jwt is empty but username and token are |
| 63 | * not empty anonymous if all of jwt, username and token are empty | 63 | * not empty anonymous if all of jwt, username and token are empty |
| 64 | */ | 64 | */ |
| 65 | Common::WebResult GenericRequest(const std::string& method, const std::string& path, | 65 | WebResult GenericRequest(const std::string& method, const std::string& path, |
| 66 | const std::string& data, const std::string& accept, | 66 | const std::string& data, const std::string& accept, |
| 67 | const std::string& jwt = "", const std::string& username = "", | 67 | const std::string& jwt = "", const std::string& username = "", |
| 68 | const std::string& token = "") { | 68 | const std::string& token = "") { |
| 69 | if (cli == nullptr) { | 69 | if (cli == nullptr) { |
| 70 | auto parsedUrl = LUrlParser::clParseURL::ParseURL(host); | 70 | auto parsedUrl = LUrlParser::clParseURL::ParseURL(host); |
| 71 | int port; | 71 | int port; |
| @@ -81,12 +81,12 @@ struct Client::Impl { | |||
| 81 | cli = std::make_unique<httplib::SSLClient>(parsedUrl.m_Host.c_str(), port); | 81 | cli = std::make_unique<httplib::SSLClient>(parsedUrl.m_Host.c_str(), port); |
| 82 | } else { | 82 | } else { |
| 83 | LOG_ERROR(WebService, "Bad URL scheme {}", parsedUrl.m_Scheme); | 83 | LOG_ERROR(WebService, "Bad URL scheme {}", parsedUrl.m_Scheme); |
| 84 | return Common::WebResult{Common::WebResult::Code::InvalidURL, "Bad URL scheme", ""}; | 84 | return WebResult{WebResult::Code::InvalidURL, "Bad URL scheme", ""}; |
| 85 | } | 85 | } |
| 86 | } | 86 | } |
| 87 | if (cli == nullptr) { | 87 | if (cli == nullptr) { |
| 88 | LOG_ERROR(WebService, "Invalid URL {}", host + path); | 88 | LOG_ERROR(WebService, "Invalid URL {}", host + path); |
| 89 | return Common::WebResult{Common::WebResult::Code::InvalidURL, "Invalid URL", ""}; | 89 | return WebResult{WebResult::Code::InvalidURL, "Invalid URL", ""}; |
| 90 | } | 90 | } |
| 91 | cli->set_timeout_sec(TIMEOUT_SECONDS); | 91 | cli->set_timeout_sec(TIMEOUT_SECONDS); |
| 92 | 92 | ||
| @@ -106,7 +106,7 @@ struct Client::Impl { | |||
| 106 | std::string(API_VERSION.begin(), API_VERSION.end())); | 106 | std::string(API_VERSION.begin(), API_VERSION.end())); |
| 107 | if (method != "GET") { | 107 | if (method != "GET") { |
| 108 | params.emplace(std::string("Content-Type"), std::string("application/json")); | 108 | params.emplace(std::string("Content-Type"), std::string("application/json")); |
| 109 | }; | 109 | } |
| 110 | 110 | ||
| 111 | httplib::Request request; | 111 | httplib::Request request; |
| 112 | request.method = method; | 112 | request.method = method; |
| @@ -118,29 +118,28 @@ struct Client::Impl { | |||
| 118 | 118 | ||
| 119 | if (!cli->send(request, response)) { | 119 | if (!cli->send(request, response)) { |
| 120 | LOG_ERROR(WebService, "{} to {} returned null", method, host + path); | 120 | LOG_ERROR(WebService, "{} to {} returned null", method, host + path); |
| 121 | return Common::WebResult{Common::WebResult::Code::LibError, "Null response", ""}; | 121 | return WebResult{WebResult::Code::LibError, "Null response", ""}; |
| 122 | } | 122 | } |
| 123 | 123 | ||
| 124 | if (response.status >= 400) { | 124 | if (response.status >= 400) { |
| 125 | LOG_ERROR(WebService, "{} to {} returned error status code: {}", method, host + path, | 125 | LOG_ERROR(WebService, "{} to {} returned error status code: {}", method, host + path, |
| 126 | response.status); | 126 | response.status); |
| 127 | return Common::WebResult{Common::WebResult::Code::HttpError, | 127 | return WebResult{WebResult::Code::HttpError, std::to_string(response.status), ""}; |
| 128 | std::to_string(response.status), ""}; | ||
| 129 | } | 128 | } |
| 130 | 129 | ||
| 131 | auto content_type = response.headers.find("content-type"); | 130 | auto content_type = response.headers.find("content-type"); |
| 132 | 131 | ||
| 133 | if (content_type == response.headers.end()) { | 132 | if (content_type == response.headers.end()) { |
| 134 | LOG_ERROR(WebService, "{} to {} returned no content", method, host + path); | 133 | LOG_ERROR(WebService, "{} to {} returned no content", method, host + path); |
| 135 | return Common::WebResult{Common::WebResult::Code::WrongContent, "", ""}; | 134 | return WebResult{WebResult::Code::WrongContent, "", ""}; |
| 136 | } | 135 | } |
| 137 | 136 | ||
| 138 | if (content_type->second.find(accept) == std::string::npos) { | 137 | if (content_type->second.find(accept) == std::string::npos) { |
| 139 | LOG_ERROR(WebService, "{} to {} returned wrong content: {}", method, host + path, | 138 | LOG_ERROR(WebService, "{} to {} returned wrong content: {}", method, host + path, |
| 140 | content_type->second); | 139 | content_type->second); |
| 141 | return Common::WebResult{Common::WebResult::Code::WrongContent, "Wrong content", ""}; | 140 | return WebResult{WebResult::Code::WrongContent, "Wrong content", ""}; |
| 142 | } | 141 | } |
| 143 | return Common::WebResult{Common::WebResult::Code::Success, "", response.body}; | 142 | return WebResult{WebResult::Code::Success, "", response.body}; |
| 144 | } | 143 | } |
| 145 | 144 | ||
| 146 | // Retrieve a new JWT from given username and token | 145 | // Retrieve a new JWT from given username and token |
| @@ -150,7 +149,7 @@ struct Client::Impl { | |||
| 150 | } | 149 | } |
| 151 | 150 | ||
| 152 | auto result = GenericRequest("POST", "/jwt/internal", "", "text/html", "", username, token); | 151 | auto result = GenericRequest("POST", "/jwt/internal", "", "text/html", "", username, token); |
| 153 | if (result.result_code != Common::WebResult::Code::Success) { | 152 | if (result.result_code != WebResult::Code::Success) { |
| 154 | LOG_ERROR(WebService, "UpdateJWT failed"); | 153 | LOG_ERROR(WebService, "UpdateJWT failed"); |
| 155 | } else { | 154 | } else { |
| 156 | std::lock_guard lock{jwt_cache.mutex}; | 155 | std::lock_guard lock{jwt_cache.mutex}; |
| @@ -180,29 +179,28 @@ Client::Client(std::string host, std::string username, std::string token) | |||
| 180 | 179 | ||
| 181 | Client::~Client() = default; | 180 | Client::~Client() = default; |
| 182 | 181 | ||
| 183 | Common::WebResult Client::PostJson(const std::string& path, const std::string& data, | 182 | WebResult Client::PostJson(const std::string& path, const std::string& data, bool allow_anonymous) { |
| 184 | bool allow_anonymous) { | ||
| 185 | return impl->GenericRequest("POST", path, data, allow_anonymous, "application/json"); | 183 | return impl->GenericRequest("POST", path, data, allow_anonymous, "application/json"); |
| 186 | } | 184 | } |
| 187 | 185 | ||
| 188 | Common::WebResult Client::GetJson(const std::string& path, bool allow_anonymous) { | 186 | WebResult Client::GetJson(const std::string& path, bool allow_anonymous) { |
| 189 | return impl->GenericRequest("GET", path, "", allow_anonymous, "application/json"); | 187 | return impl->GenericRequest("GET", path, "", allow_anonymous, "application/json"); |
| 190 | } | 188 | } |
| 191 | 189 | ||
| 192 | Common::WebResult Client::DeleteJson(const std::string& path, const std::string& data, | 190 | WebResult Client::DeleteJson(const std::string& path, const std::string& data, |
| 193 | bool allow_anonymous) { | 191 | bool allow_anonymous) { |
| 194 | return impl->GenericRequest("DELETE", path, data, allow_anonymous, "application/json"); | 192 | return impl->GenericRequest("DELETE", path, data, allow_anonymous, "application/json"); |
| 195 | } | 193 | } |
| 196 | 194 | ||
| 197 | Common::WebResult Client::GetPlain(const std::string& path, bool allow_anonymous) { | 195 | WebResult Client::GetPlain(const std::string& path, bool allow_anonymous) { |
| 198 | return impl->GenericRequest("GET", path, "", allow_anonymous, "text/plain"); | 196 | return impl->GenericRequest("GET", path, "", allow_anonymous, "text/plain"); |
| 199 | } | 197 | } |
| 200 | 198 | ||
| 201 | Common::WebResult Client::GetImage(const std::string& path, bool allow_anonymous) { | 199 | WebResult Client::GetImage(const std::string& path, bool allow_anonymous) { |
| 202 | return impl->GenericRequest("GET", path, "", allow_anonymous, "image/png"); | 200 | return impl->GenericRequest("GET", path, "", allow_anonymous, "image/png"); |
| 203 | } | 201 | } |
| 204 | 202 | ||
| 205 | Common::WebResult Client::GetExternalJWT(const std::string& audience) { | 203 | WebResult Client::GetExternalJWT(const std::string& audience) { |
| 206 | return impl->GenericRequest("POST", fmt::format("/jwt/external/{}", audience), "", false, | 204 | return impl->GenericRequest("POST", fmt::format("/jwt/external/{}", audience), "", false, |
| 207 | "text/html"); | 205 | "text/html"); |
| 208 | } | 206 | } |
diff --git a/src/web_service/web_backend.h b/src/web_service/web_backend.h index 04121f17e..81f58583c 100644 --- a/src/web_service/web_backend.h +++ b/src/web_service/web_backend.h | |||
| @@ -7,12 +7,10 @@ | |||
| 7 | #include <memory> | 7 | #include <memory> |
| 8 | #include <string> | 8 | #include <string> |
| 9 | 9 | ||
| 10 | namespace Common { | ||
| 11 | struct WebResult; | ||
| 12 | } | ||
| 13 | |||
| 14 | namespace WebService { | 10 | namespace WebService { |
| 15 | 11 | ||
| 12 | struct WebResult; | ||
| 13 | |||
| 16 | class Client { | 14 | class Client { |
| 17 | public: | 15 | public: |
| 18 | Client(std::string host, std::string username, std::string token); | 16 | Client(std::string host, std::string username, std::string token); |
| @@ -25,8 +23,7 @@ public: | |||
| 25 | * @param allow_anonymous If true, allow anonymous unauthenticated requests. | 23 | * @param allow_anonymous If true, allow anonymous unauthenticated requests. |
| 26 | * @return the result of the request. | 24 | * @return the result of the request. |
| 27 | */ | 25 | */ |
| 28 | Common::WebResult PostJson(const std::string& path, const std::string& data, | 26 | WebResult PostJson(const std::string& path, const std::string& data, bool allow_anonymous); |
| 29 | bool allow_anonymous); | ||
| 30 | 27 | ||
| 31 | /** | 28 | /** |
| 32 | * Gets JSON from the specified path. | 29 | * Gets JSON from the specified path. |
| @@ -34,7 +31,7 @@ public: | |||
| 34 | * @param allow_anonymous If true, allow anonymous unauthenticated requests. | 31 | * @param allow_anonymous If true, allow anonymous unauthenticated requests. |
| 35 | * @return the result of the request. | 32 | * @return the result of the request. |
| 36 | */ | 33 | */ |
| 37 | Common::WebResult GetJson(const std::string& path, bool allow_anonymous); | 34 | WebResult GetJson(const std::string& path, bool allow_anonymous); |
| 38 | 35 | ||
| 39 | /** | 36 | /** |
| 40 | * Deletes JSON to the specified path. | 37 | * Deletes JSON to the specified path. |
| @@ -43,8 +40,7 @@ public: | |||
| 43 | * @param allow_anonymous If true, allow anonymous unauthenticated requests. | 40 | * @param allow_anonymous If true, allow anonymous unauthenticated requests. |
| 44 | * @return the result of the request. | 41 | * @return the result of the request. |
| 45 | */ | 42 | */ |
| 46 | Common::WebResult DeleteJson(const std::string& path, const std::string& data, | 43 | WebResult DeleteJson(const std::string& path, const std::string& data, bool allow_anonymous); |
| 47 | bool allow_anonymous); | ||
| 48 | 44 | ||
| 49 | /** | 45 | /** |
| 50 | * Gets a plain string from the specified path. | 46 | * Gets a plain string from the specified path. |
| @@ -52,7 +48,7 @@ public: | |||
| 52 | * @param allow_anonymous If true, allow anonymous unauthenticated requests. | 48 | * @param allow_anonymous If true, allow anonymous unauthenticated requests. |
| 53 | * @return the result of the request. | 49 | * @return the result of the request. |
| 54 | */ | 50 | */ |
| 55 | Common::WebResult GetPlain(const std::string& path, bool allow_anonymous); | 51 | WebResult GetPlain(const std::string& path, bool allow_anonymous); |
| 56 | 52 | ||
| 57 | /** | 53 | /** |
| 58 | * Gets an PNG image from the specified path. | 54 | * Gets an PNG image from the specified path. |
| @@ -60,14 +56,14 @@ public: | |||
| 60 | * @param allow_anonymous If true, allow anonymous unauthenticated requests. | 56 | * @param allow_anonymous If true, allow anonymous unauthenticated requests. |
| 61 | * @return the result of the request. | 57 | * @return the result of the request. |
| 62 | */ | 58 | */ |
| 63 | Common::WebResult GetImage(const std::string& path, bool allow_anonymous); | 59 | WebResult GetImage(const std::string& path, bool allow_anonymous); |
| 64 | 60 | ||
| 65 | /** | 61 | /** |
| 66 | * Requests an external JWT for the specific audience provided. | 62 | * Requests an external JWT for the specific audience provided. |
| 67 | * @param audience the audience of the JWT requested. | 63 | * @param audience the audience of the JWT requested. |
| 68 | * @return the result of the request. | 64 | * @return the result of the request. |
| 69 | */ | 65 | */ |
| 70 | Common::WebResult GetExternalJWT(const std::string& audience); | 66 | WebResult GetExternalJWT(const std::string& audience); |
| 71 | 67 | ||
| 72 | private: | 68 | private: |
| 73 | struct Impl; | 69 | struct Impl; |
diff --git a/src/common/web_result.h b/src/web_service/web_result.h index 8bfa2141d..3aeeb5288 100644 --- a/src/common/web_result.h +++ b/src/web_service/web_result.h | |||
| @@ -7,7 +7,7 @@ | |||
| 7 | #include <string> | 7 | #include <string> |
| 8 | #include "common/common_types.h" | 8 | #include "common/common_types.h" |
| 9 | 9 | ||
| 10 | namespace Common { | 10 | namespace WebService { |
| 11 | struct WebResult { | 11 | struct WebResult { |
| 12 | enum class Code : u32 { | 12 | enum class Code : u32 { |
| 13 | Success, | 13 | Success, |
| @@ -22,4 +22,4 @@ struct WebResult { | |||
| 22 | std::string result_string; | 22 | std::string result_string; |
| 23 | std::string returned_data; | 23 | std::string returned_data; |
| 24 | }; | 24 | }; |
| 25 | } // namespace Common | 25 | } // namespace WebService |
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index a372190cc..7af974d8d 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp | |||
| @@ -635,6 +635,11 @@ void Config::ReadCpuValues() { | |||
| 635 | ReadSetting(QStringLiteral("cpuopt_misc_ir"), true).toBool(); | 635 | ReadSetting(QStringLiteral("cpuopt_misc_ir"), true).toBool(); |
| 636 | Settings::values.cpuopt_reduce_misalign_checks = | 636 | Settings::values.cpuopt_reduce_misalign_checks = |
| 637 | ReadSetting(QStringLiteral("cpuopt_reduce_misalign_checks"), true).toBool(); | 637 | ReadSetting(QStringLiteral("cpuopt_reduce_misalign_checks"), true).toBool(); |
| 638 | |||
| 639 | Settings::values.cpuopt_unsafe_unfuse_fma = | ||
| 640 | ReadSetting(QStringLiteral("cpuopt_unsafe_unfuse_fma"), true).toBool(); | ||
| 641 | Settings::values.cpuopt_unsafe_reduce_fp_error = | ||
| 642 | ReadSetting(QStringLiteral("cpuopt_unsafe_reduce_fp_error"), true).toBool(); | ||
| 638 | } | 643 | } |
| 639 | 644 | ||
| 640 | qt_config->endGroup(); | 645 | qt_config->endGroup(); |
| @@ -1132,6 +1137,11 @@ void Config::SaveCpuValues() { | |||
| 1132 | WriteSetting(QStringLiteral("cpuopt_misc_ir"), Settings::values.cpuopt_misc_ir, true); | 1137 | WriteSetting(QStringLiteral("cpuopt_misc_ir"), Settings::values.cpuopt_misc_ir, true); |
| 1133 | WriteSetting(QStringLiteral("cpuopt_reduce_misalign_checks"), | 1138 | WriteSetting(QStringLiteral("cpuopt_reduce_misalign_checks"), |
| 1134 | Settings::values.cpuopt_reduce_misalign_checks, true); | 1139 | Settings::values.cpuopt_reduce_misalign_checks, true); |
| 1140 | |||
| 1141 | WriteSetting(QStringLiteral("cpuopt_unsafe_unfuse_fma"), | ||
| 1142 | Settings::values.cpuopt_unsafe_unfuse_fma, true); | ||
| 1143 | WriteSetting(QStringLiteral("cpuopt_unsafe_reduce_fp_error"), | ||
| 1144 | Settings::values.cpuopt_unsafe_reduce_fp_error, true); | ||
| 1135 | } | 1145 | } |
| 1136 | 1146 | ||
| 1137 | qt_config->endGroup(); | 1147 | qt_config->endGroup(); |
diff --git a/src/yuzu/configuration/configure_cpu.cpp b/src/yuzu/configuration/configure_cpu.cpp index 7493e5ffb..37fcd6adc 100644 --- a/src/yuzu/configuration/configure_cpu.cpp +++ b/src/yuzu/configuration/configure_cpu.cpp | |||
| @@ -19,6 +19,8 @@ ConfigureCpu::ConfigureCpu(QWidget* parent) : QWidget(parent), ui(new Ui::Config | |||
| 19 | 19 | ||
| 20 | connect(ui->accuracy, qOverload<int>(&QComboBox::activated), this, | 20 | connect(ui->accuracy, qOverload<int>(&QComboBox::activated), this, |
| 21 | &ConfigureCpu::AccuracyUpdated); | 21 | &ConfigureCpu::AccuracyUpdated); |
| 22 | connect(ui->accuracy, qOverload<int>(&QComboBox::currentIndexChanged), this, | ||
| 23 | &ConfigureCpu::UpdateGroup); | ||
| 22 | } | 24 | } |
| 23 | 25 | ||
| 24 | ConfigureCpu::~ConfigureCpu() = default; | 26 | ConfigureCpu::~ConfigureCpu() = default; |
| @@ -28,6 +30,12 @@ void ConfigureCpu::SetConfiguration() { | |||
| 28 | 30 | ||
| 29 | ui->accuracy->setEnabled(runtime_lock); | 31 | ui->accuracy->setEnabled(runtime_lock); |
| 30 | ui->accuracy->setCurrentIndex(static_cast<int>(Settings::values.cpu_accuracy)); | 32 | ui->accuracy->setCurrentIndex(static_cast<int>(Settings::values.cpu_accuracy)); |
| 33 | UpdateGroup(static_cast<int>(Settings::values.cpu_accuracy)); | ||
| 34 | |||
| 35 | ui->cpuopt_unsafe_unfuse_fma->setEnabled(runtime_lock); | ||
| 36 | ui->cpuopt_unsafe_unfuse_fma->setChecked(Settings::values.cpuopt_unsafe_unfuse_fma); | ||
| 37 | ui->cpuopt_unsafe_reduce_fp_error->setEnabled(runtime_lock); | ||
| 38 | ui->cpuopt_unsafe_reduce_fp_error->setChecked(Settings::values.cpuopt_unsafe_reduce_fp_error); | ||
| 31 | } | 39 | } |
| 32 | 40 | ||
| 33 | void ConfigureCpu::AccuracyUpdated(int index) { | 41 | void ConfigureCpu::AccuracyUpdated(int index) { |
| @@ -38,14 +46,21 @@ void ConfigureCpu::AccuracyUpdated(int index) { | |||
| 38 | QMessageBox::Yes | QMessageBox::No); | 46 | QMessageBox::Yes | QMessageBox::No); |
| 39 | if (result == QMessageBox::No) { | 47 | if (result == QMessageBox::No) { |
| 40 | ui->accuracy->setCurrentIndex(static_cast<int>(Settings::CPUAccuracy::Accurate)); | 48 | ui->accuracy->setCurrentIndex(static_cast<int>(Settings::CPUAccuracy::Accurate)); |
| 41 | return; | 49 | UpdateGroup(static_cast<int>(Settings::CPUAccuracy::Accurate)); |
| 42 | } | 50 | } |
| 43 | } | 51 | } |
| 44 | } | 52 | } |
| 45 | 53 | ||
| 54 | void ConfigureCpu::UpdateGroup(int index) { | ||
| 55 | ui->unsafe_group->setVisible(static_cast<Settings::CPUAccuracy>(index) == | ||
| 56 | Settings::CPUAccuracy::Unsafe); | ||
| 57 | } | ||
| 58 | |||
| 46 | void ConfigureCpu::ApplyConfiguration() { | 59 | void ConfigureCpu::ApplyConfiguration() { |
| 47 | Settings::values.cpu_accuracy = | 60 | Settings::values.cpu_accuracy = |
| 48 | static_cast<Settings::CPUAccuracy>(ui->accuracy->currentIndex()); | 61 | static_cast<Settings::CPUAccuracy>(ui->accuracy->currentIndex()); |
| 62 | Settings::values.cpuopt_unsafe_unfuse_fma = ui->cpuopt_unsafe_unfuse_fma->isChecked(); | ||
| 63 | Settings::values.cpuopt_unsafe_reduce_fp_error = ui->cpuopt_unsafe_reduce_fp_error->isChecked(); | ||
| 49 | } | 64 | } |
| 50 | 65 | ||
| 51 | void ConfigureCpu::changeEvent(QEvent* event) { | 66 | void ConfigureCpu::changeEvent(QEvent* event) { |
diff --git a/src/yuzu/configuration/configure_cpu.h b/src/yuzu/configuration/configure_cpu.h index e4741d3a4..3c5683d81 100644 --- a/src/yuzu/configuration/configure_cpu.h +++ b/src/yuzu/configuration/configure_cpu.h | |||
| @@ -26,6 +26,7 @@ private: | |||
| 26 | void RetranslateUI(); | 26 | void RetranslateUI(); |
| 27 | 27 | ||
| 28 | void AccuracyUpdated(int index); | 28 | void AccuracyUpdated(int index); |
| 29 | void UpdateGroup(int index); | ||
| 29 | 30 | ||
| 30 | void SetConfiguration(); | 31 | void SetConfiguration(); |
| 31 | 32 | ||
diff --git a/src/yuzu/configuration/configure_cpu.ui b/src/yuzu/configuration/configure_cpu.ui index bf6ea79bb..ebdd2e6e9 100644 --- a/src/yuzu/configuration/configure_cpu.ui +++ b/src/yuzu/configuration/configure_cpu.ui | |||
| @@ -40,6 +40,11 @@ | |||
| 40 | </item> | 40 | </item> |
| 41 | <item> | 41 | <item> |
| 42 | <property name="text"> | 42 | <property name="text"> |
| 43 | <string>Unsafe</string> | ||
| 44 | </property> | ||
| 45 | </item> | ||
| 46 | <item> | ||
| 47 | <property name="text"> | ||
| 43 | <string>Enable Debug Mode</string> | 48 | <string>Enable Debug Mode</string> |
| 44 | </property> | 49 | </property> |
| 45 | </item> | 50 | </item> |
| @@ -63,6 +68,53 @@ | |||
| 63 | </layout> | 68 | </layout> |
| 64 | </item> | 69 | </item> |
| 65 | <item> | 70 | <item> |
| 71 | <layout class="QVBoxLayout"> | ||
| 72 | <item> | ||
| 73 | <widget class="QGroupBox" name="unsafe_group"> | ||
| 74 | <property name="title"> | ||
| 75 | <string>Unsafe CPU Optimization Settings</string> | ||
| 76 | </property> | ||
| 77 | <layout class="QVBoxLayout"> | ||
| 78 | <item> | ||
| 79 | <widget class="QLabel"> | ||
| 80 | <property name="wordWrap"> | ||
| 81 | <bool>1</bool> | ||
| 82 | </property> | ||
| 83 | <property name="text"> | ||
| 84 | <string>These settings reduce accuracy for speed.</string> | ||
| 85 | </property> | ||
| 86 | </widget> | ||
| 87 | </item> | ||
| 88 | <item> | ||
| 89 | <widget class="QCheckBox" name="cpuopt_unsafe_unfuse_fma"> | ||
| 90 | <property name="text"> | ||
| 91 | <string>Unfuse FMA (improve performance on CPUs without FMA)</string> | ||
| 92 | </property> | ||
| 93 | <property name="toolTip"> | ||
| 94 | <string> | ||
| 95 | <div>This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support.</div> | ||
| 96 | </string> | ||
| 97 | </property> | ||
| 98 | </widget> | ||
| 99 | </item> | ||
| 100 | <item> | ||
| 101 | <widget class="QCheckBox" name="cpuopt_unsafe_reduce_fp_error"> | ||
| 102 | <property name="text"> | ||
| 103 | <string>Faster FRSQRTE and FRECPE</string> | ||
| 104 | </property> | ||
| 105 | <property name="toolTip"> | ||
| 106 | <string> | ||
| 107 | <div>This option improves the speed of some approximate floating-point functions by using less accurate native approximations.</div> | ||
| 108 | </string> | ||
| 109 | </property> | ||
| 110 | </widget> | ||
| 111 | </item> | ||
| 112 | </layout> | ||
| 113 | </widget> | ||
| 114 | </item> | ||
| 115 | </layout> | ||
| 116 | </item> | ||
| 117 | <item> | ||
| 66 | <spacer name="verticalSpacer"> | 118 | <spacer name="verticalSpacer"> |
| 67 | <property name="orientation"> | 119 | <property name="orientation"> |
| 68 | <enum>Qt::Vertical</enum> | 120 | <enum>Qt::Vertical</enum> |