vblank: trace the vblank object creation.
[platform/core/uifw/libtdm.git] / src / tdm.c
1 /**************************************************************************
2  *
3  * libtdm
4  *
5  * Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
6  *
7  * Contact: Eunchul Kim <chulspro.kim@samsung.com>,
8  *          JinYoung Jeon <jy0.jeon@samsung.com>,
9  *          Taeheon Kim <th908.kim@samsung.com>,
10  *          YoungJun Cho <yj44.cho@samsung.com>,
11  *          SooChan Lim <sc1.lim@samsung.com>,
12  *          Boram Park <sc1.lim@samsung.com>
13  *
14  * Permission is hereby granted, free of charge, to any person obtaining a
15  * copy of this software and associated documentation files (the
16  * "Software"), to deal in the Software without restriction, including
17  * without limitation the rights to use, copy, modify, merge, publish,
18  * distribute, sub license, and/or sell copies of the Software, and to
19  * permit persons to whom the Software is furnished to do so, subject to
20  * the following conditions:
21  *
22  * The above copyright notice and this permission notice (including the
23  * next paragraph) shall be included in all copies or substantial portions
24  * of the Software.
25  *
26  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
27  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
29  * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
30  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
31  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
32  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33  *
34 **************************************************************************/
35
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
39
40 #include "tdm.h"
41 #include "tdm_backend.h"
42 #include "tdm_private.h"
43 #include "tdm_helper.h"
44 #include <tbm_drm_helper.h>
45
46 pthread_mutex_t tdm_mutex_check_lock = PTHREAD_MUTEX_INITIALIZER;
47 int tdm_mutex_locked;
48 const char *tdm_mutex_lock_func;
49 int tdm_mutex_lock_line;
50 const char *tdm_mutex_unlock_func;
51 int tdm_mutex_unlock_line;
52
53 /* LCOV_EXCL_START */
54 static tdm_private_layer *
55 _tdm_display_find_private_layer(tdm_private_output *private_output,
56                                                                 tdm_layer *layer_backend)
57 {
58         tdm_private_layer *private_layer = NULL;
59
60         LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) {
61                 if (private_layer->layer_backend == layer_backend)
62                         return private_layer;
63         }
64
65         return NULL;
66 }
67
68 static tdm_private_output *
69 _tdm_display_find_private_output(tdm_private_display *private_display,
70                                                                  tdm_output *output_backend)
71 {
72         tdm_private_output *private_output = NULL;
73
74         LIST_FOR_EACH_ENTRY(private_output, &private_display->output_list, link) {
75                 if (private_output->output_backend == output_backend)
76                         return private_output;
77         }
78
79         return NULL;
80 }
81
82 INTERN tdm_private_output *
83 tdm_display_find_output_stamp(tdm_private_display *private_display, double stamp)
84 {
85         tdm_private_output *private_output = NULL;
86
87         LIST_FOR_EACH_ENTRY(private_output, &private_display->output_list, link) {
88                 if (private_output->stamp == stamp)
89                         return private_output;
90         }
91
92         return NULL;
93 }
94
95 static void
96 _tdm_display_destroy_caps_pp(tdm_caps_pp *caps_pp)
97 {
98         if (caps_pp->formats)
99                 free(caps_pp->formats);
100
101         memset(caps_pp, 0, sizeof(tdm_caps_pp));
102 }
103
104 static void
105 _tdm_display_destroy_caps_capture(tdm_caps_capture *caps_capture)
106 {
107         if (caps_capture->formats)
108                 free(caps_capture->formats);
109
110         memset(caps_capture, 0, sizeof(tdm_caps_capture));
111 }
112
113 static void
114 _tdm_display_destroy_caps_layer(tdm_caps_layer *caps_layer)
115 {
116         if (caps_layer->formats)
117                 free(caps_layer->formats);
118
119         if (caps_layer->props)
120                 free(caps_layer->props);
121
122         memset(caps_layer, 0, sizeof(tdm_caps_layer));
123 }
124
125 static void
126 _tdm_display_destroy_caps_output(tdm_caps_output *caps_output)
127 {
128         if (caps_output->modes)
129                 free(caps_output->modes);
130
131         if (caps_output->props)
132                 free(caps_output->props);
133
134         memset(caps_output, 0, sizeof(tdm_caps_output));
135 }
136
137 static void
138 _tdm_display_destroy_private_layer(tdm_private_layer *private_layer)
139 {
140         tdm_private_capture *c = NULL, *cc = NULL;
141
142         LIST_DEL(&private_layer->link);
143
144         LIST_FOR_EACH_ENTRY_SAFE(c, cc, &private_layer->capture_list, link)
145         tdm_capture_destroy_internal(c);
146
147         _tdm_display_destroy_caps_layer(&private_layer->caps);
148
149         free(private_layer);
150 }
151
152 static void
153 _tdm_display_destroy_private_output(tdm_private_output *private_output)
154 {
155         tdm_private_display *private_display = private_output->private_display;
156         tdm_private_layer *l = NULL, *ll = NULL;
157         tdm_private_hwc_window *hw = NULL, *hww = NULL;
158         tdm_private_capture *c = NULL, *cc = NULL;
159         tdm_private_vblank_handler *v = NULL, *vv = NULL;
160         tdm_private_output_commit_handler *om = NULL, *omm = NULL;
161         tdm_private_layer_commit_handler *lm = NULL, *lmm = NULL;
162         tdm_private_change_handler *h = NULL, *hh = NULL;
163
164         LIST_DEL(&private_output->link);
165
166         free(private_output->layers_ptr);
167
168         LIST_FOR_EACH_ENTRY_SAFE(v, vv, &private_output->vblank_handler_list, link) {
169                 LIST_DEL(&v->link);
170                 free(v);
171         }
172
173         LIST_FOR_EACH_ENTRY_SAFE(om, omm, &private_output->output_commit_handler_list, link) {
174                 LIST_DEL(&om->link);
175                 free(om);
176         }
177
178         LIST_FOR_EACH_ENTRY_SAFE(lm, lmm, &private_output->layer_commit_handler_list, link) {
179                 LIST_DEL(&lm->link);
180                 free(lm);
181         }
182
183         LIST_FOR_EACH_ENTRY_SAFE(lm, lmm, &private_output->pending_commit_handler_list, link) {
184                 LIST_DEL(&lm->link);
185                 free(lm);
186         }
187
188         LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_output->change_handler_list_main, link) {
189                 LIST_DEL(&h->link);
190                 free(h);
191         }
192
193         LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_output->change_handler_list_sub, link) {
194                 LIST_DEL(&h->link);
195                 free(h);
196         }
197
198         if (private_output->vblank) {
199                 /* tdm_vblank APIs is for server. it should be called in unlock status*/
200                 _pthread_mutex_unlock(&private_display->lock);
201                 tdm_vblank_destroy(private_output->vblank);
202                 _pthread_mutex_lock(&private_display->lock);
203         }
204
205         if (private_output->ttrace_vblank) {
206                 /* tdm_vblank APIs is for server. it should be called in unlock status*/
207                 _pthread_mutex_unlock(&private_display->lock);
208                 tdm_vblank_destroy(private_output->ttrace_vblank);
209                 _pthread_mutex_lock(&private_display->lock);
210         }
211
212         LIST_FOR_EACH_ENTRY_SAFE(c, cc, &private_output->capture_list, link)
213         tdm_capture_destroy_internal(c);
214
215         LIST_FOR_EACH_ENTRY_SAFE(hw, hww, &private_output->hwc_window_list, link)
216         tdm_hwc_window_destroy_internal(hw);
217
218         LIST_FOR_EACH_ENTRY_SAFE(l, ll, &private_output->layer_list, link)
219         _tdm_display_destroy_private_layer(l);
220
221         _tdm_display_destroy_caps_output(&private_output->caps);
222
223         if (private_output->dpms_changed_timer)
224                 tdm_event_loop_source_remove(private_output->dpms_changed_timer);
225
226         tdm_event_loop_source_remove(private_output->need_validate.event_source);
227         close(private_output->need_validate.event_fd);
228
229         private_output->stamp = 0;
230         free(private_output);
231 }
232
233 static void
234 _tdm_display_destroy_private_display(tdm_private_display *private_display)
235 {
236         tdm_private_output *o = NULL, *oo = NULL;
237         tdm_private_pp *p = NULL, *pp = NULL;
238
239         free(private_display->outputs_ptr);
240         if (private_display->outputs) {
241                 free(private_display->outputs);
242                 private_display->outputs = NULL;
243         }
244
245         LIST_FOR_EACH_ENTRY_SAFE(p, pp, &private_display->pp_list, link)
246         tdm_pp_destroy_internal(p);
247
248         LIST_FOR_EACH_ENTRY_SAFE(o, oo, &private_display->output_list, link)
249         _tdm_display_destroy_private_output(o);
250
251         _tdm_display_destroy_caps_pp(&private_display->caps_pp);
252         _tdm_display_destroy_caps_capture(&private_display->caps_capture);
253
254         private_display->capabilities = 0;
255         private_display->caps_display.max_layer_count = 0;
256 }
257
258 static tdm_error
259 _tdm_display_update_caps_pp(tdm_private_display *private_display,
260                                                         tdm_caps_pp *caps)
261 {
262         tdm_func_display *func_display = &private_display->func_display;
263         tdm_error ret;
264
265         if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP))
266                 return TDM_ERROR_NONE;
267
268         if (!func_display->display_get_pp_capability) {
269                 TDM_ERR("no display_get_pp_capability()");
270                 return TDM_ERROR_BAD_MODULE;
271         }
272
273         ret = func_display->display_get_pp_capability(private_display->bdata, caps);
274         if (ret != TDM_ERROR_NONE) {
275                 TDM_ERR("display_get_pp_capability() failed");
276                 return TDM_ERROR_BAD_MODULE;
277         }
278
279         return TDM_ERROR_NONE;
280 }
281
282 static tdm_error
283 _tdm_display_update_caps_capture(tdm_private_display *private_display,
284                                                                  tdm_caps_capture *caps)
285 {
286         tdm_func_display *func_display = &private_display->func_display;
287         tdm_error ret;
288
289         if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE))
290                 return TDM_ERROR_NONE;
291
292         if (!func_display->display_get_capture_capability) {
293                 TDM_ERR("no display_get_capture_capability()");
294                 return TDM_ERROR_BAD_MODULE;
295         }
296
297         ret = func_display->display_get_capture_capability(private_display->bdata, caps);
298         if (ret != TDM_ERROR_NONE) {
299                 TDM_ERR("display_get_capture_capability() failed");
300                 return TDM_ERROR_BAD_MODULE;
301         }
302
303         return TDM_ERROR_NONE;
304 }
305
306 static tdm_error
307 _tdm_display_update_caps_layer(tdm_private_display *private_display,
308                                                            tdm_layer *layer_backend, tdm_caps_layer *caps)
309 {
310         tdm_func_layer *func_layer = &private_display->func_layer;
311         tdm_error ret;
312
313         if (!func_layer->layer_get_capability) {
314                 TDM_ERR("no layer_get_capability()");
315                 return TDM_ERROR_BAD_MODULE;
316         }
317
318         ret = func_layer->layer_get_capability(layer_backend, caps);
319         if (ret != TDM_ERROR_NONE) {
320                 TDM_ERR("layer_get_capability() failed");
321                 return TDM_ERROR_BAD_MODULE;
322         }
323
324         return TDM_ERROR_NONE;
325 }
326
327 static tdm_error
328 _tdm_display_update_caps_output(tdm_private_display *private_display, int pipe,
329                                                                 tdm_output *output_backend, tdm_caps_output *caps)
330 {
331         tdm_func_output *func_output = &private_display->func_output;
332         char temp[TDM_NAME_LEN];
333         tdm_error ret;
334         double stamp;
335
336         if (!func_output->output_get_capability) {
337                 TDM_ERR("no output_get_capability()");
338                 return TDM_ERROR_BAD_MODULE;
339         }
340
341         stamp = tdm_helper_get_time();
342         ret = func_output->output_get_capability(output_backend, caps);
343         TDM_DBG("backend output_get_capability() time: %.3f ms", (tdm_helper_get_time() - stamp) * 1000.0);
344
345         if (ret != TDM_ERROR_NONE) {
346                 TDM_ERR("output_get_capability() failed");
347                 return TDM_ERROR_BAD_MODULE;
348         }
349
350         /* FIXME: Use model for tdm client to distinguish amoung outputs */
351         snprintf(temp, TDM_NAME_LEN, "%s-%d", caps->model, pipe);
352         snprintf(caps->model, TDM_NAME_LEN, "%s", temp);
353
354         return TDM_ERROR_NONE;
355 }
356
357 static tdm_error
358 _tdm_display_update_layer(tdm_private_display *private_display,
359                                                   tdm_private_output *private_output,
360                                                   tdm_layer *layer_backend, int index)
361 {
362         tdm_private_layer *private_layer;
363         tdm_error ret;
364
365         private_layer = _tdm_display_find_private_layer(private_output, layer_backend);
366         if (!private_layer) {
367                 private_layer = calloc(1, sizeof(tdm_private_layer));
368                 TDM_RETURN_VAL_IF_FAIL(private_layer != NULL, TDM_ERROR_OUT_OF_MEMORY);
369
370                 LIST_ADDTAIL(&private_layer->link, &private_output->layer_list);
371                 private_layer->index = index;
372                 private_layer->private_display = private_display;
373                 private_layer->private_output = private_output;
374                 private_layer->layer_backend = layer_backend;
375
376                 LIST_INITHEAD(&private_layer->capture_list);
377
378                 private_layer->usable = 1;
379         } else
380                 _tdm_display_destroy_caps_layer(&private_layer->caps);
381
382         ret = _tdm_display_update_caps_layer(private_display, layer_backend,
383                                                                                  &private_layer->caps);
384         if (ret != TDM_ERROR_NONE)
385                 goto failed_update;
386
387         return TDM_ERROR_NONE;
388 failed_update:
389         _tdm_display_destroy_private_layer(private_layer);
390         return ret;
391 }
392
393 INTERN tdm_error
394 tdm_display_update_output(tdm_private_display *private_display,
395                                                   tdm_output *output_backend, int pipe)
396 {
397         tdm_func_output *func_output = &private_display->func_output;
398         tdm_private_output *private_output = NULL;
399         tdm_layer **layers = NULL;
400         int layer_count = 0, i;
401         tdm_error ret;
402
403         private_output = _tdm_display_find_private_output(private_display, output_backend);
404         if (!private_output) {
405                 private_output = calloc(1, sizeof(tdm_private_output));
406                 TDM_RETURN_VAL_IF_FAIL(private_output != NULL, TDM_ERROR_OUT_OF_MEMORY);
407
408                 private_output->stamp = tdm_helper_get_time();
409                 while (tdm_display_find_output_stamp(private_display, private_output->stamp))
410                         private_output->stamp++;
411
412                 LIST_ADDTAIL(&private_output->link, &private_display->output_list);
413
414                 private_output->private_display = private_display;
415                 private_output->current_dpms_value = TDM_OUTPUT_DPMS_OFF;
416                 private_output->output_backend = output_backend;
417                 private_output->pipe = pipe;
418                 private_output->index = pipe;
419
420                 LIST_INITHEAD(&private_output->layer_list);
421                 LIST_INITHEAD(&private_output->hwc_window_list);
422                 LIST_INITHEAD(&private_output->capture_list);
423                 LIST_INITHEAD(&private_output->vblank_handler_list);
424                 LIST_INITHEAD(&private_output->output_commit_handler_list);
425                 LIST_INITHEAD(&private_output->layer_commit_handler_list);
426                 LIST_INITHEAD(&private_output->pending_commit_handler_list);
427                 LIST_INITHEAD(&private_output->change_handler_list_main);
428                 LIST_INITHEAD(&private_output->change_handler_list_sub);
429
430                 if (func_output->output_set_status_handler) {
431                         func_output->output_set_status_handler(private_output->output_backend,
432                                                                                                    tdm_output_cb_status,
433                                                                                                    private_output);
434                         private_output->regist_change_cb = 1;
435                 }
436
437                 ret = _tdm_display_update_caps_output(private_display, pipe, output_backend,
438                                                                                           &private_output->caps);
439                 if (ret != TDM_ERROR_NONE)
440                         return ret;
441         } else {
442                 tdm_caps_output new_caps;
443
444                 ret = _tdm_display_update_caps_output(private_display, pipe, output_backend,
445                                                                                           &new_caps);
446                 if (ret != TDM_ERROR_NONE)
447                         return ret;
448
449                 /* FIXME: This is very ugly. need to fix after the TDM ABI is changed. */
450                 if (private_output->caps.status != new_caps.status) {
451                         _tdm_display_destroy_caps_output(&private_output->caps);
452                         private_output->caps = new_caps;
453                         private_output->current_mode = NULL;
454                 } else {
455                         tdm_output_mode *old_modes = private_output->caps.modes;
456                         unsigned int old_mode_count = private_output->caps.mode_count;
457                         if (new_caps.modes)
458                                 free(new_caps.modes);
459                         new_caps.modes = old_modes;
460                         new_caps.mode_count = old_mode_count;
461                         if (private_output->caps.props)
462                                 free(private_output->caps.props);
463                         private_output->caps = new_caps;
464                 }
465         }
466
467         layers = func_output->output_get_layers(output_backend, &layer_count, &ret);
468         if (ret != TDM_ERROR_NONE)
469                 goto failed_update;
470
471         for (i = 0; i < layer_count; i++) {
472                 ret = _tdm_display_update_layer(private_display, private_output, layers[i], i);
473                 if (ret != TDM_ERROR_NONE)
474                         goto failed_update;
475         }
476
477         free(layers);
478
479         return TDM_ERROR_NONE;
480 failed_update:
481         _tdm_display_destroy_private_output(private_output);
482         free(layers);
483         return ret;
484 }
485
486 static tdm_output **
487 _tdm_display_set_main_first(tdm_output **outputs, int index)
488 {
489         tdm_output *output_tmp = NULL;
490
491         if (index == 0)
492                 return outputs;
493
494         output_tmp = outputs[0];
495         outputs[0] = outputs[index];
496         outputs[index] = output_tmp;
497
498         return outputs;
499 }
500
501 static tdm_output **
502 _tdm_display_get_ordered_outputs(tdm_private_display *private_display, int *count)
503 {
504         tdm_func_display *func_display = &private_display->func_display;
505         tdm_output **outputs = NULL;
506         tdm_output **new_outputs = NULL;
507         tdm_output *output_dsi = NULL;
508         tdm_output *output_lvds = NULL;
509         tdm_output *output_hdmia = NULL;
510         tdm_output *output_hdmib = NULL;
511         int i, output_count = 0, output_connected_count = 0;
512         int index_dsi = 0, index_lvds = 0, index_hdmia = 0, index_hdmib = 0;
513         tdm_error ret;
514
515         /* don't change list order if not init time */
516         if (private_display->outputs)
517                 return private_display->outputs;
518
519         outputs = func_display->display_get_outputs(private_display->bdata, &output_count, &ret);
520         if (ret != TDM_ERROR_NONE)
521                 goto failed_get_outputs;
522
523         *count = output_count;
524
525         if (output_count == 0)
526                 goto failed_get_outputs;
527         else if (output_count == 1) {
528                 private_display->outputs = outputs;
529                 return outputs;
530         }
531
532         /* count connected outputs */
533         for (i = 0; i < output_count; i++) {
534                 tdm_func_output *func_output = &private_display->func_output;
535                 tdm_caps_output caps;
536                 memset(&caps, 0, sizeof(tdm_caps_output));
537
538                 if (!func_output->output_get_capability) {
539                         TDM_ERR("no output_get_capability()");
540                         goto failed_get_outputs;
541                 }
542
543                 ret = func_output->output_get_capability(outputs[i], &caps);
544                 if (ret != TDM_ERROR_NONE) {
545                         TDM_ERR("output_get_capability() failed");
546                         goto failed_get_outputs;
547                 }
548
549                 if (caps.status == TDM_OUTPUT_CONN_STATUS_CONNECTED) {
550                         output_connected_count++;
551
552                         switch (caps.type) {
553                         case TDM_OUTPUT_TYPE_DSI:
554                                 output_dsi = outputs[i];
555                                 index_dsi = i;
556                                 break;
557                         case TDM_OUTPUT_TYPE_LVDS:
558                                 output_lvds = outputs[i];
559                                 index_lvds = i;
560                                 break;
561                         case TDM_OUTPUT_TYPE_HDMIA:
562                                 output_hdmia = outputs[i];
563                                 index_hdmia = i;
564                                 break;
565                         case TDM_OUTPUT_TYPE_HDMIB:
566                                 output_hdmib = outputs[i];
567                                 index_hdmib = i;
568                                 break;
569                         default:
570                                 break;
571                         }
572                 }
573
574                 _tdm_display_destroy_caps_output(&caps);
575         }
576
577         /* ordering : main output is first */
578         /* If there is no connected output, lvds or dsi cannot be main display. (cannot connect after booting)
579           * But hdmi is possible, so set hdmi to main display.
580           * If connected only one output, it is main output.
581           * If connected outputs over 2, has priority like below.
582           * (dsi > lvds > hdmi > else)
583           */
584         if (output_connected_count == 0) {
585                 /* hdmi > dsi > lvds > else */
586                 if (output_hdmia != NULL)
587                         new_outputs = _tdm_display_set_main_first(outputs, index_hdmia);
588                 else if (output_hdmib != NULL)
589                         new_outputs = _tdm_display_set_main_first(outputs, index_hdmib);
590                 else if (output_dsi != NULL)
591                         new_outputs = _tdm_display_set_main_first(outputs, index_dsi);
592                 else if (output_lvds != NULL)
593                         new_outputs = _tdm_display_set_main_first(outputs, index_lvds);
594                 else
595                         new_outputs = outputs;
596         } else { /* (output_connected_count > 1) */
597                 /* dsi > lvds > hdmi > else */
598                 if (output_dsi != NULL)
599                         new_outputs = _tdm_display_set_main_first(outputs, index_dsi);
600                 else if (output_lvds != NULL)
601                         new_outputs = _tdm_display_set_main_first(outputs, index_lvds);
602                 else if (output_hdmia != NULL)
603                         new_outputs = _tdm_display_set_main_first(outputs, index_hdmia);
604                 else if (output_hdmib != NULL)
605                         new_outputs = _tdm_display_set_main_first(outputs, index_hdmib);
606                 else
607                         new_outputs = outputs;
608         }
609
610         private_display->outputs = new_outputs;
611
612         return new_outputs;
613
614 failed_get_outputs:
615         free(outputs);
616         *count = 0;
617         return NULL;
618 }
619
620 static tdm_error
621 _tdm_display_update_internal(tdm_private_display *private_display,
622                                                          int only_display)
623 {
624         tdm_output **outputs = NULL;
625         int output_count = 0, i;
626         tdm_error ret = TDM_ERROR_NONE;
627
628         LIST_INITHEAD(&private_display->output_list);
629         LIST_INITHEAD(&private_display->pp_list);
630         LIST_INITHEAD(&private_display->capture_list);
631
632         if (!only_display) {
633                 ret = _tdm_display_update_caps_pp(private_display, &private_display->caps_pp);
634                 if (ret != TDM_ERROR_NONE)
635                         goto failed_update;
636
637                 ret = _tdm_display_update_caps_capture(private_display,
638                                                                                            &private_display->caps_capture);
639                 if (ret != TDM_ERROR_NONE)
640                         goto failed_update;
641         }
642
643         outputs = _tdm_display_get_ordered_outputs(private_display, &output_count);
644         if (!outputs)
645                 goto failed_update;
646
647         for (i = 0; i < output_count; i++) {
648                 ret = tdm_display_update_output(private_display, outputs[i], i);
649                 if (ret != TDM_ERROR_NONE)
650                         goto failed_update;
651         }
652
653         return TDM_ERROR_NONE;
654
655 failed_update:
656         _tdm_display_destroy_private_display(private_display);
657         return ret;
658 }
659 /* LCOV_EXCL_STOP */
660
661 EXTERN tdm_error
662 tdm_display_update(tdm_display *dpy)
663 {
664         tdm_private_display *private_display;
665         tdm_error ret;
666
667         TDM_RETURN_VAL_IF_FAIL(dpy != NULL, TDM_ERROR_INVALID_PARAMETER);
668         TDM_RETURN_VAL_IF_FAIL(tdm_display_is_valid(dpy), TDM_ERROR_INVALID_PARAMETER);
669
670         private_display = dpy;
671         _pthread_mutex_lock(&private_display->lock);
672
673         ret = _tdm_display_update_internal(private_display, 1);
674
675         _pthread_mutex_unlock(&private_display->lock);
676
677         return ret;
678 }
679
680 #define SUFFIX_MODULE    ".so"
681 #define TDM_DEFAULT_MODULE   "libtdm-default"SUFFIX_MODULE
682 #define TDM_DUMMY_MODULE     "libtdm-dummy"SUFFIX_MODULE
683
684 int tdm_debug_module;
685 int tdm_debug_dump;
686 int tdm_ttrace_module;
687 int tdm_ttrace_output;
688
689 static tdm_private_display *g_private_display;
690 static pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER;
691
692 /* LCOV_EXCL_START */
693 static tdm_error
694 _tdm_display_check_module(tdm_backend_module *module)
695 {
696         int major, minor;
697
698         TDM_INFO("TDM ABI version : %d.%d",
699                          TDM_MAJOR_VERSION, TDM_MINOR_VERSION);
700
701         if (!module->name) {
702                 TDM_ERR("TDM backend doesn't have name");
703                 return TDM_ERROR_BAD_MODULE;
704         }
705
706         if (!module->vendor) {
707                 TDM_ERR("TDM backend doesn't have vendor");
708                 return TDM_ERROR_BAD_MODULE;
709         }
710
711         major = TDM_BACKEND_GET_ABI_MAJOR(module->abi_version);
712         minor = TDM_BACKEND_GET_ABI_MINOR(module->abi_version);
713
714         TDM_INFO("TDM module name: %s", module->name);
715         TDM_INFO("'%s' vendor: %s", module->name, module->vendor);
716         TDM_INFO("'%s' version: %d.%d", module->name, major, minor);
717
718         if (major != TDM_MAJOR_VERSION) {
719                 TDM_ERR("'%s' major version mismatch, %d != %d",
720                                 module->name, major, TDM_MAJOR_VERSION);
721                 return TDM_ERROR_BAD_MODULE;
722         }
723
724         if (minor > TDM_MINOR_VERSION) {
725                 TDM_ERR("'%s' minor version(%d) is newer than %d",
726                                 module->name, minor, TDM_MINOR_VERSION);
727                 return TDM_ERROR_BAD_MODULE;
728         }
729
730         if (!module->init) {
731                 TDM_ERR("'%s' doesn't have init function", module->name);
732                 return TDM_ERROR_BAD_MODULE;
733         }
734
735         if (!module->deinit) {
736                 TDM_ERR("'%s' doesn't have deinit function", module->name);
737                 return TDM_ERROR_BAD_MODULE;
738         }
739
740         return TDM_ERROR_NONE;
741 }
742
743 static tdm_error
744 _tdm_display_check_backend_functions(tdm_private_display *private_display)
745 {
746         tdm_func_display *func_display = &private_display->func_display;
747         tdm_func_output *func_output = &private_display->func_output;
748         tdm_func_layer *func_layer = &private_display->func_layer;
749         tdm_error ret;
750
751         /* below functions should be implemented in backend side */
752
753         TDM_RETURN_VAL_IF_FAIL(func_display != NULL, TDM_ERROR_BAD_MODULE);
754         TDM_RETURN_VAL_IF_FAIL(func_display->display_get_outputs, TDM_ERROR_BAD_MODULE);
755         TDM_RETURN_VAL_IF_FAIL(func_output->output_get_capability, TDM_ERROR_BAD_MODULE);
756         TDM_RETURN_VAL_IF_FAIL(func_output->output_get_layers, TDM_ERROR_BAD_MODULE);
757         TDM_RETURN_VAL_IF_FAIL(func_layer->layer_get_capability, TDM_ERROR_BAD_MODULE);
758
759         ret = func_display->display_get_capability(private_display->bdata, &private_display->caps_display);
760         if (ret != TDM_ERROR_NONE) {
761                 TDM_ERR("display_get_capability() failed");
762                 return TDM_ERROR_BAD_MODULE;
763         }
764
765         if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP) {
766                 tdm_func_pp *func_pp = &private_display->func_pp;
767                 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_pp_capability, TDM_ERROR_BAD_MODULE);
768                 TDM_RETURN_VAL_IF_FAIL(func_display->display_create_pp, TDM_ERROR_BAD_MODULE);
769                 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_destroy, TDM_ERROR_BAD_MODULE);
770                 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_commit, TDM_ERROR_BAD_MODULE);
771                 TDM_RETURN_VAL_IF_FAIL(func_pp->pp_set_done_handler, TDM_ERROR_BAD_MODULE);
772         }
773
774         if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE) {
775                 tdm_func_capture *func_capture = &private_display->func_capture;
776                 TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capture_capability, TDM_ERROR_BAD_MODULE);
777                 if (private_display->caps_capture.capabilities & TDM_CAPTURE_CAPABILITY_OUTPUT)
778                         TDM_RETURN_VAL_IF_FAIL(func_output->output_create_capture, TDM_ERROR_BAD_MODULE);
779                 if (private_display->caps_capture.capabilities & TDM_CAPTURE_CAPABILITY_LAYER)
780                         TDM_RETURN_VAL_IF_FAIL(func_layer->layer_create_capture, TDM_ERROR_BAD_MODULE);
781                 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_destroy, TDM_ERROR_BAD_MODULE);
782                 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_commit, TDM_ERROR_BAD_MODULE);
783                 TDM_RETURN_VAL_IF_FAIL(func_capture->capture_set_done_handler, TDM_ERROR_BAD_MODULE);
784         }
785
786         return TDM_ERROR_NONE;
787 }
788
789 static tdm_error
790 _tdm_display_load_module_with_file(tdm_private_display *private_display,
791                                                                    const char *file)
792 {
793         char path[PATH_MAX] = {0,};
794         tdm_backend_module *module_data;
795         void *module;
796         tdm_error ret;
797         double stamp;
798         int size;
799
800         size = snprintf(path, sizeof(path), TDM_MODULE_PATH "/%s", file);
801         if (size >= (int)sizeof(path)) {
802                 TDM_WRN("too long: %s/%s", TDM_MODULE_PATH, file);
803                 return TDM_ERROR_BAD_MODULE;
804         };
805
806         stamp = tdm_helper_get_time();
807
808         TDM_TRACE_BEGIN("TDM_Load_Backend");
809         module = dlopen(path, RTLD_LAZY);
810         if (!module) {
811                 TDM_ERR("failed to load module: %s(%s)", dlerror(), file);
812                 TDM_TRACE_END();
813                 return TDM_ERROR_BAD_MODULE;
814         }
815
816         module_data = dlsym(module, "tdm_backend_module_data");
817         if (!module_data) {
818                 TDM_ERR("'%s' doesn't have data object", file);
819                 ret = TDM_ERROR_BAD_MODULE;
820                 TDM_TRACE_END();
821                 goto failed_load;
822         }
823         TDM_TRACE_END();
824
825         TDM_DBG("dlopen, dlsym time: %.3f ms", (tdm_helper_get_time() - stamp) * 1000.0);
826
827         private_display->module_data = module_data;
828         private_display->module = module;
829
830         /* check if version, init() and deinit() are valid or not */
831         ret = _tdm_display_check_module(module_data);
832         if (ret != TDM_ERROR_NONE)
833                 goto failed_load;
834
835         /* We don't care if backend_data is NULL or not. It's up to backend. */
836         TDM_TRACE_BEGIN("TDM_Init_Backend");
837         stamp = tdm_helper_get_time();
838         private_display->bdata = module_data->init((tdm_display *)private_display, &ret);
839         TDM_DBG("backend init() time: %.3f ms", (tdm_helper_get_time() - stamp) * 1000.0);
840         TDM_TRACE_END();
841
842         if (ret != TDM_ERROR_NONE) {
843                 TDM_ERR("failed to init '%s' module", module_data->name);
844                 goto failed_load;
845         }
846
847         ret = _tdm_display_check_backend_functions(private_display);
848         if (ret != TDM_ERROR_NONE) {
849                 module_data->deinit(private_display->bdata);
850                 private_display->bdata = NULL;
851                 goto failed_load;
852         }
853
854         TDM_INFO("Success to load '%s' module", module_data->name);
855
856         return TDM_ERROR_NONE;
857 failed_load:
858         dlclose(module);
859         private_display->module_data = NULL;
860         private_display->module = NULL;
861         return ret;
862 }
863
864 static tdm_error
865 _tdm_display_load_module(tdm_private_display *private_display)
866 {
867         const char *module_name;
868         struct dirent **namelist;
869         int n, len;
870         tdm_error ret = 0;
871
872         module_name = getenv("TDM_MODULE");
873         if (!module_name)
874                 module_name = TDM_DEFAULT_MODULE;
875
876         len = strlen(module_name);
877         if (len > TDM_NAME_LEN - 1) {
878                 TDM_ERR("TDM_MODULE is too long\n");
879                 return TDM_ERROR_OPERATION_FAILED;
880         }
881
882         /* load bufmgr priv from default lib */
883         ret = _tdm_display_load_module_with_file(private_display, module_name);
884         if (ret == TDM_ERROR_NONE)
885                 return TDM_ERROR_NONE;
886
887         /* load bufmgr priv from dummy lib */
888         ret = _tdm_display_load_module_with_file(private_display, TDM_DUMMY_MODULE);
889         if (ret == TDM_ERROR_NONE)
890                 return TDM_ERROR_NONE;
891
892         /* load bufmgr priv from configured path */
893         n = scandir(TDM_MODULE_PATH, &namelist, 0, alphasort);
894         if (n < 0) {
895                 TDM_ERR("no module in '%s'\n", TDM_MODULE_PATH);
896                 return TDM_ERROR_BAD_MODULE;
897         }
898
899         ret = TDM_ERROR_BAD_MODULE;
900         while (n--) {
901                 if (ret < 0 && strstr(namelist[n]->d_name, SUFFIX_MODULE))
902                         ret = _tdm_display_load_module_with_file(private_display, namelist[n]->d_name);
903
904                 free(namelist[n]);
905         }
906         free(namelist);
907
908         return ret;
909 }
910
911 static void
912 _tdm_display_unload_module(tdm_private_display *private_display)
913 {
914         if (private_display->module_data)
915                 private_display->module_data->deinit(private_display->bdata);
916         if (private_display->module)
917                 dlclose(private_display->module);
918
919         private_display->bdata = NULL;
920         private_display->module_data = NULL;
921         private_display->module = NULL;
922 }
923 /* LCOV_EXCL_STOP */
924
925 EXTERN tdm_display *
926 tdm_display_init(tdm_error *error)
927 {
928         tdm_private_display *private_display = NULL;
929         const char *str;
930         tdm_error ret;
931         double stamp1, stamp2, start;
932
933         pthread_mutex_lock(&gLock);
934
935         if (g_private_display) {
936                 g_private_display->init_count++;
937                 pthread_mutex_unlock(&gLock);
938                 if (error)
939                         *error = TDM_ERROR_NONE;
940                 return g_private_display;
941         }
942
943         start = stamp1 = tdm_helper_get_time();
944
945         private_display = calloc(1, sizeof(tdm_private_display));
946         if (!private_display) {
947                 /* LCOV_EXCL_START */
948                 ret = TDM_ERROR_OUT_OF_MEMORY;
949                 TDM_ERR("'private_display != NULL' failed");
950                 goto failed_alloc;
951                 /* LCOV_EXCL_STOP */
952         }
953
954         str = getenv("TDM_DEBUG_MODULE");
955         if (str)
956                 tdm_display_enable_debug_module(str);
957
958         str = getenv("TDM_DEBUG_DUMP");
959         if (str)
960                 tdm_display_enable_dump(private_display, str, NULL, NULL);
961
962         str = getenv("TDM_DEBUG_PATH");
963         if (str)
964                 tdm_display_enable_path(str);
965
966         if (pthread_mutex_init(&private_display->lock, NULL)) {
967                 /* LCOV_EXCL_START */
968                 ret = TDM_ERROR_OPERATION_FAILED;
969                 TDM_ERR("mutex init failed: %m");
970                 goto failed_mutex_init;
971                 /* LCOV_EXCL_STOP */
972         }
973
974         _pthread_mutex_lock(&private_display->lock);
975
976         stamp2 = tdm_helper_get_time();
977         TDM_DBG("prepare init time: %.3f ms", (stamp2 - stamp1) * 1000.0);
978         stamp1 = stamp2;
979
980         ret = tdm_vblank_init(private_display);
981         if (ret != TDM_ERROR_NONE)
982                 goto failed_vblank;
983
984         ret = tdm_event_loop_init(private_display);
985         if (ret != TDM_ERROR_NONE)
986                 goto failed_event;
987
988         stamp2 = tdm_helper_get_time();
989         TDM_DBG("creating event loop time: %.3f ms", (stamp2 - stamp1) * 1000.0);
990         stamp1 = stamp2;
991
992         ret = _tdm_display_load_module(private_display);
993         if (ret != TDM_ERROR_NONE)
994                 goto failed_load;
995
996         stamp2 = tdm_helper_get_time();
997         TDM_DBG("loading backend time: %.3f ms", (stamp2 - stamp1) * 1000.0);
998         stamp1 = stamp2;
999
1000 #ifdef INIT_BUFMGR
1001         int tdm_drm_fd = tdm_helper_get_fd("TDM_DRM_MASTER_FD");
1002         if (tdm_drm_fd >= 0) {
1003                 private_display->bufmgr = tbm_bufmgr_init(tdm_drm_fd);
1004                 close(tdm_drm_fd);
1005                 if (!private_display->bufmgr) {
1006                         TDM_ERR("tbm_bufmgr_init failed");
1007                         goto failed_update;
1008                 } else {
1009                         TDM_INFO("tbm_bufmgr_init successed");
1010                 }
1011
1012                 stamp2 = tdm_helper_get_time();
1013                 TDM_DBG("initializing bufmgr time: %.3f ms", (stamp2 - stamp1) * 1000.0);
1014                 stamp1 = stamp2;
1015         }
1016 #endif
1017
1018         TDM_TRACE_BEGIN("TDM_Update_Display");
1019         ret = _tdm_display_update_internal(private_display, 0);
1020         TDM_TRACE_END();
1021         if (ret != TDM_ERROR_NONE)
1022                 goto failed_update;
1023
1024         stamp2 = tdm_helper_get_time();
1025         TDM_DBG("updating display time: %.3f ms", (stamp2 - stamp1) * 1000.0);
1026         stamp1 = stamp2;
1027
1028         tdm_event_loop_create_backend_source(private_display);
1029
1030         private_display->init_count = 1;
1031         g_private_display = private_display;
1032
1033         tdm_private_output *o = NULL;
1034         LIST_FOR_EACH_ENTRY(o, &private_display->output_list, link) {
1035                 if (o->caps.capabilities & TDM_OUTPUT_CAPABILITY_HWC)
1036                         tdm_output_need_validate_event_init(o);
1037         }
1038
1039         /* the COMMIT_PER_VBLANK functionality is ability of an output to support
1040          * several operational modes (commit_per_vblank modes) related to tdm_commit;
1041          * this functionality can be turned off which means a default mode */
1042         str = getenv("TDM_COMMIT_PER_VBLANK");
1043         if (str) {
1044                 tdm_private_output *o = NULL;
1045                 char *end;
1046                 int mode = strtol(str, &end, 10);
1047
1048                 /* outputs which support hwc capability can work only
1049                  * if commit_per_vblank mode is '0' (default mode) */
1050                 LIST_FOR_EACH_ENTRY(o, &private_display->output_list, link)
1051                         if (!(o->caps.capabilities & TDM_OUTPUT_CAPABILITY_HWC))
1052                                 tdm_output_choose_commit_per_vblank_mode(o, mode);
1053         }
1054
1055         if (error)
1056                 *error = TDM_ERROR_NONE;
1057
1058         _pthread_mutex_unlock(&private_display->lock);
1059         pthread_mutex_unlock(&gLock);
1060
1061         TDM_INFO("init time: %.3f ms", (tdm_helper_get_time() - start) * 1000.0);
1062
1063         return (tdm_display *)private_display;
1064
1065 /* LCOV_EXCL_START */
1066 failed_update:
1067         _tdm_display_unload_module(private_display);
1068 failed_load:
1069         tdm_event_loop_stop(private_display);
1070         tdm_event_loop_deinit(private_display);
1071 failed_event:
1072         tdm_vblank_deinit(private_display);
1073 failed_vblank:
1074         _pthread_mutex_unlock(&private_display->lock);
1075         pthread_mutex_destroy(&private_display->lock);
1076 failed_mutex_init:
1077         free(private_display);
1078 failed_alloc:
1079         if (error)
1080                 *error = ret;
1081         pthread_mutex_unlock(&gLock);
1082         return NULL;
1083 /* LCOV_EXCL_STOP */
1084 }
1085
1086 EXTERN void
1087 tdm_display_deinit(tdm_display *dpy)
1088 {
1089         tdm_private_display *private_display = dpy;
1090
1091         if (!private_display)
1092                 return;
1093
1094         TDM_RETURN_IF_FAIL(tdm_display_is_valid(dpy));
1095
1096         pthread_mutex_lock(&gLock);
1097
1098         private_display->init_count--;
1099         if (private_display->init_count > 0) {
1100                 pthread_mutex_unlock(&gLock);
1101                 return;
1102         }
1103
1104         /* dont move the position of lock/unlock. all resource should be protected
1105          * during destroying. after tdm_event_loop_deinit, we don't worry about thread
1106          * things because it's finalized.
1107          */
1108         _pthread_mutex_lock(&private_display->lock);
1109         tdm_event_loop_stop(private_display);
1110         _tdm_display_destroy_private_display(private_display);
1111         _tdm_display_unload_module(private_display);
1112         _pthread_mutex_unlock(&private_display->lock);
1113
1114         tdm_event_loop_deinit(private_display);
1115         tdm_vblank_deinit(private_display);
1116
1117 #ifdef INIT_BUFMGR
1118         if (private_display->bufmgr)
1119                 tbm_bufmgr_deinit(private_display->bufmgr);
1120 #endif
1121
1122         tbm_drm_helper_unset_tbm_master_fd();
1123
1124         pthread_mutex_destroy(&private_display->lock);
1125         free(private_display);
1126         g_private_display = NULL;
1127
1128         if (tdm_debug_dump_dir) {
1129                 free(tdm_debug_dump_dir);
1130                 tdm_debug_dump_dir = NULL;
1131         }
1132
1133         pthread_mutex_unlock(&gLock);
1134
1135         TDM_INFO("done");
1136 }
1137
1138 INTERN int
1139 tdm_display_is_valid(tdm_display *dpy)
1140 {
1141         if (dpy != NULL && dpy == g_private_display)
1142                 return 1;
1143         return 0;
1144 }
1145
1146 INTERN int
1147 tdm_output_is_valid(tdm_output *output)
1148 {
1149         tdm_private_output *o = NULL, *private_output = output;
1150         if (output && g_private_display)
1151                 LIST_FOR_EACH_ENTRY(o, &g_private_display->output_list, link)
1152                         if (o == private_output)
1153                                 return 1;
1154         return 0;
1155 }
1156
1157 /* LCOV_EXCL_START */
1158 INTERN int
1159 tdm_display_check_module_abi(tdm_private_display *private_display, int abimaj, int abimin)
1160 {
1161         tdm_backend_module *module = private_display->module_data;
1162
1163         if (TDM_BACKEND_GET_ABI_MAJOR(module->abi_version) < abimaj)
1164                 return 0;
1165
1166         if (TDM_BACKEND_GET_ABI_MINOR(module->abi_version) < abimin)
1167                 return 0;
1168
1169         return 1;
1170 }
1171
1172 INTERN tdm_error
1173 tdm_display_enable_debug_module(const char*modules)
1174 {
1175         char temp[TDM_PATH_LEN];
1176         char *arg;
1177         char *end;
1178
1179         snprintf(temp, TDM_PATH_LEN, "%s", modules);
1180
1181         tdm_debug_module = 0;
1182
1183         arg = strtok_r(temp, TDM_DELIM, &end);
1184         while (arg) {
1185                 if (!strncmp(arg, "none", 4)) {
1186                         tdm_debug_module = 0;
1187                         return TDM_ERROR_NONE;
1188                 }
1189                 if (!strncmp(arg, "all", 3)) {
1190                         tdm_debug_module = 0xFFFFFFFF;
1191                         return TDM_ERROR_NONE;
1192                 }
1193                 if (!strncmp(arg, "buffer", 6))
1194                         tdm_debug_module |= TDM_DEBUG_BUFFER;
1195                 else if (!strncmp(arg, "thread", 6))
1196                         tdm_debug_module |= TDM_DEBUG_THREAD;
1197                 else if (!strncmp(arg, "mutex", 5))
1198                         tdm_debug_module |= TDM_DEBUG_MUTEX;
1199                 else if (!strncmp(arg, "vblank", 6))
1200                         tdm_debug_module |= TDM_DEBUG_VBLANK;
1201                 else if (!strncmp(arg, "commit", 6))
1202                         tdm_debug_module |= TDM_DEBUG_COMMIT;
1203
1204                 arg = strtok_r(NULL, TDM_DELIM, &end);
1205         }
1206
1207         TDM_INFO("module debugging... '%s'", modules);
1208
1209         return TDM_ERROR_NONE;
1210 }
1211
1212 INTERN tdm_error
1213 tdm_display_enable_dump(tdm_private_display *private_display, const char *dump_str, char *reply, int *len)
1214 {
1215         char temp[TDM_PATH_LEN] = {0,}, temp2[TDM_PATH_LEN] = {0,};
1216         char *path = NULL, *path2;
1217         char *arg;
1218         char *end;
1219
1220         snprintf(temp2, TDM_PATH_LEN, "%s", dump_str);
1221         path2 = strtostr(temp, TDM_PATH_LEN, temp2, "@");
1222         if (!path2 || path2[0] == '\0')
1223                 path2 = TDM_DUMP_DIR;
1224         else
1225                 path2++;
1226
1227         tdm_debug_dump = 0;
1228
1229         snprintf(temp, sizeof(temp), "%s", dump_str);
1230         arg = strtok_r(temp, ",", &end);
1231         TDM_GOTO_IF_FAIL(arg != NULL, done);
1232
1233         if (!strncmp(arg, "none", 4)) {
1234                 tdm_debug_dump = 0;
1235                 TDM_SNPRINTF(reply, len, "path: %s\n", (tdm_debug_dump_dir) ? : "unknown");
1236                 if (tdm_debug_dump_dir) {
1237                         free(tdm_debug_dump_dir);
1238                         tdm_debug_dump_dir = NULL;
1239                 }
1240                 goto done;
1241         }
1242
1243         path = tdm_helper_dump_make_directory(path2, reply, len);
1244         TDM_GOTO_IF_FAIL(path != NULL, done);
1245
1246         if (!strncmp(arg, "current", 7)) {
1247                 tdm_private_output *o = NULL;
1248                 if (!private_display) {
1249                         TDM_WRN("no private_display");
1250                         goto done;
1251                 }
1252
1253                 LIST_FOR_EACH_ENTRY(o, &private_display->output_list, link) {
1254                         tdm_private_layer *l = NULL;
1255                         LIST_FOR_EACH_ENTRY(l, &o->layer_list, link) {
1256                                 char str[TDM_PATH_LEN];
1257                                 if (l->usable || l->caps.capabilities & TDM_LAYER_CAPABILITY_VIDEO)
1258                                         continue;
1259                                 if (!l->showing_buffer)
1260                                         continue;
1261                                 snprintf(str, TDM_PATH_LEN, "layer_%d_%d", o->index, l->index);
1262                                 tdm_helper_dump_buffer_str(l->showing_buffer->buffer, path, str);
1263                         }
1264                 }
1265
1266                 TDM_SNPRINTF(reply, len, "path: %s\n", path);
1267                 goto done;
1268         }
1269
1270         TDM_SNPRINTF(reply, len, "dump: %s\n", arg);
1271
1272         while (arg) {
1273                 if (!strncmp(arg, "all", 3)) {
1274                         tdm_debug_dump = 0xFFFFFFFF;
1275                         goto done;
1276                 } else if (!strncmp(arg, "layer", 5)) {
1277                         tdm_debug_dump |= TDM_DUMP_FLAG_LAYER;
1278                 } else if (!strncmp(arg, "pp", 2)) {
1279                         tdm_debug_dump |= TDM_DUMP_FLAG_PP;
1280                 } else if (!strncmp(arg, "capture", 7)) {
1281                         tdm_debug_dump |= TDM_DUMP_FLAG_CAPTURE;
1282                 } else if (!strncmp(arg, "window", 6)) {
1283                         tdm_debug_dump |= TDM_DUMP_FLAG_WINDOW;
1284                 } else
1285                         goto done;
1286
1287                 arg = strtok_r(NULL, ",", &end);
1288         }
1289
1290         if (tdm_debug_dump_dir)
1291                 free(tdm_debug_dump_dir);
1292
1293         tdm_debug_dump_dir = strndup(path, TDM_PATH_LEN);
1294
1295         TDM_INFO("dump... '%s'", dump_str);
1296
1297 done:
1298         if (path)
1299                 free(path);
1300
1301         return TDM_ERROR_NONE;
1302 }
1303
1304 INTERN tdm_error
1305 tdm_display_enable_path(const char *path)
1306 {
1307         static int old_stdout = -1;
1308         char fd_name[TDM_PATH_LEN];
1309         int  log_fd = -1;
1310         FILE *log_fl;
1311
1312         if (old_stdout == -1)
1313                 old_stdout = dup(STDOUT_FILENO);
1314
1315         tdm_log_enable_dlog(0);
1316
1317         snprintf(fd_name, TDM_PATH_LEN, "%s", path);
1318
1319         log_fl = fopen(fd_name, "a");
1320         if (!log_fl) {
1321                 TDM_ERR("failed: open file(%s)\n", fd_name);
1322                 return TDM_ERROR_OPERATION_FAILED;
1323         }
1324
1325         fflush(stderr);
1326         close(STDOUT_FILENO);
1327
1328         setvbuf(log_fl, NULL, _IOLBF, 512);
1329         log_fd = fileno(log_fl);
1330
1331         dup2(log_fd, STDOUT_FILENO);
1332         fclose(log_fl);
1333
1334         return TDM_ERROR_NONE;
1335 }
1336
1337 static void
1338 _tdm_display_ttrace_vblank_cb(tdm_vblank *vblank, tdm_error error, unsigned int sequence,
1339                                                           unsigned int tv_sec, unsigned int tv_usec, void *user_data)
1340 {
1341         tdm_error ret = TDM_ERROR_NONE;
1342
1343         TDM_TRACE_MARK("VSYNC");
1344
1345         ret = tdm_vblank_wait(vblank, 0, 0, 1, _tdm_display_ttrace_vblank_cb, NULL);
1346         TDM_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
1347 }
1348
1349 INTERN tdm_error
1350 tdm_display_enable_ttrace_vblank(tdm_display *dpy, tdm_output *output, int enable)
1351 {
1352         tdm_private_display *private_display = dpy;
1353         tdm_private_output *private_output = NULL;
1354         const tdm_output_mode *mode = NULL;
1355         tdm_vblank *vblank = NULL;
1356         tdm_error ret = TDM_ERROR_NONE;
1357
1358         if (!enable) {
1359                 LIST_FOR_EACH_ENTRY(private_output, &private_display->output_list, link) {
1360                         if (private_output->ttrace_vblank)
1361                                 tdm_vblank_destroy(private_output->ttrace_vblank);
1362                         private_output->ttrace_vblank = NULL;
1363                 }
1364                 return TDM_ERROR_NONE;
1365         }
1366
1367         private_output = output;
1368         TDM_RETURN_VAL_IF_FAIL(private_output != NULL, TDM_ERROR_INVALID_PARAMETER);
1369
1370         if (private_output->ttrace_vblank)
1371                 return TDM_ERROR_NONE;
1372
1373         vblank = tdm_vblank_create(private_display, output, &ret);
1374         TDM_RETURN_VAL_IF_FAIL(vblank != NULL, ret);
1375
1376         ret = tdm_output_get_mode(output, &mode);
1377         TDM_GOTO_IF_FAIL(mode != NULL, enable_fail);
1378
1379         ret = tdm_vblank_set_fps(vblank, mode->vrefresh);
1380         TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, enable_fail);
1381
1382         ret = tdm_vblank_set_enable_fake(vblank, 1);
1383         TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, enable_fail);
1384
1385         ret = tdm_vblank_wait(vblank, 0, 0, 1, _tdm_display_ttrace_vblank_cb, NULL);
1386         TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, enable_fail);
1387
1388         private_output->ttrace_vblank = vblank;
1389
1390         return TDM_ERROR_NONE;
1391
1392 enable_fail:
1393         if (vblank)
1394                 tdm_vblank_destroy(vblank);
1395
1396         return ret;
1397 }
1398
1399 INTERN tdm_error
1400 tdm_display_enable_ttrace(tdm_private_display *private_display, const char *ttrace, int output_id, char *reply, int *len)
1401 {
1402         char temp[TDM_PATH_LEN];
1403         char *arg;
1404         char *end;
1405         tdm_output *output;
1406         tdm_error ret;
1407         tdm_output_type type;
1408
1409         snprintf(temp, TDM_PATH_LEN, "%s", ttrace);
1410
1411         tdm_ttrace_output = output_id;
1412         tdm_ttrace_module = 0;
1413
1414         output = tdm_display_get_output(private_display, output_id, &ret);
1415         if (!output) {
1416                 TDM_SNPRINTF(reply, len, "can't find the output_id(%d)\n", output_id);
1417                 return ret;
1418         }
1419
1420         ret = tdm_output_get_output_type(output, &type);
1421         if (ret != TDM_ERROR_NONE) {
1422                 TDM_SNPRINTF(reply, len, "can't find the type of output_id(%d)\n", output_id);
1423                 return ret;
1424         }
1425
1426         arg = strtok_r(temp, TDM_DELIM, &end);
1427         while (arg) {
1428                 if (!strncmp(arg, "none", 4))
1429                         tdm_ttrace_module = 0;
1430                 else if (!strncmp(arg, "all", 3))
1431                         tdm_ttrace_module = 0xFFFFFFFF;
1432                 else if (!strncmp(arg, "vblank", 6))
1433                         tdm_ttrace_module |= TDM_TTRACE_VBLANK;
1434                 else if (!strncmp(arg, "client", 6))
1435                         tdm_ttrace_module |= TDM_TTRACE_CLIENT;
1436                 else if (!strncmp(arg, "layer", 5))
1437                         tdm_ttrace_module |= TDM_TTRACE_LAYER;
1438                 else if (!strncmp(arg, "pp", 2))
1439                         tdm_ttrace_module |= TDM_TTRACE_PP;
1440                 else if (!strncmp(arg, "capture", 7))
1441                         tdm_ttrace_module |= TDM_TTRACE_CAPTURE;
1442                 else  {
1443                         tdm_ttrace_module = 0;
1444                         tdm_display_enable_ttrace_vblank(private_display, NULL, 0);
1445                         tdm_server_enable_ttrace_client_vblank(private_display, NULL, 0);
1446                         TDM_SNPRINTF(reply, len, "unknown option: '%s'\n", arg);
1447                         return TDM_ERROR_NONE;
1448                 }
1449
1450                 arg = strtok_r(NULL, TDM_DELIM, &end);
1451         }
1452
1453         TDM_SNPRINTF(reply, len, "ttrace debugging... '%s' %x\n", ttrace, tdm_ttrace_module);
1454
1455         if (tdm_ttrace_module & TDM_TTRACE_VBLANK)
1456                 tdm_display_enable_ttrace_vblank(private_display, output, 1);
1457         else
1458                 tdm_display_enable_ttrace_vblank(private_display, NULL, 0);
1459
1460         if (tdm_ttrace_module & TDM_TTRACE_CLIENT)
1461                 tdm_server_enable_ttrace_client_vblank(private_display, output, 1);
1462         else
1463                 tdm_server_enable_ttrace_client_vblank(private_display, NULL, 0);
1464
1465         return TDM_ERROR_NONE;
1466 }
1467
1468 INTERN tdm_error
1469 tdm_display_enable_fps(tdm_private_display *private_display, int enable)
1470 {
1471         private_display->print_fps = enable;
1472
1473         TDM_INFO("print fps: %s", (enable) ? "enable" : "disable");
1474
1475         return TDM_ERROR_NONE;
1476 }
1477 /* LCOV_EXCL_STOP */