OptiX 7.x のメモ

7.x から API が変わっています. 7.x はより low-level(Vulkan などに近い) API になっています.

motion blur とか hair とかが不要な場合は 6.x の API を使ったほうがいいかもしれません
(ただ今後 6.x がどのようにメンテされるのかは不明)

7.x は少なくとも future-proof であり underlying な GPU アーキテクチャが変わっても API に変更はないとはあります
(とはいえ NVIDIA は OpenGL/Vulkan などの標準化されている API ではないものは, **仕様をころころ変えるのであんまりあてにしない方がよいでしょう**)

## Supported GPU

Maxwell 以降の GPU になります.
Kepler では動きません(GTX TITAN で確認).

raygen でレンズ効果を入れるために倍精度使いたいなどの場合は TITAN V あたりを使うことになってしまいます
(GTX TITAN(Kepler) だと倍精度 1.0 ~ 1.4 TF くらいある)
 
## SDK

SDK 自体は header とサンプルコードしかありません.
OptiX 用のユーザアプリでリンクすべき lib は無いです(dll を動的呼び出ししているため不要).

### サンプルのビルド

Linux の場合, X11 関連のライブラリ(Xrandr, X11, ...)が必要になります.
Ubuntu であれば, gtk3 関連いれると一式入りますので,

`sudo apt install libgtk-3-dev`

がよいでしょうか.

### 実行の仕組み

optix のコンパイル時では dll とのリンクは行われず、実行時に 
nvoptix.dll を動的に呼び出している

https://forums.developer.nvidia.com/t/how-to-keep-nvoptix-dll-up-to-date/74600

Linux の場合は libnvoptix.so.1 を使います.
これらはドライバのインストールでインストールされるため, 別途 OptiX のランタイムをインストールする必要はありません.

cuew と組み合わせれば, CUDA SDK いらずのビルド環境を作ることができます(Cycles がそうしている).

CUEW で CUDA SDK いらずの開発環境を整える(CUDA Toolkit 11.0 対応. cuDNN 8.0 対応もしたよ) 
https://qiita.com/syoyo/items/57c4d2fbbae78b25b2cf

cuew を使う場合は CUDA Driver API 限定になります. ただそんなに高レイヤーな API(CUDA runtime API)は必要ないかと思われますので Driver API でよいかと思います.

### Trace 関数

専用の命令を asm で呼び出している. 
OptiX 側では, 交差判定時などの処理(CUDA コード)は, 専用関数で PTX で読むようになっています. 
(デフォルト提供のシェーダは無さそうっぽい)

`optixModuleCreateFromPTX` など.

trace などを含んだ .ptx は OptiX API 経由でのコンパイルを想定しているようで, trace 関数を含んだ .ptx を nvcc でそのままにはバイナリにはコンパイルできません.
(trace 関数など optix 用命令を呼び出すcall命令でエラーがでる)

OptiX SDK では, NVRTC で .cu ソースを .ptx にするユーティリティライブラリがあります.

## Hair(curves)

OptiX 7.1(2020 Jun 30 release) から Hair(curves) 対応されました.

motion blur も対応しています
(optixCurves sample で `-m` つけて起動すると効果がわかります)

## アラインメント

Sbt 用変数などでは, 変数メンバのアライメントが合っている必要があります.

nvcc 経由でのコンパイルの場合は, `__align__(N)` が利用できますが, 素の MSVC や gcc/clang では未対応の拡張 pragma なのでエラーになります.

とりあえずは

```
template <typename T>
struct SbtRecord {
#ifdef _MSC_VER
  __declspec(align(
      OPTIX_SBT_RECORD_ALIGNMENT)) char header[OPTIX_SBT_RECORD_HEADER_SIZE];
#else  // assume gcc or clang
  char header[OPTIX_SBT_RECORD_HEADER_SIZE]
      __attribute__((aligned(OPTIX_SBT_RECORD_ALIGNMENT)));
#endif
  T data;
};
``` 

で MSVC, gcc/clang でうまくアラインメントを扱えるようです.

しかし, 本当に確実性を求めるならば, コンパイル時レベルでは NG で, 実行時メモリ確保のときにアラインしないとだめかもです.

`static_assert` + `offsetof` でチェック入れておくとよいでしょう. e.g. 

```
  static_assert(
      offsetof(RayGenSbtRecord, data) % OPTIX_SBT_RECORD_ALIGNMENT == 0,
      "Member variable must be aligned to OPTIX_SBT_RECORD_ALIGNMENT(=16)");
```

## BVH build

頂点データの転送(e.g. cudaMemcpy, cuMemcpyHtoD)では, メモリの確保などのサイズがきちんと合っているか確認しましょう.
筆者はサイズがあっておらず(e.g. sizeof(float3) 倍していなかった), 描画が適切に行われず(エラーではないのでエラーはでない), 1/2 営業日無駄に消費してしまったことがあります :cry:

## その他コード例

Cycles レンダラの OptiX 部分(7.x API 利用)が, 実務的で参考になるでしょう.

https://github.com/blender/blender

## NVLink

複数 GPU をひとつの GPU に見せる方法?

`libnvidia-ml.so` を dll 動的ロードして対応します.
(OptiX SDK の例では)

## 複数 GPU

特に OptiX 自体には複数 GPU 用の API は無いようなので, 基本は GPU ごとに CUDA/OptiX コンテキストを使ってうまくやっていくことになります.

## Denoiser

パストレ画像用の Denoiser が OptiX にあります.
trained model は GPU ドライバ(or libOptiX)と一緒に配布になっているようで, アプリ側でモデルファイルなどの指定は不要になっています.

## 7.2

2020/10/07 に 7.2 がリリースされました.

https://news.developer.nvidia.com/the-nvidia-optix-sdk-release-7-2/

相変わらず SDK document には新機能のまとめとか無いので, どう使えばよいかわかりずらくつらい :cry:

* motion blur bound の自動計算
* shader(light path?) specialization
* validation layer: Vulkan validation layer のようなものと思われます.

## 7.3

2021/04 に 7.3 がリリースされました.

* curves の改善
* temporal denoising のサポート

465.89 は, Linux では 2021/05/26 時点では apt などで安定版(?)としてリリースされていないため, しばらくまつ必要があります.

## TODO

* [ ] clang/LLVM で C/C++ JIT で nvcc, NVRTC 不要で, 実行時に CUDA コードを PTX に変換する
  * libClang/LLVM で C++ コードの JIT コンパイルを行う. https://qiita.com/syoyo/items/486ce53a0dd7a8c73d71