# SEKTION 03 — DIE ENGINE

> Hier entscheidet sich, ob aus 29 Sekunden zwei werden.
> **Nach Sektion 01 dran, nicht vorher.**

> ⛔ **VULKAN IST PFLICHT** (REGELN.md Regel 0, der Nutzer 13.08.2026).
> Das Rechenwerk dieser Sektion ist Vulkan Compute auf AMD (RX 9060 XT,
> RDNA4). Kein `diffusers`, keine ComfyUI-Brücke, torch nicht als Ziel.
> Die CPU-/torch-Referenz aus 3.2 bleibt — aber **nur** als Maßstab, gegen
> den ein Kernel geprüft wird, und sie wird für jeden fertigen Kernel
> wieder überflüssig.

---

## 3.1 Warum ein eigenes Programm schneller sein kann

Nicht „weil Vulkan". Drei konkrete Gründe, nach Gewicht:

**1. Der Graph wird EINMAL übersetzt.**
ComfyUI ruft pro Bild hunderte Python-Funktionen auf, mit Tensor-Umkopiererei
dazwischen. Global UI übersetzt den Graphen einmal in eine **Kommandokette**
und führt die aus. Das ist der eigentliche architektonische Grund — nicht das
Backend.

**2. Modelle bleiben liegen.**
Gemessen: 7 GB fliegen bei jedem Bild raus und wieder rein, ~6,2 s.
Der Graph sagt, was bleibt (`resident`, `verdraengen`) — die Engine hält sich
daran. **Das ist bereits im Speicher-Plan beschrieben, hier wird es
durchgesetzt.**

**3. Vulkan Compute statt CUDA/ROCm.**
Herstellerneutral, Pipeline-Cache auf der Platte (der erste Lauf nach dem
Start ist sonst immer der teuerste — auf ROCm wie auf Vulkan).

## 3.2 Bau-Reihenfolge INNERHALB dieser Sektion

**Erst eine Referenz, die stimmt. Dann eine, die schnell ist.**

1. **`kern/ausfuehren.py` — Rückgrat.** Graph → Reihenfolge → Schritte
   ausführen → Ergebnis. Zuerst mit **NumPy auf der CPU**, ohne jede
   Optimierung. Ziel: ein trivialer Graph läuft wirklich durch.
2. **`kern/speicher.py` — Modell-Verwaltung.** Wer liegt im VRAM, wer darf
   raus, wer bleibt. Setzt `resident`/`verdraengen`/`bei_engpass` durch und
   **meldet jede Räumung** (sonst merkt niemand, dass wieder geschoben wird).
3. **Referenz-Ergebnisse einfrieren.** Ein bekannter Graph, bekannter Seed,
   gespeichertes Ergebnis. Ab jetzt muss jede Optimierung **bitgenau oder
   innerhalb einer festgelegten Toleranz** dasselbe liefern.
4. **`kern/vulkan/` — Compute-Backend.** Erst jetzt. Kernel für Faltung,
   Aufmerksamkeit, Normalisierung, Matrixmultiplikation. Jeder Kernel wird
   gegen die CPU-Referenz aus Schritt 3 geprüft.
5. **Graph-Übersetzer.** Aus der geprüften Kette eine Kommandokette bauen.

**Ein Vulkan-Kernel ohne Referenzergebnis ist nicht prüfbar** — dann weiß
niemand, ob das Bild anders aussieht, weil der Kernel schneller oder weil er
falsch ist.

## 3.3 Der Modell-Verwalter (`kern/speicher.py`)

Aufgaben:

- **weiß, was im VRAM liegt** und wie groß es ist — gemessen, nicht geschätzt
- **hält, was der Graph halten will** (`resident`)
- **räumt nur, was der Graph räumen lässt** (`verdraengen`)
- **meldet jede Räumung** über denselben Fortschritts-Kanal wie die Nodes
- **landet nie aus Versehen im geteilten Systemspeicher.** Reicht es nicht,
  greift `bei_engpass` — ausweichen, stückeln, ablehnen. `auslagern` nur,
  wenn es dort ausdrücklich steht.
- **Streaming statt Zufall:** wenn ein Modell wirklich nicht ganz passt,
  werden Gewichte **geplant** Schicht für Schicht nachgeladen — nicht dem
  Treiber überlassen, der irgendwelche Seiten irgendwohin schiebt. Das ist
  der Unterschied zwischen 10 % langsamer und 10× langsamer.

## 3.4 Vulkan — was gebraucht wird

| Baustein | Zweck |
|---|---|
| Speicherverwaltung | Puffer, Staging, Wiederverwendung statt Neuanlage |
| Pipeline-Cache **auf der Platte** | erster Lauf nach dem Start ist sonst der teuerste |
| Faltung / Matrixmultiplikation | Kern des UNet |
| Aufmerksamkeit | der Flash-Attention-Posten; als Node-Eingang `attention` wählbar |
| Normalisierung, Aktivierung | Kleinkram, aber oft aufgerufen |
| Quantisierte Kernel (GGUF) | Q3–Q8 direkt rechnen statt vorher entpacken |

Nichts hiervon AMD-spezifisch bauen. Was es doch sein muss, wird gekapselt
und benannt.

## 3.5 Wo die 2 Sekunden herkommen sollen

| Hebel | erwartet | Stand |
|---|---|---|
| Modelle resident (kein Umladen) | **−6,2 s** | **gemessen** |
| Graph einmal übersetzen statt 200 Python-Aufrufe | ? | zu messen |
| Vulkan-Kernel statt ROCm | ? | zu messen |
| Batch statt Einzelbild | deutlich | bekannt |
| Wenig-Schritt-Modelle | linear | bekannt |
| warmer Pipeline-Cache | einmalig ~18 s | gemessen (Aufwärmkosten) |

**Der Sampler ist der Brocken: 20,5 s von 29,1 s.** Ohne ihn gibt es keine
2 Sekunden. Alles andere ist Beiwerk.

Nach jedem Hebel: messen und in `PROJEKT.md` schreiben. Eine Behauptung
ohne Zahl daneben zählt nicht.

## 3.6 Checks für diese Sektion

- [ ] Ein trivialer Graph läuft auf der CPU durch und liefert ein Ergebnis
- [ ] Referenz-Ergebnis eingefroren; jede Optimierung wird dagegen geprüft
- [ ] Jeder Vulkan-Kernel stimmt mit der CPU-Referenz überein (Toleranz
      festgelegt und begründet)
- [ ] `resident: true` → Modell liegt nach dem Lauf noch drin (nachgemessen)
- [ ] `verdraengen: nein` → es wird nichts geräumt (nachgemessen)
- [ ] Bei zu wenig VRAM greift `bei_engpass`; **nie** stilles Auslagern
- [ ] Jede Räumung erscheint im Fortschritt
- [ ] t2i 1024×1024 ist schneller als 29,1 s — mit Messung daneben
