early-access version 3837
This commit is contained in:
parent
d07529eada
commit
c807f0cfc8
17 changed files with 252 additions and 94 deletions
|
@ -1,7 +1,7 @@
|
||||||
yuzu emulator early access
|
yuzu emulator early access
|
||||||
=============
|
=============
|
||||||
|
|
||||||
This is the source code for early-access 3836.
|
This is the source code for early-access 3837.
|
||||||
|
|
||||||
## Legal Notice
|
## Legal Notice
|
||||||
|
|
||||||
|
|
5
dist/qt_themes/default/style.qss
vendored
5
dist/qt_themes/default/style.qss
vendored
|
@ -78,6 +78,11 @@ QPushButton#buttonRefreshDevices {
|
||||||
max-height: 21px;
|
max-height: 21px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QPushButton#button_reset_defaults {
|
||||||
|
min-width: 57px;
|
||||||
|
padding: 4px 8px;
|
||||||
|
}
|
||||||
|
|
||||||
QWidget#bottomPerGameInput,
|
QWidget#bottomPerGameInput,
|
||||||
QWidget#topControllerApplet,
|
QWidget#topControllerApplet,
|
||||||
QWidget#bottomControllerApplet,
|
QWidget#bottomControllerApplet,
|
||||||
|
|
|
@ -2228,6 +2228,10 @@ QPushButton#buttonRefreshDevices {
|
||||||
padding: 0px 0px;
|
padding: 0px 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QPushButton#button_reset_defaults {
|
||||||
|
padding: 3px 6px;
|
||||||
|
}
|
||||||
|
|
||||||
QSpinBox#spinboxLStickRange,
|
QSpinBox#spinboxLStickRange,
|
||||||
QSpinBox#spinboxRStickRange,
|
QSpinBox#spinboxRStickRange,
|
||||||
QSpinBox#vibrationSpinPlayer1,
|
QSpinBox#vibrationSpinPlayer1,
|
||||||
|
|
14
externals/CMakeLists.txt
vendored
14
externals/CMakeLists.txt
vendored
|
@ -42,6 +42,11 @@ endif()
|
||||||
# mbedtls
|
# mbedtls
|
||||||
add_subdirectory(mbedtls)
|
add_subdirectory(mbedtls)
|
||||||
target_include_directories(mbedtls PUBLIC ./mbedtls/include)
|
target_include_directories(mbedtls PUBLIC ./mbedtls/include)
|
||||||
|
if (NOT MSVC)
|
||||||
|
target_compile_options(mbedcrypto PRIVATE
|
||||||
|
-Wno-unused-but-set-variable
|
||||||
|
-Wno-string-concatenation)
|
||||||
|
endif()
|
||||||
|
|
||||||
# MicroProfile
|
# MicroProfile
|
||||||
add_library(microprofile INTERFACE)
|
add_library(microprofile INTERFACE)
|
||||||
|
@ -94,6 +99,12 @@ if (ENABLE_CUBEB AND NOT TARGET cubeb::cubeb)
|
||||||
set(BUILD_TOOLS OFF)
|
set(BUILD_TOOLS OFF)
|
||||||
add_subdirectory(cubeb)
|
add_subdirectory(cubeb)
|
||||||
add_library(cubeb::cubeb ALIAS cubeb)
|
add_library(cubeb::cubeb ALIAS cubeb)
|
||||||
|
if (NOT MSVC)
|
||||||
|
if (TARGET speex)
|
||||||
|
target_compile_options(speex PRIVATE -Wno-sign-compare)
|
||||||
|
endif()
|
||||||
|
target_compile_options(cubeb PRIVATE -Wno-implicit-const-int-float-conversion)
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# DiscordRPC
|
# DiscordRPC
|
||||||
|
@ -151,6 +162,9 @@ endif()
|
||||||
if (NOT TARGET LLVM::Demangle)
|
if (NOT TARGET LLVM::Demangle)
|
||||||
add_library(demangle demangle/ItaniumDemangle.cpp)
|
add_library(demangle demangle/ItaniumDemangle.cpp)
|
||||||
target_include_directories(demangle PUBLIC ./demangle)
|
target_include_directories(demangle PUBLIC ./demangle)
|
||||||
|
if (NOT MSVC)
|
||||||
|
target_compile_options(demangle PRIVATE -Wno-deprecated-declarations) # std::is_pod
|
||||||
|
endif()
|
||||||
add_library(LLVM::Demangle ALIAS demangle)
|
add_library(LLVM::Demangle ALIAS demangle)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
|
@ -114,16 +114,19 @@ else()
|
||||||
-Wno-attributes
|
-Wno-attributes
|
||||||
-Wno-invalid-offsetof
|
-Wno-invalid-offsetof
|
||||||
-Wno-unused-parameter
|
-Wno-unused-parameter
|
||||||
|
|
||||||
$<$<CXX_COMPILER_ID:Clang>:-Wno-braced-scalar-init>
|
|
||||||
$<$<CXX_COMPILER_ID:Clang>:-Wno-unused-private-field>
|
|
||||||
$<$<CXX_COMPILER_ID:Clang>:-Werror=shadow-uncaptured-local>
|
|
||||||
$<$<CXX_COMPILER_ID:Clang>:-Werror=implicit-fallthrough>
|
|
||||||
$<$<CXX_COMPILER_ID:Clang>:-Werror=type-limits>
|
|
||||||
$<$<CXX_COMPILER_ID:AppleClang>:-Wno-braced-scalar-init>
|
|
||||||
$<$<CXX_COMPILER_ID:AppleClang>:-Wno-unused-private-field>
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (CMAKE_CXX_COMPILER_ID MATCHES Clang) # Clang or AppleClang
|
||||||
|
add_compile_options(
|
||||||
|
-Wno-braced-scalar-init
|
||||||
|
-Wno-unused-private-field
|
||||||
|
-Wno-nullability-completeness
|
||||||
|
-Werror=shadow-uncaptured-local
|
||||||
|
-Werror=implicit-fallthrough
|
||||||
|
-Werror=type-limits
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
if (ARCHITECTURE_x86_64)
|
if (ARCHITECTURE_x86_64)
|
||||||
add_compile_options("-mcx16")
|
add_compile_options("-mcx16")
|
||||||
add_compile_options("-fwrapv")
|
add_compile_options("-fwrapv")
|
||||||
|
|
|
@ -460,11 +460,6 @@ S operator&(const S& i, const swap_struct_t<T, F> v) {
|
||||||
return i & v.swap();
|
return i & v.swap();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename S, typename T, typename F>
|
|
||||||
S operator&(const swap_struct_t<T, F> v, const S& i) {
|
|
||||||
return static_cast<S>(v.swap() & i);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Comparison
|
// Comparison
|
||||||
template <typename S, typename T, typename F>
|
template <typename S, typename T, typename F>
|
||||||
bool operator<(const S& p, const swap_struct_t<T, F> v) {
|
bool operator<(const S& p, const swap_struct_t<T, F> v) {
|
||||||
|
|
|
@ -273,7 +273,8 @@ struct System::Impl {
|
||||||
time_manager.Initialize();
|
time_manager.Initialize();
|
||||||
|
|
||||||
is_powered_on = true;
|
is_powered_on = true;
|
||||||
exit_lock = false;
|
exit_locked = false;
|
||||||
|
exit_requested = false;
|
||||||
|
|
||||||
microprofile_cpu[0] = MICROPROFILE_TOKEN(ARM_CPU0);
|
microprofile_cpu[0] = MICROPROFILE_TOKEN(ARM_CPU0);
|
||||||
microprofile_cpu[1] = MICROPROFILE_TOKEN(ARM_CPU1);
|
microprofile_cpu[1] = MICROPROFILE_TOKEN(ARM_CPU1);
|
||||||
|
@ -398,12 +399,14 @@ struct System::Impl {
|
||||||
}
|
}
|
||||||
|
|
||||||
is_powered_on = false;
|
is_powered_on = false;
|
||||||
exit_lock = false;
|
exit_locked = false;
|
||||||
|
exit_requested = false;
|
||||||
|
|
||||||
if (gpu_core != nullptr) {
|
if (gpu_core != nullptr) {
|
||||||
gpu_core->NotifyShutdown();
|
gpu_core->NotifyShutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Network::CancelPendingSocketOperations();
|
||||||
kernel.SuspendApplication(true);
|
kernel.SuspendApplication(true);
|
||||||
if (services) {
|
if (services) {
|
||||||
services->KillNVNFlinger();
|
services->KillNVNFlinger();
|
||||||
|
@ -425,6 +428,7 @@ struct System::Impl {
|
||||||
debugger.reset();
|
debugger.reset();
|
||||||
kernel.Shutdown();
|
kernel.Shutdown();
|
||||||
memory.Reset();
|
memory.Reset();
|
||||||
|
Network::RestartSocketOperations();
|
||||||
|
|
||||||
if (auto room_member = room_network.GetRoomMember().lock()) {
|
if (auto room_member = room_network.GetRoomMember().lock()) {
|
||||||
Network::GameInfo game_info{};
|
Network::GameInfo game_info{};
|
||||||
|
@ -507,7 +511,8 @@ struct System::Impl {
|
||||||
|
|
||||||
CpuManager cpu_manager;
|
CpuManager cpu_manager;
|
||||||
std::atomic_bool is_powered_on{};
|
std::atomic_bool is_powered_on{};
|
||||||
bool exit_lock = false;
|
bool exit_locked = false;
|
||||||
|
bool exit_requested = false;
|
||||||
|
|
||||||
bool nvdec_active{};
|
bool nvdec_active{};
|
||||||
|
|
||||||
|
@ -943,12 +948,20 @@ const Service::Time::TimeManager& System::GetTimeManager() const {
|
||||||
return impl->time_manager;
|
return impl->time_manager;
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::SetExitLock(bool locked) {
|
void System::SetExitLocked(bool locked) {
|
||||||
impl->exit_lock = locked;
|
impl->exit_locked = locked;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool System::GetExitLock() const {
|
bool System::GetExitLocked() const {
|
||||||
return impl->exit_lock;
|
return impl->exit_locked;
|
||||||
|
}
|
||||||
|
|
||||||
|
void System::SetExitRequested(bool requested) {
|
||||||
|
impl->exit_requested = requested;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool System::GetExitRequested() const {
|
||||||
|
return impl->exit_requested;
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::SetApplicationProcessBuildID(const CurrentBuildProcessID& id) {
|
void System::SetApplicationProcessBuildID(const CurrentBuildProcessID& id) {
|
||||||
|
|
|
@ -412,8 +412,11 @@ public:
|
||||||
/// Gets an immutable reference to the Room Network.
|
/// Gets an immutable reference to the Room Network.
|
||||||
[[nodiscard]] const Network::RoomNetwork& GetRoomNetwork() const;
|
[[nodiscard]] const Network::RoomNetwork& GetRoomNetwork() const;
|
||||||
|
|
||||||
void SetExitLock(bool locked);
|
void SetExitLocked(bool locked);
|
||||||
[[nodiscard]] bool GetExitLock() const;
|
bool GetExitLocked() const;
|
||||||
|
|
||||||
|
void SetExitRequested(bool requested);
|
||||||
|
bool GetExitRequested() const;
|
||||||
|
|
||||||
void SetApplicationProcessBuildID(const CurrentBuildProcessID& id);
|
void SetApplicationProcessBuildID(const CurrentBuildProcessID& id);
|
||||||
[[nodiscard]] const CurrentBuildProcessID& GetApplicationProcessBuildID() const;
|
[[nodiscard]] const CurrentBuildProcessID& GetApplicationProcessBuildID() const;
|
||||||
|
|
|
@ -341,7 +341,7 @@ void ISelfController::Exit(HLERequestContext& ctx) {
|
||||||
void ISelfController::LockExit(HLERequestContext& ctx) {
|
void ISelfController::LockExit(HLERequestContext& ctx) {
|
||||||
LOG_DEBUG(Service_AM, "called");
|
LOG_DEBUG(Service_AM, "called");
|
||||||
|
|
||||||
system.SetExitLock(true);
|
system.SetExitLocked(true);
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
|
@ -350,10 +350,14 @@ void ISelfController::LockExit(HLERequestContext& ctx) {
|
||||||
void ISelfController::UnlockExit(HLERequestContext& ctx) {
|
void ISelfController::UnlockExit(HLERequestContext& ctx) {
|
||||||
LOG_DEBUG(Service_AM, "called");
|
LOG_DEBUG(Service_AM, "called");
|
||||||
|
|
||||||
system.SetExitLock(false);
|
system.SetExitLocked(false);
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
|
|
||||||
|
if (system.GetExitRequested()) {
|
||||||
|
system.Exit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ISelfController::EnterFatalSection(HLERequestContext& ctx) {
|
void ISelfController::EnterFatalSection(HLERequestContext& ctx) {
|
||||||
|
|
|
@ -48,15 +48,32 @@ enum class CallType {
|
||||||
|
|
||||||
using socklen_t = int;
|
using socklen_t = int;
|
||||||
|
|
||||||
|
SOCKET interrupt_socket = static_cast<SOCKET>(-1);
|
||||||
|
|
||||||
|
void InterruptSocketOperations() {
|
||||||
|
closesocket(interrupt_socket);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AcknowledgeInterrupt() {
|
||||||
|
interrupt_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||||
|
}
|
||||||
|
|
||||||
void Initialize() {
|
void Initialize() {
|
||||||
WSADATA wsa_data;
|
WSADATA wsa_data;
|
||||||
(void)WSAStartup(MAKEWORD(2, 2), &wsa_data);
|
(void)WSAStartup(MAKEWORD(2, 2), &wsa_data);
|
||||||
|
|
||||||
|
AcknowledgeInterrupt();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Finalize() {
|
void Finalize() {
|
||||||
|
InterruptSocketOperations();
|
||||||
WSACleanup();
|
WSACleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SOCKET GetInterruptSocket() {
|
||||||
|
return interrupt_socket;
|
||||||
|
}
|
||||||
|
|
||||||
sockaddr TranslateFromSockAddrIn(SockAddrIn input) {
|
sockaddr TranslateFromSockAddrIn(SockAddrIn input) {
|
||||||
sockaddr_in result;
|
sockaddr_in result;
|
||||||
|
|
||||||
|
@ -157,9 +174,39 @@ constexpr int SD_RECEIVE = SHUT_RD;
|
||||||
constexpr int SD_SEND = SHUT_WR;
|
constexpr int SD_SEND = SHUT_WR;
|
||||||
constexpr int SD_BOTH = SHUT_RDWR;
|
constexpr int SD_BOTH = SHUT_RDWR;
|
||||||
|
|
||||||
void Initialize() {}
|
int interrupt_pipe_fd[2] = {-1, -1};
|
||||||
|
|
||||||
void Finalize() {}
|
void Initialize() {
|
||||||
|
if (pipe(interrupt_pipe_fd) != 0) {
|
||||||
|
LOG_ERROR(Network, "Failed to create interrupt pipe!");
|
||||||
|
}
|
||||||
|
int flags = fcntl(interrupt_pipe_fd[0], F_GETFL);
|
||||||
|
ASSERT_MSG(fcntl(interrupt_pipe_fd[0], F_SETFL, flags | O_NONBLOCK) == 0,
|
||||||
|
"Failed to set nonblocking state for interrupt pipe");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Finalize() {
|
||||||
|
if (interrupt_pipe_fd[0] >= 0) {
|
||||||
|
close(interrupt_pipe_fd[0]);
|
||||||
|
}
|
||||||
|
if (interrupt_pipe_fd[1] >= 0) {
|
||||||
|
close(interrupt_pipe_fd[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void InterruptSocketOperations() {
|
||||||
|
u8 value = 0;
|
||||||
|
ASSERT(write(interrupt_pipe_fd[1], &value, sizeof(value)) == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AcknowledgeInterrupt() {
|
||||||
|
u8 value = 0;
|
||||||
|
read(interrupt_pipe_fd[0], &value, sizeof(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
SOCKET GetInterruptSocket() {
|
||||||
|
return interrupt_pipe_fd[0];
|
||||||
|
}
|
||||||
|
|
||||||
sockaddr TranslateFromSockAddrIn(SockAddrIn input) {
|
sockaddr TranslateFromSockAddrIn(SockAddrIn input) {
|
||||||
sockaddr_in result;
|
sockaddr_in result;
|
||||||
|
@ -490,6 +537,14 @@ NetworkInstance::~NetworkInstance() {
|
||||||
Finalize();
|
Finalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CancelPendingSocketOperations() {
|
||||||
|
InterruptSocketOperations();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RestartSocketOperations() {
|
||||||
|
AcknowledgeInterrupt();
|
||||||
|
}
|
||||||
|
|
||||||
std::optional<IPv4Address> GetHostIPv4Address() {
|
std::optional<IPv4Address> GetHostIPv4Address() {
|
||||||
const auto network_interface = Network::GetSelectedNetworkInterface();
|
const auto network_interface = Network::GetSelectedNetworkInterface();
|
||||||
if (!network_interface.has_value()) {
|
if (!network_interface.has_value()) {
|
||||||
|
@ -560,7 +615,14 @@ std::pair<s32, Errno> Poll(std::vector<PollFD>& pollfds, s32 timeout) {
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
|
|
||||||
const int result = WSAPoll(host_pollfds.data(), static_cast<ULONG>(num), timeout);
|
host_pollfds.push_back(WSAPOLLFD{
|
||||||
|
.fd = GetInterruptSocket(),
|
||||||
|
.events = POLLIN,
|
||||||
|
.revents = 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
const int result =
|
||||||
|
WSAPoll(host_pollfds.data(), static_cast<ULONG>(host_pollfds.size()), timeout);
|
||||||
if (result == 0) {
|
if (result == 0) {
|
||||||
ASSERT(std::all_of(host_pollfds.begin(), host_pollfds.end(),
|
ASSERT(std::all_of(host_pollfds.begin(), host_pollfds.end(),
|
||||||
[](WSAPOLLFD fd) { return fd.revents == 0; }));
|
[](WSAPOLLFD fd) { return fd.revents == 0; }));
|
||||||
|
@ -627,6 +689,24 @@ Errno Socket::Initialize(Domain domain, Type type, Protocol protocol) {
|
||||||
std::pair<SocketBase::AcceptResult, Errno> Socket::Accept() {
|
std::pair<SocketBase::AcceptResult, Errno> Socket::Accept() {
|
||||||
sockaddr_in addr;
|
sockaddr_in addr;
|
||||||
socklen_t addrlen = sizeof(addr);
|
socklen_t addrlen = sizeof(addr);
|
||||||
|
|
||||||
|
std::vector<WSAPOLLFD> host_pollfds{
|
||||||
|
WSAPOLLFD{fd, POLLIN, 0},
|
||||||
|
WSAPOLLFD{GetInterruptSocket(), POLLIN, 0},
|
||||||
|
};
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const int pollres =
|
||||||
|
WSAPoll(host_pollfds.data(), static_cast<ULONG>(host_pollfds.size()), -1);
|
||||||
|
if (host_pollfds[1].revents != 0) {
|
||||||
|
// Interrupt signaled before a client could be accepted, break
|
||||||
|
return {AcceptResult{}, Errno::AGAIN};
|
||||||
|
}
|
||||||
|
if (pollres > 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const SOCKET new_socket = accept(fd, reinterpret_cast<sockaddr*>(&addr), &addrlen);
|
const SOCKET new_socket = accept(fd, reinterpret_cast<sockaddr*>(&addr), &addrlen);
|
||||||
|
|
||||||
if (new_socket == INVALID_SOCKET) {
|
if (new_socket == INVALID_SOCKET) {
|
||||||
|
|
|
@ -96,6 +96,9 @@ public:
|
||||||
~NetworkInstance();
|
~NetworkInstance();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void CancelPendingSocketOperations();
|
||||||
|
void RestartSocketOperations();
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
constexpr IPv4Address TranslateIPv4(in_addr addr) {
|
constexpr IPv4Address TranslateIPv4(in_addr addr) {
|
||||||
auto& bytes = addr.S_un.S_un_b;
|
auto& bytes = addr.S_un.S_un_b;
|
||||||
|
|
|
@ -835,15 +835,15 @@ public:
|
||||||
return input_engine->SupportsNfc(identifier);
|
return input_engine->SupportsNfc(identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
Common::Input::NfcState StartNfcPolling() {
|
Common::Input::NfcState StartNfcPolling() override {
|
||||||
return input_engine->StartNfcPolling(identifier);
|
return input_engine->StartNfcPolling(identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
Common::Input::NfcState StopNfcPolling() {
|
Common::Input::NfcState StopNfcPolling() override {
|
||||||
return input_engine->StopNfcPolling(identifier);
|
return input_engine->StopNfcPolling(identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
Common::Input::NfcState ReadAmiiboData(std::vector<u8>& out_data) {
|
Common::Input::NfcState ReadAmiiboData(std::vector<u8>& out_data) override {
|
||||||
return input_engine->ReadAmiiboData(identifier, out_data);
|
return input_engine->ReadAmiiboData(identifier, out_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -852,11 +852,11 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
Common::Input::NfcState ReadMifareData(const Common::Input::MifareRequest& request,
|
Common::Input::NfcState ReadMifareData(const Common::Input::MifareRequest& request,
|
||||||
Common::Input::MifareRequest& out_data) {
|
Common::Input::MifareRequest& out_data) override {
|
||||||
return input_engine->ReadMifareData(identifier, request, out_data);
|
return input_engine->ReadMifareData(identifier, request, out_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
Common::Input::NfcState WriteMifareData(const Common::Input::MifareRequest& request) {
|
Common::Input::NfcState WriteMifareData(const Common::Input::MifareRequest& request) override {
|
||||||
return input_engine->WriteMifareData(identifier, request);
|
return input_engine->WriteMifareData(identifier, request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,14 +27,24 @@ MICROPROFILE_DEFINE(MacroHLE, "GPU", "Execute macro HLE", MP_RGB(128, 192, 192))
|
||||||
|
|
||||||
namespace Tegra {
|
namespace Tegra {
|
||||||
|
|
||||||
static void Dump(u64 hash, std::span<const u32> code) {
|
static void Dump(u64 hash, std::span<const u32> code, bool decompiled = false) {
|
||||||
const auto base_dir{Common::FS::GetYuzuPath(Common::FS::YuzuPath::DumpDir)};
|
const auto base_dir{Common::FS::GetYuzuPath(Common::FS::YuzuPath::DumpDir)};
|
||||||
const auto macro_dir{base_dir / "macros"};
|
const auto macro_dir{base_dir / "macros"};
|
||||||
if (!Common::FS::CreateDir(base_dir) || !Common::FS::CreateDir(macro_dir)) {
|
if (!Common::FS::CreateDir(base_dir) || !Common::FS::CreateDir(macro_dir)) {
|
||||||
LOG_ERROR(Common_Filesystem, "Failed to create macro dump directories");
|
LOG_ERROR(Common_Filesystem, "Failed to create macro dump directories");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto name{macro_dir / fmt::format("{:016x}.macro", hash)};
|
auto name{macro_dir / fmt::format("{:016x}.macro", hash)};
|
||||||
|
|
||||||
|
if (decompiled) {
|
||||||
|
auto new_name{macro_dir / fmt::format("decompiled_{:016x}.macro", hash)};
|
||||||
|
if (Common::FS::Exists(name)) {
|
||||||
|
(void)Common::FS::RenameFile(name, new_name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
name = new_name;
|
||||||
|
}
|
||||||
|
|
||||||
std::fstream macro_file(name, std::ios::out | std::ios::binary);
|
std::fstream macro_file(name, std::ios::out | std::ios::binary);
|
||||||
if (!macro_file) {
|
if (!macro_file) {
|
||||||
LOG_ERROR(Common_Filesystem, "Unable to open or create file at {}",
|
LOG_ERROR(Common_Filesystem, "Unable to open or create file at {}",
|
||||||
|
@ -90,9 +100,6 @@ void MacroEngine::Execute(u32 method, const std::vector<u32>& parameters) {
|
||||||
if (!mid_method.has_value()) {
|
if (!mid_method.has_value()) {
|
||||||
cache_info.lle_program = Compile(macro_code->second);
|
cache_info.lle_program = Compile(macro_code->second);
|
||||||
cache_info.hash = Common::HashValue(macro_code->second);
|
cache_info.hash = Common::HashValue(macro_code->second);
|
||||||
if (Settings::values.dump_macros) {
|
|
||||||
Dump(cache_info.hash, macro_code->second);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
const auto& macro_cached = uploaded_macro_code[mid_method.value()];
|
const auto& macro_cached = uploaded_macro_code[mid_method.value()];
|
||||||
const auto rebased_method = method - mid_method.value();
|
const auto rebased_method = method - mid_method.value();
|
||||||
|
@ -102,9 +109,6 @@ void MacroEngine::Execute(u32 method, const std::vector<u32>& parameters) {
|
||||||
code.size() * sizeof(u32));
|
code.size() * sizeof(u32));
|
||||||
cache_info.hash = Common::HashValue(code);
|
cache_info.hash = Common::HashValue(code);
|
||||||
cache_info.lle_program = Compile(code);
|
cache_info.lle_program = Compile(code);
|
||||||
if (Settings::values.dump_macros) {
|
|
||||||
Dump(cache_info.hash, code);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto hle_program = hle_macros->GetHLEProgram(cache_info.hash);
|
auto hle_program = hle_macros->GetHLEProgram(cache_info.hash);
|
||||||
|
@ -117,6 +121,10 @@ void MacroEngine::Execute(u32 method, const std::vector<u32>& parameters) {
|
||||||
MICROPROFILE_SCOPE(MacroHLE);
|
MICROPROFILE_SCOPE(MacroHLE);
|
||||||
cache_info.hle_program->Execute(parameters, method);
|
cache_info.hle_program->Execute(parameters, method);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Settings::values.dump_macros) {
|
||||||
|
Dump(cache_info.hash, macro_code->second, cache_info.has_hle_program);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -611,9 +611,6 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(
|
||||||
|
|
||||||
const u32 cfg_offset{static_cast<u32>(env.StartAddress() + sizeof(Shader::ProgramHeader))};
|
const u32 cfg_offset{static_cast<u32>(env.StartAddress() + sizeof(Shader::ProgramHeader))};
|
||||||
Shader::Maxwell::Flow::CFG cfg(env, pools.flow_block, cfg_offset, index == 0);
|
Shader::Maxwell::Flow::CFG cfg(env, pools.flow_block, cfg_offset, index == 0);
|
||||||
if (Settings::values.dump_shaders) {
|
|
||||||
env.Dump(hash, key.unique_hashes[index]);
|
|
||||||
}
|
|
||||||
if (!uses_vertex_a || index != 1) {
|
if (!uses_vertex_a || index != 1) {
|
||||||
// Normal path
|
// Normal path
|
||||||
programs[index] = TranslateProgram(pools.inst, pools.block, env, cfg, host_info);
|
programs[index] = TranslateProgram(pools.inst, pools.block, env, cfg, host_info);
|
||||||
|
@ -624,6 +621,10 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(
|
||||||
programs[index] = MergeDualVertexPrograms(program_va, program_vb, env);
|
programs[index] = MergeDualVertexPrograms(program_va, program_vb, env);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Settings::values.dump_shaders) {
|
||||||
|
env.Dump(hash, key.unique_hashes[index]);
|
||||||
|
}
|
||||||
|
|
||||||
if (programs[index].info.requires_layer_emulation) {
|
if (programs[index].info.requires_layer_emulation) {
|
||||||
layer_source_program = &programs[index];
|
layer_source_program = &programs[index];
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#if defined(__GNUC__) || defined(__clang__)
|
#if defined(__GNUC__) || defined(__clang__)
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
|
#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
|
||||||
|
#pragma GCC diagnostic ignored "-Wdeprecated-declarations" // for deprecated OpenSSL functions
|
||||||
#endif
|
#endif
|
||||||
#include <jwt/jwt.hpp>
|
#include <jwt/jwt.hpp>
|
||||||
#if defined(__GNUC__) || defined(__clang__)
|
#if defined(__GNUC__) || defined(__clang__)
|
||||||
|
|
|
@ -2010,8 +2010,16 @@ bool GMainWindow::OnShutdownBegin() {
|
||||||
|
|
||||||
emit EmulationStopping();
|
emit EmulationStopping();
|
||||||
|
|
||||||
|
int shutdown_time = 1000;
|
||||||
|
|
||||||
|
if (system->DebuggerEnabled()) {
|
||||||
|
shutdown_time = 0;
|
||||||
|
} else if (system->GetExitLocked()) {
|
||||||
|
shutdown_time = 5000;
|
||||||
|
}
|
||||||
|
|
||||||
shutdown_timer.setSingleShot(true);
|
shutdown_timer.setSingleShot(true);
|
||||||
shutdown_timer.start(system->DebuggerEnabled() ? 0 : 5000);
|
shutdown_timer.start(shutdown_time);
|
||||||
connect(&shutdown_timer, &QTimer::timeout, this, &GMainWindow::OnEmulationStopTimeExpired);
|
connect(&shutdown_timer, &QTimer::timeout, this, &GMainWindow::OnEmulationStopTimeExpired);
|
||||||
connect(emu_thread.get(), &QThread::finished, this, &GMainWindow::OnEmulationStopped);
|
connect(emu_thread.get(), &QThread::finished, this, &GMainWindow::OnEmulationStopped);
|
||||||
|
|
||||||
|
@ -2573,50 +2581,41 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
FileSys::VirtualFile base_romfs;
|
FileSys::VirtualFile packed_update_raw{};
|
||||||
if (loader->ReadRomFS(base_romfs) != Loader::ResultStatus::Success) {
|
loader->ReadUpdateRaw(packed_update_raw);
|
||||||
failed();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto& installed = system->GetContentProvider();
|
const auto& installed = system->GetContentProvider();
|
||||||
const auto romfs_title_id = SelectRomFSDumpTarget(installed, program_id);
|
|
||||||
|
|
||||||
if (!romfs_title_id) {
|
u64 title_id{};
|
||||||
|
u8 raw_type{};
|
||||||
|
if (!SelectRomFSDumpTarget(installed, program_id, &title_id, &raw_type)) {
|
||||||
failed();
|
failed();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto type = *romfs_title_id == program_id ? FileSys::ContentRecordType::Program
|
const auto type = static_cast<FileSys::ContentRecordType>(raw_type);
|
||||||
: FileSys::ContentRecordType::Data;
|
const auto base_nca = installed.GetEntry(title_id, type);
|
||||||
const auto base_nca = installed.GetEntry(*romfs_title_id, type);
|
|
||||||
if (!base_nca) {
|
if (!base_nca) {
|
||||||
failed();
|
failed();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto base_romfs = base_nca->GetRomFS();
|
||||||
|
if (!base_romfs) {
|
||||||
|
failed();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const auto dump_dir =
|
const auto dump_dir =
|
||||||
target == DumpRomFSTarget::Normal
|
target == DumpRomFSTarget::Normal
|
||||||
? Common::FS::GetYuzuPath(Common::FS::YuzuPath::DumpDir)
|
? Common::FS::GetYuzuPath(Common::FS::YuzuPath::DumpDir)
|
||||||
: Common::FS::GetYuzuPath(Common::FS::YuzuPath::SDMCDir) / "atmosphere" / "contents";
|
: Common::FS::GetYuzuPath(Common::FS::YuzuPath::SDMCDir) / "atmosphere" / "contents";
|
||||||
const auto romfs_dir = fmt::format("{:016X}/romfs", *romfs_title_id);
|
const auto romfs_dir = fmt::format("{:016X}/romfs", title_id);
|
||||||
|
|
||||||
const auto path = Common::FS::PathToUTF8String(dump_dir / romfs_dir);
|
const auto path = Common::FS::PathToUTF8String(dump_dir / romfs_dir);
|
||||||
|
|
||||||
FileSys::VirtualFile romfs;
|
const FileSys::PatchManager pm{title_id, system->GetFileSystemController(), installed};
|
||||||
|
auto romfs = pm.PatchRomFS(base_nca.get(), base_romfs, type, packed_update_raw, false);
|
||||||
if (*romfs_title_id == program_id) {
|
|
||||||
const FileSys::PatchManager pm{program_id, system->GetFileSystemController(), installed};
|
|
||||||
romfs = pm.PatchRomFS(base_nca.get(), base_romfs, type, nullptr, false);
|
|
||||||
} else {
|
|
||||||
romfs = installed.GetEntry(*romfs_title_id, type)->GetRomFS();
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto extracted = FileSys::ExtractRomFS(romfs, FileSys::RomFSExtractionType::Full);
|
|
||||||
if (extracted == nullptr) {
|
|
||||||
failed();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto out = VfsFilesystemCreateDirectoryWrapper(vfs, path, FileSys::Mode::ReadWrite);
|
const auto out = VfsFilesystemCreateDirectoryWrapper(vfs, path, FileSys::Mode::ReadWrite);
|
||||||
|
|
||||||
|
@ -2640,6 +2639,12 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto extracted = FileSys::ExtractRomFS(romfs, FileSys::RomFSExtractionType::Full);
|
||||||
|
if (extracted == nullptr) {
|
||||||
|
failed();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const auto full = res == selections.constFirst();
|
const auto full = res == selections.constFirst();
|
||||||
const auto entry_size = CalculateRomFSEntrySize(extracted, full);
|
const auto entry_size = CalculateRomFSEntrySize(extracted, full);
|
||||||
|
|
||||||
|
@ -3261,7 +3266,7 @@ void GMainWindow::OnPauseContinueGame() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GMainWindow::OnStopGame() {
|
void GMainWindow::OnStopGame() {
|
||||||
if (system->GetExitLock() && !ConfirmForceLockedExit()) {
|
if (system->GetExitLocked() && !ConfirmForceLockedExit()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4350,28 +4355,41 @@ bool GMainWindow::CheckSystemArchiveDecryption() {
|
||||||
return mii_nca->GetRomFS().get() != nullptr;
|
return mii_nca->GetRomFS().get() != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<u64> GMainWindow::SelectRomFSDumpTarget(const FileSys::ContentProvider& installed,
|
bool GMainWindow::SelectRomFSDumpTarget(const FileSys::ContentProvider& installed, u64 program_id,
|
||||||
u64 program_id) {
|
u64* selected_title_id, u8* selected_content_record_type) {
|
||||||
const auto dlc_entries =
|
using ContentInfo = std::pair<FileSys::TitleType, FileSys::ContentRecordType>;
|
||||||
installed.ListEntriesFilter(FileSys::TitleType::AOC, FileSys::ContentRecordType::Data);
|
boost::container::flat_map<u64, ContentInfo> available_title_ids;
|
||||||
std::vector<FileSys::ContentProviderEntry> dlc_match;
|
|
||||||
dlc_match.reserve(dlc_entries.size());
|
|
||||||
std::copy_if(dlc_entries.begin(), dlc_entries.end(), std::back_inserter(dlc_match),
|
|
||||||
[&program_id, &installed](const FileSys::ContentProviderEntry& entry) {
|
|
||||||
return FileSys::GetBaseTitleID(entry.title_id) == program_id &&
|
|
||||||
installed.GetEntry(entry)->GetStatus() == Loader::ResultStatus::Success;
|
|
||||||
});
|
|
||||||
|
|
||||||
std::vector<u64> romfs_tids;
|
const auto RetrieveEntries = [&](FileSys::TitleType title_type,
|
||||||
romfs_tids.push_back(program_id);
|
FileSys::ContentRecordType record_type) {
|
||||||
for (const auto& entry : dlc_match) {
|
const auto entries = installed.ListEntriesFilter(title_type, record_type);
|
||||||
romfs_tids.push_back(entry.title_id);
|
for (const auto& entry : entries) {
|
||||||
|
if (FileSys::GetBaseTitleID(entry.title_id) == program_id &&
|
||||||
|
installed.GetEntry(entry)->GetStatus() == Loader::ResultStatus::Success) {
|
||||||
|
available_title_ids[entry.title_id] = {title_type, record_type};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
RetrieveEntries(FileSys::TitleType::Application, FileSys::ContentRecordType::Program);
|
||||||
|
RetrieveEntries(FileSys::TitleType::AOC, FileSys::ContentRecordType::Data);
|
||||||
|
|
||||||
|
if (available_title_ids.empty()) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (romfs_tids.size() > 1) {
|
size_t title_index = 0;
|
||||||
QStringList list{QStringLiteral("Base")};
|
|
||||||
for (std::size_t i = 1; i < romfs_tids.size(); ++i) {
|
if (available_title_ids.size() > 1) {
|
||||||
list.push_back(QStringLiteral("DLC %1").arg(romfs_tids[i] & 0x7FF));
|
QStringList list;
|
||||||
|
for (auto& [title_id, content_info] : available_title_ids) {
|
||||||
|
const auto hex_title_id = QString::fromStdString(fmt::format("{:X}", title_id));
|
||||||
|
if (content_info.first == FileSys::TitleType::Application) {
|
||||||
|
list.push_back(QStringLiteral("Application [%1]").arg(hex_title_id));
|
||||||
|
} else {
|
||||||
|
list.push_back(
|
||||||
|
QStringLiteral("DLC %1 [%2]").arg(title_id & 0x7FF).arg(hex_title_id));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ok;
|
bool ok;
|
||||||
|
@ -4379,13 +4397,16 @@ std::optional<u64> GMainWindow::SelectRomFSDumpTarget(const FileSys::ContentProv
|
||||||
this, tr("Select RomFS Dump Target"),
|
this, tr("Select RomFS Dump Target"),
|
||||||
tr("Please select which RomFS you would like to dump."), list, 0, false, &ok);
|
tr("Please select which RomFS you would like to dump."), list, 0, false, &ok);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
return {};
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return romfs_tids[list.indexOf(res)];
|
title_index = list.indexOf(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
return program_id;
|
const auto selected_info = available_title_ids.nth(title_index);
|
||||||
|
*selected_title_id = selected_info->first;
|
||||||
|
*selected_content_record_type = static_cast<u8>(selected_info->second.second);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GMainWindow::ConfirmClose() {
|
bool GMainWindow::ConfirmClose() {
|
||||||
|
@ -4515,6 +4536,8 @@ void GMainWindow::RequestGameExit() {
|
||||||
auto applet_ae = sm.GetService<Service::AM::AppletAE>("appletAE");
|
auto applet_ae = sm.GetService<Service::AM::AppletAE>("appletAE");
|
||||||
bool has_signalled = false;
|
bool has_signalled = false;
|
||||||
|
|
||||||
|
system->SetExitRequested(true);
|
||||||
|
|
||||||
if (applet_oe != nullptr) {
|
if (applet_oe != nullptr) {
|
||||||
applet_oe->GetMessageQueue()->RequestExit();
|
applet_oe->GetMessageQueue()->RequestExit();
|
||||||
has_signalled = true;
|
has_signalled = true;
|
||||||
|
|
|
@ -375,7 +375,8 @@ private:
|
||||||
void RemoveAllTransferableShaderCaches(u64 program_id);
|
void RemoveAllTransferableShaderCaches(u64 program_id);
|
||||||
void RemoveCustomConfiguration(u64 program_id, const std::string& game_path);
|
void RemoveCustomConfiguration(u64 program_id, const std::string& game_path);
|
||||||
void RemoveCacheStorage(u64 program_id);
|
void RemoveCacheStorage(u64 program_id);
|
||||||
std::optional<u64> SelectRomFSDumpTarget(const FileSys::ContentProvider&, u64 program_id);
|
bool SelectRomFSDumpTarget(const FileSys::ContentProvider&, u64 program_id,
|
||||||
|
u64* selected_title_id, u8* selected_content_record_type);
|
||||||
InstallResult InstallNSPXCI(const QString& filename);
|
InstallResult InstallNSPXCI(const QString& filename);
|
||||||
InstallResult InstallNCA(const QString& filename);
|
InstallResult InstallNCA(const QString& filename);
|
||||||
void MigrateConfigFiles();
|
void MigrateConfigFiles();
|
||||||
|
|
Loading…
Reference in a new issue