diff options
Diffstat (limited to 'src')
28 files changed, 877 insertions, 210 deletions
diff --git a/src/audio_core/renderer/command/effect/reverb.cpp b/src/audio_core/renderer/command/effect/reverb.cpp index 6fe844ff0..8b9b65214 100644 --- a/src/audio_core/renderer/command/effect/reverb.cpp +++ b/src/audio_core/renderer/command/effect/reverb.cpp | |||
| @@ -308,7 +308,8 @@ static void ApplyReverbEffect(const ReverbInfo::ParameterVersion2& params, Rever | |||
| 308 | } | 308 | } |
| 309 | 309 | ||
| 310 | Common::FixedPoint<50, 14> pre_delay_sample{ | 310 | Common::FixedPoint<50, 14> pre_delay_sample{ |
| 311 | state.pre_delay_line.Read() * Common::FixedPoint<50, 14>::from_base(params.late_gain)}; | 311 | state.pre_delay_line.TapOut(state.pre_delay_time) * |
| 312 | Common::FixedPoint<50, 14>::from_base(params.late_gain)}; | ||
| 312 | 313 | ||
| 313 | std::array<Common::FixedPoint<50, 14>, ReverbInfo::MaxDelayLines> mix_matrix{ | 314 | std::array<Common::FixedPoint<50, 14>, ReverbInfo::MaxDelayLines> mix_matrix{ |
| 314 | state.prev_feedback_output[2] + state.prev_feedback_output[1] + pre_delay_sample, | 315 | state.prev_feedback_output[2] + state.prev_feedback_output[1] + pre_delay_sample, |
diff --git a/src/audio_core/renderer/effect/i3dl2.h b/src/audio_core/renderer/effect/i3dl2.h index 1ebbc5c4c..6e3ffd1d4 100644 --- a/src/audio_core/renderer/effect/i3dl2.h +++ b/src/audio_core/renderer/effect/i3dl2.h | |||
| @@ -104,7 +104,8 @@ public: | |||
| 104 | } | 104 | } |
| 105 | 105 | ||
| 106 | void Write(const Common::FixedPoint<50, 14> sample) { | 106 | void Write(const Common::FixedPoint<50, 14> sample) { |
| 107 | *(input++) = sample; | 107 | *input = sample; |
| 108 | input++; | ||
| 108 | if (input >= buffer_end) { | 109 | if (input >= buffer_end) { |
| 109 | input = buffer.data(); | 110 | input = buffer.data(); |
| 110 | } | 111 | } |
diff --git a/src/audio_core/renderer/effect/reverb.h b/src/audio_core/renderer/effect/reverb.h index a72475c3c..6cc345ef6 100644 --- a/src/audio_core/renderer/effect/reverb.h +++ b/src/audio_core/renderer/effect/reverb.h | |||
| @@ -79,12 +79,10 @@ public: | |||
| 79 | return; | 79 | return; |
| 80 | } | 80 | } |
| 81 | sample_count = delay_time; | 81 | sample_count = delay_time; |
| 82 | input = &buffer[(output - buffer.data() + sample_count) % (sample_count_max + 1)]; | 82 | input = &buffer[0]; |
| 83 | } | 83 | } |
| 84 | 84 | ||
| 85 | Common::FixedPoint<50, 14> Tick(const Common::FixedPoint<50, 14> sample) { | 85 | Common::FixedPoint<50, 14> Tick(const Common::FixedPoint<50, 14> sample) { |
| 86 | Write(sample); | ||
| 87 | |||
| 88 | auto out_sample{Read()}; | 86 | auto out_sample{Read()}; |
| 89 | 87 | ||
| 90 | output++; | 88 | output++; |
| @@ -92,6 +90,7 @@ public: | |||
| 92 | output = buffer.data(); | 90 | output = buffer.data(); |
| 93 | } | 91 | } |
| 94 | 92 | ||
| 93 | Write(sample); | ||
| 95 | return out_sample; | 94 | return out_sample; |
| 96 | } | 95 | } |
| 97 | 96 | ||
| @@ -100,7 +99,8 @@ public: | |||
| 100 | } | 99 | } |
| 101 | 100 | ||
| 102 | void Write(const Common::FixedPoint<50, 14> sample) { | 101 | void Write(const Common::FixedPoint<50, 14> sample) { |
| 103 | *(input++) = sample; | 102 | *input = sample; |
| 103 | input++; | ||
| 104 | if (input >= buffer_end) { | 104 | if (input >= buffer_end) { |
| 105 | input = buffer.data(); | 105 | input = buffer.data(); |
| 106 | } | 106 | } |
diff --git a/src/common/settings.h b/src/common/settings.h index 512ecff69..1ae28ce93 100644 --- a/src/common/settings.h +++ b/src/common/settings.h | |||
| @@ -128,7 +128,7 @@ public: | |||
| 128 | /** | 128 | /** |
| 129 | * Sets a default value, label, and setting value. | 129 | * Sets a default value, label, and setting value. |
| 130 | * | 130 | * |
| 131 | * @param default_val Intial value of the setting, and default value of the setting | 131 | * @param default_val Initial value of the setting, and default value of the setting |
| 132 | * @param name Label for the setting | 132 | * @param name Label for the setting |
| 133 | */ | 133 | */ |
| 134 | explicit Setting(const Type& default_val, const std::string& name) | 134 | explicit Setting(const Type& default_val, const std::string& name) |
| @@ -139,7 +139,7 @@ public: | |||
| 139 | /** | 139 | /** |
| 140 | * Sets a default value, minimum value, maximum value, and label. | 140 | * Sets a default value, minimum value, maximum value, and label. |
| 141 | * | 141 | * |
| 142 | * @param default_val Intial value of the setting, and default value of the setting | 142 | * @param default_val Initial value of the setting, and default value of the setting |
| 143 | * @param min_val Sets the minimum allowed value of the setting | 143 | * @param min_val Sets the minimum allowed value of the setting |
| 144 | * @param max_val Sets the maximum allowed value of the setting | 144 | * @param max_val Sets the maximum allowed value of the setting |
| 145 | * @param name Label for the setting | 145 | * @param name Label for the setting |
| @@ -231,7 +231,7 @@ public: | |||
| 231 | /** | 231 | /** |
| 232 | * Sets a default value, label, and setting value. | 232 | * Sets a default value, label, and setting value. |
| 233 | * | 233 | * |
| 234 | * @param default_val Intial value of the setting, and default value of the setting | 234 | * @param default_val Initial value of the setting, and default value of the setting |
| 235 | * @param name Label for the setting | 235 | * @param name Label for the setting |
| 236 | */ | 236 | */ |
| 237 | explicit SwitchableSetting(const Type& default_val, const std::string& name) | 237 | explicit SwitchableSetting(const Type& default_val, const std::string& name) |
| @@ -242,7 +242,7 @@ public: | |||
| 242 | /** | 242 | /** |
| 243 | * Sets a default value, minimum value, maximum value, and label. | 243 | * Sets a default value, minimum value, maximum value, and label. |
| 244 | * | 244 | * |
| 245 | * @param default_val Intial value of the setting, and default value of the setting | 245 | * @param default_val Initial value of the setting, and default value of the setting |
| 246 | * @param min_val Sets the minimum allowed value of the setting | 246 | * @param min_val Sets the minimum allowed value of the setting |
| 247 | * @param max_val Sets the maximum allowed value of the setting | 247 | * @param max_val Sets the maximum allowed value of the setting |
| 248 | * @param name Label for the setting | 248 | * @param name Label for the setting |
diff --git a/src/core/constants.cpp b/src/core/constants.cpp index 4430173ef..760dc5f23 100644 --- a/src/core/constants.cpp +++ b/src/core/constants.cpp | |||
| @@ -4,13 +4,24 @@ | |||
| 4 | #include "core/constants.h" | 4 | #include "core/constants.h" |
| 5 | 5 | ||
| 6 | namespace Core::Constants { | 6 | namespace Core::Constants { |
| 7 | const std::array<u8, 107> ACCOUNT_BACKUP_JPEG{{ | 7 | const std::array<u8, 287> ACCOUNT_BACKUP_JPEG{{ |
| 8 | 0xff, 0xd8, 0xff, 0xdb, 0x00, 0x43, 0x00, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x02, 0x02, | 8 | 0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01, 0x01, 0x01, 0x00, 0x48, |
| 9 | 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x06, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, 0x06, 0x06, 0x05, | 9 | 0x00, 0x48, 0x00, 0x00, 0xff, 0xdb, 0x00, 0x43, 0x00, 0x06, 0x04, 0x04, 0x04, 0x05, 0x04, 0x06, |
| 10 | 0x06, 0x09, 0x08, 0x0a, 0x0a, 0x09, 0x08, 0x09, 0x09, 0x0a, 0x0c, 0x0f, 0x0c, 0x0a, 0x0b, 0x0e, | 10 | 0x05, 0x05, 0x06, 0x09, 0x06, 0x05, 0x06, 0x09, 0x0b, 0x08, 0x06, 0x06, 0x08, 0x0b, 0x0c, 0x0a, |
| 11 | 0x0b, 0x09, 0x09, 0x0d, 0x11, 0x0d, 0x0e, 0x0f, 0x10, 0x10, 0x11, 0x10, 0x0a, 0x0c, 0x12, 0x13, | 11 | 0x0a, 0x0b, 0x0a, 0x0a, 0x0c, 0x10, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x10, 0x0c, 0x0e, 0x0f, |
| 12 | 0x12, 0x10, 0x13, 0x0f, 0x10, 0x10, 0x10, 0xff, 0xc9, 0x00, 0x0b, 0x08, 0x00, 0x01, 0x00, 0x01, | 12 | 0x10, 0x0f, 0x0e, 0x0c, 0x13, 0x13, 0x14, 0x14, 0x13, 0x13, 0x1c, 0x1b, 0x1b, 0x1b, 0x1c, 0x20, |
| 13 | 0x01, 0x01, 0x11, 0x00, 0xff, 0xcc, 0x00, 0x06, 0x00, 0x10, 0x10, 0x05, 0xff, 0xda, 0x00, 0x08, | 13 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xff, 0xdb, 0x00, 0x43, 0x01, 0x07, 0x07, |
| 14 | 0x01, 0x01, 0x00, 0x00, 0x3f, 0x00, 0xd2, 0xcf, 0x20, 0xff, 0xd9, | 14 | 0x07, 0x0d, 0x0c, 0x0d, 0x18, 0x10, 0x10, 0x18, 0x1a, 0x15, 0x11, 0x15, 0x1a, 0x20, 0x20, 0x20, |
| 15 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, | ||
| 16 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, | ||
| 17 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xff, 0xc0, | ||
| 18 | 0x00, 0x11, 0x08, 0x00, 0x20, 0x00, 0x20, 0x03, 0x01, 0x22, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, | ||
| 19 | 0x01, 0xff, 0xc4, 0x00, 0x14, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 20 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xc4, 0x00, 0x14, 0x10, 0x01, 0x00, 0x00, 0x00, | ||
| 21 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xc4, 0x00, | ||
| 22 | 0x14, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 23 | 0x00, 0x00, 0x00, 0xff, 0xc4, 0x00, 0x14, 0x11, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
| 24 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, | ||
| 25 | 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xd9, | ||
| 15 | }}; | 26 | }}; |
| 16 | } | 27 | } |
diff --git a/src/core/constants.h b/src/core/constants.h index f916ce0b6..f1f67d3b8 100644 --- a/src/core/constants.h +++ b/src/core/constants.h | |||
| @@ -12,6 +12,6 @@ | |||
| 12 | namespace Core::Constants { | 12 | namespace Core::Constants { |
| 13 | 13 | ||
| 14 | // ACC Service - Blank JPEG used as user icon in absentia of real one. | 14 | // ACC Service - Blank JPEG used as user icon in absentia of real one. |
| 15 | extern const std::array<u8, 107> ACCOUNT_BACKUP_JPEG; | 15 | extern const std::array<u8, 287> ACCOUNT_BACKUP_JPEG; |
| 16 | 16 | ||
| 17 | } // namespace Core::Constants | 17 | } // namespace Core::Constants |
diff --git a/src/core/hle/kernel/k_scoped_lock.h b/src/core/hle/kernel/k_scoped_lock.h index 59b3e32ae..a15640fd2 100644 --- a/src/core/hle/kernel/k_scoped_lock.h +++ b/src/core/hle/kernel/k_scoped_lock.h | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include <concepts> | 6 | #include <concepts> |
| 7 | #include <memory> | ||
| 7 | #include <type_traits> | 8 | #include <type_traits> |
| 8 | 9 | ||
| 9 | namespace Kernel { | 10 | namespace Kernel { |
diff --git a/src/core/hle/service/psc/psc.cpp b/src/core/hle/service/psc/psc.cpp index 25702703e..cd0cc9287 100644 --- a/src/core/hle/service/psc/psc.cpp +++ b/src/core/hle/service/psc/psc.cpp | |||
| @@ -11,9 +11,9 @@ | |||
| 11 | 11 | ||
| 12 | namespace Service::PSC { | 12 | namespace Service::PSC { |
| 13 | 13 | ||
| 14 | class PSC_C final : public ServiceFramework<PSC_C> { | 14 | class IPmControl final : public ServiceFramework<IPmControl> { |
| 15 | public: | 15 | public: |
| 16 | explicit PSC_C(Core::System& system_) : ServiceFramework{system_, "psc:c"} { | 16 | explicit IPmControl(Core::System& system_) : ServiceFramework{system_, "psc:c"} { |
| 17 | // clang-format off | 17 | // clang-format off |
| 18 | static const FunctionInfo functions[] = { | 18 | static const FunctionInfo functions[] = { |
| 19 | {0, nullptr, "Initialize"}, | 19 | {0, nullptr, "Initialize"}, |
| @@ -23,8 +23,8 @@ public: | |||
| 23 | {4, nullptr, "Cancel"}, | 23 | {4, nullptr, "Cancel"}, |
| 24 | {5, nullptr, "PrintModuleInformation"}, | 24 | {5, nullptr, "PrintModuleInformation"}, |
| 25 | {6, nullptr, "GetModuleInformation"}, | 25 | {6, nullptr, "GetModuleInformation"}, |
| 26 | {10, nullptr, "Unknown10"}, | 26 | {10, nullptr, "AcquireStateLock"}, |
| 27 | {11, nullptr, "Unknown11"}, | 27 | {11, nullptr, "HasStateLock"}, |
| 28 | }; | 28 | }; |
| 29 | // clang-format on | 29 | // clang-format on |
| 30 | 30 | ||
| @@ -49,12 +49,12 @@ public: | |||
| 49 | } | 49 | } |
| 50 | }; | 50 | }; |
| 51 | 51 | ||
| 52 | class PSC_M final : public ServiceFramework<PSC_M> { | 52 | class IPmService final : public ServiceFramework<IPmService> { |
| 53 | public: | 53 | public: |
| 54 | explicit PSC_M(Core::System& system_) : ServiceFramework{system_, "psc:m"} { | 54 | explicit IPmService(Core::System& system_) : ServiceFramework{system_, "psc:m"} { |
| 55 | // clang-format off | 55 | // clang-format off |
| 56 | static const FunctionInfo functions[] = { | 56 | static const FunctionInfo functions[] = { |
| 57 | {0, &PSC_M::GetPmModule, "GetPmModule"}, | 57 | {0, &IPmService::GetPmModule, "GetPmModule"}, |
| 58 | }; | 58 | }; |
| 59 | // clang-format on | 59 | // clang-format on |
| 60 | 60 | ||
| @@ -74,8 +74,8 @@ private: | |||
| 74 | void LoopProcess(Core::System& system) { | 74 | void LoopProcess(Core::System& system) { |
| 75 | auto server_manager = std::make_unique<ServerManager>(system); | 75 | auto server_manager = std::make_unique<ServerManager>(system); |
| 76 | 76 | ||
| 77 | server_manager->RegisterNamedService("psc:c", std::make_shared<PSC_C>(system)); | 77 | server_manager->RegisterNamedService("psc:c", std::make_shared<IPmControl>(system)); |
| 78 | server_manager->RegisterNamedService("psc:m", std::make_shared<PSC_M>(system)); | 78 | server_manager->RegisterNamedService("psc:m", std::make_shared<IPmService>(system)); |
| 79 | ServerManager::RunServer(std::move(server_manager)); | 79 | ServerManager::RunServer(std::move(server_manager)); |
| 80 | } | 80 | } |
| 81 | 81 | ||
diff --git a/src/core/hle/service/ssl/ssl.cpp b/src/core/hle/service/ssl/ssl.cpp index b19bc1b3e..2b99dd7ac 100644 --- a/src/core/hle/service/ssl/ssl.cpp +++ b/src/core/hle/service/ssl/ssl.cpp | |||
| @@ -8,14 +8,36 @@ | |||
| 8 | 8 | ||
| 9 | namespace Service::SSL { | 9 | namespace Service::SSL { |
| 10 | 10 | ||
| 11 | // This is nn::ssl::sf::CertificateFormat | ||
| 11 | enum class CertificateFormat : u32 { | 12 | enum class CertificateFormat : u32 { |
| 12 | Pem = 1, | 13 | Pem = 1, |
| 13 | Der = 2, | 14 | Der = 2, |
| 14 | }; | 15 | }; |
| 15 | 16 | ||
| 17 | // This is nn::ssl::sf::ContextOption | ||
| 18 | enum class ContextOption : u32 { | ||
| 19 | None = 0, | ||
| 20 | CrlImportDateCheckEnable = 1, | ||
| 21 | }; | ||
| 22 | |||
| 23 | // This is nn::ssl::sf::SslVersion | ||
| 24 | struct SslVersion { | ||
| 25 | union { | ||
| 26 | u32 raw{}; | ||
| 27 | |||
| 28 | BitField<0, 1, u32> tls_auto; | ||
| 29 | BitField<3, 1, u32> tls_v10; | ||
| 30 | BitField<4, 1, u32> tls_v11; | ||
| 31 | BitField<5, 1, u32> tls_v12; | ||
| 32 | BitField<6, 1, u32> tls_v13; | ||
| 33 | BitField<24, 7, u32> api_version; | ||
| 34 | }; | ||
| 35 | }; | ||
| 36 | |||
| 16 | class ISslConnection final : public ServiceFramework<ISslConnection> { | 37 | class ISslConnection final : public ServiceFramework<ISslConnection> { |
| 17 | public: | 38 | public: |
| 18 | explicit ISslConnection(Core::System& system_) : ServiceFramework{system_, "ISslConnection"} { | 39 | explicit ISslConnection(Core::System& system_, SslVersion version) |
| 40 | : ServiceFramework{system_, "ISslConnection"}, ssl_version{version} { | ||
| 19 | // clang-format off | 41 | // clang-format off |
| 20 | static const FunctionInfo functions[] = { | 42 | static const FunctionInfo functions[] = { |
| 21 | {0, nullptr, "SetSocketDescriptor"}, | 43 | {0, nullptr, "SetSocketDescriptor"}, |
| @@ -59,11 +81,15 @@ public: | |||
| 59 | 81 | ||
| 60 | RegisterHandlers(functions); | 82 | RegisterHandlers(functions); |
| 61 | } | 83 | } |
| 84 | |||
| 85 | private: | ||
| 86 | SslVersion ssl_version; | ||
| 62 | }; | 87 | }; |
| 63 | 88 | ||
| 64 | class ISslContext final : public ServiceFramework<ISslContext> { | 89 | class ISslContext final : public ServiceFramework<ISslContext> { |
| 65 | public: | 90 | public: |
| 66 | explicit ISslContext(Core::System& system_) : ServiceFramework{system_, "ISslContext"} { | 91 | explicit ISslContext(Core::System& system_, SslVersion version) |
| 92 | : ServiceFramework{system_, "ISslContext"}, ssl_version{version} { | ||
| 67 | static const FunctionInfo functions[] = { | 93 | static const FunctionInfo functions[] = { |
| 68 | {0, &ISslContext::SetOption, "SetOption"}, | 94 | {0, &ISslContext::SetOption, "SetOption"}, |
| 69 | {1, nullptr, "GetOption"}, | 95 | {1, nullptr, "GetOption"}, |
| @@ -84,17 +110,20 @@ public: | |||
| 84 | } | 110 | } |
| 85 | 111 | ||
| 86 | private: | 112 | private: |
| 113 | SslVersion ssl_version; | ||
| 114 | |||
| 87 | void SetOption(HLERequestContext& ctx) { | 115 | void SetOption(HLERequestContext& ctx) { |
| 88 | struct Parameters { | 116 | struct Parameters { |
| 89 | u8 enable; | 117 | ContextOption option; |
| 90 | u32 option; | 118 | s32 value; |
| 91 | }; | 119 | }; |
| 120 | static_assert(sizeof(Parameters) == 0x8, "Parameters is an invalid size"); | ||
| 92 | 121 | ||
| 93 | IPC::RequestParser rp{ctx}; | 122 | IPC::RequestParser rp{ctx}; |
| 94 | const auto parameters = rp.PopRaw<Parameters>(); | 123 | const auto parameters = rp.PopRaw<Parameters>(); |
| 95 | 124 | ||
| 96 | LOG_WARNING(Service_SSL, "(STUBBED) called. enable={}, option={}", parameters.enable, | 125 | LOG_WARNING(Service_SSL, "(STUBBED) called. option={}, value={}", parameters.option, |
| 97 | parameters.option); | 126 | parameters.value); |
| 98 | 127 | ||
| 99 | IPC::ResponseBuilder rb{ctx, 2}; | 128 | IPC::ResponseBuilder rb{ctx, 2}; |
| 100 | rb.Push(ResultSuccess); | 129 | rb.Push(ResultSuccess); |
| @@ -105,7 +134,7 @@ private: | |||
| 105 | 134 | ||
| 106 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 135 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 107 | rb.Push(ResultSuccess); | 136 | rb.Push(ResultSuccess); |
| 108 | rb.PushIpcInterface<ISslConnection>(system); | 137 | rb.PushIpcInterface<ISslConnection>(system, ssl_version); |
| 109 | } | 138 | } |
| 110 | 139 | ||
| 111 | void ImportServerPki(HLERequestContext& ctx) { | 140 | void ImportServerPki(HLERequestContext& ctx) { |
| @@ -142,20 +171,21 @@ private: | |||
| 142 | } | 171 | } |
| 143 | }; | 172 | }; |
| 144 | 173 | ||
| 145 | class SSL final : public ServiceFramework<SSL> { | 174 | class ISslService final : public ServiceFramework<ISslService> { |
| 146 | public: | 175 | public: |
| 147 | explicit SSL(Core::System& system_) : ServiceFramework{system_, "ssl"} { | 176 | explicit ISslService(Core::System& system_) : ServiceFramework{system_, "ssl"} { |
| 148 | // clang-format off | 177 | // clang-format off |
| 149 | static const FunctionInfo functions[] = { | 178 | static const FunctionInfo functions[] = { |
| 150 | {0, &SSL::CreateContext, "CreateContext"}, | 179 | {0, &ISslService::CreateContext, "CreateContext"}, |
| 151 | {1, nullptr, "GetContextCount"}, | 180 | {1, nullptr, "GetContextCount"}, |
| 152 | {2, nullptr, "GetCertificates"}, | 181 | {2, nullptr, "GetCertificates"}, |
| 153 | {3, nullptr, "GetCertificateBufSize"}, | 182 | {3, nullptr, "GetCertificateBufSize"}, |
| 154 | {4, nullptr, "DebugIoctl"}, | 183 | {4, nullptr, "DebugIoctl"}, |
| 155 | {5, &SSL::SetInterfaceVersion, "SetInterfaceVersion"}, | 184 | {5, &ISslService::SetInterfaceVersion, "SetInterfaceVersion"}, |
| 156 | {6, nullptr, "FlushSessionCache"}, | 185 | {6, nullptr, "FlushSessionCache"}, |
| 157 | {7, nullptr, "SetDebugOption"}, | 186 | {7, nullptr, "SetDebugOption"}, |
| 158 | {8, nullptr, "GetDebugOption"}, | 187 | {8, nullptr, "GetDebugOption"}, |
| 188 | {8, nullptr, "ClearTls12FallbackFlag"}, | ||
| 159 | }; | 189 | }; |
| 160 | // clang-format on | 190 | // clang-format on |
| 161 | 191 | ||
| @@ -163,20 +193,30 @@ public: | |||
| 163 | } | 193 | } |
| 164 | 194 | ||
| 165 | private: | 195 | private: |
| 166 | u32 ssl_version{}; | ||
| 167 | void CreateContext(HLERequestContext& ctx) { | 196 | void CreateContext(HLERequestContext& ctx) { |
| 168 | LOG_WARNING(Service_SSL, "(STUBBED) called"); | 197 | struct Parameters { |
| 198 | SslVersion ssl_version; | ||
| 199 | INSERT_PADDING_BYTES(0x4); | ||
| 200 | u64 pid_placeholder; | ||
| 201 | }; | ||
| 202 | static_assert(sizeof(Parameters) == 0x10, "Parameters is an invalid size"); | ||
| 203 | |||
| 204 | IPC::RequestParser rp{ctx}; | ||
| 205 | const auto parameters = rp.PopRaw<Parameters>(); | ||
| 206 | |||
| 207 | LOG_WARNING(Service_SSL, "(STUBBED) called, api_version={}, pid_placeholder={}", | ||
| 208 | parameters.ssl_version.api_version, parameters.pid_placeholder); | ||
| 169 | 209 | ||
| 170 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 210 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 171 | rb.Push(ResultSuccess); | 211 | rb.Push(ResultSuccess); |
| 172 | rb.PushIpcInterface<ISslContext>(system); | 212 | rb.PushIpcInterface<ISslContext>(system, parameters.ssl_version); |
| 173 | } | 213 | } |
| 174 | 214 | ||
| 175 | void SetInterfaceVersion(HLERequestContext& ctx) { | 215 | void SetInterfaceVersion(HLERequestContext& ctx) { |
| 176 | LOG_DEBUG(Service_SSL, "called"); | ||
| 177 | |||
| 178 | IPC::RequestParser rp{ctx}; | 216 | IPC::RequestParser rp{ctx}; |
| 179 | ssl_version = rp.Pop<u32>(); | 217 | u32 ssl_version = rp.Pop<u32>(); |
| 218 | |||
| 219 | LOG_DEBUG(Service_SSL, "called, ssl_version={}", ssl_version); | ||
| 180 | 220 | ||
| 181 | IPC::ResponseBuilder rb{ctx, 2}; | 221 | IPC::ResponseBuilder rb{ctx, 2}; |
| 182 | rb.Push(ResultSuccess); | 222 | rb.Push(ResultSuccess); |
| @@ -186,7 +226,7 @@ private: | |||
| 186 | void LoopProcess(Core::System& system) { | 226 | void LoopProcess(Core::System& system) { |
| 187 | auto server_manager = std::make_unique<ServerManager>(system); | 227 | auto server_manager = std::make_unique<ServerManager>(system); |
| 188 | 228 | ||
| 189 | server_manager->RegisterNamedService("ssl", std::make_shared<SSL>(system)); | 229 | server_manager->RegisterNamedService("ssl", std::make_shared<ISslService>(system)); |
| 190 | ServerManager::RunServer(std::move(server_manager)); | 230 | ServerManager::RunServer(std::move(server_manager)); |
| 191 | } | 231 | } |
| 192 | 232 | ||
diff --git a/src/core/hle/service/usb/usb.cpp b/src/core/hle/service/usb/usb.cpp index a2855e783..f29fff1dd 100644 --- a/src/core/hle/service/usb/usb.cpp +++ b/src/core/hle/service/usb/usb.cpp | |||
| @@ -16,19 +16,19 @@ public: | |||
| 16 | explicit IDsInterface(Core::System& system_) : ServiceFramework{system_, "IDsInterface"} { | 16 | explicit IDsInterface(Core::System& system_) : ServiceFramework{system_, "IDsInterface"} { |
| 17 | // clang-format off | 17 | // clang-format off |
| 18 | static const FunctionInfo functions[] = { | 18 | static const FunctionInfo functions[] = { |
| 19 | {0, nullptr, "BindDevice"}, | 19 | {0, nullptr, "AddEndpoint"}, |
| 20 | {1, nullptr, "BindClientProcess"}, | 20 | {1, nullptr, "GetSetupEvent"}, |
| 21 | {2, nullptr, "AddInterface"}, | 21 | {2, nullptr, "GetSetupPacket"}, |
| 22 | {3, nullptr, "GetStateChangeEvent"}, | 22 | {3, nullptr, "Enable"}, |
| 23 | {4, nullptr, "GetState"}, | 23 | {4, nullptr, "Disable"}, |
| 24 | {5, nullptr, "ClearDeviceData"}, | 24 | {5, nullptr, "CtrlIn"}, |
| 25 | {6, nullptr, "AddUsbStringDescriptor"}, | 25 | {6, nullptr, "CtrlOut"}, |
| 26 | {7, nullptr, "DeleteUsbStringDescriptor"}, | 26 | {7, nullptr, "GetCtrlInCompletionEvent"}, |
| 27 | {8, nullptr, "SetUsbDeviceDescriptor"}, | 27 | {8, nullptr, "GetCtrlInUrbReport"}, |
| 28 | {9, nullptr, "SetBinaryObjectStore"}, | 28 | {9, nullptr, "GetCtrlOutCompletionEvent"}, |
| 29 | {10, nullptr, "Enable"}, | 29 | {10, nullptr, "GetCtrlOutUrbReport"}, |
| 30 | {11, nullptr, "Disable"}, | 30 | {11, nullptr, "CtrlStall"}, |
| 31 | {12, nullptr, "Unknown12"}, | 31 | {12, nullptr, "AppendConfigurationData"}, |
| 32 | }; | 32 | }; |
| 33 | // clang-format on | 33 | // clang-format on |
| 34 | 34 | ||
| @@ -36,9 +36,9 @@ public: | |||
| 36 | } | 36 | } |
| 37 | }; | 37 | }; |
| 38 | 38 | ||
| 39 | class USB_DS final : public ServiceFramework<USB_DS> { | 39 | class IDsRootSession final : public ServiceFramework<IDsRootSession> { |
| 40 | public: | 40 | public: |
| 41 | explicit USB_DS(Core::System& system_) : ServiceFramework{system_, "usb:ds"} { | 41 | explicit IDsRootSession(Core::System& system_) : ServiceFramework{system_, "usb:ds"} { |
| 42 | // clang-format off | 42 | // clang-format off |
| 43 | static const FunctionInfo functions[] = { | 43 | static const FunctionInfo functions[] = { |
| 44 | {0, nullptr, "OpenDsService"}, | 44 | {0, nullptr, "OpenDsService"}, |
| @@ -94,9 +94,9 @@ public: | |||
| 94 | } | 94 | } |
| 95 | }; | 95 | }; |
| 96 | 96 | ||
| 97 | class USB_HS final : public ServiceFramework<USB_HS> { | 97 | class IClientRootSession final : public ServiceFramework<IClientRootSession> { |
| 98 | public: | 98 | public: |
| 99 | explicit USB_HS(Core::System& system_) : ServiceFramework{system_, "usb:hs"} { | 99 | explicit IClientRootSession(Core::System& system_) : ServiceFramework{system_, "usb:hs"} { |
| 100 | // clang-format off | 100 | // clang-format off |
| 101 | static const FunctionInfo functions[] = { | 101 | static const FunctionInfo functions[] = { |
| 102 | {0, nullptr, "BindClientProcess"}, | 102 | {0, nullptr, "BindClientProcess"}, |
| @@ -107,7 +107,7 @@ public: | |||
| 107 | {5, nullptr, "DestroyInterfaceAvailableEvent"}, | 107 | {5, nullptr, "DestroyInterfaceAvailableEvent"}, |
| 108 | {6, nullptr, "GetInterfaceStateChangeEvent"}, | 108 | {6, nullptr, "GetInterfaceStateChangeEvent"}, |
| 109 | {7, nullptr, "AcquireUsbIf"}, | 109 | {7, nullptr, "AcquireUsbIf"}, |
| 110 | {8, nullptr, "ResetDevice"}, | 110 | {8, nullptr, "SetTestMode"}, |
| 111 | }; | 111 | }; |
| 112 | // clang-format on | 112 | // clang-format on |
| 113 | 113 | ||
| @@ -134,12 +134,12 @@ public: | |||
| 134 | } | 134 | } |
| 135 | }; | 135 | }; |
| 136 | 136 | ||
| 137 | class USB_PD final : public ServiceFramework<USB_PD> { | 137 | class IPdManager final : public ServiceFramework<IPdManager> { |
| 138 | public: | 138 | public: |
| 139 | explicit USB_PD(Core::System& system_) : ServiceFramework{system_, "usb:pd"} { | 139 | explicit IPdManager(Core::System& system_) : ServiceFramework{system_, "usb:pd"} { |
| 140 | // clang-format off | 140 | // clang-format off |
| 141 | static const FunctionInfo functions[] = { | 141 | static const FunctionInfo functions[] = { |
| 142 | {0, &USB_PD::GetPdSession, "GetPdSession"}, | 142 | {0, &IPdManager::OpenSession, "OpenSession"}, |
| 143 | }; | 143 | }; |
| 144 | // clang-format on | 144 | // clang-format on |
| 145 | 145 | ||
| @@ -147,7 +147,7 @@ public: | |||
| 147 | } | 147 | } |
| 148 | 148 | ||
| 149 | private: | 149 | private: |
| 150 | void GetPdSession(HLERequestContext& ctx) { | 150 | void OpenSession(HLERequestContext& ctx) { |
| 151 | LOG_DEBUG(Service_USB, "called"); | 151 | LOG_DEBUG(Service_USB, "called"); |
| 152 | 152 | ||
| 153 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 153 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| @@ -178,12 +178,12 @@ public: | |||
| 178 | } | 178 | } |
| 179 | }; | 179 | }; |
| 180 | 180 | ||
| 181 | class USB_PD_C final : public ServiceFramework<USB_PD_C> { | 181 | class IPdCradleManager final : public ServiceFramework<IPdCradleManager> { |
| 182 | public: | 182 | public: |
| 183 | explicit USB_PD_C(Core::System& system_) : ServiceFramework{system_, "usb:pd:c"} { | 183 | explicit IPdCradleManager(Core::System& system_) : ServiceFramework{system_, "usb:pd:c"} { |
| 184 | // clang-format off | 184 | // clang-format off |
| 185 | static const FunctionInfo functions[] = { | 185 | static const FunctionInfo functions[] = { |
| 186 | {0, &USB_PD_C::GetPdCradleSession, "GetPdCradleSession"}, | 186 | {0, &IPdCradleManager::OpenCradleSession, "OpenCradleSession"}, |
| 187 | }; | 187 | }; |
| 188 | // clang-format on | 188 | // clang-format on |
| 189 | 189 | ||
| @@ -191,18 +191,18 @@ public: | |||
| 191 | } | 191 | } |
| 192 | 192 | ||
| 193 | private: | 193 | private: |
| 194 | void GetPdCradleSession(HLERequestContext& ctx) { | 194 | void OpenCradleSession(HLERequestContext& ctx) { |
| 195 | LOG_DEBUG(Service_USB, "called"); | ||
| 196 | |||
| 195 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 197 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 196 | rb.Push(ResultSuccess); | 198 | rb.Push(ResultSuccess); |
| 197 | rb.PushIpcInterface<IPdCradleSession>(system); | 199 | rb.PushIpcInterface<IPdCradleSession>(system); |
| 198 | |||
| 199 | LOG_DEBUG(Service_USB, "called"); | ||
| 200 | } | 200 | } |
| 201 | }; | 201 | }; |
| 202 | 202 | ||
| 203 | class USB_PM final : public ServiceFramework<USB_PM> { | 203 | class IPmMainService final : public ServiceFramework<IPmMainService> { |
| 204 | public: | 204 | public: |
| 205 | explicit USB_PM(Core::System& system_) : ServiceFramework{system_, "usb:pm"} { | 205 | explicit IPmMainService(Core::System& system_) : ServiceFramework{system_, "usb:pm"} { |
| 206 | // clang-format off | 206 | // clang-format off |
| 207 | static const FunctionInfo functions[] = { | 207 | static const FunctionInfo functions[] = { |
| 208 | {0, nullptr, "GetPowerEvent"}, | 208 | {0, nullptr, "GetPowerEvent"}, |
| @@ -221,11 +221,11 @@ public: | |||
| 221 | void LoopProcess(Core::System& system) { | 221 | void LoopProcess(Core::System& system) { |
| 222 | auto server_manager = std::make_unique<ServerManager>(system); | 222 | auto server_manager = std::make_unique<ServerManager>(system); |
| 223 | 223 | ||
| 224 | server_manager->RegisterNamedService("usb:ds", std::make_shared<USB_DS>(system)); | 224 | server_manager->RegisterNamedService("usb:ds", std::make_shared<IDsRootSession>(system)); |
| 225 | server_manager->RegisterNamedService("usb:hs", std::make_shared<USB_HS>(system)); | 225 | server_manager->RegisterNamedService("usb:hs", std::make_shared<IClientRootSession>(system)); |
| 226 | server_manager->RegisterNamedService("usb:pd", std::make_shared<USB_PD>(system)); | 226 | server_manager->RegisterNamedService("usb:pd", std::make_shared<IPdManager>(system)); |
| 227 | server_manager->RegisterNamedService("usb:pd:c", std::make_shared<USB_PD_C>(system)); | 227 | server_manager->RegisterNamedService("usb:pd:c", std::make_shared<IPdCradleManager>(system)); |
| 228 | server_manager->RegisterNamedService("usb:pm", std::make_shared<USB_PM>(system)); | 228 | server_manager->RegisterNamedService("usb:pm", std::make_shared<IPmMainService>(system)); |
| 229 | ServerManager::RunServer(std::move(server_manager)); | 229 | ServerManager::RunServer(std::move(server_manager)); |
| 230 | } | 230 | } |
| 231 | 231 | ||
diff --git a/src/input_common/helpers/joycon_protocol/joycon_types.h b/src/input_common/helpers/joycon_protocol/joycon_types.h index b91934990..2e50a99a8 100644 --- a/src/input_common/helpers/joycon_protocol/joycon_types.h +++ b/src/input_common/helpers/joycon_protocol/joycon_types.h | |||
| @@ -95,6 +95,18 @@ enum class PasivePadButton : u32 { | |||
| 95 | ZL_ZR = 0x8000, | 95 | ZL_ZR = 0x8000, |
| 96 | }; | 96 | }; |
| 97 | 97 | ||
| 98 | enum class PasivePadStick : u8 { | ||
| 99 | Right = 0x00, | ||
| 100 | RightDown = 0x01, | ||
| 101 | Down = 0x02, | ||
| 102 | DownLeft = 0x03, | ||
| 103 | Left = 0x04, | ||
| 104 | LeftUp = 0x05, | ||
| 105 | Up = 0x06, | ||
| 106 | UpRight = 0x07, | ||
| 107 | Neutral = 0x08, | ||
| 108 | }; | ||
| 109 | |||
| 98 | enum class OutputReport : u8 { | 110 | enum class OutputReport : u8 { |
| 99 | RUMBLE_AND_SUBCMD = 0x01, | 111 | RUMBLE_AND_SUBCMD = 0x01, |
| 100 | FW_UPDATE_PKT = 0x03, | 112 | FW_UPDATE_PKT = 0x03, |
diff --git a/src/input_common/helpers/joycon_protocol/poller.cpp b/src/input_common/helpers/joycon_protocol/poller.cpp index 9bb15e935..ab48352b8 100644 --- a/src/input_common/helpers/joycon_protocol/poller.cpp +++ b/src/input_common/helpers/joycon_protocol/poller.cpp | |||
| @@ -12,7 +12,7 @@ JoyconPoller::JoyconPoller(ControllerType device_type_, JoyStickCalibration left | |||
| 12 | : device_type{device_type_}, left_stick_calibration{left_stick_calibration_}, | 12 | : device_type{device_type_}, left_stick_calibration{left_stick_calibration_}, |
| 13 | right_stick_calibration{right_stick_calibration_}, motion_calibration{motion_calibration_} {} | 13 | right_stick_calibration{right_stick_calibration_}, motion_calibration{motion_calibration_} {} |
| 14 | 14 | ||
| 15 | void JoyconPoller::SetCallbacks(const Joycon::JoyconCallbacks& callbacks_) { | 15 | void JoyconPoller::SetCallbacks(const JoyconCallbacks& callbacks_) { |
| 16 | callbacks = std::move(callbacks_); | 16 | callbacks = std::move(callbacks_); |
| 17 | } | 17 | } |
| 18 | 18 | ||
| @@ -22,13 +22,13 @@ void JoyconPoller::ReadActiveMode(std::span<u8> buffer, const MotionStatus& moti | |||
| 22 | memcpy(&data, buffer.data(), sizeof(InputReportActive)); | 22 | memcpy(&data, buffer.data(), sizeof(InputReportActive)); |
| 23 | 23 | ||
| 24 | switch (device_type) { | 24 | switch (device_type) { |
| 25 | case Joycon::ControllerType::Left: | 25 | case ControllerType::Left: |
| 26 | UpdateActiveLeftPadInput(data, motion_status); | 26 | UpdateActiveLeftPadInput(data, motion_status); |
| 27 | break; | 27 | break; |
| 28 | case Joycon::ControllerType::Right: | 28 | case ControllerType::Right: |
| 29 | UpdateActiveRightPadInput(data, motion_status); | 29 | UpdateActiveRightPadInput(data, motion_status); |
| 30 | break; | 30 | break; |
| 31 | case Joycon::ControllerType::Pro: | 31 | case ControllerType::Pro: |
| 32 | UpdateActiveProPadInput(data, motion_status); | 32 | UpdateActiveProPadInput(data, motion_status); |
| 33 | break; | 33 | break; |
| 34 | default: | 34 | default: |
| @@ -47,13 +47,13 @@ void JoyconPoller::ReadPassiveMode(std::span<u8> buffer) { | |||
| 47 | memcpy(&data, buffer.data(), sizeof(InputReportPassive)); | 47 | memcpy(&data, buffer.data(), sizeof(InputReportPassive)); |
| 48 | 48 | ||
| 49 | switch (device_type) { | 49 | switch (device_type) { |
| 50 | case Joycon::ControllerType::Left: | 50 | case ControllerType::Left: |
| 51 | UpdatePasiveLeftPadInput(data); | 51 | UpdatePasiveLeftPadInput(data); |
| 52 | break; | 52 | break; |
| 53 | case Joycon::ControllerType::Right: | 53 | case ControllerType::Right: |
| 54 | UpdatePasiveRightPadInput(data); | 54 | UpdatePasiveRightPadInput(data); |
| 55 | break; | 55 | break; |
| 56 | case Joycon::ControllerType::Pro: | 56 | case ControllerType::Pro: |
| 57 | UpdatePasiveProPadInput(data); | 57 | UpdatePasiveProPadInput(data); |
| 58 | break; | 58 | break; |
| 59 | default: | 59 | default: |
| @@ -211,13 +211,11 @@ void JoyconPoller::UpdateActiveProPadInput(const InputReportActive& input, | |||
| 211 | } | 211 | } |
| 212 | 212 | ||
| 213 | void JoyconPoller::UpdatePasiveLeftPadInput(const InputReportPassive& input) { | 213 | void JoyconPoller::UpdatePasiveLeftPadInput(const InputReportPassive& input) { |
| 214 | static constexpr std::array<Joycon::PasivePadButton, 11> left_buttons{ | 214 | static constexpr std::array<PasivePadButton, 11> left_buttons{ |
| 215 | Joycon::PasivePadButton::Down_A, Joycon::PasivePadButton::Right_X, | 215 | PasivePadButton::Down_A, PasivePadButton::Right_X, PasivePadButton::Left_B, |
| 216 | Joycon::PasivePadButton::Left_B, Joycon::PasivePadButton::Up_Y, | 216 | PasivePadButton::Up_Y, PasivePadButton::SL, PasivePadButton::SR, |
| 217 | Joycon::PasivePadButton::SL, Joycon::PasivePadButton::SR, | 217 | PasivePadButton::L_R, PasivePadButton::ZL_ZR, PasivePadButton::Minus, |
| 218 | Joycon::PasivePadButton::L_R, Joycon::PasivePadButton::ZL_ZR, | 218 | PasivePadButton::Capture, PasivePadButton::StickL, |
| 219 | Joycon::PasivePadButton::Minus, Joycon::PasivePadButton::Capture, | ||
| 220 | Joycon::PasivePadButton::StickL, | ||
| 221 | }; | 219 | }; |
| 222 | 220 | ||
| 223 | for (auto left_button : left_buttons) { | 221 | for (auto left_button : left_buttons) { |
| @@ -225,16 +223,19 @@ void JoyconPoller::UpdatePasiveLeftPadInput(const InputReportPassive& input) { | |||
| 225 | const int button = static_cast<int>(left_button); | 223 | const int button = static_cast<int>(left_button); |
| 226 | callbacks.on_button_data(button, button_status); | 224 | callbacks.on_button_data(button, button_status); |
| 227 | } | 225 | } |
| 226 | |||
| 227 | const auto [left_axis_x, left_axis_y] = | ||
| 228 | GetPassiveAxisValue(static_cast<PasivePadStick>(input.stick_state)); | ||
| 229 | callbacks.on_stick_data(static_cast<int>(PadAxes::LeftStickX), left_axis_x); | ||
| 230 | callbacks.on_stick_data(static_cast<int>(PadAxes::LeftStickY), left_axis_y); | ||
| 228 | } | 231 | } |
| 229 | 232 | ||
| 230 | void JoyconPoller::UpdatePasiveRightPadInput(const InputReportPassive& input) { | 233 | void JoyconPoller::UpdatePasiveRightPadInput(const InputReportPassive& input) { |
| 231 | static constexpr std::array<Joycon::PasivePadButton, 11> right_buttons{ | 234 | static constexpr std::array<PasivePadButton, 11> right_buttons{ |
| 232 | Joycon::PasivePadButton::Down_A, Joycon::PasivePadButton::Right_X, | 235 | PasivePadButton::Down_A, PasivePadButton::Right_X, PasivePadButton::Left_B, |
| 233 | Joycon::PasivePadButton::Left_B, Joycon::PasivePadButton::Up_Y, | 236 | PasivePadButton::Up_Y, PasivePadButton::SL, PasivePadButton::SR, |
| 234 | Joycon::PasivePadButton::SL, Joycon::PasivePadButton::SR, | 237 | PasivePadButton::L_R, PasivePadButton::ZL_ZR, PasivePadButton::Plus, |
| 235 | Joycon::PasivePadButton::L_R, Joycon::PasivePadButton::ZL_ZR, | 238 | PasivePadButton::Home, PasivePadButton::StickR, |
| 236 | Joycon::PasivePadButton::Plus, Joycon::PasivePadButton::Home, | ||
| 237 | Joycon::PasivePadButton::StickR, | ||
| 238 | }; | 239 | }; |
| 239 | 240 | ||
| 240 | for (auto right_button : right_buttons) { | 241 | for (auto right_button : right_buttons) { |
| @@ -242,17 +243,20 @@ void JoyconPoller::UpdatePasiveRightPadInput(const InputReportPassive& input) { | |||
| 242 | const int button = static_cast<int>(right_button); | 243 | const int button = static_cast<int>(right_button); |
| 243 | callbacks.on_button_data(button, button_status); | 244 | callbacks.on_button_data(button, button_status); |
| 244 | } | 245 | } |
| 246 | |||
| 247 | const auto [right_axis_x, right_axis_y] = | ||
| 248 | GetPassiveAxisValue(static_cast<PasivePadStick>(input.stick_state)); | ||
| 249 | callbacks.on_stick_data(static_cast<int>(PadAxes::RightStickX), right_axis_x); | ||
| 250 | callbacks.on_stick_data(static_cast<int>(PadAxes::RightStickY), right_axis_y); | ||
| 245 | } | 251 | } |
| 246 | 252 | ||
| 247 | void JoyconPoller::UpdatePasiveProPadInput(const InputReportPassive& input) { | 253 | void JoyconPoller::UpdatePasiveProPadInput(const InputReportPassive& input) { |
| 248 | static constexpr std::array<Joycon::PasivePadButton, 14> pro_buttons{ | 254 | static constexpr std::array<PasivePadButton, 14> pro_buttons{ |
| 249 | Joycon::PasivePadButton::Down_A, Joycon::PasivePadButton::Right_X, | 255 | PasivePadButton::Down_A, PasivePadButton::Right_X, PasivePadButton::Left_B, |
| 250 | Joycon::PasivePadButton::Left_B, Joycon::PasivePadButton::Up_Y, | 256 | PasivePadButton::Up_Y, PasivePadButton::SL, PasivePadButton::SR, |
| 251 | Joycon::PasivePadButton::SL, Joycon::PasivePadButton::SR, | 257 | PasivePadButton::L_R, PasivePadButton::ZL_ZR, PasivePadButton::Minus, |
| 252 | Joycon::PasivePadButton::L_R, Joycon::PasivePadButton::ZL_ZR, | 258 | PasivePadButton::Plus, PasivePadButton::Capture, PasivePadButton::Home, |
| 253 | Joycon::PasivePadButton::Minus, Joycon::PasivePadButton::Plus, | 259 | PasivePadButton::StickL, PasivePadButton::StickR, |
| 254 | Joycon::PasivePadButton::Capture, Joycon::PasivePadButton::Home, | ||
| 255 | Joycon::PasivePadButton::StickL, Joycon::PasivePadButton::StickR, | ||
| 256 | }; | 260 | }; |
| 257 | 261 | ||
| 258 | for (auto pro_button : pro_buttons) { | 262 | for (auto pro_button : pro_buttons) { |
| @@ -260,6 +264,15 @@ void JoyconPoller::UpdatePasiveProPadInput(const InputReportPassive& input) { | |||
| 260 | const int button = static_cast<int>(pro_button); | 264 | const int button = static_cast<int>(pro_button); |
| 261 | callbacks.on_button_data(button, button_status); | 265 | callbacks.on_button_data(button, button_status); |
| 262 | } | 266 | } |
| 267 | |||
| 268 | const auto [left_axis_x, left_axis_y] = | ||
| 269 | GetPassiveAxisValue(static_cast<PasivePadStick>(input.stick_state && 0xf)); | ||
| 270 | const auto [right_axis_x, right_axis_y] = | ||
| 271 | GetPassiveAxisValue(static_cast<PasivePadStick>(input.stick_state >> 4)); | ||
| 272 | callbacks.on_stick_data(static_cast<int>(PadAxes::LeftStickX), left_axis_x); | ||
| 273 | callbacks.on_stick_data(static_cast<int>(PadAxes::LeftStickY), left_axis_y); | ||
| 274 | callbacks.on_stick_data(static_cast<int>(PadAxes::RightStickX), right_axis_x); | ||
| 275 | callbacks.on_stick_data(static_cast<int>(PadAxes::RightStickY), right_axis_y); | ||
| 263 | } | 276 | } |
| 264 | 277 | ||
| 265 | f32 JoyconPoller::GetAxisValue(u16 raw_value, Joycon::JoyStickAxisCalibration calibration) const { | 278 | f32 JoyconPoller::GetAxisValue(u16 raw_value, Joycon::JoyStickAxisCalibration calibration) const { |
| @@ -270,6 +283,30 @@ f32 JoyconPoller::GetAxisValue(u16 raw_value, Joycon::JoyStickAxisCalibration ca | |||
| 270 | return value / calibration.min; | 283 | return value / calibration.min; |
| 271 | } | 284 | } |
| 272 | 285 | ||
| 286 | std::pair<f32, f32> JoyconPoller::GetPassiveAxisValue(PasivePadStick raw_value) const { | ||
| 287 | switch (raw_value) { | ||
| 288 | case PasivePadStick::Right: | ||
| 289 | return {1.0f, 0.0f}; | ||
| 290 | case PasivePadStick::RightDown: | ||
| 291 | return {1.0f, -1.0f}; | ||
| 292 | case PasivePadStick::Down: | ||
| 293 | return {0.0f, -1.0f}; | ||
| 294 | case PasivePadStick::DownLeft: | ||
| 295 | return {-1.0f, -1.0f}; | ||
| 296 | case PasivePadStick::Left: | ||
| 297 | return {-1.0f, 0.0f}; | ||
| 298 | case PasivePadStick::LeftUp: | ||
| 299 | return {-1.0f, 1.0f}; | ||
| 300 | case PasivePadStick::Up: | ||
| 301 | return {0.0f, 1.0f}; | ||
| 302 | case PasivePadStick::UpRight: | ||
| 303 | return {1.0f, 1.0f}; | ||
| 304 | case PasivePadStick::Neutral: | ||
| 305 | default: | ||
| 306 | return {0.0f, 0.0f}; | ||
| 307 | } | ||
| 308 | } | ||
| 309 | |||
| 273 | f32 JoyconPoller::GetAccelerometerValue(s16 raw, const MotionSensorCalibration& cal, | 310 | f32 JoyconPoller::GetAccelerometerValue(s16 raw, const MotionSensorCalibration& cal, |
| 274 | AccelerometerSensitivity sensitivity) const { | 311 | AccelerometerSensitivity sensitivity) const { |
| 275 | const f32 value = raw * (1.0f / (cal.scale - cal.offset)) * 4; | 312 | const f32 value = raw * (1.0f / (cal.scale - cal.offset)) * 4; |
diff --git a/src/input_common/helpers/joycon_protocol/poller.h b/src/input_common/helpers/joycon_protocol/poller.h index 354d41dad..5c897f070 100644 --- a/src/input_common/helpers/joycon_protocol/poller.h +++ b/src/input_common/helpers/joycon_protocol/poller.h | |||
| @@ -22,7 +22,7 @@ public: | |||
| 22 | JoyStickCalibration right_stick_calibration_, | 22 | JoyStickCalibration right_stick_calibration_, |
| 23 | MotionCalibration motion_calibration_); | 23 | MotionCalibration motion_calibration_); |
| 24 | 24 | ||
| 25 | void SetCallbacks(const Joycon::JoyconCallbacks& callbacks_); | 25 | void SetCallbacks(const JoyconCallbacks& callbacks_); |
| 26 | 26 | ||
| 27 | /// Handles data from passive packages | 27 | /// Handles data from passive packages |
| 28 | void ReadPassiveMode(std::span<u8> buffer); | 28 | void ReadPassiveMode(std::span<u8> buffer); |
| @@ -51,7 +51,10 @@ private: | |||
| 51 | void UpdatePasiveProPadInput(const InputReportPassive& buffer); | 51 | void UpdatePasiveProPadInput(const InputReportPassive& buffer); |
| 52 | 52 | ||
| 53 | /// Returns a calibrated joystick axis from raw axis data | 53 | /// Returns a calibrated joystick axis from raw axis data |
| 54 | f32 GetAxisValue(u16 raw_value, Joycon::JoyStickAxisCalibration calibration) const; | 54 | f32 GetAxisValue(u16 raw_value, JoyStickAxisCalibration calibration) const; |
| 55 | |||
| 56 | /// Returns a digital joystick axis from passive axis data | ||
| 57 | std::pair<f32, f32> GetPassiveAxisValue(PasivePadStick raw_value) const; | ||
| 55 | 58 | ||
| 56 | /// Returns a calibrated accelerometer axis from raw motion data | 59 | /// Returns a calibrated accelerometer axis from raw motion data |
| 57 | f32 GetAccelerometerValue(s16 raw, const MotionSensorCalibration& cal, | 60 | f32 GetAccelerometerValue(s16 raw, const MotionSensorCalibration& cal, |
| @@ -75,7 +78,7 @@ private: | |||
| 75 | JoyStickCalibration right_stick_calibration{}; | 78 | JoyStickCalibration right_stick_calibration{}; |
| 76 | MotionCalibration motion_calibration{}; | 79 | MotionCalibration motion_calibration{}; |
| 77 | 80 | ||
| 78 | Joycon::JoyconCallbacks callbacks{}; | 81 | JoyconCallbacks callbacks{}; |
| 79 | }; | 82 | }; |
| 80 | 83 | ||
| 81 | } // namespace InputCommon::Joycon | 84 | } // namespace InputCommon::Joycon |
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h index 06fd40851..2a150ccdc 100644 --- a/src/video_core/buffer_cache/buffer_cache.h +++ b/src/video_core/buffer_cache/buffer_cache.h | |||
| @@ -55,6 +55,19 @@ constexpr u32 NUM_STORAGE_BUFFERS = 16; | |||
| 55 | constexpr u32 NUM_TEXTURE_BUFFERS = 16; | 55 | constexpr u32 NUM_TEXTURE_BUFFERS = 16; |
| 56 | constexpr u32 NUM_STAGES = 5; | 56 | constexpr u32 NUM_STAGES = 5; |
| 57 | 57 | ||
| 58 | enum class ObtainBufferSynchronize : u32 { | ||
| 59 | NoSynchronize = 0, | ||
| 60 | FullSynchronize = 1, | ||
| 61 | SynchronizeNoDirty = 2, | ||
| 62 | }; | ||
| 63 | |||
| 64 | enum class ObtainBufferOperation : u32 { | ||
| 65 | DoNothing = 0, | ||
| 66 | MarkAsWritten = 1, | ||
| 67 | DiscardWrite = 2, | ||
| 68 | MarkQuery = 3, | ||
| 69 | }; | ||
| 70 | |||
| 58 | using UniformBufferSizes = std::array<std::array<u32, NUM_GRAPHICS_UNIFORM_BUFFERS>, NUM_STAGES>; | 71 | using UniformBufferSizes = std::array<std::array<u32, NUM_GRAPHICS_UNIFORM_BUFFERS>, NUM_STAGES>; |
| 59 | using ComputeUniformBufferSizes = std::array<u32, NUM_COMPUTE_UNIFORM_BUFFERS>; | 72 | using ComputeUniformBufferSizes = std::array<u32, NUM_COMPUTE_UNIFORM_BUFFERS>; |
| 60 | 73 | ||
| @@ -191,6 +204,10 @@ public: | |||
| 191 | 204 | ||
| 192 | bool DMAClear(GPUVAddr src_address, u64 amount, u32 value); | 205 | bool DMAClear(GPUVAddr src_address, u64 amount, u32 value); |
| 193 | 206 | ||
| 207 | [[nodiscard]] std::pair<Buffer*, u32> ObtainBuffer(GPUVAddr gpu_addr, u32 size, | ||
| 208 | ObtainBufferSynchronize sync_info, | ||
| 209 | ObtainBufferOperation post_op); | ||
| 210 | |||
| 194 | /// Return true when a CPU region is modified from the GPU | 211 | /// Return true when a CPU region is modified from the GPU |
| 195 | [[nodiscard]] bool IsRegionGpuModified(VAddr addr, size_t size); | 212 | [[nodiscard]] bool IsRegionGpuModified(VAddr addr, size_t size); |
| 196 | 213 | ||
| @@ -642,6 +659,42 @@ bool BufferCache<P>::DMAClear(GPUVAddr dst_address, u64 amount, u32 value) { | |||
| 642 | } | 659 | } |
| 643 | 660 | ||
| 644 | template <class P> | 661 | template <class P> |
| 662 | std::pair<typename P::Buffer*, u32> BufferCache<P>::ObtainBuffer(GPUVAddr gpu_addr, u32 size, | ||
| 663 | ObtainBufferSynchronize sync_info, | ||
| 664 | ObtainBufferOperation post_op) { | ||
| 665 | const std::optional<VAddr> cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr); | ||
| 666 | if (!cpu_addr) { | ||
| 667 | return {&slot_buffers[NULL_BUFFER_ID], 0}; | ||
| 668 | } | ||
| 669 | const BufferId buffer_id = FindBuffer(*cpu_addr, size); | ||
| 670 | Buffer& buffer = slot_buffers[buffer_id]; | ||
| 671 | |||
| 672 | // synchronize op | ||
| 673 | switch (sync_info) { | ||
| 674 | case ObtainBufferSynchronize::FullSynchronize: | ||
| 675 | SynchronizeBuffer(buffer, *cpu_addr, size); | ||
| 676 | break; | ||
| 677 | default: | ||
| 678 | break; | ||
| 679 | } | ||
| 680 | |||
| 681 | switch (post_op) { | ||
| 682 | case ObtainBufferOperation::MarkAsWritten: | ||
| 683 | MarkWrittenBuffer(buffer_id, *cpu_addr, size); | ||
| 684 | break; | ||
| 685 | case ObtainBufferOperation::DiscardWrite: { | ||
| 686 | IntervalType interval{*cpu_addr, size}; | ||
| 687 | ClearDownload(interval); | ||
| 688 | break; | ||
| 689 | } | ||
| 690 | default: | ||
| 691 | break; | ||
| 692 | } | ||
| 693 | |||
| 694 | return {&buffer, buffer.Offset(*cpu_addr)}; | ||
| 695 | } | ||
| 696 | |||
| 697 | template <class P> | ||
| 645 | void BufferCache<P>::BindGraphicsUniformBuffer(size_t stage, u32 index, GPUVAddr gpu_addr, | 698 | void BufferCache<P>::BindGraphicsUniformBuffer(size_t stage, u32 index, GPUVAddr gpu_addr, |
| 646 | u32 size) { | 699 | u32 size) { |
| 647 | const std::optional<VAddr> cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr); | 700 | const std::optional<VAddr> cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr); |
diff --git a/src/video_core/engines/maxwell_dma.cpp b/src/video_core/engines/maxwell_dma.cpp index 7762c7d96..e68850dc5 100644 --- a/src/video_core/engines/maxwell_dma.cpp +++ b/src/video_core/engines/maxwell_dma.cpp | |||
| @@ -14,7 +14,13 @@ | |||
| 14 | #include "video_core/textures/decoders.h" | 14 | #include "video_core/textures/decoders.h" |
| 15 | 15 | ||
| 16 | MICROPROFILE_DECLARE(GPU_DMAEngine); | 16 | MICROPROFILE_DECLARE(GPU_DMAEngine); |
| 17 | MICROPROFILE_DECLARE(GPU_DMAEngineBL); | ||
| 18 | MICROPROFILE_DECLARE(GPU_DMAEngineLB); | ||
| 19 | MICROPROFILE_DECLARE(GPU_DMAEngineBB); | ||
| 17 | MICROPROFILE_DEFINE(GPU_DMAEngine, "GPU", "DMA Engine", MP_RGB(224, 224, 128)); | 20 | MICROPROFILE_DEFINE(GPU_DMAEngine, "GPU", "DMA Engine", MP_RGB(224, 224, 128)); |
| 21 | MICROPROFILE_DEFINE(GPU_DMAEngineBL, "GPU", "DMA Engine Block - Linear", MP_RGB(224, 224, 128)); | ||
| 22 | MICROPROFILE_DEFINE(GPU_DMAEngineLB, "GPU", "DMA Engine Linear - Block", MP_RGB(224, 224, 128)); | ||
| 23 | MICROPROFILE_DEFINE(GPU_DMAEngineBB, "GPU", "DMA Engine Block - Block", MP_RGB(224, 224, 128)); | ||
| 18 | 24 | ||
| 19 | namespace Tegra::Engines { | 25 | namespace Tegra::Engines { |
| 20 | 26 | ||
| @@ -72,6 +78,7 @@ void MaxwellDMA::Launch() { | |||
| 72 | memory_manager.FlushCaching(); | 78 | memory_manager.FlushCaching(); |
| 73 | if (!is_src_pitch && !is_dst_pitch) { | 79 | if (!is_src_pitch && !is_dst_pitch) { |
| 74 | // If both the source and the destination are in block layout, assert. | 80 | // If both the source and the destination are in block layout, assert. |
| 81 | MICROPROFILE_SCOPE(GPU_DMAEngineBB); | ||
| 75 | CopyBlockLinearToBlockLinear(); | 82 | CopyBlockLinearToBlockLinear(); |
| 76 | ReleaseSemaphore(); | 83 | ReleaseSemaphore(); |
| 77 | return; | 84 | return; |
| @@ -87,8 +94,10 @@ void MaxwellDMA::Launch() { | |||
| 87 | } | 94 | } |
| 88 | } else { | 95 | } else { |
| 89 | if (!is_src_pitch && is_dst_pitch) { | 96 | if (!is_src_pitch && is_dst_pitch) { |
| 97 | MICROPROFILE_SCOPE(GPU_DMAEngineBL); | ||
| 90 | CopyBlockLinearToPitch(); | 98 | CopyBlockLinearToPitch(); |
| 91 | } else { | 99 | } else { |
| 100 | MICROPROFILE_SCOPE(GPU_DMAEngineLB); | ||
| 92 | CopyPitchToBlockLinear(); | 101 | CopyPitchToBlockLinear(); |
| 93 | } | 102 | } |
| 94 | } | 103 | } |
| @@ -153,21 +162,35 @@ void MaxwellDMA::Launch() { | |||
| 153 | } | 162 | } |
| 154 | 163 | ||
| 155 | void MaxwellDMA::CopyBlockLinearToPitch() { | 164 | void MaxwellDMA::CopyBlockLinearToPitch() { |
| 156 | UNIMPLEMENTED_IF(regs.src_params.block_size.width != 0); | 165 | UNIMPLEMENTED_IF(regs.launch_dma.remap_enable != 0); |
| 157 | UNIMPLEMENTED_IF(regs.src_params.layer != 0); | 166 | |
| 158 | 167 | u32 bytes_per_pixel = 1; | |
| 159 | const bool is_remapping = regs.launch_dma.remap_enable != 0; | 168 | DMA::ImageOperand src_operand; |
| 160 | 169 | src_operand.bytes_per_pixel = bytes_per_pixel; | |
| 161 | // Optimized path for micro copies. | 170 | src_operand.params = regs.src_params; |
| 162 | const size_t dst_size = static_cast<size_t>(regs.pitch_out) * regs.line_count; | 171 | src_operand.address = regs.offset_in; |
| 163 | if (!is_remapping && dst_size < GOB_SIZE && regs.pitch_out <= GOB_SIZE_X && | 172 | |
| 164 | regs.src_params.height > GOB_SIZE_Y) { | 173 | DMA::BufferOperand dst_operand; |
| 165 | FastCopyBlockLinearToPitch(); | 174 | dst_operand.pitch = regs.pitch_out; |
| 175 | dst_operand.width = regs.line_length_in; | ||
| 176 | dst_operand.height = regs.line_count; | ||
| 177 | dst_operand.address = regs.offset_out; | ||
| 178 | DMA::ImageCopy copy_info{}; | ||
| 179 | copy_info.length_x = regs.line_length_in; | ||
| 180 | copy_info.length_y = regs.line_count; | ||
| 181 | auto& accelerate = rasterizer->AccessAccelerateDMA(); | ||
| 182 | if (accelerate.ImageToBuffer(copy_info, src_operand, dst_operand)) { | ||
| 166 | return; | 183 | return; |
| 167 | } | 184 | } |
| 168 | 185 | ||
| 186 | UNIMPLEMENTED_IF(regs.src_params.block_size.width != 0); | ||
| 187 | UNIMPLEMENTED_IF(regs.src_params.block_size.depth != 0); | ||
| 188 | UNIMPLEMENTED_IF(regs.src_params.block_size.depth == 0 && regs.src_params.depth != 1); | ||
| 189 | |||
| 169 | // Deswizzle the input and copy it over. | 190 | // Deswizzle the input and copy it over. |
| 170 | const Parameters& src_params = regs.src_params; | 191 | const DMA::Parameters& src_params = regs.src_params; |
| 192 | |||
| 193 | const bool is_remapping = regs.launch_dma.remap_enable != 0; | ||
| 171 | 194 | ||
| 172 | const u32 num_remap_components = regs.remap_const.num_dst_components_minus_one + 1; | 195 | const u32 num_remap_components = regs.remap_const.num_dst_components_minus_one + 1; |
| 173 | const u32 remap_components_size = regs.remap_const.component_size_minus_one + 1; | 196 | const u32 remap_components_size = regs.remap_const.component_size_minus_one + 1; |
| @@ -187,7 +210,7 @@ void MaxwellDMA::CopyBlockLinearToPitch() { | |||
| 187 | x_offset >>= bpp_shift; | 210 | x_offset >>= bpp_shift; |
| 188 | } | 211 | } |
| 189 | 212 | ||
| 190 | const u32 bytes_per_pixel = base_bpp << bpp_shift; | 213 | bytes_per_pixel = base_bpp << bpp_shift; |
| 191 | const u32 height = src_params.height; | 214 | const u32 height = src_params.height; |
| 192 | const u32 depth = src_params.depth; | 215 | const u32 depth = src_params.depth; |
| 193 | const u32 block_height = src_params.block_size.height; | 216 | const u32 block_height = src_params.block_size.height; |
| @@ -195,11 +218,12 @@ void MaxwellDMA::CopyBlockLinearToPitch() { | |||
| 195 | const size_t src_size = | 218 | const size_t src_size = |
| 196 | CalculateSize(true, bytes_per_pixel, width, height, depth, block_height, block_depth); | 219 | CalculateSize(true, bytes_per_pixel, width, height, depth, block_height, block_depth); |
| 197 | 220 | ||
| 221 | const size_t dst_size = static_cast<size_t>(regs.pitch_out) * regs.line_count; | ||
| 198 | read_buffer.resize_destructive(src_size); | 222 | read_buffer.resize_destructive(src_size); |
| 199 | write_buffer.resize_destructive(dst_size); | 223 | write_buffer.resize_destructive(dst_size); |
| 200 | 224 | ||
| 201 | memory_manager.ReadBlock(regs.offset_in, read_buffer.data(), src_size); | 225 | memory_manager.ReadBlock(src_operand.address, read_buffer.data(), src_size); |
| 202 | memory_manager.ReadBlock(regs.offset_out, write_buffer.data(), dst_size); | 226 | memory_manager.ReadBlockUnsafe(dst_operand.address, write_buffer.data(), dst_size); |
| 203 | 227 | ||
| 204 | UnswizzleSubrect(write_buffer, read_buffer, bytes_per_pixel, width, height, depth, x_offset, | 228 | UnswizzleSubrect(write_buffer, read_buffer, bytes_per_pixel, width, height, depth, x_offset, |
| 205 | src_params.origin.y, x_elements, regs.line_count, block_height, block_depth, | 229 | src_params.origin.y, x_elements, regs.line_count, block_height, block_depth, |
| @@ -216,6 +240,24 @@ void MaxwellDMA::CopyPitchToBlockLinear() { | |||
| 216 | const u32 num_remap_components = regs.remap_const.num_dst_components_minus_one + 1; | 240 | const u32 num_remap_components = regs.remap_const.num_dst_components_minus_one + 1; |
| 217 | const u32 remap_components_size = regs.remap_const.component_size_minus_one + 1; | 241 | const u32 remap_components_size = regs.remap_const.component_size_minus_one + 1; |
| 218 | 242 | ||
| 243 | u32 bytes_per_pixel = 1; | ||
| 244 | DMA::ImageOperand dst_operand; | ||
| 245 | dst_operand.bytes_per_pixel = bytes_per_pixel; | ||
| 246 | dst_operand.params = regs.dst_params; | ||
| 247 | dst_operand.address = regs.offset_out; | ||
| 248 | DMA::BufferOperand src_operand; | ||
| 249 | src_operand.pitch = regs.pitch_in; | ||
| 250 | src_operand.width = regs.line_length_in; | ||
| 251 | src_operand.height = regs.line_count; | ||
| 252 | src_operand.address = regs.offset_in; | ||
| 253 | DMA::ImageCopy copy_info{}; | ||
| 254 | copy_info.length_x = regs.line_length_in; | ||
| 255 | copy_info.length_y = regs.line_count; | ||
| 256 | auto& accelerate = rasterizer->AccessAccelerateDMA(); | ||
| 257 | if (accelerate.BufferToImage(copy_info, src_operand, dst_operand)) { | ||
| 258 | return; | ||
| 259 | } | ||
| 260 | |||
| 219 | const auto& dst_params = regs.dst_params; | 261 | const auto& dst_params = regs.dst_params; |
| 220 | 262 | ||
| 221 | const u32 base_bpp = !is_remapping ? 1U : num_remap_components * remap_components_size; | 263 | const u32 base_bpp = !is_remapping ? 1U : num_remap_components * remap_components_size; |
| @@ -233,7 +275,7 @@ void MaxwellDMA::CopyPitchToBlockLinear() { | |||
| 233 | x_offset >>= bpp_shift; | 275 | x_offset >>= bpp_shift; |
| 234 | } | 276 | } |
| 235 | 277 | ||
| 236 | const u32 bytes_per_pixel = base_bpp << bpp_shift; | 278 | bytes_per_pixel = base_bpp << bpp_shift; |
| 237 | const u32 height = dst_params.height; | 279 | const u32 height = dst_params.height; |
| 238 | const u32 depth = dst_params.depth; | 280 | const u32 depth = dst_params.depth; |
| 239 | const u32 block_height = dst_params.block_size.height; | 281 | const u32 block_height = dst_params.block_size.height; |
| @@ -260,45 +302,14 @@ void MaxwellDMA::CopyPitchToBlockLinear() { | |||
| 260 | memory_manager.WriteBlockCached(regs.offset_out, write_buffer.data(), dst_size); | 302 | memory_manager.WriteBlockCached(regs.offset_out, write_buffer.data(), dst_size); |
| 261 | } | 303 | } |
| 262 | 304 | ||
| 263 | void MaxwellDMA::FastCopyBlockLinearToPitch() { | ||
| 264 | const u32 bytes_per_pixel = 1U; | ||
| 265 | const size_t src_size = GOB_SIZE; | ||
| 266 | const size_t dst_size = static_cast<size_t>(regs.pitch_out) * regs.line_count; | ||
| 267 | u32 pos_x = regs.src_params.origin.x; | ||
| 268 | u32 pos_y = regs.src_params.origin.y; | ||
| 269 | const u64 offset = GetGOBOffset(regs.src_params.width, regs.src_params.height, pos_x, pos_y, | ||
| 270 | regs.src_params.block_size.height, bytes_per_pixel); | ||
| 271 | const u32 x_in_gob = 64 / bytes_per_pixel; | ||
| 272 | pos_x = pos_x % x_in_gob; | ||
| 273 | pos_y = pos_y % 8; | ||
| 274 | |||
| 275 | read_buffer.resize_destructive(src_size); | ||
| 276 | write_buffer.resize_destructive(dst_size); | ||
| 277 | |||
| 278 | if (Settings::IsGPULevelExtreme()) { | ||
| 279 | memory_manager.ReadBlock(regs.offset_in + offset, read_buffer.data(), src_size); | ||
| 280 | memory_manager.ReadBlock(regs.offset_out, write_buffer.data(), dst_size); | ||
| 281 | } else { | ||
| 282 | memory_manager.ReadBlockUnsafe(regs.offset_in + offset, read_buffer.data(), src_size); | ||
| 283 | memory_manager.ReadBlockUnsafe(regs.offset_out, write_buffer.data(), dst_size); | ||
| 284 | } | ||
| 285 | |||
| 286 | UnswizzleSubrect(write_buffer, read_buffer, bytes_per_pixel, regs.src_params.width, | ||
| 287 | regs.src_params.height, 1, pos_x, pos_y, regs.line_length_in, regs.line_count, | ||
| 288 | regs.src_params.block_size.height, regs.src_params.block_size.depth, | ||
| 289 | regs.pitch_out); | ||
| 290 | |||
| 291 | memory_manager.WriteBlockCached(regs.offset_out, write_buffer.data(), dst_size); | ||
| 292 | } | ||
| 293 | |||
| 294 | void MaxwellDMA::CopyBlockLinearToBlockLinear() { | 305 | void MaxwellDMA::CopyBlockLinearToBlockLinear() { |
| 295 | UNIMPLEMENTED_IF(regs.src_params.block_size.width != 0); | 306 | UNIMPLEMENTED_IF(regs.src_params.block_size.width != 0); |
| 296 | 307 | ||
| 297 | const bool is_remapping = regs.launch_dma.remap_enable != 0; | 308 | const bool is_remapping = regs.launch_dma.remap_enable != 0; |
| 298 | 309 | ||
| 299 | // Deswizzle the input and copy it over. | 310 | // Deswizzle the input and copy it over. |
| 300 | const Parameters& src = regs.src_params; | 311 | const DMA::Parameters& src = regs.src_params; |
| 301 | const Parameters& dst = regs.dst_params; | 312 | const DMA::Parameters& dst = regs.dst_params; |
| 302 | 313 | ||
| 303 | const u32 num_remap_components = regs.remap_const.num_dst_components_minus_one + 1; | 314 | const u32 num_remap_components = regs.remap_const.num_dst_components_minus_one + 1; |
| 304 | const u32 remap_components_size = regs.remap_const.component_size_minus_one + 1; | 315 | const u32 remap_components_size = regs.remap_const.component_size_minus_one + 1; |
diff --git a/src/video_core/engines/maxwell_dma.h b/src/video_core/engines/maxwell_dma.h index 0e594fa74..69e26cb32 100644 --- a/src/video_core/engines/maxwell_dma.h +++ b/src/video_core/engines/maxwell_dma.h | |||
| @@ -24,6 +24,54 @@ namespace VideoCore { | |||
| 24 | class RasterizerInterface; | 24 | class RasterizerInterface; |
| 25 | } | 25 | } |
| 26 | 26 | ||
| 27 | namespace Tegra { | ||
| 28 | namespace DMA { | ||
| 29 | |||
| 30 | union Origin { | ||
| 31 | BitField<0, 16, u32> x; | ||
| 32 | BitField<16, 16, u32> y; | ||
| 33 | }; | ||
| 34 | static_assert(sizeof(Origin) == 4); | ||
| 35 | |||
| 36 | struct ImageCopy { | ||
| 37 | u32 length_x{}; | ||
| 38 | u32 length_y{}; | ||
| 39 | }; | ||
| 40 | |||
| 41 | union BlockSize { | ||
| 42 | BitField<0, 4, u32> width; | ||
| 43 | BitField<4, 4, u32> height; | ||
| 44 | BitField<8, 4, u32> depth; | ||
| 45 | BitField<12, 4, u32> gob_height; | ||
| 46 | }; | ||
| 47 | static_assert(sizeof(BlockSize) == 4); | ||
| 48 | |||
| 49 | struct Parameters { | ||
| 50 | BlockSize block_size; | ||
| 51 | u32 width; | ||
| 52 | u32 height; | ||
| 53 | u32 depth; | ||
| 54 | u32 layer; | ||
| 55 | Origin origin; | ||
| 56 | }; | ||
| 57 | static_assert(sizeof(Parameters) == 24); | ||
| 58 | |||
| 59 | struct ImageOperand { | ||
| 60 | u32 bytes_per_pixel; | ||
| 61 | Parameters params; | ||
| 62 | GPUVAddr address; | ||
| 63 | }; | ||
| 64 | |||
| 65 | struct BufferOperand { | ||
| 66 | u32 pitch; | ||
| 67 | u32 width; | ||
| 68 | u32 height; | ||
| 69 | GPUVAddr address; | ||
| 70 | }; | ||
| 71 | |||
| 72 | } // namespace DMA | ||
| 73 | } // namespace Tegra | ||
| 74 | |||
| 27 | namespace Tegra::Engines { | 75 | namespace Tegra::Engines { |
| 28 | 76 | ||
| 29 | class AccelerateDMAInterface { | 77 | class AccelerateDMAInterface { |
| @@ -32,6 +80,12 @@ public: | |||
| 32 | virtual bool BufferCopy(GPUVAddr src_address, GPUVAddr dest_address, u64 amount) = 0; | 80 | virtual bool BufferCopy(GPUVAddr src_address, GPUVAddr dest_address, u64 amount) = 0; |
| 33 | 81 | ||
| 34 | virtual bool BufferClear(GPUVAddr src_address, u64 amount, u32 value) = 0; | 82 | virtual bool BufferClear(GPUVAddr src_address, u64 amount, u32 value) = 0; |
| 83 | |||
| 84 | virtual bool ImageToBuffer(const DMA::ImageCopy& copy_info, const DMA::ImageOperand& src, | ||
| 85 | const DMA::BufferOperand& dst) = 0; | ||
| 86 | |||
| 87 | virtual bool BufferToImage(const DMA::ImageCopy& copy_info, const DMA::BufferOperand& src, | ||
| 88 | const DMA::ImageOperand& dst) = 0; | ||
| 35 | }; | 89 | }; |
| 36 | 90 | ||
| 37 | /** | 91 | /** |
| @@ -51,30 +105,6 @@ public: | |||
| 51 | } | 105 | } |
| 52 | }; | 106 | }; |
| 53 | 107 | ||
| 54 | union BlockSize { | ||
| 55 | BitField<0, 4, u32> width; | ||
| 56 | BitField<4, 4, u32> height; | ||
| 57 | BitField<8, 4, u32> depth; | ||
| 58 | BitField<12, 4, u32> gob_height; | ||
| 59 | }; | ||
| 60 | static_assert(sizeof(BlockSize) == 4); | ||
| 61 | |||
| 62 | union Origin { | ||
| 63 | BitField<0, 16, u32> x; | ||
| 64 | BitField<16, 16, u32> y; | ||
| 65 | }; | ||
| 66 | static_assert(sizeof(Origin) == 4); | ||
| 67 | |||
| 68 | struct Parameters { | ||
| 69 | BlockSize block_size; | ||
| 70 | u32 width; | ||
| 71 | u32 height; | ||
| 72 | u32 depth; | ||
| 73 | u32 layer; | ||
| 74 | Origin origin; | ||
| 75 | }; | ||
| 76 | static_assert(sizeof(Parameters) == 24); | ||
| 77 | |||
| 78 | struct Semaphore { | 108 | struct Semaphore { |
| 79 | PackedGPUVAddr address; | 109 | PackedGPUVAddr address; |
| 80 | u32 payload; | 110 | u32 payload; |
| @@ -227,8 +257,6 @@ private: | |||
| 227 | 257 | ||
| 228 | void CopyBlockLinearToBlockLinear(); | 258 | void CopyBlockLinearToBlockLinear(); |
| 229 | 259 | ||
| 230 | void FastCopyBlockLinearToPitch(); | ||
| 231 | |||
| 232 | void ReleaseSemaphore(); | 260 | void ReleaseSemaphore(); |
| 233 | 261 | ||
| 234 | void ConsumeSinkImpl() override; | 262 | void ConsumeSinkImpl() override; |
| @@ -261,17 +289,17 @@ private: | |||
| 261 | u32 reserved05[0x3f]; | 289 | u32 reserved05[0x3f]; |
| 262 | PackedGPUVAddr offset_in; | 290 | PackedGPUVAddr offset_in; |
| 263 | PackedGPUVAddr offset_out; | 291 | PackedGPUVAddr offset_out; |
| 264 | u32 pitch_in; | 292 | s32 pitch_in; |
| 265 | u32 pitch_out; | 293 | s32 pitch_out; |
| 266 | u32 line_length_in; | 294 | u32 line_length_in; |
| 267 | u32 line_count; | 295 | u32 line_count; |
| 268 | u32 reserved06[0xb6]; | 296 | u32 reserved06[0xb6]; |
| 269 | u32 remap_consta_value; | 297 | u32 remap_consta_value; |
| 270 | u32 remap_constb_value; | 298 | u32 remap_constb_value; |
| 271 | RemapConst remap_const; | 299 | RemapConst remap_const; |
| 272 | Parameters dst_params; | 300 | DMA::Parameters dst_params; |
| 273 | u32 reserved07[0x1]; | 301 | u32 reserved07[0x1]; |
| 274 | Parameters src_params; | 302 | DMA::Parameters src_params; |
| 275 | u32 reserved08[0x275]; | 303 | u32 reserved08[0x275]; |
| 276 | u32 pm_trigger_end; | 304 | u32 pm_trigger_end; |
| 277 | u32 reserved09[0x3ba]; | 305 | u32 reserved09[0x3ba]; |
diff --git a/src/video_core/renderer_null/null_rasterizer.h b/src/video_core/renderer_null/null_rasterizer.h index 51f896e43..0c59e6a1f 100644 --- a/src/video_core/renderer_null/null_rasterizer.h +++ b/src/video_core/renderer_null/null_rasterizer.h | |||
| @@ -22,6 +22,14 @@ public: | |||
| 22 | explicit AccelerateDMA(); | 22 | explicit AccelerateDMA(); |
| 23 | bool BufferCopy(GPUVAddr start_address, GPUVAddr end_address, u64 amount) override; | 23 | bool BufferCopy(GPUVAddr start_address, GPUVAddr end_address, u64 amount) override; |
| 24 | bool BufferClear(GPUVAddr src_address, u64 amount, u32 value) override; | 24 | bool BufferClear(GPUVAddr src_address, u64 amount, u32 value) override; |
| 25 | bool ImageToBuffer(const Tegra::DMA::ImageCopy& copy_info, const Tegra::DMA::ImageOperand& src, | ||
| 26 | const Tegra::DMA::BufferOperand& dst) override { | ||
| 27 | return false; | ||
| 28 | } | ||
| 29 | bool BufferToImage(const Tegra::DMA::ImageCopy& copy_info, const Tegra::DMA::BufferOperand& src, | ||
| 30 | const Tegra::DMA::ImageOperand& dst) override { | ||
| 31 | return false; | ||
| 32 | } | ||
| 25 | }; | 33 | }; |
| 26 | 34 | ||
| 27 | class RasterizerNull final : public VideoCore::RasterizerAccelerated, | 35 | class RasterizerNull final : public VideoCore::RasterizerAccelerated, |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 0c45832ae..7e21fc43d 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h | |||
| @@ -56,6 +56,16 @@ public: | |||
| 56 | 56 | ||
| 57 | bool BufferClear(GPUVAddr src_address, u64 amount, u32 value) override; | 57 | bool BufferClear(GPUVAddr src_address, u64 amount, u32 value) override; |
| 58 | 58 | ||
| 59 | bool ImageToBuffer(const Tegra::DMA::ImageCopy& copy_info, const Tegra::DMA::ImageOperand& src, | ||
| 60 | const Tegra::DMA::BufferOperand& dst) override { | ||
| 61 | return false; | ||
| 62 | } | ||
| 63 | |||
| 64 | bool BufferToImage(const Tegra::DMA::ImageCopy& copy_info, const Tegra::DMA::BufferOperand& src, | ||
| 65 | const Tegra::DMA::ImageOperand& dst) override { | ||
| 66 | return false; | ||
| 67 | } | ||
| 68 | |||
| 59 | private: | 69 | private: |
| 60 | BufferCache& buffer_cache; | 70 | BufferCache& buffer_cache; |
| 61 | }; | 71 | }; |
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 719edbcfb..f085d53a1 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp | |||
| @@ -172,7 +172,7 @@ RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra | |||
| 172 | buffer_cache(*this, cpu_memory_, buffer_cache_runtime), | 172 | buffer_cache(*this, cpu_memory_, buffer_cache_runtime), |
| 173 | pipeline_cache(*this, device, scheduler, descriptor_pool, update_descriptor_queue, | 173 | pipeline_cache(*this, device, scheduler, descriptor_pool, update_descriptor_queue, |
| 174 | render_pass_cache, buffer_cache, texture_cache, gpu.ShaderNotify()), | 174 | render_pass_cache, buffer_cache, texture_cache, gpu.ShaderNotify()), |
| 175 | query_cache{*this, device, scheduler}, accelerate_dma{buffer_cache}, | 175 | query_cache{*this, device, scheduler}, accelerate_dma(buffer_cache, texture_cache, scheduler), |
| 176 | fence_manager(*this, gpu, texture_cache, buffer_cache, query_cache, device, scheduler), | 176 | fence_manager(*this, gpu, texture_cache, buffer_cache, query_cache, device, scheduler), |
| 177 | wfi_event(device.GetLogical().CreateEvent()) { | 177 | wfi_event(device.GetLogical().CreateEvent()) { |
| 178 | scheduler.SetQueryCache(query_cache); | 178 | scheduler.SetQueryCache(query_cache); |
| @@ -756,7 +756,9 @@ void RasterizerVulkan::FlushWork() { | |||
| 756 | draw_counter = 0; | 756 | draw_counter = 0; |
| 757 | } | 757 | } |
| 758 | 758 | ||
| 759 | AccelerateDMA::AccelerateDMA(BufferCache& buffer_cache_) : buffer_cache{buffer_cache_} {} | 759 | AccelerateDMA::AccelerateDMA(BufferCache& buffer_cache_, TextureCache& texture_cache_, |
| 760 | Scheduler& scheduler_) | ||
| 761 | : buffer_cache{buffer_cache_}, texture_cache{texture_cache_}, scheduler{scheduler_} {} | ||
| 760 | 762 | ||
| 761 | bool AccelerateDMA::BufferClear(GPUVAddr src_address, u64 amount, u32 value) { | 763 | bool AccelerateDMA::BufferClear(GPUVAddr src_address, u64 amount, u32 value) { |
| 762 | std::scoped_lock lock{buffer_cache.mutex}; | 764 | std::scoped_lock lock{buffer_cache.mutex}; |
| @@ -768,6 +770,234 @@ bool AccelerateDMA::BufferCopy(GPUVAddr src_address, GPUVAddr dest_address, u64 | |||
| 768 | return buffer_cache.DMACopy(src_address, dest_address, amount); | 770 | return buffer_cache.DMACopy(src_address, dest_address, amount); |
| 769 | } | 771 | } |
| 770 | 772 | ||
| 773 | bool AccelerateDMA::ImageToBuffer(const Tegra::DMA::ImageCopy& copy_info, | ||
| 774 | const Tegra::DMA::ImageOperand& src, | ||
| 775 | const Tegra::DMA::BufferOperand& dst) { | ||
| 776 | std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex}; | ||
| 777 | auto query_image = texture_cache.ObtainImage(src, false); | ||
| 778 | if (!query_image) { | ||
| 779 | return false; | ||
| 780 | } | ||
| 781 | auto* image = query_image->first; | ||
| 782 | auto [level, base] = query_image->second; | ||
| 783 | const u32 buffer_size = static_cast<u32>(dst.pitch * dst.height); | ||
| 784 | const auto [buffer, offset] = buffer_cache.ObtainBuffer( | ||
| 785 | dst.address, buffer_size, VideoCommon::ObtainBufferSynchronize::FullSynchronize, | ||
| 786 | VideoCommon::ObtainBufferOperation::MarkAsWritten); | ||
| 787 | |||
| 788 | const bool is_rescaled = image->IsRescaled(); | ||
| 789 | if (is_rescaled) { | ||
| 790 | image->ScaleDown(); | ||
| 791 | } | ||
| 792 | VkImageSubresourceLayers subresources{ | ||
| 793 | .aspectMask = image->AspectMask(), | ||
| 794 | .mipLevel = level, | ||
| 795 | .baseArrayLayer = base, | ||
| 796 | .layerCount = 1, | ||
| 797 | }; | ||
| 798 | const u32 bpp = VideoCore::Surface::BytesPerBlock(image->info.format); | ||
| 799 | const auto convert = [old_bpp = src.bytes_per_pixel, bpp](u32 value) { | ||
| 800 | return (old_bpp * value) / bpp; | ||
| 801 | }; | ||
| 802 | const u32 base_x = convert(src.params.origin.x.Value()); | ||
| 803 | const u32 base_y = src.params.origin.y.Value(); | ||
| 804 | const u32 length_x = convert(copy_info.length_x); | ||
| 805 | const u32 length_y = copy_info.length_y; | ||
| 806 | VkOffset3D image_offset{ | ||
| 807 | .x = static_cast<s32>(base_x), | ||
| 808 | .y = static_cast<s32>(base_y), | ||
| 809 | .z = 0, | ||
| 810 | }; | ||
| 811 | VkExtent3D image_extent{ | ||
| 812 | .width = length_x, | ||
| 813 | .height = length_y, | ||
| 814 | .depth = 1, | ||
| 815 | }; | ||
| 816 | auto buff_info(dst); | ||
| 817 | buff_info.pitch = convert(dst.pitch); | ||
| 818 | scheduler.RequestOutsideRenderPassOperationContext(); | ||
| 819 | scheduler.Record([src_image = image->Handle(), dst_buffer = buffer->Handle(), | ||
| 820 | buffer_offset = offset, subresources, image_offset, image_extent, | ||
| 821 | buff_info](vk::CommandBuffer cmdbuf) { | ||
| 822 | const std::array buffer_copy_info{ | ||
| 823 | VkBufferImageCopy{ | ||
| 824 | .bufferOffset = buffer_offset, | ||
| 825 | .bufferRowLength = buff_info.pitch, | ||
| 826 | .bufferImageHeight = buff_info.height, | ||
| 827 | .imageSubresource = subresources, | ||
| 828 | .imageOffset = image_offset, | ||
| 829 | .imageExtent = image_extent, | ||
| 830 | }, | ||
| 831 | }; | ||
| 832 | const VkImageSubresourceRange range{ | ||
| 833 | .aspectMask = subresources.aspectMask, | ||
| 834 | .baseMipLevel = subresources.mipLevel, | ||
| 835 | .levelCount = 1, | ||
| 836 | .baseArrayLayer = subresources.baseArrayLayer, | ||
| 837 | .layerCount = 1, | ||
| 838 | }; | ||
| 839 | static constexpr VkMemoryBarrier WRITE_BARRIER{ | ||
| 840 | .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER, | ||
| 841 | .pNext = nullptr, | ||
| 842 | .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, | ||
| 843 | .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, | ||
| 844 | }; | ||
| 845 | const std::array pre_barriers{ | ||
| 846 | VkImageMemoryBarrier{ | ||
| 847 | .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, | ||
| 848 | .pNext = nullptr, | ||
| 849 | .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | | ||
| 850 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | | ||
| 851 | VK_ACCESS_TRANSFER_WRITE_BIT, | ||
| 852 | .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT, | ||
| 853 | .oldLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 854 | .newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, | ||
| 855 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 856 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 857 | .image = src_image, | ||
| 858 | .subresourceRange = range, | ||
| 859 | }, | ||
| 860 | }; | ||
| 861 | const std::array post_barriers{ | ||
| 862 | VkImageMemoryBarrier{ | ||
| 863 | .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, | ||
| 864 | .pNext = nullptr, | ||
| 865 | .srcAccessMask = 0, | ||
| 866 | .dstAccessMask = 0, | ||
| 867 | .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, | ||
| 868 | .newLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 869 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 870 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 871 | .image = src_image, | ||
| 872 | .subresourceRange = range, | ||
| 873 | }, | ||
| 874 | }; | ||
| 875 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, | ||
| 876 | 0, {}, {}, pre_barriers); | ||
| 877 | cmdbuf.CopyImageToBuffer(src_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_buffer, | ||
| 878 | buffer_copy_info); | ||
| 879 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, | ||
| 880 | 0, WRITE_BARRIER, nullptr, post_barriers); | ||
| 881 | }); | ||
| 882 | if (is_rescaled) { | ||
| 883 | image->ScaleUp(true); | ||
| 884 | } | ||
| 885 | return true; | ||
| 886 | } | ||
| 887 | |||
| 888 | bool AccelerateDMA::BufferToImage(const Tegra::DMA::ImageCopy& copy_info, | ||
| 889 | const Tegra::DMA::BufferOperand& src, | ||
| 890 | const Tegra::DMA::ImageOperand& dst) { | ||
| 891 | std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex}; | ||
| 892 | auto query_image = texture_cache.ObtainImage(dst, true); | ||
| 893 | if (!query_image) { | ||
| 894 | return false; | ||
| 895 | } | ||
| 896 | auto* image = query_image->first; | ||
| 897 | auto [level, base] = query_image->second; | ||
| 898 | const u32 buffer_size = static_cast<u32>(src.pitch * src.height); | ||
| 899 | const auto [buffer, offset] = buffer_cache.ObtainBuffer( | ||
| 900 | src.address, buffer_size, VideoCommon::ObtainBufferSynchronize::FullSynchronize, | ||
| 901 | VideoCommon::ObtainBufferOperation::DoNothing); | ||
| 902 | const bool is_rescaled = image->IsRescaled(); | ||
| 903 | if (is_rescaled) { | ||
| 904 | image->ScaleDown(true); | ||
| 905 | } | ||
| 906 | VkImageSubresourceLayers subresources{ | ||
| 907 | .aspectMask = image->AspectMask(), | ||
| 908 | .mipLevel = level, | ||
| 909 | .baseArrayLayer = base, | ||
| 910 | .layerCount = 1, | ||
| 911 | }; | ||
| 912 | const u32 bpp = VideoCore::Surface::BytesPerBlock(image->info.format); | ||
| 913 | const auto convert = [old_bpp = dst.bytes_per_pixel, bpp](u32 value) { | ||
| 914 | return (old_bpp * value) / bpp; | ||
| 915 | }; | ||
| 916 | const u32 base_x = convert(dst.params.origin.x.Value()); | ||
| 917 | const u32 base_y = dst.params.origin.y.Value(); | ||
| 918 | const u32 length_x = convert(copy_info.length_x); | ||
| 919 | const u32 length_y = copy_info.length_y; | ||
| 920 | VkOffset3D image_offset{ | ||
| 921 | .x = static_cast<s32>(base_x), | ||
| 922 | .y = static_cast<s32>(base_y), | ||
| 923 | .z = 0, | ||
| 924 | }; | ||
| 925 | VkExtent3D image_extent{ | ||
| 926 | .width = length_x, | ||
| 927 | .height = length_y, | ||
| 928 | .depth = 1, | ||
| 929 | }; | ||
| 930 | auto buff_info(src); | ||
| 931 | buff_info.pitch = convert(src.pitch); | ||
| 932 | scheduler.RequestOutsideRenderPassOperationContext(); | ||
| 933 | scheduler.Record([dst_image = image->Handle(), src_buffer = buffer->Handle(), | ||
| 934 | buffer_offset = offset, subresources, image_offset, image_extent, | ||
| 935 | buff_info](vk::CommandBuffer cmdbuf) { | ||
| 936 | const std::array buffer_copy_info{ | ||
| 937 | VkBufferImageCopy{ | ||
| 938 | .bufferOffset = buffer_offset, | ||
| 939 | .bufferRowLength = buff_info.pitch, | ||
| 940 | .bufferImageHeight = buff_info.height, | ||
| 941 | .imageSubresource = subresources, | ||
| 942 | .imageOffset = image_offset, | ||
| 943 | .imageExtent = image_extent, | ||
| 944 | }, | ||
| 945 | }; | ||
| 946 | const VkImageSubresourceRange range{ | ||
| 947 | .aspectMask = subresources.aspectMask, | ||
| 948 | .baseMipLevel = subresources.mipLevel, | ||
| 949 | .levelCount = 1, | ||
| 950 | .baseArrayLayer = subresources.baseArrayLayer, | ||
| 951 | .layerCount = 1, | ||
| 952 | }; | ||
| 953 | static constexpr VkMemoryBarrier READ_BARRIER{ | ||
| 954 | .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER, | ||
| 955 | .pNext = nullptr, | ||
| 956 | .srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT, | ||
| 957 | .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT, | ||
| 958 | }; | ||
| 959 | const std::array pre_barriers{ | ||
| 960 | VkImageMemoryBarrier{ | ||
| 961 | .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, | ||
| 962 | .pNext = nullptr, | ||
| 963 | .srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | | ||
| 964 | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | | ||
| 965 | VK_ACCESS_TRANSFER_WRITE_BIT, | ||
| 966 | .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT, | ||
| 967 | .oldLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 968 | .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, | ||
| 969 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 970 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 971 | .image = dst_image, | ||
| 972 | .subresourceRange = range, | ||
| 973 | }, | ||
| 974 | }; | ||
| 975 | const std::array post_barriers{ | ||
| 976 | VkImageMemoryBarrier{ | ||
| 977 | .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, | ||
| 978 | .pNext = nullptr, | ||
| 979 | .srcAccessMask = 0, | ||
| 980 | .dstAccessMask = 0, | ||
| 981 | .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, | ||
| 982 | .newLayout = VK_IMAGE_LAYOUT_GENERAL, | ||
| 983 | .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 984 | .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, | ||
| 985 | .image = dst_image, | ||
| 986 | .subresourceRange = range, | ||
| 987 | }, | ||
| 988 | }; | ||
| 989 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, | ||
| 990 | 0, READ_BARRIER, {}, pre_barriers); | ||
| 991 | cmdbuf.CopyBufferToImage(src_buffer, dst_image, VK_IMAGE_LAYOUT_GENERAL, buffer_copy_info); | ||
| 992 | cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, | ||
| 993 | 0, nullptr, nullptr, post_barriers); | ||
| 994 | }); | ||
| 995 | if (is_rescaled) { | ||
| 996 | image->ScaleUp(); | ||
| 997 | } | ||
| 998 | return true; | ||
| 999 | } | ||
| 1000 | |||
| 771 | void RasterizerVulkan::UpdateDynamicStates() { | 1001 | void RasterizerVulkan::UpdateDynamicStates() { |
| 772 | auto& regs = maxwell3d->regs; | 1002 | auto& regs = maxwell3d->regs; |
| 773 | UpdateViewportsState(regs); | 1003 | UpdateViewportsState(regs); |
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h index a0508b57c..7746c5434 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.h +++ b/src/video_core/renderer_vulkan/vk_rasterizer.h | |||
| @@ -45,14 +45,23 @@ class StateTracker; | |||
| 45 | 45 | ||
| 46 | class AccelerateDMA : public Tegra::Engines::AccelerateDMAInterface { | 46 | class AccelerateDMA : public Tegra::Engines::AccelerateDMAInterface { |
| 47 | public: | 47 | public: |
| 48 | explicit AccelerateDMA(BufferCache& buffer_cache); | 48 | explicit AccelerateDMA(BufferCache& buffer_cache, TextureCache& texture_cache, |
| 49 | Scheduler& scheduler); | ||
| 49 | 50 | ||
| 50 | bool BufferCopy(GPUVAddr start_address, GPUVAddr end_address, u64 amount) override; | 51 | bool BufferCopy(GPUVAddr start_address, GPUVAddr end_address, u64 amount) override; |
| 51 | 52 | ||
| 52 | bool BufferClear(GPUVAddr src_address, u64 amount, u32 value) override; | 53 | bool BufferClear(GPUVAddr src_address, u64 amount, u32 value) override; |
| 53 | 54 | ||
| 55 | bool ImageToBuffer(const Tegra::DMA::ImageCopy& copy_info, const Tegra::DMA::ImageOperand& src, | ||
| 56 | const Tegra::DMA::BufferOperand& dst) override; | ||
| 57 | |||
| 58 | bool BufferToImage(const Tegra::DMA::ImageCopy& copy_info, const Tegra::DMA::BufferOperand& src, | ||
| 59 | const Tegra::DMA::ImageOperand& dst) override; | ||
| 60 | |||
| 54 | private: | 61 | private: |
| 55 | BufferCache& buffer_cache; | 62 | BufferCache& buffer_cache; |
| 63 | TextureCache& texture_cache; | ||
| 64 | Scheduler& scheduler; | ||
| 56 | }; | 65 | }; |
| 57 | 66 | ||
| 58 | class RasterizerVulkan final : public VideoCore::RasterizerAccelerated, | 67 | class RasterizerVulkan final : public VideoCore::RasterizerAccelerated, |
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 80adb70eb..8a204f93f 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp | |||
| @@ -864,13 +864,19 @@ void TextureCacheRuntime::ReinterpretImage(Image& dst, Image& src, | |||
| 864 | const VkImageAspectFlags src_aspect_mask = src.AspectMask(); | 864 | const VkImageAspectFlags src_aspect_mask = src.AspectMask(); |
| 865 | const VkImageAspectFlags dst_aspect_mask = dst.AspectMask(); | 865 | const VkImageAspectFlags dst_aspect_mask = dst.AspectMask(); |
| 866 | 866 | ||
| 867 | std::ranges::transform(copies, vk_in_copies.begin(), [src_aspect_mask](const auto& copy) { | 867 | const auto bpp_in = BytesPerBlock(src.info.format) / DefaultBlockWidth(src.info.format); |
| 868 | return MakeBufferImageCopy(copy, true, src_aspect_mask); | 868 | const auto bpp_out = BytesPerBlock(dst.info.format) / DefaultBlockWidth(dst.info.format); |
| 869 | }); | 869 | std::ranges::transform(copies, vk_in_copies.begin(), |
| 870 | [src_aspect_mask, bpp_in, bpp_out](const auto& copy) { | ||
| 871 | auto copy2 = copy; | ||
| 872 | copy2.src_offset.x = (bpp_out * copy.src_offset.x) / bpp_in; | ||
| 873 | copy2.extent.width = (bpp_out * copy.extent.width) / bpp_in; | ||
| 874 | return MakeBufferImageCopy(copy2, true, src_aspect_mask); | ||
| 875 | }); | ||
| 870 | std::ranges::transform(copies, vk_out_copies.begin(), [dst_aspect_mask](const auto& copy) { | 876 | std::ranges::transform(copies, vk_out_copies.begin(), [dst_aspect_mask](const auto& copy) { |
| 871 | return MakeBufferImageCopy(copy, false, dst_aspect_mask); | 877 | return MakeBufferImageCopy(copy, false, dst_aspect_mask); |
| 872 | }); | 878 | }); |
| 873 | const u32 img_bpp = BytesPerBlock(src.info.format); | 879 | const u32 img_bpp = BytesPerBlock(dst.info.format); |
| 874 | size_t total_size = 0; | 880 | size_t total_size = 0; |
| 875 | for (const auto& copy : copies) { | 881 | for (const auto& copy : copies) { |
| 876 | total_size += copy.extent.width * copy.extent.height * copy.extent.depth * img_bpp; | 882 | total_size += copy.extent.width * copy.extent.height * copy.extent.depth * img_bpp; |
diff --git a/src/video_core/texture_cache/image_info.cpp b/src/video_core/texture_cache/image_info.cpp index e9100091e..a1296b574 100644 --- a/src/video_core/texture_cache/image_info.cpp +++ b/src/video_core/texture_cache/image_info.cpp | |||
| @@ -216,10 +216,51 @@ ImageInfo::ImageInfo(const Tegra::Engines::Fermi2D::Surface& config) noexcept { | |||
| 216 | .height = config.height, | 216 | .height = config.height, |
| 217 | .depth = 1, | 217 | .depth = 1, |
| 218 | }; | 218 | }; |
| 219 | rescaleable = block.depth == 0; | 219 | rescaleable = block.depth == 0 && size.height > 256; |
| 220 | rescaleable &= size.height > 256; | ||
| 221 | downscaleable = size.height > 512; | 220 | downscaleable = size.height > 512; |
| 222 | } | 221 | } |
| 223 | } | 222 | } |
| 224 | 223 | ||
| 224 | static PixelFormat ByteSizeToFormat(u32 bytes_per_pixel) { | ||
| 225 | switch (bytes_per_pixel) { | ||
| 226 | case 1: | ||
| 227 | return PixelFormat::R8_UINT; | ||
| 228 | case 2: | ||
| 229 | return PixelFormat::R8G8_UINT; | ||
| 230 | case 4: | ||
| 231 | return PixelFormat::A8B8G8R8_UINT; | ||
| 232 | case 8: | ||
| 233 | return PixelFormat::R16G16B16A16_UINT; | ||
| 234 | case 16: | ||
| 235 | return PixelFormat::R32G32B32A32_UINT; | ||
| 236 | default: | ||
| 237 | UNIMPLEMENTED(); | ||
| 238 | return PixelFormat::Invalid; | ||
| 239 | } | ||
| 240 | } | ||
| 241 | |||
| 242 | ImageInfo::ImageInfo(const Tegra::DMA::ImageOperand& config) noexcept { | ||
| 243 | const u32 bytes_per_pixel = config.bytes_per_pixel; | ||
| 244 | format = ByteSizeToFormat(bytes_per_pixel); | ||
| 245 | type = config.params.block_size.depth > 0 ? ImageType::e3D : ImageType::e2D; | ||
| 246 | num_samples = 1; | ||
| 247 | block = Extent3D{ | ||
| 248 | .width = config.params.block_size.width, | ||
| 249 | .height = config.params.block_size.height, | ||
| 250 | .depth = config.params.block_size.depth, | ||
| 251 | }; | ||
| 252 | size = Extent3D{ | ||
| 253 | .width = config.params.width, | ||
| 254 | .height = config.params.height, | ||
| 255 | .depth = config.params.depth, | ||
| 256 | }; | ||
| 257 | tile_width_spacing = 0; | ||
| 258 | resources.levels = 1; | ||
| 259 | resources.layers = 1; | ||
| 260 | layer_stride = CalculateLayerStride(*this); | ||
| 261 | maybe_unaligned_layer_stride = CalculateLayerSize(*this); | ||
| 262 | rescaleable = block.depth == 0 && size.height > 256; | ||
| 263 | downscaleable = size.height > 512; | ||
| 264 | } | ||
| 265 | |||
| 225 | } // namespace VideoCommon | 266 | } // namespace VideoCommon |
diff --git a/src/video_core/texture_cache/image_info.h b/src/video_core/texture_cache/image_info.h index 93755e15e..a12f5b44f 100644 --- a/src/video_core/texture_cache/image_info.h +++ b/src/video_core/texture_cache/image_info.h | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | 5 | ||
| 6 | #include "video_core/engines/fermi_2d.h" | 6 | #include "video_core/engines/fermi_2d.h" |
| 7 | #include "video_core/engines/maxwell_3d.h" | 7 | #include "video_core/engines/maxwell_3d.h" |
| 8 | #include "video_core/engines/maxwell_dma.h" | ||
| 8 | #include "video_core/surface.h" | 9 | #include "video_core/surface.h" |
| 9 | #include "video_core/texture_cache/types.h" | 10 | #include "video_core/texture_cache/types.h" |
| 10 | 11 | ||
| @@ -19,6 +20,7 @@ struct ImageInfo { | |||
| 19 | explicit ImageInfo(const Tegra::Engines::Maxwell3D::Regs& regs, size_t index) noexcept; | 20 | explicit ImageInfo(const Tegra::Engines::Maxwell3D::Regs& regs, size_t index) noexcept; |
| 20 | explicit ImageInfo(const Tegra::Engines::Maxwell3D::Regs& regs) noexcept; | 21 | explicit ImageInfo(const Tegra::Engines::Maxwell3D::Regs& regs) noexcept; |
| 21 | explicit ImageInfo(const Tegra::Engines::Fermi2D::Surface& config) noexcept; | 22 | explicit ImageInfo(const Tegra::Engines::Fermi2D::Surface& config) noexcept; |
| 23 | explicit ImageInfo(const Tegra::DMA::ImageOperand& config) noexcept; | ||
| 22 | 24 | ||
| 23 | PixelFormat format = PixelFormat::Invalid; | 25 | PixelFormat format = PixelFormat::Invalid; |
| 24 | ImageType type = ImageType::e1D; | 26 | ImageType type = ImageType::e1D; |
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 9dd152fbe..335338434 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h | |||
| @@ -1359,6 +1359,75 @@ std::optional<typename TextureCache<P>::BlitImages> TextureCache<P>::GetBlitImag | |||
| 1359 | } | 1359 | } |
| 1360 | 1360 | ||
| 1361 | template <class P> | 1361 | template <class P> |
| 1362 | ImageId TextureCache<P>::FindDMAImage(const ImageInfo& info, GPUVAddr gpu_addr) { | ||
| 1363 | std::optional<VAddr> cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr); | ||
| 1364 | if (!cpu_addr) { | ||
| 1365 | cpu_addr = gpu_memory->GpuToCpuAddress(gpu_addr, CalculateGuestSizeInBytes(info)); | ||
| 1366 | if (!cpu_addr) { | ||
| 1367 | return ImageId{}; | ||
| 1368 | } | ||
| 1369 | } | ||
| 1370 | ImageId image_id{}; | ||
| 1371 | boost::container::small_vector<ImageId, 1> image_ids; | ||
| 1372 | const auto lambda = [&](ImageId existing_image_id, ImageBase& existing_image) { | ||
| 1373 | if (True(existing_image.flags & ImageFlagBits::Remapped)) { | ||
| 1374 | return false; | ||
| 1375 | } | ||
| 1376 | if (info.type == ImageType::Linear || existing_image.info.type == ImageType::Linear) | ||
| 1377 | [[unlikely]] { | ||
| 1378 | const bool strict_size = True(existing_image.flags & ImageFlagBits::Strong); | ||
| 1379 | const ImageInfo& existing = existing_image.info; | ||
| 1380 | if (existing_image.gpu_addr == gpu_addr && existing.type == info.type && | ||
| 1381 | existing.pitch == info.pitch && | ||
| 1382 | IsPitchLinearSameSize(existing, info, strict_size) && | ||
| 1383 | IsViewCompatible(existing.format, info.format, false, true)) { | ||
| 1384 | image_id = existing_image_id; | ||
| 1385 | image_ids.push_back(existing_image_id); | ||
| 1386 | return true; | ||
| 1387 | } | ||
| 1388 | } else if (IsSubCopy(info, existing_image, gpu_addr)) { | ||
| 1389 | image_id = existing_image_id; | ||
| 1390 | image_ids.push_back(existing_image_id); | ||
| 1391 | return true; | ||
| 1392 | } | ||
| 1393 | return false; | ||
| 1394 | }; | ||
| 1395 | ForEachImageInRegion(*cpu_addr, CalculateGuestSizeInBytes(info), lambda); | ||
| 1396 | if (image_ids.size() <= 1) [[likely]] { | ||
| 1397 | return image_id; | ||
| 1398 | } | ||
| 1399 | auto image_ids_compare = [this](ImageId a, ImageId b) { | ||
| 1400 | auto& image_a = slot_images[a]; | ||
| 1401 | auto& image_b = slot_images[b]; | ||
| 1402 | return image_a.modification_tick < image_b.modification_tick; | ||
| 1403 | }; | ||
| 1404 | return *std::ranges::max_element(image_ids, image_ids_compare); | ||
| 1405 | } | ||
| 1406 | |||
| 1407 | template <class P> | ||
| 1408 | std::optional<std::pair<typename TextureCache<P>::Image*, std::pair<u32, u32>>> | ||
| 1409 | TextureCache<P>::ObtainImage(const Tegra::DMA::ImageOperand& operand, bool mark_as_modified) { | ||
| 1410 | ImageInfo dst_info(operand); | ||
| 1411 | ImageId dst_id = FindDMAImage(dst_info, operand.address); | ||
| 1412 | if (!dst_id) { | ||
| 1413 | return std::nullopt; | ||
| 1414 | } | ||
| 1415 | auto& image = slot_images[dst_id]; | ||
| 1416 | auto base = image.TryFindBase(operand.address); | ||
| 1417 | if (!base) { | ||
| 1418 | return std::nullopt; | ||
| 1419 | } | ||
| 1420 | if (False(image.flags & ImageFlagBits::GpuModified)) { | ||
| 1421 | // No need to waste time on an image that's synced with guest | ||
| 1422 | return std::nullopt; | ||
| 1423 | } | ||
| 1424 | PrepareImage(dst_id, mark_as_modified, false); | ||
| 1425 | auto& new_image = slot_images[dst_id]; | ||
| 1426 | lru_cache.Touch(new_image.lru_index, frame_tick); | ||
| 1427 | return std::make_pair(&new_image, std::make_pair(base->level, base->layer)); | ||
| 1428 | } | ||
| 1429 | |||
| 1430 | template <class P> | ||
| 1362 | SamplerId TextureCache<P>::FindSampler(const TSCEntry& config) { | 1431 | SamplerId TextureCache<P>::FindSampler(const TSCEntry& config) { |
| 1363 | if (std::ranges::all_of(config.raw, [](u64 value) { return value == 0; })) { | 1432 | if (std::ranges::all_of(config.raw, [](u64 value) { return value == 0; })) { |
| 1364 | return NULL_SAMPLER_ID; | 1433 | return NULL_SAMPLER_ID; |
diff --git a/src/video_core/texture_cache/texture_cache_base.h b/src/video_core/texture_cache/texture_cache_base.h index 013836933..848a5d9ea 100644 --- a/src/video_core/texture_cache/texture_cache_base.h +++ b/src/video_core/texture_cache/texture_cache_base.h | |||
| @@ -209,6 +209,9 @@ public: | |||
| 209 | /// Pop asynchronous downloads | 209 | /// Pop asynchronous downloads |
| 210 | void PopAsyncFlushes(); | 210 | void PopAsyncFlushes(); |
| 211 | 211 | ||
| 212 | [[nodiscard]] std::optional<std::pair<Image*, std::pair<u32, u32>>> ObtainImage( | ||
| 213 | const Tegra::DMA::ImageOperand& operand, bool mark_as_modified); | ||
| 214 | |||
| 212 | /// Return true when a CPU region is modified from the GPU | 215 | /// Return true when a CPU region is modified from the GPU |
| 213 | [[nodiscard]] bool IsRegionGpuModified(VAddr addr, size_t size); | 216 | [[nodiscard]] bool IsRegionGpuModified(VAddr addr, size_t size); |
| 214 | 217 | ||
| @@ -300,6 +303,8 @@ private: | |||
| 300 | /// Remove joined images from the cache | 303 | /// Remove joined images from the cache |
| 301 | [[nodiscard]] ImageId JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, VAddr cpu_addr); | 304 | [[nodiscard]] ImageId JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, VAddr cpu_addr); |
| 302 | 305 | ||
| 306 | [[nodiscard]] ImageId FindDMAImage(const ImageInfo& info, GPUVAddr gpu_addr); | ||
| 307 | |||
| 303 | /// Return a blit image pair from the given guest blit parameters | 308 | /// Return a blit image pair from the given guest blit parameters |
| 304 | [[nodiscard]] std::optional<BlitImages> GetBlitImages( | 309 | [[nodiscard]] std::optional<BlitImages> GetBlitImages( |
| 305 | const Tegra::Engines::Fermi2D::Surface& dst, const Tegra::Engines::Fermi2D::Surface& src, | 310 | const Tegra::Engines::Fermi2D::Surface& dst, const Tegra::Engines::Fermi2D::Surface& src, |
diff --git a/src/video_core/texture_cache/types.h b/src/video_core/texture_cache/types.h index 0453456b4..a0e10643f 100644 --- a/src/video_core/texture_cache/types.h +++ b/src/video_core/texture_cache/types.h | |||
| @@ -54,6 +54,7 @@ enum class RelaxedOptions : u32 { | |||
| 54 | Format = 1 << 1, | 54 | Format = 1 << 1, |
| 55 | Samples = 1 << 2, | 55 | Samples = 1 << 2, |
| 56 | ForceBrokenViews = 1 << 3, | 56 | ForceBrokenViews = 1 << 3, |
| 57 | FormatBpp = 1 << 4, | ||
| 57 | }; | 58 | }; |
| 58 | DECLARE_ENUM_FLAG_OPERATORS(RelaxedOptions) | 59 | DECLARE_ENUM_FLAG_OPERATORS(RelaxedOptions) |
| 59 | 60 | ||
diff --git a/src/video_core/texture_cache/util.cpp b/src/video_core/texture_cache/util.cpp index 697f86641..de37db684 100644 --- a/src/video_core/texture_cache/util.cpp +++ b/src/video_core/texture_cache/util.cpp | |||
| @@ -743,6 +743,44 @@ std::vector<ImageCopy> MakeShrinkImageCopies(const ImageInfo& dst, const ImageIn | |||
| 743 | return copies; | 743 | return copies; |
| 744 | } | 744 | } |
| 745 | 745 | ||
| 746 | std::vector<ImageCopy> MakeReinterpretImageCopies(const ImageInfo& src, u32 up_scale, | ||
| 747 | u32 down_shift) { | ||
| 748 | std::vector<ImageCopy> copies; | ||
| 749 | copies.reserve(src.resources.levels); | ||
| 750 | const bool is_3d = src.type == ImageType::e3D; | ||
| 751 | for (s32 level = 0; level < src.resources.levels; ++level) { | ||
| 752 | ImageCopy& copy = copies.emplace_back(); | ||
| 753 | copy.src_subresource = SubresourceLayers{ | ||
| 754 | .base_level = level, | ||
| 755 | .base_layer = 0, | ||
| 756 | .num_layers = src.resources.layers, | ||
| 757 | }; | ||
| 758 | copy.dst_subresource = SubresourceLayers{ | ||
| 759 | .base_level = level, | ||
| 760 | .base_layer = 0, | ||
| 761 | .num_layers = src.resources.layers, | ||
| 762 | }; | ||
| 763 | copy.src_offset = Offset3D{ | ||
| 764 | .x = 0, | ||
| 765 | .y = 0, | ||
| 766 | .z = 0, | ||
| 767 | }; | ||
| 768 | copy.dst_offset = Offset3D{ | ||
| 769 | .x = 0, | ||
| 770 | .y = 0, | ||
| 771 | .z = 0, | ||
| 772 | }; | ||
| 773 | const Extent3D mip_size = AdjustMipSize(src.size, level); | ||
| 774 | copy.extent = AdjustSamplesSize(mip_size, src.num_samples); | ||
| 775 | if (is_3d) { | ||
| 776 | copy.extent.depth = src.size.depth; | ||
| 777 | } | ||
| 778 | copy.extent.width = std::max<u32>((copy.extent.width * up_scale) >> down_shift, 1); | ||
| 779 | copy.extent.height = std::max<u32>((copy.extent.height * up_scale) >> down_shift, 1); | ||
| 780 | } | ||
| 781 | return copies; | ||
| 782 | } | ||
| 783 | |||
| 746 | bool IsValidEntry(const Tegra::MemoryManager& gpu_memory, const TICEntry& config) { | 784 | bool IsValidEntry(const Tegra::MemoryManager& gpu_memory, const TICEntry& config) { |
| 747 | const GPUVAddr address = config.Address(); | 785 | const GPUVAddr address = config.Address(); |
| 748 | if (address == 0) { | 786 | if (address == 0) { |
| @@ -999,6 +1037,20 @@ bool IsBlockLinearSizeCompatible(const ImageInfo& lhs, const ImageInfo& rhs, u32 | |||
| 999 | } | 1037 | } |
| 1000 | } | 1038 | } |
| 1001 | 1039 | ||
| 1040 | bool IsBlockLinearSizeCompatibleBPPRelaxed(const ImageInfo& lhs, const ImageInfo& rhs, | ||
| 1041 | u32 lhs_level, u32 rhs_level) noexcept { | ||
| 1042 | ASSERT(lhs.type != ImageType::Linear); | ||
| 1043 | ASSERT(rhs.type != ImageType::Linear); | ||
| 1044 | const auto lhs_bpp = BytesPerBlock(lhs.format); | ||
| 1045 | const auto rhs_bpp = BytesPerBlock(rhs.format); | ||
| 1046 | const Extent3D lhs_size = AdjustMipSize(lhs.size, lhs_level); | ||
| 1047 | const Extent3D rhs_size = AdjustMipSize(rhs.size, rhs_level); | ||
| 1048 | return Common::AlignUpLog2(lhs_size.width * lhs_bpp, GOB_SIZE_X_SHIFT) == | ||
| 1049 | Common::AlignUpLog2(rhs_size.width * rhs_bpp, GOB_SIZE_X_SHIFT) && | ||
| 1050 | Common::AlignUpLog2(lhs_size.height, GOB_SIZE_Y_SHIFT) == | ||
| 1051 | Common::AlignUpLog2(rhs_size.height, GOB_SIZE_Y_SHIFT); | ||
| 1052 | } | ||
| 1053 | |||
| 1002 | bool IsPitchLinearSameSize(const ImageInfo& lhs, const ImageInfo& rhs, bool strict_size) noexcept { | 1054 | bool IsPitchLinearSameSize(const ImageInfo& lhs, const ImageInfo& rhs, bool strict_size) noexcept { |
| 1003 | ASSERT(lhs.type == ImageType::Linear); | 1055 | ASSERT(lhs.type == ImageType::Linear); |
| 1004 | ASSERT(rhs.type == ImageType::Linear); | 1056 | ASSERT(rhs.type == ImageType::Linear); |
| @@ -1073,7 +1125,8 @@ std::optional<SubresourceBase> FindSubresource(const ImageInfo& candidate, const | |||
| 1073 | // Format checking is relaxed, but we still have to check for matching bytes per block. | 1125 | // Format checking is relaxed, but we still have to check for matching bytes per block. |
| 1074 | // This avoids creating a view for blits on UE4 titles where formats with different bytes | 1126 | // This avoids creating a view for blits on UE4 titles where formats with different bytes |
| 1075 | // per block are aliased. | 1127 | // per block are aliased. |
| 1076 | if (BytesPerBlock(existing.format) != BytesPerBlock(candidate.format)) { | 1128 | if (BytesPerBlock(existing.format) != BytesPerBlock(candidate.format) && |
| 1129 | False(options & RelaxedOptions::FormatBpp)) { | ||
| 1077 | return std::nullopt; | 1130 | return std::nullopt; |
| 1078 | } | 1131 | } |
| 1079 | } else { | 1132 | } else { |
| @@ -1088,10 +1141,8 @@ std::optional<SubresourceBase> FindSubresource(const ImageInfo& candidate, const | |||
| 1088 | if (existing.type != candidate.type) { | 1141 | if (existing.type != candidate.type) { |
| 1089 | return std::nullopt; | 1142 | return std::nullopt; |
| 1090 | } | 1143 | } |
| 1091 | if (False(options & RelaxedOptions::Samples)) { | 1144 | if (False(options & RelaxedOptions::Samples) && existing.num_samples != candidate.num_samples) { |
| 1092 | if (existing.num_samples != candidate.num_samples) { | 1145 | return std::nullopt; |
| 1093 | return std::nullopt; | ||
| 1094 | } | ||
| 1095 | } | 1146 | } |
| 1096 | if (existing.resources.levels < candidate.resources.levels + base->level) { | 1147 | if (existing.resources.levels < candidate.resources.levels + base->level) { |
| 1097 | return std::nullopt; | 1148 | return std::nullopt; |
| @@ -1101,14 +1152,16 @@ std::optional<SubresourceBase> FindSubresource(const ImageInfo& candidate, const | |||
| 1101 | if (mip_depth < candidate.size.depth + base->layer) { | 1152 | if (mip_depth < candidate.size.depth + base->layer) { |
| 1102 | return std::nullopt; | 1153 | return std::nullopt; |
| 1103 | } | 1154 | } |
| 1104 | } else { | 1155 | } else if (existing.resources.layers < candidate.resources.layers + base->layer) { |
| 1105 | if (existing.resources.layers < candidate.resources.layers + base->layer) { | 1156 | return std::nullopt; |
| 1106 | return std::nullopt; | ||
| 1107 | } | ||
| 1108 | } | 1157 | } |
| 1109 | const bool strict_size = False(options & RelaxedOptions::Size); | 1158 | const bool strict_size = False(options & RelaxedOptions::Size); |
| 1110 | if (!IsBlockLinearSizeCompatible(existing, candidate, base->level, 0, strict_size)) { | 1159 | if (!IsBlockLinearSizeCompatible(existing, candidate, base->level, 0, strict_size)) { |
| 1111 | return std::nullopt; | 1160 | if (False(options & RelaxedOptions::FormatBpp)) { |
| 1161 | return std::nullopt; | ||
| 1162 | } else if (!IsBlockLinearSizeCompatibleBPPRelaxed(existing, candidate, base->level, 0)) { | ||
| 1163 | return std::nullopt; | ||
| 1164 | } | ||
| 1112 | } | 1165 | } |
| 1113 | // TODO: compare block sizes | 1166 | // TODO: compare block sizes |
| 1114 | return base; | 1167 | return base; |
| @@ -1120,6 +1173,31 @@ bool IsSubresource(const ImageInfo& candidate, const ImageBase& image, GPUVAddr | |||
| 1120 | .has_value(); | 1173 | .has_value(); |
| 1121 | } | 1174 | } |
| 1122 | 1175 | ||
| 1176 | bool IsSubCopy(const ImageInfo& candidate, const ImageBase& image, GPUVAddr candidate_addr) { | ||
| 1177 | const std::optional<SubresourceBase> base = image.TryFindBase(candidate_addr); | ||
| 1178 | if (!base) { | ||
| 1179 | return false; | ||
| 1180 | } | ||
| 1181 | const ImageInfo& existing = image.info; | ||
| 1182 | if (existing.resources.levels < candidate.resources.levels + base->level) { | ||
| 1183 | return false; | ||
| 1184 | } | ||
| 1185 | if (existing.type == ImageType::e3D) { | ||
| 1186 | const u32 mip_depth = std::max(1U, existing.size.depth << base->level); | ||
| 1187 | if (mip_depth < candidate.size.depth + base->layer) { | ||
| 1188 | return false; | ||
| 1189 | } | ||
| 1190 | } else { | ||
| 1191 | if (existing.resources.layers < candidate.resources.layers + base->layer) { | ||
| 1192 | return false; | ||
| 1193 | } | ||
| 1194 | } | ||
| 1195 | if (!IsBlockLinearSizeCompatibleBPPRelaxed(existing, candidate, base->level, 0)) { | ||
| 1196 | return false; | ||
| 1197 | } | ||
| 1198 | return true; | ||
| 1199 | } | ||
| 1200 | |||
| 1123 | void DeduceBlitImages(ImageInfo& dst_info, ImageInfo& src_info, const ImageBase* dst, | 1201 | void DeduceBlitImages(ImageInfo& dst_info, ImageInfo& src_info, const ImageBase* dst, |
| 1124 | const ImageBase* src) { | 1202 | const ImageBase* src) { |
| 1125 | const auto original_dst_format = dst_info.format; | 1203 | const auto original_dst_format = dst_info.format; |
diff --git a/src/video_core/texture_cache/util.h b/src/video_core/texture_cache/util.h index d103db8ae..84aa6880d 100644 --- a/src/video_core/texture_cache/util.h +++ b/src/video_core/texture_cache/util.h | |||
| @@ -56,6 +56,10 @@ struct OverlapResult { | |||
| 56 | SubresourceBase base, u32 up_scale = 1, | 56 | SubresourceBase base, u32 up_scale = 1, |
| 57 | u32 down_shift = 0); | 57 | u32 down_shift = 0); |
| 58 | 58 | ||
| 59 | [[nodiscard]] std::vector<ImageCopy> MakeReinterpretImageCopies(const ImageInfo& src, | ||
| 60 | u32 up_scale = 1, | ||
| 61 | u32 down_shift = 0); | ||
| 62 | |||
| 59 | [[nodiscard]] bool IsValidEntry(const Tegra::MemoryManager& gpu_memory, const TICEntry& config); | 63 | [[nodiscard]] bool IsValidEntry(const Tegra::MemoryManager& gpu_memory, const TICEntry& config); |
| 60 | 64 | ||
| 61 | [[nodiscard]] std::vector<BufferImageCopy> UnswizzleImage(Tegra::MemoryManager& gpu_memory, | 65 | [[nodiscard]] std::vector<BufferImageCopy> UnswizzleImage(Tegra::MemoryManager& gpu_memory, |
| @@ -88,6 +92,9 @@ void SwizzleImage(Tegra::MemoryManager& gpu_memory, GPUVAddr gpu_addr, const Ima | |||
| 88 | [[nodiscard]] bool IsPitchLinearSameSize(const ImageInfo& lhs, const ImageInfo& rhs, | 92 | [[nodiscard]] bool IsPitchLinearSameSize(const ImageInfo& lhs, const ImageInfo& rhs, |
| 89 | bool strict_size) noexcept; | 93 | bool strict_size) noexcept; |
| 90 | 94 | ||
| 95 | [[nodiscard]] bool IsBlockLinearSizeCompatibleBPPRelaxed(const ImageInfo& lhs, const ImageInfo& rhs, | ||
| 96 | u32 lhs_level, u32 rhs_level) noexcept; | ||
| 97 | |||
| 91 | [[nodiscard]] std::optional<OverlapResult> ResolveOverlap(const ImageInfo& new_info, | 98 | [[nodiscard]] std::optional<OverlapResult> ResolveOverlap(const ImageInfo& new_info, |
| 92 | GPUVAddr gpu_addr, VAddr cpu_addr, | 99 | GPUVAddr gpu_addr, VAddr cpu_addr, |
| 93 | const ImageBase& overlap, | 100 | const ImageBase& overlap, |
| @@ -106,6 +113,9 @@ void SwizzleImage(Tegra::MemoryManager& gpu_memory, GPUVAddr gpu_addr, const Ima | |||
| 106 | GPUVAddr candidate_addr, RelaxedOptions options, bool broken_views, | 113 | GPUVAddr candidate_addr, RelaxedOptions options, bool broken_views, |
| 107 | bool native_bgr); | 114 | bool native_bgr); |
| 108 | 115 | ||
| 116 | [[nodiscard]] bool IsSubCopy(const ImageInfo& candidate, const ImageBase& image, | ||
| 117 | GPUVAddr candidate_addr); | ||
| 118 | |||
| 109 | void DeduceBlitImages(ImageInfo& dst_info, ImageInfo& src_info, const ImageBase* dst, | 119 | void DeduceBlitImages(ImageInfo& dst_info, ImageInfo& src_info, const ImageBase* dst, |
| 110 | const ImageBase* src); | 120 | const ImageBase* src); |
| 111 | 121 | ||