1 /* GDK - The GIMP Drawing Kit
2 *
3 * gdkglcontext-glx.c: GLX specific wrappers
4 *
5 * SPDX-FileCopyrightText: 2014 Emmanuele Bassi
6 * SPDX-FileCopyrightText: 2021 GNOME Foundation
7 *
8 * SPDX-License-Identifier: LGPL-2.1-or-later
9 */
10
11 #include "config.h"
12
13 #include "gdkglcontext-x11.h"
14 #include "gdkdisplay-x11.h"
15 #include "gdkprivate-x11.h"
16 #include "gdkscreen-x11.h"
17
18 #include "gdkx11display.h"
19 #include "gdkx11glcontext.h"
20 #include "gdkx11screen.h"
21 #include "gdkx11surface.h"
22 #include "gdkx11property.h"
23 #include <X11/Xatom.h>
24
25 #include "gdkinternals.h"
26 #include "gdkprofilerprivate.h"
27 #include "gdkintl.h"
28
29 #include <cairo-xlib.h>
30
31 #include <epoxy/glx.h>
32
33 struct _GdkX11GLContextGLX
34 {
35 GdkX11GLContext parent_instance;
36
37 GLXContext glx_context;
38
39 #ifdef HAVE_XDAMAGE
40 GLsync frame_fence;
41 Damage xdamage;
42 #endif
43
44 guint do_frame_sync : 1;
45 };
46
47 typedef struct _GdkX11GLContextClass GdkX11GLContextGLXClass;
48
G_DEFINE_TYPE(GdkX11GLContextGLX,gdk_x11_gl_context_glx,GDK_TYPE_X11_GL_CONTEXT)49 G_DEFINE_TYPE (GdkX11GLContextGLX, gdk_x11_gl_context_glx, GDK_TYPE_X11_GL_CONTEXT)
50
51 static GLXDrawable
52 gdk_x11_surface_get_glx_drawable (GdkSurface *surface)
53 {
54 GdkX11Surface *self = GDK_X11_SURFACE (surface);
55 GdkDisplay *display = gdk_surface_get_display (GDK_SURFACE (self));
56 GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
57
58 if (self->glx_drawable)
59 return self->glx_drawable;
60
61 self->glx_drawable = glXCreateWindow (gdk_x11_display_get_xdisplay (display),
62 display_x11->glx_config,
63 gdk_x11_surface_get_xid (surface),
64 NULL);
65
66 return self->glx_drawable;
67 }
68
69 void
gdk_x11_surface_destroy_glx_drawable(GdkX11Surface * self)70 gdk_x11_surface_destroy_glx_drawable (GdkX11Surface *self)
71 {
72 if (self->glx_drawable == None)
73 return;
74
75 glXDestroyWindow (gdk_x11_display_get_xdisplay (gdk_surface_get_display (GDK_SURFACE (self))),
76 self->glx_drawable);
77
78 self->glx_drawable = None;
79 }
80
81 static void
maybe_wait_for_vblank(GdkDisplay * display,GLXDrawable drawable)82 maybe_wait_for_vblank (GdkDisplay *display,
83 GLXDrawable drawable)
84 {
85 GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
86 Display *dpy = gdk_x11_display_get_xdisplay (display);
87
88 if (display_x11->has_glx_sync_control)
89 {
90 gint64 ust, msc, sbc;
91
92 glXGetSyncValuesOML (dpy, drawable, &ust, &msc, &sbc);
93 glXWaitForMscOML (dpy, drawable,
94 0, 2, (msc + 1) % 2,
95 &ust, &msc, &sbc);
96 }
97 else if (display_x11->has_glx_video_sync)
98 {
99 guint32 current_count;
100
101 glXGetVideoSyncSGI (¤t_count);
102 glXWaitVideoSyncSGI (2, (current_count + 1) % 2, ¤t_count);
103 }
104 }
105
106 static GLXDrawable
gdk_x11_gl_context_glx_get_drawable(GdkX11GLContextGLX * self)107 gdk_x11_gl_context_glx_get_drawable (GdkX11GLContextGLX *self)
108 {
109 GdkDrawContext *draw_context = GDK_DRAW_CONTEXT (self);
110 GdkSurface *surface;
111
112 if (gdk_draw_context_is_in_frame (draw_context))
113 surface = gdk_draw_context_get_surface (draw_context);
114 else
115 surface = GDK_X11_DISPLAY (gdk_draw_context_get_display (draw_context))->leader_gdk_surface;
116
117 return gdk_x11_surface_get_glx_drawable (surface);
118 }
119
120 static void
gdk_x11_gl_context_glx_end_frame(GdkDrawContext * draw_context,cairo_region_t * painted)121 gdk_x11_gl_context_glx_end_frame (GdkDrawContext *draw_context,
122 cairo_region_t *painted)
123 {
124 GdkX11GLContextGLX *self = GDK_X11_GL_CONTEXT_GLX (draw_context);
125 GdkGLContext *context = GDK_GL_CONTEXT (draw_context);
126 GdkSurface *surface = gdk_gl_context_get_surface (context);
127 GdkX11Surface *x11_surface = GDK_X11_SURFACE (surface);
128 GdkDisplay *display = gdk_gl_context_get_display (context);
129 Display *dpy = gdk_x11_display_get_xdisplay (display);
130 GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
131 GLXDrawable drawable;
132
133 GDK_DRAW_CONTEXT_CLASS (gdk_x11_gl_context_glx_parent_class)->end_frame (draw_context, painted);
134
135 gdk_gl_context_make_current (context);
136
137 drawable = gdk_x11_surface_get_glx_drawable (surface);
138
139 GDK_DISPLAY_NOTE (display, OPENGL,
140 g_message ("Flushing GLX buffers for drawable %lu (window: %lu), frame sync: %s",
141 (unsigned long) drawable,
142 (unsigned long) gdk_x11_surface_get_xid (surface),
143 self->do_frame_sync ? "yes" : "no"));
144
145 gdk_profiler_add_mark (GDK_PROFILER_CURRENT_TIME, 0, "x11", "swap buffers");
146
147 /* if we are going to wait for the vertical refresh manually
148 * we need to flush pending redraws, and we also need to wait
149 * for that to finish, otherwise we are going to tear.
150 *
151 * obviously, this condition should not be hit if we have
152 * GLX_SGI_swap_control, and we ask the driver to do the right
153 * thing.
154 */
155 if (self->do_frame_sync)
156 {
157 guint32 end_frame_counter = 0;
158 gboolean has_counter = display_x11->has_glx_video_sync;
159 gboolean can_wait = display_x11->has_glx_video_sync || display_x11->has_glx_sync_control;
160
161 if (display_x11->has_glx_video_sync)
162 glXGetVideoSyncSGI (&end_frame_counter);
163
164 if (self->do_frame_sync && !display_x11->has_glx_swap_interval)
165 {
166 glFinish ();
167
168 if (has_counter && can_wait)
169 {
170 if (x11_surface->glx_frame_counter == end_frame_counter)
171 maybe_wait_for_vblank (display, drawable);
172 }
173 else if (can_wait)
174 maybe_wait_for_vblank (display, drawable);
175 }
176 }
177
178 gdk_x11_surface_pre_damage (surface);
179
180 #ifdef HAVE_XDAMAGE
181 if (self->xdamage != 0 && _gdk_x11_surface_syncs_frames (surface))
182 {
183 g_assert (self->frame_fence == 0);
184
185 self->frame_fence = glFenceSync (GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
186
187 /* We consider the frame still getting painted until the GL operation is
188 * finished, and the window gets damage reported from the X server.
189 * It's only at this point the compositor can be sure it has full
190 * access to the new updates.
191 */
192 _gdk_x11_surface_set_frame_still_painting (surface, TRUE);
193 }
194 #endif
195
196 glXSwapBuffers (dpy, drawable);
197
198 if (self->do_frame_sync && display_x11->has_glx_video_sync)
199 glXGetVideoSyncSGI (&x11_surface->glx_frame_counter);
200 }
201
202 static gboolean
gdk_x11_gl_context_glx_clear_current(GdkGLContext * context)203 gdk_x11_gl_context_glx_clear_current (GdkGLContext *context)
204 {
205 GdkDisplay *display = gdk_gl_context_get_display (context);
206 Display *dpy = gdk_x11_display_get_xdisplay (display);
207
208 glXMakeContextCurrent (dpy, None, None, NULL);
209 return TRUE;
210 }
211
212 static gboolean
gdk_x11_gl_context_glx_make_current(GdkGLContext * context,gboolean surfaceless)213 gdk_x11_gl_context_glx_make_current (GdkGLContext *context,
214 gboolean surfaceless)
215
216 {
217 GdkX11GLContextGLX *self = GDK_X11_GL_CONTEXT_GLX (context);
218 GdkDisplay *display = gdk_gl_context_get_display (context);
219 Display *dpy = gdk_x11_display_get_xdisplay (display);
220 gboolean do_frame_sync = FALSE;
221 GdkSurface *surface;
222 GLXWindow drawable;
223
224 drawable = gdk_x11_gl_context_glx_get_drawable (self);
225
226 if (!surfaceless)
227 surface = gdk_gl_context_get_surface (context);
228 else
229 surface = GDK_X11_DISPLAY (display)->leader_gdk_surface;
230 drawable = gdk_x11_surface_get_glx_drawable (surface);
231
232 GDK_DISPLAY_NOTE (display, OPENGL,
233 g_message ("Making GLX context %p current to drawable %lu",
234 context, (unsigned long) drawable));
235
236 if (!glXMakeContextCurrent (dpy, drawable, drawable, self->glx_context))
237 return FALSE;
238
239 if (!surfaceless && GDK_X11_DISPLAY (display)->has_glx_swap_interval)
240 {
241 /* If the WM is compositing there is no particular need to delay
242 * the swap when drawing on the offscreen, rendering to the screen
243 * happens later anyway, and its up to the compositor to sync that
244 * to the vblank. */
245 do_frame_sync = ! gdk_display_is_composited (display);
246
247 if (do_frame_sync != self->do_frame_sync)
248 {
249 self->do_frame_sync = do_frame_sync;
250
251 if (do_frame_sync)
252 glXSwapIntervalSGI (1);
253 else
254 glXSwapIntervalSGI (0);
255 }
256 }
257
258 return TRUE;
259 }
260
261 static cairo_region_t *
gdk_x11_gl_context_glx_get_damage(GdkGLContext * context)262 gdk_x11_gl_context_glx_get_damage (GdkGLContext *context)
263 {
264 GdkDisplay *display = gdk_draw_context_get_display (GDK_DRAW_CONTEXT (context));
265 GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
266 Display *dpy = gdk_x11_display_get_xdisplay (display);
267 unsigned int buffer_age = 0;
268
269 if (display_x11->has_glx_buffer_age)
270 {
271 GdkX11GLContextGLX *self = GDK_X11_GL_CONTEXT_GLX (context);
272
273 gdk_gl_context_make_current (context);
274 glXQueryDrawable (dpy, gdk_x11_gl_context_glx_get_drawable (self),
275 GLX_BACK_BUFFER_AGE_EXT, &buffer_age);
276
277 switch (buffer_age)
278 {
279 case 1:
280 return cairo_region_create ();
281 break;
282
283 case 2:
284 if (context->old_updated_area[0])
285 return cairo_region_copy (context->old_updated_area[0]);
286 break;
287
288 case 3:
289 if (context->old_updated_area[0] &&
290 context->old_updated_area[1])
291 {
292 cairo_region_t *damage = cairo_region_copy (context->old_updated_area[0]);
293 cairo_region_union (damage, context->old_updated_area[1]);
294 return damage;
295 }
296 break;
297
298 default:
299 ;
300 }
301 }
302
303 return GDK_GL_CONTEXT_CLASS (gdk_x11_gl_context_glx_parent_class)->get_damage (context);
304 }
305
306 static GLXContext
create_gl3_context(GdkDisplay * display,GLXFBConfig config,GdkGLContext * share,int profile,int flags,int major,int minor)307 create_gl3_context (GdkDisplay *display,
308 GLXFBConfig config,
309 GdkGLContext *share,
310 int profile,
311 int flags,
312 int major,
313 int minor)
314 {
315 int attrib_list[] = {
316 GLX_CONTEXT_PROFILE_MASK_ARB, profile,
317 GLX_CONTEXT_MAJOR_VERSION_ARB, major,
318 GLX_CONTEXT_MINOR_VERSION_ARB, minor,
319 GLX_CONTEXT_FLAGS_ARB, flags,
320 None,
321 };
322 GLXContext res;
323
324 GdkX11GLContextGLX *share_glx = NULL;
325
326 if (share != NULL)
327 share_glx = GDK_X11_GL_CONTEXT_GLX (share);
328
329 gdk_x11_display_error_trap_push (display);
330
331 res = glXCreateContextAttribsARB (gdk_x11_display_get_xdisplay (display),
332 config,
333 share_glx != NULL ? share_glx->glx_context : NULL,
334 True,
335 attrib_list);
336
337 if (gdk_x11_display_error_trap_pop (display))
338 return NULL;
339
340 return res;
341 }
342
343 static GLXContext
create_legacy_context(GdkDisplay * display,GLXFBConfig config,GdkGLContext * share)344 create_legacy_context (GdkDisplay *display,
345 GLXFBConfig config,
346 GdkGLContext *share)
347 {
348 GdkX11GLContextGLX *share_glx = NULL;
349 GLXContext res;
350
351 if (share != NULL)
352 share_glx = GDK_X11_GL_CONTEXT_GLX (share);
353
354 gdk_x11_display_error_trap_push (display);
355
356 res = glXCreateNewContext (gdk_x11_display_get_xdisplay (display),
357 config,
358 GLX_RGBA_TYPE,
359 share_glx != NULL ? share_glx->glx_context : NULL,
360 TRUE);
361
362 if (gdk_x11_display_error_trap_pop (display))
363 return NULL;
364
365 return res;
366 }
367
368 #ifdef HAVE_XDAMAGE
369 static void
bind_context_for_frame_fence(GdkX11GLContextGLX * self)370 bind_context_for_frame_fence (GdkX11GLContextGLX *self)
371 {
372 GdkX11GLContextGLX *current_context_glx;
373 GLXContext current_glx_context = NULL;
374 GdkGLContext *current_context;
375 gboolean needs_binding = TRUE;
376
377 /* We don't care if the passed context is the current context,
378 * necessarily, but we do care that *some* context that can
379 * see the sync object is bound.
380 *
381 * If no context is bound at all, the GL dispatch layer will
382 * make glClientWaitSync() silently return 0.
383 */
384 current_glx_context = glXGetCurrentContext ();
385
386 if (current_glx_context == NULL)
387 goto out;
388
389 current_context = gdk_gl_context_get_current ();
390
391 if (current_context == NULL)
392 goto out;
393
394 current_context_glx = GDK_X11_GL_CONTEXT_GLX (current_context);
395
396 /* If the GLX context was changed out from under GDK, then
397 * that context may not be one that is able to see the
398 * created fence object.
399 */
400 if (current_context_glx->glx_context != current_glx_context)
401 goto out;
402
403 needs_binding = FALSE;
404
405 out:
406 if (needs_binding)
407 gdk_gl_context_make_current (GDK_GL_CONTEXT (self));
408 }
409
410 static void
finish_frame(GdkGLContext * context)411 finish_frame (GdkGLContext *context)
412 {
413 GdkX11GLContextGLX *context_glx = GDK_X11_GL_CONTEXT_GLX (context);
414 GdkSurface *surface = gdk_gl_context_get_surface (context);
415
416 if (context_glx->xdamage == 0)
417 return;
418
419 if (context_glx->frame_fence == 0)
420 return;
421
422 glDeleteSync (context_glx->frame_fence);
423 context_glx->frame_fence = 0;
424
425 _gdk_x11_surface_set_frame_still_painting (surface, FALSE);
426 }
427
428 static gboolean
on_gl_surface_xevent(GdkGLContext * context,XEvent * xevent,GdkX11Display * display_x11)429 on_gl_surface_xevent (GdkGLContext *context,
430 XEvent *xevent,
431 GdkX11Display *display_x11)
432 {
433 GdkX11GLContextGLX *context_glx = GDK_X11_GL_CONTEXT_GLX (context);
434 XDamageNotifyEvent *damage_xevent;
435
436 if (xevent->type != (display_x11->damage_event_base + XDamageNotify))
437 return FALSE;
438
439 damage_xevent = (XDamageNotifyEvent *) xevent;
440
441 if (damage_xevent->damage != context_glx->xdamage)
442 return FALSE;
443
444 if (context_glx->frame_fence)
445 {
446 GLenum wait_result;
447
448 bind_context_for_frame_fence (context_glx);
449
450 wait_result = glClientWaitSync (context_glx->frame_fence, 0, 0);
451
452 switch (wait_result)
453 {
454 /* We assume that if the fence has been signaled, that this damage
455 * event is the damage event that was triggered by the GL drawing
456 * associated with the fence. That's, technically, not necessarly
457 * always true. The X server could have generated damage for
458 * an unrelated event (say the size of the window changing), at
459 * just the right moment such that we're picking it up instead.
460 *
461 * We're choosing not to handle this edge case, but if it does ever
462 * happen in the wild, it could lead to slight underdrawing by
463 * the compositor for one frame. In the future, if we find out
464 * this edge case is noticeable, we can compensate by copying the
465 * painted region from gdk_x11_gl_context_end_frame and subtracting
466 * damaged areas from the copy as they come in. Once the copied
467 * region goes empty, we know that there won't be any underdraw,
468 * and can mark painting has finished. It's not worth the added
469 * complexity and resource usage to do this bookkeeping, however,
470 * unless the problem is practically visible.
471 */
472 case GL_ALREADY_SIGNALED:
473 case GL_CONDITION_SATISFIED:
474 case GL_WAIT_FAILED:
475 if (wait_result == GL_WAIT_FAILED)
476 g_warning ("failed to wait on GL fence associated with last swap buffers call");
477 finish_frame (context);
478 break;
479
480 /* We assume that if the fence hasn't been signaled, that this
481 * damage event is not the damage event that was triggered by the
482 * GL drawing associated with the fence. That's only true for
483 * the Nvidia vendor driver. When using open source drivers, damage
484 * is emitted immediately on swap buffers, before the fence ever
485 * has a chance to signal.
486 */
487 case GL_TIMEOUT_EXPIRED:
488 break;
489 default:
490 g_error ("glClientWaitSync returned unexpected result: %x", (guint) wait_result);
491 }
492 }
493
494 return FALSE;
495 }
496
497 static void
on_surface_state_changed(GdkGLContext * context)498 on_surface_state_changed (GdkGLContext *context)
499 {
500 GdkSurface *surface = gdk_gl_context_get_surface (context);
501
502 if (GDK_SURFACE_IS_MAPPED (surface))
503 return;
504
505 /* If we're about to withdraw the surface, then we don't care if the frame is
506 * still getting rendered by the GPU. The compositor is going to remove the surface
507 * from the scene anyway, so wrap up the frame.
508 */
509 finish_frame (context);
510 }
511 #endif
512
513 static gboolean
gdk_x11_gl_context_glx_realize(GdkGLContext * context,GError ** error)514 gdk_x11_gl_context_glx_realize (GdkGLContext *context,
515 GError **error)
516 {
517 GdkX11Display *display_x11;
518 GdkDisplay *display;
519 GdkX11GLContextGLX *context_glx;
520 Display *dpy;
521 GdkSurface *surface;
522 GdkGLContext *share;
523 gboolean debug_bit, compat_bit, legacy_bit, es_bit;
524 int major, minor, flags;
525
526 display = gdk_gl_context_get_display (context);
527 dpy = gdk_x11_display_get_xdisplay (display);
528 context_glx = GDK_X11_GL_CONTEXT_GLX (context);
529 display_x11 = GDK_X11_DISPLAY (display);
530 share = gdk_display_get_gl_context (display);
531 surface = gdk_gl_context_get_surface (context);
532
533 gdk_gl_context_get_required_version (context, &major, &minor);
534 debug_bit = gdk_gl_context_get_debug_enabled (context);
535 compat_bit = gdk_gl_context_get_forward_compatible (context);
536
537 /* If there is no glXCreateContextAttribsARB() then we default to legacy */
538 legacy_bit = !display_x11->has_glx_create_context || GDK_DISPLAY_DEBUG_CHECK (display, GL_LEGACY);
539
540 es_bit = (GDK_DISPLAY_DEBUG_CHECK (display, GL_GLES) || (share != NULL && gdk_gl_context_get_use_es (share))) &&
541 (display_x11->has_glx_create_context && display_x11->has_glx_create_es2_context);
542
543 /* We cannot share legacy contexts with core profile ones, so the
544 * shared context is the one that decides if we're going to create
545 * a legacy context or not.
546 */
547 if (share != NULL && gdk_gl_context_is_legacy (share))
548 legacy_bit = TRUE;
549
550 flags = 0;
551 if (debug_bit)
552 flags |= GLX_CONTEXT_DEBUG_BIT_ARB;
553 if (compat_bit)
554 flags |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
555
556 GDK_DISPLAY_NOTE (display, OPENGL,
557 g_message ("Creating GLX context (GL version:%d.%d, debug:%s, forward:%s, legacy:%s, es:%s)",
558 major, minor,
559 debug_bit ? "yes" : "no",
560 compat_bit ? "yes" : "no",
561 legacy_bit ? "yes" : "no",
562 es_bit ? "yes" : "no"));
563
564 /* If we have access to GLX_ARB_create_context_profile then we can ask for
565 * a compatibility profile; if we don't, then we have to fall back to the
566 * old GLX 1.3 API.
567 */
568 if (legacy_bit && !GDK_X11_DISPLAY (display)->has_glx_create_context)
569 {
570 GDK_DISPLAY_NOTE (display, OPENGL, g_message ("Creating legacy GL context on request"));
571 context_glx->glx_context = create_legacy_context (display, display_x11->glx_config, share);
572 }
573 else
574 {
575 int profile;
576
577 if (es_bit)
578 profile = GLX_CONTEXT_ES2_PROFILE_BIT_EXT;
579 else
580 profile = legacy_bit ? GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB
581 : GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
582
583 /* We need to tweak the version, otherwise we may end up requesting
584 * a compatibility context with a minimum version of 3.2, which is
585 * an error
586 */
587 if (legacy_bit)
588 {
589 major = 3;
590 minor = 0;
591 }
592
593 GDK_DISPLAY_NOTE (display, OPENGL, g_message ("Creating GL3 context"));
594 context_glx->glx_context = create_gl3_context (display,
595 display_x11->glx_config,
596 share,
597 profile, flags, major, minor);
598
599 /* Fall back to legacy in case the GL3 context creation failed */
600 if (context_glx->glx_context == NULL)
601 {
602 GDK_DISPLAY_NOTE (display, OPENGL, g_message ("Creating fallback legacy context"));
603 context_glx->glx_context = create_legacy_context (display, display_x11->glx_config, share);
604 legacy_bit = TRUE;
605 es_bit = FALSE;
606 }
607 }
608
609 if (context_glx->glx_context == NULL)
610 {
611 g_set_error_literal (error, GDK_GL_ERROR,
612 GDK_GL_ERROR_NOT_AVAILABLE,
613 _("Unable to create a GL context"));
614 return FALSE;
615 }
616
617 /* Ensure that any other context is created with a legacy bit set */
618 gdk_gl_context_set_is_legacy (context, legacy_bit);
619
620 /* Ensure that any other context is created with an ES bit set */
621 gdk_gl_context_set_use_es (context, es_bit);
622
623 GDK_DISPLAY_NOTE (display, OPENGL,
624 g_message ("Realized GLX context[%p], %s, version: %d.%d",
625 context_glx->glx_context,
626 glXIsDirect (dpy, context_glx->glx_context) ? "direct" : "indirect",
627 display_x11->glx_version / 10,
628 display_x11->glx_version % 10));
629
630 #ifdef HAVE_XDAMAGE
631 if (display_x11->have_damage &&
632 display_x11->has_async_glx_swap_buffers)
633 {
634 gdk_x11_display_error_trap_push (display);
635 context_glx->xdamage = XDamageCreate (dpy,
636 gdk_x11_surface_get_xid (surface),
637 XDamageReportRawRectangles);
638 if (gdk_x11_display_error_trap_pop (display))
639 {
640 context_glx->xdamage = 0;
641 }
642 else
643 {
644 g_signal_connect_object (G_OBJECT (display),
645 "xevent",
646 G_CALLBACK (on_gl_surface_xevent),
647 context,
648 G_CONNECT_SWAPPED);
649 g_signal_connect_object (G_OBJECT (surface),
650 "notify::state",
651 G_CALLBACK (on_surface_state_changed),
652 context,
653 G_CONNECT_SWAPPED);
654
655 }
656 }
657 #endif
658
659 return TRUE;
660 }
661
662 static void
gdk_x11_gl_context_glx_dispose(GObject * gobject)663 gdk_x11_gl_context_glx_dispose (GObject *gobject)
664 {
665 GdkX11GLContextGLX *context_glx = GDK_X11_GL_CONTEXT_GLX (gobject);
666
667 #ifdef HAVE_XDAMAGE
668 context_glx->xdamage = 0;
669 #endif
670
671 if (context_glx->glx_context != NULL)
672 {
673 GdkGLContext *context = GDK_GL_CONTEXT (gobject);
674 GdkDisplay *display = gdk_gl_context_get_display (context);
675 Display *dpy = gdk_x11_display_get_xdisplay (display);
676
677 if (glXGetCurrentContext () == context_glx->glx_context)
678 glXMakeContextCurrent (dpy, None, None, NULL);
679
680 GDK_DISPLAY_NOTE (display, OPENGL, g_message ("Destroying GLX context"));
681 glXDestroyContext (dpy, context_glx->glx_context);
682 context_glx->glx_context = NULL;
683 }
684
685 G_OBJECT_CLASS (gdk_x11_gl_context_glx_parent_class)->dispose (gobject);
686 }
687
688 static void
gdk_x11_gl_context_glx_class_init(GdkX11GLContextGLXClass * klass)689 gdk_x11_gl_context_glx_class_init (GdkX11GLContextGLXClass *klass)
690 {
691 GdkGLContextClass *context_class = GDK_GL_CONTEXT_CLASS (klass);
692 GdkDrawContextClass *draw_context_class = GDK_DRAW_CONTEXT_CLASS (klass);
693 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
694
695 context_class->backend_type = GDK_GL_GLX;
696
697 context_class->realize = gdk_x11_gl_context_glx_realize;
698 context_class->make_current = gdk_x11_gl_context_glx_make_current;
699 context_class->clear_current = gdk_x11_gl_context_glx_clear_current;
700 context_class->get_damage = gdk_x11_gl_context_glx_get_damage;
701
702 draw_context_class->end_frame = gdk_x11_gl_context_glx_end_frame;
703
704 gobject_class->dispose = gdk_x11_gl_context_glx_dispose;
705 }
706
707 static void
gdk_x11_gl_context_glx_init(GdkX11GLContextGLX * self)708 gdk_x11_gl_context_glx_init (GdkX11GLContextGLX *self)
709 {
710 self->do_frame_sync = TRUE;
711 }
712
713 static gboolean
visual_is_rgba(XVisualInfo * visinfo)714 visual_is_rgba (XVisualInfo *visinfo)
715 {
716 return
717 visinfo->depth == 32 &&
718 visinfo->visual->red_mask == 0xff0000 &&
719 visinfo->visual->green_mask == 0x00ff00 &&
720 visinfo->visual->blue_mask == 0x0000ff;
721 }
722
723 #define MAX_GLX_ATTRS 30
724
725 static gboolean
gdk_x11_display_create_glx_config(GdkX11Display * self,Visual ** out_visual,int * out_depth,GError ** error)726 gdk_x11_display_create_glx_config (GdkX11Display *self,
727 Visual **out_visual,
728 int *out_depth,
729 GError **error)
730 {
731 GdkDisplay *display = GDK_DISPLAY (self);
732 Display *dpy = gdk_x11_display_get_xdisplay (display);
733 int attrs[MAX_GLX_ATTRS];
734 GLXFBConfig *configs;
735 int count;
736 enum {
737 NO_VISUAL_FOUND,
738 WITH_MULTISAMPLING,
739 WITH_STENCIL_AND_DEPTH_BUFFER,
740 NO_ALPHA,
741 NO_ALPHA_VISUAL,
742 PERFECT
743 } best_features;
744 int i = 0;
745
746 attrs[i++] = GLX_DRAWABLE_TYPE;
747 attrs[i++] = GLX_WINDOW_BIT;
748
749 attrs[i++] = GLX_RENDER_TYPE;
750 attrs[i++] = GLX_RGBA_BIT;
751
752 attrs[i++] = GLX_DOUBLEBUFFER;
753 attrs[i++] = GL_TRUE;
754
755 attrs[i++] = GLX_RED_SIZE;
756 attrs[i++] = 1;
757 attrs[i++] = GLX_GREEN_SIZE;
758 attrs[i++] = 1;
759 attrs[i++] = GLX_BLUE_SIZE;
760 attrs[i++] = 1;
761 attrs[i++] = GLX_ALPHA_SIZE;
762 attrs[i++] = 1;
763
764 attrs[i++] = None;
765 g_assert (i < MAX_GLX_ATTRS);
766
767 configs = glXChooseFBConfig (dpy, DefaultScreen (dpy), attrs, &count);
768 if (configs == NULL || count == 0)
769 {
770 g_set_error_literal (error, GDK_GL_ERROR,
771 GDK_GL_ERROR_NOT_AVAILABLE,
772 _("No GLX configurations available"));
773 return FALSE;
774 }
775
776 best_features = NO_VISUAL_FOUND;
777
778 for (i = 0; i < count; i++)
779 {
780 XVisualInfo *visinfo;
781 int tmp;
782
783 visinfo = glXGetVisualFromFBConfig (dpy, configs[i]);
784 if (visinfo == NULL)
785 continue;
786
787 if (glXGetFBConfigAttrib (dpy, configs[i], GLX_SAMPLE_BUFFERS_ARB, &tmp) != Success || tmp != 0)
788 {
789 if (best_features < WITH_MULTISAMPLING)
790 {
791 GDK_NOTE (OPENGL, g_message ("Best GLX config is %u for visual 0x%lX with multisampling", i, visinfo->visualid));
792 best_features = WITH_MULTISAMPLING;
793 *out_visual = visinfo->visual;
794 *out_depth = visinfo->depth;
795 self->glx_config = configs[i];
796 }
797 XFree (visinfo);
798 continue;
799 }
800
801 if (glXGetFBConfigAttrib (dpy, configs[i], GLX_DEPTH_SIZE, &tmp) != Success || tmp != 0 ||
802 glXGetFBConfigAttrib (dpy, configs[i], GLX_STENCIL_SIZE, &tmp) != Success || tmp != 0)
803 {
804 if (best_features < WITH_STENCIL_AND_DEPTH_BUFFER)
805 {
806 GDK_NOTE (OPENGL, g_message ("Best GLX config is %u for visual 0x%lX with a stencil or depth buffer", i, visinfo->visualid));
807 best_features = WITH_STENCIL_AND_DEPTH_BUFFER;
808 *out_visual = visinfo->visual;
809 *out_depth = visinfo->depth;
810 self->glx_config = configs[i];
811 }
812 XFree (visinfo);
813 continue;
814 }
815
816 if (!visual_is_rgba (visinfo))
817 {
818 if (best_features < NO_ALPHA_VISUAL)
819 {
820 GDK_NOTE (OPENGL, g_message ("Best GLX config is %u for visual 0x%lX with no RGBA Visual", i, visinfo->visualid));
821 best_features = NO_ALPHA_VISUAL;
822 *out_visual = visinfo->visual;
823 *out_depth = visinfo->depth;
824 self->glx_config = configs[i];
825 }
826 XFree (visinfo);
827 continue;
828 }
829
830 GDK_NOTE (OPENGL, g_message ("GLX config %u for visual 0x%lX is the perfect choice", i, visinfo->visualid));
831 best_features = PERFECT;
832 *out_visual = visinfo->visual;
833 *out_depth = visinfo->depth;
834 self->glx_config = configs[i];
835 XFree (visinfo);
836 break;
837 }
838
839 XFree (configs);
840
841 if (best_features == NO_VISUAL_FOUND)
842 {
843 g_set_error_literal (error, GDK_GL_ERROR,
844 GDK_GL_ERROR_NOT_AVAILABLE,
845 _("No GLX configuration with required features found"));
846 return FALSE;
847 }
848
849 return TRUE;
850 }
851
852 #undef MAX_GLX_ATTRS
853
854 /**
855 * gdk_x11_display_get_glx_version:
856 * @display: (type GdkX11Display): a `GdkDisplay`
857 * @major: (out): return location for the GLX major version
858 * @minor: (out): return location for the GLX minor version
859 *
860 * Retrieves the version of the GLX implementation.
861 *
862 * Returns: %TRUE if GLX is available
863 */
864 gboolean
gdk_x11_display_get_glx_version(GdkDisplay * display,int * major,int * minor)865 gdk_x11_display_get_glx_version (GdkDisplay *display,
866 int *major,
867 int *minor)
868 {
869 g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
870
871 if (!GDK_IS_X11_DISPLAY (display))
872 return FALSE;
873
874 GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
875
876 if (display_x11->glx_config == NULL)
877 return FALSE;
878
879 if (major != NULL)
880 *major = display_x11->glx_version / 10;
881 if (minor != NULL)
882 *minor = display_x11->glx_version % 10;
883
884 return TRUE;
885 }
886
887 /*< private >
888 * gdk_x11_display_init_glx:
889 * @display_x11: an X11 display that has not been inited yet.
890 * @out_visual: set to the Visual to be used with the returned config
891 * @out_depth: set to the depth to be used with the returned config
892 * @error: Return location for error
893 *
894 * Initializes the cached GLX state for the given @screen.
895 *
896 * This function must be called exactly once during initialization.
897 *
898 * Returns: %TRUE if GLX was initialized
899 */
900 gboolean
gdk_x11_display_init_glx(GdkX11Display * display_x11,Visual ** out_visual,int * out_depth,GError ** error)901 gdk_x11_display_init_glx (GdkX11Display *display_x11,
902 Visual **out_visual,
903 int *out_depth,
904 GError **error)
905 {
906 GdkDisplay *display = GDK_DISPLAY (display_x11);
907 Display *dpy;
908 int screen_num;
909
910 if (!gdk_gl_backend_can_be_used (GDK_GL_GLX, error))
911 return FALSE;
912
913 dpy = gdk_x11_display_get_xdisplay (display);
914
915 if (!epoxy_has_glx (dpy))
916 {
917 g_set_error_literal (error, GDK_GL_ERROR,
918 GDK_GL_ERROR_NOT_AVAILABLE,
919 _("GLX is not supported"));
920 return FALSE;
921 }
922
923 screen_num = display_x11->screen->screen_num;
924
925 display_x11->glx_version = epoxy_glx_version (dpy, screen_num);
926
927 display_x11->has_glx_create_context =
928 epoxy_has_glx_extension (dpy, screen_num, "GLX_ARB_create_context_profile");
929 display_x11->has_glx_create_es2_context =
930 epoxy_has_glx_extension (dpy, screen_num, "GLX_EXT_create_context_es2_profile");
931 display_x11->has_glx_swap_interval =
932 epoxy_has_glx_extension (dpy, screen_num, "GLX_SGI_swap_control");
933 display_x11->has_glx_texture_from_pixmap =
934 epoxy_has_glx_extension (dpy, screen_num, "GLX_EXT_texture_from_pixmap");
935 display_x11->has_glx_video_sync =
936 epoxy_has_glx_extension (dpy, screen_num, "GLX_SGI_video_sync");
937 display_x11->has_glx_buffer_age =
938 epoxy_has_glx_extension (dpy, screen_num, "GLX_EXT_buffer_age");
939 display_x11->has_glx_sync_control =
940 epoxy_has_glx_extension (dpy, screen_num, "GLX_OML_sync_control");
941 display_x11->has_glx_multisample =
942 epoxy_has_glx_extension (dpy, screen_num, "GLX_ARB_multisample");
943 display_x11->has_glx_visual_rating =
944 epoxy_has_glx_extension (dpy, screen_num, "GLX_EXT_visual_rating");
945
946 if (g_strcmp0 (glXGetClientString (dpy, GLX_VENDOR), "NVIDIA Corporation") == 0)
947 {
948 Atom type;
949 int format;
950 gulong nitems;
951 gulong bytes_after;
952 guchar *data = NULL;
953
954 /* With the mesa based drivers, we can safely assume the compositor can
955 * access the updated surface texture immediately after glXSwapBuffers is
956 * run, because the kernel ensures there is an implicit synchronization
957 * operation upon texture access. This is not true with the Nvidia vendor
958 * driver. There is a window of time after glXSwapBuffers before other
959 * processes can see the updated drawing. We need to take special care,
960 * in that case, to defer telling the compositor our latest frame is
961 * ready until after the GPU has completed all issued commands related
962 * to the frame, and that the X server says the frame has been drawn.
963 *
964 * As this can cause deadlocks, we want to make sure to only enable it for Xorg,
965 * but not for XWayland, Xnest or whatever other X servers exist.
966 */
967
968 gdk_x11_display_error_trap_push (display);
969 if (XGetWindowProperty (dpy, DefaultRootWindow (dpy),
970 gdk_x11_get_xatom_by_name_for_display (display, "XFree86_VT"),
971 0, 1, False, AnyPropertyType,
972 &type, &format, &nitems, &bytes_after, &data) == Success)
973 {
974 if (type != None)
975 display_x11->has_async_glx_swap_buffers = TRUE;
976 }
977 gdk_x11_display_error_trap_pop_ignored (display);
978
979 if (data)
980 XFree (data);
981 }
982
983 if (!gdk_x11_display_create_glx_config (display_x11, out_visual, out_depth, error))
984 return FALSE;
985
986 GDK_DISPLAY_NOTE (display, OPENGL,
987 g_message ("GLX version %d.%d found\n"
988 " - Vendor: %s\n"
989 " - Checked extensions:\n"
990 "\t* GLX_ARB_create_context_profile: %s\n"
991 "\t* GLX_EXT_create_context_es2_profile: %s\n"
992 "\t* GLX_SGI_swap_control: %s\n"
993 "\t* GLX_EXT_texture_from_pixmap: %s\n"
994 "\t* GLX_SGI_video_sync: %s\n"
995 "\t* GLX_EXT_buffer_age: %s\n"
996 "\t* GLX_OML_sync_control: %s"
997 "\t* GLX_ARB_multisample: %s"
998 "\t* GLX_EXT_visual_rating: %s",
999 display_x11->glx_version / 10,
1000 display_x11->glx_version % 10,
1001 glXGetClientString (dpy, GLX_VENDOR),
1002 display_x11->has_glx_create_context ? "yes" : "no",
1003 display_x11->has_glx_create_es2_context ? "yes" : "no",
1004 display_x11->has_glx_swap_interval ? "yes" : "no",
1005 display_x11->has_glx_texture_from_pixmap ? "yes" : "no",
1006 display_x11->has_glx_video_sync ? "yes" : "no",
1007 display_x11->has_glx_buffer_age ? "yes" : "no",
1008 display_x11->has_glx_sync_control ? "yes" : "no",
1009 display_x11->has_glx_multisample ? "yes" : "no",
1010 display_x11->has_glx_visual_rating ? "yes" : "no"));
1011
1012 return TRUE;
1013 }
1014