Spec-Zone.ru › Qt 5.13

Графическая сцена 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.

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

QSGMaterial

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

QSGMaterialShader

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

QSGMaterialType

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

QSGFlatColorMaterial

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

QSGSimpleMaterial

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

QSGSimpleMaterialShader

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

QSGOpaqueTextureMaterial

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

QSGTextureMaterial

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

QSGVertexColorMaterial

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

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

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

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

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

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

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

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

Доступны три варианта цикла рендеринга: 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 и инициирует блокировку в потоке пользовательского интерфейса.
  3. Пока поток отрисовки готовит новый кадр, поток пользовательского интерфейса вызывает QQuickItem::updatePolish() для выполнения окончательной доработки элементов перед их отрисовкой.
  4. Поток пользовательского интерфейса блокируется.
  5. Выдаётся сигнал QQuickWindow::beforeSynchronizing(). Приложения могут установить прямые соединения (используя Qt::DirectConnection) с этим сигналом для выполнения любой подготовки, необходимой перед вызовами QQuickItem::updatePaintNode().
  6. Синхронизация состояния QML в графе сцены. Это выполняется путём вызова функции QQuickItem::updatePaintNode() для всех элементов, которые изменились с момента предыдущего кадра. Это единственное время, когда элементы QML и узлы в графе сцены взаимодействуют.
  7. Блокировка потока пользовательского интерфейса снимается.
  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. Пока поток отрисовки отрисовывает, пользовательский интерфейс свободен для выполнения анимаций, обработки событий и т. д.

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

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

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

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

По умолчанию 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 должен учитывать многопоточность, поскольку отрисовка может происходить вне потока пользовательского интерфейса.

Настраиваемые элементы, использующие 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.13/qtquick-visualcanvas-scenegraph.html

Spec-Zone.ru

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