summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/audio_core/audio_renderer.cpp4
-rw-r--r--src/audio_core/audio_renderer.h7
-rw-r--r--src/core/CMakeLists.txt6
-rw-r--r--src/core/crypto/key_manager.cpp2
-rw-r--r--src/core/file_sys/patch_manager.cpp19
-rw-r--r--src/core/file_sys/romfs_factory.cpp2
-rw-r--r--src/core/file_sys/vfs.cpp46
-rw-r--r--src/core/file_sys/vfs.h20
-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.cpp249
-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.cpp12
-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/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/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/video_core/command_processor.cpp142
-rw-r--r--src/video_core/engines/maxwell_3d.h1
-rw-r--r--src/video_core/gpu.cpp6
-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.cpp699
-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/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.cpp2
-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.cpp14
-rw-r--r--src/yuzu/main.cpp6
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.cpp2
80 files changed, 1153 insertions, 1147 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..73aec8ab0 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -97,8 +97,6 @@ add_library(core STATIC
97 hle/kernel/client_session.cpp 97 hle/kernel/client_session.cpp
98 hle/kernel/client_session.h 98 hle/kernel/client_session.h
99 hle/kernel/errors.h 99 hle/kernel/errors.h
100 hle/kernel/event.cpp
101 hle/kernel/event.h
102 hle/kernel/handle_table.cpp 100 hle/kernel/handle_table.cpp
103 hle/kernel/handle_table.h 101 hle/kernel/handle_table.h
104 hle/kernel/hle_ipc.cpp 102 hle/kernel/hle_ipc.cpp
@@ -111,6 +109,8 @@ add_library(core STATIC
111 hle/kernel/object.h 109 hle/kernel/object.h
112 hle/kernel/process.cpp 110 hle/kernel/process.cpp
113 hle/kernel/process.h 111 hle/kernel/process.h
112 hle/kernel/readable_event.cpp
113 hle/kernel/readable_event.h
114 hle/kernel/resource_limit.cpp 114 hle/kernel/resource_limit.cpp
115 hle/kernel/resource_limit.h 115 hle/kernel/resource_limit.h
116 hle/kernel/scheduler.cpp 116 hle/kernel/scheduler.cpp
@@ -133,6 +133,8 @@ add_library(core STATIC
133 hle/kernel/vm_manager.h 133 hle/kernel/vm_manager.h
134 hle/kernel/wait_object.cpp 134 hle/kernel/wait_object.cpp
135 hle/kernel/wait_object.h 135 hle/kernel/wait_object.h
136 hle/kernel/writable_event.cpp
137 hle/kernel/writable_event.h
136 hle/lock.cpp 138 hle/lock.cpp
137 hle/lock.h 139 hle/lock.h
138 hle/result.h 140 hle/result.h
diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp
index 291624cbe..ca12fb4ab 100644
--- a/src/core/crypto/key_manager.cpp
+++ b/src/core/crypto/key_manager.cpp
@@ -793,7 +793,7 @@ void KeyManager::DeriveBase() {
793 793
794void KeyManager::DeriveETicket(PartitionDataManager& data) { 794void KeyManager::DeriveETicket(PartitionDataManager& data) {
795 // ETicket keys 795 // ETicket keys
796 const auto es = Service::FileSystem::GetUnionContents()->GetEntry( 796 const auto es = Service::FileSystem::GetUnionContents().GetEntry(
797 0x0100000000000033, FileSys::ContentRecordType::Program); 797 0x0100000000000033, FileSys::ContentRecordType::Program);
798 798
799 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/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/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/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 3339777c1..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,7 +1119,7 @@ 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, arg, stack_top, priority, processor_id, *out_handle); 1124 entry_point, arg, stack_top, priority, processor_id, *out_handle);
1048 1125
@@ -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..694ec40ec 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -291,7 +291,7 @@ public:
291 {10, &IFileSystem::Commit, "Commit"}, 291 {10, &IFileSystem::Commit, "Commit"},
292 {11, nullptr, "GetFreeSpaceSize"}, 292 {11, nullptr, "GetFreeSpaceSize"},
293 {12, nullptr, "GetTotalSpaceSize"}, 293 {12, nullptr, "GetTotalSpaceSize"},
294 {13, nullptr, "CleanDirectoryRecursively"}, 294 {13, &IFileSystem::CleanDirectoryRecursively, "CleanDirectoryRecursively"},
295 {14, nullptr, "GetFileTimeStampRaw"}, 295 {14, nullptr, "GetFileTimeStampRaw"},
296 {15, nullptr, "QueryEntry"}, 296 {15, nullptr, "QueryEntry"},
297 }; 297 };
@@ -361,6 +361,16 @@ public:
361 rb.Push(backend.DeleteDirectoryRecursively(name)); 361 rb.Push(backend.DeleteDirectoryRecursively(name));
362 } 362 }
363 363
364 void CleanDirectoryRecursively(Kernel::HLERequestContext& ctx) {
365 const auto file_buffer = ctx.ReadBuffer();
366 const std::string name = Common::StringFromBuffer(file_buffer);
367
368 LOG_DEBUG(Service_FS, "called. Directory: {}", name);
369
370 IPC::ResponseBuilder rb{ctx, 2};
371 rb.Push(backend.CleanDirectoryRecursively(name));
372 }
373
364 void RenameFile(Kernel::HLERequestContext& ctx) { 374 void RenameFile(Kernel::HLERequestContext& ctx) {
365 IPC::RequestParser rp{ctx}; 375 IPC::RequestParser rp{ctx};
366 376
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/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/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/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/gpu.cpp b/src/video_core/gpu.cpp
index fd1242333..88c45a423 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -141,6 +141,12 @@ void GPU::CallMethod(const MethodCall& method_call) {
141 return; 141 return;
142 } 142 }
143 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
144 const EngineID engine = bound_engines[method_call.subchannel]; 150 const EngineID engine = bound_engines[method_call.subchannel];
145 151
146 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 a44bbfae8..9e93bd609 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -88,19 +88,6 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo
88 state.texture_units[i].sampler = texture_samplers[i].sampler.handle; 88 state.texture_units[i].sampler = texture_samplers[i].sampler.handle;
89 } 89 }
90 90
91 GLint ext_num;
92 glGetIntegerv(GL_NUM_EXTENSIONS, &ext_num);
93 for (GLint i = 0; i < ext_num; i++) {
94 const std::string_view extension{
95 reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, i))};
96
97 if (extension == "GL_ARB_direct_state_access") {
98 has_ARB_direct_state_access = true;
99 } else if (extension == "GL_ARB_multi_bind") {
100 has_ARB_multi_bind = true;
101 }
102 }
103
104 OpenGLState::ApplyDefaultState(); 91 OpenGLState::ApplyDefaultState();
105 92
106 // Create render framebuffer 93 // Create render framebuffer
@@ -295,6 +282,7 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
295 // shaders. The constbuffer bindpoint starts after the shader stage configuration bind points. 282 // shaders. The constbuffer bindpoint starts after the shader stage configuration bind points.
296 u32 current_constbuffer_bindpoint = Tegra::Engines::Maxwell3D::Regs::MaxShaderStage; 283 u32 current_constbuffer_bindpoint = Tegra::Engines::Maxwell3D::Regs::MaxShaderStage;
297 u32 current_texture_bindpoint = 0; 284 u32 current_texture_bindpoint = 0;
285 std::array<bool, Maxwell::NumClipDistances> clip_distances{};
298 286
299 for (std::size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) { 287 for (std::size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) {
300 const auto& shader_config = gpu.regs.shader_config[index]; 288 const auto& shader_config = gpu.regs.shader_config[index];
@@ -355,12 +343,22 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
355 current_texture_bindpoint = SetupTextures(static_cast<Maxwell::ShaderStage>(stage), shader, 343 current_texture_bindpoint = SetupTextures(static_cast<Maxwell::ShaderStage>(stage), shader,
356 primitive_mode, current_texture_bindpoint); 344 primitive_mode, current_texture_bindpoint);
357 345
346 // Workaround for Intel drivers.
347 // When a clip distance is enabled but not set in the shader it crops parts of the screen
348 // (sometimes it's half the screen, sometimes three quarters). To avoid this, enable the
349 // clip distances only when it's written by a shader stage.
350 for (std::size_t i = 0; i < Maxwell::NumClipDistances; ++i) {
351 clip_distances[i] |= shader->GetShaderEntries().clip_distances[i];
352 }
353
358 // When VertexA is enabled, we have dual vertex shaders 354 // When VertexA is enabled, we have dual vertex shaders
359 if (program == Maxwell::ShaderProgram::VertexA) { 355 if (program == Maxwell::ShaderProgram::VertexA) {
360 // VertexB was combined with VertexA, so we skip the VertexB iteration 356 // VertexB was combined with VertexA, so we skip the VertexB iteration
361 index++; 357 index++;
362 } 358 }
363 } 359 }
360
361 SyncClipEnabled(clip_distances);
364} 362}
365 363
366std::size_t RasterizerOpenGL::CalculateVertexArraysSize() const { 364std::size_t RasterizerOpenGL::CalculateVertexArraysSize() const {
@@ -443,7 +441,7 @@ void RasterizerOpenGL::ConfigureFramebuffers(OpenGLState& current_state, bool us
443 // TODO(bunnei): Figure out how the below register works. According to envytools, this should be 441 // TODO(bunnei): Figure out how the below register works. According to envytools, this should be
444 // used to enable multiple render targets. However, it is left unset on all games that I have 442 // used to enable multiple render targets. However, it is left unset on all games that I have
445 // tested. 443 // tested.
446 ASSERT_MSG(regs.rt_separate_frag_data == 0, "Unimplemented"); 444 UNIMPLEMENTED_IF(regs.rt_separate_frag_data != 0);
447 445
448 // Bind the framebuffer surfaces 446 // Bind the framebuffer surfaces
449 current_state.draw.draw_framebuffer = framebuffer.handle; 447 current_state.draw.draw_framebuffer = framebuffer.handle;
@@ -642,7 +640,6 @@ void RasterizerOpenGL::DrawArrays() {
642 SyncCullMode(); 640 SyncCullMode();
643 SyncPrimitiveRestart(); 641 SyncPrimitiveRestart();
644 SyncScissorTest(state); 642 SyncScissorTest(state);
645 SyncClipEnabled();
646 // Alpha Testing is synced on shaders. 643 // Alpha Testing is synced on shaders.
647 SyncTransformFeedback(); 644 SyncTransformFeedback();
648 SyncPointState(); 645 SyncPointState();
@@ -1019,20 +1016,23 @@ void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) {
1019 state.depth_clamp.near_plane = regs.view_volume_clip_control.depth_clamp_near != 0; 1016 state.depth_clamp.near_plane = regs.view_volume_clip_control.depth_clamp_near != 0;
1020} 1017}
1021 1018
1022void RasterizerOpenGL::SyncClipEnabled() { 1019void RasterizerOpenGL::SyncClipEnabled(
1020 const std::array<bool, Maxwell::Regs::NumClipDistances>& clip_mask) {
1021
1023 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; 1022 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
1024 state.clip_distance[0] = regs.clip_distance_enabled.c0 != 0; 1023 const std::array<bool, Maxwell::Regs::NumClipDistances> reg_state{
1025 state.clip_distance[1] = regs.clip_distance_enabled.c1 != 0; 1024 regs.clip_distance_enabled.c0 != 0, regs.clip_distance_enabled.c1 != 0,
1026 state.clip_distance[2] = regs.clip_distance_enabled.c2 != 0; 1025 regs.clip_distance_enabled.c2 != 0, regs.clip_distance_enabled.c3 != 0,
1027 state.clip_distance[3] = regs.clip_distance_enabled.c3 != 0; 1026 regs.clip_distance_enabled.c4 != 0, regs.clip_distance_enabled.c5 != 0,
1028 state.clip_distance[4] = regs.clip_distance_enabled.c4 != 0; 1027 regs.clip_distance_enabled.c6 != 0, regs.clip_distance_enabled.c7 != 0};
1029 state.clip_distance[5] = regs.clip_distance_enabled.c5 != 0; 1028
1030 state.clip_distance[6] = regs.clip_distance_enabled.c6 != 0; 1029 for (std::size_t i = 0; i < Maxwell::Regs::NumClipDistances; ++i) {
1031 state.clip_distance[7] = regs.clip_distance_enabled.c7 != 0; 1030 state.clip_distance[i] = reg_state[i] && clip_mask[i];
1031 }
1032} 1032}
1033 1033
1034void RasterizerOpenGL::SyncClipCoef() { 1034void RasterizerOpenGL::SyncClipCoef() {
1035 UNREACHABLE(); 1035 UNIMPLEMENTED();
1036} 1036}
1037 1037
1038void RasterizerOpenGL::SyncCullMode() { 1038void RasterizerOpenGL::SyncCullMode() {
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 7ec9746b1..988fa3e27 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -60,20 +60,6 @@ public:
60 bool AccelerateDrawBatch(bool is_indexed) override; 60 bool AccelerateDrawBatch(bool is_indexed) override;
61 void UpdatePagesCachedCount(Tegra::GPUVAddr addr, u64 size, int delta) override; 61 void UpdatePagesCachedCount(Tegra::GPUVAddr addr, u64 size, int delta) override;
62 62
63 /// OpenGL shader generated for a given Maxwell register state
64 struct MaxwellShader {
65 /// OpenGL shader resource
66 OGLProgram shader;
67 };
68
69 struct VertexShader {
70 OGLShader shader;
71 };
72
73 struct FragmentShader {
74 OGLShader shader;
75 };
76
77 /// Maximum supported size that a constbuffer can have in bytes. 63 /// Maximum supported size that a constbuffer can have in bytes.
78 static constexpr std::size_t MaxConstbufferSize = 0x10000; 64 static constexpr std::size_t MaxConstbufferSize = 0x10000;
79 static_assert(MaxConstbufferSize % sizeof(GLvec4) == 0, 65 static_assert(MaxConstbufferSize % sizeof(GLvec4) == 0,
@@ -142,7 +128,8 @@ private:
142 void SyncViewport(OpenGLState& current_state); 128 void SyncViewport(OpenGLState& current_state);
143 129
144 /// Syncs the clip enabled status to match the guest state 130 /// Syncs the clip enabled status to match the guest state
145 void SyncClipEnabled(); 131 void SyncClipEnabled(
132 const std::array<bool, Tegra::Engines::Maxwell3D::Regs::NumClipDistances>& clip_mask);
146 133
147 /// Syncs the clip coefficients to match the guest state 134 /// Syncs the clip coefficients to match the guest state
148 void SyncClipCoef(); 135 void SyncClipCoef();
@@ -193,9 +180,6 @@ private:
193 /// but are needed for correct emulation 180 /// but are needed for correct emulation
194 void CheckExtensions(); 181 void CheckExtensions();
195 182
196 bool has_ARB_direct_state_access = false;
197 bool has_ARB_multi_bind = false;
198
199 OpenGLState state; 183 OpenGLState state;
200 184
201 RasterizerCacheOpenGL res_cache; 185 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..8d68156bf 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -201,14 +201,53 @@ private:
201 } 201 }
202}; 202};
203 203
204template <typename T>
205class ShaderScopedScope {
206public:
207 explicit ShaderScopedScope(T& writer, std::string_view begin_expr, std::string end_expr)
208 : writer(writer), end_expr(std::move(end_expr)) {
209
210 if (begin_expr.empty()) {
211 writer.AddLine('{');
212 } else {
213 writer.AddExpression(begin_expr);
214 writer.AddLine(" {");
215 }
216 ++writer.scope;
217 }
218
219 ShaderScopedScope(const ShaderScopedScope&) = delete;
220
221 ~ShaderScopedScope() {
222 --writer.scope;
223 if (end_expr.empty()) {
224 writer.AddLine('}');
225 } else {
226 writer.AddExpression("} ");
227 writer.AddExpression(end_expr);
228 writer.AddLine(';');
229 }
230 }
231
232 ShaderScopedScope& operator=(const ShaderScopedScope&) = delete;
233
234private:
235 T& writer;
236 std::string end_expr;
237};
238
204class ShaderWriter { 239class ShaderWriter {
205public: 240public:
206 void AddLine(std::string_view text) { 241 void AddExpression(std::string_view text) {
207 DEBUG_ASSERT(scope >= 0); 242 DEBUG_ASSERT(scope >= 0);
208 if (!text.empty()) { 243 if (!text.empty()) {
209 AppendIndentation(); 244 AppendIndentation();
210 } 245 }
211 shader_source += text; 246 shader_source += text;
247 }
248
249 void AddLine(std::string_view text) {
250 AddExpression(text);
212 AddNewLine(); 251 AddNewLine();
213 } 252 }
214 253
@@ -228,6 +267,11 @@ public:
228 return std::move(shader_source); 267 return std::move(shader_source);
229 } 268 }
230 269
270 ShaderScopedScope<ShaderWriter> Scope(std::string_view begin_expr = {},
271 std::string end_expr = {}) {
272 return ShaderScopedScope(*this, begin_expr, end_expr);
273 }
274
231 int scope = 0; 275 int scope = 0;
232 276
233private: 277private:
@@ -311,7 +355,7 @@ public:
311 // Default - do nothing 355 // Default - do nothing
312 return value; 356 return value;
313 default: 357 default:
314 UNIMPLEMENTED_MSG("Unimplemented conversion size: {}", static_cast<u32>(size)); 358 UNREACHABLE_MSG("Unimplemented conversion size: {}", static_cast<u32>(size));
315 } 359 }
316 } 360 }
317 361
@@ -525,6 +569,7 @@ public:
525 ((header.vtg.clip_distances >> index) & 1) == 0, 569 ((header.vtg.clip_distances >> index) & 1) == 0,
526 "Shader is setting gl_ClipDistance{} without enabling it in the header", index); 570 "Shader is setting gl_ClipDistance{} without enabling it in the header", index);
527 571
572 clip_distances[index] = true;
528 fixed_pipeline_output_attributes_used.insert(attribute); 573 fixed_pipeline_output_attributes_used.insert(attribute);
529 shader.AddLine(dest + '[' + std::to_string(index) + "] = " + src + ';'); 574 shader.AddLine(dest + '[' + std::to_string(index) + "] = " + src + ';');
530 break; 575 break;
@@ -602,6 +647,11 @@ public:
602 return used_samplers; 647 return used_samplers;
603 } 648 }
604 649
650 /// Returns an array of the used clip distances.
651 const std::array<bool, Maxwell::NumClipDistances>& GetClipDistances() const {
652 return clip_distances;
653 }
654
605 /// Returns the GLSL sampler used for the input shader sampler, and creates a new one if 655 /// Returns the GLSL sampler used for the input shader sampler, and creates a new one if
606 /// necessary. 656 /// necessary.
607 std::string AccessSampler(const Sampler& sampler, Tegra::Shader::TextureType type, 657 std::string AccessSampler(const Sampler& sampler, Tegra::Shader::TextureType type,
@@ -810,14 +860,12 @@ private:
810 } 860 }
811 861
812 if (precise && stage != Maxwell3D::Regs::ShaderStage::Fragment) { 862 if (precise && stage != Maxwell3D::Regs::ShaderStage::Fragment) {
813 shader.AddLine('{'); 863 const auto scope = shader.Scope();
814 ++shader.scope; 864
815 // This avoids optimizations of constant propagation and keeps the code as the original 865 // 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. 866 // Sadly using the precise keyword causes "linking" errors on fragment shaders.
817 shader.AddLine("precise float tmp = " + src + ';'); 867 shader.AddLine("precise float tmp = " + src + ';');
818 shader.AddLine(dest + " = tmp;"); 868 shader.AddLine(dest + " = tmp;");
819 --shader.scope;
820 shader.AddLine('}');
821 } else { 869 } else {
822 shader.AddLine(dest + " = " + src + ';'); 870 shader.AddLine(dest + " = " + src + ';');
823 } 871 }
@@ -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 WriteTexsInstruction(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,17 @@ 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;
1328 shader.AddLine('}');
1329 } 1369 }
1330 1370
1331 static u32 TextureCoordinates(Tegra::Shader::TextureType texture_type) { 1371 static u32 TextureCoordinates(Tegra::Shader::TextureType texture_type) {
@@ -1348,12 +1388,10 @@ private:
1348 * top. 1388 * top.
1349 */ 1389 */
1350 void EmitPushToFlowStack(u32 target) { 1390 void EmitPushToFlowStack(u32 target) {
1351 shader.AddLine('{'); 1391 const auto scope = shader.Scope();
1352 ++shader.scope; 1392
1353 shader.AddLine("flow_stack[flow_stack_top] = " + std::to_string(target) + "u;"); 1393 shader.AddLine("flow_stack[flow_stack_top] = " + std::to_string(target) + "u;");
1354 shader.AddLine("flow_stack_top++;"); 1394 shader.AddLine("flow_stack_top++;");
1355 --shader.scope;
1356 shader.AddLine('}');
1357 } 1395 }
1358 1396
1359 /* 1397 /*
@@ -1361,13 +1399,11 @@ private:
1361 * popped address and decrementing the stack top. 1399 * popped address and decrementing the stack top.
1362 */ 1400 */
1363 void EmitPopFromFlowStack() { 1401 void EmitPopFromFlowStack() {
1364 shader.AddLine('{'); 1402 const auto scope = shader.Scope();
1365 ++shader.scope; 1403
1366 shader.AddLine("flow_stack_top--;"); 1404 shader.AddLine("flow_stack_top--;");
1367 shader.AddLine("jmp_to = flow_stack[flow_stack_top];"); 1405 shader.AddLine("jmp_to = flow_stack[flow_stack_top];");
1368 shader.AddLine("break;"); 1406 shader.AddLine("break;");
1369 --shader.scope;
1370 shader.AddLine('}');
1371 } 1407 }
1372 1408
1373 /// Writes the output values from a fragment shader to the corresponding GLSL output variables. 1409 /// Writes the output values from a fragment shader to the corresponding GLSL output variables.
@@ -1479,6 +1515,161 @@ private:
1479 } 1515 }
1480 } 1516 }
1481 1517
1518 std::pair<size_t, std::string> ValidateAndGetCoordinateElement(
1519 const Tegra::Shader::TextureType texture_type, const bool depth_compare,
1520 const bool is_array, const bool lod_bias_enabled, size_t max_coords, size_t max_inputs) {
1521 const size_t coord_count = TextureCoordinates(texture_type);
1522
1523 size_t total_coord_count = coord_count + (is_array ? 1 : 0) + (depth_compare ? 1 : 0);
1524 const size_t total_reg_count = total_coord_count + (lod_bias_enabled ? 1 : 0);
1525 if (total_coord_count > max_coords || total_reg_count > max_inputs) {
1526 UNIMPLEMENTED_MSG("Unsupported Texture operation");
1527 total_coord_count = std::min(total_coord_count, max_coords);
1528 }
1529 // 1D.DC opengl is using a vec3 but 2nd component is ignored later.
1530 total_coord_count +=
1531 (depth_compare && !is_array && texture_type == Tegra::Shader::TextureType::Texture1D)
1532 ? 1
1533 : 0;
1534
1535 constexpr std::array<const char*, 5> coord_container{
1536 {"", "float coord = (", "vec2 coord = vec2(", "vec3 coord = vec3(",
1537 "vec4 coord = vec4("}};
1538
1539 return std::pair<size_t, std::string>(coord_count, coord_container[total_coord_count]);
1540 }
1541
1542 std::string GetTextureCode(const Tegra::Shader::Instruction& instr,
1543 const Tegra::Shader::TextureType texture_type,
1544 const Tegra::Shader::TextureProcessMode process_mode,
1545 const bool depth_compare, const bool is_array,
1546 const size_t bias_offset) {
1547
1548 if ((texture_type == Tegra::Shader::TextureType::Texture3D &&
1549 (is_array || depth_compare)) ||
1550 (texture_type == Tegra::Shader::TextureType::TextureCube && is_array &&
1551 depth_compare)) {
1552 UNIMPLEMENTED_MSG("This method is not supported.");
1553 }
1554
1555 const std::string sampler =
1556 GetSampler(instr.sampler, texture_type, is_array, depth_compare);
1557
1558 const bool lod_needed = process_mode == Tegra::Shader::TextureProcessMode::LZ ||
1559 process_mode == Tegra::Shader::TextureProcessMode::LL ||
1560 process_mode == Tegra::Shader::TextureProcessMode::LLA;
1561
1562 const bool gl_lod_supported = !(
1563 (texture_type == Tegra::Shader::TextureType::Texture2D && is_array && depth_compare) ||
1564 (texture_type == Tegra::Shader::TextureType::TextureCube && !is_array &&
1565 depth_compare));
1566
1567 const std::string read_method = lod_needed && gl_lod_supported ? "textureLod(" : "texture(";
1568 std::string texture = read_method + sampler + ", coord";
1569
1570 if (process_mode != Tegra::Shader::TextureProcessMode::None) {
1571 if (process_mode == Tegra::Shader::TextureProcessMode::LZ) {
1572 if (gl_lod_supported) {
1573 texture += ", 0";
1574 } else {
1575 // Lod 0 is emulated by a big negative bias
1576 // in scenarios that are not supported by glsl
1577 texture += ", -1000";
1578 }
1579 } else {
1580 // If present, lod or bias are always stored in the register indexed by the
1581 // gpr20
1582 // field with an offset depending on the usage of the other registers
1583 texture += ',' + regs.GetRegisterAsFloat(instr.gpr20.Value() + bias_offset);
1584 }
1585 }
1586 texture += ")";
1587 return texture;
1588 }
1589
1590 std::pair<std::string, std::string> GetTEXCode(
1591 const Instruction& instr, const Tegra::Shader::TextureType texture_type,
1592 const Tegra::Shader::TextureProcessMode process_mode, const bool depth_compare,
1593 const bool is_array) {
1594 const bool lod_bias_enabled = (process_mode != Tegra::Shader::TextureProcessMode::None &&
1595 process_mode != Tegra::Shader::TextureProcessMode::LZ);
1596
1597 const auto [coord_count, coord_dcl] = ValidateAndGetCoordinateElement(
1598 texture_type, depth_compare, is_array, lod_bias_enabled, 4, 5);
1599 // If enabled arrays index is always stored in the gpr8 field
1600 const u64 array_register = instr.gpr8.Value();
1601 // First coordinate index is the gpr8 or gpr8 + 1 when arrays are used
1602 const u64 coord_register = array_register + (is_array ? 1 : 0);
1603
1604 std::string coord = coord_dcl;
1605 for (size_t i = 0; i < coord_count;) {
1606 coord += regs.GetRegisterAsFloat(coord_register + i);
1607 ++i;
1608 if (i != coord_count) {
1609 coord += ',';
1610 }
1611 }
1612 // 1D.DC in opengl the 2nd component is ignored.
1613 if (depth_compare && !is_array && texture_type == Tegra::Shader::TextureType::Texture1D) {
1614 coord += ",0.0";
1615 }
1616 if (depth_compare) {
1617 // Depth is always stored in the register signaled by gpr20
1618 // or in the next register if lod or bias are used
1619 const u64 depth_register = instr.gpr20.Value() + (lod_bias_enabled ? 1 : 0);
1620 coord += ',' + regs.GetRegisterAsFloat(depth_register);
1621 }
1622 if (is_array) {
1623 coord += ',' + regs.GetRegisterAsInteger(array_register);
1624 }
1625 coord += ");";
1626 return std::make_pair(
1627 coord, GetTextureCode(instr, texture_type, process_mode, depth_compare, is_array, 0));
1628 }
1629
1630 std::pair<std::string, std::string> GetTEXSCode(
1631 const Instruction& instr, const Tegra::Shader::TextureType texture_type,
1632 const Tegra::Shader::TextureProcessMode process_mode, const bool depth_compare,
1633 const bool is_array) {
1634 const bool lod_bias_enabled = (process_mode != Tegra::Shader::TextureProcessMode::None &&
1635 process_mode != Tegra::Shader::TextureProcessMode::LZ);
1636
1637 const auto [coord_count, coord_dcl] = ValidateAndGetCoordinateElement(
1638 texture_type, depth_compare, is_array, lod_bias_enabled, 4, 4);
1639 // If enabled arrays index is always stored in the gpr8 field
1640 const u64 array_register = instr.gpr8.Value();
1641 // First coordinate index is stored in gpr8 field or (gpr8 + 1) when arrays are used
1642 const u64 coord_register = array_register + (is_array ? 1 : 0);
1643 const u64 last_coord_register =
1644 (is_array || !(lod_bias_enabled || depth_compare) || (coord_count > 2))
1645 ? static_cast<u64>(instr.gpr20.Value())
1646 : coord_register + 1;
1647
1648 std::string coord = coord_dcl;
1649 for (size_t i = 0; i < coord_count; ++i) {
1650 const bool last = (i == (coord_count - 1)) && (coord_count > 1);
1651 coord += regs.GetRegisterAsFloat(last ? last_coord_register : coord_register + i);
1652 if (!last) {
1653 coord += ',';
1654 }
1655 }
1656
1657 if (depth_compare) {
1658 // Depth is always stored in the register signaled by gpr20
1659 // or in the next register if lod or bias are used
1660 const u64 depth_register = instr.gpr20.Value() + (lod_bias_enabled ? 1 : 0);
1661 coord += ',' + regs.GetRegisterAsFloat(depth_register);
1662 }
1663 if (is_array) {
1664 coord += ',' + regs.GetRegisterAsInteger(array_register);
1665 }
1666 coord += ");";
1667
1668 return std::make_pair(coord,
1669 GetTextureCode(instr, texture_type, process_mode, depth_compare,
1670 is_array, (coord_count > 2 ? 1 : 0)));
1671 }
1672
1482 /** 1673 /**
1483 * Compiles a single instruction from Tegra to GLSL. 1674 * Compiles a single instruction from Tegra to GLSL.
1484 * @param offset the offset of the Tegra shader instruction. 1675 * @param offset the offset of the Tegra shader instruction.
@@ -2279,8 +2470,7 @@ private:
2279 UNIMPLEMENTED_IF(instr.conversion.selector); 2470 UNIMPLEMENTED_IF(instr.conversion.selector);
2280 UNIMPLEMENTED_IF_MSG(instr.generates_cc, 2471 UNIMPLEMENTED_IF_MSG(instr.generates_cc,
2281 "Condition codes generation in I2F is not implemented"); 2472 "Condition codes generation in I2F is not implemented");
2282 2473 std::string op_a;
2283 std::string op_a{};
2284 2474
2285 if (instr.is_b_gpr) { 2475 if (instr.is_b_gpr) {
2286 op_a = 2476 op_a =
@@ -2436,10 +2626,7 @@ private:
2436 case OpCode::Id::LD_C: { 2626 case OpCode::Id::LD_C: {
2437 UNIMPLEMENTED_IF(instr.ld_c.unknown != 0); 2627 UNIMPLEMENTED_IF(instr.ld_c.unknown != 0);
2438 2628
2439 // Add an extra scope and declare the index register inside to prevent 2629 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 2630
2444 shader.AddLine("uint index = (" + regs.GetRegisterAsInteger(instr.gpr8, 0, false) + 2631 shader.AddLine("uint index = (" + regs.GetRegisterAsInteger(instr.gpr8, 0, false) +
2445 " / 4) & (MAX_CONSTBUFFER_ELEMENTS - 1);"); 2632 " / 4) & (MAX_CONSTBUFFER_ELEMENTS - 1);");
@@ -2465,19 +2652,13 @@ private:
2465 UNIMPLEMENTED_MSG("Unhandled type: {}", 2652 UNIMPLEMENTED_MSG("Unhandled type: {}",
2466 static_cast<unsigned>(instr.ld_c.type.Value())); 2653 static_cast<unsigned>(instr.ld_c.type.Value()));
2467 } 2654 }
2468
2469 --shader.scope;
2470 shader.AddLine("}");
2471 break; 2655 break;
2472 } 2656 }
2473 case OpCode::Id::LD_L: { 2657 case OpCode::Id::LD_L: {
2474 UNIMPLEMENTED_IF_MSG(instr.ld_l.unknown == 1, "LD_L Unhandled mode: {}", 2658 UNIMPLEMENTED_IF_MSG(instr.ld_l.unknown == 1, "LD_L Unhandled mode: {}",
2475 static_cast<unsigned>(instr.ld_l.unknown.Value())); 2659 static_cast<unsigned>(instr.ld_l.unknown.Value()));
2476 2660
2477 // Add an extra scope and declare the index register inside to prevent 2661 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 2662
2482 std::string op = '(' + regs.GetRegisterAsInteger(instr.gpr8, 0, false) + " + " + 2663 std::string op = '(' + regs.GetRegisterAsInteger(instr.gpr8, 0, false) + " + " +
2483 std::to_string(instr.smem_imm.Value()) + ')'; 2664 std::to_string(instr.smem_imm.Value()) + ')';
@@ -2494,9 +2675,6 @@ private:
2494 UNIMPLEMENTED_MSG("LD_L Unhandled type: {}", 2675 UNIMPLEMENTED_MSG("LD_L Unhandled type: {}",
2495 static_cast<unsigned>(instr.ldst_sl.type.Value())); 2676 static_cast<unsigned>(instr.ldst_sl.type.Value()));
2496 } 2677 }
2497
2498 --shader.scope;
2499 shader.AddLine('}');
2500 break; 2678 break;
2501 } 2679 }
2502 case OpCode::Id::ST_A: { 2680 case OpCode::Id::ST_A: {
@@ -2531,10 +2709,7 @@ private:
2531 UNIMPLEMENTED_IF_MSG(instr.st_l.unknown == 0, "ST_L Unhandled mode: {}", 2709 UNIMPLEMENTED_IF_MSG(instr.st_l.unknown == 0, "ST_L Unhandled mode: {}",
2532 static_cast<unsigned>(instr.st_l.unknown.Value())); 2710 static_cast<unsigned>(instr.st_l.unknown.Value()));
2533 2711
2534 // Add an extra scope and declare the index register inside to prevent 2712 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 2713
2539 std::string op = '(' + regs.GetRegisterAsInteger(instr.gpr8, 0, false) + " + " + 2714 std::string op = '(' + regs.GetRegisterAsInteger(instr.gpr8, 0, false) + " + " +
2540 std::to_string(instr.smem_imm.Value()) + ')'; 2715 std::to_string(instr.smem_imm.Value()) + ')';
@@ -2549,179 +2724,28 @@ private:
2549 UNIMPLEMENTED_MSG("ST_L Unhandled type: {}", 2724 UNIMPLEMENTED_MSG("ST_L Unhandled type: {}",
2550 static_cast<unsigned>(instr.ldst_sl.type.Value())); 2725 static_cast<unsigned>(instr.ldst_sl.type.Value()));
2551 } 2726 }
2552
2553 --shader.scope;
2554 shader.AddLine('}');
2555 break; 2727 break;
2556 } 2728 }
2557 case OpCode::Id::TEX: { 2729 case OpCode::Id::TEX: {
2558 Tegra::Shader::TextureType texture_type{instr.tex.texture_type}; 2730 Tegra::Shader::TextureType texture_type{instr.tex.texture_type};
2559 std::string coord;
2560 const bool is_array = instr.tex.array != 0; 2731 const bool is_array = instr.tex.array != 0;
2561 2732 const bool depth_compare =
2733 instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC);
2734 const auto process_mode = instr.tex.GetTextureProcessMode();
2562 UNIMPLEMENTED_IF_MSG(instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), 2735 UNIMPLEMENTED_IF_MSG(instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
2563 "NODEP is not implemented"); 2736 "NODEP is not implemented");
2564 UNIMPLEMENTED_IF_MSG(instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI), 2737 UNIMPLEMENTED_IF_MSG(instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI),
2565 "AOFFI is not implemented"); 2738 "AOFFI is not implemented");
2566 2739
2567 const bool depth_compare = 2740 const auto [coord, texture] =
2568 instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC); 2741 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
2590 bool depth_compare_extra = false;
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 2742
2668 shader.AddLine('{'); 2743 const auto scope = shader.Scope();
2669 ++shader.scope;
2670 shader.AddLine(coord); 2744 shader.AddLine(coord);
2671 std::string texture;
2672 2745
2673 switch (instr.tex.GetTextureProcessMode()) { 2746 if (depth_compare) {
2674 case Tegra::Shader::TextureProcessMode::None: { 2747 regs.SetRegisterToFloat(instr.gpr0, 0, texture, 1, 1, false);
2675 if (!depth_compare_extra) { 2748 } 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 + ';'); 2749 shader.AddLine("vec4 texture_tmp = " + texture + ';');
2726 std::size_t dest_elem{}; 2750 std::size_t dest_elem{};
2727 for (std::size_t elem = 0; elem < 4; ++elem) { 2751 for (std::size_t elem = 0; elem < 4; ++elem) {
@@ -2733,138 +2757,33 @@ private:
2733 dest_elem); 2757 dest_elem);
2734 ++dest_elem; 2758 ++dest_elem;
2735 } 2759 }
2736 } else {
2737 regs.SetRegisterToFloat(instr.gpr0, 0, texture, 1, 1, false);
2738 } 2760 }
2739 --shader.scope;
2740 shader.AddLine('}');
2741 break; 2761 break;
2742 } 2762 }
2743 case OpCode::Id::TEXS: { 2763 case OpCode::Id::TEXS: {
2744 Tegra::Shader::TextureType texture_type{instr.texs.GetTextureType()}; 2764 Tegra::Shader::TextureType texture_type{instr.texs.GetTextureType()};
2745 bool is_array{instr.texs.IsArrayTexture()}; 2765 const bool is_array{instr.texs.IsArrayTexture()};
2746
2747 UNIMPLEMENTED_IF_MSG(instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
2748 "NODEP is not implemented");
2749
2750 const bool depth_compare = 2766 const bool depth_compare =
2751 instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC); 2767 instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC);
2752 u32 num_coordinates = TextureCoordinates(texture_type);
2753 const auto process_mode = instr.texs.GetTextureProcessMode(); 2768 const auto process_mode = instr.texs.GetTextureProcessMode();
2754 std::string lod_value; 2769 UNIMPLEMENTED_IF_MSG(instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
2755 std::string coord; 2770 "NODEP is not implemented");
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 2771
2767 switch (num_coordinates) { 2772 const auto scope = shader.Scope();
2768 case 1: { 2773
2769 coord = "float coords = " + regs.GetRegisterAsFloat(instr.gpr8) + ';'; 2774 const auto [coord, texture] =
2770 break; 2775 GetTEXSCode(instr, texture_type, process_mode, depth_compare, is_array);
2771 } 2776
2772 case 2: { 2777 shader.AddLine(coord);
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 2778
2829 // Fallback to interpreting as a 2D texture for now
2830 const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
2831 const std::string y = regs.GetRegisterAsFloat(instr.gpr20);
2832 coord = "vec2 coords = vec2(" + x + ", " + y + ");";
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 }
2862 if (!depth_compare) { 2779 if (!depth_compare) {
2863 WriteTexsInstruction(instr, coord, texture); 2780 shader.AddLine("vec4 texture_tmp = " + texture + ';');
2781
2864 } else { 2782 } else {
2865 WriteTexsInstruction(instr, coord, "vec4(" + texture + ')'); 2783 shader.AddLine("vec4 texture_tmp = vec4(" + texture + ");");
2866 } 2784 }
2867 2785
2786 WriteTexsInstruction(instr, "texture_tmp");
2868 break; 2787 break;
2869 } 2788 }
2870 case OpCode::Id::TLDS: { 2789 case OpCode::Id::TLDS: {
@@ -2883,15 +2802,12 @@ private:
2883 2802
2884 u32 extra_op_offset = 0; 2803 u32 extra_op_offset = 0;
2885 2804
2886 // Scope to avoid variable name overlaps. 2805 ShaderScopedScope scope = shader.Scope();
2887 shader.AddLine('{');
2888 ++shader.scope;
2889 std::string coords;
2890 2806
2891 switch (texture_type) { 2807 switch (texture_type) {
2892 case Tegra::Shader::TextureType::Texture1D: { 2808 case Tegra::Shader::TextureType::Texture1D: {
2893 const std::string x = regs.GetRegisterAsInteger(instr.gpr8); 2809 const std::string x = regs.GetRegisterAsInteger(instr.gpr8);
2894 coords = "float coords = " + x + ';'; 2810 shader.AddLine("float coords = " + x + ';');
2895 break; 2811 break;
2896 } 2812 }
2897 case Tegra::Shader::TextureType::Texture2D: { 2813 case Tegra::Shader::TextureType::Texture2D: {
@@ -2900,7 +2816,7 @@ private:
2900 const std::string x = regs.GetRegisterAsInteger(instr.gpr8); 2816 const std::string x = regs.GetRegisterAsInteger(instr.gpr8);
2901 const std::string y = regs.GetRegisterAsInteger(instr.gpr20); 2817 const std::string y = regs.GetRegisterAsInteger(instr.gpr20);
2902 // shader.AddLine("ivec2 coords = ivec2(" + x + ", " + y + ");"); 2818 // shader.AddLine("ivec2 coords = ivec2(" + x + ", " + y + ");");
2903 coords = "ivec2 coords = ivec2(" + x + ", " + y + ");"; 2819 shader.AddLine("ivec2 coords = ivec2(" + x + ", " + y + ");");
2904 extra_op_offset = 1; 2820 extra_op_offset = 1;
2905 break; 2821 break;
2906 } 2822 }
@@ -2909,35 +2825,29 @@ private:
2909 } 2825 }
2910 const std::string sampler = 2826 const std::string sampler =
2911 GetSampler(instr.sampler, texture_type, is_array, false); 2827 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 2828
2933 --shader.scope; 2829 const std::string texture = [&]() {
2934 shader.AddLine('}'); 2830 switch (instr.tlds.GetTextureProcessMode()) {
2831 case Tegra::Shader::TextureProcessMode::LZ:
2832 return "texelFetch(" + sampler + ", coords, 0)";
2833 case Tegra::Shader::TextureProcessMode::LL:
2834 shader.AddLine(
2835 "float lod = " +
2836 regs.GetRegisterAsInteger(instr.gpr20.Value() + extra_op_offset) + ';');
2837 return "texelFetch(" + sampler + ", coords, lod)";
2838 default:
2839 UNIMPLEMENTED_MSG("Unhandled texture process mode {}",
2840 static_cast<u32>(instr.tlds.GetTextureProcessMode()));
2841 return "texelFetch(" + sampler + ", coords, 0)";
2842 }
2843 }();
2844
2845 WriteTexsInstruction(instr, texture);
2935 break; 2846 break;
2936 } 2847 }
2937 case OpCode::Id::TLD4: { 2848 case OpCode::Id::TLD4: {
2938 ASSERT(instr.tld4.texture_type == Tegra::Shader::TextureType::Texture2D); 2849 ASSERT(instr.tld4.texture_type == Tegra::Shader::TextureType::Texture2D);
2939 ASSERT(instr.tld4.array == 0); 2850 ASSERT(instr.tld4.array == 0);
2940 std::string coord;
2941 2851
2942 UNIMPLEMENTED_IF_MSG(instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), 2852 UNIMPLEMENTED_IF_MSG(instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
2943 "NODEP is not implemented"); 2853 "NODEP is not implemented");
@@ -2954,10 +2864,7 @@ private:
2954 if (depth_compare) 2864 if (depth_compare)
2955 num_coordinates += 1; 2865 num_coordinates += 1;
2956 2866
2957 // Add an extra scope and declare the texture coords inside to prevent 2867 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 2868
2962 switch (num_coordinates) { 2869 switch (num_coordinates) {
2963 case 2: { 2870 case 2: {
@@ -2988,23 +2895,19 @@ private:
2988 const std::string texture = "textureGather(" + sampler + ", coords, " + 2895 const std::string texture = "textureGather(" + sampler + ", coords, " +
2989 std::to_string(instr.tld4.component) + ')'; 2896 std::to_string(instr.tld4.component) + ')';
2990 2897
2991 if (!depth_compare) { 2898 if (depth_compare) {
2992 shader.AddLine("vec4 texture_tmp = " + texture + ';'); 2899 regs.SetRegisterToFloat(instr.gpr0, 0, texture, 1, 1, false);
2900 } else {
2993 std::size_t dest_elem{}; 2901 std::size_t dest_elem{};
2994 for (std::size_t elem = 0; elem < 4; ++elem) { 2902 for (std::size_t elem = 0; elem < 4; ++elem) {
2995 if (!instr.tex.IsComponentEnabled(elem)) { 2903 if (!instr.tex.IsComponentEnabled(elem)) {
2996 // Skip disabled components 2904 // Skip disabled components
2997 continue; 2905 continue;
2998 } 2906 }
2999 regs.SetRegisterToFloat(instr.gpr0, elem, "texture_tmp", 1, 4, false, 2907 regs.SetRegisterToFloat(instr.gpr0, elem, texture, 1, 4, false, dest_elem);
3000 dest_elem);
3001 ++dest_elem; 2908 ++dest_elem;
3002 } 2909 }
3003 } else {
3004 regs.SetRegisterToFloat(instr.gpr0, 0, texture, 1, 1, false);
3005 } 2910 }
3006 --shader.scope;
3007 shader.AddLine('}');
3008 break; 2911 break;
3009 } 2912 }
3010 case OpCode::Id::TLD4S: { 2913 case OpCode::Id::TLD4S: {
@@ -3015,10 +2918,7 @@ private:
3015 instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI), 2918 instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI),
3016 "AOFFI is not implemented"); 2919 "AOFFI is not implemented");
3017 2920
3018 // Scope to avoid variable name overlaps. 2921 const auto scope = shader.Scope();
3019 shader.AddLine('{');
3020 ++shader.scope;
3021 std::string coords;
3022 2922
3023 const bool depth_compare = 2923 const bool depth_compare =
3024 instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC); 2924 instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC);
@@ -3027,33 +2927,29 @@ private:
3027 // TODO(Subv): Figure out how the sampler type is encoded in the TLD4S instruction. 2927 // TODO(Subv): Figure out how the sampler type is encoded in the TLD4S instruction.
3028 const std::string sampler = GetSampler( 2928 const std::string sampler = GetSampler(
3029 instr.sampler, Tegra::Shader::TextureType::Texture2D, false, depth_compare); 2929 instr.sampler, Tegra::Shader::TextureType::Texture2D, false, depth_compare);
3030 if (!depth_compare) { 2930 if (depth_compare) {
3031 coords = "vec2 coords = vec2(" + op_a + ", " + op_b + ");";
3032 } else {
3033 // Note: TLD4S coordinate encoding works just like TEXS's 2931 // Note: TLD4S coordinate encoding works just like TEXS's
3034 const std::string op_y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); 2932 const std::string op_y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
3035 coords = "vec3 coords = vec3(" + op_a + ", " + op_y + ", " + op_b + ");"; 2933 shader.AddLine("vec3 coords = vec3(" + op_a + ", " + op_y + ", " + op_b + ");");
3036 }
3037 const std::string texture = "textureGather(" + sampler + ", coords, " +
3038 std::to_string(instr.tld4s.component) + ')';
3039
3040 if (!depth_compare) {
3041 WriteTexsInstruction(instr, coords, texture);
3042 } else { 2934 } else {
3043 WriteTexsInstruction(instr, coords, "vec4(" + texture + ')'); 2935 shader.AddLine("vec2 coords = vec2(" + op_a + ", " + op_b + ");");
3044 } 2936 }
3045 2937
3046 --shader.scope; 2938 std::string texture = "textureGather(" + sampler + ", coords, " +
3047 shader.AddLine('}'); 2939 std::to_string(instr.tld4s.component) + ')';
2940 if (depth_compare) {
2941 texture = "vec4(" + texture + ')';
2942 }
2943 WriteTexsInstruction(instr, texture);
3048 break; 2944 break;
3049 } 2945 }
3050 case OpCode::Id::TXQ: { 2946 case OpCode::Id::TXQ: {
3051 UNIMPLEMENTED_IF_MSG(instr.txq.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), 2947 UNIMPLEMENTED_IF_MSG(instr.txq.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
3052 "NODEP is not implemented"); 2948 "NODEP is not implemented");
3053 2949
3054 ++shader.scope; 2950 const auto scope = shader.Scope();
3055 shader.AddLine('{'); 2951
3056 // TODO: the new commits on the texture refactor, change the way samplers work. 2952 // 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 2953 // Sadly, not all texture instructions specify the type of texture their sampler
3058 // uses. This must be fixed at a later instance. 2954 // uses. This must be fixed at a later instance.
3059 const std::string sampler = 2955 const std::string sampler =
@@ -3064,7 +2960,8 @@ private:
3064 regs.GetRegisterAsInteger(instr.gpr8) + ')'; 2960 regs.GetRegisterAsInteger(instr.gpr8) + ')';
3065 const std::string mip_level = "textureQueryLevels(" + sampler + ')'; 2961 const std::string mip_level = "textureQueryLevels(" + sampler + ')';
3066 shader.AddLine("ivec2 sizes = " + texture + ';'); 2962 shader.AddLine("ivec2 sizes = " + texture + ';');
3067 regs.SetRegisterToInteger(instr.gpr0, true, 0, "sizes.x", 1, 1); 2963
2964 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); 2965 regs.SetRegisterToInteger(instr.gpr0.Value() + 1, true, 0, "sizes.y", 1, 1);
3069 regs.SetRegisterToInteger(instr.gpr0.Value() + 2, true, 0, "0", 1, 1); 2966 regs.SetRegisterToInteger(instr.gpr0.Value() + 2, true, 0, "0", 1, 1);
3070 regs.SetRegisterToInteger(instr.gpr0.Value() + 3, true, 0, mip_level, 1, 1); 2967 regs.SetRegisterToInteger(instr.gpr0.Value() + 3, true, 0, mip_level, 1, 1);
@@ -3075,8 +2972,6 @@ private:
3075 static_cast<u32>(instr.txq.query_type.Value())); 2972 static_cast<u32>(instr.txq.query_type.Value()));
3076 } 2973 }
3077 } 2974 }
3078 --shader.scope;
3079 shader.AddLine('}');
3080 break; 2975 break;
3081 } 2976 }
3082 case OpCode::Id::TMML: { 2977 case OpCode::Id::TMML: {
@@ -3091,17 +2986,18 @@ private:
3091 const std::string sampler = 2986 const std::string sampler =
3092 GetSampler(instr.sampler, texture_type, is_array, false); 2987 GetSampler(instr.sampler, texture_type, is_array, false);
3093 2988
3094 // TODO: add coordinates for different samplers once other texture types are 2989 const auto scope = shader.Scope();
2990
2991 // TODO: Add coordinates for different samplers once other texture types are
3095 // implemented. 2992 // implemented.
3096 std::string coord;
3097 switch (texture_type) { 2993 switch (texture_type) {
3098 case Tegra::Shader::TextureType::Texture1D: { 2994 case Tegra::Shader::TextureType::Texture1D: {
3099 coord = "float coords = " + x + ';'; 2995 shader.AddLine("float coords = " + x + ';');
3100 break; 2996 break;
3101 } 2997 }
3102 case Tegra::Shader::TextureType::Texture2D: { 2998 case Tegra::Shader::TextureType::Texture2D: {
3103 const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); 2999 const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
3104 coord = "vec2 coords = vec2(" + x + ", " + y + ");"; 3000 shader.AddLine("vec2 coords = vec2(" + x + ", " + y + ");");
3105 break; 3001 break;
3106 } 3002 }
3107 default: 3003 default:
@@ -3109,22 +3005,15 @@ private:
3109 3005
3110 // Fallback to interpreting as a 2D texture for now 3006 // Fallback to interpreting as a 2D texture for now
3111 const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); 3007 const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
3112 coord = "vec2 coords = vec2(" + x + ", " + y + ");"; 3008 shader.AddLine("vec2 coords = vec2(" + x + ", " + y + ");");
3113 texture_type = Tegra::Shader::TextureType::Texture2D; 3009 texture_type = Tegra::Shader::TextureType::Texture2D;
3114 } 3010 }
3115 // Add an extra scope and declare the texture coords inside to prevent 3011
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)"; 3012 const std::string texture = "textureQueryLod(" + sampler + ", coords)";
3121 const std::string tmp = "vec2 tmp = " + texture + "*vec2(256.0, 256.0);"; 3013 shader.AddLine("vec2 tmp = " + texture + " * vec2(256.0, 256.0);");
3122 shader.AddLine(tmp);
3123 3014
3124 regs.SetRegisterToInteger(instr.gpr0, true, 0, "int(tmp.y)", 1, 1); 3015 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); 3016 regs.SetRegisterToInteger(instr.gpr0.Value() + 1, false, 0, "uint(tmp.x)", 1, 1);
3126 --shader.scope;
3127 shader.AddLine('}');
3128 break; 3017 break;
3129 } 3018 }
3130 default: { 3019 default: {
@@ -3963,4 +3852,4 @@ std::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, u
3963 return {}; 3852 return {};
3964} 3853}
3965 3854
3966} // namespace OpenGL::GLShader::Decompiler 3855} // 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/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 0527d098c..830d26115 100644
--- a/src/yuzu/configuration/configure_input.cpp
+++ b/src/yuzu/configuration/configure_input.cpp
@@ -88,6 +88,8 @@ 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);
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..1edc60df7 100644
--- a/src/yuzu/game_list_worker.cpp
+++ b/src/yuzu/game_list_worker.cpp
@@ -97,11 +97,11 @@ GameListWorker::~GameListWorker() = default;
97 97
98void GameListWorker::AddInstalledTitlesToGameList() { 98void GameListWorker::AddInstalledTitlesToGameList() {
99 const auto cache = Service::FileSystem::GetUnionContents(); 99 const auto cache = Service::FileSystem::GetUnionContents();
100 const auto installed_games = cache->ListEntriesFilter(FileSys::TitleType::Application, 100 const auto installed_games = cache.ListEntriesFilter(FileSys::TitleType::Application,
101 FileSys::ContentRecordType::Program); 101 FileSys::ContentRecordType::Program);
102 102
103 for (const auto& game : installed_games) { 103 for (const auto& game : installed_games) {
104 const auto file = cache->GetEntryUnparsed(game); 104 const auto file = cache.GetEntryUnparsed(game);
105 std::unique_ptr<Loader::AppLoader> loader = Loader::GetLoader(file); 105 std::unique_ptr<Loader::AppLoader> loader = Loader::GetLoader(file);
106 if (!loader) 106 if (!loader)
107 continue; 107 continue;
@@ -112,7 +112,7 @@ void GameListWorker::AddInstalledTitlesToGameList() {
112 loader->ReadProgramId(program_id); 112 loader->ReadProgramId(program_id);
113 113
114 const FileSys::PatchManager patch{program_id}; 114 const FileSys::PatchManager patch{program_id};
115 const auto control = cache->GetEntry(game.title_id, FileSys::ContentRecordType::Control); 115 const auto control = cache.GetEntry(game.title_id, FileSys::ContentRecordType::Control);
116 if (control != nullptr) 116 if (control != nullptr)
117 GetMetadataFromControlNCA(patch, *control, icon, name); 117 GetMetadataFromControlNCA(patch, *control, icon, name);
118 118
@@ -141,11 +141,11 @@ void GameListWorker::AddInstalledTitlesToGameList() {
141 emit EntryReady(list); 141 emit EntryReady(list);
142 } 142 }
143 143
144 const auto control_data = cache->ListEntriesFilter(FileSys::TitleType::Application, 144 const auto control_data = cache.ListEntriesFilter(FileSys::TitleType::Application,
145 FileSys::ContentRecordType::Control); 145 FileSys::ContentRecordType::Control);
146 146
147 for (const auto& entry : control_data) { 147 for (const auto& entry : control_data) {
148 auto nca = cache->GetEntry(entry); 148 auto nca = cache.GetEntry(entry);
149 if (nca != nullptr) { 149 if (nca != nullptr) {
150 nca_control_map.insert_or_assign(entry.title_id, std::move(nca)); 150 nca_control_map.insert_or_assign(entry.title_id, std::move(nca));
151 } 151 }
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)