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