X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Ftdm_vblank.c;h=977e402a380dcfb0e5127db3d378f0fa7f7199bb;hb=95af5139e398eba6799b80b503ec2b98d0d9ee16;hp=12b760d2644d6dd82cd64f54d79e1317da3a0501;hpb=37fd93539622189a546c8f00296d3e3a0ac8a9ae;p=platform%2Fcore%2Fuifw%2Flibtdm.git diff --git a/src/tdm_vblank.c b/src/tdm_vblank.c index 12b760d..977e402 100644 --- a/src/tdm_vblank.c +++ b/src/tdm_vblank.c @@ -9,7 +9,7 @@ * Taeheon Kim , * YoungJun Cho , * SooChan Lim , - * Boram Park + * Boram Park * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the @@ -158,10 +158,10 @@ typedef struct _tdm_vblank_create_handler_info { void *user_data; } tdm_vblank_create_handler_info; -/* valid_vblank_list and valid_wait_list should be protected by valid_list_lock because - * tdm_vblank can be used in multi-thread. +/* valid_vblank_list, valid_wait_list and create_handler_list should be protected + * by valid_list_lock because tdm_vblank can be used in multi-thread. */ -static pthread_mutex_t valid_list_lock; +static pthread_mutex_t valid_list_lock = PTHREAD_MUTEX_INITIALIZER; static struct list_head valid_vblank_list; static struct list_head valid_wait_list; static struct list_head create_handler_list; @@ -321,7 +321,7 @@ _tdm_vblank_insert_wait(tdm_vblank_wait_info *wait_info, struct list_head *list) if (found) LIST_ADD(&wait_info->link, &found->link); else - LIST_ADDTAIL(&wait_info->link, list->next); + LIST_ADDTAIL(&wait_info->link, list); } static void @@ -350,7 +350,7 @@ _tdm_vblank_free_HW_wait(tdm_private_vblank *private_vblank, tdm_error error, un pid_t pid; const char *proc_name; _tdm_vblank_get_client_information(private_vblank, &pid, &proc_name); - VER("TDM HW vblank destroyed forcely!! (pid: %u, name: %s)", pid, proc_name); + VWR("TDM HW vblank destroyed forcely!! (pid: %u, name: %s)", pid, proc_name); } LIST_FOR_EACH_ENTRY_SAFE(w, ww, &private_vblank->HW_wait_list, link) { @@ -377,19 +377,17 @@ _tdm_vblank_update_output_info(tdm_private_vblank *private_vblank) tdm_output *output = private_vblank->output; tdm_output_conn_status connection = TDM_OUTPUT_CONN_STATUS_DISCONNECTED; unsigned int vrefresh = TDM_VBLANK_DEFAULT_VREFRESH; + const tdm_output_mode *mode = NULL; tdm_error ret; ret = tdm_output_get_conn_status(output, &connection); TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE); - if (connection == TDM_OUTPUT_CONN_STATUS_MODE_SETTED) { - const tdm_output_mode *mode = NULL; - tdm_output_get_mode(output, &mode); - if (mode) - vrefresh = mode->vrefresh; - else - VWR("mode not setted!!!"); - } + ret = tdm_output_get_mode(output, &mode); + if (ret == TDM_ERROR_NONE && mode) + vrefresh = mode->vrefresh; + else + VWR("mode not setted!!!"); private_vblank->connection = connection; private_vblank->vrefresh = vrefresh; @@ -452,10 +450,50 @@ _tdm_vblank_cb_output_change(tdm_output *output, tdm_output_change_type type, } /* LCOV_EXCL_STOP */ +static tdm_error +_tdm_vblank_set_fps(tdm_vblank *vblank, unsigned int fps) +{ + tdm_private_vblank *private_vblank = vblank; + + if (private_vblank->fps_fixed) { + VIN("fps(%u) can't be changed", private_vblank->fps); + return TDM_ERROR_NONE; + } + + private_vblank->fps_changeable = 0; + + if (private_vblank->fps == fps) + return TDM_ERROR_NONE; + + private_vblank->fps = fps; + private_vblank->check_HW_or_SW = 1; + + VIN("fps(%u) changed", fps); + + return TDM_ERROR_NONE; +} + +static tdm_error +_tdm_vblank_ignore_global_fps(tdm_vblank *vblank, unsigned int ignore) +{ + tdm_private_vblank *private_vblank = vblank; + + if (private_vblank->ignore_global_fps == ignore) + return TDM_ERROR_NONE; + + private_vblank->ignore_global_fps = ignore; + private_vblank->check_HW_or_SW = 1; + + VIN("ignore_global_fps(%u)", private_vblank->ignore_global_fps); + + return TDM_ERROR_NONE; +} + EXTERN tdm_error tdm_vblank_set_client_vblank_fps(unsigned int pid, const char *name, unsigned int fps) { tdm_private_vblank *v = NULL; + tdm_error ret = TDM_ERROR_NONE; TDM_RETURN_VAL_IF_FAIL(pid > 0, TDM_ERROR_INVALID_PARAMETER); TDM_RETURN_VAL_IF_FAIL(fps > 0, TDM_ERROR_INVALID_PARAMETER); @@ -484,9 +522,11 @@ tdm_vblank_set_client_vblank_fps(unsigned int pid, const char *name, unsigned in continue; } - tdm_vblank_set_fps(v, fps); - - TDM_INFO("(pid:%u) '%s' fps changed: %d", pid, v->name, fps); + ret = _tdm_vblank_set_fps(v, fps); + if (ret == TDM_ERROR_NONE) + TDM_INFO("(pid:%u) '%s' fps changed: %d", pid, v->name, fps); + else + TDM_ERR("(pid:%u) '%s' fps changing failed: %d", pid, v->name, fps); } pthread_mutex_unlock(&valid_list_lock); @@ -497,6 +537,7 @@ EXTERN tdm_error tdm_vblank_set_client_ignore_global_fps(unsigned int pid, const char *name, unsigned int ignore) { tdm_private_vblank *v = NULL; + tdm_error ret = TDM_ERROR_NONE; TDM_RETURN_VAL_IF_FAIL(pid > 0, TDM_ERROR_INVALID_PARAMETER); @@ -524,9 +565,11 @@ tdm_vblank_set_client_ignore_global_fps(unsigned int pid, const char *name, unsi continue; } - tdm_vblank_ignore_global_fps(v, ignore); - - TDM_INFO("(pid:%u) '%s' ignore changed: %u", pid, v->name, ignore); + ret = _tdm_vblank_ignore_global_fps(v, ignore); + if (ret == TDM_ERROR_NONE) + TDM_INFO("(pid:%u) '%s' ignore changed: %u", pid, v->name, ignore); + else + TDM_ERR("(pid:%u) '%s' ignore changing failed: %u", pid, v->name, ignore); } pthread_mutex_unlock(&valid_list_lock); @@ -576,9 +619,10 @@ _tdm_vblank_thread_cb_create(tdm_private_display *private_display, void *object, return; } - /* use in_create_handler instead of mutext unlock/lock */ private_vblank->in_create_handler = 1; + tdm_display_unlock(private_display); ch_info->func(private_vblank, ch_info->user_data); + tdm_display_lock(private_display); private_vblank->in_create_handler = 0; } @@ -596,7 +640,7 @@ _tdm_vblank_call_thread_cb(tdm_private_vblank *private_vblank) vblank_create.base.sync = 0; vblank_create.vblank_stamp = private_vblank->stamp; - ret = tdm_thread_cb_call(private_vblank->dpy, &vblank_create.base); + ret = tdm_thread_cb_call(private_vblank->dpy, &vblank_create.base, 1); TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE); return TDM_ERROR_NONE; @@ -608,18 +652,25 @@ tdm_vblank_add_create_handler(tdm_display *dpy, tdm_vblank_create_handler func, tdm_vblank_create_handler_info *ch_info = NULL; tdm_error ret; - TDM_RETURN_VAL_IF_FAIL(!TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED); + TDM_RETURN_VAL_IF_FAIL(dpy != NULL, TDM_ERROR_INVALID_PARAMETER); TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER); + pthread_mutex_lock(&valid_list_lock); + LIST_FOR_EACH_ENTRY(ch_info, &create_handler_list, link) { if (ch_info->func == func && ch_info->user_data == user_data) { TDM_ERR("can't be added twice"); + pthread_mutex_unlock(&valid_list_lock); return TDM_ERROR_BAD_REQUEST; } } ch_info = calloc(1, sizeof *ch_info); - TDM_RETURN_VAL_IF_FAIL(ch_info != NULL, TDM_ERROR_OUT_OF_MEMORY); + if (!ch_info) { + TDM_ERR("alloc failed: %m"); + pthread_mutex_unlock(&valid_list_lock); + return TDM_ERROR_OUT_OF_MEMORY; + } tdm_display_lock(dpy); ret = tdm_thread_cb_add(dpy, TDM_THREAD_CB_VBLANK_CREATE, NULL, _tdm_vblank_thread_cb_create, ch_info); @@ -628,6 +679,7 @@ tdm_vblank_add_create_handler(tdm_display *dpy, tdm_vblank_create_handler func, if (ret != TDM_ERROR_NONE) { TDM_ERR("tdm_thread_cb_add failed"); free(ch_info); + pthread_mutex_unlock(&valid_list_lock); return ret; } @@ -635,6 +687,9 @@ tdm_vblank_add_create_handler(tdm_display *dpy, tdm_vblank_create_handler func, ch_info->user_data = user_data; LIST_ADDTAIL(&ch_info->link, &create_handler_list); + + pthread_mutex_unlock(&valid_list_lock); + return TDM_ERROR_NONE; } @@ -643,31 +698,24 @@ tdm_vblank_remove_create_handler(tdm_display *dpy, tdm_vblank_create_handler fun { tdm_vblank_create_handler_info *ch_info = NULL, *hh = NULL; - TDM_RETURN_IF_FAIL(!TDM_MUTEX_IS_LOCKED()); - - /* we don't allow adding a create handler in sub-thread because tdm_vblank_create() - * can be called in both threads and tdm_thread_send_cb supports only one-way - * communication now. - */ - if (!tdm_thread_in_display_thread(syscall(SYS_gettid))) { - TDM_ERR("remove_create_handler should be called in main thread"); - return; - } + TDM_RETURN_IF_FAIL(dpy != NULL); + TDM_RETURN_IF_FAIL(func != NULL); tdm_display_lock(dpy); - + pthread_mutex_lock(&valid_list_lock); LIST_FOR_EACH_ENTRY_SAFE(ch_info, hh, &create_handler_list, link) { - if (ch_info->func != func && ch_info->user_data != user_data) + if (ch_info->func != func || ch_info->user_data != user_data) continue; tdm_thread_cb_remove(dpy, TDM_THREAD_CB_VBLANK_CREATE, NULL, _tdm_vblank_thread_cb_create, ch_info); LIST_DEL(&ch_info->link); free(ch_info); + pthread_mutex_unlock(&valid_list_lock); tdm_display_unlock(dpy); return; } - + pthread_mutex_unlock(&valid_list_lock); tdm_display_unlock(dpy); } @@ -683,11 +731,6 @@ tdm_vblank_init(tdm_display *dpy) if (vblank_list_inited) return TDM_ERROR_NONE; - if (pthread_mutex_init(&valid_list_lock, NULL)) { - TDM_ERR("mutex init failed: %m"); - return TDM_ERROR_OUT_OF_MEMORY; - } - LIST_INITHEAD(&valid_vblank_list); LIST_INITHEAD(&valid_wait_list); LIST_INITHEAD(&create_handler_list); @@ -719,8 +762,6 @@ tdm_vblank_deinit(tdm_display *dpy) free(ch_info); } - pthread_mutex_destroy(&valid_list_lock); - vblank_list_inited = 0; } @@ -730,8 +771,8 @@ tdm_vblank_create(tdm_display *dpy, tdm_output *output, tdm_error *error) tdm_private_vblank *private_vblank; tdm_error ret; - TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(tdm_display_is_valid(dpy), TDM_ERROR_INVALID_PARAMETER, NULL); - TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(tdm_output_is_valid(output), TDM_ERROR_INVALID_PARAMETER, NULL); + TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(dpy != NULL, TDM_ERROR_INVALID_PARAMETER, NULL); + TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(output != NULL, TDM_ERROR_INVALID_PARAMETER, NULL); if (error) *error = TDM_ERROR_NONE; @@ -746,7 +787,14 @@ tdm_vblank_create(tdm_display *dpy, tdm_output *output, tdm_error *error) /* LCOV_EXCL_STOP */ } - tdm_output_add_change_handler(output, _tdm_vblank_cb_output_change, private_vblank); + ret = tdm_output_add_change_handler(output, _tdm_vblank_cb_output_change, private_vblank); + if (ret != TDM_ERROR_NONE) { + free(private_vblank); + if (error) + *error = TDM_ERROR_OPERATION_FAILED; + TDM_ERR("tdm_output_add_change_handler failed"); + return NULL; + } private_vblank->stamp = ++stamp; private_vblank->owner_tid = syscall(SYS_gettid); @@ -827,6 +875,20 @@ tdm_vblank_destroy(tdm_vblank *vblank) free(private_vblank); } +EXTERN tdm_output * +tdm_vblank_get_output(tdm_vblank *vblank, tdm_error *error) +{ + tdm_private_vblank *private_vblank = vblank; + tdm_error ret = TDM_ERROR_NONE; + + TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(tdm_vblank_is_valid(vblank), TDM_ERROR_INVALID_PARAMETER, NULL); + + if (error) + *error = TDM_ERROR_NONE; + + return private_vblank->output; +} + EXTERN tdm_error tdm_vblank_get_client_pid(tdm_vblank *vblank, pid_t *pid) { @@ -886,27 +948,10 @@ tdm_vblank_get_name(tdm_vblank *vblank, const char **name) EXTERN tdm_error tdm_vblank_set_fps(tdm_vblank *vblank, unsigned int fps) { - tdm_private_vblank *private_vblank = vblank; - TDM_RETURN_VAL_IF_FAIL(tdm_vblank_is_valid(vblank), TDM_ERROR_INVALID_PARAMETER); TDM_RETURN_VAL_IF_FAIL(fps > 0, TDM_ERROR_INVALID_PARAMETER); - if (private_vblank->fps_fixed) { - VIN("fps(%d) can't be changed", private_vblank->fps); - return TDM_ERROR_NONE; - } - - private_vblank->fps_changeable = 0; - - if (private_vblank->fps == fps) - return TDM_ERROR_NONE; - - private_vblank->fps = fps; - private_vblank->check_HW_or_SW = 1; - - VIN("fps(%d) changed", fps); - - return TDM_ERROR_NONE; + return _tdm_vblank_set_fps(vblank, fps); } EXTERN tdm_error @@ -939,7 +984,7 @@ tdm_vblank_set_fixed_fps(tdm_vblank *vblank, unsigned int fps) private_vblank->fps = fps; private_vblank->check_HW_or_SW = 1; - VIN("fps(%d) fixed", fps); + VIN("fps(%u) fixed", fps); return TDM_ERROR_NONE; } @@ -947,19 +992,9 @@ tdm_vblank_set_fixed_fps(tdm_vblank *vblank, unsigned int fps) EXTERN tdm_error tdm_vblank_ignore_global_fps(tdm_vblank *vblank, unsigned int ignore) { - tdm_private_vblank *private_vblank = vblank; - TDM_RETURN_VAL_IF_FAIL(tdm_vblank_is_valid(vblank), TDM_ERROR_INVALID_PARAMETER); - if (private_vblank->ignore_global_fps == ignore) - return TDM_ERROR_NONE; - - private_vblank->ignore_global_fps = ignore; - private_vblank->check_HW_or_SW = 1; - - VIN("ignore_global_fps(%d)", private_vblank->ignore_global_fps); - - return TDM_ERROR_NONE; + return _tdm_vblank_ignore_global_fps(vblank, ignore); } EXTERN tdm_error @@ -968,6 +1003,7 @@ tdm_vblank_set_offset(tdm_vblank *vblank, int offset) tdm_private_vblank *private_vblank = vblank; TDM_RETURN_VAL_IF_FAIL(tdm_vblank_is_valid(vblank), TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(offset >= 0, TDM_ERROR_INVALID_PARAMETER); if (private_vblank->offset == offset) return TDM_ERROR_NONE; @@ -975,7 +1011,7 @@ tdm_vblank_set_offset(tdm_vblank *vblank, int offset) private_vblank->offset = offset; private_vblank->check_HW_or_SW = 1; - VIN("offset(%d)", private_vblank->offset); + VIN("offset(%u)", private_vblank->offset); return TDM_ERROR_NONE; } @@ -1005,7 +1041,7 @@ tdm_vblank_set_enable_fake(tdm_vblank *vblank, unsigned int enable_fake) private_vblank->enable_fake = enable_fake; - VIN("enable_fake(%d)", private_vblank->enable_fake); + VIN("enable_fake(%u)", private_vblank->enable_fake); return TDM_ERROR_NONE; } @@ -1386,7 +1422,7 @@ _tdm_vblank_cb_timeout_SW(void *user_data) vblank_sw.base.data = NULL; vblank_sw.base.sync = 0; - ret = tdm_thread_cb_call(private_vblank, &vblank_sw.base); + ret = tdm_thread_cb_call(private_vblank, &vblank_sw.base, 1); TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE); return TDM_ERROR_NONE; @@ -1397,52 +1433,53 @@ _tdm_vblank_wait_SW(tdm_vblank_wait_info *wait_info) { tdm_private_vblank *private_vblank = wait_info->private_vblank; tdm_error ret; + double last, prev, req, curr, target; + unsigned int skip; if (private_vblank->last_type != VBLANK_EVENT_TYPE_SW) { - VIN("Use SW vblank"); + tdm_output_dpms dpms; + + tdm_output_get_dpms(private_vblank->output, &dpms); + + VIN("Use SW vblank. connection(%s), dpms(%s), vrefresh(%d), fps(%d), offset(%d)", + tdm_status_str(private_vblank->connection), tdm_dpms_str(dpms), + private_vblank->vrefresh, private_vblank->fps, private_vblank->offset); private_vblank->last_type = VBLANK_EVENT_TYPE_SW; } if (private_vblank->last_time == 0) { /* SW vblank starts from now. SW vblank doesn't need to be aligned with HW vblank. */ private_vblank->last_seq = 0; - private_vblank->last_time = tdm_helper_get_time(); + private_vblank->last_time = tdm_helper_get_time() - private_vblank->vblank_gap; /* +1 ms to call the handler ASAP at the first. no matter for SW timer. */ wait_info->target_seq = 1; - wait_info->target_time = private_vblank->last_time + 0.001; - - VDB("wait(%p) last(%.6f) target(%.6f) target sequence(%u)", - wait_info, private_vblank->last_time, wait_info->target_time, wait_info->target_seq); - } else { - double last, prev, req, curr, target; - unsigned int skip; + } - last = private_vblank->last_time; - req = wait_info->req_time; + last = private_vblank->last_time; + req = wait_info->req_time; - /* make sure that req time is bigger than last. */ - if (req < last) - req = last; + /* make sure that req time is bigger than last. */ + if (req < last) + req = last; - skip = (unsigned int)((req - last) / private_vblank->vblank_gap + TDM_TIME_MARGIN); - prev = last + private_vblank->vblank_gap * skip; + skip = (unsigned int)((req - last) / private_vblank->vblank_gap + TDM_TIME_MARGIN); + prev = last + private_vblank->vblank_gap * skip; - curr = tdm_helper_get_time(); - target = prev + private_vblank->vblank_gap * wait_info->interval; + curr = tdm_helper_get_time(); + target = prev + private_vblank->vblank_gap * wait_info->interval; - while (target < curr) - target += private_vblank->vblank_gap; + while (target < curr) + target += private_vblank->vblank_gap; - wait_info->target_seq = private_vblank->last_seq; - wait_info->target_seq += (unsigned int)((target - last) / private_vblank->vblank_gap + TDM_TIME_MARGIN); + wait_info->target_seq = private_vblank->last_seq; + wait_info->target_seq += (unsigned int)((target - last) / private_vblank->vblank_gap + TDM_TIME_MARGIN); - wait_info->target_time = target; + wait_info->target_time = target + (double)(private_vblank->offset) / 1000; - VDB("wait(%p) last(%.6f) req(%.6f) prev(%.6f) curr(%.6f) targ(%.6f,%.6f) skip(%u) targ_seq(%u)", - wait_info, last, req - last, prev - last, curr - last, - target, target - last, skip, wait_info->target_seq); - } + VDB("wait(%p) last(%.6f) req(%.6f) prev(%.6f) curr(%.6f) targ(%.6f,%.6f) skip(%u) targ_seq(%u)", + wait_info, last, req - last, prev - last, curr - last, + target, target - last, skip, wait_info->target_seq); _tdm_vblank_insert_wait(wait_info, &private_vblank->SW_wait_list); @@ -1470,6 +1507,7 @@ tdm_vblank_wait(tdm_vblank *vblank, unsigned int req_sec, unsigned int req_usec, TDM_RETURN_VAL_IF_FAIL(tdm_vblank_is_valid(vblank), TDM_ERROR_INVALID_PARAMETER); TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(interval > 0, TDM_ERROR_INVALID_PARAMETER); if (private_vblank->in_create_handler) { TDM_ERR("NOT allowed to be called in a create handler"); @@ -1521,7 +1559,8 @@ tdm_vblank_wait(tdm_vblank *vblank, unsigned int req_sec, unsigned int req_usec, wait_info->user_data = user_data; wait_info->private_vblank = private_vblank; - if (private_vblank->ignore_global_fps || + if (!private_vblank->resource || + private_vblank->ignore_global_fps || vblank_global_fps == 0 || private_vblank->fps < vblank_global_fps) fps = private_vblank->fps; @@ -1536,8 +1575,8 @@ tdm_vblank_wait(tdm_vblank *vblank, unsigned int req_sec, unsigned int req_usec, /* 1) if fps != factor of vrefresh, SW timer * 2) if fps == factor of vrefresh && dpms == off, SW timer (Fake HW vblank) - * 2) if fps == factor of vrefresh && dpms == on && offset == 0, HW vblank - * 3) if fps == factor of vrefresh && dpms == on && offset != 0, HW vblank + SW timer + * 3) if fps == factor of vrefresh && dpms == on && offset == 0, HW vblank + * 4) if fps == factor of vrefresh && dpms == on && offset != 0, HW vblank + SW timer * In case of 1), we really don't need to align with HW vblank. */ if (private_vblank->vrefresh % fps)