Адаптация Qt Quick Direct3D 12
Адаптация Direct3D 12 для Windows 10 (как Win32 (windows плагин платформы), так и UWP (winrt плагин платформы)) поставляется в виде динамически загружаемого плагина. Она не будет работать на более ранних версиях Windows. Компиляция плагина автоматически включается, когда доступны необходимые файлы разработки D3D и DXGI. На практике это означает использование Visual Studio 2015 и новее.
Адаптация доступна как в обычных сборках Qt с поддержкой OpenGL, так и при конфигурации 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 использует однопоточный цикл отрисовки, аналогичный циклу отрисовки OpenGL windows. Также доступен многопоточный вариант, который может быть запрошен путем установки переменной среды QSG_RENDER_LOOP в threaded. Однако, из-за концептуальных ограничений в DXGI, интерфейсе оконной системы, многопоточный цикл подвержен тупиковым ситуациям, когда отображаются несколько экземпляров QQuickWindow или QQuickView. Поэтому на текущий момент по умолчанию используется однопоточный цикл. Это означает, что с бэкендом D3D12 приложения должны перемещать свою работу из основного (GUI) потока в потоки обработки, а не ожидать, что Qt будет поддерживать отзывчивость GUI-потока и его пригодность для тяжелых, блокирующих операций.
Для получения дополнительной информации о циклах отрисовки см. страницу Графический график, а информацию о проблемах с многопоточностью см. на странице MSDN для DXGI.
Рендерер
В текущей версии адаптации 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, то будут созданы многообразные буферы целевых значений отрисовки вне экрана с указанным количеством образцов и качеством, соответствующим максимальному поддерживаемому уровню качества. Бэкенд автоматически выполняет разрешение в буферы цепочки обмена без многообразности после каждого кадра.
Полупрозрачные окна
Когда канал альфа включён либо через QQuickWindow::setDefaultAlphaBuffer(), либо путем установки alphaBufferSize с ненулевым значением в QSurfaceFormat окна или в глобальном формате, управляемом QSurfaceFormat::setDefaultFormat(), бэкенд D3D12 создаст цепочку обмена для композиции и пройдет через DirectComposition, так как цепочка обмена модели переворота (которая обязательна) иначе не поддерживает прозрачность.
Поэтому важно не запрашивать ненужный канал альфа. Когда alphaBufferSize равен 0 или по умолчанию -1, все эти дополнительные шаги можно избежать, и традиционная цепочка обмена на основе окна будет достаточной.
Это не актуально для WinRT, так как там бэкенд всегда использует цепочку обмена композиции, связанную с ISwapChainPanel, который поддерживает QWindow на этой платформе.
Мип-мапы
Генерация мип-мап поддерживается и обрабатывается прозрачно для приложений через встроенный шейдер вычислений, но является экспериментальной и в данный момент поддерживает только изображения, являющиеся степенью двойки. Текстуры других размеров тоже будут работать, но это подразумевает масштабирование на основе QImage на ЦП в первую очередь. Поэтому, по возможности, избегайте активации мип-мапирования для изображений NPOT.
Форматы изображений
При создании текстур через C++ API сцены, такие как 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 и может блокироваться только при подготовке следующего кадра (или вообще не блокироваться, в зависимости от временного интервала между кадрами). По умолчанию блокировка презента отключена.
© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/archives/qt-5.11/qtquick-visualcanvas-adaptations-d3d12.html