14642e01fSmrg/*
24642e01fSmrg * Copyright © 2007, 2008 Red Hat, Inc.
34642e01fSmrg *
44642e01fSmrg * Permission is hereby granted, free of charge, to any person obtaining a
54642e01fSmrg * copy of this software and associated documentation files (the "Soft-
64642e01fSmrg * ware"), to deal in the Software without restriction, including without
74642e01fSmrg * limitation the rights to use, copy, modify, merge, publish, distribute,
84642e01fSmrg * and/or sell copies of the Software, and to permit persons to whom the
94642e01fSmrg * Software is furnished to do so, provided that the above copyright
104642e01fSmrg * notice(s) and this permission notice appear in all copies of the Soft-
114642e01fSmrg * ware and that both the above copyright notice(s) and this permission
124642e01fSmrg * notice appear in supporting documentation.
134642e01fSmrg *
144642e01fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
154642e01fSmrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
164642e01fSmrg * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
174642e01fSmrg * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
184642e01fSmrg * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
194642e01fSmrg * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
204642e01fSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
214642e01fSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
224642e01fSmrg * MANCE OF THIS SOFTWARE.
234642e01fSmrg *
244642e01fSmrg * Except as contained in this notice, the name of a copyright holder shall
254642e01fSmrg * not be used in advertising or otherwise to promote the sale, use or
264642e01fSmrg * other dealings in this Software without prior written authorization of
274642e01fSmrg * the copyright holder.
284642e01fSmrg *
294642e01fSmrg * Authors:
304642e01fSmrg *   Kristian Høgsberg (krh@redhat.com)
314642e01fSmrg */
324642e01fSmrg
334642e01fSmrg#ifdef HAVE_XORG_CONFIG_H
344642e01fSmrg#include <xorg-config.h>
354642e01fSmrg#endif
364642e01fSmrg
376747b715Smrg#include <errno.h>
386747b715Smrg#ifdef WITH_LIBDRM
394642e01fSmrg#include <xf86drm.h>
406747b715Smrg#endif
416747b715Smrg#include "list.h"
424642e01fSmrg#include "scrnintstr.h"
434642e01fSmrg#include "windowstr.h"
446747b715Smrg#include "dixstruct.h"
454642e01fSmrg#include "dri2.h"
46f7df2e56Smrg#include "dri2int.h"
47f7df2e56Smrg#include "damage.h"
484642e01fSmrg#include "xf86.h"
494642e01fSmrg
50f7df2e56SmrgCARD8 dri2_major;               /* version of DRI2 supported by DDX */
516747b715SmrgCARD8 dri2_minor;
526747b715Smrg
53f7df2e56Smrguint32_t prime_id_allocate_bitmask;
54f7df2e56Smrg
556747b715Smrgstatic DevPrivateKeyRec dri2ScreenPrivateKeyRec;
56f7df2e56Smrg
576747b715Smrg#define dri2ScreenPrivateKey (&dri2ScreenPrivateKeyRec)
586747b715Smrg
596747b715Smrgstatic DevPrivateKeyRec dri2WindowPrivateKeyRec;
60f7df2e56Smrg
616747b715Smrg#define dri2WindowPrivateKey (&dri2WindowPrivateKeyRec)
626747b715Smrg
636747b715Smrgstatic DevPrivateKeyRec dri2PixmapPrivateKeyRec;
64f7df2e56Smrg
656747b715Smrg#define dri2PixmapPrivateKey (&dri2PixmapPrivateKeyRec)
666747b715Smrg
67f7df2e56Smrgstatic DevPrivateKeyRec dri2ClientPrivateKeyRec;
68f7df2e56Smrg
69f7df2e56Smrg#define dri2ClientPrivateKey (&dri2ClientPrivateKeyRec)
70f7df2e56Smrg
71f7df2e56Smrg#define dri2ClientPrivate(_pClient) (dixLookupPrivate(&(_pClient)->devPrivates, \
72f7df2e56Smrg                                                      dri2ClientPrivateKey))
73f7df2e56Smrg
74f7df2e56Smrgtypedef struct _DRI2Client {
75f7df2e56Smrg    int prime_id;
76f7df2e56Smrg} DRI2ClientRec, *DRI2ClientPtr;
77f7df2e56Smrg
78f7df2e56Smrgstatic RESTYPE dri2DrawableRes;
796747b715Smrg
806747b715Smrgtypedef struct _DRI2Screen *DRI2ScreenPtr;
814642e01fSmrg
824642e01fSmrgtypedef struct _DRI2Drawable {
83f7df2e56Smrg    DRI2ScreenPtr dri2_screen;
84f7df2e56Smrg    DrawablePtr drawable;
85f7df2e56Smrg    struct xorg_list reference_list;
86f7df2e56Smrg    int width;
87f7df2e56Smrg    int height;
88f7df2e56Smrg    DRI2BufferPtr *buffers;
89f7df2e56Smrg    int bufferCount;
90f7df2e56Smrg    unsigned int swapsPending;
91f7df2e56Smrg    int swap_interval;
92f7df2e56Smrg    CARD64 swap_count;
93f7df2e56Smrg    int64_t target_sbc;         /* -1 means no SBC wait outstanding */
94f7df2e56Smrg    CARD64 last_swap_target;    /* most recently queued swap target */
95f7df2e56Smrg    CARD64 last_swap_msc;       /* msc at completion of most recent swap */
96f7df2e56Smrg    CARD64 last_swap_ust;       /* ust at completion of most recent swap */
97f7df2e56Smrg    int swap_limit;             /* for N-buffering */
98f7df2e56Smrg    unsigned blocked[3];
99f7df2e56Smrg    Bool needInvalidate;
100f7df2e56Smrg    int prime_id;
1015a112b11Smrg    PixmapPtr prime_secondary_pixmap;
102f7df2e56Smrg    PixmapPtr redirectpixmap;
1034642e01fSmrg} DRI2DrawableRec, *DRI2DrawablePtr;
1044642e01fSmrg
1054642e01fSmrgtypedef struct _DRI2Screen {
106f7df2e56Smrg    ScreenPtr screen;
107f7df2e56Smrg    int refcnt;
108f7df2e56Smrg    unsigned int numDrivers;
109f7df2e56Smrg    const char **driverNames;
110f7df2e56Smrg    const char *deviceName;
111f7df2e56Smrg    int fd;
112f7df2e56Smrg    unsigned int lastSequence;
113f7df2e56Smrg    int prime_id;
114f7df2e56Smrg
115f7df2e56Smrg    DRI2CreateBufferProcPtr CreateBuffer;
116f7df2e56Smrg    DRI2DestroyBufferProcPtr DestroyBuffer;
117f7df2e56Smrg    DRI2CopyRegionProcPtr CopyRegion;
118f7df2e56Smrg    DRI2ScheduleSwapProcPtr ScheduleSwap;
119f7df2e56Smrg    DRI2GetMSCProcPtr GetMSC;
120f7df2e56Smrg    DRI2ScheduleWaitMSCProcPtr ScheduleWaitMSC;
121f7df2e56Smrg    DRI2AuthMagic2ProcPtr AuthMagic;
122f7df2e56Smrg    DRI2AuthMagicProcPtr LegacyAuthMagic;
123f7df2e56Smrg    DRI2ReuseBufferNotifyProcPtr ReuseBufferNotify;
124f7df2e56Smrg    DRI2SwapLimitValidateProcPtr SwapLimitValidate;
125f7df2e56Smrg    DRI2GetParamProcPtr GetParam;
126f7df2e56Smrg
127f7df2e56Smrg    HandleExposuresProcPtr HandleExposures;
128f7df2e56Smrg
129f7df2e56Smrg    ConfigNotifyProcPtr ConfigNotify;
130f7df2e56Smrg    SetWindowPixmapProcPtr SetWindowPixmap;
131f7df2e56Smrg    DRI2CreateBuffer2ProcPtr CreateBuffer2;
132f7df2e56Smrg    DRI2DestroyBuffer2ProcPtr DestroyBuffer2;
133f7df2e56Smrg    DRI2CopyRegion2ProcPtr CopyRegion2;
1346747b715Smrg} DRI2ScreenRec;
1354642e01fSmrg
136f7df2e56Smrgstatic void
137f7df2e56Smrgdestroy_buffer(DrawablePtr pDraw, DRI2BufferPtr buffer, int prime_id);
138f7df2e56Smrg
139f7df2e56Smrgenum DRI2WakeType {
140f7df2e56Smrg    WAKE_SBC,
141f7df2e56Smrg    WAKE_MSC,
142f7df2e56Smrg    WAKE_SWAP,
143f7df2e56Smrg};
144f7df2e56Smrg
145f7df2e56Smrg#define Wake(c, t) (void *)((uintptr_t)(c) | (t))
146f7df2e56Smrg
147f7df2e56Smrgstatic Bool
148f7df2e56Smrgdri2WakeClient(ClientPtr client, void *closure)
149f7df2e56Smrg{
150f7df2e56Smrg    ClientWakeup(client);
151f7df2e56Smrg    return TRUE;
152f7df2e56Smrg}
153f7df2e56Smrg
154f7df2e56Smrgstatic Bool
155f7df2e56Smrgdri2WakeAll(ClientPtr client, DRI2DrawablePtr pPriv, enum DRI2WakeType t)
156f7df2e56Smrg{
157f7df2e56Smrg    int count;
158f7df2e56Smrg
159f7df2e56Smrg    if (!pPriv->blocked[t])
160f7df2e56Smrg        return FALSE;
161f7df2e56Smrg
162f7df2e56Smrg    count = ClientSignalAll(client, dri2WakeClient, Wake(pPriv, t));
163f7df2e56Smrg    pPriv->blocked[t] -= count;
164f7df2e56Smrg    return count;
165f7df2e56Smrg}
166f7df2e56Smrg
167f7df2e56Smrgstatic Bool
168f7df2e56Smrgdri2Sleep(ClientPtr client, DRI2DrawablePtr pPriv, enum DRI2WakeType t)
169f7df2e56Smrg{
170f7df2e56Smrg    if (ClientSleep(client, dri2WakeClient, Wake(pPriv, t))) {
171f7df2e56Smrg        pPriv->blocked[t]++;
172f7df2e56Smrg        return TRUE;
173f7df2e56Smrg    }
174f7df2e56Smrg    return FALSE;
175f7df2e56Smrg}
176f7df2e56Smrg
1774642e01fSmrgstatic DRI2ScreenPtr
1784642e01fSmrgDRI2GetScreen(ScreenPtr pScreen)
1794642e01fSmrg{
1804642e01fSmrg    return dixLookupPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey);
1814642e01fSmrg}
1824642e01fSmrg
183f7df2e56Smrgstatic ScreenPtr
1845a112b11SmrgGetScreenPrime(ScreenPtr primary, int prime_id)
185f7df2e56Smrg{
1865a112b11Smrg    ScreenPtr secondary;
1877e31ba66Smrg    if (prime_id == 0) {
1885a112b11Smrg        return primary;
189f7df2e56Smrg    }
1905a112b11Smrg    xorg_list_for_each_entry(secondary, &primary->secondary_list, secondary_head) {
191f7df2e56Smrg        DRI2ScreenPtr ds;
192f7df2e56Smrg
1935a112b11Smrg        if (!secondary->is_offload_secondary)
1947e31ba66Smrg            continue;
1957e31ba66Smrg
1965a112b11Smrg        ds = DRI2GetScreen(secondary);
197f7df2e56Smrg        if (ds == NULL)
198f7df2e56Smrg            continue;
199f7df2e56Smrg
200f7df2e56Smrg        if (ds->prime_id == prime_id)
2015a112b11Smrg            return secondary;
202f7df2e56Smrg    }
2035a112b11Smrg    return primary;
204f7df2e56Smrg}
205f7df2e56Smrg
206f7df2e56Smrgstatic DRI2ScreenPtr
2075a112b11SmrgDRI2GetScreenPrime(ScreenPtr primary, int prime_id)
208f7df2e56Smrg{
2095a112b11Smrg    ScreenPtr secondary = GetScreenPrime(primary, prime_id);
2105a112b11Smrg    return DRI2GetScreen(secondary);
211f7df2e56Smrg}
212f7df2e56Smrg
2134642e01fSmrgstatic DRI2DrawablePtr
2144642e01fSmrgDRI2GetDrawable(DrawablePtr pDraw)
2154642e01fSmrg{
2166747b715Smrg    WindowPtr pWin;
2176747b715Smrg    PixmapPtr pPixmap;
2184642e01fSmrg
2196747b715Smrg    switch (pDraw->type) {
2206747b715Smrg    case DRAWABLE_WINDOW:
221f7df2e56Smrg        pWin = (WindowPtr) pDraw;
222f7df2e56Smrg        return dixLookupPrivate(&pWin->devPrivates, dri2WindowPrivateKey);
2236747b715Smrg    case DRAWABLE_PIXMAP:
224f7df2e56Smrg        pPixmap = (PixmapPtr) pDraw;
225f7df2e56Smrg        return dixLookupPrivate(&pPixmap->devPrivates, dri2PixmapPrivateKey);
2266747b715Smrg    default:
227f7df2e56Smrg        return NULL;
2284642e01fSmrg    }
2294642e01fSmrg}
2304642e01fSmrg
2316747b715Smrgstatic DRI2DrawablePtr
2326747b715SmrgDRI2AllocateDrawable(DrawablePtr pDraw)
2336747b715Smrg{
234f7df2e56Smrg    DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen);
2356747b715Smrg    DRI2DrawablePtr pPriv;
236f7df2e56Smrg    CARD64 ust;
2376747b715Smrg    WindowPtr pWin;
2386747b715Smrg    PixmapPtr pPixmap;
2396747b715Smrg
2406747b715Smrg    pPriv = malloc(sizeof *pPriv);
2414642e01fSmrg    if (pPriv == NULL)
242f7df2e56Smrg        return NULL;
2434642e01fSmrg
2446747b715Smrg    pPriv->dri2_screen = ds;
2456747b715Smrg    pPriv->drawable = pDraw;
2464642e01fSmrg    pPriv->width = pDraw->width;
2474642e01fSmrg    pPriv->height = pDraw->height;
2484642e01fSmrg    pPriv->buffers = NULL;
2494642e01fSmrg    pPriv->bufferCount = 0;
2506747b715Smrg    pPriv->swapsPending = 0;
2516747b715Smrg    pPriv->swap_count = 0;
2526747b715Smrg    pPriv->target_sbc = -1;
2536747b715Smrg    pPriv->swap_interval = 1;
2546747b715Smrg    /* Initialize last swap target from DDX if possible */
255f7df2e56Smrg    if (!ds->GetMSC || !(*ds->GetMSC) (pDraw, &ust, &pPriv->last_swap_target))
256f7df2e56Smrg        pPriv->last_swap_target = 0;
2576747b715Smrg
258f7df2e56Smrg    memset(pPriv->blocked, 0, sizeof(pPriv->blocked));
259f7df2e56Smrg    pPriv->swap_limit = 1;      /* default to double buffering */
2606747b715Smrg    pPriv->last_swap_msc = 0;
2616747b715Smrg    pPriv->last_swap_ust = 0;
262f7df2e56Smrg    xorg_list_init(&pPriv->reference_list);
263f7df2e56Smrg    pPriv->needInvalidate = FALSE;
264f7df2e56Smrg    pPriv->redirectpixmap = NULL;
2655a112b11Smrg    pPriv->prime_secondary_pixmap = NULL;
2666747b715Smrg    if (pDraw->type == DRAWABLE_WINDOW) {
267f7df2e56Smrg        pWin = (WindowPtr) pDraw;
268f7df2e56Smrg        dixSetPrivate(&pWin->devPrivates, dri2WindowPrivateKey, pPriv);
269f7df2e56Smrg    }
270f7df2e56Smrg    else {
271f7df2e56Smrg        pPixmap = (PixmapPtr) pDraw;
272f7df2e56Smrg        dixSetPrivate(&pPixmap->devPrivates, dri2PixmapPrivateKey, pPriv);
2734642e01fSmrg    }
2744642e01fSmrg
2756747b715Smrg    return pPriv;
2766747b715Smrg}
2776747b715Smrg
278f7df2e56SmrgBool
279f7df2e56SmrgDRI2SwapLimit(DrawablePtr pDraw, int swap_limit)
280f7df2e56Smrg{
281f7df2e56Smrg    DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw);
282f7df2e56Smrg    DRI2ScreenPtr ds;
283f7df2e56Smrg
284f7df2e56Smrg    if (!pPriv)
285f7df2e56Smrg        return FALSE;
286f7df2e56Smrg
287f7df2e56Smrg    ds = pPriv->dri2_screen;
288f7df2e56Smrg
289f7df2e56Smrg    if (!ds->SwapLimitValidate || !ds->SwapLimitValidate(pDraw, swap_limit))
290f7df2e56Smrg        return FALSE;
291f7df2e56Smrg
292f7df2e56Smrg    pPriv->swap_limit = swap_limit;
293f7df2e56Smrg
294f7df2e56Smrg    /* Check throttling */
295f7df2e56Smrg    if (pPriv->swapsPending >= pPriv->swap_limit)
296f7df2e56Smrg        return TRUE;
297f7df2e56Smrg
298f7df2e56Smrg    dri2WakeAll(CLIENT_SIGNAL_ANY, pPriv, WAKE_SWAP);
299f7df2e56Smrg    return TRUE;
300f7df2e56Smrg}
301f7df2e56Smrg
3026747b715Smrgtypedef struct DRI2DrawableRefRec {
303f7df2e56Smrg    XID id;
304f7df2e56Smrg    XID dri2_id;
305f7df2e56Smrg    DRI2InvalidateProcPtr invalidate;
306f7df2e56Smrg    void *priv;
307f7df2e56Smrg    struct xorg_list link;
3086747b715Smrg} DRI2DrawableRefRec, *DRI2DrawableRefPtr;
3096747b715Smrg
3106747b715Smrgstatic DRI2DrawableRefPtr
3116747b715SmrgDRI2LookupDrawableRef(DRI2DrawablePtr pPriv, XID id)
3126747b715Smrg{
3138794ceb6Swiz    DRI2DrawableRefPtr ref = NULL;
3146747b715Smrg
315f7df2e56Smrg    xorg_list_for_each_entry(ref, &pPriv->reference_list, link) {
316f7df2e56Smrg        if (ref->id == id)
317f7df2e56Smrg            return ref;
3186747b715Smrg    }
319f7df2e56Smrg
3206747b715Smrg    return NULL;
3216747b715Smrg}
3226747b715Smrg
3236747b715Smrgstatic int
3246747b715SmrgDRI2AddDrawableRef(DRI2DrawablePtr pPriv, XID id, XID dri2_id,
325f7df2e56Smrg                   DRI2InvalidateProcPtr invalidate, void *priv)
3266747b715Smrg{
3276747b715Smrg    DRI2DrawableRefPtr ref;
3286747b715Smrg
3296747b715Smrg    ref = malloc(sizeof *ref);
3306747b715Smrg    if (ref == NULL)
331f7df2e56Smrg        return BadAlloc;
332f7df2e56Smrg
3339ace9065Smrg    if (!AddResource(dri2_id, dri2DrawableRes, pPriv)) {
334f7df2e56Smrg        free(ref);
335f7df2e56Smrg        return BadAlloc;
3369ace9065Smrg    }
3376747b715Smrg    if (!DRI2LookupDrawableRef(pPriv, id))
338f7df2e56Smrg        if (!AddResource(id, dri2DrawableRes, pPriv)) {
339f7df2e56Smrg            FreeResourceByType(dri2_id, dri2DrawableRes, TRUE);
340f7df2e56Smrg            free(ref);
341f7df2e56Smrg            return BadAlloc;
3429ace9065Smrg        }
3436747b715Smrg
3446747b715Smrg    ref->id = id;
345f7df2e56Smrg    ref->dri2_id = dri2_id;
3466747b715Smrg    ref->invalidate = invalidate;
3476747b715Smrg    ref->priv = priv;
348f7df2e56Smrg    xorg_list_add(&ref->link, &pPriv->reference_list);
3496747b715Smrg
3506747b715Smrg    return Success;
3516747b715Smrg}
3526747b715Smrg
3536747b715Smrgint
354f7df2e56SmrgDRI2CreateDrawable2(ClientPtr client, DrawablePtr pDraw, XID id,
355f7df2e56Smrg                    DRI2InvalidateProcPtr invalidate, void *priv,
356f7df2e56Smrg                    XID *dri2_id_out)
3576747b715Smrg{
3586747b715Smrg    DRI2DrawablePtr pPriv;
359d566a54bSmrg    DRI2ClientPtr dri2_client;
3606747b715Smrg    XID dri2_id;
3616747b715Smrg    int rc;
3626747b715Smrg
363d566a54bSmrg    if (!dixPrivateKeyRegistered(dri2ScreenPrivateKey))
364d566a54bSmrg        return BadValue;
365d566a54bSmrg
366d566a54bSmrg    dri2_client = dri2ClientPrivate(client);
367d566a54bSmrg
3686747b715Smrg    pPriv = DRI2GetDrawable(pDraw);
3696747b715Smrg    if (pPriv == NULL)
370f7df2e56Smrg        pPriv = DRI2AllocateDrawable(pDraw);
3716747b715Smrg    if (pPriv == NULL)
372f7df2e56Smrg        return BadAlloc;
373f7df2e56Smrg
374f7df2e56Smrg    pPriv->prime_id = dri2_client->prime_id;
375f7df2e56Smrg
3766747b715Smrg    dri2_id = FakeClientID(client->index);
3776747b715Smrg    rc = DRI2AddDrawableRef(pPriv, id, dri2_id, invalidate, priv);
3786747b715Smrg    if (rc != Success)
379f7df2e56Smrg        return rc;
380f7df2e56Smrg
381f7df2e56Smrg    if (dri2_id_out)
382f7df2e56Smrg        *dri2_id_out = dri2_id;
3836747b715Smrg
3846747b715Smrg    return Success;
3856747b715Smrg}
3866747b715Smrg
387f7df2e56Smrgint
388f7df2e56SmrgDRI2CreateDrawable(ClientPtr client, DrawablePtr pDraw, XID id,
389f7df2e56Smrg                   DRI2InvalidateProcPtr invalidate, void *priv)
390f7df2e56Smrg{
391f7df2e56Smrg    return DRI2CreateDrawable2(client, pDraw, id, invalidate, priv, NULL);
392f7df2e56Smrg}
393f7df2e56Smrg
394f7df2e56Smrgstatic int
395f7df2e56SmrgDRI2DrawableGone(void *p, XID id)
3966747b715Smrg{
3976747b715Smrg    DRI2DrawablePtr pPriv = p;
398f7df2e56Smrg    DRI2DrawableRefPtr ref, next;
3996747b715Smrg    WindowPtr pWin;
4006747b715Smrg    PixmapPtr pPixmap;
4016747b715Smrg    DrawablePtr pDraw;
4026747b715Smrg    int i;
4036747b715Smrg
404f7df2e56Smrg    xorg_list_for_each_entry_safe(ref, next, &pPriv->reference_list, link) {
405f7df2e56Smrg        if (ref->dri2_id == id) {
406f7df2e56Smrg            xorg_list_del(&ref->link);
407f7df2e56Smrg            /* If this was the last ref under this X drawable XID,
408f7df2e56Smrg             * unregister the X drawable resource. */
409f7df2e56Smrg            if (!DRI2LookupDrawableRef(pPriv, ref->id))
410f7df2e56Smrg                FreeResourceByType(ref->id, dri2DrawableRes, TRUE);
411f7df2e56Smrg            free(ref);
412f7df2e56Smrg            break;
413f7df2e56Smrg        }
4146747b715Smrg
415f7df2e56Smrg        if (ref->id == id) {
416f7df2e56Smrg            xorg_list_del(&ref->link);
417f7df2e56Smrg            FreeResourceByType(ref->dri2_id, dri2DrawableRes, TRUE);
418f7df2e56Smrg            free(ref);
419f7df2e56Smrg        }
4206747b715Smrg    }
4216747b715Smrg
422f7df2e56Smrg    if (!xorg_list_is_empty(&pPriv->reference_list))
423f7df2e56Smrg        return Success;
4246747b715Smrg
4256747b715Smrg    pDraw = pPriv->drawable;
4266747b715Smrg    if (pDraw->type == DRAWABLE_WINDOW) {
427f7df2e56Smrg        pWin = (WindowPtr) pDraw;
428f7df2e56Smrg        dixSetPrivate(&pWin->devPrivates, dri2WindowPrivateKey, NULL);
429f7df2e56Smrg    }
430f7df2e56Smrg    else {
431f7df2e56Smrg        pPixmap = (PixmapPtr) pDraw;
432f7df2e56Smrg        dixSetPrivate(&pPixmap->devPrivates, dri2PixmapPrivateKey, NULL);
433f7df2e56Smrg    }
434f7df2e56Smrg
4355a112b11Smrg    if (pPriv->prime_secondary_pixmap) {
4365a112b11Smrg        (*pPriv->prime_secondary_pixmap->primary_pixmap->drawable.pScreen->DestroyPixmap)(pPriv->prime_secondary_pixmap->primary_pixmap);
4375a112b11Smrg        (*pPriv->prime_secondary_pixmap->drawable.pScreen->DestroyPixmap)(pPriv->prime_secondary_pixmap);
4386747b715Smrg    }
4396747b715Smrg
4406747b715Smrg    if (pPriv->buffers != NULL) {
441f7df2e56Smrg        for (i = 0; i < pPriv->bufferCount; i++)
442f7df2e56Smrg            destroy_buffer(pDraw, pPriv->buffers[i], pPriv->prime_id);
4436747b715Smrg
444f7df2e56Smrg        free(pPriv->buffers);
4456747b715Smrg    }
4466747b715Smrg
447f7df2e56Smrg    if (pPriv->redirectpixmap) {
448f7df2e56Smrg        (*pDraw->pScreen->ReplaceScanoutPixmap)(pDraw, pPriv->redirectpixmap, FALSE);
449f7df2e56Smrg        (*pDraw->pScreen->DestroyPixmap)(pPriv->redirectpixmap);
450f7df2e56Smrg    }
451f7df2e56Smrg
452f7df2e56Smrg    dri2WakeAll(CLIENT_SIGNAL_ANY, pPriv, WAKE_SWAP);
453f7df2e56Smrg    dri2WakeAll(CLIENT_SIGNAL_ANY, pPriv, WAKE_MSC);
454f7df2e56Smrg    dri2WakeAll(CLIENT_SIGNAL_ANY, pPriv, WAKE_SBC);
455f7df2e56Smrg
4566747b715Smrg    free(pPriv);
4576747b715Smrg
4584642e01fSmrg    return Success;
4594642e01fSmrg}
4604642e01fSmrg
461f7df2e56Smrgstatic DRI2BufferPtr
462f7df2e56Smrgcreate_buffer(DRI2ScreenPtr ds, DrawablePtr pDraw,
463f7df2e56Smrg              unsigned int attachment, unsigned int format)
464f7df2e56Smrg{
465f7df2e56Smrg    DRI2BufferPtr buffer;
466f7df2e56Smrg    if (ds->CreateBuffer2)
467f7df2e56Smrg        buffer = (*ds->CreateBuffer2)(GetScreenPrime(pDraw->pScreen,
468f7df2e56Smrg                                                     DRI2GetDrawable(pDraw)->prime_id),
469f7df2e56Smrg                                      pDraw, attachment, format);
470f7df2e56Smrg    else
471f7df2e56Smrg        buffer = (*ds->CreateBuffer)(pDraw, attachment, format);
472f7df2e56Smrg    return buffer;
473f7df2e56Smrg}
474f7df2e56Smrg
475f7df2e56Smrgstatic void
476f7df2e56Smrgdestroy_buffer(DrawablePtr pDraw, DRI2BufferPtr buffer, int prime_id)
477f7df2e56Smrg{
478f7df2e56Smrg    ScreenPtr primeScreen;
479f7df2e56Smrg    DRI2ScreenPtr ds;
480f7df2e56Smrg    primeScreen = GetScreenPrime(pDraw->pScreen, prime_id);
481f7df2e56Smrg    ds = DRI2GetScreen(primeScreen);
482f7df2e56Smrg    if (ds->DestroyBuffer2)
483f7df2e56Smrg        (*ds->DestroyBuffer2)(primeScreen, pDraw, buffer);
484f7df2e56Smrg    else
485f7df2e56Smrg        (*ds->DestroyBuffer)(pDraw, buffer);
486f7df2e56Smrg}
487f7df2e56Smrg
48852397711Smrgstatic int
48952397711Smrgfind_attachment(DRI2DrawablePtr pPriv, unsigned attachment)
49052397711Smrg{
49152397711Smrg    int i;
49252397711Smrg
49352397711Smrg    if (pPriv->buffers == NULL) {
494f7df2e56Smrg        return -1;
49552397711Smrg    }
49652397711Smrg
49752397711Smrg    for (i = 0; i < pPriv->bufferCount; i++) {
498f7df2e56Smrg        if ((pPriv->buffers[i] != NULL)
499f7df2e56Smrg            && (pPriv->buffers[i]->attachment == attachment)) {
500f7df2e56Smrg            return i;
501f7df2e56Smrg        }
50252397711Smrg    }
50352397711Smrg
50452397711Smrg    return -1;
50552397711Smrg}
50652397711Smrg
5076747b715Smrgstatic Bool
50852397711Smrgallocate_or_reuse_buffer(DrawablePtr pDraw, DRI2ScreenPtr ds,
509f7df2e56Smrg                         DRI2DrawablePtr pPriv,
510f7df2e56Smrg                         unsigned int attachment, unsigned int format,
511f7df2e56Smrg                         int dimensions_match, DRI2BufferPtr * buffer)
51252397711Smrg{
5136747b715Smrg    int old_buf = find_attachment(pPriv, attachment);
51452397711Smrg
51552397711Smrg    if ((old_buf < 0)
516f7df2e56Smrg        || attachment == DRI2BufferFrontLeft
517f7df2e56Smrg        || !dimensions_match || (pPriv->buffers[old_buf]->format != format)) {
518f7df2e56Smrg        *buffer = create_buffer(ds, pDraw, attachment, format);
519f7df2e56Smrg        return TRUE;
520f7df2e56Smrg
521f7df2e56Smrg    }
522f7df2e56Smrg    else {
523f7df2e56Smrg        *buffer = pPriv->buffers[old_buf];
524f7df2e56Smrg
525f7df2e56Smrg        if (ds->ReuseBufferNotify)
526f7df2e56Smrg            (*ds->ReuseBufferNotify) (pDraw, *buffer);
5276747b715Smrg
528f7df2e56Smrg        pPriv->buffers[old_buf] = NULL;
529f7df2e56Smrg        return FALSE;
53052397711Smrg    }
5316747b715Smrg}
5326747b715Smrg
5336747b715Smrgstatic void
5346747b715Smrgupdate_dri2_drawable_buffers(DRI2DrawablePtr pPriv, DrawablePtr pDraw,
535f7df2e56Smrg                             DRI2BufferPtr * buffers, int out_count, int *width,
536f7df2e56Smrg                             int *height)
5376747b715Smrg{
5386747b715Smrg    int i;
53952397711Smrg
5406747b715Smrg    if (pPriv->buffers != NULL) {
541f7df2e56Smrg        for (i = 0; i < pPriv->bufferCount; i++) {
542f7df2e56Smrg            if (pPriv->buffers[i] != NULL) {
543f7df2e56Smrg                destroy_buffer(pDraw, pPriv->buffers[i], pPriv->prime_id);
544f7df2e56Smrg            }
545f7df2e56Smrg        }
5466747b715Smrg
547f7df2e56Smrg        free(pPriv->buffers);
5486747b715Smrg    }
5496747b715Smrg
5506747b715Smrg    pPriv->buffers = buffers;
551f7df2e56Smrg    pPriv->bufferCount = out_count;
5526747b715Smrg    pPriv->width = pDraw->width;
5536747b715Smrg    pPriv->height = pDraw->height;
5546747b715Smrg    *width = pPriv->width;
5556747b715Smrg    *height = pPriv->height;
55652397711Smrg}
55752397711Smrg
5586747b715Smrgstatic DRI2BufferPtr *
55952397711Smrgdo_get_buffers(DrawablePtr pDraw, int *width, int *height,
560f7df2e56Smrg               unsigned int *attachments, int count, int *out_count,
561f7df2e56Smrg               int has_format)
5624642e01fSmrg{
5634642e01fSmrg    DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw);
564f7df2e56Smrg    DRI2ScreenPtr ds;
565f7df2e56Smrg    DRI2BufferPtr *buffers;
56652397711Smrg    int need_real_front = 0;
56752397711Smrg    int need_fake_front = 0;
56852397711Smrg    int have_fake_front = 0;
56952397711Smrg    int front_format = 0;
570b1d344b3Smrg    int dimensions_match;
5716747b715Smrg    int buffers_changed = 0;
57252397711Smrg    int i;
57352397711Smrg
574b1d344b3Smrg    if (!pPriv) {
575f7df2e56Smrg        *width = pDraw->width;
576f7df2e56Smrg        *height = pDraw->height;
577f7df2e56Smrg        *out_count = 0;
578f7df2e56Smrg        return NULL;
579b1d344b3Smrg    }
580b1d344b3Smrg
581f7df2e56Smrg    ds = DRI2GetScreenPrime(pDraw->pScreen, pPriv->prime_id);
582f7df2e56Smrg
583b1d344b3Smrg    dimensions_match = (pDraw->width == pPriv->width)
584f7df2e56Smrg        && (pDraw->height == pPriv->height);
5856747b715Smrg
5869ace9065Smrg    buffers = calloc((count + 1), sizeof(buffers[0]));
587f7df2e56Smrg    if (!buffers)
588f7df2e56Smrg        goto err_out;
5896747b715Smrg
5906747b715Smrg    for (i = 0; i < count; i++) {
591f7df2e56Smrg        const unsigned attachment = *(attachments++);
592f7df2e56Smrg        const unsigned format = (has_format) ? *(attachments++) : 0;
593f7df2e56Smrg
594f7df2e56Smrg        if (allocate_or_reuse_buffer(pDraw, ds, pPriv, attachment,
595f7df2e56Smrg                                     format, dimensions_match, &buffers[i]))
596f7df2e56Smrg            buffers_changed = 1;
597f7df2e56Smrg
598f7df2e56Smrg        if (buffers[i] == NULL)
599f7df2e56Smrg            goto err_out;
600f7df2e56Smrg
601f7df2e56Smrg        /* If the drawable is a window and the front-buffer is requested,
602f7df2e56Smrg         * silently add the fake front-buffer to the list of requested
603f7df2e56Smrg         * attachments.  The counting logic in the loop accounts for the case
604f7df2e56Smrg         * where the client requests both the fake and real front-buffer.
605f7df2e56Smrg         */
606f7df2e56Smrg        if (attachment == DRI2BufferBackLeft) {
607f7df2e56Smrg            need_real_front++;
608f7df2e56Smrg            front_format = format;
609f7df2e56Smrg        }
610f7df2e56Smrg
611f7df2e56Smrg        if (attachment == DRI2BufferFrontLeft) {
612f7df2e56Smrg            need_real_front--;
613f7df2e56Smrg            front_format = format;
614f7df2e56Smrg
615f7df2e56Smrg            if (pDraw->type == DRAWABLE_WINDOW) {
616f7df2e56Smrg                need_fake_front++;
617f7df2e56Smrg            }
618f7df2e56Smrg        }
619f7df2e56Smrg
620f7df2e56Smrg        if (pDraw->type == DRAWABLE_WINDOW) {
621f7df2e56Smrg            if (attachment == DRI2BufferFakeFrontLeft) {
622f7df2e56Smrg                need_fake_front--;
623f7df2e56Smrg                have_fake_front = 1;
624f7df2e56Smrg            }
625f7df2e56Smrg        }
6266747b715Smrg    }
62752397711Smrg
6286747b715Smrg    if (need_real_front > 0) {
629f7df2e56Smrg        if (allocate_or_reuse_buffer(pDraw, ds, pPriv, DRI2BufferFrontLeft,
630f7df2e56Smrg                                     front_format, dimensions_match,
631f7df2e56Smrg                                     &buffers[i]))
632f7df2e56Smrg            buffers_changed = 1;
633f7df2e56Smrg
634f7df2e56Smrg        if (buffers[i] == NULL)
635f7df2e56Smrg            goto err_out;
636f7df2e56Smrg        i++;
6376747b715Smrg    }
63852397711Smrg
6396747b715Smrg    if (need_fake_front > 0) {
640f7df2e56Smrg        if (allocate_or_reuse_buffer(pDraw, ds, pPriv, DRI2BufferFakeFrontLeft,
641f7df2e56Smrg                                     front_format, dimensions_match,
642f7df2e56Smrg                                     &buffers[i]))
643f7df2e56Smrg            buffers_changed = 1;
64452397711Smrg
645f7df2e56Smrg        if (buffers[i] == NULL)
646f7df2e56Smrg            goto err_out;
64752397711Smrg
648f7df2e56Smrg        i++;
649f7df2e56Smrg        have_fake_front = 1;
6504642e01fSmrg    }
6514642e01fSmrg
6526747b715Smrg    *out_count = i;
65352397711Smrg
654f7df2e56Smrg    update_dri2_drawable_buffers(pPriv, pDraw, buffers, *out_count, width,
655f7df2e56Smrg                                 height);
65652397711Smrg
65752397711Smrg    /* If the client is getting a fake front-buffer, pre-fill it with the
65852397711Smrg     * contents of the real front-buffer.  This ensures correct operation of
65952397711Smrg     * applications that call glXWaitX before calling glDrawBuffer.
66052397711Smrg     */
6616747b715Smrg    if (have_fake_front && buffers_changed) {
662f7df2e56Smrg        BoxRec box;
663f7df2e56Smrg        RegionRec region;
66452397711Smrg
665f7df2e56Smrg        box.x1 = 0;
666f7df2e56Smrg        box.y1 = 0;
667f7df2e56Smrg        box.x2 = pPriv->width;
668f7df2e56Smrg        box.y2 = pPriv->height;
669f7df2e56Smrg        RegionInit(&region, &box, 0);
67052397711Smrg
671f7df2e56Smrg        DRI2CopyRegion(pDraw, &region, DRI2BufferFakeFrontLeft,
672f7df2e56Smrg                       DRI2BufferFrontLeft);
67352397711Smrg    }
6744642e01fSmrg
675f7df2e56Smrg    pPriv->needInvalidate = TRUE;
676f7df2e56Smrg
6774642e01fSmrg    return pPriv->buffers;
6786747b715Smrg
679f7df2e56Smrg err_out:
6806747b715Smrg
6816747b715Smrg    *out_count = 0;
6826747b715Smrg
683f7df2e56Smrg    if (buffers) {
684f7df2e56Smrg        for (i = 0; i < count; i++) {
685f7df2e56Smrg            if (buffers[i] != NULL)
686f7df2e56Smrg                destroy_buffer(pDraw, buffers[i], 0);
687f7df2e56Smrg        }
6886747b715Smrg
689f7df2e56Smrg        free(buffers);
690f7df2e56Smrg        buffers = NULL;
691f7df2e56Smrg    }
6926747b715Smrg
693f7df2e56Smrg    update_dri2_drawable_buffers(pPriv, pDraw, buffers, *out_count, width,
694f7df2e56Smrg                                 height);
6956747b715Smrg
6966747b715Smrg    return buffers;
6974642e01fSmrg}
6984642e01fSmrg
6996747b715SmrgDRI2BufferPtr *
70052397711SmrgDRI2GetBuffers(DrawablePtr pDraw, int *width, int *height,
701f7df2e56Smrg               unsigned int *attachments, int count, int *out_count)
70252397711Smrg{
70352397711Smrg    return do_get_buffers(pDraw, width, height, attachments, count,
704f7df2e56Smrg                          out_count, FALSE);
70552397711Smrg}
70652397711Smrg
7076747b715SmrgDRI2BufferPtr *
70852397711SmrgDRI2GetBuffersWithFormat(DrawablePtr pDraw, int *width, int *height,
709f7df2e56Smrg                         unsigned int *attachments, int count, int *out_count)
71052397711Smrg{
71152397711Smrg    return do_get_buffers(pDraw, width, height, attachments, count,
712f7df2e56Smrg                          out_count, TRUE);
71352397711Smrg}
71452397711Smrg
7156747b715Smrgstatic void
7166747b715SmrgDRI2InvalidateDrawable(DrawablePtr pDraw)
7176747b715Smrg{
7186747b715Smrg    DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw);
7198794ceb6Swiz    DRI2DrawableRefPtr ref = NULL;
7206747b715Smrg
721f7df2e56Smrg    if (!pPriv || !pPriv->needInvalidate)
7226747b715Smrg        return;
7236747b715Smrg
724f7df2e56Smrg    pPriv->needInvalidate = FALSE;
725f7df2e56Smrg
726f7df2e56Smrg    xorg_list_for_each_entry(ref, &pPriv->reference_list, link)
727f7df2e56Smrg        ref->invalidate(pDraw, ref->priv, ref->id);
7286747b715Smrg}
7296747b715Smrg
7306747b715Smrg/*
7316747b715Smrg * In the direct rendered case, we throttle the clients that have more
7326747b715Smrg * than their share of outstanding swaps (and thus busy buffers) when a
7336747b715Smrg * new GetBuffers request is received.  In the AIGLX case, we allow the
7346747b715Smrg * client to get the new buffers, but throttle when the next GLX request
7356747b715Smrg * comes in (see __glXDRIcontextWait()).
7366747b715Smrg */
7376747b715SmrgBool
7386747b715SmrgDRI2ThrottleClient(ClientPtr client, DrawablePtr pDraw)
7396747b715Smrg{
7406747b715Smrg    DRI2DrawablePtr pPriv;
7416747b715Smrg
7426747b715Smrg    pPriv = DRI2GetDrawable(pDraw);
7436747b715Smrg    if (pPriv == NULL)
744f7df2e56Smrg        return FALSE;
7456747b715Smrg
7466747b715Smrg    /* Throttle to swap limit */
747f7df2e56Smrg    if (pPriv->swapsPending >= pPriv->swap_limit) {
748f7df2e56Smrg        if (dri2Sleep(client, pPriv, WAKE_SWAP)) {
749f7df2e56Smrg            ResetCurrentRequest(client);
750f7df2e56Smrg            client->sequence--;
751f7df2e56Smrg            return TRUE;
752f7df2e56Smrg        }
7536747b715Smrg    }
7546747b715Smrg
7556747b715Smrg    return FALSE;
7566747b715Smrg}
7576747b715Smrg
7586747b715Smrgvoid
7596747b715SmrgDRI2BlockClient(ClientPtr client, DrawablePtr pDraw)
7606747b715Smrg{
7616747b715Smrg    DRI2DrawablePtr pPriv;
7626747b715Smrg
7636747b715Smrg    pPriv = DRI2GetDrawable(pDraw);
7646747b715Smrg    if (pPriv == NULL)
765f7df2e56Smrg        return;
766f7df2e56Smrg
767f7df2e56Smrg    dri2Sleep(client, pPriv, WAKE_MSC);
768f7df2e56Smrg}
769f7df2e56Smrg
770f7df2e56Smrgstatic inline PixmapPtr GetDrawablePixmap(DrawablePtr drawable)
771f7df2e56Smrg{
772f7df2e56Smrg    if (drawable->type == DRAWABLE_PIXMAP)
773f7df2e56Smrg        return (PixmapPtr)drawable;
774f7df2e56Smrg    else {
775f7df2e56Smrg        struct _Window *pWin = (struct _Window *)drawable;
776f7df2e56Smrg        return drawable->pScreen->GetWindowPixmap(pWin);
777f7df2e56Smrg    }
778f7df2e56Smrg}
779f7df2e56Smrg
780f7df2e56Smrg/*
781f7df2e56Smrg * A TraverseTree callback to invalidate all windows using the same
782f7df2e56Smrg * pixmap
783f7df2e56Smrg */
784f7df2e56Smrgstatic int
785f7df2e56SmrgDRI2InvalidateWalk(WindowPtr pWin, void *data)
786f7df2e56Smrg{
787f7df2e56Smrg    if (pWin->drawable.pScreen->GetWindowPixmap(pWin) != data)
788f7df2e56Smrg        return WT_DONTWALKCHILDREN;
789f7df2e56Smrg    DRI2InvalidateDrawable(&pWin->drawable);
790f7df2e56Smrg    return WT_WALKCHILDREN;
791f7df2e56Smrg}
792f7df2e56Smrg
793f7df2e56Smrgstatic void
794f7df2e56SmrgDRI2InvalidateDrawableAll(DrawablePtr pDraw)
795f7df2e56Smrg{
796f7df2e56Smrg    if (pDraw->type == DRAWABLE_WINDOW) {
797f7df2e56Smrg        WindowPtr pWin = (WindowPtr) pDraw;
798f7df2e56Smrg        PixmapPtr pPixmap = pDraw->pScreen->GetWindowPixmap(pWin);
799f7df2e56Smrg
800f7df2e56Smrg        /*
801f7df2e56Smrg         * Find the top-most window using this pixmap
802f7df2e56Smrg         */
803f7df2e56Smrg        while (pWin->parent &&
804f7df2e56Smrg               pDraw->pScreen->GetWindowPixmap(pWin->parent) == pPixmap)
805f7df2e56Smrg            pWin = pWin->parent;
806f7df2e56Smrg
807f7df2e56Smrg        /*
808f7df2e56Smrg         * Walk the sub-tree to invalidate all of the
809f7df2e56Smrg         * windows using the same pixmap
810f7df2e56Smrg         */
811f7df2e56Smrg        TraverseTree(pWin, DRI2InvalidateWalk, pPixmap);
812f7df2e56Smrg        DRI2InvalidateDrawable(&pPixmap->drawable);
813f7df2e56Smrg    }
814f7df2e56Smrg    else
815f7df2e56Smrg        DRI2InvalidateDrawable(pDraw);
816f7df2e56Smrg}
817f7df2e56Smrg
818f7df2e56SmrgDrawablePtr DRI2UpdatePrime(DrawablePtr pDraw, DRI2BufferPtr pDest)
819f7df2e56Smrg{
820f7df2e56Smrg    DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw);
821f7df2e56Smrg    PixmapPtr spix;
822f7df2e56Smrg    PixmapPtr mpix = GetDrawablePixmap(pDraw);
8235a112b11Smrg    ScreenPtr primary, secondary;
824f7df2e56Smrg    Bool ret;
8256747b715Smrg
8265a112b11Smrg    primary = mpix->drawable.pScreen;
827f7df2e56Smrg
828f7df2e56Smrg    if (pDraw->type == DRAWABLE_WINDOW) {
829f7df2e56Smrg        WindowPtr pWin = (WindowPtr)pDraw;
830f7df2e56Smrg        PixmapPtr pPixmap = pDraw->pScreen->GetWindowPixmap(pWin);
831f7df2e56Smrg
832f7df2e56Smrg        if (pDraw->pScreen->GetScreenPixmap(pDraw->pScreen) == pPixmap) {
833f7df2e56Smrg            if (pPriv->redirectpixmap &&
834f7df2e56Smrg                pPriv->redirectpixmap->drawable.width == pDraw->width &&
835f7df2e56Smrg                pPriv->redirectpixmap->drawable.height == pDraw->height &&
836f7df2e56Smrg                pPriv->redirectpixmap->drawable.depth == pDraw->depth) {
837f7df2e56Smrg                mpix = pPriv->redirectpixmap;
838f7df2e56Smrg            } else {
8395a112b11Smrg                if (primary->ReplaceScanoutPixmap) {
8405a112b11Smrg                    mpix = (*primary->CreatePixmap)(primary, pDraw->width, pDraw->height,
841f7df2e56Smrg                                                   pDraw->depth, CREATE_PIXMAP_USAGE_SHARED);
842f7df2e56Smrg                    if (!mpix)
843f7df2e56Smrg                        return NULL;
844f7df2e56Smrg
8455a112b11Smrg                    ret = (*primary->ReplaceScanoutPixmap)(pDraw, mpix, TRUE);
846f7df2e56Smrg                    if (ret == FALSE) {
8475a112b11Smrg                        (*primary->DestroyPixmap)(mpix);
848f7df2e56Smrg                        return NULL;
849f7df2e56Smrg                    }
850f7df2e56Smrg                    pPriv->redirectpixmap = mpix;
851f7df2e56Smrg                } else
852f7df2e56Smrg                    return NULL;
853f7df2e56Smrg            }
854f7df2e56Smrg        } else if (pPriv->redirectpixmap) {
8555a112b11Smrg            (*primary->ReplaceScanoutPixmap)(pDraw, pPriv->redirectpixmap, FALSE);
8565a112b11Smrg            (*primary->DestroyPixmap)(pPriv->redirectpixmap);
857f7df2e56Smrg            pPriv->redirectpixmap = NULL;
858f7df2e56Smrg        }
859f7df2e56Smrg    }
860f7df2e56Smrg
8615a112b11Smrg    secondary = GetScreenPrime(pDraw->pScreen, pPriv->prime_id);
862f7df2e56Smrg
863f7df2e56Smrg    /* check if the pixmap is still fine */
8645a112b11Smrg    if (pPriv->prime_secondary_pixmap) {
8655a112b11Smrg        if (pPriv->prime_secondary_pixmap->primary_pixmap == mpix)
8665a112b11Smrg            return &pPriv->prime_secondary_pixmap->drawable;
867f7df2e56Smrg        else {
8685a112b11Smrg            PixmapUnshareSecondaryPixmap(pPriv->prime_secondary_pixmap);
8695a112b11Smrg            (*pPriv->prime_secondary_pixmap->primary_pixmap->drawable.pScreen->DestroyPixmap)(pPriv->prime_secondary_pixmap->primary_pixmap);
8705a112b11Smrg            (*secondary->DestroyPixmap)(pPriv->prime_secondary_pixmap);
8715a112b11Smrg            pPriv->prime_secondary_pixmap = NULL;
872f7df2e56Smrg        }
873f7df2e56Smrg    }
874f7df2e56Smrg
8755a112b11Smrg    spix = PixmapShareToSecondary(mpix, secondary);
876f7df2e56Smrg    if (!spix)
877f7df2e56Smrg        return NULL;
878f7df2e56Smrg
8795a112b11Smrg    pPriv->prime_secondary_pixmap = spix;
880f7df2e56Smrg#ifdef COMPOSITE
881f7df2e56Smrg    spix->screen_x = mpix->screen_x;
882f7df2e56Smrg    spix->screen_y = mpix->screen_y;
883f7df2e56Smrg#endif
884f7df2e56Smrg
885f7df2e56Smrg    DRI2InvalidateDrawableAll(pDraw);
886f7df2e56Smrg    return &spix->drawable;
887f7df2e56Smrg}
888f7df2e56Smrg
889f7df2e56Smrgstatic void dri2_copy_region(DrawablePtr pDraw, RegionPtr pRegion,
890f7df2e56Smrg                             DRI2BufferPtr pDest, DRI2BufferPtr pSrc)
891f7df2e56Smrg{
892f7df2e56Smrg    DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw);
893f7df2e56Smrg    DRI2ScreenPtr ds;
894f7df2e56Smrg    ScreenPtr primeScreen;
895f7df2e56Smrg
896f7df2e56Smrg    primeScreen = GetScreenPrime(pDraw->pScreen, pPriv->prime_id);
897f7df2e56Smrg    ds = DRI2GetScreen(primeScreen);
898f7df2e56Smrg
899f7df2e56Smrg    if (ds->CopyRegion2)
900f7df2e56Smrg        (*ds->CopyRegion2)(primeScreen, pDraw, pRegion, pDest, pSrc);
901f7df2e56Smrg    else
902f7df2e56Smrg        (*ds->CopyRegion) (pDraw, pRegion, pDest, pSrc);
903f7df2e56Smrg
904f7df2e56Smrg    /* cause damage to the box */
905f7df2e56Smrg    if (pPriv->prime_id) {
906f7df2e56Smrg       BoxRec box;
907f7df2e56Smrg       RegionRec region;
908f7df2e56Smrg       box.x1 = 0;
909f7df2e56Smrg       box.x2 = box.x1 + pDraw->width;
910f7df2e56Smrg       box.y1 = 0;
911f7df2e56Smrg       box.y2 = box.y1 + pDraw->height;
912f7df2e56Smrg       RegionInit(&region, &box, 1);
913f7df2e56Smrg       RegionTranslate(&region, pDraw->x, pDraw->y);
914f7df2e56Smrg       DamageRegionAppend(pDraw, &region);
915f7df2e56Smrg       DamageRegionProcessPending(pDraw);
916f7df2e56Smrg       RegionUninit(&region);
917f7df2e56Smrg    }
9186747b715Smrg}
9196747b715Smrg
9204642e01fSmrgint
9214642e01fSmrgDRI2CopyRegion(DrawablePtr pDraw, RegionPtr pRegion,
922f7df2e56Smrg               unsigned int dest, unsigned int src)
9234642e01fSmrg{
9244642e01fSmrg    DRI2DrawablePtr pPriv;
925f7df2e56Smrg    DRI2BufferPtr pDestBuffer, pSrcBuffer;
926f7df2e56Smrg    int i;
9274642e01fSmrg
9284642e01fSmrg    pPriv = DRI2GetDrawable(pDraw);
9294642e01fSmrg    if (pPriv == NULL)
930f7df2e56Smrg        return BadDrawable;
9314642e01fSmrg
9324642e01fSmrg    pDestBuffer = NULL;
9334642e01fSmrg    pSrcBuffer = NULL;
934f7df2e56Smrg    for (i = 0; i < pPriv->bufferCount; i++) {
935f7df2e56Smrg        if (pPriv->buffers[i]->attachment == dest)
936f7df2e56Smrg            pDestBuffer = (DRI2BufferPtr) pPriv->buffers[i];
937f7df2e56Smrg        if (pPriv->buffers[i]->attachment == src)
938f7df2e56Smrg            pSrcBuffer = (DRI2BufferPtr) pPriv->buffers[i];
9394642e01fSmrg    }
9404642e01fSmrg    if (pSrcBuffer == NULL || pDestBuffer == NULL)
941f7df2e56Smrg        return BadValue;
94252397711Smrg
943f7df2e56Smrg    dri2_copy_region(pDraw, pRegion, pDestBuffer, pSrcBuffer);
9444642e01fSmrg
9454642e01fSmrg    return Success;
9464642e01fSmrg}
9474642e01fSmrg
9486747b715Smrg/* Can this drawable be page flipped? */
9496747b715SmrgBool
9506747b715SmrgDRI2CanFlip(DrawablePtr pDraw)
9516747b715Smrg{
9526747b715Smrg    ScreenPtr pScreen = pDraw->pScreen;
9536747b715Smrg    WindowPtr pWin, pRoot;
9546747b715Smrg    PixmapPtr pWinPixmap, pRootPixmap;
9556747b715Smrg
9566747b715Smrg    if (pDraw->type == DRAWABLE_PIXMAP)
957f7df2e56Smrg        return TRUE;
9586747b715Smrg
9596747b715Smrg    pRoot = pScreen->root;
9606747b715Smrg    pRootPixmap = pScreen->GetWindowPixmap(pRoot);
9616747b715Smrg
9626747b715Smrg    pWin = (WindowPtr) pDraw;
9636747b715Smrg    pWinPixmap = pScreen->GetWindowPixmap(pWin);
9646747b715Smrg    if (pRootPixmap != pWinPixmap)
965f7df2e56Smrg        return FALSE;
9666747b715Smrg    if (!RegionEqual(&pWin->clipList, &pRoot->winSize))
967f7df2e56Smrg        return FALSE;
9686747b715Smrg
9698223e2f2Smrg    /* Does the window match the pixmap exactly? */
970f7df2e56Smrg    if (pDraw->x != 0 || pDraw->y != 0 ||
9718223e2f2Smrg#ifdef COMPOSITE
972f7df2e56Smrg        pDraw->x != pWinPixmap->screen_x || pDraw->y != pWinPixmap->screen_y ||
9738223e2f2Smrg#endif
974f7df2e56Smrg        pDraw->width != pWinPixmap->drawable.width ||
975f7df2e56Smrg        pDraw->height != pWinPixmap->drawable.height)
976f7df2e56Smrg        return FALSE;
9778223e2f2Smrg
9786747b715Smrg    return TRUE;
9796747b715Smrg}
9806747b715Smrg
9816747b715Smrg/* Can we do a pixmap exchange instead of a blit? */
9826747b715SmrgBool
9836747b715SmrgDRI2CanExchange(DrawablePtr pDraw)
9846747b715Smrg{
9856747b715Smrg    return FALSE;
9866747b715Smrg}
9876747b715Smrg
9884642e01fSmrgvoid
9896747b715SmrgDRI2WaitMSCComplete(ClientPtr client, DrawablePtr pDraw, int frame,
990f7df2e56Smrg                    unsigned int tv_sec, unsigned int tv_usec)
9914642e01fSmrg{
9924642e01fSmrg    DRI2DrawablePtr pPriv;
9934642e01fSmrg
9944642e01fSmrg    pPriv = DRI2GetDrawable(pDraw);
9954642e01fSmrg    if (pPriv == NULL)
996f7df2e56Smrg        return;
9974642e01fSmrg
998f7df2e56Smrg    ProcDRI2WaitMSCReply(client, ((CARD64) tv_sec * 1000000) + tv_usec,
999f7df2e56Smrg                         frame, pPriv->swap_count);
100052397711Smrg
1001f7df2e56Smrg    dri2WakeAll(client, pPriv, WAKE_MSC);
10026747b715Smrg}
10036747b715Smrg
10046747b715Smrgstatic void
10056747b715SmrgDRI2WakeClient(ClientPtr client, DrawablePtr pDraw, int frame,
1006f7df2e56Smrg               unsigned int tv_sec, unsigned int tv_usec)
10076747b715Smrg{
1008f7df2e56Smrg    ScreenPtr pScreen = pDraw->pScreen;
10096747b715Smrg    DRI2DrawablePtr pPriv;
10106747b715Smrg
10116747b715Smrg    pPriv = DRI2GetDrawable(pDraw);
10126747b715Smrg    if (pPriv == NULL) {
10136747b715Smrg        xf86DrvMsg(pScreen->myNum, X_ERROR,
1014f7df2e56Smrg                   "[DRI2] %s: bad drawable\n", __func__);
1015f7df2e56Smrg        return;
10166747b715Smrg    }
10176747b715Smrg
10186747b715Smrg    /*
10196747b715Smrg     * Swap completed.
10206747b715Smrg     * Wake the client iff:
10216747b715Smrg     *   - it was waiting on SBC
10226747b715Smrg     *   - was blocked due to GLX make current
10236747b715Smrg     *   - was blocked due to swap throttling
10246747b715Smrg     *   - is not blocked due to an MSC wait
10256747b715Smrg     */
1026f7df2e56Smrg    if (pPriv->target_sbc != -1 && pPriv->target_sbc <= pPriv->swap_count) {
1027f7df2e56Smrg        if (dri2WakeAll(client, pPriv, WAKE_SBC)) {
1028f7df2e56Smrg            ProcDRI2WaitMSCReply(client, ((CARD64) tv_sec * 1000000) + tv_usec,
1029f7df2e56Smrg                                 frame, pPriv->swap_count);
1030f7df2e56Smrg            pPriv->target_sbc = -1;
1031f7df2e56Smrg        }
10326747b715Smrg    }
1033f7df2e56Smrg
1034f7df2e56Smrg    dri2WakeAll(CLIENT_SIGNAL_ANY, pPriv, WAKE_SWAP);
10356747b715Smrg}
10366747b715Smrg
10376747b715Smrgvoid
10386747b715SmrgDRI2SwapComplete(ClientPtr client, DrawablePtr pDraw, int frame,
1039f7df2e56Smrg                 unsigned int tv_sec, unsigned int tv_usec, int type,
1040f7df2e56Smrg                 DRI2SwapEventPtr swap_complete, void *swap_data)
10416747b715Smrg{
1042f7df2e56Smrg    ScreenPtr pScreen = pDraw->pScreen;
10436747b715Smrg    DRI2DrawablePtr pPriv;
1044f7df2e56Smrg    CARD64 ust = 0;
1045f7df2e56Smrg    BoxRec box;
1046f7df2e56Smrg    RegionRec region;
104752397711Smrg
10486747b715Smrg    pPriv = DRI2GetDrawable(pDraw);
10496747b715Smrg    if (pPriv == NULL) {
10506747b715Smrg        xf86DrvMsg(pScreen->myNum, X_ERROR,
1051f7df2e56Smrg                   "[DRI2] %s: bad drawable\n", __func__);
1052f7df2e56Smrg        return;
105352397711Smrg    }
105452397711Smrg
10556747b715Smrg    pPriv->swapsPending--;
10566747b715Smrg    pPriv->swap_count++;
10574642e01fSmrg
10586747b715Smrg    box.x1 = 0;
10596747b715Smrg    box.y1 = 0;
10606747b715Smrg    box.x2 = pDraw->width;
10616747b715Smrg    box.y2 = pDraw->height;
10626747b715Smrg    RegionInit(&region, &box, 0);
10636747b715Smrg    DRI2CopyRegion(pDraw, &region, DRI2BufferFakeFrontLeft,
1064f7df2e56Smrg                   DRI2BufferFrontLeft);
10656747b715Smrg
1066f7df2e56Smrg    ust = ((CARD64) tv_sec * 1000000) + tv_usec;
10676747b715Smrg    if (swap_complete)
1068f7df2e56Smrg        swap_complete(client, swap_data, type, ust, frame, pPriv->swap_count);
10696747b715Smrg
10706747b715Smrg    pPriv->last_swap_msc = frame;
10716747b715Smrg    pPriv->last_swap_ust = ust;
10726747b715Smrg
10736747b715Smrg    DRI2WakeClient(client, pDraw, frame, tv_sec, tv_usec);
10746747b715Smrg}
10756747b715Smrg
10766747b715SmrgBool
10776747b715SmrgDRI2WaitSwap(ClientPtr client, DrawablePtr pDrawable)
10786747b715Smrg{
10796747b715Smrg    DRI2DrawablePtr pPriv = DRI2GetDrawable(pDrawable);
10806747b715Smrg
10816747b715Smrg    /* If we're currently waiting for a swap on this drawable, reset
1082f7df2e56Smrg     * the request and suspend the client. */
1083f7df2e56Smrg    if (pPriv && pPriv->swapsPending) {
1084f7df2e56Smrg        if (dri2Sleep(client, pPriv, WAKE_SWAP)) {
1085f7df2e56Smrg            ResetCurrentRequest(client);
1086f7df2e56Smrg            client->sequence--;
1087f7df2e56Smrg            return TRUE;
1088f7df2e56Smrg        }
10894642e01fSmrg    }
10906747b715Smrg
10916747b715Smrg    return FALSE;
10926747b715Smrg}
10936747b715Smrg
1094f7df2e56Smrg
1095f7df2e56Smrg
10966747b715Smrgint
10976747b715SmrgDRI2SwapBuffers(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc,
1098f7df2e56Smrg                CARD64 divisor, CARD64 remainder, CARD64 * swap_target,
1099f7df2e56Smrg                DRI2SwapEventPtr func, void *data)
11006747b715Smrg{
1101f7df2e56Smrg    ScreenPtr pScreen = pDraw->pScreen;
1102f7df2e56Smrg    DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen);
11036747b715Smrg    DRI2DrawablePtr pPriv;
1104f7df2e56Smrg    DRI2BufferPtr pDestBuffer = NULL, pSrcBuffer = NULL;
1105f7df2e56Smrg    int ret, i;
1106f7df2e56Smrg    CARD64 ust, current_msc;
11076747b715Smrg
11086747b715Smrg    pPriv = DRI2GetDrawable(pDraw);
11096747b715Smrg    if (pPriv == NULL) {
11106747b715Smrg        xf86DrvMsg(pScreen->myNum, X_ERROR,
1111f7df2e56Smrg                   "[DRI2] %s: bad drawable\n", __func__);
1112f7df2e56Smrg        return BadDrawable;
11136747b715Smrg    }
11146747b715Smrg
1115f7df2e56Smrg    /* According to spec, return expected swapbuffers count SBC after this swap
1116f7df2e56Smrg     * will complete. This is ignored unless we return Success, but it must be
1117f7df2e56Smrg     * initialized on every path where we return Success or the caller will send
1118f7df2e56Smrg     * an uninitialized value off the stack to the client. So let's initialize
1119f7df2e56Smrg     * it as early as possible, just to be sure.
1120f7df2e56Smrg     */
1121f7df2e56Smrg    *swap_target = pPriv->swap_count + pPriv->swapsPending + 1;
1122f7df2e56Smrg
11236747b715Smrg    for (i = 0; i < pPriv->bufferCount; i++) {
1124f7df2e56Smrg        if (pPriv->buffers[i]->attachment == DRI2BufferFrontLeft)
1125f7df2e56Smrg            pDestBuffer = (DRI2BufferPtr) pPriv->buffers[i];
1126f7df2e56Smrg        if (pPriv->buffers[i]->attachment == DRI2BufferBackLeft)
1127f7df2e56Smrg            pSrcBuffer = (DRI2BufferPtr) pPriv->buffers[i];
11286747b715Smrg    }
11296747b715Smrg    if (pSrcBuffer == NULL || pDestBuffer == NULL) {
11306747b715Smrg        xf86DrvMsg(pScreen->myNum, X_ERROR,
1131f7df2e56Smrg                   "[DRI2] %s: drawable has no back or front?\n", __func__);
1132f7df2e56Smrg        return BadDrawable;
11336747b715Smrg    }
11346747b715Smrg
11356747b715Smrg    /* Old DDX or no swap interval, just blit */
1136f7df2e56Smrg    if (!ds->ScheduleSwap || !pPriv->swap_interval || pPriv->prime_id) {
1137f7df2e56Smrg        BoxRec box;
1138f7df2e56Smrg        RegionRec region;
11396747b715Smrg
1140f7df2e56Smrg        box.x1 = 0;
1141f7df2e56Smrg        box.y1 = 0;
1142f7df2e56Smrg        box.x2 = pDraw->width;
1143f7df2e56Smrg        box.y2 = pDraw->height;
1144f7df2e56Smrg        RegionInit(&region, &box, 0);
11456747b715Smrg
1146f7df2e56Smrg        pPriv->swapsPending++;
11476747b715Smrg
1148f7df2e56Smrg        dri2_copy_region(pDraw, &region, pDestBuffer, pSrcBuffer);
1149f7df2e56Smrg        DRI2SwapComplete(client, pDraw, target_msc, 0, 0, DRI2_BLIT_COMPLETE,
1150f7df2e56Smrg                         func, data);
1151f7df2e56Smrg        return Success;
11526747b715Smrg    }
11536747b715Smrg
11546747b715Smrg    /*
11556747b715Smrg     * In the simple glXSwapBuffers case, all params will be 0, and we just
11566747b715Smrg     * need to schedule a swap for the last swap target + the swap interval.
11576747b715Smrg     */
11586747b715Smrg    if (target_msc == 0 && divisor == 0 && remainder == 0) {
1159f7df2e56Smrg        /* If the current vblank count of the drawable's crtc is lower
1160f7df2e56Smrg         * than the count stored in last_swap_target from a previous swap
1161f7df2e56Smrg         * then reinitialize last_swap_target to the current crtc's msc,
1162f7df2e56Smrg         * otherwise the swap will hang. This will happen if the drawable
1163f7df2e56Smrg         * is moved to a crtc with a lower refresh rate, or a crtc that just
1164f7df2e56Smrg         * got enabled.
1165f7df2e56Smrg         */
1166f7df2e56Smrg        if (ds->GetMSC) {
1167f7df2e56Smrg            if (!(*ds->GetMSC) (pDraw, &ust, &current_msc))
1168f7df2e56Smrg                pPriv->last_swap_target = 0;
1169f7df2e56Smrg
1170f7df2e56Smrg            if (current_msc < pPriv->last_swap_target)
1171f7df2e56Smrg                pPriv->last_swap_target = current_msc;
1172f7df2e56Smrg
1173f7df2e56Smrg        }
1174f7df2e56Smrg
1175f7df2e56Smrg        /*
1176f7df2e56Smrg         * Swap target for this swap is last swap target + swap interval since
1177f7df2e56Smrg         * we have to account for the current swap count, interval, and the
1178f7df2e56Smrg         * number of pending swaps.
1179f7df2e56Smrg         */
1180f7df2e56Smrg        target_msc = pPriv->last_swap_target + pPriv->swap_interval;
1181f7df2e56Smrg
11826747b715Smrg    }
11836747b715Smrg
11846747b715Smrg    pPriv->swapsPending++;
1185f7df2e56Smrg    ret = (*ds->ScheduleSwap) (client, pDraw, pDestBuffer, pSrcBuffer,
1186f7df2e56Smrg                               &target_msc, divisor, remainder, func, data);
11876747b715Smrg    if (!ret) {
1188f7df2e56Smrg        pPriv->swapsPending--;  /* didn't schedule */
11896747b715Smrg        xf86DrvMsg(pScreen->myNum, X_ERROR,
1190f7df2e56Smrg                   "[DRI2] %s: driver failed to schedule swap\n", __func__);
1191f7df2e56Smrg        return BadDrawable;
11926747b715Smrg    }
11936747b715Smrg
1194f7df2e56Smrg    pPriv->last_swap_target = target_msc;
11956747b715Smrg
1196f7df2e56Smrg    DRI2InvalidateDrawableAll(pDraw);
11976747b715Smrg
11986747b715Smrg    return Success;
11996747b715Smrg}
12006747b715Smrg
12016747b715Smrgvoid
12026747b715SmrgDRI2SwapInterval(DrawablePtr pDrawable, int interval)
12036747b715Smrg{
1204f7df2e56Smrg    ScreenPtr pScreen = pDrawable->pScreen;
12056747b715Smrg    DRI2DrawablePtr pPriv = DRI2GetDrawable(pDrawable);
12066747b715Smrg
12076747b715Smrg    if (pPriv == NULL) {
12086747b715Smrg        xf86DrvMsg(pScreen->myNum, X_ERROR,
1209f7df2e56Smrg                   "[DRI2] %s: bad drawable\n", __func__);
1210f7df2e56Smrg        return;
12116747b715Smrg    }
12126747b715Smrg
12136747b715Smrg    /* fixme: check against arbitrary max? */
12146747b715Smrg    pPriv->swap_interval = interval;
12156747b715Smrg}
12166747b715Smrg
12176747b715Smrgint
1218f7df2e56SmrgDRI2GetMSC(DrawablePtr pDraw, CARD64 * ust, CARD64 * msc, CARD64 * sbc)
12196747b715Smrg{
12206747b715Smrg    ScreenPtr pScreen = pDraw->pScreen;
12216747b715Smrg    DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen);
12226747b715Smrg    DRI2DrawablePtr pPriv;
12236747b715Smrg    Bool ret;
12246747b715Smrg
12256747b715Smrg    pPriv = DRI2GetDrawable(pDraw);
12266747b715Smrg    if (pPriv == NULL) {
12276747b715Smrg        xf86DrvMsg(pScreen->myNum, X_ERROR,
1228f7df2e56Smrg                   "[DRI2] %s: bad drawable\n", __func__);
1229f7df2e56Smrg        return BadDrawable;
12306747b715Smrg    }
12316747b715Smrg
12326747b715Smrg    if (!ds->GetMSC) {
1233f7df2e56Smrg        *ust = 0;
1234f7df2e56Smrg        *msc = 0;
1235f7df2e56Smrg        *sbc = pPriv->swap_count;
1236f7df2e56Smrg        return Success;
12376747b715Smrg    }
12386747b715Smrg
12396747b715Smrg    /*
12406747b715Smrg     * Spec needs to be updated to include unmapped or redirected
12416747b715Smrg     * drawables
12426747b715Smrg     */
12436747b715Smrg
1244f7df2e56Smrg    ret = (*ds->GetMSC) (pDraw, ust, msc);
12456747b715Smrg    if (!ret)
1246f7df2e56Smrg        return BadDrawable;
12476747b715Smrg
12486747b715Smrg    *sbc = pPriv->swap_count;
12496747b715Smrg
12506747b715Smrg    return Success;
12516747b715Smrg}
12526747b715Smrg
12536747b715Smrgint
12546747b715SmrgDRI2WaitMSC(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc,
1255f7df2e56Smrg            CARD64 divisor, CARD64 remainder)
12566747b715Smrg{
12576747b715Smrg    DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen);
12586747b715Smrg    DRI2DrawablePtr pPriv;
12596747b715Smrg    Bool ret;
12606747b715Smrg
12616747b715Smrg    pPriv = DRI2GetDrawable(pDraw);
12626747b715Smrg    if (pPriv == NULL)
1263f7df2e56Smrg        return BadDrawable;
12646747b715Smrg
12656747b715Smrg    /* Old DDX just completes immediately */
12666747b715Smrg    if (!ds->ScheduleWaitMSC) {
1267f7df2e56Smrg        DRI2WaitMSCComplete(client, pDraw, target_msc, 0, 0);
12686747b715Smrg
1269f7df2e56Smrg        return Success;
12706747b715Smrg    }
12716747b715Smrg
1272f7df2e56Smrg    ret =
1273f7df2e56Smrg        (*ds->ScheduleWaitMSC) (client, pDraw, target_msc, divisor, remainder);
12746747b715Smrg    if (!ret)
1275f7df2e56Smrg        return BadDrawable;
12766747b715Smrg
12776747b715Smrg    return Success;
12786747b715Smrg}
12796747b715Smrg
12806747b715Smrgint
12816747b715SmrgDRI2WaitSBC(ClientPtr client, DrawablePtr pDraw, CARD64 target_sbc)
12826747b715Smrg{
12836747b715Smrg    DRI2DrawablePtr pPriv;
12846747b715Smrg
12856747b715Smrg    pPriv = DRI2GetDrawable(pDraw);
12866747b715Smrg    if (pPriv == NULL)
1287f7df2e56Smrg        return BadDrawable;
1288f7df2e56Smrg
1289f7df2e56Smrg    if (pPriv->target_sbc != -1) /* already in use */
1290f7df2e56Smrg        return BadDrawable;
12916747b715Smrg
12926747b715Smrg    /* target_sbc == 0 means to block until all pending swaps are
12936747b715Smrg     * finished. Recalculate target_sbc to get that behaviour.
12946747b715Smrg     */
12956747b715Smrg    if (target_sbc == 0)
12966747b715Smrg        target_sbc = pPriv->swap_count + pPriv->swapsPending;
12976747b715Smrg
12986747b715Smrg    /* If current swap count already >= target_sbc, reply and
12996747b715Smrg     * return immediately with (ust, msc, sbc) triplet of
13006747b715Smrg     * most recent completed swap.
13016747b715Smrg     */
13026747b715Smrg    if (pPriv->swap_count >= target_sbc) {
13036747b715Smrg        ProcDRI2WaitMSCReply(client, pPriv->last_swap_ust,
13046747b715Smrg                             pPriv->last_swap_msc, pPriv->swap_count);
13056747b715Smrg        return Success;
13064642e01fSmrg    }
13076747b715Smrg
1308f7df2e56Smrg    if (!dri2Sleep(client, pPriv, WAKE_SBC))
1309f7df2e56Smrg        return BadAlloc;
13106747b715Smrg
1311f7df2e56Smrg    pPriv->target_sbc = target_sbc;
13126747b715Smrg    return Success;
13136747b715Smrg}
13146747b715Smrg
13156747b715SmrgBool
13166747b715SmrgDRI2HasSwapControl(ScreenPtr pScreen)
13176747b715Smrg{
13186747b715Smrg    DRI2ScreenPtr ds = DRI2GetScreen(pScreen);
13196747b715Smrg
13206747b715Smrg    return ds->ScheduleSwap && ds->GetMSC;
13214642e01fSmrg}
13224642e01fSmrg
13234642e01fSmrgBool
1324f7df2e56SmrgDRI2Connect(ClientPtr client, ScreenPtr pScreen,
1325f7df2e56Smrg            unsigned int driverType, int *fd,
1326f7df2e56Smrg            const char **driverName, const char **deviceName)
13274642e01fSmrg{
13286747b715Smrg    DRI2ScreenPtr ds;
1329f7df2e56Smrg    uint32_t prime_id = DRI2DriverPrimeId(driverType);
1330f7df2e56Smrg    uint32_t driver_id = driverType & 0xffff;
13314642e01fSmrg
13326747b715Smrg    if (!dixPrivateKeyRegistered(dri2ScreenPrivateKey))
1333f7df2e56Smrg        return FALSE;
13344642e01fSmrg
1335f7df2e56Smrg    ds = DRI2GetScreenPrime(pScreen, prime_id);
1336f7df2e56Smrg    if (ds == NULL)
1337f7df2e56Smrg        return FALSE;
13384642e01fSmrg
1339f7df2e56Smrg    if (driver_id >= ds->numDrivers ||
1340f7df2e56Smrg        !ds->driverNames[driver_id])
1341f7df2e56Smrg        return FALSE;
1342f7df2e56Smrg
1343f7df2e56Smrg    *driverName = ds->driverNames[driver_id];
13444642e01fSmrg    *deviceName = ds->deviceName;
1345f7df2e56Smrg    *fd = ds->fd;
1346f7df2e56Smrg
1347f7df2e56Smrg    if (client) {
1348f7df2e56Smrg        DRI2ClientPtr dri2_client;
1349f7df2e56Smrg        dri2_client = dri2ClientPrivate(client);
1350f7df2e56Smrg        dri2_client->prime_id = prime_id;
1351f7df2e56Smrg    }
13524642e01fSmrg
13534642e01fSmrg    return TRUE;
13544642e01fSmrg}
13554642e01fSmrg
1356f7df2e56Smrgstatic int
1357f7df2e56SmrgDRI2AuthMagic (ScreenPtr pScreen, uint32_t magic)
13584642e01fSmrg{
13594642e01fSmrg    DRI2ScreenPtr ds = DRI2GetScreen(pScreen);
1360f7df2e56Smrg    if (ds == NULL)
1361f7df2e56Smrg        return -EINVAL;
13624642e01fSmrg
1363f7df2e56Smrg    return (*ds->LegacyAuthMagic) (ds->fd, magic);
1364f7df2e56Smrg}
1365f7df2e56Smrg
1366f7df2e56SmrgBool
1367f7df2e56SmrgDRI2Authenticate(ClientPtr client, ScreenPtr pScreen, uint32_t magic)
1368f7df2e56Smrg{
1369f7df2e56Smrg    DRI2ScreenPtr ds;
1370d566a54bSmrg    DRI2ClientPtr dri2_client;
1371f7df2e56Smrg    ScreenPtr primescreen;
1372f7df2e56Smrg
1373d566a54bSmrg    if (!dixPrivateKeyRegistered(dri2ScreenPrivateKey))
1374d566a54bSmrg        return FALSE;
1375d566a54bSmrg
1376d566a54bSmrg    dri2_client = dri2ClientPrivate(client);
1377d566a54bSmrg
1378f7df2e56Smrg    ds = DRI2GetScreenPrime(pScreen, dri2_client->prime_id);
1379f7df2e56Smrg    if (ds == NULL)
13806747b715Smrg        return FALSE;
13814642e01fSmrg
1382f7df2e56Smrg    primescreen = GetScreenPrime(pScreen, dri2_client->prime_id);
1383f7df2e56Smrg    if ((*ds->AuthMagic)(primescreen, magic))
1384f7df2e56Smrg        return FALSE;
13854642e01fSmrg    return TRUE;
13864642e01fSmrg}
13874642e01fSmrg
13886747b715Smrgstatic int
13896747b715SmrgDRI2ConfigNotify(WindowPtr pWin, int x, int y, int w, int h, int bw,
1390f7df2e56Smrg                 WindowPtr pSib)
13916747b715Smrg{
1392f7df2e56Smrg    DrawablePtr pDraw = (DrawablePtr) pWin;
13936747b715Smrg    ScreenPtr pScreen = pDraw->pScreen;
13946747b715Smrg    DRI2ScreenPtr ds = DRI2GetScreen(pScreen);
13956747b715Smrg    DRI2DrawablePtr dd = DRI2GetDrawable(pDraw);
13966747b715Smrg    int ret;
13976747b715Smrg
13986747b715Smrg    if (ds->ConfigNotify) {
1399f7df2e56Smrg        pScreen->ConfigNotify = ds->ConfigNotify;
14006747b715Smrg
1401f7df2e56Smrg        ret = (*pScreen->ConfigNotify) (pWin, x, y, w, h, bw, pSib);
14026747b715Smrg
1403f7df2e56Smrg        ds->ConfigNotify = pScreen->ConfigNotify;
1404f7df2e56Smrg        pScreen->ConfigNotify = DRI2ConfigNotify;
1405f7df2e56Smrg        if (ret)
1406f7df2e56Smrg            return ret;
14076747b715Smrg    }
14086747b715Smrg
14096747b715Smrg    if (!dd || (dd->width == w && dd->height == h))
1410f7df2e56Smrg        return Success;
14116747b715Smrg
14126747b715Smrg    DRI2InvalidateDrawable(pDraw);
14136747b715Smrg    return Success;
14146747b715Smrg}
14156747b715Smrg
1416f7df2e56Smrgstatic void
1417f7df2e56SmrgDRI2SetWindowPixmap(WindowPtr pWin, PixmapPtr pPix)
1418f7df2e56Smrg{
1419f7df2e56Smrg    ScreenPtr pScreen = pWin->drawable.pScreen;
1420f7df2e56Smrg    DRI2ScreenPtr ds = DRI2GetScreen(pScreen);
1421f7df2e56Smrg
1422f7df2e56Smrg    pScreen->SetWindowPixmap = ds->SetWindowPixmap;
1423f7df2e56Smrg    (*pScreen->SetWindowPixmap) (pWin, pPix);
1424f7df2e56Smrg    ds->SetWindowPixmap = pScreen->SetWindowPixmap;
1425f7df2e56Smrg    pScreen->SetWindowPixmap = DRI2SetWindowPixmap;
1426f7df2e56Smrg
1427f7df2e56Smrg    DRI2InvalidateDrawable(&pWin->drawable);
1428f7df2e56Smrg}
1429f7df2e56Smrg
1430f7df2e56Smrg#define MAX_PRIME DRI2DriverPrimeMask
1431f7df2e56Smrgstatic int
1432f7df2e56Smrgget_prime_id(void)
1433f7df2e56Smrg{
1434f7df2e56Smrg    int i;
1435f7df2e56Smrg    /* start at 1, prime id 0 is just normal driver */
1436f7df2e56Smrg    for (i = 1; i < MAX_PRIME; i++) {
1437f7df2e56Smrg         if (prime_id_allocate_bitmask & (1 << i))
1438f7df2e56Smrg             continue;
1439f7df2e56Smrg
1440f7df2e56Smrg         prime_id_allocate_bitmask |= (1 << i);
1441f7df2e56Smrg         return i;
1442f7df2e56Smrg    }
1443f7df2e56Smrg    return -1;
1444f7df2e56Smrg}
1445f7df2e56Smrg
1446f7df2e56Smrg#include "pci_ids/pci_id_driver_map.h"
1447f7df2e56Smrg
1448f7df2e56Smrgstatic char *
1449f7df2e56Smrgdri2_probe_driver_name(ScreenPtr pScreen, DRI2InfoPtr info)
1450f7df2e56Smrg{
14517e31ba66Smrg#ifdef WITH_LIBDRM
1452f7df2e56Smrg    int i, j;
14537e31ba66Smrg    char *driver = NULL;
14547e31ba66Smrg    drmDevicePtr dev;
1455f7df2e56Smrg
14567e31ba66Smrg    /* For non-PCI devices and drmGetDevice fail, just assume that
14577e31ba66Smrg     * the 3D driver is named the same as the kernel driver. This is
14587e31ba66Smrg     * currently true for vc4 and msm (freedreno).
1459f7df2e56Smrg     */
14607e31ba66Smrg    if (drmGetDevice(info->fd, &dev) || dev->bustype != DRM_BUS_PCI) {
1461f7df2e56Smrg        drmVersionPtr version = drmGetVersion(info->fd);
1462f7df2e56Smrg
1463f7df2e56Smrg        if (!version) {
1464f7df2e56Smrg            xf86DrvMsg(pScreen->myNum, X_ERROR,
1465f7df2e56Smrg                       "[DRI2] Couldn't drmGetVersion() on non-PCI device, "
1466f7df2e56Smrg                       "no driver name found.\n");
1467f7df2e56Smrg            return NULL;
1468f7df2e56Smrg        }
1469f7df2e56Smrg
14707e31ba66Smrg        driver = strndup(version->name, version->name_len);
1471f7df2e56Smrg        drmFreeVersion(version);
14727e31ba66Smrg        return driver;
1473f7df2e56Smrg    }
1474f7df2e56Smrg
1475f7df2e56Smrg    for (i = 0; driver_map[i].driver; i++) {
14767e31ba66Smrg        if (dev->deviceinfo.pci->vendor_id != driver_map[i].vendor_id)
1477f7df2e56Smrg            continue;
1478f7df2e56Smrg
14797e31ba66Smrg        if (driver_map[i].num_chips_ids == -1) {
14807e31ba66Smrg             driver = strdup(driver_map[i].driver);
14817e31ba66Smrg             goto out;
14827e31ba66Smrg        }
1483f7df2e56Smrg
1484f7df2e56Smrg        for (j = 0; j < driver_map[i].num_chips_ids; j++) {
14857e31ba66Smrg            if (driver_map[i].chip_ids[j] == dev->deviceinfo.pci->device_id) {
14867e31ba66Smrg                driver = strdup(driver_map[i].driver);
14877e31ba66Smrg                goto out;
14887e31ba66Smrg            }
1489f7df2e56Smrg        }
1490f7df2e56Smrg    }
1491f7df2e56Smrg
1492f7df2e56Smrg    xf86DrvMsg(pScreen->myNum, X_ERROR,
1493f7df2e56Smrg               "[DRI2] No driver mapping found for PCI device "
1494f7df2e56Smrg               "0x%04x / 0x%04x\n",
14957e31ba66Smrg               dev->deviceinfo.pci->vendor_id, dev->deviceinfo.pci->device_id);
14967e31ba66Smrgout:
14977e31ba66Smrg    drmFreeDevice(&dev);
14987e31ba66Smrg    return driver;
14997e31ba66Smrg#else
1500f7df2e56Smrg    return NULL;
15017e31ba66Smrg#endif
1502f7df2e56Smrg}
1503f7df2e56Smrg
15044642e01fSmrgBool
15054642e01fSmrgDRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info)
15064642e01fSmrg{
15074642e01fSmrg    DRI2ScreenPtr ds;
1508f7df2e56Smrg
1509f7df2e56Smrg    const char *driverTypeNames[] = {
1510f7df2e56Smrg        "DRI",                  /* DRI2DriverDRI */
1511f7df2e56Smrg        "VDPAU",                /* DRI2DriverVDPAU */
15126747b715Smrg    };
15136747b715Smrg    unsigned int i;
15146747b715Smrg    CARD8 cur_minor;
15156747b715Smrg
15166747b715Smrg    if (info->version < 3)
1517f7df2e56Smrg        return FALSE;
15184642e01fSmrg
15196747b715Smrg    if (!dixRegisterPrivateKey(&dri2ScreenPrivateKeyRec, PRIVATE_SCREEN, 0))
1520f7df2e56Smrg        return FALSE;
15216747b715Smrg
15226747b715Smrg    if (!dixRegisterPrivateKey(&dri2WindowPrivateKeyRec, PRIVATE_WINDOW, 0))
1523f7df2e56Smrg        return FALSE;
15246747b715Smrg
15256747b715Smrg    if (!dixRegisterPrivateKey(&dri2PixmapPrivateKeyRec, PRIVATE_PIXMAP, 0))
1526f7df2e56Smrg        return FALSE;
1527f7df2e56Smrg
1528f7df2e56Smrg    if (!dixRegisterPrivateKey(&dri2ClientPrivateKeyRec, PRIVATE_CLIENT, sizeof(DRI2ClientRec)))
1529f7df2e56Smrg        return FALSE;
15306747b715Smrg
15316747b715Smrg    ds = calloc(1, sizeof *ds);
15324642e01fSmrg    if (!ds)
1533f7df2e56Smrg        return FALSE;
15344642e01fSmrg
1535f7df2e56Smrg    ds->screen = pScreen;
1536f7df2e56Smrg    ds->fd = info->fd;
1537f7df2e56Smrg    ds->deviceName = info->deviceName;
1538f7df2e56Smrg    dri2_major = 1;
15396747b715Smrg
1540f7df2e56Smrg    ds->CreateBuffer = info->CreateBuffer;
1541f7df2e56Smrg    ds->DestroyBuffer = info->DestroyBuffer;
1542f7df2e56Smrg    ds->CopyRegion = info->CopyRegion;
15437e31ba66Smrg    cur_minor = 1;
154452397711Smrg
15456747b715Smrg    if (info->version >= 4) {
1546f7df2e56Smrg        ds->ScheduleSwap = info->ScheduleSwap;
1547f7df2e56Smrg        ds->ScheduleWaitMSC = info->ScheduleWaitMSC;
1548f7df2e56Smrg        ds->GetMSC = info->GetMSC;
1549f7df2e56Smrg        cur_minor = 3;
1550f7df2e56Smrg    }
155152397711Smrg
15526747b715Smrg    if (info->version >= 5) {
1553f7df2e56Smrg        ds->LegacyAuthMagic = info->AuthMagic;
1554f7df2e56Smrg    }
1555f7df2e56Smrg
1556f7df2e56Smrg    if (info->version >= 6) {
1557f7df2e56Smrg        ds->ReuseBufferNotify = info->ReuseBufferNotify;
1558f7df2e56Smrg        ds->SwapLimitValidate = info->SwapLimitValidate;
1559f7df2e56Smrg    }
1560f7df2e56Smrg
1561f7df2e56Smrg    if (info->version >= 7) {
1562f7df2e56Smrg        ds->GetParam = info->GetParam;
1563f7df2e56Smrg        cur_minor = 4;
1564f7df2e56Smrg    }
1565f7df2e56Smrg
15667e31ba66Smrg    if (info->version >= 8) {
15677e31ba66Smrg        ds->AuthMagic = info->AuthMagic2;
15687e31ba66Smrg    }
15697e31ba66Smrg
1570f7df2e56Smrg    if (info->version >= 9) {
1571f7df2e56Smrg        ds->CreateBuffer2 = info->CreateBuffer2;
1572f7df2e56Smrg        if (info->CreateBuffer2 && pScreen->isGPU) {
1573f7df2e56Smrg            ds->prime_id = get_prime_id();
1574f7df2e56Smrg            if (ds->prime_id == -1) {
1575f7df2e56Smrg                free(ds);
1576f7df2e56Smrg                return FALSE;
1577f7df2e56Smrg            }
1578f7df2e56Smrg        }
1579f7df2e56Smrg        ds->DestroyBuffer2 = info->DestroyBuffer2;
1580f7df2e56Smrg        ds->CopyRegion2 = info->CopyRegion2;
15816747b715Smrg    }
15826747b715Smrg
15836747b715Smrg    /*
15846747b715Smrg     * if the driver doesn't provide an AuthMagic function or the info struct
1585f7df2e56Smrg     * version is too low, call through LegacyAuthMagic
15866747b715Smrg     */
1587f7df2e56Smrg    if (!ds->AuthMagic) {
1588f7df2e56Smrg        ds->AuthMagic = DRI2AuthMagic;
1589f7df2e56Smrg        /*
1590f7df2e56Smrg         * If the driver doesn't provide an AuthMagic function
1591f7df2e56Smrg         * it relies on the old method (using libdrm) or fails
1592f7df2e56Smrg         */
1593f7df2e56Smrg        if (!ds->LegacyAuthMagic)
15946747b715Smrg#ifdef WITH_LIBDRM
1595f7df2e56Smrg            ds->LegacyAuthMagic = drmAuthMagic;
15966747b715Smrg#else
1597f7df2e56Smrg            goto err_out;
15986747b715Smrg#endif
1599f7df2e56Smrg    }
16006747b715Smrg
16016747b715Smrg    /* Initialize minor if needed and set to minimum provied by DDX */
16026747b715Smrg    if (!dri2_minor || dri2_minor > cur_minor)
1603f7df2e56Smrg        dri2_minor = cur_minor;
16046747b715Smrg
16056747b715Smrg    if (info->version == 3 || info->numDrivers == 0) {
1606f7df2e56Smrg        /* Driver too old: use the old-style driverName field */
1607f7df2e56Smrg        ds->numDrivers = info->driverName ? 1 : 2;
1608f7df2e56Smrg        ds->driverNames = xallocarray(ds->numDrivers, sizeof(*ds->driverNames));
1609f7df2e56Smrg        if (!ds->driverNames)
1610f7df2e56Smrg            goto err_out;
1611f7df2e56Smrg
1612f7df2e56Smrg        if (info->driverName) {
1613f7df2e56Smrg            ds->driverNames[0] = info->driverName;
1614f7df2e56Smrg        } else {
16155a112b11Smrg            /* FIXME dri2_probe_driver_name() returns a strdup-ed string,
16165a112b11Smrg             * currently this gets leaked */
1617f7df2e56Smrg            ds->driverNames[0] = ds->driverNames[1] = dri2_probe_driver_name(pScreen, info);
1618f7df2e56Smrg            if (!ds->driverNames[0])
1619f7df2e56Smrg                return FALSE;
16205a112b11Smrg
16215a112b11Smrg            /* There is no VDPAU driver for i965, fallback to the generic
16225a112b11Smrg             * OpenGL/VAAPI va_gl backend to emulate VDPAU on i965. */
16235a112b11Smrg            if (strcmp(ds->driverNames[0], "i965") == 0)
16245a112b11Smrg                ds->driverNames[1] = "va_gl";
1625f7df2e56Smrg        }
1626f7df2e56Smrg    }
1627f7df2e56Smrg    else {
1628f7df2e56Smrg        ds->numDrivers = info->numDrivers;
1629f7df2e56Smrg        ds->driverNames = xallocarray(info->numDrivers, sizeof(*ds->driverNames));
1630f7df2e56Smrg        if (!ds->driverNames)
1631f7df2e56Smrg            goto err_out;
1632f7df2e56Smrg        memcpy(ds->driverNames, info->driverNames,
1633f7df2e56Smrg               info->numDrivers * sizeof(*ds->driverNames));
163452397711Smrg    }
16354642e01fSmrg
16364642e01fSmrg    dixSetPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey, ds);
16374642e01fSmrg
16386747b715Smrg    ds->ConfigNotify = pScreen->ConfigNotify;
16396747b715Smrg    pScreen->ConfigNotify = DRI2ConfigNotify;
16406747b715Smrg
1641f7df2e56Smrg    ds->SetWindowPixmap = pScreen->SetWindowPixmap;
1642f7df2e56Smrg    pScreen->SetWindowPixmap = DRI2SetWindowPixmap;
1643f7df2e56Smrg
16444642e01fSmrg    xf86DrvMsg(pScreen->myNum, X_INFO, "[DRI2] Setup complete\n");
16457e31ba66Smrg    for (i = 0; i < ARRAY_SIZE(driverTypeNames); i++) {
1646f7df2e56Smrg        if (i < ds->numDrivers && ds->driverNames[i]) {
1647f7df2e56Smrg            xf86DrvMsg(pScreen->myNum, X_INFO, "[DRI2]   %s driver: %s\n",
1648f7df2e56Smrg                       driverTypeNames[i], ds->driverNames[i]);
1649f7df2e56Smrg        }
16506747b715Smrg    }
16514642e01fSmrg
16524642e01fSmrg    return TRUE;
16536747b715Smrg
1654f7df2e56Smrg err_out:
16556747b715Smrg    xf86DrvMsg(pScreen->myNum, X_WARNING,
1656f7df2e56Smrg               "[DRI2] Initialization failed for info version %d.\n",
1657f7df2e56Smrg               info->version);
16586747b715Smrg    free(ds);
16596747b715Smrg    return FALSE;
16604642e01fSmrg}
16614642e01fSmrg
16624642e01fSmrgvoid
16634642e01fSmrgDRI2CloseScreen(ScreenPtr pScreen)
16644642e01fSmrg{
16654642e01fSmrg    DRI2ScreenPtr ds = DRI2GetScreen(pScreen);
16664642e01fSmrg
1667f7df2e56Smrg    pScreen->ConfigNotify = ds->ConfigNotify;
1668f7df2e56Smrg    pScreen->SetWindowPixmap = ds->SetWindowPixmap;
1669f7df2e56Smrg
1670f7df2e56Smrg    if (ds->prime_id)
1671f7df2e56Smrg        prime_id_allocate_bitmask &= ~(1 << ds->prime_id);
16726747b715Smrg    free(ds->driverNames);
16736747b715Smrg    free(ds);
16744642e01fSmrg    dixSetPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey, NULL);
16754642e01fSmrg}
16764642e01fSmrg
1677475c125cSmrg/* Called by InitExtensions() */
1678475c125cSmrgBool
1679475c125cSmrgDRI2ModuleSetup(void)
1680475c125cSmrg{
1681475c125cSmrg    dri2DrawableRes = CreateNewResourceType(DRI2DrawableGone, "DRI2Drawable");
1682475c125cSmrg    if (!dri2DrawableRes)
1683f7df2e56Smrg        return FALSE;
1684475c125cSmrg
1685475c125cSmrg    return TRUE;
1686475c125cSmrg}
16874642e01fSmrg
168852397711Smrgvoid
168952397711SmrgDRI2Version(int *major, int *minor)
169052397711Smrg{
169152397711Smrg    if (major != NULL)
1692f7df2e56Smrg        *major = 1;
169352397711Smrg
169452397711Smrg    if (minor != NULL)
1695f7df2e56Smrg        *minor = 2;
1696f7df2e56Smrg}
1697f7df2e56Smrg
1698f7df2e56Smrgint
1699f7df2e56SmrgDRI2GetParam(ClientPtr client,
1700f7df2e56Smrg             DrawablePtr drawable,
1701f7df2e56Smrg             CARD64 param,
1702f7df2e56Smrg             BOOL *is_param_recognized,
1703f7df2e56Smrg             CARD64 *value)
1704f7df2e56Smrg{
1705f7df2e56Smrg    DRI2ScreenPtr ds = DRI2GetScreen(drawable->pScreen);
1706f7df2e56Smrg    char high_byte = (param >> 24);
1707f7df2e56Smrg
1708f7df2e56Smrg    switch (high_byte) {
1709f7df2e56Smrg    case 0:
1710f7df2e56Smrg        /* Parameter names whose high_byte is 0 are reserved for the X
1711f7df2e56Smrg         * server. The server currently recognizes no parameters.
1712f7df2e56Smrg         */
1713f7df2e56Smrg        goto not_recognized;
1714f7df2e56Smrg    case 1:
1715f7df2e56Smrg        /* Parameter names whose high byte is 1 are reserved for the DDX. */
1716f7df2e56Smrg        if (ds->GetParam)
1717f7df2e56Smrg            return ds->GetParam(client, drawable, param,
1718f7df2e56Smrg                                is_param_recognized, value);
1719f7df2e56Smrg        else
1720f7df2e56Smrg            goto not_recognized;
1721f7df2e56Smrg    default:
1722f7df2e56Smrg        /* Other parameter names are reserved for future use. They are never
1723f7df2e56Smrg         * recognized.
1724f7df2e56Smrg         */
1725f7df2e56Smrg        goto not_recognized;
1726f7df2e56Smrg    }
1727f7df2e56Smrg
1728f7df2e56Smrgnot_recognized:
1729f7df2e56Smrg    *is_param_recognized = FALSE;
1730f7df2e56Smrg    return Success;
173152397711Smrg}
1732