mafulechka
mafulechka10 жовтня 2019 р. 05:03

Запуск Qt Quick на Vulkan, Metal та Direct3D – Частина 3

У третій частині серії статей про графік Qt розглянемо, як обробляються шейдери Qt Quick у версії Qt 5.14 при перемиканні графа сцени на рендеринг через QRhi і Qt Rendering Hardware Interface (апаратний інтерфейс рендерингу Qt). Охопимо обробку шейдерів, перш ніж заглиблюватися в сам RHI, тому що додатки Qt Quick, що використовують елементи ShaderEffect або нестандартні матеріали (custom materials), повинні самі надавати код фрагмента та/або вершинного шейдера, і тому вони повинні знати (а в Qt 6 перейти на) новий підхід до обробки шейдерів.


Говорячи про Qt 6 (хоча все описане тут відноситься тільки до Qt 5.14 і може змінитися в пізніших випусках) те, що тут є, швидше за все, послужить основою для обробки графіки і обчислення шейдерів в Qt 6, як тільки нерівних країв, що залишилися, будуть усунуті.

Чому щось нове?

Проблема 1

Перегляд дерева вихідних текстів qt (тобто git repo, що містить QtQml, QtQuick та пов'язаних з ним модулів) та пошук у каталозі шейдерів з вершинними та фрагментними шейдерами для вбудованих матеріалів сценографа Qt Quick показує, що Qt Quick вже поставляється з двома версіями кожного вершинного або фрагментного шейдера GLSL:

Чому? Це пов'язано з підтримкою контекстів OpenGL профілю ядра (для версії 3.2 та вище). Оскільки реалізації OpenGL не зобов'язані підтримувати компіляцію шейдерів GLSL 100/110/120 у такому контексті, Qt немає іншого вибору, крім як постачати його з двома варіантами: один підходить для OpenGL ES 2.0, OpenGL 2.1 і профілів сумісності, а інший (версії 150 на практиці), який використовується лише тоді, коли контекст виявляється профільним. Як описано в частині 1 серії статей, це важливо для того, щоб дозволити розробникам додатків вирішувати, який контекст OpenGL вимагати, коли їх додаток комбінує свій власний рендеринг OpenGL і інтерфейс користувача на основі Qt Quick, незалежно від того, чи є контекст сумісністю або контекстом основного профілю Qt Quick як і раніше зможе відображати.

Це нормально, коли число варіантів дорівнює 2. Що якщо тепер можуть знадобитися Vulkan-сумісні GLSL (Vulkan-compatible GLSL), HLSL та MSL на додаток? На жаль, підхід не дуже масштабний.

Проблема 2

Деякі нові графічні API більше не мають вбудованої підтримки компіляції шейдерів, на відміну від OpenGL (до побачення glCompileShader). І, навіть, якщо вони роблять принаймні як окрему бібліотеку, вони можуть не пропонувати можливості відображення під час виконання, що означає, що немає способу динамічно визначити, які входи вершин та інші ресурси шейдерів є вершинними, фрагментними або обчислювальними шейдерами, і яке розташування цих ресурсів (наприклад, які імена та усунення елементів в єдиному блоці).

Проблема 3

Внутрішня деталь: система пакетування сценографа Qt Quick трохи покладається на переписування вершинного шейдера для матеріалів, які використовуються з так званою об'єднаною партією (merged batch) (це те, що виходить, коли кілька геометричних вузлів зрештою генерують один єдиний виклик відтворення). Перезапис шейдера на льоту перед передачею його в glCompileShader підходить, коли використовується лише одна мова шейдингу, але не масштабується, коли нам потрібно реалізувати одну і ту ж логіку для декількох різних мов.

Що тоді?

Дивлячись на сторінку Khronos SPIR page, ви бачите красиву та інформативну картину SPIR-V Open Source Ecosystem (про екосистему відкритого джерела SPIR-V). Чому б не спробувати спиратися на це?

Ключові компоненти, які цікаві:

• glslang, компілятор з (OpenGL або Vulkan) GLSL у SPIR-V, проміжне уявлення.

• SPIRV-Cross, бібліотека для роздумів про SPIR-V та розбирання його на мови високого рівня, такі як GLSL, HLSL та MSL.

Отже, якщо «стандартизувати» одну мову, таку як GLSL у стилі Vulkan, скомпілювати її у SPIR-V, вийде щось підходяще для Vulkan. Якщо потім запустити двійковий файл SPIR-V через SPIRV-Cross, отримаємо необхідну інформацію про відображення та зможемо згенерувати вихідний код для різних версій GLSL, HLSL та Metal Shading Language (GLSL, як і раніше, важливий, тому що, хоча для OpenGL існують розширення, що використовують SPIR-V, на це розраховувати просто не вийде, оскільки таке розширення, ймовірно, не буде на 90% цільових платформ і пристроїв Qt).

Нарешті, зберіть все це разом (включаючи метадані відображення) в пакет, що легко (де) серіалізується, і там є потрібне рішення.

Тому конвеєр, який використовується при запуску програми Qt Quick із встановленим QSG_RHI=1 :

Vulkan-flavor GLSL

[ -> generate batching-friendly variant for vertex shaders]

-> glslang : SPIR-V bytecode

-> SPIRV-Cross : reflection metadata + GLSL/HLSL/MSL source

-> pack it all together and serialize to a .qsb file

Розширення .qsb походить від імені інструмента командного рядка, що виконує описані вище кроки - qsb , скорочення від Qt Shader Baker (не плутати з QBS).

Під час виконання файли .qsb десеріалізуються в екземплярах QShader. Це досить простий контейнер, наступний стандартним шаблонам Qt, таким як неявне сумісне використання, і містить кілька варіантів вихідного коду і байт-коду для одного шейдера, разом з QShaderDescription, який, що не дивно, містить дані відображення. Як і решта RHI, ці класи на даний момент є приватним API.

Графічний шар безпосередньо використовує екземпляри QShader. Об'єкти стану графічного конвеєра задають QShader кожної активної стадії шейдера. Потім бекенди QRhi вибирають відповідний варіант шейдера з пакету QShader.

Починаючи з версії Qt 5.14, на практиці це означає пошук:

• SPIR-V 1.0 при націленні на Вулкан,
• Вихідний HLSL або DXBC для Shader Model 5.0, якщо націлено на D3D11,
• Metal 1.2 сумісний MSL-джерело або попередньо скомпільований metalib при націлюванні на Metal,
• джерело GLSL для однієї з версій 320, 310, 300, 100, при націлюванні на контекст OpenGL ES (у цьому порядку пріоритетів, починаючи з найвищої версії, що підтримується контекстом),
• джерело GLSL для однієї з версій 460, 450, ..., 330, 150, при націлюванні на контекст профілю ядра OpenGL (у тому порядку пріоритету, починаючи з найвищої версії, що підтримується контекстом),
• Джерело GLSL для однієї з версій 120, 110 при націлюванні на неосновний контекст OpenGL (у цьому порядку пріоритетів).

Спочатку записи HLSL і MSL у наведеному вище списку можуть здатися трохи дивними. Це пов'язано з тим, що можна компілювати HLSL і MSL з вихідного коду під час виконання (за замовчуванням підхід), також були проведені деякі експерименти, що дозволяють включати попередньо скомпіловані проміжні формати в пакети .qsb . На практиці це означає виклик fxc (поки немає підтримки dxc - це також у планах, але буде дійсно актуально тільки після того, як QT Company почне дивитися на D3D12) або інструментів командного рядка Metal перед етапом "-> pack it all together" («упакувати всі разом») в конвеєрі показано вище. Проблема тут полягає в тому, що такі інструменти пов'язані з їхньою платформою (Windows і MacOS відповідно), тому qsb може викликати їх лише при роботі на цій платформі. Так, наприклад, при ручній генерації файлу .qsb у Linux це не варіант. У довгостроковій перспективі це, швидше за все, стане меншою проблемою, тому що в часовому інтервалі Qt 6 розробникам все одно знадобиться дослідити кращу інтеграцію системи складання, тому ручні інструменти, такі як qsb, будуть менш поширеними.

Звідки ця штука qsb?

Із модуля Qt Shader Tools. Це забезпечує як API, QShaderBaker, так і інструмент командного рядка qsb для виконання етапів компіляції, перекладу та пакування, описаних вище.

На даний момент модуль qt-labs не постачається з Qt 5.14.

Чому? Ну, в основному через сторонні залежності, такі як glslang і SPIRV-Cross. Є кілька речей, які потрібно дослідити і з'ясувати, коли мова заходить про можливість компілювання та запуску на всіх цільових платформах Qt Company, також деяких речей, пов'язаних з ліцензіями тощо. Якщо все це звучить знайомо, то це тому, що деякі з ці проблеми були згадані в першій частині цієї серії статей, коли йшлося про рішення для перекладу API. Отже, на даний момент створення пакета .qsb включає перевірку і складання цього модуля, а потім запуск інструменту qsb вручну.

У той час, як необхідно рішення, яке входить у комплект постачання Qt, покладатися на автономну обробку шейдерів не так уже й погано. У будь-якому випадку це одна з цілей для Qt 6. Ідея полягає в тому, щоб мати щось, що інтегрується з системою складання Qt (Qt's build system) , щоб описані вище кроки обробки шейдера виконувались під час складання програми ( чи бібліотеки). Це залишається, як майбутнє завдання, головним чином через майбутній переход qmake -> cmake. Щойно ситуація стабілізується, можна розпочати будувати рішення поверх нової системи.

То як же це робить Qt Quick в Qt 5.14?

Дивлячись на qtdeclarative/src/quick/scenegraph/shaders_ng, відповідь очевидна, запустивши qsb вручну (зверніть увагу на compile.bat) і включивши файли .qsb в бібліотеку Qt Quick через систему ресурсів Qt. Це має стати трохи складнішим пізніше.

Файли .vert та .frag містять сумісний з Vulkan код GLSL і не постачаються у збірці Qt Quick. У файлі scenegraph.qrc перелічені лише файли .qsb.

Процес добре описаний на слайді нижче:

Кожен матеріал має тільки одну пару вершинних і фрагментних шейдерів, які завжди записуються як Vulkan-сумісний GLSL, дотримуючись кількох простих угод (як, наприклад, використання тільки одного уніфікованого буфера, поміщеного в прив'язку 0).

Кожен із цих файлів потім запускається через апарат для «випікання» шейдерів, у результаті виходить пакет QShader. У цьому прикладі результатом є 6 версій того самого шейдера, а також дані відображення (які qsb може друкувати, як текст JSON, однак, самі файли .qsb є стислими двійковими файлами і не читаються людиною). Проблеми 1 та 2 , про які йшлося вище, таким чином, вирішені.

Зверніть увагу на теги [Standard] у списку шейдерів. Якби це був вершинний шейдер, а також був вказаний аргумент -b, кількість вихідних шейдерів було б 12, а не 6. 6 додаткових було б позначено як [Batchable], вказуючи, що вони були дружніми для пакетування. Дещо змінені варіанти, призначені для рендерера графа сцен Qt Quick. Це вирішує проблему 3 за рахунок дещо вищих вимог до зберігання (але через скорочений час виконання це, ймовірно, того варте).

Це охоплює основні концепції нового шейдерного конвеєра. Ми повинні подивитись ShaderEffect і QSGMaterial в окремій статті. Основна ідея (починаючи з Qt 5.14) полягає в тому, щоб передавати імена файлів .qsb замість вихідних рядків шейдерів, але, зокрема, матеріали повинні знати ще кілька речей (в основному через роботу з уніфікованими буферами замість одиничних уніформ і відсутність концепції поточного контексту для кожного потоку, де кожен може довільно змінювати стан). Але про все це іншим разом.

Рекомендуємо хостинг TIMEWEB
Рекомендуємо хостинг TIMEWEB
Стабільний хостинг, на якому розміщується соціальна мережа EVILEG. Для проектів на Django радимо VDS хостинг.

Вам це подобається? Поділіться в соціальних мережах!

Коментарі

Only authorized users can post comments.
Please, Log in or Sign up
d
  • dsfs
  • 26 квітня 2024 р. 14:56

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:80бали,
  • Рейтинг балів4
d
  • dsfs
  • 26 квітня 2024 р. 14:45

C++ - Тест 002. Константы

  • Результат:50бали,
  • Рейтинг балів-4
d
  • dsfs
  • 26 квітня 2024 р. 14:35

C++ - Тест 001. Первая программа и типы данных

  • Результат:73бали,
  • Рейтинг балів1
Останні коментарі
k
kmssr09 лютого 2024 р. 05:43
Qt Linux - Урок 001. Автозапуск програми Qt під Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
АК
Анатолий Кононенко05 лютого 2024 р. 12:50
Qt WinAPI - Урок 007. Робота з ICMP Ping в Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
EVA
EVA25 грудня 2023 р. 21:30
Boost - статичне зв&#39;язування в проекті CMake під Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
J
JonnyJo25 грудня 2023 р. 19:38
Boost - статичне зв&#39;язування в проекті CMake під Windows Сделал всё по-как у вас, но выдаёт ошибку [build] LINK : fatal error LNK1104: не удается открыть файл "libboost_locale-vc142-mt-gd-x64-1_74.lib" Хоть убей, не могу понять в чём дел…
G
Gvozdik19 грудня 2023 р. 08:01
Qt/C++ - Урок 056. Підключення бібліотеки Boost в Qt для компіляторів MinGW і MSVC Для решения твой проблемы добавь в файл .pro строчку "LIBS += -lws2_32" она решит проблему , лично мне помогло.
Тепер обговоріть на форумі
Evgenii Legotckoi
Evgenii Legotckoi03 травня 2024 р. 00:07
Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Добрый день. По моему мнению - да, но то, что будет касаться вызовов к функционалу Андроида, может создать огромные трудности.
IscanderChe
IscanderChe30 квітня 2024 р. 14:22
Во Flask рендер шаблона не передаётся в браузер Доброе утро! Имеется вот такой шаблон: <!doctype html><html> <head> <title>{{ title }}</title> <link rel="stylesheet" href="{{ url_…
G
Gar22 квітня 2024 р. 15:46
Clipboard Как скопировать окно целиком в clipb?
Павел Дорофеев
Павел Дорофеев14 квітня 2024 р. 12:35
QTableWidget с 2 заголовками Вот тут есть кастомный QTableView с многорядностью проект поддерживается, обращайтесь
f
fastrex04 квітня 2024 р. 14:47
Вернуть старое поведение QComboBox, не менять индекс при resetModel Добрый день! У нас много проектов в которых используется QComboBox, в версии 5.5.1, когда модель испускает сигнал resetModel, currentIndex не менялся. В версии 5.15 при resetModel происходит try…

Слідкуйте за нами в соціальних мережах