summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/audio_core/renderer/command/command_generator.cpp2
-rw-r--r--src/audio_core/renderer/command/effect/aux_.cpp130
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/hle/kernel/init/init_slab_setup.cpp2
-rw-r--r--src/core/hle/kernel/k_object_name.cpp102
-rw-r--r--src/core/hle/kernel/k_object_name.h86
-rw-r--r--src/core/hle/kernel/kernel.cpp14
-rw-r--r--src/core/hle/kernel/kernel.h8
-rw-r--r--src/core/hle/kernel/svc/svc_port.cpp54
-rw-r--r--src/video_core/engines/maxwell_3d.cpp4
-rw-r--r--src/video_core/host1x/codecs/codec.cpp2
-rw-r--r--src/yuzu/configuration/config.cpp1
-rw-r--r--src/yuzu/game_list.cpp1
-rw-r--r--src/yuzu/game_list.h1
-rw-r--r--src/yuzu/main.cpp10
15 files changed, 374 insertions, 45 deletions
diff --git a/src/audio_core/renderer/command/command_generator.cpp b/src/audio_core/renderer/command/command_generator.cpp
index 2ea50d128..fba84c7bd 100644
--- a/src/audio_core/renderer/command/command_generator.cpp
+++ b/src/audio_core/renderer/command/command_generator.cpp
@@ -46,7 +46,7 @@ void CommandGenerator::GenerateDataSourceCommand(VoiceInfo& voice_info,
46 while (destination != nullptr) { 46 while (destination != nullptr) {
47 if (destination->IsConfigured()) { 47 if (destination->IsConfigured()) {
48 auto mix_id{destination->GetMixId()}; 48 auto mix_id{destination->GetMixId()};
49 if (mix_id < mix_context.GetCount()) { 49 if (mix_id < mix_context.GetCount() && mix_id != UnusedSplitterId) {
50 auto mix_info{mix_context.GetInfo(mix_id)}; 50 auto mix_info{mix_context.GetInfo(mix_id)};
51 command_buffer.GenerateDepopPrepareCommand( 51 command_buffer.GenerateDepopPrepareCommand(
52 voice_info.node_id, voice_state, render_context.depop_buffer, 52 voice_info.node_id, voice_state, render_context.depop_buffer,
diff --git a/src/audio_core/renderer/command/effect/aux_.cpp b/src/audio_core/renderer/command/effect/aux_.cpp
index e76db893f..c5650effa 100644
--- a/src/audio_core/renderer/command/effect/aux_.cpp
+++ b/src/audio_core/renderer/command/effect/aux_.cpp
@@ -4,6 +4,7 @@
4#include "audio_core/renderer/adsp/command_list_processor.h" 4#include "audio_core/renderer/adsp/command_list_processor.h"
5#include "audio_core/renderer/command/effect/aux_.h" 5#include "audio_core/renderer/command/effect/aux_.h"
6#include "audio_core/renderer/effect/aux_.h" 6#include "audio_core/renderer/effect/aux_.h"
7#include "core/core.h"
7#include "core/memory.h" 8#include "core/memory.h"
8 9
9namespace AudioCore::AudioRenderer { 10namespace AudioCore::AudioRenderer {
@@ -19,10 +20,24 @@ static void ResetAuxBufferDsp(Core::Memory::Memory& memory, const CpuAddr aux_in
19 return; 20 return;
20 } 21 }
21 22
22 auto info{reinterpret_cast<AuxInfo::AuxInfoDsp*>(memory.GetPointer(aux_info))}; 23 AuxInfo::AuxInfoDsp info{};
23 info->read_offset = 0; 24 auto info_ptr{&info};
24 info->write_offset = 0; 25 bool host_safe{(aux_info & Core::Memory::YUZU_PAGEMASK) <=
25 info->total_sample_count = 0; 26 (Core::Memory::YUZU_PAGESIZE - sizeof(AuxInfo::AuxInfoDsp))};
27
28 if (host_safe) [[likely]] {
29 info_ptr = memory.GetPointer<AuxInfo::AuxInfoDsp>(aux_info);
30 } else {
31 memory.ReadBlockUnsafe(aux_info, info_ptr, sizeof(AuxInfo::AuxInfoDsp));
32 }
33
34 info_ptr->read_offset = 0;
35 info_ptr->write_offset = 0;
36 info_ptr->total_sample_count = 0;
37
38 if (!host_safe) [[unlikely]] {
39 memory.WriteBlockUnsafe(aux_info, info_ptr, sizeof(AuxInfo::AuxInfoDsp));
40 }
26} 41}
27 42
28/** 43/**
@@ -40,11 +55,10 @@ static void ResetAuxBufferDsp(Core::Memory::Memory& memory, const CpuAddr aux_in
40 * @param update_count - If non-zero, send_info_ will be updated. 55 * @param update_count - If non-zero, send_info_ will be updated.
41 * @return Number of samples written. 56 * @return Number of samples written.
42 */ 57 */
43static u32 WriteAuxBufferDsp(Core::Memory::Memory& memory, const CpuAddr send_info_, 58static u32 WriteAuxBufferDsp(Core::Memory::Memory& memory, CpuAddr send_info_,
44 [[maybe_unused]] u32 sample_count, const CpuAddr send_buffer, 59 [[maybe_unused]] u32 sample_count, CpuAddr send_buffer, u32 count_max,
45 const u32 count_max, std::span<const s32> input, 60 std::span<const s32> input, u32 write_count_, u32 write_offset,
46 const u32 write_count_, const u32 write_offset, 61 u32 update_count) {
47 const u32 update_count) {
48 if (write_count_ > count_max) { 62 if (write_count_ > count_max) {
49 LOG_ERROR(Service_Audio, 63 LOG_ERROR(Service_Audio,
50 "write_count must be smaller than count_max! write_count {}, count_max {}", 64 "write_count must be smaller than count_max! write_count {}, count_max {}",
@@ -52,6 +66,11 @@ static u32 WriteAuxBufferDsp(Core::Memory::Memory& memory, const CpuAddr send_in
52 return 0; 66 return 0;
53 } 67 }
54 68
69 if (send_info_ == 0) {
70 LOG_ERROR(Service_Audio, "send_info_ is 0!");
71 return 0;
72 }
73
55 if (input.empty()) { 74 if (input.empty()) {
56 LOG_ERROR(Service_Audio, "input buffer is empty!"); 75 LOG_ERROR(Service_Audio, "input buffer is empty!");
57 return 0; 76 return 0;
@@ -67,33 +86,47 @@ static u32 WriteAuxBufferDsp(Core::Memory::Memory& memory, const CpuAddr send_in
67 } 86 }
68 87
69 AuxInfo::AuxInfoDsp send_info{}; 88 AuxInfo::AuxInfoDsp send_info{};
70 memory.ReadBlockUnsafe(send_info_, &send_info, sizeof(AuxInfo::AuxInfoDsp)); 89 auto send_ptr = &send_info;
90 bool host_safe = (send_info_ & Core::Memory::YUZU_PAGEMASK) <=
91 (Core::Memory::YUZU_PAGESIZE - sizeof(AuxInfo::AuxInfoDsp));
71 92
72 u32 target_write_offset{send_info.write_offset + write_offset}; 93 if (host_safe) [[likely]] {
73 if (target_write_offset > count_max || write_count_ == 0) { 94 send_ptr = memory.GetPointer<AuxInfo::AuxInfoDsp>(send_info_);
95 } else {
96 memory.ReadBlockUnsafe(send_info_, send_ptr, sizeof(AuxInfo::AuxInfoDsp));
97 }
98
99 u32 target_write_offset{send_ptr->write_offset + write_offset};
100 if (target_write_offset > count_max) {
74 return 0; 101 return 0;
75 } 102 }
76 103
77 u32 write_count{write_count_}; 104 u32 write_count{write_count_};
78 u32 write_pos{0}; 105 u32 read_pos{0};
79 while (write_count > 0) { 106 while (write_count > 0) {
80 u32 to_write{std::min(count_max - target_write_offset, write_count)}; 107 u32 to_write{std::min(count_max - target_write_offset, write_count)};
81 108 const auto write_addr = send_buffer + target_write_offset * sizeof(s32);
82 if (to_write > 0) { 109 bool write_safe{(write_addr & Core::Memory::YUZU_PAGEMASK) <=
110 (Core::Memory::YUZU_PAGESIZE - (write_addr + to_write * sizeof(s32)))};
111 if (write_safe) [[likely]] {
112 auto ptr = memory.GetPointer(write_addr);
113 std::memcpy(ptr, &input[read_pos], to_write * sizeof(s32));
114 } else {
83 memory.WriteBlockUnsafe(send_buffer + target_write_offset * sizeof(s32), 115 memory.WriteBlockUnsafe(send_buffer + target_write_offset * sizeof(s32),
84 &input[write_pos], to_write * sizeof(s32)); 116 &input[read_pos], to_write * sizeof(s32));
85 } 117 }
86
87 target_write_offset = (target_write_offset + to_write) % count_max; 118 target_write_offset = (target_write_offset + to_write) % count_max;
88 write_count -= to_write; 119 write_count -= to_write;
89 write_pos += to_write; 120 read_pos += to_write;
90 } 121 }
91 122
92 if (update_count) { 123 if (update_count) {
93 send_info.write_offset = (send_info.write_offset + update_count) % count_max; 124 send_ptr->write_offset = (send_ptr->write_offset + update_count) % count_max;
94 } 125 }
95 126
96 memory.WriteBlockUnsafe(send_info_, &send_info, sizeof(AuxInfo::AuxInfoDsp)); 127 if (!host_safe) [[unlikely]] {
128 memory.WriteBlockUnsafe(send_info_, send_ptr, sizeof(AuxInfo::AuxInfoDsp));
129 }
97 130
98 return write_count_; 131 return write_count_;
99} 132}
@@ -102,7 +135,7 @@ static u32 WriteAuxBufferDsp(Core::Memory::Memory& memory, const CpuAddr send_in
102 * Read the given memory at return_buffer into the output mix buffer, and update return_info_ if 135 * Read the given memory at return_buffer into the output mix buffer, and update return_info_ if
103 * update_count is set, to notify the game that an update happened. 136 * update_count is set, to notify the game that an update happened.
104 * 137 *
105 * @param memory - Core memory for writing. 138 * @param memory - Core memory for reading.
106 * @param return_info_ - Meta information for where to read the mix buffer. 139 * @param return_info_ - Meta information for where to read the mix buffer.
107 * @param return_buffer - Memory address to read the samples from. 140 * @param return_buffer - Memory address to read the samples from.
108 * @param count_max - Maximum number of samples in the receiving buffer. 141 * @param count_max - Maximum number of samples in the receiving buffer.
@@ -112,16 +145,21 @@ static u32 WriteAuxBufferDsp(Core::Memory::Memory& memory, const CpuAddr send_in
112 * @param update_count - If non-zero, send_info_ will be updated. 145 * @param update_count - If non-zero, send_info_ will be updated.
113 * @return Number of samples read. 146 * @return Number of samples read.
114 */ 147 */
115static u32 ReadAuxBufferDsp(Core::Memory::Memory& memory, const CpuAddr return_info_, 148static u32 ReadAuxBufferDsp(Core::Memory::Memory& memory, CpuAddr return_info_,
116 const CpuAddr return_buffer, const u32 count_max, std::span<s32> output, 149 CpuAddr return_buffer, u32 count_max, std::span<s32> output,
117 const u32 count_, const u32 read_offset, const u32 update_count) { 150 u32 read_count_, u32 read_offset, u32 update_count) {
118 if (count_max == 0) { 151 if (count_max == 0) {
119 return 0; 152 return 0;
120 } 153 }
121 154
122 if (count_ > count_max) { 155 if (read_count_ > count_max) {
123 LOG_ERROR(Service_Audio, "count must be smaller than count_max! count {}, count_max {}", 156 LOG_ERROR(Service_Audio, "count must be smaller than count_max! count {}, count_max {}",
124 count_, count_max); 157 read_count_, count_max);
158 return 0;
159 }
160
161 if (return_info_ == 0) {
162 LOG_ERROR(Service_Audio, "return_info_ is 0!");
125 return 0; 163 return 0;
126 } 164 }
127 165
@@ -136,35 +174,49 @@ static u32 ReadAuxBufferDsp(Core::Memory::Memory& memory, const CpuAddr return_i
136 } 174 }
137 175
138 AuxInfo::AuxInfoDsp return_info{}; 176 AuxInfo::AuxInfoDsp return_info{};
139 memory.ReadBlockUnsafe(return_info_, &return_info, sizeof(AuxInfo::AuxInfoDsp)); 177 auto return_ptr = &return_info;
178 bool host_safe = (return_info_ & Core::Memory::YUZU_PAGEMASK) <=
179 (Core::Memory::YUZU_PAGESIZE - sizeof(AuxInfo::AuxInfoDsp));
180
181 if (host_safe) [[likely]] {
182 return_ptr = memory.GetPointer<AuxInfo::AuxInfoDsp>(return_info_);
183 } else {
184 memory.ReadBlockUnsafe(return_info_, return_ptr, sizeof(AuxInfo::AuxInfoDsp));
185 }
140 186
141 u32 target_read_offset{return_info.read_offset + read_offset}; 187 u32 target_read_offset{return_ptr->read_offset + read_offset};
142 if (target_read_offset > count_max) { 188 if (target_read_offset > count_max) {
143 return 0; 189 return 0;
144 } 190 }
145 191
146 u32 read_count{count_}; 192 u32 read_count{read_count_};
147 u32 read_pos{0}; 193 u32 write_pos{0};
148 while (read_count > 0) { 194 while (read_count > 0) {
149 u32 to_read{std::min(count_max - target_read_offset, read_count)}; 195 u32 to_read{std::min(count_max - target_read_offset, read_count)};
150 196 const auto read_addr = return_buffer + target_read_offset * sizeof(s32);
151 if (to_read > 0) { 197 bool read_safe{(read_addr & Core::Memory::YUZU_PAGEMASK) <=
198 (Core::Memory::YUZU_PAGESIZE - (read_addr + to_read * sizeof(s32)))};
199 if (read_safe) [[likely]] {
200 auto ptr = memory.GetPointer(read_addr);
201 std::memcpy(&output[write_pos], ptr, to_read * sizeof(s32));
202 } else {
152 memory.ReadBlockUnsafe(return_buffer + target_read_offset * sizeof(s32), 203 memory.ReadBlockUnsafe(return_buffer + target_read_offset * sizeof(s32),
153 &output[read_pos], to_read * sizeof(s32)); 204 &output[write_pos], to_read * sizeof(s32));
154 } 205 }
155
156 target_read_offset = (target_read_offset + to_read) % count_max; 206 target_read_offset = (target_read_offset + to_read) % count_max;
157 read_count -= to_read; 207 read_count -= to_read;
158 read_pos += to_read; 208 write_pos += to_read;
159 } 209 }
160 210
161 if (update_count) { 211 if (update_count) {
162 return_info.read_offset = (return_info.read_offset + update_count) % count_max; 212 return_ptr->read_offset = (return_ptr->read_offset + update_count) % count_max;
163 } 213 }
164 214
165 memory.WriteBlockUnsafe(return_info_, &return_info, sizeof(AuxInfo::AuxInfoDsp)); 215 if (!host_safe) [[unlikely]] {
216 memory.WriteBlockUnsafe(return_info_, return_ptr, sizeof(AuxInfo::AuxInfoDsp));
217 }
166 218
167 return count_; 219 return read_count_;
168} 220}
169 221
170void AuxCommand::Dump([[maybe_unused]] const ADSP::CommandListProcessor& processor, 222void AuxCommand::Dump([[maybe_unused]] const ADSP::CommandListProcessor& processor,
@@ -189,7 +241,7 @@ void AuxCommand::Process(const ADSP::CommandListProcessor& processor) {
189 update_count)}; 241 update_count)};
190 242
191 if (read != processor.sample_count) { 243 if (read != processor.sample_count) {
192 std::memset(&output_buffer[read], 0, processor.sample_count - read); 244 std::memset(&output_buffer[read], 0, (processor.sample_count - read) * sizeof(s32));
193 } 245 }
194 } else { 246 } else {
195 ResetAuxBufferDsp(*processor.memory, send_buffer_info); 247 ResetAuxBufferDsp(*processor.memory, send_buffer_info);
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 16ced4595..ff5502d87 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -225,6 +225,8 @@ add_library(core STATIC
225 hle/kernel/k_memory_manager.h 225 hle/kernel/k_memory_manager.h
226 hle/kernel/k_memory_region.h 226 hle/kernel/k_memory_region.h
227 hle/kernel/k_memory_region_type.h 227 hle/kernel/k_memory_region_type.h
228 hle/kernel/k_object_name.cpp
229 hle/kernel/k_object_name.h
228 hle/kernel/k_page_bitmap.h 230 hle/kernel/k_page_bitmap.h
229 hle/kernel/k_page_buffer.cpp 231 hle/kernel/k_page_buffer.cpp
230 hle/kernel/k_page_buffer.h 232 hle/kernel/k_page_buffer.h
diff --git a/src/core/hle/kernel/init/init_slab_setup.cpp b/src/core/hle/kernel/init/init_slab_setup.cpp
index 571acf4b2..abdb5639f 100644
--- a/src/core/hle/kernel/init/init_slab_setup.cpp
+++ b/src/core/hle/kernel/init/init_slab_setup.cpp
@@ -16,6 +16,7 @@
16#include "core/hle/kernel/k_event_info.h" 16#include "core/hle/kernel/k_event_info.h"
17#include "core/hle/kernel/k_memory_layout.h" 17#include "core/hle/kernel/k_memory_layout.h"
18#include "core/hle/kernel/k_memory_manager.h" 18#include "core/hle/kernel/k_memory_manager.h"
19#include "core/hle/kernel/k_object_name.h"
19#include "core/hle/kernel/k_page_buffer.h" 20#include "core/hle/kernel/k_page_buffer.h"
20#include "core/hle/kernel/k_port.h" 21#include "core/hle/kernel/k_port.h"
21#include "core/hle/kernel/k_process.h" 22#include "core/hle/kernel/k_process.h"
@@ -49,6 +50,7 @@ namespace Kernel::Init {
49 HANDLER(KThreadLocalPage, \ 50 HANDLER(KThreadLocalPage, \
50 (SLAB_COUNT(KProcess) + (SLAB_COUNT(KProcess) + SLAB_COUNT(KThread)) / 8), \ 51 (SLAB_COUNT(KProcess) + (SLAB_COUNT(KProcess) + SLAB_COUNT(KThread)) / 8), \
51 ##__VA_ARGS__) \ 52 ##__VA_ARGS__) \
53 HANDLER(KObjectName, (SLAB_COUNT(KObjectName)), ##__VA_ARGS__) \
52 HANDLER(KResourceLimit, (SLAB_COUNT(KResourceLimit)), ##__VA_ARGS__) \ 54 HANDLER(KResourceLimit, (SLAB_COUNT(KResourceLimit)), ##__VA_ARGS__) \
53 HANDLER(KEventInfo, (SLAB_COUNT(KThread) + SLAB_COUNT(KDebug)), ##__VA_ARGS__) \ 55 HANDLER(KEventInfo, (SLAB_COUNT(KThread) + SLAB_COUNT(KDebug)), ##__VA_ARGS__) \
54 HANDLER(KDebug, (SLAB_COUNT(KDebug)), ##__VA_ARGS__) \ 56 HANDLER(KDebug, (SLAB_COUNT(KDebug)), ##__VA_ARGS__) \
diff --git a/src/core/hle/kernel/k_object_name.cpp b/src/core/hle/kernel/k_object_name.cpp
new file mode 100644
index 000000000..df3a1c4c5
--- /dev/null
+++ b/src/core/hle/kernel/k_object_name.cpp
@@ -0,0 +1,102 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "core/hle/kernel/k_object_name.h"
5
6namespace Kernel {
7
8KObjectNameGlobalData::KObjectNameGlobalData(KernelCore& kernel) : m_object_list_lock{kernel} {}
9KObjectNameGlobalData::~KObjectNameGlobalData() = default;
10
11void KObjectName::Initialize(KAutoObject* obj, const char* name) {
12 // Set member variables.
13 m_object = obj;
14 std::strncpy(m_name.data(), name, sizeof(m_name) - 1);
15 m_name[sizeof(m_name) - 1] = '\x00';
16
17 // Open a reference to the object we hold.
18 m_object->Open();
19}
20
21bool KObjectName::MatchesName(const char* name) const {
22 return std::strncmp(m_name.data(), name, sizeof(m_name)) == 0;
23}
24
25Result KObjectName::NewFromName(KernelCore& kernel, KAutoObject* obj, const char* name) {
26 // Create a new object name.
27 KObjectName* new_name = KObjectName::Allocate(kernel);
28 R_UNLESS(new_name != nullptr, ResultOutOfResource);
29
30 // Initialize the new name.
31 new_name->Initialize(obj, name);
32
33 // Check if there's an existing name.
34 {
35 // Get the global data.
36 KObjectNameGlobalData& gd{kernel.ObjectNameGlobalData()};
37
38 // Ensure we have exclusive access to the global list.
39 KScopedLightLock lk{gd.GetObjectListLock()};
40
41 // If the object doesn't exist, put it into the list.
42 KScopedAutoObject existing_object = FindImpl(kernel, name);
43 if (existing_object.IsNull()) {
44 gd.GetObjectList().push_back(*new_name);
45 R_SUCCEED();
46 }
47 }
48
49 // The object already exists, which is an error condition. Perform cleanup.
50 obj->Close();
51 KObjectName::Free(kernel, new_name);
52 R_THROW(ResultInvalidState);
53}
54
55Result KObjectName::Delete(KernelCore& kernel, KAutoObject* obj, const char* compare_name) {
56 // Get the global data.
57 KObjectNameGlobalData& gd{kernel.ObjectNameGlobalData()};
58
59 // Ensure we have exclusive access to the global list.
60 KScopedLightLock lk{gd.GetObjectListLock()};
61
62 // Find a matching entry in the list, and delete it.
63 for (auto& name : gd.GetObjectList()) {
64 if (name.MatchesName(compare_name) && obj == name.GetObject()) {
65 // We found a match, clean up its resources.
66 obj->Close();
67 gd.GetObjectList().erase(gd.GetObjectList().iterator_to(name));
68 KObjectName::Free(kernel, std::addressof(name));
69 R_SUCCEED();
70 }
71 }
72
73 // We didn't find the object in the list.
74 R_THROW(ResultNotFound);
75}
76
77KScopedAutoObject<KAutoObject> KObjectName::Find(KernelCore& kernel, const char* name) {
78 // Get the global data.
79 KObjectNameGlobalData& gd{kernel.ObjectNameGlobalData()};
80
81 // Ensure we have exclusive access to the global list.
82 KScopedLightLock lk{gd.GetObjectListLock()};
83
84 return FindImpl(kernel, name);
85}
86
87KScopedAutoObject<KAutoObject> KObjectName::FindImpl(KernelCore& kernel, const char* compare_name) {
88 // Get the global data.
89 KObjectNameGlobalData& gd{kernel.ObjectNameGlobalData()};
90
91 // Try to find a matching object in the global list.
92 for (const auto& name : gd.GetObjectList()) {
93 if (name.MatchesName(compare_name)) {
94 return name.GetObject();
95 }
96 }
97
98 // There's no matching entry in the list.
99 return nullptr;
100}
101
102} // namespace Kernel
diff --git a/src/core/hle/kernel/k_object_name.h b/src/core/hle/kernel/k_object_name.h
new file mode 100644
index 000000000..b7f943134
--- /dev/null
+++ b/src/core/hle/kernel/k_object_name.h
@@ -0,0 +1,86 @@
1// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <array>
7#include <memory>
8#include <boost/intrusive/list.hpp>
9
10#include "core/hle/kernel/k_light_lock.h"
11#include "core/hle/kernel/slab_helpers.h"
12#include "core/hle/kernel/svc_results.h"
13
14namespace Kernel {
15
16class KObjectNameGlobalData;
17
18class KObjectName : public KSlabAllocated<KObjectName>, public boost::intrusive::list_base_hook<> {
19public:
20 explicit KObjectName(KernelCore&) {}
21 virtual ~KObjectName() = default;
22
23 static constexpr size_t NameLengthMax = 12;
24 using List = boost::intrusive::list<KObjectName>;
25
26 static Result NewFromName(KernelCore& kernel, KAutoObject* obj, const char* name);
27 static Result Delete(KernelCore& kernel, KAutoObject* obj, const char* name);
28
29 static KScopedAutoObject<KAutoObject> Find(KernelCore& kernel, const char* name);
30
31 template <typename Derived>
32 static Result Delete(KernelCore& kernel, const char* name) {
33 // Find the object.
34 KScopedAutoObject obj = Find(kernel, name);
35 R_UNLESS(obj.IsNotNull(), ResultNotFound);
36
37 // Cast the object to the desired type.
38 Derived* derived = obj->DynamicCast<Derived*>();
39 R_UNLESS(derived != nullptr, ResultNotFound);
40
41 // Check that the object is closed.
42 R_UNLESS(derived->IsServerClosed(), ResultInvalidState);
43
44 return Delete(kernel, obj.GetPointerUnsafe(), name);
45 }
46
47 template <typename Derived>
48 requires(std::derived_from<Derived, KAutoObject>)
49 static KScopedAutoObject<Derived> Find(KernelCore& kernel, const char* name) {
50 return Find(kernel, name);
51 }
52
53private:
54 static KScopedAutoObject<KAutoObject> FindImpl(KernelCore& kernel, const char* name);
55
56 void Initialize(KAutoObject* obj, const char* name);
57
58 bool MatchesName(const char* name) const;
59 KAutoObject* GetObject() const {
60 return m_object;
61 }
62
63private:
64 std::array<char, NameLengthMax> m_name{};
65 KAutoObject* m_object{};
66};
67
68class KObjectNameGlobalData {
69public:
70 explicit KObjectNameGlobalData(KernelCore& kernel);
71 ~KObjectNameGlobalData();
72
73 KLightLock& GetObjectListLock() {
74 return m_object_list_lock;
75 }
76
77 KObjectName::List& GetObjectList() {
78 return m_object_list;
79 }
80
81private:
82 KLightLock m_object_list_lock;
83 KObjectName::List m_object_list;
84};
85
86} // namespace Kernel
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index b1922659d..3a68a5633 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -29,6 +29,7 @@
29#include "core/hle/kernel/k_hardware_timer.h" 29#include "core/hle/kernel/k_hardware_timer.h"
30#include "core/hle/kernel/k_memory_layout.h" 30#include "core/hle/kernel/k_memory_layout.h"
31#include "core/hle/kernel/k_memory_manager.h" 31#include "core/hle/kernel/k_memory_manager.h"
32#include "core/hle/kernel/k_object_name.h"
32#include "core/hle/kernel/k_page_buffer.h" 33#include "core/hle/kernel/k_page_buffer.h"
33#include "core/hle/kernel/k_process.h" 34#include "core/hle/kernel/k_process.h"
34#include "core/hle/kernel/k_resource_limit.h" 35#include "core/hle/kernel/k_resource_limit.h"
@@ -84,6 +85,7 @@ struct KernelCore::Impl {
84 InitializeShutdownThreads(); 85 InitializeShutdownThreads();
85 InitializePhysicalCores(); 86 InitializePhysicalCores();
86 InitializePreemption(kernel); 87 InitializePreemption(kernel);
88 InitializeGlobalData(kernel);
87 89
88 // Initialize the Dynamic Slab Heaps. 90 // Initialize the Dynamic Slab Heaps.
89 { 91 {
@@ -194,6 +196,8 @@ struct KernelCore::Impl {
194 } 196 }
195 } 197 }
196 198
199 object_name_global_data.reset();
200
197 // Ensure that the object list container is finalized and properly shutdown. 201 // Ensure that the object list container is finalized and properly shutdown.
198 global_object_list_container->Finalize(); 202 global_object_list_container->Finalize();
199 global_object_list_container.reset(); 203 global_object_list_container.reset();
@@ -363,6 +367,10 @@ struct KernelCore::Impl {
363 } 367 }
364 } 368 }
365 369
370 void InitializeGlobalData(KernelCore& kernel) {
371 object_name_global_data = std::make_unique<KObjectNameGlobalData>(kernel);
372 }
373
366 void MakeApplicationProcess(KProcess* process) { 374 void MakeApplicationProcess(KProcess* process) {
367 application_process = process; 375 application_process = process;
368 } 376 }
@@ -838,6 +846,8 @@ struct KernelCore::Impl {
838 846
839 std::unique_ptr<KAutoObjectWithListContainer> global_object_list_container; 847 std::unique_ptr<KAutoObjectWithListContainer> global_object_list_container;
840 848
849 std::unique_ptr<KObjectNameGlobalData> object_name_global_data;
850
841 /// Map of named ports managed by the kernel, which can be retrieved using 851 /// Map of named ports managed by the kernel, which can be retrieved using
842 /// the ConnectToPort SVC. 852 /// the ConnectToPort SVC.
843 std::unordered_map<std::string, ServiceInterfaceFactory> service_interface_factory; 853 std::unordered_map<std::string, ServiceInterfaceFactory> service_interface_factory;
@@ -1138,6 +1148,10 @@ void KernelCore::SetCurrentEmuThread(KThread* thread) {
1138 impl->SetCurrentEmuThread(thread); 1148 impl->SetCurrentEmuThread(thread);
1139} 1149}
1140 1150
1151KObjectNameGlobalData& KernelCore::ObjectNameGlobalData() {
1152 return *impl->object_name_global_data;
1153}
1154
1141KMemoryManager& KernelCore::MemoryManager() { 1155KMemoryManager& KernelCore::MemoryManager() {
1142 return *impl->memory_manager; 1156 return *impl->memory_manager;
1143} 1157}
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index a236e6b42..6e0668f7f 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -44,6 +44,8 @@ class KHardwareTimer;
44class KLinkedListNode; 44class KLinkedListNode;
45class KMemoryLayout; 45class KMemoryLayout;
46class KMemoryManager; 46class KMemoryManager;
47class KObjectName;
48class KObjectNameGlobalData;
47class KPageBuffer; 49class KPageBuffer;
48class KPageBufferSlabHeap; 50class KPageBufferSlabHeap;
49class KPort; 51class KPort;
@@ -240,6 +242,9 @@ public:
240 /// Register the current thread as a non CPU core thread. 242 /// Register the current thread as a non CPU core thread.
241 void RegisterHostThread(KThread* existing_thread = nullptr); 243 void RegisterHostThread(KThread* existing_thread = nullptr);
242 244
245 /// Gets global data for KObjectName.
246 KObjectNameGlobalData& ObjectNameGlobalData();
247
243 /// Gets the virtual memory manager for the kernel. 248 /// Gets the virtual memory manager for the kernel.
244 KMemoryManager& MemoryManager(); 249 KMemoryManager& MemoryManager();
245 250
@@ -372,6 +377,8 @@ public:
372 return slab_heap_container->page_buffer; 377 return slab_heap_container->page_buffer;
373 } else if constexpr (std::is_same_v<T, KThreadLocalPage>) { 378 } else if constexpr (std::is_same_v<T, KThreadLocalPage>) {
374 return slab_heap_container->thread_local_page; 379 return slab_heap_container->thread_local_page;
380 } else if constexpr (std::is_same_v<T, KObjectName>) {
381 return slab_heap_container->object_name;
375 } else if constexpr (std::is_same_v<T, KSessionRequest>) { 382 } else if constexpr (std::is_same_v<T, KSessionRequest>) {
376 return slab_heap_container->session_request; 383 return slab_heap_container->session_request;
377 } else if constexpr (std::is_same_v<T, KSecureSystemResource>) { 384 } else if constexpr (std::is_same_v<T, KSecureSystemResource>) {
@@ -443,6 +450,7 @@ private:
443 KSlabHeap<KDeviceAddressSpace> device_address_space; 450 KSlabHeap<KDeviceAddressSpace> device_address_space;
444 KSlabHeap<KPageBuffer> page_buffer; 451 KSlabHeap<KPageBuffer> page_buffer;
445 KSlabHeap<KThreadLocalPage> thread_local_page; 452 KSlabHeap<KThreadLocalPage> thread_local_page;
453 KSlabHeap<KObjectName> object_name;
446 KSlabHeap<KSessionRequest> session_request; 454 KSlabHeap<KSessionRequest> session_request;
447 KSlabHeap<KSecureSystemResource> secure_system_resource; 455 KSlabHeap<KSecureSystemResource> secure_system_resource;
448 KSlabHeap<KEventInfo> event_info; 456 KSlabHeap<KEventInfo> event_info;
diff --git a/src/core/hle/kernel/svc/svc_port.cpp b/src/core/hle/kernel/svc/svc_port.cpp
index 2b7cebde5..2f9bfcb52 100644
--- a/src/core/hle/kernel/svc/svc_port.cpp
+++ b/src/core/hle/kernel/svc/svc_port.cpp
@@ -5,6 +5,7 @@
5#include "core/core.h" 5#include "core/core.h"
6#include "core/hle/kernel/k_client_port.h" 6#include "core/hle/kernel/k_client_port.h"
7#include "core/hle/kernel/k_client_session.h" 7#include "core/hle/kernel/k_client_session.h"
8#include "core/hle/kernel/k_object_name.h"
8#include "core/hle/kernel/k_port.h" 9#include "core/hle/kernel/k_port.h"
9#include "core/hle/kernel/k_process.h" 10#include "core/hle/kernel/k_process.h"
10#include "core/hle/kernel/svc.h" 11#include "core/hle/kernel/svc.h"
@@ -74,10 +75,57 @@ Result ConnectToPort(Core::System& system, Handle* out_handle, Handle port) {
74 R_THROW(ResultNotImplemented); 75 R_THROW(ResultNotImplemented);
75} 76}
76 77
77Result ManageNamedPort(Core::System& system, Handle* out_server_handle, uint64_t name, 78Result ManageNamedPort(Core::System& system, Handle* out_server_handle, uint64_t user_name,
78 int32_t max_sessions) { 79 int32_t max_sessions) {
79 UNIMPLEMENTED(); 80 // Copy the provided name from user memory to kernel memory.
80 R_THROW(ResultNotImplemented); 81 std::array<char, KObjectName::NameLengthMax> name{};
82 system.Memory().ReadBlock(user_name, name.data(), sizeof(name));
83
84 // Validate that sessions and name are valid.
85 R_UNLESS(max_sessions >= 0, ResultOutOfRange);
86 R_UNLESS(name[sizeof(name) - 1] == '\x00', ResultOutOfRange);
87
88 if (max_sessions > 0) {
89 // Get the current handle table.
90 auto& handle_table = GetCurrentProcess(system.Kernel()).GetHandleTable();
91
92 // Create a new port.
93 KPort* port = KPort::Create(system.Kernel());
94 R_UNLESS(port != nullptr, ResultOutOfResource);
95
96 // Initialize the new port.
97 port->Initialize(max_sessions, false, "");
98
99 // Register the port.
100 KPort::Register(system.Kernel(), port);
101
102 // Ensure that our only reference to the port is in the handle table when we're done.
103 SCOPE_EXIT({
104 port->GetClientPort().Close();
105 port->GetServerPort().Close();
106 });
107
108 // Register the handle in the table.
109 R_TRY(handle_table.Add(out_server_handle, std::addressof(port->GetServerPort())));
110 ON_RESULT_FAILURE {
111 handle_table.Remove(*out_server_handle);
112 };
113
114 // Create a new object name.
115 R_TRY(KObjectName::NewFromName(system.Kernel(), std::addressof(port->GetClientPort()),
116 name.data()));
117 } else /* if (max_sessions == 0) */ {
118 // Ensure that this else case is correct.
119 ASSERT(max_sessions == 0);
120
121 // If we're closing, there's no server handle.
122 *out_server_handle = InvalidHandle;
123
124 // Delete the object.
125 R_TRY(KObjectName::Delete<KClientPort>(system.Kernel(), name.data()));
126 }
127
128 R_SUCCEED();
81} 129}
82 130
83Result ConnectToNamedPort64(Core::System& system, Handle* out_handle, uint64_t name) { 131Result ConnectToNamedPort64(Core::System& system, Handle* out_handle, uint64_t name) {
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index 7195f2bc1..614d61db4 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -186,6 +186,7 @@ bool Maxwell3D::IsMethodExecutable(u32 method) {
186 case MAXWELL3D_REG_INDEX(launch_dma): 186 case MAXWELL3D_REG_INDEX(launch_dma):
187 case MAXWELL3D_REG_INDEX(inline_data): 187 case MAXWELL3D_REG_INDEX(inline_data):
188 case MAXWELL3D_REG_INDEX(fragment_barrier): 188 case MAXWELL3D_REG_INDEX(fragment_barrier):
189 case MAXWELL3D_REG_INDEX(invalidate_texture_data_cache):
189 case MAXWELL3D_REG_INDEX(tiled_cache_barrier): 190 case MAXWELL3D_REG_INDEX(tiled_cache_barrier):
190 return true; 191 return true;
191 default: 192 default:
@@ -375,6 +376,9 @@ void Maxwell3D::ProcessMethodCall(u32 method, u32 argument, u32 nonshadow_argume
375 return; 376 return;
376 case MAXWELL3D_REG_INDEX(fragment_barrier): 377 case MAXWELL3D_REG_INDEX(fragment_barrier):
377 return rasterizer->FragmentBarrier(); 378 return rasterizer->FragmentBarrier();
379 case MAXWELL3D_REG_INDEX(invalidate_texture_data_cache):
380 rasterizer->InvalidateGPUCache();
381 return rasterizer->WaitForIdle();
378 case MAXWELL3D_REG_INDEX(tiled_cache_barrier): 382 case MAXWELL3D_REG_INDEX(tiled_cache_barrier):
379 return rasterizer->TiledCacheBarrier(); 383 return rasterizer->TiledCacheBarrier();
380 default: 384 default:
diff --git a/src/video_core/host1x/codecs/codec.cpp b/src/video_core/host1x/codecs/codec.cpp
index 42e7d6e4f..3e9022dce 100644
--- a/src/video_core/host1x/codecs/codec.cpp
+++ b/src/video_core/host1x/codecs/codec.cpp
@@ -152,6 +152,8 @@ bool Codec::CreateGpuAvDevice() {
152void Codec::InitializeAvCodecContext() { 152void Codec::InitializeAvCodecContext() {
153 av_codec_ctx = avcodec_alloc_context3(av_codec); 153 av_codec_ctx = avcodec_alloc_context3(av_codec);
154 av_opt_set(av_codec_ctx->priv_data, "tune", "zerolatency", 0); 154 av_opt_set(av_codec_ctx->priv_data, "tune", "zerolatency", 0);
155 av_codec_ctx->thread_count = 0;
156 av_codec_ctx->thread_type &= ~FF_THREAD_FRAME;
155} 157}
156 158
157void Codec::InitializeGpuDecoder() { 159void Codec::InitializeGpuDecoder() {
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 31209fb2e..db68ed259 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -1103,6 +1103,7 @@ void Config::SaveValues() {
1103 SaveRendererValues(); 1103 SaveRendererValues();
1104 SaveAudioValues(); 1104 SaveAudioValues();
1105 SaveSystemValues(); 1105 SaveSystemValues();
1106 qt_config->sync();
1106} 1107}
1107 1108
1108void Config::SaveAudioValues() { 1109void Config::SaveAudioValues() {
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp
index 22aa19c56..c21828b1d 100644
--- a/src/yuzu/game_list.cpp
+++ b/src/yuzu/game_list.cpp
@@ -870,6 +870,7 @@ void GameList::ToggleFavorite(u64 program_id) {
870 tree_view->setRowHidden(0, item_model->invisibleRootItem()->index(), true); 870 tree_view->setRowHidden(0, item_model->invisibleRootItem()->index(), true);
871 } 871 }
872 } 872 }
873 SaveConfig();
873} 874}
874 875
875void GameList::AddFavorite(u64 program_id) { 876void GameList::AddFavorite(u64 program_id) {
diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h
index f7ff93ed9..64e5af4c1 100644
--- a/src/yuzu/game_list.h
+++ b/src/yuzu/game_list.h
@@ -122,6 +122,7 @@ signals:
122 void AddDirectory(); 122 void AddDirectory();
123 void ShowList(bool show); 123 void ShowList(bool show);
124 void PopulatingCompleted(); 124 void PopulatingCompleted();
125 void SaveConfig();
125 126
126private slots: 127private slots:
127 void OnItemExpanded(const QModelIndex& item); 128 void OnItemExpanded(const QModelIndex& item);
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index a689a32db..f233b065e 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -1279,6 +1279,7 @@ void GMainWindow::ConnectWidgetEvents() {
1279 connect(game_list, &GameList::ShowList, this, &GMainWindow::OnGameListShowList); 1279 connect(game_list, &GameList::ShowList, this, &GMainWindow::OnGameListShowList);
1280 connect(game_list, &GameList::PopulatingCompleted, 1280 connect(game_list, &GameList::PopulatingCompleted,
1281 [this] { multiplayer_state->UpdateGameList(game_list->GetModel()); }); 1281 [this] { multiplayer_state->UpdateGameList(game_list->GetModel()); });
1282 connect(game_list, &GameList::SaveConfig, this, &GMainWindow::OnSaveConfig);
1282 1283
1283 connect(game_list, &GameList::OpenPerGameGeneralRequested, this, 1284 connect(game_list, &GameList::OpenPerGameGeneralRequested, this,
1284 &GMainWindow::OnGameListOpenPerGameProperties); 1285 &GMainWindow::OnGameListOpenPerGameProperties);
@@ -2662,6 +2663,8 @@ void GMainWindow::OnGameListAddDirectory() {
2662 } else { 2663 } else {
2663 LOG_WARNING(Frontend, "Selected directory is already in the game list"); 2664 LOG_WARNING(Frontend, "Selected directory is already in the game list");
2664 } 2665 }
2666
2667 OnSaveConfig();
2665} 2668}
2666 2669
2667void GMainWindow::OnGameListShowList(bool show) { 2670void GMainWindow::OnGameListShowList(bool show) {
@@ -3023,8 +3026,10 @@ void GMainWindow::OnRestartGame() {
3023 if (!system->IsPoweredOn()) { 3026 if (!system->IsPoweredOn()) {
3024 return; 3027 return;
3025 } 3028 }
3026 // Make a copy since BootGame edits game_path 3029 // Make a copy since ShutdownGame edits game_path
3027 BootGame(QString(current_game_path)); 3030 const auto current_game = QString(current_game_path);
3031 ShutdownGame();
3032 BootGame(current_game);
3028} 3033}
3029 3034
3030void GMainWindow::OnPauseGame() { 3035void GMainWindow::OnPauseGame() {
@@ -3388,6 +3393,7 @@ void GMainWindow::OnConfigureTas() {
3388 return; 3393 return;
3389 } else if (result == QDialog::Accepted) { 3394 } else if (result == QDialog::Accepted) {
3390 dialog.ApplyConfiguration(); 3395 dialog.ApplyConfiguration();
3396 OnSaveConfig();
3391 } 3397 }
3392} 3398}
3393 3399