aboutsummaryrefslogtreecommitdiff
path: root/copy_pixels_swap_hack.c
diff options
context:
space:
mode:
Diffstat (limited to 'copy_pixels_swap_hack.c')
-rw-r--r--copy_pixels_swap_hack.c67
1 files changed, 67 insertions, 0 deletions
diff --git a/copy_pixels_swap_hack.c b/copy_pixels_swap_hack.c
new file mode 100644
index 0000000..653eeaf
--- /dev/null
+++ b/copy_pixels_swap_hack.c
@@ -0,0 +1,67 @@
+// 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 <dlfcn.h>
+#include <GL/gl.h>
+#include <GL/glx.h>
+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);
+ }
+}