1706f2543Smrg/*
2706f2543Smrg * Copyright © 2008 Red Hat, Inc.
3706f2543Smrg *
4706f2543Smrg * Permission is hereby granted, free of charge, to any person obtaining a
5706f2543Smrg * copy of this software and associated documentation files (the "Soft-
6706f2543Smrg * ware"), to deal in the Software without restriction, including without
7706f2543Smrg * limitation the rights to use, copy, modify, merge, publish, distribute,
8706f2543Smrg * and/or sell copies of the Software, and to permit persons to whom the
9706f2543Smrg * Software is furnished to do so, provided that the above copyright
10706f2543Smrg * notice(s) and this permission notice appear in all copies of the Soft-
11706f2543Smrg * ware and that both the above copyright notice(s) and this permission
12706f2543Smrg * notice appear in supporting documentation.
13706f2543Smrg *
14706f2543Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15706f2543Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
16706f2543Smrg * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
17706f2543Smrg * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
18706f2543Smrg * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
19706f2543Smrg * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20706f2543Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21706f2543Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
22706f2543Smrg * MANCE OF THIS SOFTWARE.
23706f2543Smrg *
24706f2543Smrg * Except as contained in this notice, the name of a copyright holder shall
25706f2543Smrg * not be used in advertising or otherwise to promote the sale, use or
26706f2543Smrg * other dealings in this Software without prior written authorization of
27706f2543Smrg * the copyright holder.
28706f2543Smrg *
29706f2543Smrg * Authors:
30706f2543Smrg *   Kristian Høgsberg (krh@redhat.com)
31706f2543Smrg */
32706f2543Smrg
33706f2543Smrg#ifdef HAVE_XORG_CONFIG_H
34706f2543Smrg#include <xorg-config.h>
35706f2543Smrg#endif
36706f2543Smrg
37706f2543Smrg#include <X11/X.h>
38706f2543Smrg#include <X11/Xproto.h>
39706f2543Smrg#include <X11/extensions/dri2proto.h>
40706f2543Smrg#include <X11/extensions/xfixeswire.h>
41706f2543Smrg#include "dixstruct.h"
42706f2543Smrg#include "scrnintstr.h"
43706f2543Smrg#include "pixmapstr.h"
44706f2543Smrg#include "extnsionst.h"
45706f2543Smrg#include "xfixes.h"
46706f2543Smrg#include "dri2.h"
47706f2543Smrg#include "protocol-versions.h"
48706f2543Smrg
49706f2543Smrg/* The only xf86 include */
50706f2543Smrg#include "xf86Module.h"
51706f2543Smrg
52706f2543Smrgstatic ExtensionEntry	*dri2Extension;
53706f2543Smrgextern Bool DRI2ModuleSetup(void);
54706f2543Smrg
55706f2543Smrgstatic Bool
56706f2543SmrgvalidDrawable(ClientPtr client, XID drawable, Mask access_mode,
57706f2543Smrg	      DrawablePtr *pDrawable, int *status)
58706f2543Smrg{
59706f2543Smrg    *status = dixLookupDrawable(pDrawable, drawable, client,
60706f2543Smrg				M_DRAWABLE_WINDOW | M_DRAWABLE_PIXMAP,
61706f2543Smrg				access_mode);
62706f2543Smrg    if (*status != Success) {
63706f2543Smrg	client->errorValue = drawable;
64706f2543Smrg	return FALSE;
65706f2543Smrg    }
66706f2543Smrg
67706f2543Smrg    return TRUE;
68706f2543Smrg}
69706f2543Smrg
70706f2543Smrgstatic int
71706f2543SmrgProcDRI2QueryVersion(ClientPtr client)
72706f2543Smrg{
73706f2543Smrg    REQUEST(xDRI2QueryVersionReq);
74706f2543Smrg    xDRI2QueryVersionReply rep;
75706f2543Smrg    int n;
76706f2543Smrg
77706f2543Smrg    if (client->swapped)
78706f2543Smrg	swaps(&stuff->length, n);
79706f2543Smrg
80706f2543Smrg    REQUEST_SIZE_MATCH(xDRI2QueryVersionReq);
81706f2543Smrg    rep.type = X_Reply;
82706f2543Smrg    rep.length = 0;
83706f2543Smrg    rep.sequenceNumber = client->sequence;
84706f2543Smrg    rep.majorVersion = dri2_major;
85706f2543Smrg    rep.minorVersion = dri2_minor;
86706f2543Smrg
87706f2543Smrg    if (client->swapped) {
88706f2543Smrg    	swaps(&rep.sequenceNumber, n);
89706f2543Smrg    	swapl(&rep.length, n);
90706f2543Smrg	swapl(&rep.majorVersion, n);
91706f2543Smrg	swapl(&rep.minorVersion, n);
92706f2543Smrg    }
93706f2543Smrg
94706f2543Smrg    WriteToClient(client, sizeof(xDRI2QueryVersionReply), &rep);
95706f2543Smrg
96706f2543Smrg    return Success;
97706f2543Smrg}
98706f2543Smrg
99706f2543Smrgstatic int
100706f2543SmrgProcDRI2Connect(ClientPtr client)
101706f2543Smrg{
102706f2543Smrg    REQUEST(xDRI2ConnectReq);
103706f2543Smrg    xDRI2ConnectReply rep;
104706f2543Smrg    DrawablePtr pDraw;
105706f2543Smrg    int fd, status;
106706f2543Smrg    const char *driverName;
107706f2543Smrg    const char *deviceName;
108706f2543Smrg
109706f2543Smrg    REQUEST_SIZE_MATCH(xDRI2ConnectReq);
110706f2543Smrg    if (!validDrawable(client, stuff->window, DixGetAttrAccess,
111706f2543Smrg		       &pDraw, &status))
112706f2543Smrg	return status;
113706f2543Smrg
114706f2543Smrg    rep.type = X_Reply;
115706f2543Smrg    rep.length = 0;
116706f2543Smrg    rep.sequenceNumber = client->sequence;
117706f2543Smrg    rep.driverNameLength = 0;
118706f2543Smrg    rep.deviceNameLength = 0;
119706f2543Smrg
120706f2543Smrg    if (!DRI2Connect(pDraw->pScreen,
121706f2543Smrg		     stuff->driverType, &fd, &driverName, &deviceName))
122706f2543Smrg	goto fail;
123706f2543Smrg
124706f2543Smrg    rep.driverNameLength = strlen(driverName);
125706f2543Smrg    rep.deviceNameLength = strlen(deviceName);
126706f2543Smrg    rep.length = (rep.driverNameLength + 3) / 4 +
127706f2543Smrg	    (rep.deviceNameLength + 3) / 4;
128706f2543Smrg
129706f2543Smrg fail:
130706f2543Smrg    WriteToClient(client, sizeof(xDRI2ConnectReply), &rep);
131706f2543Smrg    WriteToClient(client, rep.driverNameLength, driverName);
132706f2543Smrg    WriteToClient(client, rep.deviceNameLength, deviceName);
133706f2543Smrg
134706f2543Smrg    return Success;
135706f2543Smrg}
136706f2543Smrg
137706f2543Smrgstatic int
138706f2543SmrgProcDRI2Authenticate(ClientPtr client)
139706f2543Smrg{
140706f2543Smrg    REQUEST(xDRI2AuthenticateReq);
141706f2543Smrg    xDRI2AuthenticateReply rep;
142706f2543Smrg    DrawablePtr pDraw;
143706f2543Smrg    int status;
144706f2543Smrg
145706f2543Smrg    REQUEST_SIZE_MATCH(xDRI2AuthenticateReq);
146706f2543Smrg    if (!validDrawable(client, stuff->window, DixGetAttrAccess,
147706f2543Smrg		       &pDraw, &status))
148706f2543Smrg	return status;
149706f2543Smrg
150706f2543Smrg    rep.type = X_Reply;
151706f2543Smrg    rep.sequenceNumber = client->sequence;
152706f2543Smrg    rep.length = 0;
153706f2543Smrg    rep.authenticated = DRI2Authenticate(pDraw->pScreen, stuff->magic);
154706f2543Smrg    WriteToClient(client, sizeof(xDRI2AuthenticateReply), &rep);
155706f2543Smrg
156706f2543Smrg    return Success;
157706f2543Smrg}
158706f2543Smrg
159706f2543Smrgstatic void
160706f2543SmrgDRI2InvalidateBuffersEvent(DrawablePtr pDraw, void *priv)
161706f2543Smrg{
162706f2543Smrg    xDRI2InvalidateBuffers event;
163706f2543Smrg    ClientPtr client = priv;
164706f2543Smrg
165706f2543Smrg    event.type = DRI2EventBase + DRI2_InvalidateBuffers;
166706f2543Smrg    event.drawable = pDraw->id;
167706f2543Smrg
168706f2543Smrg    WriteEventsToClient(client, 1, (xEvent *)&event);
169706f2543Smrg}
170706f2543Smrg
171706f2543Smrgstatic int
172706f2543SmrgProcDRI2CreateDrawable(ClientPtr client)
173706f2543Smrg{
174706f2543Smrg    REQUEST(xDRI2CreateDrawableReq);
175706f2543Smrg    DrawablePtr pDrawable;
176706f2543Smrg    int status;
177706f2543Smrg
178706f2543Smrg    REQUEST_SIZE_MATCH(xDRI2CreateDrawableReq);
179706f2543Smrg
180706f2543Smrg    if (!validDrawable(client, stuff->drawable, DixAddAccess,
181706f2543Smrg		       &pDrawable, &status))
182706f2543Smrg	return status;
183706f2543Smrg
184706f2543Smrg    status = DRI2CreateDrawable(client, pDrawable, stuff->drawable,
185706f2543Smrg				DRI2InvalidateBuffersEvent, client);
186706f2543Smrg    if (status != Success)
187706f2543Smrg	return status;
188706f2543Smrg
189706f2543Smrg    return Success;
190706f2543Smrg}
191706f2543Smrg
192706f2543Smrgstatic int
193706f2543SmrgProcDRI2DestroyDrawable(ClientPtr client)
194706f2543Smrg{
195706f2543Smrg    REQUEST(xDRI2DestroyDrawableReq);
196706f2543Smrg    DrawablePtr pDrawable;
197706f2543Smrg    int status;
198706f2543Smrg
199706f2543Smrg    REQUEST_SIZE_MATCH(xDRI2DestroyDrawableReq);
200706f2543Smrg    if (!validDrawable(client, stuff->drawable, DixRemoveAccess,
201706f2543Smrg		       &pDrawable, &status))
202706f2543Smrg	return status;
203706f2543Smrg
204706f2543Smrg    return Success;
205706f2543Smrg}
206706f2543Smrg
207706f2543Smrg
208706f2543Smrgstatic int
209706f2543Smrgsend_buffers_reply(ClientPtr client, DrawablePtr pDrawable,
210706f2543Smrg		   DRI2BufferPtr *buffers, int count, int width, int height)
211706f2543Smrg{
212706f2543Smrg    xDRI2GetBuffersReply rep;
213706f2543Smrg    int skip = 0;
214706f2543Smrg    int i;
215706f2543Smrg
216706f2543Smrg    if (buffers == NULL)
217706f2543Smrg	    return BadAlloc;
218706f2543Smrg
219706f2543Smrg    if (pDrawable->type == DRAWABLE_WINDOW) {
220706f2543Smrg	for (i = 0; i < count; i++) {
221706f2543Smrg	    /* Do not send the real front buffer of a window to the client.
222706f2543Smrg	     */
223706f2543Smrg	    if (buffers[i]->attachment == DRI2BufferFrontLeft) {
224706f2543Smrg		skip++;
225706f2543Smrg		continue;
226706f2543Smrg	    }
227706f2543Smrg	}
228706f2543Smrg    }
229706f2543Smrg
230706f2543Smrg    rep.type = X_Reply;
231706f2543Smrg    rep.length = (count - skip) * sizeof(xDRI2Buffer) / 4;
232706f2543Smrg    rep.sequenceNumber = client->sequence;
233706f2543Smrg    rep.width = width;
234706f2543Smrg    rep.height = height;
235706f2543Smrg    rep.count = count - skip;
236706f2543Smrg    WriteToClient(client, sizeof(xDRI2GetBuffersReply), &rep);
237706f2543Smrg
238706f2543Smrg    for (i = 0; i < count; i++) {
239706f2543Smrg	xDRI2Buffer buffer;
240706f2543Smrg
241706f2543Smrg	/* Do not send the real front buffer of a window to the client.
242706f2543Smrg	 */
243706f2543Smrg	if ((pDrawable->type == DRAWABLE_WINDOW)
244706f2543Smrg	    && (buffers[i]->attachment == DRI2BufferFrontLeft)) {
245706f2543Smrg	    continue;
246706f2543Smrg	}
247706f2543Smrg
248706f2543Smrg	buffer.attachment = buffers[i]->attachment;
249706f2543Smrg	buffer.name = buffers[i]->name;
250706f2543Smrg	buffer.pitch = buffers[i]->pitch;
251706f2543Smrg	buffer.cpp = buffers[i]->cpp;
252706f2543Smrg	buffer.flags = buffers[i]->flags;
253706f2543Smrg	WriteToClient(client, sizeof(xDRI2Buffer), &buffer);
254706f2543Smrg    }
255706f2543Smrg    return Success;
256706f2543Smrg}
257706f2543Smrg
258706f2543Smrg
259706f2543Smrgstatic int
260706f2543SmrgProcDRI2GetBuffers(ClientPtr client)
261706f2543Smrg{
262706f2543Smrg    REQUEST(xDRI2GetBuffersReq);
263706f2543Smrg    DrawablePtr pDrawable;
264706f2543Smrg    DRI2BufferPtr *buffers;
265706f2543Smrg    int status, width, height, count;
266706f2543Smrg    unsigned int *attachments;
267706f2543Smrg
268706f2543Smrg    REQUEST_FIXED_SIZE(xDRI2GetBuffersReq, stuff->count * 4);
269706f2543Smrg    if (stuff->count > (INT_MAX / 4))
270706f2543Smrg        return BadLength;
271706f2543Smrg
272706f2543Smrg    if (!validDrawable(client, stuff->drawable, DixReadAccess | DixWriteAccess,
273706f2543Smrg		       &pDrawable, &status))
274706f2543Smrg	return status;
275706f2543Smrg
276706f2543Smrg    if (DRI2ThrottleClient(client, pDrawable))
277706f2543Smrg	return Success;
278706f2543Smrg
279706f2543Smrg    attachments = (unsigned int *) &stuff[1];
280706f2543Smrg    buffers = DRI2GetBuffers(pDrawable, &width, &height,
281706f2543Smrg			     attachments, stuff->count, &count);
282706f2543Smrg
283706f2543Smrg
284706f2543Smrg    return send_buffers_reply(client, pDrawable, buffers, count, width, height);
285706f2543Smrg
286706f2543Smrg}
287706f2543Smrg
288706f2543Smrgstatic int
289706f2543SmrgProcDRI2GetBuffersWithFormat(ClientPtr client)
290706f2543Smrg{
291706f2543Smrg    REQUEST(xDRI2GetBuffersReq);
292706f2543Smrg    DrawablePtr pDrawable;
293706f2543Smrg    DRI2BufferPtr *buffers;
294706f2543Smrg    int status, width, height, count;
295706f2543Smrg    unsigned int *attachments;
296706f2543Smrg
297706f2543Smrg    REQUEST_FIXED_SIZE(xDRI2GetBuffersReq, stuff->count * (2 * 4));
298706f2543Smrg    if (!validDrawable(client, stuff->drawable, DixReadAccess | DixWriteAccess,
299706f2543Smrg		       &pDrawable, &status))
300706f2543Smrg	return status;
301706f2543Smrg
302706f2543Smrg    if (DRI2ThrottleClient(client, pDrawable))
303706f2543Smrg	return Success;
304706f2543Smrg
305706f2543Smrg    attachments = (unsigned int *) &stuff[1];
306706f2543Smrg    buffers = DRI2GetBuffersWithFormat(pDrawable, &width, &height,
307706f2543Smrg				       attachments, stuff->count, &count);
308706f2543Smrg
309706f2543Smrg    return send_buffers_reply(client, pDrawable, buffers, count, width, height);
310706f2543Smrg}
311706f2543Smrg
312706f2543Smrgstatic int
313706f2543SmrgProcDRI2CopyRegion(ClientPtr client)
314706f2543Smrg{
315706f2543Smrg    REQUEST(xDRI2CopyRegionReq);
316706f2543Smrg    xDRI2CopyRegionReply rep;
317706f2543Smrg    DrawablePtr pDrawable;
318706f2543Smrg    int status;
319706f2543Smrg    RegionPtr pRegion;
320706f2543Smrg
321706f2543Smrg    REQUEST_SIZE_MATCH(xDRI2CopyRegionReq);
322706f2543Smrg
323706f2543Smrg    if (!validDrawable(client, stuff->drawable, DixWriteAccess,
324706f2543Smrg		       &pDrawable, &status))
325706f2543Smrg	return status;
326706f2543Smrg
327706f2543Smrg    VERIFY_REGION(pRegion, stuff->region, client, DixReadAccess);
328706f2543Smrg
329706f2543Smrg    status = DRI2CopyRegion(pDrawable, pRegion, stuff->dest, stuff->src);
330706f2543Smrg    if (status != Success)
331706f2543Smrg	return status;
332706f2543Smrg
333706f2543Smrg    /* CopyRegion needs to be a round trip to make sure the X server
334706f2543Smrg     * queues the swap buffer rendering commands before the DRI client
335706f2543Smrg     * continues rendering.  The reply has a bitmask to signal the
336706f2543Smrg     * presense of optional return values as well, but we're not using
337706f2543Smrg     * that yet.
338706f2543Smrg     */
339706f2543Smrg
340706f2543Smrg    rep.type = X_Reply;
341706f2543Smrg    rep.length = 0;
342706f2543Smrg    rep.sequenceNumber = client->sequence;
343706f2543Smrg
344706f2543Smrg    WriteToClient(client, sizeof(xDRI2CopyRegionReply), &rep);
345706f2543Smrg
346706f2543Smrg    return Success;
347706f2543Smrg}
348706f2543Smrg
349706f2543Smrgstatic void
350706f2543Smrgload_swap_reply(xDRI2SwapBuffersReply *rep, CARD64 sbc)
351706f2543Smrg{
352706f2543Smrg    rep->swap_hi = sbc >> 32;
353706f2543Smrg    rep->swap_lo = sbc & 0xffffffff;
354706f2543Smrg}
355706f2543Smrg
356706f2543Smrgstatic CARD64
357706f2543Smrgvals_to_card64(CARD32 lo, CARD32 hi)
358706f2543Smrg{
359706f2543Smrg    return (CARD64)hi << 32 | lo;
360706f2543Smrg}
361706f2543Smrg
362706f2543Smrgstatic void
363706f2543SmrgDRI2SwapEvent(ClientPtr client, void *data, int type, CARD64 ust, CARD64 msc,
364706f2543Smrg	      CARD64 sbc)
365706f2543Smrg{
366706f2543Smrg    xDRI2BufferSwapComplete event;
367706f2543Smrg    DrawablePtr pDrawable = data;
368706f2543Smrg
369706f2543Smrg    event.type = DRI2EventBase + DRI2_BufferSwapComplete;
370706f2543Smrg    event.event_type = type;
371706f2543Smrg    event.drawable = pDrawable->id;
372706f2543Smrg    event.ust_hi = (CARD64)ust >> 32;
373706f2543Smrg    event.ust_lo = ust & 0xffffffff;
374706f2543Smrg    event.msc_hi = (CARD64)msc >> 32;
375706f2543Smrg    event.msc_lo = msc & 0xffffffff;
376706f2543Smrg    event.sbc_hi = (CARD64)sbc >> 32;
377706f2543Smrg    event.sbc_lo = sbc & 0xffffffff;
378706f2543Smrg
379706f2543Smrg    WriteEventsToClient(client, 1, (xEvent *)&event);
380706f2543Smrg}
381706f2543Smrg
382706f2543Smrgstatic int
383706f2543SmrgProcDRI2SwapBuffers(ClientPtr client)
384706f2543Smrg{
385706f2543Smrg    REQUEST(xDRI2SwapBuffersReq);
386706f2543Smrg    xDRI2SwapBuffersReply rep;
387706f2543Smrg    DrawablePtr pDrawable;
388706f2543Smrg    CARD64 target_msc, divisor, remainder, swap_target;
389706f2543Smrg    int status;
390706f2543Smrg
391706f2543Smrg    REQUEST_SIZE_MATCH(xDRI2SwapBuffersReq);
392706f2543Smrg
393706f2543Smrg    if (!validDrawable(client, stuff->drawable,
394706f2543Smrg		       DixReadAccess | DixWriteAccess, &pDrawable, &status))
395706f2543Smrg	return status;
396706f2543Smrg
397706f2543Smrg    /*
398706f2543Smrg     * Ensures an out of control client can't exhaust our swap queue, and
399706f2543Smrg     * also orders swaps.
400706f2543Smrg     */
401706f2543Smrg    if (DRI2ThrottleClient(client, pDrawable))
402706f2543Smrg	return Success;
403706f2543Smrg
404706f2543Smrg    target_msc = vals_to_card64(stuff->target_msc_lo, stuff->target_msc_hi);
405706f2543Smrg    divisor = vals_to_card64(stuff->divisor_lo, stuff->divisor_hi);
406706f2543Smrg    remainder = vals_to_card64(stuff->remainder_lo, stuff->remainder_hi);
407706f2543Smrg
408706f2543Smrg    status = DRI2SwapBuffers(client, pDrawable, target_msc, divisor, remainder,
409706f2543Smrg			     &swap_target, DRI2SwapEvent, pDrawable);
410706f2543Smrg    if (status != Success)
411706f2543Smrg	return BadDrawable;
412706f2543Smrg
413706f2543Smrg    rep.type = X_Reply;
414706f2543Smrg    rep.length = 0;
415706f2543Smrg    rep.sequenceNumber = client->sequence;
416706f2543Smrg    load_swap_reply(&rep, swap_target);
417706f2543Smrg
418706f2543Smrg    WriteToClient(client, sizeof(xDRI2SwapBuffersReply), &rep);
419706f2543Smrg
420706f2543Smrg    return Success;
421706f2543Smrg}
422706f2543Smrg
423706f2543Smrgstatic void
424706f2543Smrgload_msc_reply(xDRI2MSCReply *rep, CARD64 ust, CARD64 msc, CARD64 sbc)
425706f2543Smrg{
426706f2543Smrg    rep->ust_hi = ust >> 32;
427706f2543Smrg    rep->ust_lo = ust & 0xffffffff;
428706f2543Smrg    rep->msc_hi = msc >> 32;
429706f2543Smrg    rep->msc_lo = msc & 0xffffffff;
430706f2543Smrg    rep->sbc_hi = sbc >> 32;
431706f2543Smrg    rep->sbc_lo = sbc & 0xffffffff;
432706f2543Smrg}
433706f2543Smrg
434706f2543Smrgstatic int
435706f2543SmrgProcDRI2GetMSC(ClientPtr client)
436706f2543Smrg{
437706f2543Smrg    REQUEST(xDRI2GetMSCReq);
438706f2543Smrg    xDRI2MSCReply rep;
439706f2543Smrg    DrawablePtr pDrawable;
440706f2543Smrg    CARD64 ust, msc, sbc;
441706f2543Smrg    int status;
442706f2543Smrg
443706f2543Smrg    REQUEST_SIZE_MATCH(xDRI2GetMSCReq);
444706f2543Smrg
445706f2543Smrg    if (!validDrawable(client, stuff->drawable, DixReadAccess, &pDrawable,
446706f2543Smrg		       &status))
447706f2543Smrg	return status;
448706f2543Smrg
449706f2543Smrg    status = DRI2GetMSC(pDrawable, &ust, &msc, &sbc);
450706f2543Smrg    if (status != Success)
451706f2543Smrg	return status;
452706f2543Smrg
453706f2543Smrg    rep.type = X_Reply;
454706f2543Smrg    rep.length = 0;
455706f2543Smrg    rep.sequenceNumber = client->sequence;
456706f2543Smrg    load_msc_reply(&rep, ust, msc, sbc);
457706f2543Smrg
458706f2543Smrg    WriteToClient(client, sizeof(xDRI2MSCReply), &rep);
459706f2543Smrg
460706f2543Smrg    return Success;
461706f2543Smrg}
462706f2543Smrg
463706f2543Smrgstatic int
464706f2543SmrgProcDRI2WaitMSC(ClientPtr client)
465706f2543Smrg{
466706f2543Smrg    REQUEST(xDRI2WaitMSCReq);
467706f2543Smrg    DrawablePtr pDrawable;
468706f2543Smrg    CARD64 target, divisor, remainder;
469706f2543Smrg    int status;
470706f2543Smrg
471706f2543Smrg    /* FIXME: in restart case, client may be gone at this point */
472706f2543Smrg
473706f2543Smrg    REQUEST_SIZE_MATCH(xDRI2WaitMSCReq);
474706f2543Smrg
475706f2543Smrg    if (!validDrawable(client, stuff->drawable, DixReadAccess, &pDrawable,
476706f2543Smrg		       &status))
477706f2543Smrg	return status;
478706f2543Smrg
479706f2543Smrg    target = vals_to_card64(stuff->target_msc_lo, stuff->target_msc_hi);
480706f2543Smrg    divisor = vals_to_card64(stuff->divisor_lo, stuff->divisor_hi);
481706f2543Smrg    remainder = vals_to_card64(stuff->remainder_lo, stuff->remainder_hi);
482706f2543Smrg
483706f2543Smrg    status = DRI2WaitMSC(client, pDrawable, target, divisor, remainder);
484706f2543Smrg    if (status != Success)
485706f2543Smrg	return status;
486706f2543Smrg
487706f2543Smrg    return Success;
488706f2543Smrg}
489706f2543Smrg
490706f2543Smrgint
491706f2543SmrgProcDRI2WaitMSCReply(ClientPtr client, CARD64 ust, CARD64 msc, CARD64 sbc)
492706f2543Smrg{
493706f2543Smrg    xDRI2MSCReply rep;
494706f2543Smrg
495706f2543Smrg    rep.type = X_Reply;
496706f2543Smrg    rep.length = 0;
497706f2543Smrg    rep.sequenceNumber = client->sequence;
498706f2543Smrg    load_msc_reply(&rep, ust, msc, sbc);
499706f2543Smrg
500706f2543Smrg    WriteToClient(client, sizeof(xDRI2MSCReply), &rep);
501706f2543Smrg
502706f2543Smrg    return Success;
503706f2543Smrg}
504706f2543Smrg
505706f2543Smrgstatic int
506706f2543SmrgProcDRI2SwapInterval(ClientPtr client)
507706f2543Smrg{
508706f2543Smrg    REQUEST(xDRI2SwapIntervalReq);
509706f2543Smrg    DrawablePtr pDrawable;
510706f2543Smrg    int status;
511706f2543Smrg
512706f2543Smrg    /* FIXME: in restart case, client may be gone at this point */
513706f2543Smrg
514706f2543Smrg    REQUEST_SIZE_MATCH(xDRI2SwapIntervalReq);
515706f2543Smrg
516706f2543Smrg    if (!validDrawable(client, stuff->drawable, DixReadAccess | DixWriteAccess,
517706f2543Smrg		       &pDrawable, &status))
518706f2543Smrg	return status;
519706f2543Smrg
520706f2543Smrg    DRI2SwapInterval(pDrawable, stuff->interval);
521706f2543Smrg
522706f2543Smrg    return Success;
523706f2543Smrg}
524706f2543Smrg
525706f2543Smrgstatic int
526706f2543SmrgProcDRI2WaitSBC(ClientPtr client)
527706f2543Smrg{
528706f2543Smrg    REQUEST(xDRI2WaitSBCReq);
529706f2543Smrg    DrawablePtr pDrawable;
530706f2543Smrg    CARD64 target;
531706f2543Smrg    int status;
532706f2543Smrg
533706f2543Smrg    REQUEST_SIZE_MATCH(xDRI2WaitSBCReq);
534706f2543Smrg
535706f2543Smrg    if (!validDrawable(client, stuff->drawable, DixReadAccess, &pDrawable,
536706f2543Smrg		       &status))
537706f2543Smrg	return status;
538706f2543Smrg
539706f2543Smrg    target = vals_to_card64(stuff->target_sbc_lo, stuff->target_sbc_hi);
540706f2543Smrg    status = DRI2WaitSBC(client, pDrawable, target);
541706f2543Smrg
542706f2543Smrg    return status;
543706f2543Smrg}
544706f2543Smrg
545706f2543Smrgstatic int
546706f2543SmrgProcDRI2Dispatch (ClientPtr client)
547706f2543Smrg{
548706f2543Smrg    REQUEST(xReq);
549706f2543Smrg
550706f2543Smrg    switch (stuff->data) {
551706f2543Smrg    case X_DRI2QueryVersion:
552706f2543Smrg	return ProcDRI2QueryVersion(client);
553706f2543Smrg    }
554706f2543Smrg
555706f2543Smrg    if (!LocalClient(client))
556706f2543Smrg	return BadRequest;
557706f2543Smrg
558706f2543Smrg    switch (stuff->data) {
559706f2543Smrg    case X_DRI2Connect:
560706f2543Smrg	return ProcDRI2Connect(client);
561706f2543Smrg    case X_DRI2Authenticate:
562706f2543Smrg	return ProcDRI2Authenticate(client);
563706f2543Smrg    case X_DRI2CreateDrawable:
564706f2543Smrg	return ProcDRI2CreateDrawable(client);
565706f2543Smrg    case X_DRI2DestroyDrawable:
566706f2543Smrg	return ProcDRI2DestroyDrawable(client);
567706f2543Smrg    case X_DRI2GetBuffers:
568706f2543Smrg	return ProcDRI2GetBuffers(client);
569706f2543Smrg    case X_DRI2CopyRegion:
570706f2543Smrg	return ProcDRI2CopyRegion(client);
571706f2543Smrg    case X_DRI2GetBuffersWithFormat:
572706f2543Smrg	return ProcDRI2GetBuffersWithFormat(client);
573706f2543Smrg    case X_DRI2SwapBuffers:
574706f2543Smrg	return ProcDRI2SwapBuffers(client);
575706f2543Smrg    case X_DRI2GetMSC:
576706f2543Smrg	return ProcDRI2GetMSC(client);
577706f2543Smrg    case X_DRI2WaitMSC:
578706f2543Smrg	return ProcDRI2WaitMSC(client);
579706f2543Smrg    case X_DRI2WaitSBC:
580706f2543Smrg	return ProcDRI2WaitSBC(client);
581706f2543Smrg    case X_DRI2SwapInterval:
582706f2543Smrg	return ProcDRI2SwapInterval(client);
583706f2543Smrg    default:
584706f2543Smrg	return BadRequest;
585706f2543Smrg    }
586706f2543Smrg}
587706f2543Smrg
588706f2543Smrgstatic int
589706f2543SmrgSProcDRI2Connect(ClientPtr client)
590706f2543Smrg{
591706f2543Smrg    REQUEST(xDRI2ConnectReq);
592706f2543Smrg    xDRI2ConnectReply rep;
593706f2543Smrg    int n;
594706f2543Smrg
595706f2543Smrg    /* If the client is swapped, it's not local.  Talk to the hand. */
596706f2543Smrg
597706f2543Smrg    swaps(&stuff->length, n);
598706f2543Smrg    if (sizeof(*stuff) / 4 != client->req_len)
599706f2543Smrg	return BadLength;
600706f2543Smrg
601706f2543Smrg    rep.sequenceNumber = client->sequence;
602706f2543Smrg    swaps(&rep.sequenceNumber, n);
603706f2543Smrg    rep.length = 0;
604706f2543Smrg    rep.driverNameLength = 0;
605706f2543Smrg    rep.deviceNameLength = 0;
606706f2543Smrg
607706f2543Smrg    return Success;
608706f2543Smrg}
609706f2543Smrg
610706f2543Smrgstatic int
611706f2543SmrgSProcDRI2Dispatch (ClientPtr client)
612706f2543Smrg{
613706f2543Smrg    REQUEST(xReq);
614706f2543Smrg
615706f2543Smrg    /*
616706f2543Smrg     * Only local clients are allowed DRI access, but remote clients
617706f2543Smrg     * still need these requests to find out cleanly.
618706f2543Smrg     */
619706f2543Smrg    switch (stuff->data)
620706f2543Smrg    {
621706f2543Smrg    case X_DRI2QueryVersion:
622706f2543Smrg	return ProcDRI2QueryVersion(client);
623706f2543Smrg    case X_DRI2Connect:
624706f2543Smrg	return SProcDRI2Connect(client);
625706f2543Smrg    default:
626706f2543Smrg	return BadRequest;
627706f2543Smrg    }
628706f2543Smrg}
629706f2543Smrg
630706f2543Smrgint DRI2EventBase;
631706f2543Smrg
632706f2543Smrgstatic void
633706f2543SmrgDRI2ExtensionInit(void)
634706f2543Smrg{
635706f2543Smrg    dri2Extension = AddExtension(DRI2_NAME,
636706f2543Smrg				 DRI2NumberEvents,
637706f2543Smrg				 DRI2NumberErrors,
638706f2543Smrg				 ProcDRI2Dispatch,
639706f2543Smrg				 SProcDRI2Dispatch,
640706f2543Smrg				 NULL,
641706f2543Smrg				 StandardMinorOpcode);
642706f2543Smrg
643706f2543Smrg    DRI2EventBase = dri2Extension->eventBase;
644706f2543Smrg
645706f2543Smrg    DRI2ModuleSetup();
646706f2543Smrg}
647706f2543Smrg
648706f2543Smrgextern Bool noDRI2Extension;
649706f2543Smrg
650706f2543Smrg_X_HIDDEN ExtensionModule dri2ExtensionModule = {
651706f2543Smrg    DRI2ExtensionInit,
652706f2543Smrg    DRI2_NAME,
653706f2543Smrg    &noDRI2Extension,
654706f2543Smrg    NULL,
655706f2543Smrg    NULL
656706f2543Smrg};
657