Асинхронная потоковая передача данных
Потоковая передача данных — это метод оптимизации, предназначенный для уменьшения скачков, вызванных загрузкой графических ресурсов. При использовании этого метода не все данные загружаются в оперативную память (RAM) сразу. Вместо этого загружаются только необходимые данные, а все остальные загружаются постепенно, по запросу.
Ресурсы загружаются и передаются в GPU отдельными асинхронными потоками. После этого ресурсы синхронизируются и добавляются в виртуальную сцену на стороне CPU.
В UNIGINE асинхронная потоковая передача данных включена по умолчанию. Вы можете отключить асинхронную потоковую передачу данных в UnigineEditor или через консоль:
- В UnigineEditor откройте окно Settings и перейдите в раздел Streaming. Здесь вы можете переключить режим потоковой передачи текстур и/или мешей.
- В консоли запустите соответствующие команды, которые переключают режим потоковой передачи текстур и/или мешей.
Существует два основных режима потоковой передачи — асинхронный (Async) и принудительный (Force). Режим Force обеспечивает принудительную загрузку всех мешей и текстур, необходимых для каждого кадра одновременно (например, захват последовательностей кадров, рендеринг предварительного просмотра нод, прогрев и т.д.).
Для мешей существует дополнительный режим All, который отключает потоковую передачу меша и обеспечивает загрузку всех мешей, доступных в проекте, при запуске приложения. Этот режим хорош для небольших проектов с небольшим количеством мешей.
Система потоковой передачи обеспечивает асинхронную загрузку следующих данных в RAM:
- Все исполняемые файлы текстур и текстуры с включенной опцией Unchanged, включая кубические карты, карты воксельных проб и карты запеченных теней.
- Меши объектов ObjectMeshStatic, ObjectMeshClutter, ObjectMeshCluster, ObjectGuiMesh и DecalMesh.
Вы можете получить общую информацию о потоковых ресурсах, используя консольные команды render_streaming_meshes_info и render_streaming_textures_info.
Также можно вывести на экран список загруженных ресурсов и подробную информацию о них с помощью консольных команд render_streaming_meshes_list и render_streaming_textures_list.
Процедурно сгенерированные объекты, такие как ObjectMeshClutter, генерируются в отдельном потоке, что значительно снижает затраты на производительность.
Общие настройки потоковой передачи#
Чтобы сцена появлялась сразу при запуске приложения, существует параметр First Frames Force, задающий количество кадров, которые будут загружены сразу после первого кадра.
Чтобы воспользоваться преимуществами многопоточности, установите максимальное количество потоков, используемых для потоковой передачи ресурсов, с помощью параметра консоли render_streaming_max_threads. Большее количество потоков приводит к более быстрой потоковой передаче, но может вызвать всплески в случае чрезмерного потребления ресурсов GPU.
Вы можете ограничить количество загружаемых и выгружаемых графических ресурсов на кадр, указав соответствующие бюджеты. Используйте их, чтобы найти баланс между скоростью загрузки/выгрузки и производительностью: имейте в виду, что увеличение бюджета увеличивает производительность потоковой передачи, однако также увеличивается потребление памяти.
Регулируемые ограничения памяти и время автономной работы позволяют избежать ситуаций, когда ресурсы остаются загруженными в оперативную память или видеопамять даже после того, как они больше не используются. Они определены для мешей, загруженных в RAM/VRAM, текстур и частиц отдельно в процентах от общего объема RAM/VRAM.
Ограничение памяти связано со временем существования (lifetime): ресурсы удаляются из оперативной памяти или видеопамяти только при превышении обоих значений.
Ограничения памяти и RAM/VRAM, занимаемые потоковыми ресурсами, доступны в инструменте Performance Profiler.
Ограничения разделены косой чертой: первое значение отображает текущее использование оперативной памяти / видеопамяти, а второе — предел.
Кэш текстур#
Система потоковой передачи использует кеш текстур, состоящий из минимизированных копий, созданных для всех текстур с определяемым пользователем разрешением и хранящихся в папке data/.cache_textures . Эти копии используются вместо оригиналов при загрузке.
Кеш текстур загружается при запуске движка и всегда остается в памяти после загрузки. Для обеспечения плавной загрузки и отрисовки ресурсов потоковые сущности имеют следующие приоритеты загрузки:
- Кеш текстур
- Геометрия
- Некешированные текстуры (вызывают скачки, поскольку кэш текстур генерируется для них на лету; материалы с некешированными и незагруженными текстурами отображаются черными)
- Полноразмерные текстуры
Кэш текстур может быть предварительно загружен или загружен после данных геометрии, флаг Texture Cache Preload управляет приоритетом загрузки кеша текстур.
По умолчанию файлы кэша текстур генерируются с разрешением 16x16, такое низкое разрешение текстур вызывает визуальные артефакты во время загрузки.
Управляйте разрешением кэша текстур через параметр Texture Cache Resolution. Чтобы применить изменения, удалите существующие файлы кэша с помощью консольной команды render_streaming_textures_cache_destroy, после чего кэш текстур будет сгенерирован автоматически с новым указанным разрешением.
Информацию об объеме видеопамяти, занятом в данный момент кешем текстур, можно посмотреть в инструменте Performance Profiler.
Консольные команды render_streaming_textures_cache_load и render_streaming_textures_cache_unload позволяют управлять загрузкой кеша текстур. Например. после загрузки полноразмерных текстур кеш текстур может быть выгружен из видеопамяти для повышения производительности.
Потоковая передача мешей#
Меши могут быть загружены в оперативную память и видеопамять отдельно для более эффективной работы с геометрией. Это позволяет устранить утечки памяти: меши, участвующие в коллизиях и пересечениях, могут быть загружены в оперативную память только в том случае, если они в данный момент не отрисованы.
Существует 3 режима потоковой передачи мешей в RAM/VRAM:
- асинхронный режим, обеспечивающий асинхронную загрузку мешей;
- принудительный режим для одновременной принудительной загрузки мешей, необходимых для текущего кадра;
- режим загрузки всех мешей, доступных в проекте, при запуске приложения. На самом деле, этот режим вообще отключает потоковую передачу мешей.
Асинхронная загрузка в RAM и VRAM отличается. Даже если меш не был загружен в видеопамять вовремя, это не влияет на поведение приложения (вы можете заметить только некоторую задержку). Однако, если меш не был загружен в память вовремя, это может привести к неправильному физическому поведению объектов в сцене.
Прежде всего, мы настоятельно рекомендуем вам использовать формы (shape) для обнаружения столкновений и пересечений, поскольку это быстрее. Если по какой-то причине это вам не подходит, воспользуйтесь следующими способами:
- Загружайте меши и сохраняйте их в памяти, пока они существуют. В API некоторых объектов на основе меша эта функциональность предусмотрена. Это может частично решить проблему с некорректным поведением, однако загруженными могут оставаться только несколько мешей.
-
Используйте систему предварительной выборки, которая позволяет асинхронно предварительно загружать меши, участвующие в коллизиях и пересечениях, в память перед их использованием:
- Установите режим предварительной выборки Radius.
- Укажите физический радиус (для столкновений) и/или радиус, в пределах которого рассчитываются пересечения.
- Укажите радиус предварительной выборки, который должен превышать значения радиуса столкновения и пересечения.
Вы также можете предварительно загрузить все меши, для которых вычисляются коллизии и пересечения (режим предварительной выборки Full), однако это значительно увеличит использование оперативной памяти.
- API некоторых mesh-объектов, а также API класса MeshStatic предоставляют также методы, которые позволяют реализовать пользовательскую логику предварительной выборки для предварительной загрузки мешей.
Асинхронно передаваемые меши не должны изменяться. Единственный способ изменить такой меш — сделать его процедурным. Процедурный меш — это меш, созданный с помощью кода, такие меши имеют определенный режим потоковой передачи — они всегда сохраняются в памяти после создания и никогда не выгружаются, пока объект не будет уничтожен через код или меш не вернется в свой обычный режим (потоковая передача из исходного файла). API объектов на основе меша позволяет переключать меш в процедурный режим и применять изменения.
Настройки OpenGL#
Настройки и рабочий процесс для OpenGL API немного отличаются от DirectX API.
В OpenGL система потоковой передачи данных задействует два промежуточных буфера для передачи данных между CPU и новым ресурсом:
- Async Buffer используется для потоковой передачи мешей и текстур
- Async Buffer Indices используется для потоковой передачи индексов вершин мешей
размер буфера Async Buffer должен соответствовать размеру самого большого ресурса (меш/текстура), иначе в случае большего ресурса, размер буфера будет изменен, вызывая скачок.
Механизм синхронизации буфера включается, если для параметра Async Buffer Synchronization установлено значение 1 . Таким образом, асинхронные буферы создаются только один раз, а затем синхронизируются, сокращая время на выделение и освобождение памяти. Когда синхронизация отключена, и Async Buffer, и Async Buffer Indices создаются заново для каждого нового ресурса. Это уменьшает количество синхронизаций буфера, но увеличивает количество выделений памяти.
Иногда (в зависимости от используемого оборудования/драйвера, например, когда на основной поток влияют примитивы синхронизации в других потоках) выделение памяти может быть быстрее, чем синхронизация; в таких случаях, когда потоковая передача становится неприемлемо медленной, рекомендуется отключить синхронизацию буфера.
Есть некоторые известные проблемы и обходные пути для некоторых аппаратных средств / программного обеспечения драйверов:
- Mesa 3D GL: для повышения производительности необходимо отключить синхронизацию буфера (gl_async_buffer_synchronization 0). Требуются обновленные бесплатные графические драйверы.
- Intel: необходимо принять во внимание, что объем VRAM ограничен ОС половиной от RAM.