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