// copy_pixels_swap_hack.c // // Call glXSwapBuffers instead of glCopyPixels if OpenGL read and draw buffers // would perform a copy from back to front buffer. // // compile with // gcc -shared -o copy_pixels_swap_hack.so -fPIC -O2 copy_pixels_swap.c -ldl // // use with // LD_PRELOAD=copy_pixels_swap_hack.so ${YOUR_PROGRAM} // // Refer to the ld.so(8) manpage for the path at which the preloaded shared // objects is searched for. #define _GNU_SOURCE #include #include #include void glCopyPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type) { static int first = 1; static Display* (*glx_get_current_display)(void) = NULL; static GLXDrawable (*glx_get_current_drawable)(void) = NULL; static void (*glx_swap_buffers)(Display*,GLXDrawable) = NULL; static void (*gl_copy_pixels)(GLint,GLint,GLsizei,GLsizei,GLenum) = NULL; static void (*gl_get_integerv)(GLenum,GLint*) = NULL; static void (*gl_draw_buffer)(GLenum) = NULL; static void (*gl_read_buffer)(GLenum) = NULL; if( first ){ *(void**)(&glx_get_current_display) = dlsym(RTLD_NEXT, "glXGetCurrentDisplay"); *(void**)(&glx_get_current_drawable) = dlsym(RTLD_NEXT, "glXGetCurrentDrawable"); *(void**)(&glx_swap_buffers) = dlsym(RTLD_NEXT, "glXSwapBuffers"); *(void**)(&gl_copy_pixels) = dlsym(RTLD_NEXT, "glCopyPixels"); *(void**)(&gl_get_integerv) = dlsym(RTLD_NEXT, "glGetIntegerv"); *(void**)(&gl_draw_buffer) = dlsym(RTLD_NEXT, "glDrawBuffer"); *(void**)(&gl_read_buffer) = dlsym(RTLD_NEXT, "glReadBuffer"); first = 0; } Display *dpy; GLXDrawable drw; if( !glx_get_current_display || !glx_get_current_drawable || !gl_get_integerv || !gl_copy_pixels || !glx_swap_buffers || !gl_draw_buffer || !gl_read_buffer || !(dpy = glx_get_current_display()) || !(drw = glx_get_current_drawable()) ){ return; } GLint buffer_draw = 0; GLint buffer_read = ~0; gl_get_integerv(GL_DRAW_BUFFER, &buffer_draw); gl_get_integerv(GL_READ_BUFFER, &buffer_read); if( GL_COLOR == type && buffer_draw == GL_FRONT && buffer_read == GL_BACK ){ glx_swap_buffers(dpy, drw); gl_draw_buffer(GL_BACK); gl_read_buffer(GL_FRONT); gl_copy_pixels(x,y,width,height,type); gl_draw_buffer(GL_FRONT); gl_read_buffer(GL_BACK); } else { gl_copy_pixels(x,y,width,height,type); } }