Qt Quick Direct3D 12 Адаптация
Адаптация Direct3D 12 для Windows 10, как в Win32 (windows плагин платформы), так и в UWP (winrt плагин платформы), поставляется в виде динамически загружаемого плагина. Эта адаптация не работает на более ранних версиях Windows. Сборка этого плагина автоматически включается, когда присутствуют необходимые файлы разработки D3D и DXGI. На практике это означает Visual Studio 2015 и новее.
Адаптация доступна как в обычных, поддерживающих OpenGL сборках Qt, так и при конфигурации Qt с -no-opengl. Однако она никогда не является стандартной, и пользователь или приложение должны явно запросить её, установив переменную среды QT_QUICK_BACKEND в значение d3d12 или вызвав QQuickWindow::setSceneGraphBackend().
Мотивация
Эта экспериментальная адаптация является первым бэкендом Qt Quick, который фокусируется на современной, низкоуровневой графической API в сочетании с интерфейсом системы окон, отличным от традиционных подходов, используемых в сочетании с OpenGL.
Эта адаптация также позволяет улучшить интеграцию с Windows, так как Direct3D является основной поддерживаемой поставщиком решением. Следовательно, ожидается меньше проблем с драйверами, операциями, такими как изменение размеров окон, и специальными событиями, такими как потеря графического устройства, вызванная сбросом устройства или обновлениями графического драйвера.
Что касается производительности, то в целом ожидается несколько меньшее использование ЦП по сравнению с OpenGL из-за меньшей нагрузки на драйвер и более высокое использование видеокарты с меньшими затратами времени на простаивание. Бэкенд пока не активно использует потоки, что означает наличие возможностей для дальнейших улучшений в будущем, например, для дальнейшей оптимизации загрузки изображений.
Бэкенд D3D12 также вводит поддержку предварительно скомпилированных шейдеров. Все собственные шейдеры бэкенда (используемые встроенными материалами, на основе которых созданы типы Rectangle, Image, Text и другие типы QML) компилируются в байткод шейдеров D3D при компиляции Qt. Приложения, использующие элементы ShaderEffect, могут выбрать доставку байткода либо в обычных файлах, через систему ресурсов Qt, либо использовать исходные строки языка высокого уровня для шейдинга DirectX (HLSL). В отличие от OpenGL, компиляция HLSL выполняется в потоках, что означает, что компиляция шейдеров не будет блокировать приложение и его пользовательский интерфейс.
Графические адаптеры
Плагин не обязательно требует аппаратного ускорения. Вы также можете использовать WARP, программный растризатор Direct3D. По умолчанию выбирается первый адаптер, обеспечивающий аппаратное ускорение. Для переопределения этого и использования другого графического адаптера или для принудительного использования программного растризатора установите переменную среды QT_D3D_ADAPTER_INDEX в индекс адаптера. Обнаруженные адаптеры выводятся при запуске, когда включена категория ведения журнала QSG_INFO или qt.scenegraph.general.
Устранение неполадок
В случае возникновения проблем, всегда установите переменные среды QSG_INFO и QT_D3D_DEBUG в значение 1, чтобы получить отладочные и предупреждающие сообщения, выводимые в отладочный вывод. QT_D3D_DEBUG включает отладочный уровень Direct3D.
Примечание: Отладочный уровень не следует включать в производственной среде, так как он может существенно повлиять на производительность (загрузку ЦП) из-за увеличенной нагрузки на API.
Циклы рендеринга
По умолчанию адаптация D3D12 использует однопоточный цикл рендеринга, аналогичный циклу рендеринга windows OpenGL. Доступен также многопоточный вариант, который можно запросить, установив переменную среды QSG_RENDER_LOOP в значение threaded. Однако из-за концептуальных ограничений в DXGI, интерфейсе системы окон, многопоточный цикл подвержен тупиковым ситуациям при отображении нескольких экземпляров QQuickWindow или QQuickView. Следовательно, на данный момент по умолчанию используется однопоточный цикл. Это означает, что с бэкендом D3D12 ожидается, что приложения перенесут свою работу с главного (GUI) потока на рабочие потоки, а не ожидать от Qt поддержания отзывчивости GUI-потока и его пригодности для интенсивных, блокирующих операций.
Дополнительную информацию см. в разделе Графический сценарий Qt Quick для получения подробностей о циклах рендеринга и Многопоточность и DXGI по вопросам проблем с многопоточностью.
Рендерер
В настоящее время модуль рендеринга графического сценария в адаптации D3D12 не выполняет никаких группировок. Это менее критично, чем в OpenGL, так как изменения состояния не представляют проблем. Более простой алгоритм рендеринга также может привести к меньшей нагрузке на ЦП в некоторых случаях. В настоящее время ведутся исследования компромиссов между различными подходами.
Эффекты шейдеров
Тип QML ShaderEffect также полностью функционален с адаптацией D3D12. Однако интерпретация свойств fragmentShader и vertexShader отличается от OpenGL.
В D3D12 эти строки могут представлять собой URL-адрес локального файла, файл в системе ресурсов или исходный код HLSL. Использование URL-адреса локального файла или файла в системе ресурсов указывает на то, что файл содержит предварительно скомпилированный байткод шейдера D3D, сгенерированный инструментом fxc, или, альтернативно, исходный код HLSL. Тип файла определяется автоматически. Это означает, что бэкенд D3D12 поддерживает все параметры из GraphicsInfo.shaderCompilationType и GraphicsInfo.shaderSourceType.
В отличие от OpenGL, при открытии файла используется QFileSelector с дополнительным hlsl селектором. Это обеспечивает простое создание элементов ShaderEffect, которые работают в обоих бэкендах, например, путем размещения исходного кода GLSL в shaders/effect.frag, исходного кода HLSL или, предпочтительнее, предварительно скомпилированного байткода в shaders/+hlsl/effect.frag, в то время как просто записывается fragmentShader: "qrc:shaders/effect.frag" в QML. Более подробную информацию см. в разделе ShaderEffect.
Многообразные буферы рендеринга
Адаптация Direct3D 12 игнорирует значение QSurfaceFormat, установленное на QQuickWindow или QQuickView, или установленное с помощью QSurfaceFormat::setDefaultFormat(), за исключением двух случаев: QSurfaceFormat::samples() и QSurfaceFormat::alphaBufferSize() все еще учитываются. Если значение samples больше 1, будут созданы многообразные буферы рендеринга offscreen с указанным числом выборок на максимальном поддерживаемом уровне качества. Бэкенд автоматически выполняет разрешение в буферы не-многообразной цепочки обмена после каждого кадра.
Полупрозрачные окна
Если альфа-канал включен с помощью QQuickWindow::setDefaultAlphaBuffer() или установкой alphaBufferSize в ненулевое значение в QSurfaceFormat окна или в глобальном формате, управляемом QSurfaceFormat::setDefaultFormat(), бэкенд D3D12 создаст цепочку обмена для композиции и пройдет через DirectComposition. Это необходимо, так как обязательная цепочка обмена flip-модель не поддерживает прозрачность в противном случае.
Поэтому важно не запрашивать альфа-канал излишне. Когда alphaBufferSize равен 0 или по умолчанию -1, все эти дополнительные шаги можно избежать, и традиционная цепочка обмена на основе окна будет достаточной.
В WinRT это неактуально, так как бэкенд там всегда использует цепочку обмена композиции, связанную с ISwapChainPanel, которая поддерживает QWindow на этой платформе.
Mipмапы
Генерация mipмапов поддерживается и обрабатывается прозрачно для приложений с помощью встроенного шейдера вычислений. Однако в настоящее время эта функция экспериментальная и поддерживает только изображения, являющиеся степенью двойки. Текстуры других размеров также будут работать, но это предполагает предварительное масштабирование на основе QImage на ЦП. Поэтому следует по возможности избегать включения mipмапов для изображений с нестепенями двойки (NPOT).
Форматы изображений
При создании текстур с помощью API графического сценария C++, таких как QQuickWindow::createTextureFromImage(), 32-битные форматы не будут подвергаться преобразованию, они будут отображаться непосредственно в соответствующий R8G8B8A8_UNORM или B8G8R8A8_UNORM формат. Все остальное приведет к преобразованию формата на основе QImage на ЦП.
Неподдерживаемые функции
Частицы и некоторые другие зависящие от OpenGL утилиты, такие как QQuickFramebufferObject, в настоящее время не поддерживаются.
Как и в случае с адаптацией программного обеспечения, текст всегда отображается с помощью родного метода. Отображение текста на основе полей расстояния в настоящее время не реализовано.
Исходные коды шейдеров в модуле Qt Graphical Effects не были перенесены в какой-либо другой формат, кроме совместимого с OpenGL 2.0, что означает, что типы QML, предоставляемые этим модулем, в настоящее время не работают с бэкендом D3D12.
Атласы текстур в настоящее время не используются.
Рендерер может не поддерживать некоторые второстепенные функции, такие как рисование точек и линий с шириной, отличной от 1.
Пользовательские элементы Qt Quick, использующие пользовательские узлы графического сценария, могут вызывать проблемы, так как материалы неразрывно связаны с графической API. Поэтому работоспособными в рамках всех адаптаций являются только элементы, использующие утилитарные узлы прямоугольника и изображения.
QQuickWidget и лежащая в его основе архитектура композиции на основе OpenGL не поддерживаются. Если вам нужно смешивать пользовательские интерфейсы на основе QWidget, используйте QWidget::createWindowContainer() для встраивания родного окна QQuickWindow или QQuickView.
Наконец, рендеринг с помощью QSGEngine и QSGAbstractRenderer в настоящее время невозможен с адаптацией D3D12.
Связанные API
Для интеграции пользовательского рендеринга Direct3D 12 используйте QSGRenderNode в сочетании с QSGRendererInterface. Этот подход не зависит от контекстов OpenGL или API-специфики, таких как framebuffers, и позволяет получить доступ к графическому устройству и буферу команд из адаптации. Он не обязательно подходит для лёгкой интеграции всех типов контента, особенно настоящего 3D, поэтому в будущих выпусках, вероятно, он будет дополнен альтернативой QQuickFramebufferObject.
Для выполнения решений во время выполнения, основанных на адаптации, используйте QSGRendererInterface из C++ и GraphicsInfo из QML. Их также можно использовать для проверки уровня поддержки шейдеров: язык шейдинга, подход к компиляции и так далее.
END_OF_DOCUMENT_MARKERПри создании пользовательских элементов используйте новые классы QSGRectangleNode и QSGImageNode. Они заменяют устаревшие QSGSimpleRectNode и QSGSimpleTextureNode. В отличие от предшественников, эти новые классы являются интерфейсами, а реализации создаются с помощью функций-фабрик QQuickWindow::createRectangleNode() и QQuickWindow::createImageNode().
Дополнительная настройка
Адаптация D3D12 может поддерживать несколько кадров в процессе обработки, подобно современным игровым движкам. Это несколько отличается от традиционной модели «рендеринг – обмен – ожидание vsync» и позволяет улучшить использование графического процессора за счёт повышенного использования ресурсов. Это означает, что рендерер будет на несколько кадров опережать отображаемое на экране.
Для обсуждения моделей обмена цепочками кадров и типичных параметров конфигурации см. Образец приложения для цепочек кадров обмена Direct3D 12 в режиме Flip.
Вертикальная синхронизация всегда включена, что означает, что Present() вызывается с интервалом 1.
Конфигурацию можно изменить, задав следующие переменные среды:
| Переменная среды | Описание |
|---|---|
QT_D3D_BUFFER_COUNT |
Количество буферов цепочки обмена в диапазоне 2 – 4. Значение по умолчанию – 3. |
QT_D3D_FRAME_COUNT |
Количество кадров, подготовленных без блокировки, в диапазоне 1 – 4. Значение по умолчанию – 2. Present() начинает блокировку после очереди 3 кадров (независимо от QT_D3D_BUFFER_COUNT), если доступный объект ожидания не используется. Каждый дополнительный кадр увеличивает использование ресурсов графического процессора, так как геометрия и данные константного буфера должны дублироваться, а также требует больше работы от процессора. |
QT_D3D_WAITABLE_SWAP_CHAIN_MAX_LATENCY |
Задержка кадра в диапазоне 1 – 16. Значение по умолчанию – 0 (выключено). Изменяет ограничение для Present() и вызывает ожидание доступного буфера цепочки обмена при начале каждого кадра. Подробное обсуждение см. в статье, приведённой выше. Примечание: В настоящее время это поведение является экспериментальным. |
QT_D3D_BLOCKING_PRESENT |
Время, в течение которого процессор должен ожидать, ненулевое значение, окончания работы графическим процессором после каждого вызова Present(). Значение по умолчанию – 0 (выключено). Это поведение фактически убивает всю параллельность, но делает поведение похожим на традиционную модель обмена, блокирующуюся для vsync, что может быть полезно в некоторых особых случаях. Однако это поведение не эквивалентно установке количества кадров в 1, поскольку это всё ещё предотвращает блокировку после Present(), и может блокировать только при начале подготовки следующего кадра (или вообще не блокировать в зависимости от временного промежутка между кадрами). |
© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/qt-5.12/qtquick-visualcanvas-adaptations-d3d12.html