185f10d78824fa61111e6512e4f52de2c2fe17cf
[platform/core/uifw/libtdm.git] / backends / virtual / tdm_virtual_display.c
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4
5 #include "tdm_virtual.h"
6
7 typedef struct _tdm_virtual_output_data tdm_virtual_output_data;
8 typedef struct _tdm_virtual_layer_data tdm_virtual_layer_data;
9 typedef struct _tdm_virtual_event_data tdm_virtual_event_data;
10
11 typedef enum {
12         TDM_VIRTUAL_EVENT_TYPE_WAIT,
13         TDM_VIRTUAL_EVENT_TYPE_COMMIT,
14 } tdm_virtual_event_type;
15
16 struct _tdm_virtual_event_data {
17         struct list_head link;
18
19         tdm_virtual_event_type type;
20         tdm_virtual_output_data *output_data;
21         void *user_data;
22 };
23
24 struct _tdm_virtual_output_data {
25         struct list_head link;
26
27         /* data which are fixed at initializing */
28         tdm_virtual_data *virtual_data;
29
30         uint32_t pipe;
31         tdm_output_mode *output_mode;
32         tdm_output_type connector_type;
33         struct list_head layer_list;
34         tdm_virtual_layer_data *primary_layer;
35
36         /* not fixed data below */
37         tdm_output_vblank_handler vblank_func;
38         tdm_output_commit_handler commit_func;
39
40         tdm_output_conn_status status;
41
42         int mode_changed;
43         const tdm_output_mode *current_mode;
44
45         tdm_event_loop_source *timer;
46         unsigned int timer_waiting;
47         struct list_head timer_event_list;
48 };
49
50 struct _tdm_virtual_layer_data {
51         struct list_head link;
52
53         /* data which are fixed at initializing */
54         tdm_virtual_data *virtual_data;
55         tdm_virtual_output_data *output_data;
56         tdm_layer_capability capabilities;
57         int zpos;
58
59         /* not fixed data below */
60         tdm_info_layer info;
61         int info_changed;
62
63         tbm_surface_h display_buffer;
64         int display_buffer_changed;
65 };
66
67 static void
68 _tdm_virtual_display_cb_event(tdm_virtual_output_data *output_data, tdm_virtual_event_data *event_data,
69                                                         unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec)
70 {
71         switch (event_data->type) {
72         case TDM_VIRTUAL_EVENT_TYPE_WAIT:
73                 if (output_data->vblank_func)
74                         output_data->vblank_func(output_data, sequence, tv_sec, tv_usec, event_data->user_data);
75                 break;
76         case TDM_VIRTUAL_EVENT_TYPE_COMMIT:
77                 if (output_data->commit_func)
78                         output_data->commit_func(output_data, sequence, tv_sec, tv_usec, event_data->user_data);
79                 break;
80         default:
81                 break;
82         }
83 }
84
85 static tdm_error
86 _tdm_virtual_display_cb_timeout(void *user_data)
87 {
88         tdm_virtual_output_data *output_data = user_data;
89         tdm_virtual_event_data *e = NULL, *ee = NULL;
90         unsigned int tv_sec, tv_usec;
91         static unsigned int sequence = 0;
92         struct timespec tp;
93
94         sequence++;
95
96         if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) {
97                 tv_sec = tp.tv_sec;
98                 tv_usec = tp.tv_nsec / 1000;
99         } else {
100                 tv_sec = tv_usec = 0;
101         }
102
103         LIST_FOR_EACH_ENTRY_SAFE(e, ee, &output_data->timer_event_list, link) {
104                 LIST_DEL(&e->link);
105                 _tdm_virtual_display_cb_event(output_data, e, sequence, tv_sec, tv_usec);
106                 free(e);
107         }
108
109         return TDM_ERROR_NONE;
110 }
111
112 static tdm_error
113 _tdm_virtual_display_wait_vblank(tdm_virtual_output_data *output_data, int interval, tdm_virtual_event_data *event_data)
114 {
115         tdm_error ret;
116         unsigned int ms;
117
118         RETURN_VAL_IF_FAIL(output_data->timer != NULL, TDM_ERROR_OPERATION_FAILED);
119         RETURN_VAL_IF_FAIL(output_data->output_mode->vrefresh > 0, TDM_ERROR_OPERATION_FAILED);
120
121         if (output_data->timer_waiting) {
122                 LIST_ADDTAIL(&event_data->link, &output_data->timer_event_list);
123                 return TDM_ERROR_NONE;
124         }
125
126         ms = ((double)1000.0 / output_data->output_mode->vrefresh) * interval;
127
128         ret = tdm_event_loop_source_timer_update(output_data->timer, ms);
129         if (ret != TDM_ERROR_NONE)
130                 return ret;
131
132         LIST_ADDTAIL(&event_data->link, &output_data->timer_event_list);
133
134         return TDM_ERROR_NONE;
135 }
136
137 static void
138 _tdm_virtual_display_destroy_layer_list(tdm_virtual_data *virtual_data)
139 {
140         tdm_virtual_output_data *o = NULL;
141
142         LIST_FOR_EACH_ENTRY(o, &virtual_data->output_list, link) {
143                 tdm_virtual_layer_data *l = NULL, *ll = NULL;
144                 LIST_FOR_EACH_ENTRY_SAFE(l, ll, &o->layer_list, link) {
145                         LIST_DEL(&l->link);
146                         free(l);
147                 }
148         }
149 }
150
151 tdm_error
152 tdm_virtual_display_create_layer_list(tdm_virtual_data *virtual_data)
153 {
154         tdm_virtual_output_data *output_data = NULL;
155         tdm_error ret = TDM_ERROR_NONE;
156
157         if (LIST_IS_EMPTY(&virtual_data->output_list)) {
158                 TDM_ERR("no output");
159                 return TDM_ERROR_OPERATION_FAILED;
160         }
161
162         /* The TDM virtual backend only support one output. */
163         LIST_FOR_EACH_ENTRY(output_data, &virtual_data->output_list, link) {
164                 tdm_virtual_layer_data *layer_data = calloc(1, sizeof(tdm_virtual_layer_data));
165                 if (!layer_data) {
166                         TDM_ERR("alloc failed");
167                         ret = TDM_ERROR_OUT_OF_MEMORY;
168                         goto failed;
169                 }
170
171                 layer_data->virtual_data = virtual_data;
172                 layer_data->output_data = output_data;
173                 layer_data->zpos = 0;
174
175                 layer_data->capabilities = TDM_LAYER_CAPABILITY_PRIMARY | TDM_LAYER_CAPABILITY_GRAPHIC;
176                 output_data->primary_layer = layer_data;
177
178                 LIST_ADDTAIL(&layer_data->link, &output_data->layer_list);
179         }
180
181         return TDM_ERROR_NONE;
182 failed:
183         _tdm_virtual_display_destroy_layer_list(virtual_data);
184         return ret;
185 }
186
187 void
188 tdm_virtual_display_destroy_output_list(tdm_virtual_data *virtual_data)
189 {
190         tdm_virtual_output_data *o = NULL, *oo = NULL;
191
192         if (LIST_IS_EMPTY(&virtual_data->output_list))
193                 return;
194
195         _tdm_virtual_display_destroy_layer_list(virtual_data);
196
197         LIST_FOR_EACH_ENTRY_SAFE(o, oo, &virtual_data->output_list, link) {
198                 LIST_DEL(&o->link);
199
200                 if (!LIST_IS_EMPTY(&o->timer_event_list)) {
201                         tdm_virtual_event_data *e = NULL, *ee = NULL;
202                         LIST_FOR_EACH_ENTRY_SAFE(e, ee, &o->timer_event_list, link) {
203                                 LIST_DEL(&e->link);
204                                 free(e);
205                         }
206                 }
207
208                 if (o->timer)
209                         tdm_event_loop_source_remove(o->timer);
210
211                 free(o->output_mode);
212                 free(o);
213         }
214 }
215
216 tdm_error
217 tdm_virtual_display_create_output_list(tdm_virtual_data *virtual_data)
218 {
219         tdm_virtual_output_data *output_data;
220         tdm_error ret;
221
222         RETURN_VAL_IF_FAIL(LIST_IS_EMPTY(&virtual_data->output_list), TDM_ERROR_OPERATION_FAILED);
223
224         output_data = calloc(1, sizeof(tdm_virtual_output_data));
225         if (!output_data) {
226                 TDM_ERR("alloc failed");
227                 ret = TDM_ERROR_OUT_OF_MEMORY;
228                 goto failed_create;
229         }
230
231         LIST_INITHEAD(&output_data->layer_list);
232
233         output_data->virtual_data = virtual_data;
234         output_data->pipe = 0;
235         output_data->connector_type = TDM_OUTPUT_TYPE_Unknown;
236         output_data->status = TDM_OUTPUT_CONN_STATUS_CONNECTED;
237
238         output_data->output_mode = calloc(1, sizeof(tdm_output_mode));
239         if (!output_data->output_mode) {
240                 TDM_ERR("alloc failed");
241                 free(output_data);
242                 ret = TDM_ERROR_OUT_OF_MEMORY;
243                 goto failed_create;
244         }
245
246         snprintf(output_data->output_mode->name, TDM_NAME_LEN, "640x480");
247         output_data->output_mode->vrefresh = 30;
248         output_data->output_mode->clock = 25200;
249         output_data->output_mode->hdisplay = 640;
250         output_data->output_mode->hsync_start = 656;
251         output_data->output_mode->hsync_end = 752;
252         output_data->output_mode->htotal = 800;
253         output_data->output_mode->hskew = 0;
254         output_data->output_mode->vdisplay = 480;
255         output_data->output_mode->vsync_start = 490;
256         output_data->output_mode->vsync_end = 492;
257         output_data->output_mode->vtotal = 525;
258         output_data->output_mode->vscan = 0;
259         output_data->output_mode->flags = 0;
260         output_data->output_mode->type = 0;
261
262         output_data->timer = tdm_event_loop_add_timer_handler(virtual_data->dpy,
263                                                                                                                   _tdm_virtual_display_cb_timeout,
264                                                                                                                   output_data,
265                                                                                                                   &ret);
266         if (!output_data->timer) {
267                 free(output_data);
268                 return ret;
269         }
270
271         LIST_INITHEAD(&output_data->timer_event_list);
272
273         LIST_ADDTAIL(&output_data->link, &virtual_data->output_list);
274
275         return TDM_ERROR_NONE;
276 failed_create:
277         tdm_virtual_display_destroy_output_list(virtual_data);
278         return ret;
279 }
280
281 tdm_error
282 virtual_display_get_capability(tdm_backend_data *bdata, tdm_caps_display *caps)
283 {
284         RETURN_VAL_IF_FAIL(caps, TDM_ERROR_INVALID_PARAMETER);
285
286         caps->max_layer_count = -1; /* not defined */
287
288         return TDM_ERROR_NONE;
289 }
290
291 tdm_output **
292 virtual_display_get_outputs(tdm_backend_data *bdata, int *count, tdm_error *error)
293 {
294         tdm_virtual_data *virtual_data = bdata;
295         tdm_virtual_output_data *output_data = NULL;
296         tdm_output **outputs;
297         tdm_error ret;
298         int i;
299
300         RETURN_VAL_IF_FAIL(virtual_data, NULL);
301         RETURN_VAL_IF_FAIL(count, NULL);
302
303         *count = 0;
304         LIST_FOR_EACH_ENTRY(output_data, &virtual_data->output_list, link)
305         (*count)++;
306
307         if (*count == 0) {
308                 ret = TDM_ERROR_NONE;
309                 goto failed_get;
310         }
311
312         /* will be freed in frontend */
313         outputs = calloc(*count, sizeof(tdm_virtual_output_data *));
314         if (!outputs) {
315                 TDM_ERR("failed: alloc memory");
316                 *count = 0;
317                 ret = TDM_ERROR_OUT_OF_MEMORY;
318                 goto failed_get;
319         }
320
321         i = 0;
322         LIST_FOR_EACH_ENTRY(output_data, &virtual_data->output_list, link)
323         outputs[i++] = output_data;
324
325         if (error)
326                 *error = TDM_ERROR_NONE;
327
328         return outputs;
329 failed_get:
330         if (error)
331                 *error = ret;
332         return NULL;
333 }
334
335 tdm_error
336 virtual_display_get_fd(tdm_backend_data *bdata, int *fd)
337 {
338         tdm_virtual_data *virtual_data = bdata;
339
340         RETURN_VAL_IF_FAIL(virtual_data, TDM_ERROR_INVALID_PARAMETER);
341         RETURN_VAL_IF_FAIL(fd, TDM_ERROR_INVALID_PARAMETER);
342
343         *fd = virtual_data->pipe[0];
344
345         return TDM_ERROR_NONE;
346 }
347
348 tdm_error
349 virtual_display_handle_events(tdm_backend_data *bdata)
350 {
351         return TDM_ERROR_NONE;
352 }
353
354 tdm_error
355 virtual_output_get_capability(tdm_output *output, tdm_caps_output *caps)
356 {
357         tdm_virtual_output_data *output_data = output;
358         tdm_error ret;
359
360         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
361         RETURN_VAL_IF_FAIL(caps, TDM_ERROR_INVALID_PARAMETER);
362
363         memset(caps, 0, sizeof(tdm_caps_output));
364
365         snprintf(caps->maker, TDM_NAME_LEN, "virtual");
366         snprintf(caps->model, TDM_NAME_LEN, "virtual");
367         snprintf(caps->name, TDM_NAME_LEN, "virtual");
368
369         caps->status = output_data->status;
370         caps->type = output_data->connector_type;
371         caps->type_id = 0;
372
373         caps->mode_count = 1;
374         caps->modes = calloc(1, sizeof(tdm_output_mode));
375         if (!caps->modes) {
376                 ret = TDM_ERROR_OUT_OF_MEMORY;
377                 TDM_ERR("alloc failed\n");
378                 goto failed_get;
379         }
380
381         *caps->modes = *output_data->output_mode;
382
383         caps->mmWidth = 640;
384         caps->mmHeight = 480;
385         caps->subpixel = 1;
386
387         caps->min_w = -1;
388         caps->min_h = -1;
389         caps->max_w = -1;
390         caps->max_h = -1;
391         caps->preferred_align = -1;
392
393         caps->prop_count = 0;
394
395         return TDM_ERROR_NONE;
396 failed_get:
397         memset(caps, 0, sizeof(tdm_caps_output));
398         return ret;
399 }
400
401 tdm_layer **
402 virtual_output_get_layers(tdm_output *output,  int *count, tdm_error *error)
403 {
404         tdm_virtual_output_data *output_data = output;
405         tdm_virtual_layer_data *layer_data = NULL;
406         tdm_layer **layers;
407         tdm_error ret;
408         int i;
409
410         RETURN_VAL_IF_FAIL(output_data, NULL);
411         RETURN_VAL_IF_FAIL(count, NULL);
412
413         *count = 0;
414         LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link)
415         (*count)++;
416
417         if (*count == 0) {
418                 ret = TDM_ERROR_NONE;
419                 goto failed_get;
420         }
421
422         /* will be freed in frontend */
423         layers = calloc(*count, sizeof(tdm_virtual_layer_data *));
424         if (!layers) {
425                 TDM_ERR("failed: alloc memory");
426                 *count = 0;
427                 ret = TDM_ERROR_OUT_OF_MEMORY;
428                 goto failed_get;
429         }
430
431         i = 0;
432         LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link)
433         layers[i++] = layer_data;
434
435         if (error)
436                 *error = TDM_ERROR_NONE;
437
438         return layers;
439 failed_get:
440         if (error)
441                 *error = ret;
442         return NULL;
443 }
444
445 tdm_error
446 virtual_output_wait_vblank(tdm_output *output, int interval, int sync, void *user_data)
447 {
448         tdm_virtual_output_data *output_data = output;
449         tdm_virtual_event_data *event_data;
450         tdm_error ret;
451
452         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
453
454         event_data = calloc(1, sizeof(tdm_virtual_event_data));
455         if (!event_data) {
456                 TDM_ERR("alloc failed");
457                 return TDM_ERROR_OUT_OF_MEMORY;
458         }
459
460         event_data->type = TDM_VIRTUAL_EVENT_TYPE_WAIT;
461         event_data->output_data = output_data;
462         event_data->user_data = user_data;
463
464         ret = _tdm_virtual_display_wait_vblank(output_data, interval, event_data);
465         if (ret != TDM_ERROR_NONE) {
466                 free(event_data);
467                 return ret;
468         }
469
470         return TDM_ERROR_NONE;
471 }
472
473 tdm_error
474 virtual_output_set_vblank_handler(tdm_output *output, tdm_output_vblank_handler func)
475 {
476         tdm_virtual_output_data *output_data = output;
477
478         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
479         RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER);
480
481         output_data->vblank_func = func;
482
483         return TDM_ERROR_NONE;
484 }
485
486 tdm_error
487 virtual_output_commit(tdm_output *output, int sync, void *user_data)
488 {
489         tdm_virtual_output_data *output_data = output;
490         tdm_virtual_event_data *event_data;
491         tdm_error ret;
492
493         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
494
495         event_data = calloc(1, sizeof(tdm_virtual_event_data));
496         if (!event_data) {
497                 TDM_ERR("alloc failed");
498                 return TDM_ERROR_OUT_OF_MEMORY;
499         }
500
501         event_data->type = TDM_VIRTUAL_EVENT_TYPE_COMMIT;
502         event_data->output_data = output_data;
503         event_data->user_data = user_data;
504
505         ret = _tdm_virtual_display_wait_vblank(output_data, 1, event_data);
506         if (ret != TDM_ERROR_NONE) {
507                 free(event_data);
508                 return ret;
509         }
510
511         return TDM_ERROR_NONE;
512 }
513
514 tdm_error
515 virtual_output_set_commit_handler(tdm_output *output, tdm_output_commit_handler func)
516 {
517         tdm_virtual_output_data *output_data = output;
518
519         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
520         RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER);
521
522         output_data->commit_func = func;
523
524         return TDM_ERROR_NONE;
525 }
526
527 tdm_error
528 virtual_output_set_mode(tdm_output *output, const tdm_output_mode *mode)
529 {
530         tdm_virtual_output_data *output_data = output;
531
532         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
533         RETURN_VAL_IF_FAIL(mode, TDM_ERROR_INVALID_PARAMETER);
534
535         output_data->current_mode = mode;
536         output_data->mode_changed = 1;
537
538         return TDM_ERROR_NONE;
539 }
540
541 tdm_error
542 virtual_output_get_mode(tdm_output *output, const tdm_output_mode **mode)
543 {
544         tdm_virtual_output_data *output_data = output;
545
546         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
547         RETURN_VAL_IF_FAIL(mode, TDM_ERROR_INVALID_PARAMETER);
548
549         *mode = output_data->current_mode;
550
551         return TDM_ERROR_NONE;
552 }
553
554 tdm_error
555 virtual_layer_get_capability(tdm_layer *layer, tdm_caps_layer *caps)
556 {
557         tdm_virtual_layer_data *layer_data = layer;
558
559         RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
560         RETURN_VAL_IF_FAIL(caps, TDM_ERROR_INVALID_PARAMETER);
561
562         memset(caps, 0, sizeof(tdm_caps_layer));
563
564         caps->capabilities = layer_data->capabilities;
565         caps->zpos = layer_data->zpos;
566
567         caps->format_count = 2;
568         caps->formats = calloc(caps->format_count, sizeof(tbm_format));
569         if (!caps->formats) {
570                 TDM_ERR("alloc failed\n");
571                 free(caps->formats);
572                 memset(caps, 0, sizeof(tdm_caps_layer));
573                 return TDM_ERROR_OUT_OF_MEMORY;
574         }
575
576         caps->formats[0] = TBM_FORMAT_ARGB8888;
577         caps->formats[1] = TBM_FORMAT_XRGB8888;
578
579         caps->prop_count = 0;
580
581         return TDM_ERROR_NONE;
582 }
583
584 tdm_error
585 virtual_layer_set_info(tdm_layer *layer, tdm_info_layer *info)
586 {
587         tdm_virtual_layer_data *layer_data = layer;
588
589         RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
590         RETURN_VAL_IF_FAIL(info, TDM_ERROR_INVALID_PARAMETER);
591
592         layer_data->info = *info;
593         layer_data->info_changed = 1;
594
595         return TDM_ERROR_NONE;
596 }
597
598 tdm_error
599 virtual_layer_get_info(tdm_layer *layer, tdm_info_layer *info)
600 {
601         tdm_virtual_layer_data *layer_data = layer;
602
603         RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
604         RETURN_VAL_IF_FAIL(info, TDM_ERROR_INVALID_PARAMETER);
605
606         *info = layer_data->info;
607
608         return TDM_ERROR_NONE;
609 }
610
611 tdm_error
612 virtual_layer_set_buffer(tdm_layer *layer, tbm_surface_h buffer)
613 {
614         tdm_virtual_layer_data *layer_data = layer;
615
616         RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
617         RETURN_VAL_IF_FAIL(buffer, TDM_ERROR_INVALID_PARAMETER);
618
619         layer_data->display_buffer = buffer;
620         layer_data->display_buffer_changed = 1;
621
622         return TDM_ERROR_NONE;
623 }
624
625 tdm_error
626 virtual_layer_unset_buffer(tdm_layer *layer)
627 {
628         tdm_virtual_layer_data *layer_data = layer;
629
630         RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
631
632         layer_data->display_buffer = NULL;
633         layer_data->display_buffer_changed = 1;
634
635         return TDM_ERROR_NONE;
636 }