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