[gtk/wip/nobody/517-quartz-gl-context: 1/2] quartz: implement GdkGLContext for Quartz backend



commit f34709807f5b2f56a86bc3127e59084936ce57fe
Author: Brion Vibber <brion pobox com>
Date:   Sat Nov 15 16:04:58 2014 -0800

    quartz: implement GdkGLContext for Quartz backend
    
    Current problems:
    * other widgets in a GL-painted window are low-resolution on Retina
      display
    * something wrong with paint updates; gdkgears demo only updates every
      couple of seconds but reports ~30fps
    
    See: #517

 gdk/quartz/Makefile.am           |   1 +
 gdk/quartz/gdkdisplay-quartz.c   |   2 +
 gdk/quartz/gdkglcontext-quartz.c | 167 ++++++++++++++++++++++++++++++++++++++-
 gdk/quartz/gdkglcontext-quartz.h |  23 ++++++
 gdk/quartz/gdkquartzglcontext.h  |  45 +++++++++++
 gdk/quartz/gdkwindow-quartz.c    |   1 +
 6 files changed, 235 insertions(+), 4 deletions(-)
---
diff --git a/gdk/quartz/Makefile.am b/gdk/quartz/Makefile.am
index 3ba039304d..9646f8687c 100644
--- a/gdk/quartz/Makefile.am
+++ b/gdk/quartz/Makefile.am
@@ -64,6 +64,7 @@ libgdkquartzinclude_HEADERS =         \
        gdkquartzdisplay.h              \
        gdkquartzdisplaymanager.h       \
        gdkquartzdnd.h                  \
+       gdkquartzglcontext.h            \
        gdkquartzkeys.h                 \
        gdkquartzmonitor.h              \
        gdkquartzscreen.h               \
diff --git a/gdk/quartz/gdkdisplay-quartz.c b/gdk/quartz/gdkdisplay-quartz.c
index ed81f9cc48..800f6edae1 100644
--- a/gdk/quartz/gdkdisplay-quartz.c
+++ b/gdk/quartz/gdkdisplay-quartz.c
@@ -31,6 +31,7 @@
 #include "gdkmonitorprivate.h"
 #include "gdkdisplay-quartz.h"
 #include "gdkmonitor-quartz.h"
+#include "gdkglcontext-quartz.h"
 
 /* Note about coordinates: There are three coordinate systems at play:
  *
@@ -584,6 +585,7 @@ gdk_quartz_display_class_init (GdkQuartzDisplayClass *class)
   display_class->get_monitor = gdk_quartz_display_get_monitor;
   display_class->get_primary_monitor = gdk_quartz_display_get_primary_monitor;
   display_class->get_monitor_at_window = gdk_quartz_display_get_monitor_at_window;
+  display_class->make_gl_context_current = gdk_quartz_display_make_gl_context_current;
 
   /**
    * GdkQuartzDisplay::monitors-changed:
diff --git a/gdk/quartz/gdkglcontext-quartz.c b/gdk/quartz/gdkglcontext-quartz.c
index a6cc3b6a35..f259eef8e3 100644
--- a/gdk/quartz/gdkglcontext-quartz.c
+++ b/gdk/quartz/gdkglcontext-quartz.c
@@ -24,16 +24,175 @@
 
 #include "gdkglcontext-quartz.h"
 
+#include "gdkquartzdisplay.h"
+#include "gdkquartzglcontext.h"
+#include "gdkquartzwindow.h"
+#include "gdkprivate-quartz.h"
+
+#include "gdkinternals.h"
+
 #include "gdkintl.h"
 
+G_DEFINE_TYPE (GdkQuartzGLContext, gdk_quartz_gl_context, GDK_TYPE_GL_CONTEXT)
+
+static void gdk_quartz_gl_context_dispose (GObject *gobject);
+
+void
+gdk_quartz_window_invalidate_for_new_frame (GdkWindow      *window,
+                                            cairo_region_t *update_area)
+{
+  cairo_rectangle_int_t window_rect;
+
+  /* Minimal update is ok if we're not drawing with gl */
+  if (window->gl_paint_context == NULL)
+    return;
+
+  window_rect.x = 0;
+  window_rect.y = 0;
+  window_rect.width = gdk_window_get_width (window);
+  window_rect.height = gdk_window_get_height (window);
+
+  /* If nothing else is known, repaint everything so that the back
+  buffer is fully up-to-date for the swapbuffer */
+  cairo_region_union_rectangle (update_area, &window_rect);
+}
+
+static gboolean
+gdk_quartz_gl_context_realize (GdkGLContext *context,
+                               GError      **error)
+{
+  return TRUE;
+}
+
+static void
+gdk_quartz_gl_context_end_frame (GdkGLContext *context,
+                                 cairo_region_t *painted,
+                                 cairo_region_t *damage)
+{
+  GdkQuartzGLContext *context_quartz = GDK_QUARTZ_GL_CONTEXT (context);
+
+  [context_quartz->gl_context flushBuffer];
+}
+
+static void
+gdk_quartz_gl_context_class_init (GdkQuartzGLContextClass *klass)
+{
+  GdkGLContextClass *context_class = GDK_GL_CONTEXT_CLASS (klass);
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  context_class->realize = gdk_quartz_gl_context_realize;
+  context_class->end_frame = gdk_quartz_gl_context_end_frame;
+  gobject_class->dispose = gdk_quartz_gl_context_dispose;
+}
+
+static void
+gdk_quartz_gl_context_init (GdkQuartzGLContext *self)
+{
+}
+
+gboolean
+gdk_quartz_display_init_gl (GdkDisplay *display)
+{
+  return TRUE;
+}
+
 GdkGLContext *
 gdk_quartz_window_create_gl_context (GdkWindow     *window,
                                      gboolean       attached,
                                      GdkGLContext  *share,
                                      GError       **error)
 {
-  /* FIXME: implement */
-  g_set_error_literal (error, GDK_GL_ERROR, GDK_GL_ERROR_NOT_AVAILABLE,
-                       _("Not implemented on OS X"));
-  return NULL;
+  GdkDisplay *display = gdk_window_get_display (window);
+  GdkQuartzGLContext *context;
+  NSOpenGLContext *ctx;
+  NSOpenGLPixelFormatAttribute attrs[] =
+    {
+      NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
+      NSOpenGLPFADoubleBuffer,
+      NSOpenGLPFAColorSize, 24,
+      NSOpenGLPFAAlphaSize, 8,
+      0
+    };
+  NSOpenGLPixelFormat *format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
+
+  if (format == NULL)
+    {
+      g_set_error_literal (error, GDK_GL_ERROR,
+                           GDK_GL_ERROR_NOT_AVAILABLE,
+                           _("Unable to create a GL pixel format"));
+      return NULL;
+    }
+
+  ctx = [[NSOpenGLContext alloc] initWithFormat:format
+                                 shareContext:share ? GDK_QUARTZ_GL_CONTEXT (share)->gl_context : nil];
+  if (ctx == NULL)
+    {
+      g_set_error_literal (error, GDK_GL_ERROR,
+                           GDK_GL_ERROR_NOT_AVAILABLE,
+                           _("Unable to create a GL context"));
+      return NULL;
+    }
+
+  [format release];
+
+  if (attached)
+    {
+      NSView *view = gdk_quartz_window_get_nsview (window);
+
+      if ([view respondsToSelector:@selector(setWantsBestResolutionOpenGLSurface:)])
+        [view setWantsBestResolutionOpenGLSurface:YES];
+
+      GLint sync_to_framerate = 1;
+      [ctx setValues:&sync_to_framerate forParameter:NSOpenGLCPSwapInterval];
+
+      [ctx setView:view];
+    }
+
+  GDK_NOTE (OPENGL,
+            g_print ("Created NSOpenGLContext[%p]\n", ctx));
+
+  context = g_object_new (GDK_TYPE_QUARTZ_GL_CONTEXT,
+                          "window", window,
+                          "display", display,
+                          "shared-context", share,
+                          NULL);
+
+  context->gl_context = ctx;
+  context->is_attached = attached;
+
+  return GDK_GL_CONTEXT (context);
+}
+
+static void
+gdk_quartz_gl_context_dispose (GObject *gobject)
+{
+  GdkQuartzGLContext *context_quartz = GDK_QUARTZ_GL_CONTEXT (gobject);
+
+  if (context_quartz->gl_context != NULL)
+    {
+      [context_quartz->gl_context clearDrawable];
+      [context_quartz->gl_context release];
+      context_quartz->gl_context = NULL;
+    }
+
+  G_OBJECT_CLASS (gdk_quartz_gl_context_parent_class)->dispose (gobject);
+}
+
+gboolean
+gdk_quartz_display_make_gl_context_current (GdkDisplay   *display,
+                                            GdkGLContext *context)
+{
+  GdkQuartzGLContext *context_quartz;
+
+  if (context == NULL)
+    {
+      [NSOpenGLContext clearCurrentContext];
+      return TRUE;
+    }
+
+  context_quartz = GDK_QUARTZ_GL_CONTEXT (context);
+
+  [context_quartz->gl_context makeCurrentContext];
+
+  return TRUE;
 }
diff --git a/gdk/quartz/gdkglcontext-quartz.h b/gdk/quartz/gdkglcontext-quartz.h
index bc55a57032..b9e5e74dea 100644
--- a/gdk/quartz/gdkglcontext-quartz.h
+++ b/gdk/quartz/gdkglcontext-quartz.h
@@ -24,17 +24,40 @@
 #define __GDK_QUARTZ_GL_CONTEXT__
 
 #include "gdkglcontextprivate.h"
+#include "gdkdisplayprivate.h"
 #include "gdkvisual.h"
 #include "gdkwindow.h"
 #include "gdkinternals.h"
 #include "gdkmain.h"
 
+#import <OpenGL/OpenGL.h>
+#import <OpenGL/gl.h>
+#import <AppKit/AppKit.h>
+
 G_BEGIN_DECLS
 
+struct _GdkQuartzGLContext
+{
+  GdkGLContext parent_instance;
+
+  NSOpenGLContext *gl_context;
+  gboolean is_attached;
+};
+
+struct _GdkQuartzGLContextClass
+{
+  GdkGLContextClass parent_class;
+};
+
+gboolean        gdk_quartz_display_init_gl                         (GdkDisplay        *display);
 GdkGLContext *  gdk_quartz_window_create_gl_context                (GdkWindow         *window,
                                                                     gboolean           attach,
                                                                     GdkGLContext      *share,
                                                                     GError           **error);
+void            gdk_quartz_window_invalidate_for_new_frame         (GdkWindow         *window,
+                                                                    cairo_region_t    *update_area);
+gboolean        gdk_quartz_display_make_gl_context_current         (GdkDisplay        *display,
+                                                                    GdkGLContext      *context);
 
 G_END_DECLS
 
diff --git a/gdk/quartz/gdkquartzglcontext.h b/gdk/quartz/gdkquartzglcontext.h
new file mode 100644
index 0000000000..8fadaf1384
--- /dev/null
+++ b/gdk/quartz/gdkquartzglcontext.h
@@ -0,0 +1,45 @@
+/* GDK - The GIMP Drawing Kit
+ *
+ * gdkquartzglcontext.h: Quartz specific OpenGL wrappers
+ *
+ * Copyright © 2014  Emmanuele Bassi
+ * Copyright © 2014  Brion Vibber
+ *
+ * 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/>.
+ */
+
+#ifndef __GDK_QUARTZ_GL_CONTEXT_H__
+#define __GDK_QUARTZ_GL_CONTEXT_H__
+
+#if !defined (__GDKQUARTZ_H_INSIDE__) && !defined (GDK_COMPILATION)
+#error "Only <gdk/gdkquartz.h> can be included directly."
+#endif
+
+#include <gdk/gdk.h>
+
+G_BEGIN_DECLS
+
+#define GDK_TYPE_QUARTZ_GL_CONTEXT   (gdk_quartz_gl_context_get_type ())
+#define GDK_QUARTZ_GL_CONTEXT(obj)   (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_QUARTZ_GL_CONTEXT, 
GdkQuartzGLContext))
+#define GDK_QUARTZ_IS_GL_CONTEXT(obj)  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_QUARTZ_GL_CONTEXT))
+
+typedef struct _GdkQuartzGLContext   GdkQuartzGLContext;
+typedef struct _GdkQuartzGLContextClass  GdkQuartzGLContextClass;
+
+GDK_AVAILABLE_IN_3_24
+GType gdk_quartz_gl_context_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __GDK_QUARTZ_GL_CONTEXT_H__ */
diff --git a/gdk/quartz/gdkwindow-quartz.c b/gdk/quartz/gdkwindow-quartz.c
index 3b0b565de2..bc601bf709 100644
--- a/gdk/quartz/gdkwindow-quartz.c
+++ b/gdk/quartz/gdkwindow-quartz.c
@@ -3073,6 +3073,7 @@ gdk_window_impl_quartz_class_init (GdkWindowImplQuartzClass *klass)
   impl_class->delete_property = _gdk_quartz_window_delete_property;
 
   impl_class->create_gl_context = gdk_quartz_window_create_gl_context;
+  impl_class->invalidate_for_new_frame = gdk_quartz_window_invalidate_for_new_frame;
 
   impl_quartz_class->get_context = gdk_window_impl_quartz_get_context;
   impl_quartz_class->release_context = gdk_window_impl_quartz_release_context;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]