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