876 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			876 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
|  * Copyright © 2013 Keith Packard
 | |
|  *
 | |
|  * Permission to use, copy, modify, distribute, and sell this software and its
 | |
|  * documentation for any purpose is hereby granted without fee, provided that
 | |
|  * the above copyright notice appear in all copies and that both that copyright
 | |
|  * notice and this permission notice appear in supporting documentation, and
 | |
|  * that the name of the copyright holders not be used in advertising or
 | |
|  * publicity pertaining to distribution of the software without specific,
 | |
|  * written prior permission.  The copyright holders make no representations
 | |
|  * about the suitability of this software for any purpose.  It is provided "as
 | |
|  * is" without express or implied warranty.
 | |
|  *
 | |
|  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 | |
|  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 | |
|  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 | |
|  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 | |
|  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 | |
|  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
 | |
|  * OF THIS SOFTWARE.
 | |
|  */
 | |
| #include <dix-config.h>
 | |
| 
 | |
| #include <unistd.h>
 | |
| 
 | |
| #include "dix/dix_priv.h"
 | |
| #include "os/client_priv.h"
 | |
| 
 | |
| #include "dri3_priv.h"
 | |
| #include <syncsrv.h>
 | |
| #include <xace.h>
 | |
| #include "../Xext/syncsdk.h"
 | |
| #include <protocol-versions.h>
 | |
| #include <drm_fourcc.h>
 | |
| #include "randrstr_priv.h"
 | |
| #include "dixstruct_priv.h"
 | |
| 
 | |
| static Bool
 | |
| dri3_screen_can_one_point_four(ScreenPtr screen)
 | |
| {
 | |
|     dri3_screen_priv_ptr dri3 = dri3_screen_priv(screen);
 | |
| 
 | |
|     return dri3 &&
 | |
|         dri3->info &&
 | |
|         dri3->info->version >= 4 &&
 | |
|         dri3->info->import_syncobj;
 | |
| }
 | |
| 
 | |
| static Bool
 | |
| dri3_screen_can_one_point_two(ScreenPtr screen)
 | |
| {
 | |
|     dri3_screen_priv_ptr dri3 = dri3_screen_priv(screen);
 | |
| 
 | |
|     if (dri3 && dri3->info && dri3->info->version >= 2 &&
 | |
|         dri3->info->pixmap_from_fds && dri3->info->fds_from_pixmap &&
 | |
|         dri3->info->get_formats && dri3->info->get_modifiers &&
 | |
|         dri3->info->get_drawable_modifiers)
 | |
|         return TRUE;
 | |
| 
 | |
|     return FALSE;
 | |
| }
 | |
| 
 | |
| static int
 | |
| proc_dri3_query_version(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xDRI3QueryVersionReq);
 | |
| 
 | |
|     xDRI3QueryVersionReply rep = {
 | |
|         .type = X_Reply,
 | |
|         .sequenceNumber = client->sequence,
 | |
|         .majorVersion = SERVER_DRI3_MAJOR_VERSION,
 | |
|         .minorVersion = SERVER_DRI3_MINOR_VERSION
 | |
|     };
 | |
| 
 | |
|     REQUEST_SIZE_MATCH(xDRI3QueryVersionReq);
 | |
| 
 | |
|     for (int i = 0; i < screenInfo.numScreens; i++) {
 | |
|         if (!dri3_screen_can_one_point_two(screenInfo.screens[i])) {
 | |
|             rep.minorVersion = 0;
 | |
|             break;
 | |
|         }
 | |
|         if (!dri3_screen_can_one_point_four(screenInfo.screens[i])) {
 | |
|             rep.minorVersion = 2;
 | |
|             break;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     for (int i = 0; i < screenInfo.numGPUScreens; i++) {
 | |
|         if (!dri3_screen_can_one_point_two(screenInfo.gpuscreens[i])) {
 | |
|             rep.minorVersion = 0;
 | |
|             break;
 | |
|         }
 | |
|         if (!dri3_screen_can_one_point_four(screenInfo.gpuscreens[i])) {
 | |
|             rep.minorVersion = 2;
 | |
|             break;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /* From DRI3 proto:
 | |
|      *
 | |
|      * The client sends the highest supported version to the server
 | |
|      * and the server sends the highest version it supports, but no
 | |
|      * higher than the requested version.
 | |
|      */
 | |
| 
 | |
|     if (rep.majorVersion > stuff->majorVersion ||
 | |
|         (rep.majorVersion == stuff->majorVersion &&
 | |
|          rep.minorVersion > stuff->minorVersion)) {
 | |
|         rep.majorVersion = stuff->majorVersion;
 | |
|         rep.minorVersion = stuff->minorVersion;
 | |
|     }
 | |
| 
 | |
|     if (client->swapped) {
 | |
|         swaps(&rep.sequenceNumber);
 | |
|         swapl(&rep.length);
 | |
|         swapl(&rep.majorVersion);
 | |
|         swapl(&rep.minorVersion);
 | |
|     }
 | |
|     WriteToClient(client, sizeof(rep), &rep);
 | |
|     return Success;
 | |
| }
 | |
| 
 | |
| int
 | |
| dri3_send_open_reply(ClientPtr client, int fd)
 | |
| {
 | |
|     xDRI3OpenReply rep = {
 | |
|         .type = X_Reply,
 | |
|         .nfd = 1,
 | |
|         .sequenceNumber = client->sequence,
 | |
|     };
 | |
| 
 | |
|     if (client->swapped) {
 | |
|         swaps(&rep.sequenceNumber);
 | |
|         swapl(&rep.length);
 | |
|     }
 | |
| 
 | |
|     if (WriteFdToClient(client, fd, TRUE) < 0) {
 | |
|         close(fd);
 | |
|         return BadAlloc;
 | |
|     }
 | |
| 
 | |
|     WriteToClient(client, sizeof (rep), &rep);
 | |
| 
 | |
|     return Success;
 | |
| }
 | |
| 
 | |
| static int
 | |
| proc_dri3_open(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xDRI3OpenReq);
 | |
|     RRProviderPtr provider;
 | |
|     DrawablePtr drawable;
 | |
|     ScreenPtr screen;
 | |
|     int fd;
 | |
|     int status;
 | |
| 
 | |
|     REQUEST_SIZE_MATCH(xDRI3OpenReq);
 | |
| 
 | |
|     status = dixLookupDrawable(&drawable, stuff->drawable, client, 0, DixGetAttrAccess);
 | |
|     if (status != Success)
 | |
|         return status;
 | |
| 
 | |
|     if (stuff->provider == None)
 | |
|         provider = NULL;
 | |
|     else if (!RRProviderType) {
 | |
|         return BadMatch;
 | |
|     } else {
 | |
|         VERIFY_RR_PROVIDER(stuff->provider, provider, DixReadAccess);
 | |
|         if (drawable->pScreen != provider->pScreen)
 | |
|             return BadMatch;
 | |
|     }
 | |
|     screen = drawable->pScreen;
 | |
| 
 | |
|     status = dri3_open(client, screen, provider, &fd);
 | |
|     if (status != Success)
 | |
|         return status;
 | |
| 
 | |
|     if (client->ignoreCount == 0)
 | |
|         return dri3_send_open_reply(client, fd);
 | |
| 
 | |
|     return Success;
 | |
| }
 | |
| 
 | |
| static int
 | |
| proc_dri3_pixmap_from_buffer(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xDRI3PixmapFromBufferReq);
 | |
|     int fd;
 | |
|     DrawablePtr drawable;
 | |
|     PixmapPtr pixmap;
 | |
|     CARD32 stride, offset;
 | |
|     int rc;
 | |
| 
 | |
|     SetReqFds(client, 1);
 | |
|     REQUEST_SIZE_MATCH(xDRI3PixmapFromBufferReq);
 | |
|     LEGAL_NEW_RESOURCE(stuff->pixmap, client);
 | |
|     rc = dixLookupDrawable(&drawable, stuff->drawable, client, M_ANY, DixGetAttrAccess);
 | |
|     if (rc != Success) {
 | |
|         client->errorValue = stuff->drawable;
 | |
|         return rc;
 | |
|     }
 | |
| 
 | |
|     if (!stuff->width || !stuff->height) {
 | |
|         client->errorValue = 0;
 | |
|         return BadValue;
 | |
|     }
 | |
| 
 | |
|     if (stuff->width > 32767 || stuff->height > 32767)
 | |
|         return BadAlloc;
 | |
| 
 | |
|     if (stuff->depth != 1) {
 | |
|         DepthPtr depth = drawable->pScreen->allowedDepths;
 | |
|         int i;
 | |
|         for (i = 0; i < drawable->pScreen->numDepths; i++, depth++)
 | |
|             if (depth->depth == stuff->depth)
 | |
|                 break;
 | |
|         if (i == drawable->pScreen->numDepths) {
 | |
|             client->errorValue = stuff->depth;
 | |
|             return BadValue;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     fd = ReadFdFromClient(client);
 | |
|     if (fd < 0)
 | |
|         return BadValue;
 | |
| 
 | |
|     offset = 0;
 | |
|     stride = stuff->stride;
 | |
|     rc = dri3_pixmap_from_fds(&pixmap,
 | |
|                               drawable->pScreen, 1, &fd,
 | |
|                               stuff->width, stuff->height,
 | |
|                               &stride, &offset,
 | |
|                               stuff->depth, stuff->bpp,
 | |
|                               DRM_FORMAT_MOD_INVALID);
 | |
|     close (fd);
 | |
|     if (rc != Success)
 | |
|         return rc;
 | |
| 
 | |
|     pixmap->drawable.id = stuff->pixmap;
 | |
| 
 | |
|     /* security creation/labeling check */
 | |
|     rc = XaceHookResourceAccess(client, stuff->pixmap, X11_RESTYPE_PIXMAP,
 | |
|                   pixmap, X11_RESTYPE_NONE, NULL, DixCreateAccess);
 | |
| 
 | |
|     if (rc != Success) {
 | |
|         dixDestroyPixmap(pixmap, 0);
 | |
|         return rc;
 | |
|     }
 | |
|     if (!AddResource(stuff->pixmap, X11_RESTYPE_PIXMAP, (void *) pixmap))
 | |
|         return BadAlloc;
 | |
| 
 | |
|     return Success;
 | |
| }
 | |
| 
 | |
| static int
 | |
| proc_dri3_buffer_from_pixmap(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xDRI3BufferFromPixmapReq);
 | |
| 
 | |
|     int rc;
 | |
|     int fd;
 | |
|     PixmapPtr pixmap;
 | |
| 
 | |
|     REQUEST_SIZE_MATCH(xDRI3BufferFromPixmapReq);
 | |
|     rc = dixLookupResourceByType((void **) &pixmap, stuff->pixmap, X11_RESTYPE_PIXMAP,
 | |
|                                  client, DixWriteAccess);
 | |
|     if (rc != Success) {
 | |
|         client->errorValue = stuff->pixmap;
 | |
|         return rc;
 | |
|     }
 | |
| 
 | |
|     xDRI3BufferFromPixmapReply rep = {
 | |
|         .type = X_Reply,
 | |
|         .nfd = 1,
 | |
|         .sequenceNumber = client->sequence,
 | |
|         .width = pixmap->drawable.width,
 | |
|         .height = pixmap->drawable.height,
 | |
|         .depth = pixmap->drawable.depth,
 | |
|         .bpp = pixmap->drawable.bitsPerPixel,
 | |
|     };
 | |
| 
 | |
|     fd = dri3_fd_from_pixmap(pixmap, &rep.stride, &rep.size);
 | |
|     if (fd < 0)
 | |
|         return BadPixmap;
 | |
| 
 | |
|     if (client->swapped) {
 | |
|         swaps(&rep.sequenceNumber);
 | |
|         swapl(&rep.length);
 | |
|         swapl(&rep.size);
 | |
|         swaps(&rep.width);
 | |
|         swaps(&rep.height);
 | |
|         swaps(&rep.stride);
 | |
|     }
 | |
|     if (WriteFdToClient(client, fd, TRUE) < 0) {
 | |
|         close(fd);
 | |
|         return BadAlloc;
 | |
|     }
 | |
| 
 | |
|     WriteToClient(client, sizeof(rep), &rep);
 | |
| 
 | |
|     return Success;
 | |
| }
 | |
| 
 | |
| static int
 | |
| proc_dri3_fence_from_fd(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xDRI3FenceFromFDReq);
 | |
|     DrawablePtr drawable;
 | |
|     int fd;
 | |
|     int status;
 | |
| 
 | |
|     SetReqFds(client, 1);
 | |
|     REQUEST_SIZE_MATCH(xDRI3FenceFromFDReq);
 | |
|     LEGAL_NEW_RESOURCE(stuff->fence, client);
 | |
| 
 | |
|     status = dixLookupDrawable(&drawable, stuff->drawable, client, M_ANY, DixGetAttrAccess);
 | |
|     if (status != Success)
 | |
|         return status;
 | |
| 
 | |
|     fd = ReadFdFromClient(client);
 | |
|     if (fd < 0)
 | |
|         return BadValue;
 | |
| 
 | |
|     status = SyncCreateFenceFromFD(client, drawable, stuff->fence,
 | |
|                                    fd, stuff->initially_triggered);
 | |
| 
 | |
|     return status;
 | |
| }
 | |
| 
 | |
| static int
 | |
| proc_dri3_fd_from_fence(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xDRI3FDFromFenceReq);
 | |
|     xDRI3FDFromFenceReply rep = {
 | |
|         .type = X_Reply,
 | |
|         .nfd = 1,
 | |
|         .sequenceNumber = client->sequence,
 | |
|     };
 | |
|     DrawablePtr drawable;
 | |
|     int fd;
 | |
|     int status;
 | |
|     SyncFence *fence;
 | |
| 
 | |
|     REQUEST_SIZE_MATCH(xDRI3FDFromFenceReq);
 | |
| 
 | |
|     status = dixLookupDrawable(&drawable, stuff->drawable, client, M_ANY, DixGetAttrAccess);
 | |
|     if (status != Success)
 | |
|         return status;
 | |
|     status = SyncVerifyFence(&fence, stuff->fence, client, DixWriteAccess);
 | |
|     if (status != Success)
 | |
|         return status;
 | |
| 
 | |
|     fd = SyncFDFromFence(client, drawable, fence);
 | |
|     if (fd < 0)
 | |
|         return BadMatch;
 | |
| 
 | |
|     if (client->swapped) {
 | |
|         swaps(&rep.sequenceNumber);
 | |
|         swapl(&rep.length);
 | |
|     }
 | |
|     if (WriteFdToClient(client, fd, FALSE) < 0)
 | |
|         return BadAlloc;
 | |
| 
 | |
|     WriteToClient(client, sizeof(rep), &rep);
 | |
| 
 | |
|     return Success;
 | |
| }
 | |
| 
 | |
| static int
 | |
| proc_dri3_get_supported_modifiers(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xDRI3GetSupportedModifiersReq);
 | |
|     WindowPtr window;
 | |
|     ScreenPtr pScreen;
 | |
|     CARD64 *window_modifiers = NULL;
 | |
|     CARD64 *screen_modifiers = NULL;
 | |
|     CARD32 nwindowmodifiers = 0;
 | |
|     CARD32 nscreenmodifiers = 0;
 | |
|     int status;
 | |
|     int i;
 | |
| 
 | |
|     REQUEST_SIZE_MATCH(xDRI3GetSupportedModifiersReq);
 | |
| 
 | |
|     status = dixLookupWindow(&window, stuff->window, client, DixGetAttrAccess);
 | |
|     if (status != Success)
 | |
|         return status;
 | |
|     pScreen = window->drawable.pScreen;
 | |
| 
 | |
|     dri3_get_supported_modifiers(pScreen, &window->drawable,
 | |
| 				 stuff->depth, stuff->bpp,
 | |
|                                  &nwindowmodifiers, &window_modifiers,
 | |
|                                  &nscreenmodifiers, &screen_modifiers);
 | |
| 
 | |
|     const size_t bufsz = (nwindowmodifiers + nscreenmodifiers) * sizeof(CARD64);
 | |
|     CARD64 *buf = calloc(1, bufsz);
 | |
|     if (!buf) {
 | |
|         free(window_modifiers);
 | |
|         free(screen_modifiers);
 | |
|         return BadAlloc;
 | |
|     }
 | |
| 
 | |
|     memcpy(buf, window_modifiers, sizeof(CARD64) * nwindowmodifiers);
 | |
|     memcpy(&buf[nwindowmodifiers], screen_modifiers, sizeof(CARD64) * nscreenmodifiers);
 | |
| 
 | |
|     free(window_modifiers);
 | |
|     free(screen_modifiers);
 | |
| 
 | |
|     xDRI3GetSupportedModifiersReply rep = {
 | |
|         .type = X_Reply,
 | |
|         .sequenceNumber = client->sequence,
 | |
|         .numWindowModifiers = nwindowmodifiers,
 | |
|         .numScreenModifiers = nscreenmodifiers,
 | |
|         .length = bytes_to_int32(bufsz),
 | |
|     };
 | |
| 
 | |
|     if (client->swapped) {
 | |
|         swaps(&rep.sequenceNumber);
 | |
|         swapl(&rep.length);
 | |
|         swapl(&rep.numWindowModifiers);
 | |
|         swapl(&rep.numScreenModifiers);
 | |
|         for (i = 0; i < nwindowmodifiers+nscreenmodifiers; i++)
 | |
|             swapll(&buf[i]);
 | |
|     }
 | |
| 
 | |
|     WriteToClient(client, sizeof(rep), &rep);
 | |
|     WriteToClient(client, bufsz, buf);
 | |
|     free(buf);
 | |
|     return Success;
 | |
| }
 | |
| 
 | |
| static int
 | |
| proc_dri3_pixmap_from_buffers(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xDRI3PixmapFromBuffersReq);
 | |
|     int fds[4];
 | |
|     CARD32 strides[4], offsets[4];
 | |
|     ScreenPtr screen;
 | |
|     WindowPtr window;
 | |
|     PixmapPtr pixmap;
 | |
|     int rc;
 | |
|     int i;
 | |
| 
 | |
|     SetReqFds(client, stuff->num_buffers);
 | |
|     REQUEST_SIZE_MATCH(xDRI3PixmapFromBuffersReq);
 | |
|     LEGAL_NEW_RESOURCE(stuff->pixmap, client);
 | |
|     rc = dixLookupWindow(&window, stuff->window, client, DixGetAttrAccess);
 | |
|     if (rc != Success) {
 | |
|         client->errorValue = stuff->window;
 | |
|         return rc;
 | |
|     }
 | |
|     screen = window->drawable.pScreen;
 | |
| 
 | |
|     if (!stuff->width || !stuff->height || !stuff->bpp || !stuff->depth) {
 | |
|         client->errorValue = 0;
 | |
|         return BadValue;
 | |
|     }
 | |
| 
 | |
|     if (stuff->width > 32767 || stuff->height > 32767)
 | |
|         return BadAlloc;
 | |
| 
 | |
|     if (stuff->depth != 1) {
 | |
|         DepthPtr depth = screen->allowedDepths;
 | |
|         int j;
 | |
|         for (j = 0; j < screen->numDepths; j++, depth++)
 | |
|             if (depth->depth == stuff->depth)
 | |
|                 break;
 | |
|         if (j == screen->numDepths) {
 | |
|             client->errorValue = stuff->depth;
 | |
|             return BadValue;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if (!stuff->num_buffers || stuff->num_buffers > 4) {
 | |
|         client->errorValue = stuff->num_buffers;
 | |
|         return BadValue;
 | |
|     }
 | |
| 
 | |
|     for (i = 0; i < stuff->num_buffers; i++) {
 | |
|         fds[i] = ReadFdFromClient(client);
 | |
|         if (fds[i] < 0) {
 | |
|             while (--i >= 0)
 | |
|                 close(fds[i]);
 | |
|             return BadValue;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     strides[0] = stuff->stride0;
 | |
|     strides[1] = stuff->stride1;
 | |
|     strides[2] = stuff->stride2;
 | |
|     strides[3] = stuff->stride3;
 | |
|     offsets[0] = stuff->offset0;
 | |
|     offsets[1] = stuff->offset1;
 | |
|     offsets[2] = stuff->offset2;
 | |
|     offsets[3] = stuff->offset3;
 | |
| 
 | |
|     rc = dri3_pixmap_from_fds(&pixmap, screen,
 | |
|                               stuff->num_buffers, fds,
 | |
|                               stuff->width, stuff->height,
 | |
|                               strides, offsets,
 | |
|                               stuff->depth, stuff->bpp,
 | |
|                               stuff->modifier);
 | |
| 
 | |
|     for (i = 0; i < stuff->num_buffers; i++)
 | |
|         close (fds[i]);
 | |
| 
 | |
|     if (rc != Success)
 | |
|         return rc;
 | |
| 
 | |
|     pixmap->drawable.id = stuff->pixmap;
 | |
| 
 | |
|     /* security creation/labeling check */
 | |
|     rc = XaceHookResourceAccess(client, stuff->pixmap, X11_RESTYPE_PIXMAP,
 | |
|                   pixmap, X11_RESTYPE_NONE, NULL, DixCreateAccess);
 | |
| 
 | |
|     if (rc != Success) {
 | |
|         dixDestroyPixmap(pixmap, 0);
 | |
|         return rc;
 | |
|     }
 | |
|     if (!AddResource(stuff->pixmap, X11_RESTYPE_PIXMAP, (void *) pixmap))
 | |
|         return BadAlloc;
 | |
| 
 | |
|     return Success;
 | |
| }
 | |
| 
 | |
| static int
 | |
| proc_dri3_buffers_from_pixmap(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xDRI3BuffersFromPixmapReq);
 | |
|     int rc;
 | |
|     int fds[4];
 | |
|     int num_fds;
 | |
|     uint32_t strides[4], offsets[4];
 | |
|     uint64_t modifier;
 | |
|     int i;
 | |
|     PixmapPtr pixmap;
 | |
| 
 | |
|     REQUEST_SIZE_MATCH(xDRI3BuffersFromPixmapReq);
 | |
|     rc = dixLookupResourceByType((void **) &pixmap, stuff->pixmap, X11_RESTYPE_PIXMAP,
 | |
|                                  client, DixWriteAccess);
 | |
|     if (rc != Success) {
 | |
|         client->errorValue = stuff->pixmap;
 | |
|         return rc;
 | |
|     }
 | |
| 
 | |
|     num_fds = dri3_fds_from_pixmap(pixmap, fds, strides, offsets, &modifier);
 | |
|     if (num_fds == 0)
 | |
|         return BadPixmap;
 | |
| 
 | |
|     for (i = 0; i < num_fds; i++) {
 | |
|         if (WriteFdToClient(client, fds[i], TRUE) < 0) {
 | |
|             while (i--)
 | |
|                 close(fds[i]);
 | |
|             return BadAlloc;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     const size_t bufsz = num_fds * 2 * sizeof(CARD32);
 | |
|     CARD32 *buf = calloc(1, bufsz);
 | |
|     if (!buf)
 | |
|         return BadAlloc;
 | |
| 
 | |
|     memcpy(buf, strides, num_fds * sizeof(CARD32));
 | |
|     memcpy(&buf[num_fds], offsets, num_fds * sizeof(CARD32));
 | |
| 
 | |
|     xDRI3BuffersFromPixmapReply rep = {
 | |
|         .type = X_Reply,
 | |
|         .sequenceNumber = client->sequence,
 | |
|         .nfd = num_fds,
 | |
|         .length = bytes_to_int32(bufsz),
 | |
|         .width = pixmap->drawable.width,
 | |
|         .height = pixmap->drawable.height,
 | |
|         .depth = pixmap->drawable.depth,
 | |
|         .bpp = pixmap->drawable.bitsPerPixel,
 | |
|         .modifier = modifier,
 | |
|     };
 | |
| 
 | |
|     if (client->swapped) {
 | |
|         swaps(&rep.sequenceNumber);
 | |
|         swapl(&rep.length);
 | |
|         swaps(&rep.width);
 | |
|         swaps(&rep.height);
 | |
|         swapll(&rep.modifier);
 | |
|         for (i = 0; i < num_fds * 2; i++)
 | |
|             swapl(&buf[i]);
 | |
|     }
 | |
| 
 | |
|     WriteToClient(client, sizeof(rep), &rep);
 | |
|     WriteToClient(client, bufsz, buf);
 | |
|     free(buf);
 | |
|     return Success;
 | |
| }
 | |
| 
 | |
| static int
 | |
| proc_dri3_set_drm_device_in_use(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xDRI3SetDRMDeviceInUseReq);
 | |
|     WindowPtr window;
 | |
|     int status;
 | |
| 
 | |
|     REQUEST_SIZE_MATCH(xDRI3SetDRMDeviceInUseReq);
 | |
|     status = dixLookupWindow(&window, stuff->window, client,
 | |
|                              DixGetAttrAccess);
 | |
|     if (status != Success)
 | |
|         return status;
 | |
| 
 | |
|     /* TODO Eventually we should use this information to have
 | |
|      * DRI3GetSupportedModifiers return device-specific modifiers, but for now
 | |
|      * we will ignore it until multi-device support is more complete.
 | |
|      * Otherwise we can't advertise support for DRI3 1.4.
 | |
|      */
 | |
|     return Success;
 | |
| }
 | |
| 
 | |
| static int
 | |
| proc_dri3_import_syncobj(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xDRI3ImportSyncobjReq);
 | |
|     DrawablePtr drawable;
 | |
|     ScreenPtr screen;
 | |
|     int fd;
 | |
|     int status;
 | |
| 
 | |
|     SetReqFds(client, 1);
 | |
|     REQUEST_SIZE_MATCH(xDRI3ImportSyncobjReq);
 | |
|     LEGAL_NEW_RESOURCE(stuff->syncobj, client);
 | |
| 
 | |
|     status = dixLookupDrawable(&drawable, stuff->drawable, client,
 | |
|                                M_ANY, DixGetAttrAccess);
 | |
|     if (status != Success)
 | |
|         return status;
 | |
| 
 | |
|     screen = drawable->pScreen;
 | |
| 
 | |
|     fd = ReadFdFromClient(client);
 | |
|     if (fd < 0)
 | |
|         return BadValue;
 | |
| 
 | |
|     return dri3_import_syncobj(client, screen, stuff->syncobj, fd);
 | |
| }
 | |
| 
 | |
| static int
 | |
| proc_dri3_free_syncobj(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xDRI3FreeSyncobjReq);
 | |
|     struct dri3_syncobj *syncobj;
 | |
|     int status;
 | |
| 
 | |
|     REQUEST_SIZE_MATCH(xDRI3FreeSyncobjReq);
 | |
| 
 | |
|     status = dixLookupResourceByType((void **) &syncobj, stuff->syncobj,
 | |
|                                      dri3_syncobj_type, client, DixWriteAccess);
 | |
|     if (status != Success)
 | |
|         return status;
 | |
| 
 | |
|     FreeResource(stuff->syncobj, RT_NONE);
 | |
|     return Success;
 | |
| }
 | |
| 
 | |
| int
 | |
| proc_dri3_dispatch(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xReq);
 | |
|     if (!client->local)
 | |
|         return BadMatch;
 | |
| 
 | |
|     switch (stuff->data) {
 | |
|         case X_DRI3QueryVersion:
 | |
|             return proc_dri3_query_version(client);
 | |
|         case X_DRI3Open:
 | |
|             return proc_dri3_open(client);
 | |
|         case X_DRI3PixmapFromBuffer:
 | |
|             return proc_dri3_pixmap_from_buffer(client);
 | |
|         case X_DRI3BufferFromPixmap:
 | |
|             return proc_dri3_buffer_from_pixmap(client);
 | |
|         case X_DRI3FenceFromFD:
 | |
|             return proc_dri3_fence_from_fd(client);
 | |
|         case X_DRI3FDFromFence:
 | |
|             return proc_dri3_fd_from_fence(client);
 | |
| 
 | |
|         /* v1.2 */
 | |
|         case xDRI3GetSupportedModifiers:
 | |
|             return proc_dri3_get_supported_modifiers(client);
 | |
|         case xDRI3PixmapFromBuffers:
 | |
|             return proc_dri3_pixmap_from_buffers(client);
 | |
|         case xDRI3BuffersFromPixmap:
 | |
|             return proc_dri3_buffers_from_pixmap(client);
 | |
| 
 | |
|         /* v1.3 */
 | |
|         case xDRI3SetDRMDeviceInUse:
 | |
|             return proc_dri3_set_drm_device_in_use(client);
 | |
| 
 | |
|         /* v1.4 */
 | |
|         case xDRI3ImportSyncobj:
 | |
|             return proc_dri3_import_syncobj(client);
 | |
|         case xDRI3FreeSyncobj:
 | |
|             return proc_dri3_free_syncobj(client);
 | |
|         default:
 | |
|             return BadRequest;
 | |
|     }
 | |
| }
 | |
| 
 | |
| static int _X_COLD
 | |
| sproc_dri3_query_version(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xDRI3QueryVersionReq);
 | |
|     REQUEST_SIZE_MATCH(xDRI3QueryVersionReq);
 | |
|     swapl(&stuff->majorVersion);
 | |
|     swapl(&stuff->minorVersion);
 | |
|     return proc_dri3_query_version(client);
 | |
| }
 | |
| 
 | |
| static int _X_COLD
 | |
| sproc_dri3_open(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xDRI3OpenReq);
 | |
|     REQUEST_SIZE_MATCH(xDRI3OpenReq);
 | |
|     swapl(&stuff->drawable);
 | |
|     swapl(&stuff->provider);
 | |
|     return proc_dri3_open(client);
 | |
| }
 | |
| 
 | |
| static int _X_COLD
 | |
| sproc_dri3_pixmap_from_buffer(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xDRI3PixmapFromBufferReq);
 | |
|     REQUEST_SIZE_MATCH(xDRI3PixmapFromBufferReq);
 | |
|     swapl(&stuff->pixmap);
 | |
|     swapl(&stuff->drawable);
 | |
|     swapl(&stuff->size);
 | |
|     swaps(&stuff->width);
 | |
|     swaps(&stuff->height);
 | |
|     swaps(&stuff->stride);
 | |
|     return proc_dri3_pixmap_from_buffer(client);
 | |
| }
 | |
| 
 | |
| static int _X_COLD
 | |
| sproc_dri3_buffer_from_pixmap(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xDRI3BufferFromPixmapReq);
 | |
|     REQUEST_SIZE_MATCH(xDRI3BufferFromPixmapReq);
 | |
|     swapl(&stuff->pixmap);
 | |
|     return proc_dri3_buffer_from_pixmap(client);
 | |
| }
 | |
| 
 | |
| static int _X_COLD
 | |
| sproc_dri3_fence_from_fd(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xDRI3FenceFromFDReq);
 | |
|     REQUEST_SIZE_MATCH(xDRI3FenceFromFDReq);
 | |
|     swapl(&stuff->drawable);
 | |
|     swapl(&stuff->fence);
 | |
|     return proc_dri3_fence_from_fd(client);
 | |
| }
 | |
| 
 | |
| static int _X_COLD
 | |
| sproc_dri3_fd_from_fence(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xDRI3FDFromFenceReq);
 | |
|     REQUEST_SIZE_MATCH(xDRI3FDFromFenceReq);
 | |
|     swapl(&stuff->drawable);
 | |
|     swapl(&stuff->fence);
 | |
|     return proc_dri3_fd_from_fence(client);
 | |
| }
 | |
| 
 | |
| static int _X_COLD
 | |
| sproc_dri3_get_supported_modifiers(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xDRI3GetSupportedModifiersReq);
 | |
|     REQUEST_SIZE_MATCH(xDRI3GetSupportedModifiersReq);
 | |
|     swapl(&stuff->window);
 | |
|     return proc_dri3_get_supported_modifiers(client);
 | |
| }
 | |
| 
 | |
| static int _X_COLD
 | |
| sproc_dri3_pixmap_from_buffers(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xDRI3PixmapFromBuffersReq);
 | |
|     REQUEST_SIZE_MATCH(xDRI3PixmapFromBuffersReq);
 | |
|     swapl(&stuff->pixmap);
 | |
|     swapl(&stuff->window);
 | |
|     swaps(&stuff->width);
 | |
|     swaps(&stuff->height);
 | |
|     swapl(&stuff->stride0);
 | |
|     swapl(&stuff->offset0);
 | |
|     swapl(&stuff->stride1);
 | |
|     swapl(&stuff->offset1);
 | |
|     swapl(&stuff->stride2);
 | |
|     swapl(&stuff->offset2);
 | |
|     swapl(&stuff->stride3);
 | |
|     swapl(&stuff->offset3);
 | |
|     swapll(&stuff->modifier);
 | |
|     return proc_dri3_pixmap_from_buffers(client);
 | |
| }
 | |
| 
 | |
| static int _X_COLD
 | |
| sproc_dri3_buffers_from_pixmap(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xDRI3BuffersFromPixmapReq);
 | |
|     REQUEST_SIZE_MATCH(xDRI3BuffersFromPixmapReq);
 | |
|     swapl(&stuff->pixmap);
 | |
|     return proc_dri3_buffers_from_pixmap(client);
 | |
| }
 | |
| 
 | |
| static int _X_COLD
 | |
| sproc_dri3_set_drm_device_in_use(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xDRI3SetDRMDeviceInUseReq);
 | |
|     REQUEST_SIZE_MATCH(xDRI3SetDRMDeviceInUseReq);
 | |
|     swapl(&stuff->window);
 | |
|     swapl(&stuff->drmMajor);
 | |
|     swapl(&stuff->drmMinor);
 | |
|     return proc_dri3_set_drm_device_in_use(client);
 | |
| }
 | |
| 
 | |
| static int _X_COLD
 | |
| sproc_dri3_import_syncobj(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xDRI3ImportSyncobjReq);
 | |
|     REQUEST_SIZE_MATCH(xDRI3ImportSyncobjReq);
 | |
|     swapl(&stuff->syncobj);
 | |
|     swapl(&stuff->drawable);
 | |
|     return proc_dri3_import_syncobj(client);
 | |
| }
 | |
| 
 | |
| static int _X_COLD
 | |
| sproc_dri3_free_syncobj(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xDRI3FreeSyncobjReq);
 | |
|     REQUEST_SIZE_MATCH(xDRI3FreeSyncobjReq);
 | |
|     swapl(&stuff->syncobj);
 | |
|     return proc_dri3_free_syncobj(client);
 | |
| }
 | |
| 
 | |
| int _X_COLD
 | |
| sproc_dri3_dispatch(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xReq);
 | |
|     if (!client->local)
 | |
|         return BadMatch;
 | |
| 
 | |
|     switch (stuff->data) {
 | |
|         case X_DRI3QueryVersion:
 | |
|             return sproc_dri3_query_version(client);
 | |
|         case X_DRI3Open:
 | |
|             return sproc_dri3_open(client);
 | |
|         case X_DRI3PixmapFromBuffer:
 | |
|             return sproc_dri3_pixmap_from_buffer(client);
 | |
|         case X_DRI3BufferFromPixmap:
 | |
|             return sproc_dri3_buffer_from_pixmap(client);
 | |
|         case X_DRI3FenceFromFD:
 | |
|             return sproc_dri3_fence_from_fd(client);
 | |
|         case X_DRI3FDFromFence:
 | |
|             return sproc_dri3_fd_from_fence(client);
 | |
| 
 | |
|         /* v1.2 */
 | |
|         case xDRI3GetSupportedModifiers:
 | |
|             return sproc_dri3_get_supported_modifiers(client);
 | |
|         case xDRI3PixmapFromBuffers:
 | |
|             return sproc_dri3_pixmap_from_buffers(client);
 | |
|         case xDRI3BuffersFromPixmap:
 | |
|             return sproc_dri3_buffers_from_pixmap(client);
 | |
| 
 | |
|         /* v1.3 */
 | |
|         case xDRI3SetDRMDeviceInUse:
 | |
|             return sproc_dri3_set_drm_device_in_use(client);
 | |
| 
 | |
|         /* v1.4 */
 | |
|         case xDRI3ImportSyncobj:
 | |
|             return sproc_dri3_import_syncobj(client);
 | |
|         case xDRI3FreeSyncobj:
 | |
|             return sproc_dri3_free_syncobj(client);
 | |
|         default:
 | |
|             return BadRequest;
 | |
|     }
 | |
| }
 |