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