135c4bbdfSmrg/*
235c4bbdfSmrg * Copyright © 2013 Keith Packard
335c4bbdfSmrg *
435c4bbdfSmrg * Permission to use, copy, modify, distribute, and sell this software and its
535c4bbdfSmrg * documentation for any purpose is hereby granted without fee, provided that
635c4bbdfSmrg * the above copyright notice appear in all copies and that both that copyright
735c4bbdfSmrg * notice and this permission notice appear in supporting documentation, and
835c4bbdfSmrg * that the name of the copyright holders not be used in advertising or
935c4bbdfSmrg * publicity pertaining to distribution of the software without specific,
1035c4bbdfSmrg * written prior permission.  The copyright holders make no representations
1135c4bbdfSmrg * about the suitability of this software for any purpose.  It is provided "as
1235c4bbdfSmrg * is" without express or implied warranty.
1335c4bbdfSmrg *
1435c4bbdfSmrg * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1535c4bbdfSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
1635c4bbdfSmrg * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
1735c4bbdfSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
1835c4bbdfSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
1935c4bbdfSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
2035c4bbdfSmrg * OF THIS SOFTWARE.
2135c4bbdfSmrg */
2235c4bbdfSmrg
2335c4bbdfSmrg#include "dri3_priv.h"
2435c4bbdfSmrg#include <syncsrv.h>
2535c4bbdfSmrg#include <unistd.h>
2635c4bbdfSmrg#include <xace.h>
2735c4bbdfSmrg#include "../Xext/syncsdk.h"
2835c4bbdfSmrg#include <protocol-versions.h>
291b5d61b8Smrg#include <drm_fourcc.h>
301b5d61b8Smrg
311b5d61b8Smrgstatic Bool
321b5d61b8Smrgdri3_screen_can_one_point_two(ScreenPtr screen)
331b5d61b8Smrg{
341b5d61b8Smrg    dri3_screen_priv_ptr dri3 = dri3_screen_priv(screen);
351b5d61b8Smrg
361b5d61b8Smrg    if (dri3 && dri3->info && dri3->info->version >= 2 &&
371b5d61b8Smrg        dri3->info->pixmap_from_fds && dri3->info->fds_from_pixmap &&
381b5d61b8Smrg        dri3->info->get_formats && dri3->info->get_modifiers &&
391b5d61b8Smrg        dri3->info->get_drawable_modifiers)
401b5d61b8Smrg        return TRUE;
411b5d61b8Smrg
421b5d61b8Smrg    return FALSE;
431b5d61b8Smrg}
4435c4bbdfSmrg
4535c4bbdfSmrgstatic int
4635c4bbdfSmrgproc_dri3_query_version(ClientPtr client)
4735c4bbdfSmrg{
4835c4bbdfSmrg    REQUEST(xDRI3QueryVersionReq);
4935c4bbdfSmrg    xDRI3QueryVersionReply rep = {
5035c4bbdfSmrg        .type = X_Reply,
5135c4bbdfSmrg        .sequenceNumber = client->sequence,
5235c4bbdfSmrg        .length = 0,
5335c4bbdfSmrg        .majorVersion = SERVER_DRI3_MAJOR_VERSION,
5435c4bbdfSmrg        .minorVersion = SERVER_DRI3_MINOR_VERSION
5535c4bbdfSmrg    };
5635c4bbdfSmrg
5735c4bbdfSmrg    REQUEST_SIZE_MATCH(xDRI3QueryVersionReq);
581b5d61b8Smrg
591b5d61b8Smrg    for (int i = 0; i < screenInfo.numScreens; i++) {
601b5d61b8Smrg        if (!dri3_screen_can_one_point_two(screenInfo.screens[i])) {
611b5d61b8Smrg            rep.minorVersion = 0;
621b5d61b8Smrg            break;
631b5d61b8Smrg        }
641b5d61b8Smrg    }
651b5d61b8Smrg
661b5d61b8Smrg    for (int i = 0; i < screenInfo.numGPUScreens; i++) {
671b5d61b8Smrg        if (!dri3_screen_can_one_point_two(screenInfo.gpuscreens[i])) {
681b5d61b8Smrg            rep.minorVersion = 0;
691b5d61b8Smrg            break;
701b5d61b8Smrg        }
711b5d61b8Smrg    }
721b5d61b8Smrg
731b5d61b8Smrg    /* From DRI3 proto:
741b5d61b8Smrg     *
751b5d61b8Smrg     * The client sends the highest supported version to the server
761b5d61b8Smrg     * and the server sends the highest version it supports, but no
771b5d61b8Smrg     * higher than the requested version.
781b5d61b8Smrg     */
791b5d61b8Smrg
801b5d61b8Smrg    if (rep.majorVersion > stuff->majorVersion ||
811b5d61b8Smrg        (rep.majorVersion == stuff->majorVersion &&
821b5d61b8Smrg         rep.minorVersion > stuff->minorVersion)) {
831b5d61b8Smrg        rep.majorVersion = stuff->majorVersion;
841b5d61b8Smrg        rep.minorVersion = stuff->minorVersion;
851b5d61b8Smrg    }
861b5d61b8Smrg
8735c4bbdfSmrg    if (client->swapped) {
8835c4bbdfSmrg        swaps(&rep.sequenceNumber);
8935c4bbdfSmrg        swapl(&rep.length);
9035c4bbdfSmrg        swapl(&rep.majorVersion);
9135c4bbdfSmrg        swapl(&rep.minorVersion);
9235c4bbdfSmrg    }
9335c4bbdfSmrg    WriteToClient(client, sizeof(rep), &rep);
9435c4bbdfSmrg    return Success;
9535c4bbdfSmrg}
9635c4bbdfSmrg
9735c4bbdfSmrgint
9835c4bbdfSmrgdri3_send_open_reply(ClientPtr client, int fd)
9935c4bbdfSmrg{
10035c4bbdfSmrg    xDRI3OpenReply rep = {
10135c4bbdfSmrg        .type = X_Reply,
10235c4bbdfSmrg        .nfd = 1,
10335c4bbdfSmrg        .sequenceNumber = client->sequence,
10435c4bbdfSmrg        .length = 0,
10535c4bbdfSmrg    };
10635c4bbdfSmrg
10735c4bbdfSmrg    if (client->swapped) {
10835c4bbdfSmrg        swaps(&rep.sequenceNumber);
10935c4bbdfSmrg        swapl(&rep.length);
11035c4bbdfSmrg    }
11135c4bbdfSmrg
11235c4bbdfSmrg    if (WriteFdToClient(client, fd, TRUE) < 0) {
11335c4bbdfSmrg        close(fd);
11435c4bbdfSmrg        return BadAlloc;
11535c4bbdfSmrg    }
11635c4bbdfSmrg
11735c4bbdfSmrg    WriteToClient(client, sizeof (rep), &rep);
11835c4bbdfSmrg
11935c4bbdfSmrg    return Success;
12035c4bbdfSmrg}
12135c4bbdfSmrg
12235c4bbdfSmrgstatic int
12335c4bbdfSmrgproc_dri3_open(ClientPtr client)
12435c4bbdfSmrg{
12535c4bbdfSmrg    REQUEST(xDRI3OpenReq);
12635c4bbdfSmrg    RRProviderPtr provider;
12735c4bbdfSmrg    DrawablePtr drawable;
12835c4bbdfSmrg    ScreenPtr screen;
12935c4bbdfSmrg    int fd;
13035c4bbdfSmrg    int status;
13135c4bbdfSmrg
13235c4bbdfSmrg    REQUEST_SIZE_MATCH(xDRI3OpenReq);
13335c4bbdfSmrg
134e23ec014Smrg    status = dixLookupDrawable(&drawable, stuff->drawable, client, 0, DixGetAttrAccess);
13535c4bbdfSmrg    if (status != Success)
13635c4bbdfSmrg        return status;
13735c4bbdfSmrg
13835c4bbdfSmrg    if (stuff->provider == None)
13935c4bbdfSmrg        provider = NULL;
14035c4bbdfSmrg    else if (!RRProviderType) {
14135c4bbdfSmrg        return BadMatch;
14235c4bbdfSmrg    } else {
14335c4bbdfSmrg        VERIFY_RR_PROVIDER(stuff->provider, provider, DixReadAccess);
14435c4bbdfSmrg        if (drawable->pScreen != provider->pScreen)
14535c4bbdfSmrg            return BadMatch;
14635c4bbdfSmrg    }
14735c4bbdfSmrg    screen = drawable->pScreen;
14835c4bbdfSmrg
14935c4bbdfSmrg    status = dri3_open(client, screen, provider, &fd);
15035c4bbdfSmrg    if (status != Success)
15135c4bbdfSmrg        return status;
15235c4bbdfSmrg
15335c4bbdfSmrg    if (client->ignoreCount == 0)
15435c4bbdfSmrg        return dri3_send_open_reply(client, fd);
15535c4bbdfSmrg
15635c4bbdfSmrg    return Success;
15735c4bbdfSmrg}
15835c4bbdfSmrg
15935c4bbdfSmrgstatic int
16035c4bbdfSmrgproc_dri3_pixmap_from_buffer(ClientPtr client)
16135c4bbdfSmrg{
16235c4bbdfSmrg    REQUEST(xDRI3PixmapFromBufferReq);
16335c4bbdfSmrg    int fd;
16435c4bbdfSmrg    DrawablePtr drawable;
16535c4bbdfSmrg    PixmapPtr pixmap;
1661b5d61b8Smrg    CARD32 stride, offset;
16735c4bbdfSmrg    int rc;
16835c4bbdfSmrg
16935c4bbdfSmrg    SetReqFds(client, 1);
17035c4bbdfSmrg    REQUEST_SIZE_MATCH(xDRI3PixmapFromBufferReq);
17135c4bbdfSmrg    LEGAL_NEW_RESOURCE(stuff->pixmap, client);
17235c4bbdfSmrg    rc = dixLookupDrawable(&drawable, stuff->drawable, client, M_ANY, DixGetAttrAccess);
17335c4bbdfSmrg    if (rc != Success) {
17435c4bbdfSmrg        client->errorValue = stuff->drawable;
17535c4bbdfSmrg        return rc;
17635c4bbdfSmrg    }
17735c4bbdfSmrg
17835c4bbdfSmrg    if (!stuff->width || !stuff->height) {
17935c4bbdfSmrg        client->errorValue = 0;
18035c4bbdfSmrg        return BadValue;
18135c4bbdfSmrg    }
18235c4bbdfSmrg
18335c4bbdfSmrg    if (stuff->width > 32767 || stuff->height > 32767)
18435c4bbdfSmrg        return BadAlloc;
18535c4bbdfSmrg
18635c4bbdfSmrg    if (stuff->depth != 1) {
18735c4bbdfSmrg        DepthPtr depth = drawable->pScreen->allowedDepths;
18835c4bbdfSmrg        int i;
18935c4bbdfSmrg        for (i = 0; i < drawable->pScreen->numDepths; i++, depth++)
19035c4bbdfSmrg            if (depth->depth == stuff->depth)
19135c4bbdfSmrg                break;
19235c4bbdfSmrg        if (i == drawable->pScreen->numDepths) {
19335c4bbdfSmrg            client->errorValue = stuff->depth;
19435c4bbdfSmrg            return BadValue;
19535c4bbdfSmrg        }
19635c4bbdfSmrg    }
19735c4bbdfSmrg
19835c4bbdfSmrg    fd = ReadFdFromClient(client);
19935c4bbdfSmrg    if (fd < 0)
20035c4bbdfSmrg        return BadValue;
20135c4bbdfSmrg
2021b5d61b8Smrg    offset = 0;
2031b5d61b8Smrg    stride = stuff->stride;
2041b5d61b8Smrg    rc = dri3_pixmap_from_fds(&pixmap,
2051b5d61b8Smrg                              drawable->pScreen, 1, &fd,
2061b5d61b8Smrg                              stuff->width, stuff->height,
2071b5d61b8Smrg                              &stride, &offset,
2081b5d61b8Smrg                              stuff->depth, stuff->bpp,
2091b5d61b8Smrg                              DRM_FORMAT_MOD_INVALID);
21035c4bbdfSmrg    close (fd);
21135c4bbdfSmrg    if (rc != Success)
21235c4bbdfSmrg        return rc;
21335c4bbdfSmrg
21435c4bbdfSmrg    pixmap->drawable.id = stuff->pixmap;
21535c4bbdfSmrg
21635c4bbdfSmrg    /* security creation/labeling check */
21735c4bbdfSmrg    rc = XaceHook(XACE_RESOURCE_ACCESS, client, stuff->pixmap, RT_PIXMAP,
21835c4bbdfSmrg                  pixmap, RT_NONE, NULL, DixCreateAccess);
21935c4bbdfSmrg
22035c4bbdfSmrg    if (rc != Success) {
22135c4bbdfSmrg        (*drawable->pScreen->DestroyPixmap) (pixmap);
22235c4bbdfSmrg        return rc;
22335c4bbdfSmrg    }
2241b5d61b8Smrg    if (!AddResource(stuff->pixmap, RT_PIXMAP, (void *) pixmap))
2251b5d61b8Smrg        return BadAlloc;
22635c4bbdfSmrg
22735c4bbdfSmrg    return Success;
22835c4bbdfSmrg}
22935c4bbdfSmrg
23035c4bbdfSmrgstatic int
23135c4bbdfSmrgproc_dri3_buffer_from_pixmap(ClientPtr client)
23235c4bbdfSmrg{
23335c4bbdfSmrg    REQUEST(xDRI3BufferFromPixmapReq);
23435c4bbdfSmrg    xDRI3BufferFromPixmapReply rep = {
23535c4bbdfSmrg        .type = X_Reply,
23635c4bbdfSmrg        .nfd = 1,
23735c4bbdfSmrg        .sequenceNumber = client->sequence,
23835c4bbdfSmrg        .length = 0,
23935c4bbdfSmrg    };
24035c4bbdfSmrg    int rc;
24135c4bbdfSmrg    int fd;
24235c4bbdfSmrg    PixmapPtr pixmap;
24335c4bbdfSmrg
24435c4bbdfSmrg    REQUEST_SIZE_MATCH(xDRI3BufferFromPixmapReq);
24535c4bbdfSmrg    rc = dixLookupResourceByType((void **) &pixmap, stuff->pixmap, RT_PIXMAP,
24635c4bbdfSmrg                                 client, DixWriteAccess);
24735c4bbdfSmrg    if (rc != Success) {
24835c4bbdfSmrg        client->errorValue = stuff->pixmap;
24935c4bbdfSmrg        return rc;
25035c4bbdfSmrg    }
25135c4bbdfSmrg
25235c4bbdfSmrg    rep.width = pixmap->drawable.width;
25335c4bbdfSmrg    rep.height = pixmap->drawable.height;
25435c4bbdfSmrg    rep.depth = pixmap->drawable.depth;
25535c4bbdfSmrg    rep.bpp = pixmap->drawable.bitsPerPixel;
25635c4bbdfSmrg
2571b5d61b8Smrg    fd = dri3_fd_from_pixmap(pixmap, &rep.stride, &rep.size);
2581b5d61b8Smrg    if (fd < 0)
2591b5d61b8Smrg        return BadPixmap;
26035c4bbdfSmrg
26135c4bbdfSmrg    if (client->swapped) {
26235c4bbdfSmrg        swaps(&rep.sequenceNumber);
26335c4bbdfSmrg        swapl(&rep.length);
26435c4bbdfSmrg        swapl(&rep.size);
26535c4bbdfSmrg        swaps(&rep.width);
26635c4bbdfSmrg        swaps(&rep.height);
26735c4bbdfSmrg        swaps(&rep.stride);
26835c4bbdfSmrg    }
26935c4bbdfSmrg    if (WriteFdToClient(client, fd, TRUE) < 0) {
27035c4bbdfSmrg        close(fd);
27135c4bbdfSmrg        return BadAlloc;
27235c4bbdfSmrg    }
27335c4bbdfSmrg
27435c4bbdfSmrg    WriteToClient(client, sizeof(rep), &rep);
27535c4bbdfSmrg
2761b5d61b8Smrg    return Success;
27735c4bbdfSmrg}
27835c4bbdfSmrg
27935c4bbdfSmrgstatic int
28035c4bbdfSmrgproc_dri3_fence_from_fd(ClientPtr client)
28135c4bbdfSmrg{
28235c4bbdfSmrg    REQUEST(xDRI3FenceFromFDReq);
28335c4bbdfSmrg    DrawablePtr drawable;
28435c4bbdfSmrg    int fd;
28535c4bbdfSmrg    int status;
28635c4bbdfSmrg
28735c4bbdfSmrg    SetReqFds(client, 1);
28835c4bbdfSmrg    REQUEST_SIZE_MATCH(xDRI3FenceFromFDReq);
28935c4bbdfSmrg    LEGAL_NEW_RESOURCE(stuff->fence, client);
29035c4bbdfSmrg
29135c4bbdfSmrg    status = dixLookupDrawable(&drawable, stuff->drawable, client, M_ANY, DixGetAttrAccess);
29235c4bbdfSmrg    if (status != Success)
29335c4bbdfSmrg        return status;
29435c4bbdfSmrg
29535c4bbdfSmrg    fd = ReadFdFromClient(client);
29635c4bbdfSmrg    if (fd < 0)
29735c4bbdfSmrg        return BadValue;
29835c4bbdfSmrg
29935c4bbdfSmrg    status = SyncCreateFenceFromFD(client, drawable, stuff->fence,
30035c4bbdfSmrg                                   fd, stuff->initially_triggered);
30135c4bbdfSmrg
30235c4bbdfSmrg    return status;
30335c4bbdfSmrg}
30435c4bbdfSmrg
30535c4bbdfSmrgstatic int
30635c4bbdfSmrgproc_dri3_fd_from_fence(ClientPtr client)
30735c4bbdfSmrg{
30835c4bbdfSmrg    REQUEST(xDRI3FDFromFenceReq);
30935c4bbdfSmrg    xDRI3FDFromFenceReply rep = {
31035c4bbdfSmrg        .type = X_Reply,
31135c4bbdfSmrg        .nfd = 1,
31235c4bbdfSmrg        .sequenceNumber = client->sequence,
31335c4bbdfSmrg        .length = 0,
31435c4bbdfSmrg    };
31535c4bbdfSmrg    DrawablePtr drawable;
31635c4bbdfSmrg    int fd;
31735c4bbdfSmrg    int status;
31835c4bbdfSmrg    SyncFence *fence;
31935c4bbdfSmrg
32035c4bbdfSmrg    REQUEST_SIZE_MATCH(xDRI3FDFromFenceReq);
32135c4bbdfSmrg
32235c4bbdfSmrg    status = dixLookupDrawable(&drawable, stuff->drawable, client, M_ANY, DixGetAttrAccess);
32335c4bbdfSmrg    if (status != Success)
32435c4bbdfSmrg        return status;
32535c4bbdfSmrg    status = SyncVerifyFence(&fence, stuff->fence, client, DixWriteAccess);
32635c4bbdfSmrg    if (status != Success)
32735c4bbdfSmrg        return status;
32835c4bbdfSmrg
32935c4bbdfSmrg    fd = SyncFDFromFence(client, drawable, fence);
33035c4bbdfSmrg    if (fd < 0)
33135c4bbdfSmrg        return BadMatch;
33235c4bbdfSmrg
33335c4bbdfSmrg    if (client->swapped) {
33435c4bbdfSmrg        swaps(&rep.sequenceNumber);
33535c4bbdfSmrg        swapl(&rep.length);
33635c4bbdfSmrg    }
33735c4bbdfSmrg    if (WriteFdToClient(client, fd, FALSE) < 0)
33835c4bbdfSmrg        return BadAlloc;
33935c4bbdfSmrg
34035c4bbdfSmrg    WriteToClient(client, sizeof(rep), &rep);
34135c4bbdfSmrg
3421b5d61b8Smrg    return Success;
3431b5d61b8Smrg}
3441b5d61b8Smrg
3451b5d61b8Smrgstatic int
3461b5d61b8Smrgproc_dri3_get_supported_modifiers(ClientPtr client)
3471b5d61b8Smrg{
3481b5d61b8Smrg    REQUEST(xDRI3GetSupportedModifiersReq);
3491b5d61b8Smrg    xDRI3GetSupportedModifiersReply rep = {
3501b5d61b8Smrg        .type = X_Reply,
3511b5d61b8Smrg        .sequenceNumber = client->sequence,
3521b5d61b8Smrg    };
3531b5d61b8Smrg    WindowPtr window;
3541b5d61b8Smrg    ScreenPtr pScreen;
3551b5d61b8Smrg    CARD64 *window_modifiers = NULL;
3561b5d61b8Smrg    CARD64 *screen_modifiers = NULL;
3571b5d61b8Smrg    CARD32 nwindowmodifiers = 0;
3581b5d61b8Smrg    CARD32 nscreenmodifiers = 0;
3591b5d61b8Smrg    int status;
3601b5d61b8Smrg    int i;
3611b5d61b8Smrg
3621b5d61b8Smrg    REQUEST_SIZE_MATCH(xDRI3GetSupportedModifiersReq);
3631b5d61b8Smrg
364e23ec014Smrg    status = dixLookupWindow(&window, stuff->window, client, DixGetAttrAccess);
3651b5d61b8Smrg    if (status != Success)
3661b5d61b8Smrg        return status;
3671b5d61b8Smrg    pScreen = window->drawable.pScreen;
3681b5d61b8Smrg
3691b5d61b8Smrg    dri3_get_supported_modifiers(pScreen, &window->drawable,
3701b5d61b8Smrg				 stuff->depth, stuff->bpp,
3711b5d61b8Smrg                                 &nwindowmodifiers, &window_modifiers,
3721b5d61b8Smrg                                 &nscreenmodifiers, &screen_modifiers);
3731b5d61b8Smrg
3741b5d61b8Smrg    rep.numWindowModifiers = nwindowmodifiers;
3751b5d61b8Smrg    rep.numScreenModifiers = nscreenmodifiers;
3761b5d61b8Smrg    rep.length = bytes_to_int32(rep.numWindowModifiers * sizeof(CARD64)) +
3771b5d61b8Smrg                 bytes_to_int32(rep.numScreenModifiers * sizeof(CARD64));
3781b5d61b8Smrg
3791b5d61b8Smrg    if (client->swapped) {
3801b5d61b8Smrg        swaps(&rep.sequenceNumber);
3811b5d61b8Smrg        swapl(&rep.length);
3821b5d61b8Smrg        swapl(&rep.numWindowModifiers);
3831b5d61b8Smrg        swapl(&rep.numScreenModifiers);
3841b5d61b8Smrg        for (i = 0; i < nwindowmodifiers; i++)
3851b5d61b8Smrg            swapll(&window_modifiers[i]);
3861b5d61b8Smrg        for (i = 0; i < nscreenmodifiers; i++)
3871b5d61b8Smrg            swapll(&screen_modifiers[i]);
3881b5d61b8Smrg    }
3891b5d61b8Smrg
3901b5d61b8Smrg    WriteToClient(client, sizeof(rep), &rep);
3911b5d61b8Smrg    WriteToClient(client, nwindowmodifiers * sizeof(CARD64), window_modifiers);
3921b5d61b8Smrg    WriteToClient(client, nscreenmodifiers * sizeof(CARD64), screen_modifiers);
3931b5d61b8Smrg
3941b5d61b8Smrg    free(window_modifiers);
3951b5d61b8Smrg    free(screen_modifiers);
3961b5d61b8Smrg
3971b5d61b8Smrg    return Success;
3981b5d61b8Smrg}
3991b5d61b8Smrg
4001b5d61b8Smrgstatic int
4011b5d61b8Smrgproc_dri3_pixmap_from_buffers(ClientPtr client)
4021b5d61b8Smrg{
4031b5d61b8Smrg    REQUEST(xDRI3PixmapFromBuffersReq);
4041b5d61b8Smrg    int fds[4];
4051b5d61b8Smrg    CARD32 strides[4], offsets[4];
4061b5d61b8Smrg    ScreenPtr screen;
4071b5d61b8Smrg    WindowPtr window;
4081b5d61b8Smrg    PixmapPtr pixmap;
4091b5d61b8Smrg    int rc;
4101b5d61b8Smrg    int i;
4111b5d61b8Smrg
4121b5d61b8Smrg    SetReqFds(client, stuff->num_buffers);
4131b5d61b8Smrg    REQUEST_SIZE_MATCH(xDRI3PixmapFromBuffersReq);
4141b5d61b8Smrg    LEGAL_NEW_RESOURCE(stuff->pixmap, client);
4151b5d61b8Smrg    rc = dixLookupWindow(&window, stuff->window, client, DixGetAttrAccess);
4161b5d61b8Smrg    if (rc != Success) {
4171b5d61b8Smrg        client->errorValue = stuff->window;
4181b5d61b8Smrg        return rc;
4191b5d61b8Smrg    }
4201b5d61b8Smrg    screen = window->drawable.pScreen;
4211b5d61b8Smrg
4221b5d61b8Smrg    if (!stuff->width || !stuff->height || !stuff->bpp || !stuff->depth) {
4231b5d61b8Smrg        client->errorValue = 0;
4241b5d61b8Smrg        return BadValue;
4251b5d61b8Smrg    }
4261b5d61b8Smrg
4271b5d61b8Smrg    if (stuff->width > 32767 || stuff->height > 32767)
4281b5d61b8Smrg        return BadAlloc;
4291b5d61b8Smrg
4301b5d61b8Smrg    if (stuff->depth != 1) {
4311b5d61b8Smrg        DepthPtr depth = screen->allowedDepths;
4321b5d61b8Smrg        int j;
4331b5d61b8Smrg        for (j = 0; j < screen->numDepths; j++, depth++)
4341b5d61b8Smrg            if (depth->depth == stuff->depth)
4351b5d61b8Smrg                break;
4361b5d61b8Smrg        if (j == screen->numDepths) {
4371b5d61b8Smrg            client->errorValue = stuff->depth;
4381b5d61b8Smrg            return BadValue;
4391b5d61b8Smrg        }
4401b5d61b8Smrg    }
4411b5d61b8Smrg
4421b5d61b8Smrg    if (!stuff->num_buffers || stuff->num_buffers > 4) {
4431b5d61b8Smrg        client->errorValue = stuff->num_buffers;
4441b5d61b8Smrg        return BadValue;
4451b5d61b8Smrg    }
4461b5d61b8Smrg
4471b5d61b8Smrg    for (i = 0; i < stuff->num_buffers; i++) {
4481b5d61b8Smrg        fds[i] = ReadFdFromClient(client);
4491b5d61b8Smrg        if (fds[i] < 0) {
4501b5d61b8Smrg            while (--i >= 0)
4511b5d61b8Smrg                close(fds[i]);
4521b5d61b8Smrg            return BadValue;
4531b5d61b8Smrg        }
4541b5d61b8Smrg    }
4551b5d61b8Smrg
4561b5d61b8Smrg    strides[0] = stuff->stride0;
4571b5d61b8Smrg    strides[1] = stuff->stride1;
4581b5d61b8Smrg    strides[2] = stuff->stride2;
4591b5d61b8Smrg    strides[3] = stuff->stride3;
4601b5d61b8Smrg    offsets[0] = stuff->offset0;
4611b5d61b8Smrg    offsets[1] = stuff->offset1;
4621b5d61b8Smrg    offsets[2] = stuff->offset2;
4631b5d61b8Smrg    offsets[3] = stuff->offset3;
4641b5d61b8Smrg
4651b5d61b8Smrg    rc = dri3_pixmap_from_fds(&pixmap, screen,
4661b5d61b8Smrg                              stuff->num_buffers, fds,
4671b5d61b8Smrg                              stuff->width, stuff->height,
4681b5d61b8Smrg                              strides, offsets,
4691b5d61b8Smrg                              stuff->depth, stuff->bpp,
4701b5d61b8Smrg                              stuff->modifier);
4711b5d61b8Smrg
4721b5d61b8Smrg    for (i = 0; i < stuff->num_buffers; i++)
4731b5d61b8Smrg        close (fds[i]);
4741b5d61b8Smrg
4751b5d61b8Smrg    if (rc != Success)
4761b5d61b8Smrg        return rc;
4771b5d61b8Smrg
4781b5d61b8Smrg    pixmap->drawable.id = stuff->pixmap;
4791b5d61b8Smrg
4801b5d61b8Smrg    /* security creation/labeling check */
4811b5d61b8Smrg    rc = XaceHook(XACE_RESOURCE_ACCESS, client, stuff->pixmap, RT_PIXMAP,
4821b5d61b8Smrg                  pixmap, RT_NONE, NULL, DixCreateAccess);
4831b5d61b8Smrg
4841b5d61b8Smrg    if (rc != Success) {
4851b5d61b8Smrg        (*screen->DestroyPixmap) (pixmap);
4861b5d61b8Smrg        return rc;
4871b5d61b8Smrg    }
4881b5d61b8Smrg    if (!AddResource(stuff->pixmap, RT_PIXMAP, (void *) pixmap))
4891b5d61b8Smrg        return BadAlloc;
4901b5d61b8Smrg
4911b5d61b8Smrg    return Success;
4921b5d61b8Smrg}
4931b5d61b8Smrg
4941b5d61b8Smrgstatic int
4951b5d61b8Smrgproc_dri3_buffers_from_pixmap(ClientPtr client)
4961b5d61b8Smrg{
4971b5d61b8Smrg    REQUEST(xDRI3BuffersFromPixmapReq);
4981b5d61b8Smrg    xDRI3BuffersFromPixmapReply rep = {
4991b5d61b8Smrg        .type = X_Reply,
5001b5d61b8Smrg        .sequenceNumber = client->sequence,
5011b5d61b8Smrg    };
5021b5d61b8Smrg    int rc;
5031b5d61b8Smrg    int fds[4];
5041b5d61b8Smrg    int num_fds;
5051b5d61b8Smrg    uint32_t strides[4], offsets[4];
5061b5d61b8Smrg    uint64_t modifier;
5071b5d61b8Smrg    int i;
5081b5d61b8Smrg    PixmapPtr pixmap;
5091b5d61b8Smrg
5101b5d61b8Smrg    REQUEST_SIZE_MATCH(xDRI3BuffersFromPixmapReq);
5111b5d61b8Smrg    rc = dixLookupResourceByType((void **) &pixmap, stuff->pixmap, RT_PIXMAP,
5121b5d61b8Smrg                                 client, DixWriteAccess);
5131b5d61b8Smrg    if (rc != Success) {
5141b5d61b8Smrg        client->errorValue = stuff->pixmap;
5151b5d61b8Smrg        return rc;
5161b5d61b8Smrg    }
5171b5d61b8Smrg
5181b5d61b8Smrg    num_fds = dri3_fds_from_pixmap(pixmap, fds, strides, offsets, &modifier);
5191b5d61b8Smrg    if (num_fds == 0)
5201b5d61b8Smrg        return BadPixmap;
5211b5d61b8Smrg
5221b5d61b8Smrg    rep.nfd = num_fds;
5231b5d61b8Smrg    rep.length = bytes_to_int32(num_fds * 2 * sizeof(CARD32));
5241b5d61b8Smrg    rep.width = pixmap->drawable.width;
5251b5d61b8Smrg    rep.height = pixmap->drawable.height;
5261b5d61b8Smrg    rep.depth = pixmap->drawable.depth;
5271b5d61b8Smrg    rep.bpp = pixmap->drawable.bitsPerPixel;
5281b5d61b8Smrg    rep.modifier = modifier;
5291b5d61b8Smrg
5301b5d61b8Smrg    if (client->swapped) {
5311b5d61b8Smrg        swaps(&rep.sequenceNumber);
5321b5d61b8Smrg        swapl(&rep.length);
5331b5d61b8Smrg        swaps(&rep.width);
5341b5d61b8Smrg        swaps(&rep.height);
5351b5d61b8Smrg        swapll(&rep.modifier);
5361b5d61b8Smrg        for (i = 0; i < num_fds; i++) {
5371b5d61b8Smrg            swapl(&strides[i]);
5381b5d61b8Smrg            swapl(&offsets[i]);
5391b5d61b8Smrg        }
5401b5d61b8Smrg    }
5411b5d61b8Smrg
5421b5d61b8Smrg    for (i = 0; i < num_fds; i++) {
5431b5d61b8Smrg        if (WriteFdToClient(client, fds[i], TRUE) < 0) {
5441b5d61b8Smrg            while (i--)
5451b5d61b8Smrg                close(fds[i]);
5461b5d61b8Smrg            return BadAlloc;
5471b5d61b8Smrg        }
5481b5d61b8Smrg    }
5491b5d61b8Smrg
5501b5d61b8Smrg    WriteToClient(client, sizeof(rep), &rep);
5511b5d61b8Smrg    WriteToClient(client, num_fds * sizeof(CARD32), strides);
5521b5d61b8Smrg    WriteToClient(client, num_fds * sizeof(CARD32), offsets);
5531b5d61b8Smrg
5541b5d61b8Smrg    return Success;
55535c4bbdfSmrg}
55635c4bbdfSmrg
55735c4bbdfSmrgint (*proc_dri3_vector[DRI3NumberRequests]) (ClientPtr) = {
55835c4bbdfSmrg    proc_dri3_query_version,            /* 0 */
55935c4bbdfSmrg    proc_dri3_open,                     /* 1 */
56035c4bbdfSmrg    proc_dri3_pixmap_from_buffer,       /* 2 */
56135c4bbdfSmrg    proc_dri3_buffer_from_pixmap,       /* 3 */
56235c4bbdfSmrg    proc_dri3_fence_from_fd,            /* 4 */
56335c4bbdfSmrg    proc_dri3_fd_from_fence,            /* 5 */
5641b5d61b8Smrg    proc_dri3_get_supported_modifiers,  /* 6 */
5651b5d61b8Smrg    proc_dri3_pixmap_from_buffers,      /* 7 */
5661b5d61b8Smrg    proc_dri3_buffers_from_pixmap,      /* 8 */
56735c4bbdfSmrg};
56835c4bbdfSmrg
56935c4bbdfSmrgint
57035c4bbdfSmrgproc_dri3_dispatch(ClientPtr client)
57135c4bbdfSmrg{
57235c4bbdfSmrg    REQUEST(xReq);
57335c4bbdfSmrg    if (!client->local)
57435c4bbdfSmrg        return BadMatch;
57535c4bbdfSmrg    if (stuff->data >= DRI3NumberRequests || !proc_dri3_vector[stuff->data])
57635c4bbdfSmrg        return BadRequest;
57735c4bbdfSmrg    return (*proc_dri3_vector[stuff->data]) (client);
57835c4bbdfSmrg}
57935c4bbdfSmrg
5801b5d61b8Smrgstatic int _X_COLD
58135c4bbdfSmrgsproc_dri3_query_version(ClientPtr client)
58235c4bbdfSmrg{
58335c4bbdfSmrg    REQUEST(xDRI3QueryVersionReq);
58435c4bbdfSmrg    REQUEST_SIZE_MATCH(xDRI3QueryVersionReq);
58535c4bbdfSmrg
58635c4bbdfSmrg    swaps(&stuff->length);
58735c4bbdfSmrg    swapl(&stuff->majorVersion);
58835c4bbdfSmrg    swapl(&stuff->minorVersion);
58935c4bbdfSmrg    return (*proc_dri3_vector[stuff->dri3ReqType]) (client);
59035c4bbdfSmrg}
59135c4bbdfSmrg
5921b5d61b8Smrgstatic int _X_COLD
59335c4bbdfSmrgsproc_dri3_open(ClientPtr client)
59435c4bbdfSmrg{
59535c4bbdfSmrg    REQUEST(xDRI3OpenReq);
59635c4bbdfSmrg    REQUEST_SIZE_MATCH(xDRI3OpenReq);
59735c4bbdfSmrg
59835c4bbdfSmrg    swaps(&stuff->length);
59935c4bbdfSmrg    swapl(&stuff->drawable);
60035c4bbdfSmrg    swapl(&stuff->provider);
60135c4bbdfSmrg    return (*proc_dri3_vector[stuff->dri3ReqType]) (client);
60235c4bbdfSmrg}
60335c4bbdfSmrg
6041b5d61b8Smrgstatic int _X_COLD
60535c4bbdfSmrgsproc_dri3_pixmap_from_buffer(ClientPtr client)
60635c4bbdfSmrg{
60735c4bbdfSmrg    REQUEST(xDRI3PixmapFromBufferReq);
60835c4bbdfSmrg    REQUEST_SIZE_MATCH(xDRI3PixmapFromBufferReq);
60935c4bbdfSmrg
61035c4bbdfSmrg    swaps(&stuff->length);
61135c4bbdfSmrg    swapl(&stuff->pixmap);
61235c4bbdfSmrg    swapl(&stuff->drawable);
61335c4bbdfSmrg    swapl(&stuff->size);
61435c4bbdfSmrg    swaps(&stuff->width);
61535c4bbdfSmrg    swaps(&stuff->height);
61635c4bbdfSmrg    swaps(&stuff->stride);
61735c4bbdfSmrg    return (*proc_dri3_vector[stuff->dri3ReqType]) (client);
61835c4bbdfSmrg}
61935c4bbdfSmrg
6201b5d61b8Smrgstatic int _X_COLD
62135c4bbdfSmrgsproc_dri3_buffer_from_pixmap(ClientPtr client)
62235c4bbdfSmrg{
62335c4bbdfSmrg    REQUEST(xDRI3BufferFromPixmapReq);
62435c4bbdfSmrg    REQUEST_SIZE_MATCH(xDRI3BufferFromPixmapReq);
62535c4bbdfSmrg
62635c4bbdfSmrg    swaps(&stuff->length);
62735c4bbdfSmrg    swapl(&stuff->pixmap);
62835c4bbdfSmrg    return (*proc_dri3_vector[stuff->dri3ReqType]) (client);
62935c4bbdfSmrg}
63035c4bbdfSmrg
6311b5d61b8Smrgstatic int _X_COLD
63235c4bbdfSmrgsproc_dri3_fence_from_fd(ClientPtr client)
63335c4bbdfSmrg{
63435c4bbdfSmrg    REQUEST(xDRI3FenceFromFDReq);
63535c4bbdfSmrg    REQUEST_SIZE_MATCH(xDRI3FenceFromFDReq);
63635c4bbdfSmrg
63735c4bbdfSmrg    swaps(&stuff->length);
63835c4bbdfSmrg    swapl(&stuff->drawable);
63935c4bbdfSmrg    swapl(&stuff->fence);
64035c4bbdfSmrg    return (*proc_dri3_vector[stuff->dri3ReqType]) (client);
64135c4bbdfSmrg}
64235c4bbdfSmrg
6431b5d61b8Smrgstatic int _X_COLD
64435c4bbdfSmrgsproc_dri3_fd_from_fence(ClientPtr client)
64535c4bbdfSmrg{
64635c4bbdfSmrg    REQUEST(xDRI3FDFromFenceReq);
64735c4bbdfSmrg    REQUEST_SIZE_MATCH(xDRI3FDFromFenceReq);
64835c4bbdfSmrg
64935c4bbdfSmrg    swaps(&stuff->length);
65035c4bbdfSmrg    swapl(&stuff->drawable);
65135c4bbdfSmrg    swapl(&stuff->fence);
65235c4bbdfSmrg    return (*proc_dri3_vector[stuff->dri3ReqType]) (client);
65335c4bbdfSmrg}
65435c4bbdfSmrg
6551b5d61b8Smrgstatic int _X_COLD
6561b5d61b8Smrgsproc_dri3_get_supported_modifiers(ClientPtr client)
6571b5d61b8Smrg{
6581b5d61b8Smrg    REQUEST(xDRI3GetSupportedModifiersReq);
6591b5d61b8Smrg    REQUEST_SIZE_MATCH(xDRI3GetSupportedModifiersReq);
6601b5d61b8Smrg
6611b5d61b8Smrg    swaps(&stuff->length);
6621b5d61b8Smrg    swapl(&stuff->window);
6631b5d61b8Smrg    return (*proc_dri3_vector[stuff->dri3ReqType]) (client);
6641b5d61b8Smrg}
6651b5d61b8Smrg
6661b5d61b8Smrgstatic int _X_COLD
6671b5d61b8Smrgsproc_dri3_pixmap_from_buffers(ClientPtr client)
6681b5d61b8Smrg{
6691b5d61b8Smrg    REQUEST(xDRI3PixmapFromBuffersReq);
6701b5d61b8Smrg    REQUEST_SIZE_MATCH(xDRI3PixmapFromBuffersReq);
6711b5d61b8Smrg
6721b5d61b8Smrg    swaps(&stuff->length);
6731b5d61b8Smrg    swapl(&stuff->pixmap);
6741b5d61b8Smrg    swapl(&stuff->window);
6751b5d61b8Smrg    swaps(&stuff->width);
6761b5d61b8Smrg    swaps(&stuff->height);
6771b5d61b8Smrg    swapl(&stuff->stride0);
6781b5d61b8Smrg    swapl(&stuff->offset0);
6791b5d61b8Smrg    swapl(&stuff->stride1);
6801b5d61b8Smrg    swapl(&stuff->offset1);
6811b5d61b8Smrg    swapl(&stuff->stride2);
6821b5d61b8Smrg    swapl(&stuff->offset2);
6831b5d61b8Smrg    swapl(&stuff->stride3);
6841b5d61b8Smrg    swapl(&stuff->offset3);
6851b5d61b8Smrg    swapll(&stuff->modifier);
6861b5d61b8Smrg    return (*proc_dri3_vector[stuff->dri3ReqType]) (client);
6871b5d61b8Smrg}
6881b5d61b8Smrg
6891b5d61b8Smrgstatic int _X_COLD
6901b5d61b8Smrgsproc_dri3_buffers_from_pixmap(ClientPtr client)
6911b5d61b8Smrg{
6921b5d61b8Smrg    REQUEST(xDRI3BuffersFromPixmapReq);
6931b5d61b8Smrg    REQUEST_SIZE_MATCH(xDRI3BuffersFromPixmapReq);
6941b5d61b8Smrg
6951b5d61b8Smrg    swaps(&stuff->length);
6961b5d61b8Smrg    swapl(&stuff->pixmap);
6971b5d61b8Smrg    return (*proc_dri3_vector[stuff->dri3ReqType]) (client);
6981b5d61b8Smrg}
6991b5d61b8Smrg
70035c4bbdfSmrgint (*sproc_dri3_vector[DRI3NumberRequests]) (ClientPtr) = {
70135c4bbdfSmrg    sproc_dri3_query_version,           /* 0 */
70235c4bbdfSmrg    sproc_dri3_open,                    /* 1 */
70335c4bbdfSmrg    sproc_dri3_pixmap_from_buffer,      /* 2 */
70435c4bbdfSmrg    sproc_dri3_buffer_from_pixmap,      /* 3 */
70535c4bbdfSmrg    sproc_dri3_fence_from_fd,           /* 4 */
70635c4bbdfSmrg    sproc_dri3_fd_from_fence,           /* 5 */
7071b5d61b8Smrg    sproc_dri3_get_supported_modifiers, /* 6 */
7081b5d61b8Smrg    sproc_dri3_pixmap_from_buffers,     /* 7 */
7091b5d61b8Smrg    sproc_dri3_buffers_from_pixmap,     /* 8 */
71035c4bbdfSmrg};
71135c4bbdfSmrg
7121b5d61b8Smrgint _X_COLD
71335c4bbdfSmrgsproc_dri3_dispatch(ClientPtr client)
71435c4bbdfSmrg{
71535c4bbdfSmrg    REQUEST(xReq);
71635c4bbdfSmrg    if (!client->local)
71735c4bbdfSmrg        return BadMatch;
71835c4bbdfSmrg    if (stuff->data >= DRI3NumberRequests || !sproc_dri3_vector[stuff->data])
71935c4bbdfSmrg        return BadRequest;
72035c4bbdfSmrg    return (*sproc_dri3_vector[stuff->data]) (client);
72135c4bbdfSmrg}
722