source: trunk/sys/TinyGL/src/glx.c @ 339

Last change on this file since 339 was 1, checked in by alain, 8 years ago

First import

File size: 10.4 KB
Line 
1/* simple glx driver for TinyGL */
2#include <GL/glx.h>
3#include <sys/ipc.h>
4#include <sys/shm.h>
5#include <X11/extensions/XShm.h>
6#include "zgl.h"
7
8typedef struct {
9  GLContext *gl_context;
10  Display *display;
11  XVisualInfo visual_info;
12  int xsize,ysize;
13  XImage *ximage;
14  GC gc;
15  Colormap cmap;
16  Drawable drawable;
17  int do_convert; /* true if must do convertion to X11 format */
18  /* shared memory */
19  int shm_use;
20  XShmSegmentInfo *shm_info;
21  int CompletionType;
22} TinyGLXContext;
23
24Bool glXQueryExtension( Display *dpy, int *errorb, int *event )
25{
26    return True;
27}
28
29
30XVisualInfo* glXChooseVisual( Display *dpy, int screen,
31                              int *attribList )
32{
33    XVisualInfo vinfo;
34    int n;
35   
36    /* the attribList is ignored : we consider only RGBA rendering (no
37       direct color) */
38   
39    if (XMatchVisualInfo (dpy, screen, 16, TrueColor, &vinfo)) {
40        /* 16 bit visual (fastest with TinyGL) */
41    } else if (XMatchVisualInfo (dpy, screen, 24, TrueColor, &vinfo)) {
42        /* 24 bit visual */
43    } else if (XMatchVisualInfo (dpy, screen, 32, TrueColor, &vinfo)) {
44        /* 32 bit visual */
45    } else if (XMatchVisualInfo (dpy, screen, 8, PseudoColor, &vinfo)) {
46        /* 8 bit visual */
47    } else {
48        /* no suitable visual */
49        return NULL;
50    }
51   
52    return XGetVisualInfo(dpy,VisualAllMask,&vinfo,&n);
53}
54
55
56
57GLXContext glXCreateContext( Display *dpy, XVisualInfo *vis,
58                             GLXContext shareList, Bool direct )
59{
60  TinyGLXContext *ctx;
61
62  if (shareList != NULL) {
63    gl_fatal_error("No sharing available in TinyGL");
64  }
65  ctx=gl_malloc(sizeof(TinyGLXContext));
66  ctx->gl_context=NULL;
67  ctx->visual_info=*vis;
68  return (GLXContext) ctx;
69}
70
71
72void glXDestroyContext( Display *dpy, GLXContext ctx1 )
73{
74  TinyGLXContext *ctx = (TinyGLXContext *) ctx1;
75  if (ctx->gl_context != NULL) {
76    glClose();
77  }
78  gl_free(ctx);
79}
80
81
82static int glxXErrorFlag=0;
83
84static int glxHandleXError(Display *dpy,XErrorEvent *event)
85{
86  glxXErrorFlag=1;
87  return 0;
88}
89
90static int bits_per_pixel(Display *dpy, XVisualInfo *visinfo)
91{
92   XImage *img;
93   int bpp;
94   char *data;
95
96   data = gl_malloc(8);
97   if (data == NULL) 
98       return visinfo->depth;
99
100   img = XCreateImage(dpy, visinfo->visual, visinfo->depth,
101                      ZPixmap, 0, data, 1, 1, 32, 0);
102   if (img == NULL) {
103       gl_free(data);
104       return visinfo->depth;
105   }
106   bpp = img->bits_per_pixel;
107   gl_free(data);
108   img->data = NULL;
109   XDestroyImage(img);
110   return bpp;
111}
112
113static int create_ximage(TinyGLXContext *ctx,
114                         int xsize,int ysize,int depth)
115{
116  int major,minor;
117  Bool pixmaps;
118  unsigned char *framebuffer;
119  int (*old_handler)(Display *,XErrorEvent *);
120
121  if (XShmQueryVersion(ctx->display,&major,&minor,&pixmaps))
122    ctx->shm_use=1;
123  else
124    ctx->shm_use=0;
125
126  if (!ctx->shm_use) goto no_shm;
127
128  ctx->shm_info=gl_malloc(sizeof(XShmSegmentInfo));
129  ctx->ximage=XShmCreateImage(ctx->display,None,depth,ZPixmap,NULL,
130                              ctx->shm_info,xsize,ysize);
131  if (ctx->ximage == NULL) {
132    fprintf(stderr,"XShm: error: XShmCreateImage\n");
133    ctx->shm_use=0;
134    gl_free(ctx->shm_info);
135    goto no_shm;
136  }
137  ctx->shm_info->shmid=shmget(IPC_PRIVATE,
138                              ctx->ysize*ctx->ximage->bytes_per_line,
139                              IPC_CREAT | 0777);
140  if (ctx->shm_info->shmid < 0) {
141    fprintf(stderr,"XShm: error: shmget\n");
142  no_shm1:
143    ctx->shm_use=0;
144    XDestroyImage(ctx->ximage);
145    goto no_shm;
146  }
147  ctx->ximage->data=shmat(ctx->shm_info->shmid,0,0);
148  if (ctx->ximage->data == (char *) -1) {
149    fprintf(stderr,"XShm: error: shmat\n");
150  no_shm2:
151    shmctl(ctx->shm_info->shmid,IPC_RMID,0);
152    goto no_shm1;
153  }
154  ctx->shm_info->shmaddr=ctx->ximage->data;
155 
156  ctx->shm_info->readOnly=False;
157
158  /* attach & test X errors */
159
160  glxXErrorFlag=0;
161  old_handler=XSetErrorHandler(glxHandleXError);
162  XShmAttach(ctx->display,ctx->shm_info);
163  XSync(ctx->display, False);
164 
165  if (glxXErrorFlag) {
166    XFlush(ctx->display);
167    shmdt(ctx->shm_info->shmaddr);
168    XSetErrorHandler(old_handler);
169    goto no_shm2;
170  }
171
172  /* the shared memory will be automatically deleted */
173  shmctl(ctx->shm_info->shmid,IPC_RMID,0);
174
175  /* test with a dummy XShmPutImage */
176  XShmPutImage(ctx->display,ctx->drawable,ctx->gc,
177               ctx->ximage,0,0,0,0,1,1,
178               False);
179
180  XSync(ctx->display, False);
181  XSetErrorHandler(old_handler);
182 
183  if (glxXErrorFlag) {
184    fprintf(stderr,"XShm: error: XShmPutImage\n");
185    XFlush(ctx->display);
186    shmdt(ctx->shm_info->shmaddr);
187    goto no_shm2;
188  }
189 
190  ctx->CompletionType=XShmGetEventBase(ctx->display) + ShmCompletion;
191  /* shared memory is OK !! */
192
193  return 0;
194
195  no_shm:
196    ctx->ximage=XCreateImage(ctx->display, None, depth, ZPixmap, 0, 
197                             NULL,xsize,ysize, 8, 0);
198    framebuffer=gl_malloc(ysize * ctx->ximage->bytes_per_line);
199    ctx->ximage->data = framebuffer;
200    return 0;
201}
202
203static void free_ximage(TinyGLXContext *ctx)
204{
205  if (ctx->shm_use)
206  {
207    XShmDetach(ctx->display, ctx->shm_info);
208    XDestroyImage(ctx->ximage);
209    shmdt(ctx->shm_info->shmaddr);
210    gl_free(ctx->shm_info);
211  } else {
212    gl_free(ctx->ximage->data);
213    XDestroyImage(ctx->ximage);
214  }
215}
216
217/* resize the glx viewport : we try to use the xsize and ysize
218   given. We return the effective size which is guaranted to be smaller */
219
220int glX_resize_viewport(GLContext *c,int *xsize_ptr,int *ysize_ptr)
221{
222  TinyGLXContext *ctx;
223  int xsize,ysize;
224
225  ctx=(TinyGLXContext *)c->opaque;
226
227  xsize=*xsize_ptr;
228  ysize=*ysize_ptr;
229
230  /* we ensure that xsize and ysize are multiples of 2 for the zbuffer.
231     TODO: find a better solution */
232  xsize&=~3;
233  ysize&=~3;
234
235  if (xsize == 0 || ysize == 0) return -1;
236
237  *xsize_ptr=xsize;
238  *ysize_ptr=ysize;
239
240  if (ctx->ximage != NULL) free_ximage(ctx);
241 
242  ctx->xsize=xsize;
243  ctx->ysize=ysize;
244
245  if (create_ximage(ctx,ctx->xsize,ctx->ysize,ctx->visual_info.depth) != 0) 
246    return -1;
247
248  /* resize the Z buffer */
249  if (ctx->do_convert) {
250    ZB_resize(c->zb,NULL,xsize,ysize);
251  } else {
252    ZB_resize(c->zb,ctx->ximage->data,xsize,ysize);
253  }
254  return 0;
255}
256
257/* we assume here that drawable is a window */
258Bool glXMakeCurrent( Display *dpy, GLXDrawable drawable,
259                     GLXContext ctx1)
260{
261  TinyGLXContext *ctx = (TinyGLXContext *) ctx1;
262  XWindowAttributes attr;
263  int i,xsize,ysize;
264  unsigned int palette[ZB_NB_COLORS];
265  unsigned char color_indexes[ZB_NB_COLORS];
266  ZBuffer *zb;
267  XColor xcolor;
268  unsigned long pixel[ZB_NB_COLORS],tmp_plane;
269 
270  if (ctx->gl_context == NULL) {
271    /* create the TinyGL context */
272
273    ctx->display=dpy;
274    ctx->drawable=drawable;
275
276    XGetWindowAttributes(ctx->display,drawable,&attr);
277
278    xsize=attr.width;
279    ysize=attr.height;
280
281    if (attr.depth != ctx->visual_info.depth) return False;
282
283    /* ximage structure */
284    ctx->ximage=NULL;
285    ctx->shm_use=1; /* use shm */
286
287    if (attr.depth == 8) {
288      /* get the colormap from the window */
289      ctx->cmap = attr.colormap;
290
291      if ( XAllocColorCells(ctx->display,ctx->cmap,True,&tmp_plane,0,
292                            pixel,ZB_NB_COLORS) == 0) {
293        /* private cmap */
294        ctx->cmap = XCreateColormap(ctx->display, drawable, 
295                                    ctx->visual_info.visual, AllocAll);
296        XSetWindowColormap(ctx->display, drawable, ctx->cmap);
297        for(i=0;i<ZB_NB_COLORS;i++) pixel[i]=i;
298      }
299
300      for(i=0;i<ZB_NB_COLORS;i++) color_indexes[i]=pixel[i];
301
302      /* Open the Z Buffer - 256 colors */
303      zb=ZB_open(xsize,ysize,ZB_MODE_INDEX,ZB_NB_COLORS,
304                 color_indexes,palette,NULL);
305      if (zb == NULL) {
306        fprintf(stderr, "Error while initializing Z buffer\n");
307        exit(1);
308      }
309
310      for (i=0; i<ZB_NB_COLORS; i++) {
311        xcolor.flags = DoRed | DoGreen | DoBlue;
312       
313        xcolor.red = (palette[i]>>8) & 0xFF00;
314        xcolor.green = (palette[i] & 0xFF00);
315        xcolor.blue = (palette[i] << 8) & 0xFF00;
316        xcolor.pixel = pixel[i];
317        XStoreColor(ctx->display,ctx->cmap,&xcolor);
318      }
319      ctx->do_convert = 1;
320    } else {
321        int mode,bpp;
322        /* RGB 16/24/32 */
323        bpp = bits_per_pixel(ctx->display,&ctx->visual_info);
324        switch(bpp) {
325        case 24:
326            mode = ZB_MODE_RGB24;
327            ctx->do_convert = (TGL_FEATURE_RENDER_BITS != 16);
328            break;
329        case 32:
330            mode = ZB_MODE_RGBA;
331            ctx->do_convert = (TGL_FEATURE_RENDER_BITS != 16);
332            break;
333        default:
334            mode = ZB_MODE_5R6G5B;
335            ctx->do_convert = (TGL_FEATURE_RENDER_BITS != 16);
336            break;
337        }
338        zb=ZB_open(xsize,ysize,mode,0,NULL,NULL,NULL);
339        if (zb == NULL) {
340            fprintf(stderr, "Error while initializing Z buffer\n");
341            exit(1);
342        }
343    }
344
345    /* create a gc */
346    ctx->gc = XCreateGC(ctx->display, drawable, 0, 0);
347
348    /* initialisation of the TinyGL interpreter */
349    glInit(zb);
350    ctx->gl_context=gl_get_context();
351    ctx->gl_context->opaque=(void *) ctx;
352    ctx->gl_context->gl_resize_viewport=glX_resize_viewport;
353
354    /* set the viewport : we force a call to glX_resize_viewport */
355    ctx->gl_context->viewport.xsize=-1;
356    ctx->gl_context->viewport.ysize=-1;
357
358    glViewport(0, 0, xsize, ysize);
359  }
360
361  return True;
362}
363
364static Bool WaitForShmCompletion(Display *dpy, XEvent *event, char *arg) 
365{
366    TinyGLXContext *ctx=(TinyGLXContext *) arg;
367
368    return (event->type == ctx->CompletionType) && 
369        ( ((XShmCompletionEvent *)event)->drawable == (Window)ctx->drawable); 
370}
371
372void glXSwapBuffers( Display *dpy, GLXDrawable drawable )
373{
374  GLContext *gl_context;
375  TinyGLXContext *ctx;
376
377  /* retrieve the current GLXContext */
378  gl_context=gl_get_context();
379  ctx=(TinyGLXContext *)gl_context->opaque;
380
381  /* for non 16 bits visuals, a conversion is required */
382 
383
384  if (ctx->do_convert) {
385    ZB_copyFrameBuffer(ctx->gl_context->zb,
386                       ctx->ximage->data,
387                       ctx->ximage->bytes_per_line);
388
389  }
390
391  /* draw the ximage */
392  if (ctx->shm_use) {
393      XEvent event;
394
395      XShmPutImage(dpy,drawable,ctx->gc,
396                   ctx->ximage,0,0,0,0,ctx->ximage->width, ctx->ximage->height,
397                   True);
398      XIfEvent(dpy, &event, WaitForShmCompletion, (char*)ctx);
399  } else {
400    XPutImage(dpy, drawable, ctx->gc, 
401              ctx->ximage, 0, 0, 0, 0, ctx->ximage->width, ctx->ximage->height);
402  }
403  XFlush(dpy);
404}
405
406
407void glXWaitGL( void )
408{
409}
410
411void glXWaitX( void )
412{
413}
Note: See TracBrowser for help on using the repository browser.