Add mouse and keyboard configuration file
[profile/ivi/xorg-x11-server.git] / glx / glxdri.c
1 /*
2  * Copyright © 2006 Red Hat, Inc
3  *
4  * Permission to use, copy, modify, distribute, and sell this software
5  * and its documentation for any purpose is hereby granted without
6  * fee, provided that the above copyright notice appear in all copies
7  * and that both that copyright notice and this permission notice
8  * appear in supporting documentation, and that the name of Red Hat,
9  * Inc not be used in advertising or publicity pertaining to
10  * distribution of the software without specific, written prior
11  * permission.  Red Hat, Inc makes no representations about the
12  * suitability of this software for any purpose.  It is provided "as
13  * is" without express or implied warranty.
14  *
15  * RED HAT, INC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
17  * NO EVENT SHALL RED HAT, INC BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
19  * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
20  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22  */
23
24 #ifdef HAVE_DIX_CONFIG_H
25 #include <dix-config.h>
26 #endif
27
28 #include <stdint.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <sys/time.h>
33 #include <dlfcn.h>
34
35 #include <drm.h>
36 #include <GL/gl.h>
37 #include <GL/internal/dri_interface.h>
38 #include <GL/glxtokens.h>
39
40 #include <windowstr.h>
41 #include <os.h>
42 #include <damage.h>
43
44 #define _XF86DRI_SERVER_
45 #include <drm_sarea.h>
46 #include <xf86drm.h>
47 #include <X11/dri/xf86driproto.h>
48 #include <xf86str.h>
49 #include <xf86.h>
50 #include <dri.h>
51
52 #include "servermd.h"
53
54 #define DRI_NEW_INTERFACE_ONLY
55 #include "glxserver.h"
56 #include "glxutil.h"
57 #include "glxdricommon.h"
58
59 #include "g_disptab.h"
60 #include "glapitable.h"
61 #include "glapi.h"
62 #include "glthread.h"
63 #include "dispatch.h"
64 #include "extension_string.h"
65
66 typedef struct __GLXDRIscreen   __GLXDRIscreen;
67 typedef struct __GLXDRIcontext  __GLXDRIcontext;
68 typedef struct __GLXDRIdrawable __GLXDRIdrawable;
69
70 struct __GLXDRIscreen {
71     __GLXscreen          base;
72     __DRIscreen         *driScreen;
73     void                *driver;
74
75     xf86EnterVTProc     *enterVT;
76     xf86LeaveVTProc     *leaveVT;
77
78     const __DRIcoreExtension *core;
79     const __DRIlegacyExtension *legacy;
80     const __DRIcopySubBufferExtension *copySubBuffer;
81     const __DRIswapControlExtension *swapControl;
82
83 #ifdef __DRI_TEX_OFFSET
84     const __DRItexOffsetExtension *texOffset;
85     DRITexOffsetStartProcPtr texOffsetStart;
86     DRITexOffsetFinishProcPtr texOffsetFinish;
87     __GLXDRIdrawable *texOffsetOverride[16];
88     GLuint lastTexOffsetOverride;
89 #endif
90
91     unsigned char glx_enable_bits[__GLX_EXT_BYTES];
92 };
93
94 struct __GLXDRIcontext {
95     __GLXcontext base;
96     __DRIcontext *driContext;
97     XID hwContextID;
98 };
99
100 struct __GLXDRIdrawable {
101     __GLXdrawable base;
102     __DRIdrawable *driDrawable;
103
104     /* Pulled in from old __GLXpixmap */
105 #ifdef __DRI_TEX_OFFSET
106     GLint texname;
107     __GLXDRIcontext *ctx;
108     unsigned long long offset;
109     DamagePtr pDamage;
110 #endif
111 };
112
113 static void
114 __glXDRIleaveServer(GLboolean rendering)
115 {
116     int i;
117
118     for (i = 0; rendering && i < screenInfo.numScreens; i++) {
119         __GLXDRIscreen * const screen =
120             (__GLXDRIscreen *) glxGetScreen(screenInfo.screens[i]);
121         GLuint lastOverride = screen->lastTexOffsetOverride;
122
123         if (lastOverride) {
124             __GLXDRIdrawable **texOffsetOverride = screen->texOffsetOverride;
125             int j;
126
127             for (j = 0; j < lastOverride; j++) {
128                 __GLXDRIdrawable *pGlxPix = texOffsetOverride[j];
129
130                 if (pGlxPix && pGlxPix->texname) {
131                     pGlxPix->offset =
132                         screen->texOffsetStart((PixmapPtr)pGlxPix->base.pDraw);
133                 }
134             }
135         }
136     }
137
138     DRIBlockHandler(NULL, NULL, NULL);
139
140     for (i = 0; rendering && i < screenInfo.numScreens; i++) {
141         __GLXDRIscreen * const screen =
142             (__GLXDRIscreen *) glxGetScreen(screenInfo.screens[i]);
143         GLuint lastOverride = screen->lastTexOffsetOverride;
144
145         if (lastOverride) {
146             __GLXDRIdrawable **texOffsetOverride = screen->texOffsetOverride;
147             int j;
148
149             for (j = 0; j < lastOverride; j++) {
150                 __GLXDRIdrawable *pGlxPix = texOffsetOverride[j];
151
152                 if (pGlxPix && pGlxPix->texname) {
153                     screen->texOffset->setTexOffset(pGlxPix->ctx->driContext,
154                                                     pGlxPix->texname,
155                                                     pGlxPix->offset,
156                                                     pGlxPix->base.pDraw->depth,
157                                                     ((PixmapPtr)pGlxPix->base.pDraw)->devKind);
158                 }
159             }
160         }
161     }
162 }
163     
164 static void
165 __glXDRIenterServer(GLboolean rendering)
166 {
167     int i;
168
169     for (i = 0; rendering && i < screenInfo.numScreens; i++) {
170         __GLXDRIscreen * const screen = (__GLXDRIscreen *)
171             glxGetScreen(screenInfo.screens[i]);
172
173         if (screen->lastTexOffsetOverride) {
174             CALL_Flush(GET_DISPATCH(), ());
175             break;
176         }
177     }
178
179     DRIWakeupHandler(NULL, 0, NULL);
180 }
181
182
183 static void
184 __glXDRIdoReleaseTexImage(__GLXDRIscreen *screen, __GLXDRIdrawable *drawable)
185 {
186     GLuint lastOverride = screen->lastTexOffsetOverride;
187
188     if (lastOverride) {
189         __GLXDRIdrawable **texOffsetOverride = screen->texOffsetOverride;
190         int i;
191
192         for (i = 0; i < lastOverride; i++) {
193             if (texOffsetOverride[i] == drawable) {
194                 if (screen->texOffsetFinish)
195                     screen->texOffsetFinish((PixmapPtr)drawable->base.pDraw);
196
197                 texOffsetOverride[i] = NULL;
198
199                 if (i + 1 == lastOverride) {
200                     lastOverride = 0;
201
202                     while (i--) {
203                         if (texOffsetOverride[i]) {
204                             lastOverride = i + 1;
205                             break;
206                         }
207                     }
208
209                     screen->lastTexOffsetOverride = lastOverride;
210
211                     break;
212                 }
213             }
214         }
215     }
216 }
217
218
219 static void
220 __glXDRIdrawableDestroy(__GLXdrawable *drawable)
221 {
222     __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable;
223     __GLXDRIscreen *screen;
224     int i;
225
226     for (i = 0; i < screenInfo.numScreens; i++) {
227         screen = (__GLXDRIscreen *) glxGetScreen(screenInfo.screens[i]);
228         __glXDRIdoReleaseTexImage(screen, private);
229     }
230
231     /* If the X window was destroyed, the dri DestroyWindow hook will
232      * aready have taken care of this, so only call if pDraw isn't NULL. */
233     if (drawable->pDraw != NULL) {
234         screen = (__GLXDRIscreen *) glxGetScreen(drawable->pDraw->pScreen);
235         (*screen->core->destroyDrawable)(private->driDrawable);
236
237         __glXenterServer(GL_FALSE);
238         DRIDestroyDrawable(drawable->pDraw->pScreen,
239                            serverClient, drawable->pDraw);
240         __glXleaveServer(GL_FALSE);
241     }
242
243     __glXDrawableRelease(drawable);
244
245     free(private);
246 }
247
248 static GLboolean
249 __glXDRIdrawableSwapBuffers(ClientPtr client, __GLXdrawable *basePrivate)
250 {
251     __GLXDRIdrawable *private = (__GLXDRIdrawable *) basePrivate;
252     __GLXDRIscreen *screen =
253         (__GLXDRIscreen *) glxGetScreen(basePrivate->pDraw->pScreen);
254
255     (*screen->core->swapBuffers)(private->driDrawable);
256
257     return TRUE;
258 }
259
260
261 static int
262 __glXDRIdrawableSwapInterval(__GLXdrawable *baseDrawable, int interval)
263 {
264     __GLXDRIdrawable *draw = (__GLXDRIdrawable *) baseDrawable;
265     __GLXDRIscreen *screen =
266         (__GLXDRIscreen *) glxGetScreen(baseDrawable->pDraw->pScreen);
267
268     if (screen->swapControl)
269         screen->swapControl->setSwapInterval(draw->driDrawable, interval);
270
271     return 0;
272 }
273
274
275 static void
276 __glXDRIdrawableCopySubBuffer(__GLXdrawable *basePrivate,
277                                int x, int y, int w, int h)
278 {
279     __GLXDRIdrawable *private = (__GLXDRIdrawable *) basePrivate;
280     __GLXDRIscreen *screen = (__GLXDRIscreen *)
281         glxGetScreen(basePrivate->pDraw->pScreen);
282
283     if (screen->copySubBuffer)
284         screen->copySubBuffer->copySubBuffer(private->driDrawable, x, y, w, h);
285 }
286
287 static void
288 __glXDRIcontextDestroy(__GLXcontext *baseContext)
289 {
290     __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext;
291     __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen;
292     Bool retval;
293
294     screen->core->destroyContext(context->driContext);
295
296     __glXenterServer(GL_FALSE);
297     retval = DRIDestroyContext(baseContext->pGlxScreen->pScreen,
298                                context->hwContextID);
299     __glXleaveServer(GL_FALSE);
300
301     __glXContextDestroy(&context->base);
302     free(context);
303 }
304
305 static int
306 __glXDRIcontextMakeCurrent(__GLXcontext *baseContext)
307 {
308     __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext;
309     __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen;
310     __GLXDRIdrawable *draw = (__GLXDRIdrawable *) baseContext->drawPriv;
311     __GLXDRIdrawable *read = (__GLXDRIdrawable *) baseContext->readPriv;
312
313     return (*screen->core->bindContext)(context->driContext,
314                                         draw->driDrawable,
315                                         read->driDrawable);
316 }                                             
317
318 static int
319 __glXDRIcontextLoseCurrent(__GLXcontext *baseContext)
320 {
321     __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext;
322     __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen;
323
324     return (*screen->core->unbindContext)(context->driContext);
325 }
326
327 static int
328 __glXDRIcontextCopy(__GLXcontext *baseDst, __GLXcontext *baseSrc,
329                     unsigned long mask)
330 {
331     __GLXDRIcontext *dst = (__GLXDRIcontext *) baseDst;
332     __GLXDRIcontext *src = (__GLXDRIcontext *) baseSrc;
333     __GLXDRIscreen *screen = (__GLXDRIscreen *) dst->base.pGlxScreen;
334
335     return (*screen->core->copyContext)(dst->driContext,
336                                         src->driContext, mask);
337 }
338
339 static int
340 __glXDRIcontextForceCurrent(__GLXcontext *baseContext)
341 {
342     __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext;
343     __GLXDRIdrawable *draw = (__GLXDRIdrawable *) baseContext->drawPriv;
344     __GLXDRIdrawable *read = (__GLXDRIdrawable *) baseContext->readPriv;
345     __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen;
346
347     return (*screen->core->bindContext)(context->driContext,
348                                         draw->driDrawable,
349                                         read->driDrawable);
350 }
351
352 static void
353 glxFillAlphaChannel (CARD32 *pixels, CARD32 rowstride, int width, int height)
354 {
355     int i;
356     CARD32 *p, *end;
357
358     rowstride /= 4;
359     
360     for (i = 0; i < height; i++)
361     {
362         p = pixels;
363         end = p + width;
364         while (p < end)
365           *p++ |= 0xFF000000;
366         pixels += rowstride;
367     }
368 }
369
370 static Bool
371 testTexOffset(__GLXDRIscreen * const screen, PixmapPtr pPixmap)
372 {
373     Bool ret;
374
375     if (!screen->texOffsetStart || !screen->texOffset)
376         return FALSE;
377
378     __glXenterServer(GL_FALSE);
379     ret = screen->texOffsetStart(pPixmap) != ~0ULL;
380     __glXleaveServer(GL_FALSE);
381
382     return ret;
383 }
384
385 /*
386  * (sticking this here for lack of a better place)
387  * Known issues with the GLX_EXT_texture_from_pixmap implementation:
388  * - In general we ignore the fbconfig, lots of examples follow
389  * - No fbconfig handling for multiple mipmap levels
390  * - No fbconfig handling for 1D textures
391  * - No fbconfig handling for TEXTURE_TARGET
392  * - No fbconfig exposure of Y inversion state
393  * - No GenerateMipmapEXT support (due to no FBO support)
394  * - No support for anything but 16bpp and 32bpp-sparse pixmaps
395  */
396
397 static int
398 __glXDRIbindTexImage(__GLXcontext *baseContext,
399                      int buffer,
400                      __GLXdrawable *glxPixmap)
401 {
402     RegionPtr   pRegion = NULL;
403     PixmapPtr   pixmap;
404     int         bpp, override = 0, texname;
405     GLenum      format, type;
406     ScreenPtr pScreen = glxPixmap->pDraw->pScreen;
407     __GLXDRIdrawable *driDraw = (__GLXDRIdrawable *) glxPixmap;
408     __GLXDRIscreen * const screen = (__GLXDRIscreen *) glxGetScreen(pScreen);
409
410     CALL_GetIntegerv(GET_DISPATCH(), (glxPixmap->target == GL_TEXTURE_2D ?
411                                       GL_TEXTURE_BINDING_2D :
412                                       GL_TEXTURE_BINDING_RECTANGLE_NV,
413                                       &texname));
414
415     if (!texname)
416         return __glXError(GLXBadContextState);
417
418     pixmap = (PixmapPtr) glxPixmap->pDraw;
419
420     if (testTexOffset(screen, pixmap)) {
421         __GLXDRIdrawable **texOffsetOverride = screen->texOffsetOverride;
422         int i, firstEmpty = 16;
423
424         for (i = 0; i < 16; i++) {
425             if (texOffsetOverride[i] == driDraw)
426                 goto alreadyin; 
427
428             if (firstEmpty == 16 && !texOffsetOverride[i])
429                 firstEmpty = i;
430         }
431
432         if (firstEmpty == 16) {
433             ErrorF("%s: Failed to register texture offset override\n", __func__);
434             goto nooverride;
435         }
436
437         if (firstEmpty >= screen->lastTexOffsetOverride)
438             screen->lastTexOffsetOverride = firstEmpty + 1;
439
440         texOffsetOverride[firstEmpty] = driDraw;
441
442 alreadyin:
443         override = 1;
444
445         driDraw->ctx = (__GLXDRIcontext*)baseContext;
446
447         if (texname == driDraw->texname)
448             return Success;
449
450         driDraw->texname = texname;
451
452         screen->texOffset->setTexOffset(driDraw->ctx->driContext, texname, 0,
453                                         pixmap->drawable.depth,
454                                         pixmap->devKind);
455     }
456 nooverride:
457
458     if (!driDraw->pDamage) {
459         if (!override) {
460             driDraw->pDamage = DamageCreate(NULL, NULL, DamageReportNone,
461                                             TRUE, pScreen, NULL);
462             if (!driDraw->pDamage)
463                 return BadAlloc;
464
465             DamageRegister ((DrawablePtr) pixmap, driDraw->pDamage);
466         }
467
468         pRegion = NULL;
469     } else {
470         pRegion = DamageRegion(driDraw->pDamage);
471         if (RegionNil(pRegion))
472             return Success;
473     }
474
475     /* XXX 24bpp packed, 8, etc */
476     if (pixmap->drawable.depth >= 24) {
477         bpp = 4;
478         format = GL_BGRA;
479         type =
480 #if X_BYTE_ORDER == X_BIG_ENDIAN
481             !override ? GL_UNSIGNED_INT_8_8_8_8_REV :
482 #endif
483             GL_UNSIGNED_BYTE;
484     } else {
485         bpp = 2;
486         format = GL_RGB;
487         type = GL_UNSIGNED_SHORT_5_6_5;
488     }
489
490     if (pRegion == NULL)
491     {
492         void *data = NULL;
493
494         if (!override) {
495             unsigned pitch = PixmapBytePad(pixmap->drawable.width,
496                                            pixmap->drawable.depth); 
497
498             data = malloc(pitch * pixmap->drawable.height);
499
500             __glXenterServer(GL_FALSE);
501             pScreen->GetImage(&pixmap->drawable, 0 /*pixmap->drawable.x*/,
502                               0 /*pixmap->drawable.y*/, pixmap->drawable.width,
503                               pixmap->drawable.height, ZPixmap, ~0, data);
504             __glXleaveServer(GL_FALSE);
505
506             if (pixmap->drawable.depth == 24)
507                 glxFillAlphaChannel(data,
508                                     pitch,
509                                     pixmap->drawable.width,
510                                     pixmap->drawable.height);
511
512             CALL_PixelStorei( GET_DISPATCH(), (GL_UNPACK_ROW_LENGTH,
513                                                pitch / bpp) );
514             CALL_PixelStorei( GET_DISPATCH(), (GL_UNPACK_SKIP_PIXELS, 0) );
515             CALL_PixelStorei( GET_DISPATCH(), (GL_UNPACK_SKIP_ROWS, 0) );
516         }
517
518         CALL_TexImage2D( GET_DISPATCH(),
519                          (glxPixmap->target,
520                           0,
521                           bpp == 4 ? 4 : 3,
522                           pixmap->drawable.width,
523                           pixmap->drawable.height,
524                           0,
525                           format,
526                           type,
527                           data) );
528
529         free(data);
530     } else if (!override) {
531         int i, numRects;
532         BoxPtr p;
533
534         numRects = RegionNumRects (pRegion);
535         p = RegionRects (pRegion);
536
537         CALL_PixelStorei( GET_DISPATCH(), (GL_UNPACK_SKIP_PIXELS, 0) );
538         CALL_PixelStorei( GET_DISPATCH(), (GL_UNPACK_SKIP_ROWS, 0) );
539
540         for (i = 0; i < numRects; i++)
541         {
542             unsigned pitch = PixmapBytePad(p[i].x2 - p[i].x1,
543                                            pixmap->drawable.depth);
544             void *data = malloc(pitch * (p[i].y2 - p[i].y1));
545
546             __glXenterServer(GL_FALSE);
547             pScreen->GetImage(&pixmap->drawable, /*pixmap->drawable.x +*/ p[i].x1,
548                               /*pixmap->drawable.y*/ + p[i].y1, p[i].x2 - p[i].x1,
549                               p[i].y2 - p[i].y1, ZPixmap, ~0, data);
550             __glXleaveServer(GL_FALSE);
551
552             if (pixmap->drawable.depth == 24)
553                 glxFillAlphaChannel(data,
554                                     pitch,
555                                     p[i].x2 - p[i].x1,
556                                     p[i].y2 - p[i].y1);
557
558             CALL_PixelStorei( GET_DISPATCH(), (GL_UNPACK_ROW_LENGTH,
559                                                pitch / bpp) );
560
561             CALL_TexSubImage2D( GET_DISPATCH(),
562                                 (glxPixmap->target,
563                                  0,
564                                  p[i].x1, p[i].y1,
565                                  p[i].x2 - p[i].x1, p[i].y2 - p[i].y1,
566                                  format,
567                                  type,
568                                  data) );
569
570             free(data);
571         }
572     }
573
574     if (!override)
575         DamageEmpty(driDraw->pDamage);
576
577     return Success;
578 }
579
580 static int
581 __glXDRIreleaseTexImage(__GLXcontext *baseContext,
582                         int buffer,
583                         __GLXdrawable *pixmap)
584 {
585     __GLXDRIscreen *screen =
586         (__GLXDRIscreen *) glxGetScreen(pixmap->pDraw->pScreen);
587     __GLXDRIdrawable *drawable = (__GLXDRIdrawable *) pixmap;
588
589     __glXDRIdoReleaseTexImage(screen, drawable);
590
591     return Success;
592 }
593
594 static __GLXtextureFromPixmap __glXDRItextureFromPixmap = {
595     __glXDRIbindTexImage,
596     __glXDRIreleaseTexImage
597 };
598
599 static void
600 __glXDRIscreenDestroy(__GLXscreen *baseScreen)
601 {
602     __GLXDRIscreen *screen = (__GLXDRIscreen *) baseScreen;
603
604     screen->core->destroyScreen(screen->driScreen);
605
606     dlclose(screen->driver);
607
608     __glXScreenDestroy(baseScreen);
609
610     free(screen);
611 }
612
613 static __GLXcontext *
614 __glXDRIscreenCreateContext(__GLXscreen *baseScreen,
615                             __GLXconfig *glxConfig,
616                             __GLXcontext *baseShareContext)
617 {
618     __GLXDRIscreen *screen = (__GLXDRIscreen *) baseScreen;
619     __GLXDRIcontext *context, *shareContext;
620     __GLXDRIconfig *config = (__GLXDRIconfig *) glxConfig;
621     VisualPtr visual;
622     int i;
623     GLboolean retval;
624     __DRIcontext *driShare;
625     drm_context_t hwContext;
626     ScreenPtr pScreen = baseScreen->pScreen;
627
628     shareContext = (__GLXDRIcontext *) baseShareContext;
629     if (shareContext)
630         driShare = shareContext->driContext;
631     else
632         driShare = NULL;
633
634     if (baseShareContext && baseShareContext->isDirect)
635         return NULL;
636
637     context = calloc(1, sizeof *context);
638     if (context == NULL)
639         return NULL;
640
641     context->base.destroy           = __glXDRIcontextDestroy;
642     context->base.makeCurrent       = __glXDRIcontextMakeCurrent;
643     context->base.loseCurrent       = __glXDRIcontextLoseCurrent;
644     context->base.copy              = __glXDRIcontextCopy;
645     context->base.forceCurrent      = __glXDRIcontextForceCurrent;
646
647     context->base.textureFromPixmap = &__glXDRItextureFromPixmap;
648     /* Find the requested X visual */
649     visual = pScreen->visuals;
650     for (i = 0; i < pScreen->numVisuals; i++, visual++)
651         if (visual->vid == glxConfig->visualID)
652             break;
653     if (i == pScreen->numVisuals)
654         return NULL;
655
656     context->hwContextID = FakeClientID(0);
657
658     __glXenterServer(GL_FALSE);
659     retval = DRICreateContext(baseScreen->pScreen, visual,
660                               context->hwContextID, &hwContext);
661     __glXleaveServer(GL_FALSE);
662
663     if (!retval)
664         return NULL;
665
666     context->driContext =
667         screen->legacy->createNewContext(screen->driScreen,
668                                          config->driConfig,
669                                          0, /* render type */
670                                          driShare,
671                                          hwContext,
672                                          context);
673
674     if (context->driContext == NULL) {
675         __glXenterServer(GL_FALSE);
676         retval = DRIDestroyContext(baseScreen->pScreen, context->hwContextID);
677         __glXleaveServer(GL_FALSE);
678         free(context);
679         return NULL;
680     }
681
682     return &context->base;
683 }
684
685 static __GLXdrawable *
686 __glXDRIscreenCreateDrawable(ClientPtr client,
687                              __GLXscreen *screen,
688                              DrawablePtr pDraw,
689                              XID drawId,
690                              int type,
691                              XID glxDrawId,
692                              __GLXconfig *glxConfig)
693 {
694     __GLXDRIscreen *driScreen = (__GLXDRIscreen *) screen;
695     __GLXDRIconfig *config = (__GLXDRIconfig *) glxConfig;
696     __GLXDRIdrawable *private;
697     GLboolean retval;
698     drm_drawable_t hwDrawable;
699
700     private = calloc(1, sizeof *private);
701     if (private == NULL)
702         return NULL;
703
704     if (!__glXDrawableInit(&private->base, screen,
705                            pDraw, type, glxDrawId, glxConfig)) {
706         free(private);
707         return NULL;
708     }
709
710     private->base.destroy       = __glXDRIdrawableDestroy;
711     private->base.swapBuffers   = __glXDRIdrawableSwapBuffers;
712     private->base.copySubBuffer = __glXDRIdrawableCopySubBuffer;
713     private->base.waitX         = NULL;
714     private->base.waitGL        = NULL;
715
716     __glXenterServer(GL_FALSE);
717     retval = DRICreateDrawable(screen->pScreen, serverClient,
718                                pDraw, &hwDrawable);
719     __glXleaveServer(GL_FALSE);
720
721     if (!retval) {
722         free(private);
723         return NULL;
724     }
725
726     /* The last argument is 'attrs', which is used with pbuffers which
727      * we currently don't support. */
728
729     private->driDrawable =
730         (driScreen->legacy->createNewDrawable)(driScreen->driScreen,
731                                                config->driConfig,
732                                                hwDrawable, 0, NULL, private);
733
734     if (private->driDrawable == NULL) {
735         __glXenterServer(GL_FALSE);
736         DRIDestroyDrawable(screen->pScreen, serverClient, pDraw);
737         __glXleaveServer(GL_FALSE);
738         free(private);
739         return NULL;
740     }
741
742     return &private->base;
743 }
744
745 static GLboolean
746 getDrawableInfo(__DRIdrawable *driDrawable,
747                 unsigned int *index, unsigned int *stamp,
748                 int *x, int *y, int *width, int *height,
749                 int *numClipRects, drm_clip_rect_t **ppClipRects,
750                 int *backX, int *backY,
751                 int *numBackClipRects, drm_clip_rect_t **ppBackClipRects,
752                 void *data)
753 {
754     __GLXDRIdrawable *drawable = data;
755     ScreenPtr pScreen;
756     drm_clip_rect_t *pClipRects, *pBackClipRects;
757     GLboolean retval;
758     size_t size;
759
760     /* If the X window has been destroyed, give up here. */
761     if (drawable->base.pDraw == NULL)
762         return GL_FALSE;
763
764     pScreen = drawable->base.pDraw->pScreen;
765     __glXenterServer(GL_FALSE);
766     retval = DRIGetDrawableInfo(pScreen, drawable->base.pDraw, index, stamp,
767                                 x, y, width, height,
768                                 numClipRects, &pClipRects,
769                                 backX, backY,
770                                 numBackClipRects, &pBackClipRects);
771     __glXleaveServer(GL_FALSE);
772
773     if (retval && *numClipRects > 0) {
774         size = sizeof (drm_clip_rect_t) * *numClipRects;
775         *ppClipRects = malloc(size);
776
777         /* Clip cliprects to screen dimensions (redirected windows) */
778         if (*ppClipRects != NULL) {
779             int i, j;
780
781             for (i = 0, j = 0; i < *numClipRects; i++) {
782                 (*ppClipRects)[j].x1 = max(pClipRects[i].x1, 0);
783                 (*ppClipRects)[j].y1 = max(pClipRects[i].y1, 0);
784                 (*ppClipRects)[j].x2 = min(pClipRects[i].x2, pScreen->width);
785                 (*ppClipRects)[j].y2 = min(pClipRects[i].y2, pScreen->height);
786
787                 if ((*ppClipRects)[j].x1 < (*ppClipRects)[j].x2 &&
788                     (*ppClipRects)[j].y1 < (*ppClipRects)[j].y2) {
789                     j++;
790                 }
791             }
792
793             if (*numClipRects != j) {
794                 *numClipRects = j;
795                 *ppClipRects = realloc(*ppClipRects,
796                                          sizeof (drm_clip_rect_t) *
797                                          *numClipRects);
798             }
799         } else
800             *numClipRects = 0;
801     }
802     else {
803       *ppClipRects = NULL;
804       *numClipRects = 0;
805     }
806       
807     if (retval && *numBackClipRects > 0) {
808         size = sizeof (drm_clip_rect_t) * *numBackClipRects;
809         *ppBackClipRects = malloc(size);
810         if (*ppBackClipRects != NULL)
811             memcpy (*ppBackClipRects, pBackClipRects, size);
812         else
813             *numBackClipRects = 0;
814     }
815     else {
816       *ppBackClipRects = NULL;
817       *numBackClipRects = 0;
818     }
819
820     return retval;
821 }
822
823 static void __glXReportDamage(__DRIdrawable *driDraw,
824                               int x, int y,
825                               drm_clip_rect_t *rects, int num_rects,
826                               GLboolean front_buffer,
827                               void *data)
828 {
829     __GLXDRIdrawable *drawable = data;
830     DrawablePtr pDraw = drawable->base.pDraw;
831     RegionRec region;
832
833     __glXenterServer(GL_FALSE);
834
835     RegionInit(&region, (BoxPtr) rects, num_rects);
836     RegionTranslate(&region, pDraw->x, pDraw->y);
837     DamageDamageRegion(pDraw, &region);
838     RegionUninit(&region);
839
840     __glXleaveServer(GL_FALSE);
841 }
842
843 static const __DRIgetDrawableInfoExtension getDrawableInfoExtension = {
844     { __DRI_GET_DRAWABLE_INFO, __DRI_GET_DRAWABLE_INFO_VERSION },
845     getDrawableInfo
846 };
847
848 static const __DRIdamageExtension damageExtension = {
849     { __DRI_DAMAGE, __DRI_DAMAGE_VERSION },
850     __glXReportDamage,
851 };
852
853 static const __DRIextension *loader_extensions[] = {
854     &systemTimeExtension.base,
855     &getDrawableInfoExtension.base,
856     &damageExtension.base,
857     NULL
858 };
859
860
861
862 static const char dri_driver_path[] = DRI_DRIVER_PATH;
863
864 static Bool
865 glxDRIEnterVT (int index, int flags)
866 {
867     ScrnInfoPtr scrn = xf86Screens[index];
868     Bool        ret;
869     __GLXDRIscreen *screen = (__GLXDRIscreen *) 
870         glxGetScreen(screenInfo.screens[index]);
871
872     LogMessage(X_INFO, "AIGLX: Resuming AIGLX clients after VT switch\n");
873
874     scrn->EnterVT = screen->enterVT;
875
876     ret = scrn->EnterVT (index, flags);
877
878     screen->enterVT = scrn->EnterVT;
879     scrn->EnterVT = glxDRIEnterVT;
880
881     if (!ret)
882         return FALSE;
883     
884     glxResumeClients();
885
886     return TRUE;
887 }
888
889 static void
890 glxDRILeaveVT (int index, int flags)
891 {
892     ScrnInfoPtr scrn = xf86Screens[index];
893     __GLXDRIscreen *screen = (__GLXDRIscreen *)
894         glxGetScreen(screenInfo.screens[index]);
895
896     LogMessage(X_INFO, "AIGLX: Suspending AIGLX clients for VT switch\n");
897
898     glxSuspendClients();
899
900     scrn->LeaveVT = screen->leaveVT;
901     (*screen->leaveVT) (index, flags);
902     screen->leaveVT = scrn->LeaveVT;
903     scrn->LeaveVT = glxDRILeaveVT;
904 }
905
906 static void
907 initializeExtensions(__GLXDRIscreen *screen)
908 {
909     const __DRIextension **extensions;
910     int i;
911
912     extensions = screen->core->getExtensions(screen->driScreen);
913
914     for (i = 0; extensions[i]; i++) {
915 #ifdef __DRI_READ_DRAWABLE
916         if (strcmp(extensions[i]->name, __DRI_READ_DRAWABLE) == 0) {
917             __glXEnableExtension(screen->glx_enable_bits,
918                                  "GLX_SGI_make_current_read");
919             
920             LogMessage(X_INFO, "AIGLX: enabled GLX_SGI_make_current_read\n");
921         }
922 #endif
923
924 #ifdef __DRI_COPY_SUB_BUFFER
925         if (strcmp(extensions[i]->name, __DRI_COPY_SUB_BUFFER) == 0) {
926             screen->copySubBuffer = (__DRIcopySubBufferExtension *) extensions[i];
927             __glXEnableExtension(screen->glx_enable_bits,
928                                  "GLX_MESA_copy_sub_buffer");
929             
930             LogMessage(X_INFO, "AIGLX: enabled GLX_MESA_copy_sub_buffer\n");
931         }
932 #endif
933
934 #ifdef __DRI_SWAP_CONTROL
935         if (strcmp(extensions[i]->name, __DRI_SWAP_CONTROL) == 0) {
936             screen->swapControl = (__DRIswapControlExtension *) extensions[i];
937             __glXEnableExtension(screen->glx_enable_bits,
938                                  "GLX_SGI_swap_control");
939             __glXEnableExtension(screen->glx_enable_bits,
940                                  "GLX_MESA_swap_control");
941             
942             LogMessage(X_INFO, "AIGLX: enabled GLX_SGI_swap_control and GLX_MESA_swap_control\n");
943         }
944 #endif
945
946 #ifdef __DRI_TEX_OFFSET
947         if (strcmp(extensions[i]->name, __DRI_TEX_OFFSET) == 0) {
948             screen->texOffset = (__DRItexOffsetExtension *) extensions[i];
949             LogMessage(X_INFO, "AIGLX: enabled GLX_texture_from_pixmap with driver support\n");
950         }
951 #endif
952         /* Ignore unknown extensions */
953     }
954 }
955     
956 static __GLXscreen *
957 __glXDRIscreenProbe(ScreenPtr pScreen)
958 {
959     drm_handle_t hSAREA;
960     drmAddress pSAREA = NULL;
961     char *BusID;
962     __DRIversion   ddx_version;
963     __DRIversion   dri_version;
964     __DRIversion   drm_version;
965     __DRIframebuffer  framebuffer;
966     int   fd = -1;
967     int   status;
968     drm_magic_t magic;
969     drmVersionPtr version;
970     int newlyopened;
971     char *driverName;
972     drm_handle_t  hFB;
973     int        junk;
974     __GLXDRIscreen *screen;
975     char filename[128];
976     Bool isCapable;
977     size_t buffer_size;
978     ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
979     const __DRIconfig **driConfigs;
980     const __DRIextension **extensions;
981     int i;
982
983     if (!xf86LoaderCheckSymbol("DRIQueryDirectRenderingCapable") ||
984         !DRIQueryDirectRenderingCapable(pScreen, &isCapable) ||
985         !isCapable) {
986         LogMessage(X_INFO,
987                    "AIGLX: Screen %d is not DRI capable\n", pScreen->myNum);
988         return NULL;
989     }
990
991     screen = calloc(1, sizeof *screen);
992     if (screen == NULL)
993       return NULL;
994
995     screen->base.destroy        = __glXDRIscreenDestroy;
996     screen->base.createContext  = __glXDRIscreenCreateContext;
997     screen->base.createDrawable = __glXDRIscreenCreateDrawable;
998     screen->base.swapInterval   = __glXDRIdrawableSwapInterval;
999     screen->base.pScreen       = pScreen;
1000
1001     __glXInitExtensionEnableBits(screen->glx_enable_bits);
1002
1003     /* DRI protocol version. */
1004     dri_version.major = XF86DRI_MAJOR_VERSION;
1005     dri_version.minor = XF86DRI_MINOR_VERSION;
1006     dri_version.patch = XF86DRI_PATCH_VERSION;
1007
1008     if (!DRIOpenConnection(pScreen, &hSAREA, &BusID)) {
1009         LogMessage(X_ERROR, "AIGLX error: DRIOpenConnection failed\n");
1010         goto handle_error;
1011     }
1012
1013     fd = drmOpenOnce(NULL, BusID, &newlyopened);
1014
1015     if (fd < 0) {
1016         LogMessage(X_ERROR, "AIGLX error: drmOpenOnce failed (%s)\n",
1017                    strerror(-fd));
1018         goto handle_error;
1019     }
1020
1021     if (drmGetMagic(fd, &magic)) {
1022         LogMessage(X_ERROR, "AIGLX error: drmGetMagic failed\n");
1023         goto handle_error;
1024     }
1025
1026     version = drmGetVersion(fd);
1027     if (version) {
1028         drm_version.major = version->version_major;
1029         drm_version.minor = version->version_minor;
1030         drm_version.patch = version->version_patchlevel;
1031         drmFreeVersion(version);
1032     }
1033     else {
1034         drm_version.major = -1;
1035         drm_version.minor = -1;
1036         drm_version.patch = -1;
1037     }
1038
1039     if (newlyopened && !DRIAuthConnection(pScreen, magic)) {
1040         LogMessage(X_ERROR, "AIGLX error: DRIAuthConnection failed\n");
1041         goto handle_error;
1042     }
1043
1044     /* Get device name (like "tdfx") and the ddx version numbers.
1045      * We'll check the version in each DRI driver's "createNewScreen"
1046      * function. */
1047     if (!DRIGetClientDriverName(pScreen,
1048                                 &ddx_version.major,
1049                                 &ddx_version.minor,
1050                                 &ddx_version.patch,
1051                                 &driverName)) {
1052         LogMessage(X_ERROR, "AIGLX error: DRIGetClientDriverName failed\n");
1053         goto handle_error;
1054     }
1055
1056     snprintf(filename, sizeof filename, "%s/%s_dri.so",
1057              dri_driver_path, driverName);
1058
1059     screen->driver = dlopen(filename, RTLD_LAZY | RTLD_LOCAL);
1060     if (screen->driver == NULL) {
1061         LogMessage(X_ERROR, "AIGLX error: dlopen of %s failed (%s)\n",
1062                    filename, dlerror());
1063         goto handle_error;
1064     }
1065
1066     extensions = dlsym(screen->driver, __DRI_DRIVER_EXTENSIONS);
1067     if (extensions == NULL) {
1068         LogMessage(X_ERROR, "AIGLX error: %s exports no extensions (%s)\n",
1069                    driverName, dlerror());
1070         goto handle_error;
1071     }
1072     
1073     for (i = 0; extensions[i]; i++) {
1074         if (strcmp(extensions[i]->name, __DRI_CORE) == 0 &&
1075             extensions[i]->version >= __DRI_CORE_VERSION) {
1076                 screen->core = (__DRIcoreExtension *) extensions[i];
1077         }
1078
1079         if (strcmp(extensions[i]->name, __DRI_LEGACY) == 0 &&
1080             extensions[i]->version >= __DRI_LEGACY_VERSION) {
1081                 screen->legacy = (__DRIlegacyExtension *) extensions[i];
1082         }
1083     }
1084
1085     if (screen->core == NULL || screen->legacy == NULL) {
1086         LogMessage(X_ERROR,
1087                    "AIGLX error: %s does not export required DRI extension\n",
1088                    driverName);
1089         goto handle_error;
1090     }
1091
1092     /*
1093      * Get device-specific info.  pDevPriv will point to a struct
1094      * (such as DRIRADEONRec in xfree86/driver/ati/radeon_dri.h) that
1095      * has information about the screen size, depth, pitch, ancilliary
1096      * buffers, DRM mmap handles, etc.
1097      */
1098     if (!DRIGetDeviceInfo(pScreen, &hFB, &junk,
1099                           &framebuffer.size, &framebuffer.stride,
1100                           &framebuffer.dev_priv_size, &framebuffer.dev_priv)) {
1101         LogMessage(X_ERROR, "AIGLX error: XF86DRIGetDeviceInfo failed\n");
1102         goto handle_error;
1103     }
1104
1105     framebuffer.width = pScreen->width;
1106     framebuffer.height = pScreen->height;
1107
1108     /* Map the framebuffer region. */
1109     status = drmMap(fd, hFB, framebuffer.size, 
1110                     (drmAddressPtr)&framebuffer.base);
1111     if (status != 0) {
1112         LogMessage(X_ERROR, "AIGLX error: drmMap of framebuffer failed (%s)\n",
1113                    strerror(-status));
1114         goto handle_error;
1115     }
1116
1117     /* Map the SAREA region.  Further mmap regions may be setup in
1118      * each DRI driver's "createNewScreen" function.
1119      */
1120     status = drmMap(fd, hSAREA, SAREA_MAX, &pSAREA);
1121     if (status != 0) {
1122         LogMessage(X_ERROR, "AIGLX error: drmMap of SAREA failed (%s)\n",
1123                    strerror(-status));
1124         goto handle_error;
1125     }
1126     
1127     screen->driScreen =
1128         (*screen->legacy->createNewScreen)(pScreen->myNum,
1129                                            &ddx_version,
1130                                            &dri_version,
1131                                            &drm_version,
1132                                            &framebuffer,
1133                                            pSAREA,
1134                                            fd,
1135                                            loader_extensions,
1136                                            &driConfigs,
1137                                            screen);
1138
1139     if (screen->driScreen == NULL) {
1140         LogMessage(X_ERROR,
1141                    "AIGLX error: Calling driver entry point failed\n");
1142         goto handle_error;
1143     }
1144
1145     screen->base.fbconfigs = glxConvertConfigs(screen->core,
1146                                                driConfigs, GLX_WINDOW_BIT);
1147
1148     initializeExtensions(screen);
1149
1150     DRIGetTexOffsetFuncs(pScreen, &screen->texOffsetStart,
1151                          &screen->texOffsetFinish);
1152
1153     __glXScreenInit(&screen->base, pScreen);
1154
1155     /* The first call simply determines the length of the extension string.
1156      * This allows us to allocate some memory to hold the extension string,
1157      * but it requires that we call __glXGetExtensionString a second time.
1158      */
1159     buffer_size = __glXGetExtensionString(screen->glx_enable_bits, NULL);
1160     if (buffer_size > 0) {
1161         if (screen->base.GLXextensions != NULL) {
1162             free(screen->base.GLXextensions);
1163         }
1164
1165         screen->base.GLXextensions = xnfalloc(buffer_size);
1166         (void) __glXGetExtensionString(screen->glx_enable_bits, 
1167                                        screen->base.GLXextensions);
1168     }
1169
1170     __glXsetEnterLeaveServerFuncs(__glXDRIenterServer, __glXDRIleaveServer);
1171
1172     screen->enterVT = pScrn->EnterVT;
1173     pScrn->EnterVT = glxDRIEnterVT;
1174     screen->leaveVT = pScrn->LeaveVT;
1175     pScrn->LeaveVT = glxDRILeaveVT;
1176
1177     LogMessage(X_INFO,
1178                "AIGLX: Loaded and initialized %s\n", filename);
1179
1180     return &screen->base;
1181
1182  handle_error:
1183     if (pSAREA != NULL)
1184         drmUnmap(pSAREA, SAREA_MAX);
1185
1186     if (framebuffer.base != NULL)
1187         drmUnmap((drmAddress)framebuffer.base, framebuffer.size);
1188
1189     if (fd >= 0)
1190         drmCloseOnce(fd);
1191
1192     DRICloseConnection(pScreen);
1193
1194     if (screen->driver)
1195         dlclose(screen->driver);
1196
1197     free(screen);
1198
1199     LogMessage(X_ERROR, "AIGLX: reverting to software rendering\n");
1200
1201     return NULL;
1202 }
1203
1204 _X_EXPORT __GLXprovider __glXDRIProvider = {
1205     __glXDRIscreenProbe,
1206     "DRI",
1207     NULL
1208 };