From ba7dee3f8476700ad0cf3e7995a9e09234a0bc93 Mon Sep 17 00:00:00 2001 From: Konstantin Drabeniuk Date: Thu, 16 Nov 2017 17:21:57 +0200 Subject: [PATCH 01/16] add excluding coverage comments for tdm_pp.c add excluding coverage comments for tdm_pp.c for folowing code: - fail if the backend's function don't exist; - dump; - calloc fail; - check_module_abi fail. Change-Id: Ie4dd5dfbd086b858f9235afd72ab7b6518714dc9 --- src/tdm_pp.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/tdm_pp.c b/src/tdm_pp.c index ab95105..a58e4fc 100644 --- a/src/tdm_pp.c +++ b/src/tdm_pp.c @@ -131,10 +131,12 @@ tdm_pp_cb_done(tdm_pp *pp_backend, tbm_surface_h src, tbm_surface_h dst, TDM_NEVER_GET_HERE(); if (tdm_debug_dump & TDM_DUMP_FLAG_PP) { + /* LCOV_EXCL_START */ char str[TDM_PATH_LEN]; static int i; snprintf(str, TDM_PATH_LEN, "pp_dst_%03d", i++); tdm_helper_dump_buffer_str(dst, tdm_debug_dump_dir, str); + /* LCOV_EXCL_STOP */ } if (tdm_debug_module & TDM_DEBUG_BUFFER) @@ -193,35 +195,43 @@ tdm_pp_create_internal(tdm_private_display *private_display, tdm_error *error) func_pp = &private_display->func_pp; if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP)) { + /* LCOV_EXCL_START */ TDM_ERR("no pp capability"); if (error) *error = TDM_ERROR_NO_CAPABILITY; return NULL; + /* LCOV_EXCL_STOP */ } pp_backend = func_display->display_create_pp(private_display->bdata, &ret); if (ret != TDM_ERROR_NONE) { + /* LCOV_EXCL_START */ if (error) *error = ret; return NULL; + /* LCOV_EXCL_STOP */ } private_pp = calloc(1, sizeof(tdm_private_pp)); if (!private_pp) { + /* LCOV_EXCL_START */ TDM_ERR("failed: alloc memory"); func_pp->pp_destroy(pp_backend); if (error) *error = TDM_ERROR_OUT_OF_MEMORY; return NULL; + /* LCOV_EXCL_STOP */ } ret = func_pp->pp_set_done_handler(pp_backend, tdm_pp_cb_done, private_pp); if (ret != TDM_ERROR_NONE) { + /* LCOV_EXCL_START */ TDM_ERR("spp(%p) et pp_done_handler failed", private_pp); func_pp->pp_destroy(pp_backend); if (error) *error = ret; return NULL; + /* LCOV_EXCL_STOP */ } private_pp->stamp = tdm_helper_get_time(); @@ -332,9 +342,11 @@ tdm_pp_set_info(tdm_pp *pp, tdm_info_pp *info) _pthread_mutex_lock(&private_display->lock); if (!func_pp->pp_set_info) { + /* LCOV_EXCL_START */ _pthread_mutex_unlock(&private_display->lock); TDM_DBG("failed: not implemented!!"); return TDM_ERROR_NOT_IMPLEMENTED; + /* LCOV_EXCL_STOP */ } TDM_INFO("pp(%p) info: src(%dx%d %d,%d %dx%d %c%c%c%c) dst(%dx%d %d,%d %dx%d %c%c%c%c) trans(%d) sync(%d) flags(%x)", @@ -395,13 +407,16 @@ tdm_pp_attach(tdm_pp *pp, tbm_surface_h src, tbm_surface_h dst) _pthread_mutex_lock(&private_display->lock); if (!func_pp->pp_attach) { + /* LCOV_EXCL_START */ _pthread_mutex_unlock(&private_display->lock); TDM_DBG("failed: not implemented!!"); return TDM_ERROR_NOT_IMPLEMENTED; + /* LCOV_EXCL_STOP */ } if (tdm_display_check_module_abi(private_display, 1, 2) && private_display->caps_pp.max_attach_count > 0) { + /* LCOV_EXCL_START */ int length = LIST_LENGTH(&private_pp->pending_buffer_list) + LIST_LENGTH(&private_pp->buffer_list); if (length >= private_display->caps_pp.max_attach_count) { @@ -410,30 +425,37 @@ tdm_pp_attach(tdm_pp *pp, tbm_surface_h src, tbm_surface_h dst) private_display->caps_pp.max_attach_count); return TDM_ERROR_BAD_REQUEST; } + /* LCOV_EXCL_STOP */ } if (tdm_debug_dump & TDM_DUMP_FLAG_PP) { + /* LCOV_EXCL_START */ char str[TDM_PATH_LEN]; static int i; snprintf(str, TDM_PATH_LEN, "pp_src_%03d", i++); tdm_helper_dump_buffer_str(src, tdm_debug_dump_dir, str); + /* LCOV_EXCL_STOP */ } pp_buffer = calloc(1, sizeof * pp_buffer); if (!pp_buffer) { + /* LCOV_EXCL_START */ _pthread_mutex_unlock(&private_display->lock); TDM_ERR("alloc failed"); return TDM_ERROR_OUT_OF_MEMORY; + /* LCOV_EXCL_STOP */ } ret = func_pp->pp_attach(private_pp->pp_backend, src, dst); TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE); if (ret != TDM_ERROR_NONE) { + /* LCOV_EXCL_START */ free(pp_buffer); _pthread_mutex_unlock(&private_display->lock); TDM_ERR("attach failed"); return ret; + /* LCOV_EXCL_STOP */ } LIST_ADDTAIL(&pp_buffer->link, &private_pp->pending_buffer_list); @@ -461,9 +483,11 @@ tdm_pp_commit(tdm_pp *pp) _pthread_mutex_lock(&private_display->lock); if (!func_pp->pp_commit) { + /* LCOV_EXCL_START */ _pthread_mutex_unlock(&private_display->lock); TDM_DBG("failed: not implemented!!"); return TDM_ERROR_NOT_IMPLEMENTED; + /* LCOV_EXCL_STOP */ } LIST_INITHEAD(&commit_buffer_list); -- 2.7.4 From 76ed75b0f206e9bb918ca566c6760a6105fcd7bf Mon Sep 17 00:00:00 2001 From: Boram Park Date: Fri, 17 Nov 2017 15:47:22 +0900 Subject: [PATCH 02/16] output: add debugging logs Change-Id: I716746908d47b15757772ebc71cf714a0e0a5771 --- src/tdm_output.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/tdm_output.c b/src/tdm_output.c index 2307b7a..078946a 100644 --- a/src/tdm_output.c +++ b/src/tdm_output.c @@ -1126,7 +1126,7 @@ tdm_output_cb_dpms(tdm_output *output_backend, tdm_output_dpms dpms, void *user_ private_output->current_dpms_value = dpms; private_output->waiting_dpms_change = 0; - TDM_INFO("output(%d) dpms %s", private_output->pipe, tdm_dpms_str(dpms)); + TDM_INFO("output(%d) dpms async '%s' done", private_output->pipe, tdm_dpms_str(dpms)); value.u32 = dpms; tdm_output_call_change_handler_internal(private_output, @@ -1176,6 +1176,8 @@ tdm_output_set_dpms(tdm_output *output, tdm_output_dpms dpms_value) func_output = &private_display->func_output; + TDM_INFO("output(%d) dpms '%s'", private_output->pipe, tdm_dpms_str(dpms_value)); + if (func_output->output_set_dpms) ret = func_output->output_set_dpms(private_output->output_backend, dpms_value); else { @@ -1189,7 +1191,7 @@ done: tdm_value value; private_output->current_dpms_value = dpms_value; - TDM_INFO("output(%d) dpms %s", private_output->pipe, tdm_dpms_str(dpms_value)); + TDM_INFO("output(%d) dpms '%s' done", private_output->pipe, tdm_dpms_str(dpms_value)); value.u32 = dpms_value; tdm_output_call_change_handler_internal(private_output, @@ -1260,10 +1262,14 @@ tdm_output_set_dpms_async(tdm_output *output, tdm_output_dpms dpms_value) } } + TDM_INFO("output(%d) dpms async '%s'", private_output->pipe, tdm_dpms_str(dpms_value)); + ret = func_output->output_set_dpms_async(private_output->output_backend, dpms_value); - if (ret == TDM_ERROR_NONE) + if (ret == TDM_ERROR_NONE) { private_output->waiting_dpms_change = 1; + TDM_INFO("output(%d) dpms async '%s' waiting", private_output->pipe, tdm_dpms_str(dpms_value)); + } _pthread_mutex_unlock(&private_display->lock); -- 2.7.4 From 1667cd3c2b47baae13ff532a510af5493da31634 Mon Sep 17 00:00:00 2001 From: Konstantin Drabeniuk Date: Fri, 17 Nov 2017 09:01:38 +0200 Subject: [PATCH 03/16] utest: fix warnings Change-Id: I5bdb832d6074481723a7ddd14a4b1028f7701188 Signed-off-by: Konstantin Drabeniuk --- utests/src/ut_tdm_layer.cpp | 31 +++++++++++-------------------- utests/src/ut_tdm_pp.cpp | 13 +------------ utests/src/ut_tdm_vblank.cpp | 4 ++++ 3 files changed, 16 insertions(+), 32 deletions(-) diff --git a/utests/src/ut_tdm_layer.cpp b/utests/src/ut_tdm_layer.cpp index 21a552d..0d629f6 100644 --- a/utests/src/ut_tdm_layer.cpp +++ b/utests/src/ut_tdm_layer.cpp @@ -561,8 +561,7 @@ TEST_F(TDMLayer, LayerGetZposFailNullAll) TEST_F(TDMLayer, LayerGetZposFailNullLayer) { SKIP_FLAG(has_layers); - ASSERT_EXIT({const tdm_prop *props; - int zpos; + ASSERT_EXIT({int zpos; if (tdm_layer_get_zpos(NULL, &zpos) == TDM_ERROR_NONE) exit(1); exit(0);}, ::testing::ExitedWithCode(0), ""); } @@ -570,8 +569,7 @@ TEST_F(TDMLayer, LayerGetZposFailNullLayer) TEST_F(TDMLayer, LayerGetZposFailNullZpos) { SKIP_FLAG(has_layers); - ASSERT_EXIT({int count; - for (int i = 0; i < layer_count; i++) { + ASSERT_EXIT({for (int i = 0; i < layer_count; i++) { if (tdm_layer_get_zpos(tdm_layer_array[i], NULL) == TDM_ERROR_NONE) exit(1); } exit(0);}, ::testing::ExitedWithCode(0), ""); @@ -628,8 +626,7 @@ TEST_F(TDMLayer, LayerGetPropertyFailNullLayer) TEST_F(TDMLayer, LayerGetPropertyFailNullValue) { SKIP_FLAG(has_layers); - ASSERT_EXIT({tdm_value value; - int id = INT_MAX; + ASSERT_EXIT({int id = INT_MAX; for (int i = 0; i < layer_count; ++i) { if (tdm_layer_get_property(tdm_layer_array[i], id, NULL) == TDM_ERROR_NONE) exit(1); } @@ -654,9 +651,7 @@ TEST_F(TDMLayer, LayerGetPropertyFailWrongId) TEST_F(TDMLayer, LayerSetInfoFailNullAll) { SKIP_FLAG(has_layers); - ASSERT_EXIT({tdm_value value; - int id = INT_MAX; - if (tdm_layer_set_info(NULL, NULL) == TDM_ERROR_NONE) exit(1); + ASSERT_EXIT({if (tdm_layer_set_info(NULL, NULL) == TDM_ERROR_NONE) exit(1); exit(0);}, ::testing::ExitedWithCode(0), ""); } @@ -673,8 +668,7 @@ TEST_F(TDMLayer, LayerSetInfoFailNullInfo) { SKIP_FLAG(has_layers); - ASSERT_EXIT({tdm_info_layer info = {0}; - for (int i = 0; i < layer_count; ++i) + ASSERT_EXIT({for (int i = 0; i < layer_count; ++i) if (tdm_layer_set_info(tdm_layer_array[i], NULL) == TDM_ERROR_NONE) exit(1); exit(0);}, ::testing::ExitedWithCode(0), ""); } @@ -716,9 +710,7 @@ TEST_F(TDMLayer, LayerSetInfoSuccess) TEST_F(TDMLayer, LayerGetInfoFailNullAll) { SKIP_FLAG(has_layers); - ASSERT_EXIT({tdm_value value; - int id = INT_MAX; - if (tdm_layer_get_info(NULL, NULL) == TDM_ERROR_NONE) exit(1); + ASSERT_EXIT({if (tdm_layer_get_info(NULL, NULL) == TDM_ERROR_NONE) exit(1); exit(0);}, ::testing::ExitedWithCode(0), ""); } @@ -735,8 +727,7 @@ TEST_F(TDMLayer, LayerGetInfoFailNullInfo) { SKIP_FLAG(has_layers); - ASSERT_EXIT({tdm_info_layer info = {0}; - for (int i = 0; i < layer_count; ++i) + ASSERT_EXIT({for (int i = 0; i < layer_count; ++i) if (tdm_layer_get_info(tdm_layer_array[i], NULL) == TDM_ERROR_NONE) exit(1); exit(0);}, ::testing::ExitedWithCode(0), ""); } @@ -1749,12 +1740,12 @@ TEST_F(TDMLayerCommitThread, LayerSetBufferQueueSuccessRemoveBufferQueue) ASSERT_EQ(TDM_ERROR_NONE, error); tbm_err = tbm_surface_queue_dequeue(buffer_queue, &surface); - ASSERT_EQ(TBM_SURFACE_QUEUE_ERROR_NONE, error); + ASSERT_EQ(TBM_SURFACE_QUEUE_ERROR_NONE, tbm_err); tdm_layer_commit(tdm_layer_array[i], NULL, NULL); tbm_err = tbm_surface_queue_enqueue(buffer_queue, surface); - ASSERT_EQ(TBM_SURFACE_QUEUE_ERROR_NONE, error); + ASSERT_EQ(TBM_SURFACE_QUEUE_ERROR_NONE, tbm_err); } /* FIXME: use another func. */ @@ -1804,12 +1795,12 @@ TEST_F(TDMLayerCommitWithDisabledCommitPerVblank, LayerSetBufferQueueSuccessRemo ASSERT_EQ(TDM_ERROR_NONE, error); tbm_err = tbm_surface_queue_dequeue(buffer_queue, &surface); - ASSERT_EQ(TBM_SURFACE_QUEUE_ERROR_NONE, error); + ASSERT_EQ(TBM_SURFACE_QUEUE_ERROR_NONE, tbm_err); tdm_layer_commit(tdm_layer_array[i], NULL, NULL); tbm_err = tbm_surface_queue_enqueue(buffer_queue, surface); - ASSERT_EQ(TBM_SURFACE_QUEUE_ERROR_NONE, error); + ASSERT_EQ(TBM_SURFACE_QUEUE_ERROR_NONE, tbm_err); } /* FIXME: use another func. */ diff --git a/utests/src/ut_tdm_pp.cpp b/utests/src/ut_tdm_pp.cpp index fdd1353..2ff78c9 100644 --- a/utests/src/ut_tdm_pp.cpp +++ b/utests/src/ut_tdm_pp.cpp @@ -249,10 +249,7 @@ protected: void SetUp(void) { - tdm_error error; - tdm_output *output; struct epoll_event ep; - tdm_pp_capability pp_capability; ASSERT_NO_FATAL_FAILURE(TDMPP::SetUp()); @@ -277,8 +274,6 @@ protected: void TearDown(void) { - tdm_error error; - if (epFd) close(epFd); if (timerFd) @@ -351,13 +346,12 @@ protected: if (error != TDM_ERROR_NONE) return -1; + return 0; } int UtPrepareToPPWithScale() { tdm_info_pp info = {0}; - tdm_error error; - tbm_surface_h src_buf, dst_buf; UtGetPPInfoWithScale(&info); @@ -367,8 +361,6 @@ protected: int UtPrepareToPPWithScaleAndTransform() { tdm_info_pp info = {0}; - tdm_error error; - tbm_surface_h src_buf, dst_buf; UtGetPPInfoWithScaleAndTransform(&info); @@ -379,7 +371,6 @@ protected: { tdm_info_pp info = {0}; tdm_error error; - tbm_surface_h src_buf, dst_buf; int ret; UtGetPPInfoWithScale(&info); @@ -543,7 +534,6 @@ TEST_F(TDMPP, PpSetDoneHandlerFailNullPP) { SKIP_FLAG(has_pp); tdm_error error; - int data; error = tdm_pp_set_done_handler(NULL, UtPpDoneHandler, this); ASSERT_NE(TDM_ERROR_NONE, error); @@ -572,7 +562,6 @@ TEST_F(TDMPP, PpSetDoneHandlerSuccess) { SKIP_FLAG(has_pp); tdm_error error; - int data; error = tdm_pp_set_done_handler(pp, UtPpDoneHandler, this); ASSERT_EQ(TDM_ERROR_NONE, error); diff --git a/utests/src/ut_tdm_vblank.cpp b/utests/src/ut_tdm_vblank.cpp index b8701ab..b2cacdc 100644 --- a/utests/src/ut_tdm_vblank.cpp +++ b/utests/src/ut_tdm_vblank.cpp @@ -1123,6 +1123,8 @@ void *UtWaitVblankThreadHndl(void *ptr) vblankWait->utWaitVblankThreadHndlResult = 0; else vblankWait->utWaitVblankThreadHndlResult = 0; + + return NULL; } TEST_F(TDMVblankWait, VblankWaitFailInOtherThread) @@ -1792,6 +1794,8 @@ void *UtWaitVblankSeqThreadHndl(void *ptr) vblankWait->utWaitVblankSeqThreadHndlResult = 0; else vblankWait->utWaitVblankSeqThreadHndlResult = 0; + + return NULL; } TEST_F(TDMVblankWait, VblankWaitSeqFailInOtherThread) -- 2.7.4 From e122c6407b7529eb49625053e877080bed168f17 Mon Sep 17 00:00:00 2001 From: Konstantin Drabeniuk Date: Fri, 17 Nov 2017 12:56:10 +0200 Subject: [PATCH 04/16] turn on the utests bulding and fix svace issues Change-Id: I1c8288cb962725462cc71b6621740dc81075274d Signed-off-by: Konstantin Drabeniuk --- packaging/libtdm.spec | 2 +- utests/src/ut_tdm_layer.cpp | 9 ++++++--- utests/src/ut_tdm_pp.cpp | 2 +- utests/src/ut_tdm_vblank.cpp | 8 ++++---- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/packaging/libtdm.spec b/packaging/libtdm.spec index 80787c9..6e68d87 100644 --- a/packaging/libtdm.spec +++ b/packaging/libtdm.spec @@ -1,4 +1,4 @@ -%define UTEST_PACKAGE 0 +%define UTEST_PACKAGE 1 Name: libtdm Version: 1.8.3 diff --git a/utests/src/ut_tdm_layer.cpp b/utests/src/ut_tdm_layer.cpp index 0d629f6..ae6855d 100644 --- a/utests/src/ut_tdm_layer.cpp +++ b/utests/src/ut_tdm_layer.cpp @@ -87,11 +87,10 @@ protected: tbm_fd = tbm_drm_helper_get_fd(); ASSERT_TRUE(tdm_display_get_output_count(dpy, &output_count) == TDM_ERROR_NONE); - tdm_layer_output_idx = (int *) calloc(output_count, sizeof(int)); - ASSERT_FALSE(NULL == tdm_layer_output_idx); - preferred_mode_array = (const tdm_output_mode **)calloc(output_count, sizeof(tdm_output_mode *)); ASSERT_FALSE(NULL == preferred_mode_array); + if (!preferred_mode_array) + return; for (int i = 0; i < output_count; i++) { tdm_output *output = tdm_display_get_output(dpy, i, &error); @@ -132,6 +131,10 @@ protected: ASSERT_FALSE(NULL == tdm_layer_array); + tdm_layer_output_idx = (int *) realloc(tdm_layer_output_idx, + (layer_count + temp_layer_count)*sizeof(int)); + ASSERT_FALSE(NULL == tdm_layer_output_idx); + for (int k = layer_count; k < (layer_count + temp_layer_count); k++) { tdm_layer_array[k] = tdm_output_get_layer(output, k, &error); tdm_layer_output_idx[k] = i; diff --git a/utests/src/ut_tdm_pp.cpp b/utests/src/ut_tdm_pp.cpp index 2ff78c9..3e59f3c 100644 --- a/utests/src/ut_tdm_pp.cpp +++ b/utests/src/ut_tdm_pp.cpp @@ -409,7 +409,7 @@ void UtPpDoneHandler(tdm_pp *pp, tbm_surface_h src, tbm_surface_h dst, void *user_data) { TDMPPCommit *pp_commit = (TDMPPCommit *)user_data; - bool src_valid, dst_valid; + bool src_valid = false, dst_valid = false; if (!pp_commit) return; diff --git a/utests/src/ut_tdm_vblank.cpp b/utests/src/ut_tdm_vblank.cpp index b2cacdc..8f61790 100644 --- a/utests/src/ut_tdm_vblank.cpp +++ b/utests/src/ut_tdm_vblank.cpp @@ -1122,14 +1122,14 @@ void *UtWaitVblankThreadHndl(void *ptr) if (error != TDM_ERROR_NONE) vblankWait->utWaitVblankThreadHndlResult = 0; else - vblankWait->utWaitVblankThreadHndlResult = 0; + vblankWait->utWaitVblankThreadHndlResult = 1; return NULL; } TEST_F(TDMVblankWait, VblankWaitFailInOtherThread) { - pthread_t thread; + pthread_t thread = 0; SKIP_FLAG(has_output); @@ -1793,14 +1793,14 @@ void *UtWaitVblankSeqThreadHndl(void *ptr) if (error != TDM_ERROR_NONE) vblankWait->utWaitVblankSeqThreadHndlResult = 0; else - vblankWait->utWaitVblankSeqThreadHndlResult = 0; + vblankWait->utWaitVblankSeqThreadHndlResult = 1; return NULL; } TEST_F(TDMVblankWait, VblankWaitSeqFailInOtherThread) { - pthread_t thread; + pthread_t thread = 0; SKIP_FLAG(has_output); -- 2.7.4 From d150d2a755709472e4e4f60613ef14ed06589fbd Mon Sep 17 00:00:00 2001 From: Roman Marchenko Date: Thu, 16 Nov 2017 16:16:56 +0200 Subject: [PATCH 05/16] utest: Add 37 tests cases for tdm_hwc_window Change-Id: I292f3384828ae428e79cb3081cbcf23a709fbb83 Signed-off-by: Roman Marchenko --- utests/Makefile.am | 1 + utests/src/ut_tdm_hwc_window.cpp | 738 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 739 insertions(+) create mode 100644 utests/src/ut_tdm_hwc_window.cpp diff --git a/utests/Makefile.am b/utests/Makefile.am index 6317645..710e3e9 100644 --- a/utests/Makefile.am +++ b/utests/Makefile.am @@ -6,6 +6,7 @@ tdm_utests_SOURCES = \ src/ut_tdm_pp.cpp \ src/ut_tdm_capture.cpp \ src/ut_tdm_output.cpp \ + src/ut_tdm_hwc_window.cpp \ src/ut_tdm_layer.cpp \ src/ut_tdm_vblank.cpp diff --git a/utests/src/ut_tdm_hwc_window.cpp b/utests/src/ut_tdm_hwc_window.cpp new file mode 100644 index 0000000..dd1d7a5 --- /dev/null +++ b/utests/src/ut_tdm_hwc_window.cpp @@ -0,0 +1,738 @@ +/************************************************************************** + * + * Copyright 2016 Samsung Electronics co., Ltd. All Rights Reserved. + * + * Contact: Konstantin Drabeniuk + * Contact: Andrii Sokolenko + * Contact: Roman Marchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * +**************************************************************************/ + +#include "gtest/gtest.h" +#include "ut_common.h" +#include "stdint.h" + +extern "C" { +#include "tdm.h" +#include "tbm_bufmgr.h" +#include "tbm_drm_helper.h" +} + +class TDMOutputHwc : public ::testing::Test { +protected: + tdm_display *dpy = NULL; + tbm_bufmgr tbm_bufmgr = NULL; + int master_fd = -42; + /*list of connected outputs*/ + int output_count = 0; + const tdm_output_mode **preferred_mode_array = NULL; + tdm_output **outputs; + tdm_error error ; + virtual void SetEnv() + { + setenv("TDM_DEBUG_MODULE", "all", 1); + setenv("TDM_DEBUG", "1", 1); + setenv("TDM_THREAD", "0", 1); + setenv("TDM_COMMIT_PER_VBLANK", "1", 1); + setenv("TDM_DLOG", "1", 1); + setenv("TDM_HWC", "1", 1); + setenv("XDG_RUNTIME_DIR", ".", 1); + setenv("TBM_DLOG", "1", 1); + setenv("TBM_DISPLAY_SERVER", "1", 1); + } + + void UnsetEnv() + { + unsetenv("TDM_DEBUG_MODULE"); + unsetenv("TDM_DEBUG"); + unsetenv("TDM_THREAD"); + unsetenv("TDM_COMMIT_PER_VBLANK"); + unsetenv("TDM_DLOG"); + unsetenv("TDM_HWC"); + unsetenv("XDG_RUNTIME_DIR"); + unsetenv("TBM_DLOG"); + unsetenv("TBM_DISPLAY_SERVER"); + } + + int IsHwcEnable(int i) + { + tdm_output_capability capabilities = (tdm_output_capability)0; + tdm_output_get_capabilities(outputs[i], &capabilities); + return capabilities & TDM_OUTPUT_CAPABILITY_HWC; + } + + tbm_surface_h CreateBufferForOutput(int i) + { + int w = preferred_mode_array[i]->hdisplay; + int h = preferred_mode_array[i]->vdisplay; + return tbm_surface_internal_create_with_flags(w, h, TBM_FORMAT_ARGB8888, TBM_BO_SCANOUT); + } + + void SetUp(void) + { + const tdm_output_mode *preferred_mode = NULL; + tdm_error error = TDM_ERROR_NONE; + int all_output_count = 0; + + SetEnv(); + + tbm_bufmgr = tbm_bufmgr_init(-1); + ASSERT_FALSE(tbm_bufmgr == NULL); + + dpy = tdm_display_init(&error); + ASSERT_TRUE(error == TDM_ERROR_NONE); + ASSERT_FALSE(dpy == NULL); + + master_fd = tbm_drm_helper_get_master_fd(); + ASSERT_TRUE(tdm_display_get_output_count(dpy, &all_output_count) == TDM_ERROR_NONE); + + outputs = (tdm_output **)calloc(all_output_count, sizeof(tdm_output *)); + ASSERT_FALSE(NULL == outputs); + + preferred_mode_array = (const tdm_output_mode **)calloc(all_output_count, sizeof(tdm_output_mode *)); + ASSERT_FALSE(NULL == preferred_mode_array); + + output_count = 0; + + for (int i = 0; i < all_output_count; i++) { + tdm_output *output = tdm_display_get_output(dpy, i, &error); + int output_modes_cnt = 0; + const tdm_output_mode *output_modes; + + if (TDM_ERROR_NONE != error || NULL == output) + continue; + + tdm_output_conn_status status = TDM_OUTPUT_CONN_STATUS_DISCONNECTED; + if (TDM_ERROR_NONE != tdm_output_get_conn_status(output, &status)) + continue; + + if (status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) + continue; + + error = tdm_output_get_available_modes(output, &output_modes, &output_modes_cnt); + if (TDM_ERROR_NONE != error) + continue; + if (output_modes_cnt <= 0) { + continue; + } + + for(int j = 0; j < output_modes_cnt; j++) + if(output_modes[j].type & TDM_OUTPUT_MODE_TYPE_PREFERRED) + preferred_mode = &output_modes[j]; + + if (!preferred_mode) + continue; + + if (preferred_mode_array) + preferred_mode_array[output_count] = preferred_mode; + if (outputs) + outputs[output_count] = output; + output_count++; + + error = tdm_output_set_mode(output, preferred_mode); + ASSERT_EQ(TDM_ERROR_NONE, error); + } + } + void TearDown(void) + { + tdm_display_deinit(dpy); + dpy = NULL; + tbm_bufmgr_deinit(tbm_bufmgr); + tbm_bufmgr = NULL; + if (outputs) + free(outputs); + if (preferred_mode_array) + free(preferred_mode_array); + if (master_fd > -1) { + int temp_master_fd = tbm_drm_helper_get_master_fd(); + EXPECT_EQ(temp_master_fd, -1) << "Fatal Error. Can't deinit tdm/tbm" << std::endl; + if (temp_master_fd > -1) + exit(1); + close(master_fd); + } + + UnsetEnv(); + } + +}; + +#define HWC_WIN_NUM 5 +class TDMHwcWindow : public TDMOutputHwc { +protected: + tdm_hwc_window **hwc_wins; + int hwc_count; + + void SetUp(void) + { + hwc_count = 0; + + TDMOutputHwc::SetUp(); + hwc_wins = (tdm_hwc_window **)calloc(output_count * HWC_WIN_NUM, sizeof(tdm_hwc_window *)); + + //create HWC_WIN_NUM hwc_windows for each outputs + for (int i = 0; i < output_count; i++) { + if (IsHwcEnable(i)) { + for (int j = 0; j < HWC_WIN_NUM; j++) { + tdm_hwc_window * hw = tdm_output_hwc_create_window(outputs[i], &error); + ASSERT_EQ(TDM_ERROR_NONE, error); + hwc_wins[hwc_count++] = hw; + } + } + } + } + + void TearDown(void) + { + for (int i = 0; i < hwc_count; i++) { + tdm_output_hwc_destroy_window(outputs[0], hwc_wins[i]); + } + TDMOutputHwc::TearDown(); + } + +}; + +/* tdm_hwc_window * tdm_output_hwc_create_window(tdm_output *output, tdm_error *error); */ +TEST_F(TDMOutputHwc, CreateWindowFailNull) +{ + ASSERT_EQ(NULL, tdm_output_hwc_create_window(NULL, &error)); + ASSERT_NE(TDM_ERROR_NONE, error); +} + +TEST_F(TDMOutputHwc, CreateWindowSuccessful) +{ + for (int i = 0; i < output_count; i++) { + if (IsHwcEnable(i)) { + tdm_hwc_window * hw = tdm_output_hwc_create_window(outputs[i], &error); + ASSERT_EQ(TDM_ERROR_NONE, error); + error = tdm_output_hwc_destroy_window(outputs[i], hw); + ASSERT_EQ(TDM_ERROR_NONE, error); + } else { + ASSERT_EQ(NULL, tdm_output_hwc_create_window(outputs[i], &error)); + ASSERT_NE(TDM_ERROR_NONE, error); + } + } +} + + +/* tdm_error tdm_output_hwc_destroy_window(tdm_output *output, tdm_hwc_window *hwc_window); */ +TEST_F(TDMOutputHwc, DestroyWindowFailNull) +{ + for (int i = 0; i < output_count; i++) { + tdm_hwc_window * hw = NULL; + + if (IsHwcEnable(i)) { + hw = tdm_output_hwc_create_window(outputs[i], &error); + ASSERT_EQ(TDM_ERROR_NONE, error); + } + + /* test: output is NULL*/ + error = tdm_output_hwc_destroy_window(NULL, hw); + ASSERT_NE(TDM_ERROR_NONE, error); + + /* test: hw is NULL*/ + error = tdm_output_hwc_destroy_window(outputs[i], NULL); + ASSERT_NE(TDM_ERROR_NONE, error); + } +} + +TEST_F(TDMOutputHwc, DestroyWindowSuccessful) +{ + tdm_hwc_window * hw; + for (int i = 0; i < output_count; i++) { + if (IsHwcEnable(i)) { + hw = tdm_output_hwc_create_window(outputs[i], &error); + ASSERT_EQ(TDM_ERROR_NONE, error); + error = tdm_output_hwc_destroy_window(outputs[i], hw); + ASSERT_EQ(TDM_ERROR_NONE, error); + } + } +} + + +/* tdm_error tdm_output_hwc_set_client_target_buffer(tdm_output *output, + tbm_surface_h target_buffer, tdm_hwc_region damage); */ +TEST_F(TDMOutputHwc, SetClientTargetBufferFailNullOutput) +{ + tdm_hwc_region reg; + tbm_surface_h target_buff = CreateBufferForOutput(0); + error = tdm_output_hwc_set_client_target_buffer(NULL, target_buff, reg); + ASSERT_NE(TDM_ERROR_NONE, error); +} + +TEST_F(TDMOutputHwc, SetClientTargetBufferSuccessfulSetBuff) +{ + tdm_hwc_region damage; + + for (int i = 0; i < output_count; i++) { + tbm_surface_h target_buff = CreateBufferForOutput(i); + ASSERT_NE(NULL, target_buff); + if (IsHwcEnable(i)) { + error = tdm_output_hwc_set_client_target_buffer(outputs[i], target_buff, damage); + tbm_surface_internal_destroy(target_buff); + ASSERT_EQ(TDM_ERROR_NONE, error); + } else { + error = tdm_output_hwc_set_client_target_buffer(outputs[i], target_buff, damage); + tbm_surface_internal_destroy(target_buff); + ASSERT_NE(TDM_ERROR_NONE, error); + } + } +} + +TEST_F(TDMOutputHwc, SetClientTargetBufferSuccessfulResetBuff) +{ + tdm_hwc_region damage; + + for (int i = 0; i < output_count; i++) { + if (IsHwcEnable(i)) { + error = tdm_output_hwc_set_client_target_buffer(outputs[i], NULL, damage); + ASSERT_EQ(TDM_ERROR_NONE, error); + } else { + error = tdm_output_hwc_set_client_target_buffer(outputs[i], NULL, damage); + ASSERT_NE(TDM_ERROR_NONE, error); + } + } +} + +/* tbm_surface_queue_h tdm_output_hwc_get_target_buffer_queue(tdm_output *output, tdm_error *error); */ +TEST_F(TDMOutputHwc, GetTargetBufferQueueFailNullOutput) +{ + tbm_surface_queue_h queue = NULL; + + queue = tdm_output_hwc_get_target_buffer_queue(NULL, &error); + ASSERT_NE(TDM_ERROR_NONE, error); + ASSERT_EQ(NULL, queue); + + queue = tdm_output_hwc_get_target_buffer_queue(NULL, NULL); + ASSERT_EQ(NULL, queue); +} + +TEST_F(TDMOutputHwc, GetTargetBufferQueueSuccessful) +{ + tbm_surface_queue_h queue = NULL; + + for (int i = 0; i < output_count; i++) { + if (IsHwcEnable(i)) { + queue = tdm_output_hwc_get_target_buffer_queue(outputs[i], &error); + tbm_surface_queue_destroy(queue); + ASSERT_EQ(TDM_ERROR_NONE, error); + ASSERT_NE(NULL, queue); + + queue = tdm_output_hwc_get_target_buffer_queue(outputs[i], NULL); + tbm_surface_queue_destroy(queue); + ASSERT_EQ(TDM_ERROR_NONE, error); + ASSERT_NE(NULL, queue); + } else { + queue = tdm_output_hwc_get_target_buffer_queue(outputs[i], &error); + ASSERT_NE(TDM_ERROR_NONE, error); + ASSERT_EQ(NULL, queue); + + queue = tdm_output_hwc_get_target_buffer_queue(outputs[i], NULL); + ASSERT_NE(TDM_ERROR_NONE, error); + ASSERT_EQ(NULL, queue); + } + } +} + +/* tbm_surface_queue_h tdm_hwc_window_get_tbm_buffer_queue(tdm_hwc_window *hwc_window, tdm_error *error); */ +TEST_F(TDMHwcWindow, GetBufferQueueFailNull) +{ + tbm_surface_queue_h queue = NULL; + + queue = tdm_hwc_window_get_tbm_buffer_queue(NULL, &error); + ASSERT_NE(TDM_ERROR_NONE, error); + ASSERT_EQ(NULL, queue); + + queue = tdm_hwc_window_get_tbm_buffer_queue(NULL, NULL); + ASSERT_EQ(NULL, queue); +} + +TEST_F(TDMHwcWindow, GetBufferQueueSuccessful) +{ + tbm_surface_queue_h queue = NULL; + tdm_hwc_window_info info = { 0 }; + + info.src_config.format = TBM_FORMAT_ARGB8888; + info.src_config.size.h = info.src_config.size.v = 256; + info.src_config.pos.h = info.src_config.pos.w = 256; + info.dst_pos.h = info.dst_pos.w = 256; + info.transform = TDM_TRANSFORM_NORMAL; + + for (int i = 0; i < hwc_count; i++) { + error = tdm_hwc_window_set_info(hwc_wins[i], &info); + ASSERT_EQ(TDM_ERROR_NONE, error); + + queue = tdm_hwc_window_get_tbm_buffer_queue(hwc_wins[i], &error); + tbm_surface_queue_destroy(queue); + ASSERT_EQ(TDM_ERROR_NONE, error); + ASSERT_NE(NULL, queue); + + queue = tdm_hwc_window_get_tbm_buffer_queue(hwc_wins[i], NULL); + tbm_surface_queue_destroy(queue); + ASSERT_NE(NULL, queue); + } +} + +/* tdm_error tdm_hwc_window_set_zpos(tdm_hwc_window *hwc_window, uint32_t zpos); */ +TEST_F(TDMHwcWindow, SetZposFailNull) +{ + error = tdm_hwc_window_set_zpos(NULL, 1); + ASSERT_NE(TDM_ERROR_NONE, error); +} + +TEST_F(TDMHwcWindow, SetZposSuccessful) +{ + for (int i = 0; i < hwc_count; i++) { + error = tdm_hwc_window_set_zpos(hwc_wins[i], i); + ASSERT_EQ(TDM_ERROR_NONE, error); + } +} + +/* tdm_error tdm_hwc_window_set_composition_type(tdm_hwc_window *hwc_window, + tdm_hwc_window_composition composition_type); */ +TEST_F(TDMHwcWindow, SetCompositionTypeFailNull) +{ + error = tdm_hwc_window_set_composition_type(NULL, TDM_COMPOSITION_DEVICE); + ASSERT_NE(TDM_ERROR_NONE, error); +} + +TEST_F(TDMHwcWindow, SetCompositionTypeSuccessful) +{ + for (int i = 0; i < hwc_count; i++) { + error = tdm_hwc_window_set_composition_type(hwc_wins[i], TDM_COMPOSITION_DEVICE); + ASSERT_EQ(TDM_ERROR_NONE, error); + error = tdm_hwc_window_set_composition_type(hwc_wins[i], TDM_COMPOSITION_CLIENT); + ASSERT_EQ(TDM_ERROR_NONE, error); + error = tdm_hwc_window_set_composition_type(hwc_wins[i], TDM_COMPOSITION_CURSOR); + ASSERT_EQ(TDM_ERROR_NONE, error); + error = tdm_hwc_window_set_composition_type(hwc_wins[i], TDM_COMPOSITION_VIDEO); + ASSERT_EQ(TDM_ERROR_NONE, error); + } +} + +TEST_F(TDMHwcWindow, SetCompositionTypeFailInvalieCompositionType) +{ + for (int i = 0; i < hwc_count; i++) { + error = tdm_hwc_window_set_composition_type(hwc_wins[i], TDM_COMPOSITION_DEVICE_CANDIDATE); + ASSERT_NE(TDM_ERROR_NONE, error); + error = tdm_hwc_window_set_composition_type(hwc_wins[i], TDM_COMPOSITION_CLIENT_CANDIDATE); + ASSERT_NE(TDM_ERROR_NONE, error); + error = tdm_hwc_window_set_composition_type(hwc_wins[i], tdm_hwc_window_composition(TDM_COMPOSITION_CLIENT+1)); + ASSERT_NE(TDM_ERROR_NONE, error); + } +} + +/* tdm_error tdm_hwc_window_set_buffer_damage(tdm_hwc_window *hwc_window, tdm_hwc_region damage); */ +TEST_F(TDMHwcWindow, SetBufferDamageFailNullHwcWindow) +{ + tdm_hwc_region damage; + error = tdm_hwc_window_set_buffer_damage(NULL, damage); + ASSERT_NE(TDM_ERROR_NONE, error); +} + +TEST_F(TDMHwcWindow, SetBufferDamageFailNullDamageRects) +{ + tdm_hwc_region damage = {.num_rects = 1, .rects = NULL}; + + for (int i = 0; i < hwc_count; i++) { + error = tdm_hwc_window_set_buffer_damage(hwc_wins[i], damage); + ASSERT_NE(TDM_ERROR_NONE, error); + } +} + + +TEST_F(TDMHwcWindow, SetBufferDamageSuccessful) +{ + tdm_pos const rects[1] = {0}; + tdm_hwc_region damage = {.num_rects = 1, .rects = rects}; + + for (int i = 0; i < hwc_count; i++) { + error = tdm_hwc_window_set_buffer_damage(hwc_wins[i], damage); + ASSERT_EQ(TDM_ERROR_NONE, error); + } +} + + +/* tdm_error tdm_hwc_window_set_info(tdm_hwc_window *hwc_window, tdm_hwc_window_info *info); */ +TEST_F(TDMHwcWindow, SetInfoFailNull) +{ + tdm_hwc_window_info info = { 0 }; + + error = tdm_hwc_window_set_info(NULL, &info); + ASSERT_NE(TDM_ERROR_NONE, error); + + if (hwc_count > 0) { + error = tdm_hwc_window_set_info(hwc_wins[0], NULL); + ASSERT_NE(TDM_ERROR_NONE, error); + } +} +TEST_F(TDMHwcWindow, SetInfoSuccessful) +{ + tdm_hwc_window_info info = { 0 }; + + for (int i = 0; i < hwc_count; i++) { + error = tdm_hwc_window_set_info(hwc_wins[i], &info); + ASSERT_EQ(TDM_ERROR_NONE, error); + } +} + + +/* tdm_error tdm_hwc_window_set_buffer(tdm_hwc_window *hwc_window, tbm_surface_h buffer); */ +TEST_F(TDMHwcWindow, SetBufferFailNull) +{ + error = tdm_hwc_window_set_buffer(NULL, NULL); + ASSERT_NE(TDM_ERROR_NONE, error); +} + +TEST_F(TDMHwcWindow, SetBufferSuccessful) +{ + for (int i = 0; i < hwc_count; i++) { + + tbm_surface_h buff = tbm_surface_create(256, 256, TBM_FORMAT_ARGB8888); + + /* test: set*/ + error = tdm_hwc_window_set_buffer(hwc_wins[i], buff); + tbm_surface_destroy(buff); + ASSERT_EQ(TDM_ERROR_NONE, error); + + /* test: reset*/ + error = tdm_hwc_window_set_buffer(hwc_wins[i], NULL); + ASSERT_EQ(TDM_ERROR_NONE, error); + } +} + +/* tdm_error tdm_hwc_window_set_flags(tdm_hwc_window *hwc_window, tdm_hwc_window_flag flags); */ +TEST_F(TDMHwcWindow, SetFlagsFailNull) +{ + tdm_hwc_window_flag flag = (tdm_hwc_window_flag)0; + + error = tdm_hwc_window_set_flags(NULL, flag); + ASSERT_NE(TDM_ERROR_NONE, error); +} + +TEST_F(TDMHwcWindow, SetFlagsSuccessful) +{ + tdm_hwc_window_flag flag = (tdm_hwc_window_flag)0; + + for (int i = 0; i < hwc_count; i++) { + + error = tdm_hwc_window_set_flags(hwc_wins[i], flag); + ASSERT_EQ(TDM_ERROR_NONE, error); + } +} + +/* tdm_error tdm_hwc_window_unset_flags(tdm_hwc_window *hwc_window, tdm_hwc_window_flag flags); */ +TEST_F(TDMHwcWindow, UnsetFlagsFailNull) +{ + tdm_hwc_window_flag flag = (tdm_hwc_window_flag)0; + + error = tdm_hwc_window_unset_flags(NULL, flag); + ASSERT_NE(TDM_ERROR_NONE, error); +} + +TEST_F(TDMHwcWindow, UnsetFlagsSuccessful) +{ + tdm_hwc_window_flag flag = (tdm_hwc_window_flag)0; + + for (int i = 0; i < hwc_count; i++) { + + error = tdm_hwc_window_unset_flags(hwc_wins[i], flag); + ASSERT_EQ(TDM_ERROR_NONE, error); + } +} + +/* tdm_error tdm_hwc_window_video_get_capability(tdm_hwc_window *hwc_window, + tdm_hwc_window_video_capability *video_capability); */ +TEST_F(TDMHwcWindow, VideoGetCapabilityFailNull) +{ + tdm_hwc_window_video_capability video_capability; + + error = tdm_hwc_window_video_get_capability(NULL, &video_capability); + ASSERT_NE(TDM_ERROR_NONE, error); + + if (hwc_count > 0) { + error = tdm_hwc_window_video_get_capability(hwc_wins[0], NULL); + ASSERT_NE(TDM_ERROR_NONE, error); + } + +} + +TEST_F(TDMHwcWindow, VideoGetCapabilitySuccessful) +{ + tdm_hwc_window_video_capability video_capability; + + for (int i = 0; i < hwc_count; i++) { + /* hwc_window with TDM_COMPOSITION_CLIENT dosn't support tdm_hwc_window_video_get_capability()*/ + error = tdm_hwc_window_video_get_capability(hwc_wins[i], &video_capability); + ASSERT_NE(TDM_ERROR_NONE, error); + + /*TODO:: check video capability for TDM_COMPOSITION_VIDEO*/ + } +} + + +/* tdm_error tdm_hwc_window_video_get_supported_format(tdm_hwc_window *hwc_window, const tbm_format **formats, int *count); */ +TEST_F(TDMHwcWindow, VideoGetSupportedFormatFailNull) +{ + const tbm_format *formats; + int count; + + error = tdm_hwc_window_video_get_supported_format(NULL, &formats, &count); + ASSERT_NE(TDM_ERROR_NONE, error); + + if (hwc_count > 0) { + error = tdm_hwc_window_video_get_supported_format(hwc_wins[0], NULL, &count); + error = tdm_hwc_window_video_get_supported_format(hwc_wins[0], &formats, NULL); + } +} + +TEST_F(TDMHwcWindow, VideoGetSupportedFormatSuccessful) +{ + const tbm_format *formats; + int count; + + for (int i = 0; i < hwc_count; i++) { + /* hwc_window with TDM_COMPOSITION_CLIENT dosn't support tdm_hwc_window_video_get_supported_format()*/ + error = tdm_hwc_window_set_composition_type(hwc_wins[i], TDM_COMPOSITION_CLIENT); + ASSERT_EQ(TDM_ERROR_NONE, error); + error = tdm_hwc_window_video_get_supported_format(hwc_wins[i], &formats, &count); + ASSERT_NE(TDM_ERROR_NONE, error); + + /*TODO:: check format for TDM_COMPOSITION_VIDEO*/ + } +} + +/* tdm_error tdm_output_hwc_validate(tdm_output *output, uint32_t *num_types); */ +TEST_F(TDMOutputHwc, ValidateFailNull) +{ + uint32_t num_types; + error = tdm_output_hwc_validate(NULL, &num_types); + ASSERT_NE(TDM_ERROR_NONE, error); + + if (outputs[0]) { + error = tdm_output_hwc_validate(outputs[0], NULL); + ASSERT_NE(TDM_ERROR_NONE, error); + } +} + +TEST_F(TDMOutputHwc, ValidateSuccessful) +{ + uint32_t num_types; + for (int i = 0; i < output_count; i++) { + if (IsHwcEnable(i)) { + error = tdm_output_hwc_validate(outputs[i], &num_types); + ASSERT_EQ(TDM_ERROR_NONE, error); + } else { + error = tdm_output_hwc_validate(outputs[i], &num_types); + ASSERT_NE(TDM_ERROR_NONE, error); + } + } +} + +/* tdm_error tdm_output_hwc_get_changed_composition_types(tdm_output *output, + uint32_t *num_elements, tdm_hwc_window **hwc_window, + tdm_hwc_window_composition *composition_types); */ + +/* tdm_error tdm_output_hwc_accept_changes(tdm_output *output); */ +TEST_F(TDMOutputHwc, GetChangedCompositionTypesFailNull) +{ + uint32_t num_elements; + + error = tdm_output_hwc_get_changed_composition_types(NULL, &num_elements, NULL, NULL); + ASSERT_NE(TDM_ERROR_NONE, error); + + if (outputs[0]) { + error = tdm_output_hwc_get_changed_composition_types(outputs[0], NULL, NULL, NULL); + ASSERT_NE(TDM_ERROR_NONE, error); + } +} + +TEST_F(TDMHwcWindow, GetChangedCompositionTypesSuccessful) +{ + uint32_t validate_num; + uint32_t get_num = 0; + + tdm_hwc_window_composition *composition_types; + tdm_hwc_window **hwc_wnds; + + for (int i = 0; i < hwc_count; i++) { + error = tdm_hwc_window_set_composition_type(hwc_wins[i], TDM_COMPOSITION_DEVICE); + ASSERT_EQ(TDM_ERROR_NONE, error); + } + + + for (int i = 0; i < output_count; i++) { + if (IsHwcEnable(i)) { + error = tdm_output_hwc_validate(outputs[i], &validate_num); + ASSERT_EQ(TDM_ERROR_NONE, error); + + error = tdm_output_hwc_get_changed_composition_types(outputs[i], &get_num, NULL, NULL); + ASSERT_EQ(TDM_ERROR_NONE, error); + + ASSERT_TRUE(get_num == validate_num); + hwc_wnds = (tdm_hwc_window **)calloc(get_num, sizeof(tdm_hwc_window *)); + composition_types = (tdm_hwc_window_composition *)calloc(get_num, sizeof(tdm_hwc_window_composition)); + + error = tdm_output_hwc_get_changed_composition_types(outputs[i], &get_num, hwc_wnds, composition_types); + + free(hwc_wnds); + free(composition_types); + ASSERT_EQ(TDM_ERROR_NONE, error); + } else { + error = tdm_output_hwc_get_changed_composition_types(outputs[i], &get_num, NULL, NULL); + ASSERT_NE(TDM_ERROR_NONE, error); + } + } +} + +static void need_validate_handler(tdm_output *output) +{ +} +/* tdm_error tdm_output_hwc_set_need_validate_handler(tdm_output *output, + tdm_output_need_validate_handler hndl); */ +TEST_F(TDMOutputHwc, SetNeedValidateHandlerFailNull) +{ + error = tdm_output_hwc_set_need_validate_handler(NULL, &need_validate_handler); + ASSERT_NE(TDM_ERROR_NONE, error); + + error = tdm_output_hwc_set_need_validate_handler(outputs[0], NULL); + ASSERT_NE(TDM_ERROR_NONE, error); + +} +TEST_F(TDMOutputHwc, SetNeedValidateHandlerSuccessful) +{ + for (int i = 0; i < output_count; i++) { + if (IsHwcEnable(i)) { + /* test: first set*/ + error = tdm_output_hwc_set_need_validate_handler(outputs[i], &need_validate_handler); + ASSERT_EQ(TDM_ERROR_NONE, error); + + /* test: second isn't allowed*/ + error = tdm_output_hwc_set_need_validate_handler(outputs[i], &need_validate_handler); + ASSERT_NE(TDM_ERROR_NONE, error); + } else { + error = tdm_output_hwc_set_need_validate_handler(outputs[i], &need_validate_handler); + ASSERT_NE(TDM_ERROR_NONE, error); + } + } +} + -- 2.7.4 From 963c90da91b0047484cb83243d2f543c0bd9ee0b Mon Sep 17 00:00:00 2001 From: Boram Park Date: Tue, 21 Nov 2017 16:31:35 +0900 Subject: [PATCH 06/16] add stamp to vblank objects To distinguish among vblank objects Change-Id: Id419092118542442fa719824204e495c48e32d40 --- client/tdm_client.c | 22 ++++++++++++++++++++++ protocol/tdm.xml | 4 ++++ src/tdm_private.h | 2 ++ src/tdm_server.c | 4 ++++ src/tdm_vblank.c | 10 ++++++++++ 5 files changed, 42 insertions(+) diff --git a/client/tdm_client.c b/client/tdm_client.c index d80100d..cd74513 100644 --- a/client/tdm_client.c +++ b/client/tdm_client.c @@ -94,6 +94,7 @@ struct _tdm_private_client_vblank { unsigned int enable_fake; unsigned int started; + unsigned int stamp; double last_time; @@ -123,6 +124,16 @@ typedef struct _tdm_client_wait_info { } tdm_client_wait_info; static void +_tdm_client_vblank_cb_stamp(void *data, struct wl_tdm_vblank *wl_tdm_vblank, uint32_t stamp) +{ + tdm_private_client_vblank *private_vblank = data; + + TDM_RETURN_IF_FAIL(private_vblank != NULL); + + private_vblank->stamp = stamp; +} + +static void _tdm_client_vblank_cb_done(void *data, struct wl_tdm_vblank *wl_tdm_vblank, uint32_t req_id, uint32_t sequence, uint32_t tv_sec, uint32_t tv_usec, uint32_t error) @@ -159,6 +170,7 @@ _tdm_client_vblank_cb_done(void *data, struct wl_tdm_vblank *wl_tdm_vblank, } static const struct wl_tdm_vblank_listener tdm_client_vblank_listener = { + _tdm_client_vblank_cb_stamp, _tdm_client_vblank_cb_done, }; @@ -649,6 +661,7 @@ tdm_client_output_get_dpms(tdm_client_output *output, tdm_output_dpms *dpms) tdm_client_vblank* tdm_client_output_create_vblank(tdm_client_output *output, tdm_error *error) { + tdm_private_client *private_client; tdm_private_client_output *private_output; tdm_private_client_vblank *private_vblank; @@ -663,6 +676,14 @@ tdm_client_output_create_vblank(tdm_client_output *output, tdm_error *error) } private_output = (tdm_private_client_output*)output; + private_client = private_output->private_client; + + if (!private_client) { + TDM_ERR("'!private_client' failed"); + if (error) + *error = TDM_ERROR_INVALID_PARAMETER; + return NULL; + } private_vblank = calloc(1, sizeof *private_vblank); if (!private_vblank) { @@ -693,6 +714,7 @@ tdm_client_output_create_vblank(tdm_client_output *output, tdm_error *error) wl_tdm_vblank_add_listener(private_vblank->vblank, &tdm_client_vblank_listener, private_vblank); + wl_display_roundtrip(private_client->display); return (tdm_client_vblank*)private_vblank; } diff --git a/protocol/tdm.xml b/protocol/tdm.xml index 22328ac..24d3a7b 100644 --- a/protocol/tdm.xml +++ b/protocol/tdm.xml @@ -74,6 +74,10 @@ + + + + diff --git a/src/tdm_private.h b/src/tdm_private.h index 2a927db..6853bfb 100644 --- a/src/tdm_private.h +++ b/src/tdm_private.h @@ -491,6 +491,8 @@ tdm_error tdm_vblank_set_add_front(tdm_vblank *vblank, unsigned int add_front); tdm_error tdm_vblank_set_resource(tdm_vblank *vblank, struct wl_resource *resource); +double +tdm_vblank_get_stamp(tdm_vblank *vblank); tdm_error tdm_vblank_set_client_vblank_fps(unsigned int pid, const char *name, unsigned int fps); void diff --git a/src/tdm_server.c b/src/tdm_server.c index 3ade1e5..4da079d 100644 --- a/src/tdm_server.c +++ b/src/tdm_server.c @@ -72,6 +72,7 @@ typedef struct _tdm_server_vblank_info { struct wl_resource *resource; tdm_vblank *vblank; + unsigned int stamp; } tdm_server_vblank_info; typedef struct _tdm_server_wait_info { @@ -433,12 +434,15 @@ _tdm_server_output_cb_create_vblank(struct wl_client *client, struct wl_resource vblank_info->output_info = output_info; vblank_info->resource = vblank_resource; vblank_info->vblank = vblank; + vblank_info->stamp = (unsigned int)tdm_vblank_get_stamp(vblank); tdm_vblank_set_resource(vblank, vblank_resource); wl_resource_set_implementation(vblank_resource, &tdm_vblank_implementation, vblank_info, destroy_vblank_callback); + wl_tdm_vblank_send_stamp(vblank_info->resource, vblank_info->stamp); + return; } diff --git a/src/tdm_vblank.c b/src/tdm_vblank.c index b2ccb95..6861ec8 100644 --- a/src/tdm_vblank.c +++ b/src/tdm_vblank.c @@ -1230,6 +1230,16 @@ tdm_vblank_set_resource(tdm_vblank *vblank, struct wl_resource *resource) return TDM_ERROR_NONE; } +INTERN double +tdm_vblank_get_stamp(tdm_vblank *vblank) +{ + tdm_private_vblank *private_vblank = vblank; + + TDM_RETURN_VAL_IF_FAIL(private_vblank != NULL, TDM_ERROR_INVALID_PARAMETER); + + return private_vblank->stamp; +} + INTERN void tdm_vblank_get_vblank_list_information(tdm_display *dpy, char *reply, int *len) { -- 2.7.4 From 65095f1761f817e974be2594e10c5b1c57ae81fc Mon Sep 17 00:00:00 2001 From: Boram Park Date: Tue, 21 Nov 2017 16:35:02 +0900 Subject: [PATCH 07/16] remove unused event Change-Id: Ia88e9468eb8ca36f0c6902d76d1eb9d9424d7cd5 --- protocol/tdm.xml | 2 -- 1 file changed, 2 deletions(-) diff --git a/protocol/tdm.xml b/protocol/tdm.xml index 24d3a7b..0947115 100644 --- a/protocol/tdm.xml +++ b/protocol/tdm.xml @@ -86,8 +86,6 @@ - - -- 2.7.4 From ceee662cf0bdb1f8452ece299dbfe8bba5fe035b Mon Sep 17 00:00:00 2001 From: Boram Park Date: Tue, 21 Nov 2017 16:56:58 +0900 Subject: [PATCH 08/16] correct ttrace debug information for vblank Change-Id: Ie465ef620bc2f91b23c85a7321e7ba39de777c02 --- client/tdm_client.c | 17 +++++++++++------ src/tdm.c | 11 +++++------ src/tdm_private.h | 16 ++++++++++------ src/tdm_server.c | 16 ++++++++++------ src/tdm_vblank.c | 8 ++++++++ 5 files changed, 44 insertions(+), 24 deletions(-) diff --git a/client/tdm_client.c b/client/tdm_client.c index cd74513..267854b 100644 --- a/client/tdm_client.c +++ b/client/tdm_client.c @@ -96,6 +96,7 @@ struct _tdm_private_client_vblank { unsigned int started; unsigned int stamp; + double req_time; double last_time; struct list_head link; @@ -148,12 +149,12 @@ _tdm_client_vblank_cb_done(void *data, struct wl_tdm_vblank *wl_tdm_vblank, TDM_DBG("vblank(%p) req_id(%u) sequence(%u) time(%.6f)", private_vblank, req_id, sequence, TDM_TIME(tv_sec, tv_usec)); - TDM_TRACE_COUNT(ClientDoneVBlank, req_id); - LIST_FOR_EACH_ENTRY_SAFE(w, ww, &private_vblank->wait_list, link) { if (w->req_id != req_id) continue; + TDM_TRACE_ASYNC_END((int)w->req_time, "TDM_Client_Vblank:%u", private_vblank->stamp); + if (w->req_time >= private_vblank->last_time) TDM_WRN("'req(%.6f) < last(%.6f)' failed", w->req_time, private_vblank->last_time); @@ -888,10 +889,12 @@ tdm_client_vblank_wait(tdm_client_vblank *vblank, unsigned int interval, tdm_cli wl_tdm_vblank_wait_vblank(private_vblank->vblank, interval, w->req_id, req_sec, req_usec); - TDM_TRACE_COUNT(ClientWaitVBlank, w->req_id); + TDM_TRACE_ASYNC_BEGIN((int)w->req_time, "TDM_Client_Vblank:%u", private_vblank->stamp); TDM_DBG("vblank(%p) interval(%u) req_id(%d) req(%.6f)", - vblank, interval, w->req_id, TDM_TIME(req_sec, req_usec)); + vblank, interval, w->req_id, w->req_time); + + private_vblank->req_time = w->req_time; if (private_vblank->last_time >= w->req_time) TDM_ERR("'last(%.6f) < req(%.6f)' failed", private_vblank->last_time, w->req_time); @@ -970,10 +973,12 @@ tdm_client_vblank_wait_seq(tdm_client_vblank *vblank, unsigned int sequence, wl_tdm_vblank_wait_vblank_seq(private_vblank->vblank, sequence, w->req_id, req_sec, req_usec); - TDM_TRACE_COUNT(ClientWaitVBlank, w->req_id); + TDM_TRACE_ASYNC_BEGIN((int)w->req_time, "TDM_Client_Vblank:%u", private_vblank->stamp); TDM_DBG("vblank(%p) sequence(%u) req_id(%d) req(%.6f)", - vblank, sequence, w->req_id, TDM_TIME(req_sec, req_usec)); + vblank, sequence, w->req_id, w->req_time); + + private_vblank->req_time = w->req_time; if (private_vblank->last_time >= w->req_time) TDM_ERR("'last(%.6f) < req(%.6f)' failed", private_vblank->last_time, w->req_time); diff --git a/src/tdm.c b/src/tdm.c index 2246fc4..53732ac 100644 --- a/src/tdm.c +++ b/src/tdm.c @@ -788,8 +788,8 @@ _tdm_display_load_module_with_file(tdm_private_display *private_display, }; stamp = tdm_helper_get_time(); - TDM_TRACE_BEGIN(Load_Backend); + TDM_TRACE_BEGIN("TDM_Load_Backend"); module = dlopen(path, RTLD_LAZY); if (!module) { TDM_ERR("failed to load module: %s(%s)", dlerror(), file); @@ -804,6 +804,7 @@ _tdm_display_load_module_with_file(tdm_private_display *private_display, TDM_TRACE_END(); goto failed_load; } + TDM_TRACE_END(); TDM_DBG("dlopen, dlsym time: %.3f ms", (tdm_helper_get_time() - stamp) * 1000.0); @@ -815,10 +816,8 @@ _tdm_display_load_module_with_file(tdm_private_display *private_display, if (ret != TDM_ERROR_NONE) goto failed_load; - TDM_TRACE_END(); - /* We don't care if backend_data is NULL or not. It's up to backend. */ - TDM_TRACE_BEGIN(Init_Backend); + TDM_TRACE_BEGIN("TDM_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); @@ -989,7 +988,7 @@ tdm_display_init(tdm_error *error) } #endif - TDM_TRACE_BEGIN(Update_Display); + TDM_TRACE_BEGIN("TDM_Update_Display"); ret = _tdm_display_update_internal(private_display, 0); TDM_TRACE_END(); if (ret != TDM_ERROR_NONE) @@ -1289,7 +1288,7 @@ _tdm_display_ttrace_vblank_cb(tdm_vblank *vblank, tdm_error error, unsigned int { tdm_error ret = TDM_ERROR_NONE; - TDM_TRACE_MARK(VBlank); + TDM_TRACE_MARK("TDM_DISPLAY_TTRACE_VBlank"); ret = tdm_vblank_wait(vblank, 0, 0, 1, _tdm_display_ttrace_vblank_cb, NULL); TDM_RETURN_IF_FAIL(ret == TDM_ERROR_NONE); diff --git a/src/tdm_private.h b/src/tdm_private.h index 6853bfb..92bb4a1 100644 --- a/src/tdm_private.h +++ b/src/tdm_private.h @@ -91,15 +91,19 @@ extern int tdm_debug_dump; #ifdef HAVE_TTRACE #include -#define TDM_TRACE_BEGIN(NAME) traceBegin(TTRACE_TAG_GRAPHICS, "TDM:"#NAME) +#define TDM_TRACE_BEGIN(fmt, ...) traceBegin(TTRACE_TAG_GRAPHICS, fmt, ##__VA_ARGS__) #define TDM_TRACE_END() traceEnd(TTRACE_TAG_GRAPHICS) -#define TDM_TRACE_COUNT(NAME, COUNT) traceCounter(TTRACE_TAG_GRAPHICS, COUNT, "TDM:"#NAME) -#define TDM_TRACE_MARK(NAME) traceMark(TTRACE_TAG_GRAPHICS, "TDM:"#NAME) +#define TDM_TRACE_ASYNC_BEGIN(key, name,...) traceAsyncBegin(TTRACE_TAG_GRAPHICS, key, name, ##__VA_ARGS__) +#define TDM_TRACE_ASYNC_END(key, name,...) traceAsyncEnd(TTRACE_TAG_GRAPHICS, key, name, ##__VA_ARGS__) +#define TDM_TRACE_COUNT(count, fmt, ...) traceCounter(TTRACE_TAG_GRAPHICS, count, fmt, ##__VA_ARGS__) +#define TDM_TRACE_MARK(fmt, ...) traceMark(TTRACE_TAG_GRAPHICS, fmt, ##__VA_ARGS__) #else -#define TDM_TRACE_BEGIN(NAME) +#define TDM_TRACE_BEGIN(fmt, ...) #define TDM_TRACE_END() -#define TDM_TRACE_COUNT(NAME, COUNT) -#define TDM_TRACE_MARK(NAME) +#define TDM_TRACE_ASYNC_BEGIN(key, name,...) +#define TDM_TRACE_ASYNC_END(key, name,...) +#define TDM_TRACE_COUNT(count, fmt, ...) +#define TDM_TRACE_MARK(fmt, ...) #endif typedef enum { diff --git a/src/tdm_server.c b/src/tdm_server.c index 4da079d..b193ac6 100644 --- a/src/tdm_server.c +++ b/src/tdm_server.c @@ -80,6 +80,7 @@ typedef struct _tdm_server_wait_info { tdm_server_vblank_info *vblank_info; unsigned int req_id; + double req_time; } tdm_server_wait_info; typedef struct _tdm_server_client_info { @@ -179,11 +180,12 @@ _tdm_server_send_done(tdm_server_wait_info *wait_info, tdm_error error, if (tdm_debug_module & TDM_DEBUG_VBLANK) TDM_DBG("req_id(%d) done", wait_info->req_id); - TDM_TRACE_COUNT(ServerDoneVBlank, wait_info->req_id); - vblank_info = wait_info->vblank_info; wl_tdm_vblank_send_done(vblank_info->resource, wait_info->req_id, sequence, tv_sec, tv_usec, error); + + TDM_TRACE_ASYNC_END((int)wait_info->req_time, "TDM_Server_Vblank:%u", vblank_info->stamp); + destroy_wait(wait_info); } @@ -305,8 +307,6 @@ _tdm_server_vblank_cb_wait_vblank(struct wl_client *client, struct wl_resource * unsigned int enable_fake = 0; tdm_error ret; - TDM_TRACE_COUNT(ServerWaitVBlank, req_id); - wait_info = calloc(1, sizeof * wait_info); if (!wait_info) { TDM_ERR("alloc failed"); @@ -317,10 +317,13 @@ _tdm_server_vblank_cb_wait_vblank(struct wl_client *client, struct wl_resource * LIST_ADDTAIL(&wait_info->link, &private_server->wait_list); wait_info->vblank_info = vblank_info; wait_info->req_id = req_id; + wait_info->req_time = TDM_TIME(req_sec, req_usec); if (tdm_debug_module & TDM_DEBUG_VBLANK) TDM_DBG("req_id(%d) wait", req_id); + TDM_TRACE_ASYNC_BEGIN((int)wait_info->req_time, "TDM_Server_Vblank:%u", vblank_info->stamp); + ret = tdm_vblank_wait(vblank_info->vblank, req_sec, req_usec, interval, _tdm_server_cb_vblank, wait_info); tdm_vblank_get_enable_fake(vblank_info->vblank, &enable_fake); @@ -347,8 +350,6 @@ _tdm_server_vblank_cb_wait_vblank_seq(struct wl_client *client, struct wl_resour unsigned int enable_fake = 0; tdm_error ret; - TDM_TRACE_COUNT(ServerWaitVBlank, req_id); - wait_info = calloc(1, sizeof * wait_info); if (!wait_info) { TDM_ERR("alloc failed"); @@ -359,10 +360,13 @@ _tdm_server_vblank_cb_wait_vblank_seq(struct wl_client *client, struct wl_resour LIST_ADDTAIL(&wait_info->link, &private_server->wait_list); wait_info->vblank_info = vblank_info; wait_info->req_id = req_id; + wait_info->req_time = TDM_TIME(req_sec, req_usec); if (tdm_debug_module & TDM_DEBUG_VBLANK) TDM_DBG("req_id(%d) wait", req_id); + TDM_TRACE_ASYNC_BEGIN((int)wait_info->req_time, "TDM_Server_Vblank:%u", vblank_info->stamp); + ret = tdm_vblank_wait_seq(vblank_info->vblank, req_sec, req_usec, sequence, _tdm_server_cb_vblank, wait_info); tdm_vblank_get_enable_fake(vblank_info->vblank, &enable_fake); diff --git a/src/tdm_vblank.c b/src/tdm_vblank.c index 6861ec8..1a3f6b9 100644 --- a/src/tdm_vblank.c +++ b/src/tdm_vblank.c @@ -771,6 +771,8 @@ _tdm_vblank_cb_vblank_HW(tdm_output *output, unsigned int sequence, return; } + TDM_TRACE_ASYNC_END((int)wait_info->req_time, "TDM_HW_Vblank:%u", (unsigned int)private_vblank->stamp); + if (wait_info->type == VBLANK_TYPE_HW_SW) { tdm_error ret; @@ -881,6 +883,8 @@ _tdm_vblank_wait_HW(tdm_vblank_wait_info *wait_info) skip, hw_interval, wait_info->target_seq); } + TDM_TRACE_ASYNC_BEGIN((int)wait_info->req_time, "TDM_HW_Vblank:%u", (unsigned int)private_vblank->stamp); + if (private_vblank->add_front) ret = tdm_output_wait_vblank_add_front(private_vblank->output, hw_interval, 0, _tdm_vblank_cb_vblank_HW, wait_info); @@ -961,6 +965,8 @@ tdm_vblank_cb_vblank_SW(tdm_vblank *vblank, double vblank_stamp) if (w->target_time != first_wait_info->target_time) break; + TDM_TRACE_ASYNC_END((int)w->req_time, "TDM_SW_Vblank:%u", (unsigned int)private_vblank->stamp); + LIST_DEL(&w->link); _tdm_vblank_valid_list_del(&w->valid_link); @@ -1032,6 +1038,8 @@ _tdm_vblank_wait_SW(tdm_vblank_wait_info *wait_info) _tdm_vblank_insert_wait(wait_info, &private_vblank->SW_wait_list); + TDM_TRACE_ASYNC_BEGIN((int)wait_info->req_time, "TDM_SW_Vblank:%u", (unsigned int)private_vblank->stamp); + ret = _tdm_vblank_sw_timer_update(private_vblank); if (ret != TDM_ERROR_NONE) { LIST_DEL(&wait_info->link); -- 2.7.4 From 4871f958070420cd51aa0d78d5f3d405cd4dea39 Mon Sep 17 00:00:00 2001 From: Konstantin Drabeniuk Date: Tue, 21 Nov 2017 08:57:41 +0200 Subject: [PATCH 09/16] utest: add 28 test cases Covered API funcs. from the tdm_capture.c file. Change-Id: I1e4a2426247a6b0fb0e07b4b6840f94f6f172e95 Signed-off-by: Konstantin Drabeniuk --- utests/src/ut_tdm_capture.cpp | 806 +++++++++++++++++++++++++++++++++++++-- utests/src/ut_tdm_hwc_window.cpp | 5 + 2 files changed, 789 insertions(+), 22 deletions(-) diff --git a/utests/src/ut_tdm_capture.cpp b/utests/src/ut_tdm_capture.cpp index ad75d2a..424f2c6 100644 --- a/utests/src/ut_tdm_capture.cpp +++ b/utests/src/ut_tdm_capture.cpp @@ -30,56 +30,818 @@ #include "gtest/gtest.h" #include "ut_common.h" -extern "C" { #include "tdm.h" +extern "C" { #include "tbm_bufmgr.h" #include "tbm_drm_helper.h" } -class TDMCapture : public ::testing::Test { +#include +#include +#include + +class TDMCaptureWithoutCreation : public testing::Test { protected: - tdm_display *dpy = NULL; - tdm_capture_capability capture_capabilities = (tdm_capture_capability) -42; + tdm_display *dpy = nullptr; + tbm_bufmgr bufmgr = nullptr; + tdm_display_capability display_capability = (tdm_display_capability)0; bool has_capture = false; - tbm_bufmgr tbm_bufmgr = NULL; - void SetUp(void) + std::vector output_array; + + virtual void SetEnvs() { setenv("TDM_DLOG", "1", 1); setenv("XDG_RUNTIME_DIR", ".", 1); setenv("TBM_DLOG", "1", 1); + setenv("TDM_DEBUG_MODULE", "all", 1); + setenv("TDM_DEBUG", "1", 1); setenv("TBM_DISPLAY_SERVER", "1", 1); + } + + virtual void UnsetEnvs() + { + unsetenv("TDM_DLOG"); + unsetenv("XDG_RUNTIME_DIR"); + unsetenv("TBM_DLOG"); + unsetenv("TDM_DEBUG_MODULE"); + unsetenv("TDM_DEBUG"); + unsetenv("TBM_DISPLAY_SERVER"); + } + + void SetUp(void) + { + tdm_error error = TDM_ERROR_NONE; + int output_count; + + SetEnvs(); + + /* FIXME: fix the error. If we initialize TBM before TDM we get fail + * in the tdm_output_set_dpms */ +#if 0 tbm_bufmgr = tbm_bufmgr_init(-1); ASSERT_FALSE(tbm_bufmgr == NULL); - tdm_error error = TDM_ERROR_NONE; +#endif + dpy = tdm_display_init(&error); ASSERT_TRUE(error == TDM_ERROR_NONE); - ASSERT_FALSE(dpy == NULL); - error = tdm_display_get_capture_capabilities(dpy, &capture_capabilities); + ASSERT_FALSE(dpy == nullptr); + + error = tdm_display_get_capabilities(dpy, &display_capability); #ifdef FAIL_ON_UNSUPPORTED - ASSERT_GT(capture_capabilities, 0); + ASSERT_TRUE(display_capability & TDM_DISPLAY_CAPABILITY_CAPTURE); #endif - if (capture_capabilities > 0) + ASSERT_TRUE(error == TDM_ERROR_NONE); + + if (display_capability & TDM_DISPLAY_CAPABILITY_CAPTURE) has_capture = true; + + ASSERT_TRUE(tdm_display_get_output_count(dpy, &output_count) == TDM_ERROR_NONE); + + for (int i = 0; i < output_count; i++) { + tdm_output *output = tdm_display_get_output(dpy, i, &error); + + if (TDM_ERROR_NONE != error || nullptr == output) + continue; + + tdm_output_conn_status status = TDM_OUTPUT_CONN_STATUS_DISCONNECTED; + if (TDM_ERROR_NONE != tdm_output_get_conn_status(output, &status)) + continue; + + if (status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) + continue; + + output_array.push_back(output); + } } + void TearDown(void) { - tdm_display_deinit(dpy); - dpy = NULL; - tbm_bufmgr_deinit(tbm_bufmgr); - tbm_bufmgr = NULL; - unsetenv("TDM_DLOG"); - unsetenv("XDG_RUNTIME_DIR"); - unsetenv("TBM_DLOG"); - unsetenv("TBM_DISPLAY_SERVER"); + if (dpy) + tdm_display_deinit(dpy); + if (bufmgr) + tbm_bufmgr_deinit(bufmgr); + + UnsetEnvs(); + } +}; + +struct UtCapture +{ + tdm_output *output; + const tdm_output_mode *output_mode; + tdm_capture *capture; + std::vector layers; + UtCapture(tdm_output *, const tdm_output_mode *, tdm_capture *, std::vector); +}; + +UtCapture::UtCapture(tdm_output *_output, const tdm_output_mode *_output_mode, + tdm_capture *_capture, std::vector _layers) +{ + output = _output; + output_mode = _output_mode; + capture = _capture; + layers = _layers; +} + +class TDMCapture : public TDMCaptureWithoutCreation { +protected: + const tbm_format *formats = nullptr; + int format_count = 0; + std::vector captures; + std::vector buffers; + static int utCaptureDoneHandlerSuccessCounter; + friend void UtCaptureDoneHandler(tdm_capture *capture, + tbm_surface_h buffer, void *user_data); + void SetUp(void); + void TearDown(void); + void UtCaptureGetInfo(UtCapture *capture, double scale, tdm_transform transform, tdm_info_capture *info); + void UtCaptureGetInfo(UtCapture *capture, tdm_info_capture *info); + tbm_surface_h UtCaptureCreateBuffer(UtCapture *capture); + tbm_surface_h UtCaptureCreateBuffer(int width, int height, tbm_format format, int scanout); + tbm_surface_h UtCaptureCreateBuffer(int width, int height, tbm_format format); +}; + +int TDMCapture::utCaptureDoneHandlerSuccessCounter = 0; + +void UtCaptureDoneHandler(tdm_capture *capture, + tbm_surface_h buffer, void *user_data) +{ + TDMCapture *fcapture = (TDMCapture *)user_data; + + if (!fcapture) + return; + + for (tbm_surface_h buf : fcapture->buffers) { + if (buf == buffer) { + fcapture->utCaptureDoneHandlerSuccessCounter++; + break; + } + } +} + +void TDMCapture::SetUp(void) +{ + tdm_error error; + + utCaptureDoneHandlerSuccessCounter = 0; + + ASSERT_NO_FATAL_FAILURE(TDMCaptureWithoutCreation::SetUp()); + + if (!has_capture) + return; + + for (tdm_output *output : output_array) { + const tdm_output_mode *output_mode = nullptr; + int output_modes_cnt = 0; + const tdm_output_mode *output_modes; + int temp_layer_count = 0; + std::vector layers; + + error = tdm_output_get_available_modes(output, &output_modes, &output_modes_cnt); + ASSERT_EQ(TDM_ERROR_NONE, error); + + for(int j = 0; j < output_modes_cnt; j++) + if(output_modes[j].type & TDM_OUTPUT_MODE_TYPE_PREFERRED) + output_mode = &output_modes[j]; + + ASSERT_NE(nullptr, output_mode); + + if (TDM_ERROR_NONE != tdm_output_get_layer_count(output, &temp_layer_count)) + continue; + if (0 == temp_layer_count) + continue; + + for (int i = 0; i < temp_layer_count; ++i) { + tdm_layer *layer; + layer = tdm_output_get_layer(output, i, &error); + ASSERT_TRUE(TDM_ERROR_NONE == error); + ASSERT_FALSE(NULL == layer); + layers.push_back(layer); + } + + tdm_capture *capture = tdm_output_create_capture(output, &error); + ASSERT_NE(nullptr, capture); + ASSERT_EQ(TDM_ERROR_NONE, error); + + captures.emplace_back(output, output_mode, capture, layers); + } + + error = + tdm_display_get_catpure_available_formats(dpy, &formats, &format_count); + ASSERT_EQ(TDM_ERROR_NONE, error); + ASSERT_NE(nullptr, formats); + ASSERT_GE(format_count, 0); +} + +void TDMCapture::TearDown(void) +{ + for (UtCapture & utCapture : captures) + tdm_capture_destroy(utCapture.capture); + + for (tbm_surface_h buffer : buffers) { + tbm_surface_destroy(buffer); + } + + TDMCaptureWithoutCreation::TearDown(); +} + +void TDMCapture::UtCaptureGetInfo(UtCapture *capture, double scale, + tdm_transform transform, tdm_info_capture *info) +{ + memset((void *)info, 0, sizeof(tdm_info_capture)); + + const tdm_output_mode *output_mode = capture->output_mode; + + int w = output_mode->hdisplay * scale; + int h = output_mode->vdisplay * scale; + + info->dst_config.size.h = w; + info->dst_config.size.v = h; + info->dst_config.pos.x = 0; + info->dst_config.pos.y = 0; + info->dst_config.pos.w = w; + info->dst_config.pos.h = h; + info->dst_config.format = formats[0]; + info->transform = transform; + info->type = TDM_CAPTURE_TYPE_ONESHOT; +} + +void TDMCapture::UtCaptureGetInfo(UtCapture *capture, tdm_info_capture *info) +{ + UtCaptureGetInfo(capture, 1.0, TDM_TRANSFORM_NORMAL, info); +} + +tbm_surface_h +TDMCapture::UtCaptureCreateBuffer(UtCapture *capture) +{ + tbm_surface_h buffer; + + buffer = tbm_surface_create(capture->output_mode->hdisplay, + capture->output_mode->vdisplay, formats[0]); + if (buffer) + buffers.push_back(buffer); + + return buffer; +} + +tbm_surface_h +TDMCapture::UtCaptureCreateBuffer(int width, int height, tbm_format format, int scanout) +{ + tbm_surface_h buffer; + + if (scanout) + buffer = tbm_surface_internal_create_with_flags(width, height, format, TBM_BO_SCANOUT); + else + buffer = tbm_surface_internal_create_with_flags(width, height, format, TBM_BO_DEFAULT); + + if (buffer) + buffers.push_back(buffer); + + return buffer; +} + +tbm_surface_h +TDMCapture::UtCaptureCreateBuffer(int width, int height, tbm_format format) +{ + return UtCaptureCreateBuffer(width, height, format, 0); +} + +class TDMCaptureCommit : public TDMCapture { +public: +private: + int epFd = -1; + int timerFd = -1; + int tdmFd = -1; + static const int timeLimitSec = 3; + static const int timeLimitNsec = 0; +protected: + void SetUp(void); + void TearDown(void); + void UtHandleCaptureEvent(); + int UtPrepareToCapture(double scale, tdm_transform transform); + int UtPrepareToCapture(); +}; + +void TDMCaptureCommit::SetUp(void) +{ + struct epoll_event ep; + tdm_error error; + + ASSERT_NO_FATAL_FAILURE(TDMCapture::SetUp()); + + for (UtCapture & utCapture : captures) { + error = tdm_output_set_mode(utCapture.output, utCapture.output_mode); + ASSERT_TRUE(error == TDM_ERROR_NONE); + + error = tdm_output_set_dpms(utCapture.output, TDM_OUTPUT_DPMS_ON); + ASSERT_TRUE(error == TDM_ERROR_NONE); + + for (tdm_layer *layer : utCapture.layers) { + int w, h; + tdm_layer_capability lcapabilities; + tbm_surface_h buffer; + tdm_info_layer layer_info = {0}; + + w = utCapture.output_mode->hdisplay; + h = utCapture.output_mode->vdisplay; + + error = tdm_layer_get_capabilities(layer, &lcapabilities); + ASSERT_EQ(TDM_ERROR_NONE, error); + if (!(lcapabilities & TDM_LAYER_CAPABILITY_PRIMARY)) { + w = w / 2; + h = h / 2; + } + + buffer = UtCaptureCreateBuffer(w, h, TBM_FORMAT_ARGB8888, 1); + ASSERT_NE(nullptr, buffer); + + layer_info.src_config.size.h = w; + layer_info.src_config.size.v = h; + layer_info.src_config.pos.x = 0; + layer_info.src_config.pos.y = 0; + layer_info.src_config.pos.w = w; + layer_info.src_config.pos.h = h; + layer_info.src_config.format = TBM_FORMAT_ARGB8888; + layer_info.dst_pos.x = 0; + layer_info.dst_pos.y = 0; + layer_info.dst_pos.w = w; + layer_info.dst_pos.h = h; + layer_info.transform = TDM_TRANSFORM_NORMAL; + + error = tdm_layer_set_info(layer, &layer_info); + ASSERT_EQ(TDM_ERROR_NONE, error); + + error = tdm_layer_set_buffer(layer, buffer); + ASSERT_EQ(TDM_ERROR_NONE, error); + } + + error = tdm_output_commit(utCapture.output, 0, nullptr, nullptr); + ASSERT_EQ(TDM_ERROR_NONE, error); + } + + /* TODO: use output_commit_handle */ + usleep(200000); + + epFd = epoll_create1(0); + ASSERT_TRUE(epFd != -1); + + timerFd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK); + ASSERT_TRUE(timerFd != -1); + + memset(&ep, 0, sizeof ep); + ep.events |= EPOLLIN; + ep.data.fd = timerFd; + ASSERT_TRUE(epoll_ctl(epFd, EPOLL_CTL_ADD, timerFd, &ep) == 0); + + ASSERT_TRUE(tdm_display_get_fd(dpy, &tdmFd) == TDM_ERROR_NONE); + + memset(&ep, 0, sizeof ep); + ep.events |= EPOLLIN; + ep.data.fd = tdmFd; + ASSERT_TRUE(epoll_ctl(epFd, EPOLL_CTL_ADD, tdmFd, &ep) == 0); +} + +void TDMCaptureCommit::TearDown(void) +{ + if (epFd) + close(epFd); + if (timerFd) + close(timerFd); + + for (UtCapture & utCapture : captures) { + for (tdm_layer *layer : utCapture.layers) + tdm_layer_unset_buffer(layer); + + tdm_output_set_dpms(utCapture.output, TDM_OUTPUT_DPMS_OFF); + } + + TDMCapture::TearDown(); +} + +void TDMCaptureCommit::UtHandleCaptureEvent() +{ + struct itimerspec its; + int count; + struct epoll_event ep_event[2]; + + if (utCaptureDoneHandlerSuccessCounter == (int)captures.size()) + return; + + its.it_interval.tv_sec = 0; + its.it_interval.tv_nsec = 0; + its.it_value.tv_sec = timeLimitSec; + its.it_value.tv_nsec = timeLimitNsec; + + ASSERT_TRUE(timerfd_settime(timerFd, 0, &its, NULL) == 0); + + while (1) { + count = epoll_wait(epFd, ep_event, sizeof(ep_event), -1); + ASSERT_TRUE(count >= 0); + + for (int i = 0; i < count; i++) { + if (ep_event[i].data.fd == timerFd) { + return; + } else { + ASSERT_TRUE(tdm_display_handle_events(dpy) == TDM_ERROR_NONE); + if (utCaptureDoneHandlerSuccessCounter == (int)captures.size()) + return; + } + } + } +} + +int TDMCaptureCommit::UtPrepareToCapture(double scale, tdm_transform transform) +{ + tdm_error error; + tbm_surface_h buffer; + + for (UtCapture & utCapture : captures) { + tdm_info_capture info = {0}; + + UtCaptureGetInfo(&utCapture, scale, transform, &info); + + error = tdm_capture_set_done_handler(utCapture.capture, UtCaptureDoneHandler, this); + EXPECT_EQ(TDM_ERROR_NONE, error); + if (error != TDM_ERROR_NONE) + return -1; + + error = tdm_capture_set_info(utCapture.capture, &info); + EXPECT_EQ(TDM_ERROR_NONE, error); + if (error != TDM_ERROR_NONE) + return -1; + + buffer = UtCaptureCreateBuffer(info.dst_config.size.h, + info.dst_config.size.v, + info.dst_config.format); + EXPECT_NE(NULL, buffer); + if (!buffer) + return -1; + + error = tdm_capture_attach(utCapture.capture, buffer); + EXPECT_EQ(TDM_ERROR_NONE, error); + if (error != TDM_ERROR_NONE) + return -1; + } + + return 0; +} + +int TDMCaptureCommit::UtPrepareToCapture() +{ + return UtPrepareToCapture(1.0, TDM_TRANSFORM_NORMAL); +} + +class TDMCaptureCommitThread : public TDMCaptureCommit { +protected: + void SetEnvs() + { + TDMCaptureCommit::SetEnvs(); + setenv("TDM_THREAD", "1", 1); + } + void UnsetEnvs() + { + TDMCaptureCommit::UnsetEnvs(); + unsetenv("TDM_THREAD"); } }; -TEST_F(TDMCapture, DisplayGetCaptureAvailableFormatsSuccessful) +TEST_F(TDMCaptureWithoutCreation, DisplayGetCaptureAvailableFormatsSuccessful) { SKIP_FLAG(has_capture); - const tbm_format * formats = NULL; + const tbm_format * formats = nullptr; int count = -42; ASSERT_TRUE(TDM_ERROR_NONE == tdm_display_get_catpure_available_formats(dpy, &formats, &count)); ASSERT_FALSE(-42 == count); - ASSERT_FALSE(NULL == formats); + ASSERT_FALSE(nullptr == formats); +} + +/* tdm_display_create_pp() */ + +TEST_F(TDMCaptureWithoutCreation, DisplayCreateCaptureNullAll) +{ + SKIP_FLAG(has_capture); + tdm_capture *capture; + + capture = tdm_output_create_capture(nullptr, nullptr); + ASSERT_EQ(nullptr, capture); +} + +TEST_F(TDMCaptureWithoutCreation, DisplayCreateCaptureNullOutput) +{ + SKIP_FLAG(has_capture); + tdm_capture *capture; + tdm_error error; + + capture = tdm_output_create_capture(nullptr, &error); + ASSERT_EQ(nullptr, capture); + ASSERT_NE(TDM_ERROR_NONE, error); +} + +TEST_F(TDMCaptureWithoutCreation, DisplayCreateCaptureSuccessNullError) +{ + SKIP_FLAG(has_capture); + tdm_capture *capture; + + for (tdm_output *output : output_array) { + capture = tdm_output_create_capture(output, nullptr); + ASSERT_NE(nullptr, capture); + } +} + +TEST_F(TDMCaptureWithoutCreation, DisplayCreateCaptureSuccess) +{ + SKIP_FLAG(has_capture); + tdm_capture *capture; + tdm_error error; + + for (tdm_output *output : output_array) { + capture = tdm_output_create_capture(output, &error); + ASSERT_NE(nullptr, capture); + ASSERT_EQ(TDM_ERROR_NONE, error); + } +} + +/* tdm_display_get_capture_available_size */ + +TEST_F(TDMCapture, DisplayGetCaptureAvailableSizeFailNullAll) +{ + SKIP_FLAG(has_capture); + tdm_error error; + + error = tdm_display_get_capture_available_size(nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); + ASSERT_NE(TDM_ERROR_NONE, error); +} + +TEST_F(TDMCapture, DisplayGetCaptureAvailableSizeSuccess) +{ + SKIP_FLAG(has_capture); + tdm_error error; + int min_w; + int min_h; + int max_w; + int max_h; + int preferred_align; + + error = tdm_display_get_capture_available_size(dpy, &min_w, &min_h, + &max_w, &max_h, &preferred_align); + ASSERT_EQ(TDM_ERROR_NONE, error); +} + + +/* tdm_capture_set_info() */ + +TEST_F(TDMCapture, CaptureSetInfoFailNullAll) +{ + SKIP_FLAG(has_capture); + tdm_error error; + + error = tdm_capture_set_info(nullptr, nullptr); + ASSERT_NE(TDM_ERROR_NONE, error); +} + +TEST_F(TDMCapture, CaptureSetInfoFailNullCapture) +{ + SKIP_FLAG(has_capture); + tdm_error error; + tdm_info_capture info; + + error = tdm_capture_set_info(nullptr, &info); + ASSERT_NE(TDM_ERROR_NONE, error); +} + +TEST_F(TDMCapture, CaptureSetInfoNullInfo) +{ + SKIP_FLAG(has_capture); + tdm_error error; + + for (UtCapture & utCapture : captures) { + error = tdm_capture_set_info(utCapture.capture, nullptr); + ASSERT_NE(TDM_ERROR_NONE, error); + } +} + +TEST_F(TDMCapture, CaptureSetInfoSuccessStream) +{ + SKIP_FLAG(has_capture); + tdm_error error; + tdm_info_capture info; + + for (UtCapture & utCapture : captures) { + error = tdm_output_set_mode(utCapture.output, utCapture.output_mode); + ASSERT_EQ(TDM_ERROR_NONE, error); + + UtCaptureGetInfo(&utCapture, &info); + + info.type = TDM_CAPTURE_TYPE_STREAM; + + error = tdm_capture_set_info(utCapture.capture, &info); + ASSERT_EQ(TDM_ERROR_NONE, error); + } +} + +TEST_F(TDMCapture, CaptureSetInfoSuccess) +{ + SKIP_FLAG(has_capture); + tdm_error error; + tdm_info_capture info; + + for (UtCapture & utCapture : captures) { + UtCaptureGetInfo(&utCapture, &info); + + error = tdm_capture_set_info(utCapture.capture, &info); + ASSERT_EQ(TDM_ERROR_NONE, error); + } +} + +/* tdm_capture_set_done_handler() */ + +TEST_F(TDMCapture, CaptureSetDoneHandlerFailNullAll) +{ + SKIP_FLAG(has_capture); + tdm_error error; + + error = tdm_capture_set_done_handler(nullptr, nullptr, nullptr); + ASSERT_NE(TDM_ERROR_NONE, error); +} + +TEST_F(TDMCapture, CaptureSetDoneHandlerFailNullCapture) +{ + SKIP_FLAG(has_capture); + tdm_error error; + + error = tdm_capture_set_done_handler(nullptr, UtCaptureDoneHandler, this); + ASSERT_NE(TDM_ERROR_NONE, error); +} + +TEST_F(TDMCapture, CaptureSetDoneHandlerSuccessNullFailNullFunc) +{ + SKIP_FLAG(has_capture); + tdm_error error; + + for (UtCapture & utCapture : captures) { + error = tdm_pp_set_done_handler(utCapture.capture, nullptr, this); + ASSERT_NE(TDM_ERROR_NONE, error); + } +} + +TEST_F(TDMCapture, CaptureSetDoneHandlerSuccessNullData) +{ + SKIP_FLAG(has_capture); + tdm_error error; + + for (UtCapture & utCapture : captures) { + error = tdm_capture_set_done_handler(utCapture.capture, UtCaptureDoneHandler, this); + ASSERT_EQ(TDM_ERROR_NONE, error); + } +} + +TEST_F(TDMCapture, CaptureSetDoneHandlerSuccess) +{ + SKIP_FLAG(has_capture); + tdm_error error; + + for (UtCapture & utCapture : captures) { + error = tdm_capture_set_done_handler(utCapture.capture, UtCaptureDoneHandler, this); + ASSERT_EQ(TDM_ERROR_NONE, error); + } +} + +/* tdm_capture_attach() */ + +TEST_F(TDMCapture, CaptureAttachFailNullAll) +{ + SKIP_FLAG(has_capture); + tdm_error error; + + error = tdm_capture_attach(nullptr, nullptr); + ASSERT_NE(TDM_ERROR_NONE, error); +} + +TEST_F(TDMCapture, CaptureAttachFailNullCapture) +{ + SKIP_FLAG(has_capture); + tdm_error error; + tbm_surface_h buffer; + + buffer = UtCaptureCreateBuffer(&captures[0]); + ASSERT_NE(nullptr, buffer); + + error = tdm_capture_attach(nullptr, buffer); + ASSERT_NE(TDM_ERROR_NONE, error); +} + +TEST_F(TDMCapture, CaptureAttachFailNullBuffer) +{ + SKIP_FLAG(has_capture); + tdm_error error; + + for (UtCapture & utCapture : captures) { + error = tdm_capture_attach(utCapture.capture, nullptr); + ASSERT_NE(TDM_ERROR_NONE, error); + } +} + +TEST_F(TDMCapture, CaptureAttachSuccess) +{ + SKIP_FLAG(has_capture); + tdm_error error; + tbm_surface_h buffer; + + for (UtCapture & utCapture : captures) { + buffer = UtCaptureCreateBuffer(&utCapture); + ASSERT_NE(nullptr, buffer); + + error = tdm_capture_attach(utCapture.capture, buffer); + ASSERT_EQ(TDM_ERROR_NONE, error); + } +} + +/* tdm_pp_commit() */ + +TEST_F(TDMCapture, CaptureCommitFailNullCapture) +{ + SKIP_FLAG(has_capture); + tdm_error error; + + error = tdm_capture_commit(nullptr); + ASSERT_NE(TDM_ERROR_NONE, error); +} + +TEST_F(TDMCapture, CaptureCommitFailDpmsOff) +{ + SKIP_FLAG(has_capture); + tdm_error error; + + for (UtCapture & utCapture : captures) { + error = tdm_capture_commit(utCapture.capture); + ASSERT_NE(TDM_ERROR_NONE, error); + } +} + +TEST_F(TDMCaptureCommit, CaptureCommitSuccess) +{ + SKIP_FLAG(has_capture); + tdm_error error; + + ASSERT_NE(-1, UtPrepareToCapture()); + + for (UtCapture & utCapture : captures) { + error = tdm_capture_commit(utCapture.capture); + ASSERT_EQ(TDM_ERROR_NONE, error); + } + + UtHandleCaptureEvent(); + + ASSERT_EQ(captures.size(), utCaptureDoneHandlerSuccessCounter); +} + +TEST_F(TDMCaptureCommitThread, CaptureCommitSuccess) +{ + SKIP_FLAG(has_capture); + tdm_error error; + + ASSERT_NE(-1, UtPrepareToCapture()); + + for (UtCapture & utCapture : captures) { + error = tdm_capture_commit(utCapture.capture); + ASSERT_EQ(TDM_ERROR_NONE, error); + } + + UtHandleCaptureEvent(); + + ASSERT_EQ(captures.size(), utCaptureDoneHandlerSuccessCounter); +} + +TEST_F(TDMCaptureCommit, CaptureCommitSuccessScale) +{ + SKIP_FLAG(has_capture); + tdm_error error; + + ASSERT_NE(-1, UtPrepareToCapture(2.0, TDM_TRANSFORM_NORMAL)); + + for (UtCapture & utCapture : captures) { + error = tdm_capture_commit(utCapture.capture); + ASSERT_EQ(TDM_ERROR_NONE, error); + } + + UtHandleCaptureEvent(); + + ASSERT_EQ(captures.size(), utCaptureDoneHandlerSuccessCounter); +} + +TEST_F(TDMCaptureCommit, CaptureCommitSuccessScaleAndTransform) +{ + SKIP_FLAG(has_capture); + tdm_error error; + + ASSERT_NE(-1, UtPrepareToCapture(2.0, TDM_TRANSFORM_180)); + + for (UtCapture & utCapture : captures) { + error = tdm_capture_commit(utCapture.capture); + ASSERT_EQ(TDM_ERROR_NONE, error); + } + + UtHandleCaptureEvent(); + + ASSERT_EQ(captures.size(), utCaptureDoneHandlerSuccessCounter); } diff --git a/utests/src/ut_tdm_hwc_window.cpp b/utests/src/ut_tdm_hwc_window.cpp index dd1d7a5..d6fb90c 100644 --- a/utests/src/ut_tdm_hwc_window.cpp +++ b/utests/src/ut_tdm_hwc_window.cpp @@ -96,8 +96,12 @@ protected: SetEnv(); + /* FIXME: fix the error. If we initialize TBM before TDM we get fail + * in the tdm_output_set_dpms */ +#if 0 tbm_bufmgr = tbm_bufmgr_init(-1); ASSERT_FALSE(tbm_bufmgr == NULL); +#endif dpy = tdm_display_init(&error); ASSERT_TRUE(error == TDM_ERROR_NONE); @@ -276,6 +280,7 @@ TEST_F(TDMOutputHwc, SetClientTargetBufferFailNullOutput) tdm_hwc_region reg; tbm_surface_h target_buff = CreateBufferForOutput(0); error = tdm_output_hwc_set_client_target_buffer(NULL, target_buff, reg); + tbm_surface_internal_destroy(target_buff); ASSERT_NE(TDM_ERROR_NONE, error); } -- 2.7.4 From 7f007a899f57d79c0c88d3aec4c58e4cc294325a Mon Sep 17 00:00:00 2001 From: Konstantin Drabeniuk Date: Tue, 21 Nov 2017 11:35:59 +0200 Subject: [PATCH 10/16] add excluding coverage comments for tdm_capture.c add excluding coverage comments for tdm_capture.c for folowing code: - fail if the backend's function don't exist; - fail if there is not capability; - dump; - calloc fail; - check_module_abi fail; - tdm_capture_create_layer_internal. Change-Id: Icb04f5ab1cd7738d8216bb47cb80211c0821978d Signed-off-by: Konstantin Drabeniuk --- src/tdm_capture.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/tdm_capture.c b/src/tdm_capture.c index 6be39eb..751056b 100644 --- a/src/tdm_capture.c +++ b/src/tdm_capture.c @@ -130,10 +130,12 @@ tdm_capture_cb_done(tdm_capture *capture_backend, tbm_surface_h buffer, TDM_NEVER_GET_HERE(); if (tdm_debug_dump & TDM_DUMP_FLAG_CAPTURE) { + /* LCOV_EXCL_START */ char str[TDM_PATH_LEN]; static int i; snprintf(str, TDM_PATH_LEN, "capture_%03d", i++); tdm_helper_dump_buffer_str(buffer, tdm_debug_dump_dir, str); + /* LCOV_EXCL_STOP */ } if (tdm_debug_module & TDM_DEBUG_BUFFER) @@ -190,44 +192,54 @@ tdm_capture_create_output_internal(tdm_private_output *private_output, TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), NULL); if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE)) { + /* LCOV_EXCL_START */ TDM_ERR("no capture capability"); if (error) *error = TDM_ERROR_NO_CAPABILITY; return NULL; + /* LCOV_EXCL_STOP */ } if (!(private_display->caps_capture.capabilities & TDM_CAPTURE_CAPABILITY_OUTPUT)) { + /* LCOV_EXCL_START */ TDM_ERR("no output capture capability"); if (error) *error = TDM_ERROR_NO_CAPABILITY; return NULL; + /* LCOV_EXCL_STOP */ } capture_backend = func_output->output_create_capture( private_output->output_backend, &ret); if (ret != TDM_ERROR_NONE) { + /* LCOV_EXCL_START */ if (error) *error = ret; return NULL; + /* LCOV_EXCL_STOP */ } private_capture = calloc(1, sizeof(tdm_private_capture)); if (!private_capture) { + /* LCOV_EXCL_START */ TDM_ERR("failed: alloc memory"); func_capture->capture_destroy(capture_backend); if (error) *error = TDM_ERROR_OUT_OF_MEMORY; return NULL; + /* LCOV_EXCL_STOP */ } ret = func_capture->capture_set_done_handler(capture_backend, tdm_capture_cb_done, private_capture); if (ret != TDM_ERROR_NONE) { + /* LCOV_EXCL_START */ TDM_ERR("capture(%p) set capture_done_handler failed", private_capture); func_capture->capture_destroy(capture_backend); if (error) *error = ret; return NULL; + /* LCOV_EXCL_STOP */ } private_capture->stamp = tdm_helper_get_time(); @@ -255,6 +267,7 @@ tdm_capture_create_output_internal(tdm_private_output *private_output, return private_capture; } +/* LCOV_EXCL_START */ INTERN tdm_private_capture * tdm_capture_create_layer_internal(tdm_private_layer *private_layer, tdm_error *error) @@ -321,6 +334,7 @@ tdm_capture_create_layer_internal(tdm_private_layer *private_layer, return private_capture; } +/* LCOV_EXCL_STOP */ INTERN void tdm_capture_destroy_internal(tdm_private_capture *private_capture) @@ -414,9 +428,11 @@ tdm_capture_set_info(tdm_capture *capture, tdm_info_capture *info) _pthread_mutex_lock(&private_display->lock); if (!func_capture->capture_set_info) { + /* LCOV_EXCL_START */ _pthread_mutex_unlock(&private_display->lock); TDM_DBG("failed: not implemented!!"); return TDM_ERROR_NOT_IMPLEMENTED; + /* LCOV_EXCL_STOP */ } if (info->type == TDM_CAPTURE_TYPE_STREAM && info->frequency == 0) { @@ -478,13 +494,16 @@ tdm_capture_attach(tdm_capture *capture, tbm_surface_h buffer) _pthread_mutex_lock(&private_display->lock); if (!func_capture->capture_attach) { + /* LCOV_EXCL_START */ _pthread_mutex_unlock(&private_display->lock); TDM_DBG("failed: not implemented!!"); return TDM_ERROR_NOT_IMPLEMENTED; + /* LCOV_EXCL_STOP */ } if (tdm_display_check_module_abi(private_display, 1, 2) && private_display->caps_capture.max_attach_count > 0) { + /* LCOV_EXCL_START */ int length = LIST_LENGTH(&private_capture->pending_buffer_list) + LIST_LENGTH(&private_capture->buffer_list); if (length >= private_display->caps_capture.max_attach_count) { @@ -493,23 +512,28 @@ tdm_capture_attach(tdm_capture *capture, tbm_surface_h buffer) private_display->caps_capture.max_attach_count); return TDM_ERROR_BAD_REQUEST; } + /* LCOV_EXCL_STOP */ } capture_buffer = calloc(1, sizeof * capture_buffer); if (!capture_buffer) { + /* LCOV_EXCL_START */ _pthread_mutex_unlock(&private_display->lock); TDM_ERR("alloc failed"); return TDM_ERROR_OUT_OF_MEMORY; + /* LCOV_EXCL_STOP */ } ret = func_capture->capture_attach(private_capture->capture_backend, buffer); TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE); if (ret != TDM_ERROR_NONE) { + /* LCOV_EXCL_START */ free(capture_buffer); _pthread_mutex_unlock(&private_display->lock); TDM_ERR("attach failed"); return ret; + /* LCOV_EXCL_STOP */ } LIST_ADDTAIL(&capture_buffer->link, &private_capture->pending_buffer_list); @@ -545,9 +569,11 @@ tdm_capture_commit(tdm_capture *capture) } if (!func_capture->capture_commit) { + /* LCOV_EXCL_START */ _pthread_mutex_unlock(&private_display->lock); TDM_DBG("failed: not implemented!!"); return TDM_ERROR_NOT_IMPLEMENTED; + /* LCOV_EXCL_STOP */ } LIST_INITHEAD(&commit_buffer_list); @@ -568,6 +594,7 @@ tdm_capture_commit(tdm_capture *capture) continue; if (ret != TDM_ERROR_NONE) { + /* LCOV_EXCL_START */ /* Not to call the user release handler when failed. * Do we have to call this function here really? * User better use set_done_handler to know when pp is done. Using @@ -581,6 +608,7 @@ tdm_capture_commit(tdm_capture *capture) LIST_DEL(&b->link); free(b); + /* LCOV_EXCL_STOP */ } } -- 2.7.4 From 1e2f5de25c35c66e173d3690b19cb2e2ac419607 Mon Sep 17 00:00:00 2001 From: Konstantin Drabeniuk Date: Tue, 21 Nov 2017 12:26:17 +0200 Subject: [PATCH 11/16] add excluding coverage comments for tdm_display.c add excluding coverage comments for tdm_display.c for folowing code: - fail if there is not capability; - poll fail. Change-Id: I02b2bcb11058adc148057fd9a5e5d638751eab15 Signed-off-by: Konstantin Drabeniuk --- src/tdm_display.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/tdm_display.c b/src/tdm_display.c index 0e3aadc..1f1caec 100644 --- a/src/tdm_display.c +++ b/src/tdm_display.c @@ -84,9 +84,11 @@ tdm_display_get_pp_capabilities(tdm_display *dpy, _pthread_mutex_lock(&private_display->lock); if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP)) { + /* LCOV_EXCL_START */ TDM_ERR("no pp capability"); _pthread_mutex_unlock(&private_display->lock); return TDM_ERROR_NO_CAPABILITY; + /* LCOV_EXCL_STOP */ } *capabilities = private_display->caps_pp.capabilities; @@ -108,9 +110,11 @@ tdm_display_get_pp_available_formats(tdm_display *dpy, _pthread_mutex_lock(&private_display->lock); if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP)) { + /* LCOV_EXCL_START */ TDM_ERR("no pp capability"); _pthread_mutex_unlock(&private_display->lock); return TDM_ERROR_NO_CAPABILITY; + /* LCOV_EXCL_STOP */ } *formats = (const tbm_format *)private_display->caps_pp.formats; @@ -130,9 +134,11 @@ tdm_display_get_pp_available_size(tdm_display *dpy, int *min_w, int *min_h, _pthread_mutex_lock(&private_display->lock); if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_PP)) { + /* LCOV_EXCL_START */ TDM_ERR("no pp capability"); _pthread_mutex_unlock(&private_display->lock); return TDM_ERROR_NO_CAPABILITY; + /* LCOV_EXCL_STOP */ } if (min_w) @@ -162,9 +168,11 @@ tdm_display_get_capture_capabilities(tdm_display *dpy, _pthread_mutex_lock(&private_display->lock); if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE)) { + /* LCOV_EXCL_START */ TDM_ERR("no capture capability"); _pthread_mutex_unlock(&private_display->lock); return TDM_ERROR_NO_CAPABILITY; + /* LCOV_EXCL_STOP */ } *capabilities = private_display->caps_capture.capabilities; @@ -186,9 +194,11 @@ tdm_display_get_catpure_available_formats(tdm_display *dpy, _pthread_mutex_lock(&private_display->lock); if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE)) { + /* LCOV_EXCL_START */ TDM_ERR("no capture capability"); _pthread_mutex_unlock(&private_display->lock); return TDM_ERROR_NO_CAPABILITY; + /* LCOV_EXCL_STOP */ } *formats = (const tbm_format *)private_display->caps_capture.formats; @@ -208,9 +218,11 @@ tdm_display_get_capture_available_size(tdm_display *dpy, int *min_w, int *min_h, _pthread_mutex_lock(&private_display->lock); if (!(private_display->capabilities & TDM_DISPLAY_CAPABILITY_CAPTURE)) { + /* LCOV_EXCL_START */ TDM_ERR("no capture capability"); _pthread_mutex_unlock(&private_display->lock); return TDM_ERROR_NO_CAPABILITY; + /* LCOV_EXCL_STOP */ } if (min_w) @@ -261,8 +273,10 @@ tdm_display_get_output_count(tdm_display *dpy, int *count) (*count)++; if (*count == 0) { + /* LCOV_EXCL_START */ _pthread_mutex_unlock(&private_display->lock); return TDM_ERROR_NONE; + /* LCOV_EXCL_STOP */ } _pthread_mutex_unlock(&private_display->lock); @@ -333,12 +347,14 @@ tdm_display_handle_events(tdm_display *dpy) TDM_INFO("fd(%d) polling in", fd); while (poll(&fds, 1, -1) < 0) { + /* LCOV_EXCL_START */ if (errno == EINTR || errno == EAGAIN) /* normal case */ continue; else { TDM_ERR("poll failed: %m"); return TDM_ERROR_OPERATION_FAILED; } + /* LCOV_EXCL_STOP */ } if (tdm_debug_module & TDM_DEBUG_THREAD) -- 2.7.4 From aa2f71aaafaaac87a08fb6bd86999b01e1e08ec5 Mon Sep 17 00:00:00 2001 From: Roman Marchenko Date: Tue, 21 Nov 2017 15:53:05 +0200 Subject: [PATCH 12/16] utest: Add 16 tests cases for tdm_buffer Change-Id: I75caad5e4236a7b5189d43832a10a6429c4c0ac9 Signed-off-by: Roman Marchenko --- utests/Makefile.am | 1 + utests/src/ut_tdm_buffer.cpp | 251 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 252 insertions(+) create mode 100644 utests/src/ut_tdm_buffer.cpp diff --git a/utests/Makefile.am b/utests/Makefile.am index 710e3e9..b919431 100644 --- a/utests/Makefile.am +++ b/utests/Makefile.am @@ -7,6 +7,7 @@ tdm_utests_SOURCES = \ src/ut_tdm_capture.cpp \ src/ut_tdm_output.cpp \ src/ut_tdm_hwc_window.cpp \ + src/ut_tdm_buffer.cpp \ src/ut_tdm_layer.cpp \ src/ut_tdm_vblank.cpp diff --git a/utests/src/ut_tdm_buffer.cpp b/utests/src/ut_tdm_buffer.cpp new file mode 100644 index 0000000..7efba7b --- /dev/null +++ b/utests/src/ut_tdm_buffer.cpp @@ -0,0 +1,251 @@ +#include "gtest/gtest.h" +#include "ut_common.h" +#include "stdint.h" + +extern "C" { +#include "tdm.h" +#include "tdm_backend.h" +#include "tbm_bufmgr.h" +#include "tbm_surface.h" +#include "tbm_surface_internal.h" +#include "tbm_drm_helper.h" +} + +class TDMBuffer: public ::testing::Test +{ +protected: + static tbm_bufmgr tbm_bufmgr; + static int master_fd; + + tbm_surface_h surface; + + tdm_error error; + + static void SetEnv(void) + { + setenv("TDM_DEBUG_MODULE", "all", 1); + setenv("TDM_DEBUG", "1", 1); + setenv("TDM_THREAD", "0", 1); + setenv("XDG_RUNTIME_DIR", "/run", 1); + setenv("TBM_DISPLAY_SERVER", "1", 1); + } + + static void UnsetEnv(void) + { + unsetenv("TDM_DEBUG_MODULE"); + unsetenv("TDM_DEBUG"); + unsetenv("TDM_THREAD"); + unsetenv("XDG_RUNTIME_DIR"); + unsetenv("TBM_DISPLAY_SERVER"); + } + + static void SetUpTestCase() + { + SetEnv(); + tbm_bufmgr = tbm_bufmgr_init(-1); + ASSERT_FALSE(tbm_bufmgr == NULL); + master_fd = tbm_drm_helper_get_master_fd(); + } + + static void TearDownTestCase() + { + tbm_bufmgr_deinit(tbm_bufmgr); + tbm_bufmgr = NULL; + + if (master_fd > -1) { + int temp_master_fd = tbm_drm_helper_get_master_fd(); + EXPECT_EQ(temp_master_fd, -1) << "Fatal Error. Can't deinit tdm/tbm" << std::endl; + if (temp_master_fd > -1) + exit(1); + close(master_fd); + } + + UnsetEnv(); + } + void SetUp() + { + surface = tbm_surface_create(256, 256, TBM_FORMAT_ARGB8888); + ASSERT_TRUE(surface != NULL); + } + void TearDown() + { + if (surface) { + while (tbm_surface_internal_is_valid(surface)) + tbm_surface_destroy(surface); + } + } +}; + +tbm_bufmgr TDMBuffer::tbm_bufmgr = NULL; +int TDMBuffer::master_fd = -42; + + +static int handler_is_called = 0; +static void release_handler(tbm_surface_h buffer, void *user_data) +{ + if (user_data == &handler_is_called) + handler_is_called = 1; +} +static void destroy_handler(tbm_surface_h buffer, void *user_data) +{ + if (user_data == &handler_is_called) + handler_is_called = 1; +} + +/* tbm_surface_h tdm_buffer_ref_backend(tbm_surface_h buffer) */ +TEST_F(TDMBuffer, RefFailNULL) +{ + tbm_surface_h buffer = NULL; + + buffer = tdm_buffer_ref_backend(NULL); + ASSERT_EQ(NULL, buffer); +} + +TEST_F(TDMBuffer, RefSuccessful) +{ + tbm_surface_h buffer = NULL; + + buffer = tdm_buffer_ref_backend(surface); + ASSERT_EQ(buffer, surface); + + buffer = tdm_buffer_ref_backend(surface); + ASSERT_EQ(buffer, surface); + +} + +/* void tdm_buffer_unref_backend(tbm_surface_h buffer) */ +TEST_F(TDMBuffer, UnrefFailNULL) +{ + tdm_buffer_unref_backend(NULL); +} + +TEST_F(TDMBuffer, UnrefSuccessfulTwoRefUnref) +{ + tbm_surface_h buffer = NULL; + + buffer = tdm_buffer_ref_backend(surface); + ASSERT_EQ(buffer, surface); + buffer = tdm_buffer_ref_backend(surface); + ASSERT_EQ(buffer, surface); + + // first unref + tdm_buffer_unref_backend(surface); + ASSERT_TRUE(tbm_surface_internal_is_valid(surface)); + + // second unref + tdm_buffer_unref_backend(surface); + ASSERT_TRUE(tbm_surface_internal_is_valid(surface)); +} + +TEST_F(TDMBuffer, UnrefSuccessfulWithoutRef) +{ + tdm_buffer_unref_backend(surface); + ASSERT_FALSE(tbm_surface_internal_is_valid(surface)); +} + +TEST_F(TDMBuffer, UnrefSuccessfulOneRefTwoUnref) +{ + tbm_surface_h buffer = NULL; + + buffer = tdm_buffer_ref_backend(surface); + ASSERT_EQ(buffer, surface); + + tdm_buffer_unref_backend(surface); + ASSERT_TRUE(tbm_surface_internal_is_valid(surface)); + + tdm_buffer_unref_backend(surface); + ASSERT_FALSE(tbm_surface_internal_is_valid(surface)); +} + +/* tdm_error tdm_buffer_add_release_handler(tbm_surface_h buffer, tdm_buffer_release_handler func, void *user_data) */ +TEST_F(TDMBuffer, AddReleaseHandlerFailNULL) +{ + error = tdm_buffer_add_release_handler(NULL, release_handler, &handler_is_called); + ASSERT_EQ(TDM_ERROR_INVALID_PARAMETER, error); + + error = tdm_buffer_add_release_handler(surface, NULL, &handler_is_called); + ASSERT_EQ(TDM_ERROR_INVALID_PARAMETER, error); +} + +TEST_F(TDMBuffer, AddReleaseHandlerSuccessful) +{ + error = tdm_buffer_add_release_handler(surface, release_handler, &handler_is_called); + ASSERT_EQ(TDM_ERROR_NONE, error); + + handler_is_called = 0; + tdm_buffer_unref_backend(surface); + ASSERT_TRUE(handler_is_called); +} + + +/* void tdm_buffer_remove_release_handler(tbm_surface_h buffer, tdm_buffer_release_handler func, void *user_data) */ +TEST_F(TDMBuffer, RemoveReleaseHandlerFailNULL) +{ + tdm_buffer_remove_release_handler(NULL, release_handler, &handler_is_called); + + tdm_buffer_remove_release_handler(surface, NULL, &handler_is_called); +} + +TEST_F(TDMBuffer, RemoveReleaseHandlerFailWithoutAdd) +{ + tdm_buffer_remove_release_handler(surface, release_handler, &handler_is_called); +} + +TEST_F(TDMBuffer, RemoveReleaseHandlerSuccessful) +{ + error = tdm_buffer_add_release_handler(surface, release_handler, &handler_is_called); + ASSERT_EQ(TDM_ERROR_NONE, error); + + tdm_buffer_remove_release_handler(surface, release_handler, &handler_is_called); + + handler_is_called = 0; + tdm_buffer_unref_backend(surface); + ASSERT_FALSE(handler_is_called); +} + +/* tdm_error tdm_buffer_add_destroy_handler(tbm_surface_h buffer, tdm_buffer_destroy_handler func, void *user_data) */ +TEST_F(TDMBuffer, AddDestroyHandlerFailNULL) +{ + error = tdm_buffer_add_destroy_handler(NULL, destroy_handler, &handler_is_called); + ASSERT_EQ(TDM_ERROR_INVALID_PARAMETER, error); + + error = tdm_buffer_add_destroy_handler(surface, NULL, &handler_is_called); + ASSERT_EQ(TDM_ERROR_INVALID_PARAMETER, error); +} + +TEST_F(TDMBuffer, AddDestroyHandlerSuccessful) +{ + error = tdm_buffer_add_destroy_handler(surface, destroy_handler, &handler_is_called); + ASSERT_EQ(TDM_ERROR_NONE, error); + + handler_is_called = 0; + tbm_surface_internal_unref(surface); + ASSERT_TRUE(handler_is_called); + surface = NULL; +} + +/* void tdm_buffer_remove_destroy_handler() */ +TEST_F(TDMBuffer, RemoveDestroyHandlerFailNULL) +{ + tdm_buffer_remove_destroy_handler(NULL, release_handler, &handler_is_called); + + tdm_buffer_remove_destroy_handler(surface, NULL, &handler_is_called); +} + +TEST_F(TDMBuffer, RemoveDestroyHandlerFailWithoutAdd) +{ + tdm_buffer_remove_destroy_handler(surface, release_handler, &handler_is_called); +} + +TEST_F(TDMBuffer, RemoveDestroyHandlerSuccessful) +{ + error = tdm_buffer_add_destroy_handler(surface, release_handler, &handler_is_called); + ASSERT_EQ(TDM_ERROR_NONE, error); + + tdm_buffer_remove_destroy_handler(surface, release_handler, &handler_is_called); + + handler_is_called = 0; + tbm_surface_internal_unref(surface); + ASSERT_FALSE(handler_is_called); +} + -- 2.7.4 From 2f588aa809bc0d833626bfe36340be183511c6c9 Mon Sep 17 00:00:00 2001 From: Roman Marchenko Date: Tue, 21 Nov 2017 10:07:26 +0200 Subject: [PATCH 13/16] add excluding coverage comments for tdm_hwc_window.c add excluding coverage comments for tdm_hwc_window.c for folowing code: - fail if the backend's function don't exist; - dump; - calloc fail. Change-Id: I885ba709fd7407cd5ebb454fcf17f4487a646ad7 Signed-off-by: Roman Marchenko --- src/tdm_hwc_window.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/tdm_hwc_window.c b/src/tdm_hwc_window.c index 0fffd7d..3efe364 100644 --- a/src/tdm_hwc_window.c +++ b/src/tdm_hwc_window.c @@ -87,11 +87,13 @@ tdm_hwc_window_get_tbm_buffer_queue(tdm_hwc_window *hwc_window, tdm_error *error func_hwc_window = &private_display->func_hwc_window; if (!func_hwc_window->hwc_window_get_tbm_buffer_queue) { + /* LCOV_EXCL_START */ _pthread_mutex_unlock(&private_display->lock); TDM_ERR("not implemented!!"); if (error) *error = TDM_ERROR_NOT_IMPLEMENTED; return NULL; + /* LCOV_EXCL_STOP */ } queue = func_hwc_window->hwc_window_get_tbm_buffer_queue(private_hwc_window->hwc_window_backend, error); @@ -113,9 +115,11 @@ tdm_hwc_window_set_zpos(tdm_hwc_window *hwc_window, uint32_t zpos) func_hwc_window = &private_display->func_hwc_window; if (!func_hwc_window->hwc_window_set_zpos) { + /* LCOV_EXCL_START */ _pthread_mutex_unlock(&private_display->lock); TDM_ERR("not implemented!!"); return TDM_ERROR_NOT_IMPLEMENTED; + /* LCOV_EXCL_STOP */ } ret = func_hwc_window->hwc_window_set_zpos(private_hwc_window->hwc_window_backend, zpos); @@ -140,9 +144,11 @@ tdm_hwc_window_set_composition_type(tdm_hwc_window *hwc_window, func_hwc_window = &private_display->func_hwc_window; if (!func_hwc_window->hwc_window_set_composition_type) { + /* LCOV_EXCL_START */ _pthread_mutex_unlock(&private_display->lock); TDM_ERR("not implemented!!"); return TDM_ERROR_NOT_IMPLEMENTED; + /* LCOV_EXCL_STOP */ } ret = func_hwc_window->hwc_window_set_composition_type(private_hwc_window->hwc_window_backend, composition_type); @@ -164,9 +170,11 @@ tdm_hwc_window_set_buffer_damage(tdm_hwc_window *hwc_window, tdm_hwc_region dama func_hwc_window = &private_display->func_hwc_window; if (!func_hwc_window->hwc_window_set_buffer_damage) { + /* LCOV_EXCL_START */ _pthread_mutex_unlock(&private_display->lock); TDM_ERR("not implemented!!"); return TDM_ERROR_NOT_IMPLEMENTED; + /* LCOV_EXCL_STOP */ } ret = func_hwc_window->hwc_window_set_buffer_damage(private_hwc_window->hwc_window_backend, damage); @@ -192,9 +200,11 @@ tdm_hwc_window_set_info(tdm_hwc_window *hwc_window, tdm_hwc_window_info *info) func_hwc_window = &private_display->func_hwc_window; if (!func_hwc_window->hwc_window_set_info) { + /* LCOV_EXCL_START */ _pthread_mutex_unlock(&private_display->lock); TDM_ERR("not implemented!!"); return TDM_ERROR_NOT_IMPLEMENTED; + /* LCOV_EXCL_STOP */ } if (info->src_config.format) @@ -218,6 +228,7 @@ tdm_hwc_window_set_info(tdm_hwc_window *hwc_window, tdm_hwc_window_info *info) return ret; } +/* LCOV_EXCL_START */ static void _tdm_window_dump_buffer(tdm_hwc_window *hwc_window, tbm_surface_h buffer) { @@ -237,6 +248,7 @@ _tdm_window_dump_buffer(tdm_hwc_window *hwc_window, tbm_surface_h buffer) return; } +/* LCOV_EXCL_STOP */ EXTERN tdm_error tdm_hwc_window_set_buffer(tdm_hwc_window *hwc_window, tbm_surface_h buffer) @@ -248,24 +260,30 @@ tdm_hwc_window_set_buffer(tdm_hwc_window *hwc_window, tbm_surface_h buffer) _pthread_mutex_lock(&private_display->lock); if ((tdm_debug_dump & TDM_DUMP_FLAG_WINDOW) && buffer) { + /* LCOV_EXCL_START */ char str[TDM_PATH_LEN]; static int i; snprintf(str, TDM_PATH_LEN, "window_%d_%d_%03d", private_output->index, private_hwc_window->zpos, i++); tdm_helper_dump_buffer_str(buffer, tdm_debug_dump_dir, str); + /* LCOV_EXCL_STOP */ } func_hwc_window = &private_display->func_hwc_window; if (!func_hwc_window->hwc_window_set_buffer) { + /* LCOV_EXCL_START */ _pthread_mutex_unlock(&private_display->lock); TDM_ERR("not implemented!!"); return TDM_ERROR_NOT_IMPLEMENTED; + /* LCOV_EXCL_STOP */ } /* dump buffer */ + /* LCOV_EXCL_START */ if (tdm_dump_enable && buffer) _tdm_window_dump_buffer(hwc_window, buffer); + /* LCOV_EXCL_STOP */ ret = func_hwc_window->hwc_window_set_buffer(private_hwc_window->hwc_window_backend, buffer); @@ -287,9 +305,11 @@ tdm_hwc_window_create_internal(tdm_private_output *private_output, TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), NULL); if (!func_output->output_hwc_create_window) { + /* LCOV_EXCL_START */ if (error) *error = TDM_ERROR_BAD_MODULE; return NULL; + /* LCOV_EXCL_STOP */ } hwc_window_backend = func_output->output_hwc_create_window( @@ -302,11 +322,13 @@ tdm_hwc_window_create_internal(tdm_private_output *private_output, private_hwc_window = calloc(1, sizeof(tdm_private_capture)); if (!private_hwc_window) { + /* LCOV_EXCL_START */ TDM_ERR("failed: alloc memory"); func_output->output_hwc_destroy_window(private_output->output_backend, hwc_window_backend); if (error) *error = TDM_ERROR_OUT_OF_MEMORY; return NULL; + /* LCOV_EXCL_STOP */ } LIST_ADD(&private_hwc_window->link, &private_output->hwc_window_list); @@ -359,9 +381,11 @@ tdm_hwc_window_set_flags(tdm_hwc_window *hwc_window, tdm_hwc_window_flag flags) func_hwc_window = &private_display->func_hwc_window; if (!func_hwc_window->hwc_window_set_flags) { + /* LCOV_EXCL_START */ _pthread_mutex_unlock(&private_display->lock); TDM_ERR("not implemented!!"); return TDM_ERROR_NOT_IMPLEMENTED; + /* LCOV_EXCL_STOP */ } ret = func_hwc_window->hwc_window_set_flags(private_hwc_window->hwc_window_backend, flags); @@ -383,9 +407,11 @@ tdm_hwc_window_unset_flags(tdm_hwc_window *hwc_window, tdm_hwc_window_flag flags func_hwc_window = &private_display->func_hwc_window; if (!func_hwc_window->hwc_window_unset_flags) { + /* LCOV_EXCL_START */ _pthread_mutex_unlock(&private_display->lock); TDM_ERR("not implemented!!"); return TDM_ERROR_NOT_IMPLEMENTED; + /* LCOV_EXCL_STOP */ } ret = func_hwc_window->hwc_window_unset_flags(private_hwc_window->hwc_window_backend, flags); @@ -410,9 +436,11 @@ tdm_hwc_window_video_get_capability(tdm_hwc_window *hwc_window, func_hwc_window = &private_display->func_hwc_window; if (!func_hwc_window->hwc_window_video_get_capability) { + /* LCOV_EXCL_START */ _pthread_mutex_unlock(&private_display->lock); TDM_ERR("not implemented!!"); return TDM_ERROR_NOT_IMPLEMENTED; + /* LCOV_EXCL_STOP */ } ret = func_hwc_window->hwc_window_video_get_capability(private_hwc_window->hwc_window_backend, @@ -440,9 +468,11 @@ tdm_hwc_window_video_get_supported_format(tdm_hwc_window *hwc_window, func_hwc_window = &private_display->func_hwc_window; if (!func_hwc_window->hwc_window_video_get_supported_format) { + /* LCOV_EXCL_START */ _pthread_mutex_unlock(&private_display->lock); TDM_ERR("not implemented!!"); return TDM_ERROR_NOT_IMPLEMENTED; + /* LCOV_EXCL_STOP */ } ret = func_hwc_window->hwc_window_video_get_supported_format(private_hwc_window->hwc_window_backend, -- 2.7.4 From 5ae850722af8dcb70e5bf78a5c9615172f5389a7 Mon Sep 17 00:00:00 2001 From: Andrii Sokolenko Date: Wed, 22 Nov 2017 10:12:20 +0200 Subject: [PATCH 14/16] utest: rework output init func Change-Id: Ib1f07e1235ed654cf73d346730f94692dabf7438 Signed-off-by: Andrii Sokolenko --- utests/src/ut_tdm_output.cpp | 116 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 113 insertions(+), 3 deletions(-) diff --git a/utests/src/ut_tdm_output.cpp b/utests/src/ut_tdm_output.cpp index e3178c1..9c050ba 100644 --- a/utests/src/ut_tdm_output.cpp +++ b/utests/src/ut_tdm_output.cpp @@ -40,7 +40,7 @@ extern "C" { class TDMOutput : public ::testing::Test { protected: tdm_display *dpy = NULL; - int output_count = -42, master_fd = -42, tbm_fd = -42; + int output_count = 0, master_fd = -42, tbm_fd = -42; bool has_output = false; tbm_bufmgr tbm_bufmgr = NULL; static unsigned int handle_call; @@ -59,12 +59,14 @@ protected: setenv("XDG_RUNTIME_DIR", ".", 1); setenv("TBM_DLOG", "1", 1); setenv("TBM_DISPLAY_SERVER", "1", 1); - tbm_bufmgr = tbm_bufmgr_init(-1); - ASSERT_FALSE(tbm_bufmgr == NULL); + setenv("TDM_COMMIT_PER_VBLANK", "0", 1); + tdm_error error = TDM_ERROR_NONE; dpy = tdm_display_init(&error); ASSERT_TRUE(error == TDM_ERROR_NONE); ASSERT_FALSE(dpy == NULL); + tbm_bufmgr = tbm_bufmgr_init(-1); + ASSERT_FALSE(tbm_bufmgr == NULL); master_fd = tbm_drm_helper_get_master_fd(); tbm_fd = tbm_drm_helper_get_fd(); error = tdm_display_get_output_count(dpy, &output_count); @@ -99,9 +101,76 @@ protected: unsetenv("XDG_RUNTIME_DIR"); unsetenv("TBM_DLOG"); unsetenv("TBM_DISPLAY_SERVER"); + unsetenv("TDM_COMMIT_PER_VBLANK"); + } +}; + +class TDMOutputCommit : public TDMOutput { +protected: + int conn_output_count = 0; + tdm_output ** connected_output_array = NULL; + tdm_output_mode** preferred_mode = NULL; + bool has_output = false; + void SetUp(void) + { + ASSERT_NO_FATAL_FAILURE(TDMOutput::SetUp()); + if (TDMOutput::output_count > 0) { + connected_output_array = (tdm_output **) calloc(TDMOutput::output_count, sizeof(tdm_output *)); + ASSERT_FALSE(NULL == connected_output_array); + preferred_mode = (tdm_output_mode **) calloc(TDMOutput::output_count, sizeof(tdm_output_mode*)); + ASSERT_FALSE(NULL == preferred_mode); + } + conn_output_count = 0; + for (int i = 0; i < TDMOutput::output_count; i++) { + tdm_error error = TDM_ERROR_NONE; + int output_modes_cnt = 0; + const tdm_output_mode* output_modes = NULL; + tdm_output * output = tdm_display_get_output(TDMOutput::dpy, i, &error); + if (TDM_ERROR_NONE != error || NULL == output) + continue; + tdm_output_conn_status status = TDM_OUTPUT_CONN_STATUS_DISCONNECTED; + if (TDM_ERROR_NONE != tdm_output_get_conn_status(output, &status)) + continue; + if (TDM_OUTPUT_CONN_STATUS_DISCONNECTED == status) + continue; + if (TDM_ERROR_NONE != tdm_output_set_dpms(output, TDM_OUTPUT_DPMS_ON)) + continue; + if(TDM_ERROR_NONE != tdm_output_get_available_modes(output, + &output_modes, + &output_modes_cnt)) + continue; + for(int k = 0; k < output_modes_cnt; k++) { + if(output_modes[k].type & TDM_OUTPUT_MODE_TYPE_PREFERRED) { + preferred_mode[conn_output_count] = &output_modes[k]; + break; + } + } + if (NULL == preferred_mode[conn_output_count]) + continue; + connected_output_array[conn_output_count++] = output; + } +#ifdef FAIL_ON_UNSUPPORTED + ASSERT_GT(conn_output_count, 0); +#endif + + if (conn_output_count > 0) + has_output = true; + } + void TearDown(void) + { + for (int i = 0; i < conn_output_count; i++) { + EXPECT_TRUE(TDM_ERROR_NONE == tdm_output_set_dpms(connected_output_array[i], + TDM_OUTPUT_DPMS_OFF)); + } + if (connected_output_array) + free(connected_output_array); + if (preferred_mode) + free(preferred_mode); + ASSERT_NO_FATAL_FAILURE(TDMOutput::TearDown()); } }; + unsigned int TDMOutput::handle_call = 0; TEST_F(TDMOutput, DisplayGetOutputSuccessful) @@ -861,3 +930,44 @@ TEST_F(TDMOutput, OutputSetPropertyFailNullAll) error == TDM_ERROR_OPERATION_FAILED) exit(1); exit(0);}, ::testing::ExitedWithCode(0), ""); } + +TEST_F(TDMOutput, OutputGetPropertySuccessful) +{ + SKIP_FLAG(has_output); + for (int i = 0; i < output_count; i++) { + tdm_error error = TDM_ERROR_NONE; + tdm_value value = {.u32 = 0}; + tdm_output * output = tdm_display_get_output(dpy, i, &error); + ASSERT_FALSE(NULL == output); + ASSERT_TRUE(TDM_ERROR_NONE == error); + error = tdm_output_get_property(output, UINT_MAX, &value); + ASSERT_TRUE(error == TDM_ERROR_NOT_IMPLEMENTED || error == TDM_ERROR_OPERATION_FAILED); + } +} + +TEST_F(TDMOutput, OutputGetPropertyFailNullAll) +{ + SKIP_FLAG(has_output); + ASSERT_EXIT({tdm_error error = TDM_ERROR_NONE; + error = tdm_output_get_property(NULL, 0, NULL); + if (error == TDM_ERROR_NONE || error == TDM_ERROR_NOT_IMPLEMENTED || + error == TDM_ERROR_OPERATION_FAILED) exit(1); + exit(0);}, ::testing::ExitedWithCode(0), ""); +} + +TEST_F(TDMOutputCommit, OutputCommit) +{ + SKIP_FLAG(has_output); + for (int i = 0; i < conn_output_count; i++) { + ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_set_mode(connected_output_array[i], preferred_mode[i])); + ASSERT_TRUE(TDM_ERROR_NONE == tdm_output_commit(connected_output_array[i], 0, NULL, NULL)); + /* TODO: use a commit handler instead of an usleep to wait when + * commit will be applied */ + usleep(20000); + } +} + +TEST_F(TDMOutputCommit, DISABLED_OutputWaitVBlank) +{ + SKIP_FLAG(has_output); +} -- 2.7.4 From 44cbed62f18c39ef0ddadabf9ccf9c2e2cd28af5 Mon Sep 17 00:00:00 2001 From: Boram Park Date: Thu, 23 Nov 2017 14:39:47 +0900 Subject: [PATCH 15/16] server: correct wrong freeing Change-Id: I60595fa61f80ada4c4f2586eef8537cf38c04446 --- src/tdm_server.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/tdm_server.c b/src/tdm_server.c index b193ac6..b11911d 100644 --- a/src/tdm_server.c +++ b/src/tdm_server.c @@ -87,6 +87,7 @@ typedef struct _tdm_server_client_info { struct list_head link; pid_t pid; char name[TDM_NAME_LEN]; + struct wl_resource *resource; } tdm_server_client_info; static tdm_private_server *keep_private_server; @@ -700,15 +701,12 @@ destroy_client(struct wl_resource *resource) { tdm_server_client_info *c = NULL, *cc = NULL; struct wl_client *client; - pid_t pid = -1; client = wl_resource_get_client(resource); TDM_RETURN_IF_FAIL(client != NULL); - wl_client_get_credentials(client, &pid, NULL, NULL); - LIST_FOR_EACH_ENTRY_SAFE(c, cc, &client_list, link) { - if (c->pid == pid) { + if (c->resource == resource) { LIST_DEL(&c->link); free(c); return; @@ -736,6 +734,8 @@ _tdm_server_bind(struct wl_client *client, void *data, return; } + cinfo->resource = resource; + LIST_ADDTAIL(&cinfo->link, &client_list); wl_client_get_credentials(client, &cinfo->pid, NULL, NULL); _tdm_server_get_process_name(cinfo->pid, cinfo->name, TDM_NAME_LEN); @@ -907,14 +907,13 @@ tdm_server_deinit(tdm_private_loop *private_loop) wl_resource_destroy(o->resource); } + LIST_FOR_EACH_ENTRY_SAFE(c, cc, &client_list, link) { + wl_resource_destroy(c->resource); + } + free(private_server); private_loop->private_server = NULL; keep_private_server = NULL; - - LIST_FOR_EACH_ENTRY_SAFE(c, cc, &client_list, link) { - LIST_DEL(&c->link); - free(c); - } } INTERN const char* -- 2.7.4 From b11875cea5d971ff50a8c574811456bfd17a5e17 Mon Sep 17 00:00:00 2001 From: Boram Park Date: Thu, 23 Nov 2017 15:45:16 +0900 Subject: [PATCH 16/16] ttrace: enhance -ttrace_vblank option Change-Id: Ic3afb55d3b7cf06e8962bea0ee0f71322fc06d27 --- client/tdm_client.c | 21 ++++++++++++++--- protocol/tdm.xml | 4 ++++ src/tdm.c | 58 ++++++++++++++++++++++++++++----------------- src/tdm_monitor_server.c | 61 +++++++++++++++++++++++++++++------------------- src/tdm_private.h | 6 +++++ src/tdm_server.c | 44 +++++++++++++++++++++++++++++++--- src/tdm_vblank.c | 4 ---- 7 files changed, 142 insertions(+), 56 deletions(-) diff --git a/client/tdm_client.c b/client/tdm_client.c index 267854b..e576c3d 100644 --- a/client/tdm_client.c +++ b/client/tdm_client.c @@ -92,6 +92,7 @@ struct _tdm_private_client_vblank { unsigned int fps; int offset; unsigned int enable_fake; + unsigned int enable_ttrace; unsigned int started; unsigned int stamp; @@ -153,7 +154,8 @@ _tdm_client_vblank_cb_done(void *data, struct wl_tdm_vblank *wl_tdm_vblank, if (w->req_id != req_id) continue; - TDM_TRACE_ASYNC_END((int)w->req_time, "TDM_Client_Vblank:%u", private_vblank->stamp); + if (private_vblank->enable_ttrace) + TDM_TRACE_ASYNC_END((int)w->req_time, "TDM_Client_Vblank:%u", private_vblank->stamp); if (w->req_time >= private_vblank->last_time) TDM_WRN("'req(%.6f) < last(%.6f)' failed", w->req_time, private_vblank->last_time); @@ -170,9 +172,20 @@ _tdm_client_vblank_cb_done(void *data, struct wl_tdm_vblank *wl_tdm_vblank, } } +static void +_tdm_client_vblank_cb_ttrace(void *data, struct wl_tdm_vblank *wl_tdm_vblank, uint32_t enable) +{ + tdm_private_client_vblank *private_vblank = data; + + TDM_RETURN_IF_FAIL(private_vblank != NULL); + + private_vblank->enable_ttrace = enable; +} + static const struct wl_tdm_vblank_listener tdm_client_vblank_listener = { _tdm_client_vblank_cb_stamp, _tdm_client_vblank_cb_done, + _tdm_client_vblank_cb_ttrace, }; static void @@ -889,7 +902,8 @@ tdm_client_vblank_wait(tdm_client_vblank *vblank, unsigned int interval, tdm_cli wl_tdm_vblank_wait_vblank(private_vblank->vblank, interval, w->req_id, req_sec, req_usec); - TDM_TRACE_ASYNC_BEGIN((int)w->req_time, "TDM_Client_Vblank:%u", private_vblank->stamp); + if (private_vblank->enable_ttrace) + TDM_TRACE_ASYNC_BEGIN((int)w->req_time, "TDM_Client_Vblank:%u", private_vblank->stamp); TDM_DBG("vblank(%p) interval(%u) req_id(%d) req(%.6f)", vblank, interval, w->req_id, w->req_time); @@ -973,7 +987,8 @@ tdm_client_vblank_wait_seq(tdm_client_vblank *vblank, unsigned int sequence, wl_tdm_vblank_wait_vblank_seq(private_vblank->vblank, sequence, w->req_id, req_sec, req_usec); - TDM_TRACE_ASYNC_BEGIN((int)w->req_time, "TDM_Client_Vblank:%u", private_vblank->stamp); + if (private_vblank->enable_ttrace) + TDM_TRACE_ASYNC_BEGIN((int)w->req_time, "TDM_Client_Vblank:%u", private_vblank->stamp); TDM_DBG("vblank(%p) sequence(%u) req_id(%d) req(%.6f)", vblank, sequence, w->req_id, w->req_time); diff --git a/protocol/tdm.xml b/protocol/tdm.xml index 0947115..24c603e 100644 --- a/protocol/tdm.xml +++ b/protocol/tdm.xml @@ -86,6 +86,10 @@ + + + + diff --git a/src/tdm.c b/src/tdm.c index 53732ac..7c36041 100644 --- a/src/tdm.c +++ b/src/tdm.c @@ -201,6 +201,13 @@ _tdm_display_destroy_private_output(tdm_private_output *private_output) _pthread_mutex_lock(&private_display->lock); } + if (private_output->ttrace_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->ttrace_vblank); + _pthread_mutex_lock(&private_display->lock); + } + LIST_FOR_EACH_ENTRY_SAFE(c, cc, &private_output->capture_list, link) tdm_capture_destroy_internal(c); @@ -1281,14 +1288,13 @@ 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("TDM_DISPLAY_TTRACE_VBlank"); + TDM_TRACE_MARK("VSYNC"); ret = tdm_vblank_wait(vblank, 0, 0, 1, _tdm_display_ttrace_vblank_cb, NULL); TDM_RETURN_IF_FAIL(ret == TDM_ERROR_NONE); @@ -1297,42 +1303,50 @@ _tdm_display_ttrace_vblank_cb(tdm_vblank *vblank, tdm_error error, unsigned int INTERN tdm_error tdm_display_enable_ttrace_vblank(tdm_display *dpy, tdm_output *output, int enable) { - static tdm_vblank *vblank = NULL; + tdm_private_display *private_display = dpy; + tdm_private_output *private_output = NULL; + const tdm_output_mode *mode = NULL; + tdm_vblank *vblank = NULL; tdm_error ret = TDM_ERROR_NONE; if (!enable) { - if (vblank) - tdm_vblank_destroy(vblank); - vblank = NULL; + LIST_FOR_EACH_ENTRY(private_output, &private_display->output_list, link) { + if (private_output->ttrace_vblank) + tdm_vblank_destroy(private_output->ttrace_vblank); + private_output->ttrace_vblank = NULL; + } return TDM_ERROR_NONE; - } else { - const tdm_output_mode *mode = NULL; + } - if (vblank) - return TDM_ERROR_NONE; + private_output = output; + TDM_RETURN_VAL_IF_FAIL(private_output != NULL, TDM_ERROR_INVALID_PARAMETER); - vblank = tdm_vblank_create(dpy, output, &ret); - TDM_RETURN_VAL_IF_FAIL(vblank != NULL, ret); + if (private_output->ttrace_vblank) + return TDM_ERROR_NONE; - ret = tdm_output_get_mode(output, &mode); - TDM_GOTO_IF_FAIL(mode != NULL, enable_fail); + vblank = tdm_vblank_create(private_display, output, &ret); + TDM_RETURN_VAL_IF_FAIL(vblank != NULL, ret); - ret = tdm_vblank_set_fps(vblank, mode->vrefresh); - TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, enable_fail); + ret = tdm_output_get_mode(output, &mode); + TDM_GOTO_IF_FAIL(mode != NULL, enable_fail); - ret = tdm_vblank_set_enable_fake(vblank, 1); - TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, enable_fail); + ret = tdm_vblank_set_fps(vblank, mode->vrefresh); + 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); - } + 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); + + private_output->ttrace_vblank = vblank; return TDM_ERROR_NONE; enable_fail: if (vblank) tdm_vblank_destroy(vblank); - vblank = NULL; + return ret; } diff --git a/src/tdm_monitor_server.c b/src/tdm_monitor_server.c index 07c2487..0d92cef 100644 --- a/src/tdm_monitor_server.c +++ b/src/tdm_monitor_server.c @@ -108,12 +108,9 @@ _tdm_monitor_server_dpms(unsigned int pid, char *cwd, int argc, char *argv[], ch static void _tdm_monitor_server_ttrace_vblank(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy) { - int enable, output_id = 0; - tdm_output *output; + int ttrace_vblank, output_id = 0; char *arg; char *end; - tdm_error ret; - tdm_output_type type; if (argc < 3) { _tdm_monitor_server_usage(argv[0], reply, len); @@ -121,29 +118,45 @@ _tdm_monitor_server_ttrace_vblank(unsigned int pid, char *cwd, int argc, char *a } arg = argv[2]; - enable = strtol(arg, &end, 10); + ttrace_vblank = strtol(arg, &end, 10); - if (*end == '@') { - arg = end + 1; - output_id = strtol(arg, &end, 10); - } + if (ttrace_vblank > 0) { + tdm_output *output; + tdm_error ret; + tdm_output_type type; + char *temp; - output = tdm_display_get_output(dpy, output_id, NULL); - if (!output) { - TDM_SNPRINTF(reply, len, "can't find the output_id(%d)\n", output_id); - return; - } + if (*end == '@') { + arg = end + 1; + output_id = strtol(arg, &end, 10); + } - ret = tdm_output_get_output_type(output, &type); - if (ret != TDM_ERROR_NONE) { - TDM_SNPRINTF(reply, len, "can't find the type of output_id(%d)\n", output_id); - return; - } + output = tdm_display_get_output(dpy, output_id, NULL); + if (!output) { + TDM_SNPRINTF(reply, len, "can't find the output_id(%d)\n", output_id); + return; + } - tdm_display_enable_ttrace_vblank(dpy, output, enable); + ret = tdm_output_get_output_type(output, &type); + if (ret != TDM_ERROR_NONE) { + TDM_SNPRINTF(reply, len, "can't find the type of output_id(%d)\n", output_id); + return; + } - TDM_SNPRINTF(reply, len, "%s ttrace vblank for '%s'\n", - (enable) ? "enable" : "disable", tdm_conn_str(type)); + temp = "server"; + tdm_display_enable_ttrace_vblank(dpy, output, 1); + + if (ttrace_vblank > 1) { + temp = "clients"; + tdm_server_enable_ttrace_vblank(dpy, output, 1); + } + + TDM_SNPRINTF(reply, len, "enable ttrace vblank for '%s': %s \n", tdm_conn_str(type), temp); + } else { + tdm_display_enable_ttrace_vblank(dpy, NULL, 0); + tdm_server_enable_ttrace_vblank(dpy, NULL, 0); + TDM_SNPRINTF(reply, len, "disable ttrace vblank\n"); + } } static void @@ -534,8 +547,8 @@ static struct { }, { "ttrace_vblank", _tdm_monitor_server_ttrace_vblank, - "enable/disable the vblank for ttrace [0:disable 1:enable]", - "[@]", "0 or 1" + "enable/disable the vblank for ttrace [0:disable, 1:server, 2:clients]", + "[@]", "0 or 1 or 2 or 1@0 or 2@0 or 1@1 or 2@1" }, { "debug", _tdm_monitor_server_debug, diff --git a/src/tdm_private.h b/src/tdm_private.h index 92bb4a1..5e63e5c 100644 --- a/src/tdm_private.h +++ b/src/tdm_private.h @@ -235,6 +235,10 @@ struct _tdm_private_output { /* calling a output commit per a vblank */ int commit_per_vblank; tdm_commit_type commit_type; + + /* for ttrace vblank */ + tdm_vblank *ttrace_vblank; + unsigned int ttrace_vblank_client; }; struct _tdm_private_layer { @@ -653,6 +657,8 @@ void tdm_server_deinit(tdm_private_loop *private_loop); const char* tdm_server_get_client_name(pid_t pid); +tdm_error +tdm_server_enable_ttrace_vblank(tdm_display *dpy, tdm_output *output, int enable); char * tdm_helper_dump_make_directory(const char *path, char *reply, int *len); diff --git a/src/tdm_server.c b/src/tdm_server.c index b11911d..f56b1ad 100644 --- a/src/tdm_server.c +++ b/src/tdm_server.c @@ -88,6 +88,7 @@ typedef struct _tdm_server_client_info { pid_t pid; char name[TDM_NAME_LEN]; struct wl_resource *resource; + tdm_private_server *private_server; } tdm_server_client_info; static tdm_private_server *keep_private_server; @@ -167,6 +168,7 @@ _tdm_server_send_done(tdm_server_wait_info *wait_info, tdm_error error, { tdm_server_wait_info *found; tdm_server_vblank_info *vblank_info; + tdm_private_output *private_output; if (!keep_private_server) return; @@ -185,7 +187,9 @@ _tdm_server_send_done(tdm_server_wait_info *wait_info, tdm_error error, wl_tdm_vblank_send_done(vblank_info->resource, wait_info->req_id, sequence, tv_sec, tv_usec, error); - TDM_TRACE_ASYNC_END((int)wait_info->req_time, "TDM_Server_Vblank:%u", vblank_info->stamp); + private_output = vblank_info->output_info->output; + if (private_output->ttrace_vblank_client) + TDM_TRACE_ASYNC_END((int)wait_info->req_time, "TDM_Server_Vblank:%u", vblank_info->stamp); destroy_wait(wait_info); } @@ -304,6 +308,7 @@ _tdm_server_vblank_cb_wait_vblank(struct wl_client *client, struct wl_resource * tdm_server_vblank_info *vblank_info = wl_resource_get_user_data(resource); tdm_server_output_info *output_info = vblank_info->output_info; tdm_private_server *private_server = output_info->private_server; + tdm_private_output *private_output = output_info->output; tdm_server_wait_info *wait_info; unsigned int enable_fake = 0; tdm_error ret; @@ -323,7 +328,9 @@ _tdm_server_vblank_cb_wait_vblank(struct wl_client *client, struct wl_resource * if (tdm_debug_module & TDM_DEBUG_VBLANK) TDM_DBG("req_id(%d) wait", req_id); - TDM_TRACE_ASYNC_BEGIN((int)wait_info->req_time, "TDM_Server_Vblank:%u", vblank_info->stamp); + private_output = vblank_info->output_info->output; + if (private_output->ttrace_vblank_client) + TDM_TRACE_ASYNC_BEGIN((int)wait_info->req_time, "TDM_Server_Vblank:%u", vblank_info->stamp); ret = tdm_vblank_wait(vblank_info->vblank, req_sec, req_usec, interval, _tdm_server_cb_vblank, wait_info); @@ -347,6 +354,7 @@ _tdm_server_vblank_cb_wait_vblank_seq(struct wl_client *client, struct wl_resour tdm_server_vblank_info *vblank_info = wl_resource_get_user_data(resource); tdm_server_output_info *output_info = vblank_info->output_info; tdm_private_server *private_server = output_info->private_server; + tdm_private_output *private_output = output_info->output; tdm_server_wait_info *wait_info; unsigned int enable_fake = 0; tdm_error ret; @@ -366,7 +374,9 @@ _tdm_server_vblank_cb_wait_vblank_seq(struct wl_client *client, struct wl_resour if (tdm_debug_module & TDM_DEBUG_VBLANK) TDM_DBG("req_id(%d) wait", req_id); - TDM_TRACE_ASYNC_BEGIN((int)wait_info->req_time, "TDM_Server_Vblank:%u", vblank_info->stamp); + private_output = vblank_info->output_info->output; + if (private_output->ttrace_vblank_client) + TDM_TRACE_ASYNC_BEGIN((int)wait_info->req_time, "TDM_Server_Vblank:%u", vblank_info->stamp); ret = tdm_vblank_wait_seq(vblank_info->vblank, req_sec, req_usec, sequence, _tdm_server_cb_vblank, wait_info); @@ -735,6 +745,7 @@ _tdm_server_bind(struct wl_client *client, void *data, } cinfo->resource = resource; + cinfo->private_server = data; LIST_ADDTAIL(&cinfo->link, &client_list); wl_client_get_credentials(client, &cinfo->pid, NULL, NULL); @@ -928,3 +939,30 @@ tdm_server_get_client_name(pid_t pid) return NULL; } + +INTERN tdm_error +tdm_server_enable_ttrace_vblank(tdm_display *dpy, tdm_output *output, int enable) +{ + tdm_server_client_info *cinfo = NULL; + + LIST_FOR_EACH_ENTRY(cinfo, &client_list, link) { + tdm_private_server *private_server = cinfo->private_server; + tdm_server_output_info *output_info = NULL; + + LIST_FOR_EACH_ENTRY(output_info, &private_server->output_list, link) { + tdm_server_vblank_info *vblank_info = NULL; + tdm_private_output *private_output = output_info->output; + + if (output && output_info->output != output) + continue; + + private_output->ttrace_vblank_client = enable; + + LIST_FOR_EACH_ENTRY(vblank_info, &output_info->vblank_list, link) { + wl_tdm_vblank_send_ttrace(vblank_info->resource, enable); + } + } + } + + return TDM_ERROR_NONE; +} diff --git a/src/tdm_vblank.c b/src/tdm_vblank.c index 1a3f6b9..462eaf5 100644 --- a/src/tdm_vblank.c +++ b/src/tdm_vblank.c @@ -771,8 +771,6 @@ _tdm_vblank_cb_vblank_HW(tdm_output *output, unsigned int sequence, return; } - TDM_TRACE_ASYNC_END((int)wait_info->req_time, "TDM_HW_Vblank:%u", (unsigned int)private_vblank->stamp); - if (wait_info->type == VBLANK_TYPE_HW_SW) { tdm_error ret; @@ -883,8 +881,6 @@ _tdm_vblank_wait_HW(tdm_vblank_wait_info *wait_info) skip, hw_interval, wait_info->target_seq); } - TDM_TRACE_ASYNC_BEGIN((int)wait_info->req_time, "TDM_HW_Vblank:%u", (unsigned int)private_vblank->stamp); - if (private_vblank->add_front) ret = tdm_output_wait_vblank_add_front(private_vblank->output, hw_interval, 0, _tdm_vblank_cb_vblank_HW, wait_info); -- 2.7.4