dri2_glx.c revision b006d465ea0ea680326f702ad248544c576301a2
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 /* should get a fence ID back from here at some point */ 312 DRI2CopyRegion(pdraw->psc->dpy, pdraw->xDrawable, region, 313 DRI2BufferFrontLeft, DRI2BufferBackLeft); 314 XFixesDestroyRegion(pdraw->psc->dpy, region); 315 316 /* Refresh the fake front (if present) after we just damaged the real 317 * front. 318 */ 319 DRI2CopyRegion(pdraw->psc->dpy, pdraw->xDrawable, region, 320 DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft); 321 XFixesDestroyRegion(pdraw->psc->dpy, region); 322} 323 324static void 325dri2WaitX(__GLXDRIdrawable *pdraw) 326{ 327 __GLXDRIdrawablePrivate *priv = (__GLXDRIdrawablePrivate *) pdraw; 328 XRectangle xrect; 329 XserverRegion region; 330 331 /* Check we have the right attachments */ 332 if (!priv->have_fake_front) 333 return; 334 335 xrect.x = 0; 336 xrect.y = 0; 337 xrect.width = priv->width; 338 xrect.height = priv->height; 339 340#ifdef __DRI2_FLUSH 341 if (pdraw->psc->f) 342 (*pdraw->psc->f->flush) (pdraw->driDrawable); 343#endif 344 345 region = XFixesCreateRegion(pdraw->psc->dpy, &xrect, 1); 346 DRI2CopyRegion(pdraw->psc->dpy, pdraw->xDrawable, region, 347 DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft); 348 XFixesDestroyRegion(pdraw->psc->dpy, region); 349} 350 351static void 352dri2WaitGL(__GLXDRIdrawable * pdraw) 353{ 354 __GLXDRIdrawablePrivate *priv = (__GLXDRIdrawablePrivate *) pdraw; 355 XRectangle xrect; 356 XserverRegion region; 357 358 if (!priv->have_fake_front) 359 return; 360 361 xrect.x = 0; 362 xrect.y = 0; 363 xrect.width = priv->width; 364 xrect.height = priv->height; 365 366#ifdef __DRI2_FLUSH 367 if (pdraw->psc->f) 368 (*pdraw->psc->f->flush) (pdraw->driDrawable); 369#endif 370 371 region = XFixesCreateRegion(pdraw->psc->dpy, &xrect, 1); 372 DRI2CopyRegion(pdraw->psc->dpy, pdraw->xDrawable, region, 373 DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft); 374 XFixesDestroyRegion(pdraw->psc->dpy, region); 375} 376 377static void 378dri2FlushFrontBuffer(__DRIdrawable *driDrawable, void *loaderPrivate) 379{ 380 __GLXDRIdrawablePrivate *pdraw = loaderPrivate; 381 __GLXdisplayPrivate *priv = __glXInitialize(pdraw->base.psc->dpy); 382 __GLXDRIdisplayPrivate *pdp = (__GLXDRIdisplayPrivate *)priv->dri2Display; 383 384 /* Old servers don't send invalidate events */ 385 if (!pdp->invalidateAvailable) 386 dri2InvalidateBuffers(priv->dpy, pdraw->base.drawable); 387 388 dri2WaitGL(loaderPrivate); 389} 390 391 392static void 393dri2DestroyScreen(__GLXscreenConfigs * psc) 394{ 395 /* Free the direct rendering per screen data */ 396 (*psc->core->destroyScreen) (psc->__driScreen); 397 close(psc->fd); 398 psc->__driScreen = NULL; 399} 400 401/** 402 * Process list of buffer received from the server 403 * 404 * Processes the list of buffers received in a reply from the server to either 405 * \c DRI2GetBuffers or \c DRI2GetBuffersWithFormat. 406 */ 407static void 408process_buffers(__GLXDRIdrawablePrivate * pdraw, DRI2Buffer * buffers, 409 unsigned count) 410{ 411 int i; 412 413 pdraw->bufferCount = count; 414 pdraw->have_fake_front = 0; 415 pdraw->have_back = 0; 416 417 /* This assumes the DRI2 buffer attachment tokens matches the 418 * __DRIbuffer tokens. */ 419 for (i = 0; i < count; i++) { 420 pdraw->buffers[i].attachment = buffers[i].attachment; 421 pdraw->buffers[i].name = buffers[i].name; 422 pdraw->buffers[i].pitch = buffers[i].pitch; 423 pdraw->buffers[i].cpp = buffers[i].cpp; 424 pdraw->buffers[i].flags = buffers[i].flags; 425 if (pdraw->buffers[i].attachment == __DRI_BUFFER_FAKE_FRONT_LEFT) 426 pdraw->have_fake_front = 1; 427 if (pdraw->buffers[i].attachment == __DRI_BUFFER_BACK_LEFT) 428 pdraw->have_back = 1; 429 } 430 431} 432 433static int64_t 434dri2SwapBuffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor, 435 int64_t remainder) 436{ 437 __GLXDRIdrawablePrivate *priv = (__GLXDRIdrawablePrivate *) pdraw; 438 __GLXdisplayPrivate *dpyPriv = __glXInitialize(priv->base.psc->dpy); 439 __GLXDRIdisplayPrivate *pdp = 440 (__GLXDRIdisplayPrivate *)dpyPriv->dri2Display; 441 int64_t ret; 442 443#ifdef __DRI2_FLUSH 444 if (pdraw->psc->f) 445 (*pdraw->psc->f->flush)(pdraw->driDrawable); 446#endif 447 448 /* Old servers don't send invalidate events */ 449 if (!pdp->invalidateAvailable) 450 dri2InvalidateBuffers(dpyPriv->dpy, pdraw->drawable); 451 452 /* Old servers can't handle swapbuffers */ 453 if (!pdp->swapAvailable) { 454 dri2CopySubBuffer(pdraw, 0, 0, priv->width, priv->height); 455 return 0; 456 } 457 458#ifdef X_DRI2SwapBuffers 459 DRI2SwapBuffers(pdraw->psc->dpy, pdraw->xDrawable, target_msc, divisor, 460 remainder, &ret); 461#endif 462 463 return ret; 464} 465 466static __DRIbuffer * 467dri2GetBuffers(__DRIdrawable * driDrawable, 468 int *width, int *height, 469 unsigned int *attachments, int count, 470 int *out_count, void *loaderPrivate) 471{ 472 __GLXDRIdrawablePrivate *pdraw = loaderPrivate; 473 DRI2Buffer *buffers; 474 475 buffers = DRI2GetBuffers(pdraw->base.psc->dpy, pdraw->base.xDrawable, 476 width, height, attachments, count, out_count); 477 if (buffers == NULL) 478 return NULL; 479 480 pdraw->width = *width; 481 pdraw->height = *height; 482 process_buffers(pdraw, buffers, *out_count); 483 484 Xfree(buffers); 485 486 return pdraw->buffers; 487} 488 489static __DRIbuffer * 490dri2GetBuffersWithFormat(__DRIdrawable * driDrawable, 491 int *width, int *height, 492 unsigned int *attachments, int count, 493 int *out_count, void *loaderPrivate) 494{ 495 __GLXDRIdrawablePrivate *pdraw = loaderPrivate; 496 DRI2Buffer *buffers; 497 498 buffers = DRI2GetBuffersWithFormat(pdraw->base.psc->dpy, 499 pdraw->base.xDrawable, 500 width, height, attachments, 501 count, out_count); 502 if (buffers == NULL) 503 return NULL; 504 505 pdraw->width = *width; 506 pdraw->height = *height; 507 process_buffers(pdraw, buffers, *out_count); 508 509 Xfree(buffers); 510 511 return pdraw->buffers; 512} 513 514#ifdef X_DRI2SwapInterval 515 516static void 517dri2SetSwapInterval(__GLXDRIdrawable *pdraw, int interval) 518{ 519 __GLXscreenConfigs *psc = pdraw->psc; 520 __GLXDRIdrawablePrivate *priv = (__GLXDRIdrawablePrivate *) pdraw; 521 GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1; 522 523 if (psc->config) 524 psc->config->configQueryi(psc->__driScreen, "vblank_mode", &vblank_mode); 525 526 switch (vblank_mode) { 527 case DRI_CONF_VBLANK_NEVER: 528 return; 529 case DRI_CONF_VBLANK_ALWAYS_SYNC: 530 if (interval <= 0) 531 return; 532 break; 533 default: 534 break; 535 } 536 537 DRI2SwapInterval(priv->base.psc->dpy, pdraw->xDrawable, interval); 538 priv->swap_interval = interval; 539} 540 541static unsigned int 542dri2GetSwapInterval(__GLXDRIdrawable *pdraw) 543{ 544 __GLXDRIdrawablePrivate *priv = (__GLXDRIdrawablePrivate *) pdraw; 545 546 return priv->swap_interval; 547} 548 549#endif /* X_DRI2SwapInterval */ 550 551static const __DRIdri2LoaderExtension dri2LoaderExtension = { 552 {__DRI_DRI2_LOADER, __DRI_DRI2_LOADER_VERSION}, 553 dri2GetBuffers, 554 dri2FlushFrontBuffer, 555 dri2GetBuffersWithFormat, 556}; 557 558static const __DRIdri2LoaderExtension dri2LoaderExtension_old = { 559 {__DRI_DRI2_LOADER, __DRI_DRI2_LOADER_VERSION}, 560 dri2GetBuffers, 561 dri2FlushFrontBuffer, 562 NULL, 563}; 564 565#ifdef __DRI_USE_INVALIDATE 566static const __DRIuseInvalidateExtension dri2UseInvalidate = { 567 { __DRI_USE_INVALIDATE, __DRI_USE_INVALIDATE_VERSION } 568}; 569#endif 570 571_X_HIDDEN void 572dri2InvalidateBuffers(Display *dpy, XID drawable) 573{ 574 __GLXDRIdrawable *pdraw = 575 dri2GetGlxDrawableFromXDrawableId(dpy, drawable); 576 577#if __DRI2_FLUSH_VERSION >= 3 578 if (pdraw && pdraw->psc->f) 579 pdraw->psc->f->invalidate(pdraw->driDrawable); 580#endif 581} 582 583static void 584dri2_bind_tex_image(Display * dpy, 585 GLXDrawable drawable, 586 int buffer, const int *attrib_list) 587{ 588 GLXContext gc = __glXGetCurrentContext(); 589 __GLXDRIdrawable *pdraw = GetGLXDRIDrawable(dpy, drawable, NULL); 590 __GLXdisplayPrivate *dpyPriv = __glXInitialize(dpy); 591 __GLXDRIdisplayPrivate *pdp = 592 (__GLXDRIdisplayPrivate *) dpyPriv->dri2Display; 593 594 if (pdraw != NULL) { 595 596#if __DRI2_FLUSH_VERSION >= 3 597 if (!pdp->invalidateAvailable && pdraw->psc->f) 598 pdraw->psc->f->invalidate(pdraw->driDrawable); 599#endif 600 601 if (pdraw->psc->texBuffer->base.version >= 2 && 602 pdraw->psc->texBuffer->setTexBuffer2 != NULL) { 603 (*pdraw->psc->texBuffer->setTexBuffer2) (gc->__driContext, 604 pdraw->textureTarget, 605 pdraw->textureFormat, 606 pdraw->driDrawable); 607 } 608 else { 609 (*pdraw->psc->texBuffer->setTexBuffer) (gc->__driContext, 610 pdraw->textureTarget, 611 pdraw->driDrawable); 612 } 613 } 614} 615 616static void 617dri2_release_tex_image(Display * dpy, GLXDrawable drawable, int buffer) 618{ 619} 620 621static const struct glx_context_vtable dri2_context_vtable = { 622 dri2_bind_tex_image, 623 dri2_release_tex_image, 624}; 625 626static __GLXDRIscreen * 627dri2CreateScreen(__GLXscreenConfigs * psc, int screen, 628 __GLXdisplayPrivate * priv) 629{ 630 const __DRIconfig **driver_configs; 631 const __DRIextension **extensions; 632 const __GLXDRIdisplayPrivate *const pdp = (__GLXDRIdisplayPrivate *) 633 priv->dri2Display; 634 __GLXDRIscreen *psp; 635 char *driverName, *deviceName; 636 drm_magic_t magic; 637 int i; 638 639 psp = Xmalloc(sizeof *psp); 640 if (psp == NULL) 641 return NULL; 642 643 if (!DRI2Connect(psc->dpy, RootWindow(psc->dpy, screen), 644 &driverName, &deviceName)) { 645 XFree(psp); 646 return NULL; 647 } 648 649 psc->driver = driOpenDriver(driverName); 650 if (psc->driver == NULL) { 651 ErrorMessageF("driver pointer missing\n"); 652 goto handle_error; 653 } 654 655 extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS); 656 if (extensions == NULL) { 657 ErrorMessageF("driver exports no extensions (%s)\n", dlerror()); 658 goto handle_error; 659 } 660 661 for (i = 0; extensions[i]; i++) { 662 if (strcmp(extensions[i]->name, __DRI_CORE) == 0) 663 psc->core = (__DRIcoreExtension *) extensions[i]; 664 if (strcmp(extensions[i]->name, __DRI_DRI2) == 0) 665 psc->dri2 = (__DRIdri2Extension *) extensions[i]; 666 } 667 668 if (psc->core == NULL || psc->dri2 == NULL) { 669 ErrorMessageF("core dri or dri2 extension not found\n"); 670 goto handle_error; 671 } 672 673 psc->fd = open(deviceName, O_RDWR); 674 if (psc->fd < 0) { 675 ErrorMessageF("failed to open drm device: %s\n", strerror(errno)); 676 goto handle_error; 677 } 678 679 if (drmGetMagic(psc->fd, &magic)) { 680 ErrorMessageF("failed to get magic\n"); 681 goto handle_error; 682 } 683 684 if (!DRI2Authenticate(psc->dpy, RootWindow(psc->dpy, screen), magic)) { 685 ErrorMessageF("failed to authenticate magic %d\n", magic); 686 goto handle_error; 687 } 688 689 690 /* If the server does not support the protocol for 691 * DRI2GetBuffersWithFormat, don't supply that interface to the driver. 692 */ 693 psc->__driScreen = 694 psc->dri2->createNewScreen(screen, psc->fd, 695 (const __DRIextension **) 696 &pdp->loader_extensions[0], 697 &driver_configs, psc); 698 699 if (psc->__driScreen == NULL) { 700 ErrorMessageF("failed to create dri screen\n"); 701 goto handle_error; 702 } 703 704 driBindCommonExtensions(psc); 705 dri2BindExtensions(psc); 706 707 psc->configs = driConvertConfigs(psc->core, psc->configs, driver_configs); 708 psc->visuals = driConvertConfigs(psc->core, psc->visuals, driver_configs); 709 710 psc->driver_configs = driver_configs; 711 712 psp->destroyScreen = dri2DestroyScreen; 713 psp->createContext = dri2CreateContext; 714 psp->createDrawable = dri2CreateDrawable; 715 psp->swapBuffers = dri2SwapBuffers; 716 psp->waitGL = dri2WaitGL; 717 psp->waitX = dri2WaitX; 718 psp->getDrawableMSC = NULL; 719 psp->waitForMSC = NULL; 720 psp->waitForSBC = NULL; 721 psp->setSwapInterval = NULL; 722 psp->getSwapInterval = NULL; 723 724 if (pdp->driMinor >= 2) { 725#ifdef X_DRI2GetMSC 726 psp->getDrawableMSC = dri2DrawableGetMSC; 727#endif 728#ifdef X_DRI2WaitMSC 729 psp->waitForMSC = dri2WaitForMSC; 730 psp->waitForSBC = dri2WaitForSBC; 731#endif 732#ifdef X_DRI2SwapInterval 733 psp->setSwapInterval = dri2SetSwapInterval; 734 psp->getSwapInterval = dri2GetSwapInterval; 735#endif 736#if defined(X_DRI2GetMSC) && defined(X_DRI2WaitMSC) && defined(X_DRI2SwapInterval) 737 __glXEnableDirectExtension(psc, "GLX_OML_sync_control"); 738#endif 739 } 740 741 /* DRI2 suports SubBuffer through DRI2CopyRegion, so it's always 742 * available.*/ 743 psp->copySubBuffer = dri2CopySubBuffer; 744 __glXEnableDirectExtension(psc, "GLX_MESA_copy_sub_buffer"); 745 746 psc->direct_context_vtable = &dri2_context_vtable; 747 748 Xfree(driverName); 749 Xfree(deviceName); 750 751 return psp; 752 753handle_error: 754 Xfree(driverName); 755 Xfree(deviceName); 756 XFree(psp); 757 758 /* FIXME: clean up here */ 759 760 return NULL; 761} 762 763/* Called from __glXFreeDisplayPrivate. 764 */ 765static void 766dri2DestroyDisplay(__GLXDRIdisplay * dpy) 767{ 768 Xfree(dpy); 769} 770 771_X_HIDDEN __GLXDRIdrawable * 772dri2GetGlxDrawableFromXDrawableId(Display *dpy, XID id) 773{ 774 __GLXdisplayPrivate *d = __glXInitialize(dpy); 775 __GLXDRIdisplayPrivate *pdp = (__GLXDRIdisplayPrivate *) d->dri2Display; 776 __GLXDRIdrawable *pdraw; 777 778 if (__glxHashLookup(pdp->dri2Hash, id, (void *) &pdraw) == 0) 779 return pdraw; 780 781 return NULL; 782} 783 784/* 785 * Allocate, initialize and return a __DRIdisplayPrivate object. 786 * This is called from __glXInitialize() when we are given a new 787 * display pointer. 788 */ 789_X_HIDDEN __GLXDRIdisplay * 790dri2CreateDisplay(Display * dpy) 791{ 792 __GLXDRIdisplayPrivate *pdp; 793 int eventBase, errorBase, i; 794 795 if (!DRI2QueryExtension(dpy, &eventBase, &errorBase)) 796 return NULL; 797 798 pdp = Xmalloc(sizeof *pdp); 799 if (pdp == NULL) 800 return NULL; 801 802 if (!DRI2QueryVersion(dpy, &pdp->driMajor, &pdp->driMinor)) { 803 Xfree(pdp); 804 return NULL; 805 } 806 807 pdp->driPatch = 0; 808 pdp->swapAvailable = (pdp->driMinor >= 2); 809 pdp->invalidateAvailable = (pdp->driMinor >= 3); 810 811 pdp->base.destroyDisplay = dri2DestroyDisplay; 812 pdp->base.createScreen = dri2CreateScreen; 813 814 i = 0; 815 if (pdp->driMinor < 1) 816 pdp->loader_extensions[i++] = &dri2LoaderExtension_old.base; 817 else 818 pdp->loader_extensions[i++] = &dri2LoaderExtension.base; 819 820 pdp->loader_extensions[i++] = &systemTimeExtension.base; 821 822#ifdef __DRI_USE_INVALIDATE 823 pdp->loader_extensions[i++] = &dri2UseInvalidate.base; 824#endif 825 pdp->loader_extensions[i++] = NULL; 826 827 pdp->dri2Hash = __glxHashCreate(); 828 if (pdp->dri2Hash == NULL) { 829 Xfree(pdp); 830 return NULL; 831 } 832 833 return &pdp->base; 834} 835 836#endif /* GLX_DIRECT_RENDERING */ 837