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