patch to import Jon Smirl's work from Bitkeeper
[mesa.git] / src / glx / mini / dri_util.c
1 /**
2 * \file dri_util.c
3 * \brief DRI utility functions.
4 *
5 * This module acts as glue between GLX and the actual hardware driver. A DRI
6 * driver doesn't really \e have to use any of this - it's optional. But, some
7 * useful stuff is done here that otherwise would have to be duplicated in most
8 * drivers.
9 *
10 * Basically, these utility functions take care of some of the dirty details of
11 * screen initialization, context creation, context binding, DRM setup, etc.
12 *
13 * These functions are compiled into each DRI driver so libGL.so knows nothing
14 * about them.
15 *
16 */
17
18 #include <assert.h>
19 #include <fcntl.h>
20 #include <stdarg.h>
21 #include <unistd.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <linux/fb.h>
26 #include <linux/vt.h>
27 #include <sys/ioctl.h>
28 #include <sys/mman.h>
29 #include <sys/shm.h>
30
31 #include "sarea.h"
32 #include "dri_util.h"
33
34 /**
35 * \brief Print message to \c stderr if the \c LIBGL_DEBUG environment variable
36 * is set.
37 *
38 * Is called from the drivers.
39 *
40 * \param f \e printf like format.
41 *
42 * \internal
43 * This function is a wrapper around vfprintf().
44 */
45 void
46 __driUtilMessage(const char *f, ...)
47 {
48 va_list args;
49
50 if (getenv("LIBGL_DEBUG")) {
51 fprintf(stderr, "libGL error: \n");
52 va_start(args, f);
53 vfprintf(stderr, f, args);
54 va_end(args);
55 fprintf(stderr, "\n");
56 }
57 }
58
59
60 /*****************************************************************/
61 /** \name Visual utility functions */
62 /*****************************************************************/
63 /*@{*/
64
65
66 /*@}*/
67
68
69 /*****************************************************************/
70 /** \name Context (un)binding functions */
71 /*****************************************************************/
72 /*@{*/
73
74
75 /**
76 * \brief Unbind context.
77 *
78 * \param drawable __DRIdrawable
79 * \param context __DRIcontext
80 * \param will_rebind not used.
81 *
82 * \return GL_TRUE on success, or GL_FALSE on failure.
83 *
84 * \internal
85 * This function calls __DriverAPIRec::UnbindContext, and then decrements
86 * __DRIdrawablePrivateRec::refcount which must be non-zero for a successful
87 * return.
88 *
89 * While casting the opaque private pointers associated with the parameters into their
90 * respective real types it also assures they are not null.
91 */
92 static GLboolean driUnbindContext(__DRIdrawable *drawable,
93 __DRIcontext *context)
94 {
95 __DRIdrawablePrivate *pdp = (__DRIdrawablePrivate *)drawable;
96 __DRIcontextPrivate *pcp = (__DRIcontextPrivate *)context;
97 __DRIscreenPrivate *psp;
98
99 if (pdp == NULL || pcp == NULL)
100 return GL_FALSE;
101
102 if (!(psp = (__DRIscreenPrivate *)pdp->driScreenPriv))
103 return GL_FALSE;
104
105 /* Let driver unbind drawable from context */
106 (*psp->DriverAPI.UnbindContext)(pcp);
107
108 if (pdp->refcount == 0)
109 return GL_FALSE;
110
111 --pdp->refcount;
112
113 return GL_TRUE;
114 }
115
116
117 /**
118 * \brief Unbind context.
119 *
120 * \param pDRIScreen __DRIscreen
121 * \param drawable __DRIdrawable
122 * \param context __DRIcontext
123 *
124 * \internal
125 * This function and increments __DRIdrawablePrivateRec::refcount and calls
126 * __DriverAPIRec::MakeCurrent to binds the drawable.
127 *
128 * While casting the opaque private pointers into their
129 * respective real types it also assures they are not null.
130 */
131 static GLboolean driBindContext(__DRIscreen *screen, __DRIdrawable *drawable,
132 __DRIcontext *context)
133 {
134 __DRIscreenPrivate *psp = (__DRIscreenPrivate *)screen;
135 __DRIdrawablePrivate *pdp = (__DRIdrawablePrivate *)drawable;
136 __DRIcontextPrivate *pcp = (__DRIcontextPrivate *)context;
137
138 if (psp == NULL)
139 return GL_FALSE;
140
141 if (pdp == NULL || pcp == NULL) {
142 (*psp->DriverAPI.MakeCurrent)(0, 0, 0);
143 return GL_TRUE;
144 }
145
146 /* Bind the drawable to the context */
147 pcp->driDrawablePriv = pdp;
148 pdp->driContextPriv = pcp;
149 pdp->refcount++;
150
151 /* Call device-specific MakeCurrent */
152 (*psp->DriverAPI.MakeCurrent)(pcp, pdp, pdp);
153
154 return GL_TRUE;
155 }
156
157 /*@}*/
158
159
160 /*****************************************************************/
161 /** \name Drawable handling functions */
162 /*****************************************************************/
163 /*@{*/
164
165
166 /**
167 * \brief Update private drawable information.
168 *
169 * \param pdp pointer to the private drawable information to update.
170 *
171 * \internal
172 * This function is a no-op. Should never be called but is referenced as an
173 * external symbol from client drivers.
174 */
175 void __driUtilUpdateDrawableInfo(__DRIdrawablePrivate *pdp)
176 {
177 __DRIscreenPrivate *psp = pdp->driScreenPriv;
178
179 pdp->numClipRects = psp->pSAREA->drawableTable[pdp->index].flags ? 1 : 0;
180 pdp->lastStamp = *(pdp->pStamp);
181 }
182
183
184 /**
185 * \brief Swap buffers.
186 *
187 * \param pDRIscreen __DRIscreen
188 * \param drawablePrivate opaque pointer to the per-drawable private info.
189 *
190 * \internal
191 * This function calls __DRIdrawablePrivate::swapBuffers.
192 *
193 * Is called directly from glXSwapBuffers().
194 */
195 static void driSwapBuffers(__DRIdrawable *drawable)
196 {
197 __DRIdrawablePrivate *pdp = (__DRIdrawablePrivate *)drawable;
198 if (pdp)
199 pdp->swapBuffers(pdp);
200 }
201
202
203 /**
204 * \brief Destroy per-drawable private information.
205 *
206 * \param pDRIscreen __DRIscreen
207 * \param drawablePrivate opaque pointer to the per-drawable private info.
208 *
209 * \internal
210 * This function calls __DriverAPIRec::DestroyBuffer on \p drawablePrivate,
211 * frees the clip rects if any, and finally frees \p drawablePrivate itself.
212 */
213 static void driDestroyDrawable(__DRIdrawable *drawable)
214 {
215 __DRIdrawablePrivate *pdp = (__DRIdrawablePrivate *)drawable;
216 __DRIscreenPrivate *psp;
217
218 if (pdp) {
219 psp = pdp->driScreenPriv;
220 (*psp->DriverAPI.DestroyBuffer)(pdp);
221 if (pdp->pClipRects)
222 free(pdp->pClipRects);
223 free(pdp);
224 }
225 }
226
227
228 /**
229 * \brief Create the per-drawable private driver information.
230 *
231 * \param dpy the display handle.
232 * \param scrn the screen number.
233 * \param draw the GLX drawable info.
234 * \param vid visual ID.
235 * \param pdraw will receive the drawable dependent methods.
236 *
237 *
238 * \returns a opaque pointer to the per-drawable private info on success, or NULL
239 * on failure.
240 *
241 * \internal
242 * This function allocates and fills a __DRIdrawablePrivateRec structure,
243 * initializing the invariant window dimensions and clip rects. It obtains the
244 * visual config, converts it into a __GLcontextModesRec and passes it to
245 * __DriverAPIRec::CreateBuffer to create a buffer.
246 */
247 static void *driCreateDrawable(__DRIscreen *screen,
248 int width, int height, int index,
249 const __GLcontextModes *glVisual)
250 {
251 __DRIscreenPrivate *psp = (__DRIscreenPrivate *)screen;
252 __DRIdrawablePrivate *pdp;
253
254 if (!psp)
255 return NULL;
256
257 if (!(pdp = (__DRIdrawablePrivate *)malloc(sizeof(__DRIdrawablePrivate))))
258 return NULL;
259
260 pdp->index = index;
261 pdp->refcount = 0;
262 pdp->lastStamp = -1;
263 pdp->numBackClipRects = 0;
264 pdp->pBackClipRects = NULL;
265
266 /* Initialize with the invariant window dimensions and clip rects here.
267 */
268 pdp->x = 0;
269 pdp->y = 0;
270 pdp->w = width;
271 pdp->h = height;
272 pdp->numClipRects = 0;
273 pdp->pClipRects = (XF86DRIClipRectPtr) malloc(sizeof(XF86DRIClipRectRec));
274 (pdp->pClipRects)[0].x1 = 0;
275 (pdp->pClipRects)[0].y1 = 0;
276 (pdp->pClipRects)[0].x2 = width;
277 (pdp->pClipRects)[0].y2 = height;
278
279 pdp->driScreenPriv = psp;
280 pdp->driContextPriv = 0;
281
282 pdp->frontBuffer = psp->pFB;
283 pdp->currentBuffer = pdp->frontBuffer;
284 pdp->currentPitch = psp->fbStride;
285 pdp->backBuffer = psp->pFB + psp->fbStride * psp->fbHeight;
286
287 if (!(*psp->DriverAPI.CreateBuffer)(psp, pdp, glVisual, GL_FALSE)) {
288 free(pdp);
289 return NULL;
290 }
291
292 pdp->entry.destroyDrawable = driDestroyDrawable;
293 pdp->entry.swapBuffers = driSwapBuffers; /* called by glXSwapBuffers() */
294 pdp->swapBuffers = psp->DriverAPI.SwapBuffers;
295
296 pdp->pStamp = &(psp->pSAREA->drawableTable[pdp->index].stamp);
297 return (void *) pdp;
298 }
299
300 /*@}*/
301
302
303 /*****************************************************************/
304 /** \name Context handling functions */
305 /*****************************************************************/
306 /*@{*/
307
308
309 /**
310 * \brief Destroy the per-context private information.
311 *
312 * \param contextPrivate opaque pointer to the per-drawable private info.
313 *
314 * \internal
315 * This function calls __DriverAPIRec::DestroyContext on \p contextPrivate, calls
316 * drmDestroyContext(), and finally frees \p contextPrivate.
317 */
318 static void driDestroyContext(__DRIcontext *context)
319 {
320 __DRIcontextPrivate *pcp = (__DRIcontextPrivate *)context;
321 __DRIscreenPrivate *psp = NULL;
322
323 if (pcp) {
324 (*pcp->driScreenPriv->DriverAPI.DestroyContext)(pcp);
325 psp = pcp->driDrawablePriv->driScreenPriv;
326 if (psp->fd) {
327 printf(">>> drmDestroyContext(0x%x)\n", (int) pcp->hHWContext);
328 drmDestroyContext(psp->fd, pcp->hHWContext);
329 }
330 free(pcp);
331 }
332 }
333
334 /**
335 * \brief Create the per-drawable private driver information.
336 *
337 * \param dpy the display handle.
338 * \param vis the visual information.
339 * \param sharedPrivate the shared context dependent methods or NULL if non-existent.
340 * \param pctx will receive the context dependent methods.
341 *
342 * \returns a opaque pointer to the per-context private information on success, or NULL
343 * on failure.
344 *
345 * \internal
346 * This function allocates and fills a __DRIcontextPrivateRec structure. It
347 * gets the visual, converts it into a __GLcontextModesRec and passes it
348 * to __DriverAPIRec::CreateContext to create the context.
349 */
350 static void *driCreateContext(__DRIscreen *screen,
351 const __GLcontextModes *glVisual,
352 void *sharedPrivate)
353 {
354 __DRIscreenPrivate *psp = (__DRIscreenPrivate *)screen;
355 __DRIcontextPrivate *pcp;
356 __DRIcontextPrivate *pshare = (__DRIcontextPrivate *) sharedPrivate;
357 void *shareCtx;
358
359 if (!psp)
360 return NULL;
361
362 if (!(pcp = (__DRIcontextPrivate *)malloc(sizeof(__DRIcontextPrivate))))
363 return NULL;
364
365 pcp->driScreenPriv = psp;
366 pcp->driDrawablePriv = NULL;
367
368 if (psp->fd) {
369 if (drmCreateContext(psp->fd, &pcp->hHWContext)) {
370 fprintf(stderr, ">>> drmCreateContext failed\n");
371 free(pcp);
372 return NULL;
373 }
374 }
375
376 shareCtx = pshare ? pshare->driverPrivate : NULL;
377
378 if (!(*psp->DriverAPI.CreateContext)(glVisual, pcp, shareCtx)) {
379 if (psp->fd)
380 (void) drmDestroyContext(psp->fd, pcp->hHWContext);
381 free(pcp);
382 return NULL;
383 }
384
385 pcp->entry.destroyContext = driDestroyContext;
386 pcp->entry.bindContext = driBindContext;
387 pcp->entry.unbindContext = driUnbindContext;
388
389 return pcp;
390 }
391
392 /*@}*/
393
394
395 /*****************************************************************/
396 /** \name Screen handling functions */
397 /*****************************************************************/
398 /*@{*/
399
400
401 /**
402 * \brief Destroy the per-screen private information.
403 *
404 * \param pDRIscreen __DRIscreen
405 *
406 * \internal
407 * This function calls __DriverAPIRec::DestroyScreen on \p screenPrivate, calls
408 * drmClose(), and finally frees \p screenPrivate.
409 */
410 static void driDestroyScreen(__DRIscreen *screen)
411 {
412 __DRIscreenPrivate *psp = (__DRIscreenPrivate *)screen;
413 if (psp) {
414 if (psp->DriverAPI.DestroyScreen)
415 (*psp->DriverAPI.DestroyScreen)(psp);
416
417 if (psp->fd)
418 (void)drmClose(psp->fd);
419
420 free(psp->pDevPriv);
421 free(psp);
422 }
423 }
424
425
426 /**
427 * \brief Create the per-screen private information.
428 *
429 * \param dpy the display handle.
430 * \param scrn the screen number.
431 * \param psc will receive the screen dependent methods.
432 * \param numConfigs number of visuals.
433 * \param config visuals.
434 * \param driverAPI driver callbacks structure.
435 *
436 * \return a pointer to the per-screen private information.
437 *
438 * \internal
439 * This function allocates and fills a __DRIscreenPrivateRec structure. It
440 * opens the DRM device verifying that the exported version matches the
441 * expected. It copies the driver callback functions and calls
442 * __DriverAPIRec::InitDriver.
443 *
444 * If a client maps the framebuffer and SAREA regions.
445 */
446 __DRIscreenPrivate *
447 __driUtilCreateScreen(struct DRIDriverRec *driver,
448 struct DRIDriverContextRec *driverContext,
449 const struct __DriverAPIRec *driverAPI)
450 {
451 __DRIscreenPrivate *psp;
452
453 if(!(psp = (__DRIscreenPrivate *)malloc(sizeof(__DRIscreenPrivate))))
454 return NULL;
455
456 psp->fd = drmOpen(NULL, driverContext->pciBusID);
457 if (psp->fd < 0) {
458 fprintf(stderr, "libGL error: failed to open DRM: %s\n",
459 strerror(-psp->fd));
460 free(psp);
461 return NULL;
462 }
463
464 {
465 drmVersionPtr version = drmGetVersion(psp->fd);
466 if (version) {
467 psp->drmMajor = version->version_major;
468 psp->drmMinor = version->version_minor;
469 psp->drmPatch = version->version_patchlevel;
470 drmFreeVersion(version);
471 }
472 else {
473 fprintf(stderr, "libGL error: failed to get drm version: %s\n",
474 strerror(-psp->fd));
475 free(psp);
476 return NULL;
477 }
478 }
479
480 /*
481 * Fake various version numbers.
482 */
483 psp->ddxMajor = 4;
484 psp->ddxMinor = 0;
485 psp->ddxPatch = 1;
486 psp->driMajor = 4;
487 psp->driMinor = 1;
488 psp->driPatch = 0;
489
490 /* install driver's callback functions */
491 psp->DriverAPI = *driverAPI;
492
493 /*
494 * Get device-specific info. pDevPriv will point to a struct
495 * (such as DRIRADEONRec in xfree86/driver/ati/radeon_dri.h)
496 * that has information about the screen size, depth, pitch,
497 * ancilliary buffers, DRM mmap handles, etc.
498 */
499 psp->fbOrigin = driverContext->shared.fbOrigin;
500 psp->fbSize = driverContext->shared.fbSize;
501 psp->fbStride = driverContext->shared.fbStride;
502 psp->devPrivSize = driverContext->driverClientMsgSize;
503 psp->pDevPriv = driverContext->driverClientMsg;
504 psp->fbWidth = driverContext->shared.virtualWidth;
505 psp->fbHeight = driverContext->shared.virtualHeight;
506 psp->fbBPP = driverContext->bpp;
507
508 if ((driverContext->FBAddress != NULL) && (driverContext->pSAREA != NULL)) {
509 /* Already mapped in server */
510 psp->pFB = driverContext->FBAddress;
511 psp->pSAREA = driverContext->pSAREA;
512 } else {
513 /*
514 * Map the framebuffer region.
515 */
516 if (drmMap(psp->fd, driverContext->shared.hFrameBuffer, psp->fbSize,
517 (drmAddressPtr)&psp->pFB)) {
518 fprintf(stderr, "libGL error: drmMap of framebuffer failed\n");
519 (void)drmClose(psp->fd);
520 free(psp);
521 return NULL;
522 }
523
524 /*
525 * Map the SAREA region. Further mmap regions may be setup in
526 * each DRI driver's "createScreen" function.
527 */
528 if (drmMap(psp->fd, driverContext->shared.hSAREA,
529 driverContext->shared.SAREASize,
530 (drmAddressPtr)&psp->pSAREA)) {
531 fprintf(stderr, "libGL error: drmMap of sarea failed\n");
532 (void)drmUnmap((drmAddress)psp->pFB, psp->fbSize);
533 (void)drmClose(psp->fd);
534 free(psp);
535 return NULL;
536 }
537
538 #ifdef _EMBEDDED
539 mprotect(psp->pSAREA, driverContext->shared.SAREASize, PROT_READ);
540 #endif
541 }
542
543
544 /* Initialize the screen specific GLX driver */
545 if (psp->DriverAPI.InitDriver) {
546 if (!(*psp->DriverAPI.InitDriver)(psp)) {
547 fprintf(stderr, "libGL error: InitDriver failed\n");
548 free(psp->pDevPriv);
549 (void)drmClose(psp->fd);
550 free(psp);
551 return NULL;
552 }
553 }
554
555 psp->entry.destroyScreen = driDestroyScreen;
556 psp->entry.createContext = driCreateContext;
557 psp->entry.createDrawable = driCreateDrawable;
558
559 return psp;
560 }
561
562
563
564 /**
565 * \brief Create the per-screen private information.
566 *
567 * Version for drivers without a DRM module.
568 *
569 * \param dpy the display handle.
570 * \param scrn the screen number.
571 * \param numConfigs number of visuals.
572 * \param config visuals.
573 * \param driverAPI driver callbacks structure.
574 *
575 * \internal
576 * Same as __driUtilCreateScreen() but without opening the DRM device.
577 */
578 __DRIscreenPrivate *
579 __driUtilCreateScreenNoDRM(struct DRIDriverRec *driver,
580 struct DRIDriverContextRec *driverContext,
581 const struct __DriverAPIRec *driverAPI)
582 {
583 __DRIscreenPrivate *psp;
584
585 psp = (__DRIscreenPrivate *)calloc(1, sizeof(__DRIscreenPrivate));
586 if (!psp)
587 return NULL;
588
589 psp->ddxMajor = 4;
590 psp->ddxMinor = 0;
591 psp->ddxPatch = 1;
592 psp->driMajor = 4;
593 psp->driMinor = 1;
594 psp->driPatch = 0;
595 psp->fd = 0;
596
597 psp->fbOrigin = driverContext->shared.fbOrigin;
598 psp->fbSize = driverContext->shared.fbSize;
599 psp->fbStride = driverContext->shared.fbStride;
600 psp->devPrivSize = driverContext->driverClientMsgSize;
601 psp->pDevPriv = driverContext->driverClientMsg;
602 psp->fbWidth = driverContext->shared.virtualWidth;
603 psp->fbHeight = driverContext->shared.virtualHeight;
604 psp->fbBPP = driverContext->bpp;
605
606 psp->pFB = driverContext->FBAddress;
607
608 /* install driver's callback functions */
609 psp->DriverAPI = *driverAPI;
610
611 if ((driverContext->FBAddress != NULL) && (driverContext->pSAREA != NULL)) {
612 /* Already mapped in server */
613 psp->pFB = driverContext->FBAddress;
614 psp->pSAREA = driverContext->pSAREA;
615 } else {
616 psp->fd = open("/dev/mem", O_RDWR, 0);
617 /*
618 * Map the framebuffer region.
619 */
620 if (drmMap(psp->fd, driverContext->shared.hFrameBuffer, psp->fbSize,
621 (drmAddressPtr)&psp->pFB)) {
622 fprintf(stderr, "libGL error: drmMap of framebuffer failed\n");
623 (void)drmClose(psp->fd);
624 free(psp);
625 return NULL;
626 }
627 driverContext->FBAddress = psp->pFB;
628
629 /*
630 * Map the SAREA region. Non-DRM drivers use a shmem SAREA
631 */
632 int id;
633 id = shmget(driverContext->shared.hSAREA, driverContext->shared.SAREASize, 0);
634 driverContext->pSAREA = shmat(id, NULL, 0);
635 if (!driverContext->pSAREA) {
636 fprintf(stderr, "libGL error: shmget of sarea failed\n");
637 (void)drmUnmap((drmAddress)psp->pFB, psp->fbSize);
638 (void)drmClose(psp->fd);
639 free(psp);
640 return NULL;
641 }
642
643 close(psp->fd);
644 psp->fd = 0;
645 }
646
647 /* Initialize the screen specific GLX driver */
648 if (psp->DriverAPI.InitDriver) {
649 if (!(*psp->DriverAPI.InitDriver)(psp)) {
650 fprintf(stderr, "libGL error: InitDriver failed\n");
651 free(psp->pDevPriv);
652 free(psp);
653 return NULL;
654 }
655 }
656
657 psp->entry.destroyScreen = driDestroyScreen;
658 psp->entry.createContext = driCreateContext;
659 psp->entry.createDrawable = driCreateDrawable;
660
661 return psp;
662 }
663
664 /**
665 * Calculate amount of swap interval used between GLX buffer swaps.
666 *
667 * The usage value, on the range [0,max], is the fraction of total swap
668 * interval time used between GLX buffer swaps is calculated.
669 *
670 * \f$p = t_d / (i * t_r)\f$
671 *
672 * Where \f$t_d\$f is the time since the last GLX buffer swap, \f$i\f$ is the
673 * swap interval (as set by \c glXSwapIntervalSGI), and \f$t_r\f$ time
674 * required for a single vertical refresh period (as returned by \c
675 * glXGetMscRateOML).
676 *
677 * See the documentation for the GLX_MESA_swap_frame_usage extension for more
678 * details.
679 *
680 * \param dPriv Pointer to the private drawable structure.
681 * \return If less than a single swap interval time period was required
682 * between GLX buffer swaps, a number greater than 0 and less than
683 * 1.0 is returned. If exactly one swap interval time period is
684 * required, 1.0 is returned, and if more than one is required then
685 * a number greater than 1.0 will be returned.
686 *
687 * \sa glXSwapIntervalSGI(), glXGetMscRateOML().
688 */
689 float
690 driCalculateSwapUsage( __DRIdrawablePrivate *dPriv, int64_t last_swap_ust,
691 int64_t current_ust )
692 {
693 return 0.0f;
694 }
695
696 /**
697 * Compare the current GLX API version with a driver supplied required version.
698 *
699 * The minimum required version is compared with the API version exported by
700 * the \c __glXGetInternalVersion function (in libGL.so).
701 *
702 * \param required_version Minimum required internal GLX API version.
703 * \return A tri-value return, as from strcmp is returned. A value less
704 * than, equal to, or greater than zero will be returned if the
705 * internal GLX API version is less than, equal to, or greater
706 * than \c required_version.
707 *
708 * \sa __glXGetInternalVersion().
709 */
710 int driCompareGLXAPIVersion( GLuint required_version )
711 {
712 return 0;
713 }
714
715 /*@}*/