RegTest: Support using global data directory

This commit is contained in:
Stenzek 2024-11-05 13:58:20 +10:00
parent a854ed2da1
commit 88e14dd3ff
No known key found for this signature in database
5 changed files with 104 additions and 79 deletions

View File

@ -26,8 +26,9 @@ def run_regression_test(runner, destdir, dump_interval, frames, renderer, cargs,
args += cargs args += cargs
args += ["--", gamepath] args += ["--", gamepath]
print("Running '%s'" % (" ".join(args))) #print("Running '%s'" % (" ".join(args)))
subprocess.run(args) subprocess.run(args)
return os.path.basename(gamepath)
def run_regression_tests(runner, gamedir, destdir, dump_interval, frames, parallel, renderer, cargs): def run_regression_tests(runner, gamedir, destdir, dump_interval, frames, parallel, renderer, cargs):
@ -50,6 +51,11 @@ def run_regression_tests(runner, gamedir, destdir, dump_interval, frames, parall
print("Processing %u games on %u processors" % (len(gamepaths), parallel)) print("Processing %u games on %u processors" % (len(gamepaths), parallel))
func = partial(run_regression_test, runner, destdir, dump_interval, frames, renderer, cargs) func = partial(run_regression_test, runner, destdir, dump_interval, frames, renderer, cargs)
pool = multiprocessing.Pool(parallel) pool = multiprocessing.Pool(parallel)
completed = 0
for filename in pool.imap_unordered(func, gamepaths, chunksize=1):
completed += 1
print("[%u%% %u/%u] %s" % ((completed * 100) // len(gamepaths), completed, len(gamepaths), filename))
pool.map(func, gamepaths, chunksize=1) pool.map(func, gamepaths, chunksize=1)
pool.close() pool.close()

View File

@ -18,6 +18,7 @@
#include "common/assert.h" #include "common/assert.h"
#include "common/error.h" #include "common/error.h"
#include "common/file_system.h"
#include "common/layered_settings_interface.h" #include "common/layered_settings_interface.h"
#include "common/log.h" #include "common/log.h"
#include "common/path.h" #include "common/path.h"
@ -26,8 +27,14 @@
#include "fmt/format.h" #include "fmt/format.h"
#include <cstdarg> #include <cstdarg>
#include <cstdlib>
#include <limits> #include <limits>
#ifdef _WIN32
#include "common/windows_headers.h"
#include <ShlObj.h>
#endif
LOG_CHANNEL(Host); LOG_CHANNEL(Host);
namespace Host { namespace Host {
@ -35,6 +42,71 @@ static std::mutex s_settings_mutex;
static LayeredSettingsInterface s_layered_settings_interface; static LayeredSettingsInterface s_layered_settings_interface;
} // namespace Host } // namespace Host
bool Host::Internal::ShouldUsePortableMode()
{
#ifndef __ANDROID__
// Check whether portable.ini exists in the program directory.
return (FileSystem::FileExists(Path::Combine(EmuFolders::AppRoot, "portable.txt").c_str()) ||
FileSystem::FileExists(Path::Combine(EmuFolders::AppRoot, "settings.ini").c_str()));
#else
return false;
#endif
}
std::string Host::Internal::ComputeDataDirectory()
{
std::string ret;
if (ShouldUsePortableMode())
{
ret = EmuFolders::AppRoot;
return ret;
}
#if defined(_WIN32)
// On Windows, use My Documents\DuckStation.
PWSTR documents_directory;
if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_Documents, 0, NULL, &documents_directory)))
{
if (std::wcslen(documents_directory) > 0)
ret = Path::Combine(StringUtil::WideStringToUTF8String(documents_directory), "DuckStation");
CoTaskMemFree(documents_directory);
}
#elif (defined(__linux__) || defined(__FreeBSD__)) && !defined(__ANDROID__)
// Use $XDG_CONFIG_HOME/duckstation if it exists.
const char* xdg_config_home = getenv("XDG_CONFIG_HOME");
if (xdg_config_home && Path::IsAbsolute(xdg_config_home))
{
ret = Path::RealPath(Path::Combine(xdg_config_home, "duckstation"));
}
else
{
// Use ~/.local/share/duckstation otherwise.
const char* home_dir = getenv("HOME");
if (home_dir)
{
// ~/.local/share should exist, but just in case it doesn't and this is a fresh profile..
const std::string local_dir(Path::Combine(home_dir, ".local"));
const std::string share_dir(Path::Combine(local_dir, "share"));
FileSystem::EnsureDirectoryExists(local_dir.c_str(), false);
FileSystem::EnsureDirectoryExists(share_dir.c_str(), false);
ret = Path::RealPath(Path::Combine(share_dir, "duckstation"));
}
}
#elif defined(__APPLE__)
static constexpr char MAC_DATA_DIR[] = "Library/Application Support/DuckStation";
const char* home_dir = getenv("HOME");
if (home_dir)
ret = Path::RealPath(Path::Combine(home_dir, MAC_DATA_DIR));
#endif
// Couldn't find anything? Fall back to portable.
if (ret.empty())
ret = EmuFolders::AppRoot;
return ret;
}
std::unique_lock<std::mutex> Host::GetSettingsLock() std::unique_lock<std::mutex> Host::GetSettingsLock()
{ {
return std::unique_lock<std::mutex>(s_settings_mutex); return std::unique_lock<std::mutex>(s_settings_mutex);

View File

@ -112,6 +112,13 @@ void ReleaseGPUDevice();
void FrameDone(); void FrameDone();
namespace Internal { namespace Internal {
/// Returns true if the host should use portable mode.
bool ShouldUsePortableMode();
/// Based on the current configuration, determines what the data directory is.
std::string ComputeDataDirectory();
/// Retrieves the base settings layer. Must call with lock held. /// Retrieves the base settings layer. Must call with lock held.
SettingsInterface* GetBaseSettingsLayer(); SettingsInterface* GetBaseSettingsLayer();
@ -129,5 +136,7 @@ void SetGameSettingsLayer(SettingsInterface* sif, std::unique_lock<std::mutex>&
/// Sets the input profile settings layer. Called by VMManager when the game changes. /// Sets the input profile settings layer. Called by VMManager when the game changes.
void SetInputSettingsLayer(SettingsInterface* sif, std::unique_lock<std::mutex>& lock); void SetInputSettingsLayer(SettingsInterface* sif, std::unique_lock<std::mutex>& lock);
} // namespace Internal } // namespace Internal
} // namespace Host } // namespace Host

View File

@ -71,11 +71,6 @@
LOG_CHANNEL(Host); LOG_CHANNEL(Host);
#ifdef _WIN32
#include "common/windows_headers.h"
#include <ShlObj.h>
#endif
static constexpr u32 SETTINGS_VERSION = 3; static constexpr u32 SETTINGS_VERSION = 3;
static constexpr u32 SETTINGS_SAVE_DELAY = 1000; static constexpr u32 SETTINGS_SAVE_DELAY = 1000;
@ -96,7 +91,6 @@ static bool PerformEarlyHardwareChecks();
static bool EarlyProcessStartup(); static bool EarlyProcessStartup();
static void RegisterTypes(); static void RegisterTypes();
static bool InitializeConfig(std::string settings_filename); static bool InitializeConfig(std::string settings_filename);
static bool ShouldUsePortableMode();
static void SetAppRoot(); static void SetAppRoot();
static void SetResourcesDirectory(); static void SetResourcesDirectory();
static bool SetDataDirectory(); static bool SetDataDirectory();
@ -516,13 +510,6 @@ bool QtHost::SetCriticalFolders()
return true; return true;
} }
bool QtHost::ShouldUsePortableMode()
{
// Check whether portable.ini exists in the program directory.
return (FileSystem::FileExists(Path::Combine(EmuFolders::AppRoot, "portable.txt").c_str()) ||
FileSystem::FileExists(Path::Combine(EmuFolders::AppRoot, "settings.ini").c_str()));
}
void QtHost::SetAppRoot() void QtHost::SetAppRoot()
{ {
const std::string program_path = FileSystem::GetProgramPath(); const std::string program_path = FileSystem::GetProgramPath();
@ -545,54 +532,11 @@ void QtHost::SetResourcesDirectory()
bool QtHost::SetDataDirectory() bool QtHost::SetDataDirectory()
{ {
// Already set, e.g. by -portable. // Already set, e.g. by -portable.
if (!EmuFolders::DataRoot.empty()) if (EmuFolders::DataRoot.empty())
return true; EmuFolders::DataRoot = Host::Internal::ComputeDataDirectory();
if (ShouldUsePortableMode())
{
EmuFolders::DataRoot = EmuFolders::AppRoot;
return true;
}
#if defined(_WIN32)
// On Windows, use My Documents\DuckStation.
PWSTR documents_directory;
if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_Documents, 0, NULL, &documents_directory)))
{
if (std::wcslen(documents_directory) > 0)
EmuFolders::DataRoot = Path::Combine(StringUtil::WideStringToUTF8String(documents_directory), "DuckStation");
CoTaskMemFree(documents_directory);
}
#elif defined(__linux__) || defined(__FreeBSD__)
// Use $XDG_CONFIG_HOME/duckstation if it exists.
const char* xdg_config_home = getenv("XDG_CONFIG_HOME");
if (xdg_config_home && Path::IsAbsolute(xdg_config_home))
{
EmuFolders::DataRoot = Path::RealPath(Path::Combine(xdg_config_home, "duckstation"));
}
else
{
// Use ~/.local/share/duckstation otherwise.
const char* home_dir = getenv("HOME");
if (home_dir)
{
// ~/.local/share should exist, but just in case it doesn't and this is a fresh profile..
const std::string local_dir(Path::Combine(home_dir, ".local"));
const std::string share_dir(Path::Combine(local_dir, "share"));
FileSystem::EnsureDirectoryExists(local_dir.c_str(), false);
FileSystem::EnsureDirectoryExists(share_dir.c_str(), false);
EmuFolders::DataRoot = Path::RealPath(Path::Combine(share_dir, "duckstation"));
}
}
#elif defined(__APPLE__)
static constexpr char MAC_DATA_DIR[] = "Library/Application Support/DuckStation";
const char* home_dir = getenv("HOME");
if (home_dir)
EmuFolders::DataRoot = Path::RealPath(Path::Combine(home_dir, MAC_DATA_DIR));
#endif
// make sure it exists // make sure it exists
if (!EmuFolders::DataRoot.empty() && !FileSystem::DirectoryExists(EmuFolders::DataRoot.c_str())) if (!FileSystem::DirectoryExists(EmuFolders::DataRoot.c_str()))
{ {
// we're in trouble if we fail to create this directory... but try to hobble on with portable // we're in trouble if we fail to create this directory... but try to hobble on with portable
Error error; Error error;
@ -610,10 +554,6 @@ bool QtHost::SetDataDirectory()
} }
} }
// couldn't determine the data directory? fallback to portable.
if (EmuFolders::DataRoot.empty())
EmuFolders::DataRoot = EmuFolders::AppRoot;
return true; return true;
} }

View File

@ -34,7 +34,7 @@
#include <csignal> #include <csignal>
#include <cstdio> #include <cstdio>
LOG_CHANNEL(RegTestHost); LOG_CHANNEL(Host);
namespace RegTestHost { namespace RegTestHost {
static bool ParseCommandLineParameters(int argc, char* argv[], std::optional<SystemBootParameters>& autoboot); static bool ParseCommandLineParameters(int argc, char* argv[], std::optional<SystemBootParameters>& autoboot);
@ -58,19 +58,10 @@ static std::string s_dump_base_directory;
bool RegTestHost::SetFolders() bool RegTestHost::SetFolders()
{ {
std::string program_path(FileSystem::GetProgramPath()); std::string program_path(FileSystem::GetProgramPath());
INFO_LOG("Program Path: {}", program_path); DEV_LOG("Program Path: {}", program_path);
EmuFolders::AppRoot = Path::Canonicalize(Path::GetDirectory(program_path)); EmuFolders::AppRoot = Path::Canonicalize(Path::GetDirectory(program_path));
EmuFolders::DataRoot = EmuFolders::AppRoot; EmuFolders::DataRoot = Host::Internal::ComputeDataDirectory();
#ifdef __APPLE__
static constexpr char MAC_DATA_DIR[] = "Library/Application Support/DuckStation";
const char* home_dir = getenv("HOME");
if (home_dir)
EmuFolders::DataRoot = Path::Combine(home_dir, MAC_DATA_DIR);
#endif
// On Windows/Linux, these are in the binary directory.
EmuFolders::Resources = Path::Combine(EmuFolders::AppRoot, "resources"); EmuFolders::Resources = Path::Combine(EmuFolders::AppRoot, "resources");
DEV_LOG("AppRoot Directory: {}", EmuFolders::AppRoot); DEV_LOG("AppRoot Directory: {}", EmuFolders::AppRoot);
@ -87,6 +78,12 @@ bool RegTestHost::SetFolders()
return false; return false;
} }
if (EmuFolders::DataRoot.empty() || !FileSystem::EnsureDirectoryExists(EmuFolders::DataRoot.c_str(), false))
{
ERROR_LOG("Failed to create data directory '{}'", EmuFolders::DataRoot);
return false;
}
return true; return true;
} }
@ -500,7 +497,10 @@ void RegTestHost::InitializeEarlyConsole()
{ {
const bool was_console_enabled = Log::IsConsoleOutputEnabled(); const bool was_console_enabled = Log::IsConsoleOutputEnabled();
if (!was_console_enabled) if (!was_console_enabled)
{
Log::SetConsoleOutputParams(true); Log::SetConsoleOutputParams(true);
Log::SetLogLevel(Log::Level::Info);
}
} }
void RegTestHost::PrintCommandLineVersion() void RegTestHost::PrintCommandLineVersion()
@ -723,9 +723,7 @@ bool RegTestHost::SetNewDataRoot(const std::string& filename)
EmuFolders::DataRoot = std::move(dump_directory); EmuFolders::DataRoot = std::move(dump_directory);
s_base_settings_interface->SetBoolValue("Logging", "LogToFile", true); s_base_settings_interface->SetBoolValue("Logging", "LogToFile", true);
s_base_settings_interface->SetStringValue("Logging", "LogLevel", Settings::GetLogLevelName(Log::Level::Dev)); s_base_settings_interface->SetStringValue("Logging", "LogLevel", Settings::GetLogLevelName(Log::Level::Dev));
g_settings.log_to_file = true; Settings::UpdateLogConfig(*s_base_settings_interface);
g_settings.log_level = Log::Level::Dev;
g_settings.UpdateLogSettings();
} }
return true; return true;