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