~mmach/netext73/mesa-haswell

« back to all changes in this revision

Viewing changes to src/glx/apple/apple_glx_context.c

  • Committer: mmach
  • Date: 2022-09-22 19:56:13 UTC
  • Revision ID: netbit73@gmail.com-20220922195613-wtik9mmy20tmor0i
2022-09-22 21:17:09

Show diffs side-by-side

added added

removed removed

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