1 /*
2 * Copyright © 2008 Red Hat, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Soft-
6 * ware"), to deal in the Software without restriction, including without
7 * limitation the rights to use, copy, modify, merge, publish, distribute,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, provided that the above copyright
10 * notice(s) and this permission notice appear in all copies of the Soft-
11 * ware and that both the above copyright notice(s) and this permission
12 * notice appear in supporting documentation.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
16 * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
17 * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
18 * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
19 * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
22 * MANCE OF THIS SOFTWARE.
23 *
24 * Except as contained in this notice, the name of a copyright holder shall
25 * not be used in advertising or otherwise to promote the sale, use or
26 * other dealings in this Software without prior written authorization of
27 * the copyright holder.
28 *
29 * Authors:
30 * Kristian Høgsberg (krh@redhat.com)
31 */
32
33 #ifdef HAVE_XORG_CONFIG_H
34 #include <xorg-config.h>
35 #endif
36
37 #include <X11/X.h>
38 #include <X11/Xproto.h>
39 #include <X11/extensions/dri2proto.h>
40 #include <X11/extensions/xfixeswire.h>
41 #include "dixstruct.h"
42 #include "scrnintstr.h"
43 #include "pixmapstr.h"
44 #include "extnsionst.h"
45 #include "xfixes.h"
46 #include "dri2.h"
47 #include "dri2int.h"
48 #include "protocol-versions.h"
49
50 /* The only xf86 includes */
51 #include "xf86Module.h"
52 #include "xf86Extensions.h"
53
54 static int DRI2EventBase;
55
56
57 static Bool
validDrawable(ClientPtr client,XID drawable,Mask access_mode,DrawablePtr * pDrawable,int * status)58 validDrawable(ClientPtr client, XID drawable, Mask access_mode,
59 DrawablePtr *pDrawable, int *status)
60 {
61 *status = dixLookupDrawable(pDrawable, drawable, client,
62 M_DRAWABLE_WINDOW | M_DRAWABLE_PIXMAP,
63 access_mode);
64 if (*status != Success) {
65 client->errorValue = drawable;
66 return FALSE;
67 }
68
69 return TRUE;
70 }
71
72 static int
ProcDRI2QueryVersion(ClientPtr client)73 ProcDRI2QueryVersion(ClientPtr client)
74 {
75 REQUEST(xDRI2QueryVersionReq);
76 xDRI2QueryVersionReply rep = {
77 .type = X_Reply,
78 .sequenceNumber = client->sequence,
79 .length = 0,
80 .majorVersion = dri2_major,
81 .minorVersion = dri2_minor
82 };
83
84 if (client->swapped)
85 swaps(&stuff->length);
86
87 REQUEST_SIZE_MATCH(xDRI2QueryVersionReq);
88
89 if (client->swapped) {
90 swaps(&rep.sequenceNumber);
91 swapl(&rep.length);
92 swapl(&rep.majorVersion);
93 swapl(&rep.minorVersion);
94 }
95
96 WriteToClient(client, sizeof(xDRI2QueryVersionReply), &rep);
97
98 return Success;
99 }
100
101 static int
ProcDRI2Connect(ClientPtr client)102 ProcDRI2Connect(ClientPtr client)
103 {
104 REQUEST(xDRI2ConnectReq);
105 xDRI2ConnectReply rep = {
106 .type = X_Reply,
107 .sequenceNumber = client->sequence,
108 .length = 0,
109 .driverNameLength = 0,
110 .deviceNameLength = 0
111 };
112 DrawablePtr pDraw;
113 int fd, status;
114 const char *driverName;
115 const char *deviceName;
116
117 REQUEST_SIZE_MATCH(xDRI2ConnectReq);
118 if (!validDrawable(client, stuff->window, DixGetAttrAccess,
119 &pDraw, &status))
120 return status;
121
122 if (!DRI2Connect(client, pDraw->pScreen,
123 stuff->driverType, &fd, &driverName, &deviceName))
124 goto fail;
125
126 rep.driverNameLength = strlen(driverName);
127 rep.deviceNameLength = strlen(deviceName);
128 rep.length = (rep.driverNameLength + 3) / 4 +
129 (rep.deviceNameLength + 3) / 4;
130
131 fail:
132 WriteToClient(client, sizeof(xDRI2ConnectReply), &rep);
133 WriteToClient(client, rep.driverNameLength, driverName);
134 WriteToClient(client, rep.deviceNameLength, deviceName);
135
136 return Success;
137 }
138
139 static int
ProcDRI2Authenticate(ClientPtr client)140 ProcDRI2Authenticate(ClientPtr client)
141 {
142 REQUEST(xDRI2AuthenticateReq);
143 xDRI2AuthenticateReply rep;
144 DrawablePtr pDraw;
145 int status;
146
147 REQUEST_SIZE_MATCH(xDRI2AuthenticateReq);
148 if (!validDrawable(client, stuff->window, DixGetAttrAccess,
149 &pDraw, &status))
150 return status;
151
152 rep = (xDRI2AuthenticateReply) {
153 .type = X_Reply,
154 .sequenceNumber = client->sequence,
155 .length = 0,
156 .authenticated = DRI2Authenticate(client, pDraw->pScreen, stuff->magic)
157 };
158 WriteToClient(client, sizeof(xDRI2AuthenticateReply), &rep);
159
160 return Success;
161 }
162
163 static void
DRI2InvalidateBuffersEvent(DrawablePtr pDraw,void * priv,XID id)164 DRI2InvalidateBuffersEvent(DrawablePtr pDraw, void *priv, XID id)
165 {
166 ClientPtr client = priv;
167 xDRI2InvalidateBuffers event = {
168 .type = DRI2EventBase + DRI2_InvalidateBuffers,
169 .drawable = id
170 };
171
172 WriteEventsToClient(client, 1, (xEvent *) &event);
173 }
174
175 static int
ProcDRI2CreateDrawable(ClientPtr client)176 ProcDRI2CreateDrawable(ClientPtr client)
177 {
178 REQUEST(xDRI2CreateDrawableReq);
179 DrawablePtr pDrawable;
180 int status;
181
182 REQUEST_SIZE_MATCH(xDRI2CreateDrawableReq);
183
184 if (!validDrawable(client, stuff->drawable, DixAddAccess,
185 &pDrawable, &status))
186 return status;
187
188 status = DRI2CreateDrawable(client, pDrawable, stuff->drawable,
189 DRI2InvalidateBuffersEvent, client);
190 if (status != Success)
191 return status;
192
193 return Success;
194 }
195
196 static int
ProcDRI2DestroyDrawable(ClientPtr client)197 ProcDRI2DestroyDrawable(ClientPtr client)
198 {
199 REQUEST(xDRI2DestroyDrawableReq);
200 DrawablePtr pDrawable;
201 int status;
202
203 REQUEST_SIZE_MATCH(xDRI2DestroyDrawableReq);
204 if (!validDrawable(client, stuff->drawable, DixRemoveAccess,
205 &pDrawable, &status))
206 return status;
207
208 return Success;
209 }
210
211 static int
send_buffers_reply(ClientPtr client,DrawablePtr pDrawable,DRI2BufferPtr * buffers,int count,int width,int height)212 send_buffers_reply(ClientPtr client, DrawablePtr pDrawable,
213 DRI2BufferPtr * buffers, int count, int width, int height)
214 {
215 xDRI2GetBuffersReply rep;
216 int skip = 0;
217 int i;
218
219 if (buffers == NULL)
220 return BadAlloc;
221
222 if (pDrawable->type == DRAWABLE_WINDOW) {
223 for (i = 0; i < count; i++) {
224 /* Do not send the real front buffer of a window to the client.
225 */
226 if (buffers[i]->attachment == DRI2BufferFrontLeft) {
227 skip++;
228 continue;
229 }
230 }
231 }
232
233 rep = (xDRI2GetBuffersReply) {
234 .type = X_Reply,
235 .sequenceNumber = client->sequence,
236 .length = (count - skip) * sizeof(xDRI2Buffer) / 4,
237 .width = width,
238 .height = height,
239 .count = count - skip
240 };
241 WriteToClient(client, sizeof(xDRI2GetBuffersReply), &rep);
242
243 for (i = 0; i < count; i++) {
244 xDRI2Buffer buffer;
245
246 /* Do not send the real front buffer of a window to the client.
247 */
248 if ((pDrawable->type == DRAWABLE_WINDOW)
249 && (buffers[i]->attachment == DRI2BufferFrontLeft)) {
250 continue;
251 }
252
253 buffer.attachment = buffers[i]->attachment;
254 buffer.name = buffers[i]->name;
255 buffer.pitch = buffers[i]->pitch;
256 buffer.cpp = buffers[i]->cpp;
257 buffer.flags = buffers[i]->flags;
258 WriteToClient(client, sizeof(xDRI2Buffer), &buffer);
259 }
260 return Success;
261 }
262
263 static int
ProcDRI2GetBuffers(ClientPtr client)264 ProcDRI2GetBuffers(ClientPtr client)
265 {
266 REQUEST(xDRI2GetBuffersReq);
267 DrawablePtr pDrawable;
268 DRI2BufferPtr *buffers;
269 int status, width, height, count;
270 unsigned int *attachments;
271
272 REQUEST_AT_LEAST_SIZE(xDRI2GetBuffersReq);
273 /* stuff->count is a count of CARD32 attachments that follows */
274 if (stuff->count > (INT_MAX / sizeof(CARD32)))
275 return BadLength;
276 REQUEST_FIXED_SIZE(xDRI2GetBuffersReq, stuff->count * sizeof(CARD32));
277
278 if (!validDrawable(client, stuff->drawable, DixReadAccess | DixWriteAccess,
279 &pDrawable, &status))
280 return status;
281
282 if (DRI2ThrottleClient(client, pDrawable))
283 return Success;
284
285 attachments = (unsigned int *) &stuff[1];
286 buffers = DRI2GetBuffers(pDrawable, &width, &height,
287 attachments, stuff->count, &count);
288
289 return send_buffers_reply(client, pDrawable, buffers, count, width, height);
290
291 }
292
293 static int
ProcDRI2GetBuffersWithFormat(ClientPtr client)294 ProcDRI2GetBuffersWithFormat(ClientPtr client)
295 {
296 REQUEST(xDRI2GetBuffersReq);
297 DrawablePtr pDrawable;
298 DRI2BufferPtr *buffers;
299 int status, width, height, count;
300 unsigned int *attachments;
301
302 REQUEST_AT_LEAST_SIZE(xDRI2GetBuffersReq);
303 /* stuff->count is a count of pairs of CARD32s (attachments & formats)
304 that follows */
305 if (stuff->count > (INT_MAX / (2 * sizeof(CARD32))))
306 return BadLength;
307 REQUEST_FIXED_SIZE(xDRI2GetBuffersReq,
308 stuff->count * (2 * sizeof(CARD32)));
309 if (!validDrawable(client, stuff->drawable, DixReadAccess | DixWriteAccess,
310 &pDrawable, &status))
311 return status;
312
313 if (DRI2ThrottleClient(client, pDrawable))
314 return Success;
315
316 attachments = (unsigned int *) &stuff[1];
317 buffers = DRI2GetBuffersWithFormat(pDrawable, &width, &height,
318 attachments, stuff->count, &count);
319
320 return send_buffers_reply(client, pDrawable, buffers, count, width, height);
321 }
322
323 static int
ProcDRI2CopyRegion(ClientPtr client)324 ProcDRI2CopyRegion(ClientPtr client)
325 {
326 REQUEST(xDRI2CopyRegionReq);
327 xDRI2CopyRegionReply rep;
328 DrawablePtr pDrawable;
329 int status;
330 RegionPtr pRegion;
331
332 REQUEST_SIZE_MATCH(xDRI2CopyRegionReq);
333
334 if (!validDrawable(client, stuff->drawable, DixWriteAccess,
335 &pDrawable, &status))
336 return status;
337
338 VERIFY_REGION(pRegion, stuff->region, client, DixReadAccess);
339
340 status = DRI2CopyRegion(pDrawable, pRegion, stuff->dest, stuff->src);
341 if (status != Success)
342 return status;
343
344 /* CopyRegion needs to be a round trip to make sure the X server
345 * queues the swap buffer rendering commands before the DRI client
346 * continues rendering. The reply has a bitmask to signal the
347 * presense of optional return values as well, but we're not using
348 * that yet.
349 */
350
351 rep = (xDRI2CopyRegionReply) {
352 .type = X_Reply,
353 .sequenceNumber = client->sequence,
354 .length = 0
355 };
356
357 WriteToClient(client, sizeof(xDRI2CopyRegionReply), &rep);
358
359 return Success;
360 }
361
362 static void
load_swap_reply(xDRI2SwapBuffersReply * rep,CARD64 sbc)363 load_swap_reply(xDRI2SwapBuffersReply * rep, CARD64 sbc)
364 {
365 rep->swap_hi = sbc >> 32;
366 rep->swap_lo = sbc & 0xffffffff;
367 }
368
369 static CARD64
vals_to_card64(CARD32 lo,CARD32 hi)370 vals_to_card64(CARD32 lo, CARD32 hi)
371 {
372 return (CARD64) hi << 32 | lo;
373 }
374
375 static void
DRI2SwapEvent(ClientPtr client,void * data,int type,CARD64 ust,CARD64 msc,CARD32 sbc)376 DRI2SwapEvent(ClientPtr client, void *data, int type, CARD64 ust, CARD64 msc,
377 CARD32 sbc)
378 {
379 DrawablePtr pDrawable = data;
380 xDRI2BufferSwapComplete2 event = {
381 .type = DRI2EventBase + DRI2_BufferSwapComplete,
382 .event_type = type,
383 .drawable = pDrawable->id,
384 .ust_hi = (CARD64) ust >> 32,
385 .ust_lo = ust & 0xffffffff,
386 .msc_hi = (CARD64) msc >> 32,
387 .msc_lo = msc & 0xffffffff,
388 .sbc = sbc
389 };
390
391 WriteEventsToClient(client, 1, (xEvent *) &event);
392 }
393
394 static int
ProcDRI2SwapBuffers(ClientPtr client)395 ProcDRI2SwapBuffers(ClientPtr client)
396 {
397 REQUEST(xDRI2SwapBuffersReq);
398 xDRI2SwapBuffersReply rep = {
399 .type = X_Reply,
400 .sequenceNumber = client->sequence,
401 .length = 0
402 };
403 DrawablePtr pDrawable;
404 CARD64 target_msc, divisor, remainder, swap_target;
405 int status;
406
407 REQUEST_SIZE_MATCH(xDRI2SwapBuffersReq);
408
409 if (!validDrawable(client, stuff->drawable,
410 DixReadAccess | DixWriteAccess, &pDrawable, &status))
411 return status;
412
413 /*
414 * Ensures an out of control client can't exhaust our swap queue, and
415 * also orders swaps.
416 */
417 if (DRI2ThrottleClient(client, pDrawable))
418 return Success;
419
420 target_msc = vals_to_card64(stuff->target_msc_lo, stuff->target_msc_hi);
421 divisor = vals_to_card64(stuff->divisor_lo, stuff->divisor_hi);
422 remainder = vals_to_card64(stuff->remainder_lo, stuff->remainder_hi);
423
424 status = DRI2SwapBuffers(client, pDrawable, target_msc, divisor, remainder,
425 &swap_target, DRI2SwapEvent, pDrawable);
426 if (status != Success)
427 return BadDrawable;
428
429 load_swap_reply(&rep, swap_target);
430
431 WriteToClient(client, sizeof(xDRI2SwapBuffersReply), &rep);
432
433 return Success;
434 }
435
436 static void
load_msc_reply(xDRI2MSCReply * rep,CARD64 ust,CARD64 msc,CARD64 sbc)437 load_msc_reply(xDRI2MSCReply * rep, CARD64 ust, CARD64 msc, CARD64 sbc)
438 {
439 rep->ust_hi = ust >> 32;
440 rep->ust_lo = ust & 0xffffffff;
441 rep->msc_hi = msc >> 32;
442 rep->msc_lo = msc & 0xffffffff;
443 rep->sbc_hi = sbc >> 32;
444 rep->sbc_lo = sbc & 0xffffffff;
445 }
446
447 static int
ProcDRI2GetMSC(ClientPtr client)448 ProcDRI2GetMSC(ClientPtr client)
449 {
450 REQUEST(xDRI2GetMSCReq);
451 xDRI2MSCReply rep = {
452 .type = X_Reply,
453 .sequenceNumber = client->sequence,
454 .length = 0
455 };
456 DrawablePtr pDrawable;
457 CARD64 ust, msc, sbc;
458 int status;
459
460 REQUEST_SIZE_MATCH(xDRI2GetMSCReq);
461
462 if (!validDrawable(client, stuff->drawable, DixReadAccess, &pDrawable,
463 &status))
464 return status;
465
466 status = DRI2GetMSC(pDrawable, &ust, &msc, &sbc);
467 if (status != Success)
468 return status;
469
470 load_msc_reply(&rep, ust, msc, sbc);
471
472 WriteToClient(client, sizeof(xDRI2MSCReply), &rep);
473
474 return Success;
475 }
476
477 static int
ProcDRI2WaitMSC(ClientPtr client)478 ProcDRI2WaitMSC(ClientPtr client)
479 {
480 REQUEST(xDRI2WaitMSCReq);
481 DrawablePtr pDrawable;
482 CARD64 target, divisor, remainder;
483 int status;
484
485 /* FIXME: in restart case, client may be gone at this point */
486
487 REQUEST_SIZE_MATCH(xDRI2WaitMSCReq);
488
489 if (!validDrawable(client, stuff->drawable, DixReadAccess, &pDrawable,
490 &status))
491 return status;
492
493 target = vals_to_card64(stuff->target_msc_lo, stuff->target_msc_hi);
494 divisor = vals_to_card64(stuff->divisor_lo, stuff->divisor_hi);
495 remainder = vals_to_card64(stuff->remainder_lo, stuff->remainder_hi);
496
497 status = DRI2WaitMSC(client, pDrawable, target, divisor, remainder);
498 if (status != Success)
499 return status;
500
501 return Success;
502 }
503
504 int
ProcDRI2WaitMSCReply(ClientPtr client,CARD64 ust,CARD64 msc,CARD64 sbc)505 ProcDRI2WaitMSCReply(ClientPtr client, CARD64 ust, CARD64 msc, CARD64 sbc)
506 {
507 xDRI2MSCReply rep = {
508 .type = X_Reply,
509 .sequenceNumber = client->sequence,
510 .length = 0
511 };
512
513 load_msc_reply(&rep, ust, msc, sbc);
514
515 WriteToClient(client, sizeof(xDRI2MSCReply), &rep);
516
517 return Success;
518 }
519
520 static int
ProcDRI2SwapInterval(ClientPtr client)521 ProcDRI2SwapInterval(ClientPtr client)
522 {
523 REQUEST(xDRI2SwapIntervalReq);
524 DrawablePtr pDrawable;
525 int status;
526
527 /* FIXME: in restart case, client may be gone at this point */
528
529 REQUEST_SIZE_MATCH(xDRI2SwapIntervalReq);
530
531 if (!validDrawable(client, stuff->drawable, DixReadAccess | DixWriteAccess,
532 &pDrawable, &status))
533 return status;
534
535 DRI2SwapInterval(pDrawable, stuff->interval);
536
537 return Success;
538 }
539
540 static int
ProcDRI2WaitSBC(ClientPtr client)541 ProcDRI2WaitSBC(ClientPtr client)
542 {
543 REQUEST(xDRI2WaitSBCReq);
544 DrawablePtr pDrawable;
545 CARD64 target;
546 int status;
547
548 REQUEST_SIZE_MATCH(xDRI2WaitSBCReq);
549
550 if (!validDrawable(client, stuff->drawable, DixReadAccess, &pDrawable,
551 &status))
552 return status;
553
554 target = vals_to_card64(stuff->target_sbc_lo, stuff->target_sbc_hi);
555 status = DRI2WaitSBC(client, pDrawable, target);
556
557 return status;
558 }
559
560 static int
ProcDRI2GetParam(ClientPtr client)561 ProcDRI2GetParam(ClientPtr client)
562 {
563 REQUEST(xDRI2GetParamReq);
564 xDRI2GetParamReply rep = {
565 .type = X_Reply,
566 .sequenceNumber = client->sequence,
567 .length = 0
568 };
569 DrawablePtr pDrawable;
570 CARD64 value;
571 int status;
572
573 REQUEST_SIZE_MATCH(xDRI2GetParamReq);
574
575 if (!validDrawable(client, stuff->drawable, DixReadAccess,
576 &pDrawable, &status))
577 return status;
578
579 status = DRI2GetParam(client, pDrawable, stuff->param,
580 &rep.is_param_recognized, &value);
581 rep.value_hi = value >> 32;
582 rep.value_lo = value & 0xffffffff;
583
584 if (status != Success)
585 return status;
586
587 WriteToClient(client, sizeof(xDRI2GetParamReply), &rep);
588
589 return status;
590 }
591
592 static int
ProcDRI2Dispatch(ClientPtr client)593 ProcDRI2Dispatch(ClientPtr client)
594 {
595 REQUEST(xReq);
596
597 switch (stuff->data) {
598 case X_DRI2QueryVersion:
599 return ProcDRI2QueryVersion(client);
600 }
601
602 if (!client->local)
603 return BadRequest;
604
605 switch (stuff->data) {
606 case X_DRI2Connect:
607 return ProcDRI2Connect(client);
608 case X_DRI2Authenticate:
609 return ProcDRI2Authenticate(client);
610 case X_DRI2CreateDrawable:
611 return ProcDRI2CreateDrawable(client);
612 case X_DRI2DestroyDrawable:
613 return ProcDRI2DestroyDrawable(client);
614 case X_DRI2GetBuffers:
615 return ProcDRI2GetBuffers(client);
616 case X_DRI2CopyRegion:
617 return ProcDRI2CopyRegion(client);
618 case X_DRI2GetBuffersWithFormat:
619 return ProcDRI2GetBuffersWithFormat(client);
620 case X_DRI2SwapBuffers:
621 return ProcDRI2SwapBuffers(client);
622 case X_DRI2GetMSC:
623 return ProcDRI2GetMSC(client);
624 case X_DRI2WaitMSC:
625 return ProcDRI2WaitMSC(client);
626 case X_DRI2WaitSBC:
627 return ProcDRI2WaitSBC(client);
628 case X_DRI2SwapInterval:
629 return ProcDRI2SwapInterval(client);
630 case X_DRI2GetParam:
631 return ProcDRI2GetParam(client);
632 default:
633 return BadRequest;
634 }
635 }
636
637 static int _X_COLD
SProcDRI2Connect(ClientPtr client)638 SProcDRI2Connect(ClientPtr client)
639 {
640 REQUEST(xDRI2ConnectReq);
641 xDRI2ConnectReply rep = {
642 .type = X_Reply,
643 .sequenceNumber = client->sequence,
644 .length = 0,
645 .driverNameLength = 0,
646 .deviceNameLength = 0
647 };
648
649 /* If the client is swapped, it's not local. Talk to the hand. */
650
651 swaps(&stuff->length);
652 if (sizeof(*stuff) / 4 != client->req_len)
653 return BadLength;
654
655 swaps(&rep.sequenceNumber);
656
657 WriteToClient(client, sizeof(xDRI2ConnectReply), &rep);
658
659 return Success;
660 }
661
662 static int _X_COLD
SProcDRI2Dispatch(ClientPtr client)663 SProcDRI2Dispatch(ClientPtr client)
664 {
665 REQUEST(xReq);
666
667 /*
668 * Only local clients are allowed DRI access, but remote clients
669 * still need these requests to find out cleanly.
670 */
671 switch (stuff->data) {
672 case X_DRI2QueryVersion:
673 return ProcDRI2QueryVersion(client);
674 case X_DRI2Connect:
675 return SProcDRI2Connect(client);
676 default:
677 return BadRequest;
678 }
679 }
680
681 void
DRI2ExtensionInit(void)682 DRI2ExtensionInit(void)
683 {
684 ExtensionEntry *dri2Extension;
685
686 #ifdef PANORAMIX
687 if (!noPanoramiXExtension)
688 return;
689 #endif
690
691 dri2Extension = AddExtension(DRI2_NAME,
692 DRI2NumberEvents,
693 DRI2NumberErrors,
694 ProcDRI2Dispatch,
695 SProcDRI2Dispatch, NULL, StandardMinorOpcode);
696
697 DRI2EventBase = dri2Extension->eventBase;
698
699 DRI2ModuleSetup();
700 }
701