// 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 #include void glCopyPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type) { static int first = 1; static Display* (*glX_GetCurrentDisplay)(void) = NULL; static GLXDrawable (*glX_GetCurrentDrawable)(void) = NULL; static Status (*X_GetGeometry)(Display*,Drawable,Window*,int*,int*,unsigned*,unsigned*,unsigned*,unsigned*); static void (*glX_SwapBuffers)(Display*,GLXDrawable) = NULL; static void (*gl_WindowPos3i)(GLint,GLint,GLint) = NULL; static void (*gl_CopyPixels)(GLint,GLint,GLsizei,GLsizei,GLenum) = NULL; static void (*gl_GetIntegerv)(GLenum,GLint*) = NULL; static void (*gl_DrawBuffer)(GLenum) = NULL; static void (*gl_ReadBuffer)(GLenum) = NULL; if( first ){ *(void**)(&glX_GetCurrentDisplay) = dlsym(RTLD_NEXT, "glXGetCurrentDisplay"); *(void**)(&glX_GetCurrentDrawable) = dlsym(RTLD_NEXT, "glXGetCurrentDrawable"); *(void**)(&glX_SwapBuffers) = dlsym(RTLD_NEXT, "glXSwapBuffers"); *(void**)(&X_GetGeometry) = dlsym(RTLD_NEXT, "XGetGeometry"); *(void**)(&gl_WindowPos3i) = dlsym(RTLD_NEXT, "glWindowPos3i"); *(void**)(&gl_CopyPixels) = dlsym(RTLD_NEXT, "glCopyPixels"); *(void**)(&gl_GetIntegerv) = dlsym(RTLD_NEXT, "glGetIntegerv"); *(void**)(&gl_DrawBuffer) = dlsym(RTLD_NEXT, "glDrawBuffer"); *(void**)(&gl_ReadBuffer) = dlsym(RTLD_NEXT, "glReadBuffer"); first = 0; } Display *dpy; GLXDrawable drw; if( !glX_GetCurrentDisplay || !glX_GetCurrentDrawable || !glX_SwapBuffers || !gl_GetIntegerv || !gl_WindowPos3i || !gl_CopyPixels || !gl_DrawBuffer || !gl_ReadBuffer || !(dpy = glX_GetCurrentDisplay()) || !(drw = glX_GetCurrentDrawable()) ){ return; } GLint buffer_draw = 0; GLint buffer_read = ~0; gl_GetIntegerv(GL_DRAW_BUFFER, &buffer_draw); gl_GetIntegerv(GL_READ_BUFFER, &buffer_read); if( GL_COLOR == type && GL_FRONT == buffer_draw && GL_BACK == buffer_read ){ GLint rp[4] = {0,0,0,0}; Window root; int geom_x, geom_y; unsigned geom_width, geom_height, border, depth; gl_GetIntegerv(GL_CURRENT_RASTER_POSITION, rp); X_GetGeometry(dpy, drw, &root, &geom_x, &geom_y, &geom_width, &geom_height, &border, &depth); glX_SwapBuffers(dpy, drw); gl_DrawBuffer(GL_BACK); gl_ReadBuffer(GL_FRONT); gl_WindowPos3i(0,0,0); gl_CopyPixels(0, 0, geom_width, geom_height, type); gl_DrawBuffer(GL_FRONT); gl_ReadBuffer(GL_BACK); gl_WindowPos3i(rp[0],rp[1],rp[2]); } else { gl_CopyPixels(x,y,width,height,type); } }