Search code examples
copenglopengl-esscreenscreenshot

Fastest way to display a screen buffer captured from other PC


My problem is the following:

I have a pointer that stores a framebuffer which is constantly changed by some thread.

I want to display this framebuffer via OpenGL APIs. My trivial choice is to use glTexImage2D and load the framebuffer again and again at every time. This loading over the framebuffer is necessary because the framebuffer is changed by outside of the OpenGL APIs. I think that there could be some methods or tricks to speed up such as:

  • By finding out the changes inside the framebuffer (Is it even possible?)

  • Some method for fast re-loading of image

  • OpenGL could directly using the pointer of the framebuffer? (So less framebuffer copying)

I'm not sure the above approaches are valid or not. I hope if you could give some advices.


Solution

    • By finding out the changes inside the framebuffer (Is it even possible?)

    That would reduce the required bandwidth, because it's effectively video compression. However the CPU load is notably higher and its much slower than to just DMA copy the data.

    Some method for fast re-loading of image

    Use glTexSubImage2D instead glTexImage2D (note the …Sub…). glTexImage2D goes through a full texture initialization each time its called, which is rather costly.

    If your program does additional things with OpenGL rather than just displaying the image, you can speed things up further, by reducing the time the program is waiting for things to complete by using Pixel Buffer Objects. The essential gist is

    glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboID);
    void *pbuf = glMapBuffer();
    glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
    thread image_load_thread = start_thread_copy_image_to_pbo(image, pbuf);
    
    do_other_things_with_opengl();
    
    join_thread(image_load_thread();
    glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboID);
    glUnmapBuffer();
    glBindTexture(…);
    glTexSubImage2D(…, NULL); /* will read from PBO */
    glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
    
    draw_textured_quad();
    

    Instead of creating and joining with the thread you may as well use a thread pool and condition variables for inter thread synchronization.

    • OpenGL could directly using the pointer of the framebuffer? (So less framebuffer copying)

    Stuff almost always has to be copied around. Don't worry about copies, if they are necessary anyway. The Pixel Buffer Objects I outlined above may or may not work with a shader copy in system RAM. Essentially you can glBufferMap into your process' address space and directly decode into that buffer you're given. But that's no guarantee that a further copy is avoided.