Тепер, коли наближається перша бета-версія Qt 5.14, настав час поговорити про одну з найважливіших нових функцій. Складно охопити всі деталі, що стосуються поліпшень графічного стека і шляху до Qt 6 в одній статті, тому в частинах 1 і 2 буде описано тло і детальніше розглянуто, що поставлятиметься з версією 5.14. Пізніше, в іншій серії статей, розглянемо технічні деталі та майбутні напрямки.
На сторінці нових функцій 5.14 згадується: додано перший попередній перегляд незалежного від графічного API рендеру сценографа як додаткову функцію. Це дозволяє запускати відповідні програми Qt Quick поверх Vulkan, Metal або Direct3D 11 замість OpenGL .
Що це означає на практиці?
Одна з головних цілей у Qt 6 - відійти від прямого використання OpenGL у більшості місць у Qt і, за наявності відповідних абстракцій, дозволити працювати з ширшою різноманітністю графіки API, такої як Vulkan, Metal і Direct3D. Звичайно, OpenGL (і OpenGL ES) залишається опцією. Основною мотивацією цього є не підвищення продуктивності, а забезпечення Qt Everywhere і в майбутньому, навіть на платформах та пристроях, де OpenGL або недоступний, або небажаний. У той же час, можливість використовувати сучасні низькорівневі API-інтерфейси також може відкрити можливості, коли йдеться про поліпшення продуктивності (наприклад, при більш низькому використанні ЦП (CPU) через менші накладні витрати API) та нові способи роботи в движках рендерингу за Qt Quick та іншими модулями, як нещодавно анонсований Qt Quick 3D.
Крім того, можливість відображати інтерфейси користувача за допомогою основної платформи найбільш підтримуваного графічного API є відмінною новиною для додатків, які виконують власний рідний 2D або 3D графічний рендеринг при використанні Qt для візуалізації інтерфейсу користувача. У такому випадку Qt часто знаходиться не за кермом, коли справа доходить до вирішення, який графічний API використовувати. Наприклад, якщо настільний додаток на macOS хоче використовувати Metal для свого власного 3D-контенту, покладаючись на Qt Quick для рендерингу 2D елементів інтерфейсу користувача, тоді дуже корисно, якщо Qt Quick також рендерит через Metal. Це звучатиме знайомо для тих, хто стежив за розвитком графіки в Qt 5.x. Концептуально це нічим не відрізняється від того, коли підтримка роботи в контекстах профілів ядра OpenGL була представлена у рендерер Qt Quick. Сам по собі Qt Quick цього не потребує, але для того, щоб дозволити інтегрувати зовнішній код рендерингу, пов'язаний з основними функціями профілю, Qt Quick повинен бути обізнаний і здатний з ним впоратися. Так що в цьому сенсі історія є природним продовженням того, що було в Qt 5 і тепер розширюється, щоб охопити графічні API, відмінні від OpenGL.
Все сказане вище може викликати два очевидні питання:
• Як це стосується Qt 5.x? Хіба це не весь Qt матеріал 6?
• Чому б просто не використовувати
<ім'я будь-якого рішення для перекладу графічного API> (
Так що там Qt 5.14?
Розгортання повного перегляду графічних бітів у всіх (або принаймні в більшості) місць у Qt, дійсно, призначене для Qt 6. Однак, зупинка роботи над 5.x і спроба винайти, розробити та реорганізовувати все за один раз, сподіваючись, що все буде добре, не дуже приваблива на практиці. Як говорили (і продовжують говорити) розробники Qt, перша ітерація будь-якого API, ймовірно, буде неоптимальною. Тому замість цього розробники Qt використовують розроблений "паралельний підхід", зосередивши увагу на одній певній технології інтерфейсу користувача в Qt - Qt Quick.
Очікується, що Qt 5.14 поставлятиметься з попереднім переглядом нового шляху рендерингу Qt Quick. За замовчуванням це неактивно і тому для додатків немає видимих змін, всередині вони проходять той же прямий шлях коду на основі OpenGL, що і в більш ранніх версіях. Тим не менш, ті, хто хоче випробувати новий підхід, можуть підписатися: або встановивши змінне середовище, або запросивши його через C++ API в main().
Подивившись на знімок документації Qt 5.14, виявимо наступне:
Не всі програми будуть працювати з коробки під час роботи з встановленим QSG_RHI. Користувацькі реалізації QQuickItem з вузлами графа сцени, що виконують прямі виклики OpenGL або містять код шейдера GLSL в матеріалах користувача не будуть працювати при включенні рендерингу на основі RHI. Це ж стосується елементів ShaderEffect з вихідним кодом GLSL. Рішення для створення нестандартних матеріалів та ефектів сучасним способом в основному вже є, але вони вимагають відповідної міграції додатків. Ранні користувачі можуть експериментувати з цим вже в 5.14 та 5.15, але широке прийняття та міграція, природно, не очікується до Qt 6.0. З іншого боку, багато існуючих програм QML, швидше за все, будуть працювати, навіть якщо базовий движок рендерингу буде проходити через зовсім інший API, такі, як Vulkan або Metal.
Чому б не переклад шару XYZ?
Перш за все, важливо відзначити, що можливість використання API та шарів трансляції шейдерів таких, як MoltenVK, MoltenGL, ANGLE, Zink та інших, все ще існує навіть якщо вони не завжди доступні з коробки. Наприклад, MoltenVK дозволяє також відображати інтерфейси користувача Qt Quick через Vulkan на macOS. Якщо програма Qt Quick бажає використовувати тільки Vulkan і все ще хоче працювати на macOS, MoltenVK - варіант (доки належним чином налаштована збірка Qt використовується розгорнутою, MoltenVK доступний в системах користувачів і т. д.).
Зробити такий шар перекладу обов'язковою залежністю, а значить включити та розгорнути його за допомогою Qt вже зовсім інша історія.
Зайве говорити, що зміна Qt Everywhere на Qt Only, де зовнішні залежності Allow (Qt Only Where External Dependencies Allow) не є ідеальним.
Qt має на меті більшу кількість платформ і середовищ, ніж зазвичай думають. Він може покладатися тільки на обов'язкові сторонні залежності, які компілюються та працюють в «екзотичних» середовищах, і їх легко адаптувати у разі виникнення особливих потреб (наприклад, INTEGRITY, QNX, спеціалізовані вбудовані середовища Linux, системи з непрацюючими або графічними стеками, що знаходяться в розробці, рідкісна необхідність адаптації до приватних частин, або іноді необхідність взаємодії, можливо, залежно від постачальника, нестандартним способом з різними графічними або композиційними API, які ви вважали давно мертвими, і т. д. Все це вимагає гнучкості і настроюваності на кожному рівні стека рендерингу Qt).
Виконувати переклад між мовами затінювання (або проміжними форматами) під час виконання не зовсім ідеально. Очікується, що шейдерний конвеєр Qt 6 більше фокусуватиметься на роботі в автономному режимі або, найпізніше, під час складання програми. Коли шар перекладу знаходиться посередині, приховуючи реальність (яка API, яка мова використовується насправді), ці зусилля швидко стають марними на практиці, оскільки немає можливості підготувати або ввести шейдери, або байт-код для реального базового API.
Деякі зі згаданих варіантів не підлягають обговоренню у зв'язку з поточним станом реальності: OpenGL (ES) є і буде основним робочим конем у найближчому майбутньому на багатьох пристроях. Тому пряме використання одного API може означати, що API є OpenGL або рівнем перекладу, який може бути націлений на OpenGL (також досить ефективний для малопривідних пристроїв).
Випадки, коли движки рендерингу Qt доповнюються користувальницьким, власним кодом рендерингу, як правило, працюють найкраще, коли обидві сторони використовують ті самі API безпосередньо. Використання шару перекладу не завжди є блокуючим у цьому відношенні, якщо вони дозволяють отримати доступ до базових нативних об'єктів (уявіть, наприклад, як Direct3D - Qt Quick взаємодія стала можливою завдяки розширенням EGL при роботі з Qt 5 поверх ANGLE у Windows) і, коли це так, це може створити ще одну проблему, з якою доведеться зіткнутися.
Є ліцензійні наслідки та проблеми. Згадайте, що Apache 2.0 несумісний із GPLv2. Покладатися на комерційні рішення в жодному разі не може бути й мови.
Виходячи з досвіду (деякі з ANGLE і трохи з MoltenVK), використання таких рішень ніколи не було таким простим, як хотілося б спочатку. У якийсь момент зусилля, необхідні підтримки всіх опцій у робочому стані, можуть стати занадто великими, тоді ці зусилля краще витратити те що, щоб зробити все «правильно» безпосередньо з допомогою нативного API. Внутрішньо залежна від платформи природа деяких з цих рішень з перекладу також не ідеальна, якщо потрібно використовувати іншу для кожної цільової платформи Qt, ситуація швидко стає неспроможною.
Таким чином, замість того, щоб покладатися на низькорівневі транслятори API, Qt визначає свою власну високорівневу абстракцію для 3D-графіки (для внутрішнього використання, на даний момент, не доступної для додатків). Потім, це підтримується специфічними для API реалізаціями бекенда, шаблоном, знайомим з багатьох компонентів Qt. У деяких випадках бекенд є платформо-залежним за своєю природою (Metal, D3D), у той час як у деяких інших один бекенд призначений для одного API, але кількох платформ (Vulkan, OpenGL). Це доповнюється новим конвеєром управління шейдерами, заснованим на кількох сторонніх проектах, таких як glslang та SPIRV-Cross. Докладніше про це буде розказано в наступних статтях.
Це справді працює?
Давайте розглянемо приклад, а саме добре відомий демонстраційний додаток Qt5 Cinematic Experience від QUIt Coding. Ми використовуємо трохи змінену версію, в якій оновлюються кілька елементів ShaderEffect, щоб вони працювали з обома шляхами рендерингу сценографа Qt Quick.
При нормальному запуску програми із встановленим QSG_INFO=1 отримуємо:
Як показують журнали, надруковані в результатах налагодження, це працює в OpenGL на робочому столі Linux:
qt.scenegraph.general: threaded render loop qt.scenegraph.general: Using sg animation driver qt.scenegraph.general: Animation Driver: using vsync: 16.95 ms qt.scenegraph.general: opengl texture atlas dimensions: 2048x1024 qt.scenegraph.general: GL_VENDOR: X.Org qt.scenegraph.general: GL_RENDERER: AMD Radeon (TM) R9 M360 (VERDE, DRM 3.23.0, 4.15.0-62-generic, LLVM 8.0.1) qt.scenegraph.general: GL_VERSION: 4.5 (Compatibility Profile) Mesa 19.2.0-devel (git-08f1cef 2019-07-25 bionic-oibaf-ppa) qt.scenegraph.general: GL_EXTENSIONS: ... qt.scenegraph.general: Max Texture Size: 16384 qt.scenegraph.general: Debug context: false
Як зміниться, якщо ми встановимо QSG_RHI=1?
qt.scenegraph.general: Using QRhi with backend OpenGL graphics API debug/validation layers: 0 QRhi profiling and debug markers: 0 qt.scenegraph.general: threaded render loop qt.scenegraph.general: Using sg animation driver qt.scenegraph.general: Animation Driver: using vsync: 16.95 ms qt.rhi.general: Created OpenGL context QSurfaceFormat(version 4.5, options QFlags<QSurfaceFormat::FormatOption>(DeprecatedFunctions), depthBufferSize 24, redBufferSize 8, greenBufferSize 8, blueBufferSize 8, alphaBufferSize 0, stencilBufferSize 8, samples -1, swapBehavior QSurfaceFormat::DoubleBuffer, swapInterval 1, colorSpace QSurfaceFormat::DefaultColorSpace, profile QSurfaceFormat::CompatibilityProfile) qt.rhi.general: OpenGL VENDOR: X.Org RENDERER: AMD Radeon (TM) R9 M360 (VERDE, DRM 3.23.0, 4.15.0-62-generic, LLVM 8.0.1) VERSION: 4.5 (Compatibility Profile) Mesa 19.2.0-devel (git-08f1cef 2019-07-25 bionic-oibaf-ppa) qt.scenegraph.general: MSAA sample count for the swapchain is 1. Alpha channel requested = no. qt.scenegraph.general: rhi texture atlas dimensions: 2048x1024
Не дуже відрізняється, на перший погляд. Досі здається, що це відбувається через OpenGL. Тим не менш, внутрішньо немає прямого використання OpenGL і більше немає шейдерних джерел GLSL у сцені Qt Quick. Натомість рендеринг проходить через QRhi, апаратний інтерфейс рендерингу Qt (приватний API у модулі QtGui на даний момент).
Тепер давайте встановимо QSG_RHI_BACKEND=vulkan :
qt.scenegraph.general: Using QRhi with backend Vulkan graphics API debug/validation layers: 0 QRhi profiling and debug markers: 0 qt.scenegraph.general: threaded render loop qt.scenegraph.general: Using sg animation driver qt.scenegraph.general: Animation Driver: using vsync: 16.95 ms WARNING: radv is not a conformant vulkan implementation, testing use only. qt.rhi.general: Physical device 0: 'AMD RADV CAPE VERDE (LLVM 8.0.1)' 19.1.99 qt.rhi.general: using this physical device qt.rhi.general: queue family 0: flags=0xf count=1 qt.rhi.general: queue family 1: flags=0xe count=2 qt.rhi.general: 55 device extensions available qt.scenegraph.general: MSAA sample count for the swapchain is 1. Alpha channel requested = no. qt.scenegraph.general: rhi texture atlas dimensions: 2048x1024 qt.rhi.general: Creating new swapchain of 3 buffers, size 1280x720, presentation mode 2
Очевидно тепер рендеринг відбувається через Vulkan. Тим не менш, навіть найекзотичніші функції Qt Quick, такі, як рендеринг тексту в дистанційному полі, ефекти шейдерів і частинки, є, як і очікувалося.
Запуск програми в RenderDoc та захоплення кадру дає таке. Qt Quick справді будує об'єкти стану конвеєра Vulkan та буфери команд, а код шейдера надається у вигляді байт-коду SPIR-V.
У другій частині цієї серії буде розглянуто, що Qt 5.14 може запропонувати macOS і Windows. Після цього перейдемо до розгляду того, як все це працює під капотом і якими будуть наслідки для додатків, які потребують нестандартних матеріалів та ефектів.