Use __DRIextension mechanism providing loader functionality to the driver.
[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 #include <dlfcn.h>
25
26 #ifndef MAP_FAILED
27 #define MAP_FAILED ((void *)-1)
28 #endif
29
30 #include "imports.h"
31 #define None 0
32
33 #include "dri_util.h"
34 #include "drm_sarea.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 static void *driCreateNewDrawable(__DRIscreen *screen,
49 const __GLcontextModes *modes,
50 __DRIdrawable *pdraw,
51 drm_drawable_t hwDrawable,
52 int renderType, const int *attrs);
53
54 static void driDestroyDrawable(__DRIdrawable *drawable);
55
56
57 /**
58 * Print message to \c stderr if the \c LIBGL_DEBUG environment variable
59 * is set.
60 *
61 * Is called from the drivers.
62 *
63 * \param f \c printf like format string.
64 */
65 void
66 __driUtilMessage(const char *f, ...)
67 {
68 va_list args;
69
70 if (getenv("LIBGL_DEBUG")) {
71 fprintf(stderr, "libGL error: \n");
72 va_start(args, f);
73 vfprintf(stderr, f, args);
74 va_end(args);
75 fprintf(stderr, "\n");
76 }
77 }
78
79
80 /*****************************************************************/
81 /** \name Context (un)binding functions */
82 /*****************************************************************/
83 /*@{*/
84
85 /**
86 * Unbind context.
87 *
88 * \param scrn the screen.
89 * \param gc context.
90 *
91 * \return \c GL_TRUE on success, or \c GL_FALSE on failure.
92 *
93 * \internal
94 * This function calls __DriverAPIRec::UnbindContext, and then decrements
95 * __DRIdrawablePrivateRec::refcount which must be non-zero for a successful
96 * return.
97 *
98 * While casting the opaque private pointers associated with the parameters
99 * into their respective real types it also assures they are not \c NULL.
100 */
101 static GLboolean driUnbindContext(__DRIcontext *ctx)
102 {
103 __DRIcontextPrivate *pcp;
104 __DRIscreenPrivate *psp;
105 __DRIdrawablePrivate *pdp;
106 __DRIdrawablePrivate *prp;
107
108 /*
109 ** Assume error checking is done properly in glXMakeCurrent before
110 ** calling driUnbindContext.
111 */
112
113 if (ctx == NULL)
114 return GL_FALSE;
115
116 pcp = (__DRIcontextPrivate *)ctx->private;
117 psp = (__DRIscreenPrivate *)pcp->driScreenPriv;
118 pdp = (__DRIdrawablePrivate *)pcp->driDrawablePriv;
119 prp = (__DRIdrawablePrivate *)pcp->driReadablePriv;
120
121 /* Let driver unbind drawable from context */
122 (*psp->DriverAPI.UnbindContext)(pcp);
123
124 if (pdp->refcount == 0) {
125 /* ERROR!!! */
126 return GL_FALSE;
127 }
128
129 pdp->refcount--;
130
131 if (prp != pdp) {
132 if (prp->refcount == 0) {
133 /* ERROR!!! */
134 return GL_FALSE;
135 }
136
137 prp->refcount--;
138 }
139
140
141 /* XXX this is disabled so that if we call SwapBuffers on an unbound
142 * window we can determine the last context bound to the window and
143 * use that context's lock. (BrianP, 2-Dec-2000)
144 */
145 #if 0
146 /* Unbind the drawable */
147 pcp->driDrawablePriv = NULL;
148 pdp->driContextPriv = &psp->dummyContextPriv;
149 #endif
150
151 return GL_TRUE;
152 }
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 GLboolean driBindContext(__DRIcontext * ctx,
161 __DRIdrawable *pdraw,
162 __DRIdrawable *pread)
163 {
164 __DRIdrawablePrivate *pdp;
165 __DRIdrawablePrivate *prp;
166 __DRIcontextPrivate * const pcp = ctx->private;
167 __DRIscreenPrivate *psp = pcp->driScreenPriv;
168
169 /*
170 ** Assume error checking is done properly in glXMakeCurrent before
171 ** calling driBindContext.
172 */
173
174 if (ctx == NULL || pdraw == None || pread == None)
175 return GL_FALSE;
176
177 pdp = (__DRIdrawablePrivate *) pdraw->private;
178 prp = (__DRIdrawablePrivate *) pread->private;
179
180 /* Bind the drawable to the context */
181 pcp->driDrawablePriv = pdp;
182 pcp->driReadablePriv = prp;
183 pdp->driContextPriv = pcp;
184 pdp->refcount++;
185 if ( pdp != prp ) {
186 prp->refcount++;
187 }
188
189 /*
190 ** Now that we have a context associated with this drawable, we can
191 ** initialize the drawable information if has not been done before.
192 */
193
194 if (psp->dri2.enabled) {
195 __driParseEvents(psp, pdp);
196 __driParseEvents(psp, prp);
197 } else {
198 if (!pdp->pStamp || *pdp->pStamp != pdp->lastStamp) {
199 DRM_SPINLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID);
200 __driUtilUpdateDrawableInfo(pdp);
201 DRM_SPINUNLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID);
202 }
203
204 if ((pdp != prp) && (!prp->pStamp || *prp->pStamp != prp->lastStamp)) {
205 DRM_SPINLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID);
206 __driUtilUpdateDrawableInfo(prp);
207 DRM_SPINUNLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID);
208 }
209 }
210
211 /* Call device-specific MakeCurrent */
212 (*psp->DriverAPI.MakeCurrent)(pcp, pdp, prp);
213
214 return GL_TRUE;
215 }
216
217 /*@}*/
218
219
220 /*****************************************************************/
221 /** \name Drawable handling functions */
222 /*****************************************************************/
223 /*@{*/
224
225 /**
226 * Update private drawable information.
227 *
228 * \param pdp pointer to the private drawable information to update.
229 *
230 * This function basically updates the __DRIdrawablePrivate struct's
231 * cliprect information by calling \c __DRIinterfaceMethods::getDrawableInfo.
232 * This is usually called by the DRI_VALIDATE_DRAWABLE_INFO macro which
233 * compares the __DRIdrwablePrivate pStamp and lastStamp values. If
234 * the values are different that means we have to update the clipping
235 * info.
236 */
237 void
238 __driUtilUpdateDrawableInfo(__DRIdrawablePrivate *pdp)
239 {
240 __DRIscreenPrivate *psp = pdp->driScreenPriv;
241 __DRIcontextPrivate *pcp = pdp->driContextPriv;
242
243 if (!pcp
244 || ((pdp != pcp->driDrawablePriv) && (pdp != pcp->driReadablePriv))) {
245 /* ERROR!!!
246 * ...but we must ignore it. There can be many contexts bound to a
247 * drawable.
248 */
249 }
250
251 if (pdp->pClipRects) {
252 _mesa_free(pdp->pClipRects);
253 pdp->pClipRects = NULL;
254 }
255
256 if (pdp->pBackClipRects) {
257 _mesa_free(pdp->pBackClipRects);
258 pdp->pBackClipRects = NULL;
259 }
260
261 DRM_SPINUNLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID);
262
263 if (! (*psp->getDrawableInfo->getDrawableInfo)(pdp->pdraw,
264 &pdp->index, &pdp->lastStamp,
265 &pdp->x, &pdp->y, &pdp->w, &pdp->h,
266 &pdp->numClipRects, &pdp->pClipRects,
267 &pdp->backX,
268 &pdp->backY,
269 &pdp->numBackClipRects,
270 &pdp->pBackClipRects )) {
271 /* Error -- eg the window may have been destroyed. Keep going
272 * with no cliprects.
273 */
274 pdp->pStamp = &pdp->lastStamp; /* prevent endless loop */
275 pdp->numClipRects = 0;
276 pdp->pClipRects = NULL;
277 pdp->numBackClipRects = 0;
278 pdp->pBackClipRects = NULL;
279 }
280 else
281 pdp->pStamp = &(psp->pSAREA->drawableTable[pdp->index].stamp);
282
283 DRM_SPINLOCK(&psp->pSAREA->drawable_lock, psp->drawLockID);
284
285 }
286
287 int
288 __driParseEvents(__DRIscreenPrivate *psp, __DRIdrawablePrivate *pdp)
289 {
290 __DRIDrawableConfigEvent *dc;
291 __DRIBufferAttachEvent *ba;
292 unsigned int tail, mask, *p, end, total, size, changed;
293 unsigned char *data;
294 size_t rect_size;
295 __DRIcontextPrivate *pcp = pdp->driContextPriv;
296
297 if (pcp == NULL)
298 return 0;
299
300 /* Check for wraparound. */
301 if (psp->dri2.buffer->prealloc - pdp->dri2.tail > psp->dri2.buffer->size) {
302 /* If prealloc overlaps into what we just parsed, the
303 * server overwrote it and we have to reset our tail
304 * pointer. */
305 DRM_UNLOCK(psp->fd, psp->lock, pcp->hHWContext);
306 (*psp->dri2.core->reemitDrawableInfo)(pdp->pdraw);
307 DRM_LIGHT_LOCK(psp->fd, psp->lock, pcp->hHWContext);
308 }
309
310 total = psp->dri2.buffer->head - pdp->dri2.tail;
311 mask = psp->dri2.buffer->size - 1;
312 tail = pdp->dri2.tail;
313 end = psp->dri2.buffer->head;
314 data = psp->dri2.buffer->data;
315 changed = 0;
316
317 while (tail != end) {
318 p = (unsigned int *) (data + (tail & mask));
319 size = DRI2_EVENT_SIZE(*p);
320 if (size > total || (tail & mask) + size > psp->dri2.buffer->size) {
321 /* illegal data, bail out. */
322 fprintf(stderr, "illegal event size\n");
323 break;
324 }
325
326 switch (DRI2_EVENT_TYPE(*p)) {
327 case DRI2_EVENT_DRAWABLE_CONFIG:
328 dc = (__DRIDrawableConfigEvent *) p;
329
330 if (dc->drawable != pdp->hHWDrawable)
331 break;
332
333 if (pdp->w != dc->width || pdp->h != dc->height)
334 changed = 1;
335
336 pdp->x = dc->x;
337 pdp->y = dc->y;
338 pdp->w = dc->width;
339 pdp->h = dc->height;
340
341 pdp->backX = 0;
342 pdp->backY = 0;
343 pdp->numBackClipRects = 1;
344 pdp->pBackClipRects[0].x1 = 0;
345 pdp->pBackClipRects[0].y1 = 0;
346 pdp->pBackClipRects[0].x2 = pdp->w;
347 pdp->pBackClipRects[0].y2 = pdp->h;
348
349 pdp->numClipRects = dc->num_rects;
350 _mesa_free(pdp->pClipRects);
351 rect_size = dc->num_rects * sizeof dc->rects[0];
352 pdp->pClipRects = _mesa_malloc(rect_size);
353 memcpy(pdp->pClipRects, dc->rects, rect_size);
354
355 if (changed)
356 (*psp->DriverAPI.UpdateBuffer)(pdp, p);
357 break;
358
359 case DRI2_EVENT_BUFFER_ATTACH:
360 ba = (__DRIBufferAttachEvent *) p;
361
362 if (ba->drawable != pdp->hHWDrawable)
363 break;
364
365 (*psp->DriverAPI.UpdateBuffer)(pdp, p);
366 break;
367
368 default:
369 break;
370 }
371
372 tail += size;
373 }
374
375 pdp->dri2.tail = tail;
376
377 /* FIXME: Return whether we changed anything. This check always
378 * returns true if we received events, but we could refine the
379 * check to only return TRUE if the drawable actually changed. */
380
381 return total > 0;
382 }
383
384 /*@}*/
385
386 /*****************************************************************/
387 /** \name GLX callbacks */
388 /*****************************************************************/
389 /*@{*/
390
391 /**
392 * Swap buffers.
393 *
394 * \param drawablePrivate opaque pointer to the per-drawable private info.
395 *
396 * \internal
397 * This function calls __DRIdrawablePrivate::swapBuffers.
398 *
399 * Is called directly from glXSwapBuffers().
400 */
401 static void driSwapBuffers(__DRIdrawable *drawable)
402 {
403 __DRIdrawablePrivate *dPriv = drawable->private;
404 __DRIscreenPrivate *psp = dPriv->driScreenPriv;
405 drm_clip_rect_t rect;
406
407 if (!dPriv->numClipRects)
408 return;
409
410 dPriv->swapBuffers(dPriv);
411
412 /* Check that we actually have the new damage report method */
413 if (psp->damage == NULL)
414 return;
415
416 /* Assume it's affecting the whole drawable for now */
417 rect.x1 = 0;
418 rect.y1 = 0;
419 rect.x2 = rect.x1 + dPriv->w;
420 rect.y2 = rect.y1 + dPriv->h;
421
422 /* Report the damage. Currently, all our drivers draw directly to the
423 * front buffer, so we report the damage there rather than to the backing
424 * store (if any).
425 */
426 (*psp->damage->reportDamage)(dPriv->pdraw,
427 dPriv->x, dPriv->y, &rect, 1, GL_TRUE);
428 }
429
430 static int driDrawableGetMSC( __DRIscreen *screen, __DRIdrawable *drawable,
431 int64_t *msc )
432 {
433 __DRIscreenPrivate *sPriv = screen->private;
434 __DRIdrawablePrivate *dPriv = drawable->private;
435
436 return sPriv->DriverAPI.GetDrawableMSC(sPriv, dPriv, msc);
437 }
438
439 static int driWaitForMSC(__DRIdrawable *drawable, int64_t target_msc,
440 int64_t divisor, int64_t remainder,
441 int64_t * msc, int64_t * sbc)
442 {
443 __DRIdrawablePrivate *dPriv = drawable->private;
444 __DRIswapInfo sInfo;
445 int status;
446
447
448 status = dPriv->driScreenPriv->DriverAPI.WaitForMSC( dPriv, target_msc,
449 divisor, remainder,
450 msc );
451
452 /* GetSwapInfo() may not be provided by the driver if GLX_SGI_video_sync
453 * is supported but GLX_OML_sync_control is not. Therefore, don't return
454 * an error value if GetSwapInfo() is not implemented.
455 */
456 if ( status == 0
457 && dPriv->driScreenPriv->DriverAPI.GetSwapInfo ) {
458 status = dPriv->driScreenPriv->DriverAPI.GetSwapInfo( dPriv, & sInfo );
459 *sbc = sInfo.swap_count;
460 }
461
462 return status;
463 }
464
465 const __DRImediaStreamCounterExtension driMediaStreamCounterExtension = {
466 { __DRI_MEDIA_STREAM_COUNTER, __DRI_MEDIA_STREAM_COUNTER_VERSION },
467 driWaitForMSC,
468 driDrawableGetMSC,
469 };
470
471 static void driCopySubBuffer(__DRIdrawable *drawable,
472 int x, int y, int w, int h)
473 {
474 __DRIdrawablePrivate *dPriv = drawable->private;
475 dPriv->driScreenPriv->DriverAPI.CopySubBuffer(dPriv, x, y, w, h);
476 }
477
478 const __DRIcopySubBufferExtension driCopySubBufferExtension = {
479 { __DRI_COPY_SUB_BUFFER, __DRI_COPY_SUB_BUFFER_VERSION },
480 driCopySubBuffer
481 };
482
483 static void driSetSwapInterval(__DRIdrawable *drawable, unsigned int interval)
484 {
485 __DRIdrawablePrivate *dpriv = drawable->private;
486
487 dpriv->swap_interval = interval;
488 }
489
490 static unsigned int driGetSwapInterval(__DRIdrawable *drawable)
491 {
492 __DRIdrawablePrivate *dpriv = drawable->private;
493
494 return dpriv->swap_interval;
495 }
496
497 const __DRIswapControlExtension driSwapControlExtension = {
498 { __DRI_SWAP_CONTROL, __DRI_SWAP_CONTROL_VERSION },
499 driSetSwapInterval,
500 driGetSwapInterval
501 };
502
503
504 /**
505 * This is called via __DRIscreenRec's createNewDrawable pointer.
506 */
507 static void *driCreateNewDrawable(__DRIscreen *screen,
508 const __GLcontextModes *modes,
509 __DRIdrawable *pdraw,
510 drm_drawable_t hwDrawable,
511 int renderType,
512 const int *attrs)
513 {
514 __DRIscreenPrivate *psp;
515 __DRIdrawablePrivate *pdp;
516
517
518 pdraw->private = NULL;
519
520 /* Since pbuffers are not yet supported, no drawable attributes are
521 * supported either.
522 */
523 (void) attrs;
524
525 pdp = (__DRIdrawablePrivate *)_mesa_malloc(sizeof(__DRIdrawablePrivate));
526 if (!pdp) {
527 return NULL;
528 }
529
530 pdp->hHWDrawable = hwDrawable;
531 pdp->pdraw = pdraw;
532 pdp->refcount = 0;
533 pdp->pStamp = NULL;
534 pdp->lastStamp = 0;
535 pdp->index = 0;
536 pdp->x = 0;
537 pdp->y = 0;
538 pdp->w = 0;
539 pdp->h = 0;
540 pdp->numClipRects = 0;
541 pdp->numBackClipRects = 0;
542 pdp->pClipRects = NULL;
543 pdp->pBackClipRects = NULL;
544 pdp->vblSeq = 0;
545 pdp->vblFlags = 0;
546
547 psp = (__DRIscreenPrivate *)screen->private;
548 pdp->driScreenPriv = psp;
549 pdp->driContextPriv = &psp->dummyContextPriv;
550
551 if (!(*psp->DriverAPI.CreateBuffer)(psp, pdp, modes,
552 renderType == GLX_PIXMAP_BIT)) {
553 _mesa_free(pdp);
554 return NULL;
555 }
556
557 pdraw->private = pdp;
558 pdraw->destroyDrawable = driDestroyDrawable;
559 pdraw->swapBuffers = driSwapBuffers; /* called by glXSwapBuffers() */
560 pdp->msc_base = 0;
561
562 /* This special default value is replaced with the configured
563 * default value when the drawable is first bound to a direct
564 * rendering context.
565 */
566 pdp->swap_interval = (unsigned)-1;
567
568 pdp->swapBuffers = psp->DriverAPI.SwapBuffers;
569
570 if (psp->dri2.enabled) {
571 pdp->dri2.tail = 0;
572 pdp->pBackClipRects = _mesa_malloc(sizeof *pdp->pBackClipRects);
573 }
574
575 return (void *) pdp;
576 }
577
578 static void
579 driDestroyDrawable(__DRIdrawable *drawable)
580 {
581 __DRIdrawablePrivate *pdp = drawable->private;
582 __DRIscreenPrivate *psp;
583
584 if (pdp) {
585 psp = pdp->driScreenPriv;
586 (*psp->DriverAPI.DestroyBuffer)(pdp);
587 if (pdp->pClipRects) {
588 _mesa_free(pdp->pClipRects);
589 pdp->pClipRects = NULL;
590 }
591 if (pdp->pBackClipRects) {
592 _mesa_free(pdp->pBackClipRects);
593 pdp->pBackClipRects = NULL;
594 }
595 _mesa_free(pdp);
596 }
597 }
598
599 /*@}*/
600
601
602 /*****************************************************************/
603 /** \name Context handling functions */
604 /*****************************************************************/
605 /*@{*/
606
607 /**
608 * Destroy the per-context private information.
609 *
610 * \param contextPrivate opaque pointer to the per-drawable private info.
611 *
612 * \internal
613 * This function calls __DriverAPIRec::DestroyContext on \p contextPrivate, calls
614 * drmDestroyContext(), and finally frees \p contextPrivate.
615 */
616 static void
617 driDestroyContext(__DRIcontext *context)
618 {
619 __DRIcontextPrivate *pcp = context->private;
620
621 if (pcp) {
622 (*pcp->driScreenPriv->DriverAPI.DestroyContext)(pcp);
623 _mesa_free(pcp);
624 }
625 }
626
627
628 /**
629 * Create the per-drawable private driver information.
630 *
631 * \param dpy The display handle.
632 * \param modes Mode used to create the new context.
633 * \param render_type Type of rendering target. \c GLX_RGBA is the only
634 * type likely to ever be supported for direct-rendering.
635 * \param shared The shared context dependent methods or \c NULL if
636 * non-existent.
637 * \param pctx DRI context to receive the context dependent methods.
638 *
639 * \returns An opaque pointer to the per-context private information on
640 * success, or \c NULL on failure.
641 *
642 * \internal
643 * This function allocates and fills a __DRIcontextPrivateRec structure. It
644 * performs some device independent initialization and passes all the
645 * relevent information to __DriverAPIRec::CreateContext to create the
646 * context.
647 *
648 */
649 static void *
650 driCreateNewContext(__DRIscreen *screen, const __GLcontextModes *modes,
651 int render_type, __DRIcontext *shared,
652 drm_context_t hwContext, __DRIcontext *pctx)
653 {
654 __DRIcontextPrivate *pcp;
655 __DRIcontextPrivate *pshare = (shared != NULL) ? shared->private : NULL;
656 __DRIscreenPrivate *psp;
657 void * const shareCtx = (pshare != NULL) ? pshare->driverPrivate : NULL;
658
659 psp = (__DRIscreenPrivate *)screen->private;
660
661 pcp = (__DRIcontextPrivate *)_mesa_malloc(sizeof(__DRIcontextPrivate));
662 if (!pcp) {
663 return NULL;
664 }
665
666 pcp->hHWContext = hwContext;
667 pcp->driScreenPriv = psp;
668 pcp->driDrawablePriv = NULL;
669
670 /* When the first context is created for a screen, initialize a "dummy"
671 * context.
672 */
673
674 if (!psp->dri2.enabled && !psp->dummyContextPriv.driScreenPriv) {
675 psp->dummyContextPriv.hHWContext = psp->pSAREA->dummy_context;
676 psp->dummyContextPriv.driScreenPriv = psp;
677 psp->dummyContextPriv.driDrawablePriv = NULL;
678 psp->dummyContextPriv.driverPrivate = NULL;
679 /* No other fields should be used! */
680 }
681
682 pctx->destroyContext = driDestroyContext;
683 pctx->bindContext = driBindContext;
684 pctx->unbindContext = driUnbindContext;
685
686 if ( !(*psp->DriverAPI.CreateContext)(modes, pcp, shareCtx) ) {
687 _mesa_free(pcp);
688 return NULL;
689 }
690
691 return pcp;
692 }
693 /*@}*/
694
695
696 static const __DRIextension **
697 driGetExtensions(__DRIscreen *screen)
698 {
699 __DRIscreenPrivate *psp = screen->private;
700
701 return psp->extensions;
702 }
703
704 /*****************************************************************/
705 /** \name Screen handling functions */
706 /*****************************************************************/
707 /*@{*/
708
709 /**
710 * Destroy the per-screen private information.
711 *
712 * \param dpy the display handle.
713 * \param scrn the screen number.
714 * \param screenPrivate opaque pointer to the per-screen private information.
715 *
716 * \internal
717 * This function calls __DriverAPIRec::DestroyScreen on \p screenPrivate, calls
718 * drmClose(), and finally frees \p screenPrivate.
719 */
720 static void driDestroyScreen(__DRIscreen *screen)
721 {
722 __DRIscreenPrivate *psp = screen->private;
723
724 if (psp) {
725 /* No interaction with the X-server is possible at this point. This
726 * routine is called after XCloseDisplay, so there is no protocol
727 * stream open to the X-server anymore.
728 */
729
730 if (psp->DriverAPI.DestroyScreen)
731 (*psp->DriverAPI.DestroyScreen)(psp);
732
733 if (psp->dri2.enabled) {
734 drmBOUnmap(psp->fd, &psp->dri2.sareaBO);
735 drmBOUnreference(psp->fd, &psp->dri2.sareaBO);
736 } else {
737 (void)drmUnmap((drmAddress)psp->pSAREA, SAREA_MAX);
738 (void)drmUnmap((drmAddress)psp->pFB, psp->fbSize);
739 (void)drmCloseOnce(psp->fd);
740 }
741
742 _mesa_free(psp);
743 }
744 }
745
746 static void
747 setupLoaderExtensions(__DRIscreenPrivate *psp,
748 const __DRIextension **extensions)
749 {
750 int i;
751
752 for (i = 0; extensions[i]; i++) {
753 if (strcmp(extensions[i]->name, __DRI_CONTEXT_MODES) == 0)
754 psp->contextModes = (__DRIcontextModesExtension *) extensions[i];
755 if (strcmp(extensions[i]->name, __DRI_GET_DRAWABLE_INFO) == 0)
756 psp->getDrawableInfo = (__DRIgetDrawableInfoExtension *) extensions[i];
757 if (strcmp(extensions[i]->name, __DRI_DAMAGE) == 0)
758 psp->damage = (__DRIdamageExtension *) extensions[i];
759 if (strcmp(extensions[i]->name, __DRI_SYSTEM_TIME) == 0)
760 psp->systemTime = (__DRIsystemTimeExtension *) extensions[i];
761 if (strcmp(extensions[i]->name, __DRI_CORE_DRI2) == 0)
762 psp->dri2.core = (__DRIcoreDRI2Extension *) extensions[i];
763 }
764 }
765
766 /**
767 * This is the bootstrap function for the driver. libGL supplies all of the
768 * requisite information about the system, and the driver initializes itself.
769 * This routine also fills in the linked list pointed to by \c driver_modes
770 * with the \c __GLcontextModes that the driver can support for windows or
771 * pbuffers.
772 *
773 * \param scrn Index of the screen
774 * \param psc DRI screen data (not driver private)
775 * \param modes Linked list of known display modes. This list is, at a
776 * minimum, a list of modes based on the current display mode.
777 * These roughly match the set of available X11 visuals, but it
778 * need not be limited to X11! The calling libGL should create
779 * a list that will inform the driver of the current display
780 * mode (i.e., color buffer depth, depth buffer depth, etc.).
781 * \param ddx_version Version of the 2D DDX. This may not be meaningful for
782 * all drivers.
783 * \param dri_version Version of the "server-side" DRI.
784 * \param drm_version Version of the kernel DRM.
785 * \param frame_buffer Data describing the location and layout of the
786 * framebuffer.
787 * \param pSAREA Pointer the the SAREA.
788 * \param fd Device handle for the DRM.
789 * \param internal_api_version Version of the internal interface between the
790 * driver and libGL.
791 * \param driverAPI Driver API functions used by other routines in dri_util.c.
792 *
793 * \note There is no need to check the minimum API version in this
794 * function. Since the name of this function is versioned, it is
795 * impossible for a loader that is too old to even load this driver.
796 */
797 PUBLIC
798 void * __DRI_CREATE_NEW_SCREEN( int scrn, __DRIscreen *psc,
799 const __DRIversion * ddx_version,
800 const __DRIversion * dri_version,
801 const __DRIversion * drm_version,
802 const __DRIframebuffer * frame_buffer,
803 drmAddress pSAREA, int fd,
804 const __DRIextension ** extensions,
805 __GLcontextModes ** driver_modes )
806
807 {
808 __DRIscreenPrivate *psp;
809 static const __DRIextension *emptyExtensionList[] = { NULL };
810
811 psp = _mesa_malloc(sizeof(*psp));
812 if (!psp)
813 return NULL;
814
815 psp->psc = psc;
816
817 setupLoaderExtensions(psp, extensions);
818
819 /*
820 ** NOT_DONE: This is used by the X server to detect when the client
821 ** has died while holding the drawable lock. The client sets the
822 ** drawable lock to this value.
823 */
824 psp->drawLockID = 1;
825
826 psp->drm_version = *drm_version;
827 psp->ddx_version = *ddx_version;
828 psp->dri_version = *dri_version;
829
830 psp->pSAREA = pSAREA;
831 psp->lock = (drmLock *) &psp->pSAREA->lock;
832
833 psp->pFB = frame_buffer->base;
834 psp->fbSize = frame_buffer->size;
835 psp->fbStride = frame_buffer->stride;
836 psp->fbWidth = frame_buffer->width;
837 psp->fbHeight = frame_buffer->height;
838 psp->devPrivSize = frame_buffer->dev_priv_size;
839 psp->pDevPriv = frame_buffer->dev_priv;
840 psp->fbBPP = psp->fbStride * 8 / frame_buffer->width;
841
842 psp->extensions = emptyExtensionList;
843 psp->fd = fd;
844 psp->myNum = scrn;
845 psp->dri2.enabled = GL_FALSE;
846
847 /*
848 ** Do not init dummy context here; actual initialization will be
849 ** done when the first DRI context is created. Init screen priv ptr
850 ** to NULL to let CreateContext routine that it needs to be inited.
851 */
852 psp->dummyContextPriv.driScreenPriv = NULL;
853
854 psc->destroyScreen = driDestroyScreen;
855 psc->getExtensions = driGetExtensions;
856 psc->createNewDrawable = driCreateNewDrawable;
857 psc->createNewContext = driCreateNewContext;
858
859 *driver_modes = __driDriverInitScreen(psp);
860 if (*driver_modes == NULL) {
861 _mesa_free(psp);
862 return NULL;
863 }
864
865 return psp;
866 }
867
868 PUBLIC void *
869 __DRI2_CREATE_NEW_SCREEN(int scrn, __DRIscreen *psc,
870 int fd, unsigned int sarea_handle,
871 const __DRIextension **extensions,
872 __GLcontextModes **driver_modes)
873 {
874 __DRIscreenPrivate *psp;
875 static const __DRIextension *emptyExtensionList[] = { NULL };
876 unsigned int *p;
877 drmVersionPtr version;
878 __GLcontextModes *(*initScreen)(__DRIscreenPrivate *psc);
879
880 initScreen = dlsym(NULL, "__dri2DriverInitScreen");
881 if (initScreen == NULL)
882 return NULL;
883
884 psp = _mesa_malloc(sizeof(*psp));
885 if (!psp)
886 return NULL;
887
888 setupLoaderExtensions(psp, extensions);
889
890 psp->psc = psc;
891
892 version = drmGetVersion(fd);
893 if (version) {
894 psp->drm_version.major = version->version_major;
895 psp->drm_version.minor = version->version_minor;
896 psp->drm_version.patch = version->version_patchlevel;
897 drmFreeVersion(version);
898 }
899
900 psp->extensions = emptyExtensionList;
901 psp->fd = fd;
902 psp->myNum = scrn;
903 psp->dri2.enabled = GL_TRUE;
904
905 if (drmBOReference(psp->fd, sarea_handle, &psp->dri2.sareaBO)) {
906 fprintf(stderr, "Failed to reference DRI2 sarea BO\n");
907 _mesa_free(psp);
908 return NULL;
909 }
910
911 if (drmBOMap(psp->fd, &psp->dri2.sareaBO,
912 DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0, &psp->dri2.sarea)) {
913 drmBOUnreference(psp->fd, &psp->dri2.sareaBO);
914 _mesa_free(psp);
915 return NULL;
916 }
917
918 p = psp->dri2.sarea;
919 while (DRI2_SAREA_BLOCK_TYPE(*p)) {
920 switch (DRI2_SAREA_BLOCK_TYPE(*p)) {
921 case DRI2_SAREA_BLOCK_LOCK:
922 psp->dri2.lock = (__DRILock *) p;
923 break;
924 case DRI2_SAREA_BLOCK_EVENT_BUFFER:
925 psp->dri2.buffer = (__DRIEventBuffer *) p;
926 break;
927 }
928 p = DRI2_SAREA_BLOCK_NEXT(p);
929 }
930
931 psp->lock = (drmLock *) &psp->dri2.lock->lock;
932
933 psc->destroyScreen = driDestroyScreen;
934 psc->getExtensions = driGetExtensions;
935 psc->createNewDrawable = driCreateNewDrawable;
936 psc->createNewContext = driCreateNewContext;
937
938 *driver_modes = initScreen(psp);
939 if (*driver_modes == NULL) {
940 drmBOUnmap(psp->fd, &psp->dri2.sareaBO);
941 drmBOUnreference(psp->fd, &psp->dri2.sareaBO);
942 _mesa_free(psp);
943 return NULL;
944 }
945
946 return psp;
947 }
948
949 static int
950 driFrameTracking(__DRIdrawable *drawable, GLboolean enable)
951 {
952 return GLX_BAD_CONTEXT;
953 }
954
955 static int
956 driQueryFrameTracking(__DRIdrawable *drawable,
957 int64_t * sbc, int64_t * missedFrames,
958 float * lastMissedUsage, float * usage)
959 {
960 __DRIswapInfo sInfo;
961 int status;
962 int64_t ust;
963 __DRIdrawablePrivate * dpriv = drawable->private;
964 __DRIscreenPrivate *psp = dpriv->driScreenPriv;
965
966 status = dpriv->driScreenPriv->DriverAPI.GetSwapInfo( dpriv, & sInfo );
967 if ( status == 0 ) {
968 *sbc = sInfo.swap_count;
969 *missedFrames = sInfo.swap_missed_count;
970 *lastMissedUsage = sInfo.swap_missed_usage;
971
972 (*psp->systemTime->getUST)( & ust );
973 *usage = driCalculateSwapUsage( dpriv, sInfo.swap_ust, ust );
974 }
975
976 return status;
977 }
978
979 const __DRIframeTrackingExtension driFrameTrackingExtension = {
980 { __DRI_FRAME_TRACKING, __DRI_FRAME_TRACKING_VERSION },
981 driFrameTracking,
982 driQueryFrameTracking
983 };
984
985 /**
986 * Calculate amount of swap interval used between GLX buffer swaps.
987 *
988 * The usage value, on the range [0,max], is the fraction of total swap
989 * interval time used between GLX buffer swaps is calculated.
990 *
991 * \f$p = t_d / (i * t_r)\f$
992 *
993 * Where \f$t_d\f$ is the time since the last GLX buffer swap, \f$i\f$ is the
994 * swap interval (as set by \c glXSwapIntervalSGI), and \f$t_r\f$ time
995 * required for a single vertical refresh period (as returned by \c
996 * glXGetMscRateOML).
997 *
998 * See the documentation for the GLX_MESA_swap_frame_usage extension for more
999 * details.
1000 *
1001 * \param dPriv Pointer to the private drawable structure.
1002 * \return If less than a single swap interval time period was required
1003 * between GLX buffer swaps, a number greater than 0 and less than
1004 * 1.0 is returned. If exactly one swap interval time period is
1005 * required, 1.0 is returned, and if more than one is required then
1006 * a number greater than 1.0 will be returned.
1007 *
1008 * \sa glXSwapIntervalSGI glXGetMscRateOML
1009 *
1010 * \todo Instead of caching the \c glXGetMscRateOML function pointer, would it
1011 * be possible to cache the sync rate?
1012 */
1013 float
1014 driCalculateSwapUsage( __DRIdrawablePrivate *dPriv, int64_t last_swap_ust,
1015 int64_t current_ust )
1016 {
1017 int32_t n;
1018 int32_t d;
1019 int interval;
1020 float usage = 1.0;
1021 __DRIscreenPrivate *psp = dPriv->driScreenPriv;
1022
1023 if ( (*psp->systemTime->getMSCRate)(dPriv->pdraw, &n, &d) ) {
1024 interval = (dPriv->swap_interval != 0) ? dPriv->swap_interval : 1;
1025
1026
1027 /* We want to calculate
1028 * (current_UST - last_swap_UST) / (interval * us_per_refresh). We get
1029 * current_UST by calling __glXGetUST. last_swap_UST is stored in
1030 * dPriv->swap_ust. interval has already been calculated.
1031 *
1032 * The only tricky part is us_per_refresh. us_per_refresh is
1033 * 1000000 / MSC_rate. We know the MSC_rate is n / d. We can flip it
1034 * around and say us_per_refresh = 1000000 * d / n. Since this goes in
1035 * the denominator of the final calculation, we calculate
1036 * (interval * 1000000 * d) and move n into the numerator.
1037 */
1038
1039 usage = (current_ust - last_swap_ust);
1040 usage *= n;
1041 usage /= (interval * d);
1042 usage /= 1000000.0;
1043 }
1044
1045 return usage;
1046 }
1047
1048 /*@}*/