diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/audio_core/renderer/command/command_generator.cpp | 2 | ||||
| -rw-r--r-- | src/audio_core/renderer/command/effect/aux_.cpp | 130 | ||||
| -rw-r--r-- | src/core/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/core/hle/kernel/init/init_slab_setup.cpp | 2 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_object_name.cpp | 102 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_object_name.h | 86 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.cpp | 14 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.h | 8 | ||||
| -rw-r--r-- | src/core/hle/kernel/svc/svc_port.cpp | 54 | ||||
| -rw-r--r-- | src/video_core/engines/maxwell_3d.cpp | 4 | ||||
| -rw-r--r-- | src/video_core/host1x/codecs/codec.cpp | 2 | ||||
| -rw-r--r-- | src/yuzu/configuration/config.cpp | 1 | ||||
| -rw-r--r-- | src/yuzu/game_list.cpp | 1 | ||||
| -rw-r--r-- | src/yuzu/game_list.h | 1 | ||||
| -rw-r--r-- | src/yuzu/main.cpp | 10 |
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 | ||
| 9 | namespace AudioCore::AudioRenderer { | 10 | namespace 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 | */ |
| 43 | static u32 WriteAuxBufferDsp(Core::Memory::Memory& memory, const CpuAddr send_info_, | 58 | static 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 | */ |
| 115 | static u32 ReadAuxBufferDsp(Core::Memory::Memory& memory, const CpuAddr return_info_, | 148 | static 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 | ||
| 170 | void AuxCommand::Dump([[maybe_unused]] const ADSP::CommandListProcessor& processor, | 222 | void 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 | |||
| 6 | namespace Kernel { | ||
| 7 | |||
| 8 | KObjectNameGlobalData::KObjectNameGlobalData(KernelCore& kernel) : m_object_list_lock{kernel} {} | ||
| 9 | KObjectNameGlobalData::~KObjectNameGlobalData() = default; | ||
| 10 | |||
| 11 | void 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 | |||
| 21 | bool KObjectName::MatchesName(const char* name) const { | ||
| 22 | return std::strncmp(m_name.data(), name, sizeof(m_name)) == 0; | ||
| 23 | } | ||
| 24 | |||
| 25 | Result 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 | |||
| 55 | Result 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 | |||
| 77 | KScopedAutoObject<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 | |||
| 87 | KScopedAutoObject<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 | |||
| 14 | namespace Kernel { | ||
| 15 | |||
| 16 | class KObjectNameGlobalData; | ||
| 17 | |||
| 18 | class KObjectName : public KSlabAllocated<KObjectName>, public boost::intrusive::list_base_hook<> { | ||
| 19 | public: | ||
| 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 | |||
| 53 | private: | ||
| 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 | |||
| 63 | private: | ||
| 64 | std::array<char, NameLengthMax> m_name{}; | ||
| 65 | KAutoObject* m_object{}; | ||
| 66 | }; | ||
| 67 | |||
| 68 | class KObjectNameGlobalData { | ||
| 69 | public: | ||
| 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 | |||
| 81 | private: | ||
| 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 | ||
| 1151 | KObjectNameGlobalData& KernelCore::ObjectNameGlobalData() { | ||
| 1152 | return *impl->object_name_global_data; | ||
| 1153 | } | ||
| 1154 | |||
| 1141 | KMemoryManager& KernelCore::MemoryManager() { | 1155 | KMemoryManager& 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; | |||
| 44 | class KLinkedListNode; | 44 | class KLinkedListNode; |
| 45 | class KMemoryLayout; | 45 | class KMemoryLayout; |
| 46 | class KMemoryManager; | 46 | class KMemoryManager; |
| 47 | class KObjectName; | ||
| 48 | class KObjectNameGlobalData; | ||
| 47 | class KPageBuffer; | 49 | class KPageBuffer; |
| 48 | class KPageBufferSlabHeap; | 50 | class KPageBufferSlabHeap; |
| 49 | class KPort; | 51 | class 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 | ||
| 77 | Result ManageNamedPort(Core::System& system, Handle* out_server_handle, uint64_t name, | 78 | Result 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 | ||
| 83 | Result ConnectToNamedPort64(Core::System& system, Handle* out_handle, uint64_t name) { | 131 | Result 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() { | |||
| 152 | void Codec::InitializeAvCodecContext() { | 152 | void 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 | ||
| 157 | void Codec::InitializeGpuDecoder() { | 159 | void 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 | ||
| 1108 | void Config::SaveAudioValues() { | 1109 | void 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 | ||
| 875 | void GameList::AddFavorite(u64 program_id) { | 876 | void 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 | ||
| 126 | private slots: | 127 | private 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 | ||
| 2667 | void GMainWindow::OnGameListShowList(bool show) { | 2670 | void 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 | ||
| 3030 | void GMainWindow::OnPauseGame() { | 3035 | void 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 | ||