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