Merge commit 'origin/gallium-0.1' into gallium-0.2
[mesa.git] / src / mesa / drivers / dri / common / dri_util.c
1 /* $XFree86: xc/lib/GL/dri/dri_util.c,v 1.7 2003/04/28 17:01:25 dawes Exp $ */
2 /**
3 * \file dri_util.c
4 * DRI utility functions.
5 *
6 * This module acts as glue between GLX and the actual hardware driver. A DRI
7 * driver doesn't really \e have to use any of this - it's optional. But, some
8 * useful stuff is done here that otherwise would have to be duplicated in most
9 * drivers.
10 *
11 * Basically, these utility functions take care of some of the dirty details of
12 * screen initialization, context creation, context binding, DRM setup, etc.
13 *
14 * These functions are compiled into each DRI driver so libGL.so knows nothing
15 * about them.
16 */
17
18
19 #include <assert.h>
20 #include <stdarg.h>
21 #include <unistd.h>
22 #include <sys/mman.h>
23 #include <stdio.h>
24
25 #ifndef MAP_FAILED
26 #define MAP_FAILED ((void *)-1)
27 #endif
28
29 #include "main/imports.h"
30 #define None 0
31
32 #include "dri_util.h"
33 #include "drm_sarea.h"
34 #include "utils.h"
35
36 #ifndef GLX_OML_sync_control
37 typedef GLboolean ( * PFNGLXGETMSCRATEOMLPROC) (__DRIdrawable *drawable, int32_t *numerator, int32_t *denominator);
38 #endif
39
40 /**
41 * This is just a token extension used to signal that the driver
42 * supports setting a read drawable.
43 */
44 const __DRIextension driReadDrawableExtension = {
45 __DRI_READ_DRAWABLE, __DRI_READ_DRAWABLE_VERSION
46 };
47
48 /**
49 * Print message to \c stderr if the \c LIBGL_DEBUG environment variable
50 * is set.
51 *
52 * Is called from the drivers.
53 *
54 * \param f \c printf like format string.
55 */
56 void
57 __driUtilMessage(const char *f, ...)
58 {
59 va_list args;
60
61 if (getenv("LIBGL_DEBUG")) {
62 fprintf(stderr, "libGL error: \n");
63 va_start(args, f);
64 vfprintf(stderr, f, args);
65 va_end(args);
66 fprintf(stderr, "\n");
67 }
68 }
69
70 GLint
71 driIntersectArea( drm_clip_rect_t rect1, drm_clip_rect_t rect2 )
72 {
73 if (rect2.x1 > rect1.x1) rect1.x1 = rect2.x1;
74 if (rect2.x2 < rect1.x2) rect1.x2 = rect2.x2;
75 if (rect2.y1 > rect1.y1) rect1.y1 = rect2.y1;
76 if (rect2.y2 < rect1.y2) rect1.y2 = rect2.y2;
77
78 if (rect1.x1 > rect1.x2 || rect1.y1 > rect1.y2) return 0;
79
80 return (rect1.x2 - rect1.x1) * (rect1.y2 - rect1.y1);
81 }
82
83 /*****************************************************************/
84 /** \name Context (un)binding functions */
85 /*****************************************************************/
86 /*@{*/
87
88 /**
89 * Unbind context.
90 *
91 * \param scrn the screen.
92 * \param gc context.
93 *
94 * \return \c GL_TRUE on success, or \c GL_FALSE on failure.
95 *
96 * \internal
97 * This function calls __DriverAPIRec::UnbindContext, and then decrements
98 * __DRIdrawablePrivateRec::refcount which must be non-zero for a successful
99 * return.
100 *
101 * While casting the opaque private pointers associated with the parameters
102 * into their respective real types it also assures they are not \c NULL.
103 */
104 static int driUnbindContext(__DRIcontext *pcp)
105 {
106 __DRIscreen *psp;
107 __DRIdrawable *pdp;
108 __DRIdrawable *prp;
109
110 /*
111 ** Assume error checking is done properly in glXMakeCurrent before
112 ** calling driUnbindContext.
113 */
114
115 if (pcp == NULL)
116 return GL_FALSE;
117
118 psp = pcp->driScreenPriv;
119 pdp = pcp->driDrawablePriv;
120 prp = pcp->driReadablePriv;
121
122 /* Let driver unbind drawable from context */
123 (*psp->DriverAPI.UnbindContext)(pcp);
124
125 if (pdp->refcount == 0) {
126 /* ERROR!!! */
127 return GL_FALSE;
128 }
129
130 pdp->refcount--;
131
132 if (prp != pdp) {
133 if (prp->refcount == 0) {
134 /* ERROR!!! */
135 return GL_FALSE;
136 }
137
138 prp->refcount--;
139 }
140
141
142 /* XXX this is disabled so that if we call SwapBuffers on an unbound
143 * window we can determine the last context bound to the window and
144 * use that context's lock. (BrianP, 2-Dec-2000)
145 */
146 #if 0
147 /* Unbind the drawable */
148 pcp->driDrawablePriv = NULL;
149 pdp->driContextPriv = &psp->dummyContextPriv;
150 #endif
151
152 return GL_TRUE;
153 }
154
155 /**
156 * This function takes both a read buffer and a draw buffer. This is needed
157 * for \c glXMakeCurrentReadSGI or GLX 1.3's \c glXMakeContextCurrent
158 * function.
159 */
160 static int driBindContext(__DRIcontext *pcp,
161 __DRIdrawable *pdp,
162 __DRIdrawable *prp)
163 {
164 __DRIscreenPrivate *psp = pcp->driScreenPriv;
165
166 /*
167 ** Assume error checking is done properly in glXMakeCurrent before
168 ** calling driBindContext.
169 */
170
171 if (pcp == NULL || pdp == None || prp == None)
172 return GL_FALSE;
173
174 /* Bind the drawable to the context */
175 pcp->driDrawablePriv = pdp;
176 pcp->driReadablePriv = prp;
177 pdp->driContextPriv = pcp;
178 pdp->refcount++;
179 if ( pdp != prp ) {
180 prp->refcount++;
181 }
182
183 /*
184 ** Now that we have a context associated with this drawable, we can
185 ** initialize the drawable information if has not been done before.
186 */
187
188 if (!psp->dri2.enabled) {
189 if (!pdp->pStamp || *pdp->pStamp != pdp->lastStamp) {
190 DRM_SPINLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID);
191 __driUtilUpdateDrawableInfo(pdp);
192 DRM_SPINUNLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID);
193 }
194
195 if ((pdp != prp) && (!prp->pStamp || *prp->pStamp != prp->lastStamp)) {
196 DRM_SPINLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID);
197 __driUtilUpdateDrawableInfo(prp);
198 DRM_SPINUNLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID);
199 }
200 }
201
202 /* Call device-specific MakeCurrent */
203 (*psp->DriverAPI.MakeCurrent)(pcp, pdp, prp);
204
205 return GL_TRUE;
206 }
207
208 /*@}*/
209
210
211 /*****************************************************************/
212 /** \name Drawable handling functions */
213 /*****************************************************************/
214 /*@{*/
215
216 /**
217 * Update private drawable information.
218 *
219 * \param pdp pointer to the private drawable information to update.
220 *
221 * This function basically updates the __DRIdrawablePrivate struct's
222 * cliprect information by calling \c __DRIinterfaceMethods::getDrawableInfo.
223 * This is usually called by the DRI_VALIDATE_DRAWABLE_INFO macro which
224 * compares the __DRIdrwablePrivate pStamp and lastStamp values. If
225 * the values are different that means we have to update the clipping
226 * info.
227 */
228 void
229 __driUtilUpdateDrawableInfo(__DRIdrawablePrivate *pdp)
230 {
231 __DRIscreenPrivate *psp = pdp->driScreenPriv;
232 __DRIcontextPrivate *pcp = pdp->driContextPriv;
233
234 if (!pcp
235 || ((pdp != pcp->driDrawablePriv) && (pdp != pcp->driReadablePriv))) {
236 /* ERROR!!!
237 * ...but we must ignore it. There can be many contexts bound to a
238 * drawable.
239 */
240 }
241
242 if (pdp->pClipRects) {
243 _mesa_free(pdp->pClipRects);
244 pdp->pClipRects = NULL;
245 }
246
247 if (pdp->pBackClipRects) {
248 _mesa_free(pdp->pBackClipRects);
249 pdp->pBackClipRects = NULL;
250 }
251
252 DRM_SPINUNLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID);
253
254 if (! (*psp->getDrawableInfo->getDrawableInfo)(pdp,
255 &pdp->index, &pdp->lastStamp,
256 &pdp->x, &pdp->y, &pdp->w, &pdp->h,
257 &pdp->numClipRects, &pdp->pClipRects,
258 &pdp->backX,
259 &pdp->backY,
260 &pdp->numBackClipRects,
261 &pdp->pBackClipRects,
262 pdp->loaderPrivate)) {
263 /* Error -- eg the window may have been destroyed. Keep going
264 * with no cliprects.
265 */
266 pdp->pStamp = &pdp->lastStamp; /* prevent endless loop */
267 pdp->numClipRects = 0;
268 pdp->pClipRects = NULL;
269 pdp->numBackClipRects = 0;
270 pdp->pBackClipRects = NULL;
271 }
272 else
273 pdp->pStamp = &(psp->pSAREA->drawableTable[pdp->index].stamp);
274
275 DRM_SPINLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID);
276 }
277
278 /*@}*/
279
280 /*****************************************************************/
281 /** \name GLX callbacks */
282 /*****************************************************************/
283 /*@{*/
284
285 static void driReportDamage(__DRIdrawable *pdp,
286 struct drm_clip_rect *pClipRects, int numClipRects)
287 {
288 __DRIscreen *psp = pdp->driScreenPriv;
289
290 /* Check that we actually have the new damage report method */
291 if (psp->damage) {
292 /* Report the damage. Currently, all our drivers draw
293 * directly to the front buffer, so we report the damage there
294 * rather than to the backing storein (if any).
295 */
296 (*psp->damage->reportDamage)(pdp,
297 pdp->x, pdp->y,
298 pClipRects, numClipRects,
299 GL_TRUE, pdp->loaderPrivate);
300 }
301 }
302
303
304 /**
305 * Swap buffers.
306 *
307 * \param drawablePrivate opaque pointer to the per-drawable private info.
308 *
309 * \internal
310 * This function calls __DRIdrawablePrivate::swapBuffers.
311 *
312 * Is called directly from glXSwapBuffers().
313 */
314 static void driSwapBuffers(__DRIdrawable *dPriv)
315 {
316 __DRIscreen *psp = dPriv->driScreenPriv;
317
318 psp->DriverAPI.SwapBuffers(dPriv);
319
320 driReportDamage(dPriv, dPriv->pClipRects, dPriv->numClipRects);
321 }
322
323 static int driDrawableGetMSC( __DRIscreen *sPriv, __DRIdrawable *dPriv,
324 int64_t *msc )
325 {
326 return sPriv->DriverAPI.GetDrawableMSC(sPriv, dPriv, msc);
327 }
328
329
330 static int driWaitForMSC(__DRIdrawable *dPriv, int64_t target_msc,
331 int64_t divisor, int64_t remainder,
332 int64_t * msc, int64_t * sbc)
333 {
334 __DRIswapInfo sInfo;
335 int status;
336
337 status = dPriv->driScreenPriv->DriverAPI.WaitForMSC( dPriv, target_msc,
338 divisor, remainder,
339 msc );
340
341 /* GetSwapInfo() may not be provided by the driver if GLX_SGI_video_sync
342 * is supported but GLX_OML_sync_control is not. Therefore, don't return
343 * an error value if GetSwapInfo() is not implemented.
344 */
345 if ( status == 0
346 && dPriv->driScreenPriv->DriverAPI.GetSwapInfo ) {
347 status = dPriv->driScreenPriv->DriverAPI.GetSwapInfo( dPriv, & sInfo );
348 *sbc = sInfo.swap_count;
349 }
350
351 return status;
352 }
353
354
355 const __DRImediaStreamCounterExtension driMediaStreamCounterExtension = {
356 { __DRI_MEDIA_STREAM_COUNTER, __DRI_MEDIA_STREAM_COUNTER_VERSION },
357 driWaitForMSC,
358 driDrawableGetMSC,
359 };
360
361
362 static void driCopySubBuffer(__DRIdrawable *dPriv,
363 int x, int y, int w, int h)
364 {
365 drm_clip_rect_t rect;
366
367 rect.x1 = x;
368 rect.y1 = dPriv->h - y - h;
369 rect.x2 = x + w;
370 rect.y2 = rect.y1 + h;
371 driReportDamage(dPriv, &rect, 1);
372
373 dPriv->driScreenPriv->DriverAPI.CopySubBuffer(dPriv, x, y, w, h);
374 }
375
376 const __DRIcopySubBufferExtension driCopySubBufferExtension = {
377 { __DRI_COPY_SUB_BUFFER, __DRI_COPY_SUB_BUFFER_VERSION },
378 driCopySubBuffer
379 };
380
381 static void driSetSwapInterval(__DRIdrawable *dPriv, unsigned int interval)
382 {
383 dPriv->swap_interval = interval;
384 }
385
386 static unsigned int driGetSwapInterval(__DRIdrawable *dPriv)
387 {
388 return dPriv->swap_interval;
389 }
390
391 const __DRIswapControlExtension driSwapControlExtension = {
392 { __DRI_SWAP_CONTROL, __DRI_SWAP_CONTROL_VERSION },
393 driSetSwapInterval,
394 driGetSwapInterval
395 };
396
397
398 /**
399 * This is called via __DRIscreenRec's createNewDrawable pointer.
400 */
401 static __DRIdrawable *
402 driCreateNewDrawable(__DRIscreen *psp, const __DRIconfig *config,
403 drm_drawable_t hwDrawable, int renderType,
404 const int *attrs, void *data)
405 {
406 __DRIdrawable *pdp;
407
408 /* Since pbuffers are not yet supported, no drawable attributes are
409 * supported either.
410 */
411 (void) attrs;
412
413 pdp = _mesa_malloc(sizeof *pdp);
414 if (!pdp) {
415 return NULL;
416 }
417
418 pdp->loaderPrivate = data;
419 pdp->hHWDrawable = hwDrawable;
420 pdp->refcount = 0;
421 pdp->pStamp = NULL;
422 pdp->lastStamp = 0;
423 pdp->index = 0;
424 pdp->x = 0;
425 pdp->y = 0;
426 pdp->w = 0;
427 pdp->h = 0;
428 pdp->numClipRects = 0;
429 pdp->numBackClipRects = 0;
430 pdp->pClipRects = NULL;
431 pdp->pBackClipRects = NULL;
432 pdp->vblSeq = 0;
433 pdp->vblFlags = 0;
434
435 pdp->driScreenPriv = psp;
436 pdp->driContextPriv = &psp->dummyContextPriv;
437
438 if (!(*psp->DriverAPI.CreateBuffer)(psp, pdp, &config->modes,
439 renderType == GLX_PIXMAP_BIT)) {
440 _mesa_free(pdp);
441 return NULL;
442 }
443
444 pdp->msc_base = 0;
445
446 /* This special default value is replaced with the configured
447 * default value when the drawable is first bound to a direct
448 * rendering context.
449 */
450 pdp->swap_interval = (unsigned)-1;
451
452 return pdp;
453 }
454
455
456 static __DRIdrawable *
457 dri2CreateNewDrawable(__DRIscreen *screen,
458 const __DRIconfig *config,
459 void *loaderPrivate)
460 {
461 __DRIdrawable *pdraw;
462
463 pdraw = driCreateNewDrawable(screen, config, 0, 0, NULL, loaderPrivate);
464 if (!pdraw)
465 return NULL;
466
467 pdraw->pClipRects = _mesa_malloc(sizeof *pdraw->pBackClipRects);
468 pdraw->pBackClipRects = _mesa_malloc(sizeof *pdraw->pBackClipRects);
469
470 return pdraw;
471 }
472
473
474 static void
475 driDestroyDrawable(__DRIdrawable *pdp)
476 {
477 __DRIscreenPrivate *psp;
478
479 if (pdp) {
480 psp = pdp->driScreenPriv;
481 (*psp->DriverAPI.DestroyBuffer)(pdp);
482 if (pdp->pClipRects) {
483 _mesa_free(pdp->pClipRects);
484 pdp->pClipRects = NULL;
485 }
486 if (pdp->pBackClipRects) {
487 _mesa_free(pdp->pBackClipRects);
488 pdp->pBackClipRects = NULL;
489 }
490 _mesa_free(pdp);
491 }
492 }
493
494 /*@}*/
495
496
497 /*****************************************************************/
498 /** \name Context handling functions */
499 /*****************************************************************/
500 /*@{*/
501
502 /**
503 * Destroy the per-context private information.
504 *
505 * \internal
506 * This function calls __DriverAPIRec::DestroyContext on \p contextPrivate, calls
507 * drmDestroyContext(), and finally frees \p contextPrivate.
508 */
509 static void
510 driDestroyContext(__DRIcontext *pcp)
511 {
512 if (pcp) {
513 (*pcp->driScreenPriv->DriverAPI.DestroyContext)(pcp);
514 _mesa_free(pcp);
515 }
516 }
517
518
519 /**
520 * Create the per-drawable private driver information.
521 *
522 * \param render_type Type of rendering target. \c GLX_RGBA is the only
523 * type likely to ever be supported for direct-rendering.
524 * \param shared Context with which to share textures, etc. or NULL
525 *
526 * \returns An opaque pointer to the per-context private information on
527 * success, or \c NULL on failure.
528 *
529 * \internal
530 * This function allocates and fills a __DRIcontextPrivateRec structure. It
531 * performs some device independent initialization and passes all the
532 * relevent information to __DriverAPIRec::CreateContext to create the
533 * context.
534 *
535 */
536 static __DRIcontext *
537 driCreateNewContext(__DRIscreen *psp, const __DRIconfig *config,
538 int render_type, __DRIcontext *shared,
539 drm_context_t hwContext, void *data)
540 {
541 __DRIcontext *pcp;
542 void * const shareCtx = (shared != NULL) ? shared->driverPrivate : NULL;
543
544 pcp = _mesa_malloc(sizeof *pcp);
545 if (!pcp)
546 return NULL;
547
548 pcp->driScreenPriv = psp;
549 pcp->driDrawablePriv = NULL;
550
551 /* When the first context is created for a screen, initialize a "dummy"
552 * context.
553 */
554
555 if (!psp->dri2.enabled && !psp->dummyContextPriv.driScreenPriv) {
556 psp->dummyContextPriv.hHWContext = psp->pSAREA->dummy_context;
557 psp->dummyContextPriv.driScreenPriv = psp;
558 psp->dummyContextPriv.driDrawablePriv = NULL;
559 psp->dummyContextPriv.driverPrivate = NULL;
560 /* No other fields should be used! */
561 }
562
563 pcp->hHWContext = hwContext;
564
565 if ( !(*psp->DriverAPI.CreateContext)(&config->modes, pcp, shareCtx) ) {
566 _mesa_free(pcp);
567 return NULL;
568 }
569
570 return pcp;
571 }
572
573
574 static __DRIcontext *
575 dri2CreateNewContext(__DRIscreen *screen, const __DRIconfig *config,
576 __DRIcontext *shared, void *data)
577 {
578 return driCreateNewContext(screen, config, 0, shared, 0, data);
579 }
580
581
582 static int
583 driCopyContext(__DRIcontext *dest, __DRIcontext *src, unsigned long mask)
584 {
585 return GL_FALSE;
586 }
587
588 /*@}*/
589
590
591 /*****************************************************************/
592 /** \name Screen handling functions */
593 /*****************************************************************/
594 /*@{*/
595
596 /**
597 * Destroy the per-screen private information.
598 *
599 * \internal
600 * This function calls __DriverAPIRec::DestroyScreen on \p screenPrivate, calls
601 * drmClose(), and finally frees \p screenPrivate.
602 */
603 static void driDestroyScreen(__DRIscreen *psp)
604 {
605 if (psp) {
606 /* No interaction with the X-server is possible at this point. This
607 * routine is called after XCloseDisplay, so there is no protocol
608 * stream open to the X-server anymore.
609 */
610
611 if (psp->DriverAPI.DestroyScreen)
612 (*psp->DriverAPI.DestroyScreen)(psp);
613
614 if (!psp->dri2.enabled) {
615 (void)drmUnmap((drmAddress)psp->pSAREA, SAREA_MAX);
616 (void)drmUnmap((drmAddress)psp->pFB, psp->fbSize);
617 (void)drmCloseOnce(psp->fd);
618 }
619
620 _mesa_free(psp);
621 }
622 }
623
624 static void
625 setupLoaderExtensions(__DRIscreen *psp,
626 const __DRIextension **extensions)
627 {
628 int i;
629
630 for (i = 0; extensions[i]; i++) {
631 if (strcmp(extensions[i]->name, __DRI_GET_DRAWABLE_INFO) == 0)
632 psp->getDrawableInfo = (__DRIgetDrawableInfoExtension *) extensions[i];
633 if (strcmp(extensions[i]->name, __DRI_DAMAGE) == 0)
634 psp->damage = (__DRIdamageExtension *) extensions[i];
635 if (strcmp(extensions[i]->name, __DRI_SYSTEM_TIME) == 0)
636 psp->systemTime = (__DRIsystemTimeExtension *) extensions[i];
637 if (strcmp(extensions[i]->name, __DRI_DRI2_LOADER) == 0)
638 psp->dri2.loader = (__DRIdri2LoaderExtension *) extensions[i];
639 }
640 }
641
642 /**
643 * This is the bootstrap function for the driver. libGL supplies all of the
644 * requisite information about the system, and the driver initializes itself.
645 * This routine also fills in the linked list pointed to by \c driver_modes
646 * with the \c __GLcontextModes that the driver can support for windows or
647 * pbuffers.
648 *
649 * For legacy DRI.
650 *
651 * \param scrn Index of the screen
652 * \param ddx_version Version of the 2D DDX. This may not be meaningful for
653 * all drivers.
654 * \param dri_version Version of the "server-side" DRI.
655 * \param drm_version Version of the kernel DRM.
656 * \param frame_buffer Data describing the location and layout of the
657 * framebuffer.
658 * \param pSAREA Pointer the the SAREA.
659 * \param fd Device handle for the DRM.
660 * \param extensions ??
661 * \param driver_modes Returns modes suppoted by the driver
662 * \param loaderPrivate ??
663 *
664 * \note There is no need to check the minimum API version in this
665 * function. Since the name of this function is versioned, it is
666 * impossible for a loader that is too old to even load this driver.
667 */
668 static __DRIscreen *
669 driCreateNewScreen(int scrn,
670 const __DRIversion *ddx_version,
671 const __DRIversion *dri_version,
672 const __DRIversion *drm_version,
673 const __DRIframebuffer *frame_buffer,
674 drmAddress pSAREA, int fd,
675 const __DRIextension **extensions,
676 const __DRIconfig ***driver_modes,
677 void *loaderPrivate)
678 {
679 static const __DRIextension *emptyExtensionList[] = { NULL };
680 __DRIscreen *psp;
681
682 psp = _mesa_calloc(sizeof *psp);
683 if (!psp)
684 return NULL;
685
686 setupLoaderExtensions(psp, extensions);
687
688 /*
689 ** NOT_DONE: This is used by the X server to detect when the client
690 ** has died while holding the drawable lock. The client sets the
691 ** drawable lock to this value.
692 */
693 psp->drawLockID = 1;
694
695 psp->drm_version = *drm_version;
696 psp->ddx_version = *ddx_version;
697 psp->dri_version = *dri_version;
698
699 psp->pSAREA = pSAREA;
700 psp->lock = (drmLock *) &psp->pSAREA->lock;
701
702 psp->pFB = frame_buffer->base;
703 psp->fbSize = frame_buffer->size;
704 psp->fbStride = frame_buffer->stride;
705 psp->fbWidth = frame_buffer->width;
706 psp->fbHeight = frame_buffer->height;
707 psp->devPrivSize = frame_buffer->dev_priv_size;
708 psp->pDevPriv = frame_buffer->dev_priv;
709 psp->fbBPP = psp->fbStride * 8 / frame_buffer->width;
710
711 psp->extensions = emptyExtensionList;
712 psp->fd = fd;
713 psp->myNum = scrn;
714 psp->dri2.enabled = GL_FALSE;
715
716 /*
717 ** Do not init dummy context here; actual initialization will be
718 ** done when the first DRI context is created. Init screen priv ptr
719 ** to NULL to let CreateContext routine that it needs to be inited.
720 */
721 psp->dummyContextPriv.driScreenPriv = NULL;
722
723 psp->DriverAPI = driDriverAPI;
724
725 *driver_modes = driDriverAPI.InitScreen(psp);
726 if (*driver_modes == NULL) {
727 _mesa_free(psp);
728 return NULL;
729 }
730
731 return psp;
732 }
733
734 /**
735 * DRI2
736 */
737 static __DRIscreen *
738 dri2CreateNewScreen(int scrn, int fd,
739 const __DRIextension **extensions,
740 const __DRIconfig ***driver_configs, void *data)
741 {
742 static const __DRIextension *emptyExtensionList[] = { NULL };
743 __DRIscreen *psp;
744 drmVersionPtr version;
745
746 if (driDriverAPI.InitScreen2 == NULL)
747 return NULL;
748
749 psp = _mesa_malloc(sizeof(*psp));
750 if (!psp)
751 return NULL;
752
753 setupLoaderExtensions(psp, extensions);
754
755 version = drmGetVersion(fd);
756 if (version) {
757 psp->drm_version.major = version->version_major;
758 psp->drm_version.minor = version->version_minor;
759 psp->drm_version.patch = version->version_patchlevel;
760 drmFreeVersion(version);
761 }
762
763 psp->extensions = emptyExtensionList;
764 psp->fd = fd;
765 psp->myNum = scrn;
766 psp->dri2.enabled = GL_TRUE;
767
768 psp->DriverAPI = driDriverAPI;
769 *driver_configs = driDriverAPI.InitScreen2(psp);
770 if (*driver_configs == NULL) {
771 _mesa_free(psp);
772 return NULL;
773 }
774
775 psp->DriverAPI = driDriverAPI;
776
777 return psp;
778 }
779
780 static const __DRIextension **driGetExtensions(__DRIscreen *psp)
781 {
782 return psp->extensions;
783 }
784
785 /** Core interface */
786 const __DRIcoreExtension driCoreExtension = {
787 { __DRI_CORE, __DRI_CORE_VERSION },
788 NULL,
789 driDestroyScreen,
790 driGetExtensions,
791 driGetConfigAttrib,
792 driIndexConfigAttrib,
793 NULL,
794 driDestroyDrawable,
795 driSwapBuffers,
796 NULL,
797 driCopyContext,
798 driDestroyContext,
799 driBindContext,
800 driUnbindContext
801 };
802
803 /** Legacy DRI interface */
804 const __DRIlegacyExtension driLegacyExtension = {
805 { __DRI_LEGACY, __DRI_LEGACY_VERSION },
806 driCreateNewScreen,
807 driCreateNewDrawable,
808 driCreateNewContext,
809 };
810
811 /** Legacy DRI interface */
812 const __DRIdri2Extension driDRI2Extension = {
813 { __DRI_DRI2, __DRI_DRI2_VERSION },
814 dri2CreateNewScreen,
815 dri2CreateNewDrawable,
816 dri2CreateNewContext,
817 };
818
819 /* This is the table of extensions that the loader will dlsym() for. */
820 PUBLIC const __DRIextension *__driDriverExtensions[] = {
821 &driCoreExtension.base,
822 &driLegacyExtension.base,
823 &driDRI2Extension.base,
824 NULL
825 };
826
827 static int
828 driFrameTracking(__DRIdrawable *drawable, GLboolean enable)
829 {
830 return GLX_BAD_CONTEXT;
831 }
832
833 static int
834 driQueryFrameTracking(__DRIdrawable *dpriv,
835 int64_t * sbc, int64_t * missedFrames,
836 float * lastMissedUsage, float * usage)
837 {
838 __DRIswapInfo sInfo;
839 int status;
840 int64_t ust;
841 __DRIscreenPrivate *psp = dpriv->driScreenPriv;
842
843 status = dpriv->driScreenPriv->DriverAPI.GetSwapInfo( dpriv, & sInfo );
844 if ( status == 0 ) {
845 *sbc = sInfo.swap_count;
846 *missedFrames = sInfo.swap_missed_count;
847 *lastMissedUsage = sInfo.swap_missed_usage;
848
849 (*psp->systemTime->getUST)( & ust );
850 *usage = driCalculateSwapUsage( dpriv, sInfo.swap_ust, ust );
851 }
852
853 return status;
854 }
855
856 const __DRIframeTrackingExtension driFrameTrackingExtension = {
857 { __DRI_FRAME_TRACKING, __DRI_FRAME_TRACKING_VERSION },
858 driFrameTracking,
859 driQueryFrameTracking
860 };
861
862 /**
863 * Calculate amount of swap interval used between GLX buffer swaps.
864 *
865 * The usage value, on the range [0,max], is the fraction of total swap
866 * interval time used between GLX buffer swaps is calculated.
867 *
868 * \f$p = t_d / (i * t_r)\f$
869 *
870 * Where \f$t_d\f$ is the time since the last GLX buffer swap, \f$i\f$ is the
871 * swap interval (as set by \c glXSwapIntervalSGI), and \f$t_r\f$ time
872 * required for a single vertical refresh period (as returned by \c
873 * glXGetMscRateOML).
874 *
875 * See the documentation for the GLX_MESA_swap_frame_usage extension for more
876 * details.
877 *
878 * \param dPriv Pointer to the private drawable structure.
879 * \return If less than a single swap interval time period was required
880 * between GLX buffer swaps, a number greater than 0 and less than
881 * 1.0 is returned. If exactly one swap interval time period is
882 * required, 1.0 is returned, and if more than one is required then
883 * a number greater than 1.0 will be returned.
884 *
885 * \sa glXSwapIntervalSGI glXGetMscRateOML
886 *
887 * \todo Instead of caching the \c glXGetMscRateOML function pointer, would it
888 * be possible to cache the sync rate?
889 */
890 float
891 driCalculateSwapUsage( __DRIdrawablePrivate *dPriv, int64_t last_swap_ust,
892 int64_t current_ust )
893 {
894 int32_t n;
895 int32_t d;
896 int interval;
897 float usage = 1.0;
898 __DRIscreenPrivate *psp = dPriv->driScreenPriv;
899
900 if ( (*psp->systemTime->getMSCRate)(dPriv, &n, &d, dPriv->loaderPrivate) ) {
901 interval = (dPriv->swap_interval != 0) ? dPriv->swap_interval : 1;
902
903
904 /* We want to calculate
905 * (current_UST - last_swap_UST) / (interval * us_per_refresh). We get
906 * current_UST by calling __glXGetUST. last_swap_UST is stored in
907 * dPriv->swap_ust. interval has already been calculated.
908 *
909 * The only tricky part is us_per_refresh. us_per_refresh is
910 * 1000000 / MSC_rate. We know the MSC_rate is n / d. We can flip it
911 * around and say us_per_refresh = 1000000 * d / n. Since this goes in
912 * the denominator of the final calculation, we calculate
913 * (interval * 1000000 * d) and move n into the numerator.
914 */
915
916 usage = (current_ust - last_swap_ust);
917 usage *= n;
918 usage /= (interval * d);
919 usage /= 1000000.0;
920 }
921
922 return usage;
923 }
924
925 /*@}*/