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