关于Bottles中同一容器内不同应用需要配置不同显卡方案的解决办法
关于Bottles中同一容器内不同应用需要配置不同显卡方案的解决办法
这两天折腾Bottles时遇到了挺奇怪的事。
昨天下载的MC《落幕曲》整合包,在Linux发行版上运行的话,由于YSM不支持Linux,所以需要将这个模组换成旧版本,结果虽然能够运行了,但挺多动作都加载不出来,比如什么枪啊、拔刀剑啊,动作模组都没有...于是乎就尝试通过wine(Bottles)来运行,结果还真不错,性能也差不多,但有一点:运行时需要在关闭独立显卡,当然这个关闭也只是在Bottles设置一下,而且实际运行时似乎也并不会影响独显渲染🤔。
然后就是今天,今天又闲得试着在Bottles容器里装一个Epic,但不出所料的也出现问题,先是把那些dotnet48、ie、d3dcompiler、vcredist2019依赖都下好后,试着发现必须在Bottles设置里开启显卡才能运行😦,然而上面那个MC却需要关闭独立显卡,而这两个又都在同一个容器Game
内,那这我总不能每次启动都进Bottles改下显卡设置才能跑吧,而且万一哪天忘了这茬那岂不是又要一顿折腾(
于是乎,我就在想如何才能做到动态切换,先是问ChatGPT,它说可以设置为关闭独显,然后为Epic的启动参数加上环境变量,比如这些:
__NV_PRIME_RENDER_OFFLOAD=1
__GLX_VENDOR_LIBRARY_NAME=nvidia
然而经过测试,不管是在命令行执行__NV_PRIME_RENDER_OFFLOAD=1 __GLX_VENDOR_LIBRARY_NAME=nvidia -cli run -p EpicGamesLauncher -b 'Game'
还是在GUI界面加上同样的环境变量参数,都不行😅
于是我就在翻它的配置文件——毕竟它这能够通过设置来调整是否使用独立显卡,每个容器的配置又都独立,那肯定是有配置文件在生效的,结果还真在文件中找到了,在~/.local/share/bottles/bottles/Game/bottle.yml
内的Parameter部分中,存在discrete_gpu
字段,那就试着改一下,true
改成false
,《落幕曲》能进了,Epic进不去;false
改成true
,Epic能进,《落幕曲》进不了。不过这种情况也只适用于通过终端运行以及通过desktop快捷方式运行了,Bottles的GUI界面运行应用倒是不受影响,猜测它应该先是读取了一份配置,然后每次修改就写入到配置文件中,但在Bottles运行时,如果配置文件通过别的方式修改却不会被Bottles再次读取。
那既然这样的话就好办了,于是就让ChatGPT写了两个脚本。
第一个脚本bottles-gpu-switch
:用于借助sed
命令,修改discrete_gpu
字段,可传入两个参数:bottles名称、显卡状态(可为nvidia或者intel),当然路径都是默认Bottles路径,如有需要可以自行更改。内容如下:
#!/bin/bash
if [ $# -ne 2 ]; then
echo "用法: $0 [bottle_name] [nvidia|intel]"
exit 1
fi
BOTTLE="$1"
YML="$HOME/.local/share/bottles/bottles/$BOTTLE/bottle.yml"
if [ ! -f "$YML" ]; then
echo "错误:找不到 bottle 配置文件:$YML"
exit 2
fi
case "$2" in
nvidia)
sed -i 's/^\(\s*discrete_gpu:\s*\).*/\1true/' "$YML"
;;
intel)
sed -i 's/^\(\s*discrete_gpu:\s*\).*/\1false/' "$YML"
;;
*)
echo "用法: $0 [bottle_name] [nvidia|intel]"
exit 3
;;
esac
第二个脚本bottles-desktop-patch
:也是借助sed
命令,修改.desktop
文件中[Desktop Entry]
部分的Exec
行内容,改成这种格式:Exec=bash -c "bottles-gpu-switch Game intel ; bottles-cli run -p HMCL-3.6.15.287 -b 'Game' -- %u"
,也是需要传递两个参数:需要修改的.desktop
文件,显卡状态(nvidia或者intel,有需要可以自行更改)。内容如下:
#!/bin/bash
# 参数校验
if [ $# -ne 2 ]; then
echo "用法: $0 [desktop文件路径] [nvidia|intel]"
exit 1
fi
DESKTOP_FILE="$1"
GPU_MODE="$2"
if [ ! -f "$DESKTOP_FILE" ]; then
echo "错误:找不到文件 $DESKTOP_FILE"
exit 2
fi
if [[ "$GPU_MODE" != "nvidia" && "$GPU_MODE" != "intel" ]]; then
echo "错误:GPU 模式必须是 'nvidia' 或 'intel'"
exit 3
fi
# 提取旧 Exec 行,只拿等号右边内容(命令部分)
OLD_EXEC_LINE=$(awk '/^\[Desktop Entry\]/ {in_entry=1}
/^\[.*\]/ && $0 != "[Desktop Entry]" {in_entry=0}
in_entry && /^Exec=/ {
sub(/^Exec=/, "", $0);
print;
exit;
}' "$DESKTOP_FILE")
# 从中提取 Bottle 名
BOTTLE_NAME=$(echo "$OLD_EXEC_LINE" | sed -n "s/.*-b[ =']\{1,\}\([^'\" ]\+\).*/\1/p")
if [ -z "$BOTTLE_NAME" ]; then
echo "无法从 Exec 行中提取 bottle 名,请检查原始 desktop 文件"
exit 4
fi
# 构造新的 Exec 行
NEW_EXEC="Exec=bash -c \"bottles-gpu-switch $BOTTLE_NAME $GPU_MODE ; $OLD_EXEC_LINE\""
# 替换 Exec 行,只在 [Desktop Entry] 部分替换
awk -v new_exec="$NEW_EXEC" '
BEGIN { in_desktop_entry = 0 }
/^\[Desktop Entry\]/ { in_desktop_entry = 1 }
/^\[.*\]/ && $0 != "[Desktop Entry]" { in_desktop_entry = 0 }
in_desktop_entry && /^Exec=/ {
print new_exec
next
}
{ print }
' "$DESKTOP_FILE" > "${DESKTOP_FILE}.patched" && mv "${DESKTOP_FILE}.patched" "$DESKTOP_FILE"
echo "✔ 已更新 Exec 行:"
echo "$NEW_EXEC"
运行效果:
最后还是再说明一下:这种方式只是修改了通过.desktop
运行Bottles应用时的独立显卡使用情况,如果是通过Bottles的GUI界面运行,仍然能够在设置界面进行调整。