微软最近为WSLg提供了基于D3D12的GPU视频处理和编解码加速!官方在这篇博客给出了相关教程。已经迫不及待想要尝试了!

项目介绍

在build 2020微软就宣布为WSL2带来GPU硬件加速,在Linux中实现了完整的D3D12 API,并且简化DXGI为DXCORE,使得UMD和KMD可以交互。这里有更详细的介绍,我们以后再研究。WSLg中的硬件加速首先被用于3D渲染和计算,而现在又应用在视频处理。微软为Mesa添加了D3D12后端,使用VAAPI作为前端。理论上使用VAAPI的app都可以在WSLg中享受到硬件加速(FFMPEG/gstreamer狂喜)。

如何使用

硬件要求

没有找到官方的说明。参考博客里给的表格。

  • Intel: TGL,RKL,ADL,RPL,DG1,DG2
  • AMD: RX 5000+,Ryzen 4000+
  • Nvidia: GTX10,GTX20,Quadro RTX,RTX

需要的环境

  1. WSL 1.1.0+。该版本在本文截稿时还是pre-realse的状态,因此需要安装WSL preview,而WSL preview又需要preview的Windows,我不得不加入了已经退出很多年的Windows Insider,再次成为微软的小白鼠。我选择的是相对稳定的Beta通道。
  2. 安装一个Linux发行版,比如ubuntu 22.04 LTS。我使用的是已经安装的Ubuntu 20.04.
  3. 在WSL中开启systemd。官方也给出了教程

相关依赖

接下来需要安装Mesa,并且需要Mesa 22.2.0+。先查看当前使用的发行版提供的最新的Mesa版本。

sudo apt-get update
apt list mesa-va-drivers -a
Listing... Done

对应输出:

Listing... Done
mesa-va-drivers/focal-updates,focal-security,now 21.2.6-0ubuntu0.1~20.04.2 amd64 [installed]
mesa-va-drivers/focal 20.0.4-2ubuntu1 amd64

emm,只支持到Mesa 21.2.6。看来我们要自己编译Mesa了。注意,Ubuntu 22.04以上可以选择第三方编译好的Mesa:

sudo add-apt-repository ppa:oibaf/graphics-drivers
sudo apt-get update && sudo apt-get upgrade
sudo apt-get mesa-va-drivers

如果是Ubuntu 20.04,我们只能自己编译Mesa,先下载源码并解压(建议使用代理):

wget https://archive.mesa3d.org/mesa-22.3.0.tar.xz
tar -xvf mesa-22.3.0.tar.xz

然后编译Mesa:

sudo apt install meson
meson build -Dgallium-drivers=swrast,d3d12 -Dgallium-va=true -Dvideo-codecs=h264dec,h264enc,h265dec,h265enc,vc1dec

遇到开门错:

Dependency DirectX-Headers from subproject subprojects/DirectX-Headers found: YES 1.606.4
Run-time dependency vdpau found: NO (tried pkgconfig and cmake)
Program glslangValidator found: NO

meson.build:693:2: ERROR: Program(s) ['glslangValidator'] not found or not executable

看来还有依赖不全。直接然后再次meson build:

sudo apt-get install glslang-tools

啊啊啊又有新的错:

meson.build:804:2: ERROR: Dependency "libva" not found, tried pkgconfig and cmake

这个我熟,libva没装:

sudo apt install libva-dev

再次报错。hhh对libva版本还有要求:

meson.build:804:2: ERROR: Invalid version of dependency, need 'libva' ['>= 1.8.0'] found '1.7.0'.

受不了了,直接编一个libva吧:

sudo apt install autoconf libtool
git clone https://github.com/intel/libva.git
cd libva & ./autogen.sh --prefix=/usr --libdir=/usr/lib/x86_64-linux-gnu
make & sudo make install

然而vainfo还是报了链接错误:

vainfo: symbol lookup error: /lib/x86_64-linux-gnu/libva-x11.so.2: undefined symbol: va_fool_postp

va_fool_postp在libva 2.15就已经被remove了,我们把libva reset到2.15重新编译安装就好。这里我还遇到了多个版本的libva.so安装在/lib/x86_64-linux-gnu/下,建议直接(不要怕):

rm -rf /lib/x86_64-linux-gnu/libva.so*

然后再安装libva。接下来再尝试编译Mesa,错误依旧没完:

meson.build:999:2: ERROR: Problem encountered: Python (3.x) mako module >= 0.8.0 required to build mesa.

python的依赖不全。直接进行一个安装:

sudo apt install python3-pip
pip3 install mako

这下Mesa可以build了吧?哈哈哈并不可以:

meson.build:1700:4: ERROR: Invalid version of dependency, need 'libdrm_amdgpu' ['>=2.4.110'] found '2.4.107'.

行,那我们还是自己编一个libdrm:

git clone https://gitlab.freedesktop.org/mesa/drm.git
cd drm & meson build
ninja build && sudo ninja -C build install

然后build Mesa又双叒叕报错了:

meson.build:1794:2: ERROR: Subproject directory not found and llvm.wrap file not found

再进行一个llvm-config的安装:

sudo apt install llvm-11

怎么还是找不到llvm-config啊?搜索一翻,发现

which llvm-config

没有输出,但是

which llvm-config-11

有结果:

/usr/bin/llvm-config-11

无语。尝试alias设置别名,未果。我几乎快要放弃了,又想去用master branch上的Mesa编译试试:

git clone https://gitlab.freedesktop.org/mesa/mesa.git
cd mesa && meson build -Dgallium-drivers=swrast,d3d12 -Dgallium-va=enabled -Dvideo-codecs=h264dec,h264enc,h265dec,h265enc,vc1dec

这里要升级meson版本,并且编译参数有所不同。欸嘿,这下子它总算找到llvm-config了。又遇到几个依赖没装:

sudo apt install libelf-dev byacc bison flex wayland-protocols

之后又卡在了wayland-protocols这一步:

Dependency wayland-protocols found: NO found 1.20 but need: '>= 1.24'
Run-time dependency wayland-protocols found: NO (tried cmake)

meson.build:1883:2: ERROR: Dependency lookup for wayland-protocols with method 'pkgconfig' failed: Invalid version, need 'wayland-protocols' ['>= 1.24'] found '1.20'.

大不了我们再build一个wayland-protocols。。。然后又发现需要更新wayland的某些component。。。我已经几乎快要忘了原来的目的是什么。。。坚持一下。。。

git clone https://gitlab.freedesktop.org/wayland/wayland.git
cd wayland && meson build && ninja -C build && sudo ninja -C build install
git clone https://gitlab.freedesktop.org/wayland/wayland-protocols.git
cd wayland-protocols && meson build && ninja -C build && sudo ninja -C build install

此处遇到了好几个依赖,直接apt安装即可。

sudo apt install libxml2-dev graphviz doxygen xsltproc xmlto

终于我们可以继续build Mesa了。。。嗯,需要安装亿些依赖:

sudo apt install libxcb-glx0-dev libxcb-shm0-dev libx11-xcb-dev libxcb-dri2-0-dev libxcb-dri3-dev libxcb-present-dev libxshmfence-dev

!!!终于配置成功了。愉快的编译时间:

ninja -C build && sudo ninja -C build install

我的12600k花了两分钟也就,这还是在WSL里,本来还准备喝个咖啡去。。。
然后vainfo看下driver binary能不能work:

export LIBVA_DRIVER_NAME=d3d12
vainfo --display drm --device /dev/dri/card0

又是当头一棒:

libva info: VA-API version 1.15.0
libva info: User environment variable requested driver 'd3d12'
libva info: Trying to open /usr/lib/x86_64-linux-gnu/dri/d3d12_drv_video.so
libva info: va_openDriver() returns -1
vaInitialize failed with error code -1 (unknown libva error),exit

.so没安装都。。。瞄了一眼安装log的最后一行:

installing /home/jianhuyy/mesa/mesa/build/src/gallium/targets/va/libgallium_drv_video.so to /usr/local/lib/x86_64-linux-gnu/dri/d3d12_drv_video.so

因为没有设安装路径,安装到了/usr/local/lib/x86_64-linux-gnu/dri/下面。直接copy过去:

sudo cp /usr/local/lib/x86_64-linux-gnu/dri/* /usr/lib/x86_64-linux-gnu/dri/

vainfo不报错了,但是:

libva info: VA-API version 1.15.0
libva info: User environment variable requested driver 'd3d12'
libva info: Trying to open /usr/lib/x86_64-linux-gnu/dri/d3d12_drv_video.so
libva info: Found init function __vaDriverInit_1_15
libva info: va_openDriver() returns 0
vainfo: VA-API version: 1.15 (libva 2.6.0)
vainfo: Driver version: Mesa Gallium driver 23.1.0-devel for D3D12 (Intel(R) UHD Graphics 770)
vainfo: Supported profile and entrypoints
      VAProfileNone                   : VAEntrypointVideoProc

只有video processing的capability report出来了,codec全部阵亡。。。这合理吗?

合理的,Windows显卡驱动需要更新。我用的driver是Windows自动给我安装的,我甚至不想去官网下,因为官网的driver package包含了一个非常难用的Arc Control,which与NV的GeForce Experience类似。但是我这个核显给我整个给独显的控制面板干什么,核显也配叫锐炫吗?这个Arc Control甚至不能自动更新驱动。。。很不情愿地把驱动更新到官网最新的4091(原本是3616),我们终于能看到codec capabilities被report出来了:

libva info: VA-API version 1.15.0
libva info: User environment variable requested driver 'd3d12'
libva info: Trying to open /usr/lib/x86_64-linux-gnu/dri/d3d12_drv_video.so
libva info: Found init function __vaDriverInit_1_15
libva info: va_openDriver() returns 0
vainfo: VA-API version: 1.15 (libva 2.6.0)
vainfo: Driver version: Mesa Gallium driver 23.1.0-devel for D3D12 (Intel(R) UHD Graphics 770)
vainfo: Supported profile and entrypoints
      VAProfileH264ConstrainedBaseline: VAEntrypointVLD
      VAProfileH264ConstrainedBaseline: VAEntrypointEncSlice
      VAProfileH264Main               : VAEntrypointVLD
      VAProfileH264Main               : VAEntrypointEncSlice
      VAProfileH264High               : VAEntrypointVLD
      VAProfileH264High               : VAEntrypointEncSlice
      VAProfileHEVCMain               : VAEntrypointVLD
      VAProfileHEVCMain               : VAEntrypointEncSlice
      VAProfileHEVCMain10             : VAEntrypointVLD
      VAProfileHEVCMain10             : VAEntrypointEncSlice
      VAProfileVP9Profile0            : VAEntrypointVLD
      VAProfileVP9Profile2            : VAEntrypointVLD
      VAProfileAV1Profile0            : VAEntrypointVLD
      VAProfileNone                   : VAEntrypointVideoProc

H264/HEVC/VP9/AV1全都支持了。看来VP相比于codec先enable了WSL。。。按照微软官方博客的表格,各个codec不是一个Mesa版本支持的。

终于可以使用了

整个环境的配置实在太过艰辛,花了一个下午一个晚上才搞定,而且测试还需要找一段码流,我们就下一篇文章再讲吧!那是不可能的。我们随手找了一个AVC的码流,用FFMPEG测试下转码:

sudo apt-get install ffmpeg
sudo apt-get install gstreamer1.0-plugins-bad gstreamer1.0-tools gstreamer1.0-vaapi

先试下CPU转码:

ffmpeg -i ~/dota2.mp4 -c:v h264 ~/output_sw.h264

sw_process.png
sw utility.png
此时一个名为VmmemWSL的进程直接让CPU满载。
再看下核显转码:

ffmpeg -hwaccel vaapi -hwaccel_output_format vaapi -hwaccel_device /dev/dri/card0 -i ~/dota2.mp4 -c:v h264_vaapi ~/output_hw.h264

hw process.png
hw utility.png
可以看到decode engine的workload,调用进程为“虚拟机工作进程”。WSLg中你甚至可以直接播放视频:

ffplay dota2.mp4

WSLg会直接弹出播放视频的GUI,奇怪的是taskmgr显示workload在3D上。

总结

尽管历经周折,我们还是成功完成了在WSLg中调用GPU进行视频加速。几点小小的感想:

  • 再次鞭挞CPP,人生苦短,别用CPP。高贵的语法特性,配合X一样的包管理,学起来那叫一个酸爽。还好这次耐心足够,不然多半是半途而废体验不到这个项目了。
  • WSL是越来越有意思了。过去用VMware装一个虚拟机还需要一通操作,体验比原生系统差太多。现在WSL无缝集成到Windows,打开商店即可安装,无需繁琐的配置,十分方便。配合VSC开发体验极佳,现在硬件加速功能也逐渐完善,尽管WSL2退回到了虚拟机,但完全感觉不到它的存在,打开一个terminal就能直接使用。WSLg支持了GUI,以前尝试过在WSL1中跑虚拟仿真软件Gazebo,还需要设置xserver才能跑界面,并且整个GUI都是用CPU渲染的。。。WSLg微软直接帮你做好了。
  • 再次体验了Arc Control,尽管界面挺好看的,但是它开机会弹出UAC,我还是决定不留情面将它卸载。。。

后面可能会研究一下微软用了什么科技实现这个项目。