g3dvl: Use sobel filter for chroma interpolation
[mesa/nouveau-pmpeg.git] / src / glx / apple / apple_glx_drawable.c
blob55302243358a2ebbcf2f21655dc4f7a3e3463407
1 /*
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.
30 #include <stdbool.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <assert.h>
34 #include <pthread.h>
35 #include "apple_glx.h"
36 #include "apple_glx_context.h"
37 #include "apple_glx_drawable.h"
38 #include "appledri.h"
40 static pthread_mutex_t drawables_lock = PTHREAD_MUTEX_INITIALIZER;
41 static struct apple_glx_drawable *drawables_list = NULL;
43 static void
44 lock_drawables_list(void)
46 int err;
48 err = pthread_mutex_lock(&drawables_lock);
50 if (err) {
51 fprintf(stderr, "pthread_mutex_lock failure in %s: %d\n",
52 __func__, err);
53 abort();
57 static void
58 unlock_drawables_list(void)
60 int err;
62 err = pthread_mutex_unlock(&drawables_lock);
64 if (err) {
65 fprintf(stderr, "pthread_mutex_unlock failure in %s: %d\n",
66 __func__, err);
67 abort();
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) {
80 agd = i;
81 break;
85 unlock_drawables_list();
87 return agd;
90 static void
91 drawable_lock(struct apple_glx_drawable *agd)
93 int err;
95 err = pthread_mutex_lock(&agd->mutex);
97 if (err) {
98 fprintf(stderr, "pthread_mutex_lock error: %d\n", err);
99 abort();
103 static void
104 drawable_unlock(struct apple_glx_drawable *d)
106 int err;
108 err = pthread_mutex_unlock(&d->mutex);
110 if (err) {
111 fprintf(stderr, "pthread_mutex_unlock error: %d\n", err);
112 abort();
117 static void
118 reference_drawable(struct apple_glx_drawable *d)
120 d->lock(d);
121 d->reference_count++;
122 d->unlock(d);
125 static void
126 release_drawable(struct apple_glx_drawable *d)
128 d->lock(d);
129 d->reference_count--;
130 d->unlock(d);
133 /* The drawables list must be locked prior to calling this. */
134 /* Return true if the drawable was destroyed. */
135 static bool
136 destroy_drawable(struct apple_glx_drawable *d)
139 d->lock(d);
141 if (d->reference_count > 0) {
142 d->unlock(d);
143 return false;
146 d->unlock(d);
148 if (d->previous) {
149 d->previous->next = d->next;
151 else {
153 * The item must be at the head of the list, if it
154 * has no previous pointer.
156 drawables_list = d->next;
159 if (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);
175 free(d);
177 /* So that the locks are balanced and the caller correctly unlocks. */
178 lock_drawables_list();
180 return true;
184 * This is typically called when a context is destroyed or the current
185 * drawable is made None.
187 static bool
188 destroy_drawable_callback(struct apple_glx_drawable *d)
190 bool result;
192 d->lock(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) {
200 d->unlock(d);
201 return false;
204 d->unlock(d);
206 lock_drawables_list();
208 result = destroy_drawable(d);
210 unlock_drawables_list();
212 return result;
215 static bool
216 is_pbuffer(struct apple_glx_drawable *d)
218 return APPLE_GLX_DRAWABLE_PBUFFER == d->type;
221 static bool
222 is_pixmap(struct apple_glx_drawable *d)
224 return APPLE_GLX_DRAWABLE_PIXMAP == d->type;
227 static void
228 common_init(Display * dpy, GLXDrawable drawable, struct apple_glx_drawable *d)
230 int err;
231 pthread_mutexattr_t attr;
233 d->display = dpy;
234 d->reference_count = 0;
235 d->drawable = drawable;
236 d->type = -1;
238 err = pthread_mutexattr_init(&attr);
240 if (err) {
241 fprintf(stderr, "pthread_mutexattr_init error: %d\n", err);
242 abort();
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);
252 if (err) {
253 fprintf(stderr, "error: setting pthread mutex type: %d\n", err);
254 abort();
257 err = pthread_mutex_init(&d->mutex, &attr);
259 if (err) {
260 fprintf(stderr, "pthread_mutex_init error: %d\n", err);
261 abort();
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;
277 d->width = -1;
278 d->height = -1;
279 d->row_bytes = 0;
280 d->path[0] = '\0';
281 d->fd = -1;
282 d->buffer = NULL;
283 d->buffer_length = 0;
285 d->previous = NULL;
286 d->next = NULL;
289 static void
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;
297 if (drawables_list)
298 drawables_list->previous = agd;
300 drawables_list = agd;
302 unlock_drawables_list();
305 /*WARNING: this returns a locked and referenced object. */
306 bool
307 apple_glx_drawable_create(Display * dpy,
308 int screen,
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);
317 if (NULL == d) {
318 perror("malloc");
319 return true;
322 common_init(dpy, drawable, d);
323 d->type = callbacks->type;
324 d->callbacks = *callbacks;
326 d->reference(d);
327 d->lock(d);
329 link_tail(d);
331 apple_glx_diagnostic("%s: new drawable %p\n", __func__, (void *) d);
333 *agdResult = d;
335 return false;
338 static int error_count = 0;
340 static int
341 error_handler(Display * dpy, XErrorEvent * err)
343 if (err->error_code == BadWindow) {
344 ++error_count;
347 return 0;
350 void
351 apple_glx_garbage_collect_drawables(Display * dpy)
353 struct apple_glx_drawable *d, *dnext;
354 Window root;
355 int x, y;
356 unsigned int width, height, bd, depth;
357 int (*old_handler) (Display *, XErrorEvent *);
360 if (NULL == drawables_list)
361 return;
363 old_handler = XSetErrorHandler(error_handler);
365 XSync(dpy, False);
367 lock_drawables_list();
369 for (d = drawables_list; d;) {
370 dnext = d->next;
372 d->lock(d);
374 if (d->reference_count > 0) {
376 * Skip this, because some context still retains a reference
377 * to the drawable.
379 d->unlock(d);
380 d = dnext;
381 continue;
384 d->unlock(d);
386 error_count = 0;
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,
394 &depth);
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);
403 error_count = 0;
406 d = dnext;
409 XSetErrorHandler(old_handler);
411 unlock_drawables_list();
414 unsigned int
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)
423 ++result;
425 unlock_drawables_list();
427 return result;
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)
440 d->reference(d);
442 if (flags & APPLE_GLX_DRAWABLE_LOCK)
443 d->lock(d);
445 unlock_drawables_list();
447 return d;
451 unlock_drawables_list();
453 return NULL;
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)
466 d->reference(d);
468 if (flags & APPLE_GLX_DRAWABLE_LOCK)
469 d->lock(d);
471 unlock_drawables_list();
473 return d;
477 unlock_drawables_list();
479 return NULL;
482 /* Return true if the type is valid for the drawable. */
483 bool
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.
499 d->release(d);
501 apple_glx_diagnostic("%s d->reference_count %d\n",
502 __func__, d->reference_count);
504 destroy_drawable(d);
505 unlock_drawables_list();
506 return true;
510 unlock_drawables_list();
512 return false;
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)
527 d->reference(d);
529 if (flags & APPLE_GLX_DRAWABLE_LOCK)
530 d->lock(d);
532 unlock_drawables_list();
534 return d;
539 unlock_drawables_list();
541 return NULL;