続・玩式草子 ―戯れせんとや生まれけん―

第33回Days of WINE and Struggles again[2]

前回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はこれらライブラリの機能を補助するためのライブラリです。

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はこのレイヤー機能に対応するためのライブラリです。

(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を受け付けるライブラリは、libvalibvdpauという別パッケージが用意するものの、最終的に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)という規格が提案されました。

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が新しいタイプのドライバになります。

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やソースコードを調べるしか無さそうなので、また時間のある時にでも調査してみようと思っています。

おすすめ記事

記事・ニュース一覧