x11: Clear X11 selection when we can't bridge the data type
[profile/ivi/weston-ivi-shell.git] / compositor / compositor-openwfd.c
1 /*
2  * Copyright © 2011 Benjamin Franzke
3  * Copyright © 2011 Intel Corporation
4  *
5  * Permission to use, copy, modify, distribute, and sell this software and
6  * its documentation for any purpose is hereby granted without fee, provided
7  * that the above copyright notice appear in all copies and that both that
8  * copyright notice and this permission notice appear in supporting
9  * documentation, and that the name of the copyright holders not be used in
10  * advertising or publicity pertaining to distribution of the software
11  * without specific, written prior permission.  The copyright holders make
12  * no representations about the suitability of this software for any
13  * purpose.  It is provided "as is" without express or implied warranty.
14  *
15  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
16  * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17  * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
18  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
20  * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22  */
23
24 #define _GNU_SOURCE
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29
30 #include <sys/time.h>
31
32 #include <WF/wfd.h>
33 #include <WF/wfdext.h>
34
35 #include <gbm.h>
36
37 #include "compositor.h"
38 #include "evdev.h"
39
40 struct wfd_compositor {
41         struct wlsc_compositor base;
42
43         struct udev *udev;
44         struct gbm_device *gbm;
45         WFDDevice dev;
46
47         WFDEvent event;
48         int wfd_fd;
49         struct wl_event_source *wfd_source;
50
51         struct tty *tty;
52
53         uint32_t start_time;
54         uint32_t used_pipelines;
55 };
56
57 struct wfd_mode {
58         struct wlsc_mode base;
59         WFDPortMode mode;
60 };
61
62 struct wfd_output {
63         struct wlsc_output   base;
64
65         WFDPort port;
66
67         WFDPipeline pipeline;
68         WFDint pipeline_id;
69
70         WFDPortMode mode;
71         WFDSource source[2];
72
73         struct gbm_bo *bo[2];
74         EGLImageKHR image[2];
75         GLuint rbo[2];
76         uint32_t current;
77 };
78
79 union wfd_geometry {
80         struct {
81                 WFDint x, y;
82                 WFDint width, height;
83         } g;
84
85         WFDint array[4];
86 };
87
88 static int
89 wfd_output_prepare_render(struct wlsc_output *output_base)
90 {
91         struct wfd_output *output = (struct wfd_output *) output_base;
92
93         glFramebufferRenderbuffer(GL_FRAMEBUFFER,
94                                   GL_COLOR_ATTACHMENT0,
95                                   GL_RENDERBUFFER,
96                                   output->rbo[output->current]);
97
98         if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
99                 return -1;
100
101         return 0;
102 }
103
104 static int
105 wfd_output_present(struct wlsc_output *output_base)
106 {
107         struct wfd_output *output = (struct wfd_output *) output_base;
108         struct wfd_compositor *c =
109                 (struct wfd_compositor *) output->base.compositor;
110
111         if (wfd_output_prepare_render(&output->base))
112                 return -1;
113         glFlush();
114
115         output->current ^= 1;
116
117         wfdBindSourceToPipeline(c->dev, output->pipeline,
118                                 output->source[output->current ^ 1],
119                                 WFD_TRANSITION_AT_VSYNC, NULL);
120
121         wfdDeviceCommit(c->dev, WFD_COMMIT_PIPELINE, output->pipeline);
122
123         return 0;
124 }
125
126 static int
127 init_egl(struct wfd_compositor *ec)
128 {
129         EGLint major, minor;
130         const char *extensions;
131         int fd;
132         static const EGLint context_attribs[] = {
133                 EGL_CONTEXT_CLIENT_VERSION, 2,
134                 EGL_NONE
135         };
136
137         fd = wfdGetDeviceAttribi(ec->dev, WFD_DEVICE_ID);
138         if (fd < 0)
139                 return -1;
140
141         ec->wfd_fd = fd;
142         ec->gbm = gbm_create_device(ec->wfd_fd);
143         ec->base.display = eglGetDisplay(ec->gbm);
144         if (ec->base.display == NULL) {
145                 fprintf(stderr, "failed to create display\n");
146                 return -1;
147         }
148
149         if (!eglInitialize(ec->base.display, &major, &minor)) {
150                 fprintf(stderr, "failed to initialize display\n");
151                 return -1;
152         }
153
154         extensions = eglQueryString(ec->base.display, EGL_EXTENSIONS);
155         if (!strstr(extensions, "EGL_KHR_surfaceless_gles2")) {
156                 fprintf(stderr, "EGL_KHR_surfaceless_gles2 not available\n");
157                 return -1;
158         }
159
160         if (!eglBindAPI(EGL_OPENGL_ES_API)) {
161                 fprintf(stderr, "failed to bind api EGL_OPENGL_ES_API\n");
162                 return -1;
163         }
164
165         ec->base.context = eglCreateContext(ec->base.display, NULL,
166                                             EGL_NO_CONTEXT, context_attribs);
167         if (ec->base.context == NULL) {
168                 fprintf(stderr, "failed to create context\n");
169                 return -1;
170         }
171
172         if (!eglMakeCurrent(ec->base.display, EGL_NO_SURFACE,
173                             EGL_NO_SURFACE, ec->base.context)) {
174                 fprintf(stderr, "failed to make context current\n");
175                 return -1;
176         }
177
178         return 0;
179 }
180
181 static int
182 wfd_output_prepare_scanout_surface(struct wlsc_output *output_base,
183                                    struct wlsc_surface *es)
184 {
185         return -1;
186 }
187
188 static int
189 wfd_output_set_cursor(struct wlsc_output *output_base,
190                       struct wlsc_input_device *input)
191 {
192         return -1;
193 }
194
195 static void
196 wfd_output_destroy(struct wlsc_output *output_base)
197 {
198         struct wfd_output *output = (struct wfd_output *) output_base;
199         struct wfd_compositor *ec =
200                 (struct wfd_compositor *) output->base.compositor;
201         int i;
202
203         glFramebufferRenderbuffer(GL_FRAMEBUFFER,
204                                   GL_COLOR_ATTACHMENT0,
205                                   GL_RENDERBUFFER,
206                                   0);
207
208         glBindRenderbuffer(GL_RENDERBUFFER, 0);
209         glDeleteRenderbuffers(2, output->rbo);
210
211         for (i = 0; i < 2; i++) {
212                 ec->base.destroy_image(ec->base.display, output->image[i]);
213                 gbm_bo_destroy(output->bo[i]);
214                 wfdDestroySource(ec->dev, output->source[i]);
215         }
216         
217         ec->used_pipelines &= ~(1 << output->pipeline_id);
218         wfdDestroyPipeline(ec->dev, output->pipeline);
219         wfdDestroyPort(ec->dev, output->port);
220
221         wlsc_output_destroy(&output->base);
222         wl_list_remove(&output->base.link);
223
224         free(output);
225 }
226
227 static int
228 wfd_output_add_mode(struct wfd_output *output, WFDPortMode mode)
229 {
230         struct wfd_compositor *ec =
231                 (struct wfd_compositor *) output->base.compositor;
232         struct wfd_mode *wmode;
233
234         wmode = malloc(sizeof *wmode);
235         if (wmode == NULL)
236                 return -1;
237
238         wmode->base.flags = 0;
239         wmode->base.width = wfdGetPortModeAttribi(ec->dev, output->port, mode,
240                                                   WFD_PORT_MODE_WIDTH);
241         wmode->base.height = wfdGetPortModeAttribi(ec->dev, output->port, mode,
242                                                    WFD_PORT_MODE_HEIGHT);
243         wmode->base.refresh = wfdGetPortModeAttribi(ec->dev, output->port, mode,
244                                                     WFD_PORT_MODE_REFRESH_RATE);
245         wmode->mode = mode;
246         wl_list_insert(output->base.mode_list.prev, &wmode->base.link);
247
248         return 0;
249 }
250
251 static int
252 create_output_for_port(struct wfd_compositor *ec,
253                        WFDHandle port,
254                        int x, int y)
255 {
256         struct wfd_output *output;
257         int i;
258         WFDint num_pipelines, *pipelines;
259         WFDint num_modes;
260         union wfd_geometry geometry;
261         struct wfd_mode *mode;
262         WFDPortMode *modes;
263         WFDfloat physical_size[2];
264
265         output = malloc(sizeof *output);
266         if (output == NULL)
267                 return -1;
268
269         memset(output, 0, sizeof *output);
270         memset(&geometry, 0, sizeof geometry);
271
272         output->port = port;
273         wl_list_init(&output->base.mode_list);
274
275         wfdSetPortAttribi(ec->dev, output->port,
276                           WFD_PORT_POWER_MODE, WFD_POWER_MODE_ON);
277
278         num_modes = wfdGetPortModes(ec->dev, output->port, NULL, 0);
279         if (num_modes < 1) {
280                 fprintf(stderr, "failed to get port mode\n");
281                 goto cleanup_port;
282         }
283
284         modes = malloc(sizeof(WFDPortMode) * num_modes);
285         if (modes == NULL) 
286                 goto cleanup_port;
287
288         output->base.compositor = &ec->base;
289         num_modes = wfdGetPortModes(ec->dev, output->port, modes, num_modes);
290         for (i = 0; i < num_modes; ++i)
291                 wfd_output_add_mode(output, modes[i]);
292
293         free(modes);
294
295         wfdGetPortAttribiv(ec->dev, output->port,
296                            WFD_PORT_NATIVE_RESOLUTION,
297                            2, &geometry.array[2]);
298
299         output->base.current = NULL;
300         wl_list_for_each(mode, &output->base.mode_list, base.link) {
301                 if (mode->base.width == geometry.g.width &&
302                     mode->base.height == geometry.g.height) {
303                         output->base.current = &mode->base;
304                         break;
305                 }
306         }
307         if (output->base.current == NULL) {
308                 fprintf(stderr, "failed to find a native mode\n");
309                 goto cleanup_port;
310         }
311
312         mode = (struct wfd_mode *) output->base.current;
313         mode->base.flags = WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
314
315         wfdSetPortMode(ec->dev, output->port, mode->mode);
316
317         wfdEnumeratePipelines(ec->dev, NULL, 0, NULL);
318
319         num_pipelines = wfdGetPortAttribi(ec->dev, output->port,
320                                           WFD_PORT_PIPELINE_ID_COUNT);
321         if (num_pipelines < 1) {
322                 fprintf(stderr, "failed to get a bindable pipeline\n");
323                 goto cleanup_port;
324         }
325         pipelines = calloc(num_pipelines, sizeof *pipelines);
326         if (pipelines == NULL)
327                 goto cleanup_port;
328
329         wfdGetPortAttribiv(ec->dev, output->port,
330                            WFD_PORT_BINDABLE_PIPELINE_IDS,
331                            num_pipelines, pipelines);
332
333         output->pipeline_id = WFD_INVALID_PIPELINE_ID;
334         for (i = 0; i < num_pipelines; ++i) {
335                 if (!(ec->used_pipelines & (1 << pipelines[i]))) {
336                         output->pipeline_id = pipelines[i];
337                         break;
338                 }
339         }
340         if (output->pipeline_id == WFD_INVALID_PIPELINE_ID) {
341                 fprintf(stderr, "no pipeline found for port: %d\n", port);
342                 goto cleanup_pipelines;
343         }
344
345         ec->used_pipelines |= (1 << output->pipeline_id);
346
347         wfdGetPortAttribfv(ec->dev, output->port,
348                            WFD_PORT_PHYSICAL_SIZE,
349                            2, physical_size);
350
351         wlsc_output_init(&output->base, &ec->base, x, y,
352                          physical_size[0], physical_size[1], 0);
353
354         output->pipeline = wfdCreatePipeline(ec->dev, output->pipeline_id, NULL);
355         if (output->pipeline == WFD_INVALID_HANDLE) {
356                 fprintf(stderr, "failed to create a pipeline\n");
357                 goto cleanup_wlsc_output;
358         }
359
360         glGenRenderbuffers(2, output->rbo);
361         for (i = 0; i < 2; i++) {
362                 glBindRenderbuffer(GL_RENDERBUFFER, output->rbo[i]);
363
364                 output->bo[i] =
365                         gbm_bo_create(ec->gbm,
366                                       output->base.current->width,
367                                       output->base.current->height,
368                                       GBM_BO_FORMAT_XRGB8888,
369                                       GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
370                 output->image[i] = ec->base.create_image(ec->base.display,
371                                                          NULL,
372                                                          EGL_NATIVE_PIXMAP_KHR,
373                                                          output->bo[i], NULL);
374
375                 printf("output->image[i]: %p\n", output->image[i]);
376                 ec->base.image_target_renderbuffer_storage(GL_RENDERBUFFER,
377                                                            output->image[i]);
378                 output->source[i] =
379                         wfdCreateSourceFromImage(ec->dev, output->pipeline,
380                                                  output->image[i], NULL);
381
382                 if (output->source[i] == WFD_INVALID_HANDLE) {
383                         fprintf(stderr, "failed to create source\n");
384                         goto cleanup_pipeline;
385                 }
386         }
387
388         output->current = 0;
389         glFramebufferRenderbuffer(GL_FRAMEBUFFER,
390                                   GL_COLOR_ATTACHMENT0,
391                                   GL_RENDERBUFFER,
392                                   output->rbo[output->current]);
393
394         wfdSetPipelineAttribiv(ec->dev, output->pipeline,
395                                WFD_PIPELINE_SOURCE_RECTANGLE,
396                                4, geometry.array);
397         wfdSetPipelineAttribiv(ec->dev, output->pipeline,
398                                WFD_PIPELINE_DESTINATION_RECTANGLE,
399                                4, geometry.array);
400
401         wfdBindSourceToPipeline(ec->dev, output->pipeline,
402                                 output->source[output->current ^ 1],
403                                 WFD_TRANSITION_AT_VSYNC, NULL);
404
405         wfdBindPipelineToPort(ec->dev, output->port, output->pipeline);
406
407         wfdDeviceCommit(ec->dev, WFD_COMMIT_ENTIRE_DEVICE, WFD_INVALID_HANDLE);
408
409         output->base.prepare_render = wfd_output_prepare_render;
410         output->base.present = wfd_output_present;
411         output->base.prepare_scanout_surface =
412                 wfd_output_prepare_scanout_surface;
413         output->base.set_hardware_cursor = wfd_output_set_cursor;
414         output->base.destroy = wfd_output_destroy;
415
416         wl_list_insert(ec->base.output_list.prev, &output->base.link);
417
418         return 0;
419
420 cleanup_pipeline:
421         wfdDestroyPipeline(ec->dev, output->pipeline);
422 cleanup_wlsc_output:
423         wlsc_output_destroy(&output->base);
424 cleanup_pipelines:
425         free(pipelines);
426 cleanup_port:
427         wfdDestroyPort(ec->dev, output->port);
428         free(output);
429
430         return -1;
431 }
432
433 static int
434 create_outputs(struct wfd_compositor *ec, int option_connector)
435 {
436         int x = 0, y = 0;
437         WFDint i, num, *ports;
438         WFDPort port = WFD_INVALID_HANDLE;
439
440         num = wfdEnumeratePorts(ec->dev, NULL, 0, NULL);
441         ports = calloc(num, sizeof *ports);
442         if (ports == NULL)
443                 return -1;
444
445         num = wfdEnumeratePorts(ec->dev, ports, num, NULL);
446         if (num < 1)
447                 return -1;
448
449         for (i = 0; i < num; ++i) {
450                 port = wfdCreatePort(ec->dev, ports[i], NULL);
451                 if (port == WFD_INVALID_HANDLE)
452                         continue;
453
454                 if (wfdGetPortAttribi(ec->dev, port, WFD_PORT_ATTACHED) &&
455                     (option_connector == 0 || ports[i] == option_connector)) {
456                         create_output_for_port(ec, port, x, y);
457
458                         x += container_of(ec->base.output_list.prev,
459                                           struct wlsc_output,
460                                           link)->current->width;
461                 } else {
462                         wfdDestroyPort(ec->dev, port);
463                 }
464         }
465
466         free(ports);
467
468         return 0;
469 }
470
471 static int
472 handle_port_state_change(struct wfd_compositor *ec)
473 {
474         struct wfd_output *output, *next;
475         WFDint output_port_id;
476         int x = 0, y = 0;
477         int x_offset = 0, y_offset = 0;
478         WFDPort port;
479         WFDint port_id;
480         WFDboolean state;
481
482         port_id = wfdGetEventAttribi(ec->dev, ec->event,
483                                      WFD_EVENT_PORT_ATTACH_PORT_ID);
484         state = wfdGetEventAttribi(ec->dev, ec->event,
485                                    WFD_EVENT_PORT_ATTACH_STATE);
486
487         if (state) {
488                 struct wlsc_output *last_output =
489                         container_of(ec->base.output_list.prev,
490                                      struct wlsc_output, link);
491
492                 /* XXX: not yet needed, we die with 0 outputs */
493                 if (!wl_list_empty(&ec->base.output_list))
494                         x = last_output->x +
495                                 last_output->current->width;
496                 else
497                         x = 0;
498                 y = 0;
499
500                 port = wfdCreatePort(ec->dev, port_id, NULL);
501                 if (port == WFD_INVALID_HANDLE)
502                         return -1;
503
504                 create_output_for_port(ec, port, x, y);
505
506                 return 0;
507         }
508
509         wl_list_for_each_safe(output, next, &ec->base.output_list, base.link) {
510                 output_port_id =
511                         wfdGetPortAttribi(ec->dev, output->port, WFD_PORT_ID);
512
513                 if (!state && output_port_id == port_id) {
514                         x_offset += output->base.current->width;
515                         wfd_output_destroy(&output->base);
516                         continue;
517                 }
518
519                 if (x_offset != 0 || y_offset != 0) {
520                         wlsc_output_move(&output->base,
521                                          output->base.x - x_offset,
522                                          output->base.y - y_offset);
523                 }
524         }
525
526         if (ec->used_pipelines == 0)
527                 wl_display_terminate(ec->base.wl_display);
528
529         return 0;
530 }
531
532 static int
533 on_wfd_event(int fd, uint32_t mask, void *data)
534 {
535         struct wfd_compositor *c = data;
536         struct wfd_output *output = NULL, *output_iter;
537         WFDEventType type;
538         const WFDtime timeout = 0;
539         WFDint pipeline_id;
540         WFDint bind_time;
541
542         type = wfdDeviceEventWait(c->dev, c->event, timeout);
543
544         switch (type) {
545         case WFD_EVENT_PIPELINE_BIND_SOURCE_COMPLETE:
546                 pipeline_id =
547                         wfdGetEventAttribi(c->dev, c->event,
548                                            WFD_EVENT_PIPELINE_BIND_PIPELINE_ID);
549
550                 bind_time =
551                         wfdGetEventAttribi(c->dev, c->event,
552                                            WFD_EVENT_PIPELINE_BIND_TIME_EXT);
553
554                 wl_list_for_each(output_iter, &c->base.output_list, base.link) {
555                         if (output_iter->pipeline_id == pipeline_id)
556                                 output = output_iter;
557                 }
558
559                 if (output == NULL)
560                         return 1;
561
562                 wlsc_output_finish_frame(&output->base,
563                                          c->start_time + bind_time);
564                 break;
565         case WFD_EVENT_PORT_ATTACH_DETACH:
566                 handle_port_state_change(c);
567                 break;
568         default:
569                 return 1;
570         }
571
572         return 1;
573 }
574
575 static void
576 wfd_destroy(struct wlsc_compositor *ec)
577 {
578         struct wfd_compositor *d = (struct wfd_compositor *) ec;
579
580         wlsc_compositor_shutdown(ec);
581
582         udev_unref(d->udev);
583
584         wfdDestroyDevice(d->dev);
585
586         tty_destroy(d->tty);
587
588         free(d);
589 }
590
591 /* FIXME: Just add a stub here for now
592  * handle drm{Set,Drop}Master in owfdrm somehow */
593 static void
594 vt_func(struct wlsc_compositor *compositor, int event)
595 {
596         return;
597 }
598
599 static const char default_seat[] = "seat0";
600
601 static struct wlsc_compositor *
602 wfd_compositor_create(struct wl_display *display,
603                       int connector, const char *seat, int tty)
604 {
605         struct wfd_compositor *ec;
606         struct wl_event_loop *loop;
607         struct timeval tv;
608
609         ec = malloc(sizeof *ec);
610         if (ec == NULL)
611                 return NULL;
612
613         memset(ec, 0, sizeof *ec);
614
615         gettimeofday(&tv, NULL);
616         ec->start_time = tv.tv_sec * 1000 + tv.tv_usec / 1000;
617
618         ec->udev = udev_new();
619         if (ec->udev == NULL) {
620                 fprintf(stderr, "failed to initialize udev context\n");
621                 return NULL;
622         }
623
624         ec->dev = wfdCreateDevice(WFD_DEFAULT_DEVICE_ID, NULL);
625         if (ec->dev == WFD_INVALID_HANDLE) {
626                 fprintf(stderr, "failed to create wfd device\n");
627                 return NULL;
628         }
629
630         ec->event = wfdCreateEvent(ec->dev, NULL);
631         if (ec->event == WFD_INVALID_HANDLE) {
632                 fprintf(stderr, "failed to create wfd event\n");
633                 return NULL;
634         }
635
636         ec->base.wl_display = display;
637         if (init_egl(ec) < 0) {
638                 fprintf(stderr, "failed to initialize egl\n");
639                 return NULL;
640         }
641
642         ec->base.destroy = wfd_destroy;
643         ec->base.focus = 1;
644
645         glGenFramebuffers(1, &ec->base.fbo);
646         glBindFramebuffer(GL_FRAMEBUFFER, ec->base.fbo);
647
648         /* Can't init base class until we have a current egl context */
649         if (wlsc_compositor_init(&ec->base, display) < 0)
650                 return NULL;
651
652         if (create_outputs(ec, connector) < 0) {
653                 fprintf(stderr, "failed to create outputs\n");
654                 return NULL;
655         }
656
657         evdev_input_create(&ec->base, ec->udev, seat);
658
659         loop = wl_display_get_event_loop(ec->base.wl_display);
660         ec->wfd_source =
661                 wl_event_loop_add_fd(loop,
662                                      wfdDeviceEventGetFD(ec->dev, ec->event),
663                                      WL_EVENT_READABLE, on_wfd_event, ec);
664         ec->tty = tty_create(&ec->base, vt_func, tty);
665
666         return &ec->base;
667 }
668
669 struct wlsc_compositor *
670 backend_init(struct wl_display *display, char *options);
671
672 WL_EXPORT struct wlsc_compositor *
673 backend_init(struct wl_display *display, char *options)
674 {
675         int connector = 0, i;
676         const char *seat;
677         char *p, *value;
678         int tty = 1;
679
680         static char * const tokens[] = { "connector", "seat", "tty", NULL };
681         
682         p = options;
683         seat = default_seat;
684         while (i = getsubopt(&p, tokens, &value), i != -1) {
685                 switch (i) {
686                 case 0:
687                         connector = strtol(value, NULL, 0);
688                         break;
689                 case 1:
690                         seat = value;
691                         break;
692                 case 2:
693                         tty = strtol(value, NULL, 0);
694                         break;
695                 }
696         }
697
698         return wfd_compositor_create(display, connector, seat, tty);
699 }