View in English

  • メニューを開く メニューを閉じる
  • Apple Developer
検索
検索を終了
  • Apple Developer
  • ニュース
  • 見つける
  • デザイン
  • 開発
  • 配信
  • サポート
  • アカウント
次の内容に検索結果を絞り込む

クイックリンク

5 クイックリンク

ビデオ

メニューを開く メニューを閉じる
  • コレクション
  • トピック
  • すべてのビデオ
  • 利用方法

その他のビデオ

ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。

  • 概要
  • トランスクリプト
  • OpenGL AppをMetalに移行する

    MetalはAppleプラットフォームでGPUによる高速なグラフィックス処理と演算を行うための最新の基盤であり、OpenGL、OpenGL ES、OpenCLに代わるものです。このセッションでは、Metalのアーキテクチャと機能、およびOpenGLベースのAppをMetal APIに移行するための詳しいアプローチを紹介します。

    リソース

    • Metal
    • Migrating OpenGL Code to Metal
      • HDビデオ
      • SDビデオ
    • プレゼンテーションスライド(PDF)

    関連ビデオ

    WWDC21

    • EDRによるHDRレンダリング

    WWDC19

    • プロフェッショナル向けのAppのためのMetal
    • 機械学習のためのMetal
    • Metalによるレイトレーシング
    • Metalによる最新のレンダリング
    • MetalのAppとゲームを最適化する
  • このビデオを検索

    (音楽)

    (拍手) Metalのセッションへようこそ GPU ソフトウェアパフォーマンス チームのライオネルです 私とサラとマックスで OpenGL AppをMetalへ移行する 方法を紹介します

    昨年 OpenGL OpenGL ES そしてOpenCLが 非推奨になると発表しました iOS 13とmacOS Catalinaでの サポートは継続されますが 先を見据えましょう 新しいプロジェクトは Metalで始めましょう 既存のOpenGL Appを Metalへ移行したいなら このセッションが役立ちます

    2014年に初めて発表されたMetalは 低オーバーヘッドで高効率 高性能な GPUのプログラミングAPIです

    この5年で Appleの主要なフレームワークは Metalに対応しました よい成果も出ています もしアプリケーションが SpriteKitやSceneKit Core ImageやCore Animationを 使っているなら すでにMetalを使っています

    エンジンのベンダとも協力しています UnityやUnreal Engine 4 Lumberyardなど Metalをうまく生かせます これらのエンジンを使っているなら よくご存じでしょう

    もし独自のレンダラーを 作成している場合 Metalはとても有効です MetalはOpenGLとOpenCLの 機能を兼ね備えた― Unified APIです アプリケーションにマルチスレッド レンダリングを可能にします CPUのオペレーションに 大きな負荷がかかる場合 アプリケーションの実行中 オーバーヘッドを減らす努力をしてます

    Metalのシェーディング言語は C++言語です アプリケーション内のシェーダは すべてプリコンパイルされます 例えば 幅広い種類のシェーダが 簡単に使えます

    そして大事なのは デバッグツールと最適化ツールが Xcodeに組み込まれていること Metalへ移植すれば フルサポートを受けられます このセッションでは いくつかのステップをご紹介します OpenGLからMetalへの移行について― アプリケーションを比較して 説明します 概説として 簡単に OpenGLのアプリケーションを見ましょう まずレンダリングに使う ウィンドウをセットアップします 次にバッファやテクスチャなどの リソースを作ります GLSLで書かれたシェーダを 実装します GLでレンダリングする前に オブジェクトのステートが必要です 例えばGLプログラム フレームバッファオブジェクト 頂点配列オブジェクトなどです

    リソースを初期化したら レンダーループが動き フレームが書けます

    それぞれのフレームでは リソースのアップデート フレームバッファの結びつけ グラフィックステートの設定 ドローコールを決めます これをフレームバッファごとに 行います シャドウマップやライティングパス ポストプロセスなどがあるでしょう

    そして最後に 最終出力イメージが現れます 簡単ですね Metalの順序も似ています オリジナル部分の更新情報と 新たな仕様も紹介します 順序に大きな違いはありません 同じような方法で 使うことができます

    私たちは新しいコンセプトを 再導入しました OpenGLとMetalの並行性を保ち 2つのAPIを上手く移行させるためです

    グラフィックのチュートリアルで 最初に学ぶのは ウィンドウの作成方法です ウィンドウ サブシステムから 始めましょう GLもMetalも同じコンセプトですが 実行方法は少し違います

    アプリケーションに必要なのは ドローイングサーフェスの構成です ビューとビューデリゲートは APIとウィンドウシステムの下層間の インターフェイスを対処します

    GLに対応するため これらの フレームワークを使っているなら 同等のフレームワークが Metalにあります NSOpenGLViewやGLKViewは MTKViewへマップできます EAGLLayerと一緒に Core Animationを使用してる場合 CAMetalLayerを使用できます

    例としてGLKViewを使います エントリポイントは1つです 最後のフレームから解像度が 変わっていないか確認し 必要ならレンダーループで サイズの修正ができます Metalkitでは少し違います drawableを変更したい場合 別の関数があります スクリーンの回転や ウィンドウのサイズ変更ができます ドロウファンクション内で リソースの再配置が必要か チェックしなくても コードに組み込まれています

    さらに順応性を求めるなら CAMetalLayerが提供されています 表示のバッキングレイヤとして 使えます CAEAGLLayerは属性が定義されています カラーフォーマットなどです CAMetalLayerで構成できるのは drawableのサイズ ピクセルフォーマット 色空間などです CAMetalLayerは膨大なテクスチャを 保持してます 次のdrawableをコールし フレームに表示します 重要なコンセプトなので 後ほど詳しく話します

    ウィンドウの完了です 次はMetalでの 新しいコンセプトについて コマンドキュー コマンドバッファ コマンドエンコーダです これらのオブジェクトはMetal内で 同時にGPUへ働きかけます openGLContextの基礎は サブミッションを行います

    openGLは潜在的なAPIです いつ作動するかを示す コードはありません デベロッパはグラフィックの働きを あまり管理できません シェーダはコンパイルされ リソースストレージが割り当てられ 妥当性確認が行われ GPUが実際に実行します openGLContextは 大きなステートマシーンで 典型的なワークフローは こちらです アプリケーションが openGLContextを生成 スレッドにセットし任意の OpenGLコメントをコールします コメントはコンテキストで記録され ある時点で実行されます これを詳しく見てみましょう アプリケーションが これらのコールを送りました ステートの変更とdrawのコールです 完璧なシナリオはコンテキストが GPUコメントに変換され 内部バッファへ蓄積されます これが溜まるとGPUへ送られます 実行のためにglFlushを書き込んだ場合 その時点で実行されます GPUはその前でも 実行することが可能です 例えば― このdrawコールに 依存関係を持たせます この時点でプログラムは実行されます ひどい機能停止に陥ります プログラムが提出されるかは 場合によります OpenGLの欠点の1つですね パフォーマンスに一貫性がありません 小さな修正でスムーズになります

    Metalは明示的なAPIです どの作業をいつ実行するか アプリケーションで決められます

    MetalはopenGLContextを 内部のワーキングオブジェクトに 分割するコンセプトです アプリケーションが最初に生成する オブジェクトは MTLDevice オブジェクトです GPUの抽象的表現です 次はオブジェクトのキーの MTLCommandQueueです コマンドの順番を そのままGPUへ送ります コマンドバッファの形で送られます コマンドバッファは GPUが実行するコマンドのリストです これがOpenGLでの コマンドバッファの概念です もう少し詳しく見てみましょう

    アプリケーションは 直接 コマンドバッファへ指令を渡さず MTLCommandEncoderを 作成します 3つの主なエンコーダを紹介します まず MTLBlitCommandEncoder リソース周辺のコピー処理を行います

    コマンドエンコーダはAPIコードを GPUの命令に変換します そしてコマンドバッファへ 書き換えられます 例えばリソースのコピー処理の ブリットなど 一連のコマンドが エンコードされます するとエンコードが終了し エンコーダオブジェクトが放出されます

    また MTLComputeCommandEncoderは OpenCLと同様の 並列演算処理を行います いくつかのカーネルをエンキューし コマンドバッファへ書き換え エンコーダを解放します

    3つ目は MTLRenderCommandEncoderです ステートの変更やdrawのコールを エンキューしエンコードします

    残ったのはコマンドバッファです ワークロードは溜まっていますが GPUはどの作業も実行していません Metalはオブジェクトと エンコードされたコマンドを CPUで作成します アプリケーションが コメントのエンコードを終えると コマンドバッファが 明確な指示を出します GPUはそれらのコマンドを実行します エンコードされたコマンドです OpenGLとMetalを比べてみましょう OpenGLはGPUに対して 直接のコントロール力がありません glFlushやglFinishなどの コードに頼るのみです glFlushはコマンドの実行を 予定した時に強制させます glFinishはGPUの処理が 完全に履行されるまで待ちます これらのコマンドの前に 処理が行われる場合もあり 機能停止や失速につながります Metalは同等のファンクションを提供し 明確に実行のコントロール力を 得られます コマンドを待機させることは 必要ない限り お勧めしません 代わりにコマンドバッファを利用し コールバックを追加してください コマンドバッファの実行の完了後 アプリケーションに通知されます その間 CPUは他の動作ができます

    コマンドキュー コマンドバッファ コマンドエンコーダを紹介しました 次はリソースの説明です

    グラフィックアプリケーションには 主に3つのリソースがあります バッファ テクスチャ サンプラーです まずバッファを説明します バッファオブジェクトにはメモリが 関連付けされています APIのコードで オブジェクトステートとメモリを 変更することが可能です

    例えばglBufferDataを使うと オブジェクトとメモリの修正ができます バッファの寸法もglBufferDataで 変更できます 古いオブジェクトや そのコンテンツも OpenGLによって内部的に破棄されます

    MetalではAPIは似たバッファを作ります しかし一番の違いは 作られるサブジェクトが 変更不可なのです バッファをリサイズする場合 新規に作成し 古いものを破棄します

    OpenGLもMetalも オブジェトを使う方法を 指し示す方法があります しかしOpenGLのusage enumは バッファオブジェクトのデータが どうアクセスされたかのヒントです ドライバはヒントを基に メモリの最適な置き場を決めます しかしストレージを直接 コントロールできません OpenGLが最終的な決断をします

    MetalではAPIによる ストレージモードが提供され 特定のメモリがパターン化され 分配されています Metalはあなたに コントロール権を与えます オブジェクトクリエーションにおいて 重要な考えです テクスチャを説明したあと こちらを詳しく説明します

    OpenGLのテクスチャには 内部サンプラーオブジェクトがあります サンプリングモードは サンプラーを通してセットします また テクスチャの外に サンプラーオブジェクトを作れます テクスチャの作成と結合の例です サンプラーをセットし 最後にデータを書き込みます

    OpenGLには多くのAPIコールがあります データと一緒に 初期化テクスチャを作ります リソースを指定する バージョンもあります サンプラーの管理になると さらに増えます 果てしない量です

    Metalのデザインのゴールは サンプラーAPIがすべての柔軟性に 対応することです Metalのテクスチャとサンプラー オブジェクトはバラバラで 作成後は変更できません

    テクスチャの作成には ディスクリプタを作成します pixelFormat など テクスチャの大きさを定める― プロパティを書き込みます 重要なプロパティは ストレージモードです テクスチャの保存場所を定めます そしてディスクリプタを使い 変更不可のオブジェクトを作成します

    まずサンプラーディスクリプタから プロパティを書き込み 変更不可のサンプラーオブジェクトを 作る方法もあります

    テクスチャの画像の大きさは bytesPerRowで設定します OpenGLと同じように ロードするための領域を設定します テクスチャのreplaceRegionを使い 指定したポインタから データをテクスチャへコピーします

    最初のテクスチャをロードすると 上下が逆になります Metalではテクスチャの座標が Y軸になるのが原因です さらにMetal APIはシステム内部で pixelFormatの変形は 遂行しません 必要なテクスチャフォーマットの アップロードが必要です

    ストレージモードに戻ります OpenGLではドライバの選択で リソースの使い方が決められます レンダーバッファオブジェクトなどを 作成し ヒントを与えることは可能です しかし それはヒントにすぎず 実装の詳細は知ることができません

    数分前にMetalのストレージモードを 紹介しました テクスチャディスクリプタを設定し バッファを作成することもできます 実際の例を見てみましょう 一番簡単なのは 共有ストレージモードです CPUとGPUの両方が リソースにアクセスできます バッファはオブジェクトの メモリバックを ここへ合せます iOSのテクスチャは 便利なファンクションをコールし イメージデータを設定し取り出せます

    プライベートストレージモードも 使えますが GPUのみのアクセスになります 普段CPUからの アクセスが不要なものなら Metalの最適化が期待されます

    データのコンテンツを埋められるのは GPUだけなので blitEncoderを使えばCPUからも データが埋められます 共有ストレージを使い 第2中間リソースにアクセスできます

    音声はビデオメモリ専用です プライベートストレージに 保存されたデータは ビデオメモリのみに 割り当てられます

    macOSには マネージドストレージモードがあり CPUとGPUからアクセスできます ビデオメモリ専用のシステムでは 効率のよいアクセスのため ミラーメモリの作成が必要になります データを同期させるため 明示的なコードが必要になります 例えばdidModifyRangeなどです

    それぞれのストレージモードの 説明をしました macOSでは 静的アセットと レンダーターゲットのため プライベートストレージを使います 小さい動的なバッファは 共有ストレージモード 容量が大きく 更新が少ない場合は マネージドストレージモード

    iOSでの静的アセットと レンダーターゲットは プライベートストレージ ディバイスが統合メモリや 様々なサイズの動的データの場合 共有ストレージが有効でしょう

    次はグラフィックアプリケーションの シェーダの向上と 該当するAPIの紹介です

    OpenGLでのシェーダのコンパイルには シェーダオブジェクトを作成します そしてglShaderSourceの置き換えと compilationのJITと 検査が必要になります このワークフローには 利点がありますが シェーダをコンパイルするたびに パフォーマンスコストがかかります

    Metalでそれを効率よく進めるには 手早く 少ない頻度で行うことです ビルド時 Xcodeはすべての MetalのshaderSourceを デフォルトMetalライブラリファイルに コンパイルします ランタイム時の回復のため アプリケーションのバンドルへ加えます そのためランタイム時の コンパイルが避けられ コンパイルの時間を削り アプリケーションの負担も減ります 手順はアプリケーションの バンドルから Metalライブラリを作成 そこからシェーダファンクションを 取り込みます

    OpenGLはC言語をベースにした GLSLを使います Metalのシェーディング言語は C++がベースです OpenGLデベロッパにも なじみがあるでしょう C++の構成はクラス テンプレート 構造体などです enumやnamespaceも定義できます GLSLではvectorとmatrix型が 埋め込まれています グラフィックに使えるオペレーションが 多数組み込まれ テクスチャやサンプラーのクラスも 埋め込まれています

    MSLもグラフィックや計算に 向いています シェーダはコンパイル済みならば Xcodeがエラーや警告 ガイドを知らせてくれます

    MSLの実際のコードを見て GLSLと比べてみましょう シンプルな頂点シェーダで行います GLSLが上でMSLが下です

    まずプロトタイプのシェーダです GLSLはvoid main シェーダステージを 指定するものはありません glCreateShaderのコールで シェーダを確定します MSLではシェーダコードで シェーダステージを確定 vertex qualifierは それぞれのvertexでの 完璧なアウトプット実行を 示しています

    GLSLでは どのシェーダの 入り口点もmainでコールします コマンドを受け取りvoidへ戻ります MSLの各入り口点には 異なる名前があります Xcodeでシェーダを組み立てる場合 コンパイラは前処理でインクルードし 分割できます C++のコードと同じです ランタイム時にはコンパイルされた Metalライブラリから 名前で関数の照会が可能です

    次はインプットです GLSLはどの入り口点にも main関数があります すべてのインプットは 広範囲の実引数として渡されます Vertex属性と一様の変数に 当てはまります

    Metalでは シェーダステージの すべての入力は エントリ関数の実引数です 二重の角かっこは C++の属性です

    インプットの1つは 射影行列のモデルビューです

    OpenGLでは データを変数に結合するために C++のコードに含まれるGLSLの名前に 注意が必要です 間違いが起こりやすい場所です

    MSLでは均一統合のため 指標はデベロッパによって 明確にコントロールされます アプリケーションは 特定のスロットと結合します サンプルではスロット1です ここで重要なのは モデルビューのプロジェクションが すべてのvertexへ一定になるよう 意図していることです

    シェーダのための別のインプットは vertex属性です GLSLでは別々の属性の インプットを使います MSLは独自にデザインされた構造が 使われます シェーダの どの呼び出しにも 独自の変数を受け取ります

    すべてのインプットを シェーダに書き込めば すべての計算を遂行できます

    GLSLのアウトプットは glTexCoordなどの可変の属性と 既定の変数に分かれます この場合gl Positionです

    MSLでvertexシェーダのアウトプットは 独自の構造になります

    vertexとvertexアウトプット構造です スクロールしてMSLがどうなったか 見てみましょう

    GLSLではインプットのvertex属性が 別に定義されています Metalはそれらを 構造内で確定しています

    MSLではvertexシェーダのインプットで 各ストラチャの要素に キーワードの属性があります 各属性に振り分けられます GLSLと同じように これらの指標は Metal APIで使われ vertexバッファストリームから vertex属性に割り当てられます

    GLSLには特別なキーワードの 定義があります gl Positionはモデルの 射影に変換される― 頂点座標の変数を表します MSLのvertexアウトプットも同じように vertexシェーダアウトプットの 信号を送る― 特別なキーワードの位置は 構造体メンバの中です

    GLSLのvectorタイプと同じで MSLはSIMDタイプを定義します simd.hヘッダはCPUとGPUの コードを共有できます しかし注意が必要です バッファのvectorとmatrixタイプは 16バイトです 半精度では8バイト あまり詰め込まれていません float3は12バイトあり アラインされると16バイトです データがCPUとGPUに最適に アクセスできるよう注意が必要です 必要ならBackedFormatもあります 使用する前にシェーダ内で アンパックする必要があります

    GLSLとMSLの主な違いを 説明しました この移行をスムーズに 簡単に行うために マックスが すばらしいツールを 紹介します どうも (拍手)

    こんばんは

    Metalは 単なるAPIや シェーディング言語ではありません ツールの強力な集合体です 私はマックス Metalへの移植の手助けをします

    スクリーンを見てください 古いOpenGLで作成された ドローコールです Metalへ移植しました 神殿と木をドローイングしたもので 全体が光で照らされています フラグメントシェーダを移行しましょう

    まずOpenGLコードをコピーし Metalシェーダファイルへ ペーストしました すでにインプット構造体が できています 関数の原型もです 始めましょう まずはコンテンツの メインの関数をコピーし Metalの関数へ直接 貼ります ここでMetalの有能さが表れます シェーダはコンパイルされているため すぐエラーが起きます 詳しく見てみましょう

    vectorタイプの名前が違っています vec2をfloat2に修正します vec3をfloat3へ vec4はfloat4です 瞬時に修正できました

    次のエラーはインプット構造体です グローバル変数は 移行元の構造のままです 似ている命名規則を使うので簡単です

    uniformでも同じ修正が必要です

    次はもう少し複雑です Metalのsampleも異なっています 1から始めましょう sample関数を colormapから直接 選びます ご覧のとおり すべて選ぶだけです この関数ではsamplerとtextureを 選ぶよう指示されます textureは入力済みです 関数の変数としてsamplerを 渡すことも可能です またはコードで宣言することも可能です こうします

    normalMapでも同様に作業します

    最後のエラーは OpenGLで定義した多くの変数です 最終的な計算された色に戻します

    他にも色々な関数があります normalizeやdot product 私のお気に入りのmaxは まったく同じです シェーダの移植が完了しました 表示します

    何かが変ですね

    OpenGLでシェーダの エラーがあった場合 ソースコードを確認するのが 一般的でしょう アウトプットを見て 懸命に考えるでしょう ここではシェーダの デバッガーを使います

    カメラのアイコンをクリックします GPUの痕跡を入手します

    Metal APIがコールした すべての記録です ドローコールを確認していきます こちらが木の画像 こちらは神殿です

    神殿の階段で長押しします ピクセルインスペクタが シェーダをデバッガーします

    こちらをご覧ください 移行したコードのラインごとの値と 選択したピクセルの値です colorMapを見てみましょう

    適当なtextureと言えます 階段も上半分のtextureは よさそうです しかしtextureの座標を見てみると 下半分を選んでいるようです 検証してみましょう textureのY座標をひっくり返します

    そしてシェーダを更新します よさそうです 修正を続けます さらに よくなりましたね

    今のはOpenGLから Metalへ移植する際の 典型的なエラーです テクスチャローディングコードを確認し 座標の原点が正しいか確かめましょう 1つ1つ修正する手間が省けます 機能に富んだエディターと 強力なデバッギングが ゲームをMetalへ移行する 手助けになるでしょう

    ありがとう 残りのスライドはサラが説明します (拍手) マックス どうも サラ・クラウソンです Metalへの移植方法の 続きを説明します

    グラフィックアプリケーションでは 多くの設定がありました ウィンドウやコマンドの準備 リソースとシェーダの設定もありました 次はステートを設定するための レンダーループです

    OpenGLはステート管理において いくつか重要な概念がありました 頂点配列オブジェクトはvertex属性の レイアウトとバッファを定義 プログラムはvertexと フラグメントシェーダを連結 フレームバッファは アプリケーションがレンダリングする 色と深度ステンシルの組み合わせです これらのステートオブジェクトは 初期設定時に作られ フレームをとおして使われます

    OpenGLのステートの 管理方法を話します

    レンダーループです OpenGLがフレームバッファを結合させ プログラムや ステートの修正を行っています Enabling DepthやFace Culling ドローコール前のcolorMap の 変更などです

    OpenGLの視点から APIトレースを見てみると APIコールのすべての変更を たどる必要があります ドローコールが起こると 停止してしまいます Primitive AssemblyやDepth Stateなど 前の修正が正当か 検査する必要があります 確認には大きな負荷がかかります OpenGLが衝撃を 最小限にしようとするため 制限が大きくなります

    OpenGLのステートオブジェクトは 発表当初は画期的でした

    フレームバッファオブジェクトは レンダーターゲットと統合され プログラムはvertexと フラグメントシェーダを連結 頂点配列オブジェクトは vertex属性APIやvertexバッファなど 大きなオブジェクトを結合します これらの変更で ポジティブな結果を生み出しても OpenGLはドローコールで 多くの検査が必要となります

    ColorMaskがフラグメントシェーダを 最適化できるか フラグメントシェーダのアウトプットと フレームバッファの互換性は?

    vertexレイアウトと 連結されたプログラムの互換性は? 付属されたレンダーターゲットは 混合可能なのか

    Metal用に再設計された グラフィックステート管理では 頂点配列オブジェクトから 頂点レイアウトと結合された― プログラムシェーダを取り出します pixelFormatやBlendStateの 情報と一緒に MTLRenderPipelineDescriptorという 1つのオブジェクトにします 構造体はGraphicsPipelineに関わる すべてのステートを記述しています ディスクリプタを構成するには 初期化します 今説明したステートを設置します vertexとフラグメントシェーダ vertex情報やpixelFormat BlendStateなどです

    その後 ディスクリプタを使って PSOを作成します この不変オブジェクトは レンダーステートを説明しています 1度作成すれば 正当性の検査も1度で終わり プログラムをとおして使えます

    またはDepthとStencil関連の セッティングをまとめて MTLDepthStencilDescriptorに 統合します これらはすべて 深度ステンシル ステートです このディスクリプタで深度ステンシル ステートオブジェクトを作ります これも不変オブジェクトで プログラムをとおして使えます

    OpenGLでのレンダーループは Metalでは こうなります 正当性が立証されたオブジェクトは この先 検査や追跡が不要です 比べてみましょう

    Metalではレンダーパスの最初は MTLRenderCommandEncoderです フレームバッファと似ています

    depthステートは オブジェクトに焼き付けられ renderEncoderに 置けばいいだけです

    PipelineStateオブジェクトは プログラムシェーダと VertexArrayProperty pixelFormatの結合体です renderEncoderも設定します

    renderEncoderは ラスタライザステートを直接管理します パイプラインはまだ柔軟性があります PipelineStateオブジェクトに すべて焼き付けてはいません

    PSOに事前に記録されているものには フラグメント関数や PixelFormatなどがあります こちらはドロー中に 設定できるものです Cull ModeやFill Modeなど Scissor やViewportも 自由に設定できます

    ドローコールも同様に残っています 一番の違いは 新しいステートを有効にすると 隠れた検証の負荷が発生します 新しいPipelineStateに 交換すればいいのです

    OpenGLでは高負荷だった作業を 最適化する方法をお伝えします

    OpenGLのデベロッパなら ご存じですね レンダーループの 多くのステートを変更したあと 最初のドローコールで 中断が起こります 最適化を利用し そのコールを隠すでしょう Pre-Warmingはダミーコールを流し OpenGLで必要なステートを 事前に行っていました エンジンが準備万端なら 一番簡単な方法は PSOへの差し替えです

    MetalのシェーダPre-Warmingは 異なるステートとPSOオブジェクトの 生成によりできます

    まずディスクリプタを作成します 最初のドローコールまでの 書き込みを終えます 最初のPipelineStateオブジェクトを 作成します 同じディスクリプタで ステートを少し変更します ここではblendingを有効化しています 2つ目のPipelineStateオブジェクトを 作成します これらは事前に検査されているので ドロー中でも問題は起こりません OpenGLからMetalへの 簡単な移行方法でした

    アプリケーションの セットアップステージで Metalへ移行する利点について 説明します 負荷の大きいオペレーションが 減ります

    OpenGLではシェーダのコンパイルや ステートの検査には ドロー時間まで待つ必要がありました 負荷の大きい作業が フレームごとにあったのです

    Metalへ移行すれば これらのオペレーションは 違うステージへ移動します コンパイルされたシェーダや Shader Compilationは ビルド時に行われるので 1度で済みます ステートの定義は ロード時へ動きました ドロー時はドローコールだけの 負荷になります

    セットアップステージの説明でした 次はリソースやシェ-ダなど レンダーフレームでの作業です

    1つのフレームをドローするには アプリケーションは テクスチャとバッファを更新します レンダリングする レンダーターゲットを固定します 作業が終わるまで いくつかのレンダーパスが起こります まずはリソースのアップデートです リソースによっては レンダーループで更新を続けます

    例えばshader constantや Vertexやindexバッファ テクスチャです

    これらの修正はフレーム間で 終了します GPUとCPUを同期させています 典型的なOpenGLのリソース更新は 以下のどの組み合わせでも行えます

    バッファはCPUで更新されます またはGPUを介した バッファ同士のコピーで可能です テクスチャもCPUで更新されます またはGPUを介した テクスチャ同士のコピーでも可能です

    Metalも似た機能を提供しています ライオネルが説明したとおり バッファとテクスチャのコンテナは 変更できません そして初期設定時に生成されます しかしコンテンツは修正が可能です

    共有やマネージドストレージにある バッファの更新には CPUのコンテンツプロパティを 使います GPUではblitEncoderが データコピーを行います blitEncoderのcopyFromBufferを使い GPUからバッファを更新できます

    同じようにテクスチャも ストレージモードから replaceRegionを使い CPUを介して更新可能です GPUからのテクスチャの更新は copyFromTextureを使います

    更新の可否は ストレージモードによります 共有やマネージドストレージにある テクスチャやバッファは更新可能です

    OpenGLはGPUとCPUの 同期を図っていました それにより アプリケーションに 負荷をかけていました Metalでのメモリ管理のおかげで データの同期の場所と時間を選べます バッファ テクスチャ どちらも可能です

    OpenGLをMetalへ移行した場合 フローはこうなります

    CPUがレンダーパスを設定する間に リソースを更新します それが終われば バッファはレンダーパスの実行時に GPUで使用が可能です GPUがバッファから読み込む間は CPUがレンダーパスを設定し 同じバッファを更新します 競合状態です 問題の解決方法を説明します

    簡単な方法はGPUに リソースを預けることです コマンドバッファに対して waitUntilCompleted()を使います 前半で話したglFinishに似ています バッファを使ったレンダーパスの実行が GPUで終わるまで CPUの作業も制限されます

    実行が終わると GPUからコールバックを受け取ります これにより どのバッファも CPUやGPUによって 足止めを食らうことはありません

    しかしCPUは GPUの実行中 アイドリング状態です GPUはCPUが仕事を終えるまで 待ちぼうけです レース状態を解消するには 有効かもしれません しかしプログラムの遅延が発生するので waitUntilCompleted()の使用は お勧めしません

    必要性に応じて 2つかそれ以上のバッファを更新し 同期させるのが効率的な方法です CPUもGPUも それぞれの作業を行えます トリプルバッファリングを 見てみましょう

    最初のリソースです GPUによって消費されます completionHandlerを使ってみます GPUによって 該当のフレームが終了すると CPUも終了を認識します

    しかし終わるのを待つ必要はありません トリプルバッファリングでは 異なるバッファなので CPUは2つ先まで更新を進めます GPUのフレームは完了しています ここでcompletionHandlerを投入します GPUの作業は終わり バッファは バッファプールへ戻っています CPUとGPUはバッファごとに ずれて作業を行います 多くのデベロッパは この方法を使うでしょう 最適なパフォーマンスが実現できます

    作業の遂行においては トリプルバッファリングなら キューも3つ必要です

    frameBoundarySemaphoreの 初期化が必要です GPUが実行を終えるたびにバッファを オーバーライドできると CPUに伝えます

    最後にバッファインデックスを 初期化します

    レンダーループの内部は バッファを書く前に 該当のルレームのGPUの作業が 終わっている必要があります レンダーパスの最初に frameBoundarySemaphoreの 完了を待ちます 完了の信号を受け取ったら バッファを新しいフレームデータへ 再利用できます

    コマンドをエンコードし GPUへリソースを結合し 次のフレームに使います

    その前に CommandBufferへ CompletionHandlerを追加し 完遂します

    GPUの作業が終われば フレームに信号を送り CPUは実行の完了を知り バッファを次のフレームに使います

    これはシンプルなトリプルバッファの 実装です もっと大規模なリソース更新にも 使えます

    リソースが更新されました 次はレンダーターゲットです

    OpenGLでは フレームバッファオブジェクトは レンダリングコマンドの 最終地点でした フレームバッファオブジェクトは テクスチャとレンダーバッファを集め レンダリングを円滑に進めました フレームバッファは可変であり レンダーパスは漠然としています 最終的にはディスプレイ表示のため 交換します

    OpenGLのフレームバッファの典型的な ワークフローです アプリケーションの初期化処理では フレームバッファはすでにあります 結合することで最新に保ちます テクスチャなどのリソースも加え フレームバッファのステータスも 確認します

    ドロー時はフレームバッファを 現行の状態にします レンダーパスにとっては 暗黙のスタートです ドローコールの前に すべてを消去します 最後に特定の信号をOpenGLへ送って メモリへ保存する必要がないと 伝達します レンダーパスの終わりの ヒントでもありますが 保証するものではありません

    Metalでは MTLRenderCommandEncoderが レンダリングコマンドの最終ゴールです FBOと似て レンダリングの行き先を集めて 指令を届きやすくします MTLRenderCommandEncoderは直接 GPUへハードウェアコマンドを出します レンダーパスは始まりと終わりが 明確に分かります

    Metalのレンダーパスです renderPassDescriptorを作ります 付随するリソースを記述します オペレーションの始めと終わりを 指定します ロード&ストアアクションと言います OpenGLとは違い Metalはリソースを直接 削除しません ロードアクションと色を指定します ここでは黒です

    ストアアクションはDontCareにします OpenGLのフレームバッファと 似ているところです 結果を保存する場合は ストアアクションを実行します

    レンダータイムでは ディスクリプタを使って エンコードを生成します 自らドローコールを実行し エンコードを終えます

    フレームバッファを処分する前に 何か書いてみましょう

    レンダーコマンドはレンダーパスにも 参照されます テクスチャやバッファのドローコール インプットやステートを設定 ドローコマンドを発令します

    これは典型的なOpenGLの ドローの流れです よいOpenGL appはすべてを 事前にセットしておきます ターゲットを統合し

    シェーダとのリンクをプログラムします

    VertexBufferやUniformなどの リソースとを 違うステージから結合します そしてドローが完成します

    少し前に話したとおり OpenGLの変更は 隠れた負担が発生します 負担を避けるためにステージの 変更をまとめていた場合 Metalのステートオブジェクトの 事前検査も有効に活用できます Metalの検証はPipelineState オブジェクト作成時のみです シェーダがコンパイルされていれば ループは小さくなります

    プログラマーにとっては 違いはわずかです 先ほどのコードをMetalで 開いています

    まずは MTLRenderCommandEncoderからです OpenGLのフレームバッファに相当します

    あらかじめ設計された PipelineStateオブジェクトを設定 OpenGLプログラムでも 同等のものがあります

    VertexBufferとUniformの リソースを割り当てます Uniformはシェーダステージごとの 配置が必要です OpenGLとは違うところです OpenGLから引用している Uniformですが 違う物を使っても大丈夫です

    最後にテクスチャとドローコールです すべてのドローコールを設定したら レンダーパスを終えます

    まだ表示の問題があります

    GPUはフレームバッファ用に 書かれています OpenGLはレンダーフレームを表示します drawInRectから戻るとコンテキストは presetRenderBufferをコールします MetalはCore Animationから ドローアブルへ直接 実行します ドローアブルはディスプレイの テクスチャです

    レンダーバスを エンコードすることが可能です 現在のドローアブルを引き出し レンダーループのあとに コマンドバッファに指令を出します

    最初のコードを覚えていますか? ウィンドウサブシステムの時です GLKViewとdrawInMTKViewを 紹介します レンダリングを見ていただけます

    こちらです GLKViewではフレームバッファを結合し レンダーコマンドで drawInRectによりイメージが表われます Metalではコマンドバッファを作成し 終わりのエンコーダを作成し レンダーコマンドを行います 1つ追加で行うことは presentDrawableをコールすることです 最終のコマンドバッファ前に行います シングルエンコーダの 単純なレンダーループでは これを行うだけです もっと複雑なアプリケーションの場合 別のセッションも見てください “Delivering Optimized Metal Apps and Games”です

    フレームが完成しました ウィンドウサブシステムの 移行方法を説明しました リソースの作成をしましたね すばらしいツールで 問題点を簡単に見つけられます

    レンダーコマンドキュー コマンドバッファ コマンドエンコードを作成 レンダーパスも設けました 正当性が事前に検査された オブジェクトの作成 トリプルバッファリングのリソースの 更新方法を紹介 レンダーパスのための MTLRenderCommandEncoder レンダーフレームの最終的な配置

    グラフィックアプリケーションで 実演もしました OpenGLとMetalは共通点が多く 移植もスムーズに行えます グラフィックにおける問題解決に 新たな技術も取り入れました このセッションで伝えたいことは OpenGLからMetalへの移行は 難しくないということです 既存のアプリケーションは 向上するでしょう もう1つ伝えたいことは Metalはすばらしいツールを 提供しています 開発の強い味方になるでしょう マックスがデモで紹介したのも その1つです コードの問題を解決してくれます Xcodeは新しいGPUの Memory Viewerを提供しています アプリケーションのメモリ面で 役立つでしょう GamePerformance Templateの Metal System Traceは ドロップフレームなどの サブミッション問題を解決します 今年 初めて発表したのは Metal Appの Supporting Simulatorです (拍手) 興奮しますよね (笑い声)

    macOS Catalinaに搭載の Xcode 11では フルハードウェアアクセラレーションで iOSやtvOSのアプリケーションに対応 Metal シミュレータを搭載 MTLGPUFamilyApple2の機能により ゲームやアプリケーションが 高性能なスクリーンに対応しています

    シミュレータやハードウェアについては シミュレータ関連のセッションを ご覧ください Metalに関するセッションも オンラインでいくつも公開しています

    さらなる情報は ウェブサイトの資料をご覧ください ラボにもお越しください ご清聴 ありがとうございました (拍手)

Developer Footer

  • ビデオ
  • WWDC19
  • OpenGL AppをMetalに移行する
  • メニューを開く メニューを閉じる
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    Open Menu Close Menu
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • SF Symbols
    メニューを開く メニューを閉じる
    • アクセシビリティ
    • アクセサリ
    • App Extension
    • App Store
    • オーディオとビデオ(英語)
    • 拡張現実
    • デザイン
    • 配信
    • 教育
    • フォント(英語)
    • ゲーム
    • ヘルスケアとフィットネス
    • アプリ内課金
    • ローカリゼーション
    • マップと位置情報
    • 機械学習
    • オープンソース(英語)
    • セキュリティ
    • SafariとWeb(英語)
    メニューを開く メニューを閉じる
    • 英語ドキュメント(完全版)
    • 日本語ドキュメント(一部トピック)
    • チュートリアル
    • ダウンロード(英語)
    • フォーラム(英語)
    • ビデオ
    Open Menu Close Menu
    • サポートドキュメント
    • お問い合わせ
    • バグ報告
    • システム状況(英語)
    メニューを開く メニューを閉じる
    • Apple Developer
    • App Store Connect
    • Certificates, IDs, & Profiles(英語)
    • フィードバックアシスタント
    メニューを開く メニューを閉じる
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program(英語)
    • News Partner Program(英語)
    • Video Partner Program(英語)
    • セキュリティ報奨金プログラム(英語)
    • Security Research Device Program(英語)
    Open Menu Close Menu
    • Appleに相談
    • Apple Developer Center
    • App Store Awards(英語)
    • Apple Design Awards
    • Apple Developer Academy(英語)
    • WWDC
    Apple Developerアプリを入手する
    Copyright © 2025 Apple Inc. All rights reserved.
    利用規約 プライバシーポリシー 契約とガイドライン