xserver-multidpi/hw/kdrive/ephyr/ephyrdriext.c
Dodji Seketeli 6d1e44d3d5 Xephyr: fix a host X hang.
* hw/kdrive/ephyr/ephyrdri.c:
	  (ephyrDRIGetDrawableInfo): quickly hook
	  this into getting the drawable info from the host
	  X server. For the time being, this only gets the drawable info
	  of the Xephyr main window in the host. It should really get
	  the info of a the peer drawable in the host X. So there should be a
	  peer drawable to begin with.
	* hw/kdrive/ephyr/ephyrdriext.c:
	  (ProcXF86DRIGetDrawableInfo): some cleanups. Properly get the
          the drawable info otherwise there is a host X hang.
	* hw/kdrive/ephyr/ephyrhostglx.c: do not
	  (ephyrHostGLXQueryVersion): do not use C bindings of the glx protocol
	   calls. Some of those actually access DRI context directly, resulting
	   in the context having three clients. Instead all XF86DRI proto
	   fowarding request should be coded by hand and only forward the
	   protocol requests
2007-10-02 16:55:16 +02:00

727 lines
21 KiB
C

/*
* Xephyr - A kdrive X server thats runs in a host X window.
* Authored by Matthew Allum <mallum@openedhand.com>
*
* Copyright © 2007 OpenedHand Ltd
*
* 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 OpenedHand Ltd not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. OpenedHand Ltd makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* OpenedHand Ltd DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL OpenedHand Ltd 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.
*
* This file is heavily copied from hw/xfree86/dri/xf86dri.c
*
* Authors:
* Dodji Seketeli <dodji@openedhand.com>
*/
#ifdef HAVE_CONFIG_H
#include <kdrive-config.h>
#endif
#ifdef XEPHYR_DRI
#include <string.h>
#define NEED_REPLIES
#define NEED_EVENTS
#include <X11/X.h>
#include <X11/Xproto.h>
#define _XF86DRI_SERVER_
#include <X11/dri/xf86dri.h>
#include <X11/dri/xf86dristr.h>
#include "misc.h"
#include "dixstruct.h"
#include "extnsionst.h"
#include "colormapst.h"
#include "cursorstr.h"
#include "scrnintstr.h"
#include "servermd.h"
#include "swaprep.h"
#include "ephyrdri.h"
#define _HAVE_XALLOC_DECLS
#include "ephyrlog.h"
static int DRIErrorBase;
static DISPATCH_PROC(ProcXF86DRIQueryVersion);
static DISPATCH_PROC(ProcXF86DRIQueryDirectRenderingCapable);
static DISPATCH_PROC(ProcXF86DRIOpenConnection);
static DISPATCH_PROC(ProcXF86DRICloseConnection);
static DISPATCH_PROC(ProcXF86DRIGetClientDriverName);
static DISPATCH_PROC(ProcXF86DRICreateContext);
static DISPATCH_PROC(ProcXF86DRIDestroyContext);
static DISPATCH_PROC(ProcXF86DRICreateDrawable);
static DISPATCH_PROC(ProcXF86DRIDestroyDrawable);
static DISPATCH_PROC(ProcXF86DRIGetDrawableInfo);
static DISPATCH_PROC(ProcXF86DRIGetDeviceInfo);
static DISPATCH_PROC(ProcXF86DRIDispatch);
static DISPATCH_PROC(ProcXF86DRIAuthConnection);
static DISPATCH_PROC(SProcXF86DRIQueryVersion);
static DISPATCH_PROC(SProcXF86DRIQueryDirectRenderingCapable);
static DISPATCH_PROC(SProcXF86DRIDispatch);
static void XF86DRIResetProc(ExtensionEntry* extEntry);
static unsigned char DRIReqCode = 0;
extern void ephyrDRIExtensionInit(void);
void
ephyrDRIExtensionInit(void)
{
ExtensionEntry* extEntry;
EPHYR_LOG ("enter\n") ;
#ifdef XF86DRI_EVENTS
EventType = CreateNewResourceType(XF86DRIFreeEvents);
#endif
if ((extEntry = AddExtension(XF86DRINAME,
XF86DRINumberEvents,
XF86DRINumberErrors,
ProcXF86DRIDispatch,
SProcXF86DRIDispatch,
XF86DRIResetProc,
StandardMinorOpcode))) {
DRIReqCode = (unsigned char)extEntry->base;
DRIErrorBase = extEntry->errorBase;
}
EPHYR_LOG ("leave\n") ;
}
/*ARGSUSED*/
static void
XF86DRIResetProc (
ExtensionEntry* extEntry
)
{
}
static int
ProcXF86DRIQueryVersion (register ClientPtr client)
{
xXF86DRIQueryVersionReply rep;
register int n;
EPHYR_LOG ("enter\n") ;
REQUEST_SIZE_MATCH(xXF86DRIQueryVersionReq);
rep.type = X_Reply;
rep.length = 0;
rep.sequenceNumber = client->sequence;
rep.majorVersion = XF86DRI_MAJOR_VERSION;
rep.minorVersion = XF86DRI_MINOR_VERSION;
rep.patchVersion = XF86DRI_PATCH_VERSION;
if (client->swapped) {
swaps(&rep.sequenceNumber, n);
swapl(&rep.length, n);
swaps(&rep.majorVersion, n);
swaps(&rep.minorVersion, n);
swapl(&rep.patchVersion, n);
}
WriteToClient(client, sizeof(xXF86DRIQueryVersionReply), (char *)&rep);
EPHYR_LOG ("leave\n") ;
return (client->noClientException);
}
static int
ProcXF86DRIQueryDirectRenderingCapable (register ClientPtr client)
{
xXF86DRIQueryDirectRenderingCapableReply rep;
Bool isCapable;
register int n;
EPHYR_LOG ("enter\n") ;
REQUEST(xXF86DRIQueryDirectRenderingCapableReq);
REQUEST_SIZE_MATCH(xXF86DRIQueryDirectRenderingCapableReq);
if (stuff->screen >= screenInfo.numScreens) {
client->errorValue = stuff->screen;
return BadValue;
}
rep.type = X_Reply;
rep.length = 0;
rep.sequenceNumber = client->sequence;
if (!ephyrDRIQueryDirectRenderingCapable (stuff->screen, &isCapable)) {
return BadValue;
}
rep.isCapable = isCapable;
if (!LocalClient(client) || client->swapped)
rep.isCapable = 0;
if (client->swapped) {
swaps(&rep.sequenceNumber, n);
swapl(&rep.length, n);
}
WriteToClient(client, sizeof(xXF86DRIQueryDirectRenderingCapableReply), (char *)&rep);
EPHYR_LOG ("leave\n") ;
return (client->noClientException);
}
static int
ProcXF86DRIOpenConnection (register ClientPtr client)
{
xXF86DRIOpenConnectionReply rep;
drm_handle_t hSAREA;
char* busIdString;
EPHYR_LOG ("enter\n") ;
REQUEST(xXF86DRIOpenConnectionReq);
REQUEST_SIZE_MATCH(xXF86DRIOpenConnectionReq);
if (stuff->screen >= screenInfo.numScreens) {
client->errorValue = stuff->screen;
return BadValue;
}
if (!ephyrDRIOpenConnection(stuff->screen,
&hSAREA,
&busIdString)) {
return BadValue;
}
rep.type = X_Reply;
rep.sequenceNumber = client->sequence;
rep.busIdStringLength = 0;
if (busIdString)
rep.busIdStringLength = strlen(busIdString);
rep.length = (SIZEOF(xXF86DRIOpenConnectionReply) - SIZEOF(xGenericReply) +
((rep.busIdStringLength + 3) & ~3)) >> 2;
rep.hSAREALow = (CARD32)(hSAREA & 0xffffffff);
#if defined(LONG64) && !defined(__linux__)
rep.hSAREAHigh = (CARD32)(hSAREA >> 32);
#else
rep.hSAREAHigh = 0;
#endif
WriteToClient(client, sizeof(xXF86DRIOpenConnectionReply), (char *)&rep);
if (rep.busIdStringLength)
WriteToClient(client, rep.busIdStringLength, busIdString);
EPHYR_LOG ("leave\n") ;
return (client->noClientException);
}
static int
ProcXF86DRIAuthConnection (register ClientPtr client)
{
xXF86DRIAuthConnectionReply rep;
EPHYR_LOG ("enter\n") ;
REQUEST(xXF86DRIAuthConnectionReq);
REQUEST_SIZE_MATCH(xXF86DRIAuthConnectionReq);
if (stuff->screen >= screenInfo.numScreens) {
client->errorValue = stuff->screen;
return BadValue;
}
rep.type = X_Reply;
rep.length = 0;
rep.sequenceNumber = client->sequence;
rep.authenticated = 1;
if (!ephyrDRIAuthConnection (stuff->screen, stuff->magic)) {
ErrorF("Failed to authenticate %lu\n", (unsigned long)stuff->magic);
rep.authenticated = 0;
}
WriteToClient(client, sizeof(xXF86DRIAuthConnectionReply), (char *)&rep);
EPHYR_LOG ("leave\n") ;
return (client->noClientException);
}
static int
ProcXF86DRICloseConnection (register ClientPtr client)
{
EPHYR_LOG ("enter\n") ;
REQUEST(xXF86DRICloseConnectionReq);
REQUEST_SIZE_MATCH(xXF86DRICloseConnectionReq);
if (stuff->screen >= screenInfo.numScreens) {
client->errorValue = stuff->screen;
return BadValue;
}
/*
DRICloseConnection( screenInfo.screens[stuff->screen]);
*/
EPHYR_LOG ("leave\n") ;
return (client->noClientException);
}
static int
ProcXF86DRIGetClientDriverName (register ClientPtr client)
{
xXF86DRIGetClientDriverNameReply rep;
char* clientDriverName;
EPHYR_LOG ("enter\n") ;
REQUEST(xXF86DRIGetClientDriverNameReq);
REQUEST_SIZE_MATCH(xXF86DRIGetClientDriverNameReq);
if (stuff->screen >= screenInfo.numScreens) {
client->errorValue = stuff->screen;
return BadValue;
}
ephyrDRIGetClientDriverName (stuff->screen,
(int *)&rep.ddxDriverMajorVersion,
(int *)&rep.ddxDriverMinorVersion,
(int *)&rep.ddxDriverPatchVersion,
&clientDriverName);
rep.type = X_Reply;
rep.sequenceNumber = client->sequence;
rep.clientDriverNameLength = 0;
if (clientDriverName)
rep.clientDriverNameLength = strlen(clientDriverName);
rep.length = (SIZEOF(xXF86DRIGetClientDriverNameReply) -
SIZEOF(xGenericReply) +
((rep.clientDriverNameLength + 3) & ~3)) >> 2;
WriteToClient(client,
sizeof(xXF86DRIGetClientDriverNameReply), (char *)&rep);
if (rep.clientDriverNameLength)
WriteToClient(client,
rep.clientDriverNameLength,
clientDriverName);
EPHYR_LOG ("leave\n") ;
return (client->noClientException);
}
static int
ProcXF86DRICreateContext (register ClientPtr client)
{
xXF86DRICreateContextReply rep;
ScreenPtr pScreen;
VisualPtr visual;
int i;
EPHYR_LOG ("enter\n") ;
REQUEST(xXF86DRICreateContextReq);
REQUEST_SIZE_MATCH(xXF86DRICreateContextReq);
if (stuff->screen >= screenInfo.numScreens) {
client->errorValue = stuff->screen;
return BadValue;
}
rep.type = X_Reply;
rep.length = 0;
rep.sequenceNumber = client->sequence;
pScreen = screenInfo.screens[stuff->screen];
visual = pScreen->visuals;
/* Find the requested X visual */
for (i = 0; i < pScreen->numVisuals; i++, visual++)
if (visual->vid == stuff->visual)
break;
if (i == pScreen->numVisuals) {
/* No visual found */
return BadValue;
}
/*
if (!DRICreateContext( pScreen,
visual,
stuff->context,
(drm_context_t *)&rep.hHWContext)) {
return BadValue;
}
*/
WriteToClient(client, sizeof(xXF86DRICreateContextReply), (char *)&rep);
EPHYR_LOG ("leave\n") ;
return (client->noClientException);
}
static int
ProcXF86DRIDestroyContext (register ClientPtr client)
{
EPHYR_LOG ("enter\n") ;
REQUEST(xXF86DRIDestroyContextReq);
REQUEST_SIZE_MATCH(xXF86DRIDestroyContextReq);
if (stuff->screen >= screenInfo.numScreens) {
client->errorValue = stuff->screen;
return BadValue;
}
/*
if (!DRIDestroyContext( screenInfo.screens[stuff->screen],
stuff->context)) {
return BadValue;
}
*/
EPHYR_LOG ("leave\n") ;
return (client->noClientException);
}
static int
ProcXF86DRICreateDrawable (ClientPtr client)
{
xXF86DRICreateDrawableReply rep;
DrawablePtr pDrawable;
int rc;
EPHYR_LOG ("enter\n") ;
REQUEST(xXF86DRICreateDrawableReq);
REQUEST_SIZE_MATCH(xXF86DRICreateDrawableReq);
if (stuff->screen >= screenInfo.numScreens) {
client->errorValue = stuff->screen;
return BadValue;
}
rep.type = X_Reply;
rep.length = 0;
rep.sequenceNumber = client->sequence;
rc = dixLookupDrawable (&pDrawable, stuff->drawable, client, 0,
DixReadAccess);
if (rc != Success)
return rc;
/*TODO: this cannot work. We must properly
* do the mapping between the xephyr drawable and
* the host drawable
*/
if (!ephyrDRICreateDrawable (stuff->screen,
0/*should be host drawableID*/,
(drm_drawable_t *)&rep.hHWDrawable)) {
return BadValue;
}
WriteToClient(client, sizeof(xXF86DRICreateDrawableReply), (char *)&rep);
EPHYR_LOG ("leave\n") ;
return (client->noClientException);
}
static int
ProcXF86DRIDestroyDrawable (register ClientPtr client)
{
REQUEST(xXF86DRIDestroyDrawableReq);
DrawablePtr pDrawable;
REQUEST_SIZE_MATCH(xXF86DRIDestroyDrawableReq);
int rc;
EPHYR_LOG ("enter\n") ;
if (stuff->screen >= screenInfo.numScreens) {
client->errorValue = stuff->screen;
return BadValue;
}
rc = dixLookupDrawable(&pDrawable,
stuff->drawable,
client,
0,
DixReadAccess);
if (rc != Success)
return rc;
if (!ephyrDRIDestroyDrawable(stuff->screen,
0/*should be drawable in host x*/)) {
return BadValue;
}
EPHYR_LOG ("leave\n") ;
return (client->noClientException);
}
static int
ProcXF86DRIGetDrawableInfo (register ClientPtr client)
{
xXF86DRIGetDrawableInfoReply rep;
DrawablePtr drawable;
int X=0, Y=0, W=0, H=0, backX=0, backY=0, rc=0;
drm_clip_rect_t *pClipRects=NULL, *pClippedRects=NULL;
drm_clip_rect_t *pBackClipRects=NULL;
EPHYR_LOG ("enter\n") ;
memset (&rep, 0, sizeof (rep)) ;
REQUEST(xXF86DRIGetDrawableInfoReq);
REQUEST_SIZE_MATCH(xXF86DRIGetDrawableInfoReq);
if (stuff->screen >= screenInfo.numScreens) {
client->errorValue = stuff->screen;
return BadValue;
}
rep.type = X_Reply;
rep.length = 0;
rep.sequenceNumber = client->sequence;
/*TODO: this cannot work.
* We must properly do the mapping
* between xephyr drawable and the host drawable
*/
rc = dixLookupDrawable(&drawable, stuff->drawable, client, 0,
DixReadAccess);
if (rc != Success)
return rc;
if (!ephyrDRIGetDrawableInfo (stuff->screen,
drawable/*should be the drawable in hostx*/,
(unsigned int*)&rep.drawableTableIndex,
(unsigned int*)&rep.drawableTableStamp,
(int*)&X,
(int*)&Y,
(int*)&W,
(int*)&H,
(int*)&rep.numClipRects,
&pClipRects,
&backX,
&backY,
(int*)&rep.numBackClipRects,
&pBackClipRects)) {
return BadValue;
}
rep.drawableX = X;
rep.drawableY = Y;
rep.drawableWidth = W;
rep.drawableHeight = H;
rep.length = (SIZEOF(xXF86DRIGetDrawableInfoReply) -
SIZEOF(xGenericReply));
rep.backX = backX;
rep.backY = backY;
if (rep.numBackClipRects)
rep.length += sizeof(drm_clip_rect_t) * rep.numBackClipRects;
pClippedRects = pClipRects;
if (rep.numClipRects) {
/* Clip cliprects to screen dimensions (redirected windows) */
pClippedRects = xalloc(rep.numClipRects * sizeof(drm_clip_rect_t));
if (pClippedRects) {
ScreenPtr pScreen = screenInfo.screens[stuff->screen];
int i, j;
for (i = 0, j = 0; i < rep.numClipRects; i++) {
pClippedRects[j].x1 = max(pClipRects[i].x1, 0);
pClippedRects[j].y1 = max(pClipRects[i].y1, 0);
pClippedRects[j].x2 = min(pClipRects[i].x2, pScreen->width);
pClippedRects[j].y2 = min(pClipRects[i].y2, pScreen->height);
if (pClippedRects[j].x1 < pClippedRects[j].x2 &&
pClippedRects[j].y1 < pClippedRects[j].y2) {
j++;
}
}
rep.numClipRects = j;
} else {
rep.numClipRects = 0;
}
rep.length += sizeof(drm_clip_rect_t) * rep.numClipRects;
}
rep.length = ((rep.length + 3) & ~3) >> 2;
WriteToClient(client, sizeof(xXF86DRIGetDrawableInfoReply), (char *)&rep);
if (rep.numClipRects) {
WriteToClient(client,
sizeof(drm_clip_rect_t) * rep.numClipRects,
(char *)pClippedRects);
xfree(pClippedRects);
}
if (rep.numBackClipRects) {
WriteToClient(client,
sizeof(drm_clip_rect_t) * rep.numBackClipRects,
(char *)pBackClipRects);
}
EPHYR_LOG ("leave\n") ;
return (client->noClientException);
}
static int
ProcXF86DRIGetDeviceInfo (register ClientPtr client)
{
xXF86DRIGetDeviceInfoReply rep;
drm_handle_t hFrameBuffer;
void *pDevPrivate;
EPHYR_LOG ("enter\n") ;
REQUEST(xXF86DRIGetDeviceInfoReq);
REQUEST_SIZE_MATCH(xXF86DRIGetDeviceInfoReq);
if (stuff->screen >= screenInfo.numScreens) {
client->errorValue = stuff->screen;
return BadValue;
}
rep.type = X_Reply;
rep.length = 0;
rep.sequenceNumber = client->sequence;
if (!ephyrDRIGetDeviceInfo (stuff->screen,
&hFrameBuffer,
(int*)&rep.framebufferOrigin,
(int*)&rep.framebufferSize,
(int*)&rep.framebufferStride,
(int*)&rep.devPrivateSize,
&pDevPrivate)) {
return BadValue;
}
rep.hFrameBufferLow = (CARD32)(hFrameBuffer & 0xffffffff);
#if defined(LONG64) && !defined(__linux__)
rep.hFrameBufferHigh = (CARD32)(hFrameBuffer >> 32);
#else
rep.hFrameBufferHigh = 0;
#endif
rep.length = 0;
if (rep.devPrivateSize) {
rep.length = (SIZEOF(xXF86DRIGetDeviceInfoReply) -
SIZEOF(xGenericReply) +
((rep.devPrivateSize + 3) & ~3)) >> 2;
}
WriteToClient(client, sizeof(xXF86DRIGetDeviceInfoReply), (char *)&rep);
if (rep.length) {
WriteToClient(client, rep.devPrivateSize, (char *)pDevPrivate);
}
EPHYR_LOG ("leave\n") ;
return (client->noClientException);
}
static int
ProcXF86DRIDispatch (register ClientPtr client)
{
REQUEST(xReq);
EPHYR_LOG ("enter\n") ;
switch (stuff->data)
{
case X_XF86DRIQueryVersion: {
EPHYR_LOG ("leave\n") ;
return ProcXF86DRIQueryVersion(client);
}
case X_XF86DRIQueryDirectRenderingCapable: {
EPHYR_LOG ("leave\n") ;
return ProcXF86DRIQueryDirectRenderingCapable(client);
}
}
if (!LocalClient(client))
return DRIErrorBase + XF86DRIClientNotLocal;
switch (stuff->data)
{
case X_XF86DRIOpenConnection: {
EPHYR_LOG ("leave\n") ;
return ProcXF86DRIOpenConnection(client);
}
case X_XF86DRICloseConnection: {
EPHYR_LOG ("leave\n") ;
return ProcXF86DRICloseConnection(client);
}
case X_XF86DRIGetClientDriverName: {
EPHYR_LOG ("leave\n") ;
return ProcXF86DRIGetClientDriverName(client);
}
case X_XF86DRICreateContext: {
EPHYR_LOG ("leave\n") ;
return ProcXF86DRICreateContext(client);
}
case X_XF86DRIDestroyContext: {
EPHYR_LOG ("leave\n") ;
return ProcXF86DRIDestroyContext(client);
}
case X_XF86DRICreateDrawable: {
EPHYR_LOG ("leave\n") ;
return ProcXF86DRICreateDrawable(client);
}
case X_XF86DRIDestroyDrawable: {
EPHYR_LOG ("leave\n") ;
return ProcXF86DRIDestroyDrawable(client);
}
case X_XF86DRIGetDrawableInfo: {
EPHYR_LOG ("leave\n") ;
return ProcXF86DRIGetDrawableInfo(client);
}
case X_XF86DRIGetDeviceInfo: {
EPHYR_LOG ("leave\n") ;
return ProcXF86DRIGetDeviceInfo(client);
}
case X_XF86DRIAuthConnection: {
EPHYR_LOG ("leave\n") ;
return ProcXF86DRIAuthConnection(client);
}
/* {Open,Close}FullScreen are deprecated now */
default: {
EPHYR_LOG ("leave\n") ;
return BadRequest;
}
}
}
static int
SProcXF86DRIQueryVersion (register ClientPtr client)
{
register int n;
REQUEST(xXF86DRIQueryVersionReq);
swaps(&stuff->length, n);
return ProcXF86DRIQueryVersion(client);
}
static int
SProcXF86DRIQueryDirectRenderingCapable (register ClientPtr client)
{
register int n;
REQUEST(xXF86DRIQueryDirectRenderingCapableReq);
swaps(&stuff->length, n);
swapl(&stuff->screen, n);
return ProcXF86DRIQueryDirectRenderingCapable(client);
}
static int
SProcXF86DRIDispatch (register ClientPtr client)
{
REQUEST(xReq);
EPHYR_LOG ("enter\n") ;
/*
* Only local clients are allowed DRI access, but remote clients still need
* these requests to find out cleanly.
*/
switch (stuff->data)
{
case X_XF86DRIQueryVersion: {
EPHYR_LOG ("leave\n") ;
return SProcXF86DRIQueryVersion(client);
}
case X_XF86DRIQueryDirectRenderingCapable: {
EPHYR_LOG ("leave\n") ;
return SProcXF86DRIQueryDirectRenderingCapable(client);
}
default: {
EPHYR_LOG ("leave\n") ;
return DRIErrorBase + XF86DRIClientNotLocal;
}
}
}
#endif /*XEPHYR_DRI*/