native_ximage.c revision 5e72b89b89fe172638afa66abdd6607d11970e5a
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/swrast_xlib.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 XIMAGE_SURFACE_TYPE_PBUFFER 47}; 48 49struct ximage_display { 50 struct native_display base; 51 Display *dpy; 52 boolean own_dpy; 53 54 struct x11_screen *xscr; 55 int xscr_number; 56 57 struct xm_driver *driver; 58 59 struct ximage_config *configs; 60 int num_configs; 61}; 62 63struct ximage_buffer { 64 struct pipe_texture *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 83struct ximage_config { 84 struct native_config base; 85 const XVisualInfo *visual; 86}; 87 88static INLINE struct ximage_display * 89ximage_display(const struct native_display *ndpy) 90{ 91 return (struct ximage_display *) ndpy; 92} 93 94static INLINE struct ximage_surface * 95ximage_surface(const struct native_surface *nsurf) 96{ 97 return (struct ximage_surface *) nsurf; 98} 99 100static INLINE struct ximage_config * 101ximage_config(const struct native_config *nconf) 102{ 103 return (struct ximage_config *) nconf; 104} 105 106static void 107ximage_surface_free_buffer(struct native_surface *nsurf, 108 enum native_attachment which) 109{ 110 struct ximage_surface *xsurf = ximage_surface(nsurf); 111 struct ximage_buffer *xbuf = &xsurf->buffers[which]; 112 113 pipe_texture_reference(&xbuf->texture, NULL); 114} 115 116static boolean 117ximage_surface_alloc_buffer(struct native_surface *nsurf, 118 enum native_attachment which) 119{ 120 struct ximage_surface *xsurf = ximage_surface(nsurf); 121 struct ximage_buffer *xbuf = &xsurf->buffers[which]; 122 struct pipe_screen *screen = xsurf->xdpy->base.screen; 123 struct pipe_texture templ; 124 125 /* free old data */ 126 if (xbuf->texture) 127 ximage_surface_free_buffer(&xsurf->base, which); 128 129 memset(&templ, 0, sizeof(templ)); 130 templ.target = PIPE_TEXTURE_2D; 131 templ.format = xsurf->color_format; 132 templ.width0 = xsurf->width; 133 templ.height0 = xsurf->height; 134 templ.depth0 = 1; 135 templ.tex_usage = PIPE_TEXTURE_USAGE_RENDER_TARGET; 136 137 if (xsurf->type != XIMAGE_SURFACE_TYPE_PBUFFER) { 138 switch (which) { 139 case NATIVE_ATTACHMENT_FRONT_LEFT: 140 case NATIVE_ATTACHMENT_FRONT_RIGHT: 141 templ.tex_usage |= PIPE_TEXTURE_USAGE_PRIMARY; 142 break; 143 case NATIVE_ATTACHMENT_BACK_LEFT: 144 case NATIVE_ATTACHMENT_BACK_RIGHT: 145 templ.tex_usage |= PIPE_TEXTURE_USAGE_DISPLAY_TARGET; 146 break; 147 default: 148 break; 149 } 150 } 151 xbuf->texture = screen->texture_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 /* pbuffer has fixed geometry */ 180 if (xsurf->type == XIMAGE_SURFACE_TYPE_PBUFFER) 181 return 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 if (xsurf->type == XIMAGE_SURFACE_TYPE_PBUFFER) 261 return TRUE; 262 263 assert(xsurf->drawable && xbuf->texture); 264 265 /* what's the cost of surface creation? */ 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 screen->flush_frontbuffer(screen, psurf, &xbuf->xdraw); 272 273 pipe_surface_reference(&psurf, NULL); 274 275 return TRUE; 276} 277 278static boolean 279ximage_surface_flush_frontbuffer(struct native_surface *nsurf) 280{ 281 struct ximage_surface *xsurf = ximage_surface(nsurf); 282 boolean ret; 283 284 ret = ximage_surface_draw_buffer(&xsurf->base, 285 NATIVE_ATTACHMENT_FRONT_LEFT); 286 /* force buffers to be updated in next validation call */ 287 xsurf->server_stamp++; 288 ximage_surface_notify_invalid(&xsurf->base); 289 290 return ret; 291} 292 293static boolean 294ximage_surface_swap_buffers(struct native_surface *nsurf) 295{ 296 struct ximage_surface *xsurf = ximage_surface(nsurf); 297 struct ximage_buffer *xfront, *xback, xtmp; 298 boolean ret; 299 300 /* display the back buffer first */ 301 ret = ximage_surface_draw_buffer(&xsurf->base, 302 NATIVE_ATTACHMENT_BACK_LEFT); 303 /* force buffers to be updated in next validation call */ 304 xsurf->server_stamp++; 305 ximage_surface_notify_invalid(&xsurf->base); 306 307 xfront = &xsurf->buffers[NATIVE_ATTACHMENT_FRONT_LEFT]; 308 xback = &xsurf->buffers[NATIVE_ATTACHMENT_BACK_LEFT]; 309 310 /* skip swapping unless there is a front buffer */ 311 if (xfront->texture) { 312 xtmp = *xfront; 313 *xfront = *xback; 314 *xback = xtmp; 315 } 316 317 return ret; 318} 319 320static boolean 321ximage_surface_validate(struct native_surface *nsurf, uint attachment_mask, 322 unsigned int *seq_num, struct pipe_texture **textures, 323 int *width, int *height) 324{ 325 struct ximage_surface *xsurf = ximage_surface(nsurf); 326 327 if (xsurf->client_stamp != xsurf->server_stamp || 328 (xsurf->valid_mask & attachment_mask) != attachment_mask) { 329 if (!ximage_surface_update_buffers(&xsurf->base, attachment_mask)) 330 return FALSE; 331 } 332 333 if (seq_num) 334 *seq_num = xsurf->client_stamp; 335 336 if (textures) { 337 int att; 338 for (att = 0; att < NUM_NATIVE_ATTACHMENTS; att++) { 339 if (native_attachment_mask_test(attachment_mask, att)) { 340 struct ximage_buffer *xbuf = &xsurf->buffers[att]; 341 342 textures[att] = NULL; 343 pipe_texture_reference(&textures[att], xbuf->texture); 344 } 345 } 346 } 347 348 if (width) 349 *width = xsurf->width; 350 if (height) 351 *height = xsurf->height; 352 353 return TRUE; 354} 355 356static void 357ximage_surface_wait(struct native_surface *nsurf) 358{ 359 struct ximage_surface *xsurf = ximage_surface(nsurf); 360 XSync(xsurf->xdpy->dpy, FALSE); 361 /* TODO XGetImage and update the front texture */ 362} 363 364static void 365ximage_surface_destroy(struct native_surface *nsurf) 366{ 367 struct ximage_surface *xsurf = ximage_surface(nsurf); 368 int i; 369 370 for (i = 0; i < NUM_NATIVE_ATTACHMENTS; i++) 371 ximage_surface_free_buffer(&xsurf->base, i); 372 373 free(xsurf); 374} 375 376static struct ximage_surface * 377ximage_display_create_surface(struct native_display *ndpy, 378 enum ximage_surface_type type, 379 Drawable drawable, 380 const struct native_config *nconf) 381{ 382 struct ximage_display *xdpy = ximage_display(ndpy); 383 struct ximage_config *xconf = ximage_config(nconf); 384 struct ximage_surface *xsurf; 385 386 xsurf = CALLOC_STRUCT(ximage_surface); 387 if (!xsurf) 388 return NULL; 389 390 xsurf->xdpy = xdpy; 391 xsurf->type = type; 392 xsurf->color_format = xconf->base.color_format; 393 xsurf->drawable = drawable; 394 395 if (xsurf->type != XIMAGE_SURFACE_TYPE_PBUFFER) { 396 xsurf->drawable = drawable; 397 xsurf->visual = *xconf->visual; 398 /* initialize the geometry */ 399 ximage_surface_update_buffers(&xsurf->base, 0x0); 400 } 401 402 xsurf->base.destroy = ximage_surface_destroy; 403 xsurf->base.swap_buffers = ximage_surface_swap_buffers; 404 xsurf->base.flush_frontbuffer = ximage_surface_flush_frontbuffer; 405 xsurf->base.validate = ximage_surface_validate; 406 xsurf->base.wait = ximage_surface_wait; 407 408 return xsurf; 409} 410 411static struct native_surface * 412ximage_display_create_window_surface(struct native_display *ndpy, 413 EGLNativeWindowType win, 414 const struct native_config *nconf) 415{ 416 struct ximage_surface *xsurf; 417 418 xsurf = ximage_display_create_surface(ndpy, XIMAGE_SURFACE_TYPE_WINDOW, 419 (Drawable) win, nconf); 420 return (xsurf) ? &xsurf->base : NULL; 421} 422 423static struct native_surface * 424ximage_display_create_pixmap_surface(struct native_display *ndpy, 425 EGLNativePixmapType pix, 426 const struct native_config *nconf) 427{ 428 struct ximage_surface *xsurf; 429 430 xsurf = ximage_display_create_surface(ndpy, XIMAGE_SURFACE_TYPE_PIXMAP, 431 (Drawable) pix, nconf); 432 return (xsurf) ? &xsurf->base : NULL; 433} 434 435static struct native_surface * 436ximage_display_create_pbuffer_surface(struct native_display *ndpy, 437 const struct native_config *nconf, 438 uint width, uint height) 439{ 440 struct ximage_surface *xsurf; 441 442 xsurf = ximage_display_create_surface(ndpy, XIMAGE_SURFACE_TYPE_PBUFFER, 443 (Drawable) None, nconf); 444 if (xsurf) { 445 xsurf->width = width; 446 xsurf->height = height; 447 } 448 return (xsurf) ? &xsurf->base : NULL; 449} 450 451static enum pipe_format 452choose_format(const XVisualInfo *vinfo) 453{ 454 enum pipe_format fmt; 455 /* TODO elaborate the formats */ 456 switch (vinfo->depth) { 457 case 32: 458 fmt = PIPE_FORMAT_B8G8R8A8_UNORM; 459 break; 460 case 24: 461 fmt = PIPE_FORMAT_B8G8R8X8_UNORM; 462 break; 463 case 16: 464 fmt = PIPE_FORMAT_B5G6R5_UNORM; 465 break; 466 default: 467 fmt = PIPE_FORMAT_NONE; 468 break; 469 } 470 471 return fmt; 472} 473 474static const struct native_config ** 475ximage_display_get_configs(struct native_display *ndpy, int *num_configs) 476{ 477 struct ximage_display *xdpy = ximage_display(ndpy); 478 const struct native_config **configs; 479 int i; 480 481 /* first time */ 482 if (!xdpy->configs) { 483 const XVisualInfo *visuals; 484 int num_visuals, count, j; 485 486 visuals = x11_screen_get_visuals(xdpy->xscr, &num_visuals); 487 if (!visuals) 488 return NULL; 489 490 /* 491 * Create two configs for each visual. 492 * One with depth/stencil buffer; one without 493 */ 494 xdpy->configs = calloc(num_visuals * 2, sizeof(*xdpy->configs)); 495 if (!xdpy->configs) 496 return NULL; 497 498 count = 0; 499 for (i = 0; i < num_visuals; i++) { 500 for (j = 0; j < 2; j++) { 501 struct ximage_config *xconf = &xdpy->configs[count]; 502 __GLcontextModes *mode = &xconf->base.mode; 503 504 xconf->visual = &visuals[i]; 505 xconf->base.color_format = choose_format(xconf->visual); 506 if (xconf->base.color_format == PIPE_FORMAT_NONE) 507 continue; 508 509 x11_screen_convert_visual(xdpy->xscr, xconf->visual, mode); 510 /* support double buffer mode */ 511 mode->doubleBufferMode = TRUE; 512 513 xconf->base.depth_format = PIPE_FORMAT_NONE; 514 xconf->base.stencil_format = PIPE_FORMAT_NONE; 515 /* create the second config with depth/stencil buffer */ 516 if (j == 1) { 517 xconf->base.depth_format = PIPE_FORMAT_Z24S8_UNORM; 518 xconf->base.stencil_format = PIPE_FORMAT_Z24S8_UNORM; 519 mode->depthBits = 24; 520 mode->stencilBits = 8; 521 mode->haveDepthBuffer = TRUE; 522 mode->haveStencilBuffer = TRUE; 523 } 524 525 mode->maxPbufferWidth = 4096; 526 mode->maxPbufferHeight = 4096; 527 mode->maxPbufferPixels = 4096 * 4096; 528 mode->drawableType = 529 GLX_WINDOW_BIT | GLX_PIXMAP_BIT | GLX_PBUFFER_BIT; 530 mode->swapMethod = GLX_SWAP_EXCHANGE_OML; 531 532 if (mode->alphaBits) 533 mode->bindToTextureRgba = TRUE; 534 else 535 mode->bindToTextureRgb = TRUE; 536 537 count++; 538 } 539 } 540 541 xdpy->num_configs = count; 542 } 543 544 configs = malloc(xdpy->num_configs * sizeof(*configs)); 545 if (configs) { 546 for (i = 0; i < xdpy->num_configs; i++) 547 configs[i] = (const struct native_config *) &xdpy->configs[i]; 548 if (num_configs) 549 *num_configs = xdpy->num_configs; 550 } 551 return configs; 552} 553 554static boolean 555ximage_display_is_pixmap_supported(struct native_display *ndpy, 556 EGLNativePixmapType pix, 557 const struct native_config *nconf) 558{ 559 struct ximage_display *xdpy = ximage_display(ndpy); 560 enum pipe_format fmt; 561 uint depth; 562 563 depth = x11_drawable_get_depth(xdpy->xscr, (Drawable) pix); 564 switch (depth) { 565 case 32: 566 fmt = PIPE_FORMAT_B8G8R8A8_UNORM; 567 break; 568 case 24: 569 fmt = PIPE_FORMAT_B8G8R8X8_UNORM; 570 break; 571 case 16: 572 fmt = PIPE_FORMAT_B5G6R5_UNORM; 573 break; 574 default: 575 fmt = PIPE_FORMAT_NONE; 576 break; 577 } 578 579 return (fmt == nconf->color_format); 580} 581 582static int 583ximage_display_get_param(struct native_display *ndpy, 584 enum native_param_type param) 585{ 586 int val; 587 588 switch (param) { 589 case NATIVE_PARAM_USE_NATIVE_BUFFER: 590 /* private buffers are allocated */ 591 val = FALSE; 592 break; 593 default: 594 val = 0; 595 break; 596 } 597 598 return val; 599} 600 601static void 602ximage_display_destroy(struct native_display *ndpy) 603{ 604 struct ximage_display *xdpy = ximage_display(ndpy); 605 606 if (xdpy->configs) 607 free(xdpy->configs); 608 609 xdpy->base.screen->destroy(xdpy->base.screen); 610 611 x11_screen_destroy(xdpy->xscr); 612 if (xdpy->own_dpy) 613 XCloseDisplay(xdpy->dpy); 614 free(xdpy); 615} 616 617struct native_display * 618x11_create_ximage_display(EGLNativeDisplayType dpy) 619{ 620 struct ximage_display *xdpy; 621 622 xdpy = CALLOC_STRUCT(ximage_display); 623 if (!xdpy) 624 return NULL; 625 626 xdpy->dpy = dpy; 627 if (!xdpy->dpy) { 628 xdpy->dpy = XOpenDisplay(NULL); 629 if (!xdpy->dpy) { 630 free(xdpy); 631 return NULL; 632 } 633 xdpy->own_dpy = TRUE; 634 } 635 636 xdpy->xscr_number = DefaultScreen(xdpy->dpy); 637 xdpy->xscr = x11_screen_create(xdpy->dpy, xdpy->xscr_number); 638 if (!xdpy->xscr) { 639 free(xdpy); 640 return NULL; 641 } 642 643 xdpy->base.screen = swrast_xlib_create_screen(xdpy->dpy); 644 645 xdpy->base.destroy = ximage_display_destroy; 646 xdpy->base.get_param = ximage_display_get_param; 647 648 xdpy->base.get_configs = ximage_display_get_configs; 649 xdpy->base.is_pixmap_supported = ximage_display_is_pixmap_supported; 650 xdpy->base.create_window_surface = ximage_display_create_window_surface; 651 xdpy->base.create_pixmap_surface = ximage_display_create_pixmap_surface; 652 xdpy->base.create_pbuffer_surface = ximage_display_create_pbuffer_surface; 653 654 return &xdpy->base; 655} 656