dri2_glx.c revision 6e8897ff9f90601ebf6eed500ad942c11b54d1f7
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#ifdef GLX_DIRECT_RENDERING 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#include "../../mesa/drivers/dri/common/dri_util.h" 51 52#undef DRI2_MINOR 53#define DRI2_MINOR 1 54 55typedef struct __GLXDRIdisplayPrivateRec __GLXDRIdisplayPrivate; 56typedef struct __GLXDRIcontextPrivateRec __GLXDRIcontextPrivate; 57typedef struct __GLXDRIdrawablePrivateRec __GLXDRIdrawablePrivate; 58 59struct __GLXDRIdisplayPrivateRec 60{ 61 __GLXDRIdisplay base; 62 63 /* 64 ** XFree86-DRI version information 65 */ 66 int driMajor; 67 int driMinor; 68 int driPatch; 69 int swapAvailable; 70}; 71 72struct __GLXDRIcontextPrivateRec 73{ 74 __GLXDRIcontext base; 75 __DRIcontext *driContext; 76 __GLXscreenConfigs *psc; 77}; 78 79struct __GLXDRIdrawablePrivateRec 80{ 81 __GLXDRIdrawable base; 82 __DRIbuffer buffers[5]; 83 int bufferCount; 84 int width, height; 85 int have_back; 86 int have_fake_front; 87 int swap_interval; 88}; 89 90static void dri2WaitX(__GLXDRIdrawable * pdraw); 91 92static void 93dri2DestroyContext(__GLXDRIcontext * context, 94 __GLXscreenConfigs * psc, Display * dpy) 95{ 96 __GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context; 97 const __DRIcoreExtension *core = pcp->psc->core; 98 99 (*core->destroyContext) (pcp->driContext); 100 101 Xfree(pcp); 102} 103 104static Bool 105dri2BindContext(__GLXDRIcontext * context, 106 __GLXDRIdrawable * draw, __GLXDRIdrawable * read) 107{ 108 __GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context; 109 const __DRIcoreExtension *core = pcp->psc->core; 110 111 return (*core->bindContext) (pcp->driContext, 112 draw->driDrawable, read->driDrawable); 113} 114 115static void 116dri2UnbindContext(__GLXDRIcontext * context) 117{ 118 __GLXDRIcontextPrivate *pcp = (__GLXDRIcontextPrivate *) context; 119 const __DRIcoreExtension *core = pcp->psc->core; 120 121 (*core->unbindContext) (pcp->driContext); 122} 123 124static __GLXDRIcontext * 125dri2CreateContext(__GLXscreenConfigs * psc, 126 const __GLcontextModes * mode, 127 GLXContext gc, GLXContext shareList, int renderType) 128{ 129 __GLXDRIcontextPrivate *pcp, *pcp_shared; 130 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) mode; 131 __DRIcontext *shared = NULL; 132 133 if (shareList) { 134 pcp_shared = (__GLXDRIcontextPrivate *) shareList->driContext; 135 shared = pcp_shared->driContext; 136 } 137 138 pcp = Xmalloc(sizeof *pcp); 139 if (pcp == NULL) 140 return NULL; 141 142 pcp->psc = psc; 143 pcp->driContext = 144 (*psc->dri2->createNewContext) (psc->__driScreen, 145 config->driConfig, shared, pcp); 146 gc->__driContext = pcp->driContext; 147 148 if (pcp->driContext == NULL) { 149 Xfree(pcp); 150 return NULL; 151 } 152 153 pcp->base.destroyContext = dri2DestroyContext; 154 pcp->base.bindContext = dri2BindContext; 155 pcp->base.unbindContext = dri2UnbindContext; 156 157 return &pcp->base; 158} 159 160static void 161dri2DestroyDrawable(__GLXDRIdrawable * pdraw) 162{ 163 const __DRIcoreExtension *core = pdraw->psc->core; 164 165 (*core->destroyDrawable) (pdraw->driDrawable); 166 DRI2DestroyDrawable(pdraw->psc->dpy, pdraw->xDrawable); 167 Xfree(pdraw); 168} 169 170static __GLXDRIdrawable * 171dri2CreateDrawable(__GLXscreenConfigs * psc, 172 XID xDrawable, 173 GLXDrawable drawable, const __GLcontextModes * modes) 174{ 175 __GLXDRIdrawablePrivate *pdraw; 176 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) modes; 177 178 pdraw = Xmalloc(sizeof(*pdraw)); 179 if (!pdraw) 180 return NULL; 181 182 pdraw->base.destroyDrawable = dri2DestroyDrawable; 183 pdraw->base.xDrawable = xDrawable; 184 pdraw->base.drawable = drawable; 185 pdraw->base.psc = psc; 186 pdraw->bufferCount = 0; 187 188 DRI2CreateDrawable(psc->dpy, xDrawable); 189 190 /* Create a new drawable */ 191 pdraw->base.driDrawable = 192 (*psc->dri2->createNewDrawable) (psc->__driScreen, 193 config->driConfig, pdraw); 194 195 if (!pdraw->base.driDrawable) { 196 DRI2DestroyDrawable(psc->dpy, xDrawable); 197 Xfree(pdraw); 198 return NULL; 199 } 200 201 return &pdraw->base; 202} 203 204static int 205dri2DrawableGetMSC(__GLXscreenConfigs *psc, __GLXDRIdrawable *pdraw, 206 int64_t *ust, int64_t *msc, int64_t *sbc) 207{ 208 return DRI2GetMSC(psc->dpy, pdraw->xDrawable, ust, msc, sbc); 209} 210 211static int 212dri2WaitForMSC(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor, 213 int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc) 214{ 215 return DRI2WaitMSC(pdraw->psc->dpy, pdraw->xDrawable, target_msc, divisor, 216 remainder, ust, msc, sbc); 217} 218 219static int 220dri2WaitForSBC(__GLXDRIdrawable *pdraw, int64_t target_sbc, int64_t *ust, 221 int64_t *msc, int64_t *sbc) 222{ 223 return DRI2WaitSBC(pdraw->psc->dpy, pdraw->xDrawable, target_sbc, ust, msc, 224 sbc); 225} 226 227static void 228dri2CopySubBuffer(__GLXDRIdrawable *pdraw, int x, int y, int width, int height) 229{ 230 __GLXDRIdrawablePrivate *priv = (__GLXDRIdrawablePrivate *) pdraw; 231 XRectangle xrect; 232 XserverRegion region; 233 234 /* Check we have the right attachments */ 235 if (!priv->have_back) 236 return; 237 238 xrect.x = x; 239 xrect.y = priv->height - y - height; 240 xrect.width = width; 241 xrect.height = height; 242 243#ifdef __DRI2_FLUSH 244 if (pdraw->psc->f) 245 (*pdraw->psc->f->flush) (pdraw->driDrawable); 246#endif 247 248 region = XFixesCreateRegion(pdraw->psc->dpy, &xrect, 1); 249 /* should get a fence ID back from here at some point */ 250 DRI2CopyRegion(pdraw->psc->dpy, pdraw->xDrawable, region, 251 DRI2BufferFrontLeft, DRI2BufferBackLeft); 252 XFixesDestroyRegion(pdraw->psc->dpy, region); 253 254 /* Refresh the fake front (if present) after we just damaged the real 255 * front. 256 */ 257 dri2WaitX(pdraw); 258} 259 260static void 261dri2WaitX(__GLXDRIdrawable *pdraw) 262{ 263 __GLXDRIdrawablePrivate *priv = (__GLXDRIdrawablePrivate *) pdraw; 264 XRectangle xrect; 265 XserverRegion region; 266 267 /* Check we have the right attachments */ 268 if (!priv->have_fake_front) 269 return; 270 271 xrect.x = 0; 272 xrect.y = 0; 273 xrect.width = priv->width; 274 xrect.height = priv->height; 275 276#ifdef __DRI2_FLUSH 277 if (pdraw->psc->f) 278 (*pdraw->psc->f->flush) (pdraw->driDrawable); 279#endif 280 281 region = XFixesCreateRegion(pdraw->psc->dpy, &xrect, 1); 282 DRI2CopyRegion(pdraw->psc->dpy, pdraw->xDrawable, region, 283 DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft); 284 XFixesDestroyRegion(pdraw->psc->dpy, region); 285} 286 287static void 288dri2WaitGL(__GLXDRIdrawable * pdraw) 289{ 290 __GLXDRIdrawablePrivate *priv = (__GLXDRIdrawablePrivate *) pdraw; 291 XRectangle xrect; 292 XserverRegion region; 293 294 if (!priv->have_fake_front) 295 return; 296 297 xrect.x = 0; 298 xrect.y = 0; 299 xrect.width = priv->width; 300 xrect.height = priv->height; 301 302#ifdef __DRI2_FLUSH 303 if (pdraw->psc->f) 304 (*pdraw->psc->f->flush) (pdraw->driDrawable); 305#endif 306 307 region = XFixesCreateRegion(pdraw->psc->dpy, &xrect, 1); 308 DRI2CopyRegion(pdraw->psc->dpy, pdraw->xDrawable, region, 309 DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft); 310 XFixesDestroyRegion(pdraw->psc->dpy, region); 311} 312 313 314static void 315dri2FlushFrontBuffer(__DRIdrawable * driDrawable, void *loaderPrivate) 316{ 317 (void) driDrawable; 318 dri2WaitGL((__GLXDRIdrawable *) loaderPrivate); 319} 320 321 322static void 323dri2DestroyScreen(__GLXscreenConfigs * psc) 324{ 325 /* Free the direct rendering per screen data */ 326 (*psc->core->destroyScreen) (psc->__driScreen); 327 close(psc->fd); 328 psc->__driScreen = NULL; 329} 330 331/** 332 * Process list of buffer received from the server 333 * 334 * Processes the list of buffers received in a reply from the server to either 335 * \c DRI2GetBuffers or \c DRI2GetBuffersWithFormat. 336 */ 337static void 338process_buffers(__GLXDRIdrawablePrivate * pdraw, DRI2Buffer * buffers, 339 unsigned count) 340{ 341 int i; 342 343 pdraw->bufferCount = count; 344 pdraw->have_fake_front = 0; 345 pdraw->have_back = 0; 346 347 /* This assumes the DRI2 buffer attachment tokens matches the 348 * __DRIbuffer tokens. */ 349 for (i = 0; i < count; i++) { 350 pdraw->buffers[i].attachment = buffers[i].attachment; 351 pdraw->buffers[i].name = buffers[i].name; 352 pdraw->buffers[i].pitch = buffers[i].pitch; 353 pdraw->buffers[i].cpp = buffers[i].cpp; 354 pdraw->buffers[i].flags = buffers[i].flags; 355 if (pdraw->buffers[i].attachment == __DRI_BUFFER_FAKE_FRONT_LEFT) 356 pdraw->have_fake_front = 1; 357 if (pdraw->buffers[i].attachment == __DRI_BUFFER_BACK_LEFT) 358 pdraw->have_back = 1; 359 } 360 361} 362 363static int64_t 364dri2SwapBuffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor, 365 int64_t remainder) 366{ 367 __GLXDRIdrawablePrivate *priv = (__GLXDRIdrawablePrivate *) pdraw; 368 __GLXdisplayPrivate *dpyPriv = __glXInitialize(priv->base.psc->dpy); 369 __GLXDRIdisplayPrivate *pdp = 370 (__GLXDRIdisplayPrivate *)dpyPriv->dri2Display; 371 int64_t ret; 372 373#ifdef __DRI2_FLUSH 374 if (pdraw->psc->f) 375 (*pdraw->psc->f->flush)(pdraw->driDrawable); 376#endif 377 378 /* Old servers can't handle swapbuffers */ 379 if (!pdp->swapAvailable) { 380 dri2CopySubBuffer(pdraw, 0, 0, priv->width, priv->height); 381 return 0; 382 } 383 384#ifdef X_DRI2SwapBuffers 385 DRI2SwapBuffers(pdraw->psc->dpy, pdraw->xDrawable, target_msc, divisor, 386 remainder, &ret); 387#endif 388 389#if __DRI2_FLUSH_VERSION >= 2 390 if (pdraw->psc->f) 391 (*pdraw->psc->f->flushInvalidate)(pdraw->driDrawable); 392#endif 393 394 return ret; 395} 396 397static __DRIbuffer * 398dri2GetBuffers(__DRIdrawable * driDrawable, 399 int *width, int *height, 400 unsigned int *attachments, int count, 401 int *out_count, void *loaderPrivate) 402{ 403 __GLXDRIdrawablePrivate *pdraw = loaderPrivate; 404 DRI2Buffer *buffers; 405 406 buffers = DRI2GetBuffers(pdraw->base.psc->dpy, pdraw->base.xDrawable, 407 width, height, attachments, count, out_count); 408 if (buffers == NULL) 409 return NULL; 410 411 pdraw->width = *width; 412 pdraw->height = *height; 413 process_buffers(pdraw, buffers, *out_count); 414 415 Xfree(buffers); 416 417 return pdraw->buffers; 418} 419 420static __DRIbuffer * 421dri2GetBuffersWithFormat(__DRIdrawable * driDrawable, 422 int *width, int *height, 423 unsigned int *attachments, int count, 424 int *out_count, void *loaderPrivate) 425{ 426 __GLXDRIdrawablePrivate *pdraw = loaderPrivate; 427 DRI2Buffer *buffers; 428 429 buffers = DRI2GetBuffersWithFormat(pdraw->base.psc->dpy, 430 pdraw->base.xDrawable, 431 width, height, attachments, 432 count, out_count); 433 if (buffers == NULL) 434 return NULL; 435 436 pdraw->width = *width; 437 pdraw->height = *height; 438 process_buffers(pdraw, buffers, *out_count); 439 440 Xfree(buffers); 441 442 return pdraw->buffers; 443} 444 445static void 446dri2SetSwapInterval(__GLXDRIdrawable *pdraw, int interval) 447{ 448 __GLXDRIdrawablePrivate *priv = (__GLXDRIdrawablePrivate *) pdraw; 449 450 DRI2SwapInterval(priv->base.psc->dpy, pdraw->xDrawable, interval); 451 priv->swap_interval = interval; 452} 453 454static unsigned int 455dri2GetSwapInterval(__GLXDRIdrawable *pdraw) 456{ 457 __GLXDRIdrawablePrivate *priv = (__GLXDRIdrawablePrivate *) pdraw; 458 459 return priv->swap_interval; 460} 461 462static const __DRIdri2LoaderExtension dri2LoaderExtension = { 463 {__DRI_DRI2_LOADER, __DRI_DRI2_LOADER_VERSION}, 464 dri2GetBuffers, 465 dri2FlushFrontBuffer, 466 dri2GetBuffersWithFormat, 467}; 468 469static const __DRIdri2LoaderExtension dri2LoaderExtension_old = { 470 {__DRI_DRI2_LOADER, __DRI_DRI2_LOADER_VERSION}, 471 dri2GetBuffers, 472 dri2FlushFrontBuffer, 473 NULL, 474}; 475 476static const __DRIextension *loader_extensions[] = { 477 &dri2LoaderExtension.base, 478 &systemTimeExtension.base, 479 NULL 480}; 481 482static const __DRIextension *loader_extensions_old[] = { 483 &dri2LoaderExtension_old.base, 484 &systemTimeExtension.base, 485 NULL 486}; 487 488static __GLXDRIscreen * 489dri2CreateScreen(__GLXscreenConfigs * psc, int screen, 490 __GLXdisplayPrivate * priv) 491{ 492 const __DRIconfig **driver_configs; 493 const __DRIextension **extensions; 494 const __GLXDRIdisplayPrivate *const pdp = (__GLXDRIdisplayPrivate *) 495 priv->dri2Display; 496 __GLXDRIscreen *psp; 497 char *driverName, *deviceName; 498 drm_magic_t magic; 499 int i; 500 501 psp = Xmalloc(sizeof *psp); 502 if (psp == NULL) 503 return NULL; 504 505 /* Initialize per screen dynamic client GLX extensions */ 506 psc->ext_list_first_time = GL_TRUE; 507 508 if (!DRI2Connect(psc->dpy, RootWindow(psc->dpy, screen), 509 &driverName, &deviceName)) { 510 XFree(psp); 511 return NULL; 512 } 513 514 psc->driver = driOpenDriver(driverName); 515 if (psc->driver == NULL) { 516 ErrorMessageF("driver pointer missing\n"); 517 goto handle_error; 518 } 519 520 extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS); 521 if (extensions == NULL) { 522 ErrorMessageF("driver exports no extensions (%s)\n", dlerror()); 523 goto handle_error; 524 } 525 526 for (i = 0; extensions[i]; i++) { 527 if (strcmp(extensions[i]->name, __DRI_CORE) == 0) 528 psc->core = (__DRIcoreExtension *) extensions[i]; 529 if (strcmp(extensions[i]->name, __DRI_DRI2) == 0) 530 psc->dri2 = (__DRIdri2Extension *) extensions[i]; 531 } 532 533 if (psc->core == NULL || psc->dri2 == NULL) { 534 ErrorMessageF("core dri or dri2 extension not found\n"); 535 goto handle_error; 536 } 537 538 psc->fd = open(deviceName, O_RDWR); 539 if (psc->fd < 0) { 540 ErrorMessageF("failed to open drm device: %s\n", strerror(errno)); 541 goto handle_error; 542 } 543 544 if (drmGetMagic(psc->fd, &magic)) { 545 ErrorMessageF("failed to get magic\n"); 546 goto handle_error; 547 } 548 549 if (!DRI2Authenticate(psc->dpy, RootWindow(psc->dpy, screen), magic)) { 550 ErrorMessageF("failed to authenticate magic %d\n", magic); 551 goto handle_error; 552 } 553 554 /* If the server does not support the protocol for 555 * DRI2GetBuffersWithFormat, don't supply that interface to the driver. 556 */ 557 psc->__driScreen = 558 psc->dri2->createNewScreen(screen, psc->fd, ((pdp->driMinor < 1) 559 ? loader_extensions_old 560 : loader_extensions), 561 &driver_configs, psc); 562 563 if (psc->__driScreen == NULL) { 564 ErrorMessageF("failed to create dri screen\n"); 565 goto handle_error; 566 } 567 568 driBindCommonExtensions(psc); 569 dri2BindExtensions(psc); 570 571 psc->configs = driConvertConfigs(psc->core, psc->configs, driver_configs); 572 psc->visuals = driConvertConfigs(psc->core, psc->visuals, driver_configs); 573 574 psc->driver_configs = driver_configs; 575 576 psp->destroyScreen = dri2DestroyScreen; 577 psp->createContext = dri2CreateContext; 578 psp->createDrawable = dri2CreateDrawable; 579 psp->swapBuffers = dri2SwapBuffers; 580 psp->waitGL = dri2WaitGL; 581 psp->waitX = dri2WaitX; 582 psp->getDrawableMSC = NULL; 583 psp->waitForMSC = NULL; 584 psp->waitForSBC = NULL; 585 psp->setSwapInterval = NULL; 586 psp->getSwapInterval = NULL; 587 588 if (pdp->driMinor >= 2) { 589#ifdef X_DRI2GetMSC 590 psp->getDrawableMSC = dri2DrawableGetMSC; 591#endif 592#ifdef X_DRI2WaitMSC 593 psp->waitForMSC = dri2WaitForMSC; 594 psp->waitForSBC = dri2WaitForSBC; 595#endif 596#ifdef X_DRI2SwapInterval 597 psp->setSwapInterval = dri2SetSwapInterval; 598 psp->getSwapInterval = dri2GetSwapInterval; 599#endif 600 } 601 602 /* DRI2 suports SubBuffer through DRI2CopyRegion, so it's always 603 * available.*/ 604 psp->copySubBuffer = dri2CopySubBuffer; 605 __glXEnableDirectExtension(psc, "GLX_MESA_copy_sub_buffer"); 606 607 Xfree(driverName); 608 Xfree(deviceName); 609 610 return psp; 611 612handle_error: 613 Xfree(driverName); 614 Xfree(deviceName); 615 XFree(psp); 616 617 /* FIXME: clean up here */ 618 619 return NULL; 620} 621 622/* Called from __glXFreeDisplayPrivate. 623 */ 624static void 625dri2DestroyDisplay(__GLXDRIdisplay * dpy) 626{ 627 Xfree(dpy); 628} 629 630/* 631 * Allocate, initialize and return a __DRIdisplayPrivate object. 632 * This is called from __glXInitialize() when we are given a new 633 * display pointer. 634 */ 635_X_HIDDEN __GLXDRIdisplay * 636dri2CreateDisplay(Display * dpy) 637{ 638 __GLXDRIdisplayPrivate *pdp; 639 int eventBase, errorBase; 640 641 if (!DRI2QueryExtension(dpy, &eventBase, &errorBase)) 642 return NULL; 643 644 pdp = Xmalloc(sizeof *pdp); 645 if (pdp == NULL) 646 return NULL; 647 648 if (!DRI2QueryVersion(dpy, &pdp->driMajor, &pdp->driMinor)) { 649 Xfree(pdp); 650 return NULL; 651 } 652 653 pdp->driPatch = 0; 654 pdp->swapAvailable = 0; 655#ifdef X_DRI2SwapBuffers 656 if (pdp->driMinor >= 2) 657 pdp->swapAvailable = 1; 658#endif 659 660 pdp->base.destroyDisplay = dri2DestroyDisplay; 661 pdp->base.createScreen = dri2CreateScreen; 662 663 return &pdp->base; 664} 665 666#endif /* GLX_DIRECT_RENDERING */ 667