From ceb829cc332a3903e81dd5d32f2c953f25210fc2 Mon Sep 17 00:00:00 2001 From: Liam Date: Thu, 10 Nov 2022 17:05:47 -0500 Subject: debugger: allow more than one connection attempt per session --- src/core/debugger/debugger.cpp | 161 ++++++++++++++++++++++++----------------- 1 file changed, 93 insertions(+), 68 deletions(-) diff --git a/src/core/debugger/debugger.cpp b/src/core/debugger/debugger.cpp index 339f971e6..1a8e02e6a 100644 --- a/src/core/debugger/debugger.cpp +++ b/src/core/debugger/debugger.cpp @@ -27,12 +27,21 @@ static void AsyncReceiveInto(Readable& r, Buffer& buffer, Callback&& c) { const u8* buffer_start = reinterpret_cast(&buffer); std::span received_data{buffer_start, buffer_start + bytes_read}; c(received_data); + AsyncReceiveInto(r, buffer, c); } - - AsyncReceiveInto(r, buffer, c); }); } +template +static void AsyncAccept(boost::asio::ip::tcp::acceptor& acceptor, Callback&& c) { + acceptor.async_accept([&, c](const boost::system::error_code& error, auto&& peer_socket) { + if (!error.failed()) { + c(peer_socket); + AsyncAccept(acceptor, c); + } + }); +} + template static std::span ReceiveInto(Readable& r, Buffer& buffer) { static_assert(std::is_trivial_v); @@ -59,9 +68,7 @@ namespace Core { class DebuggerImpl : public DebuggerBackend { public: - explicit DebuggerImpl(Core::System& system_, u16 port) - : system{system_}, signal_pipe{io_context}, client_socket{io_context} { - frontend = std::make_unique(*this, system); + explicit DebuggerImpl(Core::System& system_, u16 port) : system{system_} { InitializeServer(port); } @@ -70,39 +77,42 @@ public: } bool SignalDebugger(SignalInfo signal_info) { - { - std::scoped_lock lk{connection_lock}; + std::scoped_lock lk{connection_lock}; - if (stopped) { - // Do not notify the debugger about another event. - // It should be ignored. - return false; - } - - // Set up the state. - stopped = true; - info = signal_info; + if (stopped || !state) { + // Do not notify the debugger about another event. + // It should be ignored. + return false; } + // Set up the state. + stopped = true; + state->info = signal_info; + // Write a single byte into the pipe to wake up the debug interface. - boost::asio::write(signal_pipe, boost::asio::buffer(&stopped, sizeof(stopped))); + boost::asio::write(state->signal_pipe, boost::asio::buffer(&stopped, sizeof(stopped))); + return true; } + // These functions are callbacks from the frontend, and the lock will be held. + // There is no need to relock it. + std::span ReadFromClient() override { - return ReceiveInto(client_socket, client_data); + return ReceiveInto(state->client_socket, state->client_data); } void WriteToClient(std::span data) override { - boost::asio::write(client_socket, boost::asio::buffer(data.data(), data.size_bytes())); + boost::asio::write(state->client_socket, + boost::asio::buffer(data.data(), data.size_bytes())); } void SetActiveThread(Kernel::KThread* thread) override { - active_thread = thread; + state->active_thread = thread; } Kernel::KThread* GetActiveThread() override { - return active_thread; + return state->active_thread; } private: @@ -113,65 +123,78 @@ private: // Run the connection thread. connection_thread = std::jthread([&, port](std::stop_token stop_token) { + Common::SetCurrentThreadName("Debugger"); + try { // Initialize the listening socket and accept a new client. tcp::endpoint endpoint{boost::asio::ip::address_v4::any(), port}; tcp::acceptor acceptor{io_context, endpoint}; - acceptor.async_accept(client_socket, [](const auto&) {}); - io_context.run_one(); - io_context.restart(); + AsyncAccept(acceptor, [&](auto&& peer) { AcceptConnection(std::move(peer)); }); - if (stop_token.stop_requested()) { - return; + while (!stop_token.stop_requested() && io_context.run()) { } - - ThreadLoop(stop_token); } catch (const std::exception& ex) { LOG_CRITICAL(Debug_GDBStub, "Stopping server: {}", ex.what()); } }); } - void ShutdownServer() { - connection_thread.request_stop(); - io_context.stop(); - connection_thread.join(); - } + void AcceptConnection(boost::asio::ip::tcp::socket&& peer) { + LOG_INFO(Debug_GDBStub, "Accepting new peer connection"); - void ThreadLoop(std::stop_token stop_token) { - Common::SetCurrentThreadName("Debugger"); + std::scoped_lock lk{connection_lock}; + + // Ensure everything is stopped. + PauseEmulation(); + + // Set up the new frontend. + frontend = std::make_unique(*this, system); + + // Set the new state. This will tear down any existing state. + state = ConnectionState{ + .client_socket{std::move(peer)}, + .signal_pipe{io_context}, + .info{}, + .active_thread{}, + .client_data{}, + .pipe_data{}, + }; // Set up the client signals for new data. - AsyncReceiveInto(signal_pipe, pipe_data, [&](auto d) { PipeData(d); }); - AsyncReceiveInto(client_socket, client_data, [&](auto d) { ClientData(d); }); + AsyncReceiveInto(state->signal_pipe, state->pipe_data, [&](auto d) { PipeData(d); }); + AsyncReceiveInto(state->client_socket, state->client_data, [&](auto d) { ClientData(d); }); // Set the active thread. UpdateActiveThread(); // Set up the frontend. frontend->Connected(); + } - // Main event loop. - while (!stop_token.stop_requested() && io_context.run()) { - } + void ShutdownServer() { + connection_thread.request_stop(); + io_context.stop(); + connection_thread.join(); } void PipeData(std::span data) { - switch (info.type) { + std::scoped_lock lk{connection_lock}; + + switch (state->info.type) { case SignalType::Stopped: case SignalType::Watchpoint: // Stop emulation. PauseEmulation(); // Notify the client. - active_thread = info.thread; + state->active_thread = state->info.thread; UpdateActiveThread(); - if (info.type == SignalType::Watchpoint) { - frontend->Watchpoint(active_thread, *info.watchpoint); + if (state->info.type == SignalType::Watchpoint) { + frontend->Watchpoint(state->active_thread, *state->info.watchpoint); } else { - frontend->Stopped(active_thread); + frontend->Stopped(state->active_thread); } break; @@ -179,8 +202,8 @@ private: frontend->ShuttingDown(); // Wait for emulation to shut down gracefully now. - signal_pipe.close(); - client_socket.shutdown(boost::asio::socket_base::shutdown_both); + state->signal_pipe.close(); + state->client_socket.shutdown(boost::asio::socket_base::shutdown_both); LOG_INFO(Debug_GDBStub, "Shut down server"); break; @@ -188,17 +211,16 @@ private: } void ClientData(std::span data) { + std::scoped_lock lk{connection_lock}; + const auto actions{frontend->ClientData(data)}; for (const auto action : actions) { switch (action) { case DebuggerAction::Interrupt: { - { - std::scoped_lock lk{connection_lock}; - stopped = true; - } + stopped = true; PauseEmulation(); UpdateActiveThread(); - frontend->Stopped(active_thread); + frontend->Stopped(state->active_thread); break; } case DebuggerAction::Continue: @@ -206,15 +228,15 @@ private: break; case DebuggerAction::StepThreadUnlocked: MarkResumed([&] { - active_thread->SetStepState(Kernel::StepState::StepPending); - active_thread->Resume(Kernel::SuspendType::Debug); - ResumeEmulation(active_thread); + state->active_thread->SetStepState(Kernel::StepState::StepPending); + state->active_thread->Resume(Kernel::SuspendType::Debug); + ResumeEmulation(state->active_thread); }); break; case DebuggerAction::StepThreadLocked: { MarkResumed([&] { - active_thread->SetStepState(Kernel::StepState::StepPending); - active_thread->Resume(Kernel::SuspendType::Debug); + state->active_thread->SetStepState(Kernel::StepState::StepPending); + state->active_thread->Resume(Kernel::SuspendType::Debug); }); break; } @@ -254,15 +276,14 @@ private: template void MarkResumed(Callback&& cb) { Kernel::KScopedSchedulerLock sl{system.Kernel()}; - std::scoped_lock cl{connection_lock}; stopped = false; cb(); } void UpdateActiveThread() { const auto& threads{ThreadList()}; - if (std::find(threads.begin(), threads.end(), active_thread) == threads.end()) { - active_thread = threads[0]; + if (std::find(threads.begin(), threads.end(), state->active_thread) == threads.end()) { + state->active_thread = threads[0]; } } @@ -274,18 +295,22 @@ private: System& system; std::unique_ptr frontend; + boost::asio::io_context io_context; std::jthread connection_thread; std::mutex connection_lock; - boost::asio::io_context io_context; - boost::process::async_pipe signal_pipe; - boost::asio::ip::tcp::socket client_socket; - SignalInfo info; - Kernel::KThread* active_thread; - bool pipe_data; - bool stopped; + struct ConnectionState { + boost::asio::ip::tcp::socket client_socket; + boost::process::async_pipe signal_pipe; + + SignalInfo info; + Kernel::KThread* active_thread; + std::array client_data; + bool pipe_data; + }; - std::array client_data; + std::optional state{}; + bool stopped{}; }; Debugger::Debugger(Core::System& system, u16 port) { -- cgit v1.2.3 From 18123ff958b0a4d877dab45a54637245c3b296ba Mon Sep 17 00:00:00 2001 From: Liam Date: Thu, 10 Nov 2022 19:17:54 -0500 Subject: gdbstub: add ams monitor commands --- src/core/debugger/gdbstub.cpp | 151 +++++++++++++++++++++++++++++++++++++ src/core/debugger/gdbstub.h | 1 + src/core/hle/kernel/k_page_table.h | 3 + 3 files changed, 155 insertions(+) diff --git a/src/core/debugger/gdbstub.cpp b/src/core/debugger/gdbstub.cpp index 884229c77..a64a9ac64 100644 --- a/src/core/debugger/gdbstub.cpp +++ b/src/core/debugger/gdbstub.cpp @@ -606,6 +606,8 @@ void GDBStub::HandleQuery(std::string_view command) { } else if (command.starts_with("StartNoAckMode")) { no_ack = true; SendReply(GDB_STUB_REPLY_OK); + } else if (command.starts_with("Rcmd,")) { + HandleRcmd(Common::HexStringToVector(command.substr(5), false)); } else { SendReply(GDB_STUB_REPLY_EMPTY); } @@ -645,6 +647,155 @@ void GDBStub::HandleVCont(std::string_view command, std::vector& } } +constexpr std::array, 22> MemoryStateNames{{ + {"----- Free -----", Kernel::Svc::MemoryState::Free}, + {"Io ", Kernel::Svc::MemoryState::Io}, + {"Static ", Kernel::Svc::MemoryState::Static}, + {"Code ", Kernel::Svc::MemoryState::Code}, + {"CodeData ", Kernel::Svc::MemoryState::CodeData}, + {"Normal ", Kernel::Svc::MemoryState::Normal}, + {"Shared ", Kernel::Svc::MemoryState::Shared}, + {"AliasCode ", Kernel::Svc::MemoryState::AliasCode}, + {"AliasCodeData ", Kernel::Svc::MemoryState::AliasCodeData}, + {"Ipc ", Kernel::Svc::MemoryState::Ipc}, + {"Stack ", Kernel::Svc::MemoryState::Stack}, + {"ThreadLocal ", Kernel::Svc::MemoryState::ThreadLocal}, + {"Transfered ", Kernel::Svc::MemoryState::Transfered}, + {"SharedTransfered", Kernel::Svc::MemoryState::SharedTransfered}, + {"SharedCode ", Kernel::Svc::MemoryState::SharedCode}, + {"Inaccessible ", Kernel::Svc::MemoryState::Inaccessible}, + {"NonSecureIpc ", Kernel::Svc::MemoryState::NonSecureIpc}, + {"NonDeviceIpc ", Kernel::Svc::MemoryState::NonDeviceIpc}, + {"Kernel ", Kernel::Svc::MemoryState::Kernel}, + {"GeneratedCode ", Kernel::Svc::MemoryState::GeneratedCode}, + {"CodeOut ", Kernel::Svc::MemoryState::CodeOut}, + {"Coverage ", Kernel::Svc::MemoryState::Coverage}, +}}; + +static constexpr const char* GetMemoryStateName(Kernel::Svc::MemoryState state) { + for (size_t i = 0; i < MemoryStateNames.size(); i++) { + if (std::get<1>(MemoryStateNames[i]) == state) { + return std::get<0>(MemoryStateNames[i]); + } + } + return "Unknown "; +} + +static constexpr const char* GetMemoryPermissionString(const Kernel::Svc::MemoryInfo& info) { + if (info.state == Kernel::Svc::MemoryState::Free) { + return " "; + } + + switch (info.permission) { + case Kernel::Svc::MemoryPermission::ReadExecute: + return "r-x"; + case Kernel::Svc::MemoryPermission::Read: + return "r--"; + case Kernel::Svc::MemoryPermission::ReadWrite: + return "rw-"; + default: + return "---"; + } +} + +static VAddr GetModuleEnd(Kernel::KPageTable& page_table, VAddr base) { + Kernel::Svc::MemoryInfo mem_info; + VAddr cur_addr{base}; + + // Expect: r-x Code (.text) + mem_info = page_table.QueryInfo(cur_addr).GetSvcMemoryInfo(); + cur_addr = mem_info.base_address + mem_info.size; + if (mem_info.state != Kernel::Svc::MemoryState::Code || + mem_info.permission != Kernel::Svc::MemoryPermission::ReadExecute) { + return cur_addr - 1; + } + + // Expect: r-- Code (.rodata) + mem_info = page_table.QueryInfo(cur_addr).GetSvcMemoryInfo(); + cur_addr = mem_info.base_address + mem_info.size; + if (mem_info.state != Kernel::Svc::MemoryState::Code || + mem_info.permission != Kernel::Svc::MemoryPermission::Read) { + return cur_addr - 1; + } + + // Expect: rw- CodeData (.data) + mem_info = page_table.QueryInfo(cur_addr).GetSvcMemoryInfo(); + cur_addr = mem_info.base_address + mem_info.size; + return cur_addr - 1; +} + +void GDBStub::HandleRcmd(const std::vector& command) { + std::string_view command_str{reinterpret_cast(&command[0]), command.size()}; + std::string reply; + + auto* process = system.CurrentProcess(); + auto& page_table = process->PageTable(); + + if (command_str == "get info") { + Loader::AppLoader::Modules modules; + system.GetAppLoader().ReadNSOModules(modules); + + reply = fmt::format("Process: {:#x} ({})\n" + "Program Id: {:#018x}\n", + process->GetProcessID(), process->GetName(), process->GetProgramID()); + reply += + fmt::format("Layout:\n" + " Alias: {:#012x} - {:#012x}\n" + " Heap: {:#012x} - {:#012x}\n" + " Aslr: {:#012x} - {:#012x}\n" + " Stack: {:#012x} - {:#012x}\n" + "Modules:\n", + page_table.GetAliasRegionStart(), page_table.GetAliasRegionEnd(), + page_table.GetHeapRegionStart(), page_table.GetHeapRegionEnd(), + page_table.GetAliasCodeRegionStart(), page_table.GetAliasCodeRegionEnd(), + page_table.GetStackRegionStart(), page_table.GetStackRegionEnd()); + + for (const auto& [vaddr, name] : modules) { + reply += fmt::format(" {:#012x} - {:#012x} {}\n", vaddr, + GetModuleEnd(page_table, vaddr), name); + } + } else if (command_str == "get mappings") { + reply = "Mappings:\n"; + VAddr cur_addr = 0; + + while (true) { + using MemoryAttribute = Kernel::Svc::MemoryAttribute; + + auto mem_info = page_table.QueryInfo(cur_addr).GetSvcMemoryInfo(); + + if (mem_info.state != Kernel::Svc::MemoryState::Inaccessible || + mem_info.base_address + mem_info.size - 1 != std::numeric_limits::max()) { + const char* state = GetMemoryStateName(mem_info.state); + const char* perm = GetMemoryPermissionString(mem_info); + + const char l = True(mem_info.attribute & MemoryAttribute::Locked) ? 'L' : '-'; + const char i = True(mem_info.attribute & MemoryAttribute::IpcLocked) ? 'I' : '-'; + const char d = True(mem_info.attribute & MemoryAttribute::DeviceShared) ? 'D' : '-'; + const char u = True(mem_info.attribute & MemoryAttribute::Uncached) ? 'U' : '-'; + + reply += + fmt::format(" {:#012x} - {:#012x} {} {} {}{}{}{} [{}, {}]\n", + mem_info.base_address, mem_info.base_address + mem_info.size - 1, + perm, state, l, i, d, u, mem_info.ipc_count, mem_info.device_count); + } + + const uintptr_t next_address = mem_info.base_address + mem_info.size; + if (next_address <= cur_addr) { + break; + } + + cur_addr = next_address; + } + } else if (command_str == "help") { + reply = "Commands:\n get info\n get mappings\n"; + } else { + reply = "Unknown command.\nCommands:\n get info\n get mappings\n"; + } + + std::span reply_span{reinterpret_cast(&reply.front()), reply.size()}; + SendReply(Common::HexToString(reply_span, false)); +} + Kernel::KThread* GDBStub::GetThreadByID(u64 thread_id) { const auto& threads{system.GlobalSchedulerContext().GetThreadList()}; for (auto* thread : threads) { diff --git a/src/core/debugger/gdbstub.h b/src/core/debugger/gdbstub.h index 0b0f56e4b..368197920 100644 --- a/src/core/debugger/gdbstub.h +++ b/src/core/debugger/gdbstub.h @@ -32,6 +32,7 @@ private: void ExecuteCommand(std::string_view packet, std::vector& actions); void HandleVCont(std::string_view command, std::vector& actions); void HandleQuery(std::string_view command); + void HandleRcmd(const std::vector& command); void HandleBreakpointInsert(std::string_view command); void HandleBreakpointRemove(std::string_view command); std::vector::const_iterator CommandEnd() const; diff --git a/src/core/hle/kernel/k_page_table.h b/src/core/hle/kernel/k_page_table.h index 950850291..f1ca785d7 100644 --- a/src/core/hle/kernel/k_page_table.h +++ b/src/core/hle/kernel/k_page_table.h @@ -320,6 +320,9 @@ public: constexpr VAddr GetAliasCodeRegionStart() const { return m_alias_code_region_start; } + constexpr VAddr GetAliasCodeRegionEnd() const { + return m_alias_code_region_end; + } constexpr VAddr GetAliasCodeRegionSize() const { return m_alias_code_region_end - m_alias_code_region_start; } -- cgit v1.2.3 From b832942b6eb22e46d80058f8a478d039e5190d5d Mon Sep 17 00:00:00 2001 From: Enrico Mancuso <55850895+HidroSaphire@users.noreply.github.com> Date: Fri, 11 Nov 2022 10:16:58 +0100 Subject: Add break statement in default case According to the contributing page (https://github.com/yuzu-emu/yuzu/wiki/Contributing) the default cases should have a break statement --- src/yuzu_cmd/yuzu.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index e16f79eb4..dfe5a30ea 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp @@ -351,6 +351,7 @@ int main(int argc, char** argv) { "additional help.\n\nError Code: {:04X}-{:04X}\nError Description: {}", loader_id, error_id, static_cast(error_id)); } + break; } system.TelemetrySession().AddField(Common::Telemetry::FieldType::App, "Frontend", "SDL"); -- cgit v1.2.3 From 70ea1c20002e8cb9a0f9e98b1992d4c731be0041 Mon Sep 17 00:00:00 2001 From: Liam Date: Sat, 12 Nov 2022 11:26:56 -0500 Subject: common: add cache management functions --- src/common/CMakeLists.txt | 2 ++ src/common/cache_management.cpp | 60 +++++++++++++++++++++++++++++++++++++++++ src/common/cache_management.h | 27 +++++++++++++++++++ 3 files changed, 89 insertions(+) create mode 100644 src/common/cache_management.cpp create mode 100644 src/common/cache_management.h diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index c0555f840..b7c15c191 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -34,6 +34,8 @@ add_library(common STATIC bit_util.h cityhash.cpp cityhash.h + cache_management.cpp + cache_management.h common_funcs.h common_types.h concepts.h diff --git a/src/common/cache_management.cpp b/src/common/cache_management.cpp new file mode 100644 index 000000000..57810b76a --- /dev/null +++ b/src/common/cache_management.cpp @@ -0,0 +1,60 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include + +#include "alignment.h" +#include "cache_management.h" +#include "common_types.h" + +namespace Common { + +#if defined(ARCHITECTURE_x86_64) + +// Most cache operations are no-ops on x86 + +void DataCacheLineCleanByVAToPoU(void* start, size_t size) {} +void DataCacheLineCleanAndInvalidateByVAToPoC(void* start, size_t size) {} +void DataCacheLineCleanByVAToPoC(void* start, size_t size) {} +void DataCacheZeroByVA(void* start, size_t size) { + std::memset(start, 0, size); +} + +#elif defined(ARCHITECTURE_arm64) + +// BS/DminLine is log2(cache size in words), we want size in bytes +#define EXTRACT_DMINLINE(ctr_el0) (1 << ((((ctr_el0) >> 16) & 0xf) + 2)) +#define EXTRACT_BS(dczid_el0) (1 << (((dczid_el0)&0xf) + 2)) + +#define DEFINE_DC_OP(op_name, function_name) \ + void function_name(void* start, size_t size) { \ + size_t ctr_el0; \ + asm volatile("mrs %[ctr_el0], ctr_el0\n\t" : [ctr_el0] "=r"(ctr_el0)); \ + size_t cacheline_size = EXTRACT_DMINLINE(ctr_el0); \ + uintptr_t va_start = reinterpret_cast(start); \ + uintptr_t va_end = va_start + size; \ + for (uintptr_t va = va_start; va < va_end; va += cacheline_size) { \ + asm volatile("dc " #op_name ", %[va]\n\t" : : [va] "r"(va) : "memory"); \ + } \ + } + +#define DEFINE_DC_OP_DCZID(op_name, function_name) \ + void function_name(void* start, size_t size) { \ + size_t dczid_el0; \ + asm volatile("mrs %[dczid_el0], dczid_el0\n\t" : [dczid_el0] "=r"(dczid_el0)); \ + size_t cacheline_size = EXTRACT_BS(dczid_el0); \ + uintptr_t va_start = reinterpret_cast(start); \ + uintptr_t va_end = va_start + size; \ + for (uintptr_t va = va_start; va < va_end; va += cacheline_size) { \ + asm volatile("dc " #op_name ", %[va]\n\t" : : [va] "r"(va) : "memory"); \ + } \ + } + +DEFINE_DC_OP(cvau, DataCacheLineCleanByVAToPoU); +DEFINE_DC_OP(civac, DataCacheLineCleanAndInvalidateByVAToPoC); +DEFINE_DC_OP(cvac, DataCacheLineCleanByVAToPoC); +DEFINE_DC_OP_DCZID(zva, DataCacheZeroByVA); + +#endif + +} // namespace Common diff --git a/src/common/cache_management.h b/src/common/cache_management.h new file mode 100644 index 000000000..e467b87e4 --- /dev/null +++ b/src/common/cache_management.h @@ -0,0 +1,27 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "stdlib.h" + +namespace Common { + +// Data cache instructions enabled at EL0 by SCTLR_EL1.UCI. +// VA = virtual address +// PoC = point of coherency +// PoU = point of unification + +// dc cvau +void DataCacheLineCleanByVAToPoU(void* start, size_t size); + +// dc civac +void DataCacheLineCleanAndInvalidateByVAToPoC(void* start, size_t size); + +// dc cvac +void DataCacheLineCleanByVAToPoC(void* start, size_t size); + +// dc zva +void DataCacheZeroByVA(void* start, size_t size); + +} // namespace Common -- cgit v1.2.3 From 651f6598ac8a980700c330f382d711f7429571a8 Mon Sep 17 00:00:00 2001 From: Liam Date: Sat, 12 Nov 2022 11:02:07 -0500 Subject: kernel: implement FlushProcessDataCache --- src/core/hle/kernel/svc.cpp | 26 +++++++++++------ src/core/hle/kernel/svc_wrap.h | 8 ++++++ src/core/memory.cpp | 65 ++++++++++++++++++++++++++++++++++++++++++ src/core/memory.h | 34 ++++++++++++++++++++++ 4 files changed, 125 insertions(+), 8 deletions(-) diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 9962ad171..e520cab47 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -2701,14 +2701,24 @@ static Result GetThreadList(Core::System& system, u32* out_num_threads, VAddr ou return ResultSuccess; } -static Result FlushProcessDataCache32([[maybe_unused]] Core::System& system, - [[maybe_unused]] Handle handle, [[maybe_unused]] u32 address, - [[maybe_unused]] u32 size) { - // Note(Blinkhawk): For emulation purposes of the data cache this is mostly a no-op, - // as all emulation is done in the same cache level in host architecture, thus data cache - // does not need flushing. - LOG_DEBUG(Kernel_SVC, "called"); - return ResultSuccess; +static Result FlushProcessDataCache32(Core::System& system, Handle process_handle, u64 address, + u64 size) { + // Validate address/size. + R_UNLESS(size > 0, ResultInvalidSize); + R_UNLESS(address == static_cast(address), ResultInvalidCurrentMemory); + R_UNLESS(size == static_cast(size), ResultInvalidCurrentMemory); + + // Get the process from its handle. + KScopedAutoObject process = + system.Kernel().CurrentProcess()->GetHandleTable().GetObject(process_handle); + R_UNLESS(process.IsNotNull(), ResultInvalidHandle); + + // Verify the region is within range. + auto& page_table = process->PageTable(); + R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory); + + // Perform the operation. + R_RETURN(system.Memory().FlushDataCache(*process, address, size)); } namespace { diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index 272c54cf7..3730937fe 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h @@ -722,4 +722,12 @@ void SvcWrap32(Core::System& system) { FuncReturn(system, retval); } +// Used by Invalidate/Store/FlushProcessDataCache32 +template +void SvcWrap32(Core::System& system) { + const u64 address = (Param(system, 3) << 32) | Param(system, 2); + const u64 size = (Param(system, 4) << 32) | Param(system, 1); + FuncReturn32(system, func(system, Param32(system, 0), address, size).raw); +} + } // namespace Kernel diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 3ca80c8ff..3141122f1 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -6,6 +6,7 @@ #include "common/assert.h" #include "common/atomic_ops.h" +#include "common/cache_management.h" #include "common/common_types.h" #include "common/logging/log.h" #include "common/page_table.h" @@ -329,6 +330,55 @@ struct Memory::Impl { }); } + template + Result PerformCacheOperation(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size, + Callback&& cb) { + class InvalidMemoryException : public std::exception {}; + + try { + WalkBlock( + process, dest_addr, size, + [&](const std::size_t block_size, const VAddr current_vaddr) { + LOG_ERROR(HW_Memory, "Unmapped cache maintenance @ {:#018X}", current_vaddr); + throw InvalidMemoryException(); + }, + [&](const std::size_t block_size, u8* const host_ptr) { cb(block_size, host_ptr); }, + [&](const VAddr current_vaddr, const std::size_t block_size, u8* const host_ptr) { + system.GPU().FlushRegion(current_vaddr, block_size); + cb(block_size, host_ptr); + }, + [](const std::size_t block_size) {}); + } catch (InvalidMemoryException&) { + return Kernel::ResultInvalidCurrentMemory; + } + + return ResultSuccess; + } + + Result InvalidateDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size) { + auto perform = [&](const std::size_t block_size, u8* const host_ptr) { + // Do nothing; this operation (dc ivac) cannot be supported + // from EL0 + }; + return PerformCacheOperation(process, dest_addr, size, perform); + } + + Result StoreDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size) { + auto perform = [&](const std::size_t block_size, u8* const host_ptr) { + // dc cvac: Store to point of coherency + Common::DataCacheLineCleanByVAToPoC(host_ptr, block_size); + }; + return PerformCacheOperation(process, dest_addr, size, perform); + } + + Result FlushDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size) { + auto perform = [&](const std::size_t block_size, u8* const host_ptr) { + // dc civac: Store to point of coherency, and invalidate from cache + Common::DataCacheLineCleanAndInvalidateByVAToPoC(host_ptr, block_size); + }; + return PerformCacheOperation(process, dest_addr, size, perform); + } + void MarkRegionDebug(VAddr vaddr, u64 size, bool debug) { if (vaddr == 0) { return; @@ -786,6 +836,21 @@ void Memory::ZeroBlock(const Kernel::KProcess& process, VAddr dest_addr, const s impl->ZeroBlock(process, dest_addr, size); } +Result Memory::InvalidateDataCache(const Kernel::KProcess& process, VAddr dest_addr, + const std::size_t size) { + return impl->InvalidateDataCache(process, dest_addr, size); +} + +Result Memory::StoreDataCache(const Kernel::KProcess& process, VAddr dest_addr, + const std::size_t size) { + return impl->StoreDataCache(process, dest_addr, size); +} + +Result Memory::FlushDataCache(const Kernel::KProcess& process, VAddr dest_addr, + const std::size_t size) { + return impl->FlushDataCache(process, dest_addr, size); +} + void Memory::RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached) { impl->RasterizerMarkRegionCached(vaddr, size, cached); } diff --git a/src/core/memory.h b/src/core/memory.h index 81eac448b..31fe699d8 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -7,6 +7,7 @@ #include #include #include "common/common_types.h" +#include "core/hle/result.h" namespace Common { struct PageTable; @@ -449,6 +450,39 @@ public: */ void ZeroBlock(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size); + /** + * Invalidates a range of bytes within the current process' address space at the specified + * virtual address. + * + * @param process The process that will have data invalidated within its address space. + * @param dest_addr The destination virtual address to invalidate the data from. + * @param size The size of the range to invalidate, in bytes. + * + */ + Result InvalidateDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size); + + /** + * Stores a range of bytes within the current process' address space at the specified + * virtual address. + * + * @param process The process that will have data stored within its address space. + * @param dest_addr The destination virtual address to store the data from. + * @param size The size of the range to store, in bytes. + * + */ + Result StoreDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size); + + /** + * Flushes a range of bytes within the current process' address space at the specified + * virtual address. + * + * @param process The process that will have data flushed within its address space. + * @param dest_addr The destination virtual address to flush the data from. + * @param size The size of the range to flush, in bytes. + * + */ + Result FlushDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size); + /** * Marks each page within the specified address range as cached or uncached. * -- cgit v1.2.3 From 540c1696d1d2b9b4ba1b7cf527f8a29e9fc1d67c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=ADas=20Locatti?= Date: Sat, 12 Nov 2022 15:31:54 -0300 Subject: Ignore ARM for core count --- src/yuzu/main.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 032ff1cbc..72498f52a 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -361,11 +361,10 @@ GMainWindow::GMainWindow(std::unique_ptr config_, bool has_broken_vulkan } } LOG_INFO(Frontend, "Host CPU: {}", cpu_string); -#endif - if (std::optional processor_core = Common::GetProcessorCount()) { LOG_INFO(Frontend, "Host CPU Cores: {}", *processor_core); } +#endif LOG_INFO(Frontend, "Host CPU Threads: {}", processor_count); LOG_INFO(Frontend, "Host OS: {}", PrettyProductName().toStdString()); LOG_INFO(Frontend, "Host RAM: {:.2f} GiB", -- cgit v1.2.3 From 6c045c9beb9c202fdea49274edd845fb2af491c3 Mon Sep 17 00:00:00 2001 From: german77 Date: Sun, 13 Nov 2022 10:52:48 -0600 Subject: service: nfc: fix tagprotocol and implement GetApplicationAreaId --- src/core/hle/service/nfp/nfp_device.cpp | 33 +++++++++++++++++++++++++++++++-- src/core/hle/service/nfp/nfp_device.h | 6 ++++-- src/core/hle/service/nfp/nfp_types.h | 10 +++++++--- src/core/hle/service/nfp/nfp_user.cpp | 2 +- 4 files changed, 43 insertions(+), 8 deletions(-) diff --git a/src/core/hle/service/nfp/nfp_device.cpp b/src/core/hle/service/nfp/nfp_device.cpp index b19672560..2f9dfa9c2 100644 --- a/src/core/hle/service/nfp/nfp_device.cpp +++ b/src/core/hle/service/nfp/nfp_device.cpp @@ -77,6 +77,9 @@ void NfpDevice::NpadUpdate(Core::HID::ControllerTriggerType type) { LoadAmiibo(nfc_status.data); break; case Common::Input::NfcState::AmiiboRemoved: + if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) { + break; + } if (device_state != DeviceState::SearchingForTag) { CloseAmiibo(); } @@ -97,6 +100,8 @@ bool NfpDevice::LoadAmiibo(std::span data) { return false; } + // TODO: Filter by allowed_protocols here + memcpy(&encrypted_tag_data, data.data(), sizeof(EncryptedNTAG215File)); device_state = DeviceState::TagFound; @@ -143,7 +148,7 @@ void NfpDevice::Finalize() { device_state = DeviceState::Unavailable; } -Result NfpDevice::StartDetection(s32 protocol_) { +Result NfpDevice::StartDetection([[maybe_unused]] TagProtocol allowed_protocol) { if (device_state != DeviceState::Initialized && device_state != DeviceState::TagRemoved) { LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); return WrongDeviceState; @@ -155,7 +160,7 @@ Result NfpDevice::StartDetection(s32 protocol_) { } device_state = DeviceState::SearchingForTag; - protocol = protocol_; + allowed_protocols = allowed_protocol; return ResultSuccess; } @@ -469,6 +474,30 @@ Result NfpDevice::OpenApplicationArea(u32 access_id) { return ResultSuccess; } +Result NfpDevice::GetApplicationAreaId(u32& application_area_id) const { + if (device_state != DeviceState::TagMounted) { + LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); + if (device_state == DeviceState::TagRemoved) { + return TagRemoved; + } + return WrongDeviceState; + } + + if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { + LOG_ERROR(Service_NFP, "Amiibo is read only", device_state); + return WrongDeviceState; + } + + if (tag_data.settings.settings.appdata_initialized.Value() == 0) { + LOG_WARNING(Service_NFP, "Application area is not initialized"); + return ApplicationAreaIsNotInitialized; + } + + application_area_id = tag_data.application_area_id; + + return ResultSuccess; +} + Result NfpDevice::GetApplicationArea(std::vector& data) const { if (device_state != DeviceState::TagMounted) { LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); diff --git a/src/core/hle/service/nfp/nfp_device.h b/src/core/hle/service/nfp/nfp_device.h index 76d0e9ae4..3d1cb4609 100644 --- a/src/core/hle/service/nfp/nfp_device.h +++ b/src/core/hle/service/nfp/nfp_device.h @@ -4,6 +4,7 @@ #pragma once #include +#include #include #include "common/common_funcs.h" @@ -37,7 +38,7 @@ public: void Initialize(); void Finalize(); - Result StartDetection(s32 protocol_); + Result StartDetection(TagProtocol allowed_protocol); Result StopDetection(); Result Mount(MountTarget mount_target); Result Unmount(); @@ -53,6 +54,7 @@ public: Result DeleteAllData(); Result OpenApplicationArea(u32 access_id); + Result GetApplicationAreaId(u32& application_area_id) const; Result GetApplicationArea(std::vector& data) const; Result SetApplicationArea(std::span data); Result CreateApplicationArea(u32 access_id, std::span data); @@ -88,7 +90,7 @@ private: bool is_data_moddified{}; bool is_app_area_open{}; - s32 protocol{}; + TagProtocol allowed_protocols{}; s64 current_posix_time{}; MountTarget mount_target{MountTarget::None}; DeviceState device_state{DeviceState::Unavailable}; diff --git a/src/core/hle/service/nfp/nfp_types.h b/src/core/hle/service/nfp/nfp_types.h index 63d5917cb..866aefe20 100644 --- a/src/core/hle/service/nfp/nfp_types.h +++ b/src/core/hle/service/nfp/nfp_types.h @@ -88,11 +88,15 @@ enum class PackedTagType : u8 { Type5, // ISO15693 RW/RO 540 bytes 106kbit/s }; +// Verify this enum. It might be completely wrong default protocol is 0x48 enum class TagProtocol : u32 { None, - TypeA, // ISO14443A - TypeB, // ISO14443B - TypeF, // Sony Felica + TypeA = 1U << 0, // ISO14443A + TypeB = 1U << 1, // ISO14443B + TypeF = 1U << 2, // Sony Felica + Unknown1 = 1U << 3, + Unknown2 = 1U << 5, + All = 0xFFFFFFFFU, }; using UniqueSerialNumber = std::array; diff --git a/src/core/hle/service/nfp/nfp_user.cpp b/src/core/hle/service/nfp/nfp_user.cpp index 33e2ef518..ac492cc27 100644 --- a/src/core/hle/service/nfp/nfp_user.cpp +++ b/src/core/hle/service/nfp/nfp_user.cpp @@ -130,7 +130,7 @@ void IUser::ListDevices(Kernel::HLERequestContext& ctx) { void IUser::StartDetection(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto device_handle{rp.Pop()}; - const auto nfp_protocol{rp.Pop()}; + const auto nfp_protocol{rp.PopEnum()}; LOG_INFO(Service_NFP, "called, device_handle={}, nfp_protocol={}", device_handle, nfp_protocol); if (state == State::NonInitialized) { -- cgit v1.2.3 From b193d40d2275fc59600268e2622ae25aab2bba64 Mon Sep 17 00:00:00 2001 From: german77 Date: Sun, 13 Nov 2022 10:56:01 -0600 Subject: input_common: Add amiibo applet functions --- src/input_common/drivers/virtual_amiibo.cpp | 15 +++++++++++++++ src/input_common/drivers/virtual_amiibo.h | 3 +++ src/input_common/input_engine.h | 2 +- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/input_common/drivers/virtual_amiibo.cpp b/src/input_common/drivers/virtual_amiibo.cpp index 0cd5129da..252c660d8 100644 --- a/src/input_common/drivers/virtual_amiibo.cpp +++ b/src/input_common/drivers/virtual_amiibo.cpp @@ -60,6 +60,8 @@ Common::Input::NfcState VirtualAmiibo::WriteNfcData( return Common::Input::NfcState::WriteFailed; } + amiibo_data = data; + return Common::Input::NfcState::Success; } @@ -91,6 +93,15 @@ VirtualAmiibo::Info VirtualAmiibo::LoadAmiibo(const std::string& filename) { return Info::Success; } +VirtualAmiibo::Info VirtualAmiibo::ReloadAmiibo() { + if (state == State::AmiiboIsOpen) { + SetNfc(identifier, {Common::Input::NfcState::NewAmiibo, amiibo_data}); + return Info::Success; + } + + return LoadAmiibo(file_path); +} + VirtualAmiibo::Info VirtualAmiibo::CloseAmiibo() { state = polling_mode == Common::Input::PollingMode::NFC ? State::WaitingForAmiibo : State::Initialized; @@ -98,4 +109,8 @@ VirtualAmiibo::Info VirtualAmiibo::CloseAmiibo() { return Info::Success; } +std::string VirtualAmiibo::GetLastFilePath() { + return file_path; +} + } // namespace InputCommon diff --git a/src/input_common/drivers/virtual_amiibo.h b/src/input_common/drivers/virtual_amiibo.h index 9eac07544..f2294b8b0 100644 --- a/src/input_common/drivers/virtual_amiibo.h +++ b/src/input_common/drivers/virtual_amiibo.h @@ -47,8 +47,11 @@ public: State GetCurrentState() const; Info LoadAmiibo(const std::string& amiibo_file); + Info ReloadAmiibo(); Info CloseAmiibo(); + std::string GetLastFilePath(); + private: static constexpr std::size_t amiibo_size = 0x21C; static constexpr std::size_t amiibo_size_without_password = amiibo_size - 0x8; diff --git a/src/input_common/input_engine.h b/src/input_common/input_engine.h index d4c264a8e..6cbcf5207 100644 --- a/src/input_common/input_engine.h +++ b/src/input_common/input_engine.h @@ -133,7 +133,7 @@ public: return Common::Input::CameraError::NotSupported; } - // Request nfc data from a controller + // Returns success if nfc is supported virtual Common::Input::NfcState SupportsNfc( [[maybe_unused]] const PadIdentifier& identifier) const { return Common::Input::NfcState::NotSupported; -- cgit v1.2.3 From fb57cd26a1219a5c91d2cb4dec402528f8ba308e Mon Sep 17 00:00:00 2001 From: german77 Date: Sun, 13 Nov 2022 11:07:48 -0600 Subject: service: am: Implement cabinet applet backend --- src/core/CMakeLists.txt | 4 + src/core/frontend/applets/cabinet.cpp | 20 +++ src/core/frontend/applets/cabinet.h | 36 +++++ src/core/hle/service/am/applets/applet_cabinet.cpp | 169 +++++++++++++++++++++ src/core/hle/service/am/applets/applet_cabinet.h | 99 ++++++++++++ src/core/hle/service/am/applets/applets.cpp | 20 ++- src/core/hle/service/am/applets/applets.h | 12 +- src/core/hle/service/nfp/nfp_types.h | 7 + src/yuzu/main.cpp | 2 + 9 files changed, 362 insertions(+), 7 deletions(-) create mode 100644 src/core/frontend/applets/cabinet.cpp create mode 100644 src/core/frontend/applets/cabinet.h create mode 100644 src/core/hle/service/am/applets/applet_cabinet.cpp create mode 100644 src/core/hle/service/am/applets/applet_cabinet.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index f67f1ce92..740c5b0fd 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -120,6 +120,8 @@ add_library(core STATIC file_sys/vfs_vector.h file_sys/xts_archive.cpp file_sys/xts_archive.h + frontend/applets/cabinet.cpp + frontend/applets/cabinet.h frontend/applets/controller.cpp frontend/applets/controller.h frontend/applets/error.cpp @@ -312,6 +314,8 @@ add_library(core STATIC hle/service/am/applet_ae.h hle/service/am/applet_oe.cpp hle/service/am/applet_oe.h + hle/service/am/applets/applet_cabinet.cpp + hle/service/am/applets/applet_cabinet.h hle/service/am/applets/applet_controller.cpp hle/service/am/applets/applet_controller.h hle/service/am/applets/applet_error.cpp diff --git a/src/core/frontend/applets/cabinet.cpp b/src/core/frontend/applets/cabinet.cpp new file mode 100644 index 000000000..5ade75de0 --- /dev/null +++ b/src/core/frontend/applets/cabinet.cpp @@ -0,0 +1,20 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/logging/log.h" +#include "core/frontend/applets/cabinet.h" + +#include + +namespace Core::Frontend { + +CabinetApplet::~CabinetApplet() = default; + +void DefaultCabinetApplet::ShowCabinetApplet( + std::function callback, const CabinetParameters& parameters, + std::shared_ptr nfp_device) const { + LOG_WARNING(Service_AM, "(STUBBED) called"); + callback(false, {}); +} + +} // namespace Core::Frontend diff --git a/src/core/frontend/applets/cabinet.h b/src/core/frontend/applets/cabinet.h new file mode 100644 index 000000000..1c68bf57d --- /dev/null +++ b/src/core/frontend/applets/cabinet.h @@ -0,0 +1,36 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include "core/hle/service/nfp/nfp_types.h" + +namespace Service::NFP { +class NfpDevice; +} // namespace Service::NFP + +namespace Core::Frontend { + +struct CabinetParameters { + Service::NFP::TagInfo tag_info; + Service::NFP::RegisterInfo register_info; + Service::NFP::CabinetMode mode; +}; + +class CabinetApplet { +public: + virtual ~CabinetApplet(); + virtual void ShowCabinetApplet(std::function callback, + const CabinetParameters& parameters, + std::shared_ptr nfp_device) const = 0; +}; + +class DefaultCabinetApplet final : public CabinetApplet { +public: + void ShowCabinetApplet(std::function callback, + const CabinetParameters& parameters, + std::shared_ptr nfp_device) const override; +}; + +} // namespace Core::Frontend diff --git a/src/core/hle/service/am/applets/applet_cabinet.cpp b/src/core/hle/service/am/applets/applet_cabinet.cpp new file mode 100644 index 000000000..1eb5a9f22 --- /dev/null +++ b/src/core/hle/service/am/applets/applet_cabinet.cpp @@ -0,0 +1,169 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/assert.h" +#include "common/logging/log.h" +#include "core/core.h" +#include "core/frontend/applets/cabinet.h" +#include "core/hid/hid_core.h" +#include "core/hle/kernel/k_event.h" +#include "core/hle/kernel/k_readable_event.h" +#include "core/hle/service/am/am.h" +#include "core/hle/service/am/applets/applet_cabinet.h" +#include "core/hle/service/mii/mii_manager.h" +#include "core/hle/service/nfp/nfp_device.h" + +namespace Service::AM::Applets { + +Cabinet::Cabinet(Core::System& system_, LibraryAppletMode applet_mode_, + const Core::Frontend::CabinetApplet& frontend_) + : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_}, service_context{ + system_, + "CabinetApplet"} { + + availability_change_event = + service_context.CreateEvent("CabinetApplet:AvailabilityChangeEvent"); +} + +Cabinet::~Cabinet() = default; + +void Cabinet::Initialize() { + Applet::Initialize(); + + LOG_INFO(Service_HID, "Initializing Cabinet Applet."); + + LOG_ERROR(Service_HID, + "Initializing Applet with common_args: arg_version={}, lib_version={}, " + "play_startup_sound={}, size={}, system_tick={}, theme_color={}", + common_args.arguments_version, common_args.library_version, + common_args.play_startup_sound, common_args.size, common_args.system_tick, + common_args.theme_color); + + const auto storage = broker.PopNormalDataToApplet(); + ASSERT(storage != nullptr); + + const auto applet_input_data = storage->GetData(); + ASSERT(applet_input_data.size() >= sizeof(StartParamForAmiiboSettings)); + + std::memcpy(&applet_input_common, applet_input_data.data(), + sizeof(StartParamForAmiiboSettings)); +} + +bool Cabinet::TransactionComplete() const { + return is_complete; +} + +Result Cabinet::GetStatus() const { + return ResultSuccess; +} + +void Cabinet::ExecuteInteractive() { + ASSERT_MSG(false, "Attempted to call interactive execution on non-interactive applet."); +} + +void Cabinet::Execute() { + if (is_complete) { + return; + } + + const auto callback = [this](bool apply_changes, const std::string& amiibo_name) { + DisplayCompleted(apply_changes, amiibo_name); + }; + + // TODO: listen on all controllers + if (nfp_device == nullptr) { + nfp_device = std::make_shared( + system.HIDCore().GetFirstNpadId(), system, service_context, availability_change_event); + nfp_device->Initialize(); + nfp_device->StartDetection(Service::NFP::TagProtocol::All); + } + + const Core::Frontend::CabinetParameters parameters{ + .tag_info = applet_input_common.tag_info, + .register_info = applet_input_common.register_info, + .mode = applet_input_common.applet_mode, + }; + + switch (applet_input_common.applet_mode) { + case Service::NFP::CabinetMode::StartNicknameAndOwnerSettings: + case Service::NFP::CabinetMode::StartGameDataEraser: + case Service::NFP::CabinetMode::StartRestorer: + case Service::NFP::CabinetMode::StartFormatter: + frontend.ShowCabinetApplet(callback, parameters, nfp_device); + break; + default: + UNIMPLEMENTED_MSG("Unknown CabinetMode={}", applet_input_common.applet_mode); + DisplayCompleted(false, {}); + break; + } +} + +void Cabinet::DisplayCompleted(bool apply_changes, const std::string& amiibo_name) { + Service::Mii::MiiManager manager; + ReturnValueForAmiiboSettings applet_output{}; + + if (!apply_changes) { + Cancel(); + } + + if (nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagFound && + nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagMounted) { + Cancel(); + } + + if (nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagFound) { + nfp_device->Mount(Service::NFP::MountTarget::All); + } + + switch (applet_input_common.applet_mode) { + case Service::NFP::CabinetMode::StartNicknameAndOwnerSettings: { + Service::NFP::AmiiboName name{}; + memccpy(name.data(), amiibo_name.data(), 0, name.size()); + nfp_device->SetNicknameAndOwner(name); + break; + } + case Service::NFP::CabinetMode::StartGameDataEraser: + nfp_device->DeleteApplicationArea(); + break; + case Service::NFP::CabinetMode::StartRestorer: + nfp_device->RestoreAmiibo(); + break; + case Service::NFP::CabinetMode::StartFormatter: + nfp_device->DeleteAllData(); + break; + default: + UNIMPLEMENTED_MSG("Unknown CabinetMode={}", applet_input_common.applet_mode); + break; + } + + applet_output.device_handle = applet_input_common.device_handle; + applet_output.result = CabinetResult::Success; + nfp_device->GetRegisterInfo(applet_output.register_info); + nfp_device->GetTagInfo(applet_output.tag_info); + nfp_device->Finalize(); + + std::vector out_data(sizeof(ReturnValueForAmiiboSettings)); + std::memcpy(out_data.data(), &applet_output, sizeof(ReturnValueForAmiiboSettings)); + + is_complete = true; + + broker.PushNormalDataFromApplet(std::make_shared(system, std::move(out_data))); + broker.SignalStateChanged(); +} + +void Cabinet::Cancel() { + ReturnValueForAmiiboSettings applet_output{}; + applet_output.device_handle = applet_input_common.device_handle; + applet_output.result = CabinetResult::Cancel; + nfp_device->Finalize(); + + std::vector out_data(sizeof(ReturnValueForAmiiboSettings)); + std::memcpy(out_data.data(), &applet_output, sizeof(ReturnValueForAmiiboSettings)); + + is_complete = true; + + broker.PushNormalDataFromApplet(std::make_shared(system, std::move(out_data))); + broker.SignalStateChanged(); +} + +} // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/applet_cabinet.h b/src/core/hle/service/am/applets/applet_cabinet.h new file mode 100644 index 000000000..2d3f22434 --- /dev/null +++ b/src/core/hle/service/am/applets/applet_cabinet.h @@ -0,0 +1,99 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include + +#include "core/hle/result.h" +#include "core/hle/service/am/applets/applets.h" +#include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/nfp/nfp_types.h" + +namespace Kernel { +class KEvent; +class KReadableEvent; +} // namespace Kernel + +namespace Core { +class System; +} // namespace Core + +namespace Service::NFP { +class NfpDevice; +} + +namespace Service::AM::Applets { + +enum class CabinetAppletVersion : s32 { + Version1 = 0x1, +}; + +enum class CabinetResult : u8 { + Cancel, + Success, +}; + +// This is nn::nfp::AmiiboSettingsStartParam +struct AmiiboSettingsStartParam { + u64 device_handle; + std::array param_1; + std::array param_2; +}; +static_assert(sizeof(AmiiboSettingsStartParam) == 0x30, + "AmiiboSettingsStartParam is an invalid size"); + +// This is nn::nfp::StartParamForAmiiboSettings +struct StartParamForAmiiboSettings { + u8 param_1; + Service::NFP::CabinetMode applet_mode; + u8 flags; + u8 amiibo_settings_1; + u64 device_handle; + Service::NFP::TagInfo tag_info; + Service::NFP::RegisterInfo register_info; + std::array amiibo_settings_3; + INSERT_PADDING_BYTES(0x20); +}; +static_assert(sizeof(StartParamForAmiiboSettings) == 0x1A8, + "StartParamForAmiiboSettings is an invalid size"); + +// This is nn::nfp::ReturnValueForAmiiboSettings +struct ReturnValueForAmiiboSettings { + CabinetResult result; + INSERT_PADDING_BYTES(0x3); + u64 device_handle; + Service::NFP::TagInfo tag_info; + Service::NFP::RegisterInfo register_info; + INSERT_PADDING_BYTES(0x24); +}; +static_assert(sizeof(ReturnValueForAmiiboSettings) == 0x190, + "ReturnValueForAmiiboSettings is an invalid size"); + +class Cabinet final : public Applet { +public: + explicit Cabinet(Core::System& system_, LibraryAppletMode applet_mode_, + const Core::Frontend::CabinetApplet& frontend_); + ~Cabinet() override; + + void Initialize() override; + + bool TransactionComplete() const override; + Result GetStatus() const override; + void ExecuteInteractive() override; + void Execute() override; + void DisplayCompleted(bool apply_changes, const std::string& amiibo_name); + void Cancel(); + +private: + const Core::Frontend::CabinetApplet& frontend; + Core::System& system; + + bool is_complete{false}; + std::shared_ptr nfp_device; + Kernel::KEvent* availability_change_event; + KernelHelpers::ServiceContext service_context; + StartParamForAmiiboSettings applet_input_common{}; +}; + +} // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp index 7062df21c..10afbc2da 100644 --- a/src/core/hle/service/am/applets/applets.cpp +++ b/src/core/hle/service/am/applets/applets.cpp @@ -5,6 +5,7 @@ #include "common/assert.h" #include "core/core.h" +#include "core/frontend/applets/cabinet.h" #include "core/frontend/applets/controller.h" #include "core/frontend/applets/error.h" #include "core/frontend/applets/general_frontend.h" @@ -16,6 +17,7 @@ #include "core/hle/service/am/am.h" #include "core/hle/service/am/applet_ae.h" #include "core/hle/service/am/applet_oe.h" +#include "core/hle/service/am/applets/applet_cabinet.h" #include "core/hle/service/am/applets/applet_controller.h" #include "core/hle/service/am/applets/applet_error.h" #include "core/hle/service/am/applets/applet_general_backend.h" @@ -171,13 +173,15 @@ void Applet::Initialize() { AppletFrontendSet::AppletFrontendSet() = default; -AppletFrontendSet::AppletFrontendSet(ControllerApplet controller_applet, ErrorApplet error_applet, +AppletFrontendSet::AppletFrontendSet(CabinetApplet cabinet_applet, + ControllerApplet controller_applet, ErrorApplet error_applet, MiiEdit mii_edit_, ParentalControlsApplet parental_controls_applet, PhotoViewer photo_viewer_, ProfileSelect profile_select_, SoftwareKeyboard software_keyboard_, WebBrowser web_browser_) - : controller{std::move(controller_applet)}, error{std::move(error_applet)}, - mii_edit{std::move(mii_edit_)}, parental_controls{std::move(parental_controls_applet)}, + : cabinet{std::move(cabinet_applet)}, controller{std::move(controller_applet)}, + error{std::move(error_applet)}, mii_edit{std::move(mii_edit_)}, + parental_controls{std::move(parental_controls_applet)}, photo_viewer{std::move(photo_viewer_)}, profile_select{std::move(profile_select_)}, software_keyboard{std::move(software_keyboard_)}, web_browser{std::move(web_browser_)} {} @@ -196,6 +200,10 @@ const AppletFrontendSet& AppletManager::GetAppletFrontendSet() const { } void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) { + if (set.cabinet != nullptr) { + frontend.cabinet = std::move(set.cabinet); + } + if (set.controller != nullptr) { frontend.controller = std::move(set.controller); } @@ -235,6 +243,10 @@ void AppletManager::SetDefaultAppletFrontendSet() { } void AppletManager::SetDefaultAppletsIfMissing() { + if (frontend.cabinet == nullptr) { + frontend.cabinet = std::make_unique(); + } + if (frontend.controller == nullptr) { frontend.controller = std::make_unique(system.HIDCore()); @@ -279,6 +291,8 @@ std::shared_ptr AppletManager::GetApplet(AppletId id, LibraryAppletMode switch (id) { case AppletId::Auth: return std::make_shared(system, mode, *frontend.parental_controls); + case AppletId::Cabinet: + return std::make_shared(system, mode, *frontend.cabinet); case AppletId::Controller: return std::make_shared(system, mode, *frontend.controller); case AppletId::Error: diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h index 12c6a5b1a..a22eb62a8 100644 --- a/src/core/hle/service/am/applets/applets.h +++ b/src/core/hle/service/am/applets/applets.h @@ -16,6 +16,7 @@ class System; } namespace Core::Frontend { +class CabinetApplet; class ControllerApplet; class ECommerceApplet; class ErrorApplet; @@ -176,6 +177,7 @@ protected: }; struct AppletFrontendSet { + using CabinetApplet = std::unique_ptr; using ControllerApplet = std::unique_ptr; using ErrorApplet = std::unique_ptr; using MiiEdit = std::unique_ptr; @@ -186,10 +188,11 @@ struct AppletFrontendSet { using WebBrowser = std::unique_ptr; AppletFrontendSet(); - AppletFrontendSet(ControllerApplet controller_applet, ErrorApplet error_applet, - MiiEdit mii_edit_, ParentalControlsApplet parental_controls_applet, - PhotoViewer photo_viewer_, ProfileSelect profile_select_, - SoftwareKeyboard software_keyboard_, WebBrowser web_browser_); + AppletFrontendSet(CabinetApplet cabinet_applet, ControllerApplet controller_applet, + ErrorApplet error_applet, MiiEdit mii_edit_, + ParentalControlsApplet parental_controls_applet, PhotoViewer photo_viewer_, + ProfileSelect profile_select_, SoftwareKeyboard software_keyboard_, + WebBrowser web_browser_); ~AppletFrontendSet(); AppletFrontendSet(const AppletFrontendSet&) = delete; @@ -198,6 +201,7 @@ struct AppletFrontendSet { AppletFrontendSet(AppletFrontendSet&&) noexcept; AppletFrontendSet& operator=(AppletFrontendSet&&) noexcept; + CabinetApplet cabinet; ControllerApplet controller; ErrorApplet error; MiiEdit mii_edit; diff --git a/src/core/hle/service/nfp/nfp_types.h b/src/core/hle/service/nfp/nfp_types.h index 866aefe20..69858096a 100644 --- a/src/core/hle/service/nfp/nfp_types.h +++ b/src/core/hle/service/nfp/nfp_types.h @@ -99,6 +99,13 @@ enum class TagProtocol : u32 { All = 0xFFFFFFFFU, }; +enum class CabinetMode : u8 { + StartNicknameAndOwnerSettings, + StartGameDataEraser, + StartRestorer, + StartFormatter, +}; + using UniqueSerialNumber = std::array; using LockBytes = std::array; using HashData = std::array; diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 032ff1cbc..27c9e1f32 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -26,6 +26,7 @@ #include "configuration/configure_tas.h" #include "core/file_sys/vfs.h" #include "core/file_sys/vfs_real.h" +#include "core/frontend/applets/cabinet.h" #include "core/frontend/applets/controller.h" #include "core/frontend/applets/general_frontend.h" #include "core/frontend/applets/mii_edit.h" @@ -1547,6 +1548,7 @@ bool GMainWindow::LoadROM(const QString& filename, u64 program_id, std::size_t p system->SetFilesystem(vfs); system->SetAppletFrontendSet({ + nullptr, // Amiibo Manager std::make_unique(*this), // Controller Selector std::make_unique(*this), // Error Display nullptr, // Mii Editor -- cgit v1.2.3 From 9afadca5dc922ac05c7b1557159b277327f40945 Mon Sep 17 00:00:00 2001 From: german77 Date: Sun, 13 Nov 2022 13:43:03 -0600 Subject: yuzu: Implement cabinet applet frontend --- src/yuzu/CMakeLists.txt | 3 + src/yuzu/applets/qt_amiibo_manager.cpp | 247 +++++++++++++++++ src/yuzu/applets/qt_amiibo_manager.h | 93 +++++++ src/yuzu/applets/qt_amiibo_manager.ui | 491 +++++++++++++++++++++++++++++++++ src/yuzu/main.cpp | 23 +- src/yuzu/main.h | 9 + 6 files changed, 865 insertions(+), 1 deletion(-) create mode 100644 src/yuzu/applets/qt_amiibo_manager.cpp create mode 100644 src/yuzu/applets/qt_amiibo_manager.h create mode 100644 src/yuzu/applets/qt_amiibo_manager.ui diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 5cc1fbf32..8571d9c7c 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -18,6 +18,9 @@ add_executable(yuzu about_dialog.cpp about_dialog.h aboutdialog.ui + applets/qt_amiibo_manager.cpp + applets/qt_amiibo_manager.h + applets/qt_amiibo_manager.ui applets/qt_controller.cpp applets/qt_controller.h applets/qt_controller.ui diff --git a/src/yuzu/applets/qt_amiibo_manager.cpp b/src/yuzu/applets/qt_amiibo_manager.cpp new file mode 100644 index 000000000..9c7b15d06 --- /dev/null +++ b/src/yuzu/applets/qt_amiibo_manager.cpp @@ -0,0 +1,247 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include +#include +#include + +#include "common/assert.h" +#include "common/string_util.h" +#include "core/hle/service/nfp/nfp_device.h" +#include "core/hle/service/nfp/nfp_result.h" +#include "input_common/drivers/virtual_amiibo.h" +#include "input_common/main.h" +#include "ui_qt_amiibo_manager.h" +#include "web_service/web_backend.h" +#include "yuzu/applets/qt_amiibo_manager.h" +#include "yuzu/main.h" + +QtAmiiboManagerDialog::QtAmiiboManagerDialog(QWidget* parent, + Core::Frontend::CabinetParameters parameters_, + InputCommon::InputSubsystem* input_subsystem_, + std::shared_ptr nfp_device_) + : QDialog(parent), ui(std::make_unique()), + input_subsystem{input_subsystem_}, nfp_device{nfp_device_}, + parameters(std::move(parameters_)) { + ui->setupUi(this); + + LoadInfo(); + + resize(0, 0); +} + +QtAmiiboManagerDialog::~QtAmiiboManagerDialog() = default; + +int QtAmiiboManagerDialog::exec() { + if (!is_initalized) { + return QDialog::Rejected; + } + return QDialog::exec(); +} + +std::string QtAmiiboManagerDialog::GetName() { + return ui->amiiboCustomNameValue->text().toStdString(); +} + +void QtAmiiboManagerDialog::LoadInfo() { + if (input_subsystem->GetVirtualAmiibo()->ReloadAmiibo() != + InputCommon::VirtualAmiibo::Info::Success) { + return; + } + + if (nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagFound && + nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagMounted) { + return; + } + nfp_device->Mount(Service::NFP::MountTarget::All); + + Service::NFP::ModelInfo model_info{}; + const auto model_result = nfp_device->GetModelInfo(model_info); + + if (model_result.IsSuccess()) { + const auto amiibo_id = + fmt::format("{:04x}{:02x}{:02x}{:04x}{:02x}02", Common::swap16(model_info.character_id), + model_info.character_variant, model_info.amiibo_type, + model_info.model_number, model_info.series); + LOG_ERROR(Input, "{}", amiibo_id); + LoadAmiiboApiInfo(amiibo_id); + } + + LoadAmiiboData(); + LoadAmiiboGameInfo(); + + ui->amiiboDirectoryValue->setText( + QString::fromStdString(input_subsystem->GetVirtualAmiibo()->GetLastFilePath())); + + SetManagerDescription(); + is_initalized = true; +} + +void QtAmiiboManagerDialog::LoadAmiiboApiInfo(std::string amiibo_id) { + WebService::Client client{"https://amiiboapi.com", {}, {}}; + WebService::Client image_client{"https://raw.githubusercontent.com", {}, {}}; + const auto url_path = fmt::format("/api/amiibo/?id={}", amiibo_id); + + const auto amiibo_json = client.GetJson(url_path, true).returned_data; + if (amiibo_json.empty()) { + ui->amiiboImageLabel->setVisible(false); + ui->amiiboInfoGroup->setVisible(false); + return; + } + + std::string amiibo_series{}; + std::string amiibo_name{}; + std::string amiibo_image_url{}; + std::string amiibo_type{}; + + const auto parsed_amiibo_json_json = nlohmann::json::parse(amiibo_json).at("amiibo"); + parsed_amiibo_json_json.at("amiiboSeries").get_to(amiibo_series); + parsed_amiibo_json_json.at("name").get_to(amiibo_name); + parsed_amiibo_json_json.at("image").get_to(amiibo_image_url); + parsed_amiibo_json_json.at("type").get_to(amiibo_type); + + ui->amiiboSeriesValue->setText(QString::fromStdString(amiibo_series)); + ui->amiiboNameValue->setText(QString::fromStdString(amiibo_name)); + ui->amiiboTypeValue->setText(QString::fromStdString(amiibo_type)); + + if (amiibo_image_url.size() < 34) { + ui->amiiboImageLabel->setVisible(false); + } + + const auto image_url_path = amiibo_image_url.substr(34, amiibo_image_url.size() - 34); + const auto image_data = image_client.GetImage(image_url_path, true).returned_data; + + if (image_data.empty()) { + ui->amiiboImageLabel->setVisible(false); + } + + QPixmap pixmap; + pixmap.loadFromData(reinterpret_cast(image_data.data()), + static_cast(image_data.size())); + pixmap = pixmap.scaled(250, 350, Qt::AspectRatioMode::KeepAspectRatio, + Qt::TransformationMode::SmoothTransformation); + ui->amiiboImageLabel->setPixmap(pixmap); +} + +void QtAmiiboManagerDialog::LoadAmiiboData() { + Service::NFP::RegisterInfo register_info{}; + Service::NFP::CommonInfo common_info{}; + const auto register_result = nfp_device->GetRegisterInfo(register_info); + const auto common_result = nfp_device->GetCommonInfo(common_info); + + if (register_result.IsFailure()) { + ui->creationDateValue->setDisabled(true); + ui->modificationDateValue->setDisabled(true); + ui->amiiboCustomNameValue->setReadOnly(false); + ui->amiiboOwnerValue->setReadOnly(false); + return; + } + + if (parameters.mode == Service::NFP::CabinetMode::StartNicknameAndOwnerSettings) { + ui->creationDateValue->setDisabled(true); + ui->modificationDateValue->setDisabled(true); + } + + const auto amiibo_name = std::string(register_info.amiibo_name.data()); + const auto owner_name = Common::UTF16ToUTF8(register_info.mii_char_info.name.data()); + const auto creation_date = + QDate(register_info.creation_date.year, register_info.creation_date.month, + register_info.creation_date.day); + + ui->amiiboCustomNameValue->setText(QString::fromStdString(amiibo_name)); + ui->amiiboOwnerValue->setText(QString::fromStdString(owner_name)); + ui->amiiboCustomNameValue->setReadOnly(true); + ui->amiiboOwnerValue->setReadOnly(true); + ui->creationDateValue->setDate(creation_date); + + if (common_result.IsFailure()) { + ui->modificationDateValue->setDisabled(true); + return; + } + + const auto modification_date = + QDate(common_info.last_write_date.year, common_info.last_write_date.month, + common_info.last_write_date.day); + ui->modificationDateValue->setDate(modification_date); +} + +void QtAmiiboManagerDialog::LoadAmiiboGameInfo() { + u32 application_area_id{}; + const auto application_result = nfp_device->GetApplicationAreaId(application_area_id); + + if (application_result.IsFailure()) { + ui->gameIdValue->setVisible(false); + ui->gameIdLabel->setText(tr("No game data present")); + return; + } + + SetGameDataName(application_area_id); +} + +void QtAmiiboManagerDialog::SetGameDataName(u32 application_area_id) { + const std::array, 12> game_name_list = { + // 3ds, wii u + std::pair{0x10110E00, QStringLiteral("Super Smash Bros (3DS/WiiU)")}, + {0x00132600, QStringLiteral("Mario & Luigi: Paper Jam")}, + {0x0014F000, QStringLiteral("Animal Crossing: Happy Home Designer")}, + {0x00152600, QStringLiteral("Chibi-Robo!: Zip Lash")}, + {0x10161f00, QStringLiteral("Mario Party 10")}, + {0x1019C800, QStringLiteral("The Legend of Zelda: Twilight Princess HD")}, + // switch + {0x10162B00, QStringLiteral("Splatoon 2")}, + {0x1016e100, QStringLiteral("Shovel Knight: Treasure Trove")}, + {0x1019C800, QStringLiteral("The Legend of Zelda: Breath of the Wild")}, + {0x34F80200, QStringLiteral("Super Smash Bros. Ultimate")}, + {0x38600500, QStringLiteral("Splatoon 3")}, + {0x3B440400, QStringLiteral("The Legend of Zelda: Link's Awakening")}, + }; + + for (const auto& [game_id, game_name] : game_name_list) { + if (application_area_id == game_id) { + ui->gameIdValue->setText(game_name); + return; + } + } + + const auto application_area_string = fmt::format("{:016x}", application_area_id); + ui->gameIdValue->setText(QString::fromStdString(application_area_string)); +} + +void QtAmiiboManagerDialog::SetManagerDescription() { + switch (parameters.mode) { + case Service::NFP::CabinetMode::StartFormatter: + ui->cabinetActionDescriptionLabel->setText( + tr("The following amiibo data will be formated:")); + break; + case Service::NFP::CabinetMode::StartGameDataEraser: + ui->cabinetActionDescriptionLabel->setText(tr("The following game data will removed:")); + break; + case Service::NFP::CabinetMode::StartNicknameAndOwnerSettings: + ui->cabinetActionDescriptionLabel->setText(tr("Set nickname and owner:")); + break; + case Service::NFP::CabinetMode::StartRestorer: + ui->cabinetActionDescriptionLabel->setText(tr("Do you wish to restore this amiibo:")); + break; + } +} + +QtAmiiboManager::QtAmiiboManager(GMainWindow& parent) { + connect(this, &QtAmiiboManager::MainWindowShowAmiiboManager, &parent, + &GMainWindow::AmiiboManagerShowDialog, Qt::QueuedConnection); + connect(&parent, &GMainWindow::AmiiboManagerFinished, this, + &QtAmiiboManager::MainWindowFinished, Qt::QueuedConnection); +} + +QtAmiiboManager::~QtAmiiboManager() = default; + +void QtAmiiboManager::ShowCabinetApplet(std::function callback_, + const Core::Frontend::CabinetParameters& parameters, + std::shared_ptr nfp_device) const { + callback = std::move(callback_); + emit MainWindowShowAmiiboManager(parameters, nfp_device); +} + +void QtAmiiboManager::MainWindowFinished(bool is_success, std::string name) { + callback(is_success, name); +} diff --git a/src/yuzu/applets/qt_amiibo_manager.h b/src/yuzu/applets/qt_amiibo_manager.h new file mode 100644 index 000000000..3f5866ed7 --- /dev/null +++ b/src/yuzu/applets/qt_amiibo_manager.h @@ -0,0 +1,93 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include +#include +#include "core/frontend/applets/cabinet.h" + +class GMainWindow; +class QCheckBox; +class QComboBox; +class QDialogButtonBox; +class QGroupBox; +class QLabel; + +class InputProfiles; + +namespace InputCommon { +class InputSubsystem; +} + +namespace Ui { +class QtAmiiboManagerDialog; +} + +namespace Core { +class System; +} + +namespace Core::HID { +class HIDCore; +enum class NpadStyleIndex : u8; +} // namespace Core::HID + +namespace Service::NFP { +class NfpDevice; +} // namespace Service::NFP + +class QtAmiiboManagerDialog final : public QDialog { + Q_OBJECT + +public: + explicit QtAmiiboManagerDialog(QWidget* parent, Core::Frontend::CabinetParameters parameters_, + InputCommon::InputSubsystem* input_subsystem_, + std::shared_ptr nfp_device_); + ~QtAmiiboManagerDialog() override; + + int exec() override; + + std::string GetName(); + +private: + void LoadInfo(); + void LoadAmiiboApiInfo(std::string amiibo_id); + void LoadAmiiboData(); + void LoadAmiiboGameInfo(); + void SetGameDataName(u32 application_area_id); + void SetManagerDescription(); + + std::unique_ptr ui; + + InputCommon::InputSubsystem* input_subsystem; + std::shared_ptr nfp_device; + + // Parameters sent in from the backend HLE applet. + Core::Frontend::CabinetParameters parameters; + + // If false amiibo manager failed to load + bool is_initalized{}; +}; + +class QtAmiiboManager final : public QObject, public Core::Frontend::CabinetApplet { + Q_OBJECT + +public: + explicit QtAmiiboManager(GMainWindow& parent); + ~QtAmiiboManager() override; + + void ShowCabinetApplet(std::function callback_, + const Core::Frontend::CabinetParameters& parameters, + std::shared_ptr nfp_device) const override; + +signals: + void MainWindowShowAmiiboManager(const Core::Frontend::CabinetParameters& parameters, + std::shared_ptr nfp_device) const; + +private: + void MainWindowFinished(bool is_success, std::string name); + + mutable std::function callback; +}; diff --git a/src/yuzu/applets/qt_amiibo_manager.ui b/src/yuzu/applets/qt_amiibo_manager.ui new file mode 100644 index 000000000..eb6eabe59 --- /dev/null +++ b/src/yuzu/applets/qt_amiibo_manager.ui @@ -0,0 +1,491 @@ + + + QtAmiiboManagerDialog + + + + 0 + 0 + 839 + 500 + + + + Amiibo Manager + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 10 + + + 20 + + + 15 + + + 0 + + + 15 + + + + + + 12 + 75 + true + + + + + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + false + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 20 + + + 15 + + + + + + 250 + 350 + + + + + 236 + 350 + + + + + + + Qt::AlignCenter + + + + + + + 20 + + + 8 + + + 15 + + + + + Amiibo Info + + + + + + + + Series + + + + + + + + 0 + 0 + + + + true + + + + + + + Type + + + + + + + + 0 + 0 + + + + true + + + + + + + Name + + + + + + + + 0 + 0 + + + + true + + + + + + + + + + + + Amiibo Data + + + + + + + + Custom Name + + + + + + + + 0 + 0 + + + + 10 + + + + + + + Owner + + + + + + + + 0 + 0 + + + + 10 + + + + + + + Creation Date + + + + + + + true + + + + 1970 + 1 + 1 + + + + dd/MM/yyyy + + + + + + + Modification Date + + + + + + + true + + + + 1970 + 1 + 1 + + + + dd/MM/yyyy + + + + + + + + + + + + + 500 + 0 + + + + Game Data + + + + + + Game Id + + + + + + + + 0 + 0 + + + + true + + + + + + + + + + + 500 + 0 + + + + Mount Amiibo + + + + + + ... + + + + + + + Qt::Horizontal + + + QSizePolicy::Maximum + + + + 60 + 20 + + + + + + + + File Path + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + + + 15 + + + 15 + + + 8 + + + 20 + + + 8 + + + + + true + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + + + + + + buttonBox + accepted() + QtAmiiboManagerDialog + accept() + + + buttonBox + rejected() + QtAmiiboManagerDialog + reject() + + + diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 27c9e1f32..27266cae3 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -15,6 +15,7 @@ #endif // VFS includes must be before glad as they will conflict with Windows file api, which uses defines. +#include "applets/qt_amiibo_manager.h" #include "applets/qt_controller.h" #include "applets/qt_error.h" #include "applets/qt_profile_select.h" @@ -550,6 +551,11 @@ void GMainWindow::RegisterMetaTypes() { // Register applet types + // Cabinet Applet + qRegisterMetaType("Core::Frontend::CabinetParameters"); + qRegisterMetaType>( + "std::shared_ptr"); + // Controller Applet qRegisterMetaType("Core::Frontend::ControllerParameters"); @@ -571,6 +577,21 @@ void GMainWindow::RegisterMetaTypes() { qRegisterMetaType("Core::SystemResultStatus"); } +void GMainWindow::AmiiboManagerShowDialog(const Core::Frontend::CabinetParameters& parameters, + std::shared_ptr nfp_device) { + QtAmiiboManagerDialog dialog(this, parameters, input_subsystem.get(), nfp_device); + + dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint | + Qt::WindowTitleHint | Qt::WindowSystemMenuHint); + dialog.setWindowModality(Qt::WindowModal); + if (dialog.exec() == QDialog::Rejected) { + emit AmiiboManagerFinished(false, {}); + return; + } + + emit AmiiboManagerFinished(true, dialog.GetName()); +} + void GMainWindow::ControllerSelectorReconfigureControllers( const Core::Frontend::ControllerParameters& parameters) { QtControllerSelectorDialog dialog(this, parameters, input_subsystem.get(), *system); @@ -1548,7 +1569,7 @@ bool GMainWindow::LoadROM(const QString& filename, u64 program_id, std::size_t p system->SetFilesystem(vfs); system->SetAppletFrontendSet({ - nullptr, // Amiibo Manager + std::make_unique(*this), // Amiibo Manager std::make_unique(*this), // Controller Selector std::make_unique(*this), // Error Display nullptr, // Mii Editor diff --git a/src/yuzu/main.h b/src/yuzu/main.h index b73f550dd..2724ecd52 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -55,6 +55,7 @@ class System; } // namespace Core namespace Core::Frontend { +struct CabinetParameters; struct ControllerParameters; struct InlineAppearParameters; struct InlineTextParameters; @@ -82,6 +83,10 @@ enum class SwkbdReplyType : u32; enum class WebExitReason : u32; } // namespace Service::AM::Applets +namespace Service::NFP { +class NfpDevice; +} // namespace Service::NFP + namespace Ui { class MainWindow; } @@ -149,6 +154,8 @@ signals: void UpdateInstallProgress(); + void AmiiboManagerFinished(bool is_success, std::string name); + void ControllerSelectorReconfigureFinished(); void ErrorDisplayFinished(); @@ -170,6 +177,8 @@ public slots: void OnExecuteProgram(std::size_t program_index); void OnExit(); void OnSaveConfig(); + void AmiiboManagerShowDialog(const Core::Frontend::CabinetParameters& parameters, + std::shared_ptr nfp_device); void ControllerSelectorReconfigureControllers( const Core::Frontend::ControllerParameters& parameters); void SoftwareKeyboardInitialize( -- cgit v1.2.3 From a253d1557d7d1fb1add6ae923ccb452d423d4547 Mon Sep 17 00:00:00 2001 From: german77 Date: Sun, 13 Nov 2022 13:59:00 -0600 Subject: service: am: Fix cabinet applet result --- src/core/hle/service/am/applets/applet_cabinet.cpp | 20 ++++++++++++++------ src/core/hle/service/am/applets/applet_cabinet.h | 12 ++++++++---- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/core/hle/service/am/applets/applet_cabinet.cpp b/src/core/hle/service/am/applets/applet_cabinet.cpp index 1eb5a9f22..01f577ab9 100644 --- a/src/core/hle/service/am/applets/applet_cabinet.cpp +++ b/src/core/hle/service/am/applets/applet_cabinet.cpp @@ -32,7 +32,7 @@ void Cabinet::Initialize() { LOG_INFO(Service_HID, "Initializing Cabinet Applet."); - LOG_ERROR(Service_HID, + LOG_DEBUG(Service_HID, "Initializing Applet with common_args: arg_version={}, lib_version={}, " "play_startup_sound={}, size={}, system_tick={}, theme_color={}", common_args.arguments_version, common_args.library_version, @@ -111,14 +111,14 @@ void Cabinet::DisplayCompleted(bool apply_changes, const std::string& amiibo_nam Cancel(); } - if (nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagFound) { + if (nfp_device->GetCurrentState() == Service::NFP::DeviceState::TagFound) { nfp_device->Mount(Service::NFP::MountTarget::All); } switch (applet_input_common.applet_mode) { case Service::NFP::CabinetMode::StartNicknameAndOwnerSettings: { Service::NFP::AmiiboName name{}; - memccpy(name.data(), amiibo_name.data(), 0, name.size()); + memcpy(name.data(), amiibo_name.data(), std::min(amiibo_name.size(), name.size() - 1)); nfp_device->SetNicknameAndOwner(name); break; } @@ -137,11 +137,19 @@ void Cabinet::DisplayCompleted(bool apply_changes, const std::string& amiibo_nam } applet_output.device_handle = applet_input_common.device_handle; - applet_output.result = CabinetResult::Success; - nfp_device->GetRegisterInfo(applet_output.register_info); - nfp_device->GetTagInfo(applet_output.tag_info); + applet_output.result = CabinetResult::Cancel; + const auto reg_result = nfp_device->GetRegisterInfo(applet_output.register_info); + const auto tag_result = nfp_device->GetTagInfo(applet_output.tag_info); nfp_device->Finalize(); + if (reg_result.IsSuccess() && tag_result.IsSuccess()) { + applet_output.result = CabinetResult::All; + } else if (reg_result.IsSuccess()) { + applet_output.result = CabinetResult::RegisterInfo; + } else if (tag_result.IsSuccess()) { + applet_output.result = CabinetResult::TagInfo; + } + std::vector out_data(sizeof(ReturnValueForAmiiboSettings)); std::memcpy(out_data.data(), &applet_output, sizeof(ReturnValueForAmiiboSettings)); diff --git a/src/core/hle/service/am/applets/applet_cabinet.h b/src/core/hle/service/am/applets/applet_cabinet.h index 2d3f22434..8466d5997 100644 --- a/src/core/hle/service/am/applets/applet_cabinet.h +++ b/src/core/hle/service/am/applets/applet_cabinet.h @@ -31,18 +31,21 @@ enum class CabinetAppletVersion : s32 { enum class CabinetResult : u8 { Cancel, - Success, + TagInfo = 1 << 1, + RegisterInfo = 1 << 2, + All = TagInfo | RegisterInfo, }; // This is nn::nfp::AmiiboSettingsStartParam struct AmiiboSettingsStartParam { u64 device_handle; std::array param_1; - std::array param_2; + u8 param_2; }; static_assert(sizeof(AmiiboSettingsStartParam) == 0x30, "AmiiboSettingsStartParam is an invalid size"); +#pragma pack(1) // This is nn::nfp::StartParamForAmiiboSettings struct StartParamForAmiiboSettings { u8 param_1; @@ -53,7 +56,7 @@ struct StartParamForAmiiboSettings { Service::NFP::TagInfo tag_info; Service::NFP::RegisterInfo register_info; std::array amiibo_settings_3; - INSERT_PADDING_BYTES(0x20); + INSERT_PADDING_BYTES(0x24); }; static_assert(sizeof(StartParamForAmiiboSettings) == 0x1A8, "StartParamForAmiiboSettings is an invalid size"); @@ -67,8 +70,9 @@ struct ReturnValueForAmiiboSettings { Service::NFP::RegisterInfo register_info; INSERT_PADDING_BYTES(0x24); }; -static_assert(sizeof(ReturnValueForAmiiboSettings) == 0x190, +static_assert(sizeof(ReturnValueForAmiiboSettings) == 0x188, "ReturnValueForAmiiboSettings is an invalid size"); +#pragma pack() class Cabinet final : public Applet { public: -- cgit v1.2.3 From 75e6ec85e107d6e5422d882b97faaa813970d42e Mon Sep 17 00:00:00 2001 From: german77 Date: Sun, 13 Nov 2022 15:14:08 -0600 Subject: general: Address review comments --- src/core/frontend/applets/cabinet.cpp | 2 +- src/core/frontend/applets/cabinet.h | 7 +- src/core/hle/service/am/applets/applet_cabinet.cpp | 16 +- src/core/hle/service/am/applets/applet_cabinet.h | 11 +- src/core/hle/service/nfp/nfp_device.cpp | 4 +- src/input_common/drivers/virtual_amiibo.cpp | 2 +- src/input_common/drivers/virtual_amiibo.h | 2 +- src/yuzu/CMakeLists.txt | 6 +- src/yuzu/applets/qt_amiibo_manager.cpp | 247 ----------- src/yuzu/applets/qt_amiibo_manager.h | 93 ---- src/yuzu/applets/qt_amiibo_manager.ui | 491 -------------------- src/yuzu/applets/qt_amiibo_settings.cpp | 260 +++++++++++ src/yuzu/applets/qt_amiibo_settings.h | 83 ++++ src/yuzu/applets/qt_amiibo_settings.ui | 494 +++++++++++++++++++++ src/yuzu/main.cpp | 14 +- src/yuzu/main.h | 6 +- 16 files changed, 874 insertions(+), 864 deletions(-) delete mode 100644 src/yuzu/applets/qt_amiibo_manager.cpp delete mode 100644 src/yuzu/applets/qt_amiibo_manager.h delete mode 100644 src/yuzu/applets/qt_amiibo_manager.ui create mode 100644 src/yuzu/applets/qt_amiibo_settings.cpp create mode 100644 src/yuzu/applets/qt_amiibo_settings.h create mode 100644 src/yuzu/applets/qt_amiibo_settings.ui diff --git a/src/core/frontend/applets/cabinet.cpp b/src/core/frontend/applets/cabinet.cpp index 5ade75de0..26c7fefe3 100644 --- a/src/core/frontend/applets/cabinet.cpp +++ b/src/core/frontend/applets/cabinet.cpp @@ -11,7 +11,7 @@ namespace Core::Frontend { CabinetApplet::~CabinetApplet() = default; void DefaultCabinetApplet::ShowCabinetApplet( - std::function callback, const CabinetParameters& parameters, + const CabinetCallback& callback, const CabinetParameters& parameters, std::shared_ptr nfp_device) const { LOG_WARNING(Service_AM, "(STUBBED) called"); callback(false, {}); diff --git a/src/core/frontend/applets/cabinet.h b/src/core/frontend/applets/cabinet.h index 1c68bf57d..c28a235c1 100644 --- a/src/core/frontend/applets/cabinet.h +++ b/src/core/frontend/applets/cabinet.h @@ -18,18 +18,19 @@ struct CabinetParameters { Service::NFP::CabinetMode mode; }; +using CabinetCallback = std::function; + class CabinetApplet { public: virtual ~CabinetApplet(); - virtual void ShowCabinetApplet(std::function callback, + virtual void ShowCabinetApplet(const CabinetCallback& callback, const CabinetParameters& parameters, std::shared_ptr nfp_device) const = 0; }; class DefaultCabinetApplet final : public CabinetApplet { public: - void ShowCabinetApplet(std::function callback, - const CabinetParameters& parameters, + void ShowCabinetApplet(const CabinetCallback& callback, const CabinetParameters& parameters, std::shared_ptr nfp_device) const override; }; diff --git a/src/core/hle/service/am/applets/applet_cabinet.cpp b/src/core/hle/service/am/applets/applet_cabinet.cpp index 01f577ab9..d0969b0f1 100644 --- a/src/core/hle/service/am/applets/applet_cabinet.cpp +++ b/src/core/hle/service/am/applets/applet_cabinet.cpp @@ -98,7 +98,7 @@ void Cabinet::Execute() { } } -void Cabinet::DisplayCompleted(bool apply_changes, const std::string& amiibo_name) { +void Cabinet::DisplayCompleted(bool apply_changes, std::string_view amiibo_name) { Service::Mii::MiiManager manager; ReturnValueForAmiiboSettings applet_output{}; @@ -118,7 +118,7 @@ void Cabinet::DisplayCompleted(bool apply_changes, const std::string& amiibo_nam switch (applet_input_common.applet_mode) { case Service::NFP::CabinetMode::StartNicknameAndOwnerSettings: { Service::NFP::AmiiboName name{}; - memcpy(name.data(), amiibo_name.data(), std::min(amiibo_name.size(), name.size() - 1)); + std::memcpy(name.data(), amiibo_name.data(), std::min(amiibo_name.size(), name.size() - 1)); nfp_device->SetNicknameAndOwner(name); break; } @@ -142,12 +142,12 @@ void Cabinet::DisplayCompleted(bool apply_changes, const std::string& amiibo_nam const auto tag_result = nfp_device->GetTagInfo(applet_output.tag_info); nfp_device->Finalize(); - if (reg_result.IsSuccess() && tag_result.IsSuccess()) { - applet_output.result = CabinetResult::All; - } else if (reg_result.IsSuccess()) { - applet_output.result = CabinetResult::RegisterInfo; - } else if (tag_result.IsSuccess()) { - applet_output.result = CabinetResult::TagInfo; + if (reg_result.IsSuccess()) { + applet_output.result |= CabinetResult::RegisterInfo; + } + + if (tag_result.IsSuccess()) { + applet_output.result |= CabinetResult::TagInfo; } std::vector out_data(sizeof(ReturnValueForAmiiboSettings)); diff --git a/src/core/hle/service/am/applets/applet_cabinet.h b/src/core/hle/service/am/applets/applet_cabinet.h index 8466d5997..84197a807 100644 --- a/src/core/hle/service/am/applets/applet_cabinet.h +++ b/src/core/hle/service/am/applets/applet_cabinet.h @@ -25,16 +25,17 @@ class NfpDevice; namespace Service::AM::Applets { -enum class CabinetAppletVersion : s32 { +enum class CabinetAppletVersion : u32 { Version1 = 0x1, }; enum class CabinetResult : u8 { - Cancel, + Cancel = 0, TagInfo = 1 << 1, RegisterInfo = 1 << 2, All = TagInfo | RegisterInfo, }; +DECLARE_ENUM_FLAG_OPERATORS(CabinetResult) // This is nn::nfp::AmiiboSettingsStartParam struct AmiiboSettingsStartParam { @@ -45,7 +46,7 @@ struct AmiiboSettingsStartParam { static_assert(sizeof(AmiiboSettingsStartParam) == 0x30, "AmiiboSettingsStartParam is an invalid size"); -#pragma pack(1) +#pragma pack(push, 1) // This is nn::nfp::StartParamForAmiiboSettings struct StartParamForAmiiboSettings { u8 param_1; @@ -72,7 +73,7 @@ struct ReturnValueForAmiiboSettings { }; static_assert(sizeof(ReturnValueForAmiiboSettings) == 0x188, "ReturnValueForAmiiboSettings is an invalid size"); -#pragma pack() +#pragma pack(pop) class Cabinet final : public Applet { public: @@ -86,7 +87,7 @@ public: Result GetStatus() const override; void ExecuteInteractive() override; void Execute() override; - void DisplayCompleted(bool apply_changes, const std::string& amiibo_name); + void DisplayCompleted(bool apply_changes, std::string_view amiibo_name); void Cancel(); private: diff --git a/src/core/hle/service/nfp/nfp_device.cpp b/src/core/hle/service/nfp/nfp_device.cpp index 2f9dfa9c2..e1bf90d7c 100644 --- a/src/core/hle/service/nfp/nfp_device.cpp +++ b/src/core/hle/service/nfp/nfp_device.cpp @@ -148,7 +148,7 @@ void NfpDevice::Finalize() { device_state = DeviceState::Unavailable; } -Result NfpDevice::StartDetection([[maybe_unused]] TagProtocol allowed_protocol) { +Result NfpDevice::StartDetection(TagProtocol allowed_protocol) { if (device_state != DeviceState::Initialized && device_state != DeviceState::TagRemoved) { LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); return WrongDeviceState; @@ -475,6 +475,8 @@ Result NfpDevice::OpenApplicationArea(u32 access_id) { } Result NfpDevice::GetApplicationAreaId(u32& application_area_id) const { + application_area_id = {}; + if (device_state != DeviceState::TagMounted) { LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); if (device_state == DeviceState::TagRemoved) { diff --git a/src/input_common/drivers/virtual_amiibo.cpp b/src/input_common/drivers/virtual_amiibo.cpp index 252c660d8..564a188e5 100644 --- a/src/input_common/drivers/virtual_amiibo.cpp +++ b/src/input_common/drivers/virtual_amiibo.cpp @@ -109,7 +109,7 @@ VirtualAmiibo::Info VirtualAmiibo::CloseAmiibo() { return Info::Success; } -std::string VirtualAmiibo::GetLastFilePath() { +std::string VirtualAmiibo::GetLastFilePath() const { return file_path; } diff --git a/src/input_common/drivers/virtual_amiibo.h b/src/input_common/drivers/virtual_amiibo.h index f2294b8b0..9baeb3997 100644 --- a/src/input_common/drivers/virtual_amiibo.h +++ b/src/input_common/drivers/virtual_amiibo.h @@ -50,7 +50,7 @@ public: Info ReloadAmiibo(); Info CloseAmiibo(); - std::string GetLastFilePath(); + std::string GetLastFilePath() const; private: static constexpr std::size_t amiibo_size = 0x21C; diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 8571d9c7c..adad36221 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -18,9 +18,9 @@ add_executable(yuzu about_dialog.cpp about_dialog.h aboutdialog.ui - applets/qt_amiibo_manager.cpp - applets/qt_amiibo_manager.h - applets/qt_amiibo_manager.ui + applets/qt_amiibo_settings.cpp + applets/qt_amiibo_settings.h + applets/qt_amiibo_settings.ui applets/qt_controller.cpp applets/qt_controller.h applets/qt_controller.ui diff --git a/src/yuzu/applets/qt_amiibo_manager.cpp b/src/yuzu/applets/qt_amiibo_manager.cpp deleted file mode 100644 index 9c7b15d06..000000000 --- a/src/yuzu/applets/qt_amiibo_manager.cpp +++ /dev/null @@ -1,247 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include -#include -#include -#include - -#include "common/assert.h" -#include "common/string_util.h" -#include "core/hle/service/nfp/nfp_device.h" -#include "core/hle/service/nfp/nfp_result.h" -#include "input_common/drivers/virtual_amiibo.h" -#include "input_common/main.h" -#include "ui_qt_amiibo_manager.h" -#include "web_service/web_backend.h" -#include "yuzu/applets/qt_amiibo_manager.h" -#include "yuzu/main.h" - -QtAmiiboManagerDialog::QtAmiiboManagerDialog(QWidget* parent, - Core::Frontend::CabinetParameters parameters_, - InputCommon::InputSubsystem* input_subsystem_, - std::shared_ptr nfp_device_) - : QDialog(parent), ui(std::make_unique()), - input_subsystem{input_subsystem_}, nfp_device{nfp_device_}, - parameters(std::move(parameters_)) { - ui->setupUi(this); - - LoadInfo(); - - resize(0, 0); -} - -QtAmiiboManagerDialog::~QtAmiiboManagerDialog() = default; - -int QtAmiiboManagerDialog::exec() { - if (!is_initalized) { - return QDialog::Rejected; - } - return QDialog::exec(); -} - -std::string QtAmiiboManagerDialog::GetName() { - return ui->amiiboCustomNameValue->text().toStdString(); -} - -void QtAmiiboManagerDialog::LoadInfo() { - if (input_subsystem->GetVirtualAmiibo()->ReloadAmiibo() != - InputCommon::VirtualAmiibo::Info::Success) { - return; - } - - if (nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagFound && - nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagMounted) { - return; - } - nfp_device->Mount(Service::NFP::MountTarget::All); - - Service::NFP::ModelInfo model_info{}; - const auto model_result = nfp_device->GetModelInfo(model_info); - - if (model_result.IsSuccess()) { - const auto amiibo_id = - fmt::format("{:04x}{:02x}{:02x}{:04x}{:02x}02", Common::swap16(model_info.character_id), - model_info.character_variant, model_info.amiibo_type, - model_info.model_number, model_info.series); - LOG_ERROR(Input, "{}", amiibo_id); - LoadAmiiboApiInfo(amiibo_id); - } - - LoadAmiiboData(); - LoadAmiiboGameInfo(); - - ui->amiiboDirectoryValue->setText( - QString::fromStdString(input_subsystem->GetVirtualAmiibo()->GetLastFilePath())); - - SetManagerDescription(); - is_initalized = true; -} - -void QtAmiiboManagerDialog::LoadAmiiboApiInfo(std::string amiibo_id) { - WebService::Client client{"https://amiiboapi.com", {}, {}}; - WebService::Client image_client{"https://raw.githubusercontent.com", {}, {}}; - const auto url_path = fmt::format("/api/amiibo/?id={}", amiibo_id); - - const auto amiibo_json = client.GetJson(url_path, true).returned_data; - if (amiibo_json.empty()) { - ui->amiiboImageLabel->setVisible(false); - ui->amiiboInfoGroup->setVisible(false); - return; - } - - std::string amiibo_series{}; - std::string amiibo_name{}; - std::string amiibo_image_url{}; - std::string amiibo_type{}; - - const auto parsed_amiibo_json_json = nlohmann::json::parse(amiibo_json).at("amiibo"); - parsed_amiibo_json_json.at("amiiboSeries").get_to(amiibo_series); - parsed_amiibo_json_json.at("name").get_to(amiibo_name); - parsed_amiibo_json_json.at("image").get_to(amiibo_image_url); - parsed_amiibo_json_json.at("type").get_to(amiibo_type); - - ui->amiiboSeriesValue->setText(QString::fromStdString(amiibo_series)); - ui->amiiboNameValue->setText(QString::fromStdString(amiibo_name)); - ui->amiiboTypeValue->setText(QString::fromStdString(amiibo_type)); - - if (amiibo_image_url.size() < 34) { - ui->amiiboImageLabel->setVisible(false); - } - - const auto image_url_path = amiibo_image_url.substr(34, amiibo_image_url.size() - 34); - const auto image_data = image_client.GetImage(image_url_path, true).returned_data; - - if (image_data.empty()) { - ui->amiiboImageLabel->setVisible(false); - } - - QPixmap pixmap; - pixmap.loadFromData(reinterpret_cast(image_data.data()), - static_cast(image_data.size())); - pixmap = pixmap.scaled(250, 350, Qt::AspectRatioMode::KeepAspectRatio, - Qt::TransformationMode::SmoothTransformation); - ui->amiiboImageLabel->setPixmap(pixmap); -} - -void QtAmiiboManagerDialog::LoadAmiiboData() { - Service::NFP::RegisterInfo register_info{}; - Service::NFP::CommonInfo common_info{}; - const auto register_result = nfp_device->GetRegisterInfo(register_info); - const auto common_result = nfp_device->GetCommonInfo(common_info); - - if (register_result.IsFailure()) { - ui->creationDateValue->setDisabled(true); - ui->modificationDateValue->setDisabled(true); - ui->amiiboCustomNameValue->setReadOnly(false); - ui->amiiboOwnerValue->setReadOnly(false); - return; - } - - if (parameters.mode == Service::NFP::CabinetMode::StartNicknameAndOwnerSettings) { - ui->creationDateValue->setDisabled(true); - ui->modificationDateValue->setDisabled(true); - } - - const auto amiibo_name = std::string(register_info.amiibo_name.data()); - const auto owner_name = Common::UTF16ToUTF8(register_info.mii_char_info.name.data()); - const auto creation_date = - QDate(register_info.creation_date.year, register_info.creation_date.month, - register_info.creation_date.day); - - ui->amiiboCustomNameValue->setText(QString::fromStdString(amiibo_name)); - ui->amiiboOwnerValue->setText(QString::fromStdString(owner_name)); - ui->amiiboCustomNameValue->setReadOnly(true); - ui->amiiboOwnerValue->setReadOnly(true); - ui->creationDateValue->setDate(creation_date); - - if (common_result.IsFailure()) { - ui->modificationDateValue->setDisabled(true); - return; - } - - const auto modification_date = - QDate(common_info.last_write_date.year, common_info.last_write_date.month, - common_info.last_write_date.day); - ui->modificationDateValue->setDate(modification_date); -} - -void QtAmiiboManagerDialog::LoadAmiiboGameInfo() { - u32 application_area_id{}; - const auto application_result = nfp_device->GetApplicationAreaId(application_area_id); - - if (application_result.IsFailure()) { - ui->gameIdValue->setVisible(false); - ui->gameIdLabel->setText(tr("No game data present")); - return; - } - - SetGameDataName(application_area_id); -} - -void QtAmiiboManagerDialog::SetGameDataName(u32 application_area_id) { - const std::array, 12> game_name_list = { - // 3ds, wii u - std::pair{0x10110E00, QStringLiteral("Super Smash Bros (3DS/WiiU)")}, - {0x00132600, QStringLiteral("Mario & Luigi: Paper Jam")}, - {0x0014F000, QStringLiteral("Animal Crossing: Happy Home Designer")}, - {0x00152600, QStringLiteral("Chibi-Robo!: Zip Lash")}, - {0x10161f00, QStringLiteral("Mario Party 10")}, - {0x1019C800, QStringLiteral("The Legend of Zelda: Twilight Princess HD")}, - // switch - {0x10162B00, QStringLiteral("Splatoon 2")}, - {0x1016e100, QStringLiteral("Shovel Knight: Treasure Trove")}, - {0x1019C800, QStringLiteral("The Legend of Zelda: Breath of the Wild")}, - {0x34F80200, QStringLiteral("Super Smash Bros. Ultimate")}, - {0x38600500, QStringLiteral("Splatoon 3")}, - {0x3B440400, QStringLiteral("The Legend of Zelda: Link's Awakening")}, - }; - - for (const auto& [game_id, game_name] : game_name_list) { - if (application_area_id == game_id) { - ui->gameIdValue->setText(game_name); - return; - } - } - - const auto application_area_string = fmt::format("{:016x}", application_area_id); - ui->gameIdValue->setText(QString::fromStdString(application_area_string)); -} - -void QtAmiiboManagerDialog::SetManagerDescription() { - switch (parameters.mode) { - case Service::NFP::CabinetMode::StartFormatter: - ui->cabinetActionDescriptionLabel->setText( - tr("The following amiibo data will be formated:")); - break; - case Service::NFP::CabinetMode::StartGameDataEraser: - ui->cabinetActionDescriptionLabel->setText(tr("The following game data will removed:")); - break; - case Service::NFP::CabinetMode::StartNicknameAndOwnerSettings: - ui->cabinetActionDescriptionLabel->setText(tr("Set nickname and owner:")); - break; - case Service::NFP::CabinetMode::StartRestorer: - ui->cabinetActionDescriptionLabel->setText(tr("Do you wish to restore this amiibo:")); - break; - } -} - -QtAmiiboManager::QtAmiiboManager(GMainWindow& parent) { - connect(this, &QtAmiiboManager::MainWindowShowAmiiboManager, &parent, - &GMainWindow::AmiiboManagerShowDialog, Qt::QueuedConnection); - connect(&parent, &GMainWindow::AmiiboManagerFinished, this, - &QtAmiiboManager::MainWindowFinished, Qt::QueuedConnection); -} - -QtAmiiboManager::~QtAmiiboManager() = default; - -void QtAmiiboManager::ShowCabinetApplet(std::function callback_, - const Core::Frontend::CabinetParameters& parameters, - std::shared_ptr nfp_device) const { - callback = std::move(callback_); - emit MainWindowShowAmiiboManager(parameters, nfp_device); -} - -void QtAmiiboManager::MainWindowFinished(bool is_success, std::string name) { - callback(is_success, name); -} diff --git a/src/yuzu/applets/qt_amiibo_manager.h b/src/yuzu/applets/qt_amiibo_manager.h deleted file mode 100644 index 3f5866ed7..000000000 --- a/src/yuzu/applets/qt_amiibo_manager.h +++ /dev/null @@ -1,93 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include -#include -#include -#include "core/frontend/applets/cabinet.h" - -class GMainWindow; -class QCheckBox; -class QComboBox; -class QDialogButtonBox; -class QGroupBox; -class QLabel; - -class InputProfiles; - -namespace InputCommon { -class InputSubsystem; -} - -namespace Ui { -class QtAmiiboManagerDialog; -} - -namespace Core { -class System; -} - -namespace Core::HID { -class HIDCore; -enum class NpadStyleIndex : u8; -} // namespace Core::HID - -namespace Service::NFP { -class NfpDevice; -} // namespace Service::NFP - -class QtAmiiboManagerDialog final : public QDialog { - Q_OBJECT - -public: - explicit QtAmiiboManagerDialog(QWidget* parent, Core::Frontend::CabinetParameters parameters_, - InputCommon::InputSubsystem* input_subsystem_, - std::shared_ptr nfp_device_); - ~QtAmiiboManagerDialog() override; - - int exec() override; - - std::string GetName(); - -private: - void LoadInfo(); - void LoadAmiiboApiInfo(std::string amiibo_id); - void LoadAmiiboData(); - void LoadAmiiboGameInfo(); - void SetGameDataName(u32 application_area_id); - void SetManagerDescription(); - - std::unique_ptr ui; - - InputCommon::InputSubsystem* input_subsystem; - std::shared_ptr nfp_device; - - // Parameters sent in from the backend HLE applet. - Core::Frontend::CabinetParameters parameters; - - // If false amiibo manager failed to load - bool is_initalized{}; -}; - -class QtAmiiboManager final : public QObject, public Core::Frontend::CabinetApplet { - Q_OBJECT - -public: - explicit QtAmiiboManager(GMainWindow& parent); - ~QtAmiiboManager() override; - - void ShowCabinetApplet(std::function callback_, - const Core::Frontend::CabinetParameters& parameters, - std::shared_ptr nfp_device) const override; - -signals: - void MainWindowShowAmiiboManager(const Core::Frontend::CabinetParameters& parameters, - std::shared_ptr nfp_device) const; - -private: - void MainWindowFinished(bool is_success, std::string name); - - mutable std::function callback; -}; diff --git a/src/yuzu/applets/qt_amiibo_manager.ui b/src/yuzu/applets/qt_amiibo_manager.ui deleted file mode 100644 index eb6eabe59..000000000 --- a/src/yuzu/applets/qt_amiibo_manager.ui +++ /dev/null @@ -1,491 +0,0 @@ - - - QtAmiiboManagerDialog - - - - 0 - 0 - 839 - 500 - - - - Amiibo Manager - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 10 - - - 20 - - - 15 - - - 0 - - - 15 - - - - - - 12 - 75 - true - - - - - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - false - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - 20 - - - 15 - - - - - - 250 - 350 - - - - - 236 - 350 - - - - - - - Qt::AlignCenter - - - - - - - 20 - - - 8 - - - 15 - - - - - Amiibo Info - - - - - - - - Series - - - - - - - - 0 - 0 - - - - true - - - - - - - Type - - - - - - - - 0 - 0 - - - - true - - - - - - - Name - - - - - - - - 0 - 0 - - - - true - - - - - - - - - - - - Amiibo Data - - - - - - - - Custom Name - - - - - - - - 0 - 0 - - - - 10 - - - - - - - Owner - - - - - - - - 0 - 0 - - - - 10 - - - - - - - Creation Date - - - - - - - true - - - - 1970 - 1 - 1 - - - - dd/MM/yyyy - - - - - - - Modification Date - - - - - - - true - - - - 1970 - 1 - 1 - - - - dd/MM/yyyy - - - - - - - - - - - - - 500 - 0 - - - - Game Data - - - - - - Game Id - - - - - - - - 0 - 0 - - - - true - - - - - - - - - - - 500 - 0 - - - - Mount Amiibo - - - - - - ... - - - - - - - Qt::Horizontal - - - QSizePolicy::Maximum - - - - 60 - 20 - - - - - - - - File Path - - - - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - - - - - 15 - - - 15 - - - 8 - - - 20 - - - 8 - - - - - true - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - - - - - - - - - buttonBox - accepted() - QtAmiiboManagerDialog - accept() - - - buttonBox - rejected() - QtAmiiboManagerDialog - reject() - - - diff --git a/src/yuzu/applets/qt_amiibo_settings.cpp b/src/yuzu/applets/qt_amiibo_settings.cpp new file mode 100644 index 000000000..efb7f6ecc --- /dev/null +++ b/src/yuzu/applets/qt_amiibo_settings.cpp @@ -0,0 +1,260 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include +#include +#include + +#include "common/assert.h" +#include "common/string_util.h" +#include "core/hle/service/nfp/nfp_device.h" +#include "core/hle/service/nfp/nfp_result.h" +#include "input_common/drivers/virtual_amiibo.h" +#include "input_common/main.h" +#include "ui_qt_amiibo_settings.h" +#include "web_service/web_backend.h" +#include "yuzu/applets/qt_amiibo_settings.h" +#include "yuzu/main.h" + +QtAmiiboSettingsDialog::QtAmiiboSettingsDialog(QWidget* parent, + Core::Frontend::CabinetParameters parameters_, + InputCommon::InputSubsystem* input_subsystem_, + std::shared_ptr nfp_device_) + : QDialog(parent), ui(std::make_unique()), + input_subsystem{input_subsystem_}, nfp_device{std::move(nfp_device_)}, + parameters(std::move(parameters_)) { + ui->setupUi(this); + + LoadInfo(); + + resize(0, 0); +} + +QtAmiiboSettingsDialog::~QtAmiiboSettingsDialog() = default; + +int QtAmiiboSettingsDialog::exec() { + if (!is_initalized) { + return QDialog::Rejected; + } + return QDialog::exec(); +} + +std::string QtAmiiboSettingsDialog::GetName() const { + return ui->amiiboCustomNameValue->text().toStdString(); +} + +void QtAmiiboSettingsDialog::LoadInfo() { + if (input_subsystem->GetVirtualAmiibo()->ReloadAmiibo() != + InputCommon::VirtualAmiibo::Info::Success) { + return; + } + + if (nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagFound && + nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagMounted) { + return; + } + nfp_device->Mount(Service::NFP::MountTarget::All); + + LoadAmiiboInfo(); + LoadAmiiboData(); + LoadAmiiboGameInfo(); + + ui->amiiboDirectoryValue->setText( + QString::fromStdString(input_subsystem->GetVirtualAmiibo()->GetLastFilePath())); + + SetSettingsDescription(); + is_initalized = true; +} + +void QtAmiiboSettingsDialog::LoadAmiiboInfo() { + Service::NFP::ModelInfo model_info{}; + const auto model_result = nfp_device->GetModelInfo(model_info); + + if (model_result.IsFailure()) { + ui->amiiboImageLabel->setVisible(false); + ui->amiiboInfoGroup->setVisible(false); + return; + } + + const auto amiibo_id = + fmt::format("{:04x}{:02x}{:02x}{:04x}{:02x}02", Common::swap16(model_info.character_id), + model_info.character_variant, model_info.amiibo_type, model_info.model_number, + model_info.series); + + LOG_DEBUG(Frontend, "Loading amiibo id {}", amiibo_id); + // Note: This function is not being used until we host the images on our server + // LoadAmiiboApiInfo(amiibo_id); + ui->amiiboImageLabel->setVisible(false); + ui->amiiboInfoGroup->setVisible(false); +} + +void QtAmiiboSettingsDialog::LoadAmiiboApiInfo(std::string_view amiibo_id) { + // TODO: Host this data on our website + WebService::Client client{"https://amiiboapi.com", {}, {}}; + WebService::Client image_client{"https://raw.githubusercontent.com", {}, {}}; + const auto url_path = fmt::format("/api/amiibo/?id={}", amiibo_id); + + const auto amiibo_json = client.GetJson(url_path, true).returned_data; + if (amiibo_json.empty()) { + ui->amiiboImageLabel->setVisible(false); + ui->amiiboInfoGroup->setVisible(false); + return; + } + + std::string amiibo_series{}; + std::string amiibo_name{}; + std::string amiibo_image_url{}; + std::string amiibo_type{}; + + const auto parsed_amiibo_json_json = nlohmann::json::parse(amiibo_json).at("amiibo"); + parsed_amiibo_json_json.at("amiiboSeries").get_to(amiibo_series); + parsed_amiibo_json_json.at("name").get_to(amiibo_name); + parsed_amiibo_json_json.at("image").get_to(amiibo_image_url); + parsed_amiibo_json_json.at("type").get_to(amiibo_type); + + ui->amiiboSeriesValue->setText(QString::fromStdString(amiibo_series)); + ui->amiiboNameValue->setText(QString::fromStdString(amiibo_name)); + ui->amiiboTypeValue->setText(QString::fromStdString(amiibo_type)); + + if (amiibo_image_url.size() < 34) { + ui->amiiboImageLabel->setVisible(false); + } + + const auto image_url_path = amiibo_image_url.substr(34, amiibo_image_url.size() - 34); + const auto image_data = image_client.GetImage(image_url_path, true).returned_data; + + if (image_data.empty()) { + ui->amiiboImageLabel->setVisible(false); + } + + QPixmap pixmap; + pixmap.loadFromData(reinterpret_cast(image_data.data()), + static_cast(image_data.size())); + pixmap = pixmap.scaled(250, 350, Qt::AspectRatioMode::KeepAspectRatio, + Qt::TransformationMode::SmoothTransformation); + ui->amiiboImageLabel->setPixmap(pixmap); +} + +void QtAmiiboSettingsDialog::LoadAmiiboData() { + Service::NFP::RegisterInfo register_info{}; + Service::NFP::CommonInfo common_info{}; + const auto register_result = nfp_device->GetRegisterInfo(register_info); + const auto common_result = nfp_device->GetCommonInfo(common_info); + + if (register_result.IsFailure()) { + ui->creationDateValue->setDisabled(true); + ui->modificationDateValue->setDisabled(true); + ui->amiiboCustomNameValue->setReadOnly(false); + ui->amiiboOwnerValue->setReadOnly(false); + return; + } + + if (parameters.mode == Service::NFP::CabinetMode::StartNicknameAndOwnerSettings) { + ui->creationDateValue->setDisabled(true); + ui->modificationDateValue->setDisabled(true); + } + + const auto amiibo_name = std::string(register_info.amiibo_name.data()); + const auto owner_name = Common::UTF16ToUTF8(register_info.mii_char_info.name.data()); + const auto creation_date = + QDate(register_info.creation_date.year, register_info.creation_date.month, + register_info.creation_date.day); + + ui->amiiboCustomNameValue->setText(QString::fromStdString(amiibo_name)); + ui->amiiboOwnerValue->setText(QString::fromStdString(owner_name)); + ui->amiiboCustomNameValue->setReadOnly(true); + ui->amiiboOwnerValue->setReadOnly(true); + ui->creationDateValue->setDate(creation_date); + + if (common_result.IsFailure()) { + ui->modificationDateValue->setDisabled(true); + return; + } + + const auto modification_date = + QDate(common_info.last_write_date.year, common_info.last_write_date.month, + common_info.last_write_date.day); + ui->modificationDateValue->setDate(modification_date); +} + +void QtAmiiboSettingsDialog::LoadAmiiboGameInfo() { + u32 application_area_id{}; + const auto application_result = nfp_device->GetApplicationAreaId(application_area_id); + + if (application_result.IsFailure()) { + ui->gameIdValue->setVisible(false); + ui->gameIdLabel->setText(tr("No game data present")); + return; + } + + SetGameDataName(application_area_id); +} + +void QtAmiiboSettingsDialog::SetGameDataName(u32 application_area_id) { + static constexpr std::array, 12> game_name_list = { + // 3ds, wii u + std::pair{0x10110E00, "Super Smash Bros (3DS/WiiU)"}, + {0x00132600, "Mario & Luigi: Paper Jam"}, + {0x0014F000, "Animal Crossing: Happy Home Designer"}, + {0x00152600, "Chibi-Robo!: Zip Lash"}, + {0x10161f00, "Mario Party 10"}, + {0x1019C800, "The Legend of Zelda: Twilight Princess HD"}, + // switch + {0x10162B00, "Splatoon 2"}, + {0x1016e100, "Shovel Knight: Treasure Trove"}, + {0x1019C800, "The Legend of Zelda: Breath of the Wild"}, + {0x34F80200, "Super Smash Bros. Ultimate"}, + {0x38600500, "Splatoon 3"}, + {0x3B440400, "The Legend of Zelda: Link's Awakening"}, + }; + + for (const auto& [game_id, game_name] : game_name_list) { + if (application_area_id == game_id) { + ui->gameIdValue->setText(QString::fromStdString(game_name)); + return; + } + } + + const auto application_area_string = fmt::format("{:016x}", application_area_id); + ui->gameIdValue->setText(QString::fromStdString(application_area_string)); +} + +void QtAmiiboSettingsDialog::SetSettingsDescription() { + switch (parameters.mode) { + case Service::NFP::CabinetMode::StartFormatter: + ui->cabinetActionDescriptionLabel->setText( + tr("The following amiibo data will be formatted:")); + break; + case Service::NFP::CabinetMode::StartGameDataEraser: + ui->cabinetActionDescriptionLabel->setText(tr("The following game data will removed:")); + break; + case Service::NFP::CabinetMode::StartNicknameAndOwnerSettings: + ui->cabinetActionDescriptionLabel->setText(tr("Set nickname and owner:")); + break; + case Service::NFP::CabinetMode::StartRestorer: + ui->cabinetActionDescriptionLabel->setText(tr("Do you wish to restore this amiibo?")); + break; + } +} + +QtAmiiboSettings::QtAmiiboSettings(GMainWindow& parent) { + connect(this, &QtAmiiboSettings::MainWindowShowAmiiboSettings, &parent, + &GMainWindow::AmiiboSettingsShowDialog, Qt::QueuedConnection); + connect(&parent, &GMainWindow::AmiiboSettingsFinished, this, + &QtAmiiboSettings::MainWindowFinished, Qt::QueuedConnection); +} + +QtAmiiboSettings::~QtAmiiboSettings() = default; + +void QtAmiiboSettings::ShowCabinetApplet( + const Core::Frontend::CabinetCallback& callback_, + const Core::Frontend::CabinetParameters& parameters, + std::shared_ptr nfp_device) const { + callback = std::move(callback_); + emit MainWindowShowAmiiboSettings(parameters, nfp_device); +} + +void QtAmiiboSettings::MainWindowFinished(bool is_success, const std::string& name) { + callback(is_success, name); +} diff --git a/src/yuzu/applets/qt_amiibo_settings.h b/src/yuzu/applets/qt_amiibo_settings.h new file mode 100644 index 000000000..930c96739 --- /dev/null +++ b/src/yuzu/applets/qt_amiibo_settings.h @@ -0,0 +1,83 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include +#include +#include "core/frontend/applets/cabinet.h" + +class GMainWindow; +class QCheckBox; +class QComboBox; +class QDialogButtonBox; +class QGroupBox; +class QLabel; + +namespace InputCommon { +class InputSubsystem; +} + +namespace Ui { +class QtAmiiboSettingsDialog; +} + +namespace Service::NFP { +class NfpDevice; +} // namespace Service::NFP + +class QtAmiiboSettingsDialog final : public QDialog { + Q_OBJECT + +public: + explicit QtAmiiboSettingsDialog(QWidget* parent, Core::Frontend::CabinetParameters parameters_, + InputCommon::InputSubsystem* input_subsystem_, + std::shared_ptr nfp_device_); + ~QtAmiiboSettingsDialog() override; + + int exec() override; + + std::string GetName() const; + +private: + void LoadInfo(); + void LoadAmiiboInfo(); + void LoadAmiiboApiInfo(std::string_view amiibo_id); + void LoadAmiiboData(); + void LoadAmiiboGameInfo(); + void SetGameDataName(u32 application_area_id); + void SetSettingsDescription(); + + std::unique_ptr ui; + + InputCommon::InputSubsystem* input_subsystem; + std::shared_ptr nfp_device; + + // Parameters sent in from the backend HLE applet. + Core::Frontend::CabinetParameters parameters; + + // If false amiibo settings failed to load + bool is_initalized{}; +}; + +class QtAmiiboSettings final : public QObject, public Core::Frontend::CabinetApplet { + Q_OBJECT + +public: + explicit QtAmiiboSettings(GMainWindow& parent); + ~QtAmiiboSettings() override; + + void ShowCabinetApplet(const Core::Frontend::CabinetCallback& callback_, + const Core::Frontend::CabinetParameters& parameters, + std::shared_ptr nfp_device) const override; + +signals: + void MainWindowShowAmiiboSettings(const Core::Frontend::CabinetParameters& parameters, + std::shared_ptr nfp_device) const; + +private: + void MainWindowFinished(bool is_success, const std::string& name); + + mutable Core::Frontend::CabinetCallback callback; +}; diff --git a/src/yuzu/applets/qt_amiibo_settings.ui b/src/yuzu/applets/qt_amiibo_settings.ui new file mode 100644 index 000000000..f377a6e61 --- /dev/null +++ b/src/yuzu/applets/qt_amiibo_settings.ui @@ -0,0 +1,494 @@ + + + QtAmiiboSettingsDialog + + + + 0 + 0 + 839 + 500 + + + + Amiibo Settings + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 10 + + + 20 + + + 15 + + + 0 + + + 15 + + + + + + 12 + 75 + true + + + + + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + false + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 20 + + + 15 + + + 15 + + + + + + 250 + 350 + + + + + 236 + 350 + + + + + + + Qt::AlignCenter + + + + + + + 0 + + + 8 + + + 15 + + + + + Amiibo Info + + + + + + + + Series + + + + + + + + 0 + 0 + + + + true + + + + + + + Type + + + + + + + + 0 + 0 + + + + true + + + + + + + Name + + + + + + + + 0 + 0 + + + + true + + + + + + + + + + + + Amiibo Data + + + + + + + + Custom Name + + + + + + + + 0 + 0 + + + + 10 + + + + + + + Owner + + + + + + + + 0 + 0 + + + + 10 + + + + + + + Creation Date + + + + + + + true + + + + 1970 + 1 + 1 + + + + dd/MM/yyyy + + + + + + + Modification Date + + + + + + + true + + + + 1970 + 1 + 1 + + + + dd/MM/yyyy + + + + + + + + + + + + + 500 + 0 + + + + Game Data + + + + + + Game Id + + + + + + + + 0 + 0 + + + + true + + + + + + + + + + + 500 + 0 + + + + Mount Amiibo + + + + + + ... + + + + + + + Qt::Horizontal + + + QSizePolicy::Maximum + + + + 60 + 20 + + + + + + + + File Path + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + + + 15 + + + 15 + + + 8 + + + 20 + + + 8 + + + + + true + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + + + + + + buttonBox + accepted() + QtAmiiboSettingsDialog + accept() + + + buttonBox + rejected() + QtAmiiboSettingsDialog + reject() + + + diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 27266cae3..33f9237e2 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -15,7 +15,7 @@ #endif // VFS includes must be before glad as they will conflict with Windows file api, which uses defines. -#include "applets/qt_amiibo_manager.h" +#include "applets/qt_amiibo_settings.h" #include "applets/qt_controller.h" #include "applets/qt_error.h" #include "applets/qt_profile_select.h" @@ -577,19 +577,19 @@ void GMainWindow::RegisterMetaTypes() { qRegisterMetaType("Core::SystemResultStatus"); } -void GMainWindow::AmiiboManagerShowDialog(const Core::Frontend::CabinetParameters& parameters, - std::shared_ptr nfp_device) { - QtAmiiboManagerDialog dialog(this, parameters, input_subsystem.get(), nfp_device); +void GMainWindow::AmiiboSettingsShowDialog(const Core::Frontend::CabinetParameters& parameters, + std::shared_ptr nfp_device) { + QtAmiiboSettingsDialog dialog(this, parameters, input_subsystem.get(), nfp_device); dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint | Qt::WindowTitleHint | Qt::WindowSystemMenuHint); dialog.setWindowModality(Qt::WindowModal); if (dialog.exec() == QDialog::Rejected) { - emit AmiiboManagerFinished(false, {}); + emit AmiiboSettingsFinished(false, {}); return; } - emit AmiiboManagerFinished(true, dialog.GetName()); + emit AmiiboSettingsFinished(true, dialog.GetName()); } void GMainWindow::ControllerSelectorReconfigureControllers( @@ -1569,7 +1569,7 @@ bool GMainWindow::LoadROM(const QString& filename, u64 program_id, std::size_t p system->SetFilesystem(vfs); system->SetAppletFrontendSet({ - std::make_unique(*this), // Amiibo Manager + std::make_unique(*this), // Amiibo Settings std::make_unique(*this), // Controller Selector std::make_unique(*this), // Error Display nullptr, // Mii Editor diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 2724ecd52..6a9992d05 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -154,7 +154,7 @@ signals: void UpdateInstallProgress(); - void AmiiboManagerFinished(bool is_success, std::string name); + void AmiiboSettingsFinished(bool is_success, const std::string& name); void ControllerSelectorReconfigureFinished(); @@ -177,8 +177,8 @@ public slots: void OnExecuteProgram(std::size_t program_index); void OnExit(); void OnSaveConfig(); - void AmiiboManagerShowDialog(const Core::Frontend::CabinetParameters& parameters, - std::shared_ptr nfp_device); + void AmiiboSettingsShowDialog(const Core::Frontend::CabinetParameters& parameters, + std::shared_ptr nfp_device); void ControllerSelectorReconfigureControllers( const Core::Frontend::ControllerParameters& parameters); void SoftwareKeyboardInitialize( -- cgit v1.2.3 From 6fa3faec658893c9fae19116232d24dac08babc7 Mon Sep 17 00:00:00 2001 From: Kyle Kienapfel Date: Fri, 11 Nov 2022 04:12:37 -0800 Subject: Add break for default cases Visual Studio has an option to search all files in a solution, so I did a search in there for "default:" looking for any missing break statements. I've left out default statements that return something, and that throw something, even if via ThrowInvalidType. UNREACHABLE leads towards throw R_THROW macro leads towards a return --- src/audio_core/renderer/performance/performance_manager.cpp | 1 + src/common/atomic_helpers.h | 1 + src/core/hle/kernel/init/init_slab_setup.cpp | 1 + src/core/hle/kernel/k_page_table.cpp | 3 +++ src/core/hle/kernel/k_process.cpp | 1 + src/core/hle/service/am/applets/applet_error.cpp | 1 + src/core/hle/service/am/applets/applet_general_backend.cpp | 2 ++ src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp | 5 ++--- src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp | 5 ++--- src/core/hle/service/service.cpp | 1 + src/core/hle/service/time/time_zone_manager.cpp | 1 + src/video_core/engines/maxwell_dma.cpp | 1 + src/video_core/engines/puller.cpp | 4 ++++ src/video_core/macro/macro_interpreter.cpp | 2 ++ src/video_core/macro/macro_jit_x64.cpp | 1 + src/video_core/renderer_opengl/gl_texture_cache.cpp | 2 ++ src/video_core/renderer_opengl/renderer_opengl.cpp | 1 + src/video_core/renderer_vulkan/vk_scheduler.cpp | 1 + src/video_core/renderer_vulkan/vk_texture_cache.cpp | 1 + src/video_core/textures/decoders.cpp | 3 +++ src/yuzu/compatdb.cpp | 1 + src/yuzu/main.cpp | 3 +++ src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp | 1 + src/yuzu_cmd/yuzu.cpp | 1 + 24 files changed, 38 insertions(+), 6 deletions(-) diff --git a/src/audio_core/renderer/performance/performance_manager.cpp b/src/audio_core/renderer/performance/performance_manager.cpp index fd5873e1e..8aa0f5ed0 100644 --- a/src/audio_core/renderer/performance/performance_manager.cpp +++ b/src/audio_core/renderer/performance/performance_manager.cpp @@ -26,6 +26,7 @@ void PerformanceManager::CreateImpl(const size_t version) { impl = std::make_unique< PerformanceManagerImpl>(); + break; } } diff --git a/src/common/atomic_helpers.h b/src/common/atomic_helpers.h index bef5015c1..aef3b66a4 100644 --- a/src/common/atomic_helpers.h +++ b/src/common/atomic_helpers.h @@ -156,6 +156,7 @@ AE_FORCEINLINE void compiler_fence(memory_order order) AE_NO_TSAN { break; default: assert(false); + break; } } diff --git a/src/core/hle/kernel/init/init_slab_setup.cpp b/src/core/hle/kernel/init/init_slab_setup.cpp index bda098511..7b363eb1e 100644 --- a/src/core/hle/kernel/init/init_slab_setup.cpp +++ b/src/core/hle/kernel/init/init_slab_setup.cpp @@ -243,6 +243,7 @@ void InitializeSlabHeaps(Core::System& system, KMemoryLayout& memory_layout) { // If we somehow get an invalid type, abort. default: ASSERT_MSG(false, "Unknown slab type: {}", slab_types[i]); + break; } // If we've hit the end of a gap, free it. diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp index 5387bf5fe..612fc76fa 100644 --- a/src/core/hle/kernel/k_page_table.cpp +++ b/src/core/hle/kernel/k_page_table.cpp @@ -2301,6 +2301,7 @@ Result KPageTable::SetProcessMemoryPermission(VAddr addr, size_t size, break; default: ASSERT(false); + break; } } @@ -2803,6 +2804,7 @@ Result KPageTable::Operate(VAddr addr, size_t num_pages, const KPageGroup& page_ break; default: ASSERT(false); + break; } addr += size; @@ -2838,6 +2840,7 @@ Result KPageTable::Operate(VAddr addr, size_t num_pages, KMemoryPermission perm, break; default: ASSERT(false); + break; } R_SUCCEED(); } diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp index 55a9c5fae..d1dc62401 100644 --- a/src/core/hle/kernel/k_process.cpp +++ b/src/core/hle/kernel/k_process.cpp @@ -395,6 +395,7 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std: default: ASSERT(false); + break; } // Create TLS region diff --git a/src/core/hle/service/am/applets/applet_error.cpp b/src/core/hle/service/am/applets/applet_error.cpp index fcf34bf7e..bae0d99a6 100644 --- a/src/core/hle/service/am/applets/applet_error.cpp +++ b/src/core/hle/service/am/applets/applet_error.cpp @@ -144,6 +144,7 @@ void Error::Initialize() { break; default: UNIMPLEMENTED_MSG("Unimplemented LibAppletError mode={:02X}!", mode); + break; } } diff --git a/src/core/hle/service/am/applets/applet_general_backend.cpp b/src/core/hle/service/am/applets/applet_general_backend.cpp index c34ef08b3..e50acdaf6 100644 --- a/src/core/hle/service/am/applets/applet_general_backend.cpp +++ b/src/core/hle/service/am/applets/applet_general_backend.cpp @@ -129,6 +129,7 @@ void Auth::Execute() { } default: unimplemented_log(); + break; } } @@ -192,6 +193,7 @@ void PhotoViewer::Execute() { break; default: UNIMPLEMENTED_MSG("Unimplemented PhotoViewer applet mode={:02X}!", mode); + break; } } diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp index ced57dfe6..b97813fbc 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp @@ -300,11 +300,10 @@ Kernel::KEvent* nvhost_ctrl_gpu::QueryEvent(u32 event_id) { return error_notifier_event; case 2: return unknown_event; - default: { + default: LOG_CRITICAL(Service_NVDRV, "Unknown Ctrl GPU Event {}", event_id); + return nullptr; } - } - return nullptr; } } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index 45a759fa8..e123564c6 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -364,11 +364,10 @@ Kernel::KEvent* nvhost_gpu::QueryEvent(u32 event_id) { return sm_exception_breakpoint_pause_report_event; case 3: return error_notifier_event; - default: { + default: LOG_CRITICAL(Service_NVDRV, "Unknown Ctrl GPU Event {}", event_id); + return nullptr; } - } - return nullptr; } } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 5ab41c0c4..0de67f1e1 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -228,6 +228,7 @@ Result ServiceFrameworkBase::HandleSyncRequest(Kernel::KServerSession& session, } UNIMPLEMENTED_MSG("command_type={}", ctx.GetCommandType()); + break; } // If emulation was shutdown, we are closing service threads, do not write the response back to diff --git a/src/core/hle/service/time/time_zone_manager.cpp b/src/core/hle/service/time/time_zone_manager.cpp index 2aa675df9..f9ada7c93 100644 --- a/src/core/hle/service/time/time_zone_manager.cpp +++ b/src/core/hle/service/time/time_zone_manager.cpp @@ -280,6 +280,7 @@ static constexpr int TransitionTime(int year, Rule rule, int offset) { } default: ASSERT(false); + break; } return value + rule.transition_time + offset; } diff --git a/src/video_core/engines/maxwell_dma.cpp b/src/video_core/engines/maxwell_dma.cpp index 4eb7a100d..27be4af87 100644 --- a/src/video_core/engines/maxwell_dma.cpp +++ b/src/video_core/engines/maxwell_dma.cpp @@ -311,6 +311,7 @@ void MaxwellDMA::ReleaseSemaphore() { } default: ASSERT_MSG(false, "Unknown semaphore type: {}", static_cast(type.Value())); + break; } } diff --git a/src/video_core/engines/puller.cpp b/src/video_core/engines/puller.cpp index 3977bb0fb..4d2278811 100644 --- a/src/video_core/engines/puller.cpp +++ b/src/video_core/engines/puller.cpp @@ -50,6 +50,7 @@ void Puller::ProcessBindMethod(const MethodCall& method_call) { break; default: UNIMPLEMENTED_MSG("Unimplemented engine {:04X}", engine_id); + break; } } @@ -65,6 +66,7 @@ void Puller::ProcessFenceActionMethod() { break; default: UNIMPLEMENTED_MSG("Unimplemented operation {}", regs.fence_action.op.Value()); + break; } } @@ -228,6 +230,7 @@ void Puller::CallEngineMethod(const MethodCall& method_call) { break; default: UNIMPLEMENTED_MSG("Unimplemented engine"); + break; } } @@ -254,6 +257,7 @@ void Puller::CallEngineMultiMethod(u32 method, u32 subchannel, const u32* base_s break; default: UNIMPLEMENTED_MSG("Unimplemented engine"); + break; } } diff --git a/src/video_core/macro/macro_interpreter.cpp b/src/video_core/macro/macro_interpreter.cpp index c0d32c112..0d63495a9 100644 --- a/src/video_core/macro/macro_interpreter.cpp +++ b/src/video_core/macro/macro_interpreter.cpp @@ -201,6 +201,7 @@ bool MacroInterpreterImpl::Step(bool is_delay_slot) { } default: UNIMPLEMENTED_MSG("Unimplemented macro operation {}", opcode.operation.Value()); + break; } // An instruction with the Exit flag will not actually @@ -297,6 +298,7 @@ void MacroInterpreterImpl::ProcessResult(Macro::ResultOperation operation, u32 r break; default: UNIMPLEMENTED_MSG("Unimplemented result operation {}", operation); + break; } } diff --git a/src/video_core/macro/macro_jit_x64.cpp b/src/video_core/macro/macro_jit_x64.cpp index 25c1ce798..7347cbd88 100644 --- a/src/video_core/macro/macro_jit_x64.cpp +++ b/src/video_core/macro/macro_jit_x64.cpp @@ -652,6 +652,7 @@ void MacroJITx64Impl::Compile_ProcessResult(Macro::ResultOperation operation, u3 break; default: UNIMPLEMENTED_MSG("Unimplemented macro operation {}", operation); + break; } } diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp index 99cd11d1e..9f7ce7414 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.cpp +++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp @@ -891,6 +891,7 @@ void Image::CopyBufferToImage(const VideoCommon::BufferImageCopy& copy, size_t b break; default: ASSERT(false); + break; } } @@ -927,6 +928,7 @@ void Image::CopyImageToBuffer(const VideoCommon::BufferImageCopy& copy, size_t b break; default: ASSERT(false); + break; } // Compressed formats don't have a pixel format or type const bool is_compressed = gl_format == GL_NONE; diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 8bd5eba7e..f29462f7c 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -340,6 +340,7 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture, texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV; // UNIMPLEMENTED_MSG("Unknown framebuffer pixel format: {}", // static_cast(framebuffer.pixel_format)); + break; } texture.resource.Release(); diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp index 7934f2a51..4a7b633b7 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.cpp +++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp @@ -221,6 +221,7 @@ void Scheduler::SubmitExecution(VkSemaphore signal_semaphore, VkSemaphore wait_s [[fallthrough]]; default: vk::Check(result); + break; } }); chunk->MarkSubmit(); diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index 853b80d8a..a65bbeb1c 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -108,6 +108,7 @@ constexpr VkBorderColor ConvertBorderColor(const std::array& color) { break; default: ASSERT_MSG(false, "Invalid surface type"); + break; } } if (info.storage) { diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp index fd1a4b987..59120cd09 100644 --- a/src/video_core/textures/decoders.cpp +++ b/src/video_core/textures/decoders.cpp @@ -170,6 +170,7 @@ void Swizzle(std::span output, std::span input, u32 bytes_per_pixe #undef BPP_CASE default: ASSERT_MSG(false, "Invalid bytes_per_pixel={}", bytes_per_pixel); + break; } } @@ -217,6 +218,7 @@ void SwizzleSubrect(std::span output, std::span input, u32 bytes_p #undef BPP_CASE default: ASSERT_MSG(false, "Invalid bytes_per_pixel={}", bytes_per_pixel); + break; } } @@ -240,6 +242,7 @@ void UnswizzleSubrect(std::span output, std::span input, u32 bytes #undef BPP_CASE default: ASSERT_MSG(false, "Invalid bytes_per_pixel={}", bytes_per_pixel); + break; } } diff --git a/src/yuzu/compatdb.cpp b/src/yuzu/compatdb.cpp index f46fff340..e5bc5c448 100644 --- a/src/yuzu/compatdb.cpp +++ b/src/yuzu/compatdb.cpp @@ -63,6 +63,7 @@ void CompatDB::Submit() { break; default: LOG_ERROR(Frontend, "Unexpected page: {}", currentId()); + break; } } diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 01a002e4f..3c61899aa 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -1953,6 +1953,7 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target } default: UNIMPLEMENTED(); + break; } const QString qpath = QString::fromStdString(Common::FS::PathToUTF8String(path)); @@ -3182,6 +3183,7 @@ void GMainWindow::OnToggleGpuAccuracy() { case Settings::GPUAccuracy::Extreme: default: { Settings::values.gpu_accuracy.SetValue(Settings::GPUAccuracy::High); + break; } } @@ -3514,6 +3516,7 @@ void GMainWindow::UpdateGPUAccuracyButton() { default: { gpu_accuracy_button->setText(tr("GPU ERROR")); gpu_accuracy_button->setChecked(true); + break; } } } diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp index 65455c86e..25948328c 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp @@ -84,6 +84,7 @@ EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsyste default: LOG_CRITICAL(Frontend, "Window manager subsystem not implemented"); std::exit(EXIT_FAILURE); + break; } OnResize(); diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index e16f79eb4..dfe5a30ea 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp @@ -351,6 +351,7 @@ int main(int argc, char** argv) { "additional help.\n\nError Code: {:04X}-{:04X}\nError Description: {}", loader_id, error_id, static_cast(error_id)); } + break; } system.TelemetrySession().AddField(Common::Telemetry::FieldType::App, "Frontend", "SDL"); -- cgit v1.2.3 From 18fcc03b3ce10997ab1559b4e4887d6267d8486c Mon Sep 17 00:00:00 2001 From: Narr the Reg Date: Mon, 14 Nov 2022 18:10:04 -0600 Subject: core: Update result module --- src/core/hle/result.h | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/src/core/hle/result.h b/src/core/hle/result.h index 56c990728..240f06689 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h @@ -28,30 +28,49 @@ enum class ErrorModule : u32 { Loader = 9, CMIF = 10, HIPC = 11, + TMA = 12, + DMNT = 13, + GDS = 14, PM = 15, NS = 16, + BSDSockets = 17, HTC = 18, + TSC = 19, NCMContent = 20, SM = 21, RO = 22, + GC = 23, SDMMC = 24, OVLN = 25, SPL = 26, + Socket = 27, + HTCLOW = 29, + DDSF = 30, + HTCFS = 31, + Async = 32, + Util = 33, + TIPC = 35, + ANIF = 37, ETHC = 100, I2C = 101, GPIO = 102, UART = 103, + CPAD = 104, Settings = 105, + FTM = 106, WLAN = 107, XCD = 108, + TMP451 = 109, NIFM = 110, Hwopus = 111, + LSM6DS3 = 112, Bluetooth = 113, VI = 114, NFP = 115, Time = 116, FGM = 117, OE = 118, + BH1730FVC = 119, PCIe = 120, Friends = 121, BCAT = 122, @@ -65,7 +84,7 @@ enum class ErrorModule : u32 { AHID = 130, Qlaunch = 132, PCV = 133, - OMM = 134, + USBPD = 134, BPC = 135, PSM = 136, NIM = 137, @@ -75,18 +94,22 @@ enum class ErrorModule : u32 { NSD = 141, PCTL = 142, BTM = 143, + LA = 144, ETicket = 145, NGC = 146, ERPT = 147, APM = 148, + CEC = 149, Profiler = 150, ErrorUpload = 151, + LIDBE = 152, Audio = 153, NPNS = 154, NPNSHTTPSTREAM = 155, ARP = 157, SWKBD = 158, BOOT = 159, + NetDiag = 160, NFCMifare = 161, UserlandAssert = 162, Fatal = 163, @@ -94,17 +117,68 @@ enum class ErrorModule : u32 { SPSM = 165, BGTC = 167, UserlandCrash = 168, + SASBUS = 169, + PI = 170, + AudioCtrl = 172, + LBL = 173, + JIT = 175, + HDCP = 176, + OMM = 177, + PDM = 178, + OLSC = 179, SREPO = 180, Dauth = 181, + STDFU = 182, + DBG = 183, + DHCPS = 186, + SPI = 187, + AVM = 188, + PWM = 189, + RTC = 191, + Regulator = 192, + LED = 193, + SIO = 195, + PCM = 196, + CLKRST = 197, + POWCTL = 198, + AudioOld = 201, HID = 202, LDN = 203, + CS = 204, Irsensor = 205, Capture = 206, Manu = 208, ATK = 209, + WEB = 210, + LCS = 211, GRC = 212, + Repair = 213, + Album = 214, + RID = 215, Migration = 216, MigrationLdcServ = 217, + HIDBUS = 218, + ENS = 219, + WebSocket = 223, + DCDMTP = 227, + PGL = 228, + Notification = 229, + INS = 230, + LP2P = 231, + RCD = 232, + LCM40607 = 233, + PRC = 235, + TMAHTC = 237, + ECTX = 238, + MNPP = 239, + HSHL = 240, + CAPMTP = 242, + DP2HDMI = 244, + Cradle = 245, + SProfile = 246, + NDRM = 250, + TSPM = 499, + DevMenu = 500, GeneralWebApplet = 800, WifiWebAuthApplet = 809, WhitelistedApplet = 810, -- cgit v1.2.3 From cf202f371862ebe92dd88924a9f7b8cfbc7ad738 Mon Sep 17 00:00:00 2001 From: Liam Date: Mon, 14 Nov 2022 21:00:32 -0500 Subject: nvnflinger: fix lost wakeup --- src/core/hle/service/nvflinger/buffer_queue_core.cpp | 6 ++++-- src/core/hle/service/nvflinger/buffer_queue_core.h | 5 +++-- src/core/hle/service/nvflinger/buffer_queue_producer.cpp | 14 +++++++------- src/core/hle/service/nvflinger/buffer_queue_producer.h | 3 ++- 4 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/core/hle/service/nvflinger/buffer_queue_core.cpp b/src/core/hle/service/nvflinger/buffer_queue_core.cpp index ea4a14ea4..3d1338e66 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_core.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue_core.cpp @@ -23,15 +23,17 @@ void BufferQueueCore::NotifyShutdown() { } void BufferQueueCore::SignalDequeueCondition() { + dequeue_possible.store(true); dequeue_condition.notify_all(); } -bool BufferQueueCore::WaitForDequeueCondition() { +bool BufferQueueCore::WaitForDequeueCondition(std::unique_lock& lk) { if (is_shutting_down) { return false; } - dequeue_condition.wait(mutex); + dequeue_condition.wait(lk, [&] { return dequeue_possible.load(); }); + dequeue_possible.store(false); return true; } diff --git a/src/core/hle/service/nvflinger/buffer_queue_core.h b/src/core/hle/service/nvflinger/buffer_queue_core.h index ca6baefaf..85b3bc4c1 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_core.h +++ b/src/core/hle/service/nvflinger/buffer_queue_core.h @@ -38,7 +38,7 @@ public: private: void SignalDequeueCondition(); - bool WaitForDequeueCondition(); + bool WaitForDequeueCondition(std::unique_lock& lk); s32 GetMinUndequeuedBufferCountLocked(bool async) const; s32 GetMinMaxBufferCountLocked(bool async) const; @@ -60,7 +60,8 @@ private: BufferQueueDefs::SlotsType slots{}; std::vector queue; s32 override_max_buffer_count{}; - mutable std::condition_variable_any dequeue_condition; + std::condition_variable dequeue_condition; + std::atomic dequeue_possible{}; const bool use_async_buffer{}; // This is always disabled on HOS bool dequeue_buffer_cannot_block{}; PixelFormat default_buffer_format{PixelFormat::Rgba8888}; diff --git a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp index 41ba44b21..e601b5da1 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp @@ -121,8 +121,8 @@ Status BufferQueueProducer::SetBufferCount(s32 buffer_count) { return Status::NoError; } -Status BufferQueueProducer::WaitForFreeSlotThenRelock(bool async, s32* found, - Status* return_flags) const { +Status BufferQueueProducer::WaitForFreeSlotThenRelock(bool async, s32* found, Status* return_flags, + std::unique_lock& lk) const { bool try_again = true; while (try_again) { @@ -214,7 +214,7 @@ Status BufferQueueProducer::WaitForFreeSlotThenRelock(bool async, s32* found, return Status::WouldBlock; } - if (!core->WaitForDequeueCondition()) { + if (!core->WaitForDequeueCondition(lk)) { // We are no longer running return Status::NoError; } @@ -237,7 +237,7 @@ Status BufferQueueProducer::DequeueBuffer(s32* out_slot, Fence* out_fence, bool Status return_flags = Status::NoError; bool attached_by_consumer = false; { - std::scoped_lock lock{core->mutex}; + std::unique_lock lock{core->mutex}; core->WaitWhileAllocatingLocked(); if (format == PixelFormat::NoFormat) { @@ -248,7 +248,7 @@ Status BufferQueueProducer::DequeueBuffer(s32* out_slot, Fence* out_fence, bool usage |= core->consumer_usage_bit; s32 found{}; - Status status = WaitForFreeSlotThenRelock(async, &found, &return_flags); + Status status = WaitForFreeSlotThenRelock(async, &found, &return_flags, lock); if (status != Status::NoError) { return status; } @@ -400,13 +400,13 @@ Status BufferQueueProducer::AttachBuffer(s32* out_slot, return Status::BadValue; } - std::scoped_lock lock{core->mutex}; + std::unique_lock lock{core->mutex}; core->WaitWhileAllocatingLocked(); Status return_flags = Status::NoError; s32 found{}; - const auto status = WaitForFreeSlotThenRelock(false, &found, &return_flags); + const auto status = WaitForFreeSlotThenRelock(false, &found, &return_flags, lock); if (status != Status::NoError) { return status; } diff --git a/src/core/hle/service/nvflinger/buffer_queue_producer.h b/src/core/hle/service/nvflinger/buffer_queue_producer.h index 7526bf8ec..1d380480f 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_producer.h +++ b/src/core/hle/service/nvflinger/buffer_queue_producer.h @@ -70,7 +70,8 @@ public: private: BufferQueueProducer(const BufferQueueProducer&) = delete; - Status WaitForFreeSlotThenRelock(bool async, s32* found, Status* return_flags) const; + Status WaitForFreeSlotThenRelock(bool async, s32* found, Status* return_flags, + std::unique_lock& lk) const; Kernel::KEvent* buffer_wait_event{}; Service::KernelHelpers::ServiceContext& service_context; -- cgit v1.2.3 From ef5184cf1cddffbd5f10657e3e6bf7c957ddd628 Mon Sep 17 00:00:00 2001 From: lat9nq <22451773+lat9nq@users.noreply.github.com> Date: Tue, 15 Nov 2022 17:57:01 -0500 Subject: configure_profile_manager: Use a custom dialog for deletion A hopefully more informative dialog that most importantly notifies the user that their saves will be deleted with the user profile. cpm: Only keep track of UI elements that we need cpm: Remove unused forward declarations cpm: Add missing include --- .../configuration/configure_profile_manager.cpp | 67 ++++++++++++++++++---- src/yuzu/configuration/configure_profile_manager.h | 25 +++++++- 2 files changed, 81 insertions(+), 11 deletions(-) diff --git a/src/yuzu/configuration/configure_profile_manager.cpp b/src/yuzu/configuration/configure_profile_manager.cpp index 5c0217ba8..9493cb82e 100644 --- a/src/yuzu/configuration/configure_profile_manager.cpp +++ b/src/yuzu/configuration/configure_profile_manager.cpp @@ -2,6 +2,9 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include +#include +#include +#include #include #include #include @@ -108,9 +111,12 @@ ConfigureProfileManager::ConfigureProfileManager(const Core::System& system_, QW connect(ui->pm_add, &QPushButton::clicked, this, &ConfigureProfileManager::AddUser); connect(ui->pm_rename, &QPushButton::clicked, this, &ConfigureProfileManager::RenameUser); - connect(ui->pm_remove, &QPushButton::clicked, this, &ConfigureProfileManager::DeleteUser); + connect(ui->pm_remove, &QPushButton::clicked, this, + &ConfigureProfileManager::ConfirmDeleteUser); connect(ui->pm_set_image, &QPushButton::clicked, this, &ConfigureProfileManager::SetUserImage); + confirm_dialog = std::make_unique(this); + scene = new QGraphicsScene; ui->current_user_icon->setScene(scene); @@ -230,26 +236,23 @@ void ConfigureProfileManager::RenameUser() { UpdateCurrentUser(); } -void ConfigureProfileManager::DeleteUser() { +void ConfigureProfileManager::ConfirmDeleteUser() { const auto index = tree_view->currentIndex().row(); const auto uuid = profile_manager->GetUser(index); ASSERT(uuid); const auto username = GetAccountUsername(*profile_manager, *uuid); - const auto confirm = QMessageBox::question( - this, tr("Confirm Delete"), - tr("You are about to delete user with name \"%1\". Are you sure?").arg(username)); - - if (confirm == QMessageBox::No) { - return; - } + confirm_dialog->SetInfo(username, *uuid, [this, uuid]() { DeleteUser(*uuid); }); + confirm_dialog->show(); +} +void ConfigureProfileManager::DeleteUser(const Common::UUID uuid) { if (Settings::values.current_user.GetValue() == tree_view->currentIndex().row()) { Settings::values.current_user = 0; } UpdateCurrentUser(); - if (!profile_manager->RemoveUser(*uuid)) { + if (!profile_manager->RemoveUser(uuid)) { return; } @@ -319,3 +322,47 @@ void ConfigureProfileManager::SetUserImage() { new QStandardItem{GetIcon(*uuid), FormatUserEntryText(username, *uuid)}); UpdateCurrentUser(); } + +ConfigureProfileManagerDeleteDialog::ConfigureProfileManagerDeleteDialog(QWidget* parent) + : QDialog(parent) { + auto dialog_vbox_layout = new QVBoxLayout(this); + dialog_button_box = + new QDialogButtonBox(QDialogButtonBox::Yes | QDialogButtonBox::No, Qt::Horizontal, parent); + auto label_message = + new QLabel(tr("Delete this user? All of the user's save data will be deleted."), this); + label_info = new QLabel(this); + auto dialog_hbox_layout_widget = new QWidget(this); + auto dialog_hbox_layout = new QHBoxLayout(dialog_hbox_layout_widget); + icon_scene = new QGraphicsScene(0, 0, 64, 64, this); + auto icon_view = new QGraphicsView(icon_scene, this); + + dialog_hbox_layout_widget->setLayout(dialog_hbox_layout); + icon_view->setMaximumSize(64, 64); + icon_view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + icon_view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + this->setLayout(dialog_vbox_layout); + this->setWindowTitle(tr("Confirm Delete")); + this->setSizeGripEnabled(false); + dialog_vbox_layout->addWidget(label_message); + dialog_vbox_layout->addWidget(dialog_hbox_layout_widget); + dialog_vbox_layout->addWidget(dialog_button_box); + dialog_hbox_layout->addWidget(icon_view); + dialog_hbox_layout->addWidget(label_info); + + connect(dialog_button_box, &QDialogButtonBox::rejected, this, [this]() { close(); }); +} + +ConfigureProfileManagerDeleteDialog::~ConfigureProfileManagerDeleteDialog() = default; + +void ConfigureProfileManagerDeleteDialog::SetInfo(const QString username, const Common::UUID uuid, + std::function accept_callback) { + label_info->setText( + tr("Name: %1\nUUID: %2").arg(username, QString::fromStdString(uuid.FormattedString()))); + icon_scene->clear(); + icon_scene->addPixmap(GetIcon(uuid)); + + connect(dialog_button_box, &QDialogButtonBox::accepted, this, [this, accept_callback]() { + close(); + accept_callback(); + }); +} diff --git a/src/yuzu/configuration/configure_profile_manager.h b/src/yuzu/configuration/configure_profile_manager.h index fe9033779..6e5cb748d 100644 --- a/src/yuzu/configuration/configure_profile_manager.h +++ b/src/yuzu/configuration/configure_profile_manager.h @@ -3,16 +3,22 @@ #pragma once +#include #include +#include #include #include +#include "common/uuid.h" + namespace Core { class System; } class QGraphicsScene; +class QDialogButtonBox; +class QLabel; class QStandardItem; class QStandardItemModel; class QTreeView; @@ -26,6 +32,20 @@ namespace Ui { class ConfigureProfileManager; } +class ConfigureProfileManagerDeleteDialog : public QDialog { +public: + explicit ConfigureProfileManagerDeleteDialog(QWidget* parent); + ~ConfigureProfileManagerDeleteDialog(); + + void SetInfo(const QString username, const Common::UUID uuid, + std::function accept_callback); + +private: + QDialogButtonBox* dialog_button_box; + QGraphicsScene* icon_scene; + QLabel* label_info; +}; + class ConfigureProfileManager : public QWidget { Q_OBJECT @@ -47,7 +67,8 @@ private: void SelectUser(const QModelIndex& index); void AddUser(); void RenameUser(); - void DeleteUser(); + void ConfirmDeleteUser(); + void DeleteUser(const Common::UUID uuid); void SetUserImage(); QVBoxLayout* layout; @@ -55,6 +76,8 @@ private: QStandardItemModel* item_model; QGraphicsScene* scene; + std::unique_ptr confirm_dialog; + std::vector> list_items; std::unique_ptr ui; -- cgit v1.2.3 From 8ca02794c5723d0b678610b3a1a90bba9e703bb0 Mon Sep 17 00:00:00 2001 From: lat9nq <22451773+lat9nq@users.noreply.github.com> Date: Tue, 15 Nov 2022 17:58:06 -0500 Subject: configure_profile_manager: Remove profile picture border The border adds its own width at least on Linux which causes the icon to be offset by 1px, and cropped by 2px on the bottom and right sides. --- src/yuzu/configuration/configure_profile_manager.ui | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/yuzu/configuration/configure_profile_manager.ui b/src/yuzu/configuration/configure_profile_manager.ui index cfe7478c8..bd6dea4f4 100644 --- a/src/yuzu/configuration/configure_profile_manager.ui +++ b/src/yuzu/configuration/configure_profile_manager.ui @@ -57,6 +57,12 @@ 48 + + QFrame::NoFrame + + + QFrame::Plain + Qt::ScrollBarAlwaysOff -- cgit v1.2.3 From e94bcf03cb20d65b6bda65fccb3f259783c8ff86 Mon Sep 17 00:00:00 2001 From: lat9nq <22451773+lat9nq@users.noreply.github.com> Date: Tue, 15 Nov 2022 19:25:09 -0500 Subject: configure_profile_manager: Cleanup reference/pointer usage Co-authored-by: Morph <39850852+Morph1984@users.noreply.github.com> Co-authored-by: Mai M. --- src/yuzu/configuration/configure_profile_manager.cpp | 8 ++++---- src/yuzu/configuration/configure_profile_manager.h | 10 ++++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/yuzu/configuration/configure_profile_manager.cpp b/src/yuzu/configuration/configure_profile_manager.cpp index 9493cb82e..a47089988 100644 --- a/src/yuzu/configuration/configure_profile_manager.cpp +++ b/src/yuzu/configuration/configure_profile_manager.cpp @@ -115,7 +115,7 @@ ConfigureProfileManager::ConfigureProfileManager(const Core::System& system_, QW &ConfigureProfileManager::ConfirmDeleteUser); connect(ui->pm_set_image, &QPushButton::clicked, this, &ConfigureProfileManager::SetUserImage); - confirm_dialog = std::make_unique(this); + confirm_dialog = new ConfigureProfileManagerDeleteDialog(this); scene = new QGraphicsScene; ui->current_user_icon->setScene(scene); @@ -246,7 +246,7 @@ void ConfigureProfileManager::ConfirmDeleteUser() { confirm_dialog->show(); } -void ConfigureProfileManager::DeleteUser(const Common::UUID uuid) { +void ConfigureProfileManager::DeleteUser(const Common::UUID& uuid) { if (Settings::values.current_user.GetValue() == tree_view->currentIndex().row()) { Settings::values.current_user = 0; } @@ -324,7 +324,7 @@ void ConfigureProfileManager::SetUserImage() { } ConfigureProfileManagerDeleteDialog::ConfigureProfileManagerDeleteDialog(QWidget* parent) - : QDialog(parent) { + : QDialog{parent} { auto dialog_vbox_layout = new QVBoxLayout(this); dialog_button_box = new QDialogButtonBox(QDialogButtonBox::Yes | QDialogButtonBox::No, Qt::Horizontal, parent); @@ -354,7 +354,7 @@ ConfigureProfileManagerDeleteDialog::ConfigureProfileManagerDeleteDialog(QWidget ConfigureProfileManagerDeleteDialog::~ConfigureProfileManagerDeleteDialog() = default; -void ConfigureProfileManagerDeleteDialog::SetInfo(const QString username, const Common::UUID uuid, +void ConfigureProfileManagerDeleteDialog::SetInfo(const QString& username, const Common::UUID& uuid, std::function accept_callback) { label_info->setText( tr("Name: %1\nUUID: %2").arg(username, QString::fromStdString(uuid.FormattedString()))); diff --git a/src/yuzu/configuration/configure_profile_manager.h b/src/yuzu/configuration/configure_profile_manager.h index 6e5cb748d..c4b1a334e 100644 --- a/src/yuzu/configuration/configure_profile_manager.h +++ b/src/yuzu/configuration/configure_profile_manager.h @@ -10,7 +10,9 @@ #include #include -#include "common/uuid.h" +namespace Common { +struct UUID; +} namespace Core { class System; @@ -37,7 +39,7 @@ public: explicit ConfigureProfileManagerDeleteDialog(QWidget* parent); ~ConfigureProfileManagerDeleteDialog(); - void SetInfo(const QString username, const Common::UUID uuid, + void SetInfo(const QString& username, const Common::UUID& uuid, std::function accept_callback); private: @@ -68,7 +70,7 @@ private: void AddUser(); void RenameUser(); void ConfirmDeleteUser(); - void DeleteUser(const Common::UUID uuid); + void DeleteUser(const Common::UUID& uuid); void SetUserImage(); QVBoxLayout* layout; @@ -76,7 +78,7 @@ private: QStandardItemModel* item_model; QGraphicsScene* scene; - std::unique_ptr confirm_dialog; + ConfigureProfileManagerDeleteDialog* confirm_dialog; std::vector> list_items; -- cgit v1.2.3 From 7c50a916c74de7de3828d36427596e43717ba53a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=ADas=20Locatti?= <42481638+goldenx86@users.noreply.github.com> Date: Wed, 16 Nov 2022 05:53:42 -0300 Subject: Update renderer_vulkan.cpp --- src/video_core/renderer_vulkan/renderer_vulkan.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index d8131232a..c2a95200b 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -172,6 +172,7 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { } void RendererVulkan::Report() const { + using namespace Common::Literals; const std::string vendor_name{device.GetVendorName()}; const std::string model_name{device.GetModelName()}; const std::string driver_version = GetDriverVersion(device); @@ -181,9 +182,12 @@ void RendererVulkan::Report() const { const std::string extensions = BuildCommaSeparatedExtensions(device.GetAvailableExtensions()); + const auto available_vram = static_cast(device.GetDeviceLocalMemory()) / f64{1_GiB}; + LOG_INFO(Render_Vulkan, "Driver: {}", driver_name); LOG_INFO(Render_Vulkan, "Device: {}", model_name); LOG_INFO(Render_Vulkan, "Vulkan: {}", api_version); + LOG_INFO(Render_Vulkan, "Available VRAM: {:.2f} GiB", available_vram); static constexpr auto field = Common::Telemetry::FieldType::UserSystem; telemetry_session.AddField(field, "GPU_Vendor", vendor_name); -- cgit v1.2.3 From fa660190ff2eb95d86110299131e3fbe8847146d Mon Sep 17 00:00:00 2001 From: Valeri Date: Wed, 16 Nov 2022 20:36:43 +0300 Subject: externals: microprofileui: Remove unused variables Allows yuzu to be built with Clang 15 --- externals/microprofile/microprofileui.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/externals/microprofile/microprofileui.h b/externals/microprofile/microprofileui.h index 1357a08fd..ca9fe7063 100644 --- a/externals/microprofile/microprofileui.h +++ b/externals/microprofile/microprofileui.h @@ -845,8 +845,6 @@ inline void MicroProfileDrawDetailedBars(uint32_t nWidth, uint32_t nHeight, int MicroProfile& S = *MicroProfileGet(); MP_DEBUG_DUMP_RANGE(); int nY = nBaseY - UI.nOffsetY; - int64_t nNumBoxes = 0; - int64_t nNumLines = 0; uint32_t nFrameNext = (S.nFrameCurrent+1) % MICROPROFILE_MAX_FRAME_HISTORY; MicroProfileFrameState* pFrameCurrent = &S.Frames[S.nFrameCurrent]; @@ -1149,7 +1147,6 @@ inline void MicroProfileDrawDetailedBars(uint32_t nWidth, uint32_t nHeight, int } } #endif - ++nNumBoxes; } else { @@ -1165,7 +1162,6 @@ inline void MicroProfileDrawDetailedBars(uint32_t nWidth, uint32_t nHeight, int } nLinesDrawn[nStackPos] = nLineX; MicroProfileDrawLineVertical(nLineX, fYStart + 0.5f, fYEnd + 0.5f, nColor|UI.nOpacityForeground); - ++nNumLines; } } nStackPos--; -- cgit v1.2.3 From ece0c1095d29d940796568d7ce20fd5f414c4066 Mon Sep 17 00:00:00 2001 From: Liam Date: Wed, 16 Nov 2022 22:28:58 -0500 Subject: maxwell3d: HLE multi-layer clear macro --- src/video_core/engines/maxwell_3d.h | 1 + src/video_core/macro/macro_hle.cpp | 22 +++++++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 34b085388..f9cdfbc0b 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h @@ -1129,6 +1129,7 @@ public: Tegra::RenderTargetFormat format; TileMode tile_mode; union { + u32 depth_volume; BitField<0, 16, u32> depth; BitField<16, 1, u32> volume; }; diff --git a/src/video_core/macro/macro_hle.cpp b/src/video_core/macro/macro_hle.cpp index f896591bf..6d35387d9 100644 --- a/src/video_core/macro/macro_hle.cpp +++ b/src/video_core/macro/macro_hle.cpp @@ -126,11 +126,31 @@ void HLE_3F5E74B9C9A50164(Engines::Maxwell3D& maxwell3d, const std::vector& } } -constexpr std::array, 4> hle_funcs{{ +// Multi-layer Clear +void HLE_EAD26C3E2109B06B(Engines::Maxwell3D& maxwell3d, const std::vector& parameters) { + ASSERT(parameters.size() == 1); + + Engines::Maxwell3D::Regs::ClearSurface clear_params{parameters[0]}; + + const u32 rt_index = clear_params.RT; + const u32 num_layers = maxwell3d.regs.rt[rt_index].depth_volume; + + for (u32 i = 0; i < num_layers; i++) { + // 0x674 = regs.clear_surface + maxwell3d.CallMethod(0x674, clear_params.raw, true); + clear_params.layer.Assign(clear_params.layer + 1); + + // FIXME: remove this when amdvlk can clear multiple layers without crashing + break; + } +} + +constexpr std::array, 5> hle_funcs{{ {0x771BB18C62444DA0, &HLE_771BB18C62444DA0}, {0x0D61FC9FAAC9FCAD, &HLE_0D61FC9FAAC9FCAD}, {0x0217920100488FF7, &HLE_0217920100488FF7}, {0x3F5E74B9C9A50164, &HLE_3F5E74B9C9A50164}, + {0xEAD26C3E2109B06B, &HLE_EAD26C3E2109B06B}, }}; class HLEMacroImpl final : public CachedMacro { -- cgit v1.2.3 From 4c42655a2defddcd8faacaaa4e0bf109693b5a9c Mon Sep 17 00:00:00 2001 From: Liam Date: Wed, 16 Nov 2022 22:41:40 -0500 Subject: maxwell3d: full HLE for multi-layer clears --- src/video_core/engines/maxwell_3d.cpp | 6 +++--- src/video_core/engines/maxwell_3d.h | 7 +++---- src/video_core/macro/macro_hle.cpp | 16 +++++----------- src/video_core/rasterizer_interface.h | 2 +- src/video_core/renderer_opengl/gl_rasterizer.cpp | 2 +- src/video_core/renderer_opengl/gl_rasterizer.h | 2 +- src/video_core/renderer_vulkan/vk_rasterizer.cpp | 4 ++-- src/video_core/renderer_vulkan/vk_rasterizer.h | 2 +- 8 files changed, 17 insertions(+), 24 deletions(-) diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index d502d181c..5bb1427c1 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp @@ -232,7 +232,7 @@ void Maxwell3D::ProcessMethodCall(u32 method, u32 argument, u32 nonshadow_argume use_topology_override = true; return; case MAXWELL3D_REG_INDEX(clear_surface): - return ProcessClearBuffers(); + return ProcessClearBuffers(1); case MAXWELL3D_REG_INDEX(report_semaphore.query): return ProcessQueryGet(); case MAXWELL3D_REG_INDEX(render_enable.mode): @@ -596,8 +596,8 @@ u32 Maxwell3D::GetRegisterValue(u32 method) const { return regs.reg_array[method]; } -void Maxwell3D::ProcessClearBuffers() { - rasterizer->Clear(); +void Maxwell3D::ProcessClearBuffers(u32 layer_count) { + rasterizer->Clear(layer_count); } void Maxwell3D::ProcessDraw(u32 instance_count) { diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index f9cdfbc0b..c3099f9a6 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h @@ -1129,7 +1129,6 @@ public: Tegra::RenderTargetFormat format; TileMode tile_mode; union { - u32 depth_volume; BitField<0, 16, u32> depth; BitField<16, 1, u32> volume; }; @@ -3087,6 +3086,9 @@ public: std::vector inline_index_draw_indexes; + /// Handles a write to the CLEAR_BUFFERS register. + void ProcessClearBuffers(u32 layer_count); + private: void InitializeRegisterDefaults(); @@ -3121,9 +3123,6 @@ private: /// Handles firmware blob 4 void ProcessFirmwareCall4(); - /// Handles a write to the CLEAR_BUFFERS register. - void ProcessClearBuffers(); - /// Handles a write to the QUERY_GET register. void ProcessQueryGet(); diff --git a/src/video_core/macro/macro_hle.cpp b/src/video_core/macro/macro_hle.cpp index 6d35387d9..0f3262edb 100644 --- a/src/video_core/macro/macro_hle.cpp +++ b/src/video_core/macro/macro_hle.cpp @@ -130,19 +130,13 @@ void HLE_3F5E74B9C9A50164(Engines::Maxwell3D& maxwell3d, const std::vector& void HLE_EAD26C3E2109B06B(Engines::Maxwell3D& maxwell3d, const std::vector& parameters) { ASSERT(parameters.size() == 1); - Engines::Maxwell3D::Regs::ClearSurface clear_params{parameters[0]}; - + const Engines::Maxwell3D::Regs::ClearSurface clear_params{parameters[0]}; const u32 rt_index = clear_params.RT; - const u32 num_layers = maxwell3d.regs.rt[rt_index].depth_volume; - - for (u32 i = 0; i < num_layers; i++) { - // 0x674 = regs.clear_surface - maxwell3d.CallMethod(0x674, clear_params.raw, true); - clear_params.layer.Assign(clear_params.layer + 1); + const u32 num_layers = maxwell3d.regs.rt[rt_index].depth; + ASSERT(clear_params.layer == 0); - // FIXME: remove this when amdvlk can clear multiple layers without crashing - break; - } + maxwell3d.regs.clear_surface.raw = clear_params.raw; + maxwell3d.ProcessClearBuffers(num_layers); } constexpr std::array, 5> hle_funcs{{ diff --git a/src/video_core/rasterizer_interface.h b/src/video_core/rasterizer_interface.h index 1cbfef090..cfd872a40 100644 --- a/src/video_core/rasterizer_interface.h +++ b/src/video_core/rasterizer_interface.h @@ -43,7 +43,7 @@ public: virtual void Draw(bool is_indexed, u32 instance_count) = 0; /// Clear the current framebuffer - virtual void Clear() = 0; + virtual void Clear(u32 layer_count) = 0; /// Dispatches a compute shader invocation virtual void DispatchCompute() = 0; diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index d05a5f60b..115a5e010 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -136,7 +136,7 @@ void RasterizerOpenGL::LoadDiskResources(u64 title_id, std::stop_token stop_load shader_cache.LoadDiskResources(title_id, stop_loading, callback); } -void RasterizerOpenGL::Clear() { +void RasterizerOpenGL::Clear(u32 layer_count) { MICROPROFILE_SCOPE(OpenGL_Clears); if (!maxwell3d->ShouldExecute()) { return; diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 793e0d608..449a14f12 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -69,7 +69,7 @@ public: ~RasterizerOpenGL() override; void Draw(bool is_indexed, u32 instance_count) override; - void Clear() override; + void Clear(u32 layer_count) override; void DispatchCompute() override; void ResetCounter(VideoCore::QueryType type) override; void Query(GPUVAddr gpu_addr, VideoCore::QueryType type, std::optional timestamp) override; diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index f69c0c50f..67b88621a 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -213,7 +213,7 @@ void RasterizerVulkan::Draw(bool is_indexed, u32 instance_count) { EndTransformFeedback(); } -void RasterizerVulkan::Clear() { +void RasterizerVulkan::Clear(u32 layer_count) { MICROPROFILE_SCOPE(Vulkan_Clearing); if (!maxwell3d->ShouldExecute()) { @@ -256,7 +256,7 @@ void RasterizerVulkan::Clear() { .rect = regs.clear_control.use_scissor ? GetScissorState(regs, 0, up_scale, down_shift) : default_scissor, .baseArrayLayer = regs.clear_surface.layer, - .layerCount = 1, + .layerCount = layer_count, }; if (clear_rect.rect.extent.width == 0 || clear_rect.rect.extent.height == 0) { return; diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h index b0bc306f5..70f36d58a 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.h +++ b/src/video_core/renderer_vulkan/vk_rasterizer.h @@ -65,7 +65,7 @@ public: ~RasterizerVulkan() override; void Draw(bool is_indexed, u32 instance_count) override; - void Clear() override; + void Clear(u32 layer_count) override; void DispatchCompute() override; void ResetCounter(VideoCore::QueryType type) override; void Query(GPUVAddr gpu_addr, VideoCore::QueryType type, std::optional timestamp) override; -- cgit v1.2.3 From 60e0d4a177803891720af4c5978bbf2604bed276 Mon Sep 17 00:00:00 2001 From: FengChen Date: Fri, 11 Nov 2022 00:25:03 +0800 Subject: shader: Implement miss attribute layer --- src/shader_recompiler/backend/glasm/emit_glasm.cpp | 1 + src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp | 3 +++ src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp | 3 +++ src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp | 2 ++ src/shader_recompiler/backend/spirv/spirv_emit_context.cpp | 4 ++++ 5 files changed, 13 insertions(+) diff --git a/src/shader_recompiler/backend/glasm/emit_glasm.cpp b/src/shader_recompiler/backend/glasm/emit_glasm.cpp index 3b0176bf6..0cb1e193e 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm.cpp @@ -320,6 +320,7 @@ void SetupOptions(const IR::Program& program, const Profile& profile, } if (stage == Stage::Fragment) { header += "OPTION ARB_draw_buffers;"; + header += "OPTION ARB_fragment_layer_viewport;"; } } diff --git a/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp b/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp index 0a7d42dda..9dbf9888d 100644 --- a/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp +++ b/src/shader_recompiler/backend/glasm/emit_glasm_context_get_set.cpp @@ -104,6 +104,9 @@ void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr, Scal case IR::Attribute::PrimitiveId: ctx.Add("MOV.F {}.x,primitive.id;", inst); break; + case IR::Attribute::Layer: + ctx.Add("MOV.F {}.x,fragment.layer;", inst); + break; case IR::Attribute::PositionX: case IR::Attribute::PositionY: case IR::Attribute::PositionZ: diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp index d7c845469..02b84cbe6 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp +++ b/src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp @@ -205,6 +205,9 @@ void EmitGetAttribute(EmitContext& ctx, IR::Inst& inst, IR::Attribute attr, case IR::Attribute::PrimitiveId: ctx.AddF32("{}=itof(gl_PrimitiveID);", inst); break; + case IR::Attribute::Layer: + ctx.AddF32("{}=itof(gl_Layer);", inst); + break; case IR::Attribute::PositionX: case IR::Attribute::PositionY: case IR::Attribute::PositionZ: diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp index a4751b42d..ce33fabf5 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp @@ -315,6 +315,8 @@ Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, Id vertex) { switch (attr) { case IR::Attribute::PrimitiveId: return ctx.OpBitcast(ctx.F32[1], ctx.OpLoad(ctx.U32[1], ctx.primitive_id)); + case IR::Attribute::Layer: + return ctx.OpBitcast(ctx.F32[1], ctx.OpLoad(ctx.U32[1], ctx.layer)); case IR::Attribute::PositionX: case IR::Attribute::PositionY: case IR::Attribute::PositionZ: diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp index c26ad8f93..e80662d23 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp @@ -1355,6 +1355,10 @@ void EmitContext::DefineInputs(const IR::Program& program) { if (loads[IR::Attribute::PrimitiveId]) { primitive_id = DefineInput(*this, U32[1], false, spv::BuiltIn::PrimitiveId); } + if (loads[IR::Attribute::Layer]) { + AddCapability(spv::Capability::Geometry); + layer = DefineInput(*this, U32[1], false, spv::BuiltIn::Layer); + } if (loads.AnyComponent(IR::Attribute::PositionX)) { const bool is_fragment{stage != Stage::Fragment}; const spv::BuiltIn built_in{is_fragment ? spv::BuiltIn::Position : spv::BuiltIn::FragCoord}; -- cgit v1.2.3 From bc957531072ad1973a690cd6c4aa9aa821ca64b1 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Thu, 17 Nov 2022 16:59:41 +0100 Subject: Dynarmic: Remove inaccurate NaN from Auto CPU settings. --- src/core/arm/dynarmic/arm_dynarmic_64.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index afb7fb3a0..cb53d64ba 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -348,7 +348,6 @@ std::shared_ptr ARM_Dynarmic_64::MakeJit(Common::PageTable* if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Auto) { config.unsafe_optimizations = true; config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA; - config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN; config.fastmem_address_space_bits = 64; config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor; } -- cgit v1.2.3 From 0d033e6b45bd5bfe30234f0cc5f588012d033a3e Mon Sep 17 00:00:00 2001 From: Liam Date: Fri, 18 Nov 2022 22:05:28 -0500 Subject: spirv_emit_context: add missing flat decoration --- src/shader_recompiler/backend/spirv/spirv_emit_context.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp index dd96b7803..8e3e40cd5 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp @@ -1362,6 +1362,7 @@ void EmitContext::DefineInputs(const IR::Program& program) { if (loads[IR::Attribute::Layer]) { AddCapability(spv::Capability::Geometry); layer = DefineInput(*this, U32[1], false, spv::BuiltIn::Layer); + Decorate(layer, spv::Decoration::Flat); } if (loads.AnyComponent(IR::Attribute::PositionX)) { const bool is_fragment{stage != Stage::Fragment}; -- cgit v1.2.3 From 38c48cf8d896f28f7424b28265110c34f69d2369 Mon Sep 17 00:00:00 2001 From: Narr the Reg Date: Sat, 5 Nov 2022 10:39:03 -0600 Subject: core: hid: Implement true multitouch support --- src/core/hid/emulated_console.cpp | 94 +++++++++++++++++++------ src/core/hid/emulated_console.h | 15 ++-- src/core/hid/input_converter.cpp | 3 - src/input_common/helpers/touch_from_buttons.cpp | 9 +-- src/input_common/input_poller.cpp | 18 ++--- 5 files changed, 93 insertions(+), 46 deletions(-) diff --git a/src/core/hid/emulated_console.cpp b/src/core/hid/emulated_console.cpp index aac45907d..fb7e5802a 100644 --- a/src/core/hid/emulated_console.cpp +++ b/src/core/hid/emulated_console.cpp @@ -19,27 +19,26 @@ void EmulatedConsole::ReloadFromSettings() { } void EmulatedConsole::SetTouchParams() { - // TODO(german77): Support any number of fingers std::size_t index = 0; - // Hardcode mouse, touchscreen and cemuhook parameters + // We can't use mouse as touch if native mouse is enabled if (!Settings::values.mouse_enabled) { - // We can't use mouse as touch if native mouse is enabled touch_params[index++] = Common::ParamPackage{"engine:mouse,axis_x:10,axis_y:11,button:0"}; } touch_params[index++] = - Common::ParamPackage{"engine:touch,axis_x:0,axis_y:1,button:0,touch_id:0"}; + Common::ParamPackage{"engine:cemuhookudp,axis_x:17,axis_y:18,button:65536"}; touch_params[index++] = - Common::ParamPackage{"engine:touch,axis_x:2,axis_y:3,button:1,touch_id:1"}; - touch_params[index++] = - Common::ParamPackage{"engine:touch,axis_x:4,axis_y:5,button:2,touch_id:2"}; - touch_params[index++] = - Common::ParamPackage{"engine:touch,axis_x:6,axis_y:7,button:3,touch_id:3"}; - touch_params[index++] = - Common::ParamPackage{"engine:cemuhookudp,axis_x:17,axis_y:18,button:65536,touch_id:0"}; - touch_params[index++] = - Common::ParamPackage{"engine:cemuhookudp,axis_x:19,axis_y:20,button:131072,touch_id:1"}; + Common::ParamPackage{"engine:cemuhookudp,axis_x:19,axis_y:20,button:131072"}; + + for (int i = 0; i < static_cast(MaxActiveTouchInputs); i++) { + Common::ParamPackage touchscreen_param{}; + touchscreen_param.Set("engine", "touch"); + touchscreen_param.Set("axis_x", i * 2); + touchscreen_param.Set("axis_y", (i * 2) + 1); + touchscreen_param.Set("button", i); + touch_params[index++] = touchscreen_param; + } const auto button_index = static_cast(Settings::values.touch_from_button_map_index.GetValue()); @@ -47,7 +46,7 @@ void EmulatedConsole::SetTouchParams() { // Map the rest of the fingers from touch from button configuration for (const auto& config_entry : touch_buttons) { - if (index >= touch_params.size()) { + if (index >= MaxTouchDevices) { continue; } Common::ParamPackage params{config_entry}; @@ -60,7 +59,6 @@ void EmulatedConsole::SetTouchParams() { touch_button_params.Set("button", params.Serialize()); touch_button_params.Set("x", x); touch_button_params.Set("y", y); - touch_button_params.Set("touch_id", static_cast(index)); touch_params[index] = touch_button_params; index++; } @@ -178,12 +176,38 @@ void EmulatedConsole::SetMotion(const Common::Input::CallbackStatus& callback) { } void EmulatedConsole::SetTouch(const Common::Input::CallbackStatus& callback, std::size_t index) { - if (index >= console.touch_values.size()) { + if (index >= MaxTouchDevices) { return; } std::unique_lock lock{mutex}; - console.touch_values[index] = TransformToTouch(callback); + const auto touch_input = TransformToTouch(callback); + auto touch_index = GetIndexFromFingerId(index); + bool is_new_input = false; + + if (!touch_index.has_value() && touch_input.pressed.value) { + touch_index = GetNextFreeIndex(); + is_new_input = true; + } + + // No free entries or invalid state. Ignore input + if (!touch_index.has_value()) { + return; + } + + auto& touch_value = console.touch_values[touch_index.value()]; + + if (is_new_input) { + touch_value.pressed.value = true; + touch_value.id = static_cast(index); + } + + touch_value.x = touch_input.x; + touch_value.y = touch_input.y; + + if (!touch_input.pressed.value) { + touch_value.pressed.value = false; + } if (is_configuring) { lock.unlock(); @@ -191,11 +215,15 @@ void EmulatedConsole::SetTouch(const Common::Input::CallbackStatus& callback, st return; } - // TODO(german77): Remap touch id in sequential order - console.touch_state[index] = { - .position = {console.touch_values[index].x.value, console.touch_values[index].y.value}, - .id = static_cast(console.touch_values[index].id), - .pressed = console.touch_values[index].pressed.value, + // Touch outside allowed range. Ignore input + if (touch_index.value() >= MaxActiveTouchInputs) { + return; + } + + console.touch_state[touch_index.value()] = { + .position = {touch_value.x.value, touch_value.y.value}, + .id = static_cast(touch_index.value()), + .pressed = touch_input.pressed.value, }; lock.unlock(); @@ -222,6 +250,28 @@ TouchFingerState EmulatedConsole::GetTouch() const { return console.touch_state; } +std::optional EmulatedConsole::GetIndexFromFingerId(std::size_t finger_id) const { + for (std::size_t index = 0; index < MaxTouchDevices; ++index) { + const auto& finger = console.touch_values[index]; + if (!finger.pressed.value) { + continue; + } + if (finger.id == static_cast(finger_id)) { + return index; + } + } + return std::nullopt; +} + +std::optional EmulatedConsole::GetNextFreeIndex() const { + for (std::size_t index = 0; index < MaxTouchDevices; ++index) { + if (!console.touch_values[index].pressed.value) { + return index; + } + } + return std::nullopt; +} + void EmulatedConsole::TriggerOnChange(ConsoleTriggerType type) { std::scoped_lock lock{callback_mutex}; for (const auto& poller_pair : callback_list) { diff --git a/src/core/hid/emulated_console.h b/src/core/hid/emulated_console.h index 1c510cd19..697ecd2d6 100644 --- a/src/core/hid/emulated_console.h +++ b/src/core/hid/emulated_console.h @@ -7,6 +7,7 @@ #include #include #include +#include #include #include "common/common_funcs.h" @@ -20,6 +21,8 @@ #include "core/hid/motion_input.h" namespace Core::HID { +static constexpr std::size_t MaxTouchDevices = 32; +static constexpr std::size_t MaxActiveTouchInputs = 16; struct ConsoleMotionInfo { Common::Input::MotionStatus raw_status{}; @@ -27,13 +30,13 @@ struct ConsoleMotionInfo { }; using ConsoleMotionDevices = std::unique_ptr; -using TouchDevices = std::array, 16>; +using TouchDevices = std::array, MaxTouchDevices>; using ConsoleMotionParams = Common::ParamPackage; -using TouchParams = std::array; +using TouchParams = std::array; using ConsoleMotionValues = ConsoleMotionInfo; -using TouchValues = std::array; +using TouchValues = std::array; struct TouchFinger { u64 last_touch{}; @@ -55,7 +58,7 @@ struct ConsoleMotion { bool is_at_rest{}; }; -using TouchFingerState = std::array; +using TouchFingerState = std::array; struct ConsoleStatus { // Data from input_common @@ -166,6 +169,10 @@ private: */ void SetTouch(const Common::Input::CallbackStatus& callback, std::size_t index); + std::optional GetIndexFromFingerId(std::size_t finger_id) const; + + std::optional GetNextFreeIndex() const; + /** * Triggers a callback that something has changed on the console status * @param type Input type of the event to trigger diff --git a/src/core/hid/input_converter.cpp b/src/core/hid/input_converter.cpp index 5d8b75b50..502692875 100644 --- a/src/core/hid/input_converter.cpp +++ b/src/core/hid/input_converter.cpp @@ -200,9 +200,6 @@ Common::Input::TouchStatus TransformToTouch(const Common::Input::CallbackStatus& x = std::clamp(x, 0.0f, 1.0f); y = std::clamp(y, 0.0f, 1.0f); - // Limit id to maximum number of fingers - status.id = std::clamp(status.id, 0, 16); - if (status.pressed.inverted) { status.pressed.value = !status.pressed.value; } diff --git a/src/input_common/helpers/touch_from_buttons.cpp b/src/input_common/helpers/touch_from_buttons.cpp index da4a3dca5..003a38da5 100644 --- a/src/input_common/helpers/touch_from_buttons.cpp +++ b/src/input_common/helpers/touch_from_buttons.cpp @@ -10,8 +10,8 @@ namespace InputCommon { class TouchFromButtonDevice final : public Common::Input::InputDevice { public: using Button = std::unique_ptr; - TouchFromButtonDevice(Button button_, int touch_id_, float x_, float y_) - : button(std::move(button_)), touch_id(touch_id_), x(x_), y(y_) { + TouchFromButtonDevice(Button button_, float x_, float y_) + : button(std::move(button_)), x(x_), y(y_) { last_button_value = false; button->SetCallback({ .on_change = @@ -34,7 +34,6 @@ public: .pressed = button_status, .x = {}, .y = {}, - .id = touch_id, }; status.x.properties = properties; status.y.properties = properties; @@ -62,7 +61,6 @@ public: private: Button button; bool last_button_value; - const int touch_id; const float x; const float y; const Common::Input::AnalogProperties properties{0.0f, 1.0f, 0.5f, 0.0f, false}; @@ -73,10 +71,9 @@ std::unique_ptr TouchFromButton::Create( const std::string null_engine = Common::ParamPackage{{"engine", "null"}}.Serialize(); auto button = Common::Input::CreateDeviceFromString( params.Get("button", null_engine)); - const auto touch_id = params.Get("touch_id", 0); const float x = params.Get("x", 0.0f) / 1280.0f; const float y = params.Get("y", 0.0f) / 720.0f; - return std::make_unique(std::move(button), touch_id, x, y); + return std::make_unique(std::move(button), x, y); } } // namespace InputCommon diff --git a/src/input_common/input_poller.cpp b/src/input_common/input_poller.cpp index 4ac182147..fb8be42e2 100644 --- a/src/input_common/input_poller.cpp +++ b/src/input_common/input_poller.cpp @@ -229,13 +229,12 @@ private: class InputFromTouch final : public Common::Input::InputDevice { public: - explicit InputFromTouch(PadIdentifier identifier_, int touch_id_, int button_, bool toggle_, - bool inverted_, int axis_x_, int axis_y_, - Common::Input::AnalogProperties properties_x_, + explicit InputFromTouch(PadIdentifier identifier_, int button_, bool toggle_, bool inverted_, + int axis_x_, int axis_y_, Common::Input::AnalogProperties properties_x_, Common::Input::AnalogProperties properties_y_, InputEngine* input_engine_) - : identifier(identifier_), touch_id(touch_id_), button(button_), toggle(toggle_), - inverted(inverted_), axis_x(axis_x_), axis_y(axis_y_), properties_x(properties_x_), + : identifier(identifier_), button(button_), toggle(toggle_), inverted(inverted_), + axis_x(axis_x_), axis_y(axis_y_), properties_x(properties_x_), properties_y(properties_y_), input_engine(input_engine_) { UpdateCallback engine_callback{[this]() { OnChange(); }}; const InputIdentifier button_input_identifier{ @@ -271,8 +270,7 @@ public: } Common::Input::TouchStatus GetStatus() const { - Common::Input::TouchStatus status; - status.id = touch_id; + Common::Input::TouchStatus status{}; status.pressed = { .value = input_engine->GetButton(identifier, button), .inverted = inverted, @@ -307,7 +305,6 @@ public: private: const PadIdentifier identifier; - const int touch_id; const int button; const bool toggle; const bool inverted; @@ -919,7 +916,6 @@ std::unique_ptr InputFactory::CreateTriggerDevice( std::unique_ptr InputFactory::CreateTouchDevice( const Common::ParamPackage& params) { - const auto touch_id = params.Get("touch_id", 0); const auto deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f); const auto range = std::clamp(params.Get("range", 1.0f), 0.25f, 1.50f); const auto threshold = std::clamp(params.Get("threshold", 0.5f), 0.0f, 1.0f); @@ -954,8 +950,8 @@ std::unique_ptr InputFactory::CreateTouchDevice( input_engine->PreSetAxis(identifier, axis_x); input_engine->PreSetAxis(identifier, axis_y); input_engine->PreSetButton(identifier, button); - return std::make_unique(identifier, touch_id, button, toggle, inverted, axis_x, - axis_y, properties_x, properties_y, input_engine.get()); + return std::make_unique(identifier, button, toggle, inverted, axis_x, axis_y, + properties_x, properties_y, input_engine.get()); } std::unique_ptr InputFactory::CreateBatteryDevice( -- cgit v1.2.3 From aa075a0c08335b1d145b2885eb0ba2f395b74f90 Mon Sep 17 00:00:00 2001 From: german77 Date: Sat, 5 Nov 2022 11:40:19 -0600 Subject: service: hid: Only overclock npad controllers --- src/core/hle/service/hid/hid.cpp | 32 +++++++++++++++++++++++++++----- src/core/hle/service/hid/hid.h | 4 +++- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 79375bd2f..bf28440c6 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -36,8 +36,9 @@ namespace Service::HID { // Updating period for each HID device. // Period time is obtained by measuring the number of samples in a second on HW using a homebrew -// Correct pad_update_ns is 4ms this is overclocked to lower input lag -constexpr auto pad_update_ns = std::chrono::nanoseconds{1 * 1000 * 1000}; // (1ms, 1000Hz) +// Correct npad_update_ns is 4ms this is overclocked to lower input lag +constexpr auto npad_update_ns = std::chrono::nanoseconds{1 * 1000 * 1000}; // (1ms, 1000Hz) +constexpr auto default_update_ns = std::chrono::nanoseconds{4 * 1000 * 1000}; // (4ms, 1000Hz) constexpr auto mouse_keyboard_update_ns = std::chrono::nanoseconds{8 * 1000 * 1000}; // (8ms, 125Hz) constexpr auto motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000}; // (5ms, 200Hz) @@ -75,8 +76,16 @@ IAppletResource::IAppletResource(Core::System& system_, GetController(HidController::UniquePad).SetCommonHeaderOffset(0x5A00); // Register update callbacks - pad_update_event = Core::Timing::CreateEvent( + npad_update_event = Core::Timing::CreateEvent( "HID::UpdatePadCallback", + [this](std::uintptr_t user_data, s64 time, + std::chrono::nanoseconds ns_late) -> std::optional { + const auto guard = LockService(); + UpdateNpad(user_data, ns_late); + return std::nullopt; + }); + default_update_event = Core::Timing::CreateEvent( + "HID::UpdateDefaultCallback", [this](std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late) -> std::optional { const auto guard = LockService(); @@ -100,7 +109,9 @@ IAppletResource::IAppletResource(Core::System& system_, return std::nullopt; }); - system.CoreTiming().ScheduleLoopingEvent(pad_update_ns, pad_update_ns, pad_update_event); + system.CoreTiming().ScheduleLoopingEvent(npad_update_ns, npad_update_ns, npad_update_event); + system.CoreTiming().ScheduleLoopingEvent(default_update_ns, default_update_ns, + default_update_event); system.CoreTiming().ScheduleLoopingEvent(mouse_keyboard_update_ns, mouse_keyboard_update_ns, mouse_keyboard_update_event); system.CoreTiming().ScheduleLoopingEvent(motion_update_ns, motion_update_ns, @@ -118,7 +129,8 @@ void IAppletResource::DeactivateController(HidController controller) { } IAppletResource::~IAppletResource() { - system.CoreTiming().UnscheduleEvent(pad_update_event, 0); + system.CoreTiming().UnscheduleEvent(npad_update_event, 0); + system.CoreTiming().UnscheduleEvent(default_update_event, 0); system.CoreTiming().UnscheduleEvent(mouse_keyboard_update_event, 0); system.CoreTiming().UnscheduleEvent(motion_update_event, 0); } @@ -144,10 +156,20 @@ void IAppletResource::UpdateControllers(std::uintptr_t user_data, if (controller == controllers[static_cast(HidController::Mouse)]) { continue; } + // Npad has it's own update event + if (controller == controllers[static_cast(HidController::NPad)]) { + continue; + } controller->OnUpdate(core_timing); } } +void IAppletResource::UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { + auto& core_timing = system.CoreTiming(); + + controllers[static_cast(HidController::NPad)]->OnUpdate(core_timing); +} + void IAppletResource::UpdateMouseKeyboard(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { auto& core_timing = system.CoreTiming(); diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index 340d26fdc..b7c2a23ef 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -71,12 +71,14 @@ private: void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx); void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); + void UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); void UpdateMouseKeyboard(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 npad_update_event; + std::shared_ptr default_update_event; std::shared_ptr mouse_keyboard_update_event; std::shared_ptr motion_update_event; -- cgit v1.2.3 From 344e171cc756912ca9df0a762831563216bdcd68 Mon Sep 17 00:00:00 2001 From: Merry Date: Sat, 19 Nov 2022 20:10:26 +0000 Subject: dynarmic: Fix stack misalignment in GenMemory128Accessors --- externals/dynarmic | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/externals/dynarmic b/externals/dynarmic index 424fdb5c5..07c614f91 160000 --- a/externals/dynarmic +++ b/externals/dynarmic @@ -1 +1 @@ -Subproject commit 424fdb5c5026ec5bdd7553271190397f63fb503e +Subproject commit 07c614f91b0af5335e1f9c0653c2d75e7b5f53bd -- cgit v1.2.3 From 975e17aa133ba939507f2f16910ed21dea15bb66 Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Sat, 19 Nov 2022 16:29:59 -0500 Subject: github: Add new bug report issue form --- .github/ISSUE_TEMPLATE/bug_report.yml | 64 +++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 000000000..1405ccce8 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,64 @@ +name: Bug Report +description: File a bug report +body: + - type: markdown + attributes: + value: Tech support does not belong here. You should only file an issue here if you think you have experienced an actual bug with yuzu. + - type: checkboxes + attributes: + label: Is there an existing issue for this? + description: Please search to see if an issue already exists for the bug you encountered. + options: + - label: I have searched the existing issues + required: true + - type: input + attributes: + label: Affected Build(s) + description: List the affected build(s) that this issue applies to. + placeholder: Mainline 1234 / Early Access 1234 + validations: + required: true + - type: textarea + id: issue-desc + attributes: + label: Description of Issue + description: A brief description of the issue encountered along with any images and/or videos. + validations: + required: true + - type: textarea + id: expected-behavior + attributes: + label: Expected Behavior + description: A brief description of how it is expected to work along with any images and/or videos. + validations: + required: true + - type: textarea + id: reproduction-steps + attributes: + label: Reproduction Steps + description: A brief explanation of how to reproduce this issue. If possible, provide a save file to aid in reproducing the issue. + validations: + required: true + - type: textarea + id: log + attributes: + label: Log File + description: A log file will help our developers to better diagnose and fix the issue. + validations: + required: true + - type: textarea + id: system-config + attributes: + label: System Configuration + placeholder: | + CPU: Intel i5-10400 / AMD Ryzen 5 3600 + GPU/Driver: NVIDIA GeForce GTX 1060 (Driver 512.95) + RAM: 16GB DDR4-3200 + OS: Windows 11 22H2 (Build 22621.819) + value: | + CPU: + GPU/Driver: + RAM: + OS: + validations: + required: true -- cgit v1.2.3 From 52acdafa95b5caf1aa97a12a4924e384d4b8c61d Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Sat, 19 Nov 2022 16:37:15 -0500 Subject: github: Add new feature request issue form --- .github/ISSUE_TEMPLATE/feature_request.yml | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/feature_request.yml diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 000000000..766da2c87 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,28 @@ +name: Feature Request +description: File a feature request +labels: "request" +body: + - type: markdown + attributes: + value: Tech support does not belong here. You should only file an issue here if you are requesting a feature you believe would make yuzu better. + - type: checkboxes + attributes: + label: Is there an existing issue for this? + description: Please search to see if an issue already exists for the feature you are requesting. + options: + - label: I have searched the existing issues + required: true + - type: textarea + id: what-feature + attributes: + label: What feature are you suggesting? + description: A brief description of the requested feature. + validations: + required: true + - type: textarea + id: why-feature + attributes: + label: Why would this feature be useful? + description: A brief description of why this feature would make yuzu better. + validations: + required: true -- cgit v1.2.3 From 98a6cd02c879e6ccec640350644b80b5bdb5cadf Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Sat, 19 Nov 2022 16:37:52 -0500 Subject: github: Remove old markdown form Replaced by the newer issue forms template --- .../ISSUE_TEMPLATE/bug-report-feature-request.md | 39 ---------------------- .reuse/dep5 | 8 ++--- 2 files changed, 2 insertions(+), 45 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/bug-report-feature-request.md diff --git a/.github/ISSUE_TEMPLATE/bug-report-feature-request.md b/.github/ISSUE_TEMPLATE/bug-report-feature-request.md deleted file mode 100644 index 808613237..000000000 --- a/.github/ISSUE_TEMPLATE/bug-report-feature-request.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -name: Bug Report / Feature Request -about: Tech support does not belong here. You should only file an issue here if you think you have experienced an actual bug with yuzu or you are requesting a feature you believe would make yuzu better. -title: '' -labels: '' -assignees: '' - ---- - - - - - - - diff --git a/.reuse/dep5 b/.reuse/dep5 index 9a90f9eb6..3810f2c41 100644 --- a/.reuse/dep5 +++ b/.reuse/dep5 @@ -132,10 +132,6 @@ Files: vcpkg.json Copyright: 2022 yuzu Emulator Project License: GPL-3.0-or-later -Files: .github/ISSUE_TEMPLATE/config.yml -Copyright: 2020 tgsm -License: GPL-2.0-or-later - -Files: .github/ISSUE_TEMPLATE/bug-report-feature-request.md -Copyright: 2016 MerryMage +Files: .github/ISSUE_TEMPLATE/* +Copyright: 2022 yuzu Emulator Project License: GPL-2.0-or-later -- cgit v1.2.3 From 54d6273975d97aa63270f52f6349a184165fd8e2 Mon Sep 17 00:00:00 2001 From: Morph <39850852+Morph1984@users.noreply.github.com> Date: Sun, 20 Nov 2022 00:16:35 -0500 Subject: github: Add blank issue template This is meant to only be used by developers. --- .github/ISSUE_TEMPLATE/blank_issue_template.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/blank_issue_template.yml diff --git a/.github/ISSUE_TEMPLATE/blank_issue_template.yml b/.github/ISSUE_TEMPLATE/blank_issue_template.yml new file mode 100644 index 000000000..49b7f3822 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/blank_issue_template.yml @@ -0,0 +1,10 @@ +name: New Issue (Developers Only) +description: A blank issue template for developers only. If you are not a developer, do not use this issue template. Your issue WILL BE CLOSED if you do not use the appropriate issue template. +body: + - type: markdown + attributes: + value: | + **If you are not a developer, do not use this issue template. Your issue WILL BE CLOSED if you do not use the appropriate issue template.** + - type: textarea + attributes: + label: "Issue" -- cgit v1.2.3