1/* 2 * Copyright © 2013 Keith Packard 3 * 4 * Permission to use, copy, modify, distribute, and sell this software and its 5 * documentation for any purpose is hereby granted without fee, provided that 6 * the above copyright notice appear in all copies and that both that copyright 7 * notice and this permission notice appear in supporting documentation, and 8 * that the name of the copyright holders not be used in advertising or 9 * publicity pertaining to distribution of the software without specific, 10 * written prior permission. The copyright holders make no representations 11 * about the suitability of this software for any purpose. It is provided "as 12 * is" without express or implied warranty. 13 * 14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 20 * OF THIS SOFTWARE. 21 */ 22 23#ifdef HAVE_DIX_CONFIG_H 24#include <dix-config.h> 25#endif 26 27#include "scrnintstr.h" 28#include "misync.h" 29#include "misyncstr.h" 30#include "misyncshm.h" 31#include "misyncfd.h" 32#include "pixmapstr.h" 33#include <sys/mman.h> 34#include <unistd.h> 35#include <fcntl.h> 36#include <X11/xshmfence.h> 37 38static DevPrivateKeyRec syncShmFencePrivateKey; 39 40typedef struct _SyncShmFencePrivate { 41 struct xshmfence *fence; 42 int fd; 43} SyncShmFencePrivateRec, *SyncShmFencePrivatePtr; 44 45#define SYNC_FENCE_PRIV(pFence) \ 46 (SyncShmFencePrivatePtr) dixLookupPrivate(&pFence->devPrivates, &syncShmFencePrivateKey) 47 48static void 49miSyncShmFenceSetTriggered(SyncFence * pFence) 50{ 51 SyncShmFencePrivatePtr pPriv = SYNC_FENCE_PRIV(pFence); 52 53 if (pPriv->fence) 54 xshmfence_trigger(pPriv->fence); 55 miSyncFenceSetTriggered(pFence); 56} 57 58static void 59miSyncShmFenceReset(SyncFence * pFence) 60{ 61 SyncShmFencePrivatePtr pPriv = SYNC_FENCE_PRIV(pFence); 62 63 if (pPriv->fence) 64 xshmfence_reset(pPriv->fence); 65 miSyncFenceReset(pFence); 66} 67 68static Bool 69miSyncShmFenceCheckTriggered(SyncFence * pFence) 70{ 71 SyncShmFencePrivatePtr pPriv = SYNC_FENCE_PRIV(pFence); 72 73 if (pPriv->fence) 74 return xshmfence_query(pPriv->fence); 75 else 76 return miSyncFenceCheckTriggered(pFence); 77} 78 79static void 80miSyncShmFenceAddTrigger(SyncTrigger * pTrigger) 81{ 82 miSyncFenceAddTrigger(pTrigger); 83} 84 85static void 86miSyncShmFenceDeleteTrigger(SyncTrigger * pTrigger) 87{ 88 miSyncFenceDeleteTrigger(pTrigger); 89} 90 91static const SyncFenceFuncsRec miSyncShmFenceFuncs = { 92 &miSyncShmFenceSetTriggered, 93 &miSyncShmFenceReset, 94 &miSyncShmFenceCheckTriggered, 95 &miSyncShmFenceAddTrigger, 96 &miSyncShmFenceDeleteTrigger 97}; 98 99static void 100miSyncShmScreenCreateFence(ScreenPtr pScreen, SyncFence * pFence, 101 Bool initially_triggered) 102{ 103 SyncShmFencePrivatePtr pPriv = SYNC_FENCE_PRIV(pFence); 104 105 pPriv->fence = NULL; 106 miSyncScreenCreateFence(pScreen, pFence, initially_triggered); 107 pFence->funcs = miSyncShmFenceFuncs; 108} 109 110static void 111miSyncShmScreenDestroyFence(ScreenPtr pScreen, SyncFence * pFence) 112{ 113 SyncShmFencePrivatePtr pPriv = SYNC_FENCE_PRIV(pFence); 114 115 if (pPriv->fence) { 116 xshmfence_trigger(pPriv->fence); 117 xshmfence_unmap_shm(pPriv->fence); 118 close(pPriv->fd); 119 } 120 miSyncScreenDestroyFence(pScreen, pFence); 121} 122 123static int 124miSyncShmCreateFenceFromFd(ScreenPtr pScreen, SyncFence *pFence, int fd, Bool initially_triggered) 125{ 126 SyncShmFencePrivatePtr pPriv = SYNC_FENCE_PRIV(pFence); 127 128 miSyncInitFence(pScreen, pFence, initially_triggered); 129 130 fd = os_move_fd(fd); 131 pPriv->fence = xshmfence_map_shm(fd); 132 if (pPriv->fence) { 133 pPriv->fd = fd; 134 return Success; 135 } 136 else 137 close(fd); 138 return BadValue; 139} 140 141static int 142miSyncShmGetFenceFd(ScreenPtr pScreen, SyncFence *pFence) 143{ 144 SyncShmFencePrivatePtr pPriv = SYNC_FENCE_PRIV(pFence); 145 146 if (!pPriv->fence) { 147 pPriv->fd = xshmfence_alloc_shm(); 148 if (pPriv->fd < 0) 149 return -1; 150 pPriv->fd = os_move_fd(pPriv->fd); 151 pPriv->fence = xshmfence_map_shm(pPriv->fd); 152 if (!pPriv->fence) { 153 close (pPriv->fd); 154 return -1; 155 } 156 } 157 return pPriv->fd; 158} 159 160static const SyncFdScreenFuncsRec miSyncShmScreenFuncs = { 161 .version = SYNC_FD_SCREEN_FUNCS_VERSION, 162 .CreateFenceFromFd = miSyncShmCreateFenceFromFd, 163 .GetFenceFd = miSyncShmGetFenceFd 164}; 165 166_X_EXPORT Bool miSyncShmScreenInit(ScreenPtr pScreen) 167{ 168 SyncScreenFuncsPtr funcs; 169 170 if (!miSyncFdScreenInit(pScreen, &miSyncShmScreenFuncs)) 171 return FALSE; 172 173 if (!dixPrivateKeyRegistered(&syncShmFencePrivateKey)) { 174 if (!dixRegisterPrivateKey(&syncShmFencePrivateKey, PRIVATE_SYNC_FENCE, 175 sizeof(SyncShmFencePrivateRec))) 176 return FALSE; 177 } 178 179 funcs = miSyncGetScreenFuncs(pScreen); 180 181 funcs->CreateFence = miSyncShmScreenCreateFence; 182 funcs->DestroyFence = miSyncShmScreenDestroyFence; 183 184 return TRUE; 185} 186 187