Primer 01 — Render Pipeline
1フレームの旅 / The Life of a Frame

ゲームスレッドと
レンダースレッドの流れ

ゲーム画面の1フレームは、CPU と GPU の間をリレーのように渡り歩いて作られます。「いま見えている絵」は、実はゲームロジックが計算している最新フレームより数フレーム前のものです。なぜそうなるのか、CPU の Game Thread から GPU までの流れを、図と動きで追っていきましょう。

Game Thread Render Thread RHI Thread GPU

§1 — Game Loop

まず「ゲームサイクル」から

どんなゲームも、毎フレーム同じ4つの仕事を高速で繰り返しています。入力を読み、世界を1コマ進め、その状態を絵にし、画面に出す。この繰り返しを ゲームループ(game loop)と呼びます。60fps なら、この一周を 約16.6ミリ秒で回し続けているわけです。

01
Input
入力を読む。キー・パッド・マウス・ネットワーク。
02
Update
世界を1コマ進める。Tick・物理・AI・アニメ。
03
Render
その状態を絵にする。CPUが命令を作りGPUが描く。
04
Present
完成した絵をモニタに出す (VSync)。→ 01へ戻る。
↻ これを毎フレーム繰り返す — 60fps なら 1 秒間に 60 周

素朴には「順番に4つやって1周」。でも実際のUEはこれを1本の直列処理では回していません — ここからが本題です。


§2 — The Pipeline

流れ作業(パイプライン)で回している

もし1フレームを「Update が終わってから Render、終わってから GPU」と直列でやると、その間ほかの部品は遊んでしまいます。そこで UE は工場のライン(pipeline)のようにずらして並行させます。Game Thread が今のフレームを計算している間に、Render Thread は1つ前のフレームを、GPU はさらに前のフレームを処理している ── これが「表示が数フレーム遅れる」正体です。

直列 vs パイプライン — なぜ「ずらして並行」なのか
Game Render RHI GPU
直列でやると(naive)
G0
R0
H0
P0
✓
G1
R1
H1
P1
✓

1フレーム完成までフル4コマ。その間ほかの部品は遊んでいる → スループットが上がらない。

パイプラインなら(UEはこちら)
F0
F1
F2
F3
F4
F0
F1
F2
F3
F0
F1
F2
F0
✓
F1
✓

段が埋まれば 毎コマ1フレームずつ完成(スループット約4倍)。ただし最初の1枚が出るまで数コマ待つ ── この待ち分が「フレーム遅延」の正体です。

時間 → (同じ色 = 同じフレームの旅)
NOW
再生すると、いま各スレッドがどのフレームを処理しているかが表示されます。

NOWの縦線を各段が下りていくのが1フレームの旅。同じ瞬間でも、下の段ほど「古いフレーム」を扱っています。(この図は分かりやすさ優先で1段=1フレーム遅延。実機のUEはRender/GPUが重なり、体感遅延はおよそ2フレームです)


§3 — Who does what

各スレッドの役割

4つは一方向のバトンリレーで動きます。前の段が作った成果物を、次の段が受け取って別の形に変換していく流れです。

CPU
Game
Thread
世界を1コマ
進める
描画命令
render cmds
→
CPU
Render
Thread
描く段取りを
組む
RHIコマンド
RHI cmds
→
CPU
RHI
Thread
GPUへの
通訳
APIコール
submit
→
Hardware
GPU
実際に
塗る
ピクセル
present
→
Monitor
画面表示
1フレーム
完成

矢印の上が「次の段へ渡す成果物」。前段の出力が次段の入力になり、少しずつGPUが分かる形へ翻訳されていきます。

下のカードをクリックすると、各担当の詳しい説明が開きます。


    §4 — Bottleneck

    fps を決めるのは「一番遅い段」

    3つの段が並行して走るので、フレームにかかる時間は3つの合計ではなく最大値で決まります。スライダーで各段の処理時間を変えて、どこがボトルネックになるか確かめてみてください。「GPUバウンド」「ゲームスレッドバウンド」という言葉はこれを指します。

    16.6 ms (60fps)
    Frame Time
    実効 fps
    結果


    §5 — Screen Capture

    画面をキャプチャしたいとき

    「今の画面を保存したい」— これは思ったより一手間かかります。絵は GPU 側のメモリ(Render Target)にあり、CPU から直接は読めません。GPU に「CPUが読める場所へコピーして」と頼み、それが終わるのをフェンス(fence)で待ってから読み出します。ステップをクリックすると詳細が開きます。

    メモリの地図 — なぜ一手間かかるか
    GPU側メモリ · VRAM
    Render Target
    描いた絵(テクスチャ)
    CPU ⇄ GPU
    メモリ境界
    →
    コピー+
    Fenceで完了待ち
    システムメモリ · CPUが読める
    Readback バッファ
    → Map → TArray<FColor> → PNG

    CPU は VRAM を直接読めません。だから「コピーして・待って・読む」の3手間になります。下の5ステップはこの地図を時間順に並べたものです。

    要点:読み取れるのは GPU が今出した絵 = ゲームスレッドより数フレーム前の状態。ReadPixels のように「今すぐ待って読む」とパイプラインが止まり (flush)、カクつきの原因になります。UE の高解像度スクリーンショットや SceneCaptureComponent2D は、この流れを裏でやっています。


    Glossary — 用語

    よく出る言葉