summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/core.cpp15
-rw-r--r--src/core/core.h8
-rw-r--r--src/core/cpu_manager.cpp2
-rw-r--r--src/core/frontend/applets/controller.cpp2
-rw-r--r--src/core/frontend/applets/controller.h4
-rw-r--r--src/core/hle/kernel/kernel.cpp5
-rw-r--r--src/core/hle/kernel/process.cpp3
-rw-r--r--src/core/hle/service/am/am.cpp2
-rw-r--r--src/core/hle/service/hid/hid.cpp2
-rw-r--r--src/core/hle/service/mii/mii.cpp1
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp100
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.h71
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp234
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h168
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_vic.cpp90
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_vic.h88
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.h1
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.cpp4
-rw-r--r--src/core/hle/service/set/set.cpp1
-rw-r--r--src/core/hle/service/set/set_sys.cpp2
-rw-r--r--src/core/hle/service/time/time.cpp28
-rw-r--r--src/core/hle/service/time/time.h9
-rw-r--r--src/core/hle/service/time/time_manager.cpp359
-rw-r--r--src/core/hle/service/time/time_manager.h85
-rw-r--r--src/core/hle/service/time/time_zone_content_manager.cpp5
-rw-r--r--src/core/hle/service/time/time_zone_content_manager.h4
-rw-r--r--src/core/settings.cpp2
-rw-r--r--src/core/settings.h1
-rw-r--r--src/core/telemetry_session.cpp2
30 files changed, 813 insertions, 487 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index db1c9fdef..e0f207f3e 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -439,6 +439,8 @@ add_library(core STATIC
439 hle/service/nvdrv/devices/nvhost_gpu.h 439 hle/service/nvdrv/devices/nvhost_gpu.h
440 hle/service/nvdrv/devices/nvhost_nvdec.cpp 440 hle/service/nvdrv/devices/nvhost_nvdec.cpp
441 hle/service/nvdrv/devices/nvhost_nvdec.h 441 hle/service/nvdrv/devices/nvhost_nvdec.h
442 hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
443 hle/service/nvdrv/devices/nvhost_nvdec_common.h
442 hle/service/nvdrv/devices/nvhost_nvjpg.cpp 444 hle/service/nvdrv/devices/nvhost_nvjpg.cpp
443 hle/service/nvdrv/devices/nvhost_nvjpg.h 445 hle/service/nvdrv/devices/nvhost_nvjpg.h
444 hle/service/nvdrv/devices/nvhost_vic.cpp 446 hle/service/nvdrv/devices/nvhost_vic.cpp
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 81e8cc338..fde2ccc09 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -40,6 +40,7 @@
40#include "core/hle/service/lm/manager.h" 40#include "core/hle/service/lm/manager.h"
41#include "core/hle/service/service.h" 41#include "core/hle/service/service.h"
42#include "core/hle/service/sm/sm.h" 42#include "core/hle/service/sm/sm.h"
43#include "core/hle/service/time/time_manager.h"
43#include "core/loader/loader.h" 44#include "core/loader/loader.h"
44#include "core/memory.h" 45#include "core/memory.h"
45#include "core/memory/cheat_engine.h" 46#include "core/memory/cheat_engine.h"
@@ -121,7 +122,7 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
121struct System::Impl { 122struct System::Impl {
122 explicit Impl(System& system) 123 explicit Impl(System& system)
123 : kernel{system}, fs_controller{system}, memory{system}, 124 : kernel{system}, fs_controller{system}, memory{system},
124 cpu_manager{system}, reporter{system}, applet_manager{system} {} 125 cpu_manager{system}, reporter{system}, applet_manager{system}, time_manager{system} {}
125 126
126 ResultStatus Run() { 127 ResultStatus Run() {
127 status = ResultStatus::Success; 128 status = ResultStatus::Success;
@@ -189,6 +190,9 @@ struct System::Impl {
189 return ResultStatus::ErrorVideoCore; 190 return ResultStatus::ErrorVideoCore;
190 } 191 }
191 192
193 // Initialize time manager, which must happen after kernel is created
194 time_manager.Initialize();
195
192 is_powered_on = true; 196 is_powered_on = true;
193 exit_lock = false; 197 exit_lock = false;
194 198
@@ -387,6 +391,7 @@ struct System::Impl {
387 /// Service State 391 /// Service State
388 Service::Glue::ARPManager arp_manager; 392 Service::Glue::ARPManager arp_manager;
389 Service::LM::Manager lm_manager{reporter}; 393 Service::LM::Manager lm_manager{reporter};
394 Service::Time::TimeManager time_manager;
390 395
391 /// Service manager 396 /// Service manager
392 std::shared_ptr<Service::SM::ServiceManager> service_manager; 397 std::shared_ptr<Service::SM::ServiceManager> service_manager;
@@ -717,6 +722,14 @@ const Service::LM::Manager& System::GetLogManager() const {
717 return impl->lm_manager; 722 return impl->lm_manager;
718} 723}
719 724
725Service::Time::TimeManager& System::GetTimeManager() {
726 return impl->time_manager;
727}
728
729const Service::Time::TimeManager& System::GetTimeManager() const {
730 return impl->time_manager;
731}
732
720void System::SetExitLock(bool locked) { 733void System::SetExitLock(bool locked) {
721 impl->exit_lock = locked; 734 impl->exit_lock = locked;
722} 735}
diff --git a/src/core/core.h b/src/core/core.h
index 27efe30bb..6db896bae 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -69,6 +69,10 @@ namespace SM {
69class ServiceManager; 69class ServiceManager;
70} // namespace SM 70} // namespace SM
71 71
72namespace Time {
73class TimeManager;
74} // namespace Time
75
72} // namespace Service 76} // namespace Service
73 77
74namespace Tegra { 78namespace Tegra {
@@ -361,6 +365,10 @@ public:
361 365
362 const Service::LM::Manager& GetLogManager() const; 366 const Service::LM::Manager& GetLogManager() const;
363 367
368 Service::Time::TimeManager& GetTimeManager();
369
370 const Service::Time::TimeManager& GetTimeManager() const;
371
364 void SetExitLock(bool locked); 372 void SetExitLock(bool locked);
365 373
366 bool GetExitLock() const; 374 bool GetExitLock() const;
diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp
index 688b99eba..983210197 100644
--- a/src/core/cpu_manager.cpp
+++ b/src/core/cpu_manager.cpp
@@ -365,6 +365,8 @@ void CpuManager::RunThread(std::size_t core) {
365 data.enter_barrier.reset(); 365 data.enter_barrier.reset();
366 data.exit_barrier.reset(); 366 data.exit_barrier.reset();
367 data.initialized = false; 367 data.initialized = false;
368
369 MicroProfileOnThreadExit();
368} 370}
369 371
370} // namespace Core 372} // namespace Core
diff --git a/src/core/frontend/applets/controller.cpp b/src/core/frontend/applets/controller.cpp
index c5d65f2d0..5582091f4 100644
--- a/src/core/frontend/applets/controller.cpp
+++ b/src/core/frontend/applets/controller.cpp
@@ -19,7 +19,7 @@ DefaultControllerApplet::DefaultControllerApplet(Service::SM::ServiceManager& se
19DefaultControllerApplet::~DefaultControllerApplet() = default; 19DefaultControllerApplet::~DefaultControllerApplet() = default;
20 20
21void DefaultControllerApplet::ReconfigureControllers(std::function<void()> callback, 21void DefaultControllerApplet::ReconfigureControllers(std::function<void()> callback,
22 ControllerParameters parameters) const { 22 const ControllerParameters& parameters) const {
23 LOG_INFO(Service_HID, "called, deducing the best configuration based on the given parameters!"); 23 LOG_INFO(Service_HID, "called, deducing the best configuration based on the given parameters!");
24 24
25 auto& npad = 25 auto& npad =
diff --git a/src/core/frontend/applets/controller.h b/src/core/frontend/applets/controller.h
index 3e49cdbb9..dff71d8d9 100644
--- a/src/core/frontend/applets/controller.h
+++ b/src/core/frontend/applets/controller.h
@@ -38,7 +38,7 @@ public:
38 virtual ~ControllerApplet(); 38 virtual ~ControllerApplet();
39 39
40 virtual void ReconfigureControllers(std::function<void()> callback, 40 virtual void ReconfigureControllers(std::function<void()> callback,
41 ControllerParameters parameters) const = 0; 41 const ControllerParameters& parameters) const = 0;
42}; 42};
43 43
44class DefaultControllerApplet final : public ControllerApplet { 44class DefaultControllerApplet final : public ControllerApplet {
@@ -47,7 +47,7 @@ public:
47 ~DefaultControllerApplet() override; 47 ~DefaultControllerApplet() override;
48 48
49 void ReconfigureControllers(std::function<void()> callback, 49 void ReconfigureControllers(std::function<void()> callback,
50 ControllerParameters parameters) const override; 50 const ControllerParameters& parameters) const override;
51 51
52private: 52private:
53 Service::SM::ServiceManager& service_manager; 53 Service::SM::ServiceManager& service_manager;
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index b2b5b8adf..bb3e312a7 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -86,8 +86,6 @@ struct KernelCore::Impl {
86 } 86 }
87 cores.clear(); 87 cores.clear();
88 88
89 registered_core_threads.reset();
90
91 process_list.clear(); 89 process_list.clear();
92 current_process = nullptr; 90 current_process = nullptr;
93 91
@@ -199,9 +197,7 @@ struct KernelCore::Impl {
199 const auto it = std::find(register_host_thread_keys.begin(), end, this_id); 197 const auto it = std::find(register_host_thread_keys.begin(), end, this_id);
200 ASSERT(core_id < Core::Hardware::NUM_CPU_CORES); 198 ASSERT(core_id < Core::Hardware::NUM_CPU_CORES);
201 ASSERT(it == end); 199 ASSERT(it == end);
202 ASSERT(!registered_core_threads[core_id]);
203 InsertHostThread(static_cast<u32>(core_id)); 200 InsertHostThread(static_cast<u32>(core_id));
204 registered_core_threads.set(core_id);
205 } 201 }
206 202
207 void RegisterHostThread() { 203 void RegisterHostThread() {
@@ -332,7 +328,6 @@ struct KernelCore::Impl {
332 328
333 // 0-3 IDs represent core threads, >3 represent others 329 // 0-3 IDs represent core threads, >3 represent others
334 std::atomic<u32> registered_thread_ids{Core::Hardware::NUM_CPU_CORES}; 330 std::atomic<u32> registered_thread_ids{Core::Hardware::NUM_CPU_CORES};
335 std::bitset<Core::Hardware::NUM_CPU_CORES> registered_core_threads;
336 331
337 // Number of host threads is a relatively high number to avoid overflowing 332 // Number of host threads is a relatively high number to avoid overflowing
338 static constexpr size_t NUM_REGISTRABLE_HOST_THREADS = 64; 333 static constexpr size_t NUM_REGISTRABLE_HOST_THREADS = 64;
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index ff9d9248b..b17529dee 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -4,6 +4,7 @@
4 4
5#include <algorithm> 5#include <algorithm>
6#include <bitset> 6#include <bitset>
7#include <ctime>
7#include <memory> 8#include <memory>
8#include <random> 9#include <random>
9#include "common/alignment.h" 10#include "common/alignment.h"
@@ -123,7 +124,7 @@ std::shared_ptr<Process> Process::Create(Core::System& system, std::string name,
123 : kernel.CreateNewUserProcessID(); 124 : kernel.CreateNewUserProcessID();
124 process->capabilities.InitializeForMetadatalessProcess(); 125 process->capabilities.InitializeForMetadatalessProcess();
125 126
126 std::mt19937 rng(Settings::values.rng_seed.GetValue().value_or(0)); 127 std::mt19937 rng(Settings::values.rng_seed.GetValue().value_or(std::time(nullptr)));
127 std::uniform_int_distribution<u64> distribution; 128 std::uniform_int_distribution<u64> distribution;
128 std::generate(process->random_entropy.begin(), process->random_entropy.end(), 129 std::generate(process->random_entropy.begin(), process->random_entropy.end(),
129 [&] { return distribution(rng); }); 130 [&] { return distribution(rng); });
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index d7a81f64a..2ce742e35 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -1201,6 +1201,8 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_)
1201 {151, nullptr, "TryPopFromNotificationStorageChannel"}, 1201 {151, nullptr, "TryPopFromNotificationStorageChannel"},
1202 {160, nullptr, "GetHealthWarningDisappearedSystemEvent"}, 1202 {160, nullptr, "GetHealthWarningDisappearedSystemEvent"},
1203 {170, nullptr, "SetHdcpAuthenticationActivated"}, 1203 {170, nullptr, "SetHdcpAuthenticationActivated"},
1204 {180, nullptr, "GetLaunchRequiredVersion"},
1205 {181, nullptr, "UpgradeLaunchRequiredVersion"},
1204 {500, nullptr, "StartContinuousRecordingFlushForDebug"}, 1206 {500, nullptr, "StartContinuousRecordingFlushForDebug"},
1205 {1000, nullptr, "CreateMovieMaker"}, 1207 {1000, nullptr, "CreateMovieMaker"},
1206 {1001, nullptr, "PrepareForJit"}, 1208 {1001, nullptr, "PrepareForJit"},
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 8918946a1..50f709b25 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -260,7 +260,7 @@ Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) {
260 {404, nullptr, "HasLeftRightBattery"}, 260 {404, nullptr, "HasLeftRightBattery"},
261 {405, nullptr, "GetNpadInterfaceType"}, 261 {405, nullptr, "GetNpadInterfaceType"},
262 {406, nullptr, "GetNpadLeftRightInterfaceType"}, 262 {406, nullptr, "GetNpadLeftRightInterfaceType"},
263 {407, nullptr, "GetNpadOfHighestBatteryLevelForJoyLeft"}, 263 {407, nullptr, "GetNpadOfHighestBatteryLevel"},
264 {408, nullptr, "GetNpadOfHighestBatteryLevelForJoyRight"}, 264 {408, nullptr, "GetNpadOfHighestBatteryLevelForJoyRight"},
265 {500, nullptr, "GetPalmaConnectionHandle"}, 265 {500, nullptr, "GetPalmaConnectionHandle"},
266 {501, nullptr, "InitializePalma"}, 266 {501, nullptr, "InitializePalma"},
diff --git a/src/core/hle/service/mii/mii.cpp b/src/core/hle/service/mii/mii.cpp
index b81bf6277..d7080b715 100644
--- a/src/core/hle/service/mii/mii.cpp
+++ b/src/core/hle/service/mii/mii.cpp
@@ -47,6 +47,7 @@ public:
47 {23, nullptr, "Convert"}, 47 {23, nullptr, "Convert"},
48 {24, nullptr, "ConvertCoreDataToCharInfo"}, 48 {24, nullptr, "ConvertCoreDataToCharInfo"},
49 {25, nullptr, "ConvertCharInfoToCoreData"}, 49 {25, nullptr, "ConvertCharInfoToCoreData"},
50 {26, nullptr, "Append"},
50 }; 51 };
51 // clang-format on 52 // clang-format on
52 53
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
index fcb612864..b6df48360 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
@@ -2,15 +2,17 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <cstring>
6
7#include "common/assert.h" 5#include "common/assert.h"
8#include "common/logging/log.h" 6#include "common/logging/log.h"
7#include "core/core.h"
9#include "core/hle/service/nvdrv/devices/nvhost_nvdec.h" 8#include "core/hle/service/nvdrv/devices/nvhost_nvdec.h"
9#include "video_core/memory_manager.h"
10#include "video_core/renderer_base.h"
10 11
11namespace Service::Nvidia::Devices { 12namespace Service::Nvidia::Devices {
12 13
13nvhost_nvdec::nvhost_nvdec(Core::System& system) : nvdevice(system) {} 14nvhost_nvdec::nvhost_nvdec(Core::System& system, std::shared_ptr<nvmap> nvmap_dev)
15 : nvhost_nvdec_common(system, std::move(nvmap_dev)) {}
14nvhost_nvdec::~nvhost_nvdec() = default; 16nvhost_nvdec::~nvhost_nvdec() = default;
15 17
16u32 nvhost_nvdec::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, 18u32 nvhost_nvdec::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
@@ -21,7 +23,7 @@ u32 nvhost_nvdec::ioctl(Ioctl command, const std::vector<u8>& input, const std::
21 23
22 switch (static_cast<IoctlCommand>(command.raw)) { 24 switch (static_cast<IoctlCommand>(command.raw)) {
23 case IoctlCommand::IocSetNVMAPfdCommand: 25 case IoctlCommand::IocSetNVMAPfdCommand:
24 return SetNVMAPfd(input, output); 26 return SetNVMAPfd(input);
25 case IoctlCommand::IocSubmit: 27 case IoctlCommand::IocSubmit:
26 return Submit(input, output); 28 return Submit(input, output);
27 case IoctlCommand::IocGetSyncpoint: 29 case IoctlCommand::IocGetSyncpoint:
@@ -29,79 +31,29 @@ u32 nvhost_nvdec::ioctl(Ioctl command, const std::vector<u8>& input, const std::
29 case IoctlCommand::IocGetWaitbase: 31 case IoctlCommand::IocGetWaitbase:
30 return GetWaitbase(input, output); 32 return GetWaitbase(input, output);
31 case IoctlCommand::IocMapBuffer: 33 case IoctlCommand::IocMapBuffer:
32 return MapBuffer(input, output); 34 case IoctlCommand::IocMapBuffer2:
35 case IoctlCommand::IocMapBuffer3:
33 case IoctlCommand::IocMapBufferEx: 36 case IoctlCommand::IocMapBufferEx:
34 return MapBufferEx(input, output); 37 return MapBuffer(input, output);
35 case IoctlCommand::IocUnmapBufferEx: 38 case IoctlCommand::IocUnmapBufferEx: {
36 return UnmapBufferEx(input, output); 39 // This command is sent when the video stream has ended, flush all video contexts
40 // This is usually sent in the folowing order: vic, nvdec, vic.
41 // Inform the GPU to clear any remaining nvdec buffers when this is detected.
42 LOG_INFO(Service_NVDRV, "NVDEC video stream ended");
43 Tegra::ChCommandHeaderList cmdlist(1);
44 cmdlist[0] = Tegra::ChCommandHeader{0xDEADB33F};
45 system.GPU().PushCommandBuffer(cmdlist);
46 [[fallthrough]]; // fallthrough to unmap buffers
47 };
48 case IoctlCommand::IocUnmapBuffer:
49 case IoctlCommand::IocUnmapBuffer2:
50 case IoctlCommand::IocUnmapBuffer3:
51 return UnmapBuffer(input, output);
52 case IoctlCommand::IocSetSubmitTimeout:
53 return SetSubmitTimeout(input, output);
37 } 54 }
38 55
39 UNIMPLEMENTED_MSG("Unimplemented ioctl"); 56 UNIMPLEMENTED_MSG("Unimplemented ioctl 0x{:X}", command.raw);
40 return 0;
41}
42
43u32 nvhost_nvdec::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) {
44 IoctlSetNvmapFD params{};
45 std::memcpy(&params, input.data(), sizeof(IoctlSetNvmapFD));
46 LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
47
48 nvmap_fd = params.nvmap_fd;
49 return 0;
50}
51
52u32 nvhost_nvdec::Submit(const std::vector<u8>& input, std::vector<u8>& output) {
53 IoctlSubmit params{};
54 std::memcpy(&params, input.data(), sizeof(IoctlSubmit));
55 LOG_WARNING(Service_NVDRV, "(STUBBED) called");
56 std::memcpy(output.data(), &params, sizeof(IoctlSubmit));
57 return 0;
58}
59
60u32 nvhost_nvdec::GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output) {
61 IoctlGetSyncpoint params{};
62 std::memcpy(&params, input.data(), sizeof(IoctlGetSyncpoint));
63 LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown);
64 params.value = 0; // Seems to be hard coded at 0
65 std::memcpy(output.data(), &params, sizeof(IoctlGetSyncpoint));
66 return 0;
67}
68
69u32 nvhost_nvdec::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) {
70 IoctlGetWaitbase params{};
71 std::memcpy(&params, input.data(), sizeof(IoctlGetWaitbase));
72 LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown);
73 params.value = 0; // Seems to be hard coded at 0
74 std::memcpy(output.data(), &params, sizeof(IoctlGetWaitbase));
75 return 0;
76}
77
78u32 nvhost_nvdec::MapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {
79 IoctlMapBuffer params{};
80 std::memcpy(&params, input.data(), sizeof(IoctlMapBuffer));
81 LOG_WARNING(Service_NVDRV, "(STUBBED) called with address={:08X}{:08X}", params.address_2,
82 params.address_1);
83 params.address_1 = 0;
84 params.address_2 = 0;
85 std::memcpy(output.data(), &params, sizeof(IoctlMapBuffer));
86 return 0;
87}
88
89u32 nvhost_nvdec::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) {
90 IoctlMapBufferEx params{};
91 std::memcpy(&params, input.data(), sizeof(IoctlMapBufferEx));
92 LOG_WARNING(Service_NVDRV, "(STUBBED) called with address={:08X}{:08X}", params.address_2,
93 params.address_1);
94 params.address_1 = 0;
95 params.address_2 = 0;
96 std::memcpy(output.data(), &params, sizeof(IoctlMapBufferEx));
97 return 0;
98}
99
100u32 nvhost_nvdec::UnmapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) {
101 IoctlUnmapBufferEx params{};
102 std::memcpy(&params, input.data(), sizeof(IoctlUnmapBufferEx));
103 LOG_WARNING(Service_NVDRV, "(STUBBED) called");
104 std::memcpy(output.data(), &params, sizeof(IoctlUnmapBufferEx));
105 return 0; 57 return 0;
106} 58}
107 59
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
index 4332db118..102777ddd 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
@@ -4,16 +4,14 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <vector> 7#include <memory>
8#include "common/common_types.h" 8#include "core/hle/service/nvdrv/devices/nvhost_nvdec_common.h"
9#include "common/swap.h"
10#include "core/hle/service/nvdrv/devices/nvdevice.h"
11 9
12namespace Service::Nvidia::Devices { 10namespace Service::Nvidia::Devices {
13 11
14class nvhost_nvdec final : public nvdevice { 12class nvhost_nvdec final : public nvhost_nvdec_common {
15public: 13public:
16 explicit nvhost_nvdec(Core::System& system); 14 explicit nvhost_nvdec(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
17 ~nvhost_nvdec() override; 15 ~nvhost_nvdec() override;
18 16
19 u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, 17 u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
@@ -27,62 +25,15 @@ private:
27 IocGetSyncpoint = 0xC0080002, 25 IocGetSyncpoint = 0xC0080002,
28 IocGetWaitbase = 0xC0080003, 26 IocGetWaitbase = 0xC0080003,
29 IocMapBuffer = 0xC01C0009, 27 IocMapBuffer = 0xC01C0009,
28 IocMapBuffer2 = 0xC16C0009,
29 IocMapBuffer3 = 0xC15C0009,
30 IocMapBufferEx = 0xC0A40009, 30 IocMapBufferEx = 0xC0A40009,
31 IocUnmapBufferEx = 0xC0A4000A, 31 IocUnmapBuffer = 0xC0A4000A,
32 IocUnmapBuffer2 = 0xC16C000A,
33 IocUnmapBufferEx = 0xC01C000A,
34 IocUnmapBuffer3 = 0xC15C000A,
35 IocSetSubmitTimeout = 0x40040007,
32 }; 36 };
33
34 struct IoctlSetNvmapFD {
35 u32_le nvmap_fd;
36 };
37 static_assert(sizeof(IoctlSetNvmapFD) == 0x4, "IoctlSetNvmapFD is incorrect size");
38
39 struct IoctlSubmit {
40 INSERT_PADDING_BYTES(0x40); // TODO(DarkLordZach): RE this structure
41 };
42 static_assert(sizeof(IoctlSubmit) == 0x40, "IoctlSubmit has incorrect size");
43
44 struct IoctlGetSyncpoint {
45 u32 unknown; // seems to be ignored? Nintendo added this
46 u32 value;
47 };
48 static_assert(sizeof(IoctlGetSyncpoint) == 0x08, "IoctlGetSyncpoint has incorrect size");
49
50 struct IoctlGetWaitbase {
51 u32 unknown; // seems to be ignored? Nintendo added this
52 u32 value;
53 };
54 static_assert(sizeof(IoctlGetWaitbase) == 0x08, "IoctlGetWaitbase has incorrect size");
55
56 struct IoctlMapBuffer {
57 u32 unknown;
58 u32 address_1;
59 u32 address_2;
60 INSERT_PADDING_BYTES(0x10); // TODO(DarkLordZach): RE this structure
61 };
62 static_assert(sizeof(IoctlMapBuffer) == 0x1C, "IoctlMapBuffer is incorrect size");
63
64 struct IoctlMapBufferEx {
65 u32 unknown;
66 u32 address_1;
67 u32 address_2;
68 INSERT_PADDING_BYTES(0x98); // TODO(DarkLordZach): RE this structure
69 };
70 static_assert(sizeof(IoctlMapBufferEx) == 0xA4, "IoctlMapBufferEx has incorrect size");
71
72 struct IoctlUnmapBufferEx {
73 INSERT_PADDING_BYTES(0xA4); // TODO(DarkLordZach): RE this structure
74 };
75 static_assert(sizeof(IoctlUnmapBufferEx) == 0xA4, "IoctlUnmapBufferEx has incorrect size");
76
77 u32_le nvmap_fd{};
78
79 u32 SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output);
80 u32 Submit(const std::vector<u8>& input, std::vector<u8>& output);
81 u32 GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output);
82 u32 GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output);
83 u32 MapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
84 u32 MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output);
85 u32 UnmapBufferEx(const std::vector<u8>& input, std::vector<u8>& output);
86}; 37};
87 38
88} // namespace Service::Nvidia::Devices 39} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
new file mode 100644
index 000000000..85792495f
--- /dev/null
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
@@ -0,0 +1,234 @@
1// Copyright 2020 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include <cstring>
7
8#include "common/assert.h"
9#include "common/common_types.h"
10#include "common/logging/log.h"
11#include "core/core.h"
12#include "core/hle/service/nvdrv/devices/nvhost_nvdec_common.h"
13#include "core/hle/service/nvdrv/devices/nvmap.h"
14#include "core/memory.h"
15#include "video_core/memory_manager.h"
16#include "video_core/renderer_base.h"
17
18namespace Service::Nvidia::Devices {
19
20namespace {
21// Splice vectors will copy count amount of type T from the input vector into the dst vector.
22template <typename T>
23std::size_t SpliceVectors(const std::vector<u8>& input, std::vector<T>& dst, std::size_t count,
24 std::size_t offset) {
25 std::memcpy(dst.data(), input.data() + offset, count * sizeof(T));
26 offset += count * sizeof(T);
27 return offset;
28}
29
30// Write vectors will write data to the output buffer
31template <typename T>
32std::size_t WriteVectors(std::vector<u8>& dst, const std::vector<T>& src, std::size_t offset) {
33 std::memcpy(dst.data() + offset, src.data(), src.size() * sizeof(T));
34 offset += src.size() * sizeof(T);
35 return offset;
36}
37} // Anonymous namespace
38
39namespace NvErrCodes {
40constexpr u32 Success{};
41constexpr u32 OutOfMemory{static_cast<u32>(-12)};
42constexpr u32 InvalidInput{static_cast<u32>(-22)};
43} // namespace NvErrCodes
44
45nvhost_nvdec_common::nvhost_nvdec_common(Core::System& system, std::shared_ptr<nvmap> nvmap_dev)
46 : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {}
47nvhost_nvdec_common::~nvhost_nvdec_common() = default;
48
49u32 nvhost_nvdec_common::SetNVMAPfd(const std::vector<u8>& input) {
50 IoctlSetNvmapFD params{};
51 std::memcpy(&params, input.data(), sizeof(IoctlSetNvmapFD));
52 LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
53
54 nvmap_fd = params.nvmap_fd;
55 return 0;
56}
57
58u32 nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u8>& output) {
59 IoctlSubmit params{};
60 std::memcpy(&params, input.data(), sizeof(IoctlSubmit));
61 LOG_DEBUG(Service_NVDRV, "called NVDEC Submit, cmd_buffer_count={}", params.cmd_buffer_count);
62
63 // Instantiate param buffers
64 std::size_t offset = sizeof(IoctlSubmit);
65 std::vector<CommandBuffer> command_buffers(params.cmd_buffer_count);
66 std::vector<Reloc> relocs(params.relocation_count);
67 std::vector<u32> reloc_shifts(params.relocation_count);
68 std::vector<SyncptIncr> syncpt_increments(params.syncpoint_count);
69 std::vector<SyncptIncr> wait_checks(params.syncpoint_count);
70 std::vector<Fence> fences(params.fence_count);
71
72 // Splice input into their respective buffers
73 offset = SpliceVectors(input, command_buffers, params.cmd_buffer_count, offset);
74 offset = SpliceVectors(input, relocs, params.relocation_count, offset);
75 offset = SpliceVectors(input, reloc_shifts, params.relocation_count, offset);
76 offset = SpliceVectors(input, syncpt_increments, params.syncpoint_count, offset);
77 offset = SpliceVectors(input, wait_checks, params.syncpoint_count, offset);
78 offset = SpliceVectors(input, fences, params.fence_count, offset);
79
80 // TODO(ameerj): For async gpu, utilize fences for syncpoint 'max' increment
81
82 auto& gpu = system.GPU();
83
84 for (const auto& cmd_buffer : command_buffers) {
85 auto object = nvmap_dev->GetObject(cmd_buffer.memory_id);
86 ASSERT_OR_EXECUTE(object, return NvErrCodes::InvalidInput;);
87 const auto map = FindBufferMap(object->dma_map_addr);
88 if (!map) {
89 LOG_ERROR(Service_NVDRV, "Tried to submit an invalid offset 0x{:X} dma 0x{:X}",
90 object->addr, object->dma_map_addr);
91 return 0;
92 }
93 Tegra::ChCommandHeaderList cmdlist(cmd_buffer.word_count);
94 gpu.MemoryManager().ReadBlock(map->StartAddr() + cmd_buffer.offset, cmdlist.data(),
95 cmdlist.size() * sizeof(u32));
96 gpu.PushCommandBuffer(cmdlist);
97 }
98
99 std::memcpy(output.data(), &params, sizeof(IoctlSubmit));
100 // Some games expect command_buffers to be written back
101 offset = sizeof(IoctlSubmit);
102 offset = WriteVectors(output, command_buffers, offset);
103 offset = WriteVectors(output, relocs, offset);
104 offset = WriteVectors(output, reloc_shifts, offset);
105 offset = WriteVectors(output, syncpt_increments, offset);
106 offset = WriteVectors(output, wait_checks, offset);
107
108 return NvErrCodes::Success;
109}
110
111u32 nvhost_nvdec_common::GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output) {
112 IoctlGetSyncpoint params{};
113 std::memcpy(&params, input.data(), sizeof(IoctlGetSyncpoint));
114 LOG_DEBUG(Service_NVDRV, "called GetSyncpoint, id={}", params.param);
115
116 // We found that implementing this causes deadlocks with async gpu, along with degraded
117 // performance. TODO: RE the nvdec async implementation
118 params.value = 0;
119 std::memcpy(output.data(), &params, sizeof(IoctlGetSyncpoint));
120
121 return NvErrCodes::Success;
122}
123
124u32 nvhost_nvdec_common::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) {
125 IoctlGetWaitbase params{};
126 std::memcpy(&params, input.data(), sizeof(IoctlGetWaitbase));
127 params.value = 0; // Seems to be hard coded at 0
128 std::memcpy(output.data(), &params, sizeof(IoctlGetWaitbase));
129 return 0;
130}
131
132u32 nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {
133 IoctlMapBuffer params{};
134 std::memcpy(&params, input.data(), sizeof(IoctlMapBuffer));
135 std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries);
136
137 SpliceVectors(input, cmd_buffer_handles, params.num_entries, sizeof(IoctlMapBuffer));
138
139 auto& gpu = system.GPU();
140
141 for (auto& cmf_buff : cmd_buffer_handles) {
142 auto object{nvmap_dev->GetObject(cmf_buff.map_handle)};
143 if (!object) {
144 LOG_ERROR(Service_NVDRV, "invalid cmd_buffer nvmap_handle={:X}", cmf_buff.map_handle);
145 std::memcpy(output.data(), &params, output.size());
146 return NvErrCodes::InvalidInput;
147 }
148 if (object->dma_map_addr == 0) {
149 // NVDEC and VIC memory is in the 32-bit address space
150 // MapAllocate32 will attempt to map a lower 32-bit value in the shared gpu memory space
151 const GPUVAddr low_addr = gpu.MemoryManager().MapAllocate32(object->addr, object->size);
152 object->dma_map_addr = static_cast<u32>(low_addr);
153 // Ensure that the dma_map_addr is indeed in the lower 32-bit address space.
154 ASSERT(object->dma_map_addr == low_addr);
155 }
156 if (!object->dma_map_addr) {
157 LOG_ERROR(Service_NVDRV, "failed to map size={}", object->size);
158 } else {
159 cmf_buff.map_address = object->dma_map_addr;
160 AddBufferMap(object->dma_map_addr, object->size, object->addr,
161 object->status == nvmap::Object::Status::Allocated);
162 }
163 }
164 std::memcpy(output.data(), &params, sizeof(IoctlMapBuffer));
165 std::memcpy(output.data() + sizeof(IoctlMapBuffer), cmd_buffer_handles.data(),
166 cmd_buffer_handles.size() * sizeof(MapBufferEntry));
167
168 return NvErrCodes::Success;
169}
170
171u32 nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {
172 IoctlMapBuffer params{};
173 std::memcpy(&params, input.data(), sizeof(IoctlMapBuffer));
174 std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries);
175 SpliceVectors(input, cmd_buffer_handles, params.num_entries, sizeof(IoctlMapBuffer));
176
177 auto& gpu = system.GPU();
178
179 for (auto& cmf_buff : cmd_buffer_handles) {
180 const auto object{nvmap_dev->GetObject(cmf_buff.map_handle)};
181 if (!object) {
182 LOG_ERROR(Service_NVDRV, "invalid cmd_buffer nvmap_handle={:X}", cmf_buff.map_handle);
183 std::memcpy(output.data(), &params, output.size());
184 return NvErrCodes::InvalidInput;
185 }
186 if (const auto size{RemoveBufferMap(object->dma_map_addr)}; size) {
187 gpu.MemoryManager().Unmap(object->dma_map_addr, *size);
188 } else {
189 // This occurs quite frequently, however does not seem to impact functionality
190 LOG_DEBUG(Service_NVDRV, "invalid offset=0x{:X} dma=0x{:X}", object->addr,
191 object->dma_map_addr);
192 }
193 object->dma_map_addr = 0;
194 }
195 std::memset(output.data(), 0, output.size());
196 return NvErrCodes::Success;
197}
198
199u32 nvhost_nvdec_common::SetSubmitTimeout(const std::vector<u8>& input, std::vector<u8>& output) {
200 std::memcpy(&submit_timeout, input.data(), input.size());
201 LOG_WARNING(Service_NVDRV, "(STUBBED) called");
202 return NvErrCodes::Success;
203}
204
205std::optional<nvhost_nvdec_common::BufferMap> nvhost_nvdec_common::FindBufferMap(
206 GPUVAddr gpu_addr) const {
207 const auto it = std::find_if(
208 buffer_mappings.begin(), buffer_mappings.upper_bound(gpu_addr), [&](const auto& entry) {
209 return (gpu_addr >= entry.second.StartAddr() && gpu_addr < entry.second.EndAddr());
210 });
211
212 ASSERT(it != buffer_mappings.end());
213 return it->second;
214}
215
216void nvhost_nvdec_common::AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr,
217 bool is_allocated) {
218 buffer_mappings.insert_or_assign(gpu_addr, BufferMap{gpu_addr, size, cpu_addr, is_allocated});
219}
220
221std::optional<std::size_t> nvhost_nvdec_common::RemoveBufferMap(GPUVAddr gpu_addr) {
222 const auto iter{buffer_mappings.find(gpu_addr)};
223 if (iter == buffer_mappings.end()) {
224 return std::nullopt;
225 }
226 std::size_t size = 0;
227 if (iter->second.IsAllocated()) {
228 size = iter->second.Size();
229 }
230 buffer_mappings.erase(iter);
231 return size;
232}
233
234} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h
new file mode 100644
index 000000000..c249c5349
--- /dev/null
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h
@@ -0,0 +1,168 @@
1// Copyright 2020 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <map>
8#include <vector>
9#include "common/common_types.h"
10#include "common/swap.h"
11#include "core/hle/service/nvdrv/devices/nvdevice.h"
12
13namespace Service::Nvidia::Devices {
14class nvmap;
15
16class nvhost_nvdec_common : public nvdevice {
17public:
18 explicit nvhost_nvdec_common(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
19 ~nvhost_nvdec_common() override;
20
21 virtual u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
22 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
23 IoctlVersion version) = 0;
24
25protected:
26 class BufferMap final {
27 public:
28 constexpr BufferMap() = default;
29
30 constexpr BufferMap(GPUVAddr start_addr, std::size_t size)
31 : start_addr{start_addr}, end_addr{start_addr + size} {}
32
33 constexpr BufferMap(GPUVAddr start_addr, std::size_t size, VAddr cpu_addr,
34 bool is_allocated)
35 : start_addr{start_addr}, end_addr{start_addr + size}, cpu_addr{cpu_addr},
36 is_allocated{is_allocated} {}
37
38 constexpr VAddr StartAddr() const {
39 return start_addr;
40 }
41
42 constexpr VAddr EndAddr() const {
43 return end_addr;
44 }
45
46 constexpr std::size_t Size() const {
47 return end_addr - start_addr;
48 }
49
50 constexpr VAddr CpuAddr() const {
51 return cpu_addr;
52 }
53
54 constexpr bool IsAllocated() const {
55 return is_allocated;
56 }
57
58 private:
59 GPUVAddr start_addr{};
60 GPUVAddr end_addr{};
61 VAddr cpu_addr{};
62 bool is_allocated{};
63 };
64
65 struct IoctlSetNvmapFD {
66 u32_le nvmap_fd;
67 };
68 static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size");
69
70 struct IoctlSubmitCommandBuffer {
71 u32_le id;
72 u32_le offset;
73 u32_le count;
74 };
75 static_assert(sizeof(IoctlSubmitCommandBuffer) == 0xC,
76 "IoctlSubmitCommandBuffer is incorrect size");
77 struct IoctlSubmit {
78 u32_le cmd_buffer_count;
79 u32_le relocation_count;
80 u32_le syncpoint_count;
81 u32_le fence_count;
82 };
83 static_assert(sizeof(IoctlSubmit) == 0x10, "IoctlSubmit has incorrect size");
84
85 struct CommandBuffer {
86 s32 memory_id;
87 u32 offset;
88 s32 word_count;
89 };
90 static_assert(sizeof(CommandBuffer) == 0xC, "CommandBuffer has incorrect size");
91
92 struct Reloc {
93 s32 cmdbuffer_memory;
94 s32 cmdbuffer_offset;
95 s32 target;
96 s32 target_offset;
97 };
98 static_assert(sizeof(Reloc) == 0x10, "CommandBuffer has incorrect size");
99
100 struct SyncptIncr {
101 u32 id;
102 u32 increments;
103 };
104 static_assert(sizeof(SyncptIncr) == 0x8, "CommandBuffer has incorrect size");
105
106 struct Fence {
107 u32 id;
108 u32 value;
109 };
110 static_assert(sizeof(Fence) == 0x8, "CommandBuffer has incorrect size");
111
112 struct IoctlGetSyncpoint {
113 // Input
114 u32_le param;
115 // Output
116 u32_le value;
117 };
118 static_assert(sizeof(IoctlGetSyncpoint) == 8, "IocGetIdParams has wrong size");
119
120 struct IoctlGetWaitbase {
121 u32_le unknown; // seems to be ignored? Nintendo added this
122 u32_le value;
123 };
124 static_assert(sizeof(IoctlGetWaitbase) == 0x8, "IoctlGetWaitbase is incorrect size");
125
126 struct IoctlMapBuffer {
127 u32_le num_entries;
128 u32_le data_address; // Ignored by the driver.
129 u32_le attach_host_ch_das;
130 };
131 static_assert(sizeof(IoctlMapBuffer) == 0x0C, "IoctlMapBuffer is incorrect size");
132
133 struct IocGetIdParams {
134 // Input
135 u32_le param;
136 // Output
137 u32_le value;
138 };
139 static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size");
140
141 // Used for mapping and unmapping command buffers
142 struct MapBufferEntry {
143 u32_le map_handle;
144 u32_le map_address;
145 };
146 static_assert(sizeof(IoctlMapBuffer) == 0x0C, "IoctlMapBuffer is incorrect size");
147
148 /// Ioctl command implementations
149 u32 SetNVMAPfd(const std::vector<u8>& input);
150 u32 Submit(const std::vector<u8>& input, std::vector<u8>& output);
151 u32 GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output);
152 u32 GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output);
153 u32 MapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
154 u32 UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
155 u32 SetSubmitTimeout(const std::vector<u8>& input, std::vector<u8>& output);
156
157 std::optional<BufferMap> FindBufferMap(GPUVAddr gpu_addr) const;
158 void AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr, bool is_allocated);
159 std::optional<std::size_t> RemoveBufferMap(GPUVAddr gpu_addr);
160
161 u32_le nvmap_fd{};
162 u32_le submit_timeout{};
163 std::shared_ptr<nvmap> nvmap_dev;
164
165 // This is expected to be ordered, therefore we must use a map, not unordered_map
166 std::map<GPUVAddr, BufferMap> buffer_mappings;
167};
168}; // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
index 9da19ad56..60db54d00 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
@@ -2,15 +2,17 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <cstring>
6
7#include "common/assert.h" 5#include "common/assert.h"
8#include "common/logging/log.h" 6#include "common/logging/log.h"
7#include "core/core.h"
9#include "core/hle/service/nvdrv/devices/nvhost_vic.h" 8#include "core/hle/service/nvdrv/devices/nvhost_vic.h"
9#include "video_core/memory_manager.h"
10#include "video_core/renderer_base.h"
10 11
11namespace Service::Nvidia::Devices { 12namespace Service::Nvidia::Devices {
13nvhost_vic::nvhost_vic(Core::System& system, std::shared_ptr<nvmap> nvmap_dev)
14 : nvhost_nvdec_common(system, std::move(nvmap_dev)) {}
12 15
13nvhost_vic::nvhost_vic(Core::System& system) : nvdevice(system) {}
14nvhost_vic::~nvhost_vic() = default; 16nvhost_vic::~nvhost_vic() = default;
15 17
16u32 nvhost_vic::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, 18u32 nvhost_vic::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
@@ -21,7 +23,7 @@ u32 nvhost_vic::ioctl(Ioctl command, const std::vector<u8>& input, const std::ve
21 23
22 switch (static_cast<IoctlCommand>(command.raw)) { 24 switch (static_cast<IoctlCommand>(command.raw)) {
23 case IoctlCommand::IocSetNVMAPfdCommand: 25 case IoctlCommand::IocSetNVMAPfdCommand:
24 return SetNVMAPfd(input, output); 26 return SetNVMAPfd(input);
25 case IoctlCommand::IocSubmit: 27 case IoctlCommand::IocSubmit:
26 return Submit(input, output); 28 return Submit(input, output);
27 case IoctlCommand::IocGetSyncpoint: 29 case IoctlCommand::IocGetSyncpoint:
@@ -29,83 +31,19 @@ u32 nvhost_vic::ioctl(Ioctl command, const std::vector<u8>& input, const std::ve
29 case IoctlCommand::IocGetWaitbase: 31 case IoctlCommand::IocGetWaitbase:
30 return GetWaitbase(input, output); 32 return GetWaitbase(input, output);
31 case IoctlCommand::IocMapBuffer: 33 case IoctlCommand::IocMapBuffer:
32 return MapBuffer(input, output); 34 case IoctlCommand::IocMapBuffer2:
35 case IoctlCommand::IocMapBuffer3:
36 case IoctlCommand::IocMapBuffer4:
33 case IoctlCommand::IocMapBufferEx: 37 case IoctlCommand::IocMapBufferEx:
34 return MapBuffer(input, output); 38 return MapBuffer(input, output);
39 case IoctlCommand::IocUnmapBuffer:
40 case IoctlCommand::IocUnmapBuffer2:
41 case IoctlCommand::IocUnmapBuffer3:
35 case IoctlCommand::IocUnmapBufferEx: 42 case IoctlCommand::IocUnmapBufferEx:
36 return UnmapBufferEx(input, output); 43 return UnmapBuffer(input, output);
37 } 44 }
38 45
39 UNIMPLEMENTED_MSG("Unimplemented ioctl"); 46 UNIMPLEMENTED_MSG("Unimplemented ioctl 0x{:X}", command.raw);
40 return 0;
41}
42
43u32 nvhost_vic::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) {
44 IoctlSetNvmapFD params{};
45 std::memcpy(&params, input.data(), sizeof(IoctlSetNvmapFD));
46 LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
47
48 nvmap_fd = params.nvmap_fd;
49 return 0;
50}
51
52u32 nvhost_vic::Submit(const std::vector<u8>& input, std::vector<u8>& output) {
53 IoctlSubmit params{};
54 std::memcpy(&params, input.data(), sizeof(IoctlSubmit));
55 LOG_WARNING(Service_NVDRV, "(STUBBED) called");
56
57 // Workaround for Luigi's Mansion 3, as nvhost_vic is not implemented for asynch GPU
58 params.command_buffer = {};
59
60 std::memcpy(output.data(), &params, sizeof(IoctlSubmit));
61 return 0;
62}
63
64u32 nvhost_vic::GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output) {
65 IoctlGetSyncpoint params{};
66 std::memcpy(&params, input.data(), sizeof(IoctlGetSyncpoint));
67 LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown);
68 params.value = 0; // Seems to be hard coded at 0
69 std::memcpy(output.data(), &params, sizeof(IoctlGetSyncpoint));
70 return 0;
71}
72
73u32 nvhost_vic::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) {
74 IoctlGetWaitbase params{};
75 std::memcpy(&params, input.data(), sizeof(IoctlGetWaitbase));
76 LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown);
77 params.value = 0; // Seems to be hard coded at 0
78 std::memcpy(output.data(), &params, sizeof(IoctlGetWaitbase));
79 return 0;
80}
81
82u32 nvhost_vic::MapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {
83 IoctlMapBuffer params{};
84 std::memcpy(&params, input.data(), sizeof(IoctlMapBuffer));
85 LOG_WARNING(Service_NVDRV, "(STUBBED) called with address={:08X}{:08X}", params.address_2,
86 params.address_1);
87 params.address_1 = 0;
88 params.address_2 = 0;
89 std::memcpy(output.data(), &params, sizeof(IoctlMapBuffer));
90 return 0;
91}
92
93u32 nvhost_vic::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) {
94 IoctlMapBufferEx params{};
95 std::memcpy(&params, input.data(), sizeof(IoctlMapBufferEx));
96 LOG_WARNING(Service_NVDRV, "(STUBBED) called with address={:08X}{:08X}", params.address_2,
97 params.address_1);
98 params.address_1 = 0;
99 params.address_2 = 0;
100 std::memcpy(output.data(), &params, sizeof(IoctlMapBufferEx));
101 return 0;
102}
103
104u32 nvhost_vic::UnmapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) {
105 IoctlUnmapBufferEx params{};
106 std::memcpy(&params, input.data(), sizeof(IoctlUnmapBufferEx));
107 LOG_WARNING(Service_NVDRV, "(STUBBED) called");
108 std::memcpy(output.data(), &params, sizeof(IoctlUnmapBufferEx));
109 return 0; 47 return 0;
110} 48}
111 49
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.h b/src/core/hle/service/nvdrv/devices/nvhost_vic.h
index a7bb7bbd5..f975b190c 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_vic.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.h
@@ -4,19 +4,15 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <array> 7#include "core/hle/service/nvdrv/devices/nvhost_nvdec_common.h"
8#include <vector>
9#include "common/common_types.h"
10#include "common/swap.h"
11#include "core/hle/service/nvdrv/devices/nvdevice.h"
12 8
13namespace Service::Nvidia::Devices { 9namespace Service::Nvidia::Devices {
10class nvmap;
14 11
15class nvhost_vic final : public nvdevice { 12class nvhost_vic final : public nvhost_nvdec_common {
16public: 13public:
17 explicit nvhost_vic(Core::System& system); 14 explicit nvhost_vic(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
18 ~nvhost_vic() override; 15 ~nvhost_vic();
19
20 u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, 16 u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
21 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, 17 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
22 IoctlVersion version) override; 18 IoctlVersion version) override;
@@ -28,74 +24,14 @@ private:
28 IocGetSyncpoint = 0xC0080002, 24 IocGetSyncpoint = 0xC0080002,
29 IocGetWaitbase = 0xC0080003, 25 IocGetWaitbase = 0xC0080003,
30 IocMapBuffer = 0xC01C0009, 26 IocMapBuffer = 0xC01C0009,
27 IocMapBuffer2 = 0xC0340009,
28 IocMapBuffer3 = 0xC0140009,
29 IocMapBuffer4 = 0xC00C0009,
31 IocMapBufferEx = 0xC03C0009, 30 IocMapBufferEx = 0xC03C0009,
32 IocUnmapBufferEx = 0xC03C000A, 31 IocUnmapBuffer = 0xC03C000A,
33 }; 32 IocUnmapBuffer2 = 0xC034000A,
34 33 IocUnmapBuffer3 = 0xC00C000A,
35 struct IoctlSetNvmapFD { 34 IocUnmapBufferEx = 0xC01C000A,
36 u32_le nvmap_fd;
37 };
38 static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size");
39
40 struct IoctlSubmitCommandBuffer {
41 u32 id;
42 u32 offset;
43 u32 count;
44 };
45 static_assert(sizeof(IoctlSubmitCommandBuffer) == 0xC,
46 "IoctlSubmitCommandBuffer is incorrect size");
47
48 struct IoctlSubmit {
49 u32 command_buffer_count;
50 u32 relocations_count;
51 u32 syncpt_count;
52 u32 wait_count;
53 std::array<IoctlSubmitCommandBuffer, 4> command_buffer;
54 };
55 static_assert(sizeof(IoctlSubmit) == 0x40, "IoctlSubmit is incorrect size");
56
57 struct IoctlGetSyncpoint {
58 u32 unknown; // seems to be ignored? Nintendo added this
59 u32 value;
60 };
61 static_assert(sizeof(IoctlGetSyncpoint) == 0x8, "IoctlGetSyncpoint is incorrect size");
62
63 struct IoctlGetWaitbase {
64 u32 unknown; // seems to be ignored? Nintendo added this
65 u32 value;
66 };
67 static_assert(sizeof(IoctlGetWaitbase) == 0x8, "IoctlGetWaitbase is incorrect size");
68
69 struct IoctlMapBuffer {
70 u32 unknown;
71 u32 address_1;
72 u32 address_2;
73 INSERT_PADDING_BYTES(0x10); // TODO(DarkLordZach): RE this structure
74 };
75 static_assert(sizeof(IoctlMapBuffer) == 0x1C, "IoctlMapBuffer is incorrect size");
76
77 struct IoctlMapBufferEx {
78 u32 unknown;
79 u32 address_1;
80 u32 address_2;
81 INSERT_PADDING_BYTES(0x30); // TODO(DarkLordZach): RE this structure
82 }; 35 };
83 static_assert(sizeof(IoctlMapBufferEx) == 0x3C, "IoctlMapBufferEx is incorrect size");
84
85 struct IoctlUnmapBufferEx {
86 INSERT_PADDING_BYTES(0x3C); // TODO(DarkLordZach): RE this structure
87 };
88 static_assert(sizeof(IoctlUnmapBufferEx) == 0x3C, "IoctlUnmapBufferEx is incorrect size");
89
90 u32_le nvmap_fd{};
91
92 u32 SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output);
93 u32 Submit(const std::vector<u8>& input, std::vector<u8>& output);
94 u32 GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output);
95 u32 GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output);
96 u32 MapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
97 u32 MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output);
98 u32 UnmapBufferEx(const std::vector<u8>& input, std::vector<u8>& output);
99}; 36};
100
101} // namespace Service::Nvidia::Devices 37} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.h b/src/core/hle/service/nvdrv/devices/nvmap.h
index 84624be00..04b9ef540 100644
--- a/src/core/hle/service/nvdrv/devices/nvmap.h
+++ b/src/core/hle/service/nvdrv/devices/nvmap.h
@@ -37,6 +37,7 @@ public:
37 VAddr addr; 37 VAddr addr;
38 Status status; 38 Status status;
39 u32 refcount; 39 u32 refcount;
40 u32 dma_map_addr;
40 }; 41 };
41 42
42 std::shared_ptr<Object> GetObject(u32 handle) const { 43 std::shared_ptr<Object> GetObject(u32 handle) const {
diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp
index 197c77db0..803c1a984 100644
--- a/src/core/hle/service/nvdrv/nvdrv.cpp
+++ b/src/core/hle/service/nvdrv/nvdrv.cpp
@@ -51,9 +51,9 @@ Module::Module(Core::System& system) {
51 devices["/dev/nvmap"] = nvmap_dev; 51 devices["/dev/nvmap"] = nvmap_dev;
52 devices["/dev/nvdisp_disp0"] = std::make_shared<Devices::nvdisp_disp0>(system, nvmap_dev); 52 devices["/dev/nvdisp_disp0"] = std::make_shared<Devices::nvdisp_disp0>(system, nvmap_dev);
53 devices["/dev/nvhost-ctrl"] = std::make_shared<Devices::nvhost_ctrl>(system, events_interface); 53 devices["/dev/nvhost-ctrl"] = std::make_shared<Devices::nvhost_ctrl>(system, events_interface);
54 devices["/dev/nvhost-nvdec"] = std::make_shared<Devices::nvhost_nvdec>(system); 54 devices["/dev/nvhost-nvdec"] = std::make_shared<Devices::nvhost_nvdec>(system, nvmap_dev);
55 devices["/dev/nvhost-nvjpg"] = std::make_shared<Devices::nvhost_nvjpg>(system); 55 devices["/dev/nvhost-nvjpg"] = std::make_shared<Devices::nvhost_nvjpg>(system);
56 devices["/dev/nvhost-vic"] = std::make_shared<Devices::nvhost_vic>(system); 56 devices["/dev/nvhost-vic"] = std::make_shared<Devices::nvhost_vic>(system, nvmap_dev);
57} 57}
58 58
59Module::~Module() = default; 59Module::~Module() = default;
diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp
index e64777668..ffbf90b00 100644
--- a/src/core/hle/service/set/set.cpp
+++ b/src/core/hle/service/set/set.cpp
@@ -202,6 +202,7 @@ SET::SET() : ServiceFramework("set") {
202 {8, &SET::GetQuestFlag, "GetQuestFlag"}, 202 {8, &SET::GetQuestFlag, "GetQuestFlag"},
203 {9, &SET::GetKeyCodeMap2, "GetKeyCodeMap2"}, 203 {9, &SET::GetKeyCodeMap2, "GetKeyCodeMap2"},
204 {10, nullptr, "GetFirmwareVersionForDebug"}, 204 {10, nullptr, "GetFirmwareVersionForDebug"},
205 {11, nullptr, "GetDeviceNickName"},
205 }; 206 };
206 // clang-format on 207 // clang-format on
207 208
diff --git a/src/core/hle/service/set/set_sys.cpp b/src/core/hle/service/set/set_sys.cpp
index 8bd4c7e79..080b5743e 100644
--- a/src/core/hle/service/set/set_sys.cpp
+++ b/src/core/hle/service/set/set_sys.cpp
@@ -300,6 +300,8 @@ SET_SYS::SET_SYS() : ServiceFramework("set:sys") {
300 {198, nullptr, "SetButtonConfigRegisteredSettingsEmbedded"}, 300 {198, nullptr, "SetButtonConfigRegisteredSettingsEmbedded"},
301 {199, nullptr, "GetButtonConfigRegisteredSettings"}, 301 {199, nullptr, "GetButtonConfigRegisteredSettings"},
302 {200, nullptr, "SetButtonConfigRegisteredSettings"}, 302 {200, nullptr, "SetButtonConfigRegisteredSettings"},
303 {201, nullptr, "GetFieldTestingFlag"},
304 {202, nullptr, "SetFieldTestingFlag"},
303 }; 305 };
304 // clang-format on 306 // clang-format on
305 307
diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp
index ee4fa4b48..7d0474e0b 100644
--- a/src/core/hle/service/time/time.cpp
+++ b/src/core/hle/service/time/time.cpp
@@ -10,6 +10,7 @@
10#include "core/hle/ipc_helpers.h" 10#include "core/hle/ipc_helpers.h"
11#include "core/hle/kernel/client_port.h" 11#include "core/hle/kernel/client_port.h"
12#include "core/hle/kernel/client_session.h" 12#include "core/hle/kernel/client_session.h"
13#include "core/hle/kernel/kernel.h"
13#include "core/hle/kernel/scheduler.h" 14#include "core/hle/kernel/scheduler.h"
14#include "core/hle/service/time/interface.h" 15#include "core/hle/service/time/interface.h"
15#include "core/hle/service/time/time.h" 16#include "core/hle/service/time/time.h"
@@ -125,7 +126,7 @@ ResultCode Module::Interface::GetClockSnapshotFromSystemClockContextInternal(
125 Kernel::Thread* thread, Clock::SystemClockContext user_context, 126 Kernel::Thread* thread, Clock::SystemClockContext user_context,
126 Clock::SystemClockContext network_context, u8 type, Clock::ClockSnapshot& clock_snapshot) { 127 Clock::SystemClockContext network_context, u8 type, Clock::ClockSnapshot& clock_snapshot) {
127 128
128 auto& time_manager{module->GetTimeManager()}; 129 auto& time_manager{system.GetTimeManager()};
129 130
130 clock_snapshot.is_automatic_correction_enabled = 131 clock_snapshot.is_automatic_correction_enabled =
131 time_manager.GetStandardUserSystemClockCore().IsAutomaticCorrectionEnabled(); 132 time_manager.GetStandardUserSystemClockCore().IsAutomaticCorrectionEnabled();
@@ -182,7 +183,7 @@ void Module::Interface::GetStandardUserSystemClock(Kernel::HLERequestContext& ct
182 LOG_DEBUG(Service_Time, "called"); 183 LOG_DEBUG(Service_Time, "called");
183 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 184 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
184 rb.Push(RESULT_SUCCESS); 185 rb.Push(RESULT_SUCCESS);
185 rb.PushIpcInterface<ISystemClock>(module->GetTimeManager().GetStandardUserSystemClockCore(), 186 rb.PushIpcInterface<ISystemClock>(system.GetTimeManager().GetStandardUserSystemClockCore(),
186 system); 187 system);
187} 188}
188 189
@@ -190,7 +191,7 @@ void Module::Interface::GetStandardNetworkSystemClock(Kernel::HLERequestContext&
190 LOG_DEBUG(Service_Time, "called"); 191 LOG_DEBUG(Service_Time, "called");
191 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 192 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
192 rb.Push(RESULT_SUCCESS); 193 rb.Push(RESULT_SUCCESS);
193 rb.PushIpcInterface<ISystemClock>(module->GetTimeManager().GetStandardNetworkSystemClockCore(), 194 rb.PushIpcInterface<ISystemClock>(system.GetTimeManager().GetStandardNetworkSystemClockCore(),
194 system); 195 system);
195} 196}
196 197
@@ -198,29 +199,28 @@ void Module::Interface::GetStandardSteadyClock(Kernel::HLERequestContext& ctx) {
198 LOG_DEBUG(Service_Time, "called"); 199 LOG_DEBUG(Service_Time, "called");
199 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 200 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
200 rb.Push(RESULT_SUCCESS); 201 rb.Push(RESULT_SUCCESS);
201 rb.PushIpcInterface<ISteadyClock>(module->GetTimeManager().GetStandardSteadyClockCore(), 202 rb.PushIpcInterface<ISteadyClock>(system.GetTimeManager().GetStandardSteadyClockCore(), system);
202 system);
203} 203}
204 204
205void Module::Interface::GetTimeZoneService(Kernel::HLERequestContext& ctx) { 205void Module::Interface::GetTimeZoneService(Kernel::HLERequestContext& ctx) {
206 LOG_DEBUG(Service_Time, "called"); 206 LOG_DEBUG(Service_Time, "called");
207 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 207 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
208 rb.Push(RESULT_SUCCESS); 208 rb.Push(RESULT_SUCCESS);
209 rb.PushIpcInterface<ITimeZoneService>(module->GetTimeManager().GetTimeZoneContentManager()); 209 rb.PushIpcInterface<ITimeZoneService>(system.GetTimeManager().GetTimeZoneContentManager());
210} 210}
211 211
212void Module::Interface::GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx) { 212void Module::Interface::GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx) {
213 LOG_DEBUG(Service_Time, "called"); 213 LOG_DEBUG(Service_Time, "called");
214 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 214 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
215 rb.Push(RESULT_SUCCESS); 215 rb.Push(RESULT_SUCCESS);
216 rb.PushIpcInterface<ISystemClock>(module->GetTimeManager().GetStandardLocalSystemClockCore(), 216 rb.PushIpcInterface<ISystemClock>(system.GetTimeManager().GetStandardLocalSystemClockCore(),
217 system); 217 system);
218} 218}
219 219
220void Module::Interface::IsStandardNetworkSystemClockAccuracySufficient( 220void Module::Interface::IsStandardNetworkSystemClockAccuracySufficient(
221 Kernel::HLERequestContext& ctx) { 221 Kernel::HLERequestContext& ctx) {
222 LOG_DEBUG(Service_Time, "called"); 222 LOG_DEBUG(Service_Time, "called");
223 auto& clock_core{module->GetTimeManager().GetStandardNetworkSystemClockCore()}; 223 auto& clock_core{system.GetTimeManager().GetStandardNetworkSystemClockCore()};
224 IPC::ResponseBuilder rb{ctx, 3}; 224 IPC::ResponseBuilder rb{ctx, 3};
225 rb.Push(RESULT_SUCCESS); 225 rb.Push(RESULT_SUCCESS);
226 rb.Push<u32>(clock_core.IsStandardNetworkSystemClockAccuracySufficient(system)); 226 rb.Push<u32>(clock_core.IsStandardNetworkSystemClockAccuracySufficient(system));
@@ -229,7 +229,7 @@ void Module::Interface::IsStandardNetworkSystemClockAccuracySufficient(
229void Module::Interface::CalculateMonotonicSystemClockBaseTimePoint(Kernel::HLERequestContext& ctx) { 229void Module::Interface::CalculateMonotonicSystemClockBaseTimePoint(Kernel::HLERequestContext& ctx) {
230 LOG_DEBUG(Service_Time, "called"); 230 LOG_DEBUG(Service_Time, "called");
231 231
232 auto& steady_clock_core{module->GetTimeManager().GetStandardSteadyClockCore()}; 232 auto& steady_clock_core{system.GetTimeManager().GetStandardSteadyClockCore()};
233 if (!steady_clock_core.IsInitialized()) { 233 if (!steady_clock_core.IsInitialized()) {
234 IPC::ResponseBuilder rb{ctx, 2}; 234 IPC::ResponseBuilder rb{ctx, 2};
235 rb.Push(ERROR_UNINITIALIZED_CLOCK); 235 rb.Push(ERROR_UNINITIALIZED_CLOCK);
@@ -262,8 +262,8 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
262 262
263 Clock::SystemClockContext user_context{}; 263 Clock::SystemClockContext user_context{};
264 if (const ResultCode result{ 264 if (const ResultCode result{
265 module->GetTimeManager().GetStandardUserSystemClockCore().GetClockContext( 265 system.GetTimeManager().GetStandardUserSystemClockCore().GetClockContext(system,
266 system, user_context)}; 266 user_context)};
267 result.IsError()) { 267 result.IsError()) {
268 IPC::ResponseBuilder rb{ctx, 2}; 268 IPC::ResponseBuilder rb{ctx, 2};
269 rb.Push(result); 269 rb.Push(result);
@@ -271,7 +271,7 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
271 } 271 }
272 Clock::SystemClockContext network_context{}; 272 Clock::SystemClockContext network_context{};
273 if (const ResultCode result{ 273 if (const ResultCode result{
274 module->GetTimeManager().GetStandardNetworkSystemClockCore().GetClockContext( 274 system.GetTimeManager().GetStandardNetworkSystemClockCore().GetClockContext(
275 system, network_context)}; 275 system, network_context)};
276 result.IsError()) { 276 result.IsError()) {
277 IPC::ResponseBuilder rb{ctx, 2}; 277 IPC::ResponseBuilder rb{ctx, 2};
@@ -372,7 +372,7 @@ void Module::Interface::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& c
372 LOG_DEBUG(Service_Time, "called"); 372 LOG_DEBUG(Service_Time, "called");
373 IPC::ResponseBuilder rb{ctx, 2, 1}; 373 IPC::ResponseBuilder rb{ctx, 2, 1};
374 rb.Push(RESULT_SUCCESS); 374 rb.Push(RESULT_SUCCESS);
375 rb.PushCopyObjects(module->GetTimeManager().GetSharedMemory().GetSharedMemoryHolder()); 375 rb.PushCopyObjects(SharedFrom(&system.Kernel().GetTimeSharedMem()));
376} 376}
377 377
378Module::Interface::Interface(std::shared_ptr<Module> module, Core::System& system, const char* name) 378Module::Interface::Interface(std::shared_ptr<Module> module, Core::System& system, const char* name)
@@ -381,7 +381,7 @@ Module::Interface::Interface(std::shared_ptr<Module> module, Core::System& syste
381Module::Interface::~Interface() = default; 381Module::Interface::~Interface() = default;
382 382
383void InstallInterfaces(Core::System& system) { 383void InstallInterfaces(Core::System& system) {
384 auto module{std::make_shared<Module>(system)}; 384 auto module{std::make_shared<Module>()};
385 std::make_shared<Time>(module, system, "time:a")->InstallAsService(system.ServiceManager()); 385 std::make_shared<Time>(module, system, "time:a")->InstallAsService(system.ServiceManager());
386 std::make_shared<Time>(module, system, "time:s")->InstallAsService(system.ServiceManager()); 386 std::make_shared<Time>(module, system, "time:s")->InstallAsService(system.ServiceManager());
387 std::make_shared<Time>(module, system, "time:u")->InstallAsService(system.ServiceManager()); 387 std::make_shared<Time>(module, system, "time:u")->InstallAsService(system.ServiceManager());
diff --git a/src/core/hle/service/time/time.h b/src/core/hle/service/time/time.h
index 41f3002e9..49f4aac0a 100644
--- a/src/core/hle/service/time/time.h
+++ b/src/core/hle/service/time/time.h
@@ -16,7 +16,7 @@ namespace Service::Time {
16 16
17class Module final { 17class Module final {
18public: 18public:
19 Module(Core::System& system) : time_manager{system} {} 19 Module() = default;
20 20
21 class Interface : public ServiceFramework<Interface> { 21 class Interface : public ServiceFramework<Interface> {
22 public: 22 public:
@@ -46,13 +46,6 @@ public:
46 std::shared_ptr<Module> module; 46 std::shared_ptr<Module> module;
47 Core::System& system; 47 Core::System& system;
48 }; 48 };
49
50 TimeManager& GetTimeManager() {
51 return time_manager;
52 }
53
54private:
55 TimeManager time_manager;
56}; 49};
57 50
58/// Registers all Time services with the specified service manager. 51/// Registers all Time services with the specified service manager.
diff --git a/src/core/hle/service/time/time_manager.cpp b/src/core/hle/service/time/time_manager.cpp
index b4dfe45e5..858623e2b 100644
--- a/src/core/hle/service/time/time_manager.cpp
+++ b/src/core/hle/service/time/time_manager.cpp
@@ -22,125 +22,282 @@ static std::chrono::seconds GetSecondsSinceEpoch() {
22 Settings::values.custom_rtc_differential; 22 Settings::values.custom_rtc_differential;
23} 23}
24 24
25static s64 GetExternalTimeZoneOffset() {
26 // With "auto" timezone setting, we use the external system's timezone offset
27 if (Settings::GetTimeZoneString() == "auto") {
28 return Common::TimeZone::GetCurrentOffsetSeconds().count();
29 }
30 return 0;
31}
32
33static s64 GetExternalRtcValue() { 25static s64 GetExternalRtcValue() {
34 return GetSecondsSinceEpoch().count() + GetExternalTimeZoneOffset(); 26 return GetSecondsSinceEpoch().count() + TimeManager::GetExternalTimeZoneOffset();
35}
36
37TimeManager::TimeManager(Core::System& system)
38 : shared_memory{system}, standard_local_system_clock_core{standard_steady_clock_core},
39 standard_network_system_clock_core{standard_steady_clock_core},
40 standard_user_system_clock_core{standard_local_system_clock_core,
41 standard_network_system_clock_core, system},
42 ephemeral_network_system_clock_core{tick_based_steady_clock_core},
43 local_system_clock_context_writer{
44 std::make_shared<Clock::LocalSystemClockContextWriter>(shared_memory)},
45 network_system_clock_context_writer{
46 std::make_shared<Clock::NetworkSystemClockContextWriter>(shared_memory)},
47 ephemeral_network_system_clock_context_writer{
48 std::make_shared<Clock::EphemeralNetworkSystemClockContextWriter>()},
49 time_zone_content_manager{*this, system} {
50
51 const auto system_time{Clock::TimeSpanType::FromSeconds(GetExternalRtcValue())};
52 SetupStandardSteadyClock(system, Common::UUID::Generate(), system_time, {}, {});
53 SetupStandardLocalSystemClock(system, {}, system_time.ToSeconds());
54 SetupStandardNetworkSystemClock({}, standard_network_clock_accuracy);
55 SetupStandardUserSystemClock(system, {}, Clock::SteadyClockTimePoint::GetRandom());
56 SetupEphemeralNetworkSystemClock();
57} 27}
58 28
59TimeManager::~TimeManager() = default; 29struct TimeManager::Impl final {
30 explicit Impl(Core::System& system)
31 : shared_memory{system}, standard_local_system_clock_core{standard_steady_clock_core},
32 standard_network_system_clock_core{standard_steady_clock_core},
33 standard_user_system_clock_core{standard_local_system_clock_core,
34 standard_network_system_clock_core, system},
35 ephemeral_network_system_clock_core{tick_based_steady_clock_core},
36 local_system_clock_context_writer{
37 std::make_shared<Clock::LocalSystemClockContextWriter>(shared_memory)},
38 network_system_clock_context_writer{
39 std::make_shared<Clock::NetworkSystemClockContextWriter>(shared_memory)},
40 ephemeral_network_system_clock_context_writer{
41 std::make_shared<Clock::EphemeralNetworkSystemClockContextWriter>()},
42 time_zone_content_manager{system} {
60 43
61void TimeManager::SetupTimeZoneManager(std::string location_name, 44 const auto system_time{Clock::TimeSpanType::FromSeconds(GetExternalRtcValue())};
62 Clock::SteadyClockTimePoint time_zone_updated_time_point, 45 SetupStandardSteadyClock(system, Common::UUID::Generate(), system_time, {}, {});
63 std::size_t total_location_name_count, 46 SetupStandardLocalSystemClock(system, {}, system_time.ToSeconds());
64 u128 time_zone_rule_version, 47 SetupStandardNetworkSystemClock({}, standard_network_clock_accuracy);
65 FileSys::VirtualFile& vfs_file) { 48 SetupStandardUserSystemClock(system, {}, Clock::SteadyClockTimePoint::GetRandom());
66 if (time_zone_content_manager.GetTimeZoneManager().SetDeviceLocationNameWithTimeZoneRule( 49 SetupEphemeralNetworkSystemClock();
67 location_name, vfs_file) != RESULT_SUCCESS) { 50 }
68 UNREACHABLE(); 51
69 return; 52 ~Impl() = default;
70 } 53
71 54 Clock::StandardSteadyClockCore& GetStandardSteadyClockCore() {
72 time_zone_content_manager.GetTimeZoneManager().SetUpdatedTime(time_zone_updated_time_point); 55 return standard_steady_clock_core;
73 time_zone_content_manager.GetTimeZoneManager().SetTotalLocationNameCount( 56 }
74 total_location_name_count); 57
75 time_zone_content_manager.GetTimeZoneManager().SetTimeZoneRuleVersion(time_zone_rule_version); 58 const Clock::StandardSteadyClockCore& GetStandardSteadyClockCore() const {
76 time_zone_content_manager.GetTimeZoneManager().MarkAsInitialized(); 59 return standard_steady_clock_core;
77} 60 }
78 61
79void TimeManager::SetupStandardSteadyClock(Core::System& system, Common::UUID clock_source_id, 62 Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore() {
80 Clock::TimeSpanType setup_value, 63 return standard_local_system_clock_core;
81 Clock::TimeSpanType internal_offset, 64 }
82 bool is_rtc_reset_detected) { 65
83 standard_steady_clock_core.SetClockSourceId(clock_source_id); 66 const Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore() const {
84 standard_steady_clock_core.SetSetupValue(setup_value); 67 return standard_local_system_clock_core;
85 standard_steady_clock_core.SetInternalOffset(internal_offset); 68 }
86 standard_steady_clock_core.MarkAsInitialized(); 69
87 70 Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore() {
88 const auto current_time_point{standard_steady_clock_core.GetCurrentRawTimePoint(system)}; 71 return standard_network_system_clock_core;
89 shared_memory.SetupStandardSteadyClock(system, clock_source_id, current_time_point); 72 }
90} 73
91 74 const Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore() const {
92void TimeManager::SetupStandardLocalSystemClock(Core::System& system, 75 return standard_network_system_clock_core;
93 Clock::SystemClockContext clock_context, 76 }
94 s64 posix_time) { 77
95 standard_local_system_clock_core.SetUpdateCallbackInstance(local_system_clock_context_writer); 78 Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore() {
96 79 return standard_user_system_clock_core;
97 const auto current_time_point{ 80 }
98 standard_local_system_clock_core.GetSteadyClockCore().GetCurrentTimePoint(system)}; 81
99 if (current_time_point.clock_source_id == clock_context.steady_time_point.clock_source_id) { 82 const Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore() const {
100 standard_local_system_clock_core.SetSystemClockContext(clock_context); 83 return standard_user_system_clock_core;
101 } else { 84 }
102 if (standard_local_system_clock_core.SetCurrentTime(system, posix_time) != RESULT_SUCCESS) { 85
86 TimeZone::TimeZoneContentManager& GetTimeZoneContentManager() {
87 return time_zone_content_manager;
88 }
89
90 const TimeZone::TimeZoneContentManager& GetTimeZoneContentManager() const {
91 return time_zone_content_manager;
92 }
93
94 SharedMemory& GetSharedMemory() {
95 return shared_memory;
96 }
97
98 const SharedMemory& GetSharedMemory() const {
99 return shared_memory;
100 }
101
102 void SetupTimeZoneManager(std::string location_name,
103 Clock::SteadyClockTimePoint time_zone_updated_time_point,
104 std::size_t total_location_name_count, u128 time_zone_rule_version,
105 FileSys::VirtualFile& vfs_file) {
106 if (time_zone_content_manager.GetTimeZoneManager().SetDeviceLocationNameWithTimeZoneRule(
107 location_name, vfs_file) != RESULT_SUCCESS) {
103 UNREACHABLE(); 108 UNREACHABLE();
104 return; 109 return;
105 } 110 }
111
112 time_zone_content_manager.GetTimeZoneManager().SetUpdatedTime(time_zone_updated_time_point);
113 time_zone_content_manager.GetTimeZoneManager().SetTotalLocationNameCount(
114 total_location_name_count);
115 time_zone_content_manager.GetTimeZoneManager().SetTimeZoneRuleVersion(
116 time_zone_rule_version);
117 time_zone_content_manager.GetTimeZoneManager().MarkAsInitialized();
106 } 118 }
107 119
108 standard_local_system_clock_core.MarkAsInitialized(); 120 static s64 GetExternalTimeZoneOffset() {
109} 121 // With "auto" timezone setting, we use the external system's timezone offset
122 if (Settings::GetTimeZoneString() == "auto") {
123 return Common::TimeZone::GetCurrentOffsetSeconds().count();
124 }
125 return 0;
126 }
110 127
111void TimeManager::SetupStandardNetworkSystemClock(Clock::SystemClockContext clock_context, 128 void SetupStandardSteadyClock(Core::System& system, Common::UUID clock_source_id,
112 Clock::TimeSpanType sufficient_accuracy) { 129 Clock::TimeSpanType setup_value,
113 standard_network_system_clock_core.SetUpdateCallbackInstance( 130 Clock::TimeSpanType internal_offset, bool is_rtc_reset_detected) {
114 network_system_clock_context_writer); 131 standard_steady_clock_core.SetClockSourceId(clock_source_id);
132 standard_steady_clock_core.SetSetupValue(setup_value);
133 standard_steady_clock_core.SetInternalOffset(internal_offset);
134 standard_steady_clock_core.MarkAsInitialized();
115 135
116 if (standard_network_system_clock_core.SetSystemClockContext(clock_context) != RESULT_SUCCESS) { 136 const auto current_time_point{standard_steady_clock_core.GetCurrentRawTimePoint(system)};
117 UNREACHABLE(); 137 shared_memory.SetupStandardSteadyClock(system, clock_source_id, current_time_point);
118 return;
119 } 138 }
120 139
121 standard_network_system_clock_core.SetStandardNetworkClockSufficientAccuracy( 140 void SetupStandardLocalSystemClock(Core::System& system,
122 sufficient_accuracy); 141 Clock::SystemClockContext clock_context, s64 posix_time) {
123 standard_network_system_clock_core.MarkAsInitialized(); 142 standard_local_system_clock_core.SetUpdateCallbackInstance(
124} 143 local_system_clock_context_writer);
144
145 const auto current_time_point{
146 standard_local_system_clock_core.GetSteadyClockCore().GetCurrentTimePoint(system)};
147 if (current_time_point.clock_source_id == clock_context.steady_time_point.clock_source_id) {
148 standard_local_system_clock_core.SetSystemClockContext(clock_context);
149 } else {
150 if (standard_local_system_clock_core.SetCurrentTime(system, posix_time) !=
151 RESULT_SUCCESS) {
152 UNREACHABLE();
153 return;
154 }
155 }
156
157 standard_local_system_clock_core.MarkAsInitialized();
158 }
159
160 void SetupStandardNetworkSystemClock(Clock::SystemClockContext clock_context,
161 Clock::TimeSpanType sufficient_accuracy) {
162 standard_network_system_clock_core.SetUpdateCallbackInstance(
163 network_system_clock_context_writer);
125 164
126void TimeManager::SetupStandardUserSystemClock( 165 if (standard_network_system_clock_core.SetSystemClockContext(clock_context) !=
127 Core::System& system, bool is_automatic_correction_enabled, 166 RESULT_SUCCESS) {
128 Clock::SteadyClockTimePoint steady_clock_time_point) { 167 UNREACHABLE();
129 if (standard_user_system_clock_core.SetAutomaticCorrectionEnabled( 168 return;
130 system, is_automatic_correction_enabled) != RESULT_SUCCESS) { 169 }
131 UNREACHABLE(); 170
132 return; 171 standard_network_system_clock_core.SetStandardNetworkClockSufficientAccuracy(
172 sufficient_accuracy);
173 standard_network_system_clock_core.MarkAsInitialized();
133 } 174 }
134 175
135 standard_user_system_clock_core.SetAutomaticCorrectionUpdatedTime(steady_clock_time_point); 176 void SetupStandardUserSystemClock(Core::System& system, bool is_automatic_correction_enabled,
136 standard_user_system_clock_core.MarkAsInitialized(); 177 Clock::SteadyClockTimePoint steady_clock_time_point) {
137 shared_memory.SetAutomaticCorrectionEnabled(is_automatic_correction_enabled); 178 if (standard_user_system_clock_core.SetAutomaticCorrectionEnabled(
179 system, is_automatic_correction_enabled) != RESULT_SUCCESS) {
180 UNREACHABLE();
181 return;
182 }
183
184 standard_user_system_clock_core.SetAutomaticCorrectionUpdatedTime(steady_clock_time_point);
185 standard_user_system_clock_core.MarkAsInitialized();
186 shared_memory.SetAutomaticCorrectionEnabled(is_automatic_correction_enabled);
187 }
188
189 void SetupEphemeralNetworkSystemClock() {
190 ephemeral_network_system_clock_core.SetUpdateCallbackInstance(
191 ephemeral_network_system_clock_context_writer);
192 ephemeral_network_system_clock_core.MarkAsInitialized();
193 }
194
195 void UpdateLocalSystemClockTime(Core::System& system, s64 posix_time) {
196 const auto timespan{Service::Time::Clock::TimeSpanType::FromSeconds(posix_time)};
197 if (GetStandardLocalSystemClockCore()
198 .SetCurrentTime(system, timespan.ToSeconds())
199 .IsError()) {
200 UNREACHABLE();
201 return;
202 }
203 }
204
205 SharedMemory shared_memory;
206
207 Clock::StandardSteadyClockCore standard_steady_clock_core;
208 Clock::TickBasedSteadyClockCore tick_based_steady_clock_core;
209 Clock::StandardLocalSystemClockCore standard_local_system_clock_core;
210 Clock::StandardNetworkSystemClockCore standard_network_system_clock_core;
211 Clock::StandardUserSystemClockCore standard_user_system_clock_core;
212 Clock::EphemeralNetworkSystemClockCore ephemeral_network_system_clock_core;
213
214 std::shared_ptr<Clock::LocalSystemClockContextWriter> local_system_clock_context_writer;
215 std::shared_ptr<Clock::NetworkSystemClockContextWriter> network_system_clock_context_writer;
216 std::shared_ptr<Clock::EphemeralNetworkSystemClockContextWriter>
217 ephemeral_network_system_clock_context_writer;
218
219 TimeZone::TimeZoneContentManager time_zone_content_manager;
220};
221
222TimeManager::TimeManager(Core::System& system) : system{system} {}
223
224TimeManager::~TimeManager() = default;
225
226void TimeManager::Initialize() {
227 impl = std::make_unique<Impl>(system);
228
229 // Time zones can only be initialized after impl is valid
230 impl->time_zone_content_manager.Initialize(*this);
231}
232
233Clock::StandardSteadyClockCore& TimeManager::GetStandardSteadyClockCore() {
234 return impl->standard_steady_clock_core;
235}
236
237const Clock::StandardSteadyClockCore& TimeManager::GetStandardSteadyClockCore() const {
238 return impl->standard_steady_clock_core;
239}
240
241Clock::StandardLocalSystemClockCore& TimeManager::GetStandardLocalSystemClockCore() {
242 return impl->standard_local_system_clock_core;
243}
244
245const Clock::StandardLocalSystemClockCore& TimeManager::GetStandardLocalSystemClockCore() const {
246 return impl->standard_local_system_clock_core;
247}
248
249Clock::StandardNetworkSystemClockCore& TimeManager::GetStandardNetworkSystemClockCore() {
250 return impl->standard_network_system_clock_core;
138} 251}
139 252
140void TimeManager::SetupEphemeralNetworkSystemClock() { 253const Clock::StandardNetworkSystemClockCore& TimeManager::GetStandardNetworkSystemClockCore()
141 ephemeral_network_system_clock_core.SetUpdateCallbackInstance( 254 const {
142 ephemeral_network_system_clock_context_writer); 255 return impl->standard_network_system_clock_core;
143 ephemeral_network_system_clock_core.MarkAsInitialized(); 256}
257
258Clock::StandardUserSystemClockCore& TimeManager::GetStandardUserSystemClockCore() {
259 return impl->standard_user_system_clock_core;
260}
261
262const Clock::StandardUserSystemClockCore& TimeManager::GetStandardUserSystemClockCore() const {
263 return impl->standard_user_system_clock_core;
264}
265
266TimeZone::TimeZoneContentManager& TimeManager::GetTimeZoneContentManager() {
267 return impl->time_zone_content_manager;
268}
269
270const TimeZone::TimeZoneContentManager& TimeManager::GetTimeZoneContentManager() const {
271 return impl->time_zone_content_manager;
272}
273
274SharedMemory& TimeManager::GetSharedMemory() {
275 return impl->shared_memory;
276}
277
278const SharedMemory& TimeManager::GetSharedMemory() const {
279 return impl->shared_memory;
280}
281
282void TimeManager::UpdateLocalSystemClockTime(s64 posix_time) {
283 impl->UpdateLocalSystemClockTime(system, posix_time);
284}
285
286void TimeManager::SetupTimeZoneManager(std::string location_name,
287 Clock::SteadyClockTimePoint time_zone_updated_time_point,
288 std::size_t total_location_name_count,
289 u128 time_zone_rule_version,
290 FileSys::VirtualFile& vfs_file) {
291 impl->SetupTimeZoneManager(location_name, time_zone_updated_time_point,
292 total_location_name_count, time_zone_rule_version, vfs_file);
293}
294
295/*static*/ s64 TimeManager::GetExternalTimeZoneOffset() {
296 // With "auto" timezone setting, we use the external system's timezone offset
297 if (Settings::GetTimeZoneString() == "auto") {
298 return Common::TimeZone::GetCurrentOffsetSeconds().count();
299 }
300 return 0;
144} 301}
145 302
146} // namespace Service::Time 303} // namespace Service::Time
diff --git a/src/core/hle/service/time/time_manager.h b/src/core/hle/service/time/time_manager.h
index 8e65f0d22..993c7c288 100644
--- a/src/core/hle/service/time/time_manager.h
+++ b/src/core/hle/service/time/time_manager.h
@@ -5,6 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "common/time_zone.h"
8#include "core/file_sys/vfs_types.h" 9#include "core/file_sys/vfs_types.h"
9#include "core/hle/service/time/clock_types.h" 10#include "core/hle/service/time/clock_types.h"
10#include "core/hle/service/time/ephemeral_network_system_clock_core.h" 11#include "core/hle/service/time/ephemeral_network_system_clock_core.h"
@@ -32,86 +33,46 @@ public:
32 explicit TimeManager(Core::System& system); 33 explicit TimeManager(Core::System& system);
33 ~TimeManager(); 34 ~TimeManager();
34 35
35 Clock::StandardSteadyClockCore& GetStandardSteadyClockCore() { 36 void Initialize();
36 return standard_steady_clock_core;
37 }
38 37
39 const Clock::StandardSteadyClockCore& GetStandardSteadyClockCore() const { 38 Clock::StandardSteadyClockCore& GetStandardSteadyClockCore();
40 return standard_steady_clock_core;
41 }
42 39
43 Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore() { 40 const Clock::StandardSteadyClockCore& GetStandardSteadyClockCore() const;
44 return standard_local_system_clock_core;
45 }
46 41
47 const Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore() const { 42 Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore();
48 return standard_local_system_clock_core;
49 }
50 43
51 Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore() { 44 const Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore() const;
52 return standard_network_system_clock_core;
53 }
54 45
55 const Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore() const { 46 Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore();
56 return standard_network_system_clock_core;
57 }
58 47
59 Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore() { 48 const Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore() const;
60 return standard_user_system_clock_core;
61 }
62 49
63 const Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore() const { 50 Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore();
64 return standard_user_system_clock_core;
65 }
66 51
67 TimeZone::TimeZoneContentManager& GetTimeZoneContentManager() { 52 const Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore() const;
68 return time_zone_content_manager;
69 }
70 53
71 const TimeZone::TimeZoneContentManager& GetTimeZoneContentManager() const { 54 TimeZone::TimeZoneContentManager& GetTimeZoneContentManager();
72 return time_zone_content_manager;
73 }
74 55
75 SharedMemory& GetSharedMemory() { 56 const TimeZone::TimeZoneContentManager& GetTimeZoneContentManager() const;
76 return shared_memory;
77 }
78 57
79 const SharedMemory& GetSharedMemory() const { 58 void UpdateLocalSystemClockTime(s64 posix_time);
80 return shared_memory; 59
81 } 60 SharedMemory& GetSharedMemory();
61
62 const SharedMemory& GetSharedMemory() const;
82 63
83 void SetupTimeZoneManager(std::string location_name, 64 void SetupTimeZoneManager(std::string location_name,
84 Clock::SteadyClockTimePoint time_zone_updated_time_point, 65 Clock::SteadyClockTimePoint time_zone_updated_time_point,
85 std::size_t total_location_name_count, u128 time_zone_rule_version, 66 std::size_t total_location_name_count, u128 time_zone_rule_version,
86 FileSys::VirtualFile& vfs_file); 67 FileSys::VirtualFile& vfs_file);
87 68
69 static s64 GetExternalTimeZoneOffset();
70
88private: 71private:
89 void SetupStandardSteadyClock(Core::System& system, Common::UUID clock_source_id, 72 Core::System& system;
90 Clock::TimeSpanType setup_value, 73
91 Clock::TimeSpanType internal_offset, bool is_rtc_reset_detected); 74 struct Impl;
92 void SetupStandardLocalSystemClock(Core::System& system, 75 std::unique_ptr<Impl> impl;
93 Clock::SystemClockContext clock_context, s64 posix_time);
94 void SetupStandardNetworkSystemClock(Clock::SystemClockContext clock_context,
95 Clock::TimeSpanType sufficient_accuracy);
96 void SetupStandardUserSystemClock(Core::System& system, bool is_automatic_correction_enabled,
97 Clock::SteadyClockTimePoint steady_clock_time_point);
98 void SetupEphemeralNetworkSystemClock();
99
100 SharedMemory shared_memory;
101
102 Clock::StandardSteadyClockCore standard_steady_clock_core;
103 Clock::TickBasedSteadyClockCore tick_based_steady_clock_core;
104 Clock::StandardLocalSystemClockCore standard_local_system_clock_core;
105 Clock::StandardNetworkSystemClockCore standard_network_system_clock_core;
106 Clock::StandardUserSystemClockCore standard_user_system_clock_core;
107 Clock::EphemeralNetworkSystemClockCore ephemeral_network_system_clock_core;
108
109 std::shared_ptr<Clock::LocalSystemClockContextWriter> local_system_clock_context_writer;
110 std::shared_ptr<Clock::NetworkSystemClockContextWriter> network_system_clock_context_writer;
111 std::shared_ptr<Clock::EphemeralNetworkSystemClockContextWriter>
112 ephemeral_network_system_clock_context_writer;
113
114 TimeZone::TimeZoneContentManager time_zone_content_manager;
115}; 76};
116 77
117} // namespace Service::Time 78} // namespace Service::Time
diff --git a/src/core/hle/service/time/time_zone_content_manager.cpp b/src/core/hle/service/time/time_zone_content_manager.cpp
index 320672add..4177d0a41 100644
--- a/src/core/hle/service/time/time_zone_content_manager.cpp
+++ b/src/core/hle/service/time/time_zone_content_manager.cpp
@@ -68,9 +68,10 @@ static std::vector<std::string> BuildLocationNameCache(Core::System& system) {
68 return location_name_cache; 68 return location_name_cache;
69} 69}
70 70
71TimeZoneContentManager::TimeZoneContentManager(TimeManager& time_manager, Core::System& system) 71TimeZoneContentManager::TimeZoneContentManager(Core::System& system)
72 : system{system}, location_name_cache{BuildLocationNameCache(system)} { 72 : system{system}, location_name_cache{BuildLocationNameCache(system)} {}
73 73
74void TimeZoneContentManager::Initialize(TimeManager& time_manager) {
74 std::string location_name; 75 std::string location_name;
75 const auto timezone_setting = Settings::GetTimeZoneString(); 76 const auto timezone_setting = Settings::GetTimeZoneString();
76 if (timezone_setting == "auto" || timezone_setting == "default") { 77 if (timezone_setting == "auto" || timezone_setting == "default") {
diff --git a/src/core/hle/service/time/time_zone_content_manager.h b/src/core/hle/service/time/time_zone_content_manager.h
index 4f302c3b9..52dd1a020 100644
--- a/src/core/hle/service/time/time_zone_content_manager.h
+++ b/src/core/hle/service/time/time_zone_content_manager.h
@@ -21,7 +21,9 @@ namespace Service::Time::TimeZone {
21 21
22class TimeZoneContentManager final { 22class TimeZoneContentManager final {
23public: 23public:
24 TimeZoneContentManager(TimeManager& time_manager, Core::System& system); 24 explicit TimeZoneContentManager(Core::System& system);
25
26 void Initialize(TimeManager& time_manager);
25 27
26 TimeZoneManager& GetTimeZoneManager() { 28 TimeZoneManager& GetTimeZoneManager() {
27 return time_zone_manager; 29 return time_zone_manager;
diff --git a/src/core/settings.cpp b/src/core/settings.cpp
index 28d3f9099..e14c02045 100644
--- a/src/core/settings.cpp
+++ b/src/core/settings.cpp
@@ -63,6 +63,7 @@ void LogSettings() {
63 log_setting("Renderer_GPUAccuracyLevel", values.gpu_accuracy.GetValue()); 63 log_setting("Renderer_GPUAccuracyLevel", values.gpu_accuracy.GetValue());
64 log_setting("Renderer_UseAsynchronousGpuEmulation", 64 log_setting("Renderer_UseAsynchronousGpuEmulation",
65 values.use_asynchronous_gpu_emulation.GetValue()); 65 values.use_asynchronous_gpu_emulation.GetValue());
66 log_setting("Renderer_UseNvdecEmulation", values.use_nvdec_emulation.GetValue());
66 log_setting("Renderer_UseVsync", values.use_vsync.GetValue()); 67 log_setting("Renderer_UseVsync", values.use_vsync.GetValue());
67 log_setting("Renderer_UseAssemblyShaders", values.use_assembly_shaders.GetValue()); 68 log_setting("Renderer_UseAssemblyShaders", values.use_assembly_shaders.GetValue());
68 log_setting("Renderer_UseAsynchronousShaders", values.use_asynchronous_shaders.GetValue()); 69 log_setting("Renderer_UseAsynchronousShaders", values.use_asynchronous_shaders.GetValue());
@@ -119,6 +120,7 @@ void RestoreGlobalState() {
119 values.use_disk_shader_cache.SetGlobal(true); 120 values.use_disk_shader_cache.SetGlobal(true);
120 values.gpu_accuracy.SetGlobal(true); 121 values.gpu_accuracy.SetGlobal(true);
121 values.use_asynchronous_gpu_emulation.SetGlobal(true); 122 values.use_asynchronous_gpu_emulation.SetGlobal(true);
123 values.use_nvdec_emulation.SetGlobal(true);
122 values.use_vsync.SetGlobal(true); 124 values.use_vsync.SetGlobal(true);
123 values.use_assembly_shaders.SetGlobal(true); 125 values.use_assembly_shaders.SetGlobal(true);
124 values.use_asynchronous_shaders.SetGlobal(true); 126 values.use_asynchronous_shaders.SetGlobal(true);
diff --git a/src/core/settings.h b/src/core/settings.h
index 9834f44bb..604805615 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -111,6 +111,7 @@ struct Values {
111 Setting<bool> use_disk_shader_cache; 111 Setting<bool> use_disk_shader_cache;
112 Setting<GPUAccuracy> gpu_accuracy; 112 Setting<GPUAccuracy> gpu_accuracy;
113 Setting<bool> use_asynchronous_gpu_emulation; 113 Setting<bool> use_asynchronous_gpu_emulation;
114 Setting<bool> use_nvdec_emulation;
114 Setting<bool> use_vsync; 115 Setting<bool> use_vsync;
115 Setting<bool> use_assembly_shaders; 116 Setting<bool> use_assembly_shaders;
116 Setting<bool> use_asynchronous_shaders; 117 Setting<bool> use_asynchronous_shaders;
diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp
index da09c0dbc..ebc19e18a 100644
--- a/src/core/telemetry_session.cpp
+++ b/src/core/telemetry_session.cpp
@@ -206,6 +206,8 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader) {
206 TranslateGPUAccuracyLevel(Settings::values.gpu_accuracy.GetValue())); 206 TranslateGPUAccuracyLevel(Settings::values.gpu_accuracy.GetValue()));
207 AddField(field_type, "Renderer_UseAsynchronousGpuEmulation", 207 AddField(field_type, "Renderer_UseAsynchronousGpuEmulation",
208 Settings::values.use_asynchronous_gpu_emulation.GetValue()); 208 Settings::values.use_asynchronous_gpu_emulation.GetValue());
209 AddField(field_type, "Renderer_UseNvdecEmulation",
210 Settings::values.use_nvdec_emulation.GetValue());
209 AddField(field_type, "Renderer_UseVsync", Settings::values.use_vsync.GetValue()); 211 AddField(field_type, "Renderer_UseVsync", Settings::values.use_vsync.GetValue());
210 AddField(field_type, "Renderer_UseAssemblyShaders", 212 AddField(field_type, "Renderer_UseAssemblyShaders",
211 Settings::values.use_assembly_shaders.GetValue()); 213 Settings::values.use_assembly_shaders.GetValue());