前回 、3Dグラフィックスの技術の歴史を振り返り、Windowsが利用しているDirectX(Direct3D)の機能をWineではOpenGLやVulkanを利用して実現していること、そのOpenGLやVulkanの機能をOSSとして実装しているのがMesa3Dライブラリであることなどを紹介しました。
元々Mesaは、OpenGLをソフトウェア的に実現するライブラリとして開発が始まったものの、ビデオカードが急速に進化し、プログラム可能なGPUを搭載するようになると、GPUを操作する機能を一括して担うようになりました。
自社のビデオカード/GPUにしか対応しない商用ドライバに比べ、Mesaは複数メーカに対応できるよう設計が工夫され、各機能はライブラリやモジュール化されたドライバとして提供されています。Mesaも長い歴史を持つプロジェクトで、調べていくとあれこれ興味深い話題が出てくるので、今回は少し脱線してMesa3Dライブラリについて語ってみましょう。
Mesa3Dライブラリの提供する機能
先に述べたように、現在のMesa3Dライブラリは、元々の目的だったOpenGL機能の実装に留まらず、GPUを操作するための総合的なライブラリ に発展し、その役割は大きく以下の3つに分けられます。
(1)OpenGL/OpenGL ES/Vulkanといった3Dグラフィックス機能
(2)各種動画コーデックのハードウェア処理機能
(3)GPUをグラフィックス以外の演算に利用するGPGPU機能
自社のGPU用にのみこれらの機能を提供すればいい商用ドライバに対し、Mesa3Dライブラリは、Intel/AMD/NVIDIAと言ったデスクトップPC用のGPUに留まらず、Android用のSoC化されたGPUまで手広く対応しています。
それら全てを扱うことは困難なので、ここではPlamo Linux用に作成したmesaパッケージを元に、どのファイルがどの機能を担っているのかを紹介することにしましょう。
Plamo Linuxでは、あるパッケージがどのようなファイルをインストールしたかを/var/log/packages/ 以下にテキストファイルで記録しているので、このディレクトリにあるmesaパッケージの記録を元に説明します。この記録は1行1ファイルなので、"cat -n"で連番を振ってみたものの、説明の都合上、取りあげる行は前後することをご理解ください。
$ cat -n /var/log/packages/mesa
1 PACKAGE NAME: mesa-21.1.8-x86_64-B1
2 COMPRESSED PACKAGE SIZE: 59467 K
3 UNCOMPRESSED PACKAGE SIZE: 220210 K
...
(1)3Dグラフィックス用ライブラリ
まずは、( 1)の各種3Dグラフィックス用のライブラリから紹介しましょう。これらはOpenGL/GLX用、EGL用、Vulkan用等に分けられ、/usr/lib/以下にインストールされています。
(a) OpenGL/GLX/EGL用のライブラリ
65 usr/lib/libglapi.so.0.0.0
77 usr/lib/libOSMesa.so.8.0.0
71 usr/lib/libGLX_mesa.so.0.0.0
72 usr/lib/libgbm.so.1.0.0
73 usr/lib/libEGL_mesa.so.0.0.0
(b) Vulkan用のライブラリ
66 usr/lib/libVkLayer_MESA_overlay.so
67 usr/lib/libVkLayer_MESA_device_select.so
69 usr/lib/libVkLayer_INTEL_nullhw.so
68 usr/lib/libvulkan_radeon.so
70 usr/lib/libvulkan_intel.so
79 usr/lib/libvulkan_lvp.so
(a)に分類したのがMesa3Dライブラリが元々の対象としていたOpenGL関連のライブラリで、77行目のlibOSMesa.so がOpenGL/OpenGL ESを処理するためのライブラリ、71行目のlibGLX_mesal.so はX Window SystemからOpenGLを使う際に利用するライブラリ、65行目のlibglapi と72行目のlibgbm はこれらライブラリの機能を補助するためのライブラリです。
OpenGLでは「レンダリング・コンテキスト(RC) 」という形で描画データ(オブジェクト)を扱うものの、元々シングル・スレッド環境を前提に設計されたOpenGLでは複数のRCを扱うことができないため、libglapiによってRCに応じたAPIを呼び出すようになっているそうです。またlibgbmは"GeneralBuffer Management"の名前の通り、バッファ管理用のライブラリです。
73行目のlibEGL_mesa.so は、EGL(Native Platform Graphics Interface)という機能を提供するライブラリで、主にOpenGL ESから利用され、OpenGLではハードウェア用のドライバが担っていた機能をソフトウェア的に提供し、Nativeなグラフィック環境(XやMS Windows)に依存しないコードを書くことを可能にします。すなわちEGL用に作成したアプリは、EGL経由でX上でもMS Windows上でもAndroid上でも動作可能になるわけです。
(b)に分類したのがVulkan用のライブラリで、68、70行目のlibvulkan_{radeon,intel}.so がレンダリング処理にAMDやIntelのGPUの機能を使うためのライブラリ、79行目のlibvulkan_lvp.so は"Lavapipe"と呼ばれるソフトウェア的な実装で、処理は正確なものの、GPUに比べるとはるかに遅いそうです。
VulkanではAPIコールを受け付けてから実際にドライバが処理するまでに、エラーチェック(Validation)や利用するドライバを選択するためのレイヤーを設けることができ、66~69行めのlibVkLayer_XXX.so はこのレイヤー機能に対応するためのライブラリです。
ちなみにVulkanのAPIコールを受け付けるのは別途Vulkan_Loader パッケージからインストールされる/usr/lib/libvulkan.so.1で、このライブラリが/usr/share/vulkan/icd.d/以下の定義ファイルを元に、適切なドライバを選択するようになっています。
(2)各種動画コーデックのハードウェア処理機能
次に動画コーデックのハードウェア処理機能を見てみます。最近のビデオカードにはMPEG2やH.264/AVCといった規格の動画をハードウェアを使ってエンコード/デコードする機能が用意され、それらを使用するためにNVIDIAはVDPAU (Video Decode and Presentation API for Unix)というAPIを、IntelはVA (Video Acceleration)というAPIをそれぞれ提案しました。
VA-APIはエンコードとデコードの機能を持つのに対し、VDPAUはその名前の通りデコード専用のAPIです。これらAPIを受け付けるライブラリは、libva やlibvdpau という別パッケージが用意するものの、最終的にGPUを操作する機能はMesaが提供しています。
37 usr/lib/vdpau/libvdpau_r300.so.1.0.0
38 usr/lib/vdpau/libvdpau_r600.so.1.0.0
39 usr/lib/vdpau/libvdpau_radeonsi.so.1.0.0
40 usr/lib/vdpau/libvdpau_nouveau.so.1.0.0
25 usr/lib/dri/r600_drv_video.so
26 usr/lib/dri/radeonsi_drv_video.so
27 usr/lib/dri/nouveau_drv_video.so
これら/usr/lib/vdpau/にインストールされるのがVDPAU用ライブラリで、/usr/lib/dri/以下にインストールされるのがVA API用ライブラリです。
Intel用のライブラリは、Intel自身がDRMを操作するライブラリを含めたlibvaパッケージをOSSとして提供しているためMesaでは対応していないものの、libvdpau-va-gl というVDPAUとVA/OpenGL間を架橋するようなライブラリも開発されているので、IntelのGPUでも問題なくVDPAUを利用できます。
(3)GPUをグラフィックス以外の演算に利用するGPGPU機能
GPUは条件分岐のような複雑な処理は苦手なものの、ベクトル演算のような単純計算の処理能力はCPUを凌駕します。このGPUの計算能力を膨大な計算量が必要な「ビットコイン・マイニング」のような作業に流用しよう、というのがGPGPU (General Purpose GPU)技術で、そのためにOpenCL (Open Computer Language)という規格が提案されました。
OpenCLも規格を策定しているのはKhronos Groupです。なお正確に言うと、OpenCLはGPUだけではなく、DSP(Digital Signal Processor)やFPGA(Field Programmable Gate Aray)等、プログラム可能な周辺機器を統一して扱おうという規格で、GPU限定というわけではありません。
Mesa3DライブラリはこのOpenCLにも対応していて、libMesaOpenCL.so というライブラリとGalliumフレームワークのドライバ を用いてOpenCLの機能を実現しています。
93 usr/lib/libMesaOpenCL.so
29 usr/lib/gallium-pipe/pipe_iris.so
30 usr/lib/gallium-pipe/pipe_nouveau.so
31 usr/lib/gallium-pipe/pipe_r300.so
32 usr/lib/gallium-pipe/pipe_r600.so
33 usr/lib/gallium-pipe/pipe_radeonsi.so
34 usr/lib/gallium-pipe/pipe_vmwgfx.so
35 usr/lib/gallium-pipe/pipe_swrast.so
ただ、OpenCLの最新規格は3.0で、NVIDIAのCUDA (Compute Unified Device Architecture)等、GPUメーカが提供しているドライバはこのバージョンに追従しているものの、Mesaが提供するOpenCL用ドライバ(Clover)はOpenCL 1.1レベル なので、実用性はあまり高くないようです。
$ clinfo
Number of platforms 1
Platform Name Clover
Platform Vendor Mesa
Platform Version OpenCL 1.1 Mesa 21.1.8
Platform Profile FULL_PROFILE
Platform Extensions cl_khr_icd
Platform Extensions function suffix MESA
...
Mesaの提供するドライバ
最後にMesaが提供するGPU用ドライバを眺めておきましょう。実際にGPUを操作するのは/usr/lib/dri以下にインストールされる以下のファイルになります。
9 usr/lib/dri/
10 usr/lib/dri/i915_dri.so
11 usr/lib/dri/i965_dri.so
12 usr/lib/dri/radeon_dri.so
13 usr/lib/dri/r200_dri.so
14 usr/lib/dri/nouveau_vieux_dri.so
15 usr/lib/dri/radeonsi_dri.so
16 usr/lib/dri/nouveau_dri.so
17 usr/lib/dri/swrast_dri.so
18 usr/lib/dri/kms_swrast_dri.so
19 usr/lib/dri/iris_dri.so
20 usr/lib/dri/r300_dri.so
21 usr/lib/dri/r600_dri.so
22 usr/lib/dri/vmwgfx_dri.so
23 usr/lib/dri/virtio_gpu_dri.so
24 usr/lib/dri/zink_dri.so
Mesaでは、当初はそれぞれのGPUごとにドライバを開発していたものの、2010年ごろからGallium という3Dグラフィックス・ドライバ用のフレームワークを採用し、新しいドライバはこのフレームワークを用いて開発するようになりました。上記リストのうち、i915、i965、nouveau_vieux、r200、radeonが古いタイプのドライバでiris、nouveau、r300、r600、radeonsiが新しいタイプのドライバになります。
i915/i965/irisはIntel用、nouveau_vieux/nouveauはNVIDIA用、r200/r300/r600/radeon/radeonsiはAMD用のドライバです。ちなみに"vieux"はフランス語で「古い」「 老いた」という意味だそうです。
swrast はGPUを使わずソフトウェア的に処理を行うドライバで、対応するGPUが無い場合も利用可能なものの、処理速度は遅く実用的では無いようです。kms_swrast はカーネルのモードセット機能を利用するソフトウェア・ドライバのようですが、詳細はよく分りません。
その他、vmwgfx はVMware、virtio_gpu はQemu、それぞれの仮想環境からホスト側のGPUを利用するためのドライバです。zink は少し毛色が違っていて、OpenGLの機能をVulkanで実現するためのドライバだそうです。
Mesaでは、先に紹介した各機能用のライブラリが、これらGPU用のドライバと連携しながらCPUとGPUを自在に扱う複雑な処理を実現しています。
ざっとMesa3Dライブラリがインストールするファイル類を眺めてきた上で、改めて/usr/lib/dri/以下を調べてみると、興味深いことに気づきました。
$ ls -l /usr/lib/dri | grep -v video
合計 412,438,528
-rwxr-xr-x 5 root root 18,151,368 9月 12日 20:37 i915_dri.so*
-rwxr-xr-x 5 root root 18,151,368 9月 12日 20:37 i965_dri.so*
-rwxr-xr-x 10 root root 27,509,592 9月 12日 20:37 iris_dri.so*
-rwxr-xr-x 10 root root 27,509,592 9月 12日 20:37 kms_swrast_dri.so*
-rwxr-xr-x 10 root root 27,509,592 9月 12日 20:37 nouveau_dri.so*
-rwxr-xr-x 5 root root 18,151,368 9月 12日 20:37 nouveau_vieux_dri.so*
-rwxr-xr-x 5 root root 18,151,368 9月 12日 20:37 r200_dri.so*
-rwxr-xr-x 10 root root 27,509,592 9月 12日 20:37 r300_dri.so*
-rwxr-xr-x 10 root root 27,509,592 9月 12日 20:37 r600_dri.so*
-rwxr-xr-x 5 root root 18,151,368 9月 12日 20:37 radeon_dri.so*
-rwxr-xr-x 10 root root 27,509,592 9月 12日 20:37 radeonsi_dri.so*
-rwxr-xr-x 10 root root 27,509,592 9月 12日 20:37 swrast_dri.so*
-rwxr-xr-x 10 root root 27,509,592 9月 12日 20:37 virtio_gpu_dri.so*
-rwxr-xr-x 10 root root 27,509,592 9月 12日 20:37 vmwgfx_dri.so*
-rwxr-xr-x 10 root root 27,509,592 9月 12日 20:37 zink_dri.so*
ファイル名等は先に紹介した通りなものの、ファイルサイズを見てみると18MBと27MBしかなく、リンクカウントもそれぞれ5と10になっています。これはすなわち、Mesaが提供しているGPU用のドライバはいろいろな名称でインストールされてはいるものの、古い世代とGalliumを使う新しい世代の2種しかなく、同じドライバでAMDやIntel、NVIDIAのGPUに対応していることを示します。
GPUもCPUと同じく機械語しか理解できませんし、x86の機械語がARMの機械語と全く異なっているように、GPUの機械語もメーカごとに異なっているから、「 Gallium3Dフレームワーク」を使っていると言っても、ドライバの一番下のレイヤには各GPU用のコードを生成するためのハードウェア依存部分があるはず、と思いこんでいた筆者には、これはちょっとした驚きでした。
このあたり、Mesaの付属ドキュメントは古いままのものが多く、新しい情報はReleaseNotesやソースコードを調べるしか無さそうなので、また時間のある時にでも調査してみようと思っています。