Replace fprintf() by weston_log()
[profile/ivi/weston.git] / src / 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 <stdlib.h>
27 #include <string.h>
28
29 #include <sys/time.h>
30
31 #include <WF/wfd.h>
32 #include <WF/wfdext.h>
33
34 #include <gbm.h>
35
36 #include "compositor.h"
37 #include "evdev.h"
38 #include "log.h"
39
40 struct wfd_compositor {
41         struct weston_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 weston_mode base;
59         WFDPortMode mode;
60 };
61
62 struct wfd_output {
63         struct weston_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 void
89 wfd_output_repaint(struct weston_output *output_base)
90 {
91         struct wfd_output *output = (struct wfd_output *) output_base;
92         struct weston_surface *surface;
93         struct wfd_compositor *compositor =
94                 (struct wfd_compositor *) output->base.compositor;
95
96         glFramebufferRenderbuffer(GL_FRAMEBUFFER,
97                                   GL_COLOR_ATTACHMENT0,
98                                   GL_RENDERBUFFER,
99                                   output->rbo[output->current]);
100
101         if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
102                 return -1;
103
104         wl_list_for_each_reverse(surface, &compositor->surface_list, link)
105                 weston_surface_draw(surface, output);
106
107         glFlush();
108
109         output->current ^= 1;
110
111         wfdBindSourceToPipeline(compositor->dev, output->pipeline,
112                                 output->source[output->current ^ 1],
113                                 WFD_TRANSITION_AT_VSYNC, NULL);
114
115         wfdDeviceCommit(compositor->dev,
116                         WFD_COMMIT_PIPELINE, output->pipeline);
117
118         return 0;
119 }
120
121 static int
122 init_egl(struct wfd_compositor *ec)
123 {
124         EGLint major, minor;
125         const char *extensions;
126         int fd;
127         static const EGLint context_attribs[] = {
128                 EGL_CONTEXT_CLIENT_VERSION, 2,
129                 EGL_NONE
130         };
131
132         fd = wfdGetDeviceAttribi(ec->dev, WFD_DEVICE_ID);
133         if (fd < 0)
134                 return -1;
135
136         ec->wfd_fd = fd;
137         ec->gbm = gbm_create_device(ec->wfd_fd);
138         ec->base.display = eglGetDisplay(ec->gbm);
139         if (ec->base.display == NULL) {
140                 weston_log("failed to create display\n");
141                 return -1;
142         }
143
144         if (!eglInitialize(ec->base.display, &major, &minor)) {
145                 weston_log("failed to initialize display\n");
146                 return -1;
147         }
148
149         extensions = eglQueryString(ec->base.display, EGL_EXTENSIONS);
150         if (!strstr(extensions, "EGL_KHR_surfaceless_gles2")) {
151                 weston_log("EGL_KHR_surfaceless_gles2 not available\n");
152                 return -1;
153         }
154
155         if (!eglBindAPI(EGL_OPENGL_ES_API)) {
156                 weston_log("failed to bind api EGL_OPENGL_ES_API\n");
157                 return -1;
158         }
159
160         ec->base.context = eglCreateContext(ec->base.display, NULL,
161                                             EGL_NO_CONTEXT, context_attribs);
162         if (ec->base.context == NULL) {
163                 weston_log("failed to create context\n");
164                 return -1;
165         }
166
167         if (!eglMakeCurrent(ec->base.display, EGL_NO_SURFACE,
168                             EGL_NO_SURFACE, ec->base.context)) {
169                 weston_log("failed to make context current\n");
170                 return -1;
171         }
172
173         return 0;
174 }
175
176 static int
177 wfd_output_prepare_scanout_surface(struct weston_output *output_base,
178                                    struct weston_surface *es)
179 {
180         return -1;
181 }
182
183 static int
184 wfd_output_set_cursor(struct weston_output *output_base,
185                       struct weston_input_device *input)
186 {
187         return -1;
188 }
189
190 static void
191 wfd_output_destroy(struct weston_output *output_base)
192 {
193         struct wfd_output *output = (struct wfd_output *) output_base;
194         struct wfd_compositor *ec =
195                 (struct wfd_compositor *) output->base.compositor;
196         int i;
197
198         glFramebufferRenderbuffer(GL_FRAMEBUFFER,
199                                   GL_COLOR_ATTACHMENT0,
200                                   GL_RENDERBUFFER,
201                                   0);
202
203         glBindRenderbuffer(GL_RENDERBUFFER, 0);
204         glDeleteRenderbuffers(2, output->rbo);
205
206         for (i = 0; i < 2; i++) {
207                 ec->base.destroy_image(ec->base.display, output->image[i]);
208                 gbm_bo_destroy(output->bo[i]);
209                 wfdDestroySource(ec->dev, output->source[i]);
210         }
211         
212         ec->used_pipelines &= ~(1 << output->pipeline_id);
213         wfdDestroyPipeline(ec->dev, output->pipeline);
214         wfdDestroyPort(ec->dev, output->port);
215
216         weston_output_destroy(&output->base);
217         wl_list_remove(&output->base.link);
218
219         free(output);
220 }
221
222 static int
223 wfd_output_add_mode(struct wfd_output *output, WFDPortMode mode)
224 {
225         struct wfd_compositor *ec =
226                 (struct wfd_compositor *) output->base.compositor;
227         struct wfd_mode *wmode;
228
229         wmode = malloc(sizeof *wmode);
230         if (wmode == NULL)
231                 return -1;
232
233         wmode->base.flags = 0;
234         wmode->base.width = wfdGetPortModeAttribi(ec->dev, output->port, mode,
235                                                   WFD_PORT_MODE_WIDTH);
236         wmode->base.height = wfdGetPortModeAttribi(ec->dev, output->port, mode,
237                                                    WFD_PORT_MODE_HEIGHT);
238         wmode->base.refresh = wfdGetPortModeAttribi(ec->dev, output->port, mode,
239                                                     WFD_PORT_MODE_REFRESH_RATE);
240         wmode->mode = mode;
241         wl_list_insert(output->base.mode_list.prev, &wmode->base.link);
242
243         return 0;
244 }
245
246 static int
247 create_output_for_port(struct wfd_compositor *ec,
248                        WFDHandle port,
249                        int x, int y)
250 {
251         struct wfd_output *output;
252         int i;
253         WFDint num_pipelines, *pipelines;
254         WFDint num_modes;
255         union wfd_geometry geometry;
256         struct wfd_mode *mode;
257         WFDPortMode *modes;
258         WFDfloat physical_size[2];
259
260         output = malloc(sizeof *output);
261         if (output == NULL)
262                 return -1;
263
264         memset(output, 0, sizeof *output);
265         memset(&geometry, 0, sizeof geometry);
266
267         output->port = port;
268         wl_list_init(&output->base.mode_list);
269
270         wfdSetPortAttribi(ec->dev, output->port,
271                           WFD_PORT_POWER_MODE, WFD_POWER_MODE_ON);
272
273         num_modes = wfdGetPortModes(ec->dev, output->port, NULL, 0);
274         if (num_modes < 1) {
275                 weston_log("failed to get port mode\n");
276                 goto cleanup_port;
277         }
278
279         modes = malloc(sizeof(WFDPortMode) * num_modes);
280         if (modes == NULL) 
281                 goto cleanup_port;
282
283         output->base.compositor = &ec->base;
284         num_modes = wfdGetPortModes(ec->dev, output->port, modes, num_modes);
285         for (i = 0; i < num_modes; ++i)
286                 wfd_output_add_mode(output, modes[i]);
287
288         free(modes);
289
290         wfdGetPortAttribiv(ec->dev, output->port,
291                            WFD_PORT_NATIVE_RESOLUTION,
292                            2, &geometry.array[2]);
293
294         output->base.current = NULL;
295         wl_list_for_each(mode, &output->base.mode_list, base.link) {
296                 if (mode->base.width == geometry.g.width &&
297                     mode->base.height == geometry.g.height) {
298                         output->base.current = &mode->base;
299                         break;
300                 }
301         }
302         if (output->base.current == NULL) {
303                 weston_log("failed to find a native mode\n");
304                 goto cleanup_port;
305         }
306
307         mode = (struct wfd_mode *) output->base.current;
308         mode->base.flags = WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
309
310         wfdSetPortMode(ec->dev, output->port, mode->mode);
311
312         wfdEnumeratePipelines(ec->dev, NULL, 0, NULL);
313
314         num_pipelines = wfdGetPortAttribi(ec->dev, output->port,
315                                           WFD_PORT_PIPELINE_ID_COUNT);
316         if (num_pipelines < 1) {
317                 weston_log("failed to get a bindable pipeline\n");
318                 goto cleanup_port;
319         }
320         pipelines = calloc(num_pipelines, sizeof *pipelines);
321         if (pipelines == NULL)
322                 goto cleanup_port;
323
324         wfdGetPortAttribiv(ec->dev, output->port,
325                            WFD_PORT_BINDABLE_PIPELINE_IDS,
326                            num_pipelines, pipelines);
327
328         output->pipeline_id = WFD_INVALID_PIPELINE_ID;
329         for (i = 0; i < num_pipelines; ++i) {
330                 if (!(ec->used_pipelines & (1 << pipelines[i]))) {
331                         output->pipeline_id = pipelines[i];
332                         break;
333                 }
334         }
335         if (output->pipeline_id == WFD_INVALID_PIPELINE_ID) {
336                 weston_log("no pipeline found for port: %d\n", port);
337                 goto cleanup_pipelines;
338         }
339
340         ec->used_pipelines |= (1 << output->pipeline_id);
341
342         wfdGetPortAttribfv(ec->dev, output->port,
343                            WFD_PORT_PHYSICAL_SIZE,
344                            2, physical_size);
345
346         weston_output_init(&output->base, &ec->base, x, y,
347                          physical_size[0], physical_size[1], 0);
348
349         output->pipeline = wfdCreatePipeline(ec->dev, output->pipeline_id, NULL);
350         if (output->pipeline == WFD_INVALID_HANDLE) {
351                 weston_log("failed to create a pipeline\n");
352                 goto cleanup_weston_output;
353         }
354
355         glGenRenderbuffers(2, output->rbo);
356         for (i = 0; i < 2; i++) {
357                 glBindRenderbuffer(GL_RENDERBUFFER, output->rbo[i]);
358
359                 output->bo[i] =
360                         gbm_bo_create(ec->gbm,
361                                       output->base.current->width,
362                                       output->base.current->height,
363                                       GBM_BO_FORMAT_XRGB8888,
364                                       GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
365                 output->image[i] = ec->base.create_image(ec->base.display,
366                                                          NULL,
367                                                          EGL_NATIVE_PIXMAP_KHR,
368                                                          output->bo[i], NULL);
369
370                 weston_log("output->image[i]: %p\n", output->image[i]);
371                 ec->base.image_target_renderbuffer_storage(GL_RENDERBUFFER,
372                                                            output->image[i]);
373                 output->source[i] =
374                         wfdCreateSourceFromImage(ec->dev, output->pipeline,
375                                                  output->image[i], NULL);
376
377                 if (output->source[i] == WFD_INVALID_HANDLE) {
378                         weston_log("failed to create source\n");
379                         goto cleanup_pipeline;
380                 }
381         }
382
383         output->current = 0;
384         glFramebufferRenderbuffer(GL_FRAMEBUFFER,
385                                   GL_COLOR_ATTACHMENT0,
386                                   GL_RENDERBUFFER,
387                                   output->rbo[output->current]);
388
389         wfdSetPipelineAttribiv(ec->dev, output->pipeline,
390                                WFD_PIPELINE_SOURCE_RECTANGLE,
391                                4, geometry.array);
392         wfdSetPipelineAttribiv(ec->dev, output->pipeline,
393                                WFD_PIPELINE_DESTINATION_RECTANGLE,
394                                4, geometry.array);
395
396         wfdBindSourceToPipeline(ec->dev, output->pipeline,
397                                 output->source[output->current ^ 1],
398                                 WFD_TRANSITION_AT_VSYNC, NULL);
399
400         wfdBindPipelineToPort(ec->dev, output->port, output->pipeline);
401
402         wfdDeviceCommit(ec->dev, WFD_COMMIT_ENTIRE_DEVICE, WFD_INVALID_HANDLE);
403
404         output->base.origin = output->base.current;
405         output->base.repaint = wfd_output_repaint;
406         output->base.prepare_scanout_surface =
407                 wfd_output_prepare_scanout_surface;
408         output->base.set_hardware_cursor = wfd_output_set_cursor;
409         output->base.destroy = wfd_output_destroy;
410         output->base.assign_planes = NULL;
411         output->base.set_backlight = NULL;
412         output->base.set_dpms = NULL;
413         output->base.switch_mode = NULL;
414
415         wl_list_insert(ec->base.output_list.prev, &output->base.link);
416
417         return 0;
418
419 cleanup_pipeline:
420         wfdDestroyPipeline(ec->dev, output->pipeline);
421 cleanup_weston_output:
422         weston_output_destroy(&output->base);
423 cleanup_pipelines:
424         free(pipelines);
425 cleanup_port:
426         wfdDestroyPort(ec->dev, output->port);
427         free(output);
428
429         return -1;
430 }
431
432 static int
433 create_outputs(struct wfd_compositor *ec, int option_connector)
434 {
435         int x = 0, y = 0;
436         WFDint i, num, *ports;
437         WFDPort port = WFD_INVALID_HANDLE;
438
439         num = wfdEnumeratePorts(ec->dev, NULL, 0, NULL);
440         ports = calloc(num, sizeof *ports);
441         if (ports == NULL)
442                 return -1;
443
444         num = wfdEnumeratePorts(ec->dev, ports, num, NULL);
445         if (num < 1)
446                 return -1;
447
448         for (i = 0; i < num; ++i) {
449                 port = wfdCreatePort(ec->dev, ports[i], NULL);
450                 if (port == WFD_INVALID_HANDLE)
451                         continue;
452
453                 if (wfdGetPortAttribi(ec->dev, port, WFD_PORT_ATTACHED) &&
454                     (option_connector == 0 || ports[i] == option_connector)) {
455                         create_output_for_port(ec, port, x, y);
456
457                         x += container_of(ec->base.output_list.prev,
458                                           struct weston_output,
459                                           link)->current->width;
460                 } else {
461                         wfdDestroyPort(ec->dev, port);
462                 }
463         }
464
465         free(ports);
466
467         return 0;
468 }
469
470 static int
471 handle_port_state_change(struct wfd_compositor *ec)
472 {
473         struct wfd_output *output, *next;
474         WFDint output_port_id;
475         int x = 0, y = 0;
476         int x_offset = 0, y_offset = 0;
477         WFDPort port;
478         WFDint port_id;
479         WFDboolean state;
480
481         port_id = wfdGetEventAttribi(ec->dev, ec->event,
482                                      WFD_EVENT_PORT_ATTACH_PORT_ID);
483         state = wfdGetEventAttribi(ec->dev, ec->event,
484                                    WFD_EVENT_PORT_ATTACH_STATE);
485
486         if (state) {
487                 struct weston_output *last_output =
488                         container_of(ec->base.output_list.prev,
489                                      struct weston_output, link);
490
491                 /* XXX: not yet needed, we die with 0 outputs */
492                 if (!wl_list_empty(&ec->base.output_list))
493                         x = last_output->x +
494                                 last_output->current->width;
495                 else
496                         x = 0;
497                 y = 0;
498
499                 port = wfdCreatePort(ec->dev, port_id, NULL);
500                 if (port == WFD_INVALID_HANDLE)
501                         return -1;
502
503                 create_output_for_port(ec, port, x, y);
504
505                 return 0;
506         }
507
508         wl_list_for_each_safe(output, next, &ec->base.output_list, base.link) {
509                 output_port_id =
510                         wfdGetPortAttribi(ec->dev, output->port, WFD_PORT_ID);
511
512                 if (!state && output_port_id == port_id) {
513                         x_offset += output->base.current->width;
514                         wfd_output_destroy(&output->base);
515                         continue;
516                 }
517
518                 if (x_offset != 0 || y_offset != 0) {
519                         weston_output_move(&output->base,
520                                          output->base.x - x_offset,
521                                          output->base.y - y_offset);
522                 }
523         }
524
525         if (ec->used_pipelines == 0)
526                 wl_display_terminate(ec->base.wl_display);
527
528         return 0;
529 }
530
531 static int
532 on_wfd_event(int fd, uint32_t mask, void *data)
533 {
534         struct wfd_compositor *c = data;
535         struct wfd_output *output = NULL, *output_iter;
536         WFDEventType type;
537         const WFDtime timeout = 0;
538         WFDint pipeline_id;
539         WFDint bind_time;
540
541         type = wfdDeviceEventWait(c->dev, c->event, timeout);
542
543         switch (type) {
544         case WFD_EVENT_PIPELINE_BIND_SOURCE_COMPLETE:
545                 pipeline_id =
546                         wfdGetEventAttribi(c->dev, c->event,
547                                            WFD_EVENT_PIPELINE_BIND_PIPELINE_ID);
548
549                 bind_time =
550                         wfdGetEventAttribi(c->dev, c->event,
551                                            WFD_EVENT_PIPELINE_BIND_TIME_EXT);
552
553                 wl_list_for_each(output_iter, &c->base.output_list, base.link) {
554                         if (output_iter->pipeline_id == pipeline_id)
555                                 output = output_iter;
556                 }
557
558                 if (output == NULL)
559                         return 1;
560
561                 weston_output_finish_frame(&output->base,
562                                          c->start_time + bind_time);
563                 break;
564         case WFD_EVENT_PORT_ATTACH_DETACH:
565                 handle_port_state_change(c);
566                 break;
567         default:
568                 return 1;
569         }
570
571         return 1;
572 }
573
574 static void
575 wfd_destroy(struct weston_compositor *ec)
576 {
577         struct wfd_compositor *d = (struct wfd_compositor *) ec;
578
579         weston_compositor_shutdown(ec);
580
581         udev_unref(d->udev);
582
583         wfdDestroyDevice(d->dev);
584
585         tty_destroy(d->tty);
586
587         free(d);
588 }
589
590 /* FIXME: Just add a stub here for now
591  * handle drm{Set,Drop}Master in owfdrm somehow */
592 static void
593 vt_func(struct weston_compositor *compositor, int event)
594 {
595         return;
596 }
597
598 static const char default_seat[] = "seat0";
599
600 static struct weston_compositor *
601 wfd_compositor_create(struct wl_display *display,
602                       int connector, const char *seat, int tty)
603 {
604         struct wfd_compositor *ec;
605         struct wl_event_loop *loop;
606         struct timeval tv;
607
608         ec = malloc(sizeof *ec);
609         if (ec == NULL)
610                 return NULL;
611
612         memset(ec, 0, sizeof *ec);
613
614         gettimeofday(&tv, NULL);
615         ec->start_time = tv.tv_sec * 1000 + tv.tv_usec / 1000;
616
617         ec->udev = udev_new();
618         if (ec->udev == NULL) {
619                 weston_log("failed to initialize udev context\n");
620                 return NULL;
621         }
622
623         ec->dev = wfdCreateDevice(WFD_DEFAULT_DEVICE_ID, NULL);
624         if (ec->dev == WFD_INVALID_HANDLE) {
625                 weston_log("failed to create wfd device\n");
626                 return NULL;
627         }
628
629         ec->event = wfdCreateEvent(ec->dev, NULL);
630         if (ec->event == WFD_INVALID_HANDLE) {
631                 weston_log("failed to create wfd event\n");
632                 return NULL;
633         }
634
635         ec->base.wl_display = display;
636         if (init_egl(ec) < 0) {
637                 weston_log("failed to initialize egl\n");
638                 return NULL;
639         }
640
641         ec->base.destroy = wfd_destroy;
642         ec->base.focus = 1;
643
644         glGenFramebuffers(1, &ec->base.fbo);
645         glBindFramebuffer(GL_FRAMEBUFFER, ec->base.fbo);
646
647         /* Can't init base class until we have a current egl context */
648         if (weston_compositor_init(&ec->base, display) < 0)
649                 return NULL;
650
651         if (create_outputs(ec, connector) < 0) {
652                 weston_log("failed to create outputs\n");
653                 return NULL;
654         }
655
656         evdev_input_create(&ec->base, ec->udev, seat);
657
658         loop = wl_display_get_event_loop(ec->base.wl_display);
659         ec->wfd_source =
660                 wl_event_loop_add_fd(loop,
661                                      wfdDeviceEventGetFD(ec->dev, ec->event),
662                                      WL_EVENT_READABLE, on_wfd_event, ec);
663         ec->tty = tty_create(&ec->base, vt_func, tty);
664
665         return &ec->base;
666 }
667
668 WL_EXPORT struct weston_compositor *
669 backend_init(struct wl_display *display, int argc, char *argv[])
670 {
671         int connector = 0, tty = 0;
672         const char *seat;
673
674         const struct weston_option wfd_options[] = {
675                 { WESTON_OPTION_INTEGER, "connector", 0, &connector },
676                 { WESTON_OPTION_STRING, "seat", 0, &seat },
677                 { WESTON_OPTION_INTEGER, "tty", 0, &tty },
678         };
679
680         parse_options(&wfd_options, ARRAY_LENGTH(wfd_options), argc, argv);
681
682         return wfd_compositor_create(display, connector, seat, tty);
683 }