[gtk/wip/chergert/gdk-macos-gl-renderer: 6/26] macos: add basic GL view and wire up GL context to use it




commit 0076e4ccedaf7be3b70aae4209139a546ca056d4
Author: Christian Hergert <chergert redhat com>
Date:   Wed Oct 21 17:09:19 2020 -0700

    macos: add basic GL view and wire up GL context to use it
    
    This creates a new GdkMacosGLView and adds it to the
    GdkMacosWindow when a GdkGLContext has been requested.
    
    Currently, a number of features of the GL renderer are not working
    and require further tweaking. For example, textures do not seem
    to be working correctly (icons, text, and shadows) and more work
    is necessary to discover why.

 gdk/macos/GdkMacosGLView.c            | 203 ++++++++++++++++++++++++++++++++
 gdk/macos/GdkMacosGLView.h            |  47 ++++++++
 gdk/macos/gdkmacosglcontext-private.h |  10 +-
 gdk/macos/gdkmacosglcontext.c         | 214 ++++++++++++++++++++++++----------
 gdk/macos/meson.build                 |   1 +
 5 files changed, 412 insertions(+), 63 deletions(-)
---
diff --git a/gdk/macos/GdkMacosGLView.c b/gdk/macos/GdkMacosGLView.c
new file mode 100644
index 0000000000..4485bacca5
--- /dev/null
+++ b/gdk/macos/GdkMacosGLView.c
@@ -0,0 +1,203 @@
+/* GdkMacosGLView.c
+ *
+ * Copyright 2020 Christian Hergert <chergert redhat com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "config.h"
+
+#include <CoreGraphics/CoreGraphics.h>
+#include <OpenGL/gl.h>
+
+#include "gdkinternals.h"
+#include "gdkmacossurface-private.h"
+
+#import "GdkMacosGLView.h"
+
+@implementation GdkMacosGLView
+
+G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+
++(NSOpenGLPixelFormat *)defaultPixelFormat
+{
+  static const NSOpenGLPixelFormatAttribute attrs[] = {
+    NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion4_1Core,
+    NSOpenGLPFAAccelerated,
+    NSOpenGLPFADoubleBuffer,
+    NSOpenGLPFADepthSize, 32,
+    NSOpenGLPFAStencilSize, 8,
+
+    (NSOpenGLPixelFormatAttribute)nil
+  };
+
+  return [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
+}
+
+-(id)initWithFrame:(NSRect)frameRect pixelFormat:(NSOpenGLPixelFormat*)format
+{
+  self = [super initWithFrame:frameRect];
+
+  if (self != nil)
+    {
+      NSNotificationCenter *center;
+
+      _pixelFormat = [format retain];
+      center = [NSNotificationCenter defaultCenter];
+
+      [center addObserver:self
+                 selector:@selector(_surfaceNeedsUpdate:)
+                     name:NSViewGlobalFrameDidChangeNotification
+                   object:self];
+
+      [center addObserver:self
+                 selector:@selector(_surfaceNeedsUpdate:)
+                     name:NSViewFrameDidChangeNotification
+                   object:self];
+    }
+
+  return self;
+}
+
+-(void)setPixelFormat:(NSOpenGLPixelFormat*)pixelFormat
+{
+  _pixelFormat = pixelFormat;
+}
+
+-(NSOpenGLPixelFormat*)pixelFormat
+{
+  return _pixelFormat;
+}
+
+-(void)_surfaceNeedsUpdate:(NSNotification *)notification
+{
+  [[self openGLContext] makeCurrentContext];
+  [self update];
+  [self reshape];
+}
+
+-(void)reshape
+{
+  [self update];
+}
+
+-(void)lockFocus
+{
+  NSOpenGLContext *context;
+
+  [super lockFocus];
+
+  context = [self openGLContext];
+
+  if ([context view] != self)
+    [context setView: self];
+}
+
+-(void)viewDidMoveToWindow
+{
+  [super viewDidMoveToWindow];
+
+  if ([self window] == nil)
+    {
+      [[self openGLContext] clearDrawable];
+      return;
+    }
+
+  [[self openGLContext] setView: self];
+}
+
+-(void)update
+{
+  [[self openGLContext] update];
+}
+
+-(void)drawRect:(NSRect)rect
+{
+}
+
+-(void)clearGLContext
+{
+  _openGLContext = nil;
+}
+
+-(void)setOpenGLContext:(NSOpenGLContext*)context
+{
+  [context setView:self];
+  _openGLContext = context;
+}
+
+-(NSOpenGLContext *)openGLContext
+{
+  return _openGLContext;
+}
+
+-(void)dealloc
+{
+  NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
+
+  [center removeObserver:self
+                    name:NSViewGlobalFrameDidChangeNotification
+                  object:self];
+
+  [center removeObserver:self
+                    name:NSViewFrameDidChangeNotification
+                  object:self];
+
+  [super dealloc];
+}
+
+-(BOOL)isOpaque
+{
+  return NO;
+}
+
+-(BOOL)isFlipped
+{
+  return YES;
+}
+
+-(BOOL)acceptsFirstMouse
+{
+  return YES;
+}
+
+-(BOOL)mouseDownCanMoveWindow
+{
+  return NO;
+}
+
+-(void)invalidateRegion:(const cairo_region_t *)region
+{
+  if (region != NULL)
+    {
+      guint n_rects = cairo_region_num_rectangles (region);
+
+      for (guint i = 0; i < n_rects; i++)
+        {
+          cairo_rectangle_int_t rect;
+          NSRect nsrect;
+
+          cairo_region_get_rectangle (region, i, &rect);
+          nsrect = NSMakeRect (rect.x, rect.y, rect.width, rect.height);
+
+          [self setNeedsDisplayInRect:nsrect];
+        }
+    }
+}
+
+G_GNUC_END_IGNORE_DEPRECATIONS
+
+@end
diff --git a/gdk/macos/GdkMacosGLView.h b/gdk/macos/GdkMacosGLView.h
new file mode 100644
index 0000000000..855b345bbc
--- /dev/null
+++ b/gdk/macos/GdkMacosGLView.h
@@ -0,0 +1,47 @@
+/* GdkMacosGLView.h
+ *
+ * Copyright © 2020 Red Hat, Inc.
+ * Copyright © 2005-2007 Imendio AB
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include <cairo.h>
+
+#import "GdkMacosBaseView.h"
+
+#define GDK_IS_MACOS_GL_VIEW(obj) ((obj) && [obj isKindOfClass:[GdkMacosGLView class]])
+
+G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+
+@interface GdkMacosGLView : GdkMacosBaseView
+{
+  NSOpenGLContext     *_openGLContext;
+  NSOpenGLPixelFormat *_pixelFormat;
+}
+
++(NSOpenGLPixelFormat*)defaultPixelFormat;
+-(id)initWithFrame:(NSRect)frameRect pixelFormat:(NSOpenGLPixelFormat*)format;
+-(void)setOpenGLContext:(NSOpenGLContext*)context;
+-(NSOpenGLContext *)openGLContext;
+-(void)update;
+-(void)setPixelFormat:(NSOpenGLPixelFormat*)pixelFormat;
+-(NSOpenGLPixelFormat*)pixelFormat;
+-(void)invalidateRegion:(const cairo_region_t *)region;
+
+G_GNUC_END_IGNORE_DEPRECATIONS
+
+@end
diff --git a/gdk/macos/gdkmacosglcontext-private.h b/gdk/macos/gdkmacosglcontext-private.h
index e976939eb1..a7417026fb 100644
--- a/gdk/macos/gdkmacosglcontext-private.h
+++ b/gdk/macos/gdkmacosglcontext-private.h
@@ -37,11 +37,13 @@ struct _GdkMacosGLContext
 {
   GdkGLContext parent_instance;
 
-  G_GNUC_BEGIN_IGNORE_DEPRECATIONS
-  NSOpenGLContext *gl_context;
-  G_GNUC_END_IGNORE_DEPRECATIONS
+  guint is_attached : 1;
 
-  gboolean is_attached;
+  struct {
+    int width;
+    int height;
+    guint needed : 1;
+  } resize;
 };
 
 struct _GdkMacosGLContextClass
diff --git a/gdk/macos/gdkmacosglcontext.c b/gdk/macos/gdkmacosglcontext.c
index 0d1e03e1d2..38a42634f4 100644
--- a/gdk/macos/gdkmacosglcontext.c
+++ b/gdk/macos/gdkmacosglcontext.c
@@ -25,32 +25,165 @@
 #include "gdkinternals.h"
 #include "gdkintl.h"
 
+#include <OpenGL/gl.h>
+
+#import "GdkMacosGLView.h"
+
 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
 
 G_DEFINE_TYPE (GdkMacosGLContext, gdk_macos_gl_context, GDK_TYPE_GL_CONTEXT)
 
+static NSOpenGLContext *
+get_ns_open_gl_context (GdkMacosGLContext  *self,
+                        GError            **error)
+{
+  NSOpenGLContext *gl_context = nil;
+  GdkSurface *surface;
+  NSView *nsview;
+
+  g_assert (GDK_IS_MACOS_GL_CONTEXT (self));
+
+  if (!(surface = gdk_draw_context_get_surface (GDK_DRAW_CONTEXT (self))) ||
+      !(nsview = _gdk_macos_surface_get_view (GDK_MACOS_SURFACE (surface))) ||
+      !GDK_IS_MACOS_GL_VIEW (nsview) ||
+      !(gl_context = [(GdkMacosGLView *)nsview openGLContext]))
+    {
+      g_set_error_literal (error,
+                           GDK_GL_ERROR,
+                           GDK_GL_ERROR_NOT_AVAILABLE,
+                           "Cannot access NSOpenGLContext for surface");
+      return NULL;
+    }
+
+  return gl_context;
+}
+
+static gboolean
+gdk_macos_gl_context_real_realize (GdkGLContext  *context,
+                                   GError       **error)
+{
+  GdkMacosGLContext *self = (GdkMacosGLContext *)context;
+  GdkSurface *surface;
+  NSView *nsview;
+
+  g_assert (GDK_IS_MACOS_GL_CONTEXT (self));
+
+  surface = gdk_draw_context_get_surface (GDK_DRAW_CONTEXT (context));
+  nsview = _gdk_macos_surface_get_view (GDK_MACOS_SURFACE (surface));
+
+  if (!GDK_IS_MACOS_GL_VIEW (nsview))
+    {
+      NSOpenGLPixelFormat *pixelFormat;
+      NSOpenGLContext *shared_gl_context = nil;
+      NSOpenGLContext *gl_context;
+      GdkMacosGLView *gl_view;
+      GdkGLContext *shared;
+      NSWindow *nswindow;
+      NSRect contentRect;
+      GLint sync_to_framerate = 1;
+      GLint opaque = 0;
+
+      if ((shared = gdk_gl_context_get_shared_context (context)))
+        {
+          if (!(shared_gl_context = get_ns_open_gl_context (GDK_MACOS_GL_CONTEXT (shared), error)))
+            return FALSE;
+        }
+
+      nswindow = _gdk_macos_surface_get_native (GDK_MACOS_SURFACE (surface));
+      pixelFormat = [GdkMacosGLView defaultPixelFormat];
+      gl_context = [[NSOpenGLContext alloc] initWithFormat:pixelFormat
+                                              shareContext:shared_gl_context];
+
+      if (gl_context == nil)
+        {
+          [pixelFormat release];
+          g_set_error_literal (error,
+                               GDK_GL_ERROR,
+                               GDK_GL_ERROR_NOT_AVAILABLE,
+                               "Failed to create NSOpenGLContext");
+          return FALSE;
+        }
+
+      [gl_context setValues:&sync_to_framerate forParameter:NSOpenGLCPSwapInterval];
+      [gl_context setValues:&opaque forParameter:NSOpenGLCPSurfaceOpacity];
+
+      GDK_NOTE (OPENGL,
+                g_print ("Created NSOpenGLContext[%p]\n", gl_context));
+
+      contentRect = [[nswindow contentView] bounds];
+      gl_view = [[GdkMacosGLView alloc] initWithFrame:contentRect
+                                          pixelFormat:pixelFormat];
+      [nswindow setContentView:gl_view];
+      [gl_view setOpenGLContext:gl_context];
+      [gl_view setWantsBestResolutionOpenGLSurface:YES];
+      [gl_view setPostsFrameChangedNotifications: YES];
+      [gl_view setNeedsDisplay:YES];
+
+      [gl_context makeCurrentContext];
+
+      [gl_view release];
+      [pixelFormat release];
+    }
+
+  g_assert (get_ns_open_gl_context (self, NULL) != NULL);
+
+  return TRUE;
+}
+
+static void
+gdk_macos_gl_context_begin_frame (GdkDrawContext *context,
+                                  cairo_region_t *painted)
+{
+  g_assert (GDK_IS_MACOS_GL_CONTEXT (context));
+
+  GDK_DRAW_CONTEXT_CLASS (gdk_macos_gl_context_parent_class)->begin_frame (context, painted);
+}
+
 static void
 gdk_macos_gl_context_end_frame (GdkDrawContext *context,
                                 cairo_region_t *painted)
 {
   GdkMacosGLContext *self = GDK_MACOS_GL_CONTEXT (context);
+  NSOpenGLContext *gl_context;
 
   g_assert (GDK_IS_MACOS_GL_CONTEXT (self));
 
-  [self->gl_context flushBuffer];
+  if ((gl_context = get_ns_open_gl_context (self, NULL)))
+    {
+      GdkMacosSurface *surface;
+      NSView *nsview;
+
+      surface = GDK_MACOS_SURFACE (gdk_draw_context_get_surface (context));
+      nsview = _gdk_macos_surface_get_view (surface);
+      [(GdkMacosGLView *)nsview invalidateRegion:painted];
+
+      [gl_context flushBuffer];
+    }
+}
+
+static void
+gdk_macos_gl_context_surface_resized (GdkDrawContext *draw_context)
+{
+  GdkMacosGLContext *self = (GdkMacosGLContext *)draw_context;
+  GdkSurface *surface;
+
+  g_assert (GDK_IS_MACOS_GL_CONTEXT (self));
+
+  surface = gdk_draw_context_get_surface (draw_context);
+
+  self->resize.needed = TRUE;
+  self->resize.width = surface->width;
+  self->resize.height = surface->height;
 }
 
 static void
 gdk_macos_gl_context_dispose (GObject *gobject)
 {
-  GdkMacosGLContext *context_macos = GDK_MACOS_GL_CONTEXT (gobject);
+  GdkMacosGLContext *self = GDK_MACOS_GL_CONTEXT (gobject);
+  NSOpenGLContext *gl_context;
 
-  if (context_macos->gl_context != NULL)
-    {
-      [context_macos->gl_context clearDrawable];
-      [context_macos->gl_context release];
-      context_macos->gl_context = NULL;
-    }
+  if ((gl_context = get_ns_open_gl_context (self, NULL)))
+    [gl_context clearDrawable];
 
   G_OBJECT_CLASS (gdk_macos_gl_context_parent_class)->dispose (gobject);
 }
@@ -60,10 +193,15 @@ gdk_macos_gl_context_class_init (GdkMacosGLContextClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
   GdkDrawContextClass *draw_context_class = GDK_DRAW_CONTEXT_CLASS (klass);
+  GdkGLContextClass *gl_class = GDK_GL_CONTEXT_CLASS (klass);
 
   object_class->dispose = gdk_macos_gl_context_dispose;
 
+  draw_context_class->begin_frame = gdk_macos_gl_context_begin_frame;
   draw_context_class->end_frame = gdk_macos_gl_context_end_frame;
+  draw_context_class->surface_resized = gdk_macos_gl_context_surface_resized;
+
+  gl_class->realize = gdk_macos_gl_context_real_realize;
 }
 
 static void
@@ -77,77 +215,35 @@ _gdk_macos_gl_context_new (GdkMacosSurface  *surface,
                            GdkGLContext     *share,
                            GError          **error)
 {
-  static const NSOpenGLPixelFormatAttribute attrs[] = {
-    NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
-    NSOpenGLPFADoubleBuffer,
-    NSOpenGLPFAColorSize, 24,
-    NSOpenGLPFAAlphaSize, 8,
-    0
-  };
-
-  NSOpenGLPixelFormat *format;
-  GdkMacosGLContext *context = NULL;
-  NSOpenGLContext *ctx;
-  GdkDisplay *display;
-  NSView *nsview;
-  GLint sync_to_framerate = 1;
+  GdkMacosGLContext *context;
 
   g_return_val_if_fail (GDK_IS_MACOS_SURFACE (surface), NULL);
   g_return_val_if_fail (!share || GDK_IS_MACOS_GL_CONTEXT (share), NULL);
 
-  display = gdk_surface_get_display (GDK_SURFACE (surface));
-
-  if (!(format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs]))
-    {
-      g_set_error_literal (error,
-                           GDK_GL_ERROR,
-                           GDK_GL_ERROR_NOT_AVAILABLE,
-                           _("Unable to create a GL pixel format"));
-      goto failure;
-    }
-
-  ctx = [[NSOpenGLContext alloc] initWithFormat:format
-                                 shareContext:share ? GDK_MACOS_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"));
-      goto failure;
-    }
-
-  nsview = _gdk_macos_surface_get_view (surface);
-  [nsview setWantsBestResolutionOpenGLSurface:YES];
-  [ctx setValues:&sync_to_framerate forParameter:NSOpenGLCPSwapInterval];
-  [ctx setView:nsview];
-
-  GDK_NOTE (OPENGL,
-            g_print ("Created NSOpenGLContext[%p]\n", ctx));
-
   context = g_object_new (GDK_TYPE_MACOS_GL_CONTEXT,
                           "surface", surface,
                           "shared-context", share,
                           NULL);
 
-  context->gl_context = ctx;
   context->is_attached = attached;
 
-failure:
-  if (format != NULL)
-    [format release];
-
   return GDK_GL_CONTEXT (context);
 }
 
 gboolean
 _gdk_macos_gl_context_make_current (GdkMacosGLContext *self)
 {
+  NSOpenGLContext *gl_context;
+
   g_return_val_if_fail (GDK_IS_MACOS_GL_CONTEXT (self), FALSE);
 
-  [self->gl_context makeCurrentContext];
+  if ((gl_context = get_ns_open_gl_context (self, NULL)))
+    {
+      [gl_context makeCurrentContext];
+      return TRUE;
+    }
 
-  return TRUE;
+  return FALSE;
 }
 
 G_GNUC_END_IGNORE_DEPRECATIONS
diff --git a/gdk/macos/meson.build b/gdk/macos/meson.build
index cf602d4439..e2bba8549b 100644
--- a/gdk/macos/meson.build
+++ b/gdk/macos/meson.build
@@ -23,6 +23,7 @@ gdk_macos_sources = files([
   'GdkMacosBaseView.c',
   'GdkMacosCairoView.c',
   'GdkMacosCairoSubview.c',
+  'GdkMacosGLView.c',
   'GdkMacosWindow.c',
 ])
 


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