LoginSignup
0
1

More than 3 years have passed since last update.

glslangとDirectXShaderCompiler

Last updated at Posted at 2020-12-22

はじめに

DirectX 12とVulkanのために, glslangとDirectXShaderCompiler (dxc) のライブラリを作成し, プログラム内でシェーダのコンパイルができるようにします.

ツールで事前コンパイルの方法にしないのは, 単純に開発時やチュートリアルのためのプログラムを作るときに楽だからです.

シェーダ言語と中間言語とバイナリの関係は, 現在は次のようになっています. 歴史的に, GLSLがHLSLに比較して機能が少なく当初は中間言語がなかったり, HLSLは当初は中間言語ではなくアセンブラだったりします.

HLSL -> DXIL -> Vendor Specific Binary
GLSL -> SPIR-V -> Vendor Specific Binary 

dxcには, HLSLからSPIR-Vへのコンパイル機能があります.
glslangについては, HLSLをSPIR-Vへ変換する機能は開発中です.

Status: Partially complete. Semantics are not reference quality and input is not validated. This is in contrast to the DXC project, which receives a much larger investment and attempts to have definitive/reference-level semantics.

KhronosGroup/glslangから

最適解はまだわかりませんが, HLSLからDXILとSPIR-Vが安定しているのではないかと思います. HLSLとGLSLを両方メンテナンスすることは避けたいです.

基本的なソフトウェアエンジニアリングについて知っていることが前提です. Visual Studio, Make, CMake, Python, Ninjaの説明もしません.

ビルド

Windows

glslang

リポジトリGitHub.
Visual StudioからInstallを行いたい場合, ファイル属性もローカルに反映してしまうため, 次のようにして抑制します.
git config --global core.fileMode false

Win32 Runtimeを変更するには, CMakeLists.txtの中でChooseMSVCCRT.cmakeをincludeする前に指定します.

set(LLVM_USE_CRT_RELEASE "MT")
set(LLVM_USE_CRT_DEBUG "MTd")
include(ChooseMSVCCRT.cmake)

glslangディレクトリ内で, ビルド環境を作成します.

$ mkdir build
$ cd build
$ cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX="path" -G "generator" ..

DirectXShaderCompiler

ビルド

結果を先に書くと, ビルド済みのものをダウンロードする方が安定すると思います.
Installが上手く動かず必要なバイナリやヘッダーがわかりにくいです.

リポジトリGitHub.
ATLと.Net Framework 4.5が必要です, Visual Studio Installerでインストールします.

$ git clone https://github.com/Microsoft/DirectXShaderCompiler.git
$ cd DirectXShaderCompiler
$ git submodule update --init
$ .\utils\hct\hctstart.cmd -x64 [path-to-sources] [path-to-build]
$ .\utils\hct\hctbuild -vs2019 -spirv -x64

使いそうなものだけ, utils\hct\hctbuild --helpで説明が見れますが, utils\hct\hctbuildを直接見た方が早いです. -spirvのようにヘルプに説明がないものがある.

  • -s: プロジェクトファイルを生成するだけ
    • Windowsでは, Visual Studioで開いてビルド, インストールするのが正解. 後述の-Debug, -Releaseオプションではデバッグ・リリースビルドの区別ができない.
  • -no-parallel: Ninjaでは効果ないように見える. Visual Studioなら自分で修正すればいいので, 存在価値が不明, make用か?
  • -no-dxilconv
  • -vs2017, -vs2019: コンパイラ
  • -ninja: ビルド環境
  • -x86, -x64, -arm, -arm64: アーキテクチャ
  • -Debug, -Release

使い方

まず, HLSLからDXILへコンパイル.

Wiki: Using-dxc.exe-and-dxcompiler.dll

HLSL to DXIL
{//HLSL -> DXIL
        CComPtr<IDxcBlobEncoding> sourceBlob = nullptr;
        utils->CreateBlob(hlsl, sizeof(hlsl), 65001, &sourceBlob);
        DxcBuffer source;
        source.Ptr = sourceBlob->GetBufferPointer();
        source.Size = sourceBlob->GetBufferSize();
        source.Encoding = DXC_CP_ACP;

        LPCWSTR args[] = {
            L"shader.hlsl",     // Optional shader source file name for error reporting and for PIX shader source view.
            L"-E", L"main",     // Entry point.
            L"-T", L"vs_6_0",   // Target.
            L"-Zi",             // Enable debug information.
            //L"-Qstrip_reflect", // Strip reflection into a separate blob.
        };

        CComPtr<IDxcResult> results;
        compiler->Compile(
            &source,
            args,
            _countof(args),
            includeHandler,
            IID_PPV_ARGS(&results));

        CComPtr<IDxcBlobUtf8> errors = nullptr;
        results->GetOutput(DXC_OUT_ERRORS, IID_PPV_ARGS(&errors), nullptr);
        if(nullptr != errors && 0 < errors->GetStringLength()) {
            printf("[Error]\n%s\n", errors->GetStringPointer());
        }

        HRESULT status = E_FAIL;
        results->GetStatus(&status);
        if(FAILED(status)) {
            return EXIT_FAILURE;
        }

        // shader binary
        CComPtr<IDxcBlob> shaderBlob = nullptr;
        CComPtr<IDxcBlobUtf16> shaderName = nullptr;
        results->GetOutput(DXC_OUT_OBJECT, IID_PPV_ARGS(&shaderBlob), &shaderName);
        if(nullptr != shaderBlob) {
            printf("A shader binary exists.\n");
        }

        // pdb
        CComPtr<IDxcBlob> pdbBlob = nullptr;
        CComPtr<IDxcBlobUtf16> pdbName = nullptr;
        results->GetOutput(DXC_OUT_PDB, IID_PPV_ARGS(&pdbBlob), &pdbName);
        if(nullptr != pdbBlob) {
            printf("A shader pdb %ls exists.\n", pdbName->GetStringPointer());
        }

        // shader hash
        CComPtr<IDxcBlob> hashBlob = nullptr;
        results->GetOutput(DXC_OUT_SHADER_HASH, IID_PPV_ARGS(&hashBlob), nullptr);
        if(nullptr != hashBlob) {
            DxcShaderHash* hash = (DxcShaderHash*)hashBlob->GetBufferPointer();
            printf("A shader hash: ");
            for(size_t i = 0; i < _countof(hash->HashDigest); ++i) {
                printf("%X", hash->HashDigest[i]);
            }
            printf("\n");
        }

        // separated reflection
        CComPtr<IDxcBlob> reflectionBlob;
        results->GetOutput(DXC_OUT_REFLECTION, IID_PPV_ARGS(&reflectionBlob), nullptr);
        if(nullptr != reflectionBlob) {
            DxcBuffer reflectionBuffer;
            reflectionBuffer.Ptr = reflectionBlob->GetBufferPointer();
            reflectionBuffer.Size = reflectionBlob->GetBufferSize();
            reflectionBuffer.Encoding = DXC_CP_ACP;

            CComPtr<ID3D12ShaderReflection> reflection;
            utils->CreateReflection(&reflectionBuffer, IID_PPV_ARGS(&reflection));

            D3D12_SHADER_DESC shaderDesc;
            if(SUCCEEDED(reflection->GetDesc(&shaderDesc))){
                printf("shader %d\n", shaderDesc.Version);
            }
        }
    }

HLSLからSPIR-Vへコンパイル, オプションは使いそうなものを選んだが, 実際に試験してみないとどれが必要かわからない.

Wiki: SPIR‐V CodeGen
Wiki: HLSL to SPIR-V Feature Mapping Manual
オプションが異なるだけです. ただし, デバッグ情報もリフレクション情報も生成されないので調査中です.

HLSL to SPIR-V
LPCWSTR args[] = {
    L"-spirv",        // Generates SPIR-V code.
    L"-E", L"main",   // Entry point.
    L"-T", L"vs_6_0", // Shader profile.
    L"-Zi",           // Enable debug information.
    L"-fvk-use-gl-layout", // Uses strict OpenGL std140/std430 layout rules for resources.
    //L"-fvk-use-dx-layout", //Uses DirectX layout rules for resources.
    L"-fspv-reflect", // Emits additional SPIR-V instructions to aid reflection.
    L"-fspv-flatten-resource-arrays", // Flattens arrays of textures and samplers into individual resources.
}

Linux

まだライブラリをビルドしたところまで, コードでは試していません.

  • C/C++コンパイラとツールチェイン
  • Git
  • Python
  • CMake
  • Ninja

glslang

$ git clone https://github.com/KhronosGroup/glslang.git
$ mkdir build && cd build
$ cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX="XXX"
$ make install

DirectXShaderCompiler

libexecinfo-devが必要かもしれません.

$ mkdir build && cd build
$ cmake .. -GNinja $(cat ../utils/cmake-predefined-config-params) -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX="XXX"
$ ninja build
$ ninja install

まとめ

とりあえず, dxcでHLSLをコンパイルするところまで. 後に追記するかも.

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1