1 /* 2 * Mesa 3-D graphics library 3 * Version: 7.8 4 * 5 * Copyright (C) 2009-2010 Chia-I Wu <olv (at) 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 "util/u_debug.h" 35 #include "egllog.h" 36 37 #include "common/native_helper.h" 38 #include "native_x11.h" 39 #include "x11_screen.h" 40 41 struct ximage_display { 42 struct native_display base; 43 Display *dpy; 44 boolean own_dpy; 45 46 const struct native_event_handler *event_handler; 47 48 struct x11_screen *xscr; 49 int xscr_number; 50 51 struct ximage_config *configs; 52 int num_configs; 53 }; 54 55 struct ximage_surface { 56 struct native_surface base; 57 Drawable drawable; 58 enum pipe_format color_format; 59 XVisualInfo visual; 60 struct ximage_display *xdpy; 61 62 unsigned int server_stamp; 63 unsigned int client_stamp; 64 65 struct resource_surface *rsurf; 66 struct xlib_drawable xdraw; 67 }; 68 69 struct ximage_config { 70 struct native_config base; 71 const XVisualInfo *visual; 72 }; 73 74 static INLINE struct ximage_display * 75 ximage_display(const struct native_display *ndpy) 76 { 77 return (struct ximage_display *) ndpy; 78 } 79 80 static INLINE struct ximage_surface * 81 ximage_surface(const struct native_surface *nsurf) 82 { 83 return (struct ximage_surface *) nsurf; 84 } 85 86 static INLINE struct ximage_config * 87 ximage_config(const struct native_config *nconf) 88 { 89 return (struct ximage_config *) nconf; 90 } 91 92 /** 93 * Update the geometry of the surface. This is a slow functions. 94 */ 95 static void 96 ximage_surface_update_geometry(struct native_surface *nsurf) 97 { 98 struct ximage_surface *xsurf = ximage_surface(nsurf); 99 Status ok; 100 Window root; 101 int x, y; 102 unsigned int w, h, border, depth; 103 104 ok = XGetGeometry(xsurf->xdpy->dpy, xsurf->drawable, 105 &root, &x, &y, &w, &h, &border, &depth); 106 if (ok && resource_surface_set_size(xsurf->rsurf, w, h)) 107 xsurf->server_stamp++; 108 } 109 110 /** 111 * Update the buffers of the surface. 112 */ 113 static boolean 114 ximage_surface_update_buffers(struct native_surface *nsurf, uint buffer_mask) 115 { 116 struct ximage_surface *xsurf = ximage_surface(nsurf); 117 118 if (xsurf->client_stamp != xsurf->server_stamp) { 119 ximage_surface_update_geometry(&xsurf->base); 120 xsurf->client_stamp = xsurf->server_stamp; 121 } 122 123 return resource_surface_add_resources(xsurf->rsurf, buffer_mask); 124 } 125 126 /** 127 * Emulate an invalidate event. 128 */ 129 static void 130 ximage_surface_invalidate(struct native_surface *nsurf) 131 { 132 struct ximage_surface *xsurf = ximage_surface(nsurf); 133 struct ximage_display *xdpy = xsurf->xdpy; 134 135 xsurf->server_stamp++; 136 xdpy->event_handler->invalid_surface(&xdpy->base, 137 &xsurf->base, xsurf->server_stamp); 138 } 139 140 static boolean 141 ximage_surface_flush_frontbuffer(struct native_surface *nsurf) 142 { 143 struct ximage_surface *xsurf = ximage_surface(nsurf); 144 boolean ret; 145 146 ret = resource_surface_present(xsurf->rsurf, 147 NATIVE_ATTACHMENT_FRONT_LEFT, (void *) &xsurf->xdraw); 148 /* force buffers to be updated in next validation call */ 149 ximage_surface_invalidate(&xsurf->base); 150 151 return ret; 152 } 153 154 static boolean 155 ximage_surface_swap_buffers(struct native_surface *nsurf) 156 { 157 struct ximage_surface *xsurf = ximage_surface(nsurf); 158 boolean ret; 159 160 ret = resource_surface_present(xsurf->rsurf, 161 NATIVE_ATTACHMENT_BACK_LEFT, (void *) &xsurf->xdraw); 162 163 resource_surface_swap_buffers(xsurf->rsurf, 164 NATIVE_ATTACHMENT_FRONT_LEFT, NATIVE_ATTACHMENT_BACK_LEFT, TRUE); 165 /* the front/back buffers have been swapped */ 166 ximage_surface_invalidate(&xsurf->base); 167 168 return ret; 169 } 170 171 static boolean 172 ximage_surface_present(struct native_surface *nsurf, 173 const struct native_present_control *ctrl) 174 { 175 boolean ret; 176 177 if (ctrl->preserve || ctrl->swap_interval) 178 return FALSE; 179 180 switch (ctrl->natt) { 181 case NATIVE_ATTACHMENT_FRONT_LEFT: 182 ret = ximage_surface_flush_frontbuffer(nsurf); 183 break; 184 case NATIVE_ATTACHMENT_BACK_LEFT: 185 ret = ximage_surface_swap_buffers(nsurf); 186 break; 187 default: 188 ret = FALSE; 189 break; 190 } 191 192 return ret; 193 } 194 195 static boolean 196 ximage_surface_validate(struct native_surface *nsurf, uint attachment_mask, 197 unsigned int *seq_num, struct pipe_resource **textures, 198 int *width, int *height) 199 { 200 struct ximage_surface *xsurf = ximage_surface(nsurf); 201 uint w, h; 202 203 if (!ximage_surface_update_buffers(&xsurf->base, attachment_mask)) 204 return FALSE; 205 206 if (seq_num) 207 *seq_num = xsurf->client_stamp; 208 209 if (textures) 210 resource_surface_get_resources(xsurf->rsurf, textures, attachment_mask); 211 212 resource_surface_get_size(xsurf->rsurf, &w, &h); 213 if (width) 214 *width = w; 215 if (height) 216 *height = h; 217 218 return TRUE; 219 } 220 221 static void 222 ximage_surface_wait(struct native_surface *nsurf) 223 { 224 struct ximage_surface *xsurf = ximage_surface(nsurf); 225 XSync(xsurf->xdpy->dpy, FALSE); 226 /* TODO XGetImage and update the front texture */ 227 } 228 229 static void 230 ximage_surface_destroy(struct native_surface *nsurf) 231 { 232 struct ximage_surface *xsurf = ximage_surface(nsurf); 233 234 resource_surface_destroy(xsurf->rsurf); 235 FREE(xsurf); 236 } 237 238 static struct ximage_surface * 239 ximage_display_create_surface(struct native_display *ndpy, 240 Drawable drawable, 241 const struct native_config *nconf) 242 { 243 struct ximage_display *xdpy = ximage_display(ndpy); 244 struct ximage_config *xconf = ximage_config(nconf); 245 struct ximage_surface *xsurf; 246 247 xsurf = CALLOC_STRUCT(ximage_surface); 248 if (!xsurf) 249 return NULL; 250 251 xsurf->xdpy = xdpy; 252 xsurf->color_format = xconf->base.color_format; 253 xsurf->drawable = drawable; 254 255 xsurf->rsurf = resource_surface_create(xdpy->base.screen, 256 xsurf->color_format, 257 PIPE_BIND_RENDER_TARGET | 258 PIPE_BIND_SAMPLER_VIEW | 259 PIPE_BIND_DISPLAY_TARGET | 260 PIPE_BIND_SCANOUT); 261 if (!xsurf->rsurf) { 262 FREE(xsurf); 263 return NULL; 264 } 265 266 xsurf->drawable = drawable; 267 xsurf->visual = *xconf->visual; 268 /* initialize the geometry */ 269 ximage_surface_update_geometry(&xsurf->base); 270 271 xsurf->xdraw.visual = xsurf->visual.visual; 272 xsurf->xdraw.depth = xsurf->visual.depth; 273 xsurf->xdraw.drawable = xsurf->drawable; 274 275 xsurf->base.destroy = ximage_surface_destroy; 276 xsurf->base.present = ximage_surface_present; 277 xsurf->base.validate = ximage_surface_validate; 278 xsurf->base.wait = ximage_surface_wait; 279 280 return xsurf; 281 } 282 283 static struct native_surface * 284 ximage_display_create_window_surface(struct native_display *ndpy, 285 EGLNativeWindowType win, 286 const struct native_config *nconf) 287 { 288 struct ximage_surface *xsurf; 289 290 xsurf = ximage_display_create_surface(ndpy, (Drawable) win, nconf); 291 return (xsurf) ? &xsurf->base : NULL; 292 } 293 294 static enum pipe_format 295 get_pixmap_format(struct native_display *ndpy, EGLNativePixmapType pix) 296 { 297 struct ximage_display *xdpy = ximage_display(ndpy); 298 enum pipe_format fmt; 299 uint depth; 300 301 depth = x11_drawable_get_depth(xdpy->xscr, (Drawable) pix); 302 303 switch (depth) { 304 case 32: 305 fmt = PIPE_FORMAT_B8G8R8A8_UNORM; 306 break; 307 case 24: 308 fmt = PIPE_FORMAT_B8G8R8X8_UNORM; 309 break; 310 case 16: 311 fmt = PIPE_FORMAT_B5G6R5_UNORM; 312 break; 313 default: 314 fmt = PIPE_FORMAT_NONE; 315 break; 316 } 317 318 return fmt; 319 } 320 321 static struct native_surface * 322 ximage_display_create_pixmap_surface(struct native_display *ndpy, 323 EGLNativePixmapType pix, 324 const struct native_config *nconf) 325 { 326 struct ximage_surface *xsurf; 327 328 /* find the config */ 329 if (!nconf) { 330 struct ximage_display *xdpy = ximage_display(ndpy); 331 enum pipe_format fmt = get_pixmap_format(&xdpy->base, pix); 332 int i; 333 334 if (fmt != PIPE_FORMAT_NONE) { 335 for (i = 0; i < xdpy->num_configs; i++) { 336 if (xdpy->configs[i].base.color_format == fmt) { 337 nconf = &xdpy->configs[i].base; 338 break; 339 } 340 } 341 } 342 343 if (!nconf) 344 return NULL; 345 } 346 347 xsurf = ximage_display_create_surface(ndpy, (Drawable) pix, nconf); 348 return (xsurf) ? &xsurf->base : NULL; 349 } 350 351 static enum pipe_format 352 choose_format(const XVisualInfo *vinfo) 353 { 354 enum pipe_format fmt; 355 /* TODO elaborate the formats */ 356 switch (vinfo->depth) { 357 case 32: 358 fmt = PIPE_FORMAT_B8G8R8A8_UNORM; 359 break; 360 case 24: 361 fmt = PIPE_FORMAT_B8G8R8X8_UNORM; 362 break; 363 case 16: 364 fmt = PIPE_FORMAT_B5G6R5_UNORM; 365 break; 366 default: 367 fmt = PIPE_FORMAT_NONE; 368 break; 369 } 370 371 return fmt; 372 } 373 374 static const struct native_config ** 375 ximage_display_get_configs(struct native_display *ndpy, int *num_configs) 376 { 377 struct ximage_display *xdpy = ximage_display(ndpy); 378 const struct native_config **configs; 379 int i; 380 381 /* first time */ 382 if (!xdpy->configs) { 383 const XVisualInfo *visuals; 384 int num_visuals, count; 385 386 visuals = x11_screen_get_visuals(xdpy->xscr, &num_visuals); 387 if (!visuals) 388 return NULL; 389 390 /* 391 * Create two configs for each visual. 392 * One with depth/stencil buffer; one without 393 */ 394 xdpy->configs = CALLOC(num_visuals * 2, sizeof(*xdpy->configs)); 395 if (!xdpy->configs) 396 return NULL; 397 398 count = 0; 399 for (i = 0; i < num_visuals; i++) { 400 struct ximage_config *xconf = &xdpy->configs[count]; 401 402 xconf->visual = &visuals[i]; 403 xconf->base.color_format = choose_format(xconf->visual); 404 if (xconf->base.color_format == PIPE_FORMAT_NONE) 405 continue; 406 407 xconf->base.buffer_mask = 408 (1 << NATIVE_ATTACHMENT_FRONT_LEFT) | 409 (1 << NATIVE_ATTACHMENT_BACK_LEFT); 410 411 xconf->base.window_bit = TRUE; 412 xconf->base.pixmap_bit = TRUE; 413 414 xconf->base.native_visual_id = xconf->visual->visualid; 415 #if defined(__cplusplus) || defined(c_plusplus) 416 xconf->base.native_visual_type = xconf->visual->c_class; 417 #else 418 xconf->base.native_visual_type = xconf->visual->class; 419 #endif 420 421 count++; 422 } 423 424 xdpy->num_configs = count; 425 } 426 427 configs = MALLOC(xdpy->num_configs * sizeof(*configs)); 428 if (configs) { 429 for (i = 0; i < xdpy->num_configs; i++) 430 configs[i] = (const struct native_config *) &xdpy->configs[i]; 431 if (num_configs) 432 *num_configs = xdpy->num_configs; 433 } 434 return configs; 435 } 436 437 static boolean 438 ximage_display_get_pixmap_format(struct native_display *ndpy, 439 EGLNativePixmapType pix, 440 enum pipe_format *format) 441 { 442 struct ximage_display *xdpy = ximage_display(ndpy); 443 444 *format = get_pixmap_format(&xdpy->base, pix); 445 446 return (*format != PIPE_FORMAT_NONE); 447 } 448 449 static boolean 450 ximage_display_copy_to_pixmap(struct native_display *ndpy, 451 EGLNativePixmapType pix, 452 struct pipe_resource *src) 453 { 454 /* fast path to avoid unnecessary allocation and resource_copy_region */ 455 if (src->bind & PIPE_BIND_DISPLAY_TARGET) { 456 struct ximage_display *xdpy = ximage_display(ndpy); 457 enum pipe_format fmt = get_pixmap_format(&xdpy->base, pix); 458 const struct ximage_config *xconf = NULL; 459 struct xlib_drawable xdraw; 460 int i; 461 462 if (fmt == PIPE_FORMAT_NONE || src->format != fmt) 463 return FALSE; 464 465 for (i = 0; i < xdpy->num_configs; i++) { 466 if (xdpy->configs[i].base.color_format == fmt) { 467 xconf = &xdpy->configs[i]; 468 break; 469 } 470 } 471 if (!xconf) 472 return FALSE; 473 474 memset(&xdraw, 0, sizeof(xdraw)); 475 xdraw.visual = xconf->visual->visual; 476 xdraw.depth = xconf->visual->depth; 477 xdraw.drawable = (Drawable) pix; 478 479 xdpy->base.screen->flush_frontbuffer(xdpy->base.screen, 480 src, 0, 0, &xdraw); 481 482 return TRUE; 483 } 484 485 return native_display_copy_to_pixmap(ndpy, pix, src); 486 } 487 488 static int 489 ximage_display_get_param(struct native_display *ndpy, 490 enum native_param_type param) 491 { 492 int val; 493 494 switch (param) { 495 case NATIVE_PARAM_USE_NATIVE_BUFFER: 496 /* private buffers are allocated */ 497 val = FALSE; 498 break; 499 case NATIVE_PARAM_PRESERVE_BUFFER: 500 case NATIVE_PARAM_MAX_SWAP_INTERVAL: 501 default: 502 val = 0; 503 break; 504 } 505 506 return val; 507 } 508 509 static void 510 ximage_display_destroy(struct native_display *ndpy) 511 { 512 struct ximage_display *xdpy = ximage_display(ndpy); 513 514 if (xdpy->configs) 515 FREE(xdpy->configs); 516 517 ndpy_uninit(ndpy); 518 519 x11_screen_destroy(xdpy->xscr); 520 if (xdpy->own_dpy) 521 XCloseDisplay(xdpy->dpy); 522 FREE(xdpy); 523 } 524 525 static boolean 526 ximage_display_init_screen(struct native_display *ndpy) 527 { 528 struct ximage_display *xdpy = ximage_display(ndpy); 529 struct sw_winsys *winsys; 530 531 winsys = xlib_create_sw_winsys(xdpy->dpy); 532 if (!winsys) 533 return FALSE; 534 535 xdpy->base.screen = 536 xdpy->event_handler->new_sw_screen(&xdpy->base, winsys); 537 if (!xdpy->base.screen) { 538 if (winsys->destroy) 539 winsys->destroy(winsys); 540 return FALSE; 541 } 542 543 return TRUE; 544 } 545 546 struct native_display * 547 x11_create_ximage_display(Display *dpy, 548 const struct native_event_handler *event_handler) 549 { 550 struct ximage_display *xdpy; 551 552 xdpy = CALLOC_STRUCT(ximage_display); 553 if (!xdpy) 554 return NULL; 555 556 xdpy->dpy = dpy; 557 if (!xdpy->dpy) { 558 xdpy->dpy = XOpenDisplay(NULL); 559 if (!xdpy->dpy) { 560 FREE(xdpy); 561 return NULL; 562 } 563 xdpy->own_dpy = TRUE; 564 } 565 566 xdpy->event_handler = event_handler; 567 568 xdpy->xscr_number = DefaultScreen(xdpy->dpy); 569 xdpy->xscr = x11_screen_create(xdpy->dpy, xdpy->xscr_number); 570 if (!xdpy->xscr) { 571 if (xdpy->own_dpy) 572 XCloseDisplay(xdpy->dpy); 573 FREE(xdpy); 574 return NULL; 575 } 576 577 xdpy->base.init_screen = ximage_display_init_screen; 578 xdpy->base.destroy = ximage_display_destroy; 579 xdpy->base.get_param = ximage_display_get_param; 580 581 xdpy->base.get_configs = ximage_display_get_configs; 582 xdpy->base.get_pixmap_format = ximage_display_get_pixmap_format; 583 xdpy->base.copy_to_pixmap = ximage_display_copy_to_pixmap; 584 xdpy->base.create_window_surface = ximage_display_create_window_surface; 585 xdpy->base.create_pixmap_surface = ximage_display_create_pixmap_surface; 586 587 return &xdpy->base; 588 } 589