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      virtual_buffer.h      wall_clock.cpp      wall_clock.h -    web_result.h      zstd_compression.cpp      zstd_compression.h  ) 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 @@  #include "common/swap.h"  #include "common/vector_math.h" -namespace Color { +namespace Common::Color {  /// Convert a 1-bit color component to 8 bit  [[nodiscard]] constexpr u8 Convert1To8(u8 value) { @@ -268,4 +268,4 @@ inline void EncodeX24S8(u8 stencil, u8* bytes) {      bytes[3] = stencil;  } -} // namespace Color +} // 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&      config.wall_clock_cntpct = uses_wall_clock;      // Safe optimizations -    if (Settings::values.cpu_accuracy != Settings::CPUAccuracy::Accurate) { +    if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::DebugMode) {          if (!Settings::values.cpuopt_page_tables) {              config.page_table = nullptr;          } @@ -170,6 +170,17 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable&          }      } +    // Unsafe optimizations +    if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::Unsafe) { +        config.unsafe_optimizations = true; +        if (Settings::values.cpuopt_unsafe_unfuse_fma) { +            config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA; +        } +        if (Settings::values.cpuopt_unsafe_reduce_fp_error) { +            config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP; +        } +    } +      return std::make_unique<Dynarmic::A32::Jit>(config);  } 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&      config.wall_clock_cntpct = uses_wall_clock;      // Safe optimizations -    if (Settings::values.cpu_accuracy != Settings::CPUAccuracy::Accurate) { +    if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::DebugMode) {          if (!Settings::values.cpuopt_page_tables) {              config.page_table = nullptr;          } @@ -222,6 +222,17 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable&          }      } +    // Unsafe optimizations +    if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::Unsafe) { +        config.unsafe_optimizations = true; +        if (Settings::values.cpuopt_unsafe_unfuse_fma) { +            config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA; +        } +        if (Settings::values.cpuopt_unsafe_reduce_fp_error) { +            config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP; +        } +    } +      return std::make_shared<Dynarmic::A64::Jit>(config);  } 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 @@  #include <string>  #include <tuple> -#include "common/assert.h"  #include "common/microprofile.h"  #include "core/core_timing.h"  #include "core/core_timing_util.h" +#include "core/hardware_properties.h"  namespace Core::Timing { -constexpr u64 MAX_SLICE_LENGTH = 4000; +constexpr s64 MAX_SLICE_LENGTH = 4000;  std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callback) {      return std::make_shared<EventType>(std::move(callback), std::move(name)); @@ -37,10 +37,8 @@ struct CoreTiming::Event {      }  }; -CoreTiming::CoreTiming() { -    clock = -        Common::CreateBestMatchingClock(Core::Hardware::BASE_CLOCK_RATE, Core::Hardware::CNTFREQ); -} +CoreTiming::CoreTiming() +    : clock{Common::CreateBestMatchingClock(Hardware::BASE_CLOCK_RATE, Hardware::CNTFREQ)} {}  CoreTiming::~CoreTiming() = default; @@ -136,7 +134,7 @@ void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type,  void CoreTiming::AddTicks(u64 ticks) {      this->ticks += ticks; -    downcount -= ticks; +    downcount -= static_cast<s64>(ticks);  }  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 @@  #include <limits>  #include "common/logging/log.h"  #include "common/uint128.h" +#include "core/hardware_properties.h"  namespace Core::Timing { 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 @@  #include <chrono>  #include "common/common_types.h" -#include "core/hardware_properties.h"  namespace Core::Timing { 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() {      running_mode = false;      Pause(false);      if (is_multicore) { -        for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { -            core_data[core].host_thread->join(); -            core_data[core].host_thread.reset(); +        for (auto& data : core_data) { +            data.host_thread->join(); +            data.host_thread.reset();          }      } else {          core_data[0].host_thread->join(); @@ -166,25 +166,23 @@ void CpuManager::MultiCorePause(bool paused) {          bool all_not_barrier = false;          while (!all_not_barrier) {              all_not_barrier = true; -            for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { -                all_not_barrier &= -                    !core_data[core].is_running.load() && core_data[core].initialized.load(); +            for (const auto& data : core_data) { +                all_not_barrier &= !data.is_running.load() && data.initialized.load();              }          } -        for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { -            core_data[core].enter_barrier->Set(); +        for (auto& data : core_data) { +            data.enter_barrier->Set();          }          if (paused_state.load()) {              bool all_barrier = false;              while (!all_barrier) {                  all_barrier = true; -                for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { -                    all_barrier &= -                        core_data[core].is_paused.load() && core_data[core].initialized.load(); +                for (const auto& data : core_data) { +                    all_barrier &= data.is_paused.load() && data.initialized.load();                  }              } -            for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { -                core_data[core].exit_barrier->Set(); +            for (auto& data : core_data) { +                data.exit_barrier->Set();              }          }      } else { @@ -192,9 +190,8 @@ void CpuManager::MultiCorePause(bool paused) {          bool all_barrier = false;          while (!all_barrier) {              all_barrier = true; -            for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { -                all_barrier &= -                    core_data[core].is_paused.load() && core_data[core].initialized.load(); +            for (const auto& data : core_data) { +                all_barrier &= data.is_paused.load() && data.initialized.load();              }          }          /// 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 @@  #include "core/settings.h"  namespace Core::Crypto { +namespace {  constexpr u64 CURRENT_CRYPTO_REVISION = 0x5;  constexpr u64 FULL_TICKET_SIZE = 0x400; @@ -49,7 +50,72 @@ constexpr std::array eticket_source_hashes{  };  // clang-format on -const std::map<std::pair<S128KeyType, u64>, std::string> KEYS_VARIABLE_LENGTH{ +constexpr std::array<std::pair<std::string_view, KeyIndex<S128KeyType>>, 30> s128_file_id{{ +    {"eticket_rsa_kek", {S128KeyType::ETicketRSAKek, 0, 0}}, +    {"eticket_rsa_kek_source", +     {S128KeyType::Source, static_cast<u64>(SourceKeyType::ETicketKek), 0}}, +    {"eticket_rsa_kekek_source", +     {S128KeyType::Source, static_cast<u64>(SourceKeyType::ETicketKekek), 0}}, +    {"rsa_kek_mask_0", {S128KeyType::RSAKek, static_cast<u64>(RSAKekType::Mask0), 0}}, +    {"rsa_kek_seed_3", {S128KeyType::RSAKek, static_cast<u64>(RSAKekType::Seed3), 0}}, +    {"rsa_oaep_kek_generation_source", +     {S128KeyType::Source, static_cast<u64>(SourceKeyType::RSAOaepKekGeneration), 0}}, +    {"sd_card_kek_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::SDKek), 0}}, +    {"aes_kek_generation_source", +     {S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKekGeneration), 0}}, +    {"aes_key_generation_source", +     {S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKeyGeneration), 0}}, +    {"package2_key_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::Package2), 0}}, +    {"master_key_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::Master), 0}}, +    {"header_kek_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::HeaderKek), 0}}, +    {"key_area_key_application_source", +     {S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyAreaKey), +      static_cast<u64>(KeyAreaKeyType::Application)}}, +    {"key_area_key_ocean_source", +     {S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyAreaKey), +      static_cast<u64>(KeyAreaKeyType::Ocean)}}, +    {"key_area_key_system_source", +     {S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyAreaKey), +      static_cast<u64>(KeyAreaKeyType::System)}}, +    {"titlekek_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::Titlekek), 0}}, +    {"keyblob_mac_key_source", +     {S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyblobMAC), 0}}, +    {"tsec_key", {S128KeyType::TSEC, 0, 0}}, +    {"secure_boot_key", {S128KeyType::SecureBoot, 0, 0}}, +    {"sd_seed", {S128KeyType::SDSeed, 0, 0}}, +    {"bis_key_0_crypt", {S128KeyType::BIS, 0, static_cast<u64>(BISKeyType::Crypto)}}, +    {"bis_key_0_tweak", {S128KeyType::BIS, 0, static_cast<u64>(BISKeyType::Tweak)}}, +    {"bis_key_1_crypt", {S128KeyType::BIS, 1, static_cast<u64>(BISKeyType::Crypto)}}, +    {"bis_key_1_tweak", {S128KeyType::BIS, 1, static_cast<u64>(BISKeyType::Tweak)}}, +    {"bis_key_2_crypt", {S128KeyType::BIS, 2, static_cast<u64>(BISKeyType::Crypto)}}, +    {"bis_key_2_tweak", {S128KeyType::BIS, 2, static_cast<u64>(BISKeyType::Tweak)}}, +    {"bis_key_3_crypt", {S128KeyType::BIS, 3, static_cast<u64>(BISKeyType::Crypto)}}, +    {"bis_key_3_tweak", {S128KeyType::BIS, 3, static_cast<u64>(BISKeyType::Tweak)}}, +    {"header_kek", {S128KeyType::HeaderKek, 0, 0}}, +    {"sd_card_kek", {S128KeyType::SDKek, 0, 0}}, +}}; + +auto Find128ByName(std::string_view name) { +    return std::find_if(s128_file_id.begin(), s128_file_id.end(), +                        [&name](const auto& pair) { return pair.first == name; }); +} + +constexpr std::array<std::pair<std::string_view, KeyIndex<S256KeyType>>, 6> s256_file_id{{ +    {"header_key", {S256KeyType::Header, 0, 0}}, +    {"sd_card_save_key_source", {S256KeyType::SDKeySource, static_cast<u64>(SDKeyType::Save), 0}}, +    {"sd_card_nca_key_source", {S256KeyType::SDKeySource, static_cast<u64>(SDKeyType::NCA), 0}}, +    {"header_key_source", {S256KeyType::HeaderSource, 0, 0}}, +    {"sd_card_save_key", {S256KeyType::SDKey, static_cast<u64>(SDKeyType::Save), 0}}, +    {"sd_card_nca_key", {S256KeyType::SDKey, static_cast<u64>(SDKeyType::NCA), 0}}, +}}; + +auto Find256ByName(std::string_view name) { +    return std::find_if(s256_file_id.begin(), s256_file_id.end(), +                        [&name](const auto& pair) { return pair.first == name; }); +} + +using KeyArray = std::array<std::pair<std::pair<S128KeyType, u64>, std::string_view>, 7>; +constexpr KeyArray KEYS_VARIABLE_LENGTH{{      {{S128KeyType::Master, 0}, "master_key_"},      {{S128KeyType::Package1, 0}, "package1_key_"},      {{S128KeyType::Package2, 0}, "package2_key_"}, @@ -57,14 +123,13 @@ const std::map<std::pair<S128KeyType, u64>, std::string> KEYS_VARIABLE_LENGTH{      {{S128KeyType::Source, static_cast<u64>(SourceKeyType::Keyblob)}, "keyblob_key_source_"},      {{S128KeyType::Keyblob, 0}, "keyblob_key_"},      {{S128KeyType::KeyblobMAC, 0}, "keyblob_mac_key_"}, -}; +}}; -namespace {  template <std::size_t Size>  bool IsAllZeroArray(const std::array<u8, Size>& array) {      return std::all_of(array.begin(), array.end(), [](const auto& elem) { return elem == 0; });  } -} // namespace +} // Anonymous namespace  u64 GetSignatureTypeDataSize(SignatureType type) {      switch (type) { @@ -564,13 +629,13 @@ void KeyManager::LoadFromFile(const std::string& filename, bool is_title_keys) {              s128_keys[{S128KeyType::Titlekey, rights_id[1], rights_id[0]}] = key;          } else {              out[0] = Common::ToLower(out[0]); -            if (s128_file_id.find(out[0]) != s128_file_id.end()) { -                const auto index = s128_file_id.at(out[0]); -                Key128 key = Common::HexStringToArray<16>(out[1]); +            if (const auto iter128 = Find128ByName(out[0]); iter128 != s128_file_id.end()) { +                const auto& index = iter128->second; +                const Key128 key = Common::HexStringToArray<16>(out[1]);                  s128_keys[{index.type, index.field1, index.field2}] = key; -            } else if (s256_file_id.find(out[0]) != s256_file_id.end()) { -                const auto index = s256_file_id.at(out[0]); -                Key256 key = Common::HexStringToArray<32>(out[1]); +            } else if (const auto iter256 = Find256ByName(out[0]); iter256 != s256_file_id.end()) { +                const auto& index = iter256->second; +                const Key256 key = Common::HexStringToArray<32>(out[1]);                  s256_keys[{index.type, index.field1, index.field2}] = key;              } else if (out[0].compare(0, 8, "keyblob_") == 0 &&                         out[0].compare(0, 9, "keyblob_k") != 0) { @@ -742,8 +807,7 @@ void KeyManager::SetKey(S128KeyType id, Key128 key, u64 field1, u64 field2) {      }      const auto iter2 = std::find_if( -        s128_file_id.begin(), s128_file_id.end(), -        [&id, &field1, &field2](const std::pair<std::string, KeyIndex<S128KeyType>> elem) { +        s128_file_id.begin(), s128_file_id.end(), [&id, &field1, &field2](const auto& elem) {              return std::tie(elem.second.type, elem.second.field1, elem.second.field2) ==                     std::tie(id, field1, field2);          }); @@ -753,9 +817,11 @@ void KeyManager::SetKey(S128KeyType id, Key128 key, u64 field1, u64 field2) {      // Variable cases      if (id == S128KeyType::KeyArea) { -        static constexpr std::array<const char*, 3> kak_names = {"key_area_key_application_{:02X}", -                                                                 "key_area_key_ocean_{:02X}", -                                                                 "key_area_key_system_{:02X}"}; +        static constexpr std::array<const char*, 3> kak_names = { +            "key_area_key_application_{:02X}", +            "key_area_key_ocean_{:02X}", +            "key_area_key_system_{:02X}", +        };          WriteKeyToFile(category, fmt::format(kak_names.at(field2), field1), key);      } else if (id == S128KeyType::Master) {          WriteKeyToFile(category, fmt::format("master_key_{:02X}", field1), key); @@ -781,8 +847,7 @@ void KeyManager::SetKey(S256KeyType id, Key256 key, u64 field1, u64 field2) {          return;      }      const auto iter = std::find_if( -        s256_file_id.begin(), s256_file_id.end(), -        [&id, &field1, &field2](const std::pair<std::string, KeyIndex<S256KeyType>> elem) { +        s256_file_id.begin(), s256_file_id.end(), [&id, &field1, &field2](const auto& elem) {              return std::tie(elem.second.type, elem.second.field1, elem.second.field2) ==                     std::tie(id, field1, field2);          }); @@ -1245,58 +1310,4 @@ bool KeyManager::AddTicketPersonalized(Ticket raw) {      SetKey(S128KeyType::Titlekey, key, rights_id[1], rights_id[0]);      return true;  } - -const boost::container::flat_map<std::string, KeyIndex<S128KeyType>> KeyManager::s128_file_id = { -    {"eticket_rsa_kek", {S128KeyType::ETicketRSAKek, 0, 0}}, -    {"eticket_rsa_kek_source", -     {S128KeyType::Source, static_cast<u64>(SourceKeyType::ETicketKek), 0}}, -    {"eticket_rsa_kekek_source", -     {S128KeyType::Source, static_cast<u64>(SourceKeyType::ETicketKekek), 0}}, -    {"rsa_kek_mask_0", {S128KeyType::RSAKek, static_cast<u64>(RSAKekType::Mask0), 0}}, -    {"rsa_kek_seed_3", {S128KeyType::RSAKek, static_cast<u64>(RSAKekType::Seed3), 0}}, -    {"rsa_oaep_kek_generation_source", -     {S128KeyType::Source, static_cast<u64>(SourceKeyType::RSAOaepKekGeneration), 0}}, -    {"sd_card_kek_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::SDKek), 0}}, -    {"aes_kek_generation_source", -     {S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKekGeneration), 0}}, -    {"aes_key_generation_source", -     {S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKeyGeneration), 0}}, -    {"package2_key_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::Package2), 0}}, -    {"master_key_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::Master), 0}}, -    {"header_kek_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::HeaderKek), 0}}, -    {"key_area_key_application_source", -     {S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyAreaKey), -      static_cast<u64>(KeyAreaKeyType::Application)}}, -    {"key_area_key_ocean_source", -     {S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyAreaKey), -      static_cast<u64>(KeyAreaKeyType::Ocean)}}, -    {"key_area_key_system_source", -     {S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyAreaKey), -      static_cast<u64>(KeyAreaKeyType::System)}}, -    {"titlekek_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::Titlekek), 0}}, -    {"keyblob_mac_key_source", -     {S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyblobMAC), 0}}, -    {"tsec_key", {S128KeyType::TSEC, 0, 0}}, -    {"secure_boot_key", {S128KeyType::SecureBoot, 0, 0}}, -    {"sd_seed", {S128KeyType::SDSeed, 0, 0}}, -    {"bis_key_0_crypt", {S128KeyType::BIS, 0, static_cast<u64>(BISKeyType::Crypto)}}, -    {"bis_key_0_tweak", {S128KeyType::BIS, 0, static_cast<u64>(BISKeyType::Tweak)}}, -    {"bis_key_1_crypt", {S128KeyType::BIS, 1, static_cast<u64>(BISKeyType::Crypto)}}, -    {"bis_key_1_tweak", {S128KeyType::BIS, 1, static_cast<u64>(BISKeyType::Tweak)}}, -    {"bis_key_2_crypt", {S128KeyType::BIS, 2, static_cast<u64>(BISKeyType::Crypto)}}, -    {"bis_key_2_tweak", {S128KeyType::BIS, 2, static_cast<u64>(BISKeyType::Tweak)}}, -    {"bis_key_3_crypt", {S128KeyType::BIS, 3, static_cast<u64>(BISKeyType::Crypto)}}, -    {"bis_key_3_tweak", {S128KeyType::BIS, 3, static_cast<u64>(BISKeyType::Tweak)}}, -    {"header_kek", {S128KeyType::HeaderKek, 0, 0}}, -    {"sd_card_kek", {S128KeyType::SDKek, 0, 0}}, -}; - -const boost::container::flat_map<std::string, KeyIndex<S256KeyType>> KeyManager::s256_file_id = { -    {"header_key", {S256KeyType::Header, 0, 0}}, -    {"sd_card_save_key_source", {S256KeyType::SDKeySource, static_cast<u64>(SDKeyType::Save), 0}}, -    {"sd_card_nca_key_source", {S256KeyType::SDKeySource, static_cast<u64>(SDKeyType::NCA), 0}}, -    {"header_key_source", {S256KeyType::HeaderSource, 0, 0}}, -    {"sd_card_save_key", {S256KeyType::SDKey, static_cast<u64>(SDKeyType::Save), 0}}, -    {"sd_card_nca_key", {S256KeyType::SDKey, static_cast<u64>(SDKeyType::NCA), 0}}, -};  } // 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 @@  #include <string>  #include <variant> -#include <boost/container/flat_map.hpp>  #include <fmt/format.h>  #include "common/common_funcs.h"  #include "common/common_types.h" @@ -293,9 +292,6 @@ private:      void SetKeyWrapped(S128KeyType id, Key128 key, u64 field1 = 0, u64 field2 = 0);      void SetKeyWrapped(S256KeyType id, Key256 key, u64 field1 = 0, u64 field2 = 0); - -    static const boost::container::flat_map<std::string, KeyIndex<S128KeyType>> s128_file_id; -    static const boost::container::flat_map<std::string, KeyIndex<S256KeyType>> s256_file_id;  };  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 {  VirtualFile RealVfsFilesystem::OpenFile(std::string_view path_, Mode perms) {      const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault); -    if (cache.find(path) != cache.end()) { -        auto weak = cache[path]; + +    if (const auto weak_iter = cache.find(path); weak_iter != cache.cend()) { +        const auto& weak = weak_iter->second; +          if (!weak.expired()) {              return std::shared_ptr<RealVfsFile>(new RealVfsFile(*this, weak.lock(), path, perms));          } @@ -84,7 +86,7 @@ VirtualFile RealVfsFilesystem::OpenFile(std::string_view path_, Mode perms) {      }      auto backing = std::make_shared<FS::IOFile>(path, ModeFlagsToString(perms).c_str()); -    cache[path] = backing; +    cache.insert_or_assign(path, backing);      // Cannot use make_shared as RealVfsFile constructor is private      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_  VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_view new_path_) {      const auto old_path = FS::SanitizePath(old_path_, FS::DirectorySeparator::PlatformDefault);      const auto new_path = FS::SanitizePath(new_path_, FS::DirectorySeparator::PlatformDefault); +    const auto cached_file_iter = cache.find(old_path); -    if (cache.find(old_path) != cache.end()) { -        auto file = cache[old_path].lock(); +    if (cached_file_iter != cache.cend()) { +        auto file = cached_file_iter->second.lock(); -        if (!cache[old_path].expired()) { +        if (!cached_file_iter->second.expired()) {              file->Close();          } @@ -131,7 +134,7 @@ VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_          cache.erase(old_path);          file->Open(new_path, "r+b"); -        cache[new_path] = file; +        cache.insert_or_assign(new_path, std::move(file));      } else {          UNREACHABLE();          return nullptr; @@ -142,12 +145,15 @@ VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_  bool RealVfsFilesystem::DeleteFile(std::string_view path_) {      const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault); -    if (cache.find(path) != cache.end()) { -        if (!cache[path].expired()) { -            cache[path].lock()->Close(); +    const auto cached_iter = cache.find(path); + +    if (cached_iter != cache.cend()) { +        if (!cached_iter->second.expired()) { +            cached_iter->second.lock()->Close();          }          cache.erase(path);      } +      return FS::Delete(path);  } @@ -192,21 +198,25 @@ VirtualDir RealVfsFilesystem::MoveDirectory(std::string_view old_path_,      }      for (auto& kv : cache) { -        // Path in cache starts with old_path -        if (kv.first.rfind(old_path, 0) == 0) { -            const auto file_old_path = -                FS::SanitizePath(kv.first, FS::DirectorySeparator::PlatformDefault); -            const auto file_new_path = -                FS::SanitizePath(new_path + DIR_SEP + kv.first.substr(old_path.size()), -                                 FS::DirectorySeparator::PlatformDefault); -            auto cached = cache[file_old_path]; -            if (!cached.expired()) { -                auto file = cached.lock(); -                file->Open(file_new_path, "r+b"); -                cache.erase(file_old_path); -                cache[file_new_path] = file; -            } +        // If the path in the cache doesn't start with old_path, then bail on this file. +        if (kv.first.rfind(old_path, 0) != 0) { +            continue; +        } + +        const auto file_old_path = +            FS::SanitizePath(kv.first, FS::DirectorySeparator::PlatformDefault); +        auto file_new_path = FS::SanitizePath(new_path + DIR_SEP + kv.first.substr(old_path.size()), +                                              FS::DirectorySeparator::PlatformDefault); +        const auto& cached = cache[file_old_path]; + +        if (cached.expired()) { +            continue;          } + +        auto file = cached.lock(); +        file->Open(file_new_path, "r+b"); +        cache.erase(file_old_path); +        cache.insert_or_assign(std::move(file_new_path), std::move(file));      }      return OpenDirectory(new_path, Mode::ReadWrite); @@ -214,15 +224,21 @@ VirtualDir RealVfsFilesystem::MoveDirectory(std::string_view old_path_,  bool RealVfsFilesystem::DeleteDirectory(std::string_view path_) {      const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault); +      for (auto& kv : cache) { -        // Path in cache starts with old_path -        if (kv.first.rfind(path, 0) == 0) { -            if (!cache[kv.first].expired()) { -                cache[kv.first].lock()->Close(); -            } -            cache.erase(kv.first); +        // If the path in the cache doesn't start with path, then bail on this file. +        if (kv.first.rfind(path, 0) != 0) { +            continue;          } + +        const auto& entry = cache[kv.first]; +        if (!entry.expired()) { +            entry.lock()->Close(); +        } + +        cache.erase(kv.first);      } +      return FS::DeleteDirRecursively(path);  } @@ -260,14 +276,14 @@ bool RealVfsFile::IsReadable() const {  }  std::size_t RealVfsFile::Read(u8* data, std::size_t length, std::size_t offset) const { -    if (!backing->Seek(offset, SEEK_SET)) { +    if (!backing->Seek(static_cast<s64>(offset), SEEK_SET)) {          return 0;      }      return backing->ReadBytes(data, length);  }  std::size_t RealVfsFile::Write(const u8* data, std::size_t length, std::size_t offset) { -    if (!backing->Seek(offset, SEEK_SET)) { +    if (!backing->Seek(static_cast<s64>(offset), SEEK_SET)) {          return 0;      }      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 {  enum class CPUAccuracy {      Accurate = 0, -    DebugMode = 1, +    Unsafe = 1, +    DebugMode = 2,  };  extern bool configuring_global; @@ -419,6 +420,9 @@ struct Values {      bool cpuopt_misc_ir;      bool cpuopt_reduce_misalign_checks; +    bool cpuopt_unsafe_unfuse_fma; +    bool cpuopt_unsafe_reduce_fp_error; +      // Renderer      Setting<RendererBackend> renderer_backend;      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 @@  namespace Tegra::Engines { -Fermi2D::Fermi2D(VideoCore::RasterizerInterface& rasterizer) : rasterizer{rasterizer} {} +Fermi2D::Fermi2D() = default; + +Fermi2D::~Fermi2D() = default; + +void Fermi2D::BindRasterizer(VideoCore::RasterizerInterface& rasterizer_) { +    rasterizer = &rasterizer_; +}  void Fermi2D::CallMethod(u32 method, u32 method_argument, bool is_last_call) {      ASSERT_MSG(method < Regs::NUM_REGS, @@ -87,7 +93,7 @@ void Fermi2D::HandleSurfaceCopy() {      copy_config.src_rect = src_rect;      copy_config.dst_rect = dst_rect; -    if (!rasterizer.AccelerateSurfaceCopy(regs.src, regs.dst, copy_config)) { +    if (!rasterizer->AccelerateSurfaceCopy(regs.src, regs.dst, copy_config)) {          UNIMPLEMENTED();      }  } 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 {  class Fermi2D final : public EngineInterface {  public: -    explicit Fermi2D(VideoCore::RasterizerInterface& rasterizer); -    ~Fermi2D() = default; +    explicit Fermi2D(); +    ~Fermi2D(); + +    /// Binds a rasterizer to this engine. +    void BindRasterizer(VideoCore::RasterizerInterface& rasterizer);      /// Write the value to the register identified by method.      void CallMethod(u32 method, u32 method_argument, bool is_last_call) override; @@ -149,7 +152,7 @@ public:      };  private: -    VideoCore::RasterizerInterface& rasterizer; +    VideoCore::RasterizerInterface* rasterizer;      /// Performs the copy from the source surface to the destination surface as configured in the      /// 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 @@  namespace Tegra::Engines { -KeplerCompute::KeplerCompute(Core::System& system, VideoCore::RasterizerInterface& rasterizer, -                             MemoryManager& memory_manager) -    : system{system}, rasterizer{rasterizer}, memory_manager{memory_manager}, upload_state{ -                                                                                  memory_manager, -                                                                                  regs.upload} {} +KeplerCompute::KeplerCompute(Core::System& system_, MemoryManager& memory_manager_) +    : system{system_}, memory_manager{memory_manager_}, upload_state{memory_manager, regs.upload} {}  KeplerCompute::~KeplerCompute() = default; +void KeplerCompute::BindRasterizer(VideoCore::RasterizerInterface& rasterizer_) { +    rasterizer = &rasterizer_; +} +  void KeplerCompute::CallMethod(u32 method, u32 method_argument, bool is_last_call) {      ASSERT_MSG(method < Regs::NUM_REGS,                 "Invalid KeplerCompute register, increase the size of the Regs structure"); @@ -104,11 +105,11 @@ SamplerDescriptor KeplerCompute::AccessSampler(u32 handle) const {  }  VideoCore::GuestDriverProfile& KeplerCompute::AccessGuestDriverProfile() { -    return rasterizer.AccessGuestDriverProfile(); +    return rasterizer->AccessGuestDriverProfile();  }  const VideoCore::GuestDriverProfile& KeplerCompute::AccessGuestDriverProfile() const { -    return rasterizer.AccessGuestDriverProfile(); +    return rasterizer->AccessGuestDriverProfile();  }  void KeplerCompute::ProcessLaunch() { @@ -119,7 +120,7 @@ void KeplerCompute::ProcessLaunch() {      const GPUVAddr code_addr = regs.code_loc.Address() + launch_description.program_start;      LOG_TRACE(HW_GPU, "Compute invocation launched at address 0x{:016x}", code_addr); -    rasterizer.DispatchCompute(code_addr); +    rasterizer->DispatchCompute(code_addr);  }  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 {  class KeplerCompute final : public ConstBufferEngineInterface, public EngineInterface {  public: -    explicit KeplerCompute(Core::System& system, VideoCore::RasterizerInterface& rasterizer, -                           MemoryManager& memory_manager); +    explicit KeplerCompute(Core::System& system, MemoryManager& memory_manager);      ~KeplerCompute(); +    /// Binds a rasterizer to this engine. +    void BindRasterizer(VideoCore::RasterizerInterface& rasterizer); +      static constexpr std::size_t NumConstBuffers = 8;      struct Regs { @@ -230,11 +232,6 @@ public:      const VideoCore::GuestDriverProfile& AccessGuestDriverProfile() const override;  private: -    Core::System& system; -    VideoCore::RasterizerInterface& rasterizer; -    MemoryManager& memory_manager; -    Upload::State upload_state; -      void ProcessLaunch();      /// Retrieves information about a specific TIC entry from the TIC buffer. @@ -242,6 +239,11 @@ private:      /// Retrieves information about a specific TSC entry from the TSC buffer.      Texture::TSCEntry GetTSCEntry(u32 tsc_index) const; + +    Core::System& system; +    MemoryManager& memory_manager; +    VideoCore::RasterizerInterface* rasterizer = nullptr; +    Upload::State upload_state;  };  #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;  /// First register id that is actually a Macro call.  constexpr u32 MacroRegistersStart = 0xE00; -Maxwell3D::Maxwell3D(Core::System& system, VideoCore::RasterizerInterface& rasterizer, -                     MemoryManager& memory_manager) -    : system{system}, rasterizer{rasterizer}, memory_manager{memory_manager}, -      macro_engine{GetMacroEngine(*this)}, upload_state{memory_manager, regs.upload} { +Maxwell3D::Maxwell3D(Core::System& system_, MemoryManager& memory_manager_) +    : system{system_}, memory_manager{memory_manager_}, macro_engine{GetMacroEngine(*this)}, +      upload_state{memory_manager, regs.upload} {      dirty.flags.flip();      InitializeRegisterDefaults();  } +Maxwell3D::~Maxwell3D() = default; + +void Maxwell3D::BindRasterizer(VideoCore::RasterizerInterface& rasterizer_) { +    rasterizer = &rasterizer_; +} +  void Maxwell3D::InitializeRegisterDefaults() {      // Initializes registers to their default values - what games expect them to be at boot. This is      // 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) {      switch (method) {      case MAXWELL3D_REG_INDEX(wait_for_idle): { -        rasterizer.WaitForIdle(); +        rasterizer->WaitForIdle();          break;      }      case MAXWELL3D_REG_INDEX(shadow_ram_control): { @@ -402,7 +407,7 @@ void Maxwell3D::FlushMMEInlineDraw() {      const bool is_indexed = mme_draw.current_mode == MMEDrawMode::Indexed;      if (ShouldExecute()) { -        rasterizer.Draw(is_indexed, true); +        rasterizer->Draw(is_indexed, true);      }      // TODO(bunnei): Below, we reset vertex count so that we can use these registers to determine if @@ -465,7 +470,7 @@ void Maxwell3D::ProcessQueryGet() {      switch (regs.query.query_get.operation) {      case Regs::QueryOperation::Release:          if (regs.query.query_get.fence == 1) { -            rasterizer.SignalSemaphore(regs.query.QueryAddress(), regs.query.query_sequence); +            rasterizer->SignalSemaphore(regs.query.QueryAddress(), regs.query.query_sequence);          } else {              StampQueryResult(regs.query.query_sequence, regs.query.query_get.short_query == 0);          } @@ -533,7 +538,7 @@ void Maxwell3D::ProcessQueryCondition() {  void Maxwell3D::ProcessCounterReset() {      switch (regs.counter_reset) {      case Regs::CounterReset::SampleCnt: -        rasterizer.ResetCounter(QueryType::SamplesPassed); +        rasterizer->ResetCounter(QueryType::SamplesPassed);          break;      default:          LOG_DEBUG(Render_OpenGL, "Unimplemented counter reset={}", @@ -547,7 +552,7 @@ void Maxwell3D::ProcessSyncPoint() {      const u32 increment = regs.sync_info.increment.Value();      [[maybe_unused]] const u32 cache_flush = regs.sync_info.unknown.Value();      if (increment) { -        rasterizer.SignalSyncPoint(sync_point); +        rasterizer->SignalSyncPoint(sync_point);      }  } @@ -570,7 +575,7 @@ void Maxwell3D::DrawArrays() {      const bool is_indexed{regs.index_array.count && !regs.vertex_buffer.count};      if (ShouldExecute()) { -        rasterizer.Draw(is_indexed, false); +        rasterizer->Draw(is_indexed, false);      }      // 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() {          return 0;      case Regs::QuerySelect::SamplesPassed:          // Deferred. -        rasterizer.Query(regs.query.QueryAddress(), VideoCore::QueryType::SamplesPassed, -                         system.GPU().GetTicks()); +        rasterizer->Query(regs.query.QueryAddress(), VideoCore::QueryType::SamplesPassed, +                          system.GPU().GetTicks());          return {};      default:          LOG_DEBUG(HW_GPU, "Unimplemented query select type {}", @@ -718,7 +723,7 @@ void Maxwell3D::ProcessClearBuffers() {             regs.clear_buffers.R == regs.clear_buffers.B &&             regs.clear_buffers.R == regs.clear_buffers.A); -    rasterizer.Clear(); +    rasterizer->Clear();  }  u32 Maxwell3D::AccessConstBuffer32(ShaderType stage, u64 const_buffer, u64 offset) const { @@ -752,11 +757,11 @@ SamplerDescriptor Maxwell3D::AccessSampler(u32 handle) const {  }  VideoCore::GuestDriverProfile& Maxwell3D::AccessGuestDriverProfile() { -    return rasterizer.AccessGuestDriverProfile(); +    return rasterizer->AccessGuestDriverProfile();  }  const VideoCore::GuestDriverProfile& Maxwell3D::AccessGuestDriverProfile() const { -    return rasterizer.AccessGuestDriverProfile(); +    return rasterizer->AccessGuestDriverProfile();  }  } // 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 {  class Maxwell3D final : public ConstBufferEngineInterface, public EngineInterface {  public: -    explicit Maxwell3D(Core::System& system, VideoCore::RasterizerInterface& rasterizer, -                       MemoryManager& memory_manager); -    ~Maxwell3D() = default; +    explicit Maxwell3D(Core::System& system, MemoryManager& memory_manager); +    ~Maxwell3D(); + +    /// Binds a rasterizer to this engine. +    void BindRasterizer(VideoCore::RasterizerInterface& rasterizer);      /// Register structure of the Maxwell3D engine.      /// TODO(Subv): This structure will need to be made bigger as more registers are discovered. @@ -1418,12 +1420,12 @@ public:          return execute_on;      } -    VideoCore::RasterizerInterface& GetRasterizer() { -        return rasterizer; +    VideoCore::RasterizerInterface& Rasterizer() { +        return *rasterizer;      } -    const VideoCore::RasterizerInterface& GetRasterizer() const { -        return rasterizer; +    const VideoCore::RasterizerInterface& Rasterizer() const { +        return *rasterizer;      }      /// Notify a memory write has happened. @@ -1460,11 +1462,10 @@ private:      void InitializeRegisterDefaults();      Core::System& system; - -    VideoCore::RasterizerInterface& rasterizer; -      MemoryManager& memory_manager; +    VideoCore::RasterizerInterface* rasterizer = nullptr; +      /// Start offsets of each macro in macro_memory      std::array<u32, 0x80> macro_positions = {}; 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 @@  #pragma once  #include <algorithm> -#include <array> -#include <memory>  #include <queue> -#include "common/assert.h"  #include "common/common_types.h"  #include "core/core.h" -#include "core/memory.h" -#include "core/settings.h"  #include "video_core/gpu.h"  #include "video_core/memory_manager.h"  #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 {  MICROPROFILE_DEFINE(GPU_wait, "GPU", "Wait for the GPU", MP_RGB(128, 128, 192)); -GPU::GPU(Core::System& system, std::unique_ptr<VideoCore::RendererBase>&& renderer_, bool is_async) -    : system{system}, renderer{std::move(renderer_)}, is_async{is_async} { -    auto& rasterizer{renderer->Rasterizer()}; -    memory_manager = std::make_unique<Tegra::MemoryManager>(system, rasterizer); -    dma_pusher = std::make_unique<Tegra::DmaPusher>(system, *this); -    maxwell_3d = std::make_unique<Engines::Maxwell3D>(system, rasterizer, *memory_manager); -    fermi_2d = std::make_unique<Engines::Fermi2D>(rasterizer); -    kepler_compute = std::make_unique<Engines::KeplerCompute>(system, rasterizer, *memory_manager); -    maxwell_dma = std::make_unique<Engines::MaxwellDMA>(system, *memory_manager); -    kepler_memory = std::make_unique<Engines::KeplerMemory>(system, *memory_manager); -    shader_notify = std::make_unique<VideoCore::ShaderNotify>(); -} +GPU::GPU(Core::System& system_, bool is_async_) +    : system{system_}, dma_pusher{std::make_unique<Tegra::DmaPusher>(system, *this)}, +      memory_manager{std::make_unique<Tegra::MemoryManager>(system)}, +      maxwell_3d{std::make_unique<Engines::Maxwell3D>(system, *memory_manager)}, +      fermi_2d{std::make_unique<Engines::Fermi2D>()}, +      kepler_compute{std::make_unique<Engines::KeplerCompute>(system, *memory_manager)}, +      maxwell_dma{std::make_unique<Engines::MaxwellDMA>(system, *memory_manager)}, +      kepler_memory{std::make_unique<Engines::KeplerMemory>(system, *memory_manager)}, +      shader_notify{std::make_unique<VideoCore::ShaderNotify>()}, is_async{is_async_} {}  GPU::~GPU() = default; +void GPU::BindRenderer(std::unique_ptr<VideoCore::RendererBase> renderer_) { +    renderer = std::move(renderer_); + +    VideoCore::RasterizerInterface& rasterizer = renderer->Rasterizer(); +    memory_manager->BindRasterizer(rasterizer); +    maxwell_3d->BindRasterizer(rasterizer); +    fermi_2d->BindRasterizer(rasterizer); +    kepler_compute->BindRasterizer(rasterizer); +} +  Engines::Maxwell3D& GPU::Maxwell3D() {      return *maxwell_3d;  } 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;  class GPU {  public: -    explicit GPU(Core::System& system, std::unique_ptr<VideoCore::RendererBase>&& renderer, -                 bool is_async); - -    virtual ~GPU(); -      struct MethodCall {          u32 method{};          u32 argument{}; @@ -162,6 +157,12 @@ public:                method_count(method_count) {}      }; +    explicit GPU(Core::System& system, bool is_async); +    virtual ~GPU(); + +    /// Binds a renderer to the GPU. +    void BindRenderer(std::unique_ptr<VideoCore::RendererBase> renderer); +      /// Calls a GPU method.      void CallMethod(const MethodCall& method_call); @@ -345,8 +346,8 @@ private:      bool ExecuteMethodOnEngine(u32 method);  protected: -    std::unique_ptr<Tegra::DmaPusher> dma_pusher;      Core::System& system; +    std::unique_ptr<Tegra::DmaPusher> dma_pusher;      std::unique_ptr<VideoCore::RendererBase> renderer;  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 @@  namespace VideoCommon { -GPUAsynch::GPUAsynch(Core::System& system, std::unique_ptr<VideoCore::RendererBase>&& renderer_, -                     std::unique_ptr<Core::Frontend::GraphicsContext>&& context) -    : GPU(system, std::move(renderer_), true), gpu_thread{system}, -      cpu_context(renderer->GetRenderWindow().CreateSharedContext()), -      gpu_context(std::move(context)) {} +GPUAsynch::GPUAsynch(Core::System& system) : GPU{system, true}, gpu_thread{system} {}  GPUAsynch::~GPUAsynch() = default;  void GPUAsynch::Start() { -    gpu_thread.StartThread(*renderer, *gpu_context, *dma_pusher); +    gpu_thread.StartThread(*renderer, renderer->Context(), *dma_pusher); +    cpu_context = renderer->GetRenderWindow().CreateSharedContext(); +    cpu_context->MakeCurrent();  }  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 {  /// Implementation of GPU interface that runs the GPU asynchronously  class GPUAsynch final : public Tegra::GPU {  public: -    explicit GPUAsynch(Core::System& system, std::unique_ptr<VideoCore::RendererBase>&& renderer, -                       std::unique_ptr<Core::Frontend::GraphicsContext>&& context); +    explicit GPUAsynch(Core::System& system);      ~GPUAsynch() override;      void Start() override; @@ -42,7 +41,6 @@ protected:  private:      GPUThread::ThreadManager gpu_thread;      std::unique_ptr<Core::Frontend::GraphicsContext> cpu_context; -    std::unique_ptr<Core::Frontend::GraphicsContext> gpu_context;  };  } // 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 @@  namespace VideoCommon { -GPUSynch::GPUSynch(Core::System& system, std::unique_ptr<VideoCore::RendererBase>&& renderer, -                   std::unique_ptr<Core::Frontend::GraphicsContext>&& context) -    : GPU(system, std::move(renderer), false), context{std::move(context)} {} +GPUSynch::GPUSynch(Core::System& system) : GPU{system, false} {}  GPUSynch::~GPUSynch() = default;  void GPUSynch::Start() {}  void GPUSynch::ObtainContext() { -    context->MakeCurrent(); +    renderer->Context().MakeCurrent();  }  void GPUSynch::ReleaseContext() { -    context->DoneCurrent(); +    renderer->Context().DoneCurrent();  }  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 {  /// Implementation of GPU interface that runs the GPU synchronously  class GPUSynch final : public Tegra::GPU {  public: -    explicit GPUSynch(Core::System& system, std::unique_ptr<VideoCore::RendererBase>&& renderer, -                      std::unique_ptr<Core::Frontend::GraphicsContext>&& context); +    explicit GPUSynch(Core::System& system);      ~GPUSynch() override;      void Start() override; @@ -36,9 +35,6 @@ public:  protected:      void TriggerCpuInterrupt([[maybe_unused]] u32 syncpoint_id,                               [[maybe_unused]] u32 value) const override {} - -private: -    std::unique_ptr<Core::Frontend::GraphicsContext> context;  };  } // 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>&      maxwell3d.regs.index_array.first = parameters[4];      if (maxwell3d.ShouldExecute()) { -        maxwell3d.GetRasterizer().Draw(true, true); +        maxwell3d.Rasterizer().Draw(true, true);      }      maxwell3d.regs.index_array.count = 0;      maxwell3d.mme_draw.instance_count = 0; @@ -42,7 +42,7 @@ void HLE_0D61FC9FAAC9FCAD(Engines::Maxwell3D& maxwell3d, const std::vector<u32>&      maxwell3d.mme_draw.instance_count = count;      if (maxwell3d.ShouldExecute()) { -        maxwell3d.GetRasterizer().Draw(false, true); +        maxwell3d.Rasterizer().Draw(false, true);      }      maxwell3d.regs.vertex_buffer.count = 0;      maxwell3d.mme_draw.instance_count = 0; @@ -65,7 +65,7 @@ void HLE_0217920100488FF7(Engines::Maxwell3D& maxwell3d, const std::vector<u32>&      maxwell3d.regs.draw.topology.Assign(          static_cast<Tegra::Engines::Maxwell3D::Regs::PrimitiveTopology>(parameters[0]));      if (maxwell3d.ShouldExecute()) { -        maxwell3d.GetRasterizer().Draw(true, true); +        maxwell3d.Rasterizer().Draw(true, true);      }      maxwell3d.regs.reg_array[0x446] = 0x0; // vertex id base?      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          this->parameters = std::make_unique<u32[]>(num_parameters);      }      std::memcpy(this->parameters.get(), parameters.data(), num_parameters * sizeof(u32)); -    this->num_parameters = num_parameters;      // Execute the code until we hit an exit condition.      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 @@  namespace Tegra { -MemoryManager::MemoryManager(Core::System& system, VideoCore::RasterizerInterface& rasterizer) -    : system{system}, rasterizer{rasterizer}, page_table(page_table_size) {} +MemoryManager::MemoryManager(Core::System& system_) +    : system{system_}, page_table(page_table_size) {}  MemoryManager::~MemoryManager() = default; +void MemoryManager::BindRasterizer(VideoCore::RasterizerInterface& rasterizer_) { +    rasterizer = &rasterizer_; +} +  GPUVAddr MemoryManager::UpdateRange(GPUVAddr gpu_addr, PageEntry page_entry, std::size_t size) {      u64 remaining_size{size};      for (u64 offset{}; offset < size; offset += page_size) { @@ -217,7 +221,7 @@ void MemoryManager::ReadBlock(GPUVAddr gpu_src_addr, void* dest_buffer, std::siz              // Flush must happen on the rasterizer interface, such that memory is always synchronous              // when it is read (even when in asynchronous GPU mode). Fixes Dead Cells title menu. -            rasterizer.FlushRegion(src_addr, copy_amount); +            rasterizer->FlushRegion(src_addr, copy_amount);              system.Memory().ReadBlockUnsafe(src_addr, dest_buffer, copy_amount);          } @@ -266,7 +270,7 @@ void MemoryManager::WriteBlock(GPUVAddr gpu_dest_addr, const void* src_buffer, s              // Invalidate must happen on the rasterizer interface, such that memory is always              // synchronous when it is written (even when in asynchronous GPU mode). -            rasterizer.InvalidateRegion(dest_addr, copy_amount); +            rasterizer->InvalidateRegion(dest_addr, copy_amount);              system.Memory().WriteBlockUnsafe(dest_addr, src_buffer, copy_amount);          } 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");  class MemoryManager final {  public: -    explicit MemoryManager(Core::System& system, VideoCore::RasterizerInterface& rasterizer); +    explicit MemoryManager(Core::System& system);      ~MemoryManager(); +    /// Binds a renderer to the memory manager. +    void BindRasterizer(VideoCore::RasterizerInterface& rasterizer); +      std::optional<VAddr> GpuToCpuAddress(GPUVAddr addr) const;      template <typename T> @@ -141,7 +144,7 @@ private:      Core::System& system; -    VideoCore::RasterizerInterface& rasterizer; +    VideoCore::RasterizerInterface* rasterizer = nullptr;      std::vector<PageEntry> page_table;  }; 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 @@  namespace VideoCore { -RendererBase::RendererBase(Core::Frontend::EmuWindow& window) : render_window{window} { +RendererBase::RendererBase(Core::Frontend::EmuWindow& window_, +                           std::unique_ptr<Core::Frontend::GraphicsContext> context_) +    : render_window{window_}, context{std::move(context_)} {      RefreshBaseSettings();  } 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 @@  namespace Core::Frontend {  class EmuWindow; -} +class GraphicsContext; +} // namespace Core::Frontend  namespace VideoCore { @@ -25,14 +26,15 @@ struct RendererSettings {      // Screenshot      std::atomic<bool> screenshot_requested{false}; -    void* screenshot_bits; +    void* screenshot_bits{};      std::function<void()> screenshot_complete_callback;      Layout::FramebufferLayout screenshot_framebuffer_layout;  };  class RendererBase : NonCopyable {  public: -    explicit RendererBase(Core::Frontend::EmuWindow& window); +    explicit RendererBase(Core::Frontend::EmuWindow& window, +                          std::unique_ptr<Core::Frontend::GraphicsContext> context);      virtual ~RendererBase();      /// Initialize the renderer @@ -68,6 +70,14 @@ public:          return *rasterizer;      } +    Core::Frontend::GraphicsContext& Context() { +        return *context; +    } + +    const Core::Frontend::GraphicsContext& Context() const { +        return *context; +    } +      Core::Frontend::EmuWindow& GetRenderWindow() {          return render_window;      } @@ -94,6 +104,7 @@ public:  protected:      Core::Frontend::EmuWindow& render_window; ///< Reference to the render window handle.      std::unique_ptr<RasterizerInterface> rasterizer; +    std::unique_ptr<Core::Frontend::GraphicsContext> context;      f32 m_current_fps = 0.0f; ///< Current framerate, should be set by the renderer      int m_current_frame = 0;  ///< Current frame, should be set by the renderer 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 @@  #include "common/assert.h" +#include <glad/glad.h> +  #include "video_core/renderer_opengl/gl_buffer_cache.h"  #include "video_core/renderer_opengl/gl_fence_manager.h"  namespace OpenGL { -GLInnerFence::GLInnerFence(u32 payload, bool is_stubbed) -    : VideoCommon::FenceBase(payload, is_stubbed), sync_object{} {} +GLInnerFence::GLInnerFence(u32 payload, bool is_stubbed) : FenceBase(payload, is_stubbed) {}  GLInnerFence::GLInnerFence(GPUVAddr address, u32 payload, bool is_stubbed) -    : VideoCommon::FenceBase(address, payload, is_stubbed), sync_object{} {} +    : FenceBase(address, payload, is_stubbed) {}  GLInnerFence::~GLInnerFence() = default; 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 @@  #pragma once  #include <memory> -#include <glad/glad.h>  #include "common/common_types.h"  #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      // Skip games without title id      const bool has_title_id = system.CurrentProcess()->GetTitleID() != 0;      if (!Settings::values.use_disk_shader_cache.GetValue() || !has_title_id) { -        return {}; +        return std::nullopt;      }      Common::FS::IOFile file(GetTransferablePath(), "rb");      if (!file.IsOpen()) {          LOG_INFO(Render_OpenGL, "No transferable shader cache found");          is_usable = true; -        return {}; +        return std::nullopt;      }      u32 version{};      if (file.ReadBytes(&version, sizeof(version)) != sizeof(version)) {          LOG_ERROR(Render_OpenGL, "Failed to get transferable cache version, skipping it"); -        return {}; +        return std::nullopt;      }      if (version < NativeVersion) { @@ -235,12 +235,12 @@ std::optional<std::vector<ShaderDiskCacheEntry>> ShaderDiskCacheOpenGL::LoadTran          file.Close();          InvalidateTransferable();          is_usable = true; -        return {}; +        return std::nullopt;      }      if (version > NativeVersion) {          LOG_WARNING(Render_OpenGL, "Transferable shader cache was generated with a newer version "                                     "of the emulator, skipping"); -        return {}; +        return std::nullopt;      }      // Version is valid, load the shaders @@ -249,7 +249,7 @@ std::optional<std::vector<ShaderDiskCacheEntry>> ShaderDiskCacheOpenGL::LoadTran          ShaderDiskCacheEntry& entry = entries.emplace_back();          if (!entry.Load(file)) {              LOG_ERROR(Render_OpenGL, "Failed to load transferable raw entry, skipping"); -            return {}; +            return std::nullopt;          }      } @@ -290,12 +290,12 @@ std::optional<std::vector<ShaderDiskCachePrecompiled>> ShaderDiskCacheOpenGL::Lo      ShaderCacheVersionHash file_hash{};      if (!LoadArrayFromPrecompiled(file_hash.data(), file_hash.size())) {          precompiled_cache_virtual_file_offset = 0; -        return {}; +        return std::nullopt;      }      if (GetShaderCacheVersionHash() != file_hash) {          LOG_INFO(Render_OpenGL, "Precompiled cache is from another version of the emulator");          precompiled_cache_virtual_file_offset = 0; -        return {}; +        return std::nullopt;      }      std::vector<ShaderDiskCachePrecompiled> entries; @@ -305,15 +305,16 @@ std::optional<std::vector<ShaderDiskCachePrecompiled>> ShaderDiskCacheOpenGL::Lo          if (!LoadObjectFromPrecompiled(entry.unique_identifier) ||              !LoadObjectFromPrecompiled(entry.binary_format) ||              !LoadObjectFromPrecompiled(binary_size)) { -            return {}; +            return std::nullopt;          }          entry.binary.resize(binary_size);          if (!LoadArrayFromPrecompiled(entry.binary.data(), entry.binary.size())) { -            return {}; +            return std::nullopt;          }      } -    return entries; + +    return std::move(entries);  }  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() {      LabelGLObject(GL_TEXTURE, texture.handle, GetGpuAddr(), params.TargetName());  } -void CachedSurfaceView::DecorateViewName(GPUVAddr gpu_addr, std::string prefix) { +void CachedSurfaceView::DecorateViewName(GPUVAddr gpu_addr, const std::string& prefix) {      LabelGLObject(GL_TEXTURE, main_view.handle, gpu_addr, prefix);  } 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:                        Tegra::Texture::SwizzleSource z_source,                        Tegra::Texture::SwizzleSource w_source); -    void DecorateViewName(GPUVAddr gpu_addr, std::string prefix); +    void DecorateViewName(GPUVAddr gpu_addr, const std::string& prefix);      void MarkAsModified(u64 tick) {          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:      }  }; -RendererOpenGL::RendererOpenGL(Core::Frontend::EmuWindow& emu_window, Core::System& system, -                               Core::Frontend::GraphicsContext& context) -    : RendererBase{emu_window}, emu_window{emu_window}, system{system}, context{context}, -      program_manager{device}, has_debug_tool{HasDebugTool()} {} +RendererOpenGL::RendererOpenGL(Core::System& system_, Core::Frontend::EmuWindow& emu_window_, +                               Tegra::GPU& gpu_, +                               std::unique_ptr<Core::Frontend::GraphicsContext> context_) +    : RendererBase{emu_window_, std::move(context_)}, system{system_}, +      emu_window{emu_window_}, gpu{gpu_}, program_manager{device}, has_debug_tool{HasDebugTool()} {}  RendererOpenGL::~RendererOpenGL() = default; @@ -384,7 +385,7 @@ void RendererOpenGL::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) {      if (has_debug_tool) {          glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);          Present(0); -        context.SwapBuffers(); +        context->SwapBuffers();      }  } 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;  class RendererOpenGL final : public VideoCore::RendererBase {  public: -    explicit RendererOpenGL(Core::Frontend::EmuWindow& emu_window, Core::System& system, -                            Core::Frontend::GraphicsContext& context); +    explicit RendererOpenGL(Core::System& system, Core::Frontend::EmuWindow& emu_window, +                            Tegra::GPU& gpu, +                            std::unique_ptr<Core::Frontend::GraphicsContext> context);      ~RendererOpenGL() override;      bool Init() override; @@ -93,9 +94,9 @@ private:      bool Present(int timeout_ms); -    Core::Frontend::EmuWindow& emu_window;      Core::System& system; -    Core::Frontend::GraphicsContext& context; +    Core::Frontend::EmuWindow& emu_window; +    Tegra::GPU& gpu;      const Device device;      StateTracker state_tracker{system}; @@ -120,7 +121,7 @@ private:      std::vector<u8> gl_framebuffer_data;      /// Used for transforming the framebuffer orientation -    Tegra::FramebufferConfig::TransformFlags framebuffer_transform_flags; +    Tegra::FramebufferConfig::TransformFlags framebuffer_transform_flags{};      Common::Rectangle<int> framebuffer_crop_rect;      /// 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  } // Anonymous namespace -RendererVulkan::RendererVulkan(Core::Frontend::EmuWindow& window, Core::System& system) -    : RendererBase(window), system{system} {} +RendererVulkan::RendererVulkan(Core::System& system_, Core::Frontend::EmuWindow& emu_window, +                               Tegra::GPU& gpu_, +                               std::unique_ptr<Core::Frontend::GraphicsContext> context) +    : RendererBase{emu_window, std::move(context)}, system{system_}, gpu{gpu_} {}  RendererVulkan::~RendererVulkan() {      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 {  class RendererVulkan final : public VideoCore::RendererBase {  public: -    explicit RendererVulkan(Core::Frontend::EmuWindow& window, Core::System& system); +    explicit RendererVulkan(Core::System& system, Core::Frontend::EmuWindow& emu_window, +                            Tegra::GPU& gpu, +                            std::unique_ptr<Core::Frontend::GraphicsContext> context);      ~RendererVulkan() override;      bool Init() override; @@ -58,6 +60,7 @@ private:      void Report() const;      Core::System& system; +    Tegra::GPU& gpu;      Common::DynamicLibrary library;      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 @@  // Refer to the license.txt file included.  #include <memory> +  #include "common/logging/log.h"  #include "core/core.h"  #include "core/settings.h" @@ -16,37 +17,46 @@  #include "video_core/video_core.h"  namespace { -std::unique_ptr<VideoCore::RendererBase> CreateRenderer(Core::Frontend::EmuWindow& emu_window, -                                                        Core::System& system, -                                                        Core::Frontend::GraphicsContext& context) { + +std::unique_ptr<VideoCore::RendererBase> CreateRenderer( +    Core::System& system, Core::Frontend::EmuWindow& emu_window, Tegra::GPU& gpu, +    std::unique_ptr<Core::Frontend::GraphicsContext> context) {      switch (Settings::values.renderer_backend.GetValue()) {      case Settings::RendererBackend::OpenGL: -        return std::make_unique<OpenGL::RendererOpenGL>(emu_window, system, context); +        return std::make_unique<OpenGL::RendererOpenGL>(system, emu_window, gpu, +                                                        std::move(context));  #ifdef HAS_VULKAN      case Settings::RendererBackend::Vulkan: -        return std::make_unique<Vulkan::RendererVulkan>(emu_window, system); +        return std::make_unique<Vulkan::RendererVulkan>(system, emu_window, gpu, +                                                        std::move(context));  #endif      default:          return nullptr;      }  } +  } // Anonymous namespace  namespace VideoCore {  std::unique_ptr<Tegra::GPU> CreateGPU(Core::Frontend::EmuWindow& emu_window, Core::System& system) { +    std::unique_ptr<Tegra::GPU> gpu; +    if (Settings::values.use_asynchronous_gpu_emulation.GetValue()) { +        gpu = std::make_unique<VideoCommon::GPUAsynch>(system); +    } else { +        gpu = std::make_unique<VideoCommon::GPUSynch>(system); +    } +      auto context = emu_window.CreateSharedContext();      const auto scope = context->Acquire(); -    auto renderer = CreateRenderer(emu_window, system, *context); + +    auto renderer = CreateRenderer(system, emu_window, *gpu, std::move(context));      if (!renderer->Init()) {          return nullptr;      } -    if (Settings::values.use_asynchronous_gpu_emulation.GetValue()) { -        return std::make_unique<VideoCommon::GPUAsynch>(system, std::move(renderer), -                                                        std::move(context)); -    } -    return std::make_unique<VideoCommon::GPUSynch>(system, std::move(renderer), std::move(context)); +    gpu->BindRenderer(std::move(renderer)); +    return gpu;  }  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      verify_login.h      web_backend.cpp      web_backend.h +    web_result.h  )  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 @@  #include <nlohmann/json.hpp>  #include "common/detached_tasks.h" -#include "common/web_result.h"  #include "web_service/telemetry_json.h"  #include "web_service/web_backend.h" +#include "web_service/web_result.h"  namespace WebService { @@ -125,7 +125,7 @@ bool TelemetryJson::SubmitTestcase() {      Client client(impl->host, impl->username, impl->token);      auto value = client.PostJson("/gamedb/testcase", content, false); -    return value.result_code == Common::WebResult::Code::Success; +    return value.result_code == WebResult::Code::Success;  }  } // 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 @@  // Refer to the license.txt file included.  #include <nlohmann/json.hpp> -#include "common/web_result.h"  #include "web_service/verify_login.h"  #include "web_service/web_backend.h" +#include "web_service/web_result.h"  namespace WebService { 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 @@  #include <cstdlib>  #include <mutex>  #include <string> +  #include <LUrlParser.h>  #include <fmt/format.h>  #include <httplib.h> -#include "common/common_types.h" +  #include "common/logging/log.h" -#include "common/web_result.h"  #include "web_service/web_backend.h" +#include "web_service/web_result.h"  namespace WebService { @@ -33,17 +34,16 @@ struct Client::Impl {      }      /// A generic function handles POST, GET and DELETE request together -    Common::WebResult GenericRequest(const std::string& method, const std::string& path, -                                     const std::string& data, bool allow_anonymous, -                                     const std::string& accept) { +    WebResult GenericRequest(const std::string& method, const std::string& path, +                             const std::string& data, bool allow_anonymous, +                             const std::string& accept) {          if (jwt.empty()) {              UpdateJWT();          }          if (jwt.empty() && !allow_anonymous) {              LOG_ERROR(WebService, "Credentials must be provided for authenticated requests"); -            return Common::WebResult{Common::WebResult::Code::CredentialsMissing, -                                     "Credentials needed", ""}; +            return WebResult{WebResult::Code::CredentialsMissing, "Credentials needed", ""};          }          auto result = GenericRequest(method, path, data, accept, jwt); @@ -62,10 +62,10 @@ struct Client::Impl {       * username + token is used if jwt is empty but username and token are       * not empty anonymous if all of jwt, username and token are empty       */ -    Common::WebResult GenericRequest(const std::string& method, const std::string& path, -                                     const std::string& data, const std::string& accept, -                                     const std::string& jwt = "", const std::string& username = "", -                                     const std::string& token = "") { +    WebResult GenericRequest(const std::string& method, const std::string& path, +                             const std::string& data, const std::string& accept, +                             const std::string& jwt = "", const std::string& username = "", +                             const std::string& token = "") {          if (cli == nullptr) {              auto parsedUrl = LUrlParser::clParseURL::ParseURL(host);              int port; @@ -81,12 +81,12 @@ struct Client::Impl {                  cli = std::make_unique<httplib::SSLClient>(parsedUrl.m_Host.c_str(), port);              } else {                  LOG_ERROR(WebService, "Bad URL scheme {}", parsedUrl.m_Scheme); -                return Common::WebResult{Common::WebResult::Code::InvalidURL, "Bad URL scheme", ""}; +                return WebResult{WebResult::Code::InvalidURL, "Bad URL scheme", ""};              }          }          if (cli == nullptr) {              LOG_ERROR(WebService, "Invalid URL {}", host + path); -            return Common::WebResult{Common::WebResult::Code::InvalidURL, "Invalid URL", ""}; +            return WebResult{WebResult::Code::InvalidURL, "Invalid URL", ""};          }          cli->set_timeout_sec(TIMEOUT_SECONDS); @@ -106,7 +106,7 @@ struct Client::Impl {                         std::string(API_VERSION.begin(), API_VERSION.end()));          if (method != "GET") {              params.emplace(std::string("Content-Type"), std::string("application/json")); -        }; +        }          httplib::Request request;          request.method = method; @@ -118,29 +118,28 @@ struct Client::Impl {          if (!cli->send(request, response)) {              LOG_ERROR(WebService, "{} to {} returned null", method, host + path); -            return Common::WebResult{Common::WebResult::Code::LibError, "Null response", ""}; +            return WebResult{WebResult::Code::LibError, "Null response", ""};          }          if (response.status >= 400) {              LOG_ERROR(WebService, "{} to {} returned error status code: {}", method, host + path,                        response.status); -            return Common::WebResult{Common::WebResult::Code::HttpError, -                                     std::to_string(response.status), ""}; +            return WebResult{WebResult::Code::HttpError, std::to_string(response.status), ""};          }          auto content_type = response.headers.find("content-type");          if (content_type == response.headers.end()) {              LOG_ERROR(WebService, "{} to {} returned no content", method, host + path); -            return Common::WebResult{Common::WebResult::Code::WrongContent, "", ""}; +            return WebResult{WebResult::Code::WrongContent, "", ""};          }          if (content_type->second.find(accept) == std::string::npos) {              LOG_ERROR(WebService, "{} to {} returned wrong content: {}", method, host + path,                        content_type->second); -            return Common::WebResult{Common::WebResult::Code::WrongContent, "Wrong content", ""}; +            return WebResult{WebResult::Code::WrongContent, "Wrong content", ""};          } -        return Common::WebResult{Common::WebResult::Code::Success, "", response.body}; +        return WebResult{WebResult::Code::Success, "", response.body};      }      // Retrieve a new JWT from given username and token @@ -150,7 +149,7 @@ struct Client::Impl {          }          auto result = GenericRequest("POST", "/jwt/internal", "", "text/html", "", username, token); -        if (result.result_code != Common::WebResult::Code::Success) { +        if (result.result_code != WebResult::Code::Success) {              LOG_ERROR(WebService, "UpdateJWT failed");          } else {              std::lock_guard lock{jwt_cache.mutex}; @@ -180,29 +179,28 @@ Client::Client(std::string host, std::string username, std::string token)  Client::~Client() = default; -Common::WebResult Client::PostJson(const std::string& path, const std::string& data, -                                   bool allow_anonymous) { +WebResult Client::PostJson(const std::string& path, const std::string& data, bool allow_anonymous) {      return impl->GenericRequest("POST", path, data, allow_anonymous, "application/json");  } -Common::WebResult Client::GetJson(const std::string& path, bool allow_anonymous) { +WebResult Client::GetJson(const std::string& path, bool allow_anonymous) {      return impl->GenericRequest("GET", path, "", allow_anonymous, "application/json");  } -Common::WebResult Client::DeleteJson(const std::string& path, const std::string& data, -                                     bool allow_anonymous) { +WebResult Client::DeleteJson(const std::string& path, const std::string& data, +                             bool allow_anonymous) {      return impl->GenericRequest("DELETE", path, data, allow_anonymous, "application/json");  } -Common::WebResult Client::GetPlain(const std::string& path, bool allow_anonymous) { +WebResult Client::GetPlain(const std::string& path, bool allow_anonymous) {      return impl->GenericRequest("GET", path, "", allow_anonymous, "text/plain");  } -Common::WebResult Client::GetImage(const std::string& path, bool allow_anonymous) { +WebResult Client::GetImage(const std::string& path, bool allow_anonymous) {      return impl->GenericRequest("GET", path, "", allow_anonymous, "image/png");  } -Common::WebResult Client::GetExternalJWT(const std::string& audience) { +WebResult Client::GetExternalJWT(const std::string& audience) {      return impl->GenericRequest("POST", fmt::format("/jwt/external/{}", audience), "", false,                                  "text/html");  } 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 @@  #include <memory>  #include <string> -namespace Common { -struct WebResult; -} -  namespace WebService { +struct WebResult; +  class Client {  public:      Client(std::string host, std::string username, std::string token); @@ -25,8 +23,7 @@ public:       * @param allow_anonymous If true, allow anonymous unauthenticated requests.       * @return the result of the request.       */ -    Common::WebResult PostJson(const std::string& path, const std::string& data, -                               bool allow_anonymous); +    WebResult PostJson(const std::string& path, const std::string& data, bool allow_anonymous);      /**       * Gets JSON from the specified path. @@ -34,7 +31,7 @@ public:       * @param allow_anonymous If true, allow anonymous unauthenticated requests.       * @return the result of the request.       */ -    Common::WebResult GetJson(const std::string& path, bool allow_anonymous); +    WebResult GetJson(const std::string& path, bool allow_anonymous);      /**       * Deletes JSON to the specified path. @@ -43,8 +40,7 @@ public:       * @param allow_anonymous If true, allow anonymous unauthenticated requests.       * @return the result of the request.       */ -    Common::WebResult DeleteJson(const std::string& path, const std::string& data, -                                 bool allow_anonymous); +    WebResult DeleteJson(const std::string& path, const std::string& data, bool allow_anonymous);      /**       * Gets a plain string from the specified path. @@ -52,7 +48,7 @@ public:       * @param allow_anonymous If true, allow anonymous unauthenticated requests.       * @return the result of the request.       */ -    Common::WebResult GetPlain(const std::string& path, bool allow_anonymous); +    WebResult GetPlain(const std::string& path, bool allow_anonymous);      /**       * Gets an PNG image from the specified path. @@ -60,14 +56,14 @@ public:       * @param allow_anonymous If true, allow anonymous unauthenticated requests.       * @return the result of the request.       */ -    Common::WebResult GetImage(const std::string& path, bool allow_anonymous); +    WebResult GetImage(const std::string& path, bool allow_anonymous);      /**       * Requests an external JWT for the specific audience provided.       * @param audience the audience of the JWT requested.       * @return the result of the request.       */ -    Common::WebResult GetExternalJWT(const std::string& audience); +    WebResult GetExternalJWT(const std::string& audience);  private:      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 @@  #include <string>  #include "common/common_types.h" -namespace Common { +namespace WebService {  struct WebResult {      enum class Code : u32 {          Success, @@ -22,4 +22,4 @@ struct WebResult {      std::string result_string;      std::string returned_data;  }; -} // namespace Common +} // 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() {              ReadSetting(QStringLiteral("cpuopt_misc_ir"), true).toBool();          Settings::values.cpuopt_reduce_misalign_checks =              ReadSetting(QStringLiteral("cpuopt_reduce_misalign_checks"), true).toBool(); + +        Settings::values.cpuopt_unsafe_unfuse_fma = +            ReadSetting(QStringLiteral("cpuopt_unsafe_unfuse_fma"), true).toBool(); +        Settings::values.cpuopt_unsafe_reduce_fp_error = +            ReadSetting(QStringLiteral("cpuopt_unsafe_reduce_fp_error"), true).toBool();      }      qt_config->endGroup(); @@ -1132,6 +1137,11 @@ void Config::SaveCpuValues() {          WriteSetting(QStringLiteral("cpuopt_misc_ir"), Settings::values.cpuopt_misc_ir, true);          WriteSetting(QStringLiteral("cpuopt_reduce_misalign_checks"),                       Settings::values.cpuopt_reduce_misalign_checks, true); + +        WriteSetting(QStringLiteral("cpuopt_unsafe_unfuse_fma"), +                     Settings::values.cpuopt_unsafe_unfuse_fma, true); +        WriteSetting(QStringLiteral("cpuopt_unsafe_reduce_fp_error"), +                     Settings::values.cpuopt_unsafe_reduce_fp_error, true);      }      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      connect(ui->accuracy, qOverload<int>(&QComboBox::activated), this,              &ConfigureCpu::AccuracyUpdated); +    connect(ui->accuracy, qOverload<int>(&QComboBox::currentIndexChanged), this, +            &ConfigureCpu::UpdateGroup);  }  ConfigureCpu::~ConfigureCpu() = default; @@ -28,6 +30,12 @@ void ConfigureCpu::SetConfiguration() {      ui->accuracy->setEnabled(runtime_lock);      ui->accuracy->setCurrentIndex(static_cast<int>(Settings::values.cpu_accuracy)); +    UpdateGroup(static_cast<int>(Settings::values.cpu_accuracy)); + +    ui->cpuopt_unsafe_unfuse_fma->setEnabled(runtime_lock); +    ui->cpuopt_unsafe_unfuse_fma->setChecked(Settings::values.cpuopt_unsafe_unfuse_fma); +    ui->cpuopt_unsafe_reduce_fp_error->setEnabled(runtime_lock); +    ui->cpuopt_unsafe_reduce_fp_error->setChecked(Settings::values.cpuopt_unsafe_reduce_fp_error);  }  void ConfigureCpu::AccuracyUpdated(int index) { @@ -38,14 +46,21 @@ void ConfigureCpu::AccuracyUpdated(int index) {                                                   QMessageBox::Yes | QMessageBox::No);          if (result == QMessageBox::No) {              ui->accuracy->setCurrentIndex(static_cast<int>(Settings::CPUAccuracy::Accurate)); -            return; +            UpdateGroup(static_cast<int>(Settings::CPUAccuracy::Accurate));          }      }  } +void ConfigureCpu::UpdateGroup(int index) { +    ui->unsafe_group->setVisible(static_cast<Settings::CPUAccuracy>(index) == +                                 Settings::CPUAccuracy::Unsafe); +} +  void ConfigureCpu::ApplyConfiguration() {      Settings::values.cpu_accuracy =          static_cast<Settings::CPUAccuracy>(ui->accuracy->currentIndex()); +    Settings::values.cpuopt_unsafe_unfuse_fma = ui->cpuopt_unsafe_unfuse_fma->isChecked(); +    Settings::values.cpuopt_unsafe_reduce_fp_error = ui->cpuopt_unsafe_reduce_fp_error->isChecked();  }  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:      void RetranslateUI();      void AccuracyUpdated(int index); +    void UpdateGroup(int index);      void SetConfiguration(); 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 @@              </item>              <item>               <property name="text"> +              <string>Unsafe</string> +             </property> +            </item> +            <item> +             <property name="text">                <string>Enable Debug Mode</string>               </property>              </item> @@ -63,6 +68,53 @@      </layout>     </item>     <item> +    <layout class="QVBoxLayout"> +     <item> +      <widget class="QGroupBox" name="unsafe_group"> +       <property name="title"> +        <string>Unsafe CPU Optimization Settings</string> +       </property> +       <layout class="QVBoxLayout"> +        <item> +         <widget class="QLabel"> +          <property name="wordWrap"> +            <bool>1</bool> +          </property> +          <property name="text"> +           <string>These settings reduce accuracy for speed.</string> +          </property> +         </widget> +        </item> +        <item> +         <widget class="QCheckBox" name="cpuopt_unsafe_unfuse_fma"> +          <property name="text"> +           <string>Unfuse FMA (improve performance on CPUs without FMA)</string> +          </property> +          <property name="toolTip"> +           <string> +            <div>This option improves speed by reducing accuracy of fused-multiply-add instructions on CPUs without native FMA support.</div> +           </string> +          </property> +         </widget> +        </item> +        <item> +         <widget class="QCheckBox" name="cpuopt_unsafe_reduce_fp_error"> +          <property name="text"> +           <string>Faster FRSQRTE and FRECPE</string> +          </property> +          <property name="toolTip"> +           <string> +            <div>This option improves the speed of some approximate floating-point functions by using less accurate native approximations.</div> +           </string> +          </property> +         </widget> +        </item> +       </layout> +      </widget> +     </item> +    </layout> +   </item> +   <item>      <spacer name="verticalSpacer">       <property name="orientation">        <enum>Qt::Vertical</enum> | 
