glxdriswrast.c revision 4642e01f
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 "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 67 const __DRIcoreExtension *core; 68 const __DRIswrastExtension *swrast; 69 const __DRIcopySubBufferExtension *copySubBuffer; 70 const __DRItexBufferExtension *texBuffer; 71}; 72 73struct __GLXDRIcontext { 74 __GLXcontext base; 75 __DRIcontext *driContext; 76}; 77 78struct __GLXDRIdrawable { 79 __GLXdrawable base; 80 __DRIdrawable *driDrawable; 81 __GLXDRIscreen *screen; 82 83 GCPtr gc; /* scratch GC for span drawing */ 84 GCPtr swapgc; /* GC for swapping the color buffers */ 85}; 86 87static void 88__glXDRIdrawableDestroy(__GLXdrawable *drawable) 89{ 90 __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable; 91 const __DRIcoreExtension *core = private->screen->core; 92 93 (*core->destroyDrawable)(private->driDrawable); 94 95 FreeScratchGC(private->gc); 96 FreeScratchGC(private->swapgc); 97 98 __glXDrawableRelease(drawable); 99 100 xfree(private); 101} 102 103static GLboolean 104__glXDRIdrawableSwapBuffers(__GLXdrawable *drawable) 105{ 106 __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable; 107 const __DRIcoreExtension *core = private->screen->core; 108 109 (*core->swapBuffers)(private->driDrawable); 110 111 return TRUE; 112} 113 114static void 115__glXDRIdrawableCopySubBuffer(__GLXdrawable *basePrivate, 116 int x, int y, int w, int h) 117{ 118 __GLXDRIdrawable *private = (__GLXDRIdrawable *) basePrivate; 119 const __DRIcopySubBufferExtension *copySubBuffer = 120 private->screen->copySubBuffer; 121 122 if (copySubBuffer) 123 (*copySubBuffer->copySubBuffer)(private->driDrawable, x, y, w, h); 124} 125 126static void 127__glXDRIcontextDestroy(__GLXcontext *baseContext) 128{ 129 __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext; 130 __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen; 131 132 (*screen->core->destroyContext)(context->driContext); 133 __glXContextDestroy(&context->base); 134 xfree(context); 135} 136 137static int 138__glXDRIcontextMakeCurrent(__GLXcontext *baseContext) 139{ 140 __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext; 141 __GLXDRIdrawable *draw = (__GLXDRIdrawable *) baseContext->drawPriv; 142 __GLXDRIdrawable *read = (__GLXDRIdrawable *) baseContext->readPriv; 143 __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen; 144 145 return (*screen->core->bindContext)(context->driContext, 146 draw->driDrawable, 147 read->driDrawable); 148} 149 150static int 151__glXDRIcontextLoseCurrent(__GLXcontext *baseContext) 152{ 153 __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext; 154 __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen; 155 156 return (*screen->core->unbindContext)(context->driContext); 157} 158 159static int 160__glXDRIcontextCopy(__GLXcontext *baseDst, __GLXcontext *baseSrc, 161 unsigned long mask) 162{ 163 __GLXDRIcontext *dst = (__GLXDRIcontext *) baseDst; 164 __GLXDRIcontext *src = (__GLXDRIcontext *) baseSrc; 165 __GLXDRIscreen *screen = (__GLXDRIscreen *) dst->base.pGlxScreen; 166 167 return (*screen->core->copyContext)(dst->driContext, 168 src->driContext, mask); 169} 170 171static int 172__glXDRIcontextForceCurrent(__GLXcontext *baseContext) 173{ 174 __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext; 175 __GLXDRIdrawable *draw = (__GLXDRIdrawable *) baseContext->drawPriv; 176 __GLXDRIdrawable *read = (__GLXDRIdrawable *) baseContext->readPriv; 177 __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen; 178 179 return (*screen->core->bindContext)(context->driContext, 180 draw->driDrawable, 181 read->driDrawable); 182} 183 184#ifdef __DRI_TEX_BUFFER 185 186static int 187__glXDRIbindTexImage(__GLXcontext *baseContext, 188 int buffer, 189 __GLXdrawable *glxPixmap) 190{ 191 __GLXDRIdrawable *drawable = (__GLXDRIdrawable *) glxPixmap; 192 const __DRItexBufferExtension *texBuffer = drawable->screen->texBuffer; 193 __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext; 194 195 if (texBuffer == NULL) 196 return Success; 197 198 texBuffer->setTexBuffer(context->driContext, 199 glxPixmap->target, 200 drawable->driDrawable); 201 202 return Success; 203} 204 205static int 206__glXDRIreleaseTexImage(__GLXcontext *baseContext, 207 int buffer, 208 __GLXdrawable *pixmap) 209{ 210 /* FIXME: Just unbind the texture? */ 211 return Success; 212} 213 214#else 215 216static int 217__glXDRIbindTexImage(__GLXcontext *baseContext, 218 int buffer, 219 __GLXdrawable *glxPixmap) 220{ 221 return Success; 222} 223 224static int 225__glXDRIreleaseTexImage(__GLXcontext *baseContext, 226 int buffer, 227 __GLXdrawable *pixmap) 228{ 229 return Success; 230} 231 232#endif 233 234static __GLXtextureFromPixmap __glXDRItextureFromPixmap = { 235 __glXDRIbindTexImage, 236 __glXDRIreleaseTexImage 237}; 238 239static void 240__glXDRIscreenDestroy(__GLXscreen *baseScreen) 241{ 242 __GLXDRIscreen *screen = (__GLXDRIscreen *) baseScreen; 243 244 (*screen->core->destroyScreen)(screen->driScreen); 245 246 dlclose(screen->driver); 247 248 __glXScreenDestroy(baseScreen); 249 250 xfree(screen); 251} 252 253static __GLXcontext * 254__glXDRIscreenCreateContext(__GLXscreen *baseScreen, 255 __GLXconfig *glxConfig, 256 __GLXcontext *baseShareContext) 257{ 258 __GLXDRIscreen *screen = (__GLXDRIscreen *) baseScreen; 259 __GLXDRIcontext *context, *shareContext; 260 __GLXDRIconfig *config = (__GLXDRIconfig *) glxConfig; 261 const __DRIcoreExtension *core = screen->core; 262 __DRIcontext *driShare; 263 264 shareContext = (__GLXDRIcontext *) baseShareContext; 265 if (shareContext) 266 driShare = shareContext->driContext; 267 else 268 driShare = NULL; 269 270 context = xcalloc(1, sizeof *context); 271 if (context == NULL) 272 return NULL; 273 274 context->base.destroy = __glXDRIcontextDestroy; 275 context->base.makeCurrent = __glXDRIcontextMakeCurrent; 276 context->base.loseCurrent = __glXDRIcontextLoseCurrent; 277 context->base.copy = __glXDRIcontextCopy; 278 context->base.forceCurrent = __glXDRIcontextForceCurrent; 279 context->base.textureFromPixmap = &__glXDRItextureFromPixmap; 280 281 context->driContext = 282 (*core->createNewContext)(screen->driScreen, 283 config->driConfig, driShare, context); 284 285 return &context->base; 286} 287 288static void 289glxChangeGC(GCPtr gc, BITS32 mask, CARD32 val) 290{ 291 CARD32 v[1]; 292 v[0] = val; 293 dixChangeGC(NullClient, gc, mask, v, NULL); 294} 295 296static __GLXdrawable * 297__glXDRIscreenCreateDrawable(__GLXscreen *screen, 298 DrawablePtr pDraw, 299 int type, 300 XID drawId, 301 __GLXconfig *glxConfig) 302{ 303 __GLXDRIscreen *driScreen = (__GLXDRIscreen *) screen; 304 __GLXDRIconfig *config = (__GLXDRIconfig *) glxConfig; 305 __GLXDRIdrawable *private; 306 307 ScreenPtr pScreen = driScreen->base.pScreen; 308 309 private = xcalloc(1, sizeof *private); 310 if (private == NULL) 311 return NULL; 312 313 private->screen = driScreen; 314 if (!__glXDrawableInit(&private->base, screen, 315 pDraw, type, drawId, glxConfig)) { 316 xfree(private); 317 return NULL; 318 } 319 320 private->base.destroy = __glXDRIdrawableDestroy; 321 private->base.swapBuffers = __glXDRIdrawableSwapBuffers; 322 private->base.copySubBuffer = __glXDRIdrawableCopySubBuffer; 323 324 private->gc = CreateScratchGC(pScreen, pDraw->depth); 325 private->swapgc = CreateScratchGC(pScreen, pDraw->depth); 326 327 glxChangeGC(private->gc, GCFunction, GXcopy); 328 glxChangeGC(private->swapgc, GCFunction, GXcopy); 329 glxChangeGC(private->swapgc, GCGraphicsExposures, FALSE); 330 331 private->driDrawable = 332 (*driScreen->swrast->createNewDrawable)(driScreen->driScreen, 333 config->driConfig, 334 private); 335 336 return &private->base; 337} 338 339static void 340swrastGetDrawableInfo(__DRIdrawable *draw, 341 int *x, int *y, int *w, int *h, 342 void *loaderPrivate) 343{ 344 __GLXDRIdrawable *drawable = loaderPrivate; 345 DrawablePtr pDraw = drawable->base.pDraw; 346 347 *x = pDraw->x; 348 *y = pDraw->x; 349 *w = pDraw->width; 350 *h = pDraw->height; 351} 352 353static void 354swrastPutImage(__DRIdrawable *draw, int op, 355 int x, int y, int w, int h, char *data, 356 void *loaderPrivate) 357{ 358 __GLXDRIdrawable *drawable = loaderPrivate; 359 DrawablePtr pDraw = drawable->base.pDraw; 360 GCPtr gc; 361 362 switch (op) { 363 case __DRI_SWRAST_IMAGE_OP_DRAW: 364 gc = drawable->gc; 365 break; 366 case __DRI_SWRAST_IMAGE_OP_SWAP: 367 gc = drawable->swapgc; 368 break; 369 default: 370 return; 371 } 372 373 ValidateGC(pDraw, gc); 374 375 gc->ops->PutImage(pDraw, gc, pDraw->depth, 376 x, y, w, h, 0, ZPixmap, data); 377} 378 379static void 380swrastGetImage(__DRIdrawable *draw, 381 int x, int y, int w, int h, char *data, 382 void *loaderPrivate) 383{ 384 __GLXDRIdrawable *drawable = loaderPrivate; 385 DrawablePtr pDraw = drawable->base.pDraw; 386 ScreenPtr pScreen = pDraw->pScreen; 387 388 pScreen->GetImage(pDraw, x, y, w, h, ZPixmap, ~0L, data); 389} 390 391static const __DRIswrastLoaderExtension swrastLoaderExtension = { 392 { __DRI_SWRAST_LOADER, __DRI_SWRAST_LOADER_VERSION }, 393 swrastGetDrawableInfo, 394 swrastPutImage, 395 swrastGetImage 396}; 397 398static const __DRIextension *loader_extensions[] = { 399 &systemTimeExtension.base, 400 &swrastLoaderExtension.base, 401 NULL 402}; 403 404static void 405initializeExtensions(__GLXDRIscreen *screen) 406{ 407 const __DRIextension **extensions; 408 int i; 409 410 extensions = screen->core->getExtensions(screen->driScreen); 411 412 for (i = 0; extensions[i]; i++) { 413#ifdef __DRI_COPY_SUB_BUFFER 414 if (strcmp(extensions[i]->name, __DRI_COPY_SUB_BUFFER) == 0) { 415 screen->copySubBuffer = 416 (const __DRIcopySubBufferExtension *) extensions[i]; 417 /* GLX_MESA_copy_sub_buffer is always enabled. */ 418 } 419#endif 420 421#ifdef __DRI_TEX_BUFFER 422 if (strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0) { 423 screen->texBuffer = 424 (const __DRItexBufferExtension *) extensions[i]; 425 /* GLX_EXT_texture_from_pixmap is always enabled. */ 426 } 427#endif 428 /* Ignore unknown extensions */ 429 } 430} 431 432static const char dri_driver_path[] = DRI_DRIVER_PATH; 433 434static __GLXscreen * 435__glXDRIscreenProbe(ScreenPtr pScreen) 436{ 437 const char *driverName = "swrast"; 438 __GLXDRIscreen *screen; 439 char filename[128]; 440 const __DRIextension **extensions; 441 const __DRIconfig **driConfigs; 442 int i; 443 444 screen = xcalloc(1, sizeof *screen); 445 if (screen == NULL) 446 return NULL; 447 448 screen->base.destroy = __glXDRIscreenDestroy; 449 screen->base.createContext = __glXDRIscreenCreateContext; 450 screen->base.createDrawable = __glXDRIscreenCreateDrawable; 451 screen->base.swapInterval = NULL; 452 screen->base.pScreen = pScreen; 453 454 snprintf(filename, sizeof filename, 455 "%s/%s_dri.so", dri_driver_path, driverName); 456 457 screen->driver = dlopen(filename, RTLD_LAZY | RTLD_LOCAL); 458 if (screen->driver == NULL) { 459 LogMessage(X_ERROR, "AIGLX error: dlopen of %s failed (%s)\n", 460 filename, dlerror()); 461 goto handle_error; 462 } 463 464 extensions = dlsym(screen->driver, __DRI_DRIVER_EXTENSIONS); 465 if (extensions == NULL) { 466 LogMessage(X_ERROR, "AIGLX error: %s exports no extensions (%s)\n", 467 driverName, dlerror()); 468 goto handle_error; 469 } 470 471 for (i = 0; extensions[i]; i++) { 472 if (strcmp(extensions[i]->name, __DRI_CORE) == 0 && 473 extensions[i]->version >= __DRI_CORE_VERSION) { 474 screen->core = (const __DRIcoreExtension *) extensions[i]; 475 } 476 if (strcmp(extensions[i]->name, __DRI_SWRAST) == 0 && 477 extensions[i]->version >= __DRI_SWRAST_VERSION) { 478 screen->swrast = (const __DRIswrastExtension *) extensions[i]; 479 } 480 } 481 482 if (screen->core == NULL || screen->swrast == NULL) { 483 LogMessage(X_ERROR, "AIGLX error: %s exports no DRI extension\n", 484 driverName); 485 goto handle_error; 486 } 487 488 screen->driScreen = 489 (*screen->swrast->createNewScreen)(pScreen->myNum, 490 loader_extensions, 491 &driConfigs, 492 screen); 493 494 if (screen->driScreen == NULL) { 495 LogMessage(X_ERROR, "AIGLX error: Calling driver entry point failed"); 496 goto handle_error; 497 } 498 499 initializeExtensions(screen); 500 501 screen->base.fbconfigs = glxConvertConfigs(screen->core, driConfigs); 502 503 __glXScreenInit(&screen->base, pScreen); 504 505 LogMessage(X_INFO, 506 "AIGLX: Loaded and initialized %s\n", filename); 507 508 return &screen->base; 509 510 handle_error: 511 if (screen->driver) 512 dlclose(screen->driver); 513 514 xfree(screen); 515 516 LogMessage(X_ERROR, "GLX: could not load software renderer\n"); 517 518 return NULL; 519} 520 521__GLXprovider __glXDRISWRastProvider = { 522 __glXDRIscreenProbe, 523 "DRISWRAST", 524 NULL 525}; 526