1 /* GDK - The GIMP Drawing Kit
2 *
3 * gdkglcontext.c: GL context abstraction
4 *
5 * Copyright © 2014 Emmanuele Bassi
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 /**
22 * GdkGLContext:
23 *
24 * `GdkGLContext` is an object representing a platform-specific
25 * OpenGL draw context.
26 *
27 * `GdkGLContext`s are created for a surface using
28 * [method@Gdk.Surface.create_gl_context], and the context will match
29 * the the characteristics of the surface.
30 *
31 * A `GdkGLContext` is not tied to any particular normal framebuffer.
32 * For instance, it cannot draw to the surface back buffer. The GDK
33 * repaint system is in full control of the painting to that. Instead,
34 * you can create render buffers or textures and use [func@cairo_draw_from_gl]
35 * in the draw function of your widget to draw them. Then GDK will handle
36 * the integration of your rendering with that of other widgets.
37 *
38 * Support for `GdkGLContext` is platform-specific and context creation
39 * can fail, returning %NULL context.
40 *
41 * A `GdkGLContext` has to be made "current" in order to start using
42 * it, otherwise any OpenGL call will be ignored.
43 *
44 * ## Creating a new OpenGL context
45 *
46 * In order to create a new `GdkGLContext` instance you need a `GdkSurface`,
47 * which you typically get during the realize call of a widget.
48 *
49 * A `GdkGLContext` is not realized until either [method@Gdk.GLContext.make_current]
50 * or [method@Gdk.GLContext.realize] is called. It is possible to specify
51 * details of the GL context like the OpenGL version to be used, or whether
52 * the GL context should have extra state validation enabled after calling
53 * [method@Gdk.Surface.create_gl_context] by calling [method@Gdk.GLContext.realize].
54 * If the realization fails you have the option to change the settings of
55 * the `GdkGLContext` and try again.
56 *
57 * ## Using a GdkGLContext
58 *
59 * You will need to make the `GdkGLContext` the current context before issuing
60 * OpenGL calls; the system sends OpenGL commands to whichever context is current.
61 * It is possible to have multiple contexts, so you always need to ensure that
62 * the one which you want to draw with is the current one before issuing commands:
63 *
64 * ```c
65 * gdk_gl_context_make_current (context);
66 * ```
67 *
68 * You can now perform your drawing using OpenGL commands.
69 *
70 * You can check which `GdkGLContext` is the current one by using
71 * [func@Gdk.GLContext.get_current]; you can also unset any `GdkGLContext`
72 * that is currently set by calling [func@Gdk.GLContext.clear_current].
73 */
74
75 #include "config.h"
76
77 #include "gdkglcontextprivate.h"
78
79 #include "gdkdebug.h"
80 #include "gdkdisplayprivate.h"
81 #include "gdkinternals.h"
82 #include "gdkintl.h"
83 #include "gdkmemorytextureprivate.h"
84
85 #include "gdk-private.h"
86
87 #ifdef GDK_WINDOWING_WIN32
88 # include "gdk/win32/gdkwin32.h"
89 #endif
90
91 #include <epoxy/gl.h>
92
93 typedef struct {
94 int major;
95 int minor;
96 int gl_version;
97
98 guint realized : 1;
99 guint use_texture_rectangle : 1;
100 guint has_khr_debug : 1;
101 guint use_khr_debug : 1;
102 guint has_unpack_subimage : 1;
103 guint has_debug_output : 1;
104 guint extensions_checked : 1;
105 guint debug_enabled : 1;
106 guint forward_compatible : 1;
107 guint is_legacy : 1;
108
109 int use_es;
110
111 int max_debug_label_length;
112
113 GdkGLContextPaintData *paint_data;
114 } GdkGLContextPrivate;
115
116 enum {
117 PROP_0,
118
119 PROP_SHARED_CONTEXT,
120
121 LAST_PROP
122 };
123
124 static GParamSpec *obj_pspecs[LAST_PROP] = { NULL, };
125
126 G_DEFINE_QUARK (gdk-gl-error-quark, gdk_gl_error)
127
128 G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GdkGLContext, gdk_gl_context, GDK_TYPE_DRAW_CONTEXT)
129
130 typedef struct _MaskedContext MaskedContext;
131
132 static inline MaskedContext *
mask_context(GdkGLContext * context,gboolean surfaceless)133 mask_context (GdkGLContext *context,
134 gboolean surfaceless)
135 {
136 return (MaskedContext *) GSIZE_TO_POINTER (GPOINTER_TO_SIZE (context) | (surfaceless ? 1 : 0));
137 }
138
139 static inline GdkGLContext *
unmask_context(MaskedContext * mask)140 unmask_context (MaskedContext *mask)
141 {
142 return GDK_GL_CONTEXT (GSIZE_TO_POINTER (GPOINTER_TO_SIZE (mask) & ~(gsize) 1));
143 }
144
145 static void
unref_unmasked(gpointer data)146 unref_unmasked (gpointer data)
147 {
148 g_object_unref (unmask_context (data));
149 }
150
151 static GPrivate thread_current_context = G_PRIVATE_INIT (unref_unmasked);
152
153 static void
gdk_gl_context_clear_old_updated_area(GdkGLContext * context)154 gdk_gl_context_clear_old_updated_area (GdkGLContext *context)
155 {
156 int i;
157
158 for (i = 0; i < 2; i++)
159 {
160 g_clear_pointer (&context->old_updated_area[i], cairo_region_destroy);
161 }
162 }
163
164 static void
gdk_gl_context_dispose(GObject * gobject)165 gdk_gl_context_dispose (GObject *gobject)
166 {
167 GdkGLContext *context = GDK_GL_CONTEXT (gobject);
168 MaskedContext *current;
169
170 gdk_gl_context_clear_old_updated_area (context);
171
172 current = g_private_get (&thread_current_context);
173 if (unmask_context (current) == context)
174 g_private_replace (&thread_current_context, NULL);
175
176 G_OBJECT_CLASS (gdk_gl_context_parent_class)->dispose (gobject);
177 }
178
179 static void
gdk_gl_context_finalize(GObject * gobject)180 gdk_gl_context_finalize (GObject *gobject)
181 {
182 GdkGLContext *context = GDK_GL_CONTEXT (gobject);
183 GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
184
185 g_clear_pointer (&priv->paint_data, g_free);
186 G_OBJECT_CLASS (gdk_gl_context_parent_class)->finalize (gobject);
187 }
188
189 static void
gdk_gl_context_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * pspec)190 gdk_gl_context_set_property (GObject *gobject,
191 guint prop_id,
192 const GValue *value,
193 GParamSpec *pspec)
194 {
195 switch (prop_id)
196 {
197 case PROP_SHARED_CONTEXT:
198 g_assert (g_value_get_object (value) == NULL);
199 break;
200
201 default:
202 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
203 }
204 }
205
206 static void
gdk_gl_context_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * pspec)207 gdk_gl_context_get_property (GObject *gobject,
208 guint prop_id,
209 GValue *value,
210 GParamSpec *pspec)
211 {
212 switch (prop_id)
213 {
214 case PROP_SHARED_CONTEXT:
215 g_value_set_object (value, NULL);
216 break;
217
218 default:
219 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
220 }
221 }
222
223 void
gdk_gl_context_upload_texture(GdkGLContext * context,const guchar * data,int width,int height,int stride,GdkMemoryFormat data_format,guint texture_target)224 gdk_gl_context_upload_texture (GdkGLContext *context,
225 const guchar *data,
226 int width,
227 int height,
228 int stride,
229 GdkMemoryFormat data_format,
230 guint texture_target)
231 {
232 GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
233 guchar *copy = NULL;
234 guint gl_format;
235 guint gl_type;
236 guint bpp;
237
238 g_return_if_fail (GDK_IS_GL_CONTEXT (context));
239
240 if (priv->use_es)
241 {
242 /* GLES only supports rgba, so convert if necessary */
243 if (data_format != GDK_MEMORY_R8G8B8A8_PREMULTIPLIED)
244 {
245 copy = g_malloc (width * height * 4);
246 gdk_memory_convert (copy, width * 4,
247 GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
248 data, stride, data_format,
249 width, height);
250 stride = width * 4;
251 data = copy;
252 }
253
254 bpp = 4;
255 gl_format = GL_RGBA;
256 gl_type = GL_UNSIGNED_BYTE;
257 }
258 else
259 {
260 if (data_format == GDK_MEMORY_DEFAULT) /* Cairo surface format */
261 {
262 gl_format = GL_BGRA;
263 gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
264 bpp = 4;
265 }
266 else if (data_format == GDK_MEMORY_R8G8B8) /* Pixmap non-alpha data */
267 {
268 gl_format = GL_RGB;
269 gl_type = GL_UNSIGNED_BYTE;
270 bpp = 3;
271 }
272 else if (data_format == GDK_MEMORY_B8G8R8)
273 {
274 gl_format = GL_BGR;
275 gl_type = GL_UNSIGNED_BYTE;
276 bpp = 3;
277 }
278 else /* Fall-back, convert to cairo-surface-format */
279 {
280 copy = g_malloc (width * height * 4);
281 gdk_memory_convert (copy, width * 4,
282 GDK_MEMORY_DEFAULT,
283 data, stride, data_format,
284 width, height);
285 stride = width * 4;
286 bpp = 4;
287 data = copy;
288 gl_format = GL_BGRA;
289 gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
290 }
291 }
292
293 /* GL_UNPACK_ROW_LENGTH is available on desktop GL, OpenGL ES >= 3.0, or if
294 * the GL_EXT_unpack_subimage extension for OpenGL ES 2.0 is available
295 */
296 if (stride == width * bpp)
297 {
298 glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
299
300 glTexImage2D (texture_target, 0, GL_RGBA, width, height, 0, gl_format, gl_type, data);
301 glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
302 }
303 else if ((!priv->use_es ||
304 (priv->use_es && (priv->gl_version >= 30 || priv->has_unpack_subimage))))
305 {
306 glPixelStorei (GL_UNPACK_ROW_LENGTH, stride / bpp);
307
308 glTexImage2D (texture_target, 0, GL_RGBA, width, height, 0, gl_format, gl_type, data);
309
310 glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
311 }
312 else
313 {
314 int i;
315 glTexImage2D (texture_target, 0, GL_RGBA, width, height, 0, gl_format, gl_type, NULL);
316 for (i = 0; i < height; i++)
317 glTexSubImage2D (texture_target, 0, 0, i, width, 1, gl_format, gl_type, data + (i * stride));
318 }
319
320 g_free (copy);
321 }
322
323 static gboolean
gdk_gl_context_real_realize(GdkGLContext * self,GError ** error)324 gdk_gl_context_real_realize (GdkGLContext *self,
325 GError **error)
326 {
327 g_set_error_literal (error, GDK_GL_ERROR, GDK_GL_ERROR_NOT_AVAILABLE,
328 "The current backend does not support OpenGL");
329
330 return FALSE;
331 }
332
333 static cairo_region_t *
gdk_gl_context_real_get_damage(GdkGLContext * context)334 gdk_gl_context_real_get_damage (GdkGLContext *context)
335 {
336 GdkSurface *surface = gdk_draw_context_get_surface (GDK_DRAW_CONTEXT (context));
337
338 return cairo_region_create_rectangle (&(GdkRectangle) {
339 0, 0,
340 gdk_surface_get_width (surface),
341 gdk_surface_get_height (surface)
342 });
343 }
344
345 static gboolean
gdk_gl_context_real_is_shared(GdkGLContext * self,GdkGLContext * other)346 gdk_gl_context_real_is_shared (GdkGLContext *self,
347 GdkGLContext *other)
348 {
349 if (gdk_draw_context_get_display (GDK_DRAW_CONTEXT (self)) != gdk_draw_context_get_display (GDK_DRAW_CONTEXT (other)))
350 return FALSE;
351
352 /* XXX: Should we check es or legacy here? */
353
354 return TRUE;
355 }
356
357 static void
gdk_gl_context_real_begin_frame(GdkDrawContext * draw_context,cairo_region_t * region)358 gdk_gl_context_real_begin_frame (GdkDrawContext *draw_context,
359 cairo_region_t *region)
360 {
361 GdkGLContext *context = GDK_GL_CONTEXT (draw_context);
362 GdkSurface *surface;
363 cairo_region_t *damage;
364 int ww, wh;
365
366 damage = GDK_GL_CONTEXT_GET_CLASS (context)->get_damage (context);
367
368 if (context->old_updated_area[1])
369 cairo_region_destroy (context->old_updated_area[1]);
370 context->old_updated_area[1] = context->old_updated_area[0];
371 context->old_updated_area[0] = cairo_region_copy (region);
372
373 cairo_region_union (region, damage);
374 cairo_region_destroy (damage);
375
376 surface = gdk_draw_context_get_surface (draw_context);
377 ww = gdk_surface_get_width (surface) * gdk_surface_get_scale_factor (surface);
378 wh = gdk_surface_get_height (surface) * gdk_surface_get_scale_factor (surface);
379
380 gdk_gl_context_make_current (context);
381
382 /* Initial setup */
383 glClearColor (0.0f, 0.0f, 0.0f, 0.0f);
384 glDisable (GL_DEPTH_TEST);
385 glDisable (GL_BLEND);
386 glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
387
388 glViewport (0, 0, ww, wh);
389 }
390
391 static void
gdk_gl_context_real_end_frame(GdkDrawContext * draw_context,cairo_region_t * painted)392 gdk_gl_context_real_end_frame (GdkDrawContext *draw_context,
393 cairo_region_t *painted)
394 {
395 }
396
397 static void
gdk_gl_context_surface_resized(GdkDrawContext * draw_context)398 gdk_gl_context_surface_resized (GdkDrawContext *draw_context)
399 {
400 GdkGLContext *context = GDK_GL_CONTEXT (draw_context);
401
402 gdk_gl_context_clear_old_updated_area (context);
403 }
404
405 static void
gdk_gl_context_class_init(GdkGLContextClass * klass)406 gdk_gl_context_class_init (GdkGLContextClass *klass)
407 {
408 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
409 GdkDrawContextClass *draw_context_class = GDK_DRAW_CONTEXT_CLASS (klass);
410
411 klass->realize = gdk_gl_context_real_realize;
412 klass->get_damage = gdk_gl_context_real_get_damage;
413 klass->is_shared = gdk_gl_context_real_is_shared;
414
415 draw_context_class->begin_frame = gdk_gl_context_real_begin_frame;
416 draw_context_class->end_frame = gdk_gl_context_real_end_frame;
417 draw_context_class->surface_resized = gdk_gl_context_surface_resized;
418
419 /**
420 * GdkGLContext:shared-context: (attributes org.gtk.Property.get=gdk_gl_context_get_shared_context)
421 *
422 * Always %NULL
423 *
424 * As many contexts can share data now and no single shared context exists
425 * anymore, this function has been deprecated and now always returns %NULL.
426 *
427 * Deprecated: 4.4: Use [method@Gdk.GLContext.is_shared] to check if contexts
428 * can be shared.
429 */
430 obj_pspecs[PROP_SHARED_CONTEXT] =
431 g_param_spec_object ("shared-context",
432 P_("Shared context"),
433 P_("The GL context this context shares data with"),
434 GDK_TYPE_GL_CONTEXT,
435 G_PARAM_READWRITE |
436 G_PARAM_CONSTRUCT_ONLY |
437 G_PARAM_STATIC_STRINGS |
438 G_PARAM_DEPRECATED);
439
440 gobject_class->set_property = gdk_gl_context_set_property;
441 gobject_class->get_property = gdk_gl_context_get_property;
442 gobject_class->dispose = gdk_gl_context_dispose;
443 gobject_class->finalize = gdk_gl_context_finalize;
444
445 g_object_class_install_properties (gobject_class, LAST_PROP, obj_pspecs);
446 }
447
448 static void
gdk_gl_context_init(GdkGLContext * self)449 gdk_gl_context_init (GdkGLContext *self)
450 {
451 GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (self);
452
453 priv->use_es = -1;
454 }
455
456 /* Must have called gdk_display_prepare_gl() before */
457 GdkGLContext *
gdk_gl_context_new_for_surface(GdkSurface * surface)458 gdk_gl_context_new_for_surface (GdkSurface *surface)
459 {
460 GdkDisplay *display = gdk_surface_get_display (surface);
461 GdkGLContext *shared = gdk_display_get_gl_context (display);
462
463 /* assert gdk_display_prepare_gl() had been called */
464 g_assert (shared);
465
466 return g_object_new (G_OBJECT_TYPE (shared),
467 "surface", surface,
468 NULL);
469 }
470
471 GdkGLContextPaintData *
gdk_gl_context_get_paint_data(GdkGLContext * context)472 gdk_gl_context_get_paint_data (GdkGLContext *context)
473 {
474 GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
475
476 if (priv->paint_data == NULL)
477 {
478 priv->paint_data = g_new0 (GdkGLContextPaintData, 1);
479 priv->paint_data->is_legacy = priv->is_legacy;
480 priv->paint_data->use_es = priv->use_es;
481 }
482
483 return priv->paint_data;
484 }
485
486 gboolean
gdk_gl_context_use_texture_rectangle(GdkGLContext * context)487 gdk_gl_context_use_texture_rectangle (GdkGLContext *context)
488 {
489 GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
490
491 return priv->use_texture_rectangle;
492 }
493
494 void
gdk_gl_context_push_debug_group(GdkGLContext * context,const char * message)495 gdk_gl_context_push_debug_group (GdkGLContext *context,
496 const char *message)
497 {
498 GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
499
500 if (priv->use_khr_debug)
501 glPushDebugGroupKHR (GL_DEBUG_SOURCE_APPLICATION, 0, -1, message);
502 }
503
504 void
gdk_gl_context_push_debug_group_printf(GdkGLContext * context,const char * format,...)505 gdk_gl_context_push_debug_group_printf (GdkGLContext *context,
506 const char *format,
507 ...)
508 {
509 GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
510 char *message;
511 va_list args;
512
513 if (priv->use_khr_debug)
514 {
515 int msg_len;
516
517 va_start (args, format);
518 message = g_strdup_vprintf (format, args);
519 va_end (args);
520
521 msg_len = MIN (priv->max_debug_label_length, strlen (message) - 1);
522 glPushDebugGroupKHR (GL_DEBUG_SOURCE_APPLICATION, 0, msg_len, message);
523 g_free (message);
524 }
525 }
526
527 void
gdk_gl_context_pop_debug_group(GdkGLContext * context)528 gdk_gl_context_pop_debug_group (GdkGLContext *context)
529 {
530 GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
531
532 if (priv->use_khr_debug)
533 glPopDebugGroupKHR ();
534 }
535
536 void
gdk_gl_context_label_object(GdkGLContext * context,guint identifier,guint name,const char * label)537 gdk_gl_context_label_object (GdkGLContext *context,
538 guint identifier,
539 guint name,
540 const char *label)
541 {
542 GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
543
544 if (priv->use_khr_debug)
545 glObjectLabel (identifier, name, -1, label);
546 }
547
548 void
gdk_gl_context_label_object_printf(GdkGLContext * context,guint identifier,guint name,const char * format,...)549 gdk_gl_context_label_object_printf (GdkGLContext *context,
550 guint identifier,
551 guint name,
552 const char *format,
553 ...)
554 {
555 GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
556 char *message;
557 va_list args;
558
559 if (priv->use_khr_debug)
560 {
561 int msg_len;
562
563 va_start (args, format);
564 message = g_strdup_vprintf (format, args);
565 va_end (args);
566
567 msg_len = MIN (priv->max_debug_label_length, strlen (message) - 1);
568
569 glObjectLabel (identifier, name, msg_len, message);
570 g_free (message);
571 }
572 }
573
574
575 gboolean
gdk_gl_context_has_unpack_subimage(GdkGLContext * context)576 gdk_gl_context_has_unpack_subimage (GdkGLContext *context)
577 {
578 GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
579
580 return priv->has_unpack_subimage;
581 }
582
583 /**
584 * gdk_gl_context_set_debug_enabled:
585 * @context: a `GdkGLContext`
586 * @enabled: whether to enable debugging in the context
587 *
588 * Sets whether the `GdkGLContext` should perform extra validations and
589 * runtime checking.
590 *
591 * This is useful during development, but has additional overhead.
592 *
593 * The `GdkGLContext` must not be realized or made current prior to
594 * calling this function.
595 */
596 void
gdk_gl_context_set_debug_enabled(GdkGLContext * context,gboolean enabled)597 gdk_gl_context_set_debug_enabled (GdkGLContext *context,
598 gboolean enabled)
599 {
600 GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
601
602 g_return_if_fail (GDK_IS_GL_CONTEXT (context));
603 g_return_if_fail (!priv->realized);
604
605 enabled = !!enabled;
606
607 priv->debug_enabled = enabled;
608 }
609
610 /**
611 * gdk_gl_context_get_debug_enabled:
612 * @context: a `GdkGLContext`
613 *
614 * Retrieves whether the context is doing extra validations and runtime checking.
615 *
616 * See [method@Gdk.GLContext.set_debug_enabled].
617 *
618 * Returns: %TRUE if debugging is enabled
619 */
620 gboolean
gdk_gl_context_get_debug_enabled(GdkGLContext * context)621 gdk_gl_context_get_debug_enabled (GdkGLContext *context)
622 {
623 GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
624
625 g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), FALSE);
626
627 return priv->debug_enabled;
628 }
629
630 /**
631 * gdk_gl_context_set_forward_compatible:
632 * @context: a `GdkGLContext`
633 * @compatible: whether the context should be forward-compatible
634 *
635 * Sets whether the `GdkGLContext` should be forward-compatible.
636 *
637 * Forward-compatible contexts must not support OpenGL functionality that
638 * has been marked as deprecated in the requested version; non-forward
639 * compatible contexts, on the other hand, must support both deprecated and
640 * non deprecated functionality.
641 *
642 * The `GdkGLContext` must not be realized or made current prior to calling
643 * this function.
644 */
645 void
gdk_gl_context_set_forward_compatible(GdkGLContext * context,gboolean compatible)646 gdk_gl_context_set_forward_compatible (GdkGLContext *context,
647 gboolean compatible)
648 {
649 GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
650
651 g_return_if_fail (GDK_IS_GL_CONTEXT (context));
652 g_return_if_fail (!priv->realized);
653
654 compatible = !!compatible;
655
656 priv->forward_compatible = compatible;
657 }
658
659 /**
660 * gdk_gl_context_get_forward_compatible:
661 * @context: a `GdkGLContext`
662 *
663 * Retrieves whether the context is forward-compatible.
664 *
665 * See [method@Gdk.GLContext.set_forward_compatible].
666 *
667 * Returns: %TRUE if the context should be forward-compatible
668 */
669 gboolean
gdk_gl_context_get_forward_compatible(GdkGLContext * context)670 gdk_gl_context_get_forward_compatible (GdkGLContext *context)
671 {
672 GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
673
674 g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), FALSE);
675
676 return priv->forward_compatible;
677 }
678
679 /**
680 * gdk_gl_context_set_required_version:
681 * @context: a `GdkGLContext`
682 * @major: the major version to request
683 * @minor: the minor version to request
684 *
685 * Sets the major and minor version of OpenGL to request.
686 *
687 * Setting @major and @minor to zero will use the default values.
688 *
689 * The `GdkGLContext` must not be realized or made current prior to calling
690 * this function.
691 */
692 void
gdk_gl_context_set_required_version(GdkGLContext * context,int major,int minor)693 gdk_gl_context_set_required_version (GdkGLContext *context,
694 int major,
695 int minor)
696 {
697 GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
698 gboolean force_gles = FALSE;
699 int version, min_ver;
700 #ifdef G_ENABLE_DEBUG
701 GdkDisplay *display;
702 #endif
703
704 g_return_if_fail (GDK_IS_GL_CONTEXT (context));
705 g_return_if_fail (!priv->realized);
706
707 /* this will take care of the default */
708 if (major == 0 && minor == 0)
709 {
710 priv->major = 0;
711 priv->minor = 0;
712 return;
713 }
714
715 version = (major * 100) + minor;
716
717 #ifdef G_ENABLE_DEBUG
718 display = gdk_draw_context_get_display (GDK_DRAW_CONTEXT (context));
719 force_gles = GDK_DISPLAY_DEBUG_CHECK (display, GL_GLES);
720 #endif
721 /* Enforce a minimum context version number of 3.2 for desktop GL,
722 * and 2.0 for GLES
723 */
724 if (priv->use_es > 0 || force_gles)
725 min_ver = 200;
726 else
727 min_ver = 302;
728
729 if (version < min_ver)
730 {
731 g_warning ("gdk_gl_context_set_required_version - GL context versions less than 3.2 are not supported.");
732 version = min_ver;
733 }
734 priv->major = version / 100;
735 priv->minor = version % 100;
736 }
737
738 /**
739 * gdk_gl_context_get_required_version:
740 * @context: a `GdkGLContext`
741 * @major: (out) (nullable): return location for the major version to request
742 * @minor: (out) (nullable): return location for the minor version to request
743 *
744 * Retrieves required OpenGL version.
745 *
746 * See [method@Gdk.GLContext.set_required_version].
747 */
748 void
gdk_gl_context_get_required_version(GdkGLContext * context,int * major,int * minor)749 gdk_gl_context_get_required_version (GdkGLContext *context,
750 int *major,
751 int *minor)
752 {
753 GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
754 gboolean force_gles = FALSE;
755 #ifdef G_ENABLE_DEBUG
756 GdkDisplay *display;
757 #endif
758 int default_major, default_minor;
759 int maj, min;
760
761 g_return_if_fail (GDK_IS_GL_CONTEXT (context));
762
763 #ifdef G_ENABLE_DEBUG
764 display = gdk_draw_context_get_display (GDK_DRAW_CONTEXT (context));
765 force_gles = GDK_DISPLAY_DEBUG_CHECK (display, GL_GLES);
766 #endif
767
768 /* Default fallback values for uninitialised contexts; we
769 * enforce a context version number of 3.2 for desktop GL,
770 * and 2.0 for GLES
771 */
772 if (priv->use_es > 0 || force_gles)
773 {
774 default_major = 2;
775 default_minor = 0;
776 }
777 else
778 {
779 default_major = 3;
780 default_minor = 2;
781 }
782
783 if (priv->major > 0)
784 maj = priv->major;
785 else
786 maj = default_major;
787
788 if (priv->minor > 0)
789 min = priv->minor;
790 else
791 min = default_minor;
792
793 if (major != NULL)
794 *major = maj;
795 if (minor != NULL)
796 *minor = min;
797 }
798
799 /**
800 * gdk_gl_context_is_legacy:
801 * @context: a `GdkGLContext`
802 *
803 * Whether the `GdkGLContext` is in legacy mode or not.
804 *
805 * The `GdkGLContext` must be realized before calling this function.
806 *
807 * When realizing a GL context, GDK will try to use the OpenGL 3.2 core
808 * profile; this profile removes all the OpenGL API that was deprecated
809 * prior to the 3.2 version of the specification. If the realization is
810 * successful, this function will return %FALSE.
811 *
812 * If the underlying OpenGL implementation does not support core profiles,
813 * GDK will fall back to a pre-3.2 compatibility profile, and this function
814 * will return %TRUE.
815 *
816 * You can use the value returned by this function to decide which kind
817 * of OpenGL API to use, or whether to do extension discovery, or what
818 * kind of shader programs to load.
819 *
820 * Returns: %TRUE if the GL context is in legacy mode
821 */
822 gboolean
gdk_gl_context_is_legacy(GdkGLContext * context)823 gdk_gl_context_is_legacy (GdkGLContext *context)
824 {
825 GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
826
827 g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), FALSE);
828 g_return_val_if_fail (priv->realized, FALSE);
829
830 return priv->is_legacy;
831 }
832
833 void
gdk_gl_context_set_is_legacy(GdkGLContext * context,gboolean is_legacy)834 gdk_gl_context_set_is_legacy (GdkGLContext *context,
835 gboolean is_legacy)
836 {
837 GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
838
839 priv->is_legacy = !!is_legacy;
840 }
841
842 /**
843 * gdk_gl_context_is_shared:
844 * @self: a `GdkGLContext`
845 * @other: the `GdkGLContext` that should be compatible with @self
846 *
847 * Checks if the two GL contexts can share resources.
848 *
849 * When they can, the texture IDs from @other can be used in @self. This
850 * is particularly useful when passing `GdkGLTexture` objects between
851 * different contexts.
852 *
853 * Contexts created for the same display with the same properties will
854 * always be compatible, even if they are created for different surfaces.
855 * For other contexts it depends on the GL backend.
856 *
857 * Both contexts must be realized for this check to succeed. If either one
858 * is not, this function will return %FALSE.
859 *
860 * Returns: %TRUE if the two GL contexts are compatible.
861 *
862 * Since: 4.4
863 */
864 gboolean
gdk_gl_context_is_shared(GdkGLContext * self,GdkGLContext * other)865 gdk_gl_context_is_shared (GdkGLContext *self,
866 GdkGLContext *other)
867 {
868 GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (self);
869 GdkGLContextPrivate *priv_other = gdk_gl_context_get_instance_private (other);
870
871 g_return_val_if_fail (GDK_IS_GL_CONTEXT (self), FALSE);
872 g_return_val_if_fail (GDK_IS_GL_CONTEXT (other), FALSE);
873
874 if (!priv->realized || !priv_other->realized)
875 return FALSE;
876
877 return GDK_GL_CONTEXT_GET_CLASS (self)->is_shared (self, other);
878 }
879
880 /**
881 * gdk_gl_context_set_use_es:
882 * @context: a `GdkGLContext`
883 * @use_es: whether the context should use OpenGL ES instead of OpenGL,
884 * or -1 to allow auto-detection
885 *
886 * Requests that GDK create an OpenGL ES context instead of an OpenGL one.
887 *
888 * Not all platforms support OpenGL ES.
889 *
890 * The @context must not have been realized.
891 *
892 * By default, GDK will attempt to automatically detect whether the
893 * underlying GL implementation is OpenGL or OpenGL ES once the @context
894 * is realized.
895 *
896 * You should check the return value of [method@Gdk.GLContext.get_use_es]
897 * after calling [method@Gdk.GLContext.realize] to decide whether to use
898 * the OpenGL or OpenGL ES API, extensions, or shaders.
899 */
900 void
gdk_gl_context_set_use_es(GdkGLContext * context,int use_es)901 gdk_gl_context_set_use_es (GdkGLContext *context,
902 int use_es)
903 {
904 GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
905
906 g_return_if_fail (GDK_IS_GL_CONTEXT (context));
907 g_return_if_fail (!priv->realized);
908
909 if (priv->use_es != use_es)
910 priv->use_es = use_es;
911 }
912
913 /**
914 * gdk_gl_context_get_use_es:
915 * @context: a `GdkGLContext`
916 *
917 * Checks whether the @context is using an OpenGL or OpenGL ES profile.
918 *
919 * Returns: %TRUE if the `GdkGLContext` is using an OpenGL ES profile
920 */
921 gboolean
gdk_gl_context_get_use_es(GdkGLContext * context)922 gdk_gl_context_get_use_es (GdkGLContext *context)
923 {
924 GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
925
926 g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), FALSE);
927
928 if (!priv->realized)
929 return FALSE;
930
931 return priv->use_es > 0;
932 }
933
934 static void APIENTRY
gl_debug_message_callback(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar * message,const void * user_data)935 gl_debug_message_callback (GLenum source,
936 GLenum type,
937 GLuint id,
938 GLenum severity,
939 GLsizei length,
940 const GLchar *message,
941 const void *user_data)
942 {
943 const char *message_source;
944 const char *message_type;
945 const char *message_severity;
946
947 if (severity == GL_DEBUG_SEVERITY_NOTIFICATION)
948 return;
949
950 switch (source)
951 {
952 case GL_DEBUG_SOURCE_API:
953 message_source = "API";
954 break;
955 case GL_DEBUG_SOURCE_WINDOW_SYSTEM:
956 message_source = "Window System";
957 break;
958 case GL_DEBUG_SOURCE_SHADER_COMPILER:
959 message_source = "Shader Compiler";
960 break;
961 case GL_DEBUG_SOURCE_THIRD_PARTY:
962 message_source = "Third Party";
963 break;
964 case GL_DEBUG_SOURCE_APPLICATION:
965 message_source = "Application";
966 break;
967 case GL_DEBUG_SOURCE_OTHER:
968 default:
969 message_source = "Other";
970 }
971
972 switch (type)
973 {
974 case GL_DEBUG_TYPE_ERROR:
975 message_type = "Error";
976 break;
977 case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
978 message_type = "Deprecated Behavior";
979 break;
980 case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
981 message_type = "Undefined Behavior";
982 break;
983 case GL_DEBUG_TYPE_PORTABILITY:
984 message_type = "Portability";
985 break;
986 case GL_DEBUG_TYPE_PERFORMANCE:
987 message_type = "Performance";
988 break;
989 case GL_DEBUG_TYPE_MARKER:
990 message_type = "Marker";
991 break;
992 case GL_DEBUG_TYPE_PUSH_GROUP:
993 message_type = "Push Group";
994 break;
995 case GL_DEBUG_TYPE_POP_GROUP:
996 message_type = "Pop Group";
997 break;
998 case GL_DEBUG_TYPE_OTHER:
999 default:
1000 message_type = "Other";
1001 }
1002
1003 switch (severity)
1004 {
1005 case GL_DEBUG_SEVERITY_HIGH:
1006 message_severity = "High";
1007 break;
1008 case GL_DEBUG_SEVERITY_MEDIUM:
1009 message_severity = "Medium";
1010 break;
1011 case GL_DEBUG_SEVERITY_LOW:
1012 message_severity = "Low";
1013 break;
1014 case GL_DEBUG_SEVERITY_NOTIFICATION:
1015 message_severity = "Notification";
1016 break;
1017 default:
1018 message_severity = "Unknown";
1019 }
1020
1021 g_warning ("OPENGL:\n Source: %s\n Type: %s\n Severity: %s\n Message: %s",
1022 message_source, message_type, message_severity, message);
1023 }
1024
1025 /**
1026 * gdk_gl_context_realize:
1027 * @context: a `GdkGLContext`
1028 * @error: return location for a `GError`
1029 *
1030 * Realizes the given `GdkGLContext`.
1031 *
1032 * It is safe to call this function on a realized `GdkGLContext`.
1033 *
1034 * Returns: %TRUE if the context is realized
1035 */
1036 gboolean
gdk_gl_context_realize(GdkGLContext * context,GError ** error)1037 gdk_gl_context_realize (GdkGLContext *context,
1038 GError **error)
1039 {
1040 GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
1041
1042 g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), FALSE);
1043
1044 if (priv->realized)
1045 return TRUE;
1046
1047 priv->realized = GDK_GL_CONTEXT_GET_CLASS (context)->realize (context, error);
1048
1049 return priv->realized;
1050 }
1051
1052 static void
gdk_gl_context_check_extensions(GdkGLContext * context)1053 gdk_gl_context_check_extensions (GdkGLContext *context)
1054 {
1055 GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
1056 gboolean has_npot, has_texture_rectangle;
1057 gboolean gl_debug = FALSE;
1058 #ifdef G_ENABLE_DEBUG
1059 GdkDisplay *display;
1060 #endif
1061
1062 if (!priv->realized)
1063 return;
1064
1065 if (priv->extensions_checked)
1066 return;
1067
1068 priv->gl_version = epoxy_gl_version ();
1069
1070 if (priv->use_es < 0)
1071 priv->use_es = !epoxy_is_desktop_gl ();
1072
1073 priv->has_debug_output = epoxy_has_gl_extension ("GL_ARB_debug_output") ||
1074 epoxy_has_gl_extension ("GL_KHR_debug");
1075
1076 #ifdef G_ENABLE_DEBUG
1077 display = gdk_draw_context_get_display (GDK_DRAW_CONTEXT (context));
1078 gl_debug = GDK_DISPLAY_DEBUG_CHECK (display, GL_DEBUG);
1079 #endif
1080
1081 if (priv->has_debug_output
1082 #ifndef G_ENABLE_CONSISTENCY_CHECKS
1083 && gl_debug
1084 #endif
1085 )
1086 {
1087 gdk_gl_context_make_current (context);
1088 glEnable (GL_DEBUG_OUTPUT);
1089 glEnable (GL_DEBUG_OUTPUT_SYNCHRONOUS);
1090 glDebugMessageCallback (gl_debug_message_callback, NULL);
1091 }
1092
1093 if (priv->use_es)
1094 {
1095 has_npot = priv->gl_version >= 20;
1096 has_texture_rectangle = FALSE;
1097
1098 priv->has_unpack_subimage = epoxy_has_gl_extension ("GL_EXT_unpack_subimage");
1099 priv->has_khr_debug = epoxy_has_gl_extension ("GL_KHR_debug");
1100 }
1101 else
1102 {
1103 has_npot = priv->gl_version >= 20 || epoxy_has_gl_extension ("GL_ARB_texture_non_power_of_two");
1104 has_texture_rectangle = priv->gl_version >= 31 || epoxy_has_gl_extension ("GL_ARB_texture_rectangle");
1105
1106 priv->has_unpack_subimage = TRUE;
1107 priv->has_khr_debug = epoxy_has_gl_extension ("GL_KHR_debug");
1108
1109 /* We asked for a core profile, but we didn't get one, so we're in legacy mode */
1110 if (priv->gl_version < 32)
1111 priv->is_legacy = TRUE;
1112 }
1113
1114 if (priv->has_khr_debug && gl_debug)
1115 {
1116 priv->use_khr_debug = TRUE;
1117 glGetIntegerv (GL_MAX_LABEL_LENGTH, &priv->max_debug_label_length);
1118 }
1119 if (!priv->use_es && GDK_DISPLAY_DEBUG_CHECK (gdk_draw_context_get_display (GDK_DRAW_CONTEXT (context)), GL_TEXTURE_RECT))
1120 priv->use_texture_rectangle = TRUE;
1121 else if (has_npot)
1122 priv->use_texture_rectangle = FALSE;
1123 else if (has_texture_rectangle)
1124 priv->use_texture_rectangle = TRUE;
1125 else
1126 g_warning ("GL implementation doesn't support any form of non-power-of-two textures");
1127
1128 GDK_DISPLAY_NOTE (gdk_draw_context_get_display (GDK_DRAW_CONTEXT (context)), OPENGL,
1129 g_message ("%s version: %d.%d (%s)\n"
1130 "* GLSL version: %s\n"
1131 "* Extensions checked:\n"
1132 " - GL_ARB_texture_non_power_of_two: %s\n"
1133 " - GL_ARB_texture_rectangle: %s\n"
1134 " - GL_KHR_debug: %s\n"
1135 " - GL_EXT_unpack_subimage: %s\n"
1136 "* Using texture rectangle: %s",
1137 priv->use_es ? "OpenGL ES" : "OpenGL",
1138 priv->gl_version / 10, priv->gl_version % 10,
1139 priv->is_legacy ? "legacy" : "core",
1140 glGetString (GL_SHADING_LANGUAGE_VERSION),
1141 has_npot ? "yes" : "no",
1142 has_texture_rectangle ? "yes" : "no",
1143 priv->has_khr_debug ? "yes" : "no",
1144 priv->has_unpack_subimage ? "yes" : "no",
1145 priv->use_texture_rectangle ? "yes" : "no"));
1146
1147 priv->extensions_checked = TRUE;
1148 }
1149
1150 /**
1151 * gdk_gl_context_make_current:
1152 * @context: a `GdkGLContext`
1153 *
1154 * Makes the @context the current one.
1155 */
1156 void
gdk_gl_context_make_current(GdkGLContext * context)1157 gdk_gl_context_make_current (GdkGLContext *context)
1158 {
1159 GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
1160 MaskedContext *current, *masked_context;
1161 gboolean surfaceless;
1162
1163 g_return_if_fail (GDK_IS_GL_CONTEXT (context));
1164
1165 surfaceless = !gdk_draw_context_is_in_frame (GDK_DRAW_CONTEXT (context));
1166 masked_context = mask_context (context, surfaceless);
1167
1168 current = g_private_get (&thread_current_context);
1169 if (current == masked_context)
1170 return;
1171
1172 /* we need to realize the GdkGLContext if it wasn't explicitly realized */
1173 if (!priv->realized)
1174 {
1175 GError *error = NULL;
1176
1177 gdk_gl_context_realize (context, &error);
1178 if (error != NULL)
1179 {
1180 g_critical ("Could not realize the GL context: %s", error->message);
1181 g_error_free (error);
1182 return;
1183 }
1184 }
1185
1186 if (!GDK_GL_CONTEXT_GET_CLASS (context)->make_current (context, surfaceless))
1187 {
1188 g_warning ("gdk_gl_context_make_current() failed");
1189 return;
1190 }
1191
1192 g_object_ref (context);
1193 g_private_replace (&thread_current_context, masked_context);
1194 gdk_gl_context_check_extensions (context);
1195 }
1196
1197 /**
1198 * gdk_gl_context_get_display:
1199 * @context: a `GdkGLContext`
1200 *
1201 * Retrieves the display the @context is created for
1202 *
1203 * Returns: (nullable) (transfer none): a `GdkDisplay`
1204 */
1205 GdkDisplay *
gdk_gl_context_get_display(GdkGLContext * context)1206 gdk_gl_context_get_display (GdkGLContext *context)
1207 {
1208 g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), NULL);
1209
1210 return gdk_draw_context_get_display (GDK_DRAW_CONTEXT (context));
1211 }
1212
1213 /**
1214 * gdk_gl_context_get_surface:
1215 * @context: a `GdkGLContext`
1216 *
1217 * Retrieves the surface used by the @context.
1218 *
1219 * Returns: (nullable) (transfer none): a `GdkSurface`
1220 */
1221 GdkSurface *
gdk_gl_context_get_surface(GdkGLContext * context)1222 gdk_gl_context_get_surface (GdkGLContext *context)
1223 {
1224 g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), NULL);
1225
1226 return gdk_draw_context_get_surface (GDK_DRAW_CONTEXT (context));
1227 }
1228
1229 /**
1230 * gdk_gl_context_get_shared_context: (attributes org.gtk.Method.get_property=shared-context)
1231 * @context: a `GdkGLContext`
1232 *
1233 * Used to retrieves the `GdkGLContext` that this @context share data with.
1234 *
1235 * As many contexts can share data now and no single shared context exists
1236 * anymore, this function has been deprecated and now always returns %NULL.
1237 *
1238 * Returns: (nullable) (transfer none): %NULL
1239 *
1240 * Deprecated: 4.4: Use [method@Gdk.GLContext.is_shared] to check if contexts
1241 * can be shared.
1242 */
1243 GdkGLContext *
gdk_gl_context_get_shared_context(GdkGLContext * context)1244 gdk_gl_context_get_shared_context (GdkGLContext *context)
1245 {
1246 g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), NULL);
1247
1248 return NULL;
1249 }
1250
1251 /**
1252 * gdk_gl_context_get_version:
1253 * @context: a `GdkGLContext`
1254 * @major: (out): return location for the major version
1255 * @minor: (out): return location for the minor version
1256 *
1257 * Retrieves the OpenGL version of the @context.
1258 *
1259 * The @context must be realized prior to calling this function.
1260 */
1261 void
gdk_gl_context_get_version(GdkGLContext * context,int * major,int * minor)1262 gdk_gl_context_get_version (GdkGLContext *context,
1263 int *major,
1264 int *minor)
1265 {
1266 GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
1267
1268 g_return_if_fail (GDK_IS_GL_CONTEXT (context));
1269 g_return_if_fail (priv->realized);
1270
1271 if (major != NULL)
1272 *major = priv->gl_version / 10;
1273 if (minor != NULL)
1274 *minor = priv->gl_version % 10;
1275 }
1276
1277 /**
1278 * gdk_gl_context_clear_current:
1279 *
1280 * Clears the current `GdkGLContext`.
1281 *
1282 * Any OpenGL call after this function returns will be ignored
1283 * until [method@Gdk.GLContext.make_current] is called.
1284 */
1285 void
gdk_gl_context_clear_current(void)1286 gdk_gl_context_clear_current (void)
1287 {
1288 MaskedContext *current;
1289
1290 current = g_private_get (&thread_current_context);
1291 if (current != NULL)
1292 {
1293 GdkGLContext *context = unmask_context (current);
1294
1295 if (GDK_GL_CONTEXT_GET_CLASS (context)->clear_current (context))
1296 g_private_replace (&thread_current_context, NULL);
1297 }
1298 }
1299
1300 /**
1301 * gdk_gl_context_get_current:
1302 *
1303 * Retrieves the current `GdkGLContext`.
1304 *
1305 * Returns: (nullable) (transfer none): the current `GdkGLContext`
1306 */
1307 GdkGLContext *
gdk_gl_context_get_current(void)1308 gdk_gl_context_get_current (void)
1309 {
1310 MaskedContext *current;
1311
1312 current = g_private_get (&thread_current_context);
1313
1314 return unmask_context (current);
1315 }
1316
1317 gboolean
gdk_gl_context_has_debug(GdkGLContext * self)1318 gdk_gl_context_has_debug (GdkGLContext *self)
1319 {
1320 GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (self);
1321
1322 return priv->debug_enabled || priv->use_khr_debug;
1323 }
1324
1325 /* This is currently private! */
1326 /* When using GL/ES, don't flip the 'R' and 'B' bits on Windows/ANGLE for glReadPixels() */
1327 gboolean
gdk_gl_context_use_es_bgra(GdkGLContext * context)1328 gdk_gl_context_use_es_bgra (GdkGLContext *context)
1329 {
1330 if (!gdk_gl_context_get_use_es (context))
1331 return FALSE;
1332
1333 #ifdef GDK_WINDOWING_WIN32
1334 if (GDK_WIN32_IS_GL_CONTEXT (context))
1335 return TRUE;
1336 #endif
1337
1338 return FALSE;
1339 }
1340
1341 static GdkGLBackend the_gl_backend_type = GDK_GL_NONE;
1342
1343 static const char *gl_backend_names[] = {
1344 [GDK_GL_NONE] = "No GL (You should never read this)",
1345 [GDK_GL_EGL] = "EGL",
1346 [GDK_GL_GLX] = "X11 GLX",
1347 [GDK_GL_WGL] = "Windows WGL",
1348 [GDK_GL_CGL] = "Apple CGL"
1349 };
1350
1351 /*<private>
1352 * gdk_gl_backend_can_be_used:
1353 * @backend_type: Type of backend to check
1354 * @error: Return location for an error
1355 *
1356 * Checks if this backend type can be used. When multiple displays
1357 * are opened that use different GL backends, conflicts can arise,
1358 * so this function checks that all displays use compatible GL
1359 * backends.
1360 *
1361 * Returns: %TRUE if the backend can still be used
1362 */
1363 gboolean
gdk_gl_backend_can_be_used(GdkGLBackend backend_type,GError ** error)1364 gdk_gl_backend_can_be_used (GdkGLBackend backend_type,
1365 GError **error)
1366 {
1367 if (the_gl_backend_type == GDK_GL_NONE ||
1368 the_gl_backend_type == backend_type)
1369 return TRUE;
1370
1371 g_set_error (error, GDK_GL_ERROR, GDK_GL_ERROR_NOT_AVAILABLE,
1372 /* translators: This is about OpenGL backend names, like
1373 * "Trying to use X11 GLX, but EGL is already in use" */
1374 _("Trying to use %s, but %s is already in use"),
1375 gl_backend_names[backend_type],
1376 gl_backend_names[the_gl_backend_type]);
1377 return FALSE;
1378 }
1379
1380 /*<private>
1381 * gdk_gl_backend_use:
1382 * @backend_type: Type of backend
1383 *
1384 * Ensures that the backend in use is the given one. If another backend
1385 * is already in use, this function will abort the program. It should
1386 * have previously checked via gdk_gl_backend_can_be_used().
1387 **/
1388 void
gdk_gl_backend_use(GdkGLBackend backend_type)1389 gdk_gl_backend_use (GdkGLBackend backend_type)
1390 {
1391 /* Check that the context class is properly initializing its backend type */
1392 g_assert (backend_type != GDK_GL_NONE);
1393
1394 if (the_gl_backend_type == GDK_GL_NONE)
1395 {
1396 the_gl_backend_type = backend_type;
1397 /* This is important!!!11eleven
1398 * (But really: How do I print a message in 2 categories?) */
1399 GDK_NOTE (OPENGL, g_print ("Using OpenGL backend %s\n", gl_backend_names[the_gl_backend_type]));
1400 GDK_NOTE (MISC, g_message ("Using Opengl backend %s", gl_backend_names[the_gl_backend_type]));
1401 }
1402
1403 g_assert (the_gl_backend_type == backend_type);
1404 }
1405