mirror of
https://github.com/moonlight-stream/moonlight-qt.git
synced 2026-10-12 03:24:00 +00:00
The AppImage bundles libva from the build environment (Ubuntu 22.04,
VA-API 1.20). VA-API driver modules (e.g. Mesa's radeonsi_drv_video.so)
are dlopen()ed by libva and export an entrypoint named after the libva
minor version they were built against (e.g. __vaDriverInit_1_23). An
older libva cannot load newer drivers, so on any host more recent than
the build container va_openDriver() fails:
Trying .../radeonsi_drv_video.so
libva error: has no function __vaDriverInit_1_0
va_openDriver() returns -1
and Moonlight silently falls back to software decoding (reproduced on
Fedora 44 / Mesa 26.1 / RX 6500 XT; overriding the bundled libva with
LD_PRELOAD of the host libva immediately yields HW decode). Refreshing
the bundled libva at each release only postpones the breakage: the host
drivers always eventually outrun it (see #1398).
Exclude libva and its backends from linuxdeploy so Moonlight and the
bundled FFmpeg resolve them through the loader's normal search path and
pick up the host libva, which the distro's package manager keeps in step
with the host drivers. This mirrors how Mesa/GL/EGL are already
host-provided.
Hosts without a usable libva (e.g. bare NVIDIA systems) must still not
fail to launch, since libva.so.2 is a direct DT_NEEDED of Moonlight and
the bundled FFmpeg. Stage the build-environment libva in
opt/libva-fallback (outside every loader search path) together with
libva-probe, a tiny program whose only job is to carry the same
DT_NEEDED entries and VA_API_* versioned symbol references as the
binaries shipped in the AppImage. The generated AppRun runs the probe
first: if the dynamic loader can start it against the host, the host
libva is used (probe passing is, by construction, exactly Moonlight
being loadable); if not, it prepends the fallback directory and launches
with the bundled libva, matching pre-existing behavior. The build script
verifies that the probe references every version node required by the
shipped binaries, so the two cannot silently drift apart.
36 lines
1.4 KiB
C
36 lines
1.4 KiB
C
/*
|
|
* libva-probe: loadability oracle for the AppImage AppRun.
|
|
*
|
|
* Moonlight and the bundled FFmpeg import libva through symbols carrying
|
|
* VA_API_* ELF version nodes. Whether the libva installed on the host can
|
|
* satisfy those requirements cannot be inferred portably from file names or
|
|
* loader caches, so this program embeds the same DT_NEEDED entries and
|
|
* versioned symbol references as those binaries without ever calling into
|
|
* them: either the dynamic loader resolves everything and main() runs (the
|
|
* host libva is usable), or the exec itself fails and AppRun must fall back
|
|
* to the build-environment libva staged next to this binary.
|
|
*
|
|
* scripts/build-appimage.sh verifies at build time that this file references
|
|
* every VA_API_* node required by the binaries shipped in the AppImage, so
|
|
* it stays automatically in sync with the libva usage there.
|
|
*/
|
|
|
|
#include <stddef.h>
|
|
|
|
#include <va/va.h>
|
|
#include <va/va_x11.h>
|
|
|
|
/* Address references are enough: they produce relocations against the
|
|
* versioned symbols, which is what makes the loader check the host's
|
|
* VA_API_* version nodes. The functions must never actually be called.
|
|
* volatile keeps the table (and its relocations) alive through -O2. */
|
|
static void *volatile requirements[] = {
|
|
(void *)vaCreateSurfaces, /* libva.so.2, VA_API_0.33.0 */
|
|
(void *)vaGetDisplay, /* libva-x11.so.2 */
|
|
};
|
|
|
|
int main(void)
|
|
{
|
|
return requirements[0] == NULL;
|
|
}
|