drisw_glx.c revision 089fc37c6fa158824279e08e3b378ced94d6f803
1/* 2 * Copyright 2008 George Sapountzis 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 * SOFTWARE. 22 */ 23 24#if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL) 25 26#include <X11/Xlib.h> 27#include "glxclient.h" 28#include <dlfcn.h> 29#include "dri_common.h" 30 31struct drisw_display 32{ 33 __GLXDRIdisplay base; 34}; 35 36struct drisw_context 37{ 38 __GLXDRIcontext base; 39 __DRIcontext *driContext; 40 __GLXscreenConfigs *psc; 41}; 42 43struct drisw_screen 44{ 45 __GLXscreenConfigs base; 46 47 __GLXDRIscreen driScreen; 48 const __DRIcoreExtension *core; 49 const __DRIswrastExtension *swrast; 50 void *driver; 51}; 52 53struct drisw_drawable 54{ 55 __GLXDRIdrawable base; 56 57 GC gc; 58 GC swapgc; 59 60 XVisualInfo *visinfo; 61 XImage *ximage; 62}; 63 64static Bool 65XCreateDrawable(struct drisw_drawable * pdp, 66 Display * dpy, XID drawable, int visualid) 67{ 68 XGCValues gcvalues; 69 long visMask; 70 XVisualInfo visTemp; 71 int num_visuals; 72 73 /* create GC's */ 74 pdp->gc = XCreateGC(dpy, drawable, 0, NULL); 75 pdp->swapgc = XCreateGC(dpy, drawable, 0, NULL); 76 77 gcvalues.function = GXcopy; 78 gcvalues.graphics_exposures = False; 79 XChangeGC(dpy, pdp->gc, GCFunction, &gcvalues); 80 XChangeGC(dpy, pdp->swapgc, GCFunction, &gcvalues); 81 XChangeGC(dpy, pdp->swapgc, GCGraphicsExposures, &gcvalues); 82 83 /* visual */ 84 visTemp.screen = DefaultScreen(dpy); 85 visTemp.visualid = visualid; 86 visMask = (VisualScreenMask | VisualIDMask); 87 pdp->visinfo = XGetVisualInfo(dpy, visMask, &visTemp, &num_visuals); 88 89 /* create XImage */ 90 pdp->ximage = XCreateImage(dpy, 91 pdp->visinfo->visual, 92 pdp->visinfo->depth, 93 ZPixmap, 0, /* format, offset */ 94 NULL, /* data */ 95 0, 0, /* width, height */ 96 32, /* bitmap_pad */ 97 0); /* bytes_per_line */ 98 99 return True; 100} 101 102static void 103XDestroyDrawable(struct drisw_drawable * pdp, Display * dpy, XID drawable) 104{ 105 XDestroyImage(pdp->ximage); 106 XFree(pdp->visinfo); 107 108 XFreeGC(dpy, pdp->gc); 109 XFreeGC(dpy, pdp->swapgc); 110} 111 112/** 113 * swrast loader functions 114 */ 115 116static void 117swrastGetDrawableInfo(__DRIdrawable * draw, 118 int *x, int *y, int *w, int *h, 119 void *loaderPrivate) 120{ 121 struct drisw_drawable *pdp = loaderPrivate; 122 __GLXDRIdrawable *pdraw = &(pdp->base); 123 Display *dpy = pdraw->psc->dpy; 124 Drawable drawable; 125 126 Window root; 127 Status stat; 128 unsigned uw, uh, bw, depth; 129 130 drawable = pdraw->xDrawable; 131 132 stat = XGetGeometry(dpy, drawable, &root, 133 x, y, &uw, &uh, &bw, &depth); 134 *w = uw; 135 *h = uh; 136} 137 138/** 139 * Align renderbuffer pitch. 140 * 141 * This should be chosen by the driver and the loader (libGL, xserver/glx) 142 * should use the driver provided pitch. 143 * 144 * It seems that the xorg loader (that is the xserver loading swrast_dri for 145 * indirect rendering, not client-side libGL) requires that the pitch is 146 * exactly the image width padded to 32 bits. XXX 147 * 148 * The above restriction can probably be overcome by using ScratchPixmap and 149 * CopyArea in the xserver, similar to ShmPutImage, and setting the width of 150 * the scratch pixmap to 'pitch / cpp'. 151 */ 152static inline int 153bytes_per_line(unsigned pitch_bits, unsigned mul) 154{ 155 unsigned mask = mul - 1; 156 157 return ((pitch_bits + mask) & ~mask) / 8; 158} 159 160static void 161swrastPutImage(__DRIdrawable * draw, int op, 162 int x, int y, int w, int h, 163 char *data, void *loaderPrivate) 164{ 165 struct drisw_drawable *pdp = loaderPrivate; 166 __GLXDRIdrawable *pdraw = &(pdp->base); 167 Display *dpy = pdraw->psc->dpy; 168 Drawable drawable; 169 XImage *ximage; 170 GC gc; 171 172 switch (op) { 173 case __DRI_SWRAST_IMAGE_OP_DRAW: 174 gc = pdp->gc; 175 break; 176 case __DRI_SWRAST_IMAGE_OP_SWAP: 177 gc = pdp->swapgc; 178 break; 179 default: 180 return; 181 } 182 183 drawable = pdraw->xDrawable; 184 185 ximage = pdp->ximage; 186 ximage->data = data; 187 ximage->width = w; 188 ximage->height = h; 189 ximage->bytes_per_line = bytes_per_line(w * ximage->bits_per_pixel, 32); 190 191 XPutImage(dpy, drawable, gc, ximage, 0, 0, x, y, w, h); 192 193 ximage->data = NULL; 194} 195 196static void 197swrastGetImage(__DRIdrawable * read, 198 int x, int y, int w, int h, 199 char *data, void *loaderPrivate) 200{ 201 struct drisw_drawable *prp = loaderPrivate; 202 __GLXDRIdrawable *pread = &(prp->base); 203 Display *dpy = pread->psc->dpy; 204 Drawable readable; 205 XImage *ximage; 206 207 readable = pread->xDrawable; 208 209 ximage = prp->ximage; 210 ximage->data = data; 211 ximage->width = w; 212 ximage->height = h; 213 ximage->bytes_per_line = bytes_per_line(w * ximage->bits_per_pixel, 32); 214 215 XGetSubImage(dpy, readable, x, y, w, h, ~0L, ZPixmap, ximage, 0, 0); 216 217 ximage->data = NULL; 218} 219 220static const __DRIswrastLoaderExtension swrastLoaderExtension = { 221 {__DRI_SWRAST_LOADER, __DRI_SWRAST_LOADER_VERSION}, 222 swrastGetDrawableInfo, 223 swrastPutImage, 224 swrastGetImage 225}; 226 227static const __DRIextension *loader_extensions[] = { 228 &systemTimeExtension.base, 229 &swrastLoaderExtension.base, 230 NULL 231}; 232 233/** 234 * GLXDRI functions 235 */ 236 237static void 238driDestroyContext(__GLXDRIcontext *context, 239 __GLXscreenConfigs *base, Display *dpy) 240{ 241 struct drisw_context *pcp = (struct drisw_context *) context; 242 struct drisw_screen *psc = (struct drisw_screen *) base; 243 244 (*psc->core->destroyContext) (pcp->driContext); 245 246 Xfree(pcp); 247} 248 249static Bool 250driBindContext(__GLXDRIcontext * context, 251 __GLXDRIdrawable * draw, __GLXDRIdrawable * read) 252{ 253 struct drisw_context *pcp = (struct drisw_context *) context; 254 struct drisw_screen *psc = (struct drisw_screen *) pcp->psc; 255 256 return (*psc->core->bindContext) (pcp->driContext, 257 draw->driDrawable, read->driDrawable); 258} 259 260static void 261driUnbindContext(__GLXDRIcontext * context) 262{ 263 struct drisw_context *pcp = (struct drisw_context *) context; 264 struct drisw_screen *psc = (struct drisw_screen *) pcp->psc; 265 266 (*psc->core->unbindContext) (pcp->driContext); 267} 268 269static __GLXDRIcontext * 270driCreateContext(__GLXscreenConfigs *base, 271 const __GLcontextModes *mode, 272 GLXContext gc, GLXContext shareList, int renderType) 273{ 274 struct drisw_context *pcp, *pcp_shared; 275 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) mode; 276 struct drisw_screen *psc = (struct drisw_screen *) base; 277 __DRIcontext *shared = NULL; 278 279 if (!psc->base.driScreen) 280 return NULL; 281 282 if (shareList) { 283 pcp_shared = (struct drisw_context *) shareList->driContext; 284 shared = pcp_shared->driContext; 285 } 286 287 pcp = Xmalloc(sizeof *pcp); 288 if (pcp == NULL) 289 return NULL; 290 291 pcp->psc = &psc->base; 292 pcp->driContext = 293 (*psc->core->createNewContext) (psc->base.__driScreen, 294 config->driConfig, shared, pcp); 295 if (pcp->driContext == NULL) { 296 Xfree(pcp); 297 return NULL; 298 } 299 300 pcp->base.destroyContext = driDestroyContext; 301 pcp->base.bindContext = driBindContext; 302 pcp->base.unbindContext = driUnbindContext; 303 304 return &pcp->base; 305} 306 307static void 308driDestroyDrawable(__GLXDRIdrawable * pdraw) 309{ 310 struct drisw_drawable *pdp = (struct drisw_drawable *) pdraw; 311 struct drisw_screen *psc = (struct drisw_screen *) pdp->base.psc; 312 313 (*psc->core->destroyDrawable) (pdraw->driDrawable); 314 315 XDestroyDrawable(pdp, pdraw->psc->dpy, pdraw->drawable); 316 Xfree(pdp); 317} 318 319static __GLXDRIdrawable * 320driCreateDrawable(__GLXscreenConfigs *base, XID xDrawable, 321 GLXDrawable drawable, const __GLcontextModes * modes) 322{ 323 __GLXDRIdrawable *pdraw; 324 struct drisw_drawable *pdp; 325 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) modes; 326 struct drisw_screen *psc = (struct drisw_screen *) base; 327 328 const __DRIswrastExtension *swrast = psc->swrast; 329 330 /* Old dri can't handle GLX 1.3+ drawable constructors. */ 331 if (xDrawable != drawable) 332 return NULL; 333 334 pdp = Xmalloc(sizeof(*pdp)); 335 if (!pdp) 336 return NULL; 337 338 pdraw = &(pdp->base); 339 pdraw->xDrawable = xDrawable; 340 pdraw->drawable = drawable; 341 pdraw->psc = &psc->base; 342 343 XCreateDrawable(pdp, psc->base.dpy, xDrawable, modes->visualID); 344 345 /* Create a new drawable */ 346 pdraw->driDrawable = 347 (*swrast->createNewDrawable) (psc->base.__driScreen, 348 config->driConfig, pdp); 349 350 if (!pdraw->driDrawable) { 351 XDestroyDrawable(pdp, psc->base.dpy, xDrawable); 352 Xfree(pdp); 353 return NULL; 354 } 355 356 pdraw->destroyDrawable = driDestroyDrawable; 357 358 return pdraw; 359} 360 361static int64_t 362driSwapBuffers(__GLXDRIdrawable * pdraw, 363 int64_t target_msc, int64_t divisor, int64_t remainder) 364{ 365 struct drisw_drawable *pdp = (struct drisw_drawable *) pdraw; 366 struct drisw_screen *psc = (struct drisw_screen *) pdp->base.psc; 367 368 (void) target_msc; 369 (void) divisor; 370 (void) remainder; 371 372 (*psc->core->swapBuffers) (pdraw->driDrawable); 373 374 return 0; 375} 376 377static void 378driDestroyScreen(__GLXscreenConfigs *base) 379{ 380 struct drisw_screen *psc = (struct drisw_screen *) base; 381 382 /* Free the direct rendering per screen data */ 383 (*psc->core->destroyScreen) (psc->base.__driScreen); 384 psc->base.__driScreen = NULL; 385 if (psc->driver) 386 dlclose(psc->driver); 387} 388 389static void * 390driOpenSwrast(void) 391{ 392 void *driver = NULL; 393 394 if (driver == NULL) 395 driver = driOpenDriver("swrast"); 396 397 if (driver == NULL) 398 driver = driOpenDriver("swrastg"); 399 400 return driver; 401} 402 403static __GLXscreenConfigs * 404driCreateScreen(int screen, __GLXdisplayPrivate *priv) 405{ 406 __GLXDRIscreen *psp; 407 const __DRIconfig **driver_configs; 408 const __DRIextension **extensions; 409 struct drisw_screen *psc; 410 int i; 411 412 psc = Xcalloc(1, sizeof *psc); 413 if (psc == NULL) 414 return NULL; 415 416 memset(psc, 0, sizeof *psc); 417 if (!glx_screen_init(&psc->base, screen, priv)) 418 return NULL; 419 420 psc->driver = driOpenSwrast(); 421 if (psc->driver == NULL) 422 goto handle_error; 423 424 extensions = dlsym(psc->driver, __DRI_DRIVER_EXTENSIONS); 425 if (extensions == NULL) { 426 ErrorMessageF("driver exports no extensions (%s)\n", dlerror()); 427 goto handle_error; 428 } 429 430 for (i = 0; extensions[i]; i++) { 431 if (strcmp(extensions[i]->name, __DRI_CORE) == 0) 432 psc->core = (__DRIcoreExtension *) extensions[i]; 433 if (strcmp(extensions[i]->name, __DRI_SWRAST) == 0) 434 psc->swrast = (__DRIswrastExtension *) extensions[i]; 435 } 436 437 if (psc->core == NULL || psc->swrast == NULL) { 438 ErrorMessageF("core dri extension not found\n"); 439 goto handle_error; 440 } 441 442 psc->base.__driScreen = 443 psc->swrast->createNewScreen(screen, loader_extensions, 444 &driver_configs, psc); 445 if (psc->base.__driScreen == NULL) { 446 ErrorMessageF("failed to create dri screen\n"); 447 goto handle_error; 448 } 449 450 extensions = psc->core->getExtensions(psc->base.__driScreen); 451 driBindCommonExtensions(&psc->base, extensions); 452 453 psc->base.configs = 454 driConvertConfigs(psc->core, psc->base.configs, driver_configs); 455 psc->base.visuals = 456 driConvertConfigs(psc->core, psc->base.visuals, driver_configs); 457 458 psc->base.driver_configs = driver_configs; 459 460 psp = &psc->driScreen; 461 psc->base.driScreen = psp; 462 psp->destroyScreen = driDestroyScreen; 463 psp->createContext = driCreateContext; 464 psp->createDrawable = driCreateDrawable; 465 psp->swapBuffers = driSwapBuffers; 466 psp->waitX = NULL; 467 psp->waitGL = NULL; 468 469 return &psc->base; 470 471 handle_error: 472 Xfree(psc); 473 474 if (psc->driver) 475 dlclose(psc->driver); 476 477 ErrorMessageF("reverting to indirect rendering\n"); 478 479 return NULL; 480} 481 482/* Called from __glXFreeDisplayPrivate. 483 */ 484static void 485driDestroyDisplay(__GLXDRIdisplay * dpy) 486{ 487 Xfree(dpy); 488} 489 490/* 491 * Allocate, initialize and return a __DRIdisplayPrivate object. 492 * This is called from __glXInitialize() when we are given a new 493 * display pointer. 494 */ 495_X_HIDDEN __GLXDRIdisplay * 496driswCreateDisplay(Display * dpy) 497{ 498 struct drisw_display *pdpyp; 499 500 pdpyp = Xmalloc(sizeof *pdpyp); 501 if (pdpyp == NULL) 502 return NULL; 503 504 pdpyp->base.destroyDisplay = driDestroyDisplay; 505 pdpyp->base.createScreen = driCreateScreen; 506 507 return &pdpyp->base; 508} 509 510#endif /* GLX_DIRECT_RENDERING */ 511