summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/audio_core/audio_renderer.cpp4
-rw-r--r--src/audio_core/audio_renderer.h7
-rw-r--r--src/core/CMakeLists.txt10
-rw-r--r--src/core/crypto/key_manager.cpp3
-rw-r--r--src/core/file_sys/patch_manager.cpp19
-rw-r--r--src/core/file_sys/registered_cache.cpp53
-rw-r--r--src/core/file_sys/romfs_factory.cpp2
-rw-r--r--src/core/file_sys/system_archive/ng_word.cpp42
-rw-r--r--src/core/file_sys/system_archive/ng_word.h13
-rw-r--r--src/core/file_sys/system_archive/system_archive.cpp90
-rw-r--r--src/core/file_sys/system_archive/system_archive.h14
-rw-r--r--src/core/file_sys/vfs.cpp46
-rw-r--r--src/core/file_sys/vfs.h20
-rw-r--r--src/core/file_sys/vfs_vector.cpp1
-rw-r--r--src/core/file_sys/vfs_vector.h53
-rw-r--r--src/core/hle/kernel/handle_table.cpp5
-rw-r--r--src/core/hle/kernel/handle_table.h1
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp29
-rw-r--r--src/core/hle/kernel/hle_ipc.h12
-rw-r--r--src/core/hle/kernel/object.cpp3
-rw-r--r--src/core/hle/kernel/object.h9
-rw-r--r--src/core/hle/kernel/process.cpp4
-rw-r--r--src/core/hle/kernel/process.h9
-rw-r--r--src/core/hle/kernel/readable_event.cpp (renamed from src/core/hle/kernel/event.cpp)27
-rw-r--r--src/core/hle/kernel/readable_event.h55
-rw-r--r--src/core/hle/kernel/svc.cpp251
-rw-r--r--src/core/hle/kernel/svc_wrap.h13
-rw-r--r--src/core/hle/kernel/writable_event.cpp52
-rw-r--r--src/core/hle/kernel/writable_event.h (renamed from src/core/hle/kernel/event.h)35
-rw-r--r--src/core/hle/service/am/am.cpp43
-rw-r--r--src/core/hle/service/am/am.h16
-rw-r--r--src/core/hle/service/am/applets/applets.cpp31
-rw-r--r--src/core/hle/service/am/applets/applets.h17
-rw-r--r--src/core/hle/service/aoc/aoc_u.cpp14
-rw-r--r--src/core/hle/service/aoc/aoc_u.h6
-rw-r--r--src/core/hle/service/audio/audout_u.cpp21
-rw-r--r--src/core/hle/service/audio/audren_u.cpp26
-rw-r--r--src/core/hle/service/btdrv/btdrv.cpp16
-rw-r--r--src/core/hle/service/btm/btm.cpp46
-rw-r--r--src/core/hle/service/erpt/erpt.cpp12
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp30
-rw-r--r--src/core/hle/service/filesystem/filesystem.h15
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp22
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp23
-rw-r--r--src/core/hle/service/hid/controllers/npad.h7
-rw-r--r--src/core/hle/service/hid/hid.cpp3
-rw-r--r--src/core/hle/service/ldr/ldr.cpp10
-rw-r--r--src/core/hle/service/nfp/nfp.cpp34
-rw-r--r--src/core/hle/service/nfp/nfp.h7
-rw-r--r--src/core/hle/service/nifm/nifm.cpp14
-rw-r--r--src/core/hle/service/nim/nim.cpp20
-rw-r--r--src/core/hle/service/nvdrv/interface.cpp9
-rw-r--r--src/core/hle/service/nvdrv/interface.h7
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.cpp19
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.h11
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp13
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.h11
-rw-r--r--src/core/hle/service/set/set.cpp21
-rw-r--r--src/core/hle/service/set/set.h1
-rw-r--r--src/core/hle/service/usb/usb.cpp2
-rw-r--r--src/core/hle/service/vi/vi.cpp7
-rw-r--r--src/core/loader/deconstructed_rom_directory.cpp3
-rw-r--r--src/core/loader/nro.cpp15
-rw-r--r--src/core/loader/nro.h8
-rw-r--r--src/core/loader/nso.cpp8
-rw-r--r--src/core/loader/nso.h8
-rw-r--r--src/core/memory.cpp8
-rw-r--r--src/video_core/command_processor.cpp142
-rw-r--r--src/video_core/engines/maxwell_3d.h1
-rw-r--r--src/video_core/engines/shader_bytecode.h3
-rw-r--r--src/video_core/gpu.cpp12
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp50
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h20
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp153
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp749
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.h1
-rw-r--r--src/video_core/renderer_opengl/gl_shader_manager.h21
-rw-r--r--src/video_core/surface.h552
-rw-r--r--src/yuzu/configuration/configure_audio.h5
-rw-r--r--src/yuzu/configuration/configure_debug.h3
-rw-r--r--src/yuzu/configuration/configure_dialog.h3
-rw-r--r--src/yuzu/configuration/configure_gamelist.h2
-rw-r--r--src/yuzu/configuration/configure_general.h2
-rw-r--r--src/yuzu/configuration/configure_graphics.h3
-rw-r--r--src/yuzu/configuration/configure_input.cpp4
-rw-r--r--src/yuzu/configuration/configure_input.h1
-rw-r--r--src/yuzu/configuration/configure_web.h5
-rw-r--r--src/yuzu/debugger/wait_tree.cpp11
-rw-r--r--src/yuzu/debugger/wait_tree.h4
-rw-r--r--src/yuzu/game_list.cpp1
-rw-r--r--src/yuzu/game_list_worker.cpp119
-rw-r--r--src/yuzu/main.cpp6
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.cpp2
93 files changed, 1807 insertions, 1534 deletions
diff --git a/src/audio_core/audio_renderer.cpp b/src/audio_core/audio_renderer.cpp
index 23e5d3f10..2e59894ab 100644
--- a/src/audio_core/audio_renderer.cpp
+++ b/src/audio_core/audio_renderer.cpp
@@ -8,7 +8,7 @@
#include "audio_core/codec.h"
#include "common/assert.h"
#include "common/logging/log.h"
-#include "core/hle/kernel/event.h"
+#include "core/hle/kernel/writable_event.h"
#include "core/memory.h"
namespace AudioCore {
@@ -72,7 +72,7 @@ private:
EffectInStatus info{};
};
AudioRenderer::AudioRenderer(AudioRendererParameter params,
- Kernel::SharedPtr<Kernel::Event> buffer_event)
+ Kernel::SharedPtr<Kernel::WritableEvent> buffer_event)
: worker_params{params}, buffer_event{buffer_event}, voices(params.voice_count),
effects(params.effect_count) {
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 @@
#include "core/hle/kernel/object.h"
namespace Kernel {
-class Event;
+class WritableEvent;
}
namespace AudioCore {
@@ -208,7 +208,8 @@ static_assert(sizeof(UpdateDataHeader) == 0x40, "UpdateDataHeader has wrong size
class AudioRenderer {
public:
- AudioRenderer(AudioRendererParameter params, Kernel::SharedPtr<Kernel::Event> buffer_event);
+ AudioRenderer(AudioRendererParameter params,
+ Kernel::SharedPtr<Kernel::WritableEvent> buffer_event);
~AudioRenderer();
std::vector<u8> UpdateAudioRenderer(const std::vector<u8>& input_params);
@@ -224,7 +225,7 @@ private:
class VoiceState;
AudioRendererParameter worker_params;
- Kernel::SharedPtr<Kernel::Event> buffer_event;
+ Kernel::SharedPtr<Kernel::WritableEvent> buffer_event;
std::vector<VoiceState> voices;
std::vector<EffectState> effects;
std::unique_ptr<AudioOut> audio_out;
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index e1f21a764..882c9ab59 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -63,6 +63,10 @@ add_library(core STATIC
file_sys/sdmc_factory.h
file_sys/submission_package.cpp
file_sys/submission_package.h
+ file_sys/system_archive/ng_word.cpp
+ file_sys/system_archive/ng_word.h
+ file_sys/system_archive/system_archive.cpp
+ file_sys/system_archive/system_archive.h
file_sys/vfs.cpp
file_sys/vfs.h
file_sys/vfs_concat.cpp
@@ -97,8 +101,6 @@ add_library(core STATIC
hle/kernel/client_session.cpp
hle/kernel/client_session.h
hle/kernel/errors.h
- hle/kernel/event.cpp
- hle/kernel/event.h
hle/kernel/handle_table.cpp
hle/kernel/handle_table.h
hle/kernel/hle_ipc.cpp
@@ -111,6 +113,8 @@ add_library(core STATIC
hle/kernel/object.h
hle/kernel/process.cpp
hle/kernel/process.h
+ hle/kernel/readable_event.cpp
+ hle/kernel/readable_event.h
hle/kernel/resource_limit.cpp
hle/kernel/resource_limit.h
hle/kernel/scheduler.cpp
@@ -133,6 +137,8 @@ add_library(core STATIC
hle/kernel/vm_manager.h
hle/kernel/wait_object.cpp
hle/kernel/wait_object.h
+ hle/kernel/writable_event.cpp
+ hle/kernel/writable_event.h
hle/lock.cpp
hle/lock.h
hle/result.h
diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp
index 904afa039..ca12fb4ab 100644
--- a/src/core/crypto/key_manager.cpp
+++ b/src/core/crypto/key_manager.cpp
@@ -246,7 +246,6 @@ std::vector<TicketRaw> GetTicketblob(const FileUtil::IOFile& ticket_save) {
}
std::vector<TicketRaw> out;
- u32 magic{};
for (std::size_t offset = 0; offset + 0x4 < buffer.size(); ++offset) {
if (buffer[offset] == 0x4 && buffer[offset + 1] == 0x0 && buffer[offset + 2] == 0x1 &&
buffer[offset + 3] == 0x0) {
@@ -794,7 +793,7 @@ void KeyManager::DeriveBase() {
void KeyManager::DeriveETicket(PartitionDataManager& data) {
// ETicket keys
- const auto es = Service::FileSystem::GetUnionContents()->GetEntry(
+ const auto es = Service::FileSystem::GetUnionContents().GetEntry(
0x0100000000000033, FileSys::ContentRecordType::Program);
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 {
// Game Updates
const auto update_tid = GetUpdateTitleID(title_id);
- const auto update = installed->GetEntry(update_tid, ContentRecordType::Program);
+ const auto update = installed.GetEntry(update_tid, ContentRecordType::Program);
if (update != nullptr && update->GetExeFS() != nullptr &&
update->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) {
LOG_INFO(Loader, " ExeFS: Update ({}) applied successfully",
- FormatTitleVersion(installed->GetEntryVersion(update_tid).value_or(0)));
+ FormatTitleVersion(installed.GetEntryVersion(update_tid).value_or(0)));
exefs = update->GetExeFS();
}
@@ -281,13 +281,13 @@ VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, Content
// Game Updates
const auto update_tid = GetUpdateTitleID(title_id);
- const auto update = installed->GetEntryRaw(update_tid, type);
+ const auto update = installed.GetEntryRaw(update_tid, type);
if (update != nullptr) {
const auto new_nca = std::make_shared<NCA>(update, romfs, ivfc_offset);
if (new_nca->GetStatus() == Loader::ResultStatus::Success &&
new_nca->GetRomFS() != nullptr) {
LOG_INFO(Loader, " RomFS: Update ({}) applied successfully",
- FormatTitleVersion(installed->GetEntryVersion(update_tid).value_or(0)));
+ FormatTitleVersion(installed.GetEntryVersion(update_tid).value_or(0)));
romfs = new_nca->GetRomFS();
}
} else if (update_raw != nullptr) {
@@ -329,8 +329,8 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
if (nacp != nullptr) {
out.insert_or_assign("Update", nacp->GetVersionString());
} else {
- if (installed->HasEntry(update_tid, ContentRecordType::Program)) {
- const auto meta_ver = installed->GetEntryVersion(update_tid);
+ if (installed.HasEntry(update_tid, ContentRecordType::Program)) {
+ const auto meta_ver = installed.GetEntryVersion(update_tid);
if (meta_ver.value_or(0) == 0) {
out.insert_or_assign("Update", "");
} else {
@@ -383,14 +383,13 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
}
// DLC
- const auto dlc_entries = installed->ListEntriesFilter(TitleType::AOC, ContentRecordType::Data);
+ const auto dlc_entries = installed.ListEntriesFilter(TitleType::AOC, ContentRecordType::Data);
std::vector<RegisteredCacheEntry> dlc_match;
dlc_match.reserve(dlc_entries.size());
std::copy_if(dlc_entries.begin(), dlc_entries.end(), std::back_inserter(dlc_match),
[this, &installed](const RegisteredCacheEntry& entry) {
return (entry.title_id & DLC_BASE_TITLE_ID_MASK) == title_id &&
- installed->GetEntry(entry)->GetStatus() ==
- Loader::ResultStatus::Success;
+ installed.GetEntry(entry)->GetStatus() == Loader::ResultStatus::Success;
});
if (!dlc_match.empty()) {
// Ensure sorted so DLC IDs show in order.
@@ -411,7 +410,7 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
std::pair<std::unique_ptr<NACP>, VirtualFile> PatchManager::GetControlMetadata() const {
const auto installed{Service::FileSystem::GetUnionContents()};
- const auto base_control_nca = installed->GetEntry(title_id, ContentRecordType::Control);
+ const auto base_control_nca = installed.GetEntry(title_id, ContentRecordType::Control);
if (base_control_nca == nullptr)
return {};
diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp
index 07c3af64a..128199063 100644
--- a/src/core/file_sys/registered_cache.cpp
+++ b/src/core/file_sys/registered_cache.cpp
@@ -107,42 +107,41 @@ static ContentRecordType GetCRTypeFromNCAType(NCAContentType type) {
VirtualFile RegisteredCache::OpenFileOrDirectoryConcat(const VirtualDir& dir,
std::string_view path) const {
const auto file = dir->GetFileRelative(path);
- if (file != nullptr)
+ if (file != nullptr) {
return file;
+ }
const auto nca_dir = dir->GetDirectoryRelative(path);
- if (nca_dir != nullptr) {
- const auto nca_dir = dir->GetDirectoryRelative(path);
- VirtualFile file = nullptr;
+ if (nca_dir == nullptr) {
+ return nullptr;
+ }
- const auto files = nca_dir->GetFiles();
- if (files.size() == 1 && files[0]->GetName() == "00") {
- file = files[0];
+ const auto files = nca_dir->GetFiles();
+ if (files.size() == 1 && files[0]->GetName() == "00") {
+ return files[0];
+ }
+
+ std::vector<VirtualFile> concat;
+ // Since the files are a two-digit hex number, max is FF.
+ for (std::size_t i = 0; i < 0x100; ++i) {
+ auto next = nca_dir->GetFile(fmt::format("{:02X}", i));
+ if (next != nullptr) {
+ concat.push_back(std::move(next));
} else {
- std::vector<VirtualFile> concat;
- // Since the files are a two-digit hex number, max is FF.
- for (std::size_t i = 0; i < 0x100; ++i) {
- auto next = nca_dir->GetFile(fmt::format("{:02X}", i));
- if (next != nullptr) {
- concat.push_back(std::move(next));
- } else {
- next = nca_dir->GetFile(fmt::format("{:02x}", i));
- if (next != nullptr)
- concat.push_back(std::move(next));
- else
- break;
- }
+ next = nca_dir->GetFile(fmt::format("{:02x}", i));
+ if (next != nullptr) {
+ concat.push_back(std::move(next));
+ } else {
+ break;
}
-
- if (concat.empty())
- return nullptr;
-
- file = ConcatenatedVfsFile::MakeConcatenatedFile(concat, concat.front()->GetName());
}
+ }
- return file;
+ if (concat.empty()) {
+ return nullptr;
}
- return nullptr;
+
+ return ConcatenatedVfsFile::MakeConcatenatedFile(concat, concat.front()->GetName());
}
VirtualFile RegisteredCache::GetFileAtID(NcaID id) const {
diff --git a/src/core/file_sys/romfs_factory.cpp b/src/core/file_sys/romfs_factory.cpp
index 0b645b106..6ad1e4f86 100644
--- a/src/core/file_sys/romfs_factory.cpp
+++ b/src/core/file_sys/romfs_factory.cpp
@@ -48,7 +48,7 @@ ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id, StorageId storage, Conte
switch (storage) {
case StorageId::None:
- res = Service::FileSystem::GetUnionContents()->GetEntry(title_id, type);
+ res = Service::FileSystem::GetUnionContents().GetEntry(title_id, type);
break;
case StorageId::NandSystem:
res = Service::FileSystem::GetSystemNANDContents()->GetEntry(title_id, type);
diff --git a/src/core/file_sys/system_archive/ng_word.cpp b/src/core/file_sys/system_archive/ng_word.cpp
new file mode 100644
index 000000000..a24f1e496
--- /dev/null
+++ b/src/core/file_sys/system_archive/ng_word.cpp
@@ -0,0 +1,42 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <fmt/format.h>
+#include "common/common_types.h"
+#include "core/file_sys/system_archive/ng_word.h"
+#include "core/file_sys/vfs_vector.h"
+
+namespace FileSys::SystemArchive {
+
+namespace NgWord1Data {
+
+constexpr std::size_t NUMBER_WORD_TXT_FILES = 0x10;
+
+// Should this archive replacement mysteriously not work on a future game, consider updating.
+constexpr std::array<u8, 4> VERSION_DAT{0x0, 0x0, 0x0, 0x19}; // 5.1.0 System Version
+
+constexpr std::array<u8, 30> WORD_TXT{
+ 0xFE, 0xFF, 0x00, 0x5E, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00, 0x79, 0x00, 0x62, 0x00,
+ 0x61, 0x00, 0x64, 0x00, 0x77, 0x00, 0x6F, 0x00, 0x72, 0x00, 0x64, 0x00, 0x24, 0x00, 0x0A,
+}; // "^verybadword$" in UTF-16
+
+} // namespace NgWord1Data
+
+VirtualDir NgWord1() {
+ std::vector<VirtualFile> files(NgWord1Data::NUMBER_WORD_TXT_FILES);
+
+ for (std::size_t i = 0; i < files.size(); ++i) {
+ files[i] = std::make_shared<ArrayVfsFile<NgWord1Data::WORD_TXT.size()>>(
+ NgWord1Data::WORD_TXT, fmt::format("{}.txt", i));
+ }
+
+ files.push_back(std::make_shared<ArrayVfsFile<NgWord1Data::WORD_TXT.size()>>(
+ NgWord1Data::WORD_TXT, "common.txt"));
+ files.push_back(std::make_shared<ArrayVfsFile<NgWord1Data::VERSION_DAT.size()>>(
+ NgWord1Data::VERSION_DAT, "version.dat"));
+
+ return std::make_shared<VectorVfsDirectory>(files, std::vector<VirtualDir>{}, "data");
+}
+
+} // namespace FileSys::SystemArchive
diff --git a/src/core/file_sys/system_archive/ng_word.h b/src/core/file_sys/system_archive/ng_word.h
new file mode 100644
index 000000000..f4bc67344
--- /dev/null
+++ b/src/core/file_sys/system_archive/ng_word.h
@@ -0,0 +1,13 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/file_sys/vfs_types.h"
+
+namespace FileSys::SystemArchive {
+
+VirtualDir NgWord1();
+
+} // namespace FileSys::SystemArchive
diff --git a/src/core/file_sys/system_archive/system_archive.cpp b/src/core/file_sys/system_archive/system_archive.cpp
new file mode 100644
index 000000000..d3883267c
--- /dev/null
+++ b/src/core/file_sys/system_archive/system_archive.cpp
@@ -0,0 +1,90 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/logging/log.h"
+#include "core/file_sys/romfs.h"
+#include "core/file_sys/system_archive/ng_word.h"
+#include "core/file_sys/system_archive/system_archive.h"
+
+namespace FileSys::SystemArchive {
+
+constexpr u64 SYSTEM_ARCHIVE_BASE_TITLE_ID = 0x0100000000000800;
+constexpr std::size_t SYSTEM_ARCHIVE_COUNT = 0x28;
+
+using SystemArchiveSupplier = VirtualDir (*)();
+
+struct SystemArchiveDescriptor {
+ u64 title_id;
+ const char* name;
+ SystemArchiveSupplier supplier;
+};
+
+constexpr std::array<SystemArchiveDescriptor, SYSTEM_ARCHIVE_COUNT> SYSTEM_ARCHIVES{{
+ {0x0100000000000800, "CertStore", nullptr},
+ {0x0100000000000801, "ErrorMessage", nullptr},
+ {0x0100000000000802, "MiiModel", nullptr},
+ {0x0100000000000803, "BrowserDll", nullptr},
+ {0x0100000000000804, "Help", nullptr},
+ {0x0100000000000805, "SharedFont", nullptr},
+ {0x0100000000000806, "NgWord", &NgWord1},
+ {0x0100000000000807, "SsidList", nullptr},
+ {0x0100000000000808, "Dictionary", nullptr},
+ {0x0100000000000809, "SystemVersion", nullptr},
+ {0x010000000000080A, "AvatarImage", nullptr},
+ {0x010000000000080B, "LocalNews", nullptr},
+ {0x010000000000080C, "Eula", nullptr},
+ {0x010000000000080D, "UrlBlackList", nullptr},
+ {0x010000000000080E, "TimeZoneBinary", nullptr},
+ {0x010000000000080F, "CertStoreCruiser", nullptr},
+ {0x0100000000000810, "FontNintendoExtension", nullptr},
+ {0x0100000000000811, "FontStandard", nullptr},
+ {0x0100000000000812, "FontKorean", nullptr},
+ {0x0100000000000813, "FontChineseTraditional", nullptr},
+ {0x0100000000000814, "FontChineseSimple", nullptr},
+ {0x0100000000000815, "FontBfcpx", nullptr},
+ {0x0100000000000816, "SystemUpdate", nullptr},
+ {0x0100000000000817, "0100000000000817", nullptr},
+ {0x0100000000000818, "FirmwareDebugSettings", nullptr},
+ {0x0100000000000819, "BootImagePackage", nullptr},
+ {0x010000000000081A, "BootImagePackageSafe", nullptr},
+ {0x010000000000081B, "BootImagePackageExFat", nullptr},
+ {0x010000000000081C, "BootImagePackageExFatSafe", nullptr},
+ {0x010000000000081D, "FatalMessage", nullptr},
+ {0x010000000000081E, "ControllerIcon", nullptr},
+ {0x010000000000081F, "PlatformConfigIcosa", nullptr},
+ {0x0100000000000820, "PlatformConfigCopper", nullptr},
+ {0x0100000000000821, "PlatformConfigHoag", nullptr},
+ {0x0100000000000822, "ControllerFirmware", nullptr},
+ {0x0100000000000823, "NgWord2", nullptr},
+ {0x0100000000000824, "PlatformConfigIcosaMariko", nullptr},
+ {0x0100000000000825, "ApplicationBlackList", nullptr},
+ {0x0100000000000826, "RebootlessSystemUpdateVersion", nullptr},
+ {0x0100000000000827, "ContentActionTable", nullptr},
+}};
+
+VirtualFile SynthesizeSystemArchive(const u64 title_id) {
+ if (title_id < SYSTEM_ARCHIVES.front().title_id || title_id > SYSTEM_ARCHIVES.back().title_id)
+ return nullptr;
+
+ const auto& desc = SYSTEM_ARCHIVES[title_id - SYSTEM_ARCHIVE_BASE_TITLE_ID];
+
+ LOG_INFO(Service_FS, "Synthesizing system archive '{}' (0x{:016X}).", desc.name, desc.title_id);
+
+ if (desc.supplier == nullptr)
+ return nullptr;
+
+ const auto dir = desc.supplier();
+
+ if (dir == nullptr)
+ return nullptr;
+
+ const auto romfs = CreateRomFS(dir);
+
+ if (romfs == nullptr)
+ return nullptr;
+
+ LOG_INFO(Service_FS, " - System archive generation successful!");
+ return romfs;
+}
+} // namespace FileSys::SystemArchive
diff --git a/src/core/file_sys/system_archive/system_archive.h b/src/core/file_sys/system_archive/system_archive.h
new file mode 100644
index 000000000..724a8eb17
--- /dev/null
+++ b/src/core/file_sys/system_archive/system_archive.h
@@ -0,0 +1,14 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "common/common_types.h"
+#include "core/file_sys/vfs_types.h"
+
+namespace FileSys::SystemArchive {
+
+VirtualFile SynthesizeSystemArchive(u64 title_id);
+
+} // namespace FileSys::SystemArchive
diff --git a/src/core/file_sys/vfs.cpp b/src/core/file_sys/vfs.cpp
index 7b584de7f..e33327ef0 100644
--- a/src/core/file_sys/vfs.cpp
+++ b/src/core/file_sys/vfs.cpp
@@ -384,6 +384,28 @@ bool VfsDirectory::DeleteSubdirectoryRecursive(std::string_view name) {
return success;
}
+bool VfsDirectory::CleanSubdirectoryRecursive(std::string_view name) {
+ auto dir = GetSubdirectory(name);
+ if (dir == nullptr) {
+ return false;
+ }
+
+ bool success = true;
+ for (const auto& file : dir->GetFiles()) {
+ if (!dir->DeleteFile(file->GetName())) {
+ success = false;
+ }
+ }
+
+ for (const auto& sdir : dir->GetSubdirectories()) {
+ if (!dir->DeleteSubdirectoryRecursive(sdir->GetName())) {
+ success = false;
+ }
+ }
+
+ return success;
+}
+
bool VfsDirectory::Copy(std::string_view src, std::string_view dest) {
const auto f1 = GetFile(src);
auto f2 = CreateFile(dest);
@@ -431,10 +453,34 @@ std::shared_ptr<VfsFile> ReadOnlyVfsDirectory::CreateFile(std::string_view name)
return nullptr;
}
+std::shared_ptr<VfsFile> ReadOnlyVfsDirectory::CreateFileAbsolute(std::string_view path) {
+ return nullptr;
+}
+
+std::shared_ptr<VfsFile> ReadOnlyVfsDirectory::CreateFileRelative(std::string_view path) {
+ return nullptr;
+}
+
+std::shared_ptr<VfsDirectory> ReadOnlyVfsDirectory::CreateDirectoryAbsolute(std::string_view path) {
+ return nullptr;
+}
+
+std::shared_ptr<VfsDirectory> ReadOnlyVfsDirectory::CreateDirectoryRelative(std::string_view path) {
+ return nullptr;
+}
+
bool ReadOnlyVfsDirectory::DeleteSubdirectory(std::string_view name) {
return false;
}
+bool ReadOnlyVfsDirectory::DeleteSubdirectoryRecursive(std::string_view name) {
+ return false;
+}
+
+bool ReadOnlyVfsDirectory::CleanSubdirectoryRecursive(std::string_view name) {
+ return false;
+}
+
bool ReadOnlyVfsDirectory::DeleteFile(std::string_view name) {
return false;
}
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:
// any failure.
virtual std::shared_ptr<VfsDirectory> CreateDirectoryAbsolute(std::string_view path);
- // Deletes the subdirectory with name and returns true on success.
+ // Deletes the subdirectory with the given name and returns true on success.
virtual bool DeleteSubdirectory(std::string_view name) = 0;
- // Deletes all subdirectories and files of subdirectory with name recirsively and then deletes
- // the subdirectory. Returns true on success.
+
+ // Deletes all subdirectories and files within the provided directory and then deletes
+ // the directory itself. Returns true on success.
virtual bool DeleteSubdirectoryRecursive(std::string_view name);
- // Returnes whether or not the file with name name was deleted successfully.
+
+ // Deletes all subdirectories and files within the provided directory.
+ // Unlike DeleteSubdirectoryRecursive, this does not delete the provided directory.
+ virtual bool CleanSubdirectoryRecursive(std::string_view name);
+
+ // Returns whether or not the file with name name was deleted successfully.
virtual bool DeleteFile(std::string_view name) = 0;
// Returns whether or not this directory was renamed to name.
@@ -276,7 +282,13 @@ public:
bool IsReadable() const override;
std::shared_ptr<VfsDirectory> CreateSubdirectory(std::string_view name) override;
std::shared_ptr<VfsFile> CreateFile(std::string_view name) override;
+ std::shared_ptr<VfsFile> CreateFileAbsolute(std::string_view path) override;
+ std::shared_ptr<VfsFile> CreateFileRelative(std::string_view path) override;
+ std::shared_ptr<VfsDirectory> CreateDirectoryAbsolute(std::string_view path) override;
+ std::shared_ptr<VfsDirectory> CreateDirectoryRelative(std::string_view path) override;
bool DeleteSubdirectory(std::string_view name) override;
+ bool DeleteSubdirectoryRecursive(std::string_view name) override;
+ bool CleanSubdirectoryRecursive(std::string_view name) override;
bool DeleteFile(std::string_view name) override;
bool Rename(std::string_view name) override;
};
diff --git a/src/core/file_sys/vfs_vector.cpp b/src/core/file_sys/vfs_vector.cpp
index 808f31e81..515626658 100644
--- a/src/core/file_sys/vfs_vector.cpp
+++ b/src/core/file_sys/vfs_vector.cpp
@@ -3,7 +3,6 @@
// Refer to the license.txt file included.
#include <algorithm>
-#include <cstring>
#include <utility>
#include "core/file_sys/vfs_vector.h"
diff --git a/src/core/file_sys/vfs_vector.h b/src/core/file_sys/vfs_vector.h
index 3e3f790c3..ac36cb2ee 100644
--- a/src/core/file_sys/vfs_vector.h
+++ b/src/core/file_sys/vfs_vector.h
@@ -4,10 +4,63 @@
#pragma once
+#include <cstring>
#include "core/file_sys/vfs.h"
namespace FileSys {
+// An implementation of VfsFile that is backed by a statically-sized array
+template <std::size_t size>
+class ArrayVfsFile : public VfsFile {
+public:
+ ArrayVfsFile(std::array<u8, size> data, std::string name = "", VirtualDir parent = nullptr)
+ : data(data), name(std::move(name)), parent(std::move(parent)) {}
+
+ std::string GetName() const override {
+ return name;
+ }
+
+ std::size_t GetSize() const override {
+ return size;
+ }
+
+ bool Resize(std::size_t new_size) override {
+ return false;
+ }
+
+ std::shared_ptr<VfsDirectory> GetContainingDirectory() const override {
+ return parent;
+ }
+
+ bool IsWritable() const override {
+ return false;
+ }
+
+ bool IsReadable() const override {
+ return true;
+ }
+
+ std::size_t Read(u8* data_, std::size_t length, std::size_t offset) const override {
+ const auto read = std::min(length, size - offset);
+ std::memcpy(data_, data.data() + offset, read);
+ return read;
+ }
+
+ std::size_t Write(const u8* data, std::size_t length, std::size_t offset) override {
+ return 0;
+ }
+
+ bool Rename(std::string_view name) override {
+ this->name = name;
+ return true;
+ }
+
+private:
+ std::array<u8, size> data;
+ std::string name;
+ VirtualDir parent;
+};
+
// An implementation of VfsFile that is backed by a vector optionally supplied upon construction
class VectorVfsFile : public VfsFile {
public:
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) {
u16 generation = next_generation++;
// Overflow count so it fits in the 15 bits dedicated to the generation in the handle.
- // CTR-OS doesn't use generation 0, so skip straight to 1.
- if (next_generation >= (1 << 15))
+ // Horizon OS uses zero to represent an invalid handle, so skip to 1.
+ if (next_generation >= (1 << 15)) {
next_generation = 1;
+ }
generations[slot] = generation;
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 @@
namespace Kernel {
enum KernelHandle : Handle {
+ InvalidHandle = 0,
CurrentThread = 0xFFFF8000,
CurrentProcess = 0xFFFF8001,
};
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 @@
#include "common/logging/log.h"
#include "core/core.h"
#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/event.h"
#include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/hle_ipc.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/object.h"
#include "core/hle/kernel/process.h"
+#include "core/hle/kernel/readable_event.h"
#include "core/hle/kernel/server_session.h"
+#include "core/hle/kernel/writable_event.h"
#include "core/memory.h"
namespace Kernel {
@@ -36,11 +37,9 @@ void SessionRequestHandler::ClientDisconnected(const SharedPtr<ServerSession>& s
boost::range::remove_erase(connected_sessions, server_session);
}
-SharedPtr<Event> HLERequestContext::SleepClientThread(SharedPtr<Thread> thread,
- const std::string& reason, u64 timeout,
- WakeupCallback&& callback,
- Kernel::SharedPtr<Kernel::Event> event) {
-
+SharedPtr<WritableEvent> HLERequestContext::SleepClientThread(
+ SharedPtr<Thread> thread, const std::string& reason, u64 timeout, WakeupCallback&& callback,
+ SharedPtr<WritableEvent> writable_event) {
// Put the client thread to sleep until the wait event is signaled or the timeout expires.
thread->SetWakeupCallback([context = *this, callback](
ThreadWakeupReason reason, SharedPtr<Thread> thread,
@@ -51,23 +50,25 @@ SharedPtr<Event> HLERequestContext::SleepClientThread(SharedPtr<Thread> thread,
return true;
});
- if (!event) {
+ auto& kernel = Core::System::GetInstance().Kernel();
+ if (!writable_event) {
// Create event if not provided
- auto& kernel = Core::System::GetInstance().Kernel();
- event =
- Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "HLE Pause Event: " + reason);
+ const auto pair = WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
+ "HLE Pause Event: " + reason);
+ writable_event = pair.writable;
}
- event->Clear();
+ const auto readable_event{writable_event->GetReadableEvent()};
+ writable_event->Clear();
thread->SetStatus(ThreadStatus::WaitHLEEvent);
- thread->SetWaitObjects({event});
- event->AddWaitingThread(thread);
+ thread->SetWaitObjects({readable_event});
+ readable_event->AddWaitingThread(thread);
if (timeout > 0) {
thread->WakeAfterDelay(timeout);
}
- return event;
+ return writable_event;
}
HLERequestContext::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;
namespace Kernel {
class Domain;
-class Event;
class HandleTable;
class HLERequestContext;
class Process;
+class ReadableEvent;
+class WritableEvent;
/**
* Interface implemented by HLE Session handlers.
@@ -119,12 +120,13 @@ public:
* @param callback Callback to be invoked when the thread is resumed. This callback must write
* the entire command response once again, regardless of the state of it before this function
* was called.
- * @param event Event to use to wake up the thread. If unspecified, an event will be created.
+ * @param writable_event Event to use to wake up the thread. If unspecified, an event will be
+ * created.
* @returns Event that when signaled will resume the thread and call the callback function.
*/
- SharedPtr<Event> SleepClientThread(SharedPtr<Thread> thread, const std::string& reason,
- u64 timeout, WakeupCallback&& callback,
- Kernel::SharedPtr<Kernel::Event> event = nullptr);
+ SharedPtr<WritableEvent> SleepClientThread(SharedPtr<Thread> thread, const std::string& reason,
+ u64 timeout, WakeupCallback&& callback,
+ SharedPtr<WritableEvent> writable_event = nullptr);
/// Populates this context with data from the requesting process/thread.
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;
bool Object::IsWaitable() const {
switch (GetHandleType()) {
- case HandleType::Event:
+ case HandleType::ReadableEvent:
case HandleType::Thread:
case HandleType::Timer:
case HandleType::ServerPort:
@@ -21,6 +21,7 @@ bool Object::IsWaitable() const {
return true;
case HandleType::Unknown:
+ case HandleType::WritableEvent:
case HandleType::SharedMemory:
case HandleType::Process:
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;
enum class HandleType : u32 {
Unknown,
- Event,
+ WritableEvent,
+ ReadableEvent,
SharedMemory,
Thread,
Process,
@@ -33,9 +34,9 @@ enum class HandleType : u32 {
};
enum class ResetType {
- OneShot,
- Sticky,
- Pulse,
+ OneShot, ///< Reset automatically on object acquisition
+ Sticky, ///< Never reset automatically
+ Pulse, ///< Reset automatically on wakeup
};
class 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) {
return process;
}
+SharedPtr<ResourceLimit> Process::GetResourceLimit() const {
+ return resource_limit;
+}
+
void Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) {
program_id = metadata.GetTitleID();
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:
}
/// Gets the resource limit descriptor for this process
- ResourceLimit& GetResourceLimit() {
- return *resource_limit;
- }
-
- /// Gets the resource limit descriptor for this process
- const ResourceLimit& GetResourceLimit() const {
- return *resource_limit;
- }
+ SharedPtr<ResourceLimit> GetResourceLimit() const;
/// Gets the default CPU ID for this process
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 @@
#include <algorithm>
#include "common/assert.h"
-#include "core/hle/kernel/event.h"
#include "core/hle/kernel/object.h"
+#include "core/hle/kernel/readable_event.h"
#include "core/hle/kernel/thread.h"
+#include "core/hle/kernel/writable_event.h"
namespace Kernel {
-Event::Event(KernelCore& kernel) : WaitObject{kernel} {}
-Event::~Event() = default;
+ReadableEvent::ReadableEvent(KernelCore& kernel) : WaitObject{kernel} {}
+ReadableEvent::~ReadableEvent() = default;
-SharedPtr<Event> Event::Create(KernelCore& kernel, ResetType reset_type, std::string name) {
- SharedPtr<Event> evt(new Event(kernel));
-
- evt->signaled = false;
- evt->reset_type = reset_type;
- evt->name = std::move(name);
-
- return evt;
-}
-
-bool Event::ShouldWait(Thread* thread) const {
+bool ReadableEvent::ShouldWait(Thread* thread) const {
return !signaled;
}
-void Event::Acquire(Thread* thread) {
+void ReadableEvent::Acquire(Thread* thread) {
ASSERT_MSG(!ShouldWait(thread), "object unavailable!");
if (reset_type == ResetType::OneShot)
signaled = false;
}
-void Event::Signal() {
+void ReadableEvent::Signal() {
signaled = true;
WakeupAllWaitingThreads();
}
-void Event::Clear() {
+void ReadableEvent::Clear() {
signaled = false;
}
-void Event::WakeupAllWaitingThreads() {
+void ReadableEvent::WakeupAllWaitingThreads() {
WaitObject::WakeupAllWaitingThreads();
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 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/kernel/object.h"
+#include "core/hle/kernel/wait_object.h"
+
+namespace Kernel {
+
+class KernelCore;
+class WritableEvent;
+
+class ReadableEvent final : public WaitObject {
+ friend class WritableEvent;
+
+public:
+ ~ReadableEvent() override;
+
+ std::string GetTypeName() const override {
+ return "ReadableEvent";
+ }
+ std::string GetName() const override {
+ return name;
+ }
+
+ ResetType GetResetType() const {
+ return reset_type;
+ }
+
+ static const HandleType HANDLE_TYPE = HandleType::ReadableEvent;
+ HandleType GetHandleType() const override {
+ return HANDLE_TYPE;
+ }
+
+ bool ShouldWait(Thread* thread) const override;
+ void Acquire(Thread* thread) override;
+
+ void WakeupAllWaitingThreads() override;
+
+ void Clear();
+
+private:
+ explicit ReadableEvent(KernelCore& kernel);
+
+ void Signal();
+
+ ResetType reset_type;
+ bool signaled;
+
+ std::string name; ///< Name of event (optional)
+};
+
+} // namespace Kernel
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 5e9660a48..e6c77f9db 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -20,21 +20,21 @@
#include "core/hle/kernel/address_arbiter.h"
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/client_session.h"
-#include "core/hle/kernel/event.h"
#include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/mutex.h"
#include "core/hle/kernel/process.h"
+#include "core/hle/kernel/readable_event.h"
#include "core/hle/kernel/resource_limit.h"
#include "core/hle/kernel/scheduler.h"
#include "core/hle/kernel/shared_memory.h"
#include "core/hle/kernel/svc.h"
#include "core/hle/kernel/svc_wrap.h"
#include "core/hle/kernel/thread.h"
+#include "core/hle/kernel/writable_event.h"
#include "core/hle/lock.h"
#include "core/hle/result.h"
#include "core/hle/service/service.h"
-#include "core/settings.h"
namespace Kernel {
namespace {
@@ -662,7 +662,7 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
TotalMemoryUsage = 6,
TotalHeapUsage = 7,
IsCurrentProcessBeingDebugged = 8,
- ResourceHandleLimit = 9,
+ RegisterResourceLimit = 9,
IdleTickCount = 10,
RandomEntropy = 11,
PerformanceCounter = 0xF0000002,
@@ -682,37 +682,137 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
ThreadTickCount = 0xF0000002,
};
- const auto* current_process = Core::CurrentProcess();
- const auto& vm_manager = current_process->VMManager();
+ const auto info_id_type = static_cast<GetInfoType>(info_id);
- switch (static_cast<GetInfoType>(info_id)) {
+ switch (info_id_type) {
case GetInfoType::AllowedCpuIdBitmask:
- *result = current_process->GetAllowedProcessorMask();
- break;
case GetInfoType::AllowedThreadPrioBitmask:
- *result = current_process->GetAllowedThreadPriorityMask();
- break;
case GetInfoType::MapRegionBaseAddr:
- *result = vm_manager.GetMapRegionBaseAddress();
- break;
case GetInfoType::MapRegionSize:
- *result = vm_manager.GetMapRegionSize();
- break;
case GetInfoType::HeapRegionBaseAddr:
- *result = vm_manager.GetHeapRegionBaseAddress();
- break;
case GetInfoType::HeapRegionSize:
- *result = vm_manager.GetHeapRegionSize();
- break;
+ case GetInfoType::ASLRRegionBaseAddr:
+ case GetInfoType::ASLRRegionSize:
+ case GetInfoType::NewMapRegionBaseAddr:
+ case GetInfoType::NewMapRegionSize:
case GetInfoType::TotalMemoryUsage:
- *result = vm_manager.GetTotalMemoryUsage();
- break;
case GetInfoType::TotalHeapUsage:
- *result = vm_manager.GetTotalHeapUsage();
- break;
+ case GetInfoType::IsVirtualAddressMemoryEnabled:
+ case GetInfoType::PersonalMmHeapUsage:
+ case GetInfoType::TitleId:
+ case GetInfoType::UserExceptionContextAddr: {
+ if (info_sub_id != 0) {
+ return ERR_INVALID_ENUM_VALUE;
+ }
+
+ const auto& current_process_handle_table = Core::CurrentProcess()->GetHandleTable();
+ const auto process = current_process_handle_table.Get<Process>(static_cast<Handle>(handle));
+ if (!process) {
+ return ERR_INVALID_HANDLE;
+ }
+
+ switch (info_id_type) {
+ case GetInfoType::AllowedCpuIdBitmask:
+ *result = process->GetAllowedProcessorMask();
+ return RESULT_SUCCESS;
+
+ case GetInfoType::AllowedThreadPrioBitmask:
+ *result = process->GetAllowedThreadPriorityMask();
+ return RESULT_SUCCESS;
+
+ case GetInfoType::MapRegionBaseAddr:
+ *result = process->VMManager().GetMapRegionBaseAddress();
+ return RESULT_SUCCESS;
+
+ case GetInfoType::MapRegionSize:
+ *result = process->VMManager().GetMapRegionSize();
+ return RESULT_SUCCESS;
+
+ case GetInfoType::HeapRegionBaseAddr:
+ *result = process->VMManager().GetHeapRegionBaseAddress();
+ return RESULT_SUCCESS;
+
+ case GetInfoType::HeapRegionSize:
+ *result = process->VMManager().GetHeapRegionSize();
+ return RESULT_SUCCESS;
+
+ case GetInfoType::ASLRRegionBaseAddr:
+ *result = process->VMManager().GetASLRRegionBaseAddress();
+ return RESULT_SUCCESS;
+
+ case GetInfoType::ASLRRegionSize:
+ *result = process->VMManager().GetASLRRegionSize();
+ return RESULT_SUCCESS;
+
+ case GetInfoType::NewMapRegionBaseAddr:
+ *result = process->VMManager().GetNewMapRegionBaseAddress();
+ return RESULT_SUCCESS;
+
+ case GetInfoType::NewMapRegionSize:
+ *result = process->VMManager().GetNewMapRegionSize();
+ return RESULT_SUCCESS;
+
+ case GetInfoType::TotalMemoryUsage:
+ *result = process->VMManager().GetTotalMemoryUsage();
+ return RESULT_SUCCESS;
+
+ case GetInfoType::TotalHeapUsage:
+ *result = process->VMManager().GetTotalHeapUsage();
+ return RESULT_SUCCESS;
+
+ case GetInfoType::IsVirtualAddressMemoryEnabled:
+ *result = process->IsVirtualMemoryEnabled();
+ return RESULT_SUCCESS;
+
+ case GetInfoType::TitleId:
+ *result = process->GetTitleID();
+ return RESULT_SUCCESS;
+
+ case GetInfoType::UserExceptionContextAddr:
+ LOG_WARNING(Kernel_SVC,
+ "(STUBBED) Attempted to query user exception context address, returned 0");
+ *result = 0;
+ return RESULT_SUCCESS;
+
+ default:
+ break;
+ }
+
+ LOG_WARNING(Kernel_SVC, "(STUBBED) Unimplemented svcGetInfo id=0x{:016X}", info_id);
+ return ERR_INVALID_ENUM_VALUE;
+ }
+
case GetInfoType::IsCurrentProcessBeingDebugged:
*result = 0;
- break;
+ return RESULT_SUCCESS;
+
+ case GetInfoType::RegisterResourceLimit: {
+ if (handle != 0) {
+ return ERR_INVALID_HANDLE;
+ }
+
+ if (info_sub_id != 0) {
+ return ERR_INVALID_COMBINATION;
+ }
+
+ Process* const current_process = Core::CurrentProcess();
+ HandleTable& handle_table = current_process->GetHandleTable();
+ const auto resource_limit = current_process->GetResourceLimit();
+ if (!resource_limit) {
+ *result = KernelHandle::InvalidHandle;
+ // Yes, the kernel considers this a successful operation.
+ return RESULT_SUCCESS;
+ }
+
+ const auto table_result = handle_table.Create(resource_limit);
+ if (table_result.Failed()) {
+ return table_result.Code();
+ }
+
+ *result = *table_result;
+ return RESULT_SUCCESS;
+ }
+
case GetInfoType::RandomEntropy:
if (handle != 0) {
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)
return ERR_INVALID_COMBINATION;
}
- *result = current_process->GetRandomEntropy(info_sub_id);
+ *result = Core::CurrentProcess()->GetRandomEntropy(info_sub_id);
return RESULT_SUCCESS;
- break;
- case GetInfoType::ASLRRegionBaseAddr:
- *result = vm_manager.GetASLRRegionBaseAddress();
- break;
- case GetInfoType::ASLRRegionSize:
- *result = vm_manager.GetASLRRegionSize();
- break;
- case GetInfoType::NewMapRegionBaseAddr:
- *result = vm_manager.GetNewMapRegionBaseAddress();
- break;
- case GetInfoType::NewMapRegionSize:
- *result = vm_manager.GetNewMapRegionSize();
- break;
- case GetInfoType::IsVirtualAddressMemoryEnabled:
- *result = current_process->IsVirtualMemoryEnabled();
- break;
- case GetInfoType::TitleId:
- *result = current_process->GetTitleID();
- break;
+
case GetInfoType::PrivilegedProcessId:
LOG_WARNING(Kernel_SVC,
"(STUBBED) Attempted to query privileged process id bounds, returned 0");
*result = 0;
- break;
- case GetInfoType::UserExceptionContextAddr:
- LOG_WARNING(Kernel_SVC,
- "(STUBBED) Attempted to query user exception context address, returned 0");
- *result = 0;
- break;
+ return RESULT_SUCCESS;
+
case GetInfoType::ThreadTickCount: {
constexpr u64 num_cpus = 4;
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)
}
const auto thread =
- current_process->GetHandleTable().Get<Thread>(static_cast<Handle>(handle));
+ Core::CurrentProcess()->GetHandleTable().Get<Thread>(static_cast<Handle>(handle));
if (!thread) {
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}",
static_cast<Handle>(handle));
@@ -789,14 +867,13 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
}
*result = out_ticks;
- break;
+ return RESULT_SUCCESS;
}
+
default:
LOG_WARNING(Kernel_SVC, "(STUBBED) Unimplemented svcGetInfo id=0x{:016X}", info_id);
return ERR_INVALID_ENUM_VALUE;
}
-
- return RESULT_SUCCESS;
}
/// Sets the thread activity
@@ -1042,9 +1119,9 @@ static void ExitProcess() {
static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, VAddr stack_top,
u32 priority, s32 processor_id) {
LOG_TRACE(Kernel_SVC,
- "called entrypoint=0x{:08X} ({}), arg=0x{:08X}, stacktop=0x{:08X}, "
+ "called entrypoint=0x{:08X}, arg=0x{:08X}, stacktop=0x{:08X}, "
"threadpriority=0x{:08X}, processorid=0x{:08X} : created handle=0x{:08X}",
- entry_point, name, arg, stack_top, priority, processor_id, *out_handle);
+ entry_point, arg, stack_top, priority, processor_id, *out_handle);
if (priority > THREADPRIO_LOWEST) {
LOG_ERROR(Kernel_SVC, "An invalid priority was specified, expected {} but got {}",
@@ -1361,7 +1438,7 @@ static ResultCode ResetSignal(Handle handle) {
LOG_DEBUG(Kernel_SVC, "called handle 0x{:08X}", handle);
const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
- auto event = handle_table.Get<Event>(handle);
+ auto event = handle_table.Get<ReadableEvent>(handle);
ASSERT(event != nullptr);
@@ -1520,17 +1597,67 @@ static ResultCode CreateSharedMemory(Handle* handle, u64 size, u32 local_permiss
return RESULT_SUCCESS;
}
+static ResultCode CreateEvent(Handle* write_handle, Handle* read_handle) {
+ LOG_DEBUG(Kernel_SVC, "called");
+
+ auto& kernel = Core::System::GetInstance().Kernel();
+ const auto [readable_event, writable_event] =
+ WritableEvent::CreateEventPair(kernel, ResetType::Sticky, "CreateEvent");
+
+ HandleTable& handle_table = kernel.CurrentProcess()->GetHandleTable();
+
+ const auto write_create_result = handle_table.Create(writable_event);
+ if (write_create_result.Failed()) {
+ return write_create_result.Code();
+ }
+ *write_handle = *write_create_result;
+
+ const auto read_create_result = handle_table.Create(readable_event);
+ if (read_create_result.Failed()) {
+ handle_table.Close(*write_create_result);
+ return read_create_result.Code();
+ }
+ *read_handle = *read_create_result;
+
+ LOG_DEBUG(Kernel_SVC,
+ "successful. Writable event handle=0x{:08X}, Readable event handle=0x{:08X}",
+ *write_create_result, *read_create_result);
+ return RESULT_SUCCESS;
+}
+
static ResultCode ClearEvent(Handle handle) {
LOG_TRACE(Kernel_SVC, "called, event=0x{:08X}", handle);
const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
- SharedPtr<Event> evt = handle_table.Get<Event>(handle);
- if (evt == nullptr) {
- LOG_ERROR(Kernel_SVC, "Event handle does not exist, handle=0x{:08X}", handle);
+
+ auto writable_event = handle_table.Get<WritableEvent>(handle);
+ if (writable_event) {
+ writable_event->Clear();
+ return RESULT_SUCCESS;
+ }
+
+ auto readable_event = handle_table.Get<ReadableEvent>(handle);
+ if (readable_event) {
+ readable_event->Clear();
+ return RESULT_SUCCESS;
+ }
+
+ LOG_ERROR(Kernel_SVC, "Event handle does not exist, handle=0x{:08X}", handle);
+ return ERR_INVALID_HANDLE;
+}
+
+static ResultCode SignalEvent(Handle handle) {
+ LOG_DEBUG(Kernel_SVC, "called. Handle=0x{:08X}", handle);
+
+ HandleTable& handle_table = Core::CurrentProcess()->GetHandleTable();
+ auto writable_event = handle_table.Get<WritableEvent>(handle);
+
+ if (!writable_event) {
+ LOG_ERROR(Kernel_SVC, "Non-existent writable event handle used (0x{:08X})", handle);
return ERR_INVALID_HANDLE;
}
- evt->Clear();
+ writable_event->Signal();
return RESULT_SUCCESS;
}
@@ -1669,7 +1796,7 @@ static const FunctionDef SVC_Table[] = {
{0x0E, SvcWrap<GetThreadCoreMask>, "GetThreadCoreMask"},
{0x0F, SvcWrap<SetThreadCoreMask>, "SetThreadCoreMask"},
{0x10, SvcWrap<GetCurrentProcessorNumber>, "GetCurrentProcessorNumber"},
- {0x11, nullptr, "SignalEvent"},
+ {0x11, SvcWrap<SignalEvent>, "SignalEvent"},
{0x12, SvcWrap<ClearEvent>, "ClearEvent"},
{0x13, SvcWrap<MapSharedMemory>, "MapSharedMemory"},
{0x14, SvcWrap<UnmapSharedMemory>, "UnmapSharedMemory"},
@@ -1721,7 +1848,7 @@ static const FunctionDef SVC_Table[] = {
{0x42, nullptr, "ReplyAndReceiveLight"},
{0x43, nullptr, "ReplyAndReceive"},
{0x44, nullptr, "ReplyAndReceiveWithUserBuffer"},
- {0x45, nullptr, "CreateEvent"},
+ {0x45, SvcWrap<CreateEvent>, "CreateEvent"},
{0x46, nullptr, "Unknown"},
{0x47, nullptr, "Unknown"},
{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() {
FuncReturn(retval);
}
+template <ResultCode func(u32*, u32*)>
+void SvcWrap() {
+ u32 param_1 = 0;
+ u32 param_2 = 0;
+ const u32 retval = func(&param_1, &param_2).raw;
+
+ auto& arm_interface = Core::CurrentArmInterface();
+ arm_interface.SetReg(1, param_1);
+ arm_interface.SetReg(2, param_2);
+
+ FuncReturn(retval);
+}
+
template <ResultCode func(u32*, u64)>
void SvcWrap() {
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 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <algorithm>
+#include "common/assert.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/object.h"
+#include "core/hle/kernel/readable_event.h"
+#include "core/hle/kernel/thread.h"
+#include "core/hle/kernel/writable_event.h"
+
+namespace Kernel {
+
+WritableEvent::WritableEvent(KernelCore& kernel) : Object{kernel} {}
+WritableEvent::~WritableEvent() = default;
+
+EventPair WritableEvent::CreateEventPair(KernelCore& kernel, ResetType reset_type,
+ std::string name) {
+ SharedPtr<WritableEvent> writable_event(new WritableEvent(kernel));
+ SharedPtr<ReadableEvent> readable_event(new ReadableEvent(kernel));
+
+ writable_event->name = name + ":Writable";
+ writable_event->readable = readable_event;
+ readable_event->name = name + ":Readable";
+ readable_event->signaled = false;
+ readable_event->reset_type = reset_type;
+
+ return {std::move(readable_event), std::move(writable_event)};
+}
+
+SharedPtr<ReadableEvent> WritableEvent::GetReadableEvent() const {
+ return readable;
+}
+
+ResetType WritableEvent::GetResetType() const {
+ return readable->reset_type;
+}
+
+void WritableEvent::Signal() {
+ readable->Signal();
+}
+
+void WritableEvent::Clear() {
+ readable->Clear();
+}
+
+bool WritableEvent::IsSignaled() const {
+ return readable->signaled;
+}
+
+} // 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 @@
namespace Kernel {
class KernelCore;
+class ReadableEvent;
+class WritableEvent;
-class Event final : public WaitObject {
+struct EventPair {
+ SharedPtr<ReadableEvent> readable;
+ SharedPtr<WritableEvent> writable;
+};
+
+class WritableEvent final : public Object {
public:
+ ~WritableEvent() override;
+
/**
* Creates an event
* @param kernel The kernel instance to create this event under.
* @param reset_type ResetType describing how to create event
* @param name Optional name of event
*/
- static SharedPtr<Event> Create(KernelCore& kernel, ResetType reset_type,
- std::string name = "Unknown");
+ static EventPair CreateEventPair(KernelCore& kernel, ResetType reset_type,
+ std::string name = "Unknown");
std::string GetTypeName() const override {
- return "Event";
+ return "WritableEvent";
}
std::string GetName() const override {
return name;
}
- static const HandleType HANDLE_TYPE = HandleType::Event;
+ static const HandleType HANDLE_TYPE = HandleType::WritableEvent;
HandleType GetHandleType() const override {
return HANDLE_TYPE;
}
- ResetType GetResetType() const {
- return reset_type;
- }
-
- bool ShouldWait(Thread* thread) const override;
- void Acquire(Thread* thread) override;
+ SharedPtr<ReadableEvent> GetReadableEvent() const;
- void WakeupAllWaitingThreads() override;
+ ResetType GetResetType() const;
void Signal();
void Clear();
+ bool IsSignaled() const;
private:
- explicit Event(KernelCore& kernel);
- ~Event() override;
+ explicit WritableEvent(KernelCore& kernel);
- ResetType reset_type; ///< Current ResetType
+ SharedPtr<ReadableEvent> readable;
- bool signaled; ///< Whether the event has already been signaled
std::string name; ///< Name of event (optional)
};
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 @@
#include "audio_core/audio_renderer.h"
#include "core/core.h"
#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/event.h"
+#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/process.h"
+#include "core/hle/kernel/readable_event.h"
#include "core/hle/kernel/shared_memory.h"
+#include "core/hle/kernel/writable_event.h"
#include "core/hle/service/acc/profile_manager.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applet_ae.h"
@@ -208,8 +210,8 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger
RegisterHandlers(functions);
auto& kernel = Core::System::GetInstance().Kernel();
- launchable_event =
- Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "ISelfController:LaunchableEvent");
+ launchable_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
+ "ISelfController:LaunchableEvent");
}
ISelfController::~ISelfController() = default;
@@ -295,11 +297,11 @@ void ISelfController::UnlockExit(Kernel::HLERequestContext& ctx) {
void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
- launchable_event->Signal();
+ launchable_event.writable->Signal();
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(launchable_event);
+ rb.PushCopyObjects(launchable_event.readable);
}
void ISelfController::SetScreenShotImageOrientation(Kernel::HLERequestContext& ctx) {
@@ -348,36 +350,38 @@ void ISelfController::GetIdleTimeDetectionExtension(Kernel::HLERequestContext& c
AppletMessageQueue::AppletMessageQueue() {
auto& kernel = Core::System::GetInstance().Kernel();
- on_new_message = Kernel::Event::Create(kernel, Kernel::ResetType::Sticky,
- "AMMessageQueue:OnMessageRecieved");
- on_operation_mode_changed = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot,
- "AMMessageQueue:OperationModeChanged");
+ on_new_message = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
+ "AMMessageQueue:OnMessageRecieved");
+ on_operation_mode_changed = Kernel::WritableEvent::CreateEventPair(
+ kernel, Kernel::ResetType::OneShot, "AMMessageQueue:OperationModeChanged");
}
AppletMessageQueue::~AppletMessageQueue() = default;
-const Kernel::SharedPtr<Kernel::Event>& AppletMessageQueue::GetMesssageRecieveEvent() const {
- return on_new_message;
+const Kernel::SharedPtr<Kernel::ReadableEvent>& AppletMessageQueue::GetMesssageRecieveEvent()
+ const {
+ return on_new_message.readable;
}
-const Kernel::SharedPtr<Kernel::Event>& AppletMessageQueue::GetOperationModeChangedEvent() const {
- return on_operation_mode_changed;
+const Kernel::SharedPtr<Kernel::ReadableEvent>& AppletMessageQueue::GetOperationModeChangedEvent()
+ const {
+ return on_operation_mode_changed.readable;
}
void AppletMessageQueue::PushMessage(AppletMessage msg) {
messages.push(msg);
- on_new_message->Signal();
+ on_new_message.writable->Signal();
}
AppletMessageQueue::AppletMessage AppletMessageQueue::PopMessage() {
if (messages.empty()) {
- on_new_message->Clear();
+ on_new_message.writable->Clear();
return AppletMessage::NoMessage;
}
auto msg = messages.front();
messages.pop();
if (messages.empty()) {
- on_new_message->Clear();
+ on_new_message.writable->Clear();
}
return msg;
}
@@ -389,7 +393,7 @@ std::size_t AppletMessageQueue::GetMessageCount() const {
void AppletMessageQueue::OperationModeChanged() {
PushMessage(AppletMessage::OperationModeChanged);
PushMessage(AppletMessage::PerformanceModeChanged);
- on_operation_mode_changed->Signal();
+ on_operation_mode_changed.writable->Signal();
}
ICommonStateGetter::ICommonStateGetter(std::shared_ptr<AppletMessageQueue> msg_queue)
@@ -426,9 +430,6 @@ ICommonStateGetter::ICommonStateGetter(std::shared_ptr<AppletMessageQueue> msg_q
// clang-format on
RegisterHandlers(functions);
-
- auto& kernel = Core::System::GetInstance().Kernel();
- event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "ICommonStateGetter:Event");
}
ICommonStateGetter::~ICommonStateGetter() = default;
@@ -564,8 +565,8 @@ private:
void GetAppletStateChangedEvent(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
+ applet->GetBroker().SignalStateChanged();
const auto event = applet->GetBroker().GetStateChangedEvent();
- event->Signal();
IPC::ResponseBuilder rb{ctx, 2, 1};
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 @@
#include <memory>
#include <queue>
+#include "core/hle/kernel/writable_event.h"
#include "core/hle/service/service.h"
-namespace Kernel {
-class Event;
-}
-
namespace Service {
namespace NVFlinger {
class NVFlinger;
@@ -52,8 +49,8 @@ public:
AppletMessageQueue();
~AppletMessageQueue();
- const Kernel::SharedPtr<Kernel::Event>& GetMesssageRecieveEvent() const;
- const Kernel::SharedPtr<Kernel::Event>& GetOperationModeChangedEvent() const;
+ const Kernel::SharedPtr<Kernel::ReadableEvent>& GetMesssageRecieveEvent() const;
+ const Kernel::SharedPtr<Kernel::ReadableEvent>& GetOperationModeChangedEvent() const;
void PushMessage(AppletMessage msg);
AppletMessage PopMessage();
std::size_t GetMessageCount() const;
@@ -61,8 +58,8 @@ public:
private:
std::queue<AppletMessage> messages;
- Kernel::SharedPtr<Kernel::Event> on_new_message;
- Kernel::SharedPtr<Kernel::Event> on_operation_mode_changed;
+ Kernel::EventPair on_new_message;
+ Kernel::EventPair on_operation_mode_changed;
};
class IWindowController final : public ServiceFramework<IWindowController> {
@@ -122,7 +119,7 @@ private:
void GetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx);
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
- Kernel::SharedPtr<Kernel::Event> launchable_event;
+ Kernel::EventPair launchable_event;
u32 idle_time_detection_extension = 0;
};
@@ -151,7 +148,6 @@ private:
void GetBootMode(Kernel::HLERequestContext& ctx);
void GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx);
- Kernel::SharedPtr<Kernel::Event> event;
std::shared_ptr<AppletMessageQueue> msg_queue;
};
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 @@
#include <cstring>
#include "common/assert.h"
#include "core/core.h"
-#include "core/hle/kernel/event.h"
+#include "core/hle/kernel/readable_event.h"
#include "core/hle/kernel/server_port.h"
+#include "core/hle/kernel/writable_event.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applets/applets.h"
@@ -14,11 +15,11 @@ namespace Service::AM::Applets {
AppletDataBroker::AppletDataBroker() {
auto& kernel = Core::System::GetInstance().Kernel();
- state_changed_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot,
- "ILibraryAppletAccessor:StateChangedEvent");
- pop_out_data_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot,
- "ILibraryAppletAccessor:PopDataOutEvent");
- pop_interactive_out_data_event = Kernel::Event::Create(
+ state_changed_event = Kernel::WritableEvent::CreateEventPair(
+ kernel, Kernel::ResetType::OneShot, "ILibraryAppletAccessor:StateChangedEvent");
+ pop_out_data_event = Kernel::WritableEvent::CreateEventPair(
+ kernel, Kernel::ResetType::OneShot, "ILibraryAppletAccessor:PopDataOutEvent");
+ pop_interactive_out_data_event = Kernel::WritableEvent::CreateEventPair(
kernel, Kernel::ResetType::OneShot, "ILibraryAppletAccessor:PopInteractiveDataOutEvent");
}
@@ -66,7 +67,7 @@ void AppletDataBroker::PushNormalDataFromGame(IStorage storage) {
void AppletDataBroker::PushNormalDataFromApplet(IStorage storage) {
out_channel.push(std::make_unique<IStorage>(storage));
- pop_out_data_event->Signal();
+ pop_out_data_event.writable->Signal();
}
void AppletDataBroker::PushInteractiveDataFromGame(IStorage storage) {
@@ -75,23 +76,23 @@ void AppletDataBroker::PushInteractiveDataFromGame(IStorage storage) {
void AppletDataBroker::PushInteractiveDataFromApplet(IStorage storage) {
out_interactive_channel.push(std::make_unique<IStorage>(storage));
- pop_interactive_out_data_event->Signal();
+ pop_interactive_out_data_event.writable->Signal();
}
void AppletDataBroker::SignalStateChanged() const {
- state_changed_event->Signal();
+ state_changed_event.writable->Signal();
}
-Kernel::SharedPtr<Kernel::Event> AppletDataBroker::GetNormalDataEvent() const {
- return pop_out_data_event;
+Kernel::SharedPtr<Kernel::ReadableEvent> AppletDataBroker::GetNormalDataEvent() const {
+ return pop_out_data_event.readable;
}
-Kernel::SharedPtr<Kernel::Event> AppletDataBroker::GetInteractiveDataEvent() const {
- return pop_interactive_out_data_event;
+Kernel::SharedPtr<Kernel::ReadableEvent> AppletDataBroker::GetInteractiveDataEvent() const {
+ return pop_interactive_out_data_event.readable;
}
-Kernel::SharedPtr<Kernel::Event> AppletDataBroker::GetStateChangedEvent() const {
- return state_changed_event;
+Kernel::SharedPtr<Kernel::ReadableEvent> AppletDataBroker::GetStateChangedEvent() const {
+ return state_changed_event.readable;
}
Applet::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 @@
#include <queue>
#include "common/swap.h"
#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/writable_event.h"
union ResultCode;
-namespace Kernel {
-class Event;
-}
-
namespace Service::AM {
class IStorage;
@@ -40,9 +37,9 @@ public:
void SignalStateChanged() const;
- Kernel::SharedPtr<Kernel::Event> GetNormalDataEvent() const;
- Kernel::SharedPtr<Kernel::Event> GetInteractiveDataEvent() const;
- Kernel::SharedPtr<Kernel::Event> GetStateChangedEvent() const;
+ Kernel::SharedPtr<Kernel::ReadableEvent> GetNormalDataEvent() const;
+ Kernel::SharedPtr<Kernel::ReadableEvent> GetInteractiveDataEvent() const;
+ Kernel::SharedPtr<Kernel::ReadableEvent> GetStateChangedEvent() const;
private:
// Queues are named from applet's perspective
@@ -59,13 +56,13 @@ private:
// PopInteractiveDataToGame and PushInteractiveDataFromApplet
std::queue<std::unique_ptr<IStorage>> out_interactive_channel;
- Kernel::SharedPtr<Kernel::Event> state_changed_event;
+ Kernel::EventPair state_changed_event;
// Signaled on PushNormalDataFromApplet
- Kernel::SharedPtr<Kernel::Event> pop_out_data_event;
+ Kernel::EventPair pop_out_data_event;
// Signaled on PushInteractiveDataFromApplet
- Kernel::SharedPtr<Kernel::Event> pop_interactive_out_data_event;
+ Kernel::EventPair pop_interactive_out_data_event;
};
class 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 @@
#include "core/file_sys/patch_manager.h"
#include "core/file_sys/registered_cache.h"
#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/event.h"
+#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/process.h"
+#include "core/hle/kernel/readable_event.h"
+#include "core/hle/kernel/writable_event.h"
#include "core/hle/service/aoc/aoc_u.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/loader/loader.h"
@@ -32,14 +34,14 @@ static std::vector<u64> AccumulateAOCTitleIDs() {
std::vector<u64> add_on_content;
const auto rcu = FileSystem::GetUnionContents();
const auto list =
- rcu->ListEntriesFilter(FileSys::TitleType::AOC, FileSys::ContentRecordType::Data);
+ rcu.ListEntriesFilter(FileSys::TitleType::AOC, FileSys::ContentRecordType::Data);
std::transform(list.begin(), list.end(), std::back_inserter(add_on_content),
[](const FileSys::RegisteredCacheEntry& rce) { return rce.title_id; });
add_on_content.erase(
std::remove_if(
add_on_content.begin(), add_on_content.end(),
[&rcu](u64 tid) {
- return rcu->GetEntry(tid, FileSys::ContentRecordType::Data)->GetStatus() !=
+ return rcu.GetEntry(tid, FileSys::ContentRecordType::Data)->GetStatus() !=
Loader::ResultStatus::Success;
}),
add_on_content.end());
@@ -61,8 +63,8 @@ AOC_U::AOC_U() : ServiceFramework("aoc:u"), add_on_content(AccumulateAOCTitleIDs
RegisterHandlers(functions);
auto& kernel = Core::System::GetInstance().Kernel();
- aoc_change_event = Kernel::Event::Create(kernel, Kernel::ResetType::Sticky,
- "GetAddOnContentListChanged:Event");
+ aoc_change_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
+ "GetAddOnContentListChanged:Event");
}
AOC_U::~AOC_U() = default;
@@ -144,7 +146,7 @@ void AOC_U::GetAddOnContentListChangedEvent(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(aoc_change_event);
+ rb.PushCopyObjects(aoc_change_event.readable);
}
void 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 @@
#include "core/hle/service/service.h"
+namespace Kernel {
+class WritableEvent;
+}
+
namespace Service::AOC {
class AOC_U final : public ServiceFramework<AOC_U> {
@@ -21,7 +25,7 @@ private:
void GetAddOnContentListChangedEvent(Kernel::HLERequestContext& ctx);
std::vector<u64> add_on_content;
- Kernel::SharedPtr<Kernel::Event> aoc_change_event;
+ Kernel::EventPair aoc_change_event;
};
/// 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 @@
#include "common/swap.h"
#include "core/core.h"
#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/event.h"
#include "core/hle/kernel/hle_ipc.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/readable_event.h"
+#include "core/hle/kernel/writable_event.h"
#include "core/hle/service/audio/audout_u.h"
#include "core/memory.h"
@@ -46,8 +48,8 @@ class IAudioOut final : public ServiceFramework<IAudioOut> {
public:
IAudioOut(AudoutParams audio_params, AudioCore::AudioOut& audio_core, std::string&& device_name,
std::string&& unique_name)
- : ServiceFramework("IAudioOut"), audio_core(audio_core), audio_params(audio_params),
- device_name(std::move(device_name)) {
+ : ServiceFramework("IAudioOut"), audio_core(audio_core),
+ device_name(std::move(device_name)), audio_params(audio_params) {
static const FunctionInfo functions[] = {
{0, &IAudioOut::GetAudioOutState, "GetAudioOutState"},
@@ -67,11 +69,12 @@ public:
// This is the event handle used to check if the audio buffer was released
auto& kernel = Core::System::GetInstance().Kernel();
- buffer_event =
- Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "IAudioOutBufferReleased");
+ buffer_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
+ "IAudioOutBufferReleased");
stream = audio_core.OpenStream(audio_params.sample_rate, audio_params.channel_count,
- std::move(unique_name), [=]() { buffer_event->Signal(); });
+ std::move(unique_name),
+ [=]() { buffer_event.writable->Signal(); });
}
private:
@@ -121,7 +124,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(buffer_event);
+ rb.PushCopyObjects(buffer_event.readable);
}
void AppendAudioOutBufferImpl(Kernel::HLERequestContext& ctx) {
@@ -187,8 +190,8 @@ private:
AudoutParams audio_params{};
- /// This is the evend handle used to check if the audio buffer was released
- Kernel::SharedPtr<Kernel::Event> buffer_event;
+ /// This is the event handle used to check if the audio buffer was released
+ Kernel::EventPair buffer_event;
};
void 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 @@
#include "common/logging/log.h"
#include "core/core.h"
#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/event.h"
#include "core/hle/kernel/hle_ipc.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/readable_event.h"
+#include "core/hle/kernel/writable_event.h"
#include "core/hle/service/audio/audren_u.h"
namespace Service::Audio {
@@ -41,14 +43,14 @@ public:
RegisterHandlers(functions);
auto& kernel = Core::System::GetInstance().Kernel();
- system_event =
- Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "IAudioRenderer:SystemEvent");
- renderer = std::make_unique<AudioCore::AudioRenderer>(audren_params, system_event);
+ system_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
+ "IAudioRenderer:SystemEvent");
+ renderer = std::make_unique<AudioCore::AudioRenderer>(audren_params, system_event.writable);
}
private:
void UpdateAudioCallback() {
- system_event->Signal();
+ system_event.writable->Signal();
}
void GetSampleRate(Kernel::HLERequestContext& ctx) {
@@ -112,7 +114,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(system_event);
+ rb.PushCopyObjects(system_event.readable);
}
void SetRenderingTimeLimit(Kernel::HLERequestContext& ctx) {
@@ -135,7 +137,7 @@ private:
rb.Push(rendering_time_limit_percent);
}
- Kernel::SharedPtr<Kernel::Event> system_event;
+ Kernel::EventPair system_event;
std::unique_ptr<AudioCore::AudioRenderer> renderer;
u32 rendering_time_limit_percent = 100;
};
@@ -162,8 +164,8 @@ public:
RegisterHandlers(functions);
auto& kernel = Core::System::GetInstance().Kernel();
- buffer_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot,
- "IAudioOutBufferReleasedEvent");
+ buffer_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
+ "IAudioOutBufferReleasedEvent");
}
private:
@@ -207,11 +209,11 @@ private:
void QueryAudioDeviceSystemEvent(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_Audio, "(STUBBED) called");
- buffer_event->Signal();
+ buffer_event.writable->Signal();
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(buffer_event);
+ rb.PushCopyObjects(buffer_event.readable);
}
void GetActiveChannelCount(Kernel::HLERequestContext& ctx) {
@@ -222,7 +224,7 @@ private:
rb.Push<u32>(1);
}
- Kernel::SharedPtr<Kernel::Event> buffer_event;
+ Kernel::EventPair buffer_event;
}; // namespace Audio
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 @@
#include "common/logging/log.h"
#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/event.h"
#include "core/hle/kernel/hle_ipc.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/readable_event.h"
+#include "core/hle/kernel/writable_event.h"
#include "core/hle/service/btdrv/btdrv.h"
#include "core/hle/service/service.h"
#include "core/hle/service/sm/sm.h"
@@ -30,20 +32,22 @@ public:
};
// clang-format on
RegisterHandlers(functions);
+
+ auto& kernel = Core::System::GetInstance().Kernel();
+ register_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
+ "BT:RegisterEvent");
}
private:
void RegisterEvent(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_BTM, "(STUBBED) called");
- auto& kernel = Core::System::GetInstance().Kernel();
- register_event =
- Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "BT:RegisterEvent");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(register_event);
+ rb.PushCopyObjects(register_event.readable);
}
- Kernel::SharedPtr<Kernel::Event> register_event;
+
+ Kernel::EventPair register_event;
};
class 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 @@
#include "common/logging/log.h"
#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/event.h"
#include "core/hle/kernel/hle_ipc.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/readable_event.h"
+#include "core/hle/kernel/writable_event.h"
#include "core/hle/service/btm/btm.h"
#include "core/hle/service/service.h"
@@ -53,53 +55,55 @@ public:
};
// clang-format on
RegisterHandlers(functions);
+
+ auto& kernel = Core::System::GetInstance().Kernel();
+ scan_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
+ "IBtmUserCore:ScanEvent");
+ connection_event = Kernel::WritableEvent::CreateEventPair(
+ kernel, Kernel::ResetType::OneShot, "IBtmUserCore:ConnectionEvent");
+ service_discovery = Kernel::WritableEvent::CreateEventPair(
+ kernel, Kernel::ResetType::OneShot, "IBtmUserCore:Discovery");
+ config_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
+ "IBtmUserCore:ConfigEvent");
}
private:
void GetScanEvent(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_BTM, "(STUBBED) called");
- auto& kernel = Core::System::GetInstance().Kernel();
- scan_event =
- Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IBtmUserCore:ScanEvent");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(scan_event);
+ rb.PushCopyObjects(scan_event.readable);
}
+
void GetConnectionEvent(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_BTM, "(STUBBED) called");
- auto& kernel = Core::System::GetInstance().Kernel();
- connection_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot,
- "IBtmUserCore:ConnectionEvent");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(connection_event);
+ rb.PushCopyObjects(connection_event.readable);
}
+
void GetDiscoveryEvent(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_BTM, "(STUBBED) called");
- auto& kernel = Core::System::GetInstance().Kernel();
- service_discovery =
- Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IBtmUserCore:Discovery");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(service_discovery);
+ rb.PushCopyObjects(service_discovery.readable);
}
+
void GetConfigEvent(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_BTM, "(STUBBED) called");
- auto& kernel = Core::System::GetInstance().Kernel();
- config_event =
- Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IBtmUserCore:ConfigEvent");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(config_event);
+ rb.PushCopyObjects(config_event.readable);
}
- Kernel::SharedPtr<Kernel::Event> scan_event;
- Kernel::SharedPtr<Kernel::Event> connection_event;
- Kernel::SharedPtr<Kernel::Event> service_discovery;
- Kernel::SharedPtr<Kernel::Event> config_event;
+
+ Kernel::EventPair scan_event;
+ Kernel::EventPair connection_event;
+ Kernel::EventPair service_discovery;
+ Kernel::EventPair config_event;
};
class 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:
static const FunctionInfo functions[] = {
{0, nullptr, "SubmitContext"},
{1, nullptr, "CreateReport"},
- {2, nullptr, "Unknown1"},
- {3, nullptr, "Unknown2"},
- {4, nullptr, "Unknown3"},
- {5, nullptr, "Unknown4"},
- {6, nullptr, "Unknown5"},
+ {2, nullptr, "SetInitialLaunchSettingsCompletionTime"},
+ {3, nullptr, "ClearInitialLaunchSettingsCompletionTime"},
+ {4, nullptr, "UpdatePowerOnTime"},
+ {5, nullptr, "UpdateAwakeTime"},
+ {6, nullptr, "SubmitMultipleCategoryContext"},
+ {7, nullptr, "UpdateApplicationLaunchTime"},
+ {8, nullptr, "ClearApplicationLaunchTime"},
};
// clang-format on
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
return RESULT_SUCCESS;
}
+ResultCode VfsDirectoryServiceWrapper::CleanDirectoryRecursively(const std::string& path) const {
+ const std::string sanitized_path(FileUtil::SanitizePath(path));
+ auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(sanitized_path));
+
+ if (!dir->CleanSubdirectoryRecursive(FileUtil::GetFilename(sanitized_path))) {
+ // TODO(DarkLordZach): Find a better error code for this
+ return ResultCode(-1);
+ }
+
+ return RESULT_SUCCESS;
+}
+
ResultCode VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path_,
const std::string& dest_path_) const {
std::string src_path(FileUtil::SanitizePath(src_path_));
@@ -329,20 +341,9 @@ ResultVal<FileSys::VirtualDir> OpenSDMC() {
return sdmc_factory->Open();
}
-std::shared_ptr<FileSys::RegisteredCacheUnion> registered_cache_union;
-
-std::shared_ptr<FileSys::RegisteredCacheUnion> GetUnionContents() {
- if (registered_cache_union == nullptr) {
- registered_cache_union =
- std::make_shared<FileSys::RegisteredCacheUnion>(std::vector<FileSys::RegisteredCache*>{
- GetSystemNANDContents(), GetUserNANDContents(), GetSDMCContents()});
- }
-
- return registered_cache_union;
-}
-
-void ClearUnionContents() {
- registered_cache_union = nullptr;
+FileSys::RegisteredCacheUnion GetUnionContents() {
+ return FileSys::RegisteredCacheUnion{
+ {GetSystemNANDContents(), GetUserNANDContents(), GetSDMCContents()}};
}
FileSys::RegisteredCache* GetSystemNANDContents() {
@@ -395,7 +396,6 @@ void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) {
bis_factory = nullptr;
save_data_factory = nullptr;
sdmc_factory = nullptr;
- ClearUnionContents();
}
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,
ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space);
ResultVal<FileSys::VirtualDir> OpenSDMC();
-std::shared_ptr<FileSys::RegisteredCacheUnion> GetUnionContents();
-void ClearUnionContents();
+FileSys::RegisteredCacheUnion GetUnionContents();
FileSys::RegisteredCache* GetSystemNANDContents();
FileSys::RegisteredCache* GetUserNANDContents();
@@ -114,6 +113,18 @@ public:
ResultCode DeleteDirectoryRecursively(const std::string& path) const;
/**
+ * Cleans the specified directory. This is similar to DeleteDirectoryRecursively,
+ * in that it deletes all the contents of the specified directory, however, this
+ * function does *not* delete the directory itself. It only deletes everything
+ * within it.
+ *
+ * @param path Path relative to the archive.
+ *
+ * @return Result of the operation.
+ */
+ ResultCode CleanDirectoryRecursively(const std::string& path) const;
+
+ /**
* Rename a File specified by its path
* @param src_path Source path relative to the archive
* @param dest_path Destination path relative to the archive
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index 99d9ebc39..d2ffd5776 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -20,6 +20,7 @@
#include "core/file_sys/nca_metadata.h"
#include "core/file_sys/patch_manager.h"
#include "core/file_sys/savedata_factory.h"
+#include "core/file_sys/system_archive/system_archive.h"
#include "core/file_sys/vfs.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/process.h"
@@ -291,7 +292,7 @@ public:
{10, &IFileSystem::Commit, "Commit"},
{11, nullptr, "GetFreeSpaceSize"},
{12, nullptr, "GetTotalSpaceSize"},
- {13, nullptr, "CleanDirectoryRecursively"},
+ {13, &IFileSystem::CleanDirectoryRecursively, "CleanDirectoryRecursively"},
{14, nullptr, "GetFileTimeStampRaw"},
{15, nullptr, "QueryEntry"},
};
@@ -361,6 +362,16 @@ public:
rb.Push(backend.DeleteDirectoryRecursively(name));
}
+ void CleanDirectoryRecursively(Kernel::HLERequestContext& ctx) {
+ const auto file_buffer = ctx.ReadBuffer();
+ const std::string name = Common::StringFromBuffer(file_buffer);
+
+ LOG_DEBUG(Service_FS, "called. Directory: {}", name);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(backend.CleanDirectoryRecursively(name));
+ }
+
void RenameFile(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
@@ -821,6 +832,15 @@ void FSP_SRV::OpenDataStorageByDataId(Kernel::HLERequestContext& ctx) {
auto data = OpenRomFS(title_id, storage_id, FileSys::ContentRecordType::Data);
if (data.Failed()) {
+ const auto archive = FileSys::SystemArchive::SynthesizeSystemArchive(title_id);
+
+ if (archive != nullptr) {
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushIpcInterface(std::make_shared<IStorage>(archive));
+ return;
+ }
+
// TODO(DarkLordZach): Find the right error code to use here
LOG_ERROR(Service_FS,
"could not open data storage with title_id={:016X}, storage_id={:02X}", title_id,
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 22e87a50a..d6829d0b8 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -12,7 +12,9 @@
#include "core/core.h"
#include "core/core_timing.h"
#include "core/frontend/input.h"
-#include "core/hle/kernel/event.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/readable_event.h"
+#include "core/hle/kernel/writable_event.h"
#include "core/hle/service/hid/controllers/npad.h"
#include "core/settings.h"
@@ -167,8 +169,8 @@ void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) {
void Controller_NPad::OnInit() {
auto& kernel = Core::System::GetInstance().Kernel();
- styleset_changed_event =
- Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "npad:NpadStyleSetChanged");
+ styleset_changed_event = Kernel::WritableEvent::CreateEventPair(
+ kernel, Kernel::ResetType::OneShot, "npad:NpadStyleSetChanged");
if (!IsControllerActivated()) {
return;
@@ -494,7 +496,7 @@ void Controller_NPad::SetSupportedNPadIdTypes(u8* data, std::size_t length) {
had_controller_update = true;
}
if (had_controller_update) {
- styleset_changed_event->Signal();
+ styleset_changed_event.writable->Signal();
}
}
}
@@ -509,7 +511,7 @@ std::size_t Controller_NPad::GetSupportedNPadIdTypesSize() const {
}
void Controller_NPad::SetHoldType(NpadHoldType joy_hold_type) {
- styleset_changed_event->Signal();
+ styleset_changed_event.writable->Signal();
hold_type = joy_hold_type;
}
@@ -518,8 +520,9 @@ Controller_NPad::NpadHoldType Controller_NPad::GetHoldType() const {
}
void Controller_NPad::SetNpadMode(u32 npad_id, NPadAssignments assignment_mode) {
- ASSERT(npad_id < shared_memory_entries.size());
- shared_memory_entries[npad_id].pad_assignment = assignment_mode;
+ const std::size_t npad_index = NPadIdToIndex(npad_id);
+ ASSERT(npad_index < shared_memory_entries.size());
+ shared_memory_entries[npad_index].pad_assignment = assignment_mode;
}
void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids,
@@ -538,11 +541,11 @@ void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids,
last_processed_vibration = vibrations.back();
}
-Kernel::SharedPtr<Kernel::Event> Controller_NPad::GetStyleSetChangedEvent() const {
+Kernel::SharedPtr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent() const {
// TODO(ogniK): Figure out the best time to signal this event. This event seems that it should
// be signalled at least once, and signaled after a new controller is connected?
- styleset_changed_event->Signal();
- return styleset_changed_event;
+ styleset_changed_event.writable->Signal();
+ return styleset_changed_event.readable;
}
Controller_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 @@
#include "common/bit_field.h"
#include "common/common_types.h"
#include "core/frontend/input.h"
-#include "core/hle/kernel/event.h"
+#include "core/hle/kernel/object.h"
+#include "core/hle/kernel/writable_event.h"
#include "core/hle/service/hid/controllers/controller_base.h"
#include "core/settings.h"
@@ -108,7 +109,7 @@ public:
void VibrateController(const std::vector<u32>& controller_ids,
const std::vector<Vibration>& vibrations);
- Kernel::SharedPtr<Kernel::Event> GetStyleSetChangedEvent() const;
+ Kernel::SharedPtr<Kernel::ReadableEvent> GetStyleSetChangedEvent() const;
Vibration GetLastVibration() const;
void AddNewController(NPadControllerType controller);
@@ -303,7 +304,7 @@ private:
sticks;
std::vector<u32> supported_npad_id_types{};
NpadHoldType hold_type{NpadHoldType::Vertical};
- Kernel::SharedPtr<Kernel::Event> styleset_changed_event;
+ Kernel::EventPair styleset_changed_event;
Vibration last_processed_vibration{};
std::array<ControllerHolder, 10> connected_controllers{};
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 @@
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/client_session.h"
-#include "core/hle/kernel/event.h"
+#include "core/hle/kernel/readable_event.h"
#include "core/hle/kernel/shared_memory.h"
+#include "core/hle/kernel/writable_event.h"
#include "core/hle/service/hid/hid.h"
#include "core/hle/service/hid/irs.h"
#include "core/hle/service/hid/xcd.h"
diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp
index ca119dd3a..453d90a22 100644
--- a/src/core/hle/service/ldr/ldr.cpp
+++ b/src/core/hle/service/ldr/ldr.cpp
@@ -335,10 +335,7 @@ public:
vm_manager.ReprotectRange(*map_address + header.rw_offset, header.rw_size,
Kernel::VMAPermission::ReadWrite);
- Core::System::GetInstance().ArmInterface(0).ClearInstructionCache();
- Core::System::GetInstance().ArmInterface(1).ClearInstructionCache();
- Core::System::GetInstance().ArmInterface(2).ClearInstructionCache();
- Core::System::GetInstance().ArmInterface(3).ClearInstructionCache();
+ Core::System::GetInstance().InvalidateCpuInstructionCaches();
nro.insert_or_assign(*map_address, NROInfo{hash, nro_size + bss_size});
@@ -391,10 +388,7 @@ public:
Kernel::MemoryState::ModuleCodeStatic) == RESULT_SUCCESS);
ASSERT(process->UnmapMemory(mapped_addr, 0, nro_size) == RESULT_SUCCESS);
- Core::System::GetInstance().ArmInterface(0).ClearInstructionCache();
- Core::System::GetInstance().ArmInterface(1).ClearInstructionCache();
- Core::System::GetInstance().ArmInterface(2).ClearInstructionCache();
- Core::System::GetInstance().ArmInterface(3).ClearInstructionCache();
+ Core::System::GetInstance().InvalidateCpuInstructionCaches();
nro.erase(iter);
IPC::ResponseBuilder rb{ctx, 2};
diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp
index ff9170c24..d5df112a0 100644
--- a/src/core/hle/service/nfp/nfp.cpp
+++ b/src/core/hle/service/nfp/nfp.cpp
@@ -7,7 +7,9 @@
#include "common/logging/log.h"
#include "core/core.h"
#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/event.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/readable_event.h"
+#include "core/hle/kernel/writable_event.h"
#include "core/hle/lock.h"
#include "core/hle/service/hid/hid.h"
#include "core/hle/service/nfp/nfp.h"
@@ -23,8 +25,8 @@ constexpr ResultCode ERR_TAG_FAILED(ErrorModule::NFP,
Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
: ServiceFramework(name), module(std::move(module)) {
auto& kernel = Core::System::GetInstance().Kernel();
- nfc_tag_load =
- Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IUser:NFCTagDetected");
+ nfc_tag_load = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
+ "IUser:NFCTagDetected");
}
Module::Interface::~Interface() = default;
@@ -63,10 +65,10 @@ public:
RegisterHandlers(functions);
auto& kernel = Core::System::GetInstance().Kernel();
- deactivate_event =
- Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IUser:DeactivateEvent");
- availability_change_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot,
- "IUser:AvailabilityChangeEvent");
+ deactivate_event = Kernel::WritableEvent::CreateEventPair(
+ kernel, Kernel::ResetType::OneShot, "IUser:DeactivateEvent");
+ availability_change_event = Kernel::WritableEvent::CreateEventPair(
+ kernel, Kernel::ResetType::OneShot, "IUser:AvailabilityChangeEvent");
}
private:
@@ -164,7 +166,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(deactivate_event);
+ rb.PushCopyObjects(deactivate_event.readable);
}
void StopDetection(Kernel::HLERequestContext& ctx) {
@@ -173,7 +175,7 @@ private:
switch (device_state) {
case DeviceState::TagFound:
case DeviceState::TagNearby:
- deactivate_event->Signal();
+ deactivate_event.writable->Signal();
device_state = DeviceState::Initialized;
break;
case DeviceState::SearchingForTag:
@@ -264,7 +266,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(availability_change_event);
+ rb.PushCopyObjects(availability_change_event.readable);
}
void GetRegisterInfo(Kernel::HLERequestContext& ctx) {
@@ -319,8 +321,8 @@ private:
const u32 npad_id{0}; // Player 1 controller
State state{State::NonInitialized};
DeviceState device_state{DeviceState::Initialized};
- Kernel::SharedPtr<Kernel::Event> deactivate_event;
- Kernel::SharedPtr<Kernel::Event> availability_change_event;
+ Kernel::EventPair deactivate_event;
+ Kernel::EventPair availability_change_event;
const Module::Interface& nfp_interface;
};
@@ -339,12 +341,14 @@ bool Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) {
}
std::memcpy(&amiibo, buffer.data(), sizeof(amiibo));
- nfc_tag_load->Signal();
+ nfc_tag_load.writable->Signal();
return true;
}
-const Kernel::SharedPtr<Kernel::Event>& Module::Interface::GetNFCEvent() const {
- return nfc_tag_load;
+
+const Kernel::SharedPtr<Kernel::ReadableEvent>& Module::Interface::GetNFCEvent() const {
+ return nfc_tag_load.readable;
}
+
const Module::Interface::AmiiboFile& Module::Interface::GetAmiiboBuffer() const {
return amiibo;
}
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 @@
#include <array>
#include <vector>
-#include "core/hle/kernel/event.h"
+#include "core/hle/kernel/readable_event.h"
+#include "core/hle/kernel/writable_event.h"
#include "core/hle/service/service.h"
namespace Service::NFP {
@@ -33,11 +34,11 @@ public:
void CreateUserInterface(Kernel::HLERequestContext& ctx);
bool LoadAmiibo(const std::vector<u8>& buffer);
- const Kernel::SharedPtr<Kernel::Event>& GetNFCEvent() const;
+ const Kernel::SharedPtr<Kernel::ReadableEvent>& GetNFCEvent() const;
const AmiiboFile& GetAmiiboBuffer() const;
private:
- Kernel::SharedPtr<Kernel::Event> nfc_tag_load{};
+ Kernel::EventPair nfc_tag_load{};
AmiiboFile amiibo{};
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 @@
#include "core/core.h"
#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/event.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/readable_event.h"
+#include "core/hle/kernel/writable_event.h"
#include "core/hle/service/nifm/nifm.h"
#include "core/hle/service/service.h"
@@ -56,8 +58,10 @@ public:
RegisterHandlers(functions);
auto& kernel = Core::System::GetInstance().Kernel();
- event1 = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IRequest:Event1");
- event2 = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IRequest:Event2");
+ event1 = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
+ "IRequest:Event1");
+ event2 = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
+ "IRequest:Event2");
}
private:
@@ -88,7 +92,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 2};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(event1, event2);
+ rb.PushCopyObjects(event1.readable, event2.readable);
}
void Cancel(Kernel::HLERequestContext& ctx) {
@@ -105,7 +109,7 @@ private:
rb.Push(RESULT_SUCCESS);
}
- Kernel::SharedPtr<Kernel::Event> event1, event2;
+ Kernel::EventPair event1, event2;
};
class 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 @@
#include <ctime>
#include "core/core.h"
#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/event.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/readable_event.h"
+#include "core/hle/kernel/writable_event.h"
#include "core/hle/service/nim/nim.h"
#include "core/hle/service/service.h"
#include "core/hle/service/sm/sm.h"
@@ -138,19 +140,18 @@ public:
RegisterHandlers(functions);
auto& kernel = Core::System::GetInstance().Kernel();
- finished_event =
- Kernel::Event::Create(kernel, Kernel::ResetType::OneShot,
- "IEnsureNetworkClockAvailabilityService:FinishEvent");
+ finished_event = Kernel::WritableEvent::CreateEventPair(
+ kernel, Kernel::ResetType::OneShot,
+ "IEnsureNetworkClockAvailabilityService:FinishEvent");
}
private:
- Kernel::SharedPtr<Kernel::Event> finished_event;
+ Kernel::EventPair finished_event;
void StartTask(Kernel::HLERequestContext& ctx) {
// No need to connect to the internet, just finish the task straight away.
LOG_DEBUG(Service_NIM, "called");
-
- finished_event->Signal();
+ finished_event.writable->Signal();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
@@ -160,7 +161,7 @@ private:
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(finished_event);
+ rb.PushCopyObjects(finished_event.readable);
}
void GetResult(Kernel::HLERequestContext& ctx) {
@@ -172,8 +173,7 @@ private:
void Cancel(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_NIM, "called");
-
- finished_event->Clear();
+ finished_event.writable->Clear();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
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 @@
#include "common/logging/log.h"
#include "core/core.h"
#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/event.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/readable_event.h"
+#include "core/hle/kernel/writable_event.h"
#include "core/hle/service/nvdrv/interface.h"
#include "core/hle/service/nvdrv/nvdrv.h"
@@ -69,7 +71,7 @@ void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 3, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushCopyObjects(query_event);
+ rb.PushCopyObjects(query_event.readable);
rb.Push<u32>(0);
}
@@ -127,7 +129,8 @@ NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name)
RegisterHandlers(functions);
auto& kernel = Core::System::GetInstance().Kernel();
- query_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "NVDRV::query_event");
+ query_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::OneShot,
+ "NVDRV::query_event");
}
NVDRV::~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 @@
#pragma once
#include <memory>
-#include "core/hle/kernel/event.h"
#include "core/hle/service/nvdrv/nvdrv.h"
#include "core/hle/service/service.h"
+namespace Kernel {
+class WritableEvent;
+}
+
namespace Service::Nvidia {
class NVDRV final : public ServiceFramework<NVDRV> {
@@ -31,7 +34,7 @@ private:
u64 pid{};
- Kernel::SharedPtr<Kernel::Event> query_event;
+ Kernel::EventPair query_event;
};
} // 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 @@
#include "common/assert.h"
#include "common/logging/log.h"
#include "core/core.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/readable_event.h"
+#include "core/hle/kernel/writable_event.h"
#include "core/hle/service/nvflinger/buffer_queue.h"
namespace Service::NVFlinger {
BufferQueue::BufferQueue(u32 id, u64 layer_id) : id(id), layer_id(layer_id) {
auto& kernel = Core::System::GetInstance().Kernel();
- buffer_wait_event =
- Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "BufferQueue NativeHandle");
+ buffer_wait_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Sticky,
+ "BufferQueue NativeHandle");
}
BufferQueue::~BufferQueue() = default;
@@ -28,7 +31,7 @@ void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer)
buffer.status = Buffer::Status::Free;
queue.emplace_back(buffer);
- buffer_wait_event->Signal();
+ buffer_wait_event.writable->Signal();
}
std::optional<u32> BufferQueue::DequeueBuffer(u32 width, u32 height) {
@@ -87,7 +90,7 @@ void BufferQueue::ReleaseBuffer(u32 slot) {
ASSERT(itr->status == Buffer::Status::Acquired);
itr->status = Buffer::Status::Free;
- buffer_wait_event->Signal();
+ buffer_wait_event.writable->Signal();
}
u32 BufferQueue::Query(QueryType type) {
@@ -104,4 +107,12 @@ u32 BufferQueue::Query(QueryType type) {
return 0;
}
+Kernel::SharedPtr<Kernel::WritableEvent> BufferQueue::GetWritableBufferWaitEvent() const {
+ return buffer_wait_event.writable;
+}
+
+Kernel::SharedPtr<Kernel::ReadableEvent> BufferQueue::GetBufferWaitEvent() const {
+ return buffer_wait_event.readable;
+}
+
} // 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 @@
#include "common/common_funcs.h"
#include "common/math_util.h"
#include "common/swap.h"
-#include "core/hle/kernel/event.h"
+#include "core/hle/kernel/object.h"
+#include "core/hle/kernel/writable_event.h"
namespace CoreTiming {
struct EventType;
@@ -86,16 +87,16 @@ public:
return id;
}
- Kernel::SharedPtr<Kernel::Event> GetBufferWaitEvent() const {
- return buffer_wait_event;
- }
+ Kernel::SharedPtr<Kernel::WritableEvent> GetWritableBufferWaitEvent() const;
+
+ Kernel::SharedPtr<Kernel::ReadableEvent> GetBufferWaitEvent() const;
private:
u32 id;
u64 layer_id;
std::vector<Buffer> queue;
- Kernel::SharedPtr<Kernel::Event> buffer_wait_event;
+ Kernel::EventPair buffer_wait_event;
};
} // 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 @@
#include "core/core.h"
#include "core/core_timing.h"
#include "core/core_timing_util.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/readable_event.h"
+#include "core/hle/kernel/writable_event.h"
#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h"
#include "core/hle/service/nvdrv/nvdrv.h"
#include "core/hle/service/nvflinger/buffer_queue.h"
@@ -83,9 +86,8 @@ u32 NVFlinger::GetBufferQueueId(u64 display_id, u64 layer_id) {
return layer.buffer_queue->GetId();
}
-Kernel::SharedPtr<Kernel::Event> NVFlinger::GetVsyncEvent(u64 display_id) {
- const auto& display = GetDisplay(display_id);
- return display.vsync_event;
+Kernel::SharedPtr<Kernel::ReadableEvent> NVFlinger::GetVsyncEvent(u64 display_id) {
+ return GetDisplay(display_id).vsync_event.readable;
}
std::shared_ptr<BufferQueue> NVFlinger::GetBufferQueue(u32 id) const {
@@ -117,7 +119,7 @@ Layer& NVFlinger::GetLayer(u64 display_id, u64 layer_id) {
void NVFlinger::Compose() {
for (auto& display : displays) {
// Trigger vsync for this display at the end of drawing
- SCOPE_EXIT({ display.vsync_event->Signal(); });
+ SCOPE_EXIT({ display.vsync_event.writable->Signal(); });
// Don't do anything for displays without layers.
if (display.layers.empty())
@@ -164,7 +166,8 @@ Layer::~Layer() = default;
Display::Display(u64 id, std::string name) : id(id), name(std::move(name)) {
auto& kernel = Core::System::GetInstance().Kernel();
- vsync_event = Kernel::Event::Create(kernel, Kernel::ResetType::Pulse, "Display VSync Event");
+ vsync_event = Kernel::WritableEvent::CreateEventPair(kernel, Kernel::ResetType::Pulse,
+ fmt::format("Display VSync Event {}", id));
}
Display::~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 @@
#include <vector>
#include "common/common_types.h"
-#include "core/hle/kernel/event.h"
+#include "core/hle/kernel/object.h"
namespace CoreTiming {
struct EventType;
}
+namespace Kernel {
+class ReadableEvent;
+class WritableEvent;
+} // namespace Kernel
+
namespace Service::Nvidia {
class Module;
}
@@ -40,7 +45,7 @@ struct Display {
std::string name;
std::vector<Layer> layers;
- Kernel::SharedPtr<Kernel::Event> vsync_event;
+ Kernel::EventPair vsync_event;
};
class NVFlinger final {
@@ -61,7 +66,7 @@ public:
u32 GetBufferQueueId(u64 display_id, u64 layer_id);
/// Gets the vsync event for the specified display.
- Kernel::SharedPtr<Kernel::Event> GetVsyncEvent(u64 display_id);
+ Kernel::SharedPtr<Kernel::ReadableEvent> GetVsyncEvent(u64 display_id);
/// Obtains a buffer queue identified by the id.
std::shared_ptr<BufferQueue> GetBufferQueue(u32 id) const;
diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp
index 40a9144f9..1afc43f75 100644
--- a/src/core/hle/service/set/set.cpp
+++ b/src/core/hle/service/set/set.cpp
@@ -35,6 +35,8 @@ constexpr std::array<LanguageCode, 17> available_language_codes = {{
constexpr std::size_t pre4_0_0_max_entries = 0xF;
constexpr std::size_t post4_0_0_max_entries = 0x40;
+constexpr ResultCode ERR_INVALID_LANGUAGE{ErrorModule::Settings, 625};
+
LanguageCode GetLanguageCodeFromIndex(std::size_t index) {
return available_language_codes.at(index);
}
@@ -67,6 +69,21 @@ void SET::GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx) {
PushResponseLanguageCode(ctx, pre4_0_0_max_entries);
}
+void SET::MakeLanguageCode(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto index = rp.Pop<u32>();
+
+ if (index >= available_language_codes.size()) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERR_INVALID_LANGUAGE);
+ return;
+ }
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushEnum(available_language_codes[index]);
+}
+
void SET::GetAvailableLanguageCodes2(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_SET, "called");
@@ -95,14 +112,14 @@ void SET::GetLanguageCode(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
- rb.Push(static_cast<u64>(available_language_codes[Settings::values.language_index]));
+ rb.PushEnum(available_language_codes[Settings::values.language_index]);
}
SET::SET() : ServiceFramework("set") {
static const FunctionInfo functions[] = {
{0, &SET::GetLanguageCode, "GetLanguageCode"},
{1, &SET::GetAvailableLanguageCodes, "GetAvailableLanguageCodes"},
- {2, nullptr, "MakeLanguageCode"},
+ {2, &SET::MakeLanguageCode, "MakeLanguageCode"},
{3, &SET::GetAvailableLanguageCodeCount, "GetAvailableLanguageCodeCount"},
{4, nullptr, "GetRegionCode"},
{5, &SET::GetAvailableLanguageCodes2, "GetAvailableLanguageCodes2"},
diff --git a/src/core/hle/service/set/set.h b/src/core/hle/service/set/set.h
index 266f13e46..31f9cb296 100644
--- a/src/core/hle/service/set/set.h
+++ b/src/core/hle/service/set/set.h
@@ -38,6 +38,7 @@ public:
private:
void GetLanguageCode(Kernel::HLERequestContext& ctx);
void GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx);
+ void MakeLanguageCode(Kernel::HLERequestContext& ctx);
void GetAvailableLanguageCodes2(Kernel::HLERequestContext& ctx);
void GetAvailableLanguageCodeCount(Kernel::HLERequestContext& ctx);
void GetAvailableLanguageCodeCount2(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/usb/usb.cpp b/src/core/hle/service/usb/usb.cpp
index f082a63bc..58a9845fc 100644
--- a/src/core/hle/service/usb/usb.cpp
+++ b/src/core/hle/service/usb/usb.cpp
@@ -73,7 +73,7 @@ public:
{3, nullptr, "Populate"},
{4, nullptr, "PostBufferAsync"},
{5, nullptr, "GetXferReport"},
- {6, nullptr, "Unknown2"},
+ {6, nullptr, "PostBufferMultiAsync"},
{7, nullptr, "Unknown3"},
{8, nullptr, "Unknown4"},
};
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 @@
#include "common/swap.h"
#include "core/core_timing.h"
#include "core/hle/ipc_helpers.h"
-#include "core/hle/kernel/event.h"
+#include "core/hle/kernel/readable_event.h"
+#include "core/hle/kernel/writable_event.h"
#include "core/hle/service/nvdrv/nvdrv.h"
#include "core/hle/service/nvflinger/buffer_queue.h"
#include "core/hle/service/nvflinger/nvflinger.h"
@@ -542,12 +543,14 @@ private:
// Repeat TransactParcel DequeueBuffer when a buffer is available
auto buffer_queue = nv_flinger->GetBufferQueue(id);
std::optional<u32> slot = buffer_queue->DequeueBuffer(width, height);
+ ASSERT_MSG(slot != std::nullopt, "Could not dequeue buffer.");
+
IGBPDequeueBufferResponseParcel response{*slot};
ctx.WriteBuffer(response.Serialize());
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
},
- buffer_queue->GetBufferWaitEvent());
+ buffer_queue->GetWritableBufferWaitEvent());
}
} else if (transaction == TransactionId::RequestBuffer) {
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 @@
#include "common/common_funcs.h"
#include "common/file_util.h"
#include "common/logging/log.h"
-#include "core/core.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/patch_manager.h"
@@ -146,7 +145,7 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(Kernel::Process& process)
const VAddr load_addr = next_load_addr;
const bool should_pass_arguments = std::strcmp(module, "rtld") == 0;
const auto tentative_next_load_addr =
- AppLoader_NSO::LoadModule(*module_file, load_addr, should_pass_arguments, pm);
+ AppLoader_NSO::LoadModule(process, *module_file, load_addr, should_pass_arguments, pm);
if (!tentative_next_load_addr) {
return ResultStatus::ErrorLoadingNSO;
}
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 @@
#include "common/file_util.h"
#include "common/logging/log.h"
#include "common/swap.h"
-#include "core/core.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/romfs_factory.h"
#include "core/file_sys/vfs_offset.h"
@@ -129,9 +128,8 @@ static constexpr u32 PageAlignSize(u32 size) {
return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK;
}
-/*static*/ bool AppLoader_NRO::LoadNro(const std::vector<u8>& data, const std::string& name,
- VAddr load_base) {
-
+static bool LoadNroImpl(Kernel::Process& process, const std::vector<u8>& data,
+ const std::string& name, VAddr load_base) {
if (data.size() < sizeof(NroHeader)) {
return {};
}
@@ -189,7 +187,7 @@ static constexpr u32 PageAlignSize(u32 size) {
// Load codeset for current process
codeset.memory = std::make_shared<std::vector<u8>>(std::move(program_image));
- Core::CurrentProcess()->LoadModule(std::move(codeset), load_base);
+ process.LoadModule(std::move(codeset), load_base);
// Register module with GDBStub
GDBStub::RegisterModule(name, load_base, load_base);
@@ -197,8 +195,9 @@ static constexpr u32 PageAlignSize(u32 size) {
return true;
}
-bool AppLoader_NRO::LoadNro(const FileSys::VfsFile& file, VAddr load_base) {
- return AppLoader_NRO::LoadNro(file.ReadAllBytes(), file.GetName(), load_base);
+bool AppLoader_NRO::LoadNro(Kernel::Process& process, const FileSys::VfsFile& file,
+ VAddr load_base) {
+ return LoadNroImpl(process, file.ReadAllBytes(), file.GetName(), load_base);
}
ResultStatus AppLoader_NRO::Load(Kernel::Process& process) {
@@ -209,7 +208,7 @@ ResultStatus AppLoader_NRO::Load(Kernel::Process& process) {
// Load NRO
const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress();
- if (!LoadNro(*file, base_address)) {
+ if (!LoadNro(process, *file, base_address)) {
return ResultStatus::ErrorLoadingNRO;
}
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 {
class NACP;
}
+namespace Kernel {
+class Process;
+}
+
namespace Loader {
/// Loads an NRO file
@@ -41,10 +45,8 @@ public:
ResultStatus ReadTitle(std::string& title) override;
bool IsRomFSUpdatable() const override;
- static bool LoadNro(const std::vector<u8>& data, const std::string& name, VAddr load_base);
-
private:
- bool LoadNro(const FileSys::VfsFile& file, VAddr load_base);
+ bool LoadNro(Kernel::Process& process, const FileSys::VfsFile& file, VAddr load_base);
std::vector<u8> icon_data;
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 @@
#include "common/file_util.h"
#include "common/logging/log.h"
#include "common/swap.h"
-#include "core/core.h"
#include "core/file_sys/patch_manager.h"
#include "core/gdbstub/gdbstub.h"
#include "core/hle/kernel/process.h"
@@ -93,7 +92,8 @@ static constexpr u32 PageAlignSize(u32 size) {
return (size + Memory::PAGE_MASK) & ~Memory::PAGE_MASK;
}
-std::optional<VAddr> AppLoader_NSO::LoadModule(const FileSys::VfsFile& file, VAddr load_base,
+std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::Process& process,
+ const FileSys::VfsFile& file, VAddr load_base,
bool should_pass_arguments,
std::optional<FileSys::PatchManager> pm) {
if (file.GetSize() < sizeof(NsoHeader))
@@ -166,7 +166,7 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(const FileSys::VfsFile& file, VAd
// Load codeset for current process
codeset.memory = std::make_shared<std::vector<u8>>(std::move(program_image));
- Core::CurrentProcess()->LoadModule(std::move(codeset), load_base);
+ process.LoadModule(std::move(codeset), load_base);
// Register module with GDBStub
GDBStub::RegisterModule(file.GetName(), load_base, load_base);
@@ -181,7 +181,7 @@ ResultStatus AppLoader_NSO::Load(Kernel::Process& process) {
// Load module
const VAddr base_address = process.VMManager().GetCodeRegionBaseAddress();
- if (!LoadModule(*file, base_address, true)) {
+ if (!LoadModule(process, *file, base_address, true)) {
return ResultStatus::ErrorLoadingNSO;
}
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 @@
#include "core/loader/linker.h"
#include "core/loader/loader.h"
+namespace Kernel {
+class Process;
+}
+
namespace Loader {
constexpr u64 NSO_ARGUMENT_DATA_ALLOCATION_SIZE = 0x9000;
@@ -37,8 +41,8 @@ public:
return IdentifyType(file);
}
- static std::optional<VAddr> LoadModule(const FileSys::VfsFile& file, VAddr load_base,
- bool should_pass_arguments,
+ static std::optional<VAddr> LoadModule(Kernel::Process& process, const FileSys::VfsFile& file,
+ VAddr load_base, bool should_pass_arguments,
std::optional<FileSys::PatchManager> pm = {});
ResultStatus Load(Kernel::Process& process) override;
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 70abd856a..41fd2a6a0 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -53,6 +53,14 @@ void PageTable::Resize(std::size_t address_space_width_in_bits) {
pointers.resize(num_page_table_entries);
attributes.resize(num_page_table_entries);
+
+ // The default is a 39-bit address space, which causes an initial 1GB allocation size. If the
+ // vector size is subsequently decreased (via resize), the vector might not automatically
+ // actually reallocate/resize its underlying allocation, which wastes up to ~800 MB for
+ // 36-bit titles. Call shrink_to_fit to reduce capacity to what's actually in use.
+
+ pointers.shrink_to_fit();
+ attributes.shrink_to_fit();
}
static void MapPages(PageTable& page_table, VAddr base, u64 size, u8* memory, PageType type) {
diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp
deleted file mode 100644
index 8b9c548cc..000000000
--- a/src/video_core/command_processor.cpp
+++ /dev/null
@@ -1,142 +0,0 @@
-// Copyright 2018 yuzu Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include <array>
-#include <cstddef>
-#include <memory>
-#include <utility>
-#include "common/assert.h"
-#include "common/logging/log.h"
-#include "common/microprofile.h"
-#include "common/vector_math.h"
-#include "core/memory.h"
-#include "core/tracer/recorder.h"
-#include "video_core/command_processor.h"
-#include "video_core/engines/fermi_2d.h"
-#include "video_core/engines/kepler_memory.h"
-#include "video_core/engines/maxwell_3d.h"
-#include "video_core/engines/maxwell_compute.h"
-#include "video_core/engines/maxwell_dma.h"
-#include "video_core/gpu.h"
-#include "video_core/renderer_base.h"
-#include "video_core/video_core.h"
-
-namespace Tegra {
-
-enum class BufferMethods {
- BindObject = 0,
- CountBufferMethods = 0x40,
-};
-
-MICROPROFILE_DEFINE(ProcessCommandLists, "GPU", "Execute command buffer", MP_RGB(128, 128, 192));
-
-void GPU::ProcessCommandLists(const std::vector<CommandListHeader>& commands) {
- MICROPROFILE_SCOPE(ProcessCommandLists);
-
- // On entering GPU code, assume all memory may be touched by the ARM core.
- maxwell_3d->dirty_flags.OnMemoryWrite();
-
- auto WriteReg = [this](u32 method, u32 subchannel, u32 value, u32 remaining_params) {
- LOG_TRACE(HW_GPU,
- "Processing method {:08X} on subchannel {} value "
- "{:08X} remaining params {}",
- method, subchannel, value, remaining_params);
-
- ASSERT(subchannel < bound_engines.size());
-
- if (method == static_cast<u32>(BufferMethods::BindObject)) {
- // Bind the current subchannel to the desired engine id.
- LOG_DEBUG(HW_GPU, "Binding subchannel {} to engine {}", subchannel, value);
- bound_engines[subchannel] = static_cast<EngineID>(value);
- return;
- }
-
- if (method < static_cast<u32>(BufferMethods::CountBufferMethods)) {
- // TODO(Subv): Research and implement these methods.
- LOG_ERROR(HW_GPU, "Special buffer methods other than Bind are not implemented");
- return;
- }
-
- const EngineID engine = bound_engines[subchannel];
-
- switch (engine) {
- case EngineID::FERMI_TWOD_A:
- fermi_2d->WriteReg(method, value);
- break;
- case EngineID::MAXWELL_B:
- maxwell_3d->WriteReg(method, value, remaining_params);
- break;
- case EngineID::MAXWELL_COMPUTE_B:
- maxwell_compute->WriteReg(method, value);
- break;
- case EngineID::MAXWELL_DMA_COPY_A:
- maxwell_dma->WriteReg(method, value);
- break;
- case EngineID::KEPLER_INLINE_TO_MEMORY_B:
- kepler_memory->WriteReg(method, value);
- break;
- default:
- UNIMPLEMENTED_MSG("Unimplemented engine");
- }
- };
-
- for (auto entry : commands) {
- Tegra::GPUVAddr address = entry.Address();
- u32 size = entry.sz;
- const std::optional<VAddr> head_address = memory_manager->GpuToCpuAddress(address);
- VAddr current_addr = *head_address;
- while (current_addr < *head_address + size * sizeof(CommandHeader)) {
- const CommandHeader header = {Memory::Read32(current_addr)};
- current_addr += sizeof(u32);
-
- switch (header.mode.Value()) {
- case SubmissionMode::IncreasingOld:
- case SubmissionMode::Increasing: {
- // Increase the method value with each argument.
- for (unsigned i = 0; i < header.arg_count; ++i) {
- WriteReg(header.method + i, header.subchannel, Memory::Read32(current_addr),
- header.arg_count - i - 1);
- current_addr += sizeof(u32);
- }
- break;
- }
- case SubmissionMode::NonIncreasingOld:
- case SubmissionMode::NonIncreasing: {
- // Use the same method value for all arguments.
- for (unsigned i = 0; i < header.arg_count; ++i) {
- WriteReg(header.method, header.subchannel, Memory::Read32(current_addr),
- header.arg_count - i - 1);
- current_addr += sizeof(u32);
- }
- break;
- }
- case SubmissionMode::IncreaseOnce: {
- ASSERT(header.arg_count.Value() >= 1);
-
- // Use the original method for the first argument and then the next method for all
- // other arguments.
- WriteReg(header.method, header.subchannel, Memory::Read32(current_addr),
- header.arg_count - 1);
- current_addr += sizeof(u32);
-
- for (unsigned i = 1; i < header.arg_count; ++i) {
- WriteReg(header.method + 1, header.subchannel, Memory::Read32(current_addr),
- header.arg_count - i - 1);
- current_addr += sizeof(u32);
- }
- break;
- }
- case SubmissionMode::Inline: {
- // The register value is stored in the bits 16-28 as an immediate
- WriteReg(header.method, header.subchannel, header.inline_data, 0);
- break;
- }
- default:
- UNIMPLEMENTED();
- }
- }
- }
-}
-
-} // 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:
static constexpr std::size_t NumVertexArrays = 32;
static constexpr std::size_t NumVertexAttributes = 32;
static constexpr std::size_t NumTextureSamplers = 32;
+ static constexpr std::size_t NumClipDistances = 8;
static constexpr std::size_t MaxShaderProgram = 6;
static constexpr std::size_t MaxShaderStage = 5;
// Maximum number of const buffers per shader stage.
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index b9faaf8e0..5ea094e64 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -1049,6 +1049,7 @@ union Instruction {
BitField<49, 1, u64> nodep_flag;
BitField<50, 3, u64> component_mask_selector;
BitField<53, 4, u64> texture_info;
+ BitField<60, 1, u64> fp32_flag;
TextureType GetTextureType() const {
// The TEXS instruction has a weird encoding for the texture type.
@@ -1549,7 +1550,7 @@ private:
INST("1110111011011---", Id::STG, Type::Memory, "STG"),
INST("110000----111---", Id::TEX, Type::Memory, "TEX"),
INST("1101111101001---", Id::TXQ, Type::Memory, "TXQ"),
- INST("1101100---------", Id::TEXS, Type::Memory, "TEXS"),
+ INST("1101-00---------", Id::TEXS, Type::Memory, "TEXS"),
INST("1101101---------", Id::TLDS, Type::Memory, "TLDS"),
INST("110010----111---", Id::TLD4, Type::Memory, "TLD4"),
INST("1101111100------", Id::TLD4S, Type::Memory, "TLD4S"),
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index 6c81dee64..88c45a423 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -128,10 +128,8 @@ enum class BufferMethods {
};
void GPU::CallMethod(const MethodCall& method_call) {
- LOG_TRACE(HW_GPU,
- "Processing method {:08X} on subchannel {} value "
- "{:08X} remaining params {}",
- MethCall.method, MethCall.subchannel, value, remaining_params);
+ LOG_TRACE(HW_GPU, "Processing method {:08X} on subchannel {}", method_call.method,
+ method_call.subchannel);
ASSERT(method_call.subchannel < bound_engines.size());
@@ -143,6 +141,12 @@ void GPU::CallMethod(const MethodCall& method_call) {
return;
}
+ if (method_call.method < static_cast<u32>(BufferMethods::CountBufferMethods)) {
+ // TODO(Subv): Research and implement these methods.
+ LOG_ERROR(HW_GPU, "Special buffer methods other than Bind are not implemented");
+ return;
+ }
+
const EngineID engine = bound_engines[method_call.subchannel];
switch (engine) {
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 7b836cc94..2b29fc45f 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -108,19 +108,6 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo
state.texture_units[i].sampler = texture_samplers[i].sampler.handle;
}
- GLint ext_num;
- glGetIntegerv(GL_NUM_EXTENSIONS, &ext_num);
- for (GLint i = 0; i < ext_num; i++) {
- const std::string_view extension{
- reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, i))};
-
- if (extension == "GL_ARB_direct_state_access") {
- has_ARB_direct_state_access = true;
- } else if (extension == "GL_ARB_multi_bind") {
- has_ARB_multi_bind = true;
- }
- }
-
OpenGLState::ApplyDefaultState();
shader_program_manager = std::make_unique<GLShader::ProgramManager>();
@@ -312,6 +299,7 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
// shaders. The constbuffer bindpoint starts after the shader stage configuration bind points.
u32 current_constbuffer_bindpoint = Tegra::Engines::Maxwell3D::Regs::MaxShaderStage;
u32 current_texture_bindpoint = 0;
+ std::array<bool, Maxwell::NumClipDistances> clip_distances{};
for (std::size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) {
const auto& shader_config = gpu.regs.shader_config[index];
@@ -372,12 +360,22 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
current_texture_bindpoint = SetupTextures(static_cast<Maxwell::ShaderStage>(stage), shader,
primitive_mode, current_texture_bindpoint);
+ // Workaround for Intel drivers.
+ // When a clip distance is enabled but not set in the shader it crops parts of the screen
+ // (sometimes it's half the screen, sometimes three quarters). To avoid this, enable the
+ // clip distances only when it's written by a shader stage.
+ for (std::size_t i = 0; i < Maxwell::NumClipDistances; ++i) {
+ clip_distances[i] |= shader->GetShaderEntries().clip_distances[i];
+ }
+
// When VertexA is enabled, we have dual vertex shaders
if (program == Maxwell::ShaderProgram::VertexA) {
// VertexB was combined with VertexA, so we skip the VertexB iteration
index++;
}
}
+
+ SyncClipEnabled(clip_distances);
}
void RasterizerOpenGL::SetupCachedFramebuffer(const FramebufferCacheKey& fbkey,
@@ -498,7 +496,7 @@ void RasterizerOpenGL::ConfigureFramebuffers(OpenGLState& current_state, bool us
// TODO(bunnei): Figure out how the below register works. According to envytools, this should be
// used to enable multiple render targets. However, it is left unset on all games that I have
// tested.
- ASSERT_MSG(regs.rt_separate_frag_data == 0, "Unimplemented");
+ UNIMPLEMENTED_IF(regs.rt_separate_frag_data != 0);
// Bind the framebuffer surfaces
current_state.framebuffer_srgb.enabled = regs.framebuffer_srgb != 0;
@@ -680,7 +678,6 @@ void RasterizerOpenGL::DrawArrays() {
SyncCullMode();
SyncPrimitiveRestart();
SyncScissorTest(state);
- SyncClipEnabled();
// Alpha Testing is synced on shaders.
SyncTransformFeedback();
SyncPointState();
@@ -1057,20 +1054,23 @@ void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) {
state.depth_clamp.near_plane = regs.view_volume_clip_control.depth_clamp_near != 0;
}
-void RasterizerOpenGL::SyncClipEnabled() {
+void RasterizerOpenGL::SyncClipEnabled(
+ const std::array<bool, Maxwell::Regs::NumClipDistances>& clip_mask) {
+
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
- state.clip_distance[0] = regs.clip_distance_enabled.c0 != 0;
- state.clip_distance[1] = regs.clip_distance_enabled.c1 != 0;
- state.clip_distance[2] = regs.clip_distance_enabled.c2 != 0;
- state.clip_distance[3] = regs.clip_distance_enabled.c3 != 0;
- state.clip_distance[4] = regs.clip_distance_enabled.c4 != 0;
- state.clip_distance[5] = regs.clip_distance_enabled.c5 != 0;
- state.clip_distance[6] = regs.clip_distance_enabled.c6 != 0;
- state.clip_distance[7] = regs.clip_distance_enabled.c7 != 0;
+ const std::array<bool, Maxwell::Regs::NumClipDistances> reg_state{
+ regs.clip_distance_enabled.c0 != 0, regs.clip_distance_enabled.c1 != 0,
+ regs.clip_distance_enabled.c2 != 0, regs.clip_distance_enabled.c3 != 0,
+ regs.clip_distance_enabled.c4 != 0, regs.clip_distance_enabled.c5 != 0,
+ regs.clip_distance_enabled.c6 != 0, regs.clip_distance_enabled.c7 != 0};
+
+ for (std::size_t i = 0; i < Maxwell::Regs::NumClipDistances; ++i) {
+ state.clip_distance[i] = reg_state[i] && clip_mask[i];
+ }
}
void RasterizerOpenGL::SyncClipCoef() {
- UNREACHABLE();
+ UNIMPLEMENTED();
}
void RasterizerOpenGL::SyncCullMode() {
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 959e8df63..8a891ffc7 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -61,20 +61,6 @@ public:
bool AccelerateDrawBatch(bool is_indexed) override;
void UpdatePagesCachedCount(Tegra::GPUVAddr addr, u64 size, int delta) override;
- /// OpenGL shader generated for a given Maxwell register state
- struct MaxwellShader {
- /// OpenGL shader resource
- OGLProgram shader;
- };
-
- struct VertexShader {
- OGLShader shader;
- };
-
- struct FragmentShader {
- OGLShader shader;
- };
-
/// Maximum supported size that a constbuffer can have in bytes.
static constexpr std::size_t MaxConstbufferSize = 0x10000;
static_assert(MaxConstbufferSize % sizeof(GLvec4) == 0,
@@ -143,7 +129,8 @@ private:
void SyncViewport(OpenGLState& current_state);
/// Syncs the clip enabled status to match the guest state
- void SyncClipEnabled();
+ void SyncClipEnabled(
+ const std::array<bool, Tegra::Engines::Maxwell3D::Regs::NumClipDistances>& clip_mask);
/// Syncs the clip coefficients to match the guest state
void SyncClipCoef();
@@ -194,9 +181,6 @@ private:
/// but are needed for correct emulation
void CheckExtensions();
- bool has_ARB_direct_state_access = false;
- bool has_ARB_multi_bind = false;
-
OpenGLState state;
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,
}
}
-MICROPROFILE_DEFINE(OpenGL_BlitSurface, "OpenGL", "BlitSurface", MP_RGB(128, 192, 64));
-static bool BlitSurface(const Surface& src_surface, const Surface& dst_surface,
- GLuint read_fb_handle, GLuint draw_fb_handle, GLenum src_attachment = 0,
- GLenum dst_attachment = 0, std::size_t cubemap_face = 0) {
- MICROPROFILE_SCOPE(OpenGL_BlitSurface);
-
- const auto& src_params{src_surface->GetSurfaceParams()};
- const auto& dst_params{dst_surface->GetSurfaceParams()};
-
- OpenGLState prev_state{OpenGLState::GetCurState()};
- SCOPE_EXIT({ prev_state.Apply(); });
-
- OpenGLState state;
- state.draw.read_framebuffer = read_fb_handle;
- state.draw.draw_framebuffer = draw_fb_handle;
- // Set sRGB enabled if the destination surfaces need it
- state.framebuffer_srgb.enabled = dst_params.srgb_conversion;
- state.ApplyFramebufferState();
-
- u32 buffers{};
-
- if (src_params.type == SurfaceType::ColorTexture) {
- switch (src_params.target) {
- case SurfaceTarget::Texture2D:
- glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
- GL_TEXTURE_2D, src_surface->Texture().handle, 0);
- glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
- 0, 0);
- break;
- case SurfaceTarget::TextureCubemap:
- glFramebufferTexture2D(
- GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
- static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face),
- src_surface->Texture().handle, 0);
- glFramebufferTexture2D(
- GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
- static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face), 0, 0);
- break;
- case SurfaceTarget::Texture2DArray:
- glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
- src_surface->Texture().handle, 0, 0);
- glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, 0, 0, 0);
- break;
- case SurfaceTarget::Texture3D:
- glFramebufferTexture3D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
- SurfaceTargetToGL(src_params.target),
- src_surface->Texture().handle, 0, 0);
- glFramebufferTexture3D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
- SurfaceTargetToGL(src_params.target), 0, 0, 0);
- break;
- default:
- glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
- GL_TEXTURE_2D, src_surface->Texture().handle, 0);
- glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
- 0, 0);
- break;
- }
-
- switch (dst_params.target) {
- case SurfaceTarget::Texture2D:
- glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
- GL_TEXTURE_2D, dst_surface->Texture().handle, 0);
- glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
- 0, 0);
- break;
- case SurfaceTarget::TextureCubemap:
- glFramebufferTexture2D(
- GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
- static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face),
- dst_surface->Texture().handle, 0);
- glFramebufferTexture2D(
- GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
- static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face), 0, 0);
- break;
- case SurfaceTarget::Texture2DArray:
- glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
- dst_surface->Texture().handle, 0, 0);
- glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, 0, 0, 0);
- break;
-
- case SurfaceTarget::Texture3D:
- glFramebufferTexture3D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
- SurfaceTargetToGL(dst_params.target),
- dst_surface->Texture().handle, 0, 0);
- glFramebufferTexture3D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
- SurfaceTargetToGL(dst_params.target), 0, 0, 0);
- break;
- default:
- glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
- GL_TEXTURE_2D, dst_surface->Texture().handle, 0);
- glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
- 0, 0);
- break;
- }
-
- buffers = GL_COLOR_BUFFER_BIT;
- } else if (src_params.type == SurfaceType::Depth) {
- glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
- GL_TEXTURE_2D, 0, 0);
- glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
- src_surface->Texture().handle, 0);
- glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
-
- glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
- GL_TEXTURE_2D, 0, 0);
- glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
- dst_surface->Texture().handle, 0);
- glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
-
- buffers = GL_DEPTH_BUFFER_BIT;
- } else if (src_params.type == SurfaceType::DepthStencil) {
- glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
- GL_TEXTURE_2D, 0, 0);
- glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
- src_surface->Texture().handle, 0);
-
- glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
- GL_TEXTURE_2D, 0, 0);
- glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
- dst_surface->Texture().handle, 0);
-
- buffers = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
- }
-
- const auto& rect{src_params.GetRect()};
- glBlitFramebuffer(rect.left, rect.bottom, rect.right, rect.top, rect.left, rect.bottom,
- rect.right, rect.top, buffers,
- buffers == GL_COLOR_BUFFER_BIT ? GL_LINEAR : GL_NEAREST);
-
- return true;
-}
-
static void FastCopySurface(const Surface& src_surface, const Surface& dst_surface) {
const auto& src_params{src_surface->GetSurfaceParams()};
const auto& dst_params{dst_surface->GetSurfaceParams()};
@@ -841,9 +709,10 @@ void CachedSurface::LoadGLBuffer() {
const auto texture_src_data_end{texture_src_data + params.size_in_bytes_gl};
gl_buffer[0].assign(texture_src_data, texture_src_data_end);
}
- for (u32 i = 0; i < params.max_mip_level; i++)
+ for (u32 i = 0; i < params.max_mip_level; i++) {
ConvertFormatAsNeeded_LoadGLBuffer(gl_buffer[i], params.pixel_format, params.MipWidth(i),
params.MipHeight(i), params.MipDepth(i));
+ }
}
MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64));
@@ -1163,7 +1032,10 @@ void RasterizerCacheOpenGL::AccurateCopySurface(const Surface& src_surface,
const Surface& dst_surface) {
const auto& src_params{src_surface->GetSurfaceParams()};
const auto& dst_params{dst_surface->GetSurfaceParams()};
- FlushRegion(src_params.addr, dst_params.MemorySize());
+
+ // Flush enough memory for both the source and destination surface
+ FlushRegion(src_params.addr, std::max(src_params.MemorySize(), dst_params.MemorySize()));
+
LoadSurface(dst_surface);
}
@@ -1189,20 +1061,9 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& old_surface,
return new_surface;
}
- // If the format is the same, just do a framebuffer blit. This is significantly faster than
- // using PBOs. The is also likely less accurate, as textures will be converted rather than
- // reinterpreted. When use_accurate_gpu_emulation setting is enabled, perform a more accurate
- // surface copy, where pixels are reinterpreted as a new format (without conversion). This
- // code path uses OpenGL PBOs and is quite slow.
- const bool is_blit{old_params.pixel_format == new_params.pixel_format};
-
switch (new_params.target) {
case SurfaceTarget::Texture2D:
- if (is_blit) {
- BlitSurface(old_surface, new_surface, read_framebuffer.handle, draw_framebuffer.handle);
- } else {
- CopySurface(old_surface, new_surface, copy_pbo.handle);
- }
+ CopySurface(old_surface, new_surface, copy_pbo.handle);
break;
case SurfaceTarget::Texture3D:
AccurateCopySurface(old_surface, new_surface);
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 0c4524d5c..4fc09cac6 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -50,6 +50,14 @@ public:
using std::runtime_error::runtime_error;
};
+/// Generates code to use for a swizzle operation.
+static std::string GetSwizzle(u64 elem) {
+ ASSERT(elem <= 3);
+ std::string swizzle = ".";
+ swizzle += "xyzw"[elem];
+ return swizzle;
+}
+
/// Translate topology
static std::string GetTopologyName(Tegra::Shader::OutputTopology topology) {
switch (topology) {
@@ -201,14 +209,53 @@ private:
}
};
+template <typename T>
+class ShaderScopedScope {
+public:
+ explicit ShaderScopedScope(T& writer, std::string_view begin_expr, std::string end_expr)
+ : writer(writer), end_expr(std::move(end_expr)) {
+
+ if (begin_expr.empty()) {
+ writer.AddLine('{');
+ } else {
+ writer.AddExpression(begin_expr);
+ writer.AddLine(" {");
+ }
+ ++writer.scope;
+ }
+
+ ShaderScopedScope(const ShaderScopedScope&) = delete;
+
+ ~ShaderScopedScope() {
+ --writer.scope;
+ if (end_expr.empty()) {
+ writer.AddLine('}');
+ } else {
+ writer.AddExpression("} ");
+ writer.AddExpression(end_expr);
+ writer.AddLine(';');
+ }
+ }
+
+ ShaderScopedScope& operator=(const ShaderScopedScope&) = delete;
+
+private:
+ T& writer;
+ std::string end_expr;
+};
+
class ShaderWriter {
public:
- void AddLine(std::string_view text) {
+ void AddExpression(std::string_view text) {
DEBUG_ASSERT(scope >= 0);
if (!text.empty()) {
AppendIndentation();
}
shader_source += text;
+ }
+
+ void AddLine(std::string_view text) {
+ AddExpression(text);
AddNewLine();
}
@@ -228,6 +275,11 @@ public:
return std::move(shader_source);
}
+ ShaderScopedScope<ShaderWriter> Scope(std::string_view begin_expr = {},
+ std::string end_expr = {}) {
+ return ShaderScopedScope(*this, begin_expr, end_expr);
+ }
+
int scope = 0;
private:
@@ -311,7 +363,7 @@ public:
// Default - do nothing
return value;
default:
- UNIMPLEMENTED_MSG("Unimplemented conversion size: {}", static_cast<u32>(size));
+ UNREACHABLE_MSG("Unimplemented conversion size: {}", static_cast<u32>(size));
}
}
@@ -525,6 +577,7 @@ public:
((header.vtg.clip_distances >> index) & 1) == 0,
"Shader is setting gl_ClipDistance{} without enabling it in the header", index);
+ clip_distances[index] = true;
fixed_pipeline_output_attributes_used.insert(attribute);
shader.AddLine(dest + '[' + std::to_string(index) + "] = " + src + ';');
break;
@@ -602,6 +655,11 @@ public:
return used_samplers;
}
+ /// Returns an array of the used clip distances.
+ const std::array<bool, Maxwell::NumClipDistances>& GetClipDistances() const {
+ return clip_distances;
+ }
+
/// Returns the GLSL sampler used for the input shader sampler, and creates a new one if
/// necessary.
std::string AccessSampler(const Sampler& sampler, Tegra::Shader::TextureType type,
@@ -810,14 +868,12 @@ private:
}
if (precise && stage != Maxwell3D::Regs::ShaderStage::Fragment) {
- shader.AddLine('{');
- ++shader.scope;
+ const auto scope = shader.Scope();
+
// This avoids optimizations of constant propagation and keeps the code as the original
// Sadly using the precise keyword causes "linking" errors on fragment shaders.
shader.AddLine("precise float tmp = " + src + ';');
shader.AddLine(dest + " = tmp;");
- --shader.scope;
- shader.AddLine('}');
} else {
shader.AddLine(dest + " = " + src + ';');
}
@@ -956,14 +1012,6 @@ private:
}
}
- /// Generates code to use for a swizzle operation.
- static std::string GetSwizzle(u64 elem) {
- ASSERT(elem <= 3);
- std::string swizzle = ".";
- swizzle += "xyzw"[elem];
- return swizzle;
- }
-
ShaderWriter& shader;
ShaderWriter& declarations;
std::vector<GLSLRegister> regs;
@@ -975,6 +1023,7 @@ private:
const std::string& suffix;
const Tegra::Shader::Header& header;
std::unordered_set<Attribute::Index> fixed_pipeline_output_attributes_used;
+ std::array<bool, Maxwell::NumClipDistances> clip_distances{};
u64 local_memory_size;
};
@@ -997,7 +1046,8 @@ public:
/// Returns entries in the shader that are useful for external functions
ShaderEntries GetEntries() const {
- return {regs.GetConstBuffersDeclarations(), regs.GetSamplers(), shader_length};
+ return {regs.GetConstBuffersDeclarations(), regs.GetSamplers(), regs.GetClipDistances(),
+ shader_length};
}
private:
@@ -1293,15 +1343,7 @@ private:
regs.SetRegisterToInteger(dest, true, 0, result, 1, 1);
}
- void WriteTexsInstruction(const Instruction& instr, const std::string& coord,
- const std::string& texture) {
- // Add an extra scope and declare the texture coords inside to prevent
- // overwriting them in case they are used as outputs of the texs instruction.
- shader.AddLine('{');
- ++shader.scope;
- shader.AddLine(coord);
- shader.AddLine("vec4 texture_tmp = " + texture + ';');
-
+ void WriteTexsInstructionFloat(const Instruction& instr, const std::string& texture) {
// TEXS has two destination registers and a swizzle. The first two elements in the swizzle
// go into gpr0+0 and gpr0+1, and the rest goes into gpr28+0 and gpr28+1
@@ -1313,19 +1355,49 @@ private:
if (written_components < 2) {
// Write the first two swizzle components to gpr0 and gpr0+1
- regs.SetRegisterToFloat(instr.gpr0, component, "texture_tmp", 1, 4, false,
+ regs.SetRegisterToFloat(instr.gpr0, component, texture, 1, 4, false,
written_components % 2);
} else {
ASSERT(instr.texs.HasTwoDestinations());
// Write the rest of the swizzle components to gpr28 and gpr28+1
- regs.SetRegisterToFloat(instr.gpr28, component, "texture_tmp", 1, 4, false,
+ regs.SetRegisterToFloat(instr.gpr28, component, texture, 1, 4, false,
written_components % 2);
}
++written_components;
}
- --shader.scope;
- shader.AddLine('}');
+ }
+
+ void WriteTexsInstructionHalfFloat(const Instruction& instr, const std::string& texture) {
+ // TEXS.F16 destionation registers are packed in two registers in pairs (just like any half
+ // float instruction).
+
+ std::array<std::string, 4> components;
+ u32 written_components = 0;
+
+ for (u32 component = 0; component < 4; ++component) {
+ if (!instr.texs.IsComponentEnabled(component))
+ continue;
+ components[written_components++] = texture + GetSwizzle(component);
+ }
+ if (written_components == 0)
+ return;
+
+ const auto BuildComponent = [&](std::string low, std::string high, bool high_enabled) {
+ return "vec2(" + low + ", " + (high_enabled ? high : "0") + ')';
+ };
+
+ regs.SetRegisterToHalfFloat(
+ instr.gpr0, 0, BuildComponent(components[0], components[1], written_components > 1),
+ Tegra::Shader::HalfMerge::H0_H1, 1, 1);
+
+ if (written_components > 2) {
+ ASSERT(instr.texs.HasTwoDestinations());
+ regs.SetRegisterToHalfFloat(
+ instr.gpr28, 0,
+ BuildComponent(components[2], components[3], written_components > 3),
+ Tegra::Shader::HalfMerge::H0_H1, 1, 1);
+ }
}
static u32 TextureCoordinates(Tegra::Shader::TextureType texture_type) {
@@ -1348,12 +1420,10 @@ private:
* top.
*/
void EmitPushToFlowStack(u32 target) {
- shader.AddLine('{');
- ++shader.scope;
+ const auto scope = shader.Scope();
+
shader.AddLine("flow_stack[flow_stack_top] = " + std::to_string(target) + "u;");
shader.AddLine("flow_stack_top++;");
- --shader.scope;
- shader.AddLine('}');
}
/*
@@ -1361,13 +1431,11 @@ private:
* popped address and decrementing the stack top.
*/
void EmitPopFromFlowStack() {
- shader.AddLine('{');
- ++shader.scope;
+ const auto scope = shader.Scope();
+
shader.AddLine("flow_stack_top--;");
shader.AddLine("jmp_to = flow_stack[flow_stack_top];");
shader.AddLine("break;");
- --shader.scope;
- shader.AddLine('}');
}
/// Writes the output values from a fragment shader to the corresponding GLSL output variables.
@@ -1479,6 +1547,161 @@ private:
}
}
+ std::pair<size_t, std::string> ValidateAndGetCoordinateElement(
+ const Tegra::Shader::TextureType texture_type, const bool depth_compare,
+ const bool is_array, const bool lod_bias_enabled, size_t max_coords, size_t max_inputs) {
+ const size_t coord_count = TextureCoordinates(texture_type);
+
+ size_t total_coord_count = coord_count + (is_array ? 1 : 0) + (depth_compare ? 1 : 0);
+ const size_t total_reg_count = total_coord_count + (lod_bias_enabled ? 1 : 0);
+ if (total_coord_count > max_coords || total_reg_count > max_inputs) {
+ UNIMPLEMENTED_MSG("Unsupported Texture operation");
+ total_coord_count = std::min(total_coord_count, max_coords);
+ }
+ // 1D.DC opengl is using a vec3 but 2nd component is ignored later.
+ total_coord_count +=
+ (depth_compare && !is_array && texture_type == Tegra::Shader::TextureType::Texture1D)
+ ? 1
+ : 0;
+
+ constexpr std::array<const char*, 5> coord_container{
+ {"", "float coord = (", "vec2 coord = vec2(", "vec3 coord = vec3(",
+ "vec4 coord = vec4("}};
+
+ return std::pair<size_t, std::string>(coord_count, coord_container[total_coord_count]);
+ }
+
+ std::string GetTextureCode(const Tegra::Shader::Instruction& instr,
+ const Tegra::Shader::TextureType texture_type,
+ const Tegra::Shader::TextureProcessMode process_mode,
+ const bool depth_compare, const bool is_array,
+ const size_t bias_offset) {
+
+ if ((texture_type == Tegra::Shader::TextureType::Texture3D &&
+ (is_array || depth_compare)) ||
+ (texture_type == Tegra::Shader::TextureType::TextureCube && is_array &&
+ depth_compare)) {
+ UNIMPLEMENTED_MSG("This method is not supported.");
+ }
+
+ const std::string sampler =
+ GetSampler(instr.sampler, texture_type, is_array, depth_compare);
+
+ const bool lod_needed = process_mode == Tegra::Shader::TextureProcessMode::LZ ||
+ process_mode == Tegra::Shader::TextureProcessMode::LL ||
+ process_mode == Tegra::Shader::TextureProcessMode::LLA;
+
+ const bool gl_lod_supported = !(
+ (texture_type == Tegra::Shader::TextureType::Texture2D && is_array && depth_compare) ||
+ (texture_type == Tegra::Shader::TextureType::TextureCube && !is_array &&
+ depth_compare));
+
+ const std::string read_method = lod_needed && gl_lod_supported ? "textureLod(" : "texture(";
+ std::string texture = read_method + sampler + ", coord";
+
+ if (process_mode != Tegra::Shader::TextureProcessMode::None) {
+ if (process_mode == Tegra::Shader::TextureProcessMode::LZ) {
+ if (gl_lod_supported) {
+ texture += ", 0";
+ } else {
+ // Lod 0 is emulated by a big negative bias
+ // in scenarios that are not supported by glsl
+ texture += ", -1000";
+ }
+ } else {
+ // If present, lod or bias are always stored in the register indexed by the
+ // gpr20
+ // field with an offset depending on the usage of the other registers
+ texture += ',' + regs.GetRegisterAsFloat(instr.gpr20.Value() + bias_offset);
+ }
+ }
+ texture += ")";
+ return texture;
+ }
+
+ std::pair<std::string, std::string> GetTEXCode(
+ const Instruction& instr, const Tegra::Shader::TextureType texture_type,
+ const Tegra::Shader::TextureProcessMode process_mode, const bool depth_compare,
+ const bool is_array) {
+ const bool lod_bias_enabled = (process_mode != Tegra::Shader::TextureProcessMode::None &&
+ process_mode != Tegra::Shader::TextureProcessMode::LZ);
+
+ const auto [coord_count, coord_dcl] = ValidateAndGetCoordinateElement(
+ texture_type, depth_compare, is_array, lod_bias_enabled, 4, 5);
+ // If enabled arrays index is always stored in the gpr8 field
+ const u64 array_register = instr.gpr8.Value();
+ // First coordinate index is the gpr8 or gpr8 + 1 when arrays are used
+ const u64 coord_register = array_register + (is_array ? 1 : 0);
+
+ std::string coord = coord_dcl;
+ for (size_t i = 0; i < coord_count;) {
+ coord += regs.GetRegisterAsFloat(coord_register + i);
+ ++i;
+ if (i != coord_count) {
+ coord += ',';
+ }
+ }
+ // 1D.DC in opengl the 2nd component is ignored.
+ if (depth_compare && !is_array && texture_type == Tegra::Shader::TextureType::Texture1D) {
+ coord += ",0.0";
+ }
+ if (depth_compare) {
+ // Depth is always stored in the register signaled by gpr20
+ // or in the next register if lod or bias are used
+ const u64 depth_register = instr.gpr20.Value() + (lod_bias_enabled ? 1 : 0);
+ coord += ',' + regs.GetRegisterAsFloat(depth_register);
+ }
+ if (is_array) {
+ coord += ',' + regs.GetRegisterAsInteger(array_register);
+ }
+ coord += ");";
+ return std::make_pair(
+ coord, GetTextureCode(instr, texture_type, process_mode, depth_compare, is_array, 0));
+ }
+
+ std::pair<std::string, std::string> GetTEXSCode(
+ const Instruction& instr, const Tegra::Shader::TextureType texture_type,
+ const Tegra::Shader::TextureProcessMode process_mode, const bool depth_compare,
+ const bool is_array) {
+ const bool lod_bias_enabled = (process_mode != Tegra::Shader::TextureProcessMode::None &&
+ process_mode != Tegra::Shader::TextureProcessMode::LZ);
+
+ const auto [coord_count, coord_dcl] = ValidateAndGetCoordinateElement(
+ texture_type, depth_compare, is_array, lod_bias_enabled, 4, 4);
+ // If enabled arrays index is always stored in the gpr8 field
+ const u64 array_register = instr.gpr8.Value();
+ // First coordinate index is stored in gpr8 field or (gpr8 + 1) when arrays are used
+ const u64 coord_register = array_register + (is_array ? 1 : 0);
+ const u64 last_coord_register =
+ (is_array || !(lod_bias_enabled || depth_compare) || (coord_count > 2))
+ ? static_cast<u64>(instr.gpr20.Value())
+ : coord_register + 1;
+
+ std::string coord = coord_dcl;
+ for (size_t i = 0; i < coord_count; ++i) {
+ const bool last = (i == (coord_count - 1)) && (coord_count > 1);
+ coord += regs.GetRegisterAsFloat(last ? last_coord_register : coord_register + i);
+ if (!last) {
+ coord += ',';
+ }
+ }
+
+ if (depth_compare) {
+ // Depth is always stored in the register signaled by gpr20
+ // or in the next register if lod or bias are used
+ const u64 depth_register = instr.gpr20.Value() + (lod_bias_enabled ? 1 : 0);
+ coord += ',' + regs.GetRegisterAsFloat(depth_register);
+ }
+ if (is_array) {
+ coord += ',' + regs.GetRegisterAsInteger(array_register);
+ }
+ coord += ");";
+
+ return std::make_pair(coord,
+ GetTextureCode(instr, texture_type, process_mode, depth_compare,
+ is_array, (coord_count > 2 ? 1 : 0)));
+ }
+
/**
* Compiles a single instruction from Tegra to GLSL.
* @param offset the offset of the Tegra shader instruction.
@@ -2279,8 +2502,7 @@ private:
UNIMPLEMENTED_IF(instr.conversion.selector);
UNIMPLEMENTED_IF_MSG(instr.generates_cc,
"Condition codes generation in I2F is not implemented");
-
- std::string op_a{};
+ std::string op_a;
if (instr.is_b_gpr) {
op_a =
@@ -2436,10 +2658,7 @@ private:
case OpCode::Id::LD_C: {
UNIMPLEMENTED_IF(instr.ld_c.unknown != 0);
- // Add an extra scope and declare the index register inside to prevent
- // overwriting it in case it is used as an output of the LD instruction.
- shader.AddLine("{");
- ++shader.scope;
+ const auto scope = shader.Scope();
shader.AddLine("uint index = (" + regs.GetRegisterAsInteger(instr.gpr8, 0, false) +
" / 4) & (MAX_CONSTBUFFER_ELEMENTS - 1);");
@@ -2465,19 +2684,13 @@ private:
UNIMPLEMENTED_MSG("Unhandled type: {}",
static_cast<unsigned>(instr.ld_c.type.Value()));
}
-
- --shader.scope;
- shader.AddLine("}");
break;
}
case OpCode::Id::LD_L: {
UNIMPLEMENTED_IF_MSG(instr.ld_l.unknown == 1, "LD_L Unhandled mode: {}",
static_cast<unsigned>(instr.ld_l.unknown.Value()));
- // Add an extra scope and declare the index register inside to prevent
- // overwriting it in case it is used as an output of the LD instruction.
- shader.AddLine('{');
- ++shader.scope;
+ const auto scope = shader.Scope();
std::string op = '(' + regs.GetRegisterAsInteger(instr.gpr8, 0, false) + " + " +
std::to_string(instr.smem_imm.Value()) + ')';
@@ -2494,9 +2707,6 @@ private:
UNIMPLEMENTED_MSG("LD_L Unhandled type: {}",
static_cast<unsigned>(instr.ldst_sl.type.Value()));
}
-
- --shader.scope;
- shader.AddLine('}');
break;
}
case OpCode::Id::ST_A: {
@@ -2531,10 +2741,7 @@ private:
UNIMPLEMENTED_IF_MSG(instr.st_l.unknown == 0, "ST_L Unhandled mode: {}",
static_cast<unsigned>(instr.st_l.unknown.Value()));
- // Add an extra scope and declare the index register inside to prevent
- // overwriting it in case it is used as an output of the LD instruction.
- shader.AddLine('{');
- ++shader.scope;
+ const auto scope = shader.Scope();
std::string op = '(' + regs.GetRegisterAsInteger(instr.gpr8, 0, false) + " + " +
std::to_string(instr.smem_imm.Value()) + ')';
@@ -2549,179 +2756,28 @@ private:
UNIMPLEMENTED_MSG("ST_L Unhandled type: {}",
static_cast<unsigned>(instr.ldst_sl.type.Value()));
}
-
- --shader.scope;
- shader.AddLine('}');
break;
}
case OpCode::Id::TEX: {
Tegra::Shader::TextureType texture_type{instr.tex.texture_type};
- std::string coord;
const bool is_array = instr.tex.array != 0;
-
+ const bool depth_compare =
+ instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC);
+ const auto process_mode = instr.tex.GetTextureProcessMode();
UNIMPLEMENTED_IF_MSG(instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
"NODEP is not implemented");
UNIMPLEMENTED_IF_MSG(instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI),
"AOFFI is not implemented");
- const bool depth_compare =
- instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC);
- u32 num_coordinates = TextureCoordinates(texture_type);
- u32 start_index = 0;
- std::string array_elem;
- if (is_array) {
- array_elem = regs.GetRegisterAsInteger(instr.gpr8);
- start_index = 1;
- }
- const auto process_mode = instr.tex.GetTextureProcessMode();
- u32 start_index_b = 0;
- std::string lod_value;
- if (process_mode != Tegra::Shader::TextureProcessMode::LZ &&
- process_mode != Tegra::Shader::TextureProcessMode::None) {
- start_index_b = 1;
- lod_value = regs.GetRegisterAsFloat(instr.gpr20);
- }
-
- std::string depth_value;
- if (depth_compare) {
- depth_value = regs.GetRegisterAsFloat(instr.gpr20.Value() + start_index_b);
- }
+ const auto [coord, texture] =
+ GetTEXCode(instr, texture_type, process_mode, depth_compare, is_array);
- bool depth_compare_extra = false;
-
- switch (num_coordinates) {
- case 1: {
- const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index);
- if (is_array) {
- if (depth_compare) {
- coord = "vec3 coords = vec3(" + x + ", " + depth_value + ", " +
- array_elem + ");";
- } else {
- coord = "vec2 coords = vec2(" + x + ", " + array_elem + ");";
- }
- } else {
- if (depth_compare) {
- coord = "vec2 coords = vec2(" + x + ", " + depth_value + ");";
- } else {
- coord = "float coords = " + x + ';';
- }
- }
- break;
- }
- case 2: {
- const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index);
- const std::string y =
- regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index + 1);
- if (is_array) {
- if (depth_compare) {
- coord = "vec4 coords = vec4(" + x + ", " + y + ", " + depth_value +
- ", " + array_elem + ");";
- } else {
- coord = "vec3 coords = vec3(" + x + ", " + y + ", " + array_elem + ");";
- }
- } else {
- if (depth_compare) {
- coord =
- "vec3 coords = vec3(" + x + ", " + y + ", " + depth_value + ");";
- } else {
- coord = "vec2 coords = vec2(" + x + ", " + y + ");";
- }
- }
- break;
- }
- case 3: {
- const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index);
- const std::string y =
- regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index + 1);
- const std::string z =
- regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index + 2);
- if (is_array) {
- depth_compare_extra = depth_compare;
- coord = "vec4 coords = vec4(" + x + ", " + y + ", " + z + ", " +
- array_elem + ");";
- } else {
- if (depth_compare) {
- coord = "vec4 coords = vec4(" + x + ", " + y + ", " + z + ", " +
- depth_value + ");";
- } else {
- coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");";
- }
- }
- break;
- }
- default:
- UNIMPLEMENTED_MSG("Unhandled coordinates number {}",
- static_cast<u32>(num_coordinates));
-
- // Fallback to interpreting as a 2D texture for now
- const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
- const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
- coord = "vec2 coords = vec2(" + x + ", " + y + ");";
- texture_type = Tegra::Shader::TextureType::Texture2D;
- }
-
- const std::string sampler =
- GetSampler(instr.sampler, texture_type, is_array, depth_compare);
- // Add an extra scope and declare the texture coords inside to prevent
- // overwriting them in case they are used as outputs of the texs instruction.
-
- shader.AddLine('{');
- ++shader.scope;
+ const auto scope = shader.Scope();
shader.AddLine(coord);
- std::string texture;
- switch (instr.tex.GetTextureProcessMode()) {
- case Tegra::Shader::TextureProcessMode::None: {
- if (!depth_compare_extra) {
- texture = "texture(" + sampler + ", coords)";
- } else {
- texture = "texture(" + sampler + ", coords, " + depth_value + ')';
- }
- break;
- }
- case Tegra::Shader::TextureProcessMode::LZ: {
- if (!depth_compare_extra) {
- texture = "textureLod(" + sampler + ", coords, 0.0)";
- } else {
- texture = "texture(" + sampler + ", coords, " + depth_value + ')';
- }
- break;
- }
- case Tegra::Shader::TextureProcessMode::LB:
- case Tegra::Shader::TextureProcessMode::LBA: {
- // TODO: Figure if A suffix changes the equation at all.
- if (!depth_compare_extra) {
- texture = "texture(" + sampler + ", coords, " + lod_value + ')';
- } else {
- texture = "texture(" + sampler + ", coords, " + depth_value + ')';
- LOG_WARNING(HW_GPU,
- "OpenGL Limitation: can't set bias value along depth compare");
- }
- break;
- }
- case Tegra::Shader::TextureProcessMode::LL:
- case Tegra::Shader::TextureProcessMode::LLA: {
- // TODO: Figure if A suffix changes the equation at all.
- if (!depth_compare_extra) {
- texture = "textureLod(" + sampler + ", coords, " + lod_value + ')';
- } else {
- texture = "texture(" + sampler + ", coords, " + depth_value + ')';
- LOG_WARNING(HW_GPU,
- "OpenGL Limitation: can't set lod value along depth compare");
- }
- break;
- }
- default: {
- if (!depth_compare_extra) {
- texture = "texture(" + sampler + ", coords)";
- } else {
- texture = "texture(" + sampler + ", coords, " + depth_value + ')';
- }
- UNIMPLEMENTED_MSG("Unhandled texture process mode {}",
- static_cast<u32>(instr.tex.GetTextureProcessMode()));
- }
- }
- if (!depth_compare) {
+ if (depth_compare) {
+ regs.SetRegisterToFloat(instr.gpr0, 0, texture, 1, 1, false);
+ } else {
shader.AddLine("vec4 texture_tmp = " + texture + ';');
std::size_t dest_elem{};
for (std::size_t elem = 0; elem < 4; ++elem) {
@@ -2733,138 +2789,36 @@ private:
dest_elem);
++dest_elem;
}
- } else {
- regs.SetRegisterToFloat(instr.gpr0, 0, texture, 1, 1, false);
}
- --shader.scope;
- shader.AddLine('}');
break;
}
case OpCode::Id::TEXS: {
Tegra::Shader::TextureType texture_type{instr.texs.GetTextureType()};
- bool is_array{instr.texs.IsArrayTexture()};
+ const bool is_array{instr.texs.IsArrayTexture()};
+ const bool depth_compare =
+ instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC);
+ const auto process_mode = instr.texs.GetTextureProcessMode();
UNIMPLEMENTED_IF_MSG(instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
"NODEP is not implemented");
- const bool depth_compare =
- instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC);
- u32 num_coordinates = TextureCoordinates(texture_type);
- const auto process_mode = instr.texs.GetTextureProcessMode();
- std::string lod_value;
- std::string coord;
- u32 lod_offset = 0;
- if (process_mode == Tegra::Shader::TextureProcessMode::LL) {
- if (num_coordinates > 2) {
- lod_value = regs.GetRegisterAsFloat(instr.gpr20.Value() + 1);
- lod_offset = 2;
- } else {
- lod_value = regs.GetRegisterAsFloat(instr.gpr20);
- lod_offset = 1;
- }
- }
+ const auto scope = shader.Scope();
- switch (num_coordinates) {
- case 1: {
- coord = "float coords = " + regs.GetRegisterAsFloat(instr.gpr8) + ';';
- break;
- }
- case 2: {
- if (is_array) {
- if (depth_compare) {
- const std::string index = regs.GetRegisterAsInteger(instr.gpr8);
- const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
- const std::string y = regs.GetRegisterAsFloat(instr.gpr20);
- const std::string z = regs.GetRegisterAsFloat(instr.gpr20.Value() + 1);
- coord = "vec4 coords = vec4(" + x + ", " + y + ", " + z + ", " + index +
- ");";
- } else {
- const std::string index = regs.GetRegisterAsInteger(instr.gpr8);
- const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
- const std::string y = regs.GetRegisterAsFloat(instr.gpr20);
- coord = "vec3 coords = vec3(" + x + ", " + y + ", " + index + ");";
- }
- } else {
- if (lod_offset != 0) {
- if (depth_compare) {
- const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
- const std::string y =
- regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
- const std::string z =
- regs.GetRegisterAsFloat(instr.gpr20.Value() + lod_offset);
- coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");";
- } else {
- const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
- const std::string y =
- regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
- coord = "vec2 coords = vec2(" + x + ", " + y + ");";
- }
- } else {
- if (depth_compare) {
- const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
- const std::string y =
- regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
- const std::string z = regs.GetRegisterAsFloat(instr.gpr20);
- coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");";
- } else {
- const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
- const std::string y = regs.GetRegisterAsFloat(instr.gpr20);
- coord = "vec2 coords = vec2(" + x + ", " + y + ");";
- }
- }
- }
- break;
- }
- case 3: {
- const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
- const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
- const std::string z = regs.GetRegisterAsFloat(instr.gpr20);
- coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");";
- break;
- }
- default:
- UNIMPLEMENTED_MSG("Unhandled coordinates number {}",
- static_cast<u32>(num_coordinates));
+ auto [coord, texture] =
+ GetTEXSCode(instr, texture_type, process_mode, depth_compare, is_array);
- // Fallback to interpreting as a 2D texture for now
- const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
- const std::string y = regs.GetRegisterAsFloat(instr.gpr20);
- coord = "vec2 coords = vec2(" + x + ", " + y + ");";
- texture_type = Tegra::Shader::TextureType::Texture2D;
- is_array = false;
- }
- const std::string sampler =
- GetSampler(instr.sampler, texture_type, is_array, depth_compare);
- std::string texture;
- switch (process_mode) {
- case Tegra::Shader::TextureProcessMode::None: {
- texture = "texture(" + sampler + ", coords)";
- break;
- }
- case Tegra::Shader::TextureProcessMode::LZ: {
- if (depth_compare && is_array) {
- texture = "texture(" + sampler + ", coords)";
- } else {
- texture = "textureLod(" + sampler + ", coords, 0.0)";
- }
- break;
- }
- case Tegra::Shader::TextureProcessMode::LL: {
- texture = "textureLod(" + sampler + ", coords, " + lod_value + ')';
- break;
- }
- default: {
- texture = "texture(" + sampler + ", coords)";
- UNIMPLEMENTED_MSG("Unhandled texture process mode {}",
- static_cast<u32>(instr.texs.GetTextureProcessMode()));
- }
+ shader.AddLine(coord);
+
+ if (depth_compare) {
+ texture = "vec4(" + texture + ')';
}
- if (!depth_compare) {
- WriteTexsInstruction(instr, coord, texture);
+ shader.AddLine("vec4 texture_tmp = " + texture + ';');
+
+ if (instr.texs.fp32_flag) {
+ WriteTexsInstructionFloat(instr, "texture_tmp");
} else {
- WriteTexsInstruction(instr, coord, "vec4(" + texture + ')');
+ WriteTexsInstructionHalfFloat(instr, "texture_tmp");
}
-
break;
}
case OpCode::Id::TLDS: {
@@ -2883,15 +2837,12 @@ private:
u32 extra_op_offset = 0;
- // Scope to avoid variable name overlaps.
- shader.AddLine('{');
- ++shader.scope;
- std::string coords;
+ ShaderScopedScope scope = shader.Scope();
switch (texture_type) {
case Tegra::Shader::TextureType::Texture1D: {
const std::string x = regs.GetRegisterAsInteger(instr.gpr8);
- coords = "float coords = " + x + ';';
+ shader.AddLine("float coords = " + x + ';');
break;
}
case Tegra::Shader::TextureType::Texture2D: {
@@ -2900,7 +2851,7 @@ private:
const std::string x = regs.GetRegisterAsInteger(instr.gpr8);
const std::string y = regs.GetRegisterAsInteger(instr.gpr20);
// shader.AddLine("ivec2 coords = ivec2(" + x + ", " + y + ");");
- coords = "ivec2 coords = ivec2(" + x + ", " + y + ");";
+ shader.AddLine("ivec2 coords = ivec2(" + x + ", " + y + ");");
extra_op_offset = 1;
break;
}
@@ -2909,35 +2860,29 @@ private:
}
const std::string sampler =
GetSampler(instr.sampler, texture_type, is_array, false);
- std::string texture = "texelFetch(" + sampler + ", coords, 0)";
- switch (instr.tlds.GetTextureProcessMode()) {
- case Tegra::Shader::TextureProcessMode::LZ: {
- texture = "texelFetch(" + sampler + ", coords, 0)";
- break;
- }
- case Tegra::Shader::TextureProcessMode::LL: {
- shader.AddLine(
- "float lod = " +
- regs.GetRegisterAsInteger(instr.gpr20.Value() + extra_op_offset) + ';');
- texture = "texelFetch(" + sampler + ", coords, lod)";
- break;
- }
- default: {
- texture = "texelFetch(" + sampler + ", coords, 0)";
- UNIMPLEMENTED_MSG("Unhandled texture process mode {}",
- static_cast<u32>(instr.tlds.GetTextureProcessMode()));
- }
- }
- WriteTexsInstruction(instr, coords, texture);
- --shader.scope;
- shader.AddLine('}');
+ const std::string texture = [&]() {
+ switch (instr.tlds.GetTextureProcessMode()) {
+ case Tegra::Shader::TextureProcessMode::LZ:
+ return "texelFetch(" + sampler + ", coords, 0)";
+ case Tegra::Shader::TextureProcessMode::LL:
+ shader.AddLine(
+ "float lod = " +
+ regs.GetRegisterAsInteger(instr.gpr20.Value() + extra_op_offset) + ';');
+ return "texelFetch(" + sampler + ", coords, lod)";
+ default:
+ UNIMPLEMENTED_MSG("Unhandled texture process mode {}",
+ static_cast<u32>(instr.tlds.GetTextureProcessMode()));
+ return "texelFetch(" + sampler + ", coords, 0)";
+ }
+ }();
+
+ WriteTexsInstructionFloat(instr, texture);
break;
}
case OpCode::Id::TLD4: {
ASSERT(instr.tld4.texture_type == Tegra::Shader::TextureType::Texture2D);
ASSERT(instr.tld4.array == 0);
- std::string coord;
UNIMPLEMENTED_IF_MSG(instr.tld4.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
"NODEP is not implemented");
@@ -2954,10 +2899,7 @@ private:
if (depth_compare)
num_coordinates += 1;
- // Add an extra scope and declare the texture coords inside to prevent
- // overwriting them in case they are used as outputs of the texs instruction.
- shader.AddLine('{');
- ++shader.scope;
+ const auto scope = shader.Scope();
switch (num_coordinates) {
case 2: {
@@ -2988,23 +2930,19 @@ private:
const std::string texture = "textureGather(" + sampler + ", coords, " +
std::to_string(instr.tld4.component) + ')';
- if (!depth_compare) {
- shader.AddLine("vec4 texture_tmp = " + texture + ';');
+ if (depth_compare) {
+ regs.SetRegisterToFloat(instr.gpr0, 0, texture, 1, 1, false);
+ } else {
std::size_t dest_elem{};
for (std::size_t elem = 0; elem < 4; ++elem) {
if (!instr.tex.IsComponentEnabled(elem)) {
// Skip disabled components
continue;
}
- regs.SetRegisterToFloat(instr.gpr0, elem, "texture_tmp", 1, 4, false,
- dest_elem);
+ regs.SetRegisterToFloat(instr.gpr0, elem, texture, 1, 4, false, dest_elem);
++dest_elem;
}
- } else {
- regs.SetRegisterToFloat(instr.gpr0, 0, texture, 1, 1, false);
}
- --shader.scope;
- shader.AddLine('}');
break;
}
case OpCode::Id::TLD4S: {
@@ -3015,10 +2953,7 @@ private:
instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI),
"AOFFI is not implemented");
- // Scope to avoid variable name overlaps.
- shader.AddLine('{');
- ++shader.scope;
- std::string coords;
+ const auto scope = shader.Scope();
const bool depth_compare =
instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC);
@@ -3027,33 +2962,30 @@ private:
// TODO(Subv): Figure out how the sampler type is encoded in the TLD4S instruction.
const std::string sampler = GetSampler(
instr.sampler, Tegra::Shader::TextureType::Texture2D, false, depth_compare);
- if (!depth_compare) {
- coords = "vec2 coords = vec2(" + op_a + ", " + op_b + ");";
- } else {
+ if (depth_compare) {
// Note: TLD4S coordinate encoding works just like TEXS's
const std::string op_y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
- coords = "vec3 coords = vec3(" + op_a + ", " + op_y + ", " + op_b + ");";
+ shader.AddLine("vec3 coords = vec3(" + op_a + ", " + op_y + ", " + op_b + ");");
+ } else {
+ shader.AddLine("vec2 coords = vec2(" + op_a + ", " + op_b + ");");
}
- const std::string texture = "textureGather(" + sampler + ", coords, " +
- std::to_string(instr.tld4s.component) + ')';
- if (!depth_compare) {
- WriteTexsInstruction(instr, coords, texture);
- } else {
- WriteTexsInstruction(instr, coords, "vec4(" + texture + ')');
+ std::string texture = "textureGather(" + sampler + ", coords, " +
+ std::to_string(instr.tld4s.component) + ')';
+ if (depth_compare) {
+ texture = "vec4(" + texture + ')';
}
- --shader.scope;
- shader.AddLine('}');
+ WriteTexsInstructionFloat(instr, texture);
break;
}
case OpCode::Id::TXQ: {
UNIMPLEMENTED_IF_MSG(instr.txq.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP),
"NODEP is not implemented");
- ++shader.scope;
- shader.AddLine('{');
- // TODO: the new commits on the texture refactor, change the way samplers work.
+ const auto scope = shader.Scope();
+
+ // TODO: The new commits on the texture refactor, change the way samplers work.
// Sadly, not all texture instructions specify the type of texture their sampler
// uses. This must be fixed at a later instance.
const std::string sampler =
@@ -3064,7 +2996,8 @@ private:
regs.GetRegisterAsInteger(instr.gpr8) + ')';
const std::string mip_level = "textureQueryLevels(" + sampler + ')';
shader.AddLine("ivec2 sizes = " + texture + ';');
- regs.SetRegisterToInteger(instr.gpr0, true, 0, "sizes.x", 1, 1);
+
+ regs.SetRegisterToInteger(instr.gpr0.Value() + 0, true, 0, "sizes.x", 1, 1);
regs.SetRegisterToInteger(instr.gpr0.Value() + 1, true, 0, "sizes.y", 1, 1);
regs.SetRegisterToInteger(instr.gpr0.Value() + 2, true, 0, "0", 1, 1);
regs.SetRegisterToInteger(instr.gpr0.Value() + 3, true, 0, mip_level, 1, 1);
@@ -3075,8 +3008,6 @@ private:
static_cast<u32>(instr.txq.query_type.Value()));
}
}
- --shader.scope;
- shader.AddLine('}');
break;
}
case OpCode::Id::TMML: {
@@ -3091,17 +3022,18 @@ private:
const std::string sampler =
GetSampler(instr.sampler, texture_type, is_array, false);
- // TODO: add coordinates for different samplers once other texture types are
+ const auto scope = shader.Scope();
+
+ // TODO: Add coordinates for different samplers once other texture types are
// implemented.
- std::string coord;
switch (texture_type) {
case Tegra::Shader::TextureType::Texture1D: {
- coord = "float coords = " + x + ';';
+ shader.AddLine("float coords = " + x + ';');
break;
}
case Tegra::Shader::TextureType::Texture2D: {
const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
- coord = "vec2 coords = vec2(" + x + ", " + y + ");";
+ shader.AddLine("vec2 coords = vec2(" + x + ", " + y + ");");
break;
}
default:
@@ -3109,22 +3041,15 @@ private:
// Fallback to interpreting as a 2D texture for now
const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
- coord = "vec2 coords = vec2(" + x + ", " + y + ");";
+ shader.AddLine("vec2 coords = vec2(" + x + ", " + y + ");");
texture_type = Tegra::Shader::TextureType::Texture2D;
}
- // Add an extra scope and declare the texture coords inside to prevent
- // overwriting them in case they are used as outputs of the texs instruction.
- shader.AddLine('{');
- ++shader.scope;
- shader.AddLine(coord);
+
const std::string texture = "textureQueryLod(" + sampler + ", coords)";
- const std::string tmp = "vec2 tmp = " + texture + "*vec2(256.0, 256.0);";
- shader.AddLine(tmp);
+ shader.AddLine("vec2 tmp = " + texture + " * vec2(256.0, 256.0);");
regs.SetRegisterToInteger(instr.gpr0, true, 0, "int(tmp.y)", 1, 1);
regs.SetRegisterToInteger(instr.gpr0.Value() + 1, false, 0, "uint(tmp.x)", 1, 1);
- --shader.scope;
- shader.AddLine('}');
break;
}
default: {
@@ -3963,4 +3888,4 @@ std::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, u
return {};
}
-} // namespace OpenGL::GLShader::Decompiler
+} // 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:
struct ShaderEntries {
std::vector<ConstBufferEntry> const_buffer_entries;
std::vector<SamplerEntry> texture_samplers;
+ std::array<bool, Tegra::Engines::Maxwell3D::Regs::NumClipDistances> clip_distances;
std::size_t shader_length;
};
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:
}
void ApplyTo(OpenGLState& state) {
+ UpdatePipeline();
+ state.draw.shader_program = 0;
+ state.draw.program_pipeline = pipeline.handle;
+ state.geometry_shaders.enabled = (gs != 0);
+ }
+
+private:
+ void UpdatePipeline() {
+ // Avoid updating the pipeline when values have no changed
+ if (old_vs == vs && old_fs == fs && old_gs == gs)
+ return;
// Workaround for AMD bug
glUseProgramStages(pipeline.handle,
GL_VERTEX_SHADER_BIT | GL_GEOMETRY_SHADER_BIT | GL_FRAGMENT_SHADER_BIT,
@@ -68,14 +79,16 @@ public:
glUseProgramStages(pipeline.handle, GL_VERTEX_SHADER_BIT, vs);
glUseProgramStages(pipeline.handle, GL_GEOMETRY_SHADER_BIT, gs);
glUseProgramStages(pipeline.handle, GL_FRAGMENT_SHADER_BIT, fs);
- state.draw.shader_program = 0;
- state.draw.program_pipeline = pipeline.handle;
- state.geometry_shaders.enabled = (gs != 0);
+
+ // Update the old values
+ old_vs = vs;
+ old_fs = fs;
+ old_gs = gs;
}
-private:
OGLPipeline pipeline;
GLuint vs{}, fs{}, gs{};
+ GLuint old_vs{}, old_fs{}, old_gs{};
};
} // namespace OpenGL::GLShader
diff --git a/src/video_core/surface.h b/src/video_core/surface.h
index 0dd3eb2e4..e23cfecbc 100644
--- a/src/video_core/surface.h
+++ b/src/video_core/surface.h
@@ -125,6 +125,75 @@ enum class SurfaceTarget {
TextureCubeArray,
};
+constexpr std::array<u32, MaxPixelFormat> compression_factor_table = {{
+ 1, // ABGR8U
+ 1, // ABGR8S
+ 1, // ABGR8UI
+ 1, // B5G6R5U
+ 1, // A2B10G10R10U
+ 1, // A1B5G5R5U
+ 1, // R8U
+ 1, // R8UI
+ 1, // RGBA16F
+ 1, // RGBA16U
+ 1, // RGBA16UI
+ 1, // R11FG11FB10F
+ 1, // RGBA32UI
+ 4, // DXT1
+ 4, // DXT23
+ 4, // DXT45
+ 4, // DXN1
+ 4, // DXN2UNORM
+ 4, // DXN2SNORM
+ 4, // BC7U
+ 4, // BC6H_UF16
+ 4, // BC6H_SF16
+ 4, // ASTC_2D_4X4
+ 1, // G8R8U
+ 1, // G8R8S
+ 1, // BGRA8
+ 1, // RGBA32F
+ 1, // RG32F
+ 1, // R32F
+ 1, // R16F
+ 1, // R16U
+ 1, // R16S
+ 1, // R16UI
+ 1, // R16I
+ 1, // RG16
+ 1, // RG16F
+ 1, // RG16UI
+ 1, // RG16I
+ 1, // RG16S
+ 1, // RGB32F
+ 1, // RGBA8_SRGB
+ 1, // RG8U
+ 1, // RG8S
+ 1, // RG32UI
+ 1, // R32UI
+ 4, // ASTC_2D_8X8
+ 4, // ASTC_2D_8X5
+ 4, // ASTC_2D_5X4
+ 1, // BGRA8_SRGB
+ 4, // DXT1_SRGB
+ 4, // DXT23_SRGB
+ 4, // DXT45_SRGB
+ 4, // BC7U_SRGB
+ 4, // ASTC_2D_4X4_SRGB
+ 4, // ASTC_2D_8X8_SRGB
+ 4, // ASTC_2D_8X5_SRGB
+ 4, // ASTC_2D_5X4_SRGB
+ 4, // ASTC_2D_5X5
+ 4, // ASTC_2D_5X5_SRGB
+ 4, // ASTC_2D_10X8
+ 4, // ASTC_2D_10X8_SRGB
+ 1, // Z32F
+ 1, // Z16
+ 1, // Z24S8
+ 1, // S8Z24
+ 1, // Z32FS8
+}};
+
/**
* Gets the compression factor for the specified PixelFormat. This applies to just the
* "compressed width" and "compressed height", not the overall compression factor of a
@@ -135,304 +204,237 @@ static constexpr u32 GetCompressionFactor(PixelFormat format) {
if (format == PixelFormat::Invalid)
return 0;
- constexpr std::array<u32, MaxPixelFormat> compression_factor_table = {{
- 1, // ABGR8U
- 1, // ABGR8S
- 1, // ABGR8UI
- 1, // B5G6R5U
- 1, // A2B10G10R10U
- 1, // A1B5G5R5U
- 1, // R8U
- 1, // R8UI
- 1, // RGBA16F
- 1, // RGBA16U
- 1, // RGBA16UI
- 1, // R11FG11FB10F
- 1, // RGBA32UI
- 4, // DXT1
- 4, // DXT23
- 4, // DXT45
- 4, // DXN1
- 4, // DXN2UNORM
- 4, // DXN2SNORM
- 4, // BC7U
- 4, // BC6H_UF16
- 4, // BC6H_SF16
- 4, // ASTC_2D_4X4
- 1, // G8R8U
- 1, // G8R8S
- 1, // BGRA8
- 1, // RGBA32F
- 1, // RG32F
- 1, // R32F
- 1, // R16F
- 1, // R16U
- 1, // R16S
- 1, // R16UI
- 1, // R16I
- 1, // RG16
- 1, // RG16F
- 1, // RG16UI
- 1, // RG16I
- 1, // RG16S
- 1, // RGB32F
- 1, // RGBA8_SRGB
- 1, // RG8U
- 1, // RG8S
- 1, // RG32UI
- 1, // R32UI
- 4, // ASTC_2D_8X8
- 4, // ASTC_2D_8X5
- 4, // ASTC_2D_5X4
- 1, // BGRA8_SRGB
- 4, // DXT1_SRGB
- 4, // DXT23_SRGB
- 4, // DXT45_SRGB
- 4, // BC7U_SRGB
- 4, // ASTC_2D_4X4_SRGB
- 4, // ASTC_2D_8X8_SRGB
- 4, // ASTC_2D_8X5_SRGB
- 4, // ASTC_2D_5X4_SRGB
- 4, // ASTC_2D_5X5
- 4, // ASTC_2D_5X5_SRGB
- 4, // ASTC_2D_10X8
- 4, // ASTC_2D_10X8_SRGB
- 1, // Z32F
- 1, // Z16
- 1, // Z24S8
- 1, // S8Z24
- 1, // Z32FS8
- }};
-
ASSERT(static_cast<std::size_t>(format) < compression_factor_table.size());
return compression_factor_table[static_cast<std::size_t>(format)];
}
+constexpr std::array<u32, MaxPixelFormat> block_width_table = {{
+ 1, // ABGR8U
+ 1, // ABGR8S
+ 1, // ABGR8UI
+ 1, // B5G6R5U
+ 1, // A2B10G10R10U
+ 1, // A1B5G5R5U
+ 1, // R8U
+ 1, // R8UI
+ 1, // RGBA16F
+ 1, // RGBA16U
+ 1, // RGBA16UI
+ 1, // R11FG11FB10F
+ 1, // RGBA32UI
+ 4, // DXT1
+ 4, // DXT23
+ 4, // DXT45
+ 4, // DXN1
+ 4, // DXN2UNORM
+ 4, // DXN2SNORM
+ 4, // BC7U
+ 4, // BC6H_UF16
+ 4, // BC6H_SF16
+ 4, // ASTC_2D_4X4
+ 1, // G8R8U
+ 1, // G8R8S
+ 1, // BGRA8
+ 1, // RGBA32F
+ 1, // RG32F
+ 1, // R32F
+ 1, // R16F
+ 1, // R16U
+ 1, // R16S
+ 1, // R16UI
+ 1, // R16I
+ 1, // RG16
+ 1, // RG16F
+ 1, // RG16UI
+ 1, // RG16I
+ 1, // RG16S
+ 1, // RGB32F
+ 1, // RGBA8_SRGB
+ 1, // RG8U
+ 1, // RG8S
+ 1, // RG32UI
+ 1, // R32UI
+ 8, // ASTC_2D_8X8
+ 8, // ASTC_2D_8X5
+ 5, // ASTC_2D_5X4
+ 1, // BGRA8_SRGB
+ 4, // DXT1_SRGB
+ 4, // DXT23_SRGB
+ 4, // DXT45_SRGB
+ 4, // BC7U_SRGB
+ 4, // ASTC_2D_4X4_SRGB
+ 8, // ASTC_2D_8X8_SRGB
+ 8, // ASTC_2D_8X5_SRGB
+ 5, // ASTC_2D_5X4_SRGB
+ 5, // ASTC_2D_5X5
+ 5, // ASTC_2D_5X5_SRGB
+ 10, // ASTC_2D_10X8
+ 10, // ASTC_2D_10X8_SRGB
+ 1, // Z32F
+ 1, // Z16
+ 1, // Z24S8
+ 1, // S8Z24
+ 1, // Z32FS8
+}};
+
static constexpr u32 GetDefaultBlockWidth(PixelFormat format) {
if (format == PixelFormat::Invalid)
return 0;
- constexpr std::array<u32, MaxPixelFormat> block_width_table = {{
- 1, // ABGR8U
- 1, // ABGR8S
- 1, // ABGR8UI
- 1, // B5G6R5U
- 1, // A2B10G10R10U
- 1, // A1B5G5R5U
- 1, // R8U
- 1, // R8UI
- 1, // RGBA16F
- 1, // RGBA16U
- 1, // RGBA16UI
- 1, // R11FG11FB10F
- 1, // RGBA32UI
- 4, // DXT1
- 4, // DXT23
- 4, // DXT45
- 4, // DXN1
- 4, // DXN2UNORM
- 4, // DXN2SNORM
- 4, // BC7U
- 4, // BC6H_UF16
- 4, // BC6H_SF16
- 4, // ASTC_2D_4X4
- 1, // G8R8U
- 1, // G8R8S
- 1, // BGRA8
- 1, // RGBA32F
- 1, // RG32F
- 1, // R32F
- 1, // R16F
- 1, // R16U
- 1, // R16S
- 1, // R16UI
- 1, // R16I
- 1, // RG16
- 1, // RG16F
- 1, // RG16UI
- 1, // RG16I
- 1, // RG16S
- 1, // RGB32F
- 1, // RGBA8_SRGB
- 1, // RG8U
- 1, // RG8S
- 1, // RG32UI
- 1, // R32UI
- 8, // ASTC_2D_8X8
- 8, // ASTC_2D_8X5
- 5, // ASTC_2D_5X4
- 1, // BGRA8_SRGB
- 4, // DXT1_SRGB
- 4, // DXT23_SRGB
- 4, // DXT45_SRGB
- 4, // BC7U_SRGB
- 4, // ASTC_2D_4X4_SRGB
- 8, // ASTC_2D_8X8_SRGB
- 8, // ASTC_2D_8X5_SRGB
- 5, // ASTC_2D_5X4_SRGB
- 5, // ASTC_2D_5X5
- 5, // ASTC_2D_5X5_SRGB
- 10, // ASTC_2D_10X8
- 10, // ASTC_2D_10X8_SRGB
- 1, // Z32F
- 1, // Z16
- 1, // Z24S8
- 1, // S8Z24
- 1, // Z32FS8
- }};
+
ASSERT(static_cast<std::size_t>(format) < block_width_table.size());
return block_width_table[static_cast<std::size_t>(format)];
}
+constexpr std::array<u32, MaxPixelFormat> block_height_table = {{
+ 1, // ABGR8U
+ 1, // ABGR8S
+ 1, // ABGR8UI
+ 1, // B5G6R5U
+ 1, // A2B10G10R10U
+ 1, // A1B5G5R5U
+ 1, // R8U
+ 1, // R8UI
+ 1, // RGBA16F
+ 1, // RGBA16U
+ 1, // RGBA16UI
+ 1, // R11FG11FB10F
+ 1, // RGBA32UI
+ 4, // DXT1
+ 4, // DXT23
+ 4, // DXT45
+ 4, // DXN1
+ 4, // DXN2UNORM
+ 4, // DXN2SNORM
+ 4, // BC7U
+ 4, // BC6H_UF16
+ 4, // BC6H_SF16
+ 4, // ASTC_2D_4X4
+ 1, // G8R8U
+ 1, // G8R8S
+ 1, // BGRA8
+ 1, // RGBA32F
+ 1, // RG32F
+ 1, // R32F
+ 1, // R16F
+ 1, // R16U
+ 1, // R16S
+ 1, // R16UI
+ 1, // R16I
+ 1, // RG16
+ 1, // RG16F
+ 1, // RG16UI
+ 1, // RG16I
+ 1, // RG16S
+ 1, // RGB32F
+ 1, // RGBA8_SRGB
+ 1, // RG8U
+ 1, // RG8S
+ 1, // RG32UI
+ 1, // R32UI
+ 8, // ASTC_2D_8X8
+ 5, // ASTC_2D_8X5
+ 4, // ASTC_2D_5X4
+ 1, // BGRA8_SRGB
+ 4, // DXT1_SRGB
+ 4, // DXT23_SRGB
+ 4, // DXT45_SRGB
+ 4, // BC7U_SRGB
+ 4, // ASTC_2D_4X4_SRGB
+ 8, // ASTC_2D_8X8_SRGB
+ 5, // ASTC_2D_8X5_SRGB
+ 4, // ASTC_2D_5X4_SRGB
+ 5, // ASTC_2D_5X5
+ 5, // ASTC_2D_5X5_SRGB
+ 8, // ASTC_2D_10X8
+ 8, // ASTC_2D_10X8_SRGB
+ 1, // Z32F
+ 1, // Z16
+ 1, // Z24S8
+ 1, // S8Z24
+ 1, // Z32FS8
+}};
+
static constexpr u32 GetDefaultBlockHeight(PixelFormat format) {
if (format == PixelFormat::Invalid)
return 0;
- constexpr std::array<u32, MaxPixelFormat> block_height_table = {{
- 1, // ABGR8U
- 1, // ABGR8S
- 1, // ABGR8UI
- 1, // B5G6R5U
- 1, // A2B10G10R10U
- 1, // A1B5G5R5U
- 1, // R8U
- 1, // R8UI
- 1, // RGBA16F
- 1, // RGBA16U
- 1, // RGBA16UI
- 1, // R11FG11FB10F
- 1, // RGBA32UI
- 4, // DXT1
- 4, // DXT23
- 4, // DXT45
- 4, // DXN1
- 4, // DXN2UNORM
- 4, // DXN2SNORM
- 4, // BC7U
- 4, // BC6H_UF16
- 4, // BC6H_SF16
- 4, // ASTC_2D_4X4
- 1, // G8R8U
- 1, // G8R8S
- 1, // BGRA8
- 1, // RGBA32F
- 1, // RG32F
- 1, // R32F
- 1, // R16F
- 1, // R16U
- 1, // R16S
- 1, // R16UI
- 1, // R16I
- 1, // RG16
- 1, // RG16F
- 1, // RG16UI
- 1, // RG16I
- 1, // RG16S
- 1, // RGB32F
- 1, // RGBA8_SRGB
- 1, // RG8U
- 1, // RG8S
- 1, // RG32UI
- 1, // R32UI
- 8, // ASTC_2D_8X8
- 5, // ASTC_2D_8X5
- 4, // ASTC_2D_5X4
- 1, // BGRA8_SRGB
- 4, // DXT1_SRGB
- 4, // DXT23_SRGB
- 4, // DXT45_SRGB
- 4, // BC7U_SRGB
- 4, // ASTC_2D_4X4_SRGB
- 8, // ASTC_2D_8X8_SRGB
- 5, // ASTC_2D_8X5_SRGB
- 4, // ASTC_2D_5X4_SRGB
- 5, // ASTC_2D_5X5
- 5, // ASTC_2D_5X5_SRGB
- 8, // ASTC_2D_10X8
- 8, // ASTC_2D_10X8_SRGB
- 1, // Z32F
- 1, // Z16
- 1, // Z24S8
- 1, // S8Z24
- 1, // Z32FS8
- }};
-
ASSERT(static_cast<std::size_t>(format) < block_height_table.size());
return block_height_table[static_cast<std::size_t>(format)];
}
+constexpr std::array<u32, MaxPixelFormat> bpp_table = {{
+ 32, // ABGR8U
+ 32, // ABGR8S
+ 32, // ABGR8UI
+ 16, // B5G6R5U
+ 32, // A2B10G10R10U
+ 16, // A1B5G5R5U
+ 8, // R8U
+ 8, // R8UI
+ 64, // RGBA16F
+ 64, // RGBA16U
+ 64, // RGBA16UI
+ 32, // R11FG11FB10F
+ 128, // RGBA32UI
+ 64, // DXT1
+ 128, // DXT23
+ 128, // DXT45
+ 64, // DXN1
+ 128, // DXN2UNORM
+ 128, // DXN2SNORM
+ 128, // BC7U
+ 128, // BC6H_UF16
+ 128, // BC6H_SF16
+ 128, // ASTC_2D_4X4
+ 16, // G8R8U
+ 16, // G8R8S
+ 32, // BGRA8
+ 128, // RGBA32F
+ 64, // RG32F
+ 32, // R32F
+ 16, // R16F
+ 16, // R16U
+ 16, // R16S
+ 16, // R16UI
+ 16, // R16I
+ 32, // RG16
+ 32, // RG16F
+ 32, // RG16UI
+ 32, // RG16I
+ 32, // RG16S
+ 96, // RGB32F
+ 32, // RGBA8_SRGB
+ 16, // RG8U
+ 16, // RG8S
+ 64, // RG32UI
+ 32, // R32UI
+ 128, // ASTC_2D_8X8
+ 128, // ASTC_2D_8X5
+ 128, // ASTC_2D_5X4
+ 32, // BGRA8_SRGB
+ 64, // DXT1_SRGB
+ 128, // DXT23_SRGB
+ 128, // DXT45_SRGB
+ 128, // BC7U
+ 128, // ASTC_2D_4X4_SRGB
+ 128, // ASTC_2D_8X8_SRGB
+ 128, // ASTC_2D_8X5_SRGB
+ 128, // ASTC_2D_5X4_SRGB
+ 128, // ASTC_2D_5X5
+ 128, // ASTC_2D_5X5_SRGB
+ 128, // ASTC_2D_10X8
+ 128, // ASTC_2D_10X8_SRGB
+ 32, // Z32F
+ 16, // Z16
+ 32, // Z24S8
+ 32, // S8Z24
+ 64, // Z32FS8
+}};
+
static constexpr u32 GetFormatBpp(PixelFormat format) {
if (format == PixelFormat::Invalid)
return 0;
- constexpr std::array<u32, MaxPixelFormat> bpp_table = {{
- 32, // ABGR8U
- 32, // ABGR8S
- 32, // ABGR8UI
- 16, // B5G6R5U
- 32, // A2B10G10R10U
- 16, // A1B5G5R5U
- 8, // R8U
- 8, // R8UI
- 64, // RGBA16F
- 64, // RGBA16U
- 64, // RGBA16UI
- 32, // R11FG11FB10F
- 128, // RGBA32UI
- 64, // DXT1
- 128, // DXT23
- 128, // DXT45
- 64, // DXN1
- 128, // DXN2UNORM
- 128, // DXN2SNORM
- 128, // BC7U
- 128, // BC6H_UF16
- 128, // BC6H_SF16
- 128, // ASTC_2D_4X4
- 16, // G8R8U
- 16, // G8R8S
- 32, // BGRA8
- 128, // RGBA32F
- 64, // RG32F
- 32, // R32F
- 16, // R16F
- 16, // R16U
- 16, // R16S
- 16, // R16UI
- 16, // R16I
- 32, // RG16
- 32, // RG16F
- 32, // RG16UI
- 32, // RG16I
- 32, // RG16S
- 96, // RGB32F
- 32, // RGBA8_SRGB
- 16, // RG8U
- 16, // RG8S
- 64, // RG32UI
- 32, // R32UI
- 128, // ASTC_2D_8X8
- 128, // ASTC_2D_8X5
- 128, // ASTC_2D_5X4
- 32, // BGRA8_SRGB
- 64, // DXT1_SRGB
- 128, // DXT23_SRGB
- 128, // DXT45_SRGB
- 128, // BC7U
- 128, // ASTC_2D_4X4_SRGB
- 128, // ASTC_2D_8X8_SRGB
- 128, // ASTC_2D_8X5_SRGB
- 128, // ASTC_2D_5X4_SRGB
- 128, // ASTC_2D_5X5
- 128, // ASTC_2D_5X5_SRGB
- 128, // ASTC_2D_10X8
- 128, // ASTC_2D_10X8_SRGB
- 32, // Z32F
- 16, // Z16
- 32, // Z24S8
- 32, // S8Z24
- 64, // Z32FS8
- }};
-
ASSERT(static_cast<std::size_t>(format) < bpp_table.size());
return bpp_table[static_cast<std::size_t>(format)];
}
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 {
public:
explicit ConfigureAudio(QWidget* parent = nullptr);
- ~ConfigureAudio();
+ ~ConfigureAudio() override;
void applyConfiguration();
void retranslateUi();
-public slots:
+private:
void updateAudioDevices(int sink_index);
-private:
void setConfiguration();
void setOutputSinkFromSinkID();
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 {
public:
explicit ConfigureDebug(QWidget* parent = nullptr);
- ~ConfigureDebug();
+ ~ConfigureDebug() override;
void applyConfiguration();
private:
void setConfiguration();
-private:
std::unique_ptr<Ui::ConfigureDebug> ui;
};
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 {
public:
explicit ConfigureDialog(QWidget* parent, const HotkeyRegistry& registry);
- ~ConfigureDialog();
+ ~ConfigureDialog() override;
void applyConfiguration();
private:
void setConfiguration();
-private:
std::unique_ptr<Ui::ConfigureDialog> ui;
};
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 {
public:
explicit ConfigureGameList(QWidget* parent = nullptr);
- ~ConfigureGameList();
+ ~ConfigureGameList() override;
void applyConfiguration();
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 {
public:
explicit ConfigureGeneral(QWidget* parent = nullptr);
- ~ConfigureGeneral();
+ ~ConfigureGeneral() override;
void PopulateHotkeyList(const HotkeyRegistry& registry);
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 {
public:
explicit ConfigureGraphics(QWidget* parent = nullptr);
- ~ConfigureGraphics();
+ ~ConfigureGraphics() override;
void applyConfiguration();
private:
void setConfiguration();
-private:
std::unique_ptr<Ui::ConfigureGraphics> ui;
QColor bg_color;
};
diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp
index e25597b7f..830d26115 100644
--- a/src/yuzu/configuration/configure_input.cpp
+++ b/src/yuzu/configuration/configure_input.cpp
@@ -88,8 +88,10 @@ ConfigureInput::ConfigureInput(QWidget* parent)
[this] { CallConfigureDialog<ConfigureTouchscreenAdvanced>(*this); });
}
+ConfigureInput::~ConfigureInput() = default;
+
void ConfigureInput::OnDockedModeChanged(bool last_state, bool new_state) {
- if (ui->use_docked_mode->isChecked() && ui->handheld_connected->isChecked()){
+ if (ui->use_docked_mode->isChecked() && ui->handheld_connected->isChecked()) {
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 {
public:
explicit ConfigureInput(QWidget* parent = nullptr);
+ ~ConfigureInput() override;
/// Save all button configurations to settings file
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 {
public:
explicit ConfigureWeb(QWidget* parent = nullptr);
- ~ConfigureWeb();
+ ~ConfigureWeb() override;
void applyConfiguration();
void retranslateUi();
-public slots:
+private:
void RefreshTelemetryID();
void OnLoginChanged();
void VerifyLogin();
void OnLoginVerified();
-private:
void setConfiguration();
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 @@
#include "common/assert.h"
#include "core/core.h"
-#include "core/hle/kernel/event.h"
#include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/mutex.h"
#include "core/hle/kernel/process.h"
+#include "core/hle/kernel/readable_event.h"
#include "core/hle/kernel/scheduler.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/kernel/timer.h"
@@ -153,8 +153,8 @@ QString WaitTreeWaitObject::GetText() const {
std::unique_ptr<WaitTreeWaitObject> WaitTreeWaitObject::make(const Kernel::WaitObject& object) {
switch (object.GetHandleType()) {
- case Kernel::HandleType::Event:
- return std::make_unique<WaitTreeEvent>(static_cast<const Kernel::Event&>(object));
+ case Kernel::HandleType::ReadableEvent:
+ return std::make_unique<WaitTreeEvent>(static_cast<const Kernel::ReadableEvent&>(object));
case Kernel::HandleType::Timer:
return std::make_unique<WaitTreeTimer>(static_cast<const Kernel::Timer&>(object));
case Kernel::HandleType::Thread:
@@ -332,7 +332,7 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const {
return list;
}
-WaitTreeEvent::WaitTreeEvent(const Kernel::Event& object) : WaitTreeWaitObject(object) {}
+WaitTreeEvent::WaitTreeEvent(const Kernel::ReadableEvent& object) : WaitTreeWaitObject(object) {}
WaitTreeEvent::~WaitTreeEvent() = default;
std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeEvent::GetChildren() const {
@@ -340,7 +340,8 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeEvent::GetChildren() const {
list.push_back(std::make_unique<WaitTreeText>(
tr("reset type = %1")
- .arg(GetResetTypeQString(static_cast<const Kernel::Event&>(object).GetResetType()))));
+ .arg(GetResetTypeQString(
+ static_cast<const Kernel::ReadableEvent&>(object).GetResetType()))));
return list;
}
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 @@
class EmuThread;
namespace Kernel {
+class ReadableEvent;
class WaitObject;
-class Event;
class Thread;
class Timer;
} // namespace Kernel
@@ -144,7 +144,7 @@ public:
class WaitTreeEvent : public WaitTreeWaitObject {
Q_OBJECT
public:
- explicit WaitTreeEvent(const Kernel::Event& object);
+ explicit WaitTreeEvent(const Kernel::ReadableEvent& object);
~WaitTreeEvent() override;
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)
tree_view->setEditTriggers(QHeaderView::NoEditTriggers);
tree_view->setUniformRowHeights(true);
tree_view->setContextMenuPolicy(Qt::CustomContextMenu);
+ tree_view->setStyleSheet("QTreeView{ border: none; }");
item_model->insertColumns(0, UISettings::values.show_add_ons ? COLUMN_COUNT : COLUMN_COUNT - 1);
item_model->setHeaderData(COLUMN_NAME, Qt::Horizontal, tr("Name"));
diff --git a/src/yuzu/game_list_worker.cpp b/src/yuzu/game_list_worker.cpp
index 362902e46..9fd074223 100644
--- a/src/yuzu/game_list_worker.cpp
+++ b/src/yuzu/game_list_worker.cpp
@@ -86,6 +86,35 @@ QString FormatPatchNameVersions(const FileSys::PatchManager& patch_manager,
out.chop(1);
return out;
}
+
+QList<QStandardItem*> MakeGameListEntry(const std::string& path, const std::string& name,
+ const std::vector<u8>& icon, Loader::AppLoader& loader,
+ u64 program_id, const CompatibilityList& compatibility_list,
+ const FileSys::PatchManager& patch) {
+ const auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id);
+
+ // The game list uses this as compatibility number for untested games
+ QString compatibility{"99"};
+ if (it != compatibility_list.end()) {
+ compatibility = it->second.first;
+ }
+
+ QList<QStandardItem*> list{
+ new GameListItemPath(
+ FormatGameName(path), icon, QString::fromStdString(name),
+ QString::fromStdString(Loader::GetFileTypeString(loader.GetFileType())), program_id),
+ new GameListItemCompat(compatibility),
+ new GameListItem(QString::fromStdString(Loader::GetFileTypeString(loader.GetFileType()))),
+ new GameListItemSize(FileUtil::GetSize(path)),
+ };
+
+ if (UISettings::values.show_add_ons) {
+ list.insert(
+ 2, new GameListItem(FormatPatchNameVersions(patch, loader, loader.IsRomFSUpdatable())));
+ }
+
+ return list;
+}
} // Anonymous namespace
GameListWorker::GameListWorker(FileSys::VirtualFilesystem vfs, QString dir_path, bool deep_scan,
@@ -97,11 +126,11 @@ GameListWorker::~GameListWorker() = default;
void GameListWorker::AddInstalledTitlesToGameList() {
const auto cache = Service::FileSystem::GetUnionContents();
- const auto installed_games = cache->ListEntriesFilter(FileSys::TitleType::Application,
- FileSys::ContentRecordType::Program);
+ const auto installed_games = cache.ListEntriesFilter(FileSys::TitleType::Application,
+ FileSys::ContentRecordType::Program);
for (const auto& game : installed_games) {
- const auto file = cache->GetEntryUnparsed(game);
+ const auto file = cache.GetEntryUnparsed(game);
std::unique_ptr<Loader::AppLoader> loader = Loader::GetLoader(file);
if (!loader)
continue;
@@ -112,40 +141,19 @@ void GameListWorker::AddInstalledTitlesToGameList() {
loader->ReadProgramId(program_id);
const FileSys::PatchManager patch{program_id};
- const auto control = cache->GetEntry(game.title_id, FileSys::ContentRecordType::Control);
+ const auto control = cache.GetEntry(game.title_id, FileSys::ContentRecordType::Control);
if (control != nullptr)
GetMetadataFromControlNCA(patch, *control, icon, name);
- auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id);
-
- // The game list uses this as compatibility number for untested games
- QString compatibility("99");
- if (it != compatibility_list.end())
- compatibility = it->second.first;
-
- QList<QStandardItem*> list{
- new GameListItemPath(
- FormatGameName(file->GetFullPath()), icon, QString::fromStdString(name),
- QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType())),
- program_id),
- new GameListItemCompat(compatibility),
- new GameListItem(
- QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType()))),
- new GameListItemSize(file->GetSize()),
- };
-
- if (UISettings::values.show_add_ons) {
- list.insert(2, new GameListItem(FormatPatchNameVersions(patch, *loader)));
- }
-
- emit EntryReady(list);
+ emit EntryReady(MakeGameListEntry(file->GetFullPath(), name, icon, *loader, program_id,
+ compatibility_list, patch));
}
- const auto control_data = cache->ListEntriesFilter(FileSys::TitleType::Application,
- FileSys::ContentRecordType::Control);
+ const auto control_data = cache.ListEntriesFilter(FileSys::TitleType::Application,
+ FileSys::ContentRecordType::Control);
for (const auto& entry : control_data) {
- auto nca = cache->GetEntry(entry);
+ auto nca = cache.GetEntry(entry);
if (nca != nullptr) {
nca_control_map.insert_or_assign(entry.title_id, std::move(nca));
}
@@ -155,14 +163,14 @@ void GameListWorker::AddInstalledTitlesToGameList() {
void GameListWorker::FillControlMap(const std::string& dir_path) {
const auto nca_control_callback = [this](u64* num_entries_out, const std::string& directory,
const std::string& virtual_name) -> bool {
- std::string physical_name = directory + DIR_SEP + virtual_name;
-
- if (stop_processing)
- return false; // Breaks the callback loop.
+ if (stop_processing) {
+ // Breaks the callback loop
+ return false;
+ }
- bool is_dir = FileUtil::IsDirectory(physical_name);
- QFileInfo file_info(physical_name.c_str());
- if (!is_dir && file_info.suffix().toStdString() == "nca") {
+ const std::string physical_name = directory + DIR_SEP + virtual_name;
+ const QFileInfo file_info(QString::fromStdString(physical_name));
+ if (!file_info.isDir() && file_info.suffix() == QStringLiteral("nca")) {
auto nca =
std::make_unique<FileSys::NCA>(vfs->OpenFile(physical_name, FileSys::Mode::Read));
if (nca->GetType() == FileSys::NCAContentType::Control) {
@@ -179,12 +187,13 @@ void GameListWorker::FillControlMap(const std::string& dir_path) {
void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsigned int recursion) {
const auto callback = [this, recursion](u64* num_entries_out, const std::string& directory,
const std::string& virtual_name) -> bool {
- std::string physical_name = directory + DIR_SEP + virtual_name;
-
- if (stop_processing)
- return false; // Breaks the callback loop.
+ if (stop_processing) {
+ // Breaks the callback loop.
+ return false;
+ }
- bool is_dir = FileUtil::IsDirectory(physical_name);
+ const std::string physical_name = directory + DIR_SEP + virtual_name;
+ const bool is_dir = FileUtil::IsDirectory(physical_name);
if (!is_dir &&
(HasSupportedFileExtension(physical_name) || IsExtractedNCAMain(physical_name))) {
std::unique_ptr<Loader::AppLoader> loader =
@@ -214,30 +223,8 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign
}
}
- auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id);
-
- // The game list uses this as compatibility number for untested games
- QString compatibility("99");
- if (it != compatibility_list.end())
- compatibility = it->second.first;
-
- QList<QStandardItem*> list{
- new GameListItemPath(
- FormatGameName(physical_name), icon, QString::fromStdString(name),
- QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType())),
- program_id),
- new GameListItemCompat(compatibility),
- new GameListItem(
- QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType()))),
- new GameListItemSize(FileUtil::GetSize(physical_name)),
- };
-
- if (UISettings::values.show_add_ons) {
- list.insert(2, new GameListItem(FormatPatchNameVersions(
- patch, *loader, loader->IsRomFSUpdatable())));
- }
-
- emit EntryReady(std::move(list));
+ emit EntryReady(MakeGameListEntry(physical_name, name, icon, *loader, program_id,
+ compatibility_list, patch));
} else if (is_dir && recursion > 0) {
watch_list.append(QString::fromStdString(physical_name));
AddFstEntriesToGameList(physical_name, recursion - 1);
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 93bf117c8..22c207a3a 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -518,6 +518,8 @@ void GMainWindow::OnDisplayTitleBars(bool show) {
QStringList GMainWindow::GetUnsupportedGLExtensions() {
QStringList unsupported_ext;
+ if (!GLAD_GL_ARB_direct_state_access)
+ unsupported_ext.append("ARB_direct_state_access");
if (!GLAD_GL_ARB_vertex_type_10f_11f_11f_rev)
unsupported_ext.append("ARB_vertex_type_10f_11f_11f_rev");
if (!GLAD_GL_ARB_texture_mirror_clamp_to_edge)
@@ -905,7 +907,7 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa
}
const auto installed = Service::FileSystem::GetUnionContents();
- auto romfs_title_id = SelectRomFSDumpTarget(*installed, program_id);
+ const auto romfs_title_id = SelectRomFSDumpTarget(installed, program_id);
if (!romfs_title_id) {
failed();
@@ -920,7 +922,7 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa
if (*romfs_title_id == program_id) {
romfs = file;
} else {
- romfs = installed->GetEntry(*romfs_title_id, FileSys::ContentRecordType::Data)->GetRomFS();
+ romfs = installed.GetEntry(*romfs_title_id, FileSys::ContentRecordType::Data)->GetRomFS();
}
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() {
bool EmuWindow_SDL2::SupportsRequiredGLExtensions() {
std::vector<std::string> unsupported_ext;
+ if (!GLAD_GL_ARB_direct_state_access)
+ unsupported_ext.push_back("ARB_direct_state_access");
if (!GLAD_GL_ARB_vertex_type_10f_11f_11f_rev)
unsupported_ext.push_back("ARB_vertex_type_10f_11f_11f_rev");
if (!GLAD_GL_ARB_texture_mirror_clamp_to_edge)