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