mirror of
https://github.com/ran-j/PS2Recomp.git
synced 2026-09-26 08:51:05 -04:00
f4309cd18c
* refactor: from guest threads to EE scheduler * feat: bad wip mpeg fix for code veronica * feat: cheap copy from host feat: small perf o vsync tick * feat: added EE clock Hz fix: fix MPEG out of sync with new EE refactor * fix: fix lotr tests
251 lines
7.8 KiB
C++
251 lines
7.8 KiB
C++
#include "ps2_runtime.h"
|
|
#include "games_database.h"
|
|
#if defined(PS2X_ENABLE_DEBUG_UI) && !defined(PLATFORM_VITA)
|
|
#include "ps2_debug_panel.h"
|
|
#endif
|
|
|
|
#ifdef _DEBUG
|
|
#include "ps2_log.h"
|
|
#endif
|
|
|
|
#include <iostream>
|
|
#include <string>
|
|
#include <filesystem>
|
|
#include <exception>
|
|
#include <algorithm>
|
|
#include <cstdlib>
|
|
|
|
#if defined(__ANDROID__)
|
|
#include <android/log.h>
|
|
#include <unistd.h>
|
|
#include <thread>
|
|
#include <cstdio>
|
|
#include <cstring>
|
|
#endif
|
|
|
|
namespace
|
|
{
|
|
#if defined(__ANDROID__)
|
|
int g_logcatPipeFds[2]{-1, -1};
|
|
std::thread g_logcatThread;
|
|
|
|
void stopLogcatRedirect()
|
|
{
|
|
std::fflush(stdout);
|
|
std::fflush(stderr);
|
|
close(STDOUT_FILENO);
|
|
close(STDERR_FILENO);
|
|
if (g_logcatPipeFds[1] >= 0)
|
|
{
|
|
close(g_logcatPipeFds[1]);
|
|
g_logcatPipeFds[1] = -1;
|
|
}
|
|
if (g_logcatThread.joinable())
|
|
{
|
|
g_logcatThread.join();
|
|
}
|
|
}
|
|
|
|
void redirectStdioToLogcat()
|
|
{
|
|
if (pipe(g_logcatPipeFds) != 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
setvbuf(stdout, nullptr, _IOLBF, 0);
|
|
setvbuf(stderr, nullptr, _IONBF, 0);
|
|
dup2(g_logcatPipeFds[1], STDOUT_FILENO);
|
|
dup2(g_logcatPipeFds[1], STDERR_FILENO);
|
|
|
|
g_logcatThread = std::thread([]()
|
|
{
|
|
FILE *reader = fdopen(g_logcatPipeFds[0], "r");
|
|
if (!reader)
|
|
{
|
|
return;
|
|
}
|
|
char line[1024];
|
|
while (fgets(line, sizeof(line), reader))
|
|
{
|
|
size_t len = std::strlen(line);
|
|
if (len > 0 && line[len - 1] == '\n')
|
|
{
|
|
line[len - 1] = '\0';
|
|
}
|
|
__android_log_write(ANDROID_LOG_INFO, "ps2x", line);
|
|
}
|
|
fclose(reader);
|
|
g_logcatPipeFds[0] = -1;
|
|
});
|
|
if (std::atexit(stopLogcatRedirect) != 0)
|
|
{
|
|
close(STDOUT_FILENO);
|
|
close(STDERR_FILENO);
|
|
close(g_logcatPipeFds[1]);
|
|
g_logcatPipeFds[1] = -1;
|
|
if (g_logcatThread.joinable())
|
|
{
|
|
g_logcatThread.join();
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void setupTerminateLogger() // to help on release build crashs
|
|
{
|
|
std::set_terminate([]()
|
|
{
|
|
std::cerr << "[terminate] unhandled exception" << std::endl;
|
|
const std::exception_ptr ep = std::current_exception();
|
|
if (ep)
|
|
{
|
|
try
|
|
{
|
|
std::rethrow_exception(ep);
|
|
}
|
|
catch (const std::system_error &e)
|
|
{
|
|
std::cerr << "[terminate] std::system_error code=" << e.code().value()
|
|
<< " category=" << e.code().category().name()
|
|
<< " message=" << e.what() << std::endl;
|
|
}
|
|
catch (const std::exception &e)
|
|
{
|
|
std::cerr << "[terminate] std::exception: " << e.what() << std::endl;
|
|
}
|
|
catch (...)
|
|
{
|
|
std::cerr << "[terminate] non-std exception" << std::endl;
|
|
}
|
|
}
|
|
std::abort(); });
|
|
}
|
|
|
|
std::string normalizeGameId(const std::string &folderName)
|
|
{
|
|
std::string result = folderName;
|
|
|
|
size_t underscore = result.find('_');
|
|
if (underscore != std::string::npos)
|
|
result[underscore] = '-';
|
|
|
|
size_t dot = result.find('.');
|
|
if (dot != std::string::npos)
|
|
result.erase(dot, 1);
|
|
|
|
std::ranges::transform(result, result.begin(), [](unsigned char character)
|
|
{ return static_cast<char>(std::toupper(character)); });
|
|
|
|
return result;
|
|
}
|
|
|
|
std::filesystem::path getExecutablePath(int argc, char *argv[])
|
|
{
|
|
if (argc >= 2 && argv[1] && argv[1][0] != '\0')
|
|
{
|
|
std::cout << "Using argv boot path" << std::endl;
|
|
return std::filesystem::path(argv[1]);
|
|
}
|
|
#if defined(PS2X_DEFAULT_BOOT_ELF)
|
|
std::cout << "Using default boot file" << std::endl;
|
|
const std::filesystem::path configuredPath = std::filesystem::path(PS2X_DEFAULT_BOOT_ELF);
|
|
#if defined(PLATFORM_VITA)
|
|
return configuredPath;
|
|
#endif
|
|
if (configuredPath.is_absolute())
|
|
{
|
|
return configuredPath;
|
|
}
|
|
return (std::filesystem::current_path() / configuredPath).lexically_normal();
|
|
#else
|
|
throw std::runtime_error("Unable to determine executable path. Pass the guest ELF as argv[1] or define PS2X_DEFAULT_BOOT_ELF.");
|
|
#endif
|
|
}
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
#if defined(__ANDROID__)
|
|
redirectStdioToLogcat();
|
|
#endif
|
|
setupTerminateLogger();
|
|
|
|
try
|
|
{
|
|
std::filesystem::path pathObj = getExecutablePath(argc, argv);
|
|
|
|
std::string filePathStr = pathObj.string();
|
|
std::string elfName = pathObj.filename().string();
|
|
std::string normalizedId = normalizeGameId(elfName);
|
|
|
|
std::string windowTitle = "PS2-Recomp | ";
|
|
const char *gameName = getGameName(normalizedId);
|
|
|
|
#if !defined(PLATFORM_VITA)
|
|
if (gameName)
|
|
{
|
|
windowTitle += std::string(gameName) + " | " + elfName;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
windowTitle += elfName;
|
|
}
|
|
|
|
PS2Runtime runtime;
|
|
#if defined(PS2X_ENABLE_DEBUG_UI) && !defined(PLATFORM_VITA)
|
|
// This hook is to prevent leak rlimgui deps to recompiler etc
|
|
PS2DebugPanel debugPanel;
|
|
runtime.setDebugUiCallbacks(
|
|
[](PS2Runtime &rt, void *userData)
|
|
{
|
|
(void)rt;
|
|
static_cast<PS2DebugPanel *>(userData)->initialize();
|
|
},
|
|
[](PS2Runtime &rt, void *userData)
|
|
{
|
|
static_cast<PS2DebugPanel *>(userData)->draw(rt);
|
|
},
|
|
[](PS2Runtime &rt, void *userData)
|
|
{
|
|
(void)rt;
|
|
static_cast<PS2DebugPanel *>(userData)->shutdown();
|
|
},
|
|
&debugPanel);
|
|
#endif
|
|
if (!runtime.initialize(windowTitle.c_str()))
|
|
{
|
|
std::cerr << "Failed to initialize PS2 runtime" << std::endl;
|
|
return 1;
|
|
}
|
|
|
|
if (!runtime.loadELF(filePathStr))
|
|
{
|
|
std::cerr << "Failed to load ELF file: " << filePathStr << std::endl;
|
|
return 1;
|
|
}
|
|
|
|
runtime.run();
|
|
|
|
#ifdef _DEBUG
|
|
ps2_log::print_saved_location();
|
|
#endif
|
|
std::cout.flush();
|
|
std::cerr.flush();
|
|
std::_Exit(0);
|
|
}
|
|
catch (const std::exception &e)
|
|
{
|
|
std::cerr << "[main] fatal exception: " << e.what() << std::endl;
|
|
}
|
|
catch (...)
|
|
{
|
|
std::cerr << "[main] fatal exception: unknown" << std::endl;
|
|
}
|
|
|
|
std::cout.flush();
|
|
std::cerr.flush();
|
|
std::_Exit(1);
|
|
}
|