# 機能設計書 268-imgui_impl_metal

## 概要

本ドキュメントは、Dear ImGuiのMetalレンダラーバックエンド（imgui_impl_metal）の機能設計を定義する。

### 本機能の処理概要

MetalレンダラーバックエンドはDear ImGuiのUI描画コマンドをApple Metal APIに変換し、画面にUIを描画する機能を提供する。Objective-CおよびMetal C++（オプショナル）に対応し、macOS、iOS、tvOS環境でのレンダリングをサポートする。

**業務上の目的・背景**：
Metalを使用するAppleプラットフォームアプリケーションにDear ImGuiを統合する必要がある場合に本バックエンドを使用する。Metalはmacros Mojave以降、iOS 8以降でサポートされ、Apple GPUに最適化されたパフォーマンスを提供する。

**機能の利用シーン**：
- macOSアプリケーションへのImGuiデバッグUI追加
- iOS/tvOSアプリケーションへのUI統合
- Metal C++を使用したクロスプラットフォーム開発

**主要な処理内容**：
1. バックエンドの初期化（`ImGui_ImplMetal_Init`）：MTLDevice取得
2. デバイスオブジェクト作成（`ImGui_ImplMetal_CreateDeviceObjects`）：DepthStencilState作成
3. フレーム開始処理（`ImGui_ImplMetal_NewFrame`）：RenderPassDescriptorからFramebufferDescriptor取得
4. 描画データのレンダリング（`ImGui_ImplMetal_RenderDrawData`）：コマンドエンコーダへの描画記録
5. テクスチャ更新（`ImGui_ImplMetal_UpdateTexture`）：MTLTexture作成・更新・破棄
6. バックエンドの終了処理（`ImGui_ImplMetal_Shutdown`）：リソース解放

**関連システム・外部連携**：
- プラットフォームバックエンド（OSX、iOS）と組み合わせて使用
- Metal Framework

**権限による制御**：
特になし

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | 全画面 | 主画面 | すべてのDear ImGuiウィジェットの描画出力先 |

## 機能種別

レンダリングバックエンド / グラフィックスAPI抽象化

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|-----------------|
| device | id<MTLDevice> | Yes | Metalデバイス | nil以外 |
| renderPassDescriptor | MTLRenderPassDescriptor* | Yes | レンダーパス記述子 | nil以外 |
| commandBuffer | id<MTLCommandBuffer> | Yes | コマンドバッファ | nil以外 |
| commandEncoder | id<MTLRenderCommandEncoder> | Yes | レンダーコマンドエンコーダ | nil以外 |
| draw_data | ImDrawData* | Yes | 描画コマンドリスト | DisplaySize > 0 |

### 入力データソース

- MTLDeviceインスタンス
- MTLRenderPassDescriptor
- MTLCommandBuffer
- MTLRenderCommandEncoder
- ImDrawData構造体
- ImTextureData構造体

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 初期化結果 | bool | Init関数の成功/失敗 |
| テクスチャID | id<MTLTexture> | MTLTextureとして使用 |
| コマンドエンコーダ出力 | Metalコマンド | MTLRenderCommandEncoderへの描画コマンド記録 |

### 出力先

- MTLRenderCommandEncoder
- io.BackendRendererUserData

## 処理フロー

### 処理シーケンス

```
1. ImGui_ImplMetal_Init(device)
   └─ MetalContext初期化

2. ImGui_ImplMetal_CreateDeviceObjects(device)
   └─ newDepthStencilStateWithDescriptor

3. [毎フレーム] ImGui_ImplMetal_NewFrame(renderPassDescriptor)
   ├─ FramebufferDescriptor作成
   └─ 必要ならCreateDeviceObjects呼び出し

4. [毎フレーム] ImGui_ImplMetal_RenderDrawData(draw_data, commandBuffer, commandEncoder)
   ├─ テクスチャ更新
   ├─ RenderPipelineState取得（キャッシュから or 新規作成）
   ├─ VB/IB取得（再利用バッファプールから）
   ├─ SetupRenderState
   │      ├─ setCullMode:MTLCullModeNone
   │      ├─ setDepthStencilState
   │      ├─ setViewport
   │      ├─ setVertexBytes（正射影行列）
   │      └─ setRenderPipelineState
   ├─ VB/IBへのデータコピー
   └─ 描画コマンド実行
          ├─ setScissorRect
          ├─ setFragmentTexture
          └─ drawIndexedPrimitives

5. ImGui_ImplMetal_UpdateTexture(tex)
   ├─ newTextureWithDescriptor（MTLPixelFormatRGBA8Unorm）
   └─ replaceRegion（テクスチャ更新）

6. ImGui_ImplMetal_Shutdown()
   └─ DestroyDeviceObjects
```

### フローチャート

```mermaid
flowchart TD
    A[Init] --> B[NewFrame]
    B --> C[FramebufferDescriptor作成]
    C --> D{DepthStencilState作成済み?}
    D -->|No| E[CreateDeviceObjects]
    D -->|Yes| F[RenderDrawData]
    E --> F
    F --> G[Update Textures]
    G --> H{RenderPipelineStateキャッシュ?}
    H -->|Miss| I[新規Pipeline作成]
    H -->|Hit| J[キャッシュ使用]
    I --> J
    J --> K[Buffer取得]
    K --> L[SetupRenderState]
    L --> M[setViewport]
    M --> N[setVertexBytes]
    N --> O[For each DrawList/DrawCmd]
    O --> P[setScissorRect]
    P --> Q[setFragmentTexture]
    Q --> R[drawIndexedPrimitives]
    R --> S[Bufferキャッシュ返却]
    S --> T[Shutdown]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | テクスチャ形式 | MTLPixelFormatRGBA8Unorm | テクスチャ作成時 |
| BR-002 | 大規模メッシュ対応 | 64K頂点以上サポート | drawIndexedPrimitivesのVtxOffset使用 |
| BR-003 | パイプラインキャッシュ | FramebufferDescriptorをキーにRenderPipelineStateをキャッシュ | パイプライン取得時 |
| BR-004 | バッファ再利用 | MetalBufferプールから取得・返却 | VB/IB管理 |
| BR-005 | ストレージモード | macOS: MTLStorageModeManaged、iOS: MTLStorageModeShared | テクスチャ作成時 |

### 計算ロジック

**正射影行列**（行206-212）:
```cpp
const float ortho_projection[4][4] =
{
    { 2.0f/(R-L),   0.0f,           0.0f,   0.0f },
    { 0.0f,         2.0f/(T-B),     0.0f,   0.0f },
    { 0.0f,         0.0f,        1/(F-N),   0.0f },
    { (R+L)/(L-R),  (T+B)/(B-T), N/(F-N),   1.0f },
};
```

## データベース操作仕様

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| IM_ASSERT | 初期化エラー | 二重初期化 | 初期化状態確認 |
| IM_ASSERT | コンテキストエラー | バックエンド未初期化 | Init呼び出し確認 |

### リトライ仕様

リトライなし

## トランザクション仕様

該当なし

## パフォーマンス要件

- RenderPipelineStateキャッシュによる再利用（FramebufferDescriptorをキーに）
- MetalBufferプールによるVB/IB再利用
- completedHandlerでのバッファ返却（非同期）
- dispatch_asyncによるメインキューでのバッファキャッシュ操作

## セキュリティ考慮事項

- デバイスポインタの検証

## 備考

- IMGUI_IMPL_METAL_CPPマクロでMetal C++ API対応
- __bridgeによるARC対応
- macOS CatalystでのMTLStorageModeManaged使用
- バッファキャッシュのパージ機能（lastReuseTime管理）

---

## コードリーディングガイド

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | imgui_impl_metal.mm | `backends/imgui_impl_metal.mm` | MetalContext クラス（行73-82）を確認 |
| 1-2 | imgui_impl_metal.mm | `backends/imgui_impl_metal.mm` | MetalBuffer クラス（行49-53）を確認 |
| 1-3 | imgui_impl_metal.mm | `backends/imgui_impl_metal.mm` | FramebufferDescriptor クラス（行57-63）を確認 |
| 1-4 | imgui_impl_metal.mm | `backends/imgui_impl_metal.mm` | MetalTexture クラス（行65-68）を確認 |
| 1-5 | imgui_impl_metal.mm | `backends/imgui_impl_metal.mm` | ImGui_ImplMetal_Data構造体（行84-89）を確認 |

**読解のコツ**: MetalバックエンドはObjective-Cで実装されており、NSObject派生のヘルパークラスを使用している。

#### Step 2: 初期化処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | imgui_impl_metal.h | `backends/imgui_impl_metal.h` | 公開API宣言（ObjC: 行31-44、C++: 行59-72）を確認 |
| 2-2 | imgui_impl_metal.mm | `backends/imgui_impl_metal.mm` | Init関数（行129-145）を確認 |

**主要処理フロー**:
- **行138-139**: ImGuiBackendFlags設定（RendererHasVtxOffset, RendererHasTextures）
- **行141-142**: MetalContext初期化、デバイス設定

#### Step 3: レンダリング処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | imgui_impl_metal.mm | `backends/imgui_impl_metal.mm` | RenderDrawData関数（行222-337）を確認 |
| 3-2 | imgui_impl_metal.mm | `backends/imgui_impl_metal.mm` | SetupRenderState関数（行177-219）を確認 |

**主要処理フロー**:
- **行242-250**: RenderPipelineState取得（キャッシュ or 新規作成）
- **行254-255**: バッファ取得（dequeueReusableBufferOfLength）
- **行268-269**: VB/IBへのデータコピー（memcpy to buffer.contents）
- **行314**: drawIndexedPrimitives
- **行327-336**: completedHandlerでのバッファ返却

#### Step 4: テクスチャ処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | imgui_impl_metal.mm | `backends/imgui_impl_metal.mm` | UpdateTexture関数（行353-404）を確認 |

**主要処理フロー**:
- **行367-370**: MTLTextureDescriptor作成（MTLPixelFormatRGBA8Unorm）
- **行371-376**: MTLTextureUsageShaderRead、ストレージモード設定
- **行377**: newTextureWithDescriptor
- **行378**: replaceRegion（初回アップロード）
- **行391-397**: replaceRegion（部分更新）

### プログラム呼び出し階層図

```
アプリケーション
    │
    ├─ ImGui_ImplMetal_Init(device)
    │      └─ MetalContext 初期化
    │
    ├─ [フレームループ]
    │      │
    │      ├─ ImGui_ImplMetal_NewFrame(renderPassDescriptor)
    │      │      ├─ FramebufferDescriptor 作成
    │      │      └─ ImGui_ImplMetal_CreateDeviceObjects() [初回のみ]
    │      │             └─ newDepthStencilStateWithDescriptor()
    │      │
    │      └─ ImGui_ImplMetal_RenderDrawData()
    │             ├─ ImGui_ImplMetal_UpdateTexture()
    │             │      ├─ texture2DDescriptorWithPixelFormat()
    │             │      ├─ newTextureWithDescriptor()
    │             │      └─ replaceRegion()
    │             │
    │             ├─ renderPipelineStateForFramebufferDescriptor() [キャッシュミス時]
    │             ├─ dequeueReusableBufferOfLength() [VB/IB]
    │             ├─ ImGui_ImplMetal_SetupRenderState()
    │             │      ├─ setCullMode()
    │             │      ├─ setDepthStencilState()
    │             │      ├─ setViewport()
    │             │      ├─ setVertexBytes() [正射影行列]
    │             │      └─ setRenderPipelineState()
    │             │
    │             ├─ memcpy() [VB/IBへデータコピー]
    │             ├─ setScissorRect()
    │             ├─ setFragmentTexture()
    │             ├─ drawIndexedPrimitives()
    │             └─ addCompletedHandler() [バッファ返却]
    │
    └─ ImGui_ImplMetal_Shutdown()
           ├─ ImGui_ImplMetal_DestroyDeviceObjects()
           └─ ImGui_ImplMetal_DestroyBackendData()
```

### データフロー図

```
[入力]                         [処理]                              [出力]

MTLDevice ──────────────▶ Init() ───────────────────────▶ MetalContext
                             └─ SharedMetalContext 初期化

MTLRenderPassDescriptor ──▶ NewFrame() ─────────────────▶ FramebufferDescriptor
                             └─ フレームバッファ設定取得

ImDrawData ─────────────▶ RenderDrawData() ───────────▶ MTLRenderCommandEncoder
  ├─ DisplaySize               ├─ RenderPipelineState取得        └─ 描画コマンド記録
  ├─ FramebufferScale          ├─ MetalBuffer取得
  ├─ CmdLists[]                ├─ SetupRenderState()
  │   ├─ VtxBuffer             └─ drawIndexedPrimitives()
  │   └─ IdxBuffer
  │
  └─ Textures[] ──────────▶ UpdateTexture() ──────────▶ id<MTLTexture>
       └─ ImTextureData       ├─ texture2DDescriptor()
                              ├─ newTextureWithDescriptor()
                              └─ replaceRegion()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| imgui_impl_metal.h | `backends/imgui_impl_metal.h` | ヘッダー | 公開API宣言（ObjC/C++両対応）（79行） |
| imgui_impl_metal.mm | `backends/imgui_impl_metal.mm` | ソース | バックエンド実装本体（Objective-C） |
| Metal/Metal.h | システム | フレームワーク | Metal API宣言 |
| Metal/Metal.hpp | システム | フレームワーク | Metal C++ API宣言（オプショナル） |
