1848b8605Smrg/* 2848b8605Smrg Copyright (c) 2008, 2009 Apple Inc. 3848b8605Smrg 4848b8605Smrg Permission is hereby granted, free of charge, to any person 5848b8605Smrg obtaining a copy of this software and associated documentation files 6848b8605Smrg (the "Software"), to deal in the Software without restriction, 7848b8605Smrg including without limitation the rights to use, copy, modify, merge, 8848b8605Smrg publish, distribute, sublicense, and/or sell copies of the Software, 9848b8605Smrg and to permit persons to whom the Software is furnished to do so, 10848b8605Smrg subject to the following conditions: 11848b8605Smrg 12848b8605Smrg The above copyright notice and this permission notice shall be 13848b8605Smrg included in all copies or substantial portions of the Software. 14848b8605Smrg 15848b8605Smrg THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16848b8605Smrg EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17848b8605Smrg MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18848b8605Smrg NONINFRINGEMENT. IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT 19848b8605Smrg HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20848b8605Smrg WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21848b8605Smrg OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22848b8605Smrg DEALINGS IN THE SOFTWARE. 23848b8605Smrg 24848b8605Smrg Except as contained in this notice, the name(s) of the above 25848b8605Smrg copyright holders shall not be used in advertising or otherwise to 26848b8605Smrg promote the sale, use or other dealings in this Software without 27848b8605Smrg prior written authorization. 28848b8605Smrg*/ 29848b8605Smrg 30848b8605Smrg#include <stdbool.h> 31848b8605Smrg#include <stdio.h> 32848b8605Smrg#include <stdlib.h> 33848b8605Smrg#include <assert.h> 34848b8605Smrg#include <pthread.h> 35848b8605Smrg#include <string.h> 36848b8605Smrg#include "apple_glx.h" 37848b8605Smrg#include "apple_glx_context.h" 38848b8605Smrg#include "apple_glx_drawable.h" 39848b8605Smrg#include "appledri.h" 40848b8605Smrg 41848b8605Smrgstatic pthread_mutex_t drawables_lock = PTHREAD_MUTEX_INITIALIZER; 42848b8605Smrgstatic struct apple_glx_drawable *drawables_list = NULL; 43848b8605Smrg 44848b8605Smrgstatic void 45848b8605Smrglock_drawables_list(void) 46848b8605Smrg{ 47848b8605Smrg int err; 48848b8605Smrg 49848b8605Smrg err = pthread_mutex_lock(&drawables_lock); 50848b8605Smrg 51848b8605Smrg if (err) { 52848b8605Smrg fprintf(stderr, "pthread_mutex_lock failure in %s: %s\n", 53848b8605Smrg __func__, strerror(err)); 54848b8605Smrg abort(); 55848b8605Smrg } 56848b8605Smrg} 57848b8605Smrg 58848b8605Smrgstatic void 59848b8605Smrgunlock_drawables_list(void) 60848b8605Smrg{ 61848b8605Smrg int err; 62848b8605Smrg 63848b8605Smrg err = pthread_mutex_unlock(&drawables_lock); 64848b8605Smrg 65848b8605Smrg if (err) { 66848b8605Smrg fprintf(stderr, "pthread_mutex_unlock failure in %s: %s\n", 67848b8605Smrg __func__, strerror(err)); 68848b8605Smrg abort(); 69848b8605Smrg } 70848b8605Smrg} 71848b8605Smrg 72848b8605Smrgstruct apple_glx_drawable * 73848b8605Smrgapple_glx_find_drawable(Display * dpy, GLXDrawable drawable) 74848b8605Smrg{ 75848b8605Smrg struct apple_glx_drawable *i, *agd = NULL; 76848b8605Smrg 77848b8605Smrg lock_drawables_list(); 78848b8605Smrg 79848b8605Smrg for (i = drawables_list; i; i = i->next) { 80848b8605Smrg if (i->drawable == drawable) { 81848b8605Smrg agd = i; 82848b8605Smrg break; 83848b8605Smrg } 84848b8605Smrg } 85848b8605Smrg 86848b8605Smrg unlock_drawables_list(); 87848b8605Smrg 88848b8605Smrg return agd; 89848b8605Smrg} 90848b8605Smrg 91848b8605Smrgstatic void 92848b8605Smrgdrawable_lock(struct apple_glx_drawable *agd) 93848b8605Smrg{ 94848b8605Smrg int err; 95848b8605Smrg 96848b8605Smrg err = pthread_mutex_lock(&agd->mutex); 97848b8605Smrg 98848b8605Smrg if (err) { 99848b8605Smrg fprintf(stderr, "pthread_mutex_lock error: %s\n", strerror(err)); 100848b8605Smrg abort(); 101848b8605Smrg } 102848b8605Smrg} 103848b8605Smrg 104848b8605Smrgstatic void 105848b8605Smrgdrawable_unlock(struct apple_glx_drawable *d) 106848b8605Smrg{ 107848b8605Smrg int err; 108848b8605Smrg 109848b8605Smrg err = pthread_mutex_unlock(&d->mutex); 110848b8605Smrg 111848b8605Smrg if (err) { 112848b8605Smrg fprintf(stderr, "pthread_mutex_unlock error: %s\n", strerror(err)); 113848b8605Smrg abort(); 114848b8605Smrg } 115848b8605Smrg} 116848b8605Smrg 117848b8605Smrg 118848b8605Smrgstatic void 119848b8605Smrgreference_drawable(struct apple_glx_drawable *d) 120848b8605Smrg{ 121848b8605Smrg d->lock(d); 122848b8605Smrg d->reference_count++; 123848b8605Smrg d->unlock(d); 124848b8605Smrg} 125848b8605Smrg 126848b8605Smrgstatic void 127848b8605Smrgrelease_drawable(struct apple_glx_drawable *d) 128848b8605Smrg{ 129848b8605Smrg d->lock(d); 130848b8605Smrg d->reference_count--; 131848b8605Smrg d->unlock(d); 132848b8605Smrg} 133848b8605Smrg 134848b8605Smrg/* The drawables list must be locked prior to calling this. */ 135848b8605Smrg/* Return true if the drawable was destroyed. */ 136848b8605Smrgstatic bool 137848b8605Smrgdestroy_drawable(struct apple_glx_drawable *d) 138848b8605Smrg{ 139848b8605Smrg int err; 140848b8605Smrg 141848b8605Smrg d->lock(d); 142848b8605Smrg 143848b8605Smrg if (d->reference_count > 0) { 144848b8605Smrg d->unlock(d); 145848b8605Smrg return false; 146848b8605Smrg } 147848b8605Smrg 148848b8605Smrg d->unlock(d); 149848b8605Smrg 150848b8605Smrg if (d->previous) { 151848b8605Smrg d->previous->next = d->next; 152848b8605Smrg } 153848b8605Smrg else { 154848b8605Smrg /* 155848b8605Smrg * The item must be at the head of the list, if it 156848b8605Smrg * has no previous pointer. 157848b8605Smrg */ 158848b8605Smrg drawables_list = d->next; 159848b8605Smrg } 160848b8605Smrg 161848b8605Smrg if (d->next) 162848b8605Smrg d->next->previous = d->previous; 163848b8605Smrg 164848b8605Smrg unlock_drawables_list(); 165848b8605Smrg 166848b8605Smrg if (d->callbacks.destroy) { 167848b8605Smrg /* 168848b8605Smrg * Warning: this causes other routines to be called (potentially) 169848b8605Smrg * from surface_notify_handler. It's probably best to not have 170848b8605Smrg * any locks at this point locked. 171848b8605Smrg */ 172848b8605Smrg d->callbacks.destroy(d->display, d); 173848b8605Smrg } 174848b8605Smrg 175848b8605Smrg apple_glx_diagnostic("%s: freeing %p\n", __func__, (void *) d); 176848b8605Smrg 177848b8605Smrg /* Stupid recursive locks */ 178848b8605Smrg while (pthread_mutex_unlock(&d->mutex) == 0); 179848b8605Smrg 180848b8605Smrg err = pthread_mutex_destroy(&d->mutex); 181848b8605Smrg if (err) { 182848b8605Smrg fprintf(stderr, "pthread_mutex_destroy error: %s\n", strerror(err)); 183848b8605Smrg abort(); 184848b8605Smrg } 185848b8605Smrg 186848b8605Smrg free(d); 187848b8605Smrg 188848b8605Smrg /* So that the locks are balanced and the caller correctly unlocks. */ 189848b8605Smrg lock_drawables_list(); 190848b8605Smrg 191848b8605Smrg return true; 192848b8605Smrg} 193848b8605Smrg 194848b8605Smrg/* 195848b8605Smrg * This is typically called when a context is destroyed or the current 196848b8605Smrg * drawable is made None. 197848b8605Smrg */ 198848b8605Smrgstatic bool 199848b8605Smrgdestroy_drawable_callback(struct apple_glx_drawable *d) 200848b8605Smrg{ 201848b8605Smrg bool result; 202848b8605Smrg 203848b8605Smrg d->lock(d); 204848b8605Smrg 205848b8605Smrg apple_glx_diagnostic("%s: %p ->reference_count before -- %d\n", __func__, 206848b8605Smrg (void *) d, d->reference_count); 207848b8605Smrg 208848b8605Smrg d->reference_count--; 209848b8605Smrg 210848b8605Smrg if (d->reference_count > 0) { 211848b8605Smrg d->unlock(d); 212848b8605Smrg return false; 213848b8605Smrg } 214848b8605Smrg 215848b8605Smrg d->unlock(d); 216848b8605Smrg 217848b8605Smrg lock_drawables_list(); 218848b8605Smrg 219848b8605Smrg result = destroy_drawable(d); 220848b8605Smrg 221848b8605Smrg unlock_drawables_list(); 222848b8605Smrg 223848b8605Smrg return result; 224848b8605Smrg} 225848b8605Smrg 226848b8605Smrgstatic bool 227848b8605Smrgis_pbuffer(struct apple_glx_drawable *d) 228848b8605Smrg{ 229848b8605Smrg return APPLE_GLX_DRAWABLE_PBUFFER == d->type; 230848b8605Smrg} 231848b8605Smrg 232848b8605Smrgstatic bool 233848b8605Smrgis_pixmap(struct apple_glx_drawable *d) 234848b8605Smrg{ 235848b8605Smrg return APPLE_GLX_DRAWABLE_PIXMAP == d->type; 236848b8605Smrg} 237848b8605Smrg 238848b8605Smrgstatic void 239848b8605Smrgcommon_init(Display * dpy, GLXDrawable drawable, struct apple_glx_drawable *d) 240848b8605Smrg{ 241848b8605Smrg int err; 242848b8605Smrg pthread_mutexattr_t attr; 243848b8605Smrg 244848b8605Smrg d->display = dpy; 245848b8605Smrg d->reference_count = 0; 246848b8605Smrg d->drawable = drawable; 247848b8605Smrg d->type = -1; 248848b8605Smrg 249848b8605Smrg err = pthread_mutexattr_init(&attr); 250848b8605Smrg 251848b8605Smrg if (err) { 252848b8605Smrg fprintf(stderr, "pthread_mutexattr_init error: %s\n", strerror(err)); 253848b8605Smrg abort(); 254848b8605Smrg } 255848b8605Smrg 256848b8605Smrg /* 257848b8605Smrg * There are some patterns that require a recursive mutex, 258848b8605Smrg * when working with locks that protect the apple_glx_drawable, 259848b8605Smrg * and reference functions like ->reference, and ->release. 260848b8605Smrg */ 261848b8605Smrg err = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); 262848b8605Smrg 263848b8605Smrg if (err) { 264848b8605Smrg fprintf(stderr, "error: setting pthread mutex type: %s\n", strerror(err)); 265848b8605Smrg abort(); 266848b8605Smrg } 267848b8605Smrg 268848b8605Smrg err = pthread_mutex_init(&d->mutex, &attr); 269848b8605Smrg 270848b8605Smrg if (err) { 271848b8605Smrg fprintf(stderr, "pthread_mutex_init error: %s\n", strerror(err)); 272848b8605Smrg abort(); 273848b8605Smrg } 274848b8605Smrg 275848b8605Smrg (void) pthread_mutexattr_destroy(&attr); 276848b8605Smrg 277848b8605Smrg d->lock = drawable_lock; 278848b8605Smrg d->unlock = drawable_unlock; 279848b8605Smrg 280848b8605Smrg d->reference = reference_drawable; 281848b8605Smrg d->release = release_drawable; 282848b8605Smrg 283848b8605Smrg d->destroy = destroy_drawable_callback; 284848b8605Smrg 285848b8605Smrg d->is_pbuffer = is_pbuffer; 286848b8605Smrg d->is_pixmap = is_pixmap; 287848b8605Smrg 288848b8605Smrg d->width = -1; 289848b8605Smrg d->height = -1; 290848b8605Smrg d->row_bytes = 0; 291848b8605Smrg d->path[0] = '\0'; 292848b8605Smrg d->fd = -1; 293848b8605Smrg d->buffer = NULL; 294848b8605Smrg d->buffer_length = 0; 295848b8605Smrg 296848b8605Smrg d->previous = NULL; 297848b8605Smrg d->next = NULL; 298848b8605Smrg} 299848b8605Smrg 300848b8605Smrgstatic void 301848b8605Smrglink_tail(struct apple_glx_drawable *agd) 302848b8605Smrg{ 303848b8605Smrg lock_drawables_list(); 304848b8605Smrg 305848b8605Smrg /* Link the new drawable into the global list. */ 306848b8605Smrg agd->next = drawables_list; 307848b8605Smrg 308848b8605Smrg if (drawables_list) 309848b8605Smrg drawables_list->previous = agd; 310848b8605Smrg 311848b8605Smrg drawables_list = agd; 312848b8605Smrg 313848b8605Smrg unlock_drawables_list(); 314848b8605Smrg} 315848b8605Smrg 316848b8605Smrg/*WARNING: this returns a locked and referenced object. */ 317848b8605Smrgbool 318848b8605Smrgapple_glx_drawable_create(Display * dpy, 319848b8605Smrg int screen, 320848b8605Smrg GLXDrawable drawable, 321848b8605Smrg struct apple_glx_drawable **agdResult, 322848b8605Smrg struct apple_glx_drawable_callbacks *callbacks) 323848b8605Smrg{ 324848b8605Smrg struct apple_glx_drawable *d; 325848b8605Smrg 326848b8605Smrg d = calloc(1, sizeof *d); 327848b8605Smrg 328848b8605Smrg if (NULL == d) { 329848b8605Smrg perror("malloc"); 330848b8605Smrg return true; 331848b8605Smrg } 332848b8605Smrg 333848b8605Smrg common_init(dpy, drawable, d); 334848b8605Smrg d->type = callbacks->type; 335848b8605Smrg d->callbacks = *callbacks; 336848b8605Smrg 337848b8605Smrg d->reference(d); 338848b8605Smrg d->lock(d); 339848b8605Smrg 340848b8605Smrg link_tail(d); 341848b8605Smrg 342848b8605Smrg apple_glx_diagnostic("%s: new drawable %p\n", __func__, (void *) d); 343848b8605Smrg 344848b8605Smrg *agdResult = d; 345848b8605Smrg 346848b8605Smrg return false; 347848b8605Smrg} 348848b8605Smrg 349848b8605Smrgstatic int error_count = 0; 350848b8605Smrg 351848b8605Smrgstatic int 352848b8605Smrgerror_handler(Display * dpy, XErrorEvent * err) 353848b8605Smrg{ 354848b8605Smrg if (err->error_code == BadWindow) { 355848b8605Smrg ++error_count; 356848b8605Smrg } 357848b8605Smrg 358848b8605Smrg return 0; 359848b8605Smrg} 360848b8605Smrg 361848b8605Smrgvoid 362848b8605Smrgapple_glx_garbage_collect_drawables(Display * dpy) 363848b8605Smrg{ 364848b8605Smrg struct apple_glx_drawable *d, *dnext; 365848b8605Smrg Window root; 366848b8605Smrg int x, y; 367848b8605Smrg unsigned int width, height, bd, depth; 368848b8605Smrg int (*old_handler) (Display *, XErrorEvent *); 369848b8605Smrg 370848b8605Smrg 371848b8605Smrg if (NULL == drawables_list) 372848b8605Smrg return; 373848b8605Smrg 374848b8605Smrg old_handler = XSetErrorHandler(error_handler); 375848b8605Smrg 376848b8605Smrg XSync(dpy, False); 377848b8605Smrg 378848b8605Smrg lock_drawables_list(); 379848b8605Smrg 380848b8605Smrg for (d = drawables_list; d;) { 381848b8605Smrg dnext = d->next; 382848b8605Smrg 383848b8605Smrg d->lock(d); 384848b8605Smrg 385848b8605Smrg if (d->reference_count > 0) { 386848b8605Smrg /* 387848b8605Smrg * Skip this, because some context still retains a reference 388848b8605Smrg * to the drawable. 389848b8605Smrg */ 390848b8605Smrg d->unlock(d); 391848b8605Smrg d = dnext; 392848b8605Smrg continue; 393848b8605Smrg } 394848b8605Smrg 395848b8605Smrg d->unlock(d); 396848b8605Smrg 397848b8605Smrg error_count = 0; 398848b8605Smrg 399848b8605Smrg /* 400848b8605Smrg * Mesa uses XGetWindowAttributes, but some of these things are 401848b8605Smrg * most definitely not Windows, and that's against the rules. 402848b8605Smrg * XGetGeometry on the other hand is legal with a Pixmap and Window. 403848b8605Smrg */ 404848b8605Smrg XGetGeometry(dpy, d->drawable, &root, &x, &y, &width, &height, &bd, 405848b8605Smrg &depth); 406848b8605Smrg 407848b8605Smrg if (error_count > 0) { 408848b8605Smrg /* 409848b8605Smrg * Note: this may not actually destroy the drawable. 410848b8605Smrg * If another context retains a reference to the drawable 411848b8605Smrg * after the reference count test above. 412848b8605Smrg */ 413848b8605Smrg (void) destroy_drawable(d); 414848b8605Smrg error_count = 0; 415848b8605Smrg } 416848b8605Smrg 417848b8605Smrg d = dnext; 418848b8605Smrg } 419848b8605Smrg 420848b8605Smrg XSetErrorHandler(old_handler); 421848b8605Smrg 422848b8605Smrg unlock_drawables_list(); 423848b8605Smrg} 424848b8605Smrg 425848b8605Smrgunsigned int 426848b8605Smrgapple_glx_get_drawable_count(void) 427848b8605Smrg{ 428848b8605Smrg unsigned int result = 0; 429848b8605Smrg struct apple_glx_drawable *d; 430848b8605Smrg 431848b8605Smrg lock_drawables_list(); 432848b8605Smrg 433848b8605Smrg for (d = drawables_list; d; d = d->next) 434848b8605Smrg ++result; 435848b8605Smrg 436848b8605Smrg unlock_drawables_list(); 437848b8605Smrg 438848b8605Smrg return result; 439848b8605Smrg} 440848b8605Smrg 441848b8605Smrgstruct apple_glx_drawable * 442848b8605Smrgapple_glx_drawable_find_by_type(GLXDrawable drawable, int type, int flags) 443848b8605Smrg{ 444848b8605Smrg struct apple_glx_drawable *d; 445848b8605Smrg 446848b8605Smrg lock_drawables_list(); 447848b8605Smrg 448848b8605Smrg for (d = drawables_list; d; d = d->next) { 449848b8605Smrg if (d->type == type && d->drawable == drawable) { 450848b8605Smrg if (flags & APPLE_GLX_DRAWABLE_REFERENCE) 451848b8605Smrg d->reference(d); 452848b8605Smrg 453848b8605Smrg if (flags & APPLE_GLX_DRAWABLE_LOCK) 454848b8605Smrg d->lock(d); 455848b8605Smrg 456848b8605Smrg unlock_drawables_list(); 457848b8605Smrg 458848b8605Smrg return d; 459848b8605Smrg } 460848b8605Smrg } 461848b8605Smrg 462848b8605Smrg unlock_drawables_list(); 463848b8605Smrg 464848b8605Smrg return NULL; 465848b8605Smrg} 466848b8605Smrg 467848b8605Smrgstruct apple_glx_drawable * 468848b8605Smrgapple_glx_drawable_find(GLXDrawable drawable, int flags) 469848b8605Smrg{ 470848b8605Smrg struct apple_glx_drawable *d; 471848b8605Smrg 472848b8605Smrg lock_drawables_list(); 473848b8605Smrg 474848b8605Smrg for (d = drawables_list; d; d = d->next) { 475848b8605Smrg if (d->drawable == drawable) { 476848b8605Smrg if (flags & APPLE_GLX_DRAWABLE_REFERENCE) 477848b8605Smrg d->reference(d); 478848b8605Smrg 479848b8605Smrg if (flags & APPLE_GLX_DRAWABLE_LOCK) 480848b8605Smrg d->lock(d); 481848b8605Smrg 482848b8605Smrg unlock_drawables_list(); 483848b8605Smrg 484848b8605Smrg return d; 485848b8605Smrg } 486848b8605Smrg } 487848b8605Smrg 488848b8605Smrg unlock_drawables_list(); 489848b8605Smrg 490848b8605Smrg return NULL; 491848b8605Smrg} 492848b8605Smrg 493848b8605Smrg/* Return true if the type is valid for the drawable. */ 494848b8605Smrgbool 495848b8605Smrgapple_glx_drawable_destroy_by_type(Display * dpy, 496848b8605Smrg GLXDrawable drawable, int type) 497848b8605Smrg{ 498848b8605Smrg struct apple_glx_drawable *d; 499848b8605Smrg 500848b8605Smrg lock_drawables_list(); 501848b8605Smrg 502848b8605Smrg for (d = drawables_list; d; d = d->next) { 503848b8605Smrg if (drawable == d->drawable && type == d->type) { 504848b8605Smrg /* 505848b8605Smrg * The user has requested that we destroy this resource. 506848b8605Smrg * However, there may be references in the contexts to it, so 507848b8605Smrg * release it, and call destroy_drawable which doesn't destroy 508848b8605Smrg * if the reference_count is > 0. 509848b8605Smrg */ 510848b8605Smrg d->release(d); 511848b8605Smrg 512848b8605Smrg apple_glx_diagnostic("%s d->reference_count %d\n", 513848b8605Smrg __func__, d->reference_count); 514848b8605Smrg 515848b8605Smrg destroy_drawable(d); 516848b8605Smrg unlock_drawables_list(); 517848b8605Smrg return true; 518848b8605Smrg } 519848b8605Smrg } 520848b8605Smrg 521848b8605Smrg unlock_drawables_list(); 522848b8605Smrg 523848b8605Smrg return false; 524848b8605Smrg} 525848b8605Smrg 526848b8605Smrgstruct apple_glx_drawable * 527848b8605Smrgapple_glx_drawable_find_by_uid(unsigned int uid, int flags) 528848b8605Smrg{ 529848b8605Smrg struct apple_glx_drawable *d; 530848b8605Smrg 531848b8605Smrg lock_drawables_list(); 532848b8605Smrg 533848b8605Smrg for (d = drawables_list; d; d = d->next) { 534848b8605Smrg /* Only surfaces have a uid. */ 535848b8605Smrg if (APPLE_GLX_DRAWABLE_SURFACE == d->type) { 536848b8605Smrg if (d->types.surface.uid == uid) { 537848b8605Smrg if (flags & APPLE_GLX_DRAWABLE_REFERENCE) 538848b8605Smrg d->reference(d); 539848b8605Smrg 540848b8605Smrg if (flags & APPLE_GLX_DRAWABLE_LOCK) 541848b8605Smrg d->lock(d); 542848b8605Smrg 543848b8605Smrg unlock_drawables_list(); 544848b8605Smrg 545848b8605Smrg return d; 546848b8605Smrg } 547848b8605Smrg } 548848b8605Smrg } 549848b8605Smrg 550848b8605Smrg unlock_drawables_list(); 551848b8605Smrg 552848b8605Smrg return NULL; 553848b8605Smrg} 554