set initialization value
[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_voutput_data tdm_virtual_voutput_data;
9 typedef struct _tdm_virtual_layer_data tdm_virtual_layer_data;
10 typedef struct _tdm_virtual_event_data tdm_virtual_event_data;
11
12 typedef enum {
13         TDM_VIRTUAL_EVENT_TYPE_WAIT,
14         TDM_VIRTUAL_EVENT_TYPE_COMMIT,
15         TDM_VIRTUAL_EVENT_TYPE_VCOMMIT,
16 } tdm_virtual_event_type;
17
18 struct _tdm_virtual_event_data {
19         struct list_head link;
20
21         tdm_virtual_event_type type;
22         tdm_virtual_output_data *output_data;
23         void *user_data;
24 };
25
26 struct _tdm_virtual_output_data {
27         struct list_head link;
28
29         /* data which are fixed at initializing */
30         tdm_virtual_data *virtual_data;
31         tdm_virtual_voutput_data *voutput_data;
32
33         char name[TDM_NAME_LEN]; /* output name */
34         uint32_t pipe;
35         tdm_output_type connector_type;
36         struct list_head layer_list;
37         tdm_virtual_layer_data *primary_layer;
38
39         tdm_output_dpms dpms;
40
41         /* not fixed data below */
42         tdm_output_vblank_handler vblank_func;
43         tdm_output_commit_handler commit_func;
44         void *commit_user_data;
45
46         tdm_output_conn_status status;
47         tdm_output_status_handler status_func;
48         void *status_user_data;
49
50         int mode_changed;
51         const tdm_output_mode *current_mode;
52
53         tdm_event_loop_source *timer;
54         unsigned int timer_waiting;
55         struct list_head timer_event_list;
56 };
57
58 struct _tdm_virtual_voutput_data {
59         struct list_head link;
60
61         /* data which are fixed at initializing */
62         tdm_virtual_data *virtual_data;
63         tdm_virtual_output_data *output_data;
64
65         char name[TDM_NAME_LEN]; /* output name */
66
67         tdm_voutput_commit_handler vcommit_func;
68
69         tdm_output_mode *output_modes;
70         int mode_count;
71
72         unsigned int mmwidth;
73         unsigned int mmheight;
74 };
75
76
77 struct _tdm_virtual_layer_data {
78         struct list_head link;
79
80         /* data which are fixed at initializing */
81         tdm_virtual_data *virtual_data;
82         tdm_virtual_output_data *output_data;
83         tdm_layer_capability capabilities;
84         int zpos;
85
86         /* not fixed data below */
87         tdm_info_layer info;
88         int info_changed;
89
90         tbm_surface_h display_buffer;
91         int display_buffer_changed;
92 };
93
94 static void
95 _tdm_virtual_display_cb_event(tdm_virtual_output_data *output_data, tdm_virtual_event_data *event_data,
96                                                         unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec)
97 {
98         tdm_virtual_voutput_data *voutput_data = NULL;
99
100         switch (event_data->type) {
101         case TDM_VIRTUAL_EVENT_TYPE_WAIT:
102                 if (output_data->vblank_func)
103                         output_data->vblank_func(output_data, sequence, tv_sec, tv_usec, event_data->user_data);
104                 break;
105         case TDM_VIRTUAL_EVENT_TYPE_COMMIT:
106                 if (output_data->commit_func)
107                         output_data->commit_func(output_data, sequence, tv_sec, tv_usec, event_data->user_data);
108                 break;
109         case TDM_VIRTUAL_EVENT_TYPE_VCOMMIT:
110                 voutput_data = output_data->voutput_data;
111                 voutput_data->vcommit_func(voutput_data, sequence, tv_sec, tv_usec, NULL);
112         default:
113                 break;
114         }
115 }
116
117 static void _tdm_virtual_get_current_time(unsigned int *tv_sec, unsigned int *tv_usec)
118 {
119         struct timespec tp;
120
121         if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) {
122                 *tv_sec = tp.tv_sec;
123                 *tv_usec = tp.tv_nsec / 1000;
124         } else {
125                 *tv_sec = *tv_usec = 0;
126         }
127 }
128
129 static tdm_error
130 _tdm_virtual_display_cb_timeout(void *user_data)
131 {
132         tdm_virtual_output_data *output_data = user_data;
133         tdm_virtual_event_data *e = NULL, *ee = NULL;
134         unsigned int tv_sec, tv_usec;
135         static unsigned int sequence = 0;
136
137         sequence++;
138
139         _tdm_virtual_get_current_time(&tv_sec, &tv_usec);
140
141         LIST_FOR_EACH_ENTRY_SAFE(e, ee, &output_data->timer_event_list, link) {
142                 LIST_DEL(&e->link);
143                 _tdm_virtual_display_cb_event(output_data, e, sequence, tv_sec, tv_usec);
144                 free(e);
145         }
146
147         return TDM_ERROR_NONE;
148 }
149
150 static tdm_error
151 _tdm_virtual_display_wait_vblank(tdm_virtual_output_data *output_data, int interval, tdm_virtual_event_data *event_data)
152 {
153         tdm_error ret;
154         unsigned int ms;
155
156         RETURN_VAL_IF_FAIL(output_data->timer != NULL, TDM_ERROR_OPERATION_FAILED);
157         RETURN_VAL_IF_FAIL(output_data->current_mode->vrefresh > 0, TDM_ERROR_OPERATION_FAILED);
158
159         if (output_data->timer_waiting) {
160                 LIST_ADDTAIL(&event_data->link, &output_data->timer_event_list);
161                 return TDM_ERROR_NONE;
162         }
163
164         if (interval == -1)
165                 ms = 1;
166         else
167                 ms = ((double)1000.0 / output_data->current_mode->vrefresh) * interval;
168
169         ret = tdm_event_loop_source_timer_update(output_data->timer, ms);
170         if (ret != TDM_ERROR_NONE)
171                 return ret;
172
173         LIST_ADDTAIL(&event_data->link, &output_data->timer_event_list);
174
175         return TDM_ERROR_NONE;
176 }
177
178 static void
179 _tdm_virtual_display_destroy_layer_list(tdm_virtual_data *virtual_data)
180 {
181         tdm_virtual_output_data *o = NULL;
182
183         LIST_FOR_EACH_ENTRY(o, &virtual_data->output_list, link) {
184                 tdm_virtual_layer_data *l = NULL, *ll = NULL;
185                 LIST_FOR_EACH_ENTRY_SAFE(l, ll, &o->layer_list, link) {
186                         LIST_DEL(&l->link);
187                         free(l);
188                 }
189         }
190 }
191
192 void
193 tdm_virtual_display_destroy_output_list(tdm_virtual_data *virtual_data)
194 {
195         tdm_virtual_output_data *o = NULL, *oo = NULL;
196
197         if (LIST_IS_EMPTY(&virtual_data->output_list))
198                 return;
199
200         _tdm_virtual_display_destroy_layer_list(virtual_data);
201
202         LIST_FOR_EACH_ENTRY_SAFE(o, oo, &virtual_data->output_list, link) {
203                 LIST_DEL(&o->link);
204
205                 if (!LIST_IS_EMPTY(&o->timer_event_list)) {
206                         tdm_virtual_event_data *e = NULL, *ee = NULL;
207                         LIST_FOR_EACH_ENTRY_SAFE(e, ee, &o->timer_event_list, link) {
208                                 LIST_DEL(&e->link);
209                                 free(e);
210                         }
211                 }
212
213                 if (o->timer)
214                         tdm_event_loop_source_remove(o->timer);
215
216                 free(o);
217         }
218 }
219
220 tdm_error
221 virtual_display_get_capability(tdm_backend_data *bdata, tdm_caps_display *caps)
222 {
223         RETURN_VAL_IF_FAIL(caps, TDM_ERROR_INVALID_PARAMETER);
224
225         caps->max_layer_count = -1; /* not defined */
226
227         return TDM_ERROR_NONE;
228 }
229
230 tdm_output **
231 virtual_display_get_outputs(tdm_backend_data *bdata, int *count, tdm_error *error)
232 {
233         tdm_virtual_data *virtual_data = bdata;
234         tdm_virtual_output_data *output_data = NULL;
235         tdm_output **outputs;
236         tdm_error ret;
237         int i;
238
239         RETURN_VAL_IF_FAIL(virtual_data, NULL);
240         RETURN_VAL_IF_FAIL(count, NULL);
241
242         *count = 0;
243         LIST_FOR_EACH_ENTRY(output_data, &virtual_data->output_list, link)
244                 (*count)++;
245
246         if (*count == 0) {
247                 ret = TDM_ERROR_NONE;
248                 goto failed_get;
249         }
250
251         /* will be freed in frontend */
252         outputs = calloc(*count, sizeof(tdm_virtual_output_data *));
253         if (!outputs) {
254                 TDM_ERR("failed: alloc memory");
255                 *count = 0;
256                 ret = TDM_ERROR_OUT_OF_MEMORY;
257                 goto failed_get;
258         }
259
260         i = 0;
261         LIST_FOR_EACH_ENTRY(output_data, &virtual_data->output_list, link)
262                 outputs[i++] = output_data;
263
264         if (error)
265                 *error = TDM_ERROR_NONE;
266
267         return outputs;
268 failed_get:
269         if (error)
270                 *error = ret;
271         return NULL;
272 }
273
274 tdm_error
275 virtual_display_get_fd(tdm_backend_data *bdata, int *fd)
276 {
277         tdm_virtual_data *virtual_data = bdata;
278
279         RETURN_VAL_IF_FAIL(virtual_data, TDM_ERROR_INVALID_PARAMETER);
280         RETURN_VAL_IF_FAIL(fd, TDM_ERROR_INVALID_PARAMETER);
281
282         *fd = virtual_data->pipe[0];
283
284         return TDM_ERROR_NONE;
285 }
286
287 tdm_error
288 virtual_display_handle_events(tdm_backend_data *bdata)
289 {
290         return TDM_ERROR_NONE;
291 }
292
293 tdm_error
294 virtual_output_get_capability(tdm_output *output, tdm_caps_output *caps)
295 {
296         tdm_virtual_output_data *output_data = output;
297         tdm_virtual_voutput_data *voutput_data = NULL;
298         tdm_error ret;
299
300         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
301         RETURN_VAL_IF_FAIL(caps, TDM_ERROR_INVALID_PARAMETER);
302
303         voutput_data = output_data->voutput_data;
304
305         memset(caps, 0, sizeof(tdm_caps_output));
306
307         snprintf(caps->maker, TDM_NAME_LEN, "virtual");
308         snprintf(caps->model, TDM_NAME_LEN, "virtual");
309         snprintf(caps->name, TDM_NAME_LEN, "%s", output_data->name);
310
311         caps->status = output_data->status;
312         caps->type = output_data->connector_type;
313         caps->type_id = 0;
314
315         if (output_data->status == TDM_OUTPUT_CONN_STATUS_CONNECTED ||
316                 output_data->status == TDM_OUTPUT_CONN_STATUS_MODE_SETTED) {
317                 caps->mode_count = voutput_data->mode_count;
318                 if (voutput_data->mode_count != 0) {
319                         caps->modes = calloc(voutput_data->mode_count, sizeof(tdm_output_mode));
320                         if (!caps->modes) {
321                                 ret = TDM_ERROR_OUT_OF_MEMORY;
322                                 TDM_ERR("alloc failed\n");
323                                 goto failed_get;
324                         }
325                         memcpy(caps->modes, voutput_data->output_modes, voutput_data->mode_count * sizeof(tdm_output_mode));
326                 }
327
328                 caps->mmWidth = voutput_data->mmwidth;
329                 caps->mmHeight = voutput_data->mmheight;
330         } else {
331                 caps->modes = NULL;
332                 caps->mode_count = 0;
333                 caps->mmWidth = 0;
334                 caps->mmHeight = 0;
335         }
336         caps->subpixel = 1;
337
338         caps->min_w = -1;
339         caps->min_h = -1;
340         caps->max_w = -1;
341         caps->max_h = -1;
342         caps->preferred_align = -1;
343
344         caps->prop_count = 0;
345
346         return TDM_ERROR_NONE;
347 failed_get:
348         memset(caps, 0, sizeof(tdm_caps_output));
349         return ret;
350 }
351
352 tdm_layer **
353 virtual_output_get_layers(tdm_output *output,  int *count, tdm_error *error)
354 {
355         tdm_virtual_output_data *output_data = output;
356         tdm_virtual_layer_data *layer_data = NULL;
357         tdm_layer **layers;
358         tdm_error ret;
359         int i;
360
361         RETURN_VAL_IF_FAIL(output_data, NULL);
362         RETURN_VAL_IF_FAIL(count, NULL);
363
364         *count = 0;
365         LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link)
366                 (*count)++;
367
368         if (*count == 0) {
369                 ret = TDM_ERROR_NONE;
370                 goto failed_get;
371         }
372
373         /* will be freed in frontend */
374         layers = calloc(*count, sizeof(tdm_virtual_layer_data *));
375         if (!layers) {
376                 TDM_ERR("failed: alloc memory");
377                 *count = 0;
378                 ret = TDM_ERROR_OUT_OF_MEMORY;
379                 goto failed_get;
380         }
381
382         i = 0;
383         LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link)
384                 layers[i++] = layer_data;
385
386         if (error)
387                 *error = TDM_ERROR_NONE;
388
389         return layers;
390 failed_get:
391         if (error)
392                 *error = ret;
393         return NULL;
394 }
395
396 tdm_error
397 virtual_output_wait_vblank(tdm_output *output, int interval, int sync, void *user_data)
398 {
399         tdm_virtual_output_data *output_data = output;
400         tdm_virtual_event_data *event_data;
401         tdm_error ret;
402
403         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
404
405         event_data = calloc(1, sizeof(tdm_virtual_event_data));
406         if (!event_data) {
407                 TDM_ERR("alloc failed");
408                 return TDM_ERROR_OUT_OF_MEMORY;
409         }
410
411         event_data->type = TDM_VIRTUAL_EVENT_TYPE_WAIT;
412         event_data->output_data = output_data;
413         event_data->user_data = user_data;
414
415         ret = _tdm_virtual_display_wait_vblank(output_data, interval, event_data);
416         if (ret != TDM_ERROR_NONE) {
417                 free(event_data);
418                 return ret;
419         }
420
421         return TDM_ERROR_NONE;
422 }
423
424 tdm_error
425 virtual_output_set_vblank_handler(tdm_output *output, tdm_output_vblank_handler func)
426 {
427         tdm_virtual_output_data *output_data = output;
428
429         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
430         RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER);
431
432         output_data->vblank_func = func;
433
434         return TDM_ERROR_NONE;
435 }
436
437 tdm_error
438 virtual_output_commit(tdm_output *output, int sync, void *user_data)
439 {
440         tdm_virtual_output_data *output_data = output;
441         tdm_virtual_voutput_data *voutput_data = NULL;
442         tdm_virtual_layer_data *layer_data = NULL;
443         tdm_virtual_event_data *event_data;
444         tdm_error ret;
445
446         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
447
448         voutput_data = output_data->voutput_data;
449         RETURN_VAL_IF_FAIL(voutput_data, TDM_ERROR_INVALID_PARAMETER);
450
451         if (output_data->mode_changed) {
452                 output_data->mode_changed = 0;
453                 output_data->status = TDM_OUTPUT_CONN_STATUS_MODE_SETTED;
454
455                 if (output_data->status_func)
456                         output_data->status_func(output_data, TDM_OUTPUT_CONN_STATUS_MODE_SETTED,
457                                                                          output_data->status_user_data);
458         }
459
460         if (voutput_data->vcommit_func) {
461                 layer_data = output_data->primary_layer;
462                 if (layer_data->display_buffer_changed) {
463                         output_data->commit_user_data = user_data;
464                         event_data = calloc(1, sizeof(tdm_virtual_event_data));
465                         if (!event_data) {
466                                 TDM_ERR("alloc failed");
467                                 return TDM_ERROR_OUT_OF_MEMORY;
468                         }
469
470                         event_data->type = TDM_VIRTUAL_EVENT_TYPE_VCOMMIT;
471                         event_data->output_data = output_data;
472                         event_data->user_data = user_data;
473
474                         ret = _tdm_virtual_display_wait_vblank(output_data, 1, event_data);
475                         if (ret != TDM_ERROR_NONE) {
476                                 free(event_data);
477                                 return ret;
478                         }
479                 }
480         } else {
481                 event_data = calloc(1, sizeof(tdm_virtual_event_data));
482                 if (!event_data) {
483                         TDM_ERR("alloc failed");
484                         return TDM_ERROR_OUT_OF_MEMORY;
485                 }
486
487                 event_data->type = TDM_VIRTUAL_EVENT_TYPE_COMMIT;
488                 event_data->output_data = output_data;
489                 event_data->user_data = user_data;
490
491                 ret = _tdm_virtual_display_wait_vblank(output_data, 1, event_data);
492                 if (ret != TDM_ERROR_NONE) {
493                         free(event_data);
494                         return ret;
495                 }
496         }
497
498         return TDM_ERROR_NONE;
499 }
500
501 tdm_error
502 virtual_output_set_commit_handler(tdm_output *output, tdm_output_commit_handler func)
503 {
504         tdm_virtual_output_data *output_data = output;
505
506         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
507         RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER);
508
509         output_data->commit_func = func;
510
511         return TDM_ERROR_NONE;
512 }
513
514 tdm_error
515 virtual_output_set_dpms(tdm_output *output, tdm_output_dpms dpms_value)
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(dpms_value <= TDM_OUTPUT_DPMS_OFF, TDM_ERROR_INVALID_PARAMETER);
521
522         TDM_DBG("dpms change [%d] -> [%d]", output_data->dpms, dpms_value);
523
524         output_data->dpms = dpms_value;
525
526         return TDM_ERROR_NONE;
527 }
528
529 tdm_error
530 virtual_output_get_dpms(tdm_output *output, tdm_output_dpms *dpms_value)
531 {
532         tdm_virtual_output_data *output_data = output;
533
534         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
535         RETURN_VAL_IF_FAIL(dpms_value, TDM_ERROR_INVALID_PARAMETER);
536
537         *dpms_value = output_data->dpms;
538
539         return TDM_ERROR_NONE;
540 }
541
542 tdm_error
543 virtual_output_set_mode(tdm_output *output, const tdm_output_mode *mode)
544 {
545         tdm_virtual_output_data *output_data = output;
546
547         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
548         RETURN_VAL_IF_FAIL(mode, TDM_ERROR_INVALID_PARAMETER);
549
550         output_data->current_mode = mode;
551         output_data->mode_changed = 1;
552
553         return TDM_ERROR_NONE;
554 }
555
556 tdm_error
557 virtual_output_get_mode(tdm_output *output, const tdm_output_mode **mode)
558 {
559         tdm_virtual_output_data *output_data = output;
560
561         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
562         RETURN_VAL_IF_FAIL(mode, TDM_ERROR_INVALID_PARAMETER);
563
564         *mode = output_data->current_mode;
565
566         return TDM_ERROR_NONE;
567 }
568
569 tdm_error
570 virtual_output_set_status_handler(tdm_output *output,
571                                                                   tdm_output_status_handler func, void *user_data)
572 {
573         tdm_virtual_output_data *output_data = output;
574
575         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
576         RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER);
577
578         output_data->status_func = func;
579         output_data->status_user_data = user_data;
580
581         return TDM_ERROR_NONE;
582 }
583
584 tdm_error
585 virtual_output_set_available_mode(tdm_voutput *voutput, const tdm_output_mode *modes, int count)
586 {
587         tdm_virtual_voutput_data *voutput_data = voutput;
588         tdm_virtual_output_data *output_data = NULL;
589
590         RETURN_VAL_IF_FAIL(voutput_data, TDM_ERROR_INVALID_PARAMETER);
591         RETURN_VAL_IF_FAIL(modes, TDM_ERROR_INVALID_PARAMETER);
592         RETURN_VAL_IF_FAIL(count > 0, TDM_ERROR_INVALID_PARAMETER);
593
594         output_data = voutput_data->output_data;
595
596         /* set available mode only permittied disconnect status */
597         RETURN_VAL_IF_FAIL(output_data->status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED, TDM_ERROR_BUSY);
598
599         if (voutput_data->output_modes)
600                 free(voutput_data->output_modes);
601         voutput_data->output_modes = NULL;
602
603         voutput_data->output_modes = calloc(1, count * sizeof(tdm_output_mode));
604         RETURN_VAL_IF_FAIL(voutput_data->output_modes != NULL, TDM_ERROR_OUT_OF_MEMORY);
605
606         memcpy(voutput_data->output_modes, modes, count * sizeof(tdm_output_mode));
607         voutput_data->mode_count = count;
608
609         return TDM_ERROR_NONE;
610 }
611
612 tdm_error
613 virtual_output_set_physical_size(tdm_voutput *voutput, unsigned int mmwidth, unsigned int mmheight)
614 {
615         tdm_virtual_voutput_data *voutput_data = voutput;
616
617         RETURN_VAL_IF_FAIL(voutput_data, TDM_ERROR_INVALID_PARAMETER);
618         RETURN_VAL_IF_FAIL(mmwidth != 0, TDM_ERROR_INVALID_PARAMETER);
619         RETURN_VAL_IF_FAIL(mmheight != 0, TDM_ERROR_INVALID_PARAMETER);
620
621         voutput_data->mmwidth = mmwidth;
622         voutput_data->mmheight = mmheight;
623
624         return TDM_ERROR_NONE;
625 }
626
627 tdm_error
628 virtual_output_connect(tdm_voutput *voutput)
629 {
630         tdm_virtual_voutput_data *voutput_data = voutput;
631         tdm_virtual_output_data *output_data = NULL;
632
633         RETURN_VAL_IF_FAIL(voutput_data, TDM_ERROR_INVALID_PARAMETER);
634
635         output_data = voutput_data->output_data;
636
637         if (output_data->status == TDM_OUTPUT_CONN_STATUS_CONNECTED ||
638                 output_data->status == TDM_OUTPUT_CONN_STATUS_MODE_SETTED)
639                 return TDM_ERROR_NONE;
640
641         output_data->status = TDM_OUTPUT_CONN_STATUS_CONNECTED;
642
643         if (output_data->status_func)
644                 output_data->status_func(output_data, output_data->status,
645                                                                  output_data->status_user_data);
646
647         return TDM_ERROR_NONE;
648 }
649
650 tdm_error
651 virtual_output_disconnect(tdm_voutput *voutput)
652 {
653
654         tdm_virtual_voutput_data *voutput_data = voutput;
655         tdm_virtual_output_data *output_data = NULL;
656
657         RETURN_VAL_IF_FAIL(voutput_data, TDM_ERROR_INVALID_PARAMETER);
658
659         output_data = voutput_data->output_data;
660
661         if (output_data->status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED)
662                 return TDM_ERROR_NONE;
663
664         output_data->status = TDM_OUTPUT_CONN_STATUS_DISCONNECTED;
665
666         if (output_data->status_func)
667                 output_data->status_func(output_data, output_data->status,
668                                                                  output_data->status_user_data);
669
670         return TDM_ERROR_NONE;
671 }
672
673 tdm_error
674 virtual_layer_get_capability(tdm_layer *layer, tdm_caps_layer *caps)
675 {
676         tdm_virtual_layer_data *layer_data = layer;
677
678         RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
679         RETURN_VAL_IF_FAIL(caps, TDM_ERROR_INVALID_PARAMETER);
680
681         memset(caps, 0, sizeof(tdm_caps_layer));
682
683         caps->capabilities = layer_data->capabilities;
684         caps->zpos = layer_data->zpos;
685
686         caps->format_count = 2;
687         caps->formats = calloc(caps->format_count, sizeof(tbm_format));
688         if (!caps->formats) {
689                 TDM_ERR("alloc failed\n");
690                 free(caps->formats);
691                 memset(caps, 0, sizeof(tdm_caps_layer));
692                 return TDM_ERROR_OUT_OF_MEMORY;
693         }
694
695         caps->formats[0] = TBM_FORMAT_ARGB8888;
696         caps->formats[1] = TBM_FORMAT_XRGB8888;
697
698         caps->prop_count = 0;
699
700         return TDM_ERROR_NONE;
701 }
702
703 tdm_error
704 virtual_layer_set_info(tdm_layer *layer, tdm_info_layer *info)
705 {
706         tdm_virtual_layer_data *layer_data = layer;
707
708         RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
709         RETURN_VAL_IF_FAIL(info, TDM_ERROR_INVALID_PARAMETER);
710
711         layer_data->info = *info;
712         layer_data->info_changed = 1;
713
714         return TDM_ERROR_NONE;
715 }
716
717 tdm_error
718 virtual_layer_get_info(tdm_layer *layer, tdm_info_layer *info)
719 {
720         tdm_virtual_layer_data *layer_data = layer;
721
722         RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
723         RETURN_VAL_IF_FAIL(info, TDM_ERROR_INVALID_PARAMETER);
724
725         *info = layer_data->info;
726
727         return TDM_ERROR_NONE;
728 }
729
730 tdm_error
731 virtual_layer_set_buffer(tdm_layer *layer, tbm_surface_h buffer)
732 {
733         tdm_virtual_layer_data *layer_data = layer;
734
735         RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
736         RETURN_VAL_IF_FAIL(buffer, TDM_ERROR_INVALID_PARAMETER);
737
738         layer_data->display_buffer = buffer;
739         layer_data->display_buffer_changed = 1;
740
741         return TDM_ERROR_NONE;
742 }
743
744 tdm_error
745 virtual_layer_unset_buffer(tdm_layer *layer)
746 {
747         tdm_virtual_layer_data *layer_data = layer;
748
749         RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
750
751         layer_data->display_buffer = NULL;
752         layer_data->display_buffer_changed = 1;
753
754         return TDM_ERROR_NONE;
755 }
756
757 tdm_voutput *
758 virtual_output_create(tdm_backend_data *bdata, const char *name, tdm_error *error)
759 {
760         tdm_virtual_data *virtual_data = bdata;
761         tdm_virtual_voutput_data *voutput_data = NULL;
762         tdm_virtual_output_data *output_data = NULL;
763         tdm_virtual_layer_data *layer_data = NULL;
764
765         if (!virtual_data || !name) {
766                 TDM_ERR("invalid parameter");
767                 if (error) *error = TDM_ERROR_INVALID_PARAMETER;
768                 return NULL;
769         }
770
771         voutput_data = calloc(1, sizeof(tdm_virtual_voutput_data));
772         if (!voutput_data) {
773                 TDM_ERR("alloc failed");
774                 if (error) *error = TDM_ERROR_OUT_OF_MEMORY;
775                 return NULL;
776         }
777
778         voutput_data->output_modes = calloc(1, sizeof(tdm_output_mode));
779         if (!voutput_data->output_modes) {
780                 TDM_ERR("alloc failed");
781                 goto create_fail;
782         }
783
784         /* default mode */
785         snprintf(voutput_data->output_modes->name, TDM_NAME_LEN, "640x480");
786         voutput_data->output_modes->vrefresh = 30;
787         voutput_data->output_modes->clock = 25200;
788         voutput_data->output_modes->hdisplay = 640;
789         voutput_data->output_modes->hsync_start = 656;
790         voutput_data->output_modes->hsync_end = 752;
791         voutput_data->output_modes->htotal = 800;
792         voutput_data->output_modes->hskew = 0;
793         voutput_data->output_modes->vdisplay = 480;
794         voutput_data->output_modes->vsync_start = 490;
795         voutput_data->output_modes->vsync_end = 492;
796         voutput_data->output_modes->vtotal = 525;
797         voutput_data->output_modes->vscan = 0;
798         voutput_data->output_modes->flags = 0;
799         voutput_data->output_modes->type = 0;
800         voutput_data->mode_count = 1;
801
802         voutput_data->mmwidth = 10;
803         voutput_data->mmheight = 10;
804
805         voutput_data->virtual_data = virtual_data;
806
807         output_data = calloc(1, sizeof(tdm_virtual_output_data));
808         if (!output_data) {
809                 TDM_ERR("alloc failed");
810                 goto create_fail;
811         }
812         voutput_data->output_data = output_data;
813
814         LIST_INITHEAD(&output_data->layer_list);
815
816         output_data->virtual_data = virtual_data;
817         output_data->voutput_data = voutput_data;
818         output_data->pipe = 0;
819         output_data->connector_type = TDM_OUTPUT_TYPE_Unknown;
820         output_data->status = TDM_OUTPUT_CONN_STATUS_DISCONNECTED;
821
822         snprintf(voutput_data->name, TDM_NAME_LEN, "%s", name);
823         snprintf(output_data->name, TDM_NAME_LEN, "%s", name);
824
825         output_data->timer = tdm_event_loop_add_timer_handler(virtual_data->dpy,
826                                                                                                                   _tdm_virtual_display_cb_timeout,
827                                                                                                                   output_data,
828                                                                                                                   NULL);
829         if (!output_data->timer) goto create_fail;
830
831         LIST_INITHEAD(&output_data->timer_event_list);
832
833         /* The TDM virtual backend output support only one layer. */
834         layer_data = calloc(1, sizeof(tdm_virtual_layer_data));
835         if (!layer_data) {
836                 TDM_ERR("alloc failed");
837                 goto create_fail;
838         }
839
840         layer_data->virtual_data = virtual_data;
841         layer_data->output_data = output_data;
842         layer_data->zpos = 0;
843
844         layer_data->capabilities = TDM_LAYER_CAPABILITY_PRIMARY | TDM_LAYER_CAPABILITY_GRAPHIC;
845         output_data->primary_layer = layer_data;
846
847         LIST_ADDTAIL(&voutput_data->link, &virtual_data->voutput_list);
848         LIST_ADDTAIL(&output_data->link, &virtual_data->output_list);
849         LIST_ADDTAIL(&layer_data->link, &output_data->layer_list);
850
851         if (error) *error = TDM_ERROR_NONE;
852
853         TDM_DBG("virtual output create(%s)(%p)(%p)", output_data->name, voutput_data, output_data);
854
855         return voutput_data;
856
857 create_fail:
858         if (output_data) free(output_data);
859         if (voutput_data->output_modes) free(voutput_data->output_modes);
860         if (voutput_data) free(voutput_data);
861
862         if (error) *error = TDM_ERROR_OUT_OF_MEMORY;
863
864         return NULL;
865 }
866
867 tdm_error
868 virtual_output_destroy(tdm_voutput *voutput)
869 {
870         tdm_virtual_data *virtual_data = NULL;
871         tdm_virtual_voutput_data *vo = NULL, *voutput_data = voutput;
872         int find = 0;
873
874         RETURN_VAL_IF_FAIL(voutput_data, TDM_ERROR_INVALID_PARAMETER);
875
876         virtual_data = voutput_data->virtual_data;
877
878         LIST_FOR_EACH_ENTRY(vo, &virtual_data->voutput_list, link) {
879                 if (vo == voutput_data) {
880                         find = 1;
881                         break;
882                 }
883         }
884
885         if (find) {
886                 tdm_virtual_layer_data *l = NULL, *ll = NULL;
887                 tdm_virtual_output_data *output_data = NULL;
888
889                 TDM_DBG("virtual output destroy(%s)", voutput_data->name);
890
891                 output_data = voutput_data->output_data;
892
893                 if (!LIST_IS_EMPTY(&output_data->timer_event_list)) {
894                         tdm_virtual_event_data *e = NULL, *ee = NULL;
895                         LIST_FOR_EACH_ENTRY_SAFE(e, ee, &output_data->timer_event_list, link) {
896                                 LIST_DEL(&e->link);
897                                 free(e);
898                         }
899                 }
900
901                 if (output_data->timer)
902                         tdm_event_loop_source_remove(output_data->timer);
903
904                 LIST_FOR_EACH_ENTRY_SAFE(l, ll, &output_data->layer_list, link) {
905                         LIST_DEL(&l->link);
906                         free(l);
907                 }
908
909                 LIST_DEL(&output_data->link);
910                 free(output_data);
911
912                 if (voutput_data->output_modes)
913                         free(voutput_data->output_modes);
914                 LIST_DEL(&voutput_data->link);
915                 free(voutput_data);
916         } else
917                 return TDM_ERROR_INVALID_PARAMETER;
918
919         return TDM_ERROR_NONE;
920 }
921
922 tdm_output *
923 virtual_output_get_output(tdm_voutput *voutput, tdm_error *error)
924 {
925         tdm_virtual_voutput_data *voutput_data = voutput;
926
927         if (!voutput_data) {
928                 if (error) *error = TDM_ERROR_INVALID_PARAMETER;
929                 return NULL;
930         }
931
932         if (error) *error = TDM_ERROR_NONE;
933
934         return voutput_data->output_data;
935 }
936
937 tdm_error
938 virtual_output_set_commit_func(tdm_voutput *voutput,  tdm_voutput_commit_handler commit_func)
939 {
940         tdm_virtual_voutput_data *voutput_data = voutput;
941
942         RETURN_VAL_IF_FAIL(voutput_data, TDM_ERROR_INVALID_PARAMETER);
943         RETURN_VAL_IF_FAIL(commit_func, TDM_ERROR_INVALID_PARAMETER);
944
945         voutput_data->vcommit_func = commit_func;
946
947         return TDM_ERROR_NONE;
948 }
949
950 tdm_error
951 virtual_output_commit_done(tdm_voutput *voutput)
952 {
953         tdm_virtual_voutput_data *voutput_data = voutput;
954         tdm_virtual_output_data *output_data = NULL;
955         unsigned int tv_sec, tv_usec;
956         static unsigned int sequence = 0;
957         tdm_virtual_event_data *event_data;
958         tdm_error ret = TDM_ERROR_NONE;
959
960         RETURN_VAL_IF_FAIL(voutput_data, TDM_ERROR_INVALID_PARAMETER);
961         output_data = voutput_data->output_data;
962
963         sequence++;
964
965         _tdm_virtual_get_current_time(&tv_sec, &tv_usec);
966
967         event_data = calloc(1, sizeof(tdm_virtual_event_data));
968         if (!event_data) {
969                 TDM_ERR("alloc failed");
970                 return TDM_ERROR_OUT_OF_MEMORY;
971         }
972
973         event_data->type = TDM_VIRTUAL_EVENT_TYPE_COMMIT;
974         event_data->output_data = output_data;
975         event_data->user_data = output_data->commit_user_data;
976
977         ret = _tdm_virtual_display_wait_vblank(output_data, 1, event_data);
978         if (ret != TDM_ERROR_NONE) {
979                 free(event_data);
980                 return ret;
981         }
982
983         return TDM_ERROR_NONE;
984 }
985