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#include "dri3_priv.h" 24#include <syncsrv.h> 25#include <unistd.h> 26#include <xace.h> 27#include "../Xext/syncsdk.h" 28#include <protocol-versions.h> 29#include <drm_fourcc.h> 30 31static Bool 32dri3_screen_can_one_point_two(ScreenPtr screen) 33{ 34 dri3_screen_priv_ptr dri3 = dri3_screen_priv(screen); 35 36 if (dri3 && dri3->info && dri3->info->version >= 2 && 37 dri3->info->pixmap_from_fds && dri3->info->fds_from_pixmap && 38 dri3->info->get_formats && dri3->info->get_modifiers && 39 dri3->info->get_drawable_modifiers) 40 return TRUE; 41 42 return FALSE; 43} 44 45static int 46proc_dri3_query_version(ClientPtr client) 47{ 48 REQUEST(xDRI3QueryVersionReq); 49 xDRI3QueryVersionReply rep = { 50 .type = X_Reply, 51 .sequenceNumber = client->sequence, 52 .length = 0, 53 .majorVersion = SERVER_DRI3_MAJOR_VERSION, 54 .minorVersion = SERVER_DRI3_MINOR_VERSION 55 }; 56 57 REQUEST_SIZE_MATCH(xDRI3QueryVersionReq); 58 59 for (int i = 0; i < screenInfo.numScreens; i++) { 60 if (!dri3_screen_can_one_point_two(screenInfo.screens[i])) { 61 rep.minorVersion = 0; 62 break; 63 } 64 } 65 66 for (int i = 0; i < screenInfo.numGPUScreens; i++) { 67 if (!dri3_screen_can_one_point_two(screenInfo.gpuscreens[i])) { 68 rep.minorVersion = 0; 69 break; 70 } 71 } 72 73 /* From DRI3 proto: 74 * 75 * The client sends the highest supported version to the server 76 * and the server sends the highest version it supports, but no 77 * higher than the requested version. 78 */ 79 80 if (rep.majorVersion > stuff->majorVersion || 81 (rep.majorVersion == stuff->majorVersion && 82 rep.minorVersion > stuff->minorVersion)) { 83 rep.majorVersion = stuff->majorVersion; 84 rep.minorVersion = stuff->minorVersion; 85 } 86 87 if (client->swapped) { 88 swaps(&rep.sequenceNumber); 89 swapl(&rep.length); 90 swapl(&rep.majorVersion); 91 swapl(&rep.minorVersion); 92 } 93 WriteToClient(client, sizeof(rep), &rep); 94 return Success; 95} 96 97int 98dri3_send_open_reply(ClientPtr client, int fd) 99{ 100 xDRI3OpenReply rep = { 101 .type = X_Reply, 102 .nfd = 1, 103 .sequenceNumber = client->sequence, 104 .length = 0, 105 }; 106 107 if (client->swapped) { 108 swaps(&rep.sequenceNumber); 109 swapl(&rep.length); 110 } 111 112 if (WriteFdToClient(client, fd, TRUE) < 0) { 113 close(fd); 114 return BadAlloc; 115 } 116 117 WriteToClient(client, sizeof (rep), &rep); 118 119 return Success; 120} 121 122static int 123proc_dri3_open(ClientPtr client) 124{ 125 REQUEST(xDRI3OpenReq); 126 RRProviderPtr provider; 127 DrawablePtr drawable; 128 ScreenPtr screen; 129 int fd; 130 int status; 131 132 REQUEST_SIZE_MATCH(xDRI3OpenReq); 133 134 status = dixLookupDrawable(&drawable, stuff->drawable, client, 0, DixGetAttrAccess); 135 if (status != Success) 136 return status; 137 138 if (stuff->provider == None) 139 provider = NULL; 140 else if (!RRProviderType) { 141 return BadMatch; 142 } else { 143 VERIFY_RR_PROVIDER(stuff->provider, provider, DixReadAccess); 144 if (drawable->pScreen != provider->pScreen) 145 return BadMatch; 146 } 147 screen = drawable->pScreen; 148 149 status = dri3_open(client, screen, provider, &fd); 150 if (status != Success) 151 return status; 152 153 if (client->ignoreCount == 0) 154 return dri3_send_open_reply(client, fd); 155 156 return Success; 157} 158 159static int 160proc_dri3_pixmap_from_buffer(ClientPtr client) 161{ 162 REQUEST(xDRI3PixmapFromBufferReq); 163 int fd; 164 DrawablePtr drawable; 165 PixmapPtr pixmap; 166 CARD32 stride, offset; 167 int rc; 168 169 SetReqFds(client, 1); 170 REQUEST_SIZE_MATCH(xDRI3PixmapFromBufferReq); 171 LEGAL_NEW_RESOURCE(stuff->pixmap, client); 172 rc = dixLookupDrawable(&drawable, stuff->drawable, client, M_ANY, DixGetAttrAccess); 173 if (rc != Success) { 174 client->errorValue = stuff->drawable; 175 return rc; 176 } 177 178 if (!stuff->width || !stuff->height) { 179 client->errorValue = 0; 180 return BadValue; 181 } 182 183 if (stuff->width > 32767 || stuff->height > 32767) 184 return BadAlloc; 185 186 if (stuff->depth != 1) { 187 DepthPtr depth = drawable->pScreen->allowedDepths; 188 int i; 189 for (i = 0; i < drawable->pScreen->numDepths; i++, depth++) 190 if (depth->depth == stuff->depth) 191 break; 192 if (i == drawable->pScreen->numDepths) { 193 client->errorValue = stuff->depth; 194 return BadValue; 195 } 196 } 197 198 fd = ReadFdFromClient(client); 199 if (fd < 0) 200 return BadValue; 201 202 offset = 0; 203 stride = stuff->stride; 204 rc = dri3_pixmap_from_fds(&pixmap, 205 drawable->pScreen, 1, &fd, 206 stuff->width, stuff->height, 207 &stride, &offset, 208 stuff->depth, stuff->bpp, 209 DRM_FORMAT_MOD_INVALID); 210 close (fd); 211 if (rc != Success) 212 return rc; 213 214 pixmap->drawable.id = stuff->pixmap; 215 216 /* security creation/labeling check */ 217 rc = XaceHook(XACE_RESOURCE_ACCESS, client, stuff->pixmap, RT_PIXMAP, 218 pixmap, RT_NONE, NULL, DixCreateAccess); 219 220 if (rc != Success) { 221 (*drawable->pScreen->DestroyPixmap) (pixmap); 222 return rc; 223 } 224 if (!AddResource(stuff->pixmap, RT_PIXMAP, (void *) pixmap)) 225 return BadAlloc; 226 227 return Success; 228} 229 230static int 231proc_dri3_buffer_from_pixmap(ClientPtr client) 232{ 233 REQUEST(xDRI3BufferFromPixmapReq); 234 xDRI3BufferFromPixmapReply rep = { 235 .type = X_Reply, 236 .nfd = 1, 237 .sequenceNumber = client->sequence, 238 .length = 0, 239 }; 240 int rc; 241 int fd; 242 PixmapPtr pixmap; 243 244 REQUEST_SIZE_MATCH(xDRI3BufferFromPixmapReq); 245 rc = dixLookupResourceByType((void **) &pixmap, stuff->pixmap, RT_PIXMAP, 246 client, DixWriteAccess); 247 if (rc != Success) { 248 client->errorValue = stuff->pixmap; 249 return rc; 250 } 251 252 rep.width = pixmap->drawable.width; 253 rep.height = pixmap->drawable.height; 254 rep.depth = pixmap->drawable.depth; 255 rep.bpp = pixmap->drawable.bitsPerPixel; 256 257 fd = dri3_fd_from_pixmap(pixmap, &rep.stride, &rep.size); 258 if (fd < 0) 259 return BadPixmap; 260 261 if (client->swapped) { 262 swaps(&rep.sequenceNumber); 263 swapl(&rep.length); 264 swapl(&rep.size); 265 swaps(&rep.width); 266 swaps(&rep.height); 267 swaps(&rep.stride); 268 } 269 if (WriteFdToClient(client, fd, TRUE) < 0) { 270 close(fd); 271 return BadAlloc; 272 } 273 274 WriteToClient(client, sizeof(rep), &rep); 275 276 return Success; 277} 278 279static int 280proc_dri3_fence_from_fd(ClientPtr client) 281{ 282 REQUEST(xDRI3FenceFromFDReq); 283 DrawablePtr drawable; 284 int fd; 285 int status; 286 287 SetReqFds(client, 1); 288 REQUEST_SIZE_MATCH(xDRI3FenceFromFDReq); 289 LEGAL_NEW_RESOURCE(stuff->fence, client); 290 291 status = dixLookupDrawable(&drawable, stuff->drawable, client, M_ANY, DixGetAttrAccess); 292 if (status != Success) 293 return status; 294 295 fd = ReadFdFromClient(client); 296 if (fd < 0) 297 return BadValue; 298 299 status = SyncCreateFenceFromFD(client, drawable, stuff->fence, 300 fd, stuff->initially_triggered); 301 302 return status; 303} 304 305static int 306proc_dri3_fd_from_fence(ClientPtr client) 307{ 308 REQUEST(xDRI3FDFromFenceReq); 309 xDRI3FDFromFenceReply rep = { 310 .type = X_Reply, 311 .nfd = 1, 312 .sequenceNumber = client->sequence, 313 .length = 0, 314 }; 315 DrawablePtr drawable; 316 int fd; 317 int status; 318 SyncFence *fence; 319 320 REQUEST_SIZE_MATCH(xDRI3FDFromFenceReq); 321 322 status = dixLookupDrawable(&drawable, stuff->drawable, client, M_ANY, DixGetAttrAccess); 323 if (status != Success) 324 return status; 325 status = SyncVerifyFence(&fence, stuff->fence, client, DixWriteAccess); 326 if (status != Success) 327 return status; 328 329 fd = SyncFDFromFence(client, drawable, fence); 330 if (fd < 0) 331 return BadMatch; 332 333 if (client->swapped) { 334 swaps(&rep.sequenceNumber); 335 swapl(&rep.length); 336 } 337 if (WriteFdToClient(client, fd, FALSE) < 0) 338 return BadAlloc; 339 340 WriteToClient(client, sizeof(rep), &rep); 341 342 return Success; 343} 344 345static int 346proc_dri3_get_supported_modifiers(ClientPtr client) 347{ 348 REQUEST(xDRI3GetSupportedModifiersReq); 349 xDRI3GetSupportedModifiersReply rep = { 350 .type = X_Reply, 351 .sequenceNumber = client->sequence, 352 }; 353 WindowPtr window; 354 ScreenPtr pScreen; 355 CARD64 *window_modifiers = NULL; 356 CARD64 *screen_modifiers = NULL; 357 CARD32 nwindowmodifiers = 0; 358 CARD32 nscreenmodifiers = 0; 359 int status; 360 int i; 361 362 REQUEST_SIZE_MATCH(xDRI3GetSupportedModifiersReq); 363 364 status = dixLookupWindow(&window, stuff->window, client, DixGetAttrAccess); 365 if (status != Success) 366 return status; 367 pScreen = window->drawable.pScreen; 368 369 dri3_get_supported_modifiers(pScreen, &window->drawable, 370 stuff->depth, stuff->bpp, 371 &nwindowmodifiers, &window_modifiers, 372 &nscreenmodifiers, &screen_modifiers); 373 374 rep.numWindowModifiers = nwindowmodifiers; 375 rep.numScreenModifiers = nscreenmodifiers; 376 rep.length = bytes_to_int32(rep.numWindowModifiers * sizeof(CARD64)) + 377 bytes_to_int32(rep.numScreenModifiers * sizeof(CARD64)); 378 379 if (client->swapped) { 380 swaps(&rep.sequenceNumber); 381 swapl(&rep.length); 382 swapl(&rep.numWindowModifiers); 383 swapl(&rep.numScreenModifiers); 384 for (i = 0; i < nwindowmodifiers; i++) 385 swapll(&window_modifiers[i]); 386 for (i = 0; i < nscreenmodifiers; i++) 387 swapll(&screen_modifiers[i]); 388 } 389 390 WriteToClient(client, sizeof(rep), &rep); 391 WriteToClient(client, nwindowmodifiers * sizeof(CARD64), window_modifiers); 392 WriteToClient(client, nscreenmodifiers * sizeof(CARD64), screen_modifiers); 393 394 free(window_modifiers); 395 free(screen_modifiers); 396 397 return Success; 398} 399 400static int 401proc_dri3_pixmap_from_buffers(ClientPtr client) 402{ 403 REQUEST(xDRI3PixmapFromBuffersReq); 404 int fds[4]; 405 CARD32 strides[4], offsets[4]; 406 ScreenPtr screen; 407 WindowPtr window; 408 PixmapPtr pixmap; 409 int rc; 410 int i; 411 412 SetReqFds(client, stuff->num_buffers); 413 REQUEST_SIZE_MATCH(xDRI3PixmapFromBuffersReq); 414 LEGAL_NEW_RESOURCE(stuff->pixmap, client); 415 rc = dixLookupWindow(&window, stuff->window, client, DixGetAttrAccess); 416 if (rc != Success) { 417 client->errorValue = stuff->window; 418 return rc; 419 } 420 screen = window->drawable.pScreen; 421 422 if (!stuff->width || !stuff->height || !stuff->bpp || !stuff->depth) { 423 client->errorValue = 0; 424 return BadValue; 425 } 426 427 if (stuff->width > 32767 || stuff->height > 32767) 428 return BadAlloc; 429 430 if (stuff->depth != 1) { 431 DepthPtr depth = screen->allowedDepths; 432 int j; 433 for (j = 0; j < screen->numDepths; j++, depth++) 434 if (depth->depth == stuff->depth) 435 break; 436 if (j == screen->numDepths) { 437 client->errorValue = stuff->depth; 438 return BadValue; 439 } 440 } 441 442 if (!stuff->num_buffers || stuff->num_buffers > 4) { 443 client->errorValue = stuff->num_buffers; 444 return BadValue; 445 } 446 447 for (i = 0; i < stuff->num_buffers; i++) { 448 fds[i] = ReadFdFromClient(client); 449 if (fds[i] < 0) { 450 while (--i >= 0) 451 close(fds[i]); 452 return BadValue; 453 } 454 } 455 456 strides[0] = stuff->stride0; 457 strides[1] = stuff->stride1; 458 strides[2] = stuff->stride2; 459 strides[3] = stuff->stride3; 460 offsets[0] = stuff->offset0; 461 offsets[1] = stuff->offset1; 462 offsets[2] = stuff->offset2; 463 offsets[3] = stuff->offset3; 464 465 rc = dri3_pixmap_from_fds(&pixmap, screen, 466 stuff->num_buffers, fds, 467 stuff->width, stuff->height, 468 strides, offsets, 469 stuff->depth, stuff->bpp, 470 stuff->modifier); 471 472 for (i = 0; i < stuff->num_buffers; i++) 473 close (fds[i]); 474 475 if (rc != Success) 476 return rc; 477 478 pixmap->drawable.id = stuff->pixmap; 479 480 /* security creation/labeling check */ 481 rc = XaceHook(XACE_RESOURCE_ACCESS, client, stuff->pixmap, RT_PIXMAP, 482 pixmap, RT_NONE, NULL, DixCreateAccess); 483 484 if (rc != Success) { 485 (*screen->DestroyPixmap) (pixmap); 486 return rc; 487 } 488 if (!AddResource(stuff->pixmap, RT_PIXMAP, (void *) pixmap)) 489 return BadAlloc; 490 491 return Success; 492} 493 494static int 495proc_dri3_buffers_from_pixmap(ClientPtr client) 496{ 497 REQUEST(xDRI3BuffersFromPixmapReq); 498 xDRI3BuffersFromPixmapReply rep = { 499 .type = X_Reply, 500 .sequenceNumber = client->sequence, 501 }; 502 int rc; 503 int fds[4]; 504 int num_fds; 505 uint32_t strides[4], offsets[4]; 506 uint64_t modifier; 507 int i; 508 PixmapPtr pixmap; 509 510 REQUEST_SIZE_MATCH(xDRI3BuffersFromPixmapReq); 511 rc = dixLookupResourceByType((void **) &pixmap, stuff->pixmap, RT_PIXMAP, 512 client, DixWriteAccess); 513 if (rc != Success) { 514 client->errorValue = stuff->pixmap; 515 return rc; 516 } 517 518 num_fds = dri3_fds_from_pixmap(pixmap, fds, strides, offsets, &modifier); 519 if (num_fds == 0) 520 return BadPixmap; 521 522 rep.nfd = num_fds; 523 rep.length = bytes_to_int32(num_fds * 2 * sizeof(CARD32)); 524 rep.width = pixmap->drawable.width; 525 rep.height = pixmap->drawable.height; 526 rep.depth = pixmap->drawable.depth; 527 rep.bpp = pixmap->drawable.bitsPerPixel; 528 rep.modifier = modifier; 529 530 if (client->swapped) { 531 swaps(&rep.sequenceNumber); 532 swapl(&rep.length); 533 swaps(&rep.width); 534 swaps(&rep.height); 535 swapll(&rep.modifier); 536 for (i = 0; i < num_fds; i++) { 537 swapl(&strides[i]); 538 swapl(&offsets[i]); 539 } 540 } 541 542 for (i = 0; i < num_fds; i++) { 543 if (WriteFdToClient(client, fds[i], TRUE) < 0) { 544 while (i--) 545 close(fds[i]); 546 return BadAlloc; 547 } 548 } 549 550 WriteToClient(client, sizeof(rep), &rep); 551 WriteToClient(client, num_fds * sizeof(CARD32), strides); 552 WriteToClient(client, num_fds * sizeof(CARD32), offsets); 553 554 return Success; 555} 556 557int (*proc_dri3_vector[DRI3NumberRequests]) (ClientPtr) = { 558 proc_dri3_query_version, /* 0 */ 559 proc_dri3_open, /* 1 */ 560 proc_dri3_pixmap_from_buffer, /* 2 */ 561 proc_dri3_buffer_from_pixmap, /* 3 */ 562 proc_dri3_fence_from_fd, /* 4 */ 563 proc_dri3_fd_from_fence, /* 5 */ 564 proc_dri3_get_supported_modifiers, /* 6 */ 565 proc_dri3_pixmap_from_buffers, /* 7 */ 566 proc_dri3_buffers_from_pixmap, /* 8 */ 567}; 568 569int 570proc_dri3_dispatch(ClientPtr client) 571{ 572 REQUEST(xReq); 573 if (!client->local) 574 return BadMatch; 575 if (stuff->data >= DRI3NumberRequests || !proc_dri3_vector[stuff->data]) 576 return BadRequest; 577 return (*proc_dri3_vector[stuff->data]) (client); 578} 579 580static int _X_COLD 581sproc_dri3_query_version(ClientPtr client) 582{ 583 REQUEST(xDRI3QueryVersionReq); 584 REQUEST_SIZE_MATCH(xDRI3QueryVersionReq); 585 586 swaps(&stuff->length); 587 swapl(&stuff->majorVersion); 588 swapl(&stuff->minorVersion); 589 return (*proc_dri3_vector[stuff->dri3ReqType]) (client); 590} 591 592static int _X_COLD 593sproc_dri3_open(ClientPtr client) 594{ 595 REQUEST(xDRI3OpenReq); 596 REQUEST_SIZE_MATCH(xDRI3OpenReq); 597 598 swaps(&stuff->length); 599 swapl(&stuff->drawable); 600 swapl(&stuff->provider); 601 return (*proc_dri3_vector[stuff->dri3ReqType]) (client); 602} 603 604static int _X_COLD 605sproc_dri3_pixmap_from_buffer(ClientPtr client) 606{ 607 REQUEST(xDRI3PixmapFromBufferReq); 608 REQUEST_SIZE_MATCH(xDRI3PixmapFromBufferReq); 609 610 swaps(&stuff->length); 611 swapl(&stuff->pixmap); 612 swapl(&stuff->drawable); 613 swapl(&stuff->size); 614 swaps(&stuff->width); 615 swaps(&stuff->height); 616 swaps(&stuff->stride); 617 return (*proc_dri3_vector[stuff->dri3ReqType]) (client); 618} 619 620static int _X_COLD 621sproc_dri3_buffer_from_pixmap(ClientPtr client) 622{ 623 REQUEST(xDRI3BufferFromPixmapReq); 624 REQUEST_SIZE_MATCH(xDRI3BufferFromPixmapReq); 625 626 swaps(&stuff->length); 627 swapl(&stuff->pixmap); 628 return (*proc_dri3_vector[stuff->dri3ReqType]) (client); 629} 630 631static int _X_COLD 632sproc_dri3_fence_from_fd(ClientPtr client) 633{ 634 REQUEST(xDRI3FenceFromFDReq); 635 REQUEST_SIZE_MATCH(xDRI3FenceFromFDReq); 636 637 swaps(&stuff->length); 638 swapl(&stuff->drawable); 639 swapl(&stuff->fence); 640 return (*proc_dri3_vector[stuff->dri3ReqType]) (client); 641} 642 643static int _X_COLD 644sproc_dri3_fd_from_fence(ClientPtr client) 645{ 646 REQUEST(xDRI3FDFromFenceReq); 647 REQUEST_SIZE_MATCH(xDRI3FDFromFenceReq); 648 649 swaps(&stuff->length); 650 swapl(&stuff->drawable); 651 swapl(&stuff->fence); 652 return (*proc_dri3_vector[stuff->dri3ReqType]) (client); 653} 654 655static int _X_COLD 656sproc_dri3_get_supported_modifiers(ClientPtr client) 657{ 658 REQUEST(xDRI3GetSupportedModifiersReq); 659 REQUEST_SIZE_MATCH(xDRI3GetSupportedModifiersReq); 660 661 swaps(&stuff->length); 662 swapl(&stuff->window); 663 return (*proc_dri3_vector[stuff->dri3ReqType]) (client); 664} 665 666static int _X_COLD 667sproc_dri3_pixmap_from_buffers(ClientPtr client) 668{ 669 REQUEST(xDRI3PixmapFromBuffersReq); 670 REQUEST_SIZE_MATCH(xDRI3PixmapFromBuffersReq); 671 672 swaps(&stuff->length); 673 swapl(&stuff->pixmap); 674 swapl(&stuff->window); 675 swaps(&stuff->width); 676 swaps(&stuff->height); 677 swapl(&stuff->stride0); 678 swapl(&stuff->offset0); 679 swapl(&stuff->stride1); 680 swapl(&stuff->offset1); 681 swapl(&stuff->stride2); 682 swapl(&stuff->offset2); 683 swapl(&stuff->stride3); 684 swapl(&stuff->offset3); 685 swapll(&stuff->modifier); 686 return (*proc_dri3_vector[stuff->dri3ReqType]) (client); 687} 688 689static int _X_COLD 690sproc_dri3_buffers_from_pixmap(ClientPtr client) 691{ 692 REQUEST(xDRI3BuffersFromPixmapReq); 693 REQUEST_SIZE_MATCH(xDRI3BuffersFromPixmapReq); 694 695 swaps(&stuff->length); 696 swapl(&stuff->pixmap); 697 return (*proc_dri3_vector[stuff->dri3ReqType]) (client); 698} 699 700int (*sproc_dri3_vector[DRI3NumberRequests]) (ClientPtr) = { 701 sproc_dri3_query_version, /* 0 */ 702 sproc_dri3_open, /* 1 */ 703 sproc_dri3_pixmap_from_buffer, /* 2 */ 704 sproc_dri3_buffer_from_pixmap, /* 3 */ 705 sproc_dri3_fence_from_fd, /* 4 */ 706 sproc_dri3_fd_from_fence, /* 5 */ 707 sproc_dri3_get_supported_modifiers, /* 6 */ 708 sproc_dri3_pixmap_from_buffers, /* 7 */ 709 sproc_dri3_buffers_from_pixmap, /* 8 */ 710}; 711 712int _X_COLD 713sproc_dri3_dispatch(ClientPtr client) 714{ 715 REQUEST(xReq); 716 if (!client->local) 717 return BadMatch; 718 if (stuff->data >= DRI3NumberRequests || !sproc_dri3_vector[stuff->data]) 719 return BadRequest; 720 return (*sproc_dri3_vector[stuff->data]) (client); 721} 722