present_request.c revision 35c4bbdf
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_XORG_CONFIG_H
24#include <xorg-config.h>
25#endif
26
27#include "present_priv.h"
28#include "randrstr.h"
29#include <protocol-versions.h>
30
31static int
32proc_present_query_version(ClientPtr client)
33{
34    REQUEST(xPresentQueryVersionReq);
35    xPresentQueryVersionReply rep = {
36        .type = X_Reply,
37        .sequenceNumber = client->sequence,
38        .length = 0,
39        .majorVersion = SERVER_PRESENT_MAJOR_VERSION,
40        .minorVersion = SERVER_PRESENT_MINOR_VERSION
41    };
42
43    REQUEST_SIZE_MATCH(xPresentQueryVersionReq);
44    (void) stuff;
45    if (client->swapped) {
46        swaps(&rep.sequenceNumber);
47        swapl(&rep.length);
48        swapl(&rep.majorVersion);
49        swapl(&rep.minorVersion);
50    }
51    WriteToClient(client, sizeof(rep), &rep);
52    return Success;
53}
54
55#define VERIFY_FENCE_OR_NONE(fence_ptr, fence_id, client, access) do {  \
56        if ((fence_id) == None)                                         \
57            (fence_ptr) = NULL;                                         \
58        else {                                                          \
59            int __rc__ = SyncVerifyFence(&fence_ptr, fence_id, client, access); \
60            if (__rc__ != Success)                                      \
61                return __rc__;                                          \
62        }                                                               \
63    } while (0)
64
65#define VERIFY_CRTC_OR_NONE(crtc_ptr, crtc_id, client, access) do {     \
66        if ((crtc_id) == None)                                          \
67            (crtc_ptr) = NULL;                                          \
68        else {                                                          \
69            VERIFY_RR_CRTC(crtc_id, crtc_ptr, access);                  \
70        }                                                               \
71    } while (0)
72
73static int
74proc_present_pixmap(ClientPtr client)
75{
76    REQUEST(xPresentPixmapReq);
77    WindowPtr           window;
78    PixmapPtr           pixmap;
79    RegionPtr           valid = NULL;
80    RegionPtr           update = NULL;
81    SyncFence           *wait_fence;
82    SyncFence           *idle_fence;
83    RRCrtcPtr           target_crtc;
84    int                 ret;
85    int                 nnotifies;
86    present_notify_ptr  notifies = NULL;
87
88    REQUEST_AT_LEAST_SIZE(xPresentPixmapReq);
89    ret = dixLookupWindow(&window, stuff->window, client, DixWriteAccess);
90    if (ret != Success)
91        return ret;
92    ret = dixLookupResourceByType((void **) &pixmap, stuff->pixmap, RT_PIXMAP, client, DixReadAccess);
93    if (ret != Success)
94        return ret;
95
96    if (window->drawable.depth != pixmap->drawable.depth)
97        return BadMatch;
98
99    VERIFY_REGION_OR_NONE(valid, stuff->valid, client, DixReadAccess);
100    VERIFY_REGION_OR_NONE(update, stuff->update, client, DixReadAccess);
101
102    VERIFY_CRTC_OR_NONE(target_crtc, stuff->target_crtc, client, DixReadAccess);
103
104    VERIFY_FENCE_OR_NONE(wait_fence, stuff->wait_fence, client, DixReadAccess);
105    VERIFY_FENCE_OR_NONE(idle_fence, stuff->idle_fence, client, DixWriteAccess);
106
107    if (stuff->options & ~(PresentAllOptions)) {
108        client->errorValue = stuff->options;
109        return BadValue;
110    }
111
112    /*
113     * Check to see if remainder is sane
114     */
115    if (stuff->divisor == 0) {
116        if (stuff->remainder != 0) {
117            client->errorValue = (CARD32) stuff->remainder;
118            return BadValue;
119        }
120    } else {
121        if (stuff->remainder >= stuff->divisor) {
122            client->errorValue = (CARD32) stuff->remainder;
123            return BadValue;
124        }
125    }
126
127    nnotifies = (client->req_len << 2) - sizeof (xPresentPixmapReq);
128    if (nnotifies % sizeof (xPresentNotify))
129        return BadLength;
130
131    nnotifies /= sizeof (xPresentNotify);
132    if (nnotifies) {
133        ret = present_create_notifies(client, nnotifies, (xPresentNotify *) (stuff + 1), &notifies);
134        if (ret != Success)
135            return ret;
136    }
137
138    ret = present_pixmap(window, pixmap, stuff->serial, valid, update,
139                         stuff->x_off, stuff->y_off, target_crtc,
140                         wait_fence, idle_fence, stuff->options,
141                         stuff->target_msc, stuff->divisor, stuff->remainder, notifies, nnotifies);
142    if (ret != Success)
143        present_destroy_notifies(notifies, nnotifies);
144    return ret;
145}
146
147static int
148proc_present_notify_msc(ClientPtr client)
149{
150    REQUEST(xPresentNotifyMSCReq);
151    WindowPtr   window;
152    int         rc;
153
154    REQUEST_SIZE_MATCH(xPresentNotifyMSCReq);
155    rc = dixLookupWindow(&window, stuff->window, client, DixReadAccess);
156    if (rc != Success)
157        return rc;
158
159    /*
160     * Check to see if remainder is sane
161     */
162    if (stuff->divisor == 0) {
163        if (stuff->remainder != 0) {
164            client->errorValue = (CARD32) stuff->remainder;
165            return BadValue;
166        }
167    } else {
168        if (stuff->remainder >= stuff->divisor) {
169            client->errorValue = (CARD32) stuff->remainder;
170            return BadValue;
171        }
172    }
173
174    return present_notify_msc(window, stuff->serial,
175                              stuff->target_msc, stuff->divisor, stuff->remainder);
176}
177
178static int
179proc_present_select_input (ClientPtr client)
180{
181    REQUEST(xPresentSelectInputReq);
182    WindowPtr window;
183    int rc;
184
185    REQUEST_SIZE_MATCH(xPresentSelectInputReq);
186
187    LEGAL_NEW_RESOURCE(stuff->eid, client);
188
189    rc = dixLookupWindow(&window, stuff->window, client, DixGetAttrAccess);
190    if (rc != Success)
191        return rc;
192
193    if (stuff->eventMask & ~PresentAllEvents) {
194        client->errorValue = stuff->eventMask;
195        return BadValue;
196    }
197    return present_select_input(client, stuff->eid, window, stuff->eventMask);
198}
199
200static int
201proc_present_query_capabilities (ClientPtr client)
202{
203    REQUEST(xPresentQueryCapabilitiesReq);
204    xPresentQueryCapabilitiesReply rep = {
205        .type = X_Reply,
206        .sequenceNumber = client->sequence,
207        .length = 0,
208    };
209    WindowPtr   window;
210    RRCrtcPtr   crtc = NULL;
211    int         r;
212
213    REQUEST_SIZE_MATCH(xPresentQueryCapabilitiesReq);
214    r = dixLookupWindow(&window, stuff->target, client, DixGetAttrAccess);
215    switch (r) {
216    case Success:
217        crtc = present_get_crtc(window);
218        break;
219    case BadWindow:
220        VERIFY_RR_CRTC(stuff->target, crtc, DixGetAttrAccess);
221        break;
222    default:
223        return r;
224    }
225
226    rep.capabilities = present_query_capabilities(crtc);
227
228    if (client->swapped) {
229        swaps(&rep.sequenceNumber);
230        swapl(&rep.length);
231        swapl(&rep.capabilities);
232    }
233    WriteToClient(client, sizeof(rep), &rep);
234    return Success;
235}
236
237static int (*proc_present_vector[PresentNumberRequests]) (ClientPtr) = {
238    proc_present_query_version,            /* 0 */
239    proc_present_pixmap,                   /* 1 */
240    proc_present_notify_msc,               /* 2 */
241    proc_present_select_input,             /* 3 */
242    proc_present_query_capabilities,       /* 4 */
243};
244
245int
246proc_present_dispatch(ClientPtr client)
247{
248    REQUEST(xReq);
249    if (stuff->data >= PresentNumberRequests || !proc_present_vector[stuff->data])
250        return BadRequest;
251    return (*proc_present_vector[stuff->data]) (client);
252}
253
254static int
255sproc_present_query_version(ClientPtr client)
256{
257    REQUEST(xPresentQueryVersionReq);
258    REQUEST_SIZE_MATCH(xPresentQueryVersionReq);
259
260    swaps(&stuff->length);
261    swapl(&stuff->majorVersion);
262    swapl(&stuff->minorVersion);
263    return (*proc_present_vector[stuff->presentReqType]) (client);
264}
265
266static int
267sproc_present_pixmap(ClientPtr client)
268{
269    REQUEST(xPresentPixmapReq);
270    REQUEST_AT_LEAST_SIZE(xPresentPixmapReq);
271
272    swaps(&stuff->length);
273    swapl(&stuff->window);
274    swapl(&stuff->pixmap);
275    swapl(&stuff->valid);
276    swapl(&stuff->update);
277    swaps(&stuff->x_off);
278    swaps(&stuff->y_off);
279    swapll(&stuff->target_msc);
280    swapll(&stuff->divisor);
281    swapll(&stuff->remainder);
282    swapl(&stuff->idle_fence);
283    return (*proc_present_vector[stuff->presentReqType]) (client);
284}
285
286static int
287sproc_present_notify_msc(ClientPtr client)
288{
289    REQUEST(xPresentNotifyMSCReq);
290    REQUEST_SIZE_MATCH(xPresentNotifyMSCReq);
291
292    swaps(&stuff->length);
293    swapl(&stuff->window);
294    swapll(&stuff->target_msc);
295    swapll(&stuff->divisor);
296    swapll(&stuff->remainder);
297    return (*proc_present_vector[stuff->presentReqType]) (client);
298}
299
300static int
301sproc_present_select_input (ClientPtr client)
302{
303    REQUEST(xPresentSelectInputReq);
304    REQUEST_SIZE_MATCH(xPresentSelectInputReq);
305
306    swaps(&stuff->length);
307    swapl(&stuff->window);
308    swapl(&stuff->eventMask);
309    return (*proc_present_vector[stuff->presentReqType]) (client);
310}
311
312static int
313sproc_present_query_capabilities (ClientPtr client)
314{
315    REQUEST(xPresentQueryCapabilitiesReq);
316    REQUEST_SIZE_MATCH(xPresentQueryCapabilitiesReq);
317    swaps(&stuff->length);
318    swapl(&stuff->target);
319    return (*proc_present_vector[stuff->presentReqType]) (client);
320}
321
322static int (*sproc_present_vector[PresentNumberRequests]) (ClientPtr) = {
323    sproc_present_query_version,           /* 0 */
324    sproc_present_pixmap,                  /* 1 */
325    sproc_present_notify_msc,              /* 2 */
326    sproc_present_select_input,            /* 3 */
327    sproc_present_query_capabilities,      /* 4 */
328};
329
330int
331sproc_present_dispatch(ClientPtr client)
332{
333    REQUEST(xReq);
334    if (stuff->data >= PresentNumberRequests || !sproc_present_vector[stuff->data])
335        return BadRequest;
336    return (*sproc_present_vector[stuff->data]) (client);
337}
338