14642e01fSmrg/*
24642e01fSmrg * Copyright © 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
374642e01fSmrg#include <X11/X.h>
384642e01fSmrg#include <X11/Xproto.h>
394642e01fSmrg#include <X11/extensions/dri2proto.h>
404642e01fSmrg#include <X11/extensions/xfixeswire.h>
414642e01fSmrg#include "dixstruct.h"
424642e01fSmrg#include "scrnintstr.h"
434642e01fSmrg#include "pixmapstr.h"
444642e01fSmrg#include "extnsionst.h"
454642e01fSmrg#include "xfixes.h"
464642e01fSmrg#include "dri2.h"
47f7df2e56Smrg#include "dri2int.h"
486747b715Smrg#include "protocol-versions.h"
494642e01fSmrg
50f7df2e56Smrg/* The only xf86 includes */
514642e01fSmrg#include "xf86Module.h"
52f7df2e56Smrg#include "xf86Extensions.h"
53f7df2e56Smrg
54f7df2e56Smrgstatic int DRI2EventBase;
554642e01fSmrg
564642e01fSmrg
574642e01fSmrgstatic Bool
586747b715SmrgvalidDrawable(ClientPtr client, XID drawable, Mask access_mode,
59f7df2e56Smrg              DrawablePtr *pDrawable, int *status)
604642e01fSmrg{
616747b715Smrg    *status = dixLookupDrawable(pDrawable, drawable, client,
62f7df2e56Smrg                                M_DRAWABLE_WINDOW | M_DRAWABLE_PIXMAP,
63f7df2e56Smrg                                access_mode);
644642e01fSmrg    if (*status != Success) {
65f7df2e56Smrg        client->errorValue = drawable;
66f7df2e56Smrg        return FALSE;
674642e01fSmrg    }
684642e01fSmrg
694642e01fSmrg    return TRUE;
704642e01fSmrg}
714642e01fSmrg
724642e01fSmrgstatic int
734642e01fSmrgProcDRI2QueryVersion(ClientPtr client)
744642e01fSmrg{
754642e01fSmrg    REQUEST(xDRI2QueryVersionReq);
76f7df2e56Smrg    xDRI2QueryVersionReply rep = {
77f7df2e56Smrg        .type = X_Reply,
78f7df2e56Smrg        .sequenceNumber = client->sequence,
79f7df2e56Smrg        .length = 0,
80f7df2e56Smrg        .majorVersion = dri2_major,
81f7df2e56Smrg        .minorVersion = dri2_minor
82f7df2e56Smrg    };
834642e01fSmrg
844642e01fSmrg    if (client->swapped)
85f7df2e56Smrg        swaps(&stuff->length);
864642e01fSmrg
874642e01fSmrg    REQUEST_SIZE_MATCH(xDRI2QueryVersionReq);
884642e01fSmrg
894642e01fSmrg    if (client->swapped) {
90f7df2e56Smrg        swaps(&rep.sequenceNumber);
91f7df2e56Smrg        swapl(&rep.length);
92f7df2e56Smrg        swapl(&rep.majorVersion);
93f7df2e56Smrg        swapl(&rep.minorVersion);
944642e01fSmrg    }
954642e01fSmrg
964642e01fSmrg    WriteToClient(client, sizeof(xDRI2QueryVersionReply), &rep);
974642e01fSmrg
986747b715Smrg    return Success;
994642e01fSmrg}
1004642e01fSmrg
1014642e01fSmrgstatic int
1024642e01fSmrgProcDRI2Connect(ClientPtr client)
1034642e01fSmrg{
1044642e01fSmrg    REQUEST(xDRI2ConnectReq);
105f7df2e56Smrg    xDRI2ConnectReply rep = {
106f7df2e56Smrg        .type = X_Reply,
107f7df2e56Smrg        .sequenceNumber = client->sequence,
108f7df2e56Smrg        .length = 0,
109f7df2e56Smrg        .driverNameLength = 0,
110f7df2e56Smrg        .deviceNameLength = 0
111f7df2e56Smrg    };
1124642e01fSmrg    DrawablePtr pDraw;
1134642e01fSmrg    int fd, status;
1144642e01fSmrg    const char *driverName;
1154642e01fSmrg    const char *deviceName;
1164642e01fSmrg
1174642e01fSmrg    REQUEST_SIZE_MATCH(xDRI2ConnectReq);
1186747b715Smrg    if (!validDrawable(client, stuff->window, DixGetAttrAccess,
119f7df2e56Smrg                       &pDraw, &status))
120f7df2e56Smrg        return status;
121f7df2e56Smrg
122f7df2e56Smrg    if (!DRI2Connect(client, pDraw->pScreen,
123f7df2e56Smrg                     stuff->driverType, &fd, &driverName, &deviceName))
124f7df2e56Smrg        goto fail;
1254642e01fSmrg
1264642e01fSmrg    rep.driverNameLength = strlen(driverName);
1274642e01fSmrg    rep.deviceNameLength = strlen(deviceName);
1284642e01fSmrg    rep.length = (rep.driverNameLength + 3) / 4 +
129f7df2e56Smrg        (rep.deviceNameLength + 3) / 4;
1304642e01fSmrg
1314642e01fSmrg fail:
1324642e01fSmrg    WriteToClient(client, sizeof(xDRI2ConnectReply), &rep);
1334642e01fSmrg    WriteToClient(client, rep.driverNameLength, driverName);
1344642e01fSmrg    WriteToClient(client, rep.deviceNameLength, deviceName);
1354642e01fSmrg
1366747b715Smrg    return Success;
1374642e01fSmrg}
1384642e01fSmrg
1394642e01fSmrgstatic int
1404642e01fSmrgProcDRI2Authenticate(ClientPtr client)
1414642e01fSmrg{
1424642e01fSmrg    REQUEST(xDRI2AuthenticateReq);
1434642e01fSmrg    xDRI2AuthenticateReply rep;
1444642e01fSmrg    DrawablePtr pDraw;
1454642e01fSmrg    int status;
1464642e01fSmrg
1474642e01fSmrg    REQUEST_SIZE_MATCH(xDRI2AuthenticateReq);
1486747b715Smrg    if (!validDrawable(client, stuff->window, DixGetAttrAccess,
149f7df2e56Smrg                       &pDraw, &status))
150f7df2e56Smrg        return status;
151f7df2e56Smrg
152f7df2e56Smrg    rep = (xDRI2AuthenticateReply) {
153f7df2e56Smrg        .type = X_Reply,
154f7df2e56Smrg        .sequenceNumber = client->sequence,
155f7df2e56Smrg        .length = 0,
156f7df2e56Smrg        .authenticated = DRI2Authenticate(client, pDraw->pScreen, stuff->magic)
157f7df2e56Smrg    };
1584642e01fSmrg    WriteToClient(client, sizeof(xDRI2AuthenticateReply), &rep);
1594642e01fSmrg
1606747b715Smrg    return Success;
1616747b715Smrg}
1626747b715Smrg
1636747b715Smrgstatic void
164f7df2e56SmrgDRI2InvalidateBuffersEvent(DrawablePtr pDraw, void *priv, XID id)
1656747b715Smrg{
1666747b715Smrg    ClientPtr client = priv;
167f7df2e56Smrg    xDRI2InvalidateBuffers event = {
168f7df2e56Smrg        .type = DRI2EventBase + DRI2_InvalidateBuffers,
169f7df2e56Smrg        .drawable = id
170f7df2e56Smrg    };
1716747b715Smrg
172f7df2e56Smrg    WriteEventsToClient(client, 1, (xEvent *) &event);
1734642e01fSmrg}
1744642e01fSmrg
1754642e01fSmrgstatic int
1764642e01fSmrgProcDRI2CreateDrawable(ClientPtr client)
1774642e01fSmrg{
1784642e01fSmrg    REQUEST(xDRI2CreateDrawableReq);
1794642e01fSmrg    DrawablePtr pDrawable;
1804642e01fSmrg    int status;
1814642e01fSmrg
1824642e01fSmrg    REQUEST_SIZE_MATCH(xDRI2CreateDrawableReq);
1834642e01fSmrg
1846747b715Smrg    if (!validDrawable(client, stuff->drawable, DixAddAccess,
185f7df2e56Smrg                       &pDrawable, &status))
186f7df2e56Smrg        return status;
1874642e01fSmrg
1886747b715Smrg    status = DRI2CreateDrawable(client, pDrawable, stuff->drawable,
189f7df2e56Smrg                                DRI2InvalidateBuffersEvent, client);
1904642e01fSmrg    if (status != Success)
191f7df2e56Smrg        return status;
1924642e01fSmrg
1936747b715Smrg    return Success;
1944642e01fSmrg}
1954642e01fSmrg
1964642e01fSmrgstatic int
1974642e01fSmrgProcDRI2DestroyDrawable(ClientPtr client)
1984642e01fSmrg{
1994642e01fSmrg    REQUEST(xDRI2DestroyDrawableReq);
2004642e01fSmrg    DrawablePtr pDrawable;
2014642e01fSmrg    int status;
2024642e01fSmrg
2034642e01fSmrg    REQUEST_SIZE_MATCH(xDRI2DestroyDrawableReq);
2046747b715Smrg    if (!validDrawable(client, stuff->drawable, DixRemoveAccess,
205f7df2e56Smrg                       &pDrawable, &status))
206f7df2e56Smrg        return status;
2074642e01fSmrg
2086747b715Smrg    return Success;
2094642e01fSmrg}
2104642e01fSmrg
2116747b715Smrgstatic int
21252397711Smrgsend_buffers_reply(ClientPtr client, DrawablePtr pDrawable,
213f7df2e56Smrg                   DRI2BufferPtr * buffers, int count, int width, int height)
21452397711Smrg{
21552397711Smrg    xDRI2GetBuffersReply rep;
21652397711Smrg    int skip = 0;
21752397711Smrg    int i;
21852397711Smrg
2196747b715Smrg    if (buffers == NULL)
220f7df2e56Smrg        return BadAlloc;
2216747b715Smrg
22252397711Smrg    if (pDrawable->type == DRAWABLE_WINDOW) {
223f7df2e56Smrg        for (i = 0; i < count; i++) {
224f7df2e56Smrg            /* Do not send the real front buffer of a window to the client.
225f7df2e56Smrg             */
226f7df2e56Smrg            if (buffers[i]->attachment == DRI2BufferFrontLeft) {
227f7df2e56Smrg                skip++;
228f7df2e56Smrg                continue;
229f7df2e56Smrg            }
230f7df2e56Smrg        }
23152397711Smrg    }
23252397711Smrg
233f7df2e56Smrg    rep = (xDRI2GetBuffersReply) {
234f7df2e56Smrg        .type = X_Reply,
235f7df2e56Smrg        .sequenceNumber = client->sequence,
236f7df2e56Smrg        .length = (count - skip) * sizeof(xDRI2Buffer) / 4,
237f7df2e56Smrg        .width = width,
238f7df2e56Smrg        .height = height,
239f7df2e56Smrg        .count = count - skip
240f7df2e56Smrg    };
24152397711Smrg    WriteToClient(client, sizeof(xDRI2GetBuffersReply), &rep);
24252397711Smrg
24352397711Smrg    for (i = 0; i < count; i++) {
244f7df2e56Smrg        xDRI2Buffer buffer;
245f7df2e56Smrg
246f7df2e56Smrg        /* Do not send the real front buffer of a window to the client.
247f7df2e56Smrg         */
248f7df2e56Smrg        if ((pDrawable->type == DRAWABLE_WINDOW)
249f7df2e56Smrg            && (buffers[i]->attachment == DRI2BufferFrontLeft)) {
250f7df2e56Smrg            continue;
251f7df2e56Smrg        }
252f7df2e56Smrg
253f7df2e56Smrg        buffer.attachment = buffers[i]->attachment;
254f7df2e56Smrg        buffer.name = buffers[i]->name;
255f7df2e56Smrg        buffer.pitch = buffers[i]->pitch;
256f7df2e56Smrg        buffer.cpp = buffers[i]->cpp;
257f7df2e56Smrg        buffer.flags = buffers[i]->flags;
258f7df2e56Smrg        WriteToClient(client, sizeof(xDRI2Buffer), &buffer);
25952397711Smrg    }
2606747b715Smrg    return Success;
26152397711Smrg}
26252397711Smrg
2634642e01fSmrgstatic int
2644642e01fSmrgProcDRI2GetBuffers(ClientPtr client)
2654642e01fSmrg{
2664642e01fSmrg    REQUEST(xDRI2GetBuffersReq);
2674642e01fSmrg    DrawablePtr pDrawable;
2686747b715Smrg    DRI2BufferPtr *buffers;
26952397711Smrg    int status, width, height, count;
2704642e01fSmrg    unsigned int *attachments;
2714642e01fSmrg
272f7df2e56Smrg    REQUEST_AT_LEAST_SIZE(xDRI2GetBuffersReq);
273f7df2e56Smrg    /* stuff->count is a count of CARD32 attachments that follows */
274f7df2e56Smrg    if (stuff->count > (INT_MAX / sizeof(CARD32)))
2750b0d8713Smrg        return BadLength;
276f7df2e56Smrg    REQUEST_FIXED_SIZE(xDRI2GetBuffersReq, stuff->count * sizeof(CARD32));
2770b0d8713Smrg
2786747b715Smrg    if (!validDrawable(client, stuff->drawable, DixReadAccess | DixWriteAccess,
279f7df2e56Smrg                       &pDrawable, &status))
280f7df2e56Smrg        return status;
2814642e01fSmrg
2826747b715Smrg    if (DRI2ThrottleClient(client, pDrawable))
283f7df2e56Smrg        return Success;
2846747b715Smrg
2854642e01fSmrg    attachments = (unsigned int *) &stuff[1];
2864642e01fSmrg    buffers = DRI2GetBuffers(pDrawable, &width, &height,
287f7df2e56Smrg                             attachments, stuff->count, &count);
2884642e01fSmrg
2896747b715Smrg    return send_buffers_reply(client, pDrawable, buffers, count, width, height);
29052397711Smrg
29152397711Smrg}
29252397711Smrg
29352397711Smrgstatic int
29452397711SmrgProcDRI2GetBuffersWithFormat(ClientPtr client)
29552397711Smrg{
29652397711Smrg    REQUEST(xDRI2GetBuffersReq);
29752397711Smrg    DrawablePtr pDrawable;
2986747b715Smrg    DRI2BufferPtr *buffers;
29952397711Smrg    int status, width, height, count;
30052397711Smrg    unsigned int *attachments;
30152397711Smrg
302f7df2e56Smrg    REQUEST_AT_LEAST_SIZE(xDRI2GetBuffersReq);
303f7df2e56Smrg    /* stuff->count is a count of pairs of CARD32s (attachments & formats)
304f7df2e56Smrg       that follows */
305f7df2e56Smrg    if (stuff->count > (INT_MAX / (2 * sizeof(CARD32))))
306f7df2e56Smrg        return BadLength;
307f7df2e56Smrg    REQUEST_FIXED_SIZE(xDRI2GetBuffersReq,
308f7df2e56Smrg                       stuff->count * (2 * sizeof(CARD32)));
3096747b715Smrg    if (!validDrawable(client, stuff->drawable, DixReadAccess | DixWriteAccess,
310f7df2e56Smrg                       &pDrawable, &status))
311f7df2e56Smrg        return status;
31252397711Smrg
3136747b715Smrg    if (DRI2ThrottleClient(client, pDrawable))
314f7df2e56Smrg        return Success;
3156747b715Smrg
31652397711Smrg    attachments = (unsigned int *) &stuff[1];
31752397711Smrg    buffers = DRI2GetBuffersWithFormat(pDrawable, &width, &height,
318f7df2e56Smrg                                       attachments, stuff->count, &count);
31952397711Smrg
3206747b715Smrg    return send_buffers_reply(client, pDrawable, buffers, count, width, height);
3214642e01fSmrg}
3224642e01fSmrg
3234642e01fSmrgstatic int
3244642e01fSmrgProcDRI2CopyRegion(ClientPtr client)
3254642e01fSmrg{
3264642e01fSmrg    REQUEST(xDRI2CopyRegionReq);
3274642e01fSmrg    xDRI2CopyRegionReply rep;
3284642e01fSmrg    DrawablePtr pDrawable;
3294642e01fSmrg    int status;
3304642e01fSmrg    RegionPtr pRegion;
3314642e01fSmrg
3324642e01fSmrg    REQUEST_SIZE_MATCH(xDRI2CopyRegionReq);
3334642e01fSmrg
3346747b715Smrg    if (!validDrawable(client, stuff->drawable, DixWriteAccess,
335f7df2e56Smrg                       &pDrawable, &status))
336f7df2e56Smrg        return status;
3374642e01fSmrg
3384642e01fSmrg    VERIFY_REGION(pRegion, stuff->region, client, DixReadAccess);
3394642e01fSmrg
3404642e01fSmrg    status = DRI2CopyRegion(pDrawable, pRegion, stuff->dest, stuff->src);
3414642e01fSmrg    if (status != Success)
342f7df2e56Smrg        return status;
3434642e01fSmrg
3444642e01fSmrg    /* CopyRegion needs to be a round trip to make sure the X server
3454642e01fSmrg     * queues the swap buffer rendering commands before the DRI client
3464642e01fSmrg     * continues rendering.  The reply has a bitmask to signal the
3475a112b11Smrg     * presence of optional return values as well, but we're not using
3484642e01fSmrg     * that yet.
3494642e01fSmrg     */
3504642e01fSmrg
351f7df2e56Smrg    rep = (xDRI2CopyRegionReply) {
352f7df2e56Smrg        .type = X_Reply,
353f7df2e56Smrg        .sequenceNumber = client->sequence,
354f7df2e56Smrg        .length = 0
355f7df2e56Smrg    };
3564642e01fSmrg
3574642e01fSmrg    WriteToClient(client, sizeof(xDRI2CopyRegionReply), &rep);
3584642e01fSmrg
3596747b715Smrg    return Success;
3606747b715Smrg}
3616747b715Smrg
3626747b715Smrgstatic void
363f7df2e56Smrgload_swap_reply(xDRI2SwapBuffersReply * rep, CARD64 sbc)
3646747b715Smrg{
3656747b715Smrg    rep->swap_hi = sbc >> 32;
3666747b715Smrg    rep->swap_lo = sbc & 0xffffffff;
3676747b715Smrg}
3686747b715Smrg
3696747b715Smrgstatic CARD64
3706747b715Smrgvals_to_card64(CARD32 lo, CARD32 hi)
3716747b715Smrg{
372f7df2e56Smrg    return (CARD64) hi << 32 | lo;
3736747b715Smrg}
3746747b715Smrg
3756747b715Smrgstatic void
3766747b715SmrgDRI2SwapEvent(ClientPtr client, void *data, int type, CARD64 ust, CARD64 msc,
377f7df2e56Smrg              CARD32 sbc)
3786747b715Smrg{
3796747b715Smrg    DrawablePtr pDrawable = data;
380f7df2e56Smrg    xDRI2BufferSwapComplete2 event = {
381f7df2e56Smrg        .type = DRI2EventBase + DRI2_BufferSwapComplete,
382f7df2e56Smrg        .event_type = type,
383f7df2e56Smrg        .drawable = pDrawable->id,
384f7df2e56Smrg        .ust_hi = (CARD64) ust >> 32,
385f7df2e56Smrg        .ust_lo = ust & 0xffffffff,
386f7df2e56Smrg        .msc_hi = (CARD64) msc >> 32,
387f7df2e56Smrg        .msc_lo = msc & 0xffffffff,
388f7df2e56Smrg        .sbc = sbc
389f7df2e56Smrg    };
390f7df2e56Smrg
391f7df2e56Smrg    WriteEventsToClient(client, 1, (xEvent *) &event);
3926747b715Smrg}
3936747b715Smrg
3946747b715Smrgstatic int
3956747b715SmrgProcDRI2SwapBuffers(ClientPtr client)
3966747b715Smrg{
3976747b715Smrg    REQUEST(xDRI2SwapBuffersReq);
398f7df2e56Smrg    xDRI2SwapBuffersReply rep = {
399f7df2e56Smrg        .type = X_Reply,
400f7df2e56Smrg        .sequenceNumber = client->sequence,
401f7df2e56Smrg        .length = 0
402f7df2e56Smrg    };
4036747b715Smrg    DrawablePtr pDrawable;
4046747b715Smrg    CARD64 target_msc, divisor, remainder, swap_target;
4056747b715Smrg    int status;
4066747b715Smrg
4076747b715Smrg    REQUEST_SIZE_MATCH(xDRI2SwapBuffersReq);
4086747b715Smrg
4096747b715Smrg    if (!validDrawable(client, stuff->drawable,
410f7df2e56Smrg                       DixReadAccess | DixWriteAccess, &pDrawable, &status))
411f7df2e56Smrg        return status;
4126747b715Smrg
4136747b715Smrg    /*
4146747b715Smrg     * Ensures an out of control client can't exhaust our swap queue, and
4156747b715Smrg     * also orders swaps.
4166747b715Smrg     */
4176747b715Smrg    if (DRI2ThrottleClient(client, pDrawable))
418f7df2e56Smrg        return Success;
4196747b715Smrg
4206747b715Smrg    target_msc = vals_to_card64(stuff->target_msc_lo, stuff->target_msc_hi);
4216747b715Smrg    divisor = vals_to_card64(stuff->divisor_lo, stuff->divisor_hi);
4226747b715Smrg    remainder = vals_to_card64(stuff->remainder_lo, stuff->remainder_hi);
4236747b715Smrg
4246747b715Smrg    status = DRI2SwapBuffers(client, pDrawable, target_msc, divisor, remainder,
425f7df2e56Smrg                             &swap_target, DRI2SwapEvent, pDrawable);
4266747b715Smrg    if (status != Success)
427f7df2e56Smrg        return BadDrawable;
4286747b715Smrg
4296747b715Smrg    load_swap_reply(&rep, swap_target);
4306747b715Smrg
4316747b715Smrg    WriteToClient(client, sizeof(xDRI2SwapBuffersReply), &rep);
4326747b715Smrg
4336747b715Smrg    return Success;
4346747b715Smrg}
4356747b715Smrg
4366747b715Smrgstatic void
437f7df2e56Smrgload_msc_reply(xDRI2MSCReply * rep, CARD64 ust, CARD64 msc, CARD64 sbc)
4386747b715Smrg{
4396747b715Smrg    rep->ust_hi = ust >> 32;
4406747b715Smrg    rep->ust_lo = ust & 0xffffffff;
4416747b715Smrg    rep->msc_hi = msc >> 32;
4426747b715Smrg    rep->msc_lo = msc & 0xffffffff;
4436747b715Smrg    rep->sbc_hi = sbc >> 32;
4446747b715Smrg    rep->sbc_lo = sbc & 0xffffffff;
4456747b715Smrg}
4466747b715Smrg
4476747b715Smrgstatic int
4486747b715SmrgProcDRI2GetMSC(ClientPtr client)
4496747b715Smrg{
4506747b715Smrg    REQUEST(xDRI2GetMSCReq);
451f7df2e56Smrg    xDRI2MSCReply rep = {
452f7df2e56Smrg        .type = X_Reply,
453f7df2e56Smrg        .sequenceNumber = client->sequence,
454f7df2e56Smrg        .length = 0
455f7df2e56Smrg    };
4566747b715Smrg    DrawablePtr pDrawable;
4576747b715Smrg    CARD64 ust, msc, sbc;
4586747b715Smrg    int status;
4596747b715Smrg
4606747b715Smrg    REQUEST_SIZE_MATCH(xDRI2GetMSCReq);
4616747b715Smrg
4626747b715Smrg    if (!validDrawable(client, stuff->drawable, DixReadAccess, &pDrawable,
463f7df2e56Smrg                       &status))
464f7df2e56Smrg        return status;
4656747b715Smrg
4666747b715Smrg    status = DRI2GetMSC(pDrawable, &ust, &msc, &sbc);
4676747b715Smrg    if (status != Success)
468f7df2e56Smrg        return status;
4696747b715Smrg
4706747b715Smrg    load_msc_reply(&rep, ust, msc, sbc);
4716747b715Smrg
4726747b715Smrg    WriteToClient(client, sizeof(xDRI2MSCReply), &rep);
4736747b715Smrg
4746747b715Smrg    return Success;
4756747b715Smrg}
4766747b715Smrg
4776747b715Smrgstatic int
4786747b715SmrgProcDRI2WaitMSC(ClientPtr client)
4796747b715Smrg{
4806747b715Smrg    REQUEST(xDRI2WaitMSCReq);
4816747b715Smrg    DrawablePtr pDrawable;
4826747b715Smrg    CARD64 target, divisor, remainder;
4836747b715Smrg    int status;
4846747b715Smrg
4856747b715Smrg    /* FIXME: in restart case, client may be gone at this point */
4866747b715Smrg
4876747b715Smrg    REQUEST_SIZE_MATCH(xDRI2WaitMSCReq);
4886747b715Smrg
4896747b715Smrg    if (!validDrawable(client, stuff->drawable, DixReadAccess, &pDrawable,
490f7df2e56Smrg                       &status))
491f7df2e56Smrg        return status;
4926747b715Smrg
4936747b715Smrg    target = vals_to_card64(stuff->target_msc_lo, stuff->target_msc_hi);
4946747b715Smrg    divisor = vals_to_card64(stuff->divisor_lo, stuff->divisor_hi);
4956747b715Smrg    remainder = vals_to_card64(stuff->remainder_lo, stuff->remainder_hi);
4966747b715Smrg
4976747b715Smrg    status = DRI2WaitMSC(client, pDrawable, target, divisor, remainder);
4986747b715Smrg    if (status != Success)
499f7df2e56Smrg        return status;
5006747b715Smrg
5016747b715Smrg    return Success;
5026747b715Smrg}
5036747b715Smrg
5046747b715Smrgint
5056747b715SmrgProcDRI2WaitMSCReply(ClientPtr client, CARD64 ust, CARD64 msc, CARD64 sbc)
5066747b715Smrg{
507f7df2e56Smrg    xDRI2MSCReply rep = {
508f7df2e56Smrg        .type = X_Reply,
509f7df2e56Smrg        .sequenceNumber = client->sequence,
510f7df2e56Smrg        .length = 0
511f7df2e56Smrg    };
5126747b715Smrg
5136747b715Smrg    load_msc_reply(&rep, ust, msc, sbc);
5146747b715Smrg
5156747b715Smrg    WriteToClient(client, sizeof(xDRI2MSCReply), &rep);
5166747b715Smrg
5176747b715Smrg    return Success;
5186747b715Smrg}
5196747b715Smrg
5206747b715Smrgstatic int
5216747b715SmrgProcDRI2SwapInterval(ClientPtr client)
5226747b715Smrg{
5236747b715Smrg    REQUEST(xDRI2SwapIntervalReq);
5246747b715Smrg    DrawablePtr pDrawable;
5256747b715Smrg    int status;
5266747b715Smrg
5276747b715Smrg    /* FIXME: in restart case, client may be gone at this point */
5286747b715Smrg
5296747b715Smrg    REQUEST_SIZE_MATCH(xDRI2SwapIntervalReq);
5306747b715Smrg
5316747b715Smrg    if (!validDrawable(client, stuff->drawable, DixReadAccess | DixWriteAccess,
532f7df2e56Smrg                       &pDrawable, &status))
533f7df2e56Smrg        return status;
5346747b715Smrg
5356747b715Smrg    DRI2SwapInterval(pDrawable, stuff->interval);
5366747b715Smrg
5376747b715Smrg    return Success;
5386747b715Smrg}
5396747b715Smrg
5406747b715Smrgstatic int
5416747b715SmrgProcDRI2WaitSBC(ClientPtr client)
5426747b715Smrg{
5436747b715Smrg    REQUEST(xDRI2WaitSBCReq);
5446747b715Smrg    DrawablePtr pDrawable;
5456747b715Smrg    CARD64 target;
5466747b715Smrg    int status;
5476747b715Smrg
5486747b715Smrg    REQUEST_SIZE_MATCH(xDRI2WaitSBCReq);
5496747b715Smrg
5506747b715Smrg    if (!validDrawable(client, stuff->drawable, DixReadAccess, &pDrawable,
551f7df2e56Smrg                       &status))
552f7df2e56Smrg        return status;
5536747b715Smrg
5546747b715Smrg    target = vals_to_card64(stuff->target_sbc_lo, stuff->target_sbc_hi);
5556747b715Smrg    status = DRI2WaitSBC(client, pDrawable, target);
5566747b715Smrg
5576747b715Smrg    return status;
5584642e01fSmrg}
5594642e01fSmrg
5604642e01fSmrgstatic int
561f7df2e56SmrgProcDRI2GetParam(ClientPtr client)
562f7df2e56Smrg{
563f7df2e56Smrg    REQUEST(xDRI2GetParamReq);
564f7df2e56Smrg    xDRI2GetParamReply rep = {
565f7df2e56Smrg        .type = X_Reply,
566f7df2e56Smrg        .sequenceNumber = client->sequence,
567f7df2e56Smrg        .length = 0
568f7df2e56Smrg    };
569f7df2e56Smrg    DrawablePtr pDrawable;
570f7df2e56Smrg    CARD64 value;
571f7df2e56Smrg    int status;
572f7df2e56Smrg
573f7df2e56Smrg    REQUEST_SIZE_MATCH(xDRI2GetParamReq);
574f7df2e56Smrg
575f7df2e56Smrg    if (!validDrawable(client, stuff->drawable, DixReadAccess,
576f7df2e56Smrg                       &pDrawable, &status))
577f7df2e56Smrg        return status;
578f7df2e56Smrg
579f7df2e56Smrg    status = DRI2GetParam(client, pDrawable, stuff->param,
580f7df2e56Smrg                          &rep.is_param_recognized, &value);
581f7df2e56Smrg    rep.value_hi = value >> 32;
582f7df2e56Smrg    rep.value_lo = value & 0xffffffff;
583f7df2e56Smrg
584f7df2e56Smrg    if (status != Success)
585f7df2e56Smrg        return status;
586f7df2e56Smrg
587f7df2e56Smrg    WriteToClient(client, sizeof(xDRI2GetParamReply), &rep);
588f7df2e56Smrg
589f7df2e56Smrg    return status;
590f7df2e56Smrg}
591f7df2e56Smrg
592f7df2e56Smrgstatic int
593f7df2e56SmrgProcDRI2Dispatch(ClientPtr client)
5944642e01fSmrg{
5954642e01fSmrg    REQUEST(xReq);
596f7df2e56Smrg
5974642e01fSmrg    switch (stuff->data) {
5984642e01fSmrg    case X_DRI2QueryVersion:
599f7df2e56Smrg        return ProcDRI2QueryVersion(client);
6004642e01fSmrg    }
6014642e01fSmrg
602f7df2e56Smrg    if (!client->local)
603f7df2e56Smrg        return BadRequest;
6044642e01fSmrg
6054642e01fSmrg    switch (stuff->data) {
6064642e01fSmrg    case X_DRI2Connect:
607f7df2e56Smrg        return ProcDRI2Connect(client);
6084642e01fSmrg    case X_DRI2Authenticate:
609f7df2e56Smrg        return ProcDRI2Authenticate(client);
6104642e01fSmrg    case X_DRI2CreateDrawable:
611f7df2e56Smrg        return ProcDRI2CreateDrawable(client);
6124642e01fSmrg    case X_DRI2DestroyDrawable:
613f7df2e56Smrg        return ProcDRI2DestroyDrawable(client);
6144642e01fSmrg    case X_DRI2GetBuffers:
615f7df2e56Smrg        return ProcDRI2GetBuffers(client);
6164642e01fSmrg    case X_DRI2CopyRegion:
617f7df2e56Smrg        return ProcDRI2CopyRegion(client);
61852397711Smrg    case X_DRI2GetBuffersWithFormat:
619f7df2e56Smrg        return ProcDRI2GetBuffersWithFormat(client);
6206747b715Smrg    case X_DRI2SwapBuffers:
621f7df2e56Smrg        return ProcDRI2SwapBuffers(client);
6226747b715Smrg    case X_DRI2GetMSC:
623f7df2e56Smrg        return ProcDRI2GetMSC(client);
6246747b715Smrg    case X_DRI2WaitMSC:
625f7df2e56Smrg        return ProcDRI2WaitMSC(client);
6266747b715Smrg    case X_DRI2WaitSBC:
627f7df2e56Smrg        return ProcDRI2WaitSBC(client);
6286747b715Smrg    case X_DRI2SwapInterval:
629f7df2e56Smrg        return ProcDRI2SwapInterval(client);
630f7df2e56Smrg    case X_DRI2GetParam:
631f7df2e56Smrg        return ProcDRI2GetParam(client);
6324642e01fSmrg    default:
633f7df2e56Smrg        return BadRequest;
6344642e01fSmrg    }
6354642e01fSmrg}
6364642e01fSmrg
6377e31ba66Smrgstatic int _X_COLD
6384642e01fSmrgSProcDRI2Connect(ClientPtr client)
6394642e01fSmrg{
6404642e01fSmrg    REQUEST(xDRI2ConnectReq);
641f7df2e56Smrg    xDRI2ConnectReply rep = {
642f7df2e56Smrg        .type = X_Reply,
643f7df2e56Smrg        .sequenceNumber = client->sequence,
644f7df2e56Smrg        .length = 0,
645f7df2e56Smrg        .driverNameLength = 0,
646f7df2e56Smrg        .deviceNameLength = 0
647f7df2e56Smrg    };
6484642e01fSmrg
6494642e01fSmrg    /* If the client is swapped, it's not local.  Talk to the hand. */
6504642e01fSmrg
651f7df2e56Smrg    swaps(&stuff->length);
6524642e01fSmrg    if (sizeof(*stuff) / 4 != client->req_len)
653f7df2e56Smrg        return BadLength;
6544642e01fSmrg
655f7df2e56Smrg    swaps(&rep.sequenceNumber);
656f7df2e56Smrg
657f7df2e56Smrg    WriteToClient(client, sizeof(xDRI2ConnectReply), &rep);
6584642e01fSmrg
6596747b715Smrg    return Success;
6604642e01fSmrg}
6614642e01fSmrg
6627e31ba66Smrgstatic int _X_COLD
663f7df2e56SmrgSProcDRI2Dispatch(ClientPtr client)
6644642e01fSmrg{
6654642e01fSmrg    REQUEST(xReq);
6664642e01fSmrg
6674642e01fSmrg    /*
6684642e01fSmrg     * Only local clients are allowed DRI access, but remote clients
6694642e01fSmrg     * still need these requests to find out cleanly.
6704642e01fSmrg     */
671f7df2e56Smrg    switch (stuff->data) {
6724642e01fSmrg    case X_DRI2QueryVersion:
673f7df2e56Smrg        return ProcDRI2QueryVersion(client);
6744642e01fSmrg    case X_DRI2Connect:
675f7df2e56Smrg        return SProcDRI2Connect(client);
6764642e01fSmrg    default:
677f7df2e56Smrg        return BadRequest;
6784642e01fSmrg    }
6794642e01fSmrg}
6804642e01fSmrg
681f7df2e56Smrgvoid
6824642e01fSmrgDRI2ExtensionInit(void)
6834642e01fSmrg{
684f7df2e56Smrg    ExtensionEntry *dri2Extension;
685f7df2e56Smrg
686f7df2e56Smrg#ifdef PANORAMIX
687f7df2e56Smrg    if (!noPanoramiXExtension)
688f7df2e56Smrg        return;
689f7df2e56Smrg#endif
690f7df2e56Smrg
6914642e01fSmrg    dri2Extension = AddExtension(DRI2_NAME,
692f7df2e56Smrg                                 DRI2NumberEvents,
693f7df2e56Smrg                                 DRI2NumberErrors,
694f7df2e56Smrg                                 ProcDRI2Dispatch,
695f7df2e56Smrg                                 SProcDRI2Dispatch, NULL, StandardMinorOpcode);
6964642e01fSmrg
6976747b715Smrg    DRI2EventBase = dri2Extension->eventBase;
698475c125cSmrg
699475c125cSmrg    DRI2ModuleSetup();
7004642e01fSmrg}
701