Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / glx / apple / apple_glx_context.c
1 /* 
2  Copyright (c) 2008, 2009 Apple Inc.
3  
4  Permission is hereby granted, free of charge, to any person
5  obtaining a copy of this software and associated documentation files
6  (the "Software"), to deal in the Software without restriction,
7  including without limitation the rights to use, copy, modify, merge,
8  publish, distribute, sublicense, and/or sell copies of the Software,
9  and to permit persons to whom the Software is furnished to do so,
10  subject to the following conditions:
11  
12  The above copyright notice and this permission notice shall be
13  included in all copies or substantial portions of the Software.
14  
15  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18  NONINFRINGEMENT.  IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT
19  HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  DEALINGS IN THE SOFTWARE.
23  
24  Except as contained in this notice, the name(s) of the above
25  copyright holders shall not be used in advertising or otherwise to
26  promote the sale, use or other dealings in this Software without
27  prior written authorization.
28 */
29
30 #include <stdbool.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <limits.h>
34 #include <assert.h>
35 #include <pthread.h>
36
37 #include <fcntl.h>
38 #include <sys/mman.h>
39 #include <unistd.h>
40
41 // Get the newer glext.h first
42 #include <GL/gl.h>
43 #include <GL/glext.h>
44
45 #include <OpenGL/CGLTypes.h>
46 #include <OpenGL/CGLCurrent.h>
47 #include <OpenGL/OpenGL.h>
48
49 #include "glxclient.h"
50
51 #include "apple_glx.h"
52 #include "apple_glx_context.h"
53 #include "appledri.h"
54 #include "apple_visual.h"
55 #include "apple_cgl.h"
56 #include "apple_glx_drawable.h"
57
58 static pthread_mutex_t context_lock = PTHREAD_MUTEX_INITIALIZER;
59
60 /*
61  * This should be locked on creation and destruction of the 
62  * apple_glx_contexts.
63  *
64  * It's also locked when the surface_notify_handler is searching
65  * for a uid associated with a surface.
66  */
67 static struct apple_glx_context *context_list = NULL;
68
69 /* This guards the context_list above. */
70 static void
71 lock_context_list(void)
72 {
73    int err;
74
75    err = pthread_mutex_lock(&context_lock);
76
77    if (err) {
78       fprintf(stderr, "pthread_mutex_lock failure in %s: %d\n",
79               __func__, err);
80       abort();
81    }
82 }
83
84 static void
85 unlock_context_list(void)
86 {
87    int err;
88
89    err = pthread_mutex_unlock(&context_lock);
90
91    if (err) {
92       fprintf(stderr, "pthread_mutex_unlock failure in %s: %d\n",
93               __func__, err);
94       abort();
95    }
96 }
97
98 static bool
99 is_context_valid(struct apple_glx_context *ac)
100 {
101    struct apple_glx_context *i;
102
103    lock_context_list();
104
105    for (i = context_list; i; i = i->next) {
106       if (ac == i) {
107          unlock_context_list();
108          return true;
109       }
110    }
111
112    unlock_context_list();
113
114    return false;
115 }
116
117 /* This creates an apple_private_context struct.  
118  *
119  * It's typically called to save the struct in a GLXContext.
120  *
121  * This is also where the CGLContextObj is created, and the CGLPixelFormatObj.
122  */
123 bool
124 apple_glx_create_context(void **ptr, Display * dpy, int screen,
125                          const void *mode, void *sharedContext,
126                          int *errorptr, bool * x11errorptr)
127 {
128    struct apple_glx_context *ac;
129    struct apple_glx_context *sharedac = sharedContext;
130    CGLError error;
131
132    *ptr = NULL;
133
134    ac = malloc(sizeof *ac);
135
136    if (NULL == ac) {
137       *errorptr = BadAlloc;
138       *x11errorptr = true;
139       return true;
140    }
141
142    if (sharedac && !is_context_valid(sharedac)) {
143       *errorptr = GLXBadContext;
144       *x11errorptr = false;
145       return true;
146    }
147
148    ac->context_obj = NULL;
149    ac->pixel_format_obj = NULL;
150    ac->drawable = NULL;
151    ac->thread_id = pthread_self();
152    ac->screen = screen;
153    ac->double_buffered = false;
154    ac->uses_stereo = false;
155    ac->need_update = false;
156    ac->is_current = false;
157    ac->made_current = false;
158    ac->last_surface_window = None;
159
160    apple_visual_create_pfobj(&ac->pixel_format_obj, mode,
161                              &ac->double_buffered, &ac->uses_stereo,
162                              /*offscreen */ false);
163
164    error = apple_cgl.create_context(ac->pixel_format_obj,
165                                     sharedac ? sharedac->context_obj : NULL,
166                                     &ac->context_obj);
167
168
169    if (error) {
170       (void) apple_cgl.destroy_pixel_format(ac->pixel_format_obj);
171
172       free(ac);
173
174       if (kCGLBadMatch == error) {
175          *errorptr = BadMatch;
176          *x11errorptr = true;
177       }
178       else {
179          *errorptr = GLXBadContext;
180          *x11errorptr = false;
181       }
182
183       if (getenv("LIBGL_DIAGNOSTIC"))
184          fprintf(stderr, "error: %s\n", apple_cgl.error_string(error));
185
186       return true;
187    }
188
189    /* The context creation succeeded, so we can link in the new context. */
190    lock_context_list();
191
192    if (context_list)
193       context_list->previous = ac;
194
195    ac->previous = NULL;
196    ac->next = context_list;
197    context_list = ac;
198
199    *ptr = ac;
200
201    apple_glx_diagnostic("%s: ac %p ac->context_obj %p\n",
202                         __func__, (void *) ac, (void *) ac->context_obj);
203
204    unlock_context_list();
205
206    return false;
207 }
208
209 void
210 apple_glx_destroy_context(void **ptr, Display * dpy)
211 {
212    struct apple_glx_context *ac = *ptr;
213
214    if (NULL == ac)
215       return;
216
217    apple_glx_diagnostic("%s: ac %p ac->context_obj %p\n",
218                         __func__, (void *) ac, (void *) ac->context_obj);
219
220    if (apple_cgl.get_current_context() == ac->context_obj) {
221       apple_glx_diagnostic("%s: context ac->context_obj %p "
222                            "is still current!\n", __func__,
223                            (void *) ac->context_obj);
224       if (apple_cgl.set_current_context(NULL)) {
225          abort();
226       }
227    }
228
229    /* Remove ac from the context_list as soon as possible. */
230    lock_context_list();
231
232    if (ac->previous) {
233       ac->previous->next = ac->next;
234    }
235    else {
236       context_list = ac->next;
237    }
238
239    if (ac->next) {
240       ac->next->previous = ac->previous;
241    }
242
243    unlock_context_list();
244
245
246    if (apple_cgl.clear_drawable(ac->context_obj)) {
247       fprintf(stderr, "error: while clearing drawable!\n");
248       abort();
249    }
250
251    /*
252     * This potentially causes surface_notify_handler to be called in
253     * apple_glx.c... 
254     * We can NOT have a lock held at this point.  It would result in 
255     * an abort due to an attempted deadlock.  This is why we earlier
256     * removed the ac pointer from the double-linked list.
257     */
258    if (ac->drawable) {
259       ac->drawable->destroy(ac->drawable);
260    }
261
262    if (apple_cgl.destroy_pixel_format(ac->pixel_format_obj)) {
263       fprintf(stderr, "error: destroying pixel format in %s\n", __func__);
264       abort();
265    }
266
267    if (apple_cgl.destroy_context(ac->context_obj)) {
268       fprintf(stderr, "error: destroying context_obj in %s\n", __func__);
269       abort();
270    }
271
272    free(ac);
273
274    *ptr = NULL;
275
276    apple_glx_garbage_collect_drawables(dpy);
277 }
278
279
280 /* Return true if an error occured. */
281 bool
282 apple_glx_make_current_context(Display * dpy, void *oldptr, void *ptr,
283                                GLXDrawable drawable)
284 {
285    struct apple_glx_context *oldac = oldptr;
286    struct apple_glx_context *ac = ptr;
287    struct apple_glx_drawable *newagd = NULL;
288    CGLError cglerr;
289    bool same_drawable = false;
290
291 #if 0
292    apple_glx_diagnostic("%s: oldac %p ac %p drawable 0x%lx\n",
293                         __func__, (void *) oldac, (void *) ac, drawable);
294
295    apple_glx_diagnostic("%s: oldac->context_obj %p ac->context_obj %p\n",
296                         __func__,
297                         (void *) (oldac ? oldac->context_obj : NULL),
298                         (void *) (ac ? ac->context_obj : NULL));
299 #endif
300
301    /* This a common path for GLUT and other apps, so special case it. */
302    if (ac && ac->drawable && ac->drawable->drawable == drawable) {
303       same_drawable = true;
304
305       if (ac->is_current)
306          return false;
307    }
308
309    /* Reset the is_current state of the old context, if non-NULL. */
310    if (oldac && (ac != oldac))
311       oldac->is_current = false;
312
313    if (NULL == ac) {
314       /*Clear the current context for this thread. */
315       apple_cgl.set_current_context(NULL);
316
317       if (oldac) {
318          oldac->is_current = false;
319
320          if (oldac->drawable) {
321             oldac->drawable->destroy(oldac->drawable);
322             oldac->drawable = NULL;
323          }
324
325          /* Invalidate this to prevent surface recreation. */
326          oldac->last_surface_window = None;
327       }
328
329       return false;
330    }
331
332    if (None == drawable) {
333       bool error = false;
334
335       /* Clear the current drawable for this context_obj. */
336
337       if (apple_cgl.set_current_context(ac->context_obj))
338          error = true;
339
340       if (apple_cgl.clear_drawable(ac->context_obj))
341          error = true;
342
343       if (ac->drawable) {
344          ac->drawable->destroy(ac->drawable);
345          ac->drawable = NULL;
346       }
347
348       /* Invalidate this to prevent surface recreation. */
349       ac->last_surface_window = None;
350
351       apple_glx_diagnostic("%s: drawable is None, error is: %d\n",
352                            __func__, error);
353
354       return error;
355    }
356
357    /* This is an optimisation to avoid searching for the current drawable. */
358    if (ac->drawable && ac->drawable->drawable == drawable) {
359       newagd = ac->drawable;
360    }
361    else {
362       /* Find the drawable if possible, and retain a reference to it. */
363       newagd =
364          apple_glx_drawable_find(drawable, APPLE_GLX_DRAWABLE_REFERENCE);
365    }
366
367    /*
368     * Try to destroy the old drawable, so long as the new one
369     * isn't the old. 
370     */
371    if (ac->drawable && !same_drawable) {
372       ac->drawable->destroy(ac->drawable);
373       ac->drawable = NULL;
374    }
375
376    if (NULL == newagd) {
377       if (apple_glx_surface_create(dpy, ac->screen, drawable, &newagd))
378          return true;
379
380       /* The drawable is referenced once by apple_glx_surface_create. */
381
382       /*
383        * FIXME: We actually need 2 references to prevent premature surface 
384        * destruction.  The problem is that the surface gets destroyed in 
385        * the case of the context being reused for another window, and
386        * we then lose the surface contents.  Wait for destruction of a
387        * window to destroy a surface.
388        *
389        * Note: this may leave around surfaces we don't want around, if
390        * say we are using X for raster drawing after OpenGL rendering, 
391        * but it will be compatible with the old libGL's behavior.
392        *
393        * Someday the X11 and OpenGL rendering must be unified at some
394        * layer.  I suspect we can do that via shared memory and 
395        * multiple threads in the X server (1 for each context created
396        * by a client).  This would also allow users to render from 
397        * multiple clients to the same OpenGL surface.  In fact it could
398        * all be OpenGL.
399        *
400        */
401       newagd->reference(newagd);
402
403       /* Save the new drawable with the context structure. */
404       ac->drawable = newagd;
405    }
406    else {
407       /* We are reusing an existing drawable structure. */
408
409       if (same_drawable) {
410          assert(ac->drawable == newagd);
411          /* The drawable_find above retained a reference for us. */
412       }
413       else {
414          ac->drawable = newagd;
415       }
416    }
417
418    /* 
419     * Avoid this costly path if this is the same drawable and the
420     * context is already current. 
421     */
422
423    if (same_drawable && ac->is_current) {
424       apple_glx_diagnostic("%s: same_drawable and ac->is_current\n");
425       return false;
426    }
427
428    cglerr = apple_cgl.set_current_context(ac->context_obj);
429
430    if (kCGLNoError != cglerr) {
431       fprintf(stderr, "set current error: %s\n",
432               apple_cgl.error_string(cglerr));
433       return true;
434    }
435
436    ac->is_current = true;
437
438    assert(NULL != ac->context_obj);
439    assert(NULL != ac->drawable);
440
441    ac->thread_id = pthread_self();
442
443    /* This will be set if the pending_destroy code indicates it should be: */
444    ac->last_surface_window = None;
445
446    switch (ac->drawable->type) {
447    case APPLE_GLX_DRAWABLE_PBUFFER:
448    case APPLE_GLX_DRAWABLE_SURFACE:
449    case APPLE_GLX_DRAWABLE_PIXMAP:
450       if (ac->drawable->callbacks.make_current) {
451          if (ac->drawable->callbacks.make_current(ac, ac->drawable))
452             return true;
453       }
454       break;
455
456    default:
457       fprintf(stderr, "internal error: invalid drawable type: %d\n",
458               ac->drawable->type);
459       abort();
460    }
461
462    return false;
463 }
464
465 bool
466 apple_glx_is_current_drawable(Display * dpy, void *ptr, GLXDrawable drawable)
467 {
468    struct apple_glx_context *ac = ptr;
469
470    if (ac->drawable && ac->drawable->drawable == drawable) {
471       return true;
472    }
473    else if (NULL == ac->drawable && None != ac->last_surface_window) {
474       apple_glx_context_update(dpy, ac);
475
476       return (ac->drawable && ac->drawable->drawable == drawable);
477    }
478
479    return false;
480 }
481
482 bool
483 apple_glx_copy_context(void *currentptr, void *srcptr, void *destptr,
484                        unsigned long mask, int *errorptr, bool * x11errorptr)
485 {
486    struct apple_glx_context *src, *dest;
487    CGLError err;
488
489    src = srcptr;
490    dest = destptr;
491
492    if (src->screen != dest->screen) {
493       *errorptr = BadMatch;
494       *x11errorptr = true;
495       return true;
496    }
497
498    if (dest == currentptr || dest->is_current) {
499       *errorptr = BadAccess;
500       *x11errorptr = true;
501       return true;
502    }
503
504    /* 
505     * If srcptr is the current context then we should do an implicit glFlush.
506     */
507    if (currentptr == srcptr)
508       glFlush();
509
510    err = apple_cgl.copy_context(src->context_obj, dest->context_obj,
511                                 (GLbitfield) mask);
512
513    if (kCGLNoError != err) {
514       *errorptr = GLXBadContext;
515       *x11errorptr = false;
516       return true;
517    }
518
519    return false;
520 }
521
522 /* 
523  * The value returned is the total number of contexts set to update. 
524  * It's meant for debugging/introspection.
525  */
526 int
527 apple_glx_context_surface_changed(unsigned int uid, pthread_t caller)
528 {
529    struct apple_glx_context *ac;
530    int updated = 0;
531
532    lock_context_list();
533
534    for (ac = context_list; ac; ac = ac->next) {
535       if (ac->drawable && APPLE_GLX_DRAWABLE_SURFACE == ac->drawable->type
536           && ac->drawable->types.surface.uid == uid) {
537
538          if (caller == ac->thread_id) {
539             apple_glx_diagnostic("caller is the same thread for uid %u\n",
540                                  uid);
541
542             xp_update_gl_context(ac->context_obj);
543          }
544          else {
545             ac->need_update = true;
546             ++updated;
547          }
548       }
549    }
550
551    unlock_context_list();
552
553    return updated;
554 }
555
556 void
557 apple_glx_context_update(Display * dpy, void *ptr)
558 {
559    struct apple_glx_context *ac = ptr;
560
561    if (NULL == ac->drawable && None != ac->last_surface_window) {
562       bool failed;
563
564       /* Attempt to recreate the surface for a destroyed drawable. */
565       failed =
566          apple_glx_make_current_context(dpy, ac, ac, ac->last_surface_window);
567
568       apple_glx_diagnostic("%s: surface recreation failed? %s\n", __func__,
569                            failed ? "YES" : "NO");
570    }
571
572    if (ac->need_update) {
573       xp_update_gl_context(ac->context_obj);
574       ac->need_update = false;
575
576       apple_glx_diagnostic("%s: updating context %p\n", __func__, ptr);
577    }
578
579    if (ac->drawable && APPLE_GLX_DRAWABLE_SURFACE == ac->drawable->type
580        && ac->drawable->types.surface.pending_destroy) {
581       apple_glx_diagnostic("%s: clearing drawable %p\n", __func__, ptr);
582       apple_cgl.clear_drawable(ac->context_obj);
583
584       if (ac->drawable) {
585          struct apple_glx_drawable *d;
586
587          apple_glx_diagnostic("%s: attempting to destroy drawable %p\n",
588                               __func__, ptr);
589          apple_glx_diagnostic("%s: ac->drawable->drawable is 0x%lx\n",
590                               __func__, ac->drawable->drawable);
591
592          d = ac->drawable;
593
594          ac->last_surface_window = d->drawable;
595
596          ac->drawable = NULL;
597
598          /* 
599           * This will destroy the surface drawable if there are 
600           * no references to it.  
601           * It also subtracts 1 from the reference_count.
602           * If there are references to it, then it's probably made
603           * current in another context.
604           */
605          d->destroy(d);
606       }
607    }
608 }
609
610 bool
611 apple_glx_context_uses_stereo(void *ptr)
612 {
613    struct apple_glx_context *ac = ptr;
614
615    return ac->uses_stereo;
616 }