1 /*
2  * Copyright © 2007 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 <dlfcn.h>
33 
34 #include <GL/gl.h>
35 #include <GL/internal/dri_interface.h>
36 #include <GL/glxtokens.h>
37 
38 #include <windowstr.h>
39 #include <os.h>
40 
41 #define _XF86DRI_SERVER_
42 #include <xf86.h>
43 #include <dri2.h>
44 
45 #include <GL/glxtokens.h>
46 #include "glxserver.h"
47 #include "glxutil.h"
48 #include "glxdricommon.h"
49 
50 #include "extension_string.h"
51 
52 typedef struct __GLXDRIscreen __GLXDRIscreen;
53 typedef struct __GLXDRIcontext __GLXDRIcontext;
54 typedef struct __GLXDRIdrawable __GLXDRIdrawable;
55 
56 #define ALL_DRI_CTX_FLAGS (__DRI_CTX_FLAG_DEBUG                         \
57                            | __DRI_CTX_FLAG_FORWARD_COMPATIBLE          \
58                            | __DRI_CTX_FLAG_ROBUST_BUFFER_ACCESS)
59 
60 struct __GLXDRIscreen {
61     __GLXscreen base;
62     __DRIscreen *driScreen;
63     void *driver;
64     int fd;
65 
66     xf86EnterVTProc *enterVT;
67     xf86LeaveVTProc *leaveVT;
68 
69     const __DRIcoreExtension *core;
70     const __DRIdri2Extension *dri2;
71     const __DRI2flushExtension *flush;
72     const __DRIcopySubBufferExtension *copySubBuffer;
73     const __DRIswapControlExtension *swapControl;
74     const __DRItexBufferExtension *texBuffer;
75     const __DRIconfig **driConfigs;
76 };
77 
78 struct __GLXDRIcontext {
79     __GLXcontext base;
80     __DRIcontext *driContext;
81 };
82 
83 #define MAX_DRAWABLE_BUFFERS 5
84 
85 struct __GLXDRIdrawable {
86     __GLXdrawable base;
87     __DRIdrawable *driDrawable;
88     __GLXDRIscreen *screen;
89 
90     /* Dimensions as last reported by DRI2GetBuffers. */
91     int width;
92     int height;
93     __DRIbuffer buffers[MAX_DRAWABLE_BUFFERS];
94     int count;
95     XID dri2_id;
96 };
97 
98 static void
copy_box(__GLXdrawable * drawable,int dst,int src,int x,int y,int w,int h)99 copy_box(__GLXdrawable * drawable,
100          int dst, int src,
101          int x, int y, int w, int h)
102 {
103     BoxRec box;
104     RegionRec region;
105     __GLXcontext *cx = lastGLContext;
106 
107     box.x1 = x;
108     box.y1 = y;
109     box.x2 = x + w;
110     box.y2 = y + h;
111     RegionInit(&region, &box, 0);
112 
113     DRI2CopyRegion(drawable->pDraw, &region, dst, src);
114     if (cx != lastGLContext) {
115         lastGLContext = cx;
116         cx->makeCurrent(cx);
117     }
118 }
119 
120 /* white lie */
121 extern glx_func_ptr glXGetProcAddressARB(const char *);
122 
123 static void
__glXDRIdrawableDestroy(__GLXdrawable * drawable)124 __glXDRIdrawableDestroy(__GLXdrawable * drawable)
125 {
126     __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable;
127     const __DRIcoreExtension *core = private->screen->core;
128 
129     FreeResource(private->dri2_id, FALSE);
130 
131     (*core->destroyDrawable) (private->driDrawable);
132 
133     __glXDrawableRelease(drawable);
134 
135     free(private);
136 }
137 
138 static void
__glXDRIdrawableCopySubBuffer(__GLXdrawable * drawable,int x,int y,int w,int h)139 __glXDRIdrawableCopySubBuffer(__GLXdrawable * drawable,
140                               int x, int y, int w, int h)
141 {
142     __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable;
143 
144     copy_box(drawable, x, private->height - y - h,
145              w, h,
146              DRI2BufferFrontLeft, DRI2BufferBackLeft);
147 }
148 
149 static void
__glXDRIdrawableWaitX(__GLXdrawable * drawable)150 __glXDRIdrawableWaitX(__GLXdrawable * drawable)
151 {
152     __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable;
153 
154     copy_box(drawable, DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft,
155              0, 0, private->width, private->height);
156 }
157 
158 static void
__glXDRIdrawableWaitGL(__GLXdrawable * drawable)159 __glXDRIdrawableWaitGL(__GLXdrawable * drawable)
160 {
161     __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable;
162 
163     copy_box(drawable, DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft,
164              0, 0, private->width, private->height);
165 }
166 
167 static void
__glXdriSwapEvent(ClientPtr client,void * data,int type,CARD64 ust,CARD64 msc,CARD32 sbc)168 __glXdriSwapEvent(ClientPtr client, void *data, int type, CARD64 ust,
169                   CARD64 msc, CARD32 sbc)
170 {
171     __GLXdrawable *drawable = data;
172     int glx_type;
173     switch (type) {
174     case DRI2_EXCHANGE_COMPLETE:
175         glx_type = GLX_EXCHANGE_COMPLETE_INTEL;
176         break;
177     default:
178         /* unknown swap completion type,
179          * BLIT is a reasonable default, so
180          * fall through ...
181          */
182     case DRI2_BLIT_COMPLETE:
183         glx_type = GLX_BLIT_COMPLETE_INTEL;
184         break;
185     case DRI2_FLIP_COMPLETE:
186         glx_type = GLX_FLIP_COMPLETE_INTEL;
187         break;
188     }
189 
190     __glXsendSwapEvent(drawable, glx_type, ust, msc, sbc);
191 }
192 
193 /*
194  * Copy or flip back to front, honoring the swap interval if possible.
195  *
196  * If the kernel supports it, we request an event for the frame when the
197  * swap should happen, then perform the copy when we receive it.
198  */
199 static GLboolean
__glXDRIdrawableSwapBuffers(ClientPtr client,__GLXdrawable * drawable)200 __glXDRIdrawableSwapBuffers(ClientPtr client, __GLXdrawable * drawable)
201 {
202     __GLXDRIdrawable *priv = (__GLXDRIdrawable *) drawable;
203     __GLXDRIscreen *screen = priv->screen;
204     CARD64 unused;
205     __GLXcontext *cx = lastGLContext;
206     int status;
207 
208     if (screen->flush) {
209         (*screen->flush->flush) (priv->driDrawable);
210         (*screen->flush->invalidate) (priv->driDrawable);
211     }
212 
213     status = DRI2SwapBuffers(client, drawable->pDraw, 0, 0, 0, &unused,
214                              __glXdriSwapEvent, drawable);
215     if (cx != lastGLContext) {
216         lastGLContext = cx;
217         cx->makeCurrent(cx);
218     }
219 
220     return status == Success;
221 }
222 
223 static int
__glXDRIdrawableSwapInterval(__GLXdrawable * drawable,int interval)224 __glXDRIdrawableSwapInterval(__GLXdrawable * drawable, int interval)
225 {
226     __GLXcontext *cx = lastGLContext;
227 
228     if (interval <= 0)          /* || interval > BIGNUM? */
229         return GLX_BAD_VALUE;
230 
231     DRI2SwapInterval(drawable->pDraw, interval);
232     if (cx != lastGLContext) {
233         lastGLContext = cx;
234         cx->makeCurrent(cx);
235     }
236 
237     return 0;
238 }
239 
240 static void
__glXDRIcontextDestroy(__GLXcontext * baseContext)241 __glXDRIcontextDestroy(__GLXcontext * baseContext)
242 {
243     __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext;
244     __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen;
245 
246     (*screen->core->destroyContext) (context->driContext);
247     __glXContextDestroy(&context->base);
248     free(context);
249 }
250 
251 static int
__glXDRIcontextMakeCurrent(__GLXcontext * baseContext)252 __glXDRIcontextMakeCurrent(__GLXcontext * baseContext)
253 {
254     __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext;
255     __GLXDRIdrawable *draw = (__GLXDRIdrawable *) baseContext->drawPriv;
256     __GLXDRIdrawable *read = (__GLXDRIdrawable *) baseContext->readPriv;
257     __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen;
258 
259     return (*screen->core->bindContext) (context->driContext,
260                                          draw->driDrawable, read->driDrawable);
261 }
262 
263 static int
__glXDRIcontextLoseCurrent(__GLXcontext * baseContext)264 __glXDRIcontextLoseCurrent(__GLXcontext * baseContext)
265 {
266     __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext;
267     __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen;
268 
269     return (*screen->core->unbindContext) (context->driContext);
270 }
271 
272 static int
__glXDRIcontextCopy(__GLXcontext * baseDst,__GLXcontext * baseSrc,unsigned long mask)273 __glXDRIcontextCopy(__GLXcontext * baseDst, __GLXcontext * baseSrc,
274                     unsigned long mask)
275 {
276     __GLXDRIcontext *dst = (__GLXDRIcontext *) baseDst;
277     __GLXDRIcontext *src = (__GLXDRIcontext *) baseSrc;
278     __GLXDRIscreen *screen = (__GLXDRIscreen *) dst->base.pGlxScreen;
279 
280     return (*screen->core->copyContext) (dst->driContext,
281                                          src->driContext, mask);
282 }
283 
284 static Bool
__glXDRIcontextWait(__GLXcontext * baseContext,__GLXclientState * cl,int * error)285 __glXDRIcontextWait(__GLXcontext * baseContext,
286                     __GLXclientState * cl, int *error)
287 {
288     __GLXcontext *cx = lastGLContext;
289     Bool ret;
290 
291     ret = DRI2WaitSwap(cl->client, baseContext->drawPriv->pDraw);
292     if (cx != lastGLContext) {
293         lastGLContext = cx;
294         cx->makeCurrent(cx);
295     }
296 
297     if (ret) {
298         *error = cl->client->noClientException;
299         return TRUE;
300     }
301 
302     return FALSE;
303 }
304 
305 static int
__glXDRIbindTexImage(__GLXcontext * baseContext,int buffer,__GLXdrawable * glxPixmap)306 __glXDRIbindTexImage(__GLXcontext * baseContext,
307                      int buffer, __GLXdrawable * glxPixmap)
308 {
309     __GLXDRIdrawable *drawable = (__GLXDRIdrawable *) glxPixmap;
310     const __DRItexBufferExtension *texBuffer = drawable->screen->texBuffer;
311     __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext;
312 
313     if (texBuffer == NULL)
314         return Success;
315 
316     if (texBuffer->base.version >= 2 && texBuffer->setTexBuffer2 != NULL) {
317         (*texBuffer->setTexBuffer2) (context->driContext,
318                                      glxPixmap->target,
319                                      glxPixmap->format, drawable->driDrawable);
320     }
321     else
322     {
323         texBuffer->setTexBuffer(context->driContext,
324                                 glxPixmap->target, drawable->driDrawable);
325     }
326 
327     return Success;
328 }
329 
330 static int
__glXDRIreleaseTexImage(__GLXcontext * baseContext,int buffer,__GLXdrawable * pixmap)331 __glXDRIreleaseTexImage(__GLXcontext * baseContext,
332                         int buffer, __GLXdrawable * pixmap)
333 {
334     /* FIXME: Just unbind the texture? */
335     return Success;
336 }
337 
338 static Bool
dri2_convert_glx_attribs(__GLXDRIscreen * screen,unsigned num_attribs,const uint32_t * attribs,unsigned * major_ver,unsigned * minor_ver,uint32_t * flags,int * api,int * reset,unsigned * error)339 dri2_convert_glx_attribs(__GLXDRIscreen *screen, unsigned num_attribs,
340                          const uint32_t *attribs,
341                          unsigned *major_ver, unsigned *minor_ver,
342                          uint32_t *flags, int *api, int *reset, unsigned *error)
343 {
344     unsigned i;
345 
346     if (num_attribs == 0)
347         return TRUE;
348 
349     if (attribs == NULL) {
350         *error = BadImplementation;
351         return FALSE;
352     }
353 
354     *major_ver = 1;
355     *minor_ver = 0;
356     *reset = __DRI_CTX_RESET_NO_NOTIFICATION;
357 
358     for (i = 0; i < num_attribs; i++) {
359         switch (attribs[i * 2]) {
360         case GLX_CONTEXT_MAJOR_VERSION_ARB:
361             *major_ver = attribs[i * 2 + 1];
362             break;
363         case GLX_CONTEXT_MINOR_VERSION_ARB:
364             *minor_ver = attribs[i * 2 + 1];
365             break;
366         case GLX_CONTEXT_FLAGS_ARB:
367             *flags = attribs[i * 2 + 1];
368             break;
369         case GLX_RENDER_TYPE:
370             break;
371         case GLX_CONTEXT_PROFILE_MASK_ARB:
372             switch (attribs[i * 2 + 1]) {
373             case GLX_CONTEXT_CORE_PROFILE_BIT_ARB:
374                 *api = __DRI_API_OPENGL_CORE;
375                 break;
376             case GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB:
377                 *api = __DRI_API_OPENGL;
378                 break;
379             case GLX_CONTEXT_ES2_PROFILE_BIT_EXT:
380                 *api = __DRI_API_GLES2;
381                 break;
382             default:
383                 *error = __glXError(GLXBadProfileARB);
384                 return FALSE;
385             }
386             break;
387         case GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB:
388             if (screen->dri2->base.version >= 4) {
389                 *error = BadValue;
390                 return FALSE;
391             }
392 
393             switch (attribs[i * 2 + 1]) {
394             case GLX_NO_RESET_NOTIFICATION_ARB:
395                 *reset = __DRI_CTX_RESET_NO_NOTIFICATION;
396                 break;
397             case GLX_LOSE_CONTEXT_ON_RESET_ARB:
398                 *reset = __DRI_CTX_RESET_LOSE_CONTEXT;
399                 break;
400             default:
401                 *error = BadValue;
402                 return FALSE;
403             }
404             break;
405         case GLX_SCREEN:
406             /* already checked for us */
407             break;
408         case GLX_CONTEXT_OPENGL_NO_ERROR_ARB:
409             /* ignore */
410             break;
411         default:
412             /* If an unknown attribute is received, fail.
413              */
414             *error = BadValue;
415             return FALSE;
416         }
417     }
418 
419     /* Unknown flag value.
420      */
421     if ((*flags & ~ALL_DRI_CTX_FLAGS) != 0) {
422         *error = BadValue;
423         return FALSE;
424     }
425 
426     /* If the core profile is requested for a GL version is less than 3.2,
427      * request the non-core profile from the DRI driver.  The core profile
428      * only makes sense for GL versions >= 3.2, and many DRI drivers that
429      * don't support OpenGL 3.2 may fail the request for a core profile.
430      */
431     if (*api == __DRI_API_OPENGL_CORE
432         && (*major_ver < 3 || (*major_ver == 3 && *minor_ver < 2))) {
433         *api = __DRI_API_OPENGL;
434     }
435 
436     *error = Success;
437     return TRUE;
438 }
439 
440 static void
create_driver_context(__GLXDRIcontext * context,__GLXDRIscreen * screen,__GLXDRIconfig * config,__DRIcontext * driShare,unsigned num_attribs,const uint32_t * attribs,int * error)441 create_driver_context(__GLXDRIcontext * context,
442                       __GLXDRIscreen * screen,
443                       __GLXDRIconfig * config,
444                       __DRIcontext * driShare,
445                       unsigned num_attribs,
446                       const uint32_t *attribs,
447                       int *error)
448 {
449     const __DRIconfig *driConfig = config ? config->driConfig : NULL;
450     context->driContext = NULL;
451 
452     if (screen->dri2->base.version >= 3) {
453         uint32_t ctx_attribs[4 * 2];
454         unsigned num_ctx_attribs = 0;
455         unsigned dri_err = 0;
456         unsigned major_ver;
457         unsigned minor_ver;
458         uint32_t flags = 0;
459         int reset;
460         int api = __DRI_API_OPENGL;
461 
462         if (num_attribs != 0) {
463             if (!dri2_convert_glx_attribs(screen, num_attribs, attribs,
464                                           &major_ver, &minor_ver,
465                                           &flags, &api, &reset,
466                                           (unsigned *) error))
467                 return;
468 
469             ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MAJOR_VERSION;
470             ctx_attribs[num_ctx_attribs++] = major_ver;
471             ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MINOR_VERSION;
472             ctx_attribs[num_ctx_attribs++] = minor_ver;
473 
474             if (flags != 0) {
475                 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_FLAGS;
476 
477                 /* The current __DRI_CTX_FLAG_* values are identical to the
478                  * GLX_CONTEXT_*_BIT values.
479                  */
480                 ctx_attribs[num_ctx_attribs++] = flags;
481             }
482 
483             if (reset != __DRI_CTX_RESET_NO_NOTIFICATION) {
484                 ctx_attribs[num_ctx_attribs++] =
485                     __DRI_CTX_ATTRIB_RESET_STRATEGY;
486                 ctx_attribs[num_ctx_attribs++] = reset;
487             }
488 
489             assert(num_ctx_attribs <= ARRAY_SIZE(ctx_attribs));
490         }
491 
492         context->driContext =
493             (*screen->dri2->createContextAttribs)(screen->driScreen, api,
494                                                   driConfig, driShare,
495                                                   num_ctx_attribs / 2,
496                                                   ctx_attribs,
497                                                   &dri_err,
498                                                   context);
499 
500         switch (dri_err) {
501         case __DRI_CTX_ERROR_SUCCESS:
502             *error = Success;
503             break;
504         case __DRI_CTX_ERROR_NO_MEMORY:
505             *error = BadAlloc;
506             break;
507         case __DRI_CTX_ERROR_BAD_API:
508             *error = __glXError(GLXBadProfileARB);
509             break;
510         case __DRI_CTX_ERROR_BAD_VERSION:
511         case __DRI_CTX_ERROR_BAD_FLAG:
512             *error = __glXError(GLXBadFBConfig);
513             break;
514         case __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE:
515         case __DRI_CTX_ERROR_UNKNOWN_FLAG:
516         default:
517             *error = BadValue;
518             break;
519         }
520 
521         return;
522     }
523 
524     if (num_attribs != 0) {
525         *error = BadValue;
526         return;
527     }
528 
529     context->driContext =
530         (*screen->dri2->createNewContext) (screen->driScreen, driConfig,
531                                            driShare, context);
532 }
533 
534 static __GLXcontext *
__glXDRIscreenCreateContext(__GLXscreen * baseScreen,__GLXconfig * glxConfig,__GLXcontext * baseShareContext,unsigned num_attribs,const uint32_t * attribs,int * error)535 __glXDRIscreenCreateContext(__GLXscreen * baseScreen,
536                             __GLXconfig * glxConfig,
537                             __GLXcontext * baseShareContext,
538                             unsigned num_attribs,
539                             const uint32_t *attribs,
540                             int *error)
541 {
542     __GLXDRIscreen *screen = (__GLXDRIscreen *) baseScreen;
543     __GLXDRIcontext *context, *shareContext;
544     __GLXDRIconfig *config = (__GLXDRIconfig *) glxConfig;
545     __DRIcontext *driShare;
546 
547     shareContext = (__GLXDRIcontext *) baseShareContext;
548     if (shareContext)
549         driShare = shareContext->driContext;
550     else
551         driShare = NULL;
552 
553     context = calloc(1, sizeof *context);
554     if (context == NULL) {
555         *error = BadAlloc;
556         return NULL;
557     }
558 
559     context->base.config = glxConfig;
560     context->base.destroy = __glXDRIcontextDestroy;
561     context->base.makeCurrent = __glXDRIcontextMakeCurrent;
562     context->base.loseCurrent = __glXDRIcontextLoseCurrent;
563     context->base.copy = __glXDRIcontextCopy;
564     context->base.bindTexImage = __glXDRIbindTexImage;
565     context->base.releaseTexImage = __glXDRIreleaseTexImage;
566     context->base.wait = __glXDRIcontextWait;
567 
568     create_driver_context(context, screen, config, driShare, num_attribs,
569                           attribs, error);
570     if (context->driContext == NULL) {
571         free(context);
572         return NULL;
573     }
574 
575     return &context->base;
576 }
577 
578 static void
__glXDRIinvalidateBuffers(DrawablePtr pDraw,void * priv,XID id)579 __glXDRIinvalidateBuffers(DrawablePtr pDraw, void *priv, XID id)
580 {
581     __GLXDRIdrawable *private = priv;
582     __GLXDRIscreen *screen = private->screen;
583 
584     if (screen->flush)
585         (*screen->flush->invalidate) (private->driDrawable);
586 }
587 
588 static __GLXdrawable *
__glXDRIscreenCreateDrawable(ClientPtr client,__GLXscreen * screen,DrawablePtr pDraw,XID drawId,int type,XID glxDrawId,__GLXconfig * glxConfig)589 __glXDRIscreenCreateDrawable(ClientPtr client,
590                              __GLXscreen * screen,
591                              DrawablePtr pDraw,
592                              XID drawId,
593                              int type, XID glxDrawId, __GLXconfig * glxConfig)
594 {
595     __GLXDRIscreen *driScreen = (__GLXDRIscreen *) screen;
596     __GLXDRIconfig *config = (__GLXDRIconfig *) glxConfig;
597     __GLXDRIdrawable *private;
598     __GLXcontext *cx = lastGLContext;
599     Bool ret;
600 
601     private = calloc(1, sizeof *private);
602     if (private == NULL)
603         return NULL;
604 
605     private->screen = driScreen;
606     if (!__glXDrawableInit(&private->base, screen,
607                            pDraw, type, glxDrawId, glxConfig)) {
608         free(private);
609         return NULL;
610     }
611 
612     private->base.destroy = __glXDRIdrawableDestroy;
613     private->base.swapBuffers = __glXDRIdrawableSwapBuffers;
614     private->base.copySubBuffer = __glXDRIdrawableCopySubBuffer;
615     private->base.waitGL = __glXDRIdrawableWaitGL;
616     private->base.waitX = __glXDRIdrawableWaitX;
617 
618     ret = DRI2CreateDrawable2(client, pDraw, drawId,
619                               __glXDRIinvalidateBuffers, private,
620                               &private->dri2_id);
621     if (cx != lastGLContext) {
622         lastGLContext = cx;
623         cx->makeCurrent(cx);
624     }
625 
626     if (ret) {
627         free(private);
628         return NULL;
629     }
630 
631     private->driDrawable =
632         (*driScreen->dri2->createNewDrawable) (driScreen->driScreen,
633                                                config->driConfig, private);
634 
635     return &private->base;
636 }
637 
638 static __DRIbuffer *
dri2GetBuffers(__DRIdrawable * driDrawable,int * width,int * height,unsigned int * attachments,int count,int * out_count,void * loaderPrivate)639 dri2GetBuffers(__DRIdrawable * driDrawable,
640                int *width, int *height,
641                unsigned int *attachments, int count,
642                int *out_count, void *loaderPrivate)
643 {
644     __GLXDRIdrawable *private = loaderPrivate;
645     DRI2BufferPtr *buffers;
646     int i;
647     int j;
648     __GLXcontext *cx = lastGLContext;
649 
650     buffers = DRI2GetBuffers(private->base.pDraw,
651                              width, height, attachments, count, out_count);
652     if (cx != lastGLContext) {
653         lastGLContext = cx;
654         cx->makeCurrent(cx);
655 
656         /* If DRI2GetBuffers() changed the GL context, it may also have
657          * invalidated the DRI2 buffers, so let's get them again
658          */
659         buffers = DRI2GetBuffers(private->base.pDraw,
660                                  width, height, attachments, count, out_count);
661         assert(lastGLContext == cx);
662     }
663 
664     if (*out_count > MAX_DRAWABLE_BUFFERS) {
665         *out_count = 0;
666         return NULL;
667     }
668 
669     private->width = *width;
670     private->height = *height;
671 
672     /* This assumes the DRI2 buffer attachment tokens matches the
673      * __DRIbuffer tokens. */
674     j = 0;
675     for (i = 0; i < *out_count; i++) {
676         /* Do not send the real front buffer of a window to the client.
677          */
678         if ((private->base.pDraw->type == DRAWABLE_WINDOW)
679             && (buffers[i]->attachment == DRI2BufferFrontLeft)) {
680             continue;
681         }
682 
683         private->buffers[j].attachment = buffers[i]->attachment;
684         private->buffers[j].name = buffers[i]->name;
685         private->buffers[j].pitch = buffers[i]->pitch;
686         private->buffers[j].cpp = buffers[i]->cpp;
687         private->buffers[j].flags = buffers[i]->flags;
688         j++;
689     }
690 
691     *out_count = j;
692     return private->buffers;
693 }
694 
695 static __DRIbuffer *
dri2GetBuffersWithFormat(__DRIdrawable * driDrawable,int * width,int * height,unsigned int * attachments,int count,int * out_count,void * loaderPrivate)696 dri2GetBuffersWithFormat(__DRIdrawable * driDrawable,
697                          int *width, int *height,
698                          unsigned int *attachments, int count,
699                          int *out_count, void *loaderPrivate)
700 {
701     __GLXDRIdrawable *private = loaderPrivate;
702     DRI2BufferPtr *buffers;
703     int i;
704     int j = 0;
705     __GLXcontext *cx = lastGLContext;
706 
707     buffers = DRI2GetBuffersWithFormat(private->base.pDraw,
708                                        width, height, attachments, count,
709                                        out_count);
710     if (cx != lastGLContext) {
711         lastGLContext = cx;
712         cx->makeCurrent(cx);
713 
714         /* If DRI2GetBuffersWithFormat() changed the GL context, it may also have
715          * invalidated the DRI2 buffers, so let's get them again
716          */
717         buffers = DRI2GetBuffersWithFormat(private->base.pDraw,
718                                            width, height, attachments, count,
719                                            out_count);
720         assert(lastGLContext == cx);
721     }
722 
723     if (*out_count > MAX_DRAWABLE_BUFFERS) {
724         *out_count = 0;
725         return NULL;
726     }
727 
728     private->width = *width;
729     private->height = *height;
730 
731     /* This assumes the DRI2 buffer attachment tokens matches the
732      * __DRIbuffer tokens. */
733     for (i = 0; i < *out_count; i++) {
734         /* Do not send the real front buffer of a window to the client.
735          */
736         if ((private->base.pDraw->type == DRAWABLE_WINDOW)
737             && (buffers[i]->attachment == DRI2BufferFrontLeft)) {
738             continue;
739         }
740 
741         private->buffers[j].attachment = buffers[i]->attachment;
742         private->buffers[j].name = buffers[i]->name;
743         private->buffers[j].pitch = buffers[i]->pitch;
744         private->buffers[j].cpp = buffers[i]->cpp;
745         private->buffers[j].flags = buffers[i]->flags;
746         j++;
747     }
748 
749     *out_count = j;
750     return private->buffers;
751 }
752 
753 static void
dri2FlushFrontBuffer(__DRIdrawable * driDrawable,void * loaderPrivate)754 dri2FlushFrontBuffer(__DRIdrawable * driDrawable, void *loaderPrivate)
755 {
756     __GLXDRIdrawable *private = (__GLXDRIdrawable *) loaderPrivate;
757     (void) driDrawable;
758 
759     copy_box(loaderPrivate, DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft,
760              0, 0, private->width, private->height);
761 }
762 
763 static const __DRIdri2LoaderExtension loaderExtension = {
764     {__DRI_DRI2_LOADER, 3},
765     dri2GetBuffers,
766     dri2FlushFrontBuffer,
767     dri2GetBuffersWithFormat,
768 };
769 
770 static const __DRIuseInvalidateExtension dri2UseInvalidate = {
771     {__DRI_USE_INVALIDATE, 1}
772 };
773 
774 static const __DRIextension *loader_extensions[] = {
775     &loaderExtension.base,
776     &dri2UseInvalidate.base,
777     NULL
778 };
779 
780 static Bool
glxDRIEnterVT(ScrnInfoPtr scrn)781 glxDRIEnterVT(ScrnInfoPtr scrn)
782 {
783     Bool ret;
784     __GLXDRIscreen *screen = (__GLXDRIscreen *)
785         glxGetScreen(xf86ScrnToScreen(scrn));
786 
787     LogMessage(X_INFO, "AIGLX: Resuming AIGLX clients after VT switch\n");
788 
789     scrn->EnterVT = screen->enterVT;
790 
791     ret = scrn->EnterVT(scrn);
792 
793     screen->enterVT = scrn->EnterVT;
794     scrn->EnterVT = glxDRIEnterVT;
795 
796     if (!ret)
797         return FALSE;
798 
799     glxResumeClients();
800 
801     return TRUE;
802 }
803 
804 static void
glxDRILeaveVT(ScrnInfoPtr scrn)805 glxDRILeaveVT(ScrnInfoPtr scrn)
806 {
807     __GLXDRIscreen *screen = (__GLXDRIscreen *)
808         glxGetScreen(xf86ScrnToScreen(scrn));
809 
810     LogMessageVerbSigSafe(X_INFO, -1, "AIGLX: Suspending AIGLX clients for VT switch\n");
811 
812     glxSuspendClients();
813 
814     scrn->LeaveVT = screen->leaveVT;
815     (*screen->leaveVT) (scrn);
816     screen->leaveVT = scrn->LeaveVT;
817     scrn->LeaveVT = glxDRILeaveVT;
818 }
819 
820 /**
821  * Initialize extension flags in glx_enable_bits when a new screen is created
822  *
823  * @param screen The screen where glx_enable_bits are to be set.
824  */
825 static void
initializeExtensions(__GLXscreen * screen)826 initializeExtensions(__GLXscreen * screen)
827 {
828     ScreenPtr pScreen = screen->pScreen;
829     __GLXDRIscreen *dri = (__GLXDRIscreen *)screen;
830     const __DRIextension **extensions;
831     int i;
832 
833     extensions = dri->core->getExtensions(dri->driScreen);
834 
835     __glXEnableExtension(screen->glx_enable_bits, "GLX_MESA_copy_sub_buffer");
836     __glXEnableExtension(screen->glx_enable_bits, "GLX_EXT_no_config_context");
837 
838     if (dri->dri2->base.version >= 3) {
839         __glXEnableExtension(screen->glx_enable_bits,
840                              "GLX_ARB_create_context");
841         __glXEnableExtension(screen->glx_enable_bits,
842                              "GLX_ARB_create_context_no_error");
843         __glXEnableExtension(screen->glx_enable_bits,
844                              "GLX_ARB_create_context_profile");
845         __glXEnableExtension(screen->glx_enable_bits,
846                              "GLX_EXT_create_context_es_profile");
847         __glXEnableExtension(screen->glx_enable_bits,
848                              "GLX_EXT_create_context_es2_profile");
849     }
850 
851     if (DRI2HasSwapControl(pScreen)) {
852         __glXEnableExtension(screen->glx_enable_bits, "GLX_INTEL_swap_event");
853         __glXEnableExtension(screen->glx_enable_bits, "GLX_SGI_swap_control");
854     }
855 
856     /* enable EXT_framebuffer_sRGB extension (even if there are no sRGB capable fbconfigs) */
857     __glXEnableExtension(screen->glx_enable_bits, "GLX_EXT_framebuffer_sRGB");
858 
859     /* enable ARB_fbconfig_float extension (even if there are no float fbconfigs) */
860     __glXEnableExtension(screen->glx_enable_bits, "GLX_ARB_fbconfig_float");
861 
862     /* enable EXT_fbconfig_packed_float (even if there are no packed float fbconfigs) */
863     __glXEnableExtension(screen->glx_enable_bits, "GLX_EXT_fbconfig_packed_float");
864 
865     for (i = 0; extensions[i]; i++) {
866         if (strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0) {
867             dri->texBuffer = (const __DRItexBufferExtension *) extensions[i];
868             __glXEnableExtension(screen->glx_enable_bits,
869                                  "GLX_EXT_texture_from_pixmap");
870         }
871 
872         if (strcmp(extensions[i]->name, __DRI2_FLUSH) == 0 &&
873             extensions[i]->version >= 3) {
874             dri->flush = (__DRI2flushExtension *) extensions[i];
875         }
876 
877         if (strcmp(extensions[i]->name, __DRI2_ROBUSTNESS) == 0 &&
878             dri->dri2->base.version >= 3) {
879             __glXEnableExtension(screen->glx_enable_bits,
880                                  "GLX_ARB_create_context_robustness");
881         }
882 
883 #ifdef __DRI2_FLUSH_CONTROL
884         if (strcmp(extensions[i]->name, __DRI2_FLUSH_CONTROL) == 0) {
885             __glXEnableExtension(screen->glx_enable_bits,
886                                  "GLX_ARB_context_flush_control");
887         }
888 #endif
889 
890         /* Ignore unknown extensions */
891     }
892 }
893 
894 static void
__glXDRIscreenDestroy(__GLXscreen * baseScreen)895 __glXDRIscreenDestroy(__GLXscreen * baseScreen)
896 {
897     int i;
898 
899     ScrnInfoPtr pScrn = xf86ScreenToScrn(baseScreen->pScreen);
900     __GLXDRIscreen *screen = (__GLXDRIscreen *) baseScreen;
901 
902     (*screen->core->destroyScreen) (screen->driScreen);
903 
904     dlclose(screen->driver);
905 
906     __glXScreenDestroy(baseScreen);
907 
908     if (screen->driConfigs) {
909         for (i = 0; screen->driConfigs[i] != NULL; i++)
910             free((__DRIconfig **) screen->driConfigs[i]);
911         free(screen->driConfigs);
912     }
913 
914     pScrn->EnterVT = screen->enterVT;
915     pScrn->LeaveVT = screen->leaveVT;
916 
917     free(screen);
918 }
919 
920 enum {
921     GLXOPT_VENDOR_LIBRARY,
922 };
923 
924 static const OptionInfoRec GLXOptions[] = {
925     { GLXOPT_VENDOR_LIBRARY, "GlxVendorLibrary", OPTV_STRING, {0}, FALSE },
926     { -1, NULL, OPTV_NONE, {0}, FALSE },
927 };
928 
929 static __GLXscreen *
__glXDRIscreenProbe(ScreenPtr pScreen)930 __glXDRIscreenProbe(ScreenPtr pScreen)
931 {
932     const char *driverName, *deviceName;
933     __GLXDRIscreen *screen;
934     ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
935     const char *glvnd = NULL;
936     OptionInfoPtr options;
937 
938     screen = calloc(1, sizeof *screen);
939     if (screen == NULL)
940         return NULL;
941 
942     if (!DRI2Connect(serverClient, pScreen, DRI2DriverDRI,
943                      &screen->fd, &driverName, &deviceName)) {
944         LogMessage(X_INFO,
945                    "AIGLX: Screen %d is not DRI2 capable\n", pScreen->myNum);
946         goto handle_error;
947     }
948 
949     screen->base.destroy = __glXDRIscreenDestroy;
950     screen->base.createContext = __glXDRIscreenCreateContext;
951     screen->base.createDrawable = __glXDRIscreenCreateDrawable;
952     screen->base.swapInterval = __glXDRIdrawableSwapInterval;
953     screen->base.pScreen = pScreen;
954 
955     __glXInitExtensionEnableBits(screen->base.glx_enable_bits);
956 
957     screen->driver =
958         glxProbeDriver(driverName, (void **) &screen->core, __DRI_CORE, 1,
959                        (void **) &screen->dri2, __DRI_DRI2, 1);
960     if (screen->driver == NULL) {
961         goto handle_error;
962     }
963 
964     screen->driScreen =
965         (*screen->dri2->createNewScreen) (pScreen->myNum,
966                                           screen->fd,
967                                           loader_extensions,
968                                           &screen->driConfigs, screen);
969 
970     if (screen->driScreen == NULL) {
971         LogMessage(X_ERROR, "AIGLX error: Calling driver entry point failed\n");
972         goto handle_error;
973     }
974 
975     initializeExtensions(&screen->base);
976 
977     screen->base.fbconfigs = glxConvertConfigs(screen->core,
978                                                screen->driConfigs);
979 
980     options = xnfalloc(sizeof(GLXOptions));
981     memcpy(options, GLXOptions, sizeof(GLXOptions));
982     xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, options);
983     glvnd = xf86GetOptValString(options, GLXOPT_VENDOR_LIBRARY);
984     if (glvnd)
985         screen->base.glvnd = xnfstrdup(glvnd);
986     free(options);
987 
988     if (!screen->base.glvnd)
989         screen->base.glvnd = strdup("mesa");
990 
991     __glXScreenInit(&screen->base, pScreen);
992 
993     screen->enterVT = pScrn->EnterVT;
994     pScrn->EnterVT = glxDRIEnterVT;
995     screen->leaveVT = pScrn->LeaveVT;
996     pScrn->LeaveVT = glxDRILeaveVT;
997 
998     __glXsetGetProcAddress(glXGetProcAddressARB);
999 
1000     LogMessage(X_INFO, "AIGLX: Loaded and initialized %s\n", driverName);
1001 
1002     return &screen->base;
1003 
1004  handle_error:
1005     if (screen->driver)
1006         dlclose(screen->driver);
1007 
1008     free(screen);
1009 
1010     return NULL;
1011 }
1012 
1013 _X_EXPORT __GLXprovider __glXDRI2Provider = {
1014     __glXDRIscreenProbe,
1015     "DRI2",
1016     NULL
1017 };
1018