diff --git a/.github/workflows/scripts/linux/build-dependencies-runner.sh b/.github/workflows/scripts/linux/build-dependencies-runner.sh new file mode 100755 index 0000000000000..5ad7eed33b4ab --- /dev/null +++ b/.github/workflows/scripts/linux/build-dependencies-runner.sh @@ -0,0 +1,195 @@ +#!/usr/bin/env bash + +set -e + +if [ "$#" -ne 1 ]; then + echo "Syntax: $0 " + exit 1 +fi + +SCRIPTDIR=$(realpath $(dirname "${BASH_SOURCE[0]}")) +INSTALLDIR="$1" +if [ "${INSTALLDIR:0:1}" != "/" ]; then + INSTALLDIR="$PWD/$INSTALLDIR" +fi + +FREETYPE=2.14.1 +HARFBUZZ=12.0.0 +LIBBACKTRACE=ad106d5fdd5d960bd33fae1c48a351af567fd075 +LIBPNG=1.6.50 +LIBWEBP=1.6.0 +SDL=SDL3-3.2.22 +LZ4=1.10.0 +ZSTD=1.5.7 +PLUTOVG=1.3.1 +PLUTOSVG=0.0.7 + +SHADERC=2025.3 +SHADERC_GLSLANG=efd24d75bcbc55620e759f6bf42c45a32abac5f8 +SHADERC_SPIRVHEADERS=2a611a970fdbc41ac2e3e328802aed9985352dca +SHADERC_SPIRVTOOLS=33e02568181e3312f49a3cf33df470bf96ef293a + +mkdir -p deps-build +cd deps-build + +cat > SHASUMS < +#include +#include +#include +#endif + namespace GSRunner { static void InitializeConsole(); @@ -1086,4 +1094,118 @@ void GSRunner::StopPlatformMessagePump() CocoaTools::StopMainThreadEventLoop(); } +#elif defined(__linux__) +static Display* s_display = nullptr; +static Window s_window = None; +static WindowInfo s_wi; +static std::atomic s_shutdown_requested{false}; + +bool GSRunner::CreatePlatformWindow() +{ + pxAssertRel(!s_display && s_window == None, "Tried to create window when there already was one!"); + + s_display = XOpenDisplay(nullptr); + if (!s_display) + { + Console.Error("Failed to open X11 display"); + return false; + } + + int screen = DefaultScreen(s_display); + Window root = RootWindow(s_display, screen); + + s_window = XCreateSimpleWindow(s_display, root, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 1, + BlackPixel(s_display, screen), WhitePixel(s_display, screen)); + + if (s_window == None) + { + Console.Error("Failed to create X11 window"); + XCloseDisplay(s_display); + s_display = nullptr; + return false; + } + + XStoreName(s_display, s_window, "PCSX2 GS Runner"); + XSelectInput(s_display, s_window, StructureNotifyMask); + XMapWindow(s_display, s_window); + + s_wi.type = WindowInfo::Type::X11; + s_wi.display_connection = s_display; + s_wi.window_handle = reinterpret_cast(s_window); + s_wi.surface_width = WINDOW_WIDTH; + s_wi.surface_height = WINDOW_HEIGHT; + s_wi.surface_scale = 1.0f; + + XFlush(s_display); + PumpPlatformMessages(); + return true; +} + +void GSRunner::DestroyPlatformWindow() +{ + if (s_display && s_window != None) + { + XDestroyWindow(s_display, s_window); + s_window = None; + } + + if (s_display) + { + XCloseDisplay(s_display); + s_display = nullptr; + } +} + +std::optional GSRunner::GetPlatformWindowInfo() +{ + WindowInfo wi; + if (s_display && s_window != None) + wi = s_wi; + else + wi.type = WindowInfo::Type::Surfaceless; + return wi; +} + +void GSRunner::PumpPlatformMessages(bool forever) +{ + if (!s_display) + return; + + do + { + while (XPending(s_display) > 0) + { + XEvent event; + XNextEvent(s_display, &event); + + switch (event.type) + { + case ConfigureNotify: + { + const XConfigureEvent& configure = event.xconfigure; + s_wi.surface_width = static_cast(configure.width); + s_wi.surface_height = static_cast(configure.height); + break; + } + case DestroyNotify: + return; + default: + break; + } + } + + if (s_shutdown_requested.load()) + return; + + if (forever) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + } while (forever && !s_shutdown_requested.load()); +} + +void GSRunner::StopPlatformMessagePump() +{ + s_shutdown_requested.store(true); +} #endif // _WIN32 / __APPLE__ diff --git a/pcsx2-gsrunner/test_run_dumps.py b/pcsx2-gsrunner/test_run_dumps.py index b61db398fcb73..09debbd46a176 100644 --- a/pcsx2-gsrunner/test_run_dumps.py +++ b/pcsx2-gsrunner/test_run_dumps.py @@ -73,7 +73,6 @@ def run_regression_test(runner, dumpdir, renderer, upscale, renderhacks, paralle #print("Running '%s'" % (" ".join(args))) subprocess.run(args, env=environ, stdin=subprocess.DEVNULL, stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL, creationflags=creationflags) - def run_regression_tests(runner, gsdir, dumpdir, renderer, upscale, renderhacks, parallel=1): paths = glob.glob(gsdir + "/*.*", recursive=True) gamepaths = list(filter(lambda x: get_gs_name(x) is not None, paths)) @@ -104,12 +103,12 @@ def run_regression_tests(runner, gsdir, dumpdir, renderer, upscale, renderhacks, if __name__ == "__main__": parser = argparse.ArgumentParser(description="Generate frame dump images for regression tests") - parser.add_argument("-runner", action="store", required=True, help="Path to PCSX2 GS runner") - parser.add_argument("-gsdir", action="store", required=True, help="Directory containing GS dumps") - parser.add_argument("-dumpdir", action="store", required=True, help="Base directory to dump frames to") - parser.add_argument("-renderer", action="store", required=False, help="Renderer to use") + parser.add_argument("-runner", action="store", required=True, type=str.strip, help="Path to PCSX2 GS runner") + parser.add_argument("-gsdir", action="store", required=True, type=str.strip, help="Directory containing GS dumps") + parser.add_argument("-dumpdir", action="store", required=True, type=str.strip, help="Base directory to dump frames to") + parser.add_argument("-renderer", action="store", required=False, type=str.strip, help="Renderer to use") parser.add_argument("-upscale", action="store", type=float, default=1, help="Upscaling multiplier to use") - parser.add_argument("-renderhacks", action="store", required=False, help="Enable HW Rendering hacks") + parser.add_argument("-renderhacks", action="store", required=False, type=str.strip, help="Enable HW Rendering hacks") parser.add_argument("-parallel", action="store", type=int, default=1, help="Number of processes to run") args = parser.parse_args()