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