~oem-solutions-group/unity-2d/clutter-1.0

« back to all changes in this revision

Viewing changes to clutter/glx/clutter-backend-glx.c

  • Committer: Bazaar Package Importer
  • Author(s): Emilio Pozuelo Monfort
  • Date: 2010-03-21 13:27:56 UTC
  • mto: (2.1.3 experimental)
  • mto: This revision was merged to the branch mainline in revision 8.
  • Revision ID: james.westby@ubuntu.com-20100321132756-nf8yd30yxo3zzwcm
Tags: upstream-1.2.2
ImportĀ upstreamĀ versionĀ 1.2.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
 * Lesser General Public License for more details.
15
15
 *
16
16
 * You should have received a copy of the GNU Lesser General Public
17
 
 * License along with this library; if not, write to the
18
 
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19
 
 * Boston, MA 02111-1307, USA.
 
17
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
 
18
 *
 
19
 *
20
20
 */
21
21
 
22
22
#ifdef HAVE_CONFIG_H
28
28
#ifdef HAVE_UNISTD_H
29
29
#include <unistd.h>
30
30
#endif
 
31
#include <fcntl.h>
31
32
 
32
33
#include <glib/gi18n-lib.h>
33
34
 
34
 
#include <sys/stat.h>
35
 
#include <sys/ioctl.h>
36
 
#include <fcntl.h>
37
 
#include <errno.h>
38
 
 
39
35
#include <GL/glx.h>
 
36
#include <GL/glxext.h>
40
37
#include <GL/gl.h>
41
38
 
42
39
#include "clutter-backend-glx.h"
 
40
#include "clutter-event-glx.h"
43
41
#include "clutter-stage-glx.h"
44
42
#include "clutter-glx.h"
 
43
#include "clutter-profile.h"
45
44
 
46
45
#include "../clutter-event.h"
47
46
#include "../clutter-main.h"
51
50
 
52
51
#include "cogl/cogl.h"
53
52
 
 
53
 
54
54
G_DEFINE_TYPE (ClutterBackendGLX, clutter_backend_glx, CLUTTER_TYPE_BACKEND_X11);
55
55
 
56
56
/* singleton object */
57
57
static ClutterBackendGLX *backend_singleton = NULL;
58
58
 
59
 
static gchar *clutter_vblank_name = NULL;
60
 
 
61
 
#ifdef __linux__
62
 
#define DRM_VBLANK_RELATIVE 0x1;
63
 
 
64
 
struct drm_wait_vblank_request {
65
 
    int           type;
66
 
    unsigned int  sequence;
67
 
    unsigned long signal;
68
 
};
69
 
 
70
 
struct drm_wait_vblank_reply {
71
 
    int          type;
72
 
    unsigned int sequence;
73
 
    long         tval_sec;
74
 
    long         tval_usec;
75
 
};
76
 
 
77
 
typedef union drm_wait_vblank {
78
 
    struct drm_wait_vblank_request request;
79
 
    struct drm_wait_vblank_reply reply;
80
 
} drm_wait_vblank_t;
81
 
 
82
 
#define DRM_IOCTL_BASE                  'd'
83
 
#define DRM_IOWR(nr,type)               _IOWR(DRM_IOCTL_BASE,nr,type)
84
 
#define DRM_IOCTL_WAIT_VBLANK           DRM_IOWR(0x3a, drm_wait_vblank_t)
85
 
 
86
 
static int drm_wait_vblank(int fd, drm_wait_vblank_t *vbl)
87
 
{
88
 
    int ret, rc;
89
 
 
90
 
    do 
91
 
      {
92
 
        ret = ioctl(fd, DRM_IOCTL_WAIT_VBLANK, vbl);
93
 
        vbl->request.type &= ~DRM_VBLANK_RELATIVE;
94
 
        rc = errno;
95
 
      } 
96
 
    while (ret && rc == EINTR);
97
 
    
98
 
    return rc;
99
 
}
100
 
 
101
 
#endif 
 
59
static gchar    *clutter_vblank_name = NULL;
102
60
 
103
61
G_CONST_RETURN gchar*
104
62
clutter_backend_glx_get_vblank_method (void)
127
85
                                GError         **error)
128
86
{
129
87
  ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
 
88
  ClutterBackendGLX *backend_glx = CLUTTER_BACKEND_GLX (backend);
 
89
  ClutterBackendClass *backend_class =
 
90
    CLUTTER_BACKEND_CLASS (clutter_backend_glx_parent_class);
130
91
  int glx_major, glx_minor;
131
92
 
132
 
  if (clutter_backend_x11_post_parse (backend, error))
133
 
    {
134
 
      if (!glXQueryVersion (backend_x11->xdpy, &glx_major, &glx_minor) 
135
 
          || !(glx_major > 1 || glx_minor > 1)) 
136
 
        {
137
 
          g_set_error (error, CLUTTER_INIT_ERROR,
138
 
                       CLUTTER_INIT_ERROR_BACKEND,
139
 
                       "XServer appears to lack required GLX support");
140
 
 
141
 
          return FALSE;
142
 
        }
143
 
    }
144
 
  else
 
93
  if (!backend_class->post_parse (backend, error))
145
94
    return FALSE;
146
95
 
 
96
  if (!glXQueryExtension (backend_x11->xdpy,
 
97
                          &backend_glx->error_base,
 
98
                          &backend_glx->event_base))
 
99
    {
 
100
      g_set_error (error, CLUTTER_INIT_ERROR,
 
101
                   CLUTTER_INIT_ERROR_BACKEND,
 
102
                   "XServer appears to lack required GLX support");
 
103
 
 
104
      return FALSE;
 
105
    }
 
106
 
 
107
  /* XXX: Technically we should require >= GLX 1.3 support but for a long
 
108
   * time Mesa has exported a hybrid GLX, exporting extensions specified
 
109
   * to require GLX 1.3, but still reporting 1.2 via glXQueryVersion. */
 
110
  if (!glXQueryVersion (backend_x11->xdpy, &glx_major, &glx_minor)
 
111
      || !(glx_major == 1 && glx_minor >= 2))
 
112
    {
 
113
      g_set_error (error, CLUTTER_INIT_ERROR,
 
114
                   CLUTTER_INIT_ERROR_BACKEND,
 
115
                   "XServer appears to lack required GLX 1.2 support");
 
116
      return FALSE;
 
117
    }
 
118
 
147
119
  return TRUE;
148
120
}
149
121
 
150
122
static const GOptionEntry entries[] =
151
123
{
152
 
  { "vblank", 0, 
153
 
    0, 
 
124
  { "vblank", 0,
 
125
    0,
154
126
    G_OPTION_ARG_STRING, &clutter_vblank_name,
155
127
    N_("VBlank method to be used (none, dri or glx)"), "METHOD"
156
128
  },
185
157
 
186
158
  if (backend_glx->gl_context)
187
159
    {
 
160
      glXMakeContextCurrent (backend_x11->xdpy, None, None, NULL);
188
161
      glXDestroyContext (backend_x11->xdpy, backend_glx->gl_context);
189
162
      backend_glx->gl_context = None;
190
163
    }
191
164
 
 
165
  if (backend_glx->dummy_glxwin)
 
166
    {
 
167
      glXDestroyWindow (backend_x11->xdpy, backend_glx->dummy_glxwin);
 
168
      backend_glx->dummy_glxwin = None;
 
169
    }
 
170
 
 
171
  if (backend_glx->dummy_xwin)
 
172
    {
 
173
      XDestroyWindow (backend_x11->xdpy, backend_glx->dummy_xwin);
 
174
      backend_glx->dummy_xwin = None;
 
175
    }
 
176
 
192
177
  G_OBJECT_CLASS (clutter_backend_glx_parent_class)->dispose (gobject);
193
178
}
194
179
 
212
197
 
213
198
  g_warning ("Attempting to create a new backend object. This should "
214
199
             "never happen, so we return the singleton instance.");
215
 
  
 
200
 
216
201
  return g_object_ref (backend_singleton);
217
202
}
218
203
 
228
213
static ClutterFeatureFlags
229
214
clutter_backend_glx_get_features (ClutterBackend *backend)
230
215
{
231
 
  ClutterBackendGLX  *backend_glx = CLUTTER_BACKEND_GLX (backend);
232
 
  const gchar        *glx_extensions = NULL;
 
216
  ClutterBackendGLX *backend_glx = CLUTTER_BACKEND_GLX (backend);
 
217
  const gchar *glx_extensions = NULL;
233
218
  ClutterFeatureFlags flags;
234
 
  
 
219
  gboolean use_dri = FALSE;
 
220
 
235
221
  flags = clutter_backend_x11_get_features (backend);
236
222
  flags |= CLUTTER_FEATURE_STAGE_MULTIPLE;
237
223
 
238
 
  /* this will make sure that the GL context exists and
239
 
   * it's bound to a drawable
240
 
   */
 
224
  /* this will make sure that the GL context exists */
241
225
  g_assert (backend_glx->gl_context != None);
242
226
  g_assert (glXGetCurrentDrawable () != None);
243
227
 
244
 
  CLUTTER_NOTE (BACKEND, "Checking features\n"
245
 
                "GL_VENDOR: %s\n"
246
 
                "GL_RENDERER: %s\n"
247
 
                "GL_VERSION: %s\n"
248
 
                "GL_EXTENSIONS: %s\n",
 
228
  CLUTTER_NOTE (BACKEND,
 
229
                "Checking features\n"
 
230
                "  GL_VENDOR: %s\n"
 
231
                "  GL_RENDERER: %s\n"
 
232
                "  GL_VERSION: %s\n"
 
233
                "  GL_EXTENSIONS: %s",
249
234
                glGetString (GL_VENDOR),
250
235
                glGetString (GL_RENDERER),
251
236
                glGetString (GL_VERSION),
252
237
                glGetString (GL_EXTENSIONS));
253
238
 
254
 
  glx_extensions = 
 
239
  glx_extensions =
255
240
    glXQueryExtensionsString (clutter_x11_get_default_display (),
256
 
                              clutter_x11_get_default_screen ());
257
 
 
258
 
  CLUTTER_NOTE (BACKEND, "GLX Extensions: %s", glx_extensions);
 
241
                              clutter_x11_get_default_screen ());
 
242
 
 
243
  CLUTTER_NOTE (BACKEND, "  GLX Extensions: %s", glx_extensions);
 
244
 
 
245
  use_dri = check_vblank_env ("dri");
259
246
 
260
247
  /* First check for explicit disabling or it set elsewhere (eg NVIDIA) */
261
 
  if (getenv("__GL_SYNC_TO_VBLANK") || check_vblank_env ("none"))
 
248
  if (check_vblank_env ("none"))
262
249
    {
263
250
      CLUTTER_NOTE (BACKEND, "vblank sync: disabled at user request");
264
 
    }
265
 
  else
266
 
    {
267
 
      /* We try two GL vblank syncing mechanisms.  
268
 
       * glXSwapIntervalSGI is tried first, then glXGetVideoSyncSGI.
269
 
       *
270
 
       * glXSwapIntervalSGI is known to work with Mesa and in particular
271
 
       * the Intel drivers. glXGetVideoSyncSGI has serious problems with
272
 
       * Intel drivers causing terrible frame rate so it only tried as a
273
 
       * fallback.
274
 
       *
275
 
       * How well glXGetVideoSyncSGI works with other driver (ATI etc) needs
276
 
       * to be investigated. glXGetVideoSyncSGI on ATI at least seems to have
277
 
       * no effect.
278
 
      */
279
 
      if (!check_vblank_env ("dri") && 
280
 
          cogl_check_extension ("GLX_SGI_swap_control", glx_extensions))
281
 
        {
282
 
          backend_glx->swap_interval = 
283
 
            (SwapIntervalProc) cogl_get_proc_address ("glXSwapIntervalSGI");
284
 
 
285
 
          CLUTTER_NOTE (BACKEND, "attempting glXSwapIntervalSGI vblank setup");
286
 
 
287
 
          if (backend_glx->swap_interval != NULL)
288
 
            {
289
 
              if (backend_glx->swap_interval (1) == 0)
 
251
      goto vblank_setup_done;
 
252
    }
 
253
 
 
254
  if (g_getenv ("__GL_SYNC_TO_VBLANK") != NULL)
 
255
    {
 
256
      backend_glx->vblank_type = CLUTTER_VBLANK_GLX_SWAP;
 
257
      flags |= CLUTTER_FEATURE_SYNC_TO_VBLANK;
 
258
 
 
259
      CLUTTER_NOTE (BACKEND, "Using __GL_SYNC_TO_VBLANK hint");
 
260
      goto vblank_setup_done;
 
261
    }
 
262
 
 
263
  /* We try two GL vblank syncing mechanisms.
 
264
   * glXSwapIntervalSGI is tried first, then glXGetVideoSyncSGI.
 
265
   *
 
266
   * glXSwapIntervalSGI is known to work with Mesa and in particular
 
267
   * the Intel drivers. glXGetVideoSyncSGI has serious problems with
 
268
   * Intel drivers causing terrible frame rate so it only tried as a
 
269
   * fallback.
 
270
   *
 
271
   * How well glXGetVideoSyncSGI works with other driver (ATI etc) needs
 
272
   * to be investigated. glXGetVideoSyncSGI on ATI at least seems to have
 
273
   * no effect.
 
274
   */
 
275
  if (!use_dri &&
 
276
      _cogl_check_extension ("GLX_SGI_swap_control", glx_extensions))
 
277
    {
 
278
      backend_glx->swap_interval =
 
279
        (SwapIntervalProc) cogl_get_proc_address ("glXSwapIntervalSGI");
 
280
 
 
281
      CLUTTER_NOTE (BACKEND, "attempting glXSwapIntervalSGI vblank setup");
 
282
 
 
283
      if (backend_glx->swap_interval != NULL &&
 
284
          backend_glx->swap_interval (1) == 0)
 
285
        {
 
286
          backend_glx->vblank_type = CLUTTER_VBLANK_GLX_SWAP;
 
287
          flags |= CLUTTER_FEATURE_SYNC_TO_VBLANK;
 
288
 
 
289
          CLUTTER_NOTE (BACKEND, "glXSwapIntervalSGI setup success");
 
290
 
 
291
#ifdef GLX_INTEL_swap_event
 
292
          /* GLX_INTEL_swap_event allows us to avoid blocking the CPU
 
293
           * while we wait for glXSwapBuffers to complete, and instead
 
294
           * we get an X event notifying us of completion...
 
295
           */
 
296
          if (!(clutter_paint_debug_flags & CLUTTER_DEBUG_DISABLE_SWAP_EVENTS) &&
 
297
              _cogl_check_extension ("GLX_INTEL_swap_event", glx_extensions))
 
298
            {
 
299
              flags |= CLUTTER_FEATURE_SWAP_EVENTS;
 
300
            }
 
301
#endif /* GLX_INTEL_swap_event */
 
302
 
 
303
          goto vblank_setup_done;
 
304
        }
 
305
 
 
306
      CLUTTER_NOTE (BACKEND, "glXSwapIntervalSGI vblank setup failed");
 
307
    }
 
308
 
 
309
  if (!use_dri &&
 
310
      !(flags & CLUTTER_FEATURE_SYNC_TO_VBLANK) &&
 
311
      _cogl_check_extension ("GLX_SGI_video_sync", glx_extensions))
 
312
    {
 
313
      CLUTTER_NOTE (BACKEND, "attempting glXGetVideoSyncSGI vblank setup");
 
314
 
 
315
      backend_glx->get_video_sync =
 
316
        (GetVideoSyncProc) cogl_get_proc_address ("glXGetVideoSyncSGI");
 
317
 
 
318
      backend_glx->wait_video_sync =
 
319
        (WaitVideoSyncProc) cogl_get_proc_address ("glXWaitVideoSyncSGI");
 
320
 
 
321
      if ((backend_glx->get_video_sync != NULL) &&
 
322
          (backend_glx->wait_video_sync != NULL))
 
323
        {
 
324
          CLUTTER_NOTE (BACKEND, "glXGetVideoSyncSGI vblank setup success");
 
325
 
 
326
          backend_glx->vblank_type = CLUTTER_VBLANK_GLX;
 
327
          flags |= CLUTTER_FEATURE_SYNC_TO_VBLANK;
 
328
 
 
329
          goto vblank_setup_done;
 
330
        }
 
331
 
 
332
      CLUTTER_NOTE (BACKEND, "glXGetVideoSyncSGI vblank setup failed");
 
333
    }
 
334
 
 
335
#ifdef __linux__
 
336
  /*
 
337
   * DRI is really an extreme fallback -rumoured to work with Via chipsets
 
338
   */
 
339
  if (!(flags & CLUTTER_FEATURE_SYNC_TO_VBLANK))
 
340
    {
 
341
      CLUTTER_NOTE (BACKEND, "attempting DRI vblank setup");
 
342
 
 
343
      backend_glx->dri_fd = open("/dev/dri/card0", O_RDWR);
 
344
      if (backend_glx->dri_fd >= 0)
 
345
        {
 
346
          CLUTTER_NOTE (BACKEND, "DRI vblank setup success");
 
347
 
 
348
          backend_glx->vblank_type = CLUTTER_VBLANK_DRI;
 
349
          flags |= CLUTTER_FEATURE_SYNC_TO_VBLANK;
 
350
 
 
351
          goto vblank_setup_done;
 
352
        }
 
353
 
 
354
      CLUTTER_NOTE (BACKEND, "DRI vblank setup failed");
 
355
    }
 
356
#endif /* __linux__ */
 
357
 
 
358
  CLUTTER_NOTE (BACKEND, "no use-able vblank mechanism found");
 
359
 
 
360
vblank_setup_done:
 
361
 
 
362
  if (_cogl_check_extension ("GLX_MESA_copy_sub_buffer", glx_extensions))
 
363
    {
 
364
      backend_glx->copy_sub_buffer =
 
365
        (CopySubBufferProc) cogl_get_proc_address ("glXCopySubBufferMESA");
 
366
    }
 
367
 
 
368
  CLUTTER_NOTE (BACKEND, "backend features checked");
 
369
 
 
370
  return flags;
 
371
}
 
372
 
 
373
/* It seems the GLX spec never defined an invalid GLXFBConfig that
 
374
 * we could overload as an indication of error, so we have to return
 
375
 * an explicit boolean status. */
 
376
gboolean
 
377
_clutter_backend_glx_get_fbconfig (ClutterBackendGLX *backend_glx,
 
378
                                   GLXFBConfig       *config)
 
379
{
 
380
  ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend_glx);
 
381
  GLXFBConfig *configs = NULL;
 
382
  gboolean use_argb = clutter_x11_get_use_argb_visual ();
 
383
  int n_configs, i;
 
384
  static const int attributes[] = {
 
385
    GLX_DRAWABLE_TYPE,    GLX_WINDOW_BIT,
 
386
    GLX_RENDER_TYPE,      GLX_RGBA_BIT,
 
387
    GLX_DOUBLEBUFFER,     GL_TRUE,
 
388
    GLX_RED_SIZE,         1,
 
389
    GLX_GREEN_SIZE,       1,
 
390
    GLX_BLUE_SIZE,        1,
 
391
    GLX_ALPHA_SIZE,       1,
 
392
    GLX_DEPTH_SIZE,       1,
 
393
    GLX_STENCIL_SIZE,     1,
 
394
    None
 
395
  };
 
396
 
 
397
  if (backend_x11->xdpy == None || backend_x11->xscreen == None)
 
398
    return FALSE;
 
399
 
 
400
  /* If we don't already have a cached config then try to get one */
 
401
  if (!backend_glx->found_fbconfig)
 
402
    {
 
403
      CLUTTER_NOTE (BACKEND,
 
404
                    "Retrieving GL fbconfig, dpy: %p, xscreen; %p (%d)",
 
405
                    backend_x11->xdpy,
 
406
                    backend_x11->xscreen,
 
407
                    backend_x11->xscreen_num);
 
408
 
 
409
      configs = glXChooseFBConfig (backend_x11->xdpy,
 
410
                                   backend_x11->xscreen_num,
 
411
                                   attributes,
 
412
                                   &n_configs);
 
413
      if (configs)
 
414
        {
 
415
          if (use_argb)
 
416
            {
 
417
              for (i = 0; i < n_configs; i++)
290
418
                {
291
 
                  backend_glx->vblank_type = CLUTTER_VBLANK_GLX_SWAP;
292
 
                  flags |= CLUTTER_FEATURE_SYNC_TO_VBLANK;
293
 
                  CLUTTER_NOTE (BACKEND, "glXSwapIntervalSGI setup success");
 
419
                  XVisualInfo *vinfo;
 
420
 
 
421
                  vinfo = glXGetVisualFromFBConfig (backend_x11->xdpy,
 
422
                                                    configs[i]);
 
423
                  if (vinfo == None)
 
424
                    continue;
 
425
 
 
426
                  if (vinfo->depth == 32 &&
 
427
                      (vinfo->red_mask   == 0xff0000 &&
 
428
                       vinfo->green_mask == 0x00ff00 &&
 
429
                       vinfo->blue_mask  == 0x0000ff))
 
430
                    {
 
431
                      CLUTTER_NOTE (BACKEND,
 
432
                                    "Found GLX visual ARGB [index:%d]", i);
 
433
 
 
434
                      backend_glx->found_fbconfig = TRUE;
 
435
                      backend_glx->fbconfig = configs[i];
 
436
 
 
437
                      goto out;
 
438
                    }
294
439
                }
295
 
            }
296
 
 
297
 
          if (!(flags & CLUTTER_FEATURE_SYNC_TO_VBLANK))
298
 
            CLUTTER_NOTE (BACKEND, "glXSwapIntervalSGI vblank setup failed");
299
 
        }
300
 
 
301
 
      if (!check_vblank_env ("dri") && 
302
 
          !(flags & CLUTTER_FEATURE_SYNC_TO_VBLANK) &&
303
 
          cogl_check_extension ("GLX_SGI_video_sync", glx_extensions))
304
 
        {
305
 
          CLUTTER_NOTE (BACKEND, "attempting glXGetVideoSyncSGI vblank setup");
306
 
 
307
 
          backend_glx->get_video_sync = 
308
 
            (GetVideoSyncProc) cogl_get_proc_address ("glXGetVideoSyncSGI");
309
 
 
310
 
          backend_glx->wait_video_sync = 
311
 
            (WaitVideoSyncProc) cogl_get_proc_address ("glXWaitVideoSyncSGI");
312
 
 
313
 
          if ((backend_glx->get_video_sync != NULL) &&
314
 
              (backend_glx->wait_video_sync != NULL))
315
 
            {
316
 
              CLUTTER_NOTE (BACKEND, 
317
 
                            "glXGetVideoSyncSGI vblank setup success");
318
 
 
319
 
              backend_glx->vblank_type = CLUTTER_VBLANK_GLX;
320
 
              flags |= CLUTTER_FEATURE_SYNC_TO_VBLANK;
321
 
            }
322
 
 
323
 
          if (!(flags & CLUTTER_FEATURE_SYNC_TO_VBLANK))
324
 
            CLUTTER_NOTE (BACKEND, "glXGetVideoSyncSGI vblank setup failed");
325
 
        }
326
 
#ifdef __linux__
327
 
      /* 
328
 
       * DRI is really an extreme fallback -rumoured to work with Via chipsets
329
 
      */
330
 
      if (!(flags & CLUTTER_FEATURE_SYNC_TO_VBLANK))
331
 
        {
332
 
          CLUTTER_NOTE (BACKEND, "attempting DRI vblank setup");
333
 
          backend_glx->dri_fd = open("/dev/dri/card0", O_RDWR);
334
 
          if (backend_glx->dri_fd >= 0)
335
 
            {
336
 
              CLUTTER_NOTE (BACKEND, "DRI vblank setup success");
337
 
              backend_glx->vblank_type = CLUTTER_VBLANK_DRI;
338
 
              flags |= CLUTTER_FEATURE_SYNC_TO_VBLANK;
339
 
            }
340
 
 
341
 
          if (!(flags & CLUTTER_FEATURE_SYNC_TO_VBLANK))
342
 
            CLUTTER_NOTE (BACKEND, "DRI vblank setup failed");
343
 
        }
344
 
#endif
345
 
      if (!(flags & CLUTTER_FEATURE_SYNC_TO_VBLANK))
346
 
        {
347
 
          CLUTTER_NOTE (BACKEND,
348
 
                        "no use-able vblank mechanism found");
349
 
        }
350
 
    }
351
 
 
352
 
  CLUTTER_NOTE (MISC, "backend features checked");
353
 
 
354
 
  return flags;
 
440
 
 
441
              /* If we make it here then we didn't find an RGBA config so
 
442
                 we'll fall back to using an RGB config */
 
443
              CLUTTER_NOTE (BACKEND, "ARGB visual requested, but none found");
 
444
            }
 
445
 
 
446
          if (n_configs >= 1)
 
447
            {
 
448
              backend_glx->found_fbconfig = TRUE;
 
449
              backend_glx->fbconfig = configs[0];
 
450
            }
 
451
 
 
452
        out:
 
453
          XFree (configs);
 
454
        }
 
455
    }
 
456
 
 
457
  if (backend_glx->found_fbconfig)
 
458
    {
 
459
      *config = backend_glx->fbconfig;
 
460
 
 
461
      return TRUE;
 
462
    }
 
463
  else
 
464
    return FALSE;
 
465
}
 
466
 
 
467
static XVisualInfo *
 
468
clutter_backend_glx_get_visual_info (ClutterBackendX11 *backend_x11)
 
469
{
 
470
  ClutterBackendGLX *backend_glx = CLUTTER_BACKEND_GLX (backend_x11);
 
471
  GLXFBConfig config;
 
472
 
 
473
  if (!_clutter_backend_glx_get_fbconfig (backend_glx, &config))
 
474
    return NULL;
 
475
 
 
476
  return glXGetVisualFromFBConfig (backend_x11->xdpy, config);
355
477
}
356
478
 
357
479
static gboolean
358
480
clutter_backend_glx_create_context (ClutterBackend  *backend,
359
 
                                    gboolean         is_offscreen,
360
481
                                    GError         **error)
361
482
{
362
483
  ClutterBackendGLX *backend_glx = CLUTTER_BACKEND_GLX (backend);
363
484
  ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
364
 
 
 
485
  GLXFBConfig config;
 
486
  gboolean is_direct;
 
487
  Window root_xwin;
 
488
  XSetWindowAttributes attrs;
 
489
  XVisualInfo *xvisinfo;
 
490
  Display *xdisplay;
 
491
  int major;
 
492
  int minor;
 
493
  GLXDrawable dummy_drawable;
 
494
 
 
495
  if (backend_glx->gl_context != None)
 
496
    return TRUE;
 
497
 
 
498
  xdisplay = clutter_x11_get_default_display ();
 
499
  root_xwin = clutter_x11_get_root_window ();
 
500
 
 
501
  if (!_clutter_backend_glx_get_fbconfig (backend_glx, &config))
 
502
    {
 
503
      g_set_error (error, CLUTTER_INIT_ERROR,
 
504
                   CLUTTER_INIT_ERROR_BACKEND,
 
505
                   "Unable to find suitable fbconfig for the GLX context");
 
506
      return FALSE;
 
507
    }
 
508
 
 
509
  CLUTTER_NOTE (BACKEND, "Creating GLX Context (display: %p)", xdisplay);
 
510
 
 
511
  backend_glx->gl_context = glXCreateNewContext (xdisplay,
 
512
                                                 config,
 
513
                                                 GLX_RGBA_TYPE,
 
514
                                                 NULL,
 
515
                                                 True);
365
516
  if (backend_glx->gl_context == None)
366
517
    {
367
 
      XVisualInfo *xvisinfo;
368
 
 
369
 
      xvisinfo =
370
 
        clutter_backend_x11_get_visual_info (backend_x11, is_offscreen);
371
 
 
372
 
      CLUTTER_NOTE (GL, "Creating GL Context (display: %p, %s)",
373
 
                    backend_x11->xdpy,
374
 
                    is_offscreen ? "offscreen" : "onscreen");
375
 
 
376
 
      backend_glx->gl_context = glXCreateContext (backend_x11->xdpy,
377
 
                                                  xvisinfo,
378
 
                                                  0,
379
 
                                                  is_offscreen ? False : True);
380
 
 
381
 
      XFree (xvisinfo);
382
 
 
383
 
      if (backend_glx->gl_context == None)
384
 
        {
385
 
          g_set_error (error, CLUTTER_INIT_ERROR,
386
 
                       CLUTTER_INIT_ERROR_BACKEND,
387
 
                       "Unable to create suitable %s GL context",
388
 
                       is_offscreen ? "offscreen" : "onscreen");
389
 
          return FALSE;
390
 
        }
391
 
 
392
 
      if (!is_offscreen)
393
 
        {
394
 
          gboolean is_direct;
395
 
 
396
 
          is_direct = glXIsDirect (backend_x11->xdpy,
397
 
                                   backend_glx->gl_context);
398
 
 
399
 
          CLUTTER_NOTE (GL, "Setting %s context",
400
 
                        is_direct ? "direct" : "indirect");
401
 
          _cogl_set_indirect_context (!is_direct);
402
 
        }
 
518
      g_set_error (error, CLUTTER_INIT_ERROR,
 
519
                   CLUTTER_INIT_ERROR_BACKEND,
 
520
                   "Unable to create suitable GL context");
 
521
      return FALSE;
 
522
    }
 
523
 
 
524
  is_direct = glXIsDirect (xdisplay, backend_glx->gl_context);
 
525
 
 
526
  CLUTTER_NOTE (GL, "Setting %s context",
 
527
                is_direct ? "direct"
 
528
                          : "indirect");
 
529
  _cogl_set_indirect_context (!is_direct);
 
530
 
 
531
  /* COGL assumes that there is always a GL context selected; in order
 
532
   * to make sure that a GLX context exists and is made current, we use
 
533
   * a dummy, offscreen override-redirect window to which we can always
 
534
   * fall back if no stage is available
 
535
   *
 
536
   * XXX - we need to do this dance because GLX does not allow creating
 
537
   * a context and querying it for basic information (even the function
 
538
   * pointers) unless it's made current to a real Drawable. it should be
 
539
   * possible to avoid this in future releases of Mesa and X11, but right
 
540
   * now this is the best solution available.
 
541
   */
 
542
  xvisinfo = glXGetVisualFromFBConfig (xdisplay, config);
 
543
  if (xvisinfo == None)
 
544
    {
 
545
      g_set_error (error, CLUTTER_INIT_ERROR,
 
546
                   CLUTTER_INIT_ERROR_BACKEND,
 
547
                   "Unable to retrieve the X11 visual");
 
548
      return FALSE;
 
549
    }
 
550
 
 
551
  clutter_x11_trap_x_errors ();
 
552
 
 
553
  attrs.override_redirect = True;
 
554
  attrs.colormap = XCreateColormap (xdisplay,
 
555
                                    root_xwin,
 
556
                                    xvisinfo->visual,
 
557
                                    AllocNone);
 
558
  attrs.border_pixel = 0;
 
559
 
 
560
  backend_glx->dummy_xwin = XCreateWindow (xdisplay, root_xwin,
 
561
                                           -100, -100, 1, 1,
 
562
                                           0,
 
563
                                           xvisinfo->depth,
 
564
                                           CopyFromParent,
 
565
                                           xvisinfo->visual,
 
566
                                           CWOverrideRedirect | CWColormap | CWBorderPixel,
 
567
                                           &attrs);
 
568
 
 
569
  /* Try and create a GLXWindow to use with extensions dependent on
 
570
   * GLX versions >= 1.3 that don't accept regular X Windows as GLX
 
571
   * drawables. */
 
572
  if (glXQueryVersion (backend_x11->xdpy, &major, &minor) &&
 
573
      major == 1 && minor >= 3)
 
574
    {
 
575
      backend_glx->dummy_glxwin = glXCreateWindow (backend_x11->xdpy,
 
576
                                                   config,
 
577
                                                   backend_glx->dummy_xwin,
 
578
                                                   NULL);
 
579
    }
 
580
 
 
581
  if (backend_glx->dummy_glxwin)
 
582
    dummy_drawable = backend_glx->dummy_glxwin;
 
583
  else
 
584
    dummy_drawable = backend_glx->dummy_xwin;
 
585
 
 
586
  CLUTTER_NOTE (BACKEND, "Selecting dummy 0x%x for the GLX context",
 
587
                (unsigned int) dummy_drawable);
 
588
 
 
589
  glXMakeContextCurrent (xdisplay,
 
590
                         dummy_drawable,
 
591
                         dummy_drawable,
 
592
                         backend_glx->gl_context);
 
593
 
 
594
  XFree (xvisinfo);
 
595
 
 
596
  if (clutter_x11_untrap_x_errors ())
 
597
    {
 
598
      g_set_error (error, CLUTTER_INIT_ERROR,
 
599
                   CLUTTER_INIT_ERROR_BACKEND,
 
600
                   "Unable to select the newly created GLX context");
 
601
      return FALSE;
403
602
    }
404
603
 
405
604
  return TRUE;
406
605
}
407
606
 
 
607
/* TODO: remove this interface in favour of
 
608
 * _clutter_stage_window_make_current () */
408
609
static void
409
 
clutter_backend_glx_ensure_context (ClutterBackend *backend, 
 
610
clutter_backend_glx_ensure_context (ClutterBackend *backend,
410
611
                                    ClutterStage   *stage)
411
612
{
412
613
  ClutterStageWindow *impl;
423
624
      backend_x11 = CLUTTER_BACKEND_X11 (backend);
424
625
      CLUTTER_NOTE (MULTISTAGE, "Clearing all context");
425
626
 
426
 
      glXMakeCurrent (backend_x11->xdpy, None, NULL);
 
627
      glXMakeContextCurrent (backend_x11->xdpy, None, None, NULL);
427
628
    }
428
629
  else
429
630
    {
430
631
      ClutterBackendGLX *backend_glx;
 
632
      ClutterBackendX11 *backend_x11;
431
633
      ClutterStageGLX   *stage_glx;
432
634
      ClutterStageX11   *stage_x11;
 
635
      GLXDrawable        drawable;
433
636
 
434
637
      g_assert (impl != NULL);
435
638
 
436
 
      CLUTTER_NOTE (MULTISTAGE, "Setting context for stage of type %s [%p]",
437
 
                    g_type_name (G_OBJECT_TYPE (impl)),
438
 
                    impl);
439
 
 
440
639
      stage_glx = CLUTTER_STAGE_GLX (impl);
441
640
      stage_x11 = CLUTTER_STAGE_X11 (impl);
442
641
      backend_glx = CLUTTER_BACKEND_GLX (backend);
 
642
      backend_x11 = CLUTTER_BACKEND_X11 (backend);
 
643
 
 
644
      drawable = stage_glx->glxwin ? stage_glx->glxwin : stage_x11->xwin;
 
645
 
 
646
      CLUTTER_NOTE (BACKEND,
 
647
                    "Setting context for stage of type %s, window: 0x%x",
 
648
                    G_OBJECT_TYPE_NAME (impl),
 
649
                    (unsigned int) drawable);
443
650
 
444
651
      /* no GL context to set */
445
652
      if (backend_glx->gl_context == None)
450
657
      /* we might get here inside the final dispose cycle, so we
451
658
       * need to handle this gracefully
452
659
       */
453
 
      if (stage_x11->xwin == None)
 
660
      if (drawable == None)
454
661
        {
455
 
          ClutterBackendX11 *backend_x11;
 
662
          GLXDrawable dummy_drawable;
456
663
 
457
 
          backend_x11 = CLUTTER_BACKEND_X11 (backend);
458
 
          CLUTTER_NOTE (MULTISTAGE,
 
664
          CLUTTER_NOTE (BACKEND,
459
665
                        "Received a stale stage, clearing all context");
460
666
 
461
 
          glXMakeCurrent (backend_x11->xdpy, None, NULL);
 
667
          if (backend_glx->dummy_glxwin)
 
668
            dummy_drawable = backend_glx->dummy_glxwin;
 
669
          else
 
670
            dummy_drawable = backend_glx->dummy_xwin;
 
671
 
 
672
          if (dummy_drawable == None)
 
673
            glXMakeContextCurrent (backend_x11->xdpy, None, None, NULL);
 
674
          else
 
675
            {
 
676
              glXMakeContextCurrent (backend_x11->xdpy,
 
677
                                     dummy_drawable,
 
678
                                     dummy_drawable,
 
679
                                     backend_glx->gl_context);
 
680
            }
462
681
        }
463
682
      else
464
683
        {
465
684
          CLUTTER_NOTE (BACKEND,
466
 
                        "MakeCurrent dpy: %p, window: 0x%x (%s), context: %p",
467
 
                        stage_x11->xdpy,
468
 
                        (int) stage_x11->xwin,
 
685
                        "MakeContextCurrent dpy: %p, window: 0x%x (%s), context: %p",
 
686
                        backend_x11->xdpy,
 
687
                        (unsigned int) drawable,
469
688
                        stage_x11->is_foreign_xwin ? "foreign" : "native",
470
689
                        backend_glx->gl_context);
471
690
 
472
 
          glXMakeCurrent (stage_x11->xdpy,
473
 
                          stage_x11->xwin,
474
 
                          backend_glx->gl_context);
 
691
          glXMakeContextCurrent (backend_x11->xdpy,
 
692
                                 drawable,
 
693
                                 drawable,
 
694
                                 backend_glx->gl_context);
475
695
        }
476
696
 
477
697
      if (clutter_x11_untrap_x_errors ())
478
698
        g_critical ("Unable to make the stage window 0x%x the current "
479
699
                    "GLX drawable",
480
 
                    (int) stage_x11->xwin);
481
 
    }
482
 
}
483
 
 
484
 
static void
485
 
glx_wait_for_vblank (ClutterBackendGLX *backend_glx)
486
 
{
487
 
  /* If we are going to wait for VBLANK manually, we not only need
488
 
   * to flush out pending drawing to the GPU before we sleep, we
489
 
   * need to wait for it to finish. Otherwise, we may end up with
490
 
   * the situation:
491
 
   *
492
 
   *        - We finish drawing      - GPU drawing continues
493
 
   *        - We go to sleep         - GPU drawing continues
494
 
   * VBLANK - We call glXSwapBuffers - GPU drawing continues
495
 
   *                                 - GPU drawing continues
496
 
   *                                 - Swap buffers happens
497
 
   *
498
 
   * Producing a tear. Calling glFinish() first will cause us to properly
499
 
   * wait for the next VBLANK before we swap. This obviously does not
500
 
   * happen when we use GLX_SWAP and let the driver do the right thing
501
 
   */
502
 
 
503
 
  switch (backend_glx->vblank_type)
504
 
    {
505
 
    case CLUTTER_VBLANK_GLX_SWAP:
506
 
      /* Nothing */
507
 
      break;
508
 
 
509
 
    case CLUTTER_VBLANK_GLX:
510
 
      {
511
 
        unsigned int retraceCount;
512
 
 
513
 
        glFinish ();
514
 
 
515
 
        backend_glx->get_video_sync (&retraceCount);
516
 
        backend_glx->wait_video_sync (2,
517
 
                                      (retraceCount + 1) % 2,
518
 
                                      &retraceCount);
519
 
      }
520
 
      break;
521
 
 
522
 
    case CLUTTER_VBLANK_DRI:
523
 
#ifdef __linux__
524
 
      {
525
 
        drm_wait_vblank_t blank;
526
 
 
527
 
        glFinish ();
528
 
 
529
 
        blank.request.type     = DRM_VBLANK_RELATIVE;
530
 
        blank.request.sequence = 1;
531
 
        blank.request.signal   = 0;
532
 
        drm_wait_vblank (backend_glx->dri_fd, &blank);
533
 
      }
534
 
#endif
535
 
      break;
536
 
 
537
 
    case CLUTTER_VBLANK_NONE:
538
 
    default:
539
 
      break;
540
 
    }
541
 
}
542
 
 
 
700
                    (unsigned int) drawable);
 
701
    }
 
702
}
 
703
 
 
704
/*
 
705
 * FIXME: we should remove backend_class->redraw() and just
 
706
 * have stage_window_iface->redraw()
 
707
 */
543
708
static void
544
709
clutter_backend_glx_redraw (ClutterBackend *backend,
545
710
                            ClutterStage   *stage)
546
711
{
547
 
  ClutterStageGLX *stage_glx;
548
 
  ClutterStageX11 *stage_x11;
549
 
  ClutterStageWindow *impl;
 
712
  ClutterStageWindow *impl = _clutter_stage_get_window (stage);
550
713
 
551
 
  impl = _clutter_stage_get_window (stage);
552
714
  if (G_UNLIKELY (impl == NULL))
553
715
    {
554
716
      CLUTTER_NOTE (BACKEND, "Stage [%p] has no implementation", stage);
557
719
 
558
720
  g_assert (CLUTTER_IS_STAGE_GLX (impl));
559
721
 
560
 
  stage_x11 = CLUTTER_STAGE_X11 (impl);
561
 
  stage_glx = CLUTTER_STAGE_GLX (impl);
562
 
 
563
 
  /* this will cause the stage implementation to be painted */
564
 
  clutter_actor_paint (CLUTTER_ACTOR (stage));
565
 
  cogl_flush ();
566
 
 
567
 
  if (stage_x11->xwin != None)
568
 
    {
569
 
      /* wait for the next vblank */
570
 
      CLUTTER_NOTE (BACKEND, "Waiting for vblank");
571
 
      glx_wait_for_vblank (CLUTTER_BACKEND_GLX (backend));
572
 
 
573
 
      /* push on the screen */
574
 
      CLUTTER_NOTE (BACKEND, "glXSwapBuffers (display: %p, window: 0x%lx)",
575
 
                    stage_x11->xdpy,
576
 
                    (unsigned long) stage_x11->xwin);
577
 
      glXSwapBuffers (stage_x11->xdpy, stage_x11->xwin);
578
 
    }
579
 
  else
580
 
    {
581
 
      /* offscreen */
582
 
      glXWaitGL ();
583
 
 
584
 
      CLUTTER_GLERR ();
585
 
    }
 
722
  clutter_stage_glx_redraw (CLUTTER_STAGE_GLX (impl),
 
723
                            stage);
586
724
}
587
725
 
588
 
static ClutterActor *
 
726
static ClutterStageWindow *
589
727
clutter_backend_glx_create_stage (ClutterBackend  *backend,
590
728
                                  ClutterStage    *wrapper,
591
729
                                  GError         **error)
592
730
{
593
731
  ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
594
 
  ClutterStageX11   *stage_x11;
595
 
  ClutterActor      *stage;
 
732
  ClutterStageWindow *stage_window;
 
733
  ClutterStageX11 *stage_x11;
596
734
 
597
735
  CLUTTER_NOTE (BACKEND, "Creating stage of type '%s'",
598
736
                g_type_name (CLUTTER_STAGE_TYPE));
599
737
 
600
 
  stage = g_object_new (CLUTTER_TYPE_STAGE_GLX, NULL);
 
738
  stage_window = g_object_new (CLUTTER_TYPE_STAGE_GLX, NULL);
601
739
 
602
740
  /* copy backend data into the stage */
603
 
  stage_x11 = CLUTTER_STAGE_X11 (stage);
604
 
  stage_x11->xdpy = backend_x11->xdpy;
605
 
  stage_x11->xwin_root = backend_x11->xwin_root;
606
 
  stage_x11->xscreen = backend_x11->xscreen_num;
607
 
  stage_x11->backend = backend_x11;
 
741
  stage_x11 = CLUTTER_STAGE_X11 (stage_window);
608
742
  stage_x11->wrapper = wrapper;
609
743
 
610
744
  CLUTTER_NOTE (BACKEND,
611
745
                "GLX stage created[%p] (dpy:%p, screen:%d, root:%u, wrap:%p)",
612
 
                stage,
613
 
                stage_x11->xdpy,
614
 
                stage_x11->xscreen,
615
 
                (unsigned int) stage_x11->xwin_root,
 
746
                stage_window,
 
747
                backend_x11->xdpy,
 
748
                backend_x11->xscreen_num,
 
749
                (unsigned int) backend_x11->xwin_root,
616
750
                wrapper);
617
751
 
618
 
  return stage;
619
 
}
620
 
 
621
 
static XVisualInfo *
622
 
clutter_backend_glx_get_visual_info (ClutterBackendX11 *backend_x11,
623
 
                                     gboolean           for_offscreen)
624
 
{
625
 
  XVisualInfo *xvisinfo;
626
 
  int onscreen_gl_attributes[] = {
627
 
    GLX_RGBA,
628
 
    GLX_DOUBLEBUFFER,
629
 
    GLX_RED_SIZE,     1,
630
 
    GLX_GREEN_SIZE,   1,
631
 
    GLX_BLUE_SIZE,    1,
632
 
    GLX_ALPHA_SIZE,   1,
633
 
    GLX_STENCIL_SIZE, 1,
634
 
    GLX_DEPTH_SIZE,   1,
635
 
    0
636
 
  };
637
 
  int offscreen_gl_attributes[] = {
638
 
    GLX_RGBA,
639
 
    GLX_USE_GL,
640
 
    GLX_DEPTH_SIZE,   0,
641
 
    GLX_ALPHA_SIZE,   0,
642
 
    GLX_STENCIL_SIZE, 1,
643
 
    GLX_RED_SIZE,     1,
644
 
    GLX_GREEN_SIZE,   1,
645
 
    GLX_BLUE_SIZE,    1,
646
 
    0
647
 
  };
648
 
 
649
 
  if (backend_x11->xdpy == None || backend_x11->xscreen == None)
650
 
    return NULL;
651
 
 
652
 
  CLUTTER_NOTE (BACKEND,
653
 
                "Retrieving GL visual (for %s use), dpy: %p, xscreen; %p (%d)",
654
 
                for_offscreen ? "offscreen" : "onscreen",
655
 
                backend_x11->xdpy,
656
 
                backend_x11->xscreen,
657
 
                backend_x11->xscreen_num);
658
 
 
659
 
  xvisinfo = glXChooseVisual (backend_x11->xdpy,
660
 
                              backend_x11->xscreen_num,
661
 
                              for_offscreen ? offscreen_gl_attributes
662
 
                                            : onscreen_gl_attributes);
663
 
 
664
 
  return xvisinfo;
 
752
  return stage_window;
665
753
}
666
754
 
667
755
static void
685
773
  backend_class->ensure_context = clutter_backend_glx_ensure_context;
686
774
 
687
775
  backendx11_class->get_visual_info = clutter_backend_glx_get_visual_info;
 
776
  backendx11_class->handle_event = clutter_backend_glx_handle_event;
688
777
}
689
778
 
690
779
static void