Files
ARMSX3/3rdparty
jpolo1224 7d25a7086e VK: frame generation through Lossless Scaling, experimental
Interpolates frames between the ones the game draws, at x2/x3/x4. The shaders
come from the user's own Lossless.dll; nothing is bundled or downloaded.

framegen runs on its OWN VkDevice and statically links volk, which defines 655
globals named vkCreateImage, vkQueueSubmit and so on -- including all 124 our
loader declares. Linked into the core those either fail to link or, worse,
merge, and framegen's volkLoadDevice() then repoints the whole RSX renderer at
framegen's device. So it lives in libarmsx3_lsfg.so, reached only by dlopen
with RTLD_LOCAL, behind a C ABI and a version script that exports eleven
symbols and nothing else. Verify with llvm-nm --dynamic --defined-only: only
armsx3_lsfg_* may appear.

Two devices with no shared semaphore means images cross as AHardwareBuffer --
Adreno and Mali both refuse vkGetMemoryFdKHR(OPAQUE_FD) on AHB-imported memory,
so upstream's FD path does not work on this hardware. Capture costs 0.007
ms/frame CPU, measured; the cost is the synchronisation, not the copies.

Notes for anyone reading this later:

  * The shader loader's user pointer must outlive initialize(). framegen copies
    the callback into ShaderPool::source and resolves shaders lazily while
    BUILDING THE CONTEXT, so a stack local there is read back from a dead frame
    -- a segfault executing at a mapped, non-executable address.
  * The "device UUID" is not one. framegen matches (vendorID << 32) | deviceID.
    Zero matches nothing.
  * Imported shaders are cached to disk. They used to live only in the library's
    map, so every restart silently had none and generate() returned 0 before
    doing any work.
  * Capture takes the COMPOSITED swapchain image, after overlays. Capturing the
    game image put the perf overlay on real frames only, so it blinked at half
    the display rate.
  * generate() runs only on a frame the game actually drew, or the PPU/SPU
    compilation screen gets interpolated too.

The pipelined path that would take waitIdle off the critical path is present but
disabled behind k_framegen_pipelining_enabled: holding a frame back conflicts
with frame-context recycling, and at least one reclaim path has not been found.
The serialised path is what works. Frame generation costs some real framerate
and wants a steady one -- interpolating an unstable rate reads as judder -- so
it is labelled experimental in the UI.
2026-08-15 01:25:21 -04:00
..
2026-06-26 12:24:04 +02:00
2026-07-09 18:12:27 +02:00
2026-08-02 00:11:19 +02:00
2026-06-12 08:09:18 +02:00
2026-07-27 16:18:26 +02:00
2026-04-19 15:25:57 +02:00
2026-07-01 22:56:29 +02:00
2026-05-20 18:10:01 +02:00
2026-08-03 22:45:24 +02:00
2026-05-30 13:14:25 +02:00
2026-06-16 12:07:57 +02:00
2026-06-21 16:37:09 +02:00
2026-04-05 11:14:11 +02:00
2026-03-06 15:06:25 +01:00
2026-03-25 08:30:41 +01:00