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
)
142 if (d
->reference_count
> 0) {
150 d
->previous
->next
= d
->next
;
154 * The item must be at the head of the list, if it
155 * has no previous pointer.
157 drawables_list
= d
->next
;
161 d
->next
->previous
= d
->previous
;
163 unlock_drawables_list();
165 if (d
->callbacks
.destroy
) {
167 * Warning: this causes other routines to be called (potentially)
168 * from surface_notify_handler. It's probably best to not have
169 * any locks at this point locked.
171 d
->callbacks
.destroy(d
->display
, d
);
174 apple_glx_diagnostic("%s: freeing %p\n", __func__
, (void *) d
);
176 err
= pthread_mutex_destroy(&d
->mutex
);
178 fprintf(stderr
, "pthread_mutex_destroy error: %s\n", strerror(err
));
184 /* So that the locks are balanced and the caller correctly unlocks. */
185 lock_drawables_list();
191 * This is typically called when a context is destroyed or the current
192 * drawable is made None.
195 destroy_drawable_callback(struct apple_glx_drawable
*d
)
201 apple_glx_diagnostic("%s: %p ->reference_count before -- %d\n", __func__
,
202 (void *) d
, d
->reference_count
);
204 d
->reference_count
--;
206 if (d
->reference_count
> 0) {
213 lock_drawables_list();
215 result
= destroy_drawable(d
);
217 unlock_drawables_list();
223 is_pbuffer(struct apple_glx_drawable
*d
)
225 return APPLE_GLX_DRAWABLE_PBUFFER
== d
->type
;
229 is_pixmap(struct apple_glx_drawable
*d
)
231 return APPLE_GLX_DRAWABLE_PIXMAP
== d
->type
;
235 common_init(Display
* dpy
, GLXDrawable drawable
, struct apple_glx_drawable
*d
)
238 pthread_mutexattr_t attr
;
241 d
->reference_count
= 0;
242 d
->drawable
= drawable
;
245 err
= pthread_mutexattr_init(&attr
);
248 fprintf(stderr
, "pthread_mutexattr_init error: %d\n", err
);
253 * There are some patterns that require a recursive mutex,
254 * when working with locks that protect the apple_glx_drawable,
255 * and reference functions like ->reference, and ->release.
257 err
= pthread_mutexattr_settype(&attr
, PTHREAD_MUTEX_RECURSIVE
);
260 fprintf(stderr
, "error: setting pthread mutex type: %d\n", err
);
264 err
= pthread_mutex_init(&d
->mutex
, &attr
);
267 fprintf(stderr
, "pthread_mutex_init error: %d\n", err
);
271 (void) pthread_mutexattr_destroy(&attr
);
273 d
->lock
= drawable_lock
;
274 d
->unlock
= drawable_unlock
;
276 d
->reference
= reference_drawable
;
277 d
->release
= release_drawable
;
279 d
->destroy
= destroy_drawable_callback
;
281 d
->is_pbuffer
= is_pbuffer
;
282 d
->is_pixmap
= is_pixmap
;
290 d
->buffer_length
= 0;
297 link_tail(struct apple_glx_drawable
*agd
)
299 lock_drawables_list();
301 /* Link the new drawable into the global list. */
302 agd
->next
= drawables_list
;
305 drawables_list
->previous
= agd
;
307 drawables_list
= agd
;
309 unlock_drawables_list();
312 /*WARNING: this returns a locked and referenced object. */
314 apple_glx_drawable_create(Display
* dpy
,
316 GLXDrawable drawable
,
317 struct apple_glx_drawable
**agdResult
,
318 struct apple_glx_drawable_callbacks
*callbacks
)
320 struct apple_glx_drawable
*d
;
322 d
= calloc(1, sizeof *d
);
329 common_init(dpy
, drawable
, d
);
330 d
->type
= callbacks
->type
;
331 d
->callbacks
= *callbacks
;
338 apple_glx_diagnostic("%s: new drawable %p\n", __func__
, (void *) d
);
345 static int error_count
= 0;
348 error_handler(Display
* dpy
, XErrorEvent
* err
)
350 if (err
->error_code
== BadWindow
) {
358 apple_glx_garbage_collect_drawables(Display
* dpy
)
360 struct apple_glx_drawable
*d
, *dnext
;
363 unsigned int width
, height
, bd
, depth
;
364 int (*old_handler
) (Display
*, XErrorEvent
*);
367 if (NULL
== drawables_list
)
370 old_handler
= XSetErrorHandler(error_handler
);
374 lock_drawables_list();
376 for (d
= drawables_list
; d
;) {
381 if (d
->reference_count
> 0) {
383 * Skip this, because some context still retains a reference
396 * Mesa uses XGetWindowAttributes, but some of these things are
397 * most definitely not Windows, and that's against the rules.
398 * XGetGeometry on the other hand is legal with a Pixmap and Window.
400 XGetGeometry(dpy
, d
->drawable
, &root
, &x
, &y
, &width
, &height
, &bd
,
403 if (error_count
> 0) {
405 * Note: this may not actually destroy the drawable.
406 * If another context retains a reference to the drawable
407 * after the reference count test above.
409 (void) destroy_drawable(d
);
416 XSetErrorHandler(old_handler
);
418 unlock_drawables_list();
422 apple_glx_get_drawable_count(void)
424 unsigned int result
= 0;
425 struct apple_glx_drawable
*d
;
427 lock_drawables_list();
429 for (d
= drawables_list
; d
; d
= d
->next
)
432 unlock_drawables_list();
437 struct apple_glx_drawable
*
438 apple_glx_drawable_find_by_type(GLXDrawable drawable
, int type
, int flags
)
440 struct apple_glx_drawable
*d
;
442 lock_drawables_list();
444 for (d
= drawables_list
; d
; d
= d
->next
) {
445 if (d
->type
== type
&& d
->drawable
== drawable
) {
446 if (flags
& APPLE_GLX_DRAWABLE_REFERENCE
)
449 if (flags
& APPLE_GLX_DRAWABLE_LOCK
)
452 unlock_drawables_list();
458 unlock_drawables_list();
463 struct apple_glx_drawable
*
464 apple_glx_drawable_find(GLXDrawable drawable
, int flags
)
466 struct apple_glx_drawable
*d
;
468 lock_drawables_list();
470 for (d
= drawables_list
; d
; d
= d
->next
) {
471 if (d
->drawable
== drawable
) {
472 if (flags
& APPLE_GLX_DRAWABLE_REFERENCE
)
475 if (flags
& APPLE_GLX_DRAWABLE_LOCK
)
478 unlock_drawables_list();
484 unlock_drawables_list();
489 /* Return true if the type is valid for the drawable. */
491 apple_glx_drawable_destroy_by_type(Display
* dpy
,
492 GLXDrawable drawable
, int type
)
494 struct apple_glx_drawable
*d
;
496 lock_drawables_list();
498 for (d
= drawables_list
; d
; d
= d
->next
) {
499 if (drawable
== d
->drawable
&& type
== d
->type
) {
501 * The user has requested that we destroy this resource.
502 * However, there may be references in the contexts to it, so
503 * release it, and call destroy_drawable which doesn't destroy
504 * if the reference_count is > 0.
508 apple_glx_diagnostic("%s d->reference_count %d\n",
509 __func__
, d
->reference_count
);
512 unlock_drawables_list();
517 unlock_drawables_list();
522 struct apple_glx_drawable
*
523 apple_glx_drawable_find_by_uid(unsigned int uid
, int flags
)
525 struct apple_glx_drawable
*d
;
527 lock_drawables_list();
529 for (d
= drawables_list
; d
; d
= d
->next
) {
530 /* Only surfaces have a uid. */
531 if (APPLE_GLX_DRAWABLE_SURFACE
== d
->type
) {
532 if (d
->types
.surface
.uid
== uid
) {
533 if (flags
& APPLE_GLX_DRAWABLE_REFERENCE
)
536 if (flags
& APPLE_GLX_DRAWABLE_LOCK
)
539 unlock_drawables_list();
546 unlock_drawables_list();