bring in changes from 6.4 branch
[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: 6.0.1
13 *
14 * Copyright (C) 1999-2004 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
35 /**
36 * \mainpage Mini GLX
37 *
38 * \section miniglxIntro Introduction
39 *
40 * The Mini GLX interface facilitates OpenGL rendering on embedded devices. The
41 * interface is a subset of the GLX interface, plus a minimal set of Xlib-like
42 * functions.
43 *
44 * Programs written to the Mini GLX specification should run unchanged
45 * on systems with the X Window System and the GLX extension (after
46 * recompilation). The intention is to allow flexibility for
47 * prototyping and testing.
48 *
49 * The files in the src/miniglx/ directory are compiled to build the
50 * libGL.so library. This is the library which applications link with.
51 * libGL.so in turn, loads the hardware-specific device driver.
52 *
53 *
54 * \section miniglxDoxygen About Doxygen
55 *
56 * For a list of all files, select <b>File List</b>. Choose a file from
57 * the list for a list of all functions in the file.
58 *
59 * For a list of all functions, types, constants, etc.
60 * select <b>File Members</b>.
61 *
62 *
63 * \section miniglxReferences References
64 *
65 * - <A HREF="file:../../docs/MiniGLX.html">Mini GLX Specification</A>,
66 * Tungsten Graphics, Inc.
67 * - OpenGL Graphics with the X Window System, Silicon Graphics, Inc.,
68 * ftp://ftp.sgi.com/opengl/doc/opengl1.2/glx1.3.ps
69 * - Xlib - C Language X Interface, X Consortium Standard, X Version 11,
70 * Release 6.4, ftp://ftp.x.org/pub/R6.4/xc/doc/hardcopy/X11/xlib.PS.gz
71 * - XFree86 Man pages, The XFree86 Project, Inc.,
72 * http://www.xfree86.org/current/manindex3.html
73 *
74 */
75
76 /**
77 * \page datatypes Notes on the XVisualInfo, Visual, and __GLXvisualConfig data types
78 *
79 * -# X (unfortunately) has two (or three) data types which
80 * describe visuals. Ideally, there would just be one.
81 * -# We need the #__GLXvisualConfig type to augment #XVisualInfo and #Visual
82 * because we need to describe the GLX-specific attributes of visuals.
83 * -# In this interface there is a one-to-one-to-one correspondence between
84 * the three types and they're all interconnected.
85 * -# The #XVisualInfo type has a pointer to a #Visual. The #Visual structure
86 * (aka MiniGLXVisualRec) has a pointer to the #__GLXvisualConfig. The
87 * #Visual structure also has a pointer pointing back to the #XVisualInfo.
88 * -# The #XVisualInfo structure is the only one who's contents are public.
89 * -# The glXChooseVisual() and XGetVisualInfo() are the only functions that
90 * return #XVisualInfo structures. They can be freed with XFree(), though
91 * there is a small memory leak.
92 */
93
94
95 #include <assert.h>
96 #include <errno.h>
97 #include <signal.h>
98 #include <stdio.h>
99 #include <stdlib.h>
100 #include <string.h>
101 #include <dlfcn.h>
102 #include <fcntl.h>
103 #include <unistd.h>
104 #include <sys/ioctl.h>
105 #include <sys/mman.h>
106 #include <sys/types.h>
107 #include <sys/time.h> /* for gettimeofday */
108 #include <linux/kd.h>
109 #include <linux/vt.h>
110
111 #include "miniglxP.h"
112 #include "dri_util.h"
113
114 #include "imports.h"
115 #include "glcontextmodes.h"
116 #include "glapi.h"
117
118
119 static GLboolean __glXCreateContextWithConfig(__DRInativeDisplay *dpy,
120 int screen, int fbconfigID, void *contextID,
121 drm_context_t *hHWContext);
122
123 static GLboolean __glXGetDrawableInfo(__DRInativeDisplay *dpy, int scrn,
124 __DRIid draw, unsigned int * index, unsigned int * stamp,
125 int * x, int * y, int * width, int * height,
126 int * numClipRects, drm_clip_rect_t ** pClipRects,
127 int * backX, int * backY,
128 int * numBackClipRects, drm_clip_rect_t ** pBackClipRects);
129
130 static __DRIscreen * __glXFindDRIScreen(__DRInativeDisplay *dpy, int scrn);
131
132 static GLboolean __glXWindowExists(__DRInativeDisplay *dpy, __DRIid draw);
133
134 static int __glXGetUST( int64_t * ust );
135
136 static GLboolean __glXGetMscRate(__DRInativeDisplay * dpy, __DRIid drawable,
137 int32_t * numerator, int32_t * denominator);
138
139 static GLboolean xf86DRI_DestroyContext(__DRInativeDisplay *dpy, int screen,
140 __DRIid context_id );
141
142 static GLboolean xf86DRI_CreateDrawable(__DRInativeDisplay *dpy, int screen,
143 __DRIid drawable, drm_drawable_t *hHWDrawable );
144
145 static GLboolean xf86DRI_DestroyDrawable(__DRInativeDisplay *dpy, int screen,
146 __DRIid drawable);
147
148
149 /** Wrapper around either malloc() */
150 void *
151 _mesa_malloc(size_t bytes)
152 {
153 return malloc(bytes);
154 }
155
156 /** Wrapper around either calloc() */
157 void *
158 _mesa_calloc(size_t bytes)
159 {
160 return calloc(1, bytes);
161 }
162
163 /** Wrapper around either free() */
164 void
165 _mesa_free(void *ptr)
166 {
167 free(ptr);
168 }
169
170
171 /**
172 * \brief Current GLX context.
173 *
174 * \sa glXGetCurrentContext().
175 */
176 static GLXContext CurrentContext = NULL;
177
178
179
180 static Display *SignalDisplay = 0;
181
182 static void SwitchVT(int sig)
183 {
184 fprintf(stderr, "SwitchVT %d dpy %p\n", sig, SignalDisplay);
185
186 if (SignalDisplay) {
187 SignalDisplay->vtSignalFlag = 1;
188 switch( sig )
189 {
190 case SIGUSR1: /* vt has been released */
191 SignalDisplay->haveVT = 0;
192 break;
193 case SIGUSR2: /* vt has been acquired */
194 SignalDisplay->haveVT = 1;
195 break;
196 }
197 }
198 }
199
200 /**********************************************************************/
201 /** \name Framebuffer device functions */
202 /**********************************************************************/
203 /*@{*/
204
205 /**
206 * \brief Do the first part of setting up the framebuffer device.
207 *
208 * \param dpy the display handle.
209 * \param use_vt use a VT for display or not
210 *
211 * \return GL_TRUE on success, or GL_FALSE on failure.
212 *
213 * \sa This is called during XOpenDisplay().
214 *
215 * \internal
216 * Gets the VT number, opens the respective console TTY device. Saves its state
217 * to restore when exiting and goes into graphics mode.
218 *
219 * Opens the framebuffer device and make a copy of the original variable screen
220 * information and gets the fixed screen information. Maps the framebuffer and
221 * MMIO region into the process address space.
222 */
223 static GLboolean
224 OpenFBDev( Display *dpy, int use_vt )
225 {
226 char ttystr[1000];
227 int fd, vtnumber, ttyfd;
228
229 assert(dpy);
230
231 if (geteuid()) {
232 fprintf(stderr, "error: you need to be root\n");
233 return GL_FALSE;
234 }
235
236 if (use_vt) {
237
238 /* open /dev/tty0 and get the VT number */
239 if ((fd = open("/dev/tty0", O_WRONLY, 0)) < 0) {
240 fprintf(stderr, "error opening /dev/tty0\n");
241 return GL_FALSE;
242 }
243 if (ioctl(fd, VT_OPENQRY, &vtnumber) < 0 || vtnumber < 0) {
244 fprintf(stderr, "error: couldn't get a free vt\n");
245 return GL_FALSE;
246 }
247
248 fprintf(stderr, "*** got vt nr: %d\n", vtnumber);
249 close(fd);
250
251 /* open the console tty */
252 sprintf(ttystr, "/dev/tty%d", vtnumber); /* /dev/tty1-64 */
253 dpy->ConsoleFD = open(ttystr, O_RDWR | O_NDELAY, 0);
254 if (dpy->ConsoleFD < 0) {
255 fprintf(stderr, "error couldn't open console fd\n");
256 return GL_FALSE;
257 }
258
259 /* save current vt number */
260 {
261 struct vt_stat vts;
262 if (ioctl(dpy->ConsoleFD, VT_GETSTATE, &vts) == 0)
263 dpy->OriginalVT = vts.v_active;
264 }
265
266 /* disconnect from controlling tty */
267 ttyfd = open("/dev/tty", O_RDWR);
268 if (ttyfd >= 0) {
269 ioctl(ttyfd, TIOCNOTTY, 0);
270 close(ttyfd);
271 }
272
273 /* some magic to restore the vt when we exit */
274 {
275 struct vt_mode vt;
276 struct sigaction sig_tty;
277
278 /* Set-up tty signal handler to catch the signal we request below */
279 SignalDisplay = dpy;
280 memset( &sig_tty, 0, sizeof( sig_tty ) );
281 sig_tty.sa_handler = SwitchVT;
282 sigemptyset( &sig_tty.sa_mask );
283 if( sigaction( SIGUSR1, &sig_tty, &dpy->OrigSigUsr1 ) ||
284 sigaction( SIGUSR2, &sig_tty, &dpy->OrigSigUsr2 ) )
285 {
286 fprintf(stderr, "error: can't set up signal handler (%s)",
287 strerror(errno) );
288 return GL_FALSE;
289 }
290
291
292
293 vt.mode = VT_PROCESS;
294 vt.waitv = 0;
295 vt.relsig = SIGUSR1;
296 vt.acqsig = SIGUSR2;
297 if (ioctl(dpy->ConsoleFD, VT_SETMODE, &vt) < 0) {
298 fprintf(stderr, "error: ioctl(VT_SETMODE) failed: %s\n",
299 strerror(errno));
300 return GL_FALSE;
301 }
302
303
304 if (ioctl(dpy->ConsoleFD, VT_ACTIVATE, vtnumber) != 0)
305 printf("ioctl VT_ACTIVATE: %s\n", strerror(errno));
306 if (ioctl(dpy->ConsoleFD, VT_WAITACTIVE, vtnumber) != 0)
307 printf("ioctl VT_WAITACTIVE: %s\n", strerror(errno));
308
309 if (ioctl(dpy->ConsoleFD, VT_GETMODE, &vt) < 0) {
310 fprintf(stderr, "error: ioctl VT_GETMODE: %s\n", strerror(errno));
311 return GL_FALSE;
312 }
313
314
315
316 }
317
318 /* go into graphics mode */
319 if (ioctl(dpy->ConsoleFD, KDSETMODE, KD_GRAPHICS) < 0) {
320 fprintf(stderr, "error: ioctl(KDSETMODE, KD_GRAPHICS) failed: %s\n",
321 strerror(errno));
322 return GL_FALSE;
323 }
324 }
325
326 /* open the framebuffer device */
327 dpy->FrameBufferFD = open(dpy->fbdevDevice, O_RDWR);
328 if (dpy->FrameBufferFD < 0) {
329 fprintf(stderr, "Error opening /dev/fb0: %s\n", strerror(errno));
330 return GL_FALSE;
331 }
332
333 /* get the original variable screen info */
334 if (ioctl(dpy->FrameBufferFD, FBIOGET_VSCREENINFO, &dpy->OrigVarInfo)) {
335 fprintf(stderr, "error: ioctl(FBIOGET_VSCREENINFO) failed: %s\n",
336 strerror(errno));
337 return GL_FALSE;
338 }
339
340 /* make copy */
341 dpy->VarInfo = dpy->OrigVarInfo; /* structure copy */
342
343 /* Turn off hw accels (otherwise mmap of mmio region will be
344 * refused)
345 */
346 dpy->VarInfo.accel_flags = 0;
347 if (ioctl(dpy->FrameBufferFD, FBIOPUT_VSCREENINFO, &dpy->VarInfo)) {
348 fprintf(stderr, "error: ioctl(FBIOPUT_VSCREENINFO) failed: %s\n",
349 strerror(errno));
350 return GL_FALSE;
351 }
352
353
354
355 /* Get the fixed screen info */
356 if (ioctl(dpy->FrameBufferFD, FBIOGET_FSCREENINFO, &dpy->FixedInfo)) {
357 fprintf(stderr, "error: ioctl(FBIOGET_FSCREENINFO) failed: %s\n",
358 strerror(errno));
359 return GL_FALSE;
360 }
361
362
363
364 /* mmap the framebuffer into our address space */
365 dpy->driverContext.FBStart = dpy->FixedInfo.smem_start;
366 dpy->driverContext.FBSize = dpy->FixedInfo.smem_len;
367 dpy->driverContext.shared.fbSize = dpy->FixedInfo.smem_len;
368 dpy->driverContext.FBAddress = (caddr_t) mmap(0, /* start */
369 dpy->driverContext.shared.fbSize, /* bytes */
370 PROT_READ | PROT_WRITE, /* prot */
371 MAP_SHARED, /* flags */
372 dpy->FrameBufferFD, /* fd */
373 0 /* offset */);
374 if (dpy->driverContext.FBAddress == (caddr_t) - 1) {
375 fprintf(stderr, "error: unable to mmap framebuffer: %s\n",
376 strerror(errno));
377 return GL_FALSE;
378 }
379
380 /* mmap the MMIO region into our address space */
381 dpy->driverContext.MMIOStart = dpy->FixedInfo.mmio_start;
382 dpy->driverContext.MMIOSize = dpy->FixedInfo.mmio_len;
383 dpy->driverContext.MMIOAddress = (caddr_t) mmap(0, /* start */
384 dpy->driverContext.MMIOSize, /* bytes */
385 PROT_READ | PROT_WRITE, /* prot */
386 MAP_SHARED, /* flags */
387 dpy->FrameBufferFD, /* fd */
388 dpy->FixedInfo.smem_len /* offset */);
389 if (dpy->driverContext.MMIOAddress == (caddr_t) - 1) {
390 fprintf(stderr, "error: unable to mmap mmio region: %s\n",
391 strerror(errno));
392 return GL_FALSE;
393 }
394
395 fprintf(stderr, "got MMIOAddress %p offset %d\n",
396 dpy->driverContext.MMIOAddress,
397 dpy->FixedInfo.smem_len);
398
399 return GL_TRUE;
400 }
401
402
403
404
405 /**
406 * \brief Setup up the desired framebuffer device mode.
407 *
408 * \param dpy the display handle.
409 *
410 * \return GL_TRUE on success, or GL_FALSE on failure.
411 *
412 * \sa This is called during __miniglx_StartServer().
413 *
414 * \internal
415 *
416 * Bumps the size of the window the the next supported mode. Sets the
417 * variable screen information according to the desired mode and asks
418 * the driver to validate the mode. Certifies that a DirectColor or
419 * TrueColor visual is used from the updated fixed screen information.
420 * In the case of DirectColor visuals, sets up an 'identity' colormap to
421 * mimic a TrueColor visual.
422 *
423 * Calls the driver hooks 'ValidateMode' and 'PostValidateMode' to
424 * allow the driver to make modifications to the chosen mode according
425 * to hardware constraints, or to save and restore videocard registers
426 * that may be clobbered by the fbdev driver.
427 *
428 * \todo Timings are hard-coded in the source for a set of supported modes.
429 */
430 static GLboolean
431 SetupFBDev( Display *dpy )
432 {
433 int width, height;
434
435 assert(dpy);
436
437 width = dpy->driverContext.shared.virtualWidth;
438 height = dpy->driverContext.shared.virtualHeight;
439
440 if (width==832)
441 width=800;
442 /* Bump size up to next supported mode.
443 */
444 if (width <= 720 && height <= 480) {
445 width = 720; height = 480;
446 }
447 else if (width <= 960 && height <= 540) {
448 width = 960; height = 540;
449 }
450 else if (width <= 800 && height <= 600) {
451 width = 800; height = 600;
452 }
453 else if (width <= 1024 && height <= 768) {
454 width = 1024; height = 768;
455 }
456 else if (width <= 768 && height <= 1024) {
457 width = 768; height = 1024;
458 }
459 else if (width <= 1280 && height <= 1024) {
460 width = 1280; height = 1024;
461 }
462
463
464 dpy->driverContext.shared.fbStride = width * (dpy->driverContext.bpp / 8);
465
466 /* set the depth, resolution, etc */
467 dpy->VarInfo = dpy->OrigVarInfo;
468 dpy->VarInfo.bits_per_pixel = dpy->driverContext.bpp;
469 dpy->VarInfo.xres_virtual = dpy->driverContext.shared.virtualWidth;
470 dpy->VarInfo.yres_virtual = dpy->driverContext.shared.virtualHeight;
471 dpy->VarInfo.xres = width;
472 dpy->VarInfo.yres = height;
473 dpy->VarInfo.xoffset = 0;
474 dpy->VarInfo.yoffset = 0;
475 dpy->VarInfo.nonstd = 0;
476 dpy->VarInfo.vmode &= ~FB_VMODE_YWRAP; /* turn off scrolling */
477
478 if (dpy->VarInfo.bits_per_pixel == 32) {
479 dpy->VarInfo.red.offset = 16;
480 dpy->VarInfo.green.offset = 8;
481 dpy->VarInfo.blue.offset = 0;
482 dpy->VarInfo.transp.offset = 24;
483 dpy->VarInfo.red.length = 8;
484 dpy->VarInfo.green.length = 8;
485 dpy->VarInfo.blue.length = 8;
486 dpy->VarInfo.transp.length = 8;
487 }
488 else if (dpy->VarInfo.bits_per_pixel == 16) {
489 dpy->VarInfo.red.offset = 11;
490 dpy->VarInfo.green.offset = 5;
491 dpy->VarInfo.blue.offset = 0;
492 dpy->VarInfo.red.length = 5;
493 dpy->VarInfo.green.length = 6;
494 dpy->VarInfo.blue.length = 5;
495 dpy->VarInfo.transp.offset = 0;
496 dpy->VarInfo.transp.length = 0;
497 }
498 else {
499 fprintf(stderr, "Only 32bpp and 16bpp modes supported at the moment\n");
500 return 0;
501 }
502
503 if (!dpy->driver->validateMode( &dpy->driverContext )) {
504 fprintf(stderr, "Driver validateMode() failed\n");
505 return 0;
506 }
507
508 /* These should be calculated with the gtf.c program, and then we could
509 remove all this... AlanH. */
510 if (dpy->VarInfo.xres == 1280 &&
511 dpy->VarInfo.yres == 1024) {
512 /* timing values taken from /etc/fb.modes (1280x1024 @ 75Hz) */
513 dpy->VarInfo.pixclock = 7408;
514 dpy->VarInfo.left_margin = 248;
515 dpy->VarInfo.right_margin = 16;
516 dpy->VarInfo.upper_margin = 38;
517 dpy->VarInfo.lower_margin = 1;
518 dpy->VarInfo.hsync_len = 144;
519 dpy->VarInfo.vsync_len = 3;
520 }
521 else if (dpy->VarInfo.xres == 1024 &&
522 dpy->VarInfo.yres == 768) {
523 /* timing values taken from /etc/fb.modes (1024x768 @ 75Hz) */
524 dpy->VarInfo.pixclock = 12699;
525 dpy->VarInfo.left_margin = 176;
526 dpy->VarInfo.right_margin = 16;
527 dpy->VarInfo.upper_margin = 28;
528 dpy->VarInfo.lower_margin = 1;
529 dpy->VarInfo.hsync_len = 96;
530 dpy->VarInfo.vsync_len = 3;
531 }
532 else if (dpy->VarInfo.xres == 800 &&
533 dpy->VarInfo.yres == 600) {
534 /* timing values taken from /etc/fb.modes (800x600 @ 75Hz) */
535 dpy->VarInfo.pixclock = 27778;
536 dpy->VarInfo.left_margin = 128;
537 dpy->VarInfo.right_margin = 24;
538 dpy->VarInfo.upper_margin = 22;
539 dpy->VarInfo.lower_margin = 1;
540 dpy->VarInfo.hsync_len = 72;
541 dpy->VarInfo.vsync_len = 2;
542 }
543 else if (dpy->VarInfo.xres == 720 &&
544 dpy->VarInfo.yres == 480) {
545 dpy->VarInfo.pixclock = 37202;
546 dpy->VarInfo.left_margin = 88;
547 dpy->VarInfo.right_margin = 16;
548 dpy->VarInfo.upper_margin = 14;
549 dpy->VarInfo.lower_margin = 1;
550 dpy->VarInfo.hsync_len = 72;
551 dpy->VarInfo.vsync_len = 3;
552 }
553 else if (dpy->VarInfo.xres == 960 &&
554 dpy->VarInfo.yres == 540) {
555 dpy->VarInfo.pixclock = 24273;
556 dpy->VarInfo.left_margin = 128;
557 dpy->VarInfo.right_margin = 32;
558 dpy->VarInfo.upper_margin = 16;
559 dpy->VarInfo.lower_margin = 1;
560 dpy->VarInfo.hsync_len = 96;
561 dpy->VarInfo.vsync_len = 3;
562 }
563 else if (dpy->VarInfo.xres == 768 &&
564 dpy->VarInfo.yres == 1024) {
565 /* timing values for 768x1024 @ 75Hz */
566 dpy->VarInfo.pixclock = 11993;
567 dpy->VarInfo.left_margin = 136;
568 dpy->VarInfo.right_margin = 32;
569 dpy->VarInfo.upper_margin = 41;
570 dpy->VarInfo.lower_margin = 1;
571 dpy->VarInfo.hsync_len = 80;
572 dpy->VarInfo.vsync_len = 3;
573 }
574 else {
575 /* XXX need timings for other screen sizes */
576 fprintf(stderr, "XXXX screen size %d x %d not supported at this time!\n",
577 dpy->VarInfo.xres, dpy->VarInfo.yres);
578 return GL_FALSE;
579 }
580
581 fprintf(stderr, "[miniglx] Setting mode: visible %dx%d virtual %dx%dx%d\n",
582 dpy->VarInfo.xres, dpy->VarInfo.yres,
583 dpy->VarInfo.xres_virtual, dpy->VarInfo.yres_virtual,
584 dpy->VarInfo.bits_per_pixel);
585
586 /* set variable screen info */
587 if (ioctl(dpy->FrameBufferFD, FBIOPUT_VSCREENINFO, &dpy->VarInfo)) {
588 fprintf(stderr, "error: ioctl(FBIOPUT_VSCREENINFO) failed: %s\n",
589 strerror(errno));
590 return GL_FALSE;
591 }
592
593 /* get the variable screen info, in case it has been modified */
594 if (ioctl(dpy->FrameBufferFD, FBIOGET_VSCREENINFO, &dpy->VarInfo)) {
595 fprintf(stderr, "error: ioctl(FBIOGET_VSCREENINFO) failed: %s\n",
596 strerror(errno));
597 return GL_FALSE;
598 }
599
600
601 fprintf(stderr, "[miniglx] Readback mode: visible %dx%d virtual %dx%dx%d\n",
602 dpy->VarInfo.xres, dpy->VarInfo.yres,
603 dpy->VarInfo.xres_virtual, dpy->VarInfo.yres_virtual,
604 dpy->VarInfo.bits_per_pixel);
605
606 /* Get the fixed screen info */
607 if (ioctl(dpy->FrameBufferFD, FBIOGET_FSCREENINFO, &dpy->FixedInfo)) {
608 fprintf(stderr, "error: ioctl(FBIOGET_FSCREENINFO) failed: %s\n",
609 strerror(errno));
610 return GL_FALSE;
611 }
612
613 if (dpy->FixedInfo.visual != FB_VISUAL_TRUECOLOR &&
614 dpy->FixedInfo.visual != FB_VISUAL_DIRECTCOLOR) {
615 fprintf(stderr, "non-TRUECOLOR visuals not supported.\n");
616 return GL_FALSE;
617 }
618
619 if (dpy->FixedInfo.visual == FB_VISUAL_DIRECTCOLOR) {
620 struct fb_cmap cmap;
621 unsigned short red[256], green[256], blue[256];
622 int rcols = 1 << dpy->VarInfo.red.length;
623 int gcols = 1 << dpy->VarInfo.green.length;
624 int bcols = 1 << dpy->VarInfo.blue.length;
625 int i;
626
627 cmap.start = 0;
628 cmap.len = gcols;
629 cmap.red = red;
630 cmap.green = green;
631 cmap.blue = blue;
632 cmap.transp = NULL;
633
634 for (i = 0; i < rcols ; i++)
635 red[i] = (65536/(rcols-1)) * i;
636
637 for (i = 0; i < gcols ; i++)
638 green[i] = (65536/(gcols-1)) * i;
639
640 for (i = 0; i < bcols ; i++)
641 blue[i] = (65536/(bcols-1)) * i;
642
643 if (ioctl(dpy->FrameBufferFD, FBIOPUTCMAP, (void *) &cmap) < 0) {
644 fprintf(stderr, "ioctl(FBIOPUTCMAP) failed [%d]\n", i);
645 exit(1);
646 }
647 }
648
649 /* May need to restore regs fbdev has clobbered:
650 */
651 if (!dpy->driver->postValidateMode( &dpy->driverContext )) {
652 fprintf(stderr, "Driver postValidateMode() failed\n");
653 return 0;
654 }
655
656 return GL_TRUE;
657 }
658
659
660 /**
661 * \brief Restore the framebuffer device to state it was in before we started
662 *
663 * Undoes the work done by SetupFBDev().
664 *
665 * \param dpy the display handle.
666 *
667 * \return GL_TRUE on success, or GL_FALSE on failure.
668 *
669 * \sa Called from XDestroyWindow().
670 *
671 * \internal
672 * Restores the original variable screen info.
673 */
674 static GLboolean
675 RestoreFBDev( Display *dpy )
676 {
677 /* restore original variable screen info */
678 if (ioctl(dpy->FrameBufferFD, FBIOPUT_VSCREENINFO, &dpy->OrigVarInfo)) {
679 fprintf(stderr, "ioctl(FBIOPUT_VSCREENINFO failed): %s\n",
680 strerror(errno));
681 return GL_FALSE;
682 }
683 dpy->VarInfo = dpy->OrigVarInfo;
684
685 return GL_TRUE;
686 }
687
688
689 /**
690 * \brief Close the framebuffer device.
691 *
692 * \param dpy the display handle.
693 *
694 * \sa Called from XCloseDisplay().
695 *
696 * \internal
697 * Unmaps the framebuffer and MMIO region. Restores the text mode and the
698 * original virtual terminal. Closes the console and framebuffer devices.
699 */
700 static void
701 CloseFBDev( Display *dpy )
702 {
703 struct vt_mode VT;
704
705 munmap(dpy->driverContext.FBAddress, dpy->driverContext.FBSize);
706 munmap(dpy->driverContext.MMIOAddress, dpy->driverContext.MMIOSize);
707
708 if (dpy->ConsoleFD) {
709 /* restore text mode */
710 ioctl(dpy->ConsoleFD, KDSETMODE, KD_TEXT);
711
712 /* set vt */
713 if (ioctl(dpy->ConsoleFD, VT_GETMODE, &VT) != -1) {
714 VT.mode = VT_AUTO;
715 ioctl(dpy->ConsoleFD, VT_SETMODE, &VT);
716 }
717
718 /* restore original vt */
719 if (dpy->OriginalVT >= 0) {
720 ioctl(dpy->ConsoleFD, VT_ACTIVATE, dpy->OriginalVT);
721 dpy->OriginalVT = -1;
722 }
723
724 close(dpy->ConsoleFD);
725 }
726 close(dpy->FrameBufferFD);
727 }
728
729 /*@}*/
730
731
732 /**********************************************************************/
733 /** \name Misc functions needed for DRI drivers */
734 /**********************************************************************/
735 /*@{*/
736
737 /**
738 * \brief Find the DRI screen dependent methods associated with the display.
739 *
740 * \param dpy a display handle, as returned by XOpenDisplay().
741 * \param scrn the screen number. Not referenced.
742 *
743 * \returns a pointer to a __DRIscreenRec structure.
744 *
745 * \internal
746 * Returns the MiniGLXDisplayRec::driScreen attribute.
747 */
748 static __DRIscreen *
749 __glXFindDRIScreen(__DRInativeDisplay *dpy, int scrn)
750 {
751 (void) scrn;
752 return &((Display*)dpy)->driScreen;
753 }
754
755 /**
756 * \brief Validate a drawable.
757 *
758 * \param dpy a display handle, as returned by XOpenDisplay().
759 * \param draw drawable to validate.
760 *
761 * \internal
762 * Since Mini GLX only supports one window, compares the specified drawable with
763 * the MiniGLXDisplayRec::TheWindow attribute.
764 */
765 static GLboolean
766 __glXWindowExists(__DRInativeDisplay *dpy, __DRIid draw)
767 {
768 const Display * const display = (Display*)dpy;
769 if (display->TheWindow == (Window) draw)
770 return True;
771 else
772 return False;
773 }
774
775 /**
776 * \brief Get current thread ID.
777 *
778 * \return thread ID.
779 *
780 * \internal
781 * Always returns 0.
782 */
783 /*unsigned long
784 _glthread_GetID(void)
785 {
786 return 0;
787 }*/
788
789 /*@}*/
790
791
792 /**
793 * \brief Scan Linux /prog/bus/pci/devices file to determine hardware
794 * chipset based on supplied bus ID.
795 *
796 * \return probed chipset (non-zero) on success, zero otherwise.
797 *
798 * \internal
799 */
800 static int get_chipset_from_busid( Display *dpy )
801 {
802 char buf[0x200];
803 FILE *file;
804 const char *fname = "/proc/bus/pci/devices";
805 int retval = 0;
806
807 if (!(file = fopen(fname,"r"))) {
808 fprintf(stderr, "couldn't open %s: %s\n", fname, strerror(errno));
809 return 0;
810 }
811
812 while (fgets(buf, sizeof(buf)-1, file)) {
813 unsigned int nr, bus, dev, fn, vendor, device, encode;
814 nr = sscanf(buf, "%04x\t%04x%04x", &encode,
815 &vendor, &device);
816
817 bus = encode >> 8;
818 dev = (encode & 0xFF) >> 3;
819 fn = encode & 0x7;
820
821 if (nr != 3)
822 break;
823
824 if (bus == dpy->driverContext.pciBus &&
825 dev == dpy->driverContext.pciDevice &&
826 fn == dpy->driverContext.pciFunc) {
827 retval = device;
828 break;
829 }
830 }
831
832 fclose(file);
833
834 if (retval)
835 fprintf(stderr, "[miniglx] probed chipset 0x%x\n", retval);
836 else
837 fprintf(stderr, "[miniglx] failed to probe chipset\n");
838
839 return retval;
840 }
841
842
843 /**
844 * \brief Read settings from a configuration file.
845 *
846 * The configuration file is usually "/etc/miniglx.conf", but can be overridden
847 * with the MINIGLX_CONF environment variable.
848 *
849 * The format consists in \code option = value \endcode lines. The option names
850 * corresponds to the fields in MiniGLXDisplayRec.
851 *
852 * \param dpy the display handle as.
853 *
854 * \return non-zero on success, zero otherwise.
855 *
856 * \internal
857 * Sets some defaults. Opens and parses the the Mini GLX configuration file and
858 * fills in the MiniGLXDisplayRec field that corresponds for each option.
859 */
860 static int __read_config_file( Display *dpy )
861 {
862 FILE *file;
863 const char *fname;
864
865 /* Fallback/defaults
866 */
867 dpy->fbdevDevice = "/dev/fb0";
868 dpy->clientDriverName = "fb_dri.so";
869 dpy->driverContext.pciBus = 0;
870 dpy->driverContext.pciDevice = 0;
871 dpy->driverContext.pciFunc = 0;
872 dpy->driverContext.chipset = 0;
873 dpy->driverContext.pciBusID = 0;
874 dpy->driverContext.shared.virtualWidth = 1280;
875 dpy->driverContext.shared.virtualHeight = 1024;
876 dpy->driverContext.bpp = 32;
877 dpy->driverContext.cpp = 4;
878 dpy->rotateMode = 0;
879 dpy->driverContext.agpmode = 1;
880 dpy->driverContext.isPCI = 0;
881 dpy->driverContext.colorTiling = 0;
882
883 fname = getenv("MINIGLX_CONF");
884 if (!fname) fname = "/etc/miniglx.conf";
885
886 file = fopen(fname, "r");
887 if (!file) {
888 fprintf(stderr, "couldn't open config file %s: %s\n", fname, strerror(errno));
889 return 0;
890 }
891
892
893 while (!feof(file)) {
894 char buf[81], *opt = buf, *val, *tmp1, *tmp2;
895 fgets(buf, sizeof(buf), file);
896
897 /* Parse 'opt = val' -- must be easier ways to do this.
898 */
899 while (isspace(*opt)) opt++;
900 val = opt;
901 if (*val == '#') continue; /* comment */
902 while (!isspace(*val) && *val != '=' && *val) val++;
903 tmp1 = val;
904 while (isspace(*val)) val++;
905 if (*val != '=') continue;
906 *tmp1 = 0;
907 val++;
908 while (isspace(*val)) val++;
909 tmp2 = val;
910 while (!isspace(*tmp2) && *tmp2 != '\n' && *tmp2) tmp2++;
911 *tmp2 = 0;
912
913
914 if (strcmp(opt, "fbdevDevice") == 0)
915 dpy->fbdevDevice = strdup(val);
916 else if (strcmp(opt, "clientDriverName") == 0)
917 dpy->clientDriverName = strdup(val);
918 else if (strcmp(opt, "rotateMode") == 0)
919 dpy->rotateMode = atoi(val) ? 1 : 0;
920 else if (strcmp(opt, "pciBusID") == 0) {
921 if (sscanf(val, "PCI:%d:%d:%d",
922 &dpy->driverContext.pciBus,
923 &dpy->driverContext.pciDevice,
924 &dpy->driverContext.pciFunc) != 3) {
925 fprintf(stderr, "malformed bus id: %s\n", val);
926 continue;
927 }
928 dpy->driverContext.pciBusID = strdup(val);
929 }
930 else if (strcmp(opt, "chipset") == 0) {
931 if (sscanf(val, "0x%x", &dpy->driverContext.chipset) != 1)
932 fprintf(stderr, "malformed chipset: %s\n", opt);
933 }
934 else if (strcmp(opt, "virtualWidth") == 0) {
935 if (sscanf(val, "%d", &dpy->driverContext.shared.virtualWidth) != 1)
936 fprintf(stderr, "malformed virtualWidth: %s\n", opt);
937 }
938 else if (strcmp(opt, "virtualHeight") == 0) {
939 if (sscanf(val, "%d", &dpy->driverContext.shared.virtualHeight) != 1)
940 fprintf(stderr, "malformed virutalHeight: %s\n", opt);
941 }
942 else if (strcmp(opt, "bpp") == 0) {
943 if (sscanf(val, "%d", &dpy->driverContext.bpp) != 1)
944 fprintf(stderr, "malformed bpp: %s\n", opt);
945 dpy->driverContext.cpp = dpy->driverContext.bpp / 8;
946 }
947 else if (strcmp(opt, "agpmode") == 0) {
948 if (sscanf(val, "%d", &dpy->driverContext.agpmode) != 1)
949 fprintf(stderr, "malformed agpmode: %s\n", opt);
950 }
951 else if (strcmp(opt, "isPCI") == 0) {
952 dpy->driverContext.isPCI = atoi(val) ? 1 : 0;
953 }
954 else if (strcmp(opt, "colorTiling") == 0) {
955 dpy->driverContext.colorTiling = atoi(val) ? 1 : 0;
956 }
957 }
958
959 fclose(file);
960
961 if (dpy->driverContext.chipset == 0 && dpy->driverContext.pciBusID != 0)
962 dpy->driverContext.chipset = get_chipset_from_busid( dpy );
963
964 return 1;
965 }
966
967 /**
968 * Versioned name of the expected \c __driCreateNewScreen function.
969 *
970 * The version of the last incompatible loader/driver inteface change is
971 * appended to the name of the \c __driCreateNewScreen function. This
972 * prevents loaders from trying to load drivers that are too old.
973 *
974 * \todo
975 * Create a macro or something so that this is automatically updated.
976 */
977 static const char createNewScreenName[] = "__driCreateNewScreen_20050727";
978
979
980 static int InitDriver( Display *dpy )
981 {
982 /*
983 * Begin DRI setup.
984 * We're kind of combining the per-display and per-screen information
985 * which was kept separate in XFree86/DRI's libGL.
986 */
987 dpy->dlHandle = dlopen(dpy->clientDriverName, RTLD_NOW | RTLD_GLOBAL);
988 if (!dpy->dlHandle) {
989 fprintf(stderr, "Unable to open %s: %s\n", dpy->clientDriverName,
990 dlerror());
991 goto failed;
992 }
993
994 /* Pull in Mini GLX specific hooks:
995 */
996 dpy->driver = (struct DRIDriverRec *) dlsym(dpy->dlHandle,
997 "__driDriver");
998 if (!dpy->driver) {
999 fprintf(stderr, "Couldn't find __driDriver in %s\n",
1000 dpy->clientDriverName);
1001 goto failed;
1002 }
1003
1004 /* Pull in standard DRI client-side driver hooks:
1005 */
1006 dpy->createNewScreen = (PFNCREATENEWSCREENFUNC)
1007 dlsym(dpy->dlHandle, createNewScreenName);
1008 if (!dpy->createNewScreen) {
1009 fprintf(stderr, "Couldn't find %s in %s\n", createNewScreenName,
1010 dpy->clientDriverName);
1011 goto failed;
1012 }
1013
1014 return GL_TRUE;
1015
1016 failed:
1017 if (dpy->dlHandle) {
1018 dlclose(dpy->dlHandle);
1019 dpy->dlHandle = 0;
1020 }
1021 return GL_FALSE;
1022 }
1023
1024
1025 /**********************************************************************/
1026 /** \name Public API functions (Xlib and GLX) */
1027 /**********************************************************************/
1028 /*@{*/
1029
1030
1031 /**
1032 * \brief Initialize the graphics system.
1033 *
1034 * \param display_name currently ignored. It is recommended to pass it as NULL.
1035 * \return a pointer to a #Display if the function is able to initialize
1036 * the graphics system, NULL otherwise.
1037 *
1038 * Allocates a MiniGLXDisplayRec structure and fills in with information from a
1039 * configuration file.
1040 *
1041 * Calls OpenFBDev() to open the framebuffer device and calls
1042 * DRIDriverRec::initFBDev to do the client-side initialization on it.
1043 *
1044 * Loads the DRI driver and pulls in Mini GLX specific hooks into a
1045 * DRIDriverRec structure, and the standard DRI \e __driCreateScreen hook.
1046 * Asks the driver for a list of supported visuals. Performs the per-screen
1047 * client-side initialization. Also setups the callbacks in the screen private
1048 * information.
1049 *
1050 * Does the framebuffer device setup. Calls __miniglx_open_connections() to
1051 * serve clients.
1052 */
1053 Display *
1054 __miniglx_StartServer( const char *display_name )
1055 {
1056 Display *dpy;
1057 int use_vt = 0;
1058
1059 dpy = (Display *)calloc(1, sizeof(Display));
1060 if (!dpy)
1061 return NULL;
1062
1063 dpy->IsClient = False;
1064
1065 if (!__read_config_file( dpy )) {
1066 fprintf(stderr, "Couldn't get configuration details\n");
1067 free(dpy);
1068 return NULL;
1069 }
1070
1071 /* Open the fbdev device
1072 */
1073 if (!OpenFBDev(dpy, use_vt)) {
1074 fprintf(stderr, "OpenFBDev failed\n");
1075 free(dpy);
1076 return NULL;
1077 }
1078
1079 if (!InitDriver(dpy)) {
1080 fprintf(stderr, "InitDriver failed\n");
1081 free(dpy);
1082 return NULL;
1083 }
1084
1085 /* Perform the initialization normally done in the X server
1086 */
1087 if (!dpy->driver->initFBDev( &dpy->driverContext )) {
1088 fprintf(stderr, "%s: __driInitFBDev failed\n", __FUNCTION__);
1089 dlclose(dpy->dlHandle);
1090 return GL_FALSE;
1091 }
1092
1093 /* do fbdev setup
1094 */
1095 if (!SetupFBDev(dpy)) {
1096 fprintf(stderr, "SetupFBDev failed\n");
1097 free(dpy);
1098 return NULL;
1099 }
1100
1101 /* unlock here if not using VT -- JDS */
1102 if (!use_vt) {
1103 if (dpy->driver->restoreHardware)
1104 dpy->driver->restoreHardware( &dpy->driverContext );
1105 DRM_UNLOCK( dpy->driverContext.drmFD,
1106 dpy->driverContext.pSAREA,
1107 dpy->driverContext.serverContext );
1108 dpy->hwActive = 1;
1109 }
1110
1111 /* Ready for clients:
1112 */
1113 if (!__miniglx_open_connections(dpy)) {
1114 free(dpy);
1115 return NULL;
1116 }
1117
1118 return dpy;
1119 }
1120
1121
1122 /**
1123 * Implement \c __DRIinterfaceMethods::getProcAddress.
1124 */
1125 static __DRIfuncPtr get_proc_address( const char * proc_name )
1126 {
1127 (void) proc_name;
1128 return NULL;
1129 }
1130
1131
1132 /**
1133 * Table of functions exported by the loader to the driver.
1134 */
1135 static const __DRIinterfaceMethods interface_methods = {
1136 get_proc_address,
1137
1138 _gl_context_modes_create,
1139 _gl_context_modes_destroy,
1140
1141 __glXFindDRIScreen,
1142 __glXWindowExists,
1143
1144 __glXCreateContextWithConfig,
1145 xf86DRI_DestroyContext,
1146
1147 xf86DRI_CreateDrawable,
1148 xf86DRI_DestroyDrawable,
1149 __glXGetDrawableInfo,
1150
1151 __glXGetUST,
1152 __glXGetMscRate,
1153 };
1154
1155
1156 static void *
1157 CallCreateNewScreen(Display *dpy, int scrn, __DRIscreen *psc)
1158 {
1159 void *psp = NULL;
1160 drm_handle_t hSAREA;
1161 drmAddress pSAREA;
1162 const char *BusID;
1163 int i;
1164 __DRIversion ddx_version;
1165 __DRIversion dri_version;
1166 __DRIversion drm_version;
1167 __DRIframebuffer framebuffer;
1168 int fd = -1;
1169 int status;
1170 const char * err_msg;
1171 const char * err_extra;
1172 drmVersionPtr version;
1173 drm_handle_t hFB;
1174 drm_magic_t magic;
1175
1176
1177 hSAREA = dpy->driverContext.shared.hSAREA;
1178 BusID = dpy->driverContext.pciBusID;
1179
1180 fd = drmOpen(NULL, BusID);
1181
1182 err_msg = "open DRM";
1183 err_extra = strerror( -fd );
1184
1185 if (fd < 0) goto done;
1186
1187 err_msg = "drmGetMagic";
1188 err_extra = NULL;
1189
1190 if (drmGetMagic(fd, &magic)) goto done;
1191
1192 dpy->authorized = False;
1193 send_char_msg( dpy, 0, _Authorize );
1194 send_msg( dpy, 0, &magic, sizeof(magic));
1195
1196 /* force net buffer flush */
1197 while (!dpy->authorized)
1198 handle_fd_events( dpy, 0 );
1199
1200 version = drmGetVersion(fd);
1201 if (version) {
1202 drm_version.major = version->version_major;
1203 drm_version.minor = version->version_minor;
1204 drm_version.patch = version->version_patchlevel;
1205 drmFreeVersion(version);
1206 }
1207 else {
1208 drm_version.major = -1;
1209 drm_version.minor = -1;
1210 drm_version.patch = -1;
1211 }
1212
1213 /*
1214 * Get device name (like "tdfx") and the ddx version numbers.
1215 * We'll check the version in each DRI driver's "createScreen"
1216 * function.
1217 */
1218 ddx_version.major = 4;
1219 ddx_version.minor = 0;
1220 ddx_version.patch = 0;
1221
1222 /*
1223 * Get the DRI X extension version.
1224 */
1225 dri_version.major = 4;
1226 dri_version.minor = 0;
1227 dri_version.patch = 0;
1228
1229 /*
1230 * Get device-specific info. pDevPriv will point to a struct
1231 * (such as DRIRADEONRec in xfree86/driver/ati/radeon_dri.h)
1232 * that has information about the screen size, depth, pitch,
1233 * ancilliary buffers, DRM mmap handles, etc.
1234 */
1235 hFB = dpy->driverContext.shared.hFrameBuffer;
1236 framebuffer.size = dpy->driverContext.shared.fbSize;
1237 framebuffer.stride = dpy->driverContext.shared.fbStride;
1238 framebuffer.dev_priv_size = dpy->driverContext.driverClientMsgSize;
1239 framebuffer.dev_priv = dpy->driverContext.driverClientMsg;
1240 framebuffer.width = dpy->driverContext.shared.virtualWidth;
1241 framebuffer.height = dpy->driverContext.shared.virtualHeight;
1242
1243 /*
1244 * Map the framebuffer region.
1245 */
1246 status = drmMap(fd, hFB, framebuffer.size,
1247 (drmAddressPtr)&framebuffer.base);
1248
1249 err_msg = "drmMap of framebuffer";
1250 err_extra = strerror( -status );
1251
1252 if ( status != 0 ) goto done;
1253
1254 /*
1255 * Map the SAREA region. Further mmap regions may be setup in
1256 * each DRI driver's "createScreen" function.
1257 */
1258 status = drmMap(fd, hSAREA, SAREA_MAX, &pSAREA);
1259
1260 err_msg = "drmMap of sarea";
1261 err_extra = strerror( -status );
1262
1263 if ( status == 0 ) {
1264 err_msg = "InitDriver";
1265 err_extra = NULL;
1266 psp = dpy->createNewScreen(dpy, scrn, psc, NULL,
1267 & ddx_version,
1268 & dri_version,
1269 & drm_version,
1270 & framebuffer,
1271 pSAREA,
1272 fd,
1273 20050727,
1274 & interface_methods,
1275 (__GLcontextModes **) &dpy->driver_modes);
1276
1277 /* fill in dummy visual ids */
1278 {
1279 __GLcontextModes *temp;
1280 temp = (__GLcontextModes *)dpy->driver_modes;
1281 i = 1;
1282 while (temp)
1283 {
1284 temp->visualID = i++;
1285 temp=temp->next;
1286 }
1287 }
1288 }
1289
1290 done:
1291 if ( psp == NULL ) {
1292 if ( pSAREA != MAP_FAILED ) {
1293 (void)drmUnmap(pSAREA, SAREA_MAX);
1294 }
1295
1296 if ( framebuffer.base != MAP_FAILED ) {
1297 (void)drmUnmap((drmAddress)framebuffer.base, framebuffer.size);
1298 }
1299
1300 if ( framebuffer.dev_priv != NULL ) {
1301 free(framebuffer.dev_priv);
1302 }
1303
1304 if ( fd >= 0 ) {
1305 (void)drmClose(fd);
1306 }
1307
1308 if ( err_extra != NULL ) {
1309 fprintf(stderr, "libGL error: %s failed (%s)\n", err_msg,
1310 err_extra);
1311 }
1312 else {
1313 fprintf(stderr, "libGL error: %s failed\n", err_msg );
1314 }
1315
1316 fprintf(stderr, "libGL error: reverting to (slow) indirect rendering\n");
1317 }
1318
1319 return psp;
1320 }
1321
1322 /**
1323 * \brief Initialize the graphics system.
1324 *
1325 * \param display_name currently ignored. It is recommended to pass it as NULL.
1326 * \return a pointer to a #Display if the function is able to initialize
1327 * the graphics system, NULL otherwise.
1328 *
1329 * Allocates a MiniGLXDisplayRec structure and fills in with information from a
1330 * configuration file.
1331 *
1332 * Calls __miniglx_open_connections() to connect to the server.
1333 *
1334 * Loads the DRI driver and pulls in Mini GLX specific hooks into a
1335 * DRIDriverRec structure, and the standard DRI \e __driCreateScreen hook.
1336 * Asks the driver for a list of supported visuals. Performs the per-screen
1337 * client-side initialization. Also setups the callbacks in the screen private
1338 * information.
1339 *
1340 * \todo
1341 * - read config file
1342 * - what about virtualWidth, etc?
1343 * - determine dpy->driverClientMsgSize,
1344 * - allocate dpy->driverClientMsg
1345 */
1346 Display *
1347 XOpenDisplay( const char *display_name )
1348 {
1349 Display *dpy;
1350
1351 dpy = (Display *)calloc(1, sizeof(Display));
1352 if (!dpy)
1353 return NULL;
1354
1355 dpy->IsClient = True;
1356
1357 /* read config file
1358 */
1359 if (!__read_config_file( dpy )) {
1360 fprintf(stderr, "Couldn't get configuration details\n");
1361 free(dpy);
1362 return NULL;
1363 }
1364
1365 /* Connect to the server and receive driverClientMsg
1366 */
1367 if (!__miniglx_open_connections(dpy)) {
1368 free(dpy);
1369 return NULL;
1370 }
1371
1372 /* dlopen the driver .so file
1373 */
1374 if (!InitDriver(dpy)) {
1375 fprintf(stderr, "InitDriver failed\n");
1376 free(dpy);
1377 return NULL;
1378 }
1379
1380 /* Perform the client-side initialization.
1381 *
1382 * Clearly there is a limit of one on the number of windows in
1383 * existence at any time.
1384 *
1385 * Need to shut down DRM and free DRI data in XDestroyWindow(), too.
1386 */
1387 dpy->driScreen.private = CallCreateNewScreen(dpy, 0, &dpy->driScreen);
1388 if (!dpy->driScreen.private) {
1389 fprintf(stderr, "%s: __driCreateScreen failed\n", __FUNCTION__);
1390 dlclose(dpy->dlHandle);
1391 free(dpy);
1392 return NULL;
1393 }
1394
1395 /* Anything more to do?
1396 */
1397 return dpy;
1398 }
1399
1400
1401 /**
1402 * \brief Release display resources.
1403 *
1404 * When the application is about to exit, the resources associated with the
1405 * graphics system can be released by calling this function.
1406 *
1407 * \param dpy display handle. It becomes invalid at this point.
1408 *
1409 * Destroys the window if any, and destroys the per-screen
1410 * driver private information.
1411 * Calls __miniglx_close_connections().
1412 *
1413 * If a server, puts the the framebuffer back into the initial state.
1414 *
1415 * Finally frees the display structure.
1416 */
1417 void
1418 XCloseDisplay( Display *dpy )
1419 {
1420 glXMakeCurrent( dpy, NULL, NULL);
1421
1422 if (dpy->NumWindows)
1423 XDestroyWindow( dpy, dpy->TheWindow );
1424
1425 /* As this is done in XOpenDisplay, need to undo it here:
1426 */
1427 dpy->driScreen.destroyScreen(dpy, 0, dpy->driScreen.private);
1428
1429 __miniglx_close_connections( dpy );
1430
1431 if (!dpy->IsClient) {
1432 /* put framebuffer back to initial state
1433 */
1434 (*dpy->driver->haltFBDev)( &dpy->driverContext );
1435 RestoreFBDev(dpy);
1436 CloseFBDev(dpy);
1437 }
1438
1439 dlclose(dpy->dlHandle);
1440 free(dpy);
1441 }
1442
1443
1444 /**
1445 * \brief Window creation.
1446 *
1447 * \param display a display handle, as returned by XOpenDisplay().
1448 * \param parent the parent window for the new window. For Mini GLX this should
1449 * be
1450 * \code RootWindow(display, 0) \endcode
1451 * \param x the window abscissa. For Mini GLX, it should be zero.
1452 * \param y the window ordinate. For Mini GLX, it should be zero.
1453 * \param width the window width. For Mini GLX, this specifies the desired
1454 * screen width such as 1024 or 1280.
1455 * \param height the window height. For Mini GLX, this specifies the desired
1456 * screen height such as 768 or 1024.
1457 * \param border_width the border width. For Mini GLX, it should be zero.
1458 * \param depth the window pixel depth. For Mini GLX, this should be the depth
1459 * found in the #XVisualInfo object returned by glXChooseVisual()
1460 * \param winclass the window class. For Mini GLX this value should be
1461 * #InputOutput.
1462 * \param visual the visual type. It should be the visual field of the
1463 * #XVisualInfo object returned by glXChooseVisual().
1464 * \param valuemask which fields of the XSetWindowAttributes() are to be used.
1465 * For Mini GLX this is typically the bitmask
1466 * \code CWBackPixel | CWBorderPixel | CWColormap \endcode
1467 * \param attributes initial window attributes. The
1468 * XSetWindowAttributes::background_pixel, XSetWindowAttributes::border_pixel
1469 * and XSetWindowAttributes::colormap fields should be set.
1470 *
1471 * \return a window handle if it succeeds or zero if it fails.
1472 *
1473 * \note For Mini GLX, windows are full-screen; they cover the entire frame
1474 * buffer. Also, Mini GLX imposes a limit of one window. A second window
1475 * cannot be created until the first one is destroyed.
1476 *
1477 * This function creates and initializes a ::MiniGLXWindowRec structure after
1478 * ensuring that there is no other window created. Performs the per-drawable
1479 * client-side initialization calling the __DRIscreenRec::createDrawable
1480 * method.
1481 *
1482 */
1483 Window
1484 XCreateWindow( Display *dpy, Window parent, int x, int y,
1485 unsigned int width, unsigned int height,
1486 unsigned int border_width, int depth, unsigned int winclass,
1487 Visual *visual, unsigned long valuemask,
1488 XSetWindowAttributes *attributes )
1489 {
1490 const int empty_attribute_list[1] = { None };
1491
1492 Window win;
1493
1494 /* ignored */
1495 (void) x;
1496 (void) y;
1497 (void) border_width;
1498 (void) depth;
1499 (void) winclass;
1500 (void) valuemask;
1501 (void) attributes;
1502
1503 if (!dpy->IsClient) {
1504 fprintf(stderr, "Server process may not create windows (currently)\n");
1505 return NULL;
1506 }
1507
1508 if (dpy->NumWindows > 0)
1509 return NULL; /* only allow one window */
1510
1511 assert(dpy->TheWindow == NULL);
1512
1513 win = malloc(sizeof(struct MiniGLXWindowRec));
1514 if (!win)
1515 return NULL;
1516
1517 /* In rotated mode, translate incoming x,y,width,height into
1518 * 'normal' coordinates.
1519 */
1520 if (dpy->rotateMode) {
1521 int tmp;
1522 tmp = width; width = height; height = tmp;
1523 tmp = x; x = y; y = tmp;
1524 }
1525
1526 /* init other per-window fields */
1527 win->x = 0;
1528 win->y = 0;
1529 win->w = width;
1530 win->h = height;
1531 win->visual = visual; /* ptr assignment */
1532
1533 win->bytesPerPixel = dpy->driverContext.cpp;
1534 win->rowStride = dpy->driverContext.shared.virtualWidth * win->bytesPerPixel;
1535 win->size = win->rowStride * height;
1536 win->frontStart = dpy->driverContext.FBAddress;
1537 win->frontBottom = (GLubyte *) win->frontStart + (height-1) * win->rowStride;
1538
1539 /* This is incorrect: the hardware driver could put the backbuffer
1540 * just about anywhere. These fields, including the above are
1541 * hardware dependent & don't really belong here.
1542 */
1543 if (visual->mode->doubleBufferMode) {
1544 win->backStart = (GLubyte *) win->frontStart +
1545 win->rowStride * dpy->driverContext.shared.virtualHeight;
1546 win->backBottom = (GLubyte *) win->backStart
1547 + (height - 1) * win->rowStride;
1548 win->curBottom = win->backBottom;
1549 }
1550 else {
1551 /* single buffered */
1552 win->backStart = NULL;
1553 win->backBottom = NULL;
1554 win->curBottom = win->frontBottom;
1555 }
1556
1557 dpy->driScreen.createNewDrawable(dpy, visual->mode, (int) win,
1558 &win->driDrawable, GLX_WINDOW_BIT, empty_attribute_list);
1559
1560 if (!win->driDrawable.private) {
1561 fprintf(stderr, "%s: dri.createDrawable failed\n", __FUNCTION__);
1562 free(win);
1563 return NULL;
1564 }
1565
1566 dpy->NumWindows++;
1567 dpy->TheWindow = win;
1568
1569 return win;
1570 }
1571
1572
1573 /**
1574 * \brief Destroy window.
1575 *
1576 * \param display display handle.
1577 * \param w window handle.
1578 *
1579 * This function calls XUnmapWindow() and frees window \p w.
1580 *
1581 * In case of destroying the current buffer first unbinds the GLX context
1582 * by calling glXMakeCurrent() with no drawable.
1583 */
1584 void
1585 XDestroyWindow( Display *display, Window win )
1586 {
1587 if (display && display->IsClient && win) {
1588 /* check if destroying the current buffer */
1589 Window curDraw = glXGetCurrentDrawable();
1590 if (win == curDraw) {
1591 glXMakeCurrent( display, NULL, NULL);
1592 }
1593
1594 XUnmapWindow( display, win );
1595
1596 /* Destroy the drawable. */
1597 win->driDrawable.destroyDrawable(display, win->driDrawable.private);
1598 free(win);
1599
1600 /* unlink window from display */
1601 display->NumWindows--;
1602 assert(display->NumWindows == 0);
1603 display->TheWindow = NULL;
1604 }
1605 }
1606
1607
1608
1609
1610 /**
1611 * \brief Create color map structure.
1612 *
1613 * \param dpy the display handle as returned by XOpenDisplay().
1614 * \param w the window on whose screen you want to create a color map. This
1615 * parameter is ignored by Mini GLX but should be the value returned by the
1616 * \code RootWindow(display, 0) \endcode macro.
1617 * \param visual a visual type supported on the screen. This parameter is
1618 * ignored by Mini GLX but should be the XVisualInfo::visual returned by
1619 * glXChooseVisual().
1620 * \param alloc the color map entries to be allocated. This parameter is ignored
1621 * by Mini GLX but should be set to #AllocNone.
1622 *
1623 * \return the color map.
1624 *
1625 * This function is only provided to ease porting. Practically a no-op -
1626 * returns a pointer to a dynamically allocated chunk of memory (one byte).
1627 */
1628 Colormap
1629 XCreateColormap( Display *dpy, Window w, Visual *visual, int alloc )
1630 {
1631 (void) dpy;
1632 (void) w;
1633 (void) visual;
1634 (void) alloc;
1635 return (Colormap) malloc(1);
1636 }
1637
1638
1639 /**
1640 * \brief Destroy color map structure.
1641 *
1642 * \param display The display handle as returned by XOpenDisplay().
1643 * \param colormap the color map to destroy.
1644 *
1645 * This function is only provided to ease porting. Practically a no-op.
1646 *
1647 * Frees the memory pointed by \p colormap.
1648 */
1649 void
1650 XFreeColormap( Display *display, Colormap colormap )
1651 {
1652 (void) display;
1653 (void) colormap;
1654 free(colormap);
1655 }
1656
1657
1658 /**
1659 * \brief Free client data.
1660 *
1661 * \param data the data that is to be freed.
1662 *
1663 * Frees the memory pointed by \p data.
1664 */
1665 void
1666 XFree( void *data )
1667 {
1668 free(data);
1669 }
1670
1671
1672 /**
1673 * \brief Query available visuals.
1674 *
1675 * \param dpy the display handle, as returned by XOpenDisplay().
1676 * \param vinfo_mask a bitmask indicating which fields of the \p vinfo_template
1677 * are to be matched. The value must be \c VisualScreenMask.
1678 * \param vinfo_template a template whose fields indicate which visual
1679 * attributes must be matched by the results. The XVisualInfo::screen field of
1680 * this structure must be zero.
1681 * \param nitens_return will hold the number of visuals returned.
1682 *
1683 * \return the address of an array of all available visuals.
1684 *
1685 * An example of using XGetVisualInfo() to get all available visuals follows:
1686 *
1687 * \code
1688 * XVisualInfo vinfo_template, *results;
1689 * int nitens_return;
1690 * Display *dpy = XOpenDisplay(NULL);
1691 * vinfo_template.screen = 0;
1692 * results = XGetVisualInfo(dpy, VisualScreenMask, &vinfo_template, &nitens_return);
1693 * \endcode
1694 *
1695 * Returns the list of all ::XVisualInfo available, one per
1696 * ::__GLcontextMode stored in MiniGLXDisplayRec::modes.
1697 */
1698 XVisualInfo *
1699 XGetVisualInfo( Display *dpy, long vinfo_mask, XVisualInfo *vinfo_template, int *nitens_return )
1700 {
1701 const __GLcontextModes *mode;
1702 XVisualInfo *results;
1703 Visual *visResults;
1704 int i, n=0;
1705
1706 // ASSERT(vinfo_mask == VisualScreenMask);
1707 ASSERT(vinfo_template.screen == 0);
1708
1709 if (vinfo_mask == VisualIDMask)
1710 {
1711 for ( mode = dpy->driver_modes ; mode != NULL ; mode= mode->next )
1712 if (mode->visualID == vinfo_template->visualid)
1713 n=1;
1714
1715 if (n==0)
1716 return NULL;
1717
1718 results = (XVisualInfo *)calloc(1, n * sizeof(XVisualInfo));
1719 if (!results) {
1720 *nitens_return = 0;
1721 return NULL;
1722 }
1723
1724 visResults = (Visual *)calloc(1, n * sizeof(Visual));
1725 if (!results) {
1726 free(results);
1727 *nitens_return = 0;
1728 return NULL;
1729 }
1730
1731 for ( mode = dpy->driver_modes ; mode != NULL ; mode= mode->next )
1732 if (mode->visualID == vinfo_template->visualid)
1733 {
1734 visResults[0].mode=mode;
1735 visResults[0].visInfo = results;
1736 visResults[0].dpy = dpy;
1737 if (dpy->driverContext.bpp == 32)
1738 visResults[0].pixelFormat = PF_B8G8R8A8; /* XXX: FIX ME */
1739 else
1740 visResults[0].pixelFormat = PF_B5G6R5; /* XXX: FIX ME */
1741
1742 results[0].visual = visResults;
1743 results[0].visualid = mode->visualID;
1744 #if defined(__cplusplus) || defined(c_plusplus)
1745 results[0].c_class = TrueColor;
1746 #else
1747 results[0].class = TrueColor;
1748 #endif
1749 results[0].depth = mode->redBits +
1750 mode->redBits +
1751 mode->redBits +
1752 mode->redBits;
1753 results[0].bits_per_rgb = dpy->driverContext.bpp;
1754
1755 }
1756
1757 }
1758 else // if (vinfo_mask == VisualScreenMask)
1759 {
1760 n = 0;
1761 for ( mode = dpy->driver_modes ; mode != NULL ; mode = mode->next )
1762 n++;
1763
1764 results = (XVisualInfo *)calloc(1, n * sizeof(XVisualInfo));
1765 if (!results) {
1766 *nitens_return = 0;
1767 return NULL;
1768 }
1769
1770 visResults = (Visual *)calloc(1, n * sizeof(Visual));
1771 if (!results) {
1772 free(results);
1773 *nitens_return = 0;
1774 return NULL;
1775 }
1776
1777 for ( mode = dpy->driver_modes, i = 0 ; mode != NULL ; mode = mode->next, i++ ) {
1778 visResults[i].mode = mode;
1779 visResults[i].visInfo = results + i;
1780 visResults[i].dpy = dpy;
1781
1782 if (dpy->driverContext.bpp == 32)
1783 visResults[i].pixelFormat = PF_B8G8R8A8; /* XXX: FIX ME */
1784 else
1785 visResults[i].pixelFormat = PF_B5G6R5; /* XXX: FIX ME */
1786
1787 results[i].visual = visResults + i;
1788 results[i].visualid = mode->visualID;
1789 #if defined(__cplusplus) || defined(c_plusplus)
1790 results[i].c_class = TrueColor;
1791 #else
1792 results[i].class = TrueColor;
1793 #endif
1794 results[i].depth = mode->redBits +
1795 mode->redBits +
1796 mode->redBits +
1797 mode->redBits;
1798 results[i].bits_per_rgb = dpy->driverContext.bpp;
1799 }
1800 }
1801 *nitens_return = n;
1802 return results;
1803 }
1804
1805
1806 /**
1807 * \brief Return a visual that matches specified attributes.
1808 *
1809 * \param dpy the display handle, as returned by XOpenDisplay().
1810 * \param screen the screen number. It is currently ignored by Mini GLX and
1811 * should be zero.
1812 * \param attribList a list of GLX attributes which describe the desired pixel
1813 * format. It is terminated by the token \c None.
1814 *
1815 * The attributes are as follows:
1816 * \arg GLX_USE_GL:
1817 * This attribute should always be present in order to maintain compatibility
1818 * with GLX.
1819 * \arg GLX_RGBA:
1820 * If present, only RGBA pixel formats will be considered. Otherwise, only
1821 * color index formats are considered.
1822 * \arg GLX_DOUBLEBUFFER:
1823 * if present, only double-buffered pixel formats will be chosen.
1824 * \arg GLX_RED_SIZE \e n:
1825 * Must be followed by a non-negative integer indicating the minimum number of
1826 * bits per red pixel component that is acceptable.
1827 * \arg GLX_GREEN_SIZE \e n:
1828 * Must be followed by a non-negative integer indicating the minimum number of
1829 * bits per green pixel component that is acceptable.
1830 * \arg GLX_BLUE_SIZE \e n:
1831 * Must be followed by a non-negative integer indicating the minimum number of
1832 * bits per blue pixel component that is acceptable.
1833 * \arg GLX_ALPHA_SIZE \e n:
1834 * Must be followed by a non-negative integer indicating the minimum number of
1835 * bits per alpha pixel component that is acceptable.
1836 * \arg GLX_STENCIL_SIZE \e n:
1837 * Must be followed by a non-negative integer indicating the minimum number of
1838 * bits per stencil value that is acceptable.
1839 * \arg GLX_DEPTH_SIZE \e n:
1840 * Must be followed by a non-negative integer indicating the minimum number of
1841 * bits per depth component that is acceptable.
1842 * \arg None:
1843 * This token is used to terminate the attribute list.
1844 *
1845 * \return a pointer to an #XVisualInfo object which most closely matches the
1846 * requirements of the attribute list. If there is no visual which matches the
1847 * request, \c NULL will be returned.
1848 *
1849 * \note Visuals with accumulation buffers are not available.
1850 *
1851 * This function searches the list of available visual configurations in
1852 * MiniGLXDisplayRec::configs for a configuration which best matches the GLX
1853 * attribute list parameter. A new ::XVisualInfo object is created which
1854 * describes the visual configuration. The match criteria is described in the
1855 * specification.
1856 */
1857 XVisualInfo*
1858 glXChooseVisual( Display *dpy, int screen, int *attribList )
1859 {
1860 const __GLcontextModes *mode;
1861 Visual *vis;
1862 XVisualInfo *visInfo;
1863 const int *attrib;
1864 GLboolean rgbFlag = GL_FALSE, dbFlag = GL_FALSE, stereoFlag = GL_FALSE;
1865 GLint redBits = 0, greenBits = 0, blueBits = 0, alphaBits = 0;
1866 GLint indexBits = 0, depthBits = 0, stencilBits = 0;
1867 GLint numSamples = 0;
1868 int i=0;
1869
1870 /*
1871 * XXX in the future, <screen> might be interpreted as a VT
1872 */
1873 ASSERT(dpy);
1874 ASSERT(screen == 0);
1875
1876 vis = (Visual *)calloc(1, sizeof(Visual));
1877 if (!vis)
1878 return NULL;
1879
1880 visInfo = (XVisualInfo *)malloc(sizeof(XVisualInfo));
1881 if (!visInfo) {
1882 free(vis);
1883 return NULL;
1884 }
1885
1886 visInfo->visual = vis;
1887 vis->visInfo = visInfo;
1888 vis->dpy = dpy;
1889
1890 /* parse the attribute list */
1891 for (attrib = attribList; attrib && *attrib != None; attrib++) {
1892 switch (attrib[0]) {
1893 case GLX_DOUBLEBUFFER:
1894 dbFlag = GL_TRUE;
1895 break;
1896 case GLX_RGBA:
1897 rgbFlag = GL_TRUE;
1898 break;
1899 case GLX_RED_SIZE:
1900 redBits = attrib[1];
1901 attrib++;
1902 break;
1903 case GLX_GREEN_SIZE:
1904 greenBits = attrib[1];
1905 attrib++;
1906 break;
1907 case GLX_BLUE_SIZE:
1908 blueBits = attrib[1];
1909 attrib++;
1910 break;
1911 case GLX_ALPHA_SIZE:
1912 alphaBits = attrib[1];
1913 attrib++;
1914 break;
1915 case GLX_STENCIL_SIZE:
1916 stencilBits = attrib[1];
1917 attrib++;
1918 break;
1919 case GLX_DEPTH_SIZE:
1920 depthBits = attrib[1];
1921 attrib++;
1922 break;
1923 #if 0
1924 case GLX_ACCUM_RED_SIZE:
1925 accumRedBits = attrib[1];
1926 attrib++;
1927 break;
1928 case GLX_ACCUM_GREEN_SIZE:
1929 accumGreenBits = attrib[1];
1930 attrib++;
1931 break;
1932 case GLX_ACCUM_BLUE_SIZE:
1933 accumBlueBits = attrib[1];
1934 attrib++;
1935 break;
1936 case GLX_ACCUM_ALPHA_SIZE:
1937 accumAlphaBits = attrib[1];
1938 attrib++;
1939 break;
1940 case GLX_LEVEL:
1941 /* ignored for now */
1942 break;
1943 #endif
1944 default:
1945 /* unexpected token */
1946 fprintf(stderr, "unexpected token in glXChooseVisual attrib list\n");
1947 free(vis);
1948 free(visInfo);
1949 return NULL;
1950 }
1951 }
1952
1953 /* search screen configs for suitable visual */
1954 (void) numSamples;
1955 (void) indexBits;
1956 (void) redBits;
1957 (void) greenBits;
1958 (void) blueBits;
1959 (void) alphaBits;
1960 (void) stereoFlag;
1961 for ( mode = dpy->driver_modes ; mode != NULL ; mode = mode->next ) {
1962 i++;
1963 if (mode->rgbMode == rgbFlag &&
1964 mode->doubleBufferMode == dbFlag &&
1965 mode->redBits >= redBits &&
1966 mode->greenBits >= greenBits &&
1967 mode->blueBits >= blueBits &&
1968 mode->alphaBits >= alphaBits &&
1969 mode->depthBits >= depthBits &&
1970 mode->stencilBits >= stencilBits) {
1971 /* found it */
1972 visInfo->visualid = i;
1973 vis->mode = mode;
1974 break;
1975 }
1976 }
1977 if (!vis->mode)
1978 return NULL;
1979
1980 /* compute depth and bpp */
1981 if (rgbFlag) {
1982 /* XXX maybe support depth 16 someday */
1983 #if defined(__cplusplus) || defined(c_plusplus)
1984 visInfo->c_class = TrueColor;
1985 #else
1986 visInfo->class = TrueColor;
1987 #endif
1988 visInfo->depth = dpy->driverContext.bpp;
1989 visInfo->bits_per_rgb = dpy->driverContext.bpp;
1990 if (dpy->driverContext.bpp == 32)
1991 vis->pixelFormat = PF_B8G8R8A8;
1992 else
1993 vis->pixelFormat = PF_B5G6R5;
1994 }
1995 else {
1996 /* color index mode */
1997 #if defined(__cplusplus) || defined(c_plusplus)
1998 visInfo->c_class = PseudoColor;
1999 #else
2000 visInfo->class = PseudoColor;
2001 #endif
2002 visInfo->depth = 8;
2003 visInfo->bits_per_rgb = 8; /* bits/pixel */
2004 vis->pixelFormat = PF_CI8;
2005 }
2006
2007 return visInfo;
2008 }
2009
2010
2011 /**
2012 * \brief Return information about GLX visuals.
2013 *
2014 * \param dpy the display handle, as returned by XOpenDisplay().
2015 * \param vis the visual to be queried, as returned by glXChooseVisual().
2016 * \param attrib the visual attribute to be returned.
2017 * \param value pointer to an integer in which the result of the query will be
2018 * stored.
2019 *
2020 * \return zero if no error occurs, \c GLX_INVALID_ATTRIBUTE if the attribute
2021 * parameter is invalid, or \c GLX_BAD_VISUAL if the \p vis parameter is
2022 * invalid.
2023 *
2024 * Returns the appropriate attribute of ::__GLXvisualConfig pointed by
2025 * MiniGLXVisualRec::glxConfig of XVisualInfo::visual.
2026 *
2027 * \sa data types.
2028 */
2029 int
2030 glXGetConfig( Display *dpy, XVisualInfo *vis, int attrib, int *value )
2031 {
2032 const __GLcontextModes *mode = vis->visual->mode;
2033 if (!mode) {
2034 *value = 0;
2035 return GLX_BAD_VISUAL;
2036 }
2037
2038 switch (attrib) {
2039 case GLX_USE_GL:
2040 *value = True;
2041 return 0;
2042 case GLX_RGBA:
2043 *value = mode->rgbMode;
2044 return 0;
2045 case GLX_DOUBLEBUFFER:
2046 *value = mode->doubleBufferMode;
2047 return 0;
2048 case GLX_RED_SIZE:
2049 *value = mode->redBits;
2050 return 0;
2051 case GLX_GREEN_SIZE:
2052 *value = mode->greenBits;
2053 return 0;
2054 case GLX_BLUE_SIZE:
2055 *value = mode->blueBits;
2056 return 0;
2057 case GLX_ALPHA_SIZE:
2058 *value = mode->alphaBits;
2059 return 0;
2060 case GLX_DEPTH_SIZE:
2061 *value = mode->depthBits;
2062 return 0;
2063 case GLX_STENCIL_SIZE:
2064 *value = mode->stencilBits;
2065 return 0;
2066 default:
2067 *value = 0;
2068 return GLX_BAD_ATTRIBUTE;
2069 }
2070 return 0;
2071 }
2072
2073
2074 /**
2075 * \brief Create a new GLX rendering context.
2076 *
2077 * \param dpy the display handle, as returned by XOpenDisplay().
2078 * \param vis the visual that defines the frame buffer resources available to
2079 * the rendering context, as returned by glXChooseVisual().
2080 * \param shareList If non-zero, texture objects and display lists are shared
2081 * with the named rendering context. If zero, texture objects and display lists
2082 * will (initially) be private to this context. They may be shared when a
2083 * subsequent context is created.
2084 * \param direct whether direct or indirect rendering is desired. For Mini GLX
2085 * this value is ignored but it should be set to \c True.
2086 *
2087 * \return a ::GLXContext handle if it succeeds or zero if it fails due to
2088 * invalid parameter or insufficient resources.
2089 *
2090 * This function creates and initializes a ::MiniGLXContextRec structure and
2091 * calls the __DRIscreenRec::createContext method to initialize the client
2092 * private data.
2093 */
2094 GLXContext
2095 glXCreateContext( Display *dpy, XVisualInfo *vis,
2096 GLXContext shareList, Bool direct )
2097 {
2098 GLXContext ctx;
2099 void *sharePriv;
2100
2101 ASSERT(vis);
2102
2103 ctx = (struct MiniGLXContextRec *)calloc(1, sizeof(struct MiniGLXContextRec));
2104 if (!ctx)
2105 return NULL;
2106
2107 ctx->vid = vis->visualid;
2108
2109 if (shareList)
2110 sharePriv = shareList->driContext.private;
2111 else
2112 sharePriv = NULL;
2113
2114 ctx->driContext.mode = vis->visual->mode;
2115 ctx->driContext.private = dpy->driScreen.createNewContext(dpy, vis->visual->mode,
2116 GLX_WINDOW_BIT, sharePriv, &ctx->driContext);
2117
2118 if (!ctx->driContext.private) {
2119 free(ctx);
2120 return NULL;
2121 }
2122
2123 return ctx;
2124 }
2125
2126
2127 /**
2128 * \brief Destroy a GLX context.
2129 *
2130 * \param dpy the display handle, as returned by XOpenDisplay().
2131 * \param ctx the GLX context to be destroyed.
2132 *
2133 * This function frees the \p ctx parameter after unbinding the current context
2134 * by calling the __DRIcontextRec::bindContext method with zeros and calling
2135 * the __DRIcontextRec::destroyContext method.
2136 */
2137 void
2138 glXDestroyContext( Display *dpy, GLXContext ctx )
2139 {
2140 GLXContext glxctx = glXGetCurrentContext();
2141
2142 if (ctx) {
2143 if (glxctx == ctx) {
2144 /* destroying current context */
2145 ctx->driContext.bindContext(dpy, 0, 0, 0, 0);
2146 CurrentContext = 0;
2147 }
2148 ctx->driContext.destroyContext(dpy, 0, ctx->driContext.private);
2149 free(ctx);
2150 }
2151 }
2152
2153
2154 /**
2155 * \brief Bind a GLX context to a window or a pixmap.
2156 *
2157 * \param dpy the display handle, as returned by XOpenDisplay().
2158 * \param drawable the window or drawable to bind to the rendering context.
2159 * This should be the value returned by XCreateWindow().
2160 * \param ctx the GLX context to be destroyed.
2161 *
2162 * \return \c True if it succeeds, \c False otherwise to indicate an invalid
2163 * display, window or context parameter.
2164 *
2165 * The current rendering context may be unbound by calling glXMakeCurrent()
2166 * with the window and context parameters set to zero.
2167 *
2168 * An application may create any number of rendering contexts and bind them as
2169 * needed. Note that binding a rendering context is generally not a
2170 * light-weight operation. Most simple OpenGL applications create only one
2171 * rendering context.
2172 *
2173 * This function first unbinds any old context via
2174 * __DRIcontextRec::unbindContext and binds the new one via
2175 * __DRIcontextRec::bindContext.
2176 *
2177 * If \p drawable is zero it unbinds the GLX context by calling
2178 * __DRIcontextRec::bindContext with zeros.
2179 */
2180 Bool
2181 glXMakeCurrent( Display *dpy, GLXDrawable drawable, GLXContext ctx)
2182 {
2183 if (dpy && drawable && ctx) {
2184 GLXContext oldContext = glXGetCurrentContext();
2185 GLXDrawable oldDrawable = glXGetCurrentDrawable();
2186 /* unbind old */
2187 if (oldContext) {
2188 oldContext->driContext.unbindContext(dpy, 0,
2189 (__DRIid) oldDrawable, (__DRIid) oldDrawable,
2190 &oldContext->driContext);
2191 }
2192 /* bind new */
2193 CurrentContext = ctx;
2194 ctx->driContext.bindContext(dpy, 0, (__DRIid) drawable,
2195 (__DRIid) drawable, &ctx->driContext);
2196 ctx->drawBuffer = drawable;
2197 ctx->curBuffer = drawable;
2198 }
2199 else if (ctx && dpy) {
2200 /* unbind */
2201 ctx->driContext.bindContext(dpy, 0, 0, 0, 0);
2202 }
2203 else if (dpy) {
2204 CurrentContext = 0; /* kw: this seems to be intended??? */
2205 }
2206
2207 return True;
2208 }
2209
2210
2211 /**
2212 * \brief Exchange front and back buffers.
2213 *
2214 * \param dpy the display handle, as returned by XOpenDisplay().
2215 * \param drawable the drawable whose buffers are to be swapped.
2216 *
2217 * Any pending rendering commands will be completed before the buffer swap
2218 * takes place.
2219 *
2220 * Calling glXSwapBuffers() on a window which is single-buffered has no effect.
2221 *
2222 * This function just calls the __DRIdrawableRec::swapBuffers method to do the
2223 * work.
2224 */
2225 void
2226 glXSwapBuffers( Display *dpy, GLXDrawable drawable )
2227 {
2228 if (!dpy || !drawable)
2229 return;
2230
2231 drawable->driDrawable.swapBuffers(dpy, drawable->driDrawable.private);
2232 }
2233
2234
2235 /**
2236 * \brief Return the current context
2237 *
2238 * \return the current context, as specified by glXMakeCurrent(), or zero if no
2239 * context is currently bound.
2240 *
2241 * \sa glXCreateContext(), glXMakeCurrent()
2242 *
2243 * Returns the value of the ::CurrentContext global variable.
2244 */
2245 GLXContext
2246 glXGetCurrentContext( void )
2247 {
2248 return CurrentContext;
2249 }
2250
2251
2252 /**
2253 * \brief Return the current drawable.
2254 *
2255 * \return the current drawable, as specified by glXMakeCurrent(), or zero if
2256 * no drawable is currently bound.
2257 *
2258 * This function gets the current context via glXGetCurrentContext() and
2259 * returns the MiniGLXContextRec::drawBuffer attribute.
2260 */
2261 GLXDrawable
2262 glXGetCurrentDrawable( void )
2263 {
2264 GLXContext glxctx = glXGetCurrentContext();
2265 if (glxctx)
2266 return glxctx->drawBuffer;
2267 else
2268 return NULL;
2269 }
2270
2271
2272 static GLboolean
2273 __glXCreateContextWithConfig(__DRInativeDisplay *dpy, int screen,
2274 int fbconfigID, void *contextID, drm_context_t *hHWContext)
2275 {
2276 __DRIscreen *pDRIScreen;
2277 __DRIscreenPrivate *psp;
2278
2279 pDRIScreen = __glXFindDRIScreen(dpy, screen);
2280 if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
2281 return GL_FALSE;
2282 }
2283
2284 psp = (__DRIscreenPrivate *) pDRIScreen->private;
2285
2286 if (psp->fd) {
2287 if (drmCreateContext(psp->fd, hHWContext)) {
2288 fprintf(stderr, ">>> drmCreateContext failed\n");
2289 return GL_FALSE;
2290 }
2291 *(void**)contextID = (void*) *hHWContext;
2292 }
2293
2294 return GL_TRUE;
2295 }
2296
2297
2298 static GLboolean
2299 __glXGetDrawableInfo(__DRInativeDisplay *dpy, int scrn,
2300 __DRIid draw, unsigned int * index, unsigned int * stamp,
2301 int * x, int * y, int * width, int * height,
2302 int * numClipRects, drm_clip_rect_t ** pClipRects,
2303 int * backX, int * backY,
2304 int * numBackClipRects, drm_clip_rect_t ** pBackClipRects)
2305 {
2306 GLXDrawable drawable = (GLXDrawable) draw;
2307 drm_clip_rect_t * cliprect;
2308 Display* display = (Display*)dpy;
2309 __DRIcontextPrivate *pcp = (__DRIcontextPrivate *)CurrentContext->driContext.private;
2310 if (drawable == 0) {
2311 return GL_FALSE;
2312 }
2313
2314 cliprect = (drm_clip_rect_t*) _mesa_malloc(sizeof(drm_clip_rect_t));
2315 cliprect->x1 = drawable->x;
2316 cliprect->y1 = drawable->y;
2317 cliprect->x2 = drawable->x + drawable->w;
2318 cliprect->y2 = drawable->y + drawable->h;
2319
2320 /* the drawable index is by client id */
2321 *index = display->clientID;
2322
2323 *stamp = pcp->driScreenPriv->pSAREA->drawableTable[display->clientID].stamp;
2324 *x = drawable->x;
2325 *y = drawable->y;
2326 *width = drawable->w;
2327 *height = drawable->h;
2328 *numClipRects = 1;
2329 *pClipRects = cliprect;
2330
2331 *backX = drawable->x;
2332 *backY = drawable->y;
2333 *numBackClipRects = 0;
2334 *pBackClipRects = 0;
2335
2336 return GL_TRUE;
2337 }
2338
2339
2340 static GLboolean
2341 xf86DRI_DestroyContext(__DRInativeDisplay *dpy, int screen, __DRIid context_id )
2342 {
2343 return GL_TRUE;
2344 }
2345
2346
2347 static GLboolean
2348 xf86DRI_CreateDrawable(__DRInativeDisplay *dpy, int screen, __DRIid drawable,
2349 drm_drawable_t *hHWDrawable )
2350 {
2351 return GL_TRUE;
2352 }
2353
2354
2355 static GLboolean
2356 xf86DRI_DestroyDrawable(__DRInativeDisplay *dpy, int screen, __DRIid drawable)
2357 {
2358 return GL_TRUE;
2359 }
2360
2361
2362 /**
2363 * \brief Query function address.
2364 *
2365 * The glXGetProcAddress() function will return the address of any available
2366 * OpenGL or Mini GLX function.
2367 *
2368 * \param procName name of the function to be returned.
2369 *
2370 * \return If \p procName is a valid function name, a pointer to that function
2371 * will be returned. Otherwise, \c NULL will be returned.
2372 *
2373 * The purpose of glXGetProcAddress() is to facilitate using future extensions
2374 * to OpenGL or Mini GLX. If a future version of the library adds new extension
2375 * functions they'll be accessible via glXGetProcAddress(). The alternative is
2376 * to hard-code calls to the new functions in the application but doing so will
2377 * prevent linking the application with older versions of the library.
2378 *
2379 * Returns the function address by looking up its name in a static (name,
2380 * address) pair list.
2381 */
2382 void (*glXGetProcAddress(const GLubyte *procname))( void )
2383 {
2384 struct name_address {
2385 const char *name;
2386 const void *func;
2387 };
2388 static const struct name_address functions[] = {
2389 { "glXChooseVisual", (void *) glXChooseVisual },
2390 { "glXCreateContext", (void *) glXCreateContext },
2391 { "glXDestroyContext", (void *) glXDestroyContext },
2392 { "glXMakeCurrent", (void *) glXMakeCurrent },
2393 { "glXSwapBuffers", (void *) glXSwapBuffers },
2394 { "glXGetCurrentContext", (void *) glXGetCurrentContext },
2395 { "glXGetCurrentDrawable", (void *) glXGetCurrentDrawable },
2396 { "glXGetProcAddress", (void *) glXGetProcAddress },
2397 { "XOpenDisplay", (void *) XOpenDisplay },
2398 { "XCloseDisplay", (void *) XCloseDisplay },
2399 { "XCreateWindow", (void *) XCreateWindow },
2400 { "XDestroyWindow", (void *) XDestroyWindow },
2401 { "XMapWindow", (void *) XMapWindow },
2402 { "XCreateColormap", (void *) XCreateColormap },
2403 { "XFreeColormap", (void *) XFreeColormap },
2404 { "XFree", (void *) XFree },
2405 { "XGetVisualinfo", (void *) XGetVisualInfo },
2406 { "glXCreatePbuffer", (void *) glXCreatePbuffer },
2407 { "glXDestroyPbuffer", (void *) glXDestroyPbuffer },
2408 { "glXChooseFBConfig", (void *) glXChooseFBConfig },
2409 { "glXGetVisualFromFBConfig", (void *) glXGetVisualFromFBConfig },
2410 { NULL, NULL }
2411 };
2412 const struct name_address *entry;
2413 for (entry = functions; entry->name; entry++) {
2414 if (strcmp(entry->name, (const char *) procname) == 0) {
2415 return entry->func;
2416 }
2417 }
2418 return _glapi_get_proc_address((const char *) procname);
2419 }
2420
2421
2422 /**
2423 * \brief Query the Mini GLX version.
2424 *
2425 * \param dpy the display handle. It is currently ignored, but should be the
2426 * value returned by XOpenDisplay().
2427 * \param major receives the major version number of Mini GLX.
2428 * \param minor receives the minor version number of Mini GLX.
2429 *
2430 * \return \c True if the function succeeds, \c False if the function fails due
2431 * to invalid parameters.
2432 *
2433 * \sa #MINI_GLX_VERSION_1_0.
2434 *
2435 * Returns the hard-coded Mini GLX version.
2436 */
2437 Bool
2438 glXQueryVersion( Display *dpy, int *major, int *minor )
2439 {
2440 (void) dpy;
2441 *major = 1;
2442 *minor = 0;
2443 return True;
2444 }
2445
2446
2447 /**
2448 * \brief Create a new pbuffer.
2449 */
2450 GLXPbuffer
2451 glXCreatePbuffer( Display *dpy, GLXFBConfig config, const int *attribList )
2452 {
2453 return NULL;
2454 }
2455
2456
2457 void
2458 glXDestroyPbuffer( Display *dpy, GLXPbuffer pbuf )
2459 {
2460 free(pbuf);
2461 }
2462
2463
2464 GLXFBConfig *
2465 glXChooseFBConfig( Display *dpy, int screen, const int *attribList,
2466 int *nitems )
2467 {
2468 GLXFBConfig *f = (GLXFBConfig *) malloc(sizeof(GLXFBConfig));
2469 f->visInfo = glXChooseVisual( dpy, screen, (int *) attribList );
2470 if (f->visInfo) {
2471 *nitems = 1;
2472 return f;
2473 }
2474 else {
2475 *nitems = 0;
2476 free(f);
2477 return NULL;
2478 }
2479 }
2480
2481
2482 XVisualInfo *
2483 glXGetVisualFromFBConfig( Display *dpy, GLXFBConfig config )
2484 {
2485 /* XVisualInfo and GLXFBConfig are the same structure */
2486 (void) dpy;
2487 return config.visInfo;
2488 }
2489
2490 void *glXAllocateMemoryMESA(Display *dpy, int scrn,
2491 size_t size, float readFreq,
2492 float writeFreq, float priority)
2493 {
2494 if (dpy->driScreen.private && dpy->driScreen.allocateMemory) {
2495 return (*dpy->driScreen.allocateMemory)( dpy, scrn, size,
2496 readFreq, writeFreq,
2497 priority );
2498 }
2499
2500 return NULL;
2501 }
2502
2503 void glXFreeMemoryMESA(Display *dpy, int scrn, void *pointer)
2504 {
2505 if (dpy->driScreen.private && dpy->driScreen.freeMemory) {
2506 (*dpy->driScreen.freeMemory)( dpy, scrn, pointer );
2507 }
2508 }
2509
2510 GLuint glXGetMemoryOffsetMESA( Display *dpy, int scrn,
2511 const void *pointer )
2512 {
2513 if (dpy->driScreen.private && dpy->driScreen.memoryOffset) {
2514 return (*dpy->driScreen.memoryOffset)( dpy, scrn, pointer );
2515 }
2516
2517 return 0;
2518 }
2519
2520
2521 /**
2522 * Get the unadjusted system time (UST). Currently, the UST is measured in
2523 * microseconds since Epoc. The actual resolution of the UST may vary from
2524 * system to system, and the units may vary from release to release.
2525 * Drivers should not call this function directly. They should instead use
2526 * \c glXGetProcAddress to obtain a pointer to the function.
2527 *
2528 * \param ust Location to store the 64-bit UST
2529 * \returns Zero on success or a negative errno value on failure.
2530 *
2531 * \note
2532 * This function was copied directly from src/glx/x11/glxcmds.c.
2533 */
2534 static int __glXGetUST( int64_t * ust )
2535 {
2536 struct timeval tv;
2537
2538 if ( ust == NULL ) {
2539 return -EFAULT;
2540 }
2541
2542 if ( gettimeofday( & tv, NULL ) == 0 ) {
2543 ust[0] = (tv.tv_sec * 1000000) + tv.tv_usec;
2544 return 0;
2545 } else {
2546 return -errno;
2547 }
2548 }
2549
2550
2551 /**
2552 *
2553 * \bug
2554 * This needs to be implemented for miniGlx.
2555 */
2556 static GLboolean __glXGetMscRate(__DRInativeDisplay * dpy, __DRIid drawable,
2557 int32_t * numerator, int32_t * denominator)
2558 {
2559 *numerator = 0;
2560 *denominator = 0;
2561 return False;
2562 }
2563 /*@}*/