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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
|
// 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>
#include <X11/Xlib.h>
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);
}
}
|