version 2.8
glx.c
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 
8 typedef 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 
24 Bool glXQueryExtension( Display *dpy, int *errorb, int *event )
25 {
26  return True;
27 }
28 
29 
30 XVisualInfo* 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 
57 GLXContext 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 
72 void 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 
82 static int glxXErrorFlag=0;
83 
84 static int glxHandleXError(Display *dpy,XErrorEvent *event)
85 {
86  glxXErrorFlag=1;
87  return 0;
88 }
89 
90 static 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 
113 static 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 
203 static 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 
220 int 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 */
258 Bool 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 
364 static 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 
372 void 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 
407 void glXWaitGL( void )
408 {
409 }
410 
411 void glXWaitX( void )
412 {
413 }