Как отправить только новые данные в opengl без потери предыдущих данных? - PullRequest
0 голосов
/ 02 декабря 2018

Я работаю с данными PointCloud, которые мне нужно визуализировать с помощью opengl.Я получаю новый вектор точек данных каждый кадр.Я хочу, чтобы я мог кешировать данные, ранее отправленные в opengl, и отправлять только самые новые данные фрейма.Как я могу это сделать?

Я провел некоторый поиск и нашел эту идею здесь :

// Bind the old buffer to `GL_COPY_READ_BUFFER`
glBindBuffer (GL_COPY_READ_BUFFER, old_buffer);

// Allocate data for a new buffer
glGenBuffers (1, &new_buffer);
glBindBuffer (GL_COPY_WRITE_BUFFER, new_buffer);
glBufferData (GL_COPY_WRITE_BUFFER, ...);

// Copy `old_buffer_size`-bytes of data from `GL_COPY_READ_BUFFER`
//   to `GL_COPY_WRITE_BUFFER` beginning at 0.
glCopyBufferSubData (GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, old_buffer_size);

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

Ответы [ 2 ]

0 голосов
/ 02 декабря 2018

Поскольку OpenGL - это API, ориентированный на рисование объектов (на данный момент игнорируя вычислительные шейдеры), и при рисовании сцены вы обычно начинаете с пустого холста, вам придется сохранять полное отставание данных облака точек на всем протяжении всегоВы хотите иметь возможность перерисовывать промежуток времени.

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

Типичные графические процессоры в наши дни вполне способны выполнять настройку полной вершины со скоростью, значительно превышающей 10 ^ 9 вершин в секунду (уже 20 лет назад графические процессоры могли это делатьчто-то порядка 20 · 10 ^ 6 вершин / секунду).Ваш обычный компьютерный дисплей имеет менее 10 · 10 ^ 6 пикселей.Таким образом, из-за принципа «голубиных отверстий», если вы рисуете больше 10 · 10 ^ 6 точек, вы либо создаете серьезное перерисовывание, либо заполняете большую часть пикселей;на практике это будет где-то между ними.

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

Требуется некоторая форма удаления данных, если вы хотите, чтобы все это оставалось читаемым.И для любого размера pointcloud, который читается, ваш GPU сможет перерисовать все это очень хорошо.

Учитывая необходимость удаления данных, я предлагаю вам выделить большой буфер, который может содержать целоенабор точек в течение срока их службы, до выселения, и использовать его в качестве кругового кругового буфера: иметь смещение, при котором вы записываете новые данные по мере их поступления (используя glBufferSubData), по краям вам, возможно, придется разделить их на двавызовы, передайте последний индекс записи как единое целое, чтобы затемнить точки по возрасту, а затем просто отправьте один вызов glDrawElements, чтобы извлечь все содержимое этого буфера за один раз.

0 голосов
/ 02 декабря 2018

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

Ваш пример кода не имеет значения для этой задачи, поскольку glCopyBufferSubData копирует данные из расположения в памяти GPU в другое место в памяти GPUснова.

Вам нужна комбинация glBufferData и glBufferSubData.glBufferData выделяет память в GPU и optinoaly инициализирует ее.glBufferSubData записывает некоторые данные в уже выделенный буфер GPU.Вы можете трактовать glBufferData как C malloc или C ++ new, тогда как glBufferSubData походит на особую версию C memcpy или C ++ std::copy.Точнее, glBufferSubData - это memcpy от процессора к графическому процессору, а glCopyBufferSubData - это memcpy от графического процессора к графическому процессору.

Как их готовить вместе?Так же, как в C. Вызовите glBufferData один раз во время инициализации (при запуске программы) и вызовите glBufferSubData, когда вам нужно добавить данные.Обязательно выделите достаточно места!Буфер, выделенный glBufferData, не увеличивается, как и буфер malloc.Переполнение буфера с помощью glBufferSubData вызывает неопределенное поведение и может привести к сбою приложения.

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

Помните, что вызов glBufferData с уже назначенной привязкой буфера освободит существующий буфер и создаст новый.

glBufferSubData не перераспределит ваш буфер, но перезапишет данные, которые уже есть.

Позвольте мне проиллюстрировать это переводом C:

glGenBuffers(..., buf); // float* buf;
glBindBuffer(buf); // Tell opengl that we will use buf pointer, no analog in C.
glBufferData(/*non-null pointer*/); // buf = malloc(/*..*/); memcpy(to_gpu, from_cpu);
glBufferData(/*another non-null pointer*/); // free(buf); buf = malloc(/*..*/); memcpy(to_gpu, from_cpu);
glBufferSubData(...); // memcpy(to_gpu, from_cpu);

Идеологический подход

Что вам нужно:

glGenBuffers(..., buf); // float* buf;
glBindBuffer(buf); // Tell opengl that we will use buf pointer, no analog in C.

// Initialization
glBufferData(/*non-null pointer*/); // buf = malloc(/*..*/); memcpy(to_gpu, from_cpu);

// Hot loop
while (needToRender) {
    if(needToAppend) {
        if (dataDoesNotFit) glBufferData(...); // Reallocate, same buffer name
        else glBufferSubData(...); // memcpy(to_gpu, from_cpu);
    }
}

Здесь мы перераспределяем память только изредка,когда нам нужно что-то добавить и буфер слишком мал.

Другие подходы

Я посоветовал перераспределить с glBufferData, так как у вас уже есть все данные в одном буфере на CPU.Если нет (то есть у вас есть блок данных на GPU и другой блок на CPU, но не вместе), вы можете использовать glCopyBufferSubData для перераспределения:

glBufferData(/*alloc new_gpu_buffer*/);
glCopyBufferSubData(/*from old_gpu_buffer to new_gpu_buffer*/);
glDeleteBuffers(/*old_gpu_buffer*/);
glBufferSubData(/*from_cpu_buffer to new_cpu_buffer*/)p; // Add some new data from CPU.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...