2014-02-05 3 views
3

Я хотел отобразить несколько видеопотоков с помощью OpenGL. В настоящее время я выполняю использование glTexImage2D, предоставляемое JOGL, и рендеринг в окне Swing. Для обновления содержимого текстуры для каждого видеокадра я вызываю glTexImage2D. Я хочу знать, есть ли более быстрый способ обновления текстуры без вызова glTexImage2D для каждого фрейма.Эффективный способ обновления текстуры в OpenGL

ответ

6

Вы всегда будете использовать glTexImage2D, но с той разницей, что данные поступают из объекта-буфера (what is this?), а не из указателя.

Что происходит при обновлении текстуры, это не обновление текстуры, а синхронизация (блокировка) с текущей операции рисования и передача PCIe. Когда вы вызываете glTexImage, OpenGL должен подождать, пока он не будет сделан, показывая последний кадр, в течение которого он все еще читает из текстуры. За это время ваше приложение заблокировано и ничего не делает (это необходимо, потому что в противном случае вы могли бы изменить или освободить указанную память до того, как OpenGL сможет ее скопировать!). Затем он должен скопировать данные и перенести их на графическую карту, и только тогда ваше приложение продолжит работу.
Невозможно сделать этот процесс намного быстрее, можно запустить его асинхронно, так что эта латентность в значительной степени исчезает.

Самый простой способ сделать это, чтобы для видеокадров в create a buffer name, привязать его, и reserve-initialize это раз.
Затем в каждом последующем фрейме отбрасывайте-инициализируйте его, вызывая glBufferData с нулевым указателем данных и заполняя его либо вызовом non-reserving, либо mapping the buffer's complete range.

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

Поскольку слово «синхронизация» уже использовалось, я объясню свой выбор glMapBufferRange по ссылке выше, когда на самом деле вы хотите отобразить весь буфер, а не некоторый диапазон. Зачем это нужно?
Даже если OpenGL может в большинстве случаев избегать синхронизации при использовании вышеприведенной техники сброса, иногда может потребоваться.
Кроме того, для управления буферами все еще требуется выполнить какой-то алгоритм распределения памяти, который требует времени водителя. glMapBufferRange позволяет указать дополнительные флаги, в частности (в более поздних версиях OpenGL), флаг, который говорит «не синхронизировать». Это позволяет использовать более сложный, но все же более быстрый подход, при котором вы создаете один буфер в два раза больше необходимого вам размера, а затем сохраняете отображение/запись нижней или верхней половины, говоря, что OpenGL не синхронизируется вообще. Тогда вы должны знать, когда это безопасно (предположительно, используя объект забора), но вы максимально избегаете всех накладных расходов.

0

Вы не можете обновлять текстуру без обновления текстуры.


Кроме того, я не думаю, что один вызов glTexImage может быть реальной проблемой производительности. Если вы так озабочены этим, создайте две текстуры и нарисуйте одну из них для записи, когда используете другую для рисования, а затем поменяйте (как и операции с двойной буферизацией).

Если вы можете переместить обработку на GPU, вам не нужно будет вызывать функцию вообще, что составляет около 100% ускорения.

Смежные вопросы