375 lines
		
	
	
		
			9.5 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			375 lines
		
	
	
		
			9.5 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
|  * Copyright © 2008 Red Hat, Inc.
 | |
|  *
 | |
|  * Permission is hereby granted, free of charge, to any person obtaining a
 | |
|  * copy of this software and associated documentation files (the "Soft-
 | |
|  * ware"), to deal in the Software without restriction, including without
 | |
|  * limitation the rights to use, copy, modify, merge, publish, distribute,
 | |
|  * and/or sell copies of the Software, and to permit persons to whom the
 | |
|  * Software is furnished to do so, provided that the above copyright
 | |
|  * notice(s) and this permission notice appear in all copies of the Soft-
 | |
|  * ware and that both the above copyright notice(s) and this permission
 | |
|  * notice appear in supporting documentation.
 | |
|  *
 | |
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 | |
|  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
 | |
|  * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
 | |
|  * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
 | |
|  * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
 | |
|  * QUENTIAL 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 PERFOR-
 | |
|  * MANCE OF THIS SOFTWARE.
 | |
|  *
 | |
|  * Except as contained in this notice, the name of a copyright holder shall
 | |
|  * not be used in advertising or otherwise to promote the sale, use or
 | |
|  * other dealings in this Software without prior written authorization of
 | |
|  * the copyright holder.
 | |
|  *
 | |
|  * Authors:
 | |
|  *   Kristian Høgsberg (krh@redhat.com)
 | |
|  */
 | |
| 
 | |
| #ifdef HAVE_XORG_CONFIG_H
 | |
| #include <xorg-config.h>
 | |
| #endif
 | |
| 
 | |
| #include <X11/X.h>
 | |
| #include <X11/Xproto.h>
 | |
| #include <X11/extensions/dri2proto.h>
 | |
| #include <X11/extensions/xfixeswire.h>
 | |
| #include "dixstruct.h"
 | |
| #include "scrnintstr.h"
 | |
| #include "pixmapstr.h"
 | |
| #include "extnsionst.h"
 | |
| #include "xf86drm.h"
 | |
| #include "xfixes.h"
 | |
| #include "dri2.h"
 | |
| 
 | |
| /* The only xf86 include */
 | |
| #include "xf86Module.h"
 | |
| 
 | |
| static ExtensionEntry	*dri2Extension;
 | |
| static RESTYPE		 dri2DrawableRes;
 | |
| 
 | |
| static Bool
 | |
| validDrawable(ClientPtr client, XID drawable,
 | |
| 	      DrawablePtr *pDrawable, int *status)
 | |
| {
 | |
|     *status = dixLookupDrawable(pDrawable, drawable, client, 0, DixReadAccess);
 | |
|     if (*status != Success) {
 | |
| 	client->errorValue = drawable;
 | |
| 	return FALSE;
 | |
|     }
 | |
| 
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| static int
 | |
| ProcDRI2QueryVersion(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xDRI2QueryVersionReq);
 | |
|     xDRI2QueryVersionReply rep;
 | |
|     int n;
 | |
| 
 | |
|     if (client->swapped)
 | |
| 	swaps(&stuff->length, n);
 | |
| 
 | |
|     REQUEST_SIZE_MATCH(xDRI2QueryVersionReq);
 | |
|     rep.type = X_Reply;
 | |
|     rep.length = 0;
 | |
|     rep.sequenceNumber = client->sequence;
 | |
|     rep.majorVersion = DRI2_MAJOR;
 | |
|     rep.minorVersion = DRI2_MINOR;
 | |
| 
 | |
|     if (client->swapped) {
 | |
|     	swaps(&rep.sequenceNumber, n);
 | |
|     	swapl(&rep.length, n);
 | |
| 	swapl(&rep.majorVersion, n);
 | |
| 	swapl(&rep.minorVersion, n);
 | |
|     }
 | |
| 
 | |
|     WriteToClient(client, sizeof(xDRI2QueryVersionReply), &rep);
 | |
| 
 | |
|     return client->noClientException;
 | |
| }
 | |
| 
 | |
| static int
 | |
| ProcDRI2Connect(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xDRI2ConnectReq);
 | |
|     xDRI2ConnectReply rep;
 | |
|     DrawablePtr pDraw;
 | |
|     int fd, status;
 | |
|     const char *driverName;
 | |
|     const char *deviceName;
 | |
| 
 | |
|     REQUEST_SIZE_MATCH(xDRI2ConnectReq);
 | |
|     if (!validDrawable(client, stuff->window, &pDraw, &status))
 | |
| 	return status;
 | |
|     
 | |
|     rep.type = X_Reply;
 | |
|     rep.length = 0;
 | |
|     rep.sequenceNumber = client->sequence;
 | |
|     rep.driverNameLength = 0;
 | |
|     rep.deviceNameLength = 0;
 | |
| 
 | |
|     if (!DRI2Connect(pDraw->pScreen,
 | |
| 		     stuff->driverType, &fd, &driverName, &deviceName))
 | |
| 	goto fail;
 | |
| 
 | |
|     rep.driverNameLength = strlen(driverName);
 | |
|     rep.deviceNameLength = strlen(deviceName);
 | |
|     rep.length = (rep.driverNameLength + 3) / 4 +
 | |
| 	    (rep.deviceNameLength + 3) / 4;
 | |
| 
 | |
|  fail:
 | |
|     WriteToClient(client, sizeof(xDRI2ConnectReply), &rep);
 | |
|     WriteToClient(client, rep.driverNameLength, driverName);
 | |
|     WriteToClient(client, rep.deviceNameLength, deviceName);
 | |
| 
 | |
|     return client->noClientException;
 | |
| }
 | |
| 
 | |
| static int
 | |
| ProcDRI2Authenticate(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xDRI2AuthenticateReq);
 | |
|     xDRI2AuthenticateReply rep;
 | |
|     DrawablePtr pDraw;
 | |
|     int status;
 | |
| 
 | |
|     REQUEST_SIZE_MATCH(xDRI2AuthenticateReq);
 | |
|     if (!validDrawable(client, stuff->window, &pDraw, &status))
 | |
| 	return status;
 | |
| 
 | |
|     rep.type = X_Reply;
 | |
|     rep.sequenceNumber = client->sequence;
 | |
|     rep.length = 0;
 | |
|     rep.authenticated = DRI2Authenticate(pDraw->pScreen, stuff->magic);
 | |
|     WriteToClient(client, sizeof(xDRI2AuthenticateReply), &rep);
 | |
| 
 | |
|     return client->noClientException;
 | |
| }
 | |
| 
 | |
| static int
 | |
| ProcDRI2CreateDrawable(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xDRI2CreateDrawableReq);
 | |
|     DrawablePtr pDrawable;
 | |
|     int status;
 | |
| 
 | |
|     REQUEST_SIZE_MATCH(xDRI2CreateDrawableReq);
 | |
| 
 | |
|     if (!validDrawable(client, stuff->drawable, &pDrawable, &status))
 | |
| 	return status;
 | |
| 
 | |
|     status = DRI2CreateDrawable(pDrawable);
 | |
|     if (status != Success)
 | |
| 	return status;
 | |
| 
 | |
|     if (!AddResource(stuff->drawable, dri2DrawableRes, pDrawable)) {
 | |
| 	DRI2DestroyDrawable(pDrawable);
 | |
| 	return BadAlloc;
 | |
|     }
 | |
| 
 | |
|     return client->noClientException;
 | |
| }
 | |
| 
 | |
| static int
 | |
| ProcDRI2DestroyDrawable(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xDRI2DestroyDrawableReq);
 | |
|     DrawablePtr pDrawable;
 | |
|     int status;
 | |
| 
 | |
|     REQUEST_SIZE_MATCH(xDRI2DestroyDrawableReq);
 | |
|     if (!validDrawable(client, stuff->drawable, &pDrawable, &status))
 | |
| 	return status;
 | |
| 
 | |
|     FreeResourceByType(stuff->drawable, dri2DrawableRes, FALSE);
 | |
| 
 | |
|     return client->noClientException;
 | |
| }
 | |
| 
 | |
| static int
 | |
| ProcDRI2GetBuffers(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xDRI2GetBuffersReq);
 | |
|     xDRI2GetBuffersReply rep;
 | |
|     DrawablePtr pDrawable;
 | |
|     DRI2BufferPtr buffers;
 | |
|     int i, status, width, height, count;
 | |
|     unsigned int *attachments;
 | |
|     xDRI2Buffer buffer;
 | |
| 
 | |
|     REQUEST_FIXED_SIZE(xDRI2GetBuffersReq, stuff->count * 4);
 | |
|     if (!validDrawable(client, stuff->drawable, &pDrawable, &status))
 | |
| 	return status;
 | |
| 
 | |
|     attachments = (unsigned int *) &stuff[1];
 | |
|     buffers = DRI2GetBuffers(pDrawable, &width, &height,
 | |
| 			     attachments, stuff->count, &count);
 | |
| 
 | |
|     rep.type = X_Reply;
 | |
|     rep.length = count * sizeof(xDRI2Buffer) / 4;
 | |
|     rep.sequenceNumber = client->sequence;
 | |
|     rep.width = width;
 | |
|     rep.height = height;
 | |
|     rep.count = count;
 | |
|     WriteToClient(client, sizeof(xDRI2GetBuffersReply), &rep);
 | |
| 
 | |
|     for (i = 0; i < count; i++) {
 | |
| 	buffer.attachment = buffers[i].attachment;
 | |
| 	buffer.name = buffers[i].name;
 | |
| 	buffer.pitch = buffers[i].pitch;
 | |
| 	buffer.cpp = buffers[i].cpp;
 | |
| 	buffer.flags = buffers[i].flags;
 | |
| 	WriteToClient(client, sizeof(xDRI2Buffer), &buffer);
 | |
|     }
 | |
| 
 | |
|     return client->noClientException;
 | |
| }
 | |
| 
 | |
| static int
 | |
| ProcDRI2CopyRegion(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xDRI2CopyRegionReq);
 | |
|     xDRI2CopyRegionReply rep;
 | |
|     DrawablePtr pDrawable;
 | |
|     int status;
 | |
|     RegionPtr pRegion;
 | |
| 
 | |
|     REQUEST_SIZE_MATCH(xDRI2CopyRegionReq);
 | |
| 
 | |
|     if (!validDrawable(client, stuff->drawable, &pDrawable, &status))
 | |
| 	return status;
 | |
| 
 | |
|     VERIFY_REGION(pRegion, stuff->region, client, DixReadAccess);
 | |
| 
 | |
|     status = DRI2CopyRegion(pDrawable, pRegion, stuff->dest, stuff->src);
 | |
|     if (status != Success)
 | |
| 	return status;
 | |
| 
 | |
|     /* CopyRegion needs to be a round trip to make sure the X server
 | |
|      * queues the swap buffer rendering commands before the DRI client
 | |
|      * continues rendering.  The reply has a bitmask to signal the
 | |
|      * presense of optional return values as well, but we're not using
 | |
|      * that yet.
 | |
|      */
 | |
| 
 | |
|     rep.type = X_Reply;
 | |
|     rep.length = 0;
 | |
|     rep.sequenceNumber = client->sequence;
 | |
| 
 | |
|     WriteToClient(client, sizeof(xDRI2CopyRegionReply), &rep);
 | |
| 
 | |
|     return client->noClientException;
 | |
| }
 | |
| 
 | |
| static int
 | |
| ProcDRI2Dispatch (ClientPtr client)
 | |
| {
 | |
|     REQUEST(xReq);
 | |
|     
 | |
|     switch (stuff->data) {
 | |
|     case X_DRI2QueryVersion:
 | |
| 	return ProcDRI2QueryVersion(client);
 | |
|     }
 | |
| 
 | |
|     if (!LocalClient(client))
 | |
| 	return BadRequest;
 | |
| 
 | |
|     switch (stuff->data) {
 | |
|     case X_DRI2Connect:
 | |
| 	return ProcDRI2Connect(client);
 | |
|     case X_DRI2Authenticate:
 | |
| 	return ProcDRI2Authenticate(client);
 | |
|     case X_DRI2CreateDrawable:
 | |
| 	return ProcDRI2CreateDrawable(client);
 | |
|     case X_DRI2DestroyDrawable:
 | |
| 	return ProcDRI2DestroyDrawable(client);
 | |
|     case X_DRI2GetBuffers:
 | |
| 	return ProcDRI2GetBuffers(client);
 | |
|     case X_DRI2CopyRegion:
 | |
| 	return ProcDRI2CopyRegion(client);
 | |
|     default:
 | |
| 	return BadRequest;
 | |
|     }
 | |
| }
 | |
| 
 | |
| static int
 | |
| SProcDRI2Connect(ClientPtr client)
 | |
| {
 | |
|     REQUEST(xDRI2ConnectReq);
 | |
|     xDRI2ConnectReply rep;
 | |
|     int n;
 | |
| 
 | |
|     /* If the client is swapped, it's not local.  Talk to the hand. */
 | |
| 
 | |
|     swaps(&stuff->length, n);
 | |
|     if (sizeof(*stuff) / 4 != client->req_len)
 | |
| 	return BadLength;
 | |
| 
 | |
|     rep.sequenceNumber = client->sequence;
 | |
|     swaps(&rep.sequenceNumber, n);
 | |
|     rep.length = 0;
 | |
|     rep.driverNameLength = 0;
 | |
|     rep.deviceNameLength = 0;
 | |
| 
 | |
|     return client->noClientException;
 | |
| }
 | |
| 
 | |
| static int
 | |
| SProcDRI2Dispatch (ClientPtr client)
 | |
| {
 | |
|     REQUEST(xReq);
 | |
| 
 | |
|     /*
 | |
|      * Only local clients are allowed DRI access, but remote clients
 | |
|      * still need these requests to find out cleanly.
 | |
|      */
 | |
|     switch (stuff->data)
 | |
|     {
 | |
|     case X_DRI2QueryVersion:
 | |
| 	return ProcDRI2QueryVersion(client);
 | |
|     case X_DRI2Connect:
 | |
| 	return SProcDRI2Connect(client);
 | |
|     default:
 | |
| 	return BadRequest;
 | |
|     }
 | |
| }
 | |
| 
 | |
| static int DRI2DrawableGone(pointer p, XID id)
 | |
| {
 | |
|     DrawablePtr pDrawable = p;
 | |
| 
 | |
|     DRI2DestroyDrawable(pDrawable);
 | |
| 
 | |
|     return Success;
 | |
| }
 | |
| 
 | |
| static void
 | |
| DRI2ExtensionInit(void)
 | |
| {
 | |
|     dri2Extension = AddExtension(DRI2_NAME,
 | |
| 				 DRI2NumberEvents,
 | |
| 				 DRI2NumberErrors,
 | |
| 				 ProcDRI2Dispatch,
 | |
| 				 SProcDRI2Dispatch,
 | |
| 				 NULL,
 | |
| 				 StandardMinorOpcode);
 | |
| 
 | |
|     dri2DrawableRes = CreateNewResourceType(DRI2DrawableGone);
 | |
| }
 | |
| 
 | |
| extern Bool noDRI2Extension;
 | |
| 
 | |
| _X_HIDDEN ExtensionModule dri2ExtensionModule = {
 | |
|     DRI2ExtensionInit,
 | |
|     DRI2_NAME,
 | |
|     &noDRI2Extension,
 | |
|     NULL,
 | |
|     NULL
 | |
| };
 |