Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4358 Serge 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 
31
#include 
32
#include 
33
#include 
34
#include 
35
#include 
36
 
37
#include 
38
#include 
39
#include 
40
 
41
// Get the newer glext.h first
42
#include 
43
#include 
44
 
45
#include 
46
#include 
47
#include 
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("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
}