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