1 /* 2 * Copyright 2013 Keith Packard 3 * Copyright 2015 Boyan Ding 4 * 5 * Permission to use, copy, modify, distribute, and sell this software and its 6 * documentation for any purpose is hereby granted without fee, provided that 7 * the above copyright notice appear in all copies and that both that copyright 8 * notice and this permission notice appear in supporting documentation, and 9 * that the name of the copyright holders not be used in advertising or 10 * publicity pertaining to distribution of the software without specific, 11 * written prior permission. The copyright holders make no representations 12 * about the suitability of this software for any purpose. It is provided "as 13 * is" without express or implied warranty. 14 * 15 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 17 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 19 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 20 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 21 * OF THIS SOFTWARE. 22 */ 23 24 #include <fcntl.h> 25 #include <stdlib.h> 26 #include <unistd.h> 27 28 #include <X11/xshmfence.h> 29 #include <xcb/xcb.h> 30 #include <xcb/dri3.h> 31 #include <xcb/present.h> 32 33 #include <X11/Xlib-xcb.h> 34 35 #include "loader_dri3_helper.h" 36 37 /* From xmlpool/options.h, user exposed so should be stable */ 38 #define DRI_CONF_VBLANK_NEVER 0 39 #define DRI_CONF_VBLANK_DEF_INTERVAL_0 1 40 #define DRI_CONF_VBLANK_DEF_INTERVAL_1 2 41 #define DRI_CONF_VBLANK_ALWAYS_SYNC 3 42 43 static inline void 44 dri3_fence_reset(xcb_connection_t *c, struct loader_dri3_buffer *buffer) 45 { 46 xshmfence_reset(buffer->shm_fence); 47 } 48 49 static inline void 50 dri3_fence_set(struct loader_dri3_buffer *buffer) 51 { 52 xshmfence_trigger(buffer->shm_fence); 53 } 54 55 static inline void 56 dri3_fence_trigger(xcb_connection_t *c, struct loader_dri3_buffer *buffer) 57 { 58 xcb_sync_trigger_fence(c, buffer->sync_fence); 59 } 60 61 static inline void 62 dri3_fence_await(xcb_connection_t *c, struct loader_dri3_buffer *buffer) 63 { 64 xcb_flush(c); 65 xshmfence_await(buffer->shm_fence); 66 } 67 68 static void 69 dri3_update_num_back(struct loader_dri3_drawable *draw) 70 { 71 if (draw->flipping) 72 draw->num_back = 3; 73 else 74 draw->num_back = 2; 75 } 76 77 void 78 loader_dri3_set_swap_interval(struct loader_dri3_drawable *draw, int interval) 79 { 80 interval = draw->vtable->clamp_swap_interval(draw, interval); 81 draw->vtable->set_swap_interval(draw, interval); 82 dri3_update_num_back(draw); 83 } 84 85 /** dri3_free_render_buffer 86 * 87 * Free everything associated with one render buffer including pixmap, fence 88 * stuff and the driver image 89 */ 90 static void 91 dri3_free_render_buffer(struct loader_dri3_drawable *draw, 92 struct loader_dri3_buffer *buffer) 93 { 94 if (buffer->own_pixmap) 95 xcb_free_pixmap(draw->conn, buffer->pixmap); 96 xcb_sync_destroy_fence(draw->conn, buffer->sync_fence); 97 xshmfence_unmap_shm(buffer->shm_fence); 98 draw->ext->image->destroyImage(buffer->image); 99 if (buffer->linear_buffer) 100 draw->ext->image->destroyImage(buffer->linear_buffer); 101 free(buffer); 102 } 103 104 void 105 loader_dri3_drawable_fini(struct loader_dri3_drawable *draw) 106 { 107 int i; 108 109 draw->ext->core->destroyDrawable(draw->dri_drawable); 110 111 for (i = 0; i < LOADER_DRI3_NUM_BUFFERS; i++) { 112 if (draw->buffers[i]) 113 dri3_free_render_buffer(draw, draw->buffers[i]); 114 } 115 116 if (draw->special_event) { 117 xcb_void_cookie_t cookie = 118 xcb_present_select_input_checked(draw->conn, draw->eid, draw->drawable, 119 XCB_PRESENT_EVENT_MASK_NO_EVENT); 120 121 xcb_discard_reply(draw->conn, cookie.sequence); 122 xcb_unregister_for_special_event(draw->conn, draw->special_event); 123 } 124 } 125 126 int 127 loader_dri3_drawable_init(xcb_connection_t *conn, 128 xcb_drawable_t drawable, 129 __DRIscreen *dri_screen, 130 bool is_different_gpu, 131 const __DRIconfig *dri_config, 132 struct loader_dri3_extensions *ext, 133 const struct loader_dri3_vtable *vtable, 134 struct loader_dri3_drawable *draw) 135 { 136 xcb_get_geometry_cookie_t cookie; 137 xcb_get_geometry_reply_t *reply; 138 xcb_generic_error_t *error; 139 GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1; 140 int swap_interval; 141 142 draw->conn = conn; 143 draw->ext = ext; 144 draw->vtable = vtable; 145 draw->drawable = drawable; 146 draw->dri_screen = dri_screen; 147 draw->is_different_gpu = is_different_gpu; 148 149 draw->have_back = 0; 150 draw->have_fake_front = 0; 151 draw->first_init = true; 152 153 if (draw->ext->config) 154 draw->ext->config->configQueryi(draw->dri_screen, 155 "vblank_mode", &vblank_mode); 156 157 switch (vblank_mode) { 158 case DRI_CONF_VBLANK_NEVER: 159 case DRI_CONF_VBLANK_DEF_INTERVAL_0: 160 swap_interval = 0; 161 break; 162 case DRI_CONF_VBLANK_DEF_INTERVAL_1: 163 case DRI_CONF_VBLANK_ALWAYS_SYNC: 164 default: 165 swap_interval = 1; 166 break; 167 } 168 draw->vtable->set_swap_interval(draw, swap_interval); 169 170 dri3_update_num_back(draw); 171 172 /* Create a new drawable */ 173 draw->dri_drawable = 174 draw->ext->image_driver->createNewDrawable(dri_screen, 175 dri_config, 176 draw); 177 178 if (!draw->dri_drawable) 179 return 1; 180 181 cookie = xcb_get_geometry(draw->conn, draw->drawable); 182 reply = xcb_get_geometry_reply(draw->conn, cookie, &error); 183 if (reply == NULL || error != NULL) { 184 draw->ext->core->destroyDrawable(draw->dri_drawable); 185 return 1; 186 } 187 188 draw->width = reply->width; 189 draw->height = reply->height; 190 draw->depth = reply->depth; 191 draw->vtable->set_drawable_size(draw, draw->width, draw->height); 192 free(reply); 193 194 /* 195 * Make sure server has the same swap interval we do for the new 196 * drawable. 197 */ 198 loader_dri3_set_swap_interval(draw, swap_interval); 199 200 return 0; 201 } 202 203 /* 204 * Process one Present event 205 */ 206 static void 207 dri3_handle_present_event(struct loader_dri3_drawable *draw, 208 xcb_present_generic_event_t *ge) 209 { 210 switch (ge->evtype) { 211 case XCB_PRESENT_CONFIGURE_NOTIFY: { 212 xcb_present_configure_notify_event_t *ce = (void *) ge; 213 214 draw->width = ce->width; 215 draw->height = ce->height; 216 draw->vtable->set_drawable_size(draw, draw->width, draw->height); 217 break; 218 } 219 case XCB_PRESENT_COMPLETE_NOTIFY: { 220 xcb_present_complete_notify_event_t *ce = (void *) ge; 221 222 /* Compute the processed SBC number from the received 32-bit serial number 223 * merged with the upper 32-bits of the sent 64-bit serial number while 224 * checking for wrap. 225 */ 226 if (ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP) { 227 draw->recv_sbc = (draw->send_sbc & 0xffffffff00000000LL) | ce->serial; 228 if (draw->recv_sbc > draw->send_sbc) 229 draw->recv_sbc -= 0x100000000; 230 switch (ce->mode) { 231 case XCB_PRESENT_COMPLETE_MODE_FLIP: 232 draw->flipping = true; 233 break; 234 case XCB_PRESENT_COMPLETE_MODE_COPY: 235 draw->flipping = false; 236 break; 237 } 238 dri3_update_num_back(draw); 239 240 if (draw->vtable->show_fps) 241 draw->vtable->show_fps(draw, ce->ust); 242 243 draw->ust = ce->ust; 244 draw->msc = ce->msc; 245 } else { 246 draw->recv_msc_serial = ce->serial; 247 draw->notify_ust = ce->ust; 248 draw->notify_msc = ce->msc; 249 } 250 break; 251 } 252 case XCB_PRESENT_EVENT_IDLE_NOTIFY: { 253 xcb_present_idle_notify_event_t *ie = (void *) ge; 254 int b; 255 256 for (b = 0; b < sizeof(draw->buffers) / sizeof(draw->buffers[0]); b++) { 257 struct loader_dri3_buffer *buf = draw->buffers[b]; 258 259 if (buf && buf->pixmap == ie->pixmap) { 260 buf->busy = 0; 261 if (draw->num_back <= b && b < LOADER_DRI3_MAX_BACK) { 262 dri3_free_render_buffer(draw, buf); 263 draw->buffers[b] = NULL; 264 } 265 break; 266 } 267 } 268 break; 269 } 270 } 271 free(ge); 272 } 273 274 static bool 275 dri3_wait_for_event(struct loader_dri3_drawable *draw) 276 { 277 xcb_generic_event_t *ev; 278 xcb_present_generic_event_t *ge; 279 280 xcb_flush(draw->conn); 281 ev = xcb_wait_for_special_event(draw->conn, draw->special_event); 282 if (!ev) 283 return false; 284 ge = (void *) ev; 285 dri3_handle_present_event(draw, ge); 286 return true; 287 } 288 289 /** loader_dri3_wait_for_msc 290 * 291 * Get the X server to send an event when the target msc/divisor/remainder is 292 * reached. 293 */ 294 bool 295 loader_dri3_wait_for_msc(struct loader_dri3_drawable *draw, 296 int64_t target_msc, 297 int64_t divisor, int64_t remainder, 298 int64_t *ust, int64_t *msc, int64_t *sbc) 299 { 300 uint32_t msc_serial; 301 302 msc_serial = ++draw->send_msc_serial; 303 xcb_present_notify_msc(draw->conn, 304 draw->drawable, 305 msc_serial, 306 target_msc, 307 divisor, 308 remainder); 309 310 xcb_flush(draw->conn); 311 312 /* Wait for the event */ 313 if (draw->special_event) { 314 while ((int32_t) (msc_serial - draw->recv_msc_serial) > 0) { 315 if (!dri3_wait_for_event(draw)) 316 return false; 317 } 318 } 319 320 *ust = draw->notify_ust; 321 *msc = draw->notify_msc; 322 *sbc = draw->recv_sbc; 323 324 return true; 325 } 326 327 /** loader_dri3_wait_for_sbc 328 * 329 * Wait for the completed swap buffer count to reach the specified 330 * target. Presumably the application knows that this will be reached with 331 * outstanding complete events, or we're going to be here awhile. 332 */ 333 int 334 loader_dri3_wait_for_sbc(struct loader_dri3_drawable *draw, 335 int64_t target_sbc, int64_t *ust, 336 int64_t *msc, int64_t *sbc) 337 { 338 /* From the GLX_OML_sync_control spec: 339 * 340 * "If <target_sbc> = 0, the function will block until all previous 341 * swaps requested with glXSwapBuffersMscOML for that window have 342 * completed." 343 */ 344 if (!target_sbc) 345 target_sbc = draw->send_sbc; 346 347 while (draw->recv_sbc < target_sbc) { 348 if (!dri3_wait_for_event(draw)) 349 return 0; 350 } 351 352 *ust = draw->ust; 353 *msc = draw->msc; 354 *sbc = draw->recv_sbc; 355 return 1; 356 } 357 358 /** loader_dri3_find_back 359 * 360 * Find an idle back buffer. If there isn't one, then 361 * wait for a present idle notify event from the X server 362 */ 363 static int 364 dri3_find_back(struct loader_dri3_drawable *draw) 365 { 366 int b; 367 xcb_generic_event_t *ev; 368 xcb_present_generic_event_t *ge; 369 370 for (;;) { 371 for (b = 0; b < draw->num_back; b++) { 372 int id = LOADER_DRI3_BACK_ID((b + draw->cur_back) % draw->num_back); 373 struct loader_dri3_buffer *buffer = draw->buffers[id]; 374 375 if (!buffer || !buffer->busy) { 376 draw->cur_back = id; 377 return id; 378 } 379 } 380 xcb_flush(draw->conn); 381 ev = xcb_wait_for_special_event(draw->conn, draw->special_event); 382 if (!ev) 383 return -1; 384 ge = (void *) ev; 385 dri3_handle_present_event(draw, ge); 386 } 387 } 388 389 static xcb_gcontext_t 390 dri3_drawable_gc(struct loader_dri3_drawable *draw) 391 { 392 if (!draw->gc) { 393 uint32_t v = 0; 394 xcb_create_gc(draw->conn, 395 (draw->gc = xcb_generate_id(draw->conn)), 396 draw->drawable, 397 XCB_GC_GRAPHICS_EXPOSURES, 398 &v); 399 } 400 return draw->gc; 401 } 402 403 404 static struct loader_dri3_buffer * 405 dri3_back_buffer(struct loader_dri3_drawable *draw) 406 { 407 return draw->buffers[LOADER_DRI3_BACK_ID(draw->cur_back)]; 408 } 409 410 static struct loader_dri3_buffer * 411 dri3_fake_front_buffer(struct loader_dri3_drawable *draw) 412 { 413 return draw->buffers[LOADER_DRI3_FRONT_ID]; 414 } 415 416 static void 417 dri3_copy_area(xcb_connection_t *c, 418 xcb_drawable_t src_drawable, 419 xcb_drawable_t dst_drawable, 420 xcb_gcontext_t gc, 421 int16_t src_x, 422 int16_t src_y, 423 int16_t dst_x, 424 int16_t dst_y, 425 uint16_t width, 426 uint16_t height) 427 { 428 xcb_void_cookie_t cookie; 429 430 cookie = xcb_copy_area_checked(c, 431 src_drawable, 432 dst_drawable, 433 gc, 434 src_x, 435 src_y, 436 dst_x, 437 dst_y, 438 width, 439 height); 440 xcb_discard_reply(c, cookie.sequence); 441 } 442 443 /** 444 * Asks the driver to flush any queued work necessary for serializing with the 445 * X command stream, and optionally the slightly more strict requirement of 446 * glFlush() equivalence (which would require flushing even if nothing had 447 * been drawn to a window system framebuffer, for example). 448 */ 449 void 450 loader_dri3_flush(struct loader_dri3_drawable *draw, 451 unsigned flags, 452 enum __DRI2throttleReason throttle_reason) 453 { 454 /* NEED TO CHECK WHETHER CONTEXT IS NULL */ 455 __DRIcontext *dri_context = draw->vtable->get_dri_context(draw); 456 457 if (dri_context) { 458 draw->ext->flush->flush_with_flags(dri_context, draw->dri_drawable, 459 flags, throttle_reason); 460 } 461 } 462 463 void 464 loader_dri3_copy_sub_buffer(struct loader_dri3_drawable *draw, 465 int x, int y, 466 int width, int height, 467 bool flush) 468 { 469 struct loader_dri3_buffer *back; 470 unsigned flags = __DRI2_FLUSH_DRAWABLE; 471 __DRIcontext *dri_context; 472 473 dri_context = draw->vtable->get_dri_context(draw); 474 475 /* Check we have the right attachments */ 476 if (!draw->have_back || draw->is_pixmap) 477 return; 478 479 if (flush) 480 flags |= __DRI2_FLUSH_CONTEXT; 481 loader_dri3_flush(draw, flags, __DRI2_THROTTLE_SWAPBUFFER); 482 483 back = dri3_back_buffer(draw); 484 y = draw->height - y - height; 485 486 if (draw->is_different_gpu && draw->vtable->in_current_context(draw)) { 487 /* Update the linear buffer part of the back buffer 488 * for the dri3_copy_area operation 489 */ 490 draw->ext->image->blitImage(dri_context, 491 back->linear_buffer, 492 back->image, 493 0, 0, back->width, 494 back->height, 495 0, 0, back->width, 496 back->height, __BLIT_FLAG_FLUSH); 497 /* We use blitImage to update our fake front, 498 */ 499 if (draw->have_fake_front) 500 draw->ext->image->blitImage(dri_context, 501 dri3_fake_front_buffer(draw)->image, 502 back->image, 503 x, y, width, height, 504 x, y, width, height, __BLIT_FLAG_FLUSH); 505 } 506 507 dri3_fence_reset(draw->conn, back); 508 dri3_copy_area(draw->conn, 509 dri3_back_buffer(draw)->pixmap, 510 draw->drawable, 511 dri3_drawable_gc(draw), 512 x, y, x, y, width, height); 513 dri3_fence_trigger(draw->conn, back); 514 /* Refresh the fake front (if present) after we just damaged the real 515 * front. 516 */ 517 if (draw->have_fake_front && !draw->is_different_gpu) { 518 dri3_fence_reset(draw->conn, dri3_fake_front_buffer(draw)); 519 dri3_copy_area(draw->conn, 520 dri3_back_buffer(draw)->pixmap, 521 dri3_fake_front_buffer(draw)->pixmap, 522 dri3_drawable_gc(draw), 523 x, y, x, y, width, height); 524 dri3_fence_trigger(draw->conn, dri3_fake_front_buffer(draw)); 525 dri3_fence_await(draw->conn, dri3_fake_front_buffer(draw)); 526 } 527 dri3_fence_await(draw->conn, back); 528 } 529 530 void 531 loader_dri3_copy_drawable(struct loader_dri3_drawable *draw, 532 xcb_drawable_t dest, 533 xcb_drawable_t src) 534 { 535 loader_dri3_flush(draw, __DRI2_FLUSH_DRAWABLE, 0); 536 537 dri3_fence_reset(draw->conn, dri3_fake_front_buffer(draw)); 538 dri3_copy_area(draw->conn, 539 src, dest, 540 dri3_drawable_gc(draw), 541 0, 0, 0, 0, draw->width, draw->height); 542 dri3_fence_trigger(draw->conn, dri3_fake_front_buffer(draw)); 543 dri3_fence_await(draw->conn, dri3_fake_front_buffer(draw)); 544 } 545 546 void 547 loader_dri3_wait_x(struct loader_dri3_drawable *draw) 548 { 549 struct loader_dri3_buffer *front; 550 __DRIcontext *dri_context; 551 552 if (draw == NULL || !draw->have_fake_front) 553 return; 554 555 front = dri3_fake_front_buffer(draw); 556 dri_context = draw->vtable->get_dri_context(draw); 557 558 loader_dri3_copy_drawable(draw, front->pixmap, draw->drawable); 559 560 /* In the psc->is_different_gpu case, the linear buffer has been updated, 561 * but not yet the tiled buffer. 562 * Copy back to the tiled buffer we use for rendering. 563 * Note that we don't need flushing. 564 */ 565 if (draw->is_different_gpu && draw->vtable->in_current_context(draw)) 566 draw->ext->image->blitImage(dri_context, 567 front->image, 568 front->linear_buffer, 569 0, 0, front->width, 570 front->height, 571 0, 0, front->width, 572 front->height, 0); 573 } 574 575 void 576 loader_dri3_wait_gl(struct loader_dri3_drawable *draw) 577 { 578 struct loader_dri3_buffer *front; 579 __DRIcontext *dri_context; 580 581 if (draw == NULL || !draw->have_fake_front) 582 return; 583 584 front = dri3_fake_front_buffer(draw); 585 dri_context = draw->vtable->get_dri_context(draw); 586 587 /* In the psc->is_different_gpu case, we update the linear_buffer 588 * before updating the real front. 589 */ 590 if (draw->is_different_gpu && draw->vtable->in_current_context(draw)) 591 draw->ext->image->blitImage(dri_context, 592 front->linear_buffer, 593 front->image, 594 0, 0, front->width, 595 front->height, 596 0, 0, front->width, 597 front->height, __BLIT_FLAG_FLUSH); 598 loader_dri3_copy_drawable(draw, draw->drawable, front->pixmap); 599 } 600 601 /** dri3_flush_present_events 602 * 603 * Process any present events that have been received from the X server 604 */ 605 static void 606 dri3_flush_present_events(struct loader_dri3_drawable *draw) 607 { 608 /* Check to see if any configuration changes have occurred 609 * since we were last invoked 610 */ 611 if (draw->special_event) { 612 xcb_generic_event_t *ev; 613 614 while ((ev = xcb_poll_for_special_event(draw->conn, 615 draw->special_event)) != NULL) { 616 xcb_present_generic_event_t *ge = (void *) ev; 617 dri3_handle_present_event(draw, ge); 618 } 619 } 620 } 621 622 /** loader_dri3_swap_buffers_msc 623 * 624 * Make the current back buffer visible using the present extension 625 */ 626 int64_t 627 loader_dri3_swap_buffers_msc(struct loader_dri3_drawable *draw, 628 int64_t target_msc, int64_t divisor, 629 int64_t remainder, unsigned flush_flags, 630 bool force_copy) 631 { 632 struct loader_dri3_buffer *back; 633 __DRIcontext *dri_context; 634 int64_t ret = 0; 635 uint32_t options = XCB_PRESENT_OPTION_NONE; 636 int swap_interval; 637 638 dri_context = draw->vtable->get_dri_context(draw); 639 swap_interval = draw->vtable->get_swap_interval(draw); 640 641 draw->vtable->flush_drawable(draw, flush_flags); 642 643 back = draw->buffers[LOADER_DRI3_BACK_ID(draw->cur_back)]; 644 if (draw->is_different_gpu && back) { 645 /* Update the linear buffer before presenting the pixmap */ 646 draw->ext->image->blitImage(dri_context, 647 back->linear_buffer, 648 back->image, 649 0, 0, back->width, 650 back->height, 651 0, 0, back->width, 652 back->height, __BLIT_FLAG_FLUSH); 653 /* Update the fake front */ 654 if (draw->have_fake_front) 655 draw->ext->image->blitImage(dri_context, 656 draw->buffers[LOADER_DRI3_FRONT_ID]->image, 657 back->image, 658 0, 0, draw->width, draw->height, 659 0, 0, draw->width, draw->height, 660 __BLIT_FLAG_FLUSH); 661 } 662 663 dri3_flush_present_events(draw); 664 665 if (back && !draw->is_pixmap) { 666 dri3_fence_reset(draw->conn, back); 667 668 /* Compute when we want the frame shown by taking the last known 669 * successful MSC and adding in a swap interval for each outstanding swap 670 * request. target_msc=divisor=remainder=0 means "Use glXSwapBuffers() 671 * semantic" 672 */ 673 ++draw->send_sbc; 674 if (target_msc == 0 && divisor == 0 && remainder == 0) 675 target_msc = draw->msc + swap_interval * 676 (draw->send_sbc - draw->recv_sbc); 677 else if (divisor == 0 && remainder > 0) { 678 /* From the GLX_OML_sync_control spec: 679 * "If <divisor> = 0, the swap will occur when MSC becomes 680 * greater than or equal to <target_msc>." 681 * 682 * Note that there's no mention of the remainder. The Present 683 * extension throws BadValue for remainder != 0 with divisor == 0, so 684 * just drop the passed in value. 685 */ 686 remainder = 0; 687 } 688 689 /* From the GLX_EXT_swap_control spec 690 * and the EGL 1.4 spec (page 53): 691 * 692 * "If <interval> is set to a value of 0, buffer swaps are not 693 * synchronized to a video frame." 694 * 695 * Implementation note: It is possible to enable triple buffering 696 * behaviour by not using XCB_PRESENT_OPTION_ASYNC, but this should not be 697 * the default. 698 */ 699 if (swap_interval == 0) 700 options |= XCB_PRESENT_OPTION_ASYNC; 701 if (force_copy) 702 options |= XCB_PRESENT_OPTION_COPY; 703 704 back->busy = 1; 705 back->last_swap = draw->send_sbc; 706 xcb_present_pixmap(draw->conn, 707 draw->drawable, 708 back->pixmap, 709 (uint32_t) draw->send_sbc, 710 0, /* valid */ 711 0, /* update */ 712 0, /* x_off */ 713 0, /* y_off */ 714 None, /* target_crtc */ 715 None, 716 back->sync_fence, 717 options, 718 target_msc, 719 divisor, 720 remainder, 0, NULL); 721 ret = (int64_t) draw->send_sbc; 722 723 /* If there's a fake front, then copy the source back buffer 724 * to the fake front to keep it up to date. This needs 725 * to reset the fence and make future users block until 726 * the X server is done copying the bits 727 */ 728 if (draw->have_fake_front && !draw->is_different_gpu) { 729 dri3_fence_reset(draw->conn, draw->buffers[LOADER_DRI3_FRONT_ID]); 730 dri3_copy_area(draw->conn, 731 back->pixmap, 732 draw->buffers[LOADER_DRI3_FRONT_ID]->pixmap, 733 dri3_drawable_gc(draw), 734 0, 0, 0, 0, 735 draw->width, draw->height); 736 dri3_fence_trigger(draw->conn, draw->buffers[LOADER_DRI3_FRONT_ID]); 737 } 738 xcb_flush(draw->conn); 739 if (draw->stamp) 740 ++(*draw->stamp); 741 } 742 743 draw->ext->flush->invalidate(draw->dri_drawable); 744 745 return ret; 746 } 747 748 int 749 loader_dri3_query_buffer_age(struct loader_dri3_drawable *draw) 750 { 751 int back_id = LOADER_DRI3_BACK_ID(dri3_find_back(draw)); 752 753 if (back_id < 0 || !draw->buffers[back_id]) 754 return 0; 755 756 if (draw->buffers[back_id]->last_swap != 0) 757 return draw->send_sbc - draw->buffers[back_id]->last_swap + 1; 758 else 759 return 0; 760 } 761 762 /** loader_dri3_open 763 * 764 * Wrapper around xcb_dri3_open 765 */ 766 int 767 loader_dri3_open(xcb_connection_t *conn, 768 xcb_window_t root, 769 uint32_t provider) 770 { 771 xcb_dri3_open_cookie_t cookie; 772 xcb_dri3_open_reply_t *reply; 773 int fd; 774 775 cookie = xcb_dri3_open(conn, 776 root, 777 provider); 778 779 reply = xcb_dri3_open_reply(conn, cookie, NULL); 780 if (!reply) 781 return -1; 782 783 if (reply->nfd != 1) { 784 free(reply); 785 return -1; 786 } 787 788 fd = xcb_dri3_open_reply_fds(conn, reply)[0]; 789 free(reply); 790 fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); 791 792 return fd; 793 } 794 795 static uint32_t 796 dri3_cpp_for_format(uint32_t format) { 797 switch (format) { 798 case __DRI_IMAGE_FORMAT_R8: 799 return 1; 800 case __DRI_IMAGE_FORMAT_RGB565: 801 case __DRI_IMAGE_FORMAT_GR88: 802 return 2; 803 case __DRI_IMAGE_FORMAT_XRGB8888: 804 case __DRI_IMAGE_FORMAT_ARGB8888: 805 case __DRI_IMAGE_FORMAT_ABGR8888: 806 case __DRI_IMAGE_FORMAT_XBGR8888: 807 case __DRI_IMAGE_FORMAT_XRGB2101010: 808 case __DRI_IMAGE_FORMAT_ARGB2101010: 809 case __DRI_IMAGE_FORMAT_SARGB8: 810 return 4; 811 case __DRI_IMAGE_FORMAT_NONE: 812 default: 813 return 0; 814 } 815 } 816 817 /** loader_dri3_alloc_render_buffer 818 * 819 * Use the driver createImage function to construct a __DRIimage, then 820 * get a file descriptor for that and create an X pixmap from that 821 * 822 * Allocate an xshmfence for synchronization 823 */ 824 static struct loader_dri3_buffer * 825 dri3_alloc_render_buffer(struct loader_dri3_drawable *draw, unsigned int format, 826 int width, int height, int depth) 827 { 828 struct loader_dri3_buffer *buffer; 829 __DRIimage *pixmap_buffer; 830 xcb_pixmap_t pixmap; 831 xcb_sync_fence_t sync_fence; 832 struct xshmfence *shm_fence; 833 int buffer_fd, fence_fd; 834 int stride; 835 836 /* Create an xshmfence object and 837 * prepare to send that to the X server 838 */ 839 840 fence_fd = xshmfence_alloc_shm(); 841 if (fence_fd < 0) 842 return NULL; 843 844 shm_fence = xshmfence_map_shm(fence_fd); 845 if (shm_fence == NULL) 846 goto no_shm_fence; 847 848 /* Allocate the image from the driver 849 */ 850 buffer = calloc(1, sizeof *buffer); 851 if (!buffer) 852 goto no_buffer; 853 854 buffer->cpp = dri3_cpp_for_format(format); 855 if (!buffer->cpp) 856 goto no_image; 857 858 if (!draw->is_different_gpu) { 859 buffer->image = draw->ext->image->createImage(draw->dri_screen, 860 width, height, 861 format, 862 __DRI_IMAGE_USE_SHARE | 863 __DRI_IMAGE_USE_SCANOUT | 864 __DRI_IMAGE_USE_BACKBUFFER, 865 buffer); 866 pixmap_buffer = buffer->image; 867 868 if (!buffer->image) 869 goto no_image; 870 } else { 871 buffer->image = draw->ext->image->createImage(draw->dri_screen, 872 width, height, 873 format, 874 0, 875 buffer); 876 877 if (!buffer->image) 878 goto no_image; 879 880 buffer->linear_buffer = 881 draw->ext->image->createImage(draw->dri_screen, 882 width, height, format, 883 __DRI_IMAGE_USE_SHARE | 884 __DRI_IMAGE_USE_LINEAR | 885 __DRI_IMAGE_USE_BACKBUFFER, 886 buffer); 887 pixmap_buffer = buffer->linear_buffer; 888 889 if (!buffer->linear_buffer) 890 goto no_linear_buffer; 891 } 892 893 /* X wants the stride, so ask the image for it 894 */ 895 if (!draw->ext->image->queryImage(pixmap_buffer, __DRI_IMAGE_ATTRIB_STRIDE, 896 &stride)) 897 goto no_buffer_attrib; 898 899 buffer->pitch = stride; 900 901 if (!draw->ext->image->queryImage(pixmap_buffer, __DRI_IMAGE_ATTRIB_FD, 902 &buffer_fd)) 903 goto no_buffer_attrib; 904 905 xcb_dri3_pixmap_from_buffer(draw->conn, 906 (pixmap = xcb_generate_id(draw->conn)), 907 draw->drawable, 908 buffer->size, 909 width, height, buffer->pitch, 910 depth, buffer->cpp * 8, 911 buffer_fd); 912 913 xcb_dri3_fence_from_fd(draw->conn, 914 pixmap, 915 (sync_fence = xcb_generate_id(draw->conn)), 916 false, 917 fence_fd); 918 919 buffer->pixmap = pixmap; 920 buffer->own_pixmap = true; 921 buffer->sync_fence = sync_fence; 922 buffer->shm_fence = shm_fence; 923 buffer->width = width; 924 buffer->height = height; 925 926 /* Mark the buffer as idle 927 */ 928 dri3_fence_set(buffer); 929 930 return buffer; 931 932 no_buffer_attrib: 933 draw->ext->image->destroyImage(pixmap_buffer); 934 no_linear_buffer: 935 if (draw->is_different_gpu) 936 draw->ext->image->destroyImage(buffer->image); 937 no_image: 938 free(buffer); 939 no_buffer: 940 xshmfence_unmap_shm(shm_fence); 941 no_shm_fence: 942 close(fence_fd); 943 return NULL; 944 } 945 946 /** loader_dri3_update_drawable 947 * 948 * Called the first time we use the drawable and then 949 * after we receive present configure notify events to 950 * track the geometry of the drawable 951 */ 952 static int 953 dri3_update_drawable(__DRIdrawable *driDrawable, 954 struct loader_dri3_drawable *draw) 955 { 956 if (draw->first_init) { 957 xcb_get_geometry_cookie_t geom_cookie; 958 xcb_get_geometry_reply_t *geom_reply; 959 xcb_void_cookie_t cookie; 960 xcb_generic_error_t *error; 961 xcb_present_query_capabilities_cookie_t present_capabilities_cookie; 962 xcb_present_query_capabilities_reply_t *present_capabilities_reply; 963 964 draw->first_init = false; 965 966 /* Try to select for input on the window. 967 * 968 * If the drawable is a window, this will get our events 969 * delivered. 970 * 971 * Otherwise, we'll get a BadWindow error back from this request which 972 * will let us know that the drawable is a pixmap instead. 973 */ 974 975 draw->eid = xcb_generate_id(draw->conn); 976 cookie = 977 xcb_present_select_input_checked(draw->conn, draw->eid, draw->drawable, 978 XCB_PRESENT_EVENT_MASK_CONFIGURE_NOTIFY | 979 XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY | 980 XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY); 981 982 present_capabilities_cookie = 983 xcb_present_query_capabilities(draw->conn, draw->drawable); 984 985 /* Create an XCB event queue to hold present events outside of the usual 986 * application event queue 987 */ 988 draw->special_event = xcb_register_for_special_xge(draw->conn, 989 &xcb_present_id, 990 draw->eid, 991 draw->stamp); 992 geom_cookie = xcb_get_geometry(draw->conn, draw->drawable); 993 994 geom_reply = xcb_get_geometry_reply(draw->conn, geom_cookie, NULL); 995 996 if (!geom_reply) 997 return false; 998 999 draw->width = geom_reply->width; 1000 draw->height = geom_reply->height; 1001 draw->depth = geom_reply->depth; 1002 draw->vtable->set_drawable_size(draw, draw->width, draw->height); 1003 1004 free(geom_reply); 1005 1006 draw->is_pixmap = false; 1007 1008 /* Check to see if our select input call failed. If it failed with a 1009 * BadWindow error, then assume the drawable is a pixmap. Destroy the 1010 * special event queue created above and mark the drawable as a pixmap 1011 */ 1012 1013 error = xcb_request_check(draw->conn, cookie); 1014 1015 present_capabilities_reply = 1016 xcb_present_query_capabilities_reply(draw->conn, 1017 present_capabilities_cookie, 1018 NULL); 1019 1020 if (present_capabilities_reply) { 1021 draw->present_capabilities = present_capabilities_reply->capabilities; 1022 free(present_capabilities_reply); 1023 } else 1024 draw->present_capabilities = 0; 1025 1026 if (error) { 1027 if (error->error_code != BadWindow) { 1028 free(error); 1029 return false; 1030 } 1031 draw->is_pixmap = true; 1032 xcb_unregister_for_special_event(draw->conn, draw->special_event); 1033 draw->special_event = NULL; 1034 } 1035 } 1036 dri3_flush_present_events(draw); 1037 return true; 1038 } 1039 1040 /* the DRIimage createImage function takes __DRI_IMAGE_FORMAT codes, while 1041 * the createImageFromFds call takes __DRI_IMAGE_FOURCC codes. To avoid 1042 * complete confusion, just deal in __DRI_IMAGE_FORMAT codes for now and 1043 * translate to __DRI_IMAGE_FOURCC codes in the call to createImageFromFds 1044 */ 1045 static int 1046 image_format_to_fourcc(int format) 1047 { 1048 1049 /* Convert from __DRI_IMAGE_FORMAT to __DRI_IMAGE_FOURCC (sigh) */ 1050 switch (format) { 1051 case __DRI_IMAGE_FORMAT_SARGB8: return __DRI_IMAGE_FOURCC_SARGB8888; 1052 case __DRI_IMAGE_FORMAT_RGB565: return __DRI_IMAGE_FOURCC_RGB565; 1053 case __DRI_IMAGE_FORMAT_XRGB8888: return __DRI_IMAGE_FOURCC_XRGB8888; 1054 case __DRI_IMAGE_FORMAT_ARGB8888: return __DRI_IMAGE_FOURCC_ARGB8888; 1055 case __DRI_IMAGE_FORMAT_ABGR8888: return __DRI_IMAGE_FOURCC_ABGR8888; 1056 case __DRI_IMAGE_FORMAT_XBGR8888: return __DRI_IMAGE_FOURCC_XBGR8888; 1057 } 1058 return 0; 1059 } 1060 1061 __DRIimage * 1062 loader_dri3_create_image(xcb_connection_t *c, 1063 xcb_dri3_buffer_from_pixmap_reply_t *bp_reply, 1064 unsigned int format, 1065 __DRIscreen *dri_screen, 1066 const __DRIimageExtension *image, 1067 void *loaderPrivate) 1068 { 1069 int *fds; 1070 __DRIimage *image_planar, *ret; 1071 int stride, offset; 1072 1073 /* Get an FD for the pixmap object 1074 */ 1075 fds = xcb_dri3_buffer_from_pixmap_reply_fds(c, bp_reply); 1076 1077 stride = bp_reply->stride; 1078 offset = 0; 1079 1080 /* createImageFromFds creates a wrapper __DRIimage structure which 1081 * can deal with multiple planes for things like Yuv images. So, once 1082 * we've gotten the planar wrapper, pull the single plane out of it and 1083 * discard the wrapper. 1084 */ 1085 image_planar = image->createImageFromFds(dri_screen, 1086 bp_reply->width, 1087 bp_reply->height, 1088 image_format_to_fourcc(format), 1089 fds, 1, 1090 &stride, &offset, loaderPrivate); 1091 close(fds[0]); 1092 if (!image_planar) 1093 return NULL; 1094 1095 ret = image->fromPlanar(image_planar, 0, loaderPrivate); 1096 1097 image->destroyImage(image_planar); 1098 1099 return ret; 1100 } 1101 1102 /** dri3_get_pixmap_buffer 1103 * 1104 * Get the DRM object for a pixmap from the X server and 1105 * wrap that with a __DRIimage structure using createImageFromFds 1106 */ 1107 static struct loader_dri3_buffer * 1108 dri3_get_pixmap_buffer(__DRIdrawable *driDrawable, unsigned int format, 1109 enum loader_dri3_buffer_type buffer_type, 1110 struct loader_dri3_drawable *draw) 1111 { 1112 int buf_id = loader_dri3_pixmap_buf_id(buffer_type); 1113 struct loader_dri3_buffer *buffer = draw->buffers[buf_id]; 1114 xcb_drawable_t pixmap; 1115 xcb_dri3_buffer_from_pixmap_cookie_t bp_cookie; 1116 xcb_dri3_buffer_from_pixmap_reply_t *bp_reply; 1117 xcb_sync_fence_t sync_fence; 1118 struct xshmfence *shm_fence; 1119 int fence_fd; 1120 __DRIscreen *cur_screen; 1121 1122 if (buffer) 1123 return buffer; 1124 1125 pixmap = draw->drawable; 1126 1127 buffer = calloc(1, sizeof *buffer); 1128 if (!buffer) 1129 goto no_buffer; 1130 1131 fence_fd = xshmfence_alloc_shm(); 1132 if (fence_fd < 0) 1133 goto no_fence; 1134 shm_fence = xshmfence_map_shm(fence_fd); 1135 if (shm_fence == NULL) { 1136 close (fence_fd); 1137 goto no_fence; 1138 } 1139 1140 xcb_dri3_fence_from_fd(draw->conn, 1141 pixmap, 1142 (sync_fence = xcb_generate_id(draw->conn)), 1143 false, 1144 fence_fd); 1145 1146 bp_cookie = xcb_dri3_buffer_from_pixmap(draw->conn, pixmap); 1147 bp_reply = xcb_dri3_buffer_from_pixmap_reply(draw->conn, bp_cookie, NULL); 1148 if (!bp_reply) 1149 goto no_image; 1150 1151 /* Get the currently-bound screen or revert to using the drawable's screen if 1152 * no contexts are currently bound. The latter case is at least necessary for 1153 * obs-studio, when using Window Capture (Xcomposite) as a Source. 1154 */ 1155 cur_screen = draw->vtable->get_dri_screen(draw); 1156 if (!cur_screen) { 1157 cur_screen = draw->dri_screen; 1158 } 1159 1160 buffer->image = loader_dri3_create_image(draw->conn, bp_reply, format, 1161 cur_screen, draw->ext->image, 1162 buffer); 1163 if (!buffer->image) 1164 goto no_image; 1165 1166 buffer->pixmap = pixmap; 1167 buffer->own_pixmap = false; 1168 buffer->width = bp_reply->width; 1169 buffer->height = bp_reply->height; 1170 buffer->buffer_type = buffer_type; 1171 buffer->shm_fence = shm_fence; 1172 buffer->sync_fence = sync_fence; 1173 1174 draw->buffers[buf_id] = buffer; 1175 1176 free(bp_reply); 1177 1178 return buffer; 1179 1180 no_image: 1181 free(bp_reply); 1182 xcb_sync_destroy_fence(draw->conn, sync_fence); 1183 xshmfence_unmap_shm(shm_fence); 1184 no_fence: 1185 free(buffer); 1186 no_buffer: 1187 return NULL; 1188 } 1189 1190 /** dri3_get_buffer 1191 * 1192 * Find a front or back buffer, allocating new ones as necessary 1193 */ 1194 static struct loader_dri3_buffer * 1195 dri3_get_buffer(__DRIdrawable *driDrawable, 1196 unsigned int format, 1197 enum loader_dri3_buffer_type buffer_type, 1198 struct loader_dri3_drawable *draw) 1199 { 1200 struct loader_dri3_buffer *buffer; 1201 int buf_id; 1202 __DRIcontext *dri_context; 1203 1204 dri_context = draw->vtable->get_dri_context(draw); 1205 1206 if (buffer_type == loader_dri3_buffer_back) { 1207 buf_id = dri3_find_back(draw); 1208 1209 if (buf_id < 0) 1210 return NULL; 1211 } else { 1212 buf_id = LOADER_DRI3_FRONT_ID; 1213 } 1214 1215 buffer = draw->buffers[buf_id]; 1216 1217 /* Allocate a new buffer if there isn't an old one, or if that 1218 * old one is the wrong size 1219 */ 1220 if (!buffer || buffer->width != draw->width || 1221 buffer->height != draw->height) { 1222 struct loader_dri3_buffer *new_buffer; 1223 1224 /* Allocate the new buffers 1225 */ 1226 new_buffer = dri3_alloc_render_buffer(draw, 1227 format, 1228 draw->width, 1229 draw->height, 1230 draw->depth); 1231 if (!new_buffer) 1232 return NULL; 1233 1234 /* When resizing, copy the contents of the old buffer, waiting for that 1235 * copy to complete using our fences before proceeding 1236 */ 1237 switch (buffer_type) { 1238 case loader_dri3_buffer_back: 1239 if (buffer) { 1240 if (!buffer->linear_buffer) { 1241 dri3_fence_reset(draw->conn, new_buffer); 1242 dri3_fence_await(draw->conn, buffer); 1243 dri3_copy_area(draw->conn, 1244 buffer->pixmap, 1245 new_buffer->pixmap, 1246 dri3_drawable_gc(draw), 1247 0, 0, 0, 0, 1248 draw->width, draw->height); 1249 dri3_fence_trigger(draw->conn, new_buffer); 1250 } else if (draw->vtable->in_current_context(draw)) { 1251 draw->ext->image->blitImage(dri_context, 1252 new_buffer->image, 1253 buffer->image, 1254 0, 0, draw->width, draw->height, 1255 0, 0, draw->width, draw->height, 0); 1256 } 1257 dri3_free_render_buffer(draw, buffer); 1258 } 1259 break; 1260 case loader_dri3_buffer_front: 1261 dri3_fence_reset(draw->conn, new_buffer); 1262 dri3_copy_area(draw->conn, 1263 draw->drawable, 1264 new_buffer->pixmap, 1265 dri3_drawable_gc(draw), 1266 0, 0, 0, 0, 1267 draw->width, draw->height); 1268 dri3_fence_trigger(draw->conn, new_buffer); 1269 1270 if (new_buffer->linear_buffer && 1271 draw->vtable->in_current_context(draw)) { 1272 dri3_fence_await(draw->conn, new_buffer); 1273 draw->ext->image->blitImage(dri_context, 1274 new_buffer->image, 1275 new_buffer->linear_buffer, 1276 0, 0, draw->width, draw->height, 1277 0, 0, draw->width, draw->height, 0); 1278 } 1279 break; 1280 } 1281 buffer = new_buffer; 1282 buffer->buffer_type = buffer_type; 1283 draw->buffers[buf_id] = buffer; 1284 } 1285 dri3_fence_await(draw->conn, buffer); 1286 1287 /* Return the requested buffer */ 1288 return buffer; 1289 } 1290 1291 /** dri3_free_buffers 1292 * 1293 * Free the front bufffer or all of the back buffers. Used 1294 * when the application changes which buffers it needs 1295 */ 1296 static void 1297 dri3_free_buffers(__DRIdrawable *driDrawable, 1298 enum loader_dri3_buffer_type buffer_type, 1299 struct loader_dri3_drawable *draw) 1300 { 1301 struct loader_dri3_buffer *buffer; 1302 int first_id; 1303 int n_id; 1304 int buf_id; 1305 1306 switch (buffer_type) { 1307 case loader_dri3_buffer_back: 1308 first_id = LOADER_DRI3_BACK_ID(0); 1309 n_id = LOADER_DRI3_MAX_BACK; 1310 break; 1311 case loader_dri3_buffer_front: 1312 first_id = LOADER_DRI3_FRONT_ID; 1313 n_id = 1; 1314 } 1315 1316 for (buf_id = first_id; buf_id < first_id + n_id; buf_id++) { 1317 buffer = draw->buffers[buf_id]; 1318 if (buffer) { 1319 dri3_free_render_buffer(draw, buffer); 1320 draw->buffers[buf_id] = NULL; 1321 } 1322 } 1323 } 1324 1325 /** loader_dri3_get_buffers 1326 * 1327 * The published buffer allocation API. 1328 * Returns all of the necessary buffers, allocating 1329 * as needed. 1330 */ 1331 int 1332 loader_dri3_get_buffers(__DRIdrawable *driDrawable, 1333 unsigned int format, 1334 uint32_t *stamp, 1335 void *loaderPrivate, 1336 uint32_t buffer_mask, 1337 struct __DRIimageList *buffers) 1338 { 1339 struct loader_dri3_drawable *draw = loaderPrivate; 1340 struct loader_dri3_buffer *front, *back; 1341 1342 buffers->image_mask = 0; 1343 buffers->front = NULL; 1344 buffers->back = NULL; 1345 1346 front = NULL; 1347 back = NULL; 1348 1349 if (!dri3_update_drawable(driDrawable, draw)) 1350 return false; 1351 1352 /* pixmaps always have front buffers */ 1353 if (draw->is_pixmap) 1354 buffer_mask |= __DRI_IMAGE_BUFFER_FRONT; 1355 1356 if (buffer_mask & __DRI_IMAGE_BUFFER_FRONT) { 1357 /* All pixmaps are owned by the server gpu. 1358 * When we use a different gpu, we can't use the pixmap 1359 * as buffer since it is potentially tiled a way 1360 * our device can't understand. In this case, use 1361 * a fake front buffer. Hopefully the pixmap 1362 * content will get synced with the fake front 1363 * buffer. 1364 */ 1365 if (draw->is_pixmap && !draw->is_different_gpu) 1366 front = dri3_get_pixmap_buffer(driDrawable, 1367 format, 1368 loader_dri3_buffer_front, 1369 draw); 1370 else 1371 front = dri3_get_buffer(driDrawable, 1372 format, 1373 loader_dri3_buffer_front, 1374 draw); 1375 1376 if (!front) 1377 return false; 1378 } else { 1379 dri3_free_buffers(driDrawable, loader_dri3_buffer_front, draw); 1380 draw->have_fake_front = 0; 1381 } 1382 1383 if (buffer_mask & __DRI_IMAGE_BUFFER_BACK) { 1384 back = dri3_get_buffer(driDrawable, 1385 format, 1386 loader_dri3_buffer_back, 1387 draw); 1388 if (!back) 1389 return false; 1390 draw->have_back = 1; 1391 } else { 1392 dri3_free_buffers(driDrawable, loader_dri3_buffer_back, draw); 1393 draw->have_back = 0; 1394 } 1395 1396 if (front) { 1397 buffers->image_mask |= __DRI_IMAGE_BUFFER_FRONT; 1398 buffers->front = front->image; 1399 draw->have_fake_front = draw->is_different_gpu || !draw->is_pixmap; 1400 } 1401 1402 if (back) { 1403 buffers->image_mask |= __DRI_IMAGE_BUFFER_BACK; 1404 buffers->back = back->image; 1405 } 1406 1407 draw->stamp = stamp; 1408 1409 return true; 1410 } 1411 1412 /** loader_dri3_update_drawable_geometry 1413 * 1414 * Get the current drawable geometry. 1415 */ 1416 void 1417 loader_dri3_update_drawable_geometry(struct loader_dri3_drawable *draw) 1418 { 1419 xcb_get_geometry_cookie_t geom_cookie; 1420 xcb_get_geometry_reply_t *geom_reply; 1421 1422 geom_cookie = xcb_get_geometry(draw->conn, draw->drawable); 1423 1424 geom_reply = xcb_get_geometry_reply(draw->conn, geom_cookie, NULL); 1425 1426 if (geom_reply) { 1427 draw->width = geom_reply->width; 1428 draw->height = geom_reply->height; 1429 draw->vtable->set_drawable_size(draw, draw->width, draw->height); 1430 1431 free(geom_reply); 1432 } 1433 } 1434