Initial version of headless-server
[platform/core/uifw/headless-server.git] / src / output / output_led.c
1 /*
2 * Copyright © 2019 Samsung Electronics co., Ltd. All Rights Reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28
29 #include <tbm_bufmgr.h>
30 #include <wayland-tbm-server.h>
31 #include <pepper-output-backend.h>
32 #include "HL_UI_LED.h"
33 #include "output_internal.h"
34
35 static const int KEY_OUTPUT;
36 static void led_output_add_frame_done(led_output_t *output);
37 static void led_output_update(led_output_t *output);
38
39 static void
40 led_output_destroy(void *data)
41 {
42         led_output_t *output = (led_output_t *)data;
43         PEPPER_TRACE("Output Destroy %p base %p\n", output, output->output);
44
45         if (output->ui_led) {
46                 HL_UI_LED_Close(output->ui_led);
47                 output->ui_led = NULL;
48         }
49
50         if (output->tbm_server) {
51                 wayland_tbm_server_deinit(output->tbm_server);
52                 output->tbm_server = NULL;
53         }
54 }
55
56 static int32_t
57 led_output_get_subpixel_order(void *o)
58 {
59         return 0;
60 }
61
62 static const char *
63 led_output_get_maker_name(void *o)
64 {
65         return "PePPer LED";
66 }
67
68 static const char *
69 led_output_get_model_name(void *o)
70 {
71         return "PePPer LED";
72 }
73
74 static int
75 led_output_get_mode_count(void *o)
76 {
77         return 1;
78 }
79
80 static void
81 led_output_get_mode(void *o, int index, pepper_output_mode_t *mode)
82 {
83         led_output_t *output = (led_output_t *)o;
84
85         PEPPER_TRACE("[OUTPUT]\n");
86
87         if (index != 0)
88                 return;
89
90         mode->flags = WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
91         mode->w = output->num_led;
92         mode->h = output->num_led;
93         mode->refresh = 60000;
94 }
95
96 static pepper_bool_t
97 led_output_set_mode(void *o, const pepper_output_mode_t *mode)
98 {
99         return PEPPER_FALSE;
100 }
101
102 static void
103 led_output_assign_planes(void *o, const pepper_list_t *view_list)
104 {
105         led_output_t *output = (led_output_t *)o;
106         pepper_list_t *l;
107         pepper_view_t *view, *top_view = NULL;
108
109         PEPPER_TRACE("[OUTPUT] Assign plane\n");
110         pepper_list_for_each_list(l, view_list) {
111                 view = (pepper_view_t*)l->item;
112
113                 if (pepper_view_is_mapped(view) && pepper_view_is_visible(view)) {
114                         top_view = view;
115                         break;
116                 }
117         }
118
119         if (output->top_view != top_view)
120                 PEPPER_TRACE("\tTop-View is changed(%p -> %p)\n", output->top_view, top_view);
121
122         output->top_view = top_view;
123 }
124
125 static void
126 led_output_start_repaint_loop(void *o)
127 {
128         led_output_t *output = (led_output_t *)o;
129         struct timespec     ts;
130
131         PEPPER_TRACE("[OUTPUT] Start reapint loop\n");
132         pepper_compositor_get_time(output->compositor, &ts);
133         pepper_output_finish_frame(output->output, &ts);
134 }
135
136 static void
137 led_output_repaint(void *o, const pepper_list_t *plane_list)
138 {
139         pepper_list_t *l;
140         pepper_plane_t *plane;
141         led_output_t *output = (led_output_t *)o;
142
143         PEPPER_TRACE("[OUTPUT] Repaint\n");
144
145         pepper_list_for_each_list(l, plane_list) {
146                 plane = (pepper_plane_t *)l->item;
147                 pepper_plane_clear_damage_region(plane);
148         }
149
150         led_output_update(output);
151         led_output_add_frame_done(output);
152 }
153
154 static void
155 led_output_attach_surface(void *o, pepper_surface_t *surface, int *w, int *h)
156 {
157         *w = 10;
158         *h = 10;
159         PEPPER_TRACE("[OUTPUT] attach surface:%p\n", surface);
160 }
161
162 static void
163 led_output_flush_surface_damage(void *o, pepper_surface_t *surface, pepper_bool_t *keep_buffer)
164 {
165         *keep_buffer = PEPPER_TRUE;
166         PEPPER_TRACE("[OUTPUT] flush_surface_damage surface:%p\n", surface);
167 }
168
169 struct pepper_output_backend led_output_backend = {
170         led_output_destroy,
171
172         led_output_get_subpixel_order,
173         led_output_get_maker_name,
174         led_output_get_model_name,
175
176         led_output_get_mode_count,
177         led_output_get_mode,
178         led_output_set_mode,
179
180         led_output_assign_planes,
181         led_output_start_repaint_loop,
182         led_output_repaint,
183         led_output_attach_surface,
184         led_output_flush_surface_damage,
185 };
186
187 static void
188 led_output_update_led(led_output_t *output, unsigned char *data)
189 {
190         int i;
191         uint8_t *ptr = (uint8_t *)data;
192
193         if (data == NULL) {
194                 PEPPER_TRACE("[OUTPUT] update LED to empty\n");
195                 HL_UI_LED_Clear_All(output->ui_led);
196                 return;
197         }
198
199         for(i=0; i<output->num_led; i++) {
200                 HL_UI_LED_Set_Pixel_RGB(output->ui_led, i, ptr[R_OFF_SET], ptr[G_OFF_SET], ptr[B_OFF_SET]);
201                 ptr += 4;
202         }
203
204         HL_UI_LED_Refresh(output->ui_led);
205 }
206
207 static void
208 led_output_update(led_output_t *output)
209 {
210         pepper_buffer_t *buf;
211         pepper_surface_t *surface;
212         struct wl_resource *buf_res;
213         tbm_surface_h tbm_surface;
214         tbm_surface_info_s info;
215         int ret;
216
217         if (!output->top_view) {
218                 if (!output->ui_led)
219                         PEPPER_TRACE("[UPDATE LED] Empty Display\n");
220                 else
221                         led_output_update_led(output, NULL);
222
223                 return;
224         }
225
226         surface = pepper_view_get_surface(output->top_view);
227         PEPPER_CHECK(surface, return, "fail to get a surafce from a view(%p)\n", output->top_view);
228
229         buf = pepper_surface_get_buffer(surface);
230         PEPPER_CHECK(buf, return, "fail to get a pepper_buffer from a surface(%p)\n", surface);
231
232         buf_res = pepper_buffer_get_resource(buf);
233         tbm_surface = wayland_tbm_server_get_surface(NULL, buf_res);
234         PEPPER_CHECK(tbm_surface, return, "fail to get a tbm_surface from a pepper_buffer(%p)\n", buf);
235
236         ret = tbm_surface_map(tbm_surface, TBM_SURF_OPTION_READ, &info);
237         PEPPER_CHECK(ret == TBM_SURFACE_ERROR_NONE, return, "fail to map the tbm_surface\n");
238
239         if (!output->ui_led)
240                 PEPPER_TRACE("[UPDATE LED] %s\n", (char*)info.planes[0].ptr);
241         else
242                 led_output_update_led(output, info.planes[0].ptr);
243
244         tbm_surface_unmap(tbm_surface);
245 }
246
247 static void
248 led_output_cb_frame_done(void *data)
249 {
250         led_output_t *output = (led_output_t *)data;
251
252         PEPPER_TRACE("[OUTPUT] frame_done %p\n", output);
253         output->frame_done = NULL;
254
255         pepper_output_finish_frame(output->output, NULL);
256 }
257
258 static void
259 led_output_add_frame_done(led_output_t *output)
260 {
261         struct wl_event_loop *loop;
262
263         PEPPER_TRACE("[OUTPUT] Add idle for frame(output:%p, frame_done:%p)\n", output, output->frame_done);
264
265         if (!output || output->frame_done) {
266                 PEPPER_TRACE("[OUTPUT] skip add frame_done\n");
267                 return;
268         }
269
270         loop = wl_display_get_event_loop(pepper_compositor_get_display(output->compositor));
271         PEPPER_CHECK(loop, return, "[OUTPUT] fail to get event loop\n");
272
273         output->frame_done = wl_event_loop_add_idle(loop, led_output_cb_frame_done, output);
274         PEPPER_CHECK(output->frame_done, return, "[OUTPUT] fail to add idle\n");
275 }
276
277 static void
278 pepper_output_bind_display(led_output_t *output)
279 {
280         tbm_bufmgr bufmgr = NULL;
281
282         PEPPER_CHECK(getenv("TBM_DISPLAY_SERVER"), return, "[TBM] run the subcompoitor mode\n");
283
284         bufmgr = wayland_tbm_server_get_bufmgr(output->tbm_server);
285         PEPPER_CHECK(bufmgr, return, "fail to get tbm_bufmgr\n");
286
287         if (!tbm_bufmgr_bind_native_display(bufmgr, (void *)pepper_compositor_get_display(output->compositor)))
288         {
289                 PEPPER_CHECK(0, return, "fail to tbm_bufmgr_bind_native_display\n");
290         }
291
292         return;
293 }
294
295 pepper_bool_t
296 headless_output_init(pepper_compositor_t *compositor)
297 {
298         led_output_t *output = (led_output_t*)calloc(sizeof(led_output_t), 1);
299
300         PEPPER_TRACE("Output Init\n");
301
302         if (!output) {
303                 PEPPER_ERROR("Failed to allocate memory in %s\n", __FUNCTION__);
304                 goto error;
305         }
306
307         output->compositor = compositor;
308         output->tbm_server = wayland_tbm_server_init(pepper_compositor_get_display(compositor), NULL, -1, 0);
309         PEPPER_CHECK(output->tbm_server, goto error, "failed to wayland_tbm_server_init.\n");
310
311         pepper_output_bind_display(output);
312
313         output->num_led = NUM_LED;
314         output->ui_led = HL_UI_LED_Init(output->num_led);
315         if (output->ui_led) HL_UI_LED_Change_Brightness(output->ui_led, 0x1);
316
317         if (!output->ui_led)
318                 PEPPER_ERROR("HL_UI_LED_Init() failed.\n");
319         else
320                 boot_ani_start(output);
321
322         output->output = pepper_compositor_add_output(compositor,
323                         &led_output_backend, "led_output",
324                         output,  WL_OUTPUT_TRANSFORM_NORMAL, 1);
325         PEPPER_CHECK(output->output, goto error, "pepper_compositor_add_output() failed.\n");
326
327         output->plane = pepper_output_add_plane(output->output, NULL);
328         PEPPER_CHECK(output->plane, goto error, "pepper_output_add_plane() failed.\n");
329
330         pepper_object_set_user_data((pepper_object_t *)compositor,
331                         &KEY_OUTPUT, output, NULL);
332         PEPPER_TRACE("\t Add Output %p, base %p\n", output, output->output);
333         PEPPER_TRACE("\t Add Output %p, plane %p\n", output, output->plane);
334         PEPPER_TRACE("\t Userdata %p\n", pepper_object_get_user_data((pepper_object_t *)compositor,&KEY_OUTPUT));
335         return PEPPER_TRUE;
336
337 error:
338         if (output->ui_led)
339                 HL_UI_LED_Close(output->ui_led);
340
341         if (output->tbm_server)
342                 wayland_tbm_server_deinit(output->tbm_server);
343
344         if (output->output)
345                 pepper_output_destroy(output->output);
346
347         if (output)
348                 free(output);
349         return PEPPER_FALSE;
350 }
351
352 void
353 headless_output_deinit(pepper_compositor_t *compositor)
354 {
355         led_output_t *output;
356
357
358         output = pepper_object_get_user_data((pepper_object_t *)compositor, &KEY_OUTPUT);
359
360         if (output) {
361                 pepper_object_set_user_data((pepper_object_t *)compositor, &KEY_OUTPUT, NULL, NULL);
362
363                 if (output->boot_ani) {
364                         boot_ani_stop(output);
365                 }
366
367                 pepper_output_destroy(output->output);
368                 led_output_destroy(output);
369
370                 free(output);
371         }
372
373         PEPPER_TRACE("Output Deinit ... DONE\n");
374 }