apple_glx_drawable.c [plain text]
#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);
}
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 {
drawables_list = d->next;
}
if(d->next)
d->next->previous = d->previous;
unlock_drawables_list();
if (d->callbacks.destroy) {
d->callbacks.destroy(d->display, d);
}
apple_glx_diagnostic("%s: freeing %p\n", __func__, (void *)d);
free(d);
lock_drawables_list();
return true;
}
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();
}
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();
agd->next = drawables_list;
if(drawables_list)
drawables_list->previous = agd;
drawables_list = agd;
unlock_drawables_list();
}
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) {
d->unlock(d);
d = dnext;
continue;
}
d->unlock(d);
error_count = 0;
XGetGeometry(dpy, d->drawable, &root, &x, &y, &width, &height, &bd,
&depth);
if(error_count > 0) {
(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;
}
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) {
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) {
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;
}