Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5563 serge 1
/*
2
 Copyright (c) 2008, 2009 Apple Inc.
3
 
4
 Permission is hereby granted, free of charge, to any person
5
 obtaining a copy of this software and associated documentation files
6
 (the "Software"), to deal in the Software without restriction,
7
 including without limitation the rights to use, copy, modify, merge,
8
 publish, distribute, sublicense, and/or sell copies of the Software,
9
 and to permit persons to whom the Software is furnished to do so,
10
 subject to the following conditions:
11
 
12
 The above copyright notice and this permission notice shall be
13
 included in all copies or substantial portions of the Software.
14
 
15
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
 NONINFRINGEMENT.  IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT
19
 HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22
 DEALINGS IN THE SOFTWARE.
23
 
24
 Except as contained in this notice, the name(s) of the above
25
 copyright holders shall not be used in advertising or otherwise to
26
 promote the sale, use or other dealings in this Software without
27
 prior written authorization.
28
*/
29
 
30
#include 
31
#include 
32
#include 
33
#include 
34
#include 
35
#include 
36
#include "apple_glx.h"
37
#include "apple_glx_context.h"
38
#include "apple_glx_drawable.h"
39
#include "appledri.h"
40
 
41
static pthread_mutex_t drawables_lock = PTHREAD_MUTEX_INITIALIZER;
42
static struct apple_glx_drawable *drawables_list = NULL;
43
 
44
static void
45
lock_drawables_list(void)
46
{
47
   int err;
48
 
49
   err = pthread_mutex_lock(&drawables_lock);
50
 
51
   if (err) {
52
      fprintf(stderr, "pthread_mutex_lock failure in %s: %s\n",
53
              __func__, strerror(err));
54
      abort();
55
   }
56
}
57
 
58
static void
59
unlock_drawables_list(void)
60
{
61
   int err;
62
 
63
   err = pthread_mutex_unlock(&drawables_lock);
64
 
65
   if (err) {
66
      fprintf(stderr, "pthread_mutex_unlock failure in %s: %s\n",
67
              __func__, strerror(err));
68
      abort();
69
   }
70
}
71
 
72
struct apple_glx_drawable *
73
apple_glx_find_drawable(Display * dpy, GLXDrawable drawable)
74
{
75
   struct apple_glx_drawable *i, *agd = NULL;
76
 
77
   lock_drawables_list();
78
 
79
   for (i = drawables_list; i; i = i->next) {
80
      if (i->drawable == drawable) {
81
         agd = i;
82
         break;
83
      }
84
   }
85
 
86
   unlock_drawables_list();
87
 
88
   return agd;
89
}
90
 
91
static void
92
drawable_lock(struct apple_glx_drawable *agd)
93
{
94
   int err;
95
 
96
   err = pthread_mutex_lock(&agd->mutex);
97
 
98
   if (err) {
99
      fprintf(stderr, "pthread_mutex_lock error: %s\n", strerror(err));
100
      abort();
101
   }
102
}
103
 
104
static void
105
drawable_unlock(struct apple_glx_drawable *d)
106
{
107
   int err;
108
 
109
   err = pthread_mutex_unlock(&d->mutex);
110
 
111
   if (err) {
112
      fprintf(stderr, "pthread_mutex_unlock error: %s\n", strerror(err));
113
      abort();
114
   }
115
}
116
 
117
 
118
static void
119
reference_drawable(struct apple_glx_drawable *d)
120
{
121
   d->lock(d);
122
   d->reference_count++;
123
   d->unlock(d);
124
}
125
 
126
static void
127
release_drawable(struct apple_glx_drawable *d)
128
{
129
   d->lock(d);
130
   d->reference_count--;
131
   d->unlock(d);
132
}
133
 
134
/* The drawables list must be locked prior to calling this. */
135
/* Return true if the drawable was destroyed. */
136
static bool
137
destroy_drawable(struct apple_glx_drawable *d)
138
{
139
   int err;
140
 
141
   d->lock(d);
142
 
143
   if (d->reference_count > 0) {
144
      d->unlock(d);
145
      return false;
146
   }
147
 
148
   d->unlock(d);
149
 
150
   if (d->previous) {
151
      d->previous->next = d->next;
152
   }
153
   else {
154
      /*
155
       * The item must be at the head of the list, if it
156
       * has no previous pointer.
157
       */
158
      drawables_list = d->next;
159
   }
160
 
161
   if (d->next)
162
      d->next->previous = d->previous;
163
 
164
   unlock_drawables_list();
165
 
166
   if (d->callbacks.destroy) {
167
      /*
168
       * Warning: this causes other routines to be called (potentially)
169
       * from surface_notify_handler.  It's probably best to not have
170
       * any locks at this point locked.
171
       */
172
      d->callbacks.destroy(d->display, d);
173
   }
174
 
175
   apple_glx_diagnostic("%s: freeing %p\n", __func__, (void *) d);
176
 
177
   /* Stupid recursive locks */
178
   while (pthread_mutex_unlock(&d->mutex) == 0);
179
 
180
   err = pthread_mutex_destroy(&d->mutex);
181
   if (err) {
182
      fprintf(stderr, "pthread_mutex_destroy error: %s\n", strerror(err));
183
      abort();
184
   }
185
 
186
   free(d);
187
 
188
   /* So that the locks are balanced and the caller correctly unlocks. */
189
   lock_drawables_list();
190
 
191
   return true;
192
}
193
 
194
/*
195
 * This is typically called when a context is destroyed or the current
196
 * drawable is made None.
197
 */
198
static bool
199
destroy_drawable_callback(struct apple_glx_drawable *d)
200
{
201
   bool result;
202
 
203
   d->lock(d);
204
 
205
   apple_glx_diagnostic("%s: %p ->reference_count before -- %d\n", __func__,
206
                        (void *) d, d->reference_count);
207
 
208
   d->reference_count--;
209
 
210
   if (d->reference_count > 0) {
211
      d->unlock(d);
212
      return false;
213
   }
214
 
215
   d->unlock(d);
216
 
217
   lock_drawables_list();
218
 
219
   result = destroy_drawable(d);
220
 
221
   unlock_drawables_list();
222
 
223
   return result;
224
}
225
 
226
static bool
227
is_pbuffer(struct apple_glx_drawable *d)
228
{
229
   return APPLE_GLX_DRAWABLE_PBUFFER == d->type;
230
}
231
 
232
static bool
233
is_pixmap(struct apple_glx_drawable *d)
234
{
235
   return APPLE_GLX_DRAWABLE_PIXMAP == d->type;
236
}
237
 
238
static void
239
common_init(Display * dpy, GLXDrawable drawable, struct apple_glx_drawable *d)
240
{
241
   int err;
242
   pthread_mutexattr_t attr;
243
 
244
   d->display = dpy;
245
   d->reference_count = 0;
246
   d->drawable = drawable;
247
   d->type = -1;
248
 
249
   err = pthread_mutexattr_init(&attr);
250
 
251
   if (err) {
252
      fprintf(stderr, "pthread_mutexattr_init error: %s\n", strerror(err));
253
      abort();
254
   }
255
 
256
   /*
257
    * There are some patterns that require a recursive mutex,
258
    * when working with locks that protect the apple_glx_drawable,
259
    * and reference functions like ->reference, and ->release.
260
    */
261
   err = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
262
 
263
   if (err) {
264
      fprintf(stderr, "error: setting pthread mutex type: %s\n", strerror(err));
265
      abort();
266
   }
267
 
268
   err = pthread_mutex_init(&d->mutex, &attr);
269
 
270
   if (err) {
271
      fprintf(stderr, "pthread_mutex_init error: %s\n", strerror(err));
272
      abort();
273
   }
274
 
275
   (void) pthread_mutexattr_destroy(&attr);
276
 
277
   d->lock = drawable_lock;
278
   d->unlock = drawable_unlock;
279
 
280
   d->reference = reference_drawable;
281
   d->release = release_drawable;
282
 
283
   d->destroy = destroy_drawable_callback;
284
 
285
   d->is_pbuffer = is_pbuffer;
286
   d->is_pixmap = is_pixmap;
287
 
288
   d->width = -1;
289
   d->height = -1;
290
   d->row_bytes = 0;
291
   d->path[0] = '\0';
292
   d->fd = -1;
293
   d->buffer = NULL;
294
   d->buffer_length = 0;
295
 
296
   d->previous = NULL;
297
   d->next = NULL;
298
}
299
 
300
static void
301
link_tail(struct apple_glx_drawable *agd)
302
{
303
   lock_drawables_list();
304
 
305
   /* Link the new drawable into the global list. */
306
   agd->next = drawables_list;
307
 
308
   if (drawables_list)
309
      drawables_list->previous = agd;
310
 
311
   drawables_list = agd;
312
 
313
   unlock_drawables_list();
314
}
315
 
316
/*WARNING: this returns a locked and referenced object. */
317
bool
318
apple_glx_drawable_create(Display * dpy,
319
                          int screen,
320
                          GLXDrawable drawable,
321
                          struct apple_glx_drawable **agdResult,
322
                          struct apple_glx_drawable_callbacks *callbacks)
323
{
324
   struct apple_glx_drawable *d;
325
 
326
   d = calloc(1, sizeof *d);
327
 
328
   if (NULL == d) {
329
      perror("malloc");
330
      return true;
331
   }
332
 
333
   common_init(dpy, drawable, d);
334
   d->type = callbacks->type;
335
   d->callbacks = *callbacks;
336
 
337
   d->reference(d);
338
   d->lock(d);
339
 
340
   link_tail(d);
341
 
342
   apple_glx_diagnostic("%s: new drawable %p\n", __func__, (void *) d);
343
 
344
   *agdResult = d;
345
 
346
   return false;
347
}
348
 
349
static int error_count = 0;
350
 
351
static int
352
error_handler(Display * dpy, XErrorEvent * err)
353
{
354
   if (err->error_code == BadWindow) {
355
      ++error_count;
356
   }
357
 
358
   return 0;
359
}
360
 
361
void
362
apple_glx_garbage_collect_drawables(Display * dpy)
363
{
364
   struct apple_glx_drawable *d, *dnext;
365
   Window root;
366
   int x, y;
367
   unsigned int width, height, bd, depth;
368
   int (*old_handler) (Display *, XErrorEvent *);
369
 
370
 
371
   if (NULL == drawables_list)
372
      return;
373
 
374
   old_handler = XSetErrorHandler(error_handler);
375
 
376
   XSync(dpy, False);
377
 
378
   lock_drawables_list();
379
 
380
   for (d = drawables_list; d;) {
381
      dnext = d->next;
382
 
383
      d->lock(d);
384
 
385
      if (d->reference_count > 0) {
386
         /*
387
          * Skip this, because some context still retains a reference
388
          * to the drawable.
389
          */
390
         d->unlock(d);
391
         d = dnext;
392
         continue;
393
      }
394
 
395
      d->unlock(d);
396
 
397
      error_count = 0;
398
 
399
      /*
400
       * Mesa uses XGetWindowAttributes, but some of these things are
401
       * most definitely not Windows, and that's against the rules.
402
       * XGetGeometry on the other hand is legal with a Pixmap and Window.
403
       */
404
      XGetGeometry(dpy, d->drawable, &root, &x, &y, &width, &height, &bd,
405
                   &depth);
406
 
407
      if (error_count > 0) {
408
         /*
409
          * Note: this may not actually destroy the drawable.
410
          * If another context retains a reference to the drawable
411
          * after the reference count test above.
412
          */
413
         (void) destroy_drawable(d);
414
         error_count = 0;
415
      }
416
 
417
      d = dnext;
418
   }
419
 
420
   XSetErrorHandler(old_handler);
421
 
422
   unlock_drawables_list();
423
}
424
 
425
unsigned int
426
apple_glx_get_drawable_count(void)
427
{
428
   unsigned int result = 0;
429
   struct apple_glx_drawable *d;
430
 
431
   lock_drawables_list();
432
 
433
   for (d = drawables_list; d; d = d->next)
434
      ++result;
435
 
436
   unlock_drawables_list();
437
 
438
   return result;
439
}
440
 
441
struct apple_glx_drawable *
442
apple_glx_drawable_find_by_type(GLXDrawable drawable, int type, int flags)
443
{
444
   struct apple_glx_drawable *d;
445
 
446
   lock_drawables_list();
447
 
448
   for (d = drawables_list; d; d = d->next) {
449
      if (d->type == type && d->drawable == drawable) {
450
         if (flags & APPLE_GLX_DRAWABLE_REFERENCE)
451
            d->reference(d);
452
 
453
         if (flags & APPLE_GLX_DRAWABLE_LOCK)
454
            d->lock(d);
455
 
456
         unlock_drawables_list();
457
 
458
         return d;
459
      }
460
   }
461
 
462
   unlock_drawables_list();
463
 
464
   return NULL;
465
}
466
 
467
struct apple_glx_drawable *
468
apple_glx_drawable_find(GLXDrawable drawable, int flags)
469
{
470
   struct apple_glx_drawable *d;
471
 
472
   lock_drawables_list();
473
 
474
   for (d = drawables_list; d; d = d->next) {
475
      if (d->drawable == drawable) {
476
         if (flags & APPLE_GLX_DRAWABLE_REFERENCE)
477
            d->reference(d);
478
 
479
         if (flags & APPLE_GLX_DRAWABLE_LOCK)
480
            d->lock(d);
481
 
482
         unlock_drawables_list();
483
 
484
         return d;
485
      }
486
   }
487
 
488
   unlock_drawables_list();
489
 
490
   return NULL;
491
}
492
 
493
/* Return true if the type is valid for the drawable. */
494
bool
495
apple_glx_drawable_destroy_by_type(Display * dpy,
496
                                   GLXDrawable drawable, int type)
497
{
498
   struct apple_glx_drawable *d;
499
 
500
   lock_drawables_list();
501
 
502
   for (d = drawables_list; d; d = d->next) {
503
      if (drawable == d->drawable && type == d->type) {
504
         /*
505
          * The user has requested that we destroy this resource.
506
          * However, there may be references in the contexts to it, so
507
          * release it, and call destroy_drawable which doesn't destroy
508
          * if the reference_count is > 0.
509
          */
510
         d->release(d);
511
 
512
         apple_glx_diagnostic("%s d->reference_count %d\n",
513
                              __func__, d->reference_count);
514
 
515
         destroy_drawable(d);
516
         unlock_drawables_list();
517
         return true;
518
      }
519
   }
520
 
521
   unlock_drawables_list();
522
 
523
   return false;
524
}
525
 
526
struct apple_glx_drawable *
527
apple_glx_drawable_find_by_uid(unsigned int uid, int flags)
528
{
529
   struct apple_glx_drawable *d;
530
 
531
   lock_drawables_list();
532
 
533
   for (d = drawables_list; d; d = d->next) {
534
      /* Only surfaces have a uid. */
535
      if (APPLE_GLX_DRAWABLE_SURFACE == d->type) {
536
         if (d->types.surface.uid == uid) {
537
            if (flags & APPLE_GLX_DRAWABLE_REFERENCE)
538
               d->reference(d);
539
 
540
            if (flags & APPLE_GLX_DRAWABLE_LOCK)
541
               d->lock(d);
542
 
543
            unlock_drawables_list();
544
 
545
            return d;
546
         }
547
      }
548
   }
549
 
550
   unlock_drawables_list();
551
 
552
   return NULL;
553
}