unsigned int tv_sec, unsigned int tv_usec, void *user_data);
static void _tbm_layer_queue_acquirable_cb(tbm_surface_queue_h surface_queue, void *data);
static void _tbm_layer_queue_destroy_cb(tbm_surface_queue_h surface_queue, void *data);
+static void _tdm_layer_cb_output_commit(tdm_output *output, unsigned int sequence,
+ unsigned int tv_sec, unsigned int tv_usec, void *user_data);
EXTERN tdm_error
tdm_layer_get_capabilities(tdm_layer *layer, tdm_layer_capability *capabilities)
LIST_FOR_EACH_ENTRY_SAFE(lm, lmm, &clone_list, link) {
LIST_DEL(&lm->link);
+ tdm_output_remove_commit_handler_internal(private_output, _tdm_layer_cb_output_commit, lm);
_tdm_layer_free_buffer(private_layer, lm->committed_buffer);
free(lm);
}
tdm_private_layer_commit_handler *lm = NULL, *lmm = NULL;
tdm_private_display *private_display;
struct list_head clone_list, pending_clone_list;
- tdm_error ret;
+ tdm_error ret = TDM_ERROR_NONE;
private_display = private_output->private_display;
if (tdm_debug_module & TDM_DEBUG_COMMIT)
TDM_INFO("layer commit: output(%d) commit", private_output->pipe);
- /* tdm_vblank APIs is for server. it should be called in unlock status*/
- if (!private_output->layer_waiting_vblank) {
- _pthread_mutex_unlock(&private_display->lock);
- ret = tdm_vblank_wait(private_output->vblank, 0, 0, 1, _tdm_layer_cb_wait_vblank, private_output);
- _pthread_mutex_lock(&private_display->lock);
- TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, wait_failed);
- private_output->layer_waiting_vblank = 1;
+ if (private_output->current_dpms_value == TDM_OUTPUT_DPMS_ON) {
+ /* tdm_vblank APIs is for server. it should be called in unlock status*/
+ if (!private_output->layer_waiting_vblank) {
+ _pthread_mutex_unlock(&private_display->lock);
+ ret = tdm_vblank_wait(private_output->vblank, 0, 0, 1, _tdm_layer_cb_wait_vblank, private_output);
+ _pthread_mutex_lock(&private_display->lock);
+ TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, wait_failed);
+ private_output->layer_waiting_vblank = 1;
+ }
}
if (tdm_debug_module & TDM_DEBUG_COMMIT)
LIST_ADDTAIL(&lm->link, &private_output->layer_commit_handler_list);
}
+ if (private_output->current_dpms_value != TDM_OUTPUT_DPMS_ON) {
+ TDM_WRN("TDM_OUTPUT_DPMS_OFF. Directly call vblank callback.");
+ _pthread_mutex_unlock(&private_display->lock);
+ _tdm_layer_cb_wait_vblank(private_output->vblank, 0, 0, 0, 0, private_output);
+ _pthread_mutex_lock(&private_display->lock);
+ }
+
return;
wait_failed:
+ /* CAUTION: Once _tdm_layer_commit returns success, the layer commit handler MUST be called always.
+ * That is, even if we get error in _tdm_layer_got_output_vblank() function for some reasons,
+ * the layer commit handler MUST be called.
+ */
LIST_FOR_EACH_ENTRY_SAFE(lm, lmm, &pending_clone_list, link) {
+ TDM_WRN("Directly call layer commit handlers: ret(%d)\n", ret);
LIST_DEL(&lm->link);
+ _pthread_mutex_unlock(&private_display->lock);
+ if (lm->func)
+ lm->func(lm->private_layer, sequence, tv_sec, tv_usec, lm->user_data);
+ _pthread_mutex_lock(&private_display->lock);
_tdm_layer_free_buffer(lm->private_layer, lm->committed_buffer);
free(lm);
}
+
return;
}
return count;
}
+/* commit_per_vblank == 1: we can commit if
+ * - there is no previous commit request
+ * - only 1 layer is used
+ * commit_per_vblank == 2: we can commit if
+ * - there is no previous commit request
+ */
static int
_tdm_layer_commit_possible(tdm_private_layer *private_layer)
{
tdm_private_output *private_output = private_layer->private_output;
tdm_private_display *private_display = private_output->private_display;
- if (private_display->commit_per_vblank == 1 && _tdm_lauer_get_output_used_layer_count(private_output) == 1) {
+ TDM_RETURN_VAL_IF_FAIL(!(private_display->commit_per_vblank > 0), 1);
+
+ /* There is a previous commit request which is not done and displayed on screen yet.
+ * We can't commit at this time.
+ */
+ if (!LIST_IS_EMPTY(&private_output->layer_commit_handler_list)) {
if (tdm_debug_module & TDM_DEBUG_COMMIT)
- TDM_INFO("layer(%p) commit: 1 layer", private_layer);
- return 1;
+ TDM_INFO("layer(%p) commit: not possible(previous commit)", private_layer);
+ return 0;
}
- if (private_display->commit_per_vblank == 2 && LIST_IS_EMPTY(&private_output->layer_commit_handler_list)) {
+ if (private_display->commit_per_vblank == 1 && _tdm_lauer_get_output_used_layer_count(private_output) > 1) {
if (tdm_debug_module & TDM_DEBUG_COMMIT)
- TDM_INFO("layer(%p) commit: non previous commit", private_layer);
- return 1;
+ TDM_INFO("layer(%p) commit: not possible(more than 2 layers)", private_layer);
+ return 0;
}
- return 0;
+ TDM_INFO("layer(%p) commit: possible", private_layer);
+
+ return 1;
}
+/* CAUTION: Once _tdm_layer_commit returns success, the layer commit handler MUST be called always.
+ * That is, even if we get error in _tdm_layer_got_output_vblank() function for some reasons,
+ * the layer commit handler MUST be called.
+ */
static tdm_error
_tdm_layer_commit(tdm_layer *layer, tdm_layer_commit_handler func, void *user_data)
{
return ret;
}
+INTERN void
+tdm_layer_remove_commit_handler_internal(tdm_layer *layer, tdm_layer_commit_handler func, void *user_data)
+{
+ tdm_private_layer *private_layer = (tdm_private_layer*)layer;
+ tdm_private_output *private_output = private_layer->private_output;
+ tdm_private_layer_commit_handler *lm = NULL, *lmm = NULL;
+
+ TDM_RETURN_IF_FAIL(private_layer != NULL);
+ TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED());
+
+ LIST_FOR_EACH_ENTRY_SAFE(lm, lmm, &private_output->layer_commit_handler_list, link) {
+ if (lm->func == func && lm->user_data == user_data) {
+ LIST_DEL(&lm->link);
+ tdm_output_remove_commit_handler_internal(private_output, _tdm_layer_cb_output_commit, lm);
+ _tdm_layer_free_buffer(private_layer, lm->committed_buffer);
+ free(lm);
+ break;
+ }
+ }
+
+ LIST_FOR_EACH_ENTRY_SAFE(lm, lmm, &private_output->pending_commit_handler_list, link) {
+ if (lm->func == func && lm->user_data == user_data) {
+ LIST_DEL(&lm->link);
+ tdm_output_remove_commit_handler_internal(private_output, _tdm_layer_cb_output_commit, lm);
+ _tdm_layer_free_buffer(private_layer, lm->committed_buffer);
+ free(lm);
+ break;
+ }
+ }
+}
+
+EXTERN tdm_error
+tdm_layer_remove_commit_handler(tdm_layer *layer, tdm_layer_commit_handler func, void *user_data)
+{
+ LAYER_FUNC_ENTRY();
+
+ _pthread_mutex_lock(&private_display->lock);
+
+ tdm_layer_remove_commit_handler_internal(layer, func, user_data);
+
+ _pthread_mutex_unlock(&private_display->lock);
+
+ return ret;
+}
+
EXTERN tbm_surface_h
tdm_layer_get_displaying_buffer(tdm_layer *layer, tdm_error *error)
{