dri2_glx.c revision eeaab2047cfce8a7445fd9f835e737682eb503ac
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 427 /* Old servers don't send invalidate events */ 428 if (!pdp->invalidateAvailable) 429 dri2InvalidateBuffers(priv->dpy, pdraw->base.drawable); 430 431 dri2_copy_drawable(pdraw, DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft); 432} 433 434 435static void 436dri2DestroyScreen(__GLXscreenConfigs *base) 437{ 438 struct dri2_screen *psc = (struct dri2_screen *) base; 439 440 /* Free the direct rendering per screen data */ 441 (*psc->core->destroyScreen) (psc->driScreen); 442 driDestroyConfigs(psc->driver_configs); 443 close(psc->fd); 444 Xfree(psc); 445} 446 447/** 448 * Process list of buffer received from the server 449 * 450 * Processes the list of buffers received in a reply from the server to either 451 * \c DRI2GetBuffers or \c DRI2GetBuffersWithFormat. 452 */ 453static void 454process_buffers(struct dri2_drawable * pdraw, DRI2Buffer * buffers, 455 unsigned count) 456{ 457 int i; 458 459 pdraw->bufferCount = count; 460 pdraw->have_fake_front = 0; 461 pdraw->have_back = 0; 462 463 /* This assumes the DRI2 buffer attachment tokens matches the 464 * __DRIbuffer tokens. */ 465 for (i = 0; i < count; i++) { 466 pdraw->buffers[i].attachment = buffers[i].attachment; 467 pdraw->buffers[i].name = buffers[i].name; 468 pdraw->buffers[i].pitch = buffers[i].pitch; 469 pdraw->buffers[i].cpp = buffers[i].cpp; 470 pdraw->buffers[i].flags = buffers[i].flags; 471 if (pdraw->buffers[i].attachment == __DRI_BUFFER_FAKE_FRONT_LEFT) 472 pdraw->have_fake_front = 1; 473 if (pdraw->buffers[i].attachment == __DRI_BUFFER_BACK_LEFT) 474 pdraw->have_back = 1; 475 } 476 477} 478 479static int64_t 480dri2SwapBuffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor, 481 int64_t remainder) 482{ 483 struct dri2_drawable *priv = (struct dri2_drawable *) pdraw; 484 __GLXdisplayPrivate *dpyPriv = __glXInitialize(priv->base.psc->dpy); 485 struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc; 486 struct dri2_display *pdp = 487 (struct dri2_display *)dpyPriv->dri2Display; 488 CARD64 ret; 489 490#ifdef __DRI2_FLUSH 491 if (psc->f) 492 (*psc->f->flush)(priv->driDrawable); 493#endif 494 495 /* Old servers don't send invalidate events */ 496 if (!pdp->invalidateAvailable) 497 dri2InvalidateBuffers(dpyPriv->dpy, pdraw->drawable); 498 499 /* Old servers can't handle swapbuffers */ 500 if (!pdp->swapAvailable) { 501 dri2CopySubBuffer(pdraw, 0, 0, priv->width, priv->height); 502 return 0; 503 } 504 505#ifdef X_DRI2SwapBuffers 506 DRI2SwapBuffers(psc->base.dpy, pdraw->xDrawable, target_msc, divisor, 507 remainder, &ret); 508#endif 509 510 return ret; 511} 512 513static __DRIbuffer * 514dri2GetBuffers(__DRIdrawable * driDrawable, 515 int *width, int *height, 516 unsigned int *attachments, int count, 517 int *out_count, void *loaderPrivate) 518{ 519 struct dri2_drawable *pdraw = loaderPrivate; 520 DRI2Buffer *buffers; 521 522 buffers = DRI2GetBuffers(pdraw->base.psc->dpy, pdraw->base.xDrawable, 523 width, height, attachments, count, out_count); 524 if (buffers == NULL) 525 return NULL; 526 527 pdraw->width = *width; 528 pdraw->height = *height; 529 process_buffers(pdraw, buffers, *out_count); 530 531 Xfree(buffers); 532 533 return pdraw->buffers; 534} 535 536static __DRIbuffer * 537dri2GetBuffersWithFormat(__DRIdrawable * driDrawable, 538 int *width, int *height, 539 unsigned int *attachments, int count, 540 int *out_count, void *loaderPrivate) 541{ 542 struct dri2_drawable *pdraw = loaderPrivate; 543 DRI2Buffer *buffers; 544 545 buffers = DRI2GetBuffersWithFormat(pdraw->base.psc->dpy, 546 pdraw->base.xDrawable, 547 width, height, attachments, 548 count, out_count); 549 if (buffers == NULL) 550 return NULL; 551 552 pdraw->width = *width; 553 pdraw->height = *height; 554 process_buffers(pdraw, buffers, *out_count); 555 556 Xfree(buffers); 557 558 return pdraw->buffers; 559} 560 561#ifdef X_DRI2SwapInterval 562 563static int 564dri2SetSwapInterval(__GLXDRIdrawable *pdraw, int interval) 565{ 566 struct dri2_drawable *priv = (struct dri2_drawable *) pdraw; 567 GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1; 568 struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc; 569 570 if (psc->config) 571 psc->config->configQueryi(psc->driScreen, 572 "vblank_mode", &vblank_mode); 573 574 switch (vblank_mode) { 575 case DRI_CONF_VBLANK_NEVER: 576 return GLX_BAD_VALUE; 577 case DRI_CONF_VBLANK_ALWAYS_SYNC: 578 if (interval <= 0) 579 return GLX_BAD_VALUE; 580 break; 581 default: 582 break; 583 } 584 585 DRI2SwapInterval(priv->base.psc->dpy, priv->base.xDrawable, interval); 586 priv->swap_interval = interval; 587 588 return 0; 589} 590 591static int 592dri2GetSwapInterval(__GLXDRIdrawable *pdraw) 593{ 594 struct dri2_drawable *priv = (struct dri2_drawable *) pdraw; 595 596 return priv->swap_interval; 597} 598 599#endif /* X_DRI2SwapInterval */ 600 601static const __DRIdri2LoaderExtension dri2LoaderExtension = { 602 {__DRI_DRI2_LOADER, __DRI_DRI2_LOADER_VERSION}, 603 dri2GetBuffers, 604 dri2FlushFrontBuffer, 605 dri2GetBuffersWithFormat, 606}; 607 608static const __DRIdri2LoaderExtension dri2LoaderExtension_old = { 609 {__DRI_DRI2_LOADER, __DRI_DRI2_LOADER_VERSION}, 610 dri2GetBuffers, 611 dri2FlushFrontBuffer, 612 NULL, 613}; 614 615#ifdef __DRI_USE_INVALIDATE 616static const __DRIuseInvalidateExtension dri2UseInvalidate = { 617 { __DRI_USE_INVALIDATE, __DRI_USE_INVALIDATE_VERSION } 618}; 619#endif 620 621_X_HIDDEN void 622dri2InvalidateBuffers(Display *dpy, XID drawable) 623{ 624 __GLXDRIdrawable *pdraw = 625 dri2GetGlxDrawableFromXDrawableId(dpy, drawable); 626 struct dri2_screen *psc = (struct dri2_screen *) pdraw->psc; 627 struct dri2_drawable *pdp = (struct dri2_drawable *) pdraw; 628 629#if __DRI2_FLUSH_VERSION >= 3 630 if (pdraw && psc->f) 631 psc->f->invalidate(pdp->driDrawable); 632#endif 633} 634 635static void 636dri2_bind_tex_image(Display * dpy, 637 GLXDrawable drawable, 638 int buffer, const int *attrib_list) 639{ 640 GLXContext gc = __glXGetCurrentContext(); 641 __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable); 642 __GLXdisplayPrivate *dpyPriv = __glXInitialize(dpy); 643 struct dri2_drawable *pdraw = (struct dri2_drawable *) base; 644 struct dri2_display *pdp = 645 (struct dri2_display *) dpyPriv->dri2Display; 646 struct dri2_screen *psc = (struct dri2_screen *) base->psc; 647 struct dri2_context *pcp = (struct dri2_context *) gc->driContext; 648 649 if (pdraw != NULL) { 650 651#if __DRI2_FLUSH_VERSION >= 3 652 if (!pdp->invalidateAvailable && psc->f) 653 psc->f->invalidate(pdraw->driDrawable); 654#endif 655 656 if (psc->texBuffer->base.version >= 2 && 657 psc->texBuffer->setTexBuffer2 != NULL) { 658 (*psc->texBuffer->setTexBuffer2) (pcp->driContext, 659 pdraw->base.textureTarget, 660 pdraw->base.textureFormat, 661 pdraw->driDrawable); 662 } 663 else { 664 (*psc->texBuffer->setTexBuffer) (pcp->driContext, 665 pdraw->base.textureTarget, 666 pdraw->driDrawable); 667 } 668 } 669} 670 671static void 672dri2_release_tex_image(Display * dpy, GLXDrawable drawable, int buffer) 673{ 674} 675 676static const struct glx_context_vtable dri2_context_vtable = { 677 dri2_wait_gl, 678 dri2_wait_x, 679 DRI_glXUseXFont, 680 dri2_bind_tex_image, 681 dri2_release_tex_image, 682}; 683 684static void 685dri2BindExtensions(struct dri2_screen *psc, const __DRIextension **extensions) 686{ 687 int i; 688 689 __glXEnableDirectExtension(&psc->base, "GLX_SGI_video_sync"); 690 __glXEnableDirectExtension(&psc->base, "GLX_SGI_swap_control"); 691 __glXEnableDirectExtension(&psc->base, "GLX_MESA_swap_control"); 692 __glXEnableDirectExtension(&psc->base, "GLX_SGI_make_current_read"); 693 694 /* FIXME: if DRI2 version supports it... */ 695 __glXEnableDirectExtension(&psc->base, "INTEL_swap_event"); 696 697 for (i = 0; extensions[i]; i++) { 698 if ((strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0)) { 699 psc->texBuffer = (__DRItexBufferExtension *) extensions[i]; 700 __glXEnableDirectExtension(&psc->base, "GLX_EXT_texture_from_pixmap"); 701 } 702 703 if ((strcmp(extensions[i]->name, __DRI2_FLUSH) == 0)) { 704 psc->f = (__DRI2flushExtension *) extensions[i]; 705 /* internal driver extension, no GL extension exposed */ 706 } 707 708 if ((strcmp(extensions[i]->name, __DRI2_CONFIG_QUERY) == 0)) 709 psc->config = (__DRI2configQueryExtension *) extensions[i]; 710 } 711} 712 713 714static __GLXscreenConfigs * 715dri2CreateScreen(int screen, __GLXdisplayPrivate * priv) 716{ 717 const __DRIconfig **driver_configs; 718 const __DRIextension **extensions; 719 const struct dri2_display *const pdp = (struct dri2_display *) 720 priv->dri2Display; 721 struct dri2_screen *psc; 722 __GLXDRIscreen *psp; 723 char *driverName, *deviceName; 724 drm_magic_t magic; 725 int i; 726 727 psc = Xmalloc(sizeof *psc); 728 if (psc == NULL) 729 return NULL; 730 731 memset(psc, 0, sizeof *psc); 732 if (!glx_screen_init(&psc->base, screen, priv)) 733 return NULL; 734 735 if (!DRI2Connect(priv->dpy, RootWindow(priv->dpy, screen), 736 &driverName, &deviceName)) { 737 XFree(psc); 738 return NULL; 739 } 740 741 psc->driver = driOpenDriver(driverName); 742 if (psc->driver == NULL) { 743 ErrorMessageF("driver pointer missing\n"); 744 goto handle_error; 745 } 746 747 extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS); 748 if (extensions == NULL) { 749 ErrorMessageF("driver exports no extensions (%s)\n", dlerror()); 750 goto handle_error; 751 } 752 753 for (i = 0; extensions[i]; i++) { 754 if (strcmp(extensions[i]->name, __DRI_CORE) == 0) 755 psc->core = (__DRIcoreExtension *) extensions[i]; 756 if (strcmp(extensions[i]->name, __DRI_DRI2) == 0) 757 psc->dri2 = (__DRIdri2Extension *) extensions[i]; 758 } 759 760 if (psc->core == NULL || psc->dri2 == NULL) { 761 ErrorMessageF("core dri or dri2 extension not found\n"); 762 goto handle_error; 763 } 764 765 psc->fd = open(deviceName, O_RDWR); 766 if (psc->fd < 0) { 767 ErrorMessageF("failed to open drm device: %s\n", strerror(errno)); 768 goto handle_error; 769 } 770 771 if (drmGetMagic(psc->fd, &magic)) { 772 ErrorMessageF("failed to get magic\n"); 773 goto handle_error; 774 } 775 776 if (!DRI2Authenticate(priv->dpy, RootWindow(priv->dpy, screen), magic)) { 777 ErrorMessageF("failed to authenticate magic %d\n", magic); 778 goto handle_error; 779 } 780 781 782 /* If the server does not support the protocol for 783 * DRI2GetBuffersWithFormat, don't supply that interface to the driver. 784 */ 785 psc->driScreen = 786 psc->dri2->createNewScreen(screen, psc->fd, 787 (const __DRIextension **) 788 &pdp->loader_extensions[0], 789 &driver_configs, psc); 790 791 if (psc->driScreen == NULL) { 792 ErrorMessageF("failed to create dri screen\n"); 793 goto handle_error; 794 } 795 796 extensions = psc->core->getExtensions(psc->driScreen); 797 dri2BindExtensions(psc, extensions); 798 799 psc->base.configs = 800 driConvertConfigs(psc->core, psc->base.configs, driver_configs); 801 psc->base.visuals = 802 driConvertConfigs(psc->core, psc->base.visuals, driver_configs); 803 804 psc->driver_configs = driver_configs; 805 806 psp = &psc->vtable; 807 psc->base.driScreen = psp; 808 psp->destroyScreen = dri2DestroyScreen; 809 psp->createContext = dri2CreateContext; 810 psp->createDrawable = dri2CreateDrawable; 811 psp->swapBuffers = dri2SwapBuffers; 812 psp->getDrawableMSC = NULL; 813 psp->waitForMSC = NULL; 814 psp->waitForSBC = NULL; 815 psp->setSwapInterval = NULL; 816 psp->getSwapInterval = NULL; 817 818 if (pdp->driMinor >= 2) { 819#ifdef X_DRI2GetMSC 820 psp->getDrawableMSC = dri2DrawableGetMSC; 821#endif 822#ifdef X_DRI2WaitMSC 823 psp->waitForMSC = dri2WaitForMSC; 824 psp->waitForSBC = dri2WaitForSBC; 825#endif 826#ifdef X_DRI2SwapInterval 827 psp->setSwapInterval = dri2SetSwapInterval; 828 psp->getSwapInterval = dri2GetSwapInterval; 829#endif 830#if defined(X_DRI2GetMSC) && defined(X_DRI2WaitMSC) && defined(X_DRI2SwapInterval) 831 __glXEnableDirectExtension(&psc->base, "GLX_OML_sync_control"); 832#endif 833 } 834 835 /* DRI2 suports SubBuffer through DRI2CopyRegion, so it's always 836 * available.*/ 837 psp->copySubBuffer = dri2CopySubBuffer; 838 __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer"); 839 840 Xfree(driverName); 841 Xfree(deviceName); 842 843 return &psc->base; 844 845handle_error: 846 Xfree(driverName); 847 Xfree(deviceName); 848 XFree(psc); 849 850 /* FIXME: clean up here */ 851 852 return NULL; 853} 854 855/* Called from __glXFreeDisplayPrivate. 856 */ 857static void 858dri2DestroyDisplay(__GLXDRIdisplay * dpy) 859{ 860 Xfree(dpy); 861} 862 863_X_HIDDEN __GLXDRIdrawable * 864dri2GetGlxDrawableFromXDrawableId(Display *dpy, XID id) 865{ 866 __GLXdisplayPrivate *d = __glXInitialize(dpy); 867 struct dri2_display *pdp = (struct dri2_display *) d->dri2Display; 868 __GLXDRIdrawable *pdraw; 869 870 if (__glxHashLookup(pdp->dri2Hash, id, (void *) &pdraw) == 0) 871 return pdraw; 872 873 return NULL; 874} 875 876/* 877 * Allocate, initialize and return a __DRIdisplayPrivate object. 878 * This is called from __glXInitialize() when we are given a new 879 * display pointer. 880 */ 881_X_HIDDEN __GLXDRIdisplay * 882dri2CreateDisplay(Display * dpy) 883{ 884 struct dri2_display *pdp; 885 int eventBase, errorBase, i; 886 887 if (!DRI2QueryExtension(dpy, &eventBase, &errorBase)) 888 return NULL; 889 890 pdp = Xmalloc(sizeof *pdp); 891 if (pdp == NULL) 892 return NULL; 893 894 if (!DRI2QueryVersion(dpy, &pdp->driMajor, &pdp->driMinor)) { 895 Xfree(pdp); 896 return NULL; 897 } 898 899 pdp->driPatch = 0; 900 pdp->swapAvailable = (pdp->driMinor >= 2); 901 pdp->invalidateAvailable = (pdp->driMinor >= 3); 902 903 pdp->base.destroyDisplay = dri2DestroyDisplay; 904 pdp->base.createScreen = dri2CreateScreen; 905 906 i = 0; 907 if (pdp->driMinor < 1) 908 pdp->loader_extensions[i++] = &dri2LoaderExtension_old.base; 909 else 910 pdp->loader_extensions[i++] = &dri2LoaderExtension.base; 911 912 pdp->loader_extensions[i++] = &systemTimeExtension.base; 913 914#ifdef __DRI_USE_INVALIDATE 915 pdp->loader_extensions[i++] = &dri2UseInvalidate.base; 916#endif 917 pdp->loader_extensions[i++] = NULL; 918 919 pdp->dri2Hash = __glxHashCreate(); 920 if (pdp->dri2Hash == NULL) { 921 Xfree(pdp); 922 return NULL; 923 } 924 925 return &pdp->base; 926} 927 928#endif /* GLX_DIRECT_RENDERING */ 929