Как эффективно скопировать texture1 в texture2?
Я хочу скопировать texture1 в texture2. Самый глупый способ - копировать данные tex1 из GPU в CPU, а затем копировать данные CPU в GPU. Глупый код, как показано ниже:
float *data = new float[width*height*4];
glBindTexture(GL_TEXTURE_2D, tex1);
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, data);
glBindTexture(GL_TEXTURE_2D, tex2]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, width, height, 0, GL_RGBA, GL_FLOAT, data);
Как я знаю, должен существовать метод, который поддерживает копирование данных из графического процессора в текстовый процессор без участия ЦП. Я рассматриваю возможность использования FBO для рендеринга квадрата tex1 в tex2. Но почему-то я думаю, что это все еще наивно. Так какой же самый эффективный способ реализовать это?
1 ответ
Если у вас есть поддержка OpenGL 4.3, есть прямая glCopyImageSubData
именно для этой цели:
glCopyImageSubData(tex1, GL_TEXTURE_2D, 0, 0, 0, 0,
tex2, GL_TEXTURE_2D, 0, 0, 0, 0,
width, height, 1);
Конечно, это требует, чтобы текстура назначения уже была выделена с изображением соответствующего размера и формата (используя простую glTexImage2D(..., nullptr)
или, может быть, даже лучше glTexStorage2D
если у вас есть GL 4 в любом случае).
Если у вас этого нет, то лучшим вариантом может быть рендеринг одной текстуры в другую с использованием FBO. В конце концов вам даже не нужно визуализировать исходную текстуру. Вы можете просто прикрепить обе текстуры к FBO и вставить одно цветовое вложение в другое, используя glBlitFramebuffer
(ядро начиная с OpenGL 3 или с расширением GL_EXT_framebuffer_blit в 2.x, практически везде, где FBO находятся на первом месте):
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, tex1, 0);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT1,
GL_TEXTURE_2D, tex2, 0);
glDrawBuffer(GL_COLOR_ATTACHMENT1);
glBlitFramebuffer(0, 0, width, height, 0, 0, width, height,
GL_COLOR_BUFFER_BIT, GL_NEAREST);
Конечно, если вы сделаете это несколько раз, было бы неплохо сохранить этот FBO живым. И также это требует, чтобы целевое изображение текстуры имело заранее соответствующий размер и формат. Или вы могли бы также использовать предложение Майкла о том, чтобы только прикрепить исходную текстуру к FBO и сделать старый добрый glCopyTex(Sub)Image2D
в текстуру назначения. Требуется оценка, которая работает лучше (если есть).
И если у вас его даже нет, то вы все равно можете использовать свой подход чтения одной текстуры и записи этих данных в другую. Но вместо использования памяти ЦП в качестве временного буфера, используйте объект буфера пикселей (PBO) (ядро начиная с OpenGL 2.1). У вас все еще будет дополнительная копия, но, по крайней мере, она будет (или, скорее всего, будет) копией GPU-GPU.