native_wayland.c revision 58dc1b28d1ef4d1931c52b079d304f2e1546329d
1/* 2 * Mesa 3-D graphics library 3 * Version: 7.11 4 * 5 * Copyright (C) 2011 Benjamin Franzke <benjaminfranzke@googlemail.com> 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_inlines.h" 28 29#include "pipe/p_compiler.h" 30#include "pipe/p_screen.h" 31#include "pipe/p_context.h" 32#include "pipe/p_state.h" 33#include "state_tracker/drm_driver.h" 34#include "egllog.h" 35 36#include "native_wayland.h" 37 38static const struct native_event_handler *wayland_event_handler; 39 40const static struct { 41 enum pipe_format format; 42 enum wayland_format_flag flag; 43} wayland_formats[] = { 44 { PIPE_FORMAT_B8G8R8A8_UNORM, HAS_ARGB8888 }, 45 { PIPE_FORMAT_B8G8R8X8_UNORM, HAS_XRGB8888 }, 46}; 47 48static const struct native_config ** 49wayland_display_get_configs(struct native_display *ndpy, int *num_configs) 50{ 51 struct wayland_display *display = wayland_display(ndpy); 52 const struct native_config **configs; 53 int i; 54 55 if (!display->configs) { 56 struct native_config *nconf; 57 58 display->num_configs = 0; 59 display->configs = CALLOC(Elements(wayland_formats), 60 sizeof(*display->configs)); 61 if (!display->configs) 62 return NULL; 63 64 for (i = 0; i < Elements(wayland_formats); ++i) { 65 if (!(display->formats & wayland_formats[i].flag)) 66 continue; 67 68 nconf = &display->configs[display->num_configs].base; 69 nconf->buffer_mask = 70 (1 << NATIVE_ATTACHMENT_FRONT_LEFT) | 71 (1 << NATIVE_ATTACHMENT_BACK_LEFT); 72 73 nconf->window_bit = TRUE; 74 nconf->pixmap_bit = TRUE; 75 76 nconf->color_format = wayland_formats[i].format; 77 display->num_configs++; 78 } 79 } 80 81 configs = MALLOC(display->num_configs * sizeof(*configs)); 82 if (configs) { 83 for (i = 0; i < display->num_configs; ++i) 84 configs[i] = &display->configs[i].base; 85 if (num_configs) 86 *num_configs = display->num_configs; 87 } 88 89 return configs; 90} 91 92static int 93wayland_display_get_param(struct native_display *ndpy, 94 enum native_param_type param) 95{ 96 struct wayland_display *display = wayland_display(ndpy); 97 int val; 98 99 switch (param) { 100 case NATIVE_PARAM_PREMULTIPLIED_ALPHA: 101 val = 1; 102 break; 103 case NATIVE_PARAM_USE_NATIVE_BUFFER: 104 case NATIVE_PARAM_PRESERVE_BUFFER: 105 case NATIVE_PARAM_MAX_SWAP_INTERVAL: 106 default: 107 val = 0; 108 break; 109 } 110 111 return val; 112} 113 114static boolean 115wayland_display_get_pixmap_format(struct native_display *ndpy, 116 EGLNativePixmapType pix, 117 enum pipe_format *format) 118{ 119 /* all wl_egl_pixmaps are supported */ 120 *format = PIPE_FORMAT_NONE; 121 122 return TRUE; 123} 124 125static void 126wayland_pixmap_destroy(struct wl_egl_pixmap *egl_pixmap) 127{ 128 struct pipe_resource *resource = egl_pixmap->driver_private; 129 130 assert(resource); 131 132 pipe_resource_reference(&resource, NULL); 133 if (egl_pixmap->buffer) { 134 wl_buffer_destroy(egl_pixmap->buffer); 135 egl_pixmap->buffer = NULL; 136 } 137 138 egl_pixmap->driver_private = NULL; 139 egl_pixmap->destroy = NULL; 140} 141 142static void 143wayland_pixmap_surface_initialize(struct wayland_surface *surface) 144{ 145 struct wayland_display *display = wayland_display(&surface->display->base); 146 const enum native_attachment front_natt = NATIVE_ATTACHMENT_FRONT_LEFT; 147 148 if (surface->pix->buffer != NULL) 149 return; 150 151 surface->pix->buffer = display->create_buffer(display, surface, front_natt); 152 surface->pix->destroy = wayland_pixmap_destroy; 153 surface->pix->driver_private = 154 resource_surface_get_single_resource(surface->rsurf, front_natt); 155} 156 157static void 158wayland_release_pending_resource(void *data, 159 struct wl_callback *callback, 160 uint32_t time) 161{ 162 struct wayland_surface *surface = data; 163 164 wl_callback_destroy(callback); 165 166 /* FIXME: print internal error */ 167 if (!surface->pending_resource) 168 return; 169 170 pipe_resource_reference(&surface->pending_resource, NULL); 171} 172 173static const struct wl_callback_listener release_buffer_listener = { 174 wayland_release_pending_resource 175}; 176 177static void 178wayland_window_surface_handle_resize(struct wayland_surface *surface) 179{ 180 struct wayland_display *display = surface->display; 181 struct pipe_resource *front_resource; 182 const enum native_attachment front_natt = NATIVE_ATTACHMENT_FRONT_LEFT; 183 int i; 184 185 front_resource = resource_surface_get_single_resource(surface->rsurf, 186 front_natt); 187 if (resource_surface_set_size(surface->rsurf, 188 surface->win->width, surface->win->height)) { 189 190 if (surface->pending_resource) 191 wl_display_roundtrip(display->dpy); 192 193 if (front_resource) { 194 struct wl_callback *callback; 195 196 surface->pending_resource = front_resource; 197 front_resource = NULL; 198 199 callback = wl_display_sync(display->dpy); 200 wl_callback_add_listener(callback, &release_buffer_listener, surface); 201 } 202 203 for (i = 0; i < WL_BUFFER_COUNT; ++i) { 204 if (surface->buffer[i]) 205 wl_buffer_destroy(surface->buffer[i]); 206 surface->buffer[i] = NULL; 207 } 208 209 surface->dx = surface->win->dx; 210 surface->dy = surface->win->dy; 211 } 212 pipe_resource_reference(&front_resource, NULL); 213} 214 215static boolean 216wayland_surface_validate(struct native_surface *nsurf, uint attachment_mask, 217 unsigned int *seq_num, struct pipe_resource **textures, 218 int *width, int *height) 219{ 220 struct wayland_surface *surface = wayland_surface(nsurf); 221 222 if (surface->type == WL_WINDOW_SURFACE) 223 wayland_window_surface_handle_resize(surface); 224 225 if (!resource_surface_add_resources(surface->rsurf, attachment_mask | 226 surface->attachment_mask)) 227 return FALSE; 228 229 if (textures) 230 resource_surface_get_resources(surface->rsurf, textures, attachment_mask); 231 232 if (seq_num) 233 *seq_num = surface->sequence_number; 234 235 resource_surface_get_size(surface->rsurf, (uint *) width, (uint *) height); 236 237 if (surface->type == WL_PIXMAP_SURFACE) 238 wayland_pixmap_surface_initialize(surface); 239 240 return TRUE; 241} 242 243static void 244wayland_frame_callback(void *data, struct wl_callback *callback, uint32_t time) 245{ 246 struct wayland_surface *surface = data; 247 248 surface->block_swap_buffers = FALSE; 249 250 wl_callback_destroy(callback); 251} 252 253static const struct wl_callback_listener frame_listener = { 254 wayland_frame_callback 255}; 256 257static INLINE void 258wayland_buffers_swap(struct wl_buffer **buffer, 259 enum wayland_buffer_type buf1, 260 enum wayland_buffer_type buf2) 261{ 262 struct wl_buffer *tmp = buffer[buf1]; 263 buffer[buf1] = buffer[buf2]; 264 buffer[buf2] = tmp; 265} 266 267static boolean 268wayland_surface_swap_buffers(struct native_surface *nsurf) 269{ 270 struct wayland_surface *surface = wayland_surface(nsurf); 271 struct wayland_display *display = surface->display; 272 struct wl_callback *callback; 273 274 while (surface->block_swap_buffers) 275 wl_display_iterate(display->dpy, WL_DISPLAY_READABLE); 276 277 surface->block_swap_buffers = TRUE; 278 279 callback = wl_surface_frame(surface->win->surface); 280 wl_callback_add_listener(callback, &frame_listener, surface); 281 282 if (surface->type == WL_WINDOW_SURFACE) { 283 resource_surface_swap_buffers(surface->rsurf, 284 NATIVE_ATTACHMENT_FRONT_LEFT, 285 NATIVE_ATTACHMENT_BACK_LEFT, FALSE); 286 287 wayland_buffers_swap(surface->buffer, WL_BUFFER_FRONT, WL_BUFFER_BACK); 288 289 if (surface->buffer[WL_BUFFER_FRONT] == NULL) 290 surface->buffer[WL_BUFFER_FRONT] = 291 display->create_buffer(display, surface, 292 NATIVE_ATTACHMENT_FRONT_LEFT); 293 294 wl_surface_attach(surface->win->surface, surface->buffer[WL_BUFFER_FRONT], 295 surface->dx, surface->dy); 296 297 resource_surface_get_size(surface->rsurf, 298 (uint *) &surface->win->attached_width, 299 (uint *) &surface->win->attached_height); 300 surface->dx = 0; 301 surface->dy = 0; 302 } 303 304 surface->sequence_number++; 305 wayland_event_handler->invalid_surface(&display->base, 306 &surface->base, 307 surface->sequence_number); 308 309 return TRUE; 310} 311 312static boolean 313wayland_surface_present(struct native_surface *nsurf, 314 const struct native_present_control *ctrl) 315{ 316 struct wayland_surface *surface = wayland_surface(nsurf); 317 uint width, height; 318 boolean ret; 319 320 if (ctrl->preserve || ctrl->swap_interval) 321 return FALSE; 322 323 /* force buffers to be re-created if they will be presented differently */ 324 if (surface->premultiplied_alpha != ctrl->premultiplied_alpha) { 325 enum wayland_buffer_type buffer; 326 327 for (buffer = 0; buffer < WL_BUFFER_COUNT; ++buffer) { 328 if (surface->buffer[buffer]) { 329 wl_buffer_destroy(surface->buffer[buffer]); 330 surface->buffer[buffer] = NULL; 331 } 332 } 333 334 surface->premultiplied_alpha = ctrl->premultiplied_alpha; 335 } 336 337 switch (ctrl->natt) { 338 case NATIVE_ATTACHMENT_FRONT_LEFT: 339 ret = TRUE; 340 break; 341 case NATIVE_ATTACHMENT_BACK_LEFT: 342 ret = wayland_surface_swap_buffers(nsurf); 343 break; 344 default: 345 ret = FALSE; 346 break; 347 } 348 349 if (surface->type == WL_WINDOW_SURFACE) { 350 resource_surface_get_size(surface->rsurf, &width, &height); 351 wl_buffer_damage(surface->buffer[WL_BUFFER_FRONT], 0, 0, width, height); 352 wl_surface_damage(surface->win->surface, 0, 0, width, height); 353 } 354 355 return ret; 356} 357 358static void 359wayland_surface_wait(struct native_surface *nsurf) 360{ 361 /* no-op */ 362} 363 364static void 365wayland_surface_destroy(struct native_surface *nsurf) 366{ 367 struct wayland_surface *surface = wayland_surface(nsurf); 368 enum wayland_buffer_type buffer; 369 370 for (buffer = 0; buffer < WL_BUFFER_COUNT; ++buffer) { 371 if (surface->buffer[buffer]) 372 wl_buffer_destroy(surface->buffer[buffer]); 373 } 374 375 resource_surface_destroy(surface->rsurf); 376 FREE(surface); 377} 378 379 380 381static struct native_surface * 382wayland_create_pixmap_surface(struct native_display *ndpy, 383 EGLNativePixmapType pix, 384 const struct native_config *nconf) 385{ 386 struct wayland_display *display = wayland_display(ndpy); 387 struct wayland_surface *surface; 388 struct wl_egl_pixmap *egl_pixmap = (struct wl_egl_pixmap *) pix; 389 enum native_attachment natt = NATIVE_ATTACHMENT_FRONT_LEFT; 390 uint bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW | 391 PIPE_BIND_DISPLAY_TARGET | PIPE_BIND_SCANOUT; 392 393 surface = CALLOC_STRUCT(wayland_surface); 394 if (!surface) 395 return NULL; 396 397 surface->display = display; 398 399 surface->pending_resource = NULL; 400 surface->type = WL_PIXMAP_SURFACE; 401 surface->pix = egl_pixmap; 402 403 if (nconf) 404 surface->color_format = nconf->color_format; 405 else /* FIXME: derive format from wl_visual */ 406 surface->color_format = PIPE_FORMAT_B8G8R8A8_UNORM; 407 408 surface->attachment_mask = (1 << NATIVE_ATTACHMENT_FRONT_LEFT); 409 410 surface->rsurf = resource_surface_create(display->base.screen, 411 surface->color_format, bind); 412 413 if (!surface->rsurf) { 414 FREE(surface); 415 return NULL; 416 } 417 418 resource_surface_set_size(surface->rsurf, 419 egl_pixmap->width, egl_pixmap->height); 420 421 /* the pixmap is already allocated, so import it */ 422 if (surface->pix->buffer != NULL) 423 resource_surface_import_resource(surface->rsurf, natt, 424 surface->pix->driver_private); 425 426 surface->base.destroy = wayland_surface_destroy; 427 surface->base.present = wayland_surface_present; 428 surface->base.validate = wayland_surface_validate; 429 surface->base.wait = wayland_surface_wait; 430 431 return &surface->base; 432} 433 434 435static struct native_surface * 436wayland_create_window_surface(struct native_display *ndpy, 437 EGLNativeWindowType win, 438 const struct native_config *nconf) 439{ 440 struct wayland_display *display = wayland_display(ndpy); 441 struct wayland_config *config = wayland_config(nconf); 442 struct wayland_surface *surface; 443 uint bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW | 444 PIPE_BIND_DISPLAY_TARGET | PIPE_BIND_SCANOUT; 445 446 surface = CALLOC_STRUCT(wayland_surface); 447 if (!surface) 448 return NULL; 449 450 surface->display = display; 451 surface->color_format = config->base.color_format; 452 453 surface->win = (struct wl_egl_window *) win; 454 455 surface->pending_resource = NULL; 456 surface->block_swap_buffers = FALSE; 457 surface->type = WL_WINDOW_SURFACE; 458 459 surface->buffer[WL_BUFFER_FRONT] = NULL; 460 surface->buffer[WL_BUFFER_BACK] = NULL; 461 surface->attachment_mask = (1 << NATIVE_ATTACHMENT_FRONT_LEFT) | 462 (1 << NATIVE_ATTACHMENT_BACK_LEFT); 463 464 surface->rsurf = resource_surface_create(display->base.screen, 465 surface->color_format, bind); 466 467 if (!surface->rsurf) { 468 FREE(surface); 469 return NULL; 470 } 471 472 surface->base.destroy = wayland_surface_destroy; 473 surface->base.present = wayland_surface_present; 474 surface->base.validate = wayland_surface_validate; 475 surface->base.wait = wayland_surface_wait; 476 477 return &surface->base; 478} 479 480static struct native_display * 481native_create_display(void *dpy, boolean use_sw) 482{ 483 struct wayland_display *display = NULL; 484 boolean own_dpy = FALSE; 485 486 use_sw = use_sw || debug_get_bool_option("EGL_SOFTWARE", FALSE); 487 488 if (dpy == NULL) { 489 dpy = wl_display_connect(NULL); 490 if (dpy == NULL) 491 return NULL; 492 own_dpy = TRUE; 493 } 494 495 if (use_sw) { 496 _eglLog(_EGL_INFO, "use software fallback"); 497 display = wayland_create_shm_display((struct wl_display *) dpy, 498 wayland_event_handler); 499 } else { 500 display = wayland_create_drm_display((struct wl_display *) dpy, 501 wayland_event_handler); 502 } 503 504 if (!display) 505 return NULL; 506 507 display->base.get_param = wayland_display_get_param; 508 display->base.get_configs = wayland_display_get_configs; 509 display->base.get_pixmap_format = wayland_display_get_pixmap_format; 510 display->base.copy_to_pixmap = native_display_copy_to_pixmap; 511 display->base.create_window_surface = wayland_create_window_surface; 512 display->base.create_pixmap_surface = wayland_create_pixmap_surface; 513 514 display->own_dpy = own_dpy; 515 516 return &display->base; 517} 518 519static const struct native_platform wayland_platform = { 520 "wayland", /* name */ 521 native_create_display 522}; 523 524const struct native_platform * 525native_get_wayland_platform(const struct native_event_handler *event_handler) 526{ 527 wayland_event_handler = event_handler; 528 return &wayland_platform; 529} 530 531/* vim: set sw=3 ts=8 sts=3 expandtab: */ 532