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