13464ebd5Sriastradh/*
23464ebd5Sriastradh Copyright (c) 2008, 2009 Apple Inc.
33464ebd5Sriastradh
43464ebd5Sriastradh Permission is hereby granted, free of charge, to any person
53464ebd5Sriastradh obtaining a copy of this software and associated documentation files
63464ebd5Sriastradh (the "Software"), to deal in the Software without restriction,
73464ebd5Sriastradh including without limitation the rights to use, copy, modify, merge,
83464ebd5Sriastradh publish, distribute, sublicense, and/or sell copies of the Software,
93464ebd5Sriastradh and to permit persons to whom the Software is furnished to do so,
103464ebd5Sriastradh subject to the following conditions:
113464ebd5Sriastradh
123464ebd5Sriastradh The above copyright notice and this permission notice shall be
133464ebd5Sriastradh included in all copies or substantial portions of the Software.
143464ebd5Sriastradh
153464ebd5Sriastradh THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
163464ebd5Sriastradh EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
173464ebd5Sriastradh MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
183464ebd5Sriastradh NONINFRINGEMENT.  IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT
193464ebd5Sriastradh HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
203464ebd5Sriastradh WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
213464ebd5Sriastradh OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
223464ebd5Sriastradh DEALINGS IN THE SOFTWARE.
233464ebd5Sriastradh
243464ebd5Sriastradh Except as contained in this notice, the name(s) of the above
253464ebd5Sriastradh copyright holders shall not be used in advertising or otherwise to
263464ebd5Sriastradh promote the sale, use or other dealings in this Software without
273464ebd5Sriastradh prior written authorization.
283464ebd5Sriastradh*/
293464ebd5Sriastradh
303464ebd5Sriastradh#include <stdbool.h>
313464ebd5Sriastradh#include <stdio.h>
323464ebd5Sriastradh#include <stdlib.h>
333464ebd5Sriastradh#include <limits.h>
343464ebd5Sriastradh#include <assert.h>
353464ebd5Sriastradh#include <pthread.h>
363464ebd5Sriastradh
373464ebd5Sriastradh#include <fcntl.h>
383464ebd5Sriastradh#include <sys/mman.h>
393464ebd5Sriastradh#include <unistd.h>
403464ebd5Sriastradh
413464ebd5Sriastradh// Get the newer glext.h first
423464ebd5Sriastradh#include <GL/gl.h>
433464ebd5Sriastradh#include <GL/glext.h>
443464ebd5Sriastradh
453464ebd5Sriastradh#include <OpenGL/CGLTypes.h>
463464ebd5Sriastradh#include <OpenGL/CGLCurrent.h>
473464ebd5Sriastradh#include <OpenGL/OpenGL.h>
483464ebd5Sriastradh
493464ebd5Sriastradh#include "glxclient.h"
503464ebd5Sriastradh
513464ebd5Sriastradh#include "apple_glx.h"
523464ebd5Sriastradh#include "apple_glx_context.h"
533464ebd5Sriastradh#include "appledri.h"
543464ebd5Sriastradh#include "apple_visual.h"
553464ebd5Sriastradh#include "apple_cgl.h"
563464ebd5Sriastradh#include "apple_glx_drawable.h"
573464ebd5Sriastradh
5801e04c3fSmrg#include "util/debug.h"
5901e04c3fSmrg
603464ebd5Sriastradhstatic pthread_mutex_t context_lock = PTHREAD_MUTEX_INITIALIZER;
613464ebd5Sriastradh
623464ebd5Sriastradh/*
633464ebd5Sriastradh * This should be locked on creation and destruction of the
643464ebd5Sriastradh * apple_glx_contexts.
653464ebd5Sriastradh *
663464ebd5Sriastradh * It's also locked when the surface_notify_handler is searching
673464ebd5Sriastradh * for a uid associated with a surface.
683464ebd5Sriastradh */
693464ebd5Sriastradhstatic struct apple_glx_context *context_list = NULL;
703464ebd5Sriastradh
713464ebd5Sriastradh/* This guards the context_list above. */
723464ebd5Sriastradhstatic void
733464ebd5Sriastradhlock_context_list(void)
743464ebd5Sriastradh{
753464ebd5Sriastradh   int err;
763464ebd5Sriastradh
773464ebd5Sriastradh   err = pthread_mutex_lock(&context_lock);
783464ebd5Sriastradh
793464ebd5Sriastradh   if (err) {
803464ebd5Sriastradh      fprintf(stderr, "pthread_mutex_lock failure in %s: %d\n",
813464ebd5Sriastradh              __func__, err);
823464ebd5Sriastradh      abort();
833464ebd5Sriastradh   }
843464ebd5Sriastradh}
853464ebd5Sriastradh
863464ebd5Sriastradhstatic void
873464ebd5Sriastradhunlock_context_list(void)
883464ebd5Sriastradh{
893464ebd5Sriastradh   int err;
903464ebd5Sriastradh
913464ebd5Sriastradh   err = pthread_mutex_unlock(&context_lock);
923464ebd5Sriastradh
933464ebd5Sriastradh   if (err) {
943464ebd5Sriastradh      fprintf(stderr, "pthread_mutex_unlock failure in %s: %d\n",
953464ebd5Sriastradh              __func__, err);
963464ebd5Sriastradh      abort();
973464ebd5Sriastradh   }
983464ebd5Sriastradh}
993464ebd5Sriastradh
1003464ebd5Sriastradhstatic bool
1013464ebd5Sriastradhis_context_valid(struct apple_glx_context *ac)
1023464ebd5Sriastradh{
1033464ebd5Sriastradh   struct apple_glx_context *i;
1043464ebd5Sriastradh
1053464ebd5Sriastradh   lock_context_list();
1063464ebd5Sriastradh
1073464ebd5Sriastradh   for (i = context_list; i; i = i->next) {
1083464ebd5Sriastradh      if (ac == i) {
1093464ebd5Sriastradh         unlock_context_list();
1103464ebd5Sriastradh         return true;
1113464ebd5Sriastradh      }
1123464ebd5Sriastradh   }
1133464ebd5Sriastradh
1143464ebd5Sriastradh   unlock_context_list();
1153464ebd5Sriastradh
1163464ebd5Sriastradh   return false;
1173464ebd5Sriastradh}
1183464ebd5Sriastradh
1193464ebd5Sriastradh/* This creates an apple_private_context struct.
1203464ebd5Sriastradh *
1213464ebd5Sriastradh * It's typically called to save the struct in a GLXContext.
1223464ebd5Sriastradh *
1233464ebd5Sriastradh * This is also where the CGLContextObj is created, and the CGLPixelFormatObj.
1243464ebd5Sriastradh */
1253464ebd5Sriastradhbool
1263464ebd5Sriastradhapple_glx_create_context(void **ptr, Display * dpy, int screen,
1273464ebd5Sriastradh                         const void *mode, void *sharedContext,
1283464ebd5Sriastradh                         int *errorptr, bool * x11errorptr)
1293464ebd5Sriastradh{
1303464ebd5Sriastradh   struct apple_glx_context *ac;
1313464ebd5Sriastradh   struct apple_glx_context *sharedac = sharedContext;
1323464ebd5Sriastradh   CGLError error;
1333464ebd5Sriastradh
1343464ebd5Sriastradh   *ptr = NULL;
1353464ebd5Sriastradh
1363464ebd5Sriastradh   ac = malloc(sizeof *ac);
1373464ebd5Sriastradh
1383464ebd5Sriastradh   if (NULL == ac) {
1393464ebd5Sriastradh      *errorptr = BadAlloc;
1403464ebd5Sriastradh      *x11errorptr = true;
1413464ebd5Sriastradh      return true;
1423464ebd5Sriastradh   }
1433464ebd5Sriastradh
1443464ebd5Sriastradh   if (sharedac && !is_context_valid(sharedac)) {
1453464ebd5Sriastradh      *errorptr = GLXBadContext;
1463464ebd5Sriastradh      *x11errorptr = false;
147af69d88dSmrg      free(ac);
1483464ebd5Sriastradh      return true;
1493464ebd5Sriastradh   }
1503464ebd5Sriastradh
1513464ebd5Sriastradh   ac->context_obj = NULL;
1523464ebd5Sriastradh   ac->pixel_format_obj = NULL;
1533464ebd5Sriastradh   ac->drawable = NULL;
1543464ebd5Sriastradh   ac->thread_id = pthread_self();
1553464ebd5Sriastradh   ac->screen = screen;
1563464ebd5Sriastradh   ac->double_buffered = false;
1573464ebd5Sriastradh   ac->uses_stereo = false;
1583464ebd5Sriastradh   ac->need_update = false;
1593464ebd5Sriastradh   ac->is_current = false;
1603464ebd5Sriastradh   ac->made_current = false;
1613464ebd5Sriastradh   ac->last_surface_window = None;
1623464ebd5Sriastradh
1633464ebd5Sriastradh   apple_visual_create_pfobj(&ac->pixel_format_obj, mode,
1643464ebd5Sriastradh                             &ac->double_buffered, &ac->uses_stereo,
1653464ebd5Sriastradh                             /*offscreen */ false);
1663464ebd5Sriastradh
1673464ebd5Sriastradh   error = apple_cgl.create_context(ac->pixel_format_obj,
1683464ebd5Sriastradh                                    sharedac ? sharedac->context_obj : NULL,
1693464ebd5Sriastradh                                    &ac->context_obj);
1703464ebd5Sriastradh
1713464ebd5Sriastradh
1723464ebd5Sriastradh   if (error) {
1733464ebd5Sriastradh      (void) apple_cgl.destroy_pixel_format(ac->pixel_format_obj);
1743464ebd5Sriastradh
1753464ebd5Sriastradh      free(ac);
1763464ebd5Sriastradh
1773464ebd5Sriastradh      if (kCGLBadMatch == error) {
1783464ebd5Sriastradh         *errorptr = BadMatch;
1793464ebd5Sriastradh         *x11errorptr = true;
1803464ebd5Sriastradh      }
1813464ebd5Sriastradh      else {
1823464ebd5Sriastradh         *errorptr = GLXBadContext;
1833464ebd5Sriastradh         *x11errorptr = false;
1843464ebd5Sriastradh      }
1853464ebd5Sriastradh
1867ec681f3Smrg      DebugMessageF("error: %s\n", apple_cgl.error_string(error));
1873464ebd5Sriastradh
1883464ebd5Sriastradh      return true;
1893464ebd5Sriastradh   }
1903464ebd5Sriastradh
1913464ebd5Sriastradh   /* The context creation succeeded, so we can link in the new context. */
1923464ebd5Sriastradh   lock_context_list();
1933464ebd5Sriastradh
1943464ebd5Sriastradh   if (context_list)
1953464ebd5Sriastradh      context_list->previous = ac;
1963464ebd5Sriastradh
1973464ebd5Sriastradh   ac->previous = NULL;
1983464ebd5Sriastradh   ac->next = context_list;
1993464ebd5Sriastradh   context_list = ac;
2003464ebd5Sriastradh
2013464ebd5Sriastradh   *ptr = ac;
2023464ebd5Sriastradh
2033464ebd5Sriastradh   apple_glx_diagnostic("%s: ac %p ac->context_obj %p\n",
2043464ebd5Sriastradh                        __func__, (void *) ac, (void *) ac->context_obj);
2053464ebd5Sriastradh
2063464ebd5Sriastradh   unlock_context_list();
2073464ebd5Sriastradh
2083464ebd5Sriastradh   return false;
2093464ebd5Sriastradh}
2103464ebd5Sriastradh
2113464ebd5Sriastradhvoid
2123464ebd5Sriastradhapple_glx_destroy_context(void **ptr, Display * dpy)
2133464ebd5Sriastradh{
2143464ebd5Sriastradh   struct apple_glx_context *ac = *ptr;
2153464ebd5Sriastradh
2163464ebd5Sriastradh   if (NULL == ac)
2173464ebd5Sriastradh      return;
2183464ebd5Sriastradh
2193464ebd5Sriastradh   apple_glx_diagnostic("%s: ac %p ac->context_obj %p\n",
2203464ebd5Sriastradh                        __func__, (void *) ac, (void *) ac->context_obj);
2213464ebd5Sriastradh
2223464ebd5Sriastradh   if (apple_cgl.get_current_context() == ac->context_obj) {
2233464ebd5Sriastradh      apple_glx_diagnostic("%s: context ac->context_obj %p "
2243464ebd5Sriastradh                           "is still current!\n", __func__,
2253464ebd5Sriastradh                           (void *) ac->context_obj);
2263464ebd5Sriastradh      if (apple_cgl.set_current_context(NULL)) {
2273464ebd5Sriastradh         abort();
2283464ebd5Sriastradh      }
2293464ebd5Sriastradh   }
2303464ebd5Sriastradh
2313464ebd5Sriastradh   /* Remove ac from the context_list as soon as possible. */
2323464ebd5Sriastradh   lock_context_list();
2333464ebd5Sriastradh
2343464ebd5Sriastradh   if (ac->previous) {
2353464ebd5Sriastradh      ac->previous->next = ac->next;
2363464ebd5Sriastradh   }
2373464ebd5Sriastradh   else {
2383464ebd5Sriastradh      context_list = ac->next;
2393464ebd5Sriastradh   }
2403464ebd5Sriastradh
2413464ebd5Sriastradh   if (ac->next) {
2423464ebd5Sriastradh      ac->next->previous = ac->previous;
2433464ebd5Sriastradh   }
2443464ebd5Sriastradh
2453464ebd5Sriastradh   unlock_context_list();
2463464ebd5Sriastradh
2473464ebd5Sriastradh
2483464ebd5Sriastradh   if (apple_cgl.clear_drawable(ac->context_obj)) {
2493464ebd5Sriastradh      fprintf(stderr, "error: while clearing drawable!\n");
2503464ebd5Sriastradh      abort();
2513464ebd5Sriastradh   }
2523464ebd5Sriastradh
2533464ebd5Sriastradh   /*
2543464ebd5Sriastradh    * This potentially causes surface_notify_handler to be called in
2553464ebd5Sriastradh    * apple_glx.c...
2563464ebd5Sriastradh    * We can NOT have a lock held at this point.  It would result in
2573464ebd5Sriastradh    * an abort due to an attempted deadlock.  This is why we earlier
2583464ebd5Sriastradh    * removed the ac pointer from the double-linked list.
2593464ebd5Sriastradh    */
2603464ebd5Sriastradh   if (ac->drawable) {
2613464ebd5Sriastradh      ac->drawable->destroy(ac->drawable);
2623464ebd5Sriastradh   }
2633464ebd5Sriastradh
2643464ebd5Sriastradh   if (apple_cgl.destroy_pixel_format(ac->pixel_format_obj)) {
2653464ebd5Sriastradh      fprintf(stderr, "error: destroying pixel format in %s\n", __func__);
2663464ebd5Sriastradh      abort();
2673464ebd5Sriastradh   }
2683464ebd5Sriastradh
2693464ebd5Sriastradh   if (apple_cgl.destroy_context(ac->context_obj)) {
2703464ebd5Sriastradh      fprintf(stderr, "error: destroying context_obj in %s\n", __func__);
2713464ebd5Sriastradh      abort();
2723464ebd5Sriastradh   }
2733464ebd5Sriastradh
2743464ebd5Sriastradh   free(ac);
2753464ebd5Sriastradh
2763464ebd5Sriastradh   *ptr = NULL;
2773464ebd5Sriastradh
2783464ebd5Sriastradh   apple_glx_garbage_collect_drawables(dpy);
2793464ebd5Sriastradh}
2803464ebd5Sriastradh
2813464ebd5Sriastradh
28201e04c3fSmrg/* Return true if an error occurred. */
2833464ebd5Sriastradhbool
2843464ebd5Sriastradhapple_glx_make_current_context(Display * dpy, void *oldptr, void *ptr,
2853464ebd5Sriastradh                               GLXDrawable drawable)
2863464ebd5Sriastradh{
2873464ebd5Sriastradh   struct apple_glx_context *oldac = oldptr;
2883464ebd5Sriastradh   struct apple_glx_context *ac = ptr;
2893464ebd5Sriastradh   struct apple_glx_drawable *newagd = NULL;
2903464ebd5Sriastradh   CGLError cglerr;
2913464ebd5Sriastradh   bool same_drawable = false;
2923464ebd5Sriastradh
2933464ebd5Sriastradh#if 0
2943464ebd5Sriastradh   apple_glx_diagnostic("%s: oldac %p ac %p drawable 0x%lx\n",
2953464ebd5Sriastradh                        __func__, (void *) oldac, (void *) ac, drawable);
2963464ebd5Sriastradh
2973464ebd5Sriastradh   apple_glx_diagnostic("%s: oldac->context_obj %p ac->context_obj %p\n",
2983464ebd5Sriastradh                        __func__,
2993464ebd5Sriastradh                        (void *) (oldac ? oldac->context_obj : NULL),
3003464ebd5Sriastradh                        (void *) (ac ? ac->context_obj : NULL));
3013464ebd5Sriastradh#endif
3023464ebd5Sriastradh
3033464ebd5Sriastradh   /* This a common path for GLUT and other apps, so special case it. */
3043464ebd5Sriastradh   if (ac && ac->drawable && ac->drawable->drawable == drawable) {
3053464ebd5Sriastradh      same_drawable = true;
3063464ebd5Sriastradh
3073464ebd5Sriastradh      if (ac->is_current)
3083464ebd5Sriastradh         return false;
3093464ebd5Sriastradh   }
3103464ebd5Sriastradh
3113464ebd5Sriastradh   /* Reset the is_current state of the old context, if non-NULL. */
3123464ebd5Sriastradh   if (oldac && (ac != oldac))
3133464ebd5Sriastradh      oldac->is_current = false;
3143464ebd5Sriastradh
3153464ebd5Sriastradh   if (NULL == ac) {
3163464ebd5Sriastradh      /*Clear the current context for this thread. */
3173464ebd5Sriastradh      apple_cgl.set_current_context(NULL);
3183464ebd5Sriastradh
3193464ebd5Sriastradh      if (oldac) {
3203464ebd5Sriastradh         oldac->is_current = false;
3213464ebd5Sriastradh
3223464ebd5Sriastradh         if (oldac->drawable) {
3233464ebd5Sriastradh            oldac->drawable->destroy(oldac->drawable);
3243464ebd5Sriastradh            oldac->drawable = NULL;
3253464ebd5Sriastradh         }
3263464ebd5Sriastradh
3273464ebd5Sriastradh         /* Invalidate this to prevent surface recreation. */
3283464ebd5Sriastradh         oldac->last_surface_window = None;
3293464ebd5Sriastradh      }
3303464ebd5Sriastradh
3313464ebd5Sriastradh      return false;
3323464ebd5Sriastradh   }
3333464ebd5Sriastradh
3343464ebd5Sriastradh   if (None == drawable) {
3353464ebd5Sriastradh      bool error = false;
3363464ebd5Sriastradh
3373464ebd5Sriastradh      /* Clear the current drawable for this context_obj. */
3383464ebd5Sriastradh
3393464ebd5Sriastradh      if (apple_cgl.set_current_context(ac->context_obj))
3403464ebd5Sriastradh         error = true;
3413464ebd5Sriastradh
3423464ebd5Sriastradh      if (apple_cgl.clear_drawable(ac->context_obj))
3433464ebd5Sriastradh         error = true;
3443464ebd5Sriastradh
3453464ebd5Sriastradh      if (ac->drawable) {
3463464ebd5Sriastradh         ac->drawable->destroy(ac->drawable);
3473464ebd5Sriastradh         ac->drawable = NULL;
3483464ebd5Sriastradh      }
3493464ebd5Sriastradh
3503464ebd5Sriastradh      /* Invalidate this to prevent surface recreation. */
3513464ebd5Sriastradh      ac->last_surface_window = None;
3523464ebd5Sriastradh
3533464ebd5Sriastradh      apple_glx_diagnostic("%s: drawable is None, error is: %d\n",
3543464ebd5Sriastradh                           __func__, error);
3553464ebd5Sriastradh
3563464ebd5Sriastradh      return error;
3573464ebd5Sriastradh   }
3583464ebd5Sriastradh
3593464ebd5Sriastradh   /* This is an optimisation to avoid searching for the current drawable. */
3603464ebd5Sriastradh   if (ac->drawable && ac->drawable->drawable == drawable) {
3613464ebd5Sriastradh      newagd = ac->drawable;
3623464ebd5Sriastradh   }
3633464ebd5Sriastradh   else {
3643464ebd5Sriastradh      /* Find the drawable if possible, and retain a reference to it. */
3653464ebd5Sriastradh      newagd =
3663464ebd5Sriastradh         apple_glx_drawable_find(drawable, APPLE_GLX_DRAWABLE_REFERENCE);
3673464ebd5Sriastradh   }
3683464ebd5Sriastradh
3693464ebd5Sriastradh   /*
3703464ebd5Sriastradh    * Try to destroy the old drawable, so long as the new one
3713464ebd5Sriastradh    * isn't the old.
3723464ebd5Sriastradh    */
3733464ebd5Sriastradh   if (ac->drawable && !same_drawable) {
3743464ebd5Sriastradh      ac->drawable->destroy(ac->drawable);
3753464ebd5Sriastradh      ac->drawable = NULL;
3763464ebd5Sriastradh   }
3773464ebd5Sriastradh
3783464ebd5Sriastradh   if (NULL == newagd) {
3793464ebd5Sriastradh      if (apple_glx_surface_create(dpy, ac->screen, drawable, &newagd))
3803464ebd5Sriastradh         return true;
3813464ebd5Sriastradh
3823464ebd5Sriastradh      /* The drawable is referenced once by apple_glx_surface_create. */
3833464ebd5Sriastradh
3843464ebd5Sriastradh      /*
3853464ebd5Sriastradh       * FIXME: We actually need 2 references to prevent premature surface
3863464ebd5Sriastradh       * destruction.  The problem is that the surface gets destroyed in
3873464ebd5Sriastradh       * the case of the context being reused for another window, and
3883464ebd5Sriastradh       * we then lose the surface contents.  Wait for destruction of a
3893464ebd5Sriastradh       * window to destroy a surface.
3903464ebd5Sriastradh       *
3913464ebd5Sriastradh       * Note: this may leave around surfaces we don't want around, if
3923464ebd5Sriastradh       * say we are using X for raster drawing after OpenGL rendering,
3933464ebd5Sriastradh       * but it will be compatible with the old libGL's behavior.
3943464ebd5Sriastradh       *
3953464ebd5Sriastradh       * Someday the X11 and OpenGL rendering must be unified at some
3963464ebd5Sriastradh       * layer.  I suspect we can do that via shared memory and
3973464ebd5Sriastradh       * multiple threads in the X server (1 for each context created
3983464ebd5Sriastradh       * by a client).  This would also allow users to render from
3993464ebd5Sriastradh       * multiple clients to the same OpenGL surface.  In fact it could
4003464ebd5Sriastradh       * all be OpenGL.
4013464ebd5Sriastradh       *
4023464ebd5Sriastradh       */
4033464ebd5Sriastradh      newagd->reference(newagd);
4043464ebd5Sriastradh
4053464ebd5Sriastradh      /* Save the new drawable with the context structure. */
4063464ebd5Sriastradh      ac->drawable = newagd;
4073464ebd5Sriastradh   }
4083464ebd5Sriastradh   else {
4093464ebd5Sriastradh      /* We are reusing an existing drawable structure. */
4103464ebd5Sriastradh
4113464ebd5Sriastradh      if (same_drawable) {
4123464ebd5Sriastradh         assert(ac->drawable == newagd);
4133464ebd5Sriastradh         /* The drawable_find above retained a reference for us. */
4143464ebd5Sriastradh      }
4153464ebd5Sriastradh      else {
4163464ebd5Sriastradh         ac->drawable = newagd;
4173464ebd5Sriastradh      }
4183464ebd5Sriastradh   }
4193464ebd5Sriastradh
4203464ebd5Sriastradh   /*
4213464ebd5Sriastradh    * Avoid this costly path if this is the same drawable and the
4223464ebd5Sriastradh    * context is already current.
4233464ebd5Sriastradh    */
4243464ebd5Sriastradh
4253464ebd5Sriastradh   if (same_drawable && ac->is_current) {
426af69d88dSmrg      apple_glx_diagnostic("same_drawable and ac->is_current\n");
4273464ebd5Sriastradh      return false;
4283464ebd5Sriastradh   }
4293464ebd5Sriastradh
4303464ebd5Sriastradh   cglerr = apple_cgl.set_current_context(ac->context_obj);
4313464ebd5Sriastradh
4323464ebd5Sriastradh   if (kCGLNoError != cglerr) {
4333464ebd5Sriastradh      fprintf(stderr, "set current error: %s\n",
4343464ebd5Sriastradh              apple_cgl.error_string(cglerr));
4353464ebd5Sriastradh      return true;
4363464ebd5Sriastradh   }
4373464ebd5Sriastradh
4383464ebd5Sriastradh   ac->is_current = true;
4393464ebd5Sriastradh
4403464ebd5Sriastradh   assert(NULL != ac->context_obj);
4413464ebd5Sriastradh   assert(NULL != ac->drawable);
4423464ebd5Sriastradh
4433464ebd5Sriastradh   ac->thread_id = pthread_self();
4443464ebd5Sriastradh
4453464ebd5Sriastradh   /* This will be set if the pending_destroy code indicates it should be: */
4463464ebd5Sriastradh   ac->last_surface_window = None;
4473464ebd5Sriastradh
4483464ebd5Sriastradh   switch (ac->drawable->type) {
4493464ebd5Sriastradh   case APPLE_GLX_DRAWABLE_PBUFFER:
4503464ebd5Sriastradh   case APPLE_GLX_DRAWABLE_SURFACE:
4513464ebd5Sriastradh   case APPLE_GLX_DRAWABLE_PIXMAP:
4523464ebd5Sriastradh      if (ac->drawable->callbacks.make_current) {
4533464ebd5Sriastradh         if (ac->drawable->callbacks.make_current(ac, ac->drawable))
4543464ebd5Sriastradh            return true;
4553464ebd5Sriastradh      }
4563464ebd5Sriastradh      break;
4573464ebd5Sriastradh
4583464ebd5Sriastradh   default:
4593464ebd5Sriastradh      fprintf(stderr, "internal error: invalid drawable type: %d\n",
4603464ebd5Sriastradh              ac->drawable->type);
4613464ebd5Sriastradh      abort();
4623464ebd5Sriastradh   }
4633464ebd5Sriastradh
4643464ebd5Sriastradh   return false;
4653464ebd5Sriastradh}
4663464ebd5Sriastradh
4673464ebd5Sriastradhbool
4683464ebd5Sriastradhapple_glx_is_current_drawable(Display * dpy, void *ptr, GLXDrawable drawable)
4693464ebd5Sriastradh{
4703464ebd5Sriastradh   struct apple_glx_context *ac = ptr;
4713464ebd5Sriastradh
4723464ebd5Sriastradh   if (ac->drawable && ac->drawable->drawable == drawable) {
4733464ebd5Sriastradh      return true;
4743464ebd5Sriastradh   }
4753464ebd5Sriastradh   else if (NULL == ac->drawable && None != ac->last_surface_window) {
4763464ebd5Sriastradh      apple_glx_context_update(dpy, ac);
4773464ebd5Sriastradh
4783464ebd5Sriastradh      return (ac->drawable && ac->drawable->drawable == drawable);
4793464ebd5Sriastradh   }
4803464ebd5Sriastradh
4813464ebd5Sriastradh   return false;
4823464ebd5Sriastradh}
4833464ebd5Sriastradh
4843464ebd5Sriastradhbool
4853464ebd5Sriastradhapple_glx_copy_context(void *currentptr, void *srcptr, void *destptr,
4863464ebd5Sriastradh                       unsigned long mask, int *errorptr, bool * x11errorptr)
4873464ebd5Sriastradh{
4883464ebd5Sriastradh   struct apple_glx_context *src, *dest;
4893464ebd5Sriastradh   CGLError err;
4903464ebd5Sriastradh
4913464ebd5Sriastradh   src = srcptr;
4923464ebd5Sriastradh   dest = destptr;
4933464ebd5Sriastradh
4943464ebd5Sriastradh   if (src->screen != dest->screen) {
4953464ebd5Sriastradh      *errorptr = BadMatch;
4963464ebd5Sriastradh      *x11errorptr = true;
4973464ebd5Sriastradh      return true;
4983464ebd5Sriastradh   }
4993464ebd5Sriastradh
5003464ebd5Sriastradh   if (dest == currentptr || dest->is_current) {
5013464ebd5Sriastradh      *errorptr = BadAccess;
5023464ebd5Sriastradh      *x11errorptr = true;
5033464ebd5Sriastradh      return true;
5043464ebd5Sriastradh   }
5053464ebd5Sriastradh
5063464ebd5Sriastradh   /*
5073464ebd5Sriastradh    * If srcptr is the current context then we should do an implicit glFlush.
5083464ebd5Sriastradh    */
5093464ebd5Sriastradh   if (currentptr == srcptr)
5103464ebd5Sriastradh      glFlush();
5113464ebd5Sriastradh
5123464ebd5Sriastradh   err = apple_cgl.copy_context(src->context_obj, dest->context_obj,
5133464ebd5Sriastradh                                (GLbitfield) mask);
5143464ebd5Sriastradh
5153464ebd5Sriastradh   if (kCGLNoError != err) {
5163464ebd5Sriastradh      *errorptr = GLXBadContext;
5173464ebd5Sriastradh      *x11errorptr = false;
5183464ebd5Sriastradh      return true;
5193464ebd5Sriastradh   }
5203464ebd5Sriastradh
5213464ebd5Sriastradh   return false;
5223464ebd5Sriastradh}
5233464ebd5Sriastradh
5243464ebd5Sriastradh/*
5253464ebd5Sriastradh * The value returned is the total number of contexts set to update.
5263464ebd5Sriastradh * It's meant for debugging/introspection.
5273464ebd5Sriastradh */
5283464ebd5Sriastradhint
5293464ebd5Sriastradhapple_glx_context_surface_changed(unsigned int uid, pthread_t caller)
5303464ebd5Sriastradh{
5313464ebd5Sriastradh   struct apple_glx_context *ac;
5323464ebd5Sriastradh   int updated = 0;
5333464ebd5Sriastradh
5343464ebd5Sriastradh   lock_context_list();
5353464ebd5Sriastradh
5363464ebd5Sriastradh   for (ac = context_list; ac; ac = ac->next) {
5373464ebd5Sriastradh      if (ac->drawable && APPLE_GLX_DRAWABLE_SURFACE == ac->drawable->type
5383464ebd5Sriastradh          && ac->drawable->types.surface.uid == uid) {
5393464ebd5Sriastradh
5403464ebd5Sriastradh         if (caller == ac->thread_id) {
5413464ebd5Sriastradh            apple_glx_diagnostic("caller is the same thread for uid %u\n",
5423464ebd5Sriastradh                                 uid);
5433464ebd5Sriastradh
5443464ebd5Sriastradh            xp_update_gl_context(ac->context_obj);
5453464ebd5Sriastradh         }
5463464ebd5Sriastradh         else {
5473464ebd5Sriastradh            ac->need_update = true;
5483464ebd5Sriastradh            ++updated;
5493464ebd5Sriastradh         }
5503464ebd5Sriastradh      }
5513464ebd5Sriastradh   }
5523464ebd5Sriastradh
5533464ebd5Sriastradh   unlock_context_list();
5543464ebd5Sriastradh
5553464ebd5Sriastradh   return updated;
5563464ebd5Sriastradh}
5573464ebd5Sriastradh
5583464ebd5Sriastradhvoid
5593464ebd5Sriastradhapple_glx_context_update(Display * dpy, void *ptr)
5603464ebd5Sriastradh{
5613464ebd5Sriastradh   struct apple_glx_context *ac = ptr;
5623464ebd5Sriastradh
5633464ebd5Sriastradh   if (NULL == ac->drawable && None != ac->last_surface_window) {
5643464ebd5Sriastradh      bool failed;
5653464ebd5Sriastradh
5663464ebd5Sriastradh      /* Attempt to recreate the surface for a destroyed drawable. */
5673464ebd5Sriastradh      failed =
5683464ebd5Sriastradh         apple_glx_make_current_context(dpy, ac, ac, ac->last_surface_window);
5693464ebd5Sriastradh
5703464ebd5Sriastradh      apple_glx_diagnostic("%s: surface recreation failed? %s\n", __func__,
5713464ebd5Sriastradh                           failed ? "YES" : "NO");
5723464ebd5Sriastradh   }
5733464ebd5Sriastradh
5743464ebd5Sriastradh   if (ac->need_update) {
5753464ebd5Sriastradh      xp_update_gl_context(ac->context_obj);
5763464ebd5Sriastradh      ac->need_update = false;
5773464ebd5Sriastradh
5783464ebd5Sriastradh      apple_glx_diagnostic("%s: updating context %p\n", __func__, ptr);
5793464ebd5Sriastradh   }
5803464ebd5Sriastradh
5813464ebd5Sriastradh   if (ac->drawable && APPLE_GLX_DRAWABLE_SURFACE == ac->drawable->type
5823464ebd5Sriastradh       && ac->drawable->types.surface.pending_destroy) {
5833464ebd5Sriastradh      apple_glx_diagnostic("%s: clearing drawable %p\n", __func__, ptr);
5843464ebd5Sriastradh      apple_cgl.clear_drawable(ac->context_obj);
5853464ebd5Sriastradh
5863464ebd5Sriastradh      if (ac->drawable) {
5873464ebd5Sriastradh         struct apple_glx_drawable *d;
5883464ebd5Sriastradh
5893464ebd5Sriastradh         apple_glx_diagnostic("%s: attempting to destroy drawable %p\n",
5903464ebd5Sriastradh                              __func__, ptr);
5913464ebd5Sriastradh         apple_glx_diagnostic("%s: ac->drawable->drawable is 0x%lx\n",
5923464ebd5Sriastradh                              __func__, ac->drawable->drawable);
5933464ebd5Sriastradh
5943464ebd5Sriastradh         d = ac->drawable;
5953464ebd5Sriastradh
5963464ebd5Sriastradh         ac->last_surface_window = d->drawable;
5973464ebd5Sriastradh
5983464ebd5Sriastradh         ac->drawable = NULL;
5993464ebd5Sriastradh
6003464ebd5Sriastradh         /*
6013464ebd5Sriastradh          * This will destroy the surface drawable if there are
6023464ebd5Sriastradh          * no references to it.
6033464ebd5Sriastradh          * It also subtracts 1 from the reference_count.
6043464ebd5Sriastradh          * If there are references to it, then it's probably made
6053464ebd5Sriastradh          * current in another context.
6063464ebd5Sriastradh          */
6073464ebd5Sriastradh         d->destroy(d);
6083464ebd5Sriastradh      }
6093464ebd5Sriastradh   }
6103464ebd5Sriastradh}
6113464ebd5Sriastradh
6123464ebd5Sriastradhbool
6133464ebd5Sriastradhapple_glx_context_uses_stereo(void *ptr)
6143464ebd5Sriastradh{
6153464ebd5Sriastradh   struct apple_glx_context *ac = ptr;
6163464ebd5Sriastradh
6173464ebd5Sriastradh   return ac->uses_stereo;
6183464ebd5Sriastradh}
619