Path: blob/21.2-virgl/src/glx/apple/apple_glx_drawable.c
4560 views
/*1Copyright (c) 2008, 2009 Apple Inc.23Permission is hereby granted, free of charge, to any person4obtaining a copy of this software and associated documentation files5(the "Software"), to deal in the Software without restriction,6including without limitation the rights to use, copy, modify, merge,7publish, distribute, sublicense, and/or sell copies of the Software,8and to permit persons to whom the Software is furnished to do so,9subject to the following conditions:1011The above copyright notice and this permission notice shall be12included in all copies or substantial portions of the Software.1314THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,15EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND17NONINFRINGEMENT. IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT18HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,19WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,20OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER21DEALINGS IN THE SOFTWARE.2223Except as contained in this notice, the name(s) of the above24copyright holders shall not be used in advertising or otherwise to25promote the sale, use or other dealings in this Software without26prior written authorization.27*/2829#include <stdbool.h>30#include <stdio.h>31#include <stdlib.h>32#include <assert.h>33#include <pthread.h>34#include <string.h>35#include "apple_glx.h"36#include "apple_glx_context.h"37#include "apple_glx_drawable.h"38#include "appledri.h"3940static pthread_mutex_t drawables_lock = PTHREAD_MUTEX_INITIALIZER;41static struct apple_glx_drawable *drawables_list = NULL;4243static void44lock_drawables_list(void)45{46int err;4748err = pthread_mutex_lock(&drawables_lock);4950if (err) {51fprintf(stderr, "pthread_mutex_lock failure in %s: %s\n",52__func__, strerror(err));53abort();54}55}5657static void58unlock_drawables_list(void)59{60int err;6162err = pthread_mutex_unlock(&drawables_lock);6364if (err) {65fprintf(stderr, "pthread_mutex_unlock failure in %s: %s\n",66__func__, strerror(err));67abort();68}69}7071struct apple_glx_drawable *72apple_glx_find_drawable(Display * dpy, GLXDrawable drawable)73{74struct apple_glx_drawable *i, *agd = NULL;7576lock_drawables_list();7778for (i = drawables_list; i; i = i->next) {79if (i->drawable == drawable) {80agd = i;81break;82}83}8485unlock_drawables_list();8687return agd;88}8990static void91drawable_lock(struct apple_glx_drawable *agd)92{93int err;9495err = pthread_mutex_lock(&agd->mutex);9697if (err) {98fprintf(stderr, "pthread_mutex_lock error: %s\n", strerror(err));99abort();100}101}102103static void104drawable_unlock(struct apple_glx_drawable *d)105{106int err;107108err = pthread_mutex_unlock(&d->mutex);109110if (err) {111fprintf(stderr, "pthread_mutex_unlock error: %s\n", strerror(err));112abort();113}114}115116117static void118reference_drawable(struct apple_glx_drawable *d)119{120d->lock(d);121d->reference_count++;122d->unlock(d);123}124125static void126release_drawable(struct apple_glx_drawable *d)127{128d->lock(d);129d->reference_count--;130d->unlock(d);131}132133/* The drawables list must be locked prior to calling this. */134/* Return true if the drawable was destroyed. */135static bool136destroy_drawable(struct apple_glx_drawable *d)137{138int err;139140d->lock(d);141142if (d->reference_count > 0) {143d->unlock(d);144return false;145}146147d->unlock(d);148149if (d->previous) {150d->previous->next = d->next;151}152else {153/*154* The item must be at the head of the list, if it155* has no previous pointer.156*/157drawables_list = d->next;158}159160if (d->next)161d->next->previous = d->previous;162163unlock_drawables_list();164165if (d->callbacks.destroy) {166/*167* Warning: this causes other routines to be called (potentially)168* from surface_notify_handler. It's probably best to not have169* any locks at this point locked.170*/171d->callbacks.destroy(d->display, d);172}173174apple_glx_diagnostic("%s: freeing %p\n", __func__, (void *) d);175176/* Stupid recursive locks */177while (pthread_mutex_unlock(&d->mutex) == 0);178179err = pthread_mutex_destroy(&d->mutex);180if (err) {181fprintf(stderr, "pthread_mutex_destroy error: %s\n", strerror(err));182abort();183}184185free(d);186187/* So that the locks are balanced and the caller correctly unlocks. */188lock_drawables_list();189190return true;191}192193/*194* This is typically called when a context is destroyed or the current195* drawable is made None.196*/197static bool198destroy_drawable_callback(struct apple_glx_drawable *d)199{200bool result;201202d->lock(d);203204apple_glx_diagnostic("%s: %p ->reference_count before -- %d\n", __func__,205(void *) d, d->reference_count);206207d->reference_count--;208209if (d->reference_count > 0) {210d->unlock(d);211return false;212}213214d->unlock(d);215216lock_drawables_list();217218result = destroy_drawable(d);219220unlock_drawables_list();221222return result;223}224225static bool226is_pbuffer(struct apple_glx_drawable *d)227{228return APPLE_GLX_DRAWABLE_PBUFFER == d->type;229}230231static bool232is_pixmap(struct apple_glx_drawable *d)233{234return APPLE_GLX_DRAWABLE_PIXMAP == d->type;235}236237static void238common_init(Display * dpy, GLXDrawable drawable, struct apple_glx_drawable *d)239{240int err;241pthread_mutexattr_t attr;242243d->display = dpy;244d->reference_count = 0;245d->drawable = drawable;246d->type = -1;247248err = pthread_mutexattr_init(&attr);249250if (err) {251fprintf(stderr, "pthread_mutexattr_init error: %s\n", strerror(err));252abort();253}254255/*256* There are some patterns that require a recursive mutex,257* when working with locks that protect the apple_glx_drawable,258* and reference functions like ->reference, and ->release.259*/260err = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);261262if (err) {263fprintf(stderr, "error: setting pthread mutex type: %s\n", strerror(err));264abort();265}266267err = pthread_mutex_init(&d->mutex, &attr);268269if (err) {270fprintf(stderr, "pthread_mutex_init error: %s\n", strerror(err));271abort();272}273274(void) pthread_mutexattr_destroy(&attr);275276d->lock = drawable_lock;277d->unlock = drawable_unlock;278279d->reference = reference_drawable;280d->release = release_drawable;281282d->destroy = destroy_drawable_callback;283284d->is_pbuffer = is_pbuffer;285d->is_pixmap = is_pixmap;286287d->width = -1;288d->height = -1;289d->row_bytes = 0;290d->path[0] = '\0';291d->fd = -1;292d->buffer = NULL;293d->buffer_length = 0;294295d->previous = NULL;296d->next = NULL;297}298299static void300link_tail(struct apple_glx_drawable *agd)301{302lock_drawables_list();303304/* Link the new drawable into the global list. */305agd->next = drawables_list;306307if (drawables_list)308drawables_list->previous = agd;309310drawables_list = agd;311312unlock_drawables_list();313}314315/*WARNING: this returns a locked and referenced object. */316bool317apple_glx_drawable_create(Display * dpy,318int screen,319GLXDrawable drawable,320struct apple_glx_drawable **agdResult,321struct apple_glx_drawable_callbacks *callbacks)322{323struct apple_glx_drawable *d;324325d = calloc(1, sizeof *d);326327if (NULL == d) {328perror("malloc");329return true;330}331332common_init(dpy, drawable, d);333d->type = callbacks->type;334d->callbacks = *callbacks;335336d->reference(d);337d->lock(d);338339link_tail(d);340341apple_glx_diagnostic("%s: new drawable %p\n", __func__, (void *) d);342343*agdResult = d;344345return false;346}347348static int error_count = 0;349350static int351error_handler(Display * dpy, XErrorEvent * err)352{353if (err->error_code == BadWindow) {354++error_count;355}356357return 0;358}359360void361apple_glx_garbage_collect_drawables(Display * dpy)362{363struct apple_glx_drawable *d, *dnext;364Window root;365int x, y;366unsigned int width, height, bd, depth;367int (*old_handler) (Display *, XErrorEvent *);368369370if (NULL == drawables_list)371return;372373old_handler = XSetErrorHandler(error_handler);374375XSync(dpy, False);376377lock_drawables_list();378379for (d = drawables_list; d;) {380dnext = d->next;381382d->lock(d);383384if (d->reference_count > 0) {385/*386* Skip this, because some context still retains a reference387* to the drawable.388*/389d->unlock(d);390d = dnext;391continue;392}393394d->unlock(d);395396error_count = 0;397398/*399* Mesa uses XGetWindowAttributes, but some of these things are400* most definitely not Windows, and that's against the rules.401* XGetGeometry on the other hand is legal with a Pixmap and Window.402*/403XGetGeometry(dpy, d->drawable, &root, &x, &y, &width, &height, &bd,404&depth);405406if (error_count > 0) {407/*408* Note: this may not actually destroy the drawable.409* If another context retains a reference to the drawable410* after the reference count test above.411*/412(void) destroy_drawable(d);413error_count = 0;414}415416d = dnext;417}418419XSetErrorHandler(old_handler);420421unlock_drawables_list();422}423424unsigned int425apple_glx_get_drawable_count(void)426{427unsigned int result = 0;428struct apple_glx_drawable *d;429430lock_drawables_list();431432for (d = drawables_list; d; d = d->next)433++result;434435unlock_drawables_list();436437return result;438}439440struct apple_glx_drawable *441apple_glx_drawable_find_by_type(GLXDrawable drawable, int type, int flags)442{443struct apple_glx_drawable *d;444445lock_drawables_list();446447for (d = drawables_list; d; d = d->next) {448if (d->type == type && d->drawable == drawable) {449if (flags & APPLE_GLX_DRAWABLE_REFERENCE)450d->reference(d);451452if (flags & APPLE_GLX_DRAWABLE_LOCK)453d->lock(d);454455unlock_drawables_list();456457return d;458}459}460461unlock_drawables_list();462463return NULL;464}465466struct apple_glx_drawable *467apple_glx_drawable_find(GLXDrawable drawable, int flags)468{469struct apple_glx_drawable *d;470471lock_drawables_list();472473for (d = drawables_list; d; d = d->next) {474if (d->drawable == drawable) {475if (flags & APPLE_GLX_DRAWABLE_REFERENCE)476d->reference(d);477478if (flags & APPLE_GLX_DRAWABLE_LOCK)479d->lock(d);480481unlock_drawables_list();482483return d;484}485}486487unlock_drawables_list();488489return NULL;490}491492/* Return true if the type is valid for the drawable. */493bool494apple_glx_drawable_destroy_by_type(Display * dpy,495GLXDrawable drawable, int type)496{497struct apple_glx_drawable *d;498499lock_drawables_list();500501for (d = drawables_list; d; d = d->next) {502if (drawable == d->drawable && type == d->type) {503/*504* The user has requested that we destroy this resource.505* However, there may be references in the contexts to it, so506* release it, and call destroy_drawable which doesn't destroy507* if the reference_count is > 0.508*/509d->release(d);510511apple_glx_diagnostic("%s d->reference_count %d\n",512__func__, d->reference_count);513514destroy_drawable(d);515unlock_drawables_list();516return true;517}518}519520unlock_drawables_list();521522return false;523}524525struct apple_glx_drawable *526apple_glx_drawable_find_by_uid(unsigned int uid, int flags)527{528struct apple_glx_drawable *d;529530lock_drawables_list();531532for (d = drawables_list; d; d = d->next) {533/* Only surfaces have a uid. */534if (APPLE_GLX_DRAWABLE_SURFACE == d->type) {535if (d->types.surface.uid == uid) {536if (flags & APPLE_GLX_DRAWABLE_REFERENCE)537d->reference(d);538539if (flags & APPLE_GLX_DRAWABLE_LOCK)540d->lock(d);541542unlock_drawables_list();543544return d;545}546}547}548549unlock_drawables_list();550551return NULL;552}553554555