From a89840f309229da7a1860d3941984e1faa3bca58 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 17 Aug 2020 23:08:35 -0700 Subject: [PATCH 1/6] Net: Cut down on local IP aliasing. --- Core/HLE/proAdhoc.cpp | 22 +++++++++++----------- Core/HLE/proAdhoc.h | 7 ++++++- Core/HLE/proAdhocServer.cpp | 2 +- Core/HLE/sceNet.cpp | 12 ++++++------ 4 files changed, 24 insertions(+), 19 deletions(-) diff --git a/Core/HLE/proAdhoc.cpp b/Core/HLE/proAdhoc.cpp index 681e11e493..6b9621c72a 100644 --- a/Core/HLE/proAdhoc.cpp +++ b/Core/HLE/proAdhoc.cpp @@ -76,7 +76,7 @@ bool updateChatScreen = false; int newChat = 0; bool isOriPort = false; bool isLocalServer = false; -sockaddr LocalhostIP; +SockAddrIN4 g_localhostIP; sockaddr LocalIP; int defaultWlanChannel = PSP_SYSTEMPARAM_ADHOC_CHANNEL_1; // Don't put 0(Auto) here, it needed to be a valid/actual channel number @@ -1535,7 +1535,7 @@ int getLocalIp(sockaddr_in* SocketAddress) { socklen_t addrLen = sizeof(localAddr); if (SOCKET_ERROR != getsockname(metasocket, (struct sockaddr*) & localAddr, &addrLen)) { if (isLocalServer) { - localAddr.sin_addr = ((sockaddr_in*)&LocalhostIP)->sin_addr; + localAddr.sin_addr = g_localhostIP.in.sin_addr; } SocketAddress->sin_addr = localAddr.sin_addr; return 0; @@ -1556,7 +1556,7 @@ int getLocalIp(sockaddr_in* SocketAddress) { if (pHost) { memcpy(&SocketAddress->sin_addr, pHost->h_addr_list[0], pHost->h_length); if (isLocalServer) { - SocketAddress->sin_addr = ((sockaddr_in*)&LocalhostIP)->sin_addr; + SocketAddress->sin_addr = g_localhostIP.in.sin_addr; } return 0; } @@ -1580,7 +1580,7 @@ int getLocalIp(sockaddr_in* SocketAddress) { } freeifaddrs(ifAddrStruct); if (isLocalServer) { - SocketAddress->sin_addr = ((sockaddr_in*)&LocalhostIP)->sin_addr; + SocketAddress->sin_addr = g_localhostIP.in.sin_addr; } return 0; } @@ -1606,7 +1606,7 @@ int getLocalIp(sockaddr_in* SocketAddress) { SocketAddress->sin_addr = name.sin_addr; // May be we should cache this so it doesn't need to use connect all the time, or even better cache it when connecting to adhoc server to get an accurate IP closesocket(sock); if (isLocalServer) { - SocketAddress->sin_addr = ((sockaddr_in*)&LocalhostIP)->sin_addr; + SocketAddress->sin_addr = g_localhostIP.in.sin_addr; } return 0; } @@ -1623,7 +1623,7 @@ uint32_t getLocalIp(int sock) { socklen_t addrLen = sizeof(localAddr); getsockname(sock, (struct sockaddr*)&localAddr, &addrLen); if (isLocalServer) { - localAddr.sin_addr = ((sockaddr_in*)&LocalhostIP)->sin_addr; + localAddr.sin_addr = g_localhostIP.in.sin_addr; } return localAddr.sin_addr.s_addr; } @@ -1843,12 +1843,12 @@ int initNetwork(SceNetAdhocctlAdhocId *adhoc_id){ setsockopt(metasocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on)); setsockopt(metasocket, SOL_SOCKET, SO_DONTROUTE, (const char*)&on, sizeof(on)); - ((struct sockaddr_in*) & LocalhostIP)->sin_port = 0; + g_localhostIP.in.sin_port = 0; // Bind Local Address to Socket - iResult = bind(metasocket, (struct sockaddr*) & LocalhostIP, sizeof(sockaddr)); + iResult = bind(metasocket, &g_localhostIP.addr, sizeof(sockaddr)); if (iResult == SOCKET_ERROR) { - ERROR_LOG(SCENET, "Bind to alternate localhost[%s] failed(%i).", inet_ntoa(((struct sockaddr_in*) & LocalhostIP)->sin_addr), iResult); - host->NotifyUserMessage(std::string(n->T("Failed to Bind Localhost IP")) + " " + inet_ntoa(((struct sockaddr_in*) & LocalhostIP)->sin_addr), 2.0, 0x0000ff); + ERROR_LOG(SCENET, "Bind to alternate localhost[%s] failed(%i).", inet_ntoa(g_localhostIP.in.sin_addr), iResult); + host->NotifyUserMessage(std::string(n->T("Failed to Bind Localhost IP")) + " " + inet_ntoa(g_localhostIP.in.sin_addr), 2.0, 0x0000ff); } } @@ -1917,7 +1917,7 @@ bool resolveIP(uint32_t ip, SceNetEtherAddr * mac) { getLocalIp(&addr); uint32_t localIp = addr.sin_addr.s_addr; - if (ip == localIp || ip == ((sockaddr_in*)&LocalhostIP)->sin_addr.s_addr){ + if (ip == localIp || ip == g_localhostIP.in.sin_addr.s_addr) { getLocalMac(mac); return true; } diff --git a/Core/HLE/proAdhoc.h b/Core/HLE/proAdhoc.h index e5d39745ee..4657700fbe 100644 --- a/Core/HLE/proAdhoc.h +++ b/Core/HLE/proAdhoc.h @@ -829,11 +829,16 @@ extern std::recursive_mutex peerlock; extern SceNetAdhocPdpStat * pdp[255]; extern SceNetAdhocPtpStat * ptp[255]; +union SockAddrIN4 { + sockaddr addr; + sockaddr_in in; +}; + extern uint16_t portOffset; extern uint32_t minSocketTimeoutUS; extern bool isOriPort; extern bool isLocalServer; -extern sockaddr LocalhostIP; // Used to differentiate localhost IP on multiple-instance +extern SockAddrIN4 g_localhostIP; // Used to differentiate localhost IP on multiple-instance extern sockaddr LocalIP; // IP of Network Adapter used to connect to Adhoc Server (LAN/WAN) extern int defaultWlanChannel; // Default WLAN Channel for Auto, JPCSP uses 11 diff --git a/Core/HLE/proAdhocServer.cpp b/Core/HLE/proAdhocServer.cpp index 85d4f2d56a..07ddaf29eb 100644 --- a/Core/HLE/proAdhocServer.cpp +++ b/Core/HLE/proAdhocServer.cpp @@ -1826,7 +1826,7 @@ int create_listen_socket(uint16_t port) //Should only bind to specific IP for the 2nd or more instance of PPSSPP to prevent communication interference issue when sharing the same port. Doesn't work well when PPSSPP_ID reseted everytime emulation restarted. /* if (PPSSPP_ID > 1) { - local.sin_addr = ((sockaddr_in *)&LocalhostIP)->sin_addr; + local.sin_addr = g_localhostIP.in.sin_addr; } */ diff --git a/Core/HLE/sceNet.cpp b/Core/HLE/sceNet.cpp index 1b3f900aeb..1b848df461 100644 --- a/Core/HLE/sceNet.cpp +++ b/Core/HLE/sceNet.cpp @@ -123,19 +123,19 @@ static int InitLocalhostIP() { if (iResult != 0) { ERROR_LOG(SCENET, "DNS Error (%s) result: %d\n", ipstr, iResult); //osm.Show("DNS Error, can't resolve client bind " + ipstr, 8.0f); - ((sockaddr_in*)&LocalhostIP)->sin_family = AF_INET; - ((sockaddr_in*)&LocalhostIP)->sin_addr.s_addr = inet_addr(ipstr); //"127.0.0.1" - ((sockaddr_in*)&LocalhostIP)->sin_port = 0; + g_localhostIP.in.sin_family = AF_INET; + g_localhostIP.in.sin_addr.s_addr = inet_addr(ipstr); //"127.0.0.1" + g_localhostIP.in.sin_port = 0; return iResult; } for (ptr = localAddr; ptr != NULL; ptr = ptr->ai_next) { switch (ptr->ai_family) { case AF_INET: - memcpy(&LocalhostIP, ptr->ai_addr, sizeof(sockaddr)); + memcpy(&g_localhostIP.addr, ptr->ai_addr, sizeof(sockaddr)); break; } } - ((sockaddr_in*)&LocalhostIP)->sin_port = 0; + g_localhostIP.in.sin_port = 0; freeaddrinfo(localAddr); // Resolve server dns @@ -198,7 +198,7 @@ void __NetInit() { SceNetEtherAddr mac; getLocalMac(&mac); - INFO_LOG(SCENET, "LocalHost IP will be %s [%s]", inet_ntoa(((sockaddr_in*)&LocalhostIP)->sin_addr), mac2str(&mac).c_str()); + INFO_LOG(SCENET, "LocalHost IP will be %s [%s]", inet_ntoa(g_localhostIP.in.sin_addr), mac2str(&mac).c_str()); // TODO: May be we should initialize & cleanup somewhere else than here for PortManager to be used as general purpose for whatever port forwarding PPSSPP needed __UPnPInit(); From 4d307be2b2cfe31f14f080f9c25c0b070b659b20 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 17 Aug 2020 23:33:27 -0700 Subject: [PATCH 2/6] Net: Simplify local IP lookup. --- Core/HLE/sceNet.cpp | 54 ++++++++++++++------------------------------- 1 file changed, 16 insertions(+), 38 deletions(-) diff --git a/Core/HLE/sceNet.cpp b/Core/HLE/sceNet.cpp index 1b848df461..63bd62c093 100644 --- a/Core/HLE/sceNet.cpp +++ b/Core/HLE/sceNet.cpp @@ -114,49 +114,27 @@ void AfterApctlMipsCall::SetData(int HandlerID, int OldState, int NewState, int } static int InitLocalhostIP() { - // find local IP - addrinfo* localAddr; - addrinfo* ptr; - char ipstr[256]; - sprintf(ipstr, "127.0.0.%u", PPSSPP_ID); - int iResult = getaddrinfo(ipstr, 0, NULL, &localAddr); - if (iResult != 0) { - ERROR_LOG(SCENET, "DNS Error (%s) result: %d\n", ipstr, iResult); - //osm.Show("DNS Error, can't resolve client bind " + ipstr, 8.0f); - g_localhostIP.in.sin_family = AF_INET; - g_localhostIP.in.sin_addr.s_addr = inet_addr(ipstr); //"127.0.0.1" - g_localhostIP.in.sin_port = 0; - return iResult; - } - for (ptr = localAddr; ptr != NULL; ptr = ptr->ai_next) { - switch (ptr->ai_family) { - case AF_INET: - memcpy(&g_localhostIP.addr, ptr->ai_addr, sizeof(sockaddr)); - break; - } - } + // The entire 127.*.*.* is reserved for loopback. + uint32_t localIP = 0x7F000001 + PPSSPP_ID - 1; + + g_localhostIP.in.sin_family = AF_INET; + g_localhostIP.in.sin_addr.s_addr = htonl(localIP); g_localhostIP.in.sin_port = 0; - freeaddrinfo(localAddr); - // Resolve server dns - addrinfo* resultAddr; - in_addr serverIp; - serverIp.s_addr = INADDR_NONE; + // If lookup fails, we'll assume it's not local. + isLocalServer = false; - iResult = getaddrinfo(g_Config.proAdhocServer.c_str(), 0, NULL, &resultAddr); - if (iResult != 0) { - ERROR_LOG(SCENET, "DNS Error (%s)\n", g_Config.proAdhocServer.c_str()); - return iResult; - } - for (ptr = resultAddr; ptr != NULL; ptr = ptr->ai_next) { - switch (ptr->ai_family) { - case AF_INET: - serverIp = ((sockaddr_in*)ptr->ai_addr)->sin_addr; - break; + addrinfo *resultAddr = nullptr; + std::string error; + if (net::DNSResolve(g_Config.proAdhocServer, "", &resultAddr, error, net::DNSType::IPV4)) { + for (addrinfo *ptr = resultAddr; ptr != nullptr; ptr = ptr->ai_next) { + auto addr4 = ((sockaddr_in *)ptr->ai_addr)->sin_addr.s_addr; + isLocalServer = (ntohl(addr4) & 0x7F000000) == 0x7F000000; } + + net::DNSResolveFree(resultAddr); + resultAddr = nullptr; } - freeaddrinfo(resultAddr); - isLocalServer = (((uint8_t*)&serverIp.s_addr)[0] == 0x7f); return 0; } From 495996e58bcc65807bf1b34bfd6c7c737f6b014c Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 18 Aug 2020 00:47:22 -0700 Subject: [PATCH 3/6] Windows: Make the instance counter go by 1, 2, 3. --- Core/Config.cpp | 12 +++++++++--- Core/Config.h | 3 ++- Windows/main.cpp | 27 ++++++++++++++++----------- 3 files changed, 27 insertions(+), 15 deletions(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index f7fd8e9af9..0a2355e5fc 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -1117,12 +1117,13 @@ static void IterateSettings(IniFile &iniFile, std::function> GetLangValuesMapping() { @@ -1173,6 +1174,11 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) { const bool useIniFilename = iniFileName != nullptr && strlen(iniFileName) > 0; iniFilename_ = FindConfigFile(useIniFilename ? iniFileName : "ppsspp.ini"); + if (!bUpdatedInstanceCounter) { + InitInstanceCounter(); + bUpdatedInstanceCounter = true; + } + const bool useControllerIniFilename = controllerIniFilename != nullptr && strlen(controllerIniFilename) > 0; controllerIniFilename_ = FindConfigFile(useControllerIniFilename ? controllerIniFilename : "controls.ini"); diff --git a/Core/Config.h b/Core/Config.h index 71fa93e357..3072efdbc3 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -61,7 +61,8 @@ public: // Whether to save the config on close. bool bSaveSettings; bool bFirstRun; - bool bGameSpecific; + bool bGameSpecific = false; + bool bUpdatedInstanceCounter = false; int iRunCount; // To be used to for example check for updates every 10 runs and things like that. diff --git a/Windows/main.cpp b/Windows/main.cpp index 50cd28534b..7ee603d783 100644 --- a/Windows/main.cpp +++ b/Windows/main.cpp @@ -516,6 +516,22 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin g_Config.internalDataDirectory = W32Util::UserDocumentsPath(); InitSysDirectories(); + // Check for the Vulkan workaround before any serious init. + for (size_t i = 1; i < wideArgs.size(); ++i) { + if (wideArgs[i][0] == L'-') { + // This should only be called by DetectVulkanInExternalProcess(). + if (wideArgs[i] == L"--vulkan-available-check") { + // Just call it, this way it will crash here if it doesn't work. + // (this is an external process.) + bool result = VulkanMayBeAvailable(); + + LogManager::Shutdown(); + WinMainCleanup(); + return result ? EXIT_CODE_VULKAN_WORKS : EXIT_FAILURE; + } + } + } + // Load config up here, because those changes below would be overwritten // if it's not loaded here first. g_Config.AddSearchPath(""); @@ -574,17 +590,6 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin g_Config.bSoftwareRendering = true; } } - - // This should only be called by DetectVulkanInExternalProcess(). - if (wideArgs[i] == L"--vulkan-available-check") { - // Just call it, this way it will crash here if it doesn't work. - // (this is an external process.) - bool result = VulkanMayBeAvailable(); - - LogManager::Shutdown(); - WinMainCleanup(); - return result ? EXIT_CODE_VULKAN_WORKS : EXIT_FAILURE; - } } } #ifdef _DEBUG From 09a3d1f7cb74924272a2ec29c3c99df438deed2c Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 18 Aug 2020 00:48:24 -0700 Subject: [PATCH 4/6] Net: Use locking consistently for instance counter. --- Core/Instance.cpp | 144 +++++++++++++++++++++++++++------------------- 1 file changed, 86 insertions(+), 58 deletions(-) diff --git a/Core/Instance.cpp b/Core/Instance.cpp index 8d8554629a..58673a6483 100644 --- a/Core/Instance.cpp +++ b/Core/Instance.cpp @@ -37,14 +37,74 @@ uint8_t PPSSPP_ID = 0; #if PPSSPP_PLATFORM(WINDOWS) -static HANDLE hIDMapFile = NULL; +static HANDLE hIDMapFile = nullptr; +static HANDLE mapLock = nullptr; #else -static int hIDMapFile = 0; +static int hIDMapFile = -1; +static long BUF_SIZE = 4096; #endif -static int32_t* pIDBuf = NULL; +struct InstanceInfo { + uint8_t pad[2]; + uint8_t next; + uint8_t total; +}; + #define ID_SHM_NAME "/PPSSPP_ID" +static bool UpdateInstanceCounter(void (*callback)(volatile InstanceInfo *)) { +#if PPSSPP_PLATFORM(WINDOWS) + if (!hIDMapFile) { + return false; + } + InstanceInfo *buf = (InstanceInfo *)MapViewOfFile(hIDMapFile, // handle to map object + FILE_MAP_ALL_ACCESS, // read/write permission + 0, + 0, + sizeof(InstanceInfo)); + + if (!buf) { + ERROR_LOG(SCENET, "Could not map view of file %s (%d).", ID_SHM_NAME, GetLastError()); + return false; + } + + bool result = false; + if (!mapLock || WaitForSingleObject(mapLock, INFINITE) == 0) { + callback(buf); + if (mapLock) { + ReleaseMutex(mapLock); + } + result = true; + } + UnmapViewOfFile(buf); + + return result; +#elif PPSSPP_PLATFORM(ANDROID) || defined(__LIBRETRO__) + // TODO: replace shm_open & shm_unlink with ashmem or android-shmem + return false; +#else + if (hIDMapFile < 0) { + return false; + } + + InstanceInfo *buf = (InstanceInfo *)mmap(0, BUF_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, hIDMapFile, 0); + if (buf == MAP_FAILED) { + ERROR_LOG(SCENET, "mmap(%s) failure.", ID_SHM_NAME); + return false; + } + + bool result = false; + if (mlock(buf, BUF_SIZE) == 0) { + callback(buf); + munlock(buf, BUF_SIZE); + result = true; + } + + munmap(buf, BUF_SIZE); + return result; +#endif +} + // Get current number of instance of PPSSPP running. // Must be called only once during init. void InitInstanceCounter() { @@ -56,6 +116,8 @@ void InitInstanceCounter() { int gran = sysInfo.dwAllocationGranularity ? sysInfo.dwAllocationGranularity : 0x10000; BUF_SIZE = (BUF_SIZE + gran - 1) & ~(gran - 1); + mapLock = CreateMutex(nullptr, FALSE, L"PPSSPP_ID_mutex"); + hIDMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, // use paging file NULL, // default security @@ -65,89 +127,55 @@ void InitInstanceCounter() { TEXT(ID_SHM_NAME)); // name of mapping object DWORD lasterr = GetLastError(); - if (hIDMapFile == NULL) - { + if (!hIDMapFile) { ERROR_LOG(SCENET, "Could not create %s file mapping object (%d).", ID_SHM_NAME, lasterr); PPSSPP_ID = 1; return; } - - pIDBuf = (int32_t*)MapViewOfFile(hIDMapFile, // handle to map object - FILE_MAP_ALL_ACCESS, // read/write permission - 0, - 0, - sizeof(int32_t)); //BUF_SIZE - - if (pIDBuf == NULL) { - ERROR_LOG(SCENET, "Could not map view of file %s (%d).", ID_SHM_NAME, GetLastError()); - //CloseHandle(hIDMapFile); - PPSSPP_ID = 1; - return; - } - - (*pIDBuf)++; - int id = *pIDBuf; - UnmapViewOfFile(pIDBuf); - //CloseHandle(hIDMapFile); //Should be called when program exits - //hIDMapFile = NULL; - - PPSSPP_ID = id; #elif PPSSPP_PLATFORM(ANDROID) || defined(__LIBRETRO__) // TODO : replace shm_open & shm_unlink with ashmem or android-shmem - PPSSPP_ID = 1; #else - long BUF_SIZE = 4096; - //caddr_t pIDBuf; - int status; - - // Create shared memory object - + // Create shared memory object hIDMapFile = shm_open(ID_SHM_NAME, O_CREAT | O_RDWR, 0); BUF_SIZE = (BUF_SIZE < sysconf(_SC_PAGE_SIZE)) ? sysconf(_SC_PAGE_SIZE) : BUF_SIZE; - if ((ftruncate(hIDMapFile, BUF_SIZE)) == -1) { // Set the size + if (hIDMapFile < 0 || (ftruncate(hIDMapFile, BUF_SIZE)) == -1) { // Set the size ERROR_LOG(SCENET, "ftruncate(%s) failure.", ID_SHM_NAME); PPSSPP_ID = 1; return; } - - pIDBuf = (int32_t*)mmap(0, BUF_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, hIDMapFile, 0); - if (pIDBuf == MAP_FAILED) { // Set the size - ERROR_LOG(SCENET, "mmap(%s) failure.", ID_SHM_NAME); - pIDBuf = NULL; - PPSSPP_ID = 1; - return; - } - - int id = 1; - if (mlock(pIDBuf, BUF_SIZE) == 0) { - (*pIDBuf)++; - id = *pIDBuf; - munlock(pIDBuf, BUF_SIZE); - } - - status = munmap(pIDBuf, BUF_SIZE); // Unmap the page - //status = close(hIDMapFile); // Close file, should be called when program exits? - //status = shm_unlink(ID_SHM_NAME); // Unlink [& delete] shared-memory object, should be called when program exits - - PPSSPP_ID = id; #endif + + bool success = UpdateInstanceCounter([](volatile InstanceInfo *buf) { + PPSSPP_ID = ++buf->next; + buf->total++; + }); + if (!success) { + PPSSPP_ID = 1; + } } void ShutdownInstanceCounter() { + UpdateInstanceCounter([](volatile InstanceInfo *buf) { + buf->total--; + }); + #if PPSSPP_PLATFORM(WINDOWS) if (hIDMapFile) { CloseHandle(hIDMapFile); // If program exited(or crashed?) or the last handle reference closed the shared memory object will be deleted. hIDMapFile = nullptr; } + if (mapLock) { + CloseHandle(mapLock); + mapLock = nullptr; + } #elif PPSSPP_PLATFORM(ANDROID) || defined(__LIBRETRO__) // Do nothing #else - // TODO : This unlink should be called when program exits instead of everytime the game reset. - if (hIDMapFile != 0) { + if (hIDMapFile >= 0) { close(hIDMapFile); shm_unlink(ID_SHM_NAME); // If program exited or crashed before unlinked the shared memory object and it's contents will persist. - hIDMapFile = 0; + hIDMapFile = -1; } #endif } From b0ca6354147c61fcb75345549b4eaa65b57d9dbe Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 18 Aug 2020 01:07:12 -0700 Subject: [PATCH 5/6] Windows: Show instance counter only with peers. --- Core/Instance.cpp | 8 ++++++++ Core/Instance.h | 1 + Windows/MainWindow.cpp | 12 +++++++++++- Windows/WindowsHost.cpp | 10 +++++++--- Windows/WindowsHost.h | 2 ++ 5 files changed, 29 insertions(+), 4 deletions(-) diff --git a/Core/Instance.cpp b/Core/Instance.cpp index 58673a6483..8084c2ff25 100644 --- a/Core/Instance.cpp +++ b/Core/Instance.cpp @@ -105,6 +105,14 @@ static bool UpdateInstanceCounter(void (*callback)(volatile InstanceInfo *)) { #endif } +int GetInstancePeerCount() { + static int c = 0; + UpdateInstanceCounter([](volatile InstanceInfo *buf) { + c = buf->total; + }); + return c; +} + // Get current number of instance of PPSSPP running. // Must be called only once during init. void InitInstanceCounter() { diff --git a/Core/Instance.h b/Core/Instance.h index 5fdfd8106c..12f6518f10 100644 --- a/Core/Instance.h +++ b/Core/Instance.h @@ -25,6 +25,7 @@ extern uint8_t PPSSPP_ID; void InitInstanceCounter(); void ShutdownInstanceCounter(); +int GetInstancePeerCount(); inline bool IsFirstInstance() { return PPSSPP_ID == 1; diff --git a/Windows/MainWindow.cpp b/Windows/MainWindow.cpp index 59f6820aa5..a6ba627622 100644 --- a/Windows/MainWindow.cpp +++ b/Windows/MainWindow.cpp @@ -46,6 +46,7 @@ #include "Core/Config.h" #include "Core/ConfigValues.h" #include "Core/Debugger/SymbolMap.h" +#include "Core/Instance.h" #include "Core/MIPS/JitCommon/JitCommon.h" #include "Core/MIPS/JitCommon/JitBlockCache.h" #include "Windows/InputBox.h" @@ -466,7 +467,11 @@ namespace MainWindow void UpdateWindowTitle() { // Seems to be fine to call now since we use a UNICODE build... - SetWindowText(hwndMain, windowTitle.c_str()); + std::wstring title = windowTitle; + if (PPSSPP_ID >= 1 && GetInstancePeerCount() > 1) { + title.append(ConvertUTF8ToWString(StringFromFormat(" (instance: %d)", (int)PPSSPP_ID))); + } + SetWindowText(hwndMain, title.c_str()); } void SetWindowTitle(const wchar_t *title) { @@ -708,6 +713,7 @@ namespace MainWindow case WM_ACTIVATE: { + UpdateWindowTitle(); bool pause = true; if (wParam == WA_ACTIVE || wParam == WA_CLICKACTIVE) { WindowsRawInput::GainFocus(); @@ -741,6 +747,10 @@ namespace MainWindow } break; + case WM_SETFOCUS: + UpdateWindowTitle(); + break; + case WM_ERASEBKGND: // This window is always covered by DisplayWindow. No reason to erase. return 1; diff --git a/Windows/WindowsHost.cpp b/Windows/WindowsHost.cpp index f0735eb202..e197877ce7 100644 --- a/Windows/WindowsHost.cpp +++ b/Windows/WindowsHost.cpp @@ -170,9 +170,7 @@ void WindowsHost::SetWindowTitle(const char *message) { #ifdef _DEBUG winTitle.append(L" (debug)"); #endif - if (PPSSPP_ID >= 1) { - winTitle.append(ConvertUTF8ToWString(StringFromFormat(" (instance: %d)", (int)PPSSPP_ID))); - } + lastTitle_ = winTitle; MainWindow::SetWindowTitle(winTitle.c_str()); PostMessage(mainWindow_, MainWindow::WM_USER_WINDOW_TITLE_CHANGED, 0, 0); @@ -194,6 +192,12 @@ void WindowsHost::ShutdownSound() { void WindowsHost::UpdateUI() { PostMessage(mainWindow_, MainWindow::WM_USER_UPDATE_UI, 0, 0); + + int peers = GetInstancePeerCount(); + if (PPSSPP_ID >= 1 && peers != lastNumInstances_) { + lastNumInstances_ = peers; + PostMessage(mainWindow_, MainWindow::WM_USER_WINDOW_TITLE_CHANGED, 0, 0); + } } void WindowsHost::UpdateMemView() { diff --git a/Windows/WindowsHost.h b/Windows/WindowsHost.h index 3aadb76dc8..7c96fe6631 100644 --- a/Windows/WindowsHost.h +++ b/Windows/WindowsHost.h @@ -73,6 +73,8 @@ private: HWND mainWindow_; GraphicsContext *gfx_ = nullptr; size_t numDinputDevices_ = 0; + std::wstring lastTitle_; + int lastNumInstances_ = 0; std::list> input; }; From 31830dd4df457b0099bfcb80b9f1d7ad6f69e32b Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 18 Aug 2020 01:07:51 -0700 Subject: [PATCH 6/6] native: Minor header cleanup. --- ext/native/net/resolve.h | 4 ---- ext/native/ui/ui_context.cpp | 1 + ext/native/ui/ui_context.h | 6 +++++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/ext/native/net/resolve.h b/ext/native/net/resolve.h index 8cc9756392..882ed5c0d5 100644 --- a/ext/native/net/resolve.h +++ b/ext/native/net/resolve.h @@ -11,10 +11,6 @@ namespace net { void Init(); void Shutdown(); -// use free() to free the returned string. -char *DNSResolveTry(const char *host, const char **err); -char *DNSResolve(const char *host); - enum class DNSType { ANY = 0, IPV4 = 1, diff --git a/ext/native/ui/ui_context.cpp b/ext/native/ui/ui_context.cpp index 22cc79c24b..be30e861ca 100644 --- a/ext/native/ui/ui_context.cpp +++ b/ext/native/ui/ui_context.cpp @@ -12,6 +12,7 @@ #include "gfx_es2/draw_text.h" #include "Common/Log.h" +#include "UI/TextureUtil.h" UIContext::UIContext() { fontStyle_ = new UI::FontStyle(); diff --git a/ext/native/ui/ui_context.h b/ext/native/ui/ui_context.h index effc248136..b6d9dd3e43 100644 --- a/ext/native/ui/ui_context.h +++ b/ext/native/ui/ui_context.h @@ -1,12 +1,12 @@ #pragma once +#include #include #include "base/basictypes.h" #include "math/geom2d.h" #include "math/lin/vec3.h" #include "gfx/texture_atlas.h" -#include "UI/TextureUtil.h" // Everything you need to draw a UI collected into a single unit that can be passed around. // Everything forward declared so this header is safe everywhere. @@ -22,13 +22,17 @@ namespace Draw { } class Texture; +class ManagedTexture; class DrawBuffer; class TextDrawer; namespace UI { struct Drawable; + struct EventParams; struct Theme; struct FontStyle; + class Event; + class View; } class DrawBuffer;