Spec-Zone.ru › Qt 5.14

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

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

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

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

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

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

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

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

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

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

Узлы

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

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

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

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

QSGClipNode

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

QSGGeometryNode

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

QSGNode

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

QSGOpacityNode

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

QSGTransformNode

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

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

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

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

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

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

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

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

Материалы

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

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

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

QSGFlatColorMaterial

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

QSGMaterial

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

QSGMaterialRhiShader

Представляет независимую от графического API программу шейдера

QSGMaterialShader

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

QSGMaterialType

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

QSGOpaqueTextureMaterial

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

QSGSimpleMaterial

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

QSGSimpleMaterialShader

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

QSGTextureMaterial

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

QSGVertexColorMaterial

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

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

Узлы для удобства использования

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

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

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

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

Для подробного описания работы рендерера графической сцены см. По умолчанию рендерер графической сцены Qt Quick.

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

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

Потоковый цикл отрисовки ("threaded")

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

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

  1. Происходит изменение в QML-сцене, вызывая QQuickItem::update(). Это может быть результатом, например, анимации или пользовательского ввода. В поток отрисовки публикуется событие для запуска нового кадра.
  2. Поток отрисовки готовится к отрисовке нового кадра и инициирует блокировку в потоке 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) с этим сигналом для использования пользовательских вызовов графического API, которые будут визуально располагаться под QML-сценой.
    2. Элементы, для которых указан QSGNode::UsePreprocess, будут иметь вызываемую функцию QSGNode::preprocess().
    3. Рендерер обрабатывает узлы.
    4. Рендерер генерирует состояния и записывает вызовы отрисовки для используемого графического API.
    5. Сигнал QQuickWindow::afterRendering() генерируется. Приложения могут создавать прямые соединения (используя Qt::DirectConnection) с этим сигналом для выдачи пользовательских вызовов графического API, которые будут визуально располагаться над QML-сценой.
    6. Кадр готов. Буферы обмениваются (OpenGL), или команда представления записывается, и буферы команд отправляются в очередь графики (Vulkan, Metal). Генерируется QQuickWindow::frameSwapped().
  9. Пока поток отрисовки выполняет отрисовку, поток GUI свободен для продвижения анимаций, обработки событий и т. д.

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

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

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

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

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

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

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

Настройка управления отрисовкой с QQuickRenderControl

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

Сочетание графа сцены и родного графического API

Граф сцены предлагает два способа интеграции команд графики, предоставляемых приложением: путем прямого вызова команд OpenGL, Vulkan, Metal и т. д. и путем создания текстурного узла в графе сцены.

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

Пример Scene Graph - OpenGL Under QML демонстрирует использование этих сигналов с OpenGL.

Пример Scene Graph - Direct3D 11 Under QML демонстрирует использование этих сигналов с Direct3D.

Пример Scene Graph - Metal Under QML демонстрирует использование этих сигналов с Metal.

Пример Scene Graph - Vulkan Under QML демонстрирует использование этих сигналов с Vulkan.

Другой вариант, доступный в настоящее время только для OpenGL, заключается в создании QQuickFramebufferObject, отрисовке в нем и отображении его в графе сцены в качестве текстуры. Пример Scene Graph - Rendering FBOs показывает, как это можно сделать. Также можно объединить несколько контекстов отрисовки и несколько потоков для создания содержимого, отображаемого в графе сцены. Примеры Scene Graph - Rendering FBOs in a thread показывают, как это можно сделать.

Графические API, отличные от OpenGL, также могут следовать этому подходу, хотя QQuickFramebufferObject в настоящее время их не поддерживает. Создание и отрисовка непосредственно в текстуру с использованием базового API, за которым следует обертывание и использование этого ресурса в Qt Quick-сцене в пользовательском QQuickItem, показано в примере Scene Graph - Metal Texture Import. Этот пример использует Metal, но концепции применимы и ко всем остальным графическим API.

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

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

Также доступна устаревшая переменная среды QSG_INFO. Установка значения, отличного от нуля, включает категорию qt.scenegraph.general.

END_OF_DOCUMENT_MARKER

Примечание: При возникновении проблем с графикой или при неопределенности, какой цикл обработки графики или графический API используется, всегда запускайте приложение с включенными по меньшей мере qt.scenegraph.general и qt.rhi.*, или QSG_INFO=1. Это позволит вывести необходимую информацию на вывод отладки во время инициализации.

Бэкенд графа сцены

Помимо публичного 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.14/qtquick-visualcanvas-scenegraph.html

Spec-Zone.ru

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