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