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