Merge branch 'master' of ssh://repo.or.cz/srv/git/tgl
[tgl.git] / src / glx.c
blob957d8bb35c16f4e0116b7fd676731dad16f5d590
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"
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;
24 Bool glXQueryExtension( Display *dpy, int *errorb, int *event )
26 return True;
30 XVisualInfo* glXChooseVisual( Display *dpy, int screen,
31 int *attribList )
33 XVisualInfo vinfo;
34 int n;
36 /* the attribList is ignored : we consider only RGBA rendering (no
37 direct color) */
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;
52 return XGetVisualInfo(dpy,VisualAllMask,&vinfo,&n);
57 GLXContext glXCreateContext( Display *dpy, XVisualInfo *vis,
58 GLXContext shareList, Bool direct )
60 TinyGLXContext *ctx;
62 if (shareList != NULL) {
63 gl_fatal_error("No sharing available in TinyGL");
65 ctx=gl_malloc(sizeof(TinyGLXContext));
66 ctx->gl_context=NULL;
67 ctx->visual_info=*vis;
68 return (GLXContext) ctx;
72 void glXDestroyContext( Display *dpy, GLXContext ctx1 )
74 TinyGLXContext *ctx = (TinyGLXContext *) ctx1;
75 if (ctx->gl_context != NULL) {
76 glClose();
78 gl_free(ctx);
82 static int glxXErrorFlag=0;
84 static int glxHandleXError(Display *dpy,XErrorEvent *event)
86 glxXErrorFlag=1;
87 return 0;
90 static int bits_per_pixel(Display *dpy, XVisualInfo *visinfo)
92 XImage *img;
93 int bpp;
94 char *data;
96 data = gl_malloc(8);
97 if (data == NULL)
98 return visinfo->depth;
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;
106 bpp = img->bits_per_pixel;
107 gl_free(data);
108 img->data = NULL;
109 XDestroyImage(img);
110 return bpp;
113 static int create_ximage(TinyGLXContext *ctx,
114 int xsize,int ysize,int depth)
116 int major,minor;
117 Bool pixmaps;
118 unsigned char *framebuffer;
119 int (*old_handler)(Display *,XErrorEvent *);
121 if (XShmQueryVersion(ctx->display,&major,&minor,&pixmaps))
122 ctx->shm_use=1;
123 else
124 ctx->shm_use=0;
126 if (!ctx->shm_use) goto no_shm;
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;
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;
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;
154 ctx->shm_info->shmaddr=ctx->ximage->data;
156 ctx->shm_info->readOnly=False;
158 /* attach & test X errors */
160 glxXErrorFlag=0;
161 old_handler=XSetErrorHandler(glxHandleXError);
162 XShmAttach(ctx->display,ctx->shm_info);
163 XSync(ctx->display, False);
165 if (glxXErrorFlag) {
166 XFlush(ctx->display);
167 shmdt(ctx->shm_info->shmaddr);
168 XSetErrorHandler(old_handler);
169 goto no_shm2;
172 /* the shared memory will be automatically deleted */
173 shmctl(ctx->shm_info->shmid,IPC_RMID,0);
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);
180 XSync(ctx->display, False);
181 XSetErrorHandler(old_handler);
183 if (glxXErrorFlag) {
184 fprintf(stderr,"XShm: error: XShmPutImage\n");
185 XFlush(ctx->display);
186 shmdt(ctx->shm_info->shmaddr);
187 goto no_shm2;
190 ctx->CompletionType=XShmGetEventBase(ctx->display) + ShmCompletion;
191 /* shared memory is OK !! */
193 return 0;
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;
203 static void free_ximage(TinyGLXContext *ctx)
205 if (ctx->shm_use)
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);
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 */
220 int glX_resize_viewport(GLContext *c,int *xsize_ptr,int *ysize_ptr)
222 TinyGLXContext *ctx;
223 int xsize,ysize;
225 ctx=(TinyGLXContext *)c->opaque;
227 xsize=*xsize_ptr;
228 ysize=*ysize_ptr;
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;
235 if (xsize == 0 || ysize == 0) return -1;
237 *xsize_ptr=xsize;
238 *ysize_ptr=ysize;
240 if (ctx->ximage != NULL) free_ximage(ctx);
242 ctx->xsize=xsize;
243 ctx->ysize=ysize;
245 if (create_ximage(ctx,ctx->xsize,ctx->ysize,ctx->visual_info.depth) != 0)
246 return -1;
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);
254 return 0;
257 /* we assume here that drawable is a window */
258 Bool glXMakeCurrent( Display *dpy, GLXDrawable drawable,
259 GLXContext ctx1)
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;
270 if (ctx->gl_context == NULL) {
271 /* create the TinyGL context */
273 ctx->display=dpy;
274 ctx->drawable=drawable;
276 XGetWindowAttributes(ctx->display,drawable,&attr);
278 xsize=attr.width;
279 ysize=attr.height;
281 if (attr.depth != ctx->visual_info.depth) return False;
283 /* ximage structure */
284 ctx->ximage=NULL;
285 ctx->shm_use=1; /* use shm */
287 if (attr.depth == 8) {
288 /* get the colormap from the window */
289 ctx->cmap = attr.colormap;
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;
300 for(i=0;i<ZB_NB_COLORS;i++) color_indexes[i]=pixel[i];
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);
310 for (i=0; i<ZB_NB_COLORS; i++) {
311 xcolor.flags = DoRed | DoGreen | DoBlue;
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);
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;
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);
345 /* create a gc */
346 ctx->gc = XCreateGC(ctx->display, drawable, 0, 0);
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;
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;
358 glViewport(0, 0, xsize, ysize);
361 return True;
364 static Bool WaitForShmCompletion(Display *dpy, XEvent *event, char *arg)
366 TinyGLXContext *ctx=(TinyGLXContext *) arg;
368 return (event->type == ctx->CompletionType) &&
369 ( ((XShmCompletionEvent *)event)->drawable == (Window)ctx->drawable);
372 void glXSwapBuffers( Display *dpy, GLXDrawable drawable )
374 GLContext *gl_context;
375 TinyGLXContext *ctx;
377 /* retrieve the current GLXContext */
378 gl_context=gl_get_context();
379 ctx=(TinyGLXContext *)gl_context->opaque;
381 /* for non 16 bits visuals, a conversion is required */
384 if (ctx->do_convert) {
385 ZB_copyFrameBuffer(ctx->gl_context->zb,
386 ctx->ximage->data,
387 ctx->ximage->bytes_per_line);
391 /* draw the ximage */
392 if (ctx->shm_use) {
393 XEvent event;
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);
403 XFlush(dpy);
407 void glXWaitGL( void )
411 void glXWaitX( void )