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