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