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