Revert "Use appid between homescreen-service and apps"
[src/libhomescreen.git] / sample / simple-egl / src / simple-egl.cpp
1 /*
2  * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
3  * Copyright © 2011 Benjamin Franzke
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  */
24
25 #include <mutex>
26 #include <chrono>
27
28 #include <iostream>
29 #include <string>
30 #include <stdarg.h>
31 #include <sys/types.h>
32 #include <thread>
33 #include <exception>
34 #include <vector>
35 #include <sstream>
36
37 #include <assert.h>
38 #include <signal.h>
39
40 #include <wayland-client.h>
41 #include <wayland-egl.h>
42
43 #include <GLES2/gl2.h>
44 #include <EGL/egl.h>
45 #include <EGL/eglext.h>
46
47 #include <unistd.h>
48 #include <time.h>
49
50 #include <libwindowmanager.h>
51 #include <libhomescreen.hpp>
52
53 #include <ilm/ivi-application-client-protocol.h>
54 #include "hmi-debug.h"
55
56 using namespace std;
57
58
59 uint32_t g_id_ivisurf = 9009;
60 long port = 1700;
61 string token = string("wm");
62
63 string app_name = string("Navigation");
64
65 LibHomeScreen* hs;
66 LibWindowmanager *wm;
67
68 static const struct wl_interface *types[] = {
69         NULL,
70         NULL,
71         NULL,
72         &wl_surface_interface,
73         &ivi_surface_interface,
74 };
75
76 static const struct wl_message ivi_surface_requests[] = {
77         { "destroy", "", types + 0 },
78 };
79
80 static const struct wl_message ivi_surface_events[] = {
81         { "configure", "ii", types + 0 },
82 };
83
84 const struct wl_interface ivi_surface_interface = {
85         "ivi_surface", 1,
86         1, ivi_surface_requests,
87         1, ivi_surface_events,
88 };
89
90 static const struct wl_message ivi_application_requests[] = {
91         { "surface_create", "uon", types + 2 },
92 };
93
94 const struct wl_interface ivi_application_interface = {
95         "ivi_application", 1,
96         1, ivi_application_requests,
97         0, NULL,
98 };
99
100 #include "platform.h"
101
102 #ifndef EGL_EXT_swap_buffers_with_damage
103 #define EGL_EXT_swap_buffers_with_damage 1
104 typedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC)(EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint n_rects);
105 #endif
106
107 #ifndef EGL_EXT_buffer_age
108 #define EGL_EXT_buffer_age 1
109 #define EGL_BUFFER_AGE_EXT                      0x313D
110 #endif
111
112 struct window;
113 struct seat;
114
115 struct display {
116         struct wl_display *display;
117         struct wl_registry *registry;
118         struct wl_compositor *compositor;
119         struct wl_seat *seat;
120         struct {
121                 EGLDisplay dpy;
122                 EGLContext ctx;
123                 EGLConfig conf;
124         } egl;
125         struct window *window;
126         struct ivi_application *ivi_application;
127
128         PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC swap_buffers_with_damage;
129 };
130
131 struct geometry {
132         int width, height;
133 };
134
135 struct window {
136         struct display *display;
137         struct geometry geometry, window_size;
138         struct {
139                 GLuint rotation_uniform;
140                 GLuint pos;
141                 GLuint col;
142         } gl;
143
144         uint32_t benchmark_time, frames;
145         struct wl_egl_window *native;
146         struct wl_surface *surface;
147         struct ivi_surface *ivi_surface;
148         EGLSurface egl_surface;
149         struct wl_callback *callback;
150         int fullscreen, opaque, buffer_size, frame_sync;
151 };
152
153 static const char *vert_shader_text =
154         "uniform mat4 rotation;\n"
155         "attribute vec4 pos;\n"
156         "attribute vec4 color;\n"
157         "varying vec4 v_color;\n"
158         "void main() {\n"
159         "  gl_Position = rotation * pos;\n"
160         "  v_color = color;\n"
161         "}\n";
162
163 static const char *frag_shader_text =
164         "precision mediump float;\n"
165         "varying vec4 v_color;\n"
166         "void main() {\n"
167         "  gl_FragColor = v_color;\n"
168         "}\n";
169
170 static int running = 1;
171
172 static void
173 init_egl(struct display *display, struct window *window)
174 {
175         static const EGLint context_attribs[] = {
176                 EGL_CONTEXT_CLIENT_VERSION, 2,
177                 EGL_NONE
178         };
179         const char *extensions;
180
181         EGLint config_attribs[] = {
182                 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
183                 EGL_RED_SIZE, 1,
184                 EGL_GREEN_SIZE, 1,
185                 EGL_BLUE_SIZE, 1,
186                 EGL_ALPHA_SIZE, 1,
187                 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
188                 EGL_NONE
189         };
190
191         EGLint major, minor, n, count, i, size;
192         EGLConfig *configs;
193         EGLBoolean ret;
194
195         if (window->opaque || window->buffer_size == 16)
196                 config_attribs[9] = 0;
197         
198         display->egl.dpy = weston_platform_get_egl_display(EGL_PLATFORM_WAYLAND_KHR, display->display, NULL);
199         assert(display->egl.dpy);
200
201         ret = eglInitialize(display->egl.dpy, &major, &minor);
202         assert(ret == EGL_TRUE);
203         ret = eglBindAPI(EGL_OPENGL_ES_API);
204         assert(ret == EGL_TRUE);
205
206         if (!eglGetConfigs(display->egl.dpy, NULL, 0, &count) || count < 1)
207                 assert(0);
208
209         configs = calloc(count, sizeof *configs);
210         assert(configs);
211
212         ret = eglChooseConfig(display->egl.dpy, config_attribs,
213                               configs, count, &n);
214         assert(ret && n >= 1);
215
216         for (i = 0; i < n; i++) {
217                 eglGetConfigAttrib(display->egl.dpy,
218                                    configs[i], EGL_BUFFER_SIZE, &size);
219                 if (window->buffer_size == size) {
220                         display->egl.conf = configs[i];
221                         break;
222                 }
223         }
224         free(configs);
225         if (display->egl.conf == NULL) {
226                 HMI_ERROR("simple-egl","did not find config with buffer size %d",
227                         window->buffer_size);
228                 exit(EXIT_FAILURE);
229         }
230
231         display->egl.ctx = eglCreateContext(display->egl.dpy,
232                                             display->egl.conf,
233                                             EGL_NO_CONTEXT, context_attribs);
234         assert(display->egl.ctx);
235
236         display->swap_buffers_with_damage = NULL;
237         extensions = eglQueryString(display->egl.dpy, EGL_EXTENSIONS);
238         if (extensions &&
239             strstr(extensions, "EGL_EXT_swap_buffers_with_damage") &&
240             strstr(extensions, "EGL_EXT_buffer_age"))
241                 display->swap_buffers_with_damage =
242                         (PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC)
243                         eglGetProcAddress("eglSwapBuffersWithDamageEXT");
244
245         if (display->swap_buffers_with_damage)
246                 HMI_DEBUG("simple-egl","has EGL_EXT_buffer_age and EGL_EXT_swap_buffers_with_damage");
247
248 }
249
250 static void
251 fini_egl(struct display *display)
252 {
253         eglTerminate(display->egl.dpy);
254         eglReleaseThread();
255 }
256
257 static GLuint
258 create_shader(struct window *window, const char *source, GLenum shader_type)
259 {
260         GLuint shader;
261         GLint status;
262
263         shader = glCreateShader(shader_type);
264         assert(shader != 0);
265
266         glShaderSource(shader, 1, (const char **) &source, NULL);
267         glCompileShader(shader);
268
269         glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
270         if (!status) {
271                 char log[1000];
272                 GLsizei len;
273                 glGetShaderInfoLog(shader, 1000, &len, log);
274                 HMI_ERROR("simple-egl","Error: compiling %s: %*s",
275                         shader_type == GL_VERTEX_SHADER ? "vertex" : "fragment",
276                         len, log);
277                 exit(1);
278         }
279
280         return shader;
281 }
282
283 static void
284 init_gl(struct window *window)
285 {
286         GLuint frag, vert;
287         GLuint program;
288         GLint status;
289
290         frag = create_shader(window, frag_shader_text, GL_FRAGMENT_SHADER);
291         vert = create_shader(window, vert_shader_text, GL_VERTEX_SHADER);
292
293         program = glCreateProgram();
294         glAttachShader(program, frag);
295         glAttachShader(program, vert);
296         glLinkProgram(program);
297
298         glGetProgramiv(program, GL_LINK_STATUS, &status);
299         if (!status) {
300                 char log[1000];
301                 GLsizei len;
302                 glGetProgramInfoLog(program, 1000, &len, log);
303                 HMI_ERROR("simple-egl","Error: linking:%*s", len, log);
304                 exit(1);
305         }
306
307         glUseProgram(program);
308
309         window->gl.pos = 0;
310         window->gl.col = 1;
311
312         glBindAttribLocation(program, window->gl.pos, "pos");
313         glBindAttribLocation(program, window->gl.col, "color");
314         glLinkProgram(program);
315
316         window->gl.rotation_uniform =
317                 glGetUniformLocation(program, "rotation");
318 }
319
320 static void
321 create_ivi_surface(struct window *window, struct display *display)
322 {
323         uint32_t id_ivisurf = g_id_ivisurf;
324         window->ivi_surface =
325                 ivi_application_surface_create(display->ivi_application,
326                                                id_ivisurf, window->surface);
327
328         if (window->ivi_surface == NULL) {
329                 HMI_ERROR("simple-egl","Failed to create ivi_client_surface");
330                 abort();
331         }
332
333 }
334
335 static void
336 create_surface(struct window *window)
337 {
338         struct display *display = window->display;
339         EGLBoolean ret;
340
341         window->surface = wl_compositor_create_surface(display->compositor);
342
343         window->native =
344                 wl_egl_window_create(window->surface,
345                                      window->geometry.width,
346                                      window->geometry.height);
347         window->egl_surface =
348                 weston_platform_create_egl_surface(display->egl.dpy,
349                                                    display->egl.conf,
350                                                    window->native, NULL);
351
352
353         if (display->ivi_application ) {
354                 create_ivi_surface(window, display);
355         } else {
356                 assert(0);
357         }
358
359         ret = eglMakeCurrent(window->display->egl.dpy, window->egl_surface,
360                              window->egl_surface, window->display->egl.ctx);
361         assert(ret == EGL_TRUE);
362
363         if (!window->frame_sync)
364                 eglSwapInterval(display->egl.dpy, 0);
365
366 }
367
368 static void
369 destroy_surface(struct window *window)
370 {
371         /* Required, otherwise segfault in egl_dri2.c: dri2_make_current()
372          * on eglReleaseThread(). */
373         eglMakeCurrent(window->display->egl.dpy, EGL_NO_SURFACE, EGL_NO_SURFACE,
374                        EGL_NO_CONTEXT);
375
376         eglDestroySurface(window->display->egl.dpy, window->egl_surface);
377         wl_egl_window_destroy(window->native);
378
379         if (window->display->ivi_application)
380                 ivi_surface_destroy(window->ivi_surface);
381         wl_surface_destroy(window->surface);
382
383         if (window->callback)
384                 wl_callback_destroy(window->callback);
385 }
386
387 static void
388 redraw(void *data, struct wl_callback *callback, uint32_t time)
389 {
390         struct window *window = data;
391         struct display *display = window->display;
392         static const GLfloat verts[3][2] = {
393                 { -0.5, -0.5 },
394                 {  0.5, -0.5 },
395                 {  0,    0.5 }
396         };
397
398         static const GLfloat colors[3][3] = {
399                 { 1, 0, 0 },
400                 { 0, 1, 0 },
401                 { 0, 0, 1 }
402         };
403
404         GLfloat angle;
405         GLfloat rotation[4][4] = {
406                 { 1, 0, 0, 0 },
407                 { 0, 1, 0, 0 },
408                 { 0, 0, 1, 0 },
409                 { 0, 0, 0, 1 }
410         };
411         static const uint32_t speed_div = 5, benchmark_interval = 5;
412         struct wl_region *region;
413         EGLint rect[4];
414         EGLint buffer_age = 0;
415         struct timeval tv;
416
417         assert(window->callback == callback);
418         window->callback = NULL;
419
420         if (callback)
421                 wl_callback_destroy(callback);
422
423         gettimeofday(&tv, NULL);
424         time = tv.tv_sec * 1000 + tv.tv_usec / 1000;
425         if (window->frames == 0)
426                 window->benchmark_time = time;
427
428         if (time - window->benchmark_time > (benchmark_interval * 1000)) {
429                 HMI_DEBUG("simple-egl","%d frames in %d seconds: %f fps",
430                        window->frames,
431                        benchmark_interval,
432                        (float) window->frames / benchmark_interval);
433                 window->benchmark_time = time;
434                 window->frames = 0;
435         }
436
437         angle = (time / speed_div) % 360 * M_PI / 180.0;
438         rotation[0][0] =  cos(angle);
439         rotation[0][2] =  sin(angle);
440         rotation[2][0] = -sin(angle);
441         rotation[2][2] =  cos(angle);
442
443         if (display->swap_buffers_with_damage)
444                 eglQuerySurface(display->egl.dpy, window->egl_surface,
445                                 EGL_BUFFER_AGE_EXT, &buffer_age);
446
447         glViewport(0, 0, window->geometry.width, window->geometry.height);
448
449         glUniformMatrix4fv(window->gl.rotation_uniform, 1, GL_FALSE,
450                            (GLfloat *) rotation);
451
452         glClearColor(0.0, 0.0, 0.0, 0.5);
453         glClear(GL_COLOR_BUFFER_BIT);
454
455         glVertexAttribPointer(window->gl.pos, 2, GL_FLOAT, GL_FALSE, 0, verts);
456         glVertexAttribPointer(window->gl.col, 3, GL_FLOAT, GL_FALSE, 0, colors);
457         glEnableVertexAttribArray(window->gl.pos);
458         glEnableVertexAttribArray(window->gl.col);
459
460         glDrawArrays(GL_TRIANGLES, 0, 3);
461
462         glDisableVertexAttribArray(window->gl.pos);
463         glDisableVertexAttribArray(window->gl.col);
464
465         if (window->opaque || window->fullscreen) {
466                 region = wl_compositor_create_region(window->display->compositor);
467                 wl_region_add(region, 0, 0,
468                               window->geometry.width,
469                               window->geometry.height);
470                 wl_surface_set_opaque_region(window->surface, region);
471                 wl_region_destroy(region);
472         } else {
473                 wl_surface_set_opaque_region(window->surface, NULL);
474         }
475
476         if (display->swap_buffers_with_damage && buffer_age > 0) {
477                 rect[0] = window->geometry.width / 4 - 1;
478                 rect[1] = window->geometry.height / 4 - 1;
479                 rect[2] = window->geometry.width / 2 + 2;
480                 rect[3] = window->geometry.height / 2 + 2;
481                 display->swap_buffers_with_damage(display->egl.dpy,
482                                                   window->egl_surface,
483                                                   rect, 1);
484         } else {
485                 eglSwapBuffers(display->egl.dpy, window->egl_surface);
486         }
487     
488         window->frames++;
489 }
490
491 static void
492 registry_handle_global(void *data, struct wl_registry *registry,
493                        uint32_t name, const char *interface, uint32_t version)
494 {
495         struct display *d = data;
496
497         if (strcmp(interface, "wl_compositor") == 0) {
498                 d->compositor =
499                         wl_registry_bind(registry, name,
500                                          &wl_compositor_interface, 1);
501         } else if (strcmp(interface, "ivi_application") == 0) {
502                 d->ivi_application =
503                         wl_registry_bind(registry, name,
504                                          &ivi_application_interface, 1);
505         }
506 }
507
508 static void
509 registry_handle_global_remove(void *data, struct wl_registry *registry,
510                               uint32_t name)
511 {
512 }
513
514 static const struct wl_registry_listener registry_listener = {
515         registry_handle_global,
516         registry_handle_global_remove
517 };
518
519 static void
520 signal_int(int signum)
521 {
522         running = 0;
523 }
524
525 int
526 init_wm(LibWindowmanager *wm, struct window *window)
527 {
528         HMI_DEBUG("simple-egl","called");
529
530         if (wm->init(port, token.c_str()) != 0) {
531                 HMI_ERROR("simple-egl","wm init failed. ");
532                 return -1;
533         }
534
535         json_object *obj = json_object_new_object();
536         json_object_object_add(obj, wm->kKeyDrawingName, json_object_new_string(app_name.c_str()));
537         g_id_ivisurf = wm->requestSurface(obj);
538         if (g_id_ivisurf < 0) {
539                 HMI_ERROR("simple-egl","wm request surface failed ");
540                 return -1;
541         }
542         HMI_DEBUG("simple-egl","IVI_SURFACE_ID: %d ", g_id_ivisurf);
543         wm->set_event_handler(LibWindowmanager::Event_SyncDraw, [wm, window](json_object *object) {
544                 const char *label = json_object_get_string(
545                         json_object_object_get(object, wm->kKeyDrawingName));
546                 const char *area = json_object_get_string(
547                         json_object_object_get(object, wm->kKeyDrawingArea));
548
549                 HMI_DEBUG("simple-egl","Surface %s got syncDraw! Area: %s. ", label, area);
550                 if ((wm->kStrLayoutNormal + "." + wm->kStrAreaFull) == std::string(area)) {
551                         wl_egl_window_resize(window->native, 1080, 1488, 0, 0);
552                         window->geometry.width = 1080;
553                         window->geometry.height = 1488;
554                 }
555                 else if ((wm->kStrLayoutSplit + "." + wm->kStrAreaMain) == std::string(area) ||
556                                  (wm->kStrLayoutSplit + "." + wm->kStrAreaSub) == std::string(area)) {
557                         wl_egl_window_resize(window->native, 1080, 744, 0, 0);
558                         window->geometry.width = 1080;
559                         window->geometry.height = 744;
560                 }
561
562                 if (!window->fullscreen)
563                         window->window_size = window->geometry;
564                 json_object *obj = json_object_new_object();
565                 json_object_object_add(obj, wm->kKeyDrawingName, json_object_new_string(app_name.c_str()));
566
567         wm->endDraw(obj);
568     });
569
570         return 0;
571 }
572
573 int
574 init_hs(LibHomeScreen* hs){
575         if(hs->init(port, token)!=0)
576         {
577                 HMI_ERROR("simple-egl","homescreen init failed. ");
578                 return -1;
579         }
580
581         hs->set_event_handler(LibHomeScreen::Event_TapShortcut, [](json_object *object){
582                 const char *application_name = json_object_get_string(
583                         json_object_object_get(object, "application_name"));
584                 HMI_DEBUG("simple-egl","Event_TapShortcut application_name = %s ", application_name);
585                 if(strcmp(application_name, app_name.c_str()) == 0)
586                 {
587                         HMI_DEBUG("simple-egl","try to activesurface %s ", app_name.c_str());
588                         json_object *obj = json_object_new_object();
589                         json_object_object_add(obj, wm->kKeyDrawingName, json_object_new_string(app_name.c_str()));
590                         json_object_object_add(obj, wm->kKeyDrawingArea, json_object_new_string("normal.full"));
591                         wm->activateSurface(obj);
592                 }
593         });
594
595         return 0;
596 }
597
598 int
599 main(int argc, char **argv)
600 {
601         struct sigaction sigint;
602         struct window  window  = { 0 };
603         struct display display = { 0 };
604
605         window.display = &display;
606         display.window = &window;
607         window.geometry.width  = 1080;
608         window.geometry.height = 1488;
609         window.window_size = window.geometry;
610         window.buffer_size = 32;
611         window.frame_sync = 1;
612
613         if(argc > 2){
614                 port = strtol(argv[1], NULL, 10);
615                 token = argv[2];
616         }
617
618         HMI_DEBUG("simple-egl","app_name: %s, port: %d, token: %s. ", app_name.c_str(), port, token.c_str());
619
620         display.display = wl_display_connect(NULL);
621         assert(display.display);
622
623         display.registry = wl_display_get_registry(display.display);
624         wl_registry_add_listener(display.registry,
625                                  &registry_listener, &display);
626
627         wl_display_roundtrip(display.display);
628
629         init_egl(&display, &window);
630
631         wm = new LibWindowmanager();
632         if(init_wm(wm, &window)!=0){
633                 fini_egl(&display);
634                 if (display.ivi_application)
635                         ivi_application_destroy(display.ivi_application);
636                 if (display.compositor)
637                         wl_compositor_destroy(display.compositor);
638                 wl_registry_destroy(display.registry);
639                 wl_display_flush(display.display);
640                 return -1;
641         }
642
643         hs = new LibHomeScreen();
644         if(init_hs(hs)!=0){
645                 fini_egl(&display);
646                 if (display.ivi_application)
647                         ivi_application_destroy(display.ivi_application);
648                 if (display.compositor)
649                         wl_compositor_destroy(display.compositor);
650                 wl_registry_destroy(display.registry);
651                 wl_display_flush(display.display);
652                 return -1;
653         }
654
655         create_surface(&window);
656         init_gl(&window);
657
658         //Ctrl+C
659         sigint.sa_handler = signal_int;
660         sigemptyset(&sigint.sa_mask);
661         sigint.sa_flags = SA_RESETHAND;
662         sigaction(SIGINT, &sigint, NULL);
663
664         eglSwapBuffers(window.display->egl.dpy, window.egl_surface);
665         json_object *obj = json_object_new_object();
666         json_object_object_add(obj, wm->kKeyDrawingName, json_object_new_string(app_name.c_str()));
667         json_object_object_add(obj, wm->kKeyDrawingArea, json_object_new_string("normal.full"));
668         wm->activateSurface(obj);
669
670         /* The mainloop here is a little subtle.  Redrawing will cause
671          * EGL to read events so we can just call
672          * wl_display_dispatch_pending() to handle any events that got
673          * queued up as a side effect. */
674         while (running) {
675                 wl_display_dispatch_pending(display.display);
676                 redraw(&window, NULL, 0);
677         }
678
679         HMI_DEBUG("simple-egl","simple-egl exiting! ");
680
681         destroy_surface(&window);
682         fini_egl(&display);
683
684         if (display.ivi_application)
685                 ivi_application_destroy(display.ivi_application);
686
687         if (display.compositor)
688                 wl_compositor_destroy(display.compositor);
689
690         wl_registry_destroy(display.registry);
691         wl_display_flush(display.display);
692         wl_display_disconnect(display.display);
693
694         return 0;
695 }