Что может блокировать glGetTexImage в Unreal Engine?

#opengl #synchronization #unreal-engine4

#opengl #синхронизация #unreal-engineer4

Вопрос:

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

Контекст

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

Проблема

Что-то блокирует мой вызов glGetTexImage (копирует текстуру из памяти gpu в память cpu) в Unreal Engine. Я использую отдельный рендерер и поток, чем использует Unreal Engine, поэтому я полагаю, что это не будет конфликтовать. Я думаю, это как-то связано с тем, как движок синхронизируется с потоком рендеринга. У меня есть некоторые доказательства ниже.

Доказательства и теория

Ось y — это время, которое занимает каждый вызов в миллисекундах, а ось x — в реальном времени. Зеленый график — это мой призыв glGetTexImage . Синяя линия — это время, которое требуется игровому потоку для обработки кадра, а красная линия — это время, которое требуется потоку рендеринга для обработки кадра. В этом примере я полностью привязан к графическому процессору, игровой поток просто останавливается для потока рендеринга в соответствии с профилировщиком (не показан). Судя по графику, он glGetTexImage останавливается до тех пор, пока не будет отрисован один или два кадра. Я знаю, что в документации Unreal Engines говорится, что

В Unreal Engine 4 (UE4) весь рендерер работает в своем собственном потоке, который находится на один или два кадра позади игрового потока.

Профилирование данных

Любые рекомендации были бы полезны

Я действительно не ожидаю, что кто-нибудь точно узнает, что здесь происходит не так, если у вас есть какие-либо идеи или советы, я был бы рад их услышать. Я не знаю, какой механизм задействован, который останавливает вызов glGetTexImage , пока Unreal Engine не отобразит один или два кадра. Два средства визуализации полностью исключают друг друга в своей работе, я действительно не уверен, как можно повлиять на работу другого. Это может быть побочным эффектом, основанным на том, как работает мой графический драйвер или что-то в этом роде. Я попытался использовать DirectX11 и Vulkan для средства визуализации Unreal Engine, и оба они вызывают одну и ту же проблему. Если у кого-нибудь есть какие-либо идеи о том, что происходит, или знает какие-либо хорошие инструменты отладки, которые будут диагностировать, что блокирует вызов, я был бы очень признателен.

Ответ №1:

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

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

Итак, если UE и вы сами запускаете некоторые команды рендеринга на GPU, работа UE, возможно, дошла туда первой. Это означает, что когда вы ждете завершения своей работы, вы также ждете завершения работы UE.

И даже если графический процессор позволяет выполнять несколько очередей работы одновременно, работа UE все равно будет потреблять некоторые ресурсы графического процессора от вашей работы. В нем будут использоваться модули выполнения шейдеров и ROP, которые могли использоваться в вашей работе.

Короче говоря, я был бы более удивлен, если бы на glGetTexImage вызов не повлияла работа UE.

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

Комментарии:

1. Спасибо, чувак, ты спасатель. Я действительно ценю это.