glxdri2.c revision 35c4bbdf
1/* 2 * Copyright © 2007 Red Hat, Inc 3 * 4 * Permission to use, copy, modify, distribute, and sell this software 5 * and its documentation for any purpose is hereby granted without 6 * fee, provided that the above copyright notice appear in all copies 7 * and that both that copyright notice and this permission notice 8 * appear in supporting documentation, and that the name of Red Hat, 9 * Inc not be used in advertising or publicity pertaining to 10 * distribution of the software without specific, written prior 11 * permission. Red Hat, Inc makes no representations about the 12 * suitability of this software for any purpose. It is provided "as 13 * is" without express or implied warranty. 14 * 15 * RED HAT, INC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN 17 * NO EVENT SHALL RED HAT, INC BE LIABLE FOR ANY SPECIAL, INDIRECT OR 18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 19 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 20 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 22 */ 23 24#ifdef HAVE_DIX_CONFIG_H 25#include <dix-config.h> 26#endif 27 28#include <stdint.h> 29#include <stdio.h> 30#include <string.h> 31#include <errno.h> 32#include <dlfcn.h> 33 34#include <drm.h> 35#include <GL/gl.h> 36#include <GL/internal/dri_interface.h> 37#include <GL/glxtokens.h> 38 39#include <windowstr.h> 40#include <os.h> 41 42#define _XF86DRI_SERVER_ 43#include <xf86drm.h> 44#include <xf86.h> 45#include <dri2.h> 46 47#include "glxserver.h" 48#include "glxutil.h" 49#include "glxdricommon.h" 50#include <GL/glxtokens.h> 51 52#include "extension_string.h" 53 54typedef struct __GLXDRIscreen __GLXDRIscreen; 55typedef struct __GLXDRIcontext __GLXDRIcontext; 56typedef struct __GLXDRIdrawable __GLXDRIdrawable; 57 58#define ALL_DRI_CTX_FLAGS (__DRI_CTX_FLAG_DEBUG \ 59 | __DRI_CTX_FLAG_FORWARD_COMPATIBLE \ 60 | __DRI_CTX_FLAG_ROBUST_BUFFER_ACCESS) 61 62struct __GLXDRIscreen { 63 __GLXscreen base; 64 __DRIscreen *driScreen; 65 void *driver; 66 int fd; 67 68 xf86EnterVTProc *enterVT; 69 xf86LeaveVTProc *leaveVT; 70 71 const __DRIcoreExtension *core; 72 const __DRIdri2Extension *dri2; 73 const __DRI2flushExtension *flush; 74 const __DRIcopySubBufferExtension *copySubBuffer; 75 const __DRIswapControlExtension *swapControl; 76 const __DRItexBufferExtension *texBuffer; 77 const __DRIconfig **driConfigs; 78 79 unsigned char glx_enable_bits[__GLX_EXT_BYTES]; 80}; 81 82struct __GLXDRIcontext { 83 __GLXcontext base; 84 __DRIcontext *driContext; 85}; 86 87#define MAX_DRAWABLE_BUFFERS 5 88 89struct __GLXDRIdrawable { 90 __GLXdrawable base; 91 __DRIdrawable *driDrawable; 92 __GLXDRIscreen *screen; 93 94 /* Dimensions as last reported by DRI2GetBuffers. */ 95 int width; 96 int height; 97 __DRIbuffer buffers[MAX_DRAWABLE_BUFFERS]; 98 int count; 99 XID dri2_id; 100}; 101 102static void 103__glXDRIdrawableDestroy(__GLXdrawable * drawable) 104{ 105 __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable; 106 const __DRIcoreExtension *core = private->screen->core; 107 108 FreeResource(private->dri2_id, FALSE); 109 110 (*core->destroyDrawable) (private->driDrawable); 111 112 __glXDrawableRelease(drawable); 113 114 free(private); 115} 116 117static void 118copy_box(__GLXdrawable * drawable, 119 int dst, int src, 120 int x, int y, int w, int h) 121{ 122 BoxRec box; 123 RegionRec region; 124 __GLXcontext *cx = lastGLContext; 125 126 box.x1 = x; 127 box.y1 = y; 128 box.x2 = x + w; 129 box.y2 = y + h; 130 RegionInit(®ion, &box, 0); 131 132 DRI2CopyRegion(drawable->pDraw, ®ion, dst, src); 133 if (cx != lastGLContext) { 134 lastGLContext = cx; 135 cx->makeCurrent(cx); 136 } 137} 138 139static void 140__glXDRIdrawableCopySubBuffer(__GLXdrawable * drawable, 141 int x, int y, int w, int h) 142{ 143 __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable; 144 145 copy_box(drawable, x, private->height - y - h, 146 w, h, 147 DRI2BufferFrontLeft, DRI2BufferBackLeft); 148} 149 150static void 151__glXDRIdrawableWaitX(__GLXdrawable * drawable) 152{ 153 __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable; 154 155 copy_box(drawable, DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft, 156 0, 0, private->width, private->height); 157} 158 159static void 160__glXDRIdrawableWaitGL(__GLXdrawable * drawable) 161{ 162 __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable; 163 164 copy_box(drawable, DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft, 165 0, 0, private->width, private->height); 166} 167 168static void 169__glXdriSwapEvent(ClientPtr client, void *data, int type, CARD64 ust, 170 CARD64 msc, CARD32 sbc) 171{ 172 __GLXdrawable *drawable = data; 173 int glx_type; 174 switch (type) { 175 case DRI2_EXCHANGE_COMPLETE: 176 glx_type = GLX_EXCHANGE_COMPLETE_INTEL; 177 break; 178 default: 179 /* unknown swap completion type, 180 * BLIT is a reasonable default, so 181 * fall through ... 182 */ 183 case DRI2_BLIT_COMPLETE: 184 glx_type = GLX_BLIT_COMPLETE_INTEL; 185 break; 186 case DRI2_FLIP_COMPLETE: 187 glx_type = GLX_FLIP_COMPLETE_INTEL; 188 break; 189 } 190 191 __glXsendSwapEvent(drawable, glx_type, ust, msc, sbc); 192} 193 194/* 195 * Copy or flip back to front, honoring the swap interval if possible. 196 * 197 * If the kernel supports it, we request an event for the frame when the 198 * swap should happen, then perform the copy when we receive it. 199 */ 200static GLboolean 201__glXDRIdrawableSwapBuffers(ClientPtr client, __GLXdrawable * drawable) 202{ 203 __GLXDRIdrawable *priv = (__GLXDRIdrawable *) drawable; 204 __GLXDRIscreen *screen = priv->screen; 205 CARD64 unused; 206 __GLXcontext *cx = lastGLContext; 207 int status; 208 209 if (screen->flush) { 210 (*screen->flush->flush) (priv->driDrawable); 211 (*screen->flush->invalidate) (priv->driDrawable); 212 } 213 214 status = DRI2SwapBuffers(client, drawable->pDraw, 0, 0, 0, &unused, 215 __glXdriSwapEvent, drawable); 216 if (cx != lastGLContext) { 217 lastGLContext = cx; 218 cx->makeCurrent(cx); 219 } 220 221 return status == Success; 222} 223 224static int 225__glXDRIdrawableSwapInterval(__GLXdrawable * drawable, int interval) 226{ 227 __GLXcontext *cx = lastGLContext; 228 229 if (interval <= 0) /* || interval > BIGNUM? */ 230 return GLX_BAD_VALUE; 231 232 DRI2SwapInterval(drawable->pDraw, interval); 233 if (cx != lastGLContext) { 234 lastGLContext = cx; 235 cx->makeCurrent(cx); 236 } 237 238 return 0; 239} 240 241static void 242__glXDRIcontextDestroy(__GLXcontext * baseContext) 243{ 244 __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext; 245 __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen; 246 247 (*screen->core->destroyContext) (context->driContext); 248 __glXContextDestroy(&context->base); 249 free(context); 250} 251 252static int 253__glXDRIcontextMakeCurrent(__GLXcontext * baseContext) 254{ 255 __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext; 256 __GLXDRIdrawable *draw = (__GLXDRIdrawable *) baseContext->drawPriv; 257 __GLXDRIdrawable *read = (__GLXDRIdrawable *) baseContext->readPriv; 258 __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen; 259 260 return (*screen->core->bindContext) (context->driContext, 261 draw->driDrawable, read->driDrawable); 262} 263 264static int 265__glXDRIcontextLoseCurrent(__GLXcontext * baseContext) 266{ 267 __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext; 268 __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen; 269 270 return (*screen->core->unbindContext) (context->driContext); 271} 272 273static int 274__glXDRIcontextCopy(__GLXcontext * baseDst, __GLXcontext * baseSrc, 275 unsigned long mask) 276{ 277 __GLXDRIcontext *dst = (__GLXDRIcontext *) baseDst; 278 __GLXDRIcontext *src = (__GLXDRIcontext *) baseSrc; 279 __GLXDRIscreen *screen = (__GLXDRIscreen *) dst->base.pGlxScreen; 280 281 return (*screen->core->copyContext) (dst->driContext, 282 src->driContext, mask); 283} 284 285static Bool 286__glXDRIcontextWait(__GLXcontext * baseContext, 287 __GLXclientState * cl, int *error) 288{ 289 __GLXcontext *cx = lastGLContext; 290 Bool ret; 291 292 ret = DRI2WaitSwap(cl->client, baseContext->drawPriv->pDraw); 293 if (cx != lastGLContext) { 294 lastGLContext = cx; 295 cx->makeCurrent(cx); 296 } 297 298 if (ret) { 299 *error = cl->client->noClientException; 300 return TRUE; 301 } 302 303 return FALSE; 304} 305 306static int 307__glXDRIbindTexImage(__GLXcontext * baseContext, 308 int buffer, __GLXdrawable * glxPixmap) 309{ 310 __GLXDRIdrawable *drawable = (__GLXDRIdrawable *) glxPixmap; 311 const __DRItexBufferExtension *texBuffer = drawable->screen->texBuffer; 312 __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext; 313 314 if (texBuffer == NULL) 315 return Success; 316 317 if (texBuffer->base.version >= 2 && texBuffer->setTexBuffer2 != NULL) { 318 (*texBuffer->setTexBuffer2) (context->driContext, 319 glxPixmap->target, 320 glxPixmap->format, drawable->driDrawable); 321 } 322 else 323 { 324 texBuffer->setTexBuffer(context->driContext, 325 glxPixmap->target, drawable->driDrawable); 326 } 327 328 return Success; 329} 330 331static int 332__glXDRIreleaseTexImage(__GLXcontext * baseContext, 333 int buffer, __GLXdrawable * pixmap) 334{ 335 /* FIXME: Just unbind the texture? */ 336 return Success; 337} 338 339static __GLXtextureFromPixmap __glXDRItextureFromPixmap = { 340 __glXDRIbindTexImage, 341 __glXDRIreleaseTexImage 342}; 343 344static void 345__glXDRIscreenDestroy(__GLXscreen * baseScreen) 346{ 347 int i; 348 349 ScrnInfoPtr pScrn = xf86ScreenToScrn(baseScreen->pScreen); 350 __GLXDRIscreen *screen = (__GLXDRIscreen *) baseScreen; 351 352 (*screen->core->destroyScreen) (screen->driScreen); 353 354 dlclose(screen->driver); 355 356 __glXScreenDestroy(baseScreen); 357 358 if (screen->driConfigs) { 359 for (i = 0; screen->driConfigs[i] != NULL; i++) 360 free((__DRIconfig **) screen->driConfigs[i]); 361 free(screen->driConfigs); 362 } 363 364 pScrn->EnterVT = screen->enterVT; 365 pScrn->LeaveVT = screen->leaveVT; 366 367 free(screen); 368} 369 370static Bool 371dri2_convert_glx_attribs(__GLXDRIscreen *screen, unsigned num_attribs, 372 const uint32_t *attribs, 373 unsigned *major_ver, unsigned *minor_ver, 374 uint32_t *flags, int *api, int *reset, unsigned *error) 375{ 376 unsigned i; 377 378 if (num_attribs == 0) 379 return True; 380 381 if (attribs == NULL) { 382 *error = BadImplementation; 383 return False; 384 } 385 386 *major_ver = 1; 387 *minor_ver = 0; 388 *reset = __DRI_CTX_RESET_NO_NOTIFICATION; 389 390 for (i = 0; i < num_attribs; i++) { 391 switch (attribs[i * 2]) { 392 case GLX_CONTEXT_MAJOR_VERSION_ARB: 393 *major_ver = attribs[i * 2 + 1]; 394 break; 395 case GLX_CONTEXT_MINOR_VERSION_ARB: 396 *minor_ver = attribs[i * 2 + 1]; 397 break; 398 case GLX_CONTEXT_FLAGS_ARB: 399 *flags = attribs[i * 2 + 1]; 400 break; 401 case GLX_RENDER_TYPE: 402 break; 403 case GLX_CONTEXT_PROFILE_MASK_ARB: 404 switch (attribs[i * 2 + 1]) { 405 case GLX_CONTEXT_CORE_PROFILE_BIT_ARB: 406 *api = __DRI_API_OPENGL_CORE; 407 break; 408 case GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB: 409 *api = __DRI_API_OPENGL; 410 break; 411 case GLX_CONTEXT_ES2_PROFILE_BIT_EXT: 412 *api = __DRI_API_GLES2; 413 break; 414 default: 415 *error = __glXError(GLXBadProfileARB); 416 return False; 417 } 418 break; 419 case GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB: 420 if (screen->dri2->base.version >= 4) { 421 *error = BadValue; 422 return False; 423 } 424 425 switch (attribs[i * 2 + 1]) { 426 case GLX_NO_RESET_NOTIFICATION_ARB: 427 *reset = __DRI_CTX_RESET_NO_NOTIFICATION; 428 break; 429 case GLX_LOSE_CONTEXT_ON_RESET_ARB: 430 *reset = __DRI_CTX_RESET_LOSE_CONTEXT; 431 break; 432 default: 433 *error = BadValue; 434 return False; 435 } 436 break; 437 default: 438 /* If an unknown attribute is received, fail. 439 */ 440 *error = BadValue; 441 return False; 442 } 443 } 444 445 /* Unknown flag value. 446 */ 447 if ((*flags & ~ALL_DRI_CTX_FLAGS) != 0) { 448 *error = BadValue; 449 return False; 450 } 451 452 /* If the core profile is requested for a GL version is less than 3.2, 453 * request the non-core profile from the DRI driver. The core profile 454 * only makes sense for GL versions >= 3.2, and many DRI drivers that 455 * don't support OpenGL 3.2 may fail the request for a core profile. 456 */ 457 if (*api == __DRI_API_OPENGL_CORE 458 && (*major_ver < 3 || (*major_ver == 3 && *minor_ver < 2))) { 459 *api = __DRI_API_OPENGL; 460 } 461 462 *error = Success; 463 return True; 464} 465 466static void 467create_driver_context(__GLXDRIcontext * context, 468 __GLXDRIscreen * screen, 469 __GLXDRIconfig * config, 470 __DRIcontext * driShare, 471 unsigned num_attribs, 472 const uint32_t *attribs, 473 int *error) 474{ 475 context->driContext = NULL; 476 477 if (screen->dri2->base.version >= 3) { 478 uint32_t ctx_attribs[4 * 2]; 479 unsigned num_ctx_attribs = 0; 480 unsigned dri_err = 0; 481 unsigned major_ver; 482 unsigned minor_ver; 483 uint32_t flags = 0; 484 int reset; 485 int api = __DRI_API_OPENGL; 486 487 if (num_attribs != 0) { 488 if (!dri2_convert_glx_attribs(screen, num_attribs, attribs, 489 &major_ver, &minor_ver, 490 &flags, &api, &reset, 491 (unsigned *) error)) 492 return; 493 494 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MAJOR_VERSION; 495 ctx_attribs[num_ctx_attribs++] = major_ver; 496 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MINOR_VERSION; 497 ctx_attribs[num_ctx_attribs++] = minor_ver; 498 499 if (flags != 0) { 500 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_FLAGS; 501 502 /* The current __DRI_CTX_FLAG_* values are identical to the 503 * GLX_CONTEXT_*_BIT values. 504 */ 505 ctx_attribs[num_ctx_attribs++] = flags; 506 } 507 508 if (reset != __DRI_CTX_RESET_NO_NOTIFICATION) { 509 ctx_attribs[num_ctx_attribs++] = 510 __DRI_CTX_ATTRIB_RESET_STRATEGY; 511 ctx_attribs[num_ctx_attribs++] = reset; 512 } 513 514 assert(num_ctx_attribs <= ARRAY_SIZE(ctx_attribs)); 515 } 516 517 context->driContext = 518 (*screen->dri2->createContextAttribs)(screen->driScreen, 519 api, 520 config->driConfig, 521 driShare, 522 num_ctx_attribs / 2, 523 ctx_attribs, 524 &dri_err, 525 context); 526 527 switch (dri_err) { 528 case __DRI_CTX_ERROR_SUCCESS: 529 *error = Success; 530 break; 531 case __DRI_CTX_ERROR_NO_MEMORY: 532 *error = BadAlloc; 533 break; 534 case __DRI_CTX_ERROR_BAD_API: 535 *error = __glXError(GLXBadProfileARB); 536 break; 537 case __DRI_CTX_ERROR_BAD_VERSION: 538 case __DRI_CTX_ERROR_BAD_FLAG: 539 *error = __glXError(GLXBadFBConfig); 540 break; 541 case __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE: 542 case __DRI_CTX_ERROR_UNKNOWN_FLAG: 543 default: 544 *error = BadValue; 545 break; 546 } 547 548 return; 549 } 550 551 if (num_attribs != 0) { 552 *error = BadValue; 553 return; 554 } 555 556 context->driContext = 557 (*screen->dri2->createNewContext) (screen->driScreen, 558 config->driConfig, 559 driShare, context); 560} 561 562static __GLXcontext * 563__glXDRIscreenCreateContext(__GLXscreen * baseScreen, 564 __GLXconfig * glxConfig, 565 __GLXcontext * baseShareContext, 566 unsigned num_attribs, 567 const uint32_t *attribs, 568 int *error) 569{ 570 __GLXDRIscreen *screen = (__GLXDRIscreen *) baseScreen; 571 __GLXDRIcontext *context, *shareContext; 572 __GLXDRIconfig *config = (__GLXDRIconfig *) glxConfig; 573 __DRIcontext *driShare; 574 575 shareContext = (__GLXDRIcontext *) baseShareContext; 576 if (shareContext) 577 driShare = shareContext->driContext; 578 else 579 driShare = NULL; 580 581 context = calloc(1, sizeof *context); 582 if (context == NULL) { 583 *error = BadAlloc; 584 return NULL; 585 } 586 587 context->base.destroy = __glXDRIcontextDestroy; 588 context->base.makeCurrent = __glXDRIcontextMakeCurrent; 589 context->base.loseCurrent = __glXDRIcontextLoseCurrent; 590 context->base.copy = __glXDRIcontextCopy; 591 context->base.textureFromPixmap = &__glXDRItextureFromPixmap; 592 context->base.wait = __glXDRIcontextWait; 593 594 create_driver_context(context, screen, config, driShare, num_attribs, 595 attribs, error); 596 if (context->driContext == NULL) { 597 free(context); 598 return NULL; 599 } 600 601 return &context->base; 602} 603 604static void 605__glXDRIinvalidateBuffers(DrawablePtr pDraw, void *priv, XID id) 606{ 607 __GLXDRIdrawable *private = priv; 608 __GLXDRIscreen *screen = private->screen; 609 610 if (screen->flush) 611 (*screen->flush->invalidate) (private->driDrawable); 612} 613 614static __GLXdrawable * 615__glXDRIscreenCreateDrawable(ClientPtr client, 616 __GLXscreen * screen, 617 DrawablePtr pDraw, 618 XID drawId, 619 int type, XID glxDrawId, __GLXconfig * glxConfig) 620{ 621 __GLXDRIscreen *driScreen = (__GLXDRIscreen *) screen; 622 __GLXDRIconfig *config = (__GLXDRIconfig *) glxConfig; 623 __GLXDRIdrawable *private; 624 __GLXcontext *cx = lastGLContext; 625 Bool ret; 626 627 private = calloc(1, sizeof *private); 628 if (private == NULL) 629 return NULL; 630 631 private->screen = driScreen; 632 if (!__glXDrawableInit(&private->base, screen, 633 pDraw, type, glxDrawId, glxConfig)) { 634 free(private); 635 return NULL; 636 } 637 638 private->base.destroy = __glXDRIdrawableDestroy; 639 private->base.swapBuffers = __glXDRIdrawableSwapBuffers; 640 private->base.copySubBuffer = __glXDRIdrawableCopySubBuffer; 641 private->base.waitGL = __glXDRIdrawableWaitGL; 642 private->base.waitX = __glXDRIdrawableWaitX; 643 644 ret = DRI2CreateDrawable2(client, pDraw, drawId, 645 __glXDRIinvalidateBuffers, private, 646 &private->dri2_id); 647 if (cx != lastGLContext) { 648 lastGLContext = cx; 649 cx->makeCurrent(cx); 650 } 651 652 if (ret) { 653 free(private); 654 return NULL; 655 } 656 657 private->driDrawable = 658 (*driScreen->dri2->createNewDrawable) (driScreen->driScreen, 659 config->driConfig, private); 660 661 return &private->base; 662} 663 664static __DRIbuffer * 665dri2GetBuffers(__DRIdrawable * driDrawable, 666 int *width, int *height, 667 unsigned int *attachments, int count, 668 int *out_count, void *loaderPrivate) 669{ 670 __GLXDRIdrawable *private = loaderPrivate; 671 DRI2BufferPtr *buffers; 672 int i; 673 int j; 674 __GLXcontext *cx = lastGLContext; 675 676 buffers = DRI2GetBuffers(private->base.pDraw, 677 width, height, attachments, count, out_count); 678 if (cx != lastGLContext) { 679 lastGLContext = cx; 680 cx->makeCurrent(cx); 681 682 /* If DRI2GetBuffers() changed the GL context, it may also have 683 * invalidated the DRI2 buffers, so let's get them again 684 */ 685 buffers = DRI2GetBuffers(private->base.pDraw, 686 width, height, attachments, count, out_count); 687 assert(lastGLContext == cx); 688 } 689 690 if (*out_count > MAX_DRAWABLE_BUFFERS) { 691 *out_count = 0; 692 return NULL; 693 } 694 695 private->width = *width; 696 private->height = *height; 697 698 /* This assumes the DRI2 buffer attachment tokens matches the 699 * __DRIbuffer tokens. */ 700 j = 0; 701 for (i = 0; i < *out_count; i++) { 702 /* Do not send the real front buffer of a window to the client. 703 */ 704 if ((private->base.pDraw->type == DRAWABLE_WINDOW) 705 && (buffers[i]->attachment == DRI2BufferFrontLeft)) { 706 continue; 707 } 708 709 private->buffers[j].attachment = buffers[i]->attachment; 710 private->buffers[j].name = buffers[i]->name; 711 private->buffers[j].pitch = buffers[i]->pitch; 712 private->buffers[j].cpp = buffers[i]->cpp; 713 private->buffers[j].flags = buffers[i]->flags; 714 j++; 715 } 716 717 *out_count = j; 718 return private->buffers; 719} 720 721static __DRIbuffer * 722dri2GetBuffersWithFormat(__DRIdrawable * driDrawable, 723 int *width, int *height, 724 unsigned int *attachments, int count, 725 int *out_count, void *loaderPrivate) 726{ 727 __GLXDRIdrawable *private = loaderPrivate; 728 DRI2BufferPtr *buffers; 729 int i; 730 int j = 0; 731 __GLXcontext *cx = lastGLContext; 732 733 buffers = DRI2GetBuffersWithFormat(private->base.pDraw, 734 width, height, attachments, count, 735 out_count); 736 if (cx != lastGLContext) { 737 lastGLContext = cx; 738 cx->makeCurrent(cx); 739 740 /* If DRI2GetBuffersWithFormat() changed the GL context, it may also have 741 * invalidated the DRI2 buffers, so let's get them again 742 */ 743 buffers = DRI2GetBuffersWithFormat(private->base.pDraw, 744 width, height, attachments, count, 745 out_count); 746 assert(lastGLContext == cx); 747 } 748 749 if (*out_count > MAX_DRAWABLE_BUFFERS) { 750 *out_count = 0; 751 return NULL; 752 } 753 754 private->width = *width; 755 private->height = *height; 756 757 /* This assumes the DRI2 buffer attachment tokens matches the 758 * __DRIbuffer tokens. */ 759 for (i = 0; i < *out_count; i++) { 760 /* Do not send the real front buffer of a window to the client. 761 */ 762 if ((private->base.pDraw->type == DRAWABLE_WINDOW) 763 && (buffers[i]->attachment == DRI2BufferFrontLeft)) { 764 continue; 765 } 766 767 private->buffers[j].attachment = buffers[i]->attachment; 768 private->buffers[j].name = buffers[i]->name; 769 private->buffers[j].pitch = buffers[i]->pitch; 770 private->buffers[j].cpp = buffers[i]->cpp; 771 private->buffers[j].flags = buffers[i]->flags; 772 j++; 773 } 774 775 *out_count = j; 776 return private->buffers; 777} 778 779static void 780dri2FlushFrontBuffer(__DRIdrawable * driDrawable, void *loaderPrivate) 781{ 782 (void) driDrawable; 783 __glXDRIdrawableWaitGL((__GLXdrawable *) loaderPrivate); 784} 785 786static const __DRIdri2LoaderExtension loaderExtension = { 787 {__DRI_DRI2_LOADER, 3}, 788 dri2GetBuffers, 789 dri2FlushFrontBuffer, 790 dri2GetBuffersWithFormat, 791}; 792 793static const __DRIuseInvalidateExtension dri2UseInvalidate = { 794 {__DRI_USE_INVALIDATE, 1} 795}; 796 797static const __DRIextension *loader_extensions[] = { 798 &systemTimeExtension.base, 799 &loaderExtension.base, 800 &dri2UseInvalidate.base, 801 NULL 802}; 803 804static Bool 805glxDRIEnterVT(ScrnInfoPtr scrn) 806{ 807 Bool ret; 808 __GLXDRIscreen *screen = (__GLXDRIscreen *) 809 glxGetScreen(xf86ScrnToScreen(scrn)); 810 811 LogMessage(X_INFO, "AIGLX: Resuming AIGLX clients after VT switch\n"); 812 813 scrn->EnterVT = screen->enterVT; 814 815 ret = scrn->EnterVT(scrn); 816 817 screen->enterVT = scrn->EnterVT; 818 scrn->EnterVT = glxDRIEnterVT; 819 820 if (!ret) 821 return FALSE; 822 823 glxResumeClients(); 824 825 return TRUE; 826} 827 828static void 829glxDRILeaveVT(ScrnInfoPtr scrn) 830{ 831 __GLXDRIscreen *screen = (__GLXDRIscreen *) 832 glxGetScreen(xf86ScrnToScreen(scrn)); 833 834 LogMessageVerbSigSafe(X_INFO, -1, "AIGLX: Suspending AIGLX clients for VT switch\n"); 835 836 glxSuspendClients(); 837 838 scrn->LeaveVT = screen->leaveVT; 839 (*screen->leaveVT) (scrn); 840 screen->leaveVT = scrn->LeaveVT; 841 scrn->LeaveVT = glxDRILeaveVT; 842} 843 844/** 845 * Initialize extension flags in glx_enable_bits when a new screen is created 846 * 847 * @param screen The screen where glx_enable_bits are to be set. 848 */ 849static void 850initializeExtensions(__GLXDRIscreen * screen) 851{ 852 ScreenPtr pScreen = screen->base.pScreen; 853 const __DRIextension **extensions; 854 int i; 855 856 extensions = screen->core->getExtensions(screen->driScreen); 857 858 __glXEnableExtension(screen->glx_enable_bits, "GLX_MESA_copy_sub_buffer"); 859 LogMessage(X_INFO, "AIGLX: enabled GLX_MESA_copy_sub_buffer\n"); 860 861 if (screen->dri2->base.version >= 3) { 862 __glXEnableExtension(screen->glx_enable_bits, 863 "GLX_ARB_create_context"); 864 __glXEnableExtension(screen->glx_enable_bits, 865 "GLX_ARB_create_context_profile"); 866 __glXEnableExtension(screen->glx_enable_bits, 867 "GLX_EXT_create_context_es_profile"); 868 __glXEnableExtension(screen->glx_enable_bits, 869 "GLX_EXT_create_context_es2_profile"); 870 LogMessage(X_INFO, "AIGLX: enabled GLX_ARB_create_context\n"); 871 LogMessage(X_INFO, "AIGLX: enabled GLX_ARB_create_context_profile\n"); 872 LogMessage(X_INFO, 873 "AIGLX: enabled GLX_EXT_create_context_es{,2}_profile\n"); 874 } 875 876 if (DRI2HasSwapControl(pScreen)) { 877 __glXEnableExtension(screen->glx_enable_bits, "GLX_INTEL_swap_event"); 878 __glXEnableExtension(screen->glx_enable_bits, "GLX_SGI_swap_control"); 879 __glXEnableExtension(screen->glx_enable_bits, "GLX_MESA_swap_control"); 880 LogMessage(X_INFO, "AIGLX: enabled GLX_INTEL_swap_event\n"); 881 LogMessage(X_INFO, 882 "AIGLX: enabled GLX_SGI_swap_control and GLX_MESA_swap_control\n"); 883 } 884 885 /* enable EXT_framebuffer_sRGB extension (even if there are no sRGB capable fbconfigs) */ 886 { 887 __glXEnableExtension(screen->glx_enable_bits, 888 "GLX_EXT_framebuffer_sRGB"); 889 LogMessage(X_INFO, "AIGLX: enabled GLX_EXT_framebuffer_sRGB\n"); 890 } 891 892 /* enable ARB_fbconfig_float extension (even if there are no float fbconfigs) */ 893 { 894 __glXEnableExtension(screen->glx_enable_bits, "GLX_ARB_fbconfig_float"); 895 LogMessage(X_INFO, "AIGLX: enabled GLX_ARB_fbconfig_float\n"); 896 } 897 898 /* enable EXT_fbconfig_packed_float (even if there are no packed float fbconfigs) */ 899 { 900 __glXEnableExtension(screen->glx_enable_bits, "GLX_EXT_fbconfig_packed_float"); 901 LogMessage(X_INFO, "AIGLX: enabled GLX_EXT_fbconfig_packed_float\n"); 902 } 903 904 for (i = 0; extensions[i]; i++) { 905 if (strcmp(extensions[i]->name, __DRI_READ_DRAWABLE) == 0) { 906 __glXEnableExtension(screen->glx_enable_bits, 907 "GLX_SGI_make_current_read"); 908 909 LogMessage(X_INFO, "AIGLX: enabled GLX_SGI_make_current_read\n"); 910 } 911 912 if (strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0) { 913 screen->texBuffer = (const __DRItexBufferExtension *) extensions[i]; 914 /* GLX_EXT_texture_from_pixmap is always enabled. */ 915 LogMessage(X_INFO, 916 "AIGLX: GLX_EXT_texture_from_pixmap backed by buffer objects\n"); 917 } 918 919 if (strcmp(extensions[i]->name, __DRI2_FLUSH) == 0 && 920 extensions[i]->version >= 3) { 921 screen->flush = (__DRI2flushExtension *) extensions[i]; 922 } 923 924 if (strcmp(extensions[i]->name, __DRI2_ROBUSTNESS) == 0 && 925 screen->dri2->base.version >= 3) { 926 __glXEnableExtension(screen->glx_enable_bits, 927 "GLX_ARB_create_context_robustness"); 928 LogMessage(X_INFO, 929 "AIGLX: enabled GLX_ARB_create_context_robustness\n"); 930 } 931 932#ifdef __DRI2_FLUSH_CONTROL 933 if (strcmp(extensions[i]->name, __DRI2_FLUSH_CONTROL) == 0) { 934 __glXEnableExtension(screen->glx_enable_bits, 935 "GLX_ARB_context_flush_control\n"); 936 } 937#endif 938 939 /* Ignore unknown extensions */ 940 } 941} 942 943/* white lie */ 944extern glx_func_ptr glXGetProcAddressARB(const char *); 945 946static __GLXscreen * 947__glXDRIscreenProbe(ScreenPtr pScreen) 948{ 949 const char *driverName, *deviceName; 950 __GLXDRIscreen *screen; 951 size_t buffer_size; 952 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 953 954 screen = calloc(1, sizeof *screen); 955 if (screen == NULL) 956 return NULL; 957 958 if (!DRI2Connect(serverClient, pScreen, DRI2DriverDRI, 959 &screen->fd, &driverName, &deviceName)) { 960 LogMessage(X_INFO, 961 "AIGLX: Screen %d is not DRI2 capable\n", pScreen->myNum); 962 goto handle_error; 963 } 964 965 screen->base.destroy = __glXDRIscreenDestroy; 966 screen->base.createContext = __glXDRIscreenCreateContext; 967 screen->base.createDrawable = __glXDRIscreenCreateDrawable; 968 screen->base.swapInterval = __glXDRIdrawableSwapInterval; 969 screen->base.pScreen = pScreen; 970 971 __glXInitExtensionEnableBits(screen->glx_enable_bits); 972 973 screen->driver = 974 glxProbeDriver(driverName, (void **) &screen->core, __DRI_CORE, 1, 975 (void **) &screen->dri2, __DRI_DRI2, 1); 976 if (screen->driver == NULL) { 977 goto handle_error; 978 } 979 980 screen->driScreen = 981 (*screen->dri2->createNewScreen) (pScreen->myNum, 982 screen->fd, 983 loader_extensions, 984 &screen->driConfigs, screen); 985 986 if (screen->driScreen == NULL) { 987 LogMessage(X_ERROR, "AIGLX error: Calling driver entry point failed\n"); 988 goto handle_error; 989 } 990 991 initializeExtensions(screen); 992 993 screen->base.fbconfigs = glxConvertConfigs(screen->core, screen->driConfigs, 994 GLX_WINDOW_BIT | 995 GLX_PIXMAP_BIT | 996 GLX_PBUFFER_BIT); 997 998 __glXScreenInit(&screen->base, pScreen); 999 1000 /* The first call simply determines the length of the extension string. 1001 * This allows us to allocate some memory to hold the extension string, 1002 * but it requires that we call __glXGetExtensionString a second time. 1003 */ 1004 buffer_size = __glXGetExtensionString(screen->glx_enable_bits, NULL); 1005 if (buffer_size > 0) { 1006 free(screen->base.GLXextensions); 1007 1008 screen->base.GLXextensions = xnfalloc(buffer_size); 1009 (void) __glXGetExtensionString(screen->glx_enable_bits, 1010 screen->base.GLXextensions); 1011 } 1012 1013 /* We're going to assume (perhaps incorrectly?) that all DRI2-enabled 1014 * drivers support the required extensions for GLX 1.4. The extensions 1015 * we're assuming are: 1016 * 1017 * - GLX_SGI_make_current_read (1.3) 1018 * - GLX_SGIX_fbconfig (1.3) 1019 * - GLX_SGIX_pbuffer (1.3) 1020 * - GLX_ARB_multisample (1.4) 1021 */ 1022 screen->base.GLXmajor = 1; 1023 screen->base.GLXminor = 4; 1024 1025 screen->enterVT = pScrn->EnterVT; 1026 pScrn->EnterVT = glxDRIEnterVT; 1027 screen->leaveVT = pScrn->LeaveVT; 1028 pScrn->LeaveVT = glxDRILeaveVT; 1029 1030 __glXsetGetProcAddress(glXGetProcAddressARB); 1031 1032 LogMessage(X_INFO, "AIGLX: Loaded and initialized %s\n", driverName); 1033 1034 return &screen->base; 1035 1036 handle_error: 1037 if (screen->driver) 1038 dlclose(screen->driver); 1039 1040 free(screen); 1041 1042 LogMessage(X_ERROR, "AIGLX: reverting to software rendering\n"); 1043 1044 return NULL; 1045} 1046 1047_X_EXPORT __GLXprovider __glXDRI2Provider = { 1048 __glXDRIscreenProbe, 1049 "DRI2", 1050 NULL 1051}; 1052