2017-02-15 2 views
1

У меня есть 38 систем частиц с разными шейдерами, и каждая система частиц может быть отображена до 200 раз в разных местах (излучателях) в мире. Единственное, что мне нужно обновить (загрузить на GPU), каждый кадр - это позиции эмиттера (и, возможно, некоторые другие атрибуты в некоторых системах), тогда и только тогда, когда какая-либо система частиц активна и видима в области усечения.Должен ли я обновлять несколько VBO с помощью нескольких вызовов glBufferSubData() или одного VBO с одним вызовом glBufferSubData()?

Должен ли я назначить и обновить все вроде этого: -Allocate один VBO для каждой системы частиц, которые могут обрабатывать до 200 эмитентов. Обновите от 0 до 200 излучателей каждый кадр для каждой системы частиц с помощью glBufferSubData(). Выполните одиночный призыв для каждой системы частиц.

В этом худшем случае нам необходимо выполнить 38 вызовов glBufferSubData()!

ИЛИ, я должен сделать это так (Shared VBO): -Allocate очень большой ВБО, который может обрабатывать до 38 (системы частиц) * 200 (излучатели в системе частиц). Обновите все системы частиц одним вызовом для glBufferSubData(). В этом случае нам нужно сгруппировать все излучатели для каждой системы частиц , потому что каждый вызов вызова должен знать начальное смещение для каждой системы частиц и ее излучателей. Выполните одиночный призыв для каждой системы частиц.

Нам нужно позвонить glBufferSubData() только один раз!

Звучит очевидно, что случай nr 2 является победителем, но у меня есть некоторые сомнения. Мы знаем, что 38 систем частиц разделяют один VBO, , но как насчет остановки газопровода GPU? Графический драйвер может выполнять только обновление VBO тогда и только тогда, когда все 38 систем частиц закончены с рендерингом, то есть не будут считывать данные с VBO.

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

Здесь: https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glBufferSubData.xhtml

Должен ли я использовать двойную или даже тройную буферизацию для случая NR 2?

+0

38 * 200 = 7600 позиций ничто. Графический процессор должен сделать их кратковременным миганием. Зачем беспокоиться? – Ripi2

+0

Каждое положение эмиттера составляет 150-300 частиц на графическом процессоре. Большой вопрос заключается в том, как следует обрабатывать передачу CPU-GPU, а не часть вычисления/рендеринга GPU. – karl88

+0

ОК. 2 миллиона не так малы, но все же не так велики. Оцените это. В случае, если оба пути медленны (первый способ, нарисуйте половину, загрузите и нарисуйте остальные). Вы лучше прочитаете главу 28 Асинхронный ... по адресу http://openglinsights.com/ – Ripi2

ответ

2

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

Я бы не хотел останавливать конвейер GPU, если весь буфер не был больше нескольких мегабайт (подумайте, что размер кадра или два в потоке видео высокого разрешения). Изменение VBO - гораздо более дешевое изменение состояния, чем изменение шейдера или фреймбуфера.

В основном это сводится к тому, что у вас есть в запасе: время обработки/синхронизация графического процессора (в виде изменений состояния) или пропускная способность шины PCI-e.

+0

Спасибо за ответ! Да, иногда бывает сложно выбирать между различными решениями. Мое решение: выделите три больших объекта буфера с помощью Round Robin (избегайте неявной синхронизации) и выделите большой вектор поплавков. Этот вектор содержит всю информацию, которая может быть замечена в нашем фрейме, и этот вектор будет загружен на GPU, выполнив один вызов glBufferSubData(). – karl88

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