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