1706f2543Smrg/*
2706f2543Smrg * Copyright © 2007 Red Hat, Inc
3706f2543Smrg *
4706f2543Smrg * Permission to use, copy, modify, distribute, and sell this software
5706f2543Smrg * and its documentation for any purpose is hereby granted without
6706f2543Smrg * fee, provided that the above copyright notice appear in all copies
7706f2543Smrg * and that both that copyright notice and this permission notice
8706f2543Smrg * appear in supporting documentation, and that the name of Red Hat,
9706f2543Smrg * Inc not be used in advertising or publicity pertaining to
10706f2543Smrg * distribution of the software without specific, written prior
11706f2543Smrg * permission.  Red Hat, Inc makes no representations about the
12706f2543Smrg * suitability of this software for any purpose.  It is provided "as
13706f2543Smrg * is" without express or implied warranty.
14706f2543Smrg *
15706f2543Smrg * RED HAT, INC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16706f2543Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
17706f2543Smrg * NO EVENT SHALL RED HAT, INC BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18706f2543Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
19706f2543Smrg * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
20706f2543Smrg * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21706f2543Smrg * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22706f2543Smrg */
23706f2543Smrg
24706f2543Smrg#ifdef HAVE_DIX_CONFIG_H
25706f2543Smrg#include <dix-config.h>
26706f2543Smrg#endif
27706f2543Smrg
28706f2543Smrg#include <stdint.h>
29706f2543Smrg#include <stdio.h>
30706f2543Smrg#include <string.h>
31706f2543Smrg#include <errno.h>
32706f2543Smrg#include <dlfcn.h>
33706f2543Smrg
34706f2543Smrg#include <drm.h>
35706f2543Smrg#include <GL/gl.h>
36706f2543Smrg#include <GL/internal/dri_interface.h>
37706f2543Smrg#include <GL/glxtokens.h>
38706f2543Smrg
39706f2543Smrg#include <windowstr.h>
40706f2543Smrg#include <os.h>
41706f2543Smrg
42706f2543Smrg#define _XF86DRI_SERVER_
43706f2543Smrg#include <xf86drm.h>
44706f2543Smrg#include <xf86.h>
45706f2543Smrg#include <dri2.h>
46706f2543Smrg
47706f2543Smrg#include "glxserver.h"
48706f2543Smrg#include "glxutil.h"
49706f2543Smrg#include "glxdricommon.h"
50706f2543Smrg
51706f2543Smrg#include "glapitable.h"
52706f2543Smrg#include "glapi.h"
53706f2543Smrg#include "glthread.h"
54706f2543Smrg#include "dispatch.h"
55706f2543Smrg#include "extension_string.h"
56706f2543Smrg
57706f2543Smrgtypedef struct __GLXDRIscreen   __GLXDRIscreen;
58706f2543Smrgtypedef struct __GLXDRIcontext  __GLXDRIcontext;
59706f2543Smrgtypedef struct __GLXDRIdrawable __GLXDRIdrawable;
60706f2543Smrg
61706f2543Smrgstruct __GLXDRIscreen {
62706f2543Smrg    __GLXscreen		 base;
63706f2543Smrg    __DRIscreen		*driScreen;
64706f2543Smrg    void		*driver;
65706f2543Smrg    int			 fd;
66706f2543Smrg
67706f2543Smrg    xf86EnterVTProc	*enterVT;
68706f2543Smrg    xf86LeaveVTProc	*leaveVT;
69706f2543Smrg
70706f2543Smrg    const __DRIcoreExtension *core;
71706f2543Smrg    const __DRIdri2Extension *dri2;
72706f2543Smrg    const __DRI2flushExtension *flush;
73706f2543Smrg    const __DRIcopySubBufferExtension *copySubBuffer;
74706f2543Smrg    const __DRIswapControlExtension *swapControl;
75706f2543Smrg    const __DRItexBufferExtension *texBuffer;
76706f2543Smrg
77706f2543Smrg    unsigned char glx_enable_bits[__GLX_EXT_BYTES];
78706f2543Smrg};
79706f2543Smrg
80706f2543Smrgstruct __GLXDRIcontext {
81706f2543Smrg    __GLXcontext	 base;
82706f2543Smrg    __DRIcontext	*driContext;
83706f2543Smrg};
84706f2543Smrg
85706f2543Smrg#define MAX_DRAWABLE_BUFFERS 5
86706f2543Smrg
87706f2543Smrgstruct __GLXDRIdrawable {
88706f2543Smrg    __GLXdrawable	 base;
89706f2543Smrg    __DRIdrawable	*driDrawable;
90706f2543Smrg    __GLXDRIscreen	*screen;
91706f2543Smrg
92706f2543Smrg    /* Dimensions as last reported by DRI2GetBuffers. */
93706f2543Smrg    int width;
94706f2543Smrg    int height;
95706f2543Smrg    __DRIbuffer buffers[MAX_DRAWABLE_BUFFERS];
96706f2543Smrg    int count;
97706f2543Smrg};
98706f2543Smrg
99706f2543Smrgstatic void
100706f2543Smrg__glXDRIdrawableDestroy(__GLXdrawable *drawable)
101706f2543Smrg{
102706f2543Smrg    __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable;
103706f2543Smrg    const __DRIcoreExtension *core = private->screen->core;
104706f2543Smrg
105706f2543Smrg    (*core->destroyDrawable)(private->driDrawable);
106706f2543Smrg
107706f2543Smrg    __glXDrawableRelease(drawable);
108706f2543Smrg
109706f2543Smrg    free(private);
110706f2543Smrg}
111706f2543Smrg
112706f2543Smrgstatic void
113706f2543Smrg__glXDRIdrawableCopySubBuffer(__GLXdrawable *drawable,
114706f2543Smrg			       int x, int y, int w, int h)
115706f2543Smrg{
116706f2543Smrg    __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable;
117706f2543Smrg    BoxRec box;
118706f2543Smrg    RegionRec region;
119706f2543Smrg
120706f2543Smrg    box.x1 = x;
121706f2543Smrg    box.y1 = private->height - y - h;
122706f2543Smrg    box.x2 = x + w;
123706f2543Smrg    box.y2 = private->height - y;
124706f2543Smrg    RegionInit(&region, &box, 0);
125706f2543Smrg
126706f2543Smrg    DRI2CopyRegion(drawable->pDraw, &region,
127706f2543Smrg		   DRI2BufferFrontLeft, DRI2BufferBackLeft);
128706f2543Smrg}
129706f2543Smrg
130706f2543Smrgstatic void
131706f2543Smrg__glXDRIdrawableWaitX(__GLXdrawable *drawable)
132706f2543Smrg{
133706f2543Smrg    __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable;
134706f2543Smrg    BoxRec box;
135706f2543Smrg    RegionRec region;
136706f2543Smrg
137706f2543Smrg    box.x1 = 0;
138706f2543Smrg    box.y1 = 0;
139706f2543Smrg    box.x2 = private->width;
140706f2543Smrg    box.y2 = private->height;
141706f2543Smrg    RegionInit(&region, &box, 0);
142706f2543Smrg
143706f2543Smrg    DRI2CopyRegion(drawable->pDraw, &region,
144706f2543Smrg		   DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft);
145706f2543Smrg}
146706f2543Smrg
147706f2543Smrgstatic void
148706f2543Smrg__glXDRIdrawableWaitGL(__GLXdrawable *drawable)
149706f2543Smrg{
150706f2543Smrg    __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable;
151706f2543Smrg    BoxRec box;
152706f2543Smrg    RegionRec region;
153706f2543Smrg
154706f2543Smrg    box.x1 = 0;
155706f2543Smrg    box.y1 = 0;
156706f2543Smrg    box.x2 = private->width;
157706f2543Smrg    box.y2 = private->height;
158706f2543Smrg    RegionInit(&region, &box, 0);
159706f2543Smrg
160706f2543Smrg    DRI2CopyRegion(drawable->pDraw, &region,
161706f2543Smrg		   DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft);
162706f2543Smrg}
163706f2543Smrg
164706f2543Smrgstatic void
165706f2543Smrg__glXdriSwapEvent(ClientPtr client, void *data, int type, CARD64 ust,
166706f2543Smrg		  CARD64 msc, CARD64 sbc)
167706f2543Smrg{
168706f2543Smrg    __GLXdrawable *drawable = data;
169706f2543Smrg    xGLXBufferSwapComplete wire;
170706f2543Smrg
171706f2543Smrg    if (!(drawable->eventMask & GLX_BUFFER_SWAP_COMPLETE_INTEL_MASK))
172706f2543Smrg	return;
173706f2543Smrg
174706f2543Smrg    wire.type = __glXEventBase + GLX_BufferSwapComplete;
175706f2543Smrg    switch (type) {
176706f2543Smrg    case DRI2_EXCHANGE_COMPLETE:
177706f2543Smrg	wire.event_type = GLX_EXCHANGE_COMPLETE_INTEL;
178706f2543Smrg	break;
179706f2543Smrg    case DRI2_BLIT_COMPLETE:
180706f2543Smrg	wire.event_type = GLX_BLIT_COMPLETE_INTEL;
181706f2543Smrg	break;
182706f2543Smrg    case DRI2_FLIP_COMPLETE:
183706f2543Smrg	wire.event_type = GLX_FLIP_COMPLETE_INTEL;
184706f2543Smrg	break;
185706f2543Smrg    default:
186706f2543Smrg	/* unknown swap completion type */
187706f2543Smrg	wire.event_type = 0;
188706f2543Smrg	break;
189706f2543Smrg    }
190706f2543Smrg    wire.drawable = drawable->drawId;
191706f2543Smrg    wire.ust_hi = ust >> 32;
192706f2543Smrg    wire.ust_lo = ust & 0xffffffff;
193706f2543Smrg    wire.msc_hi = msc >> 32;
194706f2543Smrg    wire.msc_lo = msc & 0xffffffff;
195706f2543Smrg    wire.sbc_hi = sbc >> 32;
196706f2543Smrg    wire.sbc_lo = sbc & 0xffffffff;
197706f2543Smrg
198706f2543Smrg    WriteEventsToClient(client, 1, (xEvent *) &wire);
199706f2543Smrg}
200706f2543Smrg
201706f2543Smrg/*
202706f2543Smrg * Copy or flip back to front, honoring the swap interval if possible.
203706f2543Smrg *
204706f2543Smrg * If the kernel supports it, we request an event for the frame when the
205706f2543Smrg * swap should happen, then perform the copy when we receive it.
206706f2543Smrg */
207706f2543Smrgstatic GLboolean
208706f2543Smrg__glXDRIdrawableSwapBuffers(ClientPtr client, __GLXdrawable *drawable)
209706f2543Smrg{
210706f2543Smrg    __GLXDRIdrawable *priv = (__GLXDRIdrawable *) drawable;
211706f2543Smrg    __GLXDRIscreen *screen = priv->screen;
212706f2543Smrg    CARD64 unused;
213706f2543Smrg
214706f2543Smrg#if __DRI2_FLUSH_VERSION >= 3
215706f2543Smrg    if (screen->flush) {
216706f2543Smrg	(*screen->flush->flush)(priv->driDrawable);
217706f2543Smrg	(*screen->flush->invalidate)(priv->driDrawable);
218706f2543Smrg    }
219706f2543Smrg#else
220706f2543Smrg    if (screen->flush)
221706f2543Smrg	(*screen->flush->flushInvalidate)(priv->driDrawable);
222706f2543Smrg#endif
223706f2543Smrg
224706f2543Smrg    if (DRI2SwapBuffers(client, drawable->pDraw, 0, 0, 0, &unused,
225706f2543Smrg			__glXdriSwapEvent, drawable->pDraw) != Success)
226706f2543Smrg	return FALSE;
227706f2543Smrg
228706f2543Smrg    return TRUE;
229706f2543Smrg}
230706f2543Smrg
231706f2543Smrgstatic int
232706f2543Smrg__glXDRIdrawableSwapInterval(__GLXdrawable *drawable, int interval)
233706f2543Smrg{
234706f2543Smrg    if (interval <= 0) /* || interval > BIGNUM? */
235706f2543Smrg	return GLX_BAD_VALUE;
236706f2543Smrg
237706f2543Smrg    DRI2SwapInterval(drawable->pDraw, interval);
238706f2543Smrg
239706f2543Smrg    return 0;
240706f2543Smrg}
241706f2543Smrg
242706f2543Smrgstatic void
243706f2543Smrg__glXDRIcontextDestroy(__GLXcontext *baseContext)
244706f2543Smrg{
245706f2543Smrg    __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext;
246706f2543Smrg    __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen;
247706f2543Smrg
248706f2543Smrg    (*screen->core->destroyContext)(context->driContext);
249706f2543Smrg    __glXContextDestroy(&context->base);
250706f2543Smrg    free(context);
251706f2543Smrg}
252706f2543Smrg
253706f2543Smrgstatic int
254706f2543Smrg__glXDRIcontextMakeCurrent(__GLXcontext *baseContext)
255706f2543Smrg{
256706f2543Smrg    __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext;
257706f2543Smrg    __GLXDRIdrawable *draw = (__GLXDRIdrawable *) baseContext->drawPriv;
258706f2543Smrg    __GLXDRIdrawable *read = (__GLXDRIdrawable *) baseContext->readPriv;
259706f2543Smrg    __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen;
260706f2543Smrg
261706f2543Smrg    return (*screen->core->bindContext)(context->driContext,
262706f2543Smrg					draw->driDrawable,
263706f2543Smrg					read->driDrawable);
264706f2543Smrg}
265706f2543Smrg
266706f2543Smrgstatic int
267706f2543Smrg__glXDRIcontextLoseCurrent(__GLXcontext *baseContext)
268706f2543Smrg{
269706f2543Smrg    __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext;
270706f2543Smrg    __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen;
271706f2543Smrg
272706f2543Smrg    return (*screen->core->unbindContext)(context->driContext);
273706f2543Smrg}
274706f2543Smrg
275706f2543Smrgstatic int
276706f2543Smrg__glXDRIcontextCopy(__GLXcontext *baseDst, __GLXcontext *baseSrc,
277706f2543Smrg		    unsigned long mask)
278706f2543Smrg{
279706f2543Smrg    __GLXDRIcontext *dst = (__GLXDRIcontext *) baseDst;
280706f2543Smrg    __GLXDRIcontext *src = (__GLXDRIcontext *) baseSrc;
281706f2543Smrg    __GLXDRIscreen *screen = (__GLXDRIscreen *) dst->base.pGlxScreen;
282706f2543Smrg
283706f2543Smrg    return (*screen->core->copyContext)(dst->driContext,
284706f2543Smrg					src->driContext, mask);
285706f2543Smrg}
286706f2543Smrg
287706f2543Smrgstatic int
288706f2543Smrg__glXDRIcontextForceCurrent(__GLXcontext *baseContext)
289706f2543Smrg{
290706f2543Smrg    __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext;
291706f2543Smrg    __GLXDRIdrawable *draw = (__GLXDRIdrawable *) baseContext->drawPriv;
292706f2543Smrg    __GLXDRIdrawable *read = (__GLXDRIdrawable *) baseContext->readPriv;
293706f2543Smrg    __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen;
294706f2543Smrg
295706f2543Smrg    return (*screen->core->bindContext)(context->driContext,
296706f2543Smrg					draw->driDrawable,
297706f2543Smrg					read->driDrawable);
298706f2543Smrg}
299706f2543Smrg
300706f2543Smrgstatic Bool
301706f2543Smrg__glXDRIcontextWait(__GLXcontext *baseContext,
302706f2543Smrg		    __GLXclientState *cl, int *error)
303706f2543Smrg{
304706f2543Smrg    if (DRI2WaitSwap(cl->client, baseContext->drawPriv->pDraw)) {
305706f2543Smrg	*error = cl->client->noClientException;
306706f2543Smrg	return TRUE;
307706f2543Smrg    }
308706f2543Smrg
309706f2543Smrg    return FALSE;
310706f2543Smrg}
311706f2543Smrg
312706f2543Smrg#ifdef __DRI_TEX_BUFFER
313706f2543Smrg
314706f2543Smrgstatic int
315706f2543Smrg__glXDRIbindTexImage(__GLXcontext *baseContext,
316706f2543Smrg		     int buffer,
317706f2543Smrg		     __GLXdrawable *glxPixmap)
318706f2543Smrg{
319706f2543Smrg    __GLXDRIdrawable *drawable = (__GLXDRIdrawable *) glxPixmap;
320706f2543Smrg    const __DRItexBufferExtension *texBuffer = drawable->screen->texBuffer;
321706f2543Smrg    __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext;
322706f2543Smrg
323706f2543Smrg    if (texBuffer == NULL)
324706f2543Smrg        return Success;
325706f2543Smrg
326706f2543Smrg#if __DRI_TEX_BUFFER_VERSION >= 2
327706f2543Smrg    if (texBuffer->base.version >= 2 && texBuffer->setTexBuffer2 != NULL) {
328706f2543Smrg	(*texBuffer->setTexBuffer2)(context->driContext,
329706f2543Smrg				    glxPixmap->target,
330706f2543Smrg				    glxPixmap->format,
331706f2543Smrg				    drawable->driDrawable);
332706f2543Smrg    } else
333706f2543Smrg#endif
334706f2543Smrg    {
335706f2543Smrg	texBuffer->setTexBuffer(context->driContext,
336706f2543Smrg				glxPixmap->target,
337706f2543Smrg				drawable->driDrawable);
338706f2543Smrg    }
339706f2543Smrg
340706f2543Smrg    return Success;
341706f2543Smrg}
342706f2543Smrg
343706f2543Smrgstatic int
344706f2543Smrg__glXDRIreleaseTexImage(__GLXcontext *baseContext,
345706f2543Smrg			int buffer,
346706f2543Smrg			__GLXdrawable *pixmap)
347706f2543Smrg{
348706f2543Smrg    /* FIXME: Just unbind the texture? */
349706f2543Smrg    return Success;
350706f2543Smrg}
351706f2543Smrg
352706f2543Smrg#else
353706f2543Smrg
354706f2543Smrgstatic int
355706f2543Smrg__glXDRIbindTexImage(__GLXcontext *baseContext,
356706f2543Smrg		     int buffer,
357706f2543Smrg		     __GLXdrawable *glxPixmap)
358706f2543Smrg{
359706f2543Smrg    return Success;
360706f2543Smrg}
361706f2543Smrg
362706f2543Smrgstatic int
363706f2543Smrg__glXDRIreleaseTexImage(__GLXcontext *baseContext,
364706f2543Smrg			int buffer,
365706f2543Smrg			__GLXdrawable *pixmap)
366706f2543Smrg{
367706f2543Smrg    return Success;
368706f2543Smrg}
369706f2543Smrg
370706f2543Smrg#endif
371706f2543Smrg
372706f2543Smrgstatic __GLXtextureFromPixmap __glXDRItextureFromPixmap = {
373706f2543Smrg    __glXDRIbindTexImage,
374706f2543Smrg    __glXDRIreleaseTexImage
375706f2543Smrg};
376706f2543Smrg
377706f2543Smrgstatic void
378706f2543Smrg__glXDRIscreenDestroy(__GLXscreen *baseScreen)
379706f2543Smrg{
380706f2543Smrg    __GLXDRIscreen *screen = (__GLXDRIscreen *) baseScreen;
381706f2543Smrg
382706f2543Smrg    (*screen->core->destroyScreen)(screen->driScreen);
383706f2543Smrg
384706f2543Smrg    dlclose(screen->driver);
385706f2543Smrg
386706f2543Smrg    __glXScreenDestroy(baseScreen);
387706f2543Smrg
388706f2543Smrg    free(screen);
389706f2543Smrg}
390706f2543Smrg
391706f2543Smrgstatic __GLXcontext *
392706f2543Smrg__glXDRIscreenCreateContext(__GLXscreen *baseScreen,
393706f2543Smrg			    __GLXconfig *glxConfig,
394706f2543Smrg			    __GLXcontext *baseShareContext)
395706f2543Smrg{
396706f2543Smrg    __GLXDRIscreen *screen = (__GLXDRIscreen *) baseScreen;
397706f2543Smrg    __GLXDRIcontext *context, *shareContext;
398706f2543Smrg    __GLXDRIconfig *config = (__GLXDRIconfig *) glxConfig;
399706f2543Smrg    __DRIcontext *driShare;
400706f2543Smrg
401706f2543Smrg    shareContext = (__GLXDRIcontext *) baseShareContext;
402706f2543Smrg    if (shareContext)
403706f2543Smrg	driShare = shareContext->driContext;
404706f2543Smrg    else
405706f2543Smrg	driShare = NULL;
406706f2543Smrg
407706f2543Smrg    context = calloc(1, sizeof *context);
408706f2543Smrg    if (context == NULL)
409706f2543Smrg	return NULL;
410706f2543Smrg
411706f2543Smrg    context->base.destroy           = __glXDRIcontextDestroy;
412706f2543Smrg    context->base.makeCurrent       = __glXDRIcontextMakeCurrent;
413706f2543Smrg    context->base.loseCurrent       = __glXDRIcontextLoseCurrent;
414706f2543Smrg    context->base.copy              = __glXDRIcontextCopy;
415706f2543Smrg    context->base.forceCurrent      = __glXDRIcontextForceCurrent;
416706f2543Smrg    context->base.textureFromPixmap = &__glXDRItextureFromPixmap;
417706f2543Smrg    context->base.wait              = __glXDRIcontextWait;
418706f2543Smrg
419706f2543Smrg    context->driContext =
420706f2543Smrg	(*screen->dri2->createNewContext)(screen->driScreen,
421706f2543Smrg					  config->driConfig,
422706f2543Smrg					  driShare, context);
423706f2543Smrg    if (context->driContext == NULL) {
424706f2543Smrg	    free(context);
425706f2543Smrg        return NULL;
426706f2543Smrg    }
427706f2543Smrg
428706f2543Smrg    return &context->base;
429706f2543Smrg}
430706f2543Smrg
431706f2543Smrgstatic void
432706f2543Smrg__glXDRIinvalidateBuffers(DrawablePtr pDraw, void *priv)
433706f2543Smrg{
434706f2543Smrg#if __DRI2_FLUSH_VERSION >= 3
435706f2543Smrg    __GLXDRIdrawable *private = priv;
436706f2543Smrg    __GLXDRIscreen *screen = private->screen;
437706f2543Smrg
438706f2543Smrg    if (screen->flush)
439706f2543Smrg	(*screen->flush->invalidate)(private->driDrawable);
440706f2543Smrg#endif
441706f2543Smrg}
442706f2543Smrg
443706f2543Smrgstatic __GLXdrawable *
444706f2543Smrg__glXDRIscreenCreateDrawable(ClientPtr client,
445706f2543Smrg			     __GLXscreen *screen,
446706f2543Smrg			     DrawablePtr pDraw,
447706f2543Smrg			     XID drawId,
448706f2543Smrg			     int type,
449706f2543Smrg			     XID glxDrawId,
450706f2543Smrg			     __GLXconfig *glxConfig)
451706f2543Smrg{
452706f2543Smrg    __GLXDRIscreen *driScreen = (__GLXDRIscreen *) screen;
453706f2543Smrg    __GLXDRIconfig *config = (__GLXDRIconfig *) glxConfig;
454706f2543Smrg    __GLXDRIdrawable *private;
455706f2543Smrg
456706f2543Smrg    private = calloc(1, sizeof *private);
457706f2543Smrg    if (private == NULL)
458706f2543Smrg	return NULL;
459706f2543Smrg
460706f2543Smrg    private->screen = driScreen;
461706f2543Smrg    if (!__glXDrawableInit(&private->base, screen,
462706f2543Smrg			   pDraw, type, glxDrawId, glxConfig)) {
463706f2543Smrg        free(private);
464706f2543Smrg	return NULL;
465706f2543Smrg    }
466706f2543Smrg
467706f2543Smrg    private->base.destroy       = __glXDRIdrawableDestroy;
468706f2543Smrg    private->base.swapBuffers   = __glXDRIdrawableSwapBuffers;
469706f2543Smrg    private->base.copySubBuffer = __glXDRIdrawableCopySubBuffer;
470706f2543Smrg    private->base.waitGL	= __glXDRIdrawableWaitGL;
471706f2543Smrg    private->base.waitX		= __glXDRIdrawableWaitX;
472706f2543Smrg
473706f2543Smrg    if (DRI2CreateDrawable(client, pDraw, drawId,
474706f2543Smrg			   __glXDRIinvalidateBuffers, private)) {
475706f2543Smrg	    free(private);
476706f2543Smrg	    return NULL;
477706f2543Smrg    }
478706f2543Smrg
479706f2543Smrg    private->driDrawable =
480706f2543Smrg	(*driScreen->dri2->createNewDrawable)(driScreen->driScreen,
481706f2543Smrg					      config->driConfig, private);
482706f2543Smrg
483706f2543Smrg    return &private->base;
484706f2543Smrg}
485706f2543Smrg
486706f2543Smrgstatic __DRIbuffer *
487706f2543Smrgdri2GetBuffers(__DRIdrawable *driDrawable,
488706f2543Smrg	       int *width, int *height,
489706f2543Smrg	       unsigned int *attachments, int count,
490706f2543Smrg	       int *out_count, void *loaderPrivate)
491706f2543Smrg{
492706f2543Smrg    __GLXDRIdrawable *private = loaderPrivate;
493706f2543Smrg    DRI2BufferPtr *buffers;
494706f2543Smrg    int i;
495706f2543Smrg    int j;
496706f2543Smrg
497706f2543Smrg    buffers = DRI2GetBuffers(private->base.pDraw,
498706f2543Smrg			     width, height, attachments, count, out_count);
499706f2543Smrg    if (*out_count > MAX_DRAWABLE_BUFFERS) {
500706f2543Smrg	*out_count = 0;
501706f2543Smrg	return NULL;
502706f2543Smrg    }
503706f2543Smrg
504706f2543Smrg    private->width = *width;
505706f2543Smrg    private->height = *height;
506706f2543Smrg
507706f2543Smrg    /* This assumes the DRI2 buffer attachment tokens matches the
508706f2543Smrg     * __DRIbuffer tokens. */
509706f2543Smrg    j = 0;
510706f2543Smrg    for (i = 0; i < *out_count; i++) {
511706f2543Smrg	/* Do not send the real front buffer of a window to the client.
512706f2543Smrg	 */
513706f2543Smrg	if ((private->base.pDraw->type == DRAWABLE_WINDOW)
514706f2543Smrg	    && (buffers[i]->attachment == DRI2BufferFrontLeft)) {
515706f2543Smrg	    continue;
516706f2543Smrg	}
517706f2543Smrg
518706f2543Smrg	private->buffers[j].attachment = buffers[i]->attachment;
519706f2543Smrg	private->buffers[j].name = buffers[i]->name;
520706f2543Smrg	private->buffers[j].pitch = buffers[i]->pitch;
521706f2543Smrg	private->buffers[j].cpp = buffers[i]->cpp;
522706f2543Smrg	private->buffers[j].flags = buffers[i]->flags;
523706f2543Smrg	j++;
524706f2543Smrg    }
525706f2543Smrg
526706f2543Smrg    *out_count = j;
527706f2543Smrg    return private->buffers;
528706f2543Smrg}
529706f2543Smrg
530706f2543Smrgstatic __DRIbuffer *
531706f2543Smrgdri2GetBuffersWithFormat(__DRIdrawable *driDrawable,
532706f2543Smrg			 int *width, int *height,
533706f2543Smrg			 unsigned int *attachments, int count,
534706f2543Smrg			 int *out_count, void *loaderPrivate)
535706f2543Smrg{
536706f2543Smrg    __GLXDRIdrawable *private = loaderPrivate;
537706f2543Smrg    DRI2BufferPtr *buffers;
538706f2543Smrg    int i;
539706f2543Smrg    int j = 0;
540706f2543Smrg
541706f2543Smrg    buffers = DRI2GetBuffersWithFormat(private->base.pDraw,
542706f2543Smrg				       width, height, attachments, count,
543706f2543Smrg				       out_count);
544706f2543Smrg    if (*out_count > MAX_DRAWABLE_BUFFERS) {
545706f2543Smrg	*out_count = 0;
546706f2543Smrg	return NULL;
547706f2543Smrg    }
548706f2543Smrg
549706f2543Smrg    private->width = *width;
550706f2543Smrg    private->height = *height;
551706f2543Smrg
552706f2543Smrg    /* This assumes the DRI2 buffer attachment tokens matches the
553706f2543Smrg     * __DRIbuffer tokens. */
554706f2543Smrg    for (i = 0; i < *out_count; i++) {
555706f2543Smrg	/* Do not send the real front buffer of a window to the client.
556706f2543Smrg	 */
557706f2543Smrg	if ((private->base.pDraw->type == DRAWABLE_WINDOW)
558706f2543Smrg	    && (buffers[i]->attachment == DRI2BufferFrontLeft)) {
559706f2543Smrg	    continue;
560706f2543Smrg	}
561706f2543Smrg
562706f2543Smrg	private->buffers[j].attachment = buffers[i]->attachment;
563706f2543Smrg	private->buffers[j].name = buffers[i]->name;
564706f2543Smrg	private->buffers[j].pitch = buffers[i]->pitch;
565706f2543Smrg	private->buffers[j].cpp = buffers[i]->cpp;
566706f2543Smrg	private->buffers[j].flags = buffers[i]->flags;
567706f2543Smrg	j++;
568706f2543Smrg    }
569706f2543Smrg
570706f2543Smrg    *out_count = j;
571706f2543Smrg    return private->buffers;
572706f2543Smrg}
573706f2543Smrg
574706f2543Smrgstatic void
575706f2543Smrgdri2FlushFrontBuffer(__DRIdrawable *driDrawable, void *loaderPrivate)
576706f2543Smrg{
577706f2543Smrg    (void) driDrawable;
578706f2543Smrg    __glXDRIdrawableWaitGL((__GLXdrawable *) loaderPrivate);
579706f2543Smrg}
580706f2543Smrg
581706f2543Smrgstatic const __DRIdri2LoaderExtension loaderExtension = {
582706f2543Smrg    { __DRI_DRI2_LOADER, __DRI_DRI2_LOADER_VERSION },
583706f2543Smrg    dri2GetBuffers,
584706f2543Smrg    dri2FlushFrontBuffer,
585706f2543Smrg    dri2GetBuffersWithFormat,
586706f2543Smrg};
587706f2543Smrg
588706f2543Smrg#ifdef __DRI_USE_INVALIDATE
589706f2543Smrgstatic const __DRIuseInvalidateExtension dri2UseInvalidate = {
590706f2543Smrg   { __DRI_USE_INVALIDATE, __DRI_USE_INVALIDATE_VERSION }
591706f2543Smrg};
592706f2543Smrg#endif
593706f2543Smrg
594706f2543Smrgstatic const __DRIextension *loader_extensions[] = {
595706f2543Smrg    &systemTimeExtension.base,
596706f2543Smrg    &loaderExtension.base,
597706f2543Smrg#ifdef __DRI_USE_INVALIDATE
598706f2543Smrg    &dri2UseInvalidate.base,
599706f2543Smrg#endif
600706f2543Smrg    NULL
601706f2543Smrg};
602706f2543Smrg
603706f2543Smrgstatic const char dri_driver_path[] = DRI_DRIVER_PATH;
604706f2543Smrg
605706f2543Smrgstatic Bool
606706f2543SmrgglxDRIEnterVT (int index, int flags)
607706f2543Smrg{
608706f2543Smrg    ScrnInfoPtr scrn = xf86Screens[index];
609706f2543Smrg    Bool	ret;
610706f2543Smrg    __GLXDRIscreen *screen = (__GLXDRIscreen *)
611706f2543Smrg	glxGetScreen(screenInfo.screens[index]);
612706f2543Smrg
613706f2543Smrg    LogMessage(X_INFO, "AIGLX: Resuming AIGLX clients after VT switch\n");
614706f2543Smrg
615706f2543Smrg    scrn->EnterVT = screen->enterVT;
616706f2543Smrg
617706f2543Smrg    ret = scrn->EnterVT (index, flags);
618706f2543Smrg
619706f2543Smrg    screen->enterVT = scrn->EnterVT;
620706f2543Smrg    scrn->EnterVT = glxDRIEnterVT;
621706f2543Smrg
622706f2543Smrg    if (!ret)
623706f2543Smrg	return FALSE;
624706f2543Smrg
625706f2543Smrg    glxResumeClients();
626706f2543Smrg
627706f2543Smrg    return TRUE;
628706f2543Smrg}
629706f2543Smrg
630706f2543Smrgstatic void
631706f2543SmrgglxDRILeaveVT (int index, int flags)
632706f2543Smrg{
633706f2543Smrg    ScrnInfoPtr scrn = xf86Screens[index];
634706f2543Smrg    __GLXDRIscreen *screen = (__GLXDRIscreen *)
635706f2543Smrg	glxGetScreen(screenInfo.screens[index]);
636706f2543Smrg
637706f2543Smrg    LogMessage(X_INFO, "AIGLX: Suspending AIGLX clients for VT switch\n");
638706f2543Smrg
639706f2543Smrg    glxSuspendClients();
640706f2543Smrg
641706f2543Smrg    scrn->LeaveVT = screen->leaveVT;
642706f2543Smrg    (*screen->leaveVT) (index, flags);
643706f2543Smrg    screen->leaveVT = scrn->LeaveVT;
644706f2543Smrg    scrn->LeaveVT = glxDRILeaveVT;
645706f2543Smrg}
646706f2543Smrg
647706f2543Smrgstatic void
648706f2543SmrginitializeExtensions(__GLXDRIscreen *screen)
649706f2543Smrg{
650706f2543Smrg    ScreenPtr pScreen = screen->base.pScreen;
651706f2543Smrg    const __DRIextension **extensions;
652706f2543Smrg    int i;
653706f2543Smrg
654706f2543Smrg    extensions = screen->core->getExtensions(screen->driScreen);
655706f2543Smrg
656706f2543Smrg    __glXEnableExtension(screen->glx_enable_bits,
657706f2543Smrg			 "GLX_MESA_copy_sub_buffer");
658706f2543Smrg    LogMessage(X_INFO, "AIGLX: enabled GLX_MESA_copy_sub_buffer\n");
659706f2543Smrg
660706f2543Smrg    __glXEnableExtension(screen->glx_enable_bits, "GLX_INTEL_swap_event");
661706f2543Smrg    LogMessage(X_INFO, "AIGLX: enabled GLX_INTEL_swap_event\n");
662706f2543Smrg
663706f2543Smrg    if (DRI2HasSwapControl(pScreen)) {
664706f2543Smrg	__glXEnableExtension(screen->glx_enable_bits,
665706f2543Smrg			     "GLX_SGI_swap_control");
666706f2543Smrg	__glXEnableExtension(screen->glx_enable_bits,
667706f2543Smrg			     "GLX_MESA_swap_control");
668706f2543Smrg	LogMessage(X_INFO, "AIGLX: enabled GLX_SGI_swap_control and GLX_MESA_swap_control\n");
669706f2543Smrg    }
670706f2543Smrg
671706f2543Smrg    for (i = 0; extensions[i]; i++) {
672706f2543Smrg#ifdef __DRI_READ_DRAWABLE
673706f2543Smrg	if (strcmp(extensions[i]->name, __DRI_READ_DRAWABLE) == 0) {
674706f2543Smrg	    __glXEnableExtension(screen->glx_enable_bits,
675706f2543Smrg				 "GLX_SGI_make_current_read");
676706f2543Smrg
677706f2543Smrg	    LogMessage(X_INFO, "AIGLX: enabled GLX_SGI_make_current_read\n");
678706f2543Smrg	}
679706f2543Smrg#endif
680706f2543Smrg
681706f2543Smrg#ifdef __DRI_TEX_BUFFER
682706f2543Smrg	if (strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0) {
683706f2543Smrg	    screen->texBuffer =
684706f2543Smrg		(const __DRItexBufferExtension *) extensions[i];
685706f2543Smrg	    /* GLX_EXT_texture_from_pixmap is always enabled. */
686706f2543Smrg	    LogMessage(X_INFO, "AIGLX: GLX_EXT_texture_from_pixmap backed by buffer objects\n");
687706f2543Smrg	}
688706f2543Smrg#endif
689706f2543Smrg
690706f2543Smrg#ifdef __DRI2_FLUSH
691706f2543Smrg	if (strcmp(extensions[i]->name, __DRI2_FLUSH) == 0 &&
692706f2543Smrg	    extensions[i]->version >= 3) {
693706f2543Smrg		screen->flush = (__DRI2flushExtension *) extensions[i];
694706f2543Smrg	}
695706f2543Smrg#endif
696706f2543Smrg
697706f2543Smrg	/* Ignore unknown extensions */
698706f2543Smrg    }
699706f2543Smrg}
700706f2543Smrg
701706f2543Smrgstatic __GLXscreen *
702706f2543Smrg__glXDRIscreenProbe(ScreenPtr pScreen)
703706f2543Smrg{
704706f2543Smrg    const char *driverName, *deviceName;
705706f2543Smrg    __GLXDRIscreen *screen;
706706f2543Smrg    char filename[128];
707706f2543Smrg    size_t buffer_size;
708706f2543Smrg    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
709706f2543Smrg    const __DRIextension **extensions;
710706f2543Smrg    const __DRIconfig **driConfigs;
711706f2543Smrg    int i;
712706f2543Smrg
713706f2543Smrg    screen = calloc(1, sizeof *screen);
714706f2543Smrg    if (screen == NULL)
715706f2543Smrg	return NULL;
716706f2543Smrg
717706f2543Smrg    if (!xf86LoaderCheckSymbol("DRI2Connect") ||
718706f2543Smrg	!DRI2Connect(pScreen, DRI2DriverDRI,
719706f2543Smrg		     &screen->fd, &driverName, &deviceName)) {
720706f2543Smrg	LogMessage(X_INFO,
721706f2543Smrg		   "AIGLX: Screen %d is not DRI2 capable\n", pScreen->myNum);
722706f2543Smrg	return NULL;
723706f2543Smrg    }
724706f2543Smrg
725706f2543Smrg    screen->base.destroy        = __glXDRIscreenDestroy;
726706f2543Smrg    screen->base.createContext  = __glXDRIscreenCreateContext;
727706f2543Smrg    screen->base.createDrawable = __glXDRIscreenCreateDrawable;
728706f2543Smrg    screen->base.swapInterval   = __glXDRIdrawableSwapInterval;
729706f2543Smrg    screen->base.pScreen       = pScreen;
730706f2543Smrg
731706f2543Smrg    __glXInitExtensionEnableBits(screen->glx_enable_bits);
732706f2543Smrg
733706f2543Smrg    snprintf(filename, sizeof filename,
734706f2543Smrg	     "%s/%s_dri.so", dri_driver_path, driverName);
735706f2543Smrg
736706f2543Smrg    screen->driver = dlopen(filename, RTLD_LAZY | RTLD_LOCAL);
737706f2543Smrg    if (screen->driver == NULL) {
738706f2543Smrg	LogMessage(X_ERROR, "AIGLX error: dlopen of %s failed (%s)\n",
739706f2543Smrg		   filename, dlerror());
740706f2543Smrg        goto handle_error;
741706f2543Smrg    }
742706f2543Smrg
743706f2543Smrg    extensions = dlsym(screen->driver, __DRI_DRIVER_EXTENSIONS);
744706f2543Smrg    if (extensions == NULL) {
745706f2543Smrg	LogMessage(X_ERROR, "AIGLX error: %s exports no extensions (%s)\n",
746706f2543Smrg		   driverName, dlerror());
747706f2543Smrg	goto handle_error;
748706f2543Smrg    }
749706f2543Smrg
750706f2543Smrg    for (i = 0; extensions[i]; i++) {
751706f2543Smrg        if (strcmp(extensions[i]->name, __DRI_CORE) == 0 &&
752706f2543Smrg	    extensions[i]->version >= 1) {
753706f2543Smrg		screen->core = (const __DRIcoreExtension *) extensions[i];
754706f2543Smrg	}
755706f2543Smrg        if (strcmp(extensions[i]->name, __DRI_DRI2) == 0 &&
756706f2543Smrg	    extensions[i]->version >= 1) {
757706f2543Smrg		screen->dri2 = (const __DRIdri2Extension *) extensions[i];
758706f2543Smrg	}
759706f2543Smrg    }
760706f2543Smrg
761706f2543Smrg    if (screen->core == NULL || screen->dri2 == NULL) {
762706f2543Smrg	LogMessage(X_ERROR, "AIGLX error: %s exports no DRI extension\n",
763706f2543Smrg		   driverName);
764706f2543Smrg	goto handle_error;
765706f2543Smrg    }
766706f2543Smrg
767706f2543Smrg    screen->driScreen =
768706f2543Smrg	(*screen->dri2->createNewScreen)(pScreen->myNum,
769706f2543Smrg					 screen->fd,
770706f2543Smrg					 loader_extensions,
771706f2543Smrg					 &driConfigs,
772706f2543Smrg					 screen);
773706f2543Smrg
774706f2543Smrg    if (screen->driScreen == NULL) {
775706f2543Smrg	LogMessage(X_ERROR,
776706f2543Smrg		   "AIGLX error: Calling driver entry point failed\n");
777706f2543Smrg	goto handle_error;
778706f2543Smrg    }
779706f2543Smrg
780706f2543Smrg    initializeExtensions(screen);
781706f2543Smrg
782706f2543Smrg    screen->base.fbconfigs = glxConvertConfigs(screen->core, driConfigs,
783706f2543Smrg					       GLX_WINDOW_BIT |
784706f2543Smrg					       GLX_PIXMAP_BIT |
785706f2543Smrg					       GLX_PBUFFER_BIT);
786706f2543Smrg
787706f2543Smrg    __glXScreenInit(&screen->base, pScreen);
788706f2543Smrg
789706f2543Smrg    /* The first call simply determines the length of the extension string.
790706f2543Smrg     * This allows us to allocate some memory to hold the extension string,
791706f2543Smrg     * but it requires that we call __glXGetExtensionString a second time.
792706f2543Smrg     */
793706f2543Smrg    buffer_size = __glXGetExtensionString(screen->glx_enable_bits, NULL);
794706f2543Smrg    if (buffer_size > 0) {
795706f2543Smrg	free(screen->base.GLXextensions);
796706f2543Smrg
797706f2543Smrg	screen->base.GLXextensions = xnfalloc(buffer_size);
798706f2543Smrg	(void) __glXGetExtensionString(screen->glx_enable_bits,
799706f2543Smrg				       screen->base.GLXextensions);
800706f2543Smrg    }
801706f2543Smrg
802706f2543Smrg    /* We're going to assume (perhaps incorrectly?) that all DRI2-enabled
803706f2543Smrg     * drivers support the required extensions for GLX 1.4.  The extensions
804706f2543Smrg     * we're assuming are:
805706f2543Smrg     *
806706f2543Smrg     *    - GLX_SGI_make_current_read (1.3)
807706f2543Smrg     *    - GLX_SGIX_fbconfig (1.3)
808706f2543Smrg     *    - GLX_SGIX_pbuffer (1.3)
809706f2543Smrg     *    - GLX_ARB_multisample (1.4)
810706f2543Smrg     */
811706f2543Smrg    screen->base.GLXmajor = 1;
812706f2543Smrg    screen->base.GLXminor = 4;
813706f2543Smrg
814706f2543Smrg    screen->enterVT = pScrn->EnterVT;
815706f2543Smrg    pScrn->EnterVT = glxDRIEnterVT;
816706f2543Smrg    screen->leaveVT = pScrn->LeaveVT;
817706f2543Smrg    pScrn->LeaveVT = glxDRILeaveVT;
818706f2543Smrg
819706f2543Smrg    LogMessage(X_INFO,
820706f2543Smrg	       "AIGLX: Loaded and initialized %s\n", filename);
821706f2543Smrg
822706f2543Smrg    return &screen->base;
823706f2543Smrg
824706f2543Smrg handle_error:
825706f2543Smrg    if (screen->driver)
826706f2543Smrg        dlclose(screen->driver);
827706f2543Smrg
828706f2543Smrg    free(screen);
829706f2543Smrg
830706f2543Smrg    LogMessage(X_ERROR, "AIGLX: reverting to software rendering\n");
831706f2543Smrg
832706f2543Smrg    return NULL;
833706f2543Smrg}
834706f2543Smrg
835706f2543Smrg_X_EXPORT __GLXprovider __glXDRI2Provider = {
836706f2543Smrg    __glXDRIscreenProbe,
837706f2543Smrg    "DRI2",
838706f2543Smrg    NULL
839706f2543Smrg};
840