fb8a66791eb711ce133f9fd5634d2ecfce2bfa76
[platform/adaptation/nexell/libtdm-nexell.git] / src / libtdm-nexell / tdm_nexell_hwc.c
1 /**************************************************************************
2
3 libtdm_nexell
4
5 Copyright 2017 Samsung Electronics co., Ltd. All Rights Reserved.
6
7 Contact: SooChan Lim <sc1.lim@samsung.com>
8
9 Permission is hereby granted, free of charge, to any person obtaining a
10 copy of this software and associated documentation files (the
11 "Software"), to deal in the Software without restriction, including
12 without limitation the rights to use, copy, modify, merge, publish,
13 distribute, sub license, and/or sell copies of the Software, and to
14 permit persons to whom the Software is furnished to do so, subject to
15 the following conditions:
16
17 The above copyright notice and this permission notice (including the
18 next paragraph) shall be included in all copies or substantial portions
19 of the Software.
20
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
24 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
25 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
26 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
27 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28
29 **************************************************************************/
30
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34
35 #include <tdm_helper.h>
36 #include <pixman.h>
37 #include "tdm_nexell.h"
38
39 #define MIN_WIDTH      32
40
41 tbm_format hwc_window_video_formats[] = {
42         TBM_FORMAT_NV12,
43         TBM_FORMAT_YUV420
44 };
45
46 const char *
47 _comp_to_str(tdm_hwc_window_composition composition_type)
48 {
49         if (composition_type == TDM_HWC_WIN_COMPOSITION_CLIENT)
50                 return "CLIENT";
51         else if (composition_type == TDM_HWC_WIN_COMPOSITION_DEVICE)
52                 return "DEVICE";
53         else if (composition_type == TDM_HWC_WIN_COMPOSITION_CURSOR)
54                 return "CURSOR";
55         else if (composition_type == TDM_HWC_WIN_COMPOSITION_VIDEO)
56                 return "VIDEO";
57         else if (composition_type == TDM_HWC_WIN_COMPOSITION_NONE)
58                 return "SKIP";
59
60         return "unknown";
61 }
62
63 static int
64 _nexell_hwc_cursor_buffer_image_render(tdm_nexell_hwc_data *hwc_data, tdm_nexell_hwc_window_data *hwc_window_data)
65 {
66         tbm_surface_info_s tsurface_info;
67         tbm_surface_error_e ret = TBM_SURFACE_ERROR_NONE;
68         void *src_ptr = NULL, *dst_ptr = NULL;
69         int src_stride, transform, img_w, img_h;
70         pixman_image_t *src_img = NULL, *dst_img = NULL;
71         pixman_transform_t t;
72         struct pixman_f_transform ft;
73         int c = 0, s = 0, tx = 0, ty = 0;
74         int i;
75
76         ret = tbm_surface_map(hwc_data->cursor_tsurface, TBM_SURF_OPTION_WRITE, &tsurface_info);
77         if (ret != TBM_SURFACE_ERROR_NONE) {
78                 TDM_ERR("Failed to map tsurface\n");
79                 return 0;
80         }
81
82         src_ptr = hwc_window_data->cursor_img.ptr;
83         src_stride = hwc_window_data->cursor_img.stride;
84         img_w = hwc_window_data->cursor_img.width;
85         img_h = hwc_window_data->cursor_img.height;
86         transform = hwc_window_data->info.transform;
87
88         dst_ptr = tsurface_info.planes[0].ptr;
89
90         memset(dst_ptr, 0, tsurface_info.planes[0].stride * tsurface_info.height);
91
92         if (transform) {
93                 src_img = pixman_image_create_bits(PIXMAN_a8r8g8b8, img_w, img_h, (uint32_t*)src_ptr, src_stride);
94                 if (!src_img) {
95                         TDM_ERR("Failed to create src pixman\n");
96                         return 0;
97                 }
98
99                 dst_img = pixman_image_create_bits(PIXMAN_a8r8g8b8, tsurface_info.width, tsurface_info.height,
100                         (uint32_t*)dst_ptr, tsurface_info.planes[0].stride);
101                 if (!dst_img) {
102                         TDM_ERR("Failed to create dst pixman\n");
103                         pixman_image_unref(src_img);
104                         return 0;
105                 }
106
107                 pixman_f_transform_init_identity(&ft);
108
109                 if (transform >= TDM_TRANSFORM_FLIPPED) {
110                         pixman_f_transform_scale(&ft, NULL, -1, 1);
111                         pixman_f_transform_translate(&ft, NULL, tsurface_info.width, 0);
112                 }
113
114                 switch (transform) {
115                 case TDM_TRANSFORM_90:
116                 case TDM_TRANSFORM_FLIPPED_90:
117                         c = 0, s = 1, ty = -tsurface_info.height;
118                         break;
119                 case TDM_TRANSFORM_180:
120                 case TDM_TRANSFORM_FLIPPED_180:
121                         c = -1, s = 0, tx = -tsurface_info.width, ty = -tsurface_info.height;
122                         break;
123                 case TDM_TRANSFORM_270:
124                 case TDM_TRANSFORM_FLIPPED_270:
125                         c = 0, s = -1, tx = -tsurface_info.width;
126                         break;
127                 default:
128                         break;
129                 }
130
131                 pixman_f_transform_translate(&ft, NULL, tx, ty);
132                 pixman_f_transform_rotate(&ft, NULL, c, s);
133                 pixman_transform_from_pixman_f_transform(&t, &ft);
134                 pixman_image_set_transform(src_img, &t);
135                 pixman_image_composite(PIXMAN_OP_SRC, src_img, NULL, dst_img, 0, 0, 0, 0, 0, 0,
136                                        tsurface_info.width, tsurface_info.height);
137                 pixman_image_unref(src_img);
138                 pixman_image_unref(dst_img);
139         }
140         else {
141                 for (i = 0 ; i < img_h ; i++) {
142                         memcpy(dst_ptr, src_ptr, src_stride);
143                         dst_ptr += tsurface_info.planes[0].stride;
144                         src_ptr += src_stride;
145                 }
146         }
147
148         tbm_surface_unmap(hwc_data->cursor_tsurface);
149
150         return 1;
151 }
152
153 static int
154 _nexell_hwc_cursor_window_surface_clear(tdm_nexell_hwc_window_data *hwc_window_data)
155 {
156         hwc_window_data->surface = NULL;
157         hwc_window_data->cursor_img_surface = 0;
158
159         hwc_window_data->info.src_config.pos.w = hwc_window_data->cursor_img.width;
160         hwc_window_data->info.src_config.pos.h = hwc_window_data->cursor_img.height;
161         hwc_window_data->info.dst_pos.w = hwc_window_data->cursor_img.width;
162         hwc_window_data->info.dst_pos.h = hwc_window_data->cursor_img.height;
163
164         return 1;
165 }
166
167 static void
168 _nexell_hwc_cursor_buffer_unset(tdm_nexell_hwc_data *hwc_data)
169 {
170         if (hwc_data->cursor_tsurface) {
171                 tbm_surface_queue_release(hwc_data->cursor_tqueue, hwc_data->cursor_tsurface);
172                 hwc_data->cursor_tsurface = NULL;
173         }
174
175         if (hwc_data->cursor_tqueue) {
176                 tdm_nexell_hwc_window_destroy_tbm_buffer_queue(hwc_data->cursor_tqueue);
177                 hwc_data->cursor_tqueue = NULL;
178         }
179 }
180
181 static void
182 _nexell_hwc_cursor_adjust_pos(tdm_nexell_hwc_data *hwc_data, tdm_nexell_hwc_window_data *hwc_window_data)
183 {
184         int x, y, width, height;
185
186         width = tbm_surface_get_width(hwc_data->cursor_tsurface);
187         height = tbm_surface_get_height(hwc_data->cursor_tsurface);
188
189         hwc_window_data->info.src_config.pos.w = width;
190         hwc_window_data->info.src_config.pos.h = height;
191         hwc_window_data->info.dst_pos.w = width;
192         hwc_window_data->info.dst_pos.h = height;
193
194         /* dst pos of cursor is possible set by negative value
195          * this is temporary code.
196          */
197         x = hwc_window_data->info.dst_pos.x;
198         y = hwc_window_data->info.dst_pos.y;
199
200         if (x < 0) hwc_window_data->info.dst_pos.x = 0;
201         if (y < 0) hwc_window_data->info.dst_pos.y = 0;
202 }
203
204 static int
205 _nexell_hwc_cursor_buffer_set(tdm_nexell_hwc_data *hwc_data, tdm_nexell_hwc_window_data *hwc_window_data)
206 {
207         tbm_surface_h cursor_tsurface = NULL;
208         tbm_surface_queue_error_e tsq_error = TBM_SURFACE_QUEUE_ERROR_NONE;
209         int img_w, img_h;
210         int tqueue_w, tqueue_h;
211         tdm_error error;
212
213         if (hwc_window_data->cursor_img_refresh || !hwc_window_data->surface) {
214                 switch (hwc_window_data->info.transform) {
215                 case TDM_TRANSFORM_90:
216                 case TDM_TRANSFORM_FLIPPED_90:
217                 case TDM_TRANSFORM_270:
218                 case TDM_TRANSFORM_FLIPPED_270:
219                         img_w = hwc_window_data->cursor_img.height;
220                         img_h = hwc_window_data->cursor_img.width;
221                         break;
222                 default:
223                         img_w = hwc_window_data->cursor_img.width;
224                         img_h = hwc_window_data->cursor_img.height;
225                         break;
226                 }
227
228                 if (!hwc_data->cursor_tqueue) {
229                         hwc_data->cursor_tqueue = tdm_nexell_hwc_window_create_cursor_tbm_buffer_queue(hwc_window_data, &error);
230                         if (error != TDM_ERROR_NONE) {
231                                 TDM_ERR("Failed to create cursor buffer queue error:%d", error);
232                                 return 0;
233                         }
234                 } else {
235                         tqueue_w = tbm_surface_queue_get_width(hwc_data->cursor_tqueue);
236                         tqueue_h = tbm_surface_queue_get_height(hwc_data->cursor_tqueue);
237                         if ((img_w != tqueue_w) || (img_h != tqueue_h))
238                                 tbm_surface_queue_reset(hwc_data->cursor_tqueue, img_w, img_h, TBM_FORMAT_ARGB8888);
239                 }
240
241                 if (hwc_data->cursor_tsurface) {
242                         tbm_surface_queue_release(hwc_data->cursor_tqueue, hwc_data->cursor_tsurface);
243                         hwc_data->cursor_tsurface = NULL;
244                 }
245
246                 if (!tbm_surface_queue_can_dequeue(hwc_data->cursor_tqueue, 0)) {
247                         TDM_ERR("Can't dequeue cursor tqueue");
248                         return 0;
249                 }
250
251                 tsq_error = tbm_surface_queue_dequeue(hwc_data->cursor_tqueue, &cursor_tsurface);
252                 if (tsq_error != TBM_SURFACE_QUEUE_ERROR_NONE) {
253                         TDM_ERR("Failed to dequeue cursor tqueue error:%d", tsq_error);
254                         return 0;
255                 }
256
257                 hwc_data->cursor_tsurface = cursor_tsurface;
258
259                 _nexell_hwc_cursor_buffer_image_render(hwc_data, hwc_window_data);
260
261                 hwc_window_data->surface = cursor_tsurface;
262                 hwc_window_data->cursor_img_surface = 1;
263                 hwc_window_data->cursor_img_refresh = 0;
264         }
265
266         _nexell_hwc_cursor_adjust_pos(hwc_data, hwc_window_data);
267
268         return 1;
269 }
270
271 static void
272 _print_validate_result(tdm_nexell_hwc_data *hwc_data, tdm_hwc_window **composited_wnds, uint32_t num_wnds)
273 {
274         tdm_nexell_hwc_window_data *hwc_window_data = NULL;
275         int i;
276         int lzpos_queue;
277
278         for (i = 0; i < num_wnds; i++) {
279                 hwc_window_data = composited_wnds[i];
280                 lzpos_queue = hwc_window_data->lzpos_queue;
281                 switch (hwc_window_data->validated_type) {
282                 case TDM_HWC_WIN_COMPOSITION_CLIENT:
283                         TDM_DBG(" window(%p) %s -> %s : lzpos(%d) lzpos_queue(%d)[tqueue:%p ref_cnt:%d] -- {%s} on TARGET WINDOW", hwc_window_data,
284                                         _comp_to_str(hwc_window_data->client_type),
285                                         _comp_to_str(hwc_window_data->validated_type),
286                                         hwc_data->target_hwc_window->lzpos,
287                                         lzpos_queue, lzpos_queue == -1 ? NULL : hwc_data->ui_buffer_queue[lzpos_queue].tqueue,
288                                         lzpos_queue == -1 ? 0 : hwc_data->ui_buffer_queue[lzpos_queue].ref_cnt,
289                                         hwc_window_data->name ? hwc_window_data->name : "NONE");
290                         break;
291                 case TDM_HWC_WIN_COMPOSITION_DEVICE:
292                 case TDM_HWC_WIN_COMPOSITION_VIDEO:
293                 case TDM_HWC_WIN_COMPOSITION_CURSOR:
294                 case TDM_HWC_WIN_COMPOSITION_NONE:
295                         TDM_DBG(" window(%p) %s -> %s : lzpos(%d) lzpos_queue(%d)[tqueue:%p ref_cnt:%d] -- {%s}", hwc_window_data,
296                                         _comp_to_str(hwc_window_data->client_type),
297                                         _comp_to_str(hwc_window_data->validated_type),
298                                         hwc_window_data->lzpos,
299                                         lzpos_queue, lzpos_queue == -1 ? NULL : hwc_data->ui_buffer_queue[lzpos_queue].tqueue,
300                                         lzpos_queue == -1 ? 0 : hwc_data->ui_buffer_queue[lzpos_queue].ref_cnt,
301                                         hwc_window_data->name ? hwc_window_data->name : "NONE");
302                         break;
303                 default:
304                         break;
305                 }
306         }
307 }
308
309 static int
310 _nexell_hwc_window_has_reserved_buffer(tdm_nexell_hwc_window_data *hwc_window_data) {
311         tbm_bo bo = NULL;
312         int flags = 0;
313
314         RETURN_VAL_IF_FAIL(hwc_window_data != NULL, 0);
315         RETURN_VAL_IF_FAIL(hwc_window_data->surface != NULL, 0);
316
317         bo = tbm_surface_internal_get_bo(hwc_window_data->surface, 0);
318         RETURN_VAL_IF_FAIL(bo != NULL, 0);
319
320         flags = tbm_bo_get_flags(bo);
321
322         return flags & TBM_BO_SCANOUT;
323 }
324
325 static int
326 _nexell_hwc_window_can_set_on_hw_layer(tdm_nexell_hwc_window_data *hwc_window_data, int bottom)
327 {
328         if (!hwc_window_data->surface)
329                 return 0;
330
331         if (hwc_window_data->info.transform != TDM_TRANSFORM_NORMAL)
332                 return 0;
333
334         if (hwc_window_data->info.src_config.pos.w != hwc_window_data->info.dst_pos.w)
335                 return 0;
336
337         if (hwc_window_data->info.src_config.pos.h != hwc_window_data->info.dst_pos.h)
338                 return 0;
339
340         if (!IS_RGB(hwc_window_data->info.src_config.format))
341                 return 0;
342
343         if ((hwc_window_data->info.dst_pos.x > hwc_window_data->hwc_data->output_data->current_mode->hdisplay) ||
344                 (hwc_window_data->info.dst_pos.y > hwc_window_data->hwc_data->output_data->current_mode->vdisplay))
345                 return 0;
346
347         if (bottom) {
348                 if ((hwc_window_data->info.dst_pos.w != hwc_window_data->hwc_data->output_data->current_mode->hdisplay) ||
349                         (hwc_window_data->info.dst_pos.h != hwc_window_data->hwc_data->output_data->current_mode->vdisplay))
350                 return 0;
351         }
352
353         return 1;
354 }
355
356 tbm_surface_queue_h
357 tdm_nexell_hwc_window_create_tbm_buffer_queue(tdm_hwc_window *hwc_window, tdm_error *error)
358 {
359         tdm_nexell_hwc_window_data *hwc_window_data = NULL;
360         tbm_surface_queue_h tqueue = NULL;
361         int width, height;
362         tbm_format format;
363
364         if (error)
365                 *error = TDM_ERROR_INVALID_PARAMETER;
366
367         RETURN_VAL_IF_FAIL(hwc_window != NULL, NULL);
368
369         hwc_window_data = hwc_window;
370
371         width = hwc_window_data->info.src_config.pos.w;
372         height = hwc_window_data->info.src_config.pos.h;
373         format = hwc_window_data->info.src_config.format;
374
375         tqueue = tbm_surface_queue_create(NUM_BUFFERS, width, height, format, TBM_BO_SCANOUT);
376         if (error)
377                 *error = TDM_ERROR_OPERATION_FAILED;
378         RETURN_VAL_IF_FAIL(tqueue != NULL, NULL);
379
380         if (error)
381                 *error = TDM_ERROR_NONE;
382
383         return tqueue;
384 }
385
386 tbm_surface_queue_h
387 tdm_nexell_hwc_window_create_cursor_tbm_buffer_queue(tdm_hwc_window *hwc_window, tdm_error *error)
388 {
389         tdm_nexell_hwc_window_data *hwc_window_data = NULL;
390         tbm_surface_queue_h tqueue = NULL;
391         int width, height;
392
393         if (error)
394                 *error = TDM_ERROR_INVALID_PARAMETER;
395
396         RETURN_VAL_IF_FAIL(hwc_window != NULL, NULL);
397
398         hwc_window_data = hwc_window;
399
400         switch (hwc_window_data->info.transform) {
401         case TDM_TRANSFORM_90:
402         case TDM_TRANSFORM_FLIPPED_90:
403         case TDM_TRANSFORM_270:
404         case TDM_TRANSFORM_FLIPPED_270:
405                 width = hwc_window_data->cursor_img.height;
406                 height = hwc_window_data->cursor_img.width;
407                 break;
408         default:
409                 width = hwc_window_data->cursor_img.width;
410                 height = hwc_window_data->cursor_img.height;
411                 break;
412         }
413
414         tqueue = tbm_surface_queue_create(NUM_BUFFERS, width, height, TBM_FORMAT_ARGB8888, TBM_BO_SCANOUT);
415         if (error)
416                 *error = TDM_ERROR_OPERATION_FAILED;
417         RETURN_VAL_IF_FAIL(tqueue != NULL, NULL);
418
419         tbm_surface_queue_set_modes(tqueue, TBM_SURFACE_QUEUE_MODE_GUARANTEE_CYCLE);
420
421         if (error)
422                 *error = TDM_ERROR_NONE;
423
424         return tqueue;
425 }
426
427 void
428 tdm_nexell_hwc_window_destroy_tbm_buffer_queue(tbm_surface_queue_h tqueue)
429 {
430         tbm_surface_queue_destroy(tqueue);
431 }
432
433 static tdm_error
434 _nexell_hwc_layer_attach_window(tdm_nexell_layer_data *layer_data, tdm_nexell_hwc_window_data *hwc_window_data)
435 {
436         tdm_error ret = TDM_ERROR_NONE;
437
438         RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_OPERATION_FAILED);
439
440         if (hwc_window_data == NULL || hwc_window_data->surface == NULL) {
441                 if (layer_data->display_buffer)
442                         ret = nexell_layer_unset_buffer(layer_data);
443                 RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, ret);
444         } else {
445                 ret = nexell_layer_set_info((tdm_layer *)layer_data, (tdm_info_layer *)&(hwc_window_data->info));
446                 RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, ret);
447                 RETURN_VAL_IF_FAIL(hwc_window_data->surface != NULL, TDM_ERROR_INVALID_PARAMETER);
448                 ret = nexell_layer_set_buffer(layer_data, hwc_window_data->surface);
449                 RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, ret);
450         }
451
452         return ret;
453 }
454
455 static tdm_error
456 _nexell_hwc_prepare_commit(tdm_nexell_hwc_data *hwc_data)
457 {
458         tdm_nexell_hwc_window_data *hwc_window_data = NULL;
459         tdm_nexell_layer_data *layer_data = NULL;
460         int use_layers_zpos[NUM_LAYERS] = {0,};
461         int lzpos = 0;
462         int cursor_enabled = 0;
463
464         /* set target hwc window to the layer */
465         if (hwc_data->need_target_window) {
466                 layer_data = nexell_output_data_get_layer_data(hwc_data->output_data, hwc_data->target_hwc_window->lzpos);
467                 _nexell_hwc_layer_attach_window(layer_data, hwc_data->target_hwc_window);
468                 use_layers_zpos[hwc_data->target_hwc_window->lzpos] = 1;
469         }
470
471         /* set the hwc_windows to the layers */
472         LIST_FOR_EACH_ENTRY_REV(hwc_window_data, &hwc_data->hwc_window_list, link) {
473                 if (hwc_window_data->validated_type == TDM_HWC_WIN_COMPOSITION_NONE ||
474                         hwc_window_data->validated_type == TDM_HWC_WIN_COMPOSITION_CLIENT) {
475                         if (hwc_window_data->cursor_img_surface)
476                                 _nexell_hwc_cursor_window_surface_clear(hwc_window_data);
477
478                         continue;
479                 }
480
481                 if (hwc_window_data == hwc_data->target_hwc_window)
482                         continue;
483
484                 /* set the cursor buffer HERE if it needs */
485                 if (hwc_window_data->validated_type == TDM_HWC_WIN_COMPOSITION_CURSOR) {
486                         _nexell_hwc_cursor_buffer_set(hwc_data, hwc_window_data);
487                         cursor_enabled = 1;
488                 }
489
490                 layer_data = nexell_output_data_get_layer_data(hwc_data->output_data, hwc_window_data->lzpos);
491                 _nexell_hwc_layer_attach_window(layer_data, hwc_window_data);
492                 use_layers_zpos[hwc_window_data->lzpos] = 1;
493         }
494
495         /* unset the unused layers */
496         for (lzpos = 0; lzpos < NUM_LAYERS; lzpos++) {
497                 if (use_layers_zpos[lzpos])
498                         continue;
499
500                 layer_data = nexell_output_data_get_layer_data(hwc_data->output_data, lzpos);
501                 if (!layer_data)
502                         continue;
503
504                 _nexell_hwc_layer_attach_window(layer_data, NULL);
505         }
506
507         if (!cursor_enabled)
508                 _nexell_hwc_cursor_buffer_unset(hwc_data);
509
510         /* for debug */
511         for (lzpos = NUM_LAYERS -1 ; lzpos >= 0; lzpos--) {
512                 if (use_layers_zpos[lzpos])
513                         TDM_DBG(" lzpos(%d) : %s", lzpos, use_layers_zpos[lzpos] ? "SET" : "UNSET");
514         }
515
516         return TDM_ERROR_NONE;
517 }
518
519 /* assign the validated_type to the composited_wnds
520  * assign the layer_zpos to the composited_wnds
521  */
522 static void
523 _nexell_hwc_apply_policy(tdm_nexell_hwc_data *hwc_data , tdm_hwc_window **composited_wnds, uint32_t num_wnds)
524 {
525         tdm_nexell_hwc_window_data *hwc_window_data = NULL;
526         tdm_nexell_hwc_window_data **composited_list = NULL;
527         int client_count = 0;
528         int device_count = 0;
529         int video_count = 0;
530         int cursor_count = 0;
531         int ui_lzpos_top = ZPOS_2;
532         int ui_lzpos_bottom = ZPOS_1;
533         int num_ui_layers = NUM_UI_LAYERS;
534         int set_clients_below = 0;
535         int i = 0;
536
537         composited_list = (tdm_nexell_hwc_window_data **)composited_wnds;
538
539         /* initialize the need_target_window */
540         hwc_data->need_target_window = 0;
541
542         /* initialize the validated_types and constraints */
543         LIST_FOR_EACH_ENTRY_REV(hwc_window_data, &hwc_data->hwc_window_list, link) {
544                 hwc_window_data->constraints = TDM_HWC_WIN_CONSTRAINT_NONE;
545                 hwc_window_data->validated_type = TDM_HWC_WIN_COMPOSITION_NONE;
546                 hwc_window_data->lzpos = -1;
547                 hwc_window_data->lzpos_queue = -1;
548         }
549
550         /* use the target_window to commit when there is no window. */
551         if (num_wnds == 0) {
552                 hwc_data->need_target_window = 1;
553                 hwc_data->target_hwc_window->lzpos = ui_lzpos_bottom;
554                 hwc_data->target_hwc_window->lzpos_queue = ui_lzpos_bottom;
555                 return;
556         }
557
558         /* 1. first check validate_type without target_window */
559         for (i = 0; i < num_wnds; i++) {
560                 switch (composited_list[i]->client_type) {
561                 case TDM_HWC_WIN_COMPOSITION_VIDEO:
562                         composited_list[i]->validated_type = TDM_HWC_WIN_COMPOSITION_VIDEO;
563                         video_count++;
564                         continue;
565                 case TDM_HWC_WIN_COMPOSITION_CURSOR:
566                         if (set_clients_below) break;
567                         if (num_ui_layers <= 0) break;
568
569                         composited_list[i]->validated_type = TDM_HWC_WIN_COMPOSITION_CURSOR;
570                         cursor_count++;
571                         num_ui_layers--;
572                         continue;
573                 case TDM_HWC_WIN_COMPOSITION_DEVICE:
574                         if (set_clients_below) break;
575                         if (num_ui_layers <= 0) break;
576
577                         if (!_nexell_hwc_window_can_set_on_hw_layer(composited_list[i], (i == num_wnds - 1)))
578                                 break;
579
580                         if (!_nexell_hwc_window_has_reserved_buffer(composited_list[i])) {
581                                 composited_list[i]->constraints = TDM_HWC_WIN_CONSTRAINT_BUFFER_QUEUE;
582                                 break;
583                         }
584
585                         composited_list[i]->validated_type = TDM_HWC_WIN_COMPOSITION_DEVICE;
586                         composited_list[i]->constraints = TDM_HWC_WIN_CONSTRAINT_BUFFER_QUEUE;
587                         device_count++;
588                         num_ui_layers--;
589                         continue;
590                 default:
591                         break;
592                 }
593
594                 composited_list[i]->validated_type = TDM_HWC_WIN_COMPOSITION_CLIENT;
595                 client_count++;
596                 set_clients_below = 1;
597         }
598
599         /* 2. check need target window and set ui_lzpos top and bottom */
600         num_ui_layers = NUM_UI_LAYERS;
601         if (client_count > 0) {
602                 hwc_data->need_target_window = 1;
603                 hwc_data->target_hwc_window->lzpos = ui_lzpos_bottom;
604                 ui_lzpos_bottom++;
605                 num_ui_layers--;
606         }
607
608         if (num_ui_layers > (device_count + cursor_count))
609                 ui_lzpos_top = ui_lzpos_bottom + device_count + cursor_count - 1;
610
611         /* 3. set lzpos and modify validate_type with target_window */
612         for (i = 0; i < num_wnds; i++) {
613                 switch (composited_list[i]->validated_type) {
614                 case TDM_HWC_WIN_COMPOSITION_VIDEO:
615                         composited_list[i]->lzpos = ZPOS_VIDEO1;
616                         continue;
617                 case TDM_HWC_WIN_COMPOSITION_CURSOR:
618                 case TDM_HWC_WIN_COMPOSITION_DEVICE:
619                         if (num_ui_layers <= 0) break;
620
621                         composited_list[i]->lzpos = ui_lzpos_top;
622                         composited_list[i]->lzpos_queue = ui_lzpos_top;
623                         ui_lzpos_top--;
624                         num_ui_layers--;
625                         continue;
626                 default:
627                         break;
628                 }
629
630                 composited_list[i]->validated_type = TDM_HWC_WIN_COMPOSITION_CLIENT;
631
632                 if (composited_list[i]->constraints == TDM_HWC_WIN_CONSTRAINT_BUFFER_QUEUE) {
633                         if (i == num_wnds - 1) //set target window queue zpos
634                                 composited_list[i]->lzpos_queue = ui_lzpos_top;
635                         else if(num_ui_layers > 0)
636                                 composited_list[i]->lzpos_queue = ui_lzpos_top + 1;
637                         else
638                                 composited_list[i]->constraints = TDM_HWC_WIN_CONSTRAINT_NONE;
639                 }
640         }
641 }
642
643 static int
644 _nexell_hwc_get_changed_number(tdm_nexell_hwc_data *hwc_data)
645 {
646         int num = 0;
647         tdm_nexell_hwc_window_data *hwc_window_data = NULL;
648
649         LIST_FOR_EACH_ENTRY(hwc_window_data, &hwc_data->hwc_window_list, link) {
650                 if (hwc_window_data->client_type == TDM_HWC_WIN_COMPOSITION_NONE)
651                         continue;
652
653                 if (hwc_window_data->client_type != hwc_window_data->validated_type)
654                         num++;
655         }
656
657         return num;
658 }
659
660 tdm_hwc_window *
661 _nexell_hwc_create_window(tdm_hwc *hwc, tdm_hwc_window_info *info, tdm_error *error)
662 {
663         tdm_nexell_hwc_data *hwc_data = hwc;
664         tdm_nexell_hwc_window_data *hwc_window_data = NULL;
665
666         if (error)
667                 *error = TDM_ERROR_NONE;
668
669         if (!hwc_data) {
670                 TDM_ERR("invalid params");
671                 if (error)
672                         *error = TDM_ERROR_INVALID_PARAMETER;
673                 return NULL;
674         }
675
676         hwc_window_data = calloc(1, sizeof(tdm_nexell_hwc_window_data));
677         if (!hwc_window_data) {
678                 TDM_ERR("alloc failed");
679                 if (error)
680                         *error = TDM_ERROR_OUT_OF_MEMORY;
681                 return NULL;
682         }
683
684         hwc_window_data->hwc_data = hwc_data;
685
686         if (info)
687                 memcpy(&hwc_window_data->info, info, sizeof(tdm_hwc_window_info));
688
689         LIST_INITHEAD(&hwc_window_data->link);
690
691         return hwc_window_data;
692 }
693
694 tdm_hwc_window *
695 nexell_hwc_create_window(tdm_hwc *hwc, tdm_error *error)
696 {
697         tdm_nexell_hwc_data *hwc_data = hwc;
698         tdm_nexell_hwc_window_data *hwc_window_data = NULL;
699
700         RETURN_VAL_IF_FAIL(hwc_data, NULL);
701
702         hwc_window_data = _nexell_hwc_create_window(hwc_data, NULL, error);
703         RETURN_VAL_IF_FAIL(hwc_window_data, NULL);
704
705         LIST_ADDTAIL(&hwc_window_data->link, &hwc_data->hwc_window_list);
706
707         TDM_DBG("hwc_window(%p) create", hwc_window_data);
708         if (error)
709                 *error = TDM_ERROR_NONE;
710
711         return hwc_window_data;
712 }
713
714 tdm_error
715 nexell_hwc_get_video_supported_formats(tdm_hwc *hwc, const tbm_format **formats, int *count)
716 {
717         RETURN_VAL_IF_FAIL(hwc != NULL, TDM_ERROR_INVALID_PARAMETER);
718         RETURN_VAL_IF_FAIL(formats != NULL, TDM_ERROR_INVALID_PARAMETER);
719         RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER);
720
721         // TODO: fix these formats.
722         *formats = hwc_window_video_formats;
723         *count = sizeof(hwc_window_video_formats) / sizeof(tbm_format);
724
725         return TDM_ERROR_NONE;
726 }
727
728 tdm_error
729 nexell_hwc_get_capabilities(tdm_hwc *hwc, tdm_hwc_capability *capabilities)
730 {
731         RETURN_VAL_IF_FAIL(hwc != NULL, TDM_ERROR_INVALID_PARAMETER);
732         RETURN_VAL_IF_FAIL(capabilities != NULL, TDM_ERROR_INVALID_PARAMETER);
733
734         *capabilities |= TDM_HWC_CAPABILITY_VIDEO_SCALE;
735
736         return TDM_ERROR_NONE;
737 }
738
739 tdm_error
740 nexell_hwc_get_available_properties(tdm_hwc *hwc, const tdm_prop **props, int *count)
741 {
742         tdm_nexell_hwc_data *hwc_data = hwc;
743
744         RETURN_VAL_IF_FAIL(hwc_data != NULL, TDM_ERROR_INVALID_PARAMETER);
745         RETURN_VAL_IF_FAIL(props != NULL, TDM_ERROR_INVALID_PARAMETER);
746         RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER);
747
748         *props = NULL;
749         *count = 0;
750
751         return TDM_ERROR_NONE;
752 }
753
754 tbm_surface_queue_h
755 nexell_hwc_get_client_target_buffer_queue(tdm_hwc *hwc, tdm_error *error)
756 {
757         tdm_nexell_hwc_data *hwc_data = hwc;
758         tbm_surface_queue_h tqueue = NULL;
759
760         if (error)
761                 *error = TDM_ERROR_INVALID_PARAMETER;
762
763         RETURN_VAL_IF_FAIL(hwc_data != NULL, NULL);
764
765         if (hwc_data->target_hwc_window == NULL) {
766                 if (error)
767                         *error = TDM_ERROR_OPERATION_FAILED;
768                 return NULL;
769         }
770
771         tqueue = tdm_nexell_hwc_window_create_tbm_buffer_queue(hwc_data->target_hwc_window, error);
772         RETURN_VAL_IF_FAIL(tqueue, NULL);
773
774         hwc_data->ui_buffer_queue[ZPOS_1].tqueue = tqueue;
775         hwc_data->ui_buffer_queue[ZPOS_1].ref_cnt = 1;
776
777         if (error)
778                 *error = TDM_ERROR_NONE;
779
780         return tqueue;
781 }
782
783 tdm_error
784 nexell_hwc_set_client_target_buffer(tdm_hwc *hwc, tbm_surface_h buffer, tdm_region damage)
785 {
786         tdm_nexell_hwc_data *hwc_data = hwc;
787         tdm_error err;
788
789         RETURN_VAL_IF_FAIL(hwc_data != NULL, TDM_ERROR_INVALID_PARAMETER);
790         RETURN_VAL_IF_FAIL(hwc_data->target_hwc_window  != NULL, TDM_ERROR_OPERATION_FAILED);
791
792         err = nexell_hwc_window_set_buffer(hwc_data->target_hwc_window, buffer);
793         RETURN_VAL_IF_FAIL(err == TDM_ERROR_NONE, err);
794
795         err = nexell_hwc_window_set_buffer_damage(hwc_data->target_hwc_window, damage);
796         RETURN_VAL_IF_FAIL(err == TDM_ERROR_NONE, err);
797
798         return TDM_ERROR_NONE;
799 }
800
801 tdm_error
802 nexell_hwc_validate(tdm_hwc *hwc, tdm_hwc_window **composited_wnds, uint32_t num_wnds, uint32_t *num_types)
803 {
804         tdm_nexell_hwc_data *hwc_data = hwc;
805         tdm_nexell_output_data *output_data;
806
807         RETURN_VAL_IF_FAIL(hwc_data != NULL, TDM_ERROR_INVALID_PARAMETER);
808         RETURN_VAL_IF_FAIL(num_types != NULL, TDM_ERROR_INVALID_PARAMETER);
809
810         output_data = hwc_data->output_data;
811         RETURN_VAL_IF_FAIL(output_data != NULL, TDM_ERROR_INVALID_PARAMETER);
812
813         TDM_DBG(" ==============Validate=================================");
814
815         /* adapt policy */
816         _nexell_hwc_apply_policy(hwc_data, composited_wnds, num_wnds);
817
818         *num_types = _nexell_hwc_get_changed_number(hwc_data);
819
820         _print_validate_result(hwc_data, composited_wnds, num_wnds);
821
822         return TDM_ERROR_NONE;
823 }
824
825 tdm_error
826 nexell_hwc_get_changed_composition_types(tdm_hwc *hwc, uint32_t *num_elements,
827                                 tdm_hwc_window **hwc_wnds, tdm_hwc_window_composition *composition_types)
828 {
829         tdm_nexell_hwc_data *hwc_data = hwc;
830         tdm_nexell_hwc_window_data *hwc_window_data = NULL;
831         int num = 0;
832
833         RETURN_VAL_IF_FAIL(hwc_data != NULL, TDM_ERROR_INVALID_PARAMETER);
834         RETURN_VAL_IF_FAIL(num_elements != NULL, TDM_ERROR_INVALID_PARAMETER);
835
836         if ((hwc_wnds == NULL) || (composition_types == NULL)) {
837                 *num_elements = _nexell_hwc_get_changed_number(hwc_data);
838                 return TDM_ERROR_NONE;
839         }
840
841         LIST_FOR_EACH_ENTRY_REV(hwc_window_data, &hwc_data->hwc_window_list, link) {
842                 if (hwc_window_data->client_type == TDM_HWC_WIN_COMPOSITION_NONE)
843                         continue;
844
845                 if (num >= *num_elements)
846                         break;
847
848                 if (hwc_window_data->client_type != hwc_window_data->validated_type) {
849                         composition_types[num] = hwc_window_data->validated_type;
850                         hwc_wnds[num] = hwc_window_data;
851                         num++;
852                 }
853         }
854
855         /* set real num of changed composition types */
856         *num_elements = num;
857
858         return TDM_ERROR_NONE;
859 }
860
861 tdm_error
862 nexell_hwc_accept_validation(tdm_hwc *hwc)
863 {
864         tdm_nexell_hwc_data *hwc_data = hwc;
865         tdm_error ret = TDM_ERROR_NONE;
866
867         RETURN_VAL_IF_FAIL(hwc_data != NULL, TDM_ERROR_INVALID_PARAMETER);
868         RETURN_VAL_IF_FAIL(hwc_data->output_data != NULL, TDM_ERROR_INVALID_PARAMETER);
869
870         TDM_DBG(" ==============Accept Changes Done=================================");
871
872         ret = _nexell_hwc_prepare_commit(hwc_data);
873         RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, ret);
874
875         return TDM_ERROR_NONE;
876 }
877
878 tdm_error
879 nexell_hwc_commit(tdm_hwc *hwc, int sync, void *user_data)
880 {
881         tdm_nexell_hwc_data *hwc_data = hwc;
882         tdm_nexell_output_data *output_data = NULL;
883         tdm_error ret;
884
885         RETURN_VAL_IF_FAIL(hwc_data, TDM_ERROR_INVALID_PARAMETER);
886
887         output_data = hwc_data->output_data;
888         RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER);
889
890         TDM_DBG(" ==============COMMIT=================================");
891
892         ret = nexell_output_commit(output_data, sync, user_data);
893         RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, ret);
894
895         return TDM_ERROR_NONE;
896 }
897
898 tdm_error
899 nexell_hwc_set_commit_handler(tdm_hwc *hwc, tdm_hwc_commit_handler func)
900 {
901         tdm_nexell_hwc_data *hwc_data = hwc;
902
903         RETURN_VAL_IF_FAIL(hwc_data, TDM_ERROR_INVALID_PARAMETER);
904         RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER);
905
906         hwc_data->commit_func = func;
907
908         return TDM_ERROR_NONE;
909 }
910
911 tdm_error
912 nexell_hwc_target_window_set_info(tdm_nexell_hwc_data *hwc_data, int width, int height)
913 {
914         tdm_hwc_window_info info = {0};
915         tdm_nexell_hwc_window_data *target_hwc_window;
916         tdm_error ret = TDM_ERROR_NONE;
917
918         RETURN_VAL_IF_FAIL(hwc_data, TDM_ERROR_INVALID_PARAMETER);
919         RETURN_VAL_IF_FAIL(hwc_data->target_hwc_window, TDM_ERROR_INVALID_PARAMETER);
920
921         target_hwc_window = hwc_data->target_hwc_window;
922
923         info.dst_pos.x = 0;
924         info.dst_pos.y = 0;
925         info.dst_pos.w = width;
926         info.dst_pos.h = height;
927
928         info.src_config.pos.x = 0;
929         info.src_config.pos.y = 0;
930         info.src_config.pos.w = width;
931         info.src_config.pos.h = height;
932
933         info.src_config.size.h = width;
934         info.src_config.size.v = height;
935         info.src_config.format = TBM_FORMAT_ARGB8888;
936
937         ret = nexell_hwc_window_set_info(target_hwc_window, &info);
938         if (ret != TDM_ERROR_NONE) {
939                 TDM_ERR("set info target hwc window failed (%d)", ret);
940                 return TDM_ERROR_OPERATION_FAILED;
941         }
942
943         return TDM_ERROR_NONE;
944 }
945
946 tdm_error
947 nexell_hwc_initailize_target_window(tdm_nexell_hwc_data *hwc_data)
948 {
949         tdm_hwc_window_info info = {0};
950         tdm_error ret = TDM_ERROR_NONE;
951         tdm_nexell_hwc_window_data *target_hwc_window;
952
953         RETURN_VAL_IF_FAIL(hwc_data, TDM_ERROR_INVALID_PARAMETER);
954
955         info.dst_pos.x = 0;
956         info.dst_pos.y = 0;
957         info.dst_pos.w = 2;
958         info.dst_pos.h = 1;
959
960         info.src_config.pos.x = 0;
961         info.src_config.pos.y = 0;
962         info.src_config.pos.w = 2;
963         info.src_config.pos.h = 1;
964
965         info.src_config.size.h = 2;
966         info.src_config.size.v = 1;
967         info.src_config.format = TBM_FORMAT_ARGB8888;
968
969         target_hwc_window = _nexell_hwc_create_window(hwc_data, &info, &ret);
970         if (ret != TDM_ERROR_NONE) {
971                 TDM_ERR("create target hwc window failed (%d)", ret);
972                 return TDM_ERROR_OPERATION_FAILED;
973         }
974
975         if (hwc_data->target_hwc_window)
976                 nexell_hwc_window_destroy(hwc_data->target_hwc_window);
977
978         hwc_data->target_hwc_window = target_hwc_window;
979         hwc_data->need_set_crtc = 1;
980
981         return TDM_ERROR_NONE;
982 }