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