En esta página

Manual QSB

qsb es una herramienta de línea de comandos proporcionada por el módulo Qt Shader Tools. Integra bibliotecas de terceros, como glslang y SPIRV-Cross, invoca opcionalmente herramientas externas, como fxc o spirv-opt, y genera archivos .qsb. Además, puede utilizarse para inspeccionar el contenido de un paquete .qsb.

Usage: qsb [options] file
Qt Shader Baker (using QShader from Qt 6.10.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.
  --orig-file <filename>       Filename to be be used for dependency tracking
                               instead of <file>.
  --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.
  --mediump                    Default to medium precision for floats in
                               fragment shaders instead of high. GLSL ES only;
                               ignored for everything else, including GLSL.
  --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, .geom, .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. Geometry shaders are not supported
                               with Metal.

Modos de funcionamiento

Existen cinco modos principales de funcionamiento:

  • .qsb generación de ficheros.
  • .qsb inspección de ficheros. Por ejemplo, qsb -d myshader.frag.qsb imprimirá los metadatos de reflexión (en forma JSON) y los sombreadores incluidos.
  • Modo de extracción. Esto permite escribir un determinado shader de un archivo .qsb existente en un archivo separado. Por ejemplo, qsb -x spirv,100 -o myshader.spv myshader.frag.qsb escribe el binario SPIR-V en myshader.spv.
  • Modo de sustitución. Permite sustituir el contenido de uno o varios sombreadores del archivo .qsb por contenido leído de los archivos especificados. De esta forma se puede inyectar código shader artesanal en el paquete .qsb.
  • Modo de borrado. Esto elimina la variante de shader especificada del archivo .qsb.

Ejemplo

Tomemos el siguiente 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);
}

Al ejecutar qsb -o shader.frag.qsb shader.frag se genera shader.frag.qsb. Inspeccionando este archivo con qsb -d shader.frag.qsb nos da:

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

Por defecto sólo se genera SPIR-V, por lo que una aplicación que utilice este paquete de shaders sólo sería funcional con Vulkan. Hagámoslo más útil:

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

Esto nos lleva a generar un paquete de shaders que lo hace apto para OpenGL, Direct 3D y Metal también. Las características utilizadas en este shader son básicas, e incluso GLSL ES 100 (el lenguaje de sombreado de OpenGL ES 2.0) es adecuado.

Inspeccionando el resultado se ve:

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

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

...

Este paquete ahora puede ser utilizado por Qt Quick con todas las APIs gráficas soportadas: Vulkan, Direct 3D, Metal, OpenGL y OpenGL ES. En tiempo de ejecución el shader apropiado es recogido automáticamente por la Interfaz de Hardware de Renderizado Qt que se encuentra debajo de Qt Quick y Qt Quick 3D.

Además de traducir el código de bytes de SPIR-V a código fuente de nivel superior, el sistema se ocupa de otros problemas, como garantizar la correcta asignación de los números de enlace de SPIR-V a los recursos nativos. Por ejemplo, con HLSL vimos una sección como ésta más arriba:

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

Internamente, esto permite mapear un punto de enlace de estilo SPIR-V 0 al registro HLSL b0 y enlazar 1 a t0 y s0. Esto ayuda a que las diferencias en los enlaces de recursos entre los distintos lenguajes de sombreado sean transparentes para los usuarios de la Interfaz de Hardware de Renderizado, y permite que todo en Qt funcione con puntos de enlace de estilo Vulkan/SPIR-V tal y como se especifican en el código fuente original de GLSL de estilo Vulkan.

Tipos de sombreadores

El tipo de shader se deduce de la extensión del archivo de entrada. Así, la extensión debe ser una de las siguientes

  • .vert - para sombreadores de vértices
  • .tesc - para shaders de control de teselación
  • .tese - para shaders de evaluación de teselación
  • .geom - para shaders de geometría
  • .frag - para sombreadores de fragmentos (píxeles)
  • .comp - para sombreadores de cálculo

Nota: Los shaders de control y evaluación de teselado no son compatibles actualmente con Direct 3D (HLSL).

Lenguajes y versiones de sombreado

SPIR-V 1.0 siempre se genera. Lo que se genera además depende de los argumentos de la línea de comandos --glsl, --hlsl, y --msl.

Todos estos parámetros van seguidos de una lista separada por comas. La lista debe incluir números de versión estilo GLSL, con un sufijo opcional (es, que indica GLSL ES). El espacio entre el sufijo y la versión es opcional (no tener el espacio puede ayudar a evitar la necesidad de entrecomillar).

Por ejemplo, los materiales incorporados en Qt Quick(los shaders que respaldan elementos como Image, Text, Rectangle) preparan todos sus shaders con --glsl "100 es,120,150" --hlsl 50 --msl 12. Esto los hace compatibles con OpenGL ES 2.0 y superior, OpenGL 2.1 y superior, y contextos de perfil de núcleo OpenGL de la versión 3.2 y superior.

Si el sombreador utiliza funciones o construcciones que no tienen un equivalente en los objetivos especificados, qsb fallará. En ese caso, será necesario ajustar los objetivos, lo que también significa que los requisitos mínimos del sistema de la aplicación se ajustan implícitamente. Como ejemplo, tomemos la función GLSL textureLod que sólo está disponible con OpenGL ES 3.0 y superior (lo que significa GLSL ES 300 o superior). Si se solicita GLSL 300 es en lugar de 100 es, qsb tendrá éxito, pero la aplicación que utilice ese archivo .qsb requerirá ahora OpenGL ES 3.0 o superior y no será compatible con sistemas basados en OpenGL ES 2.0.

Otro ejemplo obvio de esto son los sombreadores de cálculo: los sombreadores .comp necesitarán especificar --glsl 310es,430 ya que los sombreadores de cálculo sólo están disponibles con OpenGL ES 3.1 o superior y OpenGL 4.3 o superior.

Se espera que rara vez sea necesario ajustar la versión del modelo de sombreado para HLSL o la versión de Metal Shading Language. Shader Model 5.0 (--hlsl 50) y MSL 1.2 (--msl 12) suelen ser suficientes.

Qt Quick Batching de gráficos de escena

El renderizador de Qt Quick Scene Graph admite el procesamiento por lotes de geometría para reducir el número de llamadas a dibujo. Consulte las páginas de Scene Graph para obtener más información. Esto se basa en inyectar código en la función main() del sombreador de vértices. En Qt 5.x esto ocurría en tiempo de ejecución, modificando el código GLSL del sombreador de vértices. En Qt 6 eso no es una opción. En su lugar, la herramienta qsb puede crear variantes por lotes de los sombreadores de vértices. Esto se solicita mediante el argumento -b. Cuando la entrada no es un sombreador de vértices con extensión .vert, no tiene ningún efecto. Sin embargo, en el caso de los sombreadores de vértices, generará dos versiones para cada objetivo. Qt Quick elegirá automáticamente la variante correcta (estándar o por lotes) en tiempo de ejecución.

Nota: Las aplicaciones no tienen que preocuparse de los detalles de la dosificación. Simplemente deben asegurarse de que se especifica -b (o la palabra clave equivalente BATCHABLE si se utiliza la integración CMake) al procesar los sombreadores de vértices. Esto sólo es relevante para los sombreadores Qt Quick utilizados con ShaderEffect o QSGMaterialShader.

Tomemos el siguiente ejemplo de sombreador de vértices:

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

Ejecutando qsb -b --glsl 330 -o example.vert.qsb example.vert se obtiene:

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: {
  ...

Observe cómo todos los lenguajes y versiones de destino existen ahora en dos variantes: Estándar y Batchable ligeramente modificado.

Invocación de herramientas externas

qsb puede invocar ciertas herramientas externas. Éstas se dividen en dos categorías: herramientas para realizar optimizaciones en el bytecode del shader (SPIR-V), y herramientas específicas de la plataforma para realizar la primera fase de la compilación del shader, desde el código fuente a algún formato de bytecode intermedio.

Estas herramientas se activan mediante las siguientes opciones de línea de comandos:

  • -O - invoca spirv-opt como paso de posprocesamiento en el binario SPIR-V. El archivo .qsb incluirá la versión optimizada. Esto supone que spirv-opt está disponible en el sistema (por ejemplo, desde el SDK de Vulkan) y listo para ser invocado.
  • -c o --fxc - invoca fxc.exe, el compilador de shaders Direct 3D. Los datos resultantes de DXBC (DirectX Byte Code) son los que se almacenan en el archivo .qsb en lugar de HLSL. Qt lo recogerá automáticamente en tiempo de ejecución, por lo que depende del creador del archivo .qsb decidir qué incluir, el código fuente HLSL o el formato intermedio. Siempre que sea posible, prefiera este último, ya que elimina la necesidad de analizar una fuente HLSL en tiempo de ejecución, lo que lleva a ganancias de rendimiento potencialmente significativas en la creación de tuberías gráficas. El inconveniente es que este argumento sólo puede utilizarse cuando qsb se ejecuta en Windows.
  • -t o --metallib - invoca las herramientas XCode Metal apropiadas para generar un archivo .metallib e incluirlo en el paquete .qsb en lugar del código fuente MSL. Esta opción sólo está disponible cuando qsb se ejecuta en macOS.

Otras opciones

  • -D - define una macro. Esto permite usar #ifdef y similares en el código fuente GLSL.
  • -g - permite generar información completa de depuración para SPIR-V, permitiendo así que herramientas como RenderDoc muestren el código fuente completo al inspeccionar un pipeline o al realizar depuración de vértices o fragmentos. También tiene efecto para Direct 3D cuando se especifica -c, ya que fxc recibe instrucciones para incluir información de depuración en el bytecode intermedio generado.
  • --mediump - solicita por defecto precisión media para flotantes en sombreadores de fragmentos GLSL ES. Ignorado para cualquier otro objetivo, incluyendo GLSL (no ES), y para shaders no fragmentados.
  • --orig-file - especifica el nombre de archivo que se utiliza en lugar del archivo fuente de entrada al generar archivos de dependencia para CMake (-depfiles). Esto es útil cuando el archivo que se pasa a qsb es un archivo fuente de sombreado intermedio generado. Sin embargo, a efectos de seguimiento de dependencias, a menudo es el archivo original el que debe utilizarse.

Teselación

  • --msltess - Indica que el sombreador de vértices se utiliza en un canal que incluye etapas de teselación. No tiene efecto para otros tipos de shaders, y cuando la generación de shaders MSL no está activada. Si no se especifica, el sombreador de vértices no funcionará en Metal en combinación con el teselado.
  • --tess-vertex-count <count> - Especifica el recuento de vértices de salida de la etapa de control de teselación. Su especificación es obligatoria para los sombreadores de evaluación de teselación utilizados con Metal. El valor predeterminado es 3. Si no coincide con la etapa de control de teselación, el código MSL generado no funcionará como se espera.
  • --tess-mode <mode> - Esta opción especifica el modo de teselación. Puede tomar uno de estos dos valores: triangles o quads. El valor por defecto es triangles. Especificar esto es obligatorio para los shaders de control de teselación utilizados con Metal. El valor debe coincidir con la etapa de evaluación de teselación, de lo contrario el código MSL generado no funcionará como se espera.

Multivista

Tome el siguiente sombreador de vértices. Está escrito como GLSL compatible con Vulkan, habilitando la extensión GL_EXT_multiview para que el uso de gl_ViewIndex sea legal.

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

Nota: En la práctica, la línea #extension GL_EXT_multiview no será necesaria en el código fuente pasado a qsb, porque al pasar el argumento --view-count descrito a continuación se inyecta automáticamente esa línea en el código fuente del shader antes de compilar a SPIR-V.

Para Vulkan esto funciona tal cual, siempre y cuando Vulkan 1.1 sea compatible en tiempo de ejecución. Ver VK_KHR_multiview para más detalles.

Para generar un sombreador de vértices HLSL a partir de lo anterior para Direct 3D 12 (ver instanciación de vistas para más detalles), la versión mínima del modelo de sombreado es 6.1, lo que significa que qsb fallará cuando se especifique, por ejemplo, --hlsl 50. Utilice al menos --hlsl 61 cuando procese un sombreador de vértices multivista. Multiview no es compatible con Direct 3D 11.

Para OpenGL, se necesitan metadatos adicionales:

  • --view-count - Al transpilar el sombreador anterior (después de compilarlo en SPIR-V) al código fuente GLSL compatible con OpenGL, no basta con asignar gl_ViewIndex a gl_ViewID_OVR, sino que también es necesario declarar el número de vistas en el sombreador. Pasando un valor de 2 al argumento --view-count se inyecta una declaración layout(num_views = 2) in; en el código fuente GLSL generado, convirtiéndolo así en un shader GLSL válido (OpenGL). Vea GL_OVR_multiview para más detalles y tenga en cuenta que los shaders GLSL generados también requieren que GL_OVR_multiview2 esté soportado en tiempo de ejecución ya que es lo que va a requerir la directiva #extension en el código fuente del shader generado.

Cuando se utiliza OpenGL (ES) con un sombreador de vértices de este tipo, la versión GLSL generada (--glsl) debe ser al menos 330 o 300 es. Lo primero no es algo impuesto por qsb o QShaderBaker, pero en la práctica se sabe que las implementaciones de OpenGL rechazan este tipo de sombreadores si la versión GLSL es 150 o menor. De ahí que se recomiende pasar --glsl 330,300es cuando se condicionen sombreadores de vértices que habiliten GL_EXT_multiview.

Especificando --view-count automáticamente genera e inyecta una definición de preprocesador: #define QSHADER_VIEW_COUNT n donde n es el número de vistas. Si no se indica el número de vistas, la definición no se define. Esto permite escribir código como el siguiente, y permite usar el mismo archivo fuente para todas las variantes del shader específicas del número de vistas.

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

Además, la línea #extension GL_EXT_multiview : require se genera automáticamente en los sombreadores de vértices siempre que se establece un recuento de vistas de 2 o superior. Esto reduce el número de líneas adicionales que hay que añadir para el soporte multivista en un sombreador de vértices.

Establecer el recuento de vistas también puede ser relevante con otros tipos de sombreadores. Por ejemplo, cuando se comparte un búfer uniforme entre el sombreador de vértices y el de fragmentos, y ambos sombreadores tienen que garantizar la misma disposición del búfer, puede ser útil poder escribir #if QSHADER_VIEW_COUNT >= 2 en ambos archivos fuente. Esto se puede asegurar especificando --view-count para ambos al invocar qsb.

Nota: Depender directamente de la palabra clave gl_ViewIndex en una etapa que no sea de vértices, por ejemplo en un fragment shader, no es portable por el momento y debería evitarse.

Trabajar con funciones GLSL específicas de OpenGL

A veces puede ser necesario utilizar construcciones del lenguaje de sombreado que son específicas de OpenGL y GLSL, y no son aplicables a otros lenguajes de sombreado, formatos intermedios y APIs gráficas.

Los principales ejemplos son las texturas externas y los muestreadores de OpenGL ES. Implementar la reproducción de vídeo o mostrar el visor de una cámara puede implicar, en función de la plataforma, trabajar con objetos de textura de OpenGL que no están pensados para ser utilizados como texturas 2D normales, sino que son más bien utilizables, con un conjunto de características limitadas, a través del punto de enlace GL_TEXTURE_EXTERNAL_OES en la API de OpenGL y el tipo de muestreador samplerExternalOES en los sombreadores. Este último presenta un potencial obstáculo cuando se utiliza el shader pipeline de Qt basado en SPIR-V: la ejecución de dicho shader a través de qsb dará lugar a un fallo debido a que samplerExternalOES no se acepta como un tipo válido al no ser mapeable a SPIR-V y otros lenguajes de sombreado de destino.

Para superar esto, qsb ofrece la opción de reemplazar el contenido de cualquier variante de sombreador en un archivo .qsb con datos proporcionados por el usuario que se leen desde un archivo, reemplazando completamente el código fuente o código de bytes del sombreador original generado por qsb.

Tomemos el siguiente fragment shader. Observe el tipo de tex. ¿Qué pasa si el tipo necesita ser samplerExternalOES cuando se ejecuta con OpenGL ES?

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

Cambiar simplemente el tipo de samplerExternalOES no es factible. Eso conduce a errores de compilación de inmediato.

Sin embargo, hay una solución sencilla: escribir una versión separada del sombreador que sea compatible con OpenGL ES e inyectarla en el archivo .qsb. El siguiente shader sólo es compatible con GLSL ES y no puede ejecutarse a través de qsb. Sin embargo, sabemos que puede ser procesado por OpenGL ES en tiempo de ejecución.

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

Llamémoslo shader_gles.frag. Una vez que qsb --glsl 100es -o shader.frag.qsb shader.frag se complete, dándonos un archivo .qsb (medio listo), podemos hacer qsb -r glsl,100es,shader_gles.frag shader.frag.qsb para actualizar shader.frag.qsb sustituyendo el shader por GLSL 100 es con el contenido del archivo especificado (shader_gles.frag). Ahora shader.frag.qsb está listo para ser utilizado en tiempo de ejecución con OpenGL ES.

Nota: Presta atención a mantener la interfaz entre el shader y la aplicación sin cambios. Siempre inspeccione primero el código GLSL generado por qsb, ya sea imprimiendo el contenido del archivo .qsb mediante la opción -d, o extrayendo el shader GLSL ES 100 ejecutando qsb -x glsl,100es -o gles_shader.frag shader.frag.qsb. Los nombres struct, struct member y uniform tampoco deben diferir en la versión inyectada manualmente.

Nota: La capacidad de colocar datos de archivos arbitrarios en el paquete .qsb también puede utilizarse para inyectar sombreadores HLSL de casco y dominio creados a mano, con el fin de que las canalizaciones gráficas basadas en teselación también funcionen con Direct 3D.

© 2026 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.