362e089be0
Der Nutzer hat recht: Der Ordner war voller Entwicklungs-Muell. Jetzt ist sauber getrennt: ROOT (was der Nutzer sieht und braucht): - run.py = das Programm - hms_app/ = der Anwendungscode - HMS MediaEngine.app = macOS Doppelklick-Starter - HMS-Start.vbs = Windows Doppelklick-Starter - HMS-Install.vbs = Windows Erst-Installation - HMS-Mac-Install.command = macOS Homebrew-Installation - HMS-Portable-Install.command = macOS Portable-Installation (16GB-Fix) - installer_gui.py = grafischer Installer - launcher.pyw + launcher_core.py = interne Start-Logik - LIESMICH.txt = 10-Zeilen-Kurzanleitung - .gitignore _entwicklung/ (alles andere, NICHT benoetigt): - packages/ apps/ native/ plugins/ tools/ schemas/ tests/ docs/ build/ fixture_profiles/ - PLAN.md STATUS.md ERRORS.md TEST_REPORT.md CHANGELOG.md README.md - pyproject.toml uv.lock setup_*.sh/ps1 make_mac_app.py Diese Trennung gilt ab sofort fuer alle Commits. Der Nutzer kann _entwicklung/ loeschen wenn er Platz braucht - die App laeuft ohne. Verifiziert: App startet nach Aufraeumen unveraendert (Health 200).
240 lines
7.8 KiB
Markdown
240 lines
7.8 KiB
Markdown
# Shader-Vertrag
|
||
|
||
Dieses Dokument beschreibt den verbindlichen Shader-Vertrag für Plugin-Shader. Grundlage sind PLAN.md §14.4 (Standard-Shaderinputs) und die eingebauten Beispiel-Shader des Vignette-Plugins (`plugins/builtin/filters/com.hms.fx.vignette/shaders/`).
|
||
|
||
## Standard-Uniform-Satz (§14.4)
|
||
|
||
Jeder Shader erhält nach Bedarf folgende semantische Inputs:
|
||
|
||
| Semantische ID | Typ | Beschreibung |
|
||
| --- | --- | --- |
|
||
| `u_input_texture` | Textur | Eingangs-Textur (bei Filtern) |
|
||
| `u_resolution` | vec2/float4 | Auflösung in Pixeln (`xy`) |
|
||
| `u_time_seconds` | float | Zeit in Sekunden |
|
||
| `u_delta_seconds` | float | Zeit seit dem letzten Frame |
|
||
| `u_frame_index` | float | Frame-Index |
|
||
| `u_layer_opacity` | float | Opazität des Layers |
|
||
| `u_audio_rms` | float | Audio-RMS |
|
||
| `u_audio_peak` | float | Audio-Peak |
|
||
| `u_audio_bass` | float | Audio-Bass |
|
||
| `u_audio_mid` | float | Audio-Mid |
|
||
| `u_audio_treble` | float | Audio-Treble |
|
||
| `u_audio_beat` | float | Audio-Beat |
|
||
| deklarierte Pluginparameter | float | Parameter aus `plugin.json` |
|
||
|
||
Semantische Input-IDs, Typen, Wertebereiche, Farbräume und Texturkonventionen sind Teil der versionierten Plugin-API. Backendadapter binden sie an HLSL-Konstanten beziehungsweise GLSL-Uniforms; Projekte referenzieren niemals konkrete Variablennamen eines Backends (PLAN.md §14.4).
|
||
|
||
## HLSL (D3D11) – cbuffer-Layout
|
||
|
||
Im HLSL-Backend liegen die Standard-Uniforms und Pluginparameter in einem Konstantenpuffer (`cbuffer`). Das Vignette-Beispiel (`shaders/d3d11/main.hlsl`) zeigt das Layout:
|
||
|
||
```hlsl
|
||
Texture2D u_input_texture : register(t0);
|
||
SamplerState u_sampler : register(s0);
|
||
|
||
cbuffer hms_params : register(b0)
|
||
{
|
||
float4 u_resolution; // xy = Auflösung in Pixeln
|
||
float u_time_seconds;
|
||
float u_delta_seconds;
|
||
float u_frame_index;
|
||
float u_layer_opacity;
|
||
float u_audio_rms;
|
||
float u_audio_peak;
|
||
float u_audio_bass;
|
||
float u_audio_mid;
|
||
float u_audio_treble;
|
||
float u_audio_beat;
|
||
float param_amount;
|
||
float param_radius;
|
||
float param_softness;
|
||
float param_roundness;
|
||
float param_center_x;
|
||
float param_center_y;
|
||
float param_color_r;
|
||
float param_color_g;
|
||
float param_color_b;
|
||
float param_invert; // 0 = abdunkeln, 1 = aufhellen
|
||
float param_mix;
|
||
float _pad0;
|
||
float _pad1;
|
||
float _pad2;
|
||
float _pad3;
|
||
};
|
||
```
|
||
|
||
### 16-Byte-Alignment
|
||
|
||
HLSL-Konstantenpuffer werden in 16-Byte-Registern (`float4`) organisiert. Ein `float4` belegt ein Register; einzelne `float`-Werte werden in 16-Byte-Blöcken zusammengefasst. Das Beispiel füllt den Puffer mit `_pad0` bis `_pad3` auf ein Vielfaches von 16 Byte auf, damit das Layout deterministisch bleibt.
|
||
|
||
### Textur- und Sampler-Bindung
|
||
|
||
- `u_input_texture` ist an `register(t0)` gebunden.
|
||
- Der Sampler `u_sampler` ist an `register(s0)` gebunden.
|
||
- Der Konstantenpuffer `hms_params` ist an `register(b0)` gebunden.
|
||
|
||
## GLSL (OpenGL, Linux x64)
|
||
|
||
Das GL-Backend (`shaders/gl/main.frag`) deklariert die Uniforms einzeln:
|
||
|
||
```glsl
|
||
#version 330 core
|
||
|
||
uniform sampler2D u_input_texture;
|
||
uniform vec2 u_resolution;
|
||
uniform float u_time_seconds;
|
||
uniform float u_delta_seconds;
|
||
uniform float u_frame_index;
|
||
uniform float u_layer_opacity;
|
||
uniform float u_audio_rms;
|
||
uniform float u_audio_peak;
|
||
uniform float u_audio_bass;
|
||
uniform float u_audio_mid;
|
||
uniform float u_audio_treble;
|
||
uniform float u_audio_beat;
|
||
uniform float param_amount;
|
||
uniform float param_radius;
|
||
uniform float param_softness;
|
||
uniform float param_roundness;
|
||
uniform float param_center_x;
|
||
uniform float param_center_y;
|
||
uniform float param_color_r;
|
||
uniform float param_color_g;
|
||
uniform float param_color_b;
|
||
uniform float param_invert;
|
||
uniform float param_mix;
|
||
|
||
in vec2 v_uv;
|
||
out vec4 fragColor;
|
||
|
||
void main()
|
||
{
|
||
vec4 src = texture(u_input_texture, v_uv);
|
||
// ...
|
||
fragColor = out_c;
|
||
}
|
||
```
|
||
|
||
## GLES (OpenGL ES 2.0, Raspberry Pi)
|
||
|
||
Das GLES-Backend (`shaders/gles/main.frag`) folgt ES-2.0-Regeln:
|
||
|
||
```glsl
|
||
#version 100
|
||
precision mediump float;
|
||
|
||
uniform sampler2D u_input_texture;
|
||
uniform vec2 u_resolution;
|
||
uniform float u_time_seconds;
|
||
uniform float u_delta_seconds;
|
||
uniform float u_frame_index;
|
||
uniform float u_layer_opacity;
|
||
uniform float u_audio_rms;
|
||
uniform float u_audio_peak;
|
||
uniform float u_audio_bass;
|
||
uniform float u_audio_mid;
|
||
uniform float u_audio_treble;
|
||
uniform float u_audio_beat;
|
||
uniform float param_amount;
|
||
uniform float param_radius;
|
||
uniform float param_softness;
|
||
uniform float param_roundness;
|
||
uniform float param_center_x;
|
||
uniform float param_center_y;
|
||
uniform float param_color_r;
|
||
uniform float param_color_g;
|
||
uniform float param_color_b;
|
||
uniform float param_invert;
|
||
uniform float param_mix;
|
||
|
||
varying vec2 v_uv;
|
||
|
||
void main()
|
||
{
|
||
vec4 src = texture2D(u_input_texture, v_uv);
|
||
// ...
|
||
gl_FragColor = out_c;
|
||
}
|
||
```
|
||
|
||
## Backend-Syntaxunterschiede
|
||
|
||
Die drei Backends müssen semantisch identische Ergebnisse liefern (PLAN.md §12.6, §15.4). Die wichtigsten Syntaxunterschiede:
|
||
|
||
| Aspekt | HLSL (D3D11) | GLSL (OpenGL) | GLES (ES 2.0) |
|
||
| --- | --- | --- | --- |
|
||
| Version | `#version` nicht nötig | `#version 330 core` | `#version 100` |
|
||
| Texturzugriff | `u_input_texture.Sample(u_sampler, uv)` | `texture(u_input_texture, v_uv)` | `texture2D(u_input_texture, v_uv)` |
|
||
| Ausgabe | `return float4(...)` an `SV_Target` | `fragColor = ...` | `gl_FragColor = ...` |
|
||
| Eingabe | `float2 uv : TEXCOORD0` | `in vec2 v_uv` | `varying vec2 v_uv` |
|
||
| Clamp | `saturate(x)` | `clamp(x, 0.0, 1.0)` | `clamp(x, 0.0, 1.0)` |
|
||
| Mischen | `lerp(a, b, t)` | `mix(a, b, t)` | `mix(a, b, t)` |
|
||
| Präzision | – | – | `precision mediump float;` erforderlich |
|
||
|
||
### GLES-spezifische Regeln
|
||
|
||
- **Konstante Loop-Grenzen:** GLES 2.0 erlaubt nur Schleifen mit konstanten Grenzen. Dynamische Schleifengrenzen sind nicht zulässig.
|
||
- **`texture2D` statt `texture`:** In ES 2.0 wird `texture2D` verwendet.
|
||
- **Kein `atan2`:** Die Funktion `atan2` ist in ES 2.0 nicht verfügbar; verwende `atan(y, x)` mit zwei Argumenten oder baue die Logik selbst.
|
||
- **`precision`-Deklaration:** `precision mediump float;` muss vor den Uniforms stehen.
|
||
- **`varying` statt `in`/`out`:** ES 2.0 verwendet `varying` für Vertex-zu-Fragment-Daten.
|
||
|
||
## Multipass-Regeln
|
||
|
||
Multipass-Effekte (z. B. Gaussian Blur, PLAN.md §14.3) deklarieren mehrere Pässe im Manifest:
|
||
|
||
```json
|
||
"entrypoints": {
|
||
"d3d11": {
|
||
"type": "hlsl_multipass",
|
||
"passes": [
|
||
{"pixel_shader": "shaders/d3d11/horizontal.hlsl"},
|
||
{"pixel_shader": "shaders/d3d11/vertical.hlsl"}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
- Jeder Pass ist ein eigener Shader mit eigenem Dateipfad.
|
||
- Die Pässe werden in der deklarierten Reihenfolge ausgeführt; der Ausgang eines Passes ist der Eingang des nächsten.
|
||
- Jeder Pass erhält denselben Standard-Uniform-Satz.
|
||
- Die Semantik muss über alle Backends identisch sein.
|
||
|
||
## Adaptive-Quality-Varianten-Bindung
|
||
|
||
Adaptive-Quality-Varianten (PLAN.md §14.3, §15.4) können die interne Auflösung (`internal_scale`) und die Sample-Anzahl (`samples`) ändern. Die Bindung erfolgt über die deklarierten Varianten im Manifest:
|
||
|
||
```json
|
||
"adaptive_quality": {
|
||
"default": "auto",
|
||
"variants": [
|
||
{"id": "low", "internal_scale": 0.25, "samples": 5},
|
||
{"id": "medium", "internal_scale": 0.5, "samples": 9},
|
||
{"id": "high", "internal_scale": 1.0, "samples": 17}
|
||
]
|
||
}
|
||
```
|
||
|
||
Die Engine bindet die Variantenwerte an die Shader-Uniforms. Die Parameterwerte bleiben beim Wechsel der Auto-Qualitätsstufe semantisch identisch (PLAN.md §15.3). Details siehe [adaptive-quality.md](adaptive-quality.md).
|
||
|
||
## Mix-0-Bypass (§15.3)
|
||
|
||
Jeder Effekt besitzt einen `mix`-Parameter. `Mix 0` muss den Effekt kostengünstig bypassen. Das Vignette-Beispiel zeigt das Muster:
|
||
|
||
```hlsl
|
||
float m = saturate(param_mix);
|
||
if (m < 0.01)
|
||
{
|
||
return src; // Mix 0 = kostenloser Bypass (§15.3)
|
||
}
|
||
```
|
||
|
||
```glsl
|
||
float m = clamp(param_mix, 0.0, 1.0);
|
||
if (m < 0.01)
|
||
{
|
||
fragColor = src;
|
||
return;
|
||
}
|
||
```
|