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