3
* \brief Mini GLX interface functions.
6
* The Mini GLX interface is a subset of the GLX interface, plus a
7
* minimal set of Xlib functions.
11
* Mesa 3-D graphics library
14
* Copyright (C) 1999-2004 Brian Paul All Rights Reserved.
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:
23
* The above copyright notice and this permission notice shall be included
24
* in all copies or substantial portions of the Software.
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.
38
* \section miniglxIntro Introduction
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
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.
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.
54
* \section miniglxDoxygen About Doxygen
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.
59
* For a list of all functions, types, constants, etc.
60
* select <b>File Members</b>.
63
* \section miniglxReferences References
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
77
* \page datatypes Notes on the XVisualInfo, Visual, and __GLXvisualConfig data types
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.
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>
111
#include "miniglxP.h"
112
#include "dri_util.h"
115
#include "glcontextmodes.h"
118
#include "pciaccess.h"
120
static GLboolean __glXCreateContextWithConfig(__DRInativeDisplay *dpy,
121
int screen, int fbconfigID, void *contextID,
122
drm_context_t *hHWContext);
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);
131
static __DRIscreen * __glXFindDRIScreen(__DRInativeDisplay *dpy, int scrn);
133
static GLboolean __glXWindowExists(__DRInativeDisplay *dpy, __DRIid draw);
135
static int __glXGetUST( int64_t * ust );
137
static GLboolean __glXGetMscRate(__DRInativeDisplay * dpy, __DRIid drawable,
138
int32_t * numerator, int32_t * denominator);
140
static GLboolean xf86DRI_DestroyContext(__DRInativeDisplay *dpy, int screen,
141
__DRIid context_id );
143
static GLboolean xf86DRI_CreateDrawable(__DRInativeDisplay *dpy, int screen,
144
__DRIid drawable, drm_drawable_t *hHWDrawable );
146
static GLboolean xf86DRI_DestroyDrawable(__DRInativeDisplay *dpy, int screen,
150
/** Wrapper around either malloc() */
152
_mesa_malloc(size_t bytes)
154
return malloc(bytes);
157
/** Wrapper around either calloc() */
159
_mesa_calloc(size_t bytes)
161
return calloc(1, bytes);
164
/** Wrapper around either free() */
166
_mesa_free(void *ptr)
173
* \brief Current GLX context.
175
* \sa glXGetCurrentContext().
177
static GLXContext CurrentContext = NULL;
181
static Display *SignalDisplay = 0;
183
static void SwitchVT(int sig)
185
fprintf(stderr, "SwitchVT %d dpy %p\n", sig, SignalDisplay);
188
SignalDisplay->vtSignalFlag = 1;
191
case SIGUSR1: /* vt has been released */
192
SignalDisplay->haveVT = 0;
194
case SIGUSR2: /* vt has been acquired */
195
SignalDisplay->haveVT = 1;
201
/**********************************************************************/
202
/** \name Framebuffer device functions */
203
/**********************************************************************/
207
* \brief Do the first part of setting up the framebuffer device.
209
* \param dpy the display handle.
210
* \param use_vt use a VT for display or not
212
* \return GL_TRUE on success, or GL_FALSE on failure.
214
* \sa This is called during XOpenDisplay().
217
* Gets the VT number, opens the respective console TTY device. Saves its state
218
* to restore when exiting and goes into graphics mode.
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.
225
OpenFBDev( Display *dpy, int use_vt )
228
int fd, vtnumber, ttyfd;
233
fprintf(stderr, "error: you need to be root\n");
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");
244
if (ioctl(fd, VT_OPENQRY, &vtnumber) < 0 || vtnumber < 0) {
245
fprintf(stderr, "error: couldn't get a free vt\n");
249
fprintf(stderr, "*** got vt nr: %d\n", vtnumber);
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");
260
/* save current vt number */
263
if (ioctl(dpy->ConsoleFD, VT_GETSTATE, &vts) == 0)
264
dpy->OriginalVT = vts.v_active;
267
/* disconnect from controlling tty */
268
ttyfd = open("/dev/tty", O_RDWR);
270
ioctl(ttyfd, TIOCNOTTY, 0);
274
/* some magic to restore the vt when we exit */
277
struct sigaction sig_tty;
279
/* Set-up tty signal handler to catch the signal we request below */
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 ) )
287
fprintf(stderr, "error: can't set up signal handler (%s)",
294
vt.mode = VT_PROCESS;
298
if (ioctl(dpy->ConsoleFD, VT_SETMODE, &vt) < 0) {
299
fprintf(stderr, "error: ioctl(VT_SETMODE) failed: %s\n",
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));
310
if (ioctl(dpy->ConsoleFD, VT_GETMODE, &vt) < 0) {
311
fprintf(stderr, "error: ioctl VT_GETMODE: %s\n", strerror(errno));
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",
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));
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",
342
dpy->VarInfo = dpy->OrigVarInfo; /* structure copy */
344
/* Turn off hw accels (otherwise mmap of mmio region will be
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",
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",
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 */
375
if (dpy->driverContext.FBAddress == (caddr_t) - 1) {
376
fprintf(stderr, "error: unable to mmap framebuffer: %s\n",
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",
396
fprintf(stderr, "got MMIOAddress %p offset %d\n",
397
dpy->driverContext.MMIOAddress,
398
dpy->FixedInfo.smem_len);
407
* \brief Setup up the desired framebuffer device mode.
409
* \param dpy the display handle.
411
* \return GL_TRUE on success, or GL_FALSE on failure.
413
* \sa This is called during __miniglx_StartServer().
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.
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.
429
* \todo Timings are hard-coded in the source for a set of supported modes.
432
SetupFBDev( Display *dpy )
438
width = dpy->driverContext.shared.virtualWidth;
439
height = dpy->driverContext.shared.virtualHeight;
444
/* Bump size up to next supported mode.
446
if (width <= 720 && height <= 480) {
447
width = 720; height = 480;
449
else if (width <= 960 && height <= 540) {
450
width = 960; height = 540;
452
else if (width <= 800 && height <= 600) {
453
width = 800; height = 600;
455
else if (width <= 1024 && height <= 768) {
456
width = 1024; height = 768;
458
else if (width <= 768 && height <= 1024) {
459
width = 768; height = 1024;
461
else if (width <= 1280 && height <= 1024) {
462
width = 1280; height = 1024;
466
dpy->driverContext.shared.fbStride = width * (dpy->driverContext.bpp / 8);
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 */
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;
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;
501
fprintf(stderr, "Only 32bpp and 16bpp modes supported at the moment\n");
505
if (!dpy->driver->validateMode( &dpy->driverContext )) {
506
fprintf(stderr, "Driver validateMode() failed\n");
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;
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;
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;
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;
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;
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;
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);
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);
588
/* set variable screen info */
589
if (ioctl(dpy->FrameBufferFD, FBIOPUT_VSCREENINFO, &dpy->VarInfo)) {
590
fprintf(stderr, "error: ioctl(FBIOPUT_VSCREENINFO) failed: %s\n",
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",
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);
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",
615
if (dpy->FixedInfo.visual != FB_VISUAL_TRUECOLOR &&
616
dpy->FixedInfo.visual != FB_VISUAL_DIRECTCOLOR) {
617
fprintf(stderr, "non-TRUECOLOR visuals not supported.\n");
621
if (dpy->FixedInfo.visual == FB_VISUAL_DIRECTCOLOR) {
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;
636
for (i = 0; i < rcols ; i++)
637
red[i] = (65536/(rcols-1)) * i;
639
for (i = 0; i < gcols ; i++)
640
green[i] = (65536/(gcols-1)) * i;
642
for (i = 0; i < bcols ; i++)
643
blue[i] = (65536/(bcols-1)) * i;
645
if (ioctl(dpy->FrameBufferFD, FBIOPUTCMAP, (void *) &cmap) < 0) {
646
fprintf(stderr, "ioctl(FBIOPUTCMAP) failed [%d]\n", i);
651
/* May need to restore regs fbdev has clobbered:
653
if (!dpy->driver->postValidateMode( &dpy->driverContext )) {
654
fprintf(stderr, "Driver postValidateMode() failed\n");
663
* \brief Restore the framebuffer device to state it was in before we started
665
* Undoes the work done by SetupFBDev().
667
* \param dpy the display handle.
669
* \return GL_TRUE on success, or GL_FALSE on failure.
671
* \sa Called from XDestroyWindow().
674
* Restores the original variable screen info.
677
RestoreFBDev( Display *dpy )
679
/* restore original variable screen info */
680
if (ioctl(dpy->FrameBufferFD, FBIOPUT_VSCREENINFO, &dpy->OrigVarInfo)) {
681
fprintf(stderr, "ioctl(FBIOPUT_VSCREENINFO failed): %s\n",
685
dpy->VarInfo = dpy->OrigVarInfo;
692
* \brief Close the framebuffer device.
694
* \param dpy the display handle.
696
* \sa Called from XCloseDisplay().
699
* Unmaps the framebuffer and MMIO region. Restores the text mode and the
700
* original virtual terminal. Closes the console and framebuffer devices.
703
CloseFBDev( Display *dpy )
707
munmap(dpy->driverContext.FBAddress, dpy->driverContext.FBSize);
708
munmap(dpy->driverContext.MMIOAddress, dpy->driverContext.MMIOSize);
710
if (dpy->ConsoleFD) {
711
/* restore text mode */
712
ioctl(dpy->ConsoleFD, KDSETMODE, KD_TEXT);
715
if (ioctl(dpy->ConsoleFD, VT_GETMODE, &VT) != -1) {
717
ioctl(dpy->ConsoleFD, VT_SETMODE, &VT);
720
/* restore original vt */
721
if (dpy->OriginalVT >= 0) {
722
ioctl(dpy->ConsoleFD, VT_ACTIVATE, dpy->OriginalVT);
723
dpy->OriginalVT = -1;
726
close(dpy->ConsoleFD);
728
close(dpy->FrameBufferFD);
734
/**********************************************************************/
735
/** \name Misc functions needed for DRI drivers */
736
/**********************************************************************/
740
* \brief Find the DRI screen dependent methods associated with the display.
742
* \param dpy a display handle, as returned by XOpenDisplay().
743
* \param scrn the screen number. Not referenced.
745
* \returns a pointer to a __DRIscreenRec structure.
748
* Returns the MiniGLXDisplayRec::driScreen attribute.
751
__glXFindDRIScreen(__DRInativeDisplay *dpy, int scrn)
754
return &((Display*)dpy)->driScreen;
758
* \brief Validate a drawable.
760
* \param dpy a display handle, as returned by XOpenDisplay().
761
* \param draw drawable to validate.
764
* Since Mini GLX only supports one window, compares the specified drawable with
765
* the MiniGLXDisplayRec::TheWindow attribute.
768
__glXWindowExists(__DRInativeDisplay *dpy, __DRIid draw)
770
const Display * const display = (Display*)dpy;
771
if (display->TheWindow == (Window) draw)
778
* \brief Get current thread ID.
786
_glthread_GetID(void)
795
* \brief Scan Linux /prog/bus/pci/devices file to determine hardware
796
* chipset based on supplied bus ID.
798
* \return probed chipset (non-zero) on success, zero otherwise.
802
static int get_chipset_from_busid( Display *dpy )
806
const char *fname = "/proc/bus/pci/devices";
809
if (!(file = fopen(fname,"r"))) {
810
fprintf(stderr, "couldn't open %s: %s\n", fname, strerror(errno));
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,
820
dev = (encode & 0xFF) >> 3;
826
if (bus == dpy->driverContext.pciBus &&
827
dev == dpy->driverContext.pciDevice &&
828
fn == dpy->driverContext.pciFunc) {
837
fprintf(stderr, "[miniglx] probed chipset 0x%x\n", retval);
839
fprintf(stderr, "[miniglx] failed to probe chipset\n");
846
* \brief Read settings from a configuration file.
848
* The configuration file is usually "/etc/miniglx.conf", but can be overridden
849
* with the MINIGLX_CONF environment variable.
851
* The format consists in \code option = value \endcode lines. The option names
852
* corresponds to the fields in MiniGLXDisplayRec.
854
* \param dpy the display handle as.
856
* \return non-zero on success, zero otherwise.
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.
862
static int __read_config_file( Display *dpy )
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;
881
dpy->driverContext.agpmode = 1;
882
dpy->driverContext.isPCI = 0;
883
dpy->driverContext.colorTiling = 0;
885
fname = getenv("MINIGLX_CONF");
886
if (!fname) fname = "/etc/miniglx.conf";
888
file = fopen(fname, "r");
890
fprintf(stderr, "couldn't open config file %s: %s\n", fname, strerror(errno));
895
while (!feof(file)) {
896
char buf[81], *opt = buf, *val, *tmp1, *tmp2;
897
fgets(buf, sizeof(buf), file);
899
/* Parse 'opt = val' -- must be easier ways to do this.
901
while (isspace(*opt)) opt++;
903
if (*val == '#') continue; /* comment */
904
while (!isspace(*val) && *val != '=' && *val) val++;
906
while (isspace(*val)) val++;
907
if (*val != '=') continue;
910
while (isspace(*val)) val++;
912
while (!isspace(*tmp2) && *tmp2 != '\n' && *tmp2) tmp2++;
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);
930
dpy->driverContext.pciBusID = strdup(val);
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);
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);
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);
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;
949
else if (strcmp(opt, "agpmode") == 0) {
950
if (sscanf(val, "%d", &dpy->driverContext.agpmode) != 1)
951
fprintf(stderr, "malformed agpmode: %s\n", opt);
953
else if (strcmp(opt, "isPCI") == 0) {
954
dpy->driverContext.isPCI = atoi(val) ? 1 : 0;
956
else if (strcmp(opt, "colorTiling") == 0) {
957
dpy->driverContext.colorTiling = atoi(val) ? 1 : 0;
963
if (dpy->driverContext.chipset == 0 && dpy->driverContext.pciBusID != 0)
964
dpy->driverContext.chipset = get_chipset_from_busid( dpy );
970
* Versioned name of the expected \c __driCreateNewScreen function.
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.
977
* Create a macro or something so that this is automatically updated.
979
static const char createNewScreenName[] = "__driCreateNewScreen_20050727";
982
static int InitDriver( Display *dpy )
986
* We're kind of combining the per-display and per-screen information
987
* which was kept separate in XFree86/DRI's libGL.
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,
996
/* Pull in Mini GLX specific hooks:
998
dpy->driver = (struct DRIDriverRec *) dlsym(dpy->dlHandle,
1001
fprintf(stderr, "Couldn't find __driDriver in %s\n",
1002
dpy->clientDriverName);
1006
/* Pull in standard DRI client-side driver hooks:
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);
1019
if (dpy->dlHandle) {
1020
dlclose(dpy->dlHandle);
1027
/**********************************************************************/
1028
/** \name Public API functions (Xlib and GLX) */
1029
/**********************************************************************/
1034
* \brief Initialize the graphics system.
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.
1040
* Allocates a MiniGLXDisplayRec structure and fills in with information from a
1041
* configuration file.
1043
* Calls OpenFBDev() to open the framebuffer device and calls
1044
* DRIDriverRec::initFBDev to do the client-side initialization on it.
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
1052
* Does the framebuffer device setup. Calls __miniglx_open_connections() to
1056
__miniglx_StartServer( const char *display_name )
1063
dpy = (Display *)calloc(1, sizeof(Display));
1067
dpy->IsClient = False;
1069
if (!__read_config_file( dpy )) {
1070
fprintf(stderr, "Couldn't get configuration details\n");
1075
/* Open the fbdev device
1077
if (!OpenFBDev(dpy, use_vt)) {
1078
fprintf(stderr, "OpenFBDev failed\n");
1083
if (!InitDriver(dpy)) {
1084
fprintf(stderr, "InitDriver failed\n");
1089
/* Perform the initialization normally done in the X server
1091
if (!dpy->driver->initFBDev( &dpy->driverContext )) {
1092
fprintf(stderr, "%s: __driInitFBDev failed\n", __FUNCTION__);
1093
dlclose(dpy->dlHandle);
1099
if (!SetupFBDev(dpy)) {
1100
fprintf(stderr, "SetupFBDev failed\n");
1105
/* unlock here if not using VT -- JDS */
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 );
1115
/* Ready for clients:
1117
if (!__miniglx_open_connections(dpy)) {
1127
* Implement \c __DRIinterfaceMethods::getProcAddress.
1129
static __DRIfuncPtr get_proc_address( const char * proc_name )
1137
* Table of functions exported by the loader to the driver.
1139
static const __DRIinterfaceMethods interface_methods = {
1142
_gl_context_modes_create,
1143
_gl_context_modes_destroy,
1148
__glXCreateContextWithConfig,
1149
xf86DRI_DestroyContext,
1151
xf86DRI_CreateDrawable,
1152
xf86DRI_DestroyDrawable,
1153
__glXGetDrawableInfo,
1161
CallCreateNewScreen(Display *dpy, int scrn, __DRIscreen *psc)
1164
drm_handle_t hSAREA;
1168
__DRIversion ddx_version;
1169
__DRIversion dri_version;
1170
__DRIversion drm_version;
1171
__DRIframebuffer framebuffer;
1174
const char * err_msg;
1175
const char * err_extra;
1176
drmVersionPtr version;
1181
hSAREA = dpy->driverContext.shared.hSAREA;
1182
BusID = dpy->driverContext.pciBusID;
1184
fd = drmOpen(NULL, BusID);
1186
err_msg = "open DRM";
1187
err_extra = strerror( -fd );
1189
if (fd < 0) goto done;
1191
err_msg = "drmGetMagic";
1194
if (drmGetMagic(fd, &magic)) goto done;
1196
dpy->authorized = False;
1197
send_char_msg( dpy, 0, _Authorize );
1198
send_msg( dpy, 0, &magic, sizeof(magic));
1200
/* force net buffer flush */
1201
while (!dpy->authorized)
1202
handle_fd_events( dpy, 0 );
1204
version = drmGetVersion(fd);
1206
drm_version.major = version->version_major;
1207
drm_version.minor = version->version_minor;
1208
drm_version.patch = version->version_patchlevel;
1209
drmFreeVersion(version);
1212
drm_version.major = -1;
1213
drm_version.minor = -1;
1214
drm_version.patch = -1;
1218
* Get device name (like "tdfx") and the ddx version numbers.
1219
* We'll check the version in each DRI driver's "createScreen"
1222
ddx_version.major = -1;
1223
ddx_version.minor = 0;
1224
ddx_version.patch = 0;
1227
* Get the DRI X extension version.
1229
dri_version.major = 4;
1230
dri_version.minor = 0;
1231
dri_version.patch = 0;
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.
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;
1248
* Map the framebuffer region.
1250
status = drmMap(fd, hFB, framebuffer.size,
1251
(drmAddressPtr)&framebuffer.base);
1253
err_msg = "drmMap of framebuffer";
1254
err_extra = strerror( -status );
1256
if ( status != 0 ) goto done;
1259
* Map the SAREA region. Further mmap regions may be setup in
1260
* each DRI driver's "createScreen" function.
1262
status = drmMap(fd, hSAREA, SAREA_MAX, &pSAREA);
1264
err_msg = "drmMap of sarea";
1265
err_extra = strerror( -status );
1267
if ( status == 0 ) {
1268
err_msg = "InitDriver";
1270
psp = dpy->createNewScreen(dpy, scrn, psc, NULL,
1278
& interface_methods,
1279
(__GLcontextModes **) &dpy->driver_modes);
1281
/* fill in dummy visual ids */
1283
__GLcontextModes *temp;
1284
temp = (__GLcontextModes *)dpy->driver_modes;
1288
temp->visualID = i++;
1295
if ( psp == NULL ) {
1296
if ( pSAREA != MAP_FAILED ) {
1297
(void)drmUnmap(pSAREA, SAREA_MAX);
1300
if ( framebuffer.base != MAP_FAILED ) {
1301
(void)drmUnmap((drmAddress)framebuffer.base, framebuffer.size);
1304
if ( framebuffer.dev_priv != NULL ) {
1305
free(framebuffer.dev_priv);
1312
if ( err_extra != NULL ) {
1313
fprintf(stderr, "libGL error: %s failed (%s)\n", err_msg,
1317
fprintf(stderr, "libGL error: %s failed\n", err_msg );
1320
fprintf(stderr, "libGL error: reverting to (slow) indirect rendering\n");
1327
* \brief Initialize the graphics system.
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.
1333
* Allocates a MiniGLXDisplayRec structure and fills in with information from a
1334
* configuration file.
1336
* Calls __miniglx_open_connections() to connect to the server.
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
1345
* - read config file
1346
* - what about virtualWidth, etc?
1347
* - determine dpy->driverClientMsgSize,
1348
* - allocate dpy->driverClientMsg
1351
XOpenDisplay( const char *display_name )
1355
dpy = (Display *)calloc(1, sizeof(Display));
1359
dpy->IsClient = True;
1363
if (!__read_config_file( dpy )) {
1364
fprintf(stderr, "Couldn't get configuration details\n");
1369
/* Connect to the server and receive driverClientMsg
1371
if (!__miniglx_open_connections(dpy)) {
1376
/* dlopen the driver .so file
1378
if (!InitDriver(dpy)) {
1379
fprintf(stderr, "InitDriver failed\n");
1384
/* Perform the client-side initialization.
1386
* Clearly there is a limit of one on the number of windows in
1387
* existence at any time.
1389
* Need to shut down DRM and free DRI data in XDestroyWindow(), too.
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);
1399
/* Anything more to do?
1406
* \brief Release display resources.
1408
* When the application is about to exit, the resources associated with the
1409
* graphics system can be released by calling this function.
1411
* \param dpy display handle. It becomes invalid at this point.
1413
* Destroys the window if any, and destroys the per-screen
1414
* driver private information.
1415
* Calls __miniglx_close_connections().
1417
* If a server, puts the the framebuffer back into the initial state.
1419
* Finally frees the display structure.
1422
XCloseDisplay( Display *dpy )
1424
glXMakeCurrent( dpy, NULL, NULL);
1426
if (dpy->NumWindows)
1427
XDestroyWindow( dpy, dpy->TheWindow );
1429
/* As this is done in XOpenDisplay, need to undo it here:
1431
dpy->driScreen.destroyScreen(dpy, 0, dpy->driScreen.private);
1433
__miniglx_close_connections( dpy );
1435
if (!dpy->IsClient) {
1436
/* put framebuffer back to initial state
1438
(*dpy->driver->haltFBDev)( &dpy->driverContext );
1443
dlclose(dpy->dlHandle);
1449
* \brief Window creation.
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
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
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.
1475
* \return a window handle if it succeeds or zero if it fails.
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.
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
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 )
1494
const int empty_attribute_list[1] = { None };
1501
(void) border_width;
1507
if (!dpy->IsClient) {
1508
fprintf(stderr, "Server process may not create windows (currently)\n");
1512
if (dpy->NumWindows > 0)
1513
return NULL; /* only allow one window */
1515
assert(dpy->TheWindow == NULL);
1517
win = malloc(sizeof(struct MiniGLXWindowRec));
1521
/* In rotated mode, translate incoming x,y,width,height into
1522
* 'normal' coordinates.
1524
if (dpy->rotateMode) {
1526
tmp = width; width = height; height = tmp;
1527
tmp = x; x = y; y = tmp;
1530
/* init other per-window fields */
1535
win->visual = visual; /* ptr assignment */
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;
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.
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;
1555
/* single buffered */
1556
win->backStart = NULL;
1557
win->backBottom = NULL;
1558
win->curBottom = win->frontBottom;
1561
dpy->driScreen.createNewDrawable(dpy, visual->mode, (int) win,
1562
&win->driDrawable, GLX_WINDOW_BIT, empty_attribute_list);
1564
if (!win->driDrawable.private) {
1565
fprintf(stderr, "%s: dri.createDrawable failed\n", __FUNCTION__);
1571
dpy->TheWindow = win;
1578
* \brief Destroy window.
1580
* \param display display handle.
1581
* \param w window handle.
1583
* This function calls XUnmapWindow() and frees window \p w.
1585
* In case of destroying the current buffer first unbinds the GLX context
1586
* by calling glXMakeCurrent() with no drawable.
1589
XDestroyWindow( Display *display, Window win )
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);
1598
XUnmapWindow( display, win );
1600
/* Destroy the drawable. */
1601
win->driDrawable.destroyDrawable(display, win->driDrawable.private);
1604
/* unlink window from display */
1605
display->NumWindows--;
1606
assert(display->NumWindows == 0);
1607
display->TheWindow = NULL;
1615
* \brief Create color map structure.
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.
1627
* \return the color map.
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).
1633
XCreateColormap( Display *dpy, Window w, Visual *visual, int alloc )
1639
return (Colormap) malloc(1);
1644
* \brief Destroy color map structure.
1646
* \param display The display handle as returned by XOpenDisplay().
1647
* \param colormap the color map to destroy.
1649
* This function is only provided to ease porting. Practically a no-op.
1651
* Frees the memory pointed by \p colormap.
1654
XFreeColormap( Display *display, Colormap colormap )
1663
* \brief Free client data.
1665
* \param data the data that is to be freed.
1667
* Frees the memory pointed by \p data.
1677
* \brief Query available visuals.
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.
1687
* \return the address of an array of all available visuals.
1689
* An example of using XGetVisualInfo() to get all available visuals follows:
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);
1699
* Returns the list of all ::XVisualInfo available, one per
1700
* ::__GLcontextMode stored in MiniGLXDisplayRec::modes.
1703
XGetVisualInfo( Display *dpy, long vinfo_mask, XVisualInfo *vinfo_template, int *nitens_return )
1705
const __GLcontextModes *mode;
1706
XVisualInfo *results;
1710
// ASSERT(vinfo_mask == VisualScreenMask);
1711
ASSERT(vinfo_template.screen == 0);
1713
if (vinfo_mask == VisualIDMask)
1715
for ( mode = dpy->driver_modes ; mode != NULL ; mode= mode->next )
1716
if (mode->visualID == vinfo_template->visualid)
1722
results = (XVisualInfo *)calloc(1, n * sizeof(XVisualInfo));
1728
visResults = (Visual *)calloc(1, n * sizeof(Visual));
1735
for ( mode = dpy->driver_modes ; mode != NULL ; mode= mode->next )
1736
if (mode->visualID == vinfo_template->visualid)
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 */
1744
visResults[0].pixelFormat = PF_B5G6R5; /* XXX: FIX ME */
1746
results[0].visual = visResults;
1747
results[0].visualid = mode->visualID;
1748
#if defined(__cplusplus) || defined(c_plusplus)
1749
results[0].c_class = TrueColor;
1751
results[0].class = TrueColor;
1753
results[0].depth = mode->redBits +
1757
results[0].bits_per_rgb = dpy->driverContext.bpp;
1762
else // if (vinfo_mask == VisualScreenMask)
1765
for ( mode = dpy->driver_modes ; mode != NULL ; mode = mode->next )
1768
results = (XVisualInfo *)calloc(1, n * sizeof(XVisualInfo));
1774
visResults = (Visual *)calloc(1, n * sizeof(Visual));
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;
1786
if (dpy->driverContext.bpp == 32)
1787
visResults[i].pixelFormat = PF_B8G8R8A8; /* XXX: FIX ME */
1789
visResults[i].pixelFormat = PF_B5G6R5; /* XXX: FIX ME */
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;
1796
results[i].class = TrueColor;
1798
results[i].depth = mode->redBits +
1802
results[i].bits_per_rgb = dpy->driverContext.bpp;
1811
* \brief Return a visual that matches specified attributes.
1813
* \param dpy the display handle, as returned by XOpenDisplay().
1814
* \param screen the screen number. It is currently ignored by Mini GLX and
1816
* \param attribList a list of GLX attributes which describe the desired pixel
1817
* format. It is terminated by the token \c None.
1819
* The attributes are as follows:
1821
* This attribute should always be present in order to maintain compatibility
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.
1847
* This token is used to terminate the attribute list.
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.
1853
* \note Visuals with accumulation buffers are not available.
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
1862
glXChooseVisual( Display *dpy, int screen, int *attribList )
1864
const __GLcontextModes *mode;
1866
XVisualInfo *visInfo;
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;
1875
* XXX in the future, <screen> might be interpreted as a VT
1878
ASSERT(screen == 0);
1880
vis = (Visual *)calloc(1, sizeof(Visual));
1884
visInfo = (XVisualInfo *)malloc(sizeof(XVisualInfo));
1890
visInfo->visual = vis;
1891
vis->visInfo = visInfo;
1894
/* parse the attribute list */
1895
for (attrib = attribList; attrib && *attrib != None; attrib++) {
1896
switch (attrib[0]) {
1897
case GLX_DOUBLEBUFFER:
1904
redBits = attrib[1];
1907
case GLX_GREEN_SIZE:
1908
greenBits = attrib[1];
1912
blueBits = attrib[1];
1915
case GLX_ALPHA_SIZE:
1916
alphaBits = attrib[1];
1919
case GLX_STENCIL_SIZE:
1920
stencilBits = attrib[1];
1923
case GLX_DEPTH_SIZE:
1924
depthBits = attrib[1];
1928
case GLX_ACCUM_RED_SIZE:
1929
accumRedBits = attrib[1];
1932
case GLX_ACCUM_GREEN_SIZE:
1933
accumGreenBits = attrib[1];
1936
case GLX_ACCUM_BLUE_SIZE:
1937
accumBlueBits = attrib[1];
1940
case GLX_ACCUM_ALPHA_SIZE:
1941
accumAlphaBits = attrib[1];
1945
/* ignored for now */
1949
/* unexpected token */
1950
fprintf(stderr, "unexpected token in glXChooseVisual attrib list\n");
1957
/* search screen configs for suitable visual */
1965
for ( mode = dpy->driver_modes ; mode != NULL ; mode = mode->next ) {
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) {
1976
visInfo->visualid = i;
1984
/* compute depth and bpp */
1986
/* XXX maybe support depth 16 someday */
1987
#if defined(__cplusplus) || defined(c_plusplus)
1988
visInfo->c_class = TrueColor;
1990
visInfo->class = TrueColor;
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;
1997
vis->pixelFormat = PF_B5G6R5;
2000
/* color index mode */
2001
#if defined(__cplusplus) || defined(c_plusplus)
2002
visInfo->c_class = PseudoColor;
2004
visInfo->class = PseudoColor;
2007
visInfo->bits_per_rgb = 8; /* bits/pixel */
2008
vis->pixelFormat = PF_CI8;
2016
* \brief Return information about GLX visuals.
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
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
2028
* Returns the appropriate attribute of ::__GLXvisualConfig pointed by
2029
* MiniGLXVisualRec::glxConfig of XVisualInfo::visual.
2034
glXGetConfig( Display *dpy, XVisualInfo *vis, int attrib, int *value )
2036
const __GLcontextModes *mode = vis->visual->mode;
2039
return GLX_BAD_VISUAL;
2047
*value = mode->rgbMode;
2049
case GLX_DOUBLEBUFFER:
2050
*value = mode->doubleBufferMode;
2053
*value = mode->redBits;
2055
case GLX_GREEN_SIZE:
2056
*value = mode->greenBits;
2059
*value = mode->blueBits;
2061
case GLX_ALPHA_SIZE:
2062
*value = mode->alphaBits;
2064
case GLX_DEPTH_SIZE:
2065
*value = mode->depthBits;
2067
case GLX_STENCIL_SIZE:
2068
*value = mode->stencilBits;
2072
return GLX_BAD_ATTRIBUTE;
2079
* \brief Create a new GLX rendering context.
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.
2091
* \return a ::GLXContext handle if it succeeds or zero if it fails due to
2092
* invalid parameter or insufficient resources.
2094
* This function creates and initializes a ::MiniGLXContextRec structure and
2095
* calls the __DRIscreenRec::createContext method to initialize the client
2099
glXCreateContext( Display *dpy, XVisualInfo *vis,
2100
GLXContext shareList, Bool direct )
2107
ctx = (struct MiniGLXContextRec *)calloc(1, sizeof(struct MiniGLXContextRec));
2111
ctx->vid = vis->visualid;
2114
sharePriv = shareList->driContext.private;
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);
2122
if (!ctx->driContext.private) {
2132
* \brief Destroy a GLX context.
2134
* \param dpy the display handle, as returned by XOpenDisplay().
2135
* \param ctx the GLX context to be destroyed.
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.
2142
glXDestroyContext( Display *dpy, GLXContext ctx )
2144
GLXContext glxctx = glXGetCurrentContext();
2147
if (glxctx == ctx) {
2148
/* destroying current context */
2149
ctx->driContext.bindContext(dpy, 0, 0, 0, 0);
2152
ctx->driContext.destroyContext(dpy, 0, ctx->driContext.private);
2159
* \brief Bind a GLX context to a window or a pixmap.
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.
2166
* \return \c True if it succeeds, \c False otherwise to indicate an invalid
2167
* display, window or context parameter.
2169
* The current rendering context may be unbound by calling glXMakeCurrent()
2170
* with the window and context parameters set to zero.
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.
2177
* This function first unbinds any old context via
2178
* __DRIcontextRec::unbindContext and binds the new one via
2179
* __DRIcontextRec::bindContext.
2181
* If \p drawable is zero it unbinds the GLX context by calling
2182
* __DRIcontextRec::bindContext with zeros.
2185
glXMakeCurrent( Display *dpy, GLXDrawable drawable, GLXContext ctx)
2187
if (dpy && drawable && ctx) {
2188
GLXContext oldContext = glXGetCurrentContext();
2189
GLXDrawable oldDrawable = glXGetCurrentDrawable();
2192
oldContext->driContext.unbindContext(dpy, 0,
2193
(__DRIid) oldDrawable, (__DRIid) oldDrawable,
2194
&oldContext->driContext);
2197
CurrentContext = ctx;
2198
ctx->driContext.bindContext(dpy, 0, (__DRIid) drawable,
2199
(__DRIid) drawable, &ctx->driContext);
2200
ctx->drawBuffer = drawable;
2201
ctx->curBuffer = drawable;
2203
else if (ctx && dpy) {
2205
ctx->driContext.bindContext(dpy, 0, 0, 0, 0);
2208
CurrentContext = 0; /* kw: this seems to be intended??? */
2216
* \brief Exchange front and back buffers.
2218
* \param dpy the display handle, as returned by XOpenDisplay().
2219
* \param drawable the drawable whose buffers are to be swapped.
2221
* Any pending rendering commands will be completed before the buffer swap
2224
* Calling glXSwapBuffers() on a window which is single-buffered has no effect.
2226
* This function just calls the __DRIdrawableRec::swapBuffers method to do the
2230
glXSwapBuffers( Display *dpy, GLXDrawable drawable )
2232
if (!dpy || !drawable)
2235
drawable->driDrawable.swapBuffers(dpy, drawable->driDrawable.private);
2240
* \brief Return the current context
2242
* \return the current context, as specified by glXMakeCurrent(), or zero if no
2243
* context is currently bound.
2245
* \sa glXCreateContext(), glXMakeCurrent()
2247
* Returns the value of the ::CurrentContext global variable.
2250
glXGetCurrentContext( void )
2252
return CurrentContext;
2257
* \brief Return the current drawable.
2259
* \return the current drawable, as specified by glXMakeCurrent(), or zero if
2260
* no drawable is currently bound.
2262
* This function gets the current context via glXGetCurrentContext() and
2263
* returns the MiniGLXContextRec::drawBuffer attribute.
2266
glXGetCurrentDrawable( void )
2268
GLXContext glxctx = glXGetCurrentContext();
2270
return glxctx->drawBuffer;
2277
__glXCreateContextWithConfig(__DRInativeDisplay *dpy, int screen,
2278
int fbconfigID, void *contextID, drm_context_t *hHWContext)
2280
__DRIscreen *pDRIScreen;
2281
__DRIscreenPrivate *psp;
2283
pDRIScreen = __glXFindDRIScreen(dpy, screen);
2284
if ( (pDRIScreen == NULL) || (pDRIScreen->private == NULL) ) {
2288
psp = (__DRIscreenPrivate *) pDRIScreen->private;
2291
if (drmCreateContext(psp->fd, hHWContext)) {
2292
fprintf(stderr, ">>> drmCreateContext failed\n");
2295
*(void**)contextID = (void*) *hHWContext;
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)
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) {
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;
2326
/* the drawable index is by client id */
2327
*index = display->clientID;
2329
*stamp = pcp->driScreenPriv->pSAREA->drawableTable[display->clientID].stamp;
2330
drmUpdateDrawableInfo(psp->fd, pdp->hHWDrawable, DRM_DRAWABLE_CLIPRECTS, 1, cliprect);
2333
*width = drawable->w;
2334
*height = drawable->h;
2336
*pClipRects = cliprect;
2338
*backX = drawable->x;
2339
*backY = drawable->y;
2340
*numBackClipRects = 0;
2341
*pBackClipRects = 0;
2348
xf86DRI_DestroyContext(__DRInativeDisplay *dpy, int screen, __DRIid context_id )
2355
xf86DRI_CreateDrawable(__DRInativeDisplay *dpy, int screen, __DRIid drawable,
2356
drm_drawable_t *hHWDrawable )
2359
Display *display = (Display *)dpy;
2360
__DRIscreenPrivate *psp = display->driScreen.private;
2362
ret = drmCreateDrawable(psp->fd, hHWDrawable);
2364
fprintf(stderr, "drawable is %d %08X ret is %d\n", *hHWDrawable, drawable, -ret);
2372
xf86DRI_DestroyDrawable(__DRInativeDisplay *dpy, int screen, __DRIid drawable)
2379
* \brief Query function address.
2381
* The glXGetProcAddress() function will return the address of any available
2382
* OpenGL or Mini GLX function.
2384
* \param procName name of the function to be returned.
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.
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.
2395
* Returns the function address by looking up its name in a static (name,
2396
* address) pair list.
2398
void (*glXGetProcAddress(const GLubyte *procname))( void )
2400
struct name_address {
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 },
2428
const struct name_address *entry;
2429
for (entry = functions; entry->name; entry++) {
2430
if (strcmp(entry->name, (const char *) procname) == 0) {
2434
return _glapi_get_proc_address((const char *) procname);
2437
void (*glXGetProcAddressARB(const GLubyte *procName))( void ) __attribute__ ((alias ("glXGetProcAddress")));
2440
* \brief Query the Mini GLX version.
2442
* \param dpy the display handle. It is currently ignored, but should be the
2443
* value returned by XOpenDisplay().
2444
* \param major receives the major version number of Mini GLX.
2445
* \param minor receives the minor version number of Mini GLX.
2447
* \return \c True if the function succeeds, \c False if the function fails due
2448
* to invalid parameters.
2450
* \sa #MINI_GLX_VERSION_1_0.
2452
* Returns the hard-coded Mini GLX version.
2455
glXQueryVersion( Display *dpy, int *major, int *minor )
2465
* \brief Create a new pbuffer.
2468
glXCreatePbuffer( Display *dpy, GLXFBConfig config, const int *attribList )
2475
glXDestroyPbuffer( Display *dpy, GLXPbuffer pbuf )
2482
glXChooseFBConfig( Display *dpy, int screen, const int *attribList,
2485
GLXFBConfig *f = (GLXFBConfig *) malloc(sizeof(GLXFBConfig));
2486
f->visInfo = glXChooseVisual( dpy, screen, (int *) attribList );
2500
glXGetVisualFromFBConfig( Display *dpy, GLXFBConfig config )
2502
/* XVisualInfo and GLXFBConfig are the same structure */
2504
return config.visInfo;
2507
void *glXAllocateMemoryMESA(Display *dpy, int scrn,
2508
size_t size, float readFreq,
2509
float writeFreq, float priority)
2511
if (dpy->driScreen.private && dpy->driScreen.allocateMemory) {
2512
return (*dpy->driScreen.allocateMemory)( dpy, scrn, size,
2513
readFreq, writeFreq,
2520
void glXFreeMemoryMESA(Display *dpy, int scrn, void *pointer)
2522
if (dpy->driScreen.private && dpy->driScreen.freeMemory) {
2523
(*dpy->driScreen.freeMemory)( dpy, scrn, pointer );
2527
GLuint glXGetMemoryOffsetMESA( Display *dpy, int scrn,
2528
const void *pointer )
2530
if (dpy->driScreen.private && dpy->driScreen.memoryOffset) {
2531
return (*dpy->driScreen.memoryOffset)( dpy, scrn, pointer );
2539
* Get the unadjusted system time (UST). Currently, the UST is measured in
2540
* microseconds since Epoc. The actual resolution of the UST may vary from
2541
* system to system, and the units may vary from release to release.
2542
* Drivers should not call this function directly. They should instead use
2543
* \c glXGetProcAddress to obtain a pointer to the function.
2545
* \param ust Location to store the 64-bit UST
2546
* \returns Zero on success or a negative errno value on failure.
2549
* This function was copied directly from src/glx/x11/glxcmds.c.
2551
static int __glXGetUST( int64_t * ust )
2555
if ( ust == NULL ) {
2559
if ( gettimeofday( & tv, NULL ) == 0 ) {
2560
ust[0] = (tv.tv_sec * 1000000) + tv.tv_usec;
2571
* This needs to be implemented for miniGlx.
2573
static GLboolean __glXGetMscRate(__DRInativeDisplay * dpy, __DRIid drawable,
2574
int32_t * numerator, int32_t * denominator)