mafulechkaOct. 10, 2019, 5:03 a.m.

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

Content

В третьей части серии статей о графике 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 при нацеливании на Vulkan,
• Источник 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 вместо исходных строк шейдеров, но, в частности, материалы должны знать еще несколько вещей (в основном из-за работы с унифицированными буферами вместо единичных униформ и из-за отсутствие концепции текущего контекста для каждого потока, где каждый может произвольно изменять состояния). Но обо всем этом в другой раз.

We recommend hosting TIMEWEB
We recommend hosting TIMEWEB
Stable hosting, on which the social network EVILEG is located. For projects on Django we recommend VDS hosting.
Support the author Donate

Comments

Only authorized users can post comments.
Please, Log in or Sign up
Timeweb

Let me recommend you the excellent hosting on which EVILEG is located.

For many years, Timeweb has been proving his stability.

For projects on Django I recommend VDS hosting

View Hosting
GI

C ++ - Test 004. Pointers, Arrays and Loops

  • Result:60points,
  • Rating points-1
t

C ++ - Test 004. Pointers, Arrays and Loops

  • Result:70points,
  • Rating points1
LD

C++ - Тест 003. Условия и циклы

  • Result:57points,
  • Rating points-2
Last comments
VR

QML - Lesson 016. SQLite database and the working with it in QML Qt

Помогите, пожалуйста. У меня похожая задача, но я в qml слой долен передать не чистый запрос, а со сложной обработкой, поэтому у меня в С++ слое есть иерархия классов, которая имитирует бд и зап…
e
  • eviza
  • Nov. 16, 2020, 4:32 a.m.

Qt/C++ - Tutorial 083. Creating a dynamic library and connecting it to another project

здравствуйте! при компиляции библиотеки выскакивает окно особая программа( не удалось найти программу, укажите путь к ней), и в папке debug создается файл .dll, а .lib нет. подскажите…
IB

Data encryption by RSA algorithm in Qt with public and private keys without binding to OpenSSL

Библиотека подключилась нормально, только на выводе из первого примера выходит пустое сообщение, вместо "test message" просто "". Никаких ошибок не выдает.
VS

Qt WinAPI - Lesson 002. How to make win installer for Qt apllication?

Можно ли как-то однозначно (не проверяя) выяснить, запустится ли программа в windows 7? И как быть с разрядностью уже и просто в w10 (32\64)?
DT

Django - Tutorial 036. How to add authentication through social networks. VKontakte

Возможно, автор прочитает. Делал авторизацию с помощью ВК по книге Дронова. Выдает ошибку "Backend not found". Стал гуглить, нашел вашу статью, вроде почти то же самое (оно и понятно, документа…
Now discuss on the forum
m

Отправка JSON

Спасибо!

Разный масштаб в формах и при запуске

Сврестайте все в один лэйаут (Выбирите окно и нажмити сверху на голубой квадратик из 9 голубфх квадратиков)

Обращение к ячейке таблицы

Вам нужно наследоваться от QAbstractTableModel, выбрать в каких контейнерах и как будите хранить данные и уже у них по индексу будите получать данные. Вот под рукой пример был на питоне, на…
DK

QTableView не становится в редактирование

балин, вот я, конечно, "молодец". минус 5 часов, из-за того, что не поставил в модели флаги. Qt::ItemFlags UserModel::flags(const QModelIndex &index) const{ Qt::ItemFlags flags = Tre…

QSqlTableModel - Как добавить картинки в таблицу, чтобы они отражались в диалоговом окне, но не были частью модели

Ну тогда в этом столбце указывайте пути на несколько картинок
About
Services
© EVILEG 2015-2020
Recommend hosting TIMEWEB