mirror of https://github.com/PCSX2/pcsx2.git
PINE: Update to the age of Qt
This commit is contained in:
parent
1964bbc03a
commit
e3962aa794
|
@ -67,6 +67,9 @@ AdvancedSettingsWidget::AdvancedSettingsWidget(SettingsDialog* dialog, QWidget*
|
|||
SettingWidgetBinder::BindWidgetToFloatSetting(sif, m_ui.ntscFrameRate, "EmuCore/GS", "FramerateNTSC", 59.94f);
|
||||
SettingWidgetBinder::BindWidgetToFloatSetting(sif, m_ui.palFrameRate, "EmuCore/GS", "FrameratePAL", 50.00f);
|
||||
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pineEnable, "EmuCore", "EnablePINE", false);
|
||||
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_ui.pineSlot, "EmuCore", "PINESlot", 28011);
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.eeRoundingMode, tr("Rounding Mode"), tr("Chop / Zero (Default)"), tr(""));
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.eeClampMode, tr("Clamping Mode"), tr("Normal (Default)"), tr(""));
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>809</width>
|
||||
<height>647</height>
|
||||
<height>725</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
|
@ -37,7 +37,7 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>807</width>
|
||||
<height>645</height>
|
||||
<height>723</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
|
@ -417,6 +417,45 @@
|
|||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_5">
|
||||
<property name="title">
|
||||
<string>PINE Settings</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_8">
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="pineSlot">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Slot:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="pineEnable">
|
||||
<property name="text">
|
||||
<string>Enable</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "PerformanceMetrics.h"
|
||||
#include "Sio.h"
|
||||
#include "VMManager.h"
|
||||
#include "PINE.h"
|
||||
|
||||
#include "common/Assertions.h"
|
||||
#include "common/CrashHandler.h"
|
||||
|
@ -77,6 +78,8 @@ static std::string s_session_serial;
|
|||
|
||||
static bool s_screensaver_inhibited = false;
|
||||
|
||||
static PINEServer s_pine_server;
|
||||
|
||||
#ifdef ENABLE_DISCORD_PRESENCE
|
||||
static bool s_discord_presence_active = false;
|
||||
#endif
|
||||
|
@ -272,6 +275,8 @@ void CommonHost::CPUThreadInitialize()
|
|||
if (EmuConfig.EnableDiscordPresence)
|
||||
InitializeDiscordPresence();
|
||||
#endif
|
||||
|
||||
ReloadPINE();
|
||||
}
|
||||
|
||||
void CommonHost::CPUThreadShutdown()
|
||||
|
@ -284,6 +289,8 @@ void CommonHost::CPUThreadShutdown()
|
|||
Achievements::Shutdown();
|
||||
#endif
|
||||
|
||||
s_pine_server.Deinitialize();
|
||||
|
||||
InputManager::CloseSources();
|
||||
VMManager::WaitForSaveStateFlush();
|
||||
VMManager::Internal::ReleaseMemory();
|
||||
|
@ -379,6 +386,8 @@ void CommonHost::OnGameChanged(const std::string& disc_path, const std::string&
|
|||
#ifdef ENABLE_DISCORD_PRESENCE
|
||||
UpdateDiscordPresence(GetRichPresenceString());
|
||||
#endif
|
||||
|
||||
ReloadPINE();
|
||||
}
|
||||
|
||||
void CommonHost::CPUThreadVSync()
|
||||
|
@ -539,4 +548,20 @@ std::string CommonHost::GetRichPresenceString()
|
|||
return rich_presence_string;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void CommonHost::ReloadPINE()
|
||||
{
|
||||
if (EmuConfig.EnablePINE && (s_pine_server.m_slot != EmuConfig.PINESlot || s_pine_server.m_end))
|
||||
{
|
||||
if (!s_pine_server.m_end)
|
||||
{
|
||||
s_pine_server.Deinitialize();
|
||||
}
|
||||
s_pine_server.Initialize(EmuConfig.PINESlot);
|
||||
}
|
||||
else if ((!EmuConfig.EnablePINE && !s_pine_server.m_end))
|
||||
{
|
||||
s_pine_server.Deinitialize();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -85,6 +85,9 @@ namespace CommonHost
|
|||
void UpdateDiscordPresence(const std::string& rich_presence);
|
||||
#endif
|
||||
|
||||
/// Reloads PINE IPC Server if needed. Does nothing if it's already running on the correct port.
|
||||
void ReloadPINE();
|
||||
|
||||
namespace Internal
|
||||
{
|
||||
/// Resets any state for hotkey-related VMs, called on VM startup.
|
||||
|
|
|
@ -1293,6 +1293,8 @@ struct Pcsx2Config
|
|||
McdOptions Mcd[8];
|
||||
std::string GzipIsoIndexTemplate; // for quick-access index with gzipped ISO
|
||||
|
||||
int PINESlot;
|
||||
|
||||
// Set at runtime, not loaded from config.
|
||||
std::string CurrentBlockdump;
|
||||
std::string CurrentIRX;
|
||||
|
|
|
@ -27,6 +27,7 @@ u32 ElfEntry;
|
|||
std::pair<u32,u32> ElfTextRange;
|
||||
std::string LastELF;
|
||||
bool isPSXElf;
|
||||
std::string ElfVersion;
|
||||
|
||||
// All of ElfObjects functions.
|
||||
ElfObject::ElfObject(std::string srcfile, IsoFile& isofile, bool isPSXElf)
|
||||
|
@ -365,6 +366,7 @@ int GetPS2ElfName( std::string& name )
|
|||
{
|
||||
Console.WriteLn( Color_Blue, "(SYSTEM.CNF) Software version = %.*s",
|
||||
static_cast<int>(value.size()), value.data());
|
||||
ElfVersion = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -163,3 +163,4 @@ extern u32 ElfEntry;
|
|||
extern std::pair<u32,u32> ElfTextRange;
|
||||
extern std::string LastELF;
|
||||
extern bool isPSXElf;
|
||||
extern std::string ElfVersion;
|
||||
|
|
250
pcsx2/PINE.cpp
250
pcsx2/PINE.cpp
|
@ -15,15 +15,12 @@
|
|||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#ifdef PCSX2_LEFTOVER_FROM_WX
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <thread>
|
||||
#include <sys/types.h>
|
||||
#if _WIN32
|
||||
#define read_portable(a, b, c) (recv(a, b, c, 0))
|
||||
#define write_portable(a, b, c) (send(a, b, c, 0))
|
||||
#define read_portable(a, b, c) (recv(a, (char*)b, c, 0))
|
||||
#define write_portable(a, b, c) (send(a, (const char*)b, c, 0))
|
||||
#define close_portable(a) (closesocket(a))
|
||||
#define bzero(b, len) (memset((b), '\0', (len)), (void)0)
|
||||
#include <WinSock2.h>
|
||||
|
@ -34,35 +31,44 @@
|
|||
#define close_portable(a) (close(a))
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "Common.h"
|
||||
#include "Memory.h"
|
||||
#include "gui/AppSaveStates.h"
|
||||
#include "gui/AppCoreThread.h"
|
||||
#include "gui/SysThreads.h"
|
||||
#include "Elfheader.h"
|
||||
#include "pcsx2/VMManager.h"
|
||||
#include "svnrev.h"
|
||||
#include "PINE.h"
|
||||
|
||||
PINEServer::PINEServer(SysCoreThread* vm, unsigned int slot)
|
||||
: pxThread("PINE_Server")
|
||||
PINEServer::PINEServer() {}
|
||||
|
||||
PINEServer::~PINEServer()
|
||||
{
|
||||
Deinitialize();
|
||||
}
|
||||
|
||||
bool PINEServer::Initialize(int slot)
|
||||
{
|
||||
m_end.store(false, std::memory_order_release);
|
||||
m_slot = slot;
|
||||
#ifdef _WIN32
|
||||
WSADATA wsa;
|
||||
struct sockaddr_in server;
|
||||
|
||||
|
||||
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
|
||||
{
|
||||
Console.WriteLn(Color_Red, "PINE: Cannot initialize winsock! Shutting down...");
|
||||
return;
|
||||
Deinitialize();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if ((m_sock == INVALID_SOCKET) || slot > 65536)
|
||||
{
|
||||
Console.WriteLn(Color_Red, "PINE: Cannot open socket! Shutting down...");
|
||||
return;
|
||||
Deinitialize();
|
||||
return false;
|
||||
}
|
||||
|
||||
// yes very good windows s/sun/sin/g sure is fine
|
||||
|
@ -74,7 +80,8 @@ PINEServer::PINEServer(SysCoreThread* vm, unsigned int slot)
|
|||
if (bind(m_sock, (struct sockaddr*)&server, sizeof(server)) == SOCKET_ERROR)
|
||||
{
|
||||
Console.WriteLn(Color_Red, "PINE: Error while binding to socket! Shutting down...");
|
||||
return;
|
||||
Deinitialize();
|
||||
return false;
|
||||
}
|
||||
|
||||
#else
|
||||
|
@ -103,7 +110,8 @@ PINEServer::PINEServer(SysCoreThread* vm, unsigned int slot)
|
|||
if (m_sock < 0)
|
||||
{
|
||||
Console.WriteLn(Color_Red, "PINE: Cannot open socket! Shutting down...");
|
||||
return;
|
||||
Deinitialize();
|
||||
return false;
|
||||
}
|
||||
server.sun_family = AF_UNIX;
|
||||
strcpy(server.sun_path, m_socket_name.c_str());
|
||||
|
@ -114,32 +122,42 @@ PINEServer::PINEServer(SysCoreThread* vm, unsigned int slot)
|
|||
if (bind(m_sock, (struct sockaddr*)&server, sizeof(struct sockaddr_un)))
|
||||
{
|
||||
Console.WriteLn(Color_Red, "PINE: Error while binding to socket! Shutting down...");
|
||||
return;
|
||||
Deinitialize();
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
// maximum queue of 4096 commands before refusing, approximated to the
|
||||
// nearest legal value. We do not use SOMAXCONN as windows have this idea
|
||||
// that a "reasonable" value is 5, which is not.
|
||||
listen(m_sock, 4096);
|
||||
if (listen(m_sock, 4096))
|
||||
{
|
||||
Console.WriteLn(Color_Red, "PINE: Cannot listen for connections! Shutting down...");
|
||||
Deinitialize();
|
||||
return false;
|
||||
}
|
||||
|
||||
// we save a handle of the main vm object
|
||||
m_vm = vm;
|
||||
// we allocate once buffers to not have to do mallocs for each IPC
|
||||
// request, as malloc is expansive when we optimize for µs.
|
||||
m_ret_buffer.resize(MAX_IPC_RETURN_SIZE);
|
||||
m_ipc_buffer.resize(MAX_IPC_SIZE);
|
||||
|
||||
// we start the thread
|
||||
Start();
|
||||
m_thread = std::thread(&PINEServer::MainLoop, this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
char* PINEServer::MakeOkIPC(char* ret_buffer, uint32_t size = 5)
|
||||
std::vector<u8>& PINEServer::MakeOkIPC(std::vector<u8>& ret_buffer, uint32_t size = 5)
|
||||
{
|
||||
ToArray<uint32_t>(ret_buffer, size, 0);
|
||||
ToResultVector<uint32_t>(ret_buffer, size, 0);
|
||||
ret_buffer[4] = IPC_OK;
|
||||
return ret_buffer;
|
||||
}
|
||||
|
||||
char* PINEServer::MakeFailIPC(char* ret_buffer, uint32_t size = 5)
|
||||
std::vector<u8>& PINEServer::MakeFailIPC(std::vector<u8>& ret_buffer, uint32_t size = 5)
|
||||
{
|
||||
ToArray<uint32_t>(ret_buffer, size, 0);
|
||||
ToResultVector<uint32_t>(ret_buffer, size, 0);
|
||||
ret_buffer[4] = IPC_FAIL;
|
||||
return ret_buffer;
|
||||
}
|
||||
|
@ -170,30 +188,24 @@ int PINEServer::StartSocket()
|
|||
return 0;
|
||||
}
|
||||
|
||||
void PINEServer::ExecuteTaskInThread()
|
||||
void PINEServer::MainLoop()
|
||||
{
|
||||
m_end = false;
|
||||
|
||||
// we allocate once buffers to not have to do mallocs for each IPC
|
||||
// request, as malloc is expansive when we optimize for µs.
|
||||
m_ret_buffer = new char[MAX_IPC_RETURN_SIZE];
|
||||
m_ipc_buffer = new char[MAX_IPC_SIZE];
|
||||
|
||||
if (StartSocket() < 0)
|
||||
return;
|
||||
|
||||
while (true)
|
||||
while (!m_end.load(std::memory_order_acquire))
|
||||
{
|
||||
// either int or ssize_t depending on the platform, so we have to
|
||||
// use a bunch of auto
|
||||
auto receive_length = 0;
|
||||
auto end_length = 4;
|
||||
const gsl::span<u8> ipc_buffer_span = gsl::make_span(m_ipc_buffer);
|
||||
|
||||
// while we haven't received the entire packet, maybe due to
|
||||
// socket datagram splittage, we continue to read
|
||||
while (receive_length < end_length)
|
||||
{
|
||||
auto tmp_length = read_portable(m_msgsock, &m_ipc_buffer[receive_length], MAX_IPC_SIZE - receive_length);
|
||||
const auto tmp_length = read_portable(m_msgsock, &ipc_buffer_span[receive_length], MAX_IPC_SIZE - receive_length);
|
||||
|
||||
// we recreate the socket if an error happens
|
||||
if (tmp_length <= 0)
|
||||
|
@ -209,7 +221,7 @@ void PINEServer::ExecuteTaskInThread()
|
|||
// if we got at least the final size then update
|
||||
if (end_length == 4 && receive_length >= 4)
|
||||
{
|
||||
end_length = FromArray<u32>(m_ipc_buffer, 0);
|
||||
end_length = FromSpan<u32>(ipc_buffer_span, 0);
|
||||
// we'd like to avoid a client trying to do OOB
|
||||
if (end_length > MAX_IPC_SIZE || end_length < 4)
|
||||
{
|
||||
|
@ -227,10 +239,10 @@ void PINEServer::ExecuteTaskInThread()
|
|||
// disconnects
|
||||
if (receive_length != 0)
|
||||
{
|
||||
res = ParseCommand(&m_ipc_buffer[4], m_ret_buffer, (u32)end_length - 4);
|
||||
res = ParseCommand(ipc_buffer_span.subspan(4), m_ret_buffer, (u32)end_length - 4);
|
||||
|
||||
// if we cannot send back our answer restart the socket
|
||||
if (write_portable(m_msgsock, res.buffer, res.size) < 0)
|
||||
if (write_portable(m_msgsock, res.buffer.data(), res.size) < 0)
|
||||
{
|
||||
if (StartSocket() < 0)
|
||||
return;
|
||||
|
@ -240,9 +252,10 @@ void PINEServer::ExecuteTaskInThread()
|
|||
return;
|
||||
}
|
||||
|
||||
PINEServer::~PINEServer()
|
||||
void PINEServer::Deinitialize()
|
||||
{
|
||||
m_end = true;
|
||||
m_end.store(true, std::memory_order_release);
|
||||
|
||||
#ifdef _WIN32
|
||||
WSACleanup();
|
||||
#else
|
||||
|
@ -250,17 +263,14 @@ PINEServer::~PINEServer()
|
|||
#endif
|
||||
close_portable(m_sock);
|
||||
close_portable(m_msgsock);
|
||||
delete[] m_ret_buffer;
|
||||
delete[] m_ipc_buffer;
|
||||
// destroy the thread
|
||||
try
|
||||
|
||||
if (m_thread.joinable())
|
||||
{
|
||||
pxThread::Cancel();
|
||||
m_thread.join();
|
||||
}
|
||||
DESTRUCTOR_CATCHALL
|
||||
}
|
||||
|
||||
PINEServer::IPCBuffer PINEServer::ParseCommand(char* buf, char* ret_buffer, u32 buf_size)
|
||||
PINEServer::IPCBuffer PINEServer::ParseCommand(gsl::span<u8> buf, std::vector<u8>& ret_buffer, u32 buf_size)
|
||||
{
|
||||
u32 ret_cnt = 5;
|
||||
u32 buf_cnt = 0;
|
||||
|
@ -285,211 +295,197 @@ PINEServer::IPCBuffer PINEServer::ParseCommand(char* buf, char* ret_buffer, u32
|
|||
{
|
||||
case MsgRead8:
|
||||
{
|
||||
if (!m_vm->HasActiveMachine())
|
||||
if (!VMManager::HasValidVM())
|
||||
goto error;
|
||||
if (!SafetyChecks(buf_cnt, 4, ret_cnt, 1, buf_size))
|
||||
goto error;
|
||||
const u32 a = FromArray<u32>(&buf[buf_cnt], 0);
|
||||
const u32 a = FromSpan<u32>(buf, buf_cnt);
|
||||
const u8 res = memRead8(a);
|
||||
ToArray(ret_buffer, res, ret_cnt);
|
||||
ToResultVector(ret_buffer, res, ret_cnt);
|
||||
ret_cnt += 1;
|
||||
buf_cnt += 4;
|
||||
break;
|
||||
}
|
||||
case MsgRead16:
|
||||
{
|
||||
if (!m_vm->HasActiveMachine())
|
||||
if (!VMManager::HasValidVM())
|
||||
goto error;
|
||||
if (!SafetyChecks(buf_cnt, 4, ret_cnt, 2, buf_size))
|
||||
goto error;
|
||||
const u32 a = FromArray<u32>(&buf[buf_cnt], 0);
|
||||
const u32 a = FromSpan<u32>(buf, buf_cnt);
|
||||
const u16 res = memRead16(a);
|
||||
ToArray(ret_buffer, res, ret_cnt);
|
||||
ToResultVector(ret_buffer, res, ret_cnt);
|
||||
ret_cnt += 2;
|
||||
buf_cnt += 4;
|
||||
break;
|
||||
}
|
||||
case MsgRead32:
|
||||
{
|
||||
if (!m_vm->HasActiveMachine())
|
||||
if (!VMManager::HasValidVM())
|
||||
goto error;
|
||||
if (!SafetyChecks(buf_cnt, 4, ret_cnt, 4, buf_size))
|
||||
goto error;
|
||||
const u32 a = FromArray<u32>(&buf[buf_cnt], 0);
|
||||
const u32 a = FromSpan<u32>(buf, buf_cnt);
|
||||
const u32 res = memRead32(a);
|
||||
ToArray(ret_buffer, res, ret_cnt);
|
||||
ToResultVector(ret_buffer, res, ret_cnt);
|
||||
ret_cnt += 4;
|
||||
buf_cnt += 4;
|
||||
break;
|
||||
}
|
||||
case MsgRead64:
|
||||
{
|
||||
if (!m_vm->HasActiveMachine())
|
||||
if (!VMManager::HasValidVM())
|
||||
goto error;
|
||||
if (!SafetyChecks(buf_cnt, 4, ret_cnt, 8, buf_size))
|
||||
goto error;
|
||||
const u32 a = FromArray<u32>(&buf[buf_cnt], 0);
|
||||
const u32 a = FromSpan<u32>(buf, buf_cnt);
|
||||
const u64 res = memRead64(a);
|
||||
ToArray(ret_buffer, res, ret_cnt);
|
||||
ToResultVector(ret_buffer, res, ret_cnt);
|
||||
ret_cnt += 8;
|
||||
buf_cnt += 4;
|
||||
break;
|
||||
}
|
||||
case MsgWrite8:
|
||||
{
|
||||
if (!m_vm->HasActiveMachine())
|
||||
if (!VMManager::HasValidVM())
|
||||
goto error;
|
||||
if (!SafetyChecks(buf_cnt, 1 + 4, ret_cnt, 0, buf_size))
|
||||
goto error;
|
||||
const u32 a = FromArray<u32>(&buf[buf_cnt], 0);
|
||||
memWrite8(a, FromArray<u8>(&buf[buf_cnt], 4));
|
||||
const u32 a = FromSpan<u32>(buf, buf_cnt);
|
||||
memWrite8(a, FromSpan<u8>(buf, buf_cnt + 4));
|
||||
buf_cnt += 5;
|
||||
break;
|
||||
}
|
||||
case MsgWrite16:
|
||||
{
|
||||
if (!m_vm->HasActiveMachine())
|
||||
if (!VMManager::HasValidVM())
|
||||
goto error;
|
||||
if (!SafetyChecks(buf_cnt, 2 + 4, ret_cnt, 0, buf_size))
|
||||
goto error;
|
||||
const u32 a = FromArray<u32>(&buf[buf_cnt], 0);
|
||||
memWrite16(a, FromArray<u16>(&buf[buf_cnt], 4));
|
||||
const u32 a = FromSpan<u32>(buf, buf_cnt);
|
||||
memWrite16(a, FromSpan<u16>(buf, buf_cnt + 4));
|
||||
buf_cnt += 6;
|
||||
break;
|
||||
}
|
||||
case MsgWrite32:
|
||||
{
|
||||
if (!m_vm->HasActiveMachine())
|
||||
if (!VMManager::HasValidVM())
|
||||
goto error;
|
||||
if (!SafetyChecks(buf_cnt, 4 + 4, ret_cnt, 0, buf_size))
|
||||
goto error;
|
||||
const u32 a = FromArray<u32>(&buf[buf_cnt], 0);
|
||||
memWrite32(a, FromArray<u32>(&buf[buf_cnt], 4));
|
||||
const u32 a = FromSpan<u32>(buf, buf_cnt);
|
||||
memWrite32(a, FromSpan<u32>(buf, buf_cnt + 4));
|
||||
buf_cnt += 8;
|
||||
break;
|
||||
}
|
||||
case MsgWrite64:
|
||||
{
|
||||
if (!m_vm->HasActiveMachine())
|
||||
if (!VMManager::HasValidVM())
|
||||
goto error;
|
||||
if (!SafetyChecks(buf_cnt, 8 + 4, ret_cnt, 0, buf_size))
|
||||
goto error;
|
||||
const u32 a = FromArray<u32>(&buf[buf_cnt], 0);
|
||||
memWrite64(a, FromArray<u64>(&buf[buf_cnt], 4));
|
||||
const u32 a = FromSpan<u32>(buf, buf_cnt);
|
||||
memWrite64(a, FromSpan<u64>(buf, buf_cnt + 4));
|
||||
buf_cnt += 12;
|
||||
break;
|
||||
}
|
||||
case MsgVersion:
|
||||
{
|
||||
if (!m_vm->HasActiveMachine())
|
||||
if (!VMManager::HasValidVM())
|
||||
goto error;
|
||||
char version[256] = {};
|
||||
std::string version;
|
||||
if (GIT_TAGGED_COMMIT) // Nightly builds
|
||||
{
|
||||
// tagged commit - more modern implementation of dev build versioning
|
||||
// - there is no need to include the commit - that is associated with the tag, git is implied
|
||||
sprintf(version, "PCSX2 Nightly - %s", GIT_TAG);
|
||||
version = fmt::format("PCSX2 Nightly - {}", GIT_TAG);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(version, "PCSX2 %u.%u.%u-%lld", PCSX2_VersionHi, PCSX2_VersionMid, PCSX2_VersionLo, SVN_REV);
|
||||
version = fmt::format("PCSX2 {}.{}.{}-{}", PCSX2_VersionHi, PCSX2_VersionMid, PCSX2_VersionLo, SVN_REV);
|
||||
}
|
||||
const u32 size = strlen(version) + 1;
|
||||
version[size] = 0x00;
|
||||
const u32 size = version.size() + 1;
|
||||
if (!SafetyChecks(buf_cnt, 0, ret_cnt, size + 4, buf_size))
|
||||
goto error;
|
||||
ToArray(ret_buffer, size, ret_cnt);
|
||||
ToResultVector(ret_buffer, size, ret_cnt);
|
||||
ret_cnt += 4;
|
||||
memcpy(&ret_buffer[ret_cnt], version, size);
|
||||
memcpy(&ret_buffer[ret_cnt], version.c_str(), size);
|
||||
ret_cnt += size;
|
||||
break;
|
||||
}
|
||||
case MsgSaveState:
|
||||
{
|
||||
if (!m_vm->HasActiveMachine())
|
||||
if (!VMManager::HasValidVM())
|
||||
goto error;
|
||||
if (!SafetyChecks(buf_cnt, 1, ret_cnt, 0, buf_size))
|
||||
goto error;
|
||||
StateCopy_SaveToSlot(FromArray<u8>(&buf[buf_cnt], 0));
|
||||
VMManager::SaveStateToSlot(FromSpan<u8>(buf, buf_cnt));
|
||||
buf_cnt += 1;
|
||||
break;
|
||||
}
|
||||
case MsgLoadState:
|
||||
{
|
||||
if (!m_vm->HasActiveMachine())
|
||||
if (!VMManager::HasValidVM())
|
||||
goto error;
|
||||
if (!SafetyChecks(buf_cnt, 1, ret_cnt, 0, buf_size))
|
||||
goto error;
|
||||
StateCopy_LoadFromSlot(FromArray<u8>(&buf[buf_cnt], 0), false);
|
||||
VMManager::LoadStateFromSlot(FromSpan<u8>(buf, buf_cnt));
|
||||
buf_cnt += 1;
|
||||
break;
|
||||
}
|
||||
case MsgTitle:
|
||||
{
|
||||
if (!m_vm->HasActiveMachine())
|
||||
if (!VMManager::HasValidVM())
|
||||
goto error;
|
||||
char* title = new char[GameInfo::gameName.size() + 1];
|
||||
sprintf(title, "%s", GameInfo::gameName.ToUTF8().data());
|
||||
const u32 size = strlen(title) + 1;
|
||||
title[size] = 0x00;
|
||||
const std::string gameName = VMManager::GetGameName();
|
||||
const u32 size = gameName.size() + 1;
|
||||
if (!SafetyChecks(buf_cnt, 0, ret_cnt, size + 4, buf_size))
|
||||
goto error;
|
||||
ToArray(ret_buffer, size, ret_cnt);
|
||||
ToResultVector(ret_buffer, size, ret_cnt);
|
||||
ret_cnt += 4;
|
||||
memcpy(&ret_buffer[ret_cnt], title, size);
|
||||
memcpy(&ret_buffer[ret_cnt], gameName.c_str(), size);
|
||||
ret_cnt += size;
|
||||
delete[] title;
|
||||
break;
|
||||
}
|
||||
case MsgID:
|
||||
{
|
||||
if (!m_vm->HasActiveMachine())
|
||||
if (!VMManager::HasValidVM())
|
||||
goto error;
|
||||
char* title = new char[GameInfo::gameSerial.size() + 1];
|
||||
sprintf(title, "%s", GameInfo::gameSerial.ToUTF8().data());
|
||||
const u32 size = strlen(title) + 1;
|
||||
title[size] = 0x00;
|
||||
const std::string gameSerial = VMManager::GetGameSerial();
|
||||
const u32 size = gameSerial.size() + 1;
|
||||
if (!SafetyChecks(buf_cnt, 0, ret_cnt, size + 4, buf_size))
|
||||
goto error;
|
||||
ToArray(ret_buffer, size, ret_cnt);
|
||||
ToResultVector(ret_buffer, size, ret_cnt);
|
||||
ret_cnt += 4;
|
||||
memcpy(&ret_buffer[ret_cnt], title, size);
|
||||
memcpy(&ret_buffer[ret_cnt], gameSerial.c_str(), size);
|
||||
ret_cnt += size;
|
||||
delete[] title;
|
||||
break;
|
||||
}
|
||||
case MsgUUID:
|
||||
{
|
||||
if (!m_vm->HasActiveMachine())
|
||||
if (!VMManager::HasValidVM())
|
||||
goto error;
|
||||
char* title = new char[GameInfo::gameCRC.size() + 1];
|
||||
sprintf(title, "%s", GameInfo::gameCRC.ToUTF8().data());
|
||||
const u32 size = strlen(title) + 1;
|
||||
title[size] = 0x00;
|
||||
const std::string crc(fmt::format("{:08x}", VMManager::GetGameCRC()));
|
||||
const u32 size = crc.size() + 1;
|
||||
if (!SafetyChecks(buf_cnt, 0, ret_cnt, size + 4, buf_size))
|
||||
goto error;
|
||||
ToArray(ret_buffer, size, ret_cnt);
|
||||
ToResultVector(ret_buffer, size, ret_cnt);
|
||||
ret_cnt += 4;
|
||||
memcpy(&ret_buffer[ret_cnt], title, size);
|
||||
memcpy(&ret_buffer[ret_cnt], crc.c_str(), size);
|
||||
ret_cnt += size;
|
||||
delete[] title;
|
||||
break;
|
||||
}
|
||||
case MsgGameVersion:
|
||||
{
|
||||
if (!m_vm->HasActiveMachine())
|
||||
if (!VMManager::HasValidVM())
|
||||
goto error;
|
||||
char* title = new char[GameInfo::gameVersion.size() + 1];
|
||||
sprintf(title, "%s", GameInfo::gameVersion.ToUTF8().data());
|
||||
const u32 size = strlen(title) + 1;
|
||||
title[size] = 0x00;
|
||||
const u32 size = ElfVersion.size() + 1;
|
||||
if (!SafetyChecks(buf_cnt, 0, ret_cnt, size + 4, buf_size))
|
||||
goto error;
|
||||
ToArray(ret_buffer, size, ret_cnt);
|
||||
ToResultVector(ret_buffer, size, ret_cnt);
|
||||
ret_cnt += 4;
|
||||
memcpy(&ret_buffer[ret_cnt], title, size);
|
||||
memcpy(&ret_buffer[ret_cnt], ElfVersion.c_str(), size);
|
||||
ret_cnt += size;
|
||||
delete[] title;
|
||||
break;
|
||||
}
|
||||
case MsgStatus:
|
||||
|
@ -497,18 +493,20 @@ PINEServer::IPCBuffer PINEServer::ParseCommand(char* buf, char* ret_buffer, u32
|
|||
if (!SafetyChecks(buf_cnt, 0, ret_cnt, 4, buf_size))
|
||||
goto error;
|
||||
EmuStatus status;
|
||||
if (m_vm->HasActiveMachine())
|
||||
{
|
||||
if (GetCoreThread().IsClosing())
|
||||
status = Paused;
|
||||
else
|
||||
status = Running;
|
||||
|
||||
switch (VMManager::GetState()) {
|
||||
case VMState::Running:
|
||||
status = EmuStatus::Running;
|
||||
break;
|
||||
case VMState::Paused:
|
||||
status = EmuStatus::Paused;
|
||||
break;
|
||||
default:
|
||||
status = EmuStatus::Shutdown;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = Shutdown;
|
||||
}
|
||||
ToArray(ret_buffer, status, ret_cnt);
|
||||
|
||||
ToResultVector(ret_buffer, status, ret_cnt);
|
||||
ret_cnt += 4;
|
||||
break;
|
||||
}
|
||||
|
@ -521,5 +519,3 @@ PINEServer::IPCBuffer PINEServer::ParseCommand(char* buf, char* ret_buffer, u32
|
|||
}
|
||||
return IPCBuffer{(int)ret_cnt, MakeOkIPC(ret_buffer, ret_cnt)};
|
||||
}
|
||||
|
||||
#endif
|
66
pcsx2/PINE.h
66
pcsx2/PINE.h
|
@ -18,8 +18,6 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#ifdef PCSX2_LEFTOVER_FROM_WX
|
||||
|
||||
// PINE uses a concept of "slot" to be able to communicate with multiple
|
||||
// emulators at the same time, each slot should be unique to each emulator to
|
||||
// allow PnP and configurable by the end user so that several runs don't
|
||||
|
@ -27,22 +25,20 @@
|
|||
#define PINE_DEFAULT_SLOT 28011
|
||||
#define PINE_EMULATOR_NAME "pcsx2"
|
||||
|
||||
#include "gui/PersistentThread.h"
|
||||
#include "gui/SysThreads.h"
|
||||
#include <thread>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <atomic>
|
||||
#include <gsl/span>
|
||||
#ifdef _WIN32
|
||||
#include <WinSock2.h>
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
using namespace Threading;
|
||||
|
||||
class SysCoreThread;
|
||||
|
||||
class PINEServer : public pxThread
|
||||
class PINEServer
|
||||
{
|
||||
// parent thread
|
||||
typedef pxThread _parent;
|
||||
std::thread m_thread;
|
||||
|
||||
protected:
|
||||
#ifdef _WIN32
|
||||
|
@ -77,13 +73,13 @@ protected:
|
|||
* A preallocated buffer used to store all IPC replies.
|
||||
* to the size of 50.000 MsgWrite64 IPC calls.
|
||||
*/
|
||||
char* m_ret_buffer;
|
||||
std::vector<u8> m_ret_buffer{};
|
||||
|
||||
/**
|
||||
* IPC messages buffer.
|
||||
* A preallocated buffer used to store all IPC messages.
|
||||
*/
|
||||
char* m_ipc_buffer;
|
||||
std::vector<u8> m_ipc_buffer{};
|
||||
|
||||
/**
|
||||
* IPC Command messages opcodes.
|
||||
|
@ -130,7 +126,7 @@ protected:
|
|||
struct IPCBuffer
|
||||
{
|
||||
int size; /**< Size of the buffer. */
|
||||
char* buffer; /**< Buffer. */
|
||||
std::vector<u8> buffer; /**< Buffer. */
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -145,11 +141,8 @@ protected:
|
|||
IPC_FAIL = 0xFF /**< IPC command failed to complete. */
|
||||
};
|
||||
|
||||
// handle to the main vm thread
|
||||
SysCoreThread* m_vm;
|
||||
|
||||
// Thread used to relay IPC commands.
|
||||
void ExecuteTaskInThread();
|
||||
void MainLoop();
|
||||
|
||||
/**
|
||||
* Internal function, Parses an IPC command.
|
||||
|
@ -159,7 +152,7 @@ protected:
|
|||
* return value: IPCBuffer containing a buffer with the result
|
||||
* of the command and its size.
|
||||
*/
|
||||
IPCBuffer ParseCommand(char* buf, char* ret_buffer, u32 buf_size);
|
||||
IPCBuffer ParseCommand(gsl::span<u8> buf, std::vector<u8>& ret_buffer, u32 buf_size);
|
||||
|
||||
/**
|
||||
* Formats an IPC buffer
|
||||
|
@ -167,8 +160,8 @@ protected:
|
|||
* size: size of the IPC buffer.
|
||||
* return value: buffer containing the status code allocated of size
|
||||
*/
|
||||
static inline char* MakeOkIPC(char* ret_buffer, uint32_t size);
|
||||
static inline char* MakeFailIPC(char* ret_buffer, uint32_t size);
|
||||
static inline std::vector<u8>& MakeOkIPC(std::vector<u8>& ret_buffer, uint32_t size);
|
||||
static inline std::vector<u8>& MakeFailIPC(std::vector<u8>& ret_buffer, uint32_t size);
|
||||
|
||||
/**
|
||||
* Initializes an open socket for IPC communication.
|
||||
|
@ -177,31 +170,29 @@ protected:
|
|||
int StartSocket();
|
||||
|
||||
/**
|
||||
* Converts an uint to an char* in little endian
|
||||
* res_array: the array to modify
|
||||
* Converts a primitive value to bytes in little endian
|
||||
* res_vector: the vector to modify
|
||||
* res: the value to convert
|
||||
* i: when to insert it into the array
|
||||
* return value: res_array
|
||||
* i: where to insert it into the vector
|
||||
* NB: implicitely inlined
|
||||
*/
|
||||
template <typename T>
|
||||
static char* ToArray(char* res_array, T res, int i)
|
||||
static void ToResultVector(std::vector<u8>& res_vector, T res, int i)
|
||||
{
|
||||
memcpy((res_array + i), (char*)&res, sizeof(T));
|
||||
return res_array;
|
||||
memcpy(&res_vector[i], (char*)&res, sizeof(T));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a char* to an uint in little endian
|
||||
* arr: the array to convert
|
||||
* i: when to load it from the array
|
||||
* Converts bytes in little endian to a primitive value
|
||||
* span: the span to convert
|
||||
* i: where to load it from the span
|
||||
* return value: the converted value
|
||||
* NB: implicitely inlined
|
||||
*/
|
||||
template <typename T>
|
||||
static T FromArray(char* arr, int i)
|
||||
static T FromSpan(gsl::span<u8> span, int i)
|
||||
{
|
||||
return *(T*)(arr + i);
|
||||
return *(T*)(&span[i]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -210,7 +201,7 @@ protected:
|
|||
*/
|
||||
static inline bool SafetyChecks(u32 command_len, int command_size, u32 reply_len, int reply_size = 0, u32 buf_size = MAX_IPC_SIZE - 1)
|
||||
{
|
||||
bool res = ((command_len + command_size) > buf_size ||
|
||||
const bool res = ((command_len + command_size) > buf_size ||
|
||||
(reply_len + reply_size) >= MAX_IPC_RETURN_SIZE);
|
||||
if (unlikely(res))
|
||||
return false;
|
||||
|
@ -219,12 +210,13 @@ protected:
|
|||
|
||||
public:
|
||||
// Whether the socket processing thread should stop executing/is stopped.
|
||||
bool m_end = true;
|
||||
std::atomic_bool m_end{ false };
|
||||
int m_slot;
|
||||
|
||||
/* Initializers */
|
||||
PINEServer(SysCoreThread* vm, unsigned int slot = PINE_DEFAULT_SLOT);
|
||||
PINEServer();
|
||||
virtual ~PINEServer();
|
||||
bool Initialize(int slot = PINE_DEFAULT_SLOT);
|
||||
void Deinitialize();
|
||||
|
||||
}; // class SocketIPC
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1318,6 +1318,7 @@ Pcsx2Config::Pcsx2Config()
|
|||
}
|
||||
|
||||
GzipIsoIndexTemplate = "$(f).pindex.tmp";
|
||||
PINESlot = 28011;
|
||||
}
|
||||
|
||||
void Pcsx2Config::LoadSave(SettingsWrapper& wrap)
|
||||
|
@ -1371,6 +1372,7 @@ void Pcsx2Config::LoadSave(SettingsWrapper& wrap)
|
|||
#endif
|
||||
|
||||
SettingsWrapEntry(GzipIsoIndexTemplate);
|
||||
SettingsWrapEntry(PINESlot);
|
||||
|
||||
// For now, this in the derived config for backwards ini compatibility.
|
||||
SettingsWrapEntryEx(CurrentBlockdump, "BlockDumpSaveDirectory");
|
||||
|
@ -1446,7 +1448,8 @@ bool Pcsx2Config::operator==(const Pcsx2Config& right) const
|
|||
OpEqu(Framerate) &&
|
||||
OpEqu(Trace) &&
|
||||
OpEqu(BaseFilenames) &&
|
||||
OpEqu(GzipIsoIndexTemplate);
|
||||
OpEqu(GzipIsoIndexTemplate) &&
|
||||
OpEqu(PINESlot);
|
||||
for (u32 i = 0; i < sizeof(Mcd) / sizeof(Mcd[0]); i++)
|
||||
{
|
||||
equal &= OpEqu(Mcd[i].Enabled);
|
||||
|
|
Loading…
Reference in New Issue