ceedd914fb3fa52a1b7dbda5c4b3056279c73cdc
[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 if (!dPriv->numClipRects)
319 return;
320
321 psp->DriverAPI.SwapBuffers(dPriv);
322
323 driReportDamage(dPriv, dPriv->pClipRects, dPriv->numClipRects);
324 }
325
326 static int driDrawableGetMSC( __DRIscreen *sPriv, __DRIdrawable *dPriv,
327 int64_t *msc )
328 {
329 return sPriv->DriverAPI.GetDrawableMSC(sPriv, dPriv, msc);
330 }
331
332
333 static int driWaitForMSC(__DRIdrawable *dPriv, int64_t target_msc,
334 int64_t divisor, int64_t remainder,
335 int64_t * msc, int64_t * sbc)
336 {
337 __DRIswapInfo sInfo;
338 int status;
339
340 status = dPriv->driScreenPriv->DriverAPI.WaitForMSC( dPriv, target_msc,
341 divisor, remainder,
342 msc );
343
344 /* GetSwapInfo() may not be provided by the driver if GLX_SGI_video_sync
345 * is supported but GLX_OML_sync_control is not. Therefore, don't return
346 * an error value if GetSwapInfo() is not implemented.
347 */
348 if ( status == 0
349 && dPriv->driScreenPriv->DriverAPI.GetSwapInfo ) {
350 status = dPriv->driScreenPriv->DriverAPI.GetSwapInfo( dPriv, & sInfo );
351 *sbc = sInfo.swap_count;
352 }
353
354 return status;
355 }
356
357
358 const __DRImediaStreamCounterExtension driMediaStreamCounterExtension = {
359 { __DRI_MEDIA_STREAM_COUNTER, __DRI_MEDIA_STREAM_COUNTER_VERSION },
360 driWaitForMSC,
361 driDrawableGetMSC,
362 };
363
364
365 static void driCopySubBuffer(__DRIdrawable *dPriv,
366 int x, int y, int w, int h)
367 {
368 drm_clip_rect_t rect;
369
370 rect.x1 = x;
371 rect.y1 = dPriv->h - y - h;
372 rect.x2 = x + w;
373 rect.y2 = rect.y1 + h;
374 driReportDamage(dPriv, &rect, 1);
375
376 dPriv->driScreenPriv->DriverAPI.CopySubBuffer(dPriv, x, y, w, h);
377 }
378
379 const __DRIcopySubBufferExtension driCopySubBufferExtension = {
380 { __DRI_COPY_SUB_BUFFER, __DRI_COPY_SUB_BUFFER_VERSION },
381 driCopySubBuffer
382 };
383
384 static void driSetSwapInterval(__DRIdrawable *dPriv, unsigned int interval)
385 {
386 dPriv->swap_interval = interval;
387 }
388
389 static unsigned int driGetSwapInterval(__DRIdrawable *dPriv)
390 {
391 return dPriv->swap_interval;
392 }
393
394 const __DRIswapControlExtension driSwapControlExtension = {
395 { __DRI_SWAP_CONTROL, __DRI_SWAP_CONTROL_VERSION },
396 driSetSwapInterval,
397 driGetSwapInterval
398 };
399
400
401 /**
402 * This is called via __DRIscreenRec's createNewDrawable pointer.
403 */
404 static __DRIdrawable *
405 driCreateNewDrawable(__DRIscreen *psp, const __DRIconfig *config,
406 drm_drawable_t hwDrawable, int renderType,
407 const int *attrs, void *data)
408 {
409 __DRIdrawable *pdp;
410
411 /* Since pbuffers are not yet supported, no drawable attributes are
412 * supported either.
413 */
414 (void) attrs;
415
416 pdp = _mesa_malloc(sizeof *pdp);
417 if (!pdp) {
418 return NULL;
419 }
420
421 pdp->loaderPrivate = data;
422 pdp->hHWDrawable = hwDrawable;
423 pdp->refcount = 0;
424 pdp->pStamp = NULL;
425 pdp->lastStamp = 0;
426 pdp->index = 0;
427 pdp->x = 0;
428 pdp->y = 0;
429 pdp->w = 0;
430 pdp->h = 0;
431 pdp->numClipRects = 0;
432 pdp->numBackClipRects = 0;
433 pdp->pClipRects = NULL;
434 pdp->pBackClipRects = NULL;
435 pdp->vblSeq = 0;
436 pdp->vblFlags = 0;
437
438 pdp->driScreenPriv = psp;
439 pdp->driContextPriv = &psp->dummyContextPriv;
440
441 if (!(*psp->DriverAPI.CreateBuffer)(psp, pdp, &config->modes,
442 renderType == GLX_PIXMAP_BIT)) {
443 _mesa_free(pdp);
444 return NULL;
445 }
446
447 pdp->msc_base = 0;
448
449 /* This special default value is replaced with the configured
450 * default value when the drawable is first bound to a direct
451 * rendering context.
452 */
453 pdp->swap_interval = (unsigned)-1;
454
455 return pdp;
456 }
457
458
459 static __DRIdrawable *
460 dri2CreateNewDrawable(__DRIscreen *screen,
461 const __DRIconfig *config,
462 void *loaderPrivate)
463 {
464 __DRIdrawable *pdraw;
465
466 pdraw = driCreateNewDrawable(screen, config, 0, 0, NULL, loaderPrivate);
467 if (!pdraw)
468 return NULL;
469
470 pdraw->pClipRects = _mesa_malloc(sizeof *pdraw->pBackClipRects);
471 pdraw->pBackClipRects = _mesa_malloc(sizeof *pdraw->pBackClipRects);
472
473 return pdraw;
474 }
475
476
477 static void
478 driDestroyDrawable(__DRIdrawable *pdp)
479 {
480 __DRIscreenPrivate *psp;
481
482 if (pdp) {
483 psp = pdp->driScreenPriv;
484 (*psp->DriverAPI.DestroyBuffer)(pdp);
485 if (pdp->pClipRects) {
486 _mesa_free(pdp->pClipRects);
487 pdp->pClipRects = NULL;
488 }
489 if (pdp->pBackClipRects) {
490 _mesa_free(pdp->pBackClipRects);
491 pdp->pBackClipRects = NULL;
492 }
493 _mesa_free(pdp);
494 }
495 }
496
497 /*@}*/
498
499
500 /*****************************************************************/
501 /** \name Context handling functions */
502 /*****************************************************************/
503 /*@{*/
504
505 /**
506 * Destroy the per-context private information.
507 *
508 * \internal
509 * This function calls __DriverAPIRec::DestroyContext on \p contextPrivate, calls
510 * drmDestroyContext(), and finally frees \p contextPrivate.
511 */
512 static void
513 driDestroyContext(__DRIcontext *pcp)
514 {
515 if (pcp) {
516 (*pcp->driScreenPriv->DriverAPI.DestroyContext)(pcp);
517 _mesa_free(pcp);
518 }
519 }
520
521
522 /**
523 * Create the per-drawable private driver information.
524 *
525 * \param render_type Type of rendering target. \c GLX_RGBA is the only
526 * type likely to ever be supported for direct-rendering.
527 * \param shared Context with which to share textures, etc. or NULL
528 *
529 * \returns An opaque pointer to the per-context private information on
530 * success, or \c NULL on failure.
531 *
532 * \internal
533 * This function allocates and fills a __DRIcontextPrivateRec structure. It
534 * performs some device independent initialization and passes all the
535 * relevent information to __DriverAPIRec::CreateContext to create the
536 * context.
537 *
538 */
539 static __DRIcontext *
540 driCreateNewContext(__DRIscreen *psp, const __DRIconfig *config,
541 int render_type, __DRIcontext *shared,
542 drm_context_t hwContext, void *data)
543 {
544 __DRIcontext *pcp;
545 void * const shareCtx = (shared != NULL) ? shared->driverPrivate : NULL;
546
547 pcp = _mesa_malloc(sizeof *pcp);
548 if (!pcp)
549 return NULL;
550
551 pcp->driScreenPriv = psp;
552 pcp->driDrawablePriv = NULL;
553
554 /* When the first context is created for a screen, initialize a "dummy"
555 * context.
556 */
557
558 if (!psp->dri2.enabled && !psp->dummyContextPriv.driScreenPriv) {
559 psp->dummyContextPriv.hHWContext = psp->pSAREA->dummy_context;
560 psp->dummyContextPriv.driScreenPriv = psp;
561 psp->dummyContextPriv.driDrawablePriv = NULL;
562 psp->dummyContextPriv.driverPrivate = NULL;
563 /* No other fields should be used! */
564 }
565
566 pcp->hHWContext = hwContext;
567
568 if ( !(*psp->DriverAPI.CreateContext)(&config->modes, pcp, shareCtx) ) {
569 _mesa_free(pcp);
570 return NULL;
571 }
572
573 return pcp;
574 }
575
576
577 static __DRIcontext *
578 dri2CreateNewContext(__DRIscreen *screen, const __DRIconfig *config,
579 __DRIcontext *shared, void *data)
580 {
581 return driCreateNewContext(screen, config, 0, shared, 0, data);
582 }
583
584
585 static int
586 driCopyContext(__DRIcontext *dest, __DRIcontext *src, unsigned long mask)
587 {
588 return GL_FALSE;
589 }
590
591 /*@}*/
592
593
594 /*****************************************************************/
595 /** \name Screen handling functions */
596 /*****************************************************************/
597 /*@{*/
598
599 /**
600 * Destroy the per-screen private information.
601 *
602 * \internal
603 * This function calls __DriverAPIRec::DestroyScreen on \p screenPrivate, calls
604 * drmClose(), and finally frees \p screenPrivate.
605 */
606 static void driDestroyScreen(__DRIscreen *psp)
607 {
608 if (psp) {
609 /* No interaction with the X-server is possible at this point. This
610 * routine is called after XCloseDisplay, so there is no protocol
611 * stream open to the X-server anymore.
612 */
613
614 if (psp->DriverAPI.DestroyScreen)
615 (*psp->DriverAPI.DestroyScreen)(psp);
616
617 if (!psp->dri2.enabled) {
618 (void)drmUnmap((drmAddress)psp->pSAREA, SAREA_MAX);
619 (void)drmUnmap((drmAddress)psp->pFB, psp->fbSize);
620 (void)drmCloseOnce(psp->fd);
621 }
622
623 _mesa_free(psp);
624 }
625 }
626
627 static void
628 setupLoaderExtensions(__DRIscreen *psp,
629 const __DRIextension **extensions)
630 {
631 int i;
632
633 for (i = 0; extensions[i]; i++) {
634 if (strcmp(extensions[i]->name, __DRI_GET_DRAWABLE_INFO) == 0)
635 psp->getDrawableInfo = (__DRIgetDrawableInfoExtension *) extensions[i];
636 if (strcmp(extensions[i]->name, __DRI_DAMAGE) == 0)
637 psp->damage = (__DRIdamageExtension *) extensions[i];
638 if (strcmp(extensions[i]->name, __DRI_SYSTEM_TIME) == 0)
639 psp->systemTime = (__DRIsystemTimeExtension *) extensions[i];
640 if (strcmp(extensions[i]->name, __DRI_DRI2_LOADER) == 0)
641 psp->dri2.loader = (__DRIdri2LoaderExtension *) extensions[i];
642 }
643 }
644
645 /**
646 * This is the bootstrap function for the driver. libGL supplies all of the
647 * requisite information about the system, and the driver initializes itself.
648 * This routine also fills in the linked list pointed to by \c driver_modes
649 * with the \c __GLcontextModes that the driver can support for windows or
650 * pbuffers.
651 *
652 * For legacy DRI.
653 *
654 * \param scrn Index of the screen
655 * \param ddx_version Version of the 2D DDX. This may not be meaningful for
656 * all drivers.
657 * \param dri_version Version of the "server-side" DRI.
658 * \param drm_version Version of the kernel DRM.
659 * \param frame_buffer Data describing the location and layout of the
660 * framebuffer.
661 * \param pSAREA Pointer the the SAREA.
662 * \param fd Device handle for the DRM.
663 * \param extensions ??
664 * \param driver_modes Returns modes suppoted by the driver
665 * \param loaderPrivate ??
666 *
667 * \note There is no need to check the minimum API version in this
668 * function. Since the name of this function is versioned, it is
669 * impossible for a loader that is too old to even load this driver.
670 */
671 static __DRIscreen *
672 driCreateNewScreen(int scrn,
673 const __DRIversion *ddx_version,
674 const __DRIversion *dri_version,
675 const __DRIversion *drm_version,
676 const __DRIframebuffer *frame_buffer,
677 drmAddress pSAREA, int fd,
678 const __DRIextension **extensions,
679 const __DRIconfig ***driver_modes,
680 void *loaderPrivate)
681 {
682 static const __DRIextension *emptyExtensionList[] = { NULL };
683 __DRIscreen *psp;
684
685 psp = _mesa_malloc(sizeof *psp);
686 if (!psp)
687 return NULL;
688
689 setupLoaderExtensions(psp, extensions);
690
691 /*
692 ** NOT_DONE: This is used by the X server to detect when the client
693 ** has died while holding the drawable lock. The client sets the
694 ** drawable lock to this value.
695 */
696 psp->drawLockID = 1;
697
698 psp->drm_version = *drm_version;
699 psp->ddx_version = *ddx_version;
700 psp->dri_version = *dri_version;
701
702 psp->pSAREA = pSAREA;
703 psp->lock = (drmLock *) &psp->pSAREA->lock;
704
705 psp->pFB = frame_buffer->base;
706 psp->fbSize = frame_buffer->size;
707 psp->fbStride = frame_buffer->stride;
708 psp->fbWidth = frame_buffer->width;
709 psp->fbHeight = frame_buffer->height;
710 psp->devPrivSize = frame_buffer->dev_priv_size;
711 psp->pDevPriv = frame_buffer->dev_priv;
712 psp->fbBPP = psp->fbStride * 8 / frame_buffer->width;
713
714 psp->extensions = emptyExtensionList;
715 psp->fd = fd;
716 psp->myNum = scrn;
717 psp->dri2.enabled = GL_FALSE;
718
719 /*
720 ** Do not init dummy context here; actual initialization will be
721 ** done when the first DRI context is created. Init screen priv ptr
722 ** to NULL to let CreateContext routine that it needs to be inited.
723 */
724 psp->dummyContextPriv.driScreenPriv = NULL;
725
726 psp->DriverAPI = driDriverAPI;
727
728 *driver_modes = driDriverAPI.InitScreen(psp);
729 if (*driver_modes == NULL) {
730 _mesa_free(psp);
731 return NULL;
732 }
733
734 return psp;
735 }
736
737 /**
738 * DRI2
739 */
740 static __DRIscreen *
741 dri2CreateNewScreen(int scrn, int fd,
742 const __DRIextension **extensions,
743 const __DRIconfig ***driver_configs, void *data)
744 {
745 static const __DRIextension *emptyExtensionList[] = { NULL };
746 __DRIscreen *psp;
747 drmVersionPtr version;
748
749 if (driDriverAPI.InitScreen2 == NULL)
750 return NULL;
751
752 psp = _mesa_malloc(sizeof(*psp));
753 if (!psp)
754 return NULL;
755
756 setupLoaderExtensions(psp, extensions);
757
758 version = drmGetVersion(fd);
759 if (version) {
760 psp->drm_version.major = version->version_major;
761 psp->drm_version.minor = version->version_minor;
762 psp->drm_version.patch = version->version_patchlevel;
763 drmFreeVersion(version);
764 }
765
766 psp->extensions = emptyExtensionList;
767 psp->fd = fd;
768 psp->myNum = scrn;
769 psp->dri2.enabled = GL_TRUE;
770
771 psp->DriverAPI = driDriverAPI;
772 *driver_configs = driDriverAPI.InitScreen2(psp);
773 if (*driver_configs == NULL) {
774 _mesa_free(psp);
775 return NULL;
776 }
777
778 psp->DriverAPI = driDriverAPI;
779
780 return psp;
781 }
782
783 static const __DRIextension **driGetExtensions(__DRIscreen *psp)
784 {
785 return psp->extensions;
786 }
787
788 /** Core interface */
789 const __DRIcoreExtension driCoreExtension = {
790 { __DRI_CORE, __DRI_CORE_VERSION },
791 NULL,
792 driDestroyScreen,
793 driGetExtensions,
794 driGetConfigAttrib,
795 driIndexConfigAttrib,
796 NULL,
797 driDestroyDrawable,
798 driSwapBuffers,
799 NULL,
800 driCopyContext,
801 driDestroyContext,
802 driBindContext,
803 driUnbindContext
804 };
805
806 /** Legacy DRI interface */
807 const __DRIlegacyExtension driLegacyExtension = {
808 { __DRI_LEGACY, __DRI_LEGACY_VERSION },
809 driCreateNewScreen,
810 driCreateNewDrawable,
811 driCreateNewContext,
812 };
813
814 /** Legacy DRI interface */
815 const __DRIdri2Extension driDRI2Extension = {
816 { __DRI_DRI2, __DRI_DRI2_VERSION },
817 dri2CreateNewScreen,
818 dri2CreateNewDrawable,
819 dri2CreateNewContext,
820 };
821
822 /* This is the table of extensions that the loader will dlsym() for. */
823 PUBLIC const __DRIextension *__driDriverExtensions[] = {
824 &driCoreExtension.base,
825 &driLegacyExtension.base,
826 &driDRI2Extension.base,
827 NULL
828 };
829
830 static int
831 driFrameTracking(__DRIdrawable *drawable, GLboolean enable)
832 {
833 return GLX_BAD_CONTEXT;
834 }
835
836 static int
837 driQueryFrameTracking(__DRIdrawable *dpriv,
838 int64_t * sbc, int64_t * missedFrames,
839 float * lastMissedUsage, float * usage)
840 {
841 __DRIswapInfo sInfo;
842 int status;
843 int64_t ust;
844 __DRIscreenPrivate *psp = dpriv->driScreenPriv;
845
846 status = dpriv->driScreenPriv->DriverAPI.GetSwapInfo( dpriv, & sInfo );
847 if ( status == 0 ) {
848 *sbc = sInfo.swap_count;
849 *missedFrames = sInfo.swap_missed_count;
850 *lastMissedUsage = sInfo.swap_missed_usage;
851
852 (*psp->systemTime->getUST)( & ust );
853 *usage = driCalculateSwapUsage( dpriv, sInfo.swap_ust, ust );
854 }
855
856 return status;
857 }
858
859 const __DRIframeTrackingExtension driFrameTrackingExtension = {
860 { __DRI_FRAME_TRACKING, __DRI_FRAME_TRACKING_VERSION },
861 driFrameTracking,
862 driQueryFrameTracking
863 };
864
865 /**
866 * Calculate amount of swap interval used between GLX buffer swaps.
867 *
868 * The usage value, on the range [0,max], is the fraction of total swap
869 * interval time used between GLX buffer swaps is calculated.
870 *
871 * \f$p = t_d / (i * t_r)\f$
872 *
873 * Where \f$t_d\f$ is the time since the last GLX buffer swap, \f$i\f$ is the
874 * swap interval (as set by \c glXSwapIntervalSGI), and \f$t_r\f$ time
875 * required for a single vertical refresh period (as returned by \c
876 * glXGetMscRateOML).
877 *
878 * See the documentation for the GLX_MESA_swap_frame_usage extension for more
879 * details.
880 *
881 * \param dPriv Pointer to the private drawable structure.
882 * \return If less than a single swap interval time period was required
883 * between GLX buffer swaps, a number greater than 0 and less than
884 * 1.0 is returned. If exactly one swap interval time period is
885 * required, 1.0 is returned, and if more than one is required then
886 * a number greater than 1.0 will be returned.
887 *
888 * \sa glXSwapIntervalSGI glXGetMscRateOML
889 *
890 * \todo Instead of caching the \c glXGetMscRateOML function pointer, would it
891 * be possible to cache the sync rate?
892 */
893 float
894 driCalculateSwapUsage( __DRIdrawablePrivate *dPriv, int64_t last_swap_ust,
895 int64_t current_ust )
896 {
897 int32_t n;
898 int32_t d;
899 int interval;
900 float usage = 1.0;
901 __DRIscreenPrivate *psp = dPriv->driScreenPriv;
902
903 if ( (*psp->systemTime->getMSCRate)(dPriv, &n, &d, dPriv->loaderPrivate) ) {
904 interval = (dPriv->swap_interval != 0) ? dPriv->swap_interval : 1;
905
906
907 /* We want to calculate
908 * (current_UST - last_swap_UST) / (interval * us_per_refresh). We get
909 * current_UST by calling __glXGetUST. last_swap_UST is stored in
910 * dPriv->swap_ust. interval has already been calculated.
911 *
912 * The only tricky part is us_per_refresh. us_per_refresh is
913 * 1000000 / MSC_rate. We know the MSC_rate is n / d. We can flip it
914 * around and say us_per_refresh = 1000000 * d / n. Since this goes in
915 * the denominator of the final calculation, we calculate
916 * (interval * 1000000 * d) and move n into the numerator.
917 */
918
919 usage = (current_ust - last_swap_ust);
920 usage *= n;
921 usage /= (interval * d);
922 usage /= 1000000.0;
923 }
924
925 return usage;
926 }
927
928 /*@}*/