From fd09be5496b742b61c0ee1babf0012d2dafa196d Mon Sep 17 00:00:00 2001
From: Fernando Sahmkow
Date: Thu, 8 Jul 2021 23:21:08 +0200
Subject: Settings: Eliminate ASYNC & MULTICORE Toggles and add GPU Accuracy
Toggle.
---
src/yuzu/main.cpp | 80 ++++++++++++++++++++++++++++++-------------------------
src/yuzu/main.h | 4 +--
2 files changed, 45 insertions(+), 39 deletions(-)
(limited to 'src')
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 5ed3b90b8..1e6f0e4a7 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -789,41 +789,28 @@ void GMainWindow::InitializeWidgets() {
dock_status_button->setChecked(Settings::values.use_docked_mode.GetValue());
statusBar()->insertPermanentWidget(0, dock_status_button);
- // Setup ASync button
- async_status_button = new QPushButton();
- async_status_button->setObjectName(QStringLiteral("TogglableStatusBarButton"));
- async_status_button->setFocusPolicy(Qt::NoFocus);
- connect(async_status_button, &QPushButton::clicked, [&] {
- if (emulation_running) {
- return;
+ gpu_accuracy_button = new QPushButton();
+ gpu_accuracy_button->setObjectName(QStringLiteral("GPUStatusBarButton"));
+ gpu_accuracy_button->setCheckable(true);
+ gpu_accuracy_button->setFocusPolicy(Qt::NoFocus);
+ connect(gpu_accuracy_button, &QPushButton::clicked, [this] {
+ switch (Settings::values.gpu_accuracy.GetValue()) {
+ case Settings::GPUAccuracy::High: {
+ Settings::values.gpu_accuracy.SetValue(Settings::GPUAccuracy::Normal);
+ break;
+ }
+ case Settings::GPUAccuracy::Normal:
+ case Settings::GPUAccuracy::Extreme:
+ default: {
+ Settings::values.gpu_accuracy.SetValue(Settings::GPUAccuracy::High);
}
- Settings::values.use_asynchronous_gpu_emulation.SetValue(
- !Settings::values.use_asynchronous_gpu_emulation.GetValue());
- async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation.GetValue());
- Core::System::GetInstance().ApplySettings();
- });
- async_status_button->setText(tr("ASYNC"));
- async_status_button->setCheckable(true);
- async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation.GetValue());
-
- // Setup Multicore button
- multicore_status_button = new QPushButton();
- multicore_status_button->setObjectName(QStringLiteral("TogglableStatusBarButton"));
- multicore_status_button->setFocusPolicy(Qt::NoFocus);
- connect(multicore_status_button, &QPushButton::clicked, [&] {
- if (emulation_running) {
- return;
}
- Settings::values.use_multi_core.SetValue(!Settings::values.use_multi_core.GetValue());
- multicore_status_button->setChecked(Settings::values.use_multi_core.GetValue());
+
Core::System::GetInstance().ApplySettings();
+ UpdateGPUAccuracyButton();
});
- multicore_status_button->setText(tr("MULTICORE"));
- multicore_status_button->setCheckable(true);
- multicore_status_button->setChecked(Settings::values.use_multi_core.GetValue());
-
- statusBar()->insertPermanentWidget(0, multicore_status_button);
- statusBar()->insertPermanentWidget(0, async_status_button);
+ UpdateGPUAccuracyButton();
+ statusBar()->insertPermanentWidget(0, gpu_accuracy_button);
// Setup Renderer API button
renderer_status_button = new QPushButton();
@@ -1397,8 +1384,6 @@ void GMainWindow::BootGame(const QString& filename, std::size_t program_index, S
game_list_placeholder->hide();
}
status_bar_update_timer.start(500);
- async_status_button->setDisabled(true);
- multicore_status_button->setDisabled(true);
renderer_status_button->setDisabled(true);
if (UISettings::values.hide_mouse || Settings::values.mouse_panning) {
@@ -1500,8 +1485,6 @@ void GMainWindow::ShutdownGame() {
emu_speed_label->setVisible(false);
game_fps_label->setVisible(false);
emu_frametime_label->setVisible(false);
- async_status_button->setEnabled(true);
- multicore_status_button->setEnabled(true);
renderer_status_button->setEnabled(true);
emulation_running = false;
@@ -2921,12 +2904,35 @@ void GMainWindow::UpdateStatusBar() {
emu_frametime_label->setVisible(true);
}
+void GMainWindow::UpdateGPUAccuracyButton() {
+ switch (Settings::values.gpu_accuracy.GetValue()) {
+ case Settings::GPUAccuracy::Normal: {
+ gpu_accuracy_button->setText(tr("GPU NORMAL "));
+ gpu_accuracy_button->setChecked(false);
+ break;
+ }
+ case Settings::GPUAccuracy::High: {
+ gpu_accuracy_button->setText(tr("GPU HIGH "));
+ gpu_accuracy_button->setChecked(true);
+ break;
+ }
+ case Settings::GPUAccuracy::Extreme: {
+ gpu_accuracy_button->setText(tr("GPU EXTREME"));
+ gpu_accuracy_button->setChecked(true);
+ break;
+ }
+ default: {
+ gpu_accuracy_button->setText(tr("GPU ERROR"));
+ gpu_accuracy_button->setChecked(true);
+ }
+ }
+}
+
void GMainWindow::UpdateStatusButtons() {
dock_status_button->setChecked(Settings::values.use_docked_mode.GetValue());
- multicore_status_button->setChecked(Settings::values.use_multi_core.GetValue());
- async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation.GetValue());
renderer_status_button->setChecked(Settings::values.renderer_backend.GetValue() ==
Settings::RendererBackend::Vulkan);
+ UpdateGPUAccuracyButton();
}
void GMainWindow::UpdateUISettings() {
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 45c8310e1..15e4deab9 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -291,6 +291,7 @@ private:
void UpdateWindowTitle(std::string_view title_name = {}, std::string_view title_version = {},
std::string_view gpu_vendor = {});
void UpdateStatusBar();
+ void UpdateGPUAccuracyButton();
void UpdateStatusButtons();
void UpdateUISettings();
void HideMouseCursor();
@@ -316,8 +317,7 @@ private:
QLabel* emu_speed_label = nullptr;
QLabel* game_fps_label = nullptr;
QLabel* emu_frametime_label = nullptr;
- QPushButton* async_status_button = nullptr;
- QPushButton* multicore_status_button = nullptr;
+ QPushButton* gpu_accuracy_button = nullptr;
QPushButton* renderer_status_button = nullptr;
QPushButton* dock_status_button = nullptr;
QTimer status_bar_update_timer;
--
cgit v1.2.3
From 598d154f69b746796f1f6f11c2836a0ca2b5ea75 Mon Sep 17 00:00:00 2001
From: Fernando S
Date: Fri, 9 Jul 2021 12:28:51 +0200
Subject: Update src/yuzu/main.cpp
Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com>---
src/yuzu/main.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
(limited to 'src')
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 1e6f0e4a7..d94c660b3 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -2907,12 +2907,12 @@ void GMainWindow::UpdateStatusBar() {
void GMainWindow::UpdateGPUAccuracyButton() {
switch (Settings::values.gpu_accuracy.GetValue()) {
case Settings::GPUAccuracy::Normal: {
- gpu_accuracy_button->setText(tr("GPU NORMAL "));
+ gpu_accuracy_button->setText(tr("GPU NORMAL"));
gpu_accuracy_button->setChecked(false);
break;
}
case Settings::GPUAccuracy::High: {
- gpu_accuracy_button->setText(tr("GPU HIGH "));
+ gpu_accuracy_button->setText(tr("GPU HIGH"));
gpu_accuracy_button->setChecked(true);
break;
}
--
cgit v1.2.3
From 6e2ca7fbee8b7de964926da392ab0550b2a76475 Mon Sep 17 00:00:00 2001
From: ReinUsesLisp
Date: Tue, 20 Jul 2021 18:50:48 -0300
Subject: buffer_cache: Simplify clear logic
Use existing helper functions and avoid looping when
only one buffer has to be active.
---
src/video_core/buffer_cache/buffer_cache.h | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
(limited to 'src')
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h
index 7373cb62d..5a0b6f0c0 100644
--- a/src/video_core/buffer_cache/buffer_cache.h
+++ b/src/video_core/buffer_cache/buffer_cache.h
@@ -553,13 +553,9 @@ bool BufferCache
::DMAClear(GPUVAddr dst_address, u64 amount, u32 value) {
ClearDownload(subtract_interval);
common_ranges.subtract(subtract_interval);
- BufferId buffer;
- do {
- has_deleted_buffers = false;
- buffer = FindBuffer(*cpu_dst_address, static_cast(size));
- } while (has_deleted_buffers);
+ const BufferId buffer = FindBuffer(*cpu_dst_address, static_cast(size));
auto& dest_buffer = slot_buffers[buffer];
- const u32 offset = static_cast(*cpu_dst_address - dest_buffer.CpuAddr());
+ const u32 offset = dest_buffer.Offset(*cpu_dst_address);
runtime.ClearBuffer(dest_buffer, offset, size, value);
return true;
}
--
cgit v1.2.3
From a0c4557557172b3139e3b53a42e31338900037c6 Mon Sep 17 00:00:00 2001
From: ReinUsesLisp
Date: Tue, 20 Jul 2021 18:51:42 -0300
Subject: gl_buffer_cache: Use glClearNamedBufferSubData:GL_RED instead of
GL_RGBA
Avoids reading out of bounds from the stack.
---
src/video_core/renderer_opengl/gl_buffer_cache.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'src')
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.cpp b/src/video_core/renderer_opengl/gl_buffer_cache.cpp
index c4189fb60..a02a45e04 100644
--- a/src/video_core/renderer_opengl/gl_buffer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_buffer_cache.cpp
@@ -100,7 +100,7 @@ void BufferCacheRuntime::CopyBuffer(Buffer& dst_buffer, Buffer& src_buffer,
void BufferCacheRuntime::ClearBuffer(Buffer& dest_buffer, u32 offset, size_t size, u32 value) {
glClearNamedBufferSubData(dest_buffer.Handle(), GL_R32UI, static_cast(offset),
- static_cast(size / sizeof(u32)), GL_RGBA, GL_UNSIGNED_INT,
+ static_cast(size / sizeof(u32)), GL_RED, GL_UNSIGNED_INT,
&value);
}
--
cgit v1.2.3
From 929994132a4f39ca4ab2975caf47a2a99a19b518 Mon Sep 17 00:00:00 2001
From: bunnei
Date: Mon, 28 Jun 2021 14:38:14 -0700
Subject: hle: kernel: Provide methods for tracking dangling kernel objects.
---
src/core/hle/kernel/k_auto_object.cpp | 9 +++++++++
src/core/hle/kernel/k_auto_object.h | 12 ++++++++++--
src/core/hle/kernel/kernel.cpp | 16 ++++++++++++++++
src/core/hle/kernel/kernel.h | 8 ++++++++
4 files changed, 43 insertions(+), 2 deletions(-)
(limited to 'src')
diff --git a/src/core/hle/kernel/k_auto_object.cpp b/src/core/hle/kernel/k_auto_object.cpp
index dbe237f09..c99a9ebb7 100644
--- a/src/core/hle/kernel/k_auto_object.cpp
+++ b/src/core/hle/kernel/k_auto_object.cpp
@@ -3,6 +3,7 @@
// Refer to the license.txt file included.
#include "core/hle/kernel/k_auto_object.h"
+#include "core/hle/kernel/kernel.h"
namespace Kernel {
@@ -11,4 +12,12 @@ KAutoObject* KAutoObject::Create(KAutoObject* obj) {
return obj;
}
+void KAutoObject::RegisterWithKernel() {
+ kernel.RegisterKernelObject(this);
+}
+
+void KAutoObject::UnregisterWithKernel() {
+ kernel.UnregisterKernelObject(this);
+}
+
} // namespace Kernel
diff --git a/src/core/hle/kernel/k_auto_object.h b/src/core/hle/kernel/k_auto_object.h
index 88a052f65..e4fcdbc67 100644
--- a/src/core/hle/kernel/k_auto_object.h
+++ b/src/core/hle/kernel/k_auto_object.h
@@ -85,8 +85,12 @@ private:
KERNEL_AUTOOBJECT_TRAITS(KAutoObject, KAutoObject);
public:
- explicit KAutoObject(KernelCore& kernel_) : kernel(kernel_) {}
- virtual ~KAutoObject() = default;
+ explicit KAutoObject(KernelCore& kernel_) : kernel(kernel_) {
+ RegisterWithKernel();
+ }
+ virtual ~KAutoObject() {
+ UnregisterWithKernel();
+ }
static KAutoObject* Create(KAutoObject* ptr);
@@ -166,6 +170,10 @@ public:
}
}
+private:
+ void RegisterWithKernel();
+ void UnregisterWithKernel();
+
protected:
KernelCore& kernel;
std::string name;
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 64bd0c494..ee60072c2 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -142,6 +142,13 @@ struct KernelCore::Impl {
// Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others
next_host_thread_id = Core::Hardware::NUM_CPU_CORES;
+
+ // Track kernel objects that were not freed on shutdown
+ if (registered_objects.size()) {
+ LOG_WARNING(Kernel, "{} kernel objects were dangling on shutdown!",
+ registered_objects.size());
+ registered_objects.clear();
+ }
}
void InitializePhysicalCores() {
@@ -656,6 +663,7 @@ struct KernelCore::Impl {
/// the ConnectToPort SVC.
std::unordered_map service_interface_factory;
NamedPortTable named_ports;
+ std::unordered_set registered_objects;
std::unique_ptr exclusive_monitor;
std::vector cores;
@@ -852,6 +860,14 @@ KClientPort* KernelCore::CreateNamedServicePort(std::string name) {
return &search->second(impl->system.ServiceManager(), impl->system);
}
+void KernelCore::RegisterKernelObject(KAutoObject* object) {
+ impl->registered_objects.insert(object);
+}
+
+void KernelCore::UnregisterKernelObject(KAutoObject* object) {
+ impl->registered_objects.erase(object);
+}
+
bool KernelCore::IsValidNamedPort(NamedPortTable::const_iterator port) const {
return port != impl->named_ports.cend();
}
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 2d01e1ae0..b669ca74e 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -185,6 +185,14 @@ public:
/// Opens a port to a service previously registered with RegisterNamedService.
KClientPort* CreateNamedServicePort(std::string name);
+ /// Registers all kernel objects with the global emulation state, this is purely for tracking
+ /// leaks after emulation has been shutdown.
+ void RegisterKernelObject(KAutoObject* object);
+
+ /// Unregisters a kernel object previously registered with RegisterKernelObject when it was
+ /// destroyed during the current emulation session.
+ void UnregisterKernelObject(KAutoObject* object);
+
/// Determines whether or not the given port is a valid named port.
bool IsValidNamedPort(NamedPortTable::const_iterator port) const;
--
cgit v1.2.3
From 015058fadf8dbc72c186e833512e7189c625474b Mon Sep 17 00:00:00 2001
From: bunnei
Date: Mon, 28 Jun 2021 14:41:24 -0700
Subject: hle: service: Add a helper module for managing kernel objects.
---
src/core/CMakeLists.txt | 2 +
src/core/hle/service/hid/controllers/npad.cpp | 12 ++---
src/core/hle/service/hid/controllers/npad.h | 8 +++-
src/core/hle/service/hid/hid.cpp | 14 +++---
src/core/hle/service/hid/hid.h | 13 +++++-
src/core/hle/service/kernel_helpers.cpp | 64 +++++++++++++++++++++++++++
src/core/hle/service/kernel_helpers.h | 35 +++++++++++++++
src/core/hle/service/nvdrv/nvdrv.cpp | 10 ++---
src/core/hle/service/nvdrv/nvdrv.h | 3 ++
src/core/hle/service/service.h | 5 ++-
10 files changed, 146 insertions(+), 20 deletions(-)
create mode 100644 src/core/hle/service/kernel_helpers.cpp
create mode 100644 src/core/hle/service/kernel_helpers.h
(limited to 'src')
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index c7b899131..5c99c00f5 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -517,6 +517,8 @@ add_library(core STATIC
hle/service/psc/psc.h
hle/service/ptm/psm.cpp
hle/service/ptm/psm.h
+ hle/service/kernel_helpers.cpp
+ hle/service/kernel_helpers.h
hle/service/service.cpp
hle/service/service.h
hle/service/set/set.cpp
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 6ce1360e3..95d4f9588 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -18,6 +18,7 @@
#include "core/hle/kernel/k_writable_event.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/service/hid/controllers/npad.h"
+#include "core/hle/service/kernel_helpers.h"
namespace Service::HID {
constexpr s32 HID_JOYSTICK_MAX = 0x7fff;
@@ -147,7 +148,9 @@ bool Controller_NPad::IsDeviceHandleValid(const DeviceHandle& device_handle) {
device_handle.device_index < DeviceIndex::MaxDeviceIndex;
}
-Controller_NPad::Controller_NPad(Core::System& system_) : ControllerBase{system_} {
+Controller_NPad::Controller_NPad(Core::System& system_,
+ KernelHelpers::ServiceContext& service_context_)
+ : ControllerBase{system_}, service_context{service_context_} {
latest_vibration_values.fill({DEFAULT_VIBRATION_VALUE, DEFAULT_VIBRATION_VALUE});
}
@@ -253,8 +256,8 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) {
void Controller_NPad::OnInit() {
auto& kernel = system.Kernel();
for (std::size_t i = 0; i < styleset_changed_events.size(); ++i) {
- styleset_changed_events[i] = Kernel::KEvent::Create(kernel);
- styleset_changed_events[i]->Initialize(fmt::format("npad:NpadStyleSetChanged_{}", i));
+ styleset_changed_events[i] =
+ service_context.CreateEvent(fmt::format("npad:NpadStyleSetChanged_{}", i));
}
if (!IsControllerActivated()) {
@@ -344,8 +347,7 @@ void Controller_NPad::OnRelease() {
}
for (std::size_t i = 0; i < styleset_changed_events.size(); ++i) {
- styleset_changed_events[i]->Close();
- styleset_changed_events[i] = nullptr;
+ service_context.CloseEvent(styleset_changed_events[i]);
}
}
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 1409d82a2..4fcc6f93a 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -20,6 +20,10 @@ class KEvent;
class KReadableEvent;
} // namespace Kernel
+namespace Service::KernelHelpers {
+class ServiceContext;
+}
+
namespace Service::HID {
constexpr u32 NPAD_HANDHELD = 32;
@@ -27,7 +31,8 @@ constexpr u32 NPAD_UNKNOWN = 16; // TODO(ogniK): What is this?
class Controller_NPad final : public ControllerBase {
public:
- explicit Controller_NPad(Core::System& system_);
+ explicit Controller_NPad(Core::System& system_,
+ KernelHelpers::ServiceContext& service_context_);
~Controller_NPad() override;
// Called when the controller is initialized
@@ -566,6 +571,7 @@ private:
std::array, Settings::NativeMotion::NUM_MOTIONS_HID>,
10>;
+ KernelHelpers::ServiceContext& service_context;
std::mutex mutex;
ButtonArray buttons;
StickArray sticks;
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index d68b023d0..b8b80570d 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -46,8 +46,9 @@ constexpr auto pad_update_ns = std::chrono::nanoseconds{1000 * 1000}; //
constexpr auto motion_update_ns = std::chrono::nanoseconds{15 * 1000 * 1000}; // (15ms, 66.666Hz)
constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000;
-IAppletResource::IAppletResource(Core::System& system_)
- : ServiceFramework{system_, "IAppletResource"} {
+IAppletResource::IAppletResource(Core::System& system_,
+ KernelHelpers::ServiceContext& service_context_)
+ : ServiceFramework{system_, "IAppletResource"}, service_context{service_context_} {
static const FunctionInfo functions[] = {
{0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"},
};
@@ -63,7 +64,7 @@ IAppletResource::IAppletResource(Core::System& system_)
MakeController(HidController::CaptureButton);
MakeController(HidController::InputDetector);
MakeController(HidController::UniquePad);
- MakeController(HidController::NPad);
+ MakeControllerWithServiceContext(HidController::NPad);
MakeController(HidController::Gesture);
MakeController(HidController::ConsoleSixAxisSensor);
@@ -191,13 +192,14 @@ private:
std::shared_ptr Hid::GetAppletResource() {
if (applet_resource == nullptr) {
- applet_resource = std::make_shared(system);
+ applet_resource = std::make_shared(system, service_context);
}
return applet_resource;
}
-Hid::Hid(Core::System& system_) : ServiceFramework{system_, "hid"} {
+Hid::Hid(Core::System& system_)
+ : ServiceFramework{system_, "hid"}, service_context{system_, service_name} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &Hid::CreateAppletResource, "CreateAppletResource"},
@@ -347,7 +349,7 @@ void Hid::CreateAppletResource(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
if (applet_resource == nullptr) {
- applet_resource = std::make_shared(system);
+ applet_resource = std::make_shared(system, service_context);
}
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index 83fc2ea1d..9c5c7f252 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -7,6 +7,7 @@
#include
#include "core/hle/service/hid/controllers/controller_base.h"
+#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/service.h"
namespace Core::Timing {
@@ -39,7 +40,8 @@ enum class HidController : std::size_t {
class IAppletResource final : public ServiceFramework {
public:
- explicit IAppletResource(Core::System& system_);
+ explicit IAppletResource(Core::System& system_,
+ KernelHelpers::ServiceContext& service_context_);
~IAppletResource() override;
void ActivateController(HidController controller);
@@ -60,11 +62,18 @@ private:
void MakeController(HidController controller) {
controllers[static_cast(controller)] = std::make_unique(system);
}
+ template
+ void MakeControllerWithServiceContext(HidController controller) {
+ controllers[static_cast(controller)] =
+ std::make_unique(system, service_context);
+ }
void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx);
void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
+ KernelHelpers::ServiceContext& service_context;
+
std::shared_ptr pad_update_event;
std::shared_ptr motion_update_event;
@@ -176,6 +185,8 @@ private:
static_assert(sizeof(VibrationDeviceInfo) == 0x8, "VibrationDeviceInfo has incorrect size.");
std::shared_ptr applet_resource;
+
+ KernelHelpers::ServiceContext service_context;
};
/// Reload input devices. Used when input configuration changed
diff --git a/src/core/hle/service/kernel_helpers.cpp b/src/core/hle/service/kernel_helpers.cpp
new file mode 100644
index 000000000..895294c9f
--- /dev/null
+++ b/src/core/hle/service/kernel_helpers.cpp
@@ -0,0 +1,64 @@
+// Copyright 2021 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/core.h"
+#include "core/hle/kernel/k_event.h"
+#include "core/hle/kernel/k_process.h"
+#include "core/hle/kernel/k_readable_event.h"
+#include "core/hle/kernel/k_resource_limit.h"
+#include "core/hle/kernel/k_scoped_resource_reservation.h"
+#include "core/hle/kernel/k_writable_event.h"
+#include "core/hle/service/kernel_helpers.h"
+
+namespace Service::KernelHelpers {
+
+ServiceContext::ServiceContext(Core::System& system_, std::string name_)
+ : kernel(system_.Kernel()) {
+ process = Kernel::KProcess::Create(kernel);
+ ASSERT(Kernel::KProcess::Initialize(process, system_, std::move(name_),
+ Kernel::KProcess::ProcessType::Userland)
+ .IsSuccess());
+}
+
+ServiceContext::~ServiceContext() {
+ process->Close();
+ process = nullptr;
+}
+
+Kernel::KEvent* ServiceContext::CreateEvent(std::string&& name) {
+ // Reserve a new event from the process resource limit
+ Kernel::KScopedResourceReservation event_reservation(process,
+ Kernel::LimitableResource::Events);
+ if (!event_reservation.Succeeded()) {
+ LOG_CRITICAL(Service, "Resource limit reached!");
+ return {};
+ }
+
+ // Create a new event.
+ auto* event = Kernel::KEvent::Create(kernel);
+ if (!event) {
+ LOG_CRITICAL(Service, "Unable to create event!");
+ return {};
+ }
+
+ // Initialize the event.
+ event->Initialize(std::move(name));
+
+ // Commit the thread reservation.
+ event_reservation.Commit();
+
+ // Register the event.
+ Kernel::KEvent::Register(kernel, event);
+
+ return event;
+}
+
+void ServiceContext::CloseEvent(Kernel::KEvent* event) {
+ event->GetReadableEvent().Close();
+ event->GetWritableEvent().Close();
+}
+
+} // namespace Service::KernelHelpers
diff --git a/src/core/hle/service/kernel_helpers.h b/src/core/hle/service/kernel_helpers.h
new file mode 100644
index 000000000..4f3e95f67
--- /dev/null
+++ b/src/core/hle/service/kernel_helpers.h
@@ -0,0 +1,35 @@
+// Copyright 2021 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include
+
+namespace Core {
+class System;
+}
+
+namespace Kernel {
+class KernelCore;
+class KEvent;
+class KProcess;
+} // namespace Kernel
+
+namespace Service::KernelHelpers {
+
+class ServiceContext {
+public:
+ ServiceContext(Core::System& system_, std::string name_);
+ ~ServiceContext();
+
+ Kernel::KEvent* CreateEvent(std::string&& name);
+
+ void CloseEvent(Kernel::KEvent* event);
+
+private:
+ Kernel::KernelCore& kernel;
+ Kernel::KProcess* process{};
+};
+
+} // namespace Service::KernelHelpers
diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp
index 03992af5e..5600ea126 100644
--- a/src/core/hle/service/nvdrv/nvdrv.cpp
+++ b/src/core/hle/service/nvdrv/nvdrv.cpp
@@ -39,11 +39,12 @@ void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger
nvflinger.SetNVDrvInstance(module_);
}
-Module::Module(Core::System& system) : syncpoint_manager{system.GPU()} {
+Module::Module(Core::System& system)
+ : syncpoint_manager{system.GPU()}, service_context{system, "nvdrv"} {
auto& kernel = system.Kernel();
for (u32 i = 0; i < MaxNvEvents; i++) {
- events_interface.events[i].event = Kernel::KEvent::Create(kernel);
- events_interface.events[i].event->Initialize(fmt::format("NVDRV::NvEvent_{}", i));
+ events_interface.events[i].event =
+ service_context.CreateEvent(fmt::format("NVDRV::NvEvent_{}", i));
events_interface.status[i] = EventState::Free;
events_interface.registered[i] = false;
}
@@ -65,8 +66,7 @@ Module::Module(Core::System& system) : syncpoint_manager{system.GPU()} {
Module::~Module() {
for (u32 i = 0; i < MaxNvEvents; i++) {
- events_interface.events[i].event->Close();
- events_interface.events[i].event = nullptr;
+ service_context.CloseEvent(events_interface.events[i].event);
}
}
diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h
index a43ceb7ae..e2a1dde5b 100644
--- a/src/core/hle/service/nvdrv/nvdrv.h
+++ b/src/core/hle/service/nvdrv/nvdrv.h
@@ -9,6 +9,7 @@
#include
#include "common/common_types.h"
+#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/nvdrv/nvdata.h"
#include "core/hle/service/nvdrv/syncpoint_manager.h"
#include "core/hle/service/service.h"
@@ -154,6 +155,8 @@ private:
std::unordered_map> devices;
EventInterface events_interface;
+
+ KernelHelpers::ServiceContext service_context;
};
/// Registers all NVDRV services with the specified service manager.
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index e078ac176..632ce9252 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -96,6 +96,9 @@ protected:
/// System context that the service operates under.
Core::System& system;
+ /// Identifier string used to connect to the service.
+ std::string service_name;
+
private:
template
friend class ServiceFramework;
@@ -117,8 +120,6 @@ private:
void RegisterHandlersBaseTipc(const FunctionInfoBase* functions, std::size_t n);
void ReportUnimplementedFunction(Kernel::HLERequestContext& ctx, const FunctionInfoBase* info);
- /// Identifier string used to connect to the service.
- std::string service_name;
/// Maximum number of concurrent sessions that this service can handle.
u32 max_sessions;
--
cgit v1.2.3
From fe402d350650de50bf9a0aa70c04bec986863978 Mon Sep 17 00:00:00 2001
From: bunnei
Date: Mon, 28 Jun 2021 16:38:13 -0700
Subject: hle: kernel: Ensure global handle table is initialized.
---
src/core/hle/kernel/kernel.cpp | 1 +
1 file changed, 1 insertion(+)
(limited to 'src')
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index ee60072c2..e180db791 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -61,6 +61,7 @@ struct KernelCore::Impl {
void Initialize(KernelCore& kernel) {
global_scheduler_context = std::make_unique(kernel);
global_handle_table = std::make_unique(kernel);
+ global_handle_table->Initialize(KHandleTable::MaxTableSize);
is_phantom_mode_for_singlecore = false;
--
cgit v1.2.3
From 6020723e77585835eddcc5675385f5e7dd3072ac Mon Sep 17 00:00:00 2001
From: bunnei
Date: Mon, 28 Jun 2021 16:58:40 -0700
Subject: hle: kernel: k_process: Close main thread reference after it is
inserted into handle table.
---
src/core/hle/kernel/k_process.cpp | 3 +++
1 file changed, 3 insertions(+)
(limited to 'src')
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp
index d1bd98051..c309ae563 100644
--- a/src/core/hle/kernel/k_process.cpp
+++ b/src/core/hle/kernel/k_process.cpp
@@ -10,6 +10,7 @@
#include "common/alignment.h"
#include "common/assert.h"
#include "common/logging/log.h"
+#include "common/scope_exit.h"
#include "common/settings.h"
#include "core/core.h"
#include "core/device_memory.h"
@@ -43,6 +44,8 @@ void SetupMainThread(Core::System& system, KProcess& owner_process, u32 priority
ASSERT(owner_process.GetResourceLimit()->Reserve(LimitableResource::Threads, 1));
KThread* thread = KThread::Create(system.Kernel());
+ SCOPE_EXIT({ thread->Close(); });
+
ASSERT(KThread::InitializeUserThread(system, thread, entry_point, 0, stack_top, priority,
owner_process.GetIdealCoreId(), &owner_process)
.IsSuccess());
--
cgit v1.2.3
From b119363fc27994a4eb68405011235c4a1b3cdf8f Mon Sep 17 00:00:00 2001
From: bunnei
Date: Mon, 28 Jun 2021 16:59:49 -0700
Subject: hle: kernel: k_process: Close the handle table on shutdown.
---
src/core/hle/kernel/k_process.cpp | 3 +++
1 file changed, 3 insertions(+)
(limited to 'src')
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp
index c309ae563..87171b1c8 100644
--- a/src/core/hle/kernel/k_process.cpp
+++ b/src/core/hle/kernel/k_process.cpp
@@ -409,6 +409,9 @@ void KProcess::Finalize() {
resource_limit->Close();
}
+ // Finalize the handle table and close any open handles.
+ handle_table.Finalize();
+
// Perform inherited finalization.
KAutoObjectWithSlabHeapAndContainer::Finalize();
}
--
cgit v1.2.3
From 7bd020e0307c6a870707440f99bf6bb8b513306f Mon Sep 17 00:00:00 2001
From: bunnei
Date: Wed, 30 Jun 2021 18:06:47 -0700
Subject: hle: service: sm: Refactor to better manage ports.
---
src/core/hle/service/service.cpp | 11 ++++---
src/core/hle/service/service.h | 2 +-
src/core/hle/service/sm/sm.cpp | 65 +++++++++++++++++++++-------------------
src/core/hle/service/sm/sm.h | 14 ++++-----
4 files changed, 47 insertions(+), 45 deletions(-)
(limited to 'src')
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index e6fba88b2..b3e50433b 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -104,23 +104,22 @@ ServiceFrameworkBase::~ServiceFrameworkBase() {
void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager) {
const auto guard = LockService();
- ASSERT(!port_installed);
+ ASSERT(!service_registered);
- auto port = service_manager.RegisterService(service_name, max_sessions).Unwrap();
- port->SetSessionHandler(shared_from_this());
- port_installed = true;
+ service_manager.RegisterService(service_name, max_sessions, shared_from_this());
+ service_registered = true;
}
Kernel::KClientPort& ServiceFrameworkBase::CreatePort() {
const auto guard = LockService();
- ASSERT(!port_installed);
+ ASSERT(!service_registered);
auto* port = Kernel::KPort::Create(kernel);
port->Initialize(max_sessions, false, service_name);
port->GetServerPort().SetSessionHandler(shared_from_this());
- port_installed = true;
+ service_registered = true;
return port->GetClientPort();
}
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index 632ce9252..c9d6b879d 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -125,7 +125,7 @@ private:
/// Flag to store if a port was already create/installed to detect multiple install attempts,
/// which is not supported.
- bool port_installed = false;
+ bool service_registered = false;
/// Function used to safely up-cast pointers to the derived class before invoking a handler.
InvokerFn* handler_invoker;
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp
index 15034abed..ae4dc4a75 100644
--- a/src/core/hle/service/sm/sm.cpp
+++ b/src/core/hle/service/sm/sm.cpp
@@ -4,6 +4,7 @@
#include
#include "common/assert.h"
+#include "common/scope_exit.h"
#include "core/core.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/k_client_port.h"
@@ -40,17 +41,13 @@ static ResultCode ValidateServiceName(const std::string& name) {
}
Kernel::KClientPort& ServiceManager::InterfaceFactory(ServiceManager& self, Core::System& system) {
- ASSERT(self.sm_interface.expired());
-
- auto sm = std::make_shared(self, system);
- self.sm_interface = sm;
+ self.sm_interface = std::make_shared(self, system);
self.controller_interface = std::make_unique(system);
-
- return sm->CreatePort();
+ return self.sm_interface->CreatePort();
}
-ResultVal ServiceManager::RegisterService(std::string name,
- u32 max_sessions) {
+ResultCode ServiceManager::RegisterService(std::string name, u32 max_sessions,
+ Kernel::SessionRequestHandlerPtr handler) {
CASCADE_CODE(ValidateServiceName(name));
@@ -59,12 +56,9 @@ ResultVal ServiceManager::RegisterService(std::string name
return ERR_ALREADY_REGISTERED;
}
- auto* port = Kernel::KPort::Create(kernel);
- port->Initialize(max_sessions, false, name);
+ registered_services.emplace(std::move(name), handler);
- registered_services.emplace(std::move(name), port);
-
- return MakeResult(&port->GetServerPort());
+ return ResultSuccess;
}
ResultCode ServiceManager::UnregisterService(const std::string& name) {
@@ -76,14 +70,11 @@ ResultCode ServiceManager::UnregisterService(const std::string& name) {
return ERR_SERVICE_NOT_REGISTERED;
}
- iter->second->Close();
-
registered_services.erase(iter);
return ResultSuccess;
}
ResultVal ServiceManager::GetServicePort(const std::string& name) {
-
CASCADE_CODE(ValidateServiceName(name));
auto it = registered_services.find(name);
if (it == registered_services.end()) {
@@ -91,10 +82,13 @@ ResultVal ServiceManager::GetServicePort(const std::string& name
return ERR_SERVICE_NOT_REGISTERED;
}
- return MakeResult(it->second);
-}
+ auto* port = Kernel::KPort::Create(kernel);
+ port->Initialize(ServerSessionCountMax, false, name);
+ auto handler = it->second;
+ port->GetServerPort().SetSessionHandler(std::move(handler));
-SM::~SM() = default;
+ return MakeResult(port);
+}
/**
* SM::Initialize service function
@@ -156,11 +150,15 @@ ResultVal SM::GetServiceImpl(Kernel::HLERequestContext&
LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, port_result.Code().raw);
return port_result.Code();
}
- auto& port = port_result.Unwrap()->GetClientPort();
+ auto& port = port_result.Unwrap();
+ SCOPE_EXIT({ port->GetClientPort().Close(); });
+
+ server_ports.emplace_back(&port->GetServerPort());
// Create a new session.
Kernel::KClientSession* session{};
- if (const auto result = port.CreateSession(std::addressof(session)); result.IsError()) {
+ if (const auto result = port->GetClientPort().CreateSession(std::addressof(session));
+ result.IsError()) {
LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, result.raw);
return result;
}
@@ -180,20 +178,21 @@ void SM::RegisterService(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_SM, "called with name={}, max_session_count={}, is_light={}", name,
max_session_count, is_light);
- auto handle = service_manager.RegisterService(name, max_session_count);
- if (handle.Failed()) {
- LOG_ERROR(Service_SM, "failed to register service with error_code={:08X}",
- handle.Code().raw);
+ if (const auto result = service_manager.RegisterService(name, max_session_count, nullptr);
+ result.IsError()) {
+ LOG_ERROR(Service_SM, "failed to register service with error_code={:08X}", result.raw);
IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(handle.Code());
+ rb.Push(result);
return;
}
- IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
- rb.Push(handle.Code());
+ auto* port = Kernel::KPort::Create(kernel);
+ port->Initialize(ServerSessionCountMax, is_light, name);
+ SCOPE_EXIT({ port->GetClientPort().Close(); });
- auto server_port = handle.Unwrap();
- rb.PushMoveObjects(server_port);
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
+ rb.Push(ResultSuccess);
+ rb.PushMoveObjects(port->GetServerPort());
}
void SM::UnregisterService(Kernel::HLERequestContext& ctx) {
@@ -225,4 +224,10 @@ SM::SM(ServiceManager& service_manager_, Core::System& system_)
});
}
+SM::~SM() {
+ for (auto& server_port : server_ports) {
+ server_port->Close();
+ }
+}
+
} // namespace Service::SM
diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h
index ea37f11d4..068c78588 100644
--- a/src/core/hle/service/sm/sm.h
+++ b/src/core/hle/service/sm/sm.h
@@ -49,6 +49,7 @@ private:
ServiceManager& service_manager;
bool is_initialized{};
Kernel::KernelCore& kernel;
+ std::vector server_ports;
};
class ServiceManager {
@@ -58,7 +59,8 @@ public:
explicit ServiceManager(Kernel::KernelCore& kernel_);
~ServiceManager();
- ResultVal RegisterService(std::string name, u32 max_sessions);
+ ResultCode RegisterService(std::string name, u32 max_sessions,
+ Kernel::SessionRequestHandlerPtr handler);
ResultCode UnregisterService(const std::string& name);
ResultVal GetServicePort(const std::string& name);
@@ -69,21 +71,17 @@ public:
LOG_DEBUG(Service, "Can't find service: {}", service_name);
return nullptr;
}
- auto* port = service->second;
- if (port == nullptr) {
- return nullptr;
- }
- return std::static_pointer_cast(port->GetServerPort().GetSessionRequestHandler());
+ return std::static_pointer_cast(service->second);
}
void InvokeControlRequest(Kernel::HLERequestContext& context);
private:
- std::weak_ptr sm_interface;
+ std::shared_ptr sm_interface;
std::unique_ptr controller_interface;
/// Map of registered services, retrieved using GetServicePort.
- std::unordered_map registered_services;
+ std::unordered_map registered_services;
/// Kernel context
Kernel::KernelCore& kernel;
--
cgit v1.2.3
From 24540e0ad9b81092aa3f60fa843bfe45ebd25b8b Mon Sep 17 00:00:00 2001
From: bunnei
Date: Thu, 1 Jul 2021 20:05:10 -0700
Subject: kernel: svc: ConnectToNamedPort: Close extra reference to port.
---
src/core/hle/kernel/svc.cpp | 1 +
1 file changed, 1 insertion(+)
(limited to 'src')
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 8339e11a0..e1e556370 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -298,6 +298,7 @@ static ResultCode ConnectToNamedPort(Core::System& system, Handle* out, VAddr po
// Create a session.
KClientSession* session{};
R_TRY(port->CreateSession(std::addressof(session)));
+ port->Close();
// Register the session in the table, close the extra reference.
handle_table.Register(*out, session);
--
cgit v1.2.3
From ecf36534446df97bbe18042a098f25069dfd8648 Mon Sep 17 00:00:00 2001
From: bunnei
Date: Thu, 1 Jul 2021 21:44:50 -0700
Subject: hle: kernel: Ensure global handle table is finalized before closing.
---
src/core/hle/kernel/kernel.cpp | 1 +
1 file changed, 1 insertion(+)
(limited to 'src')
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index e180db791..b7f9eb5c1 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -117,6 +117,7 @@ struct KernelCore::Impl {
current_process = nullptr;
}
+ global_handle_table->Finalize();
global_handle_table.reset();
preemption_event = nullptr;
--
cgit v1.2.3
From 854c7a3c2826b769d9d41c79570c4dae57e0b3eb Mon Sep 17 00:00:00 2001
From: bunnei
Date: Thu, 1 Jul 2021 21:50:42 -0700
Subject: hle: kernel: Ensure current running process is closed.
---
src/core/hle/kernel/kernel.cpp | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
(limited to 'src')
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index b7f9eb5c1..2d5525839 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -91,6 +91,12 @@ struct KernelCore::Impl {
}
void Shutdown() {
+ if (current_process) {
+ current_process->Finalize();
+ current_process->Close();
+ current_process = nullptr;
+ }
+
process_list.clear();
// Ensures all service threads gracefully shutdown
@@ -112,11 +118,6 @@ struct KernelCore::Impl {
cores.clear();
- if (current_process) {
- current_process->Close();
- current_process = nullptr;
- }
-
global_handle_table->Finalize();
global_handle_table.reset();
--
cgit v1.2.3
From 8d755147d8fbe664d78b3e78514b64804505d6d7 Mon Sep 17 00:00:00 2001
From: bunnei
Date: Fri, 2 Jul 2021 15:04:08 -0700
Subject: hle: kernel: KProcess: Change process termination assert to a
warning.
- Since we do not implement multiprocess right now, this should not be a crashing assert.
---
src/core/hle/kernel/k_process.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'src')
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp
index 87171b1c8..8ead1a769 100644
--- a/src/core/hle/kernel/k_process.cpp
+++ b/src/core/hle/kernel/k_process.cpp
@@ -165,7 +165,7 @@ void KProcess::DecrementThreadCount() {
ASSERT(num_threads > 0);
if (const auto count = --num_threads; count == 0) {
- UNIMPLEMENTED_MSG("Process termination is not implemented!");
+ LOG_WARNING(Kernel, "Process termination is not fully implemented.");
}
}
--
cgit v1.2.3
From 52caa52cc2e47d426b5af38fd8439da237836e0e Mon Sep 17 00:00:00 2001
From: bunnei
Date: Fri, 2 Jul 2021 15:19:04 -0700
Subject: hle: kernel: Track and release server sessions, and protect methods
with locks.
---
src/core/hle/kernel/hle_ipc.cpp | 3 ++
src/core/hle/kernel/k_server_session.cpp | 5 +-
src/core/hle/kernel/kernel.cpp | 78 +++++++++++++++++++++++++++-----
src/core/hle/kernel/kernel.h | 9 ++++
4 files changed, 82 insertions(+), 13 deletions(-)
(limited to 'src')
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index 28ed6265a..ca68fc325 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -58,6 +58,9 @@ bool SessionRequestManager::HasSessionRequestHandler(const HLERequestContext& co
void SessionRequestHandler::ClientConnected(KServerSession* session) {
session->ClientConnected(shared_from_this());
+
+ // Ensure our server session is tracked globally.
+ kernel.RegisterServerSession(session);
}
void SessionRequestHandler::ClientDisconnected(KServerSession* session) {
diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp
index 5c3c13ce6..b9f24475c 100644
--- a/src/core/hle/kernel/k_server_session.cpp
+++ b/src/core/hle/kernel/k_server_session.cpp
@@ -28,7 +28,10 @@ namespace Kernel {
KServerSession::KServerSession(KernelCore& kernel_) : KSynchronizationObject{kernel_} {}
-KServerSession::~KServerSession() {}
+KServerSession::~KServerSession() {
+ // Ensure that the global list tracking server sessions does not hold on to a reference.
+ kernel.UnregisterServerSession(this);
+}
void KServerSession::Initialize(KSession* parent_session_, std::string&& name_,
std::shared_ptr manager_) {
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 2d5525839..92fbc5532 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -91,15 +91,39 @@ struct KernelCore::Impl {
}
void Shutdown() {
+ // Shutdown all processes.
if (current_process) {
current_process->Finalize();
current_process->Close();
current_process = nullptr;
}
-
process_list.clear();
- // Ensures all service threads gracefully shutdown
+ // Close all open server ports.
+ std::unordered_set server_ports_;
+ {
+ std::lock_guard lk(server_ports_lock);
+ server_ports_ = server_ports;
+ server_ports.clear();
+ }
+ for (auto* server_port : server_ports_) {
+ server_port->Close();
+ }
+ // Close all open server sessions.
+ std::unordered_set server_sessions_;
+ {
+ std::lock_guard lk(server_sessions_lock);
+ server_sessions_ = server_sessions;
+ server_sessions.clear();
+ }
+ for (auto* server_session : server_sessions_) {
+ server_session->Close();
+ }
+
+ // Ensure that the object list container is finalized and properly shutdown.
+ object_list_container.Finalize();
+
+ // Ensures all service threads gracefully shutdown.
service_threads.clear();
next_object_id = 0;
@@ -147,10 +171,13 @@ struct KernelCore::Impl {
next_host_thread_id = Core::Hardware::NUM_CPU_CORES;
// Track kernel objects that were not freed on shutdown
- if (registered_objects.size()) {
- LOG_WARNING(Kernel, "{} kernel objects were dangling on shutdown!",
- registered_objects.size());
- registered_objects.clear();
+ {
+ std::lock_guard lk(registered_objects_lock);
+ if (registered_objects.size()) {
+ LOG_WARNING(Kernel, "{} kernel objects were dangling on shutdown!",
+ registered_objects.size());
+ registered_objects.clear();
+ }
}
}
@@ -640,6 +667,21 @@ struct KernelCore::Impl {
user_slab_heap_size);
}
+ KClientPort* CreateNamedServicePort(std::string name) {
+ auto search = service_interface_factory.find(name);
+ if (search == service_interface_factory.end()) {
+ UNIMPLEMENTED();
+ return {};
+ }
+
+ KClientPort* port = &search->second(system.ServiceManager(), system);
+ {
+ std::lock_guard lk(server_ports_lock);
+ server_ports.insert(&port->GetParent()->GetServerPort());
+ }
+ return port;
+ }
+
std::atomic next_object_id{0};
std::atomic next_kernel_process_id{KProcess::InitialKIPIDMin};
std::atomic next_user_process_id{KProcess::ProcessIDMin};
@@ -666,7 +708,12 @@ struct KernelCore::Impl {
/// the ConnectToPort SVC.
std::unordered_map service_interface_factory;
NamedPortTable named_ports;
+ std::unordered_set server_ports;
+ std::unordered_set server_sessions;
std::unordered_set registered_objects;
+ std::mutex server_ports_lock;
+ std::mutex server_sessions_lock;
+ std::mutex registered_objects_lock;
std::unique_ptr exclusive_monitor;
std::vector cores;
@@ -855,19 +902,26 @@ void KernelCore::RegisterNamedService(std::string name, ServiceInterfaceFactory&
}
KClientPort* KernelCore::CreateNamedServicePort(std::string name) {
- auto search = impl->service_interface_factory.find(name);
- if (search == impl->service_interface_factory.end()) {
- UNIMPLEMENTED();
- return {};
- }
- return &search->second(impl->system.ServiceManager(), impl->system);
+ return impl->CreateNamedServicePort(std::move(name));
+}
+
+void KernelCore::RegisterServerSession(KServerSession* server_session) {
+ std::lock_guard lk(impl->server_sessions_lock);
+ impl->server_sessions.insert(server_session);
+}
+
+void KernelCore::UnregisterServerSession(KServerSession* server_session) {
+ std::lock_guard lk(impl->server_sessions_lock);
+ impl->server_sessions.erase(server_session);
}
void KernelCore::RegisterKernelObject(KAutoObject* object) {
+ std::lock_guard lk(impl->registered_objects_lock);
impl->registered_objects.insert(object);
}
void KernelCore::UnregisterKernelObject(KAutoObject* object) {
+ std::lock_guard lk(impl->registered_objects_lock);
impl->registered_objects.erase(object);
}
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index b669ca74e..3a6db0b1c 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -45,6 +45,7 @@ class KPort;
class KProcess;
class KResourceLimit;
class KScheduler;
+class KServerSession;
class KSession;
class KSharedMemory;
class KThread;
@@ -185,6 +186,14 @@ public:
/// Opens a port to a service previously registered with RegisterNamedService.
KClientPort* CreateNamedServicePort(std::string name);
+ /// Registers a server session with the gobal emulation state, to be freed on shutdown. This is
+ /// necessary because we do not emulate processes for HLE sessions.
+ void RegisterServerSession(KServerSession* server_session);
+
+ /// Unregisters a server session previously registered with RegisterServerSession when it was
+ /// destroyed during the current emulation session.
+ void UnregisterServerSession(KServerSession* server_session);
+
/// Registers all kernel objects with the global emulation state, this is purely for tracking
/// leaks after emulation has been shutdown.
void RegisterKernelObject(KAutoObject* object);
--
cgit v1.2.3
From 6c6e730e9a7d88184b807b97ce88da907f36d7e3 Mon Sep 17 00:00:00 2001
From: bunnei
Date: Sat, 3 Jul 2021 02:34:40 -0700
Subject: hle: service: hid: npad: Remove unused kernel reference.
---
src/core/hle/service/hid/controllers/npad.cpp | 1 -
1 file changed, 1 deletion(-)
(limited to 'src')
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 95d4f9588..b7f551e40 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -254,7 +254,6 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) {
}
void Controller_NPad::OnInit() {
- auto& kernel = system.Kernel();
for (std::size_t i = 0; i < styleset_changed_events.size(); ++i) {
styleset_changed_events[i] =
service_context.CreateEvent(fmt::format("npad:NpadStyleSetChanged_{}", i));
--
cgit v1.2.3
From 185b19fd5b5c9cec1db860fc15d23bec4ba0647a Mon Sep 17 00:00:00 2001
From: bunnei
Date: Sat, 3 Jul 2021 12:02:47 -0700
Subject: hle: service: nvdrv: Remove unused kernel reference.
---
src/core/hle/service/nvdrv/nvdrv.cpp | 1 -
1 file changed, 1 deletion(-)
(limited to 'src')
diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp
index 5600ea126..ff405099a 100644
--- a/src/core/hle/service/nvdrv/nvdrv.cpp
+++ b/src/core/hle/service/nvdrv/nvdrv.cpp
@@ -41,7 +41,6 @@ void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger
Module::Module(Core::System& system)
: syncpoint_manager{system.GPU()}, service_context{system, "nvdrv"} {
- auto& kernel = system.Kernel();
for (u32 i = 0; i < MaxNvEvents; i++) {
events_interface.events[i].event =
service_context.CreateEvent(fmt::format("NVDRV::NvEvent_{}", i));
--
cgit v1.2.3
From f3db3dcc8d5941bf09d682c9d22c865701e8160f Mon Sep 17 00:00:00 2001
From: bunnei
Date: Tue, 20 Jul 2021 18:53:43 -0700
Subject: hle: kernel: svc: Remove part of ExitProcess.
- ExitProcess is not actually implemented either way, and this needs more work before we implement.
---
src/core/hle/kernel/svc.cpp | 5 -----
1 file changed, 5 deletions(-)
(limited to 'src')
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index e1e556370..2eb532472 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -1440,11 +1440,6 @@ static void ExitProcess(Core::System& system) {
LOG_INFO(Kernel_SVC, "Process {} exiting", current_process->GetProcessID());
ASSERT_MSG(current_process->GetStatus() == ProcessStatus::Running,
"Process has already exited");
-
- current_process->PrepareForTermination();
-
- // Kill the current thread
- system.Kernel().CurrentScheduler()->GetCurrentThread()->Exit();
}
static void ExitProcess32(Core::System& system) {
--
cgit v1.2.3
From 346bfb6c47096239e1997e348c76aeadbe05294d Mon Sep 17 00:00:00 2001
From: bunnei
Date: Tue, 20 Jul 2021 18:54:35 -0700
Subject: hle: service: kernel_helpers: Remove unnecessary pragma once.
---
src/core/hle/service/kernel_helpers.cpp | 2 --
1 file changed, 2 deletions(-)
(limited to 'src')
diff --git a/src/core/hle/service/kernel_helpers.cpp b/src/core/hle/service/kernel_helpers.cpp
index 895294c9f..62f4cdfb2 100644
--- a/src/core/hle/service/kernel_helpers.cpp
+++ b/src/core/hle/service/kernel_helpers.cpp
@@ -2,8 +2,6 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#pragma once
-
#include "core/core.h"
#include "core/hle/kernel/k_event.h"
#include "core/hle/kernel/k_process.h"
--
cgit v1.2.3
From 75059c46d645e42e8da31fb97d003047c67b004b Mon Sep 17 00:00:00 2001
From: ameerj
Date: Fri, 9 Jul 2021 13:59:09 -0400
Subject: thread_worker: Fix compile time error
state is unused in the branch where with_state is false
---
src/common/thread_worker.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'src')
diff --git a/src/common/thread_worker.h b/src/common/thread_worker.h
index 8272985ff..0a975a869 100644
--- a/src/common/thread_worker.h
+++ b/src/common/thread_worker.h
@@ -39,7 +39,7 @@ public:
const auto lambda = [this, func](std::stop_token stop_token) {
Common::SetCurrentThreadName(thread_name.c_str());
{
- std::conditional_t state{func()};
+ [[maybe_unused]] std::conditional_t state{func()};
while (!stop_token.stop_requested()) {
Task task;
{
--
cgit v1.2.3
From 2d48a7b4d0666ad16d03a22d85712617a0849046 Mon Sep 17 00:00:00 2001
From: ReinUsesLisp
Date: Sat, 9 Jan 2021 03:30:07 -0300
Subject: shader: Initial recompiler work
---
src/CMakeLists.txt | 1 +
src/shader_recompiler/CMakeLists.txt | 86 ++
src/shader_recompiler/environment.h | 14 +
src/shader_recompiler/exception.h | 42 +
src/shader_recompiler/file_environment.cpp | 42 +
src/shader_recompiler/file_environment.h | 21 +
src/shader_recompiler/frontend/ir/attribute.cpp | 447 ++++++++
src/shader_recompiler/frontend/ir/attribute.h | 242 +++++
src/shader_recompiler/frontend/ir/basic_block.cpp | 142 +++
src/shader_recompiler/frontend/ir/basic_block.h | 134 +++
src/shader_recompiler/frontend/ir/condition.cpp | 31 +
src/shader_recompiler/frontend/ir/condition.h | 60 ++
src/shader_recompiler/frontend/ir/flow_test.cpp | 83 ++
src/shader_recompiler/frontend/ir/flow_test.h | 61 ++
src/shader_recompiler/frontend/ir/ir_emitter.cpp | 533 ++++++++++
src/shader_recompiler/frontend/ir/ir_emitter.h | 123 +++
.../frontend/ir/microinstruction.cpp | 189 ++++
.../frontend/ir/microinstruction.h | 82 ++
src/shader_recompiler/frontend/ir/opcode.cpp | 67 ++
src/shader_recompiler/frontend/ir/opcode.h | 44 +
src/shader_recompiler/frontend/ir/opcode.inc | 142 +++
src/shader_recompiler/frontend/ir/pred.h | 28 +
src/shader_recompiler/frontend/ir/reg.h | 314 ++++++
src/shader_recompiler/frontend/ir/type.cpp | 36 +
src/shader_recompiler/frontend/ir/type.h | 47 +
src/shader_recompiler/frontend/ir/value.cpp | 124 +++
src/shader_recompiler/frontend/ir/value.h | 98 ++
.../frontend/maxwell/control_flow.cpp | 531 ++++++++++
.../frontend/maxwell/control_flow.h | 137 +++
src/shader_recompiler/frontend/maxwell/decode.cpp | 149 +++
src/shader_recompiler/frontend/maxwell/decode.h | 14 +
.../frontend/maxwell/instruction.h | 62 ++
src/shader_recompiler/frontend/maxwell/location.h | 106 ++
src/shader_recompiler/frontend/maxwell/maxwell.inc | 285 +++++
src/shader_recompiler/frontend/maxwell/opcode.cpp | 26 +
src/shader_recompiler/frontend/maxwell/opcode.h | 30 +
src/shader_recompiler/frontend/maxwell/program.cpp | 69 ++
src/shader_recompiler/frontend/maxwell/program.h | 39 +
.../frontend/maxwell/termination_code.cpp | 79 ++
.../frontend/maxwell/termination_code.h | 16 +
.../frontend/maxwell/translate/impl/exit.cpp | 15 +
.../impl/floating_point_conversion_integer.cpp | 133 +++
.../impl/floating_point_multi_function.cpp | 71 ++
.../frontend/maxwell/translate/impl/impl.cpp | 79 ++
.../frontend/maxwell/translate/impl/impl.h | 316 ++++++
.../translate/impl/load_store_attribute.cpp | 92 ++
.../maxwell/translate/impl/load_store_memory.cpp | 90 ++
.../maxwell/translate/impl/not_implemented.cpp | 1105 ++++++++++++++++++++
.../maxwell/translate/impl/register_move.cpp | 45 +
.../frontend/maxwell/translate/translate.cpp | 50 +
.../frontend/maxwell/translate/translate.h | 16 +
.../ir_opt/dead_code_elimination_pass.cpp | 23 +
.../ir_opt/get_set_elimination_pass.cpp | 87 ++
.../ir_opt/identity_removal_pass.cpp | 37 +
src/shader_recompiler/ir_opt/passes.h | 16 +
src/shader_recompiler/ir_opt/verification_pass.cpp | 50 +
src/shader_recompiler/main.cpp | 60 ++
57 files changed, 7061 insertions(+)
create mode 100644 src/shader_recompiler/CMakeLists.txt
create mode 100644 src/shader_recompiler/environment.h
create mode 100644 src/shader_recompiler/exception.h
create mode 100644 src/shader_recompiler/file_environment.cpp
create mode 100644 src/shader_recompiler/file_environment.h
create mode 100644 src/shader_recompiler/frontend/ir/attribute.cpp
create mode 100644 src/shader_recompiler/frontend/ir/attribute.h
create mode 100644 src/shader_recompiler/frontend/ir/basic_block.cpp
create mode 100644 src/shader_recompiler/frontend/ir/basic_block.h
create mode 100644 src/shader_recompiler/frontend/ir/condition.cpp
create mode 100644 src/shader_recompiler/frontend/ir/condition.h
create mode 100644 src/shader_recompiler/frontend/ir/flow_test.cpp
create mode 100644 src/shader_recompiler/frontend/ir/flow_test.h
create mode 100644 src/shader_recompiler/frontend/ir/ir_emitter.cpp
create mode 100644 src/shader_recompiler/frontend/ir/ir_emitter.h
create mode 100644 src/shader_recompiler/frontend/ir/microinstruction.cpp
create mode 100644 src/shader_recompiler/frontend/ir/microinstruction.h
create mode 100644 src/shader_recompiler/frontend/ir/opcode.cpp
create mode 100644 src/shader_recompiler/frontend/ir/opcode.h
create mode 100644 src/shader_recompiler/frontend/ir/opcode.inc
create mode 100644 src/shader_recompiler/frontend/ir/pred.h
create mode 100644 src/shader_recompiler/frontend/ir/reg.h
create mode 100644 src/shader_recompiler/frontend/ir/type.cpp
create mode 100644 src/shader_recompiler/frontend/ir/type.h
create mode 100644 src/shader_recompiler/frontend/ir/value.cpp
create mode 100644 src/shader_recompiler/frontend/ir/value.h
create mode 100644 src/shader_recompiler/frontend/maxwell/control_flow.cpp
create mode 100644 src/shader_recompiler/frontend/maxwell/control_flow.h
create mode 100644 src/shader_recompiler/frontend/maxwell/decode.cpp
create mode 100644 src/shader_recompiler/frontend/maxwell/decode.h
create mode 100644 src/shader_recompiler/frontend/maxwell/instruction.h
create mode 100644 src/shader_recompiler/frontend/maxwell/location.h
create mode 100644 src/shader_recompiler/frontend/maxwell/maxwell.inc
create mode 100644 src/shader_recompiler/frontend/maxwell/opcode.cpp
create mode 100644 src/shader_recompiler/frontend/maxwell/opcode.h
create mode 100644 src/shader_recompiler/frontend/maxwell/program.cpp
create mode 100644 src/shader_recompiler/frontend/maxwell/program.h
create mode 100644 src/shader_recompiler/frontend/maxwell/termination_code.cpp
create mode 100644 src/shader_recompiler/frontend/maxwell/termination_code.h
create mode 100644 src/shader_recompiler/frontend/maxwell/translate/impl/exit.cpp
create mode 100644 src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_conversion_integer.cpp
create mode 100644 src/shader_recompiler/frontend/maxwell/translate/impl/floating_point_multi_function.cpp
create mode 100644 src/shader_recompiler/frontend/maxwell/translate/impl/impl.cpp
create mode 100644 src/shader_recompiler/frontend/maxwell/translate/impl/impl.h
create mode 100644 src/shader_recompiler/frontend/maxwell/translate/impl/load_store_attribute.cpp
create mode 100644 src/shader_recompiler/frontend/maxwell/translate/impl/load_store_memory.cpp
create mode 100644 src/shader_recompiler/frontend/maxwell/translate/impl/not_implemented.cpp
create mode 100644 src/shader_recompiler/frontend/maxwell/translate/impl/register_move.cpp
create mode 100644 src/shader_recompiler/frontend/maxwell/translate/translate.cpp
create mode 100644 src/shader_recompiler/frontend/maxwell/translate/translate.h
create mode 100644 src/shader_recompiler/ir_opt/dead_code_elimination_pass.cpp
create mode 100644 src/shader_recompiler/ir_opt/get_set_elimination_pass.cpp
create mode 100644 src/shader_recompiler/ir_opt/identity_removal_pass.cpp
create mode 100644 src/shader_recompiler/ir_opt/passes.h
create mode 100644 src/shader_recompiler/ir_opt/verification_pass.cpp
create mode 100644 src/shader_recompiler/main.cpp
(limited to 'src')
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index f8ec8fea8..6e66dc1df 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -142,6 +142,7 @@ add_subdirectory(core)
add_subdirectory(audio_core)
add_subdirectory(video_core)
add_subdirectory(input_common)
+add_subdirectory(shader_recompiler)
add_subdirectory(tests)
if (ENABLE_SDL2)
diff --git a/src/shader_recompiler/CMakeLists.txt b/src/shader_recompiler/CMakeLists.txt
new file mode 100644
index 000000000..c65846bc4
--- /dev/null
+++ b/src/shader_recompiler/CMakeLists.txt
@@ -0,0 +1,86 @@
+add_executable(shader_recompiler
+ environment.h
+ exception.h
+ file_environment.cpp
+ file_environment.h
+ frontend/ir/attribute.cpp
+ frontend/ir/attribute.h
+ frontend/ir/basic_block.cpp
+ frontend/ir/basic_block.h
+ frontend/ir/condition.cpp
+ frontend/ir/condition.h
+ frontend/ir/flow_test.cpp
+ frontend/ir/flow_test.h
+ frontend/ir/ir_emitter.cpp
+ frontend/ir/ir_emitter.h
+ frontend/ir/microinstruction.cpp
+ frontend/ir/microinstruction.h
+ frontend/ir/opcode.cpp
+ frontend/ir/opcode.h
+ frontend/ir/opcode.inc
+ frontend/ir/pred.h
+ frontend/ir/reg.h
+ frontend/ir/type.cpp
+ frontend/ir/type.h
+ frontend/ir/value.cpp
+ frontend/ir/value.h
+ frontend/maxwell/control_flow.cpp
+ frontend/maxwell/control_flow.h
+ frontend/maxwell/decode.cpp
+ frontend/maxwell/decode.h
+ frontend/maxwell/instruction.h
+ frontend/maxwell/location.h
+ frontend/maxwell/maxwell.inc
+ frontend/maxwell/opcode.cpp
+ frontend/maxwell/opcode.h
+ frontend/maxwell/program.cpp
+ frontend/maxwell/program.h
+ frontend/maxwell/termination_code.cpp
+ frontend/maxwell/termination_code.h
+ frontend/maxwell/translate/impl/floating_point_conversion_integer.cpp
+ frontend/maxwell/translate/impl/floating_point_multi_function.cpp
+ frontend/maxwell/translate/impl/impl.cpp
+ frontend/maxwell/translate/impl/impl.h
+ frontend/maxwell/translate/impl/load_store_attribute.cpp
+ frontend/maxwell/translate/impl/load_store_memory.cpp
+ frontend/maxwell/translate/impl/not_implemented.cpp
+ frontend/maxwell/translate/impl/register_move.cpp
+ frontend/maxwell/translate/translate.cpp
+ frontend/maxwell/translate/translate.h
+ ir_opt/dead_code_elimination_pass.cpp
+ ir_opt/get_set_elimination_pass.cpp
+ ir_opt/identity_removal_pass.cpp
+ ir_opt/passes.h
+ ir_opt/verification_pass.cpp
+ main.cpp
+)
+target_link_libraries(shader_recompiler PRIVATE fmt::fmt)
+
+if (MSVC)
+ target_compile_options(shader_recompiler PRIVATE
+ /W4
+ /WX
+ /we4018 # 'expression' : signed/unsigned mismatch
+ /we4244 # 'argument' : conversion from 'type1' to 'type2', possible loss of data (floating-point)
+ /we4245 # 'conversion' : conversion from 'type1' to 'type2', signed/unsigned mismatch
+ /we4254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data
+ /we4267 # 'var' : conversion from 'size_t' to 'type', possible loss of data
+ /we4305 # 'context' : truncation from 'type1' to 'type2'
+ /we4800 # Implicit conversion from 'type' to bool. Possible information loss
+ /we4826 # Conversion from 'type1' to 'type2' is sign-extended. This may cause unexpected runtime behavior.
+ )
+else()
+ target_compile_options(shader_recompiler PRIVATE
+ -Werror
+ -Werror=conversion
+ -Werror=ignored-qualifiers
+ -Werror=implicit-fallthrough
+ -Werror=shadow
+ -Werror=sign-compare
+ $<$:-Werror=unused-but-set-parameter>
+ $<$:-Werror=unused-but-set-variable>
+ -Werror=unused-variable
+ )
+endif()
+
+create_target_directory_groups(shader_recompiler)
diff --git a/src/shader_recompiler/environment.h b/src/shader_recompiler/environment.h
new file mode 100644
index 000000000..f6230e817
--- /dev/null
+++ b/src/shader_recompiler/environment.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#include "common/common_types.h"
+
+namespace Shader {
+
+class Environment {
+public:
+ virtual ~Environment() = default;
+
+ [[nodiscard]] virtual u64 ReadInstruction(u32 address) const = 0;
+};
+
+} // namespace Shader
diff --git a/src/shader_recompiler/exception.h b/src/shader_recompiler/exception.h
new file mode 100644
index 000000000..6fe620801
--- /dev/null
+++ b/src/shader_recompiler/exception.h
@@ -0,0 +1,42 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include
+#include
+
+#include
+
+namespace Shader {
+
+class LogicError : public std::logic_error {
+public:
+ template
+ LogicError(const char* message, Args&&... args)
+ : std::logic_error{fmt::format(message, std::forward(args)...)} {}
+};
+
+class RuntimeError : public std::runtime_error {
+public:
+ template
+ RuntimeError(const char* message, Args&&... args)
+ : std::runtime_error{fmt::format(message, std::forward(args)...)} {}
+};
+
+class NotImplementedException : public std::logic_error {
+public:
+ template
+ NotImplementedException(const char* message, Args&&... args)
+ : std::logic_error{fmt::format(message, std::forward(args)...)} {}
+};
+
+class InvalidArgument : public std::invalid_argument {
+public:
+ template
+ InvalidArgument(const char* message, Args&&... args)
+ : std::invalid_argument{fmt::format(message, std::forward(args)...)} {}
+};
+
+} // namespace Shader
diff --git a/src/shader_recompiler/file_environment.cpp b/src/shader_recompiler/file_environment.cpp
new file mode 100644
index 000000000..b34bf462b
--- /dev/null
+++ b/src/shader_recompiler/file_environment.cpp
@@ -0,0 +1,42 @@
+#include
+
+#include "exception.h"
+#include "file_environment.h"
+
+namespace Shader {
+
+FileEnvironment::FileEnvironment(const char* path) {
+ std::FILE* const file{std::fopen(path, "rb")};
+ if (!file) {
+ throw RuntimeError("Failed to open file='{}'", path);
+ }
+ std::fseek(file, 0, SEEK_END);
+ const long size{std::ftell(file)};
+ std::rewind(file);
+ if (size % 8 != 0) {
+ std::fclose(file);
+ throw RuntimeError("File size={} is not aligned to 8", size);
+ }
+ // TODO: Use a unique_ptr to avoid zero-initializing this
+ const size_t num_inst{static_cast(size) / 8};
+ data.resize(num_inst);
+ if (std::fread(data.data(), 8, num_inst, file) != num_inst) {
+ std::fclose(file);
+ throw RuntimeError("Failed to read instructions={} from file='{}'", num_inst, path);
+ }
+ std::fclose(file);
+}
+
+FileEnvironment::~FileEnvironment() = default;
+
+u64 FileEnvironment::ReadInstruction(u32 offset) const {
+ if (offset % 8 != 0) {
+ throw InvalidArgument("offset={} is not aligned to 8", offset);
+ }
+ if (offset / 8 >= static_cast(data.size())) {
+ throw InvalidArgument("offset={} is out of bounds", offset);
+ }
+ return data[offset / 8];
+}
+
+} // namespace Shader
diff --git a/src/shader_recompiler/file_environment.h b/src/shader_recompiler/file_environment.h
new file mode 100644
index 000000000..c294bc6fa
--- /dev/null
+++ b/src/shader_recompiler/file_environment.h
@@ -0,0 +1,21 @@
+#pragma once
+
+#include
+
+#include "common/common_types.h"
+#include "environment.h"
+
+namespace Shader {
+
+class FileEnvironment final : public Environment {
+public:
+ explicit FileEnvironment(const char* path);
+ ~FileEnvironment() override;
+
+ u64 ReadInstruction(u32 offset) const override;
+
+private:
+ std::vector data;
+};
+
+} // namespace Shader
diff --git a/src/shader_recompiler/frontend/ir/attribute.cpp b/src/shader_recompiler/frontend/ir/attribute.cpp
new file mode 100644
index 000000000..2fb7d576f
--- /dev/null
+++ b/src/shader_recompiler/frontend/ir/attribute.cpp
@@ -0,0 +1,447 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include
+
+#include "shader_recompiler/exception.h"
+#include "shader_recompiler/frontend/ir/attribute.h"
+
+namespace Shader::IR {
+
+bool IsGeneric(Attribute attribute) noexcept {
+ return attribute >= Attribute::Generic0X && attribute <= Attribute::Generic31X;
+}
+
+int GenericAttributeIndex(Attribute attribute) {
+ if (!IsGeneric(attribute)) {
+ throw InvalidArgument("Attribute is not generic {}", attribute);
+ }
+ return (static_cast(attribute) - static_cast(Attribute::Generic0X)) / 4;
+}
+
+std::string NameOf(Attribute attribute) {
+ switch (attribute) {
+ case Attribute::PrimitiveId:
+ return "PrimitiveId";
+ case Attribute::Layer:
+ return "Layer";
+ case Attribute::ViewportIndex:
+ return "ViewportIndex";
+ case Attribute::PointSize:
+ return "PointSize";
+ case Attribute::PositionX:
+ return "Position.X";
+ case Attribute::PositionY:
+ return "Position.Y";
+ case Attribute::PositionZ:
+ return "Position.Z";
+ case Attribute::PositionW:
+ return "Position.W";
+ case Attribute::Generic0X:
+ return "Generic[0].X";
+ case Attribute::Generic0Y:
+ return "Generic[0].Y";
+ case Attribute::Generic0Z:
+ return "Generic[0].Z";
+ case Attribute::Generic0W:
+ return "Generic[0].W";
+ case Attribute::Generic1X:
+ return "Generic[1].X";
+ case Attribute::Generic1Y:
+ return "Generic[1].Y";
+ case Attribute::Generic1Z:
+ return "Generic[1].Z";
+ case Attribute::Generic1W:
+ return "Generic[1].W";
+ case Attribute::Generic2X:
+ return "Generic[2].X";
+ case Attribute::Generic2Y:
+ return "Generic[2].Y";
+ case Attribute::Generic2Z:
+ return "Generic[2].Z";
+ case Attribute::Generic2W:
+ return "Generic[2].W";
+ case Attribute::Generic3X:
+ return "Generic[3].X";
+ case Attribute::Generic3Y:
+ return "Generic[3].Y";
+ case Attribute::Generic3Z:
+ return "Generic[3].Z";
+ case Attribute::Generic3W:
+ return "Generic[3].W";
+ case Attribute::Generic4X:
+ return "Generic[4].X";
+ case Attribute::Generic4Y:
+ return "Generic[4].Y";
+ case Attribute::Generic4Z:
+ return "Generic[4].Z";
+ case Attribute::Generic4W:
+ return "Generic[4].W";
+ case Attribute::Generic5X:
+ return "Generic[5].X";
+ case Attribute::Generic5Y:
+ return "Generic[5].Y";
+ case Attribute::Generic5Z:
+ return "Generic[5].Z";
+ case Attribute::Generic5W:
+ return "Generic[5].W";
+ case Attribute::Generic6X:
+ return "Generic[6].X";
+ case Attribute::Generic6Y:
+ return "Generic[6].Y";
+ case Attribute::Generic6Z:
+ return "Generic[6].Z";
+ case Attribute::Generic6W:
+ return "Generic[6].W";
+ case Attribute::Generic7X:
+ return "Generic[7].X";
+ case Attribute::Generic7Y:
+ return "Generic[7].Y";
+ case Attribute::Generic7Z:
+ return "Generic[7].Z";
+ case Attribute::Generic7W:
+ return "Generic[7].W";
+ case Attribute::Generic8X:
+ return "Generic[8].X";
+ case Attribute::Generic8Y:
+ return "Generic[8].Y";
+ case Attribute::Generic8Z:
+ return "Generic[8].Z";
+ case Attribute::Generic8W:
+ return "Generic[8].W";
+ case Attribute::Generic9X:
+ return "Generic[9].X";
+ case Attribute::Generic9Y:
+ return "Generic[9].Y";
+ case Attribute::Generic9Z:
+ return "Generic[9].Z";
+ case Attribute::Generic9W:
+ return "Generic[9].W";
+ case Attribute::Generic10X:
+ return "Generic[10].X";
+ case Attribute::Generic10Y:
+ return "Generic[10].Y";
+ case Attribute::Generic10Z:
+ return "Generic[10].Z";
+ case Attribute::Generic10W:
+ return "Generic[10].W";
+ case Attribute::Generic11X:
+ return "Generic[11].X";
+ case Attribute::Generic11Y:
+ return "Generic[11].Y";
+ case Attribute::Generic11Z:
+ return "Generic[11].Z";
+ case Attribute::Generic11W:
+ return "Generic[11].W";
+ case Attribute::Generic12X:
+ return "Generic[12].X";
+ case Attribute::Generic12Y:
+ return "Generic[12].Y";
+ case Attribute::Generic12Z:
+ return "Generic[12].Z";
+ case Attribute::Generic12W:
+ return "Generic[12].W";
+ case Attribute::Generic13X:
+ return "Generic[13].X";
+ case Attribute::Generic13Y:
+ return "Generic[13].Y";
+ case Attribute::Generic13Z:
+ return "Generic[13].Z";
+ case Attribute::Generic13W:
+ return "Generic[13].W";
+ case Attribute::Generic14X:
+ return "Generic[14].X";
+ case Attribute::Generic14Y:
+ return "Generic[14].Y";
+ case Attribute::Generic14Z:
+ return "Generic[14].Z";
+ case Attribute::Generic14W:
+ return "Generic[14].W";
+ case Attribute::Generic15X:
+ return "Generic[15].X";
+ case Attribute::Generic15Y:
+ return "Generic[15].Y";
+ case Attribute::Generic15Z:
+ return "Generic[15].Z";
+ case Attribute::Generic15W:
+ return "Generic[15].W";
+ case Attribute::Generic16X:
+ return "Generic[16].X";
+ case Attribute::Generic16Y:
+ return "Generic[16].Y";
+ case Attribute::Generic16Z:
+ return "Generic[16].Z";
+ case Attribute::Generic16W:
+ return "Generic[16].W";
+ case Attribute::Generic17X:
+ return "Generic[17].X";
+ case Attribute::Generic17Y:
+ return "Generic[17].Y";
+ case Attribute::Generic17Z:
+ return "Generic[17].Z";
+ case Attribute::Generic17W:
+ return "Generic[17].W";
+ case Attribute::Generic18X:
+ return "Generic[18].X";
+ case Attribute::Generic18Y:
+ return "Generic[18].Y";
+ case Attribute::Generic18Z:
+ return "Generic[18].Z";
+ case Attribute::Generic18W:
+ return "Generic[18].W";
+ case Attribute::Generic19X:
+ return "Generic[19].X";
+ case Attribute::Generic19Y:
+ return "Generic[19].Y";
+ case Attribute::Generic19Z:
+ return "Generic[19].Z";
+ case Attribute::Generic19W:
+ return "Generic[19].W";
+ case Attribute::Generic20X:
+ return "Generic[20].X";
+ case Attribute::Generic20Y:
+ return "Generic[20].Y";
+ case Attribute::Generic20Z:
+ return "Generic[20].Z";
+ case Attribute::Generic20W:
+ return "Generic[20].W";
+ case Attribute::Generic21X:
+ return "Generic[21].X";
+ case Attribute::Generic21Y:
+ return "Generic[21].Y";
+ case Attribute::Generic21Z:
+ return "Generic[21].Z";
+ case Attribute::Generic21W:
+ return "Generic[21].W";
+ case Attribute::Generic22X:
+ return "Generic[22].X";
+ case Attribute::Generic22Y:
+ return "Generic[22].Y";
+ case Attribute::Generic22Z:
+ return "Generic[22].Z";
+ case Attribute::Generic22W:
+ return "Generic[22].W";
+ case Attribute::Generic23X:
+ return "Generic[23].X";
+ case Attribute::Generic23Y:
+ return "Generic[23].Y";
+ case Attribute::Generic23Z:
+ return "Generic[23].Z";
+ case Attribute::Generic23W:
+ return "Generic[23].W";
+ case Attribute::Generic24X:
+ return "Generic[24].X";
+ case Attribute::Generic24Y:
+ return "Generic[24].Y";
+ case Attribute::Generic24Z:
+ return "Generic[24].Z";
+ case Attribute::Generic24W:
+ return "Generic[24].W";
+ case Attribute::Generic25X:
+ return "Generic[25].X";
+ case Attribute::Generic25Y:
+ return "Generic[25].Y";
+ case Attribute::Generic25Z:
+ return "Generic[25].Z";
+ case Attribute::Generic25W:
+ return "Generic[25].W";
+ case Attribute::Generic26X:
+ return "Generic[26].X";
+ case Attribute::Generic26Y:
+ return "Generic[26].Y";
+ case Attribute::Generic26Z:
+ return "Generic[26].Z";
+ case Attribute::Generic26W:
+ return "Generic[26].W";
+ case Attribute::Generic27X:
+ return "Generic[27].X";
+ case Attribute::Generic27Y:
+ return "Generic[27].Y";
+ case Attribute::Generic27Z:
+ return "Generic[27].Z";
+ case Attribute::Generic27W:
+ return "Generic[27].W";
+ case Attribute::Generic28X:
+ return "Generic[28].X";
+ case Attribute::Generic28Y:
+ return "Generic[28].Y";
+ case Attribute::Generic28Z:
+ return "Generic[28].Z";
+ case Attribute::Generic28W:
+ return "Generic[28].W";
+ case Attribute::Generic29X:
+ return "Generic[29].X";
+ case Attribute::Generic29Y:
+ return "Generic[29].Y";
+ case Attribute::Generic29Z:
+ return "Generic[29].Z";
+ case Attribute::Generic29W:
+ return "Generic[29].W";
+ case Attribute::Generic30X:
+ return "Generic[30].X";
+ case Attribute::Generic30Y:
+ return "Generic[30].Y";
+ case Attribute::Generic30Z:
+ return "Generic[30].Z";
+ case Attribute::Generic30W:
+ return "Generic[30].W";
+ case Attribute::Generic31X:
+ return "Generic[31].X";
+ case Attribute::Generic31Y:
+ return "Generic[31].Y";
+ case Attribute::Generic31Z:
+ return "Generic[31].Z";
+ case Attribute::Generic31W:
+ return "Generic[31].W";
+ case Attribute::ColorFrontDiffuseR:
+ return "ColorFrontDiffuse.R";
+ case Attribute::ColorFrontDiffuseG:
+ return "ColorFrontDiffuse.G";
+ case Attribute::ColorFrontDiffuseB:
+ return "ColorFrontDiffuse.B";
+ case Attribute::ColorFrontDiffuseA:
+ return "ColorFrontDiffuse.A";
+ case Attribute::ColorFrontSpecularR:
+ return "ColorFrontSpecular.R";
+ case Attribute::ColorFrontSpecularG:
+ return "ColorFrontSpecular.G";
+ case Attribute::ColorFrontSpecularB:
+ return "ColorFrontSpecular.B";
+ case Attribute::ColorFrontSpecularA:
+ return "ColorFrontSpecular.A";
+ case Attribute::ColorBackDiffuseR:
+ return "ColorBackDiffuse.R";
+ case Attribute::ColorBackDiffuseG:
+ return "ColorBackDiffuse.G";
+ case Attribute::ColorBackDiffuseB:
+ return "ColorBackDiffuse.B";
+ case Attribute::ColorBackDiffuseA:
+ return "ColorBackDiffuse.A";
+ case Attribute::ColorBackSpecularR:
+ return "ColorBackSpecular.R";
+ case Attribute::ColorBackSpecularG:
+ return "ColorBackSpecular.G";
+ case Attribute::ColorBackSpecularB:
+ return "ColorBackSpecular.B";
+ case Attribute::ColorBackSpecularA:
+ return "ColorBackSpecular.A";
+ case Attribute::ClipDistance0:
+ return "ClipDistance[0]";
+ case Attribute::ClipDistance1:
+ return "ClipDistance[1]";
+ case Attribute::ClipDistance2:
+ return "ClipDistance[2]";
+ case Attribute::ClipDistance3:
+ return "ClipDistance[3]";
+ case Attribute::ClipDistance4:
+ return "ClipDistance[4]";
+ case Attribute::ClipDistance5:
+ return "ClipDistance[5]";
+ case Attribute::ClipDistance6:
+ return "ClipDistance[6]";
+ case Attribute::ClipDistance7:
+ return "ClipDistance[7]";
+ case Attribute::PointSpriteS:
+ return "PointSprite.S";
+ case Attribute::PointSpriteT:
+ return "PointSprite.T";
+ case Attribute::FogCoordinate:
+ return "FogCoordinate";
+ case Attribute::TessellationEvaluationPointU:
+ return "TessellationEvaluationPoint.U";
+ case Attribute::TessellationEvaluationPointV:
+ return "TessellationEvaluationPoint.V";
+ case Attribute::InstanceId:
+ return "InstanceId";
+ case Attribute::VertexId:
+ return "VertexId";
+ case Attribute::FixedFncTexture0S:
+ return "FixedFncTexture[0].S";
+ case Attribute::FixedFncTexture0T:
+ return "FixedFncTexture[0].T";
+ case Attribute::FixedFncTexture0R:
+ return "FixedFncTexture[0].R";
+ case Attribute::FixedFncTexture0Q:
+ return "FixedFncTexture[0].Q";
+ case Attribute::FixedFncTexture1S:
+ return "FixedFncTexture[1].S";
+ case Attribute::FixedFncTexture1T:
+ return "FixedFncTexture[1].T";
+ case Attribute::FixedFncTexture1R:
+ return "FixedFncTexture[1].R";
+ case Attribute::FixedFncTexture1Q:
+ return "FixedFncTexture[1].Q";
+ case Attribute::FixedFncTexture2S:
+ return "FixedFncTexture[2].S";
+ case Attribute::FixedFncTexture2T:
+ return "FixedFncTexture[2].T";
+ case Attribute::FixedFncTexture2R:
+ return "FixedFncTexture[2].R";
+ case Attribute::FixedFncTexture2Q:
+ return "FixedFncTexture[2].Q";
+ case Attribute::FixedFncTexture3S:
+ return "FixedFncTexture[3].S";
+ case Attribute::FixedFncTexture3T:
+ return "FixedFncTexture[3].T";
+ case Attribute::FixedFncTexture3R:
+ return "FixedFncTexture[3].R";
+ case Attribute::FixedFncTexture3Q:
+ return "FixedFncTexture[3].Q";
+ case Attribute::FixedFncTexture4S:
+ return "FixedFncTexture[4].S";
+ case Attribute::FixedFncTexture4T:
+ return "FixedFncTexture[4].T";
+ case Attribute::FixedFncTexture4R:
+ return "FixedFncTexture[4].R";
+ case Attribute::FixedFncTexture4Q:
+ return "FixedFncTexture[4].Q";
+ case Attribute::FixedFncTexture5S:
+ return "FixedFncTexture[5].S";
+ case Attribute::FixedFncTexture5T:
+ return "FixedFncTexture[5].T";
+ case Attribute::FixedFncTexture5R:
+ return "FixedFncTexture[5].R";
+ case Attribute::FixedFncTexture5Q:
+ return "FixedFncTexture[5].Q";
+ case Attribute::FixedFncTexture6S:
+ return "FixedFncTexture[6].S";
+ case Attribute::FixedFncTexture6T:
+ return "FixedFncTexture[6].T";
+ case Attribute::FixedFncTexture6R:
+ return "FixedFncTexture[6].R";
+ case Attribute::FixedFncTexture6Q:
+ return "FixedFncTexture[6].Q";
+ case Attribute::FixedFncTexture7S:
+ return "FixedFncTexture[7].S";
+ case Attribute::FixedFncTexture7T:
+ return "FixedFncTexture[7].T";
+ case Attribute::FixedFncTexture7R:
+ return "FixedFncTexture[7].R";
+ case Attribute::FixedFncTexture7Q:
+ return "FixedFncTexture[7].Q";
+ case Attribute::FixedFncTexture8S:
+ return "FixedFncTexture[8].S";
+ case Attribute::FixedFncTexture8T:
+ return "FixedFncTexture[8].T";
+ case Attribute::FixedFncTexture8R:
+ return "FixedFncTexture[8].R";
+ case Attribute::FixedFncTexture8Q:
+ return "FixedFncTexture[8].Q";
+ case Attribute::FixedFncTexture9S:
+ return "FixedFncTexture[9].S";
+ case Attribute::FixedFncTexture9T:
+ return "FixedFncTexture[9].T";
+ case Attribute::FixedFncTexture9R:
+ return "FixedFncTexture[9].R";
+ case Attribute::FixedFncTexture9Q:
+ return "FixedFncTexture[9].Q";
+ case Attribute::ViewportMask:
+ return "ViewportMask";
+ case Attribute::FrontFace:
+ return "FrontFace";
+ }
+ return fmt::format("", static_cast(attribute));
+}
+
+} // namespace Shader::IR
\ No newline at end of file
diff --git a/src/shader_recompiler/frontend/ir/attribute.h b/src/shader_recompiler/frontend/ir/attribute.h
new file mode 100644
index 000000000..bb2cad6af
--- /dev/null
+++ b/src/shader_recompiler/frontend/ir/attribute.h
@@ -0,0 +1,242 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include
+
+#include "common/common_types.h"
+
+namespace Shader::IR {
+
+enum class Attribute : u64 {
+ PrimitiveId = 24,
+ Layer = 25,
+ ViewportIndex = 26,
+ PointSize = 27,
+ PositionX = 28,
+ PositionY = 29,
+ PositionZ = 30,
+ PositionW = 31,
+ Generic0X = 32,
+ Generic0Y = 33,
+ Generic0Z = 34,
+ Generic0W = 35,
+ Generic1X = 36,
+ Generic1Y = 37,
+ Generic1Z = 38,
+ Generic1W = 39,
+ Generic2X = 40,
+ Generic2Y = 41,
+ Generic2Z = 42,
+ Generic2W = 43,
+ Generic3X = 44,
+ Generic3Y = 45,
+ Generic3Z = 46,
+ Generic3W = 47,
+ Generic4X = 48,
+ Generic4Y = 49,
+ Generic4Z = 50,
+ Generic4W = 51,
+ Generic5X = 52,
+ Generic5Y = 53,
+ Generic5Z = 54,
+ Generic5W = 55,
+ Generic6X = 56,
+ Generic6Y = 57,
+ Generic6Z = 58,
+ Generic6W = 59,
+ Generic7X = 60,
+ Generic7Y = 61,
+ Generic7Z = 62,
+ Generic7W = 63,
+ Generic8X = 64,
+ Generic8Y = 65,
+ Generic8Z = 66,
+ Generic8W = 67,
+ Generic9X = 68,
+ Generic9Y = 69,
+ Generic9Z = 70,
+ Generic9W = 71,
+ Generic10X = 72,
+ Generic10Y = 73,
+ Generic10Z = 74,
+ Generic10W = 75,
+ Generic11X = 76,
+ Generic11Y = 77,
+ Generic11Z = 78,
+ Generic11W = 79,
+ Generic12X = 80,
+ Generic12Y = 81,
+ Generic12Z = 82,
+ Generic12W = 83,
+ Generic13X = 84,
+ Generic13Y = 85,
+ Generic13Z = 86,
+ Generic13W = 87,
+ Generic14X = 88,
+ Generic14Y = 89,
+ Generic14Z = 90,
+ Generic14W = 91,
+ Generic15X = 92,
+ Generic15Y = 93,
+ Generic15Z = 94,
+ Generic15W = 95,
+ Generic16X = 96,
+ Generic16Y = 97,
+ Generic16Z = 98,
+ Generic16W = 99,
+ Generic17X = 100,
+ Generic17Y = 101,
+ Generic17Z = 102,
+ Generic17W = 103,
+ Generic18X = 104,
+ Generic18Y = 105,
+ Generic18Z = 106,
+ Generic18W = 107,
+ Generic19X = 108,
+ Generic19Y = 109,
+ Generic19Z = 110,
+ Generic19W = 111,
+ Generic20X = 112,
+ Generic20Y = 113,
+ Generic20Z = 114,
+ Generic20W = 115,
+ Generic21X = 116,
+ Generic21Y = 117,
+ Generic21Z = 118,
+ Generic21W = 119,
+ Generic22X = 120,
+ Generic22Y = 121,
+ Generic22Z = 122,
+ Generic22W = 123,
+ Generic23X = 124,
+ Generic23Y = 125,
+ Generic23Z = 126,
+ Generic23W = 127,
+ Generic24X = 128,
+ Generic24Y = 129,
+ Generic24Z = 130,
+ Generic24W = 131,
+ Generic25X = 132,
+ Generic25Y = 133,
+ Generic25Z = 134,
+ Generic25W = 135,
+ Generic26X = 136,
+ Generic26Y = 137,
+ Generic26Z = 138,
+ Generic26W = 139,
+ Generic27X = 140,
+ Generic27Y = 141,
+ Generic27Z = 142,
+ Generic27W = 143,
+ Generic28X = 144,
+ Generic28Y = 145,
+ Generic28Z = 146,
+ Generic28W = 147,
+ Generic29X = 148,
+ Generic29Y = 149,
+ Generic29Z = 150,
+ Generic29W = 151,
+ Generic30X = 152,
+ Generic30Y = 153,
+ Generic30Z = 154,
+ Generic30W = 155,
+ Generic31X = 156,
+ Generic31Y = 157,
+ Generic31Z = 158,
+ Generic31W = 159,
+ ColorFrontDiffuseR = 160,
+ ColorFrontDiffuseG = 161,
+ ColorFrontDiffuseB = 162,
+ ColorFrontDiffuseA = 163,
+ ColorFrontSpecularR = 164,
+ ColorFrontSpecularG = 165,
+ ColorFrontSpecularB = 166,
+ ColorFrontSpecularA = 167,
+ ColorBackDiffuseR = 168,
+ ColorBackDiffuseG = 169,
+ ColorBackDiffuseB = 170,
+ ColorBackDiffuseA = 171,
+ ColorBackSpecularR = 172,
+ ColorBackSpecularG = 173,
+ ColorBackSpecularB = 174,
+ ColorBackSpecularA = 175,
+ ClipDistance0 = 176,
+ ClipDistance1 = 177,
+ ClipDistance2 = 178,
+ ClipDistance3 = 179,
+ ClipDistance4 = 180,
+ ClipDistance5 = 181,
+ ClipDistance6 = 182,
+ ClipDistance7 = 183,
+ PointSpriteS = 184,
+ PointSpriteT = 185,
+ FogCoordinate = 186,
+ TessellationEvaluationPointU = 188,
+ TessellationEvaluationPointV = 189,
+ InstanceId = 190,
+ VertexId = 191,
+ FixedFncTexture0S = 192,
+ FixedFncTexture0T = 193,
+ FixedFncTexture0R = 194,
+ FixedFncTexture0Q = 195,
+ FixedFncTexture1S = 196,
+ FixedFncTexture1T = 197,
+ FixedFncTexture1R = 198,
+ FixedFncTexture1Q = 199,
+ FixedFncTexture2S = 200,
+ FixedFncTexture2T = 201,
+ FixedFncTexture2R = 202,
+ FixedFncTexture2Q = 203,
+ FixedFncTexture3S = 204,
+ FixedFncTexture3T = 205,
+ FixedFncTexture3R = 206,
+ FixedFncTexture3Q = 207,
+ FixedFncTexture4S = 208,
+ FixedFncTexture4T = 209,
+ FixedFncTexture4R = 210,
+ FixedFncTexture4Q = 211,
+ FixedFncTexture5S = 212,
+ FixedFncTexture5T = 213,
+ FixedFncTexture5R = 214,
+ FixedFncTexture5Q = 215,
+ FixedFncTexture6S = 216,
+ FixedFncTexture6T = 217,
+ FixedFncTexture6R = 218,
+ FixedFncTexture6Q = 219,
+ FixedFncTexture7S = 220,
+ FixedFncTexture7T = 221,
+ FixedFncTexture7R = 222,
+ FixedFncTexture7Q = 223,
+ FixedFncTexture8S = 224,
+ FixedFncTexture8T = 225,
+ FixedFncTexture8R = 226,
+ FixedFncTexture8Q = 227,
+ FixedFncTexture9S = 228,
+ FixedFncTexture9T = 229,
+ FixedFncTexture9R = 230,
+ FixedFncTexture9Q = 231,
+ ViewportMask = 232,
+ FrontFace = 255,
+};
+
+[[nodiscard]] bool IsGeneric(Attribute attribute) noexcept;
+
+[[nodiscard]] int GenericAttributeIndex(Attribute attribute);
+
+[[nodiscard]] std::string NameOf(Attribute attribute);
+
+} // namespace Shader::IR
+
+template <>
+struct fmt::formatter {
+ constexpr auto parse(format_parse_context& ctx) {
+ return ctx.begin();
+ }
+ template
+ auto format(const Shader::IR::Attribute& attribute, FormatContext& ctx) {
+ return fmt::format_to(ctx.out(), "{}", Shader::IR::NameOf(attribute));
+ }
+};
diff --git a/src/shader_recompiler/frontend/ir/basic_block.cpp b/src/shader_recompiler/frontend/ir/basic_block.cpp
new file mode 100644
index 000000000..0406726ad
--- /dev/null
+++ b/src/shader_recompiler/frontend/ir/basic_block.cpp
@@ -0,0 +1,142 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include
+#include
+#include