Files
hms-mediaengine/docs/plugin-sdk/shader-contract.md
T

240 lines
7.8 KiB
Markdown
Raw Normal View History

# 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;
}
```