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