native_ximage.c revision 0c96690a5b6e1c2d114e7ec5f1e9d60a4ff2a330
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_simple_screen.h" 36#include "util/u_inlines.h" 37#include "state_tracker/xlib_sw_winsys.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 GC gc; 77 78 unsigned int server_stamp; 79 unsigned int client_stamp; 80 int width, height; 81 struct ximage_buffer buffers[NUM_NATIVE_ATTACHMENTS]; 82 uint valid_mask; 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_texture_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_texture 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.tex_usage = PIPE_TEXTURE_USAGE_RENDER_TARGET; 138 139 if (xsurf->type != XIMAGE_SURFACE_TYPE_PBUFFER) { 140 switch (which) { 141 case NATIVE_ATTACHMENT_FRONT_LEFT: 142 case NATIVE_ATTACHMENT_FRONT_RIGHT: 143 templ.tex_usage |= PIPE_TEXTURE_USAGE_PRIMARY; 144 break; 145 case NATIVE_ATTACHMENT_BACK_LEFT: 146 case NATIVE_ATTACHMENT_BACK_RIGHT: 147 templ.tex_usage |= PIPE_TEXTURE_USAGE_DISPLAY_TARGET; 148 break; 149 default: 150 break; 151 } 152 } 153 xbuf->texture = screen->texture_create(screen, &templ); 154 if (xbuf->texture) { 155 xbuf->xdraw.visual = xsurf->visual.visual; 156 xbuf->xdraw.depth = xsurf->visual.depth; 157 xbuf->xdraw.drawable = xsurf->drawable; 158 xbuf->xdraw.gc = xsurf->gc; 159 } 160 161 /* clean up the buffer if allocation failed */ 162 if (!xbuf->texture) 163 ximage_surface_free_buffer(&xsurf->base, which); 164 165 return (xbuf->texture != NULL); 166} 167 168/** 169 * Update the geometry of the surface. Return TRUE if the geometry has changed 170 * since last call. 171 */ 172static boolean 173ximage_surface_update_geometry(struct native_surface *nsurf) 174{ 175 struct ximage_surface *xsurf = ximage_surface(nsurf); 176 Status ok; 177 Window root; 178 int x, y; 179 unsigned int w, h, border, depth; 180 boolean updated = FALSE; 181 182 /* pbuffer has fixed geometry */ 183 if (xsurf->type == XIMAGE_SURFACE_TYPE_PBUFFER) 184 return FALSE; 185 186 ok = XGetGeometry(xsurf->xdpy->dpy, xsurf->drawable, 187 &root, &x, &y, &w, &h, &border, &depth); 188 if (ok && (xsurf->width != w || xsurf->height != h)) { 189 xsurf->width = w; 190 xsurf->height = h; 191 192 xsurf->server_stamp++; 193 updated = TRUE; 194 } 195 196 return updated; 197} 198 199static void 200ximage_surface_notify_invalid(struct native_surface *nsurf) 201{ 202 struct ximage_surface *xsurf = ximage_surface(nsurf); 203 struct ximage_display *xdpy = xsurf->xdpy; 204 205 xdpy->event_handler->invalid_surface(&xdpy->base, 206 &xsurf->base, xsurf->server_stamp); 207} 208 209/** 210 * Update the buffers of the surface. It is a slow function due to the 211 * round-trip to the server. 212 */ 213static boolean 214ximage_surface_update_buffers(struct native_surface *nsurf, uint buffer_mask) 215{ 216 struct ximage_surface *xsurf = ximage_surface(nsurf); 217 boolean updated; 218 uint new_valid; 219 int att; 220 221 updated = ximage_surface_update_geometry(&xsurf->base); 222 if (updated) { 223 /* all buffers become invalid */ 224 xsurf->valid_mask = 0x0; 225 } 226 else { 227 buffer_mask &= ~xsurf->valid_mask; 228 /* all requested buffers are valid */ 229 if (!buffer_mask) { 230 xsurf->client_stamp = xsurf->server_stamp; 231 return TRUE; 232 } 233 } 234 235 new_valid = 0x0; 236 for (att = 0; att < NUM_NATIVE_ATTACHMENTS; att++) { 237 if (native_attachment_mask_test(buffer_mask, att)) { 238 /* reallocate the texture */ 239 if (!ximage_surface_alloc_buffer(&xsurf->base, att)) 240 break; 241 242 new_valid |= (1 << att); 243 if (buffer_mask == new_valid) 244 break; 245 } 246 } 247 248 xsurf->valid_mask |= new_valid; 249 xsurf->client_stamp = xsurf->server_stamp; 250 251 return (new_valid == buffer_mask); 252} 253 254static boolean 255ximage_surface_draw_buffer(struct native_surface *nsurf, 256 enum native_attachment which) 257{ 258 struct ximage_surface *xsurf = ximage_surface(nsurf); 259 struct ximage_buffer *xbuf = &xsurf->buffers[which]; 260 struct pipe_screen *screen = xsurf->xdpy->base.screen; 261 struct pipe_surface *psurf; 262 263 if (xsurf->type == XIMAGE_SURFACE_TYPE_PBUFFER) 264 return TRUE; 265 266 assert(xsurf->drawable && xbuf->texture); 267 268 /* what's the cost of surface creation? */ 269 psurf = screen->get_tex_surface(screen, 270 xbuf->texture, 0, 0, 0, PIPE_BUFFER_USAGE_CPU_READ); 271 if (!psurf) 272 return FALSE; 273 274 screen->flush_frontbuffer(screen, psurf, &xbuf->xdraw); 275 276 pipe_surface_reference(&psurf, NULL); 277 278 return TRUE; 279} 280 281static boolean 282ximage_surface_flush_frontbuffer(struct native_surface *nsurf) 283{ 284 struct ximage_surface *xsurf = ximage_surface(nsurf); 285 boolean ret; 286 287 ret = ximage_surface_draw_buffer(&xsurf->base, 288 NATIVE_ATTACHMENT_FRONT_LEFT); 289 /* force buffers to be updated in next validation call */ 290 xsurf->server_stamp++; 291 ximage_surface_notify_invalid(&xsurf->base); 292 293 return ret; 294} 295 296static boolean 297ximage_surface_swap_buffers(struct native_surface *nsurf) 298{ 299 struct ximage_surface *xsurf = ximage_surface(nsurf); 300 struct ximage_buffer *xfront, *xback, xtmp; 301 boolean ret; 302 303 /* display the back buffer first */ 304 ret = ximage_surface_draw_buffer(&xsurf->base, 305 NATIVE_ATTACHMENT_BACK_LEFT); 306 /* force buffers to be updated in next validation call */ 307 xsurf->server_stamp++; 308 ximage_surface_notify_invalid(&xsurf->base); 309 310 xfront = &xsurf->buffers[NATIVE_ATTACHMENT_FRONT_LEFT]; 311 xback = &xsurf->buffers[NATIVE_ATTACHMENT_BACK_LEFT]; 312 313 /* skip swapping unless there is a front buffer */ 314 if (xfront->texture) { 315 xtmp = *xfront; 316 *xfront = *xback; 317 *xback = xtmp; 318 } 319 320 return ret; 321} 322 323static boolean 324ximage_surface_validate(struct native_surface *nsurf, uint attachment_mask, 325 unsigned int *seq_num, struct pipe_texture **textures, 326 int *width, int *height) 327{ 328 struct ximage_surface *xsurf = ximage_surface(nsurf); 329 330 if (xsurf->client_stamp != xsurf->server_stamp || 331 (xsurf->valid_mask & attachment_mask) != attachment_mask) { 332 if (!ximage_surface_update_buffers(&xsurf->base, attachment_mask)) 333 return FALSE; 334 } 335 336 if (seq_num) 337 *seq_num = xsurf->client_stamp; 338 339 if (textures) { 340 int att; 341 for (att = 0; att < NUM_NATIVE_ATTACHMENTS; att++) { 342 if (native_attachment_mask_test(attachment_mask, att)) { 343 struct ximage_buffer *xbuf = &xsurf->buffers[att]; 344 345 textures[att] = NULL; 346 pipe_texture_reference(&textures[att], xbuf->texture); 347 } 348 } 349 } 350 351 if (width) 352 *width = xsurf->width; 353 if (height) 354 *height = xsurf->height; 355 356 return TRUE; 357} 358 359static void 360ximage_surface_wait(struct native_surface *nsurf) 361{ 362 struct ximage_surface *xsurf = ximage_surface(nsurf); 363 XSync(xsurf->xdpy->dpy, FALSE); 364 /* TODO XGetImage and update the front texture */ 365} 366 367static void 368ximage_surface_destroy(struct native_surface *nsurf) 369{ 370 struct ximage_surface *xsurf = ximage_surface(nsurf); 371 int i; 372 373 for (i = 0; i < NUM_NATIVE_ATTACHMENTS; i++) 374 ximage_surface_free_buffer(&xsurf->base, i); 375 376 if (xsurf->type != XIMAGE_SURFACE_TYPE_PBUFFER) 377 XFreeGC(xsurf->xdpy->dpy, xsurf->gc); 378 free(xsurf); 379} 380 381static struct ximage_surface * 382ximage_display_create_surface(struct native_display *ndpy, 383 enum ximage_surface_type type, 384 Drawable drawable, 385 const struct native_config *nconf) 386{ 387 struct ximage_display *xdpy = ximage_display(ndpy); 388 struct ximage_config *xconf = ximage_config(nconf); 389 struct ximage_surface *xsurf; 390 391 xsurf = CALLOC_STRUCT(ximage_surface); 392 if (!xsurf) 393 return NULL; 394 395 xsurf->xdpy = xdpy; 396 xsurf->type = type; 397 xsurf->color_format = xconf->base.color_format; 398 xsurf->drawable = drawable; 399 400 if (xsurf->type != XIMAGE_SURFACE_TYPE_PBUFFER) { 401 xsurf->drawable = drawable; 402 xsurf->visual = *xconf->visual; 403 404 xsurf->gc = XCreateGC(xdpy->dpy, xsurf->drawable, 0, NULL); 405 if (!xsurf->gc) { 406 free(xsurf); 407 return NULL; 408 } 409 410 /* initialize the geometry */ 411 ximage_surface_update_buffers(&xsurf->base, 0x0); 412 } 413 414 xsurf->base.destroy = ximage_surface_destroy; 415 xsurf->base.swap_buffers = ximage_surface_swap_buffers; 416 xsurf->base.flush_frontbuffer = ximage_surface_flush_frontbuffer; 417 xsurf->base.validate = ximage_surface_validate; 418 xsurf->base.wait = ximage_surface_wait; 419 420 return xsurf; 421} 422 423static struct native_surface * 424ximage_display_create_window_surface(struct native_display *ndpy, 425 EGLNativeWindowType win, 426 const struct native_config *nconf) 427{ 428 struct ximage_surface *xsurf; 429 430 xsurf = ximage_display_create_surface(ndpy, XIMAGE_SURFACE_TYPE_WINDOW, 431 (Drawable) win, nconf); 432 return (xsurf) ? &xsurf->base : NULL; 433} 434 435static struct native_surface * 436ximage_display_create_pixmap_surface(struct native_display *ndpy, 437 EGLNativePixmapType pix, 438 const struct native_config *nconf) 439{ 440 struct ximage_surface *xsurf; 441 442 xsurf = ximage_display_create_surface(ndpy, XIMAGE_SURFACE_TYPE_PIXMAP, 443 (Drawable) pix, nconf); 444 return (xsurf) ? &xsurf->base : NULL; 445} 446 447static struct native_surface * 448ximage_display_create_pbuffer_surface(struct native_display *ndpy, 449 const struct native_config *nconf, 450 uint width, uint height) 451{ 452 struct ximage_surface *xsurf; 453 454 xsurf = ximage_display_create_surface(ndpy, XIMAGE_SURFACE_TYPE_PBUFFER, 455 (Drawable) None, nconf); 456 if (xsurf) { 457 xsurf->width = width; 458 xsurf->height = height; 459 } 460 return (xsurf) ? &xsurf->base : NULL; 461} 462 463static enum pipe_format 464choose_format(const XVisualInfo *vinfo) 465{ 466 enum pipe_format fmt; 467 /* TODO elaborate the formats */ 468 switch (vinfo->depth) { 469 case 32: 470 fmt = PIPE_FORMAT_B8G8R8A8_UNORM; 471 break; 472 case 24: 473 fmt = PIPE_FORMAT_B8G8R8X8_UNORM; 474 break; 475 case 16: 476 fmt = PIPE_FORMAT_B5G6R5_UNORM; 477 break; 478 default: 479 fmt = PIPE_FORMAT_NONE; 480 break; 481 } 482 483 return fmt; 484} 485 486static const struct native_config ** 487ximage_display_get_configs(struct native_display *ndpy, int *num_configs) 488{ 489 struct ximage_display *xdpy = ximage_display(ndpy); 490 const struct native_config **configs; 491 int i; 492 493 /* first time */ 494 if (!xdpy->configs) { 495 const XVisualInfo *visuals; 496 int num_visuals, count, j; 497 498 visuals = x11_screen_get_visuals(xdpy->xscr, &num_visuals); 499 if (!visuals) 500 return NULL; 501 502 /* 503 * Create two configs for each visual. 504 * One with depth/stencil buffer; one without 505 */ 506 xdpy->configs = calloc(num_visuals * 2, sizeof(*xdpy->configs)); 507 if (!xdpy->configs) 508 return NULL; 509 510 count = 0; 511 for (i = 0; i < num_visuals; i++) { 512 for (j = 0; j < 2; j++) { 513 struct ximage_config *xconf = &xdpy->configs[count]; 514 __GLcontextModes *mode = &xconf->base.mode; 515 516 xconf->visual = &visuals[i]; 517 xconf->base.color_format = choose_format(xconf->visual); 518 if (xconf->base.color_format == PIPE_FORMAT_NONE) 519 continue; 520 521 x11_screen_convert_visual(xdpy->xscr, xconf->visual, mode); 522 /* support double buffer mode */ 523 mode->doubleBufferMode = TRUE; 524 525 xconf->base.depth_format = PIPE_FORMAT_NONE; 526 xconf->base.stencil_format = PIPE_FORMAT_NONE; 527 /* create the second config with depth/stencil buffer */ 528 if (j == 1) { 529 xconf->base.depth_format = PIPE_FORMAT_Z24S8_UNORM; 530 xconf->base.stencil_format = PIPE_FORMAT_Z24S8_UNORM; 531 mode->depthBits = 24; 532 mode->stencilBits = 8; 533 mode->haveDepthBuffer = TRUE; 534 mode->haveStencilBuffer = TRUE; 535 } 536 537 mode->maxPbufferWidth = 4096; 538 mode->maxPbufferHeight = 4096; 539 mode->maxPbufferPixels = 4096 * 4096; 540 mode->drawableType = 541 GLX_WINDOW_BIT | GLX_PIXMAP_BIT | GLX_PBUFFER_BIT; 542 mode->swapMethod = GLX_SWAP_EXCHANGE_OML; 543 544 if (mode->alphaBits) 545 mode->bindToTextureRgba = TRUE; 546 else 547 mode->bindToTextureRgb = TRUE; 548 549 count++; 550 } 551 } 552 553 xdpy->num_configs = count; 554 } 555 556 configs = malloc(xdpy->num_configs * sizeof(*configs)); 557 if (configs) { 558 for (i = 0; i < xdpy->num_configs; i++) 559 configs[i] = (const struct native_config *) &xdpy->configs[i]; 560 if (num_configs) 561 *num_configs = xdpy->num_configs; 562 } 563 return configs; 564} 565 566static boolean 567ximage_display_is_pixmap_supported(struct native_display *ndpy, 568 EGLNativePixmapType pix, 569 const struct native_config *nconf) 570{ 571 struct ximage_display *xdpy = ximage_display(ndpy); 572 enum pipe_format fmt; 573 uint depth; 574 575 depth = x11_drawable_get_depth(xdpy->xscr, (Drawable) pix); 576 switch (depth) { 577 case 32: 578 fmt = PIPE_FORMAT_B8G8R8A8_UNORM; 579 break; 580 case 24: 581 fmt = PIPE_FORMAT_B8G8R8X8_UNORM; 582 break; 583 case 16: 584 fmt = PIPE_FORMAT_B5G6R5_UNORM; 585 break; 586 default: 587 fmt = PIPE_FORMAT_NONE; 588 break; 589 } 590 591 return (fmt == nconf->color_format); 592} 593 594static int 595ximage_display_get_param(struct native_display *ndpy, 596 enum native_param_type param) 597{ 598 int val; 599 600 switch (param) { 601 case NATIVE_PARAM_USE_NATIVE_BUFFER: 602 /* private buffers are allocated */ 603 val = FALSE; 604 break; 605 default: 606 val = 0; 607 break; 608 } 609 610 return val; 611} 612 613static void 614ximage_display_destroy(struct native_display *ndpy) 615{ 616 struct ximage_display *xdpy = ximage_display(ndpy); 617 618 if (xdpy->configs) 619 free(xdpy->configs); 620 621 xdpy->base.screen->destroy(xdpy->base.screen); 622 623 x11_screen_destroy(xdpy->xscr); 624 if (xdpy->own_dpy) 625 XCloseDisplay(xdpy->dpy); 626 free(xdpy); 627} 628 629struct native_display * 630x11_create_ximage_display(EGLNativeDisplayType dpy) 631{ 632 struct ximage_display *xdpy; 633 634 xdpy = CALLOC_STRUCT(ximage_display); 635 if (!xdpy) 636 return NULL; 637 638 xdpy->dpy = dpy; 639 if (!xdpy->dpy) { 640 xdpy->dpy = XOpenDisplay(NULL); 641 if (!xdpy->dpy) { 642 free(xdpy); 643 return NULL; 644 } 645 xdpy->own_dpy = TRUE; 646 } 647 648 xdpy->xscr_number = DefaultScreen(xdpy->dpy); 649 xdpy->xscr = x11_screen_create(xdpy->dpy, xdpy->xscr_number); 650 if (!xdpy->xscr) { 651 free(xdpy); 652 return NULL; 653 } 654 655 xdpy->driver = xlib_sw_winsys_init(); 656 xdpy->base.screen = xdpy->driver->create_pipe_screen(xdpy->dpy); 657 658 xdpy->base.destroy = ximage_display_destroy; 659 xdpy->base.get_param = ximage_display_get_param; 660 661 xdpy->base.get_configs = ximage_display_get_configs; 662 xdpy->base.is_pixmap_supported = ximage_display_is_pixmap_supported; 663 xdpy->base.create_window_surface = ximage_display_create_window_surface; 664 xdpy->base.create_pixmap_surface = ximage_display_create_pixmap_surface; 665 xdpy->base.create_pbuffer_surface = ximage_display_create_pbuffer_surface; 666 667 return &xdpy->base; 668} 669