Commit 9f1d6e1f authored by Benjamin Otte's avatar Benjamin Otte
Browse files

gl: Move vfunc

Instead of
  Display::make_gl_context_current()
we now have
  GLContext::clear_current()
  GLContext::make_current()

This fits better with the backends (we can actually implement
clearCurrent on macOS now) and makes it easier to implement different GL
backends for backends (like EGL/GLX on X11).

We also pass a surfaceless boolean to make_current() so the calling code
can decide if a surface needs to be bound or not, because the backends
were all doing whatever, which was very counterproductive.
parent 15ed1a32
......@@ -1298,21 +1298,6 @@ gdk_display_get_gl_context (GdkDisplay *self)
return priv->gl_context;
}
/*< private >
* gdk_display_make_gl_context_current:
* @display: a `GdkDisplay`
* @context: (optional): a `GdkGLContext`
*
* Makes the given @context the current GL context, or unsets
* the current GL context if @context is %NULL.
*/
gboolean
gdk_display_make_gl_context_current (GdkDisplay *display,
GdkGLContext *context)
{
return GDK_DISPLAY_GET_CLASS (display)->make_gl_context_current (display, context);
}
GdkDebugFlags
gdk_display_get_debug_flags (GdkDisplay *display)
{
......
......@@ -142,8 +142,6 @@ struct _GdkDisplayClass
GdkGLContext * (*init_gl) (GdkDisplay *display,
GError **error);
gboolean (*make_gl_context_current) (GdkDisplay *display,
GdkGLContext *context);
GdkSeat * (*get_default_seat) (GdkDisplay *display);
......@@ -209,8 +207,6 @@ GdkSurface * gdk_display_create_surface (GdkDisplay *display
int height);
GdkGLContext * gdk_display_get_gl_context (GdkDisplay *display);
gboolean gdk_display_make_gl_context_current (GdkDisplay *display,
GdkGLContext *context);
void gdk_display_set_rgba (GdkDisplay *display,
gboolean rgba);
......
......@@ -128,9 +128,10 @@ G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GdkGLContext, gdk_gl_context, GDK_TYPE_DRAW
typedef struct _MaskedContext MaskedContext;
static inline MaskedContext *
mask_context (GdkGLContext *context)
mask_context (GdkGLContext *context,
gboolean surfaceless)
{
return (MaskedContext *) GSIZE_TO_POINTER (GPOINTER_TO_SIZE (context) | (gdk_draw_context_is_in_frame (GDK_DRAW_CONTEXT (context)) ? 1 : 0));
return (MaskedContext *) GSIZE_TO_POINTER (GPOINTER_TO_SIZE (context) | (surfaceless ? 1 : 0));
}
static inline GdkGLContext *
......@@ -1138,10 +1139,12 @@ 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));
masked_context = mask_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)
......@@ -1161,12 +1164,15 @@ gdk_gl_context_make_current (GdkGLContext *context)
}
}
if (gdk_display_make_gl_context_current (gdk_draw_context_get_display (GDK_DRAW_CONTEXT (context)), context))
if (!GDK_GL_CONTEXT_GET_CLASS (context)->make_current (context, surfaceless))
{
g_object_ref (context);
g_private_replace (&thread_current_context, masked_context);
gdk_gl_context_check_extensions (context);
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);
}
/**
......@@ -1265,8 +1271,9 @@ gdk_gl_context_clear_current (void)
current = g_private_get (&thread_current_context);
if (current != NULL)
{
GdkGLContext *current_context = unmask_context (current);
if (gdk_display_make_gl_context_current (gdk_draw_context_get_display (GDK_DRAW_CONTEXT (current_context)), NULL))
GdkGLContext *context = unmask_context (current);
if (GDK_GL_CONTEXT_GET_CLASS (context)->clear_current (context))
g_private_replace (&thread_current_context, NULL);
}
}
......
......@@ -55,6 +55,9 @@ struct _GdkGLContextClass
gboolean (* realize) (GdkGLContext *context,
GError **error);
gboolean (* make_current) (GdkGLContext *context,
gboolean surfaceless);
gboolean (* clear_current) (GdkGLContext *context);
cairo_region_t * (* get_damage) (GdkGLContext *context);
gboolean (* is_shared) (GdkGLContext *self,
......
......@@ -644,19 +644,6 @@ gdk_macos_display_init_gl (GdkDisplay *display,
return _gdk_macos_gl_context_new (display, NULL, FALSE, NULL, error);
}
static gboolean
gdk_macos_display_make_gl_context_current (GdkDisplay *display,
GdkGLContext *gl_context)
{
g_assert (GDK_IS_MACOS_DISPLAY (display));
g_assert (!gl_context || GDK_IS_MACOS_GL_CONTEXT (gl_context));
if (gl_context == NULL)
return FALSE;
return _gdk_macos_gl_context_make_current (GDK_MACOS_GL_CONTEXT (gl_context));
}
static void
gdk_macos_display_finalize (GObject *object)
{
......@@ -703,7 +690,6 @@ gdk_macos_display_class_init (GdkMacosDisplayClass *klass)
display_class->get_setting = gdk_macos_display_get_setting;
display_class->has_pending = gdk_macos_display_has_pending;
display_class->init_gl = gdk_macos_display_init_gl;
display_class->make_gl_context_current = gdk_macos_display_make_gl_context_current;
display_class->notify_startup_complete = gdk_macos_display_notify_startup_complete;
display_class->queue_events = gdk_macos_display_queue_events;
display_class->sync = gdk_macos_display_sync;
......
......@@ -62,7 +62,6 @@ GdkGLContext *_gdk_macos_gl_context_new (GdkMacosDisplay *display,
gboolean attached,
GdkGLContext *share,
GError **error);
gboolean _gdk_macos_gl_context_make_current (GdkMacosGLContext *self);
G_END_DECLS
......
......@@ -403,6 +403,57 @@ gdk_macos_gl_context_surface_resized (GdkDrawContext *draw_context)
g_clear_pointer (&self->damage, cairo_region_destroy);
}
static gboolean
gdk_macos_gl_context_clear_current (GdkGLContext *context)
{
GdkMacosGLContext *self = GDK_MACOS_GL_CONTEXT (context);
NSOpenGLContext *current;
g_return_val_if_fail (GDK_IS_MACOS_GL_CONTEXT (self), FALSE);
current = [NSOpenGLContext currentContext];
if (self->gl_context == current)
{
/* The OpenGL mac programming guide suggests that glFlush() is called
* before switching current contexts to ensure that the drawing commands
* are submitted.
*/
if (current != NULL)
glFlush ();
[NSOpenGLContext clearCurrentContext];
}
return TRUE;
}
static gboolean
gdk_macos_gl_context_make_current (GdkGLContext *context,
gboolean surfaceless)
{
GdkMacosGLContext *self = GDK_MACOS_GL_CONTEXT (context);
NSOpenGLContext *current;
g_return_val_if_fail (GDK_IS_MACOS_GL_CONTEXT (self), FALSE);
current = [NSOpenGLContext currentContext];
if (self->gl_context != current)
{
/* The OpenGL mac programming guide suggests that glFlush() is called
* before switching current contexts to ensure that the drawing commands
* are submitted.
*/
if (current != NULL)
glFlush ();
[self->gl_context makeCurrentContext];
}
return TRUE;
}
static cairo_region_t *
gdk_macos_gl_context_get_damage (GdkGLContext *context)
{
......@@ -494,31 +545,4 @@ _gdk_macos_gl_context_new (GdkMacosDisplay *display,
return GDK_GL_CONTEXT (context);
}
gboolean
_gdk_macos_gl_context_make_current (GdkMacosGLContext *self)
{
NSOpenGLContext *current;
g_return_val_if_fail (GDK_IS_MACOS_GL_CONTEXT (self), FALSE);
if (self->gl_context == NULL)
return FALSE;
current = [NSOpenGLContext currentContext];
if (self->gl_context != current)
{
/* The OpenGL mac programming guide suggests that glFlush() is called
* before switching current contexts to ensure that the drawing commands
* are submitted.
*/
if (current != NULL)
glFlush ();
[self->gl_context makeCurrentContext];
}
return TRUE;
}
G_GNUC_END_IGNORE_DEPRECATIONS
......@@ -970,7 +970,6 @@ gdk_wayland_display_class_init (GdkWaylandDisplayClass *class)
display_class->get_keymap = _gdk_wayland_display_get_keymap;
display_class->init_gl = gdk_wayland_display_init_gl;
display_class->make_gl_context_current = gdk_wayland_display_make_gl_context_current;
display_class->get_monitors = gdk_wayland_display_get_monitors;
display_class->get_monitor_at_surface = gdk_wayland_display_get_monitor_at_surface;
......
......@@ -245,6 +245,37 @@ gdk_wayland_gl_context_get_damage (GdkGLContext *context)
return GDK_GL_CONTEXT_CLASS (gdk_wayland_gl_context_parent_class)->get_damage (context);
}
static gboolean
gdk_wayland_gl_context_clear_current (GdkGLContext *context)
{
GdkDisplay *display = gdk_gl_context_get_display (context);
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
return eglMakeCurrent (display_wayland->egl_display,
EGL_NO_SURFACE,
EGL_NO_SURFACE,
EGL_NO_CONTEXT);
}
static gboolean
gdk_wayland_gl_context_make_current (GdkGLContext *context,
gboolean surfaceless)
{
GdkWaylandGLContext *context_wayland = GDK_WAYLAND_GL_CONTEXT (context);
GdkDisplay *display = gdk_gl_context_get_display (context);
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
EGLSurface egl_surface;
if (!surfaceless)
egl_surface = gdk_wayland_surface_get_egl_surface (gdk_gl_context_get_surface (context));
else
egl_surface = EGL_NO_SURFACE;
return eglMakeCurrent (display_wayland->egl_display,
egl_surface,
egl_surface,
context_wayland->egl_context);
}
static void
gdk_wayland_gl_context_end_frame (GdkDrawContext *draw_context,
cairo_region_t *painted)
......@@ -309,6 +340,8 @@ gdk_wayland_gl_context_class_init (GdkWaylandGLContextClass *klass)
draw_context_class->end_frame = gdk_wayland_gl_context_end_frame;
context_class->realize = gdk_wayland_gl_context_realize;
context_class->make_current = gdk_wayland_gl_context_make_current;
context_class->clear_current = gdk_wayland_gl_context_clear_current;
context_class->get_damage = gdk_wayland_gl_context_get_damage;
}
......@@ -556,36 +589,3 @@ gdk_wayland_gl_context_dispose (GObject *gobject)
G_OBJECT_CLASS (gdk_wayland_gl_context_parent_class)->dispose (gobject);
}
gboolean
gdk_wayland_display_make_gl_context_current (GdkDisplay *display,
GdkGLContext *context)
{
GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
GdkWaylandGLContext *context_wayland;
GdkSurface *surface;
EGLSurface egl_surface;
if (context == NULL)
{
eglMakeCurrent(display_wayland->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE,
EGL_NO_CONTEXT);
return TRUE;
}
context_wayland = GDK_WAYLAND_GL_CONTEXT (context);
surface = gdk_gl_context_get_surface (context);
if (gdk_draw_context_is_in_frame (GDK_DRAW_CONTEXT (context)))
egl_surface = gdk_wayland_surface_get_egl_surface (surface);
else
egl_surface = EGL_NO_SURFACE;
if (!eglMakeCurrent (display_wayland->egl_display, egl_surface,
egl_surface, context_wayland->egl_context))
{
g_warning ("eglMakeCurrent failed");
return FALSE;
}
return TRUE;
}
......@@ -47,8 +47,6 @@ GdkGLContext * gdk_wayland_display_init_gl (GdkDisplay
GError **error);
GdkGLContext * gdk_wayland_surface_create_gl_context (GdkSurface *surface,
GError **error);
gboolean gdk_wayland_display_make_gl_context_current (GdkDisplay *display,
GdkGLContext *context);
G_END_DECLS
......
......@@ -1165,7 +1165,6 @@ gdk_win32_display_class_init (GdkWin32DisplayClass *klass)
display_class->create_surface = _gdk_win32_display_create_surface;
display_class->get_keymap = _gdk_win32_display_get_keymap;
display_class->make_gl_context_current = _gdk_win32_display_make_gl_context_current;
display_class->get_monitors = gdk_win32_display_get_monitors;
......
......@@ -1046,113 +1046,40 @@ gdk_win32_gl_context_realize (GdkGLContext *context,
return TRUE;
}
static void
gdk_win32_gl_context_class_init (GdkWin32GLContextClass *klass)
{
GdkGLContextClass *gl_context_class = GDK_GL_CONTEXT_CLASS(klass);
GdkDrawContextClass *draw_context_class = GDK_DRAW_CONTEXT_CLASS(klass);
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gl_context_class->realize = gdk_win32_gl_context_realize;
draw_context_class->begin_frame = gdk_win32_gl_context_begin_frame;
draw_context_class->end_frame = gdk_win32_gl_context_end_frame;
gobject_class->dispose = _gdk_win32_gl_context_dispose;
}
static void
gdk_win32_gl_context_init (GdkWin32GLContext *self)
{
}
GdkGLContext *
_gdk_win32_surface_create_gl_context (GdkSurface *surface,
GError **error)
static gboolean
gdk_win32_gl_context_clear_current (GdkGLContext *context)
{
GdkDisplay *display = gdk_surface_get_display (surface);
GdkDisplay *display = gdk_gl_context_get_display (context);
GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (display);
GdkWin32GLContext *context = NULL;
GdkWin32Surface *impl = GDK_WIN32_SURFACE (surface);
#ifdef GDK_WIN32_ENABLE_EGL
EGLContext egl_context;
EGLConfig config;
#endif
impl->hdc = GetDC (GDK_SURFACE_HWND (surface));
#ifdef GDK_WIN32_ENABLE_EGL
/* display_win32->hdc_egl_temp should *not* be destroyed here! It is destroyed at dispose()! */
display_win32->hdc_egl_temp = impl->hdc;
#endif
if (!_gdk_win32_display_init_gl (display))
{
g_set_error_literal (error, GDK_GL_ERROR,
GDK_GL_ERROR_NOT_AVAILABLE,
_("No GL implementation is available"));
return NULL;
}
#ifdef GDK_WIN32_ENABLE_EGL
if (display_win32->have_egl && !find_eglconfig_for_window (display_win32, &config,
&display_win32->egl_min_swap_interval, error))
return NULL;
#endif
context = g_object_new (GDK_TYPE_WIN32_GL_CONTEXT,
"surface", surface,
NULL);
context->gl_hdc = impl->hdc;
#ifdef GDK_WIN32_ENABLE_EGL
if (display_win32->have_egl)
context->egl_config = config;
if (display_win32->egl_disp != EGL_NO_DISPLAY)
return eglMakeCurrent (display_win32->egl_disp,
EGL_NO_SURFACE,
EGL_NO_SURFACE,
EGL_NO_CONTEXT);
else
#endif
return GDK_GL_CONTEXT (context);
return wglMakeCurrent (NULL, NULL);
}
gboolean
_gdk_win32_display_make_gl_context_current (GdkDisplay *display,
GdkGLContext *context)
static gboolean
gdk_win32_gl_context_make_current (GdkGLContext *context,
gboolean surfaceless)
{
GdkWin32GLContext *context_win32;
GdkWin32GLContext *context_win32 = GDK_WIN32_GL_CONTEXT (context);
GdkDisplay *display = gdk_gl_context_get_display (context);
GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (display);
GdkSurface *surface;
gboolean do_frame_sync = FALSE;
if (context == NULL)
{
#ifdef GDK_WIN32_ENABLE_EGL
if (display_win32->egl_disp != EGL_NO_DISPLAY)
eglMakeCurrent(display_win32->egl_disp,
EGL_NO_SURFACE,
EGL_NO_SURFACE,
EGL_NO_CONTEXT);
else
#endif
wglMakeCurrent(NULL, NULL);
return TRUE;
}
context_win32 = GDK_WIN32_GL_CONTEXT (context);
if (!gdk_gl_context_get_use_es (context))
{
if (!wglMakeCurrent (context_win32->gl_hdc, context_win32->hglrc))
{
GDK_NOTE (OPENGL,
g_print ("Making WGL context current failed\n"));
return FALSE;
}
return FALSE;
if (gdk_draw_context_is_in_frame (GDK_DRAW_CONTEXT (context)) &&
display_win32->hasWglEXTSwapControl)
if (!surfaceless && display_win32->hasWglEXTSwapControl)
{
surface = gdk_gl_context_get_surface (context);
......@@ -1182,7 +1109,7 @@ _gdk_win32_display_make_gl_context_current (GdkDisplay *display,
surface = gdk_gl_context_get_surface (context);
if (gdk_draw_context_is_in_frame (GDK_DRAW_CONTEXT (context)))
if (!surfaceless)
egl_surface = _gdk_win32_surface_get_egl_surface (surface, context_win32->egl_config, FALSE);
else
{
......@@ -1196,10 +1123,7 @@ _gdk_win32_display_make_gl_context_current (GdkDisplay *display,
egl_surface,
egl_surface,
context_win32->egl_context))
{
g_warning ("eglMakeCurrent failed");
return FALSE;
}
return FALSE;
if (display_win32->egl_min_swap_interval == 0)
eglSwapInterval (display_win32->egl_disp, 0);
......@@ -1211,6 +1135,75 @@ _gdk_win32_display_make_gl_context_current (GdkDisplay *display,
return TRUE;
}
static void
gdk_win32_gl_context_class_init (GdkWin32GLContextClass *klass)
{
GdkGLContextClass *gl_context_class = GDK_GL_CONTEXT_CLASS(klass);
GdkDrawContextClass *draw_context_class = GDK_DRAW_CONTEXT_CLASS(klass);
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gl_context_class->realize = gdk_win32_gl_context_realize;
draw_context_class->begin_frame = gdk_win32_gl_context_begin_frame;
draw_context_class->end_frame = gdk_win32_gl_context_end_frame;
gobject_class->dispose = _gdk_win32_gl_context_dispose;
}
static void
gdk_win32_gl_context_init (GdkWin32GLContext *self)
{
}
GdkGLContext *
_gdk_win32_surface_create_gl_context (GdkSurface *surface,
GError **error)
{
GdkDisplay *display = gdk_surface_get_display (surface);
GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (display);
GdkWin32GLContext *context = NULL;
GdkWin32Surface *impl = GDK_WIN32_SURFACE (surface);
#ifdef GDK_WIN32_ENABLE_EGL
EGLContext egl_context;
EGLConfig config;
#endif
impl->hdc = GetDC (GDK_SURFACE_HWND (surface));
#ifdef GDK_WIN32_ENABLE_EGL
/* display_win32->hdc_egl_temp should *not* be destroyed here! It is destroyed at dispose()! */
display_win32->hdc_egl_temp = impl->hdc;
#endif
if (!_gdk_win32_display_init_gl (display))
{
g_set_error_literal (error, GDK_GL_ERROR,
GDK_GL_ERROR_NOT_AVAILABLE,
_("No GL implementation is available"));
return NULL;
}
#ifdef GDK_WIN32_ENABLE_EGL
if (display_win32->have_egl && !find_eglconfig_for_window (display_win32, &config,
&display_win32->egl_min_swap_interval, error))
return NULL;
#endif
context = g_object_new (GDK_TYPE_WIN32_GL_CONTEXT,
"surface", surface,
NULL);
context->gl_hdc = impl->hdc;
#ifdef GDK_WIN32_ENABLE_EGL
if (display_win32->have_egl)
context->egl_config = config;
#endif
return GDK_GL_CONTEXT (context);
}
/**
* gdk_win32_display_get_wgl_version:
* @display: a `GdkDisplay`
......
......@@ -63,9 +63,6 @@ GdkGLContext *
_gdk_win32_surface_create_gl_context (GdkSurface *window,
GError **error);
gboolean
_gdk_win32_display_make_gl_context_current (GdkDisplay *display,
GdkGLContext *context);
void
_gdk_win32_surface_invalidate_egl_framebuffer (GdkSurface *surface);
......
......@@ -2923,7 +2923,6 @@ gdk_x11_display_class_init (GdkX11DisplayClass * class)
display_class->get_keymap = gdk_x11_display_get_keymap;
display_class->init_gl = gdk_x11_display_init_gl;
display_class->make_gl_context_current = gdk_x11_display_make_gl_context_current;
display_class->get_default_seat = gdk_x11_display_get_default_seat;
......
......@@ -360,6 +360,70 @@ gdk_x11_gl_context_egl_end_frame (GdkDrawContext *draw_context,
eglSwapBuffers (display_x11->egl_display, egl_surface);
}
static gboolean
gdk_x11_gl_context_egl_clear_current (GdkGLContext *context)
{
GdkDisplay *display = gdk_gl_context_get_display (context);
GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
return eglMakeCurrent (display_x11->egl_display,
EGL_NO_SURFACE,
EGL_NO_SURFACE,
EGL_NO_CONTEXT);
}
static gboolean
gdk_x11_gl_context_egl_make_current (GdkGLContext *context,
gboolean surfaceless)