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;
}