forked from AuroraMiddleware/gtk
e06e0e8555
Now that we have the display's context to hook into, we can use it to construct other GL contexts and don't need a GdkSurface vfunc anymore. This has the added benefit that backends can have different GdkGLContext classes on the display and get new GLContexts generated from them, so we get multiple GL backend support per GDK backend for free. I originally wanted to make this a vfunc on GdkGLContextClass, but it turns out all the abckends would just call g_object_new() anyway.
1336 lines
38 KiB
C
1336 lines
38 KiB
C
/* GDK - The GIMP Drawing Kit
|
|
*
|
|
* gdkglcontext.c: GL context abstraction
|
|
*
|
|
* Copyright © 2014 Emmanuele Bassi
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/**
|
|
* GdkGLContext:
|
|
*
|
|
* `GdkGLContext` is an object representing a platform-specific
|
|
* OpenGL draw context.
|
|
*
|
|
* `GdkGLContext`s are created for a surface using
|
|
* [method@Gdk.Surface.create_gl_context], and the context will match
|
|
* the the characteristics of the surface.
|
|
*
|
|
* A `GdkGLContext` is not tied to any particular normal framebuffer.
|
|
* For instance, it cannot draw to the surface back buffer. The GDK
|
|
* repaint system is in full control of the painting to that. Instead,
|
|
* you can create render buffers or textures and use [func@cairo_draw_from_gl]
|
|
* in the draw function of your widget to draw them. Then GDK will handle
|
|
* the integration of your rendering with that of other widgets.
|
|
*
|
|
* Support for `GdkGLContext` is platform-specific and context creation
|
|
* can fail, returning %NULL context.
|
|
*
|
|
* A `GdkGLContext` has to be made "current" in order to start using
|
|
* it, otherwise any OpenGL call will be ignored.
|
|
*
|
|
* ## Creating a new OpenGL context
|
|
*
|
|
* In order to create a new `GdkGLContext` instance you need a `GdkSurface`,
|
|
* which you typically get during the realize call of a widget.
|
|
*
|
|
* A `GdkGLContext` is not realized until either [method@Gdk.GLContext.make_current]
|
|
* or [method@Gdk.GLContext.realize] is called. It is possible to specify
|
|
* details of the GL context like the OpenGL version to be used, or whether
|
|
* the GL context should have extra state validation enabled after calling
|
|
* [method@Gdk.Surface.create_gl_context] by calling [method@Gdk.GLContext.realize].
|
|
* If the realization fails you have the option to change the settings of
|
|
* the `GdkGLContext` and try again.
|
|
*
|
|
* ## Using a GdkGLContext
|
|
*
|
|
* You will need to make the `GdkGLContext` the current context before issuing
|
|
* OpenGL calls; the system sends OpenGL commands to whichever context is current.
|
|
* It is possible to have multiple contexts, so you always need to ensure that
|
|
* the one which you want to draw with is the current one before issuing commands:
|
|
*
|
|
* ```c
|
|
* gdk_gl_context_make_current (context);
|
|
* ```
|
|
*
|
|
* You can now perform your drawing using OpenGL commands.
|
|
*
|
|
* You can check which `GdkGLContext` is the current one by using
|
|
* [func@Gdk.GLContext.get_current]; you can also unset any `GdkGLContext`
|
|
* that is currently set by calling [func@Gdk.GLContext.clear_current].
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "gdkglcontextprivate.h"
|
|
#include "gdkdisplayprivate.h"
|
|
#include "gdkmemorytextureprivate.h"
|
|
#include "gdkinternals.h"
|
|
|
|
#include "gdkintl.h"
|
|
#include "gdk-private.h"
|
|
|
|
#ifdef GDK_WINDOWING_WIN32
|
|
# include "gdk/win32/gdkwin32.h"
|
|
#endif
|
|
|
|
#include <epoxy/gl.h>
|
|
|
|
typedef struct {
|
|
int major;
|
|
int minor;
|
|
int gl_version;
|
|
|
|
guint realized : 1;
|
|
guint use_texture_rectangle : 1;
|
|
guint has_khr_debug : 1;
|
|
guint use_khr_debug : 1;
|
|
guint has_unpack_subimage : 1;
|
|
guint has_debug_output : 1;
|
|
guint extensions_checked : 1;
|
|
guint debug_enabled : 1;
|
|
guint forward_compatible : 1;
|
|
guint is_legacy : 1;
|
|
|
|
int use_es;
|
|
|
|
int max_debug_label_length;
|
|
|
|
GdkGLContextPaintData *paint_data;
|
|
} GdkGLContextPrivate;
|
|
|
|
enum {
|
|
PROP_0,
|
|
|
|
PROP_SHARED_CONTEXT,
|
|
|
|
LAST_PROP
|
|
};
|
|
|
|
static GParamSpec *obj_pspecs[LAST_PROP] = { NULL, };
|
|
|
|
G_DEFINE_QUARK (gdk-gl-error-quark, gdk_gl_error)
|
|
|
|
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GdkGLContext, gdk_gl_context, GDK_TYPE_DRAW_CONTEXT)
|
|
|
|
typedef struct _MaskedContext MaskedContext;
|
|
|
|
static inline MaskedContext *
|
|
mask_context (GdkGLContext *context,
|
|
gboolean surfaceless)
|
|
{
|
|
return (MaskedContext *) GSIZE_TO_POINTER (GPOINTER_TO_SIZE (context) | (surfaceless ? 1 : 0));
|
|
}
|
|
|
|
static inline GdkGLContext *
|
|
unmask_context (MaskedContext *mask)
|
|
{
|
|
return GDK_GL_CONTEXT (GSIZE_TO_POINTER (GPOINTER_TO_SIZE (mask) & ~(gsize) 1));
|
|
}
|
|
|
|
static void
|
|
unref_unmasked (gpointer data)
|
|
{
|
|
g_object_unref (unmask_context (data));
|
|
}
|
|
|
|
static GPrivate thread_current_context = G_PRIVATE_INIT (unref_unmasked);
|
|
|
|
static void
|
|
gdk_gl_context_clear_old_updated_area (GdkGLContext *context)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < 2; i++)
|
|
{
|
|
g_clear_pointer (&context->old_updated_area[i], cairo_region_destroy);
|
|
}
|
|
}
|
|
|
|
static void
|
|
gdk_gl_context_dispose (GObject *gobject)
|
|
{
|
|
GdkGLContext *context = GDK_GL_CONTEXT (gobject);
|
|
MaskedContext *current;
|
|
|
|
gdk_gl_context_clear_old_updated_area (context);
|
|
|
|
current = g_private_get (&thread_current_context);
|
|
if (unmask_context (current) == context)
|
|
g_private_replace (&thread_current_context, NULL);
|
|
|
|
G_OBJECT_CLASS (gdk_gl_context_parent_class)->dispose (gobject);
|
|
}
|
|
|
|
static void
|
|
gdk_gl_context_finalize (GObject *gobject)
|
|
{
|
|
GdkGLContext *context = GDK_GL_CONTEXT (gobject);
|
|
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
|
|
|
|
g_clear_pointer (&priv->paint_data, g_free);
|
|
G_OBJECT_CLASS (gdk_gl_context_parent_class)->finalize (gobject);
|
|
}
|
|
|
|
static void
|
|
gdk_gl_context_set_property (GObject *gobject,
|
|
guint prop_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
switch (prop_id)
|
|
{
|
|
case PROP_SHARED_CONTEXT:
|
|
g_assert (g_value_get_object (value) == NULL);
|
|
break;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
|
}
|
|
}
|
|
|
|
static void
|
|
gdk_gl_context_get_property (GObject *gobject,
|
|
guint prop_id,
|
|
GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
switch (prop_id)
|
|
{
|
|
case PROP_SHARED_CONTEXT:
|
|
g_value_set_object (value, NULL);
|
|
break;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
|
}
|
|
}
|
|
|
|
void
|
|
gdk_gl_context_upload_texture (GdkGLContext *context,
|
|
const guchar *data,
|
|
int width,
|
|
int height,
|
|
int stride,
|
|
GdkMemoryFormat data_format,
|
|
guint texture_target)
|
|
{
|
|
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
|
|
guchar *copy = NULL;
|
|
guint gl_format;
|
|
guint gl_type;
|
|
guint bpp;
|
|
|
|
g_return_if_fail (GDK_IS_GL_CONTEXT (context));
|
|
|
|
if (priv->use_es)
|
|
{
|
|
/* GLES only supports rgba, so convert if necessary */
|
|
if (data_format != GDK_MEMORY_R8G8B8A8_PREMULTIPLIED)
|
|
{
|
|
copy = g_malloc (width * height * 4);
|
|
gdk_memory_convert (copy, width * 4,
|
|
GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
|
|
data, stride, data_format,
|
|
width, height);
|
|
stride = width * 4;
|
|
data = copy;
|
|
}
|
|
|
|
bpp = 4;
|
|
gl_format = GL_RGBA;
|
|
gl_type = GL_UNSIGNED_BYTE;
|
|
}
|
|
else
|
|
{
|
|
if (data_format == GDK_MEMORY_DEFAULT) /* Cairo surface format */
|
|
{
|
|
gl_format = GL_BGRA;
|
|
gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
|
|
bpp = 4;
|
|
}
|
|
else if (data_format == GDK_MEMORY_R8G8B8) /* Pixmap non-alpha data */
|
|
{
|
|
gl_format = GL_RGB;
|
|
gl_type = GL_UNSIGNED_BYTE;
|
|
bpp = 3;
|
|
}
|
|
else if (data_format == GDK_MEMORY_B8G8R8)
|
|
{
|
|
gl_format = GL_BGR;
|
|
gl_type = GL_UNSIGNED_BYTE;
|
|
bpp = 3;
|
|
}
|
|
else /* Fall-back, convert to cairo-surface-format */
|
|
{
|
|
copy = g_malloc (width * height * 4);
|
|
gdk_memory_convert (copy, width * 4,
|
|
GDK_MEMORY_DEFAULT,
|
|
data, stride, data_format,
|
|
width, height);
|
|
stride = width * 4;
|
|
bpp = 4;
|
|
data = copy;
|
|
gl_format = GL_BGRA;
|
|
gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
|
|
}
|
|
}
|
|
|
|
/* GL_UNPACK_ROW_LENGTH is available on desktop GL, OpenGL ES >= 3.0, or if
|
|
* the GL_EXT_unpack_subimage extension for OpenGL ES 2.0 is available
|
|
*/
|
|
if (stride == width * bpp)
|
|
{
|
|
glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
|
|
|
|
glTexImage2D (texture_target, 0, GL_RGBA, width, height, 0, gl_format, gl_type, data);
|
|
glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
|
|
}
|
|
else if ((!priv->use_es ||
|
|
(priv->use_es && (priv->gl_version >= 30 || priv->has_unpack_subimage))))
|
|
{
|
|
glPixelStorei (GL_UNPACK_ROW_LENGTH, stride / bpp);
|
|
|
|
glTexImage2D (texture_target, 0, GL_RGBA, width, height, 0, gl_format, gl_type, data);
|
|
|
|
glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
|
|
}
|
|
else
|
|
{
|
|
int i;
|
|
glTexImage2D (texture_target, 0, GL_RGBA, width, height, 0, gl_format, gl_type, NULL);
|
|
for (i = 0; i < height; i++)
|
|
glTexSubImage2D (texture_target, 0, 0, i, width, 1, gl_format, gl_type, data + (i * stride));
|
|
}
|
|
|
|
g_free (copy);
|
|
}
|
|
|
|
static gboolean
|
|
gdk_gl_context_real_realize (GdkGLContext *self,
|
|
GError **error)
|
|
{
|
|
g_set_error_literal (error, GDK_GL_ERROR, GDK_GL_ERROR_NOT_AVAILABLE,
|
|
"The current backend does not support OpenGL");
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static cairo_region_t *
|
|
gdk_gl_context_real_get_damage (GdkGLContext *context)
|
|
{
|
|
GdkSurface *surface = gdk_draw_context_get_surface (GDK_DRAW_CONTEXT (context));
|
|
|
|
return cairo_region_create_rectangle (&(GdkRectangle) {
|
|
0, 0,
|
|
gdk_surface_get_width (surface),
|
|
gdk_surface_get_height (surface)
|
|
});
|
|
}
|
|
|
|
static gboolean
|
|
gdk_gl_context_real_is_shared (GdkGLContext *self,
|
|
GdkGLContext *other)
|
|
{
|
|
if (gdk_draw_context_get_display (GDK_DRAW_CONTEXT (self)) != gdk_draw_context_get_display (GDK_DRAW_CONTEXT (other)))
|
|
return FALSE;
|
|
|
|
/* XXX: Should we check es or legacy here? */
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
gdk_gl_context_real_begin_frame (GdkDrawContext *draw_context,
|
|
cairo_region_t *region)
|
|
{
|
|
GdkGLContext *context = GDK_GL_CONTEXT (draw_context);
|
|
GdkSurface *surface;
|
|
cairo_region_t *damage;
|
|
int ww, wh;
|
|
|
|
damage = GDK_GL_CONTEXT_GET_CLASS (context)->get_damage (context);
|
|
|
|
if (context->old_updated_area[1])
|
|
cairo_region_destroy (context->old_updated_area[1]);
|
|
context->old_updated_area[1] = context->old_updated_area[0];
|
|
context->old_updated_area[0] = cairo_region_copy (region);
|
|
|
|
cairo_region_union (region, damage);
|
|
cairo_region_destroy (damage);
|
|
|
|
surface = gdk_draw_context_get_surface (draw_context);
|
|
ww = gdk_surface_get_width (surface) * gdk_surface_get_scale_factor (surface);
|
|
wh = gdk_surface_get_height (surface) * gdk_surface_get_scale_factor (surface);
|
|
|
|
gdk_gl_context_make_current (context);
|
|
|
|
/* Initial setup */
|
|
glClearColor (0.0f, 0.0f, 0.0f, 0.0f);
|
|
glDisable (GL_DEPTH_TEST);
|
|
glDisable (GL_BLEND);
|
|
glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
glViewport (0, 0, ww, wh);
|
|
}
|
|
|
|
static void
|
|
gdk_gl_context_real_end_frame (GdkDrawContext *draw_context,
|
|
cairo_region_t *painted)
|
|
{
|
|
}
|
|
|
|
static void
|
|
gdk_gl_context_surface_resized (GdkDrawContext *draw_context)
|
|
{
|
|
GdkGLContext *context = GDK_GL_CONTEXT (draw_context);
|
|
|
|
gdk_gl_context_clear_old_updated_area (context);
|
|
}
|
|
|
|
static void
|
|
gdk_gl_context_class_init (GdkGLContextClass *klass)
|
|
{
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
GdkDrawContextClass *draw_context_class = GDK_DRAW_CONTEXT_CLASS (klass);
|
|
|
|
klass->realize = gdk_gl_context_real_realize;
|
|
klass->get_damage = gdk_gl_context_real_get_damage;
|
|
klass->is_shared = gdk_gl_context_real_is_shared;
|
|
|
|
draw_context_class->begin_frame = gdk_gl_context_real_begin_frame;
|
|
draw_context_class->end_frame = gdk_gl_context_real_end_frame;
|
|
draw_context_class->surface_resized = gdk_gl_context_surface_resized;
|
|
|
|
/**
|
|
* GdkGLContext:shared-context: (attributes org.gtk.Property.get=gdk_gl_context_get_shared_context)
|
|
*
|
|
* Always %NULL
|
|
*
|
|
* As many contexts can share data now and no single shared context exists
|
|
* anymore, this function has been deprecated and now always returns %NULL.
|
|
*
|
|
* Deprecated: 4.4: Use [method@Gdk.GLContext.is_shared] to check if contexts
|
|
* can be shared.
|
|
*/
|
|
obj_pspecs[PROP_SHARED_CONTEXT] =
|
|
g_param_spec_object ("shared-context",
|
|
P_("Shared context"),
|
|
P_("The GL context this context shares data with"),
|
|
GDK_TYPE_GL_CONTEXT,
|
|
G_PARAM_READWRITE |
|
|
G_PARAM_CONSTRUCT_ONLY |
|
|
G_PARAM_STATIC_STRINGS |
|
|
G_PARAM_DEPRECATED);
|
|
|
|
gobject_class->set_property = gdk_gl_context_set_property;
|
|
gobject_class->get_property = gdk_gl_context_get_property;
|
|
gobject_class->dispose = gdk_gl_context_dispose;
|
|
gobject_class->finalize = gdk_gl_context_finalize;
|
|
|
|
g_object_class_install_properties (gobject_class, LAST_PROP, obj_pspecs);
|
|
}
|
|
|
|
static void
|
|
gdk_gl_context_init (GdkGLContext *self)
|
|
{
|
|
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (self);
|
|
|
|
priv->use_es = -1;
|
|
}
|
|
|
|
/* Must have called gdk_display_prepare_gl() before */
|
|
GdkGLContext *
|
|
gdk_gl_context_new_for_surface (GdkSurface *surface)
|
|
{
|
|
GdkDisplay *display = gdk_surface_get_display (surface);
|
|
GdkGLContext *shared = gdk_display_get_gl_context (display);
|
|
|
|
/* assert gdk_display_prepare_gl() had been called */
|
|
g_assert (shared);
|
|
|
|
return g_object_new (G_OBJECT_TYPE (shared),
|
|
"surface", surface,
|
|
NULL);
|
|
}
|
|
|
|
GdkGLContextPaintData *
|
|
gdk_gl_context_get_paint_data (GdkGLContext *context)
|
|
{
|
|
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
|
|
|
|
if (priv->paint_data == NULL)
|
|
{
|
|
priv->paint_data = g_new0 (GdkGLContextPaintData, 1);
|
|
priv->paint_data->is_legacy = priv->is_legacy;
|
|
priv->paint_data->use_es = priv->use_es;
|
|
}
|
|
|
|
return priv->paint_data;
|
|
}
|
|
|
|
gboolean
|
|
gdk_gl_context_use_texture_rectangle (GdkGLContext *context)
|
|
{
|
|
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
|
|
|
|
return priv->use_texture_rectangle;
|
|
}
|
|
|
|
void
|
|
gdk_gl_context_push_debug_group (GdkGLContext *context,
|
|
const char *message)
|
|
{
|
|
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
|
|
|
|
if (priv->use_khr_debug)
|
|
glPushDebugGroupKHR (GL_DEBUG_SOURCE_APPLICATION, 0, -1, message);
|
|
}
|
|
|
|
void
|
|
gdk_gl_context_push_debug_group_printf (GdkGLContext *context,
|
|
const char *format,
|
|
...)
|
|
{
|
|
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
|
|
char *message;
|
|
va_list args;
|
|
|
|
if (priv->use_khr_debug)
|
|
{
|
|
int msg_len;
|
|
|
|
va_start (args, format);
|
|
message = g_strdup_vprintf (format, args);
|
|
va_end (args);
|
|
|
|
msg_len = MIN (priv->max_debug_label_length, strlen (message) - 1);
|
|
glPushDebugGroupKHR (GL_DEBUG_SOURCE_APPLICATION, 0, msg_len, message);
|
|
g_free (message);
|
|
}
|
|
}
|
|
|
|
void
|
|
gdk_gl_context_pop_debug_group (GdkGLContext *context)
|
|
{
|
|
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
|
|
|
|
if (priv->use_khr_debug)
|
|
glPopDebugGroupKHR ();
|
|
}
|
|
|
|
void
|
|
gdk_gl_context_label_object (GdkGLContext *context,
|
|
guint identifier,
|
|
guint name,
|
|
const char *label)
|
|
{
|
|
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
|
|
|
|
if (priv->use_khr_debug)
|
|
glObjectLabel (identifier, name, -1, label);
|
|
}
|
|
|
|
void
|
|
gdk_gl_context_label_object_printf (GdkGLContext *context,
|
|
guint identifier,
|
|
guint name,
|
|
const char *format,
|
|
...)
|
|
{
|
|
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
|
|
char *message;
|
|
va_list args;
|
|
|
|
if (priv->use_khr_debug)
|
|
{
|
|
int msg_len;
|
|
|
|
va_start (args, format);
|
|
message = g_strdup_vprintf (format, args);
|
|
va_end (args);
|
|
|
|
msg_len = MIN (priv->max_debug_label_length, strlen (message) - 1);
|
|
|
|
glObjectLabel (identifier, name, msg_len, message);
|
|
g_free (message);
|
|
}
|
|
}
|
|
|
|
|
|
gboolean
|
|
gdk_gl_context_has_unpack_subimage (GdkGLContext *context)
|
|
{
|
|
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
|
|
|
|
return priv->has_unpack_subimage;
|
|
}
|
|
|
|
/**
|
|
* gdk_gl_context_set_debug_enabled:
|
|
* @context: a `GdkGLContext`
|
|
* @enabled: whether to enable debugging in the context
|
|
*
|
|
* Sets whether the `GdkGLContext` should perform extra validations and
|
|
* runtime checking.
|
|
*
|
|
* This is useful during development, but has additional overhead.
|
|
*
|
|
* The `GdkGLContext` must not be realized or made current prior to
|
|
* calling this function.
|
|
*/
|
|
void
|
|
gdk_gl_context_set_debug_enabled (GdkGLContext *context,
|
|
gboolean enabled)
|
|
{
|
|
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
|
|
|
|
g_return_if_fail (GDK_IS_GL_CONTEXT (context));
|
|
g_return_if_fail (!priv->realized);
|
|
|
|
enabled = !!enabled;
|
|
|
|
priv->debug_enabled = enabled;
|
|
}
|
|
|
|
/**
|
|
* gdk_gl_context_get_debug_enabled:
|
|
* @context: a `GdkGLContext`
|
|
*
|
|
* Retrieves whether the context is doing extra validations and runtime checking.
|
|
*
|
|
* See [method@Gdk.GLContext.set_debug_enabled].
|
|
*
|
|
* Returns: %TRUE if debugging is enabled
|
|
*/
|
|
gboolean
|
|
gdk_gl_context_get_debug_enabled (GdkGLContext *context)
|
|
{
|
|
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
|
|
|
|
g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), FALSE);
|
|
|
|
return priv->debug_enabled;
|
|
}
|
|
|
|
/**
|
|
* gdk_gl_context_set_forward_compatible:
|
|
* @context: a `GdkGLContext`
|
|
* @compatible: whether the context should be forward-compatible
|
|
*
|
|
* Sets whether the `GdkGLContext` should be forward-compatible.
|
|
*
|
|
* Forward-compatible contexts must not support OpenGL functionality that
|
|
* has been marked as deprecated in the requested version; non-forward
|
|
* compatible contexts, on the other hand, must support both deprecated and
|
|
* non deprecated functionality.
|
|
*
|
|
* The `GdkGLContext` must not be realized or made current prior to calling
|
|
* this function.
|
|
*/
|
|
void
|
|
gdk_gl_context_set_forward_compatible (GdkGLContext *context,
|
|
gboolean compatible)
|
|
{
|
|
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
|
|
|
|
g_return_if_fail (GDK_IS_GL_CONTEXT (context));
|
|
g_return_if_fail (!priv->realized);
|
|
|
|
compatible = !!compatible;
|
|
|
|
priv->forward_compatible = compatible;
|
|
}
|
|
|
|
/**
|
|
* gdk_gl_context_get_forward_compatible:
|
|
* @context: a `GdkGLContext`
|
|
*
|
|
* Retrieves whether the context is forward-compatible.
|
|
*
|
|
* See [method@Gdk.GLContext.set_forward_compatible].
|
|
*
|
|
* Returns: %TRUE if the context should be forward-compatible
|
|
*/
|
|
gboolean
|
|
gdk_gl_context_get_forward_compatible (GdkGLContext *context)
|
|
{
|
|
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
|
|
|
|
g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), FALSE);
|
|
|
|
return priv->forward_compatible;
|
|
}
|
|
|
|
/**
|
|
* gdk_gl_context_set_required_version:
|
|
* @context: a `GdkGLContext`
|
|
* @major: the major version to request
|
|
* @minor: the minor version to request
|
|
*
|
|
* Sets the major and minor version of OpenGL to request.
|
|
*
|
|
* Setting @major and @minor to zero will use the default values.
|
|
*
|
|
* The `GdkGLContext` must not be realized or made current prior to calling
|
|
* this function.
|
|
*/
|
|
void
|
|
gdk_gl_context_set_required_version (GdkGLContext *context,
|
|
int major,
|
|
int minor)
|
|
{
|
|
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
|
|
gboolean force_gles = FALSE;
|
|
int version, min_ver;
|
|
#ifdef G_ENABLE_DEBUG
|
|
GdkDisplay *display;
|
|
#endif
|
|
|
|
g_return_if_fail (GDK_IS_GL_CONTEXT (context));
|
|
g_return_if_fail (!priv->realized);
|
|
|
|
/* this will take care of the default */
|
|
if (major == 0 && minor == 0)
|
|
{
|
|
priv->major = 0;
|
|
priv->minor = 0;
|
|
return;
|
|
}
|
|
|
|
version = (major * 100) + minor;
|
|
|
|
#ifdef G_ENABLE_DEBUG
|
|
display = gdk_draw_context_get_display (GDK_DRAW_CONTEXT (context));
|
|
force_gles = GDK_DISPLAY_DEBUG_CHECK (display, GL_GLES);
|
|
#endif
|
|
/* Enforce a minimum context version number of 3.2 for desktop GL,
|
|
* and 2.0 for GLES
|
|
*/
|
|
if (priv->use_es > 0 || force_gles)
|
|
min_ver = 200;
|
|
else
|
|
min_ver = 302;
|
|
|
|
if (version < min_ver)
|
|
{
|
|
g_warning ("gdk_gl_context_set_required_version - GL context versions less than 3.2 are not supported.");
|
|
version = min_ver;
|
|
}
|
|
priv->major = version / 100;
|
|
priv->minor = version % 100;
|
|
}
|
|
|
|
/**
|
|
* gdk_gl_context_get_required_version:
|
|
* @context: a `GdkGLContext`
|
|
* @major: (out) (nullable): return location for the major version to request
|
|
* @minor: (out) (nullable): return location for the minor version to request
|
|
*
|
|
* Retrieves required OpenGL version.
|
|
*
|
|
* See [method@Gdk.GLContext.set_required_version].
|
|
*/
|
|
void
|
|
gdk_gl_context_get_required_version (GdkGLContext *context,
|
|
int *major,
|
|
int *minor)
|
|
{
|
|
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
|
|
gboolean force_gles = FALSE;
|
|
#ifdef G_ENABLE_DEBUG
|
|
GdkDisplay *display;
|
|
#endif
|
|
int default_major, default_minor;
|
|
int maj, min;
|
|
|
|
g_return_if_fail (GDK_IS_GL_CONTEXT (context));
|
|
|
|
#ifdef G_ENABLE_DEBUG
|
|
display = gdk_draw_context_get_display (GDK_DRAW_CONTEXT (context));
|
|
force_gles = GDK_DISPLAY_DEBUG_CHECK (display, GL_GLES);
|
|
#endif
|
|
|
|
/* Default fallback values for uninitialised contexts; we
|
|
* enforce a context version number of 3.2 for desktop GL,
|
|
* and 2.0 for GLES
|
|
*/
|
|
if (priv->use_es > 0 || force_gles)
|
|
{
|
|
default_major = 2;
|
|
default_minor = 0;
|
|
}
|
|
else
|
|
{
|
|
default_major = 3;
|
|
default_minor = 2;
|
|
}
|
|
|
|
if (priv->major > 0)
|
|
maj = priv->major;
|
|
else
|
|
maj = default_major;
|
|
|
|
if (priv->minor > 0)
|
|
min = priv->minor;
|
|
else
|
|
min = default_minor;
|
|
|
|
if (major != NULL)
|
|
*major = maj;
|
|
if (minor != NULL)
|
|
*minor = min;
|
|
}
|
|
|
|
/**
|
|
* gdk_gl_context_is_legacy:
|
|
* @context: a `GdkGLContext`
|
|
*
|
|
* Whether the `GdkGLContext` is in legacy mode or not.
|
|
*
|
|
* The `GdkGLContext` must be realized before calling this function.
|
|
*
|
|
* When realizing a GL context, GDK will try to use the OpenGL 3.2 core
|
|
* profile; this profile removes all the OpenGL API that was deprecated
|
|
* prior to the 3.2 version of the specification. If the realization is
|
|
* successful, this function will return %FALSE.
|
|
*
|
|
* If the underlying OpenGL implementation does not support core profiles,
|
|
* GDK will fall back to a pre-3.2 compatibility profile, and this function
|
|
* will return %TRUE.
|
|
*
|
|
* You can use the value returned by this function to decide which kind
|
|
* of OpenGL API to use, or whether to do extension discovery, or what
|
|
* kind of shader programs to load.
|
|
*
|
|
* Returns: %TRUE if the GL context is in legacy mode
|
|
*/
|
|
gboolean
|
|
gdk_gl_context_is_legacy (GdkGLContext *context)
|
|
{
|
|
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
|
|
|
|
g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), FALSE);
|
|
g_return_val_if_fail (priv->realized, FALSE);
|
|
|
|
return priv->is_legacy;
|
|
}
|
|
|
|
void
|
|
gdk_gl_context_set_is_legacy (GdkGLContext *context,
|
|
gboolean is_legacy)
|
|
{
|
|
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
|
|
|
|
priv->is_legacy = !!is_legacy;
|
|
}
|
|
|
|
/**
|
|
* gdk_gl_context_is_shared:
|
|
* @self: a `GdkGLContext`
|
|
* @other: the `GdkGLContext` that should be compatible with @self
|
|
*
|
|
* Checks if the two GL contexts can share resources.
|
|
*
|
|
* When they can, the texture IDs from @other can be used in @self. This
|
|
* is particularly useful when passing `GdkGLTexture` objects between
|
|
* different contexts.
|
|
*
|
|
* Contexts created for the same display with the same properties will
|
|
* always be compatible, even if they are created for different surfaces.
|
|
* For other contexts it depends on the GL backend.
|
|
*
|
|
* Both contexts must be realized for this check to succeed. If either one
|
|
* is not, this function will return %FALSE.
|
|
*
|
|
* Returns: %TRUE if the two GL contexts are compatible.
|
|
*/
|
|
gboolean
|
|
gdk_gl_context_is_shared (GdkGLContext *self,
|
|
GdkGLContext *other)
|
|
{
|
|
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (self);
|
|
GdkGLContextPrivate *priv_other = gdk_gl_context_get_instance_private (other);
|
|
|
|
g_return_val_if_fail (GDK_IS_GL_CONTEXT (self), FALSE);
|
|
g_return_val_if_fail (GDK_IS_GL_CONTEXT (other), FALSE);
|
|
|
|
if (!priv->realized || !priv_other->realized)
|
|
return FALSE;
|
|
|
|
return GDK_GL_CONTEXT_GET_CLASS (self)->is_shared (self, other);
|
|
}
|
|
|
|
/**
|
|
* gdk_gl_context_set_use_es:
|
|
* @context: a `GdkGLContext`
|
|
* @use_es: whether the context should use OpenGL ES instead of OpenGL,
|
|
* or -1 to allow auto-detection
|
|
*
|
|
* Requests that GDK create an OpenGL ES context instead of an OpenGL one.
|
|
*
|
|
* Not all platforms support OpenGL ES.
|
|
*
|
|
* The @context must not have been realized.
|
|
*
|
|
* By default, GDK will attempt to automatically detect whether the
|
|
* underlying GL implementation is OpenGL or OpenGL ES once the @context
|
|
* is realized.
|
|
*
|
|
* You should check the return value of [method@Gdk.GLContext.get_use_es]
|
|
* after calling [method@Gdk.GLContext.realize] to decide whether to use
|
|
* the OpenGL or OpenGL ES API, extensions, or shaders.
|
|
*/
|
|
void
|
|
gdk_gl_context_set_use_es (GdkGLContext *context,
|
|
int use_es)
|
|
{
|
|
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
|
|
|
|
g_return_if_fail (GDK_IS_GL_CONTEXT (context));
|
|
g_return_if_fail (!priv->realized);
|
|
|
|
if (priv->use_es != use_es)
|
|
priv->use_es = use_es;
|
|
}
|
|
|
|
/**
|
|
* gdk_gl_context_get_use_es:
|
|
* @context: a `GdkGLContext`
|
|
*
|
|
* Checks whether the @context is using an OpenGL or OpenGL ES profile.
|
|
*
|
|
* Returns: %TRUE if the `GdkGLContext` is using an OpenGL ES profile
|
|
*/
|
|
gboolean
|
|
gdk_gl_context_get_use_es (GdkGLContext *context)
|
|
{
|
|
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
|
|
|
|
g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), FALSE);
|
|
|
|
if (!priv->realized)
|
|
return FALSE;
|
|
|
|
return priv->use_es > 0;
|
|
}
|
|
|
|
static void APIENTRY
|
|
gl_debug_message_callback (GLenum source,
|
|
GLenum type,
|
|
GLuint id,
|
|
GLenum severity,
|
|
GLsizei length,
|
|
const GLchar *message,
|
|
const void *user_data)
|
|
{
|
|
const char *message_source;
|
|
const char *message_type;
|
|
const char *message_severity;
|
|
|
|
if (severity == GL_DEBUG_SEVERITY_NOTIFICATION)
|
|
return;
|
|
|
|
switch (source)
|
|
{
|
|
case GL_DEBUG_SOURCE_API:
|
|
message_source = "API";
|
|
break;
|
|
case GL_DEBUG_SOURCE_WINDOW_SYSTEM:
|
|
message_source = "Window System";
|
|
break;
|
|
case GL_DEBUG_SOURCE_SHADER_COMPILER:
|
|
message_source = "Shader Compiler";
|
|
break;
|
|
case GL_DEBUG_SOURCE_THIRD_PARTY:
|
|
message_source = "Third Party";
|
|
break;
|
|
case GL_DEBUG_SOURCE_APPLICATION:
|
|
message_source = "Application";
|
|
break;
|
|
case GL_DEBUG_SOURCE_OTHER:
|
|
default:
|
|
message_source = "Other";
|
|
}
|
|
|
|
switch (type)
|
|
{
|
|
case GL_DEBUG_TYPE_ERROR:
|
|
message_type = "Error";
|
|
break;
|
|
case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
|
|
message_type = "Deprecated Behavior";
|
|
break;
|
|
case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
|
|
message_type = "Undefined Behavior";
|
|
break;
|
|
case GL_DEBUG_TYPE_PORTABILITY:
|
|
message_type = "Portability";
|
|
break;
|
|
case GL_DEBUG_TYPE_PERFORMANCE:
|
|
message_type = "Performance";
|
|
break;
|
|
case GL_DEBUG_TYPE_MARKER:
|
|
message_type = "Marker";
|
|
break;
|
|
case GL_DEBUG_TYPE_PUSH_GROUP:
|
|
message_type = "Push Group";
|
|
break;
|
|
case GL_DEBUG_TYPE_POP_GROUP:
|
|
message_type = "Pop Group";
|
|
break;
|
|
case GL_DEBUG_TYPE_OTHER:
|
|
default:
|
|
message_type = "Other";
|
|
}
|
|
|
|
switch (severity)
|
|
{
|
|
case GL_DEBUG_SEVERITY_HIGH:
|
|
message_severity = "High";
|
|
break;
|
|
case GL_DEBUG_SEVERITY_MEDIUM:
|
|
message_severity = "Medium";
|
|
break;
|
|
case GL_DEBUG_SEVERITY_LOW:
|
|
message_severity = "Low";
|
|
break;
|
|
case GL_DEBUG_SEVERITY_NOTIFICATION:
|
|
message_severity = "Notification";
|
|
break;
|
|
default:
|
|
message_severity = "Unknown";
|
|
}
|
|
|
|
g_warning ("OPENGL:\n Source: %s\n Type: %s\n Severity: %s\n Message: %s",
|
|
message_source, message_type, message_severity, message);
|
|
}
|
|
|
|
/**
|
|
* gdk_gl_context_realize:
|
|
* @context: a `GdkGLContext`
|
|
* @error: return location for a `GError`
|
|
*
|
|
* Realizes the given `GdkGLContext`.
|
|
*
|
|
* It is safe to call this function on a realized `GdkGLContext`.
|
|
*
|
|
* Returns: %TRUE if the context is realized
|
|
*/
|
|
gboolean
|
|
gdk_gl_context_realize (GdkGLContext *context,
|
|
GError **error)
|
|
{
|
|
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
|
|
|
|
g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), FALSE);
|
|
|
|
if (priv->realized)
|
|
return TRUE;
|
|
|
|
priv->realized = GDK_GL_CONTEXT_GET_CLASS (context)->realize (context, error);
|
|
|
|
return priv->realized;
|
|
}
|
|
|
|
static void
|
|
gdk_gl_context_check_extensions (GdkGLContext *context)
|
|
{
|
|
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
|
|
gboolean has_npot, has_texture_rectangle;
|
|
gboolean gl_debug = FALSE;
|
|
#ifdef G_ENABLE_DEBUG
|
|
GdkDisplay *display;
|
|
#endif
|
|
|
|
if (!priv->realized)
|
|
return;
|
|
|
|
if (priv->extensions_checked)
|
|
return;
|
|
|
|
priv->gl_version = epoxy_gl_version ();
|
|
|
|
if (priv->use_es < 0)
|
|
priv->use_es = !epoxy_is_desktop_gl ();
|
|
|
|
priv->has_debug_output = epoxy_has_gl_extension ("GL_ARB_debug_output") ||
|
|
epoxy_has_gl_extension ("GL_KHR_debug");
|
|
|
|
#ifdef G_ENABLE_DEBUG
|
|
display = gdk_draw_context_get_display (GDK_DRAW_CONTEXT (context));
|
|
gl_debug = GDK_DISPLAY_DEBUG_CHECK (display, GL_DEBUG);
|
|
#endif
|
|
|
|
if (priv->has_debug_output
|
|
#ifndef G_ENABLE_CONSISTENCY_CHECKS
|
|
&& gl_debug
|
|
#endif
|
|
)
|
|
{
|
|
gdk_gl_context_make_current (context);
|
|
glEnable (GL_DEBUG_OUTPUT);
|
|
glEnable (GL_DEBUG_OUTPUT_SYNCHRONOUS);
|
|
glDebugMessageCallback (gl_debug_message_callback, NULL);
|
|
}
|
|
|
|
if (priv->use_es)
|
|
{
|
|
has_npot = priv->gl_version >= 20;
|
|
has_texture_rectangle = FALSE;
|
|
|
|
priv->has_unpack_subimage = epoxy_has_gl_extension ("GL_EXT_unpack_subimage");
|
|
priv->has_khr_debug = epoxy_has_gl_extension ("GL_KHR_debug");
|
|
}
|
|
else
|
|
{
|
|
has_npot = priv->gl_version >= 20 || epoxy_has_gl_extension ("GL_ARB_texture_non_power_of_two");
|
|
has_texture_rectangle = priv->gl_version >= 31 || epoxy_has_gl_extension ("GL_ARB_texture_rectangle");
|
|
|
|
priv->has_unpack_subimage = TRUE;
|
|
priv->has_khr_debug = epoxy_has_gl_extension ("GL_KHR_debug");
|
|
|
|
/* We asked for a core profile, but we didn't get one, so we're in legacy mode */
|
|
if (priv->gl_version < 32)
|
|
priv->is_legacy = TRUE;
|
|
}
|
|
|
|
if (priv->has_khr_debug && gl_debug)
|
|
{
|
|
priv->use_khr_debug = TRUE;
|
|
glGetIntegerv (GL_MAX_LABEL_LENGTH, &priv->max_debug_label_length);
|
|
}
|
|
if (!priv->use_es && GDK_DISPLAY_DEBUG_CHECK (gdk_draw_context_get_display (GDK_DRAW_CONTEXT (context)), GL_TEXTURE_RECT))
|
|
priv->use_texture_rectangle = TRUE;
|
|
else if (has_npot)
|
|
priv->use_texture_rectangle = FALSE;
|
|
else if (has_texture_rectangle)
|
|
priv->use_texture_rectangle = TRUE;
|
|
else
|
|
g_warning ("GL implementation doesn't support any form of non-power-of-two textures");
|
|
|
|
GDK_DISPLAY_NOTE (gdk_draw_context_get_display (GDK_DRAW_CONTEXT (context)), OPENGL,
|
|
g_message ("%s version: %d.%d (%s)\n"
|
|
"* GLSL version: %s\n"
|
|
"* Extensions checked:\n"
|
|
" - GL_ARB_texture_non_power_of_two: %s\n"
|
|
" - GL_ARB_texture_rectangle: %s\n"
|
|
" - GL_KHR_debug: %s\n"
|
|
" - GL_EXT_unpack_subimage: %s\n"
|
|
"* Using texture rectangle: %s",
|
|
priv->use_es ? "OpenGL ES" : "OpenGL",
|
|
priv->gl_version / 10, priv->gl_version % 10,
|
|
priv->is_legacy ? "legacy" : "core",
|
|
glGetString (GL_SHADING_LANGUAGE_VERSION),
|
|
has_npot ? "yes" : "no",
|
|
has_texture_rectangle ? "yes" : "no",
|
|
priv->has_khr_debug ? "yes" : "no",
|
|
priv->has_unpack_subimage ? "yes" : "no",
|
|
priv->use_texture_rectangle ? "yes" : "no"));
|
|
|
|
priv->extensions_checked = TRUE;
|
|
}
|
|
|
|
/**
|
|
* gdk_gl_context_make_current:
|
|
* @context: a `GdkGLContext`
|
|
*
|
|
* Makes the @context the current one.
|
|
*/
|
|
void
|
|
gdk_gl_context_make_current (GdkGLContext *context)
|
|
{
|
|
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
|
|
MaskedContext *current, *masked_context;
|
|
gboolean surfaceless;
|
|
|
|
g_return_if_fail (GDK_IS_GL_CONTEXT (context));
|
|
|
|
surfaceless = !gdk_draw_context_is_in_frame (GDK_DRAW_CONTEXT (context));
|
|
masked_context = mask_context (context, surfaceless);
|
|
|
|
current = g_private_get (&thread_current_context);
|
|
if (current == masked_context)
|
|
return;
|
|
|
|
/* we need to realize the GdkGLContext if it wasn't explicitly realized */
|
|
if (!priv->realized)
|
|
{
|
|
GError *error = NULL;
|
|
|
|
gdk_gl_context_realize (context, &error);
|
|
if (error != NULL)
|
|
{
|
|
g_critical ("Could not realize the GL context: %s", error->message);
|
|
g_error_free (error);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (!GDK_GL_CONTEXT_GET_CLASS (context)->make_current (context, surfaceless))
|
|
{
|
|
g_warning ("gdk_gl_context_make_current() failed");
|
|
return;
|
|
}
|
|
|
|
g_object_ref (context);
|
|
g_private_replace (&thread_current_context, masked_context);
|
|
gdk_gl_context_check_extensions (context);
|
|
}
|
|
|
|
/**
|
|
* gdk_gl_context_get_display:
|
|
* @context: a `GdkGLContext`
|
|
*
|
|
* Retrieves the display the @context is created for
|
|
*
|
|
* Returns: (nullable) (transfer none): a `GdkDisplay`
|
|
*/
|
|
GdkDisplay *
|
|
gdk_gl_context_get_display (GdkGLContext *context)
|
|
{
|
|
g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), NULL);
|
|
|
|
return gdk_draw_context_get_display (GDK_DRAW_CONTEXT (context));
|
|
}
|
|
|
|
/**
|
|
* gdk_gl_context_get_surface:
|
|
* @context: a `GdkGLContext`
|
|
*
|
|
* Retrieves the surface used by the @context.
|
|
*
|
|
* Returns: (nullable) (transfer none): a `GdkSurface`
|
|
*/
|
|
GdkSurface *
|
|
gdk_gl_context_get_surface (GdkGLContext *context)
|
|
{
|
|
g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), NULL);
|
|
|
|
return gdk_draw_context_get_surface (GDK_DRAW_CONTEXT (context));
|
|
}
|
|
|
|
/**
|
|
* gdk_gl_context_get_shared_context: (attributes org.gtk.Method.get_property=shared-context)
|
|
* @context: a `GdkGLContext`
|
|
*
|
|
* Used to retrieves the `GdkGLContext` that this @context share data with.
|
|
*
|
|
* As many contexts can share data now and no single shared context exists
|
|
* anymore, this function has been deprecated and now always returns %NULL.
|
|
*
|
|
* Returns: (nullable) (transfer none): %NULL
|
|
*
|
|
* Deprecated: 4.4: Use [method@Gdk.GLContext.is_shared] to check if contexts
|
|
* can be shared.
|
|
*/
|
|
GdkGLContext *
|
|
gdk_gl_context_get_shared_context (GdkGLContext *context)
|
|
{
|
|
g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), NULL);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* gdk_gl_context_get_version:
|
|
* @context: a `GdkGLContext`
|
|
* @major: (out): return location for the major version
|
|
* @minor: (out): return location for the minor version
|
|
*
|
|
* Retrieves the OpenGL version of the @context.
|
|
*
|
|
* The @context must be realized prior to calling this function.
|
|
*/
|
|
void
|
|
gdk_gl_context_get_version (GdkGLContext *context,
|
|
int *major,
|
|
int *minor)
|
|
{
|
|
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
|
|
|
|
g_return_if_fail (GDK_IS_GL_CONTEXT (context));
|
|
g_return_if_fail (priv->realized);
|
|
|
|
if (major != NULL)
|
|
*major = priv->gl_version / 10;
|
|
if (minor != NULL)
|
|
*minor = priv->gl_version % 10;
|
|
}
|
|
|
|
/**
|
|
* gdk_gl_context_clear_current:
|
|
*
|
|
* Clears the current `GdkGLContext`.
|
|
*
|
|
* Any OpenGL call after this function returns will be ignored
|
|
* until [method@Gdk.GLContext.make_current] is called.
|
|
*/
|
|
void
|
|
gdk_gl_context_clear_current (void)
|
|
{
|
|
MaskedContext *current;
|
|
|
|
current = g_private_get (&thread_current_context);
|
|
if (current != NULL)
|
|
{
|
|
GdkGLContext *context = unmask_context (current);
|
|
|
|
if (GDK_GL_CONTEXT_GET_CLASS (context)->clear_current (context))
|
|
g_private_replace (&thread_current_context, NULL);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* gdk_gl_context_get_current:
|
|
*
|
|
* Retrieves the current `GdkGLContext`.
|
|
*
|
|
* Returns: (nullable) (transfer none): the current `GdkGLContext`
|
|
*/
|
|
GdkGLContext *
|
|
gdk_gl_context_get_current (void)
|
|
{
|
|
MaskedContext *current;
|
|
|
|
current = g_private_get (&thread_current_context);
|
|
|
|
return unmask_context (current);
|
|
}
|
|
|
|
gboolean
|
|
gdk_gl_context_has_debug (GdkGLContext *self)
|
|
{
|
|
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (self);
|
|
|
|
return priv->debug_enabled || priv->use_khr_debug;
|
|
}
|
|
|
|
/* This is currently private! */
|
|
/* When using GL/ES, don't flip the 'R' and 'B' bits on Windows/ANGLE for glReadPixels() */
|
|
gboolean
|
|
gdk_gl_context_use_es_bgra (GdkGLContext *context)
|
|
{
|
|
if (!gdk_gl_context_get_use_es (context))
|
|
return FALSE;
|
|
|
|
#ifdef GDK_WINDOWING_WIN32
|
|
if (GDK_WIN32_IS_GL_CONTEXT (context))
|
|
return TRUE;
|
|
#endif
|
|
|
|
return FALSE;
|
|
}
|