~ubuntu-branches/ubuntu/trusty/gnome-shell/trusty-proposed

« back to all changes in this revision

Viewing changes to src/shell-screen-grabber.c

Tags: upstream-3.3.90
ImportĀ upstreamĀ versionĀ 3.3.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 
2
 
 
3
#include <string.h>
 
4
 
 
5
#include <clutter/clutter.h>
 
6
#include <cogl/cogl.h>
 
7
#include <GL/gl.h>
 
8
#include <GL/glx.h>
 
9
#include <GL/glext.h>
 
10
 
 
11
#include "shell-screen-grabber.h"
 
12
 
 
13
PFNGLBINDBUFFERARBPROC pf_glBindBufferARB;
 
14
PFNGLBUFFERDATAARBPROC pf_glBufferDataARB;
 
15
PFNGLDELETEBUFFERSARBPROC pf_glDeleteBuffersARB;
 
16
PFNGLGENBUFFERSARBPROC pf_glGenBuffersARB;
 
17
PFNGLMAPBUFFERARBPROC pf_glMapBufferARB;
 
18
PFNGLUNMAPBUFFERARBPROC pf_glUnmapBufferARB;
 
19
 
 
20
struct _ShellScreenGrabberClass
 
21
{
 
22
  GObjectClass parent_class;
 
23
};
 
24
 
 
25
struct _ShellScreenGrabber
 
26
{
 
27
  GObject parent_instance;
 
28
 
 
29
  int have_pixel_buffers;
 
30
  int have_pack_invert;
 
31
  int width, height;
 
32
  GLuint pixel_buffer;
 
33
};
 
34
 
 
35
G_DEFINE_TYPE(ShellScreenGrabber, shell_screen_grabber, G_TYPE_OBJECT);
 
36
 
 
37
static void
 
38
shell_screen_grabber_finalize (GObject *gobject)
 
39
{
 
40
  ShellScreenGrabber *grabber = SHELL_SCREEN_GRABBER (gobject);
 
41
 
 
42
  if (grabber->pixel_buffer != 0)
 
43
    pf_glDeleteBuffersARB (1, &grabber->pixel_buffer);
 
44
}
 
45
 
 
46
static void
 
47
shell_screen_grabber_class_init (ShellScreenGrabberClass *grabber_class)
 
48
{
 
49
  GObjectClass *gobject_class = G_OBJECT_CLASS (grabber_class);
 
50
 
 
51
  gobject_class->finalize = shell_screen_grabber_finalize;
 
52
}
 
53
 
 
54
static void
 
55
shell_screen_grabber_init (ShellScreenGrabber *grabber)
 
56
{
 
57
  grabber->have_pixel_buffers = -1;
 
58
  grabber->width = -1;
 
59
  grabber->height= -1;
 
60
  grabber->pixel_buffer = 0;
 
61
}
 
62
 
 
63
ShellScreenGrabber *
 
64
shell_screen_grabber_new  (void)
 
65
{
 
66
  return g_object_new (SHELL_TYPE_SCREEN_GRABBER, NULL);
 
67
}
 
68
 
 
69
/**
 
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
 
75
 *
 
76
 * Grabs pixel data from a portion of the screen.
 
77
 *
 
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().
 
82
 **/
 
83
guchar *
 
84
shell_screen_grabber_grab (ShellScreenGrabber *grabber,
 
85
                           int                 x,
 
86
                           int                 y,
 
87
                           int                 width,
 
88
                           int                 height)
 
89
{
 
90
  guchar *data;
 
91
  gsize row_bytes;
 
92
  gsize data_size;
 
93
 
 
94
  row_bytes = width * 4;
 
95
  data_size = row_bytes * height;
 
96
  data = g_malloc (data_size);
 
97
 
 
98
  if (grabber->have_pixel_buffers == -1)
 
99
    {
 
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;
 
103
    }
 
104
 
 
105
  if (grabber->have_pixel_buffers)
 
106
    {
 
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;
 
111
      int i;
 
112
 
 
113
      cogl_flush ();
 
114
 
 
115
      if (pf_glBindBufferARB == NULL)
 
116
        {
 
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");
 
123
        }
 
124
 
 
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);
 
131
 
 
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);
 
138
 
 
139
      if (grabber->have_pack_invert)
 
140
        {
 
141
          glGetIntegerv (GL_PACK_INVERT_MESA, &old_pack_invert);
 
142
          glPixelStorei (GL_PACK_INVERT_MESA, GL_FALSE);
 
143
        }
 
144
 
 
145
      if (grabber->pixel_buffer != 0 &&
 
146
          (grabber->width != width ||
 
147
           grabber->height != height))
 
148
        {
 
149
          pf_glDeleteBuffersARB (1, &grabber->pixel_buffer);
 
150
          grabber->pixel_buffer = 0;
 
151
        }
 
152
 
 
153
      if (grabber->pixel_buffer == 0)
 
154
        {
 
155
          pf_glGenBuffersARB (1, &grabber->pixel_buffer);
 
156
 
 
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);
 
159
 
 
160
          grabber->width = width;
 
161
          grabber->height = height;
 
162
        }
 
163
      else
 
164
        {
 
165
          pf_glBindBufferARB (GL_PIXEL_PACK_BUFFER_ARB, grabber->pixel_buffer);
 
166
        }
 
167
 
 
168
      glReadPixels (x, y, width, height, GL_BGRA, GL_UNSIGNED_BYTE, 0);
 
169
 
 
170
      mapped_data = pf_glMapBufferARB (GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB);
 
171
 
 
172
      src_row = mapped_data + (height - 1) * row_bytes;
 
173
      dest_row = data;
 
174
 
 
175
      for (i = 0; i < height; i++)
 
176
        {
 
177
          memcpy (dest_row, src_row, row_bytes);
 
178
          src_row -= row_bytes;
 
179
          dest_row += row_bytes;
 
180
        }
 
181
 
 
182
      pf_glUnmapBufferARB (GL_PIXEL_PACK_BUFFER_ARB);
 
183
      pf_glBindBufferARB (GL_PIXEL_PACK_BUFFER_ARB, 0);
 
184
 
 
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);
 
191
 
 
192
      if (grabber->have_pack_invert)
 
193
        glPixelStorei (GL_PACK_INVERT_MESA, old_pack_invert);
 
194
    }
 
195
  else
 
196
    {
 
197
      cogl_read_pixels (x, y,
 
198
                        width, height,
 
199
                        COGL_READ_PIXELS_COLOR_BUFFER,
 
200
                        CLUTTER_CAIRO_FORMAT_ARGB32,
 
201
                        data);
 
202
    }
 
203
 
 
204
  return data;
 
205
}