diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | src/core/hid/emulated_controller.cpp | 4 | ||||
| -rw-r--r-- | src/core/hle/service/am/am.cpp | 2 | ||||
| -rw-r--r-- | src/core/hle/service/nfp/nfp.cpp | 187 | ||||
| -rw-r--r-- | src/core/hle/service/nfp/nfp_device.cpp | 224 | ||||
| -rw-r--r-- | src/core/hle/service/nfp/nfp_device.h | 12 | ||||
| -rw-r--r-- | src/core/hle/service/nfp/nfp_interface.cpp (renamed from src/core/hle/service/nfp/nfp_user.cpp) | 495 | ||||
| -rw-r--r-- | src/core/hle/service/nfp/nfp_interface.h (renamed from src/core/hle/service/nfp/nfp_user.h) | 36 | ||||
| -rw-r--r-- | src/core/hle/service/nfp/nfp_types.h | 54 | ||||
| -rw-r--r-- | src/dedicated_room/yuzu_room.cpp | 16 | ||||
| -rw-r--r-- | src/video_core/engines/fermi_2d.cpp | 16 | ||||
| -rw-r--r-- | src/video_core/engines/maxwell_3d.cpp | 10 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_master_semaphore.cpp | 139 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_master_semaphore.h | 48 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_scheduler.cpp | 36 | ||||
| -rw-r--r-- | src/video_core/vulkan_common/vulkan_device.h | 6 |
16 files changed, 1135 insertions, 154 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 4e677f287..8817a99c9 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -570,10 +570,10 @@ add_library(core STATIC | |||
| 570 | hle/service/nfp/nfp.h | 570 | hle/service/nfp/nfp.h |
| 571 | hle/service/nfp/nfp_device.cpp | 571 | hle/service/nfp/nfp_device.cpp |
| 572 | hle/service/nfp/nfp_device.h | 572 | hle/service/nfp/nfp_device.h |
| 573 | hle/service/nfp/nfp_interface.cpp | ||
| 574 | hle/service/nfp/nfp_interface.h | ||
| 573 | hle/service/nfp/nfp_result.h | 575 | hle/service/nfp/nfp_result.h |
| 574 | hle/service/nfp/nfp_types.h | 576 | hle/service/nfp/nfp_types.h |
| 575 | hle/service/nfp/nfp_user.cpp | ||
| 576 | hle/service/nfp/nfp_user.h | ||
| 577 | hle/service/ngct/ngct.cpp | 577 | hle/service/ngct/ngct.cpp |
| 578 | hle/service/ngct/ngct.h | 578 | hle/service/ngct/ngct.h |
| 579 | hle/service/nifm/nifm.cpp | 579 | hle/service/nifm/nifm.cpp |
diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index a29c9a6f8..a70f8807c 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp | |||
| @@ -280,6 +280,10 @@ void EmulatedController::LoadVirtualGamepadParams() { | |||
| 280 | virtual_stick_params[Settings::NativeAnalog::LStick].Set("axis_y", 1); | 280 | virtual_stick_params[Settings::NativeAnalog::LStick].Set("axis_y", 1); |
| 281 | virtual_stick_params[Settings::NativeAnalog::RStick].Set("axis_x", 2); | 281 | virtual_stick_params[Settings::NativeAnalog::RStick].Set("axis_x", 2); |
| 282 | virtual_stick_params[Settings::NativeAnalog::RStick].Set("axis_y", 3); | 282 | virtual_stick_params[Settings::NativeAnalog::RStick].Set("axis_y", 3); |
| 283 | virtual_stick_params[Settings::NativeAnalog::LStick].Set("deadzone", 0.0f); | ||
| 284 | virtual_stick_params[Settings::NativeAnalog::LStick].Set("range", 1.0f); | ||
| 285 | virtual_stick_params[Settings::NativeAnalog::RStick].Set("deadzone", 0.0f); | ||
| 286 | virtual_stick_params[Settings::NativeAnalog::RStick].Set("range", 1.0f); | ||
| 283 | } | 287 | } |
| 284 | 288 | ||
| 285 | void EmulatedController::ReloadInput() { | 289 | void EmulatedController::ReloadInput() { |
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index a17c46121..e59de844c 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp | |||
| @@ -1807,7 +1807,7 @@ void IApplicationFunctions::GetFriendInvitationStorageChannelEvent(HLERequestCon | |||
| 1807 | } | 1807 | } |
| 1808 | 1808 | ||
| 1809 | void IApplicationFunctions::TryPopFromFriendInvitationStorageChannel(HLERequestContext& ctx) { | 1809 | void IApplicationFunctions::TryPopFromFriendInvitationStorageChannel(HLERequestContext& ctx) { |
| 1810 | LOG_WARNING(Service_AM, "(STUBBED) called"); | 1810 | LOG_DEBUG(Service_AM, "(STUBBED) called"); |
| 1811 | 1811 | ||
| 1812 | IPC::ResponseBuilder rb{ctx, 2}; | 1812 | IPC::ResponseBuilder rb{ctx, 2}; |
| 1813 | rb.Push(AM::ResultNoDataInChannel); | 1813 | rb.Push(AM::ResultNoDataInChannel); |
diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp index e262dc2f2..2714f4bea 100644 --- a/src/core/hle/service/nfp/nfp.cpp +++ b/src/core/hle/service/nfp/nfp.cpp | |||
| @@ -4,11 +4,138 @@ | |||
| 4 | #include "common/logging/log.h" | 4 | #include "common/logging/log.h" |
| 5 | #include "core/hle/service/ipc_helpers.h" | 5 | #include "core/hle/service/ipc_helpers.h" |
| 6 | #include "core/hle/service/nfp/nfp.h" | 6 | #include "core/hle/service/nfp/nfp.h" |
| 7 | #include "core/hle/service/nfp/nfp_user.h" | 7 | #include "core/hle/service/nfp/nfp_interface.h" |
| 8 | #include "core/hle/service/server_manager.h" | 8 | #include "core/hle/service/server_manager.h" |
| 9 | 9 | ||
| 10 | namespace Service::NFP { | 10 | namespace Service::NFP { |
| 11 | 11 | ||
| 12 | class IUser final : public Interface { | ||
| 13 | public: | ||
| 14 | explicit IUser(Core::System& system_) : Interface(system_, "NFP:IUser") { | ||
| 15 | // clang-format off | ||
| 16 | static const FunctionInfo functions[] = { | ||
| 17 | {0, &IUser::Initialize, "Initialize"}, | ||
| 18 | {1, &IUser::Finalize, "Finalize"}, | ||
| 19 | {2, &IUser::ListDevices, "ListDevices"}, | ||
| 20 | {3, &IUser::StartDetection, "StartDetection"}, | ||
| 21 | {4, &IUser::StopDetection, "StopDetection"}, | ||
| 22 | {5, &IUser::Mount, "Mount"}, | ||
| 23 | {6, &IUser::Unmount, "Unmount"}, | ||
| 24 | {7, &IUser::OpenApplicationArea, "OpenApplicationArea"}, | ||
| 25 | {8, &IUser::GetApplicationArea, "GetApplicationArea"}, | ||
| 26 | {9, &IUser::SetApplicationArea, "SetApplicationArea"}, | ||
| 27 | {10, &IUser::Flush, "Flush"}, | ||
| 28 | {11, &IUser::Restore, "Restore"}, | ||
| 29 | {12, &IUser::CreateApplicationArea, "CreateApplicationArea"}, | ||
| 30 | {13, &IUser::GetTagInfo, "GetTagInfo"}, | ||
| 31 | {14, &IUser::GetRegisterInfo, "GetRegisterInfo"}, | ||
| 32 | {15, &IUser::GetCommonInfo, "GetCommonInfo"}, | ||
| 33 | {16, &IUser::GetModelInfo, "GetModelInfo"}, | ||
| 34 | {17, &IUser::AttachActivateEvent, "AttachActivateEvent"}, | ||
| 35 | {18, &IUser::AttachDeactivateEvent, "AttachDeactivateEvent"}, | ||
| 36 | {19, &IUser::GetState, "GetState"}, | ||
| 37 | {20, &IUser::GetDeviceState, "GetDeviceState"}, | ||
| 38 | {21, &IUser::GetNpadId, "GetNpadId"}, | ||
| 39 | {22, &IUser::GetApplicationAreaSize, "GetApplicationAreaSize"}, | ||
| 40 | {23, &IUser::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"}, | ||
| 41 | {24, &IUser::RecreateApplicationArea, "RecreateApplicationArea"}, | ||
| 42 | }; | ||
| 43 | // clang-format on | ||
| 44 | |||
| 45 | RegisterHandlers(functions); | ||
| 46 | } | ||
| 47 | }; | ||
| 48 | |||
| 49 | class ISystem final : public Interface { | ||
| 50 | public: | ||
| 51 | explicit ISystem(Core::System& system_) : Interface(system_, "NFP:ISystem") { | ||
| 52 | // clang-format off | ||
| 53 | static const FunctionInfo functions[] = { | ||
| 54 | {0, &ISystem::InitializeSystem, "InitializeSystem"}, | ||
| 55 | {1, &ISystem::FinalizeSystem, "FinalizeSystem"}, | ||
| 56 | {2, &ISystem::ListDevices, "ListDevices"}, | ||
| 57 | {3, &ISystem::StartDetection, "StartDetection"}, | ||
| 58 | {4, &ISystem::StopDetection, "StopDetection"}, | ||
| 59 | {5, &ISystem::Mount, "Mount"}, | ||
| 60 | {6, &ISystem::Unmount, "Unmount"}, | ||
| 61 | {10, &ISystem::Flush, "Flush"}, | ||
| 62 | {11, &ISystem::Restore, "Restore"}, | ||
| 63 | {12, &ISystem::CreateApplicationArea, "CreateApplicationArea"}, | ||
| 64 | {13, &ISystem::GetTagInfo, "GetTagInfo"}, | ||
| 65 | {14, &ISystem::GetRegisterInfo, "GetRegisterInfo"}, | ||
| 66 | {15, &ISystem::GetCommonInfo, "GetCommonInfo"}, | ||
| 67 | {16, &ISystem::GetModelInfo, "GetModelInfo"}, | ||
| 68 | {17, &ISystem::AttachActivateEvent, "AttachActivateEvent"}, | ||
| 69 | {18, &ISystem::AttachDeactivateEvent, "AttachDeactivateEvent"}, | ||
| 70 | {19, &ISystem::GetState, "GetState"}, | ||
| 71 | {20, &ISystem::GetDeviceState, "GetDeviceState"}, | ||
| 72 | {21, &ISystem::GetNpadId, "GetNpadId"}, | ||
| 73 | {23, &ISystem::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"}, | ||
| 74 | {100, &ISystem::Format, "Format"}, | ||
| 75 | {101, &ISystem::GetAdminInfo, "GetAdminInfo"}, | ||
| 76 | {102, &ISystem::GetRegisterInfoPrivate, "GetRegisterInfoPrivate"}, | ||
| 77 | {103, &ISystem::SetRegisterInfoPrivate, "SetRegisterInfoPrivate"}, | ||
| 78 | {104, &ISystem::DeleteRegisterInfo, "DeleteRegisterInfo"}, | ||
| 79 | {105, &ISystem::DeleteApplicationArea, "DeleteApplicationArea"}, | ||
| 80 | {106, &ISystem::ExistsApplicationArea, "ExistsApplicationArea"}, | ||
| 81 | }; | ||
| 82 | // clang-format on | ||
| 83 | |||
| 84 | RegisterHandlers(functions); | ||
| 85 | } | ||
| 86 | }; | ||
| 87 | |||
| 88 | class IDebug final : public Interface { | ||
| 89 | public: | ||
| 90 | explicit IDebug(Core::System& system_) : Interface(system_, "NFP:IDebug") { | ||
| 91 | // clang-format off | ||
| 92 | static const FunctionInfo functions[] = { | ||
| 93 | {0, &IDebug::InitializeDebug, "InitializeDebug"}, | ||
| 94 | {1, &IDebug::FinalizeDebug, "FinalizeDebug"}, | ||
| 95 | {2, &IDebug::ListDevices, "ListDevices"}, | ||
| 96 | {3, &IDebug::StartDetection, "StartDetection"}, | ||
| 97 | {4, &IDebug::StopDetection, "StopDetection"}, | ||
| 98 | {5, &IDebug::Mount, "Mount"}, | ||
| 99 | {6, &IDebug::Unmount, "Unmount"}, | ||
| 100 | {7, &IDebug::OpenApplicationArea, "OpenApplicationArea"}, | ||
| 101 | {8, &IDebug::GetApplicationArea, "GetApplicationArea"}, | ||
| 102 | {9, &IDebug::SetApplicationArea, "SetApplicationArea"}, | ||
| 103 | {10, &IDebug::Flush, "Flush"}, | ||
| 104 | {11, &IDebug::Restore, "Restore"}, | ||
| 105 | {12, &IDebug::CreateApplicationArea, "CreateApplicationArea"}, | ||
| 106 | {13, &IDebug::GetTagInfo, "GetTagInfo"}, | ||
| 107 | {14, &IDebug::GetRegisterInfo, "GetRegisterInfo"}, | ||
| 108 | {15, &IDebug::GetCommonInfo, "GetCommonInfo"}, | ||
| 109 | {16, &IDebug::GetModelInfo, "GetModelInfo"}, | ||
| 110 | {17, &IDebug::AttachActivateEvent, "AttachActivateEvent"}, | ||
| 111 | {18, &IDebug::AttachDeactivateEvent, "AttachDeactivateEvent"}, | ||
| 112 | {19, &IDebug::GetState, "GetState"}, | ||
| 113 | {20, &IDebug::GetDeviceState, "GetDeviceState"}, | ||
| 114 | {21, &IDebug::GetNpadId, "GetNpadId"}, | ||
| 115 | {22, &IDebug::GetApplicationAreaSize, "GetApplicationAreaSize"}, | ||
| 116 | {23, &IDebug::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"}, | ||
| 117 | {24, &IDebug::RecreateApplicationArea, "RecreateApplicationArea"}, | ||
| 118 | {100, &IDebug::Format, "Format"}, | ||
| 119 | {101, &IDebug::GetAdminInfo, "GetAdminInfo"}, | ||
| 120 | {102, &IDebug::GetRegisterInfoPrivate, "GetRegisterInfoPrivate"}, | ||
| 121 | {103, &IDebug::SetRegisterInfoPrivate, "SetRegisterInfoPrivate"}, | ||
| 122 | {104, &IDebug::DeleteRegisterInfo, "DeleteRegisterInfo"}, | ||
| 123 | {105, &IDebug::DeleteApplicationArea, "DeleteApplicationArea"}, | ||
| 124 | {106, &IDebug::ExistsApplicationArea, "ExistsApplicationArea"}, | ||
| 125 | {200, &IDebug::GetAll, "GetAll"}, | ||
| 126 | {201, &IDebug::SetAll, "SetAll"}, | ||
| 127 | {202, &IDebug::FlushDebug, "FlushDebug"}, | ||
| 128 | {203, &IDebug::BreakTag, "BreakTag"}, | ||
| 129 | {204, nullptr, "ReadBackupData"}, | ||
| 130 | {205, nullptr, "WriteBackupData"}, | ||
| 131 | {206, nullptr, "WriteNtf"}, | ||
| 132 | }; | ||
| 133 | // clang-format on | ||
| 134 | |||
| 135 | RegisterHandlers(functions); | ||
| 136 | } | ||
| 137 | }; | ||
| 138 | |||
| 12 | class IUserManager final : public ServiceFramework<IUserManager> { | 139 | class IUserManager final : public ServiceFramework<IUserManager> { |
| 13 | public: | 140 | public: |
| 14 | explicit IUserManager(Core::System& system_) : ServiceFramework{system_, "nfp:user"} { | 141 | explicit IUserManager(Core::System& system_) : ServiceFramework{system_, "nfp:user"} { |
| @@ -37,10 +164,68 @@ private: | |||
| 37 | std::shared_ptr<IUser> user_interface; | 164 | std::shared_ptr<IUser> user_interface; |
| 38 | }; | 165 | }; |
| 39 | 166 | ||
| 167 | class ISystemManager final : public ServiceFramework<ISystemManager> { | ||
| 168 | public: | ||
| 169 | explicit ISystemManager(Core::System& system_) : ServiceFramework{system_, "nfp:sys"} { | ||
| 170 | // clang-format off | ||
| 171 | static const FunctionInfo functions[] = { | ||
| 172 | {0, &ISystemManager::CreateSystemInterface, "CreateSystemInterface"}, | ||
| 173 | }; | ||
| 174 | // clang-format on | ||
| 175 | |||
| 176 | RegisterHandlers(functions); | ||
| 177 | } | ||
| 178 | |||
| 179 | private: | ||
| 180 | void CreateSystemInterface(HLERequestContext& ctx) { | ||
| 181 | LOG_DEBUG(Service_NFP, "called"); | ||
| 182 | |||
| 183 | if (system_interface == nullptr) { | ||
| 184 | system_interface = std::make_shared<ISystem>(system); | ||
| 185 | } | ||
| 186 | |||
| 187 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 188 | rb.Push(ResultSuccess); | ||
| 189 | rb.PushIpcInterface<ISystem>(system_interface); | ||
| 190 | } | ||
| 191 | |||
| 192 | std::shared_ptr<ISystem> system_interface; | ||
| 193 | }; | ||
| 194 | |||
| 195 | class IDebugManager final : public ServiceFramework<IDebugManager> { | ||
| 196 | public: | ||
| 197 | explicit IDebugManager(Core::System& system_) : ServiceFramework{system_, "nfp:dbg"} { | ||
| 198 | // clang-format off | ||
| 199 | static const FunctionInfo functions[] = { | ||
| 200 | {0, &IDebugManager::CreateDebugInterface, "CreateDebugInterface"}, | ||
| 201 | }; | ||
| 202 | // clang-format on | ||
| 203 | |||
| 204 | RegisterHandlers(functions); | ||
| 205 | } | ||
| 206 | |||
| 207 | private: | ||
| 208 | void CreateDebugInterface(HLERequestContext& ctx) { | ||
| 209 | LOG_DEBUG(Service_NFP, "called"); | ||
| 210 | |||
| 211 | if (system_interface == nullptr) { | ||
| 212 | system_interface = std::make_shared<IDebug>(system); | ||
| 213 | } | ||
| 214 | |||
| 215 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | ||
| 216 | rb.Push(ResultSuccess); | ||
| 217 | rb.PushIpcInterface<IDebug>(system_interface); | ||
| 218 | } | ||
| 219 | |||
| 220 | std::shared_ptr<IDebug> system_interface; | ||
| 221 | }; | ||
| 222 | |||
| 40 | void LoopProcess(Core::System& system) { | 223 | void LoopProcess(Core::System& system) { |
| 41 | auto server_manager = std::make_unique<ServerManager>(system); | 224 | auto server_manager = std::make_unique<ServerManager>(system); |
| 42 | 225 | ||
| 43 | server_manager->RegisterNamedService("nfp:user", std::make_shared<IUserManager>(system)); | 226 | server_manager->RegisterNamedService("nfp:user", std::make_shared<IUserManager>(system)); |
| 227 | server_manager->RegisterNamedService("nfp:sys", std::make_shared<ISystemManager>(system)); | ||
| 228 | server_manager->RegisterNamedService("nfp:dbg", std::make_shared<IDebugManager>(system)); | ||
| 44 | ServerManager::RunServer(std::move(server_manager)); | 229 | ServerManager::RunServer(std::move(server_manager)); |
| 45 | } | 230 | } |
| 46 | 231 | ||
diff --git a/src/core/hle/service/nfp/nfp_device.cpp b/src/core/hle/service/nfp/nfp_device.cpp index 607e70968..3f9af53c8 100644 --- a/src/core/hle/service/nfp/nfp_device.cpp +++ b/src/core/hle/service/nfp/nfp_device.cpp | |||
| @@ -29,7 +29,6 @@ | |||
| 29 | #include "core/hle/service/nfp/amiibo_crypto.h" | 29 | #include "core/hle/service/nfp/amiibo_crypto.h" |
| 30 | #include "core/hle/service/nfp/nfp_device.h" | 30 | #include "core/hle/service/nfp/nfp_device.h" |
| 31 | #include "core/hle/service/nfp/nfp_result.h" | 31 | #include "core/hle/service/nfp/nfp_result.h" |
| 32 | #include "core/hle/service/nfp/nfp_user.h" | ||
| 33 | #include "core/hle/service/time/time_manager.h" | 32 | #include "core/hle/service/time/time_manager.h" |
| 34 | #include "core/hle/service/time/time_zone_content_manager.h" | 33 | #include "core/hle/service/time/time_zone_content_manager.h" |
| 35 | #include "core/hle/service/time/time_zone_types.h" | 34 | #include "core/hle/service/time/time_zone_types.h" |
| @@ -241,6 +240,42 @@ Result NfpDevice::Flush() { | |||
| 241 | 240 | ||
| 242 | tag_data.write_counter++; | 241 | tag_data.write_counter++; |
| 243 | 242 | ||
| 243 | FlushWithBreak(BreakType::Normal); | ||
| 244 | |||
| 245 | is_data_moddified = false; | ||
| 246 | |||
| 247 | return ResultSuccess; | ||
| 248 | } | ||
| 249 | |||
| 250 | Result NfpDevice::FlushDebug() { | ||
| 251 | if (device_state != DeviceState::TagMounted) { | ||
| 252 | LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); | ||
| 253 | if (device_state == DeviceState::TagRemoved) { | ||
| 254 | return TagRemoved; | ||
| 255 | } | ||
| 256 | return WrongDeviceState; | ||
| 257 | } | ||
| 258 | |||
| 259 | if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { | ||
| 260 | LOG_ERROR(Service_NFC, "Amiibo is read only", device_state); | ||
| 261 | return WrongDeviceState; | ||
| 262 | } | ||
| 263 | |||
| 264 | tag_data.write_counter++; | ||
| 265 | |||
| 266 | FlushWithBreak(BreakType::Normal); | ||
| 267 | |||
| 268 | is_data_moddified = false; | ||
| 269 | |||
| 270 | return ResultSuccess; | ||
| 271 | } | ||
| 272 | |||
| 273 | Result NfpDevice::FlushWithBreak(BreakType break_type) { | ||
| 274 | if (break_type != BreakType::Normal) { | ||
| 275 | LOG_ERROR(Service_NFC, "Break type not implemented {}", break_type); | ||
| 276 | return WrongDeviceState; | ||
| 277 | } | ||
| 278 | |||
| 244 | std::vector<u8> data(sizeof(EncryptedNTAG215File)); | 279 | std::vector<u8> data(sizeof(EncryptedNTAG215File)); |
| 245 | if (is_plain_amiibo) { | 280 | if (is_plain_amiibo) { |
| 246 | memcpy(data.data(), &tag_data, sizeof(tag_data)); | 281 | memcpy(data.data(), &tag_data, sizeof(tag_data)); |
| @@ -258,8 +293,6 @@ Result NfpDevice::Flush() { | |||
| 258 | return WriteAmiiboFailed; | 293 | return WriteAmiiboFailed; |
| 259 | } | 294 | } |
| 260 | 295 | ||
| 261 | is_data_moddified = false; | ||
| 262 | |||
| 263 | return ResultSuccess; | 296 | return ResultSuccess; |
| 264 | } | 297 | } |
| 265 | 298 | ||
| @@ -417,6 +450,38 @@ Result NfpDevice::GetRegisterInfo(RegisterInfo& register_info) const { | |||
| 417 | return ResultSuccess; | 450 | return ResultSuccess; |
| 418 | } | 451 | } |
| 419 | 452 | ||
| 453 | Result NfpDevice::GetRegisterInfoPrivate(RegisterInfoPrivate& register_info) const { | ||
| 454 | if (device_state != DeviceState::TagMounted) { | ||
| 455 | LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); | ||
| 456 | if (device_state == DeviceState::TagRemoved) { | ||
| 457 | return TagRemoved; | ||
| 458 | } | ||
| 459 | return WrongDeviceState; | ||
| 460 | } | ||
| 461 | |||
| 462 | if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { | ||
| 463 | LOG_ERROR(Service_NFP, "Amiibo is read only", device_state); | ||
| 464 | return WrongDeviceState; | ||
| 465 | } | ||
| 466 | |||
| 467 | if (tag_data.settings.settings.amiibo_initialized == 0) { | ||
| 468 | return RegistrationIsNotInitialized; | ||
| 469 | } | ||
| 470 | |||
| 471 | Service::Mii::MiiManager manager; | ||
| 472 | const auto& settings = tag_data.settings; | ||
| 473 | |||
| 474 | // TODO: Validate and complete this data | ||
| 475 | register_info = { | ||
| 476 | .mii_store_data = {}, | ||
| 477 | .creation_date = settings.init_date.GetWriteDate(), | ||
| 478 | .amiibo_name = GetAmiiboName(settings), | ||
| 479 | .font_region = settings.settings.font_region, | ||
| 480 | }; | ||
| 481 | |||
| 482 | return ResultSuccess; | ||
| 483 | } | ||
| 484 | |||
| 420 | Result NfpDevice::GetAdminInfo(AdminInfo& admin_info) const { | 485 | Result NfpDevice::GetAdminInfo(AdminInfo& admin_info) const { |
| 421 | if (device_state != DeviceState::TagMounted) { | 486 | if (device_state != DeviceState::TagMounted) { |
| 422 | LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); | 487 | LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); |
| @@ -807,6 +872,159 @@ Result NfpDevice::DeleteApplicationArea() { | |||
| 807 | return Flush(); | 872 | return Flush(); |
| 808 | } | 873 | } |
| 809 | 874 | ||
| 875 | Result NfpDevice::ExistApplicationArea(bool& has_application_area) { | ||
| 876 | if (device_state != DeviceState::TagMounted) { | ||
| 877 | LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); | ||
| 878 | if (device_state == DeviceState::TagRemoved) { | ||
| 879 | return TagRemoved; | ||
| 880 | } | ||
| 881 | return WrongDeviceState; | ||
| 882 | } | ||
| 883 | |||
| 884 | if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { | ||
| 885 | LOG_ERROR(Service_NFC, "Amiibo is read only", device_state); | ||
| 886 | return WrongDeviceState; | ||
| 887 | } | ||
| 888 | |||
| 889 | has_application_area = tag_data.settings.settings.appdata_initialized.Value() != 0; | ||
| 890 | |||
| 891 | return ResultSuccess; | ||
| 892 | } | ||
| 893 | |||
| 894 | Result NfpDevice::GetAll(NfpData& data) const { | ||
| 895 | if (device_state != DeviceState::TagMounted) { | ||
| 896 | LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); | ||
| 897 | if (device_state == DeviceState::TagRemoved) { | ||
| 898 | return TagRemoved; | ||
| 899 | } | ||
| 900 | return WrongDeviceState; | ||
| 901 | } | ||
| 902 | |||
| 903 | if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { | ||
| 904 | LOG_ERROR(Service_NFC, "Amiibo is read only", device_state); | ||
| 905 | return WrongDeviceState; | ||
| 906 | } | ||
| 907 | |||
| 908 | CommonInfo common_info{}; | ||
| 909 | Service::Mii::MiiManager manager; | ||
| 910 | const u64 application_id = tag_data.application_id; | ||
| 911 | |||
| 912 | GetCommonInfo(common_info); | ||
| 913 | |||
| 914 | data = { | ||
| 915 | .magic = tag_data.constant_value, | ||
| 916 | .write_counter = tag_data.write_counter, | ||
| 917 | .settings_crc = tag_data.settings.crc, | ||
| 918 | .common_info = common_info, | ||
| 919 | .mii_char_info = tag_data.owner_mii, | ||
| 920 | .mii_store_data_extension = tag_data.mii_extension, | ||
| 921 | .creation_date = tag_data.settings.init_date.GetWriteDate(), | ||
| 922 | .amiibo_name = tag_data.settings.amiibo_name, | ||
| 923 | .amiibo_name_null_terminated = 0, | ||
| 924 | .settings = tag_data.settings.settings, | ||
| 925 | .unknown1 = tag_data.unknown, | ||
| 926 | .register_info_crc = tag_data.register_info_crc, | ||
| 927 | .unknown2 = tag_data.unknown2, | ||
| 928 | .application_id = application_id, | ||
| 929 | .access_id = tag_data.application_area_id, | ||
| 930 | .settings_crc_counter = tag_data.settings.crc_counter, | ||
| 931 | .font_region = tag_data.settings.settings.font_region, | ||
| 932 | .tag_type = PackedTagType::Type2, | ||
| 933 | .console_type = | ||
| 934 | static_cast<AppAreaVersion>(application_id >> application_id_version_offset & 0xf), | ||
| 935 | .application_id_byte = tag_data.application_id_byte, | ||
| 936 | .application_area = tag_data.application_area, | ||
| 937 | }; | ||
| 938 | |||
| 939 | return ResultSuccess; | ||
| 940 | } | ||
| 941 | |||
| 942 | Result NfpDevice::SetAll(const NfpData& data) { | ||
| 943 | if (device_state != DeviceState::TagMounted) { | ||
| 944 | LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); | ||
| 945 | if (device_state == DeviceState::TagRemoved) { | ||
| 946 | return TagRemoved; | ||
| 947 | } | ||
| 948 | return WrongDeviceState; | ||
| 949 | } | ||
| 950 | |||
| 951 | if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { | ||
| 952 | LOG_ERROR(Service_NFC, "Amiibo is read only", device_state); | ||
| 953 | return WrongDeviceState; | ||
| 954 | } | ||
| 955 | |||
| 956 | tag_data.constant_value = data.magic; | ||
| 957 | tag_data.write_counter = data.write_counter; | ||
| 958 | tag_data.settings.crc = data.settings_crc; | ||
| 959 | tag_data.settings.write_date.SetWriteDate(data.common_info.last_write_date); | ||
| 960 | tag_data.write_counter = data.common_info.write_counter; | ||
| 961 | tag_data.amiibo_version = data.common_info.version; | ||
| 962 | tag_data.owner_mii = data.mii_char_info; | ||
| 963 | tag_data.mii_extension = data.mii_store_data_extension; | ||
| 964 | tag_data.settings.init_date.SetWriteDate(data.creation_date); | ||
| 965 | tag_data.settings.amiibo_name = data.amiibo_name; | ||
| 966 | tag_data.settings.settings = data.settings; | ||
| 967 | tag_data.unknown = data.unknown1; | ||
| 968 | tag_data.register_info_crc = data.register_info_crc; | ||
| 969 | tag_data.unknown2 = data.unknown2; | ||
| 970 | tag_data.application_id = data.application_id; | ||
| 971 | tag_data.application_area_id = data.access_id; | ||
| 972 | tag_data.settings.crc_counter = data.settings_crc_counter; | ||
| 973 | tag_data.settings.settings.font_region.Assign(data.font_region); | ||
| 974 | tag_data.application_id_byte = data.application_id_byte; | ||
| 975 | tag_data.application_area = data.application_area; | ||
| 976 | |||
| 977 | return ResultSuccess; | ||
| 978 | } | ||
| 979 | |||
| 980 | Result NfpDevice::BreakTag(BreakType break_type) { | ||
| 981 | if (device_state != DeviceState::TagMounted) { | ||
| 982 | LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); | ||
| 983 | if (device_state == DeviceState::TagRemoved) { | ||
| 984 | return TagRemoved; | ||
| 985 | } | ||
| 986 | return WrongDeviceState; | ||
| 987 | } | ||
| 988 | |||
| 989 | if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { | ||
| 990 | LOG_ERROR(Service_NFC, "Amiibo is read only", device_state); | ||
| 991 | return WrongDeviceState; | ||
| 992 | } | ||
| 993 | |||
| 994 | // TODO: Complete this implementation | ||
| 995 | |||
| 996 | return FlushWithBreak(break_type); | ||
| 997 | } | ||
| 998 | |||
| 999 | Result NfpDevice::ReadBackupData() { | ||
| 1000 | // Not implemented | ||
| 1001 | return ResultSuccess; | ||
| 1002 | } | ||
| 1003 | |||
| 1004 | Result NfpDevice::WriteBackupData() { | ||
| 1005 | // Not implemented | ||
| 1006 | return ResultSuccess; | ||
| 1007 | } | ||
| 1008 | |||
| 1009 | Result NfpDevice::WriteNtf() { | ||
| 1010 | if (device_state != DeviceState::TagMounted) { | ||
| 1011 | LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); | ||
| 1012 | if (device_state == DeviceState::TagRemoved) { | ||
| 1013 | return TagRemoved; | ||
| 1014 | } | ||
| 1015 | return WrongDeviceState; | ||
| 1016 | } | ||
| 1017 | |||
| 1018 | if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { | ||
| 1019 | LOG_ERROR(Service_NFC, "Amiibo is read only", device_state); | ||
| 1020 | return WrongDeviceState; | ||
| 1021 | } | ||
| 1022 | |||
| 1023 | // Not implemented | ||
| 1024 | |||
| 1025 | return ResultSuccess; | ||
| 1026 | } | ||
| 1027 | |||
| 810 | u64 NfpDevice::GetHandle() const { | 1028 | u64 NfpDevice::GetHandle() const { |
| 811 | // Generate a handle based of the npad id | 1029 | // Generate a handle based of the npad id |
| 812 | return static_cast<u64>(npad_id); | 1030 | return static_cast<u64>(npad_id); |
diff --git a/src/core/hle/service/nfp/nfp_device.h b/src/core/hle/service/nfp/nfp_device.h index 7f963730d..bab05538a 100644 --- a/src/core/hle/service/nfp/nfp_device.h +++ b/src/core/hle/service/nfp/nfp_device.h | |||
| @@ -41,12 +41,16 @@ public: | |||
| 41 | Result StopDetection(); | 41 | Result StopDetection(); |
| 42 | Result Mount(MountTarget mount_target); | 42 | Result Mount(MountTarget mount_target); |
| 43 | Result Unmount(); | 43 | Result Unmount(); |
| 44 | |||
| 44 | Result Flush(); | 45 | Result Flush(); |
| 46 | Result FlushDebug(); | ||
| 47 | Result FlushWithBreak(BreakType break_type); | ||
| 45 | 48 | ||
| 46 | Result GetTagInfo(TagInfo& tag_info) const; | 49 | Result GetTagInfo(TagInfo& tag_info) const; |
| 47 | Result GetCommonInfo(CommonInfo& common_info) const; | 50 | Result GetCommonInfo(CommonInfo& common_info) const; |
| 48 | Result GetModelInfo(ModelInfo& model_info) const; | 51 | Result GetModelInfo(ModelInfo& model_info) const; |
| 49 | Result GetRegisterInfo(RegisterInfo& register_info) const; | 52 | Result GetRegisterInfo(RegisterInfo& register_info) const; |
| 53 | Result GetRegisterInfoPrivate(RegisterInfoPrivate& register_info) const; | ||
| 50 | Result GetAdminInfo(AdminInfo& admin_info) const; | 54 | Result GetAdminInfo(AdminInfo& admin_info) const; |
| 51 | 55 | ||
| 52 | Result DeleteRegisterInfo(); | 56 | Result DeleteRegisterInfo(); |
| @@ -61,6 +65,14 @@ public: | |||
| 61 | Result CreateApplicationArea(u32 access_id, std::span<const u8> data); | 65 | Result CreateApplicationArea(u32 access_id, std::span<const u8> data); |
| 62 | Result RecreateApplicationArea(u32 access_id, std::span<const u8> data); | 66 | Result RecreateApplicationArea(u32 access_id, std::span<const u8> data); |
| 63 | Result DeleteApplicationArea(); | 67 | Result DeleteApplicationArea(); |
| 68 | Result ExistApplicationArea(bool& has_application_area); | ||
| 69 | |||
| 70 | Result GetAll(NfpData& data) const; | ||
| 71 | Result SetAll(const NfpData& data); | ||
| 72 | Result BreakTag(BreakType break_type); | ||
| 73 | Result ReadBackupData(); | ||
| 74 | Result WriteBackupData(); | ||
| 75 | Result WriteNtf(); | ||
| 64 | 76 | ||
| 65 | u64 GetHandle() const; | 77 | u64 GetHandle() const; |
| 66 | u32 GetApplicationAreaSize() const; | 78 | u32 GetApplicationAreaSize() const; |
diff --git a/src/core/hle/service/nfp/nfp_user.cpp b/src/core/hle/service/nfp/nfp_interface.cpp index 4e8534113..2ed8bb1ba 100644 --- a/src/core/hle/service/nfp/nfp_user.cpp +++ b/src/core/hle/service/nfp/nfp_interface.cpp | |||
| @@ -7,42 +7,13 @@ | |||
| 7 | #include "core/hle/kernel/k_event.h" | 7 | #include "core/hle/kernel/k_event.h" |
| 8 | #include "core/hle/service/ipc_helpers.h" | 8 | #include "core/hle/service/ipc_helpers.h" |
| 9 | #include "core/hle/service/nfp/nfp_device.h" | 9 | #include "core/hle/service/nfp/nfp_device.h" |
| 10 | #include "core/hle/service/nfp/nfp_interface.h" | ||
| 10 | #include "core/hle/service/nfp/nfp_result.h" | 11 | #include "core/hle/service/nfp/nfp_result.h" |
| 11 | #include "core/hle/service/nfp/nfp_user.h" | ||
| 12 | 12 | ||
| 13 | namespace Service::NFP { | 13 | namespace Service::NFP { |
| 14 | 14 | ||
| 15 | IUser::IUser(Core::System& system_) | 15 | Interface::Interface(Core::System& system_, const char* name) |
| 16 | : ServiceFramework{system_, "NFP::IUser"}, service_context{system_, service_name} { | 16 | : ServiceFramework{system_, name}, service_context{system_, service_name} { |
| 17 | static const FunctionInfo functions[] = { | ||
| 18 | {0, &IUser::Initialize, "Initialize"}, | ||
| 19 | {1, &IUser::Finalize, "Finalize"}, | ||
| 20 | {2, &IUser::ListDevices, "ListDevices"}, | ||
| 21 | {3, &IUser::StartDetection, "StartDetection"}, | ||
| 22 | {4, &IUser::StopDetection, "StopDetection"}, | ||
| 23 | {5, &IUser::Mount, "Mount"}, | ||
| 24 | {6, &IUser::Unmount, "Unmount"}, | ||
| 25 | {7, &IUser::OpenApplicationArea, "OpenApplicationArea"}, | ||
| 26 | {8, &IUser::GetApplicationArea, "GetApplicationArea"}, | ||
| 27 | {9, &IUser::SetApplicationArea, "SetApplicationArea"}, | ||
| 28 | {10, &IUser::Flush, "Flush"}, | ||
| 29 | {11, &IUser::Restore, "Restore"}, | ||
| 30 | {12, &IUser::CreateApplicationArea, "CreateApplicationArea"}, | ||
| 31 | {13, &IUser::GetTagInfo, "GetTagInfo"}, | ||
| 32 | {14, &IUser::GetRegisterInfo, "GetRegisterInfo"}, | ||
| 33 | {15, &IUser::GetCommonInfo, "GetCommonInfo"}, | ||
| 34 | {16, &IUser::GetModelInfo, "GetModelInfo"}, | ||
| 35 | {17, &IUser::AttachActivateEvent, "AttachActivateEvent"}, | ||
| 36 | {18, &IUser::AttachDeactivateEvent, "AttachDeactivateEvent"}, | ||
| 37 | {19, &IUser::GetState, "GetState"}, | ||
| 38 | {20, &IUser::GetDeviceState, "GetDeviceState"}, | ||
| 39 | {21, &IUser::GetNpadId, "GetNpadId"}, | ||
| 40 | {22, &IUser::GetApplicationAreaSize, "GetApplicationAreaSize"}, | ||
| 41 | {23, &IUser::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"}, | ||
| 42 | {24, &IUser::RecreateApplicationArea, "RecreateApplicationArea"}, | ||
| 43 | }; | ||
| 44 | RegisterHandlers(functions); | ||
| 45 | |||
| 46 | availability_change_event = service_context.CreateEvent("IUser:AvailabilityChangeEvent"); | 17 | availability_change_event = service_context.CreateEvent("IUser:AvailabilityChangeEvent"); |
| 47 | 18 | ||
| 48 | for (u32 device_index = 0; device_index < 10; device_index++) { | 19 | for (u32 device_index = 0; device_index < 10; device_index++) { |
| @@ -52,11 +23,37 @@ IUser::IUser(Core::System& system_) | |||
| 52 | } | 23 | } |
| 53 | } | 24 | } |
| 54 | 25 | ||
| 55 | IUser ::~IUser() { | 26 | Interface::~Interface() { |
| 56 | availability_change_event->Close(); | 27 | availability_change_event->Close(); |
| 57 | } | 28 | } |
| 58 | 29 | ||
| 59 | void IUser::Initialize(HLERequestContext& ctx) { | 30 | void Interface::Initialize(HLERequestContext& ctx) { |
| 31 | LOG_INFO(Service_NFP, "called"); | ||
| 32 | |||
| 33 | state = State::Initialized; | ||
| 34 | |||
| 35 | for (auto& device : devices) { | ||
| 36 | device->Initialize(); | ||
| 37 | } | ||
| 38 | |||
| 39 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 40 | rb.Push(ResultSuccess); | ||
| 41 | } | ||
| 42 | |||
| 43 | void Interface::InitializeSystem(HLERequestContext& ctx) { | ||
| 44 | LOG_INFO(Service_NFP, "called"); | ||
| 45 | |||
| 46 | state = State::Initialized; | ||
| 47 | |||
| 48 | for (auto& device : devices) { | ||
| 49 | device->Initialize(); | ||
| 50 | } | ||
| 51 | |||
| 52 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 53 | rb.Push(ResultSuccess); | ||
| 54 | } | ||
| 55 | |||
| 56 | void Interface::InitializeDebug(HLERequestContext& ctx) { | ||
| 60 | LOG_INFO(Service_NFP, "called"); | 57 | LOG_INFO(Service_NFP, "called"); |
| 61 | 58 | ||
| 62 | state = State::Initialized; | 59 | state = State::Initialized; |
| @@ -69,7 +66,7 @@ void IUser::Initialize(HLERequestContext& ctx) { | |||
| 69 | rb.Push(ResultSuccess); | 66 | rb.Push(ResultSuccess); |
| 70 | } | 67 | } |
| 71 | 68 | ||
| 72 | void IUser::Finalize(HLERequestContext& ctx) { | 69 | void Interface::Finalize(HLERequestContext& ctx) { |
| 73 | LOG_INFO(Service_NFP, "called"); | 70 | LOG_INFO(Service_NFP, "called"); |
| 74 | 71 | ||
| 75 | state = State::NonInitialized; | 72 | state = State::NonInitialized; |
| @@ -82,7 +79,33 @@ void IUser::Finalize(HLERequestContext& ctx) { | |||
| 82 | rb.Push(ResultSuccess); | 79 | rb.Push(ResultSuccess); |
| 83 | } | 80 | } |
| 84 | 81 | ||
| 85 | void IUser::ListDevices(HLERequestContext& ctx) { | 82 | void Interface::FinalizeSystem(HLERequestContext& ctx) { |
| 83 | LOG_INFO(Service_NFP, "called"); | ||
| 84 | |||
| 85 | state = State::NonInitialized; | ||
| 86 | |||
| 87 | for (auto& device : devices) { | ||
| 88 | device->Finalize(); | ||
| 89 | } | ||
| 90 | |||
| 91 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 92 | rb.Push(ResultSuccess); | ||
| 93 | } | ||
| 94 | |||
| 95 | void Interface::FinalizeDebug(HLERequestContext& ctx) { | ||
| 96 | LOG_INFO(Service_NFP, "called"); | ||
| 97 | |||
| 98 | state = State::NonInitialized; | ||
| 99 | |||
| 100 | for (auto& device : devices) { | ||
| 101 | device->Finalize(); | ||
| 102 | } | ||
| 103 | |||
| 104 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 105 | rb.Push(ResultSuccess); | ||
| 106 | } | ||
| 107 | |||
| 108 | void Interface::ListDevices(HLERequestContext& ctx) { | ||
| 86 | LOG_DEBUG(Service_NFP, "called"); | 109 | LOG_DEBUG(Service_NFP, "called"); |
| 87 | 110 | ||
| 88 | if (state == State::NonInitialized) { | 111 | if (state == State::NonInitialized) { |
| @@ -128,7 +151,7 @@ void IUser::ListDevices(HLERequestContext& ctx) { | |||
| 128 | rb.Push(static_cast<s32>(nfp_devices.size())); | 151 | rb.Push(static_cast<s32>(nfp_devices.size())); |
| 129 | } | 152 | } |
| 130 | 153 | ||
| 131 | void IUser::StartDetection(HLERequestContext& ctx) { | 154 | void Interface::StartDetection(HLERequestContext& ctx) { |
| 132 | IPC::RequestParser rp{ctx}; | 155 | IPC::RequestParser rp{ctx}; |
| 133 | const auto device_handle{rp.Pop<u64>()}; | 156 | const auto device_handle{rp.Pop<u64>()}; |
| 134 | const auto nfp_protocol{rp.PopEnum<TagProtocol>()}; | 157 | const auto nfp_protocol{rp.PopEnum<TagProtocol>()}; |
| @@ -153,7 +176,7 @@ void IUser::StartDetection(HLERequestContext& ctx) { | |||
| 153 | rb.Push(result); | 176 | rb.Push(result); |
| 154 | } | 177 | } |
| 155 | 178 | ||
| 156 | void IUser::StopDetection(HLERequestContext& ctx) { | 179 | void Interface::StopDetection(HLERequestContext& ctx) { |
| 157 | IPC::RequestParser rp{ctx}; | 180 | IPC::RequestParser rp{ctx}; |
| 158 | const auto device_handle{rp.Pop<u64>()}; | 181 | const auto device_handle{rp.Pop<u64>()}; |
| 159 | LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); | 182 | LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); |
| @@ -177,7 +200,7 @@ void IUser::StopDetection(HLERequestContext& ctx) { | |||
| 177 | rb.Push(result); | 200 | rb.Push(result); |
| 178 | } | 201 | } |
| 179 | 202 | ||
| 180 | void IUser::Mount(HLERequestContext& ctx) { | 203 | void Interface::Mount(HLERequestContext& ctx) { |
| 181 | IPC::RequestParser rp{ctx}; | 204 | IPC::RequestParser rp{ctx}; |
| 182 | const auto device_handle{rp.Pop<u64>()}; | 205 | const auto device_handle{rp.Pop<u64>()}; |
| 183 | const auto model_type{rp.PopEnum<ModelType>()}; | 206 | const auto model_type{rp.PopEnum<ModelType>()}; |
| @@ -204,7 +227,7 @@ void IUser::Mount(HLERequestContext& ctx) { | |||
| 204 | rb.Push(result); | 227 | rb.Push(result); |
| 205 | } | 228 | } |
| 206 | 229 | ||
| 207 | void IUser::Unmount(HLERequestContext& ctx) { | 230 | void Interface::Unmount(HLERequestContext& ctx) { |
| 208 | IPC::RequestParser rp{ctx}; | 231 | IPC::RequestParser rp{ctx}; |
| 209 | const auto device_handle{rp.Pop<u64>()}; | 232 | const auto device_handle{rp.Pop<u64>()}; |
| 210 | LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); | 233 | LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); |
| @@ -228,7 +251,7 @@ void IUser::Unmount(HLERequestContext& ctx) { | |||
| 228 | rb.Push(result); | 251 | rb.Push(result); |
| 229 | } | 252 | } |
| 230 | 253 | ||
| 231 | void IUser::OpenApplicationArea(HLERequestContext& ctx) { | 254 | void Interface::OpenApplicationArea(HLERequestContext& ctx) { |
| 232 | IPC::RequestParser rp{ctx}; | 255 | IPC::RequestParser rp{ctx}; |
| 233 | const auto device_handle{rp.Pop<u64>()}; | 256 | const auto device_handle{rp.Pop<u64>()}; |
| 234 | const auto access_id{rp.Pop<u32>()}; | 257 | const auto access_id{rp.Pop<u32>()}; |
| @@ -253,7 +276,7 @@ void IUser::OpenApplicationArea(HLERequestContext& ctx) { | |||
| 253 | rb.Push(result); | 276 | rb.Push(result); |
| 254 | } | 277 | } |
| 255 | 278 | ||
| 256 | void IUser::GetApplicationArea(HLERequestContext& ctx) { | 279 | void Interface::GetApplicationArea(HLERequestContext& ctx) { |
| 257 | IPC::RequestParser rp{ctx}; | 280 | IPC::RequestParser rp{ctx}; |
| 258 | const auto device_handle{rp.Pop<u64>()}; | 281 | const auto device_handle{rp.Pop<u64>()}; |
| 259 | const auto data_size = ctx.GetWriteBufferSize(); | 282 | const auto data_size = ctx.GetWriteBufferSize(); |
| @@ -287,7 +310,7 @@ void IUser::GetApplicationArea(HLERequestContext& ctx) { | |||
| 287 | rb.Push(static_cast<u32>(data_size)); | 310 | rb.Push(static_cast<u32>(data_size)); |
| 288 | } | 311 | } |
| 289 | 312 | ||
| 290 | void IUser::SetApplicationArea(HLERequestContext& ctx) { | 313 | void Interface::SetApplicationArea(HLERequestContext& ctx) { |
| 291 | IPC::RequestParser rp{ctx}; | 314 | IPC::RequestParser rp{ctx}; |
| 292 | const auto device_handle{rp.Pop<u64>()}; | 315 | const auto device_handle{rp.Pop<u64>()}; |
| 293 | const auto data{ctx.ReadBuffer()}; | 316 | const auto data{ctx.ReadBuffer()}; |
| @@ -318,7 +341,7 @@ void IUser::SetApplicationArea(HLERequestContext& ctx) { | |||
| 318 | rb.Push(result); | 341 | rb.Push(result); |
| 319 | } | 342 | } |
| 320 | 343 | ||
| 321 | void IUser::Flush(HLERequestContext& ctx) { | 344 | void Interface::Flush(HLERequestContext& ctx) { |
| 322 | IPC::RequestParser rp{ctx}; | 345 | IPC::RequestParser rp{ctx}; |
| 323 | const auto device_handle{rp.Pop<u64>()}; | 346 | const auto device_handle{rp.Pop<u64>()}; |
| 324 | LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); | 347 | LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); |
| @@ -342,7 +365,7 @@ void IUser::Flush(HLERequestContext& ctx) { | |||
| 342 | rb.Push(result); | 365 | rb.Push(result); |
| 343 | } | 366 | } |
| 344 | 367 | ||
| 345 | void IUser::Restore(HLERequestContext& ctx) { | 368 | void Interface::Restore(HLERequestContext& ctx) { |
| 346 | IPC::RequestParser rp{ctx}; | 369 | IPC::RequestParser rp{ctx}; |
| 347 | const auto device_handle{rp.Pop<u64>()}; | 370 | const auto device_handle{rp.Pop<u64>()}; |
| 348 | LOG_WARNING(Service_NFP, "(STUBBED) called, device_handle={}", device_handle); | 371 | LOG_WARNING(Service_NFP, "(STUBBED) called, device_handle={}", device_handle); |
| @@ -366,7 +389,7 @@ void IUser::Restore(HLERequestContext& ctx) { | |||
| 366 | rb.Push(result); | 389 | rb.Push(result); |
| 367 | } | 390 | } |
| 368 | 391 | ||
| 369 | void IUser::CreateApplicationArea(HLERequestContext& ctx) { | 392 | void Interface::CreateApplicationArea(HLERequestContext& ctx) { |
| 370 | IPC::RequestParser rp{ctx}; | 393 | IPC::RequestParser rp{ctx}; |
| 371 | const auto device_handle{rp.Pop<u64>()}; | 394 | const auto device_handle{rp.Pop<u64>()}; |
| 372 | const auto access_id{rp.Pop<u32>()}; | 395 | const auto access_id{rp.Pop<u32>()}; |
| @@ -399,7 +422,7 @@ void IUser::CreateApplicationArea(HLERequestContext& ctx) { | |||
| 399 | rb.Push(result); | 422 | rb.Push(result); |
| 400 | } | 423 | } |
| 401 | 424 | ||
| 402 | void IUser::GetTagInfo(HLERequestContext& ctx) { | 425 | void Interface::GetTagInfo(HLERequestContext& ctx) { |
| 403 | IPC::RequestParser rp{ctx}; | 426 | IPC::RequestParser rp{ctx}; |
| 404 | const auto device_handle{rp.Pop<u64>()}; | 427 | const auto device_handle{rp.Pop<u64>()}; |
| 405 | LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); | 428 | LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); |
| @@ -425,7 +448,7 @@ void IUser::GetTagInfo(HLERequestContext& ctx) { | |||
| 425 | rb.Push(result); | 448 | rb.Push(result); |
| 426 | } | 449 | } |
| 427 | 450 | ||
| 428 | void IUser::GetRegisterInfo(HLERequestContext& ctx) { | 451 | void Interface::GetRegisterInfo(HLERequestContext& ctx) { |
| 429 | IPC::RequestParser rp{ctx}; | 452 | IPC::RequestParser rp{ctx}; |
| 430 | const auto device_handle{rp.Pop<u64>()}; | 453 | const auto device_handle{rp.Pop<u64>()}; |
| 431 | LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); | 454 | LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); |
| @@ -451,7 +474,7 @@ void IUser::GetRegisterInfo(HLERequestContext& ctx) { | |||
| 451 | rb.Push(result); | 474 | rb.Push(result); |
| 452 | } | 475 | } |
| 453 | 476 | ||
| 454 | void IUser::GetCommonInfo(HLERequestContext& ctx) { | 477 | void Interface::GetCommonInfo(HLERequestContext& ctx) { |
| 455 | IPC::RequestParser rp{ctx}; | 478 | IPC::RequestParser rp{ctx}; |
| 456 | const auto device_handle{rp.Pop<u64>()}; | 479 | const auto device_handle{rp.Pop<u64>()}; |
| 457 | LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); | 480 | LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); |
| @@ -477,7 +500,7 @@ void IUser::GetCommonInfo(HLERequestContext& ctx) { | |||
| 477 | rb.Push(result); | 500 | rb.Push(result); |
| 478 | } | 501 | } |
| 479 | 502 | ||
| 480 | void IUser::GetModelInfo(HLERequestContext& ctx) { | 503 | void Interface::GetModelInfo(HLERequestContext& ctx) { |
| 481 | IPC::RequestParser rp{ctx}; | 504 | IPC::RequestParser rp{ctx}; |
| 482 | const auto device_handle{rp.Pop<u64>()}; | 505 | const auto device_handle{rp.Pop<u64>()}; |
| 483 | LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); | 506 | LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); |
| @@ -503,7 +526,7 @@ void IUser::GetModelInfo(HLERequestContext& ctx) { | |||
| 503 | rb.Push(result); | 526 | rb.Push(result); |
| 504 | } | 527 | } |
| 505 | 528 | ||
| 506 | void IUser::AttachActivateEvent(HLERequestContext& ctx) { | 529 | void Interface::AttachActivateEvent(HLERequestContext& ctx) { |
| 507 | IPC::RequestParser rp{ctx}; | 530 | IPC::RequestParser rp{ctx}; |
| 508 | const auto device_handle{rp.Pop<u64>()}; | 531 | const auto device_handle{rp.Pop<u64>()}; |
| 509 | LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); | 532 | LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); |
| @@ -527,7 +550,7 @@ void IUser::AttachActivateEvent(HLERequestContext& ctx) { | |||
| 527 | rb.PushCopyObjects(device.value()->GetActivateEvent()); | 550 | rb.PushCopyObjects(device.value()->GetActivateEvent()); |
| 528 | } | 551 | } |
| 529 | 552 | ||
| 530 | void IUser::AttachDeactivateEvent(HLERequestContext& ctx) { | 553 | void Interface::AttachDeactivateEvent(HLERequestContext& ctx) { |
| 531 | IPC::RequestParser rp{ctx}; | 554 | IPC::RequestParser rp{ctx}; |
| 532 | const auto device_handle{rp.Pop<u64>()}; | 555 | const auto device_handle{rp.Pop<u64>()}; |
| 533 | LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); | 556 | LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); |
| @@ -551,7 +574,7 @@ void IUser::AttachDeactivateEvent(HLERequestContext& ctx) { | |||
| 551 | rb.PushCopyObjects(device.value()->GetDeactivateEvent()); | 574 | rb.PushCopyObjects(device.value()->GetDeactivateEvent()); |
| 552 | } | 575 | } |
| 553 | 576 | ||
| 554 | void IUser::GetState(HLERequestContext& ctx) { | 577 | void Interface::GetState(HLERequestContext& ctx) { |
| 555 | LOG_DEBUG(Service_NFP, "called"); | 578 | LOG_DEBUG(Service_NFP, "called"); |
| 556 | 579 | ||
| 557 | IPC::ResponseBuilder rb{ctx, 3}; | 580 | IPC::ResponseBuilder rb{ctx, 3}; |
| @@ -559,7 +582,7 @@ void IUser::GetState(HLERequestContext& ctx) { | |||
| 559 | rb.PushEnum(state); | 582 | rb.PushEnum(state); |
| 560 | } | 583 | } |
| 561 | 584 | ||
| 562 | void IUser::GetDeviceState(HLERequestContext& ctx) { | 585 | void Interface::GetDeviceState(HLERequestContext& ctx) { |
| 563 | IPC::RequestParser rp{ctx}; | 586 | IPC::RequestParser rp{ctx}; |
| 564 | const auto device_handle{rp.Pop<u64>()}; | 587 | const auto device_handle{rp.Pop<u64>()}; |
| 565 | LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); | 588 | LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); |
| @@ -577,7 +600,7 @@ void IUser::GetDeviceState(HLERequestContext& ctx) { | |||
| 577 | rb.PushEnum(device.value()->GetCurrentState()); | 600 | rb.PushEnum(device.value()->GetCurrentState()); |
| 578 | } | 601 | } |
| 579 | 602 | ||
| 580 | void IUser::GetNpadId(HLERequestContext& ctx) { | 603 | void Interface::GetNpadId(HLERequestContext& ctx) { |
| 581 | IPC::RequestParser rp{ctx}; | 604 | IPC::RequestParser rp{ctx}; |
| 582 | const auto device_handle{rp.Pop<u64>()}; | 605 | const auto device_handle{rp.Pop<u64>()}; |
| 583 | LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); | 606 | LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); |
| @@ -601,7 +624,7 @@ void IUser::GetNpadId(HLERequestContext& ctx) { | |||
| 601 | rb.PushEnum(device.value()->GetNpadId()); | 624 | rb.PushEnum(device.value()->GetNpadId()); |
| 602 | } | 625 | } |
| 603 | 626 | ||
| 604 | void IUser::GetApplicationAreaSize(HLERequestContext& ctx) { | 627 | void Interface::GetApplicationAreaSize(HLERequestContext& ctx) { |
| 605 | IPC::RequestParser rp{ctx}; | 628 | IPC::RequestParser rp{ctx}; |
| 606 | const auto device_handle{rp.Pop<u64>()}; | 629 | const auto device_handle{rp.Pop<u64>()}; |
| 607 | LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); | 630 | LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); |
| @@ -619,7 +642,7 @@ void IUser::GetApplicationAreaSize(HLERequestContext& ctx) { | |||
| 619 | rb.Push(device.value()->GetApplicationAreaSize()); | 642 | rb.Push(device.value()->GetApplicationAreaSize()); |
| 620 | } | 643 | } |
| 621 | 644 | ||
| 622 | void IUser::AttachAvailabilityChangeEvent(HLERequestContext& ctx) { | 645 | void Interface::AttachAvailabilityChangeEvent(HLERequestContext& ctx) { |
| 623 | LOG_INFO(Service_NFP, "called"); | 646 | LOG_INFO(Service_NFP, "called"); |
| 624 | 647 | ||
| 625 | if (state == State::NonInitialized) { | 648 | if (state == State::NonInitialized) { |
| @@ -633,7 +656,7 @@ void IUser::AttachAvailabilityChangeEvent(HLERequestContext& ctx) { | |||
| 633 | rb.PushCopyObjects(availability_change_event->GetReadableEvent()); | 656 | rb.PushCopyObjects(availability_change_event->GetReadableEvent()); |
| 634 | } | 657 | } |
| 635 | 658 | ||
| 636 | void IUser::RecreateApplicationArea(HLERequestContext& ctx) { | 659 | void Interface::RecreateApplicationArea(HLERequestContext& ctx) { |
| 637 | IPC::RequestParser rp{ctx}; | 660 | IPC::RequestParser rp{ctx}; |
| 638 | const auto device_handle{rp.Pop<u64>()}; | 661 | const auto device_handle{rp.Pop<u64>()}; |
| 639 | const auto access_id{rp.Pop<u32>()}; | 662 | const auto access_id{rp.Pop<u32>()}; |
| @@ -660,7 +683,361 @@ void IUser::RecreateApplicationArea(HLERequestContext& ctx) { | |||
| 660 | rb.Push(result); | 683 | rb.Push(result); |
| 661 | } | 684 | } |
| 662 | 685 | ||
| 663 | std::optional<std::shared_ptr<NfpDevice>> IUser::GetNfpDevice(u64 handle) { | 686 | void Interface::Format(HLERequestContext& ctx) { |
| 687 | IPC::RequestParser rp{ctx}; | ||
| 688 | const auto device_handle{rp.Pop<u64>()}; | ||
| 689 | LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); | ||
| 690 | |||
| 691 | if (state == State::NonInitialized) { | ||
| 692 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 693 | rb.Push(NfcDisabled); | ||
| 694 | return; | ||
| 695 | } | ||
| 696 | |||
| 697 | auto device = GetNfpDevice(device_handle); | ||
| 698 | |||
| 699 | if (!device.has_value()) { | ||
| 700 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 701 | rb.Push(DeviceNotFound); | ||
| 702 | return; | ||
| 703 | } | ||
| 704 | |||
| 705 | const auto result = device.value()->Format(); | ||
| 706 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 707 | rb.Push(result); | ||
| 708 | } | ||
| 709 | |||
| 710 | void Interface::GetAdminInfo(HLERequestContext& ctx) { | ||
| 711 | IPC::RequestParser rp{ctx}; | ||
| 712 | const auto device_handle{rp.Pop<u64>()}; | ||
| 713 | LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); | ||
| 714 | |||
| 715 | if (state == State::NonInitialized) { | ||
| 716 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 717 | rb.Push(NfcDisabled); | ||
| 718 | return; | ||
| 719 | } | ||
| 720 | |||
| 721 | auto device = GetNfpDevice(device_handle); | ||
| 722 | |||
| 723 | if (!device.has_value()) { | ||
| 724 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 725 | rb.Push(DeviceNotFound); | ||
| 726 | return; | ||
| 727 | } | ||
| 728 | |||
| 729 | AdminInfo admin_info{}; | ||
| 730 | const auto result = device.value()->GetAdminInfo(admin_info); | ||
| 731 | ctx.WriteBuffer(admin_info); | ||
| 732 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 733 | rb.Push(result); | ||
| 734 | } | ||
| 735 | |||
| 736 | void Interface::GetRegisterInfoPrivate(HLERequestContext& ctx) { | ||
| 737 | IPC::RequestParser rp{ctx}; | ||
| 738 | const auto device_handle{rp.Pop<u64>()}; | ||
| 739 | LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); | ||
| 740 | |||
| 741 | if (state == State::NonInitialized) { | ||
| 742 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 743 | rb.Push(NfcDisabled); | ||
| 744 | return; | ||
| 745 | } | ||
| 746 | |||
| 747 | auto device = GetNfpDevice(device_handle); | ||
| 748 | |||
| 749 | if (!device.has_value()) { | ||
| 750 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 751 | rb.Push(DeviceNotFound); | ||
| 752 | return; | ||
| 753 | } | ||
| 754 | |||
| 755 | RegisterInfoPrivate register_info{}; | ||
| 756 | const auto result = device.value()->GetRegisterInfoPrivate(register_info); | ||
| 757 | ctx.WriteBuffer(register_info); | ||
| 758 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 759 | rb.Push(result); | ||
| 760 | } | ||
| 761 | |||
| 762 | void Interface::SetRegisterInfoPrivate(HLERequestContext& ctx) { | ||
| 763 | IPC::RequestParser rp{ctx}; | ||
| 764 | const auto device_handle{rp.Pop<u64>()}; | ||
| 765 | const auto buffer{ctx.ReadBuffer()}; | ||
| 766 | LOG_DEBUG(Service_NFP, "called, device_handle={}, buffer_size={}", device_handle, | ||
| 767 | buffer.size()); | ||
| 768 | |||
| 769 | if (state == State::NonInitialized) { | ||
| 770 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 771 | rb.Push(NfcDisabled); | ||
| 772 | return; | ||
| 773 | } | ||
| 774 | |||
| 775 | auto device = GetNfpDevice(device_handle); | ||
| 776 | |||
| 777 | if (!device.has_value()) { | ||
| 778 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 779 | rb.Push(DeviceNotFound); | ||
| 780 | return; | ||
| 781 | } | ||
| 782 | |||
| 783 | const auto result = device.value()->SetRegisterInfoPrivate({}); | ||
| 784 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 785 | rb.Push(result); | ||
| 786 | } | ||
| 787 | |||
| 788 | void Interface::DeleteRegisterInfo(HLERequestContext& ctx) { | ||
| 789 | IPC::RequestParser rp{ctx}; | ||
| 790 | const auto device_handle{rp.Pop<u64>()}; | ||
| 791 | LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); | ||
| 792 | |||
| 793 | if (state == State::NonInitialized) { | ||
| 794 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 795 | rb.Push(NfcDisabled); | ||
| 796 | return; | ||
| 797 | } | ||
| 798 | |||
| 799 | auto device = GetNfpDevice(device_handle); | ||
| 800 | |||
| 801 | if (!device.has_value()) { | ||
| 802 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 803 | rb.Push(DeviceNotFound); | ||
| 804 | return; | ||
| 805 | } | ||
| 806 | |||
| 807 | const auto result = device.value()->DeleteRegisterInfo(); | ||
| 808 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 809 | rb.Push(result); | ||
| 810 | } | ||
| 811 | |||
| 812 | void Interface::DeleteApplicationArea(HLERequestContext& ctx) { | ||
| 813 | IPC::RequestParser rp{ctx}; | ||
| 814 | const auto device_handle{rp.Pop<u64>()}; | ||
| 815 | LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); | ||
| 816 | |||
| 817 | if (state == State::NonInitialized) { | ||
| 818 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 819 | rb.Push(NfcDisabled); | ||
| 820 | return; | ||
| 821 | } | ||
| 822 | |||
| 823 | auto device = GetNfpDevice(device_handle); | ||
| 824 | |||
| 825 | if (!device.has_value()) { | ||
| 826 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 827 | rb.Push(DeviceNotFound); | ||
| 828 | return; | ||
| 829 | } | ||
| 830 | |||
| 831 | const auto result = device.value()->DeleteApplicationArea(); | ||
| 832 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 833 | rb.Push(result); | ||
| 834 | } | ||
| 835 | |||
| 836 | void Interface::ExistsApplicationArea(HLERequestContext& ctx) { | ||
| 837 | IPC::RequestParser rp{ctx}; | ||
| 838 | const auto device_handle{rp.Pop<u64>()}; | ||
| 839 | LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); | ||
| 840 | |||
| 841 | if (state == State::NonInitialized) { | ||
| 842 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 843 | rb.Push(NfcDisabled); | ||
| 844 | return; | ||
| 845 | } | ||
| 846 | |||
| 847 | auto device = GetNfpDevice(device_handle); | ||
| 848 | |||
| 849 | if (!device.has_value()) { | ||
| 850 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 851 | rb.Push(DeviceNotFound); | ||
| 852 | return; | ||
| 853 | } | ||
| 854 | |||
| 855 | bool has_application_area = false; | ||
| 856 | const auto result = device.value()->ExistApplicationArea(has_application_area); | ||
| 857 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 858 | rb.Push(result); | ||
| 859 | rb.Push(has_application_area); | ||
| 860 | } | ||
| 861 | |||
| 862 | void Interface::GetAll(HLERequestContext& ctx) { | ||
| 863 | IPC::RequestParser rp{ctx}; | ||
| 864 | const auto device_handle{rp.Pop<u64>()}; | ||
| 865 | LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); | ||
| 866 | |||
| 867 | if (state == State::NonInitialized) { | ||
| 868 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 869 | rb.Push(NfcDisabled); | ||
| 870 | return; | ||
| 871 | } | ||
| 872 | |||
| 873 | auto device = GetNfpDevice(device_handle); | ||
| 874 | |||
| 875 | if (!device.has_value()) { | ||
| 876 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 877 | rb.Push(DeviceNotFound); | ||
| 878 | return; | ||
| 879 | } | ||
| 880 | |||
| 881 | NfpData data{}; | ||
| 882 | const auto result = device.value()->GetAll(data); | ||
| 883 | |||
| 884 | ctx.WriteBuffer(data); | ||
| 885 | |||
| 886 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 887 | rb.Push(result); | ||
| 888 | } | ||
| 889 | |||
| 890 | void Interface::SetAll(HLERequestContext& ctx) { | ||
| 891 | IPC::RequestParser rp{ctx}; | ||
| 892 | const auto device_handle{rp.Pop<u64>()}; | ||
| 893 | const auto nfp_data{ctx.ReadBuffer()}; | ||
| 894 | |||
| 895 | LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); | ||
| 896 | |||
| 897 | if (state == State::NonInitialized) { | ||
| 898 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 899 | rb.Push(NfcDisabled); | ||
| 900 | return; | ||
| 901 | } | ||
| 902 | |||
| 903 | auto device = GetNfpDevice(device_handle); | ||
| 904 | |||
| 905 | if (!device.has_value()) { | ||
| 906 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 907 | rb.Push(DeviceNotFound); | ||
| 908 | return; | ||
| 909 | } | ||
| 910 | |||
| 911 | NfpData data{}; | ||
| 912 | memcpy(&data, nfp_data.data(), sizeof(NfpData)); | ||
| 913 | |||
| 914 | const auto result = device.value()->SetAll(data); | ||
| 915 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 916 | rb.Push(result); | ||
| 917 | } | ||
| 918 | |||
| 919 | void Interface::FlushDebug(HLERequestContext& ctx) { | ||
| 920 | IPC::RequestParser rp{ctx}; | ||
| 921 | const auto device_handle{rp.Pop<u64>()}; | ||
| 922 | LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); | ||
| 923 | |||
| 924 | if (state == State::NonInitialized) { | ||
| 925 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 926 | rb.Push(NfcDisabled); | ||
| 927 | return; | ||
| 928 | } | ||
| 929 | |||
| 930 | auto device = GetNfpDevice(device_handle); | ||
| 931 | |||
| 932 | if (!device.has_value()) { | ||
| 933 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 934 | rb.Push(DeviceNotFound); | ||
| 935 | return; | ||
| 936 | } | ||
| 937 | |||
| 938 | const auto result = device.value()->FlushDebug(); | ||
| 939 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 940 | rb.Push(result); | ||
| 941 | } | ||
| 942 | |||
| 943 | void Interface::BreakTag(HLERequestContext& ctx) { | ||
| 944 | IPC::RequestParser rp{ctx}; | ||
| 945 | const auto device_handle{rp.Pop<u64>()}; | ||
| 946 | const auto break_type{rp.PopEnum<BreakType>()}; | ||
| 947 | LOG_DEBUG(Service_NFP, "called, device_handle={}, break_type={}", device_handle, break_type); | ||
| 948 | |||
| 949 | if (state == State::NonInitialized) { | ||
| 950 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 951 | rb.Push(NfcDisabled); | ||
| 952 | return; | ||
| 953 | } | ||
| 954 | |||
| 955 | auto device = GetNfpDevice(device_handle); | ||
| 956 | |||
| 957 | if (!device.has_value()) { | ||
| 958 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 959 | rb.Push(DeviceNotFound); | ||
| 960 | return; | ||
| 961 | } | ||
| 962 | |||
| 963 | const auto result = device.value()->BreakTag(break_type); | ||
| 964 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 965 | rb.Push(result); | ||
| 966 | } | ||
| 967 | |||
| 968 | void Interface::ReadBackupData(HLERequestContext& ctx) { | ||
| 969 | IPC::RequestParser rp{ctx}; | ||
| 970 | const auto device_handle{rp.Pop<u64>()}; | ||
| 971 | LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); | ||
| 972 | |||
| 973 | if (state == State::NonInitialized) { | ||
| 974 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 975 | rb.Push(NfcDisabled); | ||
| 976 | return; | ||
| 977 | } | ||
| 978 | |||
| 979 | auto device = GetNfpDevice(device_handle); | ||
| 980 | |||
| 981 | if (!device.has_value()) { | ||
| 982 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 983 | rb.Push(DeviceNotFound); | ||
| 984 | return; | ||
| 985 | } | ||
| 986 | |||
| 987 | const auto result = device.value()->ReadBackupData(); | ||
| 988 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 989 | rb.Push(result); | ||
| 990 | } | ||
| 991 | |||
| 992 | void Interface::WriteBackupData(HLERequestContext& ctx) { | ||
| 993 | IPC::RequestParser rp{ctx}; | ||
| 994 | const auto device_handle{rp.Pop<u64>()}; | ||
| 995 | LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); | ||
| 996 | |||
| 997 | if (state == State::NonInitialized) { | ||
| 998 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 999 | rb.Push(NfcDisabled); | ||
| 1000 | return; | ||
| 1001 | } | ||
| 1002 | |||
| 1003 | auto device = GetNfpDevice(device_handle); | ||
| 1004 | |||
| 1005 | if (!device.has_value()) { | ||
| 1006 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 1007 | rb.Push(DeviceNotFound); | ||
| 1008 | return; | ||
| 1009 | } | ||
| 1010 | |||
| 1011 | const auto result = device.value()->WriteBackupData(); | ||
| 1012 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 1013 | rb.Push(result); | ||
| 1014 | } | ||
| 1015 | |||
| 1016 | void Interface::WriteNtf(HLERequestContext& ctx) { | ||
| 1017 | IPC::RequestParser rp{ctx}; | ||
| 1018 | const auto device_handle{rp.Pop<u64>()}; | ||
| 1019 | LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); | ||
| 1020 | |||
| 1021 | if (state == State::NonInitialized) { | ||
| 1022 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 1023 | rb.Push(NfcDisabled); | ||
| 1024 | return; | ||
| 1025 | } | ||
| 1026 | |||
| 1027 | auto device = GetNfpDevice(device_handle); | ||
| 1028 | |||
| 1029 | if (!device.has_value()) { | ||
| 1030 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 1031 | rb.Push(DeviceNotFound); | ||
| 1032 | return; | ||
| 1033 | } | ||
| 1034 | |||
| 1035 | const auto result = device.value()->WriteNtf(); | ||
| 1036 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 1037 | rb.Push(result); | ||
| 1038 | } | ||
| 1039 | |||
| 1040 | std::optional<std::shared_ptr<NfpDevice>> Interface::GetNfpDevice(u64 handle) { | ||
| 664 | for (auto& device : devices) { | 1041 | for (auto& device : devices) { |
| 665 | if (device->GetHandle() == handle) { | 1042 | if (device->GetHandle() == handle) { |
| 666 | return device; | 1043 | return device; |
diff --git a/src/core/hle/service/nfp/nfp_user.h b/src/core/hle/service/nfp/nfp_interface.h index 1f3ff2ea8..616c94b06 100644 --- a/src/core/hle/service/nfp/nfp_user.h +++ b/src/core/hle/service/nfp/nfp_interface.h | |||
| @@ -13,19 +13,17 @@ | |||
| 13 | namespace Service::NFP { | 13 | namespace Service::NFP { |
| 14 | class NfpDevice; | 14 | class NfpDevice; |
| 15 | 15 | ||
| 16 | class IUser final : public ServiceFramework<IUser> { | 16 | class Interface : public ServiceFramework<Interface> { |
| 17 | public: | 17 | public: |
| 18 | explicit IUser(Core::System& system_); | 18 | explicit Interface(Core::System& system_, const char* name); |
| 19 | ~IUser(); | 19 | ~Interface() override; |
| 20 | |||
| 21 | private: | ||
| 22 | enum class State : u32 { | ||
| 23 | NonInitialized, | ||
| 24 | Initialized, | ||
| 25 | }; | ||
| 26 | 20 | ||
| 27 | void Initialize(HLERequestContext& ctx); | 21 | void Initialize(HLERequestContext& ctx); |
| 22 | void InitializeSystem(HLERequestContext& ctx); | ||
| 23 | void InitializeDebug(HLERequestContext& ctx); | ||
| 28 | void Finalize(HLERequestContext& ctx); | 24 | void Finalize(HLERequestContext& ctx); |
| 25 | void FinalizeSystem(HLERequestContext& ctx); | ||
| 26 | void FinalizeDebug(HLERequestContext& ctx); | ||
| 29 | void ListDevices(HLERequestContext& ctx); | 27 | void ListDevices(HLERequestContext& ctx); |
| 30 | void StartDetection(HLERequestContext& ctx); | 28 | void StartDetection(HLERequestContext& ctx); |
| 31 | void StopDetection(HLERequestContext& ctx); | 29 | void StopDetection(HLERequestContext& ctx); |
| @@ -49,6 +47,26 @@ private: | |||
| 49 | void GetApplicationAreaSize(HLERequestContext& ctx); | 47 | void GetApplicationAreaSize(HLERequestContext& ctx); |
| 50 | void AttachAvailabilityChangeEvent(HLERequestContext& ctx); | 48 | void AttachAvailabilityChangeEvent(HLERequestContext& ctx); |
| 51 | void RecreateApplicationArea(HLERequestContext& ctx); | 49 | void RecreateApplicationArea(HLERequestContext& ctx); |
| 50 | void Format(HLERequestContext& ctx); | ||
| 51 | void GetAdminInfo(HLERequestContext& ctx); | ||
| 52 | void GetRegisterInfoPrivate(HLERequestContext& ctx); | ||
| 53 | void SetRegisterInfoPrivate(HLERequestContext& ctx); | ||
| 54 | void DeleteRegisterInfo(HLERequestContext& ctx); | ||
| 55 | void DeleteApplicationArea(HLERequestContext& ctx); | ||
| 56 | void ExistsApplicationArea(HLERequestContext& ctx); | ||
| 57 | void GetAll(HLERequestContext& ctx); | ||
| 58 | void SetAll(HLERequestContext& ctx); | ||
| 59 | void FlushDebug(HLERequestContext& ctx); | ||
| 60 | void BreakTag(HLERequestContext& ctx); | ||
| 61 | void ReadBackupData(HLERequestContext& ctx); | ||
| 62 | void WriteBackupData(HLERequestContext& ctx); | ||
| 63 | void WriteNtf(HLERequestContext& ctx); | ||
| 64 | |||
| 65 | private: | ||
| 66 | enum class State : u32 { | ||
| 67 | NonInitialized, | ||
| 68 | Initialized, | ||
| 69 | }; | ||
| 52 | 70 | ||
| 53 | std::optional<std::shared_ptr<NfpDevice>> GetNfpDevice(u64 handle); | 71 | std::optional<std::shared_ptr<NfpDevice>> GetNfpDevice(u64 handle); |
| 54 | 72 | ||
diff --git a/src/core/hle/service/nfp/nfp_types.h b/src/core/hle/service/nfp/nfp_types.h index 70c878552..1ef047cee 100644 --- a/src/core/hle/service/nfp/nfp_types.h +++ b/src/core/hle/service/nfp/nfp_types.h | |||
| @@ -109,6 +109,12 @@ enum class AppAreaVersion : u8 { | |||
| 109 | NotSet = 0xFF, | 109 | NotSet = 0xFF, |
| 110 | }; | 110 | }; |
| 111 | 111 | ||
| 112 | enum class BreakType : u32 { | ||
| 113 | Normal, | ||
| 114 | Unknown1, | ||
| 115 | Unknown2, | ||
| 116 | }; | ||
| 117 | |||
| 112 | enum class CabinetMode : u8 { | 118 | enum class CabinetMode : u8 { |
| 113 | StartNicknameAndOwnerSettings, | 119 | StartNicknameAndOwnerSettings, |
| 114 | StartGameDataEraser, | 120 | StartGameDataEraser, |
| @@ -181,6 +187,12 @@ struct AmiiboDate { | |||
| 181 | }; | 187 | }; |
| 182 | } | 188 | } |
| 183 | 189 | ||
| 190 | void SetWriteDate(const WriteDate& write_date) { | ||
| 191 | SetYear(write_date.year); | ||
| 192 | SetMonth(write_date.month); | ||
| 193 | SetDay(write_date.day); | ||
| 194 | } | ||
| 195 | |||
| 184 | void SetYear(u16 year) { | 196 | void SetYear(u16 year) { |
| 185 | const u16 year_converted = static_cast<u16>((year - 2000) << 9); | 197 | const u16 year_converted = static_cast<u16>((year - 2000) << 9); |
| 186 | raw_date = Common::swap16((GetValue() & ~0xFE00) | year_converted); | 198 | raw_date = Common::swap16((GetValue() & ~0xFE00) | year_converted); |
| @@ -354,6 +366,15 @@ struct RegisterInfo { | |||
| 354 | }; | 366 | }; |
| 355 | static_assert(sizeof(RegisterInfo) == 0x100, "RegisterInfo is an invalid size"); | 367 | static_assert(sizeof(RegisterInfo) == 0x100, "RegisterInfo is an invalid size"); |
| 356 | 368 | ||
| 369 | struct RegisterInfoPrivate { | ||
| 370 | Service::Mii::MiiStoreData mii_store_data; | ||
| 371 | WriteDate creation_date; | ||
| 372 | AmiiboName amiibo_name; | ||
| 373 | u8 font_region; | ||
| 374 | INSERT_PADDING_BYTES(0x8E); | ||
| 375 | }; | ||
| 376 | static_assert(sizeof(RegisterInfoPrivate) == 0x100, "RegisterInfoPrivate is an invalid size"); | ||
| 377 | |||
| 357 | struct AdminInfo { | 378 | struct AdminInfo { |
| 358 | u64 application_id; | 379 | u64 application_id; |
| 359 | u32 application_area_id; | 380 | u32 application_area_id; |
| @@ -366,6 +387,39 @@ struct AdminInfo { | |||
| 366 | }; | 387 | }; |
| 367 | static_assert(sizeof(AdminInfo) == 0x40, "AdminInfo is an invalid size"); | 388 | static_assert(sizeof(AdminInfo) == 0x40, "AdminInfo is an invalid size"); |
| 368 | 389 | ||
| 390 | #pragma pack(1) | ||
| 391 | // This is nn::nfp::NfpData | ||
| 392 | struct NfpData { | ||
| 393 | u8 magic; | ||
| 394 | INSERT_PADDING_BYTES(0x1); | ||
| 395 | u8 write_counter; | ||
| 396 | INSERT_PADDING_BYTES(0x1); | ||
| 397 | u32 settings_crc; | ||
| 398 | INSERT_PADDING_BYTES(0x38); | ||
| 399 | CommonInfo common_info; | ||
| 400 | Service::Mii::Ver3StoreData mii_char_info; | ||
| 401 | Service::Mii::NfpStoreDataExtension mii_store_data_extension; | ||
| 402 | WriteDate creation_date; | ||
| 403 | std::array<u16_be, amiibo_name_length> amiibo_name; | ||
| 404 | u16 amiibo_name_null_terminated; | ||
| 405 | Settings settings; | ||
| 406 | u8 unknown1; | ||
| 407 | u32 register_info_crc; | ||
| 408 | std::array<u32, 5> unknown2; | ||
| 409 | INSERT_PADDING_BYTES(0x64); | ||
| 410 | u64 application_id; | ||
| 411 | u32 access_id; | ||
| 412 | u16 settings_crc_counter; | ||
| 413 | u8 font_region; | ||
| 414 | PackedTagType tag_type; | ||
| 415 | AppAreaVersion console_type; | ||
| 416 | u8 application_id_byte; | ||
| 417 | INSERT_PADDING_BYTES(0x2E); | ||
| 418 | ApplicationArea application_area; | ||
| 419 | }; | ||
| 420 | static_assert(sizeof(NfpData) == 0x298, "NfpData is an invalid size"); | ||
| 421 | #pragma pack() | ||
| 422 | |||
| 369 | struct SectorKey { | 423 | struct SectorKey { |
| 370 | MifareCmd command; | 424 | MifareCmd command; |
| 371 | u8 unknown; // Usually 1 | 425 | u8 unknown; // Usually 1 |
diff --git a/src/dedicated_room/yuzu_room.cpp b/src/dedicated_room/yuzu_room.cpp index 359891883..d707dabe2 100644 --- a/src/dedicated_room/yuzu_room.cpp +++ b/src/dedicated_room/yuzu_room.cpp | |||
| @@ -49,6 +49,7 @@ static void PrintHelp(const char* argv0) { | |||
| 49 | " [options] <filename>\n" | 49 | " [options] <filename>\n" |
| 50 | "--room-name The name of the room\n" | 50 | "--room-name The name of the room\n" |
| 51 | "--room-description The room description\n" | 51 | "--room-description The room description\n" |
| 52 | "--bind-address The bind address for the room\n" | ||
| 52 | "--port The port used for the room\n" | 53 | "--port The port used for the room\n" |
| 53 | "--max_members The maximum number of players for this room\n" | 54 | "--max_members The maximum number of players for this room\n" |
| 54 | "--password The password for the room\n" | 55 | "--password The password for the room\n" |
| @@ -195,6 +196,7 @@ int main(int argc, char** argv) { | |||
| 195 | std::string web_api_url; | 196 | std::string web_api_url; |
| 196 | std::string ban_list_file; | 197 | std::string ban_list_file; |
| 197 | std::string log_file = "yuzu-room.log"; | 198 | std::string log_file = "yuzu-room.log"; |
| 199 | std::string bind_address; | ||
| 198 | u64 preferred_game_id = 0; | 200 | u64 preferred_game_id = 0; |
| 199 | u32 port = Network::DefaultRoomPort; | 201 | u32 port = Network::DefaultRoomPort; |
| 200 | u32 max_members = 16; | 202 | u32 max_members = 16; |
| @@ -203,6 +205,7 @@ int main(int argc, char** argv) { | |||
| 203 | static struct option long_options[] = { | 205 | static struct option long_options[] = { |
| 204 | {"room-name", required_argument, 0, 'n'}, | 206 | {"room-name", required_argument, 0, 'n'}, |
| 205 | {"room-description", required_argument, 0, 'd'}, | 207 | {"room-description", required_argument, 0, 'd'}, |
| 208 | {"bind-address", required_argument, 0, 's'}, | ||
| 206 | {"port", required_argument, 0, 'p'}, | 209 | {"port", required_argument, 0, 'p'}, |
| 207 | {"max_members", required_argument, 0, 'm'}, | 210 | {"max_members", required_argument, 0, 'm'}, |
| 208 | {"password", required_argument, 0, 'w'}, | 211 | {"password", required_argument, 0, 'w'}, |
| @@ -222,7 +225,8 @@ int main(int argc, char** argv) { | |||
| 222 | InitializeLogging(log_file); | 225 | InitializeLogging(log_file); |
| 223 | 226 | ||
| 224 | while (optind < argc) { | 227 | while (optind < argc) { |
| 225 | int arg = getopt_long(argc, argv, "n:d:p:m:w:g:u:t:a:i:l:hv", long_options, &option_index); | 228 | int arg = |
| 229 | getopt_long(argc, argv, "n:d:s:p:m:w:g:u:t:a:i:l:hv", long_options, &option_index); | ||
| 226 | if (arg != -1) { | 230 | if (arg != -1) { |
| 227 | switch (static_cast<char>(arg)) { | 231 | switch (static_cast<char>(arg)) { |
| 228 | case 'n': | 232 | case 'n': |
| @@ -231,6 +235,9 @@ int main(int argc, char** argv) { | |||
| 231 | case 'd': | 235 | case 'd': |
| 232 | room_description.assign(optarg); | 236 | room_description.assign(optarg); |
| 233 | break; | 237 | break; |
| 238 | case 's': | ||
| 239 | bind_address.assign(optarg); | ||
| 240 | break; | ||
| 234 | case 'p': | 241 | case 'p': |
| 235 | port = strtoul(optarg, &endarg, 0); | 242 | port = strtoul(optarg, &endarg, 0); |
| 236 | break; | 243 | break; |
| @@ -295,6 +302,9 @@ int main(int argc, char** argv) { | |||
| 295 | PrintHelp(argv[0]); | 302 | PrintHelp(argv[0]); |
| 296 | return -1; | 303 | return -1; |
| 297 | } | 304 | } |
| 305 | if (bind_address.empty()) { | ||
| 306 | LOG_INFO(Network, "Bind address is empty: defaulting to 0.0.0.0"); | ||
| 307 | } | ||
| 298 | if (port > UINT16_MAX) { | 308 | if (port > UINT16_MAX) { |
| 299 | LOG_ERROR(Network, "Port needs to be in the range 0 - 65535!"); | 309 | LOG_ERROR(Network, "Port needs to be in the range 0 - 65535!"); |
| 300 | PrintHelp(argv[0]); | 310 | PrintHelp(argv[0]); |
| @@ -358,8 +368,8 @@ int main(int argc, char** argv) { | |||
| 358 | if (auto room = network.GetRoom().lock()) { | 368 | if (auto room = network.GetRoom().lock()) { |
| 359 | AnnounceMultiplayerRoom::GameInfo preferred_game_info{.name = preferred_game, | 369 | AnnounceMultiplayerRoom::GameInfo preferred_game_info{.name = preferred_game, |
| 360 | .id = preferred_game_id}; | 370 | .id = preferred_game_id}; |
| 361 | if (!room->Create(room_name, room_description, "", port, password, max_members, username, | 371 | if (!room->Create(room_name, room_description, bind_address, port, password, max_members, |
| 362 | preferred_game_info, std::move(verify_backend), ban_list, | 372 | username, preferred_game_info, std::move(verify_backend), ban_list, |
| 363 | enable_yuzu_mods)) { | 373 | enable_yuzu_mods)) { |
| 364 | LOG_INFO(Network, "Failed to create room: "); | 374 | LOG_INFO(Network, "Failed to create room: "); |
| 365 | return -1; | 375 | return -1; |
diff --git a/src/video_core/engines/fermi_2d.cpp b/src/video_core/engines/fermi_2d.cpp index a126c359c..02e161270 100644 --- a/src/video_core/engines/fermi_2d.cpp +++ b/src/video_core/engines/fermi_2d.cpp | |||
| @@ -77,6 +77,14 @@ void Fermi2D::Blit() { | |||
| 77 | const auto bytes_per_pixel = BytesPerBlock(PixelFormatFromRenderTargetFormat(src.format)); | 77 | const auto bytes_per_pixel = BytesPerBlock(PixelFormatFromRenderTargetFormat(src.format)); |
| 78 | const bool delegate_to_gpu = src.width > 512 && src.height > 512 && bytes_per_pixel <= 8 && | 78 | const bool delegate_to_gpu = src.width > 512 && src.height > 512 && bytes_per_pixel <= 8 && |
| 79 | src.format != regs.dst.format; | 79 | src.format != regs.dst.format; |
| 80 | |||
| 81 | auto srcX = args.src_x0; | ||
| 82 | auto srcY = args.src_y0; | ||
| 83 | if (args.sample_mode.origin == Origin::Corner) { | ||
| 84 | srcX -= (args.du_dx >> 33) << 32; | ||
| 85 | srcY -= (args.dv_dy >> 33) << 32; | ||
| 86 | } | ||
| 87 | |||
| 80 | Config config{ | 88 | Config config{ |
| 81 | .operation = regs.operation, | 89 | .operation = regs.operation, |
| 82 | .filter = args.sample_mode.filter, | 90 | .filter = args.sample_mode.filter, |
| @@ -86,10 +94,10 @@ void Fermi2D::Blit() { | |||
| 86 | .dst_y0 = args.dst_y0, | 94 | .dst_y0 = args.dst_y0, |
| 87 | .dst_x1 = args.dst_x0 + args.dst_width, | 95 | .dst_x1 = args.dst_x0 + args.dst_width, |
| 88 | .dst_y1 = args.dst_y0 + args.dst_height, | 96 | .dst_y1 = args.dst_y0 + args.dst_height, |
| 89 | .src_x0 = static_cast<s32>(args.src_x0 >> 32), | 97 | .src_x0 = static_cast<s32>(srcX >> 32), |
| 90 | .src_y0 = static_cast<s32>(args.src_y0 >> 32), | 98 | .src_y0 = static_cast<s32>(srcY >> 32), |
| 91 | .src_x1 = static_cast<s32>((args.du_dx * args.dst_width + args.src_x0) >> 32), | 99 | .src_x1 = static_cast<s32>((srcX + args.du_dx * args.dst_width) >> 32), |
| 92 | .src_y1 = static_cast<s32>((args.dv_dy * args.dst_height + args.src_y0) >> 32), | 100 | .src_y1 = static_cast<s32>((srcY + args.dv_dy * args.dst_height) >> 32), |
| 93 | }; | 101 | }; |
| 94 | 102 | ||
| 95 | const auto need_align_to_pitch = | 103 | const auto need_align_to_pitch = |
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 614d61db4..0932fadc2 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | #include <cstring> | 4 | #include <cstring> |
| 5 | #include <optional> | 5 | #include <optional> |
| 6 | #include "common/assert.h" | 6 | #include "common/assert.h" |
| 7 | #include "common/bit_util.h" | ||
| 7 | #include "common/scope_exit.h" | 8 | #include "common/scope_exit.h" |
| 8 | #include "common/settings.h" | 9 | #include "common/settings.h" |
| 9 | #include "core/core.h" | 10 | #include "core/core.h" |
| @@ -259,12 +260,13 @@ u32 Maxwell3D::GetMaxCurrentVertices() { | |||
| 259 | size_t Maxwell3D::EstimateIndexBufferSize() { | 260 | size_t Maxwell3D::EstimateIndexBufferSize() { |
| 260 | GPUVAddr start_address = regs.index_buffer.StartAddress(); | 261 | GPUVAddr start_address = regs.index_buffer.StartAddress(); |
| 261 | GPUVAddr end_address = regs.index_buffer.EndAddress(); | 262 | GPUVAddr end_address = regs.index_buffer.EndAddress(); |
| 262 | static constexpr std::array<size_t, 4> max_sizes = { | 263 | static constexpr std::array<size_t, 3> max_sizes = {std::numeric_limits<u8>::max(), |
| 263 | std::numeric_limits<u8>::max(), std::numeric_limits<u16>::max(), | 264 | std::numeric_limits<u16>::max(), |
| 264 | std::numeric_limits<u32>::max(), std::numeric_limits<u32>::max()}; | 265 | std::numeric_limits<u32>::max()}; |
| 265 | const size_t byte_size = regs.index_buffer.FormatSizeInBytes(); | 266 | const size_t byte_size = regs.index_buffer.FormatSizeInBytes(); |
| 267 | const size_t log2_byte_size = Common::Log2Ceil64(byte_size); | ||
| 266 | return std::min<size_t>( | 268 | return std::min<size_t>( |
| 267 | memory_manager.GetMemoryLayoutSize(start_address, byte_size * max_sizes[byte_size]) / | 269 | memory_manager.GetMemoryLayoutSize(start_address, byte_size * max_sizes[log2_byte_size]) / |
| 268 | byte_size, | 270 | byte_size, |
| 269 | static_cast<size_t>(end_address - start_address)); | 271 | static_cast<size_t>(end_address - start_address)); |
| 270 | } | 272 | } |
diff --git a/src/video_core/renderer_vulkan/vk_master_semaphore.cpp b/src/video_core/renderer_vulkan/vk_master_semaphore.cpp index 8aa07ef9d..47c74e4d8 100644 --- a/src/video_core/renderer_vulkan/vk_master_semaphore.cpp +++ b/src/video_core/renderer_vulkan/vk_master_semaphore.cpp | |||
| @@ -10,7 +10,14 @@ | |||
| 10 | 10 | ||
| 11 | namespace Vulkan { | 11 | namespace Vulkan { |
| 12 | 12 | ||
| 13 | MasterSemaphore::MasterSemaphore(const Device& device) { | 13 | MasterSemaphore::MasterSemaphore(const Device& device_) : device(device_) { |
| 14 | if (!device.HasTimelineSemaphore()) { | ||
| 15 | static constexpr VkFenceCreateInfo fence_ci{ | ||
| 16 | .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, .pNext = nullptr, .flags = 0}; | ||
| 17 | fence = device.GetLogical().CreateFence(fence_ci); | ||
| 18 | return; | ||
| 19 | } | ||
| 20 | |||
| 14 | static constexpr VkSemaphoreTypeCreateInfo semaphore_type_ci{ | 21 | static constexpr VkSemaphoreTypeCreateInfo semaphore_type_ci{ |
| 15 | .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO, | 22 | .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO, |
| 16 | .pNext = nullptr, | 23 | .pNext = nullptr, |
| @@ -42,4 +49,134 @@ MasterSemaphore::MasterSemaphore(const Device& device) { | |||
| 42 | 49 | ||
| 43 | MasterSemaphore::~MasterSemaphore() = default; | 50 | MasterSemaphore::~MasterSemaphore() = default; |
| 44 | 51 | ||
| 52 | void MasterSemaphore::Refresh() { | ||
| 53 | if (!semaphore) { | ||
| 54 | // If we don't support timeline semaphores, there's nothing to refresh | ||
| 55 | return; | ||
| 56 | } | ||
| 57 | |||
| 58 | u64 this_tick{}; | ||
| 59 | u64 counter{}; | ||
| 60 | do { | ||
| 61 | this_tick = gpu_tick.load(std::memory_order_acquire); | ||
| 62 | counter = semaphore.GetCounter(); | ||
| 63 | if (counter < this_tick) { | ||
| 64 | return; | ||
| 65 | } | ||
| 66 | } while (!gpu_tick.compare_exchange_weak(this_tick, counter, std::memory_order_release, | ||
| 67 | std::memory_order_relaxed)); | ||
| 68 | } | ||
| 69 | |||
| 70 | void MasterSemaphore::Wait(u64 tick) { | ||
| 71 | if (!semaphore) { | ||
| 72 | // If we don't support timeline semaphores, use an atomic wait | ||
| 73 | while (true) { | ||
| 74 | u64 current_value = gpu_tick.load(std::memory_order_relaxed); | ||
| 75 | if (current_value >= tick) { | ||
| 76 | return; | ||
| 77 | } | ||
| 78 | gpu_tick.wait(current_value); | ||
| 79 | } | ||
| 80 | |||
| 81 | return; | ||
| 82 | } | ||
| 83 | |||
| 84 | // No need to wait if the GPU is ahead of the tick | ||
| 85 | if (IsFree(tick)) { | ||
| 86 | return; | ||
| 87 | } | ||
| 88 | |||
| 89 | // Update the GPU tick and try again | ||
| 90 | Refresh(); | ||
| 91 | |||
| 92 | if (IsFree(tick)) { | ||
| 93 | return; | ||
| 94 | } | ||
| 95 | |||
| 96 | // If none of the above is hit, fallback to a regular wait | ||
| 97 | while (!semaphore.Wait(tick)) { | ||
| 98 | } | ||
| 99 | |||
| 100 | Refresh(); | ||
| 101 | } | ||
| 102 | |||
| 103 | VkResult MasterSemaphore::SubmitQueue(vk::CommandBuffer& cmdbuf, VkSemaphore signal_semaphore, | ||
| 104 | VkSemaphore wait_semaphore, u64 host_tick) { | ||
| 105 | if (semaphore) { | ||
| 106 | return SubmitQueueTimeline(cmdbuf, signal_semaphore, wait_semaphore, host_tick); | ||
| 107 | } else { | ||
| 108 | return SubmitQueueFence(cmdbuf, signal_semaphore, wait_semaphore, host_tick); | ||
| 109 | } | ||
| 110 | } | ||
| 111 | |||
| 112 | static constexpr std::array<VkPipelineStageFlags, 2> wait_stage_masks{ | ||
| 113 | VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, | ||
| 114 | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, | ||
| 115 | }; | ||
| 116 | |||
| 117 | VkResult MasterSemaphore::SubmitQueueTimeline(vk::CommandBuffer& cmdbuf, | ||
| 118 | VkSemaphore signal_semaphore, | ||
| 119 | VkSemaphore wait_semaphore, u64 host_tick) { | ||
| 120 | const VkSemaphore timeline_semaphore = *semaphore; | ||
| 121 | |||
| 122 | const u32 num_signal_semaphores = signal_semaphore ? 2 : 1; | ||
| 123 | const std::array signal_values{host_tick, u64(0)}; | ||
| 124 | const std::array signal_semaphores{timeline_semaphore, signal_semaphore}; | ||
| 125 | |||
| 126 | const u32 num_wait_semaphores = wait_semaphore ? 2 : 1; | ||
| 127 | const std::array wait_values{host_tick - 1, u64(1)}; | ||
| 128 | const std::array wait_semaphores{timeline_semaphore, wait_semaphore}; | ||
| 129 | |||
| 130 | const VkTimelineSemaphoreSubmitInfo timeline_si{ | ||
| 131 | .sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO, | ||
| 132 | .pNext = nullptr, | ||
| 133 | .waitSemaphoreValueCount = num_wait_semaphores, | ||
| 134 | .pWaitSemaphoreValues = wait_values.data(), | ||
| 135 | .signalSemaphoreValueCount = num_signal_semaphores, | ||
| 136 | .pSignalSemaphoreValues = signal_values.data(), | ||
| 137 | }; | ||
| 138 | const VkSubmitInfo submit_info{ | ||
| 139 | .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, | ||
| 140 | .pNext = &timeline_si, | ||
| 141 | .waitSemaphoreCount = num_wait_semaphores, | ||
| 142 | .pWaitSemaphores = wait_semaphores.data(), | ||
| 143 | .pWaitDstStageMask = wait_stage_masks.data(), | ||
| 144 | .commandBufferCount = 1, | ||
| 145 | .pCommandBuffers = cmdbuf.address(), | ||
| 146 | .signalSemaphoreCount = num_signal_semaphores, | ||
| 147 | .pSignalSemaphores = signal_semaphores.data(), | ||
| 148 | }; | ||
| 149 | |||
| 150 | return device.GetGraphicsQueue().Submit(submit_info); | ||
| 151 | } | ||
| 152 | |||
| 153 | VkResult MasterSemaphore::SubmitQueueFence(vk::CommandBuffer& cmdbuf, VkSemaphore signal_semaphore, | ||
| 154 | VkSemaphore wait_semaphore, u64 host_tick) { | ||
| 155 | const u32 num_signal_semaphores = signal_semaphore ? 1 : 0; | ||
| 156 | const u32 num_wait_semaphores = wait_semaphore ? 1 : 0; | ||
| 157 | |||
| 158 | const VkSubmitInfo submit_info{ | ||
| 159 | .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, | ||
| 160 | .pNext = nullptr, | ||
| 161 | .waitSemaphoreCount = num_wait_semaphores, | ||
| 162 | .pWaitSemaphores = &wait_semaphore, | ||
| 163 | .pWaitDstStageMask = wait_stage_masks.data(), | ||
| 164 | .commandBufferCount = 1, | ||
| 165 | .pCommandBuffers = cmdbuf.address(), | ||
| 166 | .signalSemaphoreCount = num_signal_semaphores, | ||
| 167 | .pSignalSemaphores = &signal_semaphore, | ||
| 168 | }; | ||
| 169 | |||
| 170 | auto result = device.GetGraphicsQueue().Submit(submit_info, *fence); | ||
| 171 | |||
| 172 | if (result == VK_SUCCESS) { | ||
| 173 | fence.Wait(); | ||
| 174 | fence.Reset(); | ||
| 175 | gpu_tick.store(host_tick); | ||
| 176 | gpu_tick.notify_all(); | ||
| 177 | } | ||
| 178 | |||
| 179 | return result; | ||
| 180 | } | ||
| 181 | |||
| 45 | } // namespace Vulkan | 182 | } // namespace Vulkan |
diff --git a/src/video_core/renderer_vulkan/vk_master_semaphore.h b/src/video_core/renderer_vulkan/vk_master_semaphore.h index 689f02ea5..f2f61f781 100644 --- a/src/video_core/renderer_vulkan/vk_master_semaphore.h +++ b/src/video_core/renderer_vulkan/vk_master_semaphore.h | |||
| @@ -4,6 +4,8 @@ | |||
| 4 | #pragma once | 4 | #pragma once |
| 5 | 5 | ||
| 6 | #include <atomic> | 6 | #include <atomic> |
| 7 | #include <condition_variable> | ||
| 8 | #include <mutex> | ||
| 7 | #include <thread> | 9 | #include <thread> |
| 8 | 10 | ||
| 9 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| @@ -29,11 +31,6 @@ public: | |||
| 29 | return gpu_tick.load(std::memory_order_acquire); | 31 | return gpu_tick.load(std::memory_order_acquire); |
| 30 | } | 32 | } |
| 31 | 33 | ||
| 32 | /// Returns the timeline semaphore handle. | ||
| 33 | [[nodiscard]] VkSemaphore Handle() const noexcept { | ||
| 34 | return *semaphore; | ||
| 35 | } | ||
| 36 | |||
| 37 | /// Returns true when a tick has been hit by the GPU. | 34 | /// Returns true when a tick has been hit by the GPU. |
| 38 | [[nodiscard]] bool IsFree(u64 tick) const noexcept { | 35 | [[nodiscard]] bool IsFree(u64 tick) const noexcept { |
| 39 | return KnownGpuTick() >= tick; | 36 | return KnownGpuTick() >= tick; |
| @@ -45,37 +42,24 @@ public: | |||
| 45 | } | 42 | } |
| 46 | 43 | ||
| 47 | /// Refresh the known GPU tick | 44 | /// Refresh the known GPU tick |
| 48 | void Refresh() { | 45 | void Refresh(); |
| 49 | u64 this_tick{}; | ||
| 50 | u64 counter{}; | ||
| 51 | do { | ||
| 52 | this_tick = gpu_tick.load(std::memory_order_acquire); | ||
| 53 | counter = semaphore.GetCounter(); | ||
| 54 | if (counter < this_tick) { | ||
| 55 | return; | ||
| 56 | } | ||
| 57 | } while (!gpu_tick.compare_exchange_weak(this_tick, counter, std::memory_order_release, | ||
| 58 | std::memory_order_relaxed)); | ||
| 59 | } | ||
| 60 | 46 | ||
| 61 | /// Waits for a tick to be hit on the GPU | 47 | /// Waits for a tick to be hit on the GPU |
| 62 | void Wait(u64 tick) { | 48 | void Wait(u64 tick); |
| 63 | // No need to wait if the GPU is ahead of the tick | 49 | |
| 64 | if (IsFree(tick)) { | 50 | /// Submits the device graphics queue, updating the tick as necessary |
| 65 | return; | 51 | VkResult SubmitQueue(vk::CommandBuffer& cmdbuf, VkSemaphore signal_semaphore, |
| 66 | } | 52 | VkSemaphore wait_semaphore, u64 host_tick); |
| 67 | // Update the GPU tick and try again | 53 | |
| 68 | Refresh(); | 54 | private: |
| 69 | if (IsFree(tick)) { | 55 | VkResult SubmitQueueTimeline(vk::CommandBuffer& cmdbuf, VkSemaphore signal_semaphore, |
| 70 | return; | 56 | VkSemaphore wait_semaphore, u64 host_tick); |
| 71 | } | 57 | VkResult SubmitQueueFence(vk::CommandBuffer& cmdbuf, VkSemaphore signal_semaphore, |
| 72 | // If none of the above is hit, fallback to a regular wait | 58 | VkSemaphore wait_semaphore, u64 host_tick); |
| 73 | while (!semaphore.Wait(tick)) { | ||
| 74 | } | ||
| 75 | Refresh(); | ||
| 76 | } | ||
| 77 | 59 | ||
| 78 | private: | 60 | private: |
| 61 | const Device& device; ///< Device. | ||
| 62 | vk::Fence fence; ///< Fence. | ||
| 79 | vk::Semaphore semaphore; ///< Timeline semaphore. | 63 | vk::Semaphore semaphore; ///< Timeline semaphore. |
| 80 | std::atomic<u64> gpu_tick{0}; ///< Current known GPU tick. | 64 | std::atomic<u64> gpu_tick{0}; ///< Current known GPU tick. |
| 81 | std::atomic<u64> current_tick{1}; ///< Current logical tick. | 65 | std::atomic<u64> current_tick{1}; ///< Current logical tick. |
diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp index b264e6ada..057e16967 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.cpp +++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp | |||
| @@ -212,45 +212,13 @@ void Scheduler::SubmitExecution(VkSemaphore signal_semaphore, VkSemaphore wait_s | |||
| 212 | const u64 signal_value = master_semaphore->NextTick(); | 212 | const u64 signal_value = master_semaphore->NextTick(); |
| 213 | Record([signal_semaphore, wait_semaphore, signal_value, this](vk::CommandBuffer cmdbuf) { | 213 | Record([signal_semaphore, wait_semaphore, signal_value, this](vk::CommandBuffer cmdbuf) { |
| 214 | cmdbuf.End(); | 214 | cmdbuf.End(); |
| 215 | const VkSemaphore timeline_semaphore = master_semaphore->Handle(); | ||
| 216 | |||
| 217 | const u32 num_signal_semaphores = signal_semaphore ? 2U : 1U; | ||
| 218 | const std::array signal_values{signal_value, u64(0)}; | ||
| 219 | const std::array signal_semaphores{timeline_semaphore, signal_semaphore}; | ||
| 220 | |||
| 221 | const u32 num_wait_semaphores = wait_semaphore ? 2U : 1U; | ||
| 222 | const std::array wait_values{signal_value - 1, u64(1)}; | ||
| 223 | const std::array wait_semaphores{timeline_semaphore, wait_semaphore}; | ||
| 224 | static constexpr std::array<VkPipelineStageFlags, 2> wait_stage_masks{ | ||
| 225 | VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, | ||
| 226 | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, | ||
| 227 | }; | ||
| 228 | |||
| 229 | const VkTimelineSemaphoreSubmitInfo timeline_si{ | ||
| 230 | .sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO, | ||
| 231 | .pNext = nullptr, | ||
| 232 | .waitSemaphoreValueCount = num_wait_semaphores, | ||
| 233 | .pWaitSemaphoreValues = wait_values.data(), | ||
| 234 | .signalSemaphoreValueCount = num_signal_semaphores, | ||
| 235 | .pSignalSemaphoreValues = signal_values.data(), | ||
| 236 | }; | ||
| 237 | const VkSubmitInfo submit_info{ | ||
| 238 | .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, | ||
| 239 | .pNext = &timeline_si, | ||
| 240 | .waitSemaphoreCount = num_wait_semaphores, | ||
| 241 | .pWaitSemaphores = wait_semaphores.data(), | ||
| 242 | .pWaitDstStageMask = wait_stage_masks.data(), | ||
| 243 | .commandBufferCount = 1, | ||
| 244 | .pCommandBuffers = cmdbuf.address(), | ||
| 245 | .signalSemaphoreCount = num_signal_semaphores, | ||
| 246 | .pSignalSemaphores = signal_semaphores.data(), | ||
| 247 | }; | ||
| 248 | 215 | ||
| 249 | if (on_submit) { | 216 | if (on_submit) { |
| 250 | on_submit(); | 217 | on_submit(); |
| 251 | } | 218 | } |
| 252 | 219 | ||
| 253 | switch (const VkResult result = device.GetGraphicsQueue().Submit(submit_info)) { | 220 | switch (const VkResult result = master_semaphore->SubmitQueue( |
| 221 | cmdbuf, signal_semaphore, wait_semaphore, signal_value)) { | ||
| 254 | case VK_SUCCESS: | 222 | case VK_SUCCESS: |
| 255 | break; | 223 | break; |
| 256 | case VK_ERROR_DEVICE_LOST: | 224 | case VK_ERROR_DEVICE_LOST: |
diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index 41b5da18a..7d5018151 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h | |||
| @@ -145,7 +145,6 @@ | |||
| 145 | FEATURE_NAME(robustness2, robustImageAccess2) \ | 145 | FEATURE_NAME(robustness2, robustImageAccess2) \ |
| 146 | FEATURE_NAME(shader_demote_to_helper_invocation, shaderDemoteToHelperInvocation) \ | 146 | FEATURE_NAME(shader_demote_to_helper_invocation, shaderDemoteToHelperInvocation) \ |
| 147 | FEATURE_NAME(shader_draw_parameters, shaderDrawParameters) \ | 147 | FEATURE_NAME(shader_draw_parameters, shaderDrawParameters) \ |
| 148 | FEATURE_NAME(timeline_semaphore, timelineSemaphore) \ | ||
| 149 | FEATURE_NAME(variable_pointer, variablePointers) \ | 148 | FEATURE_NAME(variable_pointer, variablePointers) \ |
| 150 | FEATURE_NAME(variable_pointer, variablePointersStorageBuffer) | 149 | FEATURE_NAME(variable_pointer, variablePointersStorageBuffer) |
| 151 | 150 | ||
| @@ -158,6 +157,7 @@ | |||
| 158 | FEATURE_NAME(provoking_vertex, provokingVertexLast) \ | 157 | FEATURE_NAME(provoking_vertex, provokingVertexLast) \ |
| 159 | FEATURE_NAME(shader_float16_int8, shaderFloat16) \ | 158 | FEATURE_NAME(shader_float16_int8, shaderFloat16) \ |
| 160 | FEATURE_NAME(shader_float16_int8, shaderInt8) \ | 159 | FEATURE_NAME(shader_float16_int8, shaderInt8) \ |
| 160 | FEATURE_NAME(timeline_semaphore, timelineSemaphore) \ | ||
| 161 | FEATURE_NAME(transform_feedback, transformFeedback) \ | 161 | FEATURE_NAME(transform_feedback, transformFeedback) \ |
| 162 | FEATURE_NAME(uniform_buffer_standard_layout, uniformBufferStandardLayout) \ | 162 | FEATURE_NAME(uniform_buffer_standard_layout, uniformBufferStandardLayout) \ |
| 163 | FEATURE_NAME(vertex_input_dynamic_state, vertexInputDynamicState) | 163 | FEATURE_NAME(vertex_input_dynamic_state, vertexInputDynamicState) |
| @@ -493,6 +493,10 @@ public: | |||
| 493 | return extensions.shader_atomic_int64; | 493 | return extensions.shader_atomic_int64; |
| 494 | } | 494 | } |
| 495 | 495 | ||
| 496 | bool HasTimelineSemaphore() const { | ||
| 497 | return features.timeline_semaphore.timelineSemaphore; | ||
| 498 | } | ||
| 499 | |||
| 496 | /// Returns the minimum supported version of SPIR-V. | 500 | /// Returns the minimum supported version of SPIR-V. |
| 497 | u32 SupportedSpirvVersion() const { | 501 | u32 SupportedSpirvVersion() const { |
| 498 | if (instance_version >= VK_API_VERSION_1_3) { | 502 | if (instance_version >= VK_API_VERSION_1_3) { |