Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/glx/apple/apple_glx_context.c
4560 views
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
}
619
620