summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt4
-rw-r--r--externals/CMakeLists.txt5
-rw-r--r--src/common/CMakeLists.txt1
-rw-r--r--src/common/range_mutex.h93
-rw-r--r--src/common/settings.h12
-rw-r--r--src/core/device_memory_manager.h18
-rw-r--r--src/core/device_memory_manager.inc63
-rw-r--r--src/core/hle/service/aoc/aoc_u.cpp2
-rw-r--r--src/core/hle/service/cmif_serialization.h56
-rw-r--r--src/core/hle/service/glue/time/time_zone.cpp27
-rw-r--r--src/core/hle/service/glue/time/time_zone.h6
-rw-r--r--src/core/hle/service/hid/hid_server.cpp45
-rw-r--r--src/core/hle/service/hid/hid_server.h5
-rw-r--r--src/core/hle/service/nvdrv/core/container.cpp4
-rw-r--r--src/core/hle/service/psc/time/common.h24
-rw-r--r--src/core/hle/service/psc/time/service_manager.cpp14
-rw-r--r--src/core/hle/service/psc/time/time_zone.cpp41
-rw-r--r--src/core/hle/service/psc/time/time_zone.h12
-rw-r--r--src/core/hle/service/psc/time/time_zone_service.cpp20
-rw-r--r--src/core/hle/service/psc/time/time_zone_service.h4
-rw-r--r--src/core/hle/service/set/system_settings_server.cpp2
-rw-r--r--src/core/hle/service/sockets/sockets.h1
-rw-r--r--src/core/hle/service/sockets/sockets_translate.cpp2
-rw-r--r--src/core/internal_network/network.cpp32
-rw-r--r--src/core/internal_network/sockets.h3
-rw-r--r--src/hid_core/hid_types.h5
-rw-r--r--src/hid_core/resources/npad/npad.cpp11
-rw-r--r--src/hid_core/resources/npad/npad.h2
-rw-r--r--src/video_core/texture_cache/texture_cache.h87
-rw-r--r--src/video_core/texture_cache/texture_cache_base.h4
-rw-r--r--src/yuzu/configuration/configure_audio.cpp117
-rw-r--r--src/yuzu/configuration/configure_audio.h7
32 files changed, 480 insertions, 249 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index eb26fbfd8..f4b64544f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -322,6 +322,10 @@ if (ARCHITECTURE_x86 OR ARCHITECTURE_x86_64)
322 find_package(xbyak 6 CONFIG) 322 find_package(xbyak 6 CONFIG)
323endif() 323endif()
324 324
325if (ARCHITECTURE_arm64)
326 find_package(oaknut 2.0.1 CONFIG)
327endif()
328
325if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64) 329if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
326 find_package(dynarmic 6.4.0 CONFIG) 330 find_package(dynarmic 6.4.0 CONFIG)
327endif() 331endif()
diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt
index 42355716c..d49a2e43e 100644
--- a/externals/CMakeLists.txt
+++ b/externals/CMakeLists.txt
@@ -14,16 +14,17 @@ set(BUILD_SHARED_LIBS OFF)
14# Skip install rules for all externals 14# Skip install rules for all externals
15set_directory_properties(PROPERTIES EXCLUDE_FROM_ALL ON) 15set_directory_properties(PROPERTIES EXCLUDE_FROM_ALL ON)
16 16
17# xbyak 17# Xbyak (also used by Dynarmic, so needs to be added first)
18if ((ARCHITECTURE_x86 OR ARCHITECTURE_x86_64) AND NOT TARGET xbyak::xbyak) 18if ((ARCHITECTURE_x86 OR ARCHITECTURE_x86_64) AND NOT TARGET xbyak::xbyak)
19 add_subdirectory(xbyak) 19 add_subdirectory(xbyak)
20endif() 20endif()
21 21
22# Dynarmic 22# Oaknut (also used by Dynarmic, so needs to be added first)
23if (ARCHITECTURE_arm64 AND NOT TARGET merry::oaknut) 23if (ARCHITECTURE_arm64 AND NOT TARGET merry::oaknut)
24 add_subdirectory(oaknut) 24 add_subdirectory(oaknut)
25endif() 25endif()
26 26
27# Dynarmic
27if ((ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64) AND NOT TARGET dynarmic::dynarmic) 28if ((ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64) AND NOT TARGET dynarmic::dynarmic)
28 set(DYNARMIC_IGNORE_ASSERTS ON) 29 set(DYNARMIC_IGNORE_ASSERTS ON)
29 add_subdirectory(dynarmic) 30 add_subdirectory(dynarmic)
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index e30fea268..85926fc8f 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -106,6 +106,7 @@ add_library(common STATIC
106 precompiled_headers.h 106 precompiled_headers.h
107 quaternion.h 107 quaternion.h
108 range_map.h 108 range_map.h
109 range_mutex.h
109 reader_writer_queue.h 110 reader_writer_queue.h
110 ring_buffer.h 111 ring_buffer.h
111 ${CMAKE_CURRENT_BINARY_DIR}/scm_rev.cpp 112 ${CMAKE_CURRENT_BINARY_DIR}/scm_rev.cpp
diff --git a/src/common/range_mutex.h b/src/common/range_mutex.h
new file mode 100644
index 000000000..d6c949811
--- /dev/null
+++ b/src/common/range_mutex.h
@@ -0,0 +1,93 @@
1// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <condition_variable>
7#include <mutex>
8
9#include "common/intrusive_list.h"
10
11namespace Common {
12
13class ScopedRangeLock;
14
15class RangeMutex {
16public:
17 explicit RangeMutex() = default;
18 ~RangeMutex() = default;
19
20private:
21 friend class ScopedRangeLock;
22
23 void Lock(ScopedRangeLock& l);
24 void Unlock(ScopedRangeLock& l);
25 bool HasIntersectionLocked(ScopedRangeLock& l);
26
27private:
28 std::mutex m_mutex;
29 std::condition_variable m_cv;
30
31 using LockList = Common::IntrusiveListBaseTraits<ScopedRangeLock>::ListType;
32 LockList m_list;
33};
34
35class ScopedRangeLock : public Common::IntrusiveListBaseNode<ScopedRangeLock> {
36public:
37 explicit ScopedRangeLock(RangeMutex& mutex, u64 address, u64 size)
38 : m_mutex(mutex), m_address(address), m_size(size) {
39 if (m_size > 0) {
40 m_mutex.Lock(*this);
41 }
42 }
43 ~ScopedRangeLock() {
44 if (m_size > 0) {
45 m_mutex.Unlock(*this);
46 }
47 }
48
49 u64 GetAddress() const {
50 return m_address;
51 }
52
53 u64 GetSize() const {
54 return m_size;
55 }
56
57private:
58 RangeMutex& m_mutex;
59 const u64 m_address{};
60 const u64 m_size{};
61};
62
63inline void RangeMutex::Lock(ScopedRangeLock& l) {
64 std::unique_lock lk{m_mutex};
65 m_cv.wait(lk, [&] { return !HasIntersectionLocked(l); });
66 m_list.push_back(l);
67}
68
69inline void RangeMutex::Unlock(ScopedRangeLock& l) {
70 {
71 std::scoped_lock lk{m_mutex};
72 m_list.erase(m_list.iterator_to(l));
73 }
74 m_cv.notify_all();
75}
76
77inline bool RangeMutex::HasIntersectionLocked(ScopedRangeLock& l) {
78 const auto cur_begin = l.GetAddress();
79 const auto cur_last = l.GetAddress() + l.GetSize() - 1;
80
81 for (const auto& other : m_list) {
82 const auto other_begin = other.GetAddress();
83 const auto other_last = other.GetAddress() + other.GetSize() - 1;
84
85 if (cur_begin <= other_last && other_begin <= cur_last) {
86 return true;
87 }
88 }
89
90 return false;
91}
92
93} // namespace Common
diff --git a/src/common/settings.h b/src/common/settings.h
index 16749ab68..f1b1add56 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -134,12 +134,12 @@ struct Values {
134 Linkage linkage{}; 134 Linkage linkage{};
135 135
136 // Audio 136 // Audio
137 Setting<AudioEngine> sink_id{linkage, AudioEngine::Auto, "output_engine", Category::Audio, 137 SwitchableSetting<AudioEngine> sink_id{linkage, AudioEngine::Auto, "output_engine",
138 Specialization::RuntimeList}; 138 Category::Audio, Specialization::RuntimeList};
139 Setting<std::string> audio_output_device_id{linkage, "auto", "output_device", Category::Audio, 139 SwitchableSetting<std::string> audio_output_device_id{
140 Specialization::RuntimeList}; 140 linkage, "auto", "output_device", Category::Audio, Specialization::RuntimeList};
141 Setting<std::string> audio_input_device_id{linkage, "auto", "input_device", Category::Audio, 141 SwitchableSetting<std::string> audio_input_device_id{
142 Specialization::RuntimeList}; 142 linkage, "auto", "input_device", Category::Audio, Specialization::RuntimeList};
143 SwitchableSetting<AudioMode, true> sound_index{ 143 SwitchableSetting<AudioMode, true> sound_index{
144 linkage, AudioMode::Stereo, AudioMode::Mono, AudioMode::Surround, 144 linkage, AudioMode::Stereo, AudioMode::Mono, AudioMode::Surround,
145 "sound_index", Category::SystemAudio, Specialization::Default, true, 145 "sound_index", Category::SystemAudio, Specialization::Default, true,
diff --git a/src/core/device_memory_manager.h b/src/core/device_memory_manager.h
index ffeed46cc..0568a821b 100644
--- a/src/core/device_memory_manager.h
+++ b/src/core/device_memory_manager.h
@@ -5,11 +5,13 @@
5 5
6#include <array> 6#include <array>
7#include <atomic> 7#include <atomic>
8#include <bit>
8#include <deque> 9#include <deque>
9#include <memory> 10#include <memory>
10#include <mutex> 11#include <mutex>
11 12
12#include "common/common_types.h" 13#include "common/common_types.h"
14#include "common/range_mutex.h"
13#include "common/scratch_buffer.h" 15#include "common/scratch_buffer.h"
14#include "common/virtual_buffer.h" 16#include "common/virtual_buffer.h"
15 17
@@ -180,31 +182,35 @@ private:
180 } 182 }
181 183
182 Common::VirtualBuffer<VAddr> cpu_backing_address; 184 Common::VirtualBuffer<VAddr> cpu_backing_address;
183 static constexpr size_t subentries = 8 / sizeof(u8); 185 using CounterType = u8;
186 using CounterAtomicType = std::atomic_uint8_t;
187 static constexpr size_t subentries = 8 / sizeof(CounterType);
184 static constexpr size_t subentries_mask = subentries - 1; 188 static constexpr size_t subentries_mask = subentries - 1;
189 static constexpr size_t subentries_shift =
190 std::countr_zero(sizeof(u64)) - std::countr_zero(sizeof(CounterType));
185 class CounterEntry final { 191 class CounterEntry final {
186 public: 192 public:
187 CounterEntry() = default; 193 CounterEntry() = default;
188 194
189 std::atomic_uint8_t& Count(std::size_t page) { 195 CounterAtomicType& Count(std::size_t page) {
190 return values[page & subentries_mask]; 196 return values[page & subentries_mask];
191 } 197 }
192 198
193 const std::atomic_uint8_t& Count(std::size_t page) const { 199 const CounterAtomicType& Count(std::size_t page) const {
194 return values[page & subentries_mask]; 200 return values[page & subentries_mask];
195 } 201 }
196 202
197 private: 203 private:
198 std::array<std::atomic_uint8_t, subentries> values{}; 204 std::array<CounterAtomicType, subentries> values{};
199 }; 205 };
200 static_assert(sizeof(CounterEntry) == subentries * sizeof(u8), 206 static_assert(sizeof(CounterEntry) == subentries * sizeof(CounterType),
201 "CounterEntry should be 8 bytes!"); 207 "CounterEntry should be 8 bytes!");
202 208
203 static constexpr size_t num_counter_entries = 209 static constexpr size_t num_counter_entries =
204 (1ULL << (device_virtual_bits - page_bits)) / subentries; 210 (1ULL << (device_virtual_bits - page_bits)) / subentries;
205 using CachedPages = std::array<CounterEntry, num_counter_entries>; 211 using CachedPages = std::array<CounterEntry, num_counter_entries>;
206 std::unique_ptr<CachedPages> cached_pages; 212 std::unique_ptr<CachedPages> cached_pages;
207 std::mutex counter_guard; 213 Common::RangeMutex counter_guard;
208 std::mutex mapping_guard; 214 std::mutex mapping_guard;
209}; 215};
210 216
diff --git a/src/core/device_memory_manager.inc b/src/core/device_memory_manager.inc
index eab8a2731..b026f4220 100644
--- a/src/core/device_memory_manager.inc
+++ b/src/core/device_memory_manager.inc
@@ -213,8 +213,8 @@ void DeviceMemoryManager<Traits>::Free(DAddr start, size_t size) {
213} 213}
214 214
215template <typename Traits> 215template <typename Traits>
216void DeviceMemoryManager<Traits>::Map(DAddr address, VAddr virtual_address, size_t size, 216void DeviceMemoryManager<Traits>::Map(DAddr address, VAddr virtual_address, size_t size, Asid asid,
217 Asid asid, bool track) { 217 bool track) {
218 Core::Memory::Memory* process_memory = registered_processes[asid.id]; 218 Core::Memory::Memory* process_memory = registered_processes[asid.id];
219 size_t start_page_d = address >> Memory::YUZU_PAGEBITS; 219 size_t start_page_d = address >> Memory::YUZU_PAGEBITS;
220 size_t num_pages = Common::AlignUp(size, Memory::YUZU_PAGESIZE) >> Memory::YUZU_PAGEBITS; 220 size_t num_pages = Common::AlignUp(size, Memory::YUZU_PAGESIZE) >> Memory::YUZU_PAGEBITS;
@@ -508,12 +508,7 @@ void DeviceMemoryManager<Traits>::UnregisterProcess(Asid asid) {
508 508
509template <typename Traits> 509template <typename Traits>
510void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size, s32 delta) { 510void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size, s32 delta) {
511 std::unique_lock<std::mutex> lk(counter_guard, std::defer_lock); 511 Common::ScopedRangeLock lk(counter_guard, addr, size);
512 const auto Lock = [&] {
513 if (!lk) {
514 lk.lock();
515 }
516 };
517 u64 uncache_begin = 0; 512 u64 uncache_begin = 0;
518 u64 cache_begin = 0; 513 u64 cache_begin = 0;
519 u64 uncache_bytes = 0; 514 u64 uncache_bytes = 0;
@@ -524,22 +519,36 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size
524 const size_t page_end = Common::DivCeil(addr + size, Memory::YUZU_PAGESIZE); 519 const size_t page_end = Common::DivCeil(addr + size, Memory::YUZU_PAGESIZE);
525 size_t page = addr >> Memory::YUZU_PAGEBITS; 520 size_t page = addr >> Memory::YUZU_PAGEBITS;
526 auto [asid, base_vaddress] = ExtractCPUBacking(page); 521 auto [asid, base_vaddress] = ExtractCPUBacking(page);
527 size_t vpage = base_vaddress >> Memory::YUZU_PAGEBITS;
528 auto* memory_device_inter = registered_processes[asid.id]; 522 auto* memory_device_inter = registered_processes[asid.id];
523 const auto release_pending = [&] {
524 if (uncache_bytes > 0) {
525 MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS,
526 uncache_bytes, false);
527 uncache_bytes = 0;
528 }
529 if (cache_bytes > 0) {
530 MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS,
531 cache_bytes, true);
532 cache_bytes = 0;
533 }
534 };
529 for (; page != page_end; ++page) { 535 for (; page != page_end; ++page) {
530 std::atomic_uint8_t& count = cached_pages->at(page >> 3).Count(page); 536 CounterAtomicType& count = cached_pages->at(page >> subentries_shift).Count(page);
537 auto [asid_2, vpage] = ExtractCPUBacking(page);
538 vpage >>= Memory::YUZU_PAGEBITS;
531 539
532 if (delta > 0) { 540 if (vpage == 0) [[unlikely]] {
533 ASSERT_MSG(count.load(std::memory_order::relaxed) < std::numeric_limits<u8>::max(), 541 release_pending();
534 "Count may overflow!"); 542 continue;
535 } else if (delta < 0) { 543 }
536 ASSERT_MSG(count.load(std::memory_order::relaxed) > 0, "Count may underflow!"); 544
537 } else { 545 if (asid.id != asid_2.id) [[unlikely]] {
538 ASSERT_MSG(false, "Delta must be non-zero!"); 546 release_pending();
547 memory_device_inter = registered_processes[asid_2.id];
539 } 548 }
540 549
541 // Adds or subtracts 1, as count is a unsigned 8-bit value 550 // Adds or subtracts 1, as count is a unsigned 8-bit value
542 count.fetch_add(static_cast<u8>(delta), std::memory_order_release); 551 count.fetch_add(static_cast<CounterType>(delta), std::memory_order_release);
543 552
544 // Assume delta is either -1 or 1 553 // Assume delta is either -1 or 1
545 if (count.load(std::memory_order::relaxed) == 0) { 554 if (count.load(std::memory_order::relaxed) == 0) {
@@ -548,7 +557,6 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size
548 } 557 }
549 uncache_bytes += Memory::YUZU_PAGESIZE; 558 uncache_bytes += Memory::YUZU_PAGESIZE;
550 } else if (uncache_bytes > 0) { 559 } else if (uncache_bytes > 0) {
551 Lock();
552 MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS, 560 MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS,
553 uncache_bytes, false); 561 uncache_bytes, false);
554 uncache_bytes = 0; 562 uncache_bytes = 0;
@@ -559,23 +567,12 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size
559 } 567 }
560 cache_bytes += Memory::YUZU_PAGESIZE; 568 cache_bytes += Memory::YUZU_PAGESIZE;
561 } else if (cache_bytes > 0) { 569 } else if (cache_bytes > 0) {
562 Lock(); 570 MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS,
563 MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes, 571 cache_bytes, true);
564 true);
565 cache_bytes = 0; 572 cache_bytes = 0;
566 } 573 }
567 vpage++;
568 }
569 if (uncache_bytes > 0) {
570 Lock();
571 MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS, uncache_bytes,
572 false);
573 }
574 if (cache_bytes > 0) {
575 Lock();
576 MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS, cache_bytes,
577 true);
578 } 574 }
575 release_pending();
579} 576}
580 577
581} // namespace Core 578} // namespace Core
diff --git a/src/core/hle/service/aoc/aoc_u.cpp b/src/core/hle/service/aoc/aoc_u.cpp
index 7075ab800..486719cc0 100644
--- a/src/core/hle/service/aoc/aoc_u.cpp
+++ b/src/core/hle/service/aoc/aoc_u.cpp
@@ -202,7 +202,7 @@ void AOC_U::ListAddOnContent(HLERequestContext& ctx) {
202 LOG_DEBUG(Service_AOC, "called with offset={}, count={}, process_id={}", offset, count, 202 LOG_DEBUG(Service_AOC, "called with offset={}, count={}, process_id={}", offset, count,
203 process_id); 203 process_id);
204 204
205 const auto current = system.GetApplicationProcessProgramID(); 205 const auto current = FileSys::GetBaseTitleID(system.GetApplicationProcessProgramID());
206 206
207 std::vector<u32> out; 207 std::vector<u32> out;
208 const auto& disabled = Settings::values.disabled_addons[current]; 208 const auto& disabled = Settings::values.disabled_addons[current];
diff --git a/src/core/hle/service/cmif_serialization.h b/src/core/hle/service/cmif_serialization.h
index 9ee26400d..315475e71 100644
--- a/src/core/hle/service/cmif_serialization.h
+++ b/src/core/hle/service/cmif_serialization.h
@@ -122,14 +122,14 @@ struct RequestLayout {
122 u32 domain_interface_count; 122 u32 domain_interface_count;
123}; 123};
124 124
125template <ArgumentType Type1, ArgumentType Type2, typename MethodArguments, size_t PrevAlign = 1, size_t DataOffset = 0, size_t ArgIndex = 0> 125template <typename MethodArguments, size_t PrevAlign = 1, size_t DataOffset = 0, size_t ArgIndex = 0>
126constexpr u32 GetArgumentRawDataSize() { 126constexpr u32 GetInRawDataSize() {
127 if constexpr (ArgIndex >= std::tuple_size_v<MethodArguments>) { 127 if constexpr (ArgIndex >= std::tuple_size_v<MethodArguments>) {
128 return static_cast<u32>(DataOffset); 128 return static_cast<u32>(DataOffset);
129 } else { 129 } else {
130 using ArgType = std::tuple_element_t<ArgIndex, MethodArguments>; 130 using ArgType = std::tuple_element_t<ArgIndex, MethodArguments>;
131 131
132 if constexpr (ArgumentTraits<ArgType>::Type == Type1 || ArgumentTraits<ArgType>::Type == Type2) { 132 if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::InData || ArgumentTraits<ArgType>::Type == ArgumentType::InProcessId) {
133 constexpr size_t ArgAlign = alignof(ArgType); 133 constexpr size_t ArgAlign = alignof(ArgType);
134 constexpr size_t ArgSize = sizeof(ArgType); 134 constexpr size_t ArgSize = sizeof(ArgType);
135 135
@@ -138,9 +138,33 @@ constexpr u32 GetArgumentRawDataSize() {
138 constexpr size_t ArgOffset = Common::AlignUp(DataOffset, ArgAlign); 138 constexpr size_t ArgOffset = Common::AlignUp(DataOffset, ArgAlign);
139 constexpr size_t ArgEnd = ArgOffset + ArgSize; 139 constexpr size_t ArgEnd = ArgOffset + ArgSize;
140 140
141 return GetArgumentRawDataSize<Type1, Type2, MethodArguments, ArgAlign, ArgEnd, ArgIndex + 1>(); 141 return GetInRawDataSize<MethodArguments, ArgAlign, ArgEnd, ArgIndex + 1>();
142 } else {
143 return GetInRawDataSize<MethodArguments, PrevAlign, DataOffset, ArgIndex + 1>();
144 }
145 }
146}
147
148template <typename MethodArguments, size_t PrevAlign = 1, size_t DataOffset = 0, size_t ArgIndex = 0>
149constexpr u32 GetOutRawDataSize() {
150 if constexpr (ArgIndex >= std::tuple_size_v<MethodArguments>) {
151 return static_cast<u32>(DataOffset);
152 } else {
153 using ArgType = std::tuple_element_t<ArgIndex, MethodArguments>;
154
155 if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutData) {
156 using RawArgType = typename ArgType::Type;
157 constexpr size_t ArgAlign = alignof(RawArgType);
158 constexpr size_t ArgSize = sizeof(RawArgType);
159
160 static_assert(PrevAlign <= ArgAlign, "Output argument is not ordered by alignment");
161
162 constexpr size_t ArgOffset = Common::AlignUp(DataOffset, ArgAlign);
163 constexpr size_t ArgEnd = ArgOffset + ArgSize;
164
165 return GetOutRawDataSize<MethodArguments, ArgAlign, ArgEnd, ArgIndex + 1>();
142 } else { 166 } else {
143 return GetArgumentRawDataSize<Type1, Type2, MethodArguments, PrevAlign, DataOffset, ArgIndex + 1>(); 167 return GetOutRawDataSize<MethodArguments, PrevAlign, DataOffset, ArgIndex + 1>();
144 } 168 }
145 } 169 }
146} 170}
@@ -165,7 +189,7 @@ constexpr RequestLayout GetNonDomainReplyInLayout() {
165 return RequestLayout{ 189 return RequestLayout{
166 .copy_handle_count = GetArgumentTypeCount<ArgumentType::InCopyHandle, MethodArguments>(), 190 .copy_handle_count = GetArgumentTypeCount<ArgumentType::InCopyHandle, MethodArguments>(),
167 .move_handle_count = 0, 191 .move_handle_count = 0,
168 .cmif_raw_data_size = GetArgumentRawDataSize<ArgumentType::InData, ArgumentType::InProcessId, MethodArguments>(), 192 .cmif_raw_data_size = GetInRawDataSize<MethodArguments>(),
169 .domain_interface_count = 0, 193 .domain_interface_count = 0,
170 }; 194 };
171} 195}
@@ -175,7 +199,7 @@ constexpr RequestLayout GetDomainReplyInLayout() {
175 return RequestLayout{ 199 return RequestLayout{
176 .copy_handle_count = GetArgumentTypeCount<ArgumentType::InCopyHandle, MethodArguments>(), 200 .copy_handle_count = GetArgumentTypeCount<ArgumentType::InCopyHandle, MethodArguments>(),
177 .move_handle_count = 0, 201 .move_handle_count = 0,
178 .cmif_raw_data_size = GetArgumentRawDataSize<ArgumentType::InData, ArgumentType::InProcessId, MethodArguments>(), 202 .cmif_raw_data_size = GetInRawDataSize<MethodArguments>(),
179 .domain_interface_count = GetArgumentTypeCount<ArgumentType::InInterface, MethodArguments>(), 203 .domain_interface_count = GetArgumentTypeCount<ArgumentType::InInterface, MethodArguments>(),
180 }; 204 };
181} 205}
@@ -185,7 +209,7 @@ constexpr RequestLayout GetNonDomainReplyOutLayout() {
185 return RequestLayout{ 209 return RequestLayout{
186 .copy_handle_count = GetArgumentTypeCount<ArgumentType::OutCopyHandle, MethodArguments>(), 210 .copy_handle_count = GetArgumentTypeCount<ArgumentType::OutCopyHandle, MethodArguments>(),
187 .move_handle_count = GetArgumentTypeCount<ArgumentType::OutMoveHandle, MethodArguments>() + GetArgumentTypeCount<ArgumentType::OutInterface, MethodArguments>(), 211 .move_handle_count = GetArgumentTypeCount<ArgumentType::OutMoveHandle, MethodArguments>() + GetArgumentTypeCount<ArgumentType::OutInterface, MethodArguments>(),
188 .cmif_raw_data_size = GetArgumentRawDataSize<ArgumentType::OutData, ArgumentType::OutData, MethodArguments>(), 212 .cmif_raw_data_size = GetOutRawDataSize<MethodArguments>(),
189 .domain_interface_count = 0, 213 .domain_interface_count = 0,
190 }; 214 };
191} 215}
@@ -195,7 +219,7 @@ constexpr RequestLayout GetDomainReplyOutLayout() {
195 return RequestLayout{ 219 return RequestLayout{
196 .copy_handle_count = GetArgumentTypeCount<ArgumentType::OutCopyHandle, MethodArguments>(), 220 .copy_handle_count = GetArgumentTypeCount<ArgumentType::OutCopyHandle, MethodArguments>(),
197 .move_handle_count = GetArgumentTypeCount<ArgumentType::OutMoveHandle, MethodArguments>(), 221 .move_handle_count = GetArgumentTypeCount<ArgumentType::OutMoveHandle, MethodArguments>(),
198 .cmif_raw_data_size = GetArgumentRawDataSize<ArgumentType::OutData, ArgumentType::OutData, MethodArguments>(), 222 .cmif_raw_data_size = GetOutRawDataSize<MethodArguments>(),
199 .domain_interface_count = GetArgumentTypeCount<ArgumentType::OutInterface, MethodArguments>(), 223 .domain_interface_count = GetArgumentTypeCount<ArgumentType::OutInterface, MethodArguments>(),
200 }; 224 };
201} 225}
@@ -259,7 +283,7 @@ void ReadInArgument(bool is_domain, CallArguments& args, const u8* raw_data, HLE
259 283
260 return ReadInArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex + 1, InBufferIndex, OutBufferIndex, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); 284 return ReadInArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex + 1, InBufferIndex, OutBufferIndex, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp);
261 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::InLargeData) { 285 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::InLargeData) {
262 constexpr size_t BufferSize = sizeof(ArgType); 286 constexpr size_t BufferSize = sizeof(typename ArgType::Type);
263 287
264 // Clear the existing data. 288 // Clear the existing data.
265 std::memset(&std::get<ArgIndex>(args), 0, BufferSize); 289 std::memset(&std::get<ArgIndex>(args), 0, BufferSize);
@@ -300,7 +324,7 @@ void ReadInArgument(bool is_domain, CallArguments& args, const u8* raw_data, HLE
300 324
301 return ReadInArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex + 1, OutBufferIndex, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); 325 return ReadInArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex + 1, OutBufferIndex, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp);
302 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutLargeData) { 326 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutLargeData) {
303 constexpr size_t BufferSize = sizeof(ArgType); 327 constexpr size_t BufferSize = sizeof(typename ArgType::Type);
304 328
305 // Clear the existing data. 329 // Clear the existing data.
306 std::memset(&std::get<ArgIndex>(args).raw, 0, BufferSize); 330 std::memset(&std::get<ArgIndex>(args).raw, 0, BufferSize);
@@ -337,13 +361,15 @@ void WriteOutArgument(bool is_domain, CallArguments& args, u8* raw_data, HLERequ
337 using ArgType = std::tuple_element_t<ArgIndex, MethodArguments>; 361 using ArgType = std::tuple_element_t<ArgIndex, MethodArguments>;
338 362
339 if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutData) { 363 if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutData) {
340 constexpr size_t ArgAlign = alignof(ArgType); 364 using RawArgType = decltype(std::get<ArgIndex>(args).raw);
341 constexpr size_t ArgSize = sizeof(ArgType); 365 constexpr size_t ArgAlign = alignof(RawArgType);
366 constexpr size_t ArgSize = sizeof(RawArgType);
342 367
343 static_assert(PrevAlign <= ArgAlign, "Output argument is not ordered by alignment"); 368 static_assert(PrevAlign <= ArgAlign, "Output argument is not ordered by alignment");
344 static_assert(!RawDataFinished, "All output interface arguments must appear after raw data"); 369 static_assert(!RawDataFinished, "All output interface arguments must appear after raw data");
345 static_assert(!std::is_pointer_v<ArgType>, "Output raw data must not be a pointer"); 370 static_assert(!std::is_pointer_v<ArgType>, "Output raw data must not be a pointer");
346 static_assert(std::is_trivially_copyable_v<decltype(std::get<ArgIndex>(args).raw)>, "Output raw data must be trivially copyable"); 371 static_assert(!std::is_pointer_v<RawArgType>, "Output raw data must not be a pointer");
372 static_assert(std::is_trivially_copyable_v<RawArgType>, "Output raw data must be trivially copyable");
347 373
348 constexpr size_t ArgOffset = Common::AlignUp(DataOffset, ArgAlign); 374 constexpr size_t ArgOffset = Common::AlignUp(DataOffset, ArgAlign);
349 constexpr size_t ArgEnd = ArgOffset + ArgSize; 375 constexpr size_t ArgEnd = ArgOffset + ArgSize;
@@ -368,7 +394,7 @@ void WriteOutArgument(bool is_domain, CallArguments& args, u8* raw_data, HLERequ
368 394
369 return WriteOutArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); 395 return WriteOutArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp);
370 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutLargeData) { 396 } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutLargeData) {
371 constexpr size_t BufferSize = sizeof(ArgType); 397 constexpr size_t BufferSize = sizeof(typename ArgType::Type);
372 398
373 ASSERT(ctx.CanWriteBuffer(OutBufferIndex)); 399 ASSERT(ctx.CanWriteBuffer(OutBufferIndex));
374 if constexpr (ArgType::Attr & BufferAttr_HipcAutoSelect) { 400 if constexpr (ArgType::Attr & BufferAttr_HipcAutoSelect) {
diff --git a/src/core/hle/service/glue/time/time_zone.cpp b/src/core/hle/service/glue/time/time_zone.cpp
index 5dc1187cb..98d928697 100644
--- a/src/core/hle/service/glue/time/time_zone.cpp
+++ b/src/core/hle/service/glue/time/time_zone.cpp
@@ -197,32 +197,27 @@ Result TimeZoneService::ToCalendarTimeWithMyRule(
197 197
198Result TimeZoneService::ToPosixTime(Out<u32> out_count, 198Result TimeZoneService::ToPosixTime(Out<u32> out_count,
199 OutArray<s64, BufferAttr_HipcPointer> out_times, 199 OutArray<s64, BufferAttr_HipcPointer> out_times,
200 Out<u32> out_times_count, 200 const Service::PSC::Time::CalendarTime& calendar_time,
201 Service::PSC::Time::CalendarTime& calendar_time, InRule rule) { 201 InRule rule) {
202 SCOPE_EXIT({ 202 SCOPE_EXIT({
203 LOG_DEBUG(Service_Time, 203 LOG_DEBUG(Service_Time,
204 "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={} " 204 "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={}",
205 "out_times_count={}", 205 calendar_time, *out_count, out_times[0], out_times[1]);
206 calendar_time, *out_count, out_times[0], out_times[1], *out_times_count);
207 }); 206 });
208 207
209 R_RETURN( 208 R_RETURN(m_wrapped_service->ToPosixTime(out_count, out_times, calendar_time, rule));
210 m_wrapped_service->ToPosixTime(out_count, out_times, out_times_count, calendar_time, rule));
211} 209}
212 210
213Result TimeZoneService::ToPosixTimeWithMyRule(Out<u32> out_count, 211Result TimeZoneService::ToPosixTimeWithMyRule(
214 OutArray<s64, BufferAttr_HipcPointer> out_times, 212 Out<u32> out_count, OutArray<s64, BufferAttr_HipcPointer> out_times,
215 Out<u32> out_times_count, 213 const Service::PSC::Time::CalendarTime& calendar_time) {
216 Service::PSC::Time::CalendarTime& calendar_time) {
217 SCOPE_EXIT({ 214 SCOPE_EXIT({
218 LOG_DEBUG(Service_Time, 215 LOG_DEBUG(Service_Time,
219 "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={} " 216 "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={}",
220 "out_times_count={}", 217 calendar_time, *out_count, out_times[0], out_times[1]);
221 calendar_time, *out_count, out_times[0], out_times[1], *out_times_count);
222 }); 218 });
223 219
224 R_RETURN(m_wrapped_service->ToPosixTimeWithMyRule(out_count, out_times, out_times_count, 220 R_RETURN(m_wrapped_service->ToPosixTimeWithMyRule(out_count, out_times, calendar_time));
225 calendar_time));
226} 221}
227 222
228} // namespace Service::Glue::Time 223} // namespace Service::Glue::Time
diff --git a/src/core/hle/service/glue/time/time_zone.h b/src/core/hle/service/glue/time/time_zone.h
index bf12adbdc..9c1530966 100644
--- a/src/core/hle/service/glue/time/time_zone.h
+++ b/src/core/hle/service/glue/time/time_zone.h
@@ -68,12 +68,10 @@ public:
68 Out<Service::PSC::Time::CalendarTime> out_calendar_time, 68 Out<Service::PSC::Time::CalendarTime> out_calendar_time,
69 Out<Service::PSC::Time::CalendarAdditionalInfo> out_additional_info, s64 time); 69 Out<Service::PSC::Time::CalendarAdditionalInfo> out_additional_info, s64 time);
70 Result ToPosixTime(Out<u32> out_count, OutArray<s64, BufferAttr_HipcPointer> out_times, 70 Result ToPosixTime(Out<u32> out_count, OutArray<s64, BufferAttr_HipcPointer> out_times,
71 Out<u32> out_times_count, Service::PSC::Time::CalendarTime& calendar_time, 71 const Service::PSC::Time::CalendarTime& calendar_time, InRule rule);
72 InRule rule);
73 Result ToPosixTimeWithMyRule(Out<u32> out_count, 72 Result ToPosixTimeWithMyRule(Out<u32> out_count,
74 OutArray<s64, BufferAttr_HipcPointer> out_times, 73 OutArray<s64, BufferAttr_HipcPointer> out_times,
75 Out<u32> out_times_count, 74 const Service::PSC::Time::CalendarTime& calendar_time);
76 Service::PSC::Time::CalendarTime& calendar_time);
77 75
78private: 76private:
79 Core::System& m_system; 77 Core::System& m_system;
diff --git a/src/core/hle/service/hid/hid_server.cpp b/src/core/hle/service/hid/hid_server.cpp
index 09c47b5e3..938b93451 100644
--- a/src/core/hle/service/hid/hid_server.cpp
+++ b/src/core/hle/service/hid/hid_server.cpp
@@ -8,6 +8,7 @@
8#include "core/hle/kernel/k_shared_memory.h" 8#include "core/hle/kernel/k_shared_memory.h"
9#include "core/hle/kernel/k_transfer_memory.h" 9#include "core/hle/kernel/k_transfer_memory.h"
10#include "core/hle/kernel/kernel.h" 10#include "core/hle/kernel/kernel.h"
11#include "core/hle/service/cmif_serialization.h"
11#include "core/hle/service/hid/hid_server.h" 12#include "core/hle/service/hid/hid_server.h"
12#include "core/hle/service/ipc_helpers.h" 13#include "core/hle/service/ipc_helpers.h"
13#include "core/memory.h" 14#include "core/memory.h"
@@ -153,7 +154,7 @@ IHidServer::IHidServer(Core::System& system_, std::shared_ptr<ResourceManager> r
153 {104, &IHidServer::DeactivateNpad, "DeactivateNpad"}, 154 {104, &IHidServer::DeactivateNpad, "DeactivateNpad"},
154 {106, &IHidServer::AcquireNpadStyleSetUpdateEventHandle, "AcquireNpadStyleSetUpdateEventHandle"}, 155 {106, &IHidServer::AcquireNpadStyleSetUpdateEventHandle, "AcquireNpadStyleSetUpdateEventHandle"},
155 {107, &IHidServer::DisconnectNpad, "DisconnectNpad"}, 156 {107, &IHidServer::DisconnectNpad, "DisconnectNpad"},
156 {108, &IHidServer::GetPlayerLedPattern, "GetPlayerLedPattern"}, 157 {108, C<&IHidServer::GetPlayerLedPattern>, "GetPlayerLedPattern"},
157 {109, &IHidServer::ActivateNpadWithRevision, "ActivateNpadWithRevision"}, 158 {109, &IHidServer::ActivateNpadWithRevision, "ActivateNpadWithRevision"},
158 {120, &IHidServer::SetNpadJoyHoldType, "SetNpadJoyHoldType"}, 159 {120, &IHidServer::SetNpadJoyHoldType, "SetNpadJoyHoldType"},
159 {121, &IHidServer::GetNpadJoyHoldType, "GetNpadJoyHoldType"}, 160 {121, &IHidServer::GetNpadJoyHoldType, "GetNpadJoyHoldType"},
@@ -1136,19 +1137,39 @@ void IHidServer::DisconnectNpad(HLERequestContext& ctx) {
1136 rb.Push(ResultSuccess); 1137 rb.Push(ResultSuccess);
1137} 1138}
1138 1139
1139void IHidServer::GetPlayerLedPattern(HLERequestContext& ctx) { 1140Result IHidServer::GetPlayerLedPattern(Out<Core::HID::LedPattern> out_led_pattern,
1140 IPC::RequestParser rp{ctx}; 1141 Core::HID::NpadIdType npad_id) {
1141 const auto npad_id{rp.PopEnum<Core::HID::NpadIdType>()};
1142
1143 Core::HID::LedPattern pattern{0, 0, 0, 0};
1144 auto controller = GetResourceManager()->GetNpad();
1145 const auto result = controller->GetLedPattern(npad_id, pattern);
1146
1147 LOG_DEBUG(Service_HID, "called, npad_id={}", npad_id); 1142 LOG_DEBUG(Service_HID, "called, npad_id={}", npad_id);
1148 1143
1149 IPC::ResponseBuilder rb{ctx, 4}; 1144 switch (npad_id) {
1150 rb.Push(result); 1145 case Core::HID::NpadIdType::Player1:
1151 rb.Push(pattern.raw); 1146 *out_led_pattern = Core::HID::LedPattern{1, 0, 0, 0};
1147 R_SUCCEED();
1148 case Core::HID::NpadIdType::Player2:
1149 *out_led_pattern = Core::HID::LedPattern{1, 1, 0, 0};
1150 R_SUCCEED();
1151 case Core::HID::NpadIdType::Player3:
1152 *out_led_pattern = Core::HID::LedPattern{1, 1, 1, 0};
1153 R_SUCCEED();
1154 case Core::HID::NpadIdType::Player4:
1155 *out_led_pattern = Core::HID::LedPattern{1, 1, 1, 1};
1156 R_SUCCEED();
1157 case Core::HID::NpadIdType::Player5:
1158 *out_led_pattern = Core::HID::LedPattern{1, 0, 0, 1};
1159 R_SUCCEED();
1160 case Core::HID::NpadIdType::Player6:
1161 *out_led_pattern = Core::HID::LedPattern{1, 0, 1, 0};
1162 R_SUCCEED();
1163 case Core::HID::NpadIdType::Player7:
1164 *out_led_pattern = Core::HID::LedPattern{1, 0, 1, 1};
1165 R_SUCCEED();
1166 case Core::HID::NpadIdType::Player8:
1167 *out_led_pattern = Core::HID::LedPattern{0, 1, 1, 0};
1168 R_SUCCEED();
1169 default:
1170 *out_led_pattern = Core::HID::LedPattern{0, 0, 0, 0};
1171 R_SUCCEED();
1172 }
1152} 1173}
1153 1174
1154void IHidServer::ActivateNpadWithRevision(HLERequestContext& ctx) { 1175void IHidServer::ActivateNpadWithRevision(HLERequestContext& ctx) {
diff --git a/src/core/hle/service/hid/hid_server.h b/src/core/hle/service/hid/hid_server.h
index 3a2e0a230..faf775689 100644
--- a/src/core/hle/service/hid/hid_server.h
+++ b/src/core/hle/service/hid/hid_server.h
@@ -3,7 +3,9 @@
3 3
4#pragma once 4#pragma once
5 5
6#include "core/hle/service/cmif_types.h"
6#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8#include "hid_core/hid_types.h"
7 9
8namespace Core { 10namespace Core {
9class System; 11class System;
@@ -66,7 +68,8 @@ private:
66 void DeactivateNpad(HLERequestContext& ctx); 68 void DeactivateNpad(HLERequestContext& ctx);
67 void AcquireNpadStyleSetUpdateEventHandle(HLERequestContext& ctx); 69 void AcquireNpadStyleSetUpdateEventHandle(HLERequestContext& ctx);
68 void DisconnectNpad(HLERequestContext& ctx); 70 void DisconnectNpad(HLERequestContext& ctx);
69 void GetPlayerLedPattern(HLERequestContext& ctx); 71 Result GetPlayerLedPattern(Out<Core::HID::LedPattern> out_led_pattern,
72 Core::HID::NpadIdType npad_id);
70 void ActivateNpadWithRevision(HLERequestContext& ctx); 73 void ActivateNpadWithRevision(HLERequestContext& ctx);
71 void SetNpadJoyHoldType(HLERequestContext& ctx); 74 void SetNpadJoyHoldType(HLERequestContext& ctx);
72 void GetNpadJoyHoldType(HLERequestContext& ctx); 75 void GetNpadJoyHoldType(HLERequestContext& ctx);
diff --git a/src/core/hle/service/nvdrv/core/container.cpp b/src/core/hle/service/nvdrv/core/container.cpp
index dc1b4d5be..e89cca6f2 100644
--- a/src/core/hle/service/nvdrv/core/container.cpp
+++ b/src/core/hle/service/nvdrv/core/container.cpp
@@ -83,7 +83,9 @@ SessionId Container::OpenSession(Kernel::KProcess* process) {
83 83
84 // Check if this memory block is heap. 84 // Check if this memory block is heap.
85 if (svc_mem_info.state == Kernel::Svc::MemoryState::Normal) { 85 if (svc_mem_info.state == Kernel::Svc::MemoryState::Normal) {
86 if (svc_mem_info.size > region_size) { 86 if (region_start + region_size == svc_mem_info.base_address) {
87 region_size += svc_mem_info.size;
88 } else if (svc_mem_info.size > region_size) {
87 region_size = svc_mem_info.size; 89 region_size = svc_mem_info.size;
88 region_start = svc_mem_info.base_address; 90 region_start = svc_mem_info.base_address;
89 } 91 }
diff --git a/src/core/hle/service/psc/time/common.h b/src/core/hle/service/psc/time/common.h
index 596828b8b..3e13144a0 100644
--- a/src/core/hle/service/psc/time/common.h
+++ b/src/core/hle/service/psc/time/common.h
@@ -189,7 +189,7 @@ struct fmt::formatter<Service::PSC::Time::SteadyClockTimePoint> : fmt::formatter
189 template <typename FormatContext> 189 template <typename FormatContext>
190 auto format(const Service::PSC::Time::SteadyClockTimePoint& time_point, 190 auto format(const Service::PSC::Time::SteadyClockTimePoint& time_point,
191 FormatContext& ctx) const { 191 FormatContext& ctx) const {
192 return fmt::format_to(ctx.out(), "time_point={}", time_point.time_point); 192 return fmt::format_to(ctx.out(), "[time_point={}]", time_point.time_point);
193 } 193 }
194}; 194};
195 195
@@ -197,7 +197,7 @@ template <>
197struct fmt::formatter<Service::PSC::Time::SystemClockContext> : fmt::formatter<fmt::string_view> { 197struct fmt::formatter<Service::PSC::Time::SystemClockContext> : fmt::formatter<fmt::string_view> {
198 template <typename FormatContext> 198 template <typename FormatContext>
199 auto format(const Service::PSC::Time::SystemClockContext& context, FormatContext& ctx) const { 199 auto format(const Service::PSC::Time::SystemClockContext& context, FormatContext& ctx) const {
200 return fmt::format_to(ctx.out(), "offset={} steady_time_point={}", context.offset, 200 return fmt::format_to(ctx.out(), "[offset={} steady_time_point={}]", context.offset,
201 context.steady_time_point.time_point); 201 context.steady_time_point.time_point);
202 } 202 }
203}; 203};
@@ -206,8 +206,9 @@ template <>
206struct fmt::formatter<Service::PSC::Time::CalendarTime> : fmt::formatter<fmt::string_view> { 206struct fmt::formatter<Service::PSC::Time::CalendarTime> : fmt::formatter<fmt::string_view> {
207 template <typename FormatContext> 207 template <typename FormatContext>
208 auto format(const Service::PSC::Time::CalendarTime& calendar, FormatContext& ctx) const { 208 auto format(const Service::PSC::Time::CalendarTime& calendar, FormatContext& ctx) const {
209 return fmt::format_to(ctx.out(), "{}/{}/{} {}:{}:{}", calendar.day, calendar.month, 209 return fmt::format_to(ctx.out(), "[{:02}/{:02}/{:04} {:02}:{:02}:{:02}]", calendar.day,
210 calendar.year, calendar.hour, calendar.minute, calendar.second); 210 calendar.month, calendar.year, calendar.hour, calendar.minute,
211 calendar.second);
211 } 212 }
212}; 213};
213 214
@@ -217,7 +218,7 @@ struct fmt::formatter<Service::PSC::Time::CalendarAdditionalInfo>
217 template <typename FormatContext> 218 template <typename FormatContext>
218 auto format(const Service::PSC::Time::CalendarAdditionalInfo& additional, 219 auto format(const Service::PSC::Time::CalendarAdditionalInfo& additional,
219 FormatContext& ctx) const { 220 FormatContext& ctx) const {
220 return fmt::format_to(ctx.out(), "weekday={} yearday={} name={} is_dst={} ut_offset={}", 221 return fmt::format_to(ctx.out(), "[weekday={} yearday={} name={} is_dst={} ut_offset={}]",
221 additional.day_of_week, additional.day_of_year, 222 additional.day_of_week, additional.day_of_year,
222 additional.name.data(), additional.is_dst, additional.ut_offset); 223 additional.name.data(), additional.is_dst, additional.ut_offset);
223 } 224 }
@@ -227,8 +228,7 @@ template <>
227struct fmt::formatter<Service::PSC::Time::LocationName> : fmt::formatter<fmt::string_view> { 228struct fmt::formatter<Service::PSC::Time::LocationName> : fmt::formatter<fmt::string_view> {
228 template <typename FormatContext> 229 template <typename FormatContext>
229 auto format(const Service::PSC::Time::LocationName& name, FormatContext& ctx) const { 230 auto format(const Service::PSC::Time::LocationName& name, FormatContext& ctx) const {
230 std::string_view n{name.data(), name.size()}; 231 return formatter<string_view>::format(name.data(), ctx);
231 return formatter<string_view>::format(n, ctx);
232 } 232 }
233}; 233};
234 234
@@ -236,8 +236,7 @@ template <>
236struct fmt::formatter<Service::PSC::Time::RuleVersion> : fmt::formatter<fmt::string_view> { 236struct fmt::formatter<Service::PSC::Time::RuleVersion> : fmt::formatter<fmt::string_view> {
237 template <typename FormatContext> 237 template <typename FormatContext>
238 auto format(const Service::PSC::Time::RuleVersion& version, FormatContext& ctx) const { 238 auto format(const Service::PSC::Time::RuleVersion& version, FormatContext& ctx) const {
239 std::string_view v{version.data(), version.size()}; 239 return formatter<string_view>::format(version.data(), ctx);
240 return formatter<string_view>::format(v, ctx);
241 } 240 }
242}; 241};
243 242
@@ -247,10 +246,11 @@ struct fmt::formatter<Service::PSC::Time::ClockSnapshot> : fmt::formatter<fmt::s
247 auto format(const Service::PSC::Time::ClockSnapshot& snapshot, FormatContext& ctx) const { 246 auto format(const Service::PSC::Time::ClockSnapshot& snapshot, FormatContext& ctx) const {
248 return fmt::format_to( 247 return fmt::format_to(
249 ctx.out(), 248 ctx.out(),
250 "user_context={} network_context={} user_time={} network_time={} user_calendar_time={} " 249 "[user_context={} network_context={} user_time={} network_time={} "
250 "user_calendar_time={} "
251 "network_calendar_time={} user_calendar_additional_time={} " 251 "network_calendar_time={} user_calendar_additional_time={} "
252 "network_calendar_additional_time={} steady_clock_time_point={} location={} " 252 "network_calendar_additional_time={} steady_clock_time_point={} location={} "
253 "is_automatic_correction_enabled={} type={}", 253 "is_automatic_correction_enabled={} type={}]",
254 snapshot.user_context, snapshot.network_context, snapshot.user_time, 254 snapshot.user_context, snapshot.network_context, snapshot.user_time,
255 snapshot.network_time, snapshot.user_calendar_time, snapshot.network_calendar_time, 255 snapshot.network_time, snapshot.user_calendar_time, snapshot.network_calendar_time,
256 snapshot.user_calendar_additional_time, snapshot.network_calendar_additional_time, 256 snapshot.user_calendar_additional_time, snapshot.network_calendar_additional_time,
@@ -266,7 +266,7 @@ struct fmt::formatter<Service::PSC::Time::ContinuousAdjustmentTimePoint>
266 auto format(const Service::PSC::Time::ContinuousAdjustmentTimePoint& time_point, 266 auto format(const Service::PSC::Time::ContinuousAdjustmentTimePoint& time_point,
267 FormatContext& ctx) const { 267 FormatContext& ctx) const {
268 return fmt::format_to(ctx.out(), 268 return fmt::format_to(ctx.out(),
269 "rtc_offset={} diff_scale={} shift_amount={} lower={} upper={}", 269 "[rtc_offset={} diff_scale={} shift_amount={} lower={} upper={}]",
270 time_point.rtc_offset, time_point.diff_scale, time_point.shift_amount, 270 time_point.rtc_offset, time_point.diff_scale, time_point.shift_amount,
271 time_point.lower, time_point.upper); 271 time_point.lower, time_point.upper);
272 } 272 }
diff --git a/src/core/hle/service/psc/time/service_manager.cpp b/src/core/hle/service/psc/time/service_manager.cpp
index ec906b723..4e1643fcb 100644
--- a/src/core/hle/service/psc/time/service_manager.cpp
+++ b/src/core/hle/service/psc/time/service_manager.cpp
@@ -120,11 +120,8 @@ Result ServiceManager::SetupStandardNetworkSystemClockCore(SystemClockContext& c
120 context, context.steady_time_point.clock_source_id.RawString(), accuracy); 120 context, context.steady_time_point.clock_source_id.RawString(), accuracy);
121 121
122 // TODO this is a hack! The network clock should be updated independently, from the ntc service 122 // TODO this is a hack! The network clock should be updated independently, from the ntc service
123 // and maybe elsewhere. We do not do that, so fix the clock to the local clock on first boot 123 // and maybe elsewhere. We do not do that, so fix the clock to the local clock.
124 // to avoid it being stuck at 0. 124 m_local_system_clock.GetContext(context);
125 if (context == Service::PSC::Time::SystemClockContext{}) {
126 m_local_system_clock.GetContext(context);
127 }
128 125
129 m_network_system_clock.SetContextWriter(m_network_system_context_writer); 126 m_network_system_clock.SetContextWriter(m_network_system_context_writer);
130 m_network_system_clock.Initialize(context, accuracy); 127 m_network_system_clock.Initialize(context, accuracy);
@@ -138,13 +135,6 @@ Result ServiceManager::SetupStandardUserSystemClockCore(bool automatic_correctio
138 LOG_DEBUG(Service_Time, "called. automatic_correction={} time_point={} clock_source_id={}", 135 LOG_DEBUG(Service_Time, "called. automatic_correction={} time_point={} clock_source_id={}",
139 automatic_correction, time_point, time_point.clock_source_id.RawString()); 136 automatic_correction, time_point, time_point.clock_source_id.RawString());
140 137
141 // TODO this is a hack! The user clock should be updated independently, from the ntc service
142 // and maybe elsewhere. We do not do that, so fix the clock to the local clock on first boot
143 // to avoid it being stuck at 0.
144 if (time_point == Service::PSC::Time::SteadyClockTimePoint{}) {
145 m_local_system_clock.GetCurrentTimePoint(time_point);
146 }
147
148 m_user_system_clock.SetAutomaticCorrection(automatic_correction); 138 m_user_system_clock.SetAutomaticCorrection(automatic_correction);
149 m_user_system_clock.SetTimePointAndSignal(time_point); 139 m_user_system_clock.SetTimePointAndSignal(time_point);
150 m_user_system_clock.SetInitialized(); 140 m_user_system_clock.SetInitialized();
diff --git a/src/core/hle/service/psc/time/time_zone.cpp b/src/core/hle/service/psc/time/time_zone.cpp
index 82ddba42f..cc855c763 100644
--- a/src/core/hle/service/psc/time/time_zone.cpp
+++ b/src/core/hle/service/psc/time/time_zone.cpp
@@ -140,11 +140,11 @@ Result TimeZone::ParseBinaryInto(Tz::Rule& out_rule, std::span<const u8> binary)
140 R_RETURN(ParseBinaryImpl(out_rule, binary)); 140 R_RETURN(ParseBinaryImpl(out_rule, binary));
141} 141}
142 142
143Result TimeZone::ToPosixTime(u32& out_count, std::span<s64> out_times, u32 out_times_count, 143Result TimeZone::ToPosixTime(u32& out_count, std::span<s64> out_times, size_t out_times_max_count,
144 CalendarTime& calendar, const Tz::Rule& rule) { 144 const CalendarTime& calendar, const Tz::Rule& rule) {
145 std::scoped_lock l{m_mutex}; 145 std::scoped_lock l{m_mutex};
146 146
147 auto res = ToPosixTimeImpl(out_count, out_times, out_times_count, calendar, rule, -1); 147 auto res = ToPosixTimeImpl(out_count, out_times, out_times_max_count, calendar, rule, -1);
148 148
149 if (res != ResultSuccess) { 149 if (res != ResultSuccess) {
150 if (res == ResultTimeZoneNotFound) { 150 if (res == ResultTimeZoneNotFound) {
@@ -158,10 +158,10 @@ Result TimeZone::ToPosixTime(u32& out_count, std::span<s64> out_times, u32 out_t
158} 158}
159 159
160Result TimeZone::ToPosixTimeWithMyRule(u32& out_count, std::span<s64> out_times, 160Result TimeZone::ToPosixTimeWithMyRule(u32& out_count, std::span<s64> out_times,
161 u32 out_times_count, CalendarTime& calendar) { 161 size_t out_times_max_count, const CalendarTime& calendar) {
162 std::scoped_lock l{m_mutex}; 162 std::scoped_lock l{m_mutex};
163 163
164 auto res = ToPosixTimeImpl(out_count, out_times, out_times_count, calendar, m_my_rule, -1); 164 auto res = ToPosixTimeImpl(out_count, out_times, out_times_max_count, calendar, m_my_rule, -1);
165 165
166 if (res != ResultSuccess) { 166 if (res != ResultSuccess) {
167 if (res == ResultTimeZoneNotFound) { 167 if (res == ResultTimeZoneNotFound) {
@@ -212,20 +212,23 @@ Result TimeZone::ToCalendarTimeImpl(CalendarTime& out_calendar_time,
212 R_SUCCEED(); 212 R_SUCCEED();
213} 213}
214 214
215Result TimeZone::ToPosixTimeImpl(u32& out_count, std::span<s64> out_times, u32 out_times_count, 215Result TimeZone::ToPosixTimeImpl(u32& out_count, std::span<s64> out_times,
216 CalendarTime& calendar, const Tz::Rule& rule, s32 is_dst) { 216 size_t out_times_max_count, const CalendarTime& calendar,
217 const Tz::Rule& rule, s32 is_dst) {
217 R_TRY(ValidateRule(rule)); 218 R_TRY(ValidateRule(rule));
218 219
219 calendar.month -= 1; 220 CalendarTime local_calendar{calendar};
220 calendar.year -= 1900; 221
222 local_calendar.month -= 1;
223 local_calendar.year -= 1900;
221 224
222 Tz::CalendarTimeInternal internal{ 225 Tz::CalendarTimeInternal internal{
223 .tm_sec = calendar.second, 226 .tm_sec = local_calendar.second,
224 .tm_min = calendar.minute, 227 .tm_min = local_calendar.minute,
225 .tm_hour = calendar.hour, 228 .tm_hour = local_calendar.hour,
226 .tm_mday = calendar.day, 229 .tm_mday = local_calendar.day,
227 .tm_mon = calendar.month, 230 .tm_mon = local_calendar.month,
228 .tm_year = calendar.year, 231 .tm_year = local_calendar.year,
229 .tm_wday = 0, 232 .tm_wday = 0,
230 .tm_yday = 0, 233 .tm_yday = 0,
231 .tm_isdst = is_dst, 234 .tm_isdst = is_dst,
@@ -243,9 +246,9 @@ Result TimeZone::ToPosixTimeImpl(u32& out_count, std::span<s64> out_times, u32 o
243 R_RETURN(ResultTimeZoneNotFound); 246 R_RETURN(ResultTimeZoneNotFound);
244 } 247 }
245 248
246 if (internal.tm_sec != calendar.second || internal.tm_min != calendar.minute || 249 if (internal.tm_sec != local_calendar.second || internal.tm_min != local_calendar.minute ||
247 internal.tm_hour != calendar.hour || internal.tm_mday != calendar.day || 250 internal.tm_hour != local_calendar.hour || internal.tm_mday != local_calendar.day ||
248 internal.tm_mon != calendar.month || internal.tm_year != calendar.year) { 251 internal.tm_mon != local_calendar.month || internal.tm_year != local_calendar.year) {
249 R_RETURN(ResultTimeZoneNotFound); 252 R_RETURN(ResultTimeZoneNotFound);
250 } 253 }
251 254
@@ -254,7 +257,7 @@ Result TimeZone::ToPosixTimeImpl(u32& out_count, std::span<s64> out_times, u32 o
254 } 257 }
255 258
256 out_times[0] = time; 259 out_times[0] = time;
257 if (out_times_count < 2) { 260 if (out_times_max_count < 2) {
258 out_count = 1; 261 out_count = 1;
259 R_SUCCEED(); 262 R_SUCCEED();
260 } 263 }
diff --git a/src/core/hle/service/psc/time/time_zone.h b/src/core/hle/service/psc/time/time_zone.h
index 6bd8f2fda..6248e45f9 100644
--- a/src/core/hle/service/psc/time/time_zone.h
+++ b/src/core/hle/service/psc/time/time_zone.h
@@ -38,18 +38,18 @@ public:
38 CalendarAdditionalInfo& calendar_additional, s64 time); 38 CalendarAdditionalInfo& calendar_additional, s64 time);
39 Result ParseBinary(LocationName& name, std::span<const u8> binary); 39 Result ParseBinary(LocationName& name, std::span<const u8> binary);
40 Result ParseBinaryInto(Tz::Rule& out_rule, std::span<const u8> binary); 40 Result ParseBinaryInto(Tz::Rule& out_rule, std::span<const u8> binary);
41 Result ToPosixTime(u32& out_count, std::span<s64> out_times, u32 out_times_count, 41 Result ToPosixTime(u32& out_count, std::span<s64> out_times, size_t out_times_max_count,
42 CalendarTime& calendar, const Tz::Rule& rule); 42 const CalendarTime& calendar, const Tz::Rule& rule);
43 Result ToPosixTimeWithMyRule(u32& out_count, std::span<s64> out_times, u32 out_times_count, 43 Result ToPosixTimeWithMyRule(u32& out_count, std::span<s64> out_times,
44 CalendarTime& calendar); 44 size_t out_times_max_count, const CalendarTime& calendar);
45 45
46private: 46private:
47 Result ParseBinaryImpl(Tz::Rule& out_rule, std::span<const u8> binary); 47 Result ParseBinaryImpl(Tz::Rule& out_rule, std::span<const u8> binary);
48 Result ToCalendarTimeImpl(CalendarTime& out_calendar_time, 48 Result ToCalendarTimeImpl(CalendarTime& out_calendar_time,
49 CalendarAdditionalInfo& out_additional_info, s64 time, 49 CalendarAdditionalInfo& out_additional_info, s64 time,
50 const Tz::Rule& rule); 50 const Tz::Rule& rule);
51 Result ToPosixTimeImpl(u32& out_count, std::span<s64> out_times, u32 out_times_count, 51 Result ToPosixTimeImpl(u32& out_count, std::span<s64> out_times, size_t out_times_max_count,
52 CalendarTime& calendar, const Tz::Rule& rule, s32 is_dst); 52 const CalendarTime& calendar, const Tz::Rule& rule, s32 is_dst);
53 53
54 bool m_initialized{}; 54 bool m_initialized{};
55 std::recursive_mutex m_mutex; 55 std::recursive_mutex m_mutex;
diff --git a/src/core/hle/service/psc/time/time_zone_service.cpp b/src/core/hle/service/psc/time/time_zone_service.cpp
index 9376a0324..eb81f5b03 100644
--- a/src/core/hle/service/psc/time/time_zone_service.cpp
+++ b/src/core/hle/service/psc/time/time_zone_service.cpp
@@ -138,32 +138,28 @@ Result TimeZoneService::ToCalendarTimeWithMyRule(Out<CalendarTime> out_calendar_
138 138
139Result TimeZoneService::ToPosixTime(Out<u32> out_count, 139Result TimeZoneService::ToPosixTime(Out<u32> out_count,
140 OutArray<s64, BufferAttr_HipcPointer> out_times, 140 OutArray<s64, BufferAttr_HipcPointer> out_times,
141 Out<u32> out_times_count, CalendarTime& calendar_time, 141 const CalendarTime& calendar_time, InRule rule) {
142 InRule rule) {
143 SCOPE_EXIT({ 142 SCOPE_EXIT({
144 LOG_DEBUG(Service_Time, 143 LOG_DEBUG(Service_Time,
145 "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={} " 144 "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={} ",
146 "out_times_count={}", 145 calendar_time, *out_count, out_times[0], out_times[1]);
147 calendar_time, *out_count, out_times[0], out_times[1], *out_times_count);
148 }); 146 });
149 147
150 R_RETURN( 148 R_RETURN(
151 m_time_zone.ToPosixTime(*out_count, out_times, *out_times_count, calendar_time, *rule)); 149 m_time_zone.ToPosixTime(*out_count, out_times, out_times.size(), calendar_time, *rule));
152} 150}
153 151
154Result TimeZoneService::ToPosixTimeWithMyRule(Out<u32> out_count, 152Result TimeZoneService::ToPosixTimeWithMyRule(Out<u32> out_count,
155 OutArray<s64, BufferAttr_HipcPointer> out_times, 153 OutArray<s64, BufferAttr_HipcPointer> out_times,
156 Out<u32> out_times_count, 154 const CalendarTime& calendar_time) {
157 CalendarTime& calendar_time) {
158 SCOPE_EXIT({ 155 SCOPE_EXIT({
159 LOG_DEBUG(Service_Time, 156 LOG_DEBUG(Service_Time,
160 "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={} " 157 "called. calendar_time={} out_count={} out_times[0]={} out_times[1]={} ",
161 "out_times_count={}", 158 calendar_time, *out_count, out_times[0], out_times[1]);
162 calendar_time, *out_count, out_times[0], out_times[1], *out_times_count);
163 }); 159 });
164 160
165 R_RETURN( 161 R_RETURN(
166 m_time_zone.ToPosixTimeWithMyRule(*out_count, out_times, *out_times_count, calendar_time)); 162 m_time_zone.ToPosixTimeWithMyRule(*out_count, out_times, out_times.size(), calendar_time));
167} 163}
168 164
169} // namespace Service::PSC::Time 165} // namespace Service::PSC::Time
diff --git a/src/core/hle/service/psc/time/time_zone_service.h b/src/core/hle/service/psc/time/time_zone_service.h
index 084e3f907..6eb9ddc4b 100644
--- a/src/core/hle/service/psc/time/time_zone_service.h
+++ b/src/core/hle/service/psc/time/time_zone_service.h
@@ -50,10 +50,10 @@ public:
50 Result ToCalendarTimeWithMyRule(Out<CalendarTime> out_calendar_time, 50 Result ToCalendarTimeWithMyRule(Out<CalendarTime> out_calendar_time,
51 Out<CalendarAdditionalInfo> out_additional_info, s64 time); 51 Out<CalendarAdditionalInfo> out_additional_info, s64 time);
52 Result ToPosixTime(Out<u32> out_count, OutArray<s64, BufferAttr_HipcPointer> out_times, 52 Result ToPosixTime(Out<u32> out_count, OutArray<s64, BufferAttr_HipcPointer> out_times,
53 Out<u32> out_times_count, CalendarTime& calendar_time, InRule rule); 53 const CalendarTime& calendar_time, InRule rule);
54 Result ToPosixTimeWithMyRule(Out<u32> out_count, 54 Result ToPosixTimeWithMyRule(Out<u32> out_count,
55 OutArray<s64, BufferAttr_HipcPointer> out_times, 55 OutArray<s64, BufferAttr_HipcPointer> out_times,
56 Out<u32> out_times_count, CalendarTime& calendar_time); 56 const CalendarTime& calendar_time);
57 57
58private: 58private:
59 Core::System& m_system; 59 Core::System& m_system;
diff --git a/src/core/hle/service/set/system_settings_server.cpp b/src/core/hle/service/set/system_settings_server.cpp
index 100cb2db4..d3d0fb112 100644
--- a/src/core/hle/service/set/system_settings_server.cpp
+++ b/src/core/hle/service/set/system_settings_server.cpp
@@ -25,7 +25,7 @@
25namespace Service::Set { 25namespace Service::Set {
26 26
27namespace { 27namespace {
28constexpr u32 SETTINGS_VERSION{2u}; 28constexpr u32 SETTINGS_VERSION{3u};
29constexpr auto SETTINGS_MAGIC = Common::MakeMagic('y', 'u', 'z', 'u', '_', 's', 'e', 't'); 29constexpr auto SETTINGS_MAGIC = Common::MakeMagic('y', 'u', 'z', 'u', '_', 's', 'e', 't');
30struct SettingsHeader { 30struct SettingsHeader {
31 u64 magic; 31 u64 magic;
diff --git a/src/core/hle/service/sockets/sockets.h b/src/core/hle/service/sockets/sockets.h
index f86af01a4..f3ea31bde 100644
--- a/src/core/hle/service/sockets/sockets.h
+++ b/src/core/hle/service/sockets/sockets.h
@@ -24,6 +24,7 @@ enum class Errno : u32 {
24 CONNRESET = 104, 24 CONNRESET = 104,
25 NOTCONN = 107, 25 NOTCONN = 107,
26 TIMEDOUT = 110, 26 TIMEDOUT = 110,
27 CONNREFUSED = 111,
27 INPROGRESS = 115, 28 INPROGRESS = 115,
28}; 29};
29 30
diff --git a/src/core/hle/service/sockets/sockets_translate.cpp b/src/core/hle/service/sockets/sockets_translate.cpp
index aed05250c..21bb3e776 100644
--- a/src/core/hle/service/sockets/sockets_translate.cpp
+++ b/src/core/hle/service/sockets/sockets_translate.cpp
@@ -25,6 +25,8 @@ Errno Translate(Network::Errno value) {
25 return Errno::MFILE; 25 return Errno::MFILE;
26 case Network::Errno::PIPE: 26 case Network::Errno::PIPE:
27 return Errno::PIPE; 27 return Errno::PIPE;
28 case Network::Errno::CONNREFUSED:
29 return Errno::CONNREFUSED;
28 case Network::Errno::NOTCONN: 30 case Network::Errno::NOTCONN:
29 return Errno::NOTCONN; 31 return Errno::NOTCONN;
30 case Network::Errno::TIMEDOUT: 32 case Network::Errno::TIMEDOUT:
diff --git a/src/core/internal_network/network.cpp b/src/core/internal_network/network.cpp
index a983f23ea..7785c1d16 100644
--- a/src/core/internal_network/network.cpp
+++ b/src/core/internal_network/network.cpp
@@ -693,20 +693,23 @@ std::pair<SocketBase::AcceptResult, Errno> Socket::Accept() {
693 sockaddr_in addr; 693 sockaddr_in addr;
694 socklen_t addrlen = sizeof(addr); 694 socklen_t addrlen = sizeof(addr);
695 695
696 std::vector<WSAPOLLFD> host_pollfds{ 696 const bool wait_for_accept = !is_non_blocking;
697 WSAPOLLFD{fd, POLLIN, 0}, 697 if (wait_for_accept) {
698 WSAPOLLFD{GetInterruptSocket(), POLLIN, 0}, 698 std::vector<WSAPOLLFD> host_pollfds{
699 }; 699 WSAPOLLFD{fd, POLLIN, 0},
700 700 WSAPOLLFD{GetInterruptSocket(), POLLIN, 0},
701 while (true) { 701 };
702 const int pollres = 702
703 WSAPoll(host_pollfds.data(), static_cast<ULONG>(host_pollfds.size()), -1); 703 while (true) {
704 if (host_pollfds[1].revents != 0) { 704 const int pollres =
705 // Interrupt signaled before a client could be accepted, break 705 WSAPoll(host_pollfds.data(), static_cast<ULONG>(host_pollfds.size()), -1);
706 return {AcceptResult{}, Errno::AGAIN}; 706 if (host_pollfds[1].revents != 0) {
707 } 707 // Interrupt signaled before a client could be accepted, break
708 if (pollres > 0) { 708 return {AcceptResult{}, Errno::AGAIN};
709 break; 709 }
710 if (pollres > 0) {
711 break;
712 }
710 } 713 }
711 } 714 }
712 715
@@ -913,6 +916,7 @@ Errno Socket::SetRcvTimeo(u32 value) {
913 916
914Errno Socket::SetNonBlock(bool enable) { 917Errno Socket::SetNonBlock(bool enable) {
915 if (EnableNonBlock(fd, enable)) { 918 if (EnableNonBlock(fd, enable)) {
919 is_non_blocking = enable;
916 return Errno::SUCCESS; 920 return Errno::SUCCESS;
917 } 921 }
918 return GetAndLogLastError(); 922 return GetAndLogLastError();
diff --git a/src/core/internal_network/sockets.h b/src/core/internal_network/sockets.h
index 4ba51f62c..3a32dff75 100644
--- a/src/core/internal_network/sockets.h
+++ b/src/core/internal_network/sockets.h
@@ -166,6 +166,9 @@ public:
166 bool IsOpened() const override; 166 bool IsOpened() const override;
167 167
168 void HandleProxyPacket(const ProxyPacket& packet) override; 168 void HandleProxyPacket(const ProxyPacket& packet) override;
169
170private:
171 bool is_non_blocking = false;
169}; 172};
170 173
171std::pair<s32, Errno> Poll(std::vector<PollFD>& poll_fds, s32 timeout); 174std::pair<s32, Errno> Poll(std::vector<PollFD>& poll_fds, s32 timeout);
diff --git a/src/hid_core/hid_types.h b/src/hid_core/hid_types.h
index b310ab72d..ffb5f1926 100644
--- a/src/hid_core/hid_types.h
+++ b/src/hid_core/hid_types.h
@@ -422,7 +422,10 @@ struct NpadPowerInfo {
422static_assert(sizeof(NpadPowerInfo) == 0xC, "NpadPowerInfo is an invalid size"); 422static_assert(sizeof(NpadPowerInfo) == 0xC, "NpadPowerInfo is an invalid size");
423 423
424struct LedPattern { 424struct LedPattern {
425 explicit LedPattern(u64 light1, u64 light2, u64 light3, u64 light4) { 425 LedPattern() {
426 raw = 0;
427 }
428 LedPattern(u64 light1, u64 light2, u64 light3, u64 light4) {
426 position1.Assign(light1); 429 position1.Assign(light1);
427 position2.Assign(light2); 430 position2.Assign(light2);
428 position3.Assign(light3); 431 position3.Assign(light3);
diff --git a/src/hid_core/resources/npad/npad.cpp b/src/hid_core/resources/npad/npad.cpp
index cde84b1bb..2823be348 100644
--- a/src/hid_core/resources/npad/npad.cpp
+++ b/src/hid_core/resources/npad/npad.cpp
@@ -956,17 +956,6 @@ Result NPad::SwapNpadAssignment(u64 aruid, Core::HID::NpadIdType npad_id_1,
956 return ResultSuccess; 956 return ResultSuccess;
957} 957}
958 958
959Result NPad::GetLedPattern(Core::HID::NpadIdType npad_id, Core::HID::LedPattern& pattern) const {
960 if (!IsNpadIdValid(npad_id)) {
961 LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id);
962 return ResultInvalidNpadId;
963 }
964 const auto aruid = applet_resource_holder.applet_resource->GetActiveAruid();
965 const auto& controller = GetControllerFromNpadIdType(aruid, npad_id).device;
966 pattern = controller->GetLedPattern();
967 return ResultSuccess;
968}
969
970Result NPad::IsUnintendedHomeButtonInputProtectionEnabled(bool& out_is_enabled, u64 aruid, 959Result NPad::IsUnintendedHomeButtonInputProtectionEnabled(bool& out_is_enabled, u64 aruid,
971 Core::HID::NpadIdType npad_id) const { 960 Core::HID::NpadIdType npad_id) const {
972 std::scoped_lock lock{mutex}; 961 std::scoped_lock lock{mutex};
diff --git a/src/hid_core/resources/npad/npad.h b/src/hid_core/resources/npad/npad.h
index 502cb9b55..3b1a69e7f 100644
--- a/src/hid_core/resources/npad/npad.h
+++ b/src/hid_core/resources/npad/npad.h
@@ -97,8 +97,6 @@ public:
97 Result ResetIsSixAxisSensorDeviceNewlyAssigned( 97 Result ResetIsSixAxisSensorDeviceNewlyAssigned(
98 u64 aruid, const Core::HID::SixAxisSensorHandle& sixaxis_handle); 98 u64 aruid, const Core::HID::SixAxisSensorHandle& sixaxis_handle);
99 99
100 Result GetLedPattern(Core::HID::NpadIdType npad_id, Core::HID::LedPattern& pattern) const;
101
102 Result IsUnintendedHomeButtonInputProtectionEnabled(bool& out_is_enabled, u64 aruid, 100 Result IsUnintendedHomeButtonInputProtectionEnabled(bool& out_is_enabled, u64 aruid,
103 Core::HID::NpadIdType npad_id) const; 101 Core::HID::NpadIdType npad_id) const;
104 Result EnableUnintendedHomeButtonInputProtection(u64 aruid, Core::HID::NpadIdType npad_id, 102 Result EnableUnintendedHomeButtonInputProtection(u64 aruid, Core::HID::NpadIdType npad_id,
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index 7398ed2ec..a7400adfa 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -1431,7 +1431,8 @@ ImageId TextureCache<P>::JoinImages(const ImageInfo& info, GPUVAddr gpu_addr, DA
1431 } 1431 }
1432 } 1432 }
1433 }; 1433 };
1434 ForEachSparseImageInRegion(gpu_addr, size_bytes, region_check_gpu); 1434 ForEachSparseImageInRegion(channel_state->gpu_memory.GetID(), gpu_addr, size_bytes,
1435 region_check_gpu);
1435 1436
1436 bool can_rescale = info.rescaleable; 1437 bool can_rescale = info.rescaleable;
1437 bool any_rescaled = false; 1438 bool any_rescaled = false;
@@ -1842,7 +1843,7 @@ void TextureCache<P>::ForEachImageInRegionGPU(size_t as_id, GPUVAddr gpu_addr, s
1842 if (!storage_id) { 1843 if (!storage_id) {
1843 return; 1844 return;
1844 } 1845 }
1845 auto& gpu_page_table = gpu_page_table_storage[*storage_id]; 1846 auto& gpu_page_table = gpu_page_table_storage[*storage_id * 2];
1846 ForEachGPUPage(gpu_addr, size, 1847 ForEachGPUPage(gpu_addr, size,
1847 [this, &gpu_page_table, &images, gpu_addr, size, func](u64 page) { 1848 [this, &gpu_page_table, &images, gpu_addr, size, func](u64 page) {
1848 const auto it = gpu_page_table.find(page); 1849 const auto it = gpu_page_table.find(page);
@@ -1882,41 +1883,48 @@ void TextureCache<P>::ForEachImageInRegionGPU(size_t as_id, GPUVAddr gpu_addr, s
1882 1883
1883template <class P> 1884template <class P>
1884template <typename Func> 1885template <typename Func>
1885void TextureCache<P>::ForEachSparseImageInRegion(GPUVAddr gpu_addr, size_t size, Func&& func) { 1886void TextureCache<P>::ForEachSparseImageInRegion(size_t as_id, GPUVAddr gpu_addr, size_t size,
1887 Func&& func) {
1886 using FuncReturn = typename std::invoke_result<Func, ImageId, Image&>::type; 1888 using FuncReturn = typename std::invoke_result<Func, ImageId, Image&>::type;
1887 static constexpr bool BOOL_BREAK = std::is_same_v<FuncReturn, bool>; 1889 static constexpr bool BOOL_BREAK = std::is_same_v<FuncReturn, bool>;
1888 boost::container::small_vector<ImageId, 8> images; 1890 boost::container::small_vector<ImageId, 8> images;
1889 ForEachGPUPage(gpu_addr, size, [this, &images, gpu_addr, size, func](u64 page) { 1891 auto storage_id = getStorageID(as_id);
1890 const auto it = sparse_page_table.find(page); 1892 if (!storage_id) {
1891 if (it == sparse_page_table.end()) { 1893 return;
1892 if constexpr (BOOL_BREAK) { 1894 }
1893 return false; 1895 auto& sparse_page_table = gpu_page_table_storage[*storage_id * 2 + 1];
1894 } else { 1896 ForEachGPUPage(gpu_addr, size,
1895 return; 1897 [this, &sparse_page_table, &images, gpu_addr, size, func](u64 page) {
1896 } 1898 const auto it = sparse_page_table.find(page);
1897 } 1899 if (it == sparse_page_table.end()) {
1898 for (const ImageId image_id : it->second) { 1900 if constexpr (BOOL_BREAK) {
1899 Image& image = slot_images[image_id]; 1901 return false;
1900 if (True(image.flags & ImageFlagBits::Picked)) { 1902 } else {
1901 continue; 1903 return;
1902 } 1904 }
1903 if (!image.OverlapsGPU(gpu_addr, size)) { 1905 }
1904 continue; 1906 for (const ImageId image_id : it->second) {
1905 } 1907 Image& image = slot_images[image_id];
1906 image.flags |= ImageFlagBits::Picked; 1908 if (True(image.flags & ImageFlagBits::Picked)) {
1907 images.push_back(image_id); 1909 continue;
1908 if constexpr (BOOL_BREAK) { 1910 }
1909 if (func(image_id, image)) { 1911 if (!image.OverlapsGPU(gpu_addr, size)) {
1910 return true; 1912 continue;
1911 } 1913 }
1912 } else { 1914 image.flags |= ImageFlagBits::Picked;
1913 func(image_id, image); 1915 images.push_back(image_id);
1914 } 1916 if constexpr (BOOL_BREAK) {
1915 } 1917 if (func(image_id, image)) {
1916 if constexpr (BOOL_BREAK) { 1918 return true;
1917 return false; 1919 }
1918 } 1920 } else {
1919 }); 1921 func(image_id, image);
1922 }
1923 }
1924 if constexpr (BOOL_BREAK) {
1925 return false;
1926 }
1927 });
1920 for (const ImageId image_id : images) { 1928 for (const ImageId image_id : images) {
1921 slot_images[image_id].flags &= ~ImageFlagBits::Picked; 1929 slot_images[image_id].flags &= ~ImageFlagBits::Picked;
1922 } 1930 }
@@ -1988,8 +1996,9 @@ void TextureCache<P>::RegisterImage(ImageId image_id) {
1988 sparse_maps.push_back(map_id); 1996 sparse_maps.push_back(map_id);
1989 }); 1997 });
1990 sparse_views.emplace(image_id, std::move(sparse_maps)); 1998 sparse_views.emplace(image_id, std::move(sparse_maps));
1991 ForEachGPUPage(image.gpu_addr, image.guest_size_bytes, 1999 ForEachGPUPage(image.gpu_addr, image.guest_size_bytes, [this, image_id](u64 page) {
1992 [this, image_id](u64 page) { sparse_page_table[page].push_back(image_id); }); 2000 (*channel_state->sparse_page_table)[page].push_back(image_id);
2001 });
1993} 2002}
1994 2003
1995template <class P> 2004template <class P>
@@ -2042,7 +2051,7 @@ void TextureCache<P>::UnregisterImage(ImageId image_id) {
2042 return; 2051 return;
2043 } 2052 }
2044 ForEachGPUPage(image.gpu_addr, image.guest_size_bytes, [this, &clear_page_table](u64 page) { 2053 ForEachGPUPage(image.gpu_addr, image.guest_size_bytes, [this, &clear_page_table](u64 page) {
2045 clear_page_table(page, sparse_page_table); 2054 clear_page_table(page, (*channel_state->sparse_page_table));
2046 }); 2055 });
2047 auto it = sparse_views.find(image_id); 2056 auto it = sparse_views.find(image_id);
2048 ASSERT(it != sparse_views.end()); 2057 ASSERT(it != sparse_views.end());
@@ -2496,13 +2505,15 @@ void TextureCache<P>::CreateChannel(struct Tegra::Control::ChannelState& channel
2496 const auto it = channel_map.find(channel.bind_id); 2505 const auto it = channel_map.find(channel.bind_id);
2497 auto* this_state = &channel_storage[it->second]; 2506 auto* this_state = &channel_storage[it->second];
2498 const auto& this_as_ref = address_spaces[channel.memory_manager->GetID()]; 2507 const auto& this_as_ref = address_spaces[channel.memory_manager->GetID()];
2499 this_state->gpu_page_table = &gpu_page_table_storage[this_as_ref.storage_id]; 2508 this_state->gpu_page_table = &gpu_page_table_storage[this_as_ref.storage_id * 2];
2509 this_state->sparse_page_table = &gpu_page_table_storage[this_as_ref.storage_id * 2 + 1];
2500} 2510}
2501 2511
2502/// Bind a channel for execution. 2512/// Bind a channel for execution.
2503template <class P> 2513template <class P>
2504void TextureCache<P>::OnGPUASRegister([[maybe_unused]] size_t map_id) { 2514void TextureCache<P>::OnGPUASRegister([[maybe_unused]] size_t map_id) {
2505 gpu_page_table_storage.emplace_back(); 2515 gpu_page_table_storage.emplace_back();
2516 gpu_page_table_storage.emplace_back();
2506} 2517}
2507 2518
2508} // namespace VideoCommon 2519} // namespace VideoCommon
diff --git a/src/video_core/texture_cache/texture_cache_base.h b/src/video_core/texture_cache/texture_cache_base.h
index 8699d40d4..f9aebb293 100644
--- a/src/video_core/texture_cache/texture_cache_base.h
+++ b/src/video_core/texture_cache/texture_cache_base.h
@@ -86,6 +86,7 @@ public:
86 std::unordered_map<TSCEntry, SamplerId> samplers; 86 std::unordered_map<TSCEntry, SamplerId> samplers;
87 87
88 TextureCacheGPUMap* gpu_page_table; 88 TextureCacheGPUMap* gpu_page_table;
89 TextureCacheGPUMap* sparse_page_table;
89}; 90};
90 91
91template <class P> 92template <class P>
@@ -357,7 +358,7 @@ private:
357 void ForEachImageInRegionGPU(size_t as_id, GPUVAddr gpu_addr, size_t size, Func&& func); 358 void ForEachImageInRegionGPU(size_t as_id, GPUVAddr gpu_addr, size_t size, Func&& func);
358 359
359 template <typename Func> 360 template <typename Func>
360 void ForEachSparseImageInRegion(GPUVAddr gpu_addr, size_t size, Func&& func); 361 void ForEachSparseImageInRegion(size_t as_id, GPUVAddr gpu_addr, size_t size, Func&& func);
361 362
362 /// Iterates over all the images in a region calling func 363 /// Iterates over all the images in a region calling func
363 template <typename Func> 364 template <typename Func>
@@ -431,7 +432,6 @@ private:
431 std::unordered_map<RenderTargets, FramebufferId> framebuffers; 432 std::unordered_map<RenderTargets, FramebufferId> framebuffers;
432 433
433 std::unordered_map<u64, std::vector<ImageMapId>, Common::IdentityHash<u64>> page_table; 434 std::unordered_map<u64, std::vector<ImageMapId>, Common::IdentityHash<u64>> page_table;
434 std::unordered_map<u64, std::vector<ImageId>, Common::IdentityHash<u64>> sparse_page_table;
435 std::unordered_map<ImageId, boost::container::small_vector<ImageViewId, 16>> sparse_views; 435 std::unordered_map<ImageId, boost::container::small_vector<ImageViewId, 16>> sparse_views;
436 436
437 DAddr virtual_invalid_space{}; 437 DAddr virtual_invalid_space{};
diff --git a/src/yuzu/configuration/configure_audio.cpp b/src/yuzu/configuration/configure_audio.cpp
index 9b6ef47a7..c235b0fca 100644
--- a/src/yuzu/configuration/configure_audio.cpp
+++ b/src/yuzu/configuration/configure_audio.cpp
@@ -5,6 +5,7 @@
5#include <memory> 5#include <memory>
6#include <vector> 6#include <vector>
7#include <QComboBox> 7#include <QComboBox>
8#include <QPushButton>
8 9
9#include "audio_core/sink/sink.h" 10#include "audio_core/sink/sink.h"
10#include "audio_core/sink/sink_details.h" 11#include "audio_core/sink/sink_details.h"
@@ -67,19 +68,99 @@ void ConfigureAudio::Setup(const ConfigurationShared::Builder& builder) {
67 68
68 hold.emplace(std::pair{setting->Id(), widget}); 69 hold.emplace(std::pair{setting->Id(), widget});
69 70
71 auto global_sink_match = [this] {
72 return static_cast<Settings::AudioEngine>(sink_combo_box->currentIndex()) ==
73 Settings::values.sink_id.GetValue(true);
74 };
70 if (setting->Id() == Settings::values.sink_id.Id()) { 75 if (setting->Id() == Settings::values.sink_id.Id()) {
71 // TODO (lat9nq): Let the system manage sink_id 76 // TODO (lat9nq): Let the system manage sink_id
72 sink_combo_box = widget->combobox; 77 sink_combo_box = widget->combobox;
73 InitializeAudioSinkComboBox(); 78 InitializeAudioSinkComboBox();
74 79
75 connect(sink_combo_box, qOverload<int>(&QComboBox::currentIndexChanged), this, 80 if (Settings::IsConfiguringGlobal()) {
76 &ConfigureAudio::UpdateAudioDevices); 81 connect(sink_combo_box, qOverload<int>(&QComboBox::currentIndexChanged), this,
82 &ConfigureAudio::UpdateAudioDevices);
83 } else {
84 restore_sink_button = ConfigurationShared::Widget::CreateRestoreGlobalButton(
85 Settings::values.sink_id.UsingGlobal(), widget);
86 widget->layout()->addWidget(restore_sink_button);
87 connect(restore_sink_button, &QAbstractButton::clicked, [this](bool) {
88 Settings::values.sink_id.SetGlobal(true);
89 const int sink_index = static_cast<int>(Settings::values.sink_id.GetValue());
90 sink_combo_box->setCurrentIndex(sink_index);
91 ConfigureAudio::UpdateAudioDevices(sink_index);
92 Settings::values.audio_output_device_id.SetGlobal(true);
93 Settings::values.audio_input_device_id.SetGlobal(true);
94 restore_sink_button->setVisible(false);
95 });
96 connect(sink_combo_box, qOverload<int>(&QComboBox::currentIndexChanged),
97 [this, global_sink_match](const int slot) {
98 Settings::values.sink_id.SetGlobal(false);
99 Settings::values.audio_output_device_id.SetGlobal(false);
100 Settings::values.audio_input_device_id.SetGlobal(false);
101
102 restore_sink_button->setVisible(true);
103 restore_sink_button->setEnabled(true);
104 output_device_combo_box->setCurrentIndex(0);
105 restore_output_device_button->setVisible(true);
106 restore_output_device_button->setEnabled(global_sink_match());
107 input_device_combo_box->setCurrentIndex(0);
108 restore_input_device_button->setVisible(true);
109 restore_input_device_button->setEnabled(global_sink_match());
110 ConfigureAudio::UpdateAudioDevices(slot);
111 });
112 }
77 } else if (setting->Id() == Settings::values.audio_output_device_id.Id()) { 113 } else if (setting->Id() == Settings::values.audio_output_device_id.Id()) {
78 // Keep track of output (and input) device comboboxes to populate them with system 114 // Keep track of output (and input) device comboboxes to populate them with system
79 // devices, which are determined at run time 115 // devices, which are determined at run time
80 output_device_combo_box = widget->combobox; 116 output_device_combo_box = widget->combobox;
117
118 if (!Settings::IsConfiguringGlobal()) {
119 restore_output_device_button =
120 ConfigurationShared::Widget::CreateRestoreGlobalButton(
121 Settings::values.audio_output_device_id.UsingGlobal(), widget);
122 restore_output_device_button->setEnabled(global_sink_match());
123 restore_output_device_button->setVisible(
124 !Settings::values.audio_output_device_id.UsingGlobal());
125 widget->layout()->addWidget(restore_output_device_button);
126 connect(restore_output_device_button, &QAbstractButton::clicked, [this](bool) {
127 Settings::values.audio_output_device_id.SetGlobal(true);
128 SetOutputDevicesFromDeviceID();
129 restore_output_device_button->setVisible(false);
130 });
131 connect(output_device_combo_box, qOverload<int>(&QComboBox::currentIndexChanged),
132 [this, global_sink_match](int) {
133 if (updating_devices) {
134 return;
135 }
136 Settings::values.audio_output_device_id.SetGlobal(false);
137 restore_output_device_button->setVisible(true);
138 restore_output_device_button->setEnabled(global_sink_match());
139 });
140 }
81 } else if (setting->Id() == Settings::values.audio_input_device_id.Id()) { 141 } else if (setting->Id() == Settings::values.audio_input_device_id.Id()) {
82 input_device_combo_box = widget->combobox; 142 input_device_combo_box = widget->combobox;
143
144 if (!Settings::IsConfiguringGlobal()) {
145 restore_input_device_button =
146 ConfigurationShared::Widget::CreateRestoreGlobalButton(
147 Settings::values.audio_input_device_id.UsingGlobal(), widget);
148 widget->layout()->addWidget(restore_input_device_button);
149 connect(restore_input_device_button, &QAbstractButton::clicked, [this](bool) {
150 Settings::values.audio_input_device_id.SetGlobal(true);
151 SetInputDevicesFromDeviceID();
152 restore_input_device_button->setVisible(false);
153 });
154 connect(input_device_combo_box, qOverload<int>(&QComboBox::currentIndexChanged),
155 [this, global_sink_match](int) {
156 if (updating_devices) {
157 return;
158 }
159 Settings::values.audio_input_device_id.SetGlobal(false);
160 restore_input_device_button->setVisible(true);
161 restore_input_device_button->setEnabled(global_sink_match());
162 });
163 }
83 } 164 }
84 } 165 }
85 166
@@ -89,16 +170,13 @@ void ConfigureAudio::Setup(const ConfigurationShared::Builder& builder) {
89} 170}
90 171
91void ConfigureAudio::SetConfiguration() { 172void ConfigureAudio::SetConfiguration() {
92 if (!Settings::IsConfiguringGlobal()) {
93 return;
94 }
95
96 SetOutputSinkFromSinkID(); 173 SetOutputSinkFromSinkID();
97 174
98 // The device list cannot be pre-populated (nor listed) until the output sink is known. 175 // The device list cannot be pre-populated (nor listed) until the output sink is known.
99 UpdateAudioDevices(sink_combo_box->currentIndex()); 176 UpdateAudioDevices(sink_combo_box->currentIndex());
100 177
101 SetAudioDevicesFromDeviceID(); 178 SetOutputDevicesFromDeviceID();
179 SetInputDevicesFromDeviceID();
102} 180}
103 181
104void ConfigureAudio::SetOutputSinkFromSinkID() { 182void ConfigureAudio::SetOutputSinkFromSinkID() {
@@ -116,8 +194,8 @@ void ConfigureAudio::SetOutputSinkFromSinkID() {
116 sink_combo_box->setCurrentIndex(new_sink_index); 194 sink_combo_box->setCurrentIndex(new_sink_index);
117} 195}
118 196
119void ConfigureAudio::SetAudioDevicesFromDeviceID() { 197void ConfigureAudio::SetOutputDevicesFromDeviceID() {
120 int new_device_index = -1; 198 int new_device_index = 0;
121 199
122 const QString output_device_id = 200 const QString output_device_id =
123 QString::fromStdString(Settings::values.audio_output_device_id.GetValue()); 201 QString::fromStdString(Settings::values.audio_output_device_id.GetValue());
@@ -129,8 +207,10 @@ void ConfigureAudio::SetAudioDevicesFromDeviceID() {
129 } 207 }
130 208
131 output_device_combo_box->setCurrentIndex(new_device_index); 209 output_device_combo_box->setCurrentIndex(new_device_index);
210}
132 211
133 new_device_index = -1; 212void ConfigureAudio::SetInputDevicesFromDeviceID() {
213 int new_device_index = 0;
134 const QString input_device_id = 214 const QString input_device_id =
135 QString::fromStdString(Settings::values.audio_input_device_id.GetValue()); 215 QString::fromStdString(Settings::values.audio_input_device_id.GetValue());
136 for (int index = 0; index < input_device_combo_box->count(); index++) { 216 for (int index = 0; index < input_device_combo_box->count(); index++) {
@@ -149,15 +229,12 @@ void ConfigureAudio::ApplyConfiguration() {
149 apply_func(is_powered_on); 229 apply_func(is_powered_on);
150 } 230 }
151 231
152 if (Settings::IsConfiguringGlobal()) { 232 Settings::values.sink_id.LoadString(
153 Settings::values.sink_id.LoadString( 233 sink_combo_box->itemText(sink_combo_box->currentIndex()).toStdString());
154 sink_combo_box->itemText(sink_combo_box->currentIndex()).toStdString()); 234 Settings::values.audio_output_device_id.SetValue(
155 Settings::values.audio_output_device_id.SetValue( 235 output_device_combo_box->itemText(output_device_combo_box->currentIndex()).toStdString());
156 output_device_combo_box->itemText(output_device_combo_box->currentIndex()) 236 Settings::values.audio_input_device_id.SetValue(
157 .toStdString()); 237 input_device_combo_box->itemText(input_device_combo_box->currentIndex()).toStdString());
158 Settings::values.audio_input_device_id.SetValue(
159 input_device_combo_box->itemText(input_device_combo_box->currentIndex()).toStdString());
160 }
161} 238}
162 239
163void ConfigureAudio::changeEvent(QEvent* event) { 240void ConfigureAudio::changeEvent(QEvent* event) {
@@ -169,6 +246,7 @@ void ConfigureAudio::changeEvent(QEvent* event) {
169} 246}
170 247
171void ConfigureAudio::UpdateAudioDevices(int sink_index) { 248void ConfigureAudio::UpdateAudioDevices(int sink_index) {
249 updating_devices = true;
172 output_device_combo_box->clear(); 250 output_device_combo_box->clear();
173 output_device_combo_box->addItem(QString::fromUtf8(AudioCore::Sink::auto_device_name)); 251 output_device_combo_box->addItem(QString::fromUtf8(AudioCore::Sink::auto_device_name));
174 252
@@ -183,6 +261,7 @@ void ConfigureAudio::UpdateAudioDevices(int sink_index) {
183 for (const auto& device : AudioCore::Sink::GetDeviceListForSink(sink_id, true)) { 261 for (const auto& device : AudioCore::Sink::GetDeviceListForSink(sink_id, true)) {
184 input_device_combo_box->addItem(QString::fromStdString(device)); 262 input_device_combo_box->addItem(QString::fromStdString(device));
185 } 263 }
264 updating_devices = false;
186} 265}
187 266
188void ConfigureAudio::InitializeAudioSinkComboBox() { 267void ConfigureAudio::InitializeAudioSinkComboBox() {
diff --git a/src/yuzu/configuration/configure_audio.h b/src/yuzu/configuration/configure_audio.h
index 82d7f6524..32a2fa5f0 100644
--- a/src/yuzu/configuration/configure_audio.h
+++ b/src/yuzu/configuration/configure_audio.h
@@ -45,7 +45,8 @@ private:
45 void UpdateAudioDevices(int sink_index); 45 void UpdateAudioDevices(int sink_index);
46 46
47 void SetOutputSinkFromSinkID(); 47 void SetOutputSinkFromSinkID();
48 void SetAudioDevicesFromDeviceID(); 48 void SetOutputDevicesFromDeviceID();
49 void SetInputDevicesFromDeviceID();
49 50
50 void Setup(const ConfigurationShared::Builder& builder); 51 void Setup(const ConfigurationShared::Builder& builder);
51 52
@@ -55,7 +56,11 @@ private:
55 56
56 std::vector<std::function<void(bool)>> apply_funcs{}; 57 std::vector<std::function<void(bool)>> apply_funcs{};
57 58
59 bool updating_devices = false;
58 QComboBox* sink_combo_box; 60 QComboBox* sink_combo_box;
61 QPushButton* restore_sink_button;
59 QComboBox* output_device_combo_box; 62 QComboBox* output_device_combo_box;
63 QPushButton* restore_output_device_button;
60 QComboBox* input_device_combo_box; 64 QComboBox* input_device_combo_box;
65 QPushButton* restore_input_device_button;
61}; 66};