1/* 2 * Copyright © 2008 George Sapountzis <gsap7@yahoo.gr> 3 * Copyright © 2008 Red Hat, Inc 4 * 5 * Permission to use, copy, modify, distribute, and sell this software 6 * and its documentation for any purpose is hereby granted without 7 * fee, provided that the above copyright notice appear in all copies 8 * and that both that copyright notice and this permission notice 9 * appear in supporting documentation, and that the name of the 10 * copyright holders not be used in advertising or publicity 11 * pertaining to distribution of the software without specific, 12 * written prior permission. The copyright holders make no 13 * representations about the suitability of this software for any 14 * purpose. It is provided "as is" without express or implied 15 * warranty. 16 * 17 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS 18 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 19 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 21 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 22 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 23 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 24 * SOFTWARE. 25 */ 26 27#ifdef HAVE_DIX_CONFIG_H 28#include <dix-config.h> 29#endif 30 31#include <stdint.h> 32#include <stdio.h> 33#include <string.h> 34#include <errno.h> 35#include <sys/time.h> 36#include <dlfcn.h> 37 38#include <GL/gl.h> 39#include <GL/internal/dri_interface.h> 40#include <GL/glxtokens.h> 41 42#include "scrnintstr.h" 43#include "pixmapstr.h" 44#include "gcstruct.h" 45#include "os.h" 46 47#include "glxserver.h" 48#include "glxutil.h" 49#include "glxdricommon.h" 50 51#include "glapitable.h" 52#include "glapi.h" 53#include "glthread.h" 54#include "dispatch.h" 55#include "extension_string.h" 56 57/* RTLD_LOCAL is not defined on Cygwin */ 58#ifdef __CYGWIN__ 59#ifndef RTLD_LOCAL 60#define RTLD_LOCAL 0 61#endif 62#endif 63 64typedef struct __GLXDRIscreen __GLXDRIscreen; 65typedef struct __GLXDRIcontext __GLXDRIcontext; 66typedef struct __GLXDRIdrawable __GLXDRIdrawable; 67 68struct __GLXDRIscreen { 69 __GLXscreen base; 70 __DRIscreen *driScreen; 71 void *driver; 72 73 const __DRIcoreExtension *core; 74 const __DRIswrastExtension *swrast; 75 const __DRIcopySubBufferExtension *copySubBuffer; 76 const __DRItexBufferExtension *texBuffer; 77}; 78 79struct __GLXDRIcontext { 80 __GLXcontext base; 81 __DRIcontext *driContext; 82}; 83 84struct __GLXDRIdrawable { 85 __GLXdrawable base; 86 __DRIdrawable *driDrawable; 87 __GLXDRIscreen *screen; 88 89 GCPtr gc; /* scratch GC for span drawing */ 90 GCPtr swapgc; /* GC for swapping the color buffers */ 91}; 92 93static void 94__glXDRIdrawableDestroy(__GLXdrawable *drawable) 95{ 96 __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable; 97 const __DRIcoreExtension *core = private->screen->core; 98 99 (*core->destroyDrawable)(private->driDrawable); 100 101 FreeGC(private->gc, (GContext)0); 102 FreeGC(private->swapgc, (GContext)0); 103 104 __glXDrawableRelease(drawable); 105 106 free(private); 107} 108 109static GLboolean 110__glXDRIdrawableSwapBuffers(ClientPtr client, __GLXdrawable *drawable) 111{ 112 __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable; 113 const __DRIcoreExtension *core = private->screen->core; 114 115 (*core->swapBuffers)(private->driDrawable); 116 117 return TRUE; 118} 119 120static void 121__glXDRIdrawableCopySubBuffer(__GLXdrawable *basePrivate, 122 int x, int y, int w, int h) 123{ 124 __GLXDRIdrawable *private = (__GLXDRIdrawable *) basePrivate; 125 const __DRIcopySubBufferExtension *copySubBuffer = 126 private->screen->copySubBuffer; 127 128 if (copySubBuffer) 129 (*copySubBuffer->copySubBuffer)(private->driDrawable, x, y, w, h); 130} 131 132static void 133__glXDRIcontextDestroy(__GLXcontext *baseContext) 134{ 135 __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext; 136 __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen; 137 138 (*screen->core->destroyContext)(context->driContext); 139 __glXContextDestroy(&context->base); 140 free(context); 141} 142 143static int 144__glXDRIcontextMakeCurrent(__GLXcontext *baseContext) 145{ 146 __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext; 147 __GLXDRIdrawable *draw = (__GLXDRIdrawable *) baseContext->drawPriv; 148 __GLXDRIdrawable *read = (__GLXDRIdrawable *) baseContext->readPriv; 149 __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen; 150 151 return (*screen->core->bindContext)(context->driContext, 152 draw->driDrawable, 153 read->driDrawable); 154} 155 156static int 157__glXDRIcontextLoseCurrent(__GLXcontext *baseContext) 158{ 159 __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext; 160 __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen; 161 162 return (*screen->core->unbindContext)(context->driContext); 163} 164 165static int 166__glXDRIcontextCopy(__GLXcontext *baseDst, __GLXcontext *baseSrc, 167 unsigned long mask) 168{ 169 __GLXDRIcontext *dst = (__GLXDRIcontext *) baseDst; 170 __GLXDRIcontext *src = (__GLXDRIcontext *) baseSrc; 171 __GLXDRIscreen *screen = (__GLXDRIscreen *) dst->base.pGlxScreen; 172 173 return (*screen->core->copyContext)(dst->driContext, 174 src->driContext, mask); 175} 176 177static int 178__glXDRIcontextForceCurrent(__GLXcontext *baseContext) 179{ 180 __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext; 181 __GLXDRIdrawable *draw = (__GLXDRIdrawable *) baseContext->drawPriv; 182 __GLXDRIdrawable *read = (__GLXDRIdrawable *) baseContext->readPriv; 183 __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen; 184 185 return (*screen->core->bindContext)(context->driContext, 186 draw->driDrawable, 187 read->driDrawable); 188} 189 190#ifdef __DRI_TEX_BUFFER 191 192static int 193__glXDRIbindTexImage(__GLXcontext *baseContext, 194 int buffer, 195 __GLXdrawable *glxPixmap) 196{ 197 __GLXDRIdrawable *drawable = (__GLXDRIdrawable *) glxPixmap; 198 const __DRItexBufferExtension *texBuffer = drawable->screen->texBuffer; 199 __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext; 200 201 if (texBuffer == NULL) 202 return Success; 203 204#if __DRI_TEX_BUFFER_VERSION >= 2 205 if (texBuffer->base.version >= 2 && texBuffer->setTexBuffer2 != NULL) { 206 (*texBuffer->setTexBuffer2)(context->driContext, 207 glxPixmap->target, 208 glxPixmap->format, 209 drawable->driDrawable); 210 } else 211#endif 212 texBuffer->setTexBuffer(context->driContext, 213 glxPixmap->target, 214 drawable->driDrawable); 215 216 return Success; 217} 218 219static int 220__glXDRIreleaseTexImage(__GLXcontext *baseContext, 221 int buffer, 222 __GLXdrawable *pixmap) 223{ 224 /* FIXME: Just unbind the texture? */ 225 return Success; 226} 227 228#else 229 230static int 231__glXDRIbindTexImage(__GLXcontext *baseContext, 232 int buffer, 233 __GLXdrawable *glxPixmap) 234{ 235 return Success; 236} 237 238static int 239__glXDRIreleaseTexImage(__GLXcontext *baseContext, 240 int buffer, 241 __GLXdrawable *pixmap) 242{ 243 return Success; 244} 245 246#endif 247 248static __GLXtextureFromPixmap __glXDRItextureFromPixmap = { 249 __glXDRIbindTexImage, 250 __glXDRIreleaseTexImage 251}; 252 253static void 254__glXDRIscreenDestroy(__GLXscreen *baseScreen) 255{ 256 __GLXDRIscreen *screen = (__GLXDRIscreen *) baseScreen; 257 258 (*screen->core->destroyScreen)(screen->driScreen); 259 260 dlclose(screen->driver); 261 262 __glXScreenDestroy(baseScreen); 263 264 free(screen); 265} 266 267static __GLXcontext * 268__glXDRIscreenCreateContext(__GLXscreen *baseScreen, 269 __GLXconfig *glxConfig, 270 __GLXcontext *baseShareContext) 271{ 272 __GLXDRIscreen *screen = (__GLXDRIscreen *) baseScreen; 273 __GLXDRIcontext *context, *shareContext; 274 __GLXDRIconfig *config = (__GLXDRIconfig *) glxConfig; 275 const __DRIcoreExtension *core = screen->core; 276 __DRIcontext *driShare; 277 278 shareContext = (__GLXDRIcontext *) baseShareContext; 279 if (shareContext) 280 driShare = shareContext->driContext; 281 else 282 driShare = NULL; 283 284 context = calloc(1, sizeof *context); 285 if (context == NULL) 286 return NULL; 287 288 context->base.destroy = __glXDRIcontextDestroy; 289 context->base.makeCurrent = __glXDRIcontextMakeCurrent; 290 context->base.loseCurrent = __glXDRIcontextLoseCurrent; 291 context->base.copy = __glXDRIcontextCopy; 292 context->base.forceCurrent = __glXDRIcontextForceCurrent; 293 context->base.textureFromPixmap = &__glXDRItextureFromPixmap; 294 295 context->driContext = 296 (*core->createNewContext)(screen->driScreen, 297 config->driConfig, driShare, context); 298 299 return &context->base; 300} 301 302static __GLXdrawable * 303__glXDRIscreenCreateDrawable(ClientPtr client, 304 __GLXscreen *screen, 305 DrawablePtr pDraw, 306 XID drawId, 307 int type, 308 XID glxDrawId, 309 __GLXconfig *glxConfig) 310{ 311 XID gcvals[2]; 312 int status; 313 __GLXDRIscreen *driScreen = (__GLXDRIscreen *) screen; 314 __GLXDRIconfig *config = (__GLXDRIconfig *) glxConfig; 315 __GLXDRIdrawable *private; 316 317 private = calloc(1, sizeof *private); 318 if (private == NULL) 319 return NULL; 320 321 private->screen = driScreen; 322 if (!__glXDrawableInit(&private->base, screen, 323 pDraw, type, glxDrawId, glxConfig)) { 324 free(private); 325 return NULL; 326 } 327 328 private->base.destroy = __glXDRIdrawableDestroy; 329 private->base.swapBuffers = __glXDRIdrawableSwapBuffers; 330 private->base.copySubBuffer = __glXDRIdrawableCopySubBuffer; 331 332 gcvals[0] = GXcopy; 333 private->gc = CreateGC(pDraw, GCFunction, gcvals, &status, (XID)0, serverClient); 334 gcvals[1] = FALSE; 335 private->swapgc = CreateGC(pDraw, GCFunction | GCGraphicsExposures, gcvals, &status, (XID)0, serverClient); 336 337 private->driDrawable = 338 (*driScreen->swrast->createNewDrawable)(driScreen->driScreen, 339 config->driConfig, 340 private); 341 342 return &private->base; 343} 344 345static void 346swrastGetDrawableInfo(__DRIdrawable *draw, 347 int *x, int *y, int *w, int *h, 348 void *loaderPrivate) 349{ 350 __GLXDRIdrawable *drawable = loaderPrivate; 351 DrawablePtr pDraw = drawable->base.pDraw; 352 353 *x = pDraw->x; 354 *y = pDraw->x; 355 *w = pDraw->width; 356 *h = pDraw->height; 357} 358 359static void 360swrastPutImage(__DRIdrawable *draw, int op, 361 int x, int y, int w, int h, char *data, 362 void *loaderPrivate) 363{ 364 __GLXDRIdrawable *drawable = loaderPrivate; 365 DrawablePtr pDraw = drawable->base.pDraw; 366 GCPtr gc; 367 368 switch (op) { 369 case __DRI_SWRAST_IMAGE_OP_DRAW: 370 gc = drawable->gc; 371 break; 372 case __DRI_SWRAST_IMAGE_OP_SWAP: 373 gc = drawable->swapgc; 374 break; 375 default: 376 return; 377 } 378 379 ValidateGC(pDraw, gc); 380 381 gc->ops->PutImage(pDraw, gc, pDraw->depth, 382 x, y, w, h, 0, ZPixmap, data); 383} 384 385static void 386swrastGetImage(__DRIdrawable *draw, 387 int x, int y, int w, int h, char *data, 388 void *loaderPrivate) 389{ 390 __GLXDRIdrawable *drawable = loaderPrivate; 391 DrawablePtr pDraw = drawable->base.pDraw; 392 ScreenPtr pScreen = pDraw->pScreen; 393 394 pScreen->GetImage(pDraw, x, y, w, h, ZPixmap, ~0L, data); 395} 396 397static const __DRIswrastLoaderExtension swrastLoaderExtension = { 398 { __DRI_SWRAST_LOADER, __DRI_SWRAST_LOADER_VERSION }, 399 swrastGetDrawableInfo, 400 swrastPutImage, 401 swrastGetImage 402}; 403 404static const __DRIextension *loader_extensions[] = { 405 &systemTimeExtension.base, 406 &swrastLoaderExtension.base, 407 NULL 408}; 409 410static void 411initializeExtensions(__GLXDRIscreen *screen) 412{ 413 const __DRIextension **extensions; 414 int i; 415 416 extensions = screen->core->getExtensions(screen->driScreen); 417 418 for (i = 0; extensions[i]; i++) { 419#ifdef __DRI_COPY_SUB_BUFFER 420 if (strcmp(extensions[i]->name, __DRI_COPY_SUB_BUFFER) == 0) { 421 screen->copySubBuffer = 422 (const __DRIcopySubBufferExtension *) extensions[i]; 423 /* GLX_MESA_copy_sub_buffer is always enabled. */ 424 } 425#endif 426 427#ifdef __DRI_TEX_BUFFER 428 if (strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0) { 429 screen->texBuffer = 430 (const __DRItexBufferExtension *) extensions[i]; 431 /* GLX_EXT_texture_from_pixmap is always enabled. */ 432 } 433#endif 434 /* Ignore unknown extensions */ 435 } 436} 437 438static const char dri_driver_path[] = DRI_DRIVER_PATH; 439 440static __GLXscreen * 441__glXDRIscreenProbe(ScreenPtr pScreen) 442{ 443 const char *driverName = "swrast"; 444 __GLXDRIscreen *screen; 445 char filename[128]; 446 const __DRIextension **extensions; 447 const __DRIconfig **driConfigs; 448 int i; 449 450 screen = calloc(1, sizeof *screen); 451 if (screen == NULL) 452 return NULL; 453 454 screen->base.destroy = __glXDRIscreenDestroy; 455 screen->base.createContext = __glXDRIscreenCreateContext; 456 screen->base.createDrawable = __glXDRIscreenCreateDrawable; 457 screen->base.swapInterval = NULL; 458 screen->base.pScreen = pScreen; 459 460 snprintf(filename, sizeof filename, 461 "%s/%s_dri.so", dri_driver_path, driverName); 462 463 screen->driver = dlopen(filename, RTLD_LAZY | RTLD_LOCAL); 464 if (screen->driver == NULL) { 465 LogMessage(X_ERROR, "AIGLX error: dlopen of %s failed (%s)\n", 466 filename, dlerror()); 467 goto handle_error; 468 } 469 470 extensions = dlsym(screen->driver, __DRI_DRIVER_EXTENSIONS); 471 if (extensions == NULL) { 472 LogMessage(X_ERROR, "AIGLX error: %s exports no extensions (%s)\n", 473 driverName, dlerror()); 474 goto handle_error; 475 } 476 477 for (i = 0; extensions[i]; i++) { 478 if (strcmp(extensions[i]->name, __DRI_CORE) == 0 && 479 extensions[i]->version >= __DRI_CORE_VERSION) { 480 screen->core = (const __DRIcoreExtension *) extensions[i]; 481 } 482 if (strcmp(extensions[i]->name, __DRI_SWRAST) == 0 && 483 extensions[i]->version >= __DRI_SWRAST_VERSION) { 484 screen->swrast = (const __DRIswrastExtension *) extensions[i]; 485 } 486 } 487 488 if (screen->core == NULL || screen->swrast == NULL) { 489 LogMessage(X_ERROR, "AIGLX error: %s exports no DRI extension\n", 490 driverName); 491 goto handle_error; 492 } 493 494 screen->driScreen = 495 (*screen->swrast->createNewScreen)(pScreen->myNum, 496 loader_extensions, 497 &driConfigs, 498 screen); 499 500 if (screen->driScreen == NULL) { 501 LogMessage(X_ERROR, 502 "AIGLX error: Calling driver entry point failed\n"); 503 goto handle_error; 504 } 505 506 initializeExtensions(screen); 507 508 screen->base.fbconfigs = glxConvertConfigs(screen->core, driConfigs, 509 GLX_WINDOW_BIT | 510 GLX_PIXMAP_BIT | 511 GLX_PBUFFER_BIT); 512 513 __glXScreenInit(&screen->base, pScreen); 514 515 screen->base.GLXmajor = 1; 516 screen->base.GLXminor = 4; 517 518 LogMessage(X_INFO, 519 "AIGLX: Loaded and initialized %s\n", filename); 520 521 return &screen->base; 522 523 handle_error: 524 if (screen->driver) 525 dlclose(screen->driver); 526 527 free(screen); 528 529 LogMessage(X_ERROR, "GLX: could not load software renderer\n"); 530 531 return NULL; 532} 533 534_X_EXPORT __GLXprovider __glXDRISWRastProvider = { 535 __glXDRIscreenProbe, 536 "DRISWRAST", 537 NULL 538}; 539