X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Ftdm.c;h=2246fc4bb5aff06e61e6d467de35982b40d81c2e;hb=c61e3aaef986c13175c299570e8bc3ef09a4d50a;hp=371553d2633a375256200f7a1fac0e8ced1c5ec9;hpb=27146b62eac2097bb21a3ebc109513e19290faab;p=platform%2Fcore%2Fuifw%2Flibtdm.git diff --git a/src/tdm.c b/src/tdm.c index 371553d..2246fc4 100644 --- a/src/tdm.c +++ b/src/tdm.c @@ -41,9 +41,14 @@ #include "tdm_backend.h" #include "tdm_private.h" #include "tdm_helper.h" +#include pthread_mutex_t tdm_mutex_check_lock = PTHREAD_MUTEX_INITIALIZER; int tdm_mutex_locked; +const char *tdm_mutex_lock_func; +int tdm_mutex_lock_line; +const char *tdm_mutex_unlock_func; +int tdm_mutex_unlock_line; static tdm_private_layer * _tdm_display_find_private_layer(tdm_private_output *private_output, @@ -74,8 +79,7 @@ _tdm_display_find_private_output(tdm_private_display *private_display, } INTERN tdm_private_output * -tdm_display_find_output_stamp(tdm_private_display *private_display, - unsigned long stamp) +tdm_display_find_output_stamp(tdm_private_display *private_display, double stamp) { tdm_private_output *private_output = NULL; @@ -147,10 +151,13 @@ _tdm_display_destroy_private_layer(tdm_private_layer *private_layer) static void _tdm_display_destroy_private_output(tdm_private_output *private_output) { + tdm_private_display *private_display = private_output->private_display; tdm_private_layer *l = NULL, *ll = NULL; + tdm_private_hwc_window *hw = NULL, *hww = NULL; tdm_private_capture *c = NULL, *cc = NULL; tdm_private_vblank_handler *v = NULL, *vv = NULL; - tdm_private_commit_handler *m = NULL, *mm = NULL; + tdm_private_output_commit_handler *om = NULL, *omm = NULL; + tdm_private_layer_commit_handler *lm = NULL, *lmm = NULL; tdm_private_change_handler *h = NULL, *hh = NULL; LIST_DEL(&private_output->link); @@ -162,9 +169,19 @@ _tdm_display_destroy_private_output(tdm_private_output *private_output) free(v); } - LIST_FOR_EACH_ENTRY_SAFE(m, mm, &private_output->commit_handler_list, link) { - LIST_DEL(&m->link); - free(m); + LIST_FOR_EACH_ENTRY_SAFE(om, omm, &private_output->output_commit_handler_list, link) { + LIST_DEL(&om->link); + free(om); + } + + LIST_FOR_EACH_ENTRY_SAFE(lm, lmm, &private_output->layer_commit_handler_list, link) { + LIST_DEL(&lm->link); + free(lm); + } + + LIST_FOR_EACH_ENTRY_SAFE(lm, lmm, &private_output->pending_commit_handler_list, link) { + LIST_DEL(&lm->link); + free(lm); } LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_output->change_handler_list_main, link) { @@ -177,9 +194,19 @@ _tdm_display_destroy_private_output(tdm_private_output *private_output) free(h); } + if (private_output->vblank) { + /* tdm_vblank APIs is for server. it should be called in unlock status*/ + _pthread_mutex_unlock(&private_display->lock); + tdm_vblank_destroy(private_output->vblank); + _pthread_mutex_lock(&private_display->lock); + } + LIST_FOR_EACH_ENTRY_SAFE(c, cc, &private_output->capture_list, link) tdm_capture_destroy_internal(c); + LIST_FOR_EACH_ENTRY_SAFE(hw, hww, &private_output->hwc_window_list, link) + tdm_hwc_window_destroy_internal(hw); + LIST_FOR_EACH_ENTRY_SAFE(l, ll, &private_output->layer_list, link) _tdm_display_destroy_private_layer(l); @@ -214,7 +241,7 @@ _tdm_display_destroy_private_display(tdm_private_display *private_display) _tdm_display_destroy_caps_capture(&private_display->caps_capture); private_display->capabilities = 0; - private_display->caps_display.max_layer_count = -1; + private_display->caps_display.max_layer_count = 0; } static tdm_error @@ -293,13 +320,17 @@ _tdm_display_update_caps_output(tdm_private_display *private_display, int pipe, tdm_func_output *func_output = &private_display->func_output; char temp[TDM_NAME_LEN]; tdm_error ret; + double stamp; if (!func_output->output_get_capability) { TDM_ERR("no output_get_capability()"); return TDM_ERROR_BAD_MODULE; } + stamp = tdm_helper_get_time(); ret = func_output->output_get_capability(output_backend, caps); + TDM_DBG("backend output_get_capability() time: %.3f ms", (tdm_helper_get_time() - stamp) * 1000.0); + if (ret != TDM_ERROR_NONE) { TDM_ERR("output_get_capability() failed"); return TDM_ERROR_BAD_MODULE; @@ -363,7 +394,7 @@ tdm_display_update_output(tdm_private_display *private_display, private_output = calloc(1, sizeof(tdm_private_output)); TDM_RETURN_VAL_IF_FAIL(private_output != NULL, TDM_ERROR_OUT_OF_MEMORY); - private_output->stamp = tdm_helper_get_time_in_millis(); + private_output->stamp = tdm_helper_get_time(); while (tdm_display_find_output_stamp(private_display, private_output->stamp)) private_output->stamp++; @@ -376,9 +407,12 @@ tdm_display_update_output(tdm_private_display *private_display, private_output->index = pipe; LIST_INITHEAD(&private_output->layer_list); + LIST_INITHEAD(&private_output->hwc_window_list); LIST_INITHEAD(&private_output->capture_list); LIST_INITHEAD(&private_output->vblank_handler_list); - LIST_INITHEAD(&private_output->commit_handler_list); + LIST_INITHEAD(&private_output->output_commit_handler_list); + LIST_INITHEAD(&private_output->layer_commit_handler_list); + LIST_INITHEAD(&private_output->pending_commit_handler_list); LIST_INITHEAD(&private_output->change_handler_list_main); LIST_INITHEAD(&private_output->change_handler_list_sub); @@ -389,13 +423,35 @@ tdm_display_update_output(tdm_private_display *private_display, private_output->regist_change_cb = 1; } - } else - _tdm_display_destroy_caps_output(&private_output->caps); + ret = _tdm_display_update_caps_output(private_display, pipe, output_backend, + &private_output->caps); + if (ret != TDM_ERROR_NONE) + return ret; + } else { + tdm_caps_output new_caps; - ret = _tdm_display_update_caps_output(private_display, pipe, output_backend, - &private_output->caps); - if (ret != TDM_ERROR_NONE) - return ret; + ret = _tdm_display_update_caps_output(private_display, pipe, output_backend, + &new_caps); + if (ret != TDM_ERROR_NONE) + return ret; + + /* FIXME: This is very ugly. need to fix after the TDM ABI is changed. */ + if (private_output->caps.status != new_caps.status) { + _tdm_display_destroy_caps_output(&private_output->caps); + private_output->caps = new_caps; + private_output->current_mode = NULL; + } else { + tdm_output_mode *old_modes = private_output->caps.modes; + unsigned int old_mode_count = private_output->caps.mode_count; + if (new_caps.modes) + free(new_caps.modes); + new_caps.modes = old_modes; + new_caps.mode_count = old_mode_count; + if (private_output->caps.props) + free(private_output->caps.props); + private_output->caps = new_caps; + } + } layers = func_output->output_get_layers(output_backend, &layer_count, &ret); if (ret != TDM_ERROR_NONE) @@ -503,6 +559,8 @@ _tdm_display_get_ordered_outputs(tdm_private_display *private_display, int *coun break; } } + + _tdm_display_destroy_caps_output(&caps); } /* ordering : main output is first */ @@ -607,7 +665,8 @@ tdm_display_update(tdm_display *dpy) } #define SUFFIX_MODULE ".so" -#define DEFAULT_MODULE "libtdm-default"SUFFIX_MODULE +#define TDM_DEFAULT_MODULE "libtdm-default"SUFFIX_MODULE +#define TDM_DUMMY_MODULE "libtdm-dummy"SUFFIX_MODULE int tdm_debug_module; int tdm_debug_dump; @@ -676,16 +735,12 @@ _tdm_display_check_backend_functions(tdm_private_display *private_display) /* below functions should be implemented in backend side */ TDM_RETURN_VAL_IF_FAIL(func_display != NULL, TDM_ERROR_BAD_MODULE); -// TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capabilitiy, TDM_ERROR_BAD_MODULE); TDM_RETURN_VAL_IF_FAIL(func_display->display_get_outputs, TDM_ERROR_BAD_MODULE); TDM_RETURN_VAL_IF_FAIL(func_output->output_get_capability, TDM_ERROR_BAD_MODULE); TDM_RETURN_VAL_IF_FAIL(func_output->output_get_layers, TDM_ERROR_BAD_MODULE); TDM_RETURN_VAL_IF_FAIL(func_layer->layer_get_capability, TDM_ERROR_BAD_MODULE); - if (func_display->display_get_capability) - ret = func_display->display_get_capability(private_display->bdata, &private_display->caps_display); - else - ret = func_display->display_get_capabilitiy(private_display->bdata, &private_display->caps_display); + ret = func_display->display_get_capability(private_display->bdata, &private_display->caps_display); if (ret != TDM_ERROR_NONE) { TDM_ERR("display_get_capability() failed"); return TDM_ERROR_BAD_MODULE; @@ -703,8 +758,10 @@ _tdm_display_check_backend_functions(tdm_private_display *private_display) if (private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE) { tdm_func_capture *func_capture = &private_display->func_capture; TDM_RETURN_VAL_IF_FAIL(func_display->display_get_capture_capability, TDM_ERROR_BAD_MODULE); - TDM_RETURN_VAL_IF_FAIL(func_output->output_create_capture, TDM_ERROR_BAD_MODULE); - TDM_RETURN_VAL_IF_FAIL(func_layer->layer_create_capture, TDM_ERROR_BAD_MODULE); + if (private_display->caps_capture.capabilities & TDM_CAPTURE_CAPABILITY_OUTPUT) + TDM_RETURN_VAL_IF_FAIL(func_output->output_create_capture, TDM_ERROR_BAD_MODULE); + if (private_display->caps_capture.capabilities & TDM_CAPTURE_CAPABILITY_LAYER) + TDM_RETURN_VAL_IF_FAIL(func_layer->layer_create_capture, TDM_ERROR_BAD_MODULE); TDM_RETURN_VAL_IF_FAIL(func_capture->capture_destroy, TDM_ERROR_BAD_MODULE); TDM_RETURN_VAL_IF_FAIL(func_capture->capture_commit, TDM_ERROR_BAD_MODULE); TDM_RETURN_VAL_IF_FAIL(func_capture->capture_set_done_handler, TDM_ERROR_BAD_MODULE); @@ -721,9 +778,16 @@ _tdm_display_load_module_with_file(tdm_private_display *private_display, tdm_backend_module *module_data; void *module; tdm_error ret; + double stamp; + int size; - snprintf(path, sizeof(path), TDM_MODULE_PATH "/%s", file); + size = snprintf(path, sizeof(path), TDM_MODULE_PATH "/%s", file); + if (size >= (int)sizeof(path)) { + TDM_WRN("too long: %s/%s", TDM_MODULE_PATH, file); + return TDM_ERROR_BAD_MODULE; + }; + stamp = tdm_helper_get_time(); TDM_TRACE_BEGIN(Load_Backend); module = dlopen(path, RTLD_LAZY); @@ -741,6 +805,8 @@ _tdm_display_load_module_with_file(tdm_private_display *private_display, goto failed_load; } + TDM_DBG("dlopen, dlsym time: %.3f ms", (tdm_helper_get_time() - stamp) * 1000.0); + private_display->module_data = module_data; private_display->module = module; @@ -753,8 +819,11 @@ _tdm_display_load_module_with_file(tdm_private_display *private_display, /* We don't care if backend_data is NULL or not. It's up to backend. */ TDM_TRACE_BEGIN(Init_Backend); + stamp = tdm_helper_get_time(); private_display->bdata = module_data->init((tdm_display *)private_display, &ret); + TDM_DBG("backend init() time: %.3f ms", (tdm_helper_get_time() - stamp) * 1000.0); TDM_TRACE_END(); + if (ret != TDM_ERROR_NONE) { TDM_ERR("failed to init '%s' module", module_data->name); goto failed_load; @@ -781,16 +850,25 @@ static tdm_error _tdm_display_load_module(tdm_private_display *private_display) { const char *module_name; + char module[TDM_NAME_LEN]; struct dirent **namelist; int n; tdm_error ret = 0; module_name = getenv("TDM_MODULE"); if (!module_name) - module_name = DEFAULT_MODULE; + module_name = TDM_DEFAULT_MODULE; + + strncpy(module, module_name, TDM_NAME_LEN - 1); + module[TDM_NAME_LEN - 1] = '\0'; /* load bufmgr priv from default lib */ - ret = _tdm_display_load_module_with_file(private_display, module_name); + ret = _tdm_display_load_module_with_file(private_display, (const char*)module); + if (ret == TDM_ERROR_NONE) + return TDM_ERROR_NONE; + + /* load bufmgr priv from dummy lib */ + ret = _tdm_display_load_module_with_file(private_display, TDM_DUMMY_MODULE); if (ret == TDM_ERROR_NONE) return TDM_ERROR_NONE; @@ -830,19 +908,22 @@ EXTERN tdm_display * tdm_display_init(tdm_error *error) { tdm_private_display *private_display = NULL; - const char *debug; + const char *str; tdm_error ret; + double stamp1, stamp2, start; - _pthread_mutex_lock(&gLock); + pthread_mutex_lock(&gLock); if (g_private_display) { g_private_display->init_count++; - _pthread_mutex_unlock(&gLock); + pthread_mutex_unlock(&gLock); if (error) *error = TDM_ERROR_NONE; return g_private_display; } + start = stamp1 = tdm_helper_get_time(); + private_display = calloc(1, sizeof(tdm_private_display)); if (!private_display) { ret = TDM_ERROR_OUT_OF_MEMORY; @@ -850,17 +931,17 @@ tdm_display_init(tdm_error *error) goto failed_alloc; } - debug = getenv("TDM_DEBUG_MODULE"); - if (debug) - tdm_display_enable_debug_module(debug); + str = getenv("TDM_DEBUG_MODULE"); + if (str) + tdm_display_enable_debug_module(str); - debug = getenv("TDM_DEBUG_DUMP"); - if (debug) - tdm_display_enable_dump(private_display, debug, NULL, NULL); + str = getenv("TDM_DEBUG_DUMP"); + if (str) + tdm_display_enable_dump(private_display, str, NULL, NULL); - debug = getenv("TDM_DEBUG_PATH"); - if (debug) - tdm_display_enable_path(debug); + str = getenv("TDM_DEBUG_PATH"); + if (str) + tdm_display_enable_path(str); if (pthread_mutex_init(&private_display->lock, NULL)) { ret = TDM_ERROR_OPERATION_FAILED; @@ -870,14 +951,26 @@ tdm_display_init(tdm_error *error) _pthread_mutex_lock(&private_display->lock); + stamp2 = tdm_helper_get_time(); + TDM_DBG("prepare init time: %.3f ms", (stamp2 - stamp1) * 1000.0); + stamp1 = stamp2; + ret = tdm_event_loop_init(private_display); if (ret != TDM_ERROR_NONE) goto failed_event; + stamp2 = tdm_helper_get_time(); + TDM_DBG("creating event loop time: %.3f ms", (stamp2 - stamp1) * 1000.0); + stamp1 = stamp2; + ret = _tdm_display_load_module(private_display); if (ret != TDM_ERROR_NONE) goto failed_load; + stamp2 = tdm_helper_get_time(); + TDM_DBG("loading backend time: %.3f ms", (stamp2 - stamp1) * 1000.0); + stamp1 = stamp2; + #ifdef INIT_BUFMGR int tdm_drm_fd = tdm_helper_get_fd("TDM_DRM_MASTER_FD"); if (tdm_drm_fd >= 0) { @@ -889,6 +982,10 @@ tdm_display_init(tdm_error *error) } else { TDM_INFO("tbm_bufmgr_init successed"); } + + stamp2 = tdm_helper_get_time(); + TDM_DBG("initializing bufmgr time: %.3f ms", (stamp2 - stamp1) * 1000.0); + stamp1 = stamp2; } #endif @@ -898,23 +995,52 @@ tdm_display_init(tdm_error *error) if (ret != TDM_ERROR_NONE) goto failed_update; + stamp2 = tdm_helper_get_time(); + TDM_DBG("updating display time: %.3f ms", (stamp2 - stamp1) * 1000.0); + stamp1 = stamp2; + tdm_event_loop_create_backend_source(private_display); private_display->init_count = 1; + tdm_private_output *o = NULL; + LIST_FOR_EACH_ENTRY(o, &private_display->output_list, link) { + if (o->caps.capabilities & TDM_OUTPUT_CAPABILITY_HWC) + tdm_output_need_validate_event_init(o); + } + + /* the COMMIT_PER_VBLANK functionality is ability of an output to support + * several operational modes (commit_per_vblank modes) related to tdm_commit; + * this functionality can be turned off which means a default mode */ + str = getenv("TDM_COMMIT_PER_VBLANK"); + if (str) { + tdm_private_output *o = NULL; + char *end; + int mode = strtol(str, &end, 10); + + /* outputs which support hwc capability can work only + * if commit_per_vblank mode is '0' (default mode) */ + LIST_FOR_EACH_ENTRY(o, &private_display->output_list, link) + if (!(o->caps.capabilities & TDM_OUTPUT_CAPABILITY_HWC)) + tdm_output_choose_commit_per_vblank_mode(o, mode); + } + g_private_display = private_display; if (error) *error = TDM_ERROR_NONE; _pthread_mutex_unlock(&private_display->lock); - _pthread_mutex_unlock(&gLock); + pthread_mutex_unlock(&gLock); + + TDM_INFO("init time: %.3f ms", (tdm_helper_get_time() - start) * 1000.0); return (tdm_display *)private_display; failed_update: _tdm_display_unload_module(private_display); failed_load: + tdm_event_loop_stop(private_display); tdm_event_loop_deinit(private_display); failed_event: _pthread_mutex_unlock(&private_display->lock); @@ -924,7 +1050,7 @@ failed_mutex_init: failed_alloc: if (error) *error = ret; - _pthread_mutex_unlock(&gLock); + pthread_mutex_unlock(&gLock); return NULL; } @@ -936,11 +1062,11 @@ tdm_display_deinit(tdm_display *dpy) if (!private_display) return; - _pthread_mutex_lock(&gLock); + pthread_mutex_lock(&gLock); private_display->init_count--; if (private_display->init_count > 0) { - _pthread_mutex_unlock(&gLock); + pthread_mutex_unlock(&gLock); return; } @@ -949,24 +1075,30 @@ tdm_display_deinit(tdm_display *dpy) * things because it's finalized. */ _pthread_mutex_lock(&private_display->lock); - tdm_event_loop_deinit(private_display); - _pthread_mutex_unlock(&private_display->lock); - + tdm_event_loop_stop(private_display); _tdm_display_destroy_private_display(private_display); _tdm_display_unload_module(private_display); + _pthread_mutex_unlock(&private_display->lock); + + tdm_event_loop_deinit(private_display); #ifdef INIT_BUFMGR if (private_display->bufmgr) tbm_bufmgr_deinit(private_display->bufmgr); #endif - tdm_helper_set_fd("TDM_DRM_MASTER_FD", -1); + tbm_drm_helper_unset_tbm_master_fd(); pthread_mutex_destroy(&private_display->lock); free(private_display); g_private_display = NULL; - _pthread_mutex_unlock(&gLock); + if (tdm_debug_dump_dir) { + free(tdm_debug_dump_dir); + tdm_debug_dump_dir = NULL; + } + + pthread_mutex_unlock(&gLock); TDM_INFO("done"); } @@ -1014,8 +1146,8 @@ tdm_display_enable_debug_module(const char*modules) tdm_debug_module |= TDM_DEBUG_MUTEX; else if (!strncmp(arg, "vblank", 6)) tdm_debug_module |= TDM_DEBUG_VBLANK; - else - return TDM_ERROR_BAD_REQUEST; + else if (!strncmp(arg, "commit", 6)) + tdm_debug_module |= TDM_DEBUG_COMMIT; arg = strtok_r(NULL, TDM_DELIM, &end); } @@ -1029,7 +1161,7 @@ INTERN tdm_error tdm_display_enable_dump(tdm_private_display *private_display, const char *dump_str, char *reply, int *len) { char temp[TDM_PATH_LEN] = {0,}, temp2[TDM_PATH_LEN] = {0,}; - char *path, *path2; + char *path = NULL, *path2; char *arg; char *end; @@ -1040,24 +1172,25 @@ tdm_display_enable_dump(tdm_private_display *private_display, const char *dump_s else path2++; - path = tdm_helper_dump_make_directory(path2, reply, len); - TDM_GOTO_IF_FAIL(path != NULL, done); - tdm_debug_dump = 0; snprintf(temp, sizeof(temp), "%s", dump_str); arg = strtok_r(temp, ",", &end); + TDM_GOTO_IF_FAIL(arg != NULL, done); if (!strncmp(arg, "none", 4)) { tdm_debug_dump = 0; + TDM_SNPRINTF(reply, len, "path: %s\n", (tdm_debug_dump_dir) ? : "unknown"); if (tdm_debug_dump_dir) { free(tdm_debug_dump_dir); tdm_debug_dump_dir = NULL; } - TDM_SNPRINTF(reply, len, "path: %s\n", path); goto done; } + path = tdm_helper_dump_make_directory(path2, reply, len); + TDM_GOTO_IF_FAIL(path != NULL, done); + if (!strncmp(arg, "current", 7)) { tdm_private_output *o = NULL; if (!private_display) { @@ -1069,10 +1202,12 @@ tdm_display_enable_dump(tdm_private_display *private_display, const char *dump_s tdm_private_layer *l = NULL; LIST_FOR_EACH_ENTRY(l, &o->layer_list, link) { char str[TDM_PATH_LEN]; - if (l->usable) + if (l->usable || l->caps.capabilities & TDM_LAYER_CAPABILITY_VIDEO) + continue; + if (!l->showing_buffer) continue; snprintf(str, TDM_PATH_LEN, "layer_%d_%d", o->index, l->index); - tdm_helper_dump_buffer_str(l->showing_buffer, path, str); + tdm_helper_dump_buffer_str(l->showing_buffer->buffer, path, str); } } @@ -1092,6 +1227,8 @@ tdm_display_enable_dump(tdm_private_display *private_display, const char *dump_s tdm_debug_dump |= TDM_DUMP_FLAG_PP; } else if (!strncmp(arg, "capture", 7)) { tdm_debug_dump |= TDM_DUMP_FLAG_CAPTURE; + } else if (!strncmp(arg, "window", 6)) { + tdm_debug_dump |= TDM_DUMP_FLAG_WINDOW; } else goto done; @@ -1106,7 +1243,9 @@ tdm_display_enable_dump(tdm_private_display *private_display, const char *dump_s TDM_INFO("dump... '%s'", dump_str); done: - free(path); + if (path) + free(path); + return TDM_ERROR_NONE; } @@ -1142,3 +1281,68 @@ tdm_display_enable_path(const char *path) return TDM_ERROR_NONE; } + + +static void +_tdm_display_ttrace_vblank_cb(tdm_vblank *vblank, tdm_error error, unsigned int sequence, + unsigned int tv_sec, unsigned int tv_usec, void *user_data) +{ + tdm_error ret = TDM_ERROR_NONE; + + TDM_TRACE_MARK(VBlank); + + ret = tdm_vblank_wait(vblank, 0, 0, 1, _tdm_display_ttrace_vblank_cb, NULL); + TDM_RETURN_IF_FAIL(ret == TDM_ERROR_NONE); +} + +INTERN tdm_error +tdm_display_enable_ttrace_vblank(tdm_display *dpy, tdm_output *output, int enable) +{ + static tdm_vblank *vblank = NULL; + tdm_error ret = TDM_ERROR_NONE; + + if (!enable) { + if (vblank) + tdm_vblank_destroy(vblank); + vblank = NULL; + return TDM_ERROR_NONE; + } else { + const tdm_output_mode *mode = NULL; + + if (vblank) + return TDM_ERROR_NONE; + + vblank = tdm_vblank_create(dpy, output, &ret); + TDM_RETURN_VAL_IF_FAIL(vblank != NULL, ret); + + ret = tdm_output_get_mode(output, &mode); + TDM_GOTO_IF_FAIL(mode != NULL, enable_fail); + + ret = tdm_vblank_set_fps(vblank, mode->vrefresh); + TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, enable_fail); + + ret = tdm_vblank_set_enable_fake(vblank, 1); + TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, enable_fail); + + ret = tdm_vblank_wait(vblank, 0, 0, 1, _tdm_display_ttrace_vblank_cb, NULL); + TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, enable_fail); + } + + return TDM_ERROR_NONE; + +enable_fail: + if (vblank) + tdm_vblank_destroy(vblank); + vblank = NULL; + return ret; +} + +INTERN tdm_error +tdm_display_enable_fps(tdm_private_display *private_display, int enable) +{ + private_display->print_fps = enable; + + TDM_INFO("print fps: %s", (enable) ? "enable" : "disable"); + + return TDM_ERROR_NONE; +}