qemuでVirGLのGLES3が使えないのを追う会
今回ビルドしたqemuで何故かGLES3が使えないので何とかしたい。
Mesaのバージョン検出ロジック
Mesaがadvertiseするバージョンは対応している拡張等で決定される。
/* FINISHME: This list isn't quite right. */
const bool ver_3_0 = (extensions->ARB_half_float_vertex &&
extensions->ARB_internalformat_query &&
extensions->ARB_map_buffer_range &&
extensions->ARB_shader_texture_lod &&
extensions->OES_texture_float &&
extensions->OES_texture_half_float &&
extensions->OES_texture_half_float_linear &&
extensions->ARB_texture_rg &&
extensions->ARB_depth_buffer_float &&
extensions->ARB_framebuffer_object &&
extensions->EXT_sRGB &&
extensions->EXT_packed_float &&
extensions->EXT_texture_array &&
extensions->EXT_texture_shared_exponent &&
extensions->EXT_texture_sRGB &&
extensions->EXT_transform_feedback &&
extensions->ARB_draw_instanced &&
extensions->ARB_instanced_arrays &&
extensions->ARB_uniform_buffer_object &&
extensions->EXT_texture_snorm &&
(extensions->NV_primitive_restart ||
consts->PrimitiveRestartFixedIndex) &&
extensions->OES_depth_texture_cube_map &&
extensions->EXT_texture_type_2_10_10_10_REV &&
consts->MaxColorAttachments >= 4);
このリストとゲスト側の eglinfo -p wayland
の出力をねっとり比較したところ、 ARB_uniform_buffer_object
が欠けていることがわかった。
VirGL rendererをデバッグビルドする
ブレークポイントを入れるためにデバッグビルドにする。
diff --git a/build.cmake b/build.cmake
index 9c62a83..f9a9798 100644
--- a/build.cmake
+++ b/build.cmake
@@ -35,7 +35,7 @@ endfunction()
function(build_meson projname adddef)
message(STATUS "Meson setup ${projname}")
- run_docker("PKG_CONFIG_PATH=c:/libs/lib/pkgconfig /ucrt64/bin/meson setup --prefix=c:/libs --buildtype=release -Ddefault_library=static ${adddef} c:/srcs/deps/${projname} c:/objs/${projname}")
+ run_docker("PKG_CONFIG_PATH=c:/libs/lib/pkgconfig /ucrt64/bin/meson setup --prefix=c:/libs -Ddefault_library=static ${adddef} c:/srcs/deps/${projname} c:/objs/${projname}")
message(STATUS "Meson compile ${projname}")
run_docker("/ucrt64/bin/meson compile -C c:/objs/${projname}")
run_docker("/ucrt64/bin/meson install -C c:/objs/${projname}")
@@ -44,11 +44,13 @@ endfunction()
file(MAKE_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/out)
# Deps
-build_meson(glib "")
-build_meson(pixman "")
-build_meson(libslirp "")
-build_meson(libepoxy "-Degl=yes")
-build_meson(virglrenderer "")
+set(type_debug "--buildtype=debug")
+set(type_release "--buildtype=release")
+build_meson(glib "${type_release}")
+build_meson(pixman "${type_release}")
+build_meson(libslirp "${type_release}")
+build_meson(libepoxy "-Degl=yes ${type_release}")
+build_meson(virglrenderer "${type_debug}")
# SDL2
message(STATUS "SDL2 configure")
Mesonに --buildtype=debug
を渡してビルドすれば良い。
assertに当たる
これはGLのエラークリア漏れなのでvirgl側のバグ。とりあえずassertだけコメントアウトしておく。assertの中には副作用のある式を入れてはいけない(これもバグ)。他の箇所ではちゃんと全てのパスで glGetError
しているので見落しだろう。
Assertion failed: glGetError() == GL_NO_ERROR && "Stale error state detected, please check for failures in initialization", file C:/srcs
/deps/virglrenderer/src/vrend_formats.c, line 716
(gdb) bt
#0 0x00007ffd839a286e in ucrtbase!abort () from /c/WINDOWS/System32/ucrtbase.dll
#1 0x00007ffd839a4140 in ucrtbase!_get_wpgmptr () from /c/WINDOWS/System32/ucrtbase.dll
#2 0x00007ffd839a4331 in ucrtbase!_assert () from /c/WINDOWS/System32/ucrtbase.dll
#3 0x00007ff71480ca32 in vrend_renderer_query_multisample_caps (max_samples=16, caps=0x665a448)
at C:/srcs/deps/virglrenderer/src/vrend_formats.c:716
#4 0x00007ff7147caf33 in vrend_renderer_fill_caps_v2 (gl_ver=0, gles_ver=31, caps=0x665a448)
at C:/srcs/deps/virglrenderer/src/vrend_renderer.c:12482
#5 0x00007ff7147cbff3 in vrend_renderer_fill_caps (set=2, version=0, caps=0x665a448)
at C:/srcs/deps/virglrenderer/src/vrend_renderer.c:12882
#6 0x00007ff71479c0b6 in virgl_renderer_fill_caps (set=2, version=0, caps=0x665a448)
at C:/srcs/deps/virglrenderer/src/virglrenderer.c:185
#7 0x00007ff71408c22c in virgl_cmd_get_capset (g=0x60daff0, cmd=0x53f38a0) at C:/srcs/qemu/hw/display/virtio-gpu-virgl.c:654
#8 virtio_gpu_virgl_process_cmd (g=0x60daff0, cmd=0x53f38a0) at C:/srcs/qemu/hw/display/virtio-gpu-virgl.c:931
#9 0x00007ff714089c19 in virtio_gpu_process_cmdq (g=g@entry=0x60daff0) at C:/srcs/qemu/hw/display/virtio-gpu.c:1048
#10 0x00007ff71408a84a in virtio_gpu_gl_handle_ctrl (vdev=<optimized out>, vq=0x6355390) at C:/srcs/qemu/hw/display/virtio-gpu-gl.c:100
#11 0x00007ff7143aa9c1 in aio_bh_call (bh=bh@entry=0x637d510) at C:/srcs/qemu/util/async.c:172
#12 0x00007ff7143aab72 in aio_bh_poll (ctx=ctx@entry=0x7c8c40) at C:/srcs/qemu/util/async.c:219
#13 0x00007ff7143971e0 in aio_dispatch (ctx=0x7c8c40) at C:/srcs/qemu/util/aio-win32.c:317
#14 0x00007ff7143aa7be in aio_ctx_dispatch (source=<optimized out>, callback=<optimized out>, user_data=<optimized out>)
at C:/srcs/qemu/util/async.c:361
#15 0x00007ff714707819 in g_main_dispatch ()
#16 0x00007ff71470b358 in g_main_context_dispatch ()
#17 0x00007ff7143abf10 in os_host_main_loop_wait (timeout=<optimized out>) at C:/srcs/qemu/util/main-loop.c:538
#18 0x00007ff7143ac486 in main_loop_wait (nonblocking=nonblocking@entry=0) at C:/srcs/qemu/util/main-loop.c:589
#19 0x00007ff71402ae1c in qemu_main_loop () at C:/srcs/qemu/system/runstate.c:835
#20 0x00007ff7142f39aa in qemu_default_main () at C:/srcs/qemu/system/main.c:37
#21 0x00007ff7145c0496 in main_getcmdline () at C:/srcs/deps/SDL2/src/main/windows/SDL_windows_main.c:80
#22 0x00007ff7145c0505 in WinMain (hInst=<optimized out>, hPrev=hPrev@entry=0x0, szCmdLine=<optimized out>, sw=<optimized out>)
at C:/srcs/deps/SDL2/src/main/windows/SDL_windows_main.c:109
#23 0x00007ff71484bb19 in main (argc=<optimized out>, argv=<optimized out>, envp=<optimized out>)
at C:/M/B/src/mingw-w64/mingw-w64-crt/crt/crtexewin.c:67
#24 0x00007ff713e11319 in __tmainCRTStartup () at C:/M/B/src/mingw-w64/mingw-w64-crt/crt/crtexe.c:266
#25 0x00007ff713e11426 in mainCRTStartup () at C:/M/B/src/mingw-w64/mingw-w64-crt/crt/crtexe.c:186
ホスト側でUBOが有効になっているのを確認する
デバッグフラグを立てて実行する。
$ export VREND_DEBUG=all
gl_version 31 - es profile enabled
HOST: Host feature arb_or_gles_ext_texture_buffer provide by GL_EXT_texture_buffer
HOST: Host feature arrays_of_arrays provided by GLES 3.1
HOST: Host feature atomic_counters provided by GLES 3.1
HOST: Host feature barrier provided by GLES 3.1
HOST: Host feature clip_control provide by GL_EXT_clip_control
HOST: Host feature compute_shader provided by GLES 3.1
HOST: Host feature conservative_depth provide by GL_EXT_conservative_depth
HOST: Host feature cull_distance provide by GL_EXT_clip_cull_distance
HOST: Host feature depth_clamp provide by GL_EXT_depth_clamp
HOST: Host feature draw_instance provided by GLES 3.1
HOST: Host feature dual_src_blend provide by GL_EXT_blend_func_extended
HOST: Host feature egl_image provide by GL_OES_EGL_image
HOST: Host feature fb_no_attach provided by GLES 3.1
HOST: Host feature gl_prim_restart provided by GLES 3.1
HOST: Host feature gles_khr_robustness provide by GL_KHR_robustness
HOST: Host feature gles31_compatibility provided by GLES 3.1
HOST: Host feature gles31_vertex_attrib_binding provided by GLES 3.1
HOST: Host feature images provided by GLES 3.1
HOST: Host feature indep_blend provide by GL_OES_draw_buffers_indexed
HOST: Host feature indep_blend_func provide by GL_OES_draw_buffers_indexed
HOST: Host feature indirect_draw provided by GLES 3.1
HOST: Host feature khr_debug provide by GL_KHR_debug
HOST: Host feature multisample provided by GLES 3.1
HOST: Host feature shader_noperspective_interpolation provide by GL_NV_shader_noperspective_interpolation
HOST: Host feature polygon_offset_clamp provide by GL_EXT_polygon_offset_clamp
HOST: Host feature occlusion_query_boolean provided by GLES 3.1
HOST: Host feature sample_mask provided by GLES 3.1
HOST: Host feature samplers provided by GLES 3.1
HOST: Host feature sampler_border_colors provide by GL_EXT_texture_border_clamp
HOST: Host feature separate_shader_objects provided by GLES 3.1
HOST: Host feature ssbo provided by GLES 3.1
HOST: Host feature ssbo_barrier provided by GLES 3.1
HOST: Host feature stencil_texturing provided by GLES 3.1
HOST: Host feature storage_multisample provided by GLES 3.1
HOST: Host feature texture_array provided by GLES 3.1
HOST: Host feature texture_gather provided by GLES 3.1
HOST: Host feature texture_mirror_clamp_to_edge provide by GL_EXT_texture_mirror_clamp_to_edge
HOST: Host feature texture_multisample provided by GLES 3.1
HOST: Host feature texture_storage provided by GLES 3.1
HOST: Host feature timer_query provide by GL_EXT_disjoint_timer_query
HOST: Host feature transform_feedback provided by GLES 3.1
HOST: Host feature transform_feedback2 provided by GLES 3.1
HOST: Host feature ubo provided by GLES 3.1
HOST: Host feature implicit_msaa provide by GL_EXT_multisampled_render_to_texture
HOST: Host feature anisotropic_filter provide by GL_EXT_texture_filter_anisotropic
capsの中にはちゃんと ubo
が有ることを確認できる。
ゲスト側でUBOが有効になる条件を確認する
MesaはUBOが有効になる条件をいくつか設定している。 https://gitlab.freedesktop.org/mesa/mesa/-/blob/c21bc65ba7525b2d0f66e26d565437833506845d/src/mesa/state_tracker/st_extensions.c
if (c->MaxUniformBlockSize < 16384) {
can_ubo = false;
}
これはOK。ブレークポイントを入れて確認した。 MaxUniformBlockSize
= 65536。
Thread 1 hit Breakpoint 1, vrend_renderer_fill_caps_v2 (gl_ver=0, gles_ver=31, caps=0x6270e88)
at C:/srcs/deps/virglrenderer/src/vrend_renderer.c:12774
(gdb) p max
$1 = 65536
if (pc->MaxInstructions &&
(options->EmitNoIndirectUniform || pc->MaxUniformBlocks < 12)) {
can_ubo = false;
}
こっちがダメだった。12ピッタリしかない。(規格最小は MAX_COMBINED_UNIFORM_BLOCKS
= 24 なのでギリギリということになる。)
(gdb) p caps.v1.max_uniform_blocks
$6 = 12
12なら良いじゃんという感じだが、実際にはMesaは1つを通常のUniform用に消費してしまうため同じ st_extensions.c
内部で1減算されている。
pc->MaxUniformBlocks =
screen->get_shader_param(screen, sh,
PIPE_SHADER_CAP_MAX_CONST_BUFFERS);
if (pc->MaxUniformBlocks)
pc->MaxUniformBlocks -= 1; /* The first one is for ordinary uniforms. */
pc->MaxUniformBlocks = _min(pc->MaxUniformBlocks, MAX_UNIFORM_BUFFERS);
無理矢理増やしてみる
diff --git a/src/vrend_renderer.c b/src/vrend_renderer.c
index 862e9c98..5e1c2a75 100644
--- a/src/vrend_renderer.c
+++ b/src/vrend_renderer.c
@@ -12192,7 +12192,7 @@ static void vrend_renderer_fill_caps_v1(int gl_ver, int gles_ver, union virgl_ca
glGetIntegerv(GL_MAX_VERTEX_UNIFORM_BLOCKS, &max);
/* GL_MAX_VERTEX_UNIFORM_BLOCKS is omitting the ordinary uniform block, add it
* also reduce by 1 as we might generate a VirglBlock helper uniform block */
- caps->v1.max_uniform_blocks = max + 1 - 1;
+ caps->v1.max_uniform_blocks = 13;
}
if (has_feature(feat_depth_clamp))
これでちゃんとGLES3.1になったが、ゲスト側でTerminalアプリを起動すると異常に複雑なシェーダをコンパイルしようとしてハング状態になってしまった。FirefoxのWebGL2とかは正常に動作するようなので、ANGLE(が使っているDirectXのHLSLコンパイラ)側の問題の可能性が高い。
OpenGL ES profile vendor: Mesa
OpenGL ES profile renderer: virgl (ANGLE (Intel, Intel(R) HD Graphics 530 (0x00001912) ...)
OpenGL ES profile version: OpenGL ES 3.1 Mesa 24.3.2
OpenGL ES profile shading language version: OpenGL ES GLSL ES 3.10