Attention: Here be dragons

This is the latest (unstable) version of this documentation, which may document features not available in or compatible with released stable versions of Godot.

Зменшення затримок у компіляціях шейдерів (конвеєрів)

Попередження

This page only applies to the Forward+ and Mobile renderers, not Compatibility. Ubershaders and pipeline precompilation rely on functionality only available in modern low-level graphics APIs (Vulkan, Direct3D 12, Metal). The Compatibility renderer uses OpenGL 3.3, OpenGL ES 3.0, or WebGL 2.0 depending on the platform. These versions lack the functionality to effectively implement ubershaders and pipeline precompilation.

To avoid shader stutters in Compatibility, you need to use the legacy approach of preloading materials, shaders, and particles by displaying them for at least one frame in the view frustum when the level is loading.

Конвеєрна компіляція, також широко відома як компіляція шейдерів, є дорогою операцією, яка необхідна механізму для малювання будь-якого вмісту за допомогою GPU.

Блок-схема, що показує весь процес компіляції для шейдера: VisualShader і Standard Material до Godot Shading Language до GLSL до Intermediate Format (SPIR-V) до Pipeline. Компіляція шейдерів — це крок переходу від GLSL до проміжного формату. Конвеєрна компіляція є кроком проміжного форматування до конвеєрної.

Шейдери та матеріали в Godot проходять кілька етапів, перш ніж вони можуть бути запущені GPU.

Точніше кажучи, компіляція шейдерів передбачає переклад коду GLSL, який генерує Godot, у проміжний формат, який можна спільно використовувати між системами (наприклад, SPIR-V при використанні Vulkan). Однак цей формат не може використовуватися безпосередньо графічним процесором.

Конвеєрна компіляція — це крок, на якому драйвер графічного процесора перетворює проміжний формат шейдера (результат компіляції шейдера) на те, що графічний процесор може фактично використовувати для візуалізації. Драйвери зазвичай зберігають кеш конвеєрів, які зберігаються десь у системі, щоб уникнути повторення процесу під час кожного запуску гри. Цей кеш зазвичай видаляється під час оновлення драйвера.

Конвеєри містять більше інформації, ніж просто код шейдера, а це означає, що для кожного шейдера можуть бути десятки конвеєрів або більше! Це ускладнює механізму компілювати їх завчасно, оскільки це було б дуже повільно, а також тому, що це займало б багато пам’яті. Крім того, цей крок можна виконати лише в системі користувача, і дуже важко поділитися результатом між користувачами, якщо вони не мають точно такої самої версії обладнання та драйвера.

До Godot 4.4 не було іншого рішення для конвеєрної компіляції, окрім генерації, коли об’єкт з’являється в полі зору камери, що призводило до сумнозвісного заїкання шейдерів або збоїв, які трапляються лише під час першого проходження. У Godot 4.4 було введено нові механізми для пом’якшення заїкань під час конвеєрної компіляції.

  • Ubershaders: Godot використовує константи спеціалізації, функцію, яка дозволяє драйверу оптимізувати код конвеєра навколо набору параметрів, таких як освітлення, якість тіні тощо. Константи спеціалізації використовуються для оптимізації шейдера шляхом обмеження непотрібних функцій. Зміна константи спеціалізації вимагає перекомпіляції конвеєра. Ubershaders — це спеціальна версія шейдера, яка здатна змінювати ці константи під час візуалізації, що означає, що Godot може заздалегідь скомпілювати лише один конвеєр і скомпілювати більш оптимізовані версії у фоновому режимі під час гри. Це значно зменшує кількість конвеєрів, які необхідно створити.

  • Попередня компіляція конвеєра: за допомогою ubershaders механізм може попередньо компілювати конвеєри в кількох місцях, наприклад, коли завантажуються сітки або коли до сцени додаються вузли. Будучи частиною процесу завантаження ресурсів, конвеєри можуть бути навіть попередньо скомпільовані в кількох фонових потоках, якщо це можливо під час завантаження екранів або навіть під час гри.

Починаючи з Godot 4.4, Godot визначатиме, які конвеєри потрібні, і попередньо компілюватиме їх під час завантаження. Ця система виявлення здебільшого автоматична, але вона покладається на те, що RenderingServer бачить докази всіх шейдерів, сіток або функцій візуалізації під час завантаження. Наприклад, якщо ви завантажуєте сітку та шейдер під час роботи гри, конвеєр для цієї комбінації сітки/шейдера не буде скомпільовано, доки не буде завантажено сітку/шейдер. Подібним чином такі речі, як увімкнення MSAA або встановлення екземпляра вузла VoxelGI під час роботи гри, запускатимуть повторну компіляцію конвеєра.

Монітори попередньої компіляції конвеєра

Завчасна компіляція конвеєрів є основним механізмом, який Godot використовує для пом’якшення заїкань шейдерів, але це не ідеальне рішення. Усвідомлення ситуацій, які можуть призвести до заїкань конвеєра, може бути дуже корисним, а обхідні шляхи досить прості порівняно з попередніми версіями. Ці обхідні шляхи можуть стати менш потрібними з часом у майбутніх версіях Godot, оскільки буде реалізовано більше методів виявлення.

Налагоджувач Godot пропонує монітори для відстеження кількості конвеєрів, створених грою, і кроку, який ініціював їх компіляцію. Ви можете стежити за цими моніторами під час роботи гри, щоб визначити потенційні джерела зависань шейдерів, не стираючи кеш-пам’ять драйверів кожного разу, коли ви хочете перевірити. Раптове збільшення цих значень поза екранами завантаження може проявлятися як збої під час гри, коли хтось вперше грає в гру на своїй системі. Рекомендуємо вам поглянути на ці монітори, щоб визначити можливі джерела заїкань у ваших гравців, оскільки ви, можливо, не зможете відчути їх самостійно, не видаливши кеш-пам’ять драйвера або не протестувавши на слабшій системі.

Знімок екрана монітора конвеєрних компіляцій Godot

Конвеєрні компіляції одного з демонстраційних проектів.

Примітка

Ми можемо бачити конвеєри, скомпільовані під час гри, і перевіряти, які кроки можуть викликати заїкання. Зауважте, що ці значення лише зростатимуть і ніколи не зменшуватимуться, оскільки видалені конвеєри не відстежуються цими моніторами, а конвеєри можуть бути стерті та створені заново під час гри.

  • Полотно: компілюється під час малювання 2D вузла. Механізм наразі не підтримує попередню компіляцію для 2D-елементів, і коли 2D-вузол малюється вперше, з’являться затримки.

  • Сітка: скомпільовано як частину завантаження 3D-сітки та визначення того, які конвеєри можна попередньо скомпільувати з її властивостей. Це може призвести до затримок, якщо меш завантажується під час гри, але їх можна пом’якшити, якщо меш завантажується за допомогою фонового потоку. Модифікатори, які є частиною вузлів, наприклад перевизначення матеріалу, не можна скомпілювати на цьому кроці.

  • Поверхня: компілюється, коли рамку збираються намалювати, а 3D-об’єкти вперше створено на дереві сцени. Це також може включати компіляцію для вузлів, які навіть не видно на дереві сцени. Заїкання відбуватиметься лише на першому кадрі, до якого вузол додано до сцени, що не призведе до очевидного заїкання, якщо воно станеться одразу після екрана завантаження.

  • Draw: Compiled on demand when a 3D object needs to be drawn and an ubershader was not precompiled ahead of time. The engine is unable to precompile this pipeline due to triggering a case that hasn't been covered yet or a modification that was done to the engine's code. Leads to stutters during gameplay. This is identical to Godot versions before 4.4. If you see compilations here, please let the developers know as this should never happen with the Ubershader system. Make sure to attach a minimal reproduction project when doing so.

  • Спеціалізація: компілюється у фоновому режимі під час гри для оптимізації частоти кадрів. Неможливо спричинити заїкання, але може призвести до зниження частоти кадрів, якщо на кадр відбувається багато кадрів.

Особливості попередньої компіляції конвеєра

Godot пропонує багато функцій візуалізації, які не обов’язково використовуються в кожній грі. На жаль, попередня компіляція конвеєра не може знати заздалегідь, чи використовується певна функція в проекті. Деякі з цих функцій можна виявити лише тоді, коли користувач додає вузол до сцени або перемикає певний параметр у проекті чи середовищі. Система попередньої компіляції конвеєра відстежуватиме ці функції, коли вони з’являються вперше, і вмикатиме їх попередню компіляцію для будь-яких сіток або поверхонь, які створюватимуться пізніше.

Якщо ваша гра використовує ці функції, переконайтеся, що у вас є сцена, яка їх використовує, якомога раніше, перш ніж завантажувати більшість ресурсів. Ця сцена може бути дуже простою і працюватиме, якщо використовуватиме функції, які планує використовувати гра. Її навіть можна відобразити за межами екрану принаймні на один кадр, якщо необхідно, наприклад, закривши її вузлом ColorRect або використовуючи class_SubViewport, розташований за межами вікна.

Вам також слід пам’ятати, що зміна будь-якої з цих функцій під час гри призведе до миттєвого заїкання. Обов’язково змінюйте ці функції лише на екранах конфігурації, якщо це необхідно, і вставляйте екрани завантаження та повідомлення, коли зміни буде застосовано.

  • Рівень MSAA: вмикається, коли рівень 3D MSAA змінюється в налаштуваннях проекту. На жаль, різні рівні MSAA, які використовуються в різних вікнах перегляду, призведуть до зависань, оскільки механізм відстежує лише один рівень за раз для виконання попередньої компіляції.

  • Reflection Probes: увімкнено, коли вузол ReflectionProbe розміщено на сцені.

  • Separate Specular: увімкнено, якщо використовуються такі ефекти, як підповерхневе розсіювання або ефект компонування, який базується на вибірці дзеркальності безпосередньо з екрана..

  • Вектори руху: увімкнено, якщо використовуються такі ефекти, як TAA, FSR2 або ефект композитора, для якого потрібні вектори руху (наприклад, розмиття руху).

  • Normal і Roughness: увімкнено, якщо використовується SDFGI, VoxelGI, відображення екранного простору, SSAO, SSIL або використовується normal_roughness_buffer у спеціальному шейдері або CompositorEffect.

  • Карти освітлення: увімкнено, коли вузол LightmapGI розміщено на сцені та вузол використовує запечену карту освітлення.

  • VoxelGI: увімкнено, коли вузол VoxelGI розміщено на сцені.

  • SDFGI: увімкнено, коли WorldEnvironment увімкне SDFGI.

  • Multiview: увімкнено для проектів XR.

  • 16/32-розрядні тіні: увімкнено, коли конфігурацію точності глибини карт тіней змінено в налаштуваннях проекту.

  • Подвійний параболоїд Omni Shadow: увімкнено, коли всесвітнє світло відкидає тіні та використовує режим подвійного параболоїда.

  • Omni Shadow Cubemap: увімкнено, коли універсальне світло відкидає тіні та використовує режим кубічної карти (який є за умовчанням).

Якщо ви спостерігаєте заїкання під час гри, а монітори повідомляють про раптове збільшення компіляцій під час кроку Surface, дуже ймовірно, якусь функцію не було ввімкнено завчасно. Переконайтеся, що цей ефект увімкнено під час завантаження гри, імовірно, вирішить проблему.

Примірник конвеєрної попередньої компіляції

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

На щастя, для Godot 4.4 і пізніших версій можлива попередня компіляція цих конвеєрів за умови, що екземпляр сцени створено принаймні один раз на сцені, навіть якщо вона повністю невидима або поза полем зору камери.

Знімок екрана прикладу прихованого вузла для ефекту

Прихований bullet node, прикріплений до гравця в одному з демонстраційних проектів. Це допомагає механізму заздалегідь скомпілювати конвеєри ефекту.

Якщо ви знаєте про будь-які ефекти, які динамічно додаються до сцени під час гри, і спостерігаєте раптове збільшення на моніторі компіляцій, коли ці ефекти з’являються, обхідним шляхом є прикріплення десь прихованої версії ефекту, яка гарантовано з’явиться.

Наприклад, якщо персонаж гравця може спричинити якийсь вибух, ви можете приєднати ефект дочірнього гравця як невидимий вузол. Обов’язково вимкніть скрипт, приєднаний до прихованого вузла, або приховайте будь-які інші вузли, які можуть спричинити проблеми. Це можна зробити, увімкнувши дочірні елементи, які можна редагувати на вузлі.

Шейдер-бейкер

Починаючи з Godot 4.5, ви можете вибрати запікання шейдерів під час експорту, щоб покращити час початкового запуску. Зазвичай це не вирішує існуючі затримки, але скорочує час, необхідний для першого завантаження гри. Це особливо актуально при використанні Direct3D 12 або Metal, які мають значно повільніший час початкової компіляції шейдерів, ніж Vulkan, через необхідність конвертації. Власні шейдери Godot використовують GLSL і SPIR-V, але Direct3D 12 і Metal використовують інші формати.

Примітка

Шейдер-бейкер може запікати джерело тільки в проміжний формат (SPIR-V для Vulkan, DXIL для Direct3D 12, MIL для Metal). Він не може запікати проміжний формат у кінцевий конвеєр, оскільки це залежить від драйвера GPU та апаратного забезпечення.

Шейдер-бейкер не замінює передкомпіляцію конвеєра, але має на меті доповнити її.

Якщо цю опцію увімкнути, шейдер-бейкер об'єднає скомпільований код шейдера в PCK, що призведе до повного пропуску етапу компіляції шейдера. Недоліком є те, що експорт займе трохи більше часу. Файл PCK буде більшим на кілька мегабайтів.

За замовчуванням шейдер-бекер вимкнено, але ви можете ввімкнути його в кожному пресеті експорту в діалоговому вікні експорту, встановивши позначку навпроти опції експорту Shader Baker > Enabled.

Зверніть увагу, що випікання шейдерів зможе експортувати шейдери лише для драйверів, що підтримуються платформою, на якій наразі працює редактор:

  • Редактор, що працює у Windows, може експортувати шейдери для Vulkan та Direct3D 12.

  • Редактор, що працює на macOS, може експортувати шейдери для Vulkan та Metal.

  • Редактор, що працює на Linux, може експортувати шейдери лише для Vulkan.

  • Редактор, що працює на Android, може експортувати шейдери лише для Vulkan.

Шейдер-бейкер експортуватиме лише ті шейдери, які відповідають налаштуванням проекту rendering/rendering_device/driver для цільової платформи.

Примітка

Шейдер-бейкер підтримується тільки для рендерерів Forward+ і Mobile. Він не матиме ефекту, якщо проект використовує рендерер Compatibility, або для користувачів, які використовують Compatibility fallback через те, що їхнє обладнання не підтримує рендерери Forward+ або Mobile.

Це також означає, що шейдер-бейкер не підтримується на веб-платформі, оскільки веб-платформа підтримує лише рендерер сумісності.