native_ximage.c revision f69b35fa15f43747dde29addaeec845604d7e127
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 "util/u_memory.h" 32#include "util/u_math.h" 33#include "util/u_format.h" 34#include "pipe/p_compiler.h" 35#include "util/u_inlines.h" 36#include "state_tracker/xlib_sw_winsys.h" 37#include "target-helpers/wrap_screen.h" 38#include "util/u_debug.h" 39#include "softpipe/sp_public.h" 40#include "llvmpipe/lp_public.h" 41#include "cell/ppu/cell_public.h" 42#include "egllog.h" 43 44#include "native_x11.h" 45#include "x11_screen.h" 46 47enum ximage_surface_type { 48 XIMAGE_SURFACE_TYPE_WINDOW, 49 XIMAGE_SURFACE_TYPE_PIXMAP, 50}; 51 52struct ximage_display { 53 struct native_display base; 54 Display *dpy; 55 boolean own_dpy; 56 57 struct native_event_handler *event_handler; 58 59 struct x11_screen *xscr; 60 int xscr_number; 61 62 struct ximage_config *configs; 63 int num_configs; 64}; 65 66struct ximage_buffer { 67 struct pipe_texture *texture; 68 struct xlib_drawable xdraw; 69}; 70 71struct ximage_surface { 72 struct native_surface base; 73 Drawable drawable; 74 enum ximage_surface_type type; 75 enum pipe_format color_format; 76 XVisualInfo visual; 77 struct ximage_display *xdpy; 78 79 unsigned int server_stamp; 80 unsigned int client_stamp; 81 int width, height; 82 struct ximage_buffer buffers[NUM_NATIVE_ATTACHMENTS]; 83 uint valid_mask; 84 85 struct pipe_surface *draw_surface; 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 121static boolean 122ximage_surface_alloc_buffer(struct native_surface *nsurf, 123 enum native_attachment which) 124{ 125 struct ximage_surface *xsurf = ximage_surface(nsurf); 126 struct ximage_buffer *xbuf = &xsurf->buffers[which]; 127 struct pipe_screen *screen = xsurf->xdpy->base.screen; 128 struct pipe_texture templ; 129 130 /* free old data */ 131 if (xbuf->texture) 132 ximage_surface_free_buffer(&xsurf->base, which); 133 134 memset(&templ, 0, sizeof(templ)); 135 templ.target = PIPE_TEXTURE_2D; 136 templ.format = xsurf->color_format; 137 templ.width0 = xsurf->width; 138 templ.height0 = xsurf->height; 139 templ.depth0 = 1; 140 templ.tex_usage = PIPE_TEXTURE_USAGE_RENDER_TARGET; 141 142 switch (which) { 143 case NATIVE_ATTACHMENT_FRONT_LEFT: 144 case NATIVE_ATTACHMENT_FRONT_RIGHT: 145 templ.tex_usage |= PIPE_TEXTURE_USAGE_SCANOUT; 146 break; 147 case NATIVE_ATTACHMENT_BACK_LEFT: 148 case NATIVE_ATTACHMENT_BACK_RIGHT: 149 templ.tex_usage |= PIPE_TEXTURE_USAGE_DISPLAY_TARGET; 150 break; 151 default: 152 break; 153 } 154 155 xbuf->texture = screen->texture_create(screen, &templ); 156 if (xbuf->texture) { 157 xbuf->xdraw.visual = xsurf->visual.visual; 158 xbuf->xdraw.depth = xsurf->visual.depth; 159 xbuf->xdraw.drawable = xsurf->drawable; 160 } 161 162 /* clean up the buffer if allocation failed */ 163 if (!xbuf->texture) 164 ximage_surface_free_buffer(&xsurf->base, which); 165 166 return (xbuf->texture != NULL); 167} 168 169/** 170 * Update the geometry of the surface. Return TRUE if the geometry has changed 171 * since last call. 172 */ 173static boolean 174ximage_surface_update_geometry(struct native_surface *nsurf) 175{ 176 struct ximage_surface *xsurf = ximage_surface(nsurf); 177 Status ok; 178 Window root; 179 int x, y; 180 unsigned int w, h, border, depth; 181 boolean updated = FALSE; 182 183 ok = XGetGeometry(xsurf->xdpy->dpy, xsurf->drawable, 184 &root, &x, &y, &w, &h, &border, &depth); 185 if (ok && (xsurf->width != w || xsurf->height != h)) { 186 xsurf->width = w; 187 xsurf->height = h; 188 189 xsurf->server_stamp++; 190 updated = TRUE; 191 } 192 193 return updated; 194} 195 196static void 197ximage_surface_notify_invalid(struct native_surface *nsurf) 198{ 199 struct ximage_surface *xsurf = ximage_surface(nsurf); 200 struct ximage_display *xdpy = xsurf->xdpy; 201 202 xdpy->event_handler->invalid_surface(&xdpy->base, 203 &xsurf->base, xsurf->server_stamp); 204} 205 206/** 207 * Update the buffers of the surface. It is a slow function due to the 208 * round-trip to the server. 209 */ 210static boolean 211ximage_surface_update_buffers(struct native_surface *nsurf, uint buffer_mask) 212{ 213 struct ximage_surface *xsurf = ximage_surface(nsurf); 214 boolean updated; 215 uint new_valid; 216 int att; 217 218 updated = ximage_surface_update_geometry(&xsurf->base); 219 if (updated) { 220 /* all buffers become invalid */ 221 xsurf->valid_mask = 0x0; 222 } 223 else { 224 buffer_mask &= ~xsurf->valid_mask; 225 /* all requested buffers are valid */ 226 if (!buffer_mask) { 227 xsurf->client_stamp = xsurf->server_stamp; 228 return TRUE; 229 } 230 } 231 232 new_valid = 0x0; 233 for (att = 0; att < NUM_NATIVE_ATTACHMENTS; att++) { 234 if (native_attachment_mask_test(buffer_mask, att)) { 235 /* reallocate the texture */ 236 if (!ximage_surface_alloc_buffer(&xsurf->base, att)) 237 break; 238 239 new_valid |= (1 << att); 240 if (buffer_mask == new_valid) 241 break; 242 } 243 } 244 245 xsurf->valid_mask |= new_valid; 246 xsurf->client_stamp = xsurf->server_stamp; 247 248 return (new_valid == buffer_mask); 249} 250 251static boolean 252ximage_surface_draw_buffer(struct native_surface *nsurf, 253 enum native_attachment which) 254{ 255 struct ximage_surface *xsurf = ximage_surface(nsurf); 256 struct ximage_buffer *xbuf = &xsurf->buffers[which]; 257 struct pipe_screen *screen = xsurf->xdpy->base.screen; 258 struct pipe_surface *psurf; 259 260 assert(xsurf->drawable && xbuf->texture); 261 262 psurf = xsurf->draw_surface; 263 if (!psurf || psurf->texture != xbuf->texture) { 264 pipe_surface_reference(&xsurf->draw_surface, NULL); 265 266 psurf = screen->get_tex_surface(screen, 267 xbuf->texture, 0, 0, 0, PIPE_BUFFER_USAGE_CPU_READ); 268 if (!psurf) 269 return FALSE; 270 271 xsurf->draw_surface = psurf; 272 } 273 274 screen->flush_frontbuffer(screen, psurf, &xbuf->xdraw); 275 276 return TRUE; 277} 278 279static boolean 280ximage_surface_flush_frontbuffer(struct native_surface *nsurf) 281{ 282 struct ximage_surface *xsurf = ximage_surface(nsurf); 283 boolean ret; 284 285 ret = ximage_surface_draw_buffer(&xsurf->base, 286 NATIVE_ATTACHMENT_FRONT_LEFT); 287 /* force buffers to be updated in next validation call */ 288 xsurf->server_stamp++; 289 ximage_surface_notify_invalid(&xsurf->base); 290 291 return ret; 292} 293 294static boolean 295ximage_surface_swap_buffers(struct native_surface *nsurf) 296{ 297 struct ximage_surface *xsurf = ximage_surface(nsurf); 298 struct ximage_buffer *xfront, *xback, xtmp; 299 boolean ret; 300 301 /* display the back buffer first */ 302 ret = ximage_surface_draw_buffer(&xsurf->base, 303 NATIVE_ATTACHMENT_BACK_LEFT); 304 /* force buffers to be updated in next validation call */ 305 xsurf->server_stamp++; 306 ximage_surface_notify_invalid(&xsurf->base); 307 308 xfront = &xsurf->buffers[NATIVE_ATTACHMENT_FRONT_LEFT]; 309 xback = &xsurf->buffers[NATIVE_ATTACHMENT_BACK_LEFT]; 310 311 /* skip swapping unless there is a front buffer */ 312 if (xfront->texture) { 313 xtmp = *xfront; 314 *xfront = *xback; 315 *xback = xtmp; 316 } 317 318 return ret; 319} 320 321static boolean 322ximage_surface_validate(struct native_surface *nsurf, uint attachment_mask, 323 unsigned int *seq_num, struct pipe_texture **textures, 324 int *width, int *height) 325{ 326 struct ximage_surface *xsurf = ximage_surface(nsurf); 327 328 if (xsurf->client_stamp != xsurf->server_stamp || 329 (xsurf->valid_mask & attachment_mask) != attachment_mask) { 330 if (!ximage_surface_update_buffers(&xsurf->base, attachment_mask)) 331 return FALSE; 332 } 333 334 if (seq_num) 335 *seq_num = xsurf->client_stamp; 336 337 if (textures) { 338 int att; 339 for (att = 0; att < NUM_NATIVE_ATTACHMENTS; att++) { 340 if (native_attachment_mask_test(attachment_mask, att)) { 341 struct ximage_buffer *xbuf = &xsurf->buffers[att]; 342 343 textures[att] = NULL; 344 pipe_texture_reference(&textures[att], xbuf->texture); 345 } 346 } 347 } 348 349 if (width) 350 *width = xsurf->width; 351 if (height) 352 *height = xsurf->height; 353 354 return TRUE; 355} 356 357static void 358ximage_surface_wait(struct native_surface *nsurf) 359{ 360 struct ximage_surface *xsurf = ximage_surface(nsurf); 361 XSync(xsurf->xdpy->dpy, FALSE); 362 /* TODO XGetImage and update the front texture */ 363} 364 365static void 366ximage_surface_destroy(struct native_surface *nsurf) 367{ 368 struct ximage_surface *xsurf = ximage_surface(nsurf); 369 int i; 370 371 pipe_surface_reference(&xsurf->draw_surface, NULL); 372 373 for (i = 0; i < NUM_NATIVE_ATTACHMENTS; i++) 374 ximage_surface_free_buffer(&xsurf->base, i); 375 376 free(xsurf); 377} 378 379static struct ximage_surface * 380ximage_display_create_surface(struct native_display *ndpy, 381 enum ximage_surface_type type, 382 Drawable drawable, 383 const struct native_config *nconf) 384{ 385 struct ximage_display *xdpy = ximage_display(ndpy); 386 struct ximage_config *xconf = ximage_config(nconf); 387 struct ximage_surface *xsurf; 388 389 xsurf = CALLOC_STRUCT(ximage_surface); 390 if (!xsurf) 391 return NULL; 392 393 xsurf->xdpy = xdpy; 394 xsurf->type = type; 395 xsurf->color_format = xconf->base.color_format; 396 xsurf->drawable = drawable; 397 398 xsurf->drawable = drawable; 399 xsurf->visual = *xconf->visual; 400 /* initialize the geometry */ 401 ximage_surface_update_buffers(&xsurf->base, 0x0); 402 403 xsurf->base.destroy = ximage_surface_destroy; 404 xsurf->base.swap_buffers = ximage_surface_swap_buffers; 405 xsurf->base.flush_frontbuffer = ximage_surface_flush_frontbuffer; 406 xsurf->base.validate = ximage_surface_validate; 407 xsurf->base.wait = ximage_surface_wait; 408 409 return xsurf; 410} 411 412static struct native_surface * 413ximage_display_create_window_surface(struct native_display *ndpy, 414 EGLNativeWindowType win, 415 const struct native_config *nconf) 416{ 417 struct ximage_surface *xsurf; 418 419 xsurf = ximage_display_create_surface(ndpy, XIMAGE_SURFACE_TYPE_WINDOW, 420 (Drawable) win, nconf); 421 return (xsurf) ? &xsurf->base : NULL; 422} 423 424static struct native_surface * 425ximage_display_create_pixmap_surface(struct native_display *ndpy, 426 EGLNativePixmapType pix, 427 const struct native_config *nconf) 428{ 429 struct ximage_surface *xsurf; 430 431 xsurf = ximage_display_create_surface(ndpy, XIMAGE_SURFACE_TYPE_PIXMAP, 432 (Drawable) pix, nconf); 433 return (xsurf) ? &xsurf->base : NULL; 434} 435 436static enum pipe_format 437choose_format(const XVisualInfo *vinfo) 438{ 439 enum pipe_format fmt; 440 /* TODO elaborate the formats */ 441 switch (vinfo->depth) { 442 case 32: 443 fmt = PIPE_FORMAT_B8G8R8A8_UNORM; 444 break; 445 case 24: 446 fmt = PIPE_FORMAT_B8G8R8X8_UNORM; 447 break; 448 case 16: 449 fmt = PIPE_FORMAT_B5G6R5_UNORM; 450 break; 451 default: 452 fmt = PIPE_FORMAT_NONE; 453 break; 454 } 455 456 return fmt; 457} 458 459static const struct native_config ** 460ximage_display_get_configs(struct native_display *ndpy, int *num_configs) 461{ 462 struct ximage_display *xdpy = ximage_display(ndpy); 463 const struct native_config **configs; 464 int i; 465 466 /* first time */ 467 if (!xdpy->configs) { 468 const XVisualInfo *visuals; 469 int num_visuals, count, j; 470 471 visuals = x11_screen_get_visuals(xdpy->xscr, &num_visuals); 472 if (!visuals) 473 return NULL; 474 475 /* 476 * Create two configs for each visual. 477 * One with depth/stencil buffer; one without 478 */ 479 xdpy->configs = calloc(num_visuals * 2, sizeof(*xdpy->configs)); 480 if (!xdpy->configs) 481 return NULL; 482 483 count = 0; 484 for (i = 0; i < num_visuals; i++) { 485 for (j = 0; j < 2; j++) { 486 struct ximage_config *xconf = &xdpy->configs[count]; 487 __GLcontextModes *mode = &xconf->base.mode; 488 489 xconf->visual = &visuals[i]; 490 xconf->base.color_format = choose_format(xconf->visual); 491 if (xconf->base.color_format == PIPE_FORMAT_NONE) 492 continue; 493 494 x11_screen_convert_visual(xdpy->xscr, xconf->visual, mode); 495 /* support double buffer mode */ 496 mode->doubleBufferMode = TRUE; 497 498 xconf->base.depth_format = PIPE_FORMAT_NONE; 499 xconf->base.stencil_format = PIPE_FORMAT_NONE; 500 /* create the second config with depth/stencil buffer */ 501 if (j == 1) { 502 xconf->base.depth_format = PIPE_FORMAT_Z24_UNORM_S8_USCALED; 503 xconf->base.stencil_format = PIPE_FORMAT_Z24_UNORM_S8_USCALED; 504 mode->depthBits = 24; 505 mode->stencilBits = 8; 506 mode->haveDepthBuffer = TRUE; 507 mode->haveStencilBuffer = TRUE; 508 } 509 510 mode->maxPbufferWidth = 4096; 511 mode->maxPbufferHeight = 4096; 512 mode->maxPbufferPixels = 4096 * 4096; 513 mode->drawableType = 514 GLX_WINDOW_BIT | GLX_PIXMAP_BIT | GLX_PBUFFER_BIT; 515 mode->swapMethod = GLX_SWAP_EXCHANGE_OML; 516 517 if (mode->alphaBits) 518 mode->bindToTextureRgba = TRUE; 519 else 520 mode->bindToTextureRgb = TRUE; 521 522 count++; 523 } 524 } 525 526 xdpy->num_configs = count; 527 } 528 529 configs = malloc(xdpy->num_configs * sizeof(*configs)); 530 if (configs) { 531 for (i = 0; i < xdpy->num_configs; i++) 532 configs[i] = (const struct native_config *) &xdpy->configs[i]; 533 if (num_configs) 534 *num_configs = xdpy->num_configs; 535 } 536 return configs; 537} 538 539static boolean 540ximage_display_is_pixmap_supported(struct native_display *ndpy, 541 EGLNativePixmapType pix, 542 const struct native_config *nconf) 543{ 544 struct ximage_display *xdpy = ximage_display(ndpy); 545 enum pipe_format fmt; 546 uint depth; 547 548 depth = x11_drawable_get_depth(xdpy->xscr, (Drawable) pix); 549 switch (depth) { 550 case 32: 551 fmt = PIPE_FORMAT_B8G8R8A8_UNORM; 552 break; 553 case 24: 554 fmt = PIPE_FORMAT_B8G8R8X8_UNORM; 555 break; 556 case 16: 557 fmt = PIPE_FORMAT_B5G6R5_UNORM; 558 break; 559 default: 560 fmt = PIPE_FORMAT_NONE; 561 break; 562 } 563 564 return (fmt == nconf->color_format); 565} 566 567static int 568ximage_display_get_param(struct native_display *ndpy, 569 enum native_param_type param) 570{ 571 int val; 572 573 switch (param) { 574 case NATIVE_PARAM_USE_NATIVE_BUFFER: 575 /* private buffers are allocated */ 576 val = FALSE; 577 break; 578 default: 579 val = 0; 580 break; 581 } 582 583 return val; 584} 585 586static void 587ximage_display_destroy(struct native_display *ndpy) 588{ 589 struct ximage_display *xdpy = ximage_display(ndpy); 590 591 if (xdpy->configs) 592 free(xdpy->configs); 593 594 xdpy->base.screen->destroy(xdpy->base.screen); 595 596 x11_screen_destroy(xdpy->xscr); 597 if (xdpy->own_dpy) 598 XCloseDisplay(xdpy->dpy); 599 free(xdpy); 600} 601 602 603/* Helper function to build a subset of a driver stack consisting of 604 * one of the software rasterizers (cell, llvmpipe, softpipe) and the 605 * xlib winsys. 606 * 607 * This function could be shared, but currently causes headaches for 608 * the build systems, particularly scons if we try. 609 * 610 * Long term, want to avoid having global #defines for things like 611 * GALLIUM_LLVMPIPE, GALLIUM_CELL, etc. Scons already eliminates 612 * those #defines, so things that are painful for it now are likely to 613 * be painful for other build systems in the future. 614 */ 615static struct pipe_screen * 616swrast_xlib_create_screen( Display *display ) 617{ 618 struct sw_winsys *winsys; 619 struct pipe_screen *screen = NULL; 620 621 /* Create the underlying winsys, which performs presents to Xlib 622 * drawables: 623 */ 624 winsys = xlib_create_sw_winsys( display ); 625 if (winsys == NULL) 626 return NULL; 627 628 /* Create a software rasterizer on top of that winsys. Use 629 * llvmpipe if it is available. 630 */ 631#if defined(GALLIUM_LLVMPIPE) 632 if (screen == NULL && 633 !debug_get_bool_option("GALLIUM_NO_LLVM", FALSE)) 634 screen = llvmpipe_create_screen( winsys ); 635#endif 636 637 if (screen == NULL) 638 screen = softpipe_create_screen( winsys ); 639 640 if (screen == NULL) 641 goto fail; 642 643 /* Inject any wrapping layers we want to here: 644 */ 645 return gallium_wrap_screen( screen ); 646 647fail: 648 if (winsys) 649 winsys->destroy( winsys ); 650 651 return NULL; 652} 653 654 655 656struct native_display * 657x11_create_ximage_display(EGLNativeDisplayType dpy, 658 struct native_event_handler *event_handler) 659{ 660 struct ximage_display *xdpy; 661 662 xdpy = CALLOC_STRUCT(ximage_display); 663 if (!xdpy) 664 return NULL; 665 666 xdpy->dpy = dpy; 667 if (!xdpy->dpy) { 668 xdpy->dpy = XOpenDisplay(NULL); 669 if (!xdpy->dpy) { 670 free(xdpy); 671 return NULL; 672 } 673 xdpy->own_dpy = TRUE; 674 } 675 676 xdpy->event_handler = event_handler; 677 678 xdpy->xscr_number = DefaultScreen(xdpy->dpy); 679 xdpy->xscr = x11_screen_create(xdpy->dpy, xdpy->xscr_number); 680 if (!xdpy->xscr) { 681 free(xdpy); 682 return NULL; 683 } 684 685 xdpy->base.screen = swrast_xlib_create_screen(xdpy->dpy); 686 687 xdpy->base.destroy = ximage_display_destroy; 688 xdpy->base.get_param = ximage_display_get_param; 689 690 xdpy->base.get_configs = ximage_display_get_configs; 691 xdpy->base.is_pixmap_supported = ximage_display_is_pixmap_supported; 692 xdpy->base.create_window_surface = ximage_display_create_window_surface; 693 xdpy->base.create_pixmap_surface = ximage_display_create_pixmap_surface; 694 695 return &xdpy->base; 696} 697