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