Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4358 Serge 1
/**************************************************************************
2
 *
3
 * Copyright 2007 Tungsten Graphics, Inc., Bismarck, ND., USA
4
 * All Rights Reserved.
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a
7
 * copy of this software and associated documentation files (the
8
 * "Software"), to deal in the Software without restriction, including
9
 * without limitation the rights to use, copy, modify, merge, publish,
10
 * distribute, sub license, and/or sell copies of the Software, and to
11
 * permit persons to whom the Software is furnished to do so, subject to
12
 * the following conditions:
13
 *
14
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
17
 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
18
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20
 * USE OR OTHER DEALINGS IN THE SOFTWARE.
21
 *
22
 * The above copyright notice and this permission notice (including the
23
 * next paragraph) shall be included in all copies or substantial portions
24
 * of the Software.
25
 *
26
 *
27
 **************************************************************************/
28
 
29
/*
30
 * Authors:
31
 *   Keith Whitwell
32
 *   Brian Paul
33
 */
34
 
35
#include "pipe/p_format.h"
36
#include "pipe/p_context.h"
37
#include "util/u_inlines.h"
38
#include "util/u_format.h"
39
#include "util/u_math.h"
40
#include "util/u_memory.h"
41
 
42
#include "state_tracker/xlib_sw_winsys.h"
43
 
44
#include 
45
#include 
46
#include 
47
#include 
48
#include 
49
#include 
50
 
51
DEBUG_GET_ONCE_BOOL_OPTION(xlib_no_shm, "XLIB_NO_SHM", FALSE)
52
 
53
/**
54
 * Display target for Xlib winsys.
55
 * Low-level OS/window system memory buffer
56
 */
57
struct xlib_displaytarget
58
{
59
   enum pipe_format format;
60
   unsigned width;
61
   unsigned height;
62
   unsigned stride;
63
 
64
   void *data;
65
   void *mapped;
66
 
67
   Display *display;
68
   Visual *visual;
69
   XImage *tempImage;
70
   GC gc;
71
 
72
   /* This is the last drawable that this display target was presented
73
    * against.  May need to recreate gc, tempImage when this changes??
74
    */
75
   Drawable drawable;
76
 
77
   XShmSegmentInfo shminfo;
78
   Bool shm;  /** Using shared memory images? */
79
};
80
 
81
 
82
/**
83
 * Subclass of sw_winsys for Xlib winsys
84
 */
85
struct xlib_sw_winsys
86
{
87
   struct sw_winsys base;
88
   Display *display;
89
};
90
 
91
 
92
 
93
/** Cast wrapper */
94
static INLINE struct xlib_displaytarget *
95
xlib_displaytarget(struct sw_displaytarget *dt)
96
{
97
   return (struct xlib_displaytarget *) dt;
98
}
99
 
100
 
101
/**
102
 * X Shared Memory Image extension code
103
 */
104
 
105
static volatile int XErrorFlag = 0;
106
 
107
/**
108
 * Catches potential Xlib errors.
109
 */
110
static int
111
handle_xerror(Display *dpy, XErrorEvent *event)
112
{
113
   (void) dpy;
114
   (void) event;
115
   XErrorFlag = 1;
116
   return 0;
117
}
118
 
119
 
120
static char *
121
alloc_shm(struct xlib_displaytarget *buf, unsigned size)
122
{
123
   XShmSegmentInfo *const shminfo = & buf->shminfo;
124
 
125
   shminfo->shmid = -1;
126
   shminfo->shmaddr = (char *) -1;
127
 
128
   shminfo->shmid = shmget(IPC_PRIVATE, size, IPC_CREAT|0777);
129
   if (shminfo->shmid < 0) {
130
      return NULL;
131
   }
132
 
133
   shminfo->shmaddr = (char *) shmat(shminfo->shmid, 0, 0);
134
   if (shminfo->shmaddr == (char *) -1) {
135
      shmctl(shminfo->shmid, IPC_RMID, 0);
136
      return NULL;
137
   }
138
 
139
   shminfo->readOnly = False;
140
   return shminfo->shmaddr;
141
}
142
 
143
 
144
/**
145
 * Allocate a shared memory XImage back buffer for the given display target.
146
 */
147
static void
148
alloc_shm_ximage(struct xlib_displaytarget *xlib_dt,
149
                 struct xlib_drawable *xmb,
150
                 unsigned width, unsigned height)
151
{
152
   /*
153
    * We have to do a _lot_ of error checking here to be sure we can
154
    * really use the XSHM extension.  It seems different servers trigger
155
    * errors at different points if the extension won't work.  Therefore
156
    * we have to be very careful...
157
    */
158
   int (*old_handler)(Display *, XErrorEvent *);
159
 
160
   xlib_dt->tempImage = XShmCreateImage(xlib_dt->display,
161
                                      xmb->visual,
162
                                      xmb->depth,
163
                                      ZPixmap,
164
                                      NULL,
165
                                      &xlib_dt->shminfo,
166
                                      width, height);
167
   if (xlib_dt->tempImage == NULL) {
168
      shmctl(xlib_dt->shminfo.shmid, IPC_RMID, 0);
169
      xlib_dt->shm = False;
170
      return;
171
   }
172
 
173
 
174
   XErrorFlag = 0;
175
   old_handler = XSetErrorHandler(handle_xerror);
176
   /* This may trigger the X protocol error we're ready to catch: */
177
   XShmAttach(xlib_dt->display, &xlib_dt->shminfo);
178
   XSync(xlib_dt->display, False);
179
 
180
   /* Mark the segment to be destroyed, so that it is automatically destroyed
181
    * when this process dies.  Needs to be after XShmAttach() for *BSD.
182
    */
183
   shmctl(xlib_dt->shminfo.shmid, IPC_RMID, 0);
184
 
185
   if (XErrorFlag) {
186
      /* we are on a remote display, this error is normal, don't print it */
187
      XFlush(xlib_dt->display);
188
      XErrorFlag = 0;
189
      XDestroyImage(xlib_dt->tempImage);
190
      xlib_dt->tempImage = NULL;
191
      xlib_dt->shm = False;
192
      (void) XSetErrorHandler(old_handler);
193
      return;
194
   }
195
 
196
   xlib_dt->shm = True;
197
}
198
 
199
 
200
static void
201
alloc_ximage(struct xlib_displaytarget *xlib_dt,
202
             struct xlib_drawable *xmb,
203
             unsigned width, unsigned height)
204
{
205
   /* try allocating a shared memory image first */
206
   if (xlib_dt->shm) {
207
      alloc_shm_ximage(xlib_dt, xmb, width, height);
208
      if (xlib_dt->tempImage)
209
         return; /* success */
210
   }
211
 
212
   /* try regular (non-shared memory) image */
213
   xlib_dt->tempImage = XCreateImage(xlib_dt->display,
214
                                   xmb->visual,
215
                                   xmb->depth,
216
                                   ZPixmap, 0,
217
                                   NULL, width, height,
218
                                   8, 0);
219
}
220
 
221
static boolean
222
xlib_is_displaytarget_format_supported(struct sw_winsys *ws,
223
                                       unsigned tex_usage,
224
                                       enum pipe_format format)
225
{
226
   /* TODO: check visuals or other sensible thing here */
227
   return TRUE;
228
}
229
 
230
 
231
static void *
232
xlib_displaytarget_map(struct sw_winsys *ws,
233
                       struct sw_displaytarget *dt,
234
                       unsigned flags)
235
{
236
   struct xlib_displaytarget *xlib_dt = xlib_displaytarget(dt);
237
   xlib_dt->mapped = xlib_dt->data;
238
   return xlib_dt->mapped;
239
}
240
 
241
 
242
static void
243
xlib_displaytarget_unmap(struct sw_winsys *ws,
244
                         struct sw_displaytarget *dt)
245
{
246
   struct xlib_displaytarget *xlib_dt = xlib_displaytarget(dt);
247
   xlib_dt->mapped = NULL;
248
}
249
 
250
 
251
static void
252
xlib_displaytarget_destroy(struct sw_winsys *ws,
253
                           struct sw_displaytarget *dt)
254
{
255
   struct xlib_displaytarget *xlib_dt = xlib_displaytarget(dt);
256
 
257
   if (xlib_dt->data) {
258
      if (xlib_dt->shminfo.shmid >= 0) {
259
         shmdt(xlib_dt->shminfo.shmaddr);
260
         shmctl(xlib_dt->shminfo.shmid, IPC_RMID, 0);
261
 
262
         xlib_dt->shminfo.shmid = -1;
263
         xlib_dt->shminfo.shmaddr = (char *) -1;
264
 
265
         xlib_dt->data = NULL;
266
         if (xlib_dt->tempImage)
267
            xlib_dt->tempImage->data = NULL;
268
      }
269
      else {
270
         FREE(xlib_dt->data);
271
         if (xlib_dt->tempImage && xlib_dt->tempImage->data == xlib_dt->data) {
272
            xlib_dt->tempImage->data = NULL;
273
         }
274
         xlib_dt->data = NULL;
275
      }
276
   }
277
 
278
   if (xlib_dt->tempImage) {
279
      XDestroyImage(xlib_dt->tempImage);
280
      xlib_dt->tempImage = NULL;
281
   }
282
 
283
   if (xlib_dt->gc)
284
      XFreeGC(xlib_dt->display, xlib_dt->gc);
285
 
286
   FREE(xlib_dt);
287
}
288
 
289
 
290
/**
291
 * Display/copy the image in the surface into the X window specified
292
 * by the display target.
293
 */
294
static void
295
xlib_sw_display(struct xlib_drawable *xlib_drawable,
296
                struct sw_displaytarget *dt)
297
{
298
   static boolean no_swap = 0;
299
   static boolean firsttime = 1;
300
   struct xlib_displaytarget *xlib_dt = xlib_displaytarget(dt);
301
   Display *display = xlib_dt->display;
302
   XImage *ximage;
303
 
304
   if (firsttime) {
305
      no_swap = getenv("SP_NO_RAST") != NULL;
306
      firsttime = 0;
307
   }
308
 
309
   if (no_swap)
310
      return;
311
 
312
   if (xlib_dt->drawable != xlib_drawable->drawable) {
313
      if (xlib_dt->gc) {
314
         XFreeGC(display, xlib_dt->gc);
315
         xlib_dt->gc = NULL;
316
      }
317
 
318
      if (xlib_dt->tempImage) {
319
         XDestroyImage(xlib_dt->tempImage);
320
         xlib_dt->tempImage = NULL;
321
      }
322
 
323
      xlib_dt->drawable = xlib_drawable->drawable;
324
   }
325
 
326
   if (xlib_dt->tempImage == NULL) {
327
      assert(util_format_get_blockwidth(xlib_dt->format) == 1);
328
      assert(util_format_get_blockheight(xlib_dt->format) == 1);
329
      alloc_ximage(xlib_dt, xlib_drawable,
330
                   xlib_dt->stride / util_format_get_blocksize(xlib_dt->format),
331
                   xlib_dt->height);
332
      if (!xlib_dt->tempImage)
333
         return;
334
   }
335
 
336
   if (xlib_dt->gc == NULL) {
337
      xlib_dt->gc = XCreateGC(display, xlib_drawable->drawable, 0, NULL);
338
      XSetFunction(display, xlib_dt->gc, GXcopy);
339
   }
340
 
341
   if (xlib_dt->shm) {
342
      ximage = xlib_dt->tempImage;
343
      ximage->data = xlib_dt->data;
344
 
345
      /* _debug_printf("XSHM\n"); */
346
      XShmPutImage(xlib_dt->display, xlib_drawable->drawable, xlib_dt->gc,
347
                   ximage, 0, 0, 0, 0, xlib_dt->width, xlib_dt->height, False);
348
   }
349
   else {
350
      /* display image in Window */
351
      ximage = xlib_dt->tempImage;
352
      ximage->data = xlib_dt->data;
353
 
354
      /* check that the XImage has been previously initialized */
355
      assert(ximage->format);
356
      assert(ximage->bitmap_unit);
357
 
358
      /* update XImage's fields */
359
      ximage->width = xlib_dt->width;
360
      ximage->height = xlib_dt->height;
361
      ximage->bytes_per_line = xlib_dt->stride;
362
 
363
      /* _debug_printf("XPUT\n"); */
364
      XPutImage(xlib_dt->display, xlib_drawable->drawable, xlib_dt->gc,
365
                ximage, 0, 0, 0, 0, xlib_dt->width, xlib_dt->height);
366
   }
367
 
368
   XFlush(xlib_dt->display);
369
}
370
 
371
 
372
/**
373
 * Display/copy the image in the surface into the X window specified
374
 * by the display target.
375
 */
376
static void
377
xlib_displaytarget_display(struct sw_winsys *ws,
378
                           struct sw_displaytarget *dt,
379
                           void *context_private)
380
{
381
   struct xlib_drawable *xlib_drawable = (struct xlib_drawable *)context_private;
382
   xlib_sw_display(xlib_drawable, dt);
383
}
384
 
385
 
386
static struct sw_displaytarget *
387
xlib_displaytarget_create(struct sw_winsys *winsys,
388
                          unsigned tex_usage,
389
                          enum pipe_format format,
390
                          unsigned width, unsigned height,
391
                          unsigned alignment,
392
                          unsigned *stride)
393
{
394
   struct xlib_displaytarget *xlib_dt;
395
   unsigned nblocksy, size;
396
 
397
   xlib_dt = CALLOC_STRUCT(xlib_displaytarget);
398
   if (!xlib_dt)
399
      goto no_xlib_dt;
400
 
401
   xlib_dt->display = ((struct xlib_sw_winsys *)winsys)->display;
402
   xlib_dt->format = format;
403
   xlib_dt->width = width;
404
   xlib_dt->height = height;
405
 
406
   nblocksy = util_format_get_nblocksy(format, height);
407
   xlib_dt->stride = align(util_format_get_stride(format, width), alignment);
408
   size = xlib_dt->stride * nblocksy;
409
 
410
   if (!debug_get_option_xlib_no_shm()) {
411
      xlib_dt->data = alloc_shm(xlib_dt, size);
412
      if (xlib_dt->data) {
413
         xlib_dt->shm = True;
414
      }
415
   }
416
 
417
   if (!xlib_dt->data) {
418
      xlib_dt->data = align_malloc(size, alignment);
419
      if (!xlib_dt->data)
420
         goto no_data;
421
   }
422
 
423
   *stride = xlib_dt->stride;
424
   return (struct sw_displaytarget *)xlib_dt;
425
 
426
no_data:
427
   FREE(xlib_dt);
428
no_xlib_dt:
429
   return NULL;
430
}
431
 
432
 
433
static struct sw_displaytarget *
434
xlib_displaytarget_from_handle(struct sw_winsys *winsys,
435
                               const struct pipe_resource *templet,
436
                               struct winsys_handle *whandle,
437
                               unsigned *stride)
438
{
439
   assert(0);
440
   return NULL;
441
}
442
 
443
 
444
static boolean
445
xlib_displaytarget_get_handle(struct sw_winsys *winsys,
446
                              struct sw_displaytarget *dt,
447
                              struct winsys_handle *whandle)
448
{
449
   assert(0);
450
   return FALSE;
451
}
452
 
453
 
454
static void
455
xlib_destroy(struct sw_winsys *ws)
456
{
457
   FREE(ws);
458
}
459
 
460
 
461
struct sw_winsys *
462
xlib_create_sw_winsys(Display *display)
463
{
464
   struct xlib_sw_winsys *ws;
465
 
466
   ws = CALLOC_STRUCT(xlib_sw_winsys);
467
   if (!ws)
468
      return NULL;
469
 
470
   ws->display = display;
471
   ws->base.destroy = xlib_destroy;
472
 
473
   ws->base.is_displaytarget_format_supported = xlib_is_displaytarget_format_supported;
474
 
475
   ws->base.displaytarget_create = xlib_displaytarget_create;
476
   ws->base.displaytarget_from_handle = xlib_displaytarget_from_handle;
477
   ws->base.displaytarget_get_handle = xlib_displaytarget_get_handle;
478
   ws->base.displaytarget_map = xlib_displaytarget_map;
479
   ws->base.displaytarget_unmap = xlib_displaytarget_unmap;
480
   ws->base.displaytarget_destroy = xlib_displaytarget_destroy;
481
 
482
   ws->base.displaytarget_display = xlib_displaytarget_display;
483
 
484
   return &ws->base;
485
}