diff options
author | Roland Scheidegger <[email protected]> | 2010-04-30 15:27:13 +0200 |
---|---|---|
committer | Roland Scheidegger <[email protected]> | 2010-04-30 15:27:13 +0200 |
commit | 7662e3519bef3802024da3050b886068281e02b1 (patch) | |
tree | bc5bf675e67febffaf9e4d1fadd139e8c253ae32 /src/glx/apple/apple_glx_drawable.c | |
parent | 9a966b93c03aecac8eb72e6133aa9a2f2c7673f3 (diff) | |
parent | 7c769bef052fc1936d7ab33e291bb4646dc5b0d1 (diff) |
Merge commit 'origin/master' into gallium-msaa
Diffstat (limited to 'src/glx/apple/apple_glx_drawable.c')
-rw-r--r-- | src/glx/apple/apple_glx_drawable.c | 542 |
1 files changed, 542 insertions, 0 deletions
diff --git a/src/glx/apple/apple_glx_drawable.c b/src/glx/apple/apple_glx_drawable.c new file mode 100644 index 00000000000..55302243358 --- /dev/null +++ b/src/glx/apple/apple_glx_drawable.c @@ -0,0 +1,542 @@ +/* + Copyright (c) 2008, 2009 Apple Inc. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT + HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name(s) of the above + copyright holders shall not be used in advertising or otherwise to + promote the sale, use or other dealings in this Software without + prior written authorization. +*/ + +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> +#include <pthread.h> +#include "apple_glx.h" +#include "apple_glx_context.h" +#include "apple_glx_drawable.h" +#include "appledri.h" + +static pthread_mutex_t drawables_lock = PTHREAD_MUTEX_INITIALIZER; +static struct apple_glx_drawable *drawables_list = NULL; + +static void +lock_drawables_list(void) +{ + int err; + + err = pthread_mutex_lock(&drawables_lock); + + if (err) { + fprintf(stderr, "pthread_mutex_lock failure in %s: %d\n", + __func__, err); + abort(); + } +} + +static void +unlock_drawables_list(void) +{ + int err; + + err = pthread_mutex_unlock(&drawables_lock); + + if (err) { + fprintf(stderr, "pthread_mutex_unlock failure in %s: %d\n", + __func__, err); + abort(); + } +} + +struct apple_glx_drawable * +apple_glx_find_drawable(Display * dpy, GLXDrawable drawable) +{ + struct apple_glx_drawable *i, *agd = NULL; + + lock_drawables_list(); + + for (i = drawables_list; i; i = i->next) { + if (i->drawable == drawable) { + agd = i; + break; + } + } + + unlock_drawables_list(); + + return agd; +} + +static void +drawable_lock(struct apple_glx_drawable *agd) +{ + int err; + + err = pthread_mutex_lock(&agd->mutex); + + if (err) { + fprintf(stderr, "pthread_mutex_lock error: %d\n", err); + abort(); + } +} + +static void +drawable_unlock(struct apple_glx_drawable *d) +{ + int err; + + err = pthread_mutex_unlock(&d->mutex); + + if (err) { + fprintf(stderr, "pthread_mutex_unlock error: %d\n", err); + abort(); + } +} + + +static void +reference_drawable(struct apple_glx_drawable *d) +{ + d->lock(d); + d->reference_count++; + d->unlock(d); +} + +static void +release_drawable(struct apple_glx_drawable *d) +{ + d->lock(d); + d->reference_count--; + d->unlock(d); +} + +/* The drawables list must be locked prior to calling this. */ +/* Return true if the drawable was destroyed. */ +static bool +destroy_drawable(struct apple_glx_drawable *d) +{ + + d->lock(d); + + if (d->reference_count > 0) { + d->unlock(d); + return false; + } + + d->unlock(d); + + if (d->previous) { + d->previous->next = d->next; + } + else { + /* + * The item must be at the head of the list, if it + * has no previous pointer. + */ + drawables_list = d->next; + } + + if (d->next) + d->next->previous = d->previous; + + unlock_drawables_list(); + + if (d->callbacks.destroy) { + /* + * Warning: this causes other routines to be called (potentially) + * from surface_notify_handler. It's probably best to not have + * any locks at this point locked. + */ + d->callbacks.destroy(d->display, d); + } + + apple_glx_diagnostic("%s: freeing %p\n", __func__, (void *) d); + + free(d); + + /* So that the locks are balanced and the caller correctly unlocks. */ + lock_drawables_list(); + + return true; +} + +/* + * This is typically called when a context is destroyed or the current + * drawable is made None. + */ +static bool +destroy_drawable_callback(struct apple_glx_drawable *d) +{ + bool result; + + d->lock(d); + + apple_glx_diagnostic("%s: %p ->reference_count before -- %d\n", __func__, + (void *) d, d->reference_count); + + d->reference_count--; + + if (d->reference_count > 0) { + d->unlock(d); + return false; + } + + d->unlock(d); + + lock_drawables_list(); + + result = destroy_drawable(d); + + unlock_drawables_list(); + + return result; +} + +static bool +is_pbuffer(struct apple_glx_drawable *d) +{ + return APPLE_GLX_DRAWABLE_PBUFFER == d->type; +} + +static bool +is_pixmap(struct apple_glx_drawable *d) +{ + return APPLE_GLX_DRAWABLE_PIXMAP == d->type; +} + +static void +common_init(Display * dpy, GLXDrawable drawable, struct apple_glx_drawable *d) +{ + int err; + pthread_mutexattr_t attr; + + d->display = dpy; + d->reference_count = 0; + d->drawable = drawable; + d->type = -1; + + err = pthread_mutexattr_init(&attr); + + if (err) { + fprintf(stderr, "pthread_mutexattr_init error: %d\n", err); + abort(); + } + + /* + * There are some patterns that require a recursive mutex, + * when working with locks that protect the apple_glx_drawable, + * and reference functions like ->reference, and ->release. + */ + err = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + + if (err) { + fprintf(stderr, "error: setting pthread mutex type: %d\n", err); + abort(); + } + + err = pthread_mutex_init(&d->mutex, &attr); + + if (err) { + fprintf(stderr, "pthread_mutex_init error: %d\n", err); + abort(); + } + + (void) pthread_mutexattr_destroy(&attr); + + d->lock = drawable_lock; + d->unlock = drawable_unlock; + + d->reference = reference_drawable; + d->release = release_drawable; + + d->destroy = destroy_drawable_callback; + + d->is_pbuffer = is_pbuffer; + d->is_pixmap = is_pixmap; + + d->width = -1; + d->height = -1; + d->row_bytes = 0; + d->path[0] = '\0'; + d->fd = -1; + d->buffer = NULL; + d->buffer_length = 0; + + d->previous = NULL; + d->next = NULL; +} + +static void +link_tail(struct apple_glx_drawable *agd) +{ + lock_drawables_list(); + + /* Link the new drawable into the global list. */ + agd->next = drawables_list; + + if (drawables_list) + drawables_list->previous = agd; + + drawables_list = agd; + + unlock_drawables_list(); +} + +/*WARNING: this returns a locked and referenced object. */ +bool +apple_glx_drawable_create(Display * dpy, + int screen, + GLXDrawable drawable, + struct apple_glx_drawable **agdResult, + struct apple_glx_drawable_callbacks *callbacks) +{ + struct apple_glx_drawable *d; + + d = calloc(1, sizeof *d); + + if (NULL == d) { + perror("malloc"); + return true; + } + + common_init(dpy, drawable, d); + d->type = callbacks->type; + d->callbacks = *callbacks; + + d->reference(d); + d->lock(d); + + link_tail(d); + + apple_glx_diagnostic("%s: new drawable %p\n", __func__, (void *) d); + + *agdResult = d; + + return false; +} + +static int error_count = 0; + +static int +error_handler(Display * dpy, XErrorEvent * err) +{ + if (err->error_code == BadWindow) { + ++error_count; + } + + return 0; +} + +void +apple_glx_garbage_collect_drawables(Display * dpy) +{ + struct apple_glx_drawable *d, *dnext; + Window root; + int x, y; + unsigned int width, height, bd, depth; + int (*old_handler) (Display *, XErrorEvent *); + + + if (NULL == drawables_list) + return; + + old_handler = XSetErrorHandler(error_handler); + + XSync(dpy, False); + + lock_drawables_list(); + + for (d = drawables_list; d;) { + dnext = d->next; + + d->lock(d); + + if (d->reference_count > 0) { + /* + * Skip this, because some context still retains a reference + * to the drawable. + */ + d->unlock(d); + d = dnext; + continue; + } + + d->unlock(d); + + error_count = 0; + + /* + * Mesa uses XGetWindowAttributes, but some of these things are + * most definitely not Windows, and that's against the rules. + * XGetGeometry on the other hand is legal with a Pixmap and Window. + */ + XGetGeometry(dpy, d->drawable, &root, &x, &y, &width, &height, &bd, + &depth); + + if (error_count > 0) { + /* + * Note: this may not actually destroy the drawable. + * If another context retains a reference to the drawable + * after the reference count test above. + */ + (void) destroy_drawable(d); + error_count = 0; + } + + d = dnext; + } + + XSetErrorHandler(old_handler); + + unlock_drawables_list(); +} + +unsigned int +apple_glx_get_drawable_count(void) +{ + unsigned int result = 0; + struct apple_glx_drawable *d; + + lock_drawables_list(); + + for (d = drawables_list; d; d = d->next) + ++result; + + unlock_drawables_list(); + + return result; +} + +struct apple_glx_drawable * +apple_glx_drawable_find_by_type(GLXDrawable drawable, int type, int flags) +{ + struct apple_glx_drawable *d; + + lock_drawables_list(); + + for (d = drawables_list; d; d = d->next) { + if (d->type == type && d->drawable == drawable) { + if (flags & APPLE_GLX_DRAWABLE_REFERENCE) + d->reference(d); + + if (flags & APPLE_GLX_DRAWABLE_LOCK) + d->lock(d); + + unlock_drawables_list(); + + return d; + } + } + + unlock_drawables_list(); + + return NULL; +} + +struct apple_glx_drawable * +apple_glx_drawable_find(GLXDrawable drawable, int flags) +{ + struct apple_glx_drawable *d; + + lock_drawables_list(); + + for (d = drawables_list; d; d = d->next) { + if (d->drawable == drawable) { + if (flags & APPLE_GLX_DRAWABLE_REFERENCE) + d->reference(d); + + if (flags & APPLE_GLX_DRAWABLE_LOCK) + d->lock(d); + + unlock_drawables_list(); + + return d; + } + } + + unlock_drawables_list(); + + return NULL; +} + +/* Return true if the type is valid for the drawable. */ +bool +apple_glx_drawable_destroy_by_type(Display * dpy, + GLXDrawable drawable, int type) +{ + struct apple_glx_drawable *d; + + lock_drawables_list(); + + for (d = drawables_list; d; d = d->next) { + if (drawable == d->drawable && type == d->type) { + /* + * The user has requested that we destroy this resource. + * However, there may be references in the contexts to it, so + * release it, and call destroy_drawable which doesn't destroy + * if the reference_count is > 0. + */ + d->release(d); + + apple_glx_diagnostic("%s d->reference_count %d\n", + __func__, d->reference_count); + + destroy_drawable(d); + unlock_drawables_list(); + return true; + } + } + + unlock_drawables_list(); + + return false; +} + +struct apple_glx_drawable * +apple_glx_drawable_find_by_uid(unsigned int uid, int flags) +{ + struct apple_glx_drawable *d; + + lock_drawables_list(); + + for (d = drawables_list; d; d = d->next) { + /* Only surfaces have a uid. */ + if (APPLE_GLX_DRAWABLE_SURFACE == d->type) { + if (d->types.surface.uid == uid) { + if (flags & APPLE_GLX_DRAWABLE_REFERENCE) + d->reference(d); + + if (flags & APPLE_GLX_DRAWABLE_LOCK) + d->lock(d); + + unlock_drawables_list(); + + return d; + } + } + } + + unlock_drawables_list(); + + return NULL; +} |