版本比较

密钥

  • 该行被添加。
  • 该行被删除。
  • 格式已经改变。

...

...

背景

自从原神 4.3版本在2023年12月20日左右升级之后,对于amd gpu并没有专门的支持,amd gpu 运行时会崩溃在libgallium库(mesa提出的全新的3D引擎框架)中。

...


解决过程

查看waydroid上的issue,可以看到有很多大神尝试了不同的原神版本,都会崩溃。https://github.com/waydroid/waydroid/issues/1206

...

代码块
openfde/out/target/product/fde_arm64/symbols/vendor/lib64/dri$ addr2line  000000000099e844 -e  libgallium_dri.so 
openfde/external/mesa/src/mesa/main/texobj.c:639620
#打开该文件看到:
 609 /**
 610  * Reference (or unreference) a texture object.
 611  * If '*ptr', decrement *ptr's refcount (and delete if it becomes zero).
 612  * If 'tex' is non-null, increment its refcount.
 613  * This is normally only called from the _mesa_reference_texobj() macro
 614  * when there's a real pointer change.
 615  */
 616 void
 617 _mesa_reference_texobj_(struct gl_texture_object **ptr,
 618                         struct gl_texture_object *tex)
 619 {
 620    assert(ptr);
 621 
 622    if (*ptr) {
 623       /* Unreference the old texture */
 624       struct gl_texture_object *oldTex = *ptr;
 625 
 626       assert(valid_texture_object(oldTex));
 627       (void) valid_texture_object; /* silence warning in release builds */
 628 
 629       assert(oldTex->RefCount > 0);
 630 
 631       if (p_atomic_dec_zero(&oldTex->RefCount)) {

看倒620行是assert(ptr)。这是一个断言,说明ptr是不合法的指针。针对这个crash找不到更多线索。想着打开mesa的调试开关试试能不能找到其他有用的信息,打开调试开关,重新编译mesa,运行发现崩溃的地方变了,崩溃在external/mesa/src/mesa/main/uniforms.c的断言上,assert(unit < ARRAY_SIZE(prog->TexturesUsed)),发现ARRAY_SIZE(prog->TexturesUsed)为192,unit是由调用者设置,所以修改了设置的逻辑。

我们将这个问题反馈到mesa官方后(https://gitlab.freedesktop.org/mesa/mesa/-/issues/11148#note_2410145 ),得到了一个修复。原神在amdgpu崩溃修复。但是修复崩溃后,还存在丢失纹理的问题(就是游戏中外景变成一些方方正正的盒子)。

解决方法

这个问题通过启用mesa 的xmlconfig 功能来兼容运行。这个功能的原理是,针对指定的程序名,使用xmlconfig记录的特性值返回给调用者。修复纹理丢失的问题是使用另外一款gpu的名称代替amd gpu来返回给原神。https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6697

代码块
util/xmlconfig: Use a non-xml-string encoding of driver options for Android.
    
    On Android, we don't have user-defined drircs to parse, or even the
    Mesa-defined drirc.  We don't need the option descriptions, or the ranges
    for values, either.  Just "this driver has an option of this name and type
    and this default value" so that the rest of Mesa internals can interact
    with driconf options like normal.  Nothing outside of mesa on android uses
    the entrypoints to get the XML.
    
    AOSP really doesn't want to carry around a 150k XML parsing library for an
    actually unused feature.
    
    We can drop that dependency by making a trivial string encoding (so we can
    reuse the rest of the Mesa plumbing) that we parse directly to values at
    screen init time.

这个文件存在于wendor镜像的etc/drirc.d/00-mesa-defaults.conf 为192,该值超过了最大下标,导致下标越界。

打开调试开关的具体位置修改如下:

代码块
diff --git a/src/compiler/nir/meson.build b/src/compiler/nir/meson.build
index 5ce85780cca..559ceb3aab4 100644
--- a/src/compiler/nir/meson.build
+++ b/src/compiler/nir/meson.build
@@ -322,7 +322,7 @@ _libnir = static_library(
    nir_opcodes_h, nir_constant_expressions_c, nir_builder_opcodes_h,
    nir_intrinsics_c, nir_intrinsics_h, nir_intrinsics_indices_h],
   include_directories : [inc_include, inc_src],
-  c_args : [c_msvc_compat_args, no_override_init_args, no_misleading_indentation],
+  c_args : [c_msvc_compat_args, no_override_init_args, no_misleading_indentation, '-UNDEBUG'],
   gnu_symbol_visibility : 'hidden',
   dependencies : [idep_compiler, dep_valgrind],
   build_by_default : false,

diff --git a/src/gallium/auxiliary/meson.build b/src/gallium/auxiliary/meson.build
index 96b0272c69b..1e6fabf3d70 100644
--- a/src/gallium/auxiliary/meson.build
+++ b/src/gallium/auxiliary/meson.build
@@ -525,7 +525,7 @@ libgallium = static_library(
   include_directories : [
     inc_loader, inc_gallium, inc_src, inc_include, include_directories('util')
   ],
-  c_args : [c_msvc_compat_args, libgallium_extra_c_args],
+  c_args : [c_msvc_compat_args, libgallium_extra_c_args, '-DDEBUG'],
   cpp_args : [cpp_msvc_compat_args],
   gnu_symbol_visibility : 'hidden',
   dependencies : [

diff --git a/src/gallium/drivers/llvmpipe/meson.build b/src/gallium/drivers/llvmpipe/meson.build
index 38ff88980f9..12d51733c1f 100644
--- a/src/gallium/drivers/llvmpipe/meson.build
+++ b/src/gallium/drivers/llvmpipe/meson.build
@@ -115,7 +115,7 @@ files_llvmpipe = files(
 libllvmpipe = static_library(
   'llvmpipe',
   [files_llvmpipe, sha1_h],
-  c_args : [c_msvc_compat_args],
+  c_args : [c_msvc_compat_args, '-DDEBUG'],
   cpp_args : [cpp_msvc_compat_args],
   gnu_symbol_visibility : 'hidden',
   include_directories : [inc_gallium, inc_gallium_aux, inc_include, inc_src],

diff --git a/src/mesa/main/debug.c b/src/mesa/main/debug.c
index 43a68d130e1..b5cbc360863 100644
--- a/src/mesa/main/debug.c
+++ b/src/mesa/main/debug.c
@@ -22,6 +22,7 @@
  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  * OTHER DEALINGS IN THE SOFTWARE.
  */
+#define LOG_NDEBUG 0

 #include <stdio.h>
 #include "errors.h"
@@ -41,6 +42,7 @@

 #include "state_tracker/st_cb_texture.h"
 #include "state_tracker/st_cb_readpixels.h"
+#undef NDEBUG

 static const char *
 tex_target_name(GLenum tgt)

diff --git a/src/mesa/main/errors.c b/src/mesa/main/errors.c
index 70813744cd2..540a1d946f2 100644
--- a/src/mesa/main/errors.c
+++ b/src/mesa/main/errors.c
@@ -26,6 +26,7 @@
  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  * OTHER DEALINGS IN THE SOFTWARE.
  */
+#define LOG_NDEBUG 0


 #include <stdarg.h>
@@ -38,6 +39,8 @@
 #include "util/detect_os.h"
 #include "util/log.h"
 #include "api_exec_decl.h"
+#undef NDEBUG

 static void
 output_if_debug(enum mesa_log_level level, const char *outputString)

diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h
index 6eceae83a9c..b573d07995e 100644
--- a/src/mesa/main/mtypes.h
+++ b/src/mesa/main/mtypes.h
@@ -61,6 +61,7 @@
 #include "pipe/p_state.h"

 #include "frontend/api.h"
+#undef NDEBUG

 #ifdef __cplusplus
 extern "C" {

diff --git a/src/mesa/meson.build b/src/mesa/meson.build
index d07b8fb33a7..639a744d10a 100644
--- a/src/mesa/meson.build
+++ b/src/mesa/meson.build
@@ -470,7 +470,7 @@ endif
 libmesa = static_library(
   'mesa',
   files_libmesa,
-  c_args : [c_msvc_compat_args, _mesa_windows_args],
+  c_args : [c_msvc_compat_args, _mesa_windows_args, '-DDEBUG', '-UNDEBUG'],
   cpp_args : [cpp_msvc_compat_args, _mesa_windows_args],
   gnu_symbol_visibility : 'hidden',
   include_directories : [

diff --git a/src/mesa/vbo/vbo.h b/src/mesa/vbo/vbo.h
index f11824cdaa4..fbf5a5e9a15 100644
--- a/src/mesa/vbo/vbo.h
+++ b/src/mesa/vbo/vbo.h
@@ -38,6 +38,7 @@
 #include "main/macros.h"
 #include "vbo_attrib.h"
 #include "gallium/include/pipe/p_state.h"
+#undef NDEBUG

diff --git a/src/util/log.h b/src/util/log.h
index 17670cc97d9..2342970bf1f 100644
--- a/src/util/log.h
+++ b/src/util/log.h
@@ -32,6 +32,7 @@
 #ifdef __cplusplus
 extern "C" {
 #endif
+#define  DEBUG 1

我们将这个问题反馈到mesa官方后(https://gitlab.freedesktop.org/mesa/mesa/-/issues/11148#note_2410145 ),得到了一个修复(原神在amdgpu崩溃修复)。但是修复崩溃后,还存在丢失纹理的问题(就是游戏中变成一些方方正正的盒子)。如下图所示。

...

解决方法

针对这个问题YogSottot给了我们一个解决方案,就是启用mesa的xmlconfig,他的提议在此https://github.com/waydroid/waydroid/issues/1206#issuecomment-2132083401
这个功能的背景是一部分android游戏并不感知开源gpu驱动,当他们看到一款未知驱动时,通常会用最低性能去运行。所以,针对指定的游戏程序名,使用xmlconfig记录的特性值覆盖vendor或者renderer设置返回给游戏程序以获取更高的fps和更好的渲染。修复纹理丢失的问题是使用另外一款gpu的名称代替amd gpu来返回给原神。https://gitlab.freedesktop.org/mesa/mesa/-/commit/b9129496a295f3aef7d96540556eced25961f66a

代码块
freedreno: Unleash the dragon!


A number of android games are so far, sadly, unaware of open source
drivers.  And when they see an unknown driver they lump it in the lowest
performance tier, artificially limiting framerate and/or gfx settings.
So until the games catch up, use driconf to override vendor/renderer
settings for moar fps and nicer gfx.

Furthermore, some games seem to be limiting *too* conservatively when
we otherwise have plenty of headroom even if we claim to be a bigger
adreno.  Possibly a concession to battery life or tighter thermal
constraints in a phone, as compared to something like a chromebook.
Or maybe the flagship gaming phone thing is a scam ;-)

在openfde下的mesa为android启动xmlconfig的提交如下:https://github.com/openfde/waydroid_android_external_mesa3d/commit/bfb3deaf7fc215eac6f9aa31492425731ce78bad 在本提交中hardcode了dri配置文件夹的路径为/vendor/etc/drirc.d,并将00-mesa-default.conf添加了原神相关的兼容内容。

在关闭OpenFDE,登录linux系统的情况下可以手动挂载vendor镜像来查看:

代码块
#将vendor镜像挂载到/mnt目录。
sudo mount /usr/share/waydroid-extra/images/vendor.img /mnt
#打开xml配置文件
sudo vim /mnt/etc/drirc.d/00-mesa-defaults.conf 
910 <application name="Genshin Impact" executable="com.miHoYo.Yuanshen">
911            <option name="ignore_discard_framebuffer" value="true" />
912            <option name="force_gl_renderer" value="Adreno (TM) 630"/>
913           <option name="force_gl_vendor" value="Qualcomm"/>
914 </application>

esc #按下esc vim 退出到命令模式
:wq #输入:wq保存退出。
sudo umount /mnt #卸载镜像

需要注意的是这个兼容方案,有时候会造成原神整个画面显示红色问题。此时需要先注释或删除以上910~914行的内容。先让原神正常启动,进入画面(带纹理丢失的画面)。然后退出fde,再按上述步骤,添加好910~914的内容。再次进入fde,才能正常进入画面。

有兴趣的可以查看 https://github.com/openfde/openfde/issues/15#issuecomment-2116555506

...