summaryrefslogtreecommitdiffstats
path: root/src/glx/apple/apple_glx_drawable.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/glx/apple/apple_glx_drawable.c')
-rw-r--r--src/glx/apple/apple_glx_drawable.c542
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;
+}