virtual: fix voutput commit buffer send fail
[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         layer_data = output_data->primary_layer;
461
462         if (voutput_data->vcommit_func) {
463                 if (layer_data->display_buffer_changed) {
464                         output_data->commit_user_data = user_data;
465                         event_data = calloc(1, sizeof(tdm_virtual_event_data));
466                         if (!event_data) {
467                                 TDM_ERR("alloc failed");
468                                 return TDM_ERROR_OUT_OF_MEMORY;
469                         }
470
471                         event_data->type = TDM_VIRTUAL_EVENT_TYPE_VCOMMIT;
472                         event_data->output_data = output_data;
473                         event_data->user_data = user_data;
474
475                         ret = _tdm_virtual_display_wait_vblank(output_data, 1, event_data);
476                         if (ret != TDM_ERROR_NONE) {
477                                 free(event_data);
478                                 return ret;
479                         }
480                 }
481         } else {
482                 event_data = calloc(1, sizeof(tdm_virtual_event_data));
483                 if (!event_data) {
484                         TDM_ERR("alloc failed");
485                         return TDM_ERROR_OUT_OF_MEMORY;
486                 }
487
488                 event_data->type = TDM_VIRTUAL_EVENT_TYPE_COMMIT;
489                 event_data->output_data = output_data;
490                 event_data->user_data = user_data;
491
492                 ret = _tdm_virtual_display_wait_vblank(output_data, 1, event_data);
493                 if (ret != TDM_ERROR_NONE) {
494                         free(event_data);
495                         return ret;
496                 }
497         }
498
499         layer_data->display_buffer_changed = 0;
500
501         return TDM_ERROR_NONE;
502 }
503
504 tdm_error
505 virtual_output_set_commit_handler(tdm_output *output, tdm_output_commit_handler func)
506 {
507         tdm_virtual_output_data *output_data = output;
508
509         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
510         RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER);
511
512         output_data->commit_func = func;
513
514         return TDM_ERROR_NONE;
515 }
516
517 tdm_error
518 virtual_output_set_dpms(tdm_output *output, tdm_output_dpms dpms_value)
519 {
520         tdm_virtual_output_data *output_data = output;
521
522         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
523         RETURN_VAL_IF_FAIL(dpms_value <= TDM_OUTPUT_DPMS_OFF, TDM_ERROR_INVALID_PARAMETER);
524
525         TDM_DBG("dpms change [%d] -> [%d]", output_data->dpms, dpms_value);
526
527         output_data->dpms = dpms_value;
528
529         return TDM_ERROR_NONE;
530 }
531
532 tdm_error
533 virtual_output_get_dpms(tdm_output *output, tdm_output_dpms *dpms_value)
534 {
535         tdm_virtual_output_data *output_data = output;
536
537         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
538         RETURN_VAL_IF_FAIL(dpms_value, TDM_ERROR_INVALID_PARAMETER);
539
540         *dpms_value = output_data->dpms;
541
542         return TDM_ERROR_NONE;
543 }
544
545 tdm_error
546 virtual_output_set_mode(tdm_output *output, const tdm_output_mode *mode)
547 {
548         tdm_virtual_output_data *output_data = output;
549
550         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
551         RETURN_VAL_IF_FAIL(mode, TDM_ERROR_INVALID_PARAMETER);
552
553         output_data->current_mode = mode;
554         output_data->mode_changed = 1;
555
556         return TDM_ERROR_NONE;
557 }
558
559 tdm_error
560 virtual_output_get_mode(tdm_output *output, const tdm_output_mode **mode)
561 {
562         tdm_virtual_output_data *output_data = output;
563
564         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
565         RETURN_VAL_IF_FAIL(mode, TDM_ERROR_INVALID_PARAMETER);
566
567         *mode = output_data->current_mode;
568
569         return TDM_ERROR_NONE;
570 }
571
572 tdm_error
573 virtual_output_set_status_handler(tdm_output *output,
574                                                                   tdm_output_status_handler func, void *user_data)
575 {
576         tdm_virtual_output_data *output_data = output;
577
578         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
579         RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER);
580
581         output_data->status_func = func;
582         output_data->status_user_data = user_data;
583
584         return TDM_ERROR_NONE;
585 }
586
587 tdm_error
588 virtual_output_set_available_mode(tdm_voutput *voutput, const tdm_output_mode *modes, int count)
589 {
590         tdm_virtual_voutput_data *voutput_data = voutput;
591         tdm_virtual_output_data *output_data = NULL;
592
593         RETURN_VAL_IF_FAIL(voutput_data, TDM_ERROR_INVALID_PARAMETER);
594         RETURN_VAL_IF_FAIL(modes, TDM_ERROR_INVALID_PARAMETER);
595         RETURN_VAL_IF_FAIL(count > 0, TDM_ERROR_INVALID_PARAMETER);
596
597         output_data = voutput_data->output_data;
598
599         /* set available mode only permittied disconnect status */
600         RETURN_VAL_IF_FAIL(output_data->status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED, TDM_ERROR_BUSY);
601
602         if (voutput_data->output_modes)
603                 free(voutput_data->output_modes);
604         voutput_data->output_modes = NULL;
605
606         voutput_data->output_modes = calloc(1, count * sizeof(tdm_output_mode));
607         RETURN_VAL_IF_FAIL(voutput_data->output_modes != NULL, TDM_ERROR_OUT_OF_MEMORY);
608
609         memcpy(voutput_data->output_modes, modes, count * sizeof(tdm_output_mode));
610         voutput_data->mode_count = count;
611
612         return TDM_ERROR_NONE;
613 }
614
615 tdm_error
616 virtual_output_set_physical_size(tdm_voutput *voutput, unsigned int mmwidth, unsigned int mmheight)
617 {
618         tdm_virtual_voutput_data *voutput_data = voutput;
619
620         RETURN_VAL_IF_FAIL(voutput_data, TDM_ERROR_INVALID_PARAMETER);
621         RETURN_VAL_IF_FAIL(mmwidth != 0, TDM_ERROR_INVALID_PARAMETER);
622         RETURN_VAL_IF_FAIL(mmheight != 0, TDM_ERROR_INVALID_PARAMETER);
623
624         voutput_data->mmwidth = mmwidth;
625         voutput_data->mmheight = mmheight;
626
627         return TDM_ERROR_NONE;
628 }
629
630 tdm_error
631 virtual_output_connect(tdm_voutput *voutput)
632 {
633         tdm_virtual_voutput_data *voutput_data = voutput;
634         tdm_virtual_output_data *output_data = NULL;
635
636         RETURN_VAL_IF_FAIL(voutput_data, TDM_ERROR_INVALID_PARAMETER);
637
638         output_data = voutput_data->output_data;
639
640         if (output_data->status == TDM_OUTPUT_CONN_STATUS_CONNECTED ||
641                 output_data->status == TDM_OUTPUT_CONN_STATUS_MODE_SETTED)
642                 return TDM_ERROR_NONE;
643
644         output_data->status = TDM_OUTPUT_CONN_STATUS_CONNECTED;
645
646         if (output_data->status_func)
647                 output_data->status_func(output_data, output_data->status,
648                                                                  output_data->status_user_data);
649
650         return TDM_ERROR_NONE;
651 }
652
653 tdm_error
654 virtual_output_disconnect(tdm_voutput *voutput)
655 {
656
657         tdm_virtual_voutput_data *voutput_data = voutput;
658         tdm_virtual_output_data *output_data = NULL;
659
660         RETURN_VAL_IF_FAIL(voutput_data, TDM_ERROR_INVALID_PARAMETER);
661
662         output_data = voutput_data->output_data;
663
664         if (output_data->status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED)
665                 return TDM_ERROR_NONE;
666
667         output_data->status = TDM_OUTPUT_CONN_STATUS_DISCONNECTED;
668
669         if (output_data->status_func)
670                 output_data->status_func(output_data, output_data->status,
671                                                                  output_data->status_user_data);
672
673         return TDM_ERROR_NONE;
674 }
675
676 tdm_error
677 virtual_layer_get_capability(tdm_layer *layer, tdm_caps_layer *caps)
678 {
679         tdm_virtual_layer_data *layer_data = layer;
680
681         RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
682         RETURN_VAL_IF_FAIL(caps, TDM_ERROR_INVALID_PARAMETER);
683
684         memset(caps, 0, sizeof(tdm_caps_layer));
685
686         caps->capabilities = layer_data->capabilities;
687         caps->zpos = layer_data->zpos;
688
689         caps->format_count = 2;
690         caps->formats = calloc(caps->format_count, sizeof(tbm_format));
691         if (!caps->formats) {
692                 TDM_ERR("alloc failed\n");
693                 free(caps->formats);
694                 memset(caps, 0, sizeof(tdm_caps_layer));
695                 return TDM_ERROR_OUT_OF_MEMORY;
696         }
697
698         caps->formats[0] = TBM_FORMAT_ARGB8888;
699         caps->formats[1] = TBM_FORMAT_XRGB8888;
700
701         caps->prop_count = 0;
702
703         return TDM_ERROR_NONE;
704 }
705
706 tdm_error
707 virtual_layer_set_info(tdm_layer *layer, tdm_info_layer *info)
708 {
709         tdm_virtual_layer_data *layer_data = layer;
710
711         RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
712         RETURN_VAL_IF_FAIL(info, TDM_ERROR_INVALID_PARAMETER);
713
714         layer_data->info = *info;
715         layer_data->info_changed = 1;
716
717         return TDM_ERROR_NONE;
718 }
719
720 tdm_error
721 virtual_layer_get_info(tdm_layer *layer, tdm_info_layer *info)
722 {
723         tdm_virtual_layer_data *layer_data = layer;
724
725         RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
726         RETURN_VAL_IF_FAIL(info, TDM_ERROR_INVALID_PARAMETER);
727
728         *info = layer_data->info;
729
730         return TDM_ERROR_NONE;
731 }
732
733 tdm_error
734 virtual_layer_set_buffer(tdm_layer *layer, tbm_surface_h buffer)
735 {
736         tdm_virtual_layer_data *layer_data = layer;
737
738         RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
739         RETURN_VAL_IF_FAIL(buffer, TDM_ERROR_INVALID_PARAMETER);
740
741         layer_data->display_buffer = buffer;
742         layer_data->display_buffer_changed = 1;
743
744         return TDM_ERROR_NONE;
745 }
746
747 tdm_error
748 virtual_layer_unset_buffer(tdm_layer *layer)
749 {
750         tdm_virtual_layer_data *layer_data = layer;
751
752         RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER);
753
754         layer_data->display_buffer = NULL;
755         layer_data->display_buffer_changed = 1;
756
757         return TDM_ERROR_NONE;
758 }
759
760 tdm_voutput *
761 virtual_output_create(tdm_backend_data *bdata, const char *name, tdm_error *error)
762 {
763         tdm_virtual_data *virtual_data = bdata;
764         tdm_virtual_voutput_data *voutput_data = NULL;
765         tdm_virtual_output_data *output_data = NULL;
766         tdm_virtual_layer_data *layer_data = NULL;
767
768         if (!virtual_data || !name) {
769                 TDM_ERR("invalid parameter");
770                 if (error) *error = TDM_ERROR_INVALID_PARAMETER;
771                 return NULL;
772         }
773
774         voutput_data = calloc(1, sizeof(tdm_virtual_voutput_data));
775         if (!voutput_data) {
776                 TDM_ERR("alloc failed");
777                 if (error) *error = TDM_ERROR_OUT_OF_MEMORY;
778                 return NULL;
779         }
780
781         voutput_data->output_modes = calloc(1, sizeof(tdm_output_mode));
782         if (!voutput_data->output_modes) {
783                 TDM_ERR("alloc failed");
784                 goto create_fail;
785         }
786
787         /* default mode */
788         snprintf(voutput_data->output_modes->name, TDM_NAME_LEN, "640x480");
789         voutput_data->output_modes->vrefresh = 30;
790         voutput_data->output_modes->clock = 25200;
791         voutput_data->output_modes->hdisplay = 640;
792         voutput_data->output_modes->hsync_start = 656;
793         voutput_data->output_modes->hsync_end = 752;
794         voutput_data->output_modes->htotal = 800;
795         voutput_data->output_modes->hskew = 0;
796         voutput_data->output_modes->vdisplay = 480;
797         voutput_data->output_modes->vsync_start = 490;
798         voutput_data->output_modes->vsync_end = 492;
799         voutput_data->output_modes->vtotal = 525;
800         voutput_data->output_modes->vscan = 0;
801         voutput_data->output_modes->flags = 0;
802         voutput_data->output_modes->type = 0;
803         voutput_data->mode_count = 1;
804
805         voutput_data->mmwidth = 10;
806         voutput_data->mmheight = 10;
807
808         voutput_data->virtual_data = virtual_data;
809
810         output_data = calloc(1, sizeof(tdm_virtual_output_data));
811         if (!output_data) {
812                 TDM_ERR("alloc failed");
813                 goto create_fail;
814         }
815         voutput_data->output_data = output_data;
816
817         LIST_INITHEAD(&output_data->layer_list);
818
819         output_data->virtual_data = virtual_data;
820         output_data->voutput_data = voutput_data;
821         output_data->pipe = 0;
822         output_data->connector_type = TDM_OUTPUT_TYPE_Unknown;
823         output_data->status = TDM_OUTPUT_CONN_STATUS_DISCONNECTED;
824
825         snprintf(voutput_data->name, TDM_NAME_LEN, "%s", name);
826         snprintf(output_data->name, TDM_NAME_LEN, "%s", name);
827
828         output_data->timer = tdm_event_loop_add_timer_handler(virtual_data->dpy,
829                                                                                                                   _tdm_virtual_display_cb_timeout,
830                                                                                                                   output_data,
831                                                                                                                   NULL);
832         if (!output_data->timer) goto create_fail;
833
834         LIST_INITHEAD(&output_data->timer_event_list);
835
836         /* The TDM virtual backend output support only one layer. */
837         layer_data = calloc(1, sizeof(tdm_virtual_layer_data));
838         if (!layer_data) {
839                 TDM_ERR("alloc failed");
840                 goto create_fail;
841         }
842
843         layer_data->virtual_data = virtual_data;
844         layer_data->output_data = output_data;
845         layer_data->zpos = 0;
846
847         layer_data->capabilities = TDM_LAYER_CAPABILITY_PRIMARY | TDM_LAYER_CAPABILITY_GRAPHIC;
848         output_data->primary_layer = layer_data;
849
850         LIST_ADDTAIL(&voutput_data->link, &virtual_data->voutput_list);
851         LIST_ADDTAIL(&output_data->link, &virtual_data->output_list);
852         LIST_ADDTAIL(&layer_data->link, &output_data->layer_list);
853
854         if (error) *error = TDM_ERROR_NONE;
855
856         TDM_DBG("virtual output create(%s)(%p)(%p)", output_data->name, voutput_data, output_data);
857
858         return voutput_data;
859
860 create_fail:
861         if (output_data) free(output_data);
862         if (voutput_data->output_modes) free(voutput_data->output_modes);
863         if (voutput_data) free(voutput_data);
864
865         if (error) *error = TDM_ERROR_OUT_OF_MEMORY;
866
867         return NULL;
868 }
869
870 tdm_error
871 virtual_output_destroy(tdm_voutput *voutput)
872 {
873         tdm_virtual_data *virtual_data = NULL;
874         tdm_virtual_voutput_data *vo = NULL, *voutput_data = voutput;
875         int find = 0;
876
877         RETURN_VAL_IF_FAIL(voutput_data, TDM_ERROR_INVALID_PARAMETER);
878
879         virtual_data = voutput_data->virtual_data;
880
881         LIST_FOR_EACH_ENTRY(vo, &virtual_data->voutput_list, link) {
882                 if (vo == voutput_data) {
883                         find = 1;
884                         break;
885                 }
886         }
887
888         if (find) {
889                 tdm_virtual_layer_data *l = NULL, *ll = NULL;
890                 tdm_virtual_output_data *output_data = NULL;
891
892                 TDM_DBG("virtual output destroy(%s)", voutput_data->name);
893
894                 output_data = voutput_data->output_data;
895
896                 if (!LIST_IS_EMPTY(&output_data->timer_event_list)) {
897                         tdm_virtual_event_data *e = NULL, *ee = NULL;
898                         LIST_FOR_EACH_ENTRY_SAFE(e, ee, &output_data->timer_event_list, link) {
899                                 LIST_DEL(&e->link);
900                                 free(e);
901                         }
902                 }
903
904                 if (output_data->timer)
905                         tdm_event_loop_source_remove(output_data->timer);
906
907                 LIST_FOR_EACH_ENTRY_SAFE(l, ll, &output_data->layer_list, link) {
908                         LIST_DEL(&l->link);
909                         free(l);
910                 }
911
912                 LIST_DEL(&output_data->link);
913                 free(output_data);
914
915                 if (voutput_data->output_modes)
916                         free(voutput_data->output_modes);
917                 LIST_DEL(&voutput_data->link);
918                 free(voutput_data);
919         } else
920                 return TDM_ERROR_INVALID_PARAMETER;
921
922         return TDM_ERROR_NONE;
923 }
924
925 tdm_output *
926 virtual_output_get_output(tdm_voutput *voutput, tdm_error *error)
927 {
928         tdm_virtual_voutput_data *voutput_data = voutput;
929
930         if (!voutput_data) {
931                 if (error) *error = TDM_ERROR_INVALID_PARAMETER;
932                 return NULL;
933         }
934
935         if (error) *error = TDM_ERROR_NONE;
936
937         return voutput_data->output_data;
938 }
939
940 tdm_error
941 virtual_output_set_commit_func(tdm_voutput *voutput,  tdm_voutput_commit_handler commit_func)
942 {
943         tdm_virtual_voutput_data *voutput_data = voutput;
944
945         RETURN_VAL_IF_FAIL(voutput_data, TDM_ERROR_INVALID_PARAMETER);
946
947         voutput_data->vcommit_func = commit_func;
948
949         return TDM_ERROR_NONE;
950 }
951
952 tdm_error
953 virtual_output_commit_done(tdm_voutput *voutput)
954 {
955         tdm_virtual_voutput_data *voutput_data = voutput;
956         tdm_virtual_output_data *output_data = NULL;
957         unsigned int tv_sec, tv_usec;
958         static unsigned int sequence = 0;
959         tdm_virtual_event_data *event_data;
960         tdm_error ret = TDM_ERROR_NONE;
961
962         RETURN_VAL_IF_FAIL(voutput_data, TDM_ERROR_INVALID_PARAMETER);
963         output_data = voutput_data->output_data;
964
965         sequence++;
966
967         _tdm_virtual_get_current_time(&tv_sec, &tv_usec);
968
969         event_data = calloc(1, sizeof(tdm_virtual_event_data));
970         if (!event_data) {
971                 TDM_ERR("alloc failed");
972                 return TDM_ERROR_OUT_OF_MEMORY;
973         }
974
975         event_data->type = TDM_VIRTUAL_EVENT_TYPE_COMMIT;
976         event_data->output_data = output_data;
977         event_data->user_data = output_data->commit_user_data;
978
979         ret = _tdm_virtual_display_wait_vblank(output_data, 1, event_data);
980         if (ret != TDM_ERROR_NONE) {
981                 free(event_data);
982                 return ret;
983         }
984
985         return TDM_ERROR_NONE;
986 }
987