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), ¬ifies); 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