1
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
7
#include <clutter/clutter.h>
15
#include "shell-screen-grabber.h"
18
PFNGLBINDBUFFERARBPROC pf_glBindBufferARB;
19
PFNGLBUFFERDATAARBPROC pf_glBufferDataARB;
20
PFNGLDELETEBUFFERSARBPROC pf_glDeleteBuffersARB;
21
PFNGLGENBUFFERSARBPROC pf_glGenBuffersARB;
22
PFNGLMAPBUFFERARBPROC pf_glMapBufferARB;
23
PFNGLUNMAPBUFFERARBPROC pf_glUnmapBufferARB;
26
struct _ShellScreenGrabberClass
28
GObjectClass parent_class;
31
struct _ShellScreenGrabber
33
GObject parent_instance;
35
int have_pixel_buffers;
41
G_DEFINE_TYPE(ShellScreenGrabber, shell_screen_grabber, G_TYPE_OBJECT);
44
shell_screen_grabber_finalize (GObject *gobject)
46
ShellScreenGrabber *grabber = SHELL_SCREEN_GRABBER (gobject);
49
if (grabber->pixel_buffer != 0)
50
pf_glDeleteBuffersARB (1, &grabber->pixel_buffer);
55
shell_screen_grabber_class_init (ShellScreenGrabberClass *grabber_class)
57
GObjectClass *gobject_class = G_OBJECT_CLASS (grabber_class);
59
gobject_class->finalize = shell_screen_grabber_finalize;
63
shell_screen_grabber_init (ShellScreenGrabber *grabber)
65
grabber->have_pixel_buffers = -1;
68
grabber->pixel_buffer = 0;
72
shell_screen_grabber_new (void)
74
return g_object_new (SHELL_TYPE_SCREEN_GRABBER, NULL);
78
* shell_screen_grabber_grab:
79
* x: X coordinate of the rectangle to grab
80
* y: Y coordinate of the rectangle to grab
81
* width: width of the rectangle to grab
82
* height: heigth of the rectangle to grab
84
* Grabs pixel data from a portion of the screen.
86
* Return value: buffer holding the grabbed data. The data is stored as 32-bit
87
* words with native-endian xRGB pixels (i.e., the same as CAIRO_FORMAT_RGB24)
88
* with no padding on the rows. So, the size of the buffer is width * height * 4
89
* bytes. Free with g_free().
92
shell_screen_grabber_grab (ShellScreenGrabber *grabber,
102
row_bytes = width * 4;
103
data_size = row_bytes * height;
104
data = g_malloc (data_size);
107
if (grabber->have_pixel_buffers == -1)
109
const GLubyte* extensions = glGetString (GL_EXTENSIONS);
110
grabber->have_pixel_buffers = strstr ((const char *)extensions, "GL_EXT_pixel_buffer_object") != NULL;
111
grabber->have_pack_invert = strstr ((const char *)extensions, "GL_MESA_pack_invert") != NULL;
114
if (grabber->have_pixel_buffers)
116
GLubyte *mapped_data;
117
GLint old_swap_bytes, old_lsb_first, old_row_length, old_skip_pixels, old_skip_rows, old_alignment;
118
GLint old_pack_invert = GL_FALSE;
120
guchar *src_row, *dest_row;
125
if (pf_glBindBufferARB == NULL)
127
pf_glBindBufferARB = (PFNGLBINDBUFFERARBPROC) cogl_get_proc_address ("glBindBufferARB");
128
pf_glBufferDataARB = (PFNGLBUFFERDATAARBPROC) cogl_get_proc_address ("glBufferDataARB");
129
pf_glDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC) cogl_get_proc_address ("glDeleteBuffersARB");
130
pf_glGenBuffersARB = (PFNGLGENBUFFERSARBPROC) cogl_get_proc_address ("glGenBuffersARB");
131
pf_glMapBufferARB = (PFNGLMAPBUFFERARBPROC) cogl_get_proc_address ("glMapBufferARB");
132
pf_glUnmapBufferARB = (PFNGLUNMAPBUFFERARBPROC) cogl_get_proc_address ("glUnmapBufferARB");
135
glGetIntegerv (GL_PACK_SWAP_BYTES, &old_swap_bytes);
136
glGetIntegerv (GL_PACK_LSB_FIRST, &old_lsb_first);
137
glGetIntegerv (GL_PACK_ROW_LENGTH, &old_row_length);
138
glGetIntegerv (GL_PACK_SKIP_PIXELS, &old_skip_pixels);
139
glGetIntegerv (GL_PACK_SKIP_ROWS, &old_skip_rows);
140
glGetIntegerv (GL_PACK_ALIGNMENT, &old_alignment);
142
glPixelStorei (GL_PACK_SWAP_BYTES, GL_FALSE);
143
glPixelStorei (GL_PACK_LSB_FIRST, GL_FALSE);
144
glPixelStorei (GL_PACK_ROW_LENGTH, 0);
145
glPixelStorei (GL_PACK_SKIP_PIXELS, 0);
146
glPixelStorei (GL_PACK_SKIP_ROWS, 0);
147
glPixelStorei (GL_PACK_ALIGNMENT, 1);
149
if (grabber->have_pack_invert)
151
glGetIntegerv (GL_PACK_INVERT_MESA, &old_pack_invert);
152
glPixelStorei (GL_PACK_INVERT_MESA, GL_FALSE);
155
if (grabber->pixel_buffer != 0 &&
156
(grabber->width != width ||
157
grabber->height != height))
159
pf_glDeleteBuffersARB (1, &grabber->pixel_buffer);
160
grabber->pixel_buffer = 0;
163
if (grabber->pixel_buffer == 0)
165
pf_glGenBuffersARB (1, &grabber->pixel_buffer);
167
pf_glBindBufferARB (GL_PIXEL_PACK_BUFFER_ARB, grabber->pixel_buffer);
168
pf_glBufferDataARB (GL_PIXEL_PACK_BUFFER_ARB, data_size, 0, GL_STREAM_READ_ARB);
170
grabber->width = width;
171
grabber->height = height;
175
pf_glBindBufferARB (GL_PIXEL_PACK_BUFFER_ARB, grabber->pixel_buffer);
178
/* In OpenGL, (x,y) specifies the bottom-left corner rather than the
180
glGetIntegerv (GL_VIEWPORT, vp_size);
181
y = vp_size[3] - (y + height);
183
/* the "big-endian" version actually works for both, but the litle-endian
184
* version has been better tested with a range of drivers, so we'll
185
* keep on using it on little-endian.
187
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
188
glReadPixels (x, y, width, height, GL_BGRA, GL_UNSIGNED_BYTE, 0);
190
glReadPixels (x, y, width, height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, 0);
193
mapped_data = pf_glMapBufferARB (GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB);
195
src_row = mapped_data + (height - 1) * row_bytes;
198
for (i = 0; i < height; i++)
200
memcpy (dest_row, src_row, row_bytes);
201
src_row -= row_bytes;
202
dest_row += row_bytes;
205
pf_glUnmapBufferARB (GL_PIXEL_PACK_BUFFER_ARB);
206
pf_glBindBufferARB (GL_PIXEL_PACK_BUFFER_ARB, 0);
208
glPixelStorei (GL_PACK_SWAP_BYTES, old_swap_bytes);
209
glPixelStorei (GL_PACK_LSB_FIRST, old_lsb_first);
210
glPixelStorei (GL_PACK_ROW_LENGTH, old_row_length);
211
glPixelStorei (GL_PACK_SKIP_PIXELS, old_skip_pixels);
212
glPixelStorei (GL_PACK_SKIP_ROWS, old_skip_rows);
213
glPixelStorei (GL_PACK_ALIGNMENT, old_alignment);
215
if (grabber->have_pack_invert)
216
glPixelStorei (GL_PACK_INVERT_MESA, old_pack_invert);
219
#endif /* HAVE_GLX */
221
cogl_read_pixels (x, y,
223
COGL_READ_PIXELS_COLOR_BUFFER,
224
CLUTTER_CAIRO_FORMAT_ARGB32,