Таким образом, вы сохраняете некоторые данные в памяти вашего ЦП и добавляете больше данных в это хранилище.Затем вы хотите отправить только добавленные данные в графический процессор, а не весь буфер.
Ваш пример кода не имеет значения для этой задачи, поскольку 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 по указателю.Вероятно, он будет медленным (блокирует буфер, останавливает конвейер) и полезен только в особых случаях.Используйте его, если знаете, что делаете.