Spec-Zone.ru › Qt

Справочник QSB

qsb — это утилита командной строки, предоставляемая модулем Qt Shader Tools. Она интегрирует сторонние библиотеки, такие как glslang и SPIRV-Cross, при необходимости вызывает внешние инструменты, такие как fxc или spirv-opt, и генерирует файлы .qsb. Кроме того, она может использоваться для проверки содержимого пакета .qsb.

Приложение выводит обзор всех доступных опций, когда вы запускаете его из командной строки без передачи каких-либо аргументов:

Usage: qsb [options] file

Options:
  -?, -h, --help               Displays help on commandline options.
  --help-all                   Displays help including Qt specific 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.
  -g                           Generate full debug info for SPIR-V and DXBC
  -O                           Invoke spirv-opt to optimize SPIR-V for
                               performance
  -o, --output <filename>      Output file for the shader pack.
  -c, --fxc                    In combination with --hlsl invokes fxc to store
                               DXBC instead of HLSL.
  -t, --metallib               In combination with --msl builds a Metal library
                               with xcrun metal(lib) and stores that instead of
                               the source.
  -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.
                               <what>=<target>,<filename> where
                               <target>=spirv,<version>|glsl,<version>|...
  -s, --silent                 Enables silent mode. Only fatal errors will be
                               printed.

Arguments:
  file                         Vulkan GLSL source file to compile

Режимы работы

Существует три основных режима работы:

  • .qsb генерация файлов.
  • .qsb проверка файлов. Например, qsb -d myshader.frag.qsb выведет метаданные отражения (в формате JSON) и включенные шейдеры.
  • Режим извлечения. Это позволяет записать заданный шейдер из существующего файла .qsb в отдельный файл. Например, qsb -x spirv.100 -o myshader.spv myshader.frag.qsb записывает двоичный код SPIR-V в myshader.spv.

Пример

Рассмотрим следующий фрагмент шейдера:

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

Выполнение qsb -o shader.frag.qsb shader.frag приводит к генерации shader.frag.qsb. Проверка этого файла с помощью qsb -d shader.frag.qsb даёт нам:

Stage: Fragment
QSB_VERSION: 5
Has 1 shaders: (unordered list)
  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

По умолчанию генерируется только SPIR-V, поэтому приложение, использующее этот пакет шейдеров, будет функционально работать только с Vulkan. Давайте сделаем его более полезным:

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

Это приводит к генерации пакета шейдеров, который делает его подходящим для OpenGL, Direct 3D и Metal также. Функционал, использованный в этом шейдере, базовый, и даже GLSL ES 100 (язык шейдинга OpenGL ES 2.0) подходит.

Проверка результата показывает:

Stage: Fragment
QSB_VERSION: 5
Has 6 shaders: (unordered list)
  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;
}

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

...

Теперь этот пакет можно использовать в Qt Quick со всеми поддерживаемыми графическими API: Vulkan, Direct 3D, Metal, OpenGL и OpenGL ES. Во время выполнения соответствующий шейдер автоматически подбирается Qt Rendering Hardware Interface, который находится под Qt Quick и Qt Quick 3D.

Помимо трансляции байткода SPIR-V обратно в исходный код более высокого уровня, система заботится об дополнительных проблемах, таких как обеспечение правильного сопоставления номеров связей SPIR-V на нативные ресурсы. Например, с HLSL мы видели такой раздел выше:

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

Внутренне это позволяет сопоставить точку привязки стиля SPIR-V 0 с регистром HLSL b0 и привязкой 1 к t0 и s0. Это помогает сделать различия в привязках ресурсов между различными языками шейдинга прозрачными для пользователей Rendering Hardware Interface и позволяет всему в Qt работать с точками привязки стиля Vulkan/SPIR-V, как они указаны в исходном коде GLSL стиля Vulkan.

Типы шейдеров

Тип шейдера определяется из расширения входного файла. Таким образом, расширение должно быть одним из следующих:

  • .vert — для вершинных шейдеров
  • .frag — для фрагментных (пиксельных) шейдеров
  • .comp — для шейдеров вычислений

Языки и версии шейдинга

Всегда генерируется SPIR-V 1.0. Что генерируется дополнительно, зависит от аргументов командной строки --glsl, --hlsl, и --msl.

Все эти параметры следуют за списком, разделенным запятыми. Список должен включать номера версий GLSL-стиля с необязательным суффиксом (es, указывающим GLSL ES). Пробел между суффиксом и версией необязателен (отсутствие пробела может помочь избежать необходимости в кавычках).

Например, встроенные материалы Qt Quick (шейдеры, поддерживающие элементы, такие как Image, Text, Rectangle) все готовят свои шейдеры с --glsl "100 es,120,150" --hlsl 50 --msl 12. Это делает их совместимыми с OpenGL ES 2.0 и более поздними версиями, OpenGL 2.1 и более поздними версиями и контекстами профиля ядра OpenGL версии 3.2 и более поздними версиями.

Если шейдер использует функции или конструкции, которые не имеют эквивалента в указанных целевых системах, qsb завершится ошибкой. Если это так, целевые системы потребуют корректировки, и это также означает, что минимальные системные требования приложения неявно корректируются. К примеру, возьмите функцию GLSL textureLod , которая доступна только с OpenGL ES 3.0 и выше (что означает GLSL ES 300 или выше). При запросе GLSL 300 es вместо 100 es, qsb успешно выполнится, но приложение, использующее этот файл .qsb , теперь будет требовать OpenGL ES 3.0 или выше и не будет совместимо с системами на базе OpenGL ES 2.0.

Другой очевидный пример — это шейдеры вычислений: шейдеры .comp потребуют указания --glsl 310es,430, так как шейдеры вычислений доступны только с OpenGL ES 3.1 или более поздними версиями и OpenGL 4.3 или более поздними версиями.

Настройка версии модели шейдера для HLSL или версии языка шейдинга Metal ожидается редко. Модель шейдера 5.0 (--hlsl 50) и MSL 1.2 (--msl 12) обычно будут достаточны.

Использование пакетной обработки графика Qt Quick Scene Graph

Рендеринг Qt Quick Scene Graph поддерживает пакетную обработку геометрии для уменьшения количества вызовов отрисовки. Подробности см. на страницах Scene Graph в разделе Графика сцены. Это основано на вставке кода в функцию main() вершинного шейдера. В Qt 5.x это происходило во время выполнения, путём изменения предоставленного кода вершинного шейдера GLSL. В Qt 6 это не вариант. Вместо этого, пакетные варианты вершинных шейдеров могут быть созданы инструментом qsb. Это запрашивается аргументом -b. Когда входной файл не является вершинным шейдером с расширением .vert, это не оказывает никакого влияния. Однако для вершинных шейдеров это приведёт к генерации двух версий для каждой целевой системы. Qt Quick затем автоматически выберет правильный вариант (стандартный или пакетный) во время выполнения.

Примечание: Приложениям не нужно беспокоиться о подробностях пакетной обработки. Им просто нужно убедиться, что -b (или эквивалентное ключевое слово BATCHABLE при использовании интеграции CMake) указано при обработке вершинных шейдеров. Это актуально только для шейдеров Qt Quick, используемых с ShaderEffect или QSGMaterialShader.

Рассмотрим следующий пример вершинного шейдера:

#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;
out gl_PerVertex { vec4 gl_Position; };

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

Запуск qsb -b --glsl 330 -o example.vert.qsb example.vert приводит к:

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

Reflection info: {
  ...

Обратите внимание, как все языки и версии целевых систем теперь существуют в двух вариантах: Стандартном и немного изменённом Пакетном.

Вызов внешних инструментов

qsb может вызывать определённые внешние инструменты. Они делятся на две категории: инструменты для оптимизации байткода шейдера (SPIR-V) и платформенно-специфичные инструменты для выполнения первой фазы компиляции шейдера из исходного кода в некоторый промежуточный формат байткода.

Они активируются следующими параметрами командной строки:

  • -O — вызывает spirv-opt как пост-обработку двоичного файла SPIR-V. Файл .qsb будет содержать оптимизированную версию. Это предполагает, что spirv-opt доступен в системе (например, из Vulkan SDK) и готов к вызову.
  • -c или --fxc — вызывает fxc.exe, компилятор шейдеров Direct 3D. Результирующие данные DXBC (DirectX Byte Code) сохраняются в файле .qsb вместо HLSL. Qt автоматически подберёт его во время выполнения, поэтому создателю файла .qsb решать, что включать, исходный код HLSL или промежуточный формат. Всякий раз, когда это возможно, отдавайте предпочтение последнему, так как это устраняет необходимость парсить и использовать исходный код HLSL во время выполнения, что потенциально приводит к существенному увеличению производительности при создании графической конвейерной обработки. Недостатком является то, что этот аргумент может быть использован только когда qsb выполняется в Windows.
  • -t или --metallib — вызывает соответствующие инструменты XCode Metal для генерации файла .metallib и включает его в пакет .qsb вместо исходного кода MSL. Этот вариант доступен только при выполнении qsb на macOS.

Другие параметры

  • -D — определяет макрос. Это позволяет использовать #ifdef и аналогичные конструкции в исходном коде GLSL.
  • -g — включает генерацию полной отладочной информации для SPIR-V, что позволяет таким инструментам, как RenderDoc, отображать весь исходный код при проверке конвейера или при отладке вершинного или фрагментного шейдера. Также оказывает влияние на Direct 3D, когда указан -c, так как fxc тогда получает инструкции включать отладочную информацию в сгенерированный промежуточный байткод.

Работа с функциями GLSL, специфичными для OpenGL

Иногда может потребоваться использовать конструкции языка шейдинга, специфичные для OpenGL и GLSL, и неприменимые к другим языкам шейдинга, промежуточным форматам и графическим API.

Яркими примерами этого являются внешние текстуры и сэмплеры OpenGL ES. Реализация воспроизведения видео или отображения видоискателя может включать, в зависимости от платформы, работу с объектами текстур OpenGL, которые не предназначены для использования в качестве обычных 2D текстур, но могут использоваться, с ограниченным функционалом, через точку привязки GL_TEXTURE_EXTERNAL_OES в API OpenGL и тип сэмплера samplerExternalOES в шейдерах. Последний представляет потенциальную проблему при использовании конвейера шейдеров SPIR-V Qt: выполнение такого шейдера через qsb приведёт к ошибке из-за того, что samplerExternalOES не принимается как допустимый тип из-за того, что он не может быть сопоставлен с SPIR-V и другими целевыми языками шейдинга.

Чтобы преодолеть это, qsb предлагает возможность заменить содержимое любого заданного варианта шейдера в файле .qsb пользовательскими данными, считанными из файла, полностью заменяя исходный код шейдера или байткод, сгенерированные qsb.

Рассмотрим следующий фрагмент шейдера. Обратите внимание на тип tex. А что, если тип должен быть samplerExternalOES при запуске с 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;
}

Просто изменение типа сэмплера samplerExternalOES не выполнимо. Это сразу приведёт к ошибкам компиляции.

Однако есть простое решение: написать отдельный, полностью ориентированный на OpenGL ES вариант шейдера и вставить его в файл .qsb. Следующий шейдер совместим только с GLSL ES и не может быть запущен через qsb. Однако мы знаем, что его можно обработать в OpenGL ES во время выполнения.

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

Назовём это shader_gles.frag. После завершения qsb --glsl 100es -o shader.frag.qsb shader.frag, что даёт нам (полуготовый) файл .qsb, мы можем выполнить qsb -r glsl,100es,shader_gles.frag shader.frag.qsb для обновления shader.frag.qsb, заменив шейдер GLSL 100 es содержимым указанного файла (shader_gles.frag). Теперь shader.frag.qsb готов к использованию во время выполнения с OpenGL ES.

Примечание: Обратите внимание на сохранение неизменного интерфейса между шейдером и приложением. Всегда предварительно проверьте сгенерированный qsb GLSL-код, распечатав содержимое файла .qsb с помощью опции -d или извлекая шейдер GLSL ES 100, выполнив qsb -x glsl,100es -o gles_shader.frag shader.frag.qsb. Структуры, члены структур и имена униформ не должны отличаться и в ручном варианте вставки.

© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/qt-6.2/qtshadertools-qsb.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API