Merge pull request #20774 from hrydgard/more-changes

Windows: Speed up startup by moving input init to the input thread
This commit is contained in:
Henrik Rydgård
2025-08-31 23:28:25 +02:00
committed by GitHub
20 changed files with 72 additions and 58 deletions
+6 -6
View File
@@ -159,18 +159,18 @@ StorageError Android_RenameFileTo(const std::string &fileUri, const std::string
}
// NOTE: Does not set fullName - you're supposed to already know it.
static bool ParseFileInfo(const std::string &line, File::FileInfo *fileInfo) {
static bool ParseFileInfo(std::string_view line, File::FileInfo *fileInfo) {
std::vector<std::string> parts;
SplitString(line, '|', parts);
if (parts.size() != 4) {
ERROR_LOG(Log::FileSystem, "Bad format (1): %s", line.c_str());
ERROR_LOG(Log::FileSystem, "Bad format (1): %.*s", (int)line.size(), line.data());
return false;
}
fileInfo->name = std::string(parts[2]);
fileInfo->name = parts[2];
fileInfo->isDirectory = parts[0][0] == 'D';
fileInfo->exists = true;
if (1 != sscanf(parts[1].c_str(), "%" PRIu64, &fileInfo->size)) {
ERROR_LOG(Log::FileSystem, "Bad format (2): %s", line.c_str());
ERROR_LOG(Log::FileSystem, "Bad format (2): %.*s", (int)line.size(), line.data());
return false;
}
fileInfo->isWritable = true; // TODO: Should be passed as part of the string.
@@ -180,7 +180,7 @@ static bool ParseFileInfo(const std::string &line, File::FileInfo *fileInfo) {
uint64_t lastModifiedMs = 0;
if (1 != sscanf(parts[3].c_str(), "%" PRIu64, &lastModifiedMs)) {
ERROR_LOG(Log::FileSystem, "Bad format (3): %s", line.c_str());
ERROR_LOG(Log::FileSystem, "Bad format (3): %.*s", (int)line.size(), line.data());
return false;
}
@@ -206,7 +206,7 @@ bool Android_GetFileInfo(const std::string &fileUri, File::FileInfo *fileInfo) {
return false;
}
const char *charArray = env->GetStringUTFChars(str, 0);
bool retval = ParseFileInfo(std::string(charArray), fileInfo);
bool retval = ParseFileInfo(charArray, fileInfo);
fileInfo->fullName = Path(fileUri);
env->DeleteLocalRef(str);
+2
View File
@@ -62,6 +62,7 @@ int64_t Android_GetFreeSpaceByFilePath(const std::string &filePath);
bool Android_IsExternalStoragePreservedLegacy();
const char *Android_ErrorToString(StorageError error);
// TODO: prefix doesn't do anything yet.
std::vector<File::FileInfo> Android_ListContentUri(const std::string &uri, const std::string &prefix, bool *exists);
void Android_RegisterStorageCallbacks(JNIEnv * env, jobject obj);
@@ -87,6 +88,7 @@ inline int64_t Android_GetFreeSpaceByContentUri(const std::string &uri) { return
inline int64_t Android_GetFreeSpaceByFilePath(const std::string &filePath) { return -1; }
inline bool Android_IsExternalStoragePreservedLegacy() { return false; }
inline const char *Android_ErrorToString(StorageError error) { return ""; }
inline std::vector<File::FileInfo> Android_ListContentUri(const std::string &uri, const std::string &prefix, bool *exists) {
*exists = false;
return std::vector<File::FileInfo>();
+3 -3
View File
@@ -70,7 +70,7 @@ bool VFS::GetFileListing(const char *path, std::vector<File::FileInfo> *listing,
if (IsLocalAbsolutePath(path)) {
// Local path, not VFS.
// INFO_LOG(Log::IO, "Not a VFS path: %s . Reading local directory.", path);
File::GetFilesInDir(Path(std::string(path)), listing, filter);
File::GetFilesInDir(Path(path), listing, filter);
return true;
}
@@ -97,7 +97,7 @@ bool VFS::GetFileInfo(const char *path, File::FileInfo *info) {
if (IsLocalAbsolutePath(path)) {
// Local path, not VFS.
// INFO_LOG(Log::IO, "Not a VFS path: %s . Getting local file info.", path);
return File::GetFileInfo(Path(std::string(path)), info);
return File::GetFileInfo(Path(path), info);
}
bool fileSystemFound = false;
@@ -123,7 +123,7 @@ bool VFS::Exists(const char *path) {
if (IsLocalAbsolutePath(path)) {
// Local path, not VFS.
// INFO_LOG(Log::IO, "Not a VFS path: %s . Getting local file info.", path);
return File::Exists(Path(std::string(path)));
return File::Exists(Path(path));
}
bool fileSystemFound = false;
+1 -1
View File
@@ -212,7 +212,7 @@ void TextDrawerUWP::MeasureStringInternal(std::string_view str, float *w, float
}
if (!format) return;
std::wstring wstr = ConvertUTF8ToWString(ReplaceAll(std::string(str), "\n", "\r\n"));
std::wstring wstr = ConvertUTF8ToWString(ReplaceAll(str, "\n", "\r\n"));
format->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_LEADING);
+1 -1
View File
@@ -722,7 +722,7 @@ public:
class Choice : public ClickableItem {
public:
Choice(std::string_view text, LayoutParams *layoutParams = nullptr)
: Choice(text, std::string(), false, layoutParams) {}
: Choice(text, "", false, layoutParams) { }
Choice(std::string_view text, ImageID image, LayoutParams *layoutParams = nullptr)
: ClickableItem(layoutParams), text_(text), image_(image) {}
Choice(std::string_view text, std::string_view smallText, bool selected = false, LayoutParams *layoutParams = nullptr)
+17 -13
View File
@@ -44,21 +44,25 @@ struct IndexTable
u32_le data_table_offset; /* Offset of the param_data from start of data_table */
};
void ParamSFOData::SetValue(const std::string &key, unsigned int value, int max_size) {
values[key].type = VT_INT;
values[key].i_value = value;
values[key].max_size = max_size;
}
void ParamSFOData::SetValue(const std::string &key, const std::string &value, int max_size) {
values[key].type = VT_UTF8;
values[key].s_value = value;
values[key].max_size = max_size;
void ParamSFOData::SetValue(std::string_view key, unsigned int value, int max_size) {
auto [it, inserted] = values.try_emplace(std::string(key)); // The string construction only happens if inserted is true.
it->second.type = VT_INT;
it->second.i_value = value;
it->second.max_size = max_size;
}
void ParamSFOData::SetValue(const std::string &key, const u8 *value, unsigned int size, int max_size) {
values[key].type = VT_UTF8_SPE;
values[key].SetData(value, size);
values[key].max_size = max_size;
void ParamSFOData::SetValue(std::string_view key, std::string_view value, int max_size) {
auto [it, inserted] = values.try_emplace(std::string(key));
it->second.type = VT_UTF8;
it->second.s_value = value;
it->second.max_size = max_size;
}
void ParamSFOData::SetValue(std::string_view key, const u8 *value, unsigned int size, int max_size) {
auto [it, inserted] = values.try_emplace(std::string(key));
it->second.type = VT_UTF8_SPE;
it->second.SetData(value, size);
it->second.max_size = max_size;
}
int ParamSFOData::GetValueInt(std::string_view key) const {
+3 -3
View File
@@ -28,9 +28,9 @@ class Path;
class ParamSFOData {
public:
void SetValue(const std::string &key, unsigned int value, int max_size);
void SetValue(const std::string &key, const std::string &value, int max_size);
void SetValue(const std::string &key, const u8 *value, unsigned int size, int max_size);
void SetValue(std::string_view key, unsigned int value, int max_size);
void SetValue(std::string_view key, std::string_view value, int max_size);
void SetValue(std::string_view key, const u8 *value, unsigned int size, int max_size);
int GetValueInt(std::string_view key) const;
std::string GetValueString(std::string_view key) const; // Common keys: "TITLE", "DISC_VERSION"
+3 -3
View File
@@ -879,9 +879,9 @@ bool HasAchievementsOrLeaderboards() {
return IsActive();
}
void DownloadImageIfMissing(const std::string &cache_key, std::string &&url) {
void DownloadImageIfMissing(const std::string &cache_key, std::string_view url) {
if (g_iconCache.MarkPending(cache_key)) {
INFO_LOG(Log::Achievements, "Downloading image: %s (%s)", url.c_str(), cache_key.c_str());
INFO_LOG(Log::Achievements, "Downloading image: %.*s (%s)", (int)url.size(), url.data(), cache_key.c_str());
g_DownloadManager.StartDownloadWithCallback(url, Path(), http::RequestFlags::Default, [cache_key](http::Request &download) {
if (download.ResultCode() != 200)
return;
@@ -947,7 +947,7 @@ void identify_and_load_callback(int result, const char *error_message, rc_client
char temp[512];
if (RC_OK == rc_client_game_get_image_url(gameInfo, temp, sizeof(temp))) {
Achievements::DownloadImageIfMissing(cacheId, std::string(temp));
Achievements::DownloadImageIfMissing(cacheId, temp);
}
GameRegion region = DetectGameRegionFromID(g_paramSFO.GetDiscID());
+1 -1
View File
@@ -79,7 +79,7 @@ bool HasToken();
/// Called when the system is being shut down. If Shutdown() returns false, the shutdown should be aborted if possible.
bool Shutdown();
void DownloadImageIfMissing(const std::string &cache_key, std::string &&url);
void DownloadImageIfMissing(const std::string &cache_key, std::string_view url);
/// Called once a frame at vsync time on the CPU thread, during gameplay.
void FrameUpdate();
+1 -1
View File
@@ -98,7 +98,7 @@ void GameDB::LoadIfNeeded() {
SplitCSVLine(lineString, items);
if (items.size() != columns_.size()) {
// Bad line
ERROR_LOG(Log::System, "Bad line in CSV file: %s", std::string(lineString).c_str());
ERROR_LOG(Log::System, "Bad line in CSV file: %.*s", (int)lineString.size(), lineString.data());
continue;
}
+1 -1
View File
@@ -360,7 +360,7 @@ void KeyMappingNewKeyDialog::CreatePopupContents(UI::ViewGroup *parent) {
std::string pspButtonName = KeyMap::GetPspButtonName(this->pspBtn_);
parent->Add(new TextView(std::string(km->T("Map a new key for")) + " " + std::string(mc->T(pspButtonName)), new LinearLayoutParams(Margins(10, 0))));
parent->Add(new TextView(std::string(mapping_.ToVisualString()), new LinearLayoutParams(Margins(10, 0))));
parent->Add(new TextView(mapping_.ToVisualString(), new LinearLayoutParams(Margins(10, 0))));
comboMappingsNotEnabled_ = parent->Add(new NoticeView(NoticeLevel::WARN, km->T("Combo mappings are not enabled"), "", new LinearLayoutParams(Margins(10, 0))));
comboMappingsNotEnabled_->SetVisibility(UI::V_GONE);
+2 -2
View File
@@ -913,7 +913,7 @@ void GameBrowser::Refresh() {
if (browseFlags_ & BrowseFlags::NAVIGATE) {
if (path_.CanNavigateUp()) {
gameList_->Add(new DirButton(Path(std::string("..")), *gridStyle_, new UI::LinearLayoutParams(UI::FILL_PARENT, UI::FILL_PARENT)))->
gameList_->Add(new DirButton(Path(".."), *gridStyle_, new UI::LinearLayoutParams(UI::FILL_PARENT, UI::FILL_PARENT)))->
OnClick.Handle(this, &GameBrowser::NavigateClick);
}
@@ -1388,7 +1388,7 @@ void MainScreen::sendMessage(UIMessage message, const char *value) {
UIScreenWithBackground::sendMessage(message, value);
if (message == UIMessage::REQUEST_GAME_BOOT) {
LaunchFile(screenManager(), this, Path(std::string(value)));
LaunchFile(screenManager(), this, Path(value));
} else if (message == UIMessage::PERMISSION_GRANTED && !strcmp(value, "storage")) {
RecreateViews();
} else if (message == UIMessage::RECENT_FILES_CHANGED) {
+4 -4
View File
@@ -475,10 +475,10 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch
#elif PPSSPP_PLATFORM(IOS)
g_Config.defaultCurrentDirectory = g_Config.internalDataDirectory;
g_Config.memStickDirectory = DarwinFileSystemServices::appropriateMemoryStickDirectoryToUse();
g_Config.flash0Directory = Path(std::string(external_dir)) / "flash0";
g_Config.flash0Directory = Path(external_dir) / "flash0";
#elif PPSSPP_PLATFORM(MAC)
g_Config.memStickDirectory = DarwinFileSystemServices::appropriateMemoryStickDirectoryToUse();
g_Config.flash0Directory = Path(std::string(external_dir)) / "flash0";
g_Config.flash0Directory = Path(external_dir) / "flash0";
#elif PPSSPP_PLATFORM(SWITCH)
g_Config.memStickDirectory = g_Config.internalDataDirectory / "config/ppsspp";
g_Config.flash0Directory = g_Config.internalDataDirectory / "assets/flash0";
@@ -580,7 +580,7 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch
if (!strncmp(argv[i], "--log=", strlen("--log=")) && strlen(argv[i]) > strlen("--log="))
fileToLog = argv[i] + strlen("--log=");
if (!strncmp(argv[i], "--state=", strlen("--state=")) && strlen(argv[i]) > strlen("--state="))
stateToLoad = Path(std::string(argv[i] + strlen("--state=")));
stateToLoad = Path(argv[i] + strlen("--state="));
if (!strncmp(argv[i], "--escape-exit", strlen("--escape-exit")))
g_Config.bPauseExitsEmulator = true;
if (!strncmp(argv[i], "--pause-menu-exit", strlen("--pause-menu-exit")))
@@ -600,7 +600,7 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch
if (!strcmp(argv[i], "--developertools"))
gotoDeveloperTools = true;
if (!strncmp(argv[i], "--appendconfig=", strlen("--appendconfig=")) && strlen(argv[i]) > strlen("--appendconfig=")) {
g_Config.SetAppendedConfigIni(Path(std::string(argv[i] + strlen("--appendconfig="))));
g_Config.SetAppendedConfigIni(Path(argv[i] + strlen("--appendconfig=")));
g_Config.LoadAppendedConfig();
}
break;
+3 -3
View File
@@ -566,7 +566,7 @@ void RenderAchievement(UIContext &dc, const rc_client_achievement_t *achievement
char cacheKey[256];
snprintf(cacheKey, sizeof(cacheKey), "ai:%s:%s", achievement->badge_name, iconState == RC_CLIENT_ACHIEVEMENT_STATE_UNLOCKED ? "unlocked" : "locked");
if (RC_OK == rc_client_achievement_get_image_url(achievement, iconState, temp, sizeof(temp))) {
Achievements::DownloadImageIfMissing(cacheKey, std::string(temp));
Achievements::DownloadImageIfMissing(cacheKey, temp);
if (g_iconCache.BindIconTexture(&dc, cacheKey)) {
dc.Draw()->DrawTexRect(Bounds(bounds.x + padding, bounds.y + padding, iconSpace, iconSpace), 0.0f, 0.0f, 1.0f, 1.0f, whiteAlpha(alpha));
}
@@ -608,7 +608,7 @@ static void RenderGameAchievementSummary(UIContext &dc, const Bounds &bounds, fl
char cacheKey[256];
snprintf(cacheKey, sizeof(cacheKey), "gi:%s", gameInfo->badge_name);
if (RC_OK == rc_client_game_get_image_url(gameInfo, url, sizeof(url))) {
Achievements::DownloadImageIfMissing(cacheKey, std::string(url));
Achievements::DownloadImageIfMissing(cacheKey, url);
if (g_iconCache.BindIconTexture(&dc, cacheKey)) {
dc.Draw()->DrawTexRect(Bounds(bounds.x, bounds.y, iconSpace, iconSpace), 0.0f, 0.0f, 1.0f, 1.0f, whiteAlpha(alpha));
}
@@ -708,7 +708,7 @@ static void RenderLeaderboardEntry(UIContext &dc, const rc_client_leaderboard_en
snprintf(cacheKey, sizeof(cacheKey), "lbe:%s", entry->user);
char temp[512];
if (RC_OK == rc_client_leaderboard_entry_get_user_image_url(entry, temp, sizeof(temp))) {
Achievements::DownloadImageIfMissing(cacheKey, std::string(temp));
Achievements::DownloadImageIfMissing(cacheKey, temp);
if (g_iconCache.BindIconTexture(&dc, cacheKey)) {
dc.Draw()->DrawTexRect(Bounds(bounds.x + iconLeft, bounds.y + 4.0f, 64.0f, 64.0f), 0.0f, 0.0f, 1.0f, 1.0f, whiteAlpha(alpha));
}
+1 -1
View File
@@ -2,7 +2,7 @@
#pragma once
#include "Input/InputState.h"
#include "Common/Input/InputState.h"
#include "Windows/InputDevice.h"
#include <set>
#include <windows.h>
+14
View File
@@ -25,6 +25,12 @@
#include "Core/Config.h"
#include "Windows/InputDevice.h"
#if !PPSSPP_PLATFORM(UWP)
#include "Windows/DinputDevice.h"
#include "Windows/HidInputDevice.h"
#include "Windows/XinputDevice.h"
#endif
InputManager g_InputManager;
void InputManager::InputThread() {
@@ -64,6 +70,14 @@ void InputManager::InputThread() {
void InputManager::BeginPolling() {
runThread_.store(true, std::memory_order_relaxed);
inputThread_ = std::thread([this]() {
// In UWP, we add the devices from the main thread, before launching the thread.
// This is a bit awkward but worth the startup speed boost on non-UWP until we refactor it.
#if !PPSSPP_PLATFORM(UWP)
//add first XInput device to respond
AddDevice(new XinputDevice());
AddDevice(new DInputMetaDevice());
AddDevice(new HidInputDevice());
#endif
InputThread();
});
}
+1 -7
View File
@@ -66,9 +66,7 @@
#include "UI/GameInfoCache.h"
#include "Windows/resource.h"
#include "Windows/DinputDevice.h"
#include "Windows/XinputDevice.h"
#include "Windows/HidInputDevice.h"
#include "Windows/InputDevice.h"
#include "Windows/MainWindow.h"
#include "Windows/Debugger/Debugger_Disasm.h"
#include "Windows/Debugger/Debugger_MemoryDlg.h"
@@ -1140,10 +1138,6 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin
MainWindow::Minimize();
}
//add first XInput device to respond
g_InputManager.AddDevice(new XinputDevice());
g_InputManager.AddDevice(new DInputMetaDevice());
g_InputManager.AddDevice(new HidInputDevice());
// Emu thread (and render thread, if any) is always running!
// Only OpenGL uses an externally managed render thread (due to GL's single-threaded context design). Vulkan
// manages its own render thread.
+2 -2
View File
@@ -494,8 +494,8 @@ int main(int argc, const char* argv[])
coreParameter.gpuCore = glWorking ? gpuCore : GPUCORE_SOFTWARE;
coreParameter.graphicsContext = graphicsContext;
coreParameter.enableSound = false;
coreParameter.mountIso = mountIso ? Path(std::string(mountIso)) : Path();
coreParameter.mountRoot = mountRoot ? Path(std::string(mountRoot)) : Path();
coreParameter.mountIso = mountIso ? Path(mountIso) : Path();
coreParameter.mountRoot = mountRoot ? Path(mountRoot) : Path();
coreParameter.startBreak = false;
coreParameter.headLess = true;
coreParameter.renderScaleFactor = 1;
+1 -1
View File
@@ -1511,7 +1511,7 @@ bool retro_load_game(const struct retro_game_info *game)
CoreParameter coreParam = {};
coreParam.enableSound = true;
coreParam.fileToStart = Path(std::string(game->path));
coreParam.fileToStart = Path(game->path);
coreParam.startBreak = false;
coreParam.headLess = true; // really?
coreParam.graphicsContext = ctx;
+5 -5
View File
@@ -755,15 +755,15 @@ static bool TestAndroidContentURI() {
static const char *downloadURIString = "content://com.android.providers.downloads.documents/document/msf%3A10000000006";
AndroidContentURI treeURI;
EXPECT_TRUE(treeURI.Parse(std::string(treeURIString)));
EXPECT_TRUE(treeURI.Parse(treeURIString));
AndroidContentURI dirURI;
EXPECT_TRUE(dirURI.Parse(std::string(directoryURIString)));
EXPECT_TRUE(dirURI.Parse(directoryURIString));
AndroidContentURI fileTreeURI;
EXPECT_TRUE(fileTreeURI.Parse(std::string(fileTreeURIString)));
EXPECT_TRUE(fileTreeURI.Parse(fileTreeURIString));
AndroidContentURI fileTreeURICopy;
EXPECT_TRUE(fileTreeURICopy.Parse(std::string(fileTreeURIString)));
EXPECT_TRUE(fileTreeURICopy.Parse(fileTreeURIString));
AndroidContentURI fileURI;
EXPECT_TRUE(fileURI.Parse(std::string(fileNonTreeString)));
EXPECT_TRUE(fileURI.Parse(fileNonTreeString));
EXPECT_EQ_STR(fileTreeURI.GetLastPart(), std::string("Tekken 6.iso"));