QSB-Handbuch

qsb ist ein Kommandozeilenwerkzeug, das vom Qt Shader Tools Modul bereitgestellt wird. Es integriert Bibliotheken von Drittanbietern wie glslang und SPIRV-Cross, ruft optional externe Werkzeuge wie fxc oder spirv-opt auf und erzeugt .qsb Dateien. Zusätzlich kann es verwendet werden, um den Inhalt eines .qsb Pakets zu untersuchen.

Usage: qsb [options] file
Qt Shader Baker (using QShader from Qt 6.8.0)

Options:
  -?, -h, --help               Displays help on commandline options.
  --help-all                   Displays help, including generic Qt options.
  -v, --version                Displays version information.
  -b, --batchable              Also generates rewritten vertex shader for Qt
                               Quick scene graph batching.
  --zorder-loc <location>      The extra vertex input location when rewriting
                               for batching. Defaults to 7.
  --glsl <versions>            Comma separated list of GLSL versions to
                               generate. (for example, "100 es,120,330")
  --hlsl <versions>            Comma separated list of HLSL (Shader Model)
                               versions to generate. F.ex. 50 is 5.0, 51 is 5.1.
  --msl <versions>             Comma separated list of Metal Shading Language
                               versions to generate. F.ex. 12 is 1.2, 20 is 2.0.
  --qt6                        Equivalent to --glsl "100 es,120,150" --hlsl 50
                               --msl 12. This set is commonly used with shaders
                               for Qt Quick materials and effects.
  --msltess                    Indicates that a vertex shader is going to be
                               used in a pipeline with tessellation. Mandatory
                               for vertex shaders planned to be used with
                               tessellation when targeting Metal (--msl).
  --tess-vertex-count <count>  The output vertex count from the tessellation
                               control stage. Mandatory for tessellation
                               evaluation shaders planned to be used with Metal.
                               The default value is 3. If it does not match the
                               tess.control stage, the generated MSL code will
                               not function as expected.
  --tess-mode <mode>           The tessellation mode: triangles or quads.
                               Mandatory for tessellation control shaders
                               planned to be used with Metal. The default value
                               is triangles. Isolines are not supported with
                               Metal. If it does not match the tess.evaluation
                               stage, the generated MSL code will not function
                               as expected.
  --view-count <num_views>     The number of views the shader is used with.
                               num_views must be >= 2. Mandatory when multiview
                               rendering is used (gl_ViewIndex). Set only for
                               vertex shaders that really do rely on multiview
                               (as the resulting asset is tied to num_views).
                               Can be set for fragment shaders too, to get
                               QSHADER_VIEW_COUNT auto-defined. (useful for
                               ensuring uniform buffer layouts)
  -g                           Generate full debug info for SPIR-V and DXBC
  -O                           Invoke spirv-opt (external tool) to optimize
                               SPIR-V for performance.
  -o, --output <filename>      Output file for the shader pack.
  --qsbversion <version>       QSB version to use for the output file. By
                               default the latest version is automatically used,
                               use only to bake compatibility versions. F.ex. 64
                               is Qt 6.4.
  -c, --fxc                    In combination with --hlsl invokes fxc (SM
                               5.0/5.1) or dxc (SM 6.0+) to store DXBC or DXIL
                               instead of HLSL.
  -t, --metallib               In combination with --msl builds a Metal library
                               with xcrun metal(lib) and stores that instead of
                               the source. Suitable only when targeting macOS,
                               not iOS.
  -T, --metallib-ios           In combination with --msl builds a Metal library
                               with xcrun metal(lib) and stores that instead of
                               the source. Suitable only when targeting iOS, not
                               macOS.
  -D, --define <name[=value]>  Define macro. This argument can be specified
                               multiple times.
  -p, --per-target             Enable per-target compilation. (instead of
                               source->SPIRV->targets, do source->SPIRV->target
                               separately for each target)
  -d, --dump                   Switches to dump mode. Input file is expected to
                               be a shader pack.
  -x, --extract <what>         Switches to extract mode. Input file is expected
                               to be a shader pack. Result is written to the
                               output specified by -o. Pass -b to choose the
                               batchable variant.
                               <what>=reflect|spirv,<version>|glsl,<version>|...
  -r, --replace <what>         Switches to replace mode. Replaces the specified
                               shader in the shader pack with the contents of a
                               file. This argument can be specified multiple
                               times. Pass -b to choose the batchable variant.
                               Also supports adding a shader for a
                               target/variant that was not present before.
                               <what>=<target>,<filename> where
                               <target>=spirv,<version>|glsl,<version>|...
  -e, --erase <what>           Switches to erase mode. Removes the specified
                               shader from the shader pack. Pass -b to choose
                               the batchable variant.
                               <what>=spirv,<version>|glsl,<version>|...
  -s, --silent                 Enables silent mode. Only fatal errors will be
                               printed.
  --depfile <depfile>          Enables generating the depfile for the input
                               shaders, using the #include statements.

Arguments:
  file                         Vulkan GLSL source file to compile. The file
                               extension determines the shader stage, and can be
                               one of .vert, .tesc, .tese, .frag, .comp. Note:
                               Tessellation control/evaluation is not supported
                               with HLSL, instead use -r to inject handcrafted
                               hull/domain shaders. Some targets may need
                               special arguments to be set, e.g. MSL
                               tessellation will likely need --msltess,
                               --tess-vertex-count, --tess-mode, depending on
                               the stage.

Betriebsarten

Es gibt fünf Hauptbetriebsarten:

  • .qsb Dateierzeugung.
  • .qsb Dateiprüfung. Zum Beispiel wird qsb -d myshader.frag.qsb die Reflection-Metadaten (in JSON-Form) und die enthaltenen Shader ausgeben.
  • Extraktionsmodus. Dies ermöglicht das Schreiben eines bestimmten Shaders aus einer bestehenden .qsb Datei in eine separate Datei. Zum Beispiel schreibt qsb -x spirv,100 -o myshader.spv myshader.frag.qsb die SPIR-V-Binärdatei in myshader.spv.
  • Ersetzen-Modus. Dies ermöglicht das Ersetzen des Inhalts eines oder mehrerer Shader in der Datei .qsb durch Inhalte, die aus den angegebenen Dateien gelesen wurden. Auf diese Weise kann selbst erstellter Shader-Code in das .qsb -Paket eingefügt werden.
  • Modus "Löschen". Damit wird die angegebene Shader-Variante aus der Datei .qsb entfernt.

Beispiel

Nehmen Sie den folgenden Fragment-Shader:

#version 440

layout(location = 0) in vec2 v_texcoord;
layout(location = 0) out vec4 fragColor;
layout(binding = 1) uniform sampler2D tex;

layout(std140, binding = 0) uniform buf {
    float uAlpha;
};

void main()
{
    vec4 c = texture(tex, v_texcoord);
    fragColor = vec4(c.rgb, uAlpha);
}

Die Ausführung von qsb -o shader.frag.qsb shader.frag führt zur Erzeugung von shader.frag.qsb. Die Überprüfung dieser Datei mit qsb -d shader.frag.qsb ergibt:

Stage: Fragment
QSB_VERSION: 5
Has 1 shaders:
  Shader 0: SPIR-V 100 [Standard]

Reflection info: {
    "combinedImageSamplers": [
        {
            "binding": 1,
            "name": "tex",
            "set": 0,
            "type": "sampler2D"
        }
    ],
    "inputs": [
        {
            "location": 0,
            "name": "v_texcoord",
            "type": "vec2"
        }
    ],
    "localSize": [
        0,
        0,
        0
    ],
    "outputs": [
        {
            "location": 0,
            "name": "fragColor",
            "type": "vec4"
        }
    ],
    "uniformBlocks": [
        {
            "binding": 0,
            "blockName": "buf",
            "members": [
                {
                    "name": "uAlpha",
                    "offset": 0,
                    "size": 4,
                    "type": "float"
                }
            ],
            "set": 0,
            "size": 4,
            "structName": "_27"
        }
    ]
}


Shader 0: SPIR-V 100 [Standard]
Entry point: main
Contents:
Binary of 864 bytes

Standardmäßig wird nur SPIR-V generiert, so dass eine Anwendung, die dieses Shader-Paket verwendet, nur mit Vulkan funktionieren würde. Lassen Sie es uns nützlicher machen:

qsb --glsl "100 es,120,150" --hlsl 50 --msl 12 -o shader.frag.qsb shader.frag

Dies führt zur Generierung eines Shader-Pakets, das auch für OpenGL, Direct 3D und Metal geeignet ist. Die in diesem Shader verwendeten Funktionen sind einfach, und sogar GLSL ES 100 (die Shading-Sprache von OpenGL ES 2.0) ist geeignet.

Ein Blick auf das Ergebnis zeigt:

Stage: Fragment
QSB_VERSION: 5
Has 6 shaders:
  Shader 0: GLSL 120 [Standard]
  Shader 1: HLSL 50 [Standard]
  Shader 2: GLSL 100 es [Standard]
  Shader 3: MSL 12 [Standard]
  Shader 4: SPIR-V 100 [Standard]
  Shader 5: GLSL 150 [Standard]

Reflection info: {
    ... <same as above>
}


Shader 0: GLSL 120 [Standard]
Entry point: main
Contents:
#version 120

struct buf
{
    float uAlpha;
};

uniform buf _27;

uniform sampler2D tex;

varying vec2 v_texcoord;

void main()
{
    vec4 c = texture2D(tex, v_texcoord);
    gl_FragData[0] = vec4(c.xyz, _27.uAlpha);
}

************************************

Shader 1: HLSL 50 [Standard]
Entry point: main
Native resource binding map:
0 -> [0, -1]
1 -> [0, 0]
Contents:
cbuffer buf : register(b0)
{
    float _27_uAlpha : packoffset(c0);
};

Texture2D<float4> tex : register(t0);
SamplerState _tex_sampler : register(s0);

static float2 v_texcoord;
static float4 fragColor;

struct SPIRV_Cross_Input
{
    float2 v_texcoord : TEXCOORD0;
};

struct SPIRV_Cross_Output
{
    float4 fragColor : SV_Target0;
};

void frag_main()
{
    float4 c = tex.Sample(_tex_sampler, v_texcoord);
    fragColor = float4(c.xyz, _27_uAlpha);
}

SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input)
{
    v_texcoord = stage_input.v_texcoord;
    frag_main();
    SPIRV_Cross_Output stage_output;
    stage_output.fragColor = fragColor;
    return stage_output;
}

************************************

...

Shader 3: MSL 12 [Standard]
Entry point: main0
Native resource binding map:
0 -> [0, -1]
1 -> [0, 0]
Contents:
#include <metal_stdlib>
#include <simd/simd.h>

using namespace metal;

struct buf
{
    float uAlpha;
};

struct main0_out
{
    float4 fragColor [[color(0)]];
};

struct main0_in
{
    float2 v_texcoord [[user(locn0)]];
};

fragment main0_out main0(main0_in in [[stage_in]], constant buf& _27 [[buffer(0)]], texture2d<float> tex [[texture(0)]], sampler texSmplr [[sampler(0)]])
{
    main0_out out = {};
    float4 c = tex.sample(texSmplr, in.v_texcoord);
    out.fragColor = float4(c.xyz, _27.uAlpha);
    return out;
}

************************************

...

Dieses Paket kann nun von Qt Quick mit allen unterstützten Grafik-APIs verwendet werden: Vulkan, Direct 3D, Metal, OpenGL und OpenGL ES. Zur Laufzeit wird der passende Shader automatisch vom Qt Rendering Hardware Interface, das sich unter Qt Quick und Qt Quick 3D befindet, ausgewählt.

Neben der Rückübersetzung des SPIR-V-Bytecodes in höherwertigen Quellcode kümmert sich das System um weitere Probleme, wie z. B. die Gewährleistung der korrekten Zuordnung von SPIR-V-Bindungsnummern zu nativen Ressourcen. Bei HLSL haben wir zum Beispiel einen Abschnitt wie diesen oben gesehen:

Native resource binding map:
 0 -> [0, -1]
 1 -> [0, 0]

Intern ermöglicht dies die Abbildung eines SPIR-V-Bindungspunkts 0 auf das HLSL-Register b0 und die Bindung 1 an t0 und s0. Dies trägt dazu bei, die Unterschiede in den Ressourcenbindungen zwischen den verschiedenen Shading-Sprachen für die Benutzer der Rendering-Hardware-Schnittstelle transparent zu machen, und ermöglicht es, dass alles in Qt mit Vulkan/SPIR-V-Stil-Bindungspunkten arbeitet, wie sie im ursprünglichen Vulkan-Stil-GLSL-Quellcode angegeben sind.

Shader-Typen

Der Typ des Shaders wird aus der Erweiterung der Eingabedatei abgeleitet. Daher muss die Erweiterung eine der folgenden sein:

  • .vert - für Vertex-Shader
  • .tesc - für Tesselationssteuerungs-Shader
  • .tese - für Tesselationsauswertungs-Shader
  • .frag - für Fragment-Shader (Pixel-Shader)
  • .comp - für Berechnungs-Shader

Hinweis: Tessellierungssteuerungs- und Evaluierungs-Shader werden derzeit nicht mit Direct 3D (HLSL) unterstützt.

Shading-Sprachen und -Versionen

SPIR-V 1.0 wird immer generiert. Was darüber hinaus generiert wird, hängt von den Befehlszeilenargumenten --glsl, --hlsl und --msl ab.

Diesen Parametern folgt jeweils eine durch Komma getrennte Liste. Die Liste muss Versionsnummern im GLSL-Stil enthalten, mit einem optionalen Suffix (es, das für GLSL ES steht). Das Leerzeichen zwischen dem Suffix und der Version ist optional (das Fehlen des Leerzeichens kann helfen, die Notwendigkeit von Anführungszeichen zu vermeiden).

Zum Beispiel bereiten die eingebauten Materialien von Qt Quick(die Shader, die Elemente wie Image, Text, Rectangle unterstützen) alle ihre Shader mit --glsl "100 es,120,150" --hlsl 50 --msl 12 vor. Dadurch sind sie kompatibel mit OpenGL ES 2.0 und höher, OpenGL 2.1 und höher sowie OpenGL-Kernprofilkontexten der Version 3.2 und höher.

Wenn der Shader Funktionen oder Konstrukte verwendet, die keine Entsprechung in den angegebenen Zielen haben, schlägt qsb fehl. In diesem Fall müssen die Ziele angepasst werden, was auch bedeutet, dass die Mindestsystemanforderungen der Anwendung implizit angepasst werden. Nehmen wir als Beispiel die GLSL-Funktion textureLod, die nur mit OpenGL ES 3.0 und höher verfügbar ist (d. h. GLSL ES 300 oder höher). Wenn die GLSL-Funktion 300 es anstelle von 100 es angefordert wird, wird qsb erfolgreich sein, aber die Anwendung, die diese .qsb -Datei verwendet, benötigt nun OpenGL ES 3.0 oder höher und ist nicht mit OpenGL ES 2.0-basierten Systemen kompatibel.

Ein weiteres offensichtliches Beispiel hierfür sind Compute-Shader: .comp Shader müssen --glsl 310es,430 angeben, da Compute-Shader nur mit OpenGL ES 3.1 oder neuer und OpenGL 4.3 oder neuer verfügbar sind.

Die Anpassung der Shader-Modell-Version für HLSL oder die Metal Shading Language-Version wird voraussichtlich nur selten erforderlich sein. Shader Model 5.0 (--hlsl 50) und MSL 1.2 (--msl 12) sind normalerweise ausreichend.

Qt Quick Scene Graph Batching

Der Renderer des Qt Quick Scene Graphs unterstützt das Batching von Geometrie, um die Anzahl der Zeichenaufrufe zu reduzieren. Siehe die Scene Graph Seiten für Details. Dies beruht auf dem Einfügen von Code in die main()-Funktion des Vertex-Shaders. In Qt 5.x geschah dies zur Laufzeit, indem der mitgelieferte GLSL-Vertexshader-Code modifiziert wurde. In Qt 6 ist das nicht mehr möglich. Stattdessen können batchfähige Varianten von Vertex-Shadern durch das qsb Werkzeug erstellt werden. Dies wird durch das Argument -b angefordert. Wenn es sich bei der Eingabe nicht um einen Vertex-Shader mit der Erweiterung .vert handelt, hat dies keinen Effekt. Bei Vertex-Shadern führt es jedoch dazu, dass für jedes Ziel zwei Versionen erzeugt werden. Qt Quick wählt dann zur Laufzeit automatisch die richtige Variante (Standard oder Batchable).

Hinweis: Die Anwendungen müssen sich nicht mit den Details des Batching befassen. Sie müssen lediglich sicherstellen, dass -b (oder das entsprechende BATCHABLE -Schlüsselwort, wenn sie die CMake-Integration verwenden) bei der Verarbeitung der Vertex-Shader angegeben wird. Dies ist nur für Qt Quick Shader relevant, die mit ShaderEffect oder QSGMaterialShader verwendet werden.

Nehmen Sie den folgenden Beispiel-Vertex-Shader:

#version 440
layout(location = 0) in vec4 position;
layout(location = 1) in vec2 texcoord;
layout(location = 0) out vec2 v_texcoord;
layout(std140, binding = 0) uniform buf {
    mat4 mvp;
} ubuf;

void main()
{
    v_texcoord = texcoord;
    gl_Position = ubuf.mvp * position;
}

Die Ausführung von qsb -b --glsl 330 -o example.vert.qsb example.vert führt zu:

Stage: Vertex
QSB_VERSION: 5
Has 4 shaders:
  Shader 0: GLSL 330 [Standard]
  Shader 1: GLSL 330 [Batchable]
  Shader 2: SPIR-V 100 [Standard]
  Shader 3: SPIR-V 100 [Batchable]

Reflection info: {
  ...

Beachten Sie, dass alle Zielsprachen und -versionen jetzt in zwei Varianten existieren: Standard und ein leicht modifiziertes Batchable.

Aufrufen externer Tools

qsb kann bestimmte externe Tools aufrufen. Diese fallen in zwei Kategorien: Tools zur Durchführung von Optimierungen am Shader-Bytecode (SPIR-V) und plattformspezifische Tools zur Durchführung der ersten Phase der Shader-Kompilierung, vom Quellcode zu einem Bytecode-Zwischenformat.

Diese werden durch die folgenden Befehlszeilenoptionen aktiviert:

  • -O - ruft spirv-opt als Nachbearbeitungsschritt für die SPIR-V-Binärdatei auf. Die Datei .qsb wird die optimierte Version enthalten. Dies setzt voraus, dass spirv-opt auf dem System verfügbar ist (z. B. aus dem Vulkan-SDK) und aufgerufen werden kann.
  • -c oder --fxc - ruft fxc.exe auf, den Direct 3D-Shader-Compiler. Die resultierenden DXBC (DirectX Byte Code) Daten werden in der .qsb Datei anstelle von HLSL gespeichert. Qt übernimmt sie zur Laufzeit automatisch, so dass es dem Ersteller der .qsb Datei überlassen bleibt, ob er den HLSL-Quellcode oder das Zwischenformat einbinden möchte. Wann immer es möglich ist, sollten Sie letzteres bevorzugen, da es die Notwendigkeit des Parsens einer HLSL-Quelle zur Laufzeit eliminiert, was zu potenziell signifikanten Leistungssteigerungen bei der Erstellung der Grafikpipeline führt. Der Nachteil ist, dass dieses Argument nur verwendet werden kann, wenn qsb unter Windows läuft.
  • -t oder --metallib - ruft die entsprechenden XCode-Metal-Tools auf, um eine .metallib-Datei zu erzeugen, und fügt diese in das .qsb -Paket anstelle des MSL-Quellcodes ein. Diese Option ist nur verfügbar, wenn qsb unter macOS ausgeführt wird.

Andere Optionen

  • -D - definiert ein Makro. Dies ermöglicht die Verwendung von #ifdef und ähnlichem im GLSL-Quellcode.
  • -g - ermöglicht es, vollständige Debug-Informationen für SPIR-V zu generieren, so dass Tools wie RenderDoc den vollständigen Quellcode anzeigen können, wenn sie eine Pipeline inspizieren oder Vertex- oder Fragment-Debugging durchführen. Hat auch Auswirkungen auf Direct 3D, wenn -c angegeben wird, da fxc dann angewiesen wird, Debug-Informationen in den generierten Zwischen-Bytecode aufzunehmen.

Tesselierung

  • --msltess - Zeigt an, dass der Vertex-Shader in einer Pipeline verwendet wird, die Tesselierungsstufen enthält. Hat keine Auswirkung für andere Shadertypen und wenn die MSL-Shader-Generierung nicht aktiviert ist. Wenn nicht angegeben, ist der Vertex-Shader auf Metal in Kombination mit Tesselation nicht funktionsfähig.
  • --tess-vertex-count <count> - Gibt die Anzahl der Scheitelpunkte an, die von der Tesselation-Steuerungsstufe ausgegeben werden. Diese Angabe ist für Tesselation-Evaluierungs-Shader, die mit Metal verwendet werden, obligatorisch. Der Standardwert ist 3. Wenn er nicht mit der Tessellierungssteuerungsstufe übereinstimmt, funktioniert der generierte MSL-Code nicht wie erwartet.
  • --tess-mode <mode> - Diese Option gibt den Tesselierungsmodus an. Sie kann einen von zwei Werten annehmen: triangles oder quads. Der Standardwert ist triangles. Die Angabe dieser Option ist für Tessellation Control Shader, die mit Metal verwendet werden, obligatorisch. Der Wert muss mit der Tessellationsevaluierungsstufe übereinstimmen, andernfalls wird der generierte MSL-Code nicht wie erwartet funktionieren.

Multiview

Nehmen Sie den folgenden Vertex-Shader. Er ist als Vulkan-kompatibles GLSL geschrieben, so dass die GL_EXT_multiview -Erweiterung die Verwendung von gl_ViewIndex legal macht.

#version 440
#extension GL_EXT_multiview : require

layout(location = 0) in vec4 pos;
layout(std140, binding = 0) uniform buf
{
    mat4 mvp[2];
};

void main()
{
    gl_Position = mvp[gl_ViewIndex] * pos;
}

Hinweis: In der Praxis wird die Zeile #extension GL_EXT_multiview im Quellcode, der an qsb übergeben wird, nicht benötigt, da die Übergabe des unten beschriebenen Arguments --view-count diese Zeile automatisch in den Shader-Quellcode injiziert, bevor er nach SPIR-V kompiliert wird.

Für Vulkan funktioniert dies so, wie es ist, solange Vulkan 1.1 zur Laufzeit unterstützt wird. Siehe VK_KHR_multiview für Details.

Um einen HLSL-Vertex-Shader aus dem oben genannten für Direct 3D 12 zu generieren (siehe View Instancing für Details), ist die minimale Shader-Modell-Version 6.1, was bedeutet, dass qsb fehlschlägt, wenn z.B. --hlsl 50 angegeben wird. Verwenden Sie mindestens --hlsl 61, wenn Sie einen Multiview-Vertex-Shader verarbeiten. Multiview wird von Direct 3D 11 nicht unterstützt.

Für OpenGL werden zusätzliche Metadaten benötigt:

  • --view-count - Wenn obiger Shader (nach der Kompilierung nach SPIR-V) in OpenGL-kompatiblen GLSL-Quellcode transpiliert wird, reicht es nicht aus, gl_ViewIndex auf gl_ViewID_OVR zu mappen, sondern die Anzahl der Ansichten muss ebenfalls im Shader deklariert werden. Die Übergabe eines Wertes von 2 an das Argument --view-count führt dazu, dass eine layout(num_views = 2) in; -Anweisung in den generierten GLSL-Quellcode eingefügt wird, wodurch dieser zu einem gültigen (OpenGL-)GLSL-Shader wird. Siehe GL_OVR_multiview für Details und beachte, dass die generierten GLSL-Shader auch GL_OVR_multiview2 benötigen, um zur Laufzeit unterstützt zu werden, da es das ist, was von der #extension Anweisung im generierten Shader-Quellcode benötigt wird.

Wenn man OpenGL (ES) mit einem solchen Vertex-Shader anspricht, muss die generierte GLSL-Version (--glsl) mindestens 330 oder 300 es sein. Ersteres wird nicht von qsb oder QShaderBaker erzwungen, aber in der Praxis sind OpenGL-Implementierungen dafür bekannt, solche Shader abzulehnen, wenn die GLSL-Version 150 oder kleiner ist. Daher wird empfohlen, --glsl 330,300es zu übergeben, wenn man Vertex-Shader konditioniert, die GL_EXT_multiview aktivieren.

Die Angabe von --view-count generiert und injiziert automatisch ein Präprozessor-Definition: #define QSHADER_VIEW_COUNT n, wobei n die Anzahl der Ansichten ist. Wenn die Anzahl der Ansichten nicht angegeben wird, wird das Define überhaupt nicht gesetzt. Dies ermöglicht das Schreiben von Code wie dem folgenden und die Verwendung der gleichen Quelldatei für alle View Count-spezifischen Varianten des Shaders.

layout(std140, binding = 0) uniform buf {
#if QSHADER_VIEW_COUNT >= 2
    mat4 matrix[QSHADER_VIEW_COUNT];
#else
    mat4 matrix;
#endif
    float opacity;
};

Darüber hinaus wird die Zeile #extension GL_EXT_multiview : require in Vertex-Shadern automatisch generiert, wenn ein View-Count von 2 oder mehr festgelegt wird. Dies reduziert die Anzahl der zusätzlichen Zeilen, die für die Unterstützung mehrerer Ansichten in einem Vertex-Shader hinzugefügt werden müssen.

Das Festlegen der Anzahl der Ansichten kann auch bei anderen Shader-Typen von Bedeutung sein. Wenn zum Beispiel der Vertex-Shader und der Fragment-Shader sich einen einheitlichen Puffer teilen und beide Shader das gleiche Pufferlayout sicherstellen müssen, kann es nützlich sein, #if QSHADER_VIEW_COUNT >= 2 in beide Quelldateien schreiben zu können. Dies kann durch die Angabe von --view-count für beide beim Aufruf von qsb sichergestellt werden.

Hinweis: Sich direkt auf das Schlüsselwort gl_ViewIndex in einer Nicht-Vertex-Stufe zu verlassen, zum Beispiel in einem Fragment-Shader, ist derzeit nicht portabel und sollte vermieden werden.

Arbeiten mit GLSL-Funktionen, die spezifisch für OpenGL sind

Manchmal kann es notwendig sein, Shading-Sprachkonstrukte zu verwenden, die spezifisch für OpenGL und GLSL sind und nicht für andere Shading-Sprachen, Zwischenformate und Grafik-APIs gelten.

Das beste Beispiel hierfür sind die externen Texturen und Sampler von OpenGL ES. Bei der Implementierung der Videowiedergabe oder der Anzeige eines Kamerasuchers kann es je nach Plattform erforderlich sein, mit OpenGL-Texturobjekten zu arbeiten, die nicht als reguläre 2D-Texturen verwendet werden sollen, sondern mit einem begrenzten Funktionsumfang über den Bindungspunkt GL_TEXTURE_EXTERNAL_OES in der OpenGL-API und den Sampler-Typ samplerExternalOES in Shadern nutzbar sind. Letzterer stellt einen potentiellen Showstopper dar, wenn die SPIR-V basierte Shader-Pipeline von Qt verwendet wird: das Ausführen eines solchen Shaders durch qsb wird zu einem Fehler führen, da samplerExternalOES nicht als gültiger Typ akzeptiert wird, da er nicht auf SPIR-V und andere Shading-Zielsprachen abgebildet werden kann.

Um dies zu umgehen, bietet qsb die Möglichkeit, den Inhalt einer beliebigen Shader-Variante in einer .qsb-Datei durch vom Benutzer bereitgestellte Daten zu ersetzen, die aus einer Datei gelesen werden und den ursprünglichen, von qsb generierten Shader-Quell- oder Bytecode vollständig ersetzen.

Nehmen Sie den folgenden Fragment-Shader. Beachten Sie den Typ von tex. Was ist, wenn der Typ samplerExternalOES sein muss, wenn er mit OpenGL ES ausgeführt wird?

#version 440

layout(location = 0) in vec2 texCoord;
layout(location = 0) out vec4 fragColor;

layout(std140, binding = 0) uniform buf {
    float opacity;
} ubuf;

layout(binding = 1) uniform sampler2D tex;

void main()
{
    fragColor = texture(tex, texCoord).rgba * ubuf.opacity;
}

Einfach den Typ von samplerExternalOES zu ändern ist nicht machbar. Das führt sofort zu Kompilierungsfehlern.

Es gibt jedoch eine einfache Lösung: Man schreibt eine separate, rein auf OpenGL ES ausgerichtete Version des Shaders und fügt sie in die .qsb-Datei ein. Der folgende Shader ist nur mit GLSL ES kompatibel und kann nicht über qsb ausgeführt werden. Wir wissen jedoch, dass er zur Laufzeit von OpenGL ES verarbeitet werden kann.

precision highp float;
#extension GL_OES_EGL_image_external : require
varying vec2 texCoord;

struct buf
{
    float opacity;
};

uniform buf ubuf;
uniform samplerExternalOES tex;

void main()
{
    gl_FragColor = texture2D(tex, texCoord).rgba * ubuf.opacity;
}

Nennen wir ihn shader_gles.frag. Sobald qsb --glsl 100es -o shader.frag.qsb shader.frag fertig ist und uns eine (halbfertige) .qsb-Datei liefert, können wir qsb -r glsl,100es,shader_gles.frag shader.frag.qsb ausführen, um shader.frag.qsb zu aktualisieren, indem wir den Shader für GLSL 100 es durch den Inhalt der angegebenen Datei ersetzen (shader_gles.frag). Jetzt ist shader.frag.qsb bereit, zur Laufzeit mit OpenGL ES verwendet zu werden.

Hinweis: Achten Sie darauf, dass die Schnittstelle zwischen dem Shader und der Anwendung unverändert bleibt. Überprüfen Sie immer zuerst den von qsb erzeugten GLSL-Code, entweder durch Ausdrucken des Inhalts der .qsb-Datei über die Option -d oder durch Extrahieren des GLSL ES 100-Shaders durch Ausführen von qsb -x glsl,100es -o gles_shader.frag shader.frag.qsb. Die struct-, struct-member- und uniform-Namen dürfen sich auch in der manuell injizierten Version nicht unterscheiden.

Hinweis: Die Möglichkeit, Daten aus beliebigen Dateien in das .qsb-Paket zu platzieren, kann auch dazu verwendet werden, handgefertigte Hull- und Domain-HLSL-Shader zu injizieren, um tesselationsbasierte Grafikpipelines auch mit Direct 3D funktionsfähig zu machen.

© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.