From 58828ed23597b6ba74af0b6a76af7d04b5677e50 Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Mon, 14 May 2018 15:31:48 +0900 Subject: [PATCH 01/16] package version up to 1.18.2 Change-Id: I9497d4acca1549053030f5865016d825fd17413e --- packaging/libtdm.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packaging/libtdm.spec b/packaging/libtdm.spec index f3d74ce..9be0331 100644 --- a/packaging/libtdm.spec +++ b/packaging/libtdm.spec @@ -2,7 +2,7 @@ %define HALTESTS_GCOV 0 Name: libtdm -Version: 1.18.1 +Version: 1.18.2 Release: 0 Summary: User Library of Tizen Display Manager Group: Development/Libraries -- 2.7.4 From c62d87e018d27ccd2074b3ef26a37b60110e5d0d Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Mon, 21 May 2018 16:46:11 +0900 Subject: [PATCH 02/16] define the backend ABI version The TDM backend ABI version should be separated with TDM front-end ABI. Therefore, tdm defines the TDM backend ABI version at the tbm_backend.h. The tdm checks the module ABI version with this backend ABI version when the libtdm loads the backend modules. Change-Id: I80d842f225d261f7fc024c6928dc66c9d4a95a65 --- include/tdm_backend.h | 5 +++++ src/tdm.c | 27 ++++++++++++++++----------- src/tdm_backend.c | 10 ++-------- 3 files changed, 23 insertions(+), 19 deletions(-) diff --git a/include/tdm_backend.h b/include/tdm_backend.h index 53f979a..e9fc70d 100644 --- a/include/tdm_backend.h +++ b/include/tdm_backend.h @@ -1134,6 +1134,11 @@ typedef tdm_error (*tdm_event_loop_timer_handler)(void *user_data); (((major) << 16) & TDM_BACKEND_MAJOR_VERSION_MASK) | \ ((minor) & TDM_BACKEND_MINOR_VERSION_MASK) + +#define TDM_BACKEND_ABI_VERSION_1_0 TDM_BACKEND_SET_ABI_VERSION(1, 0) +#define TDM_BACKEND_ABI_VERSION_2_0 TDM_BACKEND_SET_ABI_VERSION(2, 0) +#define TDM_BACKEND_ABI_LATEST_VERSION TDM_BACKEND_ABI_VERSION_2_0 /**< the latest version of the tdm backend abi */ + /** * @brief * This MACRO is deprecated since 1.2.0. Use TDM_BACKEND_SET_ABI_VERSION instead of this. diff --git a/src/tdm.c b/src/tdm.c index bc59c3c..6f938ec 100644 --- a/src/tdm.c +++ b/src/tdm.c @@ -745,10 +745,14 @@ static pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER; static tdm_error _tdm_display_check_module(tdm_backend_module *module) { - int major, minor; + int tdm_backend_major, tdm_backend_minor; + int backend_module_major, backend_module_minor; - TDM_INFO("TDM ABI version : %d.%d", - TDM_MAJOR_VERSION, TDM_MINOR_VERSION); + tdm_backend_major = TDM_BACKEND_GET_ABI_MAJOR(TDM_BACKEND_ABI_LATEST_VERSION); + tdm_backend_minor = TDM_BACKEND_GET_ABI_MINOR(TDM_BACKEND_ABI_LATEST_VERSION); + + TDM_INFO("TDM Backend ABI version : %d.%d", + tdm_backend_major, tdm_backend_minor); if (!module->name) { TDM_ERR("TDM backend doesn't have name"); @@ -760,22 +764,23 @@ _tdm_display_check_module(tdm_backend_module *module) return TDM_ERROR_BAD_MODULE; } - major = TDM_BACKEND_GET_ABI_MAJOR(module->abi_version); - minor = TDM_BACKEND_GET_ABI_MINOR(module->abi_version); + backend_module_major = TDM_BACKEND_GET_ABI_MAJOR(module->abi_version); + backend_module_minor = TDM_BACKEND_GET_ABI_MINOR(module->abi_version); TDM_INFO("TDM module name: %s", module->name); TDM_INFO("'%s' vendor: %s", module->name, module->vendor); - TDM_INFO("'%s' version: %d.%d", module->name, major, minor); + TDM_INFO("'%s' backend ABI version: %d.%d", module->name, backend_module_major, backend_module_minor); - if (major != TDM_MAJOR_VERSION) { - TDM_ERR("'%s' major version mismatch, %d != %d", - module->name, major, TDM_MAJOR_VERSION); + if (backend_module_major > tdm_backend_major) { + TDM_ERR("'%s' major version(%d) is newer than %d", + module->name, backend_module_major, tdm_backend_major); return TDM_ERROR_BAD_MODULE; } - if (minor > TDM_MINOR_VERSION) { + if (tdm_backend_major == backend_module_major && + backend_module_minor > tdm_backend_minor) { TDM_ERR("'%s' minor version(%d) is newer than %d", - module->name, minor, TDM_MINOR_VERSION); + module->name, backend_module_minor, tdm_backend_minor); return TDM_ERROR_BAD_MODULE; } diff --git a/src/tdm_backend.c b/src/tdm_backend.c index 13ea24c..c979129 100644 --- a/src/tdm_backend.c +++ b/src/tdm_backend.c @@ -146,10 +146,7 @@ tdm_backend_register_func_hwc(tdm_display *dpy, tdm_func_hwc *func_hwc) assert(private_display->current_module); module = private_display->current_module->module_data; - /* FIX ME: - Temporarily, we set the version of hwc window to 1.1 for the development. - Originally the hwc window version is 2.0. */ - if (_check_abi_version(module, 1, 1) < 0) + if (_check_abi_version(module, 2, 0) < 0) return TDM_ERROR_BAD_MODULE; private_display->current_module->func_hwc = *func_hwc; @@ -171,10 +168,7 @@ tdm_backend_register_func_hwc_window(tdm_display *dpy, tdm_func_hwc_window *func assert(private_display->current_module); module = private_display->current_module->module_data; - /* FIX ME: - Temporarily, we set the version of hwc window to 1.1 for the development. - Originally the hwc window version is 2.0. */ - if (_check_abi_version(module, 1, 1) < 0) + if (_check_abi_version(module, 2, 0) < 0) return TDM_ERROR_BAD_MODULE; private_display->current_module->func_hwc_window = *func_hwc_window; -- 2.7.4 From 78d22f2de14be04a4878d20649e2bc0df9fbb8c7 Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Mon, 21 May 2018 16:49:58 +0900 Subject: [PATCH 03/16] package version up to 2.0.0 - add haltest cases - add the new backend APIs for the TDM-HWC at tdm_backend.h - increase the major verion of the TBM backend ABI to version 2.0 The tdm backend module needs to set the valid backend version. Change-Id: I62538cb7d634e465e007900e7b49595ea4cd9226 --- configure.ac | 4 ++-- packaging/libtdm.spec | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/configure.ac b/configure.ac index dd27580..3d13ec7 100644 --- a/configure.ac +++ b/configure.ac @@ -1,7 +1,7 @@ AC_PREREQ([2.60]) -m4_define([tdm_major_version], [1]) -m4_define([tdm_minor_version], [16]) +m4_define([tdm_major_version], [2]) +m4_define([tdm_minor_version], [0]) m4_define([tdm_micro_version], [0]) m4_define([tdm_version], [tdm_major_version.tdm_minor_version.tdm_micro_version]) diff --git a/packaging/libtdm.spec b/packaging/libtdm.spec index 9be0331..5bcae43 100644 --- a/packaging/libtdm.spec +++ b/packaging/libtdm.spec @@ -2,7 +2,7 @@ %define HALTESTS_GCOV 0 Name: libtdm -Version: 1.18.2 +Version: 2.0.0 Release: 0 Summary: User Library of Tizen Display Manager Group: Development/Libraries -- 2.7.4 From 3ada4a19f780e3d8dbe3166a7c8af0c8fee1c4f2 Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Wed, 30 May 2018 10:39:46 +0900 Subject: [PATCH 04/16] tc: add tests for tdm_hwc and tdm_hwc_window Change-Id: Id19c9f11771397f60204ef5a6af07576f4da7f37 --- haltests/Makefile.am | 4 +- haltests/src/tc_tdm_hwc.cpp | 525 +++++++++++++++++++++++++++++++++++++ haltests/src/tc_tdm_hwc_window.cpp | 351 +++++++++++++++---------- haltests/src/tc_tdm_output_hwc.cpp | 429 ------------------------------ 4 files changed, 739 insertions(+), 570 deletions(-) create mode 100644 haltests/src/tc_tdm_hwc.cpp delete mode 100644 haltests/src/tc_tdm_output_hwc.cpp diff --git a/haltests/Makefile.am b/haltests/Makefile.am index 276b503..278e1ef 100644 --- a/haltests/Makefile.am +++ b/haltests/Makefile.am @@ -15,7 +15,9 @@ tdm_haltests_SOURCES = \ src/tc_tdm_backend_env.cpp \ src/tc_tdm_backend_display.cpp \ src/tc_tdm_backend_pp.cpp \ - src/tc_tdm_backend_capture.cpp + src/tc_tdm_backend_capture.cpp \ + src/tc_tdm_hwc.cpp \ + src/tc_tdm_hwc_window.cpp tdm_haltests_SOURCES += \ ../tools/buffers.c diff --git a/haltests/src/tc_tdm_hwc.cpp b/haltests/src/tc_tdm_hwc.cpp new file mode 100644 index 0000000..545c6a0 --- /dev/null +++ b/haltests/src/tc_tdm_hwc.cpp @@ -0,0 +1,525 @@ +/************************************************************************** + * + * 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 "tc_tdm.h" + +/* LCOV_EXCL_START */ + +#define HWC_WIN_NUM 5 + +class TDMHwc : public TDMOutput +{ +public: + TDMHwc(); + void SetUp(void); + void TearDown(void); + + tdm_error error; +}; + +TDMHwc::TDMHwc() +{ + error = TDM_ERROR_NONE; +} + +void TDMHwc::SetUp(void) +{ + TDMOutput::SetUp(); +} + +void TDMHwc::TearDown(void) +{ + TDMOutput::TearDown(); +} + +static void +_tc_tdm_hwc_commit_cb(tdm_hwc *hwc, unsigned int sequence, + unsigned int tv_sec, unsigned int tv_usec, + void *user_data) +{ + bool *done = (bool*)user_data; + if (done) + *done = true; +} + +/* tdm_hwc_window * tdm_hwc_create_window(tdm_output *output, tdm_error *error); */ +TEST_P(TDMHwc, CreateWindowFailNull) +{ + TDM_UT_SKIP_FLAG(has_outputs); + + ASSERT_EQ(NULL, tdm_hwc_create_window(NULL, &error)); + ASSERT_NE(TDM_ERROR_NONE, error); +} + +TEST_P(TDMHwc, CreateWindowSuccessful) +{ + TDM_UT_SKIP_FLAG(has_outputs); + + tdm_hwc *hwc = NULL; + tdm_error error; + tdm_hwc_window * hw = NULL; + + for (int o = 0; o < output_count; o++) { + hwc = tdm_output_get_hwc(outputs[o], &error); + if (hwc) { + hw = tdm_hwc_create_window(hwc, &error); + ASSERT_EQ(TDM_ERROR_NONE, error); + tdm_hwc_window_destroy(hw); + } else { + ASSERT_EQ(NULL, tdm_hwc_create_window(hwc, &error)); + ASSERT_NE(TDM_ERROR_NONE, error); + } + } +} + +/* tdm_hwc_get_supported_formats() */ +TEST_P(TDMHwc, GetSupportedFormatsFailNull) +{ + TDM_UT_SKIP_FLAG(has_outputs); + + tdm_error error; + + error = tdm_hwc_get_supported_formats(NULL, NULL, NULL); + ASSERT_NE(TDM_ERROR_NONE, error); +} + +TEST_P(TDMHwc, GetSupportedFormatsSuccessful) +{ + TDM_UT_SKIP_FLAG(has_outputs); + + tdm_hwc *hwc = NULL; + tdm_error error = TDM_ERROR_NONE; + const tbm_format *formats; + int count; + + for (int o = 0; o < output_count; o++) { + hwc = tdm_output_get_hwc(outputs[o], &error); + if (hwc) { + error = tdm_hwc_get_supported_formats(hwc, &formats, &count); + if (error != TDM_ERROR_NOT_IMPLEMENTED) { + ASSERT_EQ(TDM_ERROR_NONE, error); + if (count > 0) + ASSERT_NE(NULL, formats); + } + } else { + error = tdm_hwc_get_supported_formats(hwc, &formats, &count); + ASSERT_NE(TDM_ERROR_NONE, error); + } + } +} + +/* tdm_hwc_get_available_properties() */ +TEST_P(TDMHwc, GetAvailablePropertiesFailNullWin) +{ + TDM_UT_SKIP_FLAG(has_outputs); + + tdm_hwc *hwc = NULL; + tdm_error error = TDM_ERROR_NONE; + const tdm_prop *props; + int count; + + for (int o = 0; o < output_count; o++) { + hwc = tdm_output_get_hwc(outputs[o], &error); + if (hwc) { + error = tdm_hwc_get_available_properties(NULL, &props, &count); + ASSERT_NE(TDM_ERROR_NONE, error); + + error = tdm_hwc_get_available_properties(hwc, NULL, &count); + ASSERT_NE(TDM_ERROR_NONE, error); + + error = tdm_hwc_get_available_properties(hwc, &props, NULL); + ASSERT_NE(TDM_ERROR_NONE, error); + } else { + error = tdm_hwc_get_available_properties(hwc, &props, &count); + ASSERT_NE(TDM_ERROR_NONE, error); + } + } +} + +TEST_P(TDMHwc, GetAvailablePropertiesSuccess) +{ + TDM_UT_SKIP_FLAG(has_outputs); + + tdm_hwc *hwc = NULL; + tdm_error error = TDM_ERROR_NONE; + const tdm_prop *props; + int count; + + for (int o = 0; o < output_count; o++) { + hwc = tdm_output_get_hwc(outputs[o], &error); + if (hwc) { + error = tdm_hwc_get_available_properties(hwc, &props, &count); + ASSERT_TRUE(TDM_ERROR_NONE == error || TDM_ERROR_NOT_IMPLEMENTED == error); + } else { + error = tdm_hwc_get_available_properties(hwc, &props, &count); + ASSERT_NE(TDM_ERROR_NONE, error); + } + } + +} + +/* tdm_hwc_get_client_target_buffer_queue() */ +TEST_P(TDMHwc, GetClientTargetBufferQueueFailNullObject) +{ + TDM_UT_SKIP_FLAG(has_outputs); + + tdm_hwc *hwc = NULL; + tdm_error error = TDM_ERROR_NONE; + tbm_surface_queue_h queue = NULL; + + for (int o = 0; o < output_count; o++) { + hwc = tdm_output_get_hwc(outputs[o], &error); + if (hwc) { + queue = tdm_hwc_get_client_target_buffer_queue(NULL, &error); + ASSERT_NE(TDM_ERROR_NONE, error); + ASSERT_EQ(NULL, queue); + + queue = tdm_hwc_get_client_target_buffer_queue(NULL, NULL); + ASSERT_EQ(NULL, queue); + } else { + ASSERT_EQ(NULL, queue); + } + } +} + +TEST_P(TDMHwc, GetClientTargetBufferQueueFainNoHwc) +{ + TDM_UT_SKIP_FLAG(has_outputs); + + tdm_hwc *hwc = NULL; + tdm_error error = TDM_ERROR_NONE; + tbm_surface_queue_h queue = NULL; + + for (int o = 0; o < output_count; o++) { + hwc = tdm_output_get_hwc(outputs[o], &error); + if (hwc) { + queue = tdm_hwc_get_client_target_buffer_queue(hwc, &error); + ASSERT_EQ(TDM_ERROR_NONE, error); + ASSERT_NE(NULL, queue); + } else { + queue = tdm_hwc_get_client_target_buffer_queue(hwc, &error); + ASSERT_NE(TDM_ERROR_NONE, error); + ASSERT_EQ(NULL, queue); + } + } +} + +TEST_P(TDMHwc, GetClientTargetBufferQueueSuccessful) +{ + TDM_UT_SKIP_FLAG(has_outputs); + + tdm_hwc *hwc = NULL; + tdm_error error = TDM_ERROR_NONE; + tbm_surface_queue_h queue = NULL; + + for (int o = 0; o < output_count; o++) { + hwc = tdm_output_get_hwc(outputs[o], &error); + if (hwc) { + queue = tdm_hwc_get_client_target_buffer_queue(hwc, &error); + tbm_surface_queue_destroy(queue); + ASSERT_EQ(TDM_ERROR_NONE, error); + ASSERT_NE(NULL, queue); + + queue = tdm_hwc_get_client_target_buffer_queue(hwc, NULL); + tbm_surface_queue_destroy(queue); + ASSERT_EQ(TDM_ERROR_NONE, error); + ASSERT_NE(NULL, queue); + } else { + queue = tdm_hwc_get_client_target_buffer_queue(hwc, &error); + ASSERT_NE(TDM_ERROR_NONE, error); + ASSERT_EQ(NULL, queue); + + queue = tdm_hwc_get_client_target_buffer_queue(hwc, NULL); + ASSERT_NE(TDM_ERROR_NONE, error); + ASSERT_EQ(NULL, queue); + } + } +} + +/* tdm_hwc_set_client_target_buffer() */ +TEST_P(TDMHwc, SetClientTargetBufferFailNullOutput) +{ + TDM_UT_SKIP_FLAG(has_outputs); + + tdm_region damage = {.num_rects = 0, .rects = NULL}; + tbm_surface_h target_buff = NULL; + + target_buff = tbm_surface_internal_create_with_flags(720, 1024, + TBM_FORMAT_ARGB8888, TBM_BO_DEFAULT); + ASSERT_NE(NULL, target_buff); + + error = tdm_hwc_set_client_target_buffer(NULL, target_buff, damage); + tbm_surface_internal_destroy(target_buff); + ASSERT_NE(TDM_ERROR_NONE, error); +} + +TEST_P(TDMHwc, SetClientTargetBufferSuccessfulSetBuff) +{ + TDM_UT_SKIP_FLAG(has_outputs); + + tdm_hwc *hwc = NULL; + tdm_error error = TDM_ERROR_NONE; + tdm_region damage = {.num_rects = 0, .rects = NULL}; + const tdm_output_mode *mode = NULL; + tbm_surface_h target_buff = NULL; + + for (int o = 0; o < output_count; o++) { + hwc = tdm_output_get_hwc(outputs[o], &error); + if (hwc) { + ASSERT_EQ(tdm_output_get_mode(outputs[o], &mode), TDM_ERROR_NONE); + target_buff = tbm_surface_internal_create_with_flags(mode->hdisplay, mode->vdisplay, + TBM_FORMAT_ARGB8888, TBM_BO_DEFAULT); + ASSERT_NE(NULL, target_buff); + + error = tdm_hwc_set_client_target_buffer(hwc, target_buff, damage); + tbm_surface_internal_destroy(target_buff); + ASSERT_EQ(TDM_ERROR_NONE, error); + } else { + error = tdm_hwc_set_client_target_buffer(hwc, target_buff, damage); + ASSERT_NE(TDM_ERROR_NONE, error); + } + } +} + +TEST_P(TDMHwc, SetClientTargetBufferSuccessfulResetBuff) +{ + TDM_UT_SKIP_FLAG(has_outputs); + + tdm_hwc *hwc = NULL; + tdm_error error = TDM_ERROR_NONE; + tdm_region damage = {.num_rects = 0, .rects = NULL}; + tbm_surface_h target_buff = NULL; + + for (int o = 0; o < output_count; o++) { + hwc = tdm_output_get_hwc(outputs[o], &error); + if (hwc) { + error = tdm_hwc_set_client_target_buffer(hwc, NULL, damage); + tbm_surface_internal_destroy(target_buff); + ASSERT_EQ(TDM_ERROR_NONE, error); + } else { + error = tdm_hwc_set_client_target_buffer(hwc, NULL, damage); + ASSERT_NE(TDM_ERROR_NONE, error); + } + } +} + +/* tdm_hwc_validate() */ +TEST_P(TDMHwc, ValidateFailNull) +{ + TDM_UT_SKIP_FLAG(has_outputs); + + tdm_hwc *hwc = NULL; + tdm_error error = TDM_ERROR_NONE; + uint32_t num_types; + + error = tdm_hwc_validate(NULL, NULL, 0, &num_types); + ASSERT_NE(TDM_ERROR_NONE, error); + + for (int o = 0; o < output_count; o++) { + hwc = tdm_output_get_hwc(outputs[o], &error); + if (hwc) { + error = tdm_hwc_validate(hwc, NULL, 0, NULL); + ASSERT_NE(TDM_ERROR_NONE, error); + } else { + error = tdm_hwc_validate(hwc, NULL, 0, NULL); + ASSERT_NE(TDM_ERROR_NONE, error); + } + } +} + +/* tdm_hwc_get_changed_composition_types() */ +TEST_P(TDMHwc, GetChangedCompositionTypesFailNull) +{ + TDM_UT_SKIP_FLAG(has_outputs); + + tdm_hwc *hwc = NULL; + tdm_error error = TDM_ERROR_NONE; + uint32_t num_elements; + + error = tdm_hwc_get_changed_composition_types(NULL, &num_elements, NULL, NULL); + ASSERT_NE(TDM_ERROR_NONE, error); + + for (int o = 0; o < output_count; o++) { + hwc = tdm_output_get_hwc(outputs[o], &error); + if (hwc) { + error = tdm_hwc_get_changed_composition_types(hwc, NULL, NULL, NULL); + ASSERT_NE(TDM_ERROR_NONE, error); + } else { + error = tdm_hwc_get_changed_composition_types(hwc, NULL, NULL, NULL); + ASSERT_NE(TDM_ERROR_NONE, error); + } + } +} + +/* tdm_error tdm_hwc_accept_changes() */ +TEST_P(TDMHwc, AcceptChangesFailNull) +{ + TDM_UT_SKIP_FLAG(has_outputs); + + error = tdm_hwc_accept_changes(NULL); + ASSERT_NE(TDM_ERROR_NONE, error); +} + +TEST_P(TDMHwc, AcceptChangesFailNoHwc) +{ + tdm_hwc *hwc = NULL; + tdm_error error = TDM_ERROR_NONE; + + for (int o = 0; o < output_count; o++) { + hwc = tdm_output_get_hwc(outputs[o], &error); + if (hwc) { + error = tdm_hwc_accept_changes(hwc); + ASSERT_NE(TDM_ERROR_NONE, error); + } else { + error = tdm_hwc_accept_changes(hwc); + ASSERT_NE(TDM_ERROR_NONE, error); + } + } +} + +TEST_P(TDMHwc, AcceptChangesSuccessful) +{ + TDM_UT_SKIP_FLAG(has_outputs); + + tdm_hwc *hwc = NULL; + tdm_error error = TDM_ERROR_NONE; + tdm_hwc_window *hwc_wnds[HWC_WIN_NUM]; + tdm_hwc_window **changed_hwc_window = NULL; + tdm_hwc_window_composition *composition_types = NULL; + uint32_t num_types; + uint32_t get_num = 0; + + for (int o = 0; o < output_count; o++) { + hwc = tdm_output_get_hwc(outputs[o], &error); + if (hwc) { + for (int w = 0; w < HWC_WIN_NUM; w++) { + hwc_wnds[w] = tdm_hwc_create_window(hwc, &error); + ASSERT_EQ(TDM_ERROR_NONE, error); + error = tdm_hwc_window_set_composition_type(hwc_wnds[w], TDM_COMPOSITION_DEVICE); + ASSERT_EQ(TDM_ERROR_NONE, error); + } + + error = tdm_hwc_validate(hwc, hwc_wnds, HWC_WIN_NUM, &num_types); + ASSERT_EQ(TDM_ERROR_NONE, error); + + if (num_types > 0) { + changed_hwc_window = (tdm_hwc_window **)calloc(num_types, sizeof(tdm_hwc_window *)); + composition_types = (tdm_hwc_window_composition *)calloc(num_types, sizeof(tdm_hwc_window_composition)); + + error = tdm_hwc_get_changed_composition_types(hwc, &get_num, changed_hwc_window, composition_types); + ASSERT_EQ(TDM_ERROR_NONE, error); + ASSERT_EQ(get_num, num_types); + + error = tdm_hwc_accept_changes(hwc); + ASSERT_EQ(TDM_ERROR_NONE, error); + + free(composition_types); + free(changed_hwc_window); + } + + for (int w = 0; w < HWC_WIN_NUM; w++) + tdm_hwc_window_destroy(hwc_wnds[w]); + + ASSERT_EQ(TDM_ERROR_NONE, error); + } + } +} + +/* tdm_error tdm_hwc_commit() */ +TEST_P(TDMHwc, CommitFailNull) +{ + TDM_UT_SKIP_FLAG(has_outputs); + + error = tdm_hwc_commit(NULL, 1, NULL, NULL); + ASSERT_NE(TDM_ERROR_NONE, error); +} + +TEST_P(TDMHwc, CommitSuccessful) +{ + TDM_UT_SKIP_FLAG(has_outputs); + + tdm_hwc *hwc = NULL; + tdm_error error = TDM_ERROR_NONE; + tdm_hwc_window *hwc_wnds[HWC_WIN_NUM]; + tdm_hwc_window **changed_hwc_window = NULL; + tdm_hwc_window_composition *composition_types = NULL; + uint32_t num_types; + uint32_t get_num = 0; + + for (int o = 0; o < output_count; o++) { + hwc = tdm_output_get_hwc(outputs[o], &error); + if (hwc) { + for (int w = 0; w < HWC_WIN_NUM; w++) { + hwc_wnds[w] = tdm_hwc_create_window(hwc, &error); + ASSERT_EQ(TDM_ERROR_NONE, error); + error = tdm_hwc_window_set_composition_type(hwc_wnds[w], TDM_COMPOSITION_DEVICE); + ASSERT_EQ(TDM_ERROR_NONE, error); + } + + error = tdm_hwc_validate(hwc, hwc_wnds, HWC_WIN_NUM, &num_types); + ASSERT_EQ(TDM_ERROR_NONE, error); + + if (num_types > 0) { + changed_hwc_window = (tdm_hwc_window **)calloc(num_types, sizeof(tdm_hwc_window *)); + composition_types = (tdm_hwc_window_composition *)calloc(num_types, sizeof(tdm_hwc_window_composition)); + + error = tdm_hwc_get_changed_composition_types(hwc, &get_num, changed_hwc_window, composition_types); + ASSERT_EQ(TDM_ERROR_NONE, error); + ASSERT_EQ(get_num, num_types); + + error = tdm_hwc_accept_changes(hwc); + ASSERT_EQ(TDM_ERROR_NONE, error); + + free(composition_types); + free(changed_hwc_window); + } + + error = tdm_hwc_commit(hwc, 0, _tc_tdm_hwc_commit_cb, NULL); + ASSERT_NE(TDM_ERROR_NONE, error); + + for (int w = 0; w < HWC_WIN_NUM; w++) + tdm_hwc_window_destroy(hwc_wnds[w]); + + ASSERT_EQ(TDM_ERROR_NONE, error); + } + } +} + +#ifdef TDM_UT_TEST_WITH_PARAMS +INSTANTIATE_TEST_CASE_P(TDMHwcParams, + TDMHwc, + Combine(Bool(), Bool(), Values(TDM_DEFAULT_MODULE))); +#else +INSTANTIATE_TEST_CASE_P(TDMHwcParams, + TDMHwc, + Values(TDM_DEFAULT_MODULE)); +#endif + +/* LCOV_EXCL_END */ \ No newline at end of file diff --git a/haltests/src/tc_tdm_hwc_window.cpp b/haltests/src/tc_tdm_hwc_window.cpp index 3af1f35..b330e85 100644 --- a/haltests/src/tc_tdm_hwc_window.cpp +++ b/haltests/src/tc_tdm_hwc_window.cpp @@ -40,50 +40,23 @@ public: TDMHwcWindow(); void SetUp(void); void TearDown(void); - - tdm_error error; - tdm_hwc_window **hwc_wins; - int hwc_count; }; TDMHwcWindow::TDMHwcWindow() { - error = TDM_ERROR_NONE; - hwc_wins = NULL; - hwc_count = 0; - video_hwc_win = NULL; } void TDMHwcWindow::SetUp(void) { - tdm_hwc_window *hw = NULL; - TDMOutput::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 o = 0; o < output_count; o++) { - if (tc_tdm_output_is_hwc_enable(outputs[o])) { - for (int w = 0; w < HWC_WIN_NUM; w++) { - hw = tdm_hwc_create_window(outputs[w], &error); - ASSERT_EQ(TDM_ERROR_NONE, error); - hwc_wins[hwc_count++] = hw; - } - } - } } void TDMHwcWindow::TearDown(void) { - for (int w = 0; w < hwc_count; w++) - tdm_hwc_window_destroy(hwc_wins[w]); - TDMOutput::TearDown(); } -/* void tdm_hwc_window_destroy(tdm_hwc_window *hwc_window); */ -/* +/* void tdm_hwc_window_destroy() */ TEST_P(TDMHwcWindow, DestroyWindowFailNull) { tdm_hwc_window_destroy(NULL); @@ -93,24 +66,27 @@ TEST_P(TDMHwcWindow, DestroyWindowSuccessful) { TDM_UT_SKIP_FLAG(has_outputs); + tdm_hwc *hwc = NULL; + tdm_error error = TDM_ERROR_NONE; tdm_hwc_window *hw = NULL; for (int o = 0; o < output_count; o++) { - if (tc_tdm_output_is_hwc_enable(outputs[o])) { - hw = tdm_hwc_create_window(outputs[o], &error); - ASSERT_EQ(TDM_ERROR_NONE, error); - error = tdm_hwc_window_destroy(outputs[o], hw); + hwc = tdm_output_get_hwc(hwc, &error); + if (hwc) { + hw = tdm_hwc_create_window(hwc, &error); ASSERT_EQ(TDM_ERROR_NONE, error); + if (hw) + tdm_hwc_window_destroy(hw); } } } -*/ -/* tbm_surface_queue_h tdm_hwc_window_get_buffer_queue(tdm_hwc_window *hwc_window, tdm_error *error); */ +/* tbm_surface_queue_h tdm_hwc_window_get_buffer_queue() */ TEST_P(TDMHwcWindow, GetBufferQueueFailNull) { TDM_UT_SKIP_FLAG(has_outputs); + tdm_error error = TDM_ERROR_NONE; tbm_surface_queue_h queue = NULL; queue = tdm_hwc_window_get_buffer_queue(NULL, &error); @@ -125,27 +101,44 @@ TEST_P(TDMHwcWindow, GetBufferQueueSuccessful) { TDM_UT_SKIP_FLAG(has_outputs); + tdm_hwc *hwc = NULL; + tdm_hwc_window *hwc_wins[HWC_WIN_NUM]; + tdm_error error = TDM_ERROR_NONE; + int w; 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 o = 0; o < output_count; o++) { + hwc = tdm_output_get_hwc(hwc, &error); + if (hwc) { + for (w = 0; w < HWC_WIN_NUM; w++) { + hwc_wins[w] = tdm_hwc_create_window(hwc, &error); + ASSERT_NE(NULL, hwc_wins[w]); + } + + 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 w = 0; w < hwc_count; w++) { - error = tdm_hwc_window_set_info(hwc_wins[w], &info); - ASSERT_EQ(TDM_ERROR_NONE, error); + for (w = 0; w < HWC_WIN_NUM; w++) { + error = tdm_hwc_window_set_info(hwc_wins[w], &info); + ASSERT_EQ(TDM_ERROR_NONE, error); - queue = tdm_hwc_window_get_buffer_queue(hwc_wins[w], &error); - tbm_surface_queue_destroy(queue); - ASSERT_EQ(TDM_ERROR_NONE, error); - ASSERT_NE(NULL, queue); + queue = tdm_hwc_window_get_buffer_queue(hwc_wins[w], &error); + tbm_surface_queue_destroy(queue); + ASSERT_EQ(TDM_ERROR_NONE, error); + ASSERT_NE(NULL, queue); - queue = tdm_hwc_window_get_buffer_queue(hwc_wins[w], NULL); - tbm_surface_queue_destroy(queue); - ASSERT_NE(NULL, queue); + queue = tdm_hwc_window_get_buffer_queue(hwc_wins[w], NULL); + tbm_surface_queue_destroy(queue); + ASSERT_NE(NULL, queue); + } + + for (w = 0; w < HWC_WIN_NUM; w++) + tdm_hwc_window_destroy(hwc_wins[w]); + } } } @@ -155,39 +148,70 @@ TEST_P(TDMHwcWindow, SetCompositionTypeFailNull) { TDM_UT_SKIP_FLAG(has_outputs); + tdm_error error = TDM_ERROR_NONE; + error = tdm_hwc_window_set_composition_type(NULL, TDM_COMPOSITION_DEVICE); ASSERT_NE(TDM_ERROR_NONE, error); } -TEST_P(TDMHwcWindow, SetCompositionTypeSuccessful) +TEST_P(TDMHwcWindow, SetCompositionTypeFailInvalieCompositionType) { TDM_UT_SKIP_FLAG(has_outputs); - for (int w = 0; w < hwc_count; w++) { - error = tdm_hwc_window_set_composition_type(hwc_wins[w], TDM_COMPOSITION_DEVICE); - ASSERT_EQ(TDM_ERROR_NONE, error); - error = tdm_hwc_window_set_composition_type(hwc_wins[w], TDM_COMPOSITION_CLIENT); - ASSERT_EQ(TDM_ERROR_NONE, error); - error = tdm_hwc_window_set_composition_type(hwc_wins[w], TDM_COMPOSITION_CURSOR); - ASSERT_EQ(TDM_ERROR_NONE, error); + tdm_hwc *hwc = NULL; + tdm_hwc_window *hwc_win; + tdm_error error = TDM_ERROR_NONE; + + for (int o = 0; o < output_count; o++) { + hwc = tdm_output_get_hwc(hwc, &error); + if (hwc) { + hwc_win = tdm_hwc_create_window(hwc, &error); + ASSERT_NE(NULL, hwc_win); + error = tdm_hwc_window_set_composition_type(hwc_win, tdm_hwc_window_composition(TDM_COMPOSITION_NONE - 1)); + ASSERT_NE(TDM_ERROR_NONE, error); + tdm_hwc_window_destroy(hwc_win); + } } } -TEST_P(TDMHwcWindow, SetCompositionTypeFailInvalieCompositionType) +TEST_P(TDMHwcWindow, SetCompositionTypeSuccessful) { TDM_UT_SKIP_FLAG(has_outputs); - for (int w = 0; w < hwc_count; w++) { - error = tdm_hwc_window_set_composition_type(hwc_wins[w], tdm_hwc_window_composition(TDM_COMPOSITION_NONE - 1)); - ASSERT_NE(TDM_ERROR_NONE, error); + tdm_hwc *hwc = NULL; + tdm_hwc_window *hwc_wins[HWC_WIN_NUM]; + tdm_error error = TDM_ERROR_NONE; + int w; + + for (int o = 0; o < output_count; o++) { + hwc = tdm_output_get_hwc(hwc, &error); + if (hwc) { + for (w = 0; w < HWC_WIN_NUM; w++) { + hwc_wins[w] = tdm_hwc_create_window(hwc, &error); + ASSERT_NE(NULL, hwc_wins[w]); + } + + for (w = 0; w < HWC_WIN_NUM; w++) { + error = tdm_hwc_window_set_composition_type(hwc_wins[w], TDM_COMPOSITION_DEVICE); + ASSERT_EQ(TDM_ERROR_NONE, error); + error = tdm_hwc_window_set_composition_type(hwc_wins[w], TDM_COMPOSITION_CLIENT); + ASSERT_EQ(TDM_ERROR_NONE, error); + error = tdm_hwc_window_set_composition_type(hwc_wins[w], TDM_COMPOSITION_CURSOR); + ASSERT_EQ(TDM_ERROR_NONE, error); + } + + for (w = 0; w < HWC_WIN_NUM; w++) + tdm_hwc_window_destroy(hwc_wins[w]); + } } } -/* tdm_error tdm_hwc_window_set_buffer_damage(tdm_hwc_window *hwc_window, tdm_region damage); */ +/* tdm_error tdm_hwc_window_set_buffer_damage() */ TEST_P(TDMHwcWindow, SetBufferDamageFailNullHwcWindow) { TDM_UT_SKIP_FLAG(has_outputs); + tdm_error error = TDM_ERROR_NONE; tdm_region damage = {.num_rects = 0, .rects = NULL}; error = tdm_hwc_window_set_buffer_damage(NULL, damage); @@ -198,42 +222,69 @@ TEST_P(TDMHwcWindow, SetBufferDamageFailNullDamageRects) { TDM_UT_SKIP_FLAG(has_outputs); + tdm_hwc *hwc = NULL; + tdm_hwc_window *hwc_win; + tdm_error error = TDM_ERROR_NONE; tdm_region damage = {.num_rects = 1, .rects = NULL}; - for (int w = 0; w < hwc_count; w++) { - error = tdm_hwc_window_set_buffer_damage(hwc_wins[w], damage); - ASSERT_NE(TDM_ERROR_NONE, error); + for (int o = 0; o < output_count; o++) { + hwc = tdm_output_get_hwc(hwc, &error); + if (hwc) { + hwc_win = tdm_hwc_create_window(hwc, &error); + ASSERT_NE(NULL, hwc_win); + error = tdm_hwc_window_set_buffer_damage(hwc_win, damage); + ASSERT_NE(TDM_ERROR_NONE, error); + tdm_hwc_window_destroy(hwc_win); + } } } - TEST_P(TDMHwcWindow, SetBufferDamageSuccessful) { TDM_UT_SKIP_FLAG(has_outputs); + tdm_hwc *hwc = NULL; + tdm_hwc_window *hwc_wins[HWC_WIN_NUM]; + tdm_error error = TDM_ERROR_NONE; tdm_pos const rects[1] = {0}; tdm_region damage = {.num_rects = 1, .rects = rects}; - for (int w = 0; w < hwc_count; w++) { - error = tdm_hwc_window_set_buffer_damage(hwc_wins[w], damage); - ASSERT_EQ(TDM_ERROR_NONE, error); + for (int o = 0; o < output_count; o++) { + hwc = tdm_output_get_hwc(hwc, &error); + if (hwc) { + for (int w = 0; w < HWC_WIN_NUM; w++) { + hwc_wins[w] = tdm_hwc_create_window(hwc, &error); + ASSERT_NE(NULL, hwc_wins[w]); + error = tdm_hwc_window_set_buffer_damage(hwc_wins[w], damage); + ASSERT_EQ(TDM_ERROR_NONE, error); + tdm_hwc_window_destroy(hwc_wins[w]); + } + } } } - -/* tdm_error tdm_hwc_window_set_info(tdm_hwc_window *hwc_window, tdm_hwc_window_info *info); */ +/* tdm_error tdm_hwc_window_set_info() */ TEST_P(TDMHwcWindow, SetInfoFailNull) { TDM_UT_SKIP_FLAG(has_outputs); + tdm_hwc *hwc = NULL; + tdm_hwc_window *hwc_win; + tdm_error error = TDM_ERROR_NONE; 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); + for (int o = 0; o < output_count; o++) { + hwc = tdm_output_get_hwc(hwc, &error); + if (hwc) { + hwc_win = tdm_hwc_create_window(hwc, &error); + ASSERT_NE(NULL, hwc_win); + error = tdm_hwc_window_set_info(hwc_win, NULL); + ASSERT_NE(TDM_ERROR_NONE, error); + tdm_hwc_window_destroy(hwc_win); + } } } @@ -241,20 +292,30 @@ TEST_P(TDMHwcWindow, SetInfoSuccessful) { TDM_UT_SKIP_FLAG(has_outputs); + tdm_hwc *hwc = NULL; + tdm_hwc_window *hwc_win; + tdm_error error = TDM_ERROR_NONE; tdm_hwc_window_info info = { 0 }; - for (int w = 0; w < hwc_count; w++) { - error = tdm_hwc_window_set_info(hwc_wins[w], &info); - ASSERT_EQ(TDM_ERROR_NONE, error); + for (int o = 0; o < output_count; o++) { + hwc = tdm_output_get_hwc(hwc, &error); + if (hwc) { + hwc_win = tdm_hwc_create_window(hwc, &error); + ASSERT_NE(NULL, hwc_win); + error = tdm_hwc_window_set_info(hwc_win, &info); + ASSERT_NE(TDM_ERROR_NONE, error); + tdm_hwc_window_destroy(hwc_win); + } } } - -/* tdm_error tdm_hwc_window_set_buffer(tdm_hwc_window *hwc_window, tbm_surface_h buffer); */ +/* tdm_error tdm_hwc_window_set_buffer() */ TEST_P(TDMHwcWindow, SetBufferFailNull) { TDM_UT_SKIP_FLAG(has_outputs); + tdm_error error = TDM_ERROR_NONE; + error = tdm_hwc_window_set_buffer(NULL, NULL); ASSERT_NE(TDM_ERROR_NONE, error); } @@ -263,106 +324,116 @@ TEST_P(TDMHwcWindow, SetBufferSuccessful) { TDM_UT_SKIP_FLAG(has_outputs); - for (int w = 0; w < hwc_count; w++) { + tdm_hwc *hwc = NULL; + tdm_hwc_window *hwc_wins[HWC_WIN_NUM]; + tdm_error error = TDM_ERROR_NONE; + tbm_surface_h buffer = NULL; - tbm_surface_h buff = tbm_surface_create(256, 256, TBM_FORMAT_ARGB8888); - - /* test: set*/ - error = tdm_hwc_window_set_buffer(hwc_wins[w], buff); - tbm_surface_destroy(buff); - ASSERT_EQ(TDM_ERROR_NONE, error); - - /* test: reset*/ - error = tdm_hwc_window_set_buffer(hwc_wins[w], NULL); - ASSERT_EQ(TDM_ERROR_NONE, error); - } -} - -/* tdm_hwc_get_available_properties() */ -/* -TEST_P(TDMHwcWindow, GetAvailablePropertiesFailNullWin) -{ - TDM_UT_SKIP_FLAG(has_outputs); - - TDM_UT_SKIP_FLAG(video_hwc_win != NULL); - const tdm_prop *props; - int count; - - error = tdm_hwc_get_available_properties(NULL, &props, &count); - ASSERT_NE(TDM_ERROR_NONE, error); - - error = tdm_hwc_get_available_properties(video_hwc_win, NULL, &count); - ASSERT_NE(TDM_ERROR_NONE, error); - - error = tdm_hwc_get_available_properties(video_hwc_win, &props, NULL); - ASSERT_NE(TDM_ERROR_NONE, error); -} + for (int o = 0; o < output_count; o++) { + hwc = tdm_output_get_hwc(hwc, &error); + if (hwc) { + for (int w = 0; w < HWC_WIN_NUM; w++) { + hwc_wins[w] = tdm_hwc_create_window(hwc, &error); + ASSERT_NE(NULL, hwc_wins[w]); -TEST_P(TDMHwcWindow, GetAvailablePropertiesSuccess) -{ - TDM_UT_SKIP_FLAG(has_outputs); + buffer = tbm_surface_create(256, 256, TBM_FORMAT_ARGB8888); + ASSERT_NE(NULL, buffer); - TDM_UT_SKIP_FLAG(video_hwc_win != NULL); + error = tdm_hwc_window_set_buffer(hwc_wins[w], buffer); + tbm_surface_destroy(buffer); + ASSERT_EQ(TDM_ERROR_NONE, error); - const tdm_prop *props; - int count; + /* set NULL to the buffer */ + error = tdm_hwc_window_set_buffer(hwc_wins[w], NULL); + ASSERT_EQ(TDM_ERROR_NONE, error); - error = tdm_hwc_get_available_properties(video_hwc_win, &props, &count); - ASSERT_TRUE(TDM_ERROR_NONE == error || TDM_ERROR_NOT_IMPLEMENTED == error); + tdm_hwc_window_destroy(hwc_wins[w]); + } + } + } } -*/ -/* tdm_hwc_window_get_property() */ -TEST_P(TDMHwcWindow, GetPropertyFailNull) +/* tdm_hwc_window_set_property() */ +TEST_P(TDMHwcWindow, SetPropertyFailNull) { TDM_UT_SKIP_FLAG(has_outputs); - TDM_UT_SKIP_FLAG(video_hwc_win != NULL); + tdm_error error = TDM_ERROR_NONE; tdm_value value; int id = 1; - error = tdm_hwc_window_get_property(NULL, id, &value); - ASSERT_NE(TDM_ERROR_NONE, error); - - error = tdm_hwc_window_get_property(video_hwc_win, id, NULL); + error = tdm_hwc_window_set_property(NULL, id, value); ASSERT_NE(TDM_ERROR_NONE, error); } -TEST_P(TDMHwcWindow, GetPropertyFailWrongId) +TEST_P(TDMHwcWindow, SetPropertyFailWrongId) { TDM_UT_SKIP_FLAG(has_outputs); - TDM_UT_SKIP_FLAG(video_hwc_win != NULL); + tdm_hwc *hwc = NULL; + tdm_hwc_window *hwc_win; + tdm_error error = TDM_ERROR_NONE; tdm_value value; int id = INT_MAX; - error = tdm_hwc_window_get_property(video_hwc_win, id, &value); - ASSERT_NE(TDM_ERROR_NONE, error); + for (int o = 0; o < output_count; o++) { + hwc = tdm_output_get_hwc(hwc, &error); + if (hwc) { + hwc_win = tdm_hwc_create_window(hwc, &error); + ASSERT_NE(NULL, hwc_win); + error = tdm_hwc_window_set_property(hwc_win, id, value); + ASSERT_NE(TDM_ERROR_NONE, error); + tdm_hwc_window_destroy(hwc_win); + } + } } -/* tdm_hwc_window_set_property() */ -TEST_P(TDMHwcWindow, SetPropertyFailNull) +/* tdm_hwc_window_get_property() */ +TEST_P(TDMHwcWindow, GetPropertyFailNull) { TDM_UT_SKIP_FLAG(has_outputs); - TDM_UT_SKIP_FLAG(video_hwc_win != NULL); + tdm_hwc *hwc = NULL; + tdm_hwc_window *hwc_win; + tdm_error error = TDM_ERROR_NONE; tdm_value value; int id = 1; - error = tdm_hwc_window_set_property(NULL, id, value); + error = tdm_hwc_window_get_property(NULL, id, &value); ASSERT_NE(TDM_ERROR_NONE, error); + + for (int o = 0; o < output_count; o++) { + hwc = tdm_output_get_hwc(hwc, &error); + if (hwc) { + hwc_win = tdm_hwc_create_window(hwc, &error); + ASSERT_NE(NULL, hwc_win); + error = tdm_hwc_window_get_property(hwc_win, id, NULL); + ASSERT_NE(TDM_ERROR_NONE, error); + tdm_hwc_window_destroy(hwc_win); + } + } } -TEST_P(TDMHwcWindow, SetPropertyFailWrongId) +TEST_P(TDMHwcWindow, GetPropertyFailWrongId) { TDM_UT_SKIP_FLAG(has_outputs); - TDM_UT_SKIP_FLAG(video_hwc_win != NULL); + tdm_hwc *hwc = NULL; + tdm_hwc_window *hwc_win; + tdm_error error = TDM_ERROR_NONE; tdm_value value; int id = INT_MAX; - error = tdm_hwc_window_set_property(video_hwc_win, id, value); - ASSERT_NE(TDM_ERROR_NONE, error); + for (int o = 0; o < output_count; o++) { + hwc = tdm_output_get_hwc(hwc, &error); + if (hwc) { + hwc_win = tdm_hwc_create_window(hwc, &error); + ASSERT_NE(NULL, hwc_win); + error = tdm_hwc_window_get_property(hwc_win, id, &value); + ASSERT_NE(TDM_ERROR_NONE, error); + tdm_hwc_window_destroy(hwc_win); + } + } } #ifdef TDM_UT_TEST_WITH_PARAMS diff --git a/haltests/src/tc_tdm_output_hwc.cpp b/haltests/src/tc_tdm_output_hwc.cpp deleted file mode 100644 index 3a6ca4d..0000000 --- a/haltests/src/tc_tdm_output_hwc.cpp +++ /dev/null @@ -1,429 +0,0 @@ -/************************************************************************** - * - * 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 "tc_tdm.h" - -/* LCOV_EXCL_START */ - -class TDMOutputHwc : public TDMOutput -{ -public: - TDMOutputHwc(); - void SetUp(void); - void TearDown(void); - - tdm_error error; -}; - -TDMOutputHwc::TDMOutputHwc() -{ - error = TDM_ERROR_NONE; -} - -void TDMOutputHwc::SetUp(void) -{ - TDMOutput::SetUp(); -} - -void TDMOutputHwc::TearDown(void) -{ - TDMOutput::TearDown(); -} - -/* tdm_hwc_window * tdm_hwc_create_window(tdm_output *output, tdm_error *error); */ -TEST_P(TDMOutputHwc, CreateWindowFailNull) -{ - TDM_UT_SKIP_FLAG(has_outputs); - - ASSERT_EQ(NULL, tdm_hwc_create_window(NULL, &error)); - ASSERT_NE(TDM_ERROR_NONE, error); -} - -/* -TEST_P(TDMOutputHwc, CreateWindowSuccessful) -{ - TDM_UT_SKIP_FLAG(has_outputs); - - tdm_hwc_window * hw = NULL; - - for (int o = 0; o < output_count; o++) { - if (tc_tdm_output_is_hwc_enable(outputs[o])) { - hw = tdm_hwc_create_window(hwc[o], &error); - ASSERT_EQ(TDM_ERROR_NONE, error); - tdm_hwc_window_destroy(hw); - } else { - ASSERT_EQ(NULL, tdm_hwc_create_window(outputs[o], &error)); - ASSERT_NE(TDM_ERROR_NONE, error); - } - } -} -*/ - -/* tdm_error tdm_hwc_set_client_target_buffer(tdm_output *output, - tbm_surface_h target_buffer, tdm_region damage, - tdm_hwc_window *composited_wnds, uint32_t num_wnds); */ -/* TDOO: need to be fixed -TEST_P(TDMOutputHwc, SetClientTargetBufferFailNullOutput) -{ - TDM_UT_SKIP_FLAG(has_outputs); - - tdm_region reg; - tbm_surface_h target_buff = CreateBufferForOutput(0); - error = tdm_hwc_set_client_target_buffer(NULL, target_buff, reg, NULL, 0 ); - tbm_surface_internal_destroy(target_buff); - ASSERT_NE(TDM_ERROR_NONE, error); -} - -TEST_P(TDMOutputHwc, SetClientTargetBufferFailNoHwc) -{ - tdm_region damage = {.num_rects = 0, .rects = NULL}; - - for (int o = 0; o < output_count; o++) { - tbm_surface_h target_buff = CreateBufferForOutput(i); - ASSERT_NE(NULL, target_buff); - error = tdm_hwc_set_client_target_buffer(outputs[o], target_buff, damage, NULL, 0); - tbm_surface_internal_destroy(target_buff); - ASSERT_NE(TDM_ERROR_NONE, error); - } -} - -TEST_P(TDMOutputHwc, SetClientTargetBufferSuccessfulSetBuff) -{ - TDM_UT_SKIP_FLAG(has_outputs); - - tdm_region damage = {.num_rects = 0, .rects = NULL}; - - for (int o = 0; o < output_count; o++) { - tbm_surface_h target_buff = CreateBufferForOutput(i); - ASSERT_NE(NULL, target_buff); - if (tc_tdm_output_is_hwc_enable(outputs[o])) { - error = tdm_hwc_set_client_target_buffer(outputs[o], target_buff, damage, - NULL, 0); - tbm_surface_internal_destroy(target_buff); - ASSERT_EQ(TDM_ERROR_NONE, error); - } else { - error = tdm_hwc_set_client_target_buffer(outputs[o], target_buff, damage, - NULL, 0); - tbm_surface_internal_destroy(target_buff); - ASSERT_NE(TDM_ERROR_NONE, error); - } - } -} - -TEST_P(TDMOutputHwc, SetClientTargetBufferSuccessfulResetBuff) -{ - TDM_UT_SKIP_FLAG(has_outputs); - - tdm_region damage = {.num_rects = 0, .rects = NULL}; - - for (int o = 0; o < output_count; o++) { - if (tc_tdm_output_is_hwc_enable(outputs[o])) { - error = tdm_hwc_set_client_target_buffer(outputs[o], NULL, damage, - NULL, 0); - ASSERT_EQ(TDM_ERROR_NONE, error); - } else { - error = tdm_hwc_set_client_target_buffer(outputs[o], NULL, damage, - NULL, 0); - ASSERT_NE(TDM_ERROR_NONE, error); - } - } -} -*/ - -/* tbm_surface_queue_h tdm_hwc_get_client_target_buffer_queue(tdm_output *output, tdm_error *error); */ -/* -TEST_P(TDMOutputHwc, GetTargetBufferQueueFailNullObject) -{ - TDM_UT_SKIP_FLAG(has_outputs); - - tbm_surface_queue_h queue = NULL; - - queue = tdm_hwc_get_client_target_buffer_queue(NULL, &error); - ASSERT_NE(TDM_ERROR_NONE, error); - ASSERT_EQ(NULL, queue); - - queue = tdm_hwc_get_client_target_buffer_queue(NULL, NULL); - ASSERT_EQ(NULL, queue); -} - -TEST_P(TDMOutputHwc, GetTargetBufferQueueFainNoHwc) -{ - TDM_UT_SKIP_FLAG(has_outputs); - - tbm_surface_queue_h queue = NULL; - - for (int o = 0; o < output_count; o++) { - queue = tdm_hwc_get_client_target_buffer_queue(outputs[o], &error); - ASSERT_NE(TDM_ERROR_NONE, error); - ASSERT_EQ(NULL, queue); - } -} -*/ - -TEST_P(TDMOutputHwc, GetTargetBufferQueueSuccessful) -{ - TDM_UT_SKIP_FLAG(has_outputs); - - tbm_surface_queue_h queue = NULL; - - for (int o = 0; o < output_count; o++) { - if (tc_tdm_output_is_hwc_enable(outputs[o])) { - queue = tdm_hwc_get_client_target_buffer_queue(outputs[o], &error); - tbm_surface_queue_destroy(queue); - ASSERT_EQ(TDM_ERROR_NONE, error); - ASSERT_NE(NULL, queue); - - queue = tdm_hwc_get_client_target_buffer_queue(outputs[o], NULL); - tbm_surface_queue_destroy(queue); - ASSERT_EQ(TDM_ERROR_NONE, error); - ASSERT_NE(NULL, queue); - } else { - queue = tdm_hwc_get_client_target_buffer_queue(outputs[o], &error); - ASSERT_NE(TDM_ERROR_NONE, error); - ASSERT_EQ(NULL, queue); - - queue = tdm_hwc_get_client_target_buffer_queue(outputs[o], NULL); - ASSERT_NE(TDM_ERROR_NONE, error); - ASSERT_EQ(NULL, queue); - } - } -} - -/* tdm_error tdm_hwc_validate(tdm_output *output, tdm_hwc_window **composited_wnds, uint32_t num_wnds, - uint32_t *num_types); */ -/* TODO: fix the validate test later. -TEST_P(TDMOutputHwc, ValidateFailNull) -{ - TDM_UT_SKIP_FLAG(has_outputs); - - uint32_t num_types; - error = tdm_hwc_validate(NULL, NULL, 0, &num_types); - ASSERT_NE(TDM_ERROR_NONE, error); - - if (outputs[0]) { - error = tdm_hwc_validate(outputs[0], NULL, 0, NULL); - ASSERT_NE(TDM_ERROR_NONE, error); - } -} - -TEST_P(TDMOutputHwc, ValidateFailNoHwc) -{ - TDM_UT_SKIP_FLAG(has_outputs); - - uint32_t num_types; - - for (int o = 0; o < output_count; o++) { - error = tdm_hwc_validate(outputs[o], &num_types); - ASSERT_NE(TDM_ERROR_NONE, error); - } -} - -TEST_P(TDMOutputHwc, ValidateSuccessful) -{ - TDM_UT_SKIP_FLAG(has_outputs); - - uint32_t num_types; - for (int o = 0; o < output_count; o++) { - if (tc_tdm_output_is_hwc_enable(outputs[o])) { - error = tdm_hwc_validate(outputs[o], &num_types); - ASSERT_EQ(TDM_ERROR_NONE, error); - } else { - error = tdm_hwc_validate(outputs[o], &num_types); - ASSERT_NE(TDM_ERROR_NONE, error); - } - } -} -TODO: */ - -/* tdm_error tdm_hwc_get_changed_composition_types(tdm_hwc *hwc, - uint32_t *num_elements, tdm_hwc_window **hwc_window, - tdm_hwc_window_composition *composition_types); */ -/* -TEST_P(TDMOutputHwc, GetChangedCompositionTypesFailNull) -{ - TDM_UT_SKIP_FLAG(has_outputs); - - uint32_t num_elements; - - error = tdm_hwc_get_changed_composition_types(NULL, &num_elements, NULL, NULL); - ASSERT_NE(TDM_ERROR_NONE, error); - - if (outputs[0]) { - error = tdm_hwc_get_changed_composition_types(outputs[0], NULL, NULL, NULL); - ASSERT_NE(TDM_ERROR_NONE, error); - } -} - -TEST_P(TDMOutputHwc, GetChangedCompositionTypesFailNoHwc) -{ - TDM_UT_SKIP_FLAG(has_outputs); - - uint32_t get_num = 10; - - for (int o = 0; o < output_count; o++) { - error = tdm_hwc_get_changed_composition_types(outputs[o], &get_num, NULL, NULL); - ASSERT_NE(TDM_ERROR_NONE, error); - } -} -*/ -/* TODO: fix the validate test later. -TEST_P(TDMHwcWindow, GetChangedCompositionTypesSuccessful) -{ - TDM_UT_SKIP_FLAG(has_outputs); - - 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[o], TDM_COMPOSITION_DEVICE); - ASSERT_EQ(TDM_ERROR_NONE, error); - } - - - for (int i = 0; i < output_count; i++) { - if (tc_tdm_output_is_hwc_enable(outputs[o])) { - error = tdm_hwc_validate(outputs[o], &validate_num); - ASSERT_EQ(TDM_ERROR_NONE, error); - - error = tdm_hwc_get_changed_composition_types(outputs[o], &get_num, NULL, NULL); - ASSERT_EQ(TDM_ERROR_NONE, error); - - ASSERT_EQ(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_hwc_get_changed_composition_types(outputs[o], &get_num, hwc_wnds, composition_types); - - free(hwc_wnds); - free(composition_types); - - ASSERT_EQ(TDM_ERROR_NONE, error); - } else { - error = tdm_hwc_get_changed_composition_types(outputs[o], &get_num, NULL, NULL); - ASSERT_NE(TDM_ERROR_NONE, error); - } - } -} -*/ - -/* tdm_error tdm_hwc_accept_changes(tdm_hwc *hwc); */ -/* -TEST_P(TDMOutputHwc, AcceptChangesFailNull) -{ - TDM_UT_SKIP_FLAG(has_outputs); - - error = tdm_hwc_accept_changes(NULL); - ASSERT_NE(TDM_ERROR_NONE, error); -} - -TEST_P(TDMOutputHwc, AcceptChangesFailNoHwc) -{ - for (int o = 0; o < output_count; o++) { - error = tdm_hwc_accept_changes(outputs[o]); - ASSERT_NE(TDM_ERROR_NONE, error); - } -} -*/ -/* TODO: fix the validate test later. -TEST_P(TDMHwcWindow, AcceptChangesSuccessful) -{ - TDM_UT_SKIP_FLAG(has_outputs); - - uint32_t validate_num; - - for (int i = 0; i < hwc_count; i++) { - error = tdm_hwc_window_set_composition_type(hwc_wins[o], TDM_COMPOSITION_DEVICE); - ASSERT_EQ(TDM_ERROR_NONE, error); - } - - for (int i = 0; i < output_count; i++) { - if (tc_tdm_output_is_hwc_enable(outputs[o])) { - error = tdm_hwc_validate(outputs[o], &validate_num); - ASSERT_EQ(TDM_ERROR_NONE, error); - - if (validate_num > 0) { - error = tdm_hwc_accept_changes(outputs[o]); - ASSERT_EQ(TDM_ERROR_NONE, error); - } - } - } -} -*/ - -/* tdm_hwc_get_supported_formats() */ -/* -TEST_P(TDMOutputHwc, GetVideoSupportedFormatsFailNull) -{ - TDM_UT_SKIP_FLAG(has_outputs); - - tdm_error error; - - error = tdm_hwc_get_supported_formats(NULL, NULL, NULL); - ASSERT_NE(TDM_ERROR_NONE, error); -} - -TEST_P(TDMOutputHwc, GetVideoSupportedFormatsSuccessful) -{ - TDM_UT_SKIP_FLAG(has_outputs); - - tdm_error error; - const tbm_format *formats; - int count; - - for (int o = 0; o < output_count; o++) { - if (tc_tdm_output_is_hwc_enable(outputs[o])) { - error = tdm_hwc_get_supported_formats(outputs[o], &formats, &count); - if (error != TDM_ERROR_NOT_IMPLEMENTED) { - ASSERT_EQ(TDM_ERROR_NONE, error); - if (count > 0) - ASSERT_NE(NULL, formats); - } - } else { - error = tdm_hwc_get_supported_formats(outputs[o], &formats, &count); - ASSERT_NE(TDM_ERROR_NONE, error); - } - } -} -*/ - -#ifdef TDM_UT_TEST_WITH_PARAMS -INSTANTIATE_TEST_CASE_P(TDMOutputHwcParams, - TDMOutputHwc, - Combine(Bool(), Bool(), Values(TDM_DEFAULT_MODULE))); -#else -INSTANTIATE_TEST_CASE_P(TDMOutputHwcParams, - TDMOutputHwc, - Values(TDM_DEFAULT_MODULE)); -#endif - -/* LCOV_EXCL_END */ \ No newline at end of file -- 2.7.4 From a4b8dac3dca041874b9890b7a79d367f100aa79a Mon Sep 17 00:00:00 2001 From: Junkyeong Kim Date: Mon, 25 Jun 2018 15:23:06 +0900 Subject: [PATCH 05/16] vblank: avoid mutex lock error. Change-Id: I4c47966a7b6bb2afab62ed51ed2f06fa097b58c7 Signed-off-by: Junkyeong Kim --- src/tdm_vblank.c | 74 ++++++++++++++++++++++++++++++++------------------------ 1 file changed, 43 insertions(+), 31 deletions(-) diff --git a/src/tdm_vblank.c b/src/tdm_vblank.c index b461a5b..568605a 100644 --- a/src/tdm_vblank.c +++ b/src/tdm_vblank.c @@ -450,6 +450,45 @@ _tdm_vblank_cb_output_change(tdm_output *output, tdm_output_change_type type, } /* LCOV_EXCL_STOP */ +static tdm_error +_tdm_vblank_set_fps(tdm_vblank *vblank, unsigned int fps) +{ + tdm_private_vblank *private_vblank = vblank; + + if (private_vblank->fps_fixed) { + VIN("fps(%u) can't be changed", private_vblank->fps); + return TDM_ERROR_NONE; + } + + private_vblank->fps_changeable = 0; + + if (private_vblank->fps == fps) + return TDM_ERROR_NONE; + + private_vblank->fps = fps; + private_vblank->check_HW_or_SW = 1; + + VIN("fps(%u) changed", fps); + + return TDM_ERROR_NONE; +} + +static tdm_error +_tdm_vblank_ignore_global_fps(tdm_vblank *vblank, unsigned int ignore) +{ + tdm_private_vblank *private_vblank = vblank; + + if (private_vblank->ignore_global_fps == ignore) + return TDM_ERROR_NONE; + + private_vblank->ignore_global_fps = ignore; + private_vblank->check_HW_or_SW = 1; + + VIN("ignore_global_fps(%u)", private_vblank->ignore_global_fps); + + return TDM_ERROR_NONE; +} + EXTERN tdm_error tdm_vblank_set_client_vblank_fps(unsigned int pid, const char *name, unsigned int fps) { @@ -483,7 +522,7 @@ tdm_vblank_set_client_vblank_fps(unsigned int pid, const char *name, unsigned in continue; } - ret = tdm_vblank_set_fps(v, fps); + ret = _tdm_vblank_set_fps(v, fps); if (ret == TDM_ERROR_NONE) TDM_INFO("(pid:%u) '%s' fps changed: %d", pid, v->name, fps); else @@ -526,7 +565,7 @@ tdm_vblank_set_client_ignore_global_fps(unsigned int pid, const char *name, unsi continue; } - ret = tdm_vblank_ignore_global_fps(v, ignore); + ret = _tdm_vblank_ignore_global_fps(v, ignore); if (ret == TDM_ERROR_NONE) TDM_INFO("(pid:%u) '%s' ignore changed: %u", pid, v->name, ignore); else @@ -909,27 +948,10 @@ tdm_vblank_get_name(tdm_vblank *vblank, const char **name) EXTERN tdm_error tdm_vblank_set_fps(tdm_vblank *vblank, unsigned int fps) { - tdm_private_vblank *private_vblank = vblank; - TDM_RETURN_VAL_IF_FAIL(tdm_vblank_is_valid(vblank), TDM_ERROR_INVALID_PARAMETER); TDM_RETURN_VAL_IF_FAIL(fps > 0, TDM_ERROR_INVALID_PARAMETER); - if (private_vblank->fps_fixed) { - VIN("fps(%u) can't be changed", private_vblank->fps); - return TDM_ERROR_NONE; - } - - private_vblank->fps_changeable = 0; - - if (private_vblank->fps == fps) - return TDM_ERROR_NONE; - - private_vblank->fps = fps; - private_vblank->check_HW_or_SW = 1; - - VIN("fps(%u) changed", fps); - - return TDM_ERROR_NONE; + return _tdm_vblank_set_fps(vblank, fps); } EXTERN tdm_error @@ -970,19 +992,9 @@ tdm_vblank_set_fixed_fps(tdm_vblank *vblank, unsigned int fps) EXTERN tdm_error tdm_vblank_ignore_global_fps(tdm_vblank *vblank, unsigned int ignore) { - tdm_private_vblank *private_vblank = vblank; - TDM_RETURN_VAL_IF_FAIL(tdm_vblank_is_valid(vblank), TDM_ERROR_INVALID_PARAMETER); - if (private_vblank->ignore_global_fps == ignore) - return TDM_ERROR_NONE; - - private_vblank->ignore_global_fps = ignore; - private_vblank->check_HW_or_SW = 1; - - VIN("ignore_global_fps(%u)", private_vblank->ignore_global_fps); - - return TDM_ERROR_NONE; + return _tdm_vblank_ignore_global_fps(vblank, ignore); } EXTERN tdm_error -- 2.7.4 From 9ee614f0bb439952510a6b58b119f0da04772b04 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Wed, 27 Jun 2018 19:23:33 +0900 Subject: [PATCH 06/16] tdm_client: Introduce header of tdm_virtual_output. Change-Id: I6365c41f02a015f31f9e19f8c3379a902181df55 --- client/tdm_client.h | 37 +++++++++++++++++++++++++++++++++++++ client/tdm_client_types.h | 15 +++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/client/tdm_client.h b/client/tdm_client.h index a13bf2a..4ffe435 100644 --- a/client/tdm_client.h +++ b/client/tdm_client.h @@ -429,6 +429,43 @@ tdm_client_vblank_wait_seq(tdm_client_vblank *vblank, unsigned int sequence, tdm unsigned int tdm_client_vblank_is_waiting(tdm_client_vblank *vblank); +/* Virtual Output */ +#include + +tdm_client_voutput * +tdm_client_create_voutput(tdm_client *client, const char *name, tdm_error *error); + +void +tdm_client_voutput_destroy(tdm_client_voutput *voutput); + +tdm_error +tdm_client_voutput_set_available_modes(tdm_client_voutput *voutput, const tdm_client_output_mode *modes, int count); + +tdm_error +tdm_client_voutput_set_physical_size(tdm_client_voutput *voutput, int mmWidth, int mmHeight); + +tdm_error +tdm_client_voutput_add_commit_handler(tdm_client_voutput *voutput, tdm_client_voutput_commit_handler *func); + +tdm_error +tdm_client_voutput_get_committed_tbm_surface(tdm_client_voutput *voutput, tbm_surface_h surface); + +tdm_client_output * +tdm_client_voutput_get_client_output(tdm_client_voutput *voutput, tdm_error *error); + +tdm_error +tdm_client_output_get_available_modes(tdm_client_output *output, tdm_client_output_mode **modes, int *count); + +tdm_error +tdm_client_output_set_mode(tdm_client_output *output, const tdm_client_output_mode *mode); + +tdm_error +tdm_client_output_connect(tdm_client_output *output); + +tdm_error +tdm_client_output_disconnect(tdm_client_output *output); +/* End of Virtual Output */ + #ifdef __cplusplus } #endif diff --git a/client/tdm_client_types.h b/client/tdm_client_types.h index bd7e8a5..cb4e96d 100644 --- a/client/tdm_client_types.h +++ b/client/tdm_client_types.h @@ -109,6 +109,21 @@ typedef void unsigned int tv_usec, void *user_data); +/* Virtual Output */ +typedef struct _tdm_client_output_mode { + char name[TDM_NAME_LEN]; /**< The output name */ + unsigned int mode_count; /**< The count of available modes */ + unsigned int prop_count; /**< The count of available properties */ + unsigned int mmWidth; /**< The physical width (milimeter) */ + unsigned int mmHeight; /**< The physical height (milimeter) */ + unsigned int subpixel; /**< The subpixel */ +} tdm_client_output_mode; + +typedef void tdm_client_voutput; + +typedef void (*tdm_client_voutput_commit_handler)(tdm_client_voutput *voutput, + void *user_data); +/* End of Virtual Output */ #ifdef __cplusplus } #endif -- 2.7.4 From 385484a21dcc7b743d2f3887c1d14ded4be64aab Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Tue, 17 Jul 2018 17:23:31 +0900 Subject: [PATCH 07/16] virtual output: Add implementation for client and test case for virtual output. - Added implementation for creation of virtual output. - Added definition for the rest of client's api of virtual output. - Added TC for client's Virtual Output API. Change-Id: Ic6959e852ec12fed4c8f7ba77c4cf3a360ce855a --- client/tdm_client.c | 227 +++++++++++++++++++++++++++++++++++++++++ haltests/src/tc_tdm_client.cpp | 210 +++++++++++++++++++++++++++++++++++++- protocol/tdm.xml | 21 ++++ src/tdm_server.c | 22 ++++ 4 files changed, 479 insertions(+), 1 deletion(-) diff --git a/client/tdm_client.c b/client/tdm_client.c index 4023208..8d17c94 100644 --- a/client/tdm_client.c +++ b/client/tdm_client.c @@ -89,6 +89,12 @@ typedef struct _tdm_private_client_output { struct list_head link; } tdm_private_client_output; +typedef struct _tdm_private_client_voutput { + tdm_private_client_output base; + struct wl_tdm_voutput *wl_voutput; + uint32_t msg; +} tdm_private_client_voutput; + struct _tdm_private_client_vblank { tdm_private_client_output *private_output; @@ -1591,3 +1597,224 @@ tdm_client_vblank_is_waiting(tdm_client_vblank *vblank) return (LIST_LENGTH(&private_vblank->wait_list) > 0) ? 1 : 0; } + +void +tdm_client_voutput_cb_ack_message(void *data, struct wl_tdm_voutput *wl_voutput, uint32_t msg) +{ + tdm_private_client_voutput *private_voutput = data; + + private_voutput->msg = msg; +} + +static const struct wl_tdm_voutput_listener tdm_client_voutput_lisntener = { + tdm_client_voutput_cb_ack_message +}; + +tdm_client_voutput * +tdm_client_create_voutput(tdm_client *client, const char *name, tdm_error *error) +{ + tdm_private_client *private_client; + tdm_private_client_output *private_output; + tdm_private_client_voutput *private_voutput; + struct wl_proxy *wrapper; + + if (error) + *error = TDM_ERROR_NONE; + + if (!client) { + TDM_ERR("'!client' failed"); + if (error) + *error = TDM_ERROR_INVALID_PARAMETER; + return NULL; + } + + if (!name) { + TDM_ERR("'!name' failed"); + if (error) + *error = TDM_ERROR_INVALID_PARAMETER; + return NULL; + } + + private_client = (tdm_private_client *)client; + + pthread_mutex_lock(&private_client->lock); + + if (CHECK_WL_PROTOCOL_ERROR(private_client)) { + if (error) + *error = TDM_ERROR_PROTOCOL_ERROR; + pthread_mutex_unlock(&private_client->lock); + return NULL; + } + + LIST_FOR_EACH_ENTRY(private_output, &private_client->output_list, link) { + if (!strncmp(private_output->name, name, TDM_NAME_LEN)) { + if (error) + *error = TDM_ERROR_INVALID_PARAMETER; // FIXME define new error type. + pthread_mutex_unlock(&private_client->lock); + return NULL; + } + } + + wrapper = wl_proxy_create_wrapper(private_client->tdm); + if (!wrapper) { + TDM_ERR("create virtual output wrapper failed"); + if (error) + *error = TDM_ERROR_OUT_OF_MEMORY; + pthread_mutex_unlock(&private_client->lock); + return NULL; + } + + wl_proxy_set_queue(wrapper, private_client->queue); + + private_voutput = calloc(1, sizeof *private_voutput); + if (!private_voutput) { + /* LOCV_EXCL_START */ + wl_proxy_wrapper_destroy(wrapper); + TDM_ERR("alloc failed"); + if (error) + *error = TDM_ERROR_OUT_OF_MEMORY; + return NULL; + /* LOCV_EXCL_STOP */ + } + + private_voutput->base.private_client = private_client; + + snprintf(private_voutput->base.name, TDM_NAME_LEN, "%s", name); + private_voutput->wl_voutput = wl_tdm_create_voutput((struct wl_tdm *)wrapper, private_voutput->base.name); + wl_proxy_wrapper_destroy(wrapper); + if (!private_voutput->wl_voutput) { + /* LCOV_EXCL_START */ + TDM_ERR("couldn't create voutput resource"); + free(private_voutput); + if (error) + *error = TDM_ERROR_OUT_OF_MEMORY; + pthread_mutex_unlock(&private_client->lock); + return NULL; + /* LCOV_EXCL_STOP */ + } + + wl_tdm_voutput_add_listener(private_voutput->wl_voutput, + &tdm_client_voutput_lisntener, private_voutput); + wl_display_roundtrip_queue(private_client->display, private_client->queue); + + wl_proxy_set_queue((struct wl_proxy *)private_voutput->wl_voutput, NULL); + + if (CHECK_WL_PROTOCOL_ERROR(private_client)) { + wl_tdm_voutput_destroy(private_voutput->wl_voutput); + free(private_voutput); + if (error) + *error = TDM_ERROR_PROTOCOL_ERROR; + pthread_mutex_unlock(&private_client->lock); + return NULL; + } + + if (private_voutput->msg != WL_TDM_VOUTPUT_MESSAGE_ADDED) + { + wl_tdm_voutput_destroy(private_voutput->wl_voutput); + free(private_voutput); + if (error) + *error = TDM_ERROR_PROTOCOL_ERROR; // FIXME add new error type. + pthread_mutex_unlock(&private_client->lock); + return NULL; + } + + pthread_mutex_unlock(&private_client->lock); + + return (tdm_client_voutput *)private_voutput; +} + +void +tdm_client_voutput_destroy(tdm_client_voutput *voutput) +{ + tdm_private_client_voutput *private_voutput = (tdm_private_client_voutput *)voutput; + + if (!private_voutput) + return; + + free(private_voutput); +} + +tdm_error +tdm_client_voutput_set_available_modes(tdm_client_voutput *voutput, const tdm_client_output_mode *modes, int count) +{ + TDM_RETURN_VAL_IF_FAIL(voutput != NULL, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(modes != NULL, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(count > 0, TDM_ERROR_INVALID_PARAMETER); + + return TDM_ERROR_NONE; +} + +tdm_error +tdm_client_voutput_set_physical_size(tdm_client_voutput *voutput, int mmWidth, int mmHeight) +{ + TDM_RETURN_VAL_IF_FAIL(voutput != NULL, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(mmWidth > 0, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(mmHeight > 0, TDM_ERROR_INVALID_PARAMETER); + + return TDM_ERROR_NONE; +} + +tdm_client_output * +tdm_client_voutput_get_client_output(tdm_client_voutput *voutput, tdm_error *error) +{ + tdm_private_client_voutput *private_voutput; + + if (error) + *error = TDM_ERROR_NONE; + + if (!voutput) + { + TDM_ERR("'!voutput' failed"); + if (error) + *error = TDM_ERROR_INVALID_PARAMETER; + return NULL; + } + + private_voutput = (tdm_private_client_voutput *)voutput; + + return &private_voutput->base; +} + +tdm_error +tdm_client_output_set_buffer_queue(tdm_client_output *output, void *queue, void *func) +{ + TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(queue != NULL, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER); + + return TDM_ERROR_NONE; +} + +tdm_error +tdm_client_output_get_available_modes(tdm_client_output *output, tdm_client_output_mode **modes, int *count) +{ + TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(modes != NULL, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(count != NULL, TDM_ERROR_INVALID_PARAMETER); + + return TDM_ERROR_NONE; +} + +tdm_error +tdm_client_output_set_mode(tdm_client_output *output, const tdm_client_output_mode *mode) +{ + TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(mode != NULL, TDM_ERROR_INVALID_PARAMETER); + + return TDM_ERROR_NONE; +} + +tdm_error +tdm_client_output_connect(tdm_client_output *output) +{ + TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER); + + return TDM_ERROR_NONE; +} + +tdm_error +tdm_client_output_disconnect(tdm_client_output *output) +{ + TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER); + return TDM_ERROR_NONE; +} diff --git a/haltests/src/tc_tdm_client.cpp b/haltests/src/tc_tdm_client.cpp index 10e122d..20aa27f 100644 --- a/haltests/src/tc_tdm_client.cpp +++ b/haltests/src/tc_tdm_client.cpp @@ -66,6 +66,7 @@ public: tdm_client *client; tdm_client_output *output; tdm_client_vblank *vblank; + tdm_client_voutput *voutput; double vrefresh_interval, start, end; @@ -1358,6 +1359,213 @@ TEST_P(TDMClient, ClientVblankIsWaitingNullObject) ASSERT_EQ(waiting, 0); } +TEST_P(TDMClient, ClientCreateVOutput) +{ + tdm_error ret; + const char name[TDM_NAME_LEN] = "Virtual Output"; + + ASSERT_EQ(PrepareClient(), true); + + voutput = tdm_client_create_voutput(client, name, &ret); + ASSERT_EQ(ret, TDM_ERROR_NONE); + ASSERT_NE(voutput, NULL); + + tdm_client_voutput_destroy(voutput); +} + +class TDMVirtualOutput : public ::testing::Test +{ +public: + TDMVirtualOutput() {}; + ~TDMVirtualOutput() {}; + + static void SetUpTestCase(); + static void TearDownTestCase(); + static bool PrepareVOutput(void); + +protected: + static tdm_client *client; + static tdm_client_voutput *voutput; + const int MODE_COUNT = 1; + +private: + static pid_t server_pid; + + /* 0: read, 1: write */ + static int pipe_parent[2]; + static int pipe_child[2]; + + static void ServerFork(void); + static void ServerKill(void); +}; + +pid_t TDMVirtualOutput::server_pid = -1; +int TDMVirtualOutput::pipe_parent[2] = {-1, -1}; +int TDMVirtualOutput::pipe_child[2] = {-1, -1}; +tdm_client* TDMVirtualOutput::client = nullptr; +tdm_client_voutput* TDMVirtualOutput::voutput = nullptr; + +void TDMVirtualOutput::ServerKill(void) +{ + if (pipe_child[0] >= 0) + close(pipe_child[0]); + if (pipe_child[1] >= 0) { + if (server_pid > 0) { + bool ret = _tc_tdm_pipe_write_msg(pipe_child[1], pipe_parent[0], TDM_UT_PIPE_MSG_TERMINATE_SERVER); + if (ret) { + if (waitpid(server_pid, NULL, 0) == server_pid) + TDM_INFO("*** server terminated ***"); + else + TDM_ERR("*** failed to terminate server ***"); + } else { + if (kill(server_pid, 9) < 0) + TDM_ERR("*** failed to kill server ***"); + } + } + close(pipe_child[1]); + } + + if (pipe_parent[0] >= 0) + close(pipe_parent[0]); + if (pipe_parent[1] >= 0) + close(pipe_parent[1]); + + server_pid = -1; + pipe_parent[0] = pipe_parent[1] = -1; + pipe_child[0] = pipe_child[1] = -1; +} + +void TDMVirtualOutput::ServerFork(void) +{ + if (server_pid > 0) + return; + + server_pid = _tc_tdm_client_server_fork(pipe_parent, pipe_child); + ASSERT_GT(server_pid, 0); +} + +void TDMVirtualOutput::SetUpTestCase(void) +{ + setenv("XDG_RUNTIME_DIR", "/run", 1); + setenv("TBM_DISPLAY_SERVER", "1", 1); + + if (server_pid == -1) + ServerFork(); + + ASSERT_EQ(PrepareVOutput(), true); +} + +void TDMVirtualOutput::TearDownTestCase(void) +{ + if (voutput) + tdm_client_voutput_destroy(voutput); + + if (client) + tdm_client_destroy(client); + + ServerKill(); + + unsetenv("XDG_RUNTIME_DIR"); + unsetenv("TBM_DISPLAY_SERVER"); +} + +bool TDMVirtualOutput::PrepareVOutput(void) +{ + tdm_error ret; + const char name[TDM_NAME_LEN] = "Virtual Output"; + + client = tdm_client_create(&ret); + TDM_UT_RETURN_FALSE_IF_FAIL(ret == TDM_ERROR_NONE); + TDM_UT_RETURN_FALSE_IF_FAIL(client != NULL); + + voutput = tdm_client_create_voutput(client, name, &ret); + TDM_UT_RETURN_FALSE_IF_FAIL(ret == TDM_ERROR_NONE); + TDM_UT_RETURN_FALSE_IF_FAIL(voutput != NULL); + return true; +} + +TEST_F(TDMVirtualOutput, SetAvailableModes) +{ + tdm_error ret; + tdm_client_output_mode modes[this->MODE_COUNT]; + int i, count = this->MODE_COUNT; + + for (i = 0; i < count; i++) + { + modes[i].mmHeight = 1234; + modes[i].mmWidth = 1234; + modes[i].mode_count = 0; + modes[i].prop_count = 0; + modes[i].subpixel = 0; + snprintf(modes[i].name, TDM_NAME_LEN, "TestModeSetting"); + } + + ret = tdm_client_voutput_set_available_modes(this->voutput, modes, count); + ASSERT_EQ(ret, TDM_ERROR_NONE); +} + +TEST_F(TDMVirtualOutput, FailTestSetAvailableModes) +{ + tdm_error ret; + tdm_client_output_mode modes[this->MODE_COUNT]; + int count = this->MODE_COUNT; + + ret = tdm_client_voutput_set_available_modes(NULL, modes, count); + ASSERT_EQ(ret, TDM_ERROR_INVALID_PARAMETER); + + ret = tdm_client_voutput_set_available_modes(this->voutput, NULL, count); + ASSERT_EQ(ret, TDM_ERROR_INVALID_PARAMETER); + + ret = tdm_client_voutput_set_available_modes(this->voutput, modes, 0); + ASSERT_EQ(ret, TDM_ERROR_INVALID_PARAMETER); +} + +TEST_F(TDMVirtualOutput, SetPhysicalSize) +{ + tdm_error ret; + int mmWidth = 1234, mmHeight = 1234; + + ret = tdm_client_voutput_set_physical_size(this->voutput, mmWidth, mmHeight); + ASSERT_EQ(ret, TDM_ERROR_NONE); +} + +TEST_F(TDMVirtualOutput, FailTestSetPhysicalSize) +{ + tdm_error ret; + int invalid_mmWidth = -1, invalid_mmHeight = -1; + + ret = tdm_client_voutput_set_physical_size(this->voutput, invalid_mmWidth, invalid_mmHeight); + ASSERT_EQ(ret, TDM_ERROR_INVALID_PARAMETER); +} + +TEST_F(TDMVirtualOutput, GetClientOutput) +{ + tdm_error ret; + tdm_client_output *output; + + output = tdm_client_voutput_get_client_output(this->voutput, &ret); + ASSERT_EQ(ret, TDM_ERROR_NONE); + ASSERT_NE(output, NULL); +} + +#if 0 +TEST_F(TDMVirtualOutput, FailTestGetClientOutput) +{ + tdm_error ret; +} + +TEST_F(TDMVirtualOutput, SetBufferQueue) +{ + tdm_error ret; +} + +TEST_F(TDMVirtualOutput, FailTestSetBufferQueue) +{ + tdm_error ret; +} + +#endif + #ifdef TDM_UT_TEST_WITH_PARAMS INSTANTIATE_TEST_CASE_P(TDMClientParams, TDMClient, @@ -1368,4 +1576,4 @@ INSTANTIATE_TEST_CASE_P(TDMClientParams, Values(TDM_DEFAULT_MODULE)); #endif -/* LCOV_EXCL_END */ \ No newline at end of file +/* LCOV_EXCL_END */ diff --git a/protocol/tdm.xml b/protocol/tdm.xml index 6434e98..58422cf 100644 --- a/protocol/tdm.xml +++ b/protocol/tdm.xml @@ -23,6 +23,11 @@ + + + + + @@ -66,6 +71,22 @@ + + + + + + + + + + + + + + + + diff --git a/src/tdm_server.c b/src/tdm_server.c index 30bb475..d77151c 100644 --- a/src/tdm_server.c +++ b/src/tdm_server.c @@ -682,6 +682,27 @@ _tdm_server_cb_create_output(struct wl_client *client, struct wl_resource *resou } } +static void +_tdm_server_cb_create_virtual_output(struct wl_client *client, struct wl_resource *resource, const char *name, uint32_t id) +{ + struct wl_resource *voutput_resource = NULL; + + voutput_resource = + wl_resource_create(client, &wl_tdm_voutput_interface, + wl_resource_get_version(resource), id); + if (!voutput_resource) { + /* LCOV_EXCL_START */ + + wl_resource_post_no_memory(resource); + TDM_ERR("wl_resource_create failed"); + return; + + /* LCOV_EXCL_STOP */ + } + + wl_tdm_voutput_send_ack_message(voutput_resource, WL_TDM_VOUTPUT_MESSAGE_ADDED); +} + /* LCOV_EXCL_START */ static void _tdm_server_cb_debug(struct wl_client *client, struct wl_resource *resource, const char *options) @@ -727,6 +748,7 @@ _tdm_server_cb_debug(struct wl_client *client, struct wl_resource *resource, con static const struct wl_tdm_interface tdm_implementation = { _tdm_server_cb_debug, _tdm_server_cb_create_output, + _tdm_server_cb_create_virtual_output }; static void -- 2.7.4 From e1484d5a3d75564e15a09d9321eb132393d890ce Mon Sep 17 00:00:00 2001 From: Boram Park Date: Mon, 9 Apr 2018 21:34:02 +0900 Subject: [PATCH 08/16] implementation Change-Id: I6600b589fb140b2ff5a5c5258f4ddf9bcab89e87 Signed-off-by: Junkyeong Kim --- backends/dummy/tdm_dummy_display.c | 2 +- src/tdm.c | 177 +++++++++++++++++++++++++++---------- src/tdm_backend.c | 47 ++++++++++ src/tdm_display.c | 123 ++++++++++++++++++++++++++ src/tdm_event_loop.c | 4 + src/tdm_helper.c | 4 + src/tdm_layer.c | 14 +++ src/tdm_macro.h | 2 + src/tdm_output.c | 125 +++++++++++++++++++++++++- src/tdm_private.h | 17 +++- src/tdm_private_types.h | 39 ++++++++ src/tdm_thread.c | 2 + 12 files changed, 506 insertions(+), 50 deletions(-) diff --git a/backends/dummy/tdm_dummy_display.c b/backends/dummy/tdm_dummy_display.c index a43c8c9..a3d9d2d 100644 --- a/backends/dummy/tdm_dummy_display.c +++ b/backends/dummy/tdm_dummy_display.c @@ -233,7 +233,7 @@ tdm_dummy_display_create_output_list(tdm_dummy_data *dummy_data) output_data->dummy_data = dummy_data; output_data->pipe = 0; output_data->connector_type = TDM_OUTPUT_TYPE_Unknown; - output_data->status = TDM_OUTPUT_CONN_STATUS_CONNECTED; + output_data->status = TDM_OUTPUT_CONN_STATUS_DISCONNECTED; output_data->output_mode = calloc(1, sizeof(tdm_output_mode)); if (!output_data->output_mode) { diff --git a/src/tdm.c b/src/tdm.c index 6f938ec..3bbd6c3 100644 --- a/src/tdm.c +++ b/src/tdm.c @@ -50,6 +50,8 @@ pthread_mutex_t tdm_debug_mutex_check_lock = PTHREAD_MUTEX_INITIALIZER; const char *tdm_debug_mutex_lock_func; int tdm_debug_mutex_lock_line; +static tdm_error _tdm_display_load_module_with_file(tdm_private_display *private_display, const char *file); + /* LCOV_EXCL_START */ static tdm_private_layer * _tdm_display_find_private_layer(tdm_private_output *private_output, @@ -81,6 +83,34 @@ tdm_display_find_private_output(tdm_private_display *private_display, tdm_output return NULL; } +INTERN unsigned int +tdm_display_find_empty_output_pipe(tdm_private_display *private_display) +{ + tdm_private_module *private_module = NULL; + tdm_private_output *private_output = NULL; + unsigned int pipe = 0; + while(1) { + int found = 0; + LIST_FOR_EACH_ENTRY(private_module, &private_display->module_list, link) { + LIST_FOR_EACH_ENTRY(private_output, &private_module->output_list, link) { + if (private_output->pipe == pipe) { + found = 1; + break; + } + } + if (found) + break; + } + + if (!found) + break; + else + pipe++; + } + + return pipe; +} + INTERN void * tdm_display_find_output_stamp(tdm_private_display *private_display, double stamp) { @@ -197,8 +227,8 @@ _tdm_display_destroy_private_layer(tdm_private_layer *private_layer) free(private_layer); } -static void -_tdm_display_destroy_private_output(tdm_private_output *private_output) +INTERN void +tdm_display_destroy_private_output(tdm_private_output *private_output) { tdm_private_display *private_display = private_output->private_display; tdm_private_layer *l = NULL, *ll = NULL; @@ -210,6 +240,11 @@ _tdm_display_destroy_private_output(tdm_private_output *private_output) tdm_private_hwc_commit_handler *hm = NULL, *hmm = NULL; tdm_private_layer_commit_handler *lm = NULL, *lmm = NULL; tdm_private_output_change_handler *h = NULL, *hh = NULL; + tdm_private_output_destroy_handler *dh = NULL, *dhh = NULL; + tdm_error ret; + + ret = tdm_output_call_thread_cb_destroy(private_output); + TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE); free(private_output->layers_ptr); @@ -251,6 +286,12 @@ _tdm_display_destroy_private_output(tdm_private_output *private_output) free(h); } + LIST_FOR_EACH_ENTRY_SAFE(dh, dhh, &private_output->destroy_handler_list, link) { + LIST_DEL(&dh->link); + tdm_thread_cb_remove(dh->private_output, TDM_THREAD_CB_OUTPUT_DESTROY, NULL, tdm_output_thread_cb_destroy, dh); + free(dh); + } + if (private_output->vblank) { /* tdm_vblank APIs is for server. it should be called in unlock status*/ _pthread_mutex_unlock(&private_display->lock); @@ -295,6 +336,7 @@ _tdm_display_destroy_private_display(tdm_private_display *private_display) tdm_private_module *private_module = NULL, *bb = NULL; tdm_private_output *o = NULL, *oo = NULL; tdm_private_pp *p = NULL, *pp = NULL; + tdm_private_output_create_handler *ch = NULL, *chh = NULL; LIST_FOR_EACH_ENTRY_SAFE(private_module, bb, &private_display->module_list, link) { LIST_FOR_EACH_ENTRY_SAFE(p, pp, &private_module->pp_list, link) { @@ -302,7 +344,7 @@ _tdm_display_destroy_private_display(tdm_private_display *private_display) } LIST_FOR_EACH_ENTRY_SAFE(o, oo, &private_module->output_list, link) { - _tdm_display_destroy_private_output(o); + tdm_display_destroy_private_output(o); } _tdm_display_destroy_caps_pp(&private_module->caps_pp); @@ -316,6 +358,13 @@ _tdm_display_destroy_private_display(tdm_private_display *private_display) private_module->outputs = NULL; } } + + LIST_FOR_EACH_ENTRY_SAFE(ch, chh, &private_display->output_create_handler_list, link) { + LIST_DEL(&ch->link); + tdm_thread_cb_remove(ch->private_display, TDM_THREAD_CB_DISPLAY_OUTPUT_CREATE, NULL, + tdm_display_thread_cb_output_create, ch); + free(ch); + } } static tdm_error @@ -392,11 +441,6 @@ _tdm_display_update_caps_output(tdm_private_module *private_module, int pipe, tdm_error ret; double stamp; - if (!func_output->output_get_capability) { - TDM_ERR("backend(%s) no output_get_capability()", private_module->module_data->name); - return TDM_ERROR_BAD_MODULE; - } - stamp = tdm_helper_get_time(); ret = func_output->output_get_capability(output_backend, caps); TDM_DBG("backend(%s) backend output_get_capability() time: %.3f ms", @@ -446,30 +490,35 @@ _tdm_display_update_layer(tdm_private_output *private_output, } INTERN tdm_error -tdm_display_update_output(tdm_private_module *private_module, - tdm_output *output_backend, int pipe, unsigned int need_new_caps) +tdm_display_update_output(tdm_private_module *private_module, tdm_output *output_backend) { tdm_func_output *func_output = &private_module->func_output; + tdm_private_display *private_display = NULL; tdm_private_output *private_output = NULL; tdm_layer **layers = NULL; tdm_private_hwc *private_hwc = NULL; tdm_hwc *hwc; int layer_count = 0, i; tdm_error ret; + unsigned int output_created = 0; + + private_display = private_module->private_display; - private_output = tdm_display_find_private_output(private_module->private_display, output_backend); + private_output = tdm_display_find_private_output(private_display, output_backend); if (!private_output) { + unsigned int pipe = tdm_display_find_empty_output_pipe(private_display); + private_output = calloc(1, sizeof(tdm_private_output)); TDM_RETURN_VAL_IF_FAIL(private_output != NULL, TDM_ERROR_OUT_OF_MEMORY); private_output->stamp = tdm_helper_get_time(); - while (tdm_display_find_output_stamp(private_module->private_display, private_output->stamp)) + while (tdm_display_find_output_stamp(private_display, private_output->stamp)) private_output->stamp++; LIST_ADDTAIL(&private_output->link, &private_module->output_list); private_output->private_module = private_module; - private_output->private_display = private_module->private_display; + private_output->private_display = private_display; private_output->current_dpms_value = TDM_OUTPUT_DPMS_OFF; private_output->output_backend = output_backend; private_output->pipe = pipe; @@ -479,6 +528,7 @@ tdm_display_update_output(tdm_private_module *private_module, LIST_INITHEAD(&private_output->vblank_handler_list); LIST_INITHEAD(&private_output->output_commit_handler_list); LIST_INITHEAD(&private_output->pending_commit_handler_list); + LIST_INITHEAD(&private_output->destroy_handler_list); LIST_INITHEAD(&private_output->change_handler_list); if (func_output->output_set_status_handler) { @@ -488,7 +538,11 @@ tdm_display_update_output(tdm_private_module *private_module, private_output->regist_change_cb = 1; } - ret = _tdm_display_update_caps_output(private_module, pipe, output_backend, &private_output->caps); + output_created = 1; + + /* NOTE that output modes will be allocated newly after here */ + _tdm_display_destroy_caps_output(&private_output->caps); + ret = _tdm_display_update_caps_output(private_module, private_output->pipe, output_backend, &private_output->caps); TDM_RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, ret); if (private_output->caps.status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) @@ -519,18 +573,12 @@ tdm_display_update_output(tdm_private_module *private_module, LIST_INITHEAD(&private_output->layer_commit_handler_list); } } else { - /* need_new_caps will be true only in case of "disconnected -> connected" and "connected -> disconnected" - * because we have to get new modes. - */ - if (need_new_caps) { - _tdm_display_destroy_caps_output(&private_output->caps); - - ret = _tdm_display_update_caps_output(private_module, pipe, output_backend, &private_output->caps); - TDM_RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, ret); + _tdm_display_destroy_caps_output(&private_output->caps); + ret = _tdm_display_update_caps_output(private_module, private_output->pipe, output_backend, &private_output->caps); + TDM_RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, ret); - if (private_output->caps.status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) - private_output->current_mode = NULL; - } + if (private_output->caps.status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) + private_output->current_mode = NULL; } /* do not use the layer object when the tdm_output has the hwc capability */ @@ -552,6 +600,11 @@ tdm_display_update_output(tdm_private_module *private_module, free(layers); } + if (output_created) { + ret = tdm_display_call_thread_cb_output_create(private_display, private_output); + TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE); + } + return TDM_ERROR_NONE; } @@ -589,12 +642,12 @@ _tdm_display_get_ordered_outputs(tdm_private_module *private_module, int *count) outputs = func_display->display_get_outputs(private_module->bdata, &output_count, &ret); if (ret != TDM_ERROR_NONE) - goto failed_get_outputs; + goto no_output; *count = output_count; if (output_count == 0) - goto failed_get_outputs; + goto no_output; else if (output_count == 1) { private_module->outputs = outputs; return outputs; @@ -609,7 +662,7 @@ _tdm_display_get_ordered_outputs(tdm_private_module *private_module, int *count) ret = func_output->output_get_capability(outputs[i], &caps); if (ret != TDM_ERROR_NONE) { TDM_ERR("output_get_capability() failed"); - goto failed_get_outputs; + goto no_output; } if (caps.status == TDM_OUTPUT_CONN_STATUS_CONNECTED) { @@ -673,7 +726,7 @@ _tdm_display_get_ordered_outputs(tdm_private_module *private_module, int *count) return outputs; -failed_get_outputs: +no_output: free(outputs); *count = 0; return NULL; @@ -684,7 +737,7 @@ _tdm_display_setup(tdm_private_display *private_display) { tdm_private_module *private_module = NULL; tdm_error ret = TDM_ERROR_NONE; - int index = 0; + int output_count = 0; if (private_display->pp_module) { ret = _tdm_display_update_caps_pp(private_display->pp_module, @@ -702,14 +755,43 @@ _tdm_display_setup(tdm_private_display *private_display) LIST_FOR_EACH_ENTRY(private_module, &private_display->module_list, link) { tdm_output **outputs; - int output_count = 0, i; + int i, count = 0; - outputs = _tdm_display_get_ordered_outputs(private_module, &output_count); - if (!outputs) - goto failed_update; + outputs = _tdm_display_get_ordered_outputs(private_module, &count); + + if (count > 0) + TDM_GOTO_IF_FAIL(outputs != NULL, failed_update); + + for (i = 0; i < count; i++) { + ret = tdm_display_update_output(private_module, outputs[i]); + if (ret != TDM_ERROR_NONE) + goto failed_update; + output_count++; + } + } + + /* At least, the output count should be greater than 0 to ensure tdm_vblank works. + * So we will create a dummy output when backends don't have any output. + * Without destroying a tdm_output object, this dummy output will be replaced with + * a virtual output which is created in runtime. + */ + if (output_count == 0) { + tdm_output **outputs; + int i, count = 0; + + TDM_INFO("loading a %s backend", TDM_DUMMY_MODULE); + ret = _tdm_display_load_module_with_file(private_display, TDM_DUMMY_MODULE); + TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, failed_update); + TDM_GOTO_IF_FAIL(private_display->dummy_module != NULL, failed_update); + + private_module = private_display->dummy_module; - for (i = 0; i < output_count; i++) { - ret = tdm_display_update_output(private_module, outputs[i], index++, 1); + outputs = _tdm_display_get_ordered_outputs(private_module, &count); + TDM_GOTO_IF_FAIL(count > 0, failed_update); + TDM_GOTO_IF_FAIL(outputs != NULL, failed_update); + + for (i = 0; i < count; i++) { + ret = tdm_display_update_output(private_module, outputs[i]); if (ret != TDM_ERROR_NONE) goto failed_update; } @@ -925,6 +1007,9 @@ _tdm_display_load_module_with_file(tdm_private_display *private_display, private_display->current_module = NULL; + if (!strncmp(file, TDM_DUMMY_MODULE, TDM_NAME_LEN)) + private_display->dummy_module = private_module; + private_module->bdata = bdata; if (ret != TDM_ERROR_NONE) { @@ -983,16 +1068,6 @@ _tdm_display_load_modules(tdm_private_display *private_display) arg = strtok_r(NULL, TDM_CONFIG_DELIM, &end); } - /* load bufmgr priv from dummy lib */ - if (LIST_IS_EMPTY(&private_display->module_list)) { - TDM_WRN("No backend. loading a %s backend", TDM_DUMMY_MODULE); - ret = _tdm_display_load_module_with_file(private_display, TDM_DUMMY_MODULE); - if (ret == TDM_ERROR_NONE) - TDM_INFO("%s backend loading success", TDM_DUMMY_MODULE); - else - TDM_INFO("%s backend loading failed", TDM_DUMMY_MODULE); - } - return ret; } @@ -1014,6 +1089,12 @@ _tdm_display_unload_modules(tdm_private_display *private_display) } /* LCOV_EXCL_STOP */ +INTERN void * +tdm_display_find_stamp(tdm_private_display *private_display, double stamp) +{ + return (void*)g_private_display; +} + EXTERN tdm_display * tdm_display_init(tdm_error *error) { @@ -1050,6 +1131,8 @@ tdm_display_init(tdm_error *error) private_display->stamp = tdm_helper_get_time(); + LIST_INITHEAD(&private_display->output_create_handler_list); + str = tdm_config_get_string(TDM_CONFIG_KEY_DEBUG_MODULE, NULL); if (str) tdm_display_enable_debug_module(str); @@ -1162,6 +1245,8 @@ tdm_display_init(tdm_error *error) if (error) *error = TDM_ERROR_NONE; + tdm_thread_cb_set_find_func(TDM_THREAD_CB_DISPLAY_OUTPUT_CREATE, tdm_display_find_stamp); + _pthread_mutex_unlock(&private_display->lock); pthread_mutex_unlock(&gLock); diff --git a/src/tdm_backend.c b/src/tdm_backend.c index c979129..7d469d1 100644 --- a/src/tdm_backend.c +++ b/src/tdm_backend.c @@ -44,6 +44,11 @@ TDM_RETURN_VAL_IF_FAIL(dpy != NULL, TDM_ERROR_INVALID_PARAMETER); \ private_display = (tdm_private_display*)dpy; +#define BACKEND_FUNC_ENTRY_VOID() \ + tdm_private_display *private_display; \ + TDM_RETURN_IF_FAIL(dpy != NULL); \ + private_display = (tdm_private_display*)dpy; + static int _check_abi_version(tdm_backend_module *module, int abimaj, int abimin) { @@ -224,3 +229,45 @@ tdm_backend_register_func_capture(tdm_display *dpy, return TDM_ERROR_NONE; } + +EXTERN tdm_error +tdm_backend_register_output(tdm_display *dpy, tdm_output *output) +{ + tdm_error ret; + + BACKEND_FUNC_ENTRY(); + + TDM_RETURN_VAL_IF_FAIL(TDM_MUTEX_IS_LOCKED(), TDM_ERROR_OPERATION_FAILED); + TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_OPERATION_FAILED); + + /* this function is only for backend. if backend calls this function, it means + * that it's triggered by frontend. frontend should set current_module before calling + * backend functions. + */ + TDM_RETURN_VAL_IF_FAIL(private_display->current_module != NULL, TDM_ERROR_OPERATION_FAILED); + + ret = tdm_display_update_output(private_display->current_module, output); + TDM_RETURN_VAL_IF_FAIL(ret == TDM_ERROR_NONE, ret); + + return TDM_ERROR_NONE; +} + +EXTERN void +tdm_backend_unregister_output(tdm_display *dpy, tdm_output *output) +{ + tdm_private_output *private_output; + + BACKEND_FUNC_ENTRY_VOID(); + + TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED()); + TDM_RETURN_IF_FAIL(output != NULL); + + /* this function is only for backend. if backend calls this function, it means + * that it's triggered by frontend. frontend should set current_module before calling + * backend functions. + */ + TDM_RETURN_IF_FAIL(private_display->current_module != NULL); + + private_output = tdm_display_find_private_output(private_display, output); + tdm_display_destroy_private_output(private_output); +} diff --git a/src/tdm_display.c b/src/tdm_display.c index 45ccdf2..9f6dd72 100644 --- a/src/tdm_display.c +++ b/src/tdm_display.c @@ -53,6 +53,13 @@ TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(dpy != NULL, TDM_ERROR_INVALID_PARAMETER, NULL); \ private_display = (tdm_private_display*)dpy; +#define DISPLAY_FUNC_ENTRY_VOID() \ + tdm_private_display *private_display; \ + TDM_RETURN_IF_FAIL(dpy != NULL); \ + TDM_RETURN_IF_FAIL(tdm_display_is_valid(dpy)); \ + private_display = (tdm_private_display*)dpy; + + #define BACKEND_FUNC_ENTRY() \ tdm_private_module *private_module; \ tdm_private_display *private_display; \ @@ -349,6 +356,122 @@ tdm_display_enable_fps(tdm_private_display *private_display, int enable) } /* LCOV_EXCL_STOP */ +INTERN tdm_error +tdm_display_call_thread_cb_output_create(tdm_private_display *private_display, tdm_output *output) +{ + tdm_thread_cb_display_output_create output_create; + tdm_error ret; + + memset(&output_create, 0, sizeof output_create); + output_create.base.type = TDM_THREAD_CB_DISPLAY_OUTPUT_CREATE; + output_create.base.length = sizeof output_create; + output_create.base.object_stamp = 0; + output_create.base.data = NULL; + output_create.base.sync = 1; + output_create.output = output; + + ret = tdm_thread_cb_call(private_display, &output_create.base, 1); + TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE); + + return TDM_ERROR_NONE; +} + +INTERN void +tdm_display_thread_cb_output_create(tdm_private_display *private_display, void *object, tdm_thread_cb_base *cb_base, void *user_data) +{ + tdm_thread_cb_display_output_create *output_create = (tdm_thread_cb_display_output_create*)cb_base; + tdm_private_output_create_handler *create_handler = user_data; + TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED()); + + assert(create_handler->owner_tid == syscall(SYS_gettid)); + + _pthread_mutex_unlock(&private_display->lock); + create_handler->func(private_display, output_create->output, create_handler->user_data); + _pthread_mutex_lock(&private_display->lock); +} + +EXTERN tdm_error +tdm_display_add_output_create_handler(tdm_display *dpy, + tdm_output_create_handler func, + void *user_data) +{ + tdm_private_output_create_handler *create_handler = NULL; + + DISPLAY_FUNC_ENTRY(); + + TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER); + + _pthread_mutex_lock(&private_display->lock); + + LIST_FOR_EACH_ENTRY(create_handler, &private_display->output_create_handler_list, link) { + if (create_handler->func == func && create_handler->user_data == user_data) { + TDM_ERR("can't add twice"); + _pthread_mutex_unlock(&private_display->lock); + return TDM_ERROR_BAD_REQUEST; + } + } + + create_handler = calloc(1, sizeof(tdm_private_output_create_handler)); + if (!create_handler) { + TDM_ERR("failed: alloc memory"); + _pthread_mutex_unlock(&private_display->lock); + return TDM_ERROR_OUT_OF_MEMORY; + } + + ret = tdm_thread_cb_add(private_display, TDM_THREAD_CB_DISPLAY_OUTPUT_CREATE, NULL, + tdm_display_thread_cb_output_create, create_handler); + if (ret != TDM_ERROR_NONE) { + TDM_ERR("tdm_thread_cb_add failed"); + free(create_handler); + _pthread_mutex_unlock(&private_display->lock); + return TDM_ERROR_OPERATION_FAILED; + } + + create_handler->private_display = private_display; + create_handler->func = func; + create_handler->user_data = user_data; + create_handler->owner_tid = syscall(SYS_gettid); + + LIST_ADDTAIL(&create_handler->link, &private_display->output_create_handler_list); + + _pthread_mutex_unlock(&private_display->lock); + + return ret; +} + +EXTERN void +tdm_display_remove_output_create_handler(tdm_display *dpy, + tdm_output_create_handler func, + void *user_data) +{ + tdm_private_display *private_display; + tdm_private_output_create_handler *create_handler = NULL, *hh = NULL; + + TDM_RETURN_IF_FAIL(dpy != NULL); + TDM_RETURN_IF_FAIL(func != NULL); + + private_display = (tdm_private_display*)dpy; + + _pthread_mutex_lock(&private_display->lock); + + LIST_FOR_EACH_ENTRY_SAFE(create_handler, hh, &private_display->output_create_handler_list, link) { + if (create_handler->func != func || create_handler->user_data != user_data) + continue; + + tdm_thread_cb_remove(private_display, TDM_THREAD_CB_DISPLAY_OUTPUT_CREATE, NULL, + tdm_display_thread_cb_output_create, create_handler); + + LIST_DEL(&create_handler->link); + free(create_handler); + + _pthread_mutex_unlock(&private_display->lock); + + return; + } + + _pthread_mutex_unlock(&private_display->lock); +} + EXTERN tdm_error tdm_display_get_capabilities(tdm_display *dpy, tdm_display_capability *capabilities) diff --git a/src/tdm_event_loop.c b/src/tdm_event_loop.c index b7de4ab..5117c27 100644 --- a/src/tdm_event_loop.c +++ b/src/tdm_event_loop.c @@ -63,6 +63,7 @@ static tdm_error _tdm_event_loop_main_fd_handler(int fd, tdm_event_loop_mask mask, void *user_data) { tdm_private_module *private_module = (tdm_private_module*)user_data; + tdm_private_display *private_display; tdm_func_display *func_display; tdm_error ret; @@ -76,7 +77,10 @@ _tdm_event_loop_main_fd_handler(int fd, tdm_event_loop_mask mask, void *user_dat if (!func_display->display_handle_events) return TDM_ERROR_NONE; + private_display = private_module->private_display; + private_display->current_module = private_module; ret = func_display->display_handle_events(private_module->bdata); + private_display->current_module = NULL; return ret; } diff --git a/src/tdm_helper.c b/src/tdm_helper.c index 0c8b336..5b5d96b 100644 --- a/src/tdm_helper.c +++ b/src/tdm_helper.c @@ -846,6 +846,8 @@ _tdm_helper_get_backend_information(tdm_private_module *private_module, char *re } } } + if (LIST_IS_EMPTY(&private_module->output_list)) + TDM_SNPRINTF(reply, len, "(no output)\n"); TDM_SNPRINTF(reply, len, "\n"); /* layer information */ @@ -948,6 +950,8 @@ _tdm_helper_get_backend_information(tdm_private_module *private_module, char *re } } } + if (LIST_IS_EMPTY(&private_module->output_list)) + TDM_SNPRINTF(reply, len, "(no layer)\n"); TDM_SNPRINTF(reply, len, "\n"); if (private_module->capabilities & TDM_DISPLAY_CAPABILITY_PP) { diff --git a/src/tdm_layer.c b/src/tdm_layer.c index d8503a5..429f885 100644 --- a/src/tdm_layer.c +++ b/src/tdm_layer.c @@ -1265,6 +1265,20 @@ tdm_layer_set_buffer_queue(tdm_layer *layer, tbm_surface_queue_h buffer_queue) return ret; } +tdm_error +tdm_layer_get_own_buffer_queue(tdm_layer *layer, tbm_surface_queue_h *buffer_queue) +{ + LAYER_FUNC_ENTRY(); + + TDM_RETURN_VAL_IF_FAIL(buffer_queue != NULL, TDM_ERROR_INVALID_PARAMETER); + + _pthread_mutex_lock(&private_display->lock); + + _pthread_mutex_unlock(&private_display->lock); + + return ret; +} + EXTERN tdm_error tdm_layer_unset_buffer_queue(tdm_layer *layer) { diff --git a/src/tdm_macro.h b/src/tdm_macro.h index 5b8f861..24899c3 100644 --- a/src/tdm_macro.h +++ b/src/tdm_macro.h @@ -245,6 +245,8 @@ TDM_TYPE_NAME_FN(value_type) static struct tdm_type_name tdm_cb_type_names[] = { { TDM_THREAD_CB_NONE, "none" }, { TDM_THREAD_CB_EXIT, "exit" }, + { TDM_THREAD_CB_DISPLAY_OUTPUT_CREATE, "output-create" }, + { TDM_THREAD_CB_OUTPUT_DESTROY, "output-destroy" }, { TDM_THREAD_CB_OUTPUT_COMMIT, "output-commit" }, { TDM_THREAD_CB_OUTPUT_VBLANK, "output-vblank" }, { TDM_THREAD_CB_OUTPUT_STATUS, "output-status" }, diff --git a/src/tdm_output.c b/src/tdm_output.c index ee760c1..550a750 100644 --- a/src/tdm_output.c +++ b/src/tdm_output.c @@ -57,6 +57,13 @@ private_output = (tdm_private_output*)output; \ private_display = private_output->private_display +#define OUTPUT_FUNC_ENTRY_VOID() \ + tdm_private_display *private_display; \ + tdm_private_output *private_output; \ + TDM_RETURN_IF_FAIL(tdm_output_is_valid(output)); \ + private_output = (tdm_private_output*)output; \ + private_display = private_output->private_display + static void _tdm_output_vblank_timeout_update(tdm_private_output *private_output, int ms_delay); @@ -130,15 +137,131 @@ _tdm_output_vblank_timeout_update(tdm_private_output *private_output, int ms_del INTERN tdm_error tdm_output_init(tdm_private_display *private_display) { + tdm_thread_cb_set_find_func(TDM_THREAD_CB_OUTPUT_DESTROY, tdm_display_find_output_stamp); tdm_thread_cb_set_find_func(TDM_THREAD_CB_OUTPUT_COMMIT, tdm_display_find_output_stamp); tdm_thread_cb_set_find_func(TDM_THREAD_CB_OUTPUT_VBLANK, tdm_display_find_output_stamp); tdm_thread_cb_set_find_func(TDM_THREAD_CB_OUTPUT_STATUS, tdm_display_find_output_stamp); tdm_thread_cb_set_find_func(TDM_THREAD_CB_OUTPUT_DPMS, tdm_display_find_output_stamp); + return TDM_ERROR_NONE; +} + +INTERN tdm_error +tdm_output_call_thread_cb_destroy(tdm_private_output *private_output) +{ + tdm_thread_cb_output_destroy output_destroy; + tdm_error ret; + + memset(&output_destroy, 0, sizeof output_destroy); + output_destroy.base.type = TDM_THREAD_CB_OUTPUT_DESTROY; + output_destroy.base.length = sizeof output_destroy; + output_destroy.base.object_stamp = private_output->stamp; + output_destroy.base.data = NULL; + output_destroy.base.sync = 1; + + ret = tdm_thread_cb_call(private_output, &output_destroy.base, 1); + TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE); return TDM_ERROR_NONE; } +INTERN void +tdm_output_thread_cb_destroy(tdm_private_display *private_display, void *object, tdm_thread_cb_base *cb_base, void *user_data) +{ + tdm_private_output *private_output = object; + tdm_private_output_destroy_handler *destroy_handler = user_data; + + TDM_RETURN_IF_FAIL(TDM_MUTEX_IS_LOCKED()); + + assert(destroy_handler->owner_tid == syscall(SYS_gettid)); + + _pthread_mutex_unlock(&private_display->lock); + destroy_handler->func(private_output, destroy_handler->user_data); + _pthread_mutex_lock(&private_display->lock); +} + +EXTERN tdm_error +tdm_output_add_destroy_handler(tdm_output *output, + tdm_output_destroy_handler func, + void *user_data) +{ + tdm_private_output_destroy_handler *destroy_handler = NULL; + OUTPUT_FUNC_ENTRY(); + + TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER); + + _pthread_mutex_lock(&private_display->lock); + + LIST_FOR_EACH_ENTRY(destroy_handler, &private_output->destroy_handler_list, link) { + if (destroy_handler->func == func && destroy_handler->user_data == user_data) { + TDM_ERR("can't add twice"); + _pthread_mutex_unlock(&private_display->lock); + return TDM_ERROR_BAD_REQUEST; + } + } + + destroy_handler = calloc(1, sizeof(tdm_private_output_destroy_handler)); + if (!destroy_handler) { + TDM_ERR("failed: alloc memory"); + _pthread_mutex_unlock(&private_display->lock); + return TDM_ERROR_OUT_OF_MEMORY; + } + + ret = tdm_thread_cb_add(private_output, TDM_THREAD_CB_OUTPUT_DESTROY, NULL, tdm_output_thread_cb_destroy, destroy_handler); + if (ret != TDM_ERROR_NONE) { + TDM_ERR("tdm_thread_cb_add failed"); + free(destroy_handler); + _pthread_mutex_unlock(&private_display->lock); + return TDM_ERROR_OPERATION_FAILED; + } + + destroy_handler->private_output = private_output; + destroy_handler->func = func; + destroy_handler->user_data = user_data; + destroy_handler->owner_tid = syscall(SYS_gettid); + + LIST_ADDTAIL(&destroy_handler->link, &private_output->destroy_handler_list); + + _pthread_mutex_unlock(&private_display->lock); + + return ret; +} + + +EXTERN void +tdm_output_remove_destroy_handler(tdm_output *output, + tdm_output_destroy_handler func, + void *user_data) +{ + tdm_private_display *private_display; + tdm_private_output *private_output; + tdm_private_output_destroy_handler *destroy_handler = NULL, *hh = NULL; + + TDM_RETURN_IF_FAIL(output != NULL); + TDM_RETURN_IF_FAIL(func != NULL); + + private_output = (tdm_private_output*)output; + private_display = private_output->private_display; + + _pthread_mutex_lock(&private_display->lock); + + LIST_FOR_EACH_ENTRY_SAFE(destroy_handler, hh, &private_output->destroy_handler_list, link) { + if (destroy_handler->func != func || destroy_handler->user_data != user_data) + continue; + + tdm_thread_cb_remove(private_output, TDM_THREAD_CB_OUTPUT_DESTROY, NULL, tdm_output_thread_cb_destroy, destroy_handler); + + LIST_DEL(&destroy_handler->link); + free(destroy_handler); + + _pthread_mutex_unlock(&private_display->lock); + + return; + } + + _pthread_mutex_unlock(&private_display->lock); +} + EXTERN tdm_module * tdm_output_get_backend_module(tdm_output *output, tdm_error *error) { @@ -297,7 +420,7 @@ tdm_output_cb_status(tdm_output *output_backend, tdm_output_conn_status status, if ((private_output->caps.status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED && status != TDM_OUTPUT_CONN_STATUS_DISCONNECTED) || (private_output->caps.status != TDM_OUTPUT_CONN_STATUS_DISCONNECTED && status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED)) { - ret = tdm_display_update_output(private_output->private_module, output_backend, private_output->pipe, 1); + ret = tdm_display_update_output(private_output->private_module, output_backend); TDM_RETURN_IF_FAIL(ret == TDM_ERROR_NONE); } else { private_output->caps.status = status; diff --git a/src/tdm_private.h b/src/tdm_private.h index 5e1ed84..6478221 100644 --- a/src/tdm_private.h +++ b/src/tdm_private.h @@ -88,10 +88,17 @@ tdm_display_get(void); int tdm_module_check_abi(tdm_private_module *private_module, int abimaj, int abimin); +tdm_error +tdm_display_call_thread_cb_output_create(tdm_private_display *private_display, tdm_output *output); +void +tdm_display_thread_cb_output_create(tdm_private_display *private_display, void *object, tdm_thread_cb_base *cb_base, void *user_data); void * tdm_display_find_output_stamp(tdm_private_display *private_display, double stamp); tdm_private_output * tdm_display_find_private_output(tdm_private_display *private_display, tdm_output *output_backend); +unsigned int +tdm_display_find_empty_output_pipe(tdm_private_display *private_display); + void * tdm_display_find_hwc_stamp(tdm_private_display *private_display, double stamp); @@ -101,6 +108,10 @@ tdm_display_find_private_hwc(tdm_private_display *private_display, tdm_hwc *hwc_ tdm_error tdm_output_init(tdm_private_display *private_display); +tdm_error +tdm_output_call_thread_cb_destroy(tdm_private_output *private_output); +void +tdm_output_thread_cb_destroy(tdm_private_display *private_display, void *object, tdm_thread_cb_base *cb_base, void *user_data); void tdm_output_thread_cb_change(tdm_private_display *private_display, void *object, tdm_thread_cb_base *cb_base, void *user_data); void @@ -225,8 +236,10 @@ extern int tdm_dump_enable; extern char *tdm_debug_dump_dir; tdm_error -tdm_display_update_output(tdm_private_module *private_module, - tdm_output *output_backend, int pipe, unsigned int need_new_caps); +tdm_display_update_output(tdm_private_module *private_module, tdm_output *output_backend); +void +tdm_display_destroy_private_output(tdm_private_output *private_output); + tdm_error tdm_display_enable_debug_module(const char*modules); tdm_error diff --git a/src/tdm_private_types.h b/src/tdm_private_types.h index 37adf72..365ea7d 100644 --- a/src/tdm_private_types.h +++ b/src/tdm_private_types.h @@ -107,6 +107,8 @@ typedef struct _tdm_private_capture tdm_private_capture; typedef struct _tdm_private_loop tdm_private_loop; typedef struct _tdm_private_server tdm_private_server; typedef struct _tdm_private_thread tdm_private_thread; +typedef struct _tdm_private_output_create_handler tdm_private_output_create_handler; +typedef struct _tdm_private_output_destroy_handler tdm_private_output_destroy_handler; typedef struct _tdm_private_output_change_handler tdm_private_output_change_handler; typedef struct _tdm_private_output_commit_handler tdm_private_output_commit_handler; typedef struct _tdm_private_output_vblank_handler tdm_private_output_vblank_handler; @@ -163,6 +165,7 @@ struct _tdm_private_display { #endif struct list_head module_list; + tdm_private_module *dummy_module; tdm_private_module *current_module; //setted only when loading tdm_private_module *pp_module; //pp-support backend tdm_private_module *capture_module; //TODO: remove later @@ -170,6 +173,8 @@ struct _tdm_private_display { /* for event handling */ tdm_private_loop *private_loop; + struct list_head output_create_handler_list; + int print_fps; }; @@ -210,6 +215,7 @@ struct _tdm_private_output { tdm_event_loop_source *vblank_timeout_timer; unsigned int vblank_timeout_timer_expired; + struct list_head destroy_handler_list; struct list_head change_handler_list; void **layers_ptr; @@ -384,6 +390,26 @@ struct _tdm_private_output_vblank_handler { pid_t owner_tid; }; +struct _tdm_private_output_create_handler { + struct list_head link; + + tdm_private_display *private_display; + tdm_output_create_handler func; + void *user_data; + + pid_t owner_tid; +}; + +struct _tdm_private_output_destroy_handler { + struct list_head link; + + tdm_private_output *private_output; + tdm_output_destroy_handler func; + void *user_data; + + pid_t owner_tid; +}; + struct _tdm_private_output_change_handler { struct list_head link; @@ -458,6 +484,8 @@ typedef struct _tdm_capture_private_buffer { typedef enum { TDM_THREAD_CB_NONE, TDM_THREAD_CB_EXIT, /* special type to exit the tdm-thread */ + TDM_THREAD_CB_DISPLAY_OUTPUT_CREATE, + TDM_THREAD_CB_OUTPUT_DESTROY, TDM_THREAD_CB_OUTPUT_COMMIT, TDM_THREAD_CB_OUTPUT_VBLANK, TDM_THREAD_CB_OUTPUT_STATUS, @@ -471,6 +499,8 @@ typedef enum { } tdm_thread_cb_type; typedef struct _tdm_thread_cb_base tdm_thread_cb_base; +typedef struct _tdm_thread_cb_display_output_create tdm_thread_cb_display_output_create; +typedef struct _tdm_thread_cb_output_destroy tdm_thread_cb_output_destroy; typedef struct _tdm_thread_cb_output_vblank tdm_thread_cb_output_commit; typedef struct _tdm_thread_cb_output_vblank tdm_thread_cb_output_vblank; typedef struct _tdm_thread_cb_output_dpms tdm_thread_cb_output_dpms; @@ -489,6 +519,15 @@ struct _tdm_thread_cb_base { unsigned int sync; }; +struct _tdm_thread_cb_display_output_create { + tdm_thread_cb_base base; + tdm_output *output; +}; + +struct _tdm_thread_cb_output_destroy { + tdm_thread_cb_base base; +}; + struct _tdm_thread_cb_output_vblank { tdm_thread_cb_base base; unsigned int sequence; diff --git a/src/tdm_thread.c b/src/tdm_thread.c index 2cc2f13..d367d4e 100644 --- a/src/tdm_thread.c +++ b/src/tdm_thread.c @@ -451,6 +451,8 @@ tdm_thread_handle_cb(tdm_private_loop *private_loop) if (tdm_debug_module & TDM_DEBUG_THREAD) TDM_INFO("type(%s), length(%d)", tdm_cb_type_str(base->type), base->length); switch (base->type) { + case TDM_THREAD_CB_DISPLAY_OUTPUT_CREATE: + case TDM_THREAD_CB_OUTPUT_DESTROY: case TDM_THREAD_CB_OUTPUT_COMMIT: case TDM_THREAD_CB_OUTPUT_VBLANK: case TDM_THREAD_CB_OUTPUT_STATUS: -- 2.7.4 From eca0e8c8a3a8b1a4b27823a87a35f81044f10a77 Mon Sep 17 00:00:00 2001 From: Junkyeong Kim Date: Wed, 18 Jul 2018 11:51:46 +0900 Subject: [PATCH 09/16] virtual:add virtual backend copy dummy backend. load virtual backend module default. Change-Id: If130aa455e28ecf01a5674ae87d8247554144a09 Signed-off-by: Junkyeong Kim --- backends/Makefile.am | 2 +- backends/virtual/Makefile.am | 14 + backends/virtual/tdm_virtual.c | 134 +++++++ backends/virtual/tdm_virtual.h | 76 ++++ backends/virtual/tdm_virtual_display.c | 636 +++++++++++++++++++++++++++++++++ configure.ac | 1 + packaging/libtdm.spec | 1 + src/tdm.c | 8 + src/tdm_macro.h | 1 + src/tdm_private_types.h | 1 + 10 files changed, 873 insertions(+), 1 deletion(-) create mode 100644 backends/virtual/Makefile.am create mode 100644 backends/virtual/tdm_virtual.c create mode 100644 backends/virtual/tdm_virtual.h create mode 100644 backends/virtual/tdm_virtual_display.c diff --git a/backends/Makefile.am b/backends/Makefile.am index 4a66860..f841dd0 100644 --- a/backends/Makefile.am +++ b/backends/Makefile.am @@ -1 +1 @@ -SUBDIRS = dummy +SUBDIRS = dummy virtual diff --git a/backends/virtual/Makefile.am b/backends/virtual/Makefile.am new file mode 100644 index 0000000..099b71e --- /dev/null +++ b/backends/virtual/Makefile.am @@ -0,0 +1,14 @@ +AM_CFLAGS = \ + $(CFLAGS) \ + $(TDM_CFLAGS) \ + -I$(top_srcdir)/include + +libtdm_virtual_la_LTLIBRARIES = libtdm-virtual.la +libtdm_virtual_ladir = $(TDM_MODULE_PATH) +libtdm_virtual_la_LDFLAGS = -module -avoid-version +libtdm_virtual_la_LIBADD = $(TDM_LIBS) $(top_builddir)/src/libtdm.la + +libtdm_virtual_la_SOURCES = \ + tdm_virtual_display.c \ + tdm_virtual.c + diff --git a/backends/virtual/tdm_virtual.c b/backends/virtual/tdm_virtual.c new file mode 100644 index 0000000..f890829 --- /dev/null +++ b/backends/virtual/tdm_virtual.c @@ -0,0 +1,134 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tdm_virtual.h" + +static tdm_virtual_data *virtual_data; + +void +tdm_virtual_deinit(tdm_backend_data *bdata) +{ + if (virtual_data != bdata) + return; + + TDM_INFO("deinit"); + + tdm_virtual_display_destroy_output_list(virtual_data); + + if (virtual_data->pipe[0] >= 0) + close(virtual_data->pipe[0]); + if (virtual_data->pipe[1] >= 0) + close(virtual_data->pipe[1]); + + free(virtual_data); + virtual_data = NULL; +} + +tdm_backend_data * +tdm_virtual_init(tdm_display *dpy, tdm_error *error) +{ + tdm_func_display virtual_func_display; + tdm_func_output virtual_func_output; + tdm_func_layer virtual_func_layer; + tdm_error ret; + + if (!dpy) { + TDM_ERR("display is null"); + if (error) + *error = TDM_ERROR_INVALID_PARAMETER; + return NULL; + } + + if (virtual_data) { + TDM_ERR("failed: init twice"); + if (error) + *error = TDM_ERROR_BAD_REQUEST; + return NULL; + } + + virtual_data = calloc(1, sizeof(tdm_virtual_data)); + if (!virtual_data) { + TDM_ERR("alloc failed"); + if (error) + *error = TDM_ERROR_OUT_OF_MEMORY; + return NULL; + } + + LIST_INITHEAD(&virtual_data->output_list); + LIST_INITHEAD(&virtual_data->buffer_list); + + memset(&virtual_func_display, 0, sizeof(virtual_func_display)); + virtual_func_display.display_get_capability = virtual_display_get_capability; + virtual_func_display.display_get_outputs = virtual_display_get_outputs; + virtual_func_display.display_get_fd = virtual_display_get_fd; + virtual_func_display.display_handle_events = virtual_display_handle_events; + + memset(&virtual_func_output, 0, sizeof(virtual_func_output)); + virtual_func_output.output_get_capability = virtual_output_get_capability; + virtual_func_output.output_get_layers = virtual_output_get_layers; + virtual_func_output.output_wait_vblank = virtual_output_wait_vblank; + virtual_func_output.output_set_vblank_handler = virtual_output_set_vblank_handler; + virtual_func_output.output_commit = virtual_output_commit; + virtual_func_output.output_set_commit_handler = virtual_output_set_commit_handler; + virtual_func_output.output_set_mode = virtual_output_set_mode; + virtual_func_output.output_get_mode = virtual_output_get_mode; + + memset(&virtual_func_layer, 0, sizeof(virtual_func_layer)); + virtual_func_layer.layer_get_capability = virtual_layer_get_capability; + virtual_func_layer.layer_set_info = virtual_layer_set_info; + virtual_func_layer.layer_get_info = virtual_layer_get_info; + virtual_func_layer.layer_set_buffer = virtual_layer_set_buffer; + virtual_func_layer.layer_unset_buffer = virtual_layer_unset_buffer; + + ret = tdm_backend_register_func_display(dpy, &virtual_func_display); + if (ret != TDM_ERROR_NONE) + goto failed; + + ret = tdm_backend_register_func_output(dpy, &virtual_func_output); + if (ret != TDM_ERROR_NONE) + goto failed; + + ret = tdm_backend_register_func_layer(dpy, &virtual_func_layer); + if (ret != TDM_ERROR_NONE) + goto failed; + + virtual_data->dpy = dpy; + + if (pipe(virtual_data->pipe) < 0) { + TDM_ERR("failed get pipe: %m"); + ret = TDM_ERROR_OPERATION_FAILED; + goto failed; + } + + ret = tdm_virtual_display_create_output_list(virtual_data); + if (ret != TDM_ERROR_NONE) + goto failed; + + ret = tdm_virtual_display_create_layer_list(virtual_data); + if (ret != TDM_ERROR_NONE) + goto failed; + + if (error) + *error = TDM_ERROR_NONE; + + TDM_INFO("init success!"); + + return (tdm_backend_data *)virtual_data; +failed: + if (error) + *error = ret; + + tdm_virtual_deinit(virtual_data); + + TDM_ERR("init failed!"); + return NULL; +} + +tdm_backend_module tdm_backend_module_data = { + "Virtual", + "Samsung", + TDM_BACKEND_SET_ABI_VERSION(1, 1), + tdm_virtual_init, + tdm_virtual_deinit +}; diff --git a/backends/virtual/tdm_virtual.h b/backends/virtual/tdm_virtual.h new file mode 100644 index 0000000..2a25ab6 --- /dev/null +++ b/backends/virtual/tdm_virtual.h @@ -0,0 +1,76 @@ +#ifndef _TDM_VIRTUAL_H_ +#define _TDM_VIRTUAL_H_ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/* virtual backend functions (display) */ +tdm_error virtual_display_get_capability(tdm_backend_data *bdata, tdm_caps_display *caps); +tdm_output** virtual_display_get_outputs(tdm_backend_data *bdata, int *count, tdm_error *error); +tdm_error virtual_display_get_fd(tdm_backend_data *bdata, int *fd); +tdm_error virtual_display_handle_events(tdm_backend_data *bdata); + +tdm_error virtual_output_get_capability(tdm_output *output, tdm_caps_output *caps); +tdm_layer** virtual_output_get_layers(tdm_output *output, int *count, tdm_error *error); +tdm_error virtual_output_wait_vblank(tdm_output *output, int interval, int sync, void *user_data); +tdm_error virtual_output_set_vblank_handler(tdm_output *output, tdm_output_vblank_handler func); +tdm_error virtual_output_commit(tdm_output *output, int sync, void *user_data); +tdm_error virtual_output_set_commit_handler(tdm_output *output, tdm_output_commit_handler func); +tdm_error virtual_output_set_mode(tdm_output *output, const tdm_output_mode *mode); +tdm_error virtual_output_get_mode(tdm_output *output, const tdm_output_mode **mode); + +tdm_error virtual_layer_get_capability(tdm_layer *layer, tdm_caps_layer *caps); +tdm_error virtual_layer_set_info(tdm_layer *layer, tdm_info_layer *info); +tdm_error virtual_layer_get_info(tdm_layer *layer, tdm_info_layer *info); +tdm_error virtual_layer_set_buffer(tdm_layer *layer, tbm_surface_h buffer); +tdm_error virtual_layer_unset_buffer(tdm_layer *layer); + +#define RETURN_VAL_IF_FAIL(cond, val) {\ + if (!(cond)) {\ + TDM_ERR("'%s' failed", #cond);\ + return val;\ + }\ +} + +#define GOTO_IF_FAIL(cond, val) {\ + if (!(cond)) {\ + TDM_ERR("'%s' failed", #cond);\ + goto val;\ + }\ +} + +typedef struct _tdm_virtual_data +{ + tdm_display *dpy; + + int pipe[2]; + + struct list_head output_list; + struct list_head buffer_list; +} tdm_virtual_data; + +tdm_error tdm_virtual_display_create_output_list(tdm_virtual_data *virtual_data); +void tdm_virtual_display_destroy_output_list(tdm_virtual_data *virtual_data); +tdm_error tdm_virtual_display_create_layer_list(tdm_virtual_data *virtual_data); + +#endif /* _TDM_VIRTUAL_H_ */ diff --git a/backends/virtual/tdm_virtual_display.c b/backends/virtual/tdm_virtual_display.c new file mode 100644 index 0000000..185f10d --- /dev/null +++ b/backends/virtual/tdm_virtual_display.c @@ -0,0 +1,636 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tdm_virtual.h" + +typedef struct _tdm_virtual_output_data tdm_virtual_output_data; +typedef struct _tdm_virtual_layer_data tdm_virtual_layer_data; +typedef struct _tdm_virtual_event_data tdm_virtual_event_data; + +typedef enum { + TDM_VIRTUAL_EVENT_TYPE_WAIT, + TDM_VIRTUAL_EVENT_TYPE_COMMIT, +} tdm_virtual_event_type; + +struct _tdm_virtual_event_data { + struct list_head link; + + tdm_virtual_event_type type; + tdm_virtual_output_data *output_data; + void *user_data; +}; + +struct _tdm_virtual_output_data { + struct list_head link; + + /* data which are fixed at initializing */ + tdm_virtual_data *virtual_data; + + uint32_t pipe; + tdm_output_mode *output_mode; + tdm_output_type connector_type; + struct list_head layer_list; + tdm_virtual_layer_data *primary_layer; + + /* not fixed data below */ + tdm_output_vblank_handler vblank_func; + tdm_output_commit_handler commit_func; + + tdm_output_conn_status status; + + int mode_changed; + const tdm_output_mode *current_mode; + + tdm_event_loop_source *timer; + unsigned int timer_waiting; + struct list_head timer_event_list; +}; + +struct _tdm_virtual_layer_data { + struct list_head link; + + /* data which are fixed at initializing */ + tdm_virtual_data *virtual_data; + tdm_virtual_output_data *output_data; + tdm_layer_capability capabilities; + int zpos; + + /* not fixed data below */ + tdm_info_layer info; + int info_changed; + + tbm_surface_h display_buffer; + int display_buffer_changed; +}; + +static void +_tdm_virtual_display_cb_event(tdm_virtual_output_data *output_data, tdm_virtual_event_data *event_data, + unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec) +{ + switch (event_data->type) { + case TDM_VIRTUAL_EVENT_TYPE_WAIT: + if (output_data->vblank_func) + output_data->vblank_func(output_data, sequence, tv_sec, tv_usec, event_data->user_data); + break; + case TDM_VIRTUAL_EVENT_TYPE_COMMIT: + if (output_data->commit_func) + output_data->commit_func(output_data, sequence, tv_sec, tv_usec, event_data->user_data); + break; + default: + break; + } +} + +static tdm_error +_tdm_virtual_display_cb_timeout(void *user_data) +{ + tdm_virtual_output_data *output_data = user_data; + tdm_virtual_event_data *e = NULL, *ee = NULL; + unsigned int tv_sec, tv_usec; + static unsigned int sequence = 0; + struct timespec tp; + + sequence++; + + if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) { + tv_sec = tp.tv_sec; + tv_usec = tp.tv_nsec / 1000; + } else { + tv_sec = tv_usec = 0; + } + + LIST_FOR_EACH_ENTRY_SAFE(e, ee, &output_data->timer_event_list, link) { + LIST_DEL(&e->link); + _tdm_virtual_display_cb_event(output_data, e, sequence, tv_sec, tv_usec); + free(e); + } + + return TDM_ERROR_NONE; +} + +static tdm_error +_tdm_virtual_display_wait_vblank(tdm_virtual_output_data *output_data, int interval, tdm_virtual_event_data *event_data) +{ + tdm_error ret; + unsigned int ms; + + RETURN_VAL_IF_FAIL(output_data->timer != NULL, TDM_ERROR_OPERATION_FAILED); + RETURN_VAL_IF_FAIL(output_data->output_mode->vrefresh > 0, TDM_ERROR_OPERATION_FAILED); + + if (output_data->timer_waiting) { + LIST_ADDTAIL(&event_data->link, &output_data->timer_event_list); + return TDM_ERROR_NONE; + } + + ms = ((double)1000.0 / output_data->output_mode->vrefresh) * interval; + + ret = tdm_event_loop_source_timer_update(output_data->timer, ms); + if (ret != TDM_ERROR_NONE) + return ret; + + LIST_ADDTAIL(&event_data->link, &output_data->timer_event_list); + + return TDM_ERROR_NONE; +} + +static void +_tdm_virtual_display_destroy_layer_list(tdm_virtual_data *virtual_data) +{ + tdm_virtual_output_data *o = NULL; + + LIST_FOR_EACH_ENTRY(o, &virtual_data->output_list, link) { + tdm_virtual_layer_data *l = NULL, *ll = NULL; + LIST_FOR_EACH_ENTRY_SAFE(l, ll, &o->layer_list, link) { + LIST_DEL(&l->link); + free(l); + } + } +} + +tdm_error +tdm_virtual_display_create_layer_list(tdm_virtual_data *virtual_data) +{ + tdm_virtual_output_data *output_data = NULL; + tdm_error ret = TDM_ERROR_NONE; + + if (LIST_IS_EMPTY(&virtual_data->output_list)) { + TDM_ERR("no output"); + return TDM_ERROR_OPERATION_FAILED; + } + + /* The TDM virtual backend only support one output. */ + LIST_FOR_EACH_ENTRY(output_data, &virtual_data->output_list, link) { + tdm_virtual_layer_data *layer_data = calloc(1, sizeof(tdm_virtual_layer_data)); + if (!layer_data) { + TDM_ERR("alloc failed"); + ret = TDM_ERROR_OUT_OF_MEMORY; + goto failed; + } + + layer_data->virtual_data = virtual_data; + layer_data->output_data = output_data; + layer_data->zpos = 0; + + layer_data->capabilities = TDM_LAYER_CAPABILITY_PRIMARY | TDM_LAYER_CAPABILITY_GRAPHIC; + output_data->primary_layer = layer_data; + + LIST_ADDTAIL(&layer_data->link, &output_data->layer_list); + } + + return TDM_ERROR_NONE; +failed: + _tdm_virtual_display_destroy_layer_list(virtual_data); + return ret; +} + +void +tdm_virtual_display_destroy_output_list(tdm_virtual_data *virtual_data) +{ + tdm_virtual_output_data *o = NULL, *oo = NULL; + + if (LIST_IS_EMPTY(&virtual_data->output_list)) + return; + + _tdm_virtual_display_destroy_layer_list(virtual_data); + + LIST_FOR_EACH_ENTRY_SAFE(o, oo, &virtual_data->output_list, link) { + LIST_DEL(&o->link); + + if (!LIST_IS_EMPTY(&o->timer_event_list)) { + tdm_virtual_event_data *e = NULL, *ee = NULL; + LIST_FOR_EACH_ENTRY_SAFE(e, ee, &o->timer_event_list, link) { + LIST_DEL(&e->link); + free(e); + } + } + + if (o->timer) + tdm_event_loop_source_remove(o->timer); + + free(o->output_mode); + free(o); + } +} + +tdm_error +tdm_virtual_display_create_output_list(tdm_virtual_data *virtual_data) +{ + tdm_virtual_output_data *output_data; + tdm_error ret; + + RETURN_VAL_IF_FAIL(LIST_IS_EMPTY(&virtual_data->output_list), TDM_ERROR_OPERATION_FAILED); + + output_data = calloc(1, sizeof(tdm_virtual_output_data)); + if (!output_data) { + TDM_ERR("alloc failed"); + ret = TDM_ERROR_OUT_OF_MEMORY; + goto failed_create; + } + + LIST_INITHEAD(&output_data->layer_list); + + output_data->virtual_data = virtual_data; + output_data->pipe = 0; + output_data->connector_type = TDM_OUTPUT_TYPE_Unknown; + output_data->status = TDM_OUTPUT_CONN_STATUS_CONNECTED; + + output_data->output_mode = calloc(1, sizeof(tdm_output_mode)); + if (!output_data->output_mode) { + TDM_ERR("alloc failed"); + free(output_data); + ret = TDM_ERROR_OUT_OF_MEMORY; + goto failed_create; + } + + snprintf(output_data->output_mode->name, TDM_NAME_LEN, "640x480"); + output_data->output_mode->vrefresh = 30; + output_data->output_mode->clock = 25200; + output_data->output_mode->hdisplay = 640; + output_data->output_mode->hsync_start = 656; + output_data->output_mode->hsync_end = 752; + output_data->output_mode->htotal = 800; + output_data->output_mode->hskew = 0; + output_data->output_mode->vdisplay = 480; + output_data->output_mode->vsync_start = 490; + output_data->output_mode->vsync_end = 492; + output_data->output_mode->vtotal = 525; + output_data->output_mode->vscan = 0; + output_data->output_mode->flags = 0; + output_data->output_mode->type = 0; + + output_data->timer = tdm_event_loop_add_timer_handler(virtual_data->dpy, + _tdm_virtual_display_cb_timeout, + output_data, + &ret); + if (!output_data->timer) { + free(output_data); + return ret; + } + + LIST_INITHEAD(&output_data->timer_event_list); + + LIST_ADDTAIL(&output_data->link, &virtual_data->output_list); + + return TDM_ERROR_NONE; +failed_create: + tdm_virtual_display_destroy_output_list(virtual_data); + return ret; +} + +tdm_error +virtual_display_get_capability(tdm_backend_data *bdata, tdm_caps_display *caps) +{ + RETURN_VAL_IF_FAIL(caps, TDM_ERROR_INVALID_PARAMETER); + + caps->max_layer_count = -1; /* not defined */ + + return TDM_ERROR_NONE; +} + +tdm_output ** +virtual_display_get_outputs(tdm_backend_data *bdata, int *count, tdm_error *error) +{ + tdm_virtual_data *virtual_data = bdata; + tdm_virtual_output_data *output_data = NULL; + tdm_output **outputs; + tdm_error ret; + int i; + + RETURN_VAL_IF_FAIL(virtual_data, NULL); + RETURN_VAL_IF_FAIL(count, NULL); + + *count = 0; + LIST_FOR_EACH_ENTRY(output_data, &virtual_data->output_list, link) + (*count)++; + + if (*count == 0) { + ret = TDM_ERROR_NONE; + goto failed_get; + } + + /* will be freed in frontend */ + outputs = calloc(*count, sizeof(tdm_virtual_output_data *)); + if (!outputs) { + TDM_ERR("failed: alloc memory"); + *count = 0; + ret = TDM_ERROR_OUT_OF_MEMORY; + goto failed_get; + } + + i = 0; + LIST_FOR_EACH_ENTRY(output_data, &virtual_data->output_list, link) + outputs[i++] = output_data; + + if (error) + *error = TDM_ERROR_NONE; + + return outputs; +failed_get: + if (error) + *error = ret; + return NULL; +} + +tdm_error +virtual_display_get_fd(tdm_backend_data *bdata, int *fd) +{ + tdm_virtual_data *virtual_data = bdata; + + RETURN_VAL_IF_FAIL(virtual_data, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(fd, TDM_ERROR_INVALID_PARAMETER); + + *fd = virtual_data->pipe[0]; + + return TDM_ERROR_NONE; +} + +tdm_error +virtual_display_handle_events(tdm_backend_data *bdata) +{ + return TDM_ERROR_NONE; +} + +tdm_error +virtual_output_get_capability(tdm_output *output, tdm_caps_output *caps) +{ + tdm_virtual_output_data *output_data = output; + tdm_error ret; + + RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(caps, TDM_ERROR_INVALID_PARAMETER); + + memset(caps, 0, sizeof(tdm_caps_output)); + + snprintf(caps->maker, TDM_NAME_LEN, "virtual"); + snprintf(caps->model, TDM_NAME_LEN, "virtual"); + snprintf(caps->name, TDM_NAME_LEN, "virtual"); + + caps->status = output_data->status; + caps->type = output_data->connector_type; + caps->type_id = 0; + + caps->mode_count = 1; + caps->modes = calloc(1, sizeof(tdm_output_mode)); + if (!caps->modes) { + ret = TDM_ERROR_OUT_OF_MEMORY; + TDM_ERR("alloc failed\n"); + goto failed_get; + } + + *caps->modes = *output_data->output_mode; + + caps->mmWidth = 640; + caps->mmHeight = 480; + caps->subpixel = 1; + + caps->min_w = -1; + caps->min_h = -1; + caps->max_w = -1; + caps->max_h = -1; + caps->preferred_align = -1; + + caps->prop_count = 0; + + return TDM_ERROR_NONE; +failed_get: + memset(caps, 0, sizeof(tdm_caps_output)); + return ret; +} + +tdm_layer ** +virtual_output_get_layers(tdm_output *output, int *count, tdm_error *error) +{ + tdm_virtual_output_data *output_data = output; + tdm_virtual_layer_data *layer_data = NULL; + tdm_layer **layers; + tdm_error ret; + int i; + + RETURN_VAL_IF_FAIL(output_data, NULL); + RETURN_VAL_IF_FAIL(count, NULL); + + *count = 0; + LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link) + (*count)++; + + if (*count == 0) { + ret = TDM_ERROR_NONE; + goto failed_get; + } + + /* will be freed in frontend */ + layers = calloc(*count, sizeof(tdm_virtual_layer_data *)); + if (!layers) { + TDM_ERR("failed: alloc memory"); + *count = 0; + ret = TDM_ERROR_OUT_OF_MEMORY; + goto failed_get; + } + + i = 0; + LIST_FOR_EACH_ENTRY(layer_data, &output_data->layer_list, link) + layers[i++] = layer_data; + + if (error) + *error = TDM_ERROR_NONE; + + return layers; +failed_get: + if (error) + *error = ret; + return NULL; +} + +tdm_error +virtual_output_wait_vblank(tdm_output *output, int interval, int sync, void *user_data) +{ + tdm_virtual_output_data *output_data = output; + tdm_virtual_event_data *event_data; + tdm_error ret; + + RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER); + + event_data = calloc(1, sizeof(tdm_virtual_event_data)); + if (!event_data) { + TDM_ERR("alloc failed"); + return TDM_ERROR_OUT_OF_MEMORY; + } + + event_data->type = TDM_VIRTUAL_EVENT_TYPE_WAIT; + event_data->output_data = output_data; + event_data->user_data = user_data; + + ret = _tdm_virtual_display_wait_vblank(output_data, interval, event_data); + if (ret != TDM_ERROR_NONE) { + free(event_data); + return ret; + } + + return TDM_ERROR_NONE; +} + +tdm_error +virtual_output_set_vblank_handler(tdm_output *output, tdm_output_vblank_handler func) +{ + tdm_virtual_output_data *output_data = output; + + RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER); + + output_data->vblank_func = func; + + return TDM_ERROR_NONE; +} + +tdm_error +virtual_output_commit(tdm_output *output, int sync, void *user_data) +{ + tdm_virtual_output_data *output_data = output; + tdm_virtual_event_data *event_data; + tdm_error ret; + + RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER); + + event_data = calloc(1, sizeof(tdm_virtual_event_data)); + if (!event_data) { + TDM_ERR("alloc failed"); + return TDM_ERROR_OUT_OF_MEMORY; + } + + event_data->type = TDM_VIRTUAL_EVENT_TYPE_COMMIT; + event_data->output_data = output_data; + event_data->user_data = user_data; + + ret = _tdm_virtual_display_wait_vblank(output_data, 1, event_data); + if (ret != TDM_ERROR_NONE) { + free(event_data); + return ret; + } + + return TDM_ERROR_NONE; +} + +tdm_error +virtual_output_set_commit_handler(tdm_output *output, tdm_output_commit_handler func) +{ + tdm_virtual_output_data *output_data = output; + + RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(func, TDM_ERROR_INVALID_PARAMETER); + + output_data->commit_func = func; + + return TDM_ERROR_NONE; +} + +tdm_error +virtual_output_set_mode(tdm_output *output, const tdm_output_mode *mode) +{ + tdm_virtual_output_data *output_data = output; + + RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(mode, TDM_ERROR_INVALID_PARAMETER); + + output_data->current_mode = mode; + output_data->mode_changed = 1; + + return TDM_ERROR_NONE; +} + +tdm_error +virtual_output_get_mode(tdm_output *output, const tdm_output_mode **mode) +{ + tdm_virtual_output_data *output_data = output; + + RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(mode, TDM_ERROR_INVALID_PARAMETER); + + *mode = output_data->current_mode; + + return TDM_ERROR_NONE; +} + +tdm_error +virtual_layer_get_capability(tdm_layer *layer, tdm_caps_layer *caps) +{ + tdm_virtual_layer_data *layer_data = layer; + + RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(caps, TDM_ERROR_INVALID_PARAMETER); + + memset(caps, 0, sizeof(tdm_caps_layer)); + + caps->capabilities = layer_data->capabilities; + caps->zpos = layer_data->zpos; + + caps->format_count = 2; + caps->formats = calloc(caps->format_count, sizeof(tbm_format)); + if (!caps->formats) { + TDM_ERR("alloc failed\n"); + free(caps->formats); + memset(caps, 0, sizeof(tdm_caps_layer)); + return TDM_ERROR_OUT_OF_MEMORY; + } + + caps->formats[0] = TBM_FORMAT_ARGB8888; + caps->formats[1] = TBM_FORMAT_XRGB8888; + + caps->prop_count = 0; + + return TDM_ERROR_NONE; +} + +tdm_error +virtual_layer_set_info(tdm_layer *layer, tdm_info_layer *info) +{ + tdm_virtual_layer_data *layer_data = layer; + + RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(info, TDM_ERROR_INVALID_PARAMETER); + + layer_data->info = *info; + layer_data->info_changed = 1; + + return TDM_ERROR_NONE; +} + +tdm_error +virtual_layer_get_info(tdm_layer *layer, tdm_info_layer *info) +{ + tdm_virtual_layer_data *layer_data = layer; + + RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(info, TDM_ERROR_INVALID_PARAMETER); + + *info = layer_data->info; + + return TDM_ERROR_NONE; +} + +tdm_error +virtual_layer_set_buffer(tdm_layer *layer, tbm_surface_h buffer) +{ + tdm_virtual_layer_data *layer_data = layer; + + RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(buffer, TDM_ERROR_INVALID_PARAMETER); + + layer_data->display_buffer = buffer; + layer_data->display_buffer_changed = 1; + + return TDM_ERROR_NONE; +} + +tdm_error +virtual_layer_unset_buffer(tdm_layer *layer) +{ + tdm_virtual_layer_data *layer_data = layer; + + RETURN_VAL_IF_FAIL(layer_data, TDM_ERROR_INVALID_PARAMETER); + + layer_data->display_buffer = NULL; + layer_data->display_buffer_changed = 1; + + return TDM_ERROR_NONE; +} diff --git a/configure.ac b/configure.ac index 3d13ec7..81d3828 100644 --- a/configure.ac +++ b/configure.ac @@ -100,6 +100,7 @@ AC_OUTPUT([ src/Makefile backends/Makefile backends/dummy/Makefile + backends/virtual/Makefile client/libtdm-client.pc client/Makefile tools/Makefile diff --git a/packaging/libtdm.spec b/packaging/libtdm.spec index 5bcae43..c915e01 100644 --- a/packaging/libtdm.spec +++ b/packaging/libtdm.spec @@ -114,6 +114,7 @@ rm -f %{_unitdir_user}/basic.target.wants/tdm-socket-user.path %license COPYING %{_libdir}/libtdm.so.* %{_libdir}/tdm/libtdm-dummy.so +%{_libdir}/tdm/libtdm-virtual.so %attr(750,root,root) %{_bindir}/tdm-monitor %{_unitdir_user}/tdm-socket-user.path %{_unitdir_user}/tdm-socket-user.service diff --git a/src/tdm.c b/src/tdm.c index 3bbd6c3..6999b9e 100644 --- a/src/tdm.c +++ b/src/tdm.c @@ -797,6 +797,11 @@ _tdm_display_setup(tdm_private_display *private_display) } } + TDM_INFO("loading a %s backend", TDM_VIRTUAL_MODULE); + ret = _tdm_display_load_module_with_file(private_display, TDM_VIRTUAL_MODULE); + TDM_GOTO_IF_FAIL(ret == TDM_ERROR_NONE, failed_update); + TDM_GOTO_IF_FAIL(private_display->virtual_module != NULL, failed_update); + return TDM_ERROR_NONE; failed_update: @@ -1010,6 +1015,9 @@ _tdm_display_load_module_with_file(tdm_private_display *private_display, if (!strncmp(file, TDM_DUMMY_MODULE, TDM_NAME_LEN)) private_display->dummy_module = private_module; + if (!strncmp(file, TDM_VIRTUAL_MODULE, TDM_NAME_LEN)) + private_display->virtual_module = private_module; + private_module->bdata = bdata; if (ret != TDM_ERROR_NONE) { diff --git a/src/tdm_macro.h b/src/tdm_macro.h index 24899c3..d831146 100644 --- a/src/tdm_macro.h +++ b/src/tdm_macro.h @@ -86,6 +86,7 @@ extern "C" { /* common backend names *****************************************************/ #define TDM_DEFAULT_MODULE "libtdm-default.so" #define TDM_DUMMY_MODULE "libtdm-dummy.so" +#define TDM_VIRTUAL_MODULE "libtdm-virtual.so" /* dump directory ***********************************************************/ #define TDM_DUMP_DIR "/tmp" diff --git a/src/tdm_private_types.h b/src/tdm_private_types.h index 365ea7d..d74f4f2 100644 --- a/src/tdm_private_types.h +++ b/src/tdm_private_types.h @@ -166,6 +166,7 @@ struct _tdm_private_display { struct list_head module_list; tdm_private_module *dummy_module; + tdm_private_module *virtual_module; tdm_private_module *current_module; //setted only when loading tdm_private_module *pp_module; //pp-support backend tdm_private_module *capture_module; //TODO: remove later -- 2.7.4 From 7e1f4f71006d85a16303b0b70e5b9d0e45b7e9ec Mon Sep 17 00:00:00 2001 From: Junkyeong Kim Date: Wed, 18 Jul 2018 19:31:12 +0900 Subject: [PATCH 10/16] virtual:add virtual output create/destroy Change-Id: Ib8ef9133c166e8fc67a9b338667941fe35849764 Signed-off-by: Junkyeong Kim --- backends/virtual/tdm_virtual.c | 6 +- backends/virtual/tdm_virtual.h | 62 ++++++------- backends/virtual/tdm_virtual_display.c | 157 ++++++++++++++++++++++++++++++--- haltests/src/tc_tdm_client.cpp | 30 +++++++ include/tdm_backend.h | 6 +- src/tdm_display.c | 62 +++++++++++++ src/tdm_private.h | 5 ++ src/tdm_server.c | 70 ++++++++++++++- 8 files changed, 350 insertions(+), 48 deletions(-) diff --git a/backends/virtual/tdm_virtual.c b/backends/virtual/tdm_virtual.c index f890829..9c9e4dd 100644 --- a/backends/virtual/tdm_virtual.c +++ b/backends/virtual/tdm_virtual.c @@ -63,6 +63,8 @@ tdm_virtual_init(tdm_display *dpy, tdm_error *error) virtual_func_display.display_get_outputs = virtual_display_get_outputs; virtual_func_display.display_get_fd = virtual_display_get_fd; virtual_func_display.display_handle_events = virtual_display_handle_events; + virtual_func_display.display_output_create = virtual_display_output_create; + virtual_func_display.display_output_destroy = virtual_display_output_destroy; memset(&virtual_func_output, 0, sizeof(virtual_func_output)); virtual_func_output.output_get_capability = virtual_output_get_capability; @@ -100,7 +102,7 @@ tdm_virtual_init(tdm_display *dpy, tdm_error *error) ret = TDM_ERROR_OPERATION_FAILED; goto failed; } - +#if 0 ret = tdm_virtual_display_create_output_list(virtual_data); if (ret != TDM_ERROR_NONE) goto failed; @@ -108,7 +110,7 @@ tdm_virtual_init(tdm_display *dpy, tdm_error *error) ret = tdm_virtual_display_create_layer_list(virtual_data); if (ret != TDM_ERROR_NONE) goto failed; - +#endif if (error) *error = TDM_ERROR_NONE; diff --git a/backends/virtual/tdm_virtual.h b/backends/virtual/tdm_virtual.h index 2a25ab6..f1cdf91 100644 --- a/backends/virtual/tdm_virtual.h +++ b/backends/virtual/tdm_virtual.h @@ -25,52 +25,52 @@ #include /* virtual backend functions (display) */ -tdm_error virtual_display_get_capability(tdm_backend_data *bdata, tdm_caps_display *caps); -tdm_output** virtual_display_get_outputs(tdm_backend_data *bdata, int *count, tdm_error *error); -tdm_error virtual_display_get_fd(tdm_backend_data *bdata, int *fd); -tdm_error virtual_display_handle_events(tdm_backend_data *bdata); +tdm_error virtual_display_get_capability(tdm_backend_data *bdata, tdm_caps_display *caps); +tdm_output **virtual_display_get_outputs(tdm_backend_data *bdata, int *count, tdm_error *error); +tdm_error virtual_display_get_fd(tdm_backend_data *bdata, int *fd); +tdm_error virtual_display_handle_events(tdm_backend_data *bdata); +tdm_output *virtual_display_output_create(tdm_backend_data *bdata, const char* name, tdm_error *error); +tdm_error virtual_display_output_destroy(tdm_backend_data *bdata, tdm_output *output); -tdm_error virtual_output_get_capability(tdm_output *output, tdm_caps_output *caps); -tdm_layer** virtual_output_get_layers(tdm_output *output, int *count, tdm_error *error); -tdm_error virtual_output_wait_vblank(tdm_output *output, int interval, int sync, void *user_data); -tdm_error virtual_output_set_vblank_handler(tdm_output *output, tdm_output_vblank_handler func); -tdm_error virtual_output_commit(tdm_output *output, int sync, void *user_data); -tdm_error virtual_output_set_commit_handler(tdm_output *output, tdm_output_commit_handler func); -tdm_error virtual_output_set_mode(tdm_output *output, const tdm_output_mode *mode); -tdm_error virtual_output_get_mode(tdm_output *output, const tdm_output_mode **mode); +tdm_error virtual_output_get_capability(tdm_output *output, tdm_caps_output *caps); +tdm_layer **virtual_output_get_layers(tdm_output *output, int *count, tdm_error *error); +tdm_error virtual_output_wait_vblank(tdm_output *output, int interval, int sync, void *user_data); +tdm_error virtual_output_set_vblank_handler(tdm_output *output, tdm_output_vblank_handler func); +tdm_error virtual_output_commit(tdm_output *output, int sync, void *user_data); +tdm_error virtual_output_set_commit_handler(tdm_output *output, tdm_output_commit_handler func); +tdm_error virtual_output_set_mode(tdm_output *output, const tdm_output_mode *mode); +tdm_error virtual_output_get_mode(tdm_output *output, const tdm_output_mode **mode); -tdm_error virtual_layer_get_capability(tdm_layer *layer, tdm_caps_layer *caps); -tdm_error virtual_layer_set_info(tdm_layer *layer, tdm_info_layer *info); -tdm_error virtual_layer_get_info(tdm_layer *layer, tdm_info_layer *info); -tdm_error virtual_layer_set_buffer(tdm_layer *layer, tbm_surface_h buffer); -tdm_error virtual_layer_unset_buffer(tdm_layer *layer); +tdm_error virtual_layer_get_capability(tdm_layer *layer, tdm_caps_layer *caps); +tdm_error virtual_layer_set_info(tdm_layer *layer, tdm_info_layer *info); +tdm_error virtual_layer_get_info(tdm_layer *layer, tdm_info_layer *info); +tdm_error virtual_layer_set_buffer(tdm_layer *layer, tbm_surface_h buffer); +tdm_error virtual_layer_unset_buffer(tdm_layer *layer); #define RETURN_VAL_IF_FAIL(cond, val) {\ - if (!(cond)) {\ - TDM_ERR("'%s' failed", #cond);\ - return val;\ - }\ + if (!(cond)) {\ + TDM_ERR("'%s' failed", #cond);\ + return val;\ + }\ } #define GOTO_IF_FAIL(cond, val) {\ - if (!(cond)) {\ - TDM_ERR("'%s' failed", #cond);\ - goto val;\ - }\ + if (!(cond)) {\ + TDM_ERR("'%s' failed", #cond);\ + goto val;\ + }\ } typedef struct _tdm_virtual_data { - tdm_display *dpy; + tdm_display *dpy; - int pipe[2]; + int pipe[2]; - struct list_head output_list; - struct list_head buffer_list; + struct list_head output_list; + struct list_head buffer_list; } tdm_virtual_data; -tdm_error tdm_virtual_display_create_output_list(tdm_virtual_data *virtual_data); void tdm_virtual_display_destroy_output_list(tdm_virtual_data *virtual_data); -tdm_error tdm_virtual_display_create_layer_list(tdm_virtual_data *virtual_data); #endif /* _TDM_VIRTUAL_H_ */ diff --git a/backends/virtual/tdm_virtual_display.c b/backends/virtual/tdm_virtual_display.c index 185f10d..9bf7363 100644 --- a/backends/virtual/tdm_virtual_display.c +++ b/backends/virtual/tdm_virtual_display.c @@ -29,6 +29,7 @@ struct _tdm_virtual_output_data { uint32_t pipe; tdm_output_mode *output_mode; + int mode_count; tdm_output_type connector_type; struct list_head layer_list; tdm_virtual_layer_data *primary_layer; @@ -45,6 +46,11 @@ struct _tdm_virtual_output_data { tdm_event_loop_source *timer; unsigned int timer_waiting; struct list_head timer_event_list; + + unsigned int mmwidth; + unsigned int mmheight; + + char name[TDM_NAME_LEN]; /**< The output name */ }; struct _tdm_virtual_layer_data { @@ -233,7 +239,7 @@ tdm_virtual_display_create_output_list(tdm_virtual_data *virtual_data) output_data->virtual_data = virtual_data; output_data->pipe = 0; output_data->connector_type = TDM_OUTPUT_TYPE_Unknown; - output_data->status = TDM_OUTPUT_CONN_STATUS_CONNECTED; + output_data->status = TDM_OUTPUT_CONN_STATUS_DISCONNECTED; output_data->output_mode = calloc(1, sizeof(tdm_output_mode)); if (!output_data->output_mode) { @@ -351,6 +357,131 @@ virtual_display_handle_events(tdm_backend_data *bdata) return TDM_ERROR_NONE; } +tdm_output * +virtual_display_output_create(tdm_backend_data *bdata, const char *name, tdm_error *error) +{ + tdm_virtual_data *virtual_data = bdata; + tdm_virtual_output_data *output_data = NULL; + tdm_virtual_layer_data *layer_data = NULL; + tdm_error ret; + + if (!virtual_data || !name) { + TDM_ERR("invalid parameter"); + *error = TDM_ERROR_INVALID_PARAMETER; + return NULL; + } + + output_data = calloc(1, sizeof(tdm_virtual_output_data)); + if (!output_data) { + TDM_ERR("alloc failed"); + *error = TDM_ERROR_OUT_OF_MEMORY; + return NULL; + } + + LIST_INITHEAD(&output_data->layer_list); + + output_data->virtual_data = virtual_data; + output_data->pipe = 0; + output_data->connector_type = TDM_OUTPUT_TYPE_Unknown; + output_data->status = TDM_OUTPUT_CONN_STATUS_DISCONNECTED; + + if (name) + snprintf(output_data->name, TDM_NAME_LEN, "%s", name); + else + snprintf(output_data->name, TDM_NAME_LEN, "unknown"); +#if 0 + output_data->output_mode = calloc(1, sizeof(tdm_output_mode)); + if (!output_data->output_mode) { + TDM_ERR("alloc failed"); + ret = TDM_ERROR_OUT_OF_MEMORY; + goto create_fail; + } + + snprintf(output_data->output_mode->name, TDM_NAME_LEN, "640x480"); + output_data->output_mode->vrefresh = 30; + output_data->output_mode->clock = 25200; + output_data->output_mode->hdisplay = 640; + output_data->output_mode->hsync_start = 656; + output_data->output_mode->hsync_end = 752; + output_data->output_mode->htotal = 800; + output_data->output_mode->hskew = 0; + output_data->output_mode->vdisplay = 480; + output_data->output_mode->vsync_start = 490; + output_data->output_mode->vsync_end = 492; + output_data->output_mode->vtotal = 525; + output_data->output_mode->vscan = 0; + output_data->output_mode->flags = 0; + output_data->output_mode->type = 0; + + output_data->mode_count = 1; +#endif + output_data->timer = tdm_event_loop_add_timer_handler(virtual_data->dpy, + _tdm_virtual_display_cb_timeout, + output_data, + &ret); + if (!output_data->timer) goto create_fail; + + LIST_INITHEAD(&output_data->timer_event_list); + + /* The TDM virtual backend output support only one layer. */ + layer_data = calloc(1, sizeof(tdm_virtual_layer_data)); + if (!layer_data) { + TDM_ERR("alloc failed"); + ret = TDM_ERROR_OUT_OF_MEMORY; + goto create_fail; + } + + layer_data->virtual_data = virtual_data; + layer_data->output_data = output_data; + layer_data->zpos = 0; + + layer_data->capabilities = TDM_LAYER_CAPABILITY_PRIMARY | TDM_LAYER_CAPABILITY_GRAPHIC; + output_data->primary_layer = layer_data; + + LIST_ADDTAIL(&layer_data->link, &output_data->layer_list); + + ret = tdm_backend_register_output(virtual_data->dpy, output_data); + GOTO_IF_FAIL(ret == TDM_ERROR_NONE, create_fail); + + *error = TDM_ERROR_NONE; + + return output_data; + +create_fail: + if (layer_data) free(layer_data); + if (output_data->output_mode) free(output_data->output_mode); + free(output_data); + + *error = ret; + + return NULL; +} + +tdm_error +virtual_display_output_destroy(tdm_backend_data *bdata, tdm_output *output) +{ + tdm_virtual_data *virtual_data = bdata; + tdm_virtual_output_data *o, *output_data = output; + int find = 0; + + RETURN_VAL_IF_FAIL(virtual_data, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER); + + LIST_FOR_EACH_ENTRY(o, &virtual_data->output_list, link) { + if (o == output_data) { + find = 1; + break; + } + } + + if (find) + tdm_backend_unregister_output(virtual_data->dpy, output); + else + return TDM_ERROR_INVALID_PARAMETER; + + return TDM_ERROR_NONE; +} + tdm_error virtual_output_get_capability(tdm_output *output, tdm_caps_output *caps) { @@ -364,24 +495,26 @@ virtual_output_get_capability(tdm_output *output, tdm_caps_output *caps) snprintf(caps->maker, TDM_NAME_LEN, "virtual"); snprintf(caps->model, TDM_NAME_LEN, "virtual"); - snprintf(caps->name, TDM_NAME_LEN, "virtual"); + snprintf(caps->name, TDM_NAME_LEN, "%s", output_data->name); caps->status = output_data->status; caps->type = output_data->connector_type; caps->type_id = 0; - caps->mode_count = 1; - caps->modes = calloc(1, sizeof(tdm_output_mode)); - if (!caps->modes) { - ret = TDM_ERROR_OUT_OF_MEMORY; - TDM_ERR("alloc failed\n"); - goto failed_get; - } + caps->mode_count = output_data->mode_count; + if (output_data->mode_count != 0) { + caps->modes = calloc(output_data->mode_count, sizeof(tdm_output_mode)); + if (!caps->modes) { + ret = TDM_ERROR_OUT_OF_MEMORY; + TDM_ERR("alloc failed\n"); + goto failed_get; + } - *caps->modes = *output_data->output_mode; + *caps->modes = *output_data->output_mode; + } - caps->mmWidth = 640; - caps->mmHeight = 480; + caps->mmWidth = output_data->mmwidth; + caps->mmHeight =output_data->mmheight; caps->subpixel = 1; caps->min_w = -1; diff --git a/haltests/src/tc_tdm_client.cpp b/haltests/src/tc_tdm_client.cpp index 20aa27f..f7ff9f8 100644 --- a/haltests/src/tc_tdm_client.cpp +++ b/haltests/src/tc_tdm_client.cpp @@ -50,6 +50,15 @@ enum { TDM_UT_PIPE_MSG_TERMINATE_SERVER, }; +#define TDM_UT_WAIT(fmt, ...) \ + do { \ + char ch; \ + do { \ + printf(fmt" [n]):next ", ##__VA_ARGS__); \ + ch = tc_tdm_getchar(); \ + } while(ch != 'n'); \ + } while (0) + static int _tc_tdm_pipe_read_msg(int fd); static bool _tc_tdm_pipe_write_msg(int fd, int reply_fd, int msg); static pid_t _tc_tdm_client_server_fork(int *pipe_to_parent, int *pipe_to_child); @@ -200,6 +209,23 @@ bool TDMClient::PrepareVblank(void) return true; } +char +tc_tdm_getchar(void) +{ + int c = getchar(); + int ch = c; + + if (ch == '\n' || ch == '\r') + ch = 'y'; + else if (ch < 'a') + ch += ('a' - 'A'); + + while (c != '\n' && c != EOF) + c = getchar(); + + return ch; +} + static int _tc_tdm_pipe_read_msg(int fd) { @@ -1478,9 +1504,13 @@ bool TDMVirtualOutput::PrepareVOutput(void) TDM_UT_RETURN_FALSE_IF_FAIL(ret == TDM_ERROR_NONE); TDM_UT_RETURN_FALSE_IF_FAIL(client != NULL); + voutput = tdm_client_create_voutput(client, name, &ret); TDM_UT_RETURN_FALSE_IF_FAIL(ret == TDM_ERROR_NONE); TDM_UT_RETURN_FALSE_IF_FAIL(voutput != NULL); + +// TDM_UT_WAIT("check & press"); + return true; } diff --git a/include/tdm_backend.h b/include/tdm_backend.h index e9fc70d..9a30004 100644 --- a/include/tdm_backend.h +++ b/include/tdm_backend.h @@ -335,8 +335,10 @@ typedef struct _tdm_func_display { */ tdm_pp *(*display_create_pp)(tdm_backend_data *bdata, tdm_error *error); - void (*reserved1)(void); - void (*reserved2)(void); + /* virtual */ + tdm_output *(*display_output_create)(tdm_backend_data *bdata, const char *name, tdm_error *error); + tdm_error (*display_output_destroy)(tdm_backend_data *bdata, tdm_output *output); + void (*reserved3)(void); void (*reserved4)(void); void (*reserved5)(void); diff --git a/src/tdm_display.c b/src/tdm_display.c index 9f6dd72..a355ab7 100644 --- a/src/tdm_display.c +++ b/src/tdm_display.c @@ -815,6 +815,68 @@ tdm_display_find_output(tdm_display *dpy, const char *name, tdm_error *error) return NULL; } +INTERN tdm_output * +tdm_display_create_output(tdm_display *dpy, const char *name, tdm_error *error) +{ + tdm_private_module *private_module = NULL; + tdm_private_module *current_module = NULL; + tdm_func_display *func_display = NULL; + tdm_output *output = NULL; + + DISPLAY_FUNC_ENTRY_ERROR(); + + TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(dpy != NULL, TDM_ERROR_INVALID_PARAMETER, NULL); + private_display = (tdm_private_display*)dpy; + + private_module = private_display->virtual_module; + TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(private_module != NULL, TDM_ERROR_BAD_MODULE, NULL); + + _pthread_mutex_lock(&private_display->lock); + + if (error) + *error = TDM_ERROR_NONE; + + func_display = &private_module->func_display; + current_module = private_display->current_module; + private_display->current_module = private_module; + output = func_display->display_output_create(private_module->bdata, name, &ret); + private_display->current_module = current_module; + + _pthread_mutex_unlock(&private_display->lock); + + TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(output != NULL, ret, NULL); + + return output; +} + +INTERN tdm_error +tdm_display_destroy_output(tdm_display *dpy, tdm_output *output) +{ + tdm_private_module *private_module = NULL; + tdm_private_module *current_module = NULL; + tdm_func_display *func_display = NULL; + + DISPLAY_FUNC_ENTRY(); + + TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER); + private_display = (tdm_private_display*)dpy; + + private_module = private_display->virtual_module; + TDM_RETURN_VAL_IF_FAIL(private_module != NULL, TDM_ERROR_BAD_MODULE); + + _pthread_mutex_lock(&private_display->lock); + + func_display = &private_module->func_display; + current_module = private_display->current_module; + private_display->current_module = private_module; + ret = func_display->display_output_destroy(private_module->bdata, output); + private_display->current_module = current_module; + + _pthread_mutex_unlock(&private_display->lock); + + return ret; +} + EXTERN tdm_error tdm_display_get_fd(tdm_display *dpy, int *fd) { diff --git a/src/tdm_private.h b/src/tdm_private.h index 6478221..d747993 100644 --- a/src/tdm_private.h +++ b/src/tdm_private.h @@ -255,6 +255,11 @@ tdm_config_deinit(void); void tdm_monitor_server_command(tdm_display *dpy, const char *options, char *reply, int *len); +tdm_output * +tdm_display_create_output(tdm_display *dpy, const char *name, tdm_error *error); +tdm_error +tdm_display_destroy_output(tdm_display *dpy, tdm_output *output); + #ifdef __cplusplus } #endif diff --git a/src/tdm_server.c b/src/tdm_server.c index d77151c..d98339c 100644 --- a/src/tdm_server.c +++ b/src/tdm_server.c @@ -53,6 +53,7 @@ struct _tdm_private_server { tdm_private_loop *private_loop; struct list_head output_list; + struct list_head voutput_list; struct list_head wait_list; }; @@ -65,6 +66,14 @@ typedef struct _tdm_server_output_info { unsigned int watch_output_changes; } tdm_server_output_info; +typedef struct _tdm_server_voutput_info { + struct list_head link; + tdm_private_server *private_server; + struct wl_resource *resource; + tdm_output *output; + struct list_head output_list; +} tdm_server_voutput_info; + typedef struct _tdm_server_vblank_info { struct list_head link; tdm_server_output_info *output_info; @@ -593,7 +602,19 @@ destroy_output_callback(struct wl_resource *resource) free(output_info); } +#if 0 +static void +destroy_voutput_callback(struct wl_resource *resource) +{ + tdm_server_voutput_info *voutput_info = wl_resource_get_user_data(resource); + + TDM_RETURN_IF_FAIL(voutput_info != NULL); + + LIST_DEL(&voutput_info->link); + free(voutput_info); +} +#endif static void _tdm_server_cb_create_output(struct wl_client *client, struct wl_resource *resource, const char *name, uint32_t id) @@ -686,6 +707,26 @@ static void _tdm_server_cb_create_virtual_output(struct wl_client *client, struct wl_resource *resource, const char *name, uint32_t id) { struct wl_resource *voutput_resource = NULL; + tdm_private_server *private_server = wl_resource_get_user_data(resource); + tdm_server_voutput_info *voutput_info; + tdm_output *output; + tdm_error ret; + + output = tdm_display_find_output(private_server->private_loop->dpy, name, NULL); + if (output) { + TDM_ERR("There is '%s' output, cannot create.", name); + wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT, + "There is '%s' output", name); + return; + } + + output = tdm_display_create_output(private_server->private_loop->dpy, name, &ret); + if (!output) { + TDM_ERR("output creation fail(%s)(%d).", name, ret); + wl_resource_post_error(resource, WL_DISPLAY_ERROR_NO_MEMORY, + "%s output creation fail", name); + return; + } voutput_resource = wl_resource_create(client, &wl_tdm_voutput_interface, @@ -700,6 +741,27 @@ _tdm_server_cb_create_virtual_output(struct wl_client *client, struct wl_resourc /* LCOV_EXCL_STOP */ } + voutput_info = calloc(1, sizeof * voutput_info); + if (!voutput_info) { + /* LCOV_EXCL_START */ + + wl_resource_post_no_memory(resource); + wl_resource_destroy(voutput_resource); + TDM_ERR("alloc failed"); + return; + + /* LCOV_EXCL_STOP */ + } + + LIST_ADDTAIL(&voutput_info->link, &private_server->voutput_list); + voutput_info->private_server = private_server; + voutput_info->resource = voutput_resource; + voutput_info->output = output; + LIST_INITHEAD(&voutput_info->output_list); +#if 0 + wl_resource_set_implementation(voutput_resource, &tdm_voutput_implementation, + voutput_info, destroy_voutput_callback); +#endif wl_tdm_voutput_send_ack_message(voutput_resource, WL_TDM_VOUTPUT_MESSAGE_ADDED); } @@ -833,6 +895,7 @@ tdm_server_init(tdm_private_loop *private_loop) } LIST_INITHEAD(&private_server->output_list); + LIST_INITHEAD(&private_server->voutput_list); LIST_INITHEAD(&private_server->wait_list); if (!wl_global_create(private_loop->wl_display, &wl_tdm_interface, 1, @@ -859,6 +922,7 @@ INTERN void tdm_server_deinit(tdm_private_loop *private_loop) { tdm_server_output_info *o = NULL, *oo = NULL; +// tdm_server_voutput_info *vo = NULL, *voo = NULL; tdm_server_wait_info *w = NULL, *ww = NULL; tdm_server_client_info *c = NULL, *cc = NULL; tdm_private_server *private_server; @@ -875,7 +939,11 @@ tdm_server_deinit(tdm_private_loop *private_loop) LIST_FOR_EACH_ENTRY_SAFE(o, oo, &private_server->output_list, link) { wl_resource_destroy(o->resource); } - +#if 0 + LIST_FOR_EACH_ENTRY_SAFE(vo, voo, &private_server->voutput_list, link) { + wl_resource_destroy(vo->resource); + } +#endif LIST_FOR_EACH_ENTRY_SAFE(c, cc, &client_list, link) { wl_resource_destroy(c->resource); } -- 2.7.4 From 691682c94ec0220be0d2f55f8ba1296e6d3cd0bd Mon Sep 17 00:00:00 2001 From: Junkyeong Kim Date: Wed, 18 Jul 2018 19:50:26 +0900 Subject: [PATCH 11/16] virtual:add omitted definitions fix build fail Change-Id: Ia217cf3dd11e7ea2b9320af0f5d14fd7b6b99c6e Signed-off-by: Junkyeong Kim --- include/tdm_backend.h | 7 +++++++ include/tdm_types.h | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/include/tdm_backend.h b/include/tdm_backend.h index 9a30004..2e80d99 100644 --- a/include/tdm_backend.h +++ b/include/tdm_backend.h @@ -1269,6 +1269,13 @@ tdm_error tdm_backend_register_func_capture(tdm_display *dpy, tdm_func_capture *func_capture); +/* virtual */ +tdm_error +tdm_backend_register_output(tdm_display *dpy, tdm_output *output); + +void +tdm_backend_unregister_output(tdm_display *dpy, tdm_output *output); + /** * @brief Increase the ref_count of a TDM buffer * @details diff --git a/include/tdm_types.h b/include/tdm_types.h index 32f544d..7c0f311 100644 --- a/include/tdm_types.h +++ b/include/tdm_types.h @@ -266,6 +266,10 @@ typedef void tdm_pp; */ typedef void tdm_vblank; +/* virtual */ +typedef void (*tdm_output_create_handler)(tdm_display *dpy, tdm_output *output, void *user_data); +typedef void (*tdm_output_destroy_handler)(tdm_output *output, void *user_data); + /** * @brief The output change handler * @details This handler will be called when the status of a output object is -- 2.7.4 From 80d388be9e095544b50a6004f2c8e54039ff7c18 Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Thu, 19 Jul 2018 16:17:14 +0900 Subject: [PATCH 12/16] virtual output: Add implementation for set_available_modes, connect and disconnect. Change-Id: Ic85238c5833286ae22fc698d3d8b3fe2fc903e24 --- client/tdm_client.c | 76 ++++++++++++++++++++++- client/tdm_client_types.h | 14 +++-- haltests/src/tc_tdm_client.cpp | 56 ++++++++++++++--- protocol/tdm.xml | 23 +++++++ src/tdm_server.c | 136 +++++++++++++++++++++++++++++++++++++++-- 5 files changed, 282 insertions(+), 23 deletions(-) diff --git a/client/tdm_client.c b/client/tdm_client.c index 8d17c94..4c05811 100644 --- a/client/tdm_client.c +++ b/client/tdm_client.c @@ -92,6 +92,13 @@ typedef struct _tdm_private_client_output { typedef struct _tdm_private_client_voutput { tdm_private_client_output base; struct wl_tdm_voutput *wl_voutput; + + struct + { + int count; + tdm_client_output_mode *modes; + } available_modes; + uint32_t msg; } tdm_private_client_voutput; @@ -1679,7 +1686,6 @@ tdm_client_create_voutput(tdm_client *client, const char *name, tdm_error *error private_voutput->base.private_client = private_client; - snprintf(private_voutput->base.name, TDM_NAME_LEN, "%s", name); private_voutput->wl_voutput = wl_tdm_create_voutput((struct wl_tdm *)wrapper, private_voutput->base.name); wl_proxy_wrapper_destroy(wrapper); if (!private_voutput->wl_voutput) { @@ -1731,15 +1737,36 @@ tdm_client_voutput_destroy(tdm_client_voutput *voutput) if (!private_voutput) return; + wl_tdm_voutput_destroy(private_voutput->wl_voutput); + free(private_voutput); } tdm_error tdm_client_voutput_set_available_modes(tdm_client_voutput *voutput, const tdm_client_output_mode *modes, int count) { + tdm_private_client_voutput *private_voutput; + TDM_RETURN_VAL_IF_FAIL(voutput != NULL, TDM_ERROR_INVALID_PARAMETER); - TDM_RETURN_VAL_IF_FAIL(modes != NULL, TDM_ERROR_INVALID_PARAMETER); - TDM_RETURN_VAL_IF_FAIL(count > 0, TDM_ERROR_INVALID_PARAMETER); + + if ((count > 0) && (modes == NULL)) + return TDM_ERROR_INVALID_PARAMETER; + + private_voutput = (tdm_private_client_voutput *)voutput; + + if (private_voutput->base.connection == TDM_OUTPUT_CONN_STATUS_CONNECTED) + return TDM_ERROR_BAD_REQUEST; + + if (private_voutput->available_modes.modes) + free(private_voutput->available_modes.modes); + + private_voutput->available_modes.count = count; + + if (count != 0) + { + private_voutput->available_modes.modes = calloc(count, sizeof(tdm_client_output_mode)); + memcpy(private_voutput->available_modes.modes, modes, sizeof(tdm_client_output_mode) * count); + } return TDM_ERROR_NONE; } @@ -1807,14 +1834,57 @@ tdm_client_output_set_mode(tdm_client_output *output, const tdm_client_output_mo tdm_error tdm_client_output_connect(tdm_client_output *output) { + tdm_private_client_output *private_output; + tdm_private_client_voutput *private_voutput; + tdm_client_output_mode *modes; + int i; + TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER); + private_output = (tdm_private_client_output *)output; + private_voutput = (tdm_private_client_voutput *)output; + + TDM_RETURN_VAL_IF_FAIL(private_output->connection != TDM_OUTPUT_CONN_STATUS_CONNECTED, + TDM_ERROR_BAD_REQUEST); + + private_output->connection = TDM_OUTPUT_CONN_STATUS_CONNECTED; + + modes = private_voutput->available_modes.modes; + for (i = 0; i < private_voutput->available_modes.count; i++) + { + wl_tdm_voutput_set_available_modes(private_voutput->wl_voutput, i, + modes[i].clock, modes[i].hdisplay, + modes[i].hsync_start, modes[i].hsync_end, + modes[i].htotal, modes[i].hskew, + modes[i].vdisplay, modes[i].vsync_start, + modes[i].vsync_end, modes[i].vtotal, + modes[i].vscan, modes[i].vrefresh, + modes[i].flags, modes[i].type, + modes[i].name); + } + + wl_tdm_voutput_connect(private_voutput->wl_voutput); + return TDM_ERROR_NONE; } tdm_error tdm_client_output_disconnect(tdm_client_output *output) { + tdm_private_client_voutput *private_voutput; + tdm_private_client_output *private_output; + TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER); + + private_output = (tdm_private_client_output *)output; + private_voutput = (tdm_private_client_voutput *)output; + + TDM_RETURN_VAL_IF_FAIL(private_output->connection != TDM_OUTPUT_CONN_STATUS_DISCONNECTED, + TDM_ERROR_BAD_REQUEST); + + private_output->connection = TDM_OUTPUT_CONN_STATUS_DISCONNECTED; + + wl_tdm_voutput_disconnect(private_voutput->wl_voutput); + return TDM_ERROR_NONE; } diff --git a/client/tdm_client_types.h b/client/tdm_client_types.h index cb4e96d..096b44f 100644 --- a/client/tdm_client_types.h +++ b/client/tdm_client_types.h @@ -110,13 +110,15 @@ typedef void void *user_data); /* Virtual Output */ +/* this is a copy of server side's tdm_output_mode */ typedef struct _tdm_client_output_mode { - char name[TDM_NAME_LEN]; /**< The output name */ - unsigned int mode_count; /**< The count of available modes */ - unsigned int prop_count; /**< The count of available properties */ - unsigned int mmWidth; /**< The physical width (milimeter) */ - unsigned int mmHeight; /**< The physical height (milimeter) */ - unsigned int subpixel; /**< The subpixel */ + unsigned int clock; + unsigned int hdisplay, hsync_start, hsync_end, htotal, hskew; + unsigned int vdisplay, vsync_start, vsync_end, vtotal, vscan; + unsigned int vrefresh; + unsigned int flags; + unsigned int type; + char name[TDM_NAME_LEN]; } tdm_client_output_mode; typedef void tdm_client_voutput; diff --git a/haltests/src/tc_tdm_client.cpp b/haltests/src/tc_tdm_client.cpp index f7ff9f8..1909ff0 100644 --- a/haltests/src/tc_tdm_client.cpp +++ b/haltests/src/tc_tdm_client.cpp @@ -1412,7 +1412,7 @@ public: protected: static tdm_client *client; static tdm_client_voutput *voutput; - const int MODE_COUNT = 1; + const int MODE_COUNT = 2; private: static pid_t server_pid; @@ -1522,12 +1522,21 @@ TEST_F(TDMVirtualOutput, SetAvailableModes) for (i = 0; i < count; i++) { - modes[i].mmHeight = 1234; - modes[i].mmWidth = 1234; - modes[i].mode_count = 0; - modes[i].prop_count = 0; - modes[i].subpixel = 0; - snprintf(modes[i].name, TDM_NAME_LEN, "TestModeSetting"); + modes[i].clock = 1; + modes[i].hdisplay = 2; + modes[i].hsync_start = 3; + modes[i].hsync_end = 4; + modes[i].htotal = 5; + modes[i].hskew = 6; + modes[i].vdisplay = 7; + modes[i].vsync_start = 8; + modes[i].vsync_end = 9; + modes[i].vtotal = 10; + modes[i].vscan = 11; + modes[i].vrefresh = 12; + modes[i].flags = 13; + modes[i].type = 14; + snprintf(modes[i].name, TDM_NAME_LEN, "TestModeSetting %d", i); } ret = tdm_client_voutput_set_available_modes(this->voutput, modes, count); @@ -1545,9 +1554,6 @@ TEST_F(TDMVirtualOutput, FailTestSetAvailableModes) ret = tdm_client_voutput_set_available_modes(this->voutput, NULL, count); ASSERT_EQ(ret, TDM_ERROR_INVALID_PARAMETER); - - ret = tdm_client_voutput_set_available_modes(this->voutput, modes, 0); - ASSERT_EQ(ret, TDM_ERROR_INVALID_PARAMETER); } TEST_F(TDMVirtualOutput, SetPhysicalSize) @@ -1578,6 +1584,36 @@ TEST_F(TDMVirtualOutput, GetClientOutput) ASSERT_NE(output, NULL); } +TEST_F(TDMVirtualOutput, Connect) +{ + tdm_error ret; + tdm_client_output *output; + + output = tdm_client_voutput_get_client_output(this->voutput, &ret); + ASSERT_EQ(ret, TDM_ERROR_NONE); + ASSERT_NE(output, NULL); + + ret = tdm_client_output_connect(output); + ASSERT_EQ(ret, TDM_ERROR_NONE); + + tdm_client_handle_events_timeout(this->client, 0); +} + +TEST_F(TDMVirtualOutput, Disconnect) +{ + tdm_error ret; + tdm_client_output *output; + + output = tdm_client_voutput_get_client_output(this->voutput, &ret); + ASSERT_EQ(ret, TDM_ERROR_NONE); + ASSERT_NE(output, NULL); + + ret = tdm_client_output_disconnect(output); + ASSERT_EQ(ret, TDM_ERROR_NONE); + + tdm_client_handle_events_timeout(this->client, 0); +} + #if 0 TEST_F(TDMVirtualOutput, FailTestGetClientOutput) { diff --git a/protocol/tdm.xml b/protocol/tdm.xml index 58422cf..1248920 100644 --- a/protocol/tdm.xml +++ b/protocol/tdm.xml @@ -77,6 +77,29 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/tdm_server.c b/src/tdm_server.c index d98339c..ed4ddff 100644 --- a/src/tdm_server.c +++ b/src/tdm_server.c @@ -703,6 +703,132 @@ _tdm_server_cb_create_output(struct wl_client *client, struct wl_resource *resou } } +typedef struct _tdm_server_voutput_info { + tdm_private_server *private_server; + tdm_output_conn_status status; + struct + { + int count; + tdm_output_mode *modes; + } available_modes; +} tdm_server_voutput_info; + +static void _tdm_voutput_cb_destroy(struct wl_client *client, struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +static void +_tdm_voutput_cb_set_available_modes(struct wl_client *client, + struct wl_resource *resource, + uint32_t index, + uint32_t clock, + uint32_t hdisplay, + uint32_t hsync_start, + uint32_t hsync_end, + uint32_t htotal, + uint32_t hskew, + uint32_t vdisplay, + uint32_t vsync_start, + uint32_t vsync_end, + uint32_t vtotal, + uint32_t vscan, + uint32_t vrefresh, + uint32_t flags, + uint32_t type, + const char *name) +{ + tdm_server_voutput_info *voutput_info; + tdm_output_mode *tmp_modes, *old_modes; + tdm_output_mode *new_mode; + int count, len; + + voutput_info = wl_resource_get_user_data(resource); + + count = voutput_info->available_modes.count; + old_modes = voutput_info->available_modes.modes; + if (index >= count) + { + if (count > 0) + { + tmp_modes = malloc(count * sizeof(*tmp_modes)); + memcpy(tmp_modes, old_modes, count * sizeof(tdm_output_mode)); + } + + voutput_info->available_modes.count = index + 1; + voutput_info->available_modes.modes = + realloc(voutput_info->available_modes.modes, + sizeof(tdm_output_mode) * (index + 1)); + + if (count > 0) + { + memcpy(voutput_info->available_modes.modes, tmp_modes, count * sizeof(tdm_output_mode)); + free(tmp_modes); + } + } + + new_mode = &voutput_info->available_modes.modes[index]; + new_mode->clock = clock; + new_mode->hdisplay = hdisplay; + new_mode->hsync_start = hsync_start; + new_mode->hsync_end = hsync_end; + new_mode->htotal = htotal; + new_mode->hskew= hskew; + new_mode->vdisplay= vdisplay; + new_mode->vsync_start= vsync_start; + new_mode->vsync_end = vsync_end; + new_mode->vtotal = vtotal; + new_mode->vscan = vscan; + new_mode->vrefresh = vrefresh; + new_mode->flags = flags; + new_mode->type = type; + + len = strlen(name); + strncpy(new_mode->name, name, len); + new_mode->name[len] = '\0'; +} + +static void +_tdm_voutput_cb_connect(struct wl_client *client, struct wl_resource *resource) +{ + tdm_server_voutput_info *voutput_info; + + voutput_info = wl_resource_get_user_data(resource); + voutput_info->status = TDM_OUTPUT_CONN_STATUS_CONNECTED; +} + +static void +_tdm_voutput_cb_disconnect(struct wl_client *client, struct wl_resource *resource) +{ + tdm_server_voutput_info *voutput_info; + + voutput_info = wl_resource_get_user_data(resource); + voutput_info->status = TDM_OUTPUT_CONN_STATUS_DISCONNECTED; + + /* Do free resources when it's being disconnected */ + free(voutput_info->available_modes.modes); + voutput_info->available_modes.modes = NULL; + voutput_info->available_modes.count = 0; +} + +static const struct wl_tdm_voutput_interface tdm_voutput_implementation = { + _tdm_voutput_cb_destroy, + _tdm_voutput_cb_set_available_modes, + _tdm_voutput_cb_connect, + _tdm_voutput_cb_disconnect +}; + +void +tdm_voutput_cb_resource_destroy(struct wl_resource *resource) +{ + tdm_server_voutput_info *voutput_info; + + voutput_info = wl_resource_get_user_data(resource); + + /* Do free your own resource */ + free(voutput_info); +} + static void _tdm_server_cb_create_virtual_output(struct wl_client *client, struct wl_resource *resource, const char *name, uint32_t id) { @@ -758,10 +884,12 @@ _tdm_server_cb_create_virtual_output(struct wl_client *client, struct wl_resourc voutput_info->resource = voutput_resource; voutput_info->output = output; LIST_INITHEAD(&voutput_info->output_list); -#if 0 - wl_resource_set_implementation(voutput_resource, &tdm_voutput_implementation, - voutput_info, destroy_voutput_callback); -#endif + + wl_resource_set_implementation(voutput_resource, + &tdm_voutput_implementation, + voutput_info, + tdm_voutput_cb_resource_destroy); + wl_tdm_voutput_send_ack_message(voutput_resource, WL_TDM_VOUTPUT_MESSAGE_ADDED); } -- 2.7.4 From 9c947c16a27e74229f34c29093dce9822ae63e5b Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Thu, 19 Jul 2018 16:42:23 +0900 Subject: [PATCH 13/16] virtual output: Remove definition, 'tdm_client_output_set_buffer_queue'. Change-Id: Ia3dec1f59ed6afe316b8ff37b551f9bf8ea548f6 --- client/tdm_client.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/client/tdm_client.c b/client/tdm_client.c index 4c05811..acd832e 100644 --- a/client/tdm_client.c +++ b/client/tdm_client.c @@ -1803,16 +1803,6 @@ tdm_client_voutput_get_client_output(tdm_client_voutput *voutput, tdm_error *err } tdm_error -tdm_client_output_set_buffer_queue(tdm_client_output *output, void *queue, void *func) -{ - TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER); - TDM_RETURN_VAL_IF_FAIL(queue != NULL, TDM_ERROR_INVALID_PARAMETER); - TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_ERROR_INVALID_PARAMETER); - - return TDM_ERROR_NONE; -} - -tdm_error tdm_client_output_get_available_modes(tdm_client_output *output, tdm_client_output_mode **modes, int *count) { TDM_RETURN_VAL_IF_FAIL(output != NULL, TDM_ERROR_INVALID_PARAMETER); -- 2.7.4 From 3f08108dd38965411ce789e7751210f5a95162cb Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Thu, 19 Jul 2018 17:59:03 +0900 Subject: [PATCH 14/16] virtual output: fix build break. Remove redefinition, 'tdm_server_voutput_info'. Change-Id: I277e3a14cd31e3db712c9005420e811f88528318 --- src/tdm_server.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/tdm_server.c b/src/tdm_server.c index ed4ddff..3ce52cb 100644 --- a/src/tdm_server.c +++ b/src/tdm_server.c @@ -72,6 +72,13 @@ typedef struct _tdm_server_voutput_info { struct wl_resource *resource; tdm_output *output; struct list_head output_list; + + tdm_output_conn_status status; + struct + { + int count; + tdm_output_mode *modes; + } available_modes; } tdm_server_voutput_info; typedef struct _tdm_server_vblank_info { @@ -703,16 +710,6 @@ _tdm_server_cb_create_output(struct wl_client *client, struct wl_resource *resou } } -typedef struct _tdm_server_voutput_info { - tdm_private_server *private_server; - tdm_output_conn_status status; - struct - { - int count; - tdm_output_mode *modes; - } available_modes; -} tdm_server_voutput_info; - static void _tdm_voutput_cb_destroy(struct wl_client *client, struct wl_resource *resource) { wl_resource_destroy(resource); -- 2.7.4 From ffd3cecfa5117811d4016bff1b39307139765703 Mon Sep 17 00:00:00 2001 From: Junkyeong Kim Date: Fri, 20 Jul 2018 18:48:41 +0900 Subject: [PATCH 15/16] virtual: add set_available_mode & set_phsycal_size function Change-Id: I9f0e0115ab64786207db49f934d72a0d7c7e8ffc Signed-off-by: Junkyeong Kim --- backends/virtual/tdm_virtual.c | 2 + backends/virtual/tdm_virtual.h | 2 + backends/virtual/tdm_virtual_display.c | 125 ++++++++++++++++++++++----------- include/tdm_backend.h | 4 ++ src/tdm_display.c | 17 ++++- src/tdm_output.c | 48 +++++++++++++ src/tdm_private.h | 5 ++ 7 files changed, 160 insertions(+), 43 deletions(-) diff --git a/backends/virtual/tdm_virtual.c b/backends/virtual/tdm_virtual.c index 9c9e4dd..426feaf 100644 --- a/backends/virtual/tdm_virtual.c +++ b/backends/virtual/tdm_virtual.c @@ -75,6 +75,8 @@ tdm_virtual_init(tdm_display *dpy, tdm_error *error) virtual_func_output.output_set_commit_handler = virtual_output_set_commit_handler; virtual_func_output.output_set_mode = virtual_output_set_mode; virtual_func_output.output_get_mode = virtual_output_get_mode; + virtual_func_output.output_set_available_mode = virtual_output_set_available_mode; + virtual_func_output.output_set_physical_size = virtual_output_set_physical_size; memset(&virtual_func_layer, 0, sizeof(virtual_func_layer)); virtual_func_layer.layer_get_capability = virtual_layer_get_capability; diff --git a/backends/virtual/tdm_virtual.h b/backends/virtual/tdm_virtual.h index f1cdf91..1ad4550 100644 --- a/backends/virtual/tdm_virtual.h +++ b/backends/virtual/tdm_virtual.h @@ -40,6 +40,8 @@ tdm_error virtual_output_commit(tdm_output *output, int sync, void *user_data); tdm_error virtual_output_set_commit_handler(tdm_output *output, tdm_output_commit_handler func); tdm_error virtual_output_set_mode(tdm_output *output, const tdm_output_mode *mode); tdm_error virtual_output_get_mode(tdm_output *output, const tdm_output_mode **mode); +tdm_error virtual_output_set_available_mode(tdm_output *output, const tdm_output_mode *modes, int count); +tdm_error virtual_output_set_physical_size(tdm_output *output, unsigned int mmwidth, unsigned int mmheight); tdm_error virtual_layer_get_capability(tdm_layer *layer, tdm_caps_layer *caps); tdm_error virtual_layer_set_info(tdm_layer *layer, tdm_info_layer *info); diff --git a/backends/virtual/tdm_virtual_display.c b/backends/virtual/tdm_virtual_display.c index 9bf7363..2288a72 100644 --- a/backends/virtual/tdm_virtual_display.c +++ b/backends/virtual/tdm_virtual_display.c @@ -28,7 +28,7 @@ struct _tdm_virtual_output_data { tdm_virtual_data *virtual_data; uint32_t pipe; - tdm_output_mode *output_mode; + tdm_output_mode *output_modes; int mode_count; tdm_output_type connector_type; struct list_head layer_list; @@ -122,14 +122,14 @@ _tdm_virtual_display_wait_vblank(tdm_virtual_output_data *output_data, int inter unsigned int ms; RETURN_VAL_IF_FAIL(output_data->timer != NULL, TDM_ERROR_OPERATION_FAILED); - RETURN_VAL_IF_FAIL(output_data->output_mode->vrefresh > 0, TDM_ERROR_OPERATION_FAILED); + RETURN_VAL_IF_FAIL(output_data->current_mode->vrefresh > 0, TDM_ERROR_OPERATION_FAILED); if (output_data->timer_waiting) { LIST_ADDTAIL(&event_data->link, &output_data->timer_event_list); return TDM_ERROR_NONE; } - ms = ((double)1000.0 / output_data->output_mode->vrefresh) * interval; + ms = ((double)1000.0 / output_data->current_mode->vrefresh) * interval; ret = tdm_event_loop_source_timer_update(output_data->timer, ms); if (ret != TDM_ERROR_NONE) @@ -214,7 +214,7 @@ tdm_virtual_display_destroy_output_list(tdm_virtual_data *virtual_data) if (o->timer) tdm_event_loop_source_remove(o->timer); - free(o->output_mode); + free(o->output_modes); free(o); } } @@ -241,29 +241,29 @@ tdm_virtual_display_create_output_list(tdm_virtual_data *virtual_data) output_data->connector_type = TDM_OUTPUT_TYPE_Unknown; output_data->status = TDM_OUTPUT_CONN_STATUS_DISCONNECTED; - output_data->output_mode = calloc(1, sizeof(tdm_output_mode)); - if (!output_data->output_mode) { + output_data->output_modes = calloc(1, sizeof(tdm_output_mode)); + if (!output_data->output_modes) { TDM_ERR("alloc failed"); free(output_data); ret = TDM_ERROR_OUT_OF_MEMORY; goto failed_create; } - snprintf(output_data->output_mode->name, TDM_NAME_LEN, "640x480"); - output_data->output_mode->vrefresh = 30; - output_data->output_mode->clock = 25200; - output_data->output_mode->hdisplay = 640; - output_data->output_mode->hsync_start = 656; - output_data->output_mode->hsync_end = 752; - output_data->output_mode->htotal = 800; - output_data->output_mode->hskew = 0; - output_data->output_mode->vdisplay = 480; - output_data->output_mode->vsync_start = 490; - output_data->output_mode->vsync_end = 492; - output_data->output_mode->vtotal = 525; - output_data->output_mode->vscan = 0; - output_data->output_mode->flags = 0; - output_data->output_mode->type = 0; + snprintf(output_data->output_modes->name, TDM_NAME_LEN, "640x480"); + output_data->output_modes->vrefresh = 30; + output_data->output_modes->clock = 25200; + output_data->output_modes->hdisplay = 640; + output_data->output_modes->hsync_start = 656; + output_data->output_modes->hsync_end = 752; + output_data->output_modes->htotal = 800; + output_data->output_modes->hskew = 0; + output_data->output_modes->vdisplay = 480; + output_data->output_modes->vsync_start = 490; + output_data->output_modes->vsync_end = 492; + output_data->output_modes->vtotal = 525; + output_data->output_modes->vscan = 0; + output_data->output_modes->flags = 0; + output_data->output_modes->type = 0; output_data->timer = tdm_event_loop_add_timer_handler(virtual_data->dpy, _tdm_virtual_display_cb_timeout, @@ -390,28 +390,28 @@ virtual_display_output_create(tdm_backend_data *bdata, const char *name, tdm_err else snprintf(output_data->name, TDM_NAME_LEN, "unknown"); #if 0 - output_data->output_mode = calloc(1, sizeof(tdm_output_mode)); - if (!output_data->output_mode) { + output_data->output_modes = calloc(1, sizeof(tdm_output_mode)); + if (!output_data->output_modes) { TDM_ERR("alloc failed"); ret = TDM_ERROR_OUT_OF_MEMORY; goto create_fail; } - snprintf(output_data->output_mode->name, TDM_NAME_LEN, "640x480"); - output_data->output_mode->vrefresh = 30; - output_data->output_mode->clock = 25200; - output_data->output_mode->hdisplay = 640; - output_data->output_mode->hsync_start = 656; - output_data->output_mode->hsync_end = 752; - output_data->output_mode->htotal = 800; - output_data->output_mode->hskew = 0; - output_data->output_mode->vdisplay = 480; - output_data->output_mode->vsync_start = 490; - output_data->output_mode->vsync_end = 492; - output_data->output_mode->vtotal = 525; - output_data->output_mode->vscan = 0; - output_data->output_mode->flags = 0; - output_data->output_mode->type = 0; + snprintf(output_data->output_modes->name, TDM_NAME_LEN, "640x480"); + output_data->output_modes->vrefresh = 30; + output_data->output_modes->clock = 25200; + output_data->output_modes->hdisplay = 640; + output_data->output_modes->hsync_start = 656; + output_data->output_modes->hsync_end = 752; + output_data->output_modes->htotal = 800; + output_data->output_modes->hskew = 0; + output_data->output_modes->vdisplay = 480; + output_data->output_modes->vsync_start = 490; + output_data->output_modes->vsync_end = 492; + output_data->output_modes->vtotal = 525; + output_data->output_modes->vscan = 0; + output_data->output_modes->flags = 0; + output_data->output_modes->type = 0; output_data->mode_count = 1; #endif @@ -449,7 +449,7 @@ virtual_display_output_create(tdm_backend_data *bdata, const char *name, tdm_err create_fail: if (layer_data) free(layer_data); - if (output_data->output_mode) free(output_data->output_mode); + if (output_data->output_modes) free(output_data->output_modes); free(output_data); *error = ret; @@ -474,8 +474,11 @@ virtual_display_output_destroy(tdm_backend_data *bdata, tdm_output *output) } } - if (find) + if (find) { + if (output_data->output_modes) + free(output_data->output_modes); tdm_backend_unregister_output(virtual_data->dpy, output); + } else return TDM_ERROR_INVALID_PARAMETER; @@ -510,7 +513,7 @@ virtual_output_get_capability(tdm_output *output, tdm_caps_output *caps) goto failed_get; } - *caps->modes = *output_data->output_mode; + *caps->modes = *output_data->output_modes; } caps->mmWidth = output_data->mmwidth; @@ -685,6 +688,46 @@ virtual_output_get_mode(tdm_output *output, const tdm_output_mode **mode) } tdm_error +virtual_output_set_available_mode(tdm_output *output, const tdm_output_mode *modes, int count) +{ + tdm_virtual_output_data *output_data = output; + + RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(modes, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(count > 0, TDM_ERROR_INVALID_PARAMETER); + + /* set available mode only permittied disconnect status */ + RETURN_VAL_IF_FAIL(output_data->status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED, TDM_ERROR_BUSY); + + if (output_data->output_modes) + free(output_data->output_modes); + output_data->output_modes = NULL; + + output_data->output_modes = calloc(1, count * sizeof(tdm_output_mode)); + RETURN_VAL_IF_FAIL(output_data->output_modes != NULL, TDM_ERROR_OUT_OF_MEMORY); + + memcpy(output_data->output_modes, modes, count * sizeof(tdm_output_mode)); + output_data->mode_count = count; + + return TDM_ERROR_NONE; +} + +tdm_error +virtual_output_set_physical_size(tdm_output *output, unsigned int mmwidth, unsigned int mmheight) +{ + tdm_virtual_output_data *output_data = output; + + RETURN_VAL_IF_FAIL(output_data, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(mmwidth != 0, TDM_ERROR_INVALID_PARAMETER); + RETURN_VAL_IF_FAIL(mmheight != 0, TDM_ERROR_INVALID_PARAMETER); + + output_data->mmwidth = mmwidth; + output_data->mmheight = mmheight; + + return TDM_ERROR_NONE; +} + +tdm_error virtual_layer_get_capability(tdm_layer *layer, tdm_caps_layer *caps) { tdm_virtual_layer_data *layer_data = layer; diff --git a/include/tdm_backend.h b/include/tdm_backend.h index 2e80d99..7f43ee2 100644 --- a/include/tdm_backend.h +++ b/include/tdm_backend.h @@ -550,6 +550,10 @@ typedef struct _tdm_func_output { */ tdm_hwc *(*output_get_hwc)(tdm_output *output, tdm_error *error); + /* virtual */ + tdm_error (*output_set_available_mode)(tdm_output *output, const tdm_output_mode *modes, int count); + tdm_error (*output_set_physical_size)(tdm_output *output, unsigned int mmwidth, unsigned int mmheight); + void (*reserved5)(void); void (*reserved6)(void); void (*reserved7)(void); diff --git a/src/tdm_display.c b/src/tdm_display.c index a355ab7..3373f88 100644 --- a/src/tdm_display.c +++ b/src/tdm_display.c @@ -820,8 +820,10 @@ tdm_display_create_output(tdm_display *dpy, const char *name, tdm_error *error) { tdm_private_module *private_module = NULL; tdm_private_module *current_module = NULL; + tdm_private_output *private_output = NULL; tdm_func_display *func_display = NULL; tdm_output *output = NULL; + int output_find = 0; DISPLAY_FUNC_ENTRY_ERROR(); @@ -840,13 +842,21 @@ tdm_display_create_output(tdm_display *dpy, const char *name, tdm_error *error) current_module = private_display->current_module; private_display->current_module = private_module; output = func_display->display_output_create(private_module->bdata, name, &ret); + LIST_FOR_EACH_ENTRY(private_output, &private_module->output_list, link) { + if (private_output->output_backend == output) { + output_find = 1; + break; + } + } private_display->current_module = current_module; _pthread_mutex_unlock(&private_display->lock); TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(output != NULL, ret, NULL); + if (output_find != 1) + private_output = NULL; - return output; + return private_output; } INTERN tdm_error @@ -854,6 +864,7 @@ tdm_display_destroy_output(tdm_display *dpy, tdm_output *output) { tdm_private_module *private_module = NULL; tdm_private_module *current_module = NULL; + tdm_private_output *private_output = NULL; tdm_func_display *func_display = NULL; DISPLAY_FUNC_ENTRY(); @@ -864,12 +875,14 @@ tdm_display_destroy_output(tdm_display *dpy, tdm_output *output) private_module = private_display->virtual_module; TDM_RETURN_VAL_IF_FAIL(private_module != NULL, TDM_ERROR_BAD_MODULE); + private_output = (tdm_private_output*)output; + _pthread_mutex_lock(&private_display->lock); func_display = &private_module->func_display; current_module = private_display->current_module; private_display->current_module = private_module; - ret = func_display->display_output_destroy(private_module->bdata, output); + ret = func_display->display_output_destroy(private_module->bdata, private_output->output_backend); private_display->current_module = current_module; _pthread_mutex_unlock(&private_display->lock); diff --git a/src/tdm_output.c b/src/tdm_output.c index 550a750..a7813da 100644 --- a/src/tdm_output.c +++ b/src/tdm_output.c @@ -1717,4 +1717,52 @@ tdm_output_choose_commit_per_vblank_mode(tdm_private_output *private_output, int return TDM_ERROR_NONE; } + +INTERN tdm_error +tdm_output_set_available_mode(tdm_output *output, const tdm_output_mode *modes, int count) +{ + tdm_private_module *private_module = NULL; + tdm_func_output *func_output = NULL; + + OUTPUT_FUNC_ENTRY(); + + TDM_RETURN_VAL_IF_FAIL(modes != NULL, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(count != 0, TDM_ERROR_INVALID_PARAMETER); + + private_module = private_output->private_module; + TDM_RETURN_VAL_IF_FAIL(private_module == private_display->virtual_module, TDM_ERROR_BAD_MODULE); + + _pthread_mutex_lock(&private_display->lock); + + func_output = &private_module->func_output; + ret = func_output->output_set_available_mode(private_output->output_backend, modes, count); + + _pthread_mutex_unlock(&private_display->lock); + + return ret; +} + +INTERN tdm_error +tdm_output_set_physical_size(tdm_output *output, unsigned int mmwidth, unsigned int mmheight) +{ + tdm_private_module *private_module = NULL; + tdm_func_output *func_output = NULL; + + OUTPUT_FUNC_ENTRY(); + + TDM_RETURN_VAL_IF_FAIL(mmwidth != 0, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(mmheight != 0, TDM_ERROR_INVALID_PARAMETER); + + private_module = private_output->private_module; + TDM_RETURN_VAL_IF_FAIL(private_module == private_display->virtual_module, TDM_ERROR_BAD_MODULE); + + _pthread_mutex_lock(&private_display->lock); + + func_output = &private_module->func_output; + ret = func_output->output_set_physical_size(private_output->output_backend, mmwidth, mmheight); + + _pthread_mutex_unlock(&private_display->lock); + + return ret; +} /* LCOV_EXCL_STOP */ diff --git a/src/tdm_private.h b/src/tdm_private.h index d747993..2e7ffa3 100644 --- a/src/tdm_private.h +++ b/src/tdm_private.h @@ -255,10 +255,15 @@ tdm_config_deinit(void); void tdm_monitor_server_command(tdm_display *dpy, const char *options, char *reply, int *len); +/* virtual */ tdm_output * tdm_display_create_output(tdm_display *dpy, const char *name, tdm_error *error); tdm_error tdm_display_destroy_output(tdm_display *dpy, tdm_output *output); +tdm_error +tdm_output_set_available_mode(tdm_output *output, const tdm_output_mode *modes, int count); +tdm_error +tdm_output_set_physical_size(tdm_output *output, unsigned int mmwidth, unsigned int mmheight); #ifdef __cplusplus } -- 2.7.4 From 77aaf72a8ef5ff9d32b1be594659201d59ccf2e1 Mon Sep 17 00:00:00 2001 From: Junkyeong Kim Date: Mon, 23 Jul 2018 15:03:45 +0900 Subject: [PATCH 16/16] virtual: add set_physical_size protocol Change-Id: I19f67d59f816bd1486f6c1f408416856c03469ac Signed-off-by: Junkyeong Kim --- client/tdm_client.c | 20 +++++++++++++++++--- client/tdm_client.h | 2 +- haltests/src/tc_tdm_client.cpp | 8 ++++---- protocol/tdm.xml | 5 +++++ src/tdm_server.c | 16 ++++++++++++++++ 5 files changed, 43 insertions(+), 8 deletions(-) diff --git a/client/tdm_client.c b/client/tdm_client.c index acd832e..e86f2d2 100644 --- a/client/tdm_client.c +++ b/client/tdm_client.c @@ -99,6 +99,9 @@ typedef struct _tdm_private_client_voutput { tdm_client_output_mode *modes; } available_modes; + unsigned int mmwidth; + unsigned int mmheight; + uint32_t msg; } tdm_private_client_voutput; @@ -1772,11 +1775,22 @@ tdm_client_voutput_set_available_modes(tdm_client_voutput *voutput, const tdm_cl } tdm_error -tdm_client_voutput_set_physical_size(tdm_client_voutput *voutput, int mmWidth, int mmHeight) +tdm_client_voutput_set_physical_size(tdm_client_voutput *voutput, unsigned int mmWidth, unsigned int mmHeight) { + tdm_private_client_voutput *private_voutput; + TDM_RETURN_VAL_IF_FAIL(voutput != NULL, TDM_ERROR_INVALID_PARAMETER); - TDM_RETURN_VAL_IF_FAIL(mmWidth > 0, TDM_ERROR_INVALID_PARAMETER); - TDM_RETURN_VAL_IF_FAIL(mmHeight > 0, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(mmWidth != 0, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(mmHeight != 0, TDM_ERROR_INVALID_PARAMETER); + + private_voutput = (tdm_private_client_voutput *)voutput; + + if (private_voutput->base.connection == TDM_OUTPUT_CONN_STATUS_CONNECTED) + return TDM_ERROR_BAD_REQUEST; + + private_voutput->mmwidth = mmWidth; + private_voutput->mmheight = mmHeight; + wl_tdm_voutput_set_physical_size(private_voutput->wl_voutput, private_voutput->mmwidth, private_voutput->mmheight); return TDM_ERROR_NONE; } diff --git a/client/tdm_client.h b/client/tdm_client.h index 4ffe435..d0512cc 100644 --- a/client/tdm_client.h +++ b/client/tdm_client.h @@ -442,7 +442,7 @@ tdm_error tdm_client_voutput_set_available_modes(tdm_client_voutput *voutput, const tdm_client_output_mode *modes, int count); tdm_error -tdm_client_voutput_set_physical_size(tdm_client_voutput *voutput, int mmWidth, int mmHeight); +tdm_client_voutput_set_physical_size(tdm_client_voutput *voutput, unsigned int mmWidth, unsigned int mmHeight); tdm_error tdm_client_voutput_add_commit_handler(tdm_client_voutput *voutput, tdm_client_voutput_commit_handler *func); diff --git a/haltests/src/tc_tdm_client.cpp b/haltests/src/tc_tdm_client.cpp index 1909ff0..c637d88 100644 --- a/haltests/src/tc_tdm_client.cpp +++ b/haltests/src/tc_tdm_client.cpp @@ -1559,8 +1559,8 @@ TEST_F(TDMVirtualOutput, FailTestSetAvailableModes) TEST_F(TDMVirtualOutput, SetPhysicalSize) { tdm_error ret; - int mmWidth = 1234, mmHeight = 1234; - + unsigned int mmWidth = 1234, mmHeight = 1234; + ret = tdm_client_voutput_set_physical_size(this->voutput, mmWidth, mmHeight); ASSERT_EQ(ret, TDM_ERROR_NONE); } @@ -1568,8 +1568,8 @@ TEST_F(TDMVirtualOutput, SetPhysicalSize) TEST_F(TDMVirtualOutput, FailTestSetPhysicalSize) { tdm_error ret; - int invalid_mmWidth = -1, invalid_mmHeight = -1; - + unsigned int invalid_mmWidth = 0, invalid_mmHeight = 0; + ret = tdm_client_voutput_set_physical_size(this->voutput, invalid_mmWidth, invalid_mmHeight); ASSERT_EQ(ret, TDM_ERROR_INVALID_PARAMETER); } diff --git a/protocol/tdm.xml b/protocol/tdm.xml index 1248920..3db00b1 100644 --- a/protocol/tdm.xml +++ b/protocol/tdm.xml @@ -96,6 +96,11 @@ + + + + + diff --git a/src/tdm_server.c b/src/tdm_server.c index 3ce52cb..cf743fa 100644 --- a/src/tdm_server.c +++ b/src/tdm_server.c @@ -79,6 +79,9 @@ typedef struct _tdm_server_voutput_info { int count; tdm_output_mode *modes; } available_modes; + + unsigned int mmwidth; + unsigned int mmheight; } tdm_server_voutput_info; typedef struct _tdm_server_vblank_info { @@ -786,6 +789,18 @@ _tdm_voutput_cb_set_available_modes(struct wl_client *client, } static void +_tdm_voutput_cb_set_physical_size(struct wl_client *client, struct wl_resource *resource, + unsigned int mmwidth, unsigned int mmheight) +{ + tdm_server_voutput_info *voutput_info; + + voutput_info = wl_resource_get_user_data(resource); + + voutput_info->mmwidth = mmwidth; + voutput_info->mmheight = mmheight; +} + +static void _tdm_voutput_cb_connect(struct wl_client *client, struct wl_resource *resource) { tdm_server_voutput_info *voutput_info; @@ -811,6 +826,7 @@ _tdm_voutput_cb_disconnect(struct wl_client *client, struct wl_resource *resourc static const struct wl_tdm_voutput_interface tdm_voutput_implementation = { _tdm_voutput_cb_destroy, _tdm_voutput_cb_set_available_modes, + _tdm_voutput_cb_set_physical_size, _tdm_voutput_cb_connect, _tdm_voutput_cb_disconnect }; -- 2.7.4