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.
36 #include "apple_glx.h"
37 #include "apple_glx_context.h"
38 #include "apple_glx_drawable.h"
41 static pthread_mutex_t drawables_lock
= PTHREAD_MUTEX_INITIALIZER
;
42 static struct apple_glx_drawable
*drawables_list
= NULL
;
45 lock_drawables_list(void)
49 err
= pthread_mutex_lock(&drawables_lock
);
52 fprintf(stderr
, "pthread_mutex_lock failure in %s: %s\n",
53 __func__
, strerror(err
));
59 unlock_drawables_list(void)
63 err
= pthread_mutex_unlock(&drawables_lock
);
66 fprintf(stderr
, "pthread_mutex_unlock failure in %s: %s\n",
67 __func__
, strerror(err
));
72 struct apple_glx_drawable
*
73 apple_glx_find_drawable(Display
* dpy
, GLXDrawable drawable
)
75 struct apple_glx_drawable
*i
, *agd
= NULL
;
77 lock_drawables_list();
79 for (i
= drawables_list
; i
; i
= i
->next
) {
80 if (i
->drawable
== drawable
) {
86 unlock_drawables_list();
92 drawable_lock(struct apple_glx_drawable
*agd
)
96 err
= pthread_mutex_lock(&agd
->mutex
);
99 fprintf(stderr
, "pthread_mutex_lock error: %s\n", strerror(err
));
105 drawable_unlock(struct apple_glx_drawable
*d
)
109 err
= pthread_mutex_unlock(&d
->mutex
);
112 fprintf(stderr
, "pthread_mutex_unlock error: %s\n", strerror(err
));
119 reference_drawable(struct apple_glx_drawable
*d
)
122 d
->reference_count
++;
127 release_drawable(struct apple_glx_drawable
*d
)
130 d
->reference_count
--;
134 /* The drawables list must be locked prior to calling this. */
135 /* Return true if the drawable was destroyed. */
137 destroy_drawable(struct apple_glx_drawable
*d
)
143 if (d
->reference_count
> 0) {
151 d
->previous
->next
= d
->next
;
155 * The item must be at the head of the list, if it
156 * has no previous pointer.
158 drawables_list
= d
->next
;
162 d
->next
->previous
= d
->previous
;
164 unlock_drawables_list();
166 if (d
->callbacks
.destroy
) {
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.
172 d
->callbacks
.destroy(d
->display
, d
);
175 apple_glx_diagnostic("%s: freeing %p\n", __func__
, (void *) d
);
177 /* Stupid recursive locks */
178 while (pthread_mutex_unlock(&d
->mutex
) == 0);
180 err
= pthread_mutex_destroy(&d
->mutex
);
182 fprintf(stderr
, "pthread_mutex_destroy error: %s\n", strerror(err
));
188 /* So that the locks are balanced and the caller correctly unlocks. */
189 lock_drawables_list();
195 * This is typically called when a context is destroyed or the current
196 * drawable is made None.
199 destroy_drawable_callback(struct apple_glx_drawable
*d
)
205 apple_glx_diagnostic("%s: %p ->reference_count before -- %d\n", __func__
,
206 (void *) d
, d
->reference_count
);
208 d
->reference_count
--;
210 if (d
->reference_count
> 0) {
217 lock_drawables_list();
219 result
= destroy_drawable(d
);
221 unlock_drawables_list();
227 is_pbuffer(struct apple_glx_drawable
*d
)
229 return APPLE_GLX_DRAWABLE_PBUFFER
== d
->type
;
233 is_pixmap(struct apple_glx_drawable
*d
)
235 return APPLE_GLX_DRAWABLE_PIXMAP
== d
->type
;
239 common_init(Display
* dpy
, GLXDrawable drawable
, struct apple_glx_drawable
*d
)
242 pthread_mutexattr_t attr
;
245 d
->reference_count
= 0;
246 d
->drawable
= drawable
;
249 err
= pthread_mutexattr_init(&attr
);
252 fprintf(stderr
, "pthread_mutexattr_init error: %s\n", strerror(err
));
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.
261 err
= pthread_mutexattr_settype(&attr
, PTHREAD_MUTEX_RECURSIVE
);
264 fprintf(stderr
, "error: setting pthread mutex type: %s\n", strerror(err
));
268 err
= pthread_mutex_init(&d
->mutex
, &attr
);
271 fprintf(stderr
, "pthread_mutex_init error: %s\n", strerror(err
));
275 (void) pthread_mutexattr_destroy(&attr
);
277 d
->lock
= drawable_lock
;
278 d
->unlock
= drawable_unlock
;
280 d
->reference
= reference_drawable
;
281 d
->release
= release_drawable
;
283 d
->destroy
= destroy_drawable_callback
;
285 d
->is_pbuffer
= is_pbuffer
;
286 d
->is_pixmap
= is_pixmap
;
294 d
->buffer_length
= 0;
301 link_tail(struct apple_glx_drawable
*agd
)
303 lock_drawables_list();
305 /* Link the new drawable into the global list. */
306 agd
->next
= drawables_list
;
309 drawables_list
->previous
= agd
;
311 drawables_list
= agd
;
313 unlock_drawables_list();
316 /*WARNING: this returns a locked and referenced object. */
318 apple_glx_drawable_create(Display
* dpy
,
320 GLXDrawable drawable
,
321 struct apple_glx_drawable
**agdResult
,
322 struct apple_glx_drawable_callbacks
*callbacks
)
324 struct apple_glx_drawable
*d
;
326 d
= calloc(1, sizeof *d
);
333 common_init(dpy
, drawable
, d
);
334 d
->type
= callbacks
->type
;
335 d
->callbacks
= *callbacks
;
342 apple_glx_diagnostic("%s: new drawable %p\n", __func__
, (void *) d
);
349 static int error_count
= 0;
352 error_handler(Display
* dpy
, XErrorEvent
* err
)
354 if (err
->error_code
== BadWindow
) {
362 apple_glx_garbage_collect_drawables(Display
* dpy
)
364 struct apple_glx_drawable
*d
, *dnext
;
367 unsigned int width
, height
, bd
, depth
;
368 int (*old_handler
) (Display
*, XErrorEvent
*);
371 if (NULL
== drawables_list
)
374 old_handler
= XSetErrorHandler(error_handler
);
378 lock_drawables_list();
380 for (d
= drawables_list
; d
;) {
385 if (d
->reference_count
> 0) {
387 * Skip this, because some context still retains a reference
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.
404 XGetGeometry(dpy
, d
->drawable
, &root
, &x
, &y
, &width
, &height
, &bd
,
407 if (error_count
> 0) {
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.
413 (void) destroy_drawable(d
);
420 XSetErrorHandler(old_handler
);
422 unlock_drawables_list();
426 apple_glx_get_drawable_count(void)
428 unsigned int result
= 0;
429 struct apple_glx_drawable
*d
;
431 lock_drawables_list();
433 for (d
= drawables_list
; d
; d
= d
->next
)
436 unlock_drawables_list();
441 struct apple_glx_drawable
*
442 apple_glx_drawable_find_by_type(GLXDrawable drawable
, int type
, int flags
)
444 struct apple_glx_drawable
*d
;
446 lock_drawables_list();
448 for (d
= drawables_list
; d
; d
= d
->next
) {
449 if (d
->type
== type
&& d
->drawable
== drawable
) {
450 if (flags
& APPLE_GLX_DRAWABLE_REFERENCE
)
453 if (flags
& APPLE_GLX_DRAWABLE_LOCK
)
456 unlock_drawables_list();
462 unlock_drawables_list();
467 struct apple_glx_drawable
*
468 apple_glx_drawable_find(GLXDrawable drawable
, int flags
)
470 struct apple_glx_drawable
*d
;
472 lock_drawables_list();
474 for (d
= drawables_list
; d
; d
= d
->next
) {
475 if (d
->drawable
== drawable
) {
476 if (flags
& APPLE_GLX_DRAWABLE_REFERENCE
)
479 if (flags
& APPLE_GLX_DRAWABLE_LOCK
)
482 unlock_drawables_list();
488 unlock_drawables_list();
493 /* Return true if the type is valid for the drawable. */
495 apple_glx_drawable_destroy_by_type(Display
* dpy
,
496 GLXDrawable drawable
, int type
)
498 struct apple_glx_drawable
*d
;
500 lock_drawables_list();
502 for (d
= drawables_list
; d
; d
= d
->next
) {
503 if (drawable
== d
->drawable
&& type
== d
->type
) {
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.
512 apple_glx_diagnostic("%s d->reference_count %d\n",
513 __func__
, d
->reference_count
);
516 unlock_drawables_list();
521 unlock_drawables_list();
526 struct apple_glx_drawable
*
527 apple_glx_drawable_find_by_uid(unsigned int uid
, int flags
)
529 struct apple_glx_drawable
*d
;
531 lock_drawables_list();
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
)
540 if (flags
& APPLE_GLX_DRAWABLE_LOCK
)
543 unlock_drawables_list();
550 unlock_drawables_list();