Адаптация 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 также добавляет поддержку предварительно скомпилированных шейдеров. Все собственные шейдеры бэкэнда (используемые встроенными материалами, на основе которых созданы типы QML Rectangle, Image, Text и т. д.) компилируются в байткод шейдеров D3D при компиляции Qt. Приложения, использующие элементы ShaderEffect, могут выбрать, чтобы отправить байткод либо в обычные файлы, либо через систему ресурсов Qt, или использовать строки исходного кода HLSL. В отличие от OpenGL, компиляция последнего выполняется с помощью нескольких потоков, что означает, что компиляция шейдеров не будет блокировать приложение и его пользовательский интерфейс.
Графические адаптеры
Плагин не обязательно требует аппаратного ускорения. Использование WARP, программного растрирующего модуля Direct3D, также является вариантом. По умолчанию выбирается первый адаптер, предоставляющий аппаратное ускорение. Чтобы переопределить это, чтобы использовать другой графический адаптер или принудительно использовать программный растрирующий модуль, установите переменную среды QT_D3D_ADAPTER_INDEX в индекс адаптера. Обнаруженные адаптеры выводятся при запуске, если включены QSG_INFO или категория логирования qt.scenegraph.general.
Устранение неполадок
При возникновении проблем всегда установите переменные среды QSG_INFO и QT_D3D_DEBUG в значение 1, чтобы получить сообщения об отладке и предупреждения, выведенные в выходной файл отладки. Последнее действие включает отладчик Direct3D. Обратите внимание, что отладчик не должен включаться в рабочей среде, так как он может значительно повлиять на производительность (загрузку ЦП) из-за увеличенной нагрузки на API.
Циклы отрисовки
По умолчанию адаптация D3D12 использует однопоточный цикл отрисовки, аналогичный циклу отрисовки windows OpenGL. Доступен также многопоточный вариант, который можно запросить, установив переменную среды QSG_RENDER_LOOP в значение threaded. Однако из-за концептуальных ограничений в DXGI, интерфейсе оконной системы, многопоточный цикл подвержен тупиковым состояниям при отображении нескольких экземпляров QQuickWindow или QQuickView. Поэтому на данный момент используется однопоточный цикл по умолчанию. Это означает, что приложения с использованием бэкэнда D3D12 должны перенести свою работу с основного (GUI) потока на потоки обработки, а не ожидать, что Qt будет поддерживать отзывчивость GUI-потока для выполнения ресурсоёмких блокирующих операций.
Дополнительную информацию о циклах отрисовки см. на странице Графического дерева сцены, а информацию о проблемах с многопоточностью в DXGI см. на странице MSDN .
Рендерер
Рендерер графического дерева в адаптации D3D12 в настоящее время не выполняет никаких операций пакетной обработки. Это менее актуально, чем в OpenGL, потому что изменения состояния не представляют проблем. Более простой логики рендеринга может привести к меньшей нагрузке на ЦП в некоторых случаях. В настоящее время изучаются компромиссы между различными подходами.
Эффекты шейдеров
Тип QML ShaderEffect полностью функционален и с адаптацией D3D12. Однако интерпретация свойств fragmentShader и vertexShader отличается от OpenGL.
В D3D12 эти строки могут быть URL-адресом локального файла или файла в системе ресурсов, или строкой исходного кода HLSL. Первый вариант указывает, что соответствующий файл содержит предварительно скомпилированный байткод шейдера D3D, сгенерированный инструментом fxc, или, альтернативно, исходный код HLSL. Тип файла определяется автоматически. Это означает, что бэкэнд D3D12 поддерживает все варианты из GraphicsInfo.shaderCompilationType и GraphicsInfo.shaderSourceType.
В отличие от OpenGL, при открытии файла используется QFileSelector с дополнительным селектором hlsl. Это позволяет легко создавать элементы ShaderEffect, которые работают с обоими бэкэндами, например, помещая исходный код GLSL в shaders/effect.frag, исходный код HLSL или - предпочтительно - предварительно скомпилированный байткод в shaders/+hlsl/effect.frag, в то время как в QML просто записывается fragmentShader: "qrc:shaders/effect.frag".
Дополнительные сведения см. в документации по ShaderEffect.
Многообразные буферы рендеринга
Адаптация Direct3D 12 игнорирует значение QSurfaceFormat, заданное для QQuickWindow или QQuickView (или заданное с помощью QSurfaceFormat::setDefaultFormat()), за исключением двух случаев: QSurfaceFormat::samples() и QSurfaceFormat::alphaBufferSize() все еще учитываются. Если значение samples больше 1, то будут созданы многообразные буферы offscreen рендеринга с указанным количеством образцов и качеством, соответствующим максимальному поддерживаемому уровню качества. Бэкэнд автоматически выполняет разрешение в буферы swapchain без многообразности после каждого кадра.
Полупрозрачные окна
При включении альфа-канала либо через QQuickWindow::setDefaultAlphaBuffer(), либо путем задания значения alphaBufferSize, отличного от нуля, в QSurfaceFormat окна или в глобальном формате, управляемом QSurfaceFormat::setDefaultFormat(), бэкэнд D3D12 создаст swapchain для композиции и выполнит операции через DirectComposition, так как swapchain в режиме отображения (который обязателен) в противном случае не поддерживает прозрачность.
Поэтому важно не излишне запрашивать альфа-канал. Когда alphaBufferSize равен 0 или по умолчанию -1, можно избежать всех этих дополнительных шагов, и традиционный swapchain, основанный на окнах, будет достаточным.
Это не актуально для WinRT, так как там бэкэнд всегда использует swapchain для композиции, связанный с ISwapChainPanel, который поддерживает QWindow на этой платформе.
Mip-карты
Генерация mip-карт поддерживается и обрабатывается прозрачно для приложений с помощью встроенного вычислительного шейдера, но является экспериментальной и на данный момент поддерживает только изображения с размером, являющимся степенью двойки. Текстуры других размеров также будут работать, но это предполагает масштабирование на основе QImage на ЦП в первую очередь. Поэтому избегайте активации mip-карт для изображений NPOT всякий раз, когда это возможно.
Форматы изображений
При создании текстур с помощью API сцены C++, таких как QQuickWindow::createTextureFromImage(), форматы 32-бита не будут сопровождаться никакой конверсией, они будут соответствовать соответствующему формату R8G8B8A8_UNORM или B8G8R8A8_UNORM. Во всех остальных случаях будет происходить конвертация формата на основе QImage на ЦП в первую очередь.
Неподдерживаемые функции
Частицы и некоторые другие зависящие от OpenGL утилиты, такие как QQuickFramebufferObject, в настоящее время не поддерживаются.
Как и в случае с адаптацией программного обеспечения, текст всегда рендерится с помощью нативного метода. Рендеринг текста на основе полей расстояния в настоящее время не реализован.
Исходные коды шейдеров в модуле Графические эффекты Qt не были перенесены в какой-либо другой формат, кроме совместимого с 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 элементов, таких как буферы кадра, и позволяет предоставлять графическое устройство и буфер команд из адаптации. Он не обязательно подходит для простой интеграции всех типов содержимого, особенно истинного 3D, поэтому, вероятно, будет дополнен альтернативой QQuickFramebufferObject в будущих выпусках.
Для принятия решений во время выполнения, основанных на используемой адаптации, используйте QSGRendererInterface с C++ и GraphicsInfo с QML. Они также могут использоваться для проверки уровня поддержки шейдеров (язык шейдеров, подход к компиляции).
END_OF_DOCUMENT_MARKERПри создании пользовательских элементов используйте новые классы QSGRectangleNode и QSGImageNode. Они заменяют устаревшие QSGSimpleRectNode и QSGSimpleTextureNode. В отличие от своих предшественников, новые классы являются интерфейсами, а реализации создаются с помощью функций-фабрик QQuickWindow::createRectangleNode() и QQuickWindow::createImageNode().
Расширенная настройка
Адаптация D3D12 может поддерживать несколько кадров в процессе обработки, подобно современным игровым движкам. Это немного отличается от традиционной модели рендеринга — обмен — ожидание vsync и позволяет лучше использовать GPU в ущерб более высокому потреблению ресурсов. Это означает, что рендерер будет на несколько кадров опережать отображаемое на экране.
Для обсуждения моделей обмена цепочками кадров и типичных параметров конфигурации обратитесь к этой статье.
Вертикальная синхронизация всегда включена, что означает, что Present() вызывается с интервалом 1.
Конфигурацию можно изменить, установив следующие переменные среды:
-
QT_D3D_BUFFER_COUNT- Количество буферов цепочки обмена в диапазоне 2—4. Значение по умолчанию — 3. -
QT_D3D_FRAME_COUNT- Количество кадров, подготовленных без блокировки, в диапазоне 1—4. Обратите внимание, что Present начнёт блокироваться после очереди из 3 кадров (независимо отQT_D3D_BUFFER_COUNT), если только ожидаемый объект не используется. Обратите внимание, что каждый дополнительный кадр увеличивает использование ресурсов GPU, так как данные геометрии и константного буфера будут дублироваться, что потребует больше работы от ЦП. Значение по умолчанию — 2. -
QT_D3D_WAITABLE_SWAP_CHAIN_MAX_LATENCY- При установке значения от 1 до 16 задержка кадра устанавливается в указанное значение. Это изменяет предел для Present() и вызовет ожидание доступного буфера цепочки обмена при начале каждого кадра. Более подробное обсуждение см. в статье выше. Пока это рассматривается как экспериментальная функция, значение по умолчанию — 0 (выключено). -
QT_D3D_BLOCKING_PRESENT- При установке ненулевого значения будет происходить ожидание со стороны ЦП завершения работы GPU после каждого вызова Present. Это фактически убивает всю параллельность, но делает поведение похожим на традиционную модель swap-blocks-for-vsync, что может быть полезно в некоторых особых случаях. Это не то же самое, что установка количества кадров в 1, так как это все равно предотвращает блокировку после Present и может блокировать только при начале подготовки следующего кадра (или вообще не блокировать в зависимости от временного интервала между кадрами). По умолчанию блокировка Present отключена.
© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/qt-5.9/qtquick-visualcanvas-adaptations-d3d12.html