ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。
-
Metal 3でバインドレスにする
Metal 3でバインドレスにする際に、レイトレーシングなどの強力なレンダリング技術をどう活用できるのかご覧ください。引数バッファーの単純化、ヒープからの加速構造の割り当て、Metalの検証レイヤーやDebugger Toolの改善による利点を活かして、Appのバインドレス化を実現する方法を紹介します。また、長期的なリソース構造で、CPUやGPUのパフォーマンスを制御する方法についても解説します。
リソース
関連ビデオ
WWDC23
WWDC22
WWDC21
-
ダウンロード
こんにちは ようこそ AppleのGPU Software Teamの Alè Segovia Azapianです 同じくGPU-ソフトウェアチームのMayurです バインドレスレンダリングについてお話します シェーダーにリソース提供する最新の方法です レイトレーシングなどの レンダリング技術に対応 今日はその仕組みについて簡単におさらいして Metal 3でゲームやAppに 採用する方法を説明します
データを集約するためCPU GPUの性能を向上させる 新たな可能性が広がります 私からCPUとGPU高速化のコツを2つお伝えし Mayurに引き継ぎます 彼はこのツールがどう役立つかを説明します バインドレスモデルではリソースは集約され- Argument Buffersで連結しています コンセプトとしてはこんな感じです この例では全メッシュを配列で集約しています あるスロットに各リソースを 独立してバインドする 従来のモデルとは異なり バインドレスモデルでは リソースはまずメモリ上で 互いにリンクされます これでシェーダーが精巧な サーフェスやライティングを 計算するためリソースに自由にアクセスし 単一のバッファーをバインドすることができます バインドレスになった後レイトレーシングの シェーダーは反射を美しく シェーディングするために 必要なデータにアクセスすることができます Appは床やトラックその素材 空までを含む 3Dモデルやテクスチャを そのすべてのデータを引数バッファに配置し シェーダーが利用できるようにします さらにバインドレスレンダリングとHeapsなど Metalの他の機能を組み合わせると CPU負荷が軽減パフォーマンスが向上します Metal 3の拡張機能のうち バインドレスレンダリングに 役立つ4つの機能について説明します 引数バッファはMetal の基本構成要素で リソースを一緒にリンクさせることができます テクスチャやその他のバッファなどを参照します Metal 3ではArgument encoderオブジェクトが 不要になったためバッファの作成が容易に 結合されていない配列の場合も同様です Metal HeapからAccelerationNstructuresを 割り当てることができ Shader Validation LayerがGPUメモリに リソースが常駐していないと警告を発します 4つの機能でバインドレス化 をより簡単に実現します
特にargument buffersを書くのが楽しいですね シーンを引数バッファにエンコードするには インスタンス メッシュ マテリアル テクスチャなど シーンデータを引数バッファに書き込みます Metal 2では引数エンコーダで実行されました そこで はじめにこれらオブジェクトが どう機能するかをおさらいし 次にMetal 3がどのように 簡素化に役立つか紹介する 関数のリフレクション構造体のメンバーを Metalに記述することで行います エンコーダーインスタンスで その記録先とオフセットを ターゲット引数バッファに設定します そのメソッドを使って バッファにデータを書き込む 引数バッファと引数エンコーダについては 昨年のbindlessセッションで 詳しく確認してください さてこの仕組みは素晴らしいのですが エンコーダオブジェクトの 管理が難しい場合があります Metalは引数エンコーダ作成に 2つのメカニズムを提供します どちらがAppに適するか 明確でない場合があります 複数スレッドからエンコーダ 使用する場合は要注意です 開発者はC言語の構造体を 直感的に理解していますが Metal3で引数バッファに対し まさにそれを実現できます 他のCPU側構造体と同様 直接バッファに書き込み可能 引数バッファの書き込みが Metal 3では簡素化されます これでリソースの仮想GPU アドレスとリソース ID に アクセスできるようになりました これらを直接引数バッファに書き込むと どのリソースを参照しているか Metalが理解します エンコーダが不要になった 以外は引数エンコーダを 使って参照するのと機能的には同じでです Tier2をサポートする 全デバイスで対応しています 2016年以降のMacとA13バイオニックチップ またはそれ以降のiOSデバイスが対象です
tier2をサポートしているかどうか不明な場合は MTLDevice objectにクエリが あるのでご利用ください Metal 3ではこのような流れになっています CPUから見える構造体を 定義 バッファアドレスには 64ビット型 テクスチャには MTLResourceIDを使用 そして引数バッファを確保 MTLDeviceから直接またはMTLHeapから割当可能 バッファ内容を取得後 引数 バッファ構造体型にキャスト 構造体メンバーにアドレスと リソースIDを書き込む レンダリングデモでその様子をご覧ください コードです いかにシンプルであるかにご注目 構造体は法線バッファのGPUアドレスを直接保存 64ビット符号なし整数なので uint64_tを使用しました エンコーダオブジェクトがないので 構造体のサイズを引数バッファに使うだけです MetalはClangとシェーダ コンパイラの間でGPUと- CPUの構造体のサイズと アライメントの一致を保証
次に通常通りバッファを確保します バッファストレージモードが ManagedかSharedの場合 ダイレクトポインタを取得 構造体タイプにキャスト normalsメンバーをgpuAddressに設定 GPUメモリへmustNalignするオフセットを設定
One thing I want to highlight is how the structure declaration changes 注目点はMetal Shading言語とC言語での変化 この例ではこれらを分離していますが 必要であれば共有ヘッダで 構造体宣言を1つにして 条件付きコンパイルで シェーダコンパイラの型と Cの型を区別可能です 以下はC言語による統一の宣言です マクロはシェーダーコードの コンパイル時にのみ定義 ヘッダ宣言でGPUとCPU コード分離の為使用します AppターゲットがC++の場合 この機能を追加可能 テンプレートを使って宣言をさらに統一します
引数バッファのサンプルで 最適な方法を確認ください 1つの構造体の書き方でした 未束縛の配列を使って 多くの構造を書くことも可能 Metalでは引数エンコーダで 非束縛の配列を実装しました Metal3はさらに処理を簡略化します 構造体のoutNan配列をほとんど埋めるだけ
1つの構造体を書く場合と 比較し違いを説明します 格納する全ての構造体に対し ストレージ割当てが必要です 配列に対し繰返し処理 各構造体のデータを書き込む
コードサンプルに戻りバッファのサイズを拡張 シーン内の構造体メッシュの数だけ保存します CPUバッファと全く同じで あることに注意ください 構造体サイズにメッシュ数を掛けたものです その力強さをこの場を強調します この変数ひとつで配列の 大きさをコントロール可能 シェーダはサイズを宣言する必要はありません Metalシェーダーコンパイラーに渡すと どの位置にも自由に インデックス付けが可能です バインドレスモデルが柔軟である理由の一部で 無制約で配列にアクセスする シェーダを書けるからです それだけでいいんです!
次にバッファを確保その内容へのポインタを 正しいメッシュ構造体の型にキャストします
バッファが十分に大きくなり メッシュ構造体のサイズを- またいで単純なループ処理で バッファを走査します 最後に配列の各構造体のGPUAddressと必要なら アライメントされた オフセットを直接設定します
シェーダーでGPU 側から 未束縛の配列を表現する1つの方法です ここではメッシュポインター パラメーターとして宣言
これによりC言語の配列と同じように 自由に中身にアクセスできます
もう一つは未束縛の配列を 構造体に引き込むことです これでシェーダーは綺麗に データは一箇所に集約します この例ではすべてのメッシュと マテリアルがシーン構造体に まとめられています
シーン構造体を使用すると すべての非束縛配列を 個別に渡す代わりに単一のバッファをバインドし シーンをシェーダーに直接渡すことができます
アクセスも以前と同じですが メッシュ配列はシーン構造体 を通して到達しています Metal3での引数バッファと 非束縛配列の書き方でした APIが一新されCPUの構造体や配列に合わせた 直感的な操作が可能になりました 今年のアップデートではレイトレーシングの アクセラレーション構造を バッファやテクスチャと 一緒にMetal Heapから割当て可能になりました
つまりリソース同士や他のリソースと一緒に 集約できるのです 全ての加速度構造体をヒープに集約すると useHeap1回の呼び出しで全フラグを常駐可能 Appのレンダースレッドにおいて CPUを大幅に節約する大きなチャンスです
ここでヒープで加速度構造を 扱う際のヒントを紹介します まずヒープから割当てた場合 アクセラレーション構造には デバイス毎にアライメントと サイズ要件があります ヒープ割り当てのための 加速度構造体のサイズと アライメントをチェックする 新しいクエリーがあります 構造体記述子のSizeAndAlignmentは MTLDeviceのheap- AccelerationStructureSizeと AlignWithDescriptorメソッドを 用いて決定します MTLDeviceの accelerationStructure- Sizes WithDescriptor- メソッドとは異なることに注意ください
加速度構造体がMTLHeap- オブジェクトになったので useHeapを用い一回の呼び出しで常駐させます 個々に対しuseResourceを 呼び出すよりも高速です またヒープをハザード- トラッキングに選ばない限り Metalは割当てられたリソース の競合状態を防げません よってacceleration structureの ビルドを同期させ レイトレーシングの作業と 同期させる必要があります でもご心配なく後で説明いします
Metal 3におけるレイトレーシングの 性能向上の詳細については 「Metalレイトレーシングの パフォーマンスを最大限に高める」を ご覧ください ヒープに割当てられたacceleration structureを 用い 大事な時AppのCPU使用率を減らせます 最後に今年のお気に入りの機能をご紹介します シェーダー検証の強化です
useResourceとuseHeapについては 間接的にアクセスされる すべてのリソースに対して NappsがMetalに残留する フラグを立てることが重要 忘れるとレンダリング時に これらをバックアップする メモリページが存在しない可能性があります バッファ不具合 GPU再起動 画像破損などの危険です バインドレスではリソースの 大半は間接的にアクセスされ シェーダは実行時にポインタ ナビゲーションを決定する 残念ながらバインドレスでは こうした問題に遭遇する可能性が高い 今年のMetal3はシェーダー 検証レイヤーに新機能が 導入されバッファ実行時に リソースのレジデント不足を 突き止めることができるようになりました 具体例をお見せしましょう Hybrid RenderingAppのアップデート作業中に 反射がおかしくなる問題が実際に発生しました これにvalidation layerが どう役立ったかを紹介します
Metalにフラグを立てるため Appロード時にヒープに 個々のリソースを可変セットに格納します このAppはバッファ追加し テクスチャを追加します レンダリング時に Appの カーネルをディスパッチ前 全リソースに使用するとMetalに指示します Appが集合を繰り返し各要素に対して useResourceを呼出す単純な処理です Metalは全リソースを常駐させてから レイトレーシング作業を開始する Here’s part of the code where the app collects the resources into this set. Appがリソースを集めているコードの一部です App読込み機能は各サブ メッシュを繰り返し処理する 引数バッファに書き込む必要のあるデータ 素材用インデックスデータと テクスチャデータを取得し バッファのアドレスを 引数バッファに格納します 素材の場合はテクスチャの配列をループして GPUリソースIDを引数バッファに書き込みます 最後にサブメッシュの マテリアルからテクスチャを すべてsceneResourcesセットに追加し ディスパッチ時に常駐フラグを立てます
残念ながら微妙なバグが存在します Appがコマンドバッファを実行し 場合によっては反映が欠けることがありました これまで これを突き止めるのは大変でした Metal3ではシェーダー検証 レイヤーが解決してくれます コマンドバッファの実行中に発生したエラーの 何が問題なのかがわかるようになりました エラーメッセージは次のように表示されます 問題を引き起こしたシェーダー関数名 パス名 アクセスを検出したメタルファイルとコード行 さらにはバッファのラベルとサイズ 常駐していないことまでが表示されます Metalオブジェクトには ラベル付けをお勧めします ツールはラベルを使用する為Appのデバッグ中に それぞれのオブジェクトを特定できます このように詳細な情報が あればシェーダーコードに 不足しているリソースを簡単に発見可能です さらにデバッグブレークポイントが有効なとき Xcodeはシェーダーコードの 中でシェーダー検証が 問題を検出した正確な行を都合よく表示します この場合欠けているのは インデックスバッファです 単純な修正ですね コードの話に戻ると Appが常駐リソースセットに不足している インデックスバッファを 格納するようになりました これでレイトレーシング時に インデックスバッファを GPUから利用できこの問題が解決されました 必要不可欠なツールかつ バインドレスジャーニーに よるデバッグ時間を短縮する ゲームチェンジャーです Metal3ではバインドレスリソースの整理と 参照に役立つ機能が強化されました さて ここからは話題を変えバインドレス化で パフォーマンスを最大化する 方法についてお話します ここでは非保持リソースと 非追跡リソースの2つのトピックを取り上げます これ長寿命で集約的な リソースを使用する場合に CPUとGPUから高いパフォーマンスを引出します 長寿命リソースでCPU性能 を向上させる方法について まずリソースのライフ- サイクルをおさらいします Objective-CとSwiftでライフ サイクルを参照カウント Metalリソースはこのモデルを採用しています リソースはretainCountが1で始まり ランタイムは強い参照が なくなり次第リソースを解放 CPUとGPU は並列に動作しているため GPUが資源を使用時にCPUのretainCount が 0になってリソースが解放される問題があります
これを防ぐためMetalのコマンドバッファは 使用するすべてのリソースに 対して強い参照を作成し retainCountが常に1以上で あることを保証しています MetalはsetVertexBufferや setFragmentTextureなどの 関数でパイプラインに 直接バインドしたリソースに 対して強い参照を作成し これにuseHeap APIを介し 常駐フラグを立てたレンダーアタッチメント- Metalヒープオブジェクトも含まれます useResource APIを介し 常駐させた間接的リソースは ヒープの一部であっても使用できます Metalオブジェクトのライフ サイクルの詳細については Program Metal in C++- with metal-cppを参照ください Metalがこれらの参照を 作成すると非常に便利です プログラマーはGPUがまだ 使用中のオブジェクトを 解放するのではないかと 心配する必要がなくなります Metalが提供するこの安全保証は実行速度が 速いのですが若干のCPUコストがかかります 現在バインドレスモデルでは Appはリソースをヒープに 集約 ドメインにマッチした 長寿命なものになる傾向です 例えばゲームではリソースは 全レベルの間 生きています この場合Metalはリソースの ライフサイクルについて 追加の保証を提供する必要がなくなります このCPUコスト回収の為 Metal command buffersNotが 参照するリソースを保持する よう依頼することができます
Metalの自動リソース保持をオフにするには 非保持参照を持つコマンド バッファを作成するだけです 通常のコマンドバッファを 作成するのと同じように MTLCommandQueueから直接行えます すでにリソースのライフ サイクルを保証している限り Appに他の多くの変更を加える必要はありません この設定の最小粒度は コマンドバッファ全体で あることに注意ください 参照した全リソースを保持 又はまったくしないかです
小さなマイクロベンチマークでは 参照を保持しないコマンド バッファに切り替えるだけで ライフサイクルで2%のCPU使用率減少が可能です 小さな勝利ですがこの時間はすべて 不必要な強い参照作りと破棄 の繰返しに費やされました
要約するとリソースの 非保持化でライフサイクルを 保証している場合CPUを節約可能と言う事です 非保持リソースと同様に非追跡リソースは より高い性能を得るために 安全機能を無効化する機会を提供する 多くの視覚技術は中間 テクスチャへレンダリングと バッファへ書込み後のパスで それを消費する構成です シャドウマッピング スキニングなどがその例です しかしリソースを生成してすぐに消費すると リード・アフター・ライトの 危険性が発生します さらに複数のパスが同じ リソースに書き込む場合 例えば2つのレンダーパスが同じ添付ファイルに 次々と描画したりブリットエンコーダーが2つ 同じリソースに書き込んだりする場合です GPUのMetalスケジュールの動作に起因する write-after-writeハザードが発生するからです トラッキングされたリソース を使用する場合Metalは 自動で同期プリミティブを 使用しハザードを回避します 例えばMetalはスキニング計算 パスがバッファへの書込みを 終了するのをGPUに待たせてから 同バッファから読込むシーン レンダリングパスを開始する
素晴らしいですね MetalがgraphicsAPIである 理由の大部分を占めますが リソースをヒープに集約する Appのパフォーマンスに- ついてはいくつか考慮すべき点があります
この例で考えてみましょう ここではGPUがビジー状態になっています スキニング レンダリングトーンマッピングを 行う2つのフレームを順番に描画します AppがGPUを使用し続けることでMetalは 従属性からレンダリングと 計算作業が重なる機会を特定 従属性なく条件が整えばメタルスケジュールは 重なり合い並行で動くようになります これでGPUは飽和状態へ同じ壁面クロック時間で より多くの仕事をこなせるようになります
これでAppがリソースをヒープに集約すると サブリソースがMetalに1つとして表示されます これがヒープの作業効率の良さです しかしMetalが同リソースの 読み書きの作業を担当する事 意味 実際に危険が無くても レースコンディションを 避け保守的に作業をする必要があります
この状況は偽共有と呼ばれ予想通り GPU作業の処理時間を増加させます そこでパフォーマンスのヒントを紹介します ヒープ内のリソース間に従属性がない場合 この操作を回避することができます
誤共有を避けリソースを ハザード・トラッキングから 外し細かい従属性を直接Metalに伝達します リソース記述子のhazardTracking プロパティをUntracked に 設定 リソース追跡をオプトアウトできます これは非常に重要なことなので ヒープのデフォルト動作とし ゲートからすぐGPUで 作業を並列実行する機会を増やせます 未追跡のリソースを使用するようになると プリミティブを使用して従属性を表現します 状況に応じFences Event Shared Events Memory Barrierを使用 Metal Fencesは1つのコマンドキュー内で 異なるレンダーパスやコンピュートパス間で 1つ以上のリソースへのアクセスを同期させます スプリットバリア方式のプリミティブで プロデューサがフェンスの シグナルを出すまで待ちます
Fencesを使用する際に注意する点は producerコマンドバッファを consumerコマンドバッファより 先にcommitまたはenqueueすることです この順序を保証できない場合 あるいは同一機器上の複数のキューを 同期させる必要がある場合は MTL Eventsを使用します Eventを使用するとconsumerコマンドバッファは producerコマンドバッファが 与えられた値での通知を待つ 値を通知した後リソースを 読み出しても問題ないです コマンドが通知するまで一時 停止するようGPUに指示 MTLSharedEventsは通常の Eventとよく似た動作をするが 単一のGPUより大きなスコープで動作します これを使い異なるMetalデバイス間さらには CPUとの間でリソースへのアクセスを同期させる 例えばGPUの計算結果をCPUから処理する場合は Shared Eventsを使用します 以下はその一例です GPUはコンピュートパスで メッシュをスキニングし CPUはディスクにポーズを保存します 2つは独立したデバイスなので GPUがShared Eventを 使ってリソース生成するまで CPUが待機するように設定 CPUは無条件にGPUからの Shared Eventシグナルを待ち始めます GPUがリソースを生成して ユニファイドメモリに配置 Shared Eventを通知します ここでCPU上で待機するスレッドが立ち上がり 安全にリソースを消費する
最後のプリミティブタイプはメモリバリアです これは1つのレンダリング またはコンピュートパス内の 後続コマンドを前コマンドが 終了するまで待機させます バリアのコストは大抵 フェンスのコストと同様です しかし一つ例外があります
レンダーパスのフラグメント ステージ後のバリアです これらのバリアはレンダーパスを分割するのと 同じような非常に高いコストを持っています MetalはAppleGPUのフラグメントステージ以降の バリアを無効化 Appを最速 ドライバパスに留めます アフターフラグメント-バリアを追加すると Metalのデバッグ層は 検証エラーを発生させるほど フラグメントステージ以降の リソースの同期には フェンスを使用することが推奨されます
ここで同期プリミティブについて どのような場合に使うかを簡単にまとめます Producer Consumerの順で 一つのコマンドキューに コミットかエンキューする際 オーバーヘッドを最小限に- するために Fencesを使用をお勧めします フェンスは一般的なケースの大半に最適です 送信順序が保証できない場合 複数のコマンドキューが ある場合はMetal Eventsを使用します Shared Eventsは複数のGPU間 およびCPUとの同期を可能にします 特定のマルチデバイスの 場合にのみ使用ください パス内で同期を取る場合は メモリバリアを使用します 同時計算パスやドロー- コール間の頂点ステージなど ほとんどの場合において高速に動作します ただしフラグメントステージ 後の同期にはバリアではなく パス間のフェンスを 使用することをお勧めします バリアはコストが高くApple GPUは許容できません
非追跡のリソースと手動での 細かなトラッキングにより GPUの並列性を最大限に活用しながら データ集約のあらゆる利点を 享受出来る様になりました 以上がバインドレス化の際にCPUとGPUの性能を 最大限に引き出すためのコツです これまでMetal3がいかにシンプルで効率的な ワークフローを実現するか 何度もお話ししてきました しかしコードは方程式の半分に過ぎないのです もう半分は利用可能なツールを使って GPUが何を見て仕事を 実行するか検証することです ここからはMayurにバインドレス用 Metal3ツールの新情報を説明してもらいます ありがとう Alè 今日はMetal Debuggerの 新機能のうちバインドレス- Appのデバッグと最適化に役立つ話をします 先ほどAlèが示したHybridRenderingAppの フレームキャプチャを撮影してみました Metal Debuggerでフレームキャプチャすると Summaryページが表示され フレームの概要とAppのパフォーマンスを 向上させる方法に関する 有益な情報が提供されます でも今日は新しい\従属性 ビューアーを紹介します 左側のDependenciesをクリックください 新しい従属性ビューアーは強力な新機能を 満載した全く新しいデザインを採用しています 従属性ビューアーではワークロードを グラフで表示することができます グラフの各ノードはコマンドエンコーダで 符号化されたパスとその出力リソースを表す エッジはパス間のリソース従属性を表す 今年から新たに2種類の従属性に着目して ワークロードを分析できる-ようになりました データフローと同期です 実線はデータの流れを表しAppの中でデータが どのように流れているかを示しています 点線は同期を表し パス間でGPUの同期を導入する従属性を示します 詳細は任意のエンコーダー リソース エッジをクリック デバッガーがサイドバーに 詳細情報を表示します 例えばこのエッジは同期を追加し またこれらのパス間のデータフローを持つ デフォルトでは従属性ビューアには データフローと同期 両方の 従属性が表示されます しかしこの下にあるメニューを使えば 従属性のタイプを1つに絞ることができます ここでは同期だけに絞って説明します Alèが述べたようにtracked heapから異なる リソースを読書きする場合 false sharingが問題です 従属性ビューアーを使えば 問題を簡単に発見できます キャプチャした このデモはこの問題がある 開発初期のバージョンです このヒープをクリックすると従属ビューアーに このヒープが追跡されている ことが表示されるので これらの2つのパスの間に同期が追加されます 従属性ビューアはエンコーダーが保存する ターゲットテクスチャーや エンコーダーが読書きする バッファなど割当てられた リソースも強調表示します 問題はエンコーダが以前のエンコーダからの リソースを未使用で2つの パス間同期が不必要な事です この従属性を消すにはAppを修正し非追跡ヒープ を使用し 同期が必要な場所にFencesを挿入 この変更により2つのパスが並列に動作します Xcode14ではバインドレスAppのデバッグに 役立つ他の改良点は 新しいリソース・リストです デバッグするドローコールに 移動し開くことができます バインドレスを使用する場合GPUは常に数百 数千のリソースを利用できます 今年のMetalデバッガでは 上部のAccessedモードを クリックするだけでドローコールがこれらの リソースのどれにアクセスしたか確認できます デバッガにはドローコールが アクセスするリソースと 各アクセスのタイプのみ 表示されるようになりました これはシェーダーが引数 バッファからどのリソースに アクセスしたかを理解するのに便利です ドローコールが使用する リソースの把握は重要ですが 予期しないリソースが表示された場合 シェーダーデバッガーの状況を把握できます シェーダーデバッガーを起動するには ボトムバーのデバッグ-ボタンをクリックし デバッグしたいピクセルを選択して デバッグボタンをクリックするだけです そして今シェーダー-デバッガーにいます シェーダーデバッガーは コードがどう実行されたかを どのリソースにアクセス- したかを含めて一行ずつ表示 このシェーダは引数バッファ からテクスチャを読込む 右サイドバーの詳細ビューを展開すると どのリソースが読まれたかを 確認することができます これはシェーダが間違った引数バッファ要素に アクセスする問題を特定するのに役立ちます このデモでは新しい従属性ビューアーを使って リソースの従属性を分析・検証する方法 新しいリソースリストを使って描画コールが アクセスしたリソースを理解する方法 そしてシェーダー-デバッガを使ってシェーダー の実行方法を1行ずつ 分析する方法を紹介しました これらの新機能を使って皆さんが素晴らしい メタルバインドレス- Appを作るのか楽しみです 再びAlèに託します ありがとうMayur素晴らしいデモでしたね Metal3はバインドレス実現に役立ちます 引数バッファの簡略化 ヒープからの加速度構造 検証層Nandツールの改善など Metal 3はゲームやAppに効果的で ハイパフォーマンスの バインドレスを実現します 今年の機能強化でHybrid- Rendering Appが改善されました この最新版のAppは Metal sample code galleryで 完全なソースコード付きで公開されています これをダウンロードして勉強し修正し さらに練習として鏡面に再帰的な 反射を加えることに挑戦してみてください 皆さんの活用が楽しみです Metal3でバインドレスを 実現する絶好の機会です ご視聴ありがとうございます
-
-
5:38 - Write argument buffers in Metal 3
// Write argument buffers in Metal 3 struct Mesh { uint64_t normals; // 64-bit uint for constant packed_float3* }; NSUInteger meshArgumentSize = sizeof(struct Mesh); id<MTLBuffer> meshArgumentBuffer = [device newBufferWithLength:meshArgumentSize options:storageMode]; struct Mesh* meshes = (struct Mesh *)(meshArgumentBuffer.contents); meshes->normals = normalBuffer.gpuAddress + normalBufferOffset;
-
6:31 - // Shader struct:
// Shader struct: struct Mesh { constant packed_float3* normals; }; // Host-side struct: struct Mesh { uint64_t normals; };
-
6:53 - Shared struct:
// Shared struct: #if __METAL_VERSION__ #define CONSTANT_PTR(x) constant x* #else #define CONSTANT_PTR(x) uint64_t #endif struct Mesh { CONSTANT_PTR(packed_float3) normals; };
-
7:53 - Write unbounded arrays of resources in Metal 3
// Write unbounded arrays of resources in Metal 3 struct Mesh { uint64_t normals; // 64-bit uint for constant packed_float3* }; NSUInteger meshArgumentSize = sizeof(struct Mesh) * meshes.count; id<MTLBuffer> meshArgumentBuffer = [device newBufferWithLength:meshArgumentSize options:storageMode]; struct Mesh* meshes = (struct Mesh *)(meshArgumentBuffer.contents); for ( NSUInteger i = 0; i < meshes.count; ++i ) { meshes[i].normals = normalBuffers[i].gpuAddress + normalBufferOffsets[i]; }
-
9:03 - Metal shading language: unbounded arrays option 1
// Metal shading language: struct Mesh { constant packed_float3* normals; }; fragment half4 fragmentShader(ColorInOut v [[stage_in]], constant Mesh* meshes [[buffer(0)]] ) { /* determine mesh to read, e.g. geometry_id */ packed_float3 n0 = meshes[ geometry_id ].normals[0]; packed_float3 n1 = meshes[ geometry_id ].normals[1]; packed_float3 n2 = meshes[ geometry_id ].normals[2]; /* interpolate normals and calculate shading */ }
-
9:25 - Metal shading language: unbounded arrays option 2
// Metal shading language: struct Mesh { constant packed_float3* normals; }; struct Scene { constant Mesh* meshes; // mesh array constant Material* materials; // material array }; fragment half4 fragmentShader(ColorInOut v [[stage_in]], constant Scene& scene [[buffer(0)]] ) { /* determine mesh to read, e.g. geometry_id */ packed_float3 n0 = scene.meshes[ geometry_id ].normals[0]; packed_float3 n1 = scene.meshes[ geometry_id ].normals[1]; packed_float3 n2 = scene.meshes[ geometry_id ].normals[2]; /* interpolate normals and calculate shading */ }
-
11:00 - Size and alignment for MTLAccelerationStructure in a MTLHeap
heapAccelerationStructureSizeAndAlignWithDescriptor:
-
13:49 - Store individual indirect resources in NSMutableSet
// Argument buffer loading for (NSUInteger i = 0; i < mesh.submeshes.count; ++i) { Submesh* submesh = mesh.submeshes[i]; id<MTLBuffer> indexBuffer = submesh.indexBuffer; NSArray* textures = submesh.textures; // Copy index buffer into argument buffer submeshAB[i].indices = indexBuffer.gpuAddress; // Copy material textures into argument buffer for (NSUInteger m = 0; m < textures.count; ++m) { submeshAB[i].textures[m] = textures[m].gpuResourceID; } // Remember indirect resources [sceneResources addObject:indexBuffer]; [sceneResources addObjectsFromArray:textures]; }
-
-
特定のトピックをお探しの場合は、上にトピックを入力すると、関連するトピックにすばやく移動できます。
クエリの送信中にエラーが発生しました。インターネット接続を確認して、もう一度お試しください。