glxdri2.c revision 4642e01f
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 51#include "g_disptab.h" 52#include "glapitable.h" 53#include "glapi.h" 54#include "glthread.h" 55#include "dispatch.h" 56#include "extension_string.h" 57 58typedef struct __GLXDRIscreen __GLXDRIscreen; 59typedef struct __GLXDRIcontext __GLXDRIcontext; 60typedef struct __GLXDRIdrawable __GLXDRIdrawable; 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 __DRIcopySubBufferExtension *copySubBuffer; 74 const __DRIswapControlExtension *swapControl; 75 const __DRItexBufferExtension *texBuffer; 76 77 unsigned char glx_enable_bits[__GLX_EXT_BYTES]; 78}; 79 80struct __GLXDRIcontext { 81 __GLXcontext base; 82 __DRIcontext *driContext; 83}; 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[5]; 94 int count; 95}; 96 97static void 98__glXDRIdrawableDestroy(__GLXdrawable *drawable) 99{ 100 __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable; 101 const __DRIcoreExtension *core = private->screen->core; 102 103 (*core->destroyDrawable)(private->driDrawable); 104 105 /* If the X window was destroyed, the dri DestroyWindow hook will 106 * aready have taken care of this, so only call if pDraw isn't NULL. */ 107 if (drawable->pDraw != NULL) 108 DRI2DestroyDrawable(drawable->pDraw); 109 110 __glXDrawableRelease(drawable); 111 112 xfree(private); 113} 114 115static void 116__glXDRIdrawableCopySubBuffer(__GLXdrawable *drawable, 117 int x, int y, int w, int h) 118{ 119 __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable; 120 BoxRec box; 121 RegionRec region; 122 123 box.x1 = x; 124 box.y1 = private->height - y - h; 125 box.x2 = x + w; 126 box.y2 = private->height - y; 127 REGION_INIT(drawable->pDraw->pScreen, ®ion, &box, 0); 128 129 DRI2CopyRegion(drawable->pDraw, ®ion, 130 DRI2BufferFrontLeft, DRI2BufferBackLeft); 131} 132 133static GLboolean 134__glXDRIdrawableSwapBuffers(__GLXdrawable *drawable) 135{ 136 __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable; 137 138 __glXDRIdrawableCopySubBuffer(drawable, 0, 0, 139 private->width, private->height); 140 141 return TRUE; 142} 143 144 145static int 146__glXDRIdrawableSwapInterval(__GLXdrawable *drawable, int interval) 147{ 148 return 0; 149} 150 151static void 152__glXDRIcontextDestroy(__GLXcontext *baseContext) 153{ 154 __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext; 155 __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen; 156 157 (*screen->core->destroyContext)(context->driContext); 158 __glXContextDestroy(&context->base); 159 xfree(context); 160} 161 162static int 163__glXDRIcontextMakeCurrent(__GLXcontext *baseContext) 164{ 165 __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext; 166 __GLXDRIdrawable *draw = (__GLXDRIdrawable *) baseContext->drawPriv; 167 __GLXDRIdrawable *read = (__GLXDRIdrawable *) baseContext->readPriv; 168 __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen; 169 170 return (*screen->core->bindContext)(context->driContext, 171 draw->driDrawable, 172 read->driDrawable); 173} 174 175static int 176__glXDRIcontextLoseCurrent(__GLXcontext *baseContext) 177{ 178 __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext; 179 __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen; 180 181 return (*screen->core->unbindContext)(context->driContext); 182} 183 184static int 185__glXDRIcontextCopy(__GLXcontext *baseDst, __GLXcontext *baseSrc, 186 unsigned long mask) 187{ 188 __GLXDRIcontext *dst = (__GLXDRIcontext *) baseDst; 189 __GLXDRIcontext *src = (__GLXDRIcontext *) baseSrc; 190 __GLXDRIscreen *screen = (__GLXDRIscreen *) dst->base.pGlxScreen; 191 192 return (*screen->core->copyContext)(dst->driContext, 193 src->driContext, mask); 194} 195 196static int 197__glXDRIcontextForceCurrent(__GLXcontext *baseContext) 198{ 199 __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext; 200 __GLXDRIdrawable *draw = (__GLXDRIdrawable *) baseContext->drawPriv; 201 __GLXDRIdrawable *read = (__GLXDRIdrawable *) baseContext->readPriv; 202 __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen; 203 204 return (*screen->core->bindContext)(context->driContext, 205 draw->driDrawable, 206 read->driDrawable); 207} 208 209#ifdef __DRI_TEX_BUFFER 210 211static int 212__glXDRIbindTexImage(__GLXcontext *baseContext, 213 int buffer, 214 __GLXdrawable *glxPixmap) 215{ 216 __GLXDRIdrawable *drawable = (__GLXDRIdrawable *) glxPixmap; 217 const __DRItexBufferExtension *texBuffer = drawable->screen->texBuffer; 218 __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext; 219 220 if (texBuffer == NULL) 221 return Success; 222 223 texBuffer->setTexBuffer(context->driContext, 224 glxPixmap->target, 225 drawable->driDrawable); 226 227 return Success; 228} 229 230static int 231__glXDRIreleaseTexImage(__GLXcontext *baseContext, 232 int buffer, 233 __GLXdrawable *pixmap) 234{ 235 /* FIXME: Just unbind the texture? */ 236 return Success; 237} 238 239#else 240 241static int 242__glXDRIbindTexImage(__GLXcontext *baseContext, 243 int buffer, 244 __GLXdrawable *glxPixmap) 245{ 246 return Success; 247} 248 249static int 250__glXDRIreleaseTexImage(__GLXcontext *baseContext, 251 int buffer, 252 __GLXdrawable *pixmap) 253{ 254 return Success; 255} 256 257#endif 258 259static __GLXtextureFromPixmap __glXDRItextureFromPixmap = { 260 __glXDRIbindTexImage, 261 __glXDRIreleaseTexImage 262}; 263 264static void 265__glXDRIscreenDestroy(__GLXscreen *baseScreen) 266{ 267 __GLXDRIscreen *screen = (__GLXDRIscreen *) baseScreen; 268 269 (*screen->core->destroyScreen)(screen->driScreen); 270 271 dlclose(screen->driver); 272 273 __glXScreenDestroy(baseScreen); 274 275 xfree(screen); 276} 277 278static __GLXcontext * 279__glXDRIscreenCreateContext(__GLXscreen *baseScreen, 280 __GLXconfig *glxConfig, 281 __GLXcontext *baseShareContext) 282{ 283 __GLXDRIscreen *screen = (__GLXDRIscreen *) baseScreen; 284 __GLXDRIcontext *context, *shareContext; 285 __GLXDRIconfig *config = (__GLXDRIconfig *) glxConfig; 286 __DRIcontext *driShare; 287 288 shareContext = (__GLXDRIcontext *) baseShareContext; 289 if (shareContext) 290 driShare = shareContext->driContext; 291 else 292 driShare = NULL; 293 294 context = xcalloc(1, sizeof *context); 295 if (context == NULL) 296 return NULL; 297 298 context->base.destroy = __glXDRIcontextDestroy; 299 context->base.makeCurrent = __glXDRIcontextMakeCurrent; 300 context->base.loseCurrent = __glXDRIcontextLoseCurrent; 301 context->base.copy = __glXDRIcontextCopy; 302 context->base.forceCurrent = __glXDRIcontextForceCurrent; 303 context->base.textureFromPixmap = &__glXDRItextureFromPixmap; 304 305 context->driContext = 306 (*screen->dri2->createNewContext)(screen->driScreen, 307 config->driConfig, 308 driShare, context); 309 if (context->driContext == NULL) { 310 xfree(context); 311 return NULL; 312 } 313 314 return &context->base; 315} 316 317static __GLXdrawable * 318__glXDRIscreenCreateDrawable(__GLXscreen *screen, 319 DrawablePtr pDraw, 320 int type, 321 XID drawId, 322 __GLXconfig *glxConfig) 323{ 324 __GLXDRIscreen *driScreen = (__GLXDRIscreen *) screen; 325 __GLXDRIconfig *config = (__GLXDRIconfig *) glxConfig; 326 __GLXDRIdrawable *private; 327 328 private = xcalloc(1, sizeof *private); 329 if (private == NULL) 330 return NULL; 331 332 private->screen = driScreen; 333 if (!__glXDrawableInit(&private->base, screen, 334 pDraw, type, drawId, glxConfig)) { 335 xfree(private); 336 return NULL; 337 } 338 339 private->base.destroy = __glXDRIdrawableDestroy; 340 private->base.swapBuffers = __glXDRIdrawableSwapBuffers; 341 private->base.copySubBuffer = __glXDRIdrawableCopySubBuffer; 342 343 if (DRI2CreateDrawable(pDraw)) { 344 xfree(private); 345 return NULL; 346 } 347 348 private->driDrawable = 349 (*driScreen->dri2->createNewDrawable)(driScreen->driScreen, 350 config->driConfig, private); 351 352 return &private->base; 353} 354 355static __DRIbuffer * 356dri2GetBuffers(__DRIdrawable *driDrawable, 357 int *width, int *height, 358 unsigned int *attachments, int count, 359 int *out_count, void *loaderPrivate) 360{ 361 __GLXDRIdrawable *private = loaderPrivate; 362 DRI2BufferPtr buffers; 363 int i; 364 365 buffers = DRI2GetBuffers(private->base.pDraw, 366 width, height, attachments, count, out_count); 367 if (*out_count > 5) { 368 *out_count = 0; 369 return NULL; 370 } 371 372 private->width = *width; 373 private->height = *height; 374 375 /* This assumes the DRI2 buffer attachment tokens matches the 376 * __DRIbuffer tokens. */ 377 for (i = 0; i < *out_count; i++) { 378 private->buffers[i].attachment = buffers[i].attachment; 379 private->buffers[i].name = buffers[i].name; 380 private->buffers[i].pitch = buffers[i].pitch; 381 private->buffers[i].cpp = buffers[i].cpp; 382 private->buffers[i].flags = buffers[i].flags; 383 } 384 385 return private->buffers; 386} 387 388static const __DRIdri2LoaderExtension loaderExtension = { 389 { __DRI_DRI2_LOADER, __DRI_DRI2_LOADER_VERSION }, 390 dri2GetBuffers, 391}; 392 393static const __DRIextension *loader_extensions[] = { 394 &systemTimeExtension.base, 395 &loaderExtension.base, 396 NULL 397}; 398 399static const char dri_driver_path[] = DRI_DRIVER_PATH; 400 401static Bool 402glxDRIEnterVT (int index, int flags) 403{ 404 __GLXDRIscreen *screen = (__GLXDRIscreen *) 405 glxGetScreen(screenInfo.screens[index]); 406 407 LogMessage(X_INFO, "AIGLX: Resuming AIGLX clients after VT switch\n"); 408 409 if (!(*screen->enterVT) (index, flags)) 410 return FALSE; 411 412 glxResumeClients(); 413 414 return TRUE; 415} 416 417static void 418glxDRILeaveVT (int index, int flags) 419{ 420 __GLXDRIscreen *screen = (__GLXDRIscreen *) 421 glxGetScreen(screenInfo.screens[index]); 422 423 LogMessage(X_INFO, "AIGLX: Suspending AIGLX clients for VT switch\n"); 424 425 glxSuspendClients(); 426 427 return (*screen->leaveVT) (index, flags); 428} 429 430static void 431initializeExtensions(__GLXDRIscreen *screen) 432{ 433 const __DRIextension **extensions; 434 int i; 435 436 extensions = screen->core->getExtensions(screen->driScreen); 437 438 __glXEnableExtension(screen->glx_enable_bits, 439 "GLX_MESA_copy_sub_buffer"); 440 LogMessage(X_INFO, "AIGLX: enabled GLX_MESA_copy_sub_buffer\n"); 441 442 for (i = 0; extensions[i]; i++) { 443#ifdef __DRI_SWAP_CONTROL 444 if (strcmp(extensions[i]->name, __DRI_SWAP_CONTROL) == 0) { 445 screen->swapControl = 446 (const __DRIswapControlExtension *) extensions[i]; 447 __glXEnableExtension(screen->glx_enable_bits, 448 "GLX_SGI_swap_control"); 449 __glXEnableExtension(screen->glx_enable_bits, 450 "GLX_MESA_swap_control"); 451 452 LogMessage(X_INFO, "AIGLX: enabled GLX_SGI_swap_control and GLX_MESA_swap_control\n"); 453 } 454#endif 455 456#ifdef __DRI_TEX_BUFFER 457 if (strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0) { 458 screen->texBuffer = 459 (const __DRItexBufferExtension *) extensions[i]; 460 /* GLX_EXT_texture_from_pixmap is always enabled. */ 461 LogMessage(X_INFO, "AIGLX: GLX_EXT_texture_from_pixmap backed by buffer objects\n"); 462 } 463#endif 464 /* Ignore unknown extensions */ 465 } 466} 467 468static __GLXscreen * 469__glXDRIscreenProbe(ScreenPtr pScreen) 470{ 471 const char *driverName, *deviceName; 472 __GLXDRIscreen *screen; 473 char filename[128]; 474 size_t buffer_size; 475 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 476 const __DRIextension **extensions; 477 const __DRIconfig **driConfigs; 478 int i; 479 480 screen = xcalloc(1, sizeof *screen); 481 if (screen == NULL) 482 return NULL; 483 484 if (!xf86LoaderCheckSymbol("DRI2Connect") || 485 !DRI2Connect(pScreen, DRI2DriverDRI, 486 &screen->fd, &driverName, &deviceName)) { 487 LogMessage(X_INFO, 488 "AIGLX: Screen %d is not DRI2 capable\n", pScreen->myNum); 489 return NULL; 490 } 491 492 screen->base.destroy = __glXDRIscreenDestroy; 493 screen->base.createContext = __glXDRIscreenCreateContext; 494 screen->base.createDrawable = __glXDRIscreenCreateDrawable; 495 screen->base.swapInterval = __glXDRIdrawableSwapInterval; 496 screen->base.pScreen = pScreen; 497 498 __glXInitExtensionEnableBits(screen->glx_enable_bits); 499 500 snprintf(filename, sizeof filename, 501 "%s/%s_dri.so", dri_driver_path, driverName); 502 503 screen->driver = dlopen(filename, RTLD_LAZY | RTLD_LOCAL); 504 if (screen->driver == NULL) { 505 LogMessage(X_ERROR, "AIGLX error: dlopen of %s failed (%s)\n", 506 filename, dlerror()); 507 goto handle_error; 508 } 509 510 extensions = dlsym(screen->driver, __DRI_DRIVER_EXTENSIONS); 511 if (extensions == NULL) { 512 LogMessage(X_ERROR, "AIGLX error: %s exports no extensions (%s)\n", 513 driverName, dlerror()); 514 goto handle_error; 515 } 516 517 for (i = 0; extensions[i]; i++) { 518 if (strcmp(extensions[i]->name, __DRI_CORE) == 0 && 519 extensions[i]->version >= __DRI_CORE_VERSION) { 520 screen->core = (const __DRIcoreExtension *) extensions[i]; 521 } 522 if (strcmp(extensions[i]->name, __DRI_DRI2) == 0 && 523 extensions[i]->version >= __DRI_DRI2_VERSION) { 524 screen->dri2 = (const __DRIdri2Extension *) extensions[i]; 525 } 526 } 527 528 if (screen->core == NULL || screen->dri2 == NULL) { 529 LogMessage(X_ERROR, "AIGLX error: %s exports no DRI extension\n", 530 driverName); 531 goto handle_error; 532 } 533 534 screen->driScreen = 535 (*screen->dri2->createNewScreen)(pScreen->myNum, 536 screen->fd, 537 loader_extensions, 538 &driConfigs, 539 screen); 540 541 if (screen->driScreen == NULL) { 542 LogMessage(X_ERROR, 543 "AIGLX error: Calling driver entry point failed\n"); 544 goto handle_error; 545 } 546 547 initializeExtensions(screen); 548 549 screen->base.fbconfigs = glxConvertConfigs(screen->core, driConfigs); 550 551 __glXScreenInit(&screen->base, pScreen); 552 553 buffer_size = __glXGetExtensionString(screen->glx_enable_bits, NULL); 554 if (buffer_size > 0) { 555 if (screen->base.GLXextensions != NULL) { 556 xfree(screen->base.GLXextensions); 557 } 558 559 screen->base.GLXextensions = xnfalloc(buffer_size); 560 (void) __glXGetExtensionString(screen->glx_enable_bits, 561 screen->base.GLXextensions); 562 } 563 564 screen->enterVT = pScrn->EnterVT; 565 pScrn->EnterVT = glxDRIEnterVT; 566 screen->leaveVT = pScrn->LeaveVT; 567 pScrn->LeaveVT = glxDRILeaveVT; 568 569 LogMessage(X_INFO, 570 "AIGLX: Loaded and initialized %s\n", filename); 571 572 return &screen->base; 573 574 handle_error: 575 if (screen->driver) 576 dlclose(screen->driver); 577 578 xfree(screen); 579 580 LogMessage(X_ERROR, "AIGLX: reverting to software rendering\n"); 581 582 return NULL; 583} 584 585__GLXprovider __glXDRI2Provider = { 586 __glXDRIscreenProbe, 587 "DRI2", 588 NULL 589}; 590