Как эффективно инициализировать текстуру с нулями?
Мне нужно инициализировать 2D-текстуру OpenGL с нулями.
Почему? Я обрабатываю эту текстуру с помощью OpenCL. Примерно, этапы рендеринга:
- Создайте текстуру RGBA, инициализируйте нулями (поэтому она содержит прозрачные черные пиксели).
- OpenCL: вычисляет цвет пикселей, где некоторые объекты видны и записывают их в эту текстуру
- OpenGL: добавить отображение среды в прозрачные пиксели и отобразить окончательное изображение
Поэтому мне не нужно передавать какие-либо фактические данные текстуры на glTexImage2d
. Но согласно спецификации, когда я передаю данные = NULL, память текстуры выделяется, но не инициализируется.
Выделение памяти на стороне клиента, заполненной нулями и переходящей в glTexImage2d
, не очень хороший вариант, хотя я могу только подумать.
EDIT: я действительно хочу инициализировать только альфа-компонент (RGB все равно будет перевыполнен), но я сомневаюсь, что это облегчит ситуацию.
Ответы
Ответ 1
Существует несколько способов сделать это:
1: для ширины и высоты для текстуры:
std::vector<GLubyte> emptyData(width * height * 4, 0);
glBindTexture(GL_TEXTURE_2D, texture);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_BGRA, GL_UNSIGNED_BYTE, &emptyData[0]);
Для максимальной эффективности вы должны оставить некоторое время между тем, когда вы вызываете это, и когда OpenCL начинает свою работу.
2: присоедините его к FBO и используйте glClearBuffer.
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0); //Only need to do this once.
glDrawBuffer(GL_COLOR_ATTACHMENT0); //Only need to do this once.
GLuint clearColor[4] = {0, 0, 0, 0};
glClearBufferuiv(GL_COLOR, 0, clearColor);
Кажется, что это должно быть быстрее, поскольку отсутствует процессор DMA CPU-GPU. Но привязка и развязывание ФБО может привести к неэффективности. Опять же, это не так. Профилируйте это, чтобы убедиться.
Обратите внимание, что это работает только для форматов изображений, которые могут использоваться в качестве целей рендеринга. Так что не сжатые текстуры.
3: При наличии достаточных драйверов вы можете использовать расширение ARB_clear_texture:
glClearTexImage(texture, 0, GL_BGRA, GL_UNSIGNED_BYTE, &clearColor);
Обратите внимание, что это работает только для форматов изображений, данные которых могут быть предоставлены стандартными передачами пикселей. Так что не сжатые форматы.
Ответ 2
Просто голова: новое расширение GL_ARB_clear_texture (ядро в 4.4) специально решает эту проблему.
Ответ 3
Возможно, вы можете установить текстуру как цель рендеринга для первого прохода и нарисовать черный примитив. Это может быть быстрее, так как между RAM и графической картой нет обмена данными.
Ответ 4
-
glTexSubImage
заполняется всем изображением:
GLfloat* pData = new GLfloat[1024*768*4];
memset(pData, 0x00, 1024*768*4*sizeof(GLfloat));
glBindTexture(GL_TEXTURE_2D, m_ImageTex);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1024, 768, GL_RGBA, GL_FLOAT, pData);
glBindTexture(GL_TEXTURE_2D, 0);
delete pData;
-
используйте Pixel Buffer для копирования данных из gpu, этот метод выполняется быстрее и лучше
я. init PBO
glGenBuffers(1, &m_PixelBuffer);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, m_PixelBuffer);
glBufferData(GL_PIXEL_UNPACK_BUFFER, SCREEN_WIDTH*SCREEN_HEIGHT*4*sizeof(GLfloat), NULL, GL_STATIC_DRAW);
GLfloat* pData = nullptr;
pData = (GLfloat*)glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);
memset(pData, 0x00, 1024*768*4*sizeof(GLfloat));
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
II.
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, m_PixelBuffer);
glBindTexture(GL_TEXTURE_2D, m_ImageTex);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, GL_RGBA, GL_FLOAT, NULL);
glBindTexture(GL_TEXTURE_2D, 0);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);