dri3_glx.c revision af69d88d
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/* 24 * Portions of this code were adapted from dri2_glx.c which carries the 25 * following copyright: 26 * 27 * Copyright © 2008 Red Hat, Inc. 28 * 29 * Permission is hereby granted, free of charge, to any person obtaining a 30 * copy of this software and associated documentation files (the "Soft- 31 * ware"), to deal in the Software without restriction, including without 32 * limitation the rights to use, copy, modify, merge, publish, distribute, 33 * and/or sell copies of the Software, and to permit persons to whom the 34 * Software is furnished to do so, provided that the above copyright 35 * notice(s) and this permission notice appear in all copies of the Soft- 36 * ware and that both the above copyright notice(s) and this permission 37 * notice appear in supporting documentation. 38 * 39 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 40 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- 41 * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY 42 * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN 43 * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE- 44 * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 45 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 46 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR- 47 * MANCE OF THIS SOFTWARE. 48 * 49 * Except as contained in this notice, the name of a copyright holder shall 50 * not be used in advertising or otherwise to promote the sale, use or 51 * other dealings in this Software without prior written authorization of 52 * the copyright holder. 53 * 54 * Authors: 55 * Kristian Høgsberg (krh@redhat.com) 56 */ 57 58#if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL) 59 60#include <X11/Xlib.h> 61#include <X11/extensions/Xfixes.h> 62#include <X11/Xlib-xcb.h> 63#include <X11/xshmfence.h> 64#include <xcb/xcb.h> 65#include <xcb/dri3.h> 66#include <xcb/present.h> 67#include <GL/gl.h> 68#include "glxclient.h" 69#include <dlfcn.h> 70#include <fcntl.h> 71#include <unistd.h> 72#include <sys/types.h> 73#include <sys/mman.h> 74#include <sys/time.h> 75 76#include "dri_common.h" 77#include "dri3_priv.h" 78#include "loader.h" 79#include "dri2.h" 80 81static const struct glx_context_vtable dri3_context_vtable; 82 83static inline void 84dri3_fence_reset(xcb_connection_t *c, struct dri3_buffer *buffer) 85{ 86 xshmfence_reset(buffer->shm_fence); 87} 88 89static inline void 90dri3_fence_set(struct dri3_buffer *buffer) 91{ 92 xshmfence_trigger(buffer->shm_fence); 93} 94 95static inline void 96dri3_fence_trigger(xcb_connection_t *c, struct dri3_buffer *buffer) 97{ 98 xcb_sync_trigger_fence(c, buffer->sync_fence); 99} 100 101static inline void 102dri3_fence_await(xcb_connection_t *c, struct dri3_buffer *buffer) 103{ 104 xcb_flush(c); 105 xshmfence_await(buffer->shm_fence); 106} 107 108static inline Bool 109dri3_fence_triggered(struct dri3_buffer *buffer) 110{ 111 return xshmfence_query(buffer->shm_fence); 112} 113 114static void 115dri3_destroy_context(struct glx_context *context) 116{ 117 struct dri3_context *pcp = (struct dri3_context *) context; 118 struct dri3_screen *psc = (struct dri3_screen *) context->psc; 119 120 driReleaseDrawables(&pcp->base); 121 122 free((char *) context->extensions); 123 124 (*psc->core->destroyContext) (pcp->driContext); 125 126 free(pcp); 127} 128 129static Bool 130dri3_bind_context(struct glx_context *context, struct glx_context *old, 131 GLXDrawable draw, GLXDrawable read) 132{ 133 struct dri3_context *pcp = (struct dri3_context *) context; 134 struct dri3_screen *psc = (struct dri3_screen *) pcp->base.psc; 135 struct dri3_drawable *pdraw, *pread; 136 137 pdraw = (struct dri3_drawable *) driFetchDrawable(context, draw); 138 pread = (struct dri3_drawable *) driFetchDrawable(context, read); 139 140 driReleaseDrawables(&pcp->base); 141 142 if (pdraw == NULL || pread == NULL) 143 return GLXBadDrawable; 144 145 if (!(*psc->core->bindContext) (pcp->driContext, 146 pdraw->driDrawable, pread->driDrawable)) 147 return GLXBadContext; 148 149 return Success; 150} 151 152static void 153dri3_unbind_context(struct glx_context *context, struct glx_context *new) 154{ 155 struct dri3_context *pcp = (struct dri3_context *) context; 156 struct dri3_screen *psc = (struct dri3_screen *) pcp->base.psc; 157 158 (*psc->core->unbindContext) (pcp->driContext); 159} 160 161static struct glx_context * 162dri3_create_context_attribs(struct glx_screen *base, 163 struct glx_config *config_base, 164 struct glx_context *shareList, 165 unsigned num_attribs, 166 const uint32_t *attribs, 167 unsigned *error) 168{ 169 struct dri3_context *pcp = NULL; 170 struct dri3_context *pcp_shared = NULL; 171 struct dri3_screen *psc = (struct dri3_screen *) base; 172 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base; 173 __DRIcontext *shared = NULL; 174 175 uint32_t minor_ver = 1; 176 uint32_t major_ver = 2; 177 uint32_t flags = 0; 178 unsigned api; 179 int reset = __DRI_CTX_RESET_NO_NOTIFICATION; 180 uint32_t ctx_attribs[2 * 5]; 181 unsigned num_ctx_attribs = 0; 182 uint32_t render_type; 183 184 /* Remap the GLX tokens to DRI2 tokens. 185 */ 186 if (!dri2_convert_glx_attribs(num_attribs, attribs, 187 &major_ver, &minor_ver, 188 &render_type, &flags, &api, 189 &reset, error)) 190 goto error_exit; 191 192 /* Check the renderType value */ 193 if (!validate_renderType_against_config(config_base, render_type)) 194 goto error_exit; 195 196 if (shareList) { 197 pcp_shared = (struct dri3_context *) shareList; 198 shared = pcp_shared->driContext; 199 } 200 201 pcp = calloc(1, sizeof *pcp); 202 if (pcp == NULL) { 203 *error = __DRI_CTX_ERROR_NO_MEMORY; 204 goto error_exit; 205 } 206 207 if (!glx_context_init(&pcp->base, &psc->base, &config->base)) 208 goto error_exit; 209 210 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MAJOR_VERSION; 211 ctx_attribs[num_ctx_attribs++] = major_ver; 212 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MINOR_VERSION; 213 ctx_attribs[num_ctx_attribs++] = minor_ver; 214 215 /* Only send a value when the non-default value is requested. By doing 216 * this we don't have to check the driver's DRI3 version before sending the 217 * default value. 218 */ 219 if (reset != __DRI_CTX_RESET_NO_NOTIFICATION) { 220 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_RESET_STRATEGY; 221 ctx_attribs[num_ctx_attribs++] = reset; 222 } 223 224 if (flags != 0) { 225 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_FLAGS; 226 227 /* The current __DRI_CTX_FLAG_* values are identical to the 228 * GLX_CONTEXT_*_BIT values. 229 */ 230 ctx_attribs[num_ctx_attribs++] = flags; 231 } 232 233 pcp->driContext = 234 (*psc->image_driver->createContextAttribs) (psc->driScreen, 235 api, 236 config->driConfig, 237 shared, 238 num_ctx_attribs / 2, 239 ctx_attribs, 240 error, 241 pcp); 242 243 if (pcp->driContext == NULL) 244 goto error_exit; 245 246 pcp->base.vtable = &dri3_context_vtable; 247 248 return &pcp->base; 249 250error_exit: 251 free(pcp); 252 253 return NULL; 254} 255 256static struct glx_context * 257dri3_create_context(struct glx_screen *base, 258 struct glx_config *config_base, 259 struct glx_context *shareList, int renderType) 260{ 261 unsigned int error; 262 263 return dri3_create_context_attribs(base, config_base, shareList, 264 0, NULL, &error); 265} 266 267static void 268dri3_free_render_buffer(struct dri3_drawable *pdraw, struct dri3_buffer *buffer); 269 270static void 271dri3_update_num_back(struct dri3_drawable *priv) 272{ 273 priv->num_back = 1; 274 if (priv->flipping) 275 priv->num_back++; 276 if (priv->swap_interval == 0) 277 priv->num_back++; 278} 279 280static void 281dri3_destroy_drawable(__GLXDRIdrawable *base) 282{ 283 struct dri3_screen *psc = (struct dri3_screen *) base->psc; 284 struct dri3_drawable *pdraw = (struct dri3_drawable *) base; 285 xcb_connection_t *c = XGetXCBConnection(pdraw->base.psc->dpy); 286 int i; 287 288 (*psc->core->destroyDrawable) (pdraw->driDrawable); 289 290 for (i = 0; i < DRI3_NUM_BUFFERS; i++) { 291 if (pdraw->buffers[i]) 292 dri3_free_render_buffer(pdraw, pdraw->buffers[i]); 293 } 294 295 if (pdraw->special_event) 296 xcb_unregister_for_special_event(c, pdraw->special_event); 297 free(pdraw); 298} 299 300static __GLXDRIdrawable * 301dri3_create_drawable(struct glx_screen *base, XID xDrawable, 302 GLXDrawable drawable, struct glx_config *config_base) 303{ 304 struct dri3_drawable *pdraw; 305 struct dri3_screen *psc = (struct dri3_screen *) base; 306 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base; 307 GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1; 308 309 pdraw = calloc(1, sizeof(*pdraw)); 310 if (!pdraw) 311 return NULL; 312 313 pdraw->base.destroyDrawable = dri3_destroy_drawable; 314 pdraw->base.xDrawable = xDrawable; 315 pdraw->base.drawable = drawable; 316 pdraw->base.psc = &psc->base; 317 pdraw->swap_interval = 1; /* default may be overridden below */ 318 pdraw->have_back = 0; 319 pdraw->have_fake_front = 0; 320 321 if (psc->config) 322 psc->config->configQueryi(psc->driScreen, 323 "vblank_mode", &vblank_mode); 324 325 switch (vblank_mode) { 326 case DRI_CONF_VBLANK_NEVER: 327 case DRI_CONF_VBLANK_DEF_INTERVAL_0: 328 pdraw->swap_interval = 0; 329 break; 330 case DRI_CONF_VBLANK_DEF_INTERVAL_1: 331 case DRI_CONF_VBLANK_ALWAYS_SYNC: 332 default: 333 pdraw->swap_interval = 1; 334 break; 335 } 336 337 dri3_update_num_back(pdraw); 338 339 (void) __glXInitialize(psc->base.dpy); 340 341 /* Create a new drawable */ 342 pdraw->driDrawable = 343 (*psc->image_driver->createNewDrawable) (psc->driScreen, 344 config->driConfig, pdraw); 345 346 if (!pdraw->driDrawable) { 347 free(pdraw); 348 return NULL; 349 } 350 351 /* 352 * Make sure server has the same swap interval we do for the new 353 * drawable. 354 */ 355 if (psc->vtable.setSwapInterval) 356 psc->vtable.setSwapInterval(&pdraw->base, pdraw->swap_interval); 357 358 return &pdraw->base; 359} 360 361/* 362 * Process one Present event 363 */ 364static void 365dri3_handle_present_event(struct dri3_drawable *priv, xcb_present_generic_event_t *ge) 366{ 367 switch (ge->evtype) { 368 case XCB_PRESENT_CONFIGURE_NOTIFY: { 369 xcb_present_configure_notify_event_t *ce = (void *) ge; 370 371 priv->width = ce->width; 372 priv->height = ce->height; 373 break; 374 } 375 case XCB_PRESENT_COMPLETE_NOTIFY: { 376 xcb_present_complete_notify_event_t *ce = (void *) ge; 377 378 /* Compute the processed SBC number from the received 32-bit serial number merged 379 * with the upper 32-bits of the sent 64-bit serial number while checking for 380 * wrap 381 */ 382 if (ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP) { 383 priv->recv_sbc = (priv->send_sbc & 0xffffffff00000000LL) | ce->serial; 384 if (priv->recv_sbc > priv->send_sbc) 385 priv->recv_sbc -= 0x100000000; 386 switch (ce->mode) { 387 case XCB_PRESENT_COMPLETE_MODE_FLIP: 388 priv->flipping = true; 389 break; 390 case XCB_PRESENT_COMPLETE_MODE_COPY: 391 priv->flipping = false; 392 break; 393 } 394 dri3_update_num_back(priv); 395 } else { 396 priv->recv_msc_serial = ce->serial; 397 } 398 priv->ust = ce->ust; 399 priv->msc = ce->msc; 400 break; 401 } 402 case XCB_PRESENT_EVENT_IDLE_NOTIFY: { 403 xcb_present_idle_notify_event_t *ie = (void *) ge; 404 int b; 405 406 for (b = 0; b < sizeof (priv->buffers) / sizeof (priv->buffers[0]); b++) { 407 struct dri3_buffer *buf = priv->buffers[b]; 408 409 if (buf && buf->pixmap == ie->pixmap) { 410 buf->busy = 0; 411 if (priv->num_back <= b && b < DRI3_MAX_BACK) { 412 dri3_free_render_buffer(priv, buf); 413 priv->buffers[b] = NULL; 414 } 415 break; 416 } 417 } 418 break; 419 } 420 } 421 free(ge); 422} 423 424static bool 425dri3_wait_for_event(__GLXDRIdrawable *pdraw) 426{ 427 xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy); 428 struct dri3_drawable *priv = (struct dri3_drawable *) pdraw; 429 xcb_generic_event_t *ev; 430 xcb_present_generic_event_t *ge; 431 432 xcb_flush(c); 433 ev = xcb_wait_for_special_event(c, priv->special_event); 434 if (!ev) 435 return false; 436 ge = (void *) ev; 437 dri3_handle_present_event(priv, ge); 438 return true; 439} 440 441/** dri3_wait_for_msc 442 * 443 * Get the X server to send an event when the target msc/divisor/remainder is 444 * reached. 445 */ 446static int 447dri3_wait_for_msc(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor, 448 int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc) 449{ 450 xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy); 451 struct dri3_drawable *priv = (struct dri3_drawable *) pdraw; 452 uint32_t msc_serial; 453 454 /* Ask for the an event for the target MSC */ 455 msc_serial = ++priv->send_msc_serial; 456 xcb_present_notify_msc(c, 457 priv->base.xDrawable, 458 msc_serial, 459 target_msc, 460 divisor, 461 remainder); 462 463 xcb_flush(c); 464 465 /* Wait for the event */ 466 if (priv->special_event) { 467 while ((int32_t) (msc_serial - priv->recv_msc_serial) > 0) { 468 if (!dri3_wait_for_event(pdraw)) 469 return 0; 470 } 471 } 472 473 *ust = priv->ust; 474 *msc = priv->msc; 475 *sbc = priv->recv_sbc; 476 477 return 1; 478} 479 480/** dri3_drawable_get_msc 481 * 482 * Return the current UST/MSC/SBC triplet by asking the server 483 * for an event 484 */ 485static int 486dri3_drawable_get_msc(struct glx_screen *psc, __GLXDRIdrawable *pdraw, 487 int64_t *ust, int64_t *msc, int64_t *sbc) 488{ 489 return dri3_wait_for_msc(pdraw, 0, 0, 0, ust, msc,sbc); 490} 491 492/** dri3_wait_for_sbc 493 * 494 * Wait for the completed swap buffer count to reach the specified 495 * target. Presumably the application knows that this will be reached with 496 * outstanding complete events, or we're going to be here awhile. 497 */ 498static int 499dri3_wait_for_sbc(__GLXDRIdrawable *pdraw, int64_t target_sbc, int64_t *ust, 500 int64_t *msc, int64_t *sbc) 501{ 502 struct dri3_drawable *priv = (struct dri3_drawable *) pdraw; 503 504 while (priv->recv_sbc < target_sbc) { 505 if (!dri3_wait_for_event(pdraw)) 506 return 0; 507 } 508 509 *ust = priv->ust; 510 *msc = priv->msc; 511 *sbc = priv->recv_sbc; 512 return 1; 513} 514 515/** 516 * Asks the driver to flush any queued work necessary for serializing with the 517 * X command stream, and optionally the slightly more strict requirement of 518 * glFlush() equivalence (which would require flushing even if nothing had 519 * been drawn to a window system framebuffer, for example). 520 */ 521static void 522dri3_flush(struct dri3_screen *psc, 523 struct dri3_drawable *draw, 524 unsigned flags, 525 enum __DRI2throttleReason throttle_reason) 526{ 527 struct glx_context *gc = __glXGetCurrentContext(); 528 529 if (gc) { 530 struct dri3_context *dri3Ctx = (struct dri3_context *)gc; 531 532 (*psc->f->flush_with_flags)(dri3Ctx->driContext, draw->driDrawable, flags, throttle_reason); 533 } 534} 535 536static xcb_gcontext_t 537dri3_drawable_gc(struct dri3_drawable *priv) 538{ 539 if (!priv->gc) { 540 uint32_t v; 541 xcb_connection_t *c = XGetXCBConnection(priv->base.psc->dpy); 542 543 v = 0; 544 xcb_create_gc(c, 545 (priv->gc = xcb_generate_id(c)), 546 priv->base.xDrawable, 547 XCB_GC_GRAPHICS_EXPOSURES, 548 &v); 549 } 550 return priv->gc; 551} 552 553static struct dri3_buffer * 554dri3_back_buffer(struct dri3_drawable *priv) 555{ 556 return priv->buffers[DRI3_BACK_ID(priv->cur_back)]; 557} 558 559static struct dri3_buffer * 560dri3_fake_front_buffer(struct dri3_drawable *priv) 561{ 562 return priv->buffers[DRI3_FRONT_ID]; 563} 564 565static void 566dri3_copy_area (xcb_connection_t *c /**< */, 567 xcb_drawable_t src_drawable /**< */, 568 xcb_drawable_t dst_drawable /**< */, 569 xcb_gcontext_t gc /**< */, 570 int16_t src_x /**< */, 571 int16_t src_y /**< */, 572 int16_t dst_x /**< */, 573 int16_t dst_y /**< */, 574 uint16_t width /**< */, 575 uint16_t height /**< */) 576{ 577 xcb_void_cookie_t cookie; 578 579 cookie = xcb_copy_area_checked(c, 580 src_drawable, 581 dst_drawable, 582 gc, 583 src_x, 584 src_y, 585 dst_x, 586 dst_y, 587 width, 588 height); 589 xcb_discard_reply(c, cookie.sequence); 590} 591 592static void 593dri3_copy_sub_buffer(__GLXDRIdrawable *pdraw, int x, int y, 594 int width, int height, 595 Bool flush) 596{ 597 struct dri3_drawable *priv = (struct dri3_drawable *) pdraw; 598 struct dri3_screen *psc = (struct dri3_screen *) pdraw->psc; 599 struct dri3_context *pcp = (struct dri3_context *) __glXGetCurrentContext(); 600 xcb_connection_t *c = XGetXCBConnection(priv->base.psc->dpy); 601 struct dri3_buffer *back; 602 603 unsigned flags = __DRI2_FLUSH_DRAWABLE; 604 605 /* Check we have the right attachments */ 606 if (!priv->have_back || priv->is_pixmap) 607 return; 608 609 if (flush) 610 flags |= __DRI2_FLUSH_CONTEXT; 611 dri3_flush(psc, priv, flags, __DRI2_THROTTLE_SWAPBUFFER); 612 613 back = dri3_back_buffer(priv); 614 y = priv->height - y - height; 615 616 if (psc->is_different_gpu && (&pcp->base != &dummyContext) && pcp->base.psc == &psc->base) { 617 /* Update the linear buffer part of the back buffer 618 * for the dri3_copy_area operation 619 */ 620 psc->image->blitImage(pcp->driContext, 621 back->linear_buffer, 622 back->image, 623 0, 0, back->width, 624 back->height, 625 0, 0, back->width, 626 back->height, __BLIT_FLAG_FLUSH); 627 /* We use blitImage to update our fake front, 628 */ 629 if (priv->have_fake_front) 630 psc->image->blitImage(pcp->driContext, 631 dri3_fake_front_buffer(priv)->image, 632 back->image, 633 x, y, width, height, 634 x, y, width, height, __BLIT_FLAG_FLUSH); 635 } 636 637 dri3_fence_reset(c, back); 638 dri3_copy_area(c, 639 dri3_back_buffer(priv)->pixmap, 640 priv->base.xDrawable, 641 dri3_drawable_gc(priv), 642 x, y, x, y, width, height); 643 dri3_fence_trigger(c, back); 644 /* Refresh the fake front (if present) after we just damaged the real 645 * front. 646 */ 647 if (priv->have_fake_front && !psc->is_different_gpu) { 648 dri3_fence_reset(c, dri3_fake_front_buffer(priv)); 649 dri3_copy_area(c, 650 dri3_back_buffer(priv)->pixmap, 651 dri3_fake_front_buffer(priv)->pixmap, 652 dri3_drawable_gc(priv), 653 x, y, x, y, width, height); 654 dri3_fence_trigger(c, dri3_fake_front_buffer(priv)); 655 dri3_fence_await(c, dri3_fake_front_buffer(priv)); 656 } 657 dri3_fence_await(c, back); 658} 659 660static void 661dri3_copy_drawable(struct dri3_drawable *priv, Drawable dest, Drawable src) 662{ 663 struct dri3_screen *psc = (struct dri3_screen *) priv->base.psc; 664 xcb_connection_t *c = XGetXCBConnection(priv->base.psc->dpy); 665 666 dri3_flush(psc, priv, __DRI2_FLUSH_DRAWABLE, 0); 667 668 dri3_fence_reset(c, dri3_fake_front_buffer(priv)); 669 dri3_copy_area(c, 670 src, dest, 671 dri3_drawable_gc(priv), 672 0, 0, 0, 0, priv->width, priv->height); 673 dri3_fence_trigger(c, dri3_fake_front_buffer(priv)); 674 dri3_fence_await(c, dri3_fake_front_buffer(priv)); 675} 676 677static void 678dri3_wait_x(struct glx_context *gc) 679{ 680 struct dri3_context *pcp = (struct dri3_context *) gc; 681 struct dri3_drawable *priv = (struct dri3_drawable *) 682 GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable); 683 struct dri3_screen *psc; 684 struct dri3_buffer *front; 685 686 if (priv == NULL || !priv->have_fake_front) 687 return; 688 689 psc = (struct dri3_screen *) priv->base.psc; 690 front = dri3_fake_front_buffer(priv); 691 692 dri3_copy_drawable(priv, front->pixmap, priv->base.xDrawable); 693 694 /* In the psc->is_different_gpu case, the linear buffer has been updated, 695 * but not yet the tiled buffer. 696 * Copy back to the tiled buffer we use for rendering. 697 * Note that we don't need flushing. 698 */ 699 if (psc->is_different_gpu && (&pcp->base != &dummyContext) && pcp->base.psc == &psc->base) 700 psc->image->blitImage(pcp->driContext, 701 front->image, 702 front->linear_buffer, 703 0, 0, front->width, 704 front->height, 705 0, 0, front->width, 706 front->height, 0); 707} 708 709static void 710dri3_wait_gl(struct glx_context *gc) 711{ 712 struct dri3_context *pcp = (struct dri3_context *) gc; 713 struct dri3_drawable *priv = (struct dri3_drawable *) 714 GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable); 715 struct dri3_screen *psc; 716 struct dri3_buffer *front; 717 718 if (priv == NULL || !priv->have_fake_front) 719 return; 720 721 psc = (struct dri3_screen *) priv->base.psc; 722 front = dri3_fake_front_buffer(priv); 723 724 /* In the psc->is_different_gpu case, we update the linear_buffer 725 * before updating the real front. 726 */ 727 if (psc->is_different_gpu && (&pcp->base != &dummyContext) && pcp->base.psc == &psc->base) 728 psc->image->blitImage(pcp->driContext, 729 front->linear_buffer, 730 front->image, 731 0, 0, front->width, 732 front->height, 733 0, 0, front->width, 734 front->height, __BLIT_FLAG_FLUSH); 735 dri3_copy_drawable(priv, priv->base.xDrawable, front->pixmap); 736} 737 738/** 739 * Called by the driver when it needs to update the real front buffer with the 740 * contents of its fake front buffer. 741 */ 742static void 743dri3_flush_front_buffer(__DRIdrawable *driDrawable, void *loaderPrivate) 744{ 745 struct glx_context *gc; 746 struct dri3_drawable *pdraw = loaderPrivate; 747 struct dri3_screen *psc; 748 749 if (!pdraw) 750 return; 751 752 if (!pdraw->base.psc) 753 return; 754 755 psc = (struct dri3_screen *) pdraw->base.psc; 756 757 (void) __glXInitialize(psc->base.dpy); 758 759 gc = __glXGetCurrentContext(); 760 761 dri3_flush(psc, pdraw, __DRI2_FLUSH_DRAWABLE, __DRI2_THROTTLE_FLUSHFRONT); 762 763 dri3_wait_gl(gc); 764} 765 766static uint32_t 767dri3_cpp_for_format(uint32_t format) { 768 switch (format) { 769 case __DRI_IMAGE_FORMAT_R8: 770 return 1; 771 case __DRI_IMAGE_FORMAT_RGB565: 772 case __DRI_IMAGE_FORMAT_GR88: 773 return 2; 774 case __DRI_IMAGE_FORMAT_XRGB8888: 775 case __DRI_IMAGE_FORMAT_ARGB8888: 776 case __DRI_IMAGE_FORMAT_ABGR8888: 777 case __DRI_IMAGE_FORMAT_XBGR8888: 778 case __DRI_IMAGE_FORMAT_XRGB2101010: 779 case __DRI_IMAGE_FORMAT_ARGB2101010: 780 case __DRI_IMAGE_FORMAT_SARGB8: 781 return 4; 782 case __DRI_IMAGE_FORMAT_NONE: 783 default: 784 return 0; 785 } 786} 787 788 789/** dri3_alloc_render_buffer 790 * 791 * Use the driver createImage function to construct a __DRIimage, then 792 * get a file descriptor for that and create an X pixmap from that 793 * 794 * Allocate an xshmfence for synchronization 795 */ 796static struct dri3_buffer * 797dri3_alloc_render_buffer(struct glx_screen *glx_screen, Drawable draw, 798 unsigned int format, int width, int height, int depth) 799{ 800 struct dri3_screen *psc = (struct dri3_screen *) glx_screen; 801 Display *dpy = glx_screen->dpy; 802 struct dri3_buffer *buffer; 803 __DRIimage *pixmap_buffer; 804 xcb_connection_t *c = XGetXCBConnection(dpy); 805 xcb_pixmap_t pixmap; 806 xcb_sync_fence_t sync_fence; 807 struct xshmfence *shm_fence; 808 int buffer_fd, fence_fd; 809 int stride; 810 811 /* Create an xshmfence object and 812 * prepare to send that to the X server 813 */ 814 815 fence_fd = xshmfence_alloc_shm(); 816 if (fence_fd < 0) { 817 ErrorMessageF("DRI3 Fence object allocation failure %s\n", strerror(errno)); 818 return NULL; 819 } 820 shm_fence = xshmfence_map_shm(fence_fd); 821 if (shm_fence == NULL) { 822 ErrorMessageF("DRI3 Fence object map failure %s\n", strerror(errno)); 823 goto no_shm_fence; 824 } 825 826 /* Allocate the image from the driver 827 */ 828 buffer = calloc(1, sizeof (struct dri3_buffer)); 829 if (!buffer) 830 goto no_buffer; 831 832 buffer->cpp = dri3_cpp_for_format(format); 833 if (!buffer->cpp) { 834 ErrorMessageF("DRI3 buffer format %d invalid\n", format); 835 goto no_image; 836 } 837 838 if (!psc->is_different_gpu) { 839 buffer->image = (*psc->image->createImage) (psc->driScreen, 840 width, height, 841 format, 842 __DRI_IMAGE_USE_SHARE | 843 __DRI_IMAGE_USE_SCANOUT, 844 buffer); 845 pixmap_buffer = buffer->image; 846 847 if (!buffer->image) { 848 ErrorMessageF("DRI3 gpu image creation failure\n"); 849 goto no_image; 850 } 851 } else { 852 buffer->image = (*psc->image->createImage) (psc->driScreen, 853 width, height, 854 format, 855 0, 856 buffer); 857 858 if (!buffer->image) { 859 ErrorMessageF("DRI3 other gpu image creation failure\n"); 860 goto no_image; 861 } 862 863 buffer->linear_buffer = (*psc->image->createImage) (psc->driScreen, 864 width, height, 865 format, 866 __DRI_IMAGE_USE_SHARE | 867 __DRI_IMAGE_USE_LINEAR, 868 buffer); 869 pixmap_buffer = buffer->linear_buffer; 870 871 if (!buffer->linear_buffer) { 872 ErrorMessageF("DRI3 gpu linear image creation failure\n"); 873 goto no_linear_buffer; 874 } 875 } 876 877 /* X wants the stride, so ask the image for it 878 */ 879 if (!(*psc->image->queryImage)(pixmap_buffer, __DRI_IMAGE_ATTRIB_STRIDE, &stride)) { 880 ErrorMessageF("DRI3 get image stride failed\n"); 881 goto no_buffer_attrib; 882 } 883 884 buffer->pitch = stride; 885 886 if (!(*psc->image->queryImage)(pixmap_buffer, __DRI_IMAGE_ATTRIB_FD, &buffer_fd)) { 887 ErrorMessageF("DRI3 get image FD failed\n"); 888 goto no_buffer_attrib; 889 } 890 891 xcb_dri3_pixmap_from_buffer(c, 892 (pixmap = xcb_generate_id(c)), 893 draw, 894 buffer->size, 895 width, height, buffer->pitch, 896 depth, buffer->cpp * 8, 897 buffer_fd); 898 899 xcb_dri3_fence_from_fd(c, 900 pixmap, 901 (sync_fence = xcb_generate_id(c)), 902 false, 903 fence_fd); 904 905 buffer->pixmap = pixmap; 906 buffer->own_pixmap = true; 907 buffer->sync_fence = sync_fence; 908 buffer->shm_fence = shm_fence; 909 buffer->width = width; 910 buffer->height = height; 911 912 /* Mark the buffer as idle 913 */ 914 dri3_fence_set(buffer); 915 916 return buffer; 917 918no_buffer_attrib: 919 (*psc->image->destroyImage)(pixmap_buffer); 920no_linear_buffer: 921 if (psc->is_different_gpu) 922 (*psc->image->destroyImage)(buffer->image); 923no_image: 924 free(buffer); 925no_buffer: 926 xshmfence_unmap_shm(shm_fence); 927no_shm_fence: 928 close(fence_fd); 929 ErrorMessageF("DRI3 alloc_render_buffer failed\n"); 930 return NULL; 931} 932 933/** dri3_free_render_buffer 934 * 935 * Free everything associated with one render buffer including pixmap, fence 936 * stuff and the driver image 937 */ 938static void 939dri3_free_render_buffer(struct dri3_drawable *pdraw, struct dri3_buffer *buffer) 940{ 941 struct dri3_screen *psc = (struct dri3_screen *) pdraw->base.psc; 942 xcb_connection_t *c = XGetXCBConnection(pdraw->base.psc->dpy); 943 944 if (buffer->own_pixmap) 945 xcb_free_pixmap(c, buffer->pixmap); 946 xcb_sync_destroy_fence(c, buffer->sync_fence); 947 xshmfence_unmap_shm(buffer->shm_fence); 948 (*psc->image->destroyImage)(buffer->image); 949 if (buffer->linear_buffer) 950 (*psc->image->destroyImage)(buffer->linear_buffer); 951 free(buffer); 952} 953 954 955/** dri3_flush_present_events 956 * 957 * Process any present events that have been received from the X server 958 */ 959static void 960dri3_flush_present_events(struct dri3_drawable *priv) 961{ 962 xcb_connection_t *c = XGetXCBConnection(priv->base.psc->dpy); 963 964 /* Check to see if any configuration changes have occurred 965 * since we were last invoked 966 */ 967 if (priv->special_event) { 968 xcb_generic_event_t *ev; 969 970 while ((ev = xcb_poll_for_special_event(c, priv->special_event)) != NULL) { 971 xcb_present_generic_event_t *ge = (void *) ev; 972 dri3_handle_present_event(priv, ge); 973 } 974 } 975} 976 977/** dri3_update_drawable 978 * 979 * Called the first time we use the drawable and then 980 * after we receive present configure notify events to 981 * track the geometry of the drawable 982 */ 983static int 984dri3_update_drawable(__DRIdrawable *driDrawable, void *loaderPrivate) 985{ 986 struct dri3_drawable *priv = loaderPrivate; 987 xcb_connection_t *c = XGetXCBConnection(priv->base.psc->dpy); 988 989 /* First time through, go get the current drawable geometry 990 */ 991 if (priv->width == 0 || priv->height == 0 || priv->depth == 0) { 992 xcb_get_geometry_cookie_t geom_cookie; 993 xcb_get_geometry_reply_t *geom_reply; 994 xcb_void_cookie_t cookie; 995 xcb_generic_error_t *error; 996 997 /* Try to select for input on the window. 998 * 999 * If the drawable is a window, this will get our events 1000 * delivered. 1001 * 1002 * Otherwise, we'll get a BadWindow error back from this request which 1003 * will let us know that the drawable is a pixmap instead. 1004 */ 1005 1006 1007 cookie = xcb_present_select_input_checked(c, 1008 (priv->eid = xcb_generate_id(c)), 1009 priv->base.xDrawable, 1010 XCB_PRESENT_EVENT_MASK_CONFIGURE_NOTIFY| 1011 XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY| 1012 XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY); 1013 1014 /* Create an XCB event queue to hold present events outside of the usual 1015 * application event queue 1016 */ 1017 priv->special_event = xcb_register_for_special_xge(c, 1018 &xcb_present_id, 1019 priv->eid, 1020 priv->stamp); 1021 1022 geom_cookie = xcb_get_geometry(c, priv->base.xDrawable); 1023 1024 geom_reply = xcb_get_geometry_reply(c, geom_cookie, NULL); 1025 1026 if (!geom_reply) 1027 return false; 1028 1029 priv->width = geom_reply->width; 1030 priv->height = geom_reply->height; 1031 priv->depth = geom_reply->depth; 1032 priv->is_pixmap = false; 1033 1034 free(geom_reply); 1035 1036 /* Check to see if our select input call failed. If it failed with a 1037 * BadWindow error, then assume the drawable is a pixmap. Destroy the 1038 * special event queue created above and mark the drawable as a pixmap 1039 */ 1040 1041 error = xcb_request_check(c, cookie); 1042 1043 if (error) { 1044 if (error->error_code != BadWindow) { 1045 free(error); 1046 return false; 1047 } 1048 priv->is_pixmap = true; 1049 xcb_unregister_for_special_event(c, priv->special_event); 1050 priv->special_event = NULL; 1051 } 1052 } 1053 dri3_flush_present_events(priv); 1054 return true; 1055} 1056 1057/* the DRIimage createImage function takes __DRI_IMAGE_FORMAT codes, while 1058 * the createImageFromFds call takes __DRI_IMAGE_FOURCC codes. To avoid 1059 * complete confusion, just deal in __DRI_IMAGE_FORMAT codes for now and 1060 * translate to __DRI_IMAGE_FOURCC codes in the call to createImageFromFds 1061 */ 1062static int 1063image_format_to_fourcc(int format) 1064{ 1065 1066 /* Convert from __DRI_IMAGE_FORMAT to __DRI_IMAGE_FOURCC (sigh) */ 1067 switch (format) { 1068 case __DRI_IMAGE_FORMAT_SARGB8: return __DRI_IMAGE_FOURCC_SARGB8888; 1069 case __DRI_IMAGE_FORMAT_RGB565: return __DRI_IMAGE_FOURCC_RGB565; 1070 case __DRI_IMAGE_FORMAT_XRGB8888: return __DRI_IMAGE_FOURCC_XRGB8888; 1071 case __DRI_IMAGE_FORMAT_ARGB8888: return __DRI_IMAGE_FOURCC_ARGB8888; 1072 case __DRI_IMAGE_FORMAT_ABGR8888: return __DRI_IMAGE_FOURCC_ABGR8888; 1073 case __DRI_IMAGE_FORMAT_XBGR8888: return __DRI_IMAGE_FOURCC_XBGR8888; 1074 } 1075 return 0; 1076} 1077 1078/** dri3_get_pixmap_buffer 1079 * 1080 * Get the DRM object for a pixmap from the X server and 1081 * wrap that with a __DRIimage structure using createImageFromFds 1082 */ 1083static struct dri3_buffer * 1084dri3_get_pixmap_buffer(__DRIdrawable *driDrawable, 1085 unsigned int format, 1086 enum dri3_buffer_type buffer_type, 1087 void *loaderPrivate) 1088{ 1089 struct dri3_drawable *pdraw = loaderPrivate; 1090 int buf_id = dri3_pixmap_buf_id(buffer_type); 1091 struct dri3_buffer *buffer = pdraw->buffers[buf_id]; 1092 Pixmap pixmap; 1093 xcb_dri3_buffer_from_pixmap_cookie_t bp_cookie; 1094 xcb_dri3_buffer_from_pixmap_reply_t *bp_reply; 1095 int *fds; 1096 Display *dpy; 1097 struct dri3_screen *psc; 1098 xcb_connection_t *c; 1099 xcb_sync_fence_t sync_fence; 1100 struct xshmfence *shm_fence; 1101 int fence_fd; 1102 __DRIimage *image_planar; 1103 int stride, offset; 1104 1105 if (buffer) 1106 return buffer; 1107 1108 pixmap = pdraw->base.xDrawable; 1109 psc = (struct dri3_screen *) pdraw->base.psc; 1110 dpy = psc->base.dpy; 1111 c = XGetXCBConnection(dpy); 1112 1113 buffer = calloc(1, sizeof (struct dri3_buffer)); 1114 if (!buffer) 1115 goto no_buffer; 1116 1117 fence_fd = xshmfence_alloc_shm(); 1118 if (fence_fd < 0) 1119 goto no_fence; 1120 shm_fence = xshmfence_map_shm(fence_fd); 1121 if (shm_fence == NULL) { 1122 close (fence_fd); 1123 goto no_fence; 1124 } 1125 1126 xcb_dri3_fence_from_fd(c, 1127 pixmap, 1128 (sync_fence = xcb_generate_id(c)), 1129 false, 1130 fence_fd); 1131 1132 /* Get an FD for the pixmap object 1133 */ 1134 bp_cookie = xcb_dri3_buffer_from_pixmap(c, pixmap); 1135 bp_reply = xcb_dri3_buffer_from_pixmap_reply(c, bp_cookie, NULL); 1136 if (!bp_reply) 1137 goto no_image; 1138 fds = xcb_dri3_buffer_from_pixmap_reply_fds(c, bp_reply); 1139 1140 stride = bp_reply->stride; 1141 offset = 0; 1142 1143 /* createImageFromFds creates a wrapper __DRIimage structure which 1144 * can deal with multiple planes for things like Yuv images. So, once 1145 * we've gotten the planar wrapper, pull the single plane out of it and 1146 * discard the wrapper. 1147 */ 1148 image_planar = (*psc->image->createImageFromFds) (psc->driScreen, 1149 bp_reply->width, 1150 bp_reply->height, 1151 image_format_to_fourcc(format), 1152 fds, 1, 1153 &stride, &offset, buffer); 1154 close(fds[0]); 1155 if (!image_planar) 1156 goto no_image; 1157 1158 buffer->image = (*psc->image->fromPlanar)(image_planar, 0, buffer); 1159 1160 (*psc->image->destroyImage)(image_planar); 1161 1162 if (!buffer->image) 1163 goto no_image; 1164 1165 buffer->pixmap = pixmap; 1166 buffer->own_pixmap = false; 1167 buffer->width = bp_reply->width; 1168 buffer->height = bp_reply->height; 1169 buffer->buffer_type = buffer_type; 1170 buffer->shm_fence = shm_fence; 1171 buffer->sync_fence = sync_fence; 1172 1173 pdraw->buffers[buf_id] = buffer; 1174 return buffer; 1175 1176no_image: 1177 xcb_sync_destroy_fence(c, sync_fence); 1178 xshmfence_unmap_shm(shm_fence); 1179no_fence: 1180 free(buffer); 1181no_buffer: 1182 return NULL; 1183} 1184 1185/** dri3_find_back 1186 * 1187 * Find an idle back buffer. If there isn't one, then 1188 * wait for a present idle notify event from the X server 1189 */ 1190static int 1191dri3_find_back(xcb_connection_t *c, struct dri3_drawable *priv) 1192{ 1193 int b; 1194 xcb_generic_event_t *ev; 1195 xcb_present_generic_event_t *ge; 1196 1197 for (;;) { 1198 for (b = 0; b < priv->num_back; b++) { 1199 int id = DRI3_BACK_ID((b + priv->cur_back) % priv->num_back); 1200 struct dri3_buffer *buffer = priv->buffers[id]; 1201 1202 if (!buffer || !buffer->busy) { 1203 priv->cur_back = id; 1204 return id; 1205 } 1206 } 1207 xcb_flush(c); 1208 ev = xcb_wait_for_special_event(c, priv->special_event); 1209 if (!ev) 1210 return -1; 1211 ge = (void *) ev; 1212 dri3_handle_present_event(priv, ge); 1213 } 1214} 1215 1216/** dri3_get_buffer 1217 * 1218 * Find a front or back buffer, allocating new ones as necessary 1219 */ 1220static struct dri3_buffer * 1221dri3_get_buffer(__DRIdrawable *driDrawable, 1222 unsigned int format, 1223 enum dri3_buffer_type buffer_type, 1224 void *loaderPrivate) 1225{ 1226 struct dri3_context *pcp = (struct dri3_context *) __glXGetCurrentContext(); 1227 struct dri3_drawable *priv = loaderPrivate; 1228 struct dri3_screen *psc = (struct dri3_screen *) priv->base.psc; 1229 xcb_connection_t *c = XGetXCBConnection(priv->base.psc->dpy); 1230 struct dri3_buffer *buffer; 1231 int buf_id; 1232 1233 if (buffer_type == dri3_buffer_back) { 1234 buf_id = dri3_find_back(c, priv); 1235 1236 if (buf_id < 0) 1237 return NULL; 1238 } else { 1239 buf_id = DRI3_FRONT_ID; 1240 } 1241 1242 buffer = priv->buffers[buf_id]; 1243 1244 /* Allocate a new buffer if there isn't an old one, or if that 1245 * old one is the wrong size 1246 */ 1247 if (!buffer || buffer->width != priv->width || buffer->height != priv->height) { 1248 struct dri3_buffer *new_buffer; 1249 1250 /* Allocate the new buffers 1251 */ 1252 new_buffer = dri3_alloc_render_buffer(priv->base.psc, 1253 priv->base.xDrawable, 1254 format, priv->width, priv->height, priv->depth); 1255 if (!new_buffer) 1256 return NULL; 1257 1258 /* When resizing, copy the contents of the old buffer, waiting for that 1259 * copy to complete using our fences before proceeding 1260 */ 1261 switch (buffer_type) { 1262 case dri3_buffer_back: 1263 if (buffer) { 1264 if (!buffer->linear_buffer) { 1265 dri3_fence_reset(c, new_buffer); 1266 dri3_fence_await(c, buffer); 1267 dri3_copy_area(c, 1268 buffer->pixmap, 1269 new_buffer->pixmap, 1270 dri3_drawable_gc(priv), 1271 0, 0, 0, 0, priv->width, priv->height); 1272 dri3_fence_trigger(c, new_buffer); 1273 } else if ((&pcp->base != &dummyContext) && pcp->base.psc == &psc->base) { 1274 psc->image->blitImage(pcp->driContext, 1275 new_buffer->image, 1276 buffer->image, 1277 0, 0, priv->width, 1278 priv->height, 1279 0, 0, priv->width, 1280 priv->height, 0); 1281 } 1282 dri3_free_render_buffer(priv, buffer); 1283 } 1284 break; 1285 case dri3_buffer_front: 1286 dri3_fence_reset(c, new_buffer); 1287 dri3_copy_area(c, 1288 priv->base.xDrawable, 1289 new_buffer->pixmap, 1290 dri3_drawable_gc(priv), 1291 0, 0, 0, 0, priv->width, priv->height); 1292 dri3_fence_trigger(c, new_buffer); 1293 1294 if (new_buffer->linear_buffer && (&pcp->base != &dummyContext) && pcp->base.psc == &psc->base) { 1295 dri3_fence_await(c, new_buffer); 1296 psc->image->blitImage(pcp->driContext, 1297 new_buffer->image, 1298 new_buffer->linear_buffer, 1299 0, 0, priv->width, 1300 priv->height, 1301 0, 0, priv->width, 1302 priv->height, 0); 1303 } 1304 break; 1305 } 1306 buffer = new_buffer; 1307 buffer->buffer_type = buffer_type; 1308 priv->buffers[buf_id] = buffer; 1309 } 1310 dri3_fence_await(c, buffer); 1311 1312 /* Return the requested buffer */ 1313 return buffer; 1314} 1315 1316/** dri3_free_buffers 1317 * 1318 * Free the front bufffer or all of the back buffers. Used 1319 * when the application changes which buffers it needs 1320 */ 1321static void 1322dri3_free_buffers(__DRIdrawable *driDrawable, 1323 enum dri3_buffer_type buffer_type, 1324 void *loaderPrivate) 1325{ 1326 struct dri3_drawable *priv = loaderPrivate; 1327 struct dri3_buffer *buffer; 1328 int first_id; 1329 int n_id; 1330 int buf_id; 1331 1332 switch (buffer_type) { 1333 case dri3_buffer_back: 1334 first_id = DRI3_BACK_ID(0); 1335 n_id = DRI3_MAX_BACK; 1336 break; 1337 case dri3_buffer_front: 1338 first_id = DRI3_FRONT_ID; 1339 n_id = 1; 1340 } 1341 1342 for (buf_id = first_id; buf_id < first_id + n_id; buf_id++) { 1343 buffer = priv->buffers[buf_id]; 1344 if (buffer) { 1345 dri3_free_render_buffer(priv, buffer); 1346 priv->buffers[buf_id] = NULL; 1347 } 1348 } 1349} 1350 1351/** dri3_get_buffers 1352 * 1353 * The published buffer allocation API. 1354 * Returns all of the necessary buffers, allocating 1355 * as needed. 1356 */ 1357static int 1358dri3_get_buffers(__DRIdrawable *driDrawable, 1359 unsigned int format, 1360 uint32_t *stamp, 1361 void *loaderPrivate, 1362 uint32_t buffer_mask, 1363 struct __DRIimageList *buffers) 1364{ 1365 struct dri3_drawable *priv = loaderPrivate; 1366 struct dri3_screen *psc = (struct dri3_screen *) priv->base.psc; 1367 struct dri3_buffer *front, *back; 1368 1369 buffers->image_mask = 0; 1370 buffers->front = NULL; 1371 buffers->back = NULL; 1372 1373 front = NULL; 1374 back = NULL; 1375 1376 if (!dri3_update_drawable(driDrawable, loaderPrivate)) 1377 return false; 1378 1379 /* pixmaps always have front buffers */ 1380 if (priv->is_pixmap) 1381 buffer_mask |= __DRI_IMAGE_BUFFER_FRONT; 1382 1383 if (buffer_mask & __DRI_IMAGE_BUFFER_FRONT) { 1384 /* All pixmaps are owned by the server gpu. 1385 * When we use a different gpu, we can't use the pixmap 1386 * as buffer since it is potentially tiled a way 1387 * our device can't understand. In this case, use 1388 * a fake front buffer. Hopefully the pixmap 1389 * content will get synced with the fake front 1390 * buffer. 1391 */ 1392 if (priv->is_pixmap && !psc->is_different_gpu) 1393 front = dri3_get_pixmap_buffer(driDrawable, 1394 format, 1395 dri3_buffer_front, 1396 loaderPrivate); 1397 else 1398 front = dri3_get_buffer(driDrawable, 1399 format, 1400 dri3_buffer_front, 1401 loaderPrivate); 1402 1403 if (!front) 1404 return false; 1405 } else { 1406 dri3_free_buffers(driDrawable, dri3_buffer_front, loaderPrivate); 1407 priv->have_fake_front = 0; 1408 } 1409 1410 if (buffer_mask & __DRI_IMAGE_BUFFER_BACK) { 1411 back = dri3_get_buffer(driDrawable, 1412 format, 1413 dri3_buffer_back, 1414 loaderPrivate); 1415 if (!back) 1416 return false; 1417 priv->have_back = 1; 1418 } else { 1419 dri3_free_buffers(driDrawable, dri3_buffer_back, loaderPrivate); 1420 priv->have_back = 0; 1421 } 1422 1423 if (front) { 1424 buffers->image_mask |= __DRI_IMAGE_BUFFER_FRONT; 1425 buffers->front = front->image; 1426 priv->have_fake_front = psc->is_different_gpu || !priv->is_pixmap; 1427 } 1428 1429 if (back) { 1430 buffers->image_mask |= __DRI_IMAGE_BUFFER_BACK; 1431 buffers->back = back->image; 1432 } 1433 1434 priv->stamp = stamp; 1435 1436 return true; 1437} 1438 1439/* The image loader extension record for DRI3 1440 */ 1441static const __DRIimageLoaderExtension imageLoaderExtension = { 1442 .base = { __DRI_IMAGE_LOADER, 1 }, 1443 1444 .getBuffers = dri3_get_buffers, 1445 .flushFrontBuffer = dri3_flush_front_buffer, 1446}; 1447 1448const __DRIuseInvalidateExtension dri3UseInvalidate = { 1449 .base = { __DRI_USE_INVALIDATE, 1 } 1450}; 1451 1452static const __DRIextension *loader_extensions[] = { 1453 &imageLoaderExtension.base, 1454 &systemTimeExtension.base, 1455 &dri3UseInvalidate.base, 1456 NULL 1457}; 1458 1459/** dri3_swap_buffers 1460 * 1461 * Make the current back buffer visible using the present extension 1462 */ 1463static int64_t 1464dri3_swap_buffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor, 1465 int64_t remainder, Bool flush) 1466{ 1467 struct dri3_context *pcp = (struct dri3_context *) __glXGetCurrentContext(); 1468 struct dri3_drawable *priv = (struct dri3_drawable *) pdraw; 1469 struct dri3_screen *psc = (struct dri3_screen *) priv->base.psc; 1470 Display *dpy = priv->base.psc->dpy; 1471 xcb_connection_t *c = XGetXCBConnection(dpy); 1472 struct dri3_buffer *back; 1473 int64_t ret = 0; 1474 1475 unsigned flags = __DRI2_FLUSH_DRAWABLE; 1476 if (flush) 1477 flags |= __DRI2_FLUSH_CONTEXT; 1478 dri3_flush(psc, priv, flags, __DRI2_THROTTLE_SWAPBUFFER); 1479 1480 back = priv->buffers[DRI3_BACK_ID(priv->cur_back)]; 1481 if (psc->is_different_gpu && back) { 1482 /* Update the linear buffer before presenting the pixmap */ 1483 psc->image->blitImage(pcp->driContext, 1484 back->linear_buffer, 1485 back->image, 1486 0, 0, back->width, 1487 back->height, 1488 0, 0, back->width, 1489 back->height, __BLIT_FLAG_FLUSH); 1490 /* Update the fake front */ 1491 if (priv->have_fake_front) 1492 psc->image->blitImage(pcp->driContext, 1493 priv->buffers[DRI3_FRONT_ID]->image, 1494 back->image, 1495 0, 0, priv->width, 1496 priv->height, 1497 0, 0, priv->width, 1498 priv->height, __BLIT_FLAG_FLUSH); 1499 } 1500 1501 dri3_flush_present_events(priv); 1502 1503 if (back && !priv->is_pixmap) { 1504 dri3_fence_reset(c, back); 1505 1506 /* Compute when we want the frame shown by taking the last known successful 1507 * MSC and adding in a swap interval for each outstanding swap request 1508 */ 1509 ++priv->send_sbc; 1510 if (target_msc == 0) 1511 target_msc = priv->msc + priv->swap_interval * (priv->send_sbc - priv->recv_sbc); 1512 1513 back->busy = 1; 1514 back->last_swap = priv->send_sbc; 1515 xcb_present_pixmap(c, 1516 priv->base.xDrawable, 1517 back->pixmap, 1518 (uint32_t) priv->send_sbc, 1519 0, /* valid */ 1520 0, /* update */ 1521 0, /* x_off */ 1522 0, /* y_off */ 1523 None, /* target_crtc */ 1524 None, 1525 back->sync_fence, 1526 XCB_PRESENT_OPTION_NONE, 1527 target_msc, 1528 divisor, 1529 remainder, 0, NULL); 1530 ret = (int64_t) priv->send_sbc; 1531 1532 /* If there's a fake front, then copy the source back buffer 1533 * to the fake front to keep it up to date. This needs 1534 * to reset the fence and make future users block until 1535 * the X server is done copying the bits 1536 */ 1537 if (priv->have_fake_front && !psc->is_different_gpu) { 1538 dri3_fence_reset(c, priv->buffers[DRI3_FRONT_ID]); 1539 dri3_copy_area(c, 1540 back->pixmap, 1541 priv->buffers[DRI3_FRONT_ID]->pixmap, 1542 dri3_drawable_gc(priv), 1543 0, 0, 0, 0, priv->width, priv->height); 1544 dri3_fence_trigger(c, priv->buffers[DRI3_FRONT_ID]); 1545 } 1546 xcb_flush(c); 1547 if (priv->stamp) 1548 ++(*priv->stamp); 1549 } 1550 1551 (*psc->f->invalidate)(priv->driDrawable); 1552 1553 return ret; 1554} 1555 1556static int 1557dri3_get_buffer_age(__GLXDRIdrawable *pdraw) 1558{ 1559 xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy); 1560 struct dri3_drawable *priv = (struct dri3_drawable *) pdraw; 1561 int back_id = DRI3_BACK_ID(dri3_find_back(c, priv)); 1562 1563 if (back_id < 0 || !priv->buffers[back_id]) 1564 return 0; 1565 1566 if (priv->buffers[back_id]->last_swap != 0) 1567 return priv->send_sbc - priv->buffers[back_id]->last_swap + 1; 1568 else 1569 return 0; 1570} 1571 1572/** dri3_open 1573 * 1574 * Wrapper around xcb_dri3_open 1575 */ 1576static int 1577dri3_open(Display *dpy, 1578 Window root, 1579 CARD32 provider) 1580{ 1581 xcb_dri3_open_cookie_t cookie; 1582 xcb_dri3_open_reply_t *reply; 1583 xcb_connection_t *c = XGetXCBConnection(dpy); 1584 int fd; 1585 1586 cookie = xcb_dri3_open(c, 1587 root, 1588 provider); 1589 1590 reply = xcb_dri3_open_reply(c, cookie, NULL); 1591 if (!reply) 1592 return -1; 1593 1594 if (reply->nfd != 1) { 1595 free(reply); 1596 return -1; 1597 } 1598 1599 fd = xcb_dri3_open_reply_fds(c, reply)[0]; 1600 fcntl(fd, F_SETFD, FD_CLOEXEC); 1601 1602 return fd; 1603} 1604 1605 1606/** dri3_destroy_screen 1607 */ 1608static void 1609dri3_destroy_screen(struct glx_screen *base) 1610{ 1611 struct dri3_screen *psc = (struct dri3_screen *) base; 1612 1613 /* Free the direct rendering per screen data */ 1614 (*psc->core->destroyScreen) (psc->driScreen); 1615 driDestroyConfigs(psc->driver_configs); 1616 close(psc->fd); 1617 free(psc); 1618} 1619 1620/** dri3_set_swap_interval 1621 * 1622 * Record the application swap interval specification, 1623 */ 1624static int 1625dri3_set_swap_interval(__GLXDRIdrawable *pdraw, int interval) 1626{ 1627 struct dri3_drawable *priv = (struct dri3_drawable *) pdraw; 1628 GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1; 1629 struct dri3_screen *psc = (struct dri3_screen *) priv->base.psc; 1630 1631 if (psc->config) 1632 psc->config->configQueryi(psc->driScreen, 1633 "vblank_mode", &vblank_mode); 1634 1635 switch (vblank_mode) { 1636 case DRI_CONF_VBLANK_NEVER: 1637 if (interval != 0) 1638 return GLX_BAD_VALUE; 1639 break; 1640 case DRI_CONF_VBLANK_ALWAYS_SYNC: 1641 if (interval <= 0) 1642 return GLX_BAD_VALUE; 1643 break; 1644 default: 1645 break; 1646 } 1647 1648 priv->swap_interval = interval; 1649 dri3_update_num_back(priv); 1650 1651 return 0; 1652} 1653 1654/** dri3_get_swap_interval 1655 * 1656 * Return the stored swap interval 1657 */ 1658static int 1659dri3_get_swap_interval(__GLXDRIdrawable *pdraw) 1660{ 1661 struct dri3_drawable *priv = (struct dri3_drawable *) pdraw; 1662 1663 return priv->swap_interval; 1664} 1665 1666static void 1667dri3_bind_tex_image(Display * dpy, 1668 GLXDrawable drawable, 1669 int buffer, const int *attrib_list) 1670{ 1671 struct glx_context *gc = __glXGetCurrentContext(); 1672 struct dri3_context *pcp = (struct dri3_context *) gc; 1673 __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable); 1674 struct dri3_drawable *pdraw = (struct dri3_drawable *) base; 1675 struct dri3_screen *psc; 1676 1677 if (pdraw != NULL) { 1678 psc = (struct dri3_screen *) base->psc; 1679 1680 (*psc->f->invalidate)(pdraw->driDrawable); 1681 1682 XSync(dpy, false); 1683 1684 (*psc->texBuffer->setTexBuffer2) (pcp->driContext, 1685 pdraw->base.textureTarget, 1686 pdraw->base.textureFormat, 1687 pdraw->driDrawable); 1688 } 1689} 1690 1691static void 1692dri3_release_tex_image(Display * dpy, GLXDrawable drawable, int buffer) 1693{ 1694 struct glx_context *gc = __glXGetCurrentContext(); 1695 struct dri3_context *pcp = (struct dri3_context *) gc; 1696 __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable); 1697 struct dri3_drawable *pdraw = (struct dri3_drawable *) base; 1698 struct dri3_screen *psc; 1699 1700 if (pdraw != NULL) { 1701 psc = (struct dri3_screen *) base->psc; 1702 1703 if (psc->texBuffer->base.version >= 3 && 1704 psc->texBuffer->releaseTexBuffer != NULL) 1705 (*psc->texBuffer->releaseTexBuffer) (pcp->driContext, 1706 pdraw->base.textureTarget, 1707 pdraw->driDrawable); 1708 } 1709} 1710 1711static const struct glx_context_vtable dri3_context_vtable = { 1712 .destroy = dri3_destroy_context, 1713 .bind = dri3_bind_context, 1714 .unbind = dri3_unbind_context, 1715 .wait_gl = dri3_wait_gl, 1716 .wait_x = dri3_wait_x, 1717 .use_x_font = DRI_glXUseXFont, 1718 .bind_tex_image = dri3_bind_tex_image, 1719 .release_tex_image = dri3_release_tex_image, 1720 .get_proc_address = NULL, 1721}; 1722 1723/** dri3_bind_extensions 1724 * 1725 * Enable all of the extensions supported on DRI3 1726 */ 1727static void 1728dri3_bind_extensions(struct dri3_screen *psc, struct glx_display * priv, 1729 const char *driverName) 1730{ 1731 const __DRIextension **extensions; 1732 unsigned mask; 1733 int i; 1734 1735 extensions = psc->core->getExtensions(psc->driScreen); 1736 1737 __glXEnableDirectExtension(&psc->base, "GLX_SGI_video_sync"); 1738 __glXEnableDirectExtension(&psc->base, "GLX_SGI_swap_control"); 1739 __glXEnableDirectExtension(&psc->base, "GLX_MESA_swap_control"); 1740 __glXEnableDirectExtension(&psc->base, "GLX_SGI_make_current_read"); 1741 __glXEnableDirectExtension(&psc->base, "GLX_INTEL_swap_event"); 1742 1743 mask = psc->image_driver->getAPIMask(psc->driScreen); 1744 1745 __glXEnableDirectExtension(&psc->base, "GLX_ARB_create_context"); 1746 __glXEnableDirectExtension(&psc->base, "GLX_ARB_create_context_profile"); 1747 1748 if ((mask & (1 << __DRI_API_GLES2)) != 0) 1749 __glXEnableDirectExtension(&psc->base, 1750 "GLX_EXT_create_context_es2_profile"); 1751 1752 for (i = 0; extensions[i]; i++) { 1753 /* when on a different gpu than the server, the server pixmaps 1754 * can have a tiling mode we can't read. Thus we can't create 1755 * a texture from them. 1756 */ 1757 if (!psc->is_different_gpu && 1758 (strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0)) { 1759 psc->texBuffer = (__DRItexBufferExtension *) extensions[i]; 1760 __glXEnableDirectExtension(&psc->base, "GLX_EXT_texture_from_pixmap"); 1761 } 1762 1763 if ((strcmp(extensions[i]->name, __DRI2_FLUSH) == 0)) { 1764 psc->f = (__DRI2flushExtension *) extensions[i]; 1765 /* internal driver extension, no GL extension exposed */ 1766 } 1767 1768 if (strcmp(extensions[i]->name, __DRI_IMAGE) == 0) 1769 psc->image = (__DRIimageExtension *) extensions[i]; 1770 1771 if ((strcmp(extensions[i]->name, __DRI2_CONFIG_QUERY) == 0)) 1772 psc->config = (__DRI2configQueryExtension *) extensions[i]; 1773 1774 if (strcmp(extensions[i]->name, __DRI2_ROBUSTNESS) == 0) 1775 __glXEnableDirectExtension(&psc->base, 1776 "GLX_ARB_create_context_robustness"); 1777 1778 if (strcmp(extensions[i]->name, __DRI2_RENDERER_QUERY) == 0) { 1779 psc->rendererQuery = (__DRI2rendererQueryExtension *) extensions[i]; 1780 __glXEnableDirectExtension(&psc->base, "GLX_MESA_query_renderer"); 1781 } 1782 } 1783} 1784 1785static const struct glx_screen_vtable dri3_screen_vtable = { 1786 .create_context = dri3_create_context, 1787 .create_context_attribs = dri3_create_context_attribs, 1788 .query_renderer_integer = dri3_query_renderer_integer, 1789 .query_renderer_string = dri3_query_renderer_string, 1790}; 1791 1792/** dri3_create_screen 1793 * 1794 * Initialize DRI3 on the specified screen. 1795 * 1796 * Opens the DRI device, locates the appropriate DRI driver 1797 * and loads that. 1798 * 1799 * Checks to see if the driver supports the necessary extensions 1800 * 1801 * Initializes the driver for the screen and sets up our structures 1802 */ 1803 1804static struct glx_screen * 1805dri3_create_screen(int screen, struct glx_display * priv) 1806{ 1807 xcb_connection_t *c = XGetXCBConnection(priv->dpy); 1808 const __DRIconfig **driver_configs; 1809 const __DRIextension **extensions; 1810 const struct dri3_display *const pdp = (struct dri3_display *) 1811 priv->dri3Display; 1812 struct dri3_screen *psc; 1813 __GLXDRIscreen *psp; 1814 struct glx_config *configs = NULL, *visuals = NULL; 1815 char *driverName, *deviceName; 1816 int i; 1817 1818 psc = calloc(1, sizeof *psc); 1819 if (psc == NULL) 1820 return NULL; 1821 1822 psc->fd = -1; 1823 1824 if (!glx_screen_init(&psc->base, screen, priv)) { 1825 free(psc); 1826 return NULL; 1827 } 1828 1829 psc->fd = dri3_open(priv->dpy, RootWindow(priv->dpy, screen), None); 1830 if (psc->fd < 0) { 1831 int conn_error = xcb_connection_has_error(c); 1832 1833 glx_screen_cleanup(&psc->base); 1834 free(psc); 1835 InfoMessageF("screen %d does not appear to be DRI3 capable\n", screen); 1836 1837 if (conn_error) 1838 ErrorMessageF("Connection closed during DRI3 initialization failure"); 1839 1840 return NULL; 1841 } 1842 1843 psc->fd = loader_get_user_preferred_fd(psc->fd, &psc->is_different_gpu); 1844 deviceName = NULL; 1845 1846 driverName = loader_get_driver_for_fd(psc->fd, 0); 1847 if (!driverName) { 1848 ErrorMessageF("No driver found\n"); 1849 goto handle_error; 1850 } 1851 1852 psc->driver = driOpenDriver(driverName); 1853 if (psc->driver == NULL) { 1854 ErrorMessageF("driver pointer missing\n"); 1855 goto handle_error; 1856 } 1857 1858 extensions = driGetDriverExtensions(psc->driver, driverName); 1859 if (extensions == NULL) 1860 goto handle_error; 1861 1862 for (i = 0; extensions[i]; i++) { 1863 if (strcmp(extensions[i]->name, __DRI_CORE) == 0) 1864 psc->core = (__DRIcoreExtension *) extensions[i]; 1865 if (strcmp(extensions[i]->name, __DRI_IMAGE_DRIVER) == 0) 1866 psc->image_driver = (__DRIimageDriverExtension *) extensions[i]; 1867 } 1868 1869 1870 if (psc->core == NULL) { 1871 ErrorMessageF("core dri driver extension not found\n"); 1872 goto handle_error; 1873 } 1874 1875 if (psc->image_driver == NULL) { 1876 ErrorMessageF("image driver extension not found\n"); 1877 goto handle_error; 1878 } 1879 1880 psc->driScreen = 1881 psc->image_driver->createNewScreen2(screen, psc->fd, 1882 pdp->loader_extensions, 1883 extensions, 1884 &driver_configs, psc); 1885 1886 if (psc->driScreen == NULL) { 1887 ErrorMessageF("failed to create dri screen\n"); 1888 goto handle_error; 1889 } 1890 1891 dri3_bind_extensions(psc, priv, driverName); 1892 1893 if (!psc->image || psc->image->base.version < 7 || !psc->image->createImageFromFds) { 1894 ErrorMessageF("Version 7 or imageFromFds image extension not found\n"); 1895 goto handle_error; 1896 } 1897 1898 if (!psc->f || psc->f->base.version < 4) { 1899 ErrorMessageF("Version 4 or later of flush extension not found\n"); 1900 goto handle_error; 1901 } 1902 1903 if (psc->is_different_gpu && psc->image->base.version < 9) { 1904 ErrorMessageF("Different GPU, but image extension version 9 or later not found\n"); 1905 goto handle_error; 1906 } 1907 1908 if (!psc->is_different_gpu && ( 1909 !psc->texBuffer || psc->texBuffer->base.version < 2 || 1910 !psc->texBuffer->setTexBuffer2 1911 )) { 1912 ErrorMessageF("Version 2 or later of texBuffer extension not found\n"); 1913 goto handle_error; 1914 } 1915 1916 configs = driConvertConfigs(psc->core, psc->base.configs, driver_configs); 1917 visuals = driConvertConfigs(psc->core, psc->base.visuals, driver_configs); 1918 1919 if (!configs || !visuals) { 1920 ErrorMessageF("No matching fbConfigs or visuals found\n"); 1921 goto handle_error; 1922 } 1923 1924 glx_config_destroy_list(psc->base.configs); 1925 psc->base.configs = configs; 1926 glx_config_destroy_list(psc->base.visuals); 1927 psc->base.visuals = visuals; 1928 1929 psc->driver_configs = driver_configs; 1930 1931 psc->base.vtable = &dri3_screen_vtable; 1932 psp = &psc->vtable; 1933 psc->base.driScreen = psp; 1934 psp->destroyScreen = dri3_destroy_screen; 1935 psp->createDrawable = dri3_create_drawable; 1936 psp->swapBuffers = dri3_swap_buffers; 1937 1938 psp->getDrawableMSC = dri3_drawable_get_msc; 1939 psp->waitForMSC = dri3_wait_for_msc; 1940 psp->waitForSBC = dri3_wait_for_sbc; 1941 psp->setSwapInterval = dri3_set_swap_interval; 1942 psp->getSwapInterval = dri3_get_swap_interval; 1943 __glXEnableDirectExtension(&psc->base, "GLX_OML_sync_control"); 1944 1945 psp->copySubBuffer = dri3_copy_sub_buffer; 1946 __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer"); 1947 1948 psp->getBufferAge = dri3_get_buffer_age; 1949 __glXEnableDirectExtension(&psc->base, "GLX_EXT_buffer_age"); 1950 1951 free(driverName); 1952 free(deviceName); 1953 1954 return &psc->base; 1955 1956handle_error: 1957 CriticalErrorMessageF("failed to load driver: %s\n", driverName); 1958 1959 if (configs) 1960 glx_config_destroy_list(configs); 1961 if (visuals) 1962 glx_config_destroy_list(visuals); 1963 if (psc->driScreen) 1964 psc->core->destroyScreen(psc->driScreen); 1965 psc->driScreen = NULL; 1966 if (psc->fd >= 0) 1967 close(psc->fd); 1968 if (psc->driver) 1969 dlclose(psc->driver); 1970 1971 free(driverName); 1972 free(deviceName); 1973 glx_screen_cleanup(&psc->base); 1974 free(psc); 1975 1976 return NULL; 1977} 1978 1979/** dri_destroy_display 1980 * 1981 * Called from __glXFreeDisplayPrivate. 1982 */ 1983static void 1984dri3_destroy_display(__GLXDRIdisplay * dpy) 1985{ 1986 free(dpy); 1987} 1988 1989/** dri3_create_display 1990 * 1991 * Allocate, initialize and return a __DRIdisplayPrivate object. 1992 * This is called from __glXInitialize() when we are given a new 1993 * display pointer. This is public to that function, but hidden from 1994 * outside of libGL. 1995 */ 1996_X_HIDDEN __GLXDRIdisplay * 1997dri3_create_display(Display * dpy) 1998{ 1999 struct dri3_display *pdp; 2000 xcb_connection_t *c = XGetXCBConnection(dpy); 2001 xcb_dri3_query_version_cookie_t dri3_cookie; 2002 xcb_dri3_query_version_reply_t *dri3_reply; 2003 xcb_present_query_version_cookie_t present_cookie; 2004 xcb_present_query_version_reply_t *present_reply; 2005 xcb_generic_error_t *error; 2006 const xcb_query_extension_reply_t *extension; 2007 2008 xcb_prefetch_extension_data(c, &xcb_dri3_id); 2009 xcb_prefetch_extension_data(c, &xcb_present_id); 2010 2011 extension = xcb_get_extension_data(c, &xcb_dri3_id); 2012 if (!(extension && extension->present)) 2013 return NULL; 2014 2015 extension = xcb_get_extension_data(c, &xcb_present_id); 2016 if (!(extension && extension->present)) 2017 return NULL; 2018 2019 dri3_cookie = xcb_dri3_query_version(c, 2020 XCB_DRI3_MAJOR_VERSION, 2021 XCB_DRI3_MINOR_VERSION); 2022 2023 2024 present_cookie = xcb_present_query_version(c, 2025 XCB_PRESENT_MAJOR_VERSION, 2026 XCB_PRESENT_MINOR_VERSION); 2027 2028 pdp = malloc(sizeof *pdp); 2029 if (pdp == NULL) 2030 return NULL; 2031 2032 dri3_reply = xcb_dri3_query_version_reply(c, dri3_cookie, &error); 2033 if (!dri3_reply) { 2034 free(error); 2035 goto no_extension; 2036 } 2037 2038 pdp->dri3Major = dri3_reply->major_version; 2039 pdp->dri3Minor = dri3_reply->minor_version; 2040 free(dri3_reply); 2041 2042 present_reply = xcb_present_query_version_reply(c, present_cookie, &error); 2043 if (!present_reply) { 2044 free(error); 2045 goto no_extension; 2046 } 2047 pdp->presentMajor = present_reply->major_version; 2048 pdp->presentMinor = present_reply->minor_version; 2049 free(present_reply); 2050 2051 pdp->base.destroyDisplay = dri3_destroy_display; 2052 pdp->base.createScreen = dri3_create_screen; 2053 2054 loader_set_logger(dri_message); 2055 2056 pdp->loader_extensions = loader_extensions; 2057 2058 return &pdp->base; 2059no_extension: 2060 free(pdp); 2061 return NULL; 2062} 2063 2064#endif /* GLX_DIRECT_RENDERING */ 2065