dri2_glx.c revision 48ffc6a1553083280c217640629cc6ebed1bf982
1/* 2 * Copyright © 2008 Red Hat, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Soft- 6 * ware"), to deal in the Software without restriction, including without 7 * limitation the rights to use, copy, modify, merge, publish, distribute, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, provided that the above copyright 10 * notice(s) and this permission notice appear in all copies of the Soft- 11 * ware and that both the above copyright notice(s) and this permission 12 * notice appear in supporting documentation. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- 16 * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY 17 * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN 18 * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE- 19 * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR- 22 * MANCE OF THIS SOFTWARE. 23 * 24 * Except as contained in this notice, the name of a copyright holder shall 25 * not be used in advertising or otherwise to promote the sale, use or 26 * other dealings in this Software without prior written authorization of 27 * the copyright holder. 28 * 29 * Authors: 30 * Kristian Høgsberg (krh@redhat.com) 31 */ 32 33#if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL) 34 35#include <X11/Xlib.h> 36#include <X11/extensions/Xfixes.h> 37#include "glapi.h" 38#include "glxclient.h" 39#include <X11/extensions/dri2proto.h> 40#include "xf86dri.h" 41#include <dlfcn.h> 42#include <fcntl.h> 43#include <unistd.h> 44#include <sys/types.h> 45#include <sys/mman.h> 46#include "xf86drm.h" 47#include "dri2.h" 48#include "dri_common.h" 49 50/* From xmlpool/options.h, user exposed so should be stable */ 51#define DRI_CONF_VBLANK_NEVER 0 52#define DRI_CONF_VBLANK_DEF_INTERVAL_0 1 53#define DRI_CONF_VBLANK_DEF_INTERVAL_1 2 54#define DRI_CONF_VBLANK_ALWAYS_SYNC 3 55 56#undef DRI2_MINOR 57#define DRI2_MINOR 1 58 59struct dri2_display 60{ 61 __GLXDRIdisplay base; 62 63 /* 64 ** XFree86-DRI version information 65 */ 66 int driMajor; 67 int driMinor; 68 int driPatch; 69 int swapAvailable; 70 int invalidateAvailable; 71 72 __glxHashTable *dri2Hash; 73 74 const __DRIextension *loader_extensions[4]; 75}; 76 77struct dri2_screen { 78 struct glx_screen base; 79 80 __DRIscreen *driScreen; 81 __GLXDRIscreen vtable; 82 const __DRIdri2Extension *dri2; 83 const __DRIcoreExtension *core; 84 85 const __DRI2flushExtension *f; 86 const __DRI2configQueryExtension *config; 87 const __DRItexBufferExtension *texBuffer; 88 const __DRI2throttleExtension *throttle; 89 const __DRIconfig **driver_configs; 90 91 void *driver; 92 int fd; 93}; 94 95struct dri2_context 96{ 97 struct glx_context base; 98 __DRIcontext *driContext; 99}; 100 101struct dri2_drawable 102{ 103 __GLXDRIdrawable base; 104 __DRIdrawable *driDrawable; 105 __DRIbuffer buffers[5]; 106 int bufferCount; 107 int width, height; 108 int have_back; 109 int have_fake_front; 110 int swap_interval; 111}; 112 113static const struct glx_context_vtable dri2_context_vtable; 114 115static void 116dri2_destroy_context(struct glx_context *context) 117{ 118 struct dri2_context *pcp = (struct dri2_context *) context; 119 struct dri2_screen *psc = (struct dri2_screen *) context->psc; 120 121 driReleaseDrawables(&pcp->base); 122 123 if (context->extensions) 124 XFree((char *) context->extensions); 125 126 (*psc->core->destroyContext) (pcp->driContext); 127 128 Xfree(pcp); 129} 130 131static Bool 132dri2_bind_context(struct glx_context *context, struct glx_context *old, 133 GLXDrawable draw, GLXDrawable read) 134{ 135 struct dri2_context *pcp = (struct dri2_context *) context; 136 struct dri2_screen *psc = (struct dri2_screen *) pcp->base.psc; 137 struct dri2_drawable *pdraw, *pread; 138 struct dri2_display *pdp; 139 140 pdraw = (struct dri2_drawable *) driFetchDrawable(context, draw); 141 pread = (struct dri2_drawable *) driFetchDrawable(context, read); 142 143 driReleaseDrawables(&pcp->base); 144 145 if (pdraw == NULL || pread == NULL) 146 return GLXBadDrawable; 147 148 if (!(*psc->core->bindContext) (pcp->driContext, 149 pdraw->driDrawable, pread->driDrawable)) 150 return GLXBadContext; 151 152 /* If the server doesn't send invalidate events, we may miss a 153 * resize before the rendering starts. Invalidate the buffers now 154 * so the driver will recheck before rendering starts. */ 155 pdp = (struct dri2_display *) psc->base.display; 156 if (!pdp->invalidateAvailable) { 157 dri2InvalidateBuffers(psc->base.dpy, pdraw->base.xDrawable); 158 if (pread != pdraw) 159 dri2InvalidateBuffers(psc->base.dpy, pread->base.xDrawable); 160 } 161 162 return Success; 163} 164 165static void 166dri2_unbind_context(struct glx_context *context, struct glx_context *new) 167{ 168 struct dri2_context *pcp = (struct dri2_context *) context; 169 struct dri2_screen *psc = (struct dri2_screen *) pcp->base.psc; 170 171 (*psc->core->unbindContext) (pcp->driContext); 172} 173 174static struct glx_context * 175dri2_create_context(struct glx_screen *base, 176 struct glx_config *config_base, 177 struct glx_context *shareList, int renderType) 178{ 179 struct dri2_context *pcp, *pcp_shared; 180 struct dri2_screen *psc = (struct dri2_screen *) base; 181 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base; 182 __DRIcontext *shared = NULL; 183 184 if (shareList) { 185 /* If the shareList context is not a DRI2 context, we cannot possibly 186 * create a DRI2 context that shares it. 187 */ 188 if (shareList->vtable->destroy != dri2_destroy_context) { 189 return NULL; 190 } 191 192 pcp_shared = (struct dri2_context *) shareList; 193 shared = pcp_shared->driContext; 194 } 195 196 pcp = Xmalloc(sizeof *pcp); 197 if (pcp == NULL) 198 return NULL; 199 200 memset(pcp, 0, sizeof *pcp); 201 if (!glx_context_init(&pcp->base, &psc->base, &config->base)) { 202 Xfree(pcp); 203 return NULL; 204 } 205 206 pcp->driContext = 207 (*psc->dri2->createNewContext) (psc->driScreen, 208 config->driConfig, shared, pcp); 209 210 if (pcp->driContext == NULL) { 211 Xfree(pcp); 212 return NULL; 213 } 214 215 pcp->base.vtable = &dri2_context_vtable; 216 217 return &pcp->base; 218} 219 220static struct glx_context * 221dri2_create_context_attribs(struct glx_screen *base, 222 struct glx_config *config_base, 223 struct glx_context *shareList, 224 unsigned num_attribs, 225 const uint32_t *attribs, 226 unsigned *error) 227{ 228 struct dri2_context *pcp = NULL; 229 struct dri2_context *pcp_shared = NULL; 230 struct dri2_screen *psc = (struct dri2_screen *) base; 231 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base; 232 __DRIcontext *shared = NULL; 233 234 uint32_t minor_ver = 1; 235 uint32_t major_ver = 2; 236 uint32_t flags = 0; 237 unsigned api; 238 uint32_t ctx_attribs[2 * 4]; 239 unsigned num_ctx_attribs = 0; 240 241 if (psc->dri2->base.version < 3) { 242 *error = __DRI_CTX_ERROR_NO_MEMORY; 243 goto error_exit; 244 } 245 246 /* Remap the GLX tokens to DRI2 tokens. 247 */ 248 if (!dri2_convert_glx_attribs(num_attribs, attribs, 249 &major_ver, &minor_ver, &flags, &api, error)) 250 goto error_exit; 251 252 if (shareList) { 253 pcp_shared = (struct dri2_context *) shareList; 254 shared = pcp_shared->driContext; 255 } 256 257 pcp = Xmalloc(sizeof *pcp); 258 if (pcp == NULL) { 259 *error = __DRI_CTX_ERROR_NO_MEMORY; 260 goto error_exit; 261 } 262 263 memset(pcp, 0, sizeof *pcp); 264 if (!glx_context_init(&pcp->base, &psc->base, &config->base)) 265 goto error_exit; 266 267 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MAJOR_VERSION; 268 ctx_attribs[num_ctx_attribs++] = major_ver; 269 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MINOR_VERSION; 270 ctx_attribs[num_ctx_attribs++] = minor_ver; 271 272 if (flags != 0) { 273 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_FLAGS; 274 275 /* The current __DRI_CTX_FLAG_* values are identical to the 276 * GLX_CONTEXT_*_BIT values. 277 */ 278 ctx_attribs[num_ctx_attribs++] = flags; 279 } 280 281 pcp->driContext = 282 (*psc->dri2->createContextAttribs) (psc->driScreen, 283 api, 284 config->driConfig, 285 shared, 286 num_ctx_attribs / 2, 287 ctx_attribs, 288 error, 289 pcp); 290 291 if (pcp->driContext == NULL) 292 goto error_exit; 293 294 pcp->base.vtable = &dri2_context_vtable; 295 296 return &pcp->base; 297 298error_exit: 299 if (pcp != NULL) 300 Xfree(pcp); 301 302 return NULL; 303} 304 305static void 306dri2DestroyDrawable(__GLXDRIdrawable *base) 307{ 308 struct dri2_screen *psc = (struct dri2_screen *) base->psc; 309 struct dri2_drawable *pdraw = (struct dri2_drawable *) base; 310 struct glx_display *dpyPriv = psc->base.display; 311 struct dri2_display *pdp = (struct dri2_display *)dpyPriv->dri2Display; 312 313 __glxHashDelete(pdp->dri2Hash, pdraw->base.xDrawable); 314 (*psc->core->destroyDrawable) (pdraw->driDrawable); 315 316 /* If it's a GLX 1.3 drawables, we can destroy the DRI2 drawable 317 * now, as the application explicitly asked to destroy the GLX 318 * drawable. Otherwise, for legacy drawables, we let the DRI2 319 * drawable linger on the server, since there's no good way of 320 * knowing when the application is done with it. The server will 321 * destroy the DRI2 drawable when it destroys the X drawable or the 322 * client exits anyway. */ 323 if (pdraw->base.xDrawable != pdraw->base.drawable) 324 DRI2DestroyDrawable(psc->base.dpy, pdraw->base.xDrawable); 325 326 Xfree(pdraw); 327} 328 329static __GLXDRIdrawable * 330dri2CreateDrawable(struct glx_screen *base, XID xDrawable, 331 GLXDrawable drawable, struct glx_config *config_base) 332{ 333 struct dri2_drawable *pdraw; 334 struct dri2_screen *psc = (struct dri2_screen *) base; 335 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base; 336 struct glx_display *dpyPriv; 337 struct dri2_display *pdp; 338 GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1; 339 340 pdraw = Xmalloc(sizeof(*pdraw)); 341 if (!pdraw) 342 return NULL; 343 344 memset(pdraw, 0, sizeof *pdraw); 345 pdraw->base.destroyDrawable = dri2DestroyDrawable; 346 pdraw->base.xDrawable = xDrawable; 347 pdraw->base.drawable = drawable; 348 pdraw->base.psc = &psc->base; 349 pdraw->bufferCount = 0; 350 pdraw->swap_interval = 1; /* default may be overridden below */ 351 pdraw->have_back = 0; 352 353 if (psc->config) 354 psc->config->configQueryi(psc->driScreen, 355 "vblank_mode", &vblank_mode); 356 357 switch (vblank_mode) { 358 case DRI_CONF_VBLANK_NEVER: 359 case DRI_CONF_VBLANK_DEF_INTERVAL_0: 360 pdraw->swap_interval = 0; 361 break; 362 case DRI_CONF_VBLANK_DEF_INTERVAL_1: 363 case DRI_CONF_VBLANK_ALWAYS_SYNC: 364 default: 365 pdraw->swap_interval = 1; 366 break; 367 } 368 369 DRI2CreateDrawable(psc->base.dpy, xDrawable); 370 371 dpyPriv = __glXInitialize(psc->base.dpy); 372 pdp = (struct dri2_display *)dpyPriv->dri2Display;; 373 /* Create a new drawable */ 374 pdraw->driDrawable = 375 (*psc->dri2->createNewDrawable) (psc->driScreen, 376 config->driConfig, pdraw); 377 378 if (!pdraw->driDrawable) { 379 DRI2DestroyDrawable(psc->base.dpy, xDrawable); 380 Xfree(pdraw); 381 return NULL; 382 } 383 384 if (__glxHashInsert(pdp->dri2Hash, xDrawable, pdraw)) { 385 (*psc->core->destroyDrawable) (pdraw->driDrawable); 386 DRI2DestroyDrawable(psc->base.dpy, xDrawable); 387 Xfree(pdraw); 388 return None; 389 } 390 391 392#ifdef X_DRI2SwapInterval 393 /* 394 * Make sure server has the same swap interval we do for the new 395 * drawable. 396 */ 397 if (pdp->swapAvailable) 398 DRI2SwapInterval(psc->base.dpy, xDrawable, pdraw->swap_interval); 399#endif 400 401 return &pdraw->base; 402} 403 404#ifdef X_DRI2GetMSC 405 406static int 407dri2DrawableGetMSC(struct glx_screen *psc, __GLXDRIdrawable *pdraw, 408 int64_t *ust, int64_t *msc, int64_t *sbc) 409{ 410 CARD64 dri2_ust, dri2_msc, dri2_sbc; 411 int ret; 412 413 ret = DRI2GetMSC(psc->dpy, pdraw->xDrawable, 414 &dri2_ust, &dri2_msc, &dri2_sbc); 415 *ust = dri2_ust; 416 *msc = dri2_msc; 417 *sbc = dri2_sbc; 418 419 return ret; 420} 421 422#endif 423 424 425#ifdef X_DRI2WaitMSC 426 427static int 428dri2WaitForMSC(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor, 429 int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc) 430{ 431 CARD64 dri2_ust, dri2_msc, dri2_sbc; 432 int ret; 433 434 ret = DRI2WaitMSC(pdraw->psc->dpy, pdraw->xDrawable, target_msc, divisor, 435 remainder, &dri2_ust, &dri2_msc, &dri2_sbc); 436 *ust = dri2_ust; 437 *msc = dri2_msc; 438 *sbc = dri2_sbc; 439 440 return ret; 441} 442 443static int 444dri2WaitForSBC(__GLXDRIdrawable *pdraw, int64_t target_sbc, int64_t *ust, 445 int64_t *msc, int64_t *sbc) 446{ 447 CARD64 dri2_ust, dri2_msc, dri2_sbc; 448 int ret; 449 450 ret = DRI2WaitSBC(pdraw->psc->dpy, pdraw->xDrawable, 451 target_sbc, &dri2_ust, &dri2_msc, &dri2_sbc); 452 *ust = dri2_ust; 453 *msc = dri2_msc; 454 *sbc = dri2_sbc; 455 456 return ret; 457} 458 459#endif /* X_DRI2WaitMSC */ 460 461/** 462 * dri2Throttle - Request driver throttling 463 * 464 * This function uses the DRI2 throttle extension to give the 465 * driver the opportunity to throttle on flush front, copysubbuffer 466 * and swapbuffers. 467 */ 468static void 469dri2Throttle(struct dri2_screen *psc, 470 struct dri2_drawable *draw, 471 enum __DRI2throttleReason reason) 472{ 473 if (psc->throttle) { 474 struct glx_context *gc = __glXGetCurrentContext(); 475 struct dri2_context *dri2Ctx = (struct dri2_context *)gc; 476 __DRIcontext *ctx = 477 (dri2Ctx) ? dri2Ctx->driContext : NULL; 478 479 psc->throttle->throttle(ctx, draw->driDrawable, reason); 480 } 481} 482 483static void 484__dri2CopySubBuffer(__GLXDRIdrawable *pdraw, int x, int y, 485 int width, int height, 486 enum __DRI2throttleReason reason) 487{ 488 struct dri2_drawable *priv = (struct dri2_drawable *) pdraw; 489 struct dri2_screen *psc = (struct dri2_screen *) pdraw->psc; 490 XRectangle xrect; 491 XserverRegion region; 492 493 /* Check we have the right attachments */ 494 if (!priv->have_back) 495 return; 496 497 xrect.x = x; 498 xrect.y = priv->height - y - height; 499 xrect.width = width; 500 xrect.height = height; 501 502#ifdef __DRI2_FLUSH 503 if (psc->f) 504 (*psc->f->flush) (priv->driDrawable); 505#endif 506 507 dri2Throttle(psc, priv, reason); 508 509 region = XFixesCreateRegion(psc->base.dpy, &xrect, 1); 510 DRI2CopyRegion(psc->base.dpy, pdraw->xDrawable, region, 511 DRI2BufferFrontLeft, DRI2BufferBackLeft); 512 513 /* Refresh the fake front (if present) after we just damaged the real 514 * front. 515 */ 516 if (priv->have_fake_front) 517 DRI2CopyRegion(psc->base.dpy, pdraw->xDrawable, region, 518 DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft); 519 520 XFixesDestroyRegion(psc->base.dpy, region); 521} 522 523static void 524dri2CopySubBuffer(__GLXDRIdrawable *pdraw, int x, int y, 525 int width, int height) 526{ 527 __dri2CopySubBuffer(pdraw, x, y, width, height, 528 __DRI2_THROTTLE_COPYSUBBUFFER); 529} 530 531 532static void 533dri2_copy_drawable(struct dri2_drawable *priv, int dest, int src) 534{ 535 XRectangle xrect; 536 XserverRegion region; 537 struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc; 538 539 xrect.x = 0; 540 xrect.y = 0; 541 xrect.width = priv->width; 542 xrect.height = priv->height; 543 544#ifdef __DRI2_FLUSH 545 if (psc->f) 546 (*psc->f->flush) (priv->driDrawable); 547#endif 548 549 region = XFixesCreateRegion(psc->base.dpy, &xrect, 1); 550 DRI2CopyRegion(psc->base.dpy, priv->base.xDrawable, region, dest, src); 551 XFixesDestroyRegion(psc->base.dpy, region); 552 553} 554 555static void 556dri2_wait_x(struct glx_context *gc) 557{ 558 struct dri2_drawable *priv = (struct dri2_drawable *) 559 GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable); 560 561 if (priv == NULL || !priv->have_fake_front) 562 return; 563 564 dri2_copy_drawable(priv, DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft); 565} 566 567static void 568dri2_wait_gl(struct glx_context *gc) 569{ 570 struct dri2_drawable *priv = (struct dri2_drawable *) 571 GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable); 572 573 if (priv == NULL || !priv->have_fake_front) 574 return; 575 576 dri2_copy_drawable(priv, DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft); 577} 578 579static void 580dri2FlushFrontBuffer(__DRIdrawable *driDrawable, void *loaderPrivate) 581{ 582 struct glx_display *priv; 583 struct dri2_display *pdp; 584 struct glx_context *gc; 585 struct dri2_drawable *pdraw = loaderPrivate; 586 struct dri2_screen *psc; 587 588 if (!pdraw) 589 return; 590 591 if (!pdraw->base.psc) 592 return; 593 594 psc = (struct dri2_screen *) pdraw->base.psc; 595 596 priv = __glXInitialize(psc->base.dpy); 597 pdp = (struct dri2_display *) priv->dri2Display; 598 gc = __glXGetCurrentContext(); 599 600 dri2Throttle(psc, pdraw, __DRI2_THROTTLE_FLUSHFRONT); 601 602 /* Old servers don't send invalidate events */ 603 if (!pdp->invalidateAvailable) 604 dri2InvalidateBuffers(priv->dpy, pdraw->base.xDrawable); 605 606 dri2_wait_gl(gc); 607} 608 609 610static void 611dri2DestroyScreen(struct glx_screen *base) 612{ 613 struct dri2_screen *psc = (struct dri2_screen *) base; 614 615 /* Free the direct rendering per screen data */ 616 (*psc->core->destroyScreen) (psc->driScreen); 617 driDestroyConfigs(psc->driver_configs); 618 close(psc->fd); 619 Xfree(psc); 620} 621 622/** 623 * Process list of buffer received from the server 624 * 625 * Processes the list of buffers received in a reply from the server to either 626 * \c DRI2GetBuffers or \c DRI2GetBuffersWithFormat. 627 */ 628static void 629process_buffers(struct dri2_drawable * pdraw, DRI2Buffer * buffers, 630 unsigned count) 631{ 632 int i; 633 634 pdraw->bufferCount = count; 635 pdraw->have_fake_front = 0; 636 pdraw->have_back = 0; 637 638 /* This assumes the DRI2 buffer attachment tokens matches the 639 * __DRIbuffer tokens. */ 640 for (i = 0; i < count; i++) { 641 pdraw->buffers[i].attachment = buffers[i].attachment; 642 pdraw->buffers[i].name = buffers[i].name; 643 pdraw->buffers[i].pitch = buffers[i].pitch; 644 pdraw->buffers[i].cpp = buffers[i].cpp; 645 pdraw->buffers[i].flags = buffers[i].flags; 646 if (pdraw->buffers[i].attachment == __DRI_BUFFER_FAKE_FRONT_LEFT) 647 pdraw->have_fake_front = 1; 648 if (pdraw->buffers[i].attachment == __DRI_BUFFER_BACK_LEFT) 649 pdraw->have_back = 1; 650 } 651 652} 653 654unsigned dri2GetSwapEventType(Display* dpy, XID drawable) 655{ 656 struct glx_display *glx_dpy = __glXInitialize(dpy); 657 __GLXDRIdrawable *pdraw; 658 pdraw = dri2GetGlxDrawableFromXDrawableId(dpy, drawable); 659 if (!pdraw || !(pdraw->eventMask & GLX_BUFFER_SWAP_COMPLETE_INTEL_MASK)) 660 return 0; 661 return glx_dpy->codes->first_event + GLX_BufferSwapComplete; 662} 663 664static int64_t 665dri2SwapBuffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor, 666 int64_t remainder) 667{ 668 struct dri2_drawable *priv = (struct dri2_drawable *) pdraw; 669 struct glx_display *dpyPriv = __glXInitialize(priv->base.psc->dpy); 670 struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc; 671 struct dri2_display *pdp = 672 (struct dri2_display *)dpyPriv->dri2Display; 673 CARD64 ret = 0; 674 675 /* Check we have the right attachments */ 676 if (!priv->have_back) 677 return ret; 678 679 /* Old servers can't handle swapbuffers */ 680 if (!pdp->swapAvailable) { 681 __dri2CopySubBuffer(pdraw, 0, 0, priv->width, priv->height, 682 __DRI2_THROTTLE_SWAPBUFFER); 683 } else { 684#ifdef X_DRI2SwapBuffers 685#ifdef __DRI2_FLUSH 686 if (psc->f) { 687 struct glx_context *gc = __glXGetCurrentContext(); 688 689 if (gc) { 690 (*psc->f->flush)(priv->driDrawable); 691 } 692 } 693#endif 694 695 dri2Throttle(psc, priv, __DRI2_THROTTLE_SWAPBUFFER); 696 697 DRI2SwapBuffers(psc->base.dpy, pdraw->xDrawable, 698 target_msc, divisor, remainder, &ret); 699#endif 700 } 701 702 /* Old servers don't send invalidate events */ 703 if (!pdp->invalidateAvailable) 704 dri2InvalidateBuffers(dpyPriv->dpy, pdraw->xDrawable); 705 706 return ret; 707} 708 709static __DRIbuffer * 710dri2GetBuffers(__DRIdrawable * driDrawable, 711 int *width, int *height, 712 unsigned int *attachments, int count, 713 int *out_count, void *loaderPrivate) 714{ 715 struct dri2_drawable *pdraw = loaderPrivate; 716 DRI2Buffer *buffers; 717 718 buffers = DRI2GetBuffers(pdraw->base.psc->dpy, pdraw->base.xDrawable, 719 width, height, attachments, count, out_count); 720 if (buffers == NULL) 721 return NULL; 722 723 pdraw->width = *width; 724 pdraw->height = *height; 725 process_buffers(pdraw, buffers, *out_count); 726 727 Xfree(buffers); 728 729 return pdraw->buffers; 730} 731 732static __DRIbuffer * 733dri2GetBuffersWithFormat(__DRIdrawable * driDrawable, 734 int *width, int *height, 735 unsigned int *attachments, int count, 736 int *out_count, void *loaderPrivate) 737{ 738 struct dri2_drawable *pdraw = loaderPrivate; 739 DRI2Buffer *buffers; 740 741 buffers = DRI2GetBuffersWithFormat(pdraw->base.psc->dpy, 742 pdraw->base.xDrawable, 743 width, height, attachments, 744 count, out_count); 745 if (buffers == NULL) 746 return NULL; 747 748 pdraw->width = *width; 749 pdraw->height = *height; 750 process_buffers(pdraw, buffers, *out_count); 751 752 Xfree(buffers); 753 754 return pdraw->buffers; 755} 756 757#ifdef X_DRI2SwapInterval 758 759static int 760dri2SetSwapInterval(__GLXDRIdrawable *pdraw, int interval) 761{ 762 struct dri2_drawable *priv = (struct dri2_drawable *) pdraw; 763 GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1; 764 struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc; 765 766 if (psc->config) 767 psc->config->configQueryi(psc->driScreen, 768 "vblank_mode", &vblank_mode); 769 770 switch (vblank_mode) { 771 case DRI_CONF_VBLANK_NEVER: 772 return GLX_BAD_VALUE; 773 case DRI_CONF_VBLANK_ALWAYS_SYNC: 774 if (interval <= 0) 775 return GLX_BAD_VALUE; 776 break; 777 default: 778 break; 779 } 780 781 DRI2SwapInterval(priv->base.psc->dpy, priv->base.xDrawable, interval); 782 priv->swap_interval = interval; 783 784 return 0; 785} 786 787static int 788dri2GetSwapInterval(__GLXDRIdrawable *pdraw) 789{ 790 struct dri2_drawable *priv = (struct dri2_drawable *) pdraw; 791 792 return priv->swap_interval; 793} 794 795#endif /* X_DRI2SwapInterval */ 796 797static const __DRIdri2LoaderExtension dri2LoaderExtension = { 798 {__DRI_DRI2_LOADER, __DRI_DRI2_LOADER_VERSION}, 799 dri2GetBuffers, 800 dri2FlushFrontBuffer, 801 dri2GetBuffersWithFormat, 802}; 803 804static const __DRIdri2LoaderExtension dri2LoaderExtension_old = { 805 {__DRI_DRI2_LOADER, __DRI_DRI2_LOADER_VERSION}, 806 dri2GetBuffers, 807 dri2FlushFrontBuffer, 808 NULL, 809}; 810 811#ifdef __DRI_USE_INVALIDATE 812static const __DRIuseInvalidateExtension dri2UseInvalidate = { 813 { __DRI_USE_INVALIDATE, __DRI_USE_INVALIDATE_VERSION } 814}; 815#endif 816 817_X_HIDDEN void 818dri2InvalidateBuffers(Display *dpy, XID drawable) 819{ 820 __GLXDRIdrawable *pdraw = 821 dri2GetGlxDrawableFromXDrawableId(dpy, drawable); 822 struct dri2_screen *psc; 823 struct dri2_drawable *pdp = (struct dri2_drawable *) pdraw; 824 825 if (!pdraw) 826 return; 827 828 psc = (struct dri2_screen *) pdraw->psc; 829 830#if __DRI2_FLUSH_VERSION >= 3 831 if (pdraw && psc->f && psc->f->base.version >= 3 && psc->f->invalidate) 832 psc->f->invalidate(pdp->driDrawable); 833#endif 834} 835 836static void 837dri2_bind_tex_image(Display * dpy, 838 GLXDrawable drawable, 839 int buffer, const int *attrib_list) 840{ 841 struct glx_context *gc = __glXGetCurrentContext(); 842 struct dri2_context *pcp = (struct dri2_context *) gc; 843 __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable); 844 struct glx_display *dpyPriv = __glXInitialize(dpy); 845 struct dri2_drawable *pdraw = (struct dri2_drawable *) base; 846 struct dri2_display *pdp = 847 (struct dri2_display *) dpyPriv->dri2Display; 848 struct dri2_screen *psc; 849 850 if (pdraw != NULL) { 851 psc = (struct dri2_screen *) base->psc; 852 853#if __DRI2_FLUSH_VERSION >= 3 854 if (!pdp->invalidateAvailable && psc->f && 855 psc->f->base.version >= 3 && psc->f->invalidate) 856 psc->f->invalidate(pdraw->driDrawable); 857#endif 858 859 if (psc->texBuffer->base.version >= 2 && 860 psc->texBuffer->setTexBuffer2 != NULL) { 861 (*psc->texBuffer->setTexBuffer2) (pcp->driContext, 862 pdraw->base.textureTarget, 863 pdraw->base.textureFormat, 864 pdraw->driDrawable); 865 } 866 else { 867 (*psc->texBuffer->setTexBuffer) (pcp->driContext, 868 pdraw->base.textureTarget, 869 pdraw->driDrawable); 870 } 871 } 872} 873 874static void 875dri2_release_tex_image(Display * dpy, GLXDrawable drawable, int buffer) 876{ 877#if __DRI_TEX_BUFFER_VERSION >= 3 878 struct glx_context *gc = __glXGetCurrentContext(); 879 struct dri2_context *pcp = (struct dri2_context *) gc; 880 __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable); 881 struct glx_display *dpyPriv = __glXInitialize(dpy); 882 struct dri2_drawable *pdraw = (struct dri2_drawable *) base; 883 struct dri2_display *pdp = 884 (struct dri2_display *) dpyPriv->dri2Display; 885 struct dri2_screen *psc; 886 887 if (pdraw != NULL) { 888 psc = (struct dri2_screen *) base->psc; 889 890 if (psc->texBuffer->base.version >= 3 && 891 psc->texBuffer->releaseTexBuffer != NULL) { 892 (*psc->texBuffer->releaseTexBuffer) (pcp->driContext, 893 pdraw->base.textureTarget, 894 pdraw->driDrawable); 895 } 896 } 897#endif 898} 899 900static const struct glx_context_vtable dri2_context_vtable = { 901 dri2_destroy_context, 902 dri2_bind_context, 903 dri2_unbind_context, 904 dri2_wait_gl, 905 dri2_wait_x, 906 DRI_glXUseXFont, 907 dri2_bind_tex_image, 908 dri2_release_tex_image, 909 NULL, /* get_proc_address */ 910}; 911 912static void 913dri2BindExtensions(struct dri2_screen *psc, const __DRIextension **extensions) 914{ 915 int i; 916 917 __glXEnableDirectExtension(&psc->base, "GLX_SGI_video_sync"); 918 __glXEnableDirectExtension(&psc->base, "GLX_SGI_swap_control"); 919 __glXEnableDirectExtension(&psc->base, "GLX_MESA_swap_control"); 920 __glXEnableDirectExtension(&psc->base, "GLX_SGI_make_current_read"); 921 922 /* FIXME: if DRI2 version supports it... */ 923 __glXEnableDirectExtension(&psc->base, "INTEL_swap_event"); 924 925 if (psc->dri2->base.version >= 3) { 926 __glXEnableDirectExtension(&psc->base, "GLX_ARB_create_context"); 927 __glXEnableDirectExtension(&psc->base, "GLX_ARB_create_context_profile"); 928 } 929 930 for (i = 0; extensions[i]; i++) { 931 if ((strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0)) { 932 psc->texBuffer = (__DRItexBufferExtension *) extensions[i]; 933 __glXEnableDirectExtension(&psc->base, "GLX_EXT_texture_from_pixmap"); 934 } 935 936 if ((strcmp(extensions[i]->name, __DRI2_FLUSH) == 0)) { 937 psc->f = (__DRI2flushExtension *) extensions[i]; 938 /* internal driver extension, no GL extension exposed */ 939 } 940 941 if ((strcmp(extensions[i]->name, __DRI2_CONFIG_QUERY) == 0)) 942 psc->config = (__DRI2configQueryExtension *) extensions[i]; 943 944 if (((strcmp(extensions[i]->name, __DRI2_THROTTLE) == 0))) 945 psc->throttle = (__DRI2throttleExtension *) extensions[i]; 946 } 947} 948 949static const struct glx_screen_vtable dri2_screen_vtable = { 950 dri2_create_context, 951 dri2_create_context_attribs 952}; 953 954static struct glx_screen * 955dri2CreateScreen(int screen, struct glx_display * priv) 956{ 957 const __DRIconfig **driver_configs; 958 const __DRIextension **extensions; 959 const struct dri2_display *const pdp = (struct dri2_display *) 960 priv->dri2Display; 961 struct dri2_screen *psc; 962 __GLXDRIscreen *psp; 963 struct glx_config *configs = NULL, *visuals = NULL; 964 char *driverName, *deviceName; 965 drm_magic_t magic; 966 int i; 967 968 psc = Xmalloc(sizeof *psc); 969 if (psc == NULL) 970 return NULL; 971 972 memset(psc, 0, sizeof *psc); 973 psc->fd = -1; 974 975 if (!glx_screen_init(&psc->base, screen, priv)) { 976 Xfree(psc); 977 return NULL; 978 } 979 980 if (!DRI2Connect(priv->dpy, RootWindow(priv->dpy, screen), 981 &driverName, &deviceName)) { 982 glx_screen_cleanup(&psc->base); 983 XFree(psc); 984 InfoMessageF("screen %d does not appear to be DRI2 capable\n", screen); 985 return NULL; 986 } 987 988 psc->driver = driOpenDriver(driverName); 989 if (psc->driver == NULL) { 990 ErrorMessageF("driver pointer missing\n"); 991 goto handle_error; 992 } 993 994 extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS); 995 if (extensions == NULL) { 996 ErrorMessageF("driver exports no extensions (%s)\n", dlerror()); 997 goto handle_error; 998 } 999 1000 for (i = 0; extensions[i]; i++) { 1001 if (strcmp(extensions[i]->name, __DRI_CORE) == 0) 1002 psc->core = (__DRIcoreExtension *) extensions[i]; 1003 if (strcmp(extensions[i]->name, __DRI_DRI2) == 0) 1004 psc->dri2 = (__DRIdri2Extension *) extensions[i]; 1005 } 1006 1007 if (psc->core == NULL || psc->dri2 == NULL) { 1008 ErrorMessageF("core dri or dri2 extension not found\n"); 1009 goto handle_error; 1010 } 1011 1012 psc->fd = open(deviceName, O_RDWR); 1013 if (psc->fd < 0) { 1014 ErrorMessageF("failed to open drm device: %s\n", strerror(errno)); 1015 goto handle_error; 1016 } 1017 1018 if (drmGetMagic(psc->fd, &magic)) { 1019 ErrorMessageF("failed to get magic\n"); 1020 goto handle_error; 1021 } 1022 1023 if (!DRI2Authenticate(priv->dpy, RootWindow(priv->dpy, screen), magic)) { 1024 ErrorMessageF("failed to authenticate magic %d\n", magic); 1025 goto handle_error; 1026 } 1027 1028 1029 /* If the server does not support the protocol for 1030 * DRI2GetBuffersWithFormat, don't supply that interface to the driver. 1031 */ 1032 psc->driScreen = 1033 psc->dri2->createNewScreen(screen, psc->fd, 1034 (const __DRIextension **) 1035 &pdp->loader_extensions[0], 1036 &driver_configs, psc); 1037 1038 if (psc->driScreen == NULL) { 1039 ErrorMessageF("failed to create dri screen\n"); 1040 goto handle_error; 1041 } 1042 1043 extensions = psc->core->getExtensions(psc->driScreen); 1044 dri2BindExtensions(psc, extensions); 1045 1046 configs = driConvertConfigs(psc->core, psc->base.configs, driver_configs); 1047 visuals = driConvertConfigs(psc->core, psc->base.visuals, driver_configs); 1048 1049 if (!configs || !visuals) 1050 goto handle_error; 1051 1052 glx_config_destroy_list(psc->base.configs); 1053 psc->base.configs = configs; 1054 glx_config_destroy_list(psc->base.visuals); 1055 psc->base.visuals = visuals; 1056 1057 psc->driver_configs = driver_configs; 1058 1059 psc->base.vtable = &dri2_screen_vtable; 1060 psp = &psc->vtable; 1061 psc->base.driScreen = psp; 1062 psp->destroyScreen = dri2DestroyScreen; 1063 psp->createDrawable = dri2CreateDrawable; 1064 psp->swapBuffers = dri2SwapBuffers; 1065 psp->getDrawableMSC = NULL; 1066 psp->waitForMSC = NULL; 1067 psp->waitForSBC = NULL; 1068 psp->setSwapInterval = NULL; 1069 psp->getSwapInterval = NULL; 1070 1071 if (pdp->driMinor >= 2) { 1072#ifdef X_DRI2GetMSC 1073 psp->getDrawableMSC = dri2DrawableGetMSC; 1074#endif 1075#ifdef X_DRI2WaitMSC 1076 psp->waitForMSC = dri2WaitForMSC; 1077 psp->waitForSBC = dri2WaitForSBC; 1078#endif 1079#ifdef X_DRI2SwapInterval 1080 psp->setSwapInterval = dri2SetSwapInterval; 1081 psp->getSwapInterval = dri2GetSwapInterval; 1082#endif 1083#if defined(X_DRI2GetMSC) && defined(X_DRI2WaitMSC) && defined(X_DRI2SwapInterval) 1084 __glXEnableDirectExtension(&psc->base, "GLX_OML_sync_control"); 1085#endif 1086 } 1087 1088 /* DRI2 suports SubBuffer through DRI2CopyRegion, so it's always 1089 * available.*/ 1090 psp->copySubBuffer = dri2CopySubBuffer; 1091 __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer"); 1092 1093 Xfree(driverName); 1094 Xfree(deviceName); 1095 1096 return &psc->base; 1097 1098handle_error: 1099 if (configs) 1100 glx_config_destroy_list(configs); 1101 if (visuals) 1102 glx_config_destroy_list(visuals); 1103 if (psc->driScreen) 1104 psc->core->destroyScreen(psc->driScreen); 1105 psc->driScreen = NULL; 1106 if (psc->fd >= 0) 1107 close(psc->fd); 1108 if (psc->driver) 1109 dlclose(psc->driver); 1110 1111 Xfree(driverName); 1112 Xfree(deviceName); 1113 glx_screen_cleanup(&psc->base); 1114 XFree(psc); 1115 1116 return NULL; 1117} 1118 1119/* Called from __glXFreeDisplayPrivate. 1120 */ 1121static void 1122dri2DestroyDisplay(__GLXDRIdisplay * dpy) 1123{ 1124 struct dri2_display *pdp = (struct dri2_display *) dpy; 1125 1126 __glxHashDestroy(pdp->dri2Hash); 1127 Xfree(dpy); 1128} 1129 1130_X_HIDDEN __GLXDRIdrawable * 1131dri2GetGlxDrawableFromXDrawableId(Display *dpy, XID id) 1132{ 1133 struct glx_display *d = __glXInitialize(dpy); 1134 struct dri2_display *pdp = (struct dri2_display *) d->dri2Display; 1135 __GLXDRIdrawable *pdraw; 1136 1137 if (__glxHashLookup(pdp->dri2Hash, id, (void *) &pdraw) == 0) 1138 return pdraw; 1139 1140 return NULL; 1141} 1142 1143/* 1144 * Allocate, initialize and return a __DRIdisplayPrivate object. 1145 * This is called from __glXInitialize() when we are given a new 1146 * display pointer. 1147 */ 1148_X_HIDDEN __GLXDRIdisplay * 1149dri2CreateDisplay(Display * dpy) 1150{ 1151 struct dri2_display *pdp; 1152 int eventBase, errorBase, i; 1153 1154 if (!DRI2QueryExtension(dpy, &eventBase, &errorBase)) 1155 return NULL; 1156 1157 pdp = Xmalloc(sizeof *pdp); 1158 if (pdp == NULL) 1159 return NULL; 1160 1161 if (!DRI2QueryVersion(dpy, &pdp->driMajor, &pdp->driMinor)) { 1162 Xfree(pdp); 1163 return NULL; 1164 } 1165 1166 pdp->driPatch = 0; 1167 pdp->swapAvailable = (pdp->driMinor >= 2); 1168 pdp->invalidateAvailable = (pdp->driMinor >= 3); 1169 1170 pdp->base.destroyDisplay = dri2DestroyDisplay; 1171 pdp->base.createScreen = dri2CreateScreen; 1172 1173 i = 0; 1174 if (pdp->driMinor < 1) 1175 pdp->loader_extensions[i++] = &dri2LoaderExtension_old.base; 1176 else 1177 pdp->loader_extensions[i++] = &dri2LoaderExtension.base; 1178 1179 pdp->loader_extensions[i++] = &systemTimeExtension.base; 1180 1181#ifdef __DRI_USE_INVALIDATE 1182 pdp->loader_extensions[i++] = &dri2UseInvalidate.base; 1183#endif 1184 pdp->loader_extensions[i++] = NULL; 1185 1186 pdp->dri2Hash = __glxHashCreate(); 1187 if (pdp->dri2Hash == NULL) { 1188 Xfree(pdp); 1189 return NULL; 1190 } 1191 1192 return &pdp->base; 1193} 1194 1195#endif /* GLX_DIRECT_RENDERING */ 1196