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
52typedef struct __GLXDRIscreen __GLXDRIscreen;
53typedef struct __GLXDRIcontext __GLXDRIcontext;
54typedef 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
60struct __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
78struct __GLXDRIcontext {
79    __GLXcontext base;
80    __DRIcontext *driContext;
81};
82
83#define MAX_DRAWABLE_BUFFERS 5
84
85struct __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
98static void
99copy_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 */
121extern glx_func_ptr glXGetProcAddressARB(const char *);
122
123static void
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
138static void
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
149static void
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
158static void
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
167static void
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 */
199static GLboolean
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
223static int
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
240static void
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
251static int
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
263static int
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
272static int
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
284static Bool
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
305static int
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
330static int
331__glXDRIreleaseTexImage(__GLXcontext * baseContext,
332                        int buffer, __GLXdrawable * pixmap)
333{
334    /* FIXME: Just unbind the texture? */
335    return Success;
336}
337
338static Bool
339dri2_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
440static void
441create_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
534static __GLXcontext *
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
578static void
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
588static __GLXdrawable *
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
638static __DRIbuffer *
639dri2GetBuffers(__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
695static __DRIbuffer *
696dri2GetBuffersWithFormat(__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
753static void
754dri2FlushFrontBuffer(__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
763static const __DRIdri2LoaderExtension loaderExtension = {
764    {__DRI_DRI2_LOADER, 3},
765    dri2GetBuffers,
766    dri2FlushFrontBuffer,
767    dri2GetBuffersWithFormat,
768};
769
770static const __DRIuseInvalidateExtension dri2UseInvalidate = {
771    {__DRI_USE_INVALIDATE, 1}
772};
773
774static const __DRIextension *loader_extensions[] = {
775    &loaderExtension.base,
776    &dri2UseInvalidate.base,
777    NULL
778};
779
780static Bool
781glxDRIEnterVT(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
804static void
805glxDRILeaveVT(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 */
825static void
826initializeExtensions(__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
894static void
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
920enum {
921    GLXOPT_VENDOR_LIBRARY,
922};
923
924static const OptionInfoRec GLXOptions[] = {
925    { GLXOPT_VENDOR_LIBRARY, "GlxVendorLibrary", OPTV_STRING, {0}, FALSE },
926    { -1, NULL, OPTV_NONE, {0}, FALSE },
927};
928
929static __GLXscreen *
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