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 /** 44 * A cached blit context. 45 */ 46 struct loader_dri3_blit_context { 47 mtx_t mtx; 48 __DRIcontext *ctx; 49 __DRIscreen *cur_screen; 50 const __DRIcoreExtension *core; 51 }; 52 53 /* For simplicity we maintain the cache only for a single screen at a time */ 54 static struct loader_dri3_blit_context blit_context = { 55 _MTX_INITIALIZER_NP, NULL 56 }; 57 58 static void 59 dri3_flush_present_events(struct loader_dri3_drawable *draw); 60 61 static struct loader_dri3_buffer * 62 dri3_find_back_alloc(struct loader_dri3_drawable *draw); 63 64 /** 65 * Do we have blit functionality in the image blit extension? 66 * 67 * \param draw[in] The drawable intended to blit from / to. 68 * \return true if we have blit functionality. false otherwise. 69 */ 70 static bool loader_dri3_have_image_blit(const struct loader_dri3_drawable *draw) 71 { 72 return draw->ext->image->base.version >= 9 && 73 draw->ext->image->blitImage != NULL; 74 } 75 76 /** 77 * Get and lock (for use with the current thread) a dri context associated 78 * with the drawable's dri screen. The context is intended to be used with 79 * the dri image extension's blitImage method. 80 * 81 * \param draw[in] Pointer to the drawable whose dri screen we want a 82 * dri context for. 83 * \return A dri context or NULL if context creation failed. 84 * 85 * When the caller is done with the context (even if the context returned was 86 * NULL), the caller must call loader_dri3_blit_context_put. 87 */ 88 static __DRIcontext * 89 loader_dri3_blit_context_get(struct loader_dri3_drawable *draw) 90 { 91 mtx_lock(&blit_context.mtx); 92 93 if (blit_context.ctx && blit_context.cur_screen != draw->dri_screen) { 94 blit_context.core->destroyContext(blit_context.ctx); 95 blit_context.ctx = NULL; 96 } 97 98 if (!blit_context.ctx) { 99 blit_context.ctx = draw->ext->core->createNewContext(draw->dri_screen, 100 NULL, NULL, NULL); 101 blit_context.cur_screen = draw->dri_screen; 102 blit_context.core = draw->ext->core; 103 } 104 105 return blit_context.ctx; 106 } 107 108 /** 109 * Release (for use with other threads) a dri context previously obtained using 110 * loader_dri3_blit_context_get. 111 */ 112 static void 113 loader_dri3_blit_context_put(void) 114 { 115 mtx_unlock(&blit_context.mtx); 116 } 117 118 /** 119 * Blit (parts of) the contents of a DRI image to another dri image 120 * 121 * \param draw[in] The drawable which owns the images. 122 * \param dst[in] The destination image. 123 * \param src[in] The source image. 124 * \param dstx0[in] Start destination coordinate. 125 * \param dsty0[in] Start destination coordinate. 126 * \param width[in] Blit width. 127 * \param height[in] Blit height. 128 * \param srcx0[in] Start source coordinate. 129 * \param srcy0[in] Start source coordinate. 130 * \param flush_flag[in] Image blit flush flag. 131 * \return true iff successful. 132 */ 133 static bool 134 loader_dri3_blit_image(struct loader_dri3_drawable *draw, 135 __DRIimage *dst, __DRIimage *src, 136 int dstx0, int dsty0, int width, int height, 137 int srcx0, int srcy0, int flush_flag) 138 { 139 __DRIcontext *dri_context; 140 bool use_blit_context = false; 141 142 if (!loader_dri3_have_image_blit(draw)) 143 return false; 144 145 dri_context = draw->vtable->get_dri_context(draw); 146 147 if (!dri_context || !draw->vtable->in_current_context(draw)) { 148 dri_context = loader_dri3_blit_context_get(draw); 149 use_blit_context = true; 150 flush_flag |= __BLIT_FLAG_FLUSH; 151 } 152 153 if (dri_context) 154 draw->ext->image->blitImage(dri_context, dst, src, dstx0, dsty0, 155 width, height, srcx0, srcy0, 156 width, height, flush_flag); 157 158 if (use_blit_context) 159 loader_dri3_blit_context_put(); 160 161 return dri_context != NULL; 162 } 163 164 static inline void 165 dri3_fence_reset(xcb_connection_t *c, struct loader_dri3_buffer *buffer) 166 { 167 xshmfence_reset(buffer->shm_fence); 168 } 169 170 static inline void 171 dri3_fence_set(struct loader_dri3_buffer *buffer) 172 { 173 xshmfence_trigger(buffer->shm_fence); 174 } 175 176 static inline void 177 dri3_fence_trigger(xcb_connection_t *c, struct loader_dri3_buffer *buffer) 178 { 179 xcb_sync_trigger_fence(c, buffer->sync_fence); 180 } 181 182 static inline void 183 dri3_fence_await(xcb_connection_t *c, struct loader_dri3_drawable *draw, 184 struct loader_dri3_buffer *buffer) 185 { 186 xcb_flush(c); 187 xshmfence_await(buffer->shm_fence); 188 if (draw) { 189 mtx_lock(&draw->mtx); 190 dri3_flush_present_events(draw); 191 mtx_unlock(&draw->mtx); 192 } 193 } 194 195 static void 196 dri3_update_num_back(struct loader_dri3_drawable *draw) 197 { 198 if (draw->flipping) 199 draw->num_back = 3; 200 else 201 draw->num_back = 2; 202 } 203 204 void 205 loader_dri3_set_swap_interval(struct loader_dri3_drawable *draw, int interval) 206 { 207 draw->swap_interval = interval; 208 } 209 210 /** dri3_free_render_buffer 211 * 212 * Free everything associated with one render buffer including pixmap, fence 213 * stuff and the driver image 214 */ 215 static void 216 dri3_free_render_buffer(struct loader_dri3_drawable *draw, 217 struct loader_dri3_buffer *buffer) 218 { 219 if (buffer->own_pixmap) 220 xcb_free_pixmap(draw->conn, buffer->pixmap); 221 xcb_sync_destroy_fence(draw->conn, buffer->sync_fence); 222 xshmfence_unmap_shm(buffer->shm_fence); 223 draw->ext->image->destroyImage(buffer->image); 224 if (buffer->linear_buffer) 225 draw->ext->image->destroyImage(buffer->linear_buffer); 226 free(buffer); 227 } 228 229 void 230 loader_dri3_drawable_fini(struct loader_dri3_drawable *draw) 231 { 232 int i; 233 234 draw->ext->core->destroyDrawable(draw->dri_drawable); 235 236 for (i = 0; i < LOADER_DRI3_NUM_BUFFERS; i++) { 237 if (draw->buffers[i]) 238 dri3_free_render_buffer(draw, draw->buffers[i]); 239 } 240 241 if (draw->special_event) { 242 xcb_void_cookie_t cookie = 243 xcb_present_select_input_checked(draw->conn, draw->eid, draw->drawable, 244 XCB_PRESENT_EVENT_MASK_NO_EVENT); 245 246 xcb_discard_reply(draw->conn, cookie.sequence); 247 xcb_unregister_for_special_event(draw->conn, draw->special_event); 248 } 249 250 cnd_destroy(&draw->event_cnd); 251 mtx_destroy(&draw->mtx); 252 } 253 254 int 255 loader_dri3_drawable_init(xcb_connection_t *conn, 256 xcb_drawable_t drawable, 257 __DRIscreen *dri_screen, 258 bool is_different_gpu, 259 const __DRIconfig *dri_config, 260 struct loader_dri3_extensions *ext, 261 const struct loader_dri3_vtable *vtable, 262 struct loader_dri3_drawable *draw) 263 { 264 xcb_get_geometry_cookie_t cookie; 265 xcb_get_geometry_reply_t *reply; 266 xcb_generic_error_t *error; 267 GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1; 268 int swap_interval; 269 270 draw->conn = conn; 271 draw->ext = ext; 272 draw->vtable = vtable; 273 draw->drawable = drawable; 274 draw->dri_screen = dri_screen; 275 draw->is_different_gpu = is_different_gpu; 276 277 draw->have_back = 0; 278 draw->have_fake_front = 0; 279 draw->first_init = true; 280 281 draw->cur_blit_source = -1; 282 draw->back_format = __DRI_IMAGE_FORMAT_NONE; 283 mtx_init(&draw->mtx, mtx_plain); 284 cnd_init(&draw->event_cnd); 285 286 if (draw->ext->config) 287 draw->ext->config->configQueryi(draw->dri_screen, 288 "vblank_mode", &vblank_mode); 289 290 switch (vblank_mode) { 291 case DRI_CONF_VBLANK_NEVER: 292 case DRI_CONF_VBLANK_DEF_INTERVAL_0: 293 swap_interval = 0; 294 break; 295 case DRI_CONF_VBLANK_DEF_INTERVAL_1: 296 case DRI_CONF_VBLANK_ALWAYS_SYNC: 297 default: 298 swap_interval = 1; 299 break; 300 } 301 draw->swap_interval = swap_interval; 302 303 dri3_update_num_back(draw); 304 305 /* Create a new drawable */ 306 draw->dri_drawable = 307 draw->ext->image_driver->createNewDrawable(dri_screen, 308 dri_config, 309 draw); 310 311 if (!draw->dri_drawable) 312 return 1; 313 314 cookie = xcb_get_geometry(draw->conn, draw->drawable); 315 reply = xcb_get_geometry_reply(draw->conn, cookie, &error); 316 if (reply == NULL || error != NULL) { 317 draw->ext->core->destroyDrawable(draw->dri_drawable); 318 return 1; 319 } 320 321 draw->width = reply->width; 322 draw->height = reply->height; 323 draw->depth = reply->depth; 324 draw->vtable->set_drawable_size(draw, draw->width, draw->height); 325 free(reply); 326 327 draw->swap_method = __DRI_ATTRIB_SWAP_UNDEFINED; 328 if (draw->ext->core->base.version >= 2) { 329 (void )draw->ext->core->getConfigAttrib(dri_config, 330 __DRI_ATTRIB_SWAP_METHOD, 331 &draw->swap_method); 332 } 333 334 /* 335 * Make sure server has the same swap interval we do for the new 336 * drawable. 337 */ 338 loader_dri3_set_swap_interval(draw, swap_interval); 339 340 return 0; 341 } 342 343 /* 344 * Process one Present event 345 */ 346 static void 347 dri3_handle_present_event(struct loader_dri3_drawable *draw, 348 xcb_present_generic_event_t *ge) 349 { 350 switch (ge->evtype) { 351 case XCB_PRESENT_CONFIGURE_NOTIFY: { 352 xcb_present_configure_notify_event_t *ce = (void *) ge; 353 354 draw->width = ce->width; 355 draw->height = ce->height; 356 draw->vtable->set_drawable_size(draw, draw->width, draw->height); 357 draw->ext->flush->invalidate(draw->dri_drawable); 358 break; 359 } 360 case XCB_PRESENT_COMPLETE_NOTIFY: { 361 xcb_present_complete_notify_event_t *ce = (void *) ge; 362 363 /* Compute the processed SBC number from the received 32-bit serial number 364 * merged with the upper 32-bits of the sent 64-bit serial number while 365 * checking for wrap. 366 */ 367 if (ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP) { 368 draw->recv_sbc = (draw->send_sbc & 0xffffffff00000000LL) | ce->serial; 369 if (draw->recv_sbc > draw->send_sbc) 370 draw->recv_sbc -= 0x100000000; 371 switch (ce->mode) { 372 case XCB_PRESENT_COMPLETE_MODE_FLIP: 373 draw->flipping = true; 374 break; 375 case XCB_PRESENT_COMPLETE_MODE_COPY: 376 draw->flipping = false; 377 break; 378 } 379 380 if (draw->vtable->show_fps) 381 draw->vtable->show_fps(draw, ce->ust); 382 383 draw->ust = ce->ust; 384 draw->msc = ce->msc; 385 } else if (ce->serial == draw->eid) { 386 draw->notify_ust = ce->ust; 387 draw->notify_msc = ce->msc; 388 } 389 break; 390 } 391 case XCB_PRESENT_EVENT_IDLE_NOTIFY: { 392 xcb_present_idle_notify_event_t *ie = (void *) ge; 393 int b; 394 395 for (b = 0; b < sizeof(draw->buffers) / sizeof(draw->buffers[0]); b++) { 396 struct loader_dri3_buffer *buf = draw->buffers[b]; 397 398 if (buf && buf->pixmap == ie->pixmap) 399 buf->busy = 0; 400 401 if (buf && draw->num_back <= b && b < LOADER_DRI3_MAX_BACK && 402 draw->cur_blit_source != b && 403 !buf->busy) { 404 dri3_free_render_buffer(draw, buf); 405 draw->buffers[b] = NULL; 406 } 407 } 408 break; 409 } 410 } 411 free(ge); 412 } 413 414 static bool 415 dri3_wait_for_event_locked(struct loader_dri3_drawable *draw) 416 { 417 xcb_generic_event_t *ev; 418 xcb_present_generic_event_t *ge; 419 420 xcb_flush(draw->conn); 421 422 /* Only have one thread waiting for events at a time */ 423 if (draw->has_event_waiter) { 424 cnd_wait(&draw->event_cnd, &draw->mtx); 425 /* Another thread has updated the protected info, so retest. */ 426 return true; 427 } else { 428 draw->has_event_waiter = true; 429 /* Allow other threads access to the drawable while we're waiting. */ 430 mtx_unlock(&draw->mtx); 431 ev = xcb_wait_for_special_event(draw->conn, draw->special_event); 432 mtx_lock(&draw->mtx); 433 draw->has_event_waiter = false; 434 cnd_broadcast(&draw->event_cnd); 435 } 436 if (!ev) 437 return false; 438 ge = (void *) ev; 439 dri3_handle_present_event(draw, ge); 440 return true; 441 } 442 443 /** loader_dri3_wait_for_msc 444 * 445 * Get the X server to send an event when the target msc/divisor/remainder is 446 * reached. 447 */ 448 bool 449 loader_dri3_wait_for_msc(struct loader_dri3_drawable *draw, 450 int64_t target_msc, 451 int64_t divisor, int64_t remainder, 452 int64_t *ust, int64_t *msc, int64_t *sbc) 453 { 454 xcb_void_cookie_t cookie = xcb_present_notify_msc(draw->conn, 455 draw->drawable, 456 draw->eid, 457 target_msc, 458 divisor, 459 remainder); 460 xcb_generic_event_t *ev; 461 unsigned full_sequence; 462 463 mtx_lock(&draw->mtx); 464 xcb_flush(draw->conn); 465 466 /* Wait for the event */ 467 do { 468 ev = xcb_wait_for_special_event(draw->conn, draw->special_event); 469 if (!ev) { 470 mtx_unlock(&draw->mtx); 471 return false; 472 } 473 474 full_sequence = ev->full_sequence; 475 dri3_handle_present_event(draw, (void *) ev); 476 } while (full_sequence != cookie.sequence || draw->notify_msc < target_msc); 477 478 *ust = draw->notify_ust; 479 *msc = draw->notify_msc; 480 *sbc = draw->recv_sbc; 481 mtx_unlock(&draw->mtx); 482 483 return true; 484 } 485 486 /** loader_dri3_wait_for_sbc 487 * 488 * Wait for the completed swap buffer count to reach the specified 489 * target. Presumably the application knows that this will be reached with 490 * outstanding complete events, or we're going to be here awhile. 491 */ 492 int 493 loader_dri3_wait_for_sbc(struct loader_dri3_drawable *draw, 494 int64_t target_sbc, int64_t *ust, 495 int64_t *msc, int64_t *sbc) 496 { 497 /* From the GLX_OML_sync_control spec: 498 * 499 * "If <target_sbc> = 0, the function will block until all previous 500 * swaps requested with glXSwapBuffersMscOML for that window have 501 * completed." 502 */ 503 mtx_lock(&draw->mtx); 504 if (!target_sbc) 505 target_sbc = draw->send_sbc; 506 507 while (draw->recv_sbc < target_sbc) { 508 if (!dri3_wait_for_event_locked(draw)) { 509 mtx_unlock(&draw->mtx); 510 return 0; 511 } 512 } 513 514 *ust = draw->ust; 515 *msc = draw->msc; 516 *sbc = draw->recv_sbc; 517 mtx_unlock(&draw->mtx); 518 return 1; 519 } 520 521 /** loader_dri3_find_back 522 * 523 * Find an idle back buffer. If there isn't one, then 524 * wait for a present idle notify event from the X server 525 */ 526 static int 527 dri3_find_back(struct loader_dri3_drawable *draw) 528 { 529 int b; 530 int num_to_consider; 531 532 mtx_lock(&draw->mtx); 533 /* Increase the likelyhood of reusing current buffer */ 534 dri3_flush_present_events(draw); 535 536 /* Check whether we need to reuse the current back buffer as new back. 537 * In that case, wait until it's not busy anymore. 538 */ 539 dri3_update_num_back(draw); 540 num_to_consider = draw->num_back; 541 if (!loader_dri3_have_image_blit(draw) && draw->cur_blit_source != -1) { 542 num_to_consider = 1; 543 draw->cur_blit_source = -1; 544 } 545 546 for (;;) { 547 for (b = 0; b < num_to_consider; b++) { 548 int id = LOADER_DRI3_BACK_ID((b + draw->cur_back) % draw->num_back); 549 struct loader_dri3_buffer *buffer = draw->buffers[id]; 550 551 if (!buffer || !buffer->busy) { 552 draw->cur_back = id; 553 mtx_unlock(&draw->mtx); 554 return id; 555 } 556 } 557 if (!dri3_wait_for_event_locked(draw)) { 558 mtx_unlock(&draw->mtx); 559 return -1; 560 } 561 } 562 } 563 564 static xcb_gcontext_t 565 dri3_drawable_gc(struct loader_dri3_drawable *draw) 566 { 567 if (!draw->gc) { 568 uint32_t v = 0; 569 xcb_create_gc(draw->conn, 570 (draw->gc = xcb_generate_id(draw->conn)), 571 draw->drawable, 572 XCB_GC_GRAPHICS_EXPOSURES, 573 &v); 574 } 575 return draw->gc; 576 } 577 578 579 static struct loader_dri3_buffer * 580 dri3_back_buffer(struct loader_dri3_drawable *draw) 581 { 582 return draw->buffers[LOADER_DRI3_BACK_ID(draw->cur_back)]; 583 } 584 585 static struct loader_dri3_buffer * 586 dri3_fake_front_buffer(struct loader_dri3_drawable *draw) 587 { 588 return draw->buffers[LOADER_DRI3_FRONT_ID]; 589 } 590 591 static void 592 dri3_copy_area(xcb_connection_t *c, 593 xcb_drawable_t src_drawable, 594 xcb_drawable_t dst_drawable, 595 xcb_gcontext_t gc, 596 int16_t src_x, 597 int16_t src_y, 598 int16_t dst_x, 599 int16_t dst_y, 600 uint16_t width, 601 uint16_t height) 602 { 603 xcb_void_cookie_t cookie; 604 605 cookie = xcb_copy_area_checked(c, 606 src_drawable, 607 dst_drawable, 608 gc, 609 src_x, 610 src_y, 611 dst_x, 612 dst_y, 613 width, 614 height); 615 xcb_discard_reply(c, cookie.sequence); 616 } 617 618 /** 619 * Asks the driver to flush any queued work necessary for serializing with the 620 * X command stream, and optionally the slightly more strict requirement of 621 * glFlush() equivalence (which would require flushing even if nothing had 622 * been drawn to a window system framebuffer, for example). 623 */ 624 void 625 loader_dri3_flush(struct loader_dri3_drawable *draw, 626 unsigned flags, 627 enum __DRI2throttleReason throttle_reason) 628 { 629 /* NEED TO CHECK WHETHER CONTEXT IS NULL */ 630 __DRIcontext *dri_context = draw->vtable->get_dri_context(draw); 631 632 if (dri_context) { 633 draw->ext->flush->flush_with_flags(dri_context, draw->dri_drawable, 634 flags, throttle_reason); 635 } 636 } 637 638 void 639 loader_dri3_copy_sub_buffer(struct loader_dri3_drawable *draw, 640 int x, int y, 641 int width, int height, 642 bool flush) 643 { 644 struct loader_dri3_buffer *back; 645 unsigned flags = __DRI2_FLUSH_DRAWABLE; 646 647 /* Check we have the right attachments */ 648 if (!draw->have_back || draw->is_pixmap) 649 return; 650 651 if (flush) 652 flags |= __DRI2_FLUSH_CONTEXT; 653 loader_dri3_flush(draw, flags, __DRI2_THROTTLE_SWAPBUFFER); 654 655 back = dri3_find_back_alloc(draw); 656 if (!back) 657 return; 658 659 y = draw->height - y - height; 660 661 if (draw->is_different_gpu) { 662 /* Update the linear buffer part of the back buffer 663 * for the dri3_copy_area operation 664 */ 665 (void) loader_dri3_blit_image(draw, 666 back->linear_buffer, 667 back->image, 668 0, 0, back->width, back->height, 669 0, 0, __BLIT_FLAG_FLUSH); 670 } 671 672 loader_dri3_swapbuffer_barrier(draw); 673 dri3_fence_reset(draw->conn, back); 674 dri3_copy_area(draw->conn, 675 back->pixmap, 676 draw->drawable, 677 dri3_drawable_gc(draw), 678 x, y, x, y, width, height); 679 dri3_fence_trigger(draw->conn, back); 680 /* Refresh the fake front (if present) after we just damaged the real 681 * front. 682 */ 683 if (draw->have_fake_front && 684 !loader_dri3_blit_image(draw, 685 dri3_fake_front_buffer(draw)->image, 686 back->image, 687 x, y, width, height, 688 x, y, __BLIT_FLAG_FLUSH) && 689 !draw->is_different_gpu) { 690 dri3_fence_reset(draw->conn, dri3_fake_front_buffer(draw)); 691 dri3_copy_area(draw->conn, 692 back->pixmap, 693 dri3_fake_front_buffer(draw)->pixmap, 694 dri3_drawable_gc(draw), 695 x, y, x, y, width, height); 696 dri3_fence_trigger(draw->conn, dri3_fake_front_buffer(draw)); 697 dri3_fence_await(draw->conn, NULL, dri3_fake_front_buffer(draw)); 698 } 699 dri3_fence_await(draw->conn, draw, back); 700 } 701 702 void 703 loader_dri3_copy_drawable(struct loader_dri3_drawable *draw, 704 xcb_drawable_t dest, 705 xcb_drawable_t src) 706 { 707 loader_dri3_flush(draw, __DRI2_FLUSH_DRAWABLE, 0); 708 709 dri3_fence_reset(draw->conn, dri3_fake_front_buffer(draw)); 710 dri3_copy_area(draw->conn, 711 src, dest, 712 dri3_drawable_gc(draw), 713 0, 0, 0, 0, draw->width, draw->height); 714 dri3_fence_trigger(draw->conn, dri3_fake_front_buffer(draw)); 715 dri3_fence_await(draw->conn, draw, dri3_fake_front_buffer(draw)); 716 } 717 718 void 719 loader_dri3_wait_x(struct loader_dri3_drawable *draw) 720 { 721 struct loader_dri3_buffer *front; 722 723 if (draw == NULL || !draw->have_fake_front) 724 return; 725 726 front = dri3_fake_front_buffer(draw); 727 728 loader_dri3_copy_drawable(draw, front->pixmap, draw->drawable); 729 730 /* In the psc->is_different_gpu case, the linear buffer has been updated, 731 * but not yet the tiled buffer. 732 * Copy back to the tiled buffer we use for rendering. 733 * Note that we don't need flushing. 734 */ 735 if (draw->is_different_gpu) 736 (void) loader_dri3_blit_image(draw, 737 front->image, 738 front->linear_buffer, 739 0, 0, front->width, front->height, 740 0, 0, 0); 741 } 742 743 void 744 loader_dri3_wait_gl(struct loader_dri3_drawable *draw) 745 { 746 struct loader_dri3_buffer *front; 747 748 if (draw == NULL || !draw->have_fake_front) 749 return; 750 751 front = dri3_fake_front_buffer(draw); 752 753 /* In the psc->is_different_gpu case, we update the linear_buffer 754 * before updating the real front. 755 */ 756 if (draw->is_different_gpu) 757 (void) loader_dri3_blit_image(draw, 758 front->linear_buffer, 759 front->image, 760 0, 0, front->width, front->height, 761 0, 0, __BLIT_FLAG_FLUSH); 762 loader_dri3_swapbuffer_barrier(draw); 763 loader_dri3_copy_drawable(draw, draw->drawable, front->pixmap); 764 } 765 766 /** dri3_flush_present_events 767 * 768 * Process any present events that have been received from the X server 769 */ 770 static void 771 dri3_flush_present_events(struct loader_dri3_drawable *draw) 772 { 773 /* Check to see if any configuration changes have occurred 774 * since we were last invoked 775 */ 776 if (draw->has_event_waiter) 777 return; 778 779 if (draw->special_event) { 780 xcb_generic_event_t *ev; 781 782 while ((ev = xcb_poll_for_special_event(draw->conn, 783 draw->special_event)) != NULL) { 784 xcb_present_generic_event_t *ge = (void *) ev; 785 dri3_handle_present_event(draw, ge); 786 } 787 } 788 } 789 790 /** loader_dri3_swap_buffers_msc 791 * 792 * Make the current back buffer visible using the present extension 793 */ 794 int64_t 795 loader_dri3_swap_buffers_msc(struct loader_dri3_drawable *draw, 796 int64_t target_msc, int64_t divisor, 797 int64_t remainder, unsigned flush_flags, 798 bool force_copy) 799 { 800 struct loader_dri3_buffer *back; 801 int64_t ret = 0; 802 uint32_t options = XCB_PRESENT_OPTION_NONE; 803 804 draw->vtable->flush_drawable(draw, flush_flags); 805 806 back = dri3_find_back_alloc(draw); 807 808 mtx_lock(&draw->mtx); 809 if (draw->is_different_gpu && back) { 810 /* Update the linear buffer before presenting the pixmap */ 811 (void) loader_dri3_blit_image(draw, 812 back->linear_buffer, 813 back->image, 814 0, 0, back->width, back->height, 815 0, 0, __BLIT_FLAG_FLUSH); 816 } 817 818 /* If we need to preload the new back buffer, remember the source. 819 * The force_copy parameter is used by EGL to attempt to preserve 820 * the back buffer across a call to this function. 821 */ 822 if (draw->swap_method != __DRI_ATTRIB_SWAP_UNDEFINED || force_copy) 823 draw->cur_blit_source = LOADER_DRI3_BACK_ID(draw->cur_back); 824 825 /* Exchange the back and fake front. Even though the server knows about these 826 * buffers, it has no notion of back and fake front. 827 */ 828 if (back && draw->have_fake_front) { 829 struct loader_dri3_buffer *tmp; 830 831 tmp = dri3_fake_front_buffer(draw); 832 draw->buffers[LOADER_DRI3_FRONT_ID] = back; 833 draw->buffers[LOADER_DRI3_BACK_ID(draw->cur_back)] = tmp; 834 835 if (draw->swap_method == __DRI_ATTRIB_SWAP_COPY || force_copy) 836 draw->cur_blit_source = LOADER_DRI3_FRONT_ID; 837 } 838 839 dri3_flush_present_events(draw); 840 841 if (back && !draw->is_pixmap) { 842 dri3_fence_reset(draw->conn, back); 843 844 /* Compute when we want the frame shown by taking the last known 845 * successful MSC and adding in a swap interval for each outstanding swap 846 * request. target_msc=divisor=remainder=0 means "Use glXSwapBuffers() 847 * semantic" 848 */ 849 ++draw->send_sbc; 850 if (target_msc == 0 && divisor == 0 && remainder == 0) 851 target_msc = draw->msc + draw->swap_interval * 852 (draw->send_sbc - draw->recv_sbc); 853 else if (divisor == 0 && remainder > 0) { 854 /* From the GLX_OML_sync_control spec: 855 * "If <divisor> = 0, the swap will occur when MSC becomes 856 * greater than or equal to <target_msc>." 857 * 858 * Note that there's no mention of the remainder. The Present 859 * extension throws BadValue for remainder != 0 with divisor == 0, so 860 * just drop the passed in value. 861 */ 862 remainder = 0; 863 } 864 865 /* From the GLX_EXT_swap_control spec 866 * and the EGL 1.4 spec (page 53): 867 * 868 * "If <interval> is set to a value of 0, buffer swaps are not 869 * synchronized to a video frame." 870 * 871 * Implementation note: It is possible to enable triple buffering 872 * behaviour by not using XCB_PRESENT_OPTION_ASYNC, but this should not be 873 * the default. 874 */ 875 if (draw->swap_interval == 0) 876 options |= XCB_PRESENT_OPTION_ASYNC; 877 878 /* If we need to populate the new back, but need to reuse the back 879 * buffer slot due to lack of local blit capabilities, make sure 880 * the server doesn't flip and we deadlock. 881 */ 882 if (!loader_dri3_have_image_blit(draw) && draw->cur_blit_source != -1) 883 options |= XCB_PRESENT_OPTION_COPY; 884 885 back->busy = 1; 886 back->last_swap = draw->send_sbc; 887 xcb_present_pixmap(draw->conn, 888 draw->drawable, 889 back->pixmap, 890 (uint32_t) draw->send_sbc, 891 0, /* valid */ 892 0, /* update */ 893 0, /* x_off */ 894 0, /* y_off */ 895 None, /* target_crtc */ 896 None, 897 back->sync_fence, 898 options, 899 target_msc, 900 divisor, 901 remainder, 0, NULL); 902 ret = (int64_t) draw->send_sbc; 903 904 /* Schedule a server-side back-preserving blit if necessary. 905 * This happens iff all conditions below are satisfied: 906 * a) We have a fake front, 907 * b) We need to preserve the back buffer, 908 * c) We don't have local blit capabilities. 909 */ 910 if (!loader_dri3_have_image_blit(draw) && draw->cur_blit_source != -1 && 911 draw->cur_blit_source != LOADER_DRI3_BACK_ID(draw->cur_back)) { 912 struct loader_dri3_buffer *new_back = dri3_back_buffer(draw); 913 struct loader_dri3_buffer *src = draw->buffers[draw->cur_blit_source]; 914 915 dri3_fence_reset(draw->conn, new_back); 916 dri3_copy_area(draw->conn, src->pixmap, 917 new_back->pixmap, 918 dri3_drawable_gc(draw), 919 0, 0, 0, 0, draw->width, draw->height); 920 dri3_fence_trigger(draw->conn, new_back); 921 new_back->last_swap = src->last_swap; 922 } 923 924 xcb_flush(draw->conn); 925 if (draw->stamp) 926 ++(*draw->stamp); 927 } 928 mtx_unlock(&draw->mtx); 929 930 draw->ext->flush->invalidate(draw->dri_drawable); 931 932 return ret; 933 } 934 935 int 936 loader_dri3_query_buffer_age(struct loader_dri3_drawable *draw) 937 { 938 struct loader_dri3_buffer *back = dri3_find_back_alloc(draw); 939 int ret; 940 941 mtx_lock(&draw->mtx); 942 ret = (!back || back->last_swap == 0) ? 0 : 943 draw->send_sbc - back->last_swap + 1; 944 mtx_unlock(&draw->mtx); 945 946 return ret; 947 } 948 949 /** loader_dri3_open 950 * 951 * Wrapper around xcb_dri3_open 952 */ 953 int 954 loader_dri3_open(xcb_connection_t *conn, 955 xcb_window_t root, 956 uint32_t provider) 957 { 958 xcb_dri3_open_cookie_t cookie; 959 xcb_dri3_open_reply_t *reply; 960 int fd; 961 962 cookie = xcb_dri3_open(conn, 963 root, 964 provider); 965 966 reply = xcb_dri3_open_reply(conn, cookie, NULL); 967 if (!reply) 968 return -1; 969 970 if (reply->nfd != 1) { 971 free(reply); 972 return -1; 973 } 974 975 fd = xcb_dri3_open_reply_fds(conn, reply)[0]; 976 free(reply); 977 fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); 978 979 return fd; 980 } 981 982 static uint32_t 983 dri3_cpp_for_format(uint32_t format) { 984 switch (format) { 985 case __DRI_IMAGE_FORMAT_R8: 986 return 1; 987 case __DRI_IMAGE_FORMAT_RGB565: 988 case __DRI_IMAGE_FORMAT_GR88: 989 return 2; 990 case __DRI_IMAGE_FORMAT_XRGB8888: 991 case __DRI_IMAGE_FORMAT_ARGB8888: 992 case __DRI_IMAGE_FORMAT_ABGR8888: 993 case __DRI_IMAGE_FORMAT_XBGR8888: 994 case __DRI_IMAGE_FORMAT_XRGB2101010: 995 case __DRI_IMAGE_FORMAT_ARGB2101010: 996 case __DRI_IMAGE_FORMAT_SARGB8: 997 return 4; 998 case __DRI_IMAGE_FORMAT_NONE: 999 default: 1000 return 0; 1001 } 1002 } 1003 1004 /* the DRIimage createImage function takes __DRI_IMAGE_FORMAT codes, while 1005 * the createImageFromFds call takes __DRI_IMAGE_FOURCC codes. To avoid 1006 * complete confusion, just deal in __DRI_IMAGE_FORMAT codes for now and 1007 * translate to __DRI_IMAGE_FOURCC codes in the call to createImageFromFds 1008 */ 1009 static int 1010 image_format_to_fourcc(int format) 1011 { 1012 1013 /* Convert from __DRI_IMAGE_FORMAT to __DRI_IMAGE_FOURCC (sigh) */ 1014 switch (format) { 1015 case __DRI_IMAGE_FORMAT_SARGB8: return __DRI_IMAGE_FOURCC_SARGB8888; 1016 case __DRI_IMAGE_FORMAT_RGB565: return __DRI_IMAGE_FOURCC_RGB565; 1017 case __DRI_IMAGE_FORMAT_XRGB8888: return __DRI_IMAGE_FOURCC_XRGB8888; 1018 case __DRI_IMAGE_FORMAT_ARGB8888: return __DRI_IMAGE_FOURCC_ARGB8888; 1019 case __DRI_IMAGE_FORMAT_ABGR8888: return __DRI_IMAGE_FOURCC_ABGR8888; 1020 case __DRI_IMAGE_FORMAT_XBGR8888: return __DRI_IMAGE_FOURCC_XBGR8888; 1021 case __DRI_IMAGE_FORMAT_XRGB2101010: return __DRI_IMAGE_FOURCC_XRGB2101010; 1022 case __DRI_IMAGE_FORMAT_ARGB2101010: return __DRI_IMAGE_FOURCC_ARGB2101010; 1023 } 1024 return 0; 1025 } 1026 1027 /** loader_dri3_alloc_render_buffer 1028 * 1029 * Use the driver createImage function to construct a __DRIimage, then 1030 * get a file descriptor for that and create an X pixmap from that 1031 * 1032 * Allocate an xshmfence for synchronization 1033 */ 1034 static struct loader_dri3_buffer * 1035 dri3_alloc_render_buffer(struct loader_dri3_drawable *draw, unsigned int format, 1036 int width, int height, int depth) 1037 { 1038 struct loader_dri3_buffer *buffer; 1039 __DRIimage *pixmap_buffer; 1040 xcb_pixmap_t pixmap; 1041 xcb_sync_fence_t sync_fence; 1042 struct xshmfence *shm_fence; 1043 int buffer_fd, fence_fd; 1044 int stride; 1045 1046 /* Create an xshmfence object and 1047 * prepare to send that to the X server 1048 */ 1049 1050 fence_fd = xshmfence_alloc_shm(); 1051 if (fence_fd < 0) 1052 return NULL; 1053 1054 shm_fence = xshmfence_map_shm(fence_fd); 1055 if (shm_fence == NULL) 1056 goto no_shm_fence; 1057 1058 /* Allocate the image from the driver 1059 */ 1060 buffer = calloc(1, sizeof *buffer); 1061 if (!buffer) 1062 goto no_buffer; 1063 1064 buffer->cpp = dri3_cpp_for_format(format); 1065 if (!buffer->cpp) 1066 goto no_image; 1067 1068 if (!draw->is_different_gpu) { 1069 buffer->image = draw->ext->image->createImage(draw->dri_screen, 1070 width, height, 1071 format, 1072 __DRI_IMAGE_USE_SHARE | 1073 __DRI_IMAGE_USE_SCANOUT | 1074 __DRI_IMAGE_USE_BACKBUFFER, 1075 buffer); 1076 pixmap_buffer = buffer->image; 1077 1078 if (!buffer->image) 1079 goto no_image; 1080 } else { 1081 buffer->image = draw->ext->image->createImage(draw->dri_screen, 1082 width, height, 1083 format, 1084 0, 1085 buffer); 1086 1087 if (!buffer->image) 1088 goto no_image; 1089 1090 buffer->linear_buffer = 1091 draw->ext->image->createImage(draw->dri_screen, 1092 width, height, format, 1093 __DRI_IMAGE_USE_SHARE | 1094 __DRI_IMAGE_USE_LINEAR | 1095 __DRI_IMAGE_USE_BACKBUFFER, 1096 buffer); 1097 pixmap_buffer = buffer->linear_buffer; 1098 1099 if (!buffer->linear_buffer) 1100 goto no_linear_buffer; 1101 } 1102 1103 /* X wants the stride, so ask the image for it 1104 */ 1105 if (!draw->ext->image->queryImage(pixmap_buffer, __DRI_IMAGE_ATTRIB_STRIDE, 1106 &stride)) 1107 goto no_buffer_attrib; 1108 1109 buffer->pitch = stride; 1110 1111 if (!draw->ext->image->queryImage(pixmap_buffer, __DRI_IMAGE_ATTRIB_FD, 1112 &buffer_fd)) 1113 goto no_buffer_attrib; 1114 1115 xcb_dri3_pixmap_from_buffer(draw->conn, 1116 (pixmap = xcb_generate_id(draw->conn)), 1117 draw->drawable, 1118 buffer->size, 1119 width, height, buffer->pitch, 1120 depth, buffer->cpp * 8, 1121 buffer_fd); 1122 1123 xcb_dri3_fence_from_fd(draw->conn, 1124 pixmap, 1125 (sync_fence = xcb_generate_id(draw->conn)), 1126 false, 1127 fence_fd); 1128 1129 buffer->pixmap = pixmap; 1130 buffer->own_pixmap = true; 1131 buffer->sync_fence = sync_fence; 1132 buffer->shm_fence = shm_fence; 1133 buffer->width = width; 1134 buffer->height = height; 1135 1136 /* Mark the buffer as idle 1137 */ 1138 dri3_fence_set(buffer); 1139 1140 return buffer; 1141 1142 no_buffer_attrib: 1143 draw->ext->image->destroyImage(pixmap_buffer); 1144 no_linear_buffer: 1145 if (draw->is_different_gpu) 1146 draw->ext->image->destroyImage(buffer->image); 1147 no_image: 1148 free(buffer); 1149 no_buffer: 1150 xshmfence_unmap_shm(shm_fence); 1151 no_shm_fence: 1152 close(fence_fd); 1153 return NULL; 1154 } 1155 1156 /** loader_dri3_update_drawable 1157 * 1158 * Called the first time we use the drawable and then 1159 * after we receive present configure notify events to 1160 * track the geometry of the drawable 1161 */ 1162 static int 1163 dri3_update_drawable(__DRIdrawable *driDrawable, 1164 struct loader_dri3_drawable *draw) 1165 { 1166 mtx_lock(&draw->mtx); 1167 if (draw->first_init) { 1168 xcb_get_geometry_cookie_t geom_cookie; 1169 xcb_get_geometry_reply_t *geom_reply; 1170 xcb_void_cookie_t cookie; 1171 xcb_generic_error_t *error; 1172 xcb_present_query_capabilities_cookie_t present_capabilities_cookie; 1173 xcb_present_query_capabilities_reply_t *present_capabilities_reply; 1174 1175 draw->first_init = false; 1176 1177 /* Try to select for input on the window. 1178 * 1179 * If the drawable is a window, this will get our events 1180 * delivered. 1181 * 1182 * Otherwise, we'll get a BadWindow error back from this request which 1183 * will let us know that the drawable is a pixmap instead. 1184 */ 1185 1186 draw->eid = xcb_generate_id(draw->conn); 1187 cookie = 1188 xcb_present_select_input_checked(draw->conn, draw->eid, draw->drawable, 1189 XCB_PRESENT_EVENT_MASK_CONFIGURE_NOTIFY | 1190 XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY | 1191 XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY); 1192 1193 present_capabilities_cookie = 1194 xcb_present_query_capabilities(draw->conn, draw->drawable); 1195 1196 /* Create an XCB event queue to hold present events outside of the usual 1197 * application event queue 1198 */ 1199 draw->special_event = xcb_register_for_special_xge(draw->conn, 1200 &xcb_present_id, 1201 draw->eid, 1202 draw->stamp); 1203 geom_cookie = xcb_get_geometry(draw->conn, draw->drawable); 1204 1205 geom_reply = xcb_get_geometry_reply(draw->conn, geom_cookie, NULL); 1206 1207 if (!geom_reply) { 1208 mtx_unlock(&draw->mtx); 1209 return false; 1210 } 1211 1212 draw->width = geom_reply->width; 1213 draw->height = geom_reply->height; 1214 draw->depth = geom_reply->depth; 1215 draw->vtable->set_drawable_size(draw, draw->width, draw->height); 1216 1217 free(geom_reply); 1218 1219 draw->is_pixmap = false; 1220 1221 /* Check to see if our select input call failed. If it failed with a 1222 * BadWindow error, then assume the drawable is a pixmap. Destroy the 1223 * special event queue created above and mark the drawable as a pixmap 1224 */ 1225 1226 error = xcb_request_check(draw->conn, cookie); 1227 1228 present_capabilities_reply = 1229 xcb_present_query_capabilities_reply(draw->conn, 1230 present_capabilities_cookie, 1231 NULL); 1232 1233 if (present_capabilities_reply) { 1234 draw->present_capabilities = present_capabilities_reply->capabilities; 1235 free(present_capabilities_reply); 1236 } else 1237 draw->present_capabilities = 0; 1238 1239 if (error) { 1240 if (error->error_code != BadWindow) { 1241 free(error); 1242 mtx_unlock(&draw->mtx); 1243 return false; 1244 } 1245 draw->is_pixmap = true; 1246 xcb_unregister_for_special_event(draw->conn, draw->special_event); 1247 draw->special_event = NULL; 1248 } 1249 } 1250 dri3_flush_present_events(draw); 1251 mtx_unlock(&draw->mtx); 1252 return true; 1253 } 1254 1255 __DRIimage * 1256 loader_dri3_create_image(xcb_connection_t *c, 1257 xcb_dri3_buffer_from_pixmap_reply_t *bp_reply, 1258 unsigned int format, 1259 __DRIscreen *dri_screen, 1260 const __DRIimageExtension *image, 1261 void *loaderPrivate) 1262 { 1263 int *fds; 1264 __DRIimage *image_planar, *ret; 1265 int stride, offset; 1266 1267 /* Get an FD for the pixmap object 1268 */ 1269 fds = xcb_dri3_buffer_from_pixmap_reply_fds(c, bp_reply); 1270 1271 stride = bp_reply->stride; 1272 offset = 0; 1273 1274 /* createImageFromFds creates a wrapper __DRIimage structure which 1275 * can deal with multiple planes for things like Yuv images. So, once 1276 * we've gotten the planar wrapper, pull the single plane out of it and 1277 * discard the wrapper. 1278 */ 1279 image_planar = image->createImageFromFds(dri_screen, 1280 bp_reply->width, 1281 bp_reply->height, 1282 image_format_to_fourcc(format), 1283 fds, 1, 1284 &stride, &offset, loaderPrivate); 1285 close(fds[0]); 1286 if (!image_planar) 1287 return NULL; 1288 1289 ret = image->fromPlanar(image_planar, 0, loaderPrivate); 1290 1291 image->destroyImage(image_planar); 1292 1293 return ret; 1294 } 1295 1296 /** dri3_get_pixmap_buffer 1297 * 1298 * Get the DRM object for a pixmap from the X server and 1299 * wrap that with a __DRIimage structure using createImageFromFds 1300 */ 1301 static struct loader_dri3_buffer * 1302 dri3_get_pixmap_buffer(__DRIdrawable *driDrawable, unsigned int format, 1303 enum loader_dri3_buffer_type buffer_type, 1304 struct loader_dri3_drawable *draw) 1305 { 1306 int buf_id = loader_dri3_pixmap_buf_id(buffer_type); 1307 struct loader_dri3_buffer *buffer = draw->buffers[buf_id]; 1308 xcb_drawable_t pixmap; 1309 xcb_dri3_buffer_from_pixmap_cookie_t bp_cookie; 1310 xcb_dri3_buffer_from_pixmap_reply_t *bp_reply; 1311 xcb_sync_fence_t sync_fence; 1312 struct xshmfence *shm_fence; 1313 int fence_fd; 1314 __DRIscreen *cur_screen; 1315 1316 if (buffer) 1317 return buffer; 1318 1319 pixmap = draw->drawable; 1320 1321 buffer = calloc(1, sizeof *buffer); 1322 if (!buffer) 1323 goto no_buffer; 1324 1325 fence_fd = xshmfence_alloc_shm(); 1326 if (fence_fd < 0) 1327 goto no_fence; 1328 shm_fence = xshmfence_map_shm(fence_fd); 1329 if (shm_fence == NULL) { 1330 close (fence_fd); 1331 goto no_fence; 1332 } 1333 1334 xcb_dri3_fence_from_fd(draw->conn, 1335 pixmap, 1336 (sync_fence = xcb_generate_id(draw->conn)), 1337 false, 1338 fence_fd); 1339 1340 bp_cookie = xcb_dri3_buffer_from_pixmap(draw->conn, pixmap); 1341 bp_reply = xcb_dri3_buffer_from_pixmap_reply(draw->conn, bp_cookie, NULL); 1342 if (!bp_reply) 1343 goto no_image; 1344 1345 /* Get the currently-bound screen or revert to using the drawable's screen if 1346 * no contexts are currently bound. The latter case is at least necessary for 1347 * obs-studio, when using Window Capture (Xcomposite) as a Source. 1348 */ 1349 cur_screen = draw->vtable->get_dri_screen(); 1350 if (!cur_screen) { 1351 cur_screen = draw->dri_screen; 1352 } 1353 1354 buffer->image = loader_dri3_create_image(draw->conn, bp_reply, format, 1355 cur_screen, draw->ext->image, 1356 buffer); 1357 if (!buffer->image) 1358 goto no_image; 1359 1360 buffer->pixmap = pixmap; 1361 buffer->own_pixmap = false; 1362 buffer->width = bp_reply->width; 1363 buffer->height = bp_reply->height; 1364 buffer->shm_fence = shm_fence; 1365 buffer->sync_fence = sync_fence; 1366 1367 draw->buffers[buf_id] = buffer; 1368 1369 free(bp_reply); 1370 1371 return buffer; 1372 1373 no_image: 1374 free(bp_reply); 1375 xcb_sync_destroy_fence(draw->conn, sync_fence); 1376 xshmfence_unmap_shm(shm_fence); 1377 no_fence: 1378 free(buffer); 1379 no_buffer: 1380 return NULL; 1381 } 1382 1383 /** dri3_get_buffer 1384 * 1385 * Find a front or back buffer, allocating new ones as necessary 1386 */ 1387 static struct loader_dri3_buffer * 1388 dri3_get_buffer(__DRIdrawable *driDrawable, 1389 unsigned int format, 1390 enum loader_dri3_buffer_type buffer_type, 1391 struct loader_dri3_drawable *draw) 1392 { 1393 struct loader_dri3_buffer *buffer; 1394 int buf_id; 1395 1396 if (buffer_type == loader_dri3_buffer_back) { 1397 draw->back_format = format; 1398 1399 buf_id = dri3_find_back(draw); 1400 1401 if (buf_id < 0) 1402 return NULL; 1403 } else { 1404 buf_id = LOADER_DRI3_FRONT_ID; 1405 } 1406 1407 buffer = draw->buffers[buf_id]; 1408 1409 /* Allocate a new buffer if there isn't an old one, or if that 1410 * old one is the wrong size 1411 */ 1412 if (!buffer || buffer->width != draw->width || 1413 buffer->height != draw->height) { 1414 struct loader_dri3_buffer *new_buffer; 1415 1416 /* Allocate the new buffers 1417 */ 1418 new_buffer = dri3_alloc_render_buffer(draw, 1419 format, 1420 draw->width, 1421 draw->height, 1422 draw->depth); 1423 if (!new_buffer) 1424 return NULL; 1425 1426 /* When resizing, copy the contents of the old buffer, waiting for that 1427 * copy to complete using our fences before proceeding 1428 */ 1429 if ((buffer_type == loader_dri3_buffer_back || 1430 (buffer_type == loader_dri3_buffer_front && draw->have_fake_front)) 1431 && buffer) { 1432 1433 /* Fill the new buffer with data from an old buffer */ 1434 dri3_fence_await(draw->conn, draw, buffer); 1435 if (!loader_dri3_blit_image(draw, 1436 new_buffer->image, 1437 buffer->image, 1438 0, 0, draw->width, draw->height, 1439 0, 0, 0) && 1440 !buffer->linear_buffer) { 1441 dri3_fence_reset(draw->conn, new_buffer); 1442 dri3_copy_area(draw->conn, 1443 buffer->pixmap, 1444 new_buffer->pixmap, 1445 dri3_drawable_gc(draw), 1446 0, 0, 0, 0, 1447 draw->width, draw->height); 1448 dri3_fence_trigger(draw->conn, new_buffer); 1449 } 1450 dri3_free_render_buffer(draw, buffer); 1451 } else if (buffer_type == loader_dri3_buffer_front) { 1452 /* Fill the new fake front with data from a real front */ 1453 loader_dri3_swapbuffer_barrier(draw); 1454 dri3_fence_reset(draw->conn, new_buffer); 1455 dri3_copy_area(draw->conn, 1456 draw->drawable, 1457 new_buffer->pixmap, 1458 dri3_drawable_gc(draw), 1459 0, 0, 0, 0, 1460 draw->width, draw->height); 1461 dri3_fence_trigger(draw->conn, new_buffer); 1462 1463 if (new_buffer->linear_buffer) { 1464 dri3_fence_await(draw->conn, draw, new_buffer); 1465 (void) loader_dri3_blit_image(draw, 1466 new_buffer->image, 1467 new_buffer->linear_buffer, 1468 0, 0, draw->width, draw->height, 1469 0, 0, 0); 1470 } 1471 } 1472 buffer = new_buffer; 1473 draw->buffers[buf_id] = buffer; 1474 } 1475 dri3_fence_await(draw->conn, draw, buffer); 1476 1477 /* 1478 * Do we need to preserve the content of a previous buffer? 1479 * 1480 * Note that this blit is needed only to avoid a wait for a buffer that 1481 * is currently in the flip chain or being scanned out from. That's really 1482 * a tradeoff. If we're ok with the wait we can reduce the number of back 1483 * buffers to 1 for SWAP_EXCHANGE, and 1 for SWAP_COPY, 1484 * but in the latter case we must disallow page-flipping. 1485 */ 1486 if (buffer_type == loader_dri3_buffer_back && 1487 draw->cur_blit_source != -1 && 1488 draw->buffers[draw->cur_blit_source] && 1489 buffer != draw->buffers[draw->cur_blit_source]) { 1490 1491 struct loader_dri3_buffer *source = draw->buffers[draw->cur_blit_source]; 1492 1493 /* Avoid flushing here. Will propably do good for tiling hardware. */ 1494 (void) loader_dri3_blit_image(draw, 1495 buffer->image, 1496 source->image, 1497 0, 0, draw->width, draw->height, 1498 0, 0, 0); 1499 buffer->last_swap = source->last_swap; 1500 draw->cur_blit_source = -1; 1501 } 1502 /* Return the requested buffer */ 1503 return buffer; 1504 } 1505 1506 /** dri3_free_buffers 1507 * 1508 * Free the front bufffer or all of the back buffers. Used 1509 * when the application changes which buffers it needs 1510 */ 1511 static void 1512 dri3_free_buffers(__DRIdrawable *driDrawable, 1513 enum loader_dri3_buffer_type buffer_type, 1514 struct loader_dri3_drawable *draw) 1515 { 1516 struct loader_dri3_buffer *buffer; 1517 int first_id; 1518 int n_id; 1519 int buf_id; 1520 1521 switch (buffer_type) { 1522 case loader_dri3_buffer_back: 1523 first_id = LOADER_DRI3_BACK_ID(0); 1524 n_id = LOADER_DRI3_MAX_BACK; 1525 draw->cur_blit_source = -1; 1526 break; 1527 case loader_dri3_buffer_front: 1528 first_id = LOADER_DRI3_FRONT_ID; 1529 /* Don't free a fake front holding new backbuffer content. */ 1530 n_id = (draw->cur_blit_source == LOADER_DRI3_FRONT_ID) ? 0 : 1; 1531 } 1532 1533 for (buf_id = first_id; buf_id < first_id + n_id; buf_id++) { 1534 buffer = draw->buffers[buf_id]; 1535 if (buffer) { 1536 dri3_free_render_buffer(draw, buffer); 1537 draw->buffers[buf_id] = NULL; 1538 } 1539 } 1540 } 1541 1542 /** loader_dri3_get_buffers 1543 * 1544 * The published buffer allocation API. 1545 * Returns all of the necessary buffers, allocating 1546 * as needed. 1547 */ 1548 int 1549 loader_dri3_get_buffers(__DRIdrawable *driDrawable, 1550 unsigned int format, 1551 uint32_t *stamp, 1552 void *loaderPrivate, 1553 uint32_t buffer_mask, 1554 struct __DRIimageList *buffers) 1555 { 1556 struct loader_dri3_drawable *draw = loaderPrivate; 1557 struct loader_dri3_buffer *front, *back; 1558 1559 buffers->image_mask = 0; 1560 buffers->front = NULL; 1561 buffers->back = NULL; 1562 1563 front = NULL; 1564 back = NULL; 1565 1566 if (!dri3_update_drawable(driDrawable, draw)) 1567 return false; 1568 1569 /* pixmaps always have front buffers. 1570 * Exchange swaps also mandate fake front buffers. 1571 */ 1572 if (draw->is_pixmap || draw->swap_method == __DRI_ATTRIB_SWAP_EXCHANGE) 1573 buffer_mask |= __DRI_IMAGE_BUFFER_FRONT; 1574 1575 if (buffer_mask & __DRI_IMAGE_BUFFER_FRONT) { 1576 /* All pixmaps are owned by the server gpu. 1577 * When we use a different gpu, we can't use the pixmap 1578 * as buffer since it is potentially tiled a way 1579 * our device can't understand. In this case, use 1580 * a fake front buffer. Hopefully the pixmap 1581 * content will get synced with the fake front 1582 * buffer. 1583 */ 1584 if (draw->is_pixmap && !draw->is_different_gpu) 1585 front = dri3_get_pixmap_buffer(driDrawable, 1586 format, 1587 loader_dri3_buffer_front, 1588 draw); 1589 else 1590 front = dri3_get_buffer(driDrawable, 1591 format, 1592 loader_dri3_buffer_front, 1593 draw); 1594 1595 if (!front) 1596 return false; 1597 } else { 1598 dri3_free_buffers(driDrawable, loader_dri3_buffer_front, draw); 1599 draw->have_fake_front = 0; 1600 } 1601 1602 if (buffer_mask & __DRI_IMAGE_BUFFER_BACK) { 1603 back = dri3_get_buffer(driDrawable, 1604 format, 1605 loader_dri3_buffer_back, 1606 draw); 1607 if (!back) 1608 return false; 1609 draw->have_back = 1; 1610 } else { 1611 dri3_free_buffers(driDrawable, loader_dri3_buffer_back, draw); 1612 draw->have_back = 0; 1613 } 1614 1615 if (front) { 1616 buffers->image_mask |= __DRI_IMAGE_BUFFER_FRONT; 1617 buffers->front = front->image; 1618 draw->have_fake_front = draw->is_different_gpu || !draw->is_pixmap; 1619 } 1620 1621 if (back) { 1622 buffers->image_mask |= __DRI_IMAGE_BUFFER_BACK; 1623 buffers->back = back->image; 1624 } 1625 1626 draw->stamp = stamp; 1627 1628 return true; 1629 } 1630 1631 /** loader_dri3_update_drawable_geometry 1632 * 1633 * Get the current drawable geometry. 1634 */ 1635 void 1636 loader_dri3_update_drawable_geometry(struct loader_dri3_drawable *draw) 1637 { 1638 xcb_get_geometry_cookie_t geom_cookie; 1639 xcb_get_geometry_reply_t *geom_reply; 1640 1641 geom_cookie = xcb_get_geometry(draw->conn, draw->drawable); 1642 1643 geom_reply = xcb_get_geometry_reply(draw->conn, geom_cookie, NULL); 1644 1645 if (geom_reply) { 1646 draw->width = geom_reply->width; 1647 draw->height = geom_reply->height; 1648 draw->vtable->set_drawable_size(draw, draw->width, draw->height); 1649 draw->ext->flush->invalidate(draw->dri_drawable); 1650 1651 free(geom_reply); 1652 } 1653 } 1654 1655 1656 /** 1657 * Make sure the server has flushed all pending swap buffers to hardware 1658 * for this drawable. Ideally we'd want to send an X protocol request to 1659 * have the server block our connection until the swaps are complete. That 1660 * would avoid the potential round-trip here. 1661 */ 1662 void 1663 loader_dri3_swapbuffer_barrier(struct loader_dri3_drawable *draw) 1664 { 1665 int64_t ust, msc, sbc; 1666 1667 (void) loader_dri3_wait_for_sbc(draw, 0, &ust, &msc, &sbc); 1668 } 1669 1670 /** 1671 * Perform any cleanup associated with a close screen operation. 1672 * \param dri_screen[in,out] Pointer to __DRIscreen about to be closed. 1673 * 1674 * This function destroys the screen's cached swap context if any. 1675 */ 1676 void 1677 loader_dri3_close_screen(__DRIscreen *dri_screen) 1678 { 1679 mtx_lock(&blit_context.mtx); 1680 if (blit_context.ctx && blit_context.cur_screen == dri_screen) { 1681 blit_context.core->destroyContext(blit_context.ctx); 1682 blit_context.ctx = NULL; 1683 } 1684 mtx_unlock(&blit_context.mtx); 1685 } 1686 1687 /** 1688 * Find a backbuffer slot - potentially allocating a back buffer 1689 * 1690 * \param draw[in,out] Pointer to the drawable for which to find back. 1691 * \return Pointer to a new back buffer or NULL if allocation failed or was 1692 * not mandated. 1693 * 1694 * Find a potentially new back buffer, and if it's not been allocated yet and 1695 * in addition needs initializing, then try to allocate and initialize it. 1696 */ 1697 #include <stdio.h> 1698 static struct loader_dri3_buffer * 1699 dri3_find_back_alloc(struct loader_dri3_drawable *draw) 1700 { 1701 struct loader_dri3_buffer *back; 1702 int id; 1703 1704 id = dri3_find_back(draw); 1705 if (id < 0) 1706 return NULL; 1707 1708 back = draw->buffers[id]; 1709 /* Allocate a new back if we haven't got one */ 1710 if (!back && draw->back_format != __DRI_IMAGE_FORMAT_NONE && 1711 dri3_update_drawable(draw->dri_drawable, draw)) 1712 back = dri3_alloc_render_buffer(draw, draw->back_format, 1713 draw->width, draw->height, draw->depth); 1714 1715 if (!back) 1716 return NULL; 1717 1718 draw->buffers[id] = back; 1719 1720 /* If necessary, prefill the back with data according to swap_method mode. */ 1721 if (draw->cur_blit_source != -1 && 1722 draw->buffers[draw->cur_blit_source] && 1723 back != draw->buffers[draw->cur_blit_source]) { 1724 struct loader_dri3_buffer *source = draw->buffers[draw->cur_blit_source]; 1725 1726 dri3_fence_await(draw->conn, draw, source); 1727 dri3_fence_await(draw->conn, draw, back); 1728 (void) loader_dri3_blit_image(draw, 1729 back->image, 1730 source->image, 1731 0, 0, draw->width, draw->height, 1732 0, 0, 0); 1733 back->last_swap = source->last_swap; 1734 draw->cur_blit_source = -1; 1735 } 1736 1737 return back; 1738 } 1739