/* * 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 #include <string.h> #include <X11/X.h> #include <X11/Xproto.h> #define _XF86DRI_SERVER_ #include <X11/dri/xf86dri.h> #include <X11/dri/xf86driproto.h> #include "misc.h" #include "privates.h" #include "dixstruct.h" #include "extnsionst.h" #include "colormapst.h" #include "cursorstr.h" #include "scrnintstr.h" #include "windowstr.h" #include "servermd.h" #include "swaprep.h" #include "ephyrdri.h" #include "ephyrdriext.h" #include "hostx.h" #define _HAVE_XALLOC_DECLS #include "ephyrlog.h" #include "protocol-versions.h" typedef struct { int foo; } EphyrDRIWindowPrivRec; typedef EphyrDRIWindowPrivRec* EphyrDRIWindowPrivPtr; typedef struct { CreateWindowProcPtr CreateWindow ; DestroyWindowProcPtr DestroyWindow ; MoveWindowProcPtr MoveWindow ; PositionWindowProcPtr PositionWindow ; ClipNotifyProcPtr ClipNotify ; } EphyrDRIScreenPrivRec; typedef EphyrDRIScreenPrivRec* EphyrDRIScreenPrivPtr; static int DRIErrorBase; static Bool ephyrDRIScreenInit (ScreenPtr a_screen) ; static Bool ephyrDRICreateWindow (WindowPtr a_win) ; static Bool ephyrDRIDestroyWindow (WindowPtr a_win) ; static void ephyrDRIMoveWindow (WindowPtr a_win, int a_x, int a_y, WindowPtr a_siblings, VTKind a_kind); static Bool ephyrDRIPositionWindow (WindowPtr a_win, int x, int y) ; static void ephyrDRIClipNotify (WindowPtr a_win, int a_x, int a_y) ; static Bool EphyrMirrorHostVisuals (ScreenPtr a_screen) ; static Bool destroyHostPeerWindow (const WindowPtr a_win) ; static Bool findWindowPairFromLocal (WindowPtr a_local, EphyrWindowPair **a_pair); static unsigned char DRIReqCode = 0; static DevPrivateKeyRec ephyrDRIWindowKeyRec; #define ephyrDRIWindowKey (&ephyrDRIWindowKeyRec) static DevPrivateKeyRec ephyrDRIScreenKeyRec; #define ephyrDRIScreenKey (&ephyrDRIScreenKeyRec) #define GET_EPHYR_DRI_WINDOW_PRIV(win) ((EphyrDRIWindowPrivPtr) \ dixLookupPrivate(&(win)->devPrivates, ephyrDRIWindowKey)) #define GET_EPHYR_DRI_SCREEN_PRIV(screen) ((EphyrDRIScreenPrivPtr) \ dixLookupPrivate(&(screen)->devPrivates, ephyrDRIScreenKey)) static Bool ephyrDRIScreenInit (ScreenPtr a_screen) { Bool is_ok=FALSE ; EphyrDRIScreenPrivPtr screen_priv=NULL ; EPHYR_RETURN_VAL_IF_FAIL (a_screen, FALSE) ; screen_priv=GET_EPHYR_DRI_SCREEN_PRIV (a_screen) ; EPHYR_RETURN_VAL_IF_FAIL (screen_priv, FALSE) ; screen_priv->CreateWindow = a_screen->CreateWindow ; screen_priv->DestroyWindow = a_screen->DestroyWindow ; screen_priv->MoveWindow = a_screen->MoveWindow ; screen_priv->PositionWindow = a_screen->PositionWindow ; screen_priv->ClipNotify = a_screen->ClipNotify ; a_screen->CreateWindow = ephyrDRICreateWindow ; a_screen->DestroyWindow = ephyrDRIDestroyWindow ; a_screen->MoveWindow = ephyrDRIMoveWindow ; a_screen->PositionWindow = ephyrDRIPositionWindow ; a_screen->ClipNotify = ephyrDRIClipNotify ; is_ok = TRUE ; return is_ok ; } static Bool ephyrDRICreateWindow (WindowPtr a_win) { Bool is_ok=FALSE ; ScreenPtr screen=NULL ; EphyrDRIScreenPrivPtr screen_priv =NULL; EPHYR_RETURN_VAL_IF_FAIL (a_win, FALSE) ; screen = a_win->drawable.pScreen ; EPHYR_RETURN_VAL_IF_FAIL (screen, FALSE) ; screen_priv = GET_EPHYR_DRI_SCREEN_PRIV (screen) ; EPHYR_RETURN_VAL_IF_FAIL (screen_priv && screen_priv->CreateWindow, FALSE) ; EPHYR_LOG ("enter. win:%p\n", a_win) ; screen->CreateWindow = screen_priv->CreateWindow ; is_ok = (*screen->CreateWindow) (a_win) ; screen->CreateWindow = ephyrDRICreateWindow ; if (is_ok) { dixSetPrivate(&a_win->devPrivates, ephyrDRIWindowKey, NULL); } return is_ok ; } static Bool ephyrDRIDestroyWindow (WindowPtr a_win) { Bool is_ok=FALSE ; ScreenPtr screen=NULL ; EphyrDRIScreenPrivPtr screen_priv =NULL; EPHYR_RETURN_VAL_IF_FAIL (a_win, FALSE) ; screen = a_win->drawable.pScreen ; EPHYR_RETURN_VAL_IF_FAIL (screen, FALSE) ; screen_priv = GET_EPHYR_DRI_SCREEN_PRIV (screen) ; EPHYR_RETURN_VAL_IF_FAIL (screen_priv && screen_priv->DestroyWindow, FALSE) ; screen->DestroyWindow = screen_priv->DestroyWindow ; if (screen->DestroyWindow) { is_ok = (*screen->DestroyWindow) (a_win) ; } screen->DestroyWindow = ephyrDRIDestroyWindow ; if (is_ok) { EphyrDRIWindowPrivPtr win_priv=GET_EPHYR_DRI_WINDOW_PRIV (a_win) ; if (win_priv) { destroyHostPeerWindow (a_win) ; free(win_priv) ; dixSetPrivate(&a_win->devPrivates, ephyrDRIWindowKey, NULL); EPHYR_LOG ("destroyed the remote peer window\n") ; } } return is_ok ; } static void ephyrDRIMoveWindow (WindowPtr a_win, int a_x, int a_y, WindowPtr a_siblings, VTKind a_kind) { Bool is_ok=FALSE ; ScreenPtr screen=NULL ; EphyrDRIScreenPrivPtr screen_priv =NULL; EphyrDRIWindowPrivPtr win_priv=NULL ; EphyrWindowPair *pair=NULL ; EphyrBox geo; int x=0,y=0;/*coords relative to parent window*/ EPHYR_RETURN_IF_FAIL (a_win) ; EPHYR_LOG ("enter\n") ; screen = a_win->drawable.pScreen ; EPHYR_RETURN_IF_FAIL (screen) ; screen_priv = GET_EPHYR_DRI_SCREEN_PRIV (screen) ; EPHYR_RETURN_IF_FAIL (screen_priv && screen_priv->MoveWindow) ; screen->MoveWindow = screen_priv->MoveWindow ; if (screen->MoveWindow) { (*screen->MoveWindow) (a_win, a_x, a_y, a_siblings, a_kind) ; } screen->MoveWindow = ephyrDRIMoveWindow ; EPHYR_LOG ("window: %p\n", a_win) ; if (!a_win->parent) { EPHYR_LOG ("cannot move root window\n") ; is_ok = TRUE ; goto out ; } win_priv = GET_EPHYR_DRI_WINDOW_PRIV (a_win) ; if (!win_priv) { EPHYR_LOG ("not a DRI peered window\n") ; is_ok = TRUE ; goto out ; } if (!findWindowPairFromLocal (a_win, &pair) || !pair) { EPHYR_LOG_ERROR ("failed to get window pair\n") ; goto out ; } /*compute position relative to parent window*/ x = a_win->drawable.x - a_win->parent->drawable.x ; y = a_win->drawable.y - a_win->parent->drawable.y ; /*set the geometry to pass to hostx_set_window_geometry*/ memset (&geo, 0, sizeof (geo)) ; geo.x = x ; geo.y = y ; geo.width = a_win->drawable.width ; geo.height = a_win->drawable.height ; hostx_set_window_geometry (pair->remote, &geo) ; is_ok = TRUE ; out: EPHYR_LOG ("leave. is_ok:%d\n", is_ok) ; /*do cleanup here*/ } static Bool ephyrDRIPositionWindow (WindowPtr a_win, int a_x, int a_y) { Bool is_ok=FALSE ; ScreenPtr screen=NULL ; EphyrDRIScreenPrivPtr screen_priv =NULL; EphyrDRIWindowPrivPtr win_priv=NULL ; EphyrWindowPair *pair=NULL ; EphyrBox geo; EPHYR_RETURN_VAL_IF_FAIL (a_win, FALSE) ; EPHYR_LOG ("enter\n") ; screen = a_win->drawable.pScreen ; EPHYR_RETURN_VAL_IF_FAIL (screen, FALSE) ; screen_priv = GET_EPHYR_DRI_SCREEN_PRIV (screen) ; EPHYR_RETURN_VAL_IF_FAIL (screen_priv && screen_priv->PositionWindow, FALSE) ; screen->PositionWindow = screen_priv->PositionWindow ; if (screen->PositionWindow) { (*screen->PositionWindow) (a_win, a_x, a_y) ; } screen->PositionWindow = ephyrDRIPositionWindow ; EPHYR_LOG ("window: %p\n", a_win) ; win_priv = GET_EPHYR_DRI_WINDOW_PRIV (a_win) ; if (!win_priv) { EPHYR_LOG ("not a DRI peered window\n") ; is_ok = TRUE ; goto out ; } if (!findWindowPairFromLocal (a_win, &pair) || !pair) { EPHYR_LOG_ERROR ("failed to get window pair\n") ; goto out ; } /*set the geometry to pass to hostx_set_window_geometry*/ memset (&geo, 0, sizeof (geo)) ; geo.x = a_x ; geo.y = a_y ; geo.width = a_win->drawable.width ; geo.height = a_win->drawable.height ; hostx_set_window_geometry (pair->remote, &geo) ; is_ok = TRUE ; out: EPHYR_LOG ("leave. is_ok:%d\n", is_ok) ; /*do cleanup here*/ return is_ok ; } static void ephyrDRIClipNotify (WindowPtr a_win, int a_x, int a_y) { Bool is_ok=FALSE ; ScreenPtr screen=NULL ; EphyrDRIScreenPrivPtr screen_priv =NULL; EphyrDRIWindowPrivPtr win_priv=NULL ; EphyrWindowPair *pair=NULL ; EphyrRect *rects=NULL; int i=0 ; EPHYR_RETURN_IF_FAIL (a_win) ; EPHYR_LOG ("enter\n") ; screen = a_win->drawable.pScreen ; EPHYR_RETURN_IF_FAIL (screen) ; screen_priv = GET_EPHYR_DRI_SCREEN_PRIV (screen) ; EPHYR_RETURN_IF_FAIL (screen_priv && screen_priv->ClipNotify) ; screen->ClipNotify = screen_priv->ClipNotify ; if (screen->ClipNotify) { (*screen->ClipNotify) (a_win, a_x, a_y) ; } screen->ClipNotify = ephyrDRIClipNotify ; EPHYR_LOG ("window: %p\n", a_win) ; win_priv = GET_EPHYR_DRI_WINDOW_PRIV (a_win) ; if (!win_priv) { EPHYR_LOG ("not a DRI peered window\n") ; is_ok = TRUE ; goto out ; } if (!findWindowPairFromLocal (a_win, &pair) || !pair) { EPHYR_LOG_ERROR ("failed to get window pair\n") ; goto out ; } rects = calloc(RegionNumRects (&a_win->clipList), sizeof (EphyrRect)) ; for (i=0; i < RegionNumRects (&a_win->clipList); i++) { memmove (&rects[i], &RegionRects (&a_win->clipList)[i], sizeof (EphyrRect)) ; rects[i].x1 -= a_win->drawable.x; rects[i].x2 -= a_win->drawable.x; rects[i].y1 -= a_win->drawable.y; rects[i].y2 -= a_win->drawable.y; } /* * push the clipping region of this window * to the peer window in the host */ is_ok = hostx_set_window_bounding_rectangles (pair->remote, rects, RegionNumRects (&a_win->clipList)) ; is_ok = TRUE ; out: free(rects) ; rects = NULL ; EPHYR_LOG ("leave. is_ok:%d\n", is_ok) ; /*do cleanup here*/ } /** * Duplicates a visual of a_screen * In screen a_screen, for depth a_depth, find a visual which * bitsPerRGBValue and colormap size equal * a_bits_per_rgb_values and a_colormap_entries. * The ID of that duplicated visual is set to a_new_id. * That duplicated visual is then added to the list of visuals * of the screen. */ static Bool EphyrDuplicateVisual (unsigned int a_screen, short a_depth, short a_class, short a_bits_per_rgb_values, short a_colormap_entries, unsigned int a_red_mask, unsigned int a_green_mask, unsigned int a_blue_mask, unsigned int a_new_id) { Bool is_ok = FALSE, found_visual=FALSE, found_depth=FALSE ; ScreenPtr screen=NULL ; VisualRec new_visual, *new_visuals=NULL ; int i=0 ; EPHYR_LOG ("enter\n") ; if (a_screen >= screenInfo.numScreens) { EPHYR_LOG_ERROR ("bad screen number\n") ; goto out; } memset (&new_visual, 0, sizeof (VisualRec)) ; /*get the screen pointed to by a_screen*/ screen = screenInfo.screens[a_screen] ; EPHYR_RETURN_VAL_IF_FAIL (screen, FALSE) ; /* * In that screen, first look for an existing visual that has the * same characteristics as those passed in parameter * to this function and copy it. */ for (i=0; i < screen->numVisuals; i++) { if (screen->visuals[i].bitsPerRGBValue == a_bits_per_rgb_values && screen->visuals[i].ColormapEntries == a_colormap_entries ) { /*copy the visual found*/ memcpy (&new_visual, &screen->visuals[i], sizeof (new_visual)) ; new_visual.vid = a_new_id ; new_visual.class = a_class ; new_visual.redMask = a_red_mask ; new_visual.greenMask = a_green_mask ; new_visual.blueMask = a_blue_mask ; found_visual = TRUE ; EPHYR_LOG ("found a visual that matches visual id: %d\n", a_new_id) ; break; } } if (!found_visual) { EPHYR_LOG ("did not find any visual matching %d\n", a_new_id) ; goto out ; } /* * be prepare to extend screen->visuals to add new_visual to it */ new_visuals = calloc(screen->numVisuals+1, sizeof (VisualRec)) ; memmove (new_visuals, screen->visuals, screen->numVisuals*sizeof (VisualRec)) ; memmove (&new_visuals[screen->numVisuals], &new_visual, sizeof (VisualRec)) ; /* * Now, in that same screen, update the screen->allowedDepths member. * In that array, each element represents the visuals applicable to * a given depth. So we need to add an entry matching the new visual * that we are going to add to screen->visuals */ for (i=0; i<screen->numDepths; i++) { VisualID *vids=NULL; DepthPtr cur_depth=NULL ; /*find the entry matching a_depth*/ if (screen->allowedDepths[i].depth != a_depth) continue ; cur_depth = &screen->allowedDepths[i]; /* * extend the list of visual IDs in that entry, * so to add a_new_id in there. */ vids = realloc(cur_depth->vids, (cur_depth->numVids+1)*sizeof (VisualID)); if (!vids) { EPHYR_LOG_ERROR ("failed to realloc numids\n") ; goto out ; } vids[cur_depth->numVids] = a_new_id ; /* * Okay now commit our change. * Do really update screen->allowedDepths[i] */ cur_depth->numVids++ ; cur_depth->vids = vids ; found_depth=TRUE; } if (!found_depth) { EPHYR_LOG_ERROR ("failed to update screen[%d]->allowedDepth\n", a_screen) ; goto out ; } /* * Commit our change to screen->visuals */ free(screen->visuals) ; screen->visuals = new_visuals ; screen->numVisuals++ ; new_visuals = NULL ; is_ok = TRUE ; out: free(new_visuals) ; new_visuals = NULL ; EPHYR_LOG ("leave\n") ; return is_ok ; } /** * Duplicates the visuals of the host X server. * This is necessary to have visuals that have the same * ID as those of the host X. It is important to have that for * GLX. */ static Bool EphyrMirrorHostVisuals (ScreenPtr a_screen) { Bool is_ok=FALSE; EphyrHostVisualInfo *visuals=NULL; int nb_visuals=0, i=0; EPHYR_LOG ("enter\n") ; if (!hostx_get_visuals_info (&visuals, &nb_visuals)) { EPHYR_LOG_ERROR ("failed to get host visuals\n") ; goto out ; } for (i=0; i<nb_visuals; i++) { if (!EphyrDuplicateVisual (a_screen->myNum, visuals[i].depth, visuals[i].class, visuals[i].bits_per_rgb, visuals[i].colormap_size, visuals[i].red_mask, visuals[i].green_mask, visuals[i].blue_mask, visuals[i].visualid)) { EPHYR_LOG_ERROR ("failed to duplicate host visual %d\n", (int)visuals[i].visualid) ; } } is_ok = TRUE ; out: EPHYR_LOG ("leave\n") ; return is_ok; } static int ProcXF86DRIQueryVersion (register ClientPtr client) { xXF86DRIQueryVersionReply rep; REQUEST_SIZE_MATCH(xXF86DRIQueryVersionReq); EPHYR_LOG ("enter\n") ; rep.type = X_Reply; rep.length = 0; rep.sequenceNumber = client->sequence; rep.majorVersion = SERVER_XF86DRI_MAJOR_VERSION; rep.minorVersion = SERVER_XF86DRI_MINOR_VERSION; rep.patchVersion = SERVER_XF86DRI_PATCH_VERSION; if (client->swapped) { swaps(&rep.sequenceNumber); swapl(&rep.length); swaps(&rep.majorVersion); swaps(&rep.minorVersion); swapl(&rep.patchVersion); } WriteToClient(client, sizeof(xXF86DRIQueryVersionReply), (char *)&rep); EPHYR_LOG ("leave\n") ; return Success; } static int ProcXF86DRIQueryDirectRenderingCapable (register ClientPtr client) { xXF86DRIQueryDirectRenderingCapableReply rep; Bool isCapable; REQUEST(xXF86DRIQueryDirectRenderingCapableReq); REQUEST_SIZE_MATCH(xXF86DRIQueryDirectRenderingCapableReq); EPHYR_LOG ("enter\n") ; 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); swapl(&rep.length); } WriteToClient(client, sizeof(xXF86DRIQueryDirectRenderingCapableReply), (char *)&rep); EPHYR_LOG ("leave\n") ; return Success; } static int ProcXF86DRIOpenConnection (register ClientPtr client) { xXF86DRIOpenConnectionReply rep; drm_handle_t hSAREA; char* busIdString = NULL; REQUEST(xXF86DRIOpenConnectionReq); REQUEST_SIZE_MATCH(xXF86DRIOpenConnectionReq); EPHYR_LOG ("enter\n") ; 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 = bytes_to_int32(SIZEOF(xXF86DRIOpenConnectionReply) - SIZEOF(xGenericReply) + pad_to_int32(rep.busIdStringLength)); 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); free(busIdString); EPHYR_LOG ("leave\n") ; return Success; } static int ProcXF86DRIAuthConnection (register ClientPtr client) { xXF86DRIAuthConnectionReply rep; REQUEST(xXF86DRIAuthConnectionReq); REQUEST_SIZE_MATCH(xXF86DRIAuthConnectionReq); EPHYR_LOG ("enter\n") ; 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 Success; } static int ProcXF86DRICloseConnection (register ClientPtr client) { REQUEST(xXF86DRICloseConnectionReq); REQUEST_SIZE_MATCH(xXF86DRICloseConnectionReq); EPHYR_LOG ("enter\n") ; if (stuff->screen >= screenInfo.numScreens) { client->errorValue = stuff->screen; return BadValue; } /* DRICloseConnection( screenInfo.screens[stuff->screen]); */ EPHYR_LOG ("leave\n") ; return Success; } static int ProcXF86DRIGetClientDriverName (register ClientPtr client) { xXF86DRIGetClientDriverNameReply rep; char* clientDriverName; REQUEST(xXF86DRIGetClientDriverNameReq); REQUEST_SIZE_MATCH(xXF86DRIGetClientDriverNameReq); EPHYR_LOG ("enter\n") ; 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 = bytes_to_int32(SIZEOF(xXF86DRIGetClientDriverNameReply) - SIZEOF(xGenericReply) + pad_to_int32(rep.clientDriverNameLength)); WriteToClient(client, sizeof(xXF86DRIGetClientDriverNameReply), (char *)&rep); if (rep.clientDriverNameLength) WriteToClient(client, rep.clientDriverNameLength, clientDriverName); EPHYR_LOG ("leave\n") ; return Success; } static int ProcXF86DRICreateContext (register ClientPtr client) { xXF86DRICreateContextReply rep; ScreenPtr pScreen; VisualPtr visual; int i=0; unsigned long context_id=0; REQUEST(xXF86DRICreateContextReq); REQUEST_SIZE_MATCH(xXF86DRICreateContextReq); EPHYR_LOG ("enter\n") ; 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; } context_id = stuff->context ; if (!ephyrDRICreateContext (stuff->screen, stuff->visual, &context_id, (drm_context_t *)&rep.hHWContext)) { return BadValue; } WriteToClient(client, sizeof(xXF86DRICreateContextReply), (char *)&rep); EPHYR_LOG ("leave\n") ; return Success; } static int ProcXF86DRIDestroyContext (register ClientPtr client) { REQUEST(xXF86DRIDestroyContextReq); REQUEST_SIZE_MATCH(xXF86DRIDestroyContextReq); EPHYR_LOG ("enter\n") ; if (stuff->screen >= screenInfo.numScreens) { client->errorValue = stuff->screen; return BadValue; } if (!ephyrDRIDestroyContext (stuff->screen, stuff->context)) { return BadValue; } EPHYR_LOG ("leave\n") ; return Success; } static Bool getWindowVisual (const WindowPtr a_win, VisualPtr *a_visual) { int i=0, visual_id=0 ; EPHYR_RETURN_VAL_IF_FAIL (a_win && a_win->drawable.pScreen && a_win->drawable.pScreen->visuals, FALSE) ; visual_id = wVisual (a_win) ; for (i=0; i < a_win->drawable.pScreen->numVisuals; i++) { if (a_win->drawable.pScreen->visuals[i].vid == visual_id) { *a_visual = &a_win->drawable.pScreen->visuals[i] ; return TRUE ; } } return FALSE ; } #define NUM_WINDOW_PAIRS 256 static EphyrWindowPair window_pairs[NUM_WINDOW_PAIRS] ; static Bool appendWindowPairToList (WindowPtr a_local, int a_remote) { int i=0 ; EPHYR_RETURN_VAL_IF_FAIL (a_local, FALSE) ; EPHYR_LOG ("(local,remote):(%p, %d)\n", a_local, a_remote) ; for (i=0; i < NUM_WINDOW_PAIRS; i++) { if (window_pairs[i].local == NULL) { window_pairs[i].local = a_local ; window_pairs[i].remote = a_remote ; return TRUE ; } } return FALSE ; } static Bool findWindowPairFromLocal (WindowPtr a_local, EphyrWindowPair **a_pair) { int i=0 ; EPHYR_RETURN_VAL_IF_FAIL (a_pair && a_local, FALSE) ; for (i=0; i < NUM_WINDOW_PAIRS; i++) { if (window_pairs[i].local == a_local) { *a_pair = &window_pairs[i] ; EPHYR_LOG ("found (%p, %d)\n", (*a_pair)->local, (*a_pair)->remote) ; return TRUE ; } } return FALSE ; } Bool findWindowPairFromRemote (int a_remote, EphyrWindowPair **a_pair) { int i=0 ; EPHYR_RETURN_VAL_IF_FAIL (a_pair, FALSE) ; for (i=0; i < NUM_WINDOW_PAIRS; i++) { if (window_pairs[i].remote == a_remote) { *a_pair = &window_pairs[i] ; EPHYR_LOG ("found (%p, %d)\n", (*a_pair)->local, (*a_pair)->remote) ; return TRUE ; } } return FALSE ; } static Bool createHostPeerWindow (const WindowPtr a_win, int *a_peer_win) { Bool is_ok=FALSE ; VisualPtr visual=NULL; EphyrBox geo ; EPHYR_RETURN_VAL_IF_FAIL (a_win && a_peer_win, FALSE) ; EPHYR_RETURN_VAL_IF_FAIL (a_win->drawable.pScreen, FALSE) ; EPHYR_LOG ("enter. a_win '%p'\n", a_win) ; if (!getWindowVisual (a_win, &visual)) { EPHYR_LOG_ERROR ("failed to get window visual\n") ; goto out ; } if (!visual) { EPHYR_LOG_ERROR ("failed to create visual\n") ; goto out ; } memset (&geo, 0, sizeof (geo)) ; geo.x = a_win->drawable.x ; geo.y = a_win->drawable.y ; geo.width = a_win->drawable.width ; geo.height = a_win->drawable.height ; if (!hostx_create_window (a_win->drawable.pScreen->myNum, &geo, visual->vid, a_peer_win)) { EPHYR_LOG_ERROR ("failed to create host peer window\n") ; goto out ; } if (!appendWindowPairToList (a_win, *a_peer_win)) { EPHYR_LOG_ERROR ("failed to append window to pair list\n") ; goto out ; } is_ok = TRUE ; out: EPHYR_LOG ("leave:remote win%d\n", *a_peer_win) ; return is_ok ; } static Bool destroyHostPeerWindow (const WindowPtr a_win) { Bool is_ok = FALSE ; EphyrWindowPair *pair=NULL ; EPHYR_RETURN_VAL_IF_FAIL (a_win, FALSE) ; EPHYR_LOG ("enter\n") ; if (!findWindowPairFromLocal (a_win, &pair) || !pair) { EPHYR_LOG_ERROR ("failed to find peer to local window\n") ; goto out; } hostx_destroy_window (pair->remote) ; is_ok = TRUE ; out: EPHYR_LOG ("leave\n") ; return is_ok; } static int ProcXF86DRICreateDrawable (ClientPtr client) { xXF86DRICreateDrawableReply rep; DrawablePtr drawable=NULL; WindowPtr window=NULL ; EphyrWindowPair *pair=NULL ; EphyrDRIWindowPrivPtr win_priv=NULL; int rc=0, remote_win=0; REQUEST(xXF86DRICreateDrawableReq); REQUEST_SIZE_MATCH(xXF86DRICreateDrawableReq); EPHYR_LOG ("enter\n") ; if (stuff->screen >= screenInfo.numScreens) { client->errorValue = stuff->screen; return BadValue; } rep.type = X_Reply; rep.length = 0; rep.sequenceNumber = client->sequence; rc = dixLookupDrawable (&drawable, stuff->drawable, client, 0, DixReadAccess); if (rc != Success) return rc; if (drawable->type != DRAWABLE_WINDOW) { EPHYR_LOG_ERROR ("non drawable windows are not yet supported\n") ; return BadImplementation ; } EPHYR_LOG ("lookedup drawable %p\n", drawable) ; window = (WindowPtr)drawable; if (findWindowPairFromLocal (window, &pair) && pair) { remote_win = pair->remote ; EPHYR_LOG ("found window '%p' paire with remote '%d'\n", window, remote_win) ; } else if (!createHostPeerWindow (window, &remote_win)) { EPHYR_LOG_ERROR ("failed to create host peer window\n") ; return BadAlloc ; } if (!ephyrDRICreateDrawable (stuff->screen, remote_win, (drm_drawable_t *)&rep.hHWDrawable)) { EPHYR_LOG_ERROR ("failed to create dri drawable\n") ; return BadValue; } win_priv = GET_EPHYR_DRI_WINDOW_PRIV (window) ; if (!win_priv) { win_priv = calloc(1, sizeof (EphyrDRIWindowPrivRec)) ; if (!win_priv) { EPHYR_LOG_ERROR ("failed to allocate window private\n") ; return BadAlloc ; } dixSetPrivate(&window->devPrivates, ephyrDRIWindowKey, win_priv); EPHYR_LOG ("paired window '%p' with remote '%d'\n", window, remote_win) ; } WriteToClient(client, sizeof(xXF86DRICreateDrawableReply), (char *)&rep); EPHYR_LOG ("leave\n") ; return Success; } static int ProcXF86DRIDestroyDrawable (register ClientPtr client) { DrawablePtr drawable=NULL; WindowPtr window=NULL; EphyrWindowPair *pair=NULL; int rc=0; REQUEST(xXF86DRIDestroyDrawableReq); REQUEST_SIZE_MATCH(xXF86DRIDestroyDrawableReq); EPHYR_LOG ("enter\n") ; if (stuff->screen >= screenInfo.numScreens) { client->errorValue = stuff->screen; return BadValue; } rc = dixLookupDrawable(&drawable, stuff->drawable, client, 0, DixReadAccess); if (rc != Success) return rc; if (drawable->type != DRAWABLE_WINDOW) { EPHYR_LOG_ERROR ("non drawable windows are not yet supported\n") ; return BadImplementation ; } window = (WindowPtr)drawable; if (!findWindowPairFromLocal (window, &pair) && pair) { EPHYR_LOG_ERROR ("failed to find pair window\n") ; return BadImplementation; } if (!ephyrDRIDestroyDrawable(stuff->screen, pair->remote/*drawable in host x*/)) { EPHYR_LOG_ERROR ("failed to destroy dri drawable\n") ; return BadImplementation; } pair->local=NULL ; pair->remote=0; EPHYR_LOG ("leave\n") ; return Success; } static int ProcXF86DRIGetDrawableInfo (register ClientPtr client) { xXF86DRIGetDrawableInfoReply rep; DrawablePtr drawable; WindowPtr window=NULL; EphyrWindowPair *pair=NULL; int X=0, Y=0, W=0, H=0, backX=0, backY=0, rc=0, i=0; drm_clip_rect_t *clipRects=NULL; drm_clip_rect_t *backClipRects=NULL; REQUEST(xXF86DRIGetDrawableInfoReq); REQUEST_SIZE_MATCH(xXF86DRIGetDrawableInfoReq); EPHYR_LOG ("enter\n") ; memset (&rep, 0, sizeof (rep)) ; if (stuff->screen >= screenInfo.numScreens) { client->errorValue = stuff->screen; return BadValue; } rep.type = X_Reply; rep.length = 0; rep.sequenceNumber = client->sequence; rc = dixLookupDrawable(&drawable, stuff->drawable, client, 0, DixReadAccess); if (rc != Success || !drawable) { EPHYR_LOG_ERROR ("could not get drawable\n") ; return rc; } if (drawable->type != DRAWABLE_WINDOW) { EPHYR_LOG_ERROR ("non windows type drawables are not yes supported\n") ; return BadImplementation ; } window = (WindowPtr)drawable ; memset (&pair, 0, sizeof (pair)) ; if (!findWindowPairFromLocal (window, &pair) || !pair) { EPHYR_LOG_ERROR ("failed to find remote peer drawable\n") ; return BadMatch ; } EPHYR_LOG ("clip list of xephyr gl drawable:\n") ; for (i=0; i < RegionNumRects (&window->clipList); i++) { EPHYR_LOG ("x1:%d, y1:%d, x2:%d, y2:%d\n", RegionRects (&window->clipList)[i].x1, RegionRects (&window->clipList)[i].y1, RegionRects (&window->clipList)[i].x2, RegionRects (&window->clipList)[i].y2) ; } if (!ephyrDRIGetDrawableInfo (stuff->screen, pair->remote/*the drawable in hostx*/, (unsigned int*)&rep.drawableTableIndex, (unsigned int*)&rep.drawableTableStamp, (int*)&X, (int*)&Y, (int*)&W, (int*)&H, (int*)&rep.numClipRects, &clipRects, &backX, &backY, (int*)&rep.numBackClipRects, &backClipRects)) { return BadValue; } EPHYR_LOG ("num clip rects:%d, num back clip rects:%d\n", (int)rep.numClipRects, (int)rep.numBackClipRects) ; 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.numClipRects) { if (clipRects) { ScreenPtr pScreen = screenInfo.screens[stuff->screen]; int i=0; EPHYR_LOG ("clip list of host gl drawable:\n") ; for (i = 0; i < rep.numClipRects; i++) { clipRects[i].x1 = max (clipRects[i].x1, 0); clipRects[i].y1 = max (clipRects[i].y1, 0); clipRects[i].x2 = min (clipRects[i].x2, pScreen->width + clipRects[i].x1) ; clipRects[i].y2 = min (clipRects[i].y2, pScreen->width + clipRects[i].y1) ; EPHYR_LOG ("x1:%d, y1:%d, x2:%d, y2:%d\n", clipRects[i].x1, clipRects[i].y1, clipRects[i].x2, clipRects[i].y2) ; } } else { rep.numClipRects = 0; } } else { EPHYR_LOG ("got zero host gl drawable clipping rects\n") ; } rep.length += sizeof(drm_clip_rect_t) * rep.numClipRects; backClipRects = clipRects ; rep.numBackClipRects = rep.numClipRects ; if (rep.numBackClipRects) rep.length += sizeof(drm_clip_rect_t) * rep.numBackClipRects; EPHYR_LOG ("num host clip rects:%d\n", (int)rep.numClipRects) ; EPHYR_LOG ("num host back clip rects:%d\n", (int)rep.numBackClipRects) ; rep.length = bytes_to_int32(rep.length); WriteToClient(client, sizeof(xXF86DRIGetDrawableInfoReply), (char *)&rep); if (rep.numClipRects) { WriteToClient(client, sizeof(drm_clip_rect_t) * rep.numClipRects, (char *)clipRects); } if (rep.numBackClipRects) { WriteToClient(client, sizeof(drm_clip_rect_t) * rep.numBackClipRects, (char *)backClipRects); } free(clipRects); clipRects = NULL ; EPHYR_LOG ("leave\n") ; return Success; } static int ProcXF86DRIGetDeviceInfo (register ClientPtr client) { xXF86DRIGetDeviceInfoReply rep; drm_handle_t hFrameBuffer; void *pDevPrivate; REQUEST(xXF86DRIGetDeviceInfoReq); REQUEST_SIZE_MATCH(xXF86DRIGetDeviceInfoReq); EPHYR_LOG ("enter\n") ; 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 = bytes_to_int32(SIZEOF(xXF86DRIGetDeviceInfoReply) - SIZEOF(xGenericReply) + pad_to_int32(rep.devPrivateSize)); } WriteToClient(client, sizeof(xXF86DRIGetDeviceInfoReply), (char *)&rep); if (rep.length) { WriteToClient(client, rep.devPrivateSize, (char *)pDevPrivate); } EPHYR_LOG ("leave\n") ; return Success; } 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) { REQUEST(xXF86DRIQueryVersionReq); swaps(&stuff->length); return ProcXF86DRIQueryVersion(client); } static int SProcXF86DRIQueryDirectRenderingCapable (register ClientPtr client) { REQUEST(xXF86DRIQueryDirectRenderingCapableReq); swaps(&stuff->length); swapl(&stuff->screen); 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; } } } Bool ephyrDRIExtensionInit (ScreenPtr a_screen) { Bool is_ok=FALSE ; ExtensionEntry* extEntry=NULL; EphyrDRIScreenPrivPtr screen_priv=NULL ; EPHYR_LOG ("enter\n") ; if (!hostx_has_dri ()) { EPHYR_LOG ("host does not have DRI extension\n") ; goto out ; } EPHYR_LOG ("host X does have DRI extension\n") ; if (!hostx_has_xshape ()) { EPHYR_LOG ("host does not have XShape extension\n") ; goto out ; } EPHYR_LOG ("host X does have XShape extension\n") ; #ifdef XF86DRI_EVENTS EventType = CreateNewResourceType (XF86DRIFreeEvents, "DRIEvents"); if (!EventType) { EPHYR_LOG_ERROR ("failed to register DRI event resource type\n") ; goto out ; } #endif if ((extEntry = AddExtension(XF86DRINAME, XF86DRINumberEvents, XF86DRINumberErrors, ProcXF86DRIDispatch, SProcXF86DRIDispatch, NULL, StandardMinorOpcode))) { DRIReqCode = (unsigned char)extEntry->base; DRIErrorBase = extEntry->errorBase; } else { EPHYR_LOG_ERROR ("failed to register DRI extension\n") ; goto out ; } if (!dixRegisterPrivateKey(&ephyrDRIScreenKeyRec, PRIVATE_SCREEN, 0)) goto out ; if (!dixRegisterPrivateKey(&ephyrDRIWindowKeyRec, PRIVATE_WINDOW, 0)) goto out ; screen_priv = calloc(1, sizeof (EphyrDRIScreenPrivRec)) ; if (!screen_priv) { EPHYR_LOG_ERROR ("failed to allocate screen_priv\n") ; goto out ; } dixSetPrivate(&a_screen->devPrivates, ephyrDRIScreenKey, screen_priv); if (!ephyrDRIScreenInit (a_screen)) { EPHYR_LOG_ERROR ("ephyrDRIScreenInit() failed\n") ; goto out ; } EphyrMirrorHostVisuals (a_screen) ; is_ok=TRUE ; out: EPHYR_LOG ("leave\n") ; return is_ok ; }