Как эффективно скопировать 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.

Другие вопросы по тегам