c3001e976514459212afc2da8baf7614b9d03908
[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 /* Bump size up to next supported mode.
441 */
442 if (width <= 720 && height <= 480) {
443 width = 720; height = 480;
444 }
445 else if (width <= 960 && height <= 540) {
446 width = 960; height = 540;
447 }
448 else if (width <= 800 && height <= 600) {
449 width = 800; height = 600;
450 }
451 else if (width <= 1024 && height <= 768) {
452 width = 1024; height = 768;
453 }
454 else if (width <= 768 && height <= 1024) {
455 width = 768; height = 1024;
456 }
457 else if (width <= 1280 && height <= 1024) {
458 width = 1280; height = 1024;
459 }
460
461
462 dpy->driverContext.shared.virtualHeight = height;
463 dpy->driverContext.shared.virtualWidth = width;
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
882 fname = getenv("MINIGLX_CONF");
883 if (!fname) fname = "/etc/miniglx.conf";
884
885 file = fopen(fname, "r");
886 if (!file) {
887 fprintf(stderr, "couldn't open config file %s: %s\n", fname, strerror(errno));
888 return 0;
889 }
890
891
892 while (!feof(file)) {
893 char buf[81], *opt = buf, *val, *tmp1, *tmp2;
894 fgets(buf, sizeof(buf), file);
895
896 /* Parse 'opt = val' -- must be easier ways to do this.
897 */
898 while (isspace(*opt)) opt++;
899 val = opt;
900 if (*val == '#') continue; /* comment */
901 while (!isspace(*val) && *val != '=' && *val) val++;
902 tmp1 = val;
903 while (isspace(*val)) val++;
904 if (*val != '=') continue;
905 *tmp1 = 0;
906 val++;
907 while (isspace(*val)) val++;
908 tmp2 = val;
909 while (!isspace(*tmp2) && *tmp2 != '\n' && *tmp2) tmp2++;
910 *tmp2 = 0;
911
912
913 if (strcmp(opt, "fbdevDevice") == 0)
914 dpy->fbdevDevice = strdup(val);
915 else if (strcmp(opt, "clientDriverName") == 0)
916 dpy->clientDriverName = strdup(val);
917 else if (strcmp(opt, "rotateMode") == 0)
918 dpy->rotateMode = atoi(val) ? 1 : 0;
919 else if (strcmp(opt, "pciBusID") == 0) {
920 if (sscanf(val, "PCI:%d:%d:%d",
921 &dpy->driverContext.pciBus,
922 &dpy->driverContext.pciDevice,
923 &dpy->driverContext.pciFunc) != 3) {
924 fprintf(stderr, "malformed bus id: %s\n", val);
925 continue;
926 }
927 dpy->driverContext.pciBusID = strdup(val);
928 }
929 else if (strcmp(opt, "chipset") == 0) {
930 if (sscanf(val, "0x%x", &dpy->driverContext.chipset) != 1)
931 fprintf(stderr, "malformed chipset: %s\n", opt);
932 }
933 else if (strcmp(opt, "virtualWidth") == 0) {
934 if (sscanf(val, "%d", &dpy->driverContext.shared.virtualWidth) != 1)
935 fprintf(stderr, "malformed virtualWidth: %s\n", opt);
936 }
937 else if (strcmp(opt, "virtualHeight") == 0) {
938 if (sscanf(val, "%d", &dpy->driverContext.shared.virtualHeight) != 1)
939 fprintf(stderr, "malformed virutalHeight: %s\n", opt);
940 }
941 else if (strcmp(opt, "bpp") == 0) {
942 if (sscanf(val, "%d", &dpy->driverContext.bpp) != 1)
943 fprintf(stderr, "malformed bpp: %s\n", opt);
944 dpy->driverContext.cpp = dpy->driverContext.bpp / 8;
945 }
946 else if (strcmp(opt, "agpmode") == 0) {
947 if (sscanf(val, "%d", &dpy->driverContext.agpmode) != 1)
948 fprintf(stderr, "malformed agpmode: %s\n", opt);
949 }
950 else if (strcmp(opt, "isPCI") == 0) {
951 dpy->driverContext.isPCI = atoi(val) ? 1 : 0;
952 }
953 }
954
955 fclose(file);
956
957 if (dpy->driverContext.chipset == 0 && dpy->driverContext.pciBusID != 0)
958 dpy->driverContext.chipset = get_chipset_from_busid( dpy );
959
960 return 1;
961 }
962
963 /**
964 * Versioned name of the expected \c __driCreateNewScreen function.
965 *
966 * The version of the last incompatible loader/driver inteface change is
967 * appended to the name of the \c __driCreateNewScreen function. This
968 * prevents loaders from trying to load drivers that are too old.
969 *
970 * \todo
971 * Create a macro or something so that this is automatically updated.
972 */
973 static const char createNewScreenName[] = "__driCreateNewScreen_20050727";
974
975
976 static int InitDriver( Display *dpy )
977 {
978 /*
979 * Begin DRI setup.
980 * We're kind of combining the per-display and per-screen information
981 * which was kept separate in XFree86/DRI's libGL.
982 */
983 dpy->dlHandle = dlopen(dpy->clientDriverName, RTLD_NOW | RTLD_GLOBAL);
984 if (!dpy->dlHandle) {
985 fprintf(stderr, "Unable to open %s: %s\n", dpy->clientDriverName,
986 dlerror());
987 goto failed;
988 }
989
990 /* Pull in Mini GLX specific hooks:
991 */
992 dpy->driver = (struct DRIDriverRec *) dlsym(dpy->dlHandle,
993 "__driDriver");
994 if (!dpy->driver) {
995 fprintf(stderr, "Couldn't find __driDriver in %s\n",
996 dpy->clientDriverName);
997 goto failed;
998 }
999
1000 /* Pull in standard DRI client-side driver hooks:
1001 */
1002 dpy->createNewScreen = (PFNCREATENEWSCREENFUNC)
1003 dlsym(dpy->dlHandle, createNewScreenName);
1004 if (!dpy->createNewScreen) {
1005 fprintf(stderr, "Couldn't find %s in %s\n", createNewScreenName,
1006 dpy->clientDriverName);
1007 goto failed;
1008 }
1009
1010 return GL_TRUE;
1011
1012 failed:
1013 if (dpy->dlHandle) {
1014 dlclose(dpy->dlHandle);
1015 dpy->dlHandle = 0;
1016 }
1017 return GL_FALSE;
1018 }
1019
1020
1021 /**********************************************************************/
1022 /** \name Public API functions (Xlib and GLX) */
1023 /**********************************************************************/
1024 /*@{*/
1025
1026
1027 /**
1028 * \brief Initialize the graphics system.
1029 *
1030 * \param display_name currently ignored. It is recommended to pass it as NULL.
1031 * \return a pointer to a #Display if the function is able to initialize
1032 * the graphics system, NULL otherwise.
1033 *
1034 * Allocates a MiniGLXDisplayRec structure and fills in with information from a
1035 * configuration file.
1036 *
1037 * Calls OpenFBDev() to open the framebuffer device and calls
1038 * DRIDriverRec::initFBDev to do the client-side initialization on it.
1039 *
1040 * Loads the DRI driver and pulls in Mini GLX specific hooks into a
1041 * DRIDriverRec structure, and the standard DRI \e __driCreateScreen hook.
1042 * Asks the driver for a list of supported visuals. Performs the per-screen
1043 * client-side initialization. Also setups the callbacks in the screen private
1044 * information.
1045 *
1046 * Does the framebuffer device setup. Calls __miniglx_open_connections() to
1047 * serve clients.
1048 */
1049 Display *
1050 __miniglx_StartServer( const char *display_name )
1051 {
1052 Display *dpy;
1053 int use_vt = 0;
1054
1055 dpy = (Display *)calloc(1, sizeof(Display));
1056 if (!dpy)
1057 return NULL;
1058
1059 dpy->IsClient = False;
1060
1061 if (!__read_config_file( dpy )) {
1062 fprintf(stderr, "Couldn't get configuration details\n");
1063 free(dpy);
1064 return NULL;
1065 }
1066
1067 /* Open the fbdev device
1068 */
1069 if (!OpenFBDev(dpy, use_vt)) {
1070 fprintf(stderr, "OpenFBDev failed\n");
1071 free(dpy);
1072 return NULL;
1073 }
1074
1075 if (!InitDriver(dpy)) {
1076 fprintf(stderr, "InitDriver failed\n");
1077 free(dpy);
1078 return NULL;
1079 }
1080
1081 /* Perform the initialization normally done in the X server
1082 */
1083 if (!dpy->driver->initFBDev( &dpy->driverContext )) {
1084 fprintf(stderr, "%s: __driInitFBDev failed\n", __FUNCTION__);
1085 dlclose(dpy->dlHandle);
1086 return GL_FALSE;
1087 }
1088
1089 /* do fbdev setup
1090 */
1091 if (!SetupFBDev(dpy)) {
1092 fprintf(stderr, "SetupFBDev failed\n");
1093 free(dpy);
1094 return NULL;
1095 }
1096
1097 /* unlock here if not using VT -- JDS */
1098 if (!use_vt) {
1099 if (dpy->driver->restoreHardware)
1100 dpy->driver->restoreHardware( &dpy->driverContext );
1101 DRM_UNLOCK( dpy->driverContext.drmFD,
1102 dpy->driverContext.pSAREA,
1103 dpy->driverContext.serverContext );
1104 dpy->hwActive = 1;
1105 }
1106
1107 /* Ready for clients:
1108 */
1109 if (!__miniglx_open_connections(dpy)) {
1110 free(dpy);
1111 return NULL;
1112 }
1113
1114 return dpy;
1115 }
1116
1117
1118 /**
1119 * Implement \c __DRIinterfaceMethods::getProcAddress.
1120 */
1121 static __DRIfuncPtr get_proc_address( const char * proc_name )
1122 {
1123 (void) proc_name;
1124 return NULL;
1125 }
1126
1127
1128 /**
1129 * Table of functions exported by the loader to the driver.
1130 */
1131 static const __DRIinterfaceMethods interface_methods = {
1132 get_proc_address,
1133
1134 _gl_context_modes_create,
1135 _gl_context_modes_destroy,
1136
1137 __glXFindDRIScreen,
1138 __glXWindowExists,
1139
1140 __glXCreateContextWithConfig,
1141 xf86DRI_DestroyContext,
1142
1143 xf86DRI_CreateDrawable,
1144 xf86DRI_DestroyDrawable,
1145 __glXGetDrawableInfo,
1146
1147 __glXGetUST,
1148 __glXGetMscRate,
1149 };
1150
1151
1152 static void *
1153 CallCreateNewScreen(Display *dpy, int scrn, __DRIscreen *psc)
1154 {
1155 void *psp = NULL;
1156 drm_handle_t hSAREA;
1157 drmAddress pSAREA;
1158 const char *BusID;
1159 int i;
1160 __DRIversion ddx_version;
1161 __DRIversion dri_version;
1162 __DRIversion drm_version;
1163 __DRIframebuffer framebuffer;
1164 int fd = -1;
1165 int status;
1166 const char * err_msg;
1167 const char * err_extra;
1168 drmVersionPtr version;
1169 drm_handle_t hFB;
1170 drm_magic_t magic;
1171
1172
1173 hSAREA = dpy->driverContext.shared.hSAREA;
1174 BusID = dpy->driverContext.pciBusID;
1175
1176 fd = drmOpen(NULL, BusID);
1177
1178 err_msg = "open DRM";
1179 err_extra = strerror( -fd );
1180
1181 if (fd < 0) goto done;
1182
1183 err_msg = "drmGetMagic";
1184 err_extra = NULL;
1185
1186 if (drmGetMagic(fd, &magic)) goto done;
1187
1188 dpy->authorized = False;
1189 send_char_msg( dpy, 0, _Authorize );
1190 send_msg( dpy, 0, &magic, sizeof(magic));
1191
1192 /* force net buffer flush */
1193 while (!dpy->authorized)
1194 handle_fd_events( dpy, 0 );
1195
1196 version = drmGetVersion(fd);
1197 if (version) {
1198 drm_version.major = version->version_major;
1199 drm_version.minor = version->version_minor;
1200 drm_version.patch = version->version_patchlevel;
1201 drmFreeVersion(version);
1202 }
1203 else {
1204 drm_version.major = -1;
1205 drm_version.minor = -1;
1206 drm_version.patch = -1;
1207 }
1208
1209 /*
1210 * Get device name (like "tdfx") and the ddx version numbers.
1211 * We'll check the version in each DRI driver's "createScreen"
1212 * function.
1213 */
1214 ddx_version.major = 4;
1215 ddx_version.minor = 0;
1216 ddx_version.patch = 0;
1217
1218 /*
1219 * Get the DRI X extension version.
1220 */
1221 dri_version.major = 4;
1222 dri_version.minor = 0;
1223 dri_version.patch = 0;
1224
1225 /*
1226 * Get device-specific info. pDevPriv will point to a struct
1227 * (such as DRIRADEONRec in xfree86/driver/ati/radeon_dri.h)
1228 * that has information about the screen size, depth, pitch,
1229 * ancilliary buffers, DRM mmap handles, etc.
1230 */
1231 hFB = dpy->driverContext.shared.hFrameBuffer;
1232 framebuffer.size = dpy->driverContext.shared.fbSize;
1233 framebuffer.stride = dpy->driverContext.shared.fbStride;
1234 framebuffer.dev_priv_size = dpy->driverContext.driverClientMsgSize;
1235 framebuffer.dev_priv = dpy->driverContext.driverClientMsg;
1236 framebuffer.width = dpy->driverContext.shared.virtualWidth;
1237 framebuffer.height = dpy->driverContext.shared.virtualHeight;
1238
1239 /*
1240 * Map the framebuffer region.
1241 */
1242 status = drmMap(fd, hFB, framebuffer.size,
1243 (drmAddressPtr)&framebuffer.base);
1244
1245 err_msg = "drmMap of framebuffer";
1246 err_extra = strerror( -status );
1247
1248 if ( status != 0 ) goto done;
1249
1250 /*
1251 * Map the SAREA region. Further mmap regions may be setup in
1252 * each DRI driver's "createScreen" function.
1253 */
1254 status = drmMap(fd, hSAREA, SAREA_MAX, &pSAREA);
1255
1256 err_msg = "drmMap of sarea";
1257 err_extra = strerror( -status );
1258
1259 if ( status == 0 ) {
1260 err_msg = "InitDriver";
1261 err_extra = NULL;
1262 psp = dpy->createNewScreen(dpy, scrn, psc, NULL,
1263 & ddx_version,
1264 & dri_version,
1265 & drm_version,
1266 & framebuffer,
1267 pSAREA,
1268 fd,
1269 20050727,
1270 & interface_methods,
1271 (__GLcontextModes **) &dpy->driver_modes);
1272
1273 /* fill in dummy visual ids */
1274 {
1275 __GLcontextModes *temp;
1276 temp = (__GLcontextModes *)dpy->driver_modes;
1277 i = 1;
1278 while (temp)
1279 {
1280 temp->visualID = i++;
1281 temp=temp->next;
1282 }
1283 }
1284 }
1285
1286 done:
1287 if ( psp == NULL ) {
1288 if ( pSAREA != MAP_FAILED ) {
1289 (void)drmUnmap(pSAREA, SAREA_MAX);
1290 }
1291
1292 if ( framebuffer.base != MAP_FAILED ) {
1293 (void)drmUnmap((drmAddress)framebuffer.base, framebuffer.size);
1294 }
1295
1296 if ( framebuffer.dev_priv != NULL ) {
1297 free(framebuffer.dev_priv);
1298 }
1299
1300 if ( fd >= 0 ) {
1301 (void)drmClose(fd);
1302 }
1303
1304 if ( err_extra != NULL ) {
1305 fprintf(stderr, "libGL error: %s failed (%s)\n", err_msg,
1306 err_extra);
1307 }
1308 else {
1309 fprintf(stderr, "libGL error: %s failed\n", err_msg );
1310 }
1311
1312 fprintf(stderr, "libGL error: reverting to (slow) indirect rendering\n");
1313 }
1314
1315 return psp;
1316 }
1317
1318 /**
1319 * \brief Initialize the graphics system.
1320 *
1321 * \param display_name currently ignored. It is recommended to pass it as NULL.
1322 * \return a pointer to a #Display if the function is able to initialize
1323 * the graphics system, NULL otherwise.
1324 *
1325 * Allocates a MiniGLXDisplayRec structure and fills in with information from a
1326 * configuration file.
1327 *
1328 * Calls __miniglx_open_connections() to connect to the server.
1329 *
1330 * Loads the DRI driver and pulls in Mini GLX specific hooks into a
1331 * DRIDriverRec structure, and the standard DRI \e __driCreateScreen hook.
1332 * Asks the driver for a list of supported visuals. Performs the per-screen
1333 * client-side initialization. Also setups the callbacks in the screen private
1334 * information.
1335 *
1336 * \todo
1337 * - read config file
1338 * - what about virtualWidth, etc?
1339 * - determine dpy->driverClientMsgSize,
1340 * - allocate dpy->driverClientMsg
1341 */
1342 Display *
1343 XOpenDisplay( const char *display_name )
1344 {
1345 Display *dpy;
1346
1347 dpy = (Display *)calloc(1, sizeof(Display));
1348 if (!dpy)
1349 return NULL;
1350
1351 dpy->IsClient = True;
1352
1353 /* read config file
1354 */
1355 if (!__read_config_file( dpy )) {
1356 fprintf(stderr, "Couldn't get configuration details\n");
1357 free(dpy);
1358 return NULL;
1359 }
1360
1361 /* Connect to the server and receive driverClientMsg
1362 */
1363 if (!__miniglx_open_connections(dpy)) {
1364 free(dpy);
1365 return NULL;
1366 }
1367
1368 /* dlopen the driver .so file
1369 */
1370 if (!InitDriver(dpy)) {
1371 fprintf(stderr, "InitDriver failed\n");
1372 free(dpy);
1373 return NULL;
1374 }
1375
1376 /* Perform the client-side initialization.
1377 *
1378 * Clearly there is a limit of one on the number of windows in
1379 * existence at any time.
1380 *
1381 * Need to shut down DRM and free DRI data in XDestroyWindow(), too.
1382 */
1383 dpy->driScreen.private = CallCreateNewScreen(dpy, 0, &dpy->driScreen);
1384 if (!dpy->driScreen.private) {
1385 fprintf(stderr, "%s: __driCreateScreen failed\n", __FUNCTION__);
1386 dlclose(dpy->dlHandle);
1387 free(dpy);
1388 return NULL;
1389 }
1390
1391 /* Anything more to do?
1392 */
1393 return dpy;
1394 }
1395
1396
1397 /**
1398 * \brief Release display resources.
1399 *
1400 * When the application is about to exit, the resources associated with the
1401 * graphics system can be released by calling this function.
1402 *
1403 * \param dpy display handle. It becomes invalid at this point.
1404 *
1405 * Destroys the window if any, and destroys the per-screen
1406 * driver private information.
1407 * Calls __miniglx_close_connections().
1408 *
1409 * If a server, puts the the framebuffer back into the initial state.
1410 *
1411 * Finally frees the display structure.
1412 */
1413 void
1414 XCloseDisplay( Display *dpy )
1415 {
1416 glXMakeCurrent( dpy, NULL, NULL);
1417
1418 if (dpy->NumWindows)
1419 XDestroyWindow( dpy, dpy->TheWindow );
1420
1421 /* As this is done in XOpenDisplay, need to undo it here:
1422 */
1423 dpy->driScreen.destroyScreen(dpy, 0, dpy->driScreen.private);
1424
1425 __miniglx_close_connections( dpy );
1426
1427 if (!dpy->IsClient) {
1428 /* put framebuffer back to initial state
1429 */
1430 (*dpy->driver->haltFBDev)( &dpy->driverContext );
1431 RestoreFBDev(dpy);
1432 CloseFBDev(dpy);
1433 }
1434
1435 dlclose(dpy->dlHandle);
1436 free(dpy);
1437 }
1438
1439
1440 /**
1441 * \brief Window creation.
1442 *
1443 * \param display a display handle, as returned by XOpenDisplay().
1444 * \param parent the parent window for the new window. For Mini GLX this should
1445 * be
1446 * \code RootWindow(display, 0) \endcode
1447 * \param x the window abscissa. For Mini GLX, it should be zero.
1448 * \param y the window ordinate. For Mini GLX, it should be zero.
1449 * \param width the window width. For Mini GLX, this specifies the desired
1450 * screen width such as 1024 or 1280.
1451 * \param height the window height. For Mini GLX, this specifies the desired
1452 * screen height such as 768 or 1024.
1453 * \param border_width the border width. For Mini GLX, it should be zero.
1454 * \param depth the window pixel depth. For Mini GLX, this should be the depth
1455 * found in the #XVisualInfo object returned by glXChooseVisual()
1456 * \param winclass the window class. For Mini GLX this value should be
1457 * #InputOutput.
1458 * \param visual the visual type. It should be the visual field of the
1459 * #XVisualInfo object returned by glXChooseVisual().
1460 * \param valuemask which fields of the XSetWindowAttributes() are to be used.
1461 * For Mini GLX this is typically the bitmask
1462 * \code CWBackPixel | CWBorderPixel | CWColormap \endcode
1463 * \param attributes initial window attributes. The
1464 * XSetWindowAttributes::background_pixel, XSetWindowAttributes::border_pixel
1465 * and XSetWindowAttributes::colormap fields should be set.
1466 *
1467 * \return a window handle if it succeeds or zero if it fails.
1468 *
1469 * \note For Mini GLX, windows are full-screen; they cover the entire frame
1470 * buffer. Also, Mini GLX imposes a limit of one window. A second window
1471 * cannot be created until the first one is destroyed.
1472 *
1473 * This function creates and initializes a ::MiniGLXWindowRec structure after
1474 * ensuring that there is no other window created. Performs the per-drawable
1475 * client-side initialization calling the __DRIscreenRec::createDrawable
1476 * method.
1477 *
1478 */
1479 Window
1480 XCreateWindow( Display *dpy, Window parent, int x, int y,
1481 unsigned int width, unsigned int height,
1482 unsigned int border_width, int depth, unsigned int winclass,
1483 Visual *visual, unsigned long valuemask,
1484 XSetWindowAttributes *attributes )
1485 {
1486 const int empty_attribute_list[1] = { None };
1487
1488 Window win;
1489
1490 /* ignored */
1491 (void) x;
1492 (void) y;
1493 (void) border_width;
1494 (void) depth;
1495 (void) winclass;
1496 (void) valuemask;
1497 (void) attributes;
1498
1499 if (!dpy->IsClient) {
1500 fprintf(stderr, "Server process may not create windows (currently)\n");
1501 return NULL;
1502 }
1503
1504 if (dpy->NumWindows > 0)
1505 return NULL; /* only allow one window */
1506
1507 assert(dpy->TheWindow == NULL);
1508
1509 win = malloc(sizeof(struct MiniGLXWindowRec));
1510 if (!win)
1511 return NULL;
1512
1513 /* In rotated mode, translate incoming x,y,width,height into
1514 * 'normal' coordinates.
1515 */
1516 if (dpy->rotateMode) {
1517 int tmp;
1518 tmp = width; width = height; height = tmp;
1519 tmp = x; x = y; y = tmp;
1520 }
1521
1522 /* init other per-window fields */
1523 win->x = 0;
1524 win->y = 0;
1525 win->w = width;
1526 win->h = height;
1527 win->visual = visual; /* ptr assignment */
1528
1529 win->bytesPerPixel = dpy->driverContext.cpp;
1530 win->rowStride = dpy->driverContext.shared.virtualWidth * win->bytesPerPixel;
1531 win->size = win->rowStride * height;
1532 win->frontStart = dpy->driverContext.FBAddress;
1533 win->frontBottom = (GLubyte *) win->frontStart + (height-1) * win->rowStride;
1534
1535 /* This is incorrect: the hardware driver could put the backbuffer
1536 * just about anywhere. These fields, including the above are
1537 * hardware dependent & don't really belong here.
1538 */
1539 if (visual->mode->doubleBufferMode) {
1540 win->backStart = (GLubyte *) win->frontStart +
1541 win->rowStride * dpy->driverContext.shared.virtualHeight;
1542 win->backBottom = (GLubyte *) win->backStart
1543 + (height - 1) * win->rowStride;
1544 win->curBottom = win->backBottom;
1545 }
1546 else {
1547 /* single buffered */
1548 win->backStart = NULL;
1549 win->backBottom = NULL;
1550 win->curBottom = win->frontBottom;
1551 }
1552
1553 dpy->driScreen.createNewDrawable(dpy, visual->mode, (int) win,
1554 &win->driDrawable, GLX_WINDOW_BIT, empty_attribute_list);
1555
1556 if (!win->driDrawable.private) {
1557 fprintf(stderr, "%s: dri.createDrawable failed\n", __FUNCTION__);
1558 free(win);
1559 return NULL;
1560 }
1561
1562 dpy->NumWindows++;
1563 dpy->TheWindow = win;
1564
1565 return win;
1566 }
1567
1568
1569 /**
1570 * \brief Destroy window.
1571 *
1572 * \param display display handle.
1573 * \param w window handle.
1574 *
1575 * This function calls XUnmapWindow() and frees window \p w.
1576 *
1577 * In case of destroying the current buffer first unbinds the GLX context
1578 * by calling glXMakeCurrent() with no drawable.
1579 */
1580 void
1581 XDestroyWindow( Display *display, Window win )
1582 {
1583 if (display && display->IsClient && win) {
1584 /* check if destroying the current buffer */
1585 Window curDraw = glXGetCurrentDrawable();
1586 if (win == curDraw) {
1587 glXMakeCurrent( display, NULL, NULL);
1588 }
1589
1590 XUnmapWindow( display, win );
1591
1592 /* Destroy the drawable. */
1593 win->driDrawable.destroyDrawable(display, win->driDrawable.private);
1594 free(win);
1595
1596 /* unlink window from display */
1597 display->NumWindows--;
1598 assert(display->NumWindows == 0);
1599 display->TheWindow = NULL;
1600 }
1601 }
1602
1603
1604
1605
1606 /**
1607 * \brief Create color map structure.
1608 *
1609 * \param dpy the display handle as returned by XOpenDisplay().
1610 * \param w the window on whose screen you want to create a color map. This
1611 * parameter is ignored by Mini GLX but should be the value returned by the
1612 * \code RootWindow(display, 0) \endcode macro.
1613 * \param visual a visual type supported on the screen. This parameter is
1614 * ignored by Mini GLX but should be the XVisualInfo::visual returned by
1615 * glXChooseVisual().
1616 * \param alloc the color map entries to be allocated. This parameter is ignored
1617 * by Mini GLX but should be set to #AllocNone.
1618 *
1619 * \return the color map.
1620 *
1621 * This function is only provided to ease porting. Practically a no-op -
1622 * returns a pointer to a dynamically allocated chunk of memory (one byte).
1623 */
1624 Colormap
1625 XCreateColormap( Display *dpy, Window w, Visual *visual, int alloc )
1626 {
1627 (void) dpy;
1628 (void) w;
1629 (void) visual;
1630 (void) alloc;
1631 return (Colormap) malloc(1);
1632 }
1633
1634
1635 /**
1636 * \brief Destroy color map structure.
1637 *
1638 * \param display The display handle as returned by XOpenDisplay().
1639 * \param colormap the color map to destroy.
1640 *
1641 * This function is only provided to ease porting. Practically a no-op.
1642 *
1643 * Frees the memory pointed by \p colormap.
1644 */
1645 void
1646 XFreeColormap( Display *display, Colormap colormap )
1647 {
1648 (void) display;
1649 (void) colormap;
1650 free(colormap);
1651 }
1652
1653
1654 /**
1655 * \brief Free client data.
1656 *
1657 * \param data the data that is to be freed.
1658 *
1659 * Frees the memory pointed by \p data.
1660 */
1661 void
1662 XFree( void *data )
1663 {
1664 free(data);
1665 }
1666
1667
1668 /**
1669 * \brief Query available visuals.
1670 *
1671 * \param dpy the display handle, as returned by XOpenDisplay().
1672 * \param vinfo_mask a bitmask indicating which fields of the \p vinfo_template
1673 * are to be matched. The value must be \c VisualScreenMask.
1674 * \param vinfo_template a template whose fields indicate which visual
1675 * attributes must be matched by the results. The XVisualInfo::screen field of
1676 * this structure must be zero.
1677 * \param nitens_return will hold the number of visuals returned.
1678 *
1679 * \return the address of an array of all available visuals.
1680 *
1681 * An example of using XGetVisualInfo() to get all available visuals follows:
1682 *
1683 * \code
1684 * XVisualInfo vinfo_template, *results;
1685 * int nitens_return;
1686 * Display *dpy = XOpenDisplay(NULL);
1687 * vinfo_template.screen = 0;
1688 * results = XGetVisualInfo(dpy, VisualScreenMask, &vinfo_template, &nitens_return);
1689 * \endcode
1690 *
1691 * Returns the list of all ::XVisualInfo available, one per
1692 * ::__GLcontextMode stored in MiniGLXDisplayRec::modes.
1693 */
1694 XVisualInfo *
1695 XGetVisualInfo( Display *dpy, long vinfo_mask, XVisualInfo *vinfo_template, int *nitens_return )
1696 {
1697 const __GLcontextModes *mode;
1698 XVisualInfo *results;
1699 Visual *visResults;
1700 int i, n=0;
1701
1702 // ASSERT(vinfo_mask == VisualScreenMask);
1703 ASSERT(vinfo_template.screen == 0);
1704
1705 if (vinfo_mask == VisualIDMask)
1706 {
1707 for ( mode = dpy->driver_modes ; mode != NULL ; mode= mode->next )
1708 if (mode->visualID == vinfo_template->visualid)
1709 n=1;
1710
1711 if (n==0)
1712 return NULL;
1713
1714 results = (XVisualInfo *)calloc(1, n * sizeof(XVisualInfo));
1715 if (!results) {
1716 *nitens_return = 0;
1717 return NULL;
1718 }
1719
1720 visResults = (Visual *)calloc(1, n * sizeof(Visual));
1721 if (!results) {
1722 free(results);
1723 *nitens_return = 0;
1724 return NULL;
1725 }
1726
1727 for ( mode = dpy->driver_modes ; mode != NULL ; mode= mode->next )
1728 if (mode->visualID == vinfo_template->visualid)
1729 {
1730 visResults[0].mode=mode;
1731 visResults[0].visInfo = results;
1732 visResults[0].dpy = dpy;
1733 if (dpy->driverContext.bpp == 32)
1734 visResults[0].pixelFormat = PF_B8G8R8A8; /* XXX: FIX ME */
1735 else
1736 visResults[0].pixelFormat = PF_B5G6R5; /* XXX: FIX ME */
1737
1738 results[0].visual = visResults;
1739 results[0].visualid = mode->visualID;
1740 #if defined(__cplusplus) || defined(c_plusplus)
1741 results[0].c_class = TrueColor;
1742 #else
1743 results[0].class = TrueColor;
1744 #endif
1745 results[0].depth = mode->redBits +
1746 mode->redBits +
1747 mode->redBits +
1748 mode->redBits;
1749 results[0].bits_per_rgb = dpy->driverContext.bpp;
1750
1751 }
1752
1753 }
1754 else // if (vinfo_mask == VisualScreenMask)
1755 {
1756 n = 0;
1757 for ( mode = dpy->driver_modes ; mode != NULL ; mode = mode->next )
1758 n++;
1759
1760 results = (XVisualInfo *)calloc(1, n * sizeof(XVisualInfo));
1761 if (!results) {
1762 *nitens_return = 0;
1763 return NULL;
1764 }
1765
1766 visResults = (Visual *)calloc(1, n * sizeof(Visual));
1767 if (!results) {
1768 free(results);
1769 *nitens_return = 0;
1770 return NULL;
1771 }
1772
1773 for ( mode = dpy->driver_modes, i = 0 ; mode != NULL ; mode = mode->next, i++ ) {
1774 visResults[i].mode = mode;
1775 visResults[i].visInfo = results + i;
1776 visResults[i].dpy = dpy;
1777
1778 if (dpy->driverContext.bpp == 32)
1779 visResults[i].pixelFormat = PF_B8G8R8A8; /* XXX: FIX ME */
1780 else
1781 visResults[i].pixelFormat = PF_B5G6R5; /* XXX: FIX ME */
1782
1783 results[i].visual = visResults + i;
1784 results[i].visualid = mode->visualID;
1785 #if defined(__cplusplus) || defined(c_plusplus)
1786 results[i].c_class = TrueColor;
1787 #else
1788 results[i].class = TrueColor;
1789 #endif
1790 results[i].depth = mode->redBits +
1791 mode->redBits +
1792 mode->redBits +
1793 mode->redBits;
1794 results[i].bits_per_rgb = dpy->driverContext.bpp;
1795 }
1796 }
1797 *nitens_return = n;
1798 return results;
1799 }
1800
1801
1802 /**
1803 * \brief Return a visual that matches specified attributes.
1804 *
1805 * \param dpy the display handle, as returned by XOpenDisplay().
1806 * \param screen the screen number. It is currently ignored by Mini GLX and
1807 * should be zero.
1808 * \param attribList a list of GLX attributes which describe the desired pixel
1809 * format. It is terminated by the token \c None.
1810 *
1811 * The attributes are as follows:
1812 * \arg GLX_USE_GL:
1813 * This attribute should always be present in order to maintain compatibility
1814 * with GLX.
1815 * \arg GLX_RGBA:
1816 * If present, only RGBA pixel formats will be considered. Otherwise, only
1817 * color index formats are considered.
1818 * \arg GLX_DOUBLEBUFFER:
1819 * if present, only double-buffered pixel formats will be chosen.
1820 * \arg GLX_RED_SIZE \e n:
1821 * Must be followed by a non-negative integer indicating the minimum number of
1822 * bits per red pixel component that is acceptable.
1823 * \arg GLX_GREEN_SIZE \e n:
1824 * Must be followed by a non-negative integer indicating the minimum number of
1825 * bits per green pixel component that is acceptable.
1826 * \arg GLX_BLUE_SIZE \e n:
1827 * Must be followed by a non-negative integer indicating the minimum number of
1828 * bits per blue pixel component that is acceptable.
1829 * \arg GLX_ALPHA_SIZE \e n:
1830 * Must be followed by a non-negative integer indicating the minimum number of
1831 * bits per alpha pixel component that is acceptable.
1832 * \arg GLX_STENCIL_SIZE \e n:
1833 * Must be followed by a non-negative integer indicating the minimum number of
1834 * bits per stencil value that is acceptable.
1835 * \arg GLX_DEPTH_SIZE \e n:
1836 * Must be followed by a non-negative integer indicating the minimum number of
1837 * bits per depth component that is acceptable.
1838 * \arg None:
1839 * This token is used to terminate the attribute list.
1840 *
1841 * \return a pointer to an #XVisualInfo object which most closely matches the
1842 * requirements of the attribute list. If there is no visual which matches the
1843 * request, \c NULL will be returned.
1844 *
1845 * \note Visuals with accumulation buffers are not available.
1846 *
1847 * This function searches the list of available visual configurations in
1848 * MiniGLXDisplayRec::configs for a configuration which best matches the GLX
1849 * attribute list parameter. A new ::XVisualInfo object is created which
1850 * describes the visual configuration. The match criteria is described in the
1851 * specification.
1852 */
1853 XVisualInfo*
1854 glXChooseVisual( Display *dpy, int screen, int *attribList )
1855 {
1856 const __GLcontextModes *mode;
1857 Visual *vis;
1858 XVisualInfo *visInfo;
1859 const int *attrib;
1860 GLboolean rgbFlag = GL_FALSE, dbFlag = GL_FALSE, stereoFlag = GL_FALSE;
1861 GLint redBits = 0, greenBits = 0, blueBits = 0, alphaBits = 0;
1862 GLint indexBits = 0, depthBits = 0, stencilBits = 0;
1863 GLint numSamples = 0;
1864 int i=0;
1865
1866 /*
1867 * XXX in the future, <screen> might be interpreted as a VT
1868 */
1869 ASSERT(dpy);
1870 ASSERT(screen == 0);
1871
1872 vis = (Visual *)calloc(1, sizeof(Visual));
1873 if (!vis)
1874 return NULL;
1875
1876 visInfo = (XVisualInfo *)malloc(sizeof(XVisualInfo));
1877 if (!visInfo) {
1878 free(vis);
1879 return NULL;
1880 }
1881
1882 visInfo->visual = vis;
1883 vis->visInfo = visInfo;
1884 vis->dpy = dpy;
1885
1886 /* parse the attribute list */
1887 for (attrib = attribList; attrib && *attrib != None; attrib++) {
1888 switch (attrib[0]) {
1889 case GLX_DOUBLEBUFFER:
1890 dbFlag = GL_TRUE;
1891 break;
1892 case GLX_RGBA:
1893 rgbFlag = GL_TRUE;
1894 break;
1895 case GLX_RED_SIZE:
1896 redBits = attrib[1];
1897 attrib++;
1898 break;
1899 case GLX_GREEN_SIZE:
1900 greenBits = attrib[1];
1901 attrib++;
1902 break;
1903 case GLX_BLUE_SIZE:
1904 blueBits = attrib[1];
1905 attrib++;
1906 break;
1907 case GLX_ALPHA_SIZE:
1908 alphaBits = attrib[1];
1909 attrib++;
1910 break;
1911 case GLX_STENCIL_SIZE:
1912 stencilBits = attrib[1];
1913 attrib++;
1914 break;
1915 case GLX_DEPTH_SIZE:
1916 depthBits = attrib[1];
1917 attrib++;
1918 break;
1919 #if 0
1920 case GLX_ACCUM_RED_SIZE:
1921 accumRedBits = attrib[1];
1922 attrib++;
1923 break;
1924 case GLX_ACCUM_GREEN_SIZE:
1925 accumGreenBits = attrib[1];
1926 attrib++;
1927 break;
1928 case GLX_ACCUM_BLUE_SIZE:
1929 accumBlueBits = attrib[1];
1930 attrib++;
1931 break;
1932 case GLX_ACCUM_ALPHA_SIZE:
1933 accumAlphaBits = attrib[1];
1934 attrib++;
1935 break;
1936 case GLX_LEVEL:
1937 /* ignored for now */
1938 break;
1939 #endif
1940 default:
1941 /* unexpected token */
1942 fprintf(stderr, "unexpected token in glXChooseVisual attrib list\n");
1943 free(vis);
1944 free(visInfo);
1945 return NULL;
1946 }
1947 }
1948
1949 /* search screen configs for suitable visual */
1950 (void) numSamples;
1951 (void) indexBits;
1952 (void) redBits;
1953 (void) greenBits;
1954 (void) blueBits;
1955 (void) alphaBits;
1956 (void) stereoFlag;
1957 for ( mode = dpy->driver_modes ; mode != NULL ; mode = mode->next ) {
1958 i++;
1959 if (mode->rgbMode == rgbFlag &&
1960 mode->doubleBufferMode == dbFlag &&
1961 mode->redBits >= redBits &&
1962 mode->greenBits >= greenBits &&
1963 mode->blueBits >= blueBits &&
1964 mode->alphaBits >= alphaBits &&
1965 mode->depthBits >= depthBits &&
1966 mode->stencilBits >= stencilBits) {
1967 /* found it */
1968 visInfo->visualid = i;
1969 vis->mode = mode;
1970 break;
1971 }
1972 }
1973 if (!vis->mode)
1974 return NULL;
1975
1976 /* compute depth and bpp */
1977 if (rgbFlag) {
1978 /* XXX maybe support depth 16 someday */
1979 #if defined(__cplusplus) || defined(c_plusplus)
1980 visInfo->c_class = TrueColor;
1981 #else
1982 visInfo->class = TrueColor;
1983 #endif
1984 visInfo->depth = dpy->driverContext.bpp;
1985 visInfo->bits_per_rgb = dpy->driverContext.bpp;
1986 if (dpy->driverContext.bpp == 32)
1987 vis->pixelFormat = PF_B8G8R8A8;
1988 else
1989 vis->pixelFormat = PF_B5G6R5;
1990 }
1991 else {
1992 /* color index mode */
1993 #if defined(__cplusplus) || defined(c_plusplus)
1994 visInfo->c_class = PseudoColor;
1995 #else
1996 visInfo->class = PseudoColor;
1997 #endif
1998 visInfo->depth = 8;
1999 visInfo->bits_per_rgb = 8; /* bits/pixel */
2000 vis->pixelFormat = PF_CI8;
2001 }
2002
2003 return visInfo;
2004 }
2005
2006
2007 /**
2008 * \brief Return information about GLX visuals.
2009 *
2010 * \param dpy the display handle, as returned by XOpenDisplay().
2011 * \param vis the visual to be queried, as returned by glXChooseVisual().
2012 * \param attrib the visual attribute to be returned.
2013 * \param value pointer to an integer in which the result of the query will be
2014 * stored.
2015 *
2016 * \return zero if no error occurs, \c GLX_INVALID_ATTRIBUTE if the attribute
2017 * parameter is invalid, or \c GLX_BAD_VISUAL if the \p vis parameter is
2018 * invalid.
2019 *
2020 * Returns the appropriate attribute of ::__GLXvisualConfig pointed by
2021 * MiniGLXVisualRec::glxConfig of XVisualInfo::visual.
2022 *
2023 * \sa data types.
2024 */
2025 int
2026 glXGetConfig( Display *dpy, XVisualInfo *vis, int attrib, int *value )
2027 {
2028 const __GLcontextModes *mode = vis->visual->mode;
2029 if (!mode) {
2030 *value = 0;
2031 return GLX_BAD_VISUAL;
2032 }
2033
2034 switch (attrib) {
2035 case GLX_USE_GL:
2036 *value = True;
2037 return 0;
2038 case GLX_RGBA:
2039 *value = mode->rgbMode;
2040 return 0;
2041 case GLX_DOUBLEBUFFER:
2042 *value = mode->doubleBufferMode;
2043 return 0;
2044 case GLX_RED_SIZE:
2045 *value = mode->redBits;
2046 return 0;
2047 case GLX_GREEN_SIZE:
2048 *value = mode->greenBits;
2049 return 0;
2050 case GLX_BLUE_SIZE:
2051 *value = mode->blueBits;
2052 return 0;
2053 case GLX_ALPHA_SIZE:
2054 *value = mode->alphaBits;
2055 return 0;
2056 case GLX_DEPTH_SIZE:
2057 *value = mode->depthBits;
2058 return 0;
2059 case GLX_STENCIL_SIZE:
2060 *value = mode->stencilBits;
2061 return 0;
2062 default:
2063 *value = 0;
2064 return GLX_BAD_ATTRIBUTE;
2065 }
2066 return 0;
2067 }
2068
2069
2070 /**
2071 * \brief Create a new GLX rendering context.
2072 *
2073 * \param dpy the display handle, as returned by XOpenDisplay().
2074 * \param vis the visual that defines the frame buffer resources available to
2075 * the rendering context, as returned by glXChooseVisual().
2076 * \param shareList If non-zero, texture objects and display lists are shared
2077 * with the named rendering context. If zero, texture objects and display lists
2078 * will (initially) be private to this context. They may be shared when a
2079 * subsequent context is created.
2080 * \param direct whether direct or indirect rendering is desired. For Mini GLX
2081 * this value is ignored but it should be set to \c True.
2082 *
2083 * \return a ::GLXContext handle if it succeeds or zero if it fails due to
2084 * invalid parameter or insufficient resources.
2085 *
2086 * This function creates and initializes a ::MiniGLXContextRec structure and
2087 * calls the __DRIscreenRec::createContext method to initialize the client
2088 * private data.
2089 */
2090 GLXContext
2091 glXCreateContext( Display *dpy, XVisualInfo *vis,
2092 GLXContext shareList, Bool direct )
2093 {
2094 GLXContext ctx;
2095 void *sharePriv;
2096
2097 ASSERT(vis);
2098
2099 ctx = (struct MiniGLXContextRec *)calloc(1, sizeof(struct MiniGLXContextRec));
2100 if (!ctx)
2101 return NULL;
2102
2103 ctx->vid = vis->visualid;
2104
2105 if (shareList)
2106 sharePriv = shareList->driContext.private;
2107 else
2108 sharePriv = NULL;
2109
2110 ctx->driContext.mode = vis->visual->mode;
2111 ctx->driContext.private = dpy->driScreen.createNewContext(dpy, vis->visual->mode,
2112 GLX_WINDOW_BIT, sharePriv, &ctx->driContext);
2113
2114 if (!ctx->driContext.private) {
2115 free(ctx);
2116 return NULL;
2117 }
2118
2119 return ctx;
2120 }
2121
2122
2123 /**
2124 * \brief Destroy a GLX context.
2125 *
2126 * \param dpy the display handle, as returned by XOpenDisplay().
2127 * \param ctx the GLX context to be destroyed.
2128 *
2129 * This function frees the \p ctx parameter after unbinding the current context
2130 * by calling the __DRIcontextRec::bindContext method with zeros and calling
2131 * the __DRIcontextRec::destroyContext method.
2132 */
2133 void
2134 glXDestroyContext( Display *dpy, GLXContext ctx )
2135 {
2136 GLXContext glxctx = glXGetCurrentContext();
2137
2138 if (ctx) {
2139 if (glxctx == ctx) {
2140 /* destroying current context */
2141 ctx->driContext.bindContext(dpy, 0, 0, 0, 0);
2142 CurrentContext = 0;
2143 }
2144 ctx->driContext.destroyContext(dpy, 0, ctx->driContext.private);
2145 free(ctx);
2146 }
2147 }
2148
2149
2150 /**
2151 * \brief Bind a GLX context to a window or a pixmap.
2152 *
2153 * \param dpy the display handle, as returned by XOpenDisplay().
2154 * \param drawable the window or drawable to bind to the rendering context.
2155 * This should be the value returned by XCreateWindow().
2156 * \param ctx the GLX context to be destroyed.
2157 *
2158 * \return \c True if it succeeds, \c False otherwise to indicate an invalid
2159 * display, window or context parameter.
2160 *
2161 * The current rendering context may be unbound by calling glXMakeCurrent()
2162 * with the window and context parameters set to zero.
2163 *
2164 * An application may create any number of rendering contexts and bind them as
2165 * needed. Note that binding a rendering context is generally not a
2166 * light-weight operation. Most simple OpenGL applications create only one
2167 * rendering context.
2168 *
2169 * This function first unbinds any old context via
2170 * __DRIcontextRec::unbindContext and binds the new one via
2171 * __DRIcontextRec::bindContext.
2172 *
2173 * If \p drawable is zero it unbinds the GLX context by calling
2174 * __DRIcontextRec::bindContext with zeros.
2175 */
2176 Bool
2177 glXMakeCurrent( Display *dpy, GLXDrawable drawable, GLXContext ctx)
2178 {
2179 if (dpy && drawable && ctx) {
2180 GLXContext oldContext = glXGetCurrentContext();
2181 GLXDrawable oldDrawable = glXGetCurrentDrawable();
2182 /* unbind old */
2183 if (oldContext) {
2184 oldContext->driContext.unbindContext(dpy, 0,
2185 (__DRIid) oldDrawable, (__DRIid) oldDrawable,
2186 &oldContext->driContext);
2187 }
2188 /* bind new */
2189 CurrentContext = ctx;
2190 ctx->driContext.bindContext(dpy, 0, (__DRIid) drawable,
2191 (__DRIid) drawable, &ctx->driContext);
2192 ctx->drawBuffer = drawable;
2193 ctx->curBuffer = drawable;
2194 }
2195 else if (ctx && dpy) {
2196 /* unbind */
2197 ctx->driContext.bindContext(dpy, 0, 0, 0, 0);
2198 }
2199 else if (dpy) {
2200 CurrentContext = 0; /* kw: this seems to be intended??? */
2201 }
2202
2203 return True;
2204 }
2205
2206
2207 /**
2208 * \brief Exchange front and back buffers.
2209 *
2210 * \param dpy the display handle, as returned by XOpenDisplay().
2211 * \param drawable the drawable whose buffers are to be swapped.
2212 *
2213 * Any pending rendering commands will be completed before the buffer swap
2214 * takes place.
2215 *
2216 * Calling glXSwapBuffers() on a window which is single-buffered has no effect.
2217 *
2218 * This function just calls the __DRIdrawableRec::swapBuffers method to do the
2219 * work.
2220 */
2221 void
2222 glXSwapBuffers( Display *dpy, GLXDrawable drawable )
2223 {
2224 if (!dpy || !drawable)
2225 return;
2226
2227 drawable->driDrawable.swapBuffers(dpy, drawable->driDrawable.private);
2228 }
2229
2230
2231 /**
2232 * \brief Return the current context
2233 *
2234 * \return the current context, as specified by glXMakeCurrent(), or zero if no
2235 * context is currently bound.
2236 *
2237 * \sa glXCreateContext(), glXMakeCurrent()
2238 *
2239 * Returns the value of the ::CurrentContext global variable.
2240 */
2241 GLXContext
2242 glXGetCurrentContext( void )
2243 {
2244 return CurrentContext;
2245 }
2246
2247
2248 /**
2249 * \brief Return the current drawable.
2250 *
2251 * \return the current drawable, as specified by glXMakeCurrent(), or zero if
2252 * no drawable is currently bound.
2253 *
2254 * This function gets the current context via glXGetCurrentContext() and
2255 * returns the MiniGLXContextRec::drawBuffer attribute.
2256 */
2257 GLXDrawable
2258 glXGetCurrentDrawable( void )
2259 {
2260 GLXContext glxctx = glXGetCurrentContext();
2261 if (glxctx)
2262 return glxctx->drawBuffer;
2263 else
2264 return NULL;
2265 }
2266
2267
2268 static GLboolean
2269 __glXCreateContextWithConfig(__DRInativeDisplay *dpy, int screen,
2270 int fbconfigID, void *contextID, drm_context_t *hHWContext)
2271 {
2272 __DRIscreen *pDRIScreen;
2273 __DRIscreenPrivate *psp;
2274
2275 pDRIScreen = __glXFindDRIScreen(dpy, screen);
2276 if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
2277 return GL_FALSE;
2278 }
2279
2280 psp = (__DRIscreenPrivate *) pDRIScreen->private;
2281
2282 if (psp->fd) {
2283 if (drmCreateContext(psp->fd, hHWContext)) {
2284 fprintf(stderr, ">>> drmCreateContext failed\n");
2285 return GL_FALSE;
2286 }
2287 *(void**)contextID = (void*) *hHWContext;
2288 }
2289
2290 return GL_TRUE;
2291 }
2292
2293
2294 static GLboolean
2295 __glXGetDrawableInfo(__DRInativeDisplay *dpy, int scrn,
2296 __DRIid draw, unsigned int * index, unsigned int * stamp,
2297 int * x, int * y, int * width, int * height,
2298 int * numClipRects, drm_clip_rect_t ** pClipRects,
2299 int * backX, int * backY,
2300 int * numBackClipRects, drm_clip_rect_t ** pBackClipRects)
2301 {
2302 GLXDrawable drawable = (GLXDrawable) draw;
2303 drm_clip_rect_t * cliprect;
2304 Display* display = (Display*)dpy;
2305 __DRIcontextPrivate *pcp = (__DRIcontextPrivate *)CurrentContext->driContext.private;
2306 if (drawable == 0) {
2307 return GL_FALSE;
2308 }
2309
2310 cliprect = (drm_clip_rect_t*) _mesa_malloc(sizeof(drm_clip_rect_t));
2311 cliprect->x1 = drawable->x;
2312 cliprect->y1 = drawable->y;
2313 cliprect->x2 = drawable->x + drawable->w;
2314 cliprect->y2 = drawable->y + drawable->h;
2315
2316 /* the drawable index is by client id */
2317 *index = display->clientID;
2318
2319 *stamp = pcp->driScreenPriv->pSAREA->drawableTable[display->clientID].stamp;
2320 *x = drawable->x;
2321 *y = drawable->y;
2322 *width = drawable->w;
2323 *height = drawable->h;
2324 *numClipRects = 1;
2325 *pClipRects = cliprect;
2326
2327 *backX = drawable->x;
2328 *backY = drawable->y;
2329 *numBackClipRects = 0;
2330 *pBackClipRects = 0;
2331
2332 return GL_TRUE;
2333 }
2334
2335
2336 static GLboolean
2337 xf86DRI_DestroyContext(__DRInativeDisplay *dpy, int screen, __DRIid context_id )
2338 {
2339 return GL_TRUE;
2340 }
2341
2342
2343 static GLboolean
2344 xf86DRI_CreateDrawable(__DRInativeDisplay *dpy, int screen, __DRIid drawable,
2345 drm_drawable_t *hHWDrawable )
2346 {
2347 return GL_TRUE;
2348 }
2349
2350
2351 static GLboolean
2352 xf86DRI_DestroyDrawable(__DRInativeDisplay *dpy, int screen, __DRIid drawable)
2353 {
2354 return GL_TRUE;
2355 }
2356
2357
2358 /**
2359 * \brief Query function address.
2360 *
2361 * The glXGetProcAddress() function will return the address of any available
2362 * OpenGL or Mini GLX function.
2363 *
2364 * \param procName name of the function to be returned.
2365 *
2366 * \return If \p procName is a valid function name, a pointer to that function
2367 * will be returned. Otherwise, \c NULL will be returned.
2368 *
2369 * The purpose of glXGetProcAddress() is to facilitate using future extensions
2370 * to OpenGL or Mini GLX. If a future version of the library adds new extension
2371 * functions they'll be accessible via glXGetProcAddress(). The alternative is
2372 * to hard-code calls to the new functions in the application but doing so will
2373 * prevent linking the application with older versions of the library.
2374 *
2375 * Returns the function address by looking up its name in a static (name,
2376 * address) pair list.
2377 */
2378 void (*glXGetProcAddress(const GLubyte *procname))( void )
2379 {
2380 struct name_address {
2381 const char *name;
2382 const void *func;
2383 };
2384 static const struct name_address functions[] = {
2385 { "glXChooseVisual", (void *) glXChooseVisual },
2386 { "glXCreateContext", (void *) glXCreateContext },
2387 { "glXDestroyContext", (void *) glXDestroyContext },
2388 { "glXMakeCurrent", (void *) glXMakeCurrent },
2389 { "glXSwapBuffers", (void *) glXSwapBuffers },
2390 { "glXGetCurrentContext", (void *) glXGetCurrentContext },
2391 { "glXGetCurrentDrawable", (void *) glXGetCurrentDrawable },
2392 { "glXGetProcAddress", (void *) glXGetProcAddress },
2393 { "XOpenDisplay", (void *) XOpenDisplay },
2394 { "XCloseDisplay", (void *) XCloseDisplay },
2395 { "XCreateWindow", (void *) XCreateWindow },
2396 { "XDestroyWindow", (void *) XDestroyWindow },
2397 { "XMapWindow", (void *) XMapWindow },
2398 { "XCreateColormap", (void *) XCreateColormap },
2399 { "XFreeColormap", (void *) XFreeColormap },
2400 { "XFree", (void *) XFree },
2401 { "XGetVisualinfo", (void *) XGetVisualInfo },
2402 { "glXCreatePbuffer", (void *) glXCreatePbuffer },
2403 { "glXDestroyPbuffer", (void *) glXDestroyPbuffer },
2404 { "glXChooseFBConfig", (void *) glXChooseFBConfig },
2405 { "glXGetVisualFromFBConfig", (void *) glXGetVisualFromFBConfig },
2406 { NULL, NULL }
2407 };
2408 const struct name_address *entry;
2409 for (entry = functions; entry->name; entry++) {
2410 if (strcmp(entry->name, (const char *) procname) == 0) {
2411 return entry->func;
2412 }
2413 }
2414 return _glapi_get_proc_address((const char *) procname);
2415 }
2416
2417
2418 /**
2419 * \brief Query the Mini GLX version.
2420 *
2421 * \param dpy the display handle. It is currently ignored, but should be the
2422 * value returned by XOpenDisplay().
2423 * \param major receives the major version number of Mini GLX.
2424 * \param minor receives the minor version number of Mini GLX.
2425 *
2426 * \return \c True if the function succeeds, \c False if the function fails due
2427 * to invalid parameters.
2428 *
2429 * \sa #MINI_GLX_VERSION_1_0.
2430 *
2431 * Returns the hard-coded Mini GLX version.
2432 */
2433 Bool
2434 glXQueryVersion( Display *dpy, int *major, int *minor )
2435 {
2436 (void) dpy;
2437 *major = 1;
2438 *minor = 0;
2439 return True;
2440 }
2441
2442
2443 /**
2444 * \brief Create a new pbuffer.
2445 */
2446 GLXPbuffer
2447 glXCreatePbuffer( Display *dpy, GLXFBConfig config, const int *attribList )
2448 {
2449 return NULL;
2450 }
2451
2452
2453 void
2454 glXDestroyPbuffer( Display *dpy, GLXPbuffer pbuf )
2455 {
2456 free(pbuf);
2457 }
2458
2459
2460 GLXFBConfig *
2461 glXChooseFBConfig( Display *dpy, int screen, const int *attribList,
2462 int *nitems )
2463 {
2464 GLXFBConfig *f = (GLXFBConfig *) malloc(sizeof(GLXFBConfig));
2465 f->visInfo = glXChooseVisual( dpy, screen, (int *) attribList );
2466 if (f->visInfo) {
2467 *nitems = 1;
2468 return f;
2469 }
2470 else {
2471 *nitems = 0;
2472 free(f);
2473 return NULL;
2474 }
2475 }
2476
2477
2478 XVisualInfo *
2479 glXGetVisualFromFBConfig( Display *dpy, GLXFBConfig config )
2480 {
2481 /* XVisualInfo and GLXFBConfig are the same structure */
2482 (void) dpy;
2483 return config.visInfo;
2484 }
2485
2486 void *glXAllocateMemoryMESA(Display *dpy, int scrn,
2487 size_t size, float readFreq,
2488 float writeFreq, float priority)
2489 {
2490 if (dpy->driScreen.private && dpy->driScreen.allocateMemory) {
2491 return (*dpy->driScreen.allocateMemory)( dpy, scrn, size,
2492 readFreq, writeFreq,
2493 priority );
2494 }
2495
2496 return NULL;
2497 }
2498
2499 void glXFreeMemoryMESA(Display *dpy, int scrn, void *pointer)
2500 {
2501 if (dpy->driScreen.private && dpy->driScreen.freeMemory) {
2502 (*dpy->driScreen.freeMemory)( dpy, scrn, pointer );
2503 }
2504 }
2505
2506 GLuint glXGetMemoryOffsetMESA( Display *dpy, int scrn,
2507 const void *pointer )
2508 {
2509 if (dpy->driScreen.private && dpy->driScreen.memoryOffset) {
2510 return (*dpy->driScreen.memoryOffset)( dpy, scrn, pointer );
2511 }
2512
2513 return 0;
2514 }
2515
2516
2517 /**
2518 * Get the unadjusted system time (UST). Currently, the UST is measured in
2519 * microseconds since Epoc. The actual resolution of the UST may vary from
2520 * system to system, and the units may vary from release to release.
2521 * Drivers should not call this function directly. They should instead use
2522 * \c glXGetProcAddress to obtain a pointer to the function.
2523 *
2524 * \param ust Location to store the 64-bit UST
2525 * \returns Zero on success or a negative errno value on failure.
2526 *
2527 * \note
2528 * This function was copied directly from src/glx/x11/glxcmds.c.
2529 */
2530 static int __glXGetUST( int64_t * ust )
2531 {
2532 struct timeval tv;
2533
2534 if ( ust == NULL ) {
2535 return -EFAULT;
2536 }
2537
2538 if ( gettimeofday( & tv, NULL ) == 0 ) {
2539 ust[0] = (tv.tv_sec * 1000000) + tv.tv_usec;
2540 return 0;
2541 } else {
2542 return -errno;
2543 }
2544 }
2545
2546
2547 /**
2548 *
2549 * \bug
2550 * This needs to be implemented for miniGlx.
2551 */
2552 static GLboolean __glXGetMscRate(__DRInativeDisplay * dpy, __DRIid drawable,
2553 int32_t * numerator, int32_t * denominator)
2554 {
2555 *numerator = 0;
2556 *denominator = 0;
2557 return False;
2558 }
2559 /*@}*/