| 1 | /* |
| 2 | * Copyright © 2008 Red Hat, Inc. |
| 3 | * |
| 4 | * Permission is hereby granted, free of charge, to any person obtaining a |
| 5 | * copy of this software and associated documentation files (the "Soft- |
| 6 | * ware"), to deal in the Software without restriction, including without |
| 7 | * limitation the rights to use, copy, modify, merge, publish, distribute, |
| 8 | * and/or sell copies of the Software, and to permit persons to whom the |
| 9 | * Software is furnished to do so, provided that the above copyright |
| 10 | * notice(s) and this permission notice appear in all copies of the Soft- |
| 11 | * ware and that both the above copyright notice(s) and this permission |
| 12 | * notice appear in supporting documentation. |
| 13 | * |
| 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
| 15 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- |
| 16 | * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY |
| 17 | * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN |
| 18 | * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE- |
| 19 | * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, |
| 20 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER |
| 21 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR- |
| 22 | * MANCE OF THIS SOFTWARE. |
| 23 | * |
| 24 | * Except as contained in this notice, the name of a copyright holder shall |
| 25 | * not be used in advertising or otherwise to promote the sale, use or |
| 26 | * other dealings in this Software without prior written authorization of |
| 27 | * the copyright holder. |
| 28 | * |
| 29 | * Authors: |
| 30 | * Kristian Høgsberg (krh@redhat.com) |
| 31 | */ |
| 32 | |
| 33 | #ifdef HAVE_XORG_CONFIG_H |
| 34 | #include <xorg-config.h> |
| 35 | #endif |
| 36 | |
| 37 | #include <X11/X.h> |
| 38 | #include <X11/Xproto.h> |
| 39 | #include <X11/extensions/dri2proto.h> |
| 40 | #include <X11/extensions/xfixeswire.h> |
| 41 | #include "dixstruct.h" |
| 42 | #include "scrnintstr.h" |
| 43 | #include "pixmapstr.h" |
| 44 | #include "extnsionst.h" |
| 45 | #include "xfixes.h" |
| 46 | #include "dri2.h" |
| 47 | #include "dri2int.h" |
| 48 | #include "protocol-versions.h" |
| 49 | |
| 50 | /* The only xf86 includes */ |
| 51 | #include "xf86Module.h" |
| 52 | #include "xf86Extensions.h" |
| 53 | |
| 54 | static int DRI2EventBase; |
| 55 | |
| 56 | |
| 57 | static Bool |
| 58 | validDrawable(ClientPtr client, XID drawable, Mask access_mode, |
| 59 | DrawablePtr *pDrawable, int *status) |
| 60 | { |
| 61 | *status = dixLookupDrawable(pDrawable, drawable, client, |
| 62 | M_DRAWABLE_WINDOW | M_DRAWABLE_PIXMAP, |
| 63 | access_mode); |
| 64 | if (*status != Success) { |
| 65 | client->errorValue = drawable; |
| 66 | return FALSE; |
| 67 | } |
| 68 | |
| 69 | return TRUE; |
| 70 | } |
| 71 | |
| 72 | static int |
| 73 | ProcDRI2QueryVersion(ClientPtr client) |
| 74 | { |
| 75 | REQUEST(xDRI2QueryVersionReq); |
| 76 | xDRI2QueryVersionReply rep = { |
| 77 | .type = X_Reply, |
| 78 | .sequenceNumber = client->sequence, |
| 79 | .length = 0, |
| 80 | .majorVersion = dri2_major, |
| 81 | .minorVersion = dri2_minor |
| 82 | }; |
| 83 | |
| 84 | if (client->swapped) |
| 85 | swaps(&stuff->length); |
| 86 | |
| 87 | REQUEST_SIZE_MATCH(xDRI2QueryVersionReq); |
| 88 | |
| 89 | if (client->swapped) { |
| 90 | swaps(&rep.sequenceNumber); |
| 91 | swapl(&rep.length); |
| 92 | swapl(&rep.majorVersion); |
| 93 | swapl(&rep.minorVersion); |
| 94 | } |
| 95 | |
| 96 | WriteToClient(client, sizeof(xDRI2QueryVersionReply), &rep); |
| 97 | |
| 98 | return Success; |
| 99 | } |
| 100 | |
| 101 | static int |
| 102 | ProcDRI2Connect(ClientPtr client) |
| 103 | { |
| 104 | REQUEST(xDRI2ConnectReq); |
| 105 | xDRI2ConnectReply rep = { |
| 106 | .type = X_Reply, |
| 107 | .sequenceNumber = client->sequence, |
| 108 | .length = 0, |
| 109 | .driverNameLength = 0, |
| 110 | .deviceNameLength = 0 |
| 111 | }; |
| 112 | DrawablePtr pDraw; |
| 113 | int fd, status; |
| 114 | const char *driverName; |
| 115 | const char *deviceName; |
| 116 | |
| 117 | REQUEST_SIZE_MATCH(xDRI2ConnectReq); |
| 118 | if (!validDrawable(client, stuff->window, DixGetAttrAccess, |
| 119 | &pDraw, &status)) |
| 120 | return status; |
| 121 | |
| 122 | if (!DRI2Connect(client, pDraw->pScreen, |
| 123 | stuff->driverType, &fd, &driverName, &deviceName)) |
| 124 | goto fail; |
| 125 | |
| 126 | rep.driverNameLength = strlen(driverName); |
| 127 | rep.deviceNameLength = strlen(deviceName); |
| 128 | rep.length = (rep.driverNameLength + 3) / 4 + |
| 129 | (rep.deviceNameLength + 3) / 4; |
| 130 | |
| 131 | fail: |
| 132 | WriteToClient(client, sizeof(xDRI2ConnectReply), &rep); |
| 133 | WriteToClient(client, rep.driverNameLength, driverName); |
| 134 | WriteToClient(client, rep.deviceNameLength, deviceName); |
| 135 | |
| 136 | return Success; |
| 137 | } |
| 138 | |
| 139 | static int |
| 140 | ProcDRI2Authenticate(ClientPtr client) |
| 141 | { |
| 142 | REQUEST(xDRI2AuthenticateReq); |
| 143 | xDRI2AuthenticateReply rep; |
| 144 | DrawablePtr pDraw; |
| 145 | int status; |
| 146 | |
| 147 | REQUEST_SIZE_MATCH(xDRI2AuthenticateReq); |
| 148 | if (!validDrawable(client, stuff->window, DixGetAttrAccess, |
| 149 | &pDraw, &status)) |
| 150 | return status; |
| 151 | |
| 152 | rep = (xDRI2AuthenticateReply) { |
| 153 | .type = X_Reply, |
| 154 | .sequenceNumber = client->sequence, |
| 155 | .length = 0, |
| 156 | .authenticated = DRI2Authenticate(client, pDraw->pScreen, stuff->magic) |
| 157 | }; |
| 158 | WriteToClient(client, sizeof(xDRI2AuthenticateReply), &rep); |
| 159 | |
| 160 | return Success; |
| 161 | } |
| 162 | |
| 163 | static void |
| 164 | DRI2InvalidateBuffersEvent(DrawablePtr pDraw, void *priv, XID id) |
| 165 | { |
| 166 | ClientPtr client = priv; |
| 167 | xDRI2InvalidateBuffers event = { |
| 168 | .type = DRI2EventBase + DRI2_InvalidateBuffers, |
| 169 | .drawable = id |
| 170 | }; |
| 171 | |
| 172 | WriteEventsToClient(client, 1, (xEvent *) &event); |
| 173 | } |
| 174 | |
| 175 | static int |
| 176 | ProcDRI2CreateDrawable(ClientPtr client) |
| 177 | { |
| 178 | REQUEST(xDRI2CreateDrawableReq); |
| 179 | DrawablePtr pDrawable; |
| 180 | int status; |
| 181 | |
| 182 | REQUEST_SIZE_MATCH(xDRI2CreateDrawableReq); |
| 183 | |
| 184 | if (!validDrawable(client, stuff->drawable, DixAddAccess, |
| 185 | &pDrawable, &status)) |
| 186 | return status; |
| 187 | |
| 188 | status = DRI2CreateDrawable(client, pDrawable, stuff->drawable, |
| 189 | DRI2InvalidateBuffersEvent, client); |
| 190 | if (status != Success) |
| 191 | return status; |
| 192 | |
| 193 | return Success; |
| 194 | } |
| 195 | |
| 196 | static int |
| 197 | ProcDRI2DestroyDrawable(ClientPtr client) |
| 198 | { |
| 199 | REQUEST(xDRI2DestroyDrawableReq); |
| 200 | DrawablePtr pDrawable; |
| 201 | int status; |
| 202 | |
| 203 | REQUEST_SIZE_MATCH(xDRI2DestroyDrawableReq); |
| 204 | if (!validDrawable(client, stuff->drawable, DixRemoveAccess, |
| 205 | &pDrawable, &status)) |
| 206 | return status; |
| 207 | |
| 208 | return Success; |
| 209 | } |
| 210 | |
| 211 | static int |
| 212 | send_buffers_reply(ClientPtr client, DrawablePtr pDrawable, |
| 213 | DRI2BufferPtr * buffers, int count, int width, int height) |
| 214 | { |
| 215 | xDRI2GetBuffersReply rep; |
| 216 | int skip = 0; |
| 217 | int i; |
| 218 | |
| 219 | if (buffers == NULL) |
| 220 | return BadAlloc; |
| 221 | |
| 222 | if (pDrawable->type == DRAWABLE_WINDOW) { |
| 223 | for (i = 0; i < count; i++) { |
| 224 | /* Do not send the real front buffer of a window to the client. |
| 225 | */ |
| 226 | if (buffers[i]->attachment == DRI2BufferFrontLeft) { |
| 227 | skip++; |
| 228 | continue; |
| 229 | } |
| 230 | } |
| 231 | } |
| 232 | |
| 233 | rep = (xDRI2GetBuffersReply) { |
| 234 | .type = X_Reply, |
| 235 | .sequenceNumber = client->sequence, |
| 236 | .length = (count - skip) * sizeof(xDRI2Buffer) / 4, |
| 237 | .width = width, |
| 238 | .height = height, |
| 239 | .count = count - skip |
| 240 | }; |
| 241 | WriteToClient(client, sizeof(xDRI2GetBuffersReply), &rep); |
| 242 | |
| 243 | for (i = 0; i < count; i++) { |
| 244 | xDRI2Buffer buffer; |
| 245 | |
| 246 | /* Do not send the real front buffer of a window to the client. |
| 247 | */ |
| 248 | if ((pDrawable->type == DRAWABLE_WINDOW) |
| 249 | && (buffers[i]->attachment == DRI2BufferFrontLeft)) { |
| 250 | continue; |
| 251 | } |
| 252 | |
| 253 | buffer.attachment = buffers[i]->attachment; |
| 254 | buffer.name = buffers[i]->name; |
| 255 | buffer.pitch = buffers[i]->pitch; |
| 256 | buffer.cpp = buffers[i]->cpp; |
| 257 | buffer.flags = buffers[i]->flags; |
| 258 | WriteToClient(client, sizeof(xDRI2Buffer), &buffer); |
| 259 | } |
| 260 | return Success; |
| 261 | } |
| 262 | |
| 263 | static int |
| 264 | ProcDRI2GetBuffers(ClientPtr client) |
| 265 | { |
| 266 | REQUEST(xDRI2GetBuffersReq); |
| 267 | DrawablePtr pDrawable; |
| 268 | DRI2BufferPtr *buffers; |
| 269 | int status, width, height, count; |
| 270 | unsigned int *attachments; |
| 271 | |
| 272 | REQUEST_FIXED_SIZE(xDRI2GetBuffersReq, stuff->count * 4); |
| 273 | if (!validDrawable(client, stuff->drawable, DixReadAccess | DixWriteAccess, |
| 274 | &pDrawable, &status)) |
| 275 | return status; |
| 276 | |
| 277 | if (DRI2ThrottleClient(client, pDrawable)) |
| 278 | return Success; |
| 279 | |
| 280 | attachments = (unsigned int *) &stuff[1]; |
| 281 | buffers = DRI2GetBuffers(pDrawable, &width, &height, |
| 282 | attachments, stuff->count, &count); |
| 283 | |
| 284 | return send_buffers_reply(client, pDrawable, buffers, count, width, height); |
| 285 | |
| 286 | } |
| 287 | |
| 288 | static int |
| 289 | ProcDRI2GetBuffersWithFormat(ClientPtr client) |
| 290 | { |
| 291 | REQUEST(xDRI2GetBuffersReq); |
| 292 | DrawablePtr pDrawable; |
| 293 | DRI2BufferPtr *buffers; |
| 294 | int status, width, height, count; |
| 295 | unsigned int *attachments; |
| 296 | |
| 297 | REQUEST_FIXED_SIZE(xDRI2GetBuffersReq, stuff->count * (2 * 4)); |
| 298 | if (!validDrawable(client, stuff->drawable, DixReadAccess | DixWriteAccess, |
| 299 | &pDrawable, &status)) |
| 300 | return status; |
| 301 | |
| 302 | if (DRI2ThrottleClient(client, pDrawable)) |
| 303 | return Success; |
| 304 | |
| 305 | attachments = (unsigned int *) &stuff[1]; |
| 306 | buffers = DRI2GetBuffersWithFormat(pDrawable, &width, &height, |
| 307 | attachments, stuff->count, &count); |
| 308 | |
| 309 | return send_buffers_reply(client, pDrawable, buffers, count, width, height); |
| 310 | } |
| 311 | |
| 312 | static int |
| 313 | ProcDRI2CopyRegion(ClientPtr client) |
| 314 | { |
| 315 | REQUEST(xDRI2CopyRegionReq); |
| 316 | xDRI2CopyRegionReply rep; |
| 317 | DrawablePtr pDrawable; |
| 318 | int status; |
| 319 | RegionPtr pRegion; |
| 320 | |
| 321 | REQUEST_SIZE_MATCH(xDRI2CopyRegionReq); |
| 322 | |
| 323 | if (!validDrawable(client, stuff->drawable, DixWriteAccess, |
| 324 | &pDrawable, &status)) |
| 325 | return status; |
| 326 | |
| 327 | VERIFY_REGION(pRegion, stuff->region, client, DixReadAccess); |
| 328 | |
| 329 | status = DRI2CopyRegion(pDrawable, pRegion, stuff->dest, stuff->src); |
| 330 | if (status != Success) |
| 331 | return status; |
| 332 | |
| 333 | /* CopyRegion needs to be a round trip to make sure the X server |
| 334 | * queues the swap buffer rendering commands before the DRI client |
| 335 | * continues rendering. The reply has a bitmask to signal the |
| 336 | * presense of optional return values as well, but we're not using |
| 337 | * that yet. |
| 338 | */ |
| 339 | |
| 340 | rep = (xDRI2CopyRegionReply) { |
| 341 | .type = X_Reply, |
| 342 | .sequenceNumber = client->sequence, |
| 343 | .length = 0 |
| 344 | }; |
| 345 | |
| 346 | WriteToClient(client, sizeof(xDRI2CopyRegionReply), &rep); |
| 347 | |
| 348 | return Success; |
| 349 | } |
| 350 | |
| 351 | static void |
| 352 | load_swap_reply(xDRI2SwapBuffersReply * rep, CARD64 sbc) |
| 353 | { |
| 354 | rep->swap_hi = sbc >> 32; |
| 355 | rep->swap_lo = sbc & 0xffffffff; |
| 356 | } |
| 357 | |
| 358 | static CARD64 |
| 359 | vals_to_card64(CARD32 lo, CARD32 hi) |
| 360 | { |
| 361 | return (CARD64) hi << 32 | lo; |
| 362 | } |
| 363 | |
| 364 | static void |
| 365 | DRI2SwapEvent(ClientPtr client, void *data, int type, CARD64 ust, CARD64 msc, |
| 366 | CARD32 sbc) |
| 367 | { |
| 368 | DrawablePtr pDrawable = data; |
| 369 | xDRI2BufferSwapComplete2 event = { |
| 370 | .type = DRI2EventBase + DRI2_BufferSwapComplete, |
| 371 | .event_type = type, |
| 372 | .drawable = pDrawable->id, |
| 373 | .ust_hi = (CARD64) ust >> 32, |
| 374 | .ust_lo = ust & 0xffffffff, |
| 375 | .msc_hi = (CARD64) msc >> 32, |
| 376 | .msc_lo = msc & 0xffffffff, |
| 377 | .sbc = sbc |
| 378 | }; |
| 379 | |
| 380 | WriteEventsToClient(client, 1, (xEvent *) &event); |
| 381 | } |
| 382 | |
| 383 | static int |
| 384 | ProcDRI2SwapBuffers(ClientPtr client) |
| 385 | { |
| 386 | REQUEST(xDRI2SwapBuffersReq); |
| 387 | xDRI2SwapBuffersReply rep = { |
| 388 | .type = X_Reply, |
| 389 | .sequenceNumber = client->sequence, |
| 390 | .length = 0 |
| 391 | }; |
| 392 | DrawablePtr pDrawable; |
| 393 | CARD64 target_msc, divisor, remainder, swap_target; |
| 394 | int status; |
| 395 | |
| 396 | REQUEST_SIZE_MATCH(xDRI2SwapBuffersReq); |
| 397 | |
| 398 | if (!validDrawable(client, stuff->drawable, |
| 399 | DixReadAccess | DixWriteAccess, &pDrawable, &status)) |
| 400 | return status; |
| 401 | |
| 402 | /* |
| 403 | * Ensures an out of control client can't exhaust our swap queue, and |
| 404 | * also orders swaps. |
| 405 | */ |
| 406 | if (DRI2ThrottleClient(client, pDrawable)) |
| 407 | return Success; |
| 408 | |
| 409 | target_msc = vals_to_card64(stuff->target_msc_lo, stuff->target_msc_hi); |
| 410 | divisor = vals_to_card64(stuff->divisor_lo, stuff->divisor_hi); |
| 411 | remainder = vals_to_card64(stuff->remainder_lo, stuff->remainder_hi); |
| 412 | |
| 413 | status = DRI2SwapBuffers(client, pDrawable, target_msc, divisor, remainder, |
| 414 | &swap_target, DRI2SwapEvent, pDrawable); |
| 415 | if (status != Success) |
| 416 | return BadDrawable; |
| 417 | |
| 418 | load_swap_reply(&rep, swap_target); |
| 419 | |
| 420 | WriteToClient(client, sizeof(xDRI2SwapBuffersReply), &rep); |
| 421 | |
| 422 | return Success; |
| 423 | } |
| 424 | |
| 425 | static void |
| 426 | load_msc_reply(xDRI2MSCReply * rep, CARD64 ust, CARD64 msc, CARD64 sbc) |
| 427 | { |
| 428 | rep->ust_hi = ust >> 32; |
| 429 | rep->ust_lo = ust & 0xffffffff; |
| 430 | rep->msc_hi = msc >> 32; |
| 431 | rep->msc_lo = msc & 0xffffffff; |
| 432 | rep->sbc_hi = sbc >> 32; |
| 433 | rep->sbc_lo = sbc & 0xffffffff; |
| 434 | } |
| 435 | |
| 436 | static int |
| 437 | ProcDRI2GetMSC(ClientPtr client) |
| 438 | { |
| 439 | REQUEST(xDRI2GetMSCReq); |
| 440 | xDRI2MSCReply rep = { |
| 441 | .type = X_Reply, |
| 442 | .sequenceNumber = client->sequence, |
| 443 | .length = 0 |
| 444 | }; |
| 445 | DrawablePtr pDrawable; |
| 446 | CARD64 ust, msc, sbc; |
| 447 | int status; |
| 448 | |
| 449 | REQUEST_SIZE_MATCH(xDRI2GetMSCReq); |
| 450 | |
| 451 | if (!validDrawable(client, stuff->drawable, DixReadAccess, &pDrawable, |
| 452 | &status)) |
| 453 | return status; |
| 454 | |
| 455 | status = DRI2GetMSC(pDrawable, &ust, &msc, &sbc); |
| 456 | if (status != Success) |
| 457 | return status; |
| 458 | |
| 459 | load_msc_reply(&rep, ust, msc, sbc); |
| 460 | |
| 461 | WriteToClient(client, sizeof(xDRI2MSCReply), &rep); |
| 462 | |
| 463 | return Success; |
| 464 | } |
| 465 | |
| 466 | static int |
| 467 | ProcDRI2WaitMSC(ClientPtr client) |
| 468 | { |
| 469 | REQUEST(xDRI2WaitMSCReq); |
| 470 | DrawablePtr pDrawable; |
| 471 | CARD64 target, divisor, remainder; |
| 472 | int status; |
| 473 | |
| 474 | /* FIXME: in restart case, client may be gone at this point */ |
| 475 | |
| 476 | REQUEST_SIZE_MATCH(xDRI2WaitMSCReq); |
| 477 | |
| 478 | if (!validDrawable(client, stuff->drawable, DixReadAccess, &pDrawable, |
| 479 | &status)) |
| 480 | return status; |
| 481 | |
| 482 | target = vals_to_card64(stuff->target_msc_lo, stuff->target_msc_hi); |
| 483 | divisor = vals_to_card64(stuff->divisor_lo, stuff->divisor_hi); |
| 484 | remainder = vals_to_card64(stuff->remainder_lo, stuff->remainder_hi); |
| 485 | |
| 486 | status = DRI2WaitMSC(client, pDrawable, target, divisor, remainder); |
| 487 | if (status != Success) |
| 488 | return status; |
| 489 | |
| 490 | return Success; |
| 491 | } |
| 492 | |
| 493 | int |
| 494 | ProcDRI2WaitMSCReply(ClientPtr client, CARD64 ust, CARD64 msc, CARD64 sbc) |
| 495 | { |
| 496 | xDRI2MSCReply rep = { |
| 497 | .type = X_Reply, |
| 498 | .sequenceNumber = client->sequence, |
| 499 | .length = 0 |
| 500 | }; |
| 501 | |
| 502 | load_msc_reply(&rep, ust, msc, sbc); |
| 503 | |
| 504 | WriteToClient(client, sizeof(xDRI2MSCReply), &rep); |
| 505 | |
| 506 | return Success; |
| 507 | } |
| 508 | |
| 509 | static int |
| 510 | ProcDRI2SwapInterval(ClientPtr client) |
| 511 | { |
| 512 | REQUEST(xDRI2SwapIntervalReq); |
| 513 | DrawablePtr pDrawable; |
| 514 | int status; |
| 515 | |
| 516 | /* FIXME: in restart case, client may be gone at this point */ |
| 517 | |
| 518 | REQUEST_SIZE_MATCH(xDRI2SwapIntervalReq); |
| 519 | |
| 520 | if (!validDrawable(client, stuff->drawable, DixReadAccess | DixWriteAccess, |
| 521 | &pDrawable, &status)) |
| 522 | return status; |
| 523 | |
| 524 | DRI2SwapInterval(pDrawable, stuff->interval); |
| 525 | |
| 526 | return Success; |
| 527 | } |
| 528 | |
| 529 | static int |
| 530 | ProcDRI2WaitSBC(ClientPtr client) |
| 531 | { |
| 532 | REQUEST(xDRI2WaitSBCReq); |
| 533 | DrawablePtr pDrawable; |
| 534 | CARD64 target; |
| 535 | int status; |
| 536 | |
| 537 | REQUEST_SIZE_MATCH(xDRI2WaitSBCReq); |
| 538 | |
| 539 | if (!validDrawable(client, stuff->drawable, DixReadAccess, &pDrawable, |
| 540 | &status)) |
| 541 | return status; |
| 542 | |
| 543 | target = vals_to_card64(stuff->target_sbc_lo, stuff->target_sbc_hi); |
| 544 | status = DRI2WaitSBC(client, pDrawable, target); |
| 545 | |
| 546 | return status; |
| 547 | } |
| 548 | |
| 549 | static int |
| 550 | ProcDRI2GetParam(ClientPtr client) |
| 551 | { |
| 552 | REQUEST(xDRI2GetParamReq); |
| 553 | xDRI2GetParamReply rep = { |
| 554 | .type = X_Reply, |
| 555 | .sequenceNumber = client->sequence, |
| 556 | .length = 0 |
| 557 | }; |
| 558 | DrawablePtr pDrawable; |
| 559 | CARD64 value; |
| 560 | int status; |
| 561 | |
| 562 | REQUEST_SIZE_MATCH(xDRI2GetParamReq); |
| 563 | |
| 564 | if (!validDrawable(client, stuff->drawable, DixReadAccess, |
| 565 | &pDrawable, &status)) |
| 566 | return status; |
| 567 | |
| 568 | status = DRI2GetParam(client, pDrawable, stuff->param, |
| 569 | &rep.is_param_recognized, &value); |
| 570 | rep.value_hi = value >> 32; |
| 571 | rep.value_lo = value & 0xffffffff; |
| 572 | |
| 573 | if (status != Success) |
| 574 | return status; |
| 575 | |
| 576 | WriteToClient(client, sizeof(xDRI2GetParamReply), &rep); |
| 577 | |
| 578 | return status; |
| 579 | } |
| 580 | |
| 581 | static int |
| 582 | ProcDRI2Dispatch(ClientPtr client) |
| 583 | { |
| 584 | REQUEST(xReq); |
| 585 | |
| 586 | switch (stuff->data) { |
| 587 | case X_DRI2QueryVersion: |
| 588 | return ProcDRI2QueryVersion(client); |
| 589 | } |
| 590 | |
| 591 | if (!client->local) |
| 592 | return BadRequest; |
| 593 | |
| 594 | switch (stuff->data) { |
| 595 | case X_DRI2Connect: |
| 596 | return ProcDRI2Connect(client); |
| 597 | case X_DRI2Authenticate: |
| 598 | return ProcDRI2Authenticate(client); |
| 599 | case X_DRI2CreateDrawable: |
| 600 | return ProcDRI2CreateDrawable(client); |
| 601 | case X_DRI2DestroyDrawable: |
| 602 | return ProcDRI2DestroyDrawable(client); |
| 603 | case X_DRI2GetBuffers: |
| 604 | return ProcDRI2GetBuffers(client); |
| 605 | case X_DRI2CopyRegion: |
| 606 | return ProcDRI2CopyRegion(client); |
| 607 | case X_DRI2GetBuffersWithFormat: |
| 608 | return ProcDRI2GetBuffersWithFormat(client); |
| 609 | case X_DRI2SwapBuffers: |
| 610 | return ProcDRI2SwapBuffers(client); |
| 611 | case X_DRI2GetMSC: |
| 612 | return ProcDRI2GetMSC(client); |
| 613 | case X_DRI2WaitMSC: |
| 614 | return ProcDRI2WaitMSC(client); |
| 615 | case X_DRI2WaitSBC: |
| 616 | return ProcDRI2WaitSBC(client); |
| 617 | case X_DRI2SwapInterval: |
| 618 | return ProcDRI2SwapInterval(client); |
| 619 | case X_DRI2GetParam: |
| 620 | return ProcDRI2GetParam(client); |
| 621 | default: |
| 622 | return BadRequest; |
| 623 | } |
| 624 | } |
| 625 | |
| 626 | static int |
| 627 | SProcDRI2Connect(ClientPtr client) |
| 628 | { |
| 629 | REQUEST(xDRI2ConnectReq); |
| 630 | xDRI2ConnectReply rep = { |
| 631 | .type = X_Reply, |
| 632 | .sequenceNumber = client->sequence, |
| 633 | .length = 0, |
| 634 | .driverNameLength = 0, |
| 635 | .deviceNameLength = 0 |
| 636 | }; |
| 637 | |
| 638 | /* If the client is swapped, it's not local. Talk to the hand. */ |
| 639 | |
| 640 | swaps(&stuff->length); |
| 641 | if (sizeof(*stuff) / 4 != client->req_len) |
| 642 | return BadLength; |
| 643 | |
| 644 | swaps(&rep.sequenceNumber); |
| 645 | |
| 646 | WriteToClient(client, sizeof(xDRI2ConnectReply), &rep); |
| 647 | |
| 648 | return Success; |
| 649 | } |
| 650 | |
| 651 | static int |
| 652 | SProcDRI2Dispatch(ClientPtr client) |
| 653 | { |
| 654 | REQUEST(xReq); |
| 655 | |
| 656 | /* |
| 657 | * Only local clients are allowed DRI access, but remote clients |
| 658 | * still need these requests to find out cleanly. |
| 659 | */ |
| 660 | switch (stuff->data) { |
| 661 | case X_DRI2QueryVersion: |
| 662 | return ProcDRI2QueryVersion(client); |
| 663 | case X_DRI2Connect: |
| 664 | return SProcDRI2Connect(client); |
| 665 | default: |
| 666 | return BadRequest; |
| 667 | } |
| 668 | } |
| 669 | |
| 670 | void |
| 671 | DRI2ExtensionInit(void) |
| 672 | { |
| 673 | ExtensionEntry *dri2Extension; |
| 674 | |
| 675 | #ifdef PANORAMIX |
| 676 | if (!noPanoramiXExtension) |
| 677 | return; |
| 678 | #endif |
| 679 | |
| 680 | dri2Extension = AddExtension(DRI2_NAME, |
| 681 | DRI2NumberEvents, |
| 682 | DRI2NumberErrors, |
| 683 | ProcDRI2Dispatch, |
| 684 | SProcDRI2Dispatch, NULL, StandardMinorOpcode); |
| 685 | |
| 686 | DRI2EventBase = dri2Extension->eventBase; |
| 687 | |
| 688 | DRI2ModuleSetup(); |
| 689 | } |