dri3_glx.c revision 7ec681f3
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 struct dri3_drawable * 82loader_drawable_to_dri3_drawable(struct loader_dri3_drawable *draw) { 83 size_t offset = offsetof(struct dri3_drawable, loader_drawable); 84 if (!draw) 85 return NULL; 86 return (struct dri3_drawable *)(((void*) draw) - offset); 87} 88 89static void 90glx_dri3_set_drawable_size(struct loader_dri3_drawable *draw, 91 int width, int height) 92{ 93 /* Nothing to do */ 94} 95 96static bool 97glx_dri3_in_current_context(struct loader_dri3_drawable *draw) 98{ 99 struct dri3_drawable *priv = loader_drawable_to_dri3_drawable(draw); 100 101 if (!priv) 102 return false; 103 104 struct dri3_context *pcp = (struct dri3_context *) __glXGetCurrentContext(); 105 struct dri3_screen *psc = (struct dri3_screen *) priv->base.psc; 106 107 return (&pcp->base != &dummyContext) && pcp->base.psc == &psc->base; 108} 109 110static __DRIcontext * 111glx_dri3_get_dri_context(struct loader_dri3_drawable *draw) 112{ 113 struct glx_context *gc = __glXGetCurrentContext(); 114 struct dri3_context *dri3Ctx = (struct dri3_context *) gc; 115 116 return (gc != &dummyContext) ? dri3Ctx->driContext : NULL; 117} 118 119static __DRIscreen * 120glx_dri3_get_dri_screen(void) 121{ 122 struct glx_context *gc = __glXGetCurrentContext(); 123 struct dri3_context *pcp = (struct dri3_context *) gc; 124 struct dri3_screen *psc = (struct dri3_screen *) pcp->base.psc; 125 126 return (gc != &dummyContext && psc) ? psc->driScreen : NULL; 127} 128 129static void 130glx_dri3_flush_drawable(struct loader_dri3_drawable *draw, unsigned flags) 131{ 132 loader_dri3_flush(draw, flags, __DRI2_THROTTLE_SWAPBUFFER); 133} 134 135static void 136glx_dri3_show_fps(struct loader_dri3_drawable *draw, uint64_t current_ust) 137{ 138 struct dri3_drawable *priv = loader_drawable_to_dri3_drawable(draw); 139 const uint64_t interval = 140 ((struct dri3_screen *) priv->base.psc)->show_fps_interval; 141 142 if (!interval) 143 return; 144 145 priv->frames++; 146 147 /* DRI3+Present together uses microseconds for UST. */ 148 if (priv->previous_ust + interval * 1000000 <= current_ust) { 149 if (priv->previous_ust) { 150 fprintf(stderr, "libGL: FPS = %.2f\n", 151 ((uint64_t) priv->frames * 1000000) / 152 (double)(current_ust - priv->previous_ust)); 153 } 154 priv->frames = 0; 155 priv->previous_ust = current_ust; 156 } 157} 158 159static const struct loader_dri3_vtable glx_dri3_vtable = { 160 .set_drawable_size = glx_dri3_set_drawable_size, 161 .in_current_context = glx_dri3_in_current_context, 162 .get_dri_context = glx_dri3_get_dri_context, 163 .get_dri_screen = glx_dri3_get_dri_screen, 164 .flush_drawable = glx_dri3_flush_drawable, 165 .show_fps = glx_dri3_show_fps, 166}; 167 168 169static const struct glx_context_vtable dri3_context_vtable; 170 171static void 172dri3_destroy_context(struct glx_context *context) 173{ 174 struct dri3_context *pcp = (struct dri3_context *) context; 175 struct dri3_screen *psc = (struct dri3_screen *) context->psc; 176 177 driReleaseDrawables(&pcp->base); 178 179 free((char *) context->extensions); 180 181 (*psc->core->destroyContext) (pcp->driContext); 182 183 free(pcp); 184} 185 186static Bool 187dri3_bind_context(struct glx_context *context, struct glx_context *old, 188 GLXDrawable draw, GLXDrawable read) 189{ 190 struct dri3_context *pcp = (struct dri3_context *) context; 191 struct dri3_screen *psc = (struct dri3_screen *) pcp->base.psc; 192 struct dri3_drawable *pdraw, *pread; 193 __DRIdrawable *dri_draw = NULL, *dri_read = NULL; 194 195 pdraw = (struct dri3_drawable *) driFetchDrawable(context, draw); 196 pread = (struct dri3_drawable *) driFetchDrawable(context, read); 197 198 driReleaseDrawables(&pcp->base); 199 200 if (pdraw) 201 dri_draw = pdraw->loader_drawable.dri_drawable; 202 else if (draw != None) 203 return GLXBadDrawable; 204 205 if (pread) 206 dri_read = pread->loader_drawable.dri_drawable; 207 else if (read != None) 208 return GLXBadDrawable; 209 210 if (!(*psc->core->bindContext) (pcp->driContext, dri_draw, dri_read)) 211 return GLXBadContext; 212 213 if (dri_draw) 214 psc->f->invalidate(dri_draw); 215 if (dri_read && dri_read != dri_draw) 216 psc->f->invalidate(dri_read); 217 218 return Success; 219} 220 221static void 222dri3_unbind_context(struct glx_context *context, struct glx_context *new) 223{ 224 struct dri3_context *pcp = (struct dri3_context *) context; 225 struct dri3_screen *psc = (struct dri3_screen *) pcp->base.psc; 226 227 (*psc->core->unbindContext) (pcp->driContext); 228} 229 230static struct glx_context * 231dri3_create_context_attribs(struct glx_screen *base, 232 struct glx_config *config_base, 233 struct glx_context *shareList, 234 unsigned num_attribs, 235 const uint32_t *attribs, 236 unsigned *error) 237{ 238 struct dri3_context *pcp = NULL; 239 struct dri3_context *pcp_shared = NULL; 240 struct dri3_screen *psc = (struct dri3_screen *) base; 241 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base; 242 __DRIcontext *shared = NULL; 243 244 struct dri_ctx_attribs dca; 245 uint32_t ctx_attribs[2 * 6]; 246 unsigned num_ctx_attribs = 0; 247 248 *error = dri_convert_glx_attribs(num_attribs, attribs, &dca); 249 if (*error != __DRI_CTX_ERROR_SUCCESS) 250 goto error_exit; 251 252 if (!dri2_check_no_error(dca.flags, shareList, dca.major_ver, error)) { 253 goto error_exit; 254 } 255 256 /* Check the renderType value */ 257 if (!validate_renderType_against_config(config_base, dca.render_type)) 258 goto error_exit; 259 260 if (shareList) { 261 /* We can't share with an indirect context */ 262 if (!shareList->isDirect) 263 return NULL; 264 265 pcp_shared = (struct dri3_context *) shareList; 266 shared = pcp_shared->driContext; 267 } 268 269 pcp = calloc(1, sizeof *pcp); 270 if (pcp == NULL) { 271 *error = __DRI_CTX_ERROR_NO_MEMORY; 272 goto error_exit; 273 } 274 275 if (!glx_context_init(&pcp->base, &psc->base, config_base)) 276 goto error_exit; 277 278 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MAJOR_VERSION; 279 ctx_attribs[num_ctx_attribs++] = dca.major_ver; 280 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MINOR_VERSION; 281 ctx_attribs[num_ctx_attribs++] = dca.minor_ver; 282 283 /* Only send a value when the non-default value is requested. By doing 284 * this we don't have to check the driver's DRI3 version before sending the 285 * default value. 286 */ 287 if (dca.reset != __DRI_CTX_RESET_NO_NOTIFICATION) { 288 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_RESET_STRATEGY; 289 ctx_attribs[num_ctx_attribs++] = dca.reset; 290 } 291 292 if (dca.release != __DRI_CTX_RELEASE_BEHAVIOR_FLUSH) { 293 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_RELEASE_BEHAVIOR; 294 ctx_attribs[num_ctx_attribs++] = dca.release; 295 } 296 297 if (dca.flags != 0) { 298 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_FLAGS; 299 300 /* The current __DRI_CTX_FLAG_* values are identical to the 301 * GLX_CONTEXT_*_BIT values. 302 */ 303 ctx_attribs[num_ctx_attribs++] = dca.flags; 304 305 if (dca.flags & __DRI_CTX_FLAG_NO_ERROR) 306 pcp->base.noError = GL_TRUE; 307 } 308 309 pcp->base.renderType = dca.render_type; 310 311 pcp->driContext = 312 (*psc->image_driver->createContextAttribs) (psc->driScreen, 313 dca.api, 314 config ? config->driConfig 315 : NULL, 316 shared, 317 num_ctx_attribs / 2, 318 ctx_attribs, 319 error, 320 pcp); 321 322 if (pcp->driContext == NULL) 323 goto error_exit; 324 325 pcp->base.vtable = base->context_vtable; 326 327 return &pcp->base; 328 329error_exit: 330 free(pcp); 331 332 return NULL; 333} 334 335static void 336dri3_destroy_drawable(__GLXDRIdrawable *base) 337{ 338 struct dri3_drawable *pdraw = (struct dri3_drawable *) base; 339 340 loader_dri3_drawable_fini(&pdraw->loader_drawable); 341 342 free(pdraw); 343} 344 345static __GLXDRIdrawable * 346dri3_create_drawable(struct glx_screen *base, XID xDrawable, 347 GLXDrawable drawable, struct glx_config *config_base) 348{ 349 struct dri3_drawable *pdraw; 350 struct dri3_screen *psc = (struct dri3_screen *) base; 351 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base; 352 bool has_multibuffer = false; 353#ifdef HAVE_DRI3_MODIFIERS 354 const struct dri3_display *const pdp = (struct dri3_display *) 355 base->display->dri3Display; 356#endif 357 358 pdraw = calloc(1, sizeof(*pdraw)); 359 if (!pdraw) 360 return NULL; 361 362 pdraw->base.destroyDrawable = dri3_destroy_drawable; 363 pdraw->base.xDrawable = xDrawable; 364 pdraw->base.drawable = drawable; 365 pdraw->base.psc = &psc->base; 366 367#ifdef HAVE_DRI3_MODIFIERS 368 if ((psc->image && psc->image->base.version >= 15) && 369 (pdp->dri3Major > 1 || (pdp->dri3Major == 1 && pdp->dri3Minor >= 2)) && 370 (pdp->presentMajor > 1 || 371 (pdp->presentMajor == 1 && pdp->presentMinor >= 2))) 372 has_multibuffer = true; 373#endif 374 375 (void) __glXInitialize(psc->base.dpy); 376 377 if (loader_dri3_drawable_init(XGetXCBConnection(base->dpy), 378 xDrawable, psc->driScreen, 379 psc->is_different_gpu, has_multibuffer, 380 psc->prefer_back_buffer_reuse, 381 config->driConfig, 382 &psc->loader_dri3_ext, &glx_dri3_vtable, 383 &pdraw->loader_drawable)) { 384 free(pdraw); 385 return NULL; 386 } 387 388 pdraw->loader_drawable.dri_screen_display_gpu = psc->driScreenDisplayGPU; 389 return &pdraw->base; 390} 391 392/** dri3_wait_for_msc 393 * 394 * Get the X server to send an event when the target msc/divisor/remainder is 395 * reached. 396 */ 397static int 398dri3_wait_for_msc(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor, 399 int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc) 400{ 401 struct dri3_drawable *priv = (struct dri3_drawable *) pdraw; 402 403 loader_dri3_wait_for_msc(&priv->loader_drawable, target_msc, divisor, 404 remainder, ust, msc, sbc); 405 406 return 1; 407} 408 409/** dri3_drawable_get_msc 410 * 411 * Return the current UST/MSC/SBC triplet by asking the server 412 * for an event 413 */ 414static int 415dri3_drawable_get_msc(struct glx_screen *psc, __GLXDRIdrawable *pdraw, 416 int64_t *ust, int64_t *msc, int64_t *sbc) 417{ 418 return dri3_wait_for_msc(pdraw, 0, 0, 0, ust, msc,sbc); 419} 420 421/** dri3_wait_for_sbc 422 * 423 * Wait for the completed swap buffer count to reach the specified 424 * target. Presumably the application knows that this will be reached with 425 * outstanding complete events, or we're going to be here awhile. 426 */ 427static int 428dri3_wait_for_sbc(__GLXDRIdrawable *pdraw, int64_t target_sbc, int64_t *ust, 429 int64_t *msc, int64_t *sbc) 430{ 431 struct dri3_drawable *priv = (struct dri3_drawable *) pdraw; 432 433 return loader_dri3_wait_for_sbc(&priv->loader_drawable, target_sbc, 434 ust, msc, sbc); 435} 436 437static void 438dri3_copy_sub_buffer(__GLXDRIdrawable *pdraw, int x, int y, 439 int width, int height, 440 Bool flush) 441{ 442 struct dri3_drawable *priv = (struct dri3_drawable *) pdraw; 443 444 loader_dri3_copy_sub_buffer(&priv->loader_drawable, x, y, 445 width, height, flush); 446} 447 448static void 449dri3_wait_x(struct glx_context *gc) 450{ 451 struct dri3_drawable *priv = (struct dri3_drawable *) 452 GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable); 453 454 if (priv) 455 loader_dri3_wait_x(&priv->loader_drawable); 456} 457 458static void 459dri3_wait_gl(struct glx_context *gc) 460{ 461 struct dri3_drawable *priv = (struct dri3_drawable *) 462 GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable); 463 464 if (priv) 465 loader_dri3_wait_gl(&priv->loader_drawable); 466} 467 468/** 469 * Called by the driver when it needs to update the real front buffer with the 470 * contents of its fake front buffer. 471 */ 472static void 473dri3_flush_front_buffer(__DRIdrawable *driDrawable, void *loaderPrivate) 474{ 475 struct loader_dri3_drawable *draw = loaderPrivate; 476 struct dri3_drawable *pdraw = loader_drawable_to_dri3_drawable(draw); 477 struct dri3_screen *psc; 478 479 if (!pdraw) 480 return; 481 482 if (!pdraw->base.psc) 483 return; 484 485 psc = (struct dri3_screen *) pdraw->base.psc; 486 487 (void) __glXInitialize(psc->base.dpy); 488 489 loader_dri3_flush(draw, __DRI2_FLUSH_DRAWABLE, __DRI2_THROTTLE_FLUSHFRONT); 490 491 psc->f->invalidate(driDrawable); 492 loader_dri3_wait_gl(draw); 493} 494 495/** 496 * Make sure all pending swapbuffers have been submitted to hardware 497 * 498 * \param driDrawable[in] Pointer to the dri drawable whose swaps we are 499 * flushing. 500 * \param loaderPrivate[in] Pointer to the corresponding struct 501 * loader_dri_drawable. 502 */ 503static void 504dri3_flush_swap_buffers(__DRIdrawable *driDrawable, void *loaderPrivate) 505{ 506 struct loader_dri3_drawable *draw = loaderPrivate; 507 struct dri3_drawable *pdraw = loader_drawable_to_dri3_drawable(draw); 508 struct dri3_screen *psc; 509 510 if (!pdraw) 511 return; 512 513 if (!pdraw->base.psc) 514 return; 515 516 psc = (struct dri3_screen *) pdraw->base.psc; 517 518 (void) __glXInitialize(psc->base.dpy); 519 loader_dri3_swapbuffer_barrier(draw); 520} 521 522static void 523dri_set_background_context(void *loaderPrivate) 524{ 525 struct dri3_context *pcp = (struct dri3_context *)loaderPrivate; 526 __glXSetCurrentContext(&pcp->base); 527} 528 529static GLboolean 530dri_is_thread_safe(void *loaderPrivate) 531{ 532 /* Unlike DRI2, DRI3 doesn't call GetBuffers/GetBuffersWithFormat 533 * during draw so we're safe here. 534 */ 535 return true; 536} 537 538/* The image loader extension record for DRI3 539 */ 540static const __DRIimageLoaderExtension imageLoaderExtension = { 541 .base = { __DRI_IMAGE_LOADER, 3 }, 542 543 .getBuffers = loader_dri3_get_buffers, 544 .flushFrontBuffer = dri3_flush_front_buffer, 545 .flushSwapBuffers = dri3_flush_swap_buffers, 546}; 547 548const __DRIuseInvalidateExtension dri3UseInvalidate = { 549 .base = { __DRI_USE_INVALIDATE, 1 } 550}; 551 552static const __DRIbackgroundCallableExtension driBackgroundCallable = { 553 .base = { __DRI_BACKGROUND_CALLABLE, 2 }, 554 555 .setBackgroundContext = dri_set_background_context, 556 .isThreadSafe = dri_is_thread_safe, 557}; 558 559static const __DRIextension *loader_extensions[] = { 560 &imageLoaderExtension.base, 561 &dri3UseInvalidate.base, 562 &driBackgroundCallable.base, 563 NULL 564}; 565 566/** dri3_swap_buffers 567 * 568 * Make the current back buffer visible using the present extension 569 */ 570static int64_t 571dri3_swap_buffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor, 572 int64_t remainder, Bool flush) 573{ 574 struct dri3_drawable *priv = (struct dri3_drawable *) pdraw; 575 unsigned flags = __DRI2_FLUSH_DRAWABLE; 576 577 if (flush) 578 flags |= __DRI2_FLUSH_CONTEXT; 579 580 return loader_dri3_swap_buffers_msc(&priv->loader_drawable, 581 target_msc, divisor, remainder, 582 flags, NULL, 0, false); 583} 584 585static int 586dri3_get_buffer_age(__GLXDRIdrawable *pdraw) 587{ 588 struct dri3_drawable *priv = (struct dri3_drawable *)pdraw; 589 590 return loader_dri3_query_buffer_age(&priv->loader_drawable); 591} 592 593/** dri3_destroy_screen 594 */ 595static void 596dri3_destroy_screen(struct glx_screen *base) 597{ 598 struct dri3_screen *psc = (struct dri3_screen *) base; 599 600 /* Free the direct rendering per screen data */ 601 if (psc->is_different_gpu) { 602 if (psc->driScreenDisplayGPU) { 603 loader_dri3_close_screen(psc->driScreenDisplayGPU); 604 (*psc->core->destroyScreen) (psc->driScreenDisplayGPU); 605 } 606 close(psc->fd_display_gpu); 607 } 608 loader_dri3_close_screen(psc->driScreen); 609 (*psc->core->destroyScreen) (psc->driScreen); 610 driDestroyConfigs(psc->driver_configs); 611 close(psc->fd); 612 free(psc); 613} 614 615/** dri3_set_swap_interval 616 * 617 * Record the application swap interval specification, 618 */ 619static int 620dri3_set_swap_interval(__GLXDRIdrawable *pdraw, int interval) 621{ 622 assert(pdraw != NULL); 623 624 struct dri3_drawable *priv = (struct dri3_drawable *) pdraw; 625 GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1; 626 struct dri3_screen *psc = (struct dri3_screen *) priv->base.psc; 627 628 if (psc->config) 629 psc->config->configQueryi(psc->driScreen, 630 "vblank_mode", &vblank_mode); 631 632 switch (vblank_mode) { 633 case DRI_CONF_VBLANK_NEVER: 634 if (interval != 0) 635 return GLX_BAD_VALUE; 636 break; 637 case DRI_CONF_VBLANK_ALWAYS_SYNC: 638 if (interval <= 0) 639 return GLX_BAD_VALUE; 640 break; 641 default: 642 break; 643 } 644 645 loader_dri3_set_swap_interval(&priv->loader_drawable, interval); 646 647 return 0; 648} 649 650/** dri3_get_swap_interval 651 * 652 * Return the stored swap interval 653 */ 654static int 655dri3_get_swap_interval(__GLXDRIdrawable *pdraw) 656{ 657 assert(pdraw != NULL); 658 659 struct dri3_drawable *priv = (struct dri3_drawable *) pdraw; 660 661 return priv->loader_drawable.swap_interval; 662} 663 664static void 665dri3_bind_tex_image(__GLXDRIdrawable *base, 666 int buffer, const int *attrib_list) 667{ 668 struct glx_context *gc = __glXGetCurrentContext(); 669 struct dri3_context *pcp = (struct dri3_context *) gc; 670 struct dri3_drawable *pdraw = (struct dri3_drawable *) base; 671 struct dri3_screen *psc; 672 673 if (pdraw != NULL) { 674 psc = (struct dri3_screen *) base->psc; 675 676 psc->f->invalidate(pdraw->loader_drawable.dri_drawable); 677 678 XSync(gc->currentDpy, false); 679 680 (*psc->texBuffer->setTexBuffer2) (pcp->driContext, 681 pdraw->base.textureTarget, 682 pdraw->base.textureFormat, 683 pdraw->loader_drawable.dri_drawable); 684 } 685} 686 687static void 688dri3_release_tex_image(__GLXDRIdrawable *base, int buffer) 689{ 690 struct glx_context *gc = __glXGetCurrentContext(); 691 struct dri3_context *pcp = (struct dri3_context *) gc; 692 struct dri3_drawable *pdraw = (struct dri3_drawable *) base; 693 struct dri3_screen *psc; 694 695 if (pdraw != NULL) { 696 psc = (struct dri3_screen *) base->psc; 697 698 if (psc->texBuffer->base.version >= 3 && 699 psc->texBuffer->releaseTexBuffer != NULL) 700 (*psc->texBuffer->releaseTexBuffer) (pcp->driContext, 701 pdraw->base.textureTarget, 702 pdraw->loader_drawable.dri_drawable); 703 } 704} 705 706static const struct glx_context_vtable dri3_context_vtable = { 707 .destroy = dri3_destroy_context, 708 .bind = dri3_bind_context, 709 .unbind = dri3_unbind_context, 710 .wait_gl = dri3_wait_gl, 711 .wait_x = dri3_wait_x, 712 .interop_query_device_info = dri3_interop_query_device_info, 713 .interop_export_object = dri3_interop_export_object 714}; 715 716/** dri3_bind_extensions 717 * 718 * Enable all of the extensions supported on DRI3 719 */ 720static void 721dri3_bind_extensions(struct dri3_screen *psc, struct glx_display * priv, 722 const char *driverName) 723{ 724 const __DRIextension **extensions; 725 unsigned mask; 726 int i; 727 728 extensions = psc->core->getExtensions(psc->driScreen); 729 730 __glXEnableDirectExtension(&psc->base, "GLX_EXT_swap_control"); 731 __glXEnableDirectExtension(&psc->base, "GLX_EXT_swap_control_tear"); 732 __glXEnableDirectExtension(&psc->base, "GLX_SGI_swap_control"); 733 __glXEnableDirectExtension(&psc->base, "GLX_MESA_swap_control"); 734 __glXEnableDirectExtension(&psc->base, "GLX_SGI_make_current_read"); 735 __glXEnableDirectExtension(&psc->base, "GLX_INTEL_swap_event"); 736 737 mask = psc->image_driver->getAPIMask(psc->driScreen); 738 739 __glXEnableDirectExtension(&psc->base, "GLX_ARB_create_context"); 740 __glXEnableDirectExtension(&psc->base, "GLX_ARB_create_context_profile"); 741 __glXEnableDirectExtension(&psc->base, "GLX_EXT_no_config_context"); 742 743 if ((mask & ((1 << __DRI_API_GLES) | 744 (1 << __DRI_API_GLES2) | 745 (1 << __DRI_API_GLES3))) != 0) { 746 __glXEnableDirectExtension(&psc->base, 747 "GLX_EXT_create_context_es_profile"); 748 __glXEnableDirectExtension(&psc->base, 749 "GLX_EXT_create_context_es2_profile"); 750 } 751 752 for (i = 0; extensions[i]; i++) { 753 /* when on a different gpu than the server, the server pixmaps 754 * can have a tiling mode we can't read. Thus we can't create 755 * a texture from them. 756 */ 757 if (!psc->is_different_gpu && 758 (strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0)) { 759 psc->texBuffer = (__DRItexBufferExtension *) extensions[i]; 760 __glXEnableDirectExtension(&psc->base, "GLX_EXT_texture_from_pixmap"); 761 } 762 763 if ((strcmp(extensions[i]->name, __DRI2_FLUSH) == 0)) { 764 psc->f = (__DRI2flushExtension *) extensions[i]; 765 /* internal driver extension, no GL extension exposed */ 766 } 767 768 if (strcmp(extensions[i]->name, __DRI_IMAGE) == 0) 769 psc->image = (__DRIimageExtension *) extensions[i]; 770 771 if ((strcmp(extensions[i]->name, __DRI2_CONFIG_QUERY) == 0)) 772 psc->config = (__DRI2configQueryExtension *) extensions[i]; 773 774 if (strcmp(extensions[i]->name, __DRI2_ROBUSTNESS) == 0) 775 __glXEnableDirectExtension(&psc->base, 776 "GLX_ARB_create_context_robustness"); 777 778 if (strcmp(extensions[i]->name, __DRI2_NO_ERROR) == 0) 779 __glXEnableDirectExtension(&psc->base, 780 "GLX_ARB_create_context_no_error"); 781 782 if (strcmp(extensions[i]->name, __DRI2_RENDERER_QUERY) == 0) { 783 psc->rendererQuery = (__DRI2rendererQueryExtension *) extensions[i]; 784 __glXEnableDirectExtension(&psc->base, "GLX_MESA_query_renderer"); 785 } 786 787 if (strcmp(extensions[i]->name, __DRI2_INTEROP) == 0) 788 psc->interop = (__DRI2interopExtension*)extensions[i]; 789 790 if (strcmp(extensions[i]->name, __DRI2_FLUSH_CONTROL) == 0) 791 __glXEnableDirectExtension(&psc->base, 792 "GLX_ARB_context_flush_control"); 793 } 794} 795 796static char * 797dri3_get_driver_name(struct glx_screen *glx_screen) 798{ 799 struct dri3_screen *psc = (struct dri3_screen *)glx_screen; 800 801 return loader_get_driver_for_fd(psc->fd); 802} 803 804static const struct glx_screen_vtable dri3_screen_vtable = { 805 .create_context = dri_common_create_context, 806 .create_context_attribs = dri3_create_context_attribs, 807 .query_renderer_integer = dri3_query_renderer_integer, 808 .query_renderer_string = dri3_query_renderer_string, 809 .get_driver_name = dri3_get_driver_name, 810}; 811 812/** dri3_create_screen 813 * 814 * Initialize DRI3 on the specified screen. 815 * 816 * Opens the DRI device, locates the appropriate DRI driver 817 * and loads that. 818 * 819 * Checks to see if the driver supports the necessary extensions 820 * 821 * Initializes the driver for the screen and sets up our structures 822 */ 823 824static struct glx_screen * 825dri3_create_screen(int screen, struct glx_display * priv) 826{ 827 xcb_connection_t *c = XGetXCBConnection(priv->dpy); 828 const __DRIconfig **driver_configs; 829 const __DRIextension **extensions; 830 const struct dri3_display *const pdp = (struct dri3_display *) 831 priv->dri3Display; 832 struct dri3_screen *psc; 833 __GLXDRIscreen *psp; 834 struct glx_config *configs = NULL, *visuals = NULL; 835 char *driverName, *driverNameDisplayGPU, *tmp; 836 int i; 837 838 psc = calloc(1, sizeof *psc); 839 if (psc == NULL) 840 return NULL; 841 842 psc->fd = -1; 843 psc->fd_display_gpu = -1; 844 845 if (!glx_screen_init(&psc->base, screen, priv)) { 846 free(psc); 847 return NULL; 848 } 849 850 psc->fd = loader_dri3_open(c, RootWindow(priv->dpy, screen), None); 851 if (psc->fd < 0) { 852 int conn_error = xcb_connection_has_error(c); 853 854 glx_screen_cleanup(&psc->base); 855 free(psc); 856 InfoMessageF("screen %d does not appear to be DRI3 capable\n", screen); 857 858 if (conn_error) 859 ErrorMessageF("Connection closed during DRI3 initialization failure"); 860 861 return NULL; 862 } 863 864 psc->fd_display_gpu = fcntl(psc->fd, F_DUPFD_CLOEXEC, 3); 865 psc->fd = loader_get_user_preferred_fd(psc->fd, &psc->is_different_gpu); 866 if (!psc->is_different_gpu) { 867 close(psc->fd_display_gpu); 868 psc->fd_display_gpu = -1; 869 } 870 871 driverName = loader_get_driver_for_fd(psc->fd); 872 if (!driverName) { 873 ErrorMessageF("No driver found\n"); 874 goto handle_error; 875 } 876 877 extensions = driOpenDriver(driverName, &psc->driver); 878 if (extensions == NULL) 879 goto handle_error; 880 881 for (i = 0; extensions[i]; i++) { 882 if (strcmp(extensions[i]->name, __DRI_CORE) == 0) 883 psc->core = (__DRIcoreExtension *) extensions[i]; 884 if (strcmp(extensions[i]->name, __DRI_IMAGE_DRIVER) == 0) 885 psc->image_driver = (__DRIimageDriverExtension *) extensions[i]; 886 } 887 888 889 if (psc->core == NULL) { 890 ErrorMessageF("core dri driver extension not found\n"); 891 goto handle_error; 892 } 893 894 if (psc->image_driver == NULL) { 895 ErrorMessageF("image driver extension not found\n"); 896 goto handle_error; 897 } 898 899 if (psc->is_different_gpu) { 900 driverNameDisplayGPU = loader_get_driver_for_fd(psc->fd_display_gpu); 901 if (driverNameDisplayGPU) { 902 903 /* check if driver name is matching so that non mesa drivers 904 * will not crash. Also need this check since image extension 905 * pointer from render gpu is shared with display gpu. Image 906 * extension pointer is shared because it keeps things simple. 907 */ 908 if (strcmp(driverName, driverNameDisplayGPU) == 0) { 909 psc->driScreenDisplayGPU = 910 psc->image_driver->createNewScreen2(screen, psc->fd_display_gpu, 911 pdp->loader_extensions, 912 extensions, 913 &driver_configs, psc); 914 } 915 916 free(driverNameDisplayGPU); 917 } 918 } 919 920 psc->driScreen = 921 psc->image_driver->createNewScreen2(screen, psc->fd, 922 pdp->loader_extensions, 923 extensions, 924 &driver_configs, psc); 925 926 if (psc->driScreen == NULL) { 927 ErrorMessageF("failed to create dri screen\n"); 928 goto handle_error; 929 } 930 931 dri3_bind_extensions(psc, priv, driverName); 932 933 if (!psc->image || psc->image->base.version < 7 || !psc->image->createImageFromFds) { 934 ErrorMessageF("Version 7 or imageFromFds image extension not found\n"); 935 goto handle_error; 936 } 937 938 if (!psc->f || psc->f->base.version < 4) { 939 ErrorMessageF("Version 4 or later of flush extension not found\n"); 940 goto handle_error; 941 } 942 943 if (psc->is_different_gpu && psc->image->base.version < 9) { 944 ErrorMessageF("Different GPU, but image extension version 9 or later not found\n"); 945 goto handle_error; 946 } 947 948 if (psc->is_different_gpu && !psc->image->blitImage) { 949 ErrorMessageF("Different GPU, but blitImage not implemented for this driver\n"); 950 goto handle_error; 951 } 952 953 if (!psc->is_different_gpu && ( 954 !psc->texBuffer || psc->texBuffer->base.version < 2 || 955 !psc->texBuffer->setTexBuffer2 956 )) { 957 ErrorMessageF("Version 2 or later of texBuffer extension not found\n"); 958 goto handle_error; 959 } 960 961 psc->loader_dri3_ext.core = psc->core; 962 psc->loader_dri3_ext.image_driver = psc->image_driver; 963 psc->loader_dri3_ext.flush = psc->f; 964 psc->loader_dri3_ext.tex_buffer = psc->texBuffer; 965 psc->loader_dri3_ext.image = psc->image; 966 psc->loader_dri3_ext.config = psc->config; 967 968 configs = driConvertConfigs(psc->core, psc->base.configs, driver_configs); 969 visuals = driConvertConfigs(psc->core, psc->base.visuals, driver_configs); 970 971 if (!configs || !visuals) { 972 ErrorMessageF("No matching fbConfigs or visuals found\n"); 973 goto handle_error; 974 } 975 976 glx_config_destroy_list(psc->base.configs); 977 psc->base.configs = configs; 978 glx_config_destroy_list(psc->base.visuals); 979 psc->base.visuals = visuals; 980 981 psc->driver_configs = driver_configs; 982 983 psc->base.vtable = &dri3_screen_vtable; 984 psc->base.context_vtable = &dri3_context_vtable; 985 psp = &psc->vtable; 986 psc->base.driScreen = psp; 987 psp->destroyScreen = dri3_destroy_screen; 988 psp->createDrawable = dri3_create_drawable; 989 psp->swapBuffers = dri3_swap_buffers; 990 991 psp->getDrawableMSC = dri3_drawable_get_msc; 992 psp->waitForMSC = dri3_wait_for_msc; 993 psp->waitForSBC = dri3_wait_for_sbc; 994 psp->setSwapInterval = dri3_set_swap_interval; 995 psp->getSwapInterval = dri3_get_swap_interval; 996 psp->bindTexImage = dri3_bind_tex_image; 997 psp->releaseTexImage = dri3_release_tex_image; 998 999 __glXEnableDirectExtension(&psc->base, "GLX_OML_sync_control"); 1000 __glXEnableDirectExtension(&psc->base, "GLX_SGI_video_sync"); 1001 1002 psp->copySubBuffer = dri3_copy_sub_buffer; 1003 __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer"); 1004 1005 psp->getBufferAge = dri3_get_buffer_age; 1006 __glXEnableDirectExtension(&psc->base, "GLX_EXT_buffer_age"); 1007 1008 if (psc->config->base.version > 1 && 1009 psc->config->configQuerys(psc->driScreen, "glx_extension_override", 1010 &tmp) == 0) 1011 __glXParseExtensionOverride(&psc->base, tmp); 1012 1013 if (psc->config->base.version > 1 && 1014 psc->config->configQuerys(psc->driScreen, 1015 "indirect_gl_extension_override", 1016 &tmp) == 0) 1017 __IndirectGlParseExtensionOverride(&psc->base, tmp); 1018 1019 free(driverName); 1020 1021 tmp = getenv("LIBGL_SHOW_FPS"); 1022 psc->show_fps_interval = tmp ? atoi(tmp) : 0; 1023 if (psc->show_fps_interval < 0) 1024 psc->show_fps_interval = 0; 1025 1026 InfoMessageF("Using DRI3 for screen %d\n", screen); 1027 1028 psc->prefer_back_buffer_reuse = 1; 1029 if (psc->is_different_gpu && psc->rendererQuery) { 1030 unsigned value; 1031 if (psc->rendererQuery->queryInteger(psc->driScreen, 1032 __DRI2_RENDERER_PREFER_BACK_BUFFER_REUSE, 1033 &value) == 0) 1034 psc->prefer_back_buffer_reuse = value; 1035 } 1036 1037 return &psc->base; 1038 1039handle_error: 1040 CriticalErrorMessageF("failed to load driver: %s\n", driverName ? driverName : "(null)"); 1041 1042 if (configs) 1043 glx_config_destroy_list(configs); 1044 if (visuals) 1045 glx_config_destroy_list(visuals); 1046 if (psc->driScreen) 1047 psc->core->destroyScreen(psc->driScreen); 1048 psc->driScreen = NULL; 1049 if (psc->driScreenDisplayGPU) 1050 psc->core->destroyScreen(psc->driScreenDisplayGPU); 1051 psc->driScreenDisplayGPU = NULL; 1052 if (psc->fd >= 0) 1053 close(psc->fd); 1054 if (psc->fd_display_gpu >= 0) 1055 close(psc->fd_display_gpu); 1056 if (psc->driver) 1057 dlclose(psc->driver); 1058 1059 free(driverName); 1060 glx_screen_cleanup(&psc->base); 1061 free(psc); 1062 1063 return NULL; 1064} 1065 1066/** dri_destroy_display 1067 * 1068 * Called from __glXFreeDisplayPrivate. 1069 */ 1070static void 1071dri3_destroy_display(__GLXDRIdisplay * dpy) 1072{ 1073 free(dpy); 1074} 1075 1076/* Only request versions of these protocols which we actually support. */ 1077#define DRI3_SUPPORTED_MAJOR 1 1078#define PRESENT_SUPPORTED_MAJOR 1 1079 1080#ifdef HAVE_DRI3_MODIFIERS 1081#define DRI3_SUPPORTED_MINOR 2 1082#define PRESENT_SUPPORTED_MINOR 2 1083#else 1084#define PRESENT_SUPPORTED_MINOR 0 1085#define DRI3_SUPPORTED_MINOR 0 1086#endif 1087 1088/** dri3_create_display 1089 * 1090 * Allocate, initialize and return a __DRIdisplayPrivate object. 1091 * This is called from __glXInitialize() when we are given a new 1092 * display pointer. This is public to that function, but hidden from 1093 * outside of libGL. 1094 */ 1095_X_HIDDEN __GLXDRIdisplay * 1096dri3_create_display(Display * dpy) 1097{ 1098 struct dri3_display *pdp; 1099 xcb_connection_t *c = XGetXCBConnection(dpy); 1100 xcb_dri3_query_version_cookie_t dri3_cookie; 1101 xcb_dri3_query_version_reply_t *dri3_reply; 1102 xcb_present_query_version_cookie_t present_cookie; 1103 xcb_present_query_version_reply_t *present_reply; 1104 xcb_generic_error_t *error; 1105 const xcb_query_extension_reply_t *extension; 1106 1107 xcb_prefetch_extension_data(c, &xcb_dri3_id); 1108 xcb_prefetch_extension_data(c, &xcb_present_id); 1109 1110 extension = xcb_get_extension_data(c, &xcb_dri3_id); 1111 if (!(extension && extension->present)) 1112 return NULL; 1113 1114 extension = xcb_get_extension_data(c, &xcb_present_id); 1115 if (!(extension && extension->present)) 1116 return NULL; 1117 1118 dri3_cookie = xcb_dri3_query_version(c, 1119 DRI3_SUPPORTED_MAJOR, 1120 DRI3_SUPPORTED_MINOR); 1121 present_cookie = xcb_present_query_version(c, 1122 PRESENT_SUPPORTED_MAJOR, 1123 PRESENT_SUPPORTED_MINOR); 1124 1125 pdp = malloc(sizeof *pdp); 1126 if (pdp == NULL) 1127 return NULL; 1128 1129 dri3_reply = xcb_dri3_query_version_reply(c, dri3_cookie, &error); 1130 if (!dri3_reply) { 1131 free(error); 1132 goto no_extension; 1133 } 1134 1135 pdp->dri3Major = dri3_reply->major_version; 1136 pdp->dri3Minor = dri3_reply->minor_version; 1137 free(dri3_reply); 1138 1139 present_reply = xcb_present_query_version_reply(c, present_cookie, &error); 1140 if (!present_reply) { 1141 free(error); 1142 goto no_extension; 1143 } 1144 pdp->presentMajor = present_reply->major_version; 1145 pdp->presentMinor = present_reply->minor_version; 1146 free(present_reply); 1147 1148 pdp->base.destroyDisplay = dri3_destroy_display; 1149 pdp->base.createScreen = dri3_create_screen; 1150 1151 pdp->loader_extensions = loader_extensions; 1152 1153 return &pdp->base; 1154no_extension: 1155 free(pdp); 1156 return NULL; 1157} 1158 1159#endif /* GLX_DIRECT_RENDERING */ 1160