2 #include <wayland-server.h>
7 #include <libds-tizen/tbm_server.h>
10 #include "tdm_internal.h"
11 #include "tdm_output_hwc.h"
14 hwc_window_update_front_buffer(struct ds_tdm_output_hwc_window *hwc_window)
16 if (hwc_window->front_buffer == hwc_window->back_buffer) {
17 if (hwc_window->back_buffer) {
18 ds_buffer_unlock(hwc_window->back_buffer);
19 hwc_window->back_buffer = NULL;
25 ds_tdm_output_hwc_window_lock(hwc_window);
27 if (hwc_window->front_buffer) {
28 ds_buffer_unlock(hwc_window->front_buffer);
29 hwc_window->front_buffer = NULL;
30 ds_tdm_output_hwc_window_unlock(hwc_window);
33 hwc_window->front_buffer = hwc_window->back_buffer;
34 hwc_window->back_buffer = NULL;
36 if (hwc_window->front_buffer)
37 ds_tdm_output_hwc_window_lock(hwc_window);
39 ds_tdm_output_hwc_window_unlock(hwc_window);
43 hwc_window_attach_back_buffer(struct ds_tdm_output_hwc_window *hwc_window,
44 struct ds_buffer *buffer)
46 if (hwc_window->back_buffer) {
47 ds_buffer_unlock(hwc_window->back_buffer);
48 hwc_window->back_buffer = NULL;
52 hwc_window->back_buffer = ds_buffer_lock(buffer);
56 get_horizontal_get(tbm_surface_h tsurface)
58 unsigned int horizontal = 0;
59 tbm_surface_info_s surf_info;
61 tbm_surface_get_info(tsurface, &surf_info);
63 switch (surf_info.format) {
64 case TBM_FORMAT_YUV420:
65 case TBM_FORMAT_YVU420:
66 case TBM_FORMAT_YUV422:
67 case TBM_FORMAT_YVU422:
70 horizontal = surf_info.planes[0].stride;
74 horizontal = surf_info.planes[0].stride >> 1;
76 case TBM_FORMAT_XRGB8888:
77 case TBM_FORMAT_XBGR8888:
78 case TBM_FORMAT_RGBX8888:
79 case TBM_FORMAT_BGRX8888:
80 case TBM_FORMAT_ARGB8888:
81 case TBM_FORMAT_ABGR8888:
82 case TBM_FORMAT_RGBA8888:
83 case TBM_FORMAT_BGRA8888:
84 case TBM_FORMAT_XRGB2101010:
85 case TBM_FORMAT_XBGR2101010:
86 case TBM_FORMAT_RGBX1010102:
87 case TBM_FORMAT_BGRX1010102:
88 case TBM_FORMAT_ARGB2101010:
89 case TBM_FORMAT_ABGR2101010:
90 case TBM_FORMAT_RGBA1010102:
91 case TBM_FORMAT_BGRA1010102:
92 horizontal = surf_info.planes[0].stride >> 2;
95 ds_err("not supported format");
102 get_tdm_transform(enum wl_output_transform output_transform)
104 switch (output_transform) {
105 case WL_OUTPUT_TRANSFORM_90:
106 return TDM_TRANSFORM_90;
107 case WL_OUTPUT_TRANSFORM_180:
108 return TDM_TRANSFORM_180;
109 case WL_OUTPUT_TRANSFORM_270:
110 return TDM_TRANSFORM_270;
111 case WL_OUTPUT_TRANSFORM_FLIPPED:
112 return TDM_TRANSFORM_FLIPPED;
113 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
114 return TDM_TRANSFORM_FLIPPED_90;
115 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
116 return TDM_TRANSFORM_FLIPPED_180;
117 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
118 return TDM_TRANSFORM_FLIPPED_270;
119 case WL_OUTPUT_TRANSFORM_NORMAL:
121 return TDM_TRANSFORM_NORMAL;
125 static tdm_hwc_window_composition
126 get_tdm_composition(enum ds_tdm_output_hwc_window_composition composition)
128 switch (composition) {
129 case DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_CLIENT:
130 return TDM_HWC_WIN_COMPOSITION_CLIENT;
131 case DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_CURSOR:
132 return TDM_HWC_WIN_COMPOSITION_CURSOR;
133 case DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_DEVICE:
134 return TDM_HWC_WIN_COMPOSITION_DEVICE;
135 case DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_VIDEO:
136 return TDM_HWC_WIN_COMPOSITION_VIDEO;
137 case DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_NONE:
139 return TDM_HWC_WIN_COMPOSITION_NONE;
143 static enum ds_tdm_output_hwc_window_composition
144 get_composition(tdm_hwc_window_composition composition)
146 switch (composition) {
147 case TDM_HWC_WIN_COMPOSITION_CLIENT:
148 return DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_CLIENT;
149 case TDM_HWC_WIN_COMPOSITION_CURSOR:
150 return DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_CURSOR;
151 case TDM_HWC_WIN_COMPOSITION_DEVICE:
152 return DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_DEVICE;
153 case TDM_HWC_WIN_COMPOSITION_VIDEO:
154 return DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_VIDEO;
155 case TDM_HWC_WIN_COMPOSITION_NONE:
157 return DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_NONE;
161 struct ds_tdm_output_hwc *
162 ds_tdm_output_hwc_create(tdm_hwc *thwc)
164 struct ds_tdm_output_hwc *hwc;
166 hwc = calloc(1, sizeof *hwc);
172 wl_list_init(&hwc->hwc_windows);
173 wl_signal_init(&hwc->events.commit_handler);
174 wl_signal_init(&hwc->events.destroy);
180 ds_tdm_output_hwc_destroy(struct ds_tdm_output_hwc *hwc)
182 wl_signal_emit(&hwc->events.destroy, hwc);
188 ds_tdm_output_hwc_set_client_target_buffer(struct ds_tdm_output_hwc *hwc, tbm_surface_h tsurface)
191 tdm_region fb_damage;
193 memset(&fb_damage, 0, sizeof(fb_damage));
195 hwc->target_buffer_info.src_config.pos.x = 0;
196 hwc->target_buffer_info.src_config.pos.y = 0;
197 hwc->target_buffer_info.src_config.pos.w = tbm_surface_get_width(tsurface);
198 hwc->target_buffer_info.src_config.pos.h = tbm_surface_get_height(tsurface);
199 hwc->target_buffer_info.src_config.size.h = get_horizontal_get(tsurface);
200 hwc->target_buffer_info.src_config.size.v = tbm_surface_get_height(tsurface);
201 hwc->target_buffer_info.src_config.format = tbm_surface_get_format(tsurface);
203 hwc->target_buffer_info.dst_pos.x = 0;
204 hwc->target_buffer_info.dst_pos.y = 0;
205 hwc->target_buffer_info.dst_pos.w = tbm_surface_get_width(tsurface);
206 hwc->target_buffer_info.dst_pos.h = tbm_surface_get_height(tsurface);
208 hwc->target_buffer_info.transform = TDM_TRANSFORM_NORMAL;
210 tdm_hwc_set_client_target_buffer_info(hwc->thwc, &hwc->target_buffer_info);
212 terr = tdm_hwc_set_client_target_buffer(hwc->thwc, tsurface, fb_damage);
213 if (terr != TDM_ERROR_NONE) {
214 ds_err("Could not set hwc client target buffer");
222 ds_tdm_output_hwc_window_set_accepted_composition(struct ds_tdm_output_hwc_window *hwc_window,
223 enum ds_tdm_output_hwc_window_composition composition)
225 if (hwc_window->accepted_composition == composition)
228 hwc_window->accepted_composition = composition;
232 hwc_window_free(struct ds_tdm_output_hwc_window *hwc_window)
234 if (hwc_window->buffer)
235 ds_buffer_unlock(hwc_window->buffer);
237 if (hwc_window->set_buffer)
238 ds_buffer_unlock(hwc_window->set_buffer);
240 if (hwc_window->front_buffer)
241 ds_buffer_unlock(hwc_window->front_buffer);
243 if (hwc_window->back_buffer)
244 ds_buffer_unlock(hwc_window->back_buffer);
246 wl_list_remove(&hwc_window->link);
248 tdm_hwc_window_destroy(hwc_window->twindow);
254 hwc_window_consider_destroy(struct ds_tdm_output_hwc_window *hwc_window)
256 if (!hwc_window->dropped || hwc_window->n_locks > 0)
259 hwc_window_free(hwc_window);
262 struct ds_tdm_output_hwc_window *
263 ds_tdm_output_hwc_window_lock(struct ds_tdm_output_hwc_window *hwc_window)
265 hwc_window->n_locks++;
266 ds_dbg("hwc_window(%p) n_locks(%zu)", hwc_window, hwc_window->n_locks);
271 ds_tdm_output_hwc_window_unlock(struct ds_tdm_output_hwc_window *hwc_window)
273 hwc_window->n_locks--;
274 ds_dbg("hwc_window(%p) n_locks(%zu)", hwc_window, hwc_window->n_locks);
276 hwc_window_consider_destroy(hwc_window);
280 ds_tdm_output_hwc_set_enabled(struct ds_tdm_output_hwc *hwc, bool enabled)
282 if (hwc->enabled == enabled)
285 hwc->enabled = enabled;
288 WL_EXPORT struct ds_tdm_output_hwc_window *
289 ds_tdm_output_hwc_window_create(struct ds_tdm_output_hwc *hwc)
292 tdm_hwc_window *thwc_window;
293 struct ds_tdm_output_hwc_window *hwc_window;
295 hwc_window = calloc(1, sizeof *hwc_window);
299 thwc_window = tdm_hwc_create_window(hwc->thwc, &terr);
300 if (terr != TDM_ERROR_NONE) {
301 ds_err("Could not create tdm_hwc_window error:%d", terr);
306 hwc_window->twindow = thwc_window;
308 wl_list_insert(hwc->hwc_windows.prev, &hwc_window->link);
314 ds_tdm_output_hwc_window_destroy(struct ds_tdm_output_hwc_window *hwc_window)
316 hwc_window->dropped = true;
317 ds_dbg("hwc_window(%p) dropped: n_locks(%zu)", hwc_window, hwc_window->n_locks);
318 hwc_window_consider_destroy(hwc_window);
322 ds_tdm_output_hwc_window_set_buffer(struct ds_tdm_output_hwc_window *hwc_window,
323 struct ds_buffer *buffer)
325 if (hwc_window->buffer == buffer)
328 if (hwc_window->buffer) {
329 ds_buffer_unlock(hwc_window->set_buffer);
330 hwc_window->buffer = NULL;
334 hwc_window->buffer = ds_buffer_lock(buffer);
340 ds_tdm_output_hwc_window_set_src_box(struct ds_tdm_output_hwc_window *hwc_window,
341 const struct ds_tdm_box *src_box)
343 if (src_box != NULL && !memcmp(&hwc_window->src_box, src_box, sizeof(*src_box)))
346 if (src_box != NULL) {
347 memcpy(&hwc_window->src_box, src_box, sizeof(*src_box));
349 memset(&hwc_window->src_box, 0, sizeof(hwc_window->src_box));
354 ds_tdm_output_hwc_window_set_transform(struct ds_tdm_output_hwc_window *hwc_window,
355 enum wl_output_transform transform)
357 if (hwc_window->transform == transform)
360 hwc_window->transform = transform;
364 ds_tdm_output_hwc_window_set_position(struct ds_tdm_output_hwc_window *hwc_window,
367 if ((hwc_window->x == x) && (hwc_window->y == y))
375 ds_tdm_output_hwc_window_set_dest_size(struct ds_tdm_output_hwc_window *hwc_window,
376 int width, int height)
378 if ((hwc_window->dest_width == width) && (hwc_window->dest_height == height))
381 hwc_window->dest_width = width;
382 hwc_window->dest_height = height;
386 ds_tdm_output_hwc_window_set_composition(struct ds_tdm_output_hwc_window *hwc_window,
387 enum ds_tdm_output_hwc_window_composition composition)
389 if (hwc_window->composition == composition)
392 hwc_window->composition = composition;
395 WL_EXPORT enum ds_tdm_output_hwc_window_composition
396 ds_tdm_output_hwc_window_get_composition(struct ds_tdm_output_hwc_window *hwc_window)
398 return hwc_window->composition;
402 hwc_window_update(struct ds_tdm_output_hwc_window *hwc_window)
405 tbm_surface_h tsurface = NULL;
406 tdm_hwc_window_info tinfo = {0, };
407 struct ds_tbm_client_buffer *client_buffer;
409 if (hwc_window->buffer) {
410 client_buffer = ds_tbm_client_buffer_from_buffer(hwc_window->buffer);
412 tsurface = ds_tbm_client_buffer_get_tbm_surface(client_buffer);
415 if (hwc_window->set_buffer != hwc_window->buffer) {
416 if (hwc_window->set_buffer) {
417 ds_buffer_unlock(hwc_window->set_buffer);
418 hwc_window->set_buffer = NULL;
421 if (hwc_window->buffer)
422 hwc_window->set_buffer = ds_buffer_lock(hwc_window->buffer);
424 terr = tdm_hwc_window_set_buffer(hwc_window->twindow, tsurface);
425 if (terr != TDM_ERROR_NONE)
426 ds_err("Could not set buffer hwc_window:%p tdm_error:%d", hwc_window, terr);
430 tinfo.src_config.pos.x = 0;
431 tinfo.src_config.pos.y = 0;
432 tinfo.src_config.pos.w = tbm_surface_get_width(tsurface);
433 tinfo.src_config.pos.h = tbm_surface_get_height(tsurface);
434 tinfo.src_config.size.h = get_horizontal_get(tsurface);
435 tinfo.src_config.size.v = tbm_surface_get_height(tsurface);
436 tinfo.src_config.format = tbm_surface_get_format(tsurface);
437 tinfo.dst_pos.x = hwc_window->x;
438 tinfo.dst_pos.y = hwc_window->y;
439 tinfo.dst_pos.w = hwc_window->dest_width;
440 tinfo.dst_pos.h = hwc_window->dest_height;
441 tinfo.transform = get_tdm_transform(hwc_window->transform);
444 if (memcmp(&hwc_window->tinfo, &tinfo, sizeof tinfo)) {
445 memcpy(&hwc_window->tinfo, &tinfo, sizeof tinfo);
447 terr = tdm_hwc_window_set_info(hwc_window->twindow, &hwc_window->tinfo);
448 if (terr != TDM_ERROR_NONE)
449 ds_err("Could not set info hwc_window:%p tdm_error:%d", hwc_window, terr);
452 terr = tdm_hwc_window_set_composition_type(hwc_window->twindow,
453 get_tdm_composition(hwc_window->composition));
454 if (terr != TDM_ERROR_NONE)
455 ds_err("Could not set composition type hwc_window:%p tdm_error:%d", hwc_window, terr);
459 ds_tdm_output_hwc_validate(struct ds_tdm_output_hwc *hwc,
460 struct ds_tdm_output_hwc_window **composited_windows, uint32_t num_windows, uint32_t *num_changed)
463 tdm_hwc_window **compositied_hwc_windows = NULL;
464 struct ds_tdm_output_hwc_window *hwc_window;
467 wl_list_for_each(hwc_window, &hwc->hwc_windows, link)
468 hwc_window_update(hwc_window);
470 if (num_windows > 0) {
471 compositied_hwc_windows = calloc(num_windows, sizeof(tdm_hwc_window *));
472 if (!compositied_hwc_windows)
475 for (i = 0; i < num_windows; i++)
476 compositied_hwc_windows[i] = composited_windows[i]->twindow;
479 terr = tdm_hwc_validate(hwc->thwc, compositied_hwc_windows, num_windows, num_changed);
480 if (terr != TDM_ERROR_NONE) {
481 if (compositied_hwc_windows)
482 free(compositied_hwc_windows);
483 ds_err("Could not hwc validate");
487 if (compositied_hwc_windows)
488 free(compositied_hwc_windows);
490 hwc->validate_num_changed = *num_changed;
495 static struct ds_tdm_output_hwc_window *
496 hwc_get_hwc_window_from_tdm_hwc_window(struct ds_tdm_output_hwc *hwc, tdm_hwc_window *thwc_window)
498 struct ds_tdm_output_hwc_window *hwc_window;
500 wl_list_for_each(hwc_window, &hwc->hwc_windows, link) {
501 if (hwc_window->twindow == thwc_window)
509 ds_tdm_output_hwc_get_changed_composition(struct ds_tdm_output_hwc *hwc, uint32_t *num_changed,
510 struct ds_tdm_output_hwc_window **changed_windows)
512 tdm_hwc_window **changed_thwc_windows = NULL;
513 tdm_hwc_window_composition *compositions = NULL;
514 struct ds_tdm_output_hwc_window *hwc_window;
518 if (!hwc->validate_num_changed) {
523 changed_thwc_windows = calloc(hwc->validate_num_changed, sizeof *changed_thwc_windows);
524 if (!changed_thwc_windows)
527 compositions = calloc(hwc->validate_num_changed, sizeof *compositions);
529 free(changed_thwc_windows);
533 terr = tdm_hwc_get_changed_composition_types(hwc->thwc, &hwc->validate_num_changed,
534 changed_thwc_windows, compositions);
535 if (terr != TDM_ERROR_NONE) {
536 ds_err("Could not hwc get changed composition types");
537 free(changed_thwc_windows);
542 for (i = 0; i < hwc->validate_num_changed; i++) {
543 if (i >= *num_changed)
546 hwc_window = hwc_get_hwc_window_from_tdm_hwc_window(hwc, changed_thwc_windows[i]);
550 ds_tdm_output_hwc_window_set_composition(hwc_window, get_composition(compositions[i]));
551 changed_windows[i] = hwc_window;
554 free(changed_thwc_windows);
563 ds_tdm_output_hwc_accept_validation(struct ds_tdm_output_hwc *hwc)
566 struct ds_tdm_output_hwc_window *hwc_window;
567 enum ds_tdm_output_hwc_window_composition composition;
569 terr = tdm_hwc_accept_validation(hwc->thwc);
570 if (terr != TDM_ERROR_NONE) {
571 ds_err("Could not hwc accept validation");
575 wl_list_for_each(hwc_window, &hwc->hwc_windows, link) {
576 composition = ds_tdm_output_hwc_window_get_composition(hwc_window);
577 ds_tdm_output_hwc_window_set_accepted_composition(hwc_window,
579 if ((composition == DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_DEVICE) ||
580 (composition == DS_TDM_OUTPUT_HWC_WINDOW_COMPOSITION_VIDEO)) {
581 hwc_window_attach_back_buffer(hwc_window, hwc_window->set_buffer);
583 hwc_window_attach_back_buffer(hwc_window, NULL);
591 ds_tdm_output_hwc_commit_handler(tdm_hwc *thwc, unsigned int sequence,
592 unsigned int tv_sec, unsigned int tv_usec, void *user_data)
594 struct ds_tdm_output_hwc *hwc = user_data;
595 struct ds_tdm_output_hwc_window *hwc_window, *tmp;
597 wl_list_for_each_safe(hwc_window, tmp, &hwc->hwc_windows, link)
598 hwc_window_update_front_buffer(hwc_window);
600 wl_signal_emit(&hwc->events.commit_handler, hwc);
604 ds_tdm_output_hwc_commit(struct ds_tdm_output_hwc *hwc)
607 uint32_t num_changes;
610 terr = tdm_hwc_validate(hwc->thwc, NULL, 0, &num_changes);
611 if (terr != TDM_ERROR_NONE) {
612 ds_err("Could not hwc validate");
616 terr = tdm_hwc_accept_validation(hwc->thwc);
617 if (terr != TDM_ERROR_NONE) {
618 ds_err("Could not hwc accept validation");
623 terr = tdm_hwc_commit(hwc->thwc, 0, ds_tdm_output_hwc_commit_handler, hwc);
624 if (terr != TDM_ERROR_NONE) {
625 ds_err("Could not hwc commit");
633 ds_tdm_output_hwc_add_commit_handler_listener(struct ds_tdm_output_hwc *hwc,
634 struct wl_listener *listener)
636 wl_signal_add(&hwc->events.commit_handler, listener);