aboutsummaryrefslogtreecommitdiff
path: root/copy_pixels_swap_hack.c
blob: 653eeafdc864e7489d91fce0ad01fa07e643b241 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
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);
	}
}