From 9a9d836fb0d090ad6ce39ed002ead2f0c86187ab Mon Sep 17 00:00:00 2001 From: Boram Park Date: Thu, 31 Mar 2016 18:53:37 +0900 Subject: [PATCH 01/16] support client API for wait_vblank Change-Id: Id7df85559d73324556752ac2a4f572ee259fd731 --- .gitignore | 2 + Makefile.am | 2 +- client/Makefile.am | 23 ++++ client/libtdm-client.pc.in | 11 ++ client/tdm_client.c | 248 ++++++++++++++++++++++++++++++++++++++++ client/tdm_client.h | 87 ++++++++++++++ configure.ac | 18 ++- include/tdm_list.h | 8 ++ include/tdm_log.h | 1 + packaging/libtdm.spec | 58 +++++++++- protocol/Makefile.am | 14 +++ protocol/tdm.xml | 30 +++++ service/tdm-socket-user.path | 5 + service/tdm-socket-user.service | 6 + service/tdm-socket.path | 5 + service/tdm-socket.service | 11 ++ src/Makefile.am | 15 ++- src/tdm.c | 93 +++++++-------- src/tdm_capture.c | 9 +- src/tdm_display.c | 166 ++++++++++++++++++++++----- src/tdm_event_loop.c | 53 +++++---- src/tdm_helper.c | 25 ++++ src/tdm_macro.h | 125 ++++++++++++++++++++ src/tdm_pp.c | 8 +- src/tdm_private.h | 158 ++++++++++++------------- src/tdm_server.c | 246 +++++++++++++++++++++++++++++++++++++++ src/tdm_thread.c | 113 +++++++++--------- 27 files changed, 1283 insertions(+), 257 deletions(-) create mode 100644 client/Makefile.am create mode 100644 client/libtdm-client.pc.in create mode 100644 client/tdm_client.c create mode 100644 client/tdm_client.h create mode 100644 protocol/Makefile.am create mode 100644 protocol/tdm.xml create mode 100644 service/tdm-socket-user.path create mode 100644 service/tdm-socket-user.service create mode 100644 service/tdm-socket.path create mode 100644 service/tdm-socket.service create mode 100644 src/tdm_macro.h create mode 100644 src/tdm_server.c diff --git a/.gitignore b/.gitignore index 49d27e8..7a0fbff 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,5 @@ stamp-h1 *~ html/ latex/ +protocol/*.h +protocol/*.c diff --git a/Makefile.am b/Makefile.am index c99188a..e8aa5d7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = . include src +SUBDIRS = . include protocol client src pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libtdm.pc diff --git a/client/Makefile.am b/client/Makefile.am new file mode 100644 index 0000000..14192b0 --- /dev/null +++ b/client/Makefile.am @@ -0,0 +1,23 @@ +libtdm_clientincludedir = ${includedir} +libtdm_clientinclude_HEADERS = \ + tdm_client.h + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = libtdm-client.pc + +libtdm_client_la_LTLIBRARIES = libtdm-client.la +libtdm_client_ladir = $(libdir) +libtdm_client_la_LDFLAGS = $(LDFLAGS) +libtdm_client_la_LIBADD = $(TDM_CLIENT_LIBS) +libtdm_client_la_CFLAGS = \ + $(CFLAGS) \ + $(WARN_CFLAGS) \ + $(TDM_CLIENT_CFLAGS) \ + -I$(top_srcdir)/include \ + -I$(top_srcdir)/protocol \ + -I$(top_srcdir)/src \ + -I$(top_srcdir)/client + +libtdm_client_la_SOURCES = \ + $(top_srcdir)/protocol/tdm-protocol.c \ + tdm_client.c diff --git a/client/libtdm-client.pc.in b/client/libtdm-client.pc.in new file mode 100644 index 0000000..cbdf224 --- /dev/null +++ b/client/libtdm-client.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libtdm-client +Description: Tizen Display Manager Client Library +Version: @PACKAGE_VERSION@ +Requires: +Libs: -L${libdir} -ltdm-client +Cflags: -I${includedir} diff --git a/client/tdm_client.c b/client/tdm_client.c new file mode 100644 index 0000000..5e2b750 --- /dev/null +++ b/client/tdm_client.c @@ -0,0 +1,248 @@ +/************************************************************************** + +libtdm + +Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved. + +Contact: Eunchul Kim , + JinYoung Jeon , + Taeheon Kim , + YoungJun Cho , + SooChan Lim , + Boram Park + +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. + +**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include "tdm_client.h" +#include "tdm_log.h" +#include "tdm_macro.h" +#include "tdm_list.h" +#include "tdm-client-protocol.h" + +extern int tdm_debug; + +typedef struct _tdm_private_client { + struct wl_display *display; + struct wl_registry *registry; + struct wl_tdm *tdm; + + struct list_head vblank_list; +} tdm_private_client; + +typedef struct _tdm_client_vblank_info { + struct list_head link; + struct wl_tdm_vblank *vblank; + tdm_client_vblank_handler func; + void *user_data; +} tdm_client_vblank_info; + +static void +_tdm_client_cb_global(void *data, struct wl_registry *registry, + uint32_t name, const char *interface, + uint32_t version) +{ + tdm_private_client *private_client = data; + + if (strcmp(interface, "wl_tdm") == 0) { + private_client->tdm = + wl_registry_bind(registry, name, &wl_tdm_interface, version); + TDM_RETURN_IF_FAIL(private_client->tdm != NULL); + + wl_display_flush(private_client->display); + } +} + +static void +_tdm_client_cb_global_remove(void *data, struct wl_registry *registry, uint32_t name) +{ +} + +static const struct wl_registry_listener tdm_client_registry_listener = +{ + _tdm_client_cb_global, + _tdm_client_cb_global_remove +}; + +tdm_client* +tdm_client_create(tdm_client_error *error) +{ + tdm_private_client *private_client; + + private_client = calloc(1, sizeof *private_client); + if (!private_client) { + TDM_ERR("alloc failed"); + if (error) + *error = TDM_CLIENT_ERROR_OUT_OF_MEMORY; + return NULL; + } + + private_client->display = wl_display_connect("tdm-socket"); + TDM_GOTO_IF_FAIL(private_client->display != NULL, create_failed); + + private_client->registry = wl_display_get_registry(private_client->display); + TDM_GOTO_IF_FAIL(private_client->registry != NULL, create_failed); + + wl_registry_add_listener(private_client->registry, + &tdm_client_registry_listener, private_client); + wl_display_roundtrip(private_client->display); + + /* check global objects */ + TDM_GOTO_IF_FAIL(private_client->tdm != NULL, create_failed); + + LIST_INITHEAD(&private_client->vblank_list); + + if (error) + *error = TDM_CLIENT_ERROR_NONE; + + return (tdm_client*)private_client; +create_failed: + tdm_client_destroy((tdm_client*)private_client); + if (error) + *error = TDM_CLIENT_ERROR_OPERATION_FAILED; + return NULL; +} + +void +tdm_client_destroy(tdm_client *client) +{ + tdm_private_client *private_client = (tdm_private_client*)client; + tdm_client_vblank_info *v = NULL, *vv = NULL; + + if (!private_client) + return; + + LIST_FOR_EACH_ENTRY_SAFE(v, vv, &private_client->vblank_list, link) { + LIST_DEL(&v->link); + wl_tdm_vblank_destroy(v->vblank); + free(v); + } + + if (private_client->tdm) + wl_tdm_destroy(private_client->tdm); + if (private_client->registry) + wl_registry_destroy(private_client->registry); + if (private_client->display) + wl_display_disconnect(private_client->display); + + free(private_client); +} + +tdm_client_error +tdm_client_get_fd(tdm_client *client, int *fd) +{ + tdm_private_client *private_client; + + TDM_RETURN_VAL_IF_FAIL(client != NULL, TDM_CLIENT_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(fd != NULL, TDM_CLIENT_ERROR_INVALID_PARAMETER); + + private_client = (tdm_private_client*)client; + + *fd = wl_display_get_fd(private_client->display); + if (*fd < 0) + return TDM_CLIENT_ERROR_OPERATION_FAILED; + + return TDM_CLIENT_ERROR_NONE; +} + +tdm_client_error +tdm_client_handle_events(tdm_client *client) +{ + tdm_private_client *private_client; + + TDM_RETURN_VAL_IF_FAIL(client != NULL, TDM_CLIENT_ERROR_INVALID_PARAMETER); + + private_client = (tdm_private_client*)client; + + wl_display_dispatch(private_client->display); + + return TDM_CLIENT_ERROR_NONE; +} + +static void +_tdm_client_cb_vblank_done(void *data, struct wl_tdm_vblank *vblank, + uint32_t sequence, uint32_t tv_sec, uint32_t tv_usec) +{ + tdm_client_vblank_info *vblank_info = (tdm_client_vblank_info*)data; + + TDM_RETURN_IF_FAIL(vblank_info != NULL); + + if (vblank_info->func) { + vblank_info->func(sequence, tv_sec, tv_usec, vblank_info->user_data); + } + + LIST_DEL(&vblank_info->link); + free(vblank_info); +} + +static const struct wl_tdm_vblank_listener tdm_client_vblank_listener = { + _tdm_client_cb_vblank_done, +}; + +tdm_client_error +tdm_client_wait_vblank(tdm_client *client, char *name, int interval, int sync, + tdm_client_vblank_handler func, void *user_data) +{ + tdm_private_client *private_client = (tdm_private_client*)client; + tdm_client_vblank_info *vblank_info; + + TDM_RETURN_VAL_IF_FAIL(name != NULL, TDM_CLIENT_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(interval > 0, TDM_CLIENT_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(func != NULL, TDM_CLIENT_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(private_client != NULL, TDM_CLIENT_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(private_client->tdm != NULL, TDM_CLIENT_ERROR_INVALID_PARAMETER); + + vblank_info = calloc(1, sizeof *vblank_info); + if (!vblank_info) { + TDM_ERR("alloc failed"); + return TDM_CLIENT_ERROR_OUT_OF_MEMORY; + } + + vblank_info->vblank = wl_tdm_wait_vblank(private_client->tdm, name, interval); + if (!vblank_info->vblank) { + TDM_ERR("couldn't create vblank resource"); + free(vblank_info); + return TDM_CLIENT_ERROR_OUT_OF_MEMORY; + } + + wl_tdm_vblank_add_listener(vblank_info->vblank, + &tdm_client_vblank_listener, vblank_info); + + vblank_info->func = func; + vblank_info->user_data = user_data; + LIST_ADDTAIL(&vblank_info->link, &private_client->vblank_list); + + if (sync) + wl_display_roundtrip(private_client->display); + else + wl_display_flush(private_client->display); + + return TDM_CLIENT_ERROR_NONE; +} diff --git a/client/tdm_client.h b/client/tdm_client.h new file mode 100644 index 0000000..6312d9d --- /dev/null +++ b/client/tdm_client.h @@ -0,0 +1,87 @@ +/************************************************************************** + +libtdm + +Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved. + +Contact: Eunchul Kim , + JinYoung Jeon , + Taeheon Kim , + YoungJun Cho , + SooChan Lim , + Boram Park + +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. + +**************************************************************************/ + +#ifndef _TDM_CLIENT_H_ +#define _TDM_CLIENT_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file tdm_client.h + * @brief The header file for a client user of TDM. + * @par Example + * @code + #include //for a client user of TDM + * @endcode + */ + +typedef enum +{ + TDM_CLIENT_ERROR_NONE = 0, /**< none */ + TDM_CLIENT_ERROR_OPERATION_FAILED = -1, /**< operaion failed */ + TDM_CLIENT_ERROR_INVALID_PARAMETER = -2, /**< wrong input parameter */ + TDM_CLIENT_ERROR_PERMISSION_DENIED = -3, /**< access denied */ + TDM_CLIENT_ERROR_OUT_OF_MEMORY = -4, /**< no free memory */ +} tdm_client_error; + +typedef void *tdm_client; + +typedef void +(*tdm_client_vblank_handler)(unsigned int sequence, unsigned int tv_sec, + unsigned int tv_usec, void *user_data); + +tdm_client* +tdm_client_create(tdm_client_error *error); + +void +tdm_client_destroy(tdm_client *client); + +tdm_client_error +tdm_client_get_fd(tdm_client *client, int *fd); + +tdm_client_error +tdm_client_handle_events(tdm_client *client); + +tdm_client_error +tdm_client_wait_vblank(tdm_client *client, char *name, int interval, int sync, + tdm_client_vblank_handler func, void *user_data); + +#ifdef __cplusplus +} +#endif + +#endif /* _TDM_CLIENT_H_ */ diff --git a/configure.ac b/configure.ac index 358c2e4..db21b7e 100644 --- a/configure.ac +++ b/configure.ac @@ -23,7 +23,14 @@ LT_INIT([disable-static]) # Enable quiet compiles on automake 1.11. m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) -PKG_CHECK_MODULES(TDM, libtbm pthread-stubs libpng wayland-server) +AC_PATH_PROG([wayland_scanner], [wayland-scanner]) +if test x$wayland_scanner = x; then + AC_MSG_ERROR([wayland-scanner is needed to compile]) +fi + +PKG_CHECK_MODULES(WAYLAND_SCANNER, wayland-scanner >= 1.7.0) + +PKG_CHECK_MODULES(TDM, dlog libtbm pthread-stubs libpng wayland-server) PKG_CHECK_MODULES(TTRACE, [ttrace], @@ -37,6 +44,10 @@ fi AC_SUBST(TDM_CFLAGS) AC_SUBST(TDM_LIBS) +PKG_CHECK_MODULES(TDM_CLIENT, dlog wayland-client) +AC_SUBST(TDM_CLIENT_CFLAGS) +AC_SUBST(TDM_CLIENT_LIBS) + # set the dir for the tbm module DEFAULT_TDM_MODULE_PATH="${libdir}/tdm" AC_ARG_WITH(tdm-module-path, AS_HELP_STRING([--with-tdm-module-path=PATH], [tdm module dir]), @@ -50,6 +61,9 @@ AC_OUTPUT([ Makefile libtdm.pc include/Makefile + protocol/Makefile + client/libtdm-client.pc + client/Makefile src/Makefile]) echo "" @@ -57,5 +71,7 @@ echo "$PACKAGE_STRING will be compiled with:" echo "" echo "TDM_CFLAGS : $TDM_CFLAGS" echo "TDM_LIBS : $TDM_LIBS" +echo "TDM_CLIENT_CFLAGS : $TDM_CLIENT_CFLAGS" +echo "TDM_CLIENT_LIBS : $TDM_CLIENT_LIBS" echo "TDM_MODULE_PATH : $TDM_MODULE_PATH" echo "" diff --git a/include/tdm_list.h b/include/tdm_list.h index bd6ac80..acdf6c4 100644 --- a/include/tdm_list.h +++ b/include/tdm_list.h @@ -133,4 +133,12 @@ static inline void list_delinit(struct list_head *item) &pos->member != (head); \ pos = container_of(pos->member.prev, pos, member)) +#define LIST_FIND_ITEM(item, head, type, member, found) \ + do { \ + type *pos; \ + found = NULL; \ + LIST_FOR_EACH_ENTRY(pos, head, member) \ + if (pos == item) { found = item; break; } \ + } while (0) + #endif /*_U_DOUBLE_LIST_H_*/ diff --git a/include/tdm_log.h b/include/tdm_log.h index 508e655..cddf0e6 100644 --- a/include/tdm_log.h +++ b/include/tdm_log.h @@ -41,6 +41,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. extern "C" { #endif +#include #include #include diff --git a/packaging/libtdm.spec b/packaging/libtdm.spec index 0673f9c..3f6e0b1 100644 --- a/packaging/libtdm.spec +++ b/packaging/libtdm.spec @@ -24,6 +24,21 @@ Requires: pkgconfig(libtbm) %description devel This supports frontend & backend library header and so +%package client +Summary: Client library for Tizen Display Manager +Group: Development/Libraries + +%description client +Tizen Display Manager Client Library + +%package client-devel +Summary: Client library for Tizen Display Manager +Group: Development/Libraries +Requires: libtdm-client = %{version} + +%description client-devel +Tizen Display Manager Client Library headers + %global TZ_SYS_RO_SHARE %{?TZ_SYS_RO_SHARE:%TZ_SYS_RO_SHARE}%{!?TZ_SYS_RO_SHARE:/usr/share} %prep @@ -42,23 +57,60 @@ mkdir -p %{buildroot}/%{TZ_SYS_RO_SHARE}/license cp -af COPYING %{buildroot}/%{TZ_SYS_RO_SHARE}/license/%{name} %make_install +%__mkdir_p %{buildroot}%{_unitdir} +install -m 644 service/tdm-socket.service %{buildroot}%{_unitdir} +install -m 644 service/tdm-socket.path %{buildroot}%{_unitdir} +%__mkdir_p %{buildroot}%{_unitdir_user} +install -m 644 service/tdm-socket-user.service %{buildroot}%{_unitdir_user} +install -m 644 service/tdm-socket-user.path %{buildroot}%{_unitdir_user} + %remove_docs + +%pre +%__mkdir_p %{_unitdir}/graphical.target.wants +ln -sf ../tdm-socket.path %{_unitdir}/graphical.target.wants/ +%__mkdir_p %{_unitdir_user}/default.target.wants +ln -sf ../tdm-socket-user.path %{_unitdir_user}/default.target.wants/ + %post -p /sbin/ldconfig %postun -p /sbin/ldconfig - +rm -f %{_unitdir}/graphical.target.wants/tdm-socket.path +rm -f %{_unitdir_user}/default.target.wants/tdm-socket-user.path %files %manifest %{name}.manifest %defattr(-,root,root,-) %{TZ_SYS_RO_SHARE}/license/%{name} %{_libdir}/libtdm.so.* +%{_unitdir}/tdm-socket.path +%{_unitdir}/tdm-socket.service +%{_unitdir_user}/tdm-socket-user.path +%{_unitdir_user}/tdm-socket-user.service %files devel %manifest %{name}.manifest %defattr(-,root,root,-) -%{_includedir}/* -%{_libdir}/pkgconfig/* +%{_includedir}/tdm.h +%{_includedir}/tdm_backend.h +%{_includedir}/tdm_helper.h +%{_includedir}/tdm_list.h +%{_includedir}/tdm_log.h +%{_includedir}/tdm_types.h +%{_libdir}/pkgconfig/libtdm.pc %{_libdir}/libtdm.so +%files client +%manifest %{name}.manifest +%defattr(-,root,root,-) +%{TZ_SYS_RO_SHARE}/license/%{name} +%{_libdir}/libtdm-client.so.* + +%files client-devel +%manifest %{name}.manifest +%defattr(-,root,root,-) +%{_includedir}/tdm_client.h +%{_libdir}/pkgconfig/libtdm-client.pc +%{_libdir}/libtdm-client.so + %changelog diff --git a/protocol/Makefile.am b/protocol/Makefile.am new file mode 100644 index 0000000..1329a0e --- /dev/null +++ b/protocol/Makefile.am @@ -0,0 +1,14 @@ +### protocol.[ch] +%-protocol.c : %.xml + $(wayland_scanner) code < $< > $@ +%-server-protocol.h : %.xml + $(wayland_scanner) server-header < $< > $@ +%-client-protocol.h : %.xml + $(wayland_scanner) client-header < $< > $@ + +BUILT_SOURCES = \ + tdm-server-protocol.h \ + tdm-client-protocol.h \ + tdm-protocol.c + +CLEANFILES = $(BUILT_SOURCES) diff --git a/protocol/tdm.xml b/protocol/tdm.xml new file mode 100644 index 0000000..f3389cb --- /dev/null +++ b/protocol/tdm.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/service/tdm-socket-user.path b/service/tdm-socket-user.path new file mode 100644 index 0000000..5ee772b --- /dev/null +++ b/service/tdm-socket-user.path @@ -0,0 +1,5 @@ +[Unit] +Description=Wait for tdm-socket + +[Path] +PathExists=/run/tdm-socket diff --git a/service/tdm-socket-user.service b/service/tdm-socket-user.service new file mode 100644 index 0000000..97d0f6f --- /dev/null +++ b/service/tdm-socket-user.service @@ -0,0 +1,6 @@ +[Unit] +Description=Creating a link file for user to access tdm-socket + +[Service] +Type=oneshot +ExecStart=/usr/bin/ln -sf /run/tdm-socket /run/user/%U/ diff --git a/service/tdm-socket.path b/service/tdm-socket.path new file mode 100644 index 0000000..5ee772b --- /dev/null +++ b/service/tdm-socket.path @@ -0,0 +1,5 @@ +[Unit] +Description=Wait for tdm-socket + +[Path] +PathExists=/run/tdm-socket diff --git a/service/tdm-socket.service b/service/tdm-socket.service new file mode 100644 index 0000000..caabbd8 --- /dev/null +++ b/service/tdm-socket.service @@ -0,0 +1,11 @@ +[Unit] +Description= tdm-socket setup service + +[Service] +Type=oneshot +ExecStart=/usr/bin/chmod g+w /run/tdm-socket +ExecStart=/usr/bin/chgrp display /run/tdm-socket +ExecStart=/usr/bin/chsmack -a User /run/tdm-socket + +[Install] +WantedBy=graphical.target diff --git a/src/Makefile.am b/src/Makefile.am index ee26b0b..245c2fa 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,16 +1,19 @@ -AM_CFLAGS = \ - $(WARN_CFLAGS) \ - $(TDM_CFLAGS) \ - -I$(top_srcdir)/include \ - -I$(top_srcdir)/src - libtdm_la_LTLIBRARIES = libtdm.la libtdm_ladir = $(libdir) libtdm_la_LDFLAGS = -version-number 1:0:0 -no-undefined libtdm_la_LIBADD = $(TDM_LIBS) -ldl -lpthread +libtdm_la_CFLAGS = \ + $(CFLAGS) \ + $(WARN_CFLAGS) \ + $(TDM_CFLAGS) \ + -I$(top_srcdir)/include \ + -I$(top_srcdir)/protocol \ + -I$(top_srcdir)/src libtdm_la_SOURCES = \ + $(top_srcdir)/protocol/tdm-protocol.c \ tdm_backend.c \ + tdm_server.c \ tdm_event_loop.c \ tdm_thread.c \ tdm_helper.c \ diff --git a/src/tdm.c b/src/tdm.c index 849efb8..ff7d85f 100644 --- a/src/tdm.c +++ b/src/tdm.c @@ -152,7 +152,12 @@ _tdm_display_destroy_private_output(tdm_private_output *private_output) free(m); } - LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_output->change_handler_list, link) { + LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_output->change_handler_list_main, link) { + LIST_DEL(&h->link); + free(h); + } + + LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_output->change_handler_list_sub, link) { LIST_DEL(&h->link); free(h); } @@ -299,10 +304,11 @@ _tdm_display_update_caps_layer(tdm_private_display *private_display, } static tdm_error -_tdm_display_update_caps_output(tdm_private_display *private_display, +_tdm_display_update_caps_output(tdm_private_display *private_display, int pipe, tdm_output *output_backend, tdm_caps_output *caps) { tdm_func_output *func_output = &private_display->func_output; + char temp[TDM_NAME_LEN]; int i; tdm_error ret; @@ -317,6 +323,10 @@ _tdm_display_update_caps_output(tdm_private_display *private_display, return TDM_ERROR_BAD_MODULE; } + /* FIXME: Use model for tdm client to distinguish amoung outputs */ + snprintf(temp, TDM_NAME_LEN, "%s-%d", caps->model, pipe); + snprintf(caps->model, TDM_NAME_LEN, "%s", temp); + TDM_DBG("output maker: %s", caps->maker); TDM_DBG("output model: %s", caps->model); TDM_DBG("output name: %s", caps->name); @@ -377,40 +387,6 @@ failed_update: return ret; } -INTERN void -tdm_output_cb_status(tdm_output *output_backend, tdm_output_conn_status status, - void *user_data) -{ - tdm_private_display *private_display; - tdm_private_output *private_output = user_data; - tdm_value value; - - TDM_RETURN_IF_FAIL(private_output); - - private_display = private_output->private_display; - - if (!tdm_thread_in_display_thread(private_display)) { - tdm_thread_cb_output_status output_status; - tdm_error ret; - - output_status.base.type = TDM_THREAD_CB_OUTPUT_STATUS; - output_status.base.length = sizeof output_status; - output_status.output_stamp = private_output->stamp; - output_status.status = status; - output_status.user_data = user_data; - - ret = tdm_thread_send_cb(private_display, &output_status.base); - TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE); - - return; - } - - value.u32 = status; - tdm_output_call_change_handler_internal(private_output, - TDM_OUTPUT_CHANGE_CONNECTION, - value); -} - static tdm_error _tdm_display_update_output(tdm_private_display *private_display, tdm_output *output_backend, int pipe) @@ -441,20 +417,18 @@ _tdm_display_update_output(tdm_private_display *private_display, LIST_INITHEAD(&private_output->capture_list); LIST_INITHEAD(&private_output->vblank_handler_list); LIST_INITHEAD(&private_output->commit_handler_list); - LIST_INITHEAD(&private_output->change_handler_list); - - if (func_output->output_set_status_handler) { - private_output->regist_change_cb = 1; - ret = func_output->output_set_status_handler(output_backend, - tdm_output_cb_status, - private_output); - if (ret != TDM_ERROR_NONE) - goto failed_update; - } + LIST_INITHEAD(&private_output->change_handler_list_main); + LIST_INITHEAD(&private_output->change_handler_list_sub); + + if (func_output->output_set_status_handler) + func_output->output_set_status_handler(private_output->output_backend, + tdm_output_cb_status, + private_output); + } else _tdm_display_destroy_caps_output(&private_output->caps); - ret = _tdm_display_update_caps_output(private_display, output_backend, + ret = _tdm_display_update_caps_output(private_display, pipe, output_backend, &private_output->caps); if (ret != TDM_ERROR_NONE) return ret; @@ -813,14 +787,23 @@ tdm_display_init(tdm_error *error) if (ret != TDM_ERROR_NONE) goto failed_event; - ret = tdm_thread_init(private_display); - if (ret != TDM_ERROR_NONE) - goto failed_thread; - ret = _tdm_display_load_module(private_display); if (ret != TDM_ERROR_NONE) goto failed_load; +#ifdef INIT_BUFMGR + int tdm_drm_fd = tdm_helper_get_fd("TDM_DRM_MASTER_FD"); + if (tdm_drm_fd >= 0) { + private_display->bufmgr = tbm_bufmgr_init(tdm_drm_fd); + if (!private_display->bufmgr) { + TDM_ERR("tbm_bufmgr_init failed"); + goto failed_update; + } else { + TDM_INFO("tbm_bufmgr_init successed"); + } + } +#endif + TDM_TRACE_BEGIN(Update_Display); ret = _tdm_display_update_internal(private_display, 0); TDM_TRACE_END(); @@ -843,8 +826,6 @@ tdm_display_init(tdm_error *error) failed_update: _tdm_display_unload_module(private_display); failed_load: - tdm_thread_deinit(private_display); -failed_thread: tdm_event_loop_deinit(private_display); failed_event: pthread_mutex_destroy(&private_display->lock); @@ -877,12 +858,16 @@ tdm_display_deinit(tdm_display *dpy) _pthread_mutex_lock(&private_display->lock); - tdm_thread_deinit(private_display); tdm_event_loop_deinit(private_display); _tdm_display_destroy_private_display(private_display); _tdm_display_unload_module(private_display); +#ifdef INIT_BUFMGR + if (private_display->bufmgr) + tbm_bufmgr_deinit(private_display->bufmgr); +#endif + tdm_helper_set_fd("TDM_DRM_MASTER_FD", -1); _pthread_mutex_unlock(&private_display->lock); diff --git a/src/tdm_capture.c b/src/tdm_capture.c index 56fe148..a4bdffd 100644 --- a/src/tdm_capture.c +++ b/src/tdm_capture.c @@ -85,7 +85,7 @@ tdm_capture_cb_done(tdm_capture *capture_backend, tbm_surface_h buffer, int lock_after_cb_done = 0; int ret; - if (!tdm_thread_in_display_thread(private_display)) { + if (private_capture->owner_tid != syscall(SYS_gettid)) { tdm_thread_cb_capture_done capture_done; tdm_error ret; @@ -95,12 +95,15 @@ tdm_capture_cb_done(tdm_capture *capture_backend, tbm_surface_h buffer, capture_done.buffer = buffer; capture_done.user_data = user_data; - ret = tdm_thread_send_cb(private_display, &capture_done.base); + ret = tdm_thread_send_cb(private_display->private_loop, &capture_done.base); TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE); return; } + if (private_capture->owner_tid != syscall(SYS_gettid)) + TDM_NEVER_GET_HERE(); + if (tdm_debug_buffer) TDM_INFO("capture(%p) done: %p", private_capture, buffer); @@ -195,6 +198,7 @@ tdm_capture_create_output_internal(tdm_private_output *private_output, private_capture->private_output = private_output; private_capture->private_layer = NULL; private_capture->capture_backend = capture_backend; + private_capture->owner_tid = syscall(SYS_gettid); LIST_INITHEAD(&private_capture->pending_buffer_list); LIST_INITHEAD(&private_capture->buffer_list); @@ -250,6 +254,7 @@ tdm_capture_create_layer_internal(tdm_private_layer *private_layer, private_capture->private_output = private_output; private_capture->private_layer = private_layer; private_capture->capture_backend = capture_backend; + private_capture->owner_tid = syscall(SYS_gettid); LIST_INITHEAD(&private_capture->pending_buffer_list); LIST_INITHEAD(&private_capture->buffer_list); diff --git a/src/tdm_display.c b/src/tdm_display.c index 76b4ba4..959cf7f 100644 --- a/src/tdm_display.c +++ b/src/tdm_display.c @@ -340,8 +340,11 @@ tdm_display_get_fd(tdm_display *dpy, int *fd) _pthread_mutex_lock(&private_display->lock); - if (private_display->private_thread) - *fd = tdm_thread_get_fd(private_display); + if (private_display->private_loop->private_thread) { + _pthread_mutex_unlock(&private_display->lock); + *fd = tdm_thread_get_fd(private_display->private_loop); + _pthread_mutex_lock(&private_display->lock); + } else *fd = tdm_event_loop_get_fd(private_display); @@ -382,8 +385,11 @@ tdm_display_handle_events(tdm_display *dpy) _pthread_mutex_lock(&private_display->lock); - if (private_display->private_thread) - ret = tdm_thread_handle_cb(private_display); + if (private_display->private_loop->private_thread) { + _pthread_mutex_unlock(&private_display->lock); + ret = tdm_thread_handle_cb(private_display->private_loop); + _pthread_mutex_lock(&private_display->lock); + } else ret = tdm_event_loop_dispatch(private_display); @@ -444,6 +450,61 @@ tdm_output_get_conn_status(tdm_output *output, tdm_output_conn_status *status) return ret; } +INTERN void +tdm_output_cb_status(tdm_output *output_backend, tdm_output_conn_status status, + void *user_data) +{ + tdm_private_display *private_display; + tdm_private_output *private_output = user_data; + tdm_value value; + int lock_after_cb_done = 0; + int ret; + + TDM_RETURN_IF_FAIL(private_output); + + private_display = private_output->private_display; + + if (!tdm_thread_in_display_thread(private_display->private_loop, + syscall(SYS_gettid))) { + tdm_thread_cb_output_status output_status; + tdm_error ret; + + output_status.base.type = TDM_THREAD_CB_OUTPUT_STATUS; + output_status.base.length = sizeof output_status; + output_status.output_stamp = private_output->stamp; + output_status.status = status; + output_status.user_data = user_data; + + value.u32 = status; + tdm_output_call_change_handler_internal(private_output, + &private_output->change_handler_list_sub, + TDM_OUTPUT_CHANGE_CONNECTION, + value); + + ret = tdm_thread_send_cb(private_display->private_loop, &output_status.base); + TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE); + + return; + } + + ret = pthread_mutex_trylock(&private_display->lock); + if (ret == 0) + _pthread_mutex_unlock(&private_display->lock); + else if (ret == EBUSY) { + _pthread_mutex_unlock(&private_display->lock); + lock_after_cb_done = 1; + } + + value.u32 = status; + tdm_output_call_change_handler_internal(private_output, + &private_output->change_handler_list_main, + TDM_OUTPUT_CHANGE_CONNECTION, + value); + + if (lock_after_cb_done) + _pthread_mutex_lock(&private_display->lock); +} + EXTERN tdm_error tdm_output_add_change_handler(tdm_output *output, tdm_output_change_handler func, @@ -469,10 +530,16 @@ tdm_output_add_change_handler(tdm_output *output, return TDM_ERROR_OUT_OF_MEMORY; } - LIST_ADD(&change_handler->link, &private_output->change_handler_list); change_handler->private_output = private_output; change_handler->func = func; change_handler->user_data = user_data; + change_handler->owner_tid = syscall(SYS_gettid); + + if (!tdm_thread_in_display_thread(private_display->private_loop, + change_handler->owner_tid)) + LIST_ADD(&change_handler->link, &private_output->change_handler_list_sub); + else + LIST_ADD(&change_handler->link, &private_output->change_handler_list_main); _pthread_mutex_unlock(&private_display->lock); @@ -496,7 +563,19 @@ tdm_output_remove_change_handler(tdm_output *output, _pthread_mutex_lock(&private_display->lock); - LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_output->change_handler_list, link) { + LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_output->change_handler_list_main, link) { + if (h->func != func || h->user_data != user_data) + continue; + + LIST_DEL(&h->link); + free(h); + + _pthread_mutex_unlock(&private_display->lock); + + return; + } + + LIST_FOR_EACH_ENTRY_SAFE(h, hh, &private_output->change_handler_list_sub, link) { if (h->func != func || h->user_data != user_data) continue; @@ -750,7 +829,7 @@ tdm_output_cb_vblank(tdm_output *output_backend, unsigned int sequence, private_display = vblank_handler->private_output->private_display; - if (!tdm_thread_in_display_thread(private_display)) { + if (vblank_handler->owner_tid != syscall(SYS_gettid)) { tdm_thread_cb_output_vblank output_vblank; tdm_error ret; @@ -762,17 +841,32 @@ tdm_output_cb_vblank(tdm_output *output_backend, unsigned int sequence, output_vblank.tv_usec = tv_usec; output_vblank.user_data = user_data; - ret = tdm_thread_send_cb(private_display, &output_vblank.base); + ret = tdm_thread_send_cb(private_display->private_loop, &output_vblank.base); TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE); return; } + if (vblank_handler->owner_tid != syscall(SYS_gettid)) + TDM_NEVER_GET_HERE(); + if (vblank_handler->func) { - _pthread_mutex_unlock(&private_display->lock); + int lock_after_cb_done = 0; + int ret; + + ret = pthread_mutex_trylock(&private_display->lock); + if (ret == 0) + _pthread_mutex_unlock(&private_display->lock); + else if (ret == EBUSY) { + _pthread_mutex_unlock(&private_display->lock); + lock_after_cb_done = 1; + } + vblank_handler->func(vblank_handler->private_output, sequence, tv_sec, tv_usec, vblank_handler->user_data); - _pthread_mutex_lock(&private_display->lock); + + if (lock_after_cb_done) + _pthread_mutex_lock(&private_display->lock); } LIST_DEL(&vblank_handler->link); @@ -787,13 +881,15 @@ tdm_output_cb_commit(tdm_output *output_backend, unsigned int sequence, tdm_private_display *private_display; tdm_private_output *private_output; tdm_private_layer *private_layer = NULL; + int lock_after_cb_done = 0; + int ret; TDM_RETURN_IF_FAIL(commit_handler); private_output = commit_handler->private_output; private_display = private_output->private_display; - if (!tdm_thread_in_display_thread(private_display)) { + if (commit_handler->owner_tid != syscall(SYS_gettid)) { tdm_thread_cb_output_commit output_commit; tdm_error ret; @@ -805,26 +901,30 @@ tdm_output_cb_commit(tdm_output *output_backend, unsigned int sequence, output_commit.tv_usec = tv_usec; output_commit.user_data = user_data; - ret = tdm_thread_send_cb(private_display, &output_commit.base); + ret = tdm_thread_send_cb(private_display->private_loop, &output_commit.base); TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE); return; } + ret = pthread_mutex_trylock(&private_display->lock); + if (ret == 0) + _pthread_mutex_unlock(&private_display->lock); + else if (ret == EBUSY) { + _pthread_mutex_unlock(&private_display->lock); + lock_after_cb_done = 1; + } + LIST_FOR_EACH_ENTRY(private_layer, &private_output->layer_list, link) { if (!private_layer->waiting_buffer) continue; if (private_layer->showing_buffer) { - _pthread_mutex_unlock(&private_display->lock); tdm_buffer_unref_backend(private_layer->showing_buffer); - _pthread_mutex_lock(&private_display->lock); if (private_layer->buffer_queue) { - _pthread_mutex_unlock(&private_display->lock); tbm_surface_queue_release(private_layer->buffer_queue, private_layer->showing_buffer); - _pthread_mutex_lock(&private_display->lock); } } @@ -838,12 +938,13 @@ tdm_output_cb_commit(tdm_output *output_backend, unsigned int sequence, } if (commit_handler->func) { - _pthread_mutex_unlock(&private_display->lock); commit_handler->func(private_output, sequence, tv_sec, tv_usec, commit_handler->user_data); - _pthread_mutex_lock(&private_display->lock); } + if (lock_after_cb_done) + _pthread_mutex_lock(&private_display->lock); + LIST_DEL(&commit_handler->link); free(commit_handler); } @@ -877,6 +978,7 @@ tdm_output_wait_vblank(tdm_output *output, int interval, int sync, vblank_handler->private_output = private_output; vblank_handler->func = func; vblank_handler->user_data = user_data; + vblank_handler->owner_tid = syscall(SYS_gettid); ret = func_output->output_wait_vblank(private_output->output_backend, interval, sync, vblank_handler); @@ -921,6 +1023,7 @@ _tdm_output_commit(tdm_output *output, int sync, tdm_output_commit_handler func, commit_handler->private_output = private_output; commit_handler->func = func; commit_handler->user_data = user_data; + commit_handler->owner_tid = syscall(SYS_gettid); ret = func_output->output_commit(private_output->output_backend, sync, commit_handler); @@ -1072,31 +1175,36 @@ tdm_output_create_capture(tdm_output *output, tdm_error *error) INTERN void tdm_output_call_change_handler_internal(tdm_private_output *private_output, + struct list_head *change_handler_list, tdm_output_change_type type, tdm_value value) { - tdm_private_change_handler *change_handler; tdm_private_display *private_display; + tdm_private_change_handler *change_handler; TDM_RETURN_IF_FAIL(private_output); private_display = private_output->private_display; + if (!tdm_thread_in_display_thread(private_display->private_loop, + syscall(SYS_gettid))) { + if (type & TDM_OUTPUT_CHANGE_CONNECTION) + TDM_INFO("output(%d) changed: %s (%d)", + private_output->pipe, status_str(value.u32), value.u32); + if (type & TDM_OUTPUT_CHANGE_DPMS) + TDM_INFO("output(%d) changed: dpms %s (%d)", + private_output->pipe, dpms_str(value.u32), value.u32); + } - if (type & TDM_OUTPUT_CHANGE_CONNECTION) - TDM_INFO("output(%d) changed: %s", - private_output->pipe, status_str(value.u32)); - if (type & TDM_OUTPUT_CHANGE_DPMS) - TDM_INFO("output(%d) changed: dpms %s", - private_output->pipe, dpms_str(value.u32)); + if (LIST_IS_EMPTY(change_handler_list)) + return; - _pthread_mutex_unlock(&private_display->lock); + LIST_FOR_EACH_ENTRY(change_handler, change_handler_list, link) { + if (change_handler->owner_tid != syscall(SYS_gettid)) + TDM_NEVER_GET_HERE(); - LIST_FOR_EACH_ENTRY(change_handler, &private_output->change_handler_list, link) { change_handler->func(private_output, type, value, change_handler->user_data); } - - _pthread_mutex_lock(&private_display->lock); } EXTERN tdm_error diff --git a/src/tdm_event_loop.c b/src/tdm_event_loop.c index e2beaf7..f653dbe 100644 --- a/src/tdm_event_loop.c +++ b/src/tdm_event_loop.c @@ -43,14 +43,6 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include -struct _tdm_private_loop { - struct wl_display *wl_display; - struct wl_event_loop *wl_loop; - - int backend_fd; - tdm_event_loop_source *backend_source; -}; - typedef struct _tdm_event_loop_source_base { struct wl_event_source *wl_source; @@ -78,6 +70,7 @@ _tdm_event_loop_main_fd_handler(int fd, tdm_event_loop_mask mask, void *user_dat tdm_private_display *private_display = (tdm_private_display*)user_data; tdm_private_loop *private_loop; tdm_func_display *func_display; + tdm_error ret; TDM_RETURN_VAL_IF_FAIL(private_display != NULL, TDM_ERROR_OPERATION_FAILED); TDM_RETURN_VAL_IF_FAIL(private_display->private_loop != NULL, TDM_ERROR_OPERATION_FAILED); @@ -91,13 +84,16 @@ _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; - return func_display->display_handle_events(private_display->bdata); + ret = func_display->display_handle_events(private_display->bdata); + + return ret; } INTERN tdm_error tdm_event_loop_init(tdm_private_display *private_display) { tdm_private_loop *private_loop; + tdm_error ret; if (private_display->private_loop) return TDM_ERROR_NONE; @@ -122,13 +118,31 @@ tdm_event_loop_init(tdm_private_display *private_display) TDM_ERR("no event loop"); wl_display_destroy(private_loop->wl_display); free(private_loop); - return TDM_ERROR_OUT_OF_MEMORY; + return TDM_ERROR_OPERATION_FAILED; } - TDM_INFO("event loop fd(%d)", wl_event_loop_get_fd(private_loop->wl_loop)); + ret = tdm_server_init(private_loop); + if (ret != TDM_ERROR_NONE) { + TDM_ERR("server init failed"); + wl_display_destroy(private_loop->wl_display); + free(private_loop); + return TDM_ERROR_OPERATION_FAILED; + } + private_loop->dpy = private_display; private_display->private_loop = private_loop; + ret = tdm_thread_init(private_loop); + if (ret != TDM_ERROR_NONE) { + TDM_ERR("thread init failed"); + tdm_server_deinit(private_loop); + wl_display_destroy(private_loop->wl_display); + free(private_loop); + return TDM_ERROR_OPERATION_FAILED; + } + + TDM_INFO("event loop fd(%d)", wl_event_loop_get_fd(private_loop->wl_loop)); + return TDM_ERROR_NONE; } @@ -138,6 +152,9 @@ tdm_event_loop_deinit(tdm_private_display *private_display) if (!private_display->private_loop) return; + tdm_thread_deinit(private_display->private_loop); + tdm_server_deinit(private_display->private_loop); + if (private_display->private_loop->backend_source) tdm_event_loop_source_remove(private_display->private_loop->backend_source); @@ -220,19 +237,15 @@ tdm_event_loop_dispatch(tdm_private_display *private_display) return TDM_ERROR_NONE; } -INTERN tdm_error -tdm_event_loop_add_socket(tdm_private_display *private_display, const char *name) + +INTERN void +tdm_event_loop_flush(tdm_private_display *private_display) { tdm_private_loop *private_loop = private_display->private_loop; - TDM_RETURN_VAL_IF_FAIL(private_loop->wl_display != NULL, TDM_ERROR_OPERATION_FAILED); - - if (wl_display_add_socket(private_loop->wl_display, name) < 0) { - TDM_ERR("add socket(\"%s\") failed", name); - return TDM_ERROR_OPERATION_FAILED; - } + TDM_RETURN_IF_FAIL(private_loop->wl_display != NULL); - return TDM_ERROR_NONE; + wl_display_flush_clients(private_loop->wl_display); } static int diff --git a/src/tdm_helper.c b/src/tdm_helper.c index 534bebc..e7d6154 100644 --- a/src/tdm_helper.c +++ b/src/tdm_helper.c @@ -16,6 +16,31 @@ static const char *dump_prefix[2] = {"png", "yuv"}; +INTERN int +tdm_helper_unlock_in_cb(tdm_private_display *private_display) +{ + int ret = pthread_mutex_trylock(&private_display->lock); + int need_lock = 0; + + if (ret == 0) + _pthread_mutex_unlock(&private_display->lock); + else if (ret == EBUSY) { + _pthread_mutex_unlock(&private_display->lock); + need_lock = 1; + } + + return need_lock; +} + +INTERN void +tdm_helper_lock_in_cb(tdm_private_display *private_display, int need_lock) +{ + if (!need_lock) + return; + + _pthread_mutex_lock(&private_display->lock); +} + INTERN unsigned long tdm_helper_get_time_in_millis(void) { diff --git a/src/tdm_macro.h b/src/tdm_macro.h new file mode 100644 index 0000000..a547c0a --- /dev/null +++ b/src/tdm_macro.h @@ -0,0 +1,125 @@ +/************************************************************************** + +libtdm + +Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved. + +Contact: Eunchul Kim , + JinYoung Jeon , + Taeheon Kim , + YoungJun Cho , + SooChan Lim , + Boram Park + +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. + +**************************************************************************/ + +#ifndef _TDM_MACRO_H_ +#define _TDM_MACRO_H_ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#undef EXTERN +#undef DEPRECATED +#undef INTERN + +#if defined(__GNUC__) && __GNUC__ >= 4 +#define EXTERN __attribute__ ((visibility("default"))) +#else +#define EXTERN +#endif + +#if defined(__GNUC__) && __GNUC__ >= 4 +#define INTERN __attribute__ ((visibility("hidden"))) +#else +#define INTERN +#endif + +#if defined(__GNUC__) && __GNUC__ >= 4 +#define DEPRECATED __attribute__ ((deprecated)) +#else +#define DEPRECATED +#endif + +/* check condition */ +#define TDM_RETURN_IF_FAIL(cond) {\ + if (!(cond)) {\ + TDM_ERR ("'%s' failed", #cond);\ + return;\ + }\ +} +#define TDM_RETURN_VAL_IF_FAIL(cond, val) {\ + if (!(cond)) {\ + TDM_ERR ("'%s' failed", #cond);\ + return val;\ + }\ +} +#define TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(cond, error_v, val) {\ + if (!(cond)) {\ + TDM_ERR ("'%s' failed", #cond);\ + ret = error_v;\ + if (error) *error = ret;\ + return val;\ + }\ +} + +#define TDM_WARNING_IF_FAIL(cond) {\ + if (!(cond))\ + TDM_ERR ("'%s' failed", #cond);\ +} +#define TDM_GOTO_IF_FAIL(cond, dst) {\ + if (!(cond)) {\ + TDM_ERR ("'%s' failed", #cond);\ + goto dst;\ + }\ +} + +#define TDM_NEVER_GET_HERE() TDM_ERR("** NEVER GET HERE **") + +#define TDM_SNPRINTF(p, len, fmt, ARG...) \ + do { \ + if (p && len && *len > 0) \ + { \ + int s = snprintf(p, *len, fmt, ##ARG); \ + p += s; \ + *len -= s; \ + } \ + } while (0) + +#define C(b,m) (((b) >> (m)) & 0xFF) +#define B(c,s) ((((unsigned int)(c)) & 0xff) << (s)) +#define FOURCC(a,b,c,d) (B(d,24) | B(c,16) | B(b,8) | B(a,0)) +#define FOURCC_STR(id) C(id,0), C(id,8), C(id,16), C(id,24) +#define FOURCC_ID(str) FOURCC(((char*)str)[0],((char*)str)[1],((char*)str)[2],((char*)str)[3]) + +#ifdef __cplusplus +} +#endif + +#endif /* _TDM_MACRO_H_ */ diff --git a/src/tdm_pp.c b/src/tdm_pp.c index f5345ad..603911e 100644 --- a/src/tdm_pp.c +++ b/src/tdm_pp.c @@ -99,7 +99,7 @@ tdm_pp_cb_done(tdm_pp *pp_backend, tbm_surface_h src, tbm_surface_h dst, int lock_after_cb_done = 0; int ret; - if (!tdm_thread_in_display_thread(private_display)) { + if (private_pp->owner_tid != syscall(SYS_gettid)) { tdm_thread_cb_pp_done pp_done; tdm_error ret; @@ -110,12 +110,15 @@ tdm_pp_cb_done(tdm_pp *pp_backend, tbm_surface_h src, tbm_surface_h dst, pp_done.dst = dst; pp_done.user_data = user_data; - ret = tdm_thread_send_cb(private_display, &pp_done.base); + ret = tdm_thread_send_cb(private_display->private_loop, &pp_done.base); TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE); return; } + if (private_pp->owner_tid != syscall(SYS_gettid)) + TDM_NEVER_GET_HERE(); + if (tdm_debug_buffer) TDM_INFO("pp(%p) done: src(%p) dst(%p)", private_pp, src, dst); @@ -212,6 +215,7 @@ tdm_pp_create_internal(tdm_private_display *private_display, tdm_error *error) LIST_ADD(&private_pp->link, &private_display->pp_list); private_pp->private_display = private_display; private_pp->pp_backend = pp_backend; + private_pp->owner_tid = syscall(SYS_gettid); LIST_INITHEAD(&private_pp->src_pending_buffer_list); LIST_INITHEAD(&private_pp->dst_pending_buffer_list); diff --git a/src/tdm_private.h b/src/tdm_private.h index 62b59c7..93d1e94 100644 --- a/src/tdm_private.h +++ b/src/tdm_private.h @@ -58,11 +58,14 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "tdm_backend.h" #include "tdm_log.h" #include "tdm_list.h" +#include "tdm_macro.h" #ifdef __cplusplus extern "C" { #endif +//#define INIT_BUFMGR + /** * @file tdm_private.h * @brief The private header file for a frontend library @@ -72,61 +75,6 @@ extern int tdm_debug_buffer; extern int tdm_debug_mutex; extern int tdm_debug_thread; -#undef EXTERN -#undef DEPRECATED -#undef INTERN - -#if defined(__GNUC__) && __GNUC__ >= 4 -#define EXTERN __attribute__ ((visibility("default"))) -#else -#define EXTERN -#endif - -#if defined(__GNUC__) && __GNUC__ >= 4 -#define INTERN __attribute__ ((visibility("hidden"))) -#else -#define INTERN -#endif - -#if defined(__GNUC__) && __GNUC__ >= 4 -#define DEPRECATED __attribute__ ((deprecated)) -#else -#define DEPRECATED -#endif - -/* check condition */ -#define TDM_RETURN_IF_FAIL(cond) {\ - if (!(cond)) {\ - TDM_ERR ("'%s' failed", #cond);\ - return;\ - }\ -} -#define TDM_RETURN_VAL_IF_FAIL(cond, val) {\ - if (!(cond)) {\ - TDM_ERR ("'%s' failed", #cond);\ - return val;\ - }\ -} -#define TDM_RETURN_VAL_IF_FAIL_WITH_ERROR(cond, error_v, val) {\ - if (!(cond)) {\ - TDM_ERR ("'%s' failed", #cond);\ - ret = error_v;\ - if (error) *error = ret;\ - return val;\ - }\ -} - -#define TDM_WARNING_IF_FAIL(cond) {\ - if (!(cond))\ - TDM_ERR ("'%s' failed", #cond);\ -} -#define TDM_GOTO_IF_FAIL(cond, dst) {\ - if (!(cond)) {\ - TDM_ERR ("'%s' failed", #cond);\ - goto dst;\ - }\ -} - #ifdef HAVE_TTRACE #include #define TDM_TRACE_BEGIN(NAME) traceBegin(TTRACE_TAG_GRAPHICS, "TDM:"#NAME) @@ -136,24 +84,6 @@ extern int tdm_debug_thread; #define TDM_TRACE_END() #endif -#define TDM_NEVER_GET_HERE() TDM_ERR("** NEVER GET HERE **") - -#define TDM_SNPRINTF(p, len, fmt, ARG...) \ - do { \ - if (p && len && *len > 0) \ - { \ - int s = snprintf(p, *len, fmt, ##ARG); \ - p += s; \ - *len -= s; \ - } \ - } while (0) - -#define C(b,m) (((b) >> (m)) & 0xFF) -#define B(c,s) ((((unsigned int)(c)) & 0xff) << (s)) -#define FOURCC(a,b,c,d) (B(d,24) | B(c,16) | B(b,8) | B(a,0)) -#define FOURCC_STR(id) C(id,0), C(id,8), C(id,16), C(id,24) -#define FOURCC_ID(str) FOURCC(((char*)str)[0],((char*)str)[1],((char*)str)[2],((char*)str)[3]) - typedef enum { TDM_CAPTURE_TARGET_OUTPUT, TDM_CAPTURE_TARGET_LAYER, @@ -165,6 +95,7 @@ typedef struct _tdm_private_layer tdm_private_layer; typedef struct _tdm_private_pp tdm_private_pp; 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_vblank_handler tdm_private_vblank_handler; typedef struct _tdm_private_commit_handler tdm_private_commit_handler; @@ -179,6 +110,10 @@ struct _tdm_private_display { tdm_backend_module *module_data; tdm_backend_data *bdata; +#ifdef INIT_BUFMGR + tbm_bufmgr bufmgr; +#endif + /* backend function */ tdm_display_capability capabilities; tdm_func_display func_display; @@ -201,9 +136,6 @@ struct _tdm_private_display { /* for event handling */ tdm_private_loop *private_loop; - - /* for own event thread */ - tdm_private_thread *private_thread; }; struct _tdm_private_output { @@ -226,7 +158,10 @@ struct _tdm_private_output { struct list_head capture_list; struct list_head vblank_handler_list; struct list_head commit_handler_list; - struct list_head change_handler_list; + + /* seperate list for multi-thread*/ + struct list_head change_handler_list_main; + struct list_head change_handler_list_sub; void **layers_ptr; }; @@ -263,6 +198,8 @@ struct _tdm_private_pp { struct list_head dst_pending_buffer_list; struct list_head src_buffer_list; struct list_head dst_buffer_list; + + pid_t owner_tid; }; struct _tdm_private_capture { @@ -281,6 +218,40 @@ struct _tdm_private_capture { struct list_head pending_buffer_list; struct list_head buffer_list; + + pid_t owner_tid; +}; + +/* CAUTION: + * Note that this structure is not thread-safe. If there is no TDM thread, all + * TDM resources are protected by private_display's lock. If there is a TDM + * thread, this struct will be used only in a TDM thread. So, we don't need to + * protect this structure. + */ +struct _tdm_private_loop { + /* TDM uses wl_event_loop to handle various event sources including the TDM + * backend's fd. + */ + struct wl_display *wl_display; + struct wl_event_loop *wl_loop; + + int backend_fd; + tdm_event_loop_source *backend_source; + + /* In event loop, all resources are accessed by this dpy. + * CAUTION: + * - DO NOT include other private structure in this structure because this + * struct is not thread-safe. + */ + tdm_display *dpy; + + /* for handling TDM client requests */ + tdm_private_server *private_server; + + /* To have a TDM event thread. If TDM_THREAD enviroment variable is not set + * private_thread is NULL. + */ + tdm_private_thread *private_thread; }; struct _tdm_private_vblank_handler { @@ -289,6 +260,8 @@ struct _tdm_private_vblank_handler { tdm_private_output *private_output; tdm_output_vblank_handler func; void *user_data; + + pid_t owner_tid; }; struct _tdm_private_commit_handler { @@ -297,6 +270,8 @@ struct _tdm_private_commit_handler { tdm_private_output *private_output; tdm_output_commit_handler func; void *user_data; + + pid_t owner_tid; }; struct _tdm_private_change_handler { @@ -305,6 +280,8 @@ struct _tdm_private_change_handler { tdm_private_output *private_output; tdm_output_change_handler func; void *user_data; + + pid_t owner_tid; }; typedef struct _tdm_buffer_info { @@ -346,6 +323,7 @@ tdm_capture_cb_done(tdm_capture *capture_backend, tbm_surface_h buffer, void tdm_output_call_change_handler_internal(tdm_private_output *private_output, + struct list_head *change_handler_list, tdm_output_change_type type, tdm_value value); @@ -382,9 +360,8 @@ int tdm_event_loop_get_fd(tdm_private_display *private_display); tdm_error tdm_event_loop_dispatch(tdm_private_display *private_display); -tdm_error -tdm_event_loop_add_socket(tdm_private_display *private_display, const char *name); - +void +tdm_event_loop_flush(tdm_private_display *private_display); typedef enum { TDM_THREAD_CB_NONE, @@ -439,20 +416,29 @@ struct _tdm_thread_cb_capture_done { }; tdm_error -tdm_thread_init(tdm_private_display *private_display); +tdm_thread_init(tdm_private_loop *private_loop); void -tdm_thread_deinit(tdm_private_display *private_display); +tdm_thread_deinit(tdm_private_loop *private_loop); int -tdm_thread_get_fd(tdm_private_display *private_display); +tdm_thread_get_fd(tdm_private_loop *private_loop); tdm_error -tdm_thread_send_cb(tdm_private_display *private_display, tdm_thread_cb_base *base); +tdm_thread_send_cb(tdm_private_loop *private_loop, tdm_thread_cb_base *base); tdm_error -tdm_thread_handle_cb(tdm_private_display *private_display); +tdm_thread_handle_cb(tdm_private_loop *private_loop); int -tdm_thread_in_display_thread(tdm_private_display *private_display); +tdm_thread_in_display_thread(tdm_private_loop *private_loop, pid_t tid); + +tdm_error +tdm_server_init(tdm_private_loop *private_loop); +void +tdm_server_deinit(tdm_private_loop *private_loop); unsigned long tdm_helper_get_time_in_millis(void); +int +tdm_helper_unlock_in_cb(tdm_private_display *private_display); +void +tdm_helper_lock_in_cb(tdm_private_display *private_display, int need_lock); #define _pthread_mutex_lock(l) \ do {if (tdm_debug_mutex) TDM_INFO("mutex lock"); pthread_mutex_lock(l);} while (0) diff --git a/src/tdm_server.c b/src/tdm_server.c new file mode 100644 index 0000000..a8d0498 --- /dev/null +++ b/src/tdm_server.c @@ -0,0 +1,246 @@ +/************************************************************************** + +libtdm + +Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved. + +Contact: Eunchul Kim , + JinYoung Jeon , + Taeheon Kim , + YoungJun Cho , + SooChan Lim , + Boram Park + +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. + +**************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "tdm.h" +#include "tdm_private.h" +#include "tdm_list.h" +#include "tdm-server-protocol.h" + +/* CAUTION: + * - tdm server doesn't care about multi-thread. + * - DO NOT use the TDM internal functions here. + */ + +struct _tdm_private_server { + struct list_head vblank_list; +}; + +typedef struct _tdm_server_vblank_info { + struct list_head link; + struct wl_resource *resource; + tdm_private_server *private_server; +} tdm_server_vblank_info; + +static void +_tdm_server_cb_output_vblank(tdm_output *output, unsigned int sequence, + unsigned int tv_sec, unsigned int tv_usec, + void *user_data) +{ + tdm_server_vblank_info *vblank_info = (tdm_server_vblank_info*)user_data; + tdm_server_vblank_info *found; + + LIST_FIND_ITEM(vblank_info, &vblank_info->private_server->vblank_list, + tdm_server_vblank_info, link, found); + if (!found) { + TDM_DBG("vblank_info(%p) is destroyed", vblank_info); + return; + } + + TDM_DBG("wl_tdm_vblank@%d done", wl_resource_get_id(vblank_info->resource)); + + wl_tdm_vblank_send_done(vblank_info->resource, sequence, tv_sec, tv_usec); + wl_resource_destroy(vblank_info->resource); +} + +static void +destroy_vblank_callback(struct wl_resource *resource) +{ + tdm_server_vblank_info *vblank_info = wl_resource_get_user_data(resource); + LIST_DEL(&vblank_info->link); + free(vblank_info); +} + +static void +_tdm_server_cb_wait_vblank(struct wl_client *client, + struct wl_resource *resource, + uint32_t id, const char *name, int32_t interval) +{ + tdm_private_loop *private_loop = wl_resource_get_user_data(resource); + tdm_private_server *private_server = private_loop->private_server; + tdm_server_vblank_info *vblank_info; + struct wl_resource *vblank_resource; + tdm_output *found = NULL; + int count = 0, i; + tdm_error ret; + + TDM_DBG("The tdm client requests vblank"); + + tdm_display_get_output_count(private_loop->dpy, &count); + + for (i = 0; i < count; i++) { + tdm_output *output= tdm_display_get_output(private_loop->dpy, i, NULL); + tdm_output_conn_status status; + const char *model = NULL; + + ret = tdm_output_get_conn_status(output, &status); + if (ret || status == TDM_OUTPUT_CONN_STATUS_DISCONNECTED) + continue; + + ret = tdm_output_get_model_info(output, NULL, &model, NULL); + if (ret || !model) + continue; + + if (strncmp(model, name, TDM_NAME_LEN)) + continue; + + found = output; + break; + } + + if (!found) { + wl_resource_post_error(resource, WL_TDM_ERROR_INVALID_NAME, + "There is no '%s' output", name); + TDM_ERR("There is no '%s' output", name); + return; + } + + vblank_resource = + wl_resource_create(client, &wl_tdm_vblank_interface, + wl_resource_get_version(resource), id); + if (!vblank_resource) { + wl_resource_post_no_memory(resource); + TDM_ERR("wl_resource_create failed"); + return; + } + + vblank_info = calloc(1, sizeof *vblank_info); + if (!vblank_info) { + wl_resource_destroy(vblank_resource); + wl_resource_post_no_memory(resource); + TDM_ERR("alloc failed"); + return; + } + + TDM_DBG("wl_tdm_vblank@%d output(%s) interval(%d)", id, name, interval); + + ret = tdm_output_wait_vblank(found, interval, 0, + _tdm_server_cb_output_vblank, vblank_info); + if (ret != TDM_ERROR_NONE) { + wl_resource_destroy(vblank_resource); + free(vblank_info); + wl_resource_post_error(resource, WL_TDM_ERROR_OPERATION_FAILED, + "couldn't wait vblank for %s", name); + TDM_ERR("couldn't wait vblank for %s", name); + return; + } + + vblank_info->resource = vblank_resource; + vblank_info->private_server = private_server; + + wl_resource_set_implementation(vblank_resource, NULL, vblank_info, + destroy_vblank_callback); + + LIST_ADDTAIL(&vblank_info->link, &private_server->vblank_list); +} + +static const struct wl_tdm_interface tdm_implementation = { + _tdm_server_cb_wait_vblank, +}; + +static void +_tdm_server_bind(struct wl_client *client, void *data, + uint32_t version, uint32_t id) +{ + struct wl_resource *resource; + + resource = wl_resource_create(client, &wl_tdm_interface, version, id); + if (!resource) { + wl_client_post_no_memory(client); + return; + } + + TDM_DBG("tdm server binding"); + + wl_resource_set_implementation(resource, &tdm_implementation, data, NULL); +} + +INTERN tdm_error +tdm_server_init(tdm_private_loop *private_loop) +{ + tdm_private_server *private_server; + + if (private_loop->private_server) + return TDM_ERROR_NONE; + + TDM_RETURN_VAL_IF_FAIL(private_loop, TDM_ERROR_OPERATION_FAILED); + TDM_RETURN_VAL_IF_FAIL(private_loop->wl_display, TDM_ERROR_OPERATION_FAILED); + + if(wl_display_add_socket(private_loop->wl_display, "tdm-socket")) { + TDM_ERR("createing a tdm-socket failed"); + return TDM_ERROR_OPERATION_FAILED; + } + + private_server = calloc(1, sizeof *private_server); + if (!private_server) { + TDM_ERR("alloc failed"); + return TDM_ERROR_OUT_OF_MEMORY; + } + + LIST_INITHEAD(&private_server->vblank_list); + + if (!wl_global_create(private_loop->wl_display, &wl_tdm_interface, 1, + private_loop, _tdm_server_bind)) { + TDM_ERR("creating a global resource failed"); + free(private_server); + return TDM_ERROR_OUT_OF_MEMORY; + } + + private_loop->private_server = private_server; + + return TDM_ERROR_NONE; +} + +INTERN void +tdm_server_deinit(tdm_private_loop *private_loop) +{ + tdm_server_vblank_info *v = NULL, *vv = NULL; + tdm_private_server *private_server; + + if (!private_loop->private_server) + return; + + private_server = private_loop->private_server; + + LIST_FOR_EACH_ENTRY_SAFE(v, vv, &private_server->vblank_list, link) { + wl_resource_destroy(v->resource); + } + + free(private_server); + private_loop->private_server = NULL; +} diff --git a/src/tdm_thread.c b/src/tdm_thread.c index 5e0d8c7..ec7ce92 100644 --- a/src/tdm_thread.c +++ b/src/tdm_thread.c @@ -44,8 +44,9 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "tdm_list.h" struct _tdm_private_thread { + tdm_private_loop *private_loop; + pthread_t event_thread; - pthread_mutex_t event_mutex; pid_t display_tid; pid_t thread_tid; @@ -57,21 +58,22 @@ struct _tdm_private_thread { static void* _tdm_thread_main(void *data) { - tdm_private_display *private_display = (tdm_private_display*)data; - tdm_private_thread *private_thread; + tdm_private_thread *private_thread = (tdm_private_thread*)data; + tdm_private_loop *private_loop = private_thread->private_loop; int fd; struct pollfd fds; int ret; - _pthread_mutex_lock(&private_display->lock); - - private_thread = private_display->private_thread; + /* Not lock/unlock for the private_thread and private_loop structure + * because they won't be destroyed as long as tdm thread is running. + * When they're destroyed, we have already exit the tdm thread. + */ private_thread->thread_tid = syscall(SYS_gettid); TDM_INFO("display_tid:%d, thread_tid: %d", private_thread->display_tid, private_thread->thread_tid); - fd = tdm_event_loop_get_fd(private_display); + fd = tdm_event_loop_get_fd(private_loop->dpy); if (fd < 0) { TDM_ERR("couldn't get fd"); goto exit_thread; @@ -81,9 +83,10 @@ _tdm_thread_main(void *data) fds.fd = fd; fds.revents = 0; - _pthread_mutex_unlock(&private_display->lock); - while (1) { + if (tdm_debug_thread) + TDM_INFO("server flush"); + tdm_event_loop_flush(private_loop->dpy); if (tdm_debug_thread) TDM_INFO("fd(%d) polling in", fd); @@ -105,25 +108,28 @@ _tdm_thread_main(void *data) if (tdm_debug_thread) TDM_INFO("thread got events"); - _pthread_mutex_lock(&private_display->lock); - - if (tdm_event_loop_dispatch(private_display) < 0) + if (tdm_event_loop_dispatch(private_loop->dpy) < 0) TDM_ERR("dispatch error"); - - _pthread_mutex_unlock(&private_display->lock); } exit_thread: pthread_exit(NULL); } +/* NOTE: tdm thread doesn't care about multi-thread. */ INTERN tdm_error -tdm_thread_init(tdm_private_display *private_display) +tdm_thread_init(tdm_private_loop *private_loop) { + tdm_private_display *private_display; tdm_private_thread *private_thread; const char *thread; - if (private_display->private_thread) + TDM_RETURN_VAL_IF_FAIL(private_loop->dpy, TDM_ERROR_OPERATION_FAILED); + + private_display = private_loop->dpy; + TDM_RETURN_VAL_IF_FAIL(private_display->private_loop, TDM_ERROR_OPERATION_FAILED); + + if (private_loop->private_thread) return TDM_ERROR_NONE; /* enable as default */ @@ -145,13 +151,13 @@ tdm_thread_init(tdm_private_display *private_display) return TDM_ERROR_OPERATION_FAILED; } + private_thread->private_loop = private_loop; + private_loop->private_thread = private_thread; + private_thread->display_tid = syscall(SYS_gettid); - pthread_mutex_init(&private_thread->event_mutex, NULL); pthread_create(&private_thread->event_thread, NULL, _tdm_thread_main, - private_display); - - private_display->private_thread = private_thread; + private_thread); TDM_INFO("using a TDM event thread. pipe(%d,%d)", private_thread->pipe[0], private_thread->pipe[1]); @@ -160,50 +166,49 @@ tdm_thread_init(tdm_private_display *private_display) } INTERN void -tdm_thread_deinit(tdm_private_display *private_display) +tdm_thread_deinit(tdm_private_loop *private_loop) { - if (!private_display->private_thread) + if (!private_loop->private_thread) return; - pthread_cancel(private_display->private_thread->event_thread); - pthread_join(private_display->private_thread->event_thread, NULL); - pthread_mutex_destroy(&private_display->private_thread->event_mutex); + pthread_cancel(private_loop->private_thread->event_thread); + pthread_join(private_loop->private_thread->event_thread, NULL); - if (private_display->private_thread->pipe[0] >= 0) - close(private_display->private_thread->pipe[0]); - if (private_display->private_thread->pipe[1] >= 0) - close(private_display->private_thread->pipe[1]); + if (private_loop->private_thread->pipe[0] >= 0) + close(private_loop->private_thread->pipe[0]); + if (private_loop->private_thread->pipe[1] >= 0) + close(private_loop->private_thread->pipe[1]); - free(private_display->private_thread); - private_display->private_thread = NULL; + free(private_loop->private_thread); + private_loop->private_thread = NULL; TDM_INFO("Finish a TDM event thread"); } INTERN int -tdm_thread_get_fd(tdm_private_display *private_display) +tdm_thread_get_fd(tdm_private_loop *private_loop) { tdm_private_thread *private_thread; - TDM_RETURN_VAL_IF_FAIL(private_display, -1); - TDM_RETURN_VAL_IF_FAIL(private_display->private_thread, -1); + TDM_RETURN_VAL_IF_FAIL(private_loop, -1); + TDM_RETURN_VAL_IF_FAIL(private_loop->private_thread, -1); - private_thread = private_display->private_thread; + private_thread = private_loop->private_thread; return private_thread->pipe[0]; } INTERN tdm_error -tdm_thread_send_cb(tdm_private_display *private_display, tdm_thread_cb_base *base) +tdm_thread_send_cb(tdm_private_loop *private_loop, tdm_thread_cb_base *base) { tdm_private_thread *private_thread; ssize_t len; TDM_RETURN_VAL_IF_FAIL(base, TDM_ERROR_INVALID_PARAMETER); - TDM_RETURN_VAL_IF_FAIL(private_display, TDM_ERROR_INVALID_PARAMETER); - TDM_RETURN_VAL_IF_FAIL(private_display->private_thread, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(private_loop, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(private_loop->private_thread, TDM_ERROR_INVALID_PARAMETER); - private_thread = private_display->private_thread; + private_thread = private_loop->private_thread; if (tdm_debug_thread) TDM_INFO("fd(%d) type(%d), length(%d)", @@ -219,17 +224,17 @@ tdm_thread_send_cb(tdm_private_display *private_display, tdm_thread_cb_base *bas } INTERN tdm_error -tdm_thread_handle_cb(tdm_private_display *private_display) +tdm_thread_handle_cb(tdm_private_loop *private_loop) { tdm_private_thread *private_thread; tdm_thread_cb_base *base; char buffer[1024]; int len, i; - TDM_RETURN_VAL_IF_FAIL(private_display, TDM_ERROR_INVALID_PARAMETER); - TDM_RETURN_VAL_IF_FAIL(private_display->private_thread, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(private_loop, TDM_ERROR_INVALID_PARAMETER); + TDM_RETURN_VAL_IF_FAIL(private_loop->private_thread, TDM_ERROR_INVALID_PARAMETER); - private_thread = private_display->private_thread; + private_thread = private_loop->private_thread; len = read(private_thread->pipe[0], buffer, sizeof buffer); @@ -254,7 +259,7 @@ tdm_thread_handle_cb(tdm_private_display *private_display) { tdm_thread_cb_output_commit *output_commit = (tdm_thread_cb_output_commit*)base; tdm_output *output_backend = - tdm_display_find_output_stamp(private_display, output_commit->output_stamp); + tdm_display_find_output_stamp(private_loop->dpy, output_commit->output_stamp); if (!output_backend) { TDM_WRN("no output(%ld)", output_commit->output_stamp); break; @@ -268,7 +273,7 @@ tdm_thread_handle_cb(tdm_private_display *private_display) { tdm_thread_cb_output_vblank *output_vblank = (tdm_thread_cb_output_vblank*)base; tdm_output *output_backend = - tdm_display_find_output_stamp(private_display, output_vblank->output_stamp); + tdm_display_find_output_stamp(private_loop->dpy, output_vblank->output_stamp); if (!output_backend) { TDM_WRN("no output(%ld)", output_vblank->output_stamp); break; @@ -282,7 +287,7 @@ tdm_thread_handle_cb(tdm_private_display *private_display) { tdm_thread_cb_output_status *output_status = (tdm_thread_cb_output_status*)base; tdm_output *output_backend = - tdm_display_find_output_stamp(private_display, output_status->output_stamp); + tdm_display_find_output_stamp(private_loop->dpy, output_status->output_stamp); if (!output_backend) { TDM_WRN("no output(%ld)", output_status->output_stamp); break; @@ -295,7 +300,7 @@ tdm_thread_handle_cb(tdm_private_display *private_display) { tdm_thread_cb_pp_done *pp_done = (tdm_thread_cb_pp_done*)base; tdm_pp *pp_backend = - tdm_pp_find_stamp(private_display, pp_done->pp_stamp); + tdm_pp_find_stamp(private_loop->dpy, pp_done->pp_stamp); if (!pp_backend) { TDM_WRN("no pp(%ld)", pp_done->pp_stamp); break; @@ -307,7 +312,7 @@ tdm_thread_handle_cb(tdm_private_display *private_display) { tdm_thread_cb_capture_done *capture_done = (tdm_thread_cb_capture_done*)base; tdm_capture *capture_backend = - tdm_capture_find_stamp(private_display, capture_done->capture_stamp); + tdm_capture_find_stamp(private_loop->dpy, capture_done->capture_stamp); if (!capture_backend) { TDM_WRN("no capture(%ld)", capture_done->capture_stamp); break; @@ -321,20 +326,22 @@ tdm_thread_handle_cb(tdm_private_display *private_display) i += base->length; } + tdm_event_loop_flush(private_loop->dpy); + return TDM_ERROR_NONE; } INTERN int -tdm_thread_in_display_thread(tdm_private_display *private_display) +tdm_thread_in_display_thread(tdm_private_loop *private_loop, pid_t tid) { tdm_private_thread *private_thread; - TDM_RETURN_VAL_IF_FAIL(private_display, 1); + TDM_RETURN_VAL_IF_FAIL(private_loop, 1); - if (!private_display->private_thread) + if (!private_loop->private_thread) return 1; - private_thread = private_display->private_thread; + private_thread = private_loop->private_thread; - return (private_thread->display_tid == syscall(SYS_gettid)) ? 1 : 0; + return (private_thread->display_tid == tid) ? 1 : 0; } -- 2.7.4 From 97937cffcaa22abe11f852c69a76ab3f5b0ec9c8 Mon Sep 17 00:00:00 2001 From: Boram Park Date: Mon, 4 Apr 2016 19:22:29 +0900 Subject: [PATCH 02/16] add tdm-client to test tdm client API Change-Id: Ifa6219f85b35d1d9d119211c276062974967986d --- Makefile.am | 2 +- configure.ac | 3 +- packaging/libtdm.spec | 12 +++++ tools/Makefile.am | 14 ++++++ tools/tdm_test_client.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 145 insertions(+), 2 deletions(-) create mode 100644 tools/Makefile.am create mode 100644 tools/tdm_test_client.c diff --git a/Makefile.am b/Makefile.am index e8aa5d7..393ba5c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = . include protocol client src +SUBDIRS = . include protocol client src tools pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libtdm.pc diff --git a/configure.ac b/configure.ac index db21b7e..84bdb79 100644 --- a/configure.ac +++ b/configure.ac @@ -64,7 +64,8 @@ AC_OUTPUT([ protocol/Makefile client/libtdm-client.pc client/Makefile - src/Makefile]) + src/Makefile + tools/Makefile]) echo "" echo "$PACKAGE_STRING will be compiled with:" diff --git a/packaging/libtdm.spec b/packaging/libtdm.spec index 3f6e0b1..37f86c1 100644 --- a/packaging/libtdm.spec +++ b/packaging/libtdm.spec @@ -41,6 +41,14 @@ Tizen Display Manager Client Library headers %global TZ_SYS_RO_SHARE %{?TZ_SYS_RO_SHARE:%TZ_SYS_RO_SHARE}%{!?TZ_SYS_RO_SHARE:/usr/share} +%package tools +Summary: Tools for libtdm +Group: Development/Utilities +#Provides: libtdm = %version + +%description tools +This contains libtdm tools for fundamental testing + %prep %setup -q cp %{SOURCE1001} . @@ -113,4 +121,8 @@ rm -f %{_unitdir_user}/default.target.wants/tdm-socket-user.path %{_libdir}/pkgconfig/libtdm-client.pc %{_libdir}/libtdm-client.so +%files tools +%manifest %{name}.manifest +%{_bindir}/tdm-client + %changelog diff --git a/tools/Makefile.am b/tools/Makefile.am new file mode 100644 index 0000000..1395786 --- /dev/null +++ b/tools/Makefile.am @@ -0,0 +1,14 @@ +bin_PROGRAMS = \ + tdm-client + +tdm_client_SOURCES = \ + tdm_test_client.c + +tdm_client_LDFLAGS = ${LDFLAGS} +tdm_client_CFLAGS = \ + $(TDM_CFLAGS) \ + -I$(top_srcdir)/include \ + -I$(top_srcdir)/client +tdm_client_LDADD = \ + $(TDM_LIBS) \ + $(top_builddir)/client/libtdm-client.la diff --git a/tools/tdm_test_client.c b/tools/tdm_test_client.c new file mode 100644 index 0000000..ed88d8a --- /dev/null +++ b/tools/tdm_test_client.c @@ -0,0 +1,116 @@ +/* +Copyright (C) 2015 Samsung Electronics co., Ltd. All Rights Reserved. + +Contact: + Changyeon Lee , + JunKyeong Kim , + Boram Park , + SooChan Lim + +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, sublicense, +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 NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS 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 +#include +#include +#include +#include + +#include +#include + +static int +get_time_in_millis(void) +{ + struct timespec tp; + + if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0) + return (int)(tp.tv_sec * 1000) + (tp.tv_nsec / 1000000L); + + return 0; +} + +static void +_client_vblank_handler(unsigned int sequence, unsigned int tv_sec, + unsigned int tv_usec, void *user_data) +{ + int temp1, temp2; + + temp1 = (int)user_data; + temp2 = get_time_in_millis(); + + printf("%d ms\n", temp2 - temp1); +} + + +int +main(int argc, char *argv[]) +{ + tdm_client *client; + tdm_client_error error; + int fd = -1; + struct pollfd fds; + + client = tdm_client_create(&error); + if (error != TDM_CLIENT_ERROR_NONE) { + printf("tdm_client_create failed\n"); + exit(1); + } + + error = tdm_client_get_fd(client, &fd); + if (error != TDM_CLIENT_ERROR_NONE || fd < 0) { + printf("tdm_client_get_fd failed\n"); + goto done; + } + + fds.events = POLLIN; + fds.fd = fd; + fds.revents = 0; + + while (1) { + int ret; + + error = tdm_client_wait_vblank(client, "unknown-0", 1, 0, + _client_vblank_handler, + (void*)get_time_in_millis()); + if (error != TDM_CLIENT_ERROR_NONE) { + printf("tdm_client_wait_vblank failed\n"); + goto done; + } + + ret = poll(&fds, 1, -1); + if (ret < 0) { + if (errno == EBUSY) /* normal case */ + continue; + else { + printf("poll failed: %m\n"); + goto done; + } + } + + error = tdm_client_handle_events(client); + if (error != TDM_CLIENT_ERROR_NONE) + printf("tdm_client_handle_events failed\n"); + } + +done: + tdm_client_destroy(client); + return 0; +} -- 2.7.4 From c7942fd59ffda80ed8c4b62fb277916dee2abe86 Mon Sep 17 00:00:00 2001 From: Boram Park Date: Fri, 8 Apr 2016 17:36:27 +0900 Subject: [PATCH 03/16] return error during DPMS off Change-Id: Idb99a669b6d4dffe78e7914b130ec78d97617fe1 --- src/tdm_capture.c | 9 +++++++++ src/tdm_display.c | 20 ++++++++++++++++++-- src/tdm_private.h | 6 ++++++ 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/tdm_capture.c b/src/tdm_capture.c index a4bdffd..411d209 100644 --- a/src/tdm_capture.c +++ b/src/tdm_capture.c @@ -393,11 +393,20 @@ EXTERN tdm_error tdm_capture_commit(tdm_capture *capture) { tdm_buffer_info *b = NULL, *bb = NULL; + tdm_private_output *private_output; CAPTURE_FUNC_ENTRY(); _pthread_mutex_lock(&private_display->lock); + private_output = private_capture->private_output; + if (private_output->current_dpms_value > TDM_OUTPUT_DPMS_ON) { + TDM_WRN("output(%d) dpms: %s", private_output->pipe, + dpms_str(private_output->current_dpms_value)); + _pthread_mutex_unlock(&private_display->lock); + return TDM_ERROR_BAD_REQUEST; + } + if (!func_capture->capture_commit) { _pthread_mutex_unlock(&private_display->lock); TDM_DBG("failed: not implemented!!"); diff --git a/src/tdm_display.c b/src/tdm_display.c index 959cf7f..d804f9d 100644 --- a/src/tdm_display.c +++ b/src/tdm_display.c @@ -125,7 +125,7 @@ struct type_name dpms_names[] = { { TDM_OUTPUT_DPMS_OFF, "off" }, }; -static type_name_fn(dpms) +INTERN type_name_fn(dpms) struct type_name status_names[] = { { TDM_OUTPUT_CONN_STATUS_DISCONNECTED, "disconnected" }, @@ -133,7 +133,7 @@ struct type_name status_names[] = { { TDM_OUTPUT_CONN_STATUS_MODE_SETTED, "mode_setted" }, }; -static type_name_fn(status) +INTERN type_name_fn(status) EXTERN tdm_error tdm_display_get_capabilities(tdm_display *dpy, @@ -959,6 +959,13 @@ tdm_output_wait_vblank(tdm_output *output, int interval, int sync, _pthread_mutex_lock(&private_display->lock); + if (private_output->current_dpms_value > TDM_OUTPUT_DPMS_ON) { + TDM_WRN("output(%d) dpms: %s", private_output->pipe, + dpms_str(private_output->current_dpms_value)); + _pthread_mutex_unlock(&private_display->lock); + return TDM_ERROR_BAD_REQUEST; + } + func_output = &private_display->func_output; if (!func_output->output_wait_vblank) { @@ -1046,6 +1053,13 @@ tdm_output_commit(tdm_output *output, int sync, tdm_output_commit_handler func, _pthread_mutex_lock(&private_display->lock); + if (private_output->current_dpms_value > TDM_OUTPUT_DPMS_ON) { + TDM_WRN("output(%d) dpms: %s", private_output->pipe, + dpms_str(private_output->current_dpms_value)); + _pthread_mutex_unlock(&private_display->lock); + return TDM_ERROR_BAD_REQUEST; + } + ret = _tdm_output_commit(output, sync, func, user_data); _pthread_mutex_unlock(&private_display->lock); @@ -1125,6 +1139,8 @@ tdm_output_set_dpms(tdm_output *output, tdm_output_dpms dpms_value) } ret = func_output->output_set_dpms(private_output->output_backend, dpms_value); + if (ret == TDM_ERROR_NONE) + private_output->current_dpms_value = dpms_value; _pthread_mutex_unlock(&private_display->lock); diff --git a/src/tdm_private.h b/src/tdm_private.h index 93d1e94..db82944 100644 --- a/src/tdm_private.h +++ b/src/tdm_private.h @@ -84,6 +84,11 @@ extern int tdm_debug_thread; #define TDM_TRACE_END() #endif +#define prototype_name_fn(res) const char * res##_str(int type) + +prototype_name_fn(dpms); +prototype_name_fn(status); + typedef enum { TDM_CAPTURE_TARGET_OUTPUT, TDM_CAPTURE_TARGET_LAYER, @@ -149,6 +154,7 @@ struct _tdm_private_output { tdm_output *output_backend; unsigned int pipe; + tdm_output_dpms current_dpms_value; int regist_vblank_cb; int regist_commit_cb; -- 2.7.4 From c893170b0cd5cdeded0d598f11d8e54d939716e2 Mon Sep 17 00:00:00 2001 From: Boram Park Date: Fri, 8 Apr 2016 18:24:11 +0900 Subject: [PATCH 04/16] need to close fd of tdm_helper_get_fd Change-Id: I5c06586ae3e07c84187137b4294a74a0505b0ca1 --- src/tdm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tdm.c b/src/tdm.c index ff7d85f..e54c7a7 100644 --- a/src/tdm.c +++ b/src/tdm.c @@ -795,6 +795,7 @@ tdm_display_init(tdm_error *error) int tdm_drm_fd = tdm_helper_get_fd("TDM_DRM_MASTER_FD"); if (tdm_drm_fd >= 0) { private_display->bufmgr = tbm_bufmgr_init(tdm_drm_fd); + close(tdm_drm_fd); if (!private_display->bufmgr) { TDM_ERR("tbm_bufmgr_init failed"); goto failed_update; -- 2.7.4 From 4aa28cdfc60e387e1b7f1766b07bc0acc739de67 Mon Sep 17 00:00:00 2001 From: Boram Park Date: Mon, 11 Apr 2016 15:50:57 +0900 Subject: [PATCH 05/16] call the change handler when dpms changed Change-Id: I34e856fceb1840b4a2fecba867550b5637571e47 --- src/tdm_display.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/tdm_display.c b/src/tdm_display.c index d804f9d..1039beb 100644 --- a/src/tdm_display.c +++ b/src/tdm_display.c @@ -1130,6 +1130,11 @@ tdm_output_set_dpms(tdm_output *output, tdm_output_dpms dpms_value) _pthread_mutex_lock(&private_display->lock); + if (private_output->current_dpms_value == dpms_value) { + _pthread_mutex_unlock(&private_display->lock); + return TDM_ERROR_NONE; + } + func_output = &private_display->func_output; if (!func_output->output_set_dpms) { @@ -1139,9 +1144,18 @@ tdm_output_set_dpms(tdm_output *output, tdm_output_dpms dpms_value) } ret = func_output->output_set_dpms(private_output->output_backend, dpms_value); - if (ret == TDM_ERROR_NONE) + if (ret == TDM_ERROR_NONE) { + tdm_value value; + private_output->current_dpms_value = dpms_value; + value.u32 = dpms_value; + tdm_output_call_change_handler_internal(private_output, + &private_output->change_handler_list_main, + TDM_OUTPUT_CHANGE_DPMS, + value); + } + _pthread_mutex_unlock(&private_display->lock); return ret; -- 2.7.4 From 1859505491bd4f1b58b8a865cddbbb73297276f5 Mon Sep 17 00:00:00 2001 From: Boram Park Date: Mon, 11 Apr 2016 17:34:24 +0900 Subject: [PATCH 06/16] fix 64bit build error Change-Id: I19f591063dc4c824aec8599fed8bb0a740debd15 --- src/tdm_thread.c | 2 +- tools/tdm_test_client.c | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/tdm_thread.c b/src/tdm_thread.c index ec7ce92..534167f 100644 --- a/src/tdm_thread.c +++ b/src/tdm_thread.c @@ -216,7 +216,7 @@ tdm_thread_send_cb(tdm_private_loop *private_loop, tdm_thread_cb_base *base) len = write(private_thread->pipe[1], base, base->length); if (len != base->length) { - TDM_ERR("write failed (%d != %d): %m", len, base->length); + TDM_ERR("write failed (%d != %d): %m", (int)len, base->length); return TDM_ERROR_OPERATION_FAILED; } diff --git a/tools/tdm_test_client.c b/tools/tdm_test_client.c index ed88d8a..817ca3e 100644 --- a/tools/tdm_test_client.c +++ b/tools/tdm_test_client.c @@ -32,6 +32,7 @@ DEALINGS IN THE SOFTWARE. #include #include #include +#include #include #include @@ -53,7 +54,7 @@ _client_vblank_handler(unsigned int sequence, unsigned int tv_sec, { int temp1, temp2; - temp1 = (int)user_data; + temp1 = (intptr_t)user_data; temp2 = get_time_in_millis(); printf("%d ms\n", temp2 - temp1); @@ -89,7 +90,7 @@ main(int argc, char *argv[]) error = tdm_client_wait_vblank(client, "unknown-0", 1, 0, _client_vblank_handler, - (void*)get_time_in_millis()); + (void*)(intptr_t)get_time_in_millis()); if (error != TDM_CLIENT_ERROR_NONE) { printf("tdm_client_wait_vblank failed\n"); goto done; -- 2.7.4 From 0d1711f8fb8978a9cd5960b4bf8e4a27a63e9b1f Mon Sep 17 00:00:00 2001 From: Andrii Sokolenko Date: Tue, 12 Apr 2016 16:58:24 +0300 Subject: [PATCH 07/16] For store user data of buffer used new surface api of libtbm Change-Id: I7fb0f7e3956a68e84c3e497222b16a8115e291bb Signed-off-by: Andrii Sokolenko --- src/tdm_buffer.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/tdm_buffer.c b/src/tdm_buffer.c index 9de916f..50a94be 100644 --- a/src/tdm_buffer.c +++ b/src/tdm_buffer.c @@ -87,14 +87,8 @@ INTERN tdm_buffer_info * tdm_buffer_get_info(tbm_surface_h buffer) { tdm_buffer_info *buf_info = NULL; - tbm_bo bo; - bo = tbm_surface_internal_get_bo(buffer, 0); - TDM_RETURN_VAL_IF_FAIL(bo != NULL, NULL); - - tbm_bo_get_user_data(bo, TDM_BUFFER_KEY, (void **)&buf_info); - - if (!buf_info) { + if (!tbm_surface_internal_get_user_data(buffer, TDM_BUFFER_KEY,(void **)&buf_info)) { buf_info = calloc(1, sizeof(tdm_buffer_info)); TDM_RETURN_VAL_IF_FAIL(buf_info != NULL, NULL); @@ -104,8 +98,14 @@ tdm_buffer_get_info(tbm_surface_h buffer) LIST_INITHEAD(&buf_info->destroy_funcs); LIST_INITHEAD(&buf_info->link); - tbm_bo_add_user_data(bo, TDM_BUFFER_KEY, _tdm_buffer_destroy_info); - tbm_bo_set_user_data(bo, TDM_BUFFER_KEY, buf_info); + if (!tbm_surface_internal_add_user_data(buffer, TDM_BUFFER_KEY, _tdm_buffer_destroy_info)) { + TDM_WRN("FAIL to create user_data for surface %p", buffer); + return NULL; + } + if (!tbm_surface_internal_set_user_data(buffer, TDM_BUFFER_KEY, buf_info)) { + TDM_WRN("FAIL to set user_data for surface %p", buffer); + return NULL; + } if (tdm_debug_buffer) TDM_INFO("%p created", buf_info->buffer); -- 2.7.4 From 8a34b8790d9bc2b027f6ba2ac0338a0dea09f29c Mon Sep 17 00:00:00 2001 From: SooChan Lim Date: Mon, 18 Apr 2016 08:39:05 +0900 Subject: [PATCH 08/16] set the initial dpms value to be off Change-Id: I3413ce4256133d58b5e02a27c4ecb036e184fae4 --- src/tdm.c | 1 + 1 file changed, 1 insertion(+) mode change 100644 => 100755 src/tdm.c diff --git a/src/tdm.c b/src/tdm.c old mode 100644 new mode 100755 index e54c7a7..24ee038 --- a/src/tdm.c +++ b/src/tdm.c @@ -410,6 +410,7 @@ _tdm_display_update_output(tdm_private_display *private_display, LIST_ADD(&private_output->link, &private_display->output_list); 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; -- 2.7.4 From 61d122abfd323a39d4ed597ab625aa2cb2c913f6 Mon Sep 17 00:00:00 2001 From: Junkyeong Kim Date: Mon, 18 Apr 2016 16:35:05 +0900 Subject: [PATCH 09/16] erase dereference of null code Change-Id: I3726b755d568255e3a82da65ada40828a40414b3 Signed-off-by: Junkyeong Kim --- src/tdm_event_loop.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/tdm_event_loop.c b/src/tdm_event_loop.c index f653dbe..e0791ab 100644 --- a/src/tdm_event_loop.c +++ b/src/tdm_event_loop.c @@ -112,14 +112,7 @@ tdm_event_loop_init(tdm_private_display *private_display) free(private_loop); return TDM_ERROR_OUT_OF_MEMORY; } - private_loop->wl_loop = wl_display_get_event_loop(private_loop->wl_display); - if (!private_loop->wl_loop) { - TDM_ERR("no event loop"); - wl_display_destroy(private_loop->wl_display); - free(private_loop); - return TDM_ERROR_OPERATION_FAILED; - } ret = tdm_server_init(private_loop); if (ret != TDM_ERROR_NONE) { -- 2.7.4 From 10d0e38fa82edfe09fb5f67537bd8086a725d570 Mon Sep 17 00:00:00 2001 From: Boram Park Date: Mon, 18 Apr 2016 21:24:27 +0900 Subject: [PATCH 10/16] disable the tdm thread as default Change-Id: I4f5584bd37e82a265b7a4fc350994076336387f7 --- src/tdm_thread.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tdm_thread.c b/src/tdm_thread.c index 534167f..08f45f9 100644 --- a/src/tdm_thread.c +++ b/src/tdm_thread.c @@ -134,7 +134,7 @@ tdm_thread_init(tdm_private_loop *private_loop) /* enable as default */ thread = getenv("TDM_THREAD"); - if (thread && strstr(thread, "0")) { + if (thread && strstr(thread, "1")) { TDM_INFO("not using a TDM event thread"); return TDM_ERROR_NONE; } -- 2.7.4 From b8fba9abbd8774defa90185e02dce7bb4778be7a Mon Sep 17 00:00:00 2001 From: Boram Park Date: Mon, 18 Apr 2016 21:33:24 +0900 Subject: [PATCH 11/16] fix syntax error Change-Id: Icdf0b36c6bc81d3382b31ab63272599593b9be37 --- src/tdm_thread.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tdm_thread.c b/src/tdm_thread.c index 08f45f9..25d76e9 100644 --- a/src/tdm_thread.c +++ b/src/tdm_thread.c @@ -134,7 +134,7 @@ tdm_thread_init(tdm_private_loop *private_loop) /* enable as default */ thread = getenv("TDM_THREAD"); - if (thread && strstr(thread, "1")) { + if (!thread || !strncmp(thread, "1", 1)) { TDM_INFO("not using a TDM event thread"); return TDM_ERROR_NONE; } -- 2.7.4 From 388d99f57225c30b6aa46bfd5aed8d59bfa814f3 Mon Sep 17 00:00:00 2001 From: Boram Park Date: Tue, 19 Apr 2016 18:45:32 +0900 Subject: [PATCH 12/16] fix syntax error Change-Id: I0a7822a23bda1ecbc2af12dbf2eae15c737d086a --- src/tdm_thread.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tdm_thread.c b/src/tdm_thread.c index 25d76e9..fd9a5ad 100644 --- a/src/tdm_thread.c +++ b/src/tdm_thread.c @@ -134,8 +134,8 @@ tdm_thread_init(tdm_private_loop *private_loop) /* enable as default */ thread = getenv("TDM_THREAD"); - if (!thread || !strncmp(thread, "1", 1)) { - TDM_INFO("not using a TDM event thread"); + if (!thread || strncmp(thread, "1", 1)) { + TDM_INFO("not using a TDM event thread: %s", (thread)?thread:"none"); return TDM_ERROR_NONE; } -- 2.7.4 From d8b97c8e109fecc403052f4101af5d844d22584d Mon Sep 17 00:00:00 2001 From: Junkyeong Kim Date: Tue, 19 Apr 2016 19:46:28 +0900 Subject: [PATCH 13/16] make dump at tdm_layer_set_buffer function add tdm dump helper functions Change-Id: I64f1d7018ede69256d45181774b91f5a27f7f341 Signed-off-by: Junkyeong Kim --- include/tdm_helper.h | 25 ++++++++++++++++++++++++- src/tdm_display.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ src/tdm_helper.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ src/tdm_private.h | 5 +++++ 4 files changed, 122 insertions(+), 1 deletion(-) diff --git a/include/tdm_helper.h b/include/tdm_helper.h index c329669..254999a 100644 --- a/include/tdm_helper.h +++ b/include/tdm_helper.h @@ -45,7 +45,7 @@ extern "C" { /** * @file tdm_helper.h - * @brief The header file to help a vendor to implement a backend module + * @brief The header file to help tdm backend/frontend user */ /** @@ -95,6 +95,29 @@ int tdm_helper_get_fd(const char *env); */ void tdm_helper_set_fd(const char *env, int fd); +/** + * @brief Start the dump debugging. + * @details + * Start tdm dump. + * Make dump file when tdm_layer_set_buffer() function is called. + * Set the dump count to 1. + * @param[in] dumppath The given dump path + * @param[in] count The dump count number + * @see #tdm_helper_dump_stop() + */ +void +tdm_helper_dump_start(char *dumppath, int *count); + +/** + * @brief Stop the dump debugging. + * @details + * Stop tdm dump. + * Set the dump count to 0. + * @see #tdm_helper_dump_start() + */ +void +tdm_helper_dump_stop(void); + #ifdef __cplusplus } #endif diff --git a/src/tdm_display.c b/src/tdm_display.c index 1039beb..a7a1327 100644 --- a/src/tdm_display.c +++ b/src/tdm_display.c @@ -40,6 +40,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "tdm.h" #include "tdm_backend.h" #include "tdm_private.h" +#include "tdm_helper.h" #define COUNT_MAX 10 @@ -1417,6 +1418,47 @@ tdm_layer_get_info(tdm_layer *layer, tdm_info_layer *info) return ret; } +static void +_tdm_layer_dump_buffer(tdm_layer *layer, tbm_surface_h buffer) +{ + tdm_private_layer *private_layer = (tdm_private_layer*)layer; + tdm_private_output *private_output = private_layer->private_output; + char *path = NULL; + int count; + unsigned int pipe; + int zpos; + tbm_surface_info_s info; + tbm_surface_error_e err; + + path = tdm_helper_get_dump_path(); + TDM_RETURN_IF_FAIL(path != NULL); + + count = tdm_helper_get_dump_count(); + TDM_RETURN_IF_FAIL(count != 0); + + err = tbm_surface_map(buffer, TBM_SURF_OPTION_READ, &info); + TDM_RETURN_IF_FAIL(err == TBM_SURFACE_ERROR_NONE); + + char fullpath[PATH_MAX] = {0, }; + + pipe = private_output->pipe; + zpos = private_layer->caps.zpos; + + if (info.format == TBM_FORMAT_ARGB8888 || info.format == TBM_FORMAT_XRGB8888) + snprintf(fullpath, sizeof(fullpath), "%s/%03d_out_%d_lyr_%d.png", + path, count, pipe, zpos); + else + snprintf(fullpath, sizeof(fullpath), "%s/%03d_out_%d_lyr_%d_%dx%d_%c%c%c%c.yuv", + path, count, pipe, zpos, info.planes[0].stride, info.height, FOURCC_STR(info.format)); + + tbm_surface_unmap(buffer); + + tdm_helper_dump_buffer(buffer, fullpath); + TDM_DBG("%d, %s dump excute", count, fullpath); + + return; +} + EXTERN tdm_error tdm_layer_set_buffer(tdm_layer *layer, tbm_surface_h buffer) { @@ -1441,6 +1483,9 @@ tdm_layer_set_buffer(tdm_layer *layer, tbm_surface_h buffer) ret = func_layer->layer_set_buffer(private_layer->layer_backend, buffer); TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE); + /* dump buffer */ + _tdm_layer_dump_buffer(layer, buffer); + if (ret == TDM_ERROR_NONE) { /* FIXME: should save to pending_buffer first. And after committing * successfully, need to move to waiting_buffer. diff --git a/src/tdm_helper.c b/src/tdm_helper.c index e7d6154..03d13cb 100644 --- a/src/tdm_helper.c +++ b/src/tdm_helper.c @@ -16,6 +16,9 @@ static const char *dump_prefix[2] = {"png", "yuv"}; +static int *tdm_helper_dump_count; +static char *tdm_helper_dump_path; + INTERN int tdm_helper_unlock_in_cb(tdm_private_display *private_display) { @@ -263,3 +266,48 @@ tdm_helper_set_fd(const char *env, int fd) if (fd >= 0) TDM_INFO("%s: fd(%d)", env, fd); } + +EXTERN void +tdm_helper_dump_start(char *dumppath, int *count) +{ + if (tdm_helper_dump_count != NULL) { + TDM_DBG("tdm_helper_dump is already started."); + return; + } + + if (dumppath == NULL) { + TDM_DBG("tdm_helper_dump dumppath is null."); + return; + } + + tdm_helper_dump_count = count; + tdm_helper_dump_path = dumppath; + + TDM_DBG("tdm_helper_dump start.(path : %s)", tdm_helper_dump_path); +} + +EXTERN void +tdm_helper_dump_stop(void) +{ + tdm_helper_dump_path = NULL; + tdm_helper_dump_count = NULL; + + TDM_DBG("tdm_helper_dump stop."); +} + +INTERN int +tdm_helper_get_dump_count(void) +{ + if ((tdm_helper_dump_count != NULL) && (tdm_helper_dump_path != NULL)) { + if (*tdm_helper_dump_count == 1000) + *tdm_helper_dump_count = 1; + return (*tdm_helper_dump_count)++; + } else + return 0; +} + +INTERN char * +tdm_helper_get_dump_path(void) +{ + return tdm_helper_dump_path; +} diff --git a/src/tdm_private.h b/src/tdm_private.h index db82944..aa19633 100644 --- a/src/tdm_private.h +++ b/src/tdm_private.h @@ -446,6 +446,11 @@ tdm_helper_unlock_in_cb(tdm_private_display *private_display); void tdm_helper_lock_in_cb(tdm_private_display *private_display, int need_lock); +int +tdm_helper_get_dump_count(void); +char * +tdm_helper_get_dump_path(void); + #define _pthread_mutex_lock(l) \ do {if (tdm_debug_mutex) TDM_INFO("mutex lock"); pthread_mutex_lock(l);} while (0) #define _pthread_mutex_unlock(l) \ -- 2.7.4 From c14e6187bd2683333d78671364d8a30392f29d45 Mon Sep 17 00:00:00 2001 From: Boram Park Date: Wed, 20 Apr 2016 18:52:46 +0900 Subject: [PATCH 14/16] fix segfault when the vblank resource is gone Change-Id: I4acfe93a46d85dcdcc4db81d79d78b8165b88a9e --- src/tdm_server.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/tdm_server.c b/src/tdm_server.c index a8d0498..c824905 100644 --- a/src/tdm_server.c +++ b/src/tdm_server.c @@ -57,6 +57,8 @@ typedef struct _tdm_server_vblank_info { tdm_private_server *private_server; } tdm_server_vblank_info; +static tdm_private_loop *keep_private_loop; + static void _tdm_server_cb_output_vblank(tdm_output *output, unsigned int sequence, unsigned int tv_sec, unsigned int tv_usec, @@ -65,7 +67,10 @@ _tdm_server_cb_output_vblank(tdm_output *output, unsigned int sequence, tdm_server_vblank_info *vblank_info = (tdm_server_vblank_info*)user_data; tdm_server_vblank_info *found; - LIST_FIND_ITEM(vblank_info, &vblank_info->private_server->vblank_list, + if (!keep_private_loop || !keep_private_loop->private_server) + return; + + LIST_FIND_ITEM(vblank_info, &keep_private_loop->private_server->vblank_list, tdm_server_vblank_info, link, found); if (!found) { TDM_DBG("vblank_info(%p) is destroyed", vblank_info); @@ -222,6 +227,7 @@ tdm_server_init(tdm_private_loop *private_loop) } private_loop->private_server = private_server; + keep_private_loop = private_loop; return TDM_ERROR_NONE; } @@ -243,4 +249,5 @@ tdm_server_deinit(tdm_private_loop *private_loop) free(private_server); private_loop->private_server = NULL; + keep_private_loop = NULL; } -- 2.7.4 From facfa524ba5d1e21ee25e71596bd62237bc60457 Mon Sep 17 00:00:00 2001 From: Boram Park Date: Thu, 21 Apr 2016 11:01:35 +0900 Subject: [PATCH 15/16] print log with color red - error yellow - warning green - info white - debug Change-Id: I9861b058efefc40c5d04677d5c1f952c959ffe60 --- include/tdm_log.h | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/include/tdm_log.h b/include/tdm_log.h index cddf0e6..841cde2 100644 --- a/include/tdm_log.h +++ b/include/tdm_log.h @@ -109,6 +109,11 @@ extern int tdm_debug; #include +#define COLOR_RED "\x1b[31m" /* for error */ +#define COLOR_YELLOW "\x1b[33m" /* for warning */ +#define COLOR_GREEN "\x1b[32m" /* for info */ +#define COLOR_RESET "\x1b[0m" + #define TDM_DBG(fmt, args...) \ if (tdm_debug) \ do { \ @@ -122,7 +127,7 @@ extern int tdm_debug; do { \ struct timespec ts; \ clock_gettime(CLOCK_MONOTONIC, &ts); \ - printf("[TDM_INF][%d.%06d][%d][%s %d] "fmt"\n", (int)ts.tv_sec, \ + printf(COLOR_GREEN"[TDM_INF]"COLOR_RESET"[%d.%06d][%d][%s %d] "fmt"\n", (int)ts.tv_sec, \ (int)ts.tv_nsec / 1000, (int)syscall(SYS_gettid), __func__, __LINE__, ##args); \ } while (0); @@ -130,7 +135,7 @@ extern int tdm_debug; do { \ struct timespec ts; \ clock_gettime(CLOCK_MONOTONIC, &ts); \ - printf("[TDM_WRN][%d.%06d][%d][%s %d] "fmt"\n", (int)ts.tv_sec, \ + printf(COLOR_YELLOW"[TDM_WRN]"COLOR_RESET"[%d.%06d][%d][%s %d] "fmt"\n", (int)ts.tv_sec, \ (int)ts.tv_nsec / 1000, (int)syscall(SYS_gettid), __func__, __LINE__, ##args); \ } while (0); @@ -138,7 +143,7 @@ extern int tdm_debug; do { \ struct timespec ts; \ clock_gettime(CLOCK_MONOTONIC, &ts); \ - printf("[TDM_ERR][%d.%06d][%d][%s %d] "fmt"\n", (int)ts.tv_sec, \ + printf(COLOR_RED"[TDM_ERR]"COLOR_RESET"[%d.%06d][%d][%s %d] "fmt"\n", (int)ts.tv_sec, \ (int)ts.tv_nsec / 1000, (int)syscall(SYS_gettid), __func__, __LINE__, ##args); \ } while (0); -- 2.7.4 From acab1c4c70fb532947a941c3514249346a07e338 Mon Sep 17 00:00:00 2001 From: Boram Park Date: Thu, 21 Apr 2016 15:35:13 +0900 Subject: [PATCH 16/16] assertion if there is error or warning Change-Id: Ie2a0586b28fd54bf6712603b2c316c3845d23869 --- include/tdm_log.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/include/tdm_log.h b/include/tdm_log.h index 841cde2..ebfa1d7 100644 --- a/include/tdm_log.h +++ b/include/tdm_log.h @@ -43,6 +43,7 @@ extern "C" { #include #include +#include #include @@ -59,6 +60,15 @@ extern "C" { extern int tdm_debug; //#define TDM_CONFIG_DLOG +//#define TDM_CONFIG_ASSERT + +#undef TDM_ASSERT +#ifdef TDM_CONFIG_ASSERT +#define TDM_ASSERT(o) assert(o) +#else +#define TDM_ASSERT(o) +#endif + #ifdef TDM_CONFIG_DLOG #include @@ -137,6 +147,7 @@ extern int tdm_debug; clock_gettime(CLOCK_MONOTONIC, &ts); \ printf(COLOR_YELLOW"[TDM_WRN]"COLOR_RESET"[%d.%06d][%d][%s %d] "fmt"\n", (int)ts.tv_sec, \ (int)ts.tv_nsec / 1000, (int)syscall(SYS_gettid), __func__, __LINE__, ##args); \ + TDM_ASSERT(0); \ } while (0); #define TDM_ERR(fmt, args...) \ @@ -145,6 +156,7 @@ extern int tdm_debug; clock_gettime(CLOCK_MONOTONIC, &ts); \ printf(COLOR_RED"[TDM_ERR]"COLOR_RESET"[%d.%06d][%d][%s %d] "fmt"\n", (int)ts.tv_sec, \ (int)ts.tv_nsec / 1000, (int)syscall(SYS_gettid), __func__, __LINE__, ##args); \ + TDM_ASSERT(0); \ } while (0); #endif /* TDM_CONFIG_DLOG */ -- 2.7.4