summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/audio_core/audio_renderer.cpp4
-rw-r--r--src/audio_core/audio_renderer.h7
-rw-r--r--src/core/CMakeLists.txt10
-rw-r--r--src/core/crypto/key_manager.cpp3
-rw-r--r--src/core/file_sys/patch_manager.cpp19
-rw-r--r--src/core/file_sys/registered_cache.cpp53
-rw-r--r--src/core/file_sys/romfs_factory.cpp2
-rw-r--r--src/core/file_sys/system_archive/ng_word.cpp42
-rw-r--r--src/core/file_sys/system_archive/ng_word.h13
-rw-r--r--src/core/file_sys/system_archive/system_archive.cpp90
-rw-r--r--src/core/file_sys/system_archive/system_archive.h14
-rw-r--r--src/core/file_sys/vfs.cpp46
-rw-r--r--src/core/file_sys/vfs.h20
-rw-r--r--src/core/file_sys/vfs_vector.cpp1
-rw-r--r--src/core/file_sys/vfs_vector.h53
-rw-r--r--src/core/hle/kernel/handle_table.cpp5
-rw-r--r--src/core/hle/kernel/handle_table.h1
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp29
-rw-r--r--src/core/hle/kernel/hle_ipc.h12
-rw-r--r--src/core/hle/kernel/object.cpp3
-rw-r--r--src/core/hle/kernel/object.h9
-rw-r--r--src/core/hle/kernel/process.cpp4
-rw-r--r--src/core/hle/kernel/process.h9
-rw-r--r--src/core/hle/kernel/readable_event.cpp (renamed from src/core/hle/kernel/event.cpp)27
-rw-r--r--src/core/hle/kernel/readable_event.h55
-rw-r--r--src/core/hle/kernel/svc.cpp251
-rw-r--r--src/core/hle/kernel/svc_wrap.h13
-rw-r--r--src/core/hle/kernel/writable_event.cpp52
-rw-r--r--src/core/hle/kernel/writable_event.h (renamed from src/core/hle/kernel/event.h)35
-rw-r--r--src/core/hle/service/am/am.cpp43
-rw-r--r--src/core/hle/service/am/am.h16
-rw-r--r--src/core/hle/service/am/applets/applets.cpp31
-rw-r--r--src/core/hle/service/am/applets/applets.h17
-rw-r--r--src/core/hle/service/aoc/aoc_u.cpp14
-rw-r--r--src/core/hle/service/aoc/aoc_u.h6
-rw-r--r--src/core/hle/service/audio/audout_u.cpp21
-rw-r--r--src/core/hle/service/audio/audren_u.cpp26
-rw-r--r--src/core/hle/service/btdrv/btdrv.cpp16
-rw-r--r--src/core/hle/service/btm/btm.cpp46
-rw-r--r--src/core/hle/service/erpt/erpt.cpp12
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp30
-rw-r--r--src/core/hle/service/filesystem/filesystem.h15
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp22
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp23
-rw-r--r--src/core/hle/service/hid/controllers/npad.h7
-rw-r--r--src/core/hle/service/hid/hid.cpp3
-rw-r--r--src/core/hle/service/ldr/ldr.cpp10
-rw-r--r--src/core/hle/service/nfp/nfp.cpp34
-rw-r--r--src/core/hle/service/nfp/nfp.h7
-rw-r--r--src/core/hle/service/nifm/nifm.cpp14
-rw-r--r--src/core/hle/service/nim/nim.cpp20
-rw-r--r--src/core/hle/service/nvdrv/interface.cpp9
-rw-r--r--src/core/hle/service/nvdrv/interface.h7
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.cpp19
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.h11
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp13
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.h11
-rw-r--r--src/core/hle/service/set/set.cpp21
-rw-r--r--src/core/hle/service/set/set.h1
-rw-r--r--src/core/hle/service/usb/usb.cpp2
-rw-r--r--src/core/hle/service/vi/vi.cpp7
-rw-r--r--src/core/loader/deconstructed_rom_directory.cpp3
-rw-r--r--src/core/loader/nro.cpp15
-rw-r--r--src/core/loader/nro.h8
-rw-r--r--src/core/loader/nso.cpp8
-rw-r--r--src/core/loader/nso.h8
-rw-r--r--src/core/memory.cpp8
-rw-r--r--src/video_core/command_processor.cpp142
-rw-r--r--src/video_core/engines/maxwell_3d.h1
-rw-r--r--src/video_core/engines/shader_bytecode.h3
-rw-r--r--src/video_core/gpu.cpp12
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp50
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h20
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp153
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp749
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.h1
-rw-r--r--src/video_core/renderer_opengl/gl_shader_manager.h21
-rw-r--r--src/video_core/surface.h552
-rw-r--r--src/yuzu/configuration/configure_audio.h5
-rw-r--r--src/yuzu/configuration/configure_debug.h3
-rw-r--r--src/yuzu/configuration/configure_dialog.h3
-rw-r--r--src/yuzu/configuration/configure_gamelist.h2
-rw-r--r--src/yuzu/configuration/configure_general.h2
-rw-r--r--src/yuzu/configuration/configure_graphics.h3
-rw-r--r--src/yuzu/configuration/configure_input.cpp4
-rw-r--r--src/yuzu/configuration/configure_input.h1
-rw-r--r--src/yuzu/configuration/configure_web.h5
-rw-r--r--src/yuzu/debugger/wait_tree.cpp11
-rw-r--r--src/yuzu/debugger/wait_tree.h4
-rw-r--r--src/yuzu/game_list.cpp1
-rw-r--r--src/yuzu/game_list_worker.cpp119
-rw-r--r--src/yuzu/main.cpp6
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.cpp2
93 files changed, 1807 insertions, 1534 deletions
diff --git a/src/audio_core/audio_renderer.cpp b/src/audio_core/audio_renderer.cpp
index 23e5d3f10..2e59894ab 100644
--- a/src/audio_core/audio_renderer.cpp
+++ b/src/audio_core/audio_renderer.cpp
@@ -8,7 +8,7 @@
8#include "audio_core/codec.h" 8#include "audio_core/codec.h"
9#include "common/assert.h" 9#include "common/assert.h"
10#include "common/logging/log.h" 10#include "common/logging/log.h"
11#include "core/hle/kernel/event.h" 11#include "core/hle/kernel/writable_event.h"
12#include "core/memory.h" 12#include "core/memory.h"
13 13
14namespace AudioCore { 14namespace AudioCore {
@@ -72,7 +72,7 @@ private:
72 EffectInStatus info{}; 72 EffectInStatus info{};
73}; 73};
74AudioRenderer::AudioRenderer(AudioRendererParameter params, 74AudioRenderer::AudioRenderer(AudioRendererParameter params,
75 Kernel::SharedPtr<Kernel::Event> buffer_event) 75 Kernel::SharedPtr<Kernel::WritableEvent> buffer_event)
76 : worker_params{params}, buffer_event{buffer_event}, voices(params.voice_count), 76 : worker_params{params}, buffer_event{buffer_event}, voices(params.voice_count),
77 effects(params.effect_count) { 77 effects(params.effect_count) {
78 78
diff --git a/src/audio_core/audio_renderer.h b/src/audio_core/audio_renderer.h
index 71ba4be40..7826881bf 100644
--- a/src/audio_core/audio_renderer.h
+++ b/src/audio_core/audio_renderer.h
@@ -15,7 +15,7 @@
15#include "core/hle/kernel/object.h" 15#include "core/hle/kernel/object.h"
16 16
17namespace Kernel { 17namespace Kernel {
18class Event; 18class WritableEvent;
19} 19}
20 20
21namespace AudioCore { 21namespace AudioCore {
@@ -208,7 +208,8 @@ static_assert(sizeof(UpdateDataHeader) == 0x40, "UpdateDataHeader has wrong size
208 208
209class AudioRenderer { 209class AudioRenderer {
210public: 210public:
211 AudioRenderer(AudioRendererParameter params, Kernel::SharedPtr<Kernel::Event> buffer_event); 211 AudioRenderer(AudioRendererParameter params,
212 Kernel::SharedPtr<Kernel::WritableEvent> buffer_event);
212 ~AudioRenderer(); 213 ~AudioRenderer();
213 214
214 std::vector<u8> UpdateAudioRenderer(const std::vector<u8>& input_params); 215 std::vector<u8> UpdateAudioRenderer(const std::vector<u8>& input_params);
@@ -224,7 +225,7 @@ private:
224 class VoiceState; 225 class VoiceState;
225 226
226 AudioRendererParameter worker_params; 227 AudioRendererParameter worker_params;
227 Kernel::SharedPtr<Kernel::Event> buffer_event; 228 Kernel::SharedPtr<Kernel::WritableEvent> buffer_event;
228 std::vector<VoiceState> voices; 229 std::vector<VoiceState> voices;
229 std::vector<EffectState> effects; 230 std::vector<EffectState> effects;
230 std::unique_ptr<AudioOut> audio_out; 231 std::unique_ptr<AudioOut> audio_out;
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index e1f21a764..882c9ab59 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -63,6 +63,10 @@ add_library(core STATIC
63 file_sys/sdmc_factory.h 63 file_sys/sdmc_factory.h
64 file_sys/submission_package.cpp 64 file_sys/submission_package.cpp
65 file_sys/submission_package.h 65 file_sys/submission_package.h
66 file_sys/system_archive/ng_word.cpp
67 file_sys/system_archive/ng_word.h
68 file_sys/system_archive/system_archive.cpp
69 file_sys/system_archive/system_archive.h
66 file_sys/vfs.cpp 70 file_sys/vfs.cpp
67 file_sys/vfs.h 71 file_sys/vfs.h
68 file_sys/vfs_concat.cpp 72 file_sys/vfs_concat.cpp
@@ -97,8 +101,6 @@ add_library(core STATIC
97 hle/kernel/client_session.cpp 101 hle/kernel/client_session.cpp
98 hle/kernel/client_session.h 102 hle/kernel/client_session.h
99 hle/kernel/errors.h 103 hle/kernel/errors.h
100 hle/kernel/event.cpp
101 hle/kernel/event.h
102 hle/kernel/handle_table.cpp 104 hle/kernel/handle_table.cpp
103 hle/kernel/handle_table.h 105 hle/kernel/handle_table.h
104 hle/kernel/hle_ipc.cpp 106 hle/kernel/hle_ipc.cpp
@@ -111,6 +113,8 @@ add_library(core STATIC
111 hle/kernel/object.h 113 hle/kernel/object.h
112 hle/kernel/process.cpp 114 hle/kernel/process.cpp
113 hle/kernel/process.h 115 hle/kernel/process.h
116 hle/kernel/readable_event.cpp
117 hle/kernel/readable_event.h
114 hle/kernel/resource_limit.cpp 118 hle/kernel/resource_limit.cpp
115 hle/kernel/resource_limit.h 119 hle/kernel/resource_limit.h
116 hle/kernel/scheduler.cpp 120 hle/kernel/scheduler.cpp
@@ -133,6 +137,8 @@ add_library(core STATIC
133 hle/kernel/vm_manager.h 137 hle/kernel/vm_manager.h
134 hle/kernel/wait_object.cpp 138 hle/kernel/wait_object.cpp
135 hle/kernel/wait_object.h 139 hle/kernel/wait_object.h
140 hle/kernel/writable_event.cpp
141 hle/kernel/writable_event.h
136 hle/lock.cpp 142 hle/lock.cpp
137 hle/lock.h 143 hle/lock.h
138 hle/result.h 144 hle/result.h
diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp
index 904afa039..ca12fb4ab 100644
--- a/src/core/crypto/key_manager.cpp
+++ b/src/core/crypto/key_manager.cpp
@@ -246,7 +246,6 @@ std::vector<TicketRaw> GetTicketblob(const FileUtil::IOFile& ticket_save) {
246 } 246 }
247 247
248 std::vector<TicketRaw> out; 248 std::vector<TicketRaw> out;
249 u32 magic{};
250 for (std::size_t offset = 0; offset + 0x4 < buffer.size(); ++offset) { 249 for (std::size_t offset = 0; offset + 0x4 < buffer.size(); ++offset) {
251 if (buffer[offset] == 0x4 && buffer[offset + 1] == 0x0 && buffer[offset + 2] == 0x1 && 250 if (buffer[offset] == 0x4 && buffer[offset + 1] == 0x0 && buffer[offset + 2] == 0x1 &&
252 buffer[offset + 3] == 0x0) { 251 buffer[offset + 3] == 0x0) {
@@ -794,7 +793,7 @@ void KeyManager::DeriveBase() {
794 793
795void KeyManager::DeriveETicket(PartitionDataManager& data) { 794void KeyManager::DeriveETicket(PartitionDataManager& data) {
796 // ETicket keys 795 // ETicket keys
797 const auto es = Service::FileSystem::GetUnionContents()->GetEntry( 796 const auto es = Service::FileSystem::GetUnionContents().GetEntry(
798 0x0100000000000033, FileSys::ContentRecordType::Program); 797 0x0100000000000033, FileSys::ContentRecordType::Program);
799 798
800 if (es == nullptr) 799 if (es == nullptr)
diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp
index e8df08724..6b14e08be 100644
--- a/src/core/file_sys/patch_manager.cpp
+++ b/src/core/file_sys/patch_manager.cpp
@@ -75,12 +75,12 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
75 75
76 // Game Updates 76 // Game Updates
77 const auto update_tid = GetUpdateTitleID(title_id); 77 const auto update_tid = GetUpdateTitleID(title_id);
78 const auto update = installed->GetEntry(update_tid, ContentRecordType::Program); 78 const auto update = installed.GetEntry(update_tid, ContentRecordType::Program);
79 79
80 if (update != nullptr && update->GetExeFS() != nullptr && 80 if (update != nullptr && update->GetExeFS() != nullptr &&
81 update->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) { 81 update->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) {
82 LOG_INFO(Loader, " ExeFS: Update ({}) applied successfully", 82 LOG_INFO(Loader, " ExeFS: Update ({}) applied successfully",
83 FormatTitleVersion(installed->GetEntryVersion(update_tid).value_or(0))); 83 FormatTitleVersion(installed.GetEntryVersion(update_tid).value_or(0)));
84 exefs = update->GetExeFS(); 84 exefs = update->GetExeFS();
85 } 85 }
86 86
@@ -281,13 +281,13 @@ VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, Content
281 281
282 // Game Updates 282 // Game Updates
283 const auto update_tid = GetUpdateTitleID(title_id); 283 const auto update_tid = GetUpdateTitleID(title_id);
284 const auto update = installed->GetEntryRaw(update_tid, type); 284 const auto update = installed.GetEntryRaw(update_tid, type);
285 if (update != nullptr) { 285 if (update != nullptr) {
286 const auto new_nca = std::make_shared<NCA>(update, romfs, ivfc_offset); 286 const auto new_nca = std::make_shared<NCA>(update, romfs, ivfc_offset);
287 if (new_nca->GetStatus() == Loader::ResultStatus::Success && 287 if (new_nca->GetStatus() == Loader::ResultStatus::Success &&
288 new_nca->GetRomFS() != nullptr) { 288 new_nca->GetRomFS() != nullptr) {
289 LOG_INFO(Loader, " RomFS: Update ({}) applied successfully", 289 LOG_INFO(Loader, " RomFS: Update ({}) applied successfully",
290 FormatTitleVersion(installed->GetEntryVersion(update_tid).value_or(0))); 290 FormatTitleVersion(installed.GetEntryVersion(update_tid).value_or(0)));
291 romfs = new_nca->GetRomFS(); 291 romfs = new_nca->GetRomFS();
292 } 292 }
293 } else if (update_raw != nullptr) { 293 } else if (update_raw != nullptr) {
@@ -329,8 +329,8 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
329 if (nacp != nullptr) { 329 if (nacp != nullptr) {
330 out.insert_or_assign("Update", nacp->GetVersionString()); 330 out.insert_or_assign("Update", nacp->GetVersionString());
331 } else { 331 } else {
332 if (installed->HasEntry(update_tid, ContentRecordType::Program)) { 332 if (installed.HasEntry(update_tid, ContentRecordType::Program)) {
333 const auto meta_ver = installed->GetEntryVersion(update_tid); 333 const auto meta_ver = installed.GetEntryVersion(update_tid);
334 if (meta_ver.value_or(0) == 0) { 334 if (meta_ver.value_or(0) == 0) {
335 out.insert_or_assign("Update", ""); 335 out.insert_or_assign("Update", "");
336 } else { 336 } else {
@@ -383,14 +383,13 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
383 } 383 }
384 384
385 // DLC 385 // DLC
386 const auto dlc_entries = installed->ListEntriesFilter(TitleType::AOC, ContentRecordType::Data); 386 const auto dlc_entries = installed.ListEntriesFilter(TitleType::AOC, ContentRecordType::Data);
387 std::vector<RegisteredCacheEntry> dlc_match; 387 std::vector<RegisteredCacheEntry> dlc_match;
388 dlc_match.reserve(dlc_entries.size()); 388 dlc_match.reserve(dlc_entries.size());
389 std::copy_if(dlc_entries.begin(), dlc_entries.end(), std::back_inserter(dlc_match), 389 std::copy_if(dlc_entries.begin(), dlc_entries.end(), std::back_inserter(dlc_match),
390 [this, &installed](const RegisteredCacheEntry& entry) { 390 [this, &installed](const RegisteredCacheEntry& entry) {
391 return (entry.title_id & DLC_BASE_TITLE_ID_MASK) == title_id && 391 return (entry.title_id & DLC_BASE_TITLE_ID_MASK) == title_id &&
392 installed->GetEntry(entry)->GetStatus() == 392 installed.GetEntry(entry)->GetStatus() == Loader::ResultStatus::Success;
393 Loader::ResultStatus::Success;
394 }); 393 });
395 if (!dlc_match.empty()) { 394 if (!dlc_match.empty()) {
396 // Ensure sorted so DLC IDs show in order. 395 // Ensure sorted so DLC IDs show in order.
@@ -411,7 +410,7 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
411std::pair<std::unique_ptr<NACP>, VirtualFile> PatchManager::GetControlMetadata() const { 410std::pair<std::unique_ptr<NACP>, VirtualFile> PatchManager::GetControlMetadata() const {
412 const auto installed{Service::FileSystem::GetUnionContents()}; 411 const auto installed{Service::FileSystem::GetUnionContents()};
413 412
414 const auto base_control_nca = installed->GetEntry(title_id, ContentRecordType::Control); 413 const auto base_control_nca = installed.GetEntry(title_id, ContentRecordType::Control);
415 if (base_control_nca == nullptr) 414 if (base_control_nca == nullptr)
416 return {}; 415 return {};
417 416
diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp
index 07c3af64a..128199063 100644
--- a/src/core/file_sys/registered_cache.cpp
+++ b/src/core/file_sys/registered_cache.cpp
@@ -107,42 +107,41 @@ static ContentRecordType GetCRTypeFromNCAType(NCAContentType type) {
107VirtualFile RegisteredCache::OpenFileOrDirectoryConcat(const VirtualDir& dir, 107VirtualFile RegisteredCache::OpenFileOrDirectoryConcat(const VirtualDir& dir,
108 std::string_view path) const { 108 std::string_view path) const {
109 const auto file = dir->GetFileRelative(path); 109 const auto file = dir->GetFileRelative(path);
110 if (file != nullptr) 110 if (file != nullptr) {
111 return file; 111 return file;
112 }
112 113
113 const auto nca_dir = dir->GetDirectoryRelative(path); 114 const auto nca_dir = dir->GetDirectoryRelative(path);
114 if (nca_dir != nullptr) { 115 if (nca_dir == nullptr) {
115 const auto nca_dir = dir->GetDirectoryRelative(path); 116 return nullptr;
116 VirtualFile file = nullptr; 117 }
117 118
118 const auto files = nca_dir->GetFiles(); 119 const auto files = nca_dir->GetFiles();
119 if (files.size() == 1 && files[0]->GetName() == "00") { 120 if (files.size() == 1 && files[0]->GetName() == "00") {
120 file = files[0]; 121 return files[0];
122 }
123
124 std::vector<VirtualFile> concat;
125 // Since the files are a two-digit hex number, max is FF.
126 for (std::size_t i = 0; i < 0x100; ++i) {
127 auto next = nca_dir->GetFile(fmt::format("{:02X}", i));
128 if (next != nullptr) {
129 concat.push_back(std::move(next));
121 } else { 130 } else {
122 std::vector<VirtualFile> concat; 131 next = nca_dir->GetFile(fmt::format("{:02x}", i));
123 // Since the files are a two-digit hex number, max is FF. 132 if (next != nullptr) {
124 for (std::size_t i = 0; i < 0x100; ++i) { 133 concat.push_back(std::move(next));
125 auto next = nca_dir->GetFile(fmt::format("{:02X}", i)); 134 } else {
126 if (next != nullptr) { 135 break;
127 concat.push_back(std::move(next));
128 } else {
129 next = nca_dir->GetFile(fmt::format("{:02x}", i));
130 if (next != nullptr)
131 concat.push_back(std::move(next));
132 else
133 break;
134 }
135 } 136 }
136
137 if (concat.empty())
138 return nullptr;
139
140 file = ConcatenatedVfsFile::MakeConcatenatedFile(concat, concat.front()->GetName());
141 } 137 }
138 }
142 139
143 return file; 140 if (concat.empty()) {
141 return nullptr;
144 } 142 }
145 return nullptr; 143
144 return ConcatenatedVfsFile::MakeConcatenatedFile(concat, concat.front()->GetName());
146} 145}
147 146
148VirtualFile RegisteredCache::GetFileAtID(NcaID id) const { 147VirtualFile RegisteredCache::GetFileAtID(NcaID id) const {
diff --git a/src/core/file_sys/romfs_factory.cpp b/src/core/file_sys/romfs_factory.cpp
index 0b645b106..6ad1e4f86 100644
--- a/src/core/file_sys/romfs_factory.cpp
+++ b/src/core/file_sys/romfs_factory.cpp
@@ -48,7 +48,7 @@ ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id, StorageId storage, Conte
48 48
49 switch (storage) { 49 switch (storage) {
50 case StorageId::None: 50 case StorageId::None:
51 res = Service::FileSystem::GetUnionContents()->GetEntry(title_id, type); 51 res = Service::FileSystem::GetUnionContents().GetEntry(title_id, type);
52 break; 52 break;
53 case StorageId::NandSystem: 53 case StorageId::NandSystem:
54 res = Service::FileSystem::GetSystemNANDContents()->GetEntry(title_id, type); 54 res = Service::FileSystem::GetSystemNANDContents()->GetEntry(title_id, type);
diff --git a/src/core/file_sys/system_archive/ng_word.cpp b/src/core/file_sys/system_archive/ng_word.cpp
new file mode 100644
index 000000000..a24f1e496
--- /dev/null
+++ b/src/core/file_sys/system_archive/ng_word.cpp
@@ -0,0 +1,42 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <fmt/format.h>
6#include "common/common_types.h"
7#include "core/file_sys/system_archive/ng_word.h"
8#include "core/file_sys/vfs_vector.h"
9
10namespace FileSys::SystemArchive {
11
12namespace NgWord1Data {
13
14constexpr std::size_t NUMBER_WORD_TXT_FILES = 0x10;
15
16// Should this archive replacement mysteriously not work on a future game, consider updating.
17constexpr std::array<u8, 4> VERSION_DAT{0x0, 0x0, 0x0, 0x19}; // 5.1.0 System Version
18
19constexpr std::array<u8, 30> WORD_TXT{
20 0xFE, 0xFF, 0x00, 0x5E, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00, 0x79, 0x00, 0x62, 0x00,
21 0x61, 0x00, 0x64, 0x00, 0x77, 0x00, 0x6F, 0x00, 0x72, 0x00, 0x64, 0x00, 0x24, 0x00, 0x0A,
22}; // "^verybadword$" in UTF-16
23
24} // namespace NgWord1Data
25
26VirtualDir NgWord1() {
27 std::vector<VirtualFile> files(NgWord1Data::NUMBER_WORD_TXT_FILES);
28
29 for (std::size_t i = 0; i < files.size(); ++i) {
30 files[i] = std::make_shared<ArrayVfsFile<NgWord1Data::WORD_TXT.size()>>(
31 NgWord1Data::WORD_TXT, fmt::format("{}.txt", i));
32 }
33
34 files.push_back(std::make_shared<ArrayVfsFile<NgWord1Data::WORD_TXT.size()>>(
35 NgWord1Data::WORD_TXT, "common.txt"));
36 files.push_back(std::make_shared<ArrayVfsFile<NgWord1Data::VERSION_DAT.size()>>(
37 NgWord1Data::VERSION_DAT, "version.dat"));
38
39 return std::make_shared<VectorVfsDirectory>(files, std::vector<VirtualDir>{}, "data");
40}
41
42} // namespace FileSys::SystemArchive
diff --git a/src/core/file_sys/system_archive/ng_word.h b/src/core/file_sys/system_archive/ng_word.h
new file mode 100644
index 000000000..f4bc67344
--- /dev/null
+++ b/src/core/file_sys/system_archive/ng_word.h
@@ -0,0 +1,13 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/file_sys/vfs_types.h"
8
9namespace FileSys::SystemArchive {
10
11VirtualDir NgWord1();
12
13} // namespace FileSys::SystemArchive
diff --git a/src/core/file_sys/system_archive/system_archive.cpp b/src/core/file_sys/system_archive/system_archive.cpp
new file mode 100644
index 000000000..d3883267c
--- /dev/null
+++ b/src/core/file_sys/system_archive/system_archive.cpp
@@ -0,0 +1,90 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/logging/log.h"
6#include "core/file_sys/romfs.h"
7#include "core/file_sys/system_archive/ng_word.h"
8#include "core/file_sys/system_archive/system_archive.h"
9
10namespace FileSys::SystemArchive {
11
12constexpr u64 SYSTEM_ARCHIVE_BASE_TITLE_ID = 0x0100000000000800;
13constexpr std::size_t SYSTEM_ARCHIVE_COUNT = 0x28;
14
15using SystemArchiveSupplier = VirtualDir (*)();
16
17struct SystemArchiveDescriptor {
18 u64 title_id;
19 const char* name;
20 SystemArchiveSupplier supplier;
21};
22
23constexpr std::array<SystemArchiveDescriptor, SYSTEM_ARCHIVE_COUNT> SYSTEM_ARCHIVES{{
24 {0x0100000000000800, "CertStore", nullptr},
25 {0x0100000000000801, "ErrorMessage", nullptr},
26 {0x0100000000000802, "MiiModel", nullptr},
27 {0x0100000000000803, "BrowserDll", nullptr},
28 {0x0100000000000804, "Help", nullptr},
29 {0x0100000000000805, "SharedFont", nullptr},
30 {0x0100000000000806, "NgWord", &NgWord1},
31 {0x0100000000000807, "SsidList", nullptr},
32 {0x0100000000000808, "Dictionary", nullptr},
33 {0x0100000000000809, "SystemVersion", nullptr},
34 {0x010000000000080A, "AvatarImage", nullptr},
35 {0x010000000000080B, "LocalNews", nullptr},
36 {0x010000000000080C, "Eula", nullptr},
37 {0x010000000000080D, "UrlBlackList", nullptr},
38 {0x010000000000080E, "TimeZoneBinary", nullptr},
39 {0x010000000000080F, "CertStoreCruiser", nullptr},
40 {0x0100000000000810, "FontNintendoExtension", nullptr},
41 {0x0100000000000811, "FontStandard", nullptr},
42 {0x0100000000000812, "FontKorean", nullptr},
43 {0x0100000000000813, "FontChineseTraditional", nullptr},
44 {0x0100000000000814, "FontChineseSimple", nullptr},
45 {0x0100000000000815, "FontBfcpx", nullptr},
46 {0x0100000000000816, "SystemUpdate", nullptr},
47 {0x0100000000000817, "0100000000000817", nullptr},
48 {0x0100000000000818, "FirmwareDebugSettings", nullptr},
49 {0x0100000000000819, "BootImagePackage", nullptr},
50 {0x010000000000081A, "BootImagePackageSafe", nullptr},
51 {0x010000000000081B, "BootImagePackageExFat", nullptr},
52 {0x010000000000081C, "BootImagePackageExFatSafe", nullptr},
53 {0x010000000000081D, "FatalMessage", nullptr},
54 {0x010000000000081E, "ControllerIcon", nullptr},
55 {0x010000000000081F, "PlatformConfigIcosa", nullptr},
56 {0x0100000000000820, "PlatformConfigCopper", nullptr},
57 {0x0100000000000821, "PlatformConfigHoag", nullptr},
58 {0x0100000000000822, "ControllerFirmware", nullptr},
59 {0x0100000000000823, "NgWord2", nullptr},
60 {0x0100000000000824, "PlatformConfigIcosaMariko", nullptr},
61 {0x0100000000000825, "ApplicationBlackList", nullptr},
62 {0x0100000000000826, "RebootlessSystemUpdateVersion", nullptr},
63 {0x0100000000000827, "ContentActionTable", nullptr},
64}};
65
66VirtualFile SynthesizeSystemArchive(const u64 title_id) {
67 if (title_id < SYSTEM_ARCHIVES.front().title_id || title_id > SYSTEM_ARCHIVES.back().title_id)
68 return nullptr;
69
70 const auto& desc = SYSTEM_ARCHIVES[title_id - SYSTEM_ARCHIVE_BASE_TITLE_ID];
71
72 LOG_INFO(Service_FS, "Synthesizing system archive '{}' (0x{:016X}).", desc.name, desc.title_id);
73
74 if (desc.supplier == nullptr)
75 return nullptr;
76
77 const auto dir = desc.supplier();
78
79 if (dir == nullptr)
80 return nullptr;
81
82 const auto romfs = CreateRomFS(dir);
83
84 if (romfs == nullptr)
85 return nullptr;
86
87 LOG_INFO(Service_FS, " - System archive generation successful!");
88 return romfs;
89}
90} // namespace FileSys::SystemArchive
diff --git a/src/core/file_sys/system_archive/system_archive.h b/src/core/file_sys/system_archive/system_archive.h
new file mode 100644
index 000000000..724a8eb17
--- /dev/null
+++ b/src/core/file_sys/system_archive/system_archive.h
@@ -0,0 +1,14 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8#include "core/file_sys/vfs_types.h"
9
10namespace FileSys::SystemArchive {
11
12VirtualFile SynthesizeSystemArchive(u64 title_id);
13
14} // namespace FileSys::SystemArchive
diff --git a/src/core/file_sys/vfs.cpp b/src/core/file_sys/vfs.cpp
index 7b584de7f..e33327ef0 100644
--- a/src/core/file_sys/vfs.cpp
+++ b/src/core/file_sys/vfs.cpp
@@ -384,6 +384,28 @@ bool VfsDirectory::DeleteSubdirectoryRecursive(std::string_view name) {
384 return success; 384 return success;
385} 385}
386 386
387bool VfsDirectory::CleanSubdirectoryRecursive(std::string_view name) {
388 auto dir = GetSubdirectory(name);
389 if (dir == nullptr) {
390 return false;
391 }
392
393 bool success = true;
394 for (const auto& file : dir->GetFiles()) {
395 if (!dir->DeleteFile(file->GetName())) {
396 success = false;
397 }
398 }
399
400 for (const auto& sdir : dir->GetSubdirectories()) {
401 if (!dir->DeleteSubdirectoryRecursive(sdir->GetName())) {
402 success = false;
403 }
404 }
405
406 return success;
407}
408
387bool VfsDirectory::Copy(std::string_view src, std::string_view dest) { 409bool VfsDirectory::Copy(std::string_view src, std::string_view dest) {
388 const auto f1 = GetFile(src); 410 const auto f1 = GetFile(src);
389 auto f2 = CreateFile(dest); 411 auto f2 = CreateFile(dest);
@@ -431,10 +453,34 @@ std::shared_ptr<VfsFile> ReadOnlyVfsDirectory::CreateFile(std::string_view name)
431 return nullptr; 453 return nullptr;
432} 454}
433 455
456std::shared_ptr<VfsFile> ReadOnlyVfsDirectory::CreateFileAbsolute(std::string_view path) {
457 return nullptr;
458}
459
460std::shared_ptr<VfsFile> ReadOnlyVfsDirectory::CreateFileRelative(std::string_view path) {
461 return nullptr;
462}
463
464std::shared_ptr<VfsDirectory> ReadOnlyVfsDirectory::CreateDirectoryAbsolute(std::string_view path) {
465 return nullptr;
466}
467
468std::shared_ptr<VfsDirectory> ReadOnlyVfsDirectory::CreateDirectoryRelative(std::string_view path) {
469 return nullptr;
470}
471
434bool ReadOnlyVfsDirectory::DeleteSubdirectory(std::string_view name) { 472bool ReadOnlyVfsDirectory::DeleteSubdirectory(std::string_view name) {
435 return false; 473 return false;
436} 474}
437 475
476bool ReadOnlyVfsDirectory::DeleteSubdirectoryRecursive(std::string_view name) {
477 return false;
478}
479
480bool ReadOnlyVfsDirectory::CleanSubdirectoryRecursive(std::string_view name) {
481 return false;
482}
483
438bool ReadOnlyVfsDirectory::DeleteFile(std::string_view name) { 484bool ReadOnlyVfsDirectory::DeleteFile(std::string_view name) {
439 return false; 485 return false;
440} 486}
diff --git a/src/core/file_sys/vfs.h b/src/core/file_sys/vfs.h
index 002f99d4e..e5641b255 100644
--- a/src/core/file_sys/vfs.h
+++ b/src/core/file_sys/vfs.h
@@ -245,12 +245,18 @@ public:
245 // any failure. 245 // any failure.
246 virtual std::shared_ptr<VfsDirectory> CreateDirectoryAbsolute(std::string_view path); 246 virtual std::shared_ptr<VfsDirectory> CreateDirectoryAbsolute(std::string_view path);
247 247
248 // Deletes the subdirectory with name and returns true on success. 248 // Deletes the subdirectory with the given name and returns true on success.
249 virtual bool DeleteSubdirectory(std::string_view name) = 0; 249 virtual bool DeleteSubdirectory(std::string_view name) = 0;
250 // Deletes all subdirectories and files of subdirectory with name recirsively and then deletes 250
251 // the subdirectory. Returns true on success. 251 // Deletes all subdirectories and files within the provided directory and then deletes
252 // the directory itself. Returns true on success.
252 virtual bool DeleteSubdirectoryRecursive(std::string_view name); 253 virtual bool DeleteSubdirectoryRecursive(std::string_view name);
253 // Returnes whether or not the file with name name was deleted successfully. 254
255 // Deletes all subdirectories and files within the provided directory.
256 // Unlike DeleteSubdirectoryRecursive, this does not delete the provided directory.
257 virtual bool CleanSubdirectoryRecursive(std::string_view name);
258
259 // Returns whether or not the file with name name was deleted successfully.
254 virtual bool DeleteFile(std::string_view name) = 0; 260 virtual bool DeleteFile(std::string_view name) = 0;
255 261
256 // Returns whether or not this directory was renamed to name. 262 // Returns whether or not this directory was renamed to name.
@@ -276,7 +282,13 @@ public:
276 bool IsReadable() const override; 282 bool IsReadable() const override;
277 std::shared_ptr<VfsDirectory> CreateSubdirectory(std::string_view name) override; 283 std::shared_ptr<VfsDirectory> CreateSubdirectory(std::string_view name) override;
278 std::shared_ptr<VfsFile> CreateFile(std::string_view name) override; 284 std::shared_ptr<VfsFile> CreateFile(std::string_view name) override;
285 std::shared_ptr<VfsFile> CreateFileAbsolute(std::string_view path) override;
286 std::shared_ptr<VfsFile> CreateFileRelative(std::string_view path) override;
287 std::shared_ptr<VfsDirectory> CreateDirectoryAbsolute(std::string_view path) override;
288 std::shared_ptr<VfsDirectory> CreateDirectoryRelative(std::string_view path) override;
279 bool DeleteSubdirectory(std::string_view name) override; 289 bool DeleteSubdirectory(std::string_view name) override;
290 bool DeleteSubdirectoryRecursive(std::string_view name) override;
291 bool CleanSubdirectoryRecursive(std::string_view name) override;
280 bool DeleteFile(std::string_view name) override; 292 bool DeleteFile(std::string_view name) override;
281 bool Rename(std::string_view name) override; 293 bool Rename(std::string_view name) override;
282}; 294};
diff --git a/src/core/file_sys/vfs_vector.cpp b/src/core/file_sys/vfs_vector.cpp
index 808f31e81..515626658 100644
--- a/src/core/file_sys/vfs_vector.cpp
+++ b/src/core/file_sys/vfs_vector.cpp
@@ -3,7 +3,6 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm> 5#include <algorithm>
6#include <cstring>
7#include <utility> 6#include <utility>
8#include "core/file_sys/vfs_vector.h" 7#include "core/file_sys/vfs_vector.h"
9 8
diff --git a/src/core/file_sys/vfs_vector.h b/src/core/file_sys/vfs_vector.h
index 3e3f790c3..ac36cb2ee 100644
--- a/src/core/file_sys/vfs_vector.h
+++ b/src/core/file_sys/vfs_vector.h
@@ -4,10 +4,63 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <cstring>
7#include "core/file_sys/vfs.h" 8#include "core/file_sys/vfs.h"
8 9
9namespace FileSys { 10namespace FileSys {
10 11
12// An implementation of VfsFile that is backed by a statically-sized array
13template <std::size_t size>
14class ArrayVfsFile : public VfsFile {
15public:
16 ArrayVfsFile(std::array<u8, size> data, std::string name = "", VirtualDir parent = nullptr)
17 : data(data), name(std::move(name)), parent(std::move(parent)) {}
18
19 std::string GetName() const override {
20 return name;
21 }
22
23 std::size_t GetSize() const override {
24 return size;
25 }
26
27 bool Resize(std::size_t new_size) override {
28 return false;
29 }
30
31 std::shared_ptr<VfsDirectory> GetContainingDirectory() const override {
32 return parent;
33 }
34
35 bool IsWritable() const override {
36 return false;
37 }
38
39 bool IsReadable() const override {
40 return true;
41 }
42
43 std::size_t Read(u8* data_, std::size_t length, std::size_t offset) const override {
44 const auto read = std::min(length, size - offset);
45 std::memcpy(data_, data.data() + offset, read);
46 return read;
47 }
48
49 std::size_t Write(const u8* data, std::size_t length, std::size_t offset) override {
50 return 0;
51 }
52
53 bool Rename(std::string_view name) override {
54 this->name = name;
55 return true;
56 }
57
58private:
59 std::array<u8, size> data;
60 std::string name;
61 VirtualDir parent;
62};
63
11// An implementation of VfsFile that is backed by a vector optionally supplied upon construction 64// An implementation of VfsFile that is backed by a vector optionally supplied upon construction
12class VectorVfsFile : public VfsFile { 65class VectorVfsFile : public VfsFile {
13public: 66public:
diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp
index 1bf79b692..c8acde5b1 100644
--- a/src/core/hle/kernel/handle_table.cpp
+++ b/src/core/hle/kernel/handle_table.cpp
@@ -42,9 +42,10 @@ ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) {
42 u16 generation = next_generation++; 42 u16 generation = next_generation++;
43 43
44 // Overflow count so it fits in the 15 bits dedicated to the generation in the handle. 44 // Overflow count so it fits in the 15 bits dedicated to the generation in the handle.
45 // CTR-OS doesn't use generation 0, so skip straight to 1. 45 // Horizon OS uses zero to represent an invalid handle, so skip to 1.
46 if (next_generation >= (1 << 15)) 46 if (next_generation >= (1 << 15)) {
47 next_generation = 1; 47 next_generation = 1;
48 }
48 49
49 generations[slot] = generation; 50 generations[slot] = generation;
50 objects[slot] = std::move(obj); 51 objects[slot] = std::move(obj);
diff --git a/src/core/hle/kernel/handle_table.h b/src/core/hle/kernel/handle_table.h
index e3f3e3fb8..6b7927fd8 100644
--- a/src/core/hle/kernel/handle_table.h
+++ b/src/core/hle/kernel/handle_table.h
@@ -13,6 +13,7 @@
13namespace Kernel { 13namespace Kernel {
14 14
15enum KernelHandle : Handle { 15enum KernelHandle : Handle {
16 InvalidHandle = 0,
16 CurrentThread = 0xFFFF8000, 17 CurrentThread = 0xFFFF8000,
17 CurrentProcess = 0xFFFF8001, 18 CurrentProcess = 0xFFFF8001,
18}; 19};
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index 68d5376cb..61ce7d7e4 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -15,13 +15,14 @@
15#include "common/logging/log.h" 15#include "common/logging/log.h"
16#include "core/core.h" 16#include "core/core.h"
17#include "core/hle/ipc_helpers.h" 17#include "core/hle/ipc_helpers.h"
18#include "core/hle/kernel/event.h"
19#include "core/hle/kernel/handle_table.h" 18#include "core/hle/kernel/handle_table.h"
20#include "core/hle/kernel/hle_ipc.h" 19#include "core/hle/kernel/hle_ipc.h"
21#include "core/hle/kernel/kernel.h" 20#include "core/hle/kernel/kernel.h"
22#include "core/hle/kernel/object.h" 21#include "core/hle/kernel/object.h"
23#include "core/hle/kernel/process.h" 22#include "core/hle/kernel/process.h"
23#include "core/hle/kernel/readable_event.h"
24#include "core/hle/kernel/server_session.h" 24#include "core/hle/kernel/server_session.h"
25#include "core/hle/kernel/writable_event.h"
25#include "core/memory.h" 26#include "core/memory.h"
26 27
27namespace Kernel { 28namespace Kernel {
@@ -36,11 +37,9 @@ void SessionRequestHandler::ClientDisconnected(const SharedPtr<ServerSession>& s
36 boost::range::remove_erase(connected_sessions, server_session); 37 boost::range::remove_erase(connected_sessions, server_session);
37} 38}
38 39
39SharedPtr<Event> HLERequestContext::SleepClientThread(SharedPtr<Thread> thread, 40SharedPtr<WritableEvent> HLERequestContext::SleepClientThread(
40 const std::string& reason, u64 timeout, 41 SharedPtr<Thread> thread, const std::string& reason, u64 timeout, WakeupCallback&& callback,
41 WakeupCallback&& callback, 42 SharedPtr<WritableEvent> writable_event) {
42 Kernel::SharedPtr<Kernel::Event> event) {
43
44 // Put the client thread to sleep until the wait event is signaled or the timeout expires. 43 // Put the client thread to sleep until the wait event is signaled or the timeout expires.
45 thread->SetWakeupCallback([context = *this, callback]( 44 thread->SetWakeupCallback([context = *this, callback](
46 ThreadWakeupReason reason, SharedPtr<Thread> thread, 45 ThreadWakeupReason reason, SharedPtr<Thread> thread,
@@ -51,23 +50,25 @@ SharedPtr<Event> HLERequestContext::SleepClientThread(SharedPtr<Thread> thread,
51 return true; 50 return true;
52 }); 51 });
53 52
54 if (!event) { 53 auto& kernel = Core::System::GetInstance().Kernel();
54 if (!writable_event) {
55 // Create event if not provided 55 // Create event if not provided
56 auto& kernel = Core::System::GetInstance().Kernel(); 56 const auto pair = WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
57 event = 57 "HLE Pause Event: " + reason);
58 Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "HLE Pause Event: " + reason); 58 writable_event = pair.writable;
59 } 59 }
60 60
61 event->Clear(); 61 const auto readable_event{writable_event->GetReadableEvent()};
62 writable_event->Clear();
62 thread->SetStatus(ThreadStatus::WaitHLEEvent); 63 thread->SetStatus(ThreadStatus::WaitHLEEvent);
63 thread->SetWaitObjects({event}); 64 thread->SetWaitObjects({readable_event});
64 event->AddWaitingThread(thread); 65 readable_event->AddWaitingThread(thread);
65 66
66 if (timeout > 0) { 67 if (timeout > 0) {
67 thread->WakeAfterDelay(timeout); 68 thread->WakeAfterDelay(timeout);
68 } 69 }
69 70
70 return event; 71 return writable_event;
71} 72}
72 73
73HLERequestContext::HLERequestContext(SharedPtr<Kernel::ServerSession> server_session) 74HLERequestContext::HLERequestContext(SharedPtr<Kernel::ServerSession> server_session)
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
index a38e34b74..e5c0610cd 100644
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -24,10 +24,11 @@ class ServiceFrameworkBase;
24namespace Kernel { 24namespace Kernel {
25 25
26class Domain; 26class Domain;
27class Event;
28class HandleTable; 27class HandleTable;
29class HLERequestContext; 28class HLERequestContext;
30class Process; 29class Process;
30class ReadableEvent;
31class WritableEvent;
31 32
32/** 33/**
33 * Interface implemented by HLE Session handlers. 34 * Interface implemented by HLE Session handlers.
@@ -119,12 +120,13 @@ public:
119 * @param callback Callback to be invoked when the thread is resumed. This callback must write 120 * @param callback Callback to be invoked when the thread is resumed. This callback must write
120 * the entire command response once again, regardless of the state of it before this function 121 * the entire command response once again, regardless of the state of it before this function
121 * was called. 122 * was called.
122 * @param event Event to use to wake up the thread. If unspecified, an event will be created. 123 * @param writable_event Event to use to wake up the thread. If unspecified, an event will be
124 * created.
123 * @returns Event that when signaled will resume the thread and call the callback function. 125 * @returns Event that when signaled will resume the thread and call the callback function.
124 */ 126 */
125 SharedPtr<Event> SleepClientThread(SharedPtr<Thread> thread, const std::string& reason, 127 SharedPtr<WritableEvent> SleepClientThread(SharedPtr<Thread> thread, const std::string& reason,
126 u64 timeout, WakeupCallback&& callback, 128 u64 timeout, WakeupCallback&& callback,
127 Kernel::SharedPtr<Kernel::Event> event = nullptr); 129 SharedPtr<WritableEvent> writable_event = nullptr);
128 130
129 /// Populates this context with data from the requesting process/thread. 131 /// Populates this context with data from the requesting process/thread.
130 ResultCode PopulateFromIncomingCommandBuffer(const HandleTable& handle_table, 132 ResultCode PopulateFromIncomingCommandBuffer(const HandleTable& handle_table,
diff --git a/src/core/hle/kernel/object.cpp b/src/core/hle/kernel/object.cpp
index d87a62bb9..bb1b68778 100644
--- a/src/core/hle/kernel/object.cpp
+++ b/src/core/hle/kernel/object.cpp
@@ -13,7 +13,7 @@ Object::~Object() = default;
13 13
14bool Object::IsWaitable() const { 14bool Object::IsWaitable() const {
15 switch (GetHandleType()) { 15 switch (GetHandleType()) {
16 case HandleType::Event: 16 case HandleType::ReadableEvent:
17 case HandleType::Thread: 17 case HandleType::Thread:
18 case HandleType::Timer: 18 case HandleType::Timer:
19 case HandleType::ServerPort: 19 case HandleType::ServerPort:
@@ -21,6 +21,7 @@ bool Object::IsWaitable() const {
21 return true; 21 return true;
22 22
23 case HandleType::Unknown: 23 case HandleType::Unknown:
24 case HandleType::WritableEvent:
24 case HandleType::SharedMemory: 25 case HandleType::SharedMemory:
25 case HandleType::Process: 26 case HandleType::Process:
26 case HandleType::AddressArbiter: 27 case HandleType::AddressArbiter:
diff --git a/src/core/hle/kernel/object.h b/src/core/hle/kernel/object.h
index c9f4d0bb3..f1606a204 100644
--- a/src/core/hle/kernel/object.h
+++ b/src/core/hle/kernel/object.h
@@ -19,7 +19,8 @@ using Handle = u32;
19 19
20enum class HandleType : u32 { 20enum class HandleType : u32 {
21 Unknown, 21 Unknown,
22 Event, 22 WritableEvent,
23 ReadableEvent,
23 SharedMemory, 24 SharedMemory,
24 Thread, 25 Thread,
25 Process, 26 Process,
@@ -33,9 +34,9 @@ enum class HandleType : u32 {
33}; 34};
34 35
35enum class ResetType { 36enum class ResetType {
36 OneShot, 37 OneShot, ///< Reset automatically on object acquisition
37 Sticky, 38 Sticky, ///< Never reset automatically
38 Pulse, 39 Pulse, ///< Reset automatically on wakeup
39}; 40};
40 41
41class Object : NonCopyable { 42class Object : NonCopyable {
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 7ca538401..4ecb8c926 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -44,6 +44,10 @@ SharedPtr<Process> Process::Create(KernelCore& kernel, std::string&& name) {
44 return process; 44 return process;
45} 45}
46 46
47SharedPtr<ResourceLimit> Process::GetResourceLimit() const {
48 return resource_limit;
49}
50
47void Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) { 51void Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) {
48 program_id = metadata.GetTitleID(); 52 program_id = metadata.GetTitleID();
49 is_64bit_process = metadata.Is64BitProgram(); 53 is_64bit_process = metadata.Is64BitProgram();
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index ada845c7f..49345aa66 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -171,14 +171,7 @@ public:
171 } 171 }
172 172
173 /// Gets the resource limit descriptor for this process 173 /// Gets the resource limit descriptor for this process
174 ResourceLimit& GetResourceLimit() { 174 SharedPtr<ResourceLimit> GetResourceLimit() const;
175 return *resource_limit;
176 }
177
178 /// Gets the resource limit descriptor for this process
179 const ResourceLimit& GetResourceLimit() const {
180 return *resource_limit;
181 }
182 175
183 /// Gets the default CPU ID for this process 176 /// Gets the default CPU ID for this process
184 u8 GetDefaultProcessorID() const { 177 u8 GetDefaultProcessorID() const {
diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/readable_event.cpp
index 8967e602e..92e16b4e6 100644
--- a/src/core/hle/kernel/event.cpp
+++ b/src/core/hle/kernel/readable_event.cpp
@@ -4,46 +4,37 @@
4 4
5#include <algorithm> 5#include <algorithm>
6#include "common/assert.h" 6#include "common/assert.h"
7#include "core/hle/kernel/event.h"
8#include "core/hle/kernel/object.h" 7#include "core/hle/kernel/object.h"
8#include "core/hle/kernel/readable_event.h"
9#include "core/hle/kernel/thread.h" 9#include "core/hle/kernel/thread.h"
10#include "core/hle/kernel/writable_event.h"
10 11
11namespace Kernel { 12namespace Kernel {
12 13
13Event::Event(KernelCore& kernel) : WaitObject{kernel} {} 14ReadableEvent::ReadableEvent(KernelCore& kernel) : WaitObject{kernel} {}
14Event::~Event() = default; 15ReadableEvent::~ReadableEvent() = default;
15 16
16SharedPtr<Event> Event::Create(KernelCore& kernel, ResetType reset_type, std::string name) { 17bool ReadableEvent::ShouldWait(Thread* thread) const {
17 SharedPtr<Event> evt(new Event(kernel));
18
19 evt->signaled = false;
20 evt->reset_type = reset_type;
21 evt->name = std::move(name);
22
23 return evt;
24}
25
26bool Event::ShouldWait(Thread* thread) const {
27 return !signaled; 18 return !signaled;
28} 19}
29 20
30void Event::Acquire(Thread* thread) { 21void ReadableEvent::Acquire(Thread* thread) {
31 ASSERT_MSG(!ShouldWait(thread), "object unavailable!"); 22 ASSERT_MSG(!ShouldWait(thread), "object unavailable!");
32 23
33 if (reset_type == ResetType::OneShot) 24 if (reset_type == ResetType::OneShot)
34 signaled = false; 25 signaled = false;
35} 26}
36 27
37void Event::Signal() { 28void ReadableEvent::Signal() {
38 signaled = true; 29 signaled = true;
39 WakeupAllWaitingThreads(); 30 WakeupAllWaitingThreads();
40} 31}
41 32
42void Event::Clear() { 33void ReadableEvent::Clear() {
43 signaled = false; 34 signaled = false;
44} 35}
45 36
46void Event::WakeupAllWaitingThreads() { 37void ReadableEvent::WakeupAllWaitingThreads() {
47 WaitObject::WakeupAllWaitingThreads(); 38 WaitObject::WakeupAllWaitingThreads();
48 39
49 if (reset_type == ResetType::Pulse) 40 if (reset_type == ResetType::Pulse)
diff --git a/src/core/hle/kernel/readable_event.h b/src/core/hle/kernel/readable_event.h
new file mode 100644
index 000000000..867ff3051
--- /dev/null
+++ b/src/core/hle/kernel/readable_event.h
@@ -0,0 +1,55 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/hle/kernel/object.h"
8#include "core/hle/kernel/wait_object.h"
9
10namespace Kernel {
11
12class KernelCore;
13class WritableEvent;
14
15class ReadableEvent final : public WaitObject {
16 friend class WritableEvent;
17
18public:
19 ~ReadableEvent() override;
20
21 std::string GetTypeName() const override {
22 return "ReadableEvent";
23 }
24 std::string GetName() const override {
25 return name;
26 }
27
28 ResetType GetResetType() const {
29 return reset_type;
30 }
31
32 static const HandleType HANDLE_TYPE = HandleType::ReadableEvent;
33 HandleType GetHandleType() const override {
34 return HANDLE_TYPE;
35 }
36
37 bool ShouldWait(Thread* thread) const override;
38 void Acquire(Thread* thread) override;
39
40 void WakeupAllWaitingThreads() override;
41
42 void Clear();
43
44private:
45 explicit ReadableEvent(KernelCore& kernel);
46
47 void Signal();
48
49 ResetType reset_type;
50 bool signaled;
51
52 std::string name; ///< Name of event (optional)
53};
54
55} // namespace Kernel
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 5e9660a48..e6c77f9db 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -20,21 +20,21 @@
20#include "core/hle/kernel/address_arbiter.h" 20#include "core/hle/kernel/address_arbiter.h"
21#include "core/hle/kernel/client_port.h" 21#include "core/hle/kernel/client_port.h"
22#include "core/hle/kernel/client_session.h" 22#include "core/hle/kernel/client_session.h"
23#include "core/hle/kernel/event.h"
24#include "core/hle/kernel/handle_table.h" 23#include "core/hle/kernel/handle_table.h"
25#include "core/hle/kernel/kernel.h" 24#include "core/hle/kernel/kernel.h"
26#include "core/hle/kernel/mutex.h" 25#include "core/hle/kernel/mutex.h"
27#include "core/hle/kernel/process.h" 26#include "core/hle/kernel/process.h"
27#include "core/hle/kernel/readable_event.h"
28#include "core/hle/kernel/resource_limit.h" 28#include "core/hle/kernel/resource_limit.h"
29#include "core/hle/kernel/scheduler.h" 29#include "core/hle/kernel/scheduler.h"
30#include "core/hle/kernel/shared_memory.h" 30#include "core/hle/kernel/shared_memory.h"
31#include "core/hle/kernel/svc.h" 31#include "core/hle/kernel/svc.h"
32#include "core/hle/kernel/svc_wrap.h" 32#include "core/hle/kernel/svc_wrap.h"
33#include "core/hle/kernel/thread.h" 33#include "core/hle/kernel/thread.h"
34#include "core/hle/kernel/writable_event.h"
34#include "core/hle/lock.h" 35#include "core/hle/lock.h"
35#include "core/hle/result.h" 36#include "core/hle/result.h"
36#include "core/hle/service/service.h" 37#include "core/hle/service/service.h"
37#include "core/settings.h"
38 38
39namespace Kernel { 39namespace Kernel {
40namespace { 40namespace {
@@ -662,7 +662,7 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
662 TotalMemoryUsage = 6, 662 TotalMemoryUsage = 6,
663 TotalHeapUsage = 7, 663 TotalHeapUsage = 7,
664 IsCurrentProcessBeingDebugged = 8, 664 IsCurrentProcessBeingDebugged = 8,
665 ResourceHandleLimit = 9, 665 RegisterResourceLimit = 9,
666 IdleTickCount = 10, 666 IdleTickCount = 10,
667 RandomEntropy = 11, 667 RandomEntropy = 11,
668 PerformanceCounter = 0xF0000002, 668 PerformanceCounter = 0xF0000002,
@@ -682,37 +682,137 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
682 ThreadTickCount = 0xF0000002, 682 ThreadTickCount = 0xF0000002,
683 }; 683 };
684 684
685 const auto* current_process = Core::CurrentProcess(); 685 const auto info_id_type = static_cast<GetInfoType>(info_id);
686 const auto& vm_manager = current_process->VMManager();
687 686
688 switch (static_cast<GetInfoType>(info_id)) { 687 switch (info_id_type) {
689 case GetInfoType::AllowedCpuIdBitmask: 688 case GetInfoType::AllowedCpuIdBitmask:
690 *result = current_process->GetAllowedProcessorMask();
691 break;
692 case GetInfoType::AllowedThreadPrioBitmask: 689 case GetInfoType::AllowedThreadPrioBitmask:
693 *result = current_process->GetAllowedThreadPriorityMask();
694 break;
695 case GetInfoType::MapRegionBaseAddr: 690 case GetInfoType::MapRegionBaseAddr:
696 *result = vm_manager.GetMapRegionBaseAddress();
697 break;
698 case GetInfoType::MapRegionSize: 691 case GetInfoType::MapRegionSize:
699 *result = vm_manager.GetMapRegionSize();
700 break;
701 case GetInfoType::HeapRegionBaseAddr: 692 case GetInfoType::HeapRegionBaseAddr:
702 *result = vm_manager.GetHeapRegionBaseAddress();
703 break;
704 case GetInfoType::HeapRegionSize: 693 case GetInfoType::HeapRegionSize:
705 *result = vm_manager.GetHeapRegionSize(); 694 case GetInfoType::ASLRRegionBaseAddr:
706 break; 695 case GetInfoType::ASLRRegionSize:
696 case GetInfoType::NewMapRegionBaseAddr:
697 case GetInfoType::NewMapRegionSize:
707 case GetInfoType::TotalMemoryUsage: 698 case GetInfoType::TotalMemoryUsage:
708 *result = vm_manager.GetTotalMemoryUsage();
709 break;
710 case GetInfoType::TotalHeapUsage: 699 case GetInfoType::TotalHeapUsage:
711 *result = vm_manager.GetTotalHeapUsage(); 700 case GetInfoType::IsVirtualAddressMemoryEnabled:
712 break; 701 case GetInfoType::PersonalMmHeapUsage:
702 case GetInfoType::TitleId:
703 case GetInfoType::UserExceptionContextAddr: {
704 if (info_sub_id != 0) {
705 return ERR_INVALID_ENUM_VALUE;
706 }
707
708 const auto& current_process_handle_table = Core::CurrentProcess()->GetHandleTable();
709 const auto process = current_process_handle_table.Get<Process>(static_cast<Handle>(handle));
710 if (!process) {
711 return ERR_INVALID_HANDLE;
712 }
713
714 switch (info_id_type) {
715 case GetInfoType::AllowedCpuIdBitmask:
716 *result = process->GetAllowedProcessorMask();
717 return RESULT_SUCCESS;
718
719 case GetInfoType::AllowedThreadPrioBitmask:
720 *result = process->GetAllowedThreadPriorityMask();
721 return RESULT_SUCCESS;
722
723 case GetInfoType::MapRegionBaseAddr:
724 *result = process->VMManager().GetMapRegionBaseAddress();
725 return RESULT_SUCCESS;
726
727 case GetInfoType::MapRegionSize:
728 *result = process->VMManager().GetMapRegionSize();
729 return RESULT_SUCCESS;
730
731 case GetInfoType::HeapRegionBaseAddr:
732 *result = process->VMManager().GetHeapRegionBaseAddress();
733 return RESULT_SUCCESS;
734
735 case GetInfoType::HeapRegionSize:
736 *result = process->VMManager().GetHeapRegionSize();
737 return RESULT_SUCCESS;
738
739 case GetInfoType::ASLRRegionBaseAddr:
740 *result = process->VMManager().GetASLRRegionBaseAddress();
741 return RESULT_SUCCESS;
742
743 case GetInfoType::ASLRRegionSize:
744 *result = process->VMManager().GetASLRRegionSize();
745 return RESULT_SUCCESS;
746
747 case GetInfoType::NewMapRegionBaseAddr:
748 *result = process->VMManager().GetNewMapRegionBaseAddress();
749 return RESULT_SUCCESS;
750
751 case GetInfoType::NewMapRegionSize:
752 *result = process->VMManager().GetNewMapRegionSize();
753 return RESULT_SUCCESS;
754
755 case GetInfoType::TotalMemoryUsage:
756 *result = process->VMManager().GetTotalMemoryUsage();
757 return RESULT_SUCCESS;
758
759 case GetInfoType::TotalHeapUsage:
760 *result = process->VMManager().GetTotalHeapUsage();
761 return RESULT_SUCCESS;
762
763 case GetInfoType::IsVirtualAddressMemoryEnabled:
764 *result = process->IsVirtualMemoryEnabled();
765 return RESULT_SUCCESS;
766
767 case GetInfoType::TitleId:
768 *result = process->GetTitleID();
769 return RESULT_SUCCESS;
770
771 case GetInfoType::UserExceptionContextAddr:
772 LOG_WARNING(Kernel_SVC,
773 "(STUBBED) Attempted to query user exception context address, returned 0");
774 *result = 0;
775 return RESULT_SUCCESS;
776
777 default:
778 break;
779 }
780
781 LOG_WARNING(Kernel_SVC, "(STUBBED) Unimplemented svcGetInfo id=0x{:016X}", info_id);
782 return ERR_INVALID_ENUM_VALUE;
783 }
784
713 case GetInfoType::IsCurrentProcessBeingDebugged: 785 case GetInfoType::IsCurrentProcessBeingDebugged:
714 *result = 0; 786 *result = 0;
715 break; 787 return RESULT_SUCCESS;
788
789 case GetInfoType::RegisterResourceLimit: {
790 if (handle != 0) {
791 return ERR_INVALID_HANDLE;
792 }
793
794 if (info_sub_id != 0) {
795 return ERR_INVALID_COMBINATION;
796 }
797
798 Process* const current_process = Core::CurrentProcess();
799 HandleTable& handle_table = current_process->GetHandleTable();
800 const auto resource_limit = current_process->GetResourceLimit();
801 if (!resource_limit) {
802 *result = KernelHandle::InvalidHandle;
803 // Yes, the kernel considers this a successful operation.
804 return RESULT_SUCCESS;
805 }
806
807 const auto table_result = handle_table.Create(resource_limit);
808 if (table_result.Failed()) {
809 return table_result.Code();
810 }
811
812 *result = *table_result;
813 return RESULT_SUCCESS;
814 }
815
716 case GetInfoType::RandomEntropy: 816 case GetInfoType::RandomEntropy:
717 if (handle != 0) { 817 if (handle != 0) {
718 LOG_ERROR(Kernel_SVC, "Process Handle is non zero, expected 0 result but got {:016X}", 818 LOG_ERROR(Kernel_SVC, "Process Handle is non zero, expected 0 result but got {:016X}",
@@ -726,37 +826,15 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
726 return ERR_INVALID_COMBINATION; 826 return ERR_INVALID_COMBINATION;
727 } 827 }
728 828
729 *result = current_process->GetRandomEntropy(info_sub_id); 829 *result = Core::CurrentProcess()->GetRandomEntropy(info_sub_id);
730 return RESULT_SUCCESS; 830 return RESULT_SUCCESS;
731 break; 831
732 case GetInfoType::ASLRRegionBaseAddr:
733 *result = vm_manager.GetASLRRegionBaseAddress();
734 break;
735 case GetInfoType::ASLRRegionSize:
736 *result = vm_manager.GetASLRRegionSize();
737 break;
738 case GetInfoType::NewMapRegionBaseAddr:
739 *result = vm_manager.GetNewMapRegionBaseAddress();
740 break;
741 case GetInfoType::NewMapRegionSize:
742 *result = vm_manager.GetNewMapRegionSize();
743 break;
744 case GetInfoType::IsVirtualAddressMemoryEnabled:
745 *result = current_process->IsVirtualMemoryEnabled();
746 break;
747 case GetInfoType::TitleId:
748 *result = current_process->GetTitleID();
749 break;
750 case GetInfoType::PrivilegedProcessId: 832 case GetInfoType::PrivilegedProcessId:
751 LOG_WARNING(Kernel_SVC, 833 LOG_WARNING(Kernel_SVC,
752 "(STUBBED) Attempted to query privileged process id bounds, returned 0"); 834 "(STUBBED) Attempted to query privileged process id bounds, returned 0");
753 *result = 0; 835 *result = 0;
754 break; 836 return RESULT_SUCCESS;
755 case GetInfoType::UserExceptionContextAddr: 837
756 LOG_WARNING(Kernel_SVC,
757 "(STUBBED) Attempted to query user exception context address, returned 0");
758 *result = 0;
759 break;
760 case GetInfoType::ThreadTickCount: { 838 case GetInfoType::ThreadTickCount: {
761 constexpr u64 num_cpus = 4; 839 constexpr u64 num_cpus = 4;
762 if (info_sub_id != 0xFFFFFFFFFFFFFFFF && info_sub_id >= num_cpus) { 840 if (info_sub_id != 0xFFFFFFFFFFFFFFFF && info_sub_id >= num_cpus) {
@@ -766,7 +844,7 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
766 } 844 }
767 845
768 const auto thread = 846 const auto thread =
769 current_process->GetHandleTable().Get<Thread>(static_cast<Handle>(handle)); 847 Core::CurrentProcess()->GetHandleTable().Get<Thread>(static_cast<Handle>(handle));
770 if (!thread) { 848 if (!thread) {
771 LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", 849 LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}",
772 static_cast<Handle>(handle)); 850 static_cast<Handle>(handle));
@@ -789,14 +867,13 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
789 } 867 }
790 868
791 *result = out_ticks; 869 *result = out_ticks;
792 break; 870 return RESULT_SUCCESS;
793 } 871 }
872
794 default: 873 default:
795 LOG_WARNING(Kernel_SVC, "(STUBBED) Unimplemented svcGetInfo id=0x{:016X}", info_id); 874 LOG_WARNING(Kernel_SVC, "(STUBBED) Unimplemented svcGetInfo id=0x{:016X}", info_id);
796 return ERR_INVALID_ENUM_VALUE; 875 return ERR_INVALID_ENUM_VALUE;
797 } 876 }
798
799 return RESULT_SUCCESS;
800} 877}
801 878
802/// Sets the thread activity 879/// Sets the thread activity
@@ -1042,9 +1119,9 @@ static void ExitProcess() {
1042static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, VAddr stack_top, 1119static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, VAddr stack_top,
1043 u32 priority, s32 processor_id) { 1120 u32 priority, s32 processor_id) {
1044 LOG_TRACE(Kernel_SVC, 1121 LOG_TRACE(Kernel_SVC,
1045 "called entrypoint=0x{:08X} ({}), arg=0x{:08X}, stacktop=0x{:08X}, " 1122 "called entrypoint=0x{:08X}, arg=0x{:08X}, stacktop=0x{:08X}, "
1046 "threadpriority=0x{:08X}, processorid=0x{:08X} : created handle=0x{:08X}", 1123 "threadpriority=0x{:08X}, processorid=0x{:08X} : created handle=0x{:08X}",
1047 entry_point, name, arg, stack_top, priority, processor_id, *out_handle); 1124 entry_point, arg, stack_top, priority, processor_id, *out_handle);
1048 1125
1049 if (priority > THREADPRIO_LOWEST) { 1126 if (priority > THREADPRIO_LOWEST) {
1050 LOG_ERROR(Kernel_SVC, "An invalid priority was specified, expected {} but got {}", 1127 LOG_ERROR(Kernel_SVC, "An invalid priority was specified, expected {} but got {}",
@@ -1361,7 +1438,7 @@ static ResultCode ResetSignal(Handle handle) {
1361 LOG_DEBUG(Kernel_SVC, "called handle 0x{:08X}", handle); 1438 LOG_DEBUG(Kernel_SVC, "called handle 0x{:08X}", handle);
1362 1439
1363 const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); 1440 const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
1364 auto event = handle_table.Get<Event>(handle); 1441 auto event = handle_table.Get<ReadableEvent>(handle);
1365 1442
1366 ASSERT(event != nullptr); 1443 ASSERT(event != nullptr);
1367 1444
@@ -1520,17 +1597,67 @@ static ResultCode CreateSharedMemory(Handle* handle, u64 size, u32 local_permiss
1520 return RESULT_SUCCESS; 1597 return RESULT_SUCCESS;
1521} 1598}
1522 1599
1600static ResultCode CreateEvent(Handle* write_handle, Handle* read_handle) {
1601 LOG_DEBUG(Kernel_SVC, "called");
1602
1603 auto& kernel = Core::System::GetInstance().Kernel();
1604 const auto [readable_event, writable_event] =
1605 WritableEvent::CreateEventPair(kernel, ResetType::Sticky, "CreateEvent");
1606
1607 HandleTable& handle_table = kernel.CurrentProcess()->GetHandleTable();
1608
1609 const auto write_create_result = handle_table.Create(writable_event);
1610 if (write_create_result.Failed()) {
1611 return write_create_result.Code();
1612 }
1613 *write_handle = *write_create_result;
1614
1615 const auto read_create_result = handle_table.Create(readable_event);
1616 if (read_create_result.Failed()) {
1617 handle_table.Close(*write_create_result);
1618 return read_create_result.Code();
1619 }
1620 *read_handle = *read_create_result;
1621
1622 LOG_DEBUG(Kernel_SVC,
1623 "successful. Writable event handle=0x{:08X}, Readable event handle=0x{:08X}",
1624 *write_create_result, *read_create_result);
1625 return RESULT_SUCCESS;
1626}
1627
1523static ResultCode ClearEvent(Handle handle) { 1628static ResultCode ClearEvent(Handle handle) {
1524 LOG_TRACE(Kernel_SVC, "called, event=0x{:08X}", handle); 1629 LOG_TRACE(Kernel_SVC, "called, event=0x{:08X}", handle);
1525 1630
1526 const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); 1631 const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
1527 SharedPtr<Event> evt = handle_table.Get<Event>(handle); 1632
1528 if (evt == nullptr) { 1633 auto writable_event = handle_table.Get<WritableEvent>(handle);
1529 LOG_ERROR(Kernel_SVC, "Event handle does not exist, handle=0x{:08X}", handle); 1634 if (writable_event) {
1635 writable_event->Clear();
1636 return RESULT_SUCCESS;
1637 }
1638
1639 auto readable_event = handle_table.Get<ReadableEvent>(handle);
1640 if (readable_event) {
1641 readable_event->Clear();
1642 return RESULT_SUCCESS;
1643 }
1644
1645 LOG_ERROR(Kernel_SVC, "Event handle does not exist, handle=0x{:08X}", handle);
1646 return ERR_INVALID_HANDLE;
1647}
1648
1649static ResultCode SignalEvent(Handle handle) {
1650 LOG_DEBUG(Kernel_SVC, "called. Handle=0x{:08X}", handle);
1651
1652 HandleTable& handle_table = Core::CurrentProcess()->GetHandleTable();
1653 auto writable_event = handle_table.Get<WritableEvent>(handle);
1654
1655 if (!writable_event) {
1656 LOG_ERROR(Kernel_SVC, "Non-existent writable event handle used (0x{:08X})", handle);
1530 return ERR_INVALID_HANDLE; 1657 return ERR_INVALID_HANDLE;
1531 } 1658 }
1532 1659
1533 evt->Clear(); 1660 writable_event->Signal();
1534 return RESULT_SUCCESS; 1661 return RESULT_SUCCESS;
1535} 1662}
1536 1663
@@ -1669,7 +1796,7 @@ static const FunctionDef SVC_Table[] = {
1669 {0x0E, SvcWrap<GetThreadCoreMask>, "GetThreadCoreMask"}, 1796 {0x0E, SvcWrap<GetThreadCoreMask>, "GetThreadCoreMask"},
1670 {0x0F, SvcWrap<SetThreadCoreMask>, "SetThreadCoreMask"}, 1797 {0x0F, SvcWrap<SetThreadCoreMask>, "SetThreadCoreMask"},
1671 {0x10, SvcWrap<GetCurrentProcessorNumber>, "GetCurrentProcessorNumber"}, 1798 {0x10, SvcWrap<GetCurrentProcessorNumber>, "GetCurrentProcessorNumber"},
1672 {0x11, nullptr, "SignalEvent"}, 1799 {0x11, SvcWrap<SignalEvent>, "SignalEvent"},
1673 {0x12, SvcWrap<ClearEvent>, "ClearEvent"}, 1800 {0x12, SvcWrap<ClearEvent>, "ClearEvent"},
1674 {0x13, SvcWrap<MapSharedMemory>, "MapSharedMemory"}, 1801 {0x13, SvcWrap<MapSharedMemory>, "MapSharedMemory"},
1675 {0x14, SvcWrap<UnmapSharedMemory>, "UnmapSharedMemory"}, 1802 {0x14, SvcWrap<UnmapSharedMemory>, "UnmapSharedMemory"},
@@ -1721,7 +1848,7 @@ static const FunctionDef SVC_Table[] = {
1721 {0x42, nullptr, "ReplyAndReceiveLight"}, 1848 {0x42, nullptr, "ReplyAndReceiveLight"},
1722 {0x43, nullptr, "ReplyAndReceive"}, 1849 {0x43, nullptr, "ReplyAndReceive"},
1723 {0x44, nullptr, "ReplyAndReceiveWithUserBuffer"}, 1850 {0x44, nullptr, "ReplyAndReceiveWithUserBuffer"},
1724 {0x45, nullptr, "CreateEvent"}, 1851 {0x45, SvcWrap<CreateEvent>, "CreateEvent"},
1725 {0x46, nullptr, "Unknown"}, 1852 {0x46, nullptr, "Unknown"},
1726 {0x47, nullptr, "Unknown"}, 1853 {0x47, nullptr, "Unknown"},
1727 {0x48, nullptr, "MapPhysicalMemoryUnsafe"}, 1854 {0x48, nullptr, "MapPhysicalMemoryUnsafe"},
diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h
index fa1116624..24aef46c9 100644
--- a/src/core/hle/kernel/svc_wrap.h
+++ b/src/core/hle/kernel/svc_wrap.h
@@ -59,6 +59,19 @@ void SvcWrap() {
59 FuncReturn(retval); 59 FuncReturn(retval);
60} 60}
61 61
62template <ResultCode func(u32*, u32*)>
63void SvcWrap() {
64 u32 param_1 = 0;
65 u32 param_2 = 0;
66 const u32 retval = func(&param_1, &param_2).raw;
67
68 auto& arm_interface = Core::CurrentArmInterface();
69 arm_interface.SetReg(1, param_1);
70 arm_interface.SetReg(2, param_2);
71
72 FuncReturn(retval);
73}
74
62template <ResultCode func(u32*, u64)> 75template <ResultCode func(u32*, u64)>
63void SvcWrap() { 76void SvcWrap() {
64 u32 param_1 = 0; 77 u32 param_1 = 0;
diff --git a/src/core/hle/kernel/writable_event.cpp b/src/core/hle/kernel/writable_event.cpp
new file mode 100644
index 000000000..a58ea6ec8
--- /dev/null
+++ b/src/core/hle/kernel/writable_event.cpp
@@ -0,0 +1,52 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include "common/assert.h"
7#include "core/hle/kernel/kernel.h"
8#include "core/hle/kernel/object.h"
9#include "core/hle/kernel/readable_event.h"
10#include "core/hle/kernel/thread.h"
11#include "core/hle/kernel/writable_event.h"
12
13namespace Kernel {
14
15WritableEvent::WritableEvent(KernelCore& kernel) : Object{kernel} {}
16WritableEvent::~WritableEvent() = default;
17
18EventPair WritableEvent::CreateEventPair(KernelCore& kernel, ResetType reset_type,
19 std::string name) {
20 SharedPtr<WritableEvent> writable_event(new WritableEvent(kernel));
21 SharedPtr<ReadableEvent> readable_event(new ReadableEvent(kernel));
22
23 writable_event->name = name + ":Writable";
24 writable_event->readable = readable_event;
25 readable_event->name = name + ":Readable";
26 readable_event->signaled = false;
27 readable_event->reset_type = reset_type;
28
29 return {std::move(readable_event), std::move(writable_event)};
30}
31
32SharedPtr<ReadableEvent> WritableEvent::GetReadableEvent() const {
33 return readable;
34}
35
36ResetType WritableEvent::GetResetType() const {
37 return readable->reset_type;
38}
39
40void WritableEvent::Signal() {
41 readable->Signal();
42}
43
44void WritableEvent::Clear() {
45 readable->Clear();
46}
47
48bool WritableEvent::IsSignaled() const {
49 return readable->signaled;
50}
51
52} // namespace Kernel
diff --git a/src/core/hle/kernel/event.h b/src/core/hle/kernel/writable_event.h
index 27d6126b0..8fa8d68ee 100644
--- a/src/core/hle/kernel/event.h
+++ b/src/core/hle/kernel/writable_event.h
@@ -11,49 +11,52 @@
11namespace Kernel { 11namespace Kernel {
12 12
13class KernelCore; 13class KernelCore;
14class ReadableEvent;
15class WritableEvent;
14 16
15class Event final : public WaitObject { 17struct EventPair {
18 SharedPtr<ReadableEvent> readable;
19 SharedPtr<WritableEvent> writable;
20};
21
22class WritableEvent final : public Object {
16public: 23public:
24 ~WritableEvent() override;
25
17 /** 26 /**
18 * Creates an event 27 * Creates an event
19 * @param kernel The kernel instance to create this event under. 28 * @param kernel The kernel instance to create this event under.
20 * @param reset_type ResetType describing how to create event 29 * @param reset_type ResetType describing how to create event
21 * @param name Optional name of event 30 * @param name Optional name of event
22 */ 31 */
23 static SharedPtr<Event> Create(KernelCore& kernel, ResetType reset_type, 32 static EventPair CreateEventPair(KernelCore& kernel, ResetType reset_type,
24 std::string name = "Unknown"); 33 std::string name = "Unknown");
25 34
26 std::string GetTypeName() const override { 35 std::string GetTypeName() const override {
27 return "Event"; 36 return "WritableEvent";
28 } 37 }
29 std::string GetName() const override { 38 std::string GetName() const override {
30 return name; 39 return name;
31 } 40 }
32 41
33 static const HandleType HANDLE_TYPE = HandleType::Event; 42 static const HandleType HANDLE_TYPE = HandleType::WritableEvent;
34 HandleType GetHandleType() const override { 43 HandleType GetHandleType() const override {
35 return HANDLE_TYPE; 44 return HANDLE_TYPE;
36 } 45 }
37 46
38 ResetType GetResetType() const { 47 SharedPtr<ReadableEvent> GetReadableEvent() const;
39 return reset_type;
40 }
41
42 bool ShouldWait(Thread* thread) const override;
43 void Acquire(Thread* thread) override;
44 48
45 void WakeupAllWaitingThreads() override; 49 ResetType GetResetType() const;
46 50
47 void Signal(); 51 void Signal();
48 void Clear(); 52 void Clear();
53 bool IsSignaled() const;
49 54
50private: 55private:
51 explicit Event(KernelCore& kernel); 56 explicit WritableEvent(KernelCore& kernel);
52 ~Event() override;
53 57
54 ResetType reset_type; ///< Current ResetType 58 SharedPtr<ReadableEvent> readable;
55 59
56 bool signaled; ///< Whether the event has already been signaled
57 std::string name; ///< Name of event (optional) 60 std::string name; ///< Name of event (optional)
58}; 61};
59 62
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index d595c37b0..3a7b6da84 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -9,9 +9,11 @@
9#include "audio_core/audio_renderer.h" 9#include "audio_core/audio_renderer.h"
10#include "core/core.h" 10#include "core/core.h"
11#include "core/hle/ipc_helpers.h" 11#include "core/hle/ipc_helpers.h"
12#include "core/hle/kernel/event.h" 12#include "core/hle/kernel/kernel.h"
13#include "core/hle/kernel/process.h" 13#include "core/hle/kernel/process.h"
14#include "core/hle/kernel/readable_event.h"
14#include "core/hle/kernel/shared_memory.h" 15#include "core/hle/kernel/shared_memory.h"
16#include "core/hle/kernel/writable_event.h"
15#include "core/hle/service/acc/profile_manager.h" 17#include "core/hle/service/acc/profile_manager.h"
16#include "core/hle/service/am/am.h" 18#include "core/hle/service/am/am.h"
17#include "core/hle/service/am/applet_ae.h" 19#include "core/hle/service/am/applet_ae.h"
@@ -208,8 +210,8 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger
208 RegisterHandlers(functions); 210 RegisterHandlers(functions);
209 211
210 auto& kernel = Core::System::GetInstance().Kernel(); 212 auto& kernel = Core::System::GetInstance().Kernel();
211 launchable_event = 213 launchable_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
212 Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "ISelfController:LaunchableEvent"); 214 "ISelfController:LaunchableEvent");
213} 215}
214 216
215ISelfController::~ISelfController() = default; 217ISelfController::~ISelfController() = default;
@@ -295,11 +297,11 @@ void ISelfController::UnlockExit(Kernel::HLERequestContext& ctx) {
295void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx) { 297void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx) {
296 LOG_WARNING(Service_AM, "(STUBBED) called"); 298 LOG_WARNING(Service_AM, "(STUBBED) called");
297 299
298 launchable_event->Signal(); 300 launchable_event.writable->Signal();
299 301
300 IPC::ResponseBuilder rb{ctx, 2, 1}; 302 IPC::ResponseBuilder rb{ctx, 2, 1};
301 rb.Push(RESULT_SUCCESS); 303 rb.Push(RESULT_SUCCESS);
302 rb.PushCopyObjects(launchable_event); 304 rb.PushCopyObjects(launchable_event.readable);
303} 305}
304 306
305void ISelfController::SetScreenShotImageOrientation(Kernel::HLERequestContext& ctx) { 307void ISelfController::SetScreenShotImageOrientation(Kernel::HLERequestContext& ctx) {
@@ -348,36 +350,38 @@ void ISelfController::GetIdleTimeDetectionExtension(Kernel::HLERequestContext& c
348 350
349AppletMessageQueue::AppletMessageQueue() { 351AppletMessageQueue::AppletMessageQueue() {
350 auto& kernel = Core::System::GetInstance().Kernel(); 352 auto& kernel = Core::System::GetInstance().Kernel();
351 on_new_message = Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, 353 on_new_message = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
352 "AMMessageQueue:OnMessageRecieved"); 354 "AMMessageQueue:OnMessageRecieved");
353 on_operation_mode_changed = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, 355 on_operation_mode_changed = Kernel::WritableEvent::CreateEventPair(
354 "AMMessageQueue:OperationModeChanged"); 356 kernel, Kernel::ResetType::OneShot, "AMMessageQueue:OperationModeChanged");
355} 357}
356 358
357AppletMessageQueue::~AppletMessageQueue() = default; 359AppletMessageQueue::~AppletMessageQueue() = default;
358 360
359const Kernel::SharedPtr<Kernel::Event>& AppletMessageQueue::GetMesssageRecieveEvent() const { 361const Kernel::SharedPtr<Kernel::ReadableEvent>& AppletMessageQueue::GetMesssageRecieveEvent()
360 return on_new_message; 362 const {
363 return on_new_message.readable;
361} 364}
362 365
363const Kernel::SharedPtr<Kernel::Event>& AppletMessageQueue::GetOperationModeChangedEvent() const { 366const Kernel::SharedPtr<Kernel::ReadableEvent>& AppletMessageQueue::GetOperationModeChangedEvent()
364 return on_operation_mode_changed; 367 const {
368 return on_operation_mode_changed.readable;
365} 369}
366 370
367void AppletMessageQueue::PushMessage(AppletMessage msg) { 371void AppletMessageQueue::PushMessage(AppletMessage msg) {
368 messages.push(msg); 372 messages.push(msg);
369 on_new_message->Signal(); 373 on_new_message.writable->Signal();
370} 374}
371 375
372AppletMessageQueue::AppletMessage AppletMessageQueue::PopMessage() { 376AppletMessageQueue::AppletMessage AppletMessageQueue::PopMessage() {
373 if (messages.empty()) { 377 if (messages.empty()) {
374 on_new_message->Clear(); 378 on_new_message.writable->Clear();
375 return AppletMessage::NoMessage; 379 return AppletMessage::NoMessage;
376 } 380 }
377 auto msg = messages.front(); 381 auto msg = messages.front();
378 messages.pop(); 382 messages.pop();
379 if (messages.empty()) { 383 if (messages.empty()) {
380 on_new_message->Clear(); 384 on_new_message.writable->Clear();
381 } 385 }
382 return msg; 386 return msg;
383} 387}
@@ -389,7 +393,7 @@ std::size_t AppletMessageQueue::GetMessageCount() const {
389void AppletMessageQueue::OperationModeChanged() { 393void AppletMessageQueue::OperationModeChanged() {
390 PushMessage(AppletMessage::OperationModeChanged); 394 PushMessage(AppletMessage::OperationModeChanged);
391 PushMessage(AppletMessage::PerformanceModeChanged); 395 PushMessage(AppletMessage::PerformanceModeChanged);
392 on_operation_mode_changed->Signal(); 396 on_operation_mode_changed.writable->Signal();
393} 397}
394 398
395ICommonStateGetter::ICommonStateGetter(std::shared_ptr<AppletMessageQueue> msg_queue) 399ICommonStateGetter::ICommonStateGetter(std::shared_ptr<AppletMessageQueue> msg_queue)
@@ -426,9 +430,6 @@ ICommonStateGetter::ICommonStateGetter(std::shared_ptr<AppletMessageQueue> msg_q
426 // clang-format on 430 // clang-format on
427 431
428 RegisterHandlers(functions); 432 RegisterHandlers(functions);
429
430 auto& kernel = Core::System::GetInstance().Kernel();
431 event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "ICommonStateGetter:Event");
432} 433}
433 434
434ICommonStateGetter::~ICommonStateGetter() = default; 435ICommonStateGetter::~ICommonStateGetter() = default;
@@ -564,8 +565,8 @@ private:
564 void GetAppletStateChangedEvent(Kernel::HLERequestContext& ctx) { 565 void GetAppletStateChangedEvent(Kernel::HLERequestContext& ctx) {
565 LOG_DEBUG(Service_AM, "called"); 566 LOG_DEBUG(Service_AM, "called");
566 567
568 applet->GetBroker().SignalStateChanged();
567 const auto event = applet->GetBroker().GetStateChangedEvent(); 569 const auto event = applet->GetBroker().GetStateChangedEvent();
568 event->Signal();
569 570
570 IPC::ResponseBuilder rb{ctx, 2, 1}; 571 IPC::ResponseBuilder rb{ctx, 2, 1};
571 rb.Push(RESULT_SUCCESS); 572 rb.Push(RESULT_SUCCESS);
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index 44c1bcde5..34c45fadf 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -6,12 +6,9 @@
6 6
7#include <memory> 7#include <memory>
8#include <queue> 8#include <queue>
9#include "core/hle/kernel/writable_event.h"
9#include "core/hle/service/service.h" 10#include "core/hle/service/service.h"
10 11
11namespace Kernel {
12class Event;
13}
14
15namespace Service { 12namespace Service {
16namespace NVFlinger { 13namespace NVFlinger {
17class NVFlinger; 14class NVFlinger;
@@ -52,8 +49,8 @@ public:
52 AppletMessageQueue(); 49 AppletMessageQueue();
53 ~AppletMessageQueue(); 50 ~AppletMessageQueue();
54 51
55 const Kernel::SharedPtr<Kernel::Event>& GetMesssageRecieveEvent() const; 52 const Kernel::SharedPtr<Kernel::ReadableEvent>& GetMesssageRecieveEvent() const;
56 const Kernel::SharedPtr<Kernel::Event>& GetOperationModeChangedEvent() const; 53 const Kernel::SharedPtr<Kernel::ReadableEvent>& GetOperationModeChangedEvent() const;
57 void PushMessage(AppletMessage msg); 54 void PushMessage(AppletMessage msg);
58 AppletMessage PopMessage(); 55 AppletMessage PopMessage();
59 std::size_t GetMessageCount() const; 56 std::size_t GetMessageCount() const;
@@ -61,8 +58,8 @@ public:
61 58
62private: 59private:
63 std::queue<AppletMessage> messages; 60 std::queue<AppletMessage> messages;
64 Kernel::SharedPtr<Kernel::Event> on_new_message; 61 Kernel::EventPair on_new_message;
65 Kernel::SharedPtr<Kernel::Event> on_operation_mode_changed; 62 Kernel::EventPair on_operation_mode_changed;
66}; 63};
67 64
68class IWindowController final : public ServiceFramework<IWindowController> { 65class IWindowController final : public ServiceFramework<IWindowController> {
@@ -122,7 +119,7 @@ private:
122 void GetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx); 119 void GetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx);
123 120
124 std::shared_ptr<NVFlinger::NVFlinger> nvflinger; 121 std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
125 Kernel::SharedPtr<Kernel::Event> launchable_event; 122 Kernel::EventPair launchable_event;
126 u32 idle_time_detection_extension = 0; 123 u32 idle_time_detection_extension = 0;
127}; 124};
128 125
@@ -151,7 +148,6 @@ private:
151 void GetBootMode(Kernel::HLERequestContext& ctx); 148 void GetBootMode(Kernel::HLERequestContext& ctx);
152 void GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx); 149 void GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx);
153 150
154 Kernel::SharedPtr<Kernel::Event> event;
155 std::shared_ptr<AppletMessageQueue> msg_queue; 151 std::shared_ptr<AppletMessageQueue> msg_queue;
156}; 152};
157 153
diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp
index becbadd06..47da35537 100644
--- a/src/core/hle/service/am/applets/applets.cpp
+++ b/src/core/hle/service/am/applets/applets.cpp
@@ -5,8 +5,9 @@
5#include <cstring> 5#include <cstring>
6#include "common/assert.h" 6#include "common/assert.h"
7#include "core/core.h" 7#include "core/core.h"
8#include "core/hle/kernel/event.h" 8#include "core/hle/kernel/readable_event.h"
9#include "core/hle/kernel/server_port.h" 9#include "core/hle/kernel/server_port.h"
10#include "core/hle/kernel/writable_event.h"
10#include "core/hle/service/am/am.h" 11#include "core/hle/service/am/am.h"
11#include "core/hle/service/am/applets/applets.h" 12#include "core/hle/service/am/applets/applets.h"
12 13
@@ -14,11 +15,11 @@ namespace Service::AM::Applets {
14 15
15AppletDataBroker::AppletDataBroker() { 16AppletDataBroker::AppletDataBroker() {
16 auto& kernel = Core::System::GetInstance().Kernel(); 17 auto& kernel = Core::System::GetInstance().Kernel();
17 state_changed_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, 18 state_changed_event = Kernel::WritableEvent::CreateEventPair(
18 "ILibraryAppletAccessor:StateChangedEvent"); 19 kernel, Kernel::ResetType::OneShot, "ILibraryAppletAccessor:StateChangedEvent");
19 pop_out_data_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, 20 pop_out_data_event = Kernel::WritableEvent::CreateEventPair(
20 "ILibraryAppletAccessor:PopDataOutEvent"); 21 kernel, Kernel::ResetType::OneShot, "ILibraryAppletAccessor:PopDataOutEvent");
21 pop_interactive_out_data_event = Kernel::Event::Create( 22 pop_interactive_out_data_event = Kernel::WritableEvent::CreateEventPair(
22 kernel, Kernel::ResetType::OneShot, "ILibraryAppletAccessor:PopInteractiveDataOutEvent"); 23 kernel, Kernel::ResetType::OneShot, "ILibraryAppletAccessor:PopInteractiveDataOutEvent");
23} 24}
24 25
@@ -66,7 +67,7 @@ void AppletDataBroker::PushNormalDataFromGame(IStorage storage) {
66 67
67void AppletDataBroker::PushNormalDataFromApplet(IStorage storage) { 68void AppletDataBroker::PushNormalDataFromApplet(IStorage storage) {
68 out_channel.push(std::make_unique<IStorage>(storage)); 69 out_channel.push(std::make_unique<IStorage>(storage));
69 pop_out_data_event->Signal(); 70 pop_out_data_event.writable->Signal();
70} 71}
71 72
72void AppletDataBroker::PushInteractiveDataFromGame(IStorage storage) { 73void AppletDataBroker::PushInteractiveDataFromGame(IStorage storage) {
@@ -75,23 +76,23 @@ void AppletDataBroker::PushInteractiveDataFromGame(IStorage storage) {
75 76
76void AppletDataBroker::PushInteractiveDataFromApplet(IStorage storage) { 77void AppletDataBroker::PushInteractiveDataFromApplet(IStorage storage) {
77 out_interactive_channel.push(std::make_unique<IStorage>(storage)); 78 out_interactive_channel.push(std::make_unique<IStorage>(storage));
78 pop_interactive_out_data_event->Signal(); 79 pop_interactive_out_data_event.writable->Signal();
79} 80}
80 81
81void AppletDataBroker::SignalStateChanged() const { 82void AppletDataBroker::SignalStateChanged() const {
82 state_changed_event->Signal(); 83 state_changed_event.writable->Signal();
83} 84}
84 85
85Kernel::SharedPtr<Kernel::Event> AppletDataBroker::GetNormalDataEvent() const { 86Kernel::SharedPtr<Kernel::ReadableEvent> AppletDataBroker::GetNormalDataEvent() const {
86 return pop_out_data_event; 87 return pop_out_data_event.readable;
87} 88}
88 89
89Kernel::SharedPtr<Kernel::Event> AppletDataBroker::GetInteractiveDataEvent() const { 90Kernel::SharedPtr<Kernel::ReadableEvent> AppletDataBroker::GetInteractiveDataEvent() const {
90 return pop_interactive_out_data_event; 91 return pop_interactive_out_data_event.readable;
91} 92}
92 93
93Kernel::SharedPtr<Kernel::Event> AppletDataBroker::GetStateChangedEvent() const { 94Kernel::SharedPtr<Kernel::ReadableEvent> AppletDataBroker::GetStateChangedEvent() const {
94 return state_changed_event; 95 return state_changed_event.readable;
95} 96}
96 97
97Applet::Applet() = default; 98Applet::Applet() = default;
diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h
index f65ea119c..b0a8913c3 100644
--- a/src/core/hle/service/am/applets/applets.h
+++ b/src/core/hle/service/am/applets/applets.h
@@ -8,13 +8,10 @@
8#include <queue> 8#include <queue>
9#include "common/swap.h" 9#include "common/swap.h"
10#include "core/hle/kernel/kernel.h" 10#include "core/hle/kernel/kernel.h"
11#include "core/hle/kernel/writable_event.h"
11 12
12union ResultCode; 13union ResultCode;
13 14
14namespace Kernel {
15class Event;
16}
17
18namespace Service::AM { 15namespace Service::AM {
19 16
20class IStorage; 17class IStorage;
@@ -40,9 +37,9 @@ public:
40 37
41 void SignalStateChanged() const; 38 void SignalStateChanged() const;
42 39
43 Kernel::SharedPtr<Kernel::Event> GetNormalDataEvent() const; 40 Kernel::SharedPtr<Kernel::ReadableEvent> GetNormalDataEvent() const;
44 Kernel::SharedPtr<Kernel::Event> GetInteractiveDataEvent() const; 41 Kernel::SharedPtr<Kernel::ReadableEvent> GetInteractiveDataEvent() const;
45 Kernel::SharedPtr<Kernel::Event> GetStateChangedEvent() const; 42 Kernel::SharedPtr<Kernel::ReadableEvent> GetStateChangedEvent() const;
46 43
47private: 44private:
48 // Queues are named from applet's perspective 45 // Queues are named from applet's perspective
@@ -59,13 +56,13 @@ private:
59 // PopInteractiveDataToGame and PushInteractiveDataFromApplet 56 // PopInteractiveDataToGame and PushInteractiveDataFromApplet
60 std::queue<std::unique_ptr<IStorage>> out_interactive_channel; 57 std::queue<std::unique_ptr<IStorage>> out_interactive_channel;
61 58
62 Kernel::SharedPtr<Kernel::Event> state_changed_event; 59 Kernel::EventPair state_changed_event;
63 60
64 // Signaled on PushNormalDataFromApplet 61 // Signaled on PushNormalDataFromApplet
65 Kernel::SharedPtr<Kernel::Event> pop_out_data_event; 62 Kernel::EventPair pop_out_data_event;
66 63
67 // Signaled on PushInteractiveDataFromApplet 64 // Signaled on PushInteractiveDataFromApplet
68 Kernel::SharedPtr<Kernel::Event> pop_interactive_out_data_event; 65 Kernel::EventPair pop_interactive_out_data_event;
69}; 66};
70 67
71class Applet { 68class Applet {
diff --git a/src/core/hle/service/aoc/aoc_u.cpp b/src/core/hle/service/aoc/aoc_u.cpp
index bacf19de2..0417fdb92 100644
--- a/src/core/hle/service/aoc/aoc_u.cpp
+++ b/src/core/hle/service/aoc/aoc_u.cpp
@@ -13,8 +13,10 @@
13#include "core/file_sys/patch_manager.h" 13#include "core/file_sys/patch_manager.h"
14#include "core/file_sys/registered_cache.h" 14#include "core/file_sys/registered_cache.h"
15#include "core/hle/ipc_helpers.h" 15#include "core/hle/ipc_helpers.h"
16#include "core/hle/kernel/event.h" 16#include "core/hle/kernel/kernel.h"
17#include "core/hle/kernel/process.h" 17#include "core/hle/kernel/process.h"
18#include "core/hle/kernel/readable_event.h"
19#include "core/hle/kernel/writable_event.h"
18#include "core/hle/service/aoc/aoc_u.h" 20#include "core/hle/service/aoc/aoc_u.h"
19#include "core/hle/service/filesystem/filesystem.h" 21#include "core/hle/service/filesystem/filesystem.h"
20#include "core/loader/loader.h" 22#include "core/loader/loader.h"
@@ -32,14 +34,14 @@ static std::vector<u64> AccumulateAOCTitleIDs() {
32 std::vector<u64> add_on_content; 34 std::vector<u64> add_on_content;
33 const auto rcu = FileSystem::GetUnionContents(); 35 const auto rcu = FileSystem::GetUnionContents();
34 const auto list = 36 const auto list =
35 rcu->ListEntriesFilter(FileSys::TitleType::AOC, FileSys::ContentRecordType::Data); 37 rcu.ListEntriesFilter(FileSys::TitleType::AOC, FileSys::ContentRecordType::Data);
36 std::transform(list.begin(), list.end(), std::back_inserter(add_on_content), 38 std::transform(list.begin(), list.end(), std::back_inserter(add_on_content),
37 [](const FileSys::RegisteredCacheEntry& rce) { return rce.title_id; }); 39 [](const FileSys::RegisteredCacheEntry& rce) { return rce.title_id; });
38 add_on_content.erase( 40 add_on_content.erase(
39 std::remove_if( 41 std::remove_if(
40 add_on_content.begin(), add_on_content.end(), 42 add_on_content.begin(), add_on_content.end(),
41 [&rcu](u64 tid) { 43 [&rcu](u64 tid) {
42 return rcu->GetEntry(tid, FileSys::ContentRecordType::Data)->GetStatus() != 44 return rcu.GetEntry(tid, FileSys::ContentRecordType::Data)->GetStatus() !=
43 Loader::ResultStatus::Success; 45 Loader::ResultStatus::Success;
44 }), 46 }),
45 add_on_content.end()); 47 add_on_content.end());
@@ -61,8 +63,8 @@ AOC_U::AOC_U() : ServiceFramework("aoc:u"), add_on_content(AccumulateAOCTitleIDs
61 RegisterHandlers(functions); 63 RegisterHandlers(functions);
62 64
63 auto& kernel = Core::System::GetInstance().Kernel(); 65 auto& kernel = Core::System::GetInstance().Kernel();
64 aoc_change_event = Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, 66 aoc_change_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
65 "GetAddOnContentListChanged:Event"); 67 "GetAddOnContentListChanged:Event");
66} 68}
67 69
68AOC_U::~AOC_U() = default; 70AOC_U::~AOC_U() = default;
@@ -144,7 +146,7 @@ void AOC_U::GetAddOnContentListChangedEvent(Kernel::HLERequestContext& ctx) {
144 146
145 IPC::ResponseBuilder rb{ctx, 2, 1}; 147 IPC::ResponseBuilder rb{ctx, 2, 1};
146 rb.Push(RESULT_SUCCESS); 148 rb.Push(RESULT_SUCCESS);
147 rb.PushCopyObjects(aoc_change_event); 149 rb.PushCopyObjects(aoc_change_event.readable);
148} 150}
149 151
150void InstallInterfaces(SM::ServiceManager& service_manager) { 152void InstallInterfaces(SM::ServiceManager& service_manager) {
diff --git a/src/core/hle/service/aoc/aoc_u.h b/src/core/hle/service/aoc/aoc_u.h
index 68d94fdaa..5effea730 100644
--- a/src/core/hle/service/aoc/aoc_u.h
+++ b/src/core/hle/service/aoc/aoc_u.h
@@ -6,6 +6,10 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9namespace Kernel {
10class WritableEvent;
11}
12
9namespace Service::AOC { 13namespace Service::AOC {
10 14
11class AOC_U final : public ServiceFramework<AOC_U> { 15class AOC_U final : public ServiceFramework<AOC_U> {
@@ -21,7 +25,7 @@ private:
21 void GetAddOnContentListChangedEvent(Kernel::HLERequestContext& ctx); 25 void GetAddOnContentListChangedEvent(Kernel::HLERequestContext& ctx);
22 26
23 std::vector<u64> add_on_content; 27 std::vector<u64> add_on_content;
24 Kernel::SharedPtr<Kernel::Event> aoc_change_event; 28 Kernel::EventPair aoc_change_event;
25}; 29};
26 30
27/// Registers all AOC services with the specified service manager. 31/// Registers all AOC services with the specified service manager.
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp
index 2ee9bc273..dc6a6b188 100644
--- a/src/core/hle/service/audio/audout_u.cpp
+++ b/src/core/hle/service/audio/audout_u.cpp
@@ -13,8 +13,10 @@
13#include "common/swap.h" 13#include "common/swap.h"
14#include "core/core.h" 14#include "core/core.h"
15#include "core/hle/ipc_helpers.h" 15#include "core/hle/ipc_helpers.h"
16#include "core/hle/kernel/event.h"
17#include "core/hle/kernel/hle_ipc.h" 16#include "core/hle/kernel/hle_ipc.h"
17#include "core/hle/kernel/kernel.h"
18#include "core/hle/kernel/readable_event.h"
19#include "core/hle/kernel/writable_event.h"
18#include "core/hle/service/audio/audout_u.h" 20#include "core/hle/service/audio/audout_u.h"
19#include "core/memory.h" 21#include "core/memory.h"
20 22
@@ -46,8 +48,8 @@ class IAudioOut final : public ServiceFramework<IAudioOut> {
46public: 48public:
47 IAudioOut(AudoutParams audio_params, AudioCore::AudioOut& audio_core, std::string&& device_name, 49 IAudioOut(AudoutParams audio_params, AudioCore::AudioOut& audio_core, std::string&& device_name,
48 std::string&& unique_name) 50 std::string&& unique_name)
49 : ServiceFramework("IAudioOut"), audio_core(audio_core), audio_params(audio_params), 51 : ServiceFramework("IAudioOut"), audio_core(audio_core),
50 device_name(std::move(device_name)) { 52 device_name(std::move(device_name)), audio_params(audio_params) {
51 53
52 static const FunctionInfo functions[] = { 54 static const FunctionInfo functions[] = {
53 {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"}, 55 {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"},
@@ -67,11 +69,12 @@ public:
67 69
68 // This is the event handle used to check if the audio buffer was released 70 // This is the event handle used to check if the audio buffer was released
69 auto& kernel = Core::System::GetInstance().Kernel(); 71 auto& kernel = Core::System::GetInstance().Kernel();
70 buffer_event = 72 buffer_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
71 Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "IAudioOutBufferReleased"); 73 "IAudioOutBufferReleased");
72 74
73 stream = audio_core.OpenStream(audio_params.sample_rate, audio_params.channel_count, 75 stream = audio_core.OpenStream(audio_params.sample_rate, audio_params.channel_count,
74 std::move(unique_name), [=]() { buffer_event->Signal(); }); 76 std::move(unique_name),
77 [=]() { buffer_event.writable->Signal(); });
75 } 78 }
76 79
77private: 80private:
@@ -121,7 +124,7 @@ private:
121 124
122 IPC::ResponseBuilder rb{ctx, 2, 1}; 125 IPC::ResponseBuilder rb{ctx, 2, 1};
123 rb.Push(RESULT_SUCCESS); 126 rb.Push(RESULT_SUCCESS);
124 rb.PushCopyObjects(buffer_event); 127 rb.PushCopyObjects(buffer_event.readable);
125 } 128 }
126 129
127 void AppendAudioOutBufferImpl(Kernel::HLERequestContext& ctx) { 130 void AppendAudioOutBufferImpl(Kernel::HLERequestContext& ctx) {
@@ -187,8 +190,8 @@ private:
187 190
188 AudoutParams audio_params{}; 191 AudoutParams audio_params{};
189 192
190 /// This is the evend handle used to check if the audio buffer was released 193 /// This is the event handle used to check if the audio buffer was released
191 Kernel::SharedPtr<Kernel::Event> buffer_event; 194 Kernel::EventPair buffer_event;
192}; 195};
193 196
194void AudOutU::ListAudioOutsImpl(Kernel::HLERequestContext& ctx) { 197void AudOutU::ListAudioOutsImpl(Kernel::HLERequestContext& ctx) {
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index 1c418a9bb..945259c7d 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -12,8 +12,10 @@
12#include "common/logging/log.h" 12#include "common/logging/log.h"
13#include "core/core.h" 13#include "core/core.h"
14#include "core/hle/ipc_helpers.h" 14#include "core/hle/ipc_helpers.h"
15#include "core/hle/kernel/event.h"
16#include "core/hle/kernel/hle_ipc.h" 15#include "core/hle/kernel/hle_ipc.h"
16#include "core/hle/kernel/kernel.h"
17#include "core/hle/kernel/readable_event.h"
18#include "core/hle/kernel/writable_event.h"
17#include "core/hle/service/audio/audren_u.h" 19#include "core/hle/service/audio/audren_u.h"
18 20
19namespace Service::Audio { 21namespace Service::Audio {
@@ -41,14 +43,14 @@ public:
41 RegisterHandlers(functions); 43 RegisterHandlers(functions);
42 44
43 auto& kernel = Core::System::GetInstance().Kernel(); 45 auto& kernel = Core::System::GetInstance().Kernel();
44 system_event = 46 system_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
45 Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "IAudioRenderer:SystemEvent"); 47 "IAudioRenderer:SystemEvent");
46 renderer = std::make_unique<AudioCore::AudioRenderer>(audren_params, system_event); 48 renderer = std::make_unique<AudioCore::AudioRenderer>(audren_params, system_event.writable);
47 } 49 }
48 50
49private: 51private:
50 void UpdateAudioCallback() { 52 void UpdateAudioCallback() {
51 system_event->Signal(); 53 system_event.writable->Signal();
52 } 54 }
53 55
54 void GetSampleRate(Kernel::HLERequestContext& ctx) { 56 void GetSampleRate(Kernel::HLERequestContext& ctx) {
@@ -112,7 +114,7 @@ private:
112 114
113 IPC::ResponseBuilder rb{ctx, 2, 1}; 115 IPC::ResponseBuilder rb{ctx, 2, 1};
114 rb.Push(RESULT_SUCCESS); 116 rb.Push(RESULT_SUCCESS);
115 rb.PushCopyObjects(system_event); 117 rb.PushCopyObjects(system_event.readable);
116 } 118 }
117 119
118 void SetRenderingTimeLimit(Kernel::HLERequestContext& ctx) { 120 void SetRenderingTimeLimit(Kernel::HLERequestContext& ctx) {
@@ -135,7 +137,7 @@ private:
135 rb.Push(rendering_time_limit_percent); 137 rb.Push(rendering_time_limit_percent);
136 } 138 }
137 139
138 Kernel::SharedPtr<Kernel::Event> system_event; 140 Kernel::EventPair system_event;
139 std::unique_ptr<AudioCore::AudioRenderer> renderer; 141 std::unique_ptr<AudioCore::AudioRenderer> renderer;
140 u32 rendering_time_limit_percent = 100; 142 u32 rendering_time_limit_percent = 100;
141}; 143};
@@ -162,8 +164,8 @@ public:
162 RegisterHandlers(functions); 164 RegisterHandlers(functions);
163 165
164 auto& kernel = Core::System::GetInstance().Kernel(); 166 auto& kernel = Core::System::GetInstance().Kernel();
165 buffer_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, 167 buffer_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
166 "IAudioOutBufferReleasedEvent"); 168 "IAudioOutBufferReleasedEvent");
167 } 169 }
168 170
169private: 171private:
@@ -207,11 +209,11 @@ private:
207 void QueryAudioDeviceSystemEvent(Kernel::HLERequestContext& ctx) { 209 void QueryAudioDeviceSystemEvent(Kernel::HLERequestContext& ctx) {
208 LOG_WARNING(Service_Audio, "(STUBBED) called"); 210 LOG_WARNING(Service_Audio, "(STUBBED) called");
209 211
210 buffer_event->Signal(); 212 buffer_event.writable->Signal();
211 213
212 IPC::ResponseBuilder rb{ctx, 2, 1}; 214 IPC::ResponseBuilder rb{ctx, 2, 1};
213 rb.Push(RESULT_SUCCESS); 215 rb.Push(RESULT_SUCCESS);
214 rb.PushCopyObjects(buffer_event); 216 rb.PushCopyObjects(buffer_event.readable);
215 } 217 }
216 218
217 void GetActiveChannelCount(Kernel::HLERequestContext& ctx) { 219 void GetActiveChannelCount(Kernel::HLERequestContext& ctx) {
@@ -222,7 +224,7 @@ private:
222 rb.Push<u32>(1); 224 rb.Push<u32>(1);
223 } 225 }
224 226
225 Kernel::SharedPtr<Kernel::Event> buffer_event; 227 Kernel::EventPair buffer_event;
226 228
227}; // namespace Audio 229}; // namespace Audio
228 230
diff --git a/src/core/hle/service/btdrv/btdrv.cpp b/src/core/hle/service/btdrv/btdrv.cpp
index 2eadcdd05..5704ca0ab 100644
--- a/src/core/hle/service/btdrv/btdrv.cpp
+++ b/src/core/hle/service/btdrv/btdrv.cpp
@@ -4,8 +4,10 @@
4 4
5#include "common/logging/log.h" 5#include "common/logging/log.h"
6#include "core/hle/ipc_helpers.h" 6#include "core/hle/ipc_helpers.h"
7#include "core/hle/kernel/event.h"
8#include "core/hle/kernel/hle_ipc.h" 7#include "core/hle/kernel/hle_ipc.h"
8#include "core/hle/kernel/kernel.h"
9#include "core/hle/kernel/readable_event.h"
10#include "core/hle/kernel/writable_event.h"
9#include "core/hle/service/btdrv/btdrv.h" 11#include "core/hle/service/btdrv/btdrv.h"
10#include "core/hle/service/service.h" 12#include "core/hle/service/service.h"
11#include "core/hle/service/sm/sm.h" 13#include "core/hle/service/sm/sm.h"
@@ -30,20 +32,22 @@ public:
30 }; 32 };
31 // clang-format on 33 // clang-format on
32 RegisterHandlers(functions); 34 RegisterHandlers(functions);
35
36 auto& kernel = Core::System::GetInstance().Kernel();
37 register_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
38 "BT:RegisterEvent");
33 } 39 }
34 40
35private: 41private:
36 void RegisterEvent(Kernel::HLERequestContext& ctx) { 42 void RegisterEvent(Kernel::HLERequestContext& ctx) {
37 LOG_WARNING(Service_BTM, "(STUBBED) called"); 43 LOG_WARNING(Service_BTM, "(STUBBED) called");
38 44
39 auto& kernel = Core::System::GetInstance().Kernel();
40 register_event =
41 Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "BT:RegisterEvent");
42 IPC::ResponseBuilder rb{ctx, 2, 1}; 45 IPC::ResponseBuilder rb{ctx, 2, 1};
43 rb.Push(RESULT_SUCCESS); 46 rb.Push(RESULT_SUCCESS);
44 rb.PushCopyObjects(register_event); 47 rb.PushCopyObjects(register_event.readable);
45 } 48 }
46 Kernel::SharedPtr<Kernel::Event> register_event; 49
50 Kernel::EventPair register_event;
47}; 51};
48 52
49class BtDrv final : public ServiceFramework<BtDrv> { 53class BtDrv final : public ServiceFramework<BtDrv> {
diff --git a/src/core/hle/service/btm/btm.cpp b/src/core/hle/service/btm/btm.cpp
index 463a79351..ef7398a23 100644
--- a/src/core/hle/service/btm/btm.cpp
+++ b/src/core/hle/service/btm/btm.cpp
@@ -6,8 +6,10 @@
6 6
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8#include "core/hle/ipc_helpers.h" 8#include "core/hle/ipc_helpers.h"
9#include "core/hle/kernel/event.h"
10#include "core/hle/kernel/hle_ipc.h" 9#include "core/hle/kernel/hle_ipc.h"
10#include "core/hle/kernel/kernel.h"
11#include "core/hle/kernel/readable_event.h"
12#include "core/hle/kernel/writable_event.h"
11#include "core/hle/service/btm/btm.h" 13#include "core/hle/service/btm/btm.h"
12#include "core/hle/service/service.h" 14#include "core/hle/service/service.h"
13 15
@@ -53,53 +55,55 @@ public:
53 }; 55 };
54 // clang-format on 56 // clang-format on
55 RegisterHandlers(functions); 57 RegisterHandlers(functions);
58
59 auto& kernel = Core::System::GetInstance().Kernel();
60 scan_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
61 "IBtmUserCore:ScanEvent");
62 connection_event = Kernel::WritableEvent::CreateEventPair(
63 kernel, Kernel::ResetType::OneShot, "IBtmUserCore:ConnectionEvent");
64 service_discovery = Kernel::WritableEvent::CreateEventPair(
65 kernel, Kernel::ResetType::OneShot, "IBtmUserCore:Discovery");
66 config_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
67 "IBtmUserCore:ConfigEvent");
56 } 68 }
57 69
58private: 70private:
59 void GetScanEvent(Kernel::HLERequestContext& ctx) { 71 void GetScanEvent(Kernel::HLERequestContext& ctx) {
60 LOG_WARNING(Service_BTM, "(STUBBED) called"); 72 LOG_WARNING(Service_BTM, "(STUBBED) called");
61 73
62 auto& kernel = Core::System::GetInstance().Kernel();
63 scan_event =
64 Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IBtmUserCore:ScanEvent");
65 IPC::ResponseBuilder rb{ctx, 2, 1}; 74 IPC::ResponseBuilder rb{ctx, 2, 1};
66 rb.Push(RESULT_SUCCESS); 75 rb.Push(RESULT_SUCCESS);
67 rb.PushCopyObjects(scan_event); 76 rb.PushCopyObjects(scan_event.readable);
68 } 77 }
78
69 void GetConnectionEvent(Kernel::HLERequestContext& ctx) { 79 void GetConnectionEvent(Kernel::HLERequestContext& ctx) {
70 LOG_WARNING(Service_BTM, "(STUBBED) called"); 80 LOG_WARNING(Service_BTM, "(STUBBED) called");
71 81
72 auto& kernel = Core::System::GetInstance().Kernel();
73 connection_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot,
74 "IBtmUserCore:ConnectionEvent");
75 IPC::ResponseBuilder rb{ctx, 2, 1}; 82 IPC::ResponseBuilder rb{ctx, 2, 1};
76 rb.Push(RESULT_SUCCESS); 83 rb.Push(RESULT_SUCCESS);
77 rb.PushCopyObjects(connection_event); 84 rb.PushCopyObjects(connection_event.readable);
78 } 85 }
86
79 void GetDiscoveryEvent(Kernel::HLERequestContext& ctx) { 87 void GetDiscoveryEvent(Kernel::HLERequestContext& ctx) {
80 LOG_WARNING(Service_BTM, "(STUBBED) called"); 88 LOG_WARNING(Service_BTM, "(STUBBED) called");
81 89
82 auto& kernel = Core::System::GetInstance().Kernel();
83 service_discovery =
84 Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IBtmUserCore:Discovery");
85 IPC::ResponseBuilder rb{ctx, 2, 1}; 90 IPC::ResponseBuilder rb{ctx, 2, 1};
86 rb.Push(RESULT_SUCCESS); 91 rb.Push(RESULT_SUCCESS);
87 rb.PushCopyObjects(service_discovery); 92 rb.PushCopyObjects(service_discovery.readable);
88 } 93 }
94
89 void GetConfigEvent(Kernel::HLERequestContext& ctx) { 95 void GetConfigEvent(Kernel::HLERequestContext& ctx) {
90 LOG_WARNING(Service_BTM, "(STUBBED) called"); 96 LOG_WARNING(Service_BTM, "(STUBBED) called");
91 97
92 auto& kernel = Core::System::GetInstance().Kernel();
93 config_event =
94 Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IBtmUserCore:ConfigEvent");
95 IPC::ResponseBuilder rb{ctx, 2, 1}; 98 IPC::ResponseBuilder rb{ctx, 2, 1};
96 rb.Push(RESULT_SUCCESS); 99 rb.Push(RESULT_SUCCESS);
97 rb.PushCopyObjects(config_event); 100 rb.PushCopyObjects(config_event.readable);
98 } 101 }
99 Kernel::SharedPtr<Kernel::Event> scan_event; 102
100 Kernel::SharedPtr<Kernel::Event> connection_event; 103 Kernel::EventPair scan_event;
101 Kernel::SharedPtr<Kernel::Event> service_discovery; 104 Kernel::EventPair connection_event;
102 Kernel::SharedPtr<Kernel::Event> config_event; 105 Kernel::EventPair service_discovery;
106 Kernel::EventPair config_event;
103}; 107};
104 108
105class BTM_USR final : public ServiceFramework<BTM_USR> { 109class BTM_USR final : public ServiceFramework<BTM_USR> {
diff --git a/src/core/hle/service/erpt/erpt.cpp b/src/core/hle/service/erpt/erpt.cpp
index ee11cd78e..d9b32954e 100644
--- a/src/core/hle/service/erpt/erpt.cpp
+++ b/src/core/hle/service/erpt/erpt.cpp
@@ -17,11 +17,13 @@ public:
17 static const FunctionInfo functions[] = { 17 static const FunctionInfo functions[] = {
18 {0, nullptr, "SubmitContext"}, 18 {0, nullptr, "SubmitContext"},
19 {1, nullptr, "CreateReport"}, 19 {1, nullptr, "CreateReport"},
20 {2, nullptr, "Unknown1"}, 20 {2, nullptr, "SetInitialLaunchSettingsCompletionTime"},
21 {3, nullptr, "Unknown2"}, 21 {3, nullptr, "ClearInitialLaunchSettingsCompletionTime"},
22 {4, nullptr, "Unknown3"}, 22 {4, nullptr, "UpdatePowerOnTime"},
23 {5, nullptr, "Unknown4"}, 23 {5, nullptr, "UpdateAwakeTime"},
24 {6, nullptr, "Unknown5"}, 24 {6, nullptr, "SubmitMultipleCategoryContext"},
25 {7, nullptr, "UpdateApplicationLaunchTime"},
26 {8, nullptr, "ClearApplicationLaunchTime"},
25 }; 27 };
26 // clang-format on 28 // clang-format on
27 29
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index 2aa77f68d..b1490e6fa 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -113,6 +113,18 @@ ResultCode VfsDirectoryServiceWrapper::DeleteDirectoryRecursively(const std::str
113 return RESULT_SUCCESS; 113 return RESULT_SUCCESS;
114} 114}
115 115
116ResultCode VfsDirectoryServiceWrapper::CleanDirectoryRecursively(const std::string& path) const {
117 const std::string sanitized_path(FileUtil::SanitizePath(path));
118 auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(sanitized_path));
119
120 if (!dir->CleanSubdirectoryRecursive(FileUtil::GetFilename(sanitized_path))) {
121 // TODO(DarkLordZach): Find a better error code for this
122 return ResultCode(-1);
123 }
124
125 return RESULT_SUCCESS;
126}
127
116ResultCode VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path_, 128ResultCode VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path_,
117 const std::string& dest_path_) const { 129 const std::string& dest_path_) const {
118 std::string src_path(FileUtil::SanitizePath(src_path_)); 130 std::string src_path(FileUtil::SanitizePath(src_path_));
@@ -329,20 +341,9 @@ ResultVal<FileSys::VirtualDir> OpenSDMC() {
329 return sdmc_factory->Open(); 341 return sdmc_factory->Open();
330} 342}
331 343
332std::shared_ptr<FileSys::RegisteredCacheUnion> registered_cache_union; 344FileSys::RegisteredCacheUnion GetUnionContents() {
333 345 return FileSys::RegisteredCacheUnion{
334std::shared_ptr<FileSys::RegisteredCacheUnion> GetUnionContents() { 346 {GetSystemNANDContents(), GetUserNANDContents(), GetSDMCContents()}};
335 if (registered_cache_union == nullptr) {
336 registered_cache_union =
337 std::make_shared<FileSys::RegisteredCacheUnion>(std::vector<FileSys::RegisteredCache*>{
338 GetSystemNANDContents(), GetUserNANDContents(), GetSDMCContents()});
339 }
340
341 return registered_cache_union;
342}
343
344void ClearUnionContents() {
345 registered_cache_union = nullptr;
346} 347}
347 348
348FileSys::RegisteredCache* GetSystemNANDContents() { 349FileSys::RegisteredCache* GetSystemNANDContents() {
@@ -395,7 +396,6 @@ void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) {
395 bis_factory = nullptr; 396 bis_factory = nullptr;
396 save_data_factory = nullptr; 397 save_data_factory = nullptr;
397 sdmc_factory = nullptr; 398 sdmc_factory = nullptr;
398 ClearUnionContents();
399 } 399 }
400 400
401 auto nand_directory = vfs.OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir), 401 auto nand_directory = vfs.OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir),
diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h
index 0a6cb6635..965414be0 100644
--- a/src/core/hle/service/filesystem/filesystem.h
+++ b/src/core/hle/service/filesystem/filesystem.h
@@ -48,8 +48,7 @@ ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space,
48ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space); 48ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space);
49ResultVal<FileSys::VirtualDir> OpenSDMC(); 49ResultVal<FileSys::VirtualDir> OpenSDMC();
50 50
51std::shared_ptr<FileSys::RegisteredCacheUnion> GetUnionContents(); 51FileSys::RegisteredCacheUnion GetUnionContents();
52void ClearUnionContents();
53 52
54FileSys::RegisteredCache* GetSystemNANDContents(); 53FileSys::RegisteredCache* GetSystemNANDContents();
55FileSys::RegisteredCache* GetUserNANDContents(); 54FileSys::RegisteredCache* GetUserNANDContents();
@@ -114,6 +113,18 @@ public:
114 ResultCode DeleteDirectoryRecursively(const std::string& path) const; 113 ResultCode DeleteDirectoryRecursively(const std::string& path) const;
115 114
116 /** 115 /**
116 * Cleans the specified directory. This is similar to DeleteDirectoryRecursively,
117 * in that it deletes all the contents of the specified directory, however, this
118 * function does *not* delete the directory itself. It only deletes everything
119 * within it.
120 *
121 * @param path Path relative to the archive.
122 *
123 * @return Result of the operation.
124 */
125 ResultCode CleanDirectoryRecursively(const std::string& path) const;
126
127 /**
117 * Rename a File specified by its path 128 * Rename a File specified by its path
118 * @param src_path Source path relative to the archive 129 * @param src_path Source path relative to the archive
119 * @param dest_path Destination path relative to the archive 130 * @param dest_path Destination path relative to the archive
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index 99d9ebc39..d2ffd5776 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -20,6 +20,7 @@
20#include "core/file_sys/nca_metadata.h" 20#include "core/file_sys/nca_metadata.h"
21#include "core/file_sys/patch_manager.h" 21#include "core/file_sys/patch_manager.h"
22#include "core/file_sys/savedata_factory.h" 22#include "core/file_sys/savedata_factory.h"
23#include "core/file_sys/system_archive/system_archive.h"
23#include "core/file_sys/vfs.h" 24#include "core/file_sys/vfs.h"
24#include "core/hle/ipc_helpers.h" 25#include "core/hle/ipc_helpers.h"
25#include "core/hle/kernel/process.h" 26#include "core/hle/kernel/process.h"
@@ -291,7 +292,7 @@ public:
291 {10, &IFileSystem::Commit, "Commit"}, 292 {10, &IFileSystem::Commit, "Commit"},
292 {11, nullptr, "GetFreeSpaceSize"}, 293 {11, nullptr, "GetFreeSpaceSize"},
293 {12, nullptr, "GetTotalSpaceSize"}, 294 {12, nullptr, "GetTotalSpaceSize"},
294 {13, nullptr, "CleanDirectoryRecursively"}, 295 {13, &IFileSystem::CleanDirectoryRecursively, "CleanDirectoryRecursively"},
295 {14, nullptr, "GetFileTimeStampRaw"}, 296 {14, nullptr, "GetFileTimeStampRaw"},
296 {15, nullptr, "QueryEntry"}, 297 {15, nullptr, "QueryEntry"},
297 }; 298 };
@@ -361,6 +362,16 @@ public:
361 rb.Push(backend.DeleteDirectoryRecursively(name)); 362 rb.Push(backend.DeleteDirectoryRecursively(name));
362 } 363 }
363 364
365 void CleanDirectoryRecursively(Kernel::HLERequestContext& ctx) {
366 const auto file_buffer = ctx.ReadBuffer();
367 const std::string name = Common::StringFromBuffer(file_buffer);
368
369 LOG_DEBUG(Service_FS, "called. Directory: {}", name);
370
371 IPC::ResponseBuilder rb{ctx, 2};
372 rb.Push(backend.CleanDirectoryRecursively(name));
373 }
374
364 void RenameFile(Kernel::HLERequestContext& ctx) { 375 void RenameFile(Kernel::HLERequestContext& ctx) {
365 IPC::RequestParser rp{ctx}; 376 IPC::RequestParser rp{ctx};
366 377
@@ -821,6 +832,15 @@ void FSP_SRV::OpenDataStorageByDataId(Kernel::HLERequestContext& ctx) {
821 auto data = OpenRomFS(title_id, storage_id, FileSys::ContentRecordType::Data); 832 auto data = OpenRomFS(title_id, storage_id, FileSys::ContentRecordType::Data);
822 833
823 if (data.Failed()) { 834 if (data.Failed()) {
835 const auto archive = FileSys::SystemArchive::SynthesizeSystemArchive(title_id);
836
837 if (archive != nullptr) {
838 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
839 rb.Push(RESULT_SUCCESS);
840 rb.PushIpcInterface(std::make_shared<IStorage>(archive));
841 return;
842 }
843
824 // TODO(DarkLordZach): Find the right error code to use here 844 // TODO(DarkLordZach): Find the right error code to use here
825 LOG_ERROR(Service_FS, 845 LOG_ERROR(Service_FS,
826 "could not open data storage with title_id={:016X}, storage_id={:02X}", title_id, 846 "could not open data storage with title_id={:016X}, storage_id={:02X}", title_id,
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 22e87a50a..d6829d0b8 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -12,7 +12,9 @@
12#include "core/core.h" 12#include "core/core.h"
13#include "core/core_timing.h" 13#include "core/core_timing.h"
14#include "core/frontend/input.h" 14#include "core/frontend/input.h"
15#include "core/hle/kernel/event.h" 15#include "core/hle/kernel/kernel.h"
16#include "core/hle/kernel/readable_event.h"
17#include "core/hle/kernel/writable_event.h"
16#include "core/hle/service/hid/controllers/npad.h" 18#include "core/hle/service/hid/controllers/npad.h"
17#include "core/settings.h" 19#include "core/settings.h"
18 20
@@ -167,8 +169,8 @@ void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) {
167 169
168void Controller_NPad::OnInit() { 170void Controller_NPad::OnInit() {
169 auto& kernel = Core::System::GetInstance().Kernel(); 171 auto& kernel = Core::System::GetInstance().Kernel();
170 styleset_changed_event = 172 styleset_changed_event = Kernel::WritableEvent::CreateEventPair(
171 Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "npad:NpadStyleSetChanged"); 173 kernel, Kernel::ResetType::OneShot, "npad:NpadStyleSetChanged");
172 174
173 if (!IsControllerActivated()) { 175 if (!IsControllerActivated()) {
174 return; 176 return;
@@ -494,7 +496,7 @@ void Controller_NPad::SetSupportedNPadIdTypes(u8* data, std::size_t length) {
494 had_controller_update = true; 496 had_controller_update = true;
495 } 497 }
496 if (had_controller_update) { 498 if (had_controller_update) {
497 styleset_changed_event->Signal(); 499 styleset_changed_event.writable->Signal();
498 } 500 }
499 } 501 }
500} 502}
@@ -509,7 +511,7 @@ std::size_t Controller_NPad::GetSupportedNPadIdTypesSize() const {
509} 511}
510 512
511void Controller_NPad::SetHoldType(NpadHoldType joy_hold_type) { 513void Controller_NPad::SetHoldType(NpadHoldType joy_hold_type) {
512 styleset_changed_event->Signal(); 514 styleset_changed_event.writable->Signal();
513 hold_type = joy_hold_type; 515 hold_type = joy_hold_type;
514} 516}
515 517
@@ -518,8 +520,9 @@ Controller_NPad::NpadHoldType Controller_NPad::GetHoldType() const {
518} 520}
519 521
520void Controller_NPad::SetNpadMode(u32 npad_id, NPadAssignments assignment_mode) { 522void Controller_NPad::SetNpadMode(u32 npad_id, NPadAssignments assignment_mode) {
521 ASSERT(npad_id < shared_memory_entries.size()); 523 const std::size_t npad_index = NPadIdToIndex(npad_id);
522 shared_memory_entries[npad_id].pad_assignment = assignment_mode; 524 ASSERT(npad_index < shared_memory_entries.size());
525 shared_memory_entries[npad_index].pad_assignment = assignment_mode;
523} 526}
524 527
525void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids, 528void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids,
@@ -538,11 +541,11 @@ void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids,
538 last_processed_vibration = vibrations.back(); 541 last_processed_vibration = vibrations.back();
539} 542}
540 543
541Kernel::SharedPtr<Kernel::Event> Controller_NPad::GetStyleSetChangedEvent() const { 544Kernel::SharedPtr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent() const {
542 // TODO(ogniK): Figure out the best time to signal this event. This event seems that it should 545 // TODO(ogniK): Figure out the best time to signal this event. This event seems that it should
543 // be signalled at least once, and signaled after a new controller is connected? 546 // be signalled at least once, and signaled after a new controller is connected?
544 styleset_changed_event->Signal(); 547 styleset_changed_event.writable->Signal();
545 return styleset_changed_event; 548 return styleset_changed_event.readable;
546} 549}
547 550
548Controller_NPad::Vibration Controller_NPad::GetLastVibration() const { 551Controller_NPad::Vibration Controller_NPad::GetLastVibration() const {
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index abff6544d..29851f16a 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -8,7 +8,8 @@
8#include "common/bit_field.h" 8#include "common/bit_field.h"
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "core/frontend/input.h" 10#include "core/frontend/input.h"
11#include "core/hle/kernel/event.h" 11#include "core/hle/kernel/object.h"
12#include "core/hle/kernel/writable_event.h"
12#include "core/hle/service/hid/controllers/controller_base.h" 13#include "core/hle/service/hid/controllers/controller_base.h"
13#include "core/settings.h" 14#include "core/settings.h"
14 15
@@ -108,7 +109,7 @@ public:
108 void VibrateController(const std::vector<u32>& controller_ids, 109 void VibrateController(const std::vector<u32>& controller_ids,
109 const std::vector<Vibration>& vibrations); 110 const std::vector<Vibration>& vibrations);
110 111
111 Kernel::SharedPtr<Kernel::Event> GetStyleSetChangedEvent() const; 112 Kernel::SharedPtr<Kernel::ReadableEvent> GetStyleSetChangedEvent() const;
112 Vibration GetLastVibration() const; 113 Vibration GetLastVibration() const;
113 114
114 void AddNewController(NPadControllerType controller); 115 void AddNewController(NPadControllerType controller);
@@ -303,7 +304,7 @@ private:
303 sticks; 304 sticks;
304 std::vector<u32> supported_npad_id_types{}; 305 std::vector<u32> supported_npad_id_types{};
305 NpadHoldType hold_type{NpadHoldType::Vertical}; 306 NpadHoldType hold_type{NpadHoldType::Vertical};
306 Kernel::SharedPtr<Kernel::Event> styleset_changed_event; 307 Kernel::EventPair styleset_changed_event;
307 Vibration last_processed_vibration{}; 308 Vibration last_processed_vibration{};
308 std::array<ControllerHolder, 10> connected_controllers{}; 309 std::array<ControllerHolder, 10> connected_controllers{};
309 bool can_controllers_vibrate{true}; 310 bool can_controllers_vibrate{true};
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 46496e9bb..2ec38c726 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -13,8 +13,9 @@
13#include "core/hle/ipc_helpers.h" 13#include "core/hle/ipc_helpers.h"
14#include "core/hle/kernel/client_port.h" 14#include "core/hle/kernel/client_port.h"
15#include "core/hle/kernel/client_session.h" 15#include "core/hle/kernel/client_session.h"
16#include "core/hle/kernel/event.h" 16#include "core/hle/kernel/readable_event.h"
17#include "core/hle/kernel/shared_memory.h" 17#include "core/hle/kernel/shared_memory.h"
18#include "core/hle/kernel/writable_event.h"
18#include "core/hle/service/hid/hid.h" 19#include "core/hle/service/hid/hid.h"
19#include "core/hle/service/hid/irs.h" 20#include "core/hle/service/hid/irs.h"
20#include "core/hle/service/hid/xcd.h" 21#include "core/hle/service/hid/xcd.h"
diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp
index ca119dd3a..453d90a22 100644
--- a/src/core/hle/service/ldr/ldr.cpp
+++ b/src/core/hle/service/ldr/ldr.cpp
@@ -335,10 +335,7 @@ public:
335 vm_manager.ReprotectRange(*map_address + header.rw_offset, header.rw_size, 335 vm_manager.ReprotectRange(*map_address + header.rw_offset, header.rw_size,
336 Kernel::VMAPermission::ReadWrite); 336 Kernel::VMAPermission::ReadWrite);
337 337
338 Core::System::GetInstance().ArmInterface(0).ClearInstructionCache(); 338 Core::System::GetInstance().InvalidateCpuInstructionCaches();
339 Core::System::GetInstance().ArmInterface(1).ClearInstructionCache();
340 Core::System::GetInstance().ArmInterface(2).ClearInstructionCache();
341 Core::System::GetInstance().ArmInterface(3).ClearInstructionCache();
342 339
343 nro.insert_or_assign(*map_address, NROInfo{hash, nro_size + bss_size}); 340 nro.insert_or_assign(*map_address, NROInfo{hash, nro_size + bss_size});
344 341
@@ -391,10 +388,7 @@ public:
391 Kernel::MemoryState::ModuleCodeStatic) == RESULT_SUCCESS); 388 Kernel::MemoryState::ModuleCodeStatic) == RESULT_SUCCESS);
392 ASSERT(process->UnmapMemory(mapped_addr, 0, nro_size) == RESULT_SUCCESS); 389 ASSERT(process->UnmapMemory(mapped_addr, 0, nro_size) == RESULT_SUCCESS);
393 390
394 Core::System::GetInstance().ArmInterface(0).ClearInstructionCache(); 391 Core::System::GetInstance().InvalidateCpuInstructionCaches();
395 Core::System::GetInstance().ArmInterface(1).ClearInstructionCache();
396 Core::System::GetInstance().ArmInterface(2).ClearInstructionCache();
397 Core::System::GetInstance().ArmInterface(3).ClearInstructionCache();
398 392
399 nro.erase(iter); 393 nro.erase(iter);
400 IPC::ResponseBuilder rb{ctx, 2}; 394 IPC::ResponseBuilder rb{ctx, 2};
diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp
index ff9170c24..d5df112a0 100644
--- a/src/core/hle/service/nfp/nfp.cpp
+++ b/src/core/hle/service/nfp/nfp.cpp
@@ -7,7 +7,9 @@
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8#include "core/core.h" 8#include "core/core.h"
9#include "core/hle/ipc_helpers.h" 9#include "core/hle/ipc_helpers.h"
10#include "core/hle/kernel/event.h" 10#include "core/hle/kernel/kernel.h"
11#include "core/hle/kernel/readable_event.h"
12#include "core/hle/kernel/writable_event.h"
11#include "core/hle/lock.h" 13#include "core/hle/lock.h"
12#include "core/hle/service/hid/hid.h" 14#include "core/hle/service/hid/hid.h"
13#include "core/hle/service/nfp/nfp.h" 15#include "core/hle/service/nfp/nfp.h"
@@ -23,8 +25,8 @@ constexpr ResultCode ERR_TAG_FAILED(ErrorModule::NFP,
23Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) 25Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
24 : ServiceFramework(name), module(std::move(module)) { 26 : ServiceFramework(name), module(std::move(module)) {
25 auto& kernel = Core::System::GetInstance().Kernel(); 27 auto& kernel = Core::System::GetInstance().Kernel();
26 nfc_tag_load = 28 nfc_tag_load = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
27 Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IUser:NFCTagDetected"); 29 "IUser:NFCTagDetected");
28} 30}
29 31
30Module::Interface::~Interface() = default; 32Module::Interface::~Interface() = default;
@@ -63,10 +65,10 @@ public:
63 RegisterHandlers(functions); 65 RegisterHandlers(functions);
64 66
65 auto& kernel = Core::System::GetInstance().Kernel(); 67 auto& kernel = Core::System::GetInstance().Kernel();
66 deactivate_event = 68 deactivate_event = Kernel::WritableEvent::CreateEventPair(
67 Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IUser:DeactivateEvent"); 69 kernel, Kernel::ResetType::OneShot, "IUser:DeactivateEvent");
68 availability_change_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, 70 availability_change_event = Kernel::WritableEvent::CreateEventPair(
69 "IUser:AvailabilityChangeEvent"); 71 kernel, Kernel::ResetType::OneShot, "IUser:AvailabilityChangeEvent");
70 } 72 }
71 73
72private: 74private:
@@ -164,7 +166,7 @@ private:
164 166
165 IPC::ResponseBuilder rb{ctx, 2, 1}; 167 IPC::ResponseBuilder rb{ctx, 2, 1};
166 rb.Push(RESULT_SUCCESS); 168 rb.Push(RESULT_SUCCESS);
167 rb.PushCopyObjects(deactivate_event); 169 rb.PushCopyObjects(deactivate_event.readable);
168 } 170 }
169 171
170 void StopDetection(Kernel::HLERequestContext& ctx) { 172 void StopDetection(Kernel::HLERequestContext& ctx) {
@@ -173,7 +175,7 @@ private:
173 switch (device_state) { 175 switch (device_state) {
174 case DeviceState::TagFound: 176 case DeviceState::TagFound:
175 case DeviceState::TagNearby: 177 case DeviceState::TagNearby:
176 deactivate_event->Signal(); 178 deactivate_event.writable->Signal();
177 device_state = DeviceState::Initialized; 179 device_state = DeviceState::Initialized;
178 break; 180 break;
179 case DeviceState::SearchingForTag: 181 case DeviceState::SearchingForTag:
@@ -264,7 +266,7 @@ private:
264 266
265 IPC::ResponseBuilder rb{ctx, 2, 1}; 267 IPC::ResponseBuilder rb{ctx, 2, 1};
266 rb.Push(RESULT_SUCCESS); 268 rb.Push(RESULT_SUCCESS);
267 rb.PushCopyObjects(availability_change_event); 269 rb.PushCopyObjects(availability_change_event.readable);
268 } 270 }
269 271
270 void GetRegisterInfo(Kernel::HLERequestContext& ctx) { 272 void GetRegisterInfo(Kernel::HLERequestContext& ctx) {
@@ -319,8 +321,8 @@ private:
319 const u32 npad_id{0}; // Player 1 controller 321 const u32 npad_id{0}; // Player 1 controller
320 State state{State::NonInitialized}; 322 State state{State::NonInitialized};
321 DeviceState device_state{DeviceState::Initialized}; 323 DeviceState device_state{DeviceState::Initialized};
322 Kernel::SharedPtr<Kernel::Event> deactivate_event; 324 Kernel::EventPair deactivate_event;
323 Kernel::SharedPtr<Kernel::Event> availability_change_event; 325 Kernel::EventPair availability_change_event;
324 const Module::Interface& nfp_interface; 326 const Module::Interface& nfp_interface;
325}; 327};
326 328
@@ -339,12 +341,14 @@ bool Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) {
339 } 341 }
340 342
341 std::memcpy(&amiibo, buffer.data(), sizeof(amiibo)); 343 std::memcpy(&amiibo, buffer.data(), sizeof(amiibo));
342 nfc_tag_load->Signal(); 344 nfc_tag_load.writable->Signal();
343 return true; 345 return true;
344} 346}
345const Kernel::SharedPtr<Kernel::Event>& Module::Interface::GetNFCEvent() const { 347
346 return nfc_tag_load; 348const Kernel::SharedPtr<Kernel::ReadableEvent>& Module::Interface::GetNFCEvent() const {
349 return nfc_tag_load.readable;
347} 350}
351
348const Module::Interface::AmiiboFile& Module::Interface::GetAmiiboBuffer() const { 352const Module::Interface::AmiiboFile& Module::Interface::GetAmiiboBuffer() const {
349 return amiibo; 353 return amiibo;
350} 354}
diff --git a/src/core/hle/service/nfp/nfp.h b/src/core/hle/service/nfp/nfp.h
index 5c0ae8a54..a1817e991 100644
--- a/src/core/hle/service/nfp/nfp.h
+++ b/src/core/hle/service/nfp/nfp.h
@@ -6,7 +6,8 @@
6 6
7#include <array> 7#include <array>
8#include <vector> 8#include <vector>
9#include "core/hle/kernel/event.h" 9#include "core/hle/kernel/readable_event.h"
10#include "core/hle/kernel/writable_event.h"
10#include "core/hle/service/service.h" 11#include "core/hle/service/service.h"
11 12
12namespace Service::NFP { 13namespace Service::NFP {
@@ -33,11 +34,11 @@ public:
33 34
34 void CreateUserInterface(Kernel::HLERequestContext& ctx); 35 void CreateUserInterface(Kernel::HLERequestContext& ctx);
35 bool LoadAmiibo(const std::vector<u8>& buffer); 36 bool LoadAmiibo(const std::vector<u8>& buffer);
36 const Kernel::SharedPtr<Kernel::Event>& GetNFCEvent() const; 37 const Kernel::SharedPtr<Kernel::ReadableEvent>& GetNFCEvent() const;
37 const AmiiboFile& GetAmiiboBuffer() const; 38 const AmiiboFile& GetAmiiboBuffer() const;
38 39
39 private: 40 private:
40 Kernel::SharedPtr<Kernel::Event> nfc_tag_load{}; 41 Kernel::EventPair nfc_tag_load{};
41 AmiiboFile amiibo{}; 42 AmiiboFile amiibo{};
42 43
43 protected: 44 protected:
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp
index dee391201..60479bb45 100644
--- a/src/core/hle/service/nifm/nifm.cpp
+++ b/src/core/hle/service/nifm/nifm.cpp
@@ -4,7 +4,9 @@
4 4
5#include "core/core.h" 5#include "core/core.h"
6#include "core/hle/ipc_helpers.h" 6#include "core/hle/ipc_helpers.h"
7#include "core/hle/kernel/event.h" 7#include "core/hle/kernel/kernel.h"
8#include "core/hle/kernel/readable_event.h"
9#include "core/hle/kernel/writable_event.h"
8#include "core/hle/service/nifm/nifm.h" 10#include "core/hle/service/nifm/nifm.h"
9#include "core/hle/service/service.h" 11#include "core/hle/service/service.h"
10 12
@@ -56,8 +58,10 @@ public:
56 RegisterHandlers(functions); 58 RegisterHandlers(functions);
57 59
58 auto& kernel = Core::System::GetInstance().Kernel(); 60 auto& kernel = Core::System::GetInstance().Kernel();
59 event1 = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IRequest:Event1"); 61 event1 = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
60 event2 = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IRequest:Event2"); 62 "IRequest:Event1");
63 event2 = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
64 "IRequest:Event2");
61 } 65 }
62 66
63private: 67private:
@@ -88,7 +92,7 @@ private:
88 92
89 IPC::ResponseBuilder rb{ctx, 2, 2}; 93 IPC::ResponseBuilder rb{ctx, 2, 2};
90 rb.Push(RESULT_SUCCESS); 94 rb.Push(RESULT_SUCCESS);
91 rb.PushCopyObjects(event1, event2); 95 rb.PushCopyObjects(event1.readable, event2.readable);
92 } 96 }
93 97
94 void Cancel(Kernel::HLERequestContext& ctx) { 98 void Cancel(Kernel::HLERequestContext& ctx) {
@@ -105,7 +109,7 @@ private:
105 rb.Push(RESULT_SUCCESS); 109 rb.Push(RESULT_SUCCESS);
106 } 110 }
107 111
108 Kernel::SharedPtr<Kernel::Event> event1, event2; 112 Kernel::EventPair event1, event2;
109}; 113};
110 114
111class INetworkProfile final : public ServiceFramework<INetworkProfile> { 115class INetworkProfile final : public ServiceFramework<INetworkProfile> {
diff --git a/src/core/hle/service/nim/nim.cpp b/src/core/hle/service/nim/nim.cpp
index 1bbccd444..0dabcd23b 100644
--- a/src/core/hle/service/nim/nim.cpp
+++ b/src/core/hle/service/nim/nim.cpp
@@ -6,7 +6,9 @@
6#include <ctime> 6#include <ctime>
7#include "core/core.h" 7#include "core/core.h"
8#include "core/hle/ipc_helpers.h" 8#include "core/hle/ipc_helpers.h"
9#include "core/hle/kernel/event.h" 9#include "core/hle/kernel/kernel.h"
10#include "core/hle/kernel/readable_event.h"
11#include "core/hle/kernel/writable_event.h"
10#include "core/hle/service/nim/nim.h" 12#include "core/hle/service/nim/nim.h"
11#include "core/hle/service/service.h" 13#include "core/hle/service/service.h"
12#include "core/hle/service/sm/sm.h" 14#include "core/hle/service/sm/sm.h"
@@ -138,19 +140,18 @@ public:
138 RegisterHandlers(functions); 140 RegisterHandlers(functions);
139 141
140 auto& kernel = Core::System::GetInstance().Kernel(); 142 auto& kernel = Core::System::GetInstance().Kernel();
141 finished_event = 143 finished_event = Kernel::WritableEvent::CreateEventPair(
142 Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, 144 kernel, Kernel::ResetType::OneShot,
143 "IEnsureNetworkClockAvailabilityService:FinishEvent"); 145 "IEnsureNetworkClockAvailabilityService:FinishEvent");
144 } 146 }
145 147
146private: 148private:
147 Kernel::SharedPtr<Kernel::Event> finished_event; 149 Kernel::EventPair finished_event;
148 150
149 void StartTask(Kernel::HLERequestContext& ctx) { 151 void StartTask(Kernel::HLERequestContext& ctx) {
150 // No need to connect to the internet, just finish the task straight away. 152 // No need to connect to the internet, just finish the task straight away.
151 LOG_DEBUG(Service_NIM, "called"); 153 LOG_DEBUG(Service_NIM, "called");
152 154 finished_event.writable->Signal();
153 finished_event->Signal();
154 IPC::ResponseBuilder rb{ctx, 2}; 155 IPC::ResponseBuilder rb{ctx, 2};
155 rb.Push(RESULT_SUCCESS); 156 rb.Push(RESULT_SUCCESS);
156 } 157 }
@@ -160,7 +161,7 @@ private:
160 161
161 IPC::ResponseBuilder rb{ctx, 2, 1}; 162 IPC::ResponseBuilder rb{ctx, 2, 1};
162 rb.Push(RESULT_SUCCESS); 163 rb.Push(RESULT_SUCCESS);
163 rb.PushCopyObjects(finished_event); 164 rb.PushCopyObjects(finished_event.readable);
164 } 165 }
165 166
166 void GetResult(Kernel::HLERequestContext& ctx) { 167 void GetResult(Kernel::HLERequestContext& ctx) {
@@ -172,8 +173,7 @@ private:
172 173
173 void Cancel(Kernel::HLERequestContext& ctx) { 174 void Cancel(Kernel::HLERequestContext& ctx) {
174 LOG_DEBUG(Service_NIM, "called"); 175 LOG_DEBUG(Service_NIM, "called");
175 176 finished_event.writable->Clear();
176 finished_event->Clear();
177 IPC::ResponseBuilder rb{ctx, 2}; 177 IPC::ResponseBuilder rb{ctx, 2};
178 rb.Push(RESULT_SUCCESS); 178 rb.Push(RESULT_SUCCESS);
179 } 179 }
diff --git a/src/core/hle/service/nvdrv/interface.cpp b/src/core/hle/service/nvdrv/interface.cpp
index ff76e0524..3b9ab4b14 100644
--- a/src/core/hle/service/nvdrv/interface.cpp
+++ b/src/core/hle/service/nvdrv/interface.cpp
@@ -6,7 +6,9 @@
6#include "common/logging/log.h" 6#include "common/logging/log.h"
7#include "core/core.h" 7#include "core/core.h"
8#include "core/hle/ipc_helpers.h" 8#include "core/hle/ipc_helpers.h"
9#include "core/hle/kernel/event.h" 9#include "core/hle/kernel/kernel.h"
10#include "core/hle/kernel/readable_event.h"
11#include "core/hle/kernel/writable_event.h"
10#include "core/hle/service/nvdrv/interface.h" 12#include "core/hle/service/nvdrv/interface.h"
11#include "core/hle/service/nvdrv/nvdrv.h" 13#include "core/hle/service/nvdrv/nvdrv.h"
12 14
@@ -69,7 +71,7 @@ void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) {
69 71
70 IPC::ResponseBuilder rb{ctx, 3, 1}; 72 IPC::ResponseBuilder rb{ctx, 3, 1};
71 rb.Push(RESULT_SUCCESS); 73 rb.Push(RESULT_SUCCESS);
72 rb.PushCopyObjects(query_event); 74 rb.PushCopyObjects(query_event.readable);
73 rb.Push<u32>(0); 75 rb.Push<u32>(0);
74} 76}
75 77
@@ -127,7 +129,8 @@ NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name)
127 RegisterHandlers(functions); 129 RegisterHandlers(functions);
128 130
129 auto& kernel = Core::System::GetInstance().Kernel(); 131 auto& kernel = Core::System::GetInstance().Kernel();
130 query_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "NVDRV::query_event"); 132 query_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
133 "NVDRV::query_event");
131} 134}
132 135
133NVDRV::~NVDRV() = default; 136NVDRV::~NVDRV() = default;
diff --git a/src/core/hle/service/nvdrv/interface.h b/src/core/hle/service/nvdrv/interface.h
index 5a1e4baa7..fe311b069 100644
--- a/src/core/hle/service/nvdrv/interface.h
+++ b/src/core/hle/service/nvdrv/interface.h
@@ -5,10 +5,13 @@
5#pragma once 5#pragma once
6 6
7#include <memory> 7#include <memory>
8#include "core/hle/kernel/event.h"
9#include "core/hle/service/nvdrv/nvdrv.h" 8#include "core/hle/service/nvdrv/nvdrv.h"
10#include "core/hle/service/service.h" 9#include "core/hle/service/service.h"
11 10
11namespace Kernel {
12class WritableEvent;
13}
14
12namespace Service::Nvidia { 15namespace Service::Nvidia {
13 16
14class NVDRV final : public ServiceFramework<NVDRV> { 17class NVDRV final : public ServiceFramework<NVDRV> {
@@ -31,7 +34,7 @@ private:
31 34
32 u64 pid{}; 35 u64 pid{};
33 36
34 Kernel::SharedPtr<Kernel::Event> query_event; 37 Kernel::EventPair query_event;
35}; 38};
36 39
37} // namespace Service::Nvidia 40} // namespace Service::Nvidia
diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp
index 172a1a441..fc07d9bb8 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.cpp
+++ b/src/core/hle/service/nvflinger/buffer_queue.cpp
@@ -7,14 +7,17 @@
7#include "common/assert.h" 7#include "common/assert.h"
8#include "common/logging/log.h" 8#include "common/logging/log.h"
9#include "core/core.h" 9#include "core/core.h"
10#include "core/hle/kernel/kernel.h"
11#include "core/hle/kernel/readable_event.h"
12#include "core/hle/kernel/writable_event.h"
10#include "core/hle/service/nvflinger/buffer_queue.h" 13#include "core/hle/service/nvflinger/buffer_queue.h"
11 14
12namespace Service::NVFlinger { 15namespace Service::NVFlinger {
13 16
14BufferQueue::BufferQueue(u32 id, u64 layer_id) : id(id), layer_id(layer_id) { 17BufferQueue::BufferQueue(u32 id, u64 layer_id) : id(id), layer_id(layer_id) {
15 auto& kernel = Core::System::GetInstance().Kernel(); 18 auto& kernel = Core::System::GetInstance().Kernel();
16 buffer_wait_event = 19 buffer_wait_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
17 Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "BufferQueue NativeHandle"); 20 "BufferQueue NativeHandle");
18} 21}
19 22
20BufferQueue::~BufferQueue() = default; 23BufferQueue::~BufferQueue() = default;
@@ -28,7 +31,7 @@ void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer)
28 buffer.status = Buffer::Status::Free; 31 buffer.status = Buffer::Status::Free;
29 32
30 queue.emplace_back(buffer); 33 queue.emplace_back(buffer);
31 buffer_wait_event->Signal(); 34 buffer_wait_event.writable->Signal();
32} 35}
33 36
34std::optional<u32> BufferQueue::DequeueBuffer(u32 width, u32 height) { 37std::optional<u32> BufferQueue::DequeueBuffer(u32 width, u32 height) {
@@ -87,7 +90,7 @@ void BufferQueue::ReleaseBuffer(u32 slot) {
87 ASSERT(itr->status == Buffer::Status::Acquired); 90 ASSERT(itr->status == Buffer::Status::Acquired);
88 itr->status = Buffer::Status::Free; 91 itr->status = Buffer::Status::Free;
89 92
90 buffer_wait_event->Signal(); 93 buffer_wait_event.writable->Signal();
91} 94}
92 95
93u32 BufferQueue::Query(QueryType type) { 96u32 BufferQueue::Query(QueryType type) {
@@ -104,4 +107,12 @@ u32 BufferQueue::Query(QueryType type) {
104 return 0; 107 return 0;
105} 108}
106 109
110Kernel::SharedPtr<Kernel::WritableEvent> BufferQueue::GetWritableBufferWaitEvent() const {
111 return buffer_wait_event.writable;
112}
113
114Kernel::SharedPtr<Kernel::ReadableEvent> BufferQueue::GetBufferWaitEvent() const {
115 return buffer_wait_event.readable;
116}
117
107} // namespace Service::NVFlinger 118} // namespace Service::NVFlinger
diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h
index 8cff5eb71..b171f256c 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.h
+++ b/src/core/hle/service/nvflinger/buffer_queue.h
@@ -10,7 +10,8 @@
10#include "common/common_funcs.h" 10#include "common/common_funcs.h"
11#include "common/math_util.h" 11#include "common/math_util.h"
12#include "common/swap.h" 12#include "common/swap.h"
13#include "core/hle/kernel/event.h" 13#include "core/hle/kernel/object.h"
14#include "core/hle/kernel/writable_event.h"
14 15
15namespace CoreTiming { 16namespace CoreTiming {
16struct EventType; 17struct EventType;
@@ -86,16 +87,16 @@ public:
86 return id; 87 return id;
87 } 88 }
88 89
89 Kernel::SharedPtr<Kernel::Event> GetBufferWaitEvent() const { 90 Kernel::SharedPtr<Kernel::WritableEvent> GetWritableBufferWaitEvent() const;
90 return buffer_wait_event; 91
91 } 92 Kernel::SharedPtr<Kernel::ReadableEvent> GetBufferWaitEvent() const;
92 93
93private: 94private:
94 u32 id; 95 u32 id;
95 u64 layer_id; 96 u64 layer_id;
96 97
97 std::vector<Buffer> queue; 98 std::vector<Buffer> queue;
98 Kernel::SharedPtr<Kernel::Event> buffer_wait_event; 99 Kernel::EventPair buffer_wait_event;
99}; 100};
100 101
101} // namespace Service::NVFlinger 102} // namespace Service::NVFlinger
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index 214e6d1b3..05af2d593 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -13,6 +13,9 @@
13#include "core/core.h" 13#include "core/core.h"
14#include "core/core_timing.h" 14#include "core/core_timing.h"
15#include "core/core_timing_util.h" 15#include "core/core_timing_util.h"
16#include "core/hle/kernel/kernel.h"
17#include "core/hle/kernel/readable_event.h"
18#include "core/hle/kernel/writable_event.h"
16#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h" 19#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h"
17#include "core/hle/service/nvdrv/nvdrv.h" 20#include "core/hle/service/nvdrv/nvdrv.h"
18#include "core/hle/service/nvflinger/buffer_queue.h" 21#include "core/hle/service/nvflinger/buffer_queue.h"
@@ -83,9 +86,8 @@ u32 NVFlinger::GetBufferQueueId(u64 display_id, u64 layer_id) {
83 return layer.buffer_queue->GetId(); 86 return layer.buffer_queue->GetId();
84} 87}
85 88
86Kernel::SharedPtr<Kernel::Event> NVFlinger::GetVsyncEvent(u64 display_id) { 89Kernel::SharedPtr<Kernel::ReadableEvent> NVFlinger::GetVsyncEvent(u64 display_id) {
87 const auto& display = GetDisplay(display_id); 90 return GetDisplay(display_id).vsync_event.readable;
88 return display.vsync_event;
89} 91}
90 92
91std::shared_ptr<BufferQueue> NVFlinger::GetBufferQueue(u32 id) const { 93std::shared_ptr<BufferQueue> NVFlinger::GetBufferQueue(u32 id) const {
@@ -117,7 +119,7 @@ Layer& NVFlinger::GetLayer(u64 display_id, u64 layer_id) {
117void NVFlinger::Compose() { 119void NVFlinger::Compose() {
118 for (auto& display : displays) { 120 for (auto& display : displays) {
119 // Trigger vsync for this display at the end of drawing 121 // Trigger vsync for this display at the end of drawing
120 SCOPE_EXIT({ display.vsync_event->Signal(); }); 122 SCOPE_EXIT({ display.vsync_event.writable->Signal(); });
121 123
122 // Don't do anything for displays without layers. 124 // Don't do anything for displays without layers.
123 if (display.layers.empty()) 125 if (display.layers.empty())
@@ -164,7 +166,8 @@ Layer::~Layer() = default;
164 166
165Display::Display(u64 id, std::string name) : id(id), name(std::move(name)) { 167Display::Display(u64 id, std::string name) : id(id), name(std::move(name)) {
166 auto& kernel = Core::System::GetInstance().Kernel(); 168 auto& kernel = Core::System::GetInstance().Kernel();
167 vsync_event = Kernel::Event::Create(kernel, Kernel::ResetType::Pulse, "Display VSync Event"); 169 vsync_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Pulse,
170 fmt::format("Display VSync Event {}", id));
168} 171}
169 172
170Display::~Display() = default; 173Display::~Display() = default;
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h
index 3dc69e69b..9abba555b 100644
--- a/src/core/hle/service/nvflinger/nvflinger.h
+++ b/src/core/hle/service/nvflinger/nvflinger.h
@@ -10,12 +10,17 @@
10#include <vector> 10#include <vector>
11 11
12#include "common/common_types.h" 12#include "common/common_types.h"
13#include "core/hle/kernel/event.h" 13#include "core/hle/kernel/object.h"
14 14
15namespace CoreTiming { 15namespace CoreTiming {
16struct EventType; 16struct EventType;
17} 17}
18 18
19namespace Kernel {
20class ReadableEvent;
21class WritableEvent;
22} // namespace Kernel
23
19namespace Service::Nvidia { 24namespace Service::Nvidia {
20class Module; 25class Module;
21} 26}
@@ -40,7 +45,7 @@ struct Display {
40 std::string name; 45 std::string name;
41 46
42 std::vector<Layer> layers; 47 std::vector<Layer> layers;
43 Kernel::SharedPtr<Kernel::Event> vsync_event; 48 Kernel::EventPair vsync_event;
44}; 49};
45 50
46class NVFlinger final { 51class NVFlinger final {
@@ -61,7 +66,7 @@ public:
61 u32 GetBufferQueueId(u64 display_id, u64 layer_id); 66 u32 GetBufferQueueId(u64 display_id, u64 layer_id);
62 67
63 /// Gets the vsync event for the specified display. 68 /// Gets the vsync event for the specified display.
64 Kernel::SharedPtr<Kernel::Event> GetVsyncEvent(u64 display_id); 69 Kernel::SharedPtr<Kernel::ReadableEvent> GetVsyncEvent(u64 display_id);
65 70
66 /// Obtains a buffer queue identified by the id. 71 /// Obtains a buffer queue identified by the id.
67 std::shared_ptr<BufferQueue> GetBufferQueue(u32 id) const; 72 std::shared_ptr<BufferQueue> GetBufferQueue(u32 id) const;
diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp
index 40a9144f9..1afc43f75 100644
--- a/src/core/hle/service/set/set.cpp
+++ b/src/core/hle/service/set/set.cpp
@@ -35,6 +35,8 @@ constexpr std::array<LanguageCode, 17> available_language_codes = {{
35constexpr std::size_t pre4_0_0_max_entries = 0xF; 35constexpr std::size_t pre4_0_0_max_entries = 0xF;
36constexpr std::size_t post4_0_0_max_entries = 0x40; 36constexpr std::size_t post4_0_0_max_entries = 0x40;
37 37
38constexpr ResultCode ERR_INVALID_LANGUAGE{ErrorModule::Settings, 625};
39
38LanguageCode GetLanguageCodeFromIndex(std::size_t index) { 40LanguageCode GetLanguageCodeFromIndex(std::size_t index) {
39 return available_language_codes.at(index); 41 return available_language_codes.at(index);
40} 42}
@@ -67,6 +69,21 @@ void SET::GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx) {
67 PushResponseLanguageCode(ctx, pre4_0_0_max_entries); 69 PushResponseLanguageCode(ctx, pre4_0_0_max_entries);
68} 70}
69 71
72void SET::MakeLanguageCode(Kernel::HLERequestContext& ctx) {
73 IPC::RequestParser rp{ctx};
74 const auto index = rp.Pop<u32>();
75
76 if (index >= available_language_codes.size()) {
77 IPC::ResponseBuilder rb{ctx, 2};
78 rb.Push(ERR_INVALID_LANGUAGE);
79 return;
80 }
81
82 IPC::ResponseBuilder rb{ctx, 4};
83 rb.Push(RESULT_SUCCESS);
84 rb.PushEnum(available_language_codes[index]);
85}
86
70void SET::GetAvailableLanguageCodes2(Kernel::HLERequestContext& ctx) { 87void SET::GetAvailableLanguageCodes2(Kernel::HLERequestContext& ctx) {
71 LOG_DEBUG(Service_SET, "called"); 88 LOG_DEBUG(Service_SET, "called");
72 89
@@ -95,14 +112,14 @@ void SET::GetLanguageCode(Kernel::HLERequestContext& ctx) {
95 112
96 IPC::ResponseBuilder rb{ctx, 4}; 113 IPC::ResponseBuilder rb{ctx, 4};
97 rb.Push(RESULT_SUCCESS); 114 rb.Push(RESULT_SUCCESS);
98 rb.Push(static_cast<u64>(available_language_codes[Settings::values.language_index])); 115 rb.PushEnum(available_language_codes[Settings::values.language_index]);
99} 116}
100 117
101SET::SET() : ServiceFramework("set") { 118SET::SET() : ServiceFramework("set") {
102 static const FunctionInfo functions[] = { 119 static const FunctionInfo functions[] = {
103 {0, &SET::GetLanguageCode, "GetLanguageCode"}, 120 {0, &SET::GetLanguageCode, "GetLanguageCode"},
104 {1, &SET::GetAvailableLanguageCodes, "GetAvailableLanguageCodes"}, 121 {1, &SET::GetAvailableLanguageCodes, "GetAvailableLanguageCodes"},
105 {2, nullptr, "MakeLanguageCode"}, 122 {2, &SET::MakeLanguageCode, "MakeLanguageCode"},
106 {3, &SET::GetAvailableLanguageCodeCount, "GetAvailableLanguageCodeCount"}, 123 {3, &SET::GetAvailableLanguageCodeCount, "GetAvailableLanguageCodeCount"},
107 {4, nullptr, "GetRegionCode"}, 124 {4, nullptr, "GetRegionCode"},
108 {5, &SET::GetAvailableLanguageCodes2, "GetAvailableLanguageCodes2"}, 125 {5, &SET::GetAvailableLanguageCodes2, "GetAvailableLanguageCodes2"},
diff --git a/src/core/hle/service/set/set.h b/src/core/hle/service/set/set.h
index 266f13e46..31f9cb296 100644
--- a/src/core/hle/service/set/set.h
+++ b/src/core/hle/service/set/set.h
@@ -38,6 +38,7 @@ public:
38private: 38private:
39 void GetLanguageCode(Kernel::HLERequestContext& ctx); 39 void GetLanguageCode(Kernel::HLERequestContext& ctx);
40 void GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx); 40 void GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx);
41 void MakeLanguageCode(Kernel::HLERequestContext& ctx);
41 void GetAvailableLanguageCodes2(Kernel::HLERequestContext& ctx); 42 void GetAvailableLanguageCodes2(Kernel::HLERequestContext& ctx);
42 void GetAvailableLanguageCodeCount(Kernel::HLERequestContext& ctx); 43 void GetAvailableLanguageCodeCount(Kernel::HLERequestContext& ctx);
43 void GetAvailableLanguageCodeCount2(Kernel::HLERequestContext& ctx); 44 void GetAvailableLanguageCodeCount2(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/usb/usb.cpp b/src/core/hle/service/usb/usb.cpp
index f082a63bc..58a9845fc 100644
--- a/src/core/hle/service/usb/usb.cpp
+++ b/src/core/hle/service/usb/usb.cpp
@@ -73,7 +73,7 @@ public:
73 {3, nullptr, "Populate"}, 73 {3, nullptr, "Populate"},
74 {4, nullptr, "PostBufferAsync"}, 74 {4, nullptr, "PostBufferAsync"},
75 {5, nullptr, "GetXferReport"}, 75 {5, nullptr, "GetXferReport"},
76 {6, nullptr, "Unknown2"}, 76 {6, nullptr, "PostBufferMultiAsync"},
77 {7, nullptr, "Unknown3"}, 77 {7, nullptr, "Unknown3"},
78 {8, nullptr, "Unknown4"}, 78 {8, nullptr, "Unknown4"},
79 }; 79 };
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index 5120abfff..311b0c765 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -18,7 +18,8 @@
18#include "common/swap.h" 18#include "common/swap.h"
19#include "core/core_timing.h" 19#include "core/core_timing.h"
20#include "core/hle/ipc_helpers.h" 20#include "core/hle/ipc_helpers.h"
21#include "core/hle/kernel/event.h" 21#include "core/hle/kernel/readable_event.h"
22#include "core/hle/kernel/writable_event.h"
22#include "core/hle/service/nvdrv/nvdrv.h" 23#include "core/hle/service/nvdrv/nvdrv.h"
23#include "core/hle/service/nvflinger/buffer_queue.h" 24#include "core/hle/service/nvflinger/buffer_queue.h"
24#include "core/hle/service/nvflinger/nvflinger.h" 25#include "core/hle/service/nvflinger/nvflinger.h"
@@ -542,12 +543,14 @@ private:
542 // Repeat TransactParcel DequeueBuffer when a buffer is available 543 // Repeat TransactParcel DequeueBuffer when a buffer is available
543 auto buffer_queue = nv_flinger->GetBufferQueue(id); 544 auto buffer_queue = nv_flinger->GetBufferQueue(id);
544 std::optional<u32> slot = buffer_queue->DequeueBuffer(width, height); 545 std::optional<u32> slot = buffer_queue->DequeueBuffer(width, height);
546 ASSERT_MSG(slot != std::nullopt, "Could not dequeue buffer.");
547
545 IGBPDequeueBufferResponseParcel response{*slot}; 548 IGBPDequeueBufferResponseParcel response{*slot};
546 ctx.WriteBuffer(response.Serialize()); 549 ctx.WriteBuffer(response.Serialize());
547 IPC::ResponseBuilder rb{ctx, 2}; 550 IPC::ResponseBuilder rb{ctx, 2};
548 rb.Push(RESULT_SUCCESS); 551 rb.Push(RESULT_SUCCESS);
549 }, 552 },
550 buffer_queue->GetBufferWaitEvent()); 553 buffer_queue->GetWritableBufferWaitEvent());
551 } 554 }
552 } else if (transaction == TransactionId::RequestBuffer) { 555 } else if (transaction == TransactionId::RequestBuffer) {
553 IGBPRequestBufferRequestParcel request{ctx.ReadBuffer()}; 556 IGBPRequestBufferRequestParcel request{ctx.ReadBuffer()};
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp
index 8518dddcb..ac04d72d7 100644
--- a/src/core/loader/deconstructed_rom_directory.cpp
+++ b/src/core/loader/deconstructed_rom_directory.cpp
@@ -7,7 +7,6 @@
7#include "common/common_funcs.h" 7#include "common/common_funcs.h"
8#include "common/file_util.h" 8#include "common/file_util.h"
9#include "common/logging/log.h" 9#include "common/logging/log.h"
10#include "core/core.h"
11#include "core/file_sys/content_archive.h" 10#include "core/file_sys/content_archive.h"
12#include "core/file_sys/control_metadata.h" 11#include "core/file_sys/control_metadata.h"
13#include "core/file_sys/patch_manager.h" 12#include "core/file_sys/patch_manager.h"
@@ -146,7 +145,7 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(Kernel::Process& process)
146 const VAddr load_addr = next_load_addr; 145 const VAddr load_addr = next_load_addr;
147 const bool should_pass_arguments = std::strcmp(module, "rtld") == 0; 146 const bool should_pass_arguments = std::strcmp(module, "rtld") == 0;
148 const auto tentative_next_load_addr = 147 const auto tentative_next_load_addr =
149 AppLoader_NSO::LoadModule(*module_file, load_addr, should_pass_arguments, pm); 148 AppLoader_NSO::LoadModule(process, *module_file, load_addr, should_pass_arguments, pm);
150 if (!tentative_next_load_addr) { 149 if (!tentative_next_load_addr) {
151 return ResultStatus::ErrorLoadingNSO; 150 return ResultStatus::ErrorLoadingNSO;
152 } 151 }
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp
index fbbd6b0de..4fad0c0dd 100644
--- a/src/core/loader/nro.cpp
+++ b/src/core/loader/nro.cpp
@@ -10,7 +10,6 @@
10#include "common/file_util.h" 10#include "common/file_util.h"
11#include "common/logging/log.h" 11#include "common/logging/log.h"
12#include "common/swap.h" 12#include "common/swap.h"
13#include "core/core.h"
14#include "core/file_sys/control_metadata.h" 13#include "core/file_sys/control_metadata.h"
15#include "core/file_sys/romfs_factory.h" 14#include "core/file_sys/romfs_factory.h"
16#include "core/file_sys/vfs_offset.h" 15#include "core/file_sys/vfs_offset.h"
@@ -129,9 +128,8 @@ static constexpr u32 PageAlignSize(u32 size) {
129 return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK; 128 return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK;
130} 129}
131 130
132/*static*/ bool AppLoader_NRO::LoadNro(const std::vector<u8>& data, const std::string& name, 131static bool LoadNroImpl(Kernel::Process& process, const std::vector<u8>& data,
133 VAddr load_base) { 132 const std::string& name, VAddr load_base) {
134
135 if (data.size() < sizeof(NroHeader)) { 133 if (data.size() < sizeof(NroHeader)) {
136 return {}; 134 return {};
137 } 135 }
@@ -189,7 +187,7 @@ static constexpr u32 PageAlignSize(u32 size) {
189 187
190 // Load codeset for current process 188 // Load codeset for current process
191 codeset.memory = std::make_shared<std::vector<u8>>(std::move(program_image)); 189 codeset.memory = std::make_shared<std::vector<u8>>(std::move(program_image));
192 Core::CurrentProcess()->LoadModule(std::move(codeset), load_base); 190 process.LoadModule(std::move(codeset), load_base);
193 191
194 // Register module with GDBStub 192 // Register module with GDBStub
195 GDBStub::RegisterModule(name, load_base, load_base); 193 GDBStub::RegisterModule(name, load_base, load_base);
@@ -197,8 +195,9 @@ static constexpr u32 PageAlignSize(u32 size) {
197 return true; 195 return true;
198} 196}
199 197
200bool AppLoader_NRO::LoadNro(const FileSys::VfsFile& file, VAddr load_base) { 198bool AppLoader_NRO::LoadNro(Kernel::Process& process, const FileSys::VfsFile& file,
201 return AppLoader_NRO::LoadNro(file.ReadAllBytes(), file.GetName(), load_base); 199 VAddr load_base) {
200 return LoadNroImpl(process, file.ReadAllBytes(), file.GetName(), load_base);
202} 201}
203 202
204ResultStatus AppLoader_NRO::Load(Kernel::Process& process) { 203ResultStatus AppLoader_NRO::Load(Kernel::Process& process) {
@@ -209,7 +208,7 @@ ResultStatus AppLoader_NRO::Load(Kernel::Process& process) {
209 // Load NRO 208 // Load NRO
210 const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress(); 209 const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress();
211 210
212 if (!LoadNro(*file, base_address)) { 211 if (!LoadNro(process, *file, base_address)) {
213 return ResultStatus::ErrorLoadingNRO; 212 return ResultStatus::ErrorLoadingNRO;
214 } 213 }
215 214
diff --git a/src/core/loader/nro.h b/src/core/loader/nro.h
index 3e6959302..6deff3a51 100644
--- a/src/core/loader/nro.h
+++ b/src/core/loader/nro.h
@@ -14,6 +14,10 @@ namespace FileSys {
14class NACP; 14class NACP;
15} 15}
16 16
17namespace Kernel {
18class Process;
19}
20
17namespace Loader { 21namespace Loader {
18 22
19/// Loads an NRO file 23/// Loads an NRO file
@@ -41,10 +45,8 @@ public:
41 ResultStatus ReadTitle(std::string& title) override; 45 ResultStatus ReadTitle(std::string& title) override;
42 bool IsRomFSUpdatable() const override; 46 bool IsRomFSUpdatable() const override;
43 47
44 static bool LoadNro(const std::vector<u8>& data, const std::string& name, VAddr load_base);
45
46private: 48private:
47 bool LoadNro(const FileSys::VfsFile& file, VAddr load_base); 49 bool LoadNro(Kernel::Process& process, const FileSys::VfsFile& file, VAddr load_base);
48 50
49 std::vector<u8> icon_data; 51 std::vector<u8> icon_data;
50 std::unique_ptr<FileSys::NACP> nacp; 52 std::unique_ptr<FileSys::NACP> nacp;
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp
index aaf006309..6ded0b707 100644
--- a/src/core/loader/nso.cpp
+++ b/src/core/loader/nso.cpp
@@ -9,7 +9,6 @@
9#include "common/file_util.h" 9#include "common/file_util.h"
10#include "common/logging/log.h" 10#include "common/logging/log.h"
11#include "common/swap.h" 11#include "common/swap.h"
12#include "core/core.h"
13#include "core/file_sys/patch_manager.h" 12#include "core/file_sys/patch_manager.h"
14#include "core/gdbstub/gdbstub.h" 13#include "core/gdbstub/gdbstub.h"
15#include "core/hle/kernel/process.h" 14#include "core/hle/kernel/process.h"
@@ -93,7 +92,8 @@ static constexpr u32 PageAlignSize(u32 size) {
93 return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK; 92 return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK;
94} 93}
95 94
96std::optional<VAddr> AppLoader_NSO::LoadModule(const FileSys::VfsFile& file, VAddr load_base, 95std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process,
96 const FileSys::VfsFile& file, VAddr load_base,
97 bool should_pass_arguments, 97 bool should_pass_arguments,
98 std::optional<FileSys::PatchManager> pm) { 98 std::optional<FileSys::PatchManager> pm) {
99 if (file.GetSize() < sizeof(NsoHeader)) 99 if (file.GetSize() < sizeof(NsoHeader))
@@ -166,7 +166,7 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(const FileSys::VfsFile& file, VAd
166 166
167 // Load codeset for current process 167 // Load codeset for current process
168 codeset.memory = std::make_shared<std::vector<u8>>(std::move(program_image)); 168 codeset.memory = std::make_shared<std::vector<u8>>(std::move(program_image));
169 Core::CurrentProcess()->LoadModule(std::move(codeset), load_base); 169 process.LoadModule(std::move(codeset), load_base);
170 170
171 // Register module with GDBStub 171 // Register module with GDBStub
172 GDBStub::RegisterModule(file.GetName(), load_base, load_base); 172 GDBStub::RegisterModule(file.GetName(), load_base, load_base);
@@ -181,7 +181,7 @@ ResultStatus AppLoader_NSO::Load(Kernel::Process& process) {
181 181
182 // Load module 182 // Load module
183 const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress(); 183 const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress();
184 if (!LoadModule(*file, base_address, true)) { 184 if (!LoadModule(process, *file, base_address, true)) {
185 return ResultStatus::ErrorLoadingNSO; 185 return ResultStatus::ErrorLoadingNSO;
186 } 186 }
187 LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), base_address); 187 LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), base_address);
diff --git a/src/core/loader/nso.h b/src/core/loader/nso.h
index 433306139..0c1defbb6 100644
--- a/src/core/loader/nso.h
+++ b/src/core/loader/nso.h
@@ -10,6 +10,10 @@
10#include "core/loader/linker.h" 10#include "core/loader/linker.h"
11#include "core/loader/loader.h" 11#include "core/loader/loader.h"
12 12
13namespace Kernel {
14class Process;
15}
16
13namespace Loader { 17namespace Loader {
14 18
15constexpr u64 NSO_ARGUMENT_DATA_ALLOCATION_SIZE = 0x9000; 19constexpr u64 NSO_ARGUMENT_DATA_ALLOCATION_SIZE = 0x9000;
@@ -37,8 +41,8 @@ public:
37 return IdentifyType(file); 41 return IdentifyType(file);
38 } 42 }
39 43
40 static std::optional<VAddr> LoadModule(const FileSys::VfsFile& file, VAddr load_base, 44 static std::optional<VAddr> LoadModule(Kernel::Process& process, const FileSys::VfsFile& file,
41 bool should_pass_arguments, 45 VAddr load_base, bool should_pass_arguments,
42 std::optional<FileSys::PatchManager> pm = {}); 46 std::optional<FileSys::PatchManager> pm = {});
43 47
44 ResultStatus Load(Kernel::Process& process) override; 48 ResultStatus Load(Kernel::Process& process) override;
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 70abd856a..41fd2a6a0 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -53,6 +53,14 @@ void PageTable::Resize(std::size_t address_space_width_in_bits) {
53 53
54 pointers.resize(num_page_table_entries); 54 pointers.resize(num_page_table_entries);
55 attributes.resize(num_page_table_entries); 55 attributes.resize(num_page_table_entries);
56
57 // The default is a 39-bit address space, which causes an initial 1GB allocation size. If the
58 // vector size is subsequently decreased (via resize), the vector might not automatically
59 // actually reallocate/resize its underlying allocation, which wastes up to ~800 MB for
60 // 36-bit titles. Call shrink_to_fit to reduce capacity to what's actually in use.
61
62 pointers.shrink_to_fit();
63 attributes.shrink_to_fit();
56} 64}
57 65
58static void MapPages(PageTable& page_table, VAddr base, u64 size, u8* memory, PageType type) { 66static void MapPages(PageTable& page_table, VAddr base, u64 size, u8* memory, PageType type) {
diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp
deleted file mode 100644
index 8b9c548cc..000000000
--- a/src/video_core/command_processor.cpp
+++ /dev/null
@@ -1,142 +0,0 @@
1// Copyright 2018 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <array>
6#include <cstddef>
7#include <memory>
8#include <utility>
9#include "common/assert.h"
10#include "common/logging/log.h"
11#include "common/microprofile.h"
12#include "common/vector_math.h"
13#include "core/memory.h"
14#include "core/tracer/recorder.h"
15#include "video_core/command_processor.h"
16#include "video_core/engines/fermi_2d.h"
17#include "video_core/engines/kepler_memory.h"
18#include "video_core/engines/maxwell_3d.h"
19#include "video_core/engines/maxwell_compute.h"
20#include "video_core/engines/maxwell_dma.h"
21#include "video_core/gpu.h"
22#include "video_core/renderer_base.h"
23#include "video_core/video_core.h"
24
25namespace Tegra {
26
27enum class BufferMethods {
28 BindObject = 0,
29 CountBufferMethods = 0x40,
30};
31
32MICROPROFILE_DEFINE(ProcessCommandLists, "GPU", "Execute command buffer", MP_RGB(128, 128, 192));
33
34void GPU::ProcessCommandLists(const std::vector<CommandListHeader>& commands) {
35 MICROPROFILE_SCOPE(ProcessCommandLists);
36
37 // On entering GPU code, assume all memory may be touched by the ARM core.
38 maxwell_3d->dirty_flags.OnMemoryWrite();
39
40 auto WriteReg = [this](u32 method, u32 subchannel, u32 value, u32 remaining_params) {
41 LOG_TRACE(HW_GPU,
42 "Processing method {:08X} on subchannel {} value "
43 "{:08X} remaining params {}",
44 method, subchannel, value, remaining_params);
45
46 ASSERT(subchannel < bound_engines.size());
47
48 if (method == static_cast<u32>(BufferMethods::BindObject)) {
49 // Bind the current subchannel to the desired engine id.
50 LOG_DEBUG(HW_GPU, "Binding subchannel {} to engine {}", subchannel, value);
51 bound_engines[subchannel] = static_cast<EngineID>(value);
52 return;
53 }
54
55 if (method < static_cast<u32>(BufferMethods::CountBufferMethods)) {
56 // TODO(Subv): Research and implement these methods.
57 LOG_ERROR(HW_GPU, "Special buffer methods other than Bind are not implemented");
58 return;
59 }
60
61 const EngineID engine = bound_engines[subchannel];
62
63 switch (engine) {
64 case EngineID::FERMI_TWOD_A:
65 fermi_2d->WriteReg(method, value);
66 break;
67 case EngineID::MAXWELL_B:
68 maxwell_3d->WriteReg(method, value, remaining_params);
69 break;
70 case EngineID::MAXWELL_COMPUTE_B:
71 maxwell_compute->WriteReg(method, value);
72 break;
73 case EngineID::MAXWELL_DMA_COPY_A:
74 maxwell_dma->WriteReg(method, value);
75 break;
76 case EngineID::KEPLER_INLINE_TO_MEMORY_B:
77 kepler_memory->WriteReg(method, value);
78 break;
79 default:
80 UNIMPLEMENTED_MSG("Unimplemented engine");
81 }
82 };
83
84 for (auto entry : commands) {
85 Tegra::GPUVAddr address = entry.Address();
86 u32 size = entry.sz;
87 const std::optional<VAddr> head_address = memory_manager->GpuToCpuAddress(address);
88 VAddr current_addr = *head_address;
89 while (current_addr < *head_address + size * sizeof(CommandHeader)) {
90 const CommandHeader header = {Memory::Read32(current_addr)};
91 current_addr += sizeof(u32);
92
93 switch (header.mode.Value()) {
94 case SubmissionMode::IncreasingOld:
95 case SubmissionMode::Increasing: {
96 // Increase the method value with each argument.
97 for (unsigned i = 0; i < header.arg_count; ++i) {
98 WriteReg(header.method + i, header.subchannel, Memory::Read32(current_addr),
99 header.arg_count - i - 1);
100 current_addr += sizeof(u32);
101 }
102 break;
103 }
104 case SubmissionMode::NonIncreasingOld:
105 case SubmissionMode::NonIncreasing: {
106 // Use the same method value for all arguments.
107 for (unsigned i = 0; i < header.arg_count; ++i) {
108 WriteReg(header.method, header.subchannel, Memory::Read32(current_addr),
109 header.arg_count - i - 1);
110 current_addr += sizeof(u32);
111 }
112 break;
113 }
114 case SubmissionMode::IncreaseOnce: {
115 ASSERT(header.arg_count.Value() >= 1);
116
117 // Use the original method for the first argument and then the next method for all
118 // other arguments.
119 WriteReg(header.method, header.subchannel, Memory::Read32(current_addr),
120 header.arg_count - 1);
121 current_addr += sizeof(u32);
122
123 for (unsigned i = 1; i < header.arg_count; ++i) {
124 WriteReg(header.method + 1, header.subchannel, Memory::Read32(current_addr),
125 header.arg_count - i - 1);
126 current_addr += sizeof(u32);
127 }
128 break;
129 }
130 case SubmissionMode::Inline: {
131 // The register value is stored in the bits 16-28 as an immediate
132 WriteReg(header.method, header.subchannel, header.inline_data, 0);
133 break;
134 }
135 default:
136 UNIMPLEMENTED();
137 }
138 }
139 }
140}
141
142} // namespace Tegra
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index d3b3ed1f0..25bb7604a 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -42,6 +42,7 @@ public:
42 static constexpr std::size_t NumVertexArrays = 32; 42 static constexpr std::size_t NumVertexArrays = 32;
43 static constexpr std::size_t NumVertexAttributes = 32; 43 static constexpr std::size_t NumVertexAttributes = 32;
44 static constexpr std::size_t NumTextureSamplers = 32; 44 static constexpr std::size_t NumTextureSamplers = 32;
45 static constexpr std::size_t NumClipDistances = 8;
45 static constexpr std::size_t MaxShaderProgram = 6; 46 static constexpr std::size_t MaxShaderProgram = 6;
46 static constexpr std::size_t MaxShaderStage = 5; 47 static constexpr std::size_t MaxShaderStage = 5;
47 // Maximum number of const buffers per shader stage. 48 // Maximum number of const buffers per shader stage.
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index b9faaf8e0..5ea094e64 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -1049,6 +1049,7 @@ union Instruction {
1049 BitField<49, 1, u64> nodep_flag; 1049 BitField<49, 1, u64> nodep_flag;
1050 BitField<50, 3, u64> component_mask_selector; 1050 BitField<50, 3, u64> component_mask_selector;
1051 BitField<53, 4, u64> texture_info; 1051 BitField<53, 4, u64> texture_info;
1052 BitField<60, 1, u64> fp32_flag;
1052 1053
1053 TextureType GetTextureType() const { 1054 TextureType GetTextureType() const {
1054 // The TEXS instruction has a weird encoding for the texture type. 1055 // The TEXS instruction has a weird encoding for the texture type.
@@ -1549,7 +1550,7 @@ private:
1549 INST("1110111011011---", Id::STG, Type::Memory, "STG"), 1550 INST("1110111011011---", Id::STG, Type::Memory, "STG"),
1550 INST("110000----111---", Id::TEX, Type::Memory, "TEX"), 1551 INST("110000----111---", Id::TEX, Type::Memory, "TEX"),
1551 INST("1101111101001---", Id::TXQ, Type::Memory, "TXQ"), 1552 INST("1101111101001---", Id::TXQ, Type::Memory, "TXQ"),
1552 INST("1101100---------", Id::TEXS, Type::Memory, "TEXS"), 1553 INST("1101-00---------", Id::TEXS, Type::Memory, "TEXS"),
1553 INST("1101101---------", Id::TLDS, Type::Memory, "TLDS"), 1554 INST("1101101---------", Id::TLDS, Type::Memory, "TLDS"),
1554 INST("110010----111---", Id::TLD4, Type::Memory, "TLD4"), 1555 INST("110010----111---", Id::TLD4, Type::Memory, "TLD4"),
1555 INST("1101111100------", Id::TLD4S, Type::Memory, "TLD4S"), 1556 INST("1101111100------", Id::TLD4S, Type::Memory, "TLD4S"),
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index 6c81dee64..88c45a423 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -128,10 +128,8 @@ enum class BufferMethods {
128}; 128};
129 129
130void GPU::CallMethod(const MethodCall& method_call) { 130void GPU::CallMethod(const MethodCall& method_call) {
131 LOG_TRACE(HW_GPU, 131 LOG_TRACE(HW_GPU, "Processing method {:08X} on subchannel {}", method_call.method,
132 "Processing method {:08X} on subchannel {} value " 132 method_call.subchannel);
133 "{:08X} remaining params {}",
134 MethCall.method, MethCall.subchannel, value, remaining_params);
135 133
136 ASSERT(method_call.subchannel < bound_engines.size()); 134 ASSERT(method_call.subchannel < bound_engines.size());
137 135
@@ -143,6 +141,12 @@ void GPU::CallMethod(const MethodCall& method_call) {
143 return; 141 return;
144 } 142 }
145 143
144 if (method_call.method < static_cast<u32>(BufferMethods::CountBufferMethods)) {
145 // TODO(Subv): Research and implement these methods.
146 LOG_ERROR(HW_GPU, "Special buffer methods other than Bind are not implemented");
147 return;
148 }
149
146 const EngineID engine = bound_engines[method_call.subchannel]; 150 const EngineID engine = bound_engines[method_call.subchannel];
147 151
148 switch (engine) { 152 switch (engine) {
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 7b836cc94..2b29fc45f 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -108,19 +108,6 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo
108 state.texture_units[i].sampler = texture_samplers[i].sampler.handle; 108 state.texture_units[i].sampler = texture_samplers[i].sampler.handle;
109 } 109 }
110 110
111 GLint ext_num;
112 glGetIntegerv(GL_NUM_EXTENSIONS, &ext_num);
113 for (GLint i = 0; i < ext_num; i++) {
114 const std::string_view extension{
115 reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, i))};
116
117 if (extension == "GL_ARB_direct_state_access") {
118 has_ARB_direct_state_access = true;
119 } else if (extension == "GL_ARB_multi_bind") {
120 has_ARB_multi_bind = true;
121 }
122 }
123
124 OpenGLState::ApplyDefaultState(); 111 OpenGLState::ApplyDefaultState();
125 112
126 shader_program_manager = std::make_unique<GLShader::ProgramManager>(); 113 shader_program_manager = std::make_unique<GLShader::ProgramManager>();
@@ -312,6 +299,7 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
312 // shaders. The constbuffer bindpoint starts after the shader stage configuration bind points. 299 // shaders. The constbuffer bindpoint starts after the shader stage configuration bind points.
313 u32 current_constbuffer_bindpoint = Tegra::Engines::Maxwell3D::Regs::MaxShaderStage; 300 u32 current_constbuffer_bindpoint = Tegra::Engines::Maxwell3D::Regs::MaxShaderStage;
314 u32 current_texture_bindpoint = 0; 301 u32 current_texture_bindpoint = 0;
302 std::array<bool, Maxwell::NumClipDistances> clip_distances{};
315 303
316 for (std::size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) { 304 for (std::size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) {
317 const auto& shader_config = gpu.regs.shader_config[index]; 305 const auto& shader_config = gpu.regs.shader_config[index];
@@ -372,12 +360,22 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
372 current_texture_bindpoint = SetupTextures(static_cast<Maxwell::ShaderStage>(stage), shader, 360 current_texture_bindpoint = SetupTextures(static_cast<Maxwell::ShaderStage>(stage), shader,
373 primitive_mode, current_texture_bindpoint); 361 primitive_mode, current_texture_bindpoint);
374 362
363 // Workaround for Intel drivers.
364 // When a clip distance is enabled but not set in the shader it crops parts of the screen
365 // (sometimes it's half the screen, sometimes three quarters). To avoid this, enable the
366 // clip distances only when it's written by a shader stage.
367 for (std::size_t i = 0; i < Maxwell::NumClipDistances; ++i) {
368 clip_distances[i] |= shader->GetShaderEntries().clip_distances[i];
369 }
370
375 // When VertexA is enabled, we have dual vertex shaders 371 // When VertexA is enabled, we have dual vertex shaders
376 if (program == Maxwell::ShaderProgram::VertexA) { 372 if (program == Maxwell::ShaderProgram::VertexA) {
377 // VertexB was combined with VertexA, so we skip the VertexB iteration 373 // VertexB was combined with VertexA, so we skip the VertexB iteration
378 index++; 374 index++;
379 } 375 }
380 } 376 }
377
378 SyncClipEnabled(clip_distances);
381} 379}
382 380
383void RasterizerOpenGL::SetupCachedFramebuffer(const FramebufferCacheKey& fbkey, 381void RasterizerOpenGL::SetupCachedFramebuffer(const FramebufferCacheKey& fbkey,
@@ -498,7 +496,7 @@ void RasterizerOpenGL::ConfigureFramebuffers(OpenGLState& current_state, bool us
498 // TODO(bunnei): Figure out how the below register works. According to envytools, this should be 496 // TODO(bunnei): Figure out how the below register works. According to envytools, this should be
499 // used to enable multiple render targets. However, it is left unset on all games that I have 497 // used to enable multiple render targets. However, it is left unset on all games that I have
500 // tested. 498 // tested.
501 ASSERT_MSG(regs.rt_separate_frag_data == 0, "Unimplemented"); 499 UNIMPLEMENTED_IF(regs.rt_separate_frag_data != 0);
502 500
503 // Bind the framebuffer surfaces 501 // Bind the framebuffer surfaces
504 current_state.framebuffer_srgb.enabled = regs.framebuffer_srgb != 0; 502 current_state.framebuffer_srgb.enabled = regs.framebuffer_srgb != 0;
@@ -680,7 +678,6 @@ void RasterizerOpenGL::DrawArrays() {
680 SyncCullMode(); 678 SyncCullMode();
681 SyncPrimitiveRestart(); 679 SyncPrimitiveRestart();
682 SyncScissorTest(state); 680 SyncScissorTest(state);
683 SyncClipEnabled();
684 // Alpha Testing is synced on shaders. 681 // Alpha Testing is synced on shaders.
685 SyncTransformFeedback(); 682 SyncTransformFeedback();
686 SyncPointState(); 683 SyncPointState();
@@ -1057,20 +1054,23 @@ void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) {
1057 state.depth_clamp.near_plane = regs.view_volume_clip_control.depth_clamp_near != 0; 1054 state.depth_clamp.near_plane = regs.view_volume_clip_control.depth_clamp_near != 0;
1058} 1055}
1059 1056
1060void RasterizerOpenGL::SyncClipEnabled() { 1057void RasterizerOpenGL::SyncClipEnabled(
1058 const std::array<bool, Maxwell::Regs::NumClipDistances>& clip_mask) {
1059
1061 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; 1060 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
1062 state.clip_distance[0] = regs.clip_distance_enabled.c0 != 0; 1061 const std::array<bool, Maxwell::Regs::NumClipDistances> reg_state{
1063 state.clip_distance[1] = regs.clip_distance_enabled.c1 != 0; 1062 regs.clip_distance_enabled.c0 != 0, regs.clip_distance_enabled.c1 != 0,
1064 state.clip_distance[2] = regs.clip_distance_enabled.c2 != 0; 1063 regs.clip_distance_enabled.c2 != 0, regs.clip_distance_enabled.c3 != 0,
1065 state.clip_distance[3] = regs.clip_distance_enabled.c3 != 0; 1064 regs.clip_distance_enabled.c4 != 0, regs.clip_distance_enabled.c5 != 0,
1066 state.clip_distance[4] = regs.clip_distance_enabled.c4 != 0; 1065 regs.clip_distance_enabled.c6 != 0, regs.clip_distance_enabled.c7 != 0};
1067 state.clip_distance[5] = regs.clip_distance_enabled.c5 != 0; 1066
1068 state.clip_distance[6] = regs.clip_distance_enabled.c6 != 0; 1067 for (std::size_t i = 0; i < Maxwell::Regs::NumClipDistances; ++i) {
1069 state.clip_distance[7] = regs.clip_distance_enabled.c7 != 0; 1068 state.clip_distance[i] = reg_state[i] && clip_mask[i];
1069 }
1070} 1070}
1071 1071
1072void RasterizerOpenGL::SyncClipCoef() { 1072void RasterizerOpenGL::SyncClipCoef() {
1073 UNREACHABLE(); 1073 UNIMPLEMENTED();
1074} 1074}
1075 1075
1076void RasterizerOpenGL::SyncCullMode() { 1076void RasterizerOpenGL::SyncCullMode() {
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 959e8df63..8a891ffc7 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -61,20 +61,6 @@ public:
61 bool AccelerateDrawBatch(bool is_indexed) override; 61 bool AccelerateDrawBatch(bool is_indexed) override;
62 void UpdatePagesCachedCount(Tegra::GPUVAddr addr, u64 size, int delta) override; 62 void UpdatePagesCachedCount(Tegra::GPUVAddr addr, u64 size, int delta) override;
63 63
64 /// OpenGL shader generated for a given Maxwell register state
65 struct MaxwellShader {
66 /// OpenGL shader resource
67 OGLProgram shader;
68 };
69
70 struct VertexShader {
71 OGLShader shader;
72 };
73
74 struct FragmentShader {
75 OGLShader shader;
76 };
77
78 /// Maximum supported size that a constbuffer can have in bytes. 64 /// Maximum supported size that a constbuffer can have in bytes.
79 static constexpr std::size_t MaxConstbufferSize = 0x10000; 65 static constexpr std::size_t MaxConstbufferSize = 0x10000;
80 static_assert(MaxConstbufferSize % sizeof(GLvec4) == 0, 66 static_assert(MaxConstbufferSize % sizeof(GLvec4) == 0,
@@ -143,7 +129,8 @@ private:
143 void SyncViewport(OpenGLState& current_state); 129 void SyncViewport(OpenGLState& current_state);
144 130
145 /// Syncs the clip enabled status to match the guest state 131 /// Syncs the clip enabled status to match the guest state
146 void SyncClipEnabled(); 132 void SyncClipEnabled(
133 const std::array<bool, Tegra::Engines::Maxwell3D::Regs::NumClipDistances>& clip_mask);
147 134
148 /// Syncs the clip coefficients to match the guest state 135 /// Syncs the clip coefficients to match the guest state
149 void SyncClipCoef(); 136 void SyncClipCoef();
@@ -194,9 +181,6 @@ private:
194 /// but are needed for correct emulation 181 /// but are needed for correct emulation
195 void CheckExtensions(); 182 void CheckExtensions();
196 183
197 bool has_ARB_direct_state_access = false;
198 bool has_ARB_multi_bind = false;
199
200 OpenGLState state; 184 OpenGLState state;
201 185
202 RasterizerCacheOpenGL res_cache; 186 RasterizerCacheOpenGL res_cache;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index dde2f468d..5f4cdd119 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -405,138 +405,6 @@ void SwizzleFunc(const MortonSwizzleMode& mode, const SurfaceParams& params,
405 } 405 }
406} 406}
407 407
408MICROPROFILE_DEFINE(OpenGL_BlitSurface, "OpenGL", "BlitSurface", MP_RGB(128, 192, 64));
409static bool BlitSurface(const Surface& src_surface, const Surface& dst_surface,
410 GLuint read_fb_handle, GLuint draw_fb_handle, GLenum src_attachment = 0,
411 GLenum dst_attachment = 0, std::size_t cubemap_face = 0) {
412 MICROPROFILE_SCOPE(OpenGL_BlitSurface);
413
414 const auto& src_params{src_surface->GetSurfaceParams()};
415 const auto& dst_params{dst_surface->GetSurfaceParams()};
416
417 OpenGLState prev_state{OpenGLState::GetCurState()};
418 SCOPE_EXIT({ prev_state.Apply(); });
419
420 OpenGLState state;
421 state.draw.read_framebuffer = read_fb_handle;
422 state.draw.draw_framebuffer = draw_fb_handle;
423 // Set sRGB enabled if the destination surfaces need it
424 state.framebuffer_srgb.enabled = dst_params.srgb_conversion;
425 state.ApplyFramebufferState();
426
427 u32 buffers{};
428
429 if (src_params.type == SurfaceType::ColorTexture) {
430 switch (src_params.target) {
431 case SurfaceTarget::Texture2D:
432 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
433 GL_TEXTURE_2D, src_surface->Texture().handle, 0);
434 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
435 0, 0);
436 break;
437 case SurfaceTarget::TextureCubemap:
438 glFramebufferTexture2D(
439 GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
440 static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face),
441 src_surface->Texture().handle, 0);
442 glFramebufferTexture2D(
443 GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
444 static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face), 0, 0);
445 break;
446 case SurfaceTarget::Texture2DArray:
447 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
448 src_surface->Texture().handle, 0, 0);
449 glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, 0, 0, 0);
450 break;
451 case SurfaceTarget::Texture3D:
452 glFramebufferTexture3D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
453 SurfaceTargetToGL(src_params.target),
454 src_surface->Texture().handle, 0, 0);
455 glFramebufferTexture3D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
456 SurfaceTargetToGL(src_params.target), 0, 0, 0);
457 break;
458 default:
459 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
460 GL_TEXTURE_2D, src_surface->Texture().handle, 0);
461 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
462 0, 0);
463 break;
464 }
465
466 switch (dst_params.target) {
467 case SurfaceTarget::Texture2D:
468 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
469 GL_TEXTURE_2D, dst_surface->Texture().handle, 0);
470 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
471 0, 0);
472 break;
473 case SurfaceTarget::TextureCubemap:
474 glFramebufferTexture2D(
475 GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
476 static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face),
477 dst_surface->Texture().handle, 0);
478 glFramebufferTexture2D(
479 GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
480 static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face), 0, 0);
481 break;
482 case SurfaceTarget::Texture2DArray:
483 glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
484 dst_surface->Texture().handle, 0, 0);
485 glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, 0, 0, 0);
486 break;
487
488 case SurfaceTarget::Texture3D:
489 glFramebufferTexture3D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
490 SurfaceTargetToGL(dst_params.target),
491 dst_surface->Texture().handle, 0, 0);
492 glFramebufferTexture3D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
493 SurfaceTargetToGL(dst_params.target), 0, 0, 0);
494 break;
495 default:
496 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
497 GL_TEXTURE_2D, dst_surface->Texture().handle, 0);
498 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
499 0, 0);
500 break;
501 }
502
503 buffers = GL_COLOR_BUFFER_BIT;
504 } else if (src_params.type == SurfaceType::Depth) {
505 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
506 GL_TEXTURE_2D, 0, 0);
507 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
508 src_surface->Texture().handle, 0);
509 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
510
511 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
512 GL_TEXTURE_2D, 0, 0);
513 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
514 dst_surface->Texture().handle, 0);
515 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
516
517 buffers = GL_DEPTH_BUFFER_BIT;
518 } else if (src_params.type == SurfaceType::DepthStencil) {
519 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
520 GL_TEXTURE_2D, 0, 0);
521 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
522 src_surface->Texture().handle, 0);
523
524 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
525 GL_TEXTURE_2D, 0, 0);
526 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
527 dst_surface->Texture().handle, 0);
528
529 buffers = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
530 }
531
532 const auto& rect{src_params.GetRect()};
533 glBlitFramebuffer(rect.left, rect.bottom, rect.right, rect.top, rect.left, rect.bottom,
534 rect.right, rect.top, buffers,
535 buffers == GL_COLOR_BUFFER_BIT ? GL_LINEAR : GL_NEAREST);
536
537 return true;
538}
539
540static void FastCopySurface(const Surface& src_surface, const Surface& dst_surface) { 408static void FastCopySurface(const Surface& src_surface, const Surface& dst_surface) {
541 const auto& src_params{src_surface->GetSurfaceParams()}; 409 const auto& src_params{src_surface->GetSurfaceParams()};
542 const auto& dst_params{dst_surface->GetSurfaceParams()}; 410 const auto& dst_params{dst_surface->GetSurfaceParams()};
@@ -841,9 +709,10 @@ void CachedSurface::LoadGLBuffer() {
841 const auto texture_src_data_end{texture_src_data + params.size_in_bytes_gl}; 709 const auto texture_src_data_end{texture_src_data + params.size_in_bytes_gl};
842 gl_buffer[0].assign(texture_src_data, texture_src_data_end); 710 gl_buffer[0].assign(texture_src_data, texture_src_data_end);
843 } 711 }
844 for (u32 i = 0; i < params.max_mip_level; i++) 712 for (u32 i = 0; i < params.max_mip_level; i++) {
845 ConvertFormatAsNeeded_LoadGLBuffer(gl_buffer[i], params.pixel_format, params.MipWidth(i), 713 ConvertFormatAsNeeded_LoadGLBuffer(gl_buffer[i], params.pixel_format, params.MipWidth(i),
846 params.MipHeight(i), params.MipDepth(i)); 714 params.MipHeight(i), params.MipDepth(i));
715 }
847} 716}
848 717
849MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64)); 718MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64));
@@ -1163,7 +1032,10 @@ void RasterizerCacheOpenGL::AccurateCopySurface(const Surface& src_surface,
1163 const Surface& dst_surface) { 1032 const Surface& dst_surface) {
1164 const auto& src_params{src_surface->GetSurfaceParams()}; 1033 const auto& src_params{src_surface->GetSurfaceParams()};
1165 const auto& dst_params{dst_surface->GetSurfaceParams()}; 1034 const auto& dst_params{dst_surface->GetSurfaceParams()};
1166 FlushRegion(src_params.addr, dst_params.MemorySize()); 1035
1036 // Flush enough memory for both the source and destination surface
1037 FlushRegion(src_params.addr, std::max(src_params.MemorySize(), dst_params.MemorySize()));
1038
1167 LoadSurface(dst_surface); 1039 LoadSurface(dst_surface);
1168} 1040}
1169 1041
@@ -1189,20 +1061,9 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& old_surface,
1189 return new_surface; 1061 return new_surface;
1190 } 1062 }
1191 1063
1192 // If the format is the same, just do a framebuffer blit. This is significantly faster than
1193 // using PBOs. The is also likely less accurate, as textures will be converted rather than
1194 // reinterpreted. When use_accurate_gpu_emulation setting is enabled, perform a more accurate
1195 // surface copy, where pixels are reinterpreted as a new format (without conversion). This
1196 // code path uses OpenGL PBOs and is quite slow.
1197 const bool is_blit{old_params.pixel_format == new_params.pixel_format};
1198
1199 switch (new_params.target) { 1064 switch (new_params.target) {
1200 case SurfaceTarget::Texture2D: 1065 case SurfaceTarget::Texture2D:
1201 if (is_blit) { 1066 CopySurface(old_surface, new_surface, copy_pbo.handle);
1202 BlitSurface(old_surface, new_surface, read_framebuffer.handle, draw_framebuffer.handle);
1203 } else {
1204 CopySurface(old_surface, new_surface, copy_pbo.handle);
1205 }
1206 break; 1067 break;
1207 case SurfaceTarget::Texture3D: 1068 case SurfaceTarget::Texture3D:
1208 AccurateCopySurface(old_surface, new_surface); 1069 AccurateCopySurface(old_surface, new_surface);
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 0c4524d5c..4fc09cac6 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -50,6 +50,14 @@ public:
50 using std::runtime_error::runtime_error; 50 using std::runtime_error::runtime_error;
51}; 51};
52 52
53/// Generates code to use for a swizzle operation.
54static std::string GetSwizzle(u64 elem) {
55 ASSERT(elem <= 3);
56 std::string swizzle = ".";
57 swizzle += "xyzw"[elem];
58 return swizzle;
59}
60
53/// Translate topology 61/// Translate topology
54static std::string GetTopologyName(Tegra::Shader::OutputTopology topology) { 62static std::string GetTopologyName(Tegra::Shader::OutputTopology topology) {
55 switch (topology) { 63 switch (topology) {
@@ -201,14 +209,53 @@ private:
201 } 209 }
202}; 210};
203 211
212template <typename T>
213class ShaderScopedScope {
214public:
215 explicit ShaderScopedScope(T& writer, std::string_view begin_expr, std::string end_expr)
216 : writer(writer), end_expr(std::move(end_expr)) {
217
218 if (begin_expr.empty()) {
219 writer.AddLine('{');
220 } else {
221 writer.AddExpression(begin_expr);
222 writer.AddLine(" {");
223 }
224 ++writer.scope;
225 }
226
227 ShaderScopedScope(const ShaderScopedScope&) = delete;
228
229 ~ShaderScopedScope() {
230 --writer.scope;
231 if (end_expr.empty()) {
232 writer.AddLine('}');
233 } else {
234 writer.AddExpression("} ");
235 writer.AddExpression(end_expr);
236 writer.AddLine(';');
237 }
238 }
239
240 ShaderScopedScope& operator=(const ShaderScopedScope&) = delete;
241
242private:
243 T& writer;
244 std::string end_expr;
245};
246
204class ShaderWriter { 247class ShaderWriter {
205public: 248public:
206 void AddLine(std::string_view text) { 249 void AddExpression(std::string_view text) {
207 DEBUG_ASSERT(scope >= 0); 250 DEBUG_ASSERT(scope >= 0);
208 if (!text.empty()) { 251 if (!text.empty()) {
209 AppendIndentation(); 252 AppendIndentation();
210 } 253 }
211 shader_source += text; 254 shader_source += text;
255 }
256
257 void AddLine(std::string_view text) {
258 AddExpression(text);
212 AddNewLine(); 259 AddNewLine();
213 } 260 }
214 261
@@ -228,6 +275,11 @@ public:
228 return std::move(shader_source); 275 return std::move(shader_source);
229 } 276 }
230 277
278 ShaderScopedScope<ShaderWriter> Scope(std::string_view begin_expr = {},
279 std::string end_expr = {}) {
280 return ShaderScopedScope(*this, begin_expr, end_expr);
281 }
282
231 int scope = 0; 283 int scope = 0;
232 284
233private: 285private:
@@ -311,7 +363,7 @@ public:
311 // Default - do nothing 363 // Default - do nothing
312 return value; 364 return value;
313 default: 365 default:
314 UNIMPLEMENTED_MSG("Unimplemented conversion size: {}", static_cast<u32>(size)); 366 UNREACHABLE_MSG("Unimplemented conversion size: {}", static_cast<u32>(size));
315 } 367 }
316 } 368 }
317 369
@@ -525,6 +577,7 @@ public:
525 ((header.vtg.clip_distances >> index) & 1) == 0, 577 ((header.vtg.clip_distances >> index) & 1) == 0,
526 "Shader is setting gl_ClipDistance{} without enabling it in the header", index); 578 "Shader is setting gl_ClipDistance{} without enabling it in the header", index);
527 579
580 clip_distances[index] = true;
528 fixed_pipeline_output_attributes_used.insert(attribute); 581 fixed_pipeline_output_attributes_used.insert(attribute);
529 shader.AddLine(dest + '[' + std::to_string(index) + "] = " + src + ';'); 582 shader.AddLine(dest + '[' + std::to_string(index) + "] = " + src + ';');
530 break; 583 break;
@@ -602,6 +655,11 @@ public:
602 return used_samplers; 655 return used_samplers;
603 } 656 }
604 657
658 /// Returns an array of the used clip distances.
659 const std::array<bool, Maxwell::NumClipDistances>& GetClipDistances() const {
660 return clip_distances;
661 }
662
605 /// Returns the GLSL sampler used for the input shader sampler, and creates a new one if 663 /// Returns the GLSL sampler used for the input shader sampler, and creates a new one if
606 /// necessary. 664 /// necessary.
607 std::string AccessSampler(const Sampler& sampler, Tegra::Shader::TextureType type, 665 std::string AccessSampler(const Sampler& sampler, Tegra::Shader::TextureType type,
@@ -810,14 +868,12 @@ private:
810 } 868 }
811 869
812 if (precise && stage != Maxwell3D::Regs::ShaderStage::Fragment) { 870 if (precise && stage != Maxwell3D::Regs::ShaderStage::Fragment) {
813 shader.AddLine('{'); 871 const auto scope = shader.Scope();
814 ++shader.scope; 872
815 // This avoids optimizations of constant propagation and keeps the code as the original 873 // This avoids optimizations of constant propagation and keeps the code as the original
816 // Sadly using the precise keyword causes "linking" errors on fragment shaders. 874 // Sadly using the precise keyword causes "linking" errors on fragment shaders.
817 shader.AddLine("precise float tmp = " + src + ';'); 875 shader.AddLine("precise float tmp = " + src + ';');
818 shader.AddLine(dest + " = tmp;"); 876 shader.AddLine(dest + " = tmp;");
819 --shader.scope;
820 shader.AddLine('}');
821 } else { 877 } else {
822 shader.AddLine(dest + " = " + src + ';'); 878 shader.AddLine(dest + " = " + src + ';');
823 } 879 }
@@ -956,14 +1012,6 @@ private:
956 } 1012 }
957 } 1013 }
958 1014
959 /// Generates code to use for a swizzle operation.
960 static std::string GetSwizzle(u64 elem) {
961 ASSERT(elem <= 3);
962 std::string swizzle = ".";
963 swizzle += "xyzw"[elem];
964 return swizzle;
965 }
966
967 ShaderWriter& shader; 1015 ShaderWriter& shader;
968 ShaderWriter& declarations; 1016 ShaderWriter& declarations;
969 std::vector<GLSLRegister> regs; 1017 std::vector<GLSLRegister> regs;
@@ -975,6 +1023,7 @@ private:
975 const std::string& suffix; 1023 const std::string& suffix;
976 const Tegra::Shader::Header& header; 1024 const Tegra::Shader::Header& header;
977 std::unordered_set<Attribute::Index> fixed_pipeline_output_attributes_used; 1025 std::unordered_set<Attribute::Index> fixed_pipeline_output_attributes_used;
1026 std::array<bool, Maxwell::NumClipDistances> clip_distances{};
978 u64 local_memory_size; 1027 u64 local_memory_size;
979}; 1028};
980 1029
@@ -997,7 +1046,8 @@ public:
997 1046
998 /// Returns entries in the shader that are useful for external functions 1047 /// Returns entries in the shader that are useful for external functions
999 ShaderEntries GetEntries() const { 1048 ShaderEntries GetEntries() const {
1000 return {regs.GetConstBuffersDeclarations(), regs.GetSamplers(), shader_length}; 1049 return {regs.GetConstBuffersDeclarations(), regs.GetSamplers(), regs.GetClipDistances(),
1050 shader_length};
1001 } 1051 }
1002 1052
1003private: 1053private:
@@ -1293,15 +1343,7 @@ private:
1293 regs.SetRegisterToInteger(dest, true, 0, result, 1, 1); 1343 regs.SetRegisterToInteger(dest, true, 0, result, 1, 1);
1294 } 1344 }
1295 1345
1296 void WriteTexsInstruction(const Instruction& instr, const std::string& coord, 1346 void WriteTexsInstructionFloat(const Instruction& instr, const std::string& texture) {
1297 const std::string& texture) {
1298 // Add an extra scope and declare the texture coords inside to prevent
1299 // overwriting them in case they are used as outputs of the texs instruction.
1300 shader.AddLine('{');
1301 ++shader.scope;
1302 shader.AddLine(coord);
1303 shader.AddLine("vec4 texture_tmp = " + texture + ';');
1304
1305 // TEXS has two destination registers and a swizzle. The first two elements in the swizzle 1347 // TEXS has two destination registers and a swizzle. The first two elements in the swizzle
1306 // go into gpr0+0 and gpr0+1, and the rest goes into gpr28+0 and gpr28+1 1348 // go into gpr0+0 and gpr0+1, and the rest goes into gpr28+0 and gpr28+1
1307 1349
@@ -1313,19 +1355,49 @@ private:
1313 1355
1314 if (written_components < 2) { 1356 if (written_components < 2) {
1315 // Write the first two swizzle components to gpr0 and gpr0+1 1357 // Write the first two swizzle components to gpr0 and gpr0+1
1316 regs.SetRegisterToFloat(instr.gpr0, component, "texture_tmp", 1, 4, false, 1358 regs.SetRegisterToFloat(instr.gpr0, component, texture, 1, 4, false,
1317 written_components % 2); 1359 written_components % 2);
1318 } else { 1360 } else {
1319 ASSERT(instr.texs.HasTwoDestinations()); 1361 ASSERT(instr.texs.HasTwoDestinations());
1320 // Write the rest of the swizzle components to gpr28 and gpr28+1 1362 // Write the rest of the swizzle components to gpr28 and gpr28+1
1321 regs.SetRegisterToFloat(instr.gpr28, component, "texture_tmp", 1, 4, false, 1363 regs.SetRegisterToFloat(instr.gpr28, component, texture, 1, 4, false,
1322 written_components % 2); 1364 written_components % 2);
1323 } 1365 }
1324 1366
1325 ++written_components; 1367 ++written_components;
1326 } 1368 }
1327 --shader.scope; 1369 }
1328 shader.AddLine('}'); 1370
1371 void WriteTexsInstructionHalfFloat(const Instruction& instr, const std::string& texture) {
1372 // TEXS.F16 destionation registers are packed in two registers in pairs (just like any half
1373 // float instruction).
1374
1375 std::array<std::string, 4> components;
1376 u32 written_components = 0;
1377
1378 for (u32 component = 0; component < 4; ++component) {
1379 if (!instr.texs.IsComponentEnabled(component))
1380 continue;
1381 components[written_components++] = texture + GetSwizzle(component);
1382 }
1383 if (written_components == 0)
1384 return;
1385
1386 const auto BuildComponent = [&](std::string low, std::string high, bool high_enabled) {
1387 return "vec2(" + low + ", " + (high_enabled ? high : "0") + ')';
1388 };
1389
1390 regs.SetRegisterToHalfFloat(
1391 instr.gpr0, 0, BuildComponent(components[0], components[1], written_components > 1),
1392 Tegra::Shader::HalfMerge::H0_H1, 1, 1);
1393
1394 if (written_components > 2) {
1395 ASSERT(instr.texs.HasTwoDestinations());
1396 regs.SetRegisterToHalfFloat(
1397 instr.gpr28, 0,
1398 BuildComponent(components[2], components[3], written_components > 3),
1399 Tegra::Shader::HalfMerge::H0_H1, 1, 1);
1400 }
1329 } 1401 }
1330 1402
1331 static u32 TextureCoordinates(Tegra::Shader::TextureType texture_type) { 1403 static u32 TextureCoordinates(Tegra::Shader::TextureType texture_type) {
@@ -1348,12 +1420,10 @@ private:
1348 * top. 1420 * top.
1349 */ 1421 */
1350 void EmitPushToFlowStack(u32 target) { 1422 void EmitPushToFlowStack(u32 target) {
1351 shader.AddLine('{'); 1423 const auto scope = shader.Scope();
1352 ++shader.scope; 1424
1353 shader.AddLine("flow_stack[flow_stack_top] = " + std::to_string(target) + "u;"); 1425 shader.AddLine("flow_stack[flow_stack_top] = " + std::to_string(target) + "u;");
1354 shader.AddLine("flow_stack_top++;"); 1426 shader.AddLine("flow_stack_top++;");
1355 --shader.scope;
1356 shader.AddLine('}');
1357 } 1427 }
1358 1428
1359 /* 1429 /*
@@ -1361,13 +1431,11 @@ private:
1361 * popped address and decrementing the stack top. 1431 * popped address and decrementing the stack top.
1362 */ 1432 */
1363 void EmitPopFromFlowStack() { 1433 void EmitPopFromFlowStack() {
1364 shader.AddLine('{'); 1434 const auto scope = shader.Scope();
1365 ++shader.scope; 1435
1366 shader.AddLine("flow_stack_top--;"); 1436 shader.AddLine("flow_stack_top--;");
1367 shader.AddLine("jmp_to = flow_stack[flow_stack_top];"); 1437 shader.AddLine("jmp_to = flow_stack[flow_stack_top];");
1368 shader.AddLine("break;"); 1438 shader.AddLine("break;");
1369 --shader.scope;
1370 shader.AddLine('}');
1371 } 1439 }
1372 1440
1373 /// Writes the output values from a fragment shader to the corresponding GLSL output variables. 1441 /// Writes the output values from a fragment shader to the corresponding GLSL output variables.
@@ -1479,6 +1547,161 @@ private:
1479 } 1547 }
1480 } 1548 }
1481 1549
1550 std::pair<size_t, std::string> ValidateAndGetCoordinateElement(
1551 const Tegra::Shader::TextureType texture_type, const bool depth_compare,
1552 const bool is_array, const bool lod_bias_enabled, size_t max_coords, size_t max_inputs) {
1553 const size_t coord_count = TextureCoordinates(texture_type);
1554
1555 size_t total_coord_count = coord_count + (is_array ? 1 : 0) + (depth_compare ? 1 : 0);
1556 const size_t total_reg_count = total_coord_count + (lod_bias_enabled ? 1 : 0);
1557 if (total_coord_count > max_coords || total_reg_count > max_inputs) {
1558 UNIMPLEMENTED_MSG("Unsupported Texture operation");
1559 total_coord_count = std::min(total_coord_count, max_coords);
1560 }
1561 // 1D.DC opengl is using a vec3 but 2nd component is ignored later.
1562 total_coord_count +=
1563 (depth_compare && !is_array && texture_type == Tegra::Shader::TextureType::Texture1D)
1564 ? 1
1565 : 0;
1566
1567 constexpr std::array<const char*, 5> coord_container{
1568 {"", "float coord = (", "vec2 coord = vec2(", "vec3 coord = vec3(",
1569 "vec4 coord = vec4("}};
1570
1571 return std::pair<size_t, std::string>(coord_count, coord_container[total_coord_count]);
1572 }
1573
1574 std::string GetTextureCode(const Tegra::Shader::Instruction& instr,
1575 const Tegra::Shader::TextureType texture_type,
1576 const Tegra::Shader::TextureProcessMode process_mode,
1577 const bool depth_compare, const bool is_array,
1578 const size_t bias_offset) {
1579
1580 if ((texture_type == Tegra::Shader::TextureType::Texture3D &&
1581 (is_array || depth_compare)) ||
1582 (texture_type == Tegra::Shader::TextureType::TextureCube && is_array &&
1583 depth_compare)) {
1584 UNIMPLEMENTED_MSG("This method is not supported.");
1585 }
1586
1587 const std::string sampler =
1588 GetSampler(instr.sampler, texture_type, is_array, depth_compare);
1589
1590 const bool lod_needed = process_mode == Tegra::Shader::TextureProcessMode::LZ ||
1591 process_mode == Tegra::Shader::TextureProcessMode::LL ||
1592 process_mode == Tegra::Shader::TextureProcessMode::LLA;
1593
1594 const bool gl_lod_supported = !(
1595 (texture_type == Tegra::Shader::TextureType::Texture2D && is_array && depth_compare) ||
1596 (texture_type == Tegra::Shader::TextureType::TextureCube && !is_array &&
1597 depth_compare));
1598
1599 const std::string read_method = lod_needed && gl_lod_supported ? "textureLod(" : "texture(";
1600 std::string texture = read_method + sampler + ", coord";
1601
1602 if (process_mode != Tegra::Shader::TextureProcessMode::None) {
1603 if (process_mode == Tegra::Shader::TextureProcessMode::LZ) {
1604 if (gl_lod_supported) {
1605 texture += ", 0";
1606 } else {
1607 // Lod 0 is emulated by a big negative bias
1608 // in scenarios that are not supported by glsl
1609 texture += ", -1000";
1610 }
1611 } else {
1612 // If present, lod or bias are always stored in the register indexed by the
1613 // gpr20
1614 // field with an offset depending on the usage of the other registers
1615 texture += ',' + regs.GetRegisterAsFloat(instr.gpr20.Value() + bias_offset);
1616 }
1617 }
1618 texture += ")";
1619 return texture;
1620 }
1621
1622 std::pair<std::string, std::string> GetTEXCode(
1623 const Instruction& instr, const Tegra::Shader::TextureType texture_type,
1624 const Tegra::Shader::TextureProcessMode process_mode, const bool depth_compare,
1625 const bool is_array) {
1626 const bool lod_bias_enabled = (process_mode != Tegra::Shader::TextureProcessMode::None &&
1627 process_mode != Tegra::Shader::TextureProcessMode::LZ);
1628
1629 const auto [coord_count, coord_dcl] = ValidateAndGetCoordinateElement(
1630 texture_type, depth_compare, is_array, lod_bias_enabled, 4, 5);
1631 // If enabled arrays index is always stored in the gpr8 field
1632 const u64 array_register = instr.gpr8.Value();
1633 // First coordinate index is the gpr8 or gpr8 + 1 when arrays are used
1634 const u64 coord_register = array_register + (is_array ? 1 : 0);
1635
1636 std::string coord = coord_dcl;
1637 for (size_t i = 0; i < coord_count;) {
1638 coord += regs.GetRegisterAsFloat(coord_register + i);
1639 ++i;
1640 if (i != coord_count) {
1641 coord += ',';
1642 }
1643 }
1644 // 1D.DC in opengl the 2nd component is ignored.
1645 if (depth_compare && !is_array && texture_type == Tegra::Shader::TextureType::Texture1D) {
1646 coord += ",0.0";
1647 }
1648 if (depth_compare) {
1649 // Depth is always stored in the register signaled by gpr20
1650 // or in the next register if lod or bias are used
1651 const u64 depth_register = instr.gpr20.Value() + (lod_bias_enabled ? 1 : 0);
1652 coord += ',' + regs.GetRegisterAsFloat(depth_register);
1653 }
1654 if (is_array) {
1655 coord += ',' + regs.GetRegisterAsInteger(array_register);
1656 }
1657 coord += ");";
1658 return std::make_pair(
1659 coord, GetTextureCode(instr, texture_type, process_mode, depth_compare, is_array, 0));
1660 }
1661
1662 std::pair<std::string, std::string> GetTEXSCode(
1663 const Instruction& instr, const Tegra::Shader::TextureType texture_type,
1664 const Tegra::Shader::TextureProcessMode process_mode, const bool depth_compare,
1665 const bool is_array) {
1666 const bool lod_bias_enabled = (process_mode != Tegra::Shader::TextureProcessMode::None &&
1667 process_mode != Tegra::Shader::TextureProcessMode::LZ);
1668
1669 const auto [coord_count, coord_dcl] = ValidateAndGetCoordinateElement(
1670 texture_type, depth_compare, is_array, lod_bias_enabled, 4, 4);
1671 // If enabled arrays index is always stored in the gpr8 field
1672 const u64 array_register = instr.gpr8.Value();
1673 // First coordinate index is stored in gpr8 field or (gpr8 + 1) when arrays are used
1674 const u64 coord_register = array_register + (is_array ? 1 : 0);
1675 const u64 last_coord_register =
1676 (is_array || !(lod_bias_enabled || depth_compare) || (coord_count > 2))
1677 ? static_cast<u64>(instr.gpr20.Value())
1678 : coord_register + 1;
1679
1680 std::string coord = coord_dcl;
1681 for (size_t i = 0; i < coord_count; ++i) {
1682 const bool last = (i == (coord_count - 1)) && (coord_count > 1);
1683 coord += regs.GetRegisterAsFloat(last ? last_coord_register : coord_register + i);
1684 if (!last) {
1685 coord += ',';
1686 }
1687 }
1688
1689 if (depth_compare) {
1690 // Depth is always stored in the register signaled by gpr20
1691 // or in the next register if lod or bias are used
1692 const u64 depth_register = instr.gpr20.Value() + (lod_bias_enabled ? 1 : 0);
1693 coord += ',' + regs.GetRegisterAsFloat(depth_register);
1694 }
1695 if (is_array) {
1696 coord += ',' + regs.GetRegisterAsInteger(array_register);
1697 }
1698 coord += ");";
1699
1700 return std::make_pair(coord,
1701 GetTextureCode(instr, texture_type, process_mode, depth_compare,
1702 is_array, (coord_count > 2 ? 1 : 0)));
1703 }
1704
1482 /** 1705 /**
1483 * Compiles a single instruction from Tegra to GLSL. 1706 * Compiles a single instruction from Tegra to GLSL.
1484 * @param offset the offset of the Tegra shader instruction. 1707 * @param offset the offset of the Tegra shader instruction.
@@ -2279,8 +2502,7 @@ private:
2279 UNIMPLEMENTED_IF(instr.conversion.selector); 2502 UNIMPLEMENTED_IF(instr.conversion.selector);
2280 UNIMPLEMENTED_IF_MSG(instr.generates_cc, 2503 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
2281 "Condition codes generation in I2F is not implemented"); 2504 "Condition codes generation in I2F is not implemented");
2282 2505 std::string op_a;
2283 std::string op_a{};
2284 2506
2285 if (instr.is_b_gpr) { 2507 if (instr.is_b_gpr) {
2286 op_a = 2508 op_a =
@@ -2436,10 +2658,7 @@ private:
2436 case OpCode::Id::LD_C: { 2658 case OpCode::Id::LD_C: {
2437 UNIMPLEMENTED_IF(instr.ld_c.unknown != 0); 2659 UNIMPLEMENTED_IF(instr.ld_c.unknown != 0);
2438 2660
2439 // Add an extra scope and declare the index register inside to prevent 2661 const auto scope = shader.Scope();
2440 // overwriting it in case it is used as an output of the LD instruction.
2441 shader.AddLine("{");
2442 ++shader.scope;
2443 2662
2444 shader.AddLine("uint index = (" + regs.GetRegisterAsInteger(instr.gpr8, 0, false) + 2663 shader.AddLine("uint index = (" + regs.GetRegisterAsInteger(instr.gpr8, 0, false) +
2445 " / 4) & (MAX_CONSTBUFFER_ELEMENTS - 1);"); 2664 " / 4) & (MAX_CONSTBUFFER_ELEMENTS - 1);");
@@ -2465,19 +2684,13 @@ private:
2465 UNIMPLEMENTED_MSG("Unhandled type: {}", 2684 UNIMPLEMENTED_MSG("Unhandled type: {}",
2466 static_cast<unsigned>(instr.ld_c.type.Value())); 2685 static_cast<unsigned>(instr.ld_c.type.Value()));
2467 } 2686 }
2468
2469 --shader.scope;
2470 shader.AddLine("}");
2471 break; 2687 break;
2472 } 2688 }
2473 case OpCode::Id::LD_L: { 2689 case OpCode::Id::LD_L: {
2474 UNIMPLEMENTED_IF_MSG(instr.ld_l.unknown == 1, "LD_L Unhandled mode: {}", 2690 UNIMPLEMENTED_IF_MSG(instr.ld_l.unknown == 1, "LD_L Unhandled mode: {}",
2475 static_cast<unsigned>(instr.ld_l.unknown.Value())); 2691 static_cast<unsigned>(instr.ld_l.unknown.Value()));
2476 2692
2477 // Add an extra scope and declare the index register inside to prevent 2693 const auto scope = shader.Scope();
2478 // overwriting it in case it is used as an output of the LD instruction.
2479 shader.AddLine('{');
2480 ++shader.scope;
2481 2694
2482 std::string op = '(' + regs.GetRegisterAsInteger(instr.gpr8, 0, false) + " + " + 2695 std::string op = '(' + regs.GetRegisterAsInteger(instr.gpr8, 0, false) + " + " +
2483 std::to_string(instr.smem_imm.Value()) + ')'; 2696 std::to_string(instr.smem_imm.Value()) + ')';
@@ -2494,9 +2707,6 @@ private:
2494 UNIMPLEMENTED_MSG("LD_L Unhandled type: {}", 2707 UNIMPLEMENTED_MSG("LD_L Unhandled type: {}",
2495 static_cast<unsigned>(instr.ldst_sl.type.Value())); 2708 static_cast<unsigned>(instr.ldst_sl.type.Value()));
2496 } 2709 }
2497
2498 --shader.scope;
2499 shader.AddLine('}');
2500 break; 2710 break;
2501 } 2711 }
2502 case OpCode::Id::ST_A: { 2712 case OpCode::Id::ST_A: {
@@ -2531,10 +2741,7 @@ private:
2531 UNIMPLEMENTED_IF_MSG(instr.st_l.unknown == 0, "ST_L Unhandled mode: {}", 2741 UNIMPLEMENTED_IF_MSG(instr.st_l.unknown == 0, "ST_L Unhandled mode: {}",
2532 static_cast<unsigned>(instr.st_l.unknown.Value())); 2742 static_cast<unsigned>(instr.st_l.unknown.Value()));
2533 2743
2534 // Add an extra scope and declare the index register inside to prevent 2744 const auto scope = shader.Scope();
2535 // overwriting it in case it is used as an output of the LD instruction.
2536 shader.AddLine('{');
2537 ++shader.scope;
2538 2745
2539 std::string op = '(' + regs.GetRegisterAsInteger(instr.gpr8, 0, false) + " + " + 2746 std::string op = '(' + regs.GetRegisterAsInteger(instr.gpr8, 0, false) + " + " +
2540 std::to_string(instr.smem_imm.Value()) + ')'; 2747 std::to_string(instr.smem_imm.Value()) + ')';
@@ -2549,179 +2756,28 @@ private:
2549 UNIMPLEMENTED_MSG("ST_L Unhandled type: {}", 2756 UNIMPLEMENTED_MSG("ST_L Unhandled type: {}",
2550 static_cast<unsigned>(instr.ldst_sl.type.Value())); 2757 static_cast<unsigned>(instr.ldst_sl.type.Value()));
2551 } 2758 }
2552
2553 --shader.scope;
2554 shader.AddLine('}');
2555 break; 2759 break;
2556 } 2760 }
2557 case OpCode::Id::TEX: { 2761 case OpCode::Id::TEX: {
2558 Tegra::Shader::TextureType texture_type{instr.tex.texture_type}; 2762 Tegra::Shader::TextureType texture_type{instr.tex.texture_type};
2559 std::string coord;
2560 const bool is_array = instr.tex.array != 0; 2763 const bool is_array = instr.tex.array != 0;
2561 2764 const bool depth_compare =
2765 instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC);
2766 const auto process_mode = instr.tex.GetTextureProcessMode();
2562 UNIMPLEMENTED_IF_MSG(instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), 2767 UNIMPLEMENTED_IF_MSG(instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
2563 "NODEP is not implemented"); 2768 "NODEP is not implemented");
2564 UNIMPLEMENTED_IF_MSG(instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI), 2769 UNIMPLEMENTED_IF_MSG(instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI),
2565 "AOFFI is not implemented"); 2770 "AOFFI is not implemented");
2566 2771
2567 const bool depth_compare = 2772 const auto [coord, texture] =
2568 instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC); 2773 GetTEXCode(instr, texture_type, process_mode, depth_compare, is_array);
2569 u32 num_coordinates = TextureCoordinates(texture_type);
2570 u32 start_index = 0;
2571 std::string array_elem;
2572 if (is_array) {
2573 array_elem = regs.GetRegisterAsInteger(instr.gpr8);
2574 start_index = 1;
2575 }
2576 const auto process_mode = instr.tex.GetTextureProcessMode();
2577 u32 start_index_b = 0;
2578 std::string lod_value;
2579 if (process_mode != Tegra::Shader::TextureProcessMode::LZ &&
2580 process_mode != Tegra::Shader::TextureProcessMode::None) {
2581 start_index_b = 1;
2582 lod_value = regs.GetRegisterAsFloat(instr.gpr20);
2583 }
2584
2585 std::string depth_value;
2586 if (depth_compare) {
2587 depth_value = regs.GetRegisterAsFloat(instr.gpr20.Value() + start_index_b);
2588 }
2589 2774
2590 bool depth_compare_extra = false; 2775 const auto scope = shader.Scope();
2591
2592 switch (num_coordinates) {
2593 case 1: {
2594 const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index);
2595 if (is_array) {
2596 if (depth_compare) {
2597 coord = "vec3 coords = vec3(" + x + ", " + depth_value + ", " +
2598 array_elem + ");";
2599 } else {
2600 coord = "vec2 coords = vec2(" + x + ", " + array_elem + ");";
2601 }
2602 } else {
2603 if (depth_compare) {
2604 coord = "vec2 coords = vec2(" + x + ", " + depth_value + ");";
2605 } else {
2606 coord = "float coords = " + x + ';';
2607 }
2608 }
2609 break;
2610 }
2611 case 2: {
2612 const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index);
2613 const std::string y =
2614 regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index + 1);
2615 if (is_array) {
2616 if (depth_compare) {
2617 coord = "vec4 coords = vec4(" + x + ", " + y + ", " + depth_value +
2618 ", " + array_elem + ");";
2619 } else {
2620 coord = "vec3 coords = vec3(" + x + ", " + y + ", " + array_elem + ");";
2621 }
2622 } else {
2623 if (depth_compare) {
2624 coord =
2625 "vec3 coords = vec3(" + x + ", " + y + ", " + depth_value + ");";
2626 } else {
2627 coord = "vec2 coords = vec2(" + x + ", " + y + ");";
2628 }
2629 }
2630 break;
2631 }
2632 case 3: {
2633 const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index);
2634 const std::string y =
2635 regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index + 1);
2636 const std::string z =
2637 regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index + 2);
2638 if (is_array) {
2639 depth_compare_extra = depth_compare;
2640 coord = "vec4 coords = vec4(" + x + ", " + y + ", " + z + ", " +
2641 array_elem + ");";
2642 } else {
2643 if (depth_compare) {
2644 coord = "vec4 coords = vec4(" + x + ", " + y + ", " + z + ", " +
2645 depth_value + ");";
2646 } else {
2647 coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");";
2648 }
2649 }
2650 break;
2651 }
2652 default:
2653 UNIMPLEMENTED_MSG("Unhandled coordinates number {}",
2654 static_cast<u32>(num_coordinates));
2655
2656 // Fallback to interpreting as a 2D texture for now
2657 const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
2658 const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
2659 coord = "vec2 coords = vec2(" + x + ", " + y + ");";
2660 texture_type = Tegra::Shader::TextureType::Texture2D;
2661 }
2662
2663 const std::string sampler =
2664 GetSampler(instr.sampler, texture_type, is_array, depth_compare);
2665 // Add an extra scope and declare the texture coords inside to prevent
2666 // overwriting them in case they are used as outputs of the texs instruction.
2667
2668 shader.AddLine('{');
2669 ++shader.scope;
2670 shader.AddLine(coord); 2776 shader.AddLine(coord);
2671 std::string texture;
2672 2777
2673 switch (instr.tex.GetTextureProcessMode()) { 2778 if (depth_compare) {
2674 case Tegra::Shader::TextureProcessMode::None: { 2779 regs.SetRegisterToFloat(instr.gpr0, 0, texture, 1, 1, false);
2675 if (!depth_compare_extra) { 2780 } else {
2676 texture = "texture(" + sampler + ", coords)";
2677 } else {
2678 texture = "texture(" + sampler + ", coords, " + depth_value + ')';
2679 }
2680 break;
2681 }
2682 case Tegra::Shader::TextureProcessMode::LZ: {
2683 if (!depth_compare_extra) {
2684 texture = "textureLod(" + sampler + ", coords, 0.0)";
2685 } else {
2686 texture = "texture(" + sampler + ", coords, " + depth_value + ')';
2687 }
2688 break;
2689 }
2690 case Tegra::Shader::TextureProcessMode::LB:
2691 case Tegra::Shader::TextureProcessMode::LBA: {
2692 // TODO: Figure if A suffix changes the equation at all.
2693 if (!depth_compare_extra) {
2694 texture = "texture(" + sampler + ", coords, " + lod_value + ')';
2695 } else {
2696 texture = "texture(" + sampler + ", coords, " + depth_value + ')';
2697 LOG_WARNING(HW_GPU,
2698 "OpenGL Limitation: can't set bias value along depth compare");
2699 }
2700 break;
2701 }
2702 case Tegra::Shader::TextureProcessMode::LL:
2703 case Tegra::Shader::TextureProcessMode::LLA: {
2704 // TODO: Figure if A suffix changes the equation at all.
2705 if (!depth_compare_extra) {
2706 texture = "textureLod(" + sampler + ", coords, " + lod_value + ')';
2707 } else {
2708 texture = "texture(" + sampler + ", coords, " + depth_value + ')';
2709 LOG_WARNING(HW_GPU,
2710 "OpenGL Limitation: can't set lod value along depth compare");
2711 }
2712 break;
2713 }
2714 default: {
2715 if (!depth_compare_extra) {
2716 texture = "texture(" + sampler + ", coords)";
2717 } else {
2718 texture = "texture(" + sampler + ", coords, " + depth_value + ')';
2719 }
2720 UNIMPLEMENTED_MSG("Unhandled texture process mode {}",
2721 static_cast<u32>(instr.tex.GetTextureProcessMode()));
2722 }
2723 }
2724 if (!depth_compare) {
2725 shader.AddLine("vec4 texture_tmp = " + texture + ';'); 2781 shader.AddLine("vec4 texture_tmp = " + texture + ';');
2726 std::size_t dest_elem{}; 2782 std::size_t dest_elem{};
2727 for (std::size_t elem = 0; elem < 4; ++elem) { 2783 for (std::size_t elem = 0; elem < 4; ++elem) {
@@ -2733,138 +2789,36 @@ private:
2733 dest_elem); 2789 dest_elem);
2734 ++dest_elem; 2790 ++dest_elem;
2735 } 2791 }
2736 } else {
2737 regs.SetRegisterToFloat(instr.gpr0, 0, texture, 1, 1, false);
2738 } 2792 }
2739 --shader.scope;
2740 shader.AddLine('}');
2741 break; 2793 break;
2742 } 2794 }
2743 case OpCode::Id::TEXS: { 2795 case OpCode::Id::TEXS: {
2744 Tegra::Shader::TextureType texture_type{instr.texs.GetTextureType()}; 2796 Tegra::Shader::TextureType texture_type{instr.texs.GetTextureType()};
2745 bool is_array{instr.texs.IsArrayTexture()}; 2797 const bool is_array{instr.texs.IsArrayTexture()};
2798 const bool depth_compare =
2799 instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC);
2800 const auto process_mode = instr.texs.GetTextureProcessMode();
2746 2801
2747 UNIMPLEMENTED_IF_MSG(instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), 2802 UNIMPLEMENTED_IF_MSG(instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
2748 "NODEP is not implemented"); 2803 "NODEP is not implemented");
2749 2804
2750 const bool depth_compare = 2805 const auto scope = shader.Scope();
2751 instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC);
2752 u32 num_coordinates = TextureCoordinates(texture_type);
2753 const auto process_mode = instr.texs.GetTextureProcessMode();
2754 std::string lod_value;
2755 std::string coord;
2756 u32 lod_offset = 0;
2757 if (process_mode == Tegra::Shader::TextureProcessMode::LL) {
2758 if (num_coordinates > 2) {
2759 lod_value = regs.GetRegisterAsFloat(instr.gpr20.Value() + 1);
2760 lod_offset = 2;
2761 } else {
2762 lod_value = regs.GetRegisterAsFloat(instr.gpr20);
2763 lod_offset = 1;
2764 }
2765 }
2766 2806
2767 switch (num_coordinates) { 2807 auto [coord, texture] =
2768 case 1: { 2808 GetTEXSCode(instr, texture_type, process_mode, depth_compare, is_array);
2769 coord = "float coords = " + regs.GetRegisterAsFloat(instr.gpr8) + ';';
2770 break;
2771 }
2772 case 2: {
2773 if (is_array) {
2774 if (depth_compare) {
2775 const std::string index = regs.GetRegisterAsInteger(instr.gpr8);
2776 const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
2777 const std::string y = regs.GetRegisterAsFloat(instr.gpr20);
2778 const std::string z = regs.GetRegisterAsFloat(instr.gpr20.Value() + 1);
2779 coord = "vec4 coords = vec4(" + x + ", " + y + ", " + z + ", " + index +
2780 ");";
2781 } else {
2782 const std::string index = regs.GetRegisterAsInteger(instr.gpr8);
2783 const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
2784 const std::string y = regs.GetRegisterAsFloat(instr.gpr20);
2785 coord = "vec3 coords = vec3(" + x + ", " + y + ", " + index + ");";
2786 }
2787 } else {
2788 if (lod_offset != 0) {
2789 if (depth_compare) {
2790 const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
2791 const std::string y =
2792 regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
2793 const std::string z =
2794 regs.GetRegisterAsFloat(instr.gpr20.Value() + lod_offset);
2795 coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");";
2796 } else {
2797 const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
2798 const std::string y =
2799 regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
2800 coord = "vec2 coords = vec2(" + x + ", " + y + ");";
2801 }
2802 } else {
2803 if (depth_compare) {
2804 const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
2805 const std::string y =
2806 regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
2807 const std::string z = regs.GetRegisterAsFloat(instr.gpr20);
2808 coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");";
2809 } else {
2810 const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
2811 const std::string y = regs.GetRegisterAsFloat(instr.gpr20);
2812 coord = "vec2 coords = vec2(" + x + ", " + y + ");";
2813 }
2814 }
2815 }
2816 break;
2817 }
2818 case 3: {
2819 const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
2820 const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
2821 const std::string z = regs.GetRegisterAsFloat(instr.gpr20);
2822 coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");";
2823 break;
2824 }
2825 default:
2826 UNIMPLEMENTED_MSG("Unhandled coordinates number {}",
2827 static_cast<u32>(num_coordinates));
2828 2809
2829 // Fallback to interpreting as a 2D texture for now 2810 shader.AddLine(coord);
2830 const std::string x = regs.GetRegisterAsFloat(instr.gpr8); 2811
2831 const std::string y = regs.GetRegisterAsFloat(instr.gpr20); 2812 if (depth_compare) {
2832 coord = "vec2 coords = vec2(" + x + ", " + y + ");"; 2813 texture = "vec4(" + texture + ')';
2833 texture_type = Tegra::Shader::TextureType::Texture2D;
2834 is_array = false;
2835 }
2836 const std::string sampler =
2837 GetSampler(instr.sampler, texture_type, is_array, depth_compare);
2838 std::string texture;
2839 switch (process_mode) {
2840 case Tegra::Shader::TextureProcessMode::None: {
2841 texture = "texture(" + sampler + ", coords)";
2842 break;
2843 }
2844 case Tegra::Shader::TextureProcessMode::LZ: {
2845 if (depth_compare && is_array) {
2846 texture = "texture(" + sampler + ", coords)";
2847 } else {
2848 texture = "textureLod(" + sampler + ", coords, 0.0)";
2849 }
2850 break;
2851 }
2852 case Tegra::Shader::TextureProcessMode::LL: {
2853 texture = "textureLod(" + sampler + ", coords, " + lod_value + ')';
2854 break;
2855 }
2856 default: {
2857 texture = "texture(" + sampler + ", coords)";
2858 UNIMPLEMENTED_MSG("Unhandled texture process mode {}",
2859 static_cast<u32>(instr.texs.GetTextureProcessMode()));
2860 }
2861 } 2814 }
2862 if (!depth_compare) { 2815 shader.AddLine("vec4 texture_tmp = " + texture + ';');
2863 WriteTexsInstruction(instr, coord, texture); 2816
2817 if (instr.texs.fp32_flag) {
2818 WriteTexsInstructionFloat(instr, "texture_tmp");
2864 } else { 2819 } else {
2865 WriteTexsInstruction(instr, coord, "vec4(" + texture + ')'); 2820 WriteTexsInstructionHalfFloat(instr, "texture_tmp");
2866 } 2821 }
2867
2868 break; 2822 break;
2869 } 2823 }
2870 case OpCode::Id::TLDS: { 2824 case OpCode::Id::TLDS: {
@@ -2883,15 +2837,12 @@ private:
2883 2837
2884 u32 extra_op_offset = 0; 2838 u32 extra_op_offset = 0;
2885 2839
2886 // Scope to avoid variable name overlaps. 2840 ShaderScopedScope scope = shader.Scope();
2887 shader.AddLine('{');
2888 ++shader.scope;
2889 std::string coords;
2890 2841
2891 switch (texture_type) { 2842 switch (texture_type) {
2892 case Tegra::Shader::TextureType::Texture1D: { 2843 case Tegra::Shader::TextureType::Texture1D: {
2893 const std::string x = regs.GetRegisterAsInteger(instr.gpr8); 2844 const std::string x = regs.GetRegisterAsInteger(instr.gpr8);
2894 coords = "float coords = " + x + ';'; 2845 shader.AddLine("float coords = " + x + ';');
2895 break; 2846 break;
2896 } 2847 }
2897 case Tegra::Shader::TextureType::Texture2D: { 2848 case Tegra::Shader::TextureType::Texture2D: {
@@ -2900,7 +2851,7 @@ private:
2900 const std::string x = regs.GetRegisterAsInteger(instr.gpr8); 2851 const std::string x = regs.GetRegisterAsInteger(instr.gpr8);
2901 const std::string y = regs.GetRegisterAsInteger(instr.gpr20); 2852 const std::string y = regs.GetRegisterAsInteger(instr.gpr20);
2902 // shader.AddLine("ivec2 coords = ivec2(" + x + ", " + y + ");"); 2853 // shader.AddLine("ivec2 coords = ivec2(" + x + ", " + y + ");");
2903 coords = "ivec2 coords = ivec2(" + x + ", " + y + ");"; 2854 shader.AddLine("ivec2 coords = ivec2(" + x + ", " + y + ");");
2904 extra_op_offset = 1; 2855 extra_op_offset = 1;
2905 break; 2856 break;
2906 } 2857 }
@@ -2909,35 +2860,29 @@ private:
2909 } 2860 }
2910 const std::string sampler = 2861 const std::string sampler =
2911 GetSampler(instr.sampler, texture_type, is_array, false); 2862 GetSampler(instr.sampler, texture_type, is_array, false);
2912 std::string texture = "texelFetch(" + sampler + ", coords, 0)";
2913 switch (instr.tlds.GetTextureProcessMode()) {
2914 case Tegra::Shader::TextureProcessMode::LZ: {
2915 texture = "texelFetch(" + sampler + ", coords, 0)";
2916 break;
2917 }
2918 case Tegra::Shader::TextureProcessMode::LL: {
2919 shader.AddLine(
2920 "float lod = " +
2921 regs.GetRegisterAsInteger(instr.gpr20.Value() + extra_op_offset) + ';');
2922 texture = "texelFetch(" + sampler + ", coords, lod)";
2923 break;
2924 }
2925 default: {
2926 texture = "texelFetch(" + sampler + ", coords, 0)";
2927 UNIMPLEMENTED_MSG("Unhandled texture process mode {}",
2928 static_cast<u32>(instr.tlds.GetTextureProcessMode()));
2929 }
2930 }
2931 WriteTexsInstruction(instr, coords, texture);
2932 2863
2933 --shader.scope; 2864 const std::string texture = [&]() {
2934 shader.AddLine('}'); 2865 switch (instr.tlds.GetTextureProcessMode()) {
2866 case Tegra::Shader::TextureProcessMode::LZ:
2867 return "texelFetch(" + sampler + ", coords, 0)";
2868 case Tegra::Shader::TextureProcessMode::LL:
2869 shader.AddLine(
2870 "float lod = " +
2871 regs.GetRegisterAsInteger(instr.gpr20.Value() + extra_op_offset) + ';');
2872 return "texelFetch(" + sampler + ", coords, lod)";
2873 default:
2874 UNIMPLEMENTED_MSG("Unhandled texture process mode {}",
2875 static_cast<u32>(instr.tlds.GetTextureProcessMode()));
2876 return "texelFetch(" + sampler + ", coords, 0)";
2877 }
2878 }();
2879
2880 WriteTexsInstructionFloat(instr, texture);
2935 break; 2881 break;
2936 } 2882 }
2937 case OpCode::Id::TLD4: { 2883 case OpCode::Id::TLD4: {
2938 ASSERT(instr.tld4.texture_type == Tegra::Shader::TextureType::Texture2D); 2884 ASSERT(instr.tld4.texture_type == Tegra::Shader::TextureType::Texture2D);
2939 ASSERT(instr.tld4.array == 0); 2885 ASSERT(instr.tld4.array == 0);
2940 std::string coord;
2941 2886
2942 UNIMPLEMENTED_IF_MSG(instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), 2887 UNIMPLEMENTED_IF_MSG(instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
2943 "NODEP is not implemented"); 2888 "NODEP is not implemented");
@@ -2954,10 +2899,7 @@ private:
2954 if (depth_compare) 2899 if (depth_compare)
2955 num_coordinates += 1; 2900 num_coordinates += 1;
2956 2901
2957 // Add an extra scope and declare the texture coords inside to prevent 2902 const auto scope = shader.Scope();
2958 // overwriting them in case they are used as outputs of the texs instruction.
2959 shader.AddLine('{');
2960 ++shader.scope;
2961 2903
2962 switch (num_coordinates) { 2904 switch (num_coordinates) {
2963 case 2: { 2905 case 2: {
@@ -2988,23 +2930,19 @@ private:
2988 const std::string texture = "textureGather(" + sampler + ", coords, " + 2930 const std::string texture = "textureGather(" + sampler + ", coords, " +
2989 std::to_string(instr.tld4.component) + ')'; 2931 std::to_string(instr.tld4.component) + ')';
2990 2932
2991 if (!depth_compare) { 2933 if (depth_compare) {
2992 shader.AddLine("vec4 texture_tmp = " + texture + ';'); 2934 regs.SetRegisterToFloat(instr.gpr0, 0, texture, 1, 1, false);
2935 } else {
2993 std::size_t dest_elem{}; 2936 std::size_t dest_elem{};
2994 for (std::size_t elem = 0; elem < 4; ++elem) { 2937 for (std::size_t elem = 0; elem < 4; ++elem) {
2995 if (!instr.tex.IsComponentEnabled(elem)) { 2938 if (!instr.tex.IsComponentEnabled(elem)) {
2996 // Skip disabled components 2939 // Skip disabled components
2997 continue; 2940 continue;
2998 } 2941 }
2999 regs.SetRegisterToFloat(instr.gpr0, elem, "texture_tmp", 1, 4, false, 2942 regs.SetRegisterToFloat(instr.gpr0, elem, texture, 1, 4, false, dest_elem);
3000 dest_elem);
3001 ++dest_elem; 2943 ++dest_elem;
3002 } 2944 }
3003 } else {
3004 regs.SetRegisterToFloat(instr.gpr0, 0, texture, 1, 1, false);
3005 } 2945 }
3006 --shader.scope;
3007 shader.AddLine('}');
3008 break; 2946 break;
3009 } 2947 }
3010 case OpCode::Id::TLD4S: { 2948 case OpCode::Id::TLD4S: {
@@ -3015,10 +2953,7 @@ private:
3015 instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI), 2953 instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI),
3016 "AOFFI is not implemented"); 2954 "AOFFI is not implemented");
3017 2955
3018 // Scope to avoid variable name overlaps. 2956 const auto scope = shader.Scope();
3019 shader.AddLine('{');
3020 ++shader.scope;
3021 std::string coords;
3022 2957
3023 const bool depth_compare = 2958 const bool depth_compare =
3024 instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC); 2959 instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC);
@@ -3027,33 +2962,30 @@ private:
3027 // TODO(Subv): Figure out how the sampler type is encoded in the TLD4S instruction. 2962 // TODO(Subv): Figure out how the sampler type is encoded in the TLD4S instruction.
3028 const std::string sampler = GetSampler( 2963 const std::string sampler = GetSampler(
3029 instr.sampler, Tegra::Shader::TextureType::Texture2D, false, depth_compare); 2964 instr.sampler, Tegra::Shader::TextureType::Texture2D, false, depth_compare);
3030 if (!depth_compare) { 2965 if (depth_compare) {
3031 coords = "vec2 coords = vec2(" + op_a + ", " + op_b + ");";
3032 } else {
3033 // Note: TLD4S coordinate encoding works just like TEXS's 2966 // Note: TLD4S coordinate encoding works just like TEXS's
3034 const std::string op_y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); 2967 const std::string op_y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
3035 coords = "vec3 coords = vec3(" + op_a + ", " + op_y + ", " + op_b + ");"; 2968 shader.AddLine("vec3 coords = vec3(" + op_a + ", " + op_y + ", " + op_b + ");");
2969 } else {
2970 shader.AddLine("vec2 coords = vec2(" + op_a + ", " + op_b + ");");
3036 } 2971 }
3037 const std::string texture = "textureGather(" + sampler + ", coords, " +
3038 std::to_string(instr.tld4s.component) + ')';
3039 2972
3040 if (!depth_compare) { 2973 std::string texture = "textureGather(" + sampler + ", coords, " +
3041 WriteTexsInstruction(instr, coords, texture); 2974 std::to_string(instr.tld4s.component) + ')';
3042 } else { 2975 if (depth_compare) {
3043 WriteTexsInstruction(instr, coords, "vec4(" + texture + ')'); 2976 texture = "vec4(" + texture + ')';
3044 } 2977 }
3045 2978
3046 --shader.scope; 2979 WriteTexsInstructionFloat(instr, texture);
3047 shader.AddLine('}');
3048 break; 2980 break;
3049 } 2981 }
3050 case OpCode::Id::TXQ: { 2982 case OpCode::Id::TXQ: {
3051 UNIMPLEMENTED_IF_MSG(instr.txq.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), 2983 UNIMPLEMENTED_IF_MSG(instr.txq.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
3052 "NODEP is not implemented"); 2984 "NODEP is not implemented");
3053 2985
3054 ++shader.scope; 2986 const auto scope = shader.Scope();
3055 shader.AddLine('{'); 2987
3056 // TODO: the new commits on the texture refactor, change the way samplers work. 2988 // TODO: The new commits on the texture refactor, change the way samplers work.
3057 // Sadly, not all texture instructions specify the type of texture their sampler 2989 // Sadly, not all texture instructions specify the type of texture their sampler
3058 // uses. This must be fixed at a later instance. 2990 // uses. This must be fixed at a later instance.
3059 const std::string sampler = 2991 const std::string sampler =
@@ -3064,7 +2996,8 @@ private:
3064 regs.GetRegisterAsInteger(instr.gpr8) + ')'; 2996 regs.GetRegisterAsInteger(instr.gpr8) + ')';
3065 const std::string mip_level = "textureQueryLevels(" + sampler + ')'; 2997 const std::string mip_level = "textureQueryLevels(" + sampler + ')';
3066 shader.AddLine("ivec2 sizes = " + texture + ';'); 2998 shader.AddLine("ivec2 sizes = " + texture + ';');
3067 regs.SetRegisterToInteger(instr.gpr0, true, 0, "sizes.x", 1, 1); 2999
3000 regs.SetRegisterToInteger(instr.gpr0.Value() + 0, true, 0, "sizes.x", 1, 1);
3068 regs.SetRegisterToInteger(instr.gpr0.Value() + 1, true, 0, "sizes.y", 1, 1); 3001 regs.SetRegisterToInteger(instr.gpr0.Value() + 1, true, 0, "sizes.y", 1, 1);
3069 regs.SetRegisterToInteger(instr.gpr0.Value() + 2, true, 0, "0", 1, 1); 3002 regs.SetRegisterToInteger(instr.gpr0.Value() + 2, true, 0, "0", 1, 1);
3070 regs.SetRegisterToInteger(instr.gpr0.Value() + 3, true, 0, mip_level, 1, 1); 3003 regs.SetRegisterToInteger(instr.gpr0.Value() + 3, true, 0, mip_level, 1, 1);
@@ -3075,8 +3008,6 @@ private:
3075 static_cast<u32>(instr.txq.query_type.Value())); 3008 static_cast<u32>(instr.txq.query_type.Value()));
3076 } 3009 }
3077 } 3010 }
3078 --shader.scope;
3079 shader.AddLine('}');
3080 break; 3011 break;
3081 } 3012 }
3082 case OpCode::Id::TMML: { 3013 case OpCode::Id::TMML: {
@@ -3091,17 +3022,18 @@ private:
3091 const std::string sampler = 3022 const std::string sampler =
3092 GetSampler(instr.sampler, texture_type, is_array, false); 3023 GetSampler(instr.sampler, texture_type, is_array, false);
3093 3024
3094 // TODO: add coordinates for different samplers once other texture types are 3025 const auto scope = shader.Scope();
3026
3027 // TODO: Add coordinates for different samplers once other texture types are
3095 // implemented. 3028 // implemented.
3096 std::string coord;
3097 switch (texture_type) { 3029 switch (texture_type) {
3098 case Tegra::Shader::TextureType::Texture1D: { 3030 case Tegra::Shader::TextureType::Texture1D: {
3099 coord = "float coords = " + x + ';'; 3031 shader.AddLine("float coords = " + x + ';');
3100 break; 3032 break;
3101 } 3033 }
3102 case Tegra::Shader::TextureType::Texture2D: { 3034 case Tegra::Shader::TextureType::Texture2D: {
3103 const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); 3035 const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
3104 coord = "vec2 coords = vec2(" + x + ", " + y + ");"; 3036 shader.AddLine("vec2 coords = vec2(" + x + ", " + y + ");");
3105 break; 3037 break;
3106 } 3038 }
3107 default: 3039 default:
@@ -3109,22 +3041,15 @@ private:
3109 3041
3110 // Fallback to interpreting as a 2D texture for now 3042 // Fallback to interpreting as a 2D texture for now
3111 const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); 3043 const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
3112 coord = "vec2 coords = vec2(" + x + ", " + y + ");"; 3044 shader.AddLine("vec2 coords = vec2(" + x + ", " + y + ");");
3113 texture_type = Tegra::Shader::TextureType::Texture2D; 3045 texture_type = Tegra::Shader::TextureType::Texture2D;
3114 } 3046 }
3115 // Add an extra scope and declare the texture coords inside to prevent 3047
3116 // overwriting them in case they are used as outputs of the texs instruction.
3117 shader.AddLine('{');
3118 ++shader.scope;
3119 shader.AddLine(coord);
3120 const std::string texture = "textureQueryLod(" + sampler + ", coords)"; 3048 const std::string texture = "textureQueryLod(" + sampler + ", coords)";
3121 const std::string tmp = "vec2 tmp = " + texture + "*vec2(256.0, 256.0);"; 3049 shader.AddLine("vec2 tmp = " + texture + " * vec2(256.0, 256.0);");
3122 shader.AddLine(tmp);
3123 3050
3124 regs.SetRegisterToInteger(instr.gpr0, true, 0, "int(tmp.y)", 1, 1); 3051 regs.SetRegisterToInteger(instr.gpr0, true, 0, "int(tmp.y)", 1, 1);
3125 regs.SetRegisterToInteger(instr.gpr0.Value() + 1, false, 0, "uint(tmp.x)", 1, 1); 3052 regs.SetRegisterToInteger(instr.gpr0.Value() + 1, false, 0, "uint(tmp.x)", 1, 1);
3126 --shader.scope;
3127 shader.AddLine('}');
3128 break; 3053 break;
3129 } 3054 }
3130 default: { 3055 default: {
@@ -3963,4 +3888,4 @@ std::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, u
3963 return {}; 3888 return {};
3964} 3889}
3965 3890
3966} // namespace OpenGL::GLShader::Decompiler 3891} // namespace OpenGL::GLShader::Decompiler \ No newline at end of file
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.h b/src/video_core/renderer_opengl/gl_shader_gen.h
index b425d98ae..4fa6d7612 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.h
+++ b/src/video_core/renderer_opengl/gl_shader_gen.h
@@ -163,6 +163,7 @@ private:
163struct ShaderEntries { 163struct ShaderEntries {
164 std::vector<ConstBufferEntry> const_buffer_entries; 164 std::vector<ConstBufferEntry> const_buffer_entries;
165 std::vector<SamplerEntry> texture_samplers; 165 std::vector<SamplerEntry> texture_samplers;
166 std::array<bool, Tegra::Engines::Maxwell3D::Regs::NumClipDistances> clip_distances;
166 std::size_t shader_length; 167 std::size_t shader_length;
167}; 168};
168 169
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.h b/src/video_core/renderer_opengl/gl_shader_manager.h
index b757f5f44..4970aafed 100644
--- a/src/video_core/renderer_opengl/gl_shader_manager.h
+++ b/src/video_core/renderer_opengl/gl_shader_manager.h
@@ -60,6 +60,17 @@ public:
60 } 60 }
61 61
62 void ApplyTo(OpenGLState& state) { 62 void ApplyTo(OpenGLState& state) {
63 UpdatePipeline();
64 state.draw.shader_program = 0;
65 state.draw.program_pipeline = pipeline.handle;
66 state.geometry_shaders.enabled = (gs != 0);
67 }
68
69private:
70 void UpdatePipeline() {
71 // Avoid updating the pipeline when values have no changed
72 if (old_vs == vs && old_fs == fs && old_gs == gs)
73 return;
63 // Workaround for AMD bug 74 // Workaround for AMD bug
64 glUseProgramStages(pipeline.handle, 75 glUseProgramStages(pipeline.handle,
65 GL_VERTEX_SHADER_BIT | GL_GEOMETRY_SHADER_BIT | GL_FRAGMENT_SHADER_BIT, 76 GL_VERTEX_SHADER_BIT | GL_GEOMETRY_SHADER_BIT | GL_FRAGMENT_SHADER_BIT,
@@ -68,14 +79,16 @@ public:
68 glUseProgramStages(pipeline.handle, GL_VERTEX_SHADER_BIT, vs); 79 glUseProgramStages(pipeline.handle, GL_VERTEX_SHADER_BIT, vs);
69 glUseProgramStages(pipeline.handle, GL_GEOMETRY_SHADER_BIT, gs); 80 glUseProgramStages(pipeline.handle, GL_GEOMETRY_SHADER_BIT, gs);
70 glUseProgramStages(pipeline.handle, GL_FRAGMENT_SHADER_BIT, fs); 81 glUseProgramStages(pipeline.handle, GL_FRAGMENT_SHADER_BIT, fs);
71 state.draw.shader_program = 0; 82
72 state.draw.program_pipeline = pipeline.handle; 83 // Update the old values
73 state.geometry_shaders.enabled = (gs != 0); 84 old_vs = vs;
85 old_fs = fs;
86 old_gs = gs;
74 } 87 }
75 88
76private:
77 OGLPipeline pipeline; 89 OGLPipeline pipeline;
78 GLuint vs{}, fs{}, gs{}; 90 GLuint vs{}, fs{}, gs{};
91 GLuint old_vs{}, old_fs{}, old_gs{};
79}; 92};
80 93
81} // namespace OpenGL::GLShader 94} // namespace OpenGL::GLShader
diff --git a/src/video_core/surface.h b/src/video_core/surface.h
index 0dd3eb2e4..e23cfecbc 100644
--- a/src/video_core/surface.h
+++ b/src/video_core/surface.h
@@ -125,6 +125,75 @@ enum class SurfaceTarget {
125 TextureCubeArray, 125 TextureCubeArray,
126}; 126};
127 127
128constexpr std::array<u32, MaxPixelFormat> compression_factor_table = {{
129 1, // ABGR8U
130 1, // ABGR8S
131 1, // ABGR8UI
132 1, // B5G6R5U
133 1, // A2B10G10R10U
134 1, // A1B5G5R5U
135 1, // R8U
136 1, // R8UI
137 1, // RGBA16F
138 1, // RGBA16U
139 1, // RGBA16UI
140 1, // R11FG11FB10F
141 1, // RGBA32UI
142 4, // DXT1
143 4, // DXT23
144 4, // DXT45
145 4, // DXN1
146 4, // DXN2UNORM
147 4, // DXN2SNORM
148 4, // BC7U
149 4, // BC6H_UF16
150 4, // BC6H_SF16
151 4, // ASTC_2D_4X4
152 1, // G8R8U
153 1, // G8R8S
154 1, // BGRA8
155 1, // RGBA32F
156 1, // RG32F
157 1, // R32F
158 1, // R16F
159 1, // R16U
160 1, // R16S
161 1, // R16UI
162 1, // R16I
163 1, // RG16
164 1, // RG16F
165 1, // RG16UI
166 1, // RG16I
167 1, // RG16S
168 1, // RGB32F
169 1, // RGBA8_SRGB
170 1, // RG8U
171 1, // RG8S
172 1, // RG32UI
173 1, // R32UI
174 4, // ASTC_2D_8X8
175 4, // ASTC_2D_8X5
176 4, // ASTC_2D_5X4
177 1, // BGRA8_SRGB
178 4, // DXT1_SRGB
179 4, // DXT23_SRGB
180 4, // DXT45_SRGB
181 4, // BC7U_SRGB
182 4, // ASTC_2D_4X4_SRGB
183 4, // ASTC_2D_8X8_SRGB
184 4, // ASTC_2D_8X5_SRGB
185 4, // ASTC_2D_5X4_SRGB
186 4, // ASTC_2D_5X5
187 4, // ASTC_2D_5X5_SRGB
188 4, // ASTC_2D_10X8
189 4, // ASTC_2D_10X8_SRGB
190 1, // Z32F
191 1, // Z16
192 1, // Z24S8
193 1, // S8Z24
194 1, // Z32FS8
195}};
196
128/** 197/**
129 * Gets the compression factor for the specified PixelFormat. This applies to just the 198 * Gets the compression factor for the specified PixelFormat. This applies to just the
130 * "compressed width" and "compressed height", not the overall compression factor of a 199 * "compressed width" and "compressed height", not the overall compression factor of a
@@ -135,304 +204,237 @@ static constexpr u32 GetCompressionFactor(PixelFormat format) {
135 if (format == PixelFormat::Invalid) 204 if (format == PixelFormat::Invalid)
136 return 0; 205 return 0;
137 206
138 constexpr std::array<u32, MaxPixelFormat> compression_factor_table = {{
139 1, // ABGR8U
140 1, // ABGR8S
141 1, // ABGR8UI
142 1, // B5G6R5U
143 1, // A2B10G10R10U
144 1, // A1B5G5R5U
145 1, // R8U
146 1, // R8UI
147 1, // RGBA16F
148 1, // RGBA16U
149 1, // RGBA16UI
150 1, // R11FG11FB10F
151 1, // RGBA32UI
152 4, // DXT1
153 4, // DXT23
154 4, // DXT45
155 4, // DXN1
156 4, // DXN2UNORM
157 4, // DXN2SNORM
158 4, // BC7U
159 4, // BC6H_UF16
160 4, // BC6H_SF16
161 4, // ASTC_2D_4X4
162 1, // G8R8U
163 1, // G8R8S
164 1, // BGRA8
165 1, // RGBA32F
166 1, // RG32F
167 1, // R32F
168 1, // R16F
169 1, // R16U
170 1, // R16S
171 1, // R16UI
172 1, // R16I
173 1, // RG16
174 1, // RG16F
175 1, // RG16UI
176 1, // RG16I
177 1, // RG16S
178 1, // RGB32F
179 1, // RGBA8_SRGB
180 1, // RG8U
181 1, // RG8S
182 1, // RG32UI
183 1, // R32UI
184 4, // ASTC_2D_8X8
185 4, // ASTC_2D_8X5
186 4, // ASTC_2D_5X4
187 1, // BGRA8_SRGB
188 4, // DXT1_SRGB
189 4, // DXT23_SRGB
190 4, // DXT45_SRGB
191 4, // BC7U_SRGB
192 4, // ASTC_2D_4X4_SRGB
193 4, // ASTC_2D_8X8_SRGB
194 4, // ASTC_2D_8X5_SRGB
195 4, // ASTC_2D_5X4_SRGB
196 4, // ASTC_2D_5X5
197 4, // ASTC_2D_5X5_SRGB
198 4, // ASTC_2D_10X8
199 4, // ASTC_2D_10X8_SRGB
200 1, // Z32F
201 1, // Z16
202 1, // Z24S8
203 1, // S8Z24
204 1, // Z32FS8
205 }};
206
207 ASSERT(static_cast<std::size_t>(format) < compression_factor_table.size()); 207 ASSERT(static_cast<std::size_t>(format) < compression_factor_table.size());
208 return compression_factor_table[static_cast<std::size_t>(format)]; 208 return compression_factor_table[static_cast<std::size_t>(format)];
209} 209}
210 210
211constexpr std::array<u32, MaxPixelFormat> block_width_table = {{
212 1, // ABGR8U
213 1, // ABGR8S
214 1, // ABGR8UI
215 1, // B5G6R5U
216 1, // A2B10G10R10U
217 1, // A1B5G5R5U
218 1, // R8U
219 1, // R8UI
220 1, // RGBA16F
221 1, // RGBA16U
222 1, // RGBA16UI
223 1, // R11FG11FB10F
224 1, // RGBA32UI
225 4, // DXT1
226 4, // DXT23
227 4, // DXT45
228 4, // DXN1
229 4, // DXN2UNORM
230 4, // DXN2SNORM
231 4, // BC7U
232 4, // BC6H_UF16
233 4, // BC6H_SF16
234 4, // ASTC_2D_4X4
235 1, // G8R8U
236 1, // G8R8S
237 1, // BGRA8
238 1, // RGBA32F
239 1, // RG32F
240 1, // R32F
241 1, // R16F
242 1, // R16U
243 1, // R16S
244 1, // R16UI
245 1, // R16I
246 1, // RG16
247 1, // RG16F
248 1, // RG16UI
249 1, // RG16I
250 1, // RG16S
251 1, // RGB32F
252 1, // RGBA8_SRGB
253 1, // RG8U
254 1, // RG8S
255 1, // RG32UI
256 1, // R32UI
257 8, // ASTC_2D_8X8
258 8, // ASTC_2D_8X5
259 5, // ASTC_2D_5X4
260 1, // BGRA8_SRGB
261 4, // DXT1_SRGB
262 4, // DXT23_SRGB
263 4, // DXT45_SRGB
264 4, // BC7U_SRGB
265 4, // ASTC_2D_4X4_SRGB
266 8, // ASTC_2D_8X8_SRGB
267 8, // ASTC_2D_8X5_SRGB
268 5, // ASTC_2D_5X4_SRGB
269 5, // ASTC_2D_5X5
270 5, // ASTC_2D_5X5_SRGB
271 10, // ASTC_2D_10X8
272 10, // ASTC_2D_10X8_SRGB
273 1, // Z32F
274 1, // Z16
275 1, // Z24S8
276 1, // S8Z24
277 1, // Z32FS8
278}};
279
211static constexpr u32 GetDefaultBlockWidth(PixelFormat format) { 280static constexpr u32 GetDefaultBlockWidth(PixelFormat format) {
212 if (format == PixelFormat::Invalid) 281 if (format == PixelFormat::Invalid)
213 return 0; 282 return 0;
214 constexpr std::array<u32, MaxPixelFormat> block_width_table = {{ 283
215 1, // ABGR8U
216 1, // ABGR8S
217 1, // ABGR8UI
218 1, // B5G6R5U
219 1, // A2B10G10R10U
220 1, // A1B5G5R5U
221 1, // R8U
222 1, // R8UI
223 1, // RGBA16F
224 1, // RGBA16U
225 1, // RGBA16UI
226 1, // R11FG11FB10F
227 1, // RGBA32UI
228 4, // DXT1
229 4, // DXT23
230 4, // DXT45
231 4, // DXN1
232 4, // DXN2UNORM
233 4, // DXN2SNORM
234 4, // BC7U
235 4, // BC6H_UF16
236 4, // BC6H_SF16
237 4, // ASTC_2D_4X4
238 1, // G8R8U
239 1, // G8R8S
240 1, // BGRA8
241 1, // RGBA32F
242 1, // RG32F
243 1, // R32F
244 1, // R16F
245 1, // R16U
246 1, // R16S
247 1, // R16UI
248 1, // R16I
249 1, // RG16
250 1, // RG16F
251 1, // RG16UI
252 1, // RG16I
253 1, // RG16S
254 1, // RGB32F
255 1, // RGBA8_SRGB
256 1, // RG8U
257 1, // RG8S
258 1, // RG32UI
259 1, // R32UI
260 8, // ASTC_2D_8X8
261 8, // ASTC_2D_8X5
262 5, // ASTC_2D_5X4
263 1, // BGRA8_SRGB
264 4, // DXT1_SRGB
265 4, // DXT23_SRGB
266 4, // DXT45_SRGB
267 4, // BC7U_SRGB
268 4, // ASTC_2D_4X4_SRGB
269 8, // ASTC_2D_8X8_SRGB
270 8, // ASTC_2D_8X5_SRGB
271 5, // ASTC_2D_5X4_SRGB
272 5, // ASTC_2D_5X5
273 5, // ASTC_2D_5X5_SRGB
274 10, // ASTC_2D_10X8
275 10, // ASTC_2D_10X8_SRGB
276 1, // Z32F
277 1, // Z16
278 1, // Z24S8
279 1, // S8Z24
280 1, // Z32FS8
281 }};
282 ASSERT(static_cast<std::size_t>(format) < block_width_table.size()); 284 ASSERT(static_cast<std::size_t>(format) < block_width_table.size());
283 return block_width_table[static_cast<std::size_t>(format)]; 285 return block_width_table[static_cast<std::size_t>(format)];
284} 286}
285 287
288constexpr std::array<u32, MaxPixelFormat> block_height_table = {{
289 1, // ABGR8U
290 1, // ABGR8S
291 1, // ABGR8UI
292 1, // B5G6R5U
293 1, // A2B10G10R10U
294 1, // A1B5G5R5U
295 1, // R8U
296 1, // R8UI
297 1, // RGBA16F
298 1, // RGBA16U
299 1, // RGBA16UI
300 1, // R11FG11FB10F
301 1, // RGBA32UI
302 4, // DXT1
303 4, // DXT23
304 4, // DXT45
305 4, // DXN1
306 4, // DXN2UNORM
307 4, // DXN2SNORM
308 4, // BC7U
309 4, // BC6H_UF16
310 4, // BC6H_SF16
311 4, // ASTC_2D_4X4
312 1, // G8R8U
313 1, // G8R8S
314 1, // BGRA8
315 1, // RGBA32F
316 1, // RG32F
317 1, // R32F
318 1, // R16F
319 1, // R16U
320 1, // R16S
321 1, // R16UI
322 1, // R16I
323 1, // RG16
324 1, // RG16F
325 1, // RG16UI
326 1, // RG16I
327 1, // RG16S
328 1, // RGB32F
329 1, // RGBA8_SRGB
330 1, // RG8U
331 1, // RG8S
332 1, // RG32UI
333 1, // R32UI
334 8, // ASTC_2D_8X8
335 5, // ASTC_2D_8X5
336 4, // ASTC_2D_5X4
337 1, // BGRA8_SRGB
338 4, // DXT1_SRGB
339 4, // DXT23_SRGB
340 4, // DXT45_SRGB
341 4, // BC7U_SRGB
342 4, // ASTC_2D_4X4_SRGB
343 8, // ASTC_2D_8X8_SRGB
344 5, // ASTC_2D_8X5_SRGB
345 4, // ASTC_2D_5X4_SRGB
346 5, // ASTC_2D_5X5
347 5, // ASTC_2D_5X5_SRGB
348 8, // ASTC_2D_10X8
349 8, // ASTC_2D_10X8_SRGB
350 1, // Z32F
351 1, // Z16
352 1, // Z24S8
353 1, // S8Z24
354 1, // Z32FS8
355}};
356
286static constexpr u32 GetDefaultBlockHeight(PixelFormat format) { 357static constexpr u32 GetDefaultBlockHeight(PixelFormat format) {
287 if (format == PixelFormat::Invalid) 358 if (format == PixelFormat::Invalid)
288 return 0; 359 return 0;
289 360
290 constexpr std::array<u32, MaxPixelFormat> block_height_table = {{
291 1, // ABGR8U
292 1, // ABGR8S
293 1, // ABGR8UI
294 1, // B5G6R5U
295 1, // A2B10G10R10U
296 1, // A1B5G5R5U
297 1, // R8U
298 1, // R8UI
299 1, // RGBA16F
300 1, // RGBA16U
301 1, // RGBA16UI
302 1, // R11FG11FB10F
303 1, // RGBA32UI
304 4, // DXT1
305 4, // DXT23
306 4, // DXT45
307 4, // DXN1
308 4, // DXN2UNORM
309 4, // DXN2SNORM
310 4, // BC7U
311 4, // BC6H_UF16
312 4, // BC6H_SF16
313 4, // ASTC_2D_4X4
314 1, // G8R8U
315 1, // G8R8S
316 1, // BGRA8
317 1, // RGBA32F
318 1, // RG32F
319 1, // R32F
320 1, // R16F
321 1, // R16U
322 1, // R16S
323 1, // R16UI
324 1, // R16I
325 1, // RG16
326 1, // RG16F
327 1, // RG16UI
328 1, // RG16I
329 1, // RG16S
330 1, // RGB32F
331 1, // RGBA8_SRGB
332 1, // RG8U
333 1, // RG8S
334 1, // RG32UI
335 1, // R32UI
336 8, // ASTC_2D_8X8
337 5, // ASTC_2D_8X5
338 4, // ASTC_2D_5X4
339 1, // BGRA8_SRGB
340 4, // DXT1_SRGB
341 4, // DXT23_SRGB
342 4, // DXT45_SRGB
343 4, // BC7U_SRGB
344 4, // ASTC_2D_4X4_SRGB
345 8, // ASTC_2D_8X8_SRGB
346 5, // ASTC_2D_8X5_SRGB
347 4, // ASTC_2D_5X4_SRGB
348 5, // ASTC_2D_5X5
349 5, // ASTC_2D_5X5_SRGB
350 8, // ASTC_2D_10X8
351 8, // ASTC_2D_10X8_SRGB
352 1, // Z32F
353 1, // Z16
354 1, // Z24S8
355 1, // S8Z24
356 1, // Z32FS8
357 }};
358
359 ASSERT(static_cast<std::size_t>(format) < block_height_table.size()); 361 ASSERT(static_cast<std::size_t>(format) < block_height_table.size());
360 return block_height_table[static_cast<std::size_t>(format)]; 362 return block_height_table[static_cast<std::size_t>(format)];
361} 363}
362 364
365constexpr std::array<u32, MaxPixelFormat> bpp_table = {{
366 32, // ABGR8U
367 32, // ABGR8S
368 32, // ABGR8UI
369 16, // B5G6R5U
370 32, // A2B10G10R10U
371 16, // A1B5G5R5U
372 8, // R8U
373 8, // R8UI
374 64, // RGBA16F
375 64, // RGBA16U
376 64, // RGBA16UI
377 32, // R11FG11FB10F
378 128, // RGBA32UI
379 64, // DXT1
380 128, // DXT23
381 128, // DXT45
382 64, // DXN1
383 128, // DXN2UNORM
384 128, // DXN2SNORM
385 128, // BC7U
386 128, // BC6H_UF16
387 128, // BC6H_SF16
388 128, // ASTC_2D_4X4
389 16, // G8R8U
390 16, // G8R8S
391 32, // BGRA8
392 128, // RGBA32F
393 64, // RG32F
394 32, // R32F
395 16, // R16F
396 16, // R16U
397 16, // R16S
398 16, // R16UI
399 16, // R16I
400 32, // RG16
401 32, // RG16F
402 32, // RG16UI
403 32, // RG16I
404 32, // RG16S
405 96, // RGB32F
406 32, // RGBA8_SRGB
407 16, // RG8U
408 16, // RG8S
409 64, // RG32UI
410 32, // R32UI
411 128, // ASTC_2D_8X8
412 128, // ASTC_2D_8X5
413 128, // ASTC_2D_5X4
414 32, // BGRA8_SRGB
415 64, // DXT1_SRGB
416 128, // DXT23_SRGB
417 128, // DXT45_SRGB
418 128, // BC7U
419 128, // ASTC_2D_4X4_SRGB
420 128, // ASTC_2D_8X8_SRGB
421 128, // ASTC_2D_8X5_SRGB
422 128, // ASTC_2D_5X4_SRGB
423 128, // ASTC_2D_5X5
424 128, // ASTC_2D_5X5_SRGB
425 128, // ASTC_2D_10X8
426 128, // ASTC_2D_10X8_SRGB
427 32, // Z32F
428 16, // Z16
429 32, // Z24S8
430 32, // S8Z24
431 64, // Z32FS8
432}};
433
363static constexpr u32 GetFormatBpp(PixelFormat format) { 434static constexpr u32 GetFormatBpp(PixelFormat format) {
364 if (format == PixelFormat::Invalid) 435 if (format == PixelFormat::Invalid)
365 return 0; 436 return 0;
366 437
367 constexpr std::array<u32, MaxPixelFormat> bpp_table = {{
368 32, // ABGR8U
369 32, // ABGR8S
370 32, // ABGR8UI
371 16, // B5G6R5U
372 32, // A2B10G10R10U
373 16, // A1B5G5R5U
374 8, // R8U
375 8, // R8UI
376 64, // RGBA16F
377 64, // RGBA16U
378 64, // RGBA16UI
379 32, // R11FG11FB10F
380 128, // RGBA32UI
381 64, // DXT1
382 128, // DXT23
383 128, // DXT45
384 64, // DXN1
385 128, // DXN2UNORM
386 128, // DXN2SNORM
387 128, // BC7U
388 128, // BC6H_UF16
389 128, // BC6H_SF16
390 128, // ASTC_2D_4X4
391 16, // G8R8U
392 16, // G8R8S
393 32, // BGRA8
394 128, // RGBA32F
395 64, // RG32F
396 32, // R32F
397 16, // R16F
398 16, // R16U
399 16, // R16S
400 16, // R16UI
401 16, // R16I
402 32, // RG16
403 32, // RG16F
404 32, // RG16UI
405 32, // RG16I
406 32, // RG16S
407 96, // RGB32F
408 32, // RGBA8_SRGB
409 16, // RG8U
410 16, // RG8S
411 64, // RG32UI
412 32, // R32UI
413 128, // ASTC_2D_8X8
414 128, // ASTC_2D_8X5
415 128, // ASTC_2D_5X4
416 32, // BGRA8_SRGB
417 64, // DXT1_SRGB
418 128, // DXT23_SRGB
419 128, // DXT45_SRGB
420 128, // BC7U
421 128, // ASTC_2D_4X4_SRGB
422 128, // ASTC_2D_8X8_SRGB
423 128, // ASTC_2D_8X5_SRGB
424 128, // ASTC_2D_5X4_SRGB
425 128, // ASTC_2D_5X5
426 128, // ASTC_2D_5X5_SRGB
427 128, // ASTC_2D_10X8
428 128, // ASTC_2D_10X8_SRGB
429 32, // Z32F
430 16, // Z16
431 32, // Z24S8
432 32, // S8Z24
433 64, // Z32FS8
434 }};
435
436 ASSERT(static_cast<std::size_t>(format) < bpp_table.size()); 438 ASSERT(static_cast<std::size_t>(format) < bpp_table.size());
437 return bpp_table[static_cast<std::size_t>(format)]; 439 return bpp_table[static_cast<std::size_t>(format)];
438} 440}
diff --git a/src/yuzu/configuration/configure_audio.h b/src/yuzu/configuration/configure_audio.h
index 207f9dfb3..8771421c0 100644
--- a/src/yuzu/configuration/configure_audio.h
+++ b/src/yuzu/configuration/configure_audio.h
@@ -16,15 +16,14 @@ class ConfigureAudio : public QWidget {
16 16
17public: 17public:
18 explicit ConfigureAudio(QWidget* parent = nullptr); 18 explicit ConfigureAudio(QWidget* parent = nullptr);
19 ~ConfigureAudio(); 19 ~ConfigureAudio() override;
20 20
21 void applyConfiguration(); 21 void applyConfiguration();
22 void retranslateUi(); 22 void retranslateUi();
23 23
24public slots: 24private:
25 void updateAudioDevices(int sink_index); 25 void updateAudioDevices(int sink_index);
26 26
27private:
28 void setConfiguration(); 27 void setConfiguration();
29 void setOutputSinkFromSinkID(); 28 void setOutputSinkFromSinkID();
30 void setAudioDeviceFromDeviceID(); 29 void setAudioDeviceFromDeviceID();
diff --git a/src/yuzu/configuration/configure_debug.h b/src/yuzu/configuration/configure_debug.h
index d167eb996..c6420b18c 100644
--- a/src/yuzu/configuration/configure_debug.h
+++ b/src/yuzu/configuration/configure_debug.h
@@ -16,13 +16,12 @@ class ConfigureDebug : public QWidget {
16 16
17public: 17public:
18 explicit ConfigureDebug(QWidget* parent = nullptr); 18 explicit ConfigureDebug(QWidget* parent = nullptr);
19 ~ConfigureDebug(); 19 ~ConfigureDebug() override;
20 20
21 void applyConfiguration(); 21 void applyConfiguration();
22 22
23private: 23private:
24 void setConfiguration(); 24 void setConfiguration();
25 25
26private:
27 std::unique_ptr<Ui::ConfigureDebug> ui; 26 std::unique_ptr<Ui::ConfigureDebug> ui;
28}; 27};
diff --git a/src/yuzu/configuration/configure_dialog.h b/src/yuzu/configuration/configure_dialog.h
index bbbdacc29..f6df7b827 100644
--- a/src/yuzu/configuration/configure_dialog.h
+++ b/src/yuzu/configuration/configure_dialog.h
@@ -18,13 +18,12 @@ class ConfigureDialog : public QDialog {
18 18
19public: 19public:
20 explicit ConfigureDialog(QWidget* parent, const HotkeyRegistry& registry); 20 explicit ConfigureDialog(QWidget* parent, const HotkeyRegistry& registry);
21 ~ConfigureDialog(); 21 ~ConfigureDialog() override;
22 22
23 void applyConfiguration(); 23 void applyConfiguration();
24 24
25private: 25private:
26 void setConfiguration(); 26 void setConfiguration();
27 27
28private:
29 std::unique_ptr<Ui::ConfigureDialog> ui; 28 std::unique_ptr<Ui::ConfigureDialog> ui;
30}; 29};
diff --git a/src/yuzu/configuration/configure_gamelist.h b/src/yuzu/configuration/configure_gamelist.h
index bbf7e25f1..bf3f1cdfa 100644
--- a/src/yuzu/configuration/configure_gamelist.h
+++ b/src/yuzu/configuration/configure_gamelist.h
@@ -16,7 +16,7 @@ class ConfigureGameList : public QWidget {
16 16
17public: 17public:
18 explicit ConfigureGameList(QWidget* parent = nullptr); 18 explicit ConfigureGameList(QWidget* parent = nullptr);
19 ~ConfigureGameList(); 19 ~ConfigureGameList() override;
20 20
21 void applyConfiguration(); 21 void applyConfiguration();
22 22
diff --git a/src/yuzu/configuration/configure_general.h b/src/yuzu/configuration/configure_general.h
index 4770034cc..59738af40 100644
--- a/src/yuzu/configuration/configure_general.h
+++ b/src/yuzu/configuration/configure_general.h
@@ -18,7 +18,7 @@ class ConfigureGeneral : public QWidget {
18 18
19public: 19public:
20 explicit ConfigureGeneral(QWidget* parent = nullptr); 20 explicit ConfigureGeneral(QWidget* parent = nullptr);
21 ~ConfigureGeneral(); 21 ~ConfigureGeneral() override;
22 22
23 void PopulateHotkeyList(const HotkeyRegistry& registry); 23 void PopulateHotkeyList(const HotkeyRegistry& registry);
24 void applyConfiguration(); 24 void applyConfiguration();
diff --git a/src/yuzu/configuration/configure_graphics.h b/src/yuzu/configuration/configure_graphics.h
index 9bda26fd6..d6ffc6fde 100644
--- a/src/yuzu/configuration/configure_graphics.h
+++ b/src/yuzu/configuration/configure_graphics.h
@@ -16,14 +16,13 @@ class ConfigureGraphics : public QWidget {
16 16
17public: 17public:
18 explicit ConfigureGraphics(QWidget* parent = nullptr); 18 explicit ConfigureGraphics(QWidget* parent = nullptr);
19 ~ConfigureGraphics(); 19 ~ConfigureGraphics() override;
20 20
21 void applyConfiguration(); 21 void applyConfiguration();
22 22
23private: 23private:
24 void setConfiguration(); 24 void setConfiguration();
25 25
26private:
27 std::unique_ptr<Ui::ConfigureGraphics> ui; 26 std::unique_ptr<Ui::ConfigureGraphics> ui;
28 QColor bg_color; 27 QColor bg_color;
29}; 28};
diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp
index e25597b7f..830d26115 100644
--- a/src/yuzu/configuration/configure_input.cpp
+++ b/src/yuzu/configuration/configure_input.cpp
@@ -88,8 +88,10 @@ ConfigureInput::ConfigureInput(QWidget* parent)
88 [this] { CallConfigureDialog<ConfigureTouchscreenAdvanced>(*this); }); 88 [this] { CallConfigureDialog<ConfigureTouchscreenAdvanced>(*this); });
89} 89}
90 90
91ConfigureInput::~ConfigureInput() = default;
92
91void ConfigureInput::OnDockedModeChanged(bool last_state, bool new_state) { 93void ConfigureInput::OnDockedModeChanged(bool last_state, bool new_state) {
92 if (ui->use_docked_mode->isChecked() && ui->handheld_connected->isChecked()){ 94 if (ui->use_docked_mode->isChecked() && ui->handheld_connected->isChecked()) {
93 ui->handheld_connected->setChecked(false); 95 ui->handheld_connected->setChecked(false);
94 } 96 }
95 97
diff --git a/src/yuzu/configuration/configure_input.h b/src/yuzu/configuration/configure_input.h
index e8723dfcb..1649e4c0b 100644
--- a/src/yuzu/configuration/configure_input.h
+++ b/src/yuzu/configuration/configure_input.h
@@ -25,6 +25,7 @@ class ConfigureInput : public QWidget {
25 25
26public: 26public:
27 explicit ConfigureInput(QWidget* parent = nullptr); 27 explicit ConfigureInput(QWidget* parent = nullptr);
28 ~ConfigureInput() override;
28 29
29 /// Save all button configurations to settings file 30 /// Save all button configurations to settings file
30 void applyConfiguration(); 31 void applyConfiguration();
diff --git a/src/yuzu/configuration/configure_web.h b/src/yuzu/configuration/configure_web.h
index 7741ab95d..7752ae4a1 100644
--- a/src/yuzu/configuration/configure_web.h
+++ b/src/yuzu/configuration/configure_web.h
@@ -17,18 +17,17 @@ class ConfigureWeb : public QWidget {
17 17
18public: 18public:
19 explicit ConfigureWeb(QWidget* parent = nullptr); 19 explicit ConfigureWeb(QWidget* parent = nullptr);
20 ~ConfigureWeb(); 20 ~ConfigureWeb() override;
21 21
22 void applyConfiguration(); 22 void applyConfiguration();
23 void retranslateUi(); 23 void retranslateUi();
24 24
25public slots: 25private:
26 void RefreshTelemetryID(); 26 void RefreshTelemetryID();
27 void OnLoginChanged(); 27 void OnLoginChanged();
28 void VerifyLogin(); 28 void VerifyLogin();
29 void OnLoginVerified(); 29 void OnLoginVerified();
30 30
31private:
32 void setConfiguration(); 31 void setConfiguration();
33 32
34 bool user_verified = true; 33 bool user_verified = true;
diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp
index 0c831c9f4..f9c18ede4 100644
--- a/src/yuzu/debugger/wait_tree.cpp
+++ b/src/yuzu/debugger/wait_tree.cpp
@@ -7,10 +7,10 @@
7 7
8#include "common/assert.h" 8#include "common/assert.h"
9#include "core/core.h" 9#include "core/core.h"
10#include "core/hle/kernel/event.h"
11#include "core/hle/kernel/handle_table.h" 10#include "core/hle/kernel/handle_table.h"
12#include "core/hle/kernel/mutex.h" 11#include "core/hle/kernel/mutex.h"
13#include "core/hle/kernel/process.h" 12#include "core/hle/kernel/process.h"
13#include "core/hle/kernel/readable_event.h"
14#include "core/hle/kernel/scheduler.h" 14#include "core/hle/kernel/scheduler.h"
15#include "core/hle/kernel/thread.h" 15#include "core/hle/kernel/thread.h"
16#include "core/hle/kernel/timer.h" 16#include "core/hle/kernel/timer.h"
@@ -153,8 +153,8 @@ QString WaitTreeWaitObject::GetText() const {
153 153
154std::unique_ptr<WaitTreeWaitObject> WaitTreeWaitObject::make(const Kernel::WaitObject& object) { 154std::unique_ptr<WaitTreeWaitObject> WaitTreeWaitObject::make(const Kernel::WaitObject& object) {
155 switch (object.GetHandleType()) { 155 switch (object.GetHandleType()) {
156 case Kernel::HandleType::Event: 156 case Kernel::HandleType::ReadableEvent:
157 return std::make_unique<WaitTreeEvent>(static_cast<const Kernel::Event&>(object)); 157 return std::make_unique<WaitTreeEvent>(static_cast<const Kernel::ReadableEvent&>(object));
158 case Kernel::HandleType::Timer: 158 case Kernel::HandleType::Timer:
159 return std::make_unique<WaitTreeTimer>(static_cast<const Kernel::Timer&>(object)); 159 return std::make_unique<WaitTreeTimer>(static_cast<const Kernel::Timer&>(object));
160 case Kernel::HandleType::Thread: 160 case Kernel::HandleType::Thread:
@@ -332,7 +332,7 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const {
332 return list; 332 return list;
333} 333}
334 334
335WaitTreeEvent::WaitTreeEvent(const Kernel::Event& object) : WaitTreeWaitObject(object) {} 335WaitTreeEvent::WaitTreeEvent(const Kernel::ReadableEvent& object) : WaitTreeWaitObject(object) {}
336WaitTreeEvent::~WaitTreeEvent() = default; 336WaitTreeEvent::~WaitTreeEvent() = default;
337 337
338std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeEvent::GetChildren() const { 338std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeEvent::GetChildren() const {
@@ -340,7 +340,8 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeEvent::GetChildren() const {
340 340
341 list.push_back(std::make_unique<WaitTreeText>( 341 list.push_back(std::make_unique<WaitTreeText>(
342 tr("reset type = %1") 342 tr("reset type = %1")
343 .arg(GetResetTypeQString(static_cast<const Kernel::Event&>(object).GetResetType())))); 343 .arg(GetResetTypeQString(
344 static_cast<const Kernel::ReadableEvent&>(object).GetResetType()))));
344 return list; 345 return list;
345} 346}
346 347
diff --git a/src/yuzu/debugger/wait_tree.h b/src/yuzu/debugger/wait_tree.h
index 331f89885..492fb6ac9 100644
--- a/src/yuzu/debugger/wait_tree.h
+++ b/src/yuzu/debugger/wait_tree.h
@@ -17,8 +17,8 @@
17class EmuThread; 17class EmuThread;
18 18
19namespace Kernel { 19namespace Kernel {
20class ReadableEvent;
20class WaitObject; 21class WaitObject;
21class Event;
22class Thread; 22class Thread;
23class Timer; 23class Timer;
24} // namespace Kernel 24} // namespace Kernel
@@ -144,7 +144,7 @@ public:
144class WaitTreeEvent : public WaitTreeWaitObject { 144class WaitTreeEvent : public WaitTreeWaitObject {
145 Q_OBJECT 145 Q_OBJECT
146public: 146public:
147 explicit WaitTreeEvent(const Kernel::Event& object); 147 explicit WaitTreeEvent(const Kernel::ReadableEvent& object);
148 ~WaitTreeEvent() override; 148 ~WaitTreeEvent() override;
149 149
150 std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override; 150 std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp
index 11a8c390b..b52a50915 100644
--- a/src/yuzu/game_list.cpp
+++ b/src/yuzu/game_list.cpp
@@ -214,6 +214,7 @@ GameList::GameList(FileSys::VirtualFilesystem vfs, GMainWindow* parent)
214 tree_view->setEditTriggers(QHeaderView::NoEditTriggers); 214 tree_view->setEditTriggers(QHeaderView::NoEditTriggers);
215 tree_view->setUniformRowHeights(true); 215 tree_view->setUniformRowHeights(true);
216 tree_view->setContextMenuPolicy(Qt::CustomContextMenu); 216 tree_view->setContextMenuPolicy(Qt::CustomContextMenu);
217 tree_view->setStyleSheet("QTreeView{ border: none; }");
217 218
218 item_model->insertColumns(0, UISettings::values.show_add_ons ? COLUMN_COUNT : COLUMN_COUNT - 1); 219 item_model->insertColumns(0, UISettings::values.show_add_ons ? COLUMN_COUNT : COLUMN_COUNT - 1);
219 item_model->setHeaderData(COLUMN_NAME, Qt::Horizontal, tr("Name")); 220 item_model->setHeaderData(COLUMN_NAME, Qt::Horizontal, tr("Name"));
diff --git a/src/yuzu/game_list_worker.cpp b/src/yuzu/game_list_worker.cpp
index 362902e46..9fd074223 100644
--- a/src/yuzu/game_list_worker.cpp
+++ b/src/yuzu/game_list_worker.cpp
@@ -86,6 +86,35 @@ QString FormatPatchNameVersions(const FileSys::PatchManager& patch_manager,
86 out.chop(1); 86 out.chop(1);
87 return out; 87 return out;
88} 88}
89
90QList<QStandardItem*> MakeGameListEntry(const std::string& path, const std::string& name,
91 const std::vector<u8>& icon, Loader::AppLoader& loader,
92 u64 program_id, const CompatibilityList& compatibility_list,
93 const FileSys::PatchManager& patch) {
94 const auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id);
95
96 // The game list uses this as compatibility number for untested games
97 QString compatibility{"99"};
98 if (it != compatibility_list.end()) {
99 compatibility = it->second.first;
100 }
101
102 QList<QStandardItem*> list{
103 new GameListItemPath(
104 FormatGameName(path), icon, QString::fromStdString(name),
105 QString::fromStdString(Loader::GetFileTypeString(loader.GetFileType())), program_id),
106 new GameListItemCompat(compatibility),
107 new GameListItem(QString::fromStdString(Loader::GetFileTypeString(loader.GetFileType()))),
108 new GameListItemSize(FileUtil::GetSize(path)),
109 };
110
111 if (UISettings::values.show_add_ons) {
112 list.insert(
113 2, new GameListItem(FormatPatchNameVersions(patch, loader, loader.IsRomFSUpdatable())));
114 }
115
116 return list;
117}
89} // Anonymous namespace 118} // Anonymous namespace
90 119
91GameListWorker::GameListWorker(FileSys::VirtualFilesystem vfs, QString dir_path, bool deep_scan, 120GameListWorker::GameListWorker(FileSys::VirtualFilesystem vfs, QString dir_path, bool deep_scan,
@@ -97,11 +126,11 @@ GameListWorker::~GameListWorker() = default;
97 126
98void GameListWorker::AddInstalledTitlesToGameList() { 127void GameListWorker::AddInstalledTitlesToGameList() {
99 const auto cache = Service::FileSystem::GetUnionContents(); 128 const auto cache = Service::FileSystem::GetUnionContents();
100 const auto installed_games = cache->ListEntriesFilter(FileSys::TitleType::Application, 129 const auto installed_games = cache.ListEntriesFilter(FileSys::TitleType::Application,
101 FileSys::ContentRecordType::Program); 130 FileSys::ContentRecordType::Program);
102 131
103 for (const auto& game : installed_games) { 132 for (const auto& game : installed_games) {
104 const auto file = cache->GetEntryUnparsed(game); 133 const auto file = cache.GetEntryUnparsed(game);
105 std::unique_ptr<Loader::AppLoader> loader = Loader::GetLoader(file); 134 std::unique_ptr<Loader::AppLoader> loader = Loader::GetLoader(file);
106 if (!loader) 135 if (!loader)
107 continue; 136 continue;
@@ -112,40 +141,19 @@ void GameListWorker::AddInstalledTitlesToGameList() {
112 loader->ReadProgramId(program_id); 141 loader->ReadProgramId(program_id);
113 142
114 const FileSys::PatchManager patch{program_id}; 143 const FileSys::PatchManager patch{program_id};
115 const auto control = cache->GetEntry(game.title_id, FileSys::ContentRecordType::Control); 144 const auto control = cache.GetEntry(game.title_id, FileSys::ContentRecordType::Control);
116 if (control != nullptr) 145 if (control != nullptr)
117 GetMetadataFromControlNCA(patch, *control, icon, name); 146 GetMetadataFromControlNCA(patch, *control, icon, name);
118 147
119 auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id); 148 emit EntryReady(MakeGameListEntry(file->GetFullPath(), name, icon, *loader, program_id,
120 149 compatibility_list, patch));
121 // The game list uses this as compatibility number for untested games
122 QString compatibility("99");
123 if (it != compatibility_list.end())
124 compatibility = it->second.first;
125
126 QList<QStandardItem*> list{
127 new GameListItemPath(
128 FormatGameName(file->GetFullPath()), icon, QString::fromStdString(name),
129 QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType())),
130 program_id),
131 new GameListItemCompat(compatibility),
132 new GameListItem(
133 QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType()))),
134 new GameListItemSize(file->GetSize()),
135 };
136
137 if (UISettings::values.show_add_ons) {
138 list.insert(2, new GameListItem(FormatPatchNameVersions(patch, *loader)));
139 }
140
141 emit EntryReady(list);
142 } 150 }
143 151
144 const auto control_data = cache->ListEntriesFilter(FileSys::TitleType::Application, 152 const auto control_data = cache.ListEntriesFilter(FileSys::TitleType::Application,
145 FileSys::ContentRecordType::Control); 153 FileSys::ContentRecordType::Control);
146 154
147 for (const auto& entry : control_data) { 155 for (const auto& entry : control_data) {
148 auto nca = cache->GetEntry(entry); 156 auto nca = cache.GetEntry(entry);
149 if (nca != nullptr) { 157 if (nca != nullptr) {
150 nca_control_map.insert_or_assign(entry.title_id, std::move(nca)); 158 nca_control_map.insert_or_assign(entry.title_id, std::move(nca));
151 } 159 }
@@ -155,14 +163,14 @@ void GameListWorker::AddInstalledTitlesToGameList() {
155void GameListWorker::FillControlMap(const std::string& dir_path) { 163void GameListWorker::FillControlMap(const std::string& dir_path) {
156 const auto nca_control_callback = [this](u64* num_entries_out, const std::string& directory, 164 const auto nca_control_callback = [this](u64* num_entries_out, const std::string& directory,
157 const std::string& virtual_name) -> bool { 165 const std::string& virtual_name) -> bool {
158 std::string physical_name = directory + DIR_SEP + virtual_name; 166 if (stop_processing) {
159 167 // Breaks the callback loop
160 if (stop_processing) 168 return false;
161 return false; // Breaks the callback loop. 169 }
162 170
163 bool is_dir = FileUtil::IsDirectory(physical_name); 171 const std::string physical_name = directory + DIR_SEP + virtual_name;
164 QFileInfo file_info(physical_name.c_str()); 172 const QFileInfo file_info(QString::fromStdString(physical_name));
165 if (!is_dir && file_info.suffix().toStdString() == "nca") { 173 if (!file_info.isDir() && file_info.suffix() == QStringLiteral("nca")) {
166 auto nca = 174 auto nca =
167 std::make_unique<FileSys::NCA>(vfs->OpenFile(physical_name, FileSys::Mode::Read)); 175 std::make_unique<FileSys::NCA>(vfs->OpenFile(physical_name, FileSys::Mode::Read));
168 if (nca->GetType() == FileSys::NCAContentType::Control) { 176 if (nca->GetType() == FileSys::NCAContentType::Control) {
@@ -179,12 +187,13 @@ void GameListWorker::FillControlMap(const std::string& dir_path) {
179void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsigned int recursion) { 187void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsigned int recursion) {
180 const auto callback = [this, recursion](u64* num_entries_out, const std::string& directory, 188 const auto callback = [this, recursion](u64* num_entries_out, const std::string& directory,
181 const std::string& virtual_name) -> bool { 189 const std::string& virtual_name) -> bool {
182 std::string physical_name = directory + DIR_SEP + virtual_name; 190 if (stop_processing) {
183 191 // Breaks the callback loop.
184 if (stop_processing) 192 return false;
185 return false; // Breaks the callback loop. 193 }
186 194
187 bool is_dir = FileUtil::IsDirectory(physical_name); 195 const std::string physical_name = directory + DIR_SEP + virtual_name;
196 const bool is_dir = FileUtil::IsDirectory(physical_name);
188 if (!is_dir && 197 if (!is_dir &&
189 (HasSupportedFileExtension(physical_name) || IsExtractedNCAMain(physical_name))) { 198 (HasSupportedFileExtension(physical_name) || IsExtractedNCAMain(physical_name))) {
190 std::unique_ptr<Loader::AppLoader> loader = 199 std::unique_ptr<Loader::AppLoader> loader =
@@ -214,30 +223,8 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign
214 } 223 }
215 } 224 }
216 225
217 auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id); 226 emit EntryReady(MakeGameListEntry(physical_name, name, icon, *loader, program_id,
218 227 compatibility_list, patch));
219 // The game list uses this as compatibility number for untested games
220 QString compatibility("99");
221 if (it != compatibility_list.end())
222 compatibility = it->second.first;
223
224 QList<QStandardItem*> list{
225 new GameListItemPath(
226 FormatGameName(physical_name), icon, QString::fromStdString(name),
227 QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType())),
228 program_id),
229 new GameListItemCompat(compatibility),
230 new GameListItem(
231 QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType()))),
232 new GameListItemSize(FileUtil::GetSize(physical_name)),
233 };
234
235 if (UISettings::values.show_add_ons) {
236 list.insert(2, new GameListItem(FormatPatchNameVersions(
237 patch, *loader, loader->IsRomFSUpdatable())));
238 }
239
240 emit EntryReady(std::move(list));
241 } else if (is_dir && recursion > 0) { 228 } else if (is_dir && recursion > 0) {
242 watch_list.append(QString::fromStdString(physical_name)); 229 watch_list.append(QString::fromStdString(physical_name));
243 AddFstEntriesToGameList(physical_name, recursion - 1); 230 AddFstEntriesToGameList(physical_name, recursion - 1);
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 93bf117c8..22c207a3a 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -518,6 +518,8 @@ void GMainWindow::OnDisplayTitleBars(bool show) {
518QStringList GMainWindow::GetUnsupportedGLExtensions() { 518QStringList GMainWindow::GetUnsupportedGLExtensions() {
519 QStringList unsupported_ext; 519 QStringList unsupported_ext;
520 520
521 if (!GLAD_GL_ARB_direct_state_access)
522 unsupported_ext.append("ARB_direct_state_access");
521 if (!GLAD_GL_ARB_vertex_type_10f_11f_11f_rev) 523 if (!GLAD_GL_ARB_vertex_type_10f_11f_11f_rev)
522 unsupported_ext.append("ARB_vertex_type_10f_11f_11f_rev"); 524 unsupported_ext.append("ARB_vertex_type_10f_11f_11f_rev");
523 if (!GLAD_GL_ARB_texture_mirror_clamp_to_edge) 525 if (!GLAD_GL_ARB_texture_mirror_clamp_to_edge)
@@ -905,7 +907,7 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa
905 } 907 }
906 908
907 const auto installed = Service::FileSystem::GetUnionContents(); 909 const auto installed = Service::FileSystem::GetUnionContents();
908 auto romfs_title_id = SelectRomFSDumpTarget(*installed, program_id); 910 const auto romfs_title_id = SelectRomFSDumpTarget(installed, program_id);
909 911
910 if (!romfs_title_id) { 912 if (!romfs_title_id) {
911 failed(); 913 failed();
@@ -920,7 +922,7 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa
920 if (*romfs_title_id == program_id) { 922 if (*romfs_title_id == program_id) {
921 romfs = file; 923 romfs = file;
922 } else { 924 } else {
923 romfs = installed->GetEntry(*romfs_title_id, FileSys::ContentRecordType::Data)->GetRomFS(); 925 romfs = installed.GetEntry(*romfs_title_id, FileSys::ContentRecordType::Data)->GetRomFS();
924 } 926 }
925 927
926 const auto extracted = FileSys::ExtractRomFS(romfs, FileSys::RomFSExtractionType::Full); 928 const auto extracted = FileSys::ExtractRomFS(romfs, FileSys::RomFSExtractionType::Full);
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
index 2d6f8cced..a557f2884 100644
--- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
+++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp
@@ -111,6 +111,8 @@ void EmuWindow_SDL2::Fullscreen() {
111bool EmuWindow_SDL2::SupportsRequiredGLExtensions() { 111bool EmuWindow_SDL2::SupportsRequiredGLExtensions() {
112 std::vector<std::string> unsupported_ext; 112 std::vector<std::string> unsupported_ext;
113 113
114 if (!GLAD_GL_ARB_direct_state_access)
115 unsupported_ext.push_back("ARB_direct_state_access");
114 if (!GLAD_GL_ARB_vertex_type_10f_11f_11f_rev) 116 if (!GLAD_GL_ARB_vertex_type_10f_11f_11f_rev)
115 unsupported_ext.push_back("ARB_vertex_type_10f_11f_11f_rev"); 117 unsupported_ext.push_back("ARB_vertex_type_10f_11f_11f_rev");
116 if (!GLAD_GL_ARB_texture_mirror_clamp_to_edge) 118 if (!GLAD_GL_ARB_texture_mirror_clamp_to_edge)