2
Copyright (c) 2008, 2009 Apple Inc.
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:
12
The above copyright notice and this permission notice shall be
13
included in all copies or substantial portions of the Software.
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.
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.
35
#include "apple_glx.h"
36
#include "apple_glx_context.h"
37
#include "apple_glx_drawable.h"
40
static pthread_mutex_t drawables_lock = PTHREAD_MUTEX_INITIALIZER;
41
static struct apple_glx_drawable *drawables_list = NULL;
44
lock_drawables_list(void)
48
err = pthread_mutex_lock(&drawables_lock);
51
fprintf(stderr, "pthread_mutex_lock failure in %s: %d\n",
58
unlock_drawables_list(void)
62
err = pthread_mutex_unlock(&drawables_lock);
65
fprintf(stderr, "pthread_mutex_unlock failure in %s: %d\n",
71
struct apple_glx_drawable *
72
apple_glx_find_drawable(Display * dpy, GLXDrawable drawable)
74
struct apple_glx_drawable *i, *agd = NULL;
76
lock_drawables_list();
78
for (i = drawables_list; i; i = i->next) {
79
if (i->drawable == drawable) {
85
unlock_drawables_list();
91
drawable_lock(struct apple_glx_drawable *agd)
95
err = pthread_mutex_lock(&agd->mutex);
98
fprintf(stderr, "pthread_mutex_lock error: %d\n", err);
104
drawable_unlock(struct apple_glx_drawable *d)
108
err = pthread_mutex_unlock(&d->mutex);
111
fprintf(stderr, "pthread_mutex_unlock error: %d\n", err);
118
reference_drawable(struct apple_glx_drawable *d)
121
d->reference_count++;
126
release_drawable(struct apple_glx_drawable *d)
129
d->reference_count--;
133
/* The drawables list must be locked prior to calling this. */
134
/* Return true if the drawable was destroyed. */
136
destroy_drawable(struct apple_glx_drawable *d)
141
if (d->reference_count > 0) {
149
d->previous->next = d->next;
153
* The item must be at the head of the list, if it
154
* has no previous pointer.
156
drawables_list = d->next;
160
d->next->previous = d->previous;
162
unlock_drawables_list();
164
if (d->callbacks.destroy) {
166
* Warning: this causes other routines to be called (potentially)
167
* from surface_notify_handler. It's probably best to not have
168
* any locks at this point locked.
170
d->callbacks.destroy(d->display, d);
173
apple_glx_diagnostic("%s: freeing %p\n", __func__, (void *) d);
177
/* So that the locks are balanced and the caller correctly unlocks. */
178
lock_drawables_list();
184
* This is typically called when a context is destroyed or the current
185
* drawable is made None.
188
destroy_drawable_callback(struct apple_glx_drawable *d)
194
apple_glx_diagnostic("%s: %p ->reference_count before -- %d\n", __func__,
195
(void *) d, d->reference_count);
197
d->reference_count--;
199
if (d->reference_count > 0) {
206
lock_drawables_list();
208
result = destroy_drawable(d);
210
unlock_drawables_list();
216
is_pbuffer(struct apple_glx_drawable *d)
218
return APPLE_GLX_DRAWABLE_PBUFFER == d->type;
222
is_pixmap(struct apple_glx_drawable *d)
224
return APPLE_GLX_DRAWABLE_PIXMAP == d->type;
228
common_init(Display * dpy, GLXDrawable drawable, struct apple_glx_drawable *d)
231
pthread_mutexattr_t attr;
234
d->reference_count = 0;
235
d->drawable = drawable;
238
err = pthread_mutexattr_init(&attr);
241
fprintf(stderr, "pthread_mutexattr_init error: %d\n", err);
246
* There are some patterns that require a recursive mutex,
247
* when working with locks that protect the apple_glx_drawable,
248
* and reference functions like ->reference, and ->release.
250
err = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
253
fprintf(stderr, "error: setting pthread mutex type: %d\n", err);
257
err = pthread_mutex_init(&d->mutex, &attr);
260
fprintf(stderr, "pthread_mutex_init error: %d\n", err);
264
(void) pthread_mutexattr_destroy(&attr);
266
d->lock = drawable_lock;
267
d->unlock = drawable_unlock;
269
d->reference = reference_drawable;
270
d->release = release_drawable;
272
d->destroy = destroy_drawable_callback;
274
d->is_pbuffer = is_pbuffer;
275
d->is_pixmap = is_pixmap;
283
d->buffer_length = 0;
290
link_tail(struct apple_glx_drawable *agd)
292
lock_drawables_list();
294
/* Link the new drawable into the global list. */
295
agd->next = drawables_list;
298
drawables_list->previous = agd;
300
drawables_list = agd;
302
unlock_drawables_list();
305
/*WARNING: this returns a locked and referenced object. */
307
apple_glx_drawable_create(Display * dpy,
309
GLXDrawable drawable,
310
struct apple_glx_drawable **agdResult,
311
struct apple_glx_drawable_callbacks *callbacks)
313
struct apple_glx_drawable *d;
315
d = calloc(1, sizeof *d);
322
common_init(dpy, drawable, d);
323
d->type = callbacks->type;
324
d->callbacks = *callbacks;
331
apple_glx_diagnostic("%s: new drawable %p\n", __func__, (void *) d);
338
static int error_count = 0;
341
error_handler(Display * dpy, XErrorEvent * err)
343
if (err->error_code == BadWindow) {
351
apple_glx_garbage_collect_drawables(Display * dpy)
353
struct apple_glx_drawable *d, *dnext;
356
unsigned int width, height, bd, depth;
357
int (*old_handler) (Display *, XErrorEvent *);
360
if (NULL == drawables_list)
363
old_handler = XSetErrorHandler(error_handler);
367
lock_drawables_list();
369
for (d = drawables_list; d;) {
374
if (d->reference_count > 0) {
376
* Skip this, because some context still retains a reference
389
* Mesa uses XGetWindowAttributes, but some of these things are
390
* most definitely not Windows, and that's against the rules.
391
* XGetGeometry on the other hand is legal with a Pixmap and Window.
393
XGetGeometry(dpy, d->drawable, &root, &x, &y, &width, &height, &bd,
396
if (error_count > 0) {
398
* Note: this may not actually destroy the drawable.
399
* If another context retains a reference to the drawable
400
* after the reference count test above.
402
(void) destroy_drawable(d);
409
XSetErrorHandler(old_handler);
411
unlock_drawables_list();
415
apple_glx_get_drawable_count(void)
417
unsigned int result = 0;
418
struct apple_glx_drawable *d;
420
lock_drawables_list();
422
for (d = drawables_list; d; d = d->next)
425
unlock_drawables_list();
430
struct apple_glx_drawable *
431
apple_glx_drawable_find_by_type(GLXDrawable drawable, int type, int flags)
433
struct apple_glx_drawable *d;
435
lock_drawables_list();
437
for (d = drawables_list; d; d = d->next) {
438
if (d->type == type && d->drawable == drawable) {
439
if (flags & APPLE_GLX_DRAWABLE_REFERENCE)
442
if (flags & APPLE_GLX_DRAWABLE_LOCK)
445
unlock_drawables_list();
451
unlock_drawables_list();
456
struct apple_glx_drawable *
457
apple_glx_drawable_find(GLXDrawable drawable, int flags)
459
struct apple_glx_drawable *d;
461
lock_drawables_list();
463
for (d = drawables_list; d; d = d->next) {
464
if (d->drawable == drawable) {
465
if (flags & APPLE_GLX_DRAWABLE_REFERENCE)
468
if (flags & APPLE_GLX_DRAWABLE_LOCK)
471
unlock_drawables_list();
477
unlock_drawables_list();
482
/* Return true if the type is valid for the drawable. */
484
apple_glx_drawable_destroy_by_type(Display * dpy,
485
GLXDrawable drawable, int type)
487
struct apple_glx_drawable *d;
489
lock_drawables_list();
491
for (d = drawables_list; d; d = d->next) {
492
if (drawable == d->drawable && type == d->type) {
494
* The user has requested that we destroy this resource.
495
* However, there may be references in the contexts to it, so
496
* release it, and call destroy_drawable which doesn't destroy
497
* if the reference_count is > 0.
501
apple_glx_diagnostic("%s d->reference_count %d\n",
502
__func__, d->reference_count);
505
unlock_drawables_list();
510
unlock_drawables_list();
515
struct apple_glx_drawable *
516
apple_glx_drawable_find_by_uid(unsigned int uid, int flags)
518
struct apple_glx_drawable *d;
520
lock_drawables_list();
522
for (d = drawables_list; d; d = d->next) {
523
/* Only surfaces have a uid. */
524
if (APPLE_GLX_DRAWABLE_SURFACE == d->type) {
525
if (d->types.surface.uid == uid) {
526
if (flags & APPLE_GLX_DRAWABLE_REFERENCE)
529
if (flags & APPLE_GLX_DRAWABLE_LOCK)
532
unlock_drawables_list();
539
unlock_drawables_list();