Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/glx/apple/apple_glx_drawable.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 <assert.h>
34
#include <pthread.h>
35
#include <string.h>
36
#include "apple_glx.h"
37
#include "apple_glx_context.h"
38
#include "apple_glx_drawable.h"
39
#include "appledri.h"
40
41
static pthread_mutex_t drawables_lock = PTHREAD_MUTEX_INITIALIZER;
42
static struct apple_glx_drawable *drawables_list = NULL;
43
44
static void
45
lock_drawables_list(void)
46
{
47
int err;
48
49
err = pthread_mutex_lock(&drawables_lock);
50
51
if (err) {
52
fprintf(stderr, "pthread_mutex_lock failure in %s: %s\n",
53
__func__, strerror(err));
54
abort();
55
}
56
}
57
58
static void
59
unlock_drawables_list(void)
60
{
61
int err;
62
63
err = pthread_mutex_unlock(&drawables_lock);
64
65
if (err) {
66
fprintf(stderr, "pthread_mutex_unlock failure in %s: %s\n",
67
__func__, strerror(err));
68
abort();
69
}
70
}
71
72
struct apple_glx_drawable *
73
apple_glx_find_drawable(Display * dpy, GLXDrawable drawable)
74
{
75
struct apple_glx_drawable *i, *agd = NULL;
76
77
lock_drawables_list();
78
79
for (i = drawables_list; i; i = i->next) {
80
if (i->drawable == drawable) {
81
agd = i;
82
break;
83
}
84
}
85
86
unlock_drawables_list();
87
88
return agd;
89
}
90
91
static void
92
drawable_lock(struct apple_glx_drawable *agd)
93
{
94
int err;
95
96
err = pthread_mutex_lock(&agd->mutex);
97
98
if (err) {
99
fprintf(stderr, "pthread_mutex_lock error: %s\n", strerror(err));
100
abort();
101
}
102
}
103
104
static void
105
drawable_unlock(struct apple_glx_drawable *d)
106
{
107
int err;
108
109
err = pthread_mutex_unlock(&d->mutex);
110
111
if (err) {
112
fprintf(stderr, "pthread_mutex_unlock error: %s\n", strerror(err));
113
abort();
114
}
115
}
116
117
118
static void
119
reference_drawable(struct apple_glx_drawable *d)
120
{
121
d->lock(d);
122
d->reference_count++;
123
d->unlock(d);
124
}
125
126
static void
127
release_drawable(struct apple_glx_drawable *d)
128
{
129
d->lock(d);
130
d->reference_count--;
131
d->unlock(d);
132
}
133
134
/* The drawables list must be locked prior to calling this. */
135
/* Return true if the drawable was destroyed. */
136
static bool
137
destroy_drawable(struct apple_glx_drawable *d)
138
{
139
int err;
140
141
d->lock(d);
142
143
if (d->reference_count > 0) {
144
d->unlock(d);
145
return false;
146
}
147
148
d->unlock(d);
149
150
if (d->previous) {
151
d->previous->next = d->next;
152
}
153
else {
154
/*
155
* The item must be at the head of the list, if it
156
* has no previous pointer.
157
*/
158
drawables_list = d->next;
159
}
160
161
if (d->next)
162
d->next->previous = d->previous;
163
164
unlock_drawables_list();
165
166
if (d->callbacks.destroy) {
167
/*
168
* Warning: this causes other routines to be called (potentially)
169
* from surface_notify_handler. It's probably best to not have
170
* any locks at this point locked.
171
*/
172
d->callbacks.destroy(d->display, d);
173
}
174
175
apple_glx_diagnostic("%s: freeing %p\n", __func__, (void *) d);
176
177
/* Stupid recursive locks */
178
while (pthread_mutex_unlock(&d->mutex) == 0);
179
180
err = pthread_mutex_destroy(&d->mutex);
181
if (err) {
182
fprintf(stderr, "pthread_mutex_destroy error: %s\n", strerror(err));
183
abort();
184
}
185
186
free(d);
187
188
/* So that the locks are balanced and the caller correctly unlocks. */
189
lock_drawables_list();
190
191
return true;
192
}
193
194
/*
195
* This is typically called when a context is destroyed or the current
196
* drawable is made None.
197
*/
198
static bool
199
destroy_drawable_callback(struct apple_glx_drawable *d)
200
{
201
bool result;
202
203
d->lock(d);
204
205
apple_glx_diagnostic("%s: %p ->reference_count before -- %d\n", __func__,
206
(void *) d, d->reference_count);
207
208
d->reference_count--;
209
210
if (d->reference_count > 0) {
211
d->unlock(d);
212
return false;
213
}
214
215
d->unlock(d);
216
217
lock_drawables_list();
218
219
result = destroy_drawable(d);
220
221
unlock_drawables_list();
222
223
return result;
224
}
225
226
static bool
227
is_pbuffer(struct apple_glx_drawable *d)
228
{
229
return APPLE_GLX_DRAWABLE_PBUFFER == d->type;
230
}
231
232
static bool
233
is_pixmap(struct apple_glx_drawable *d)
234
{
235
return APPLE_GLX_DRAWABLE_PIXMAP == d->type;
236
}
237
238
static void
239
common_init(Display * dpy, GLXDrawable drawable, struct apple_glx_drawable *d)
240
{
241
int err;
242
pthread_mutexattr_t attr;
243
244
d->display = dpy;
245
d->reference_count = 0;
246
d->drawable = drawable;
247
d->type = -1;
248
249
err = pthread_mutexattr_init(&attr);
250
251
if (err) {
252
fprintf(stderr, "pthread_mutexattr_init error: %s\n", strerror(err));
253
abort();
254
}
255
256
/*
257
* There are some patterns that require a recursive mutex,
258
* when working with locks that protect the apple_glx_drawable,
259
* and reference functions like ->reference, and ->release.
260
*/
261
err = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
262
263
if (err) {
264
fprintf(stderr, "error: setting pthread mutex type: %s\n", strerror(err));
265
abort();
266
}
267
268
err = pthread_mutex_init(&d->mutex, &attr);
269
270
if (err) {
271
fprintf(stderr, "pthread_mutex_init error: %s\n", strerror(err));
272
abort();
273
}
274
275
(void) pthread_mutexattr_destroy(&attr);
276
277
d->lock = drawable_lock;
278
d->unlock = drawable_unlock;
279
280
d->reference = reference_drawable;
281
d->release = release_drawable;
282
283
d->destroy = destroy_drawable_callback;
284
285
d->is_pbuffer = is_pbuffer;
286
d->is_pixmap = is_pixmap;
287
288
d->width = -1;
289
d->height = -1;
290
d->row_bytes = 0;
291
d->path[0] = '\0';
292
d->fd = -1;
293
d->buffer = NULL;
294
d->buffer_length = 0;
295
296
d->previous = NULL;
297
d->next = NULL;
298
}
299
300
static void
301
link_tail(struct apple_glx_drawable *agd)
302
{
303
lock_drawables_list();
304
305
/* Link the new drawable into the global list. */
306
agd->next = drawables_list;
307
308
if (drawables_list)
309
drawables_list->previous = agd;
310
311
drawables_list = agd;
312
313
unlock_drawables_list();
314
}
315
316
/*WARNING: this returns a locked and referenced object. */
317
bool
318
apple_glx_drawable_create(Display * dpy,
319
int screen,
320
GLXDrawable drawable,
321
struct apple_glx_drawable **agdResult,
322
struct apple_glx_drawable_callbacks *callbacks)
323
{
324
struct apple_glx_drawable *d;
325
326
d = calloc(1, sizeof *d);
327
328
if (NULL == d) {
329
perror("malloc");
330
return true;
331
}
332
333
common_init(dpy, drawable, d);
334
d->type = callbacks->type;
335
d->callbacks = *callbacks;
336
337
d->reference(d);
338
d->lock(d);
339
340
link_tail(d);
341
342
apple_glx_diagnostic("%s: new drawable %p\n", __func__, (void *) d);
343
344
*agdResult = d;
345
346
return false;
347
}
348
349
static int error_count = 0;
350
351
static int
352
error_handler(Display * dpy, XErrorEvent * err)
353
{
354
if (err->error_code == BadWindow) {
355
++error_count;
356
}
357
358
return 0;
359
}
360
361
void
362
apple_glx_garbage_collect_drawables(Display * dpy)
363
{
364
struct apple_glx_drawable *d, *dnext;
365
Window root;
366
int x, y;
367
unsigned int width, height, bd, depth;
368
int (*old_handler) (Display *, XErrorEvent *);
369
370
371
if (NULL == drawables_list)
372
return;
373
374
old_handler = XSetErrorHandler(error_handler);
375
376
XSync(dpy, False);
377
378
lock_drawables_list();
379
380
for (d = drawables_list; d;) {
381
dnext = d->next;
382
383
d->lock(d);
384
385
if (d->reference_count > 0) {
386
/*
387
* Skip this, because some context still retains a reference
388
* to the drawable.
389
*/
390
d->unlock(d);
391
d = dnext;
392
continue;
393
}
394
395
d->unlock(d);
396
397
error_count = 0;
398
399
/*
400
* Mesa uses XGetWindowAttributes, but some of these things are
401
* most definitely not Windows, and that's against the rules.
402
* XGetGeometry on the other hand is legal with a Pixmap and Window.
403
*/
404
XGetGeometry(dpy, d->drawable, &root, &x, &y, &width, &height, &bd,
405
&depth);
406
407
if (error_count > 0) {
408
/*
409
* Note: this may not actually destroy the drawable.
410
* If another context retains a reference to the drawable
411
* after the reference count test above.
412
*/
413
(void) destroy_drawable(d);
414
error_count = 0;
415
}
416
417
d = dnext;
418
}
419
420
XSetErrorHandler(old_handler);
421
422
unlock_drawables_list();
423
}
424
425
unsigned int
426
apple_glx_get_drawable_count(void)
427
{
428
unsigned int result = 0;
429
struct apple_glx_drawable *d;
430
431
lock_drawables_list();
432
433
for (d = drawables_list; d; d = d->next)
434
++result;
435
436
unlock_drawables_list();
437
438
return result;
439
}
440
441
struct apple_glx_drawable *
442
apple_glx_drawable_find_by_type(GLXDrawable drawable, int type, int flags)
443
{
444
struct apple_glx_drawable *d;
445
446
lock_drawables_list();
447
448
for (d = drawables_list; d; d = d->next) {
449
if (d->type == type && d->drawable == drawable) {
450
if (flags & APPLE_GLX_DRAWABLE_REFERENCE)
451
d->reference(d);
452
453
if (flags & APPLE_GLX_DRAWABLE_LOCK)
454
d->lock(d);
455
456
unlock_drawables_list();
457
458
return d;
459
}
460
}
461
462
unlock_drawables_list();
463
464
return NULL;
465
}
466
467
struct apple_glx_drawable *
468
apple_glx_drawable_find(GLXDrawable drawable, int flags)
469
{
470
struct apple_glx_drawable *d;
471
472
lock_drawables_list();
473
474
for (d = drawables_list; d; d = d->next) {
475
if (d->drawable == drawable) {
476
if (flags & APPLE_GLX_DRAWABLE_REFERENCE)
477
d->reference(d);
478
479
if (flags & APPLE_GLX_DRAWABLE_LOCK)
480
d->lock(d);
481
482
unlock_drawables_list();
483
484
return d;
485
}
486
}
487
488
unlock_drawables_list();
489
490
return NULL;
491
}
492
493
/* Return true if the type is valid for the drawable. */
494
bool
495
apple_glx_drawable_destroy_by_type(Display * dpy,
496
GLXDrawable drawable, int type)
497
{
498
struct apple_glx_drawable *d;
499
500
lock_drawables_list();
501
502
for (d = drawables_list; d; d = d->next) {
503
if (drawable == d->drawable && type == d->type) {
504
/*
505
* The user has requested that we destroy this resource.
506
* However, there may be references in the contexts to it, so
507
* release it, and call destroy_drawable which doesn't destroy
508
* if the reference_count is > 0.
509
*/
510
d->release(d);
511
512
apple_glx_diagnostic("%s d->reference_count %d\n",
513
__func__, d->reference_count);
514
515
destroy_drawable(d);
516
unlock_drawables_list();
517
return true;
518
}
519
}
520
521
unlock_drawables_list();
522
523
return false;
524
}
525
526
struct apple_glx_drawable *
527
apple_glx_drawable_find_by_uid(unsigned int uid, int flags)
528
{
529
struct apple_glx_drawable *d;
530
531
lock_drawables_list();
532
533
for (d = drawables_list; d; d = d->next) {
534
/* Only surfaces have a uid. */
535
if (APPLE_GLX_DRAWABLE_SURFACE == d->type) {
536
if (d->types.surface.uid == uid) {
537
if (flags & APPLE_GLX_DRAWABLE_REFERENCE)
538
d->reference(d);
539
540
if (flags & APPLE_GLX_DRAWABLE_LOCK)
541
d->lock(d);
542
543
unlock_drawables_list();
544
545
return d;
546
}
547
}
548
}
549
550
unlock_drawables_list();
551
552
return NULL;
553
}
554
555