gdkmacosglcontext.c 20.2 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
 * Copyright © 2020 Red Hat, Inc.
 *
 * 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.1 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"

22
23
24
25
26
27
28
#include "gdkconfig.h"

#include <OpenGL/gl3.h>
#include <OpenGL/CGLIOSurface.h>
#include <QuartzCore/QuartzCore.h>

#include "gdkmacosbuffer-private.h"
29
30
31
#include "gdkmacosglcontext-private.h"
#include "gdkmacossurface-private.h"

32
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
33

34
G_DEFINE_TYPE (GdkMacosGLContext, gdk_macos_gl_context, GDK_TYPE_GL_CONTEXT)
35

36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#define CHECK(error,cgl_error) _CHECK_CGL(error, G_STRLOC, cgl_error)
static inline gboolean
_CHECK_CGL (GError     **error,
            const char  *location,
            CGLError     cgl_error)
{
  if (cgl_error != kCGLNoError)
    {
      g_log ("Core OpenGL",
             G_LOG_LEVEL_CRITICAL,
             "%s: %s",
             location, CGLErrorString (cgl_error));
      g_set_error (error,
                   GDK_GL_ERROR,
                   GDK_GL_ERROR_NOT_AVAILABLE,
                   "%s",
                   CGLErrorString (cgl_error));
      return FALSE;
    }
55

56
57
  return TRUE;
}
58

59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/* Apple's OpenGL implementation does not contain the extension to
 * perform log handler callbacks when errors occur. Therefore, to aid in
 * tracking down issues we have a CHECK_GL() macro that can wrap GL
 * calls and check for an error afterwards.
 *
 * To make this easier, we use a statement expression, as this will
 * always be using something GCC-compatible on macOS.
 */
#define CHECK_GL(error,func) _CHECK_GL(error, G_STRLOC, ({ func; glGetError(); }))
static inline gboolean
_CHECK_GL (GError     **error,
           const char  *location,
           GLenum       gl_error)
{
  const char *msg;

  switch (gl_error)
    {
    case GL_INVALID_ENUM:
      msg = "invalid enum";
      break;
    case GL_INVALID_VALUE:
      msg = "invalid value";
      break;
    case GL_INVALID_OPERATION:
      msg = "invalid operation";
      break;
    case GL_INVALID_FRAMEBUFFER_OPERATION:
      msg = "invalid framebuffer operation";
      break;
    case GL_OUT_OF_MEMORY:
      msg = "out of memory";
      break;
    default:
      msg = "unknown error";
      break;
    }

  if (gl_error != GL_NO_ERROR)
    {
      g_log ("OpenGL",
             G_LOG_LEVEL_CRITICAL,
             "%s: %s", location, msg);
      if (error != NULL)
        g_set_error (error,
                     GDK_GL_ERROR,
                     GDK_GL_ERROR_NOT_AVAILABLE,
                     "%s", msg);
      return FALSE;
    }

  return TRUE;
}

static gboolean
check_framebuffer_status (GLenum target)
{
  switch (glCheckFramebufferStatus (target))
    {
    case GL_FRAMEBUFFER_COMPLETE:
      return TRUE;

    case GL_FRAMEBUFFER_UNDEFINED:
      g_critical ("Framebuffer is undefined");
      return FALSE;

    case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
      g_critical ("Framebuffer has incomplete attachment");
      return FALSE;

    case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
      g_critical ("Framebuffer has missing attachment");
      return FALSE;

    case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
      g_critical ("Framebuffer has incomplete draw buffer");
      return FALSE;

    case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
      g_critical ("Framebuffer has incomplete read buffer");
      return FALSE;

    case GL_FRAMEBUFFER_UNSUPPORTED:
      g_critical ("Framebuffer is unsupported");
      return FALSE;

    case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
      g_critical ("Framebuffer has incomplete multisample");
      return FALSE;

    default:
      g_critical ("Framebuffer has unknown error");
      return FALSE;
    }
}
154

155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
static const char *
get_renderer_name (GLint id)
{
  static char renderer_name[32];

  switch (id & kCGLRendererIDMatchingMask)
  {
  case kCGLRendererGenericID: return "Generic";
  case kCGLRendererGenericFloatID: return "Generic Float";
  case kCGLRendererAppleSWID: return "Apple Software Renderer";
  case kCGLRendererATIRage128ID: return "ATI Rage 128";
  case kCGLRendererATIRadeonID: return "ATI Radeon";
  case kCGLRendererATIRageProID: return "ATI Rage Pro";
  case kCGLRendererATIRadeon8500ID: return "ATI Radeon 8500";
  case kCGLRendererATIRadeon9700ID: return "ATI Radeon 9700";
  case kCGLRendererATIRadeonX1000ID: return "ATI Radeon X1000";
  case kCGLRendererATIRadeonX2000ID: return "ATI Radeon X2000";
  case kCGLRendererATIRadeonX3000ID: return "ATI Radeon X3000";
  case kCGLRendererATIRadeonX4000ID: return "ATI Radeon X4000";
  case kCGLRendererGeForce2MXID: return "GeForce 2 MX";
  case kCGLRendererGeForce3ID: return "GeForce 3";
  case kCGLRendererGeForceFXID: return "GeForce FX";
  case kCGLRendererGeForce8xxxID: return "GeForce 8xxx";
  case kCGLRendererGeForceID: return "GeForce";
  case kCGLRendererVTBladeXP2ID: return "VT Blade XP 2";
  case kCGLRendererIntel900ID: return "Intel 900";
  case kCGLRendererIntelX3100ID: return "Intel X3100";
  case kCGLRendererIntelHDID: return "Intel HD";
  case kCGLRendererIntelHD4000ID: return "Intel HD 4000";
  case kCGLRendererIntelHD5000ID: return "Intel HD 5000";
  case kCGLRendererMesa3DFXID: return "Mesa 3DFX";

  default:
    snprintf (renderer_name, sizeof renderer_name, "0x%08x", id & kCGLRendererIDMatchingMask);
    renderer_name[sizeof renderer_name-1] = 0;
    return renderer_name;
  }
}

194
195
196
197
198
199
static GLuint
create_texture (CGLContextObj cgl_context,
                GLuint        target,
                IOSurfaceRef  io_surface,
                guint         width,
                guint         height)
200
{
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
  GLuint texture = 0;

  if (!CHECK_GL (NULL, glActiveTexture (GL_TEXTURE0)) ||
      !CHECK_GL (NULL, glGenTextures (1, &texture)) ||
      !CHECK_GL (NULL, glBindTexture (target, texture)) ||
      !CHECK (NULL, CGLTexImageIOSurface2D (cgl_context,
                                            target,
                                            GL_RGBA,
                                            width,
                                            height,
                                            GL_BGRA,
                                            GL_UNSIGNED_INT_8_8_8_8_REV,
                                            io_surface,
                                            0)) ||
      !CHECK_GL (NULL, glTexParameteri (target, GL_TEXTURE_BASE_LEVEL, 0)) ||
      !CHECK_GL (NULL, glTexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_NEAREST)) ||
      !CHECK_GL (NULL, glTexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_NEAREST)) ||
      !CHECK_GL (NULL, glTexParameteri (target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)) ||
      !CHECK_GL (NULL, glTexParameteri (target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE)) ||
      !CHECK_GL (NULL, glTexParameteri (target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)) ||
      !CHECK_GL (NULL, glBindTexture (target, 0)))
222
    {
223
224
      glDeleteTextures (1, &texture);
      return 0;
225
226
    }

227
  return texture;
228
229
}

230
231
static void
gdk_macos_gl_context_allocate (GdkMacosGLContext *self)
232
{
233
234
  GdkSurface *surface;
  GLint opaque;
235

236
237
238
239
240
  g_assert (GDK_IS_MACOS_GL_CONTEXT (self));
  g_assert (self->cgl_context != NULL);
  g_assert (self->target != 0);
  g_assert (self->texture != 0 || self->fbo == 0);
  g_assert (self->fbo != 0 || self->texture == 0);
241

242
243
  if (!(surface = gdk_draw_context_get_surface (GDK_DRAW_CONTEXT (self))))
    return;
244

245
246
247
248
249
250
251
252
  /* Alter to an opaque surface if necessary */
  opaque = _gdk_macos_surface_is_opaque (GDK_MACOS_SURFACE (surface));
  if (opaque != self->last_opaque)
    {
      self->last_opaque = !!opaque;
      if (!CHECK (NULL, CGLSetParameter (self->cgl_context, kCGLCPSurfaceOpacity, &opaque)))
        return;
    }
253

254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
  if (self->texture == 0)
    {
      GdkMacosBuffer *buffer;
      IOSurfaceRef io_surface;
      guint width;
      guint height;
      GLuint texture = 0;
      GLuint fbo = 0;

      buffer = _gdk_macos_surface_get_buffer (GDK_MACOS_SURFACE (surface));
      io_surface = _gdk_macos_buffer_get_native (buffer);
      width = _gdk_macos_buffer_get_width (buffer);
      height = _gdk_macos_buffer_get_height (buffer);

      /* We might need to re-enforce our CGL context here to keep
       * video playing correctly. Something, somewhere, might have
       * changed the context without touching GdkGLContext.
       *
       * Without this, video_player often breaks in gtk-demo when using
       * the GStreamer backend.
       */
      CGLSetCurrentContext (self->cgl_context);

      if (!(texture = create_texture (self->cgl_context, self->target, io_surface, width, height)) ||
          !CHECK_GL (NULL, glGenFramebuffers (1, &fbo)) ||
          !CHECK_GL (NULL, glBindFramebuffer (GL_FRAMEBUFFER, fbo)) ||
          !CHECK_GL (NULL, glBindTexture (self->target, texture)) ||
          !CHECK_GL (NULL, glFramebufferTexture2D (GL_FRAMEBUFFER,
                                                   GL_COLOR_ATTACHMENT0,
                                                   self->target,
                                                   texture,
                                                   0)) ||
          !check_framebuffer_status (GL_FRAMEBUFFER))
        {
          glDeleteFramebuffers (1, &fbo);
          glDeleteTextures (1, &texture);
          return;
        }

      glBindTexture (self->target, 0);
      glBindFramebuffer (GL_FRAMEBUFFER, 0);

      self->texture = texture;
      self->fbo = fbo;
    }
299
300
}

301
302
static void
gdk_macos_gl_context_release (GdkMacosGLContext *self)
303
304
{
  g_assert (GDK_IS_MACOS_GL_CONTEXT (self));
305
306
  g_assert (self->texture != 0 || self->fbo == 0);
  g_assert (self->fbo != 0 || self->texture == 0);
307

308
309
310
  glBindFramebuffer (GL_FRAMEBUFFER, 0);
  glActiveTexture (GL_TEXTURE0);
  glBindTexture (self->target, 0);
311

312
  if (self->fbo != 0)
313
    {
314
315
316
      glDeleteFramebuffers (1, &self->fbo);
      self->fbo = 0;
    }
317

318
319
320
321
  if (self->texture != 0)
    {
      glDeleteTextures (1, &self->texture);
      self->texture = 0;
322
    }
323
324
325
326
327
328
329
330
331
332
}

static CGLPixelFormatObj
create_pixel_format (int      major,
                     int      minor,
                     GError **error)
{
  CGLPixelFormatAttribute attrs[] = {
    kCGLPFAOpenGLProfile, (CGLPixelFormatAttribute)kCGLOGLPVersion_Legacy,
    kCGLPFAAllowOfflineRenderers, /* allow sharing across GPUs */
333
334
    kCGLPFADepthSize, 0,
    kCGLPFAStencilSize, 0,
335
336
337
338
339
340
341
342
343
344
345
    kCGLPFAColorSize, 24,
    kCGLPFAAlphaSize, 8,
    0
  };
  CGLPixelFormatObj format = NULL;
  GLint n_format = 1;

  if (major == 3 && minor == 2)
    attrs[1] = (CGLPixelFormatAttribute)kCGLOGLPVersion_GL3_Core;
  else if (major == 4 && minor == 1)
    attrs[1] = (CGLPixelFormatAttribute)kCGLOGLPVersion_GL4_Core;
346

347
348
349
350
  if (!CHECK (error, CGLChoosePixelFormat (attrs, &format, &n_format)))
    return NULL;

  return g_steal_pointer (&format);
351
352
}

Benjamin Otte's avatar
Benjamin Otte committed
353
static GdkGLAPI
354
355
356
357
358
gdk_macos_gl_context_real_realize (GdkGLContext  *context,
                                   GError       **error)
{
  GdkMacosGLContext *self = (GdkMacosGLContext *)context;
  GdkSurface *surface;
359
  GdkDisplay *display;
360
361
  CGLPixelFormatObj pixelFormat;
  CGLContextObj shared_gl_context = nil;
362
  CGLContextObj cgl_context;
363
  CGLContextObj existing;
364
365
366
  GdkGLContext *shared;
  GLint sync_to_framerate = 1;
  GLint validate = 0;
367
  GLint renderer_id = 0;
368
  GLint swapRect[4];
369
370
371
372
  int major, minor;

  g_assert (GDK_IS_MACOS_GL_CONTEXT (self));

373
  if (self->cgl_context != nil)
374
375
376
377
    return GDK_GL_API_GL;

  if (!gdk_gl_context_is_api_allowed (context, GDK_GL_API_GL, error))
    return 0;
378

379
  existing = CGLGetCurrentContext ();
380

381
382
383
384
  gdk_gl_context_get_clipped_version (context,
                                      GDK_GL_MIN_GL_VERSION_MAJOR,
                                      GDK_GL_MIN_GL_VERSION_MINOR,
                                      &major, &minor);
385

386
387
  display = gdk_gl_context_get_display (context);
  shared = gdk_display_get_gl_context (display);
388
389
390

  if (shared != NULL)
    {
391
392
393
394
395
396
397
398
      if (!(shared_gl_context = GDK_MACOS_GL_CONTEXT (shared)->cgl_context))
        {
          g_set_error_literal (error,
                               GDK_GL_ERROR,
                               GDK_GL_ERROR_NOT_AVAILABLE,
                               "Cannot access shared CGLContextObj");
          return 0;
        }
399
400
    }

401
402
403
  GDK_DISPLAY_DEBUG (display, OPENGL,
                     "Creating CGLContextObj (version %d.%d)",
                     major, minor);
404
405

  if (!(pixelFormat = create_pixel_format (major, minor, error)))
406
    return 0;
407

408
  if (!CHECK (error, CGLCreateContext (pixelFormat, shared_gl_context, &cgl_context)))
409
    {
410
      CGLReleasePixelFormat (pixelFormat);
411
      return 0;
412
413
    }

414
415
  CGLSetCurrentContext (cgl_context);
  CGLReleasePixelFormat (pixelFormat);
416

417
418
  if (validate)
    CHECK (NULL, CGLEnable (cgl_context, kCGLCEStateValidation));
419

420
421
422
423
424
425
  if (!CHECK (error, CGLSetParameter (cgl_context, kCGLCPSwapInterval, &sync_to_framerate)) ||
      !CHECK (error, CGLGetParameter (cgl_context, kCGLCPCurrentRendererID, &renderer_id)))
   {
      CGLReleaseContext (cgl_context);
      return 0;
   }
426

427
  surface = gdk_draw_context_get_surface (GDK_DRAW_CONTEXT (context));
428

429
430
431
432
433
434
435
436
437
438
439
440
441
  if (surface != NULL)
    {
      /* Setup initial swap rectangle. We might not actually need this
       * anymore though as we are rendering to an IOSurface and we have
       * a scissor clip when rendering to it.
       */
      swapRect[0] = 0;
      swapRect[1] = 0;
      swapRect[2] = surface->width;
      swapRect[3] = surface->height;
      CGLSetParameter (cgl_context, kCGLCPSwapRectangle, swapRect);
      CGLEnable (cgl_context, kCGLCESwapRectangle);
    }
442

443
444
445
446
  GDK_DISPLAY_DEBUG (display, OPENGL,
                     "Created CGLContextObj@%p using %s",
                     cgl_context,
                     get_renderer_name (renderer_id));
447

448
  self->cgl_context = g_steal_pointer (&cgl_context);
449
450

  if (existing != NULL)
451
    CGLSetCurrentContext (existing);
452

453
  return GDK_GL_API_GL;
454
455
456
457
}

static void
gdk_macos_gl_context_begin_frame (GdkDrawContext *context,
Benjamin Otte's avatar
Benjamin Otte committed
458
                                  gboolean        prefers_high_depth,
459
                                  cairo_region_t *region)
460
461
{
  GdkMacosGLContext *self = (GdkMacosGLContext *)context;
462
463
  GdkMacosBuffer *buffer;
  cairo_region_t *copy;
464
  GdkSurface *surface;
465
466
467

  g_assert (GDK_IS_MACOS_GL_CONTEXT (self));

468
  copy = cairo_region_copy (region);
469
  surface = gdk_draw_context_get_surface (context);
470
  buffer = _gdk_macos_surface_get_buffer (GDK_MACOS_SURFACE (surface));
471

472
  _gdk_macos_buffer_set_flipped (buffer, TRUE);
473
  _gdk_macos_buffer_set_damage (buffer, region);
474

475
476
477
  /* Create our render target and bind it */
  gdk_gl_context_make_current (GDK_GL_CONTEXT (self));
  gdk_macos_gl_context_allocate (self);
478

479
  GDK_DRAW_CONTEXT_CLASS (gdk_macos_gl_context_parent_class)->begin_frame (context, prefers_high_depth, region);
480

481
482
  gdk_gl_context_make_current (GDK_GL_CONTEXT (self));
  CHECK_GL (NULL, glBindFramebuffer (GL_FRAMEBUFFER, self->fbo));
483
484
}

485
486
487
488
489
static void
gdk_macos_gl_context_end_frame (GdkDrawContext *context,
                                cairo_region_t *painted)
{
  GdkMacosGLContext *self = GDK_MACOS_GL_CONTEXT (context);
490
491
492
  GdkSurface *surface;
  cairo_rectangle_int_t flush_rect;
  GLint swapRect[4];
493
494

  g_assert (GDK_IS_MACOS_GL_CONTEXT (self));
495
  g_assert (self->cgl_context != nil);
496
497
498

  GDK_DRAW_CONTEXT_CLASS (gdk_macos_gl_context_parent_class)->end_frame (context, painted);

499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
  surface = gdk_draw_context_get_surface (context);
  gdk_gl_context_make_current (GDK_GL_CONTEXT (self));

  /* Coordinates are in display coordinates, where as flush_rect is
  * in GDK coordinates. Must flip Y to match display coordinates where
  * 0,0 is the bottom-left corner.
  */
  cairo_region_get_extents (painted, &flush_rect);
  swapRect[0] = flush_rect.x;                   /* left */
  swapRect[1] = surface->height - flush_rect.y; /* bottom */
  swapRect[2] = flush_rect.width;               /* width */
  swapRect[3] = flush_rect.height;              /* height */
  CGLSetParameter (self->cgl_context, kCGLCPSwapRectangle, swapRect);

  gdk_macos_gl_context_release (self);

  glFlush ();

  /* Begin a Core Animation transaction so that all changes we
   * make within the window are seen atomically.
   */
  [CATransaction begin];
  [CATransaction setDisableActions:YES];
  _gdk_macos_surface_swap_buffers (GDK_MACOS_SURFACE (surface), painted);
  [CATransaction commit];
524
525
}

526
527
528
529
530
531
532
static void
gdk_macos_gl_context_surface_resized (GdkDrawContext *draw_context)
{
  GdkMacosGLContext *self = (GdkMacosGLContext *)draw_context;

  g_assert (GDK_IS_MACOS_GL_CONTEXT (self));

533
534
  if (self->cgl_context != NULL)
    CGLUpdateContext (self->cgl_context);
535
536
}

Benjamin Otte's avatar
Benjamin Otte committed
537
538
539
540
541
542
543
static gboolean
gdk_macos_gl_context_clear_current (GdkGLContext *context)
{
  GdkMacosGLContext *self = GDK_MACOS_GL_CONTEXT (context);

  g_return_val_if_fail (GDK_IS_MACOS_GL_CONTEXT (self), FALSE);

544
  if (self->cgl_context == CGLGetCurrentContext ())
Benjamin Otte's avatar
Benjamin Otte committed
545
    {
546
547
      glFlush ();
      CGLSetCurrentContext (NULL);
Benjamin Otte's avatar
Benjamin Otte committed
548
549
550
551
552
553
554
555
556
557
    }

  return TRUE;
}

static gboolean
gdk_macos_gl_context_make_current (GdkGLContext *context,
                                   gboolean      surfaceless)
{
  GdkMacosGLContext *self = GDK_MACOS_GL_CONTEXT (context);
558
  CGLContextObj current;
Benjamin Otte's avatar
Benjamin Otte committed
559
560
561

  g_return_val_if_fail (GDK_IS_MACOS_GL_CONTEXT (self), FALSE);

562
  current = CGLGetCurrentContext ();
Benjamin Otte's avatar
Benjamin Otte committed
563

564
  if (self->cgl_context != current)
Benjamin Otte's avatar
Benjamin Otte committed
565
566
567
568
    {
      /* The OpenGL mac programming guide suggests that glFlush() is called
       * before switching current contexts to ensure that the drawing commands
       * are submitted.
569
570
571
572
       *
       * TODO: investigate if we need this because we may switch contexts
       *       durring composition and only need it when returning to a
       *       previous context that uses the other context.
Benjamin Otte's avatar
Benjamin Otte committed
573
574
575
576
       */
      if (current != NULL)
        glFlush ();

577
      CGLSetCurrentContext (self->cgl_context);
Benjamin Otte's avatar
Benjamin Otte committed
578
579
580
581
582
    }

  return TRUE;
}

583
584
585
586
static cairo_region_t *
gdk_macos_gl_context_get_damage (GdkGLContext *context)
{
  GdkMacosGLContext *self = (GdkMacosGLContext *)context;
587
588
589
  const cairo_region_t *damage;
  GdkMacosBuffer *buffer;
  GdkSurface *surface;
590

591
592
593
594
595
596
  g_assert (GDK_IS_MACOS_GL_CONTEXT (self));

  if ((surface = gdk_draw_context_get_surface (GDK_DRAW_CONTEXT (context))) &&
      (buffer = GDK_MACOS_SURFACE (surface)->front) &&
      (damage = _gdk_macos_buffer_get_damage (buffer)))
    return cairo_region_copy (damage);
597
598

  return GDK_GL_CONTEXT_CLASS (gdk_macos_gl_context_parent_class)->get_damage (context);
599
600
}

601
602
603
604
605
606
static guint
gdk_macos_gl_context_get_default_framebuffer (GdkGLContext *context)
{
  return GDK_MACOS_GL_CONTEXT (context)->fbo;
}

607
608
609
static void
gdk_macos_gl_context_dispose (GObject *gobject)
{
610
611
  GdkMacosGLContext *self = GDK_MACOS_GL_CONTEXT (gobject);

612
613
  self->texture = 0;
  self->fbo = 0;
614

615
  if (self->cgl_context != nil)
616
    {
617
      CGLContextObj cgl_context = g_steal_pointer (&self->cgl_context);
618

619
620
      if (cgl_context == CGLGetCurrentContext ())
        CGLSetCurrentContext (NULL);
621

622
623
      CGLClearDrawable (cgl_context);
      CGLDestroyContext (cgl_context);
624
625
626
627
628
629
630
631
632
633
    }

  G_OBJECT_CLASS (gdk_macos_gl_context_parent_class)->dispose (gobject);
}

static void
gdk_macos_gl_context_class_init (GdkMacosGLContextClass *klass)
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
  GdkDrawContextClass *draw_context_class = GDK_DRAW_CONTEXT_CLASS (klass);
634
  GdkGLContextClass *gl_class = GDK_GL_CONTEXT_CLASS (klass);
635
636
637

  object_class->dispose = gdk_macos_gl_context_dispose;

638
  draw_context_class->begin_frame = gdk_macos_gl_context_begin_frame;
639
  draw_context_class->end_frame = gdk_macos_gl_context_end_frame;
640
641
  draw_context_class->surface_resized = gdk_macos_gl_context_surface_resized;

642
  gl_class->get_damage = gdk_macos_gl_context_get_damage;
Benjamin Otte's avatar
Benjamin Otte committed
643
644
  gl_class->clear_current = gdk_macos_gl_context_clear_current;
  gl_class->make_current = gdk_macos_gl_context_make_current;
645
  gl_class->realize = gdk_macos_gl_context_real_realize;
646
  gl_class->get_default_framebuffer = gdk_macos_gl_context_get_default_framebuffer;
647
648

  gl_class->backend_type = GDK_GL_CGL;
649
650
651
652
653
}

static void
gdk_macos_gl_context_init (GdkMacosGLContext *self)
{
654
  self->target = GL_TEXTURE_RECTANGLE;
655
656
657
}

G_GNUC_END_IGNORE_DEPRECATIONS