mirror of
https://github.com/Droid-Deck/DroidDeck.git
synced 2026-11-11 11:01:07 +00:00
feat: Mali Vulkan support through MaliBridge (#2027)
This commit is contained in:
83 files changed
+2331
-80
No files matched your search
@@ -114,8 +114,10 @@ fi
|
||||
if [ "$(cat /usr/share/droiddeck/kwin-compositor 2>/dev/null)" = opengl ]; then
|
||||
unset LIBGL_ALWAYS_SOFTWARE QT_QUICK_BACKEND
|
||||
export KWIN_COMPOSE=O2 MESA_LOADER_DRIVER_OVERRIDE=zink GALLIUM_DRIVER=zink LIBGL_KOPPER_DRI2=true
|
||||
if [ -z "${KWIN_RENDER_NODES:-}" ] && [ -c /dev/dri/renderD0 ]; then
|
||||
export KWIN_RENDER_NODES=/dev/dri/renderD0
|
||||
if [ -z "${KWIN_RENDER_NODES:-}" ]; then
|
||||
for node in /dev/dri/renderD0 /dev/dri/renderD307 /dev/dri/renderD*; do
|
||||
if [ -c "$node" ]; then export KWIN_RENDER_NODES="$node"; break; fi
|
||||
done
|
||||
fi
|
||||
mkdir -p /run/droiddeck/kwin
|
||||
printf '#!/bin/sh\nGALLIUM_THREAD=0 exec /usr/bin/kwin_wayland "$@"\n' > /run/droiddeck/kwin/kwin_wayland
|
||||
|
||||
@@ -478,6 +478,14 @@ def apply_config(env, config, app_id, fixes=None):
|
||||
return result
|
||||
|
||||
|
||||
def bridge_feature_level(env):
|
||||
if env.get("BL_VKBRIDGE") != "1" or env.get("VKD3D_FEATURE_LEVEL") not in ("12_1", "12_2"):
|
||||
return None
|
||||
was = env["VKD3D_FEATURE_LEVEL"]
|
||||
env["VKD3D_FEATURE_LEVEL"] = "12_0"
|
||||
return "Mali bridge: VKD3D_FEATURE_LEVEL %s capped at 12_0 (no ray tracing or mesh shaders)" % was
|
||||
|
||||
|
||||
GAME_DEBUG_CHANNELS = (
|
||||
"timestamp", "pid", "tid", "seh", "unwind", "threadname", "debugstr", "loaddll", "mscoree",
|
||||
)
|
||||
@@ -974,6 +982,9 @@ def main():
|
||||
env["AUDIO_DIRECT_MIC"] = "0"
|
||||
env = directaudio_settings(env)
|
||||
env = vram_cap(env)
|
||||
note = bridge_feature_level(env)
|
||||
if note:
|
||||
print("droiddeck-game-env: " + note, file=sys.stderr)
|
||||
env = force_ssbs(command, env)
|
||||
game_cores(env)
|
||||
cpu_topology(env, command)
|
||||
|
||||
@@ -160,7 +160,7 @@ collect_steam_logs() {
|
||||
cp "$fex_state/status.json" "$fex_state/config/Config.json" "$BL_DEBUG_DIR/droiddeck-fex/" 2>/dev/null
|
||||
fi
|
||||
}
|
||||
trap 'collect_steam_logs 2>/dev/null || true' TERM INT HUP
|
||||
trap 'bl_stopping=1; collect_steam_logs 2>/dev/null || true' TERM INT HUP
|
||||
if [ -n "${BL_VK_DRIVER:-}" ]; then
|
||||
bl_icd_lib=$(sed -n 's/.*"library_path"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$BL_VK_DRIVER" 2>/dev/null | head -1)
|
||||
bl_icd_lib=$(printf '%s' "$bl_icd_lib" | sed 's|\\/|/|g')
|
||||
@@ -177,6 +177,83 @@ if [ -n "${BL_VK_DRIVER:-}" ]; then
|
||||
fi
|
||||
unset bl_icd_lib
|
||||
fi
|
||||
bl_webhelper_layout() {
|
||||
if [ -n "${BL_VKBRIDGE_WEBHELPER_ARGS:-}" ]; then
|
||||
printf '%s\n' "$BL_VKBRIDGE_WEBHELPER_ARGS"
|
||||
elif [ -z "${BL_VKBRIDGE_CEF_ANGLE:-}" ]; then
|
||||
echo stock
|
||||
elif [ "$BL_VKBRIDGE_CEF_ANGLE" = vulkan ] && [ "${BL_VKBRIDGE_CEF_VULKAN:-1}" != 0 ]; then
|
||||
echo "--use-gl=angle --use-angle=vulkan +Vulkan +VulkanFromANGLE +DefaultANGLEVulkan"
|
||||
else
|
||||
echo "--use-gl=angle --use-angle=$BL_VKBRIDGE_CEF_ANGLE"
|
||||
fi
|
||||
}
|
||||
bl_now_ms() {
|
||||
if [ -n "${EPOCHREALTIME:-}" ]; then
|
||||
local t=${EPOCHREALTIME/[.,]/}
|
||||
echo $((10#$t / 1000))
|
||||
else
|
||||
date +%s%3N
|
||||
fi
|
||||
}
|
||||
vkbridge_wait_socket() {
|
||||
local sock=$1 limit=${2:-10000} start now waited
|
||||
[ -n "$sock" ] || return 1
|
||||
if [ -S "$sock" ]; then
|
||||
echo "== vkbridge: server socket ready (waited 0 ms)"
|
||||
return 0
|
||||
fi
|
||||
start=$(bl_now_ms)
|
||||
while :; do
|
||||
now=$(bl_now_ms)
|
||||
waited=$((now - start))
|
||||
if [ -S "$sock" ]; then
|
||||
echo "== vkbridge: server socket ready (waited $waited ms; the server listens after its startup probe)"
|
||||
return 0
|
||||
fi
|
||||
if [ -n "${bl_stopping:-}" ]; then
|
||||
echo "== vkbridge: no server socket after $waited ms; the session is stopping"
|
||||
return 1
|
||||
fi
|
||||
if [ "$waited" -ge "$limit" ]; then
|
||||
echo "== vkbridge: no server socket after $waited ms (gave up at $limit ms)"
|
||||
return 1
|
||||
fi
|
||||
sleep 0.05
|
||||
done
|
||||
}
|
||||
if [ "${BL_VKBRIDGE:-0}" = 1 ]; then
|
||||
bl_vkb_icd=/usr/local/share/vkbridge/droidbridge_icd.json
|
||||
[ -z "${BL_INSIDE:-}" ] && vkbridge_wait_socket "${VKBRIDGE_SOCKET:-}" "${BL_VKBRIDGE_WAIT_MS:-10000}"
|
||||
bl_vkb_missing=
|
||||
[ -r "$bl_vkb_icd" ] || bl_vkb_missing="$bl_vkb_missing icd"
|
||||
[ -r /usr/local/lib/vkbridge/libvulkan_droidbridge.so ] || bl_vkb_missing="$bl_vkb_missing library"
|
||||
[ -S "${VKBRIDGE_SOCKET:-}" ] || bl_vkb_missing="$bl_vkb_missing socket"
|
||||
if [ -z "$bl_vkb_missing" ]; then
|
||||
export VK_DRIVER_FILES=$bl_vkb_icd VK_ICD_FILENAMES=$bl_vkb_icd
|
||||
export VKBRIDGE_SOCKET VKBRIDGE_CLIENT_LOG
|
||||
if [ -r /root/.vkbridge-env ]; then
|
||||
while IFS='=' read -r _k _v; do
|
||||
case "$_k" in VKBRIDGE_*|BL_VKBRIDGE_*) export "$_k=$_v" ;; esac
|
||||
done < /root/.vkbridge-env
|
||||
[ -z "${BL_INSIDE:-}" ] && echo "== vkbridge: development settings from /root/.vkbridge-env: $(cut -d= -f1 /root/.vkbridge-env | tr '\n' ' ')"
|
||||
fi
|
||||
export VKD3D_FEATURE_LEVEL=${VKD3D_FEATURE_LEVEL:-12_0}
|
||||
unset TU_DEBUG
|
||||
if [ -z "${BL_INSIDE:-}" ]; then
|
||||
step "vkbridge self-test"
|
||||
timeout 60 /usr/local/bin/droiddeck-vkbridge-smoke 2>&1 | sed 's/^/== vkbridge: /'
|
||||
if command -v vulkaninfo >/dev/null 2>&1; then
|
||||
timeout 30 vulkaninfo --summary 2>&1 | sed -n '/^Devices:/,$p' | head -40 | sed 's/^/== vulkaninfo: /'
|
||||
fi
|
||||
fi
|
||||
echo "== vulkan driver: Mali bridge ($bl_vkb_icd, server at $VKBRIDGE_SOCKET)"
|
||||
else
|
||||
echo "== vulkan driver: Mali bridge requested but NOT usable (icd $bl_vkb_icd, socket ${VKBRIDGE_SOCKET:-unset}; missing:$bl_vkb_missing)"
|
||||
[ -n "${BL_INSIDE:-}" ] || exit 69
|
||||
fi
|
||||
unset bl_vkb_icd bl_vkb_missing
|
||||
fi
|
||||
export GAMESCOPE_FORCE_VULKAN_REALTIME=${BL_GAMESCOPE_REALTIME:-0}
|
||||
|
||||
start_agent() {
|
||||
@@ -307,6 +384,13 @@ if [ -z "${BL_INSIDE:-}" ]; then
|
||||
if [ "$mode" = steam ] && [ "${BL_CURSOR_COMPOSITE:-0}" = 1 ]; then
|
||||
export gamescope_cursor_composite=2
|
||||
fi
|
||||
# Through the Mali bridge, Steam's UI flickered while gamescope handed its layers to the phone's
|
||||
# compositor as separate planes, for a reason not yet found; one composited image does not
|
||||
# (Mali-G76 MC4: 145 footer flips in 6 s at rest, 0 composited).
|
||||
if [ "$mode" = steam ] && [ "${BL_VKBRIDGE:-0}" = 1 ] && [ -z "${gamescope_composite_force:-}" ]; then
|
||||
export gamescope_composite_force=1
|
||||
echo "== gamescope: composites every frame (Mali bridge: the Steam UI flickers on separate planes)"
|
||||
fi
|
||||
args=(--backend wayland --expose-wayland -f -W "$width" -H "$height" -w "$nested" -h "$nested_h")
|
||||
if [ "$nested" != "$width" ] || [ "$nested_h" != "$height" ]; then
|
||||
args+=(-S stretch)
|
||||
@@ -1023,6 +1107,28 @@ case $mode in
|
||||
_bl_cef=(-cef-disable-gpu)
|
||||
_bl_ui=(-nobigpicture)
|
||||
fi
|
||||
if [ "${BL_VKBRIDGE:-0}" = 1 ]; then
|
||||
# On the GPU the Steam UI held about 400 MB through the bridge (Mali-G76 MC4, 3 GB of RAM); with
|
||||
# a game loading beside it, Android's low-memory killer took the whole session down.
|
||||
if [ -z "${BL_VKBRIDGE_CEF_GPU:-}" ]; then
|
||||
_bl_mem_kb=$(awk '/^MemTotal:/ {print $2}' /proc/meminfo 2>/dev/null)
|
||||
if [ "${_bl_mem_kb:-0}" -gt 0 ] && [ "$_bl_mem_kb" -lt 4194304 ]; then
|
||||
BL_VKBRIDGE_CEF_GPU=0
|
||||
echo "== steam: $((_bl_mem_kb / 1024)) MB of RAM: the browser UI draws in software to leave games the memory"
|
||||
fi
|
||||
fi
|
||||
if [ "${BL_VKBRIDGE_CEF_GPU:-1}" = 0 ]; then
|
||||
_bl_cef=(-cef-disable-gpu -cef-disable-gpu-compositing)
|
||||
echo "== steam: browser UI in software (Mali bridge)"
|
||||
elif [ "${_bl_cef[0]}" = -cef-force-gpu ]; then
|
||||
_bl_cef=(-cef-force-gpu -cef-use-gl=angle -cef-use-angle="${BL_VKBRIDGE_CEF_ANGLE:-vulkan}")
|
||||
fi
|
||||
[ "${BL_VKBRIDGE_CEF_LOG:-0}" = 1 ] && _bl_cef+=(-cef-enable-logging=stderr -cef-v=1)
|
||||
[ -n "${BL_VKBRIDGE_CEF_EXTRA:-}" ] && read -r -a _bl_cef_extra <<<"$BL_VKBRIDGE_CEF_EXTRA" && _bl_cef+=("${_bl_cef_extra[@]}")
|
||||
BL_WEBHELPER_ARGS=$(bl_webhelper_layout)
|
||||
export BL_WEBHELPER_ARGS
|
||||
echo "== steam: web helper process layout: $BL_WEBHELPER_ARGS (Mali bridge)"
|
||||
fi
|
||||
if [ "${BL_STEAM_UI:-}" != desktop ]; then
|
||||
if [ "$steam_x64" = 0 ] || [ "${BL_X64_DECK:-1}" != 0 ]; then
|
||||
_bl_ui+=(-steamdeck -steamos3)
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <pthread.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/syscall.h>
|
||||
@@ -34,7 +35,8 @@ static int is_kgsl(int fd) {
|
||||
struct stat st;
|
||||
pthread_mutex_lock(&lock);
|
||||
if (kgsl_state == 0) {
|
||||
kgsl_state = stat("/dev/kgsl-3d0", &st) == 0 ? 1 : -1;
|
||||
const char *standin = getenv("BL_DRM_STANDIN");
|
||||
kgsl_state = stat("/dev/kgsl-3d0", &st) == 0 || (standin && *standin && stat(standin, &st) == 0) ? 1 : -1;
|
||||
kgsl_dev = st.st_rdev;
|
||||
}
|
||||
pthread_mutex_unlock(&lock);
|
||||
@@ -49,18 +51,42 @@ static void *real(const char *name) {
|
||||
return fn;
|
||||
}
|
||||
|
||||
static int same_by_flock(int a, int b) {
|
||||
struct stat sa, sb;
|
||||
if (fstat(a, &sa) || fstat(b, &sb) || sa.st_dev != sb.st_dev || sa.st_ino != sb.st_ino ||
|
||||
flock(a, LOCK_EX | LOCK_NB)) {
|
||||
return 0;
|
||||
}
|
||||
int same = flock(b, LOCK_EX | LOCK_NB) == 0;
|
||||
flock(a, LOCK_UN);
|
||||
return same;
|
||||
}
|
||||
|
||||
static int same_file_description(int a, int b) {
|
||||
if (a == b) {
|
||||
return 1;
|
||||
}
|
||||
#ifdef SYS_kcmp
|
||||
int saved_errno = errno;
|
||||
long ret = syscall(SYS_kcmp, getpid(), getpid(), 0 , a, b);
|
||||
errno = saved_errno;
|
||||
return ret == 0;
|
||||
#else
|
||||
return 0;
|
||||
int ret = -1;
|
||||
#ifdef SYS_kcmp
|
||||
static int kcmp_missing;
|
||||
if (!kcmp_missing) {
|
||||
long k = syscall(SYS_kcmp, getpid(), getpid(), 0, a, b);
|
||||
if (k >= 0) {
|
||||
ret = k == 0;
|
||||
} else if (errno == ENOSYS || errno == EPERM) {
|
||||
kcmp_missing = 1;
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (ret < 0) {
|
||||
const char *standin = getenv("BL_DRM_STANDIN");
|
||||
ret = standin && *standin ? same_by_flock(a, b) : 0;
|
||||
}
|
||||
errno = saved_errno;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int find_handle_locked(int fd, uint32_t handle) {
|
||||
|
||||
Reference in new issue
Block a user