Spec-Zone.ru › Qt 5.12

Графическая сцена Qt Quick

Графическая сцена в Qt Quick

Qt Quick 2 использует специальную графическую сцену и ряд адаптаций, по умолчанию использующих OpenGL ES 2.0 или OpenGL 2.0 для рендеринга. Использование графической сцены вместо традиционных императивных систем рисования (QPainter и аналогичных) означает, что сцену, подлежащую рендерингу, можно сохранять между кадрами, и весь набор примитивов для рендеринга известен до начала рендеринга. Это открывает возможности для ряда оптимизаций, таких как пакетный рендеринг для минимизации изменений состояния и отбрасывание скрытых примитивов.

Например, предположим, что пользовательский интерфейс содержит список из десяти элементов, каждый из которых имеет цвет фона, значок и текст. При использовании традиционных методов рисования это приведет к 30 вызовам рисования и аналогичному количеству изменений состояния. Графическая сцена, с другой стороны, может переупорядочить примитивы для рендеринга таким образом, что все фоны будут нарисованы в одном вызове, затем все значки, а затем весь текст, уменьшив общее количество вызовов рисования всего до 3. Такая пакетная обработка и сокращение изменений состояния могут значительно повысить производительность на некоторых устройствах.

Графическая сцена тесно связана с Qt Quick 2.0 и не может использоваться автономно. Графическая сцена управляется и рендерится классом QQuickWindow, а пользовательские типы элементов могут добавлять свои графические примитивы в графическую сцену с помощью вызова QQuickItem::updatePaintNode().

Графическая сцена представляет собой графическое представление сцены элементов, независимой структуры, содержащей достаточную информацию для рендеринга всех элементов. После ее настройки ею можно управлять и рендерить независимо от состояния элементов. На многих платформах графическая сцена будет даже рендериться в отдельной потоке рендеринга, в то время как поток GUI готовит состояние следующего кадра.

Примечание: Большая часть информации на этой странице относится к адаптации графической сцены Qt Quick, использующей по умолчанию OpenGL. Для получения дополнительной информации об адаптациях различных графических сцен см. Адаптации графической сцены.

Структура графической сцены Qt Quick

Графическая сцена состоит из ряда предопределенных типов узлов, каждый из которых служит определенной цели. Хотя мы называем это графической сценой, более точное определение — дерево узлов. Дерево строится из типов QQuickItem в QML-сцене, а затем внутри сцена обрабатывается рендерером, который рисует сцену. Сами узлы не содержат активный код рисования или виртуальную paint() функцию.

Несмотря на то, что дерево узлов в основном строится внутри существующими типами Qt Quick QML, пользователи также могут добавлять полные поддеревья со своим содержимым, включая поддеревья, представляющие 3D-модели.

Узлы

Наиболее важным узлом для пользователей является QSGGeometryNode. Он используется для определения пользовательской графики путем определения ее геометрии и материала. Геометрия определяется с помощью QSGGeometry и описывает форму или сетку графического примитива. Это может быть линия, прямоугольник, многоугольник, несколько несвязанных прямоугольников или сложная 3D-сетка. Материал определяет, как заполняются пиксели в этой форме.

Узел может иметь любое количество дочерних элементов, и узлы геометрии будут рендериться так, что они отображаются в порядке дочерних элементов, а родители будут за своими дочерними элементами.

Примечание: Это ничего не говорит о фактическом порядке рендеринга в рендерере. Гарантируется только визуальный вывод.

Доступные узлы:

QSGClipNode

Реализует функцию обрезки в графической сцене

QSGGeometryNode

Используется для всего рендерного содержимого в графической сцене

QSGNode

Базовый класс для всех узлов в графической сцене

QSGOpacityNode

Используется для изменения непрозрачности узлов

QSGTransformNode

Реализует преобразования в графической сцене

Пользовательские узлы добавляются в графическую сцену путем наследования от QQuickItem::updatePaintNode() и установки флага QQuickItem::ItemHasContents.

Предупреждение: Крайне важно, чтобы операции OpenGL и взаимодействие с графической сценой происходили исключительно в потоке рендеринга, в первую очередь во время вызова updatePaintNode(). Правило состоит в том, чтобы использовать только классы с префиксом «QSG» внутри функции QQuickItem::updatePaintNode().

Для получения более подробной информации см. Графическая сцена — настройка геометрии.

Предварительная обработка

Узлы имеют виртуальную функцию QSGNode::preprocess(), которая вызывается перед рендерингом графической сцены. Подклассы узлов могут установить флаг QSGNode::UsePreprocess и переопределить функцию QSGNode::preprocess(), чтобы выполнить окончательную подготовку своего узла. Например, деление кривой Безье на правильный уровень детализации для текущего коэффициента масштаба или обновление части текстуры.

Владение узлами

Владение узлами выполняется либо явно создателем, либо графической сценой путем установки флага QSGNode::OwnedByParent. Назначение владения графической сцене часто предпочтительнее, так как это упрощает очистку, когда графическая сцена существует вне потока GUI.

Материалы

Материал описывает, как заполняется внутренняя часть геометрии в QSGGeometryNode. Он инкапсулирует программу OpenGL-шейдера и предоставляет достаточную гибкость в том, что можно достичь, хотя большинство элементов Qt Quick сами используют только очень простые материалы, такие как заливка сплошным цветом и текстурой.

Пользователям, которые просто хотят применить пользовательское затемнение к типу элемента QML, можно сделать это непосредственно в QML с помощью типа ShaderEffect.

Ниже приведен полный список классов материалов:

QSGFlatColorMaterial

Удобный способ рендеринга геометрии сплошного цвета в графической сцене

QSGMaterial

Инкапсулирует состояние рендеринга для программы шейдера

QSGMaterialShader

Представляет OpenGL-программу шейдера в рендерере

QSGMaterialType

Используется в качестве уникального маркера типа в сочетании с QSGMaterial

QSGOpaqueTextureMaterial

Удобный способ рендеринга текстурированной геометрии в графической сцене

QSGSimpleMaterial

Класс, сгенерированный шаблоном, используемый для хранения состояния, используемого с QSGSimpleMateralShader

QSGSimpleMaterialShader

Удобный способ создания пользовательских материалов на основе OpenGL для графической сцены

QSGTextureMaterial

Удобный способ рендеринга текстурированной геометрии в графической сцене

QSGVertexColorMaterial

Удобный способ рендеринга геометрии с цветом вершин в графической сцене

Для получения более подробной информации см. Графическая сцена — простой материал

Узлы-удобства

API графической сцены очень низкого уровня и фокусируется на производительности, а не на удобстве. Написание пользовательских геометрий и материалов с нуля, даже самых основных, требует значительного количества кода. По этой причине API включает несколько удобных классов для быстрого доступа к наиболее распространенным пользовательским узлам.

  • QSGSimpleRectNode — подкласс QSGGeometryNode, который определяет прямоугольную геометрию со сплошным цветом.
  • QSGSimpleTextureNode — подкласс QSGGeometryNode, который определяет прямоугольную геометрию с текстурным материалом.

Графическая сцена и рендеринг

Рендеринг графической сцены происходит внутри класса QQuickWindow, и нет публичного API для доступа к нему. Однако есть несколько мест в конвейере рендеринга, где пользователь может подключить код приложения. Это можно использовать для добавления пользовательского содержимого графической сцены или рендеринга необработанного содержимого OpenGL. Точки интеграции определяются циклом рендеринга.

Подробное описание того, как работает рендерер графической сцены для OpenGL, см. в Рендерере OpenGL графической сцены Qt Quick.

Доступны три варианта цикла рендеринга: basic, windows, и threaded. Из них basic и windows являются однопоточными, а threaded выполняет рендеринг графической сцены в отдельном потоке. Qt пытается выбрать подходящий цикл в зависимости от платформы и, возможно, графических драйверов. Когда это неудовлетворительно, или для тестирования, можно использовать переменную среды QSG_RENDER_LOOP для принудительного использования заданного цикла. Чтобы проверить, какой цикл рендеринга используется, включите qt.scenegraph.general категорию логгирования.

Примечание: Циклы рендеринга threaded и windows полагаются на реализацию OpenGL для регулирования скорости, запрашивая интервал переключения кадров 1. Некоторые графические драйверы позволяют пользователям переопределять этот параметр и отключать его, игнорируя запрос Qt. Без блокировки в операции обмена буферами (или в другом месте) цикл рендеринга будет выполнять анимацию слишком быстро и перегружать процессор на 100%. Если известно, что система не может обеспечить регулирование скорости с помощью vsync, используйте цикл рендеринга basic вместо него, установив QSG_RENDER_LOOP=basic в среде.

Многопоточный цикл рендеринга ("threaded")

Во многих конфигурациях отрисовка дерева сцен происходит в отдельном потоке отрисовки. Это делается для повышения параллельности многоядерных процессоров и лучшего использования времени простоя, такого как ожидание вызова буфера обмена. Это обеспечивает значительные улучшения производительности, но накладывает определенные ограничения на то, где и когда можно взаимодействовать с деревом сцен.

Ниже приведён простой обзор того, как кадр формируется с помощью потоковой петли отрисовки.

  1. В QML-сцене происходит изменение, вызывая QQuickItem::update(). Это может быть результатом, например, анимации или пользовательского ввода. В поток отрисовки публикуется событие для начала нового кадра.
  2. Поток отрисовки готовится к отрисовке нового кадра, делает контекст OpenGL текущим и инициирует блокировку потока GUI.
  3. Пока поток отрисовки готовит новый кадр, поток GUI вызывает QQuickItem::updatePolish() для окончательной правки элементов перед их отрисовкой.
  4. Поток GUI заблокирован.
  5. Сигнал QQuickWindow::beforeSynchronizing() генерируется. Приложения могут создавать прямые подключения (используя Qt::DirectConnection) к этому сигналу для выполнения необходимой подготовки перед вызовами QQuickItem::updatePaintNode().
  6. Синхронизация состояния QML в дереве сцены. Это выполняется путём вызова функции QQuickItem::updatePaintNode() для всех элементов, которые изменились с предыдущего кадра. Это единственное время, когда QML-элементы и узлы в дереве сцен взаимодействуют.
  7. Блокировка потока GUI снимается.
  8. Дерево сцены отрисовывается:
    1. Сигнал QQuickWindow::beforeRendering() генерируется. Приложения могут создавать прямые подключения (используя Qt::DirectConnection) к этому сигналу для использования пользовательских вызовов OpenGL, которые затем будут накладываться визуально под QML-сцену.
    2. Элементы, для которых указан QSGNode::UsePreprocess, будут иметь вызванную функцию QSGNode::preprocess().
    3. Отрисовщик обрабатывает узлы и вызывает функции OpenGL.
    4. Сигнал QQuickWindow::afterRendering() генерируется. Приложения могут создавать прямые подключения (используя Qt::DirectConnection) к этому сигналу для использования пользовательских вызовов OpenGL, которые затем будут накладываться визуально поверх QML-сцены.
    5. Отображаемый кадр меняется, и генерируется QQuickWindow::frameSwapped().
  9. Пока поток отрисовки отрисовывает, поток GUI свободен для продвижения анимаций, обработки событий и т. д.

Потоковый рендерер используется по умолчанию в Windows с opengl32.dll, Linux с драйверами, не основанными на Mesa, мобильных платформах и встроенных Linux с EGLFS, но это может измениться. Можно принудительно использовать потоковый рендерер, установив QSG_RENDER_LOOP=threaded в среде.

Непотоковые петли отрисовки ("basic" и "windows")

Непотоковая петля отрисовки используется по умолчанию в Windows с ANGLE или с реализацией opengl32, отличной от стандартной, macOS и Linux с драйверами Mesa. В последнем случае это в основном предосторожность, так как не все комбинации драйверов OpenGL и систем окон были протестированы. В то же время такие реализации, как ANGLE или Mesa llvmpipe, вообще не могут работать с потоковой отрисовкой, поэтому для них обязательно не использовать потоковую отрисовку.

В macOS потоковая петля отрисовки не поддерживается при сборке с XCode 10 (SDK 10.14) или более поздней версии, так как это подключает поддержку слоёв в macOS 10.14. Вы можете собрать с Xcode 9 (SDK 10.13), чтобы отключить поддержку слоёв, в этом случае потоковая петля отрисовки доступна и используется по умолчанию.

По умолчанию windows используется для непотоковой отрисовки в Windows с ANGLE, а basic используется для всех других платформ, когда нужна непотоковая отрисовка.

Даже при использовании непотоковой петли отрисовки вы должны писать свой код так, как будто вы используете потоковый рендерер, так как несоблюдение этого сделает код непереносимым.

Ниже приведена упрощённая иллюстрация последовательности отрисовки кадров в непотоковом рендерере.

Пользовательский контроль над отрисовкой с помощью QQuickRenderControl

При использовании QQuickRenderControl ответственность за управление петлёй отрисовки передаётся приложению. В этом случае встроенная петля отрисовки не используется. Вместо этого приложение должно вызывать шаги полирования, синхронизации и отрисовки в соответствующее время. Возможно реализовать как потоковое, так и непотоковое поведение, аналогичное описанному выше.

Смешивание дерева сцен и OpenGL

Дерево сцены предлагает два метода интеграции контента OpenGL: вызовом команд OpenGL напрямую и созданием текстурированного узла в дереве сцены.

Подключившись к сигналам QQuickWindow::beforeRendering() и QQuickWindow::afterRendering(), приложения могут напрямую вызывать команды OpenGL в том же контексте, в котором происходит отрисовка дерева сцен. Как показывают имена сигналов, пользователь может отрисовать контент OpenGL как под, так и над Qt Quick-сценой. Преимущество интеграции таким образом заключается в том, что не требуется дополнительный буфер кадра и память для выполнения отрисовки. Недостатком является то, что Qt Quick решает, когда вызывать сигналы, и это единственное время, когда приложение OpenGL разрешено рисовать.

Пример «Дерево сцены — OpenGL под QML» демонстрирует, как использовать эти сигналы.

Другой вариант — создать QQuickFramebufferObject, отрисовать в него и отобразить его в дереве сцен как текстуру. Пример «Дерево сцены — Отрисовка FBO» показывает, как это можно сделать. Также можно комбинировать несколько контекстов отрисовки и нескольких потоков для создания контента, который будет отображаться в дереве сцены. Примеры «Дерево сцены — Отрисовка FBO в потоке» показывают, как это можно сделать.

Предупреждение: При смешивании контента OpenGL с отрисовкой дерева сцен важно, чтобы приложение не оставляло контекст OpenGL в состоянии, когда связаны буферы, включены атрибуты, установлены специальные значения в буфере z или буфере stencil, или аналогичные. Это может привести к непредсказуемому поведению.

Предупреждение: Код отрисовки OpenGL должен быть потокобезопасным, так как отрисовка может происходить вне потока GUI.

Пользовательские элементы с использованием QPainter

Класс QQuickItem предоставляет подкласс QQuickPaintedItem, который позволяет пользователям отрисовывать контент с помощью QPainter.

Предупреждение: Использование QQuickPaintedItem использует косвенную 2D-поверхность для отрисовки контента, либо с помощью программной растеризации, либо с помощью буфера кадра OpenGL (FBO), поэтому отрисовка — двухэтапный процесс. Сначала растеризуйте поверхность, затем нарисуйте её. Использование API дерева сцен напрямую всегда значительно быстрее.

Поддержка ведения журналов

Дерево сцены поддерживает несколько категорий ведения журналов. Они могут быть полезны для отслеживания проблем с производительностью и ошибок, а также для Qt-сотрудников.

  • qt.scenegraph.time.texture - регистрирует время, затраченное на загрузку текстур
  • qt.scenegraph.time.compilation - регистрирует время, затраченное на компиляцию шейдеров
  • qt.scenegraph.time.renderer - регистрирует время, затраченное на различные этапы рендерера
  • qt.scenegraph.time.renderloop - регистрирует время, затраченное на различные этапы петли отрисовки
  • qt.scenegraph.time.glyph - регистрирует время, затраченное на подготовку глифов области расстояния
  • qt.scenegraph.general - регистрирует общую информацию о различных частях дерева сцен и графической стеке
  • qt.scenegraph.renderloop - создаёт подробный журнал различных этапов отрисовки. Этот режим журнала в первую очередь полезен для разработчиков Qt.

Бэкенд дерева сцен

В дополнение к общедоступному API, дерево сцены имеет адаптивный слой, который открывает реализацию для адаптации к конкретной аппаратной части. Это недокументированный, внутренний и закрытый API плагина, который позволяет группам по адаптации аппаратного обеспечения максимально использовать своё оборудование. Он включает:

  • Пользовательские текстуры; в частности, реализация QQuickWindow::createTextureFromImage и внутреннее представление текстуры, используемой типами Image и BorderImage.
  • Пользовательский рендерер; адаптивный слой позволяет плагину определить, как просматривается и отрисовывается дерево сцены, что позволяет оптимизировать алгоритм отрисовки для конкретного оборудования или использовать расширения, которые повышают производительность.
  • Пользовательская реализация дерева сцен многих стандартных типов QML, включая отрисовку текста и шрифтов.
  • Пользовательский драйвер анимации; позволяет системе анимации подключаться к вертикальному обновлению дисплея низкого уровня для получения плавной отрисовки.
  • Пользовательская петля отрисовки; позволяет лучше контролировать, как QML обрабатывает несколько окон.

© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/qt-5.12/qtquick-visualcanvas-scenegraph.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API