native_ximage.c revision 25357696c3f253d44e83798e2a7e7f1f60c5adc5
1/* 2 * Mesa 3-D graphics library 3 * Version: 7.8 4 * 5 * Copyright (C) 2009-2010 Chia-I Wu <olv@0xlab.org> 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the "Software"), 9 * to deal in the Software without restriction, including without limitation 10 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 * and/or sell copies of the Software, and to permit persons to whom the 12 * Software is furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included 15 * in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25#include <assert.h> 26#include <sys/ipc.h> 27#include <sys/types.h> 28#include <sys/shm.h> 29#include <X11/Xlib.h> 30#include <X11/Xutil.h> 31#include <X11/extensions/XShm.h> 32#include "util/u_memory.h" 33#include "util/u_math.h" 34#include "util/u_format.h" 35#include "pipe/p_compiler.h" 36#include "util/u_simple_screen.h" 37#include "softpipe/sp_winsys.h" 38#include "egllog.h" 39 40#include "sw_winsys.h" 41#include "native_x11.h" 42#include "x11_screen.h" 43 44enum ximage_surface_type { 45 XIMAGE_SURFACE_TYPE_WINDOW, 46 XIMAGE_SURFACE_TYPE_PIXMAP, 47 XIMAGE_SURFACE_TYPE_PBUFFER 48}; 49 50struct ximage_display { 51 struct native_display base; 52 Display *dpy; 53 boolean own_dpy; 54 55 struct x11_screen *xscr; 56 int xscr_number; 57 58 boolean use_xshm; 59 60 struct pipe_winsys *winsys; 61 struct ximage_config *configs; 62 int num_configs; 63}; 64 65struct ximage_buffer { 66 XImage *ximage; 67 68 struct pipe_texture *texture; 69 XShmSegmentInfo *shm_info; 70 boolean xshm_attached; 71}; 72 73struct ximage_surface { 74 struct native_surface base; 75 Drawable drawable; 76 enum ximage_surface_type type; 77 enum pipe_format color_format; 78 XVisualInfo visual; 79 struct ximage_display *xdpy; 80 81 int width, height; 82 GC gc; 83 84 struct ximage_buffer buffers[NUM_NATIVE_ATTACHMENTS]; 85 unsigned int sequence_number; 86}; 87 88struct ximage_config { 89 struct native_config base; 90 const XVisualInfo *visual; 91}; 92 93static INLINE struct ximage_display * 94ximage_display(const struct native_display *ndpy) 95{ 96 return (struct ximage_display *) ndpy; 97} 98 99static INLINE struct ximage_surface * 100ximage_surface(const struct native_surface *nsurf) 101{ 102 return (struct ximage_surface *) nsurf; 103} 104 105static INLINE struct ximage_config * 106ximage_config(const struct native_config *nconf) 107{ 108 return (struct ximage_config *) nconf; 109} 110 111static void 112ximage_surface_free_buffer(struct native_surface *nsurf, 113 enum native_attachment which) 114{ 115 struct ximage_surface *xsurf = ximage_surface(nsurf); 116 struct ximage_buffer *xbuf = &xsurf->buffers[which]; 117 118 pipe_texture_reference(&xbuf->texture, NULL); 119 120 if (xbuf->shm_info) { 121 if (xbuf->xshm_attached) 122 XShmDetach(xsurf->xdpy->dpy, xbuf->shm_info); 123 if (xbuf->shm_info->shmaddr != (void *) -1) 124 shmdt(xbuf->shm_info->shmaddr); 125 if (xbuf->shm_info->shmid != -1) 126 shmctl(xbuf->shm_info->shmid, IPC_RMID, 0); 127 128 xbuf->shm_info->shmaddr = (void *) -1; 129 xbuf->shm_info->shmid = -1; 130 } 131} 132 133static boolean 134ximage_surface_alloc_buffer(struct native_surface *nsurf, 135 enum native_attachment which) 136{ 137 struct ximage_surface *xsurf = ximage_surface(nsurf); 138 struct ximage_buffer *xbuf = &xsurf->buffers[which]; 139 struct pipe_screen *screen = xsurf->xdpy->base.screen; 140 struct pipe_texture templ; 141 142 /* free old data */ 143 if (xbuf->texture) 144 ximage_surface_free_buffer(&xsurf->base, which); 145 146 memset(&templ, 0, sizeof(templ)); 147 templ.target = PIPE_TEXTURE_2D; 148 templ.format = xsurf->color_format; 149 templ.width0 = xsurf->width; 150 templ.height0 = xsurf->height; 151 templ.depth0 = 1; 152 templ.tex_usage = PIPE_TEXTURE_USAGE_RENDER_TARGET; 153 154 if (xbuf->shm_info) { 155 struct pipe_buffer *pbuf; 156 unsigned stride, size; 157 void *addr = NULL; 158 159 stride = util_format_get_stride(xsurf->color_format, xsurf->width); 160 /* alignment should depend on visual? */ 161 stride = align(stride, 4); 162 size = stride * xsurf->height; 163 164 /* create and attach shm object */ 165 xbuf->shm_info->shmid = shmget(IPC_PRIVATE, size, 0755); 166 if (xbuf->shm_info->shmid != -1) { 167 xbuf->shm_info->shmaddr = 168 shmat(xbuf->shm_info->shmid, NULL, 0); 169 if (xbuf->shm_info->shmaddr != (void *) -1) { 170 if (XShmAttach(xsurf->xdpy->dpy, xbuf->shm_info)) { 171 addr = xbuf->shm_info->shmaddr; 172 xbuf->xshm_attached = TRUE; 173 } 174 } 175 } 176 177 if (addr) { 178 pbuf = screen->user_buffer_create(screen, addr, size); 179 if (pbuf) { 180 xbuf->texture = 181 screen->texture_blanket(screen, &templ, &stride, pbuf); 182 pipe_buffer_reference(&pbuf, NULL); 183 } 184 } 185 } 186 else { 187 xbuf->texture = screen->texture_create(screen, &templ); 188 } 189 190 /* clean up the buffer if allocation failed */ 191 if (!xbuf->texture) 192 ximage_surface_free_buffer(&xsurf->base, which); 193 194 return (xbuf->texture != NULL); 195} 196 197static boolean 198ximage_surface_draw_buffer(struct native_surface *nsurf, 199 enum native_attachment which) 200{ 201 struct ximage_surface *xsurf = ximage_surface(nsurf); 202 struct ximage_buffer *xbuf = &xsurf->buffers[which]; 203 struct pipe_screen *screen = xsurf->xdpy->base.screen; 204 struct pipe_transfer *transfer; 205 206 if (xsurf->type == XIMAGE_SURFACE_TYPE_PBUFFER) 207 return TRUE; 208 209 assert(xsurf->drawable && xbuf->ximage && xbuf->texture); 210 211 transfer = screen->get_tex_transfer(screen, xbuf->texture, 212 0, 0, 0, PIPE_TRANSFER_READ, 0, 0, xsurf->width, xsurf->height); 213 if (!transfer) 214 return FALSE; 215 216 xbuf->ximage->bytes_per_line = transfer->stride; 217 xbuf->ximage->data = screen->transfer_map(screen, transfer); 218 if (!xbuf->ximage->data) { 219 screen->tex_transfer_destroy(transfer); 220 return FALSE; 221 } 222 223 224 if (xbuf->shm_info) 225 XShmPutImage(xsurf->xdpy->dpy, xsurf->drawable, xsurf->gc, 226 xbuf->ximage, 0, 0, 0, 0, xsurf->width, xsurf->height, False); 227 else 228 XPutImage(xsurf->xdpy->dpy, xsurf->drawable, xsurf->gc, 229 xbuf->ximage, 0, 0, 0, 0, xsurf->width, xsurf->height); 230 231 xbuf->ximage->data = NULL; 232 screen->transfer_unmap(screen, transfer); 233 234 /* 235 * softpipe allows the pipe transfer to be re-used, but we don't want to 236 * rely on that behavior. 237 */ 238 screen->tex_transfer_destroy(transfer); 239 240 XSync(xsurf->xdpy->dpy, FALSE); 241 242 return TRUE; 243} 244 245static boolean 246ximage_surface_flush_frontbuffer(struct native_surface *nsurf) 247{ 248 return ximage_surface_draw_buffer(nsurf, NATIVE_ATTACHMENT_FRONT_LEFT); 249} 250 251static boolean 252ximage_surface_swap_buffers(struct native_surface *nsurf) 253{ 254 struct ximage_surface *xsurf = ximage_surface(nsurf); 255 struct ximage_buffer *xfront, *xback, xtmp; 256 257 xfront = &xsurf->buffers[NATIVE_ATTACHMENT_FRONT_LEFT]; 258 xback = &xsurf->buffers[NATIVE_ATTACHMENT_BACK_LEFT]; 259 260 /* draw the back buffer directly if there is no front buffer */ 261 if (!xfront->texture) 262 return ximage_surface_draw_buffer(nsurf, NATIVE_ATTACHMENT_BACK_LEFT); 263 264 /* swap the buffers */ 265 xtmp = *xfront; 266 *xfront = *xback; 267 *xback = xtmp; 268 269 /* the front/back textures are swapped */ 270 xsurf->sequence_number++; 271 272 return ximage_surface_draw_buffer(nsurf, NATIVE_ATTACHMENT_FRONT_LEFT); 273} 274 275static void 276ximage_surface_update_geometry(struct native_surface *nsurf) 277{ 278 struct ximage_surface *xsurf = ximage_surface(nsurf); 279 Status ok; 280 Window root; 281 int x, y; 282 unsigned int w, h, border, depth; 283 284 /* pbuffer has fixed geometry */ 285 if (xsurf->type == XIMAGE_SURFACE_TYPE_PBUFFER) 286 return; 287 288 ok = XGetGeometry(xsurf->xdpy->dpy, xsurf->drawable, 289 &root, &x, &y, &w, &h, &border, &depth); 290 if (ok) { 291 xsurf->width = w; 292 xsurf->height = h; 293 } 294} 295 296static boolean 297ximage_surface_validate(struct native_surface *nsurf, uint attachment_mask, 298 unsigned int *seq_num, struct pipe_texture **textures, 299 int *width, int *height) 300{ 301 struct ximage_surface *xsurf = ximage_surface(nsurf); 302 boolean new_buffers = FALSE; 303 int att; 304 305 ximage_surface_update_geometry(&xsurf->base); 306 307 for (att = 0; att < NUM_NATIVE_ATTACHMENTS; att++) { 308 struct ximage_buffer *xbuf = &xsurf->buffers[att]; 309 310 /* delay the allocation */ 311 if (!native_attachment_mask_test(attachment_mask, att)) 312 continue; 313 314 /* reallocate the texture */ 315 if (!xbuf->texture || 316 xsurf->width != xbuf->texture->width0 || 317 xsurf->height != xbuf->texture->height0) { 318 new_buffers = TRUE; 319 if (ximage_surface_alloc_buffer(&xsurf->base, att)) { 320 /* update ximage */ 321 if (xbuf->ximage) { 322 xbuf->ximage->width = xsurf->width; 323 xbuf->ximage->height = xsurf->height; 324 } 325 } 326 } 327 328 if (textures) { 329 textures[att] = NULL; 330 pipe_texture_reference(&textures[att], xbuf->texture); 331 } 332 } 333 334 /* increase the sequence number so that caller knows */ 335 if (new_buffers) 336 xsurf->sequence_number++; 337 338 if (seq_num) 339 *seq_num = xsurf->sequence_number; 340 if (width) 341 *width = xsurf->width; 342 if (height) 343 *height = xsurf->height; 344 345 return TRUE; 346} 347 348static void 349ximage_surface_wait(struct native_surface *nsurf) 350{ 351 struct ximage_surface *xsurf = ximage_surface(nsurf); 352 XSync(xsurf->xdpy->dpy, FALSE); 353 /* TODO XGetImage and update the front texture */ 354} 355 356static void 357ximage_surface_destroy(struct native_surface *nsurf) 358{ 359 struct ximage_surface *xsurf = ximage_surface(nsurf); 360 int i; 361 362 for (i = 0; i < NUM_NATIVE_ATTACHMENTS; i++) { 363 struct ximage_buffer *xbuf = &xsurf->buffers[i]; 364 ximage_surface_free_buffer(&xsurf->base, i); 365 /* xbuf->shm_info is owned by xbuf->ximage? */ 366 if (xbuf->ximage) { 367 XDestroyImage(xbuf->ximage); 368 xbuf->ximage = NULL; 369 } 370 } 371 372 if (xsurf->type != XIMAGE_SURFACE_TYPE_PBUFFER) 373 XFreeGC(xsurf->xdpy->dpy, xsurf->gc); 374 free(xsurf); 375} 376 377static struct ximage_surface * 378ximage_display_create_surface(struct native_display *ndpy, 379 enum ximage_surface_type type, 380 Drawable drawable, 381 const struct native_config *nconf) 382{ 383 struct ximage_display *xdpy = ximage_display(ndpy); 384 struct ximage_config *xconf = ximage_config(nconf); 385 struct ximage_surface *xsurf; 386 int i; 387 388 xsurf = CALLOC_STRUCT(ximage_surface); 389 if (!xsurf) 390 return NULL; 391 392 xsurf->xdpy = xdpy; 393 xsurf->type = type; 394 xsurf->color_format = xconf->base.color_format; 395 xsurf->drawable = drawable; 396 397 if (xsurf->type != XIMAGE_SURFACE_TYPE_PBUFFER) { 398 xsurf->drawable = drawable; 399 xsurf->visual = *xconf->visual; 400 401 xsurf->gc = XCreateGC(xdpy->dpy, xsurf->drawable, 0, NULL); 402 if (!xsurf->gc) { 403 free(xsurf); 404 return NULL; 405 } 406 407 for (i = 0; i < NUM_NATIVE_ATTACHMENTS; i++) { 408 struct ximage_buffer *xbuf = &xsurf->buffers[i]; 409 410 if (xdpy->use_xshm) { 411 xbuf->shm_info = calloc(1, sizeof(*xbuf->shm_info)); 412 if (xbuf->shm_info) { 413 /* initialize shm info */ 414 xbuf->shm_info->shmid = -1; 415 xbuf->shm_info->shmaddr = (void *) -1; 416 xbuf->shm_info->readOnly = TRUE; 417 418 xbuf->ximage = XShmCreateImage(xsurf->xdpy->dpy, 419 xsurf->visual.visual, 420 xsurf->visual.depth, 421 ZPixmap, NULL, 422 xbuf->shm_info, 423 0, 0); 424 } 425 } 426 else { 427 xbuf->ximage = XCreateImage(xsurf->xdpy->dpy, 428 xsurf->visual.visual, 429 xsurf->visual.depth, 430 ZPixmap, 0, /* format, offset */ 431 NULL, /* data */ 432 0, 0, /* size */ 433 8, /* bitmap_pad */ 434 0); /* bytes_per_line */ 435 } 436 437 if (!xbuf->ximage) { 438 XFreeGC(xdpy->dpy, xsurf->gc); 439 free(xsurf); 440 return NULL; 441 } 442 } 443 } 444 445 xsurf->base.destroy = ximage_surface_destroy; 446 xsurf->base.swap_buffers = ximage_surface_swap_buffers; 447 xsurf->base.flush_frontbuffer = ximage_surface_flush_frontbuffer; 448 xsurf->base.validate = ximage_surface_validate; 449 xsurf->base.wait = ximage_surface_wait; 450 451 return xsurf; 452} 453 454static struct native_surface * 455ximage_display_create_window_surface(struct native_display *ndpy, 456 EGLNativeWindowType win, 457 const struct native_config *nconf) 458{ 459 struct ximage_surface *xsurf; 460 461 xsurf = ximage_display_create_surface(ndpy, XIMAGE_SURFACE_TYPE_WINDOW, 462 (Drawable) win, nconf); 463 return (xsurf) ? &xsurf->base : NULL; 464} 465 466static struct native_surface * 467ximage_display_create_pixmap_surface(struct native_display *ndpy, 468 EGLNativePixmapType pix, 469 const struct native_config *nconf) 470{ 471 struct ximage_surface *xsurf; 472 473 xsurf = ximage_display_create_surface(ndpy, XIMAGE_SURFACE_TYPE_PIXMAP, 474 (Drawable) pix, nconf); 475 return (xsurf) ? &xsurf->base : NULL; 476} 477 478static struct native_surface * 479ximage_display_create_pbuffer_surface(struct native_display *ndpy, 480 const struct native_config *nconf, 481 uint width, uint height) 482{ 483 struct ximage_surface *xsurf; 484 485 xsurf = ximage_display_create_surface(ndpy, XIMAGE_SURFACE_TYPE_PBUFFER, 486 (Drawable) None, nconf); 487 if (xsurf) { 488 xsurf->width = width; 489 xsurf->height = height; 490 } 491 return (xsurf) ? &xsurf->base : NULL; 492} 493 494static struct pipe_context * 495ximage_display_create_context(struct native_display *ndpy, 496 void *context_private) 497{ 498 struct pipe_context *pctx = softpipe_create(ndpy->screen); 499 if (pctx) 500 pctx->priv = context_private; 501 return pctx; 502} 503 504static enum pipe_format 505choose_format(const XVisualInfo *vinfo) 506{ 507 enum pipe_format fmt; 508 /* TODO elaborate the formats */ 509 switch (vinfo->depth) { 510 case 32: 511 fmt = PIPE_FORMAT_A8R8G8B8_UNORM; 512 break; 513 case 24: 514 fmt = PIPE_FORMAT_X8R8G8B8_UNORM; 515 break; 516 case 16: 517 fmt = PIPE_FORMAT_R5G6B5_UNORM; 518 break; 519 default: 520 fmt = PIPE_FORMAT_NONE; 521 break; 522 } 523 524 return fmt; 525} 526 527static const struct native_config ** 528ximage_display_get_configs(struct native_display *ndpy, int *num_configs) 529{ 530 struct ximage_display *xdpy = ximage_display(ndpy); 531 const struct native_config **configs; 532 int i; 533 534 /* first time */ 535 if (!xdpy->configs) { 536 const XVisualInfo *visuals; 537 int num_visuals, count, j; 538 539 visuals = x11_screen_get_visuals(xdpy->xscr, &num_visuals); 540 if (!visuals) 541 return NULL; 542 543 /* 544 * Create two configs for each visual. 545 * One with depth/stencil buffer; one without 546 */ 547 xdpy->configs = calloc(num_visuals * 2, sizeof(*xdpy->configs)); 548 if (!xdpy->configs) 549 return NULL; 550 551 count = 0; 552 for (i = 0; i < num_visuals; i++) { 553 for (j = 0; j < 2; j++) { 554 struct ximage_config *xconf = &xdpy->configs[count]; 555 __GLcontextModes *mode = &xconf->base.mode; 556 557 xconf->visual = &visuals[i]; 558 xconf->base.color_format = choose_format(xconf->visual); 559 if (xconf->base.color_format == PIPE_FORMAT_NONE) 560 continue; 561 562 x11_screen_convert_visual(xdpy->xscr, xconf->visual, mode); 563 /* support double buffer mode */ 564 mode->doubleBufferMode = TRUE; 565 566 xconf->base.depth_format = PIPE_FORMAT_NONE; 567 xconf->base.stencil_format = PIPE_FORMAT_NONE; 568 /* create the second config with depth/stencil buffer */ 569 if (j == 1) { 570 xconf->base.depth_format = PIPE_FORMAT_S8Z24_UNORM; 571 xconf->base.stencil_format = PIPE_FORMAT_S8Z24_UNORM; 572 mode->depthBits = 24; 573 mode->stencilBits = 8; 574 mode->haveDepthBuffer = TRUE; 575 mode->haveStencilBuffer = TRUE; 576 } 577 578 mode->maxPbufferWidth = 4096; 579 mode->maxPbufferHeight = 4096; 580 mode->maxPbufferPixels = 4096 * 4096; 581 mode->drawableType = 582 GLX_WINDOW_BIT | GLX_PIXMAP_BIT | GLX_PBUFFER_BIT; 583 mode->swapMethod = GLX_SWAP_EXCHANGE_OML; 584 585 if (mode->alphaBits) 586 mode->bindToTextureRgba = TRUE; 587 else 588 mode->bindToTextureRgb = TRUE; 589 590 count++; 591 } 592 } 593 594 xdpy->num_configs = count; 595 } 596 597 configs = malloc(xdpy->num_configs * sizeof(*configs)); 598 if (configs) { 599 for (i = 0; i < xdpy->num_configs; i++) 600 configs[i] = (const struct native_config *) &xdpy->configs[i]; 601 if (num_configs) 602 *num_configs = xdpy->num_configs; 603 } 604 return configs; 605} 606 607static boolean 608ximage_display_is_pixmap_supported(struct native_display *ndpy, 609 EGLNativePixmapType pix, 610 const struct native_config *nconf) 611{ 612 struct ximage_display *xdpy = ximage_display(ndpy); 613 enum pipe_format fmt; 614 uint depth; 615 616 depth = x11_drawable_get_depth(xdpy->xscr, (Drawable) pix); 617 switch (depth) { 618 case 32: 619 fmt = PIPE_FORMAT_A8R8G8B8_UNORM; 620 break; 621 case 24: 622 fmt = PIPE_FORMAT_X8R8G8B8_UNORM; 623 break; 624 case 16: 625 fmt = PIPE_FORMAT_R5G6B5_UNORM; 626 break; 627 default: 628 fmt = PIPE_FORMAT_NONE; 629 break; 630 } 631 632 return (fmt == nconf->color_format); 633} 634 635static void 636ximage_display_destroy(struct native_display *ndpy) 637{ 638 struct ximage_display *xdpy = ximage_display(ndpy); 639 640 if (xdpy->configs) 641 free(xdpy->configs); 642 643 xdpy->base.screen->destroy(xdpy->base.screen); 644 free(xdpy->winsys); 645 646 x11_screen_destroy(xdpy->xscr); 647 if (xdpy->own_dpy) 648 XCloseDisplay(xdpy->dpy); 649 free(xdpy); 650} 651 652struct native_display * 653x11_create_ximage_display(EGLNativeDisplayType dpy, boolean use_xshm) 654{ 655 struct ximage_display *xdpy; 656 657 xdpy = CALLOC_STRUCT(ximage_display); 658 if (!xdpy) 659 return NULL; 660 661 xdpy->dpy = dpy; 662 if (!xdpy->dpy) { 663 xdpy->dpy = XOpenDisplay(NULL); 664 if (!xdpy->dpy) { 665 free(xdpy); 666 return NULL; 667 } 668 xdpy->own_dpy = TRUE; 669 } 670 671 xdpy->xscr_number = DefaultScreen(xdpy->dpy); 672 xdpy->xscr = x11_screen_create(xdpy->dpy, xdpy->xscr_number); 673 if (!xdpy->xscr) { 674 free(xdpy); 675 return NULL; 676 } 677 678 xdpy->use_xshm = 679 (use_xshm && x11_screen_support(xdpy->xscr, X11_SCREEN_EXTENSION_XSHM)); 680 681 xdpy->winsys = create_sw_winsys(); 682 xdpy->base.screen = softpipe_create_screen(xdpy->winsys); 683 684 xdpy->base.destroy = ximage_display_destroy; 685 686 xdpy->base.get_configs = ximage_display_get_configs; 687 xdpy->base.is_pixmap_supported = ximage_display_is_pixmap_supported; 688 xdpy->base.create_context = ximage_display_create_context; 689 xdpy->base.create_window_surface = ximage_display_create_window_surface; 690 xdpy->base.create_pixmap_surface = ximage_display_create_pixmap_surface; 691 xdpy->base.create_pbuffer_surface = ximage_display_create_pbuffer_surface; 692 693 return &xdpy->base; 694} 695