FreeBSDのFirefoxで動画をGPUデコードする
How to enable GPU video decoding for Firefox on FreeBSD
とある日、FreeBSDのノートPCでネットサーフィンしていると、異様にカクつくことに気づきました。htopで確認したところ、以下のような出力が出ました。
$ htop
0[|||||||||||||||||||||||||||||||100.0%] Tasks: 81, 0 thr, 20 kthr; 3 running
1[|||||||||||||||||||||||||||||||100.0%] Load average: 9.26 8.53 7.77
2[|||||||||||||||||||||||||||||||100.0%] Uptime: 02:26:49
3[|||||||||||||||||||||||||||||||100.0%]
Mem[||||||||||||||||||||| 2.54G/11.8G]
Swp[ 0K/4.00G]
PID USER PRI NI VIRT RES S CPU%▽MEM% TIME+ Command
2283 nshingu 11 0 1523M 1097M S 284.6 9.1 3h14:37 /usr/local/lib/firefox/firefox
4081 nshingu 114 0 3042M 616M R 71.4 5.1 0:25.28 /usr/local/lib/firefox/firefox
2270 nshingu 28 0 12.4G 1281M S 24.7 10.6 18:40.96 firefox
2284 nshingu 16 0 3844M 786M S 8.6 6.5 9:54.35 /usr/local/lib/firefox/firefox
2841 nshingu 12 0 2797M 425M S 5.3 3.5 9:51.49 /usr/local/lib/firefox/firefoxメモリ/スワップには余裕がありますが、Load Averageが9近くあり、4コアすべてがCPU 100%で張り付いている状態です。メモリ不足ではありません。
原因は、Firefoxで開いたまま忘れて放置していたNASAのページでした。
https://www.nasa.gov/aeronautics/nasa-releases-powerful-lava-software-to-us-aerospace-industry/
使用しているPCはWyse 5470というシンクライアント向けのPCなので、スペック的に仕方のないことだと思います。このPCは普段動画を見る目的で使っていないですが、動画などが含まれるページを開いただけでここまで負荷が上がってしまうのは困りものです。
そこで、少しでも軽くなればと思い、グラフィックス周りを見直すことにしました。
結論
先に結論から言うと、FreeBSD の Intel 内蔵GPU機で、次の2つを両方行うと改善しました。
# VA-API のドライバをインストール
sudo pkg install libva-utils libva-intel-media-driver
# video グループに追加する
sudo pw groupmod video -m nshingu片方だけでは効かず、ソフトウェアデコード(CPU使用)のままでした。通常の描画は、この設定と関係なく最初からGPUで動いていました。
以下これらの検証です。参考にしてもらえれば幸いです。
環境
機種: Dell Wyse 5470 (シンクライアント向けPC / ファンレス)
OS: FreeBSD 14.5-RELEASE amd64
CPU: Intel Celeron N4100 (4) @ 1.094GHz
GPU: GeminiLake [UHD Graphics 600] (CPU内蔵GPU)
Mem: 12GB
WM: fvwm3
Firefox 157.0
ドライバ、パッケージ、グループの確認
まず、ドライバ・パッケージ・ユーザのグループを確認していきます。
$ kldstat | grep -E 'i915|drm'
3 1 0xffffffff82ff9000 1e6220 i915kms.ko
4 2 0xffffffff831e0000 87090 drm.ko
$ pkg info | grep -E 'drm|mesa'
drm-61-kmod-6.1.128.1405000_10 Direct Rendering Manager (DRM) GPU drivers
drm-kmod-20260508 Direct Rendering Manager (DRM) GPU drivers metaport
gpu-firmware-kmod-20260519,1 Firmware modules for the drm-kmod drivers
libdrm-2.4.133,1 Direct Rendering Manager library and headers
mesa-demos-9.0.0 OpenGL demos distributed with Mesa
mesa-dri-26.1.3 OpenGL hardware acceleration drivers for DRI2+
mesa-libs-26.1.3 OpenGL libraries that support GLX and EGL clients
$ id
uid=1001(nshingu) gid=1001(nshingu) groups=1001(nshingu),5(operator),68(dialer)i915kms.ko と drm.ko が出ているので、ドライバは読み込み済みでした。drm-kmod や mesa-dri も入っていて、パッケージにも問題はありません。
ただ、groups に 44(video) がありませんでした。
はじめは、これが原因でllvmpipe(CPUによるソフトウェア描画)にフォールバックしているのではないかと考えました。
video グループを疑ったのは、FreeBSD Forumsの次のスレッドを見つけたからです。
https://forums.freebsd.org/threads/graphics-support.72701/
このスレッドは2019年のもので、Intel内蔵GPUのマシンにFreeBSD 11.3とGNOME 3を入れたところ、GNOME Shellが「/dev/dri/cardN の読み書き権限が必要なので、ユーザーを video グループに追加してください」という趣旨のメッセージを出した、という相談です。症状は今回と違いますが、/dev/dri 以下のデバイスを開くには video グループが関係する、という点は共通しています。スレッドでは、次のような指摘もされていました。
- drm-kmod を入れるだけでは足りず、i915kms を実際に読み込む必要がある
- /dev 以下の権限は chmod 666 で済ませてはいけない(再起動で元に戻るうえ、誰でも書き込める状態になってしまう)
/dev/dri の権限
ls -l だけではシンボリックリンクしか見えないので、-L を付けて実体を確認します。
$ ls -lL /dev/dri/
total 0
crw-rw---- 1 root video 0x7e Sep 29 17:17 card0
crw-rw---- 1 root video 0x12d Sep 29 17:17 renderD128
$ [ -r /dev/dri/renderD128 ] && echo "renderD128: readable" || echo "renderD128: denied"
renderD128: deniedcrw-rw---- root video は、root か video グループのメンバーしか開けないという意味です。当然、ユーザ(nshingu)は video に入っていないので、renderD128 は開けません。
Firefox のプロセスのグループ
$ procstat -s $(pgrep -o firefox)
PID COMM EUID RUID SVUID EGID RGID SVGID UMASK FLAGS GROUPS
7021 firefox 1001 1001 1001 1001 1001 1001 022 - 1001,5,68FirefoxのGROUPSにも 44 がない状態です。
Firefox が開いている /dev/dri
$ fstat | grep -E 'dri|drm'
nshingu firefox 7021 15 /dev 126 crw-rw---- drm/0 rw
nshingu firefox 7021 42 /dev 126 crw-rw---- drm/0 rw
nshingu firefox 7021 43 /dev 126 crw-rw---- drm/0 rw
nshingu firefox 7021 44 /dev 126 crw-rw---- drm/0 rw開いているのは drm/0 (card0) だけで、drm/128 (renderD128) は開いていません。Xorg経由の描画は動いている感じです。
通常の描画はGPUで動いていた
videoグループがないので、GPUではなくCPUで描画しているのではと疑っていたので、glxinfo でも確認しました。
$ glxinfo | grep -E 'renderer|OpenGL version'
OpenGL renderer string: Mesa Intel(R) UHD Graphics 600 (GLK 2)
OpenGL version string: 4.6 (Compatibility Profile) Mesa 26.1.3
$ glxinfo | grep "direct rendering"
direct rendering: Yesvideo グループに入っていなくても、Intel UHD 600・direct rendering: Yes と表示されました。つまり、glxinfo では video グループの有無を判定できません。Xorgが開いたGPUをアプリに渡しているのだと予想しています。
Firefoxのabout:supportページでGraphics欄を見ても、通常の描画は video グループがなくてもGPUで動いていました。

Compositing: WebRender (Software が付かない)
WebGL 1 Driver Renderer: Intel -- Mesa Intel(R) UHD Graphics 600 (GLK 2)
WebGL 1 Driver Version: 4.6 (Core Profile) Mesa 26.1.3ということで、llvmpipeにフォールバックしているから重いという最初の推測は誤りでした。負荷の原因は通常の描画ではなく、動画のデコード(VA-API)の方にあるようです。
VA-API のパッケージを入れる
VA-APIのドライバが何も入っていなかったので、VA-API関連のパッケージを入れていきます。
$ sudo pkg install libva-utils libva-intel-media-driver
The following 3 package(s) will be affected (of 0 checked):
New packages to be INSTALLED:
gmmlib: 22.10.0 [FreeBSD]
libva-intel-media-driver: 26.1.5 [FreeBSD]
libva-utils: 2.24.0 [FreeBSD]
Number of packages to be installed: 3
The process will require 819 MiB more space.
142 MiB to be downloaded.インストール後は、次のコマンドで確認できます。iHD_drv_video.so があれば、ドライバは入っています。
$ pkg info | grep -i libva
libva-2.24.1 VAAPI wrapper and dummy driver
libva-intel-media-driver-26.1.5 VAAPI driver for Intel HD 5000 (Gen8) or newer
libva-utils-2.24.0 Collection of tests and utilities for VAAPI
$ ls /usr/local/lib/dri/
iHD_drv_video.soドライバはあるが video グループがない状態の vainfo
$ vainfo
Trying display: wayland
Trying display: x11
libva info: VA-API version 1.24.0
libva error: vaGetDriverNames() failed with unknown libva error
vaInitialize failed with error code -1 (unknown libva error),exit
$ vainfo --display drm --device /dev/dri/renderD128
Trying display: drm
Failed to open the given device!ドライバが入っても、videoグループがないと vainfo は失敗します。videoグループが必要になるのは、renderD128 を直接開く処理だけです。
最初のエラーは「unknown libva error」としか表示されないので、ここから権限が原因だとは分かりません。DRMを直接指定したときのFailed to open the given deviceが、権限を疑う手がかりになります。
対処
# VA-API のドライバをインストール
sudo pkg install libva-utils libva-intel-media-driver
# video グループに追加する
sudo pw groupmod video -m nshinguグループの変更は、すでに動いているプロセスには反映されません。一度ログアウトしてログインし直し、id コマンドで groups に 44 が含まれていればOKです。
修正後の確認
$ id
uid=1001(nshingu) gid=1001(nshingu) groups=1001(nshingu),5(operator),44(video),68(dialer)
$ pgrep firefox | xargs -n1 procstat -s
PID COMM EUID RUID SVUID EGID RGID SVGID UMASK FLAGS GROUPS
5314 firefox 1001 1001 1001 1001 1001 1001 022 - 1001,5,44,68
(子プロセスを含む全14プロセスで GROUPS に 44 あり)
$ [ -r /dev/dri/renderD128 ] && echo "renderD128: readable" || echo "renderD128: denied"
renderD128: readable
$ fstat | grep -E 'drm/128|renderD128'
nshingu firefox 7396 15 /dev 301 crw-rw---- drm/128 rw
nshingu firefox 7396 41 /dev 301 crw-rw---- drm/128 rw
nshingu firefox 7411 35 /dev 301 crw-rw---- drm/128 rw
nshingu firefox 7411 36 /dev 301 crw-rw---- drm/128 rw
(以下略。7411 は計8本)グループに 44 が入り、Firefoxが drm/128 (renderD128) も直接開くようになりました。
続いて vainfo です。
$ vainfo
libva info: Trying to open /usr/local/lib/dri/iHD_drv_video.so
libva info: Found init function __vaDriverInit_1_24
libva info: va_openDriver() returns 0
vainfo: Driver version: Intel iHD driver for Intel(R) Gen Graphics - 26.1.5 (intel-media-26.1.5)
VAProfileH264Main : VAEntrypointVLD
VAProfileH264High : VAEntrypointVLD
VAProfileHEVCMain : VAEntrypointVLD
VAProfileHEVCMain10 : VAEntrypointVLD
VAProfileVP8Version0_3 : VAEntrypointVLD
VAProfileVP9Profile0 : VAEntrypointVLD
VAProfileVP9Profile2 : VAEntrypointVLD
...デコードに対応しているのは、MPEG2、H.264、VC1、JPEG、VP8、HEVC (Main / Main10)、VP9 (Profile0 / 2) です。AV1は対応していません。この世代のGPUがAV1のデコードに対応していないためです。
Firefox 側の設定と判定
# about:config
media.hardware-video-decoding.enabled true
media.hardware-video-decoding.force-enabled false
media.hardware-video-decoding-vulkan.enabled false
# about:support の Decision Log
HARDWARE_VIDEO_DECODING default available
HW_DECODED_VIDEO_ZERO_COPY default available
HARDWARE_VIDEO_DECODING_VULKAN user disabled (pref を false にしているため)ここに出ているのは使ってよいという判定であって、実際にGPUでデコードしている証拠ではないです。実際にGPUを使っているかどうかは、この後の top -H で、スレッド名を見て確認します。
動画の多いページでCPU負荷を比べる
以前張り付いたNASA LAVAの記事に、再度チャレンジしてみます。
条件を1つ変えるたびに、Firefoxを再起動してページを開き、1分後に top -H を確認しました。
# ドライバあり / video あり (修正後)
CPU: 6.0% user, 1.9% system, 91.9% idle
load averages: 0.77, 0.85, 1.00
8052 firefox{WRRenderBackend 3.12%
8052 firefox{Renderer} 2.85%
(av: で始まるスレッドは上位に出ず)
# ドライバあり / video なし
CPU: 53.4% user, 6.6% system, 39.6% idle
8396 firefox{av:hevc:d 33.79%
8396 firefox{av:hevc:d 33.68%
8396 firefox{av:hevc:d 33.67%
(id に 44 なし / fstat は drm/0 のみで drm/128 なし)
# ドライバなし (pkg delete libva-intel-media-driver) / video あり
CPU: 27.4% user, 3.1% system, 69.0% idle
9338 firefox{av:hevc:d 18.19%
9338 firefox{av:hevc:d 17.83%
9338 firefox{av:hevc:d 17.66%
9338 firefox{av:hevc:d 7.26%
9338 firefox{av:h264:d 2.69%
9338 firefox{av:h264:d 2.47%
# ドライバなし / video なし (最初の張り付き状態)
CPU: 92.6% user, 4.0% system, 3.4% interrupt, 0.0% idle
2313 firefox{av:hevc:df2} 28.56%
2313 firefox{av:hevc:df0} 26.45%
2313 firefox{av:h264:df0} 26.08%
2313 firefox{av:h264:df2} 25.18%
2313 firefox{av:h264:df1} 24.82%
2313 firefox{av:hevc:df0} 24.74%
(av: スレッドは hevc 6本 + h264 6本の計12本、合計で約294%)ドライバと video の両方がそろった A だけが、GPUでデコードされているのが分かると思います。片方でも欠けると av: スレッド(ffmpegのソフトウェアデコード)が出てきます。CPU負荷を下げたいなら、両方入れる必要があります。
※ あくまで参考例です。動画のループ位置やタブの数でも数字は変わるので、大まかな傾向として見てもらえたらと思います。
なお、次の項目は、どの条件でも同じ表示でした。
glxinfo renderer Intel UHD 600
direct rendering Yes
about:support WebRender, Intel まとめ
videoグループとVA-APIドライバの両方を入れることで、動画のハードウェアデコードが使えるようになり、CPU負荷が下がりました。片方だけでは、CPUデコードのままです。
通常の描画(WebRender / Intel UHD 600)は、videoグループやVA-APIドライバとは無関係に、最初からGPUで動いていました。
glxinfo や about:support のGraphics欄では、この問題は切り分けられません。id、fstat | grep drm/128、vainfo、top -H のスレッド名で確認するのが確実です。
CPU張り付きの原因をGPUが使われていないと考えてしまっていましたが、今回の場合は描画はGPU、動画デコードだけがCPUという状態でした。
これでYoutubeも快適に!という訳にはいかないですが、まあそこそこの状況にならいけるようになったのかなと思ってます。
今まで設定をしていなかった部分を設定してみたという話でした。
補足
i915kms.ko / drm.ko が読み込まれていない場合
パッケージをインストールします。drm-kmod はメタポートで、OSに合った drm-61-kmod などを選んでくれます。
pkg install drm-kmod gpu-firmware-kmodsysrcコマンドで、起動時に読み込む設定をいれます。こうすることで、/etc/rc.conf に kld_list=”i915kms” が追記されます
sysrc kld_list+="i915kms"手動で読み込ませて確認していきます。drm.ko は依存で自動的に読み込まれるのでそこは大丈夫です。
kldload i915kms
kldstat | grep -E 'i915|drm'読み込みに失敗するときは、dmesgを見るようにすれば大丈夫です。多くは、カーネルとdrm-kmodのバージョン不一致が原因です。FreeBSDをアップグレードした直後で不具合がでれば、pkg upgrade で更新してください。パッケージで合わなければ、portsから graphics/drm-kmod を手動ビルドしましょう。
デバイスの権限とXorgのドライバ
crw-rw—- root video なら正常ですが、root wheel のままなら /etc/devfs.rules の設定が必要です。
ls -lL /dev/dri/modesetting なら問題ありません。scfb になっていたら下の設定を書きます
grep -E 'Driver|scfb|modesetting|intel' /var/log/Xorg.0.log | headxf86-video-intel は古めで、今回の私の環境の場合、Gemini Lakeなのでmodesetting が無難です
# /usr/local/etc/X11/xorg.conf.d/driver-intel.conf
Section "Device"
Identifier "Card0"
Driver "modesetting"
EndSection参考
FreeBSD Forums「Graphics support」
https://forums.freebsd.org/threads/graphics-support.72701/
第5章 X Window System | FreeBSD Documentation Portal
https://docs.freebsd.org/ja/books/handbook/x11/#x-config
おわり