Есть ли лучший / более эффективный способ захвата композитного X windows в Linux? - PullRequest
2 голосов
/ 05 мая 2020

По теме у меня есть следующий псевдокод для настройки захвата окна в X (Linux):

xdisplay = XOpenDisplay(NULL);
win_capture = ...find the window to capture...
XCompositeRedirectWindow(xdisplay, win_capture, CompositeRedirectAutomatic);
XGetWindowAttributes(xdisplay, win_capture, &win_attr); // attributes used later
GLXFBConfig *configs = glXChooseFBConfig(xdisplay, win_attr.root, config_attrs, &nelem);
// cycle through the configs to
// find a valid one
...
win_pixmap = XCompositeNameWindowPixmap(xdisplay, win_capture);
const int pixmap_attrs[] = {GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
                    GLX_TEXTURE_FORMAT_EXT,
                    GLX_TEXTURE_FORMAT_RGBA_EXT, None};
gl_pixmap = glXCreatePixmap(xdisplay, config, win_pixmap, pixmap_attrs);
gl_ctx = glXCreateNewContext(xdisplay, config, GLX_RGBA_TYPE, 0, 1);
glXMakeCurrent(xdisplay, gl_pixmap, gl_ctx);
glEnable(GL_TEXTURE_2D);
glGenTextures(1, &gl_texmap);
glBindTexture(GL_TEXTURE_2D, gl_texmap);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, win_attr.width, win_attr.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

Тогда, намного позже, это будет l oop для захвата кадры:

glXMakeCurrent(xdisplay, gl_pixmap, gl_ctx);
glBindTexture(GL_TEXTURE_2D, gl_texmap);
glXBindTexImageEXT(xdisplay, gl_pixmap, GLX_FRONT_LEFT_EXT, NULL);
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); // data is output RGBA buffer
glXReleaseTexImageEXT(xdisplay, gl_pixmap, GLX_FRONT_LEFT_EXT);

Я в основном делаю glXBindTexImageEXT -> glGetTexImage -> glXReleaseTexImageEXT, чтобы получить обновленное изображение. Он работает, но не уверен, что делаю правильный / оптимальный вариант.

Есть ли лучший / более оптимизированный способ получить такое изображение / контекст?

1 Ответ

0 голосов
/ 14 мая 2020

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

Пример псевдокода:

// setup a PBO
GLuint cur_pbo;
glGenBuffers(1, &cur_pbo);
glBindBuffer(GL_PIXEL_PACK_BUFFER, cur_pbo);
glBufferData(GL_PIXEL_PACK_BUFFER, size, NULL, GL_STREAM_READ);

Затем намного позже

glXMakeCurrent(xdisplay, gl_pixmap, gl_ctx);
glBindTexture(GL_TEXTURE_2D, gl_texmap);
glXBindTexImageEXT(xdisplay, gl_pixmap, GLX_FRONT_LEFT_EXT, NULL);
glBindBuffer(GL_PIXEL_PACK_BUFFER, cur_pbo);
// This will initiate the data transfer, the previous
// buffer pointer is now an offset in the index bound by previous
// glBufferData call
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
// do something else
...
...
...
// then later on when we _really_ need to get the data
// perform this call which will make wait if the RGBA 
// data is not avilable yet
void* rgba_ptr = glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);
// Then when finished to use rgba_ptr, release it
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
glXReleaseTexImageEXT(xdisplay, gl_pixmap, GLX_FRONT_LEFT_EXT);

Этот подход определенно лучше, чем оригинальный подход (в вопросе), если вы можете использовать CPU / тот же поток, чтобы что-то делать между вызовами glGetTexImage и glMapBuffer.
Стоит подумать, что может быть еще лучше, даже если вы выполняете эти вызовы последовательно (вместо glGetTexImage без PBO), потому что драйвер все еще может оптимизировать передачу и сам управлять буфером системной памяти.

...