月別アーカイブ: 2018年6月

Direct3D12 GPU と ShaderModel 6.1 の対応状況

Direct3D 12 は Metal や Vulkan と同じ低レベル API に属します。新しい API Set ですが、GPU の世代更新に合わせたというよりも Direct3D 11 世代の再定義に近いものでした。ShaderModel は 5.1 のままで、GPU の新機能対応も当初は 11/12 両方に行われています。

D3D API ShaderModel OS Windows 10
Direct3D 11.0 5.0 Vista/7
Direct3D 11.1 5.0 7/8
Direct3D 11.2 5.0 7/8.1
Direct3D 11.3 5.1 10
Direct3D 11.4 5.1 10 (1511) November Update
Direct3D 12 5.1 10
Direct3D 12 6.0 10 (1607) Anniversary Update
Direct3D 12 6.1 10 (1709) Fall Creators Update
Direct3D 12 6.2 10 (1803) April 2018 Update

Direct3D 11 の Release は Windows 7 と同時ですが、Windows 10 になっても 11.3/11.4 と更新が続いていたことがわかります。しかしながら Windows 10 1607 以降は ShaderModel 6.0 も導入されており、機能面での違いも増えてきたように思います。

コメントで Vega の ShaderModel 6.0 の対応状況について情報を教えていただいたので、あらためてそれぞれの GPU で確認してみました。新しい世代の GPU はいずれも最新ドライバで 6.1 に対応していることがわかりました。

GPU FL SM Driver
GeForce GTX 1070 Pascal 12_1 6.1 397.44
GeForce GTX 960 Maxwell 2 12_1 6.1 398.11
GeForce GTX 750 Ti Maxwell 1 11_0 6.1 398.11
RADEON Vega 56 GCN 5 Vega 12_1 6.1 18.5.1
RADEON RX 480 GCN 4 Polaris 12_0 6.1 18.5.1
RADEON R7 (A10-7870K) GCN 2 (1.1) 12_0 6.1 18.5.1
Intel HD Graphcis 530 (i7-6700K) Gen 9 12_1 6.1 23.20.16.4973

下記は ShaderModel 6.0 の wave 命令の lane 数

GPU min max total
GeForce GTX 1070 Pascal 32 32 30720
GeForce GTX 960 Maxwell 2 32 32 16384
GeForce GTX 750 Ti Maxwell 1 32 32 10240
RADEON Vega 56 GCN 5 Vega 64 64 3584
RADEON RX 480 GCN 4 Polaris 64 64 2304
RADEON R7 (A10-7870K) GCN 2 (1.1) 64 64 512
Intel HD Graphcis 530 (i7-6700K) Gen 9 8 32 768

その他 GPU 毎の対応状況の詳細は下記のページに載せています。

Direct3D 12 (DirectX 12) Windows 詳細

GPU は頂点や Pixel のように大量のデータを扱います。これは並列化が容易なので、CPU の Multi Thread と同じように複数の Shader Core で分散実行しています。

CPU と異なっているのは、一定の Thread Group (wave) 毎に実行する命令 (Instruction) を共有していることです。同じ Instruction で同じ演算を行うという意味では SIMD に近いのですが、各 Thread はそれぞれ単一の Scalar 要素にだけアクセスできるようになっています。これは SIMT と呼ばれています。

例えば 4 並列の SIMT を考えてみると、Thread 0 は SIMD Vector Register の x だけ、Thread 1 は y だけ使って演算を行っていることになります。コード上は Scalar 演算と同等です。

ShaderModel 6.0 の wave 命令では、この Thread 毎の Scalar アクセスの制限が緩和されており、ある程度相互に情報をやり取りできるようになりました。先程の例でいえば、本来 Thread 0 しかアクセスできない x の要素を Thread 1~3 からも参照できることになります。

なお ShaderModel 6.0 からは ShaderCompiler が変更されているようです。5.1 までは fxc.exe (D3DCompiler_47.dll) ですが、6.0 以降は dxc.exe (dxcompiler.dll) を使います。

dxc shader.hlsl -T ps_6_0 -E pmain -Fo shader_ps.bin

dxc でコンパイルした bytecode はそのまま PipelineState (D3D12_GRAPHICS_PIPELINE_STATE_DESC) に渡すことができます。

PS_OUT  pmain( VS_OUT pin )
{
    PS_OUT  pout;
    float2  pos= pin.Position.xy;
    if( WaveIsFirstLane() ){
        pos.x*= 1.0f/500.0f;
        pos.y*= 1.0f/500.0f;
    }
    pos= WaveReadLaneFirst( pos );
    if( WaveIsFirstLane() ){
        pout.Color= float4( 0.0f, 0.0f, 1.0f, 1.0f );
    }else{
        pout.Color= float4( pos.x, pos.y, 0.0f, 1.0f );
    }
    return  pout;
}

少々わかりにくいですが、上の PixelShader で Wave Size (Lane 数) の違いを視覚化してみたものです。同一 Wave を同じカラーで塗りつぶします。

null

↑左から RADEON Vega56, Skylake (Intel HD Graphics 530), GeForce GTX1070

Vega が最も Lane 数が多いので tile の色分けがわかりやすくなっています。真ん中の Intel HD Graphcis が最も細かいことがわかります。

関連エントリ
AMD Vega と Direct3D 12
Direct3D 12 GPU GeForce GTX 1070 Pascal と RADEON RX 480 Polaris