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

source code of gtk/gdk/x11/gdkglcontext-glx.c