native_dri2.c revision ba81b0743efd978509b1931d7b4b93f37e8aeb5e
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 "util/u_memory.h" 27#include "util/u_math.h" 28#include "util/u_format.h" 29#include "util/u_inlines.h" 30#include "util/u_hash_table.h" 31#include "pipe/p_compiler.h" 32#include "pipe/p_screen.h" 33#include "pipe/p_context.h" 34#include "pipe/p_state.h" 35#include "state_tracker/drm_api.h" 36#include "egllog.h" 37 38#include "native_x11.h" 39#include "x11_screen.h" 40 41enum dri2_surface_type { 42 DRI2_SURFACE_TYPE_WINDOW, 43 DRI2_SURFACE_TYPE_PIXMAP, 44}; 45 46struct dri2_display { 47 struct native_display base; 48 Display *dpy; 49 boolean own_dpy; 50 51 struct native_event_handler *event_handler; 52 53 struct drm_api *api; 54 struct x11_screen *xscr; 55 int xscr_number; 56 const char *dri_driver; 57 int dri_major, dri_minor; 58 59 struct dri2_config *configs; 60 int num_configs; 61 62 struct util_hash_table *surfaces; 63}; 64 65struct dri2_surface { 66 struct native_surface base; 67 Drawable drawable; 68 enum dri2_surface_type type; 69 enum pipe_format color_format; 70 struct dri2_display *dri2dpy; 71 72 unsigned int server_stamp; 73 unsigned int client_stamp; 74 int width, height; 75 struct pipe_texture *textures[NUM_NATIVE_ATTACHMENTS]; 76 uint valid_mask; 77 78 boolean have_back, have_fake; 79 80 struct x11_drawable_buffer *last_xbufs; 81 int last_num_xbufs; 82}; 83 84struct dri2_config { 85 struct native_config base; 86}; 87 88static INLINE struct dri2_display * 89dri2_display(const struct native_display *ndpy) 90{ 91 return (struct dri2_display *) ndpy; 92} 93 94static INLINE struct dri2_surface * 95dri2_surface(const struct native_surface *nsurf) 96{ 97 return (struct dri2_surface *) nsurf; 98} 99 100static INLINE struct dri2_config * 101dri2_config(const struct native_config *nconf) 102{ 103 return (struct dri2_config *) nconf; 104} 105 106/** 107 * Process the buffers returned by the server. 108 */ 109static void 110dri2_surface_process_drawable_buffers(struct native_surface *nsurf, 111 struct x11_drawable_buffer *xbufs, 112 int num_xbufs) 113{ 114 struct dri2_surface *dri2surf = dri2_surface(nsurf); 115 struct dri2_display *dri2dpy = dri2surf->dri2dpy; 116 struct pipe_texture templ; 117 struct winsys_handle whandle; 118 uint valid_mask; 119 int i; 120 121 /* free the old textures */ 122 for (i = 0; i < NUM_NATIVE_ATTACHMENTS; i++) 123 pipe_texture_reference(&dri2surf->textures[i], NULL); 124 dri2surf->valid_mask = 0x0; 125 126 dri2surf->have_back = FALSE; 127 dri2surf->have_fake = FALSE; 128 129 if (!xbufs) 130 return; 131 132 memset(&templ, 0, sizeof(templ)); 133 templ.target = PIPE_TEXTURE_2D; 134 templ.last_level = 0; 135 templ.width0 = dri2surf->width; 136 templ.height0 = dri2surf->height; 137 templ.depth0 = 1; 138 templ.format = dri2surf->color_format; 139 templ.tex_usage = PIPE_TEXTURE_USAGE_RENDER_TARGET; 140 141 valid_mask = 0x0; 142 for (i = 0; i < num_xbufs; i++) { 143 struct x11_drawable_buffer *xbuf = &xbufs[i]; 144 const char *desc; 145 enum native_attachment natt; 146 147 switch (xbuf->attachment) { 148 case DRI2BufferFrontLeft: 149 natt = NATIVE_ATTACHMENT_FRONT_LEFT; 150 desc = "DRI2 Front Buffer"; 151 break; 152 case DRI2BufferFakeFrontLeft: 153 natt = NATIVE_ATTACHMENT_FRONT_LEFT; 154 desc = "DRI2 Fake Front Buffer"; 155 dri2surf->have_fake = TRUE; 156 break; 157 case DRI2BufferBackLeft: 158 natt = NATIVE_ATTACHMENT_BACK_LEFT; 159 desc = "DRI2 Back Buffer"; 160 dri2surf->have_back = TRUE; 161 break; 162 default: 163 desc = NULL; 164 break; 165 } 166 167 if (!desc || dri2surf->textures[natt]) { 168 if (!desc) 169 _eglLog(_EGL_WARNING, "unknown buffer %d", xbuf->attachment); 170 else 171 _eglLog(_EGL_WARNING, "both real and fake front buffers are listed"); 172 continue; 173 } 174 175 memset(&whandle, 0, sizeof(whandle)); 176 whandle.stride = xbuf->pitch; 177 whandle.handle = xbuf->name; 178 dri2surf->textures[natt] = dri2dpy->base.screen->texture_from_handle( 179 dri2dpy->base.screen, &templ, &whandle); 180 if (dri2surf->textures[natt]) 181 valid_mask |= 1 << natt; 182 } 183 184 dri2surf->valid_mask = valid_mask; 185} 186 187/** 188 * Get the buffers from the server. 189 */ 190static void 191dri2_surface_get_buffers(struct native_surface *nsurf, uint buffer_mask) 192{ 193 struct dri2_surface *dri2surf = dri2_surface(nsurf); 194 struct dri2_display *dri2dpy = dri2surf->dri2dpy; 195 unsigned int dri2atts[NUM_NATIVE_ATTACHMENTS]; 196 int num_ins, num_outs, att; 197 struct x11_drawable_buffer *xbufs; 198 199 /* prepare the attachments */ 200 num_ins = 0; 201 for (att = 0; att < NUM_NATIVE_ATTACHMENTS; att++) { 202 if (native_attachment_mask_test(buffer_mask, att)) { 203 unsigned int dri2att; 204 205 switch (att) { 206 case NATIVE_ATTACHMENT_FRONT_LEFT: 207 dri2att = DRI2BufferFrontLeft; 208 break; 209 case NATIVE_ATTACHMENT_BACK_LEFT: 210 dri2att = DRI2BufferBackLeft; 211 break; 212 case NATIVE_ATTACHMENT_FRONT_RIGHT: 213 dri2att = DRI2BufferFrontRight; 214 break; 215 case NATIVE_ATTACHMENT_BACK_RIGHT: 216 dri2att = DRI2BufferBackRight; 217 break; 218 default: 219 assert(0); 220 dri2att = 0; 221 break; 222 } 223 224 dri2atts[num_ins] = dri2att; 225 num_ins++; 226 } 227 } 228 229 xbufs = x11_drawable_get_buffers(dri2dpy->xscr, dri2surf->drawable, 230 &dri2surf->width, &dri2surf->height, 231 dri2atts, FALSE, num_ins, &num_outs); 232 233 /* we should be able to do better... */ 234 if (xbufs && dri2surf->last_num_xbufs == num_outs && 235 memcmp(dri2surf->last_xbufs, xbufs, sizeof(*xbufs) * num_outs) == 0) { 236 free(xbufs); 237 dri2surf->client_stamp = dri2surf->server_stamp; 238 return; 239 } 240 241 dri2_surface_process_drawable_buffers(&dri2surf->base, xbufs, num_outs); 242 243 dri2surf->server_stamp++; 244 dri2surf->client_stamp = dri2surf->server_stamp; 245 246 if (dri2surf->last_xbufs) 247 free(dri2surf->last_xbufs); 248 dri2surf->last_xbufs = xbufs; 249 dri2surf->last_num_xbufs = num_outs; 250} 251 252/** 253 * Update the buffers of the surface. This is a slow function due to the 254 * round-trip to the server. 255 */ 256static boolean 257dri2_surface_update_buffers(struct native_surface *nsurf, uint buffer_mask) 258{ 259 struct dri2_surface *dri2surf = dri2_surface(nsurf); 260 261 dri2_surface_get_buffers(&dri2surf->base, buffer_mask); 262 263 return ((dri2surf->valid_mask & buffer_mask) == buffer_mask); 264} 265 266/** 267 * Return TRUE if the surface receives DRI2_InvalidateBuffers events. 268 */ 269static INLINE boolean 270dri2_surface_receive_events(struct native_surface *nsurf) 271{ 272 struct dri2_surface *dri2surf = dri2_surface(nsurf); 273 return (dri2surf->dri2dpy->dri_minor >= 3); 274} 275 276static boolean 277dri2_surface_flush_frontbuffer(struct native_surface *nsurf) 278{ 279 struct dri2_surface *dri2surf = dri2_surface(nsurf); 280 struct dri2_display *dri2dpy = dri2surf->dri2dpy; 281 282 /* copy to real front buffer */ 283 if (dri2surf->have_fake) 284 x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable, 285 0, 0, dri2surf->width, dri2surf->height, 286 DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft); 287 288 /* force buffers to be updated in next validation call */ 289 if (!dri2_surface_receive_events(&dri2surf->base)) { 290 dri2surf->server_stamp++; 291 dri2dpy->event_handler->invalid_surface(&dri2dpy->base, 292 &dri2surf->base, dri2surf->server_stamp); 293 } 294 295 return TRUE; 296} 297 298static boolean 299dri2_surface_swap_buffers(struct native_surface *nsurf) 300{ 301 struct dri2_surface *dri2surf = dri2_surface(nsurf); 302 struct dri2_display *dri2dpy = dri2surf->dri2dpy; 303 304 /* copy to front buffer */ 305 if (dri2surf->have_back) 306 x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable, 307 0, 0, dri2surf->width, dri2surf->height, 308 DRI2BufferBackLeft, DRI2BufferFrontLeft); 309 310 /* and update fake front buffer */ 311 if (dri2surf->have_fake) 312 x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable, 313 0, 0, dri2surf->width, dri2surf->height, 314 DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft); 315 316 /* force buffers to be updated in next validation call */ 317 if (!dri2_surface_receive_events(&dri2surf->base)) { 318 dri2surf->server_stamp++; 319 dri2dpy->event_handler->invalid_surface(&dri2dpy->base, 320 &dri2surf->base, dri2surf->server_stamp); 321 } 322 323 return TRUE; 324} 325 326static boolean 327dri2_surface_validate(struct native_surface *nsurf, uint attachment_mask, 328 unsigned int *seq_num, struct pipe_texture **textures, 329 int *width, int *height) 330{ 331 struct dri2_surface *dri2surf = dri2_surface(nsurf); 332 333 if (dri2surf->server_stamp != dri2surf->client_stamp || 334 (dri2surf->valid_mask & attachment_mask) != attachment_mask) { 335 if (!dri2_surface_update_buffers(&dri2surf->base, attachment_mask)) 336 return FALSE; 337 } 338 339 if (seq_num) 340 *seq_num = dri2surf->client_stamp; 341 342 if (textures) { 343 int att; 344 for (att = 0; att < NUM_NATIVE_ATTACHMENTS; att++) { 345 if (native_attachment_mask_test(attachment_mask, att)) { 346 struct pipe_texture *ptex = dri2surf->textures[att]; 347 348 textures[att] = NULL; 349 pipe_texture_reference(&textures[att], ptex); 350 } 351 } 352 } 353 354 if (width) 355 *width = dri2surf->width; 356 if (height) 357 *height = dri2surf->height; 358 359 return TRUE; 360} 361 362static void 363dri2_surface_wait(struct native_surface *nsurf) 364{ 365 struct dri2_surface *dri2surf = dri2_surface(nsurf); 366 struct dri2_display *dri2dpy = dri2surf->dri2dpy; 367 368 if (dri2surf->have_fake) { 369 x11_drawable_copy_buffers(dri2dpy->xscr, dri2surf->drawable, 370 0, 0, dri2surf->width, dri2surf->height, 371 DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft); 372 } 373} 374 375static void 376dri2_surface_destroy(struct native_surface *nsurf) 377{ 378 struct dri2_surface *dri2surf = dri2_surface(nsurf); 379 int i; 380 381 if (dri2surf->last_xbufs) 382 free(dri2surf->last_xbufs); 383 384 for (i = 0; i < NUM_NATIVE_ATTACHMENTS; i++) { 385 struct pipe_texture *ptex = dri2surf->textures[i]; 386 pipe_texture_reference(&ptex, NULL); 387 } 388 389 if (dri2surf->drawable) { 390 x11_drawable_enable_dri2(dri2surf->dri2dpy->xscr, 391 dri2surf->drawable, FALSE); 392 393 util_hash_table_remove(dri2surf->dri2dpy->surfaces, 394 (void *) dri2surf->drawable); 395 } 396 free(dri2surf); 397} 398 399static struct dri2_surface * 400dri2_display_create_surface(struct native_display *ndpy, 401 enum dri2_surface_type type, 402 Drawable drawable, 403 const struct native_config *nconf) 404{ 405 struct dri2_display *dri2dpy = dri2_display(ndpy); 406 struct dri2_config *dri2conf = dri2_config(nconf); 407 struct dri2_surface *dri2surf; 408 409 dri2surf = CALLOC_STRUCT(dri2_surface); 410 if (!dri2surf) 411 return NULL; 412 413 dri2surf->dri2dpy = dri2dpy; 414 dri2surf->type = type; 415 dri2surf->drawable = drawable; 416 dri2surf->color_format = dri2conf->base.color_format; 417 418 dri2surf->base.destroy = dri2_surface_destroy; 419 dri2surf->base.swap_buffers = dri2_surface_swap_buffers; 420 dri2surf->base.flush_frontbuffer = dri2_surface_flush_frontbuffer; 421 dri2surf->base.validate = dri2_surface_validate; 422 dri2surf->base.wait = dri2_surface_wait; 423 424 if (drawable) { 425 x11_drawable_enable_dri2(dri2dpy->xscr, drawable, TRUE); 426 /* initialize the geometry */ 427 dri2_surface_update_buffers(&dri2surf->base, 0x0); 428 429 util_hash_table_set(dri2surf->dri2dpy->surfaces, 430 (void *) dri2surf->drawable, (void *) &dri2surf->base); 431 } 432 433 return dri2surf; 434} 435 436static struct native_surface * 437dri2_display_create_window_surface(struct native_display *ndpy, 438 EGLNativeWindowType win, 439 const struct native_config *nconf) 440{ 441 struct dri2_surface *dri2surf; 442 443 dri2surf = dri2_display_create_surface(ndpy, DRI2_SURFACE_TYPE_WINDOW, 444 (Drawable) win, nconf); 445 return (dri2surf) ? &dri2surf->base : NULL; 446} 447 448static struct native_surface * 449dri2_display_create_pixmap_surface(struct native_display *ndpy, 450 EGLNativePixmapType pix, 451 const struct native_config *nconf) 452{ 453 struct dri2_surface *dri2surf; 454 455 dri2surf = dri2_display_create_surface(ndpy, DRI2_SURFACE_TYPE_PIXMAP, 456 (Drawable) pix, nconf); 457 return (dri2surf) ? &dri2surf->base : NULL; 458} 459 460static int 461choose_color_format(const __GLcontextModes *mode, enum pipe_format formats[32]) 462{ 463 int count = 0; 464 465 switch (mode->rgbBits) { 466 case 32: 467 formats[count++] = PIPE_FORMAT_B8G8R8A8_UNORM; 468 formats[count++] = PIPE_FORMAT_A8R8G8B8_UNORM; 469 break; 470 case 24: 471 formats[count++] = PIPE_FORMAT_B8G8R8X8_UNORM; 472 formats[count++] = PIPE_FORMAT_X8R8G8B8_UNORM; 473 formats[count++] = PIPE_FORMAT_B8G8R8A8_UNORM; 474 formats[count++] = PIPE_FORMAT_A8R8G8B8_UNORM; 475 break; 476 case 16: 477 formats[count++] = PIPE_FORMAT_B5G6R5_UNORM; 478 break; 479 default: 480 break; 481 } 482 483 return count; 484} 485 486static int 487choose_depth_stencil_format(const __GLcontextModes *mode, 488 enum pipe_format formats[32]) 489{ 490 int count = 0; 491 492 switch (mode->depthBits) { 493 case 32: 494 formats[count++] = PIPE_FORMAT_Z32_UNORM; 495 break; 496 case 24: 497 if (mode->stencilBits) { 498 formats[count++] = PIPE_FORMAT_Z24_UNORM_S8_USCALED; 499 formats[count++] = PIPE_FORMAT_S8_USCALED_Z24_UNORM; 500 } 501 else { 502 formats[count++] = PIPE_FORMAT_Z24X8_UNORM; 503 formats[count++] = PIPE_FORMAT_X8Z24_UNORM; 504 } 505 break; 506 case 16: 507 formats[count++] = PIPE_FORMAT_Z16_UNORM; 508 break; 509 default: 510 break; 511 } 512 513 return count; 514} 515 516static boolean 517is_format_supported(struct pipe_screen *screen, 518 enum pipe_format fmt, boolean is_color) 519{ 520 return screen->is_format_supported(screen, fmt, PIPE_TEXTURE_2D, 521 (is_color) ? PIPE_TEXTURE_USAGE_RENDER_TARGET : 522 PIPE_TEXTURE_USAGE_DEPTH_STENCIL, 0); 523} 524 525static boolean 526dri2_display_convert_config(struct native_display *ndpy, 527 const __GLcontextModes *mode, 528 struct native_config *nconf) 529{ 530 enum pipe_format formats[32]; 531 int num_formats, i; 532 533 if (!(mode->renderType & GLX_RGBA_BIT) || !mode->rgbMode) 534 return FALSE; 535 536 /* skip single-buffered configs */ 537 if (!mode->doubleBufferMode) 538 return FALSE; 539 540 nconf->mode = *mode; 541 nconf->mode.renderType = GLX_RGBA_BIT; 542 nconf->mode.rgbMode = TRUE; 543 /* pbuffer is always supported */ 544 nconf->mode.drawableType |= GLX_PBUFFER_BIT; 545 /* the swap method is always copy */ 546 nconf->mode.swapMethod = GLX_SWAP_COPY_OML; 547 548 /* fix up */ 549 nconf->mode.rgbBits = 550 nconf->mode.redBits + nconf->mode.greenBits + 551 nconf->mode.blueBits + nconf->mode.alphaBits; 552 if (!(nconf->mode.drawableType & GLX_WINDOW_BIT)) { 553 nconf->mode.visualID = 0; 554 nconf->mode.visualType = GLX_NONE; 555 } 556 if (!(nconf->mode.drawableType & GLX_PBUFFER_BIT)) { 557 nconf->mode.bindToTextureRgb = FALSE; 558 nconf->mode.bindToTextureRgba = FALSE; 559 } 560 561 nconf->color_format = PIPE_FORMAT_NONE; 562 nconf->depth_format = PIPE_FORMAT_NONE; 563 nconf->stencil_format = PIPE_FORMAT_NONE; 564 565 /* choose color format */ 566 num_formats = choose_color_format(mode, formats); 567 for (i = 0; i < num_formats; i++) { 568 if (is_format_supported(ndpy->screen, formats[i], TRUE)) { 569 nconf->color_format = formats[i]; 570 break; 571 } 572 } 573 if (nconf->color_format == PIPE_FORMAT_NONE) 574 return FALSE; 575 576 /* choose depth/stencil format */ 577 num_formats = choose_depth_stencil_format(mode, formats); 578 for (i = 0; i < num_formats; i++) { 579 if (is_format_supported(ndpy->screen, formats[i], FALSE)) { 580 nconf->depth_format = formats[i]; 581 nconf->stencil_format = formats[i]; 582 break; 583 } 584 } 585 if ((nconf->mode.depthBits && nconf->depth_format == PIPE_FORMAT_NONE) || 586 (nconf->mode.stencilBits && nconf->stencil_format == PIPE_FORMAT_NONE)) 587 return FALSE; 588 589 return TRUE; 590} 591 592static const struct native_config ** 593dri2_display_get_configs(struct native_display *ndpy, int *num_configs) 594{ 595 struct dri2_display *dri2dpy = dri2_display(ndpy); 596 const struct native_config **configs; 597 int i; 598 599 /* first time */ 600 if (!dri2dpy->configs) { 601 const __GLcontextModes *modes; 602 int num_modes, count; 603 604 modes = x11_screen_get_glx_configs(dri2dpy->xscr); 605 if (!modes) 606 return NULL; 607 num_modes = x11_context_modes_count(modes); 608 609 dri2dpy->configs = calloc(num_modes, sizeof(*dri2dpy->configs)); 610 if (!dri2dpy->configs) 611 return NULL; 612 613 count = 0; 614 for (i = 0; i < num_modes; i++) { 615 struct native_config *nconf = &dri2dpy->configs[count].base; 616 if (dri2_display_convert_config(&dri2dpy->base, modes, nconf)) 617 count++; 618 modes = modes->next; 619 } 620 621 dri2dpy->num_configs = count; 622 } 623 624 configs = malloc(dri2dpy->num_configs * sizeof(*configs)); 625 if (configs) { 626 for (i = 0; i < dri2dpy->num_configs; i++) 627 configs[i] = (const struct native_config *) &dri2dpy->configs[i]; 628 if (num_configs) 629 *num_configs = dri2dpy->num_configs; 630 } 631 632 return configs; 633} 634 635static boolean 636dri2_display_is_pixmap_supported(struct native_display *ndpy, 637 EGLNativePixmapType pix, 638 const struct native_config *nconf) 639{ 640 struct dri2_display *dri2dpy = dri2_display(ndpy); 641 uint depth, nconf_depth; 642 643 depth = x11_drawable_get_depth(dri2dpy->xscr, (Drawable) pix); 644 nconf_depth = util_format_get_blocksizebits(nconf->color_format); 645 646 /* simple depth match for now */ 647 return (depth == nconf_depth || (depth == 24 && depth + 8 == nconf_depth)); 648} 649 650static int 651dri2_display_get_param(struct native_display *ndpy, 652 enum native_param_type param) 653{ 654 int val; 655 656 switch (param) { 657 case NATIVE_PARAM_USE_NATIVE_BUFFER: 658 /* DRI2GetBuffers use the native buffers */ 659 val = TRUE; 660 break; 661 default: 662 val = 0; 663 break; 664 } 665 666 return val; 667} 668 669static void 670dri2_display_destroy(struct native_display *ndpy) 671{ 672 struct dri2_display *dri2dpy = dri2_display(ndpy); 673 674 if (dri2dpy->configs) 675 free(dri2dpy->configs); 676 677 if (dri2dpy->base.screen) 678 dri2dpy->base.screen->destroy(dri2dpy->base.screen); 679 680 if (dri2dpy->surfaces) 681 util_hash_table_destroy(dri2dpy->surfaces); 682 683 if (dri2dpy->xscr) 684 x11_screen_destroy(dri2dpy->xscr); 685 if (dri2dpy->own_dpy) 686 XCloseDisplay(dri2dpy->dpy); 687 if (dri2dpy->api && dri2dpy->api->destroy) 688 dri2dpy->api->destroy(dri2dpy->api); 689 free(dri2dpy); 690} 691 692static void 693dri2_display_invalidate_buffers(struct x11_screen *xscr, Drawable drawable, 694 void *user_data) 695{ 696 struct native_display *ndpy = (struct native_display* ) user_data; 697 struct dri2_display *dri2dpy = dri2_display(ndpy); 698 struct native_surface *nsurf; 699 struct dri2_surface *dri2surf; 700 701 nsurf = (struct native_surface *) 702 util_hash_table_get(dri2dpy->surfaces, (void *) drawable); 703 if (!nsurf) 704 return; 705 706 dri2surf = dri2_surface(nsurf); 707 708 dri2surf->server_stamp++; 709 dri2dpy->event_handler->invalid_surface(&dri2dpy->base, 710 &dri2surf->base, dri2surf->server_stamp); 711} 712 713/** 714 * Initialize DRI2 and pipe screen. 715 */ 716static boolean 717dri2_display_init_screen(struct native_display *ndpy) 718{ 719 struct dri2_display *dri2dpy = dri2_display(ndpy); 720 const char *driver = dri2dpy->api->name; 721 struct drm_create_screen_arg arg; 722 int fd; 723 724 if (!x11_screen_support(dri2dpy->xscr, X11_SCREEN_EXTENSION_DRI2) || 725 !x11_screen_support(dri2dpy->xscr, X11_SCREEN_EXTENSION_GLX)) { 726 _eglLog(_EGL_WARNING, "GLX/DRI2 is not supported"); 727 return FALSE; 728 } 729 730 dri2dpy->dri_driver = x11_screen_probe_dri2(dri2dpy->xscr, 731 &dri2dpy->dri_major, &dri2dpy->dri_minor); 732 if (!dri2dpy->dri_driver || !driver || 733 strcmp(dri2dpy->dri_driver, driver) != 0) { 734 _eglLog(_EGL_WARNING, "Driver mismatch: %s != %s", 735 dri2dpy->dri_driver, dri2dpy->api->name); 736 return FALSE; 737 } 738 739 fd = x11_screen_enable_dri2(dri2dpy->xscr, 740 dri2_display_invalidate_buffers, &dri2dpy->base); 741 if (fd < 0) 742 return FALSE; 743 744 memset(&arg, 0, sizeof(arg)); 745 arg.mode = DRM_CREATE_NORMAL; 746 dri2dpy->base.screen = dri2dpy->api->create_screen(dri2dpy->api, fd, &arg); 747 if (!dri2dpy->base.screen) { 748 _eglLog(_EGL_WARNING, "failed to create DRM screen"); 749 return FALSE; 750 } 751 752 return TRUE; 753} 754 755static unsigned 756dri2_display_hash_table_hash(void *key) 757{ 758 XID drawable = pointer_to_uintptr(key); 759 return (unsigned) drawable; 760} 761 762static int 763dri2_display_hash_table_compare(void *key1, void *key2) 764{ 765 return (key1 - key2); 766} 767 768struct native_display * 769x11_create_dri2_display(EGLNativeDisplayType dpy, 770 struct native_event_handler *event_handler, 771 struct drm_api *api) 772{ 773 struct dri2_display *dri2dpy; 774 775 dri2dpy = CALLOC_STRUCT(dri2_display); 776 if (!dri2dpy) 777 return NULL; 778 779 dri2dpy->event_handler = event_handler; 780 dri2dpy->api = api; 781 782 dri2dpy->dpy = dpy; 783 if (!dri2dpy->dpy) { 784 dri2dpy->dpy = XOpenDisplay(NULL); 785 if (!dri2dpy->dpy) { 786 dri2_display_destroy(&dri2dpy->base); 787 return NULL; 788 } 789 dri2dpy->own_dpy = TRUE; 790 } 791 792 dri2dpy->xscr_number = DefaultScreen(dri2dpy->dpy); 793 dri2dpy->xscr = x11_screen_create(dri2dpy->dpy, dri2dpy->xscr_number); 794 if (!dri2dpy->xscr) { 795 dri2_display_destroy(&dri2dpy->base); 796 return NULL; 797 } 798 799 if (!dri2_display_init_screen(&dri2dpy->base)) { 800 dri2_display_destroy(&dri2dpy->base); 801 return NULL; 802 } 803 804 dri2dpy->surfaces = util_hash_table_create(dri2_display_hash_table_hash, 805 dri2_display_hash_table_compare); 806 if (!dri2dpy->surfaces) { 807 dri2_display_destroy(&dri2dpy->base); 808 return NULL; 809 } 810 811 dri2dpy->base.destroy = dri2_display_destroy; 812 dri2dpy->base.get_param = dri2_display_get_param; 813 dri2dpy->base.get_configs = dri2_display_get_configs; 814 dri2dpy->base.is_pixmap_supported = dri2_display_is_pixmap_supported; 815 dri2dpy->base.create_window_surface = dri2_display_create_window_surface; 816 dri2dpy->base.create_pixmap_surface = dri2_display_create_pixmap_surface; 817 818 return &dri2dpy->base; 819} 820