dri2_glx.c revision bab13969d8bf3ff9259524c3f4ab96d81485ccef
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 <X11/extensions/Xdamage.h> 38#include "glapi.h" 39#include "glxclient.h" 40#include <X11/extensions/dri2proto.h> 41#include "xf86dri.h" 42#include <dlfcn.h> 43#include <fcntl.h> 44#include <unistd.h> 45#include <sys/types.h> 46#include <sys/mman.h> 47#include "xf86drm.h" 48#include "dri2.h" 49#include "dri_common.h" 50 51/* From xmlpool/options.h, user exposed so should be stable */ 52#define DRI_CONF_VBLANK_NEVER 0 53#define DRI_CONF_VBLANK_DEF_INTERVAL_0 1 54#define DRI_CONF_VBLANK_DEF_INTERVAL_1 2 55#define DRI_CONF_VBLANK_ALWAYS_SYNC 3 56 57#undef DRI2_MINOR 58#define DRI2_MINOR 1 59 60struct dri2_display 61{ 62 __GLXDRIdisplay base; 63 64 /* 65 ** XFree86-DRI version information 66 */ 67 int driMajor; 68 int driMinor; 69 int driPatch; 70 int swapAvailable; 71 int invalidateAvailable; 72 73 __glxHashTable *dri2Hash; 74 75 const __DRIextension *loader_extensions[4]; 76}; 77 78struct dri2_screen { 79 __GLXscreenConfigs base; 80 81 __DRIscreen *driScreen; 82 __GLXDRIscreen vtable; 83 const __DRIdri2Extension *dri2; 84 const __DRIcoreExtension *core; 85 86 const __DRI2flushExtension *f; 87 const __DRI2configQueryExtension *config; 88 const __DRItexBufferExtension *texBuffer; 89 const __DRIconfig **driver_configs; 90 91 void *driver; 92 int fd; 93}; 94 95struct dri2_context 96{ 97 __GLXDRIcontext base; 98 __DRIcontext *driContext; 99 __GLXscreenConfigs *psc; 100}; 101 102struct dri2_drawable 103{ 104 __GLXDRIdrawable base; 105 __DRIdrawable *driDrawable; 106 __DRIbuffer buffers[5]; 107 int bufferCount; 108 int width, height; 109 int have_back; 110 int have_fake_front; 111 int swap_interval; 112}; 113 114static void 115dri2DestroyContext(__GLXDRIcontext *context, 116 __GLXscreenConfigs *base, Display *dpy) 117{ 118 struct dri2_context *pcp = (struct dri2_context *) context; 119 struct dri2_screen *psc = (struct dri2_screen *) base; 120 121 (*psc->core->destroyContext) (pcp->driContext); 122 123 Xfree(pcp); 124} 125 126static Bool 127dri2BindContext(__GLXDRIcontext *context, 128 __GLXDRIdrawable *draw, __GLXDRIdrawable *read) 129{ 130 struct dri2_context *pcp = (struct dri2_context *) context; 131 struct dri2_screen *psc = (struct dri2_screen *) pcp->psc; 132 struct dri2_drawable *pdr = (struct dri2_drawable *) draw; 133 struct dri2_drawable *prd = (struct dri2_drawable *) read; 134 135 return (*psc->core->bindContext) (pcp->driContext, 136 pdr->driDrawable, prd->driDrawable); 137} 138 139static void 140dri2UnbindContext(__GLXDRIcontext *context) 141{ 142 struct dri2_context *pcp = (struct dri2_context *) context; 143 struct dri2_screen *psc = (struct dri2_screen *) pcp->psc; 144 145 (*psc->core->unbindContext) (pcp->driContext); 146} 147 148static __GLXDRIcontext * 149dri2CreateContext(__GLXscreenConfigs *base, 150 const __GLcontextModes * mode, 151 GLXContext gc, GLXContext shareList, int renderType) 152{ 153 struct dri2_context *pcp, *pcp_shared; 154 struct dri2_screen *psc = (struct dri2_screen *) base; 155 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) mode; 156 __DRIcontext *shared = NULL; 157 158 if (shareList) { 159 pcp_shared = (struct dri2_context *) shareList->driContext; 160 shared = pcp_shared->driContext; 161 } 162 163 pcp = Xmalloc(sizeof *pcp); 164 if (pcp == NULL) 165 return NULL; 166 167 pcp->psc = &psc->base; 168 pcp->driContext = 169 (*psc->dri2->createNewContext) (psc->driScreen, 170 config->driConfig, shared, pcp); 171 gc->__driContext = pcp->driContext; 172 173 if (pcp->driContext == NULL) { 174 Xfree(pcp); 175 return NULL; 176 } 177 178 pcp->base.destroyContext = dri2DestroyContext; 179 pcp->base.bindContext = dri2BindContext; 180 pcp->base.unbindContext = dri2UnbindContext; 181 182 return &pcp->base; 183} 184 185static void 186dri2DestroyDrawable(__GLXDRIdrawable *base) 187{ 188 struct dri2_screen *psc = (struct dri2_screen *) base->psc; 189 struct dri2_drawable *pdraw = (struct dri2_drawable *) base; 190 __GLXdisplayPrivate *dpyPriv = psc->base.display; 191 struct dri2_display *pdp = (struct dri2_display *)dpyPriv->dri2Display; 192 193 __glxHashDelete(pdp->dri2Hash, pdraw->base.xDrawable); 194 (*psc->core->destroyDrawable) (pdraw->driDrawable); 195 DRI2DestroyDrawable(psc->base.dpy, pdraw->base.xDrawable); 196 Xfree(pdraw); 197} 198 199static __GLXDRIdrawable * 200dri2CreateDrawable(__GLXscreenConfigs *base, XID xDrawable, 201 GLXDrawable drawable, const __GLcontextModes * modes) 202{ 203 struct dri2_drawable *pdraw; 204 struct dri2_screen *psc = (struct dri2_screen *) base; 205 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) modes; 206 __GLXdisplayPrivate *dpyPriv; 207 struct dri2_display *pdp; 208 GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1; 209 210 pdraw = Xmalloc(sizeof(*pdraw)); 211 if (!pdraw) 212 return NULL; 213 214 pdraw->base.destroyDrawable = dri2DestroyDrawable; 215 pdraw->base.xDrawable = xDrawable; 216 pdraw->base.drawable = drawable; 217 pdraw->base.psc = &psc->base; 218 pdraw->bufferCount = 0; 219 pdraw->swap_interval = 1; /* default may be overridden below */ 220 pdraw->have_back = 0; 221 222 if (psc->config) 223 psc->config->configQueryi(psc->driScreen, 224 "vblank_mode", &vblank_mode); 225 226 switch (vblank_mode) { 227 case DRI_CONF_VBLANK_NEVER: 228 case DRI_CONF_VBLANK_DEF_INTERVAL_0: 229 pdraw->swap_interval = 0; 230 break; 231 case DRI_CONF_VBLANK_DEF_INTERVAL_1: 232 case DRI_CONF_VBLANK_ALWAYS_SYNC: 233 default: 234 pdraw->swap_interval = 1; 235 break; 236 } 237 238 DRI2CreateDrawable(psc->base.dpy, xDrawable); 239 240 dpyPriv = __glXInitialize(psc->base.dpy); 241 pdp = (struct dri2_display *)dpyPriv->dri2Display;; 242 /* Create a new drawable */ 243 pdraw->driDrawable = 244 (*psc->dri2->createNewDrawable) (psc->driScreen, 245 config->driConfig, pdraw); 246 247 if (!pdraw->driDrawable) { 248 DRI2DestroyDrawable(psc->base.dpy, xDrawable); 249 Xfree(pdraw); 250 return NULL; 251 } 252 253 if (__glxHashInsert(pdp->dri2Hash, xDrawable, pdraw)) { 254 (*psc->core->destroyDrawable) (pdraw->driDrawable); 255 DRI2DestroyDrawable(psc->base.dpy, xDrawable); 256 Xfree(pdraw); 257 return None; 258 } 259 260 261#ifdef X_DRI2SwapInterval 262 /* 263 * Make sure server has the same swap interval we do for the new 264 * drawable. 265 */ 266 if (pdp->swapAvailable) 267 DRI2SwapInterval(psc->base.dpy, xDrawable, pdraw->swap_interval); 268#endif 269 270 return &pdraw->base; 271} 272 273#ifdef X_DRI2GetMSC 274 275static int 276dri2DrawableGetMSC(__GLXscreenConfigs *psc, __GLXDRIdrawable *pdraw, 277 int64_t *ust, int64_t *msc, int64_t *sbc) 278{ 279 CARD64 dri2_ust, dri2_msc, dri2_sbc; 280 int ret; 281 282 ret = DRI2GetMSC(psc->dpy, pdraw->xDrawable, 283 &dri2_ust, &dri2_msc, &dri2_sbc); 284 *ust = dri2_ust; 285 *msc = dri2_msc; 286 *sbc = dri2_sbc; 287 288 return ret; 289} 290 291#endif 292 293 294#ifdef X_DRI2WaitMSC 295 296static int 297dri2WaitForMSC(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor, 298 int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc) 299{ 300 CARD64 dri2_ust, dri2_msc, dri2_sbc; 301 int ret; 302 303 ret = DRI2WaitMSC(pdraw->psc->dpy, pdraw->xDrawable, target_msc, divisor, 304 remainder, &dri2_ust, &dri2_msc, &dri2_sbc); 305 *ust = dri2_ust; 306 *msc = dri2_msc; 307 *sbc = dri2_sbc; 308 309 return ret; 310} 311 312static int 313dri2WaitForSBC(__GLXDRIdrawable *pdraw, int64_t target_sbc, int64_t *ust, 314 int64_t *msc, int64_t *sbc) 315{ 316 CARD64 dri2_ust, dri2_msc, dri2_sbc; 317 int ret; 318 319 ret = DRI2WaitSBC(pdraw->psc->dpy, pdraw->xDrawable, 320 target_sbc, &dri2_ust, &dri2_msc, &dri2_sbc); 321 *ust = dri2_ust; 322 *msc = dri2_msc; 323 *sbc = dri2_sbc; 324 325 return ret; 326} 327 328#endif /* X_DRI2WaitMSC */ 329 330static void 331dri2CopySubBuffer(__GLXDRIdrawable *pdraw, int x, int y, int width, int height) 332{ 333 struct dri2_drawable *priv = (struct dri2_drawable *) pdraw; 334 struct dri2_screen *psc = (struct dri2_screen *) pdraw->psc; 335 XRectangle xrect; 336 XserverRegion region; 337 338 /* Check we have the right attachments */ 339 if (!priv->have_back) 340 return; 341 342 xrect.x = x; 343 xrect.y = priv->height - y - height; 344 xrect.width = width; 345 xrect.height = height; 346 347#ifdef __DRI2_FLUSH 348 if (psc->f) 349 (*psc->f->flush) (priv->driDrawable); 350#endif 351 352 region = XFixesCreateRegion(psc->base.dpy, &xrect, 1); 353 DRI2CopyRegion(psc->base.dpy, pdraw->xDrawable, region, 354 DRI2BufferFrontLeft, DRI2BufferBackLeft); 355 XFixesDestroyRegion(psc->base.dpy, region); 356 357 /* Refresh the fake front (if present) after we just damaged the real 358 * front. 359 */ 360 DRI2CopyRegion(psc->base.dpy, pdraw->xDrawable, region, 361 DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft); 362 XFixesDestroyRegion(psc->base.dpy, region); 363} 364 365static void 366dri2_copy_drawable(struct dri2_drawable *priv, int dest, int src) 367{ 368 XRectangle xrect; 369 XserverRegion region; 370 struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc; 371 372 xrect.x = 0; 373 xrect.y = 0; 374 xrect.width = priv->width; 375 xrect.height = priv->height; 376 377#ifdef __DRI2_FLUSH 378 if (psc->f) 379 (*psc->f->flush) (priv->driDrawable); 380#endif 381 382 region = XFixesCreateRegion(psc->base.dpy, &xrect, 1); 383 DRI2CopyRegion(psc->base.dpy, priv->base.xDrawable, region, dest, src); 384 XFixesDestroyRegion(psc->base.dpy, region); 385 386} 387 388static void 389dri2WaitX(__GLXDRIdrawable *pdraw) 390{ 391 struct dri2_drawable *priv = (struct dri2_drawable *) pdraw; 392 393 if (!priv->have_fake_front) 394 return; 395 396 dri2_copy_drawable(priv, DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft); 397} 398 399static void 400dri2WaitGL(__GLXDRIdrawable * pdraw) 401{ 402 struct dri2_drawable *priv = (struct dri2_drawable *) pdraw; 403 404 if (!priv->have_fake_front) 405 return; 406 407 dri2_copy_drawable(priv, DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft); 408} 409 410static void 411dri2FlushFrontBuffer(__DRIdrawable *driDrawable, void *loaderPrivate) 412{ 413 struct dri2_drawable *pdraw = loaderPrivate; 414 __GLXdisplayPrivate *priv = __glXInitialize(pdraw->base.psc->dpy); 415 struct dri2_display *pdp = (struct dri2_display *)priv->dri2Display; 416 417 /* Old servers don't send invalidate events */ 418 if (!pdp->invalidateAvailable) 419 dri2InvalidateBuffers(priv->dpy, pdraw->base.drawable); 420 421 dri2WaitGL(loaderPrivate); 422} 423 424 425static void 426dri2DestroyScreen(__GLXscreenConfigs *base) 427{ 428 struct dri2_screen *psc = (struct dri2_screen *) base; 429 430 /* Free the direct rendering per screen data */ 431 (*psc->core->destroyScreen) (psc->driScreen); 432 driDestroyConfigs(psc->driver_configs); 433 close(psc->fd); 434 Xfree(psc); 435} 436 437/** 438 * Process list of buffer received from the server 439 * 440 * Processes the list of buffers received in a reply from the server to either 441 * \c DRI2GetBuffers or \c DRI2GetBuffersWithFormat. 442 */ 443static void 444process_buffers(struct dri2_drawable * pdraw, DRI2Buffer * buffers, 445 unsigned count) 446{ 447 int i; 448 449 pdraw->bufferCount = count; 450 pdraw->have_fake_front = 0; 451 pdraw->have_back = 0; 452 453 /* This assumes the DRI2 buffer attachment tokens matches the 454 * __DRIbuffer tokens. */ 455 for (i = 0; i < count; i++) { 456 pdraw->buffers[i].attachment = buffers[i].attachment; 457 pdraw->buffers[i].name = buffers[i].name; 458 pdraw->buffers[i].pitch = buffers[i].pitch; 459 pdraw->buffers[i].cpp = buffers[i].cpp; 460 pdraw->buffers[i].flags = buffers[i].flags; 461 if (pdraw->buffers[i].attachment == __DRI_BUFFER_FAKE_FRONT_LEFT) 462 pdraw->have_fake_front = 1; 463 if (pdraw->buffers[i].attachment == __DRI_BUFFER_BACK_LEFT) 464 pdraw->have_back = 1; 465 } 466 467} 468 469static int64_t 470dri2SwapBuffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor, 471 int64_t remainder) 472{ 473 struct dri2_drawable *priv = (struct dri2_drawable *) pdraw; 474 __GLXdisplayPrivate *dpyPriv = __glXInitialize(priv->base.psc->dpy); 475 struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc; 476 struct dri2_display *pdp = 477 (struct dri2_display *)dpyPriv->dri2Display; 478 CARD64 ret; 479 480#ifdef __DRI2_FLUSH 481 if (psc->f) 482 (*psc->f->flush)(priv->driDrawable); 483#endif 484 485 /* Old servers don't send invalidate events */ 486 if (!pdp->invalidateAvailable) 487 dri2InvalidateBuffers(dpyPriv->dpy, pdraw->drawable); 488 489 /* Old servers can't handle swapbuffers */ 490 if (!pdp->swapAvailable) { 491 dri2CopySubBuffer(pdraw, 0, 0, priv->width, priv->height); 492 return 0; 493 } 494 495#ifdef X_DRI2SwapBuffers 496 DRI2SwapBuffers(psc->base.dpy, pdraw->xDrawable, target_msc, divisor, 497 remainder, &ret); 498#endif 499 500 return ret; 501} 502 503static __DRIbuffer * 504dri2GetBuffers(__DRIdrawable * driDrawable, 505 int *width, int *height, 506 unsigned int *attachments, int count, 507 int *out_count, void *loaderPrivate) 508{ 509 struct dri2_drawable *pdraw = loaderPrivate; 510 DRI2Buffer *buffers; 511 512 buffers = DRI2GetBuffers(pdraw->base.psc->dpy, pdraw->base.xDrawable, 513 width, height, attachments, count, out_count); 514 if (buffers == NULL) 515 return NULL; 516 517 pdraw->width = *width; 518 pdraw->height = *height; 519 process_buffers(pdraw, buffers, *out_count); 520 521 Xfree(buffers); 522 523 return pdraw->buffers; 524} 525 526static __DRIbuffer * 527dri2GetBuffersWithFormat(__DRIdrawable * driDrawable, 528 int *width, int *height, 529 unsigned int *attachments, int count, 530 int *out_count, void *loaderPrivate) 531{ 532 struct dri2_drawable *pdraw = loaderPrivate; 533 DRI2Buffer *buffers; 534 535 buffers = DRI2GetBuffersWithFormat(pdraw->base.psc->dpy, 536 pdraw->base.xDrawable, 537 width, height, attachments, 538 count, out_count); 539 if (buffers == NULL) 540 return NULL; 541 542 pdraw->width = *width; 543 pdraw->height = *height; 544 process_buffers(pdraw, buffers, *out_count); 545 546 Xfree(buffers); 547 548 return pdraw->buffers; 549} 550 551#ifdef X_DRI2SwapInterval 552 553static int 554dri2SetSwapInterval(__GLXDRIdrawable *pdraw, int interval) 555{ 556 struct dri2_drawable *priv = (struct dri2_drawable *) pdraw; 557 GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1; 558 struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc; 559 560 if (psc->config) 561 psc->config->configQueryi(psc->driScreen, 562 "vblank_mode", &vblank_mode); 563 564 switch (vblank_mode) { 565 case DRI_CONF_VBLANK_NEVER: 566 return GLX_BAD_VALUE; 567 case DRI_CONF_VBLANK_ALWAYS_SYNC: 568 if (interval <= 0) 569 return GLX_BAD_VALUE; 570 break; 571 default: 572 break; 573 } 574 575 DRI2SwapInterval(priv->base.psc->dpy, priv->base.xDrawable, interval); 576 priv->swap_interval = interval; 577 578 return 0; 579} 580 581static int 582dri2GetSwapInterval(__GLXDRIdrawable *pdraw) 583{ 584 struct dri2_drawable *priv = (struct dri2_drawable *) pdraw; 585 586 return priv->swap_interval; 587} 588 589#endif /* X_DRI2SwapInterval */ 590 591static const __DRIdri2LoaderExtension dri2LoaderExtension = { 592 {__DRI_DRI2_LOADER, __DRI_DRI2_LOADER_VERSION}, 593 dri2GetBuffers, 594 dri2FlushFrontBuffer, 595 dri2GetBuffersWithFormat, 596}; 597 598static const __DRIdri2LoaderExtension dri2LoaderExtension_old = { 599 {__DRI_DRI2_LOADER, __DRI_DRI2_LOADER_VERSION}, 600 dri2GetBuffers, 601 dri2FlushFrontBuffer, 602 NULL, 603}; 604 605#ifdef __DRI_USE_INVALIDATE 606static const __DRIuseInvalidateExtension dri2UseInvalidate = { 607 { __DRI_USE_INVALIDATE, __DRI_USE_INVALIDATE_VERSION } 608}; 609#endif 610 611_X_HIDDEN void 612dri2InvalidateBuffers(Display *dpy, XID drawable) 613{ 614 __GLXDRIdrawable *pdraw = 615 dri2GetGlxDrawableFromXDrawableId(dpy, drawable); 616 struct dri2_screen *psc = (struct dri2_screen *) pdraw->psc; 617 struct dri2_drawable *pdp = (struct dri2_drawable *) pdraw; 618 619#if __DRI2_FLUSH_VERSION >= 3 620 if (pdraw && psc->f) 621 psc->f->invalidate(pdp->driDrawable); 622#endif 623} 624 625static void 626dri2_bind_tex_image(Display * dpy, 627 GLXDrawable drawable, 628 int buffer, const int *attrib_list) 629{ 630 GLXContext gc = __glXGetCurrentContext(); 631 __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable, NULL); 632 __GLXdisplayPrivate *dpyPriv = __glXInitialize(dpy); 633 struct dri2_drawable *pdraw = (struct dri2_drawable *) base; 634 struct dri2_display *pdp = 635 (struct dri2_display *) dpyPriv->dri2Display; 636 struct dri2_screen *psc = (struct dri2_screen *) base->psc; 637 638 if (pdraw != NULL) { 639 640#if __DRI2_FLUSH_VERSION >= 3 641 if (!pdp->invalidateAvailable && psc->f) 642 psc->f->invalidate(pdraw->driDrawable); 643#endif 644 645 if (psc->texBuffer->base.version >= 2 && 646 psc->texBuffer->setTexBuffer2 != NULL) { 647 (*psc->texBuffer->setTexBuffer2) (gc->__driContext, 648 pdraw->base.textureTarget, 649 pdraw->base.textureFormat, 650 pdraw->driDrawable); 651 } 652 else { 653 (*psc->texBuffer->setTexBuffer) (gc->__driContext, 654 pdraw->base.textureTarget, 655 pdraw->driDrawable); 656 } 657 } 658} 659 660static void 661dri2_release_tex_image(Display * dpy, GLXDrawable drawable, int buffer) 662{ 663} 664 665static const struct glx_context_vtable dri2_context_vtable = { 666 dri2_bind_tex_image, 667 dri2_release_tex_image, 668}; 669 670static void 671dri2BindExtensions(struct dri2_screen *psc, const __DRIextension **extensions) 672{ 673 int i; 674 675 __glXEnableDirectExtension(&psc->base, "GLX_SGI_video_sync"); 676 __glXEnableDirectExtension(&psc->base, "GLX_SGI_swap_control"); 677 __glXEnableDirectExtension(&psc->base, "GLX_MESA_swap_control"); 678 679 /* FIXME: if DRI2 version supports it... */ 680 __glXEnableDirectExtension(&psc->base, "INTEL_swap_event"); 681 682 for (i = 0; extensions[i]; i++) { 683 if ((strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0)) { 684 psc->texBuffer = (__DRItexBufferExtension *) extensions[i]; 685 __glXEnableDirectExtension(&psc->base, "GLX_EXT_texture_from_pixmap"); 686 } 687 688 if ((strcmp(extensions[i]->name, __DRI2_FLUSH) == 0)) { 689 psc->f = (__DRI2flushExtension *) extensions[i]; 690 /* internal driver extension, no GL extension exposed */ 691 } 692 693 if ((strcmp(extensions[i]->name, __DRI2_CONFIG_QUERY) == 0)) 694 psc->config = (__DRI2configQueryExtension *) extensions[i]; 695 } 696} 697 698 699static __GLXscreenConfigs * 700dri2CreateScreen(int screen, __GLXdisplayPrivate * priv) 701{ 702 const __DRIconfig **driver_configs; 703 const __DRIextension **extensions; 704 const struct dri2_display *const pdp = (struct dri2_display *) 705 priv->dri2Display; 706 struct dri2_screen *psc; 707 __GLXDRIscreen *psp; 708 char *driverName, *deviceName; 709 drm_magic_t magic; 710 int i; 711 712 psc = Xmalloc(sizeof *psc); 713 if (psc == NULL) 714 return NULL; 715 716 memset(psc, 0, sizeof *psc); 717 if (!glx_screen_init(&psc->base, screen, priv)) 718 return NULL; 719 720 if (!DRI2Connect(priv->dpy, RootWindow(priv->dpy, screen), 721 &driverName, &deviceName)) { 722 XFree(psc); 723 return NULL; 724 } 725 726 psc->driver = driOpenDriver(driverName); 727 if (psc->driver == NULL) { 728 ErrorMessageF("driver pointer missing\n"); 729 goto handle_error; 730 } 731 732 extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS); 733 if (extensions == NULL) { 734 ErrorMessageF("driver exports no extensions (%s)\n", dlerror()); 735 goto handle_error; 736 } 737 738 for (i = 0; extensions[i]; i++) { 739 if (strcmp(extensions[i]->name, __DRI_CORE) == 0) 740 psc->core = (__DRIcoreExtension *) extensions[i]; 741 if (strcmp(extensions[i]->name, __DRI_DRI2) == 0) 742 psc->dri2 = (__DRIdri2Extension *) extensions[i]; 743 } 744 745 if (psc->core == NULL || psc->dri2 == NULL) { 746 ErrorMessageF("core dri or dri2 extension not found\n"); 747 goto handle_error; 748 } 749 750 psc->fd = open(deviceName, O_RDWR); 751 if (psc->fd < 0) { 752 ErrorMessageF("failed to open drm device: %s\n", strerror(errno)); 753 goto handle_error; 754 } 755 756 if (drmGetMagic(psc->fd, &magic)) { 757 ErrorMessageF("failed to get magic\n"); 758 goto handle_error; 759 } 760 761 if (!DRI2Authenticate(priv->dpy, RootWindow(priv->dpy, screen), magic)) { 762 ErrorMessageF("failed to authenticate magic %d\n", magic); 763 goto handle_error; 764 } 765 766 767 /* If the server does not support the protocol for 768 * DRI2GetBuffersWithFormat, don't supply that interface to the driver. 769 */ 770 psc->driScreen = 771 psc->dri2->createNewScreen(screen, psc->fd, 772 (const __DRIextension **) 773 &pdp->loader_extensions[0], 774 &driver_configs, psc); 775 776 if (psc->driScreen == NULL) { 777 ErrorMessageF("failed to create dri screen\n"); 778 goto handle_error; 779 } 780 781 extensions = psc->core->getExtensions(psc->driScreen); 782 driBindCommonExtensions(&psc->base, extensions); 783 dri2BindExtensions(psc, extensions); 784 785 psc->base.configs = 786 driConvertConfigs(psc->core, psc->base.configs, driver_configs); 787 psc->base.visuals = 788 driConvertConfigs(psc->core, psc->base.visuals, driver_configs); 789 790 psc->driver_configs = driver_configs; 791 792 psp = &psc->vtable; 793 psc->base.driScreen = psp; 794 psp->destroyScreen = dri2DestroyScreen; 795 psp->createContext = dri2CreateContext; 796 psp->createDrawable = dri2CreateDrawable; 797 psp->swapBuffers = dri2SwapBuffers; 798 psp->waitGL = dri2WaitGL; 799 psp->waitX = dri2WaitX; 800 psp->getDrawableMSC = NULL; 801 psp->waitForMSC = NULL; 802 psp->waitForSBC = NULL; 803 psp->setSwapInterval = NULL; 804 psp->getSwapInterval = NULL; 805 806 if (pdp->driMinor >= 2) { 807#ifdef X_DRI2GetMSC 808 psp->getDrawableMSC = dri2DrawableGetMSC; 809#endif 810#ifdef X_DRI2WaitMSC 811 psp->waitForMSC = dri2WaitForMSC; 812 psp->waitForSBC = dri2WaitForSBC; 813#endif 814#ifdef X_DRI2SwapInterval 815 psp->setSwapInterval = dri2SetSwapInterval; 816 psp->getSwapInterval = dri2GetSwapInterval; 817#endif 818#if defined(X_DRI2GetMSC) && defined(X_DRI2WaitMSC) && defined(X_DRI2SwapInterval) 819 __glXEnableDirectExtension(&psc->base, "GLX_OML_sync_control"); 820#endif 821 } 822 823 /* DRI2 suports SubBuffer through DRI2CopyRegion, so it's always 824 * available.*/ 825 psp->copySubBuffer = dri2CopySubBuffer; 826 __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer"); 827 828 psc->base.direct_context_vtable = &dri2_context_vtable; 829 830 Xfree(driverName); 831 Xfree(deviceName); 832 833 return &psc->base; 834 835handle_error: 836 Xfree(driverName); 837 Xfree(deviceName); 838 XFree(psc); 839 840 /* FIXME: clean up here */ 841 842 return NULL; 843} 844 845/* Called from __glXFreeDisplayPrivate. 846 */ 847static void 848dri2DestroyDisplay(__GLXDRIdisplay * dpy) 849{ 850 Xfree(dpy); 851} 852 853_X_HIDDEN __GLXDRIdrawable * 854dri2GetGlxDrawableFromXDrawableId(Display *dpy, XID id) 855{ 856 __GLXdisplayPrivate *d = __glXInitialize(dpy); 857 struct dri2_display *pdp = (struct dri2_display *) d->dri2Display; 858 __GLXDRIdrawable *pdraw; 859 860 if (__glxHashLookup(pdp->dri2Hash, id, (void *) &pdraw) == 0) 861 return pdraw; 862 863 return NULL; 864} 865 866/* 867 * Allocate, initialize and return a __DRIdisplayPrivate object. 868 * This is called from __glXInitialize() when we are given a new 869 * display pointer. 870 */ 871_X_HIDDEN __GLXDRIdisplay * 872dri2CreateDisplay(Display * dpy) 873{ 874 struct dri2_display *pdp; 875 int eventBase, errorBase, i; 876 877 if (!DRI2QueryExtension(dpy, &eventBase, &errorBase)) 878 return NULL; 879 880 pdp = Xmalloc(sizeof *pdp); 881 if (pdp == NULL) 882 return NULL; 883 884 if (!DRI2QueryVersion(dpy, &pdp->driMajor, &pdp->driMinor)) { 885 Xfree(pdp); 886 return NULL; 887 } 888 889 pdp->driPatch = 0; 890 pdp->swapAvailable = (pdp->driMinor >= 2); 891 pdp->invalidateAvailable = (pdp->driMinor >= 3); 892 893 pdp->base.destroyDisplay = dri2DestroyDisplay; 894 pdp->base.createScreen = dri2CreateScreen; 895 896 i = 0; 897 if (pdp->driMinor < 1) 898 pdp->loader_extensions[i++] = &dri2LoaderExtension_old.base; 899 else 900 pdp->loader_extensions[i++] = &dri2LoaderExtension.base; 901 902 pdp->loader_extensions[i++] = &systemTimeExtension.base; 903 904#ifdef __DRI_USE_INVALIDATE 905 pdp->loader_extensions[i++] = &dri2UseInvalidate.base; 906#endif 907 pdp->loader_extensions[i++] = NULL; 908 909 pdp->dri2Hash = __glxHashCreate(); 910 if (pdp->dri2Hash == NULL) { 911 Xfree(pdp); 912 return NULL; 913 } 914 915 return &pdp->base; 916} 917 918#endif /* GLX_DIRECT_RENDERING */ 919