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