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