1706f2543Smrg/*
2706f2543Smrg * Copyright © 2007, 2008 Red Hat, Inc.
3706f2543Smrg *
4706f2543Smrg * Permission is hereby granted, free of charge, to any person obtaining a
5706f2543Smrg * copy of this software and associated documentation files (the "Soft-
6706f2543Smrg * ware"), to deal in the Software without restriction, including without
7706f2543Smrg * limitation the rights to use, copy, modify, merge, publish, distribute,
8706f2543Smrg * and/or sell copies of the Software, and to permit persons to whom the
9706f2543Smrg * Software is furnished to do so, provided that the above copyright
10706f2543Smrg * notice(s) and this permission notice appear in all copies of the Soft-
11706f2543Smrg * ware and that both the above copyright notice(s) and this permission
12706f2543Smrg * notice appear in supporting documentation.
13706f2543Smrg *
14706f2543Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15706f2543Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
16706f2543Smrg * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
17706f2543Smrg * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
18706f2543Smrg * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
19706f2543Smrg * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20706f2543Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21706f2543Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
22706f2543Smrg * MANCE OF THIS SOFTWARE.
23706f2543Smrg *
24706f2543Smrg * Except as contained in this notice, the name of a copyright holder shall
25706f2543Smrg * not be used in advertising or otherwise to promote the sale, use or
26706f2543Smrg * other dealings in this Software without prior written authorization of
27706f2543Smrg * the copyright holder.
28706f2543Smrg *
29706f2543Smrg * Authors:
30706f2543Smrg *   Kristian Høgsberg (krh@redhat.com)
31706f2543Smrg */
32706f2543Smrg
33706f2543Smrg#ifdef HAVE_XORG_CONFIG_H
34706f2543Smrg#include <xorg-config.h>
35706f2543Smrg#endif
36706f2543Smrg
37706f2543Smrg#include <errno.h>
38706f2543Smrg#ifdef WITH_LIBDRM
39706f2543Smrg#include <xf86drm.h>
40706f2543Smrg#endif
41706f2543Smrg#include "xf86Module.h"
42706f2543Smrg#include "list.h"
43706f2543Smrg#include "scrnintstr.h"
44706f2543Smrg#include "windowstr.h"
45706f2543Smrg#include "dixstruct.h"
46706f2543Smrg#include "dri2.h"
47706f2543Smrg#include "xf86VGAarbiter.h"
48706f2543Smrg
49706f2543Smrg#include "xf86.h"
50706f2543Smrg
51706f2543SmrgCARD8 dri2_major; /* version of DRI2 supported by DDX */
52706f2543SmrgCARD8 dri2_minor;
53706f2543Smrg
54706f2543Smrgstatic DevPrivateKeyRec dri2ScreenPrivateKeyRec;
55706f2543Smrg#define dri2ScreenPrivateKey (&dri2ScreenPrivateKeyRec)
56706f2543Smrg
57706f2543Smrgstatic DevPrivateKeyRec dri2WindowPrivateKeyRec;
58706f2543Smrg#define dri2WindowPrivateKey (&dri2WindowPrivateKeyRec)
59706f2543Smrg
60706f2543Smrgstatic DevPrivateKeyRec dri2PixmapPrivateKeyRec;
61706f2543Smrg#define dri2PixmapPrivateKey (&dri2PixmapPrivateKeyRec)
62706f2543Smrg
63706f2543Smrgstatic RESTYPE       dri2DrawableRes;
64706f2543Smrg
65706f2543Smrgtypedef struct _DRI2Screen *DRI2ScreenPtr;
66706f2543Smrg
67706f2543Smrgtypedef struct _DRI2Drawable {
68706f2543Smrg    DRI2ScreenPtr        dri2_screen;
69706f2543Smrg    DrawablePtr		 drawable;
70706f2543Smrg    struct list		 reference_list;
71706f2543Smrg    int			 width;
72706f2543Smrg    int			 height;
73706f2543Smrg    DRI2BufferPtr	*buffers;
74706f2543Smrg    int			 bufferCount;
75706f2543Smrg    unsigned int	 swapsPending;
76706f2543Smrg    ClientPtr		 blockedClient;
77706f2543Smrg    Bool		 blockedOnMsc;
78706f2543Smrg    int			 swap_interval;
79706f2543Smrg    CARD64		 swap_count;
80706f2543Smrg    int64_t		 target_sbc; /* -1 means no SBC wait outstanding */
81706f2543Smrg    CARD64		 last_swap_target; /* most recently queued swap target */
82706f2543Smrg    CARD64		 last_swap_msc; /* msc at completion of most recent swap */
83706f2543Smrg    CARD64		 last_swap_ust; /* ust at completion of most recent swap */
84706f2543Smrg    int			 swap_limit; /* for N-buffering */
85706f2543Smrg    unsigned long	 serialNumber;
86706f2543Smrg} DRI2DrawableRec, *DRI2DrawablePtr;
87706f2543Smrg
88706f2543Smrgtypedef struct _DRI2Screen {
89706f2543Smrg    ScreenPtr			 screen;
90706f2543Smrg    int				 refcnt;
91706f2543Smrg    unsigned int		 numDrivers;
92706f2543Smrg    const char			**driverNames;
93706f2543Smrg    const char			*deviceName;
94706f2543Smrg    int				 fd;
95706f2543Smrg    unsigned int		 lastSequence;
96706f2543Smrg
97706f2543Smrg    DRI2CreateBufferProcPtr	 CreateBuffer;
98706f2543Smrg    DRI2DestroyBufferProcPtr	 DestroyBuffer;
99706f2543Smrg    DRI2CopyRegionProcPtr	 CopyRegion;
100706f2543Smrg    DRI2ScheduleSwapProcPtr	 ScheduleSwap;
101706f2543Smrg    DRI2GetMSCProcPtr		 GetMSC;
102706f2543Smrg    DRI2ScheduleWaitMSCProcPtr	 ScheduleWaitMSC;
103706f2543Smrg    DRI2AuthMagicProcPtr	 AuthMagic;
104706f2543Smrg
105706f2543Smrg    HandleExposuresProcPtr       HandleExposures;
106706f2543Smrg
107706f2543Smrg    ConfigNotifyProcPtr		 ConfigNotify;
108706f2543Smrg} DRI2ScreenRec;
109706f2543Smrg
110706f2543Smrgstatic DRI2ScreenPtr
111706f2543SmrgDRI2GetScreen(ScreenPtr pScreen)
112706f2543Smrg{
113706f2543Smrg    return dixLookupPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey);
114706f2543Smrg}
115706f2543Smrg
116706f2543Smrgstatic DRI2DrawablePtr
117706f2543SmrgDRI2GetDrawable(DrawablePtr pDraw)
118706f2543Smrg{
119706f2543Smrg    WindowPtr pWin;
120706f2543Smrg    PixmapPtr pPixmap;
121706f2543Smrg
122706f2543Smrg    switch (pDraw->type) {
123706f2543Smrg    case DRAWABLE_WINDOW:
124706f2543Smrg	pWin = (WindowPtr) pDraw;
125706f2543Smrg	return dixLookupPrivate(&pWin->devPrivates, dri2WindowPrivateKey);
126706f2543Smrg    case DRAWABLE_PIXMAP:
127706f2543Smrg	pPixmap = (PixmapPtr) pDraw;
128706f2543Smrg	return dixLookupPrivate(&pPixmap->devPrivates, dri2PixmapPrivateKey);
129706f2543Smrg    default:
130706f2543Smrg	return NULL;
131706f2543Smrg    }
132706f2543Smrg}
133706f2543Smrg
134706f2543Smrgstatic unsigned long
135706f2543SmrgDRI2DrawableSerial(DrawablePtr pDraw)
136706f2543Smrg{
137706f2543Smrg    ScreenPtr pScreen = pDraw->pScreen;
138706f2543Smrg    PixmapPtr pPix;
139706f2543Smrg
140706f2543Smrg    if (pDraw->type != DRAWABLE_WINDOW)
141706f2543Smrg	return pDraw->serialNumber;
142706f2543Smrg
143706f2543Smrg    pPix = pScreen->GetWindowPixmap((WindowPtr)pDraw);
144706f2543Smrg    return pPix->drawable.serialNumber;
145706f2543Smrg}
146706f2543Smrg
147706f2543Smrgstatic DRI2DrawablePtr
148706f2543SmrgDRI2AllocateDrawable(DrawablePtr pDraw)
149706f2543Smrg{
150706f2543Smrg    DRI2ScreenPtr   ds = DRI2GetScreen(pDraw->pScreen);
151706f2543Smrg    DRI2DrawablePtr pPriv;
152706f2543Smrg    CARD64          ust;
153706f2543Smrg    WindowPtr pWin;
154706f2543Smrg    PixmapPtr pPixmap;
155706f2543Smrg
156706f2543Smrg    pPriv = malloc(sizeof *pPriv);
157706f2543Smrg    if (pPriv == NULL)
158706f2543Smrg	return NULL;
159706f2543Smrg
160706f2543Smrg    pPriv->dri2_screen = ds;
161706f2543Smrg    pPriv->drawable = pDraw;
162706f2543Smrg    pPriv->width = pDraw->width;
163706f2543Smrg    pPriv->height = pDraw->height;
164706f2543Smrg    pPriv->buffers = NULL;
165706f2543Smrg    pPriv->bufferCount = 0;
166706f2543Smrg    pPriv->swapsPending = 0;
167706f2543Smrg    pPriv->blockedClient = NULL;
168706f2543Smrg    pPriv->blockedOnMsc = FALSE;
169706f2543Smrg    pPriv->swap_count = 0;
170706f2543Smrg    pPriv->target_sbc = -1;
171706f2543Smrg    pPriv->swap_interval = 1;
172706f2543Smrg    /* Initialize last swap target from DDX if possible */
173706f2543Smrg    if (!ds->GetMSC || !(*ds->GetMSC)(pDraw, &ust, &pPriv->last_swap_target))
174706f2543Smrg	pPriv->last_swap_target = 0;
175706f2543Smrg
176706f2543Smrg    pPriv->swap_limit = 1; /* default to double buffering */
177706f2543Smrg    pPriv->last_swap_msc = 0;
178706f2543Smrg    pPriv->last_swap_ust = 0;
179706f2543Smrg    list_init(&pPriv->reference_list);
180706f2543Smrg    pPriv->serialNumber = DRI2DrawableSerial(pDraw);
181706f2543Smrg
182706f2543Smrg    if (pDraw->type == DRAWABLE_WINDOW) {
183706f2543Smrg	pWin = (WindowPtr) pDraw;
184706f2543Smrg	dixSetPrivate(&pWin->devPrivates, dri2WindowPrivateKey, pPriv);
185706f2543Smrg    } else {
186706f2543Smrg	pPixmap = (PixmapPtr) pDraw;
187706f2543Smrg	dixSetPrivate(&pPixmap->devPrivates, dri2PixmapPrivateKey, pPriv);
188706f2543Smrg    }
189706f2543Smrg
190706f2543Smrg    return pPriv;
191706f2543Smrg}
192706f2543Smrg
193706f2543Smrgtypedef struct DRI2DrawableRefRec {
194706f2543Smrg    XID		  id;
195706f2543Smrg    XID		  dri2_id;
196706f2543Smrg    DRI2InvalidateProcPtr	invalidate;
197706f2543Smrg    void	 *priv;
198706f2543Smrg    struct list	  link;
199706f2543Smrg} DRI2DrawableRefRec, *DRI2DrawableRefPtr;
200706f2543Smrg
201706f2543Smrgstatic DRI2DrawableRefPtr
202706f2543SmrgDRI2LookupDrawableRef(DRI2DrawablePtr pPriv, XID id)
203706f2543Smrg{
204706f2543Smrg    DRI2DrawableRefPtr ref = NULL;
205706f2543Smrg
206706f2543Smrg    list_for_each_entry(ref, &pPriv->reference_list, link) {
207706f2543Smrg	if (ref->id == id)
208706f2543Smrg	    return ref;
209706f2543Smrg    }
210706f2543Smrg
211706f2543Smrg    return NULL;
212706f2543Smrg}
213706f2543Smrg
214706f2543Smrgstatic int
215706f2543SmrgDRI2AddDrawableRef(DRI2DrawablePtr pPriv, XID id, XID dri2_id,
216706f2543Smrg		   DRI2InvalidateProcPtr invalidate, void *priv)
217706f2543Smrg{
218706f2543Smrg    DRI2DrawableRefPtr ref;
219706f2543Smrg
220706f2543Smrg    ref = malloc(sizeof *ref);
221706f2543Smrg    if (ref == NULL)
222706f2543Smrg	return BadAlloc;
223706f2543Smrg
224706f2543Smrg    if (!AddResource(dri2_id, dri2DrawableRes, pPriv)) {
225706f2543Smrg	free(ref);
226706f2543Smrg	return BadAlloc;
227706f2543Smrg    }
228706f2543Smrg    if (!DRI2LookupDrawableRef(pPriv, id))
229706f2543Smrg	if (!AddResource(id, dri2DrawableRes, pPriv)) {
230706f2543Smrg	    FreeResourceByType(dri2_id, dri2DrawableRes, TRUE);
231706f2543Smrg	    free(ref);
232706f2543Smrg	    return BadAlloc;
233706f2543Smrg        }
234706f2543Smrg
235706f2543Smrg    ref->id = id;
236706f2543Smrg    ref->dri2_id = dri2_id;
237706f2543Smrg    ref->invalidate = invalidate;
238706f2543Smrg    ref->priv = priv;
239706f2543Smrg    list_add(&ref->link, &pPriv->reference_list);
240706f2543Smrg
241706f2543Smrg    return Success;
242706f2543Smrg}
243706f2543Smrg
244706f2543Smrgint
245706f2543SmrgDRI2CreateDrawable(ClientPtr client, DrawablePtr pDraw, XID id,
246706f2543Smrg		   DRI2InvalidateProcPtr invalidate, void *priv)
247706f2543Smrg{
248706f2543Smrg    DRI2DrawablePtr pPriv;
249706f2543Smrg    XID dri2_id;
250706f2543Smrg    int rc;
251706f2543Smrg
252706f2543Smrg    pPriv = DRI2GetDrawable(pDraw);
253706f2543Smrg    if (pPriv == NULL)
254706f2543Smrg	pPriv = DRI2AllocateDrawable(pDraw);
255706f2543Smrg    if (pPriv == NULL)
256706f2543Smrg	return BadAlloc;
257706f2543Smrg
258706f2543Smrg    dri2_id = FakeClientID(client->index);
259706f2543Smrg    rc = DRI2AddDrawableRef(pPriv, id, dri2_id, invalidate, priv);
260706f2543Smrg    if (rc != Success)
261706f2543Smrg	return rc;
262706f2543Smrg
263706f2543Smrg    return Success;
264706f2543Smrg}
265706f2543Smrg
266706f2543Smrgstatic int DRI2DrawableGone(pointer p, XID id)
267706f2543Smrg{
268706f2543Smrg    DRI2DrawablePtr pPriv = p;
269706f2543Smrg    DRI2ScreenPtr   ds = pPriv->dri2_screen;
270706f2543Smrg    DRI2DrawableRefPtr ref = NULL, next;
271706f2543Smrg    WindowPtr pWin;
272706f2543Smrg    PixmapPtr pPixmap;
273706f2543Smrg    DrawablePtr pDraw;
274706f2543Smrg    int i;
275706f2543Smrg
276706f2543Smrg    list_for_each_entry_safe(ref, next, &pPriv->reference_list, link) {
277706f2543Smrg	if (ref->dri2_id == id) {
278706f2543Smrg	    list_del(&ref->link);
279706f2543Smrg	    /* If this was the last ref under this X drawable XID,
280706f2543Smrg	     * unregister the X drawable resource. */
281706f2543Smrg	    if (!DRI2LookupDrawableRef(pPriv, ref->id))
282706f2543Smrg		FreeResourceByType(ref->id, dri2DrawableRes, TRUE);
283706f2543Smrg	    free(ref);
284706f2543Smrg	    break;
285706f2543Smrg	}
286706f2543Smrg
287706f2543Smrg	if (ref->id == id) {
288706f2543Smrg	    list_del(&ref->link);
289706f2543Smrg	    FreeResourceByType(ref->dri2_id, dri2DrawableRes, TRUE);
290706f2543Smrg	    free(ref);
291706f2543Smrg	}
292706f2543Smrg    }
293706f2543Smrg
294706f2543Smrg    if (!list_is_empty(&pPriv->reference_list))
295706f2543Smrg	return Success;
296706f2543Smrg
297706f2543Smrg    pDraw = pPriv->drawable;
298706f2543Smrg    if (pDraw->type == DRAWABLE_WINDOW) {
299706f2543Smrg	pWin = (WindowPtr) pDraw;
300706f2543Smrg	dixSetPrivate(&pWin->devPrivates, dri2WindowPrivateKey, NULL);
301706f2543Smrg    } else {
302706f2543Smrg	pPixmap = (PixmapPtr) pDraw;
303706f2543Smrg	dixSetPrivate(&pPixmap->devPrivates, dri2PixmapPrivateKey, NULL);
304706f2543Smrg    }
305706f2543Smrg
306706f2543Smrg    if (pPriv->buffers != NULL) {
307706f2543Smrg	for (i = 0; i < pPriv->bufferCount; i++)
308706f2543Smrg	    (*ds->DestroyBuffer)(pDraw, pPriv->buffers[i]);
309706f2543Smrg
310706f2543Smrg	free(pPriv->buffers);
311706f2543Smrg    }
312706f2543Smrg
313706f2543Smrg    free(pPriv);
314706f2543Smrg
315706f2543Smrg    return Success;
316706f2543Smrg}
317706f2543Smrg
318706f2543Smrgstatic int
319706f2543Smrgfind_attachment(DRI2DrawablePtr pPriv, unsigned attachment)
320706f2543Smrg{
321706f2543Smrg    int i;
322706f2543Smrg
323706f2543Smrg    if (pPriv->buffers == NULL) {
324706f2543Smrg	return -1;
325706f2543Smrg    }
326706f2543Smrg
327706f2543Smrg    for (i = 0; i < pPriv->bufferCount; i++) {
328706f2543Smrg	if ((pPriv->buffers[i] != NULL)
329706f2543Smrg	    && (pPriv->buffers[i]->attachment == attachment)) {
330706f2543Smrg	    return i;
331706f2543Smrg	}
332706f2543Smrg    }
333706f2543Smrg
334706f2543Smrg    return -1;
335706f2543Smrg}
336706f2543Smrg
337706f2543Smrgstatic Bool
338706f2543Smrgallocate_or_reuse_buffer(DrawablePtr pDraw, DRI2ScreenPtr ds,
339706f2543Smrg			 DRI2DrawablePtr pPriv,
340706f2543Smrg			 unsigned int attachment, unsigned int format,
341706f2543Smrg			 int dimensions_match, DRI2BufferPtr *buffer)
342706f2543Smrg{
343706f2543Smrg    int old_buf = find_attachment(pPriv, attachment);
344706f2543Smrg
345706f2543Smrg    if ((old_buf < 0)
346706f2543Smrg	|| !dimensions_match
347706f2543Smrg	|| (pPriv->buffers[old_buf]->format != format)) {
348706f2543Smrg	*buffer = (*ds->CreateBuffer)(pDraw, attachment, format);
349706f2543Smrg	pPriv->serialNumber = DRI2DrawableSerial(pDraw);
350706f2543Smrg	return TRUE;
351706f2543Smrg
352706f2543Smrg    } else {
353706f2543Smrg	*buffer = pPriv->buffers[old_buf];
354706f2543Smrg	pPriv->buffers[old_buf] = NULL;
355706f2543Smrg	return FALSE;
356706f2543Smrg    }
357706f2543Smrg}
358706f2543Smrg
359706f2543Smrgstatic void
360706f2543Smrgupdate_dri2_drawable_buffers(DRI2DrawablePtr pPriv, DrawablePtr pDraw,
361706f2543Smrg			     DRI2BufferPtr *buffers, int *out_count, int *width, int *height)
362706f2543Smrg{
363706f2543Smrg    DRI2ScreenPtr   ds = DRI2GetScreen(pDraw->pScreen);
364706f2543Smrg    int i;
365706f2543Smrg
366706f2543Smrg    if (pPriv->buffers != NULL) {
367706f2543Smrg	for (i = 0; i < pPriv->bufferCount; i++) {
368706f2543Smrg	    if (pPriv->buffers[i] != NULL) {
369706f2543Smrg		(*ds->DestroyBuffer)(pDraw, pPriv->buffers[i]);
370706f2543Smrg	    }
371706f2543Smrg	}
372706f2543Smrg
373706f2543Smrg	free(pPriv->buffers);
374706f2543Smrg    }
375706f2543Smrg
376706f2543Smrg    pPriv->buffers = buffers;
377706f2543Smrg    pPriv->bufferCount = *out_count;
378706f2543Smrg    pPriv->width = pDraw->width;
379706f2543Smrg    pPriv->height = pDraw->height;
380706f2543Smrg    *width = pPriv->width;
381706f2543Smrg    *height = pPriv->height;
382706f2543Smrg}
383706f2543Smrg
384706f2543Smrgstatic DRI2BufferPtr *
385706f2543Smrgdo_get_buffers(DrawablePtr pDraw, int *width, int *height,
386706f2543Smrg	       unsigned int *attachments, int count, int *out_count,
387706f2543Smrg	       int has_format)
388706f2543Smrg{
389706f2543Smrg    DRI2ScreenPtr   ds = DRI2GetScreen(pDraw->pScreen);
390706f2543Smrg    DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw);
391706f2543Smrg    DRI2BufferPtr  *buffers;
392706f2543Smrg    int need_real_front = 0;
393706f2543Smrg    int need_fake_front = 0;
394706f2543Smrg    int have_fake_front = 0;
395706f2543Smrg    int front_format = 0;
396706f2543Smrg    int dimensions_match;
397706f2543Smrg    int buffers_changed = 0;
398706f2543Smrg    int i;
399706f2543Smrg
400706f2543Smrg    if (!pPriv) {
401706f2543Smrg	*width = pDraw->width;
402706f2543Smrg	*height = pDraw->height;
403706f2543Smrg	*out_count = 0;
404706f2543Smrg	return NULL;
405706f2543Smrg    }
406706f2543Smrg
407706f2543Smrg    dimensions_match = (pDraw->width == pPriv->width)
408706f2543Smrg	&& (pDraw->height == pPriv->height)
409706f2543Smrg	&& (pPriv->serialNumber == DRI2DrawableSerial(pDraw));
410706f2543Smrg
411706f2543Smrg    buffers = calloc((count + 1), sizeof(buffers[0]));
412706f2543Smrg
413706f2543Smrg    for (i = 0; i < count; i++) {
414706f2543Smrg	const unsigned attachment = *(attachments++);
415706f2543Smrg	const unsigned format = (has_format) ? *(attachments++) : 0;
416706f2543Smrg
417706f2543Smrg	if (allocate_or_reuse_buffer(pDraw, ds, pPriv, attachment,
418706f2543Smrg				     format, dimensions_match,
419706f2543Smrg				     &buffers[i]))
420706f2543Smrg		buffers_changed = 1;
421706f2543Smrg
422706f2543Smrg	if (buffers[i] == NULL)
423706f2543Smrg	    goto err_out;
424706f2543Smrg
425706f2543Smrg	/* If the drawable is a window and the front-buffer is requested,
426706f2543Smrg	 * silently add the fake front-buffer to the list of requested
427706f2543Smrg	 * attachments.  The counting logic in the loop accounts for the case
428706f2543Smrg	 * where the client requests both the fake and real front-buffer.
429706f2543Smrg	 */
430706f2543Smrg	if (attachment == DRI2BufferBackLeft) {
431706f2543Smrg	    need_real_front++;
432706f2543Smrg	    front_format = format;
433706f2543Smrg	}
434706f2543Smrg
435706f2543Smrg	if (attachment == DRI2BufferFrontLeft) {
436706f2543Smrg	    need_real_front--;
437706f2543Smrg	    front_format = format;
438706f2543Smrg
439706f2543Smrg	    if (pDraw->type == DRAWABLE_WINDOW) {
440706f2543Smrg		need_fake_front++;
441706f2543Smrg	    }
442706f2543Smrg	}
443706f2543Smrg
444706f2543Smrg	if (pDraw->type == DRAWABLE_WINDOW) {
445706f2543Smrg	    if (attachment == DRI2BufferFakeFrontLeft) {
446706f2543Smrg		need_fake_front--;
447706f2543Smrg		have_fake_front = 1;
448706f2543Smrg	    }
449706f2543Smrg	}
450706f2543Smrg    }
451706f2543Smrg
452706f2543Smrg    if (need_real_front > 0) {
453706f2543Smrg	if (allocate_or_reuse_buffer(pDraw, ds, pPriv, DRI2BufferFrontLeft,
454706f2543Smrg				     front_format, dimensions_match,
455706f2543Smrg				     &buffers[i]))
456706f2543Smrg	    buffers_changed = 1;
457706f2543Smrg
458706f2543Smrg	if (buffers[i] == NULL)
459706f2543Smrg	    goto err_out;
460706f2543Smrg	i++;
461706f2543Smrg    }
462706f2543Smrg
463706f2543Smrg    if (need_fake_front > 0) {
464706f2543Smrg	if (allocate_or_reuse_buffer(pDraw, ds, pPriv, DRI2BufferFakeFrontLeft,
465706f2543Smrg				     front_format, dimensions_match,
466706f2543Smrg				     &buffers[i]))
467706f2543Smrg	    buffers_changed = 1;
468706f2543Smrg
469706f2543Smrg	if (buffers[i] == NULL)
470706f2543Smrg	    goto err_out;
471706f2543Smrg
472706f2543Smrg	i++;
473706f2543Smrg	have_fake_front = 1;
474706f2543Smrg    }
475706f2543Smrg
476706f2543Smrg    *out_count = i;
477706f2543Smrg
478706f2543Smrg    update_dri2_drawable_buffers(pPriv, pDraw, buffers, out_count, width, height);
479706f2543Smrg
480706f2543Smrg    /* If the client is getting a fake front-buffer, pre-fill it with the
481706f2543Smrg     * contents of the real front-buffer.  This ensures correct operation of
482706f2543Smrg     * applications that call glXWaitX before calling glDrawBuffer.
483706f2543Smrg     */
484706f2543Smrg    if (have_fake_front && buffers_changed) {
485706f2543Smrg	BoxRec box;
486706f2543Smrg	RegionRec region;
487706f2543Smrg
488706f2543Smrg	box.x1 = 0;
489706f2543Smrg	box.y1 = 0;
490706f2543Smrg	box.x2 = pPriv->width;
491706f2543Smrg	box.y2 = pPriv->height;
492706f2543Smrg	RegionInit(&region, &box, 0);
493706f2543Smrg
494706f2543Smrg	DRI2CopyRegion(pDraw, &region, DRI2BufferFakeFrontLeft,
495706f2543Smrg		       DRI2BufferFrontLeft);
496706f2543Smrg    }
497706f2543Smrg
498706f2543Smrg    return pPriv->buffers;
499706f2543Smrg
500706f2543Smrgerr_out:
501706f2543Smrg
502706f2543Smrg    *out_count = 0;
503706f2543Smrg
504706f2543Smrg    for (i = 0; i < count; i++) {
505706f2543Smrg	    if (buffers[i] != NULL)
506706f2543Smrg		    (*ds->DestroyBuffer)(pDraw, buffers[i]);
507706f2543Smrg    }
508706f2543Smrg
509706f2543Smrg    free(buffers);
510706f2543Smrg    buffers = NULL;
511706f2543Smrg
512706f2543Smrg    update_dri2_drawable_buffers(pPriv, pDraw, buffers, out_count, width, height);
513706f2543Smrg
514706f2543Smrg    return buffers;
515706f2543Smrg}
516706f2543Smrg
517706f2543SmrgDRI2BufferPtr *
518706f2543SmrgDRI2GetBuffers(DrawablePtr pDraw, int *width, int *height,
519706f2543Smrg	       unsigned int *attachments, int count, int *out_count)
520706f2543Smrg{
521706f2543Smrg    return do_get_buffers(pDraw, width, height, attachments, count,
522706f2543Smrg			  out_count, FALSE);
523706f2543Smrg}
524706f2543Smrg
525706f2543SmrgDRI2BufferPtr *
526706f2543SmrgDRI2GetBuffersWithFormat(DrawablePtr pDraw, int *width, int *height,
527706f2543Smrg			 unsigned int *attachments, int count, int *out_count)
528706f2543Smrg{
529706f2543Smrg    return do_get_buffers(pDraw, width, height, attachments, count,
530706f2543Smrg			  out_count, TRUE);
531706f2543Smrg}
532706f2543Smrg
533706f2543Smrgstatic void
534706f2543SmrgDRI2InvalidateDrawable(DrawablePtr pDraw)
535706f2543Smrg{
536706f2543Smrg    DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw);
537706f2543Smrg    DRI2DrawableRefPtr ref = NULL;
538706f2543Smrg
539706f2543Smrg    if (!pPriv)
540706f2543Smrg        return;
541706f2543Smrg
542706f2543Smrg    list_for_each_entry(ref, &pPriv->reference_list, link)
543706f2543Smrg	ref->invalidate(pDraw, ref->priv);
544706f2543Smrg}
545706f2543Smrg
546706f2543Smrg/*
547706f2543Smrg * In the direct rendered case, we throttle the clients that have more
548706f2543Smrg * than their share of outstanding swaps (and thus busy buffers) when a
549706f2543Smrg * new GetBuffers request is received.  In the AIGLX case, we allow the
550706f2543Smrg * client to get the new buffers, but throttle when the next GLX request
551706f2543Smrg * comes in (see __glXDRIcontextWait()).
552706f2543Smrg */
553706f2543SmrgBool
554706f2543SmrgDRI2ThrottleClient(ClientPtr client, DrawablePtr pDraw)
555706f2543Smrg{
556706f2543Smrg    DRI2DrawablePtr pPriv;
557706f2543Smrg
558706f2543Smrg    pPriv = DRI2GetDrawable(pDraw);
559706f2543Smrg    if (pPriv == NULL)
560706f2543Smrg	return FALSE;
561706f2543Smrg
562706f2543Smrg    /* Throttle to swap limit */
563706f2543Smrg    if ((pPriv->swapsPending >= pPriv->swap_limit) &&
564706f2543Smrg	!pPriv->blockedClient) {
565706f2543Smrg	ResetCurrentRequest(client);
566706f2543Smrg	client->sequence--;
567706f2543Smrg	IgnoreClient(client);
568706f2543Smrg	pPriv->blockedClient = client;
569706f2543Smrg	return TRUE;
570706f2543Smrg    }
571706f2543Smrg
572706f2543Smrg    return FALSE;
573706f2543Smrg}
574706f2543Smrg
575706f2543Smrgstatic void
576706f2543Smrg__DRI2BlockClient(ClientPtr client, DRI2DrawablePtr pPriv)
577706f2543Smrg{
578706f2543Smrg    if (pPriv->blockedClient == NULL) {
579706f2543Smrg	IgnoreClient(client);
580706f2543Smrg	pPriv->blockedClient = client;
581706f2543Smrg    }
582706f2543Smrg}
583706f2543Smrg
584706f2543Smrgvoid
585706f2543SmrgDRI2BlockClient(ClientPtr client, DrawablePtr pDraw)
586706f2543Smrg{
587706f2543Smrg    DRI2DrawablePtr pPriv;
588706f2543Smrg
589706f2543Smrg    pPriv = DRI2GetDrawable(pDraw);
590706f2543Smrg    if (pPriv == NULL)
591706f2543Smrg	return;
592706f2543Smrg
593706f2543Smrg    __DRI2BlockClient(client, pPriv);
594706f2543Smrg    pPriv->blockedOnMsc = TRUE;
595706f2543Smrg}
596706f2543Smrg
597706f2543Smrgint
598706f2543SmrgDRI2CopyRegion(DrawablePtr pDraw, RegionPtr pRegion,
599706f2543Smrg	       unsigned int dest, unsigned int src)
600706f2543Smrg{
601706f2543Smrg    DRI2ScreenPtr   ds = DRI2GetScreen(pDraw->pScreen);
602706f2543Smrg    DRI2DrawablePtr pPriv;
603706f2543Smrg    DRI2BufferPtr   pDestBuffer, pSrcBuffer;
604706f2543Smrg    int		    i;
605706f2543Smrg
606706f2543Smrg    pPriv = DRI2GetDrawable(pDraw);
607706f2543Smrg    if (pPriv == NULL)
608706f2543Smrg	return BadDrawable;
609706f2543Smrg
610706f2543Smrg    pDestBuffer = NULL;
611706f2543Smrg    pSrcBuffer = NULL;
612706f2543Smrg    for (i = 0; i < pPriv->bufferCount; i++)
613706f2543Smrg    {
614706f2543Smrg	if (pPriv->buffers[i]->attachment == dest)
615706f2543Smrg	    pDestBuffer = (DRI2BufferPtr) pPriv->buffers[i];
616706f2543Smrg	if (pPriv->buffers[i]->attachment == src)
617706f2543Smrg	    pSrcBuffer = (DRI2BufferPtr) pPriv->buffers[i];
618706f2543Smrg    }
619706f2543Smrg    if (pSrcBuffer == NULL || pDestBuffer == NULL)
620706f2543Smrg	return BadValue;
621706f2543Smrg
622706f2543Smrg    (*ds->CopyRegion)(pDraw, pRegion, pDestBuffer, pSrcBuffer);
623706f2543Smrg
624706f2543Smrg    return Success;
625706f2543Smrg}
626706f2543Smrg
627706f2543Smrg/* Can this drawable be page flipped? */
628706f2543SmrgBool
629706f2543SmrgDRI2CanFlip(DrawablePtr pDraw)
630706f2543Smrg{
631706f2543Smrg    ScreenPtr pScreen = pDraw->pScreen;
632706f2543Smrg    WindowPtr pWin, pRoot;
633706f2543Smrg    PixmapPtr pWinPixmap, pRootPixmap;
634706f2543Smrg
635706f2543Smrg    if (pDraw->type == DRAWABLE_PIXMAP)
636706f2543Smrg	return TRUE;
637706f2543Smrg
638706f2543Smrg    pRoot = pScreen->root;
639706f2543Smrg    pRootPixmap = pScreen->GetWindowPixmap(pRoot);
640706f2543Smrg
641706f2543Smrg    pWin = (WindowPtr) pDraw;
642706f2543Smrg    pWinPixmap = pScreen->GetWindowPixmap(pWin);
643706f2543Smrg    if (pRootPixmap != pWinPixmap)
644706f2543Smrg	return FALSE;
645706f2543Smrg    if (!RegionEqual(&pWin->clipList, &pRoot->winSize))
646706f2543Smrg	return FALSE;
647706f2543Smrg
648706f2543Smrg    /* Does the window match the pixmap exactly? */
649706f2543Smrg    if (pDraw->x != 0 ||
650706f2543Smrg	pDraw->y != 0 ||
651706f2543Smrg#ifdef COMPOSITE
652706f2543Smrg	pDraw->x != pWinPixmap->screen_x ||
653706f2543Smrg	pDraw->y != pWinPixmap->screen_y ||
654706f2543Smrg#endif
655706f2543Smrg	pDraw->width != pWinPixmap->drawable.width ||
656706f2543Smrg	pDraw->height != pWinPixmap->drawable.height)
657706f2543Smrg	return FALSE;
658706f2543Smrg
659706f2543Smrg    return TRUE;
660706f2543Smrg}
661706f2543Smrg
662706f2543Smrg/* Can we do a pixmap exchange instead of a blit? */
663706f2543SmrgBool
664706f2543SmrgDRI2CanExchange(DrawablePtr pDraw)
665706f2543Smrg{
666706f2543Smrg    return FALSE;
667706f2543Smrg}
668706f2543Smrg
669706f2543Smrgvoid
670706f2543SmrgDRI2WaitMSCComplete(ClientPtr client, DrawablePtr pDraw, int frame,
671706f2543Smrg		    unsigned int tv_sec, unsigned int tv_usec)
672706f2543Smrg{
673706f2543Smrg    DRI2DrawablePtr pPriv;
674706f2543Smrg
675706f2543Smrg    pPriv = DRI2GetDrawable(pDraw);
676706f2543Smrg    if (pPriv == NULL)
677706f2543Smrg	return;
678706f2543Smrg
679706f2543Smrg    ProcDRI2WaitMSCReply(client, ((CARD64)tv_sec * 1000000) + tv_usec,
680706f2543Smrg			 frame, pPriv->swap_count);
681706f2543Smrg
682706f2543Smrg    if (pPriv->blockedClient)
683706f2543Smrg	AttendClient(pPriv->blockedClient);
684706f2543Smrg
685706f2543Smrg    pPriv->blockedClient = NULL;
686706f2543Smrg    pPriv->blockedOnMsc = FALSE;
687706f2543Smrg}
688706f2543Smrg
689706f2543Smrgstatic void
690706f2543SmrgDRI2WakeClient(ClientPtr client, DrawablePtr pDraw, int frame,
691706f2543Smrg	       unsigned int tv_sec, unsigned int tv_usec)
692706f2543Smrg{
693706f2543Smrg    ScreenPtr	    pScreen = pDraw->pScreen;
694706f2543Smrg    DRI2DrawablePtr pPriv;
695706f2543Smrg
696706f2543Smrg    pPriv = DRI2GetDrawable(pDraw);
697706f2543Smrg    if (pPriv == NULL) {
698706f2543Smrg        xf86DrvMsg(pScreen->myNum, X_ERROR,
699706f2543Smrg		   "[DRI2] %s: bad drawable\n", __func__);
700706f2543Smrg	return;
701706f2543Smrg    }
702706f2543Smrg
703706f2543Smrg    /*
704706f2543Smrg     * Swap completed.
705706f2543Smrg     * Wake the client iff:
706706f2543Smrg     *   - it was waiting on SBC
707706f2543Smrg     *   - was blocked due to GLX make current
708706f2543Smrg     *   - was blocked due to swap throttling
709706f2543Smrg     *   - is not blocked due to an MSC wait
710706f2543Smrg     */
711706f2543Smrg    if (pPriv->target_sbc != -1 &&
712706f2543Smrg	pPriv->target_sbc <= pPriv->swap_count) {
713706f2543Smrg	ProcDRI2WaitMSCReply(client, ((CARD64)tv_sec * 1000000) + tv_usec,
714706f2543Smrg			     frame, pPriv->swap_count);
715706f2543Smrg	pPriv->target_sbc = -1;
716706f2543Smrg
717706f2543Smrg	AttendClient(pPriv->blockedClient);
718706f2543Smrg	pPriv->blockedClient = NULL;
719706f2543Smrg    } else if (pPriv->target_sbc == -1 && !pPriv->blockedOnMsc) {
720706f2543Smrg	if (pPriv->blockedClient) {
721706f2543Smrg	    AttendClient(pPriv->blockedClient);
722706f2543Smrg	    pPriv->blockedClient = NULL;
723706f2543Smrg	}
724706f2543Smrg    }
725706f2543Smrg}
726706f2543Smrg
727706f2543Smrgvoid
728706f2543SmrgDRI2SwapComplete(ClientPtr client, DrawablePtr pDraw, int frame,
729706f2543Smrg		   unsigned int tv_sec, unsigned int tv_usec, int type,
730706f2543Smrg		   DRI2SwapEventPtr swap_complete, void *swap_data)
731706f2543Smrg{
732706f2543Smrg    ScreenPtr	    pScreen = pDraw->pScreen;
733706f2543Smrg    DRI2DrawablePtr pPriv;
734706f2543Smrg    CARD64          ust = 0;
735706f2543Smrg    BoxRec          box;
736706f2543Smrg    RegionRec       region;
737706f2543Smrg
738706f2543Smrg    pPriv = DRI2GetDrawable(pDraw);
739706f2543Smrg    if (pPriv == NULL) {
740706f2543Smrg        xf86DrvMsg(pScreen->myNum, X_ERROR,
741706f2543Smrg		   "[DRI2] %s: bad drawable\n", __func__);
742706f2543Smrg	return;
743706f2543Smrg    }
744706f2543Smrg
745706f2543Smrg    pPriv->swapsPending--;
746706f2543Smrg    pPriv->swap_count++;
747706f2543Smrg
748706f2543Smrg    box.x1 = 0;
749706f2543Smrg    box.y1 = 0;
750706f2543Smrg    box.x2 = pDraw->width;
751706f2543Smrg    box.y2 = pDraw->height;
752706f2543Smrg    RegionInit(&region, &box, 0);
753706f2543Smrg    DRI2CopyRegion(pDraw, &region, DRI2BufferFakeFrontLeft,
754706f2543Smrg		   DRI2BufferFrontLeft);
755706f2543Smrg
756706f2543Smrg    ust = ((CARD64)tv_sec * 1000000) + tv_usec;
757706f2543Smrg    if (swap_complete)
758706f2543Smrg	swap_complete(client, swap_data, type, ust, frame, pPriv->swap_count);
759706f2543Smrg
760706f2543Smrg    pPriv->last_swap_msc = frame;
761706f2543Smrg    pPriv->last_swap_ust = ust;
762706f2543Smrg
763706f2543Smrg    DRI2WakeClient(client, pDraw, frame, tv_sec, tv_usec);
764706f2543Smrg}
765706f2543Smrg
766706f2543SmrgBool
767706f2543SmrgDRI2WaitSwap(ClientPtr client, DrawablePtr pDrawable)
768706f2543Smrg{
769706f2543Smrg    DRI2DrawablePtr pPriv = DRI2GetDrawable(pDrawable);
770706f2543Smrg
771706f2543Smrg    /* If we're currently waiting for a swap on this drawable, reset
772706f2543Smrg     * the request and suspend the client.  We only support one
773706f2543Smrg     * blocked client per drawable. */
774706f2543Smrg    if (pPriv &&
775706f2543Smrg	pPriv->swapsPending &&
776706f2543Smrg	pPriv->blockedClient == NULL) {
777706f2543Smrg	ResetCurrentRequest(client);
778706f2543Smrg	client->sequence--;
779706f2543Smrg	__DRI2BlockClient(client, pPriv);
780706f2543Smrg	return TRUE;
781706f2543Smrg    }
782706f2543Smrg
783706f2543Smrg    return FALSE;
784706f2543Smrg}
785706f2543Smrg
786706f2543Smrgint
787706f2543SmrgDRI2SwapBuffers(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc,
788706f2543Smrg		CARD64 divisor, CARD64 remainder, CARD64 *swap_target,
789706f2543Smrg		DRI2SwapEventPtr func, void *data)
790706f2543Smrg{
791706f2543Smrg    ScreenPtr       pScreen = pDraw->pScreen;
792706f2543Smrg    DRI2ScreenPtr   ds = DRI2GetScreen(pDraw->pScreen);
793706f2543Smrg    DRI2DrawablePtr pPriv;
794706f2543Smrg    DRI2BufferPtr   pDestBuffer = NULL, pSrcBuffer = NULL;
795706f2543Smrg    int             ret, i;
796706f2543Smrg    CARD64          ust, current_msc;
797706f2543Smrg
798706f2543Smrg    pPriv = DRI2GetDrawable(pDraw);
799706f2543Smrg    if (pPriv == NULL) {
800706f2543Smrg        xf86DrvMsg(pScreen->myNum, X_ERROR,
801706f2543Smrg		   "[DRI2] %s: bad drawable\n", __func__);
802706f2543Smrg	return BadDrawable;
803706f2543Smrg    }
804706f2543Smrg
805706f2543Smrg    for (i = 0; i < pPriv->bufferCount; i++) {
806706f2543Smrg	if (pPriv->buffers[i]->attachment == DRI2BufferFrontLeft)
807706f2543Smrg	    pDestBuffer = (DRI2BufferPtr) pPriv->buffers[i];
808706f2543Smrg	if (pPriv->buffers[i]->attachment == DRI2BufferBackLeft)
809706f2543Smrg	    pSrcBuffer = (DRI2BufferPtr) pPriv->buffers[i];
810706f2543Smrg    }
811706f2543Smrg    if (pSrcBuffer == NULL || pDestBuffer == NULL) {
812706f2543Smrg        xf86DrvMsg(pScreen->myNum, X_ERROR,
813706f2543Smrg		   "[DRI2] %s: drawable has no back or front?\n", __func__);
814706f2543Smrg	return BadDrawable;
815706f2543Smrg    }
816706f2543Smrg
817706f2543Smrg    /* Old DDX or no swap interval, just blit */
818706f2543Smrg    if (!ds->ScheduleSwap || !pPriv->swap_interval) {
819706f2543Smrg	BoxRec box;
820706f2543Smrg	RegionRec region;
821706f2543Smrg
822706f2543Smrg	box.x1 = 0;
823706f2543Smrg	box.y1 = 0;
824706f2543Smrg	box.x2 = pDraw->width;
825706f2543Smrg	box.y2 = pDraw->height;
826706f2543Smrg	RegionInit(&region, &box, 0);
827706f2543Smrg
828706f2543Smrg	pPriv->swapsPending++;
829706f2543Smrg
830706f2543Smrg	(*ds->CopyRegion)(pDraw, &region, pDestBuffer, pSrcBuffer);
831706f2543Smrg	DRI2SwapComplete(client, pDraw, target_msc, 0, 0, DRI2_BLIT_COMPLETE,
832706f2543Smrg			 func, data);
833706f2543Smrg	return Success;
834706f2543Smrg    }
835706f2543Smrg
836706f2543Smrg    /*
837706f2543Smrg     * In the simple glXSwapBuffers case, all params will be 0, and we just
838706f2543Smrg     * need to schedule a swap for the last swap target + the swap interval.
839706f2543Smrg     */
840706f2543Smrg    if (target_msc == 0 && divisor == 0 && remainder == 0) {
841706f2543Smrg	/* If the current vblank count of the drawable's crtc is lower
842706f2543Smrg	 * than the count stored in last_swap_target from a previous swap
843706f2543Smrg	 * then reinitialize last_swap_target to the current crtc's msc,
844706f2543Smrg	 * otherwise the swap will hang. This will happen if the drawable
845706f2543Smrg	 * is moved to a crtc with a lower refresh rate, or a crtc that just
846706f2543Smrg	 * got enabled.
847706f2543Smrg	 */
848706f2543Smrg	if (ds->GetMSC) {
849706f2543Smrg	    if (!(*ds->GetMSC)(pDraw, &ust, &current_msc))
850706f2543Smrg		pPriv->last_swap_target = 0;
851706f2543Smrg
852706f2543Smrg	    if (current_msc < pPriv->last_swap_target)
853706f2543Smrg		pPriv->last_swap_target = current_msc;
854706f2543Smrg
855706f2543Smrg	}
856706f2543Smrg
857706f2543Smrg	/*
858706f2543Smrg	 * Swap target for this swap is last swap target + swap interval since
859706f2543Smrg	 * we have to account for the current swap count, interval, and the
860706f2543Smrg	 * number of pending swaps.
861706f2543Smrg	 */
862706f2543Smrg	*swap_target = pPriv->last_swap_target + pPriv->swap_interval;
863706f2543Smrg
864706f2543Smrg    } else {
865706f2543Smrg	/* glXSwapBuffersMscOML could have a 0 target_msc, honor it */
866706f2543Smrg	*swap_target = target_msc;
867706f2543Smrg    }
868706f2543Smrg
869706f2543Smrg    pPriv->swapsPending++;
870706f2543Smrg    ret = (*ds->ScheduleSwap)(client, pDraw, pDestBuffer, pSrcBuffer,
871706f2543Smrg			      swap_target, divisor, remainder, func, data);
872706f2543Smrg    if (!ret) {
873706f2543Smrg	pPriv->swapsPending--; /* didn't schedule */
874706f2543Smrg        xf86DrvMsg(pScreen->myNum, X_ERROR,
875706f2543Smrg		   "[DRI2] %s: driver failed to schedule swap\n", __func__);
876706f2543Smrg	return BadDrawable;
877706f2543Smrg    }
878706f2543Smrg
879706f2543Smrg    pPriv->last_swap_target = *swap_target;
880706f2543Smrg
881706f2543Smrg    /* According to spec, return expected swapbuffers count SBC after this swap
882706f2543Smrg     * will complete.
883706f2543Smrg     */
884706f2543Smrg    *swap_target = pPriv->swap_count + pPriv->swapsPending;
885706f2543Smrg
886706f2543Smrg    DRI2InvalidateDrawable(pDraw);
887706f2543Smrg
888706f2543Smrg    return Success;
889706f2543Smrg}
890706f2543Smrg
891706f2543Smrgvoid
892706f2543SmrgDRI2SwapInterval(DrawablePtr pDrawable, int interval)
893706f2543Smrg{
894706f2543Smrg    ScreenPtr       pScreen = pDrawable->pScreen;
895706f2543Smrg    DRI2DrawablePtr pPriv = DRI2GetDrawable(pDrawable);
896706f2543Smrg
897706f2543Smrg    if (pPriv == NULL) {
898706f2543Smrg        xf86DrvMsg(pScreen->myNum, X_ERROR,
899706f2543Smrg		   "[DRI2] %s: bad drawable\n", __func__);
900706f2543Smrg	return;
901706f2543Smrg    }
902706f2543Smrg
903706f2543Smrg    /* fixme: check against arbitrary max? */
904706f2543Smrg    pPriv->swap_interval = interval;
905706f2543Smrg}
906706f2543Smrg
907706f2543Smrgint
908706f2543SmrgDRI2GetMSC(DrawablePtr pDraw, CARD64 *ust, CARD64 *msc, CARD64 *sbc)
909706f2543Smrg{
910706f2543Smrg    ScreenPtr pScreen = pDraw->pScreen;
911706f2543Smrg    DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen);
912706f2543Smrg    DRI2DrawablePtr pPriv;
913706f2543Smrg    Bool ret;
914706f2543Smrg
915706f2543Smrg    pPriv = DRI2GetDrawable(pDraw);
916706f2543Smrg    if (pPriv == NULL) {
917706f2543Smrg        xf86DrvMsg(pScreen->myNum, X_ERROR,
918706f2543Smrg		   "[DRI2] %s: bad drawable\n", __func__);
919706f2543Smrg	return BadDrawable;
920706f2543Smrg    }
921706f2543Smrg
922706f2543Smrg    if (!ds->GetMSC) {
923706f2543Smrg	*ust = 0;
924706f2543Smrg	*msc = 0;
925706f2543Smrg	*sbc = pPriv->swap_count;
926706f2543Smrg	return Success;
927706f2543Smrg    }
928706f2543Smrg
929706f2543Smrg    /*
930706f2543Smrg     * Spec needs to be updated to include unmapped or redirected
931706f2543Smrg     * drawables
932706f2543Smrg     */
933706f2543Smrg
934706f2543Smrg    ret = (*ds->GetMSC)(pDraw, ust, msc);
935706f2543Smrg    if (!ret)
936706f2543Smrg	return BadDrawable;
937706f2543Smrg
938706f2543Smrg    *sbc = pPriv->swap_count;
939706f2543Smrg
940706f2543Smrg    return Success;
941706f2543Smrg}
942706f2543Smrg
943706f2543Smrgint
944706f2543SmrgDRI2WaitMSC(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc,
945706f2543Smrg	    CARD64 divisor, CARD64 remainder)
946706f2543Smrg{
947706f2543Smrg    DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen);
948706f2543Smrg    DRI2DrawablePtr pPriv;
949706f2543Smrg    Bool ret;
950706f2543Smrg
951706f2543Smrg    pPriv = DRI2GetDrawable(pDraw);
952706f2543Smrg    if (pPriv == NULL)
953706f2543Smrg	return BadDrawable;
954706f2543Smrg
955706f2543Smrg    /* Old DDX just completes immediately */
956706f2543Smrg    if (!ds->ScheduleWaitMSC) {
957706f2543Smrg	DRI2WaitMSCComplete(client, pDraw, target_msc, 0, 0);
958706f2543Smrg
959706f2543Smrg	return Success;
960706f2543Smrg    }
961706f2543Smrg
962706f2543Smrg    ret = (*ds->ScheduleWaitMSC)(client, pDraw, target_msc, divisor, remainder);
963706f2543Smrg    if (!ret)
964706f2543Smrg	return BadDrawable;
965706f2543Smrg
966706f2543Smrg    return Success;
967706f2543Smrg}
968706f2543Smrg
969706f2543Smrgint
970706f2543SmrgDRI2WaitSBC(ClientPtr client, DrawablePtr pDraw, CARD64 target_sbc)
971706f2543Smrg{
972706f2543Smrg    DRI2DrawablePtr pPriv;
973706f2543Smrg
974706f2543Smrg    pPriv = DRI2GetDrawable(pDraw);
975706f2543Smrg    if (pPriv == NULL)
976706f2543Smrg	return BadDrawable;
977706f2543Smrg
978706f2543Smrg    /* target_sbc == 0 means to block until all pending swaps are
979706f2543Smrg     * finished. Recalculate target_sbc to get that behaviour.
980706f2543Smrg     */
981706f2543Smrg    if (target_sbc == 0)
982706f2543Smrg        target_sbc = pPriv->swap_count + pPriv->swapsPending;
983706f2543Smrg
984706f2543Smrg    /* If current swap count already >= target_sbc, reply and
985706f2543Smrg     * return immediately with (ust, msc, sbc) triplet of
986706f2543Smrg     * most recent completed swap.
987706f2543Smrg     */
988706f2543Smrg    if (pPriv->swap_count >= target_sbc) {
989706f2543Smrg        ProcDRI2WaitMSCReply(client, pPriv->last_swap_ust,
990706f2543Smrg                             pPriv->last_swap_msc, pPriv->swap_count);
991706f2543Smrg        return Success;
992706f2543Smrg    }
993706f2543Smrg
994706f2543Smrg    pPriv->target_sbc = target_sbc;
995706f2543Smrg    __DRI2BlockClient(client, pPriv);
996706f2543Smrg
997706f2543Smrg    return Success;
998706f2543Smrg}
999706f2543Smrg
1000706f2543SmrgBool
1001706f2543SmrgDRI2HasSwapControl(ScreenPtr pScreen)
1002706f2543Smrg{
1003706f2543Smrg    DRI2ScreenPtr ds = DRI2GetScreen(pScreen);
1004706f2543Smrg
1005706f2543Smrg    return ds->ScheduleSwap && ds->GetMSC;
1006706f2543Smrg}
1007706f2543Smrg
1008706f2543SmrgBool
1009706f2543SmrgDRI2Connect(ScreenPtr pScreen, unsigned int driverType, int *fd,
1010706f2543Smrg	    const char **driverName, const char **deviceName)
1011706f2543Smrg{
1012706f2543Smrg    DRI2ScreenPtr ds;
1013706f2543Smrg
1014706f2543Smrg    if (!dixPrivateKeyRegistered(dri2ScreenPrivateKey))
1015706f2543Smrg	return FALSE;
1016706f2543Smrg
1017706f2543Smrg    ds = DRI2GetScreen(pScreen);
1018706f2543Smrg    if (ds == NULL || driverType >= ds->numDrivers ||
1019706f2543Smrg	    !ds->driverNames[driverType])
1020706f2543Smrg	return FALSE;
1021706f2543Smrg
1022706f2543Smrg    *fd = ds->fd;
1023706f2543Smrg    *driverName = ds->driverNames[driverType];
1024706f2543Smrg    *deviceName = ds->deviceName;
1025706f2543Smrg
1026706f2543Smrg    return TRUE;
1027706f2543Smrg}
1028706f2543Smrg
1029706f2543SmrgBool
1030706f2543SmrgDRI2Authenticate(ScreenPtr pScreen, uint32_t magic)
1031706f2543Smrg{
1032706f2543Smrg    DRI2ScreenPtr ds = DRI2GetScreen(pScreen);
1033706f2543Smrg
1034706f2543Smrg    if (ds == NULL || (*ds->AuthMagic)(ds->fd, magic))
1035706f2543Smrg        return FALSE;
1036706f2543Smrg
1037706f2543Smrg    return TRUE;
1038706f2543Smrg}
1039706f2543Smrg
1040706f2543Smrgstatic int
1041706f2543SmrgDRI2ConfigNotify(WindowPtr pWin, int x, int y, int w, int h, int bw,
1042706f2543Smrg		 WindowPtr pSib)
1043706f2543Smrg{
1044706f2543Smrg    DrawablePtr pDraw = (DrawablePtr)pWin;
1045706f2543Smrg    ScreenPtr pScreen = pDraw->pScreen;
1046706f2543Smrg    DRI2ScreenPtr ds = DRI2GetScreen(pScreen);
1047706f2543Smrg    DRI2DrawablePtr dd = DRI2GetDrawable(pDraw);
1048706f2543Smrg    int ret;
1049706f2543Smrg
1050706f2543Smrg    if (ds->ConfigNotify) {
1051706f2543Smrg	pScreen->ConfigNotify = ds->ConfigNotify;
1052706f2543Smrg
1053706f2543Smrg	ret = (*pScreen->ConfigNotify)(pWin, x, y, w, h, bw, pSib);
1054706f2543Smrg
1055706f2543Smrg	ds->ConfigNotify = pScreen->ConfigNotify;
1056706f2543Smrg	pScreen->ConfigNotify = DRI2ConfigNotify;
1057706f2543Smrg	if (ret)
1058706f2543Smrg	    return ret;
1059706f2543Smrg    }
1060706f2543Smrg
1061706f2543Smrg    if (!dd || (dd->width == w && dd->height == h))
1062706f2543Smrg	return Success;
1063706f2543Smrg
1064706f2543Smrg    DRI2InvalidateDrawable(pDraw);
1065706f2543Smrg    return Success;
1066706f2543Smrg}
1067706f2543Smrg
1068706f2543SmrgBool
1069706f2543SmrgDRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info)
1070706f2543Smrg{
1071706f2543Smrg    DRI2ScreenPtr ds;
1072706f2543Smrg    const char* driverTypeNames[] = {
1073706f2543Smrg	"DRI", /* DRI2DriverDRI */
1074706f2543Smrg	"VDPAU", /* DRI2DriverVDPAU */
1075706f2543Smrg    };
1076706f2543Smrg    unsigned int i;
1077706f2543Smrg    CARD8 cur_minor;
1078706f2543Smrg
1079706f2543Smrg    if (info->version < 3)
1080706f2543Smrg	return FALSE;
1081706f2543Smrg
1082706f2543Smrg    if (!xf86VGAarbiterAllowDRI(pScreen)) {
1083706f2543Smrg        xf86DrvMsg(pScreen->myNum, X_WARNING,
1084706f2543Smrg                  "[DRI2] Direct rendering is not supported when VGA arb is necessary for the device\n");
1085706f2543Smrg        return FALSE;
1086706f2543Smrg    }
1087706f2543Smrg
1088706f2543Smrg    if (!dixRegisterPrivateKey(&dri2ScreenPrivateKeyRec, PRIVATE_SCREEN, 0))
1089706f2543Smrg	return FALSE;
1090706f2543Smrg
1091706f2543Smrg    if (!dixRegisterPrivateKey(&dri2WindowPrivateKeyRec, PRIVATE_WINDOW, 0))
1092706f2543Smrg	return FALSE;
1093706f2543Smrg
1094706f2543Smrg    if (!dixRegisterPrivateKey(&dri2PixmapPrivateKeyRec, PRIVATE_PIXMAP, 0))
1095706f2543Smrg	return FALSE;
1096706f2543Smrg
1097706f2543Smrg    ds = calloc(1, sizeof *ds);
1098706f2543Smrg    if (!ds)
1099706f2543Smrg	return FALSE;
1100706f2543Smrg
1101706f2543Smrg    ds->screen         = pScreen;
1102706f2543Smrg    ds->fd	       = info->fd;
1103706f2543Smrg    ds->deviceName     = info->deviceName;
1104706f2543Smrg    dri2_major         = 1;
1105706f2543Smrg
1106706f2543Smrg    ds->CreateBuffer   = info->CreateBuffer;
1107706f2543Smrg    ds->DestroyBuffer  = info->DestroyBuffer;
1108706f2543Smrg    ds->CopyRegion     = info->CopyRegion;
1109706f2543Smrg
1110706f2543Smrg    if (info->version >= 4) {
1111706f2543Smrg	ds->ScheduleSwap = info->ScheduleSwap;
1112706f2543Smrg	ds->ScheduleWaitMSC = info->ScheduleWaitMSC;
1113706f2543Smrg	ds->GetMSC = info->GetMSC;
1114706f2543Smrg	cur_minor = 3;
1115706f2543Smrg    } else {
1116706f2543Smrg	cur_minor = 1;
1117706f2543Smrg    }
1118706f2543Smrg
1119706f2543Smrg    if (info->version >= 5) {
1120706f2543Smrg        ds->AuthMagic = info->AuthMagic;
1121706f2543Smrg    }
1122706f2543Smrg
1123706f2543Smrg    /*
1124706f2543Smrg     * if the driver doesn't provide an AuthMagic function or the info struct
1125706f2543Smrg     * version is too low, it relies on the old method (using libdrm) or fail
1126706f2543Smrg     */
1127706f2543Smrg    if (!ds->AuthMagic)
1128706f2543Smrg#ifdef WITH_LIBDRM
1129706f2543Smrg        ds->AuthMagic = drmAuthMagic;
1130706f2543Smrg#else
1131706f2543Smrg        goto err_out;
1132706f2543Smrg#endif
1133706f2543Smrg
1134706f2543Smrg    /* Initialize minor if needed and set to minimum provied by DDX */
1135706f2543Smrg    if (!dri2_minor || dri2_minor > cur_minor)
1136706f2543Smrg	dri2_minor = cur_minor;
1137706f2543Smrg
1138706f2543Smrg    if (info->version == 3 || info->numDrivers == 0) {
1139706f2543Smrg	/* Driver too old: use the old-style driverName field */
1140706f2543Smrg	ds->numDrivers = 1;
1141706f2543Smrg	ds->driverNames = malloc(sizeof(*ds->driverNames));
1142706f2543Smrg	if (!ds->driverNames)
1143706f2543Smrg	    goto err_out;
1144706f2543Smrg	ds->driverNames[0] = info->driverName;
1145706f2543Smrg    } else {
1146706f2543Smrg	ds->numDrivers = info->numDrivers;
1147706f2543Smrg	ds->driverNames = malloc(info->numDrivers * sizeof(*ds->driverNames));
1148706f2543Smrg	if (!ds->driverNames)
1149706f2543Smrg		goto err_out;
1150706f2543Smrg	memcpy(ds->driverNames, info->driverNames,
1151706f2543Smrg	       info->numDrivers * sizeof(*ds->driverNames));
1152706f2543Smrg    }
1153706f2543Smrg
1154706f2543Smrg    dixSetPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey, ds);
1155706f2543Smrg
1156706f2543Smrg    ds->ConfigNotify = pScreen->ConfigNotify;
1157706f2543Smrg    pScreen->ConfigNotify = DRI2ConfigNotify;
1158706f2543Smrg
1159706f2543Smrg    xf86DrvMsg(pScreen->myNum, X_INFO, "[DRI2] Setup complete\n");
1160706f2543Smrg    for (i = 0; i < sizeof(driverTypeNames) / sizeof(driverTypeNames[0]); i++) {
1161706f2543Smrg	if (i < ds->numDrivers && ds->driverNames[i]) {
1162706f2543Smrg	    xf86DrvMsg(pScreen->myNum, X_INFO, "[DRI2]   %s driver: %s\n",
1163706f2543Smrg		       driverTypeNames[i], ds->driverNames[i]);
1164706f2543Smrg	}
1165706f2543Smrg    }
1166706f2543Smrg
1167706f2543Smrg    return TRUE;
1168706f2543Smrg
1169706f2543Smrgerr_out:
1170706f2543Smrg    xf86DrvMsg(pScreen->myNum, X_WARNING,
1171706f2543Smrg            "[DRI2] Initialization failed for info version %d.\n", info->version);
1172706f2543Smrg    free(ds);
1173706f2543Smrg    return FALSE;
1174706f2543Smrg}
1175706f2543Smrg
1176706f2543Smrgvoid
1177706f2543SmrgDRI2CloseScreen(ScreenPtr pScreen)
1178706f2543Smrg{
1179706f2543Smrg    DRI2ScreenPtr ds = DRI2GetScreen(pScreen);
1180706f2543Smrg
1181706f2543Smrg    free(ds->driverNames);
1182706f2543Smrg    free(ds);
1183706f2543Smrg    dixSetPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey, NULL);
1184706f2543Smrg}
1185706f2543Smrg
1186706f2543Smrgextern ExtensionModule dri2ExtensionModule;
1187706f2543Smrgextern Bool DRI2ModuleSetup(void);
1188706f2543Smrg
1189706f2543Smrg/* Called by InitExtensions() */
1190706f2543SmrgBool
1191706f2543SmrgDRI2ModuleSetup(void)
1192706f2543Smrg{
1193706f2543Smrg    dri2DrawableRes = CreateNewResourceType(DRI2DrawableGone, "DRI2Drawable");
1194706f2543Smrg    if (!dri2DrawableRes)
1195706f2543Smrg	return FALSE;
1196706f2543Smrg
1197706f2543Smrg    return TRUE;
1198706f2543Smrg}
1199706f2543Smrg
1200706f2543Smrgstatic pointer
1201706f2543SmrgDRI2Setup(pointer module, pointer opts, int *errmaj, int *errmin)
1202706f2543Smrg{
1203706f2543Smrg    static Bool setupDone = FALSE;
1204706f2543Smrg
1205706f2543Smrg    if (!setupDone)
1206706f2543Smrg    {
1207706f2543Smrg	setupDone = TRUE;
1208706f2543Smrg	LoadExtension(&dri2ExtensionModule, FALSE);
1209706f2543Smrg    }
1210706f2543Smrg    else
1211706f2543Smrg    {
1212706f2543Smrg	if (errmaj)
1213706f2543Smrg	    *errmaj = LDR_ONCEONLY;
1214706f2543Smrg    }
1215706f2543Smrg
1216706f2543Smrg    return (pointer) 1;
1217706f2543Smrg}
1218706f2543Smrg
1219706f2543Smrgstatic XF86ModuleVersionInfo DRI2VersRec =
1220706f2543Smrg{
1221706f2543Smrg    "dri2",
1222706f2543Smrg    MODULEVENDORSTRING,
1223706f2543Smrg    MODINFOSTRING1,
1224706f2543Smrg    MODINFOSTRING2,
1225706f2543Smrg    XORG_VERSION_CURRENT,
1226706f2543Smrg    1, 2, 0,
1227706f2543Smrg    ABI_CLASS_EXTENSION,
1228706f2543Smrg    ABI_EXTENSION_VERSION,
1229706f2543Smrg    MOD_CLASS_NONE,
1230706f2543Smrg    { 0, 0, 0, 0 }
1231706f2543Smrg};
1232706f2543Smrg
1233706f2543Smrg_X_EXPORT XF86ModuleData dri2ModuleData = { &DRI2VersRec, DRI2Setup, NULL };
1234706f2543Smrg
1235706f2543Smrgvoid
1236706f2543SmrgDRI2Version(int *major, int *minor)
1237706f2543Smrg{
1238706f2543Smrg    if (major != NULL)
1239706f2543Smrg	*major = DRI2VersRec.majorversion;
1240706f2543Smrg
1241706f2543Smrg    if (minor != NULL)
1242706f2543Smrg	*minor = DRI2VersRec.minorversion;
1243706f2543Smrg}
1244