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();