15563df3f3e5053ac81f840f4b3058b1fa9edf74
[mesa.git] / src / glx / mini / miniglx.c
1 /**
2 * \file miniglx.c
3 * \brief Mini GLX interface functions.
4 * \author Brian Paul
5 *
6 * The Mini GLX interface is a subset of the GLX interface, plus a
7 * minimal set of Xlib functions.
8 */
9
10 /*
11 * Mesa 3-D graphics library
12 * Version: 5.0
13 *
14 * Copyright (C) 1999-2003 Brian Paul All Rights Reserved.
15 *
16 * Permission is hereby granted, free of charge, to any person obtaining a
17 * copy of this software and associated documentation files (the "Software"),
18 * to deal in the Software without restriction, including without limitation
19 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
20 * and/or sell copies of the Software, and to permit persons to whom the
21 * Software is furnished to do so, subject to the following conditions:
22 *
23 * The above copyright notice and this permission notice shall be included
24 * in all copies or substantial portions of the Software.
25 *
26 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
27 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
29 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
30 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 */
33
34 /* $Id: miniglx.c,v 1.2 2003/10/21 06:05:40 jonsmirl Exp $ */
35
36 /**
37 * \mainpage Mini GLX
38 *
39 * \section miniglxIntro Introduction
40 *
41 * The Mini GLX interface facilitates OpenGL rendering on embedded devices. The
42 * interface is a subset of the GLX interface, plus a minimal set of Xlib-like
43 * functions.
44 *
45 * Programs written to the Mini GLX specification should run unchanged
46 * on systems with the X Window System and the GLX extension (after
47 * recompilation). The intention is to allow flexibility for
48 * prototyping and testing.
49 *
50 * The files in the src/miniglx/ directory are compiled to build the
51 * libGL.so library. This is the library which applications link with.
52 * libGL.so in turn, loads the hardware-specific device driver.
53 *
54 *
55 * \section miniglxDoxygen About Doxygen
56 *
57 * For a list of all files, select <b>File List</b>. Choose a file from
58 * the list for a list of all functions in the file.
59 *
60 * For a list of all functions, types, constants, etc.
61 * select <b>File Members</b>.
62 *
63 *
64 * \section miniglxReferences References
65 *
66 * - <A HREF="file:../../docs/MiniGLX.html">Mini GLX Specification</A>,
67 * Tungsten Graphics, Inc.
68 * - OpenGL Graphics with the X Window System, Silicon Graphics, Inc.,
69 * ftp://ftp.sgi.com/opengl/doc/opengl1.2/glx1.3.ps
70 * - Xlib - C Language X Interface, X Consortium Standard, X Version 11,
71 * Release 6.4, ftp://ftp.x.org/pub/R6.4/xc/doc/hardcopy/X11/xlib.PS.gz
72 * - XFree86 Man pages, The XFree86 Project, Inc.,
73 * http://www.xfree86.org/current/manindex3.html
74 *
75 */
76
77 /**
78 * \page datatypes Notes on the XVisualInfo, Visual, and __GLXvisualConfig data types
79 *
80 * -# X (unfortunately) has two (or three) data types which
81 * describe visuals. Ideally, there would just be one.
82 * -# We need the #__GLXvisualConfig type to augment #XVisualInfo and #Visual
83 * because we need to describe the GLX-specific attributes of visuals.
84 * -# In this interface there is a one-to-one-to-one correspondence between
85 * the three types and they're all interconnected.
86 * -# The #XVisualInfo type has a pointer to a #Visual. The #Visual structure
87 * (aka MiniGLXVisualRec) has a pointer to the #__GLXvisualConfig. The
88 * #Visual structure also has a pointer pointing back to the #XVisualInfo.
89 * -# The #XVisualInfo structure is the only one who's contents are public.
90 * -# The glXChooseVisual() and XGetVisualInfo() are the only functions that
91 * return #XVisualInfo structures. They can be freed with XFree(), though
92 * there is a small memory leak.
93 */
94
95
96 #include <assert.h>
97 #include <errno.h>
98 #include <signal.h>
99 #include <stdio.h>
100 #include <stdlib.h>
101 #include <string.h>
102 #include <dlfcn.h>
103 #include <fcntl.h>
104 #include <unistd.h>
105 #include <sys/ioctl.h>
106 #include <sys/mman.h>
107 #include <sys/types.h>
108 #include <linux/kd.h>
109 #include <linux/vt.h>
110
111 #include "miniglxP.h"
112 #include "dri.h"
113
114 #include "glapi.h"
115 #include "xf86drm.h"
116
117
118 /**
119 * \brief Current GLX context.
120 *
121 * \sa glXGetCurrentContext().
122 */
123 static GLXContext CurrentContext = NULL;
124
125
126
127 static Display *SignalDisplay = 0;
128
129 static void SwitchVT(int sig)
130 {
131 fprintf(stderr, "SwitchVT %d dpy %p\n", sig, SignalDisplay);
132
133 if (SignalDisplay) {
134 SignalDisplay->vtSignalFlag = 1;
135 switch( sig )
136 {
137 case SIGUSR1: /* vt has been released */
138 SignalDisplay->haveVT = 0;
139 break;
140 case SIGUSR2: /* vt has been acquired */
141 SignalDisplay->haveVT = 1;
142 break;
143 }
144 }
145 }
146
147 /**********************************************************************/
148 /** \name Framebuffer device functions */
149 /**********************************************************************/
150 /*@{*/
151
152 /**
153 * \brief Do the first part of setting up the framebuffer device.
154 *
155 * \param dpy the display handle.
156 * \param use_vt use a VT for display or not
157 *
158 * \return GL_TRUE on success, or GL_FALSE on failure.
159 *
160 * \sa This is called during XOpenDisplay().
161 *
162 * \internal
163 * Gets the VT number, opens the respective console TTY device. Saves its state
164 * to restore when exiting and goes into graphics mode.
165 *
166 * Opens the framebuffer device and make a copy of the original variable screen
167 * information and gets the fixed screen information. Maps the framebuffer and
168 * MMIO region into the process address space.
169 */
170 static GLboolean
171 OpenFBDev( Display *dpy, int use_vt )
172 {
173 char ttystr[1000];
174 int fd, vtnumber, ttyfd;
175
176 assert(dpy);
177
178 if (geteuid()) {
179 fprintf(stderr, "error: you need to be root\n");
180 return GL_FALSE;
181 }
182
183 if (use_vt) {
184
185 /* open /dev/tty0 and get the VT number */
186 if ((fd = open("/dev/tty0", O_WRONLY, 0)) < 0) {
187 fprintf(stderr, "error opening /dev/tty0\n");
188 return GL_FALSE;
189 }
190 if (ioctl(fd, VT_OPENQRY, &vtnumber) < 0 || vtnumber < 0) {
191 fprintf(stderr, "error: couldn't get a free vt\n");
192 return GL_FALSE;
193 }
194
195 fprintf(stderr, "*** got vt nr: %d\n", vtnumber);
196 close(fd);
197
198 /* open the console tty */
199 sprintf(ttystr, "/dev/tty%d", vtnumber); /* /dev/tty1-64 */
200 dpy->ConsoleFD = open(ttystr, O_RDWR | O_NDELAY, 0);
201 if (dpy->ConsoleFD < 0) {
202 fprintf(stderr, "error couldn't open console fd\n");
203 return GL_FALSE;
204 }
205
206 /* save current vt number */
207 {
208 struct vt_stat vts;
209 if (ioctl(dpy->ConsoleFD, VT_GETSTATE, &vts) == 0)
210 dpy->OriginalVT = vts.v_active;
211 }
212
213 /* disconnect from controlling tty */
214 ttyfd = open("/dev/tty", O_RDWR);
215 if (ttyfd >= 0) {
216 ioctl(ttyfd, TIOCNOTTY, 0);
217 close(ttyfd);
218 }
219
220 /* some magic to restore the vt when we exit */
221 {
222 struct vt_mode vt;
223 struct sigaction sig_tty;
224
225 /* Set-up tty signal handler to catch the signal we request below */
226 SignalDisplay = dpy;
227 memset( &sig_tty, 0, sizeof( sig_tty ) );
228 sig_tty.sa_handler = SwitchVT;
229 sigemptyset( &sig_tty.sa_mask );
230 if( sigaction( SIGUSR1, &sig_tty, &dpy->OrigSigUsr1 ) ||
231 sigaction( SIGUSR2, &sig_tty, &dpy->OrigSigUsr2 ) )
232 {
233 fprintf(stderr, "error: can't set up signal handler (%s)",
234 strerror(errno) );
235 return GL_FALSE;
236 }
237
238
239
240 vt.mode = VT_PROCESS;
241 vt.waitv = 0;
242 vt.relsig = SIGUSR1;
243 vt.acqsig = SIGUSR2;
244 if (ioctl(dpy->ConsoleFD, VT_SETMODE, &vt) < 0) {
245 fprintf(stderr, "error: ioctl(VT_SETMODE) failed: %s\n",
246 strerror(errno));
247 return GL_FALSE;
248 }
249
250
251 if (ioctl(dpy->ConsoleFD, VT_ACTIVATE, vtnumber) != 0)
252 printf("ioctl VT_ACTIVATE: %s\n", strerror(errno));
253 if (ioctl(dpy->ConsoleFD, VT_WAITACTIVE, vtnumber) != 0)
254 printf("ioctl VT_WAITACTIVE: %s\n", strerror(errno));
255
256 if (ioctl(dpy->ConsoleFD, VT_GETMODE, &vt) < 0) {
257 fprintf(stderr, "error: ioctl VT_GETMODE: %s\n", strerror(errno));
258 return GL_FALSE;
259 }
260
261
262
263 }
264
265 /* go into graphics mode */
266 if (ioctl(dpy->ConsoleFD, KDSETMODE, KD_GRAPHICS) < 0) {
267 fprintf(stderr, "error: ioctl(KDSETMODE, KD_GRAPHICS) failed: %s\n",
268 strerror(errno));
269 return GL_FALSE;
270 }
271 }
272
273 /* open the framebuffer device */
274 dpy->FrameBufferFD = open(dpy->fbdevDevice, O_RDWR);
275 if (dpy->FrameBufferFD < 0) {
276 fprintf(stderr, "Error opening /dev/fb0: %s\n", strerror(errno));
277 return GL_FALSE;
278 }
279
280 /* get the original variable screen info */
281 if (ioctl(dpy->FrameBufferFD, FBIOGET_VSCREENINFO, &dpy->OrigVarInfo)) {
282 fprintf(stderr, "error: ioctl(FBIOGET_VSCREENINFO) failed: %s\n",
283 strerror(errno));
284 return GL_FALSE;
285 }
286
287 /* make copy */
288 dpy->VarInfo = dpy->OrigVarInfo; /* structure copy */
289
290 /* Turn off hw accels (otherwise mmap of mmio region will be
291 * refused)
292 */
293 dpy->VarInfo.accel_flags = 0;
294 if (ioctl(dpy->FrameBufferFD, FBIOPUT_VSCREENINFO, &dpy->VarInfo)) {
295 fprintf(stderr, "error: ioctl(FBIOPUT_VSCREENINFO) failed: %s\n",
296 strerror(errno));
297 return GL_FALSE;
298 }
299
300
301
302 /* Get the fixed screen info */
303 if (ioctl(dpy->FrameBufferFD, FBIOGET_FSCREENINFO, &dpy->FixedInfo)) {
304 fprintf(stderr, "error: ioctl(FBIOGET_FSCREENINFO) failed: %s\n",
305 strerror(errno));
306 return GL_FALSE;
307 }
308
309
310
311 /* mmap the framebuffer into our address space */
312 dpy->driverContext.FBStart = dpy->FixedInfo.smem_start;
313 dpy->driverContext.FBSize = dpy->FixedInfo.smem_len;
314 dpy->driverContext.shared.fbSize = dpy->FixedInfo.smem_len;
315 dpy->driverContext.FBAddress = (caddr_t) mmap(0, /* start */
316 dpy->driverContext.shared.fbSize, /* bytes */
317 PROT_READ | PROT_WRITE, /* prot */
318 MAP_SHARED, /* flags */
319 dpy->FrameBufferFD, /* fd */
320 0 /* offset */);
321 if (dpy->driverContext.FBAddress == (caddr_t) - 1) {
322 fprintf(stderr, "error: unable to mmap framebuffer: %s\n",
323 strerror(errno));
324 return GL_FALSE;
325 }
326
327 /* mmap the MMIO region into our address space */
328 dpy->driverContext.MMIOStart = dpy->FixedInfo.mmio_start;
329 dpy->driverContext.MMIOSize = dpy->FixedInfo.mmio_len;
330 dpy->driverContext.MMIOAddress = (caddr_t) mmap(0, /* start */
331 dpy->driverContext.MMIOSize, /* bytes */
332 PROT_READ | PROT_WRITE, /* prot */
333 MAP_SHARED, /* flags */
334 dpy->FrameBufferFD, /* fd */
335 dpy->FixedInfo.smem_len /* offset */);
336 if (dpy->driverContext.MMIOAddress == (caddr_t) - 1) {
337 fprintf(stderr, "error: unable to mmap mmio region: %s\n",
338 strerror(errno));
339 return GL_FALSE;
340 }
341
342 fprintf(stderr, "got MMIOAddress %p offset %d\n",
343 dpy->driverContext.MMIOAddress,
344 dpy->FixedInfo.smem_len);
345
346 return GL_TRUE;
347 }
348
349
350
351
352 /**
353 * \brief Setup up the desired framebuffer device mode.
354 *
355 * \param dpy the display handle.
356 *
357 * \return GL_TRUE on success, or GL_FALSE on failure.
358 *
359 * \sa This is called during __miniglx_StartServer().
360 *
361 * \internal
362 *
363 * Bumps the size of the window the the next supported mode. Sets the
364 * variable screen information according to the desired mode and asks
365 * the driver to validate the mode. Certifies that a DirectColor or
366 * TrueColor visual is used from the updated fixed screen information.
367 * In the case of DirectColor visuals, sets up an 'identity' colormap to
368 * mimic a TrueColor visual.
369 *
370 * Calls the driver hooks 'ValidateMode' and 'PostValidateMode' to
371 * allow the driver to make modifications to the chosen mode according
372 * to hardware constraints, or to save and restore videocard registers
373 * that may be clobbered by the fbdev driver.
374 *
375 * \todo Timings are hard-coded in the source for a set of supported modes.
376 */
377 static GLboolean
378 SetupFBDev( Display *dpy )
379 {
380 int width, height;
381
382 assert(dpy);
383
384 width = dpy->driverContext.shared.virtualWidth;
385 height = dpy->driverContext.shared.virtualHeight;
386
387 /* Bump size up to next supported mode.
388 */
389 if (width <= 800 && height <= 600) {
390 width = 800; height = 600;
391 }
392 else if (width <= 1024 && height <= 768) {
393 width = 1024; height = 768;
394 }
395 else if (width <= 768 && height <= 1024) {
396 width = 768; height = 1024;
397 }
398 else if (width <= 1280 && height <= 1024) {
399 width = 1280; height = 1024;
400 }
401
402
403 dpy->driverContext.shared.virtualHeight = height;
404 dpy->driverContext.shared.virtualWidth = width;
405 dpy->driverContext.shared.fbStride = width * (dpy->driverContext.bpp / 8);
406
407 /* set the depth, resolution, etc */
408 dpy->VarInfo = dpy->OrigVarInfo;
409 dpy->VarInfo.bits_per_pixel = dpy->driverContext.bpp;
410 dpy->VarInfo.xres_virtual = dpy->driverContext.shared.virtualWidth;
411 dpy->VarInfo.yres_virtual = dpy->driverContext.shared.virtualHeight;
412 dpy->VarInfo.xres = width;
413 dpy->VarInfo.yres = height;
414 dpy->VarInfo.xoffset = 0;
415 dpy->VarInfo.yoffset = 0;
416 dpy->VarInfo.nonstd = 0;
417 dpy->VarInfo.vmode &= ~FB_VMODE_YWRAP; /* turn off scrolling */
418
419 if (dpy->VarInfo.bits_per_pixel == 32) {
420 dpy->VarInfo.red.offset = 16;
421 dpy->VarInfo.green.offset = 8;
422 dpy->VarInfo.blue.offset = 0;
423 dpy->VarInfo.transp.offset = 24;
424 dpy->VarInfo.red.length = 8;
425 dpy->VarInfo.green.length = 8;
426 dpy->VarInfo.blue.length = 8;
427 dpy->VarInfo.transp.length = 8;
428 }
429 else if (dpy->VarInfo.bits_per_pixel == 16) {
430 dpy->VarInfo.red.offset = 11;
431 dpy->VarInfo.green.offset = 5;
432 dpy->VarInfo.blue.offset = 0;
433 dpy->VarInfo.red.length = 5;
434 dpy->VarInfo.green.length = 6;
435 dpy->VarInfo.blue.length = 5;
436 dpy->VarInfo.transp.offset = 0;
437 dpy->VarInfo.transp.length = 0;
438 }
439 else {
440 fprintf(stderr, "Only 32bpp and 16bpp modes supported at the moment\n");
441 return 0;
442 }
443
444 if (!dpy->driver->validateMode( &dpy->driverContext )) {
445 fprintf(stderr, "Driver validateMode() failed\n");
446 return 0;
447 }
448
449 if (dpy->VarInfo.xres == 1280 &&
450 dpy->VarInfo.yres == 1024) {
451 /* timing values taken from /etc/fb.modes (1280x1024 @ 75Hz) */
452 dpy->VarInfo.pixclock = 7408;
453 dpy->VarInfo.left_margin = 248;
454 dpy->VarInfo.right_margin = 16;
455 dpy->VarInfo.upper_margin = 38;
456 dpy->VarInfo.lower_margin = 1;
457 dpy->VarInfo.hsync_len = 144;
458 dpy->VarInfo.vsync_len = 3;
459 }
460 else if (dpy->VarInfo.xres == 1024 &&
461 dpy->VarInfo.yres == 768) {
462 /* timing values taken from /etc/fb.modes (1024x768 @ 75Hz) */
463 dpy->VarInfo.pixclock = 12699;
464 dpy->VarInfo.left_margin = 176;
465 dpy->VarInfo.right_margin = 16;
466 dpy->VarInfo.upper_margin = 28;
467 dpy->VarInfo.lower_margin = 1;
468 dpy->VarInfo.hsync_len = 96;
469 dpy->VarInfo.vsync_len = 3;
470 }
471 else if (dpy->VarInfo.xres == 800 &&
472 dpy->VarInfo.yres == 600) {
473 /* timing values taken from /etc/fb.modes (800x600 @ 75Hz) */
474 dpy->VarInfo.pixclock = 20203;
475 dpy->VarInfo.left_margin = 160;
476 dpy->VarInfo.right_margin = 16;
477 dpy->VarInfo.upper_margin = 21;
478 dpy->VarInfo.lower_margin = 1;
479 dpy->VarInfo.hsync_len = 80;
480 dpy->VarInfo.vsync_len = 3;
481 }
482 else if (dpy->VarInfo.xres == 768 &&
483 dpy->VarInfo.yres == 1024) {
484 /* timing values for 768x1024 @ 75Hz */
485 dpy->VarInfo.pixclock = 11993;
486 dpy->VarInfo.left_margin = 136;
487 dpy->VarInfo.right_margin = 32;
488 dpy->VarInfo.upper_margin = 41;
489 dpy->VarInfo.lower_margin = 1;
490 dpy->VarInfo.hsync_len = 80;
491 dpy->VarInfo.vsync_len = 3;
492 }
493 else {
494 /* XXX need timings for other screen sizes */
495 fprintf(stderr, "XXXX screen size %d x %d not supported at this time!\n",
496 dpy->VarInfo.xres, dpy->VarInfo.yres);
497 return GL_FALSE;
498 }
499
500 fprintf(stderr, "[miniglx] Setting mode: visible %dx%d virtual %dx%dx%d\n",
501 dpy->VarInfo.xres, dpy->VarInfo.yres,
502 dpy->VarInfo.xres_virtual, dpy->VarInfo.yres_virtual,
503 dpy->VarInfo.bits_per_pixel);
504
505 /* set variable screen info */
506 if (ioctl(dpy->FrameBufferFD, FBIOPUT_VSCREENINFO, &dpy->VarInfo)) {
507 fprintf(stderr, "error: ioctl(FBIOPUT_VSCREENINFO) failed: %s\n",
508 strerror(errno));
509 return GL_FALSE;
510 }
511
512 /* get the variable screen info, in case it has been modified */
513 if (ioctl(dpy->FrameBufferFD, FBIOGET_VSCREENINFO, &dpy->VarInfo)) {
514 fprintf(stderr, "error: ioctl(FBIOGET_VSCREENINFO) failed: %s\n",
515 strerror(errno));
516 return GL_FALSE;
517 }
518
519
520 fprintf(stderr, "[miniglx] Readback mode: visible %dx%d virtual %dx%dx%d\n",
521 dpy->VarInfo.xres, dpy->VarInfo.yres,
522 dpy->VarInfo.xres_virtual, dpy->VarInfo.yres_virtual,
523 dpy->VarInfo.bits_per_pixel);
524
525 /* Get the fixed screen info */
526 if (ioctl(dpy->FrameBufferFD, FBIOGET_FSCREENINFO, &dpy->FixedInfo)) {
527 fprintf(stderr, "error: ioctl(FBIOGET_FSCREENINFO) failed: %s\n",
528 strerror(errno));
529 return GL_FALSE;
530 }
531
532 if (dpy->FixedInfo.visual != FB_VISUAL_TRUECOLOR &&
533 dpy->FixedInfo.visual != FB_VISUAL_DIRECTCOLOR) {
534 fprintf(stderr, "non-TRUECOLOR visuals not supported.\n");
535 return GL_FALSE;
536 }
537
538 if (dpy->FixedInfo.visual == FB_VISUAL_DIRECTCOLOR) {
539 struct fb_cmap cmap;
540 unsigned short red[256], green[256], blue[256];
541 int rcols = 1 << dpy->VarInfo.red.length;
542 int gcols = 1 << dpy->VarInfo.green.length;
543 int bcols = 1 << dpy->VarInfo.blue.length;
544 int i;
545
546 cmap.start = 0;
547 cmap.len = gcols;
548 cmap.red = red;
549 cmap.green = green;
550 cmap.blue = blue;
551 cmap.transp = NULL;
552
553 for (i = 0; i < rcols ; i++)
554 red[i] = (65536/(rcols-1)) * i;
555
556 for (i = 0; i < gcols ; i++)
557 green[i] = (65536/(gcols-1)) * i;
558
559 for (i = 0; i < bcols ; i++)
560 blue[i] = (65536/(bcols-1)) * i;
561
562 if (ioctl(dpy->FrameBufferFD, FBIOPUTCMAP, (void *) &cmap) < 0) {
563 fprintf(stderr, "ioctl(FBIOPUTCMAP) failed [%d]\n", i);
564 exit(1);
565 }
566 }
567
568 /* May need to restore regs fbdev has clobbered:
569 */
570 if (!dpy->driver->postValidateMode( &dpy->driverContext )) {
571 fprintf(stderr, "Driver postValidateMode() failed\n");
572 return 0;
573 }
574
575 return GL_TRUE;
576 }
577
578
579 /**
580 * \brief Restore the framebuffer device to state it was in before we started
581 *
582 * Undoes the work done by SetupFBDev().
583 *
584 * \param dpy the display handle.
585 *
586 * \return GL_TRUE on success, or GL_FALSE on failure.
587 *
588 * \sa Called from XDestroyWindow().
589 *
590 * \internal
591 * Restores the original variable screen info.
592 */
593 static GLboolean
594 RestoreFBDev( Display *dpy )
595 {
596 /* restore original variable screen info */
597 if (ioctl(dpy->FrameBufferFD, FBIOPUT_VSCREENINFO, &dpy->OrigVarInfo)) {
598 fprintf(stderr, "ioctl(FBIOPUT_VSCREENINFO failed): %s\n",
599 strerror(errno));
600 return GL_FALSE;
601 }
602 dpy->VarInfo = dpy->OrigVarInfo;
603
604 return GL_TRUE;
605 }
606
607
608 /**
609 * \brief Close the framebuffer device.
610 *
611 * \param dpy the display handle.
612 *
613 * \sa Called from XCloseDisplay().
614 *
615 * \internal
616 * Unmaps the framebuffer and MMIO region. Restores the text mode and the
617 * original virtual terminal. Closes the console and framebuffer devices.
618 */
619 static void
620 CloseFBDev( Display *dpy )
621 {
622 struct vt_mode VT;
623
624 munmap(dpy->driverContext.FBAddress, dpy->driverContext.FBSize);
625 munmap(dpy->driverContext.MMIOAddress, dpy->driverContext.MMIOSize);
626
627 if (dpy->ConsoleFD) {
628 /* restore text mode */
629 ioctl(dpy->ConsoleFD, KDSETMODE, KD_TEXT);
630
631 /* set vt */
632 if (ioctl(dpy->ConsoleFD, VT_GETMODE, &VT) != -1) {
633 VT.mode = VT_AUTO;
634 ioctl(dpy->ConsoleFD, VT_SETMODE, &VT);
635 }
636
637 /* restore original vt */
638 if (dpy->OriginalVT >= 0) {
639 ioctl(dpy->ConsoleFD, VT_ACTIVATE, dpy->OriginalVT);
640 dpy->OriginalVT = -1;
641 }
642
643 close(dpy->ConsoleFD);
644 }
645 close(dpy->FrameBufferFD);
646 }
647
648 /*@}*/
649
650
651 /**********************************************************************/
652 /** \name Misc functions needed for DRI drivers */
653 /**********************************************************************/
654 /*@{*/
655
656 /**
657 * \brief Find the DRI screen dependent methods associated with the display.
658 *
659 * \param dpy a display handle, as returned by XOpenDisplay().
660 * \param scrn the screen number. Not referenced.
661 *
662 * \returns a pointer to a __DRIscreenRec structure.
663 *
664 * \internal
665 * Returns the MiniGLXDisplayRec::driScreen attribute.
666 */
667 __DRIscreen *
668 __glXFindDRIScreen(Display *dpy, int scrn)
669 {
670 (void) scrn;
671 return dpy->driScreen;
672 }
673
674 /**
675 * \brief Validate a drawable.
676 *
677 * \param dpy a display handle, as returned by XOpenDisplay().
678 * \param draw drawable to validate.
679 *
680 * \internal
681 * Since Mini GLX only supports one window, compares the specified drawable with
682 * the MiniGLXDisplayRec::TheWindow attribute.
683 */
684 Bool
685 __glXWindowExists(Display *dpy, GLXDrawable draw)
686 {
687 if (dpy->TheWindow == draw)
688 return True;
689 else
690 return False;
691 }
692
693 /**
694 * \brief Get current thread ID.
695 *
696 * \return thread ID.
697 *
698 * \internal
699 * Always returns 0.
700 */
701 /*unsigned long
702 _glthread_GetID(void)
703 {
704 return 0;
705 }*/
706
707 /*@}*/
708
709
710 /**
711 * \brief Scan Linux /prog/bus/pci/devices file to determine hardware
712 * chipset based on supplied bus ID.
713 *
714 * \return probed chipset (non-zero) on success, zero otherwise.
715 *
716 * \internal
717 */
718 static int get_chipset_from_busid( Display *dpy )
719 {
720 char buf[0x200];
721 FILE *file;
722 const char *fname = "/proc/bus/pci/devices";
723 int retval = 0;
724
725 if (!(file = fopen(fname,"r"))) {
726 fprintf(stderr, "couldn't open %s: %s\n", fname, strerror(errno));
727 return 0;
728 }
729
730 while (fgets(buf, sizeof(buf)-1, file)) {
731 unsigned int nr, bus, dev, fn, vendor, device, encode;
732 nr = sscanf(buf, "%04x\t%04x%04x", &encode,
733 &vendor, &device);
734
735 bus = encode >> 8;
736 dev = (encode & 0xFF) >> 3;
737 fn = encode & 0x7;
738
739 if (nr != 3)
740 break;
741
742 if (bus == dpy->driverContext.pciBus &&
743 dev == dpy->driverContext.pciDevice &&
744 fn == dpy->driverContext.pciFunc) {
745 retval = device;
746 break;
747 }
748 }
749
750 fclose(file);
751
752 if (retval)
753 fprintf(stderr, "[miniglx] probed chipset 0x%x\n", retval);
754 else
755 fprintf(stderr, "[miniglx] failed to probe chipset\n");
756
757 return retval;
758 }
759
760
761 /**
762 * \brief Read settings from a configuration file.
763 *
764 * The configuration file is usually "/etc/miniglx.conf", but can be overridden
765 * with the MINIGLX_CONF environment variable.
766 *
767 * The format consists in \code option = value \endcode lines. The option names
768 * corresponds to the fields in MiniGLXDisplayRec.
769 *
770 * \param dpy the display handle as.
771 *
772 * \return non-zero on success, zero otherwise.
773 *
774 * \internal
775 * Sets some defaults. Opens and parses the the Mini GLX configuration file and
776 * fills in the MiniGLXDisplayRec field that corresponds for each option.
777 */
778 static int __read_config_file( Display *dpy )
779 {
780 FILE *file;
781 const char *fname;
782
783 /* Fallback/defaults
784 */
785 dpy->fbdevDevice = "/dev/fb0";
786 dpy->clientDriverName = "fb_dri.so";
787 dpy->driverContext.pciBus = 0;
788 dpy->driverContext.pciDevice = 0;
789 dpy->driverContext.pciFunc = 0;
790 dpy->driverContext.chipset = 0;
791 dpy->driverContext.pciBusID = 0;
792 dpy->driverContext.shared.virtualWidth = 1280;
793 dpy->driverContext.shared.virtualHeight = 1024;
794 dpy->driverContext.bpp = 32;
795 dpy->driverContext.cpp = 4;
796 dpy->rotateMode = 0;
797
798 fname = getenv("MINIGLX_CONF");
799 if (!fname) fname = "/etc/miniglx.conf";
800
801 file = fopen(fname, "r");
802 if (!file) {
803 fprintf(stderr, "couldn't open config file %s: %s\n", fname, strerror(errno));
804 return 0;
805 }
806
807
808 while (!feof(file)) {
809 char buf[81], *opt = buf, *val, *tmp1, *tmp2;
810 fgets(buf, sizeof(buf), file);
811
812 /* Parse 'opt = val' -- must be easier ways to do this.
813 */
814 while (isspace(*opt)) opt++;
815 val = opt;
816 if (*val == '#') continue; /* comment */
817 while (!isspace(*val) && *val != '=' && *val) val++;
818 tmp1 = val;
819 while (isspace(*val)) val++;
820 if (*val != '=') continue;
821 *tmp1 = 0;
822 val++;
823 while (isspace(*val)) val++;
824 tmp2 = val;
825 while (!isspace(*tmp2) && *tmp2 != '\n' && *tmp2) tmp2++;
826 *tmp2 = 0;
827
828
829 if (strcmp(opt, "fbdevDevice") == 0)
830 dpy->fbdevDevice = strdup(val);
831 else if (strcmp(opt, "clientDriverName") == 0)
832 dpy->clientDriverName = strdup(val);
833 else if (strcmp(opt, "rotateMode") == 0)
834 dpy->rotateMode = atoi(val) ? 1 : 0;
835 else if (strcmp(opt, "pciBusID") == 0) {
836 if (sscanf(val, "PCI:%d:%d:%d",
837 &dpy->driverContext.pciBus,
838 &dpy->driverContext.pciDevice,
839 &dpy->driverContext.pciFunc) != 3) {
840 fprintf(stderr, "malformed bus id: %s\n", val);
841 continue;
842 }
843 dpy->driverContext.pciBusID = strdup(val);
844 }
845 else if (strcmp(opt, "chipset") == 0) {
846 if (sscanf(val, "0x%x", &dpy->driverContext.chipset) != 1)
847 fprintf(stderr, "malformed chipset: %s\n", opt);
848 }
849 else if (strcmp(opt, "virtualWidth") == 0) {
850 if (sscanf(val, "%d", &dpy->driverContext.shared.virtualWidth) != 1)
851 fprintf(stderr, "malformed virtualWidth: %s\n", opt);
852 }
853 else if (strcmp(opt, "virtualHeight") == 0) {
854 if (sscanf(val, "%d", &dpy->driverContext.shared.virtualHeight) != 1)
855 fprintf(stderr, "malformed virutalHeight: %s\n", opt);
856 }
857 else if (strcmp(opt, "bpp") == 0) {
858 if (sscanf(val, "%d", &dpy->driverContext.bpp) != 1)
859 fprintf(stderr, "malformed bpp: %s\n", opt);
860 dpy->driverContext.cpp = dpy->driverContext.bpp / 8;
861 }
862 }
863
864 fclose(file);
865
866 if (dpy->driverContext.chipset == 0 && dpy->driverContext.pciBusID != 0)
867 dpy->driverContext.chipset = get_chipset_from_busid( dpy );
868
869 return 1;
870 }
871
872 static int InitDriver( Display *dpy )
873 {
874 /*
875 * Begin DRI setup.
876 * We're kind of combining the per-display and per-screen information
877 * which was kept separate in XFree86/DRI's libGL.
878 */
879 dpy->dlHandle = dlopen(dpy->clientDriverName, RTLD_NOW | RTLD_GLOBAL);
880 if (!dpy->dlHandle) {
881 fprintf(stderr, "Unable to open %s: %s\n", dpy->clientDriverName,
882 dlerror());
883 return GL_FALSE;
884 }
885
886 /* Pull in Mini GLX specific hooks:
887 */
888 dpy->driver = (struct DRIDriverRec *) dlsym(dpy->dlHandle,
889 "__driDriver");
890 if (!dpy->driver) {
891 fprintf(stderr, "Couldn't find __driDriver in %s\n",
892 dpy->clientDriverName);
893 dlclose(dpy->dlHandle);
894 return GL_FALSE;
895 }
896
897 /* Pull in standard DRI client-side driver hooks:
898 */
899 dpy->createScreen = (driCreateScreenFunc*) dlsym(dpy->dlHandle,
900 "__driCreateScreen");
901 if (!dpy->createScreen) {
902 fprintf(stderr, "Couldn't find __driCreateScreen in %s\n",
903 dpy->clientDriverName);
904 dlclose(dpy->dlHandle);
905 return GL_FALSE;
906 }
907
908 return GL_TRUE;
909 }
910
911
912 /**********************************************************************/
913 /** \name Public API functions (Xlib and GLX) */
914 /**********************************************************************/
915 /*@{*/
916
917
918 /**
919 * \brief Initialize the graphics system.
920 *
921 * \param display_name currently ignored. It is recommended to pass it as NULL.
922 * \return a pointer to a #Display if the function is able to initialize
923 * the graphics system, NULL otherwise.
924 *
925 * Allocates a MiniGLXDisplayRec structure and fills in with information from a
926 * configuration file.
927 *
928 * Calls OpenFBDev() to open the framebuffer device and calls
929 * DRIDriverRec::initFBDev to do the client-side initialization on it.
930 *
931 * Loads the DRI driver and pulls in Mini GLX specific hooks into a
932 * DRIDriverRec structure, and the standard DRI \e __driCreateScreen hook.
933 * Asks the driver for a list of supported visuals. Performs the per-screen
934 * client-side initialization. Also setups the callbacks in the screen private
935 * information.
936 *
937 * Does the framebuffer device setup. Calls __miniglx_open_connections() to
938 * serve clients.
939 */
940 Display *
941 __miniglx_StartServer( const char *display_name )
942 {
943 Display *dpy;
944 int use_vt = 0;
945
946 dpy = (Display *)calloc(1, sizeof(Display));
947 if (!dpy)
948 return NULL;
949
950 dpy->IsClient = False;
951
952 if (!__read_config_file( dpy )) {
953 fprintf(stderr, "Couldn't get configuration details\n");
954 free(dpy);
955 return NULL;
956 }
957
958 /* Open the fbdev device
959 */
960 if (!OpenFBDev(dpy, use_vt)) {
961 fprintf(stderr, "OpenFBDev failed\n");
962 free(dpy);
963 return NULL;
964 }
965
966 if (!InitDriver(dpy)) {
967 fprintf(stderr, "InitDriver failed\n");
968 free(dpy);
969 return NULL;
970 }
971
972 /* Ask the driver for a list of supported configs:
973 */
974 dpy->driver->initContextModes( &dpy->driverContext, &dpy->numModes, &dpy->modes );
975
976 /* Perform the initialization normally done in the X server
977 */
978 if (!dpy->driver->initFBDev( &dpy->driverContext )) {
979 fprintf(stderr, "%s: __driInitFBDev failed\n", __FUNCTION__);
980 dlclose(dpy->dlHandle);
981 return GL_FALSE;
982 }
983
984 /* do fbdev setup
985 */
986 if (!SetupFBDev(dpy)) {
987 fprintf(stderr, "SetupFBDev failed\n");
988 free(dpy);
989 return NULL;
990 }
991
992 /* unlock here if not using VT -- JDS */
993 if (!use_vt) {
994 if (dpy->driver->restoreHardware)
995 dpy->driver->restoreHardware( &dpy->driverContext );
996 DRM_UNLOCK( dpy->driverContext.drmFD,
997 dpy->driverContext.pSAREA,
998 dpy->driverContext.serverContext );
999 dpy->hwActive = 1;
1000 }
1001
1002 /* Ready for clients:
1003 */
1004 if (!__miniglx_open_connections(dpy)) {
1005 free(dpy);
1006 return NULL;
1007 }
1008
1009 return dpy;
1010 }
1011
1012
1013 /**
1014 * \brief Initialize the graphics system.
1015 *
1016 * \param display_name currently ignored. It is recommended to pass it as NULL.
1017 * \return a pointer to a #Display if the function is able to initialize
1018 * the graphics system, NULL otherwise.
1019 *
1020 * Allocates a MiniGLXDisplayRec structure and fills in with information from a
1021 * configuration file.
1022 *
1023 * Calls __miniglx_open_connections() to connect to the server.
1024 *
1025 * Loads the DRI driver and pulls in Mini GLX specific hooks into a
1026 * DRIDriverRec structure, and the standard DRI \e __driCreateScreen hook.
1027 * Asks the driver for a list of supported visuals. Performs the per-screen
1028 * client-side initialization. Also setups the callbacks in the screen private
1029 * information.
1030 *
1031 * \todo
1032 * - read config file
1033 * - what about virtualWidth, etc?
1034 * - determine dpy->driverClientMsgSize,
1035 * - allocate dpy->driverClientMsg
1036 */
1037 Display *
1038 XOpenDisplay( const char *display_name )
1039 {
1040 Display *dpy;
1041
1042 dpy = (Display *)calloc(1, sizeof(Display));
1043 if (!dpy)
1044 return NULL;
1045
1046 dpy->IsClient = True;
1047
1048 /* read config file
1049 */
1050 if (!__read_config_file( dpy )) {
1051 fprintf(stderr, "Couldn't get configuration details\n");
1052 free(dpy);
1053 return NULL;
1054 }
1055
1056 /* Connect to the server and receive driverClientMsg
1057 */
1058 if (!__miniglx_open_connections(dpy)) {
1059 free(dpy);
1060 return NULL;
1061 }
1062
1063 /* dlopen the driver .so file
1064 */
1065 if (!InitDriver(dpy)) {
1066 fprintf(stderr, "InitDriver failed\n");
1067 free(dpy);
1068 return NULL;
1069 }
1070
1071 /* Ask the driver for a list of supported configs:
1072 */
1073 dpy->driver->initContextModes( &dpy->driverContext, &dpy->numModes, &dpy->modes );
1074
1075 /* Perform the client-side initialization.
1076 *
1077 * Clearly there is a limit of one on the number of windows in
1078 * existence at any time.
1079 *
1080 * Need to shut down DRM and free DRI data in XDestroyWindow(), too.
1081 */
1082 dpy->driScreen = (*dpy->createScreen)(dpy->driver,
1083 &dpy->driverContext);
1084 if (!dpy->driScreen) {
1085 fprintf(stderr, "%s: __driCreateScreen failed\n", __FUNCTION__);
1086 dlclose(dpy->dlHandle);
1087 free(dpy);
1088 return NULL;
1089 }
1090
1091 /* Anything more to do?
1092 */
1093 return dpy;
1094 }
1095
1096
1097 /**
1098 * \brief Release display resources.
1099 *
1100 * When the application is about to exit, the resources associated with the
1101 * graphics system can be released by calling this function.
1102 *
1103 * \param dpy display handle. It becomes invalid at this point.
1104 *
1105 * Destroys the window if any, and destroys the per-screen
1106 * driver private information.
1107 * Calls __miniglx_close_connections().
1108 *
1109 * If a server, puts the the framebuffer back into the initial state.
1110 *
1111 * Finally frees the display structure.
1112 */
1113 void
1114 XCloseDisplay( Display *dpy )
1115 {
1116 glXMakeCurrent( dpy, NULL, NULL);
1117
1118 if (dpy->NumWindows)
1119 XDestroyWindow( dpy, dpy->TheWindow );
1120
1121 /* As this is done in XOpenDisplay, need to undo it here:
1122 */
1123 (*dpy->driScreen->destroyScreen)(dpy->driScreen);
1124
1125 __miniglx_close_connections( dpy );
1126
1127 if (!dpy->IsClient) {
1128 /* put framebuffer back to initial state
1129 */
1130 (*dpy->driver->haltFBDev)( &dpy->driverContext );
1131 RestoreFBDev(dpy);
1132 CloseFBDev(dpy);
1133 }
1134
1135 dlclose(dpy->dlHandle);
1136 free(dpy);
1137 }
1138
1139
1140 /**
1141 * \brief Window creation.
1142 *
1143 * \param display a display handle, as returned by XOpenDisplay().
1144 * \param parent the parent window for the new window. For Mini GLX this should
1145 * be
1146 * \code RootWindow(display, 0) \endcode
1147 * \param x the window abscissa. For Mini GLX, it should be zero.
1148 * \param y the window ordinate. For Mini GLX, it should be zero.
1149 * \param width the window width. For Mini GLX, this specifies the desired
1150 * screen width such as 1024 or 1280.
1151 * \param height the window height. For Mini GLX, this specifies the desired
1152 * screen height such as 768 or 1024.
1153 * \param border_width the border width. For Mini GLX, it should be zero.
1154 * \param depth the window pixel depth. For Mini GLX, this should be the depth
1155 * found in the #XVisualInfo object returned by glXChooseVisual()
1156 * \param class the window class. For Mini GLX this value should be
1157 * #InputOutput.
1158 * \param visual the visual type. It should be the visual field of the
1159 * #XVisualInfo object returned by glXChooseVisual().
1160 * \param valuemask which fields of the XSetWindowAttributes() are to be used.
1161 * For Mini GLX this is typically the bitmask
1162 * \code CWBackPixel | CWBorderPixel | CWColormap \endcode
1163 * \param attributes initial window attributes. The
1164 * XSetWindowAttributes::background_pixel, XSetWindowAttributes::border_pixel
1165 * and XSetWindowAttributes::colormap fields should be set.
1166 *
1167 * \return a window handle if it succeeds or zero if it fails.
1168 *
1169 * \note For Mini GLX, windows are full-screen; they cover the entire frame
1170 * buffer. Also, Mini GLX imposes a limit of one window. A second window
1171 * cannot be created until the first one is destroyed.
1172 *
1173 * This function creates and initializes a ::MiniGLXWindowRec structure after
1174 * ensuring that there is no other window created. Performs the per-drawable
1175 * client-side initialization calling the __DRIscreenRec::createDrawable
1176 * method.
1177 *
1178 */
1179 Window
1180 XCreateWindow( Display *dpy, Window parent, int x, int y,
1181 unsigned int width, unsigned int height,
1182 unsigned int border_width, int depth, unsigned int class,
1183 Visual *visual, unsigned long valuemask,
1184 XSetWindowAttributes *attributes )
1185 {
1186 Window win;
1187
1188 /* ignored */
1189 (void) x;
1190 (void) y;
1191 (void) border_width;
1192 (void) depth;
1193 (void) class;
1194 (void) valuemask;
1195 (void) attributes;
1196
1197 if (!dpy->IsClient) {
1198 fprintf(stderr, "Server process may not create windows (currently)\n");
1199 return NULL;
1200 }
1201
1202 if (dpy->NumWindows > 0)
1203 return NULL; /* only allow one window */
1204
1205 assert(dpy->TheWindow == NULL);
1206
1207 win = malloc(sizeof(struct MiniGLXWindowRec));
1208 if (!win)
1209 return NULL;
1210
1211 /* In rotated mode, translate incoming x,y,width,height into
1212 * 'normal' coordinates.
1213 */
1214 if (dpy->rotateMode) {
1215 int tmp;
1216 tmp = width; width = height; height = tmp;
1217 tmp = x; x = y; y = tmp;
1218 }
1219
1220 /* init other per-window fields */
1221 win->x = 0;
1222 win->y = 0;
1223 win->w = width;
1224 win->h = height;
1225 win->visual = visual; /* ptr assignment */
1226
1227 win->bytesPerPixel = dpy->driverContext.cpp;
1228 win->rowStride = dpy->driverContext.shared.virtualWidth * win->bytesPerPixel;
1229 win->size = win->rowStride * height;
1230 win->frontStart = dpy->driverContext.FBAddress;
1231 win->frontBottom = (GLubyte *) win->frontStart + (height-1) * win->rowStride;
1232
1233 /* This is incorrect: the hardware driver could put the backbuffer
1234 * just about anywhere. These fields, including the above are
1235 * hardware dependent & don't really belong here.
1236 */
1237 if (visual->mode->doubleBufferMode) {
1238 win->backStart = (GLubyte *) win->frontStart +
1239 win->rowStride * dpy->driverContext.shared.virtualHeight;
1240 win->backBottom = (GLubyte *) win->backStart
1241 + (height - 1) * win->rowStride;
1242 win->curBottom = win->backBottom;
1243 }
1244 else {
1245 /* single buffered */
1246 win->backStart = NULL;
1247 win->backBottom = NULL;
1248 win->curBottom = win->frontBottom;
1249 }
1250
1251 win->driDrawable = dpy->driScreen->createDrawable(dpy->driScreen,
1252 width, height,
1253 dpy->clientID, visual->mode);
1254
1255 if (!win->driDrawable) {
1256 fprintf(stderr, "%s: dri.createDrawable failed\n", __FUNCTION__);
1257 free(win);
1258 return NULL;
1259 }
1260
1261 dpy->NumWindows++;
1262 dpy->TheWindow = win;
1263
1264 return win;
1265 }
1266
1267
1268 /**
1269 * \brief Destroy window.
1270 *
1271 * \param display display handle.
1272 * \param w window handle.
1273 *
1274 * This function calls XUnmapWindow() and frees window \p w.
1275 *
1276 * In case of destroying the current buffer first unbinds the GLX context
1277 * by calling glXMakeCurrent() with no drawable.
1278 */
1279 void
1280 XDestroyWindow( Display *display, Window win )
1281 {
1282 if (display && display->IsClient && win) {
1283 /* check if destroying the current buffer */
1284 Window curDraw = glXGetCurrentDrawable();
1285 if (win == curDraw) {
1286 glXMakeCurrent( display, NULL, NULL);
1287 }
1288
1289 XUnmapWindow( display, win );
1290
1291 /* Destroy the drawable. */
1292 (*win->driDrawable->destroyDrawable)(win->driDrawable);
1293 free(win);
1294
1295 /* unlink window from display */
1296 display->NumWindows--;
1297 assert(display->NumWindows == 0);
1298 display->TheWindow = NULL;
1299 }
1300 }
1301
1302
1303
1304
1305 /**
1306 * \brief Create color map structure.
1307 *
1308 * \param dpy the display handle as returned by XOpenDisplay().
1309 * \param w the window on whose screen you want to create a color map. This
1310 * parameter is ignored by Mini GLX but should be the value returned by the
1311 * \code RootWindow(display, 0) \endcode macro.
1312 * \param visual a visual type supported on the screen. This parameter is
1313 * ignored by Mini GLX but should be the XVisualInfo::visual returned by
1314 * glXChooseVisual().
1315 * \param alloc the color map entries to be allocated. This parameter is ignored
1316 * by Mini GLX but should be set to #AllocNone.
1317 *
1318 * \return the color map.
1319 *
1320 * This function is only provided to ease porting. Practically a no-op -
1321 * returns a pointer to a dynamically allocated chunk of memory (one byte).
1322 */
1323 Colormap
1324 XCreateColormap( Display *dpy, Window w, Visual *visual, int alloc )
1325 {
1326 (void) dpy;
1327 (void) w;
1328 (void) visual;
1329 (void) alloc;
1330 return (Colormap) malloc(1);
1331 }
1332
1333
1334 /**
1335 * \brief Destroy color map structure.
1336 *
1337 * \param display The display handle as returned by XOpenDisplay().
1338 * \param colormap the color map to destroy.
1339 *
1340 * This function is only provided to ease porting. Practically a no-op.
1341 *
1342 * Frees the memory pointed by \p colormap.
1343 */
1344 void
1345 XFreeColormap( Display *display, Colormap colormap )
1346 {
1347 (void) display;
1348 (void) colormap;
1349 free(colormap);
1350 }
1351
1352
1353 /**
1354 * \brief Free client data.
1355 *
1356 * \param data the data that is to be freed.
1357 *
1358 * Frees the memory pointed by \p data.
1359 */
1360 void
1361 XFree( void *data )
1362 {
1363 free(data);
1364 }
1365
1366
1367 /**
1368 * \brief Query available visuals.
1369 *
1370 * \param dpy the display handle, as returned by XOpenDisplay().
1371 * \param vinfo_mask a bitmask indicating which fields of the \p vinfo_template
1372 * are to be matched. The value must be \c VisualScreenMask.
1373 * \param vinfo_template a template whose fields indicate which visual
1374 * attributes must be matched by the results. The XVisualInfo::screen field of
1375 * this structure must be zero.
1376 * \param nitens_return will hold the number of visuals returned.
1377 *
1378 * \return the address of an array of all available visuals.
1379 *
1380 * An example of using XGetVisualInfo() to get all available visuals follows:
1381 *
1382 * \code
1383 * XVisualInfo vinfo_template, *results;
1384 * int nitens_return;
1385 * Display *dpy = XOpenDisplay(NULL);
1386 * vinfo_template.screen = 0;
1387 * results = XGetVisualInfo(dpy, VisualScreenMask, &vinfo_template, &nitens_return);
1388 * \endcode
1389 *
1390 * Returns the list of all ::XVisualInfo available, one per
1391 * ::__GLcontextMode stored in MiniGLXDisplayRec::modes.
1392 */
1393 XVisualInfo *
1394 XGetVisualInfo( Display *dpy, long vinfo_mask, XVisualInfo *vinfo_template, int *nitens_return )
1395 {
1396 XVisualInfo *results;
1397 Visual *visResults;
1398 int i, n;
1399
1400 ASSERT(vinfo_mask == VisualScreenMask);
1401 ASSERT(vinfo_template.screen == 0);
1402
1403 n = dpy->numModes;
1404 results = (XVisualInfo *)calloc(1, n * sizeof(XVisualInfo));
1405 if (!results) {
1406 *nitens_return = 0;
1407 return NULL;
1408 }
1409
1410 visResults = (Visual *)calloc(1, n * sizeof(Visual));
1411 if (!results) {
1412 free(results);
1413 *nitens_return = 0;
1414 return NULL;
1415 }
1416
1417 for (i = 0; i < n; i++) {
1418 visResults[i].mode = dpy->modes + i;
1419 visResults[i].visInfo = results + i;
1420 visResults[i].dpy = dpy;
1421
1422 if (dpy->driverContext.bpp == 32)
1423 visResults[i].pixelFormat = PF_B8G8R8A8; /* XXX: FIX ME */
1424 else
1425 visResults[i].pixelFormat = PF_B5G6R5; /* XXX: FIX ME */
1426
1427 results[i].visual = visResults + i;
1428 results[i].visualid = i;
1429 results[i].class = TrueColor;
1430 results[i].depth = dpy->modes[i].redBits +
1431 dpy->modes[i].redBits +
1432 dpy->modes[i].redBits +
1433 dpy->modes[i].redBits;
1434 results[i].bits_per_rgb = dpy->driverContext.bpp;
1435 }
1436 *nitens_return = n;
1437 return results;
1438 }
1439
1440
1441 /**
1442 * \brief Return a visual that matches specified attributes.
1443 *
1444 * \param dpy the display handle, as returned by XOpenDisplay().
1445 * \param screen the screen number. It is currently ignored by Mini GLX and
1446 * should be zero.
1447 * \param attribList a list of GLX attributes which describe the desired pixel
1448 * format. It is terminated by the token \c None.
1449 *
1450 * The attributes are as follows:
1451 * \arg GLX_USE_GL:
1452 * This attribute should always be present in order to maintain compatibility
1453 * with GLX.
1454 * \arg GLX_RGBA:
1455 * If present, only RGBA pixel formats will be considered. Otherwise, only
1456 * color index formats are considered.
1457 * \arg GLX_DOUBLEBUFFER:
1458 * if present, only double-buffered pixel formats will be chosen.
1459 * \arg GLX_RED_SIZE \e n:
1460 * Must be followed by a non-negative integer indicating the minimum number of
1461 * bits per red pixel component that is acceptable.
1462 * \arg GLX_GREEN_SIZE \e n:
1463 * Must be followed by a non-negative integer indicating the minimum number of
1464 * bits per green pixel component that is acceptable.
1465 * \arg GLX_BLUE_SIZE \e n:
1466 * Must be followed by a non-negative integer indicating the minimum number of
1467 * bits per blue pixel component that is acceptable.
1468 * \arg GLX_ALPHA_SIZE \e n:
1469 * Must be followed by a non-negative integer indicating the minimum number of
1470 * bits per alpha pixel component that is acceptable.
1471 * \arg GLX_STENCIL_SIZE \e n:
1472 * Must be followed by a non-negative integer indicating the minimum number of
1473 * bits per stencil value that is acceptable.
1474 * \arg GLX_DEPTH_SIZE \e n:
1475 * Must be followed by a non-negative integer indicating the minimum number of
1476 * bits per depth component that is acceptable.
1477 * \arg None:
1478 * This token is used to terminate the attribute list.
1479 *
1480 * \return a pointer to an #XVisualInfo object which most closely matches the
1481 * requirements of the attribute list. If there is no visual which matches the
1482 * request, \c NULL will be returned.
1483 *
1484 * \note Visuals with accumulation buffers are not available.
1485 *
1486 * This function searches the list of available visual configurations in
1487 * MiniGLXDisplayRec::configs for a configuration which best matches the GLX
1488 * attribute list parameter. A new ::XVisualInfo object is created which
1489 * describes the visual configuration. The match criteria is described in the
1490 * specification.
1491 */
1492 XVisualInfo*
1493 glXChooseVisual( Display *dpy, int screen, int *attribList )
1494 {
1495 Visual *vis;
1496 XVisualInfo *visInfo;
1497 const int *attrib;
1498 GLboolean rgbFlag = GL_FALSE, dbFlag = GL_FALSE, stereoFlag = GL_FALSE;
1499 GLint redBits = 0, greenBits = 0, blueBits = 0, alphaBits = 0;
1500 GLint indexBits = 0, depthBits = 0, stencilBits = 0;
1501 GLint numSamples = 0;
1502 int i;
1503
1504 /*
1505 * XXX in the future, <screen> might be interpreted as a VT
1506 */
1507 ASSERT(dpy);
1508 ASSERT(screen == 0);
1509
1510 vis = (Visual *)calloc(1, sizeof(Visual));
1511 if (!vis)
1512 return NULL;
1513
1514 visInfo = (XVisualInfo *)malloc(sizeof(XVisualInfo));
1515 if (!visInfo) {
1516 free(vis);
1517 return NULL;
1518 }
1519
1520 visInfo->visual = vis;
1521 vis->visInfo = visInfo;
1522 vis->dpy = dpy;
1523
1524 /* parse the attribute list */
1525 for (attrib = attribList; attrib && *attrib != None; attrib++) {
1526 switch (attrib[0]) {
1527 case GLX_DOUBLEBUFFER:
1528 dbFlag = GL_TRUE;
1529 break;
1530 case GLX_RGBA:
1531 rgbFlag = GL_TRUE;
1532 break;
1533 case GLX_RED_SIZE:
1534 redBits = attrib[1];
1535 attrib++;
1536 break;
1537 case GLX_GREEN_SIZE:
1538 redBits = attrib[1];
1539 attrib++;
1540 break;
1541 case GLX_BLUE_SIZE:
1542 redBits = attrib[1];
1543 attrib++;
1544 break;
1545 case GLX_ALPHA_SIZE:
1546 redBits = attrib[1];
1547 attrib++;
1548 break;
1549 case GLX_STENCIL_SIZE:
1550 stencilBits = attrib[1];
1551 attrib++;
1552 break;
1553 case GLX_DEPTH_SIZE:
1554 depthBits = attrib[1];
1555 attrib++;
1556 break;
1557 #if 0
1558 case GLX_ACCUM_RED_SIZE:
1559 accumRedBits = attrib[1];
1560 attrib++;
1561 break;
1562 case GLX_ACCUM_GREEN_SIZE:
1563 accumGreenBits = attrib[1];
1564 attrib++;
1565 break;
1566 case GLX_ACCUM_BLUE_SIZE:
1567 accumBlueBits = attrib[1];
1568 attrib++;
1569 break;
1570 case GLX_ACCUM_ALPHA_SIZE:
1571 accumAlphaBits = attrib[1];
1572 attrib++;
1573 break;
1574 case GLX_LEVEL:
1575 /* ignored for now */
1576 break;
1577 #endif
1578 default:
1579 /* unexpected token */
1580 fprintf(stderr, "unexpected token in glXChooseVisual attrib list\n");
1581 free(vis);
1582 free(visInfo);
1583 return NULL;
1584 }
1585 }
1586
1587 /* search screen configs for suitable visual */
1588 (void) numSamples;
1589 (void) indexBits;
1590 (void) redBits;
1591 (void) greenBits;
1592 (void) blueBits;
1593 (void) alphaBits;
1594 (void) stereoFlag;
1595 for (i = 0; i < dpy->numModes; i++) {
1596 const __GLcontextModes *mode = dpy->modes + i;
1597 if (mode->rgbMode == rgbFlag &&
1598 mode->redBits >= redBits &&
1599 mode->greenBits >= greenBits &&
1600 mode->blueBits >= blueBits &&
1601 mode->alphaBits >= alphaBits &&
1602 mode->depthBits >= depthBits &&
1603 mode->stencilBits >= stencilBits) {
1604 /* found it */
1605 visInfo->visualid = i;
1606 vis->mode = mode;
1607 break;
1608 }
1609 }
1610 if (!vis->mode)
1611 return NULL;
1612
1613 /* compute depth and bpp */
1614 if (rgbFlag) {
1615 /* XXX maybe support depth 16 someday */
1616 visInfo->class = TrueColor;
1617 visInfo->depth = dpy->driverContext.bpp;
1618 visInfo->bits_per_rgb = dpy->driverContext.bpp;
1619 if (dpy->driverContext.bpp == 32)
1620 vis->pixelFormat = PF_B8G8R8A8;
1621 else
1622 vis->pixelFormat = PF_B5G6R5;
1623 }
1624 else {
1625 /* color index mode */
1626 visInfo->class = PseudoColor;
1627 visInfo->depth = 8;
1628 visInfo->bits_per_rgb = 8; /* bits/pixel */
1629 vis->pixelFormat = PF_CI8;
1630 }
1631
1632 return visInfo;
1633 }
1634
1635
1636 /**
1637 * \brief Return information about GLX visuals.
1638 *
1639 * \param dpy the display handle, as returned by XOpenDisplay().
1640 * \param vis the visual to be queried, as returned by glXChooseVisual().
1641 * \param attrib the visual attribute to be returned.
1642 * \param value pointer to an integer in which the result of the query will be
1643 * stored.
1644 *
1645 * \return zero if no error occurs, \c GLX_INVALID_ATTRIBUTE if the attribute
1646 * parameter is invalid, or \c GLX_BAD_VISUAL if the \p vis parameter is
1647 * invalid.
1648 *
1649 * Returns the appropriate attribute of ::__GLXvisualConfig pointed by
1650 * MiniGLXVisualRec::glxConfig of XVisualInfo::visual.
1651 *
1652 * \sa data types.
1653 */
1654 int
1655 glXGetConfig( Display *dpy, XVisualInfo *vis, int attrib, int *value )
1656 {
1657 const __GLcontextModes *mode = vis->visual->mode;
1658 if (!mode) {
1659 *value = 0;
1660 return GLX_BAD_VISUAL;
1661 }
1662
1663 switch (attrib) {
1664 case GLX_USE_GL:
1665 *value = True;
1666 return 0;
1667 case GLX_RGBA:
1668 *value = mode->rgbMode;
1669 return 0;
1670 case GLX_DOUBLEBUFFER:
1671 *value = mode->doubleBufferMode;
1672 return 0;
1673 case GLX_RED_SIZE:
1674 *value = mode->redBits;
1675 return 0;
1676 case GLX_GREEN_SIZE:
1677 *value = mode->greenBits;
1678 return 0;
1679 case GLX_BLUE_SIZE:
1680 *value = mode->blueBits;
1681 return 0;
1682 case GLX_ALPHA_SIZE:
1683 *value = mode->alphaBits;
1684 return 0;
1685 case GLX_DEPTH_SIZE:
1686 *value = mode->depthBits;
1687 return 0;
1688 case GLX_STENCIL_SIZE:
1689 *value = mode->stencilBits;
1690 return 0;
1691 default:
1692 *value = 0;
1693 return GLX_BAD_ATTRIBUTE;
1694 }
1695 return 0;
1696 }
1697
1698
1699 /**
1700 * \brief Create a new GLX rendering context.
1701 *
1702 * \param dpy the display handle, as returned by XOpenDisplay().
1703 * \param vis the visual that defines the frame buffer resources available to
1704 * the rendering context, as returned by glXChooseVisual().
1705 * \param shareList If non-zero, texture objects and display lists are shared
1706 * with the named rendering context. If zero, texture objects and display lists
1707 * will (initially) be private to this context. They may be shared when a
1708 * subsequent context is created.
1709 * \param direct whether direct or indirect rendering is desired. For Mini GLX
1710 * this value is ignored but it should be set to \c True.
1711 *
1712 * \return a ::GLXContext handle if it succeeds or zero if it fails due to
1713 * invalid parameter or insufficient resources.
1714 *
1715 * This function creates and initializes a ::MiniGLXContextRec structure and
1716 * calls the __DRIscreenRec::createContext method to initialize the client
1717 * private data.
1718 */
1719 GLXContext
1720 glXCreateContext( Display *dpy, XVisualInfo *vis,
1721 GLXContext shareList, Bool direct )
1722 {
1723 GLXContext ctx;
1724 void *sharePriv;
1725
1726 ASSERT(vis);
1727
1728 ctx = (struct MiniGLXContextRec *)calloc(1, sizeof(struct MiniGLXContextRec));
1729 if (!ctx)
1730 return NULL;
1731
1732 ctx->vid = vis->visualid;
1733
1734 if (shareList)
1735 sharePriv = shareList->driContext;
1736 else
1737 sharePriv = NULL;
1738
1739 ctx->driContext = (*dpy->driScreen->createContext)(dpy->driScreen,
1740 vis->visual->mode,
1741 sharePriv);
1742 if (!ctx->driContext) {
1743 free(ctx);
1744 return NULL;
1745 }
1746
1747 return ctx;
1748 }
1749
1750
1751 /**
1752 * \brief Destroy a GLX context.
1753 *
1754 * \param dpy the display handle, as returned by XOpenDisplay().
1755 * \param ctx the GLX context to be destroyed.
1756 *
1757 * This function frees the \p ctx parameter after unbinding the current context
1758 * by calling the __DRIcontextRec::bindContext method with zeros and calling
1759 * the __DRIcontextRec::destroyContext method.
1760 */
1761 void
1762 glXDestroyContext( Display *dpy, GLXContext ctx )
1763 {
1764 GLXContext glxctx = glXGetCurrentContext();
1765
1766 if (ctx) {
1767 if (glxctx == ctx) {
1768 /* destroying current context */
1769 (*ctx->driContext->bindContext)(dpy->driScreen, 0, 0);
1770 CurrentContext = 0;
1771 }
1772 (*ctx->driContext->destroyContext)(ctx->driContext);
1773 free(ctx);
1774 }
1775 }
1776
1777
1778 /**
1779 * \brief Bind a GLX context to a window or a pixmap.
1780 *
1781 * \param dpy the display handle, as returned by XOpenDisplay().
1782 * \param drawable the window or drawable to bind to the rendering context.
1783 * This should be the value returned by XCreateWindow().
1784 * \param ctx the GLX context to be destroyed.
1785 *
1786 * \return \c True if it succeeds, \c False otherwise to indicate an invalid
1787 * display, window or context parameter.
1788 *
1789 * The current rendering context may be unbound by calling glXMakeCurrent()
1790 * with the window and context parameters set to zero.
1791 *
1792 * An application may create any number of rendering contexts and bind them as
1793 * needed. Note that binding a rendering context is generally not a
1794 * light-weight operation. Most simple OpenGL applications create only one
1795 * rendering context.
1796 *
1797 * This function first unbinds any old context via
1798 * __DRIcontextRec::unbindContext and binds the new one via
1799 * __DRIcontextRec::bindContext.
1800 *
1801 * If \p drawable is zero it unbinds the GLX context by calling
1802 * __DRIcontextRec::bindContext with zeros.
1803 */
1804 Bool
1805 glXMakeCurrent( Display *dpy, GLXDrawable drawable, GLXContext ctx)
1806 {
1807 if (dpy && drawable && ctx) {
1808 GLXContext oldContext = glXGetCurrentContext();
1809 GLXDrawable oldDrawable = glXGetCurrentDrawable();
1810 /* unbind old */
1811 if (oldContext) {
1812 (*oldContext->driContext->unbindContext)(oldDrawable->driDrawable, oldContext->driContext);
1813 }
1814 /* bind new */
1815 CurrentContext = ctx;
1816 (*ctx->driContext->bindContext)(dpy->driScreen, drawable->driDrawable, ctx->driContext);
1817 ctx->drawBuffer = drawable;
1818 ctx->curBuffer = drawable;
1819 }
1820 else if (ctx && dpy) {
1821 /* unbind */
1822 (*ctx->driContext->bindContext)(dpy->driScreen, 0, 0);
1823 }
1824 else if (dpy) {
1825 CurrentContext = 0; /* kw: this seems to be intended??? */
1826 }
1827
1828 return True;
1829 }
1830
1831
1832 /**
1833 * \brief Exchange front and back buffers.
1834 *
1835 * \param dpy the display handle, as returned by XOpenDisplay().
1836 * \param drawable the drawable whose buffers are to be swapped.
1837 *
1838 * Any pending rendering commands will be completed before the buffer swap
1839 * takes place.
1840 *
1841 * Calling glXSwapBuffers() on a window which is single-buffered has no effect.
1842 *
1843 * This function just calls the __DRIdrawableRec::swapBuffers method to do the
1844 * work.
1845 */
1846 void
1847 glXSwapBuffers( Display *dpy, GLXDrawable drawable )
1848 {
1849 if (!dpy || !drawable)
1850 return;
1851
1852 (*drawable->driDrawable->swapBuffers)(drawable->driDrawable);
1853 }
1854
1855
1856 /**
1857 * \brief Return the current context
1858 *
1859 * \return the current context, as specified by glXMakeCurrent(), or zero if no
1860 * context is currently bound.
1861 *
1862 * \sa glXCreateContext(), glXMakeCurrent()
1863 *
1864 * Returns the value of the ::CurrentContext global variable.
1865 */
1866 GLXContext
1867 glXGetCurrentContext( void )
1868 {
1869 return CurrentContext;
1870 }
1871
1872
1873 /**
1874 * \brief Return the current drawable.
1875 *
1876 * \return the current drawable, as specified by glXMakeCurrent(), or zero if
1877 * no drawable is currently bound.
1878 *
1879 * This function gets the current context via glXGetCurrentContext() and
1880 * returns the MiniGLXContextRec::drawBuffer attribute.
1881 */
1882 GLXDrawable
1883 glXGetCurrentDrawable( void )
1884 {
1885 GLXContext glxctx = glXGetCurrentContext();
1886 if (glxctx)
1887 return glxctx->drawBuffer;
1888 else
1889 return NULL;
1890 }
1891
1892
1893 /**
1894 * \brief Query function address.
1895 *
1896 * The glXGetProcAddress() function will return the address of any available
1897 * OpenGL or Mini GLX function.
1898 *
1899 * \param procName name of the function to be returned.
1900 *
1901 * \return If \p procName is a valid function name, a pointer to that function
1902 * will be returned. Otherwise, \c NULL will be returned.
1903 *
1904 * The purpose of glXGetProcAddress() is to facilitate using future extensions
1905 * to OpenGL or Mini GLX. If a future version of the library adds new extension
1906 * functions they'll be accessible via glXGetProcAddress(). The alternative is
1907 * to hard-code calls to the new functions in the application but doing so will
1908 * prevent linking the application with older versions of the library.
1909 *
1910 * Returns the function address by looking up its name in a static (name,
1911 * address) pair list.
1912 */
1913 const void *
1914 glXGetProcAddress( const GLubyte *procName )
1915 {
1916 struct name_address {
1917 const char *name;
1918 const void *func;
1919 };
1920 static const struct name_address functions[] = {
1921 { "glXChooseVisual", (void *) glXChooseVisual },
1922 { "glXCreateContext", (void *) glXCreateContext },
1923 { "glXDestroyContext", (void *) glXDestroyContext },
1924 { "glXMakeCurrent", (void *) glXMakeCurrent },
1925 { "glXSwapBuffers", (void *) glXSwapBuffers },
1926 { "glXGetCurrentContext", (void *) glXGetCurrentContext },
1927 { "glXGetCurrentDrawable", (void *) glXGetCurrentDrawable },
1928 { "glXGetProcAddress", (void *) glXGetProcAddress },
1929 { "XOpenDisplay", (void *) XOpenDisplay },
1930 { "XCloseDisplay", (void *) XCloseDisplay },
1931 { "XCreateWindow", (void *) XCreateWindow },
1932 { "XDestroyWindow", (void *) XDestroyWindow },
1933 { "XMapWindow", (void *) XMapWindow },
1934 { "XCreateColormap", (void *) XCreateColormap },
1935 { "XFreeColormap", (void *) XFreeColormap },
1936 { "XFree", (void *) XFree },
1937 { "XGetVisualinfo", (void *) XGetVisualInfo },
1938 { NULL, NULL }
1939 };
1940 const struct name_address *entry;
1941 for (entry = functions; entry->name; entry++) {
1942 if (strcmp(entry->name, (const char *) procName) == 0) {
1943 return entry->func;
1944 }
1945 }
1946 return _glapi_get_proc_address((const char *) procName);
1947 }
1948
1949
1950 /**
1951 * \brief Query the Mini GLX version.
1952 *
1953 * \param dpy the display handle. It is currently ignored, but should be the
1954 * value returned by XOpenDisplay().
1955 * \param major receives the major version number of Mini GLX.
1956 * \param minor receives the minor version number of Mini GLX.
1957 *
1958 * \return \c True if the function succeeds, \c False if the function fails due
1959 * to invalid parameters.
1960 *
1961 * \sa #MINI_GLX_VERSION_1_0.
1962 *
1963 * Returns the hard-coded Mini GLX version.
1964 */
1965 Bool
1966 glXQueryVersion( Display *dpy, int *major, int *minor )
1967 {
1968 (void) dpy;
1969 *major = 1;
1970 *minor = 0;
1971 return True;
1972 }
1973
1974
1975 /*@}*/