1
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
5
#include <clutter/clutter.h>
11
#include "shell-screen-grabber.h"
13
PFNGLBINDBUFFERARBPROC pf_glBindBufferARB;
14
PFNGLBUFFERDATAARBPROC pf_glBufferDataARB;
15
PFNGLDELETEBUFFERSARBPROC pf_glDeleteBuffersARB;
16
PFNGLGENBUFFERSARBPROC pf_glGenBuffersARB;
17
PFNGLMAPBUFFERARBPROC pf_glMapBufferARB;
18
PFNGLUNMAPBUFFERARBPROC pf_glUnmapBufferARB;
20
struct _ShellScreenGrabberClass
22
GObjectClass parent_class;
25
struct _ShellScreenGrabber
27
GObject parent_instance;
29
int have_pixel_buffers;
35
G_DEFINE_TYPE(ShellScreenGrabber, shell_screen_grabber, G_TYPE_OBJECT);
38
shell_screen_grabber_finalize (GObject *gobject)
40
ShellScreenGrabber *grabber = SHELL_SCREEN_GRABBER (gobject);
42
if (grabber->pixel_buffer != 0)
43
pf_glDeleteBuffersARB (1, &grabber->pixel_buffer);
47
shell_screen_grabber_class_init (ShellScreenGrabberClass *grabber_class)
49
GObjectClass *gobject_class = G_OBJECT_CLASS (grabber_class);
51
gobject_class->finalize = shell_screen_grabber_finalize;
55
shell_screen_grabber_init (ShellScreenGrabber *grabber)
57
grabber->have_pixel_buffers = -1;
60
grabber->pixel_buffer = 0;
64
shell_screen_grabber_new (void)
66
return g_object_new (SHELL_TYPE_SCREEN_GRABBER, NULL);
70
* shell_screen_grabber_grab:
71
* x: X coordinate of the rectangle to grab
72
* y: Y coordinate of the rectangle to grab
73
* width: width of the rectangle to grab
74
* height: heigth of the rectangle to grab
76
* Grabs pixel data from a portion of the screen.
78
* Return value: buffer holding the grabbed data. The data is stored as 32-bit
79
* words with native-endian xRGB pixels (i.e., the same as CAIRO_FORMAT_RGB24)
80
* with no padding on the rows. So, the size of the buffer is width * height * 4
81
* bytes. Free with g_free().
84
shell_screen_grabber_grab (ShellScreenGrabber *grabber,
94
row_bytes = width * 4;
95
data_size = row_bytes * height;
96
data = g_malloc (data_size);
98
if (grabber->have_pixel_buffers == -1)
100
const GLubyte* extensions = glGetString (GL_EXTENSIONS);
101
grabber->have_pixel_buffers = strstr ((const char *)extensions, "GL_EXT_pixel_buffer_object") != NULL;
102
grabber->have_pack_invert = strstr ((const char *)extensions, "GL_MESA_pack_invert") != NULL;
105
if (grabber->have_pixel_buffers)
107
GLubyte *mapped_data;
108
GLint old_swap_bytes, old_lsb_first, old_row_length, old_skip_pixels, old_skip_rows, old_alignment;
109
GLint old_pack_invert = GL_FALSE;
110
guchar *src_row, *dest_row;
115
if (pf_glBindBufferARB == NULL)
117
pf_glBindBufferARB = (PFNGLBINDBUFFERARBPROC) cogl_get_proc_address ("glBindBufferARB");
118
pf_glBufferDataARB = (PFNGLBUFFERDATAARBPROC) cogl_get_proc_address ("glBufferDataARB");
119
pf_glDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC) cogl_get_proc_address ("glDeleteBuffersARB");
120
pf_glGenBuffersARB = (PFNGLGENBUFFERSARBPROC) cogl_get_proc_address ("glGenBuffersARB");
121
pf_glMapBufferARB = (PFNGLMAPBUFFERARBPROC) cogl_get_proc_address ("glMapBufferARB");
122
pf_glUnmapBufferARB = (PFNGLUNMAPBUFFERARBPROC) cogl_get_proc_address ("glUnmapBufferARB");
125
glGetIntegerv (GL_PACK_SWAP_BYTES, &old_swap_bytes);
126
glGetIntegerv (GL_PACK_LSB_FIRST, &old_lsb_first);
127
glGetIntegerv (GL_PACK_ROW_LENGTH, &old_row_length);
128
glGetIntegerv (GL_PACK_SKIP_PIXELS, &old_skip_pixels);
129
glGetIntegerv (GL_PACK_SKIP_ROWS, &old_skip_rows);
130
glGetIntegerv (GL_PACK_ALIGNMENT, &old_alignment);
132
glPixelStorei (GL_PACK_SWAP_BYTES, GL_FALSE);
133
glPixelStorei (GL_PACK_LSB_FIRST, GL_FALSE);
134
glPixelStorei (GL_PACK_ROW_LENGTH, 0);
135
glPixelStorei (GL_PACK_SKIP_PIXELS, 0);
136
glPixelStorei (GL_PACK_SKIP_ROWS, 0);
137
glPixelStorei (GL_PACK_ALIGNMENT, 1);
139
if (grabber->have_pack_invert)
141
glGetIntegerv (GL_PACK_INVERT_MESA, &old_pack_invert);
142
glPixelStorei (GL_PACK_INVERT_MESA, GL_FALSE);
145
if (grabber->pixel_buffer != 0 &&
146
(grabber->width != width ||
147
grabber->height != height))
149
pf_glDeleteBuffersARB (1, &grabber->pixel_buffer);
150
grabber->pixel_buffer = 0;
153
if (grabber->pixel_buffer == 0)
155
pf_glGenBuffersARB (1, &grabber->pixel_buffer);
157
pf_glBindBufferARB (GL_PIXEL_PACK_BUFFER_ARB, grabber->pixel_buffer);
158
pf_glBufferDataARB (GL_PIXEL_PACK_BUFFER_ARB, data_size, 0, GL_STREAM_READ_ARB);
160
grabber->width = width;
161
grabber->height = height;
165
pf_glBindBufferARB (GL_PIXEL_PACK_BUFFER_ARB, grabber->pixel_buffer);
168
glReadPixels (x, y, width, height, GL_BGRA, GL_UNSIGNED_BYTE, 0);
170
mapped_data = pf_glMapBufferARB (GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB);
172
src_row = mapped_data + (height - 1) * row_bytes;
175
for (i = 0; i < height; i++)
177
memcpy (dest_row, src_row, row_bytes);
178
src_row -= row_bytes;
179
dest_row += row_bytes;
182
pf_glUnmapBufferARB (GL_PIXEL_PACK_BUFFER_ARB);
183
pf_glBindBufferARB (GL_PIXEL_PACK_BUFFER_ARB, 0);
185
glPixelStorei (GL_PACK_SWAP_BYTES, old_swap_bytes);
186
glPixelStorei (GL_PACK_LSB_FIRST, old_lsb_first);
187
glPixelStorei (GL_PACK_ROW_LENGTH, old_row_length);
188
glPixelStorei (GL_PACK_SKIP_PIXELS, old_skip_pixels);
189
glPixelStorei (GL_PACK_SKIP_ROWS, old_skip_rows);
190
glPixelStorei (GL_PACK_ALIGNMENT, old_alignment);
192
if (grabber->have_pack_invert)
193
glPixelStorei (GL_PACK_INVERT_MESA, old_pack_invert);
197
cogl_read_pixels (x, y,
199
COGL_READ_PIXELS_COLOR_BUFFER,
200
CLUTTER_CAIRO_FORMAT_ARGB32,