support client API for wait_vblank 33/65533/1
authorBoram Park <boram1288.park@samsung.com>
Thu, 31 Mar 2016 09:53:37 +0000 (18:53 +0900)
committerBoram Park <boram1288.park@samsung.com>
Mon, 11 Apr 2016 10:33:05 +0000 (19:33 +0900)
Change-Id: Id7df85559d73324556752ac2a4f572ee259fd731

27 files changed:
.gitignore
Makefile.am
client/Makefile.am [new file with mode: 0644]
client/libtdm-client.pc.in [new file with mode: 0644]
client/tdm_client.c [new file with mode: 0644]
client/tdm_client.h [new file with mode: 0644]
configure.ac
include/tdm_list.h
include/tdm_log.h
packaging/libtdm.spec
protocol/Makefile.am [new file with mode: 0644]
protocol/tdm.xml [new file with mode: 0644]
service/tdm-socket-user.path [new file with mode: 0644]
service/tdm-socket-user.service [new file with mode: 0644]
service/tdm-socket.path [new file with mode: 0644]
service/tdm-socket.service [new file with mode: 0644]
src/Makefile.am
src/tdm.c
src/tdm_capture.c
src/tdm_display.c
src/tdm_event_loop.c
src/tdm_helper.c
src/tdm_macro.h [new file with mode: 0644]
src/tdm_pp.c
src/tdm_private.h
src/tdm_server.c [new file with mode: 0644]
src/tdm_thread.c

index 49d27e8c7ab9ef8ae019febd00586db9f4174265..7a0fbffc0f07d1fd88c1a76fde348dbc937183e8 100644 (file)
@@ -24,3 +24,5 @@ stamp-h1
 *~
 html/
 latex/
+protocol/*.h
+protocol/*.c
index c99188ac611174830368b5495dbc5aa58202d9fb..e8aa5d78be32169448b19d630e1982dc2ae46be2 100644 (file)
@@ -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 (file)
index 0000000..14192b0
--- /dev/null
@@ -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 (file)
index 0000000..cbdf224
--- /dev/null
@@ -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 (file)
index 0000000..5e2b750
--- /dev/null
@@ -0,0 +1,248 @@
+/**************************************************************************
+
+libtdm
+
+Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
+
+Contact: Eunchul Kim <chulspro.kim@samsung.com>,
+         JinYoung Jeon <jy0.jeon@samsung.com>,
+         Taeheon Kim <th908.kim@samsung.com>,
+         YoungJun Cho <yj44.cho@samsung.com>,
+         SooChan Lim <sc1.lim@samsung.com>,
+         Boram Park <sc1.lim@samsung.com>
+
+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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#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 (file)
index 0000000..6312d9d
--- /dev/null
@@ -0,0 +1,87 @@
+/**************************************************************************
+
+libtdm
+
+Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
+
+Contact: Eunchul Kim <chulspro.kim@samsung.com>,
+         JinYoung Jeon <jy0.jeon@samsung.com>,
+         Taeheon Kim <th908.kim@samsung.com>,
+         YoungJun Cho <yj44.cho@samsung.com>,
+         SooChan Lim <sc1.lim@samsung.com>,
+         Boram Park <sc1.lim@samsung.com>
+
+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 <tdm_client.h>    //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_ */
index 358c2e437755e25d2416863e7a0675836eca3c6a..db21b7e832d31394703b6120485c0b2f4d04fb66 100644 (file)
@@ -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 ""
index bd6ac80a4847bdaee35c43ae448bbee8edaccfd2..acdf6c4a3bb88d57fc8fc6cd4270b3b83768acde 100644 (file)
@@ -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_*/
index 508e655eadac9201ccce8db9628cbc940a6f474b..cddf0e67139b591ce26466cdc49e246138bf2190 100644 (file)
@@ -41,6 +41,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 extern "C" {
 #endif
 
+#include <unistd.h>
 #include <time.h>
 #include <sys/syscall.h>
 
index 0673f9c7c867cd04b277106fc12eb57b414d09ad..3f6e0b12490771c660190715456d1395aa21d8b9 100644 (file)
@@ -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 (file)
index 0000000..1329a0e
--- /dev/null
@@ -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 (file)
index 0000000..f3389cb
--- /dev/null
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<protocol name="wl_tdm">
+
+    <interface name="wl_tdm_vblank" version="1">
+
+        <event name="done">
+            <arg name="sequence" type="uint"/>
+            <arg name="tv_sec" type="uint"/>
+            <arg name="tv_usec" type="uint"/>
+        </event>
+
+    </interface>
+
+    <interface name="wl_tdm" version="1">
+
+        <enum name="error">
+            <entry name="invalid_name" value="0"/>
+            <entry name="operation_failed" value="1"/>
+        </enum>
+
+        <request name="wait_vblank">
+            <arg name="id" type="new_id" interface="wl_tdm_vblank"/>
+            <arg name="name" type="string"/>
+            <arg name="interval" type="int"/>
+        </request>
+
+    </interface>
+
+</protocol>
diff --git a/service/tdm-socket-user.path b/service/tdm-socket-user.path
new file mode 100644 (file)
index 0000000..5ee772b
--- /dev/null
@@ -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 (file)
index 0000000..97d0f6f
--- /dev/null
@@ -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 (file)
index 0000000..5ee772b
--- /dev/null
@@ -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 (file)
index 0000000..caabbd8
--- /dev/null
@@ -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
index ee26b0beeceb70bf474fface75a1c060c6126be1..245c2fa2ad0c46380b2e02d1e18e2e71a111e6c4 100644 (file)
@@ -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 \
index 849efb89d71c96ed0947e6e1c9542ee1bd7a76bf..ff7d85fd9b787ad2214bfc339be1813196742a47 100644 (file)
--- 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);
index 56fe1489eee65c100352c47c220b885f90b6b48d..a4bdffdf163dee95f5a01bacae328c1018c313d5 100644 (file)
@@ -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);
index 76b4ba4f8ea387dc4059b08891c1fbcbbfb3bbc2..959cf7f592d210500d81d4a7e7e900aa28dd4874 100644 (file)
@@ -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
index e2beaf795a28a95056c62065e86dcfc281d835e8..f653dbed739c7e5b21827a3d26b19b51c042ec94 100644 (file)
@@ -43,14 +43,6 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 #include <wayland-server-core.h>
 
-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
index 534bebce9210eb77612dbb6cbbd448078bac094a..e7d61547a81bb30d76e62ff279b06f76ef19d645 100644 (file)
 
 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 (file)
index 0000000..a547c0a
--- /dev/null
@@ -0,0 +1,125 @@
+/**************************************************************************
+
+libtdm
+
+Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
+
+Contact: Eunchul Kim <chulspro.kim@samsung.com>,
+         JinYoung Jeon <jy0.jeon@samsung.com>,
+         Taeheon Kim <th908.kim@samsung.com>,
+         YoungJun Cho <yj44.cho@samsung.com>,
+         SooChan Lim <sc1.lim@samsung.com>,
+         Boram Park <sc1.lim@samsung.com>
+
+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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#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_ */
index f5345ad983089adab1b6d95cd790b62af5e252a8..603911e16c30d7cc3c6f9c3270b4a9e268c5753c 100644 (file)
@@ -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);
index 62b59c7fc7c4d88caa86afaaea33b98f492db179..93d1e948ec2c8466550e2aa36e36828070a56944 100644 (file)
@@ -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 <ttrace.h>
 #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 (file)
index 0000000..a8d0498
--- /dev/null
@@ -0,0 +1,246 @@
+/**************************************************************************
+
+libtdm
+
+Copyright 2015 Samsung Electronics co., Ltd. All Rights Reserved.
+
+Contact: Eunchul Kim <chulspro.kim@samsung.com>,
+         JinYoung Jeon <jy0.jeon@samsung.com>,
+         Taeheon Kim <th908.kim@samsung.com>,
+         YoungJun Cho <yj44.cho@samsung.com>,
+         SooChan Lim <sc1.lim@samsung.com>,
+         Boram Park <sc1.lim@samsung.com>
+
+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;
+}
index 5e0d8c792b1f009dff7f892ccdf9d0b4c0b11d6e..ec7ce923907864c8dff927c4ce94dc8264881ed5 100644 (file)
@@ -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;
 }