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