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