summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/common/logging/backend.cpp1
-rw-r--r--src/common/logging/log.h1
-rw-r--r--src/common/swap.h14
-rw-r--r--src/core/CMakeLists.txt4
-rw-r--r--src/core/core.cpp10
-rw-r--r--src/core/file_sys/disk_filesystem.cpp5
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp7
-rw-r--r--src/core/hle/kernel/process.cpp5
-rw-r--r--src/core/hle/kernel/svc.cpp14
-rw-r--r--src/core/hle/kernel/svc_wrap.h15
-rw-r--r--src/core/hle/kernel/thread.cpp2
-rw-r--r--src/core/hle/result.h3
-rw-r--r--src/core/hle/service/am/am.cpp8
-rw-r--r--src/core/hle/service/audio/audren_u.cpp44
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp23
-rw-r--r--src/core/hle/service/hid/hid.cpp34
-rw-r--r--src/core/hle/service/nfp/nfp.cpp28
-rw-r--r--src/core/hle/service/nfp/nfp.h28
-rw-r--r--src/core/hle/service/nfp/nfp_user.cpp19
-rw-r--r--src/core/hle/service/nfp/nfp_user.h18
-rw-r--r--src/core/hle/service/service.cpp14
-rw-r--r--src/core/loader/deconstructed_rom_directory.cpp2
-rw-r--r--src/core/loader/elf.cpp2
-rw-r--r--src/core/loader/nro.cpp2
-rw-r--r--src/core/loader/nso.cpp2
-rw-r--r--src/core/memory.h9
-rw-r--r--src/core/settings.h10
-rw-r--r--src/core/telemetry_session.cpp5
-rw-r--r--src/video_core/CMakeLists.txt2
-rw-r--r--src/video_core/engines/maxwell_3d.cpp113
-rw-r--r--src/video_core/engines/maxwell_3d.h29
-rw-r--r--src/video_core/macro_interpreter.cpp257
-rw-r--r--src/video_core/macro_interpreter.h164
-rw-r--r--src/yuzu/about_dialog.cpp2
-rw-r--r--src/yuzu/configuration/config.cpp15
-rw-r--r--src/yuzu/configuration/configure_general.cpp18
-rw-r--r--src/yuzu/configuration/configure_general.ui104
-rw-r--r--src/yuzu/main.cpp30
-rw-r--r--src/yuzu/main.h13
-rw-r--r--src/yuzu/ui_settings.h4
-rw-r--r--src/yuzu_cmd/config.cpp6
-rw-r--r--src/yuzu_cmd/default_ini.h10
42 files changed, 869 insertions, 227 deletions
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp
index 9bfac5e7f..a763f4abf 100644
--- a/src/common/logging/backend.cpp
+++ b/src/common/logging/backend.cpp
@@ -42,6 +42,7 @@ namespace Log {
SUB(Service, FS) \
SUB(Service, HID) \
SUB(Service, LM) \
+ SUB(Service, NFP) \
SUB(Service, NIFM) \
SUB(Service, NS) \
SUB(Service, NVDRV) \
diff --git a/src/common/logging/log.h b/src/common/logging/log.h
index 6913f6b10..7f079b20f 100644
--- a/src/common/logging/log.h
+++ b/src/common/logging/log.h
@@ -59,6 +59,7 @@ enum class Class : ClassType {
Service_FS, ///< The FS (Filesystem) service
Service_HID, ///< The HID (Human interface device) service
Service_LM, ///< The LM (Logger) service
+ Service_NFP, ///< The NFP service
Service_NIFM, ///< The NIFM (Network interface) service
Service_NS, ///< The NS services
Service_NVDRV, ///< The NVDRV (Nvidia driver) service
diff --git a/src/common/swap.h b/src/common/swap.h
index d94cbe6b2..4a4012d1a 100644
--- a/src/common/swap.h
+++ b/src/common/swap.h
@@ -103,7 +103,19 @@ inline __attribute__((always_inline)) u64 swap64(u64 _data) {
return __builtin_bswap64(_data);
}
#elif defined(__Bitrig__) || defined(__OpenBSD__)
-// swap16, swap32, swap64 are left as is
+// redefine swap16, swap32, swap64 as inline functions
+#undef swap16
+#undef swap32
+#undef swap64
+inline u16 swap16(u16 _data) {
+ return __swap16(_data);
+}
+inline u32 swap32(u32 _data) {
+ return __swap32(_data);
+}
+inline u64 swap64(u64 _data) {
+ return __swap64(_data);
+}
#elif defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__)
inline u16 swap16(u16 _data) {
return bswap16(_data);
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 3d187cd40..6f8104516 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -142,6 +142,10 @@ add_library(core STATIC
hle/service/nifm/nifm_s.h
hle/service/nifm/nifm_u.cpp
hle/service/nifm/nifm_u.h
+ hle/service/nfp/nfp.cpp
+ hle/service/nfp/nfp.h
+ hle/service/nfp/nfp_user.cpp
+ hle/service/nfp/nfp_user.h
hle/service/ns/ns.cpp
hle/service/ns/ns.h
hle/service/ns/pl_u.cpp
diff --git a/src/core/core.cpp b/src/core/core.cpp
index d55621de8..11654d4da 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -148,19 +148,15 @@ System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) {
current_process = Kernel::Process::Create("main");
- switch (Settings::values.cpu_core) {
- case Settings::CpuCore::Unicorn:
- cpu_core = std::make_shared<ARM_Unicorn>();
- break;
- case Settings::CpuCore::Dynarmic:
- default:
+ if (Settings::values.use_cpu_jit) {
#ifdef ARCHITECTURE_x86_64
cpu_core = std::make_shared<ARM_Dynarmic>();
#else
cpu_core = std::make_shared<ARM_Unicorn>();
LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
#endif
- break;
+ } else {
+ cpu_core = std::make_shared<ARM_Unicorn>();
}
gpu_core = std::make_unique<Tegra::GPU>();
diff --git a/src/core/file_sys/disk_filesystem.cpp b/src/core/file_sys/disk_filesystem.cpp
index 3a4b45721..4235f3935 100644
--- a/src/core/file_sys/disk_filesystem.cpp
+++ b/src/core/file_sys/disk_filesystem.cpp
@@ -174,8 +174,9 @@ u64 Disk_Storage::GetSize() const {
}
bool Disk_Storage::SetSize(const u64 size) const {
- LOG_WARNING(Service_FS, "(STUBBED) called");
- return false;
+ file->Resize(size);
+ file->Flush();
+ return true;
}
Disk_Directory::Disk_Directory(const std::string& path) : directory() {
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index ffcbfe64f..bef4f15f5 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -268,8 +268,11 @@ std::vector<u8> HLERequestContext::ReadBuffer() const {
size_t HLERequestContext::WriteBuffer(const void* buffer, size_t size) const {
const bool is_buffer_b{BufferDescriptorB().size() && BufferDescriptorB()[0].Size()};
-
- ASSERT_MSG(size <= GetWriteBufferSize(), "Size %lx is too big", size);
+ const size_t buffer_size{GetWriteBufferSize()};
+ if (size > buffer_size) {
+ LOG_CRITICAL(Core, "size (%016zx) is greater than buffer_size (%016zx)", size, buffer_size);
+ size = buffer_size; // TODO(bunnei): This needs to be HW tested
+ }
if (is_buffer_b) {
Memory::WriteBlock(BufferDescriptorB()[0].Address(), buffer, size);
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 3694afc60..2cffec198 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -121,8 +121,9 @@ void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) {
// TODO(bunnei): This is heap area that should be allocated by the kernel and not mapped as part
// of the user address space.
vm_manager
- .MapMemoryBlock(Memory::STACK_VADDR, std::make_shared<std::vector<u8>>(stack_size, 0), 0,
- stack_size, MemoryState::Mapped)
+ .MapMemoryBlock(Memory::STACK_AREA_VADDR_END - stack_size,
+ std::make_shared<std::vector<u8>>(stack_size, 0), 0, stack_size,
+ MemoryState::Mapped)
.Unwrap();
misc_memory_used += stack_size;
memory_region->used += stack_size;
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 311ab4187..171bbd956 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -756,8 +756,16 @@ static ResultCode CreateTransferMemory(Handle* handle, VAddr addr, u64 size, u32
return RESULT_SUCCESS;
}
-static ResultCode SetThreadCoreMask(u64, u64, u64) {
- LOG_WARNING(Kernel_SVC, "(STUBBED) called");
+static ResultCode GetThreadCoreMask(Handle handle, u32* mask, u64* unknown) {
+ LOG_WARNING(Kernel_SVC, "(STUBBED) called, handle=0x%08X", handle);
+ *mask = 0x0;
+ *unknown = 0xf;
+ return RESULT_SUCCESS;
+}
+
+static ResultCode SetThreadCoreMask(Handle handle, u32 mask, u64 unknown) {
+ LOG_WARNING(Kernel_SVC, "(STUBBED) called, handle=0x%08X, mask=0x%08X, unknown=0x%lx", handle,
+ mask, unknown);
return RESULT_SUCCESS;
}
@@ -809,7 +817,7 @@ static const FunctionDef SVC_Table[] = {
{0x0B, SvcWrap<SleepThread>, "SleepThread"},
{0x0C, SvcWrap<GetThreadPriority>, "GetThreadPriority"},
{0x0D, SvcWrap<SetThreadPriority>, "SetThreadPriority"},
- {0x0E, nullptr, "GetThreadCoreMask"},
+ {0x0E, SvcWrap<GetThreadCoreMask>, "GetThreadCoreMask"},
{0x0F, SvcWrap<SetThreadCoreMask>, "SetThreadCoreMask"},
{0x10, SvcWrap<GetCurrentProcessorNumber>, "GetCurrentProcessorNumber"},
{0x11, nullptr, "SignalEvent"},
diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h
index b224f5e67..5da4f5269 100644
--- a/src/core/hle/kernel/svc_wrap.h
+++ b/src/core/hle/kernel/svc_wrap.h
@@ -70,6 +70,21 @@ void SvcWrap() {
FuncReturn(retval);
}
+template <ResultCode func(u32, u32, u64)>
+void SvcWrap() {
+ FuncReturn(func((u32)(PARAM(0) & 0xFFFFFFFF), (u32)(PARAM(1) & 0xFFFFFFFF), PARAM(2)).raw);
+}
+
+template <ResultCode func(u32, u32*, u64*)>
+void SvcWrap() {
+ u32 param_1 = 0;
+ u64 param_2 = 0;
+ ResultCode retval = func((u32)(PARAM(2) & 0xFFFFFFFF), &param_1, &param_2);
+ Core::CPU().SetReg(1, param_1);
+ Core::CPU().SetReg(2, param_2);
+ FuncReturn(retval.raw);
+}
+
template <ResultCode func(u64, u64, u32, u32)>
void SvcWrap() {
FuncReturn(
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 145f50887..f3a8aa4aa 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -342,7 +342,7 @@ SharedPtr<Thread> SetupMainThread(VAddr entry_point, u32 priority,
// Initialize new "main" thread
auto thread_res = Thread::Create("main", entry_point, priority, 0, THREADPROCESSORID_0,
- Memory::STACK_VADDR_END, owner_process);
+ Memory::STACK_AREA_VADDR_END, owner_process);
SharedPtr<Thread> thread = std::move(thread_res).Unwrap();
diff --git a/src/core/hle/result.h b/src/core/hle/result.h
index 97fef7a48..052f49979 100644
--- a/src/core/hle/result.h
+++ b/src/core/hle/result.h
@@ -200,6 +200,9 @@ public:
}
ResultVal& operator=(const ResultVal& o) {
+ if (this == &o) {
+ return *this;
+ }
if (!empty()) {
if (!o.empty()) {
object = o.object;
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index d9f003ed4..bab338205 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -12,6 +12,7 @@
#include "core/hle/service/apm/apm.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/nvflinger/nvflinger.h"
+#include "core/settings.h"
namespace Service {
namespace AM {
@@ -241,17 +242,20 @@ void ICommonStateGetter::GetCurrentFocusState(Kernel::HLERequestContext& ctx) {
}
void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) {
+ const bool use_docked_mode{Settings::values.use_docked_mode};
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
- rb.Push(static_cast<u8>(OperationMode::Handheld));
+ rb.Push(static_cast<u8>(use_docked_mode ? OperationMode::Docked : OperationMode::Handheld));
LOG_WARNING(Service_AM, "(STUBBED) called");
}
void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) {
+ const bool use_docked_mode{Settings::values.use_docked_mode};
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
- rb.Push(static_cast<u32>(APM::PerformanceMode::Handheld));
+ rb.Push(static_cast<u32>(use_docked_mode ? APM::PerformanceMode::Docked
+ : APM::PerformanceMode::Handheld));
LOG_WARNING(Service_AM, "(STUBBED) called");
}
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index f52cd7d90..6d0461bbc 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -59,12 +59,12 @@ private:
AudioRendererResponseData response_data{};
response_data.section_0_size =
- response_data.state_entries.size() * sizeof(AudioRendererStateEntry);
- response_data.section_1_size = response_data.section_1.size();
- response_data.section_2_size = response_data.section_2.size();
- response_data.section_3_size = response_data.section_3.size();
- response_data.section_4_size = response_data.section_4.size();
- response_data.section_5_size = response_data.section_5.size();
+ static_cast<u32>(response_data.state_entries.size() * sizeof(AudioRendererStateEntry));
+ response_data.section_1_size = static_cast<u32>(response_data.section_1.size());
+ response_data.section_2_size = static_cast<u32>(response_data.section_2.size());
+ response_data.section_3_size = static_cast<u32>(response_data.section_3.size());
+ response_data.section_4_size = static_cast<u32>(response_data.section_4.size());
+ response_data.section_5_size = static_cast<u32>(response_data.section_5.size());
response_data.total_size = sizeof(AudioRendererResponseData);
for (unsigned i = 0; i < response_data.state_entries.size(); i++) {
@@ -156,7 +156,17 @@ public:
IAudioDevice() : ServiceFramework("IAudioDevice") {
static const FunctionInfo functions[] = {
{0x0, &IAudioDevice::ListAudioDeviceName, "ListAudioDeviceName"},
- {0x1, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolume"}};
+ {0x1, &IAudioDevice::SetAudioDeviceOutputVolume, "SetAudioDeviceOutputVolume"},
+ {0x2, nullptr, "GetAudioDeviceOutputVolume"},
+ {0x3, nullptr, "GetActiveAudioDeviceName"},
+ {0x4, &IAudioDevice::QueryAudioDeviceSystemEvent, "QueryAudioDeviceSystemEvent"},
+ {0x5, &IAudioDevice::GetActiveChannelCount, "GetActiveChannelCount"},
+ {0x6, nullptr, "ListAudioDeviceNameAuto"},
+ {0x7, nullptr, "SetAudioDeviceOutputVolumeAuto"},
+ {0x8, nullptr, "GetAudioDeviceOutputVolumeAuto"},
+ {0x10, nullptr, "GetActiveAudioDeviceNameAuto"},
+ {0x11, nullptr, "QueryAudioDeviceInputEvent"},
+ {0x12, nullptr, "QueryAudioDeviceOutputEvent"}};
RegisterHandlers(functions);
buffer_event =
@@ -189,8 +199,26 @@ private:
rb.Push(RESULT_SUCCESS);
}
+ void QueryAudioDeviceSystemEvent(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_Audio, "(STUBBED) called");
+
+ buffer_event->Signal();
+
+ IPC::ResponseBuilder rb{ctx, 2, 1};
+ rb.Push(RESULT_SUCCESS);
+ rb.PushCopyObjects(buffer_event);
+ }
+
+ void GetActiveChannelCount(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_Audio, "(STUBBED) called");
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<u32>(1);
+ }
+
Kernel::SharedPtr<Kernel::Event> buffer_event;
-};
+
+}; // namespace Audio
AudRenU::AudRenU() : ServiceFramework("audren:u") {
static const FunctionInfo functions[] = {
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index 41b8cbfd2..89fa70ae6 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -72,8 +72,8 @@ public:
explicit IFile(std::unique_ptr<FileSys::StorageBackend>&& backend)
: ServiceFramework("IFile"), backend(std::move(backend)) {
static const FunctionInfo functions[] = {
- {0, &IFile::Read, "Read"}, {1, &IFile::Write, "Write"}, {2, nullptr, "Flush"},
- {3, nullptr, "SetSize"}, {4, nullptr, "GetSize"},
+ {0, &IFile::Read, "Read"}, {1, &IFile::Write, "Write"}, {2, nullptr, "Flush"},
+ {3, &IFile::SetSize, "SetSize"}, {4, &IFile::GetSize, "GetSize"},
};
RegisterHandlers(functions);
}
@@ -150,6 +150,25 @@ private:
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
+
+ void SetSize(Kernel::HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const u64 size = rp.Pop<u64>();
+ backend->SetSize(size);
+ LOG_DEBUG(Service_FS, "called, size=%" PRIu64, size);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+ }
+
+ void GetSize(Kernel::HLERequestContext& ctx) {
+ const u64 size = backend->GetSize();
+ LOG_DEBUG(Service_FS, "called, size=%" PRIu64, size);
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<u64>(size);
+ }
};
class IDirectory final : public ServiceFramework<IDirectory> {
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index a0b8c6243..019a09444 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -65,13 +65,14 @@ private:
}
void UpdatePadCallback(u64 userdata, int cycles_late) {
- SharedMemory* mem = reinterpret_cast<SharedMemory*>(shared_mem->GetPointer());
+ SharedMemory mem{};
+ std::memcpy(&mem, shared_mem->GetPointer(), sizeof(SharedMemory));
if (is_device_reload_pending.exchange(false))
LoadInputDevices();
// Set up controllers as neon red+blue Joy-Con attached to console
- ControllerHeader& controller_header = mem->controllers[Controller_Handheld].header;
+ ControllerHeader& controller_header = mem.controllers[Controller_Handheld].header;
controller_header.type = ControllerType_Handheld | ControllerType_JoyconPair;
controller_header.single_colors_descriptor = ColorDesc_ColorsNonexistent;
controller_header.right_color_body = JOYCON_BODY_NEON_RED;
@@ -79,8 +80,8 @@ private:
controller_header.left_color_body = JOYCON_BODY_NEON_BLUE;
controller_header.left_color_buttons = JOYCON_BUTTONS_NEON_BLUE;
- for (int layoutIdx = 0; layoutIdx < HID_NUM_LAYOUTS; layoutIdx++) {
- ControllerLayout& layout = mem->controllers[Controller_Handheld].layouts[layoutIdx];
+ for (int index = 0; index < HID_NUM_LAYOUTS; index++) {
+ ControllerLayout& layout = mem.controllers[Controller_Handheld].layouts[index];
layout.header.num_entries = HID_NUM_ENTRIES;
layout.header.max_entry_index = HID_NUM_ENTRIES - 1;
@@ -136,10 +137,25 @@ private:
// layouts)
}
- // TODO(shinyquagsire23): Update touch info
+ // TODO(bunnei): Properly implement the touch screen, the below will just write empty data
+
+ TouchScreen& touchscreen = mem.touchscreen;
+ const u64 last_entry = touchscreen.header.latest_entry;
+ const u64 curr_entry = (last_entry + 1) % touchscreen.entries.size();
+ const u64 timestamp = CoreTiming::GetTicks();
+ const u64 sample_counter = touchscreen.entries[last_entry].header.timestamp + 1;
+ touchscreen.header.timestamp_ticks = timestamp;
+ touchscreen.header.num_entries = touchscreen.entries.size();
+ touchscreen.header.latest_entry = curr_entry;
+ touchscreen.header.max_entry_index = touchscreen.entries.size();
+ touchscreen.header.timestamp = timestamp;
+ touchscreen.entries[curr_entry].header.timestamp = sample_counter;
+ touchscreen.entries[curr_entry].header.num_touches = 0;
// TODO(shinyquagsire23): Signal events
+ std::memcpy(shared_mem->GetPointer(), &mem, sizeof(SharedMemory));
+
// Reschedule recurrent event
CoreTiming::ScheduleEvent(pad_update_ticks - cycles_late, pad_update_event);
}
@@ -185,6 +201,7 @@ public:
{66, &Hid::StartSixAxisSensor, "StartSixAxisSensor"},
{79, &Hid::SetGyroscopeZeroDriftMode, "SetGyroscopeZeroDriftMode"},
{100, &Hid::SetSupportedNpadStyleSet, "SetSupportedNpadStyleSet"},
+ {101, &Hid::GetSupportedNpadStyleSet, "GetSupportedNpadStyleSet"},
{102, &Hid::SetSupportedNpadIdType, "SetSupportedNpadIdType"},
{103, &Hid::ActivateNpad, "ActivateNpad"},
{106, &Hid::AcquireNpadStyleSetUpdateEventHandle,
@@ -265,6 +282,13 @@ private:
LOG_WARNING(Service_HID, "(STUBBED) called");
}
+ void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) {
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push<u32>(0);
+ LOG_WARNING(Service_HID, "(STUBBED) called");
+ }
+
void SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp
new file mode 100644
index 000000000..49870841c
--- /dev/null
+++ b/src/core/hle/service/nfp/nfp.cpp
@@ -0,0 +1,28 @@
+// 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/hle/ipc_helpers.h"
+#include "core/hle/service/nfp/nfp.h"
+#include "core/hle/service/nfp/nfp_user.h"
+
+namespace Service {
+namespace NFP {
+
+Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
+ : ServiceFramework(name), module(std::move(module)) {}
+
+void Module::Interface::Unknown(Kernel::HLERequestContext& ctx) {
+ LOG_WARNING(Service_NFP, "(STUBBED) called");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(RESULT_SUCCESS);
+}
+
+void InstallInterfaces(SM::ServiceManager& service_manager) {
+ auto module = std::make_shared<Module>();
+ std::make_shared<NFP_User>(module)->InstallAsService(service_manager);
+}
+
+} // namespace NFP
+} // namespace Service
diff --git a/src/core/hle/service/nfp/nfp.h b/src/core/hle/service/nfp/nfp.h
new file mode 100644
index 000000000..1163e9954
--- /dev/null
+++ b/src/core/hle/service/nfp/nfp.h
@@ -0,0 +1,28 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace NFP {
+
+class Module final {
+public:
+ class Interface : public ServiceFramework<Interface> {
+ public:
+ Interface(std::shared_ptr<Module> module, const char* name);
+
+ void Unknown(Kernel::HLERequestContext& ctx);
+
+ protected:
+ std::shared_ptr<Module> module;
+ };
+};
+
+void InstallInterfaces(SM::ServiceManager& service_manager);
+
+} // namespace NFP
+} // namespace Service
diff --git a/src/core/hle/service/nfp/nfp_user.cpp b/src/core/hle/service/nfp/nfp_user.cpp
new file mode 100644
index 000000000..14e5647c4
--- /dev/null
+++ b/src/core/hle/service/nfp/nfp_user.cpp
@@ -0,0 +1,19 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/nfp/nfp_user.h"
+
+namespace Service {
+namespace NFP {
+
+NFP_User::NFP_User(std::shared_ptr<Module> module)
+ : Module::Interface(std::move(module), "nfp:user") {
+ static const FunctionInfo functions[] = {
+ {0, &NFP_User::Unknown, "Unknown"},
+ };
+ RegisterHandlers(functions);
+}
+
+} // namespace NFP
+} // namespace Service
diff --git a/src/core/hle/service/nfp/nfp_user.h b/src/core/hle/service/nfp/nfp_user.h
new file mode 100644
index 000000000..1606444ca
--- /dev/null
+++ b/src/core/hle/service/nfp/nfp_user.h
@@ -0,0 +1,18 @@
+// Copyright 2018 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/nfp/nfp.h"
+
+namespace Service {
+namespace NFP {
+
+class NFP_User final : public Module::Interface {
+public:
+ explicit NFP_User(std::shared_ptr<Module> module);
+};
+
+} // namespace NFP
+} // namespace Service
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index b224b89da..c5490c1ae 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -25,6 +25,7 @@
#include "core/hle/service/friend/friend.h"
#include "core/hle/service/hid/hid.h"
#include "core/hle/service/lm/lm.h"
+#include "core/hle/service/nfp/nfp.h"
#include "core/hle/service/nifm/nifm.h"
#include "core/hle/service/ns/ns.h"
#include "core/hle/service/nvdrv/nvdrv.h"
@@ -111,15 +112,15 @@ void ServiceFrameworkBase::ReportUnimplementedFunction(Kernel::HLERequestContext
auto cmd_buf = ctx.CommandBuffer();
std::string function_name = info == nullptr ? fmt::format("{}", ctx.GetCommand()) : info->name;
- fmt::MemoryWriter w;
- w.write("function '{}': port='{}' cmd_buf={{[0]={:#x}", function_name, service_name,
- cmd_buf[0]);
+ fmt::memory_buffer buf;
+ fmt::format_to(buf, "function '{}': port='{}' cmd_buf={{[0]={:#x}", function_name, service_name,
+ cmd_buf[0]);
for (int i = 1; i <= 8; ++i) {
- w.write(", [{}]={:#x}", i, cmd_buf[i]);
+ fmt::format_to(buf, ", [{}]={:#x}", i, cmd_buf[i]);
}
- w << '}';
+ buf.push_back('}');
- LOG_ERROR(Service, "unknown / unimplemented %s", w.c_str());
+ LOG_ERROR(Service, "unknown / unimplemented %s", fmt::to_string(buf).c_str());
UNIMPLEMENTED();
}
@@ -187,6 +188,7 @@ void Init() {
Friend::InstallInterfaces(*SM::g_service_manager);
HID::InstallInterfaces(*SM::g_service_manager);
LM::InstallInterfaces(*SM::g_service_manager);
+ NFP::InstallInterfaces(*SM::g_service_manager);
NIFM::InstallInterfaces(*SM::g_service_manager);
NS::InstallInterfaces(*SM::g_service_manager);
Nvidia::InstallInterfaces(*SM::g_service_manager);
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp
index aa09ed323..8b4ee970f 100644
--- a/src/core/loader/deconstructed_rom_directory.cpp
+++ b/src/core/loader/deconstructed_rom_directory.cpp
@@ -76,7 +76,7 @@ FileType AppLoader_DeconstructedRomDirectory::IdentifyType(FileUtil::IOFile& fil
} else if (Common::ToLower(virtual_name) == "sdk") {
is_sdk_found = true;
} else {
- // Contrinue searching
+ // Continue searching
return true;
}
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp
index 0ba8c6fd2..e9f462196 100644
--- a/src/core/loader/elf.cpp
+++ b/src/core/loader/elf.cpp
@@ -414,7 +414,7 @@ ResultStatus AppLoader_ELF::Load(Kernel::SharedPtr<Kernel::Process>& process) {
process->resource_limit =
Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION);
- process->Run(codeset->entrypoint, 48, Memory::STACK_SIZE);
+ process->Run(codeset->entrypoint, 48, Memory::DEFAULT_STACK_SIZE);
is_loaded = true;
return ResultStatus::Success;
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp
index 6dcd1ce48..b5133e4d6 100644
--- a/src/core/loader/nro.cpp
+++ b/src/core/loader/nro.cpp
@@ -137,7 +137,7 @@ ResultStatus AppLoader_NRO::Load(Kernel::SharedPtr<Kernel::Process>& process) {
process->address_mappings = default_address_mappings;
process->resource_limit =
Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION);
- process->Run(base_addr, 48, Memory::STACK_SIZE);
+ process->Run(base_addr, 48, Memory::DEFAULT_STACK_SIZE);
is_loaded = true;
return ResultStatus::Success;
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp
index 100aa022e..3bc10ed0d 100644
--- a/src/core/loader/nso.cpp
+++ b/src/core/loader/nso.cpp
@@ -165,7 +165,7 @@ ResultStatus AppLoader_NSO::Load(Kernel::SharedPtr<Kernel::Process>& process) {
process->address_mappings = default_address_mappings;
process->resource_limit =
Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION);
- process->Run(Memory::PROCESS_IMAGE_VADDR, 48, Memory::STACK_SIZE);
+ process->Run(Memory::PROCESS_IMAGE_VADDR, 48, Memory::DEFAULT_STACK_SIZE);
is_loaded = true;
return ResultStatus::Success;
diff --git a/src/core/memory.h b/src/core/memory.h
index 413a7b4e8..e9b8ca873 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -162,12 +162,13 @@ enum : VAddr {
TLS_AREA_VADDR = NEW_LINEAR_HEAP_VADDR_END,
TLS_ENTRY_SIZE = 0x200,
TLS_AREA_SIZE = 0x10000000,
- TLS_ADREA_VADDR_END = TLS_AREA_VADDR + TLS_AREA_SIZE,
+ TLS_AREA_VADDR_END = TLS_AREA_VADDR + TLS_AREA_SIZE,
/// Application stack
- STACK_VADDR = TLS_ADREA_VADDR_END,
- STACK_SIZE = 0x10000,
- STACK_VADDR_END = STACK_VADDR + STACK_SIZE,
+ STACK_AREA_VADDR = TLS_AREA_VADDR_END,
+ STACK_AREA_SIZE = 0x10000000,
+ STACK_AREA_VADDR_END = STACK_AREA_VADDR + STACK_AREA_SIZE,
+ DEFAULT_STACK_SIZE = 0x100000,
/// Application heap
/// Size is confirmed to be a static value on fw 3.0.0
diff --git a/src/core/settings.h b/src/core/settings.h
index 6f8cd0f03..2c94caab7 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -105,12 +105,10 @@ static const std::array<const char*, NumAnalogs> mapping = {{
}};
} // namespace NativeAnalog
-enum class CpuCore {
- Unicorn,
- Dynarmic,
-};
-
struct Values {
+ // System
+ bool use_docked_mode;
+
// Controls
std::array<std::string, NativeButton::NumButtons> buttons;
std::array<std::string, NativeAnalog::NumAnalogs> analogs;
@@ -118,7 +116,7 @@ struct Values {
std::string touch_device;
// Core
- CpuCore cpu_core;
+ bool use_cpu_jit;
// Data Storage
bool use_virtual_sd;
diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp
index 970c0a817..cecf0a5cb 100644
--- a/src/core/telemetry_session.cpp
+++ b/src/core/telemetry_session.cpp
@@ -154,12 +154,13 @@ TelemetrySession::TelemetrySession() {
#endif
// Log user configuration information
- AddField(Telemetry::FieldType::UserConfig, "Core_CpuCore",
- static_cast<int>(Settings::values.cpu_core));
+ AddField(Telemetry::FieldType::UserConfig, "Core_UseCpuJit", Settings::values.use_cpu_jit);
AddField(Telemetry::FieldType::UserConfig, "Renderer_ResolutionFactor",
Settings::values.resolution_factor);
AddField(Telemetry::FieldType::UserConfig, "Renderer_ToggleFramelimit",
Settings::values.toggle_framelimit);
+ AddField(Telemetry::FieldType::UserConfig, "System_UseDockedMode",
+ Settings::values.use_docked_mode);
}
TelemetrySession::~TelemetrySession() {
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 841f27d7f..a710c4bc5 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -11,6 +11,8 @@ add_library(video_core STATIC
engines/maxwell_compute.h
gpu.cpp
gpu.h
+ macro_interpreter.cpp
+ macro_interpreter.h
memory_manager.cpp
memory_manager.h
rasterizer_interface.h
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index 5359d21a2..124753032 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -19,35 +19,21 @@ namespace Engines {
/// First register id that is actually a Macro call.
constexpr u32 MacroRegistersStart = 0xE00;
-const std::unordered_map<u32, Maxwell3D::MethodInfo> Maxwell3D::method_handlers = {
- {0xE1A, {"BindTextureInfoBuffer", 1, &Maxwell3D::BindTextureInfoBuffer}},
- {0xE24, {"SetShader", 5, &Maxwell3D::SetShader}},
- {0xE2A, {"BindStorageBuffer", 1, &Maxwell3D::BindStorageBuffer}},
-};
-
-Maxwell3D::Maxwell3D(MemoryManager& memory_manager) : memory_manager(memory_manager) {}
+Maxwell3D::Maxwell3D(MemoryManager& memory_manager)
+ : memory_manager(memory_manager), macro_interpreter(*this) {}
void Maxwell3D::SubmitMacroCode(u32 entry, std::vector<u32> code) {
uploaded_macros[entry * 2 + MacroRegistersStart] = std::move(code);
}
-void Maxwell3D::CallMacroMethod(u32 method, const std::vector<u32>& parameters) {
- // TODO(Subv): Write an interpreter for the macros uploaded via registers 0x45 and 0x47
-
+void Maxwell3D::CallMacroMethod(u32 method, std::vector<u32> parameters) {
+ auto macro_code = uploaded_macros.find(method);
// The requested macro must have been uploaded already.
- ASSERT_MSG(uploaded_macros.find(method) != uploaded_macros.end(), "Macro %08X was not uploaded",
- method);
-
- auto itr = method_handlers.find(method);
- ASSERT_MSG(itr != method_handlers.end(), "Unhandled method call %08X", method);
-
- ASSERT(itr->second.arguments == parameters.size());
-
- (this->*itr->second.handler)(parameters);
+ ASSERT_MSG(macro_code != uploaded_macros.end(), "Macro %08X was not uploaded", method);
- // Reset the current macro and its parameters.
+ // Reset the current macro and execute it.
executing_macro = 0;
- macro_params.clear();
+ macro_interpreter.Execute(macro_code->second, std::move(parameters));
}
void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) {
@@ -77,7 +63,7 @@ void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) {
// Call the macro when there are no more parameters in the command buffer
if (remaining_params == 0) {
- CallMacroMethod(executing_macro, macro_params);
+ CallMacroMethod(executing_macro, std::move(macro_params));
}
return;
}
@@ -193,84 +179,6 @@ void Maxwell3D::DrawArrays() {
VideoCore::g_renderer->Rasterizer()->AccelerateDrawBatch(false /*is_indexed*/);
}
-void Maxwell3D::BindTextureInfoBuffer(const std::vector<u32>& parameters) {
- /**
- * Parameters description:
- * [0] = Shader stage, usually 4 for FragmentShader
- */
-
- u32 stage = parameters[0];
-
- // Perform the same operations as the real macro code.
- GPUVAddr address = static_cast<GPUVAddr>(regs.tex_info_buffers.address[stage]) << 8;
- u32 size = regs.tex_info_buffers.size[stage];
-
- regs.const_buffer.cb_size = size;
- regs.const_buffer.cb_address_high = address >> 32;
- regs.const_buffer.cb_address_low = address & 0xFFFFFFFF;
-}
-
-void Maxwell3D::SetShader(const std::vector<u32>& parameters) {
- /**
- * Parameters description:
- * [0] = Shader Program.
- * [1] = Unknown, presumably the shader id.
- * [2] = Offset to the start of the shader, after the 0x30 bytes header.
- * [3] = Shader Stage.
- * [4] = Const Buffer Address >> 8.
- */
- auto shader_program = static_cast<Regs::ShaderProgram>(parameters[0]);
- // TODO(Subv): This address is probably an offset from the CODE_ADDRESS register.
- GPUVAddr address = parameters[2];
- auto shader_stage = static_cast<Regs::ShaderStage>(parameters[3]);
- GPUVAddr cb_address = parameters[4] << 8;
-
- auto& shader = state.shader_programs[static_cast<size_t>(shader_program)];
- shader.program = shader_program;
- shader.stage = shader_stage;
- shader.address = address;
-
- // Perform the same operations as the real macro code.
- // TODO(Subv): Early exit if register 0xD1C + shader_program contains the same as params[1].
- auto& shader_regs = regs.shader_config[static_cast<size_t>(shader_program)];
- shader_regs.start_id = address;
- // TODO(Subv): Write params[1] to register 0xD1C + shader_program.
- // TODO(Subv): Write params[2] to register 0xD22 + shader_program.
-
- // Note: This value is hardcoded in the macro's code.
- static constexpr u32 DefaultCBSize = 0x10000;
- regs.const_buffer.cb_size = DefaultCBSize;
- regs.const_buffer.cb_address_high = cb_address >> 32;
- regs.const_buffer.cb_address_low = cb_address & 0xFFFFFFFF;
-
- // Write a hardcoded 0x11 to CB_BIND, this binds the current const buffer to buffer c1[] in the
- // shader. It's likely that these are the constants for the shader.
- regs.cb_bind[static_cast<size_t>(shader_stage)].valid.Assign(1);
- regs.cb_bind[static_cast<size_t>(shader_stage)].index.Assign(1);
-
- ProcessCBBind(shader_stage);
-}
-
-void Maxwell3D::BindStorageBuffer(const std::vector<u32>& parameters) {
- /**
- * Parameters description:
- * [0] = Buffer offset >> 2
- */
-
- u32 buffer_offset = parameters[0] << 2;
-
- // Perform the same operations as the real macro code.
- // Note: This value is hardcoded in the macro's code.
- static constexpr u32 DefaultCBSize = 0x5F00;
- regs.const_buffer.cb_size = DefaultCBSize;
-
- GPUVAddr address = regs.ssbo_info.BufferAddress();
- regs.const_buffer.cb_address_high = address >> 32;
- regs.const_buffer.cb_address_low = address & 0xFFFFFFFF;
-
- regs.const_buffer.cb_pos = buffer_offset;
-}
-
void Maxwell3D::ProcessCBBind(Regs::ShaderStage stage) {
// Bind the buffer currently in CB_ADDRESS to the specified index in the desired shader stage.
auto& shader = state.shader_stages[static_cast<size_t>(stage)];
@@ -386,5 +294,10 @@ std::vector<Texture::FullTextureInfo> Maxwell3D::GetStageTextures(Regs::ShaderSt
return textures;
}
+u32 Maxwell3D::GetRegisterValue(u32 method) const {
+ ASSERT_MSG(method < Regs::NUM_REGS, "Invalid Maxwell3D register");
+ return regs.reg_array[method];
+}
+
} // namespace Engines
} // namespace Tegra
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index 3066bc606..98b39b2ff 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -13,6 +13,7 @@
#include "common/common_types.h"
#include "common/math_util.h"
#include "video_core/gpu.h"
+#include "video_core/macro_interpreter.h"
#include "video_core/memory_manager.h"
#include "video_core/textures/texture.h"
@@ -498,22 +499,18 @@ public:
bool enabled;
};
- struct ShaderProgramInfo {
- Regs::ShaderStage stage;
- Regs::ShaderProgram program;
- GPUVAddr address;
- };
-
struct ShaderStageInfo {
std::array<ConstBufferInfo, Regs::MaxConstBuffers> const_buffers;
};
std::array<ShaderStageInfo, Regs::MaxShaderStage> shader_stages;
- std::array<ShaderProgramInfo, Regs::MaxShaderProgram> shader_programs;
};
State state{};
+ /// Reads a register value located at the input method address
+ u32 GetRegisterValue(u32 method) const;
+
/// Write the value to the register identified by method.
void WriteReg(u32 method, u32 value, u32 remaining_params);
@@ -533,6 +530,9 @@ private:
/// Parameters that have been submitted to the macro call so far.
std::vector<u32> macro_params;
+ /// Interpreter for the macro codes uploaded to the GPU.
+ MacroInterpreter macro_interpreter;
+
/// Retrieves information about a specific TIC entry from the TIC buffer.
Texture::TICEntry GetTICEntry(u32 tic_index) const;
@@ -544,7 +544,7 @@ private:
* @param method Method to call
* @param parameters Arguments to the method call
*/
- void CallMacroMethod(u32 method, const std::vector<u32>& parameters);
+ void CallMacroMethod(u32 method, std::vector<u32> parameters);
/// Handles a write to the QUERY_GET register.
void ProcessQueryGet();
@@ -557,19 +557,6 @@ private:
/// Handles a write to the VERTEX_END_GL register, triggering a draw.
void DrawArrays();
-
- /// Method call handlers
- void BindTextureInfoBuffer(const std::vector<u32>& parameters);
- void SetShader(const std::vector<u32>& parameters);
- void BindStorageBuffer(const std::vector<u32>& parameters);
-
- struct MethodInfo {
- const char* name;
- u32 arguments;
- void (Maxwell3D::*handler)(const std::vector<u32>& parameters);
- };
-
- static const std::unordered_map<u32, MethodInfo> method_handlers;
};
#define ASSERT_REG_POSITION(field_name, position) \
diff --git a/src/video_core/macro_interpreter.cpp b/src/video_core/macro_interpreter.cpp
new file mode 100644
index 000000000..993a67746
--- /dev/null
+++ b/src/video_core/macro_interpreter.cpp
@@ -0,0 +1,257 @@
+// Copyright 2018 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/assert.h"
+#include "common/logging/log.h"
+#include "video_core/engines/maxwell_3d.h"
+#include "video_core/macro_interpreter.h"
+
+namespace Tegra {
+
+MacroInterpreter::MacroInterpreter(Engines::Maxwell3D& maxwell3d) : maxwell3d(maxwell3d) {}
+
+void MacroInterpreter::Execute(const std::vector<u32>& code, std::vector<u32> parameters) {
+ Reset();
+ registers[1] = parameters[0];
+ this->parameters = std::move(parameters);
+
+ // Execute the code until we hit an exit condition.
+ bool keep_executing = true;
+ while (keep_executing) {
+ keep_executing = Step(code, false);
+ }
+
+ // Assert the the macro used all the input parameters
+ ASSERT(next_parameter_index == this->parameters.size());
+}
+
+void MacroInterpreter::Reset() {
+ registers = {};
+ pc = 0;
+ delayed_pc = boost::none;
+ method_address.raw = 0;
+ parameters.clear();
+ // The next parameter index starts at 1, because $r1 already has the value of the first
+ // parameter.
+ next_parameter_index = 1;
+}
+
+bool MacroInterpreter::Step(const std::vector<u32>& code, bool is_delay_slot) {
+ u32 base_address = pc;
+
+ Opcode opcode = GetOpcode(code);
+ pc += 4;
+
+ // Update the program counter if we were delayed
+ if (delayed_pc != boost::none) {
+ ASSERT(is_delay_slot);
+ pc = *delayed_pc;
+ delayed_pc = boost::none;
+ }
+
+ switch (opcode.operation) {
+ case Operation::ALU: {
+ u32 result = GetALUResult(opcode.alu_operation, GetRegister(opcode.src_a),
+ GetRegister(opcode.src_b));
+ ProcessResult(opcode.result_operation, opcode.dst, result);
+ break;
+ }
+ case Operation::AddImmediate: {
+ ProcessResult(opcode.result_operation, opcode.dst,
+ GetRegister(opcode.src_a) + opcode.immediate);
+ break;
+ }
+ case Operation::ExtractInsert: {
+ u32 dst = GetRegister(opcode.src_a);
+ u32 src = GetRegister(opcode.src_b);
+
+ src = (src >> opcode.bf_src_bit) & opcode.GetBitfieldMask();
+ dst &= ~(opcode.GetBitfieldMask() << opcode.bf_dst_bit);
+ dst |= src << opcode.bf_dst_bit;
+ ProcessResult(opcode.result_operation, opcode.dst, dst);
+ break;
+ }
+ case Operation::ExtractShiftLeftImmediate: {
+ u32 dst = GetRegister(opcode.src_a);
+ u32 src = GetRegister(opcode.src_b);
+
+ u32 result = ((src >> dst) & opcode.GetBitfieldMask()) << opcode.bf_dst_bit;
+
+ ProcessResult(opcode.result_operation, opcode.dst, result);
+ break;
+ }
+ case Operation::ExtractShiftLeftRegister: {
+ u32 dst = GetRegister(opcode.src_a);
+ u32 src = GetRegister(opcode.src_b);
+
+ u32 result = ((src >> opcode.bf_src_bit) & opcode.GetBitfieldMask()) << dst;
+
+ ProcessResult(opcode.result_operation, opcode.dst, result);
+ break;
+ }
+ case Operation::Read: {
+ u32 result = Read(GetRegister(opcode.src_a) + opcode.immediate);
+ ProcessResult(opcode.result_operation, opcode.dst, result);
+ break;
+ }
+ case Operation::Branch: {
+ ASSERT_MSG(!is_delay_slot, "Executing a branch in a delay slot is not valid");
+ u32 value = GetRegister(opcode.src_a);
+ bool taken = EvaluateBranchCondition(opcode.branch_condition, value);
+ if (taken) {
+ // Ignore the delay slot if the branch has the annul bit.
+ if (opcode.branch_annul) {
+ pc = base_address + (opcode.immediate << 2);
+ return true;
+ }
+
+ delayed_pc = base_address + (opcode.immediate << 2);
+ // Execute one more instruction due to the delay slot.
+ return Step(code, true);
+ }
+ break;
+ }
+ default:
+ UNIMPLEMENTED_MSG("Unimplemented macro operation %u",
+ static_cast<u32>(opcode.operation.Value()));
+ }
+
+ if (opcode.is_exit) {
+ // Exit has a delay slot, execute the next instruction
+ // Note: Executing an exit during a branch delay slot will cause the instruction at the
+ // branch target to be executed before exiting.
+ Step(code, true);
+ return false;
+ }
+
+ return true;
+}
+
+MacroInterpreter::Opcode MacroInterpreter::GetOpcode(const std::vector<u32>& code) const {
+ ASSERT((pc % sizeof(u32)) == 0);
+ ASSERT(pc < code.size() * sizeof(u32));
+ return {code[pc / sizeof(u32)]};
+}
+
+u32 MacroInterpreter::GetALUResult(ALUOperation operation, u32 src_a, u32 src_b) const {
+ switch (operation) {
+ case ALUOperation::Add:
+ return src_a + src_b;
+ // TODO(Subv): Implement AddWithCarry
+ case ALUOperation::Subtract:
+ return src_a - src_b;
+ // TODO(Subv): Implement SubtractWithBorrow
+ case ALUOperation::Xor:
+ return src_a ^ src_b;
+ case ALUOperation::Or:
+ return src_a | src_b;
+ case ALUOperation::And:
+ return src_a & src_b;
+ case ALUOperation::AndNot:
+ return src_a & ~src_b;
+ case ALUOperation::Nand:
+ return ~(src_a & src_b);
+
+ default:
+ UNIMPLEMENTED_MSG("Unimplemented ALU operation %u", static_cast<u32>(operation));
+ }
+}
+
+void MacroInterpreter::ProcessResult(ResultOperation operation, u32 reg, u32 result) {
+ switch (operation) {
+ case ResultOperation::IgnoreAndFetch:
+ // Fetch parameter and ignore result.
+ SetRegister(reg, FetchParameter());
+ break;
+ case ResultOperation::Move:
+ // Move result.
+ SetRegister(reg, result);
+ break;
+ case ResultOperation::MoveAndSetMethod:
+ // Move result and use as Method Address.
+ SetRegister(reg, result);
+ SetMethodAddress(result);
+ break;
+ case ResultOperation::FetchAndSend:
+ // Fetch parameter and send result.
+ SetRegister(reg, FetchParameter());
+ Send(result);
+ break;
+ case ResultOperation::MoveAndSend:
+ // Move and send result.
+ SetRegister(reg, result);
+ Send(result);
+ break;
+ case ResultOperation::FetchAndSetMethod:
+ // Fetch parameter and use result as Method Address.
+ SetRegister(reg, FetchParameter());
+ SetMethodAddress(result);
+ break;
+ case ResultOperation::MoveAndSetMethodFetchAndSend:
+ // Move result and use as Method Address, then fetch and send parameter.
+ SetRegister(reg, result);
+ SetMethodAddress(result);
+ Send(FetchParameter());
+ break;
+ case ResultOperation::MoveAndSetMethodSend:
+ // Move result and use as Method Address, then send bits 12:17 of result.
+ SetRegister(reg, result);
+ SetMethodAddress(result);
+ Send((result >> 12) & 0b111111);
+ break;
+ default:
+ UNIMPLEMENTED_MSG("Unimplemented result operation %u", static_cast<u32>(operation));
+ }
+}
+
+u32 MacroInterpreter::FetchParameter() {
+ ASSERT(next_parameter_index < parameters.size());
+ return parameters[next_parameter_index++];
+}
+
+u32 MacroInterpreter::GetRegister(u32 register_id) const {
+ // Register 0 is supposed to always return 0.
+ if (register_id == 0)
+ return 0;
+
+ ASSERT(register_id < registers.size());
+ return registers[register_id];
+}
+
+void MacroInterpreter::SetRegister(u32 register_id, u32 value) {
+ // Register 0 is supposed to always return 0. NOP is implemented as a store to the zero
+ // register.
+ if (register_id == 0)
+ return;
+
+ ASSERT(register_id < registers.size());
+ registers[register_id] = value;
+}
+
+void MacroInterpreter::SetMethodAddress(u32 address) {
+ method_address.raw = address;
+}
+
+void MacroInterpreter::Send(u32 value) {
+ maxwell3d.WriteReg(method_address.address, value, 0);
+ // Increment the method address by the method increment.
+ method_address.address.Assign(method_address.address.Value() +
+ method_address.increment.Value());
+}
+
+u32 MacroInterpreter::Read(u32 method) const {
+ return maxwell3d.GetRegisterValue(method);
+}
+
+bool MacroInterpreter::EvaluateBranchCondition(BranchCondition cond, u32 value) const {
+ switch (cond) {
+ case BranchCondition::Zero:
+ return value == 0;
+ case BranchCondition::NotZero:
+ return value != 0;
+ }
+ UNREACHABLE();
+}
+
+} // namespace Tegra
diff --git a/src/video_core/macro_interpreter.h b/src/video_core/macro_interpreter.h
new file mode 100644
index 000000000..a71e359d8
--- /dev/null
+++ b/src/video_core/macro_interpreter.h
@@ -0,0 +1,164 @@
+// Copyright 2018 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+#include <vector>
+#include <boost/optional.hpp>
+#include "common/bit_field.h"
+#include "common/common_types.h"
+
+namespace Tegra {
+namespace Engines {
+class Maxwell3D;
+}
+
+class MacroInterpreter final {
+public:
+ explicit MacroInterpreter(Engines::Maxwell3D& maxwell3d);
+
+ /**
+ * Executes the macro code with the specified input parameters.
+ * @param code The macro byte code to execute
+ * @param parameters The parameters of the macro
+ */
+ void Execute(const std::vector<u32>& code, std::vector<u32> parameters);
+
+private:
+ enum class Operation : u32 {
+ ALU = 0,
+ AddImmediate = 1,
+ ExtractInsert = 2,
+ ExtractShiftLeftImmediate = 3,
+ ExtractShiftLeftRegister = 4,
+ Read = 5,
+ Unused = 6, // This operation doesn't seem to be a valid encoding.
+ Branch = 7,
+ };
+
+ enum class ALUOperation : u32 {
+ Add = 0,
+ AddWithCarry = 1,
+ Subtract = 2,
+ SubtractWithBorrow = 3,
+ // Operations 4-7 don't seem to be valid encodings.
+ Xor = 8,
+ Or = 9,
+ And = 10,
+ AndNot = 11,
+ Nand = 12
+ };
+
+ enum class ResultOperation : u32 {
+ IgnoreAndFetch = 0,
+ Move = 1,
+ MoveAndSetMethod = 2,
+ FetchAndSend = 3,
+ MoveAndSend = 4,
+ FetchAndSetMethod = 5,
+ MoveAndSetMethodFetchAndSend = 6,
+ MoveAndSetMethodSend = 7
+ };
+
+ enum class BranchCondition : u32 {
+ Zero = 0,
+ NotZero = 1,
+ };
+
+ union Opcode {
+ u32 raw;
+ BitField<0, 3, Operation> operation;
+ BitField<4, 3, ResultOperation> result_operation;
+ BitField<4, 1, BranchCondition> branch_condition;
+ BitField<5, 1, u32>
+ branch_annul; // If set on a branch, then the branch doesn't have a delay slot.
+ BitField<7, 1, u32> is_exit;
+ BitField<8, 3, u32> dst;
+ BitField<11, 3, u32> src_a;
+ BitField<14, 3, u32> src_b;
+ // The signed immediate overlaps the second source operand and the alu operation.
+ BitField<14, 18, s32> immediate;
+
+ BitField<17, 5, ALUOperation> alu_operation;
+
+ // Bitfield instructions data
+ BitField<17, 5, u32> bf_src_bit;
+ BitField<22, 5, u32> bf_size;
+ BitField<27, 5, u32> bf_dst_bit;
+
+ u32 GetBitfieldMask() const {
+ return (1 << bf_size) - 1;
+ }
+ };
+
+ union MethodAddress {
+ u32 raw;
+ BitField<0, 12, u32> address;
+ BitField<12, 6, u32> increment;
+ };
+
+ /// Resets the execution engine state, zeroing registers, etc.
+ void Reset();
+
+ /**
+ * Executes a single macro instruction located at the current program counter. Returns whether
+ * the interpreter should keep running.
+ * @param code The macro code to execute.
+ * @param is_delay_slot Whether the current step is being executed due to a delay slot in a
+ * previous instruction.
+ */
+ bool Step(const std::vector<u32>& code, bool is_delay_slot);
+
+ /// Calculates the result of an ALU operation. src_a OP src_b;
+ u32 GetALUResult(ALUOperation operation, u32 src_a, u32 src_b) const;
+
+ /// Performs the result operation on the input result and stores it in the specified register
+ /// (if necessary).
+ void ProcessResult(ResultOperation operation, u32 reg, u32 result);
+
+ /// Evaluates the branch condition and returns whether the branch should be taken or not.
+ bool EvaluateBranchCondition(BranchCondition cond, u32 value) const;
+
+ /// Reads an opcode at the current program counter location.
+ Opcode GetOpcode(const std::vector<u32>& code) const;
+
+ /// Returns the specified register's value. Register 0 is hardcoded to always return 0.
+ u32 GetRegister(u32 register_id) const;
+
+ /// Sets the register to the input value.
+ void SetRegister(u32 register_id, u32 value);
+
+ /// Sets the method address to use for the next Send instruction.
+ void SetMethodAddress(u32 address);
+
+ /// Calls a GPU Engine method with the input parameter.
+ void Send(u32 value);
+
+ /// Reads a GPU register located at the method address.
+ u32 Read(u32 method) const;
+
+ /// Returns the next parameter in the parameter queue.
+ u32 FetchParameter();
+
+ Engines::Maxwell3D& maxwell3d;
+
+ u32 pc; ///< Current program counter
+ boost::optional<u32>
+ delayed_pc; ///< Program counter to execute at after the delay slot is executed.
+
+ static constexpr size_t NumMacroRegisters = 8;
+
+ /// General purpose macro registers.
+ std::array<u32, NumMacroRegisters> registers = {};
+
+ /// Method address to use for the next Send instruction.
+ MethodAddress method_address = {};
+
+ /// Input parameters of the current macro.
+ std::vector<u32> parameters;
+ /// Index of the next parameter that will be fetched by the 'parm' instruction.
+ u32 next_parameter_index = 0;
+};
+} // namespace Tegra
diff --git a/src/yuzu/about_dialog.cpp b/src/yuzu/about_dialog.cpp
index da3429822..d6647eeea 100644
--- a/src/yuzu/about_dialog.cpp
+++ b/src/yuzu/about_dialog.cpp
@@ -2,12 +2,14 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <QIcon>
#include "common/scm_rev.h"
#include "ui_aboutdialog.h"
#include "yuzu/about_dialog.h"
AboutDialog::AboutDialog(QWidget* parent) : QDialog(parent), ui(new Ui::AboutDialog) {
ui->setupUi(this);
+ ui->labelLogo->setPixmap(QIcon::fromTheme("yuzu").pixmap(200));
ui->labelBuildInfo->setText(ui->labelBuildInfo->text().arg(
Common::g_build_name, Common::g_scm_branch, Common::g_scm_desc));
}
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 71dc58e5d..8843f2078 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -77,8 +77,7 @@ void Config::ReadValues() {
qt_config->endGroup();
qt_config->beginGroup("Core");
- Settings::values.cpu_core =
- static_cast<Settings::CpuCore>(qt_config->value("cpu_core", 1).toInt());
+ Settings::values.use_cpu_jit = qt_config->value("use_cpu_jit", true).toBool();
qt_config->endGroup();
qt_config->beginGroup("Renderer");
@@ -94,6 +93,10 @@ void Config::ReadValues() {
Settings::values.use_virtual_sd = qt_config->value("use_virtual_sd", true).toBool();
qt_config->endGroup();
+ qt_config->beginGroup("System");
+ Settings::values.use_docked_mode = qt_config->value("use_docked_mode", true).toBool();
+ qt_config->endGroup();
+
qt_config->beginGroup("Miscellaneous");
Settings::values.log_filter = qt_config->value("log_filter", "*:Info").toString().toStdString();
qt_config->endGroup();
@@ -104,6 +107,8 @@ void Config::ReadValues() {
qt_config->endGroup();
qt_config->beginGroup("UI");
+ UISettings::values.theme = qt_config->value("theme", UISettings::themes[0].second).toString();
+
qt_config->beginGroup("UILayout");
UISettings::values.geometry = qt_config->value("geometry").toByteArray();
UISettings::values.state = qt_config->value("state").toByteArray();
@@ -171,7 +176,7 @@ void Config::SaveValues() {
qt_config->endGroup();
qt_config->beginGroup("Core");
- qt_config->setValue("cpu_core", static_cast<int>(Settings::values.cpu_core));
+ qt_config->setValue("use_cpu_jit", Settings::values.use_cpu_jit);
qt_config->endGroup();
qt_config->beginGroup("Renderer");
@@ -188,6 +193,10 @@ void Config::SaveValues() {
qt_config->setValue("use_virtual_sd", Settings::values.use_virtual_sd);
qt_config->endGroup();
+ qt_config->beginGroup("System");
+ qt_config->setValue("use_docked_mode", Settings::values.use_docked_mode);
+ qt_config->endGroup();
+
qt_config->beginGroup("Miscellaneous");
qt_config->setValue("log_filter", QString::fromStdString(Settings::values.log_filter));
qt_config->endGroup();
diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp
index 92fd6ab02..2d73fc5aa 100644
--- a/src/yuzu/configuration/configure_general.cpp
+++ b/src/yuzu/configuration/configure_general.cpp
@@ -13,9 +13,14 @@ ConfigureGeneral::ConfigureGeneral(QWidget* parent)
ui->setupUi(this);
+ for (auto theme : UISettings::themes) {
+ ui->theme_combobox->addItem(theme.first, theme.second);
+ }
+
this->setConfiguration();
- ui->cpu_core_combobox->setEnabled(!Core::System::GetInstance().IsPoweredOn());
+ ui->use_cpu_jit->setEnabled(!Core::System::GetInstance().IsPoweredOn());
+ ui->use_docked_mode->setEnabled(!Core::System::GetInstance().IsPoweredOn());
}
ConfigureGeneral::~ConfigureGeneral() {}
@@ -23,13 +28,18 @@ ConfigureGeneral::~ConfigureGeneral() {}
void ConfigureGeneral::setConfiguration() {
ui->toggle_deepscan->setChecked(UISettings::values.gamedir_deepscan);
ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing);
- ui->cpu_core_combobox->setCurrentIndex(static_cast<int>(Settings::values.cpu_core));
+ ui->theme_combobox->setCurrentIndex(ui->theme_combobox->findData(UISettings::values.theme));
+ ui->use_cpu_jit->setChecked(Settings::values.use_cpu_jit);
+ ui->use_docked_mode->setChecked(Settings::values.use_docked_mode);
}
void ConfigureGeneral::applyConfiguration() {
UISettings::values.gamedir_deepscan = ui->toggle_deepscan->isChecked();
UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked();
- Settings::values.cpu_core =
- static_cast<Settings::CpuCore>(ui->cpu_core_combobox->currentIndex());
+ UISettings::values.theme =
+ ui->theme_combobox->itemData(ui->theme_combobox->currentIndex()).toString();
+
+ Settings::values.use_cpu_jit = ui->use_cpu_jit->isChecked();
+ Settings::values.use_docked_mode = ui->use_docked_mode->isChecked();
Settings::Apply();
}
diff --git a/src/yuzu/configuration/configure_general.ui b/src/yuzu/configuration/configure_general.ui
index 573c4cb0e..1775c4d40 100644
--- a/src/yuzu/configuration/configure_general.ui
+++ b/src/yuzu/configuration/configure_general.ui
@@ -13,17 +13,17 @@
<property name="windowTitle">
<string>Form</string>
</property>
- <layout class="QHBoxLayout" name="horizontalLayout">
+ <layout class="QHBoxLayout" name="HorizontalLayout">
<item>
- <layout class="QVBoxLayout" name="verticalLayout">
+ <layout class="QVBoxLayout" name="VerticalLayout">
<item>
- <widget class="QGroupBox" name="groupBox">
+ <widget class="QGroupBox" name="GeneralGroupBox">
<property name="title">
<string>General</string>
</property>
- <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <layout class="QHBoxLayout" name="GeneralHorizontalLayout">
<item>
- <layout class="QVBoxLayout" name="verticalLayout_2">
+ <layout class="QVBoxLayout" name="GeneralVerticalLayout">
<item>
<widget class="QCheckBox" name="toggle_deepscan">
<property name="text">
@@ -44,40 +44,80 @@
</widget>
</item>
<item>
- <widget class="QGroupBox" name="groupBox_2">
- <property name="title">
- <string>CPU Core</string>
- </property>
- <layout class="QHBoxLayout" name="horizontalLayout_7">
- <item>
- <layout class="QVBoxLayout" name="verticalLayout_5">
- <item>
- <widget class="QComboBox" name="cpu_core_combobox">
- <item>
- <property name="text">
- <string>Unicorn</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>Dynarmic</string>
- </property>
- </item>
- </widget>
- </item>
- </layout>
- </item>
+ <widget class="QGroupBox" name="PerformanceGroupBox">
+ <property name="title">
+ <string>Performance</string>
+ </property>
+ <layout class="QHBoxLayout" name="PerformanceHorizontalLayout">
+ <item>
+ <layout class="QVBoxLayout" name="PerformanceVerticalLayout">
+ <item>
+ <widget class="QCheckBox" name="use_cpu_jit">
+ <property name="text">
+ <string>Enable CPU JIT</string>
+ </property>
+ </widget>
+ </item>
</layout>
- </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="EmulationGroupBox">
+ <property name="title">
+ <string>Emulation</string>
+ </property>
+ <layout class="QHBoxLayout" name="EmulationHorizontalLayout">
+ <item>
+ <layout class="QVBoxLayout" name="EmulationVerticalLayout">
+ <item>
+ <widget class="QCheckBox" name="use_docked_mode">
+ <property name="text">
+ <string>Enable docked mode</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="theme_group_box">
+ <property name="title">
+ <string>Theme</string>
+ </property>
+ <layout class="QHBoxLayout" name="theme_qhbox_layout">
+ <item>
+ <layout class="QVBoxLayout" name="theme_qvbox_layout">
+ <item>
+ <layout class="QHBoxLayout" name="theme_qhbox_layout_2">
+ <item>
+ <widget class="QLabel" name="theme_label">
+ <property name="text">
+ <string>Theme:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="theme_combobox"/>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
</item>
<item>
- <widget class="QGroupBox" name="groupBox_3">
+ <widget class="QGroupBox" name="HotKeysGroupBox">
<property name="title">
<string>Hotkeys</string>
</property>
- <layout class="QHBoxLayout" name="horizontalLayout_4">
+ <layout class="QHBoxLayout" name="HotKeysHorizontalLayout">
<item>
- <layout class="QVBoxLayout" name="verticalLayout_4">
+ <layout class="QVBoxLayout" name="HotKeysVerticalLayout">
<item>
<widget class="GHotkeysDialog" name="widget" native="true"/>
</item>
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index bd323870b..265502c2a 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -78,6 +78,9 @@ GMainWindow::GMainWindow() : config(new Config()), emu_thread(nullptr) {
ui.setupUi(this);
statusBar()->hide();
+ default_theme_paths = QIcon::themeSearchPaths();
+ UpdateUITheme();
+
InitializeWidgets();
InitializeDebugWidgets();
InitializeRecentFileMenuActions();
@@ -653,6 +656,7 @@ void GMainWindow::OnConfigure() {
auto result = configureDialog.exec();
if (result == QDialog::Accepted) {
configureDialog.applyConfiguration();
+ UpdateUITheme();
config->Save();
}
}
@@ -833,6 +837,32 @@ void GMainWindow::filterBarSetChecked(bool state) {
emit(OnToggleFilterBar());
}
+void GMainWindow::UpdateUITheme() {
+ QStringList theme_paths(default_theme_paths);
+ if (UISettings::values.theme != UISettings::themes[0].second &&
+ !UISettings::values.theme.isEmpty()) {
+ QString theme_uri(":" + UISettings::values.theme + "/style.qss");
+ QFile f(theme_uri);
+ if (!f.exists()) {
+ LOG_ERROR(Frontend, "Unable to set style, stylesheet file not found");
+ } else {
+ f.open(QFile::ReadOnly | QFile::Text);
+ QTextStream ts(&f);
+ qApp->setStyleSheet(ts.readAll());
+ GMainWindow::setStyleSheet(ts.readAll());
+ }
+ theme_paths.append(QStringList{":/icons/default", ":/icons/" + UISettings::values.theme});
+ QIcon::setThemeName(":/icons/" + UISettings::values.theme);
+ } else {
+ qApp->setStyleSheet("");
+ GMainWindow::setStyleSheet("");
+ theme_paths.append(QStringList{":/icons/default"});
+ QIcon::setThemeName(":/icons/default");
+ }
+ QIcon::setThemeSearchPaths(theme_paths);
+ emit UpdateThemedIcons();
+}
+
#ifdef main
#undef main
#endif
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 2471caf83..20ff65314 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -2,8 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#ifndef _CITRA_QT_MAIN_HXX_
-#define _CITRA_QT_MAIN_HXX_
+#pragma once
#include <memory>
#include <QMainWindow>
@@ -65,6 +64,9 @@ signals:
*/
void EmulationStopping();
+ // Signal that tells widgets to update icons to use the current theme
+ void UpdateThemedIcons();
+
private:
void InitializeWidgets();
void InitializeDebugWidgets();
@@ -153,7 +155,7 @@ private:
std::unique_ptr<Config> config;
- // Whether emulation is currently running in Citra.
+ // Whether emulation is currently running in yuzu.
bool emulation_running = false;
std::unique_ptr<EmuThread> emu_thread;
@@ -167,10 +169,11 @@ private:
QAction* actions_recent_files[max_recent_files_item];
+ // stores default icon theme search paths for the platform
+ QStringList default_theme_paths;
+
protected:
void dropEvent(QDropEvent* event) override;
void dragEnterEvent(QDragEnterEvent* event) override;
void dragMoveEvent(QDragMoveEvent* event) override;
};
-
-#endif // _CITRA_QT_MAIN_HXX_
diff --git a/src/yuzu/ui_settings.h b/src/yuzu/ui_settings.h
index 9036ce2c1..8e215a002 100644
--- a/src/yuzu/ui_settings.h
+++ b/src/yuzu/ui_settings.h
@@ -15,6 +15,10 @@ namespace UISettings {
using ContextualShortcut = std::pair<QString, int>;
using Shortcut = std::pair<QString, ContextualShortcut>;
+static const std::array<std::pair<QString, QString>, 2> themes = {
+ {std::make_pair(QString("Default"), QString("default")),
+ std::make_pair(QString("Dark"), QString("qdarkstyle"))}};
+
struct Values {
QByteArray geometry;
QByteArray state;
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp
index 342ad3850..8b479bc6d 100644
--- a/src/yuzu_cmd/config.cpp
+++ b/src/yuzu_cmd/config.cpp
@@ -90,8 +90,7 @@ void Config::ReadValues() {
sdl2_config->Get("Controls", "touch_device", "engine:emu_window");
// Core
- Settings::values.cpu_core =
- static_cast<Settings::CpuCore>(sdl2_config->GetInteger("Core", "cpu_core", 1));
+ Settings::values.use_cpu_jit = sdl2_config->GetBoolean("Core", "use_cpu_jit", true);
// Renderer
Settings::values.resolution_factor =
@@ -107,6 +106,9 @@ void Config::ReadValues() {
Settings::values.use_virtual_sd =
sdl2_config->GetBoolean("Data Storage", "use_virtual_sd", true);
+ // System
+ Settings::values.use_docked_mode = sdl2_config->GetBoolean("System", "use_docked_mode", true);
+
// Miscellaneous
Settings::values.log_filter = sdl2_config->Get("Miscellaneous", "log_filter", "*:Trace");
diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h
index a0b199f95..895a42c39 100644
--- a/src/yuzu_cmd/default_ini.h
+++ b/src/yuzu_cmd/default_ini.h
@@ -76,9 +76,9 @@ motion_device=
touch_device=
[Core]
-# Which CPU core to use for CPU emulation
-# 0: Unicorn (slow), 1 (default): Dynarmic (faster)
-cpu_core =
+# Whether to use the Just-In-Time (JIT) compiler for CPU emulation
+# 0: Interpreter (slow), 1 (default): JIT (fast)
+use_cpu_jit =
[Renderer]
# Whether to use software or hardware rendering.
@@ -154,6 +154,10 @@ output_device =
use_virtual_sd =
[System]
+# Whether the system is docked
+# 1 (default): Yes, 0: No
+use_docked_mode =
+
# The system region that Citra will use during emulation
# -1: Auto-select (default), 0: Japan, 1: USA, 2: Europe, 3: Australia, 4: China, 5: Korea, 6: Taiwan
region_value =