dri3_request.c revision 1b5d61b8
1/*
2 * Copyright © 2013 Keith Packard
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of the copyright holders not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission.  The copyright holders make no representations
11 * about the suitability of this software for any purpose.  It is provided "as
12 * is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20 * OF THIS SOFTWARE.
21 */
22
23#ifdef HAVE_XORG_CONFIG_H
24#include <xorg-config.h>
25#endif
26
27#include "dri3_priv.h"
28#include <syncsrv.h>
29#include <unistd.h>
30#include <xace.h>
31#include "../Xext/syncsdk.h"
32#include <protocol-versions.h>
33#include <drm_fourcc.h>
34
35static Bool
36dri3_screen_can_one_point_two(ScreenPtr screen)
37{
38    dri3_screen_priv_ptr dri3 = dri3_screen_priv(screen);
39
40    if (dri3 && dri3->info && dri3->info->version >= 2 &&
41        dri3->info->pixmap_from_fds && dri3->info->fds_from_pixmap &&
42        dri3->info->get_formats && dri3->info->get_modifiers &&
43        dri3->info->get_drawable_modifiers)
44        return TRUE;
45
46    return FALSE;
47}
48
49static int
50proc_dri3_query_version(ClientPtr client)
51{
52    REQUEST(xDRI3QueryVersionReq);
53    xDRI3QueryVersionReply rep = {
54        .type = X_Reply,
55        .sequenceNumber = client->sequence,
56        .length = 0,
57        .majorVersion = SERVER_DRI3_MAJOR_VERSION,
58        .minorVersion = SERVER_DRI3_MINOR_VERSION
59    };
60
61    REQUEST_SIZE_MATCH(xDRI3QueryVersionReq);
62
63    for (int i = 0; i < screenInfo.numScreens; i++) {
64        if (!dri3_screen_can_one_point_two(screenInfo.screens[i])) {
65            rep.minorVersion = 0;
66            break;
67        }
68    }
69
70    for (int i = 0; i < screenInfo.numGPUScreens; i++) {
71        if (!dri3_screen_can_one_point_two(screenInfo.gpuscreens[i])) {
72            rep.minorVersion = 0;
73            break;
74        }
75    }
76
77    /* From DRI3 proto:
78     *
79     * The client sends the highest supported version to the server
80     * and the server sends the highest version it supports, but no
81     * higher than the requested version.
82     */
83
84    if (rep.majorVersion > stuff->majorVersion ||
85        (rep.majorVersion == stuff->majorVersion &&
86         rep.minorVersion > stuff->minorVersion)) {
87        rep.majorVersion = stuff->majorVersion;
88        rep.minorVersion = stuff->minorVersion;
89    }
90
91    if (client->swapped) {
92        swaps(&rep.sequenceNumber);
93        swapl(&rep.length);
94        swapl(&rep.majorVersion);
95        swapl(&rep.minorVersion);
96    }
97    WriteToClient(client, sizeof(rep), &rep);
98    return Success;
99}
100
101int
102dri3_send_open_reply(ClientPtr client, int fd)
103{
104    xDRI3OpenReply rep = {
105        .type = X_Reply,
106        .nfd = 1,
107        .sequenceNumber = client->sequence,
108        .length = 0,
109    };
110
111    if (client->swapped) {
112        swaps(&rep.sequenceNumber);
113        swapl(&rep.length);
114    }
115
116    if (WriteFdToClient(client, fd, TRUE) < 0) {
117        close(fd);
118        return BadAlloc;
119    }
120
121    WriteToClient(client, sizeof (rep), &rep);
122
123    return Success;
124}
125
126static int
127proc_dri3_open(ClientPtr client)
128{
129    REQUEST(xDRI3OpenReq);
130    RRProviderPtr provider;
131    DrawablePtr drawable;
132    ScreenPtr screen;
133    int fd;
134    int status;
135
136    REQUEST_SIZE_MATCH(xDRI3OpenReq);
137
138    status = dixLookupDrawable(&drawable, stuff->drawable, client, 0, DixReadAccess);
139    if (status != Success)
140        return status;
141
142    if (stuff->provider == None)
143        provider = NULL;
144    else if (!RRProviderType) {
145        return BadMatch;
146    } else {
147        VERIFY_RR_PROVIDER(stuff->provider, provider, DixReadAccess);
148        if (drawable->pScreen != provider->pScreen)
149            return BadMatch;
150    }
151    screen = drawable->pScreen;
152
153    status = dri3_open(client, screen, provider, &fd);
154    if (status != Success)
155        return status;
156
157    if (client->ignoreCount == 0)
158        return dri3_send_open_reply(client, fd);
159
160    return Success;
161}
162
163static int
164proc_dri3_pixmap_from_buffer(ClientPtr client)
165{
166    REQUEST(xDRI3PixmapFromBufferReq);
167    int fd;
168    DrawablePtr drawable;
169    PixmapPtr pixmap;
170    CARD32 stride, offset;
171    int rc;
172
173    SetReqFds(client, 1);
174    REQUEST_SIZE_MATCH(xDRI3PixmapFromBufferReq);
175    LEGAL_NEW_RESOURCE(stuff->pixmap, client);
176    rc = dixLookupDrawable(&drawable, stuff->drawable, client, M_ANY, DixGetAttrAccess);
177    if (rc != Success) {
178        client->errorValue = stuff->drawable;
179        return rc;
180    }
181
182    if (!stuff->width || !stuff->height) {
183        client->errorValue = 0;
184        return BadValue;
185    }
186
187    if (stuff->width > 32767 || stuff->height > 32767)
188        return BadAlloc;
189
190    if (stuff->depth != 1) {
191        DepthPtr depth = drawable->pScreen->allowedDepths;
192        int i;
193        for (i = 0; i < drawable->pScreen->numDepths; i++, depth++)
194            if (depth->depth == stuff->depth)
195                break;
196        if (i == drawable->pScreen->numDepths) {
197            client->errorValue = stuff->depth;
198            return BadValue;
199        }
200    }
201
202    fd = ReadFdFromClient(client);
203    if (fd < 0)
204        return BadValue;
205
206    offset = 0;
207    stride = stuff->stride;
208    rc = dri3_pixmap_from_fds(&pixmap,
209                              drawable->pScreen, 1, &fd,
210                              stuff->width, stuff->height,
211                              &stride, &offset,
212                              stuff->depth, stuff->bpp,
213                              DRM_FORMAT_MOD_INVALID);
214    close (fd);
215    if (rc != Success)
216        return rc;
217
218    pixmap->drawable.id = stuff->pixmap;
219
220    /* security creation/labeling check */
221    rc = XaceHook(XACE_RESOURCE_ACCESS, client, stuff->pixmap, RT_PIXMAP,
222                  pixmap, RT_NONE, NULL, DixCreateAccess);
223
224    if (rc != Success) {
225        (*drawable->pScreen->DestroyPixmap) (pixmap);
226        return rc;
227    }
228    if (!AddResource(stuff->pixmap, RT_PIXMAP, (void *) pixmap))
229        return BadAlloc;
230
231    return Success;
232}
233
234static int
235proc_dri3_buffer_from_pixmap(ClientPtr client)
236{
237    REQUEST(xDRI3BufferFromPixmapReq);
238    xDRI3BufferFromPixmapReply rep = {
239        .type = X_Reply,
240        .nfd = 1,
241        .sequenceNumber = client->sequence,
242        .length = 0,
243    };
244    int rc;
245    int fd;
246    PixmapPtr pixmap;
247
248    REQUEST_SIZE_MATCH(xDRI3BufferFromPixmapReq);
249    rc = dixLookupResourceByType((void **) &pixmap, stuff->pixmap, RT_PIXMAP,
250                                 client, DixWriteAccess);
251    if (rc != Success) {
252        client->errorValue = stuff->pixmap;
253        return rc;
254    }
255
256    rep.width = pixmap->drawable.width;
257    rep.height = pixmap->drawable.height;
258    rep.depth = pixmap->drawable.depth;
259    rep.bpp = pixmap->drawable.bitsPerPixel;
260
261    fd = dri3_fd_from_pixmap(pixmap, &rep.stride, &rep.size);
262    if (fd < 0)
263        return BadPixmap;
264
265    if (client->swapped) {
266        swaps(&rep.sequenceNumber);
267        swapl(&rep.length);
268        swapl(&rep.size);
269        swaps(&rep.width);
270        swaps(&rep.height);
271        swaps(&rep.stride);
272    }
273    if (WriteFdToClient(client, fd, TRUE) < 0) {
274        close(fd);
275        return BadAlloc;
276    }
277
278    WriteToClient(client, sizeof(rep), &rep);
279
280    return Success;
281}
282
283static int
284proc_dri3_fence_from_fd(ClientPtr client)
285{
286    REQUEST(xDRI3FenceFromFDReq);
287    DrawablePtr drawable;
288    int fd;
289    int status;
290
291    SetReqFds(client, 1);
292    REQUEST_SIZE_MATCH(xDRI3FenceFromFDReq);
293    LEGAL_NEW_RESOURCE(stuff->fence, client);
294
295    status = dixLookupDrawable(&drawable, stuff->drawable, client, M_ANY, DixGetAttrAccess);
296    if (status != Success)
297        return status;
298
299    fd = ReadFdFromClient(client);
300    if (fd < 0)
301        return BadValue;
302
303    status = SyncCreateFenceFromFD(client, drawable, stuff->fence,
304                                   fd, stuff->initially_triggered);
305
306    return status;
307}
308
309static int
310proc_dri3_fd_from_fence(ClientPtr client)
311{
312    REQUEST(xDRI3FDFromFenceReq);
313    xDRI3FDFromFenceReply rep = {
314        .type = X_Reply,
315        .nfd = 1,
316        .sequenceNumber = client->sequence,
317        .length = 0,
318    };
319    DrawablePtr drawable;
320    int fd;
321    int status;
322    SyncFence *fence;
323
324    REQUEST_SIZE_MATCH(xDRI3FDFromFenceReq);
325
326    status = dixLookupDrawable(&drawable, stuff->drawable, client, M_ANY, DixGetAttrAccess);
327    if (status != Success)
328        return status;
329    status = SyncVerifyFence(&fence, stuff->fence, client, DixWriteAccess);
330    if (status != Success)
331        return status;
332
333    fd = SyncFDFromFence(client, drawable, fence);
334    if (fd < 0)
335        return BadMatch;
336
337    if (client->swapped) {
338        swaps(&rep.sequenceNumber);
339        swapl(&rep.length);
340    }
341    if (WriteFdToClient(client, fd, FALSE) < 0)
342        return BadAlloc;
343
344    WriteToClient(client, sizeof(rep), &rep);
345
346    return Success;
347}
348
349static int
350proc_dri3_get_supported_modifiers(ClientPtr client)
351{
352    REQUEST(xDRI3GetSupportedModifiersReq);
353    xDRI3GetSupportedModifiersReply rep = {
354        .type = X_Reply,
355        .sequenceNumber = client->sequence,
356    };
357    WindowPtr window;
358    ScreenPtr pScreen;
359    CARD64 *window_modifiers = NULL;
360    CARD64 *screen_modifiers = NULL;
361    CARD32 nwindowmodifiers = 0;
362    CARD32 nscreenmodifiers = 0;
363    int status;
364    int i;
365
366    REQUEST_SIZE_MATCH(xDRI3GetSupportedModifiersReq);
367
368    status = dixLookupWindow(&window, stuff->window, client, DixReadAccess);
369    if (status != Success)
370        return status;
371    pScreen = window->drawable.pScreen;
372
373    dri3_get_supported_modifiers(pScreen, &window->drawable,
374				 stuff->depth, stuff->bpp,
375                                 &nwindowmodifiers, &window_modifiers,
376                                 &nscreenmodifiers, &screen_modifiers);
377
378    rep.numWindowModifiers = nwindowmodifiers;
379    rep.numScreenModifiers = nscreenmodifiers;
380    rep.length = bytes_to_int32(rep.numWindowModifiers * sizeof(CARD64)) +
381                 bytes_to_int32(rep.numScreenModifiers * sizeof(CARD64));
382
383    if (client->swapped) {
384        swaps(&rep.sequenceNumber);
385        swapl(&rep.length);
386        swapl(&rep.numWindowModifiers);
387        swapl(&rep.numScreenModifiers);
388        for (i = 0; i < nwindowmodifiers; i++)
389            swapll(&window_modifiers[i]);
390        for (i = 0; i < nscreenmodifiers; i++)
391            swapll(&screen_modifiers[i]);
392    }
393
394    WriteToClient(client, sizeof(rep), &rep);
395    WriteToClient(client, nwindowmodifiers * sizeof(CARD64), window_modifiers);
396    WriteToClient(client, nscreenmodifiers * sizeof(CARD64), screen_modifiers);
397
398    free(window_modifiers);
399    free(screen_modifiers);
400
401    return Success;
402}
403
404static int
405proc_dri3_pixmap_from_buffers(ClientPtr client)
406{
407    REQUEST(xDRI3PixmapFromBuffersReq);
408    int fds[4];
409    CARD32 strides[4], offsets[4];
410    ScreenPtr screen;
411    WindowPtr window;
412    PixmapPtr pixmap;
413    int rc;
414    int i;
415
416    SetReqFds(client, stuff->num_buffers);
417    REQUEST_SIZE_MATCH(xDRI3PixmapFromBuffersReq);
418    LEGAL_NEW_RESOURCE(stuff->pixmap, client);
419    rc = dixLookupWindow(&window, stuff->window, client, DixGetAttrAccess);
420    if (rc != Success) {
421        client->errorValue = stuff->window;
422        return rc;
423    }
424    screen = window->drawable.pScreen;
425
426    if (!stuff->width || !stuff->height || !stuff->bpp || !stuff->depth) {
427        client->errorValue = 0;
428        return BadValue;
429    }
430
431    if (stuff->width > 32767 || stuff->height > 32767)
432        return BadAlloc;
433
434    if (stuff->depth != 1) {
435        DepthPtr depth = screen->allowedDepths;
436        int j;
437        for (j = 0; j < screen->numDepths; j++, depth++)
438            if (depth->depth == stuff->depth)
439                break;
440        if (j == screen->numDepths) {
441            client->errorValue = stuff->depth;
442            return BadValue;
443        }
444    }
445
446    if (!stuff->num_buffers || stuff->num_buffers > 4) {
447        client->errorValue = stuff->num_buffers;
448        return BadValue;
449    }
450
451    for (i = 0; i < stuff->num_buffers; i++) {
452        fds[i] = ReadFdFromClient(client);
453        if (fds[i] < 0) {
454            while (--i >= 0)
455                close(fds[i]);
456            return BadValue;
457        }
458    }
459
460    strides[0] = stuff->stride0;
461    strides[1] = stuff->stride1;
462    strides[2] = stuff->stride2;
463    strides[3] = stuff->stride3;
464    offsets[0] = stuff->offset0;
465    offsets[1] = stuff->offset1;
466    offsets[2] = stuff->offset2;
467    offsets[3] = stuff->offset3;
468
469    rc = dri3_pixmap_from_fds(&pixmap, screen,
470                              stuff->num_buffers, fds,
471                              stuff->width, stuff->height,
472                              strides, offsets,
473                              stuff->depth, stuff->bpp,
474                              stuff->modifier);
475
476    for (i = 0; i < stuff->num_buffers; i++)
477        close (fds[i]);
478
479    if (rc != Success)
480        return rc;
481
482    pixmap->drawable.id = stuff->pixmap;
483
484    /* security creation/labeling check */
485    rc = XaceHook(XACE_RESOURCE_ACCESS, client, stuff->pixmap, RT_PIXMAP,
486                  pixmap, RT_NONE, NULL, DixCreateAccess);
487
488    if (rc != Success) {
489        (*screen->DestroyPixmap) (pixmap);
490        return rc;
491    }
492    if (!AddResource(stuff->pixmap, RT_PIXMAP, (void *) pixmap))
493        return BadAlloc;
494
495    return Success;
496}
497
498static int
499proc_dri3_buffers_from_pixmap(ClientPtr client)
500{
501    REQUEST(xDRI3BuffersFromPixmapReq);
502    xDRI3BuffersFromPixmapReply rep = {
503        .type = X_Reply,
504        .sequenceNumber = client->sequence,
505    };
506    int rc;
507    int fds[4];
508    int num_fds;
509    uint32_t strides[4], offsets[4];
510    uint64_t modifier;
511    int i;
512    PixmapPtr pixmap;
513
514    REQUEST_SIZE_MATCH(xDRI3BuffersFromPixmapReq);
515    rc = dixLookupResourceByType((void **) &pixmap, stuff->pixmap, RT_PIXMAP,
516                                 client, DixWriteAccess);
517    if (rc != Success) {
518        client->errorValue = stuff->pixmap;
519        return rc;
520    }
521
522    num_fds = dri3_fds_from_pixmap(pixmap, fds, strides, offsets, &modifier);
523    if (num_fds == 0)
524        return BadPixmap;
525
526    rep.nfd = num_fds;
527    rep.length = bytes_to_int32(num_fds * 2 * sizeof(CARD32));
528    rep.width = pixmap->drawable.width;
529    rep.height = pixmap->drawable.height;
530    rep.depth = pixmap->drawable.depth;
531    rep.bpp = pixmap->drawable.bitsPerPixel;
532    rep.modifier = modifier;
533
534    if (client->swapped) {
535        swaps(&rep.sequenceNumber);
536        swapl(&rep.length);
537        swaps(&rep.width);
538        swaps(&rep.height);
539        swapll(&rep.modifier);
540        for (i = 0; i < num_fds; i++) {
541            swapl(&strides[i]);
542            swapl(&offsets[i]);
543        }
544    }
545
546    for (i = 0; i < num_fds; i++) {
547        if (WriteFdToClient(client, fds[i], TRUE) < 0) {
548            while (i--)
549                close(fds[i]);
550            return BadAlloc;
551        }
552    }
553
554    WriteToClient(client, sizeof(rep), &rep);
555    WriteToClient(client, num_fds * sizeof(CARD32), strides);
556    WriteToClient(client, num_fds * sizeof(CARD32), offsets);
557
558    return Success;
559}
560
561int (*proc_dri3_vector[DRI3NumberRequests]) (ClientPtr) = {
562    proc_dri3_query_version,            /* 0 */
563    proc_dri3_open,                     /* 1 */
564    proc_dri3_pixmap_from_buffer,       /* 2 */
565    proc_dri3_buffer_from_pixmap,       /* 3 */
566    proc_dri3_fence_from_fd,            /* 4 */
567    proc_dri3_fd_from_fence,            /* 5 */
568    proc_dri3_get_supported_modifiers,  /* 6 */
569    proc_dri3_pixmap_from_buffers,      /* 7 */
570    proc_dri3_buffers_from_pixmap,      /* 8 */
571};
572
573int
574proc_dri3_dispatch(ClientPtr client)
575{
576    REQUEST(xReq);
577    if (!client->local)
578        return BadMatch;
579    if (stuff->data >= DRI3NumberRequests || !proc_dri3_vector[stuff->data])
580        return BadRequest;
581    return (*proc_dri3_vector[stuff->data]) (client);
582}
583
584static int _X_COLD
585sproc_dri3_query_version(ClientPtr client)
586{
587    REQUEST(xDRI3QueryVersionReq);
588    REQUEST_SIZE_MATCH(xDRI3QueryVersionReq);
589
590    swaps(&stuff->length);
591    swapl(&stuff->majorVersion);
592    swapl(&stuff->minorVersion);
593    return (*proc_dri3_vector[stuff->dri3ReqType]) (client);
594}
595
596static int _X_COLD
597sproc_dri3_open(ClientPtr client)
598{
599    REQUEST(xDRI3OpenReq);
600    REQUEST_SIZE_MATCH(xDRI3OpenReq);
601
602    swaps(&stuff->length);
603    swapl(&stuff->drawable);
604    swapl(&stuff->provider);
605    return (*proc_dri3_vector[stuff->dri3ReqType]) (client);
606}
607
608static int _X_COLD
609sproc_dri3_pixmap_from_buffer(ClientPtr client)
610{
611    REQUEST(xDRI3PixmapFromBufferReq);
612    REQUEST_SIZE_MATCH(xDRI3PixmapFromBufferReq);
613
614    swaps(&stuff->length);
615    swapl(&stuff->pixmap);
616    swapl(&stuff->drawable);
617    swapl(&stuff->size);
618    swaps(&stuff->width);
619    swaps(&stuff->height);
620    swaps(&stuff->stride);
621    return (*proc_dri3_vector[stuff->dri3ReqType]) (client);
622}
623
624static int _X_COLD
625sproc_dri3_buffer_from_pixmap(ClientPtr client)
626{
627    REQUEST(xDRI3BufferFromPixmapReq);
628    REQUEST_SIZE_MATCH(xDRI3BufferFromPixmapReq);
629
630    swaps(&stuff->length);
631    swapl(&stuff->pixmap);
632    return (*proc_dri3_vector[stuff->dri3ReqType]) (client);
633}
634
635static int _X_COLD
636sproc_dri3_fence_from_fd(ClientPtr client)
637{
638    REQUEST(xDRI3FenceFromFDReq);
639    REQUEST_SIZE_MATCH(xDRI3FenceFromFDReq);
640
641    swaps(&stuff->length);
642    swapl(&stuff->drawable);
643    swapl(&stuff->fence);
644    return (*proc_dri3_vector[stuff->dri3ReqType]) (client);
645}
646
647static int _X_COLD
648sproc_dri3_fd_from_fence(ClientPtr client)
649{
650    REQUEST(xDRI3FDFromFenceReq);
651    REQUEST_SIZE_MATCH(xDRI3FDFromFenceReq);
652
653    swaps(&stuff->length);
654    swapl(&stuff->drawable);
655    swapl(&stuff->fence);
656    return (*proc_dri3_vector[stuff->dri3ReqType]) (client);
657}
658
659static int _X_COLD
660sproc_dri3_get_supported_modifiers(ClientPtr client)
661{
662    REQUEST(xDRI3GetSupportedModifiersReq);
663    REQUEST_SIZE_MATCH(xDRI3GetSupportedModifiersReq);
664
665    swaps(&stuff->length);
666    swapl(&stuff->window);
667    return (*proc_dri3_vector[stuff->dri3ReqType]) (client);
668}
669
670static int _X_COLD
671sproc_dri3_pixmap_from_buffers(ClientPtr client)
672{
673    REQUEST(xDRI3PixmapFromBuffersReq);
674    REQUEST_SIZE_MATCH(xDRI3PixmapFromBuffersReq);
675
676    swaps(&stuff->length);
677    swapl(&stuff->pixmap);
678    swapl(&stuff->window);
679    swaps(&stuff->width);
680    swaps(&stuff->height);
681    swapl(&stuff->stride0);
682    swapl(&stuff->offset0);
683    swapl(&stuff->stride1);
684    swapl(&stuff->offset1);
685    swapl(&stuff->stride2);
686    swapl(&stuff->offset2);
687    swapl(&stuff->stride3);
688    swapl(&stuff->offset3);
689    swapll(&stuff->modifier);
690    return (*proc_dri3_vector[stuff->dri3ReqType]) (client);
691}
692
693static int _X_COLD
694sproc_dri3_buffers_from_pixmap(ClientPtr client)
695{
696    REQUEST(xDRI3BuffersFromPixmapReq);
697    REQUEST_SIZE_MATCH(xDRI3BuffersFromPixmapReq);
698
699    swaps(&stuff->length);
700    swapl(&stuff->pixmap);
701    return (*proc_dri3_vector[stuff->dri3ReqType]) (client);
702}
703
704int (*sproc_dri3_vector[DRI3NumberRequests]) (ClientPtr) = {
705    sproc_dri3_query_version,           /* 0 */
706    sproc_dri3_open,                    /* 1 */
707    sproc_dri3_pixmap_from_buffer,      /* 2 */
708    sproc_dri3_buffer_from_pixmap,      /* 3 */
709    sproc_dri3_fence_from_fd,           /* 4 */
710    sproc_dri3_fd_from_fence,           /* 5 */
711    sproc_dri3_get_supported_modifiers, /* 6 */
712    sproc_dri3_pixmap_from_buffers,     /* 7 */
713    sproc_dri3_buffers_from_pixmap,     /* 8 */
714};
715
716int _X_COLD
717sproc_dri3_dispatch(ClientPtr client)
718{
719    REQUEST(xReq);
720    if (!client->local)
721        return BadMatch;
722    if (stuff->data >= DRI3NumberRequests || !sproc_dri3_vector[stuff->data])
723        return BadRequest;
724    return (*sproc_dri3_vector[stuff->data]) (client);
725}
726