Commit Graph
53 Commits
Author SHA1 Message Date
Dallin Bland fe28583775 Use ASC API keys for macOS notarization 2026-09-20 22:20:01 -05:00
Dallin Bland 210961618e Prepare macOS build for signed releases 2026-09-20 15:34:43 -05:00
Dallin Bland b4dffde630 ci: harden automated release pipeline 2026-09-20 11:12:55 -05:00
Dallin Bland e8024869fa Merge pull request #30 from suyu-emu/android/build-review-fixes
Integrate the Android build fixes with the current release artifact gate, require valid release signing for published APKs, and ignore keystores repository-wide.
2026-09-20 01:11:16 -05:00
Dallin Bland a273987efe test(release): exercise publish gate with spaced paths 2026-09-19 23:40:01 -05:00
Dallin Bland 50c00c2c0f ci(release): harden package verification gate 2026-09-19 23:40:01 -05:00
Dallin Bland 584154cb88 ci(release): verify packaged applications and libretro cores 2026-09-19 23:40:01 -05:00
Dallin Bland e6ce02749d test: harden compatibility baseline timeout handling 2026-09-19 23:05:03 -05:00
Dallin Bland a3fb076483 test: establish reproducible recompiler compatibility baseline 2026-09-19 23:05:03 -05:00
Dallin Bland f249340047 test(recompiler): expand instruction correctness and ARM64 sanitizers 2026-09-19 21:32:07 -05:00
Dallin Bland 29accd93d1 test(recompiler): expand repeatable hybrid benchmark suite 2026-09-19 19:54:48 -05:00
Dallin Bland fffb9f523a chore(android): fix build scripts, flavor ABIs, CI workflows, and release signing
Consolidate the duplicate Android build scripts (the legacy one generated a nonexistent lowercase Gradle task name). Fix per-flavor ABI filters so chromeOS builds x86_64 only, move legacy sourceSets to the android extension, and align the compileSdk suppress flag. Repair the malformed JDK/cache step in verify.yml and drop the dead repo gate in android-build.yml. Add release-signing validation with debug-signed warnings, keystore secret wiring plus APK signature checks in release.yml, and update the Android build docs.
2026-09-17 21:07:31 -05:00
5de22d39fe Export Game: bake separate update/DLC dumps into the standalone snapshot (#29)
* feat(export): bake separate update/DLC dumps into standalone snapshots

Resolve base ROM plus picked update/DLC files and optional NAND-installed
add-ons through PatchManager at export time, so packaged exefs and
romfs.bin are the patched snapshot AOT recompiles. Dump decrypted AOC
next to the package and serve it from the deconstructed loader so the
standalone runtime does not need post-export NAND installs.

Co-authored-by: Dallin Bland <SourCreamCulture@users.noreply.github.com>

* fix(export): rename AOC dir local to unshadow loader member

-Werror=shadow failed Linux tests and macOS MoltenVK: the baked-AOC
scan used a local `name` that collided with AppLoader_DeconstructedRomDirectory::name.

Co-authored-by: Dallin Bland <SourCreamCulture@users.noreply.github.com>

* fix(export): fail closed on bake errors; honest ExeFS/AOC status

HOLD on PR 29: OnExport ignored session failures, directory ROMs could
claim an update bake after PatchExeFS(nullptr), empty exefs/ blocked the
Windows extract fallback, and aoc:u Count used the raw program id.

- Abort export on Resolve/ok()/unreadable extras; keep bake status
- Pass directory ExeFS into PatchManager; only list updates that applied
- Do not mkpath empty exefs/; extract fallback on all platforms; refuse
  DLC without main
- CountAddOnContent uses GetBaseTitleID like ListAddOnContent

Co-authored-by: Dallin Bland <SourCreamCulture@users.noreply.github.com>

* fix(export): refuse mixed directory+update snapshots; unbreak macOS

HOLD re-review on 363f352:

- Fail closed when an update is present but RomFS cannot BKTR without a
  Program NCA (directory dumps). Do not list Update over base romfs.bin.
- Do not create exefs/ for romfs.bin alone; never FillMissing unpatched
  main next to dumped AOC; honor extract/package failures.
- Drop static forward decls that Clang treated as extra overloads
  (DumpVirtualDir/ExtractExeFsFromRom ambiguous on macOS).
- Always remove .aot_work_* on export failure via RAII.

Co-authored-by: Dallin Bland <SourCreamCulture@users.noreply.github.com>

* fix(export): drop unused ExtractRomFsFromRom; require PatchManager replace

- Delete dead static ExtractRomFsFromRom (-Werror=unused on ENABLE_QT=ON)
- Count update as applied only when PatchExeFS/PatchRomFS return a
  different handle than the base input, not a side NCA open
- Refuse-path status is the error only (not "base game only")

Co-authored-by: Dallin Bland <SourCreamCulture@users.noreply.github.com>

* test(export): drop Core::System Resolve cases that SIGSEGV in CI

Linux tests on ea6d1a7 crashed in ExportContentSession Resolve after
System::Initialize. Keep header-only bake helpers; live Resolve still
needs a fuller emulator fixture.

Co-authored-by: Dallin Bland <SourCreamCulture@users.noreply.github.com>

* fix(export): stop Linux tests spinning 1500s; refuse-path status is the error

CoreTiming tests busy-waited while(HasPendingEvents()) with no deadline.
346d452 hung after Catch2's seed line until CTest's 1500s default. Bound
that wait to 5s, cap the tests target at 180s, and stream --durations.

Resolve error paths now set status to the error (not "base game only").

Co-authored-by: Dallin Bland <SourCreamCulture@users.noreply.github.com>

* test(ci): name Catch2 hangs; yield fiber handshake spins

346d452 Linux tests timed out at 1500s with only Catch2's seed line
because ctest captured stdout. Run bin/tests directly with -s /
--durations, split [export] vs the rest, and cap each at 30s/90s.

Fibers::InterExchange busy-waited on atomics with no yield; on a
2-vCPU runner that can starve the handshake. Yield and 5s deadline.

Co-authored-by: Dallin Bland <SourCreamCulture@users.noreply.github.com>

* test(ci): name Catch2 cases at start; fiber timeout yields home

Drop -s (lazy headers still hide hangs; RingBuffer -s floods Actions).
Print+flush the case name from a testCaseStarting listener; keep
--durations yes --order decl.

On InterExchange handshake expiry, YieldTo this thread's home fiber
and return so join() completes and REQUIRE_FALSE can fail closed.
Do not YieldTo the partner (fiber mutex deadlock).

Co-authored-by: Dallin Bland <SourCreamCulture@users.noreply.github.com>

* fix(core_timing): join host timer without a lost wakeup

Linux tests on a784eaf named CoreTiming[BasicOrderNoPausing] then
SIGTERM at the 90s GNU timeout. WaitForTimingIdle had already
returned; ~CoreTiming join hung because Reset Set() the events
before request_stop, so the thread could Wait() again with the
signal consumed. Stop first, then wake; skip pause_event.Wait
once the stop token is set.

Co-authored-by: Dallin Bland <SourCreamCulture@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Dallin Bland <SourCreamCulture@users.noreply.github.com>
2026-09-17 20:40:37 -05:00
21a7fbd5c1 macOS: port MoltenVK Apple Silicon path + GPU init guards (#28)
* fix(macos): port MoltenVK Apple Silicon path and GPU init guards

Port applicable patches from dougchansan/suyu-v0.0.4#1 onto drippu:
bundled MoltenVK for the suyu target, recursive CAMetalLayer search in
the Qt frontend, SDL Metal layer (not NSView), and shared GPU/process
unwind guards. CMake targets remain suyu/suyu-cmd; the packaged artifact
is drippu.app.

Co-authored-by: Dallin Bland <SourCreamCulture@users.noreply.github.com>

* fix(macos): create CAMetalLayer when Qt VulkanSurface walk is empty

VulkanRenderWidget still uses QWindow::VulkanSurface, which often leaves a
QContainerLayer and no CAMetalLayer. Walk the layer tree first, then
alloc/init a CAMetalLayer, setWantsLayer, and setLayer on the NSView.
Log critically if attachment still fails; vulkan_surface continues to
refuse a null layer.

Replace the dead USE_SYSTEM_MOLTENVK CI flag with YUZU_USE_BUNDLED_MOLTENVK=OFF
so release.yml matches brew molten-vk.

Co-authored-by: Dallin Bland <SourCreamCulture@users.noreply.github.com>

* ci(macos): PR MoltenVK smoke on Apple Silicon Qt path

Add macos-15 pull_request CI that builds suyu, suyu-cmd, and a focused
macos_moltenvk_smoke using the live Qt GetWindowSystemInfo CAMetalLayer
attach plus Vulkan metal surface creation. The job fails unless the log
shows MoltenVK device init. Also set SDL_WINDOW_METAL on the live SDL
Vulkan window and document brew vs bundled MoltenVK plus LIBVULKAN_PATH
for suyu-cmd.

Co-authored-by: Dallin Bland <SourCreamCulture@users.noreply.github.com>

* ci(macos): drive live VulkanRenderWidget MoltenVK device+swapchain

Fix Qt 6 void QWindow::create() so the smoke compiles. Host a
QApplication VulkanRenderWidget, snapshot InitRenderTarget WSI before
addWidget, load MoltenVK from suyu.app Frameworks with LIBVULKAN_PATH
unset, and require CreateDevice plus swapchain on that surface. PR CI
uses bundled MoltenVK (ON) and runs the binary from inside the app.

Co-authored-by: Dallin Bland <SourCreamCulture@users.noreply.github.com>

* fix(macos): hide unused suyu-cmd recomp lambda from -Werror

place_one is only called from SUYU_CMD_STATIC_RECOMP and Win32 DLL
loaders. Wrap it and the usings only it needs so macOS -Werror=unused
does not fail suyu-cmd. Windows and static-recomp paths are unchanged.

Co-authored-by: Dallin Bland <SourCreamCulture@users.noreply.github.com>

* fix(macos): link frontend_common into MoltenVK smoke

place_one is already ifdef-guarded. The smoke now compiles but fails to
link PlayTimeManager, which core's NS query service expects from
frontend_common (same as suyu-cmd).

Co-authored-by: Dallin Bland <SourCreamCulture@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Dallin Bland <SourCreamCulture@users.noreply.github.com>
2026-09-17 15:40:22 -05:00
7abfb935d7 test(recompiler): instruction correctness vs Dynarmic + x86-64 sanitizers (#22)
* test(recompiler): pin instruction correctness vs Dynarmic + x86-64 sanitizers

Expand backlog #4 coverage: hosted Translate C vs independent ARM arithmetic
(edge cases and randomized inputs) in homebrew_harness, and Translate AOT vs
in-tree Dynarmic on the same encodings in recomp_stack_harness.

ANDS/BICS/TST now update N/Z only (C/V unchanged when the shifter is idle),
matching Dynarmic and the ARM ARM.

Wire ASan+UBSan via -DSUYU_ENABLE_SANITIZERS / -DYUZU_ENABLE_SANITIZERS and a
Linux x86-64 tests.yml job. Nested probe/AOT compiles inherit the flags.

Co-authored-by: Dallin Bland <SourCreamCulture@users.noreply.github.com>

* test(recompiler): compare ANDS NZCV vs Dynarmic on N/Z only

AOT preserves incoming C/V when ANDS shift amount is 0 (ARM ARM). Dynarmic
reports C=V=0 on the same block, so the stack pin matches N/Z (and GPRs)
rather than treating Dynarmic C/V as the architectural reference.

Co-authored-by: Dallin Bland <SourCreamCulture@users.noreply.github.com>

* fix(recompiler): ANDS AOT writes C=V=0 to match A64/Dynarmic

Restore recomp_set_flags(add, result, 0, result) for ANDS/BICS/TST so
generated code clears C and V instead of leaving them stale. Drop the
N/Z-only Dynarmic mask; homebrew pins ands.c_cleared/v_cleared against a
C=V=1 preset so a stale emit fails.

Co-authored-by: Dallin Bland <SourCreamCulture@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Dallin Bland <SourCreamCulture@users.noreply.github.com>
2026-09-17 02:45:43 -05:00
Dallin Bland 980814122f chore(release): publish GitHub artifacts as drippu-* 2026-09-16 20:53:11 -05:00
2ced07049a test(recompiler): real ArmRecomp + Dynarmic + kernel stack harness (#16)
* test(recompiler): real ArmRecomp+Dynarmic+kernel stack harness

Add recomp_stack_harness that boots a minimal System, creates an
application KProcess with in-tree fixture bytes, and drives ArmRecomp
RunThread/StepThread against real ApplicationMemory and Dynarmic JIT
fallback. Proves SVC parking, TLS/TPIDRRO, cross-page stores, AOT miss
and unhandled->Dynarmic transitions, icache invalidation, restart, and
StepThread fallback.

Keep homebrew_harness as the no-deps stub smoke; fix Windows helpers
under #ifdef so full-tree -Werror builds. Wire the new target into Linux
tests CI.

Co-authored-by: Dallin Bland <SourCreamCulture@users.noreply.github.com>

* fix(recompiler): wire SetRecompLookup AOT + real icache asserts

Path-1 Hashbrown HOLD: process ArmInterface is ArmRecomp via SetRecompLookup
before init; Translate'd AOT + matching guest RX; LoadContext alone publishes
TPIDRRO; registered-PC force-miss; ClearInstructionCache refuses AOT.

Also: InvalidateCacheRange no longer permanently kills AOT (loader RX protect
was rejecting every block before first insn); Dynarmic Clear/Invalidate resets
MemoryReadCode page cache so rewritten guest RX is visible after Clear.

Co-authored-by: Dallin Bland <SourCreamCulture@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Dallin Bland <SourCreamCulture@users.noreply.github.com>
2026-09-15 21:26:49 -05:00
Cursor AgentandDallin Bland f8659e603d test(recompiler): add headless homebrew runtime harness
Add a CI-runnable harness that executes translated AArch64 blocks and
checks register/memory outcomes for SVC, TLS, multi-core context
switch, forced AOT miss, unsupported insn fallback, icache invalidate,
stop/relaunch, and StepThread policy.

Fix ArmRecomp::StepThread so AOT misses and unhandled encodings enter
the same Dynarmic fallback path as RunThread instead of PrefetchAbort.

Co-authored-by: Dallin Bland <SourCreamCulture@users.noreply.github.com>
2026-09-15 17:13:11 +00:00
1ab59b1541 fix(ci): gate release publish on required results (#8)
* test(ci): add release publication gate regression

Drive the Publish Release job the way GitHub Actions would. The check
evaluates job `if`/`needs` from `.github/workflows/release.yml` and runs
the job's shell against a stub `gh`. Required platform failures still
publish. The rolling `v0.04-latest` tag is deleted before the empty
artifact check. The release notes have no commit, toolchain, or checksum
metadata.

Co-authored-by: Dallin Bland <SourCreamCulture@users.noreply.github.com>

* fix(ci): gate release publish on required results

Replace if: always() with !cancelled() plus required job results so a
Windows, Linux, macOS, Android, or libretro failure cannot replace a
release. Keep FreeBSD and libretro-android optional. Stop deleting
v0.04-latest. Publish v0.04-<date>-<sha> with commit, toolchain, and
SHA-256 metadata. Call exporter smoke and the Catch2 tests from both
pull-request CI and the release needs list.

Co-authored-by: Dallin Bland <SourCreamCulture@users.noreply.github.com>

* chore(ci): drop leftover always() lecture from the gate check

Delete the module docstring that still taught if: always() after
release.yml stopped using it. GitHub's default success() wrap lives in
apply_github_default_success. Publish is forbidden from deleting a tag
at all, not only from deleting before the empty check.

Co-authored-by: Dallin Bland <SourCreamCulture@users.noreply.github.com>

* test(ci): reject gh prerelease as latest

GitHub returns HTTP 422 Latest release cannot be draft or prerelease
when gh release create passes --prerelease with --latest, then runs
cleanupDraftRelease. The gate stub now fails the same way.

Co-authored-by: Dallin Bland <SourCreamCulture@users.noreply.github.com>

* fix(ci): stop marking prereleases as latest

Remove --latest from publish_release.sh. GitHub forbids a prerelease
from being the latest release and gh then deletes the draft.

Co-authored-by: Dallin Bland <SourCreamCulture@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Dallin Bland <SourCreamCulture@users.noreply.github.com>
2026-09-15 07:39:43 +00:00
9f77011142 Repair generated C placement, fix RET/BLR semantics, and add a portable exporter smoke/regression target to CI (#2)
* Repair generated C placement, fix RET/BLR semantics, and add a portable exporter smoke/regression target to CI.

Move AES helpers to file-scope constant tables so EmitProject output is valid C, make RET use encoded Rn and BLR read its target before writing X30, and add a header-only exporter smoke job that compiles a generated project and keeps those branches as regressions.

Co-authored-by: Dallin Bland <SourCreamCulture@users.noreply.github.com>

* Fix exporter smoke on Windows by spawning CMake argv instead of cmd.exe.

cmd.exe /c stripped quotes around C:/Program Files/CMake, so nested configure never ran. Invoke cmake and the branch probe with _spawnv, and reuse the parent generator/platform.

Co-authored-by: Dallin Bland <SourCreamCulture@users.noreply.github.com>

* Quote Windows CMake argv for CreateProcess so generator names with spaces survive.

_spawnv still joined arguments unquoted, so Visual Studio 18 2026 became generator Visual and Program Files split off cmake.exe. Build a CommandLineToArgvW-compatible command line instead.

Co-authored-by: Dallin Bland <SourCreamCulture@users.noreply.github.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Dallin Bland <SourCreamCulture@users.noreply.github.com>
2026-09-14 22:58:34 +00:00
suyu team f265d95f04 FINAL 2026-09-13 12:24:29 +01:00
suyu team 1d8cd15274 fix: drop dead libusb package name from FreeBSD pkg install
devel/libusb was deprecated into the FreeBSD base system in 2013 and has produced no binary package since; pkg install failed with 'No packages available to install matching libusb'. FreeBSD 15+ already provides the libusb API in base, which is what the project's own CMakeLists.txt comment already assumes.
2026-09-13 12:11:38 +01:00
suyu team d1d09321d7 feat: build the libretro core for Windows as well as Linux
Only the Linux .so was produced, so no suyu_libretro.dll ever reached the release. RetroArch loads .dll on Windows and .so on Linux, so both are shipped.
2026-09-04 23:14:34 +01:00
suyu team d850bb223a chore: remove all workflows except release
autofix.ci opened PRs referencing pre-rewrite history, and every extra workflow auto-fired on push, creating runs attributed to the pusher. ci.yml also hardcoded the original repository name.
2026-09-04 19:23:41 +01:00
suyu team 06b5a73366 fix: use _pkg/ instead of dist/ to avoid repo dist/ collision in packaging
All build jobs were using dist/ as staging dir, which collides with
the repo's own dist/ folder containing resources/icons/translations.
This caused libretro tar.gz to contain 625 resource files instead of
just suyu_libretro.so. Renamed libretro artifact for clarity.
2026-09-04 19:18:46 +01:00