add tdm-dbg and td-test-server for debugging 96/79296/1 accepted/tizen/common/20160711.170111 accepted/tizen/ivi/20160711.031111 accepted/tizen/mobile/20160711.030644 accepted/tizen/tv/20160711.030613 accepted/tizen/wearable/20160711.030617 submit/tizen/20160711.003538
authorBoram Park <boram1288.park@samsung.com>
Mon, 4 Jul 2016 04:35:19 +0000 (13:35 +0900)
committerBoram Park <boram1288.park@samsung.com>
Mon, 11 Jul 2016 00:44:04 +0000 (09:44 +0900)
Change-Id: I381c9c517256df37ec2238e42815fd3b8618caa4

27 files changed:
client/Makefile.am
client/tdm_client.c
client/tdm_dbg.c [new file with mode: 0644]
common/tdm_log.c
include/tdm.h
include/tdm_common.h
include/tdm_helper.h
include/tdm_log.h
include/tdm_types.h
packaging/libtdm.spec
protocol/tdm.xml
src/Makefile.am
src/tdm.c
src/tdm_capture.c
src/tdm_dbg_server.c [new file with mode: 0644]
src/tdm_display.c
src/tdm_event_loop.c
src/tdm_helper.c
src/tdm_macro.h
src/tdm_pp.c
src/tdm_private.h
src/tdm_server.c
tools/Makefile.am
tools/buffers.c [new file with mode: 0644]
tools/buffers.h [new file with mode: 0644]
tools/tdm_test_client.c
tools/tdm_test_server.c [new file with mode: 0644]

index f3b29c80030c4c4c3803899823a5f9aa4d38878f..739c2f13bd586dd23cae94fe6f9976c973e3f4a1 100644 (file)
@@ -1,3 +1,6 @@
+##########################################################################
+### tdm-client library
+##########################################################################
 libtdm_clientincludedir = ${includedir}
 libtdm_clientinclude_HEADERS = \
        tdm_client.h \
@@ -22,3 +25,21 @@ libtdm_client_la_CFLAGS = \
 libtdm_client_la_SOURCES = \
        $(top_srcdir)/protocol/tdm-protocol.c \
        tdm_client.c
+
+##########################################################################
+### tdm-dbg
+##########################################################################
+bin_PROGRAMS = \
+       tdm-dbg
+
+#tdm-dbg
+tdm_dbg_SOURCES = \
+       $(top_srcdir)/protocol/tdm-protocol.c \
+       tdm_dbg.c
+tdm_dbg_LDFLAGS = ${LDFLAGS}
+tdm_dbg_LDADD = $(TDM_CLIENT_LIBS) ../common/libtdm-common.la
+tdm_dbg_CFLAGS = \
+       $(TDM_CFLAGS) \
+       -I$(top_srcdir)/include \
+       -I$(top_srcdir)/protocol \
+       -I$(top_srcdir)/src
index f03ae63736afc87e105e5f631c89e16fc5976861..b7a80c198929f22110b276356d37568c125bc393 100644 (file)
@@ -253,7 +253,7 @@ _tdm_client_cb_global(void *data, struct wl_registry *registry,
 {
        tdm_private_client *private_client = data;
 
-       if (strcmp(interface, "wl_tdm") == 0) {
+       if (strncmp(interface, "wl_tdm", 6) == 0) {
                private_client->tdm =
                        wl_registry_bind(registry, name, &wl_tdm_interface, version);
                TDM_RETURN_IF_FAIL(private_client->tdm != NULL);
diff --git a/client/tdm_dbg.c b/client/tdm_dbg.c
new file mode 100644 (file)
index 0000000..a6fc0a7
--- /dev/null
@@ -0,0 +1,155 @@
+/**************************************************************************
+ *
+ * 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_log.h>
+#include <tdm_macro.h>
+#include <tdm_list.h>
+#include <tdm-client-protocol.h>
+
+#undef exit_if_fail
+#define exit_if_fail(cond) { \
+       if (!(cond)) { \
+               printf("'%s' failed. (line:%d)\n", #cond, __LINE__); \
+               exit(0); \
+       } \
+}
+
+typedef struct _tdm_dbg_info {
+       struct wl_display *display;
+       struct wl_registry *registry;
+       struct wl_tdm *tdm;
+} tdm_dbg_info;
+
+static tdm_dbg_info td_info;
+static int done;
+
+static void
+_tdm_dbg_cb_debug_done(void *data, struct wl_tdm *wl_tdm, const char *message)
+{
+       printf("%s", message);
+
+       done = 1;
+}
+
+static const struct wl_tdm_listener  tdm_dbg_listener = {
+       _tdm_dbg_cb_debug_done,
+};
+
+static void
+_tdm_dbg_cb_global(void *data, struct wl_registry *registry,
+                                  uint32_t name, const char *interface,
+                                  uint32_t version)
+{
+       tdm_dbg_info *info = data;
+
+       if (strncmp(interface, "wl_tdm", 6) == 0) {
+               info->tdm = wl_registry_bind(registry, name, &wl_tdm_interface, version);
+               exit_if_fail(info->tdm != NULL);
+               wl_tdm_add_listener(info->tdm, &tdm_dbg_listener, info);
+               wl_display_flush(info->display);
+       }
+}
+
+static void
+_tdm_dbg_cb_global_remove(void *data, struct wl_registry *registry, uint32_t name)
+{
+}
+
+static const struct wl_registry_listener tdm_dbg_registry_listener = {
+       _tdm_dbg_cb_global,
+       _tdm_dbg_cb_global_remove
+};
+
+int
+main(int argc, char ** argv)
+{
+       tdm_dbg_info *info = &td_info;
+       int i, ret = 0;
+       char cwd[1024];
+       char options[1024];
+       int bufsize = sizeof(options);
+       char *str_buf = options;
+       int *len_buf = &bufsize;
+       const char *xdg;
+
+       xdg = (const char*)getenv("XDG_RUNTIME_DIR");
+       if (!xdg) {
+               char buf[32];
+               snprintf(buf, sizeof(buf), "/run");
+
+               ret = setenv("XDG_RUNTIME_DIR", (const char*)buf, 1);
+               exit_if_fail(ret == 0);
+       }
+
+       info->display = wl_display_connect("tdm-socket");
+       exit_if_fail(info->display != NULL);
+
+       info->registry = wl_display_get_registry(info->display);
+       exit_if_fail(info->registry != NULL);
+
+       wl_registry_add_listener(info->registry,
+                                                        &tdm_dbg_registry_listener, info);
+       wl_display_roundtrip(info->display);
+       exit_if_fail(info->tdm != NULL);
+
+       TDM_SNPRINTF(str_buf, len_buf, "%d ", getpid());
+
+       if (!getcwd(cwd, sizeof(cwd)))
+               snprintf(cwd, sizeof(cwd), "/tmp");
+       TDM_SNPRINTF(str_buf, len_buf, "%s ", cwd);
+
+       for (i = 0; i < argc; i++)
+               TDM_SNPRINTF(str_buf, len_buf, "%s ", argv[i]);
+
+       done = 0;
+
+       wl_tdm_debug(info->tdm, options);
+
+       while (!done && ret >= 0)
+               ret = wl_display_dispatch(info->display);
+
+       if (info->tdm)
+               wl_tdm_destroy(info->tdm);
+       if (info->registry)
+               wl_registry_destroy(info->registry);
+       if (info->display)
+               wl_display_disconnect(info->display);
+
+       return 0;
+}
index 2c8b0c66e0374ae0a760c3dc7814078c3bac639b..c843c9b931ee9859c220547133c81f8823997013 100644 (file)
@@ -61,7 +61,7 @@
 #define LOG_TAG "TDM"
 
 static unsigned int dlog_enable;
-static unsigned int debug_enable;
+static unsigned int debug_level = TDM_LOG_LEVEL_INFO;
 
 static unsigned int need_check_env = 1;
 
@@ -69,10 +69,15 @@ static void
 _tdm_log_check_env(void)
 {
        const char *str;
+       char *end;
+
+       str = getenv("TDM_DEBUG_LEVEL");
+       if (str)
+               debug_level = strtol(str, &end, 10);
 
        str = getenv("TDM_DEBUG");
        if (str && (strstr(str, "1")))
-               debug_enable = 1;
+               debug_level = TDM_LOG_LEVEL_DBG;
 
        str = getenv("TDM_DLOG");
        if (str && (strstr(str, "1")))
@@ -88,7 +93,16 @@ tdm_log_enable_dlog(unsigned int enable)
 EXTERN void
 tdm_log_enable_debug(unsigned int enable)
 {
-       debug_enable = enable;
+       if (enable)
+               debug_level = TDM_LOG_LEVEL_DBG;
+       else
+               debug_level = TDM_LOG_LEVEL_INFO;
+}
+
+EXTERN void
+tdm_log_set_debug_level(int level)
+{
+       debug_level = level;
 }
 
 EXTERN void
@@ -101,7 +115,7 @@ tdm_log_print(int level, const char *fmt, ...)
                _tdm_log_check_env();
        }
 
-       if (level > 3 && !debug_enable)
+       if (level > debug_level)
                return;
 
        if (dlog_enable) {
index 47afc19a931190a862d4ad1fe6a9a7cb64f01172..fa0a7f0e8975f90f04509141827247a87b01f615 100644 (file)
@@ -122,6 +122,18 @@ tdm_display_get_fd(tdm_display *dpy, int *fd);
 tdm_error
 tdm_display_handle_events(tdm_display *dpy);
 
+/**
+ * @brief Get the information of the TDM backend module.
+ * @param[in] dpy A display object
+ * @param[out] name The name of the TDM backend module
+ * @param[out] vendor The vendor of the TDM backend module
+ * @param[out] version The version of the TDM backend module
+ * @return #TDM_ERROR_NONE if success. Otherwise, error value.
+ */
+tdm_error
+tdm_display_get_backend_info(tdm_display *dpy, const char **name,
+                                                        const char **vendor, int *major, int *minor);
+
 /**
  * @brief Get the capabilities of a display object.
  * @details A frontend user can get whether TDM supports pp/capture functionality with this function.
index 79cdf69ff7859b786b31f66fb5715acfe08cbd0d..fae122404e46623fbade68af7947457bfdcbeeae 100644 (file)
@@ -43,6 +43,7 @@ extern "C" {
 #endif
 
 #define TDM_NAME_LEN        64
+#define TDM_PATH_LEN        1024
 
 /**
  * @file tdm_common.h
@@ -67,6 +68,76 @@ typedef enum {
        TDM_ERROR_DPMS_OFF              = -10, /**< dpms off */
 } tdm_error;
 
+/**
+ * @brief The transform enumeration(rotate, flip)
+ */
+typedef enum {
+       TDM_TRANSFORM_NORMAL            = 0, /**< no transform */
+       TDM_TRANSFORM_90                = 1, /**< rotate 90 */
+       TDM_TRANSFORM_180               = 2, /**< rotate 180 */
+       TDM_TRANSFORM_270               = 3, /**< rotate 270 */
+       TDM_TRANSFORM_FLIPPED           = 4, /**< no rotate and horizontal flip */
+       TDM_TRANSFORM_FLIPPED_90        = 5, /**< rotate 90 and horizontal flip */
+       TDM_TRANSFORM_FLIPPED_180       = 6, /**< rotate 180 and horizontal flip */
+       TDM_TRANSFORM_FLIPPED_270       = 7, /**< rotate 270 and horizontal flip */
+} tdm_transform;
+
+/**
+ * @brief The layer capability enumeration
+ * @details
+ * A layer can have one of CURSOR, PRIMARY and OVERLAY capability. And a layer
+ * also can have one of GRAPHIC and VIDEO capability. And a layer also can have
+ * SCALE and TRANSFORM capability.\n
+ * @par Example
+ * @code
+ *  //For example
+ *  capabilities = TDM_LAYER_CAPABILITY_PRIMARY | TDM_LAYER_CAPABILITY_GRAPHIC;
+ *  capabilities = TDM_LAYER_CAPABILITY_OVERLAY | TDM_LAYER_CAPABILITY_GRAPHIC | TDM_LAYER_CAPABILITY_SCALE;
+ *  capabilities = TDM_LAYER_CAPABILITY_OVERLAY | TDM_LAYER_CAPABILITY_GRAPHIC | TDM_LAYER_CAPABILITY_SCALE | TDM_LAYER_CAPABILITY_TRANSFORM;
+ *  capabilities = TDM_LAYER_CAPABILITY_CURSOR | TDM_LAYER_CAPABILITY_GRAPHIC;
+ *  capabilities = TDM_LAYER_CAPABILITY_OVERLAY | TDM_LAYER_CAPABILITY_VIDEO;
+ * @endcode
+ * @remark
+ * - When a video plays, in most of cases, video buffers will be displayed to
+ * a GRAPHIC layer after converting RGB buffers via PP. In this case, a backend
+ * module doesn't need to offer VIDEO layer.
+ * - But in case that s vendor wants to handle a video by their own way,
+ * a backend module offer VIDEO layers. And a display server will pass a video
+ * buffer to a VIDEO layer without converting.
+ */
+typedef enum {
+       TDM_LAYER_CAPABILITY_CURSOR         = (1 << 0), /**< cursor */
+       TDM_LAYER_CAPABILITY_PRIMARY        = (1 << 1), /**< primary */
+       TDM_LAYER_CAPABILITY_OVERLAY        = (1 << 2), /**< overlay */
+       TDM_LAYER_CAPABILITY_GRAPHIC        = (1 << 4), /**< graphic */
+       TDM_LAYER_CAPABILITY_VIDEO          = (1 << 5), /**< video */
+       TDM_LAYER_CAPABILITY_SCALE          = (1 << 8), /**< if a layer has scale capability  */
+       TDM_LAYER_CAPABILITY_TRANSFORM      = (1 << 9), /**< if a layer has transform capability  */
+       TDM_LAYER_CAPABILITY_SCANOUT        = (1 << 10), /**< if a layer allows a scanout buffer only */
+       TDM_LAYER_CAPABILITY_RESEVED_MEMORY = (1 << 11), /**< if a layer allows a reserved buffer only */
+       TDM_LAYER_CAPABILITY_NO_CROP        = (1 << 12), /**< if a layer has no cropping capability */
+} tdm_layer_capability;
+
+/**
+ * @brief The pp capability enumeration
+ */
+typedef enum {
+       TDM_PP_CAPABILITY_SYNC           = (1 << 0), /**< The pp device supports synchronous operation */
+       TDM_PP_CAPABILITY_ASYNC          = (1 << 1), /**< The pp device supports asynchronous operation */
+       TDM_PP_CAPABILITY_SCALE          = (1 << 4), /**< The pp device supports scale operation */
+       TDM_PP_CAPABILITY_TRANSFORM      = (1 << 5), /**< The pp device supports transform operation */
+} tdm_pp_capability;
+
+/**
+ * @brief The capture capability enumeration
+ */
+typedef enum {
+       TDM_CAPTURE_CAPABILITY_OUTPUT    = (1 << 0), /**< The capture device supports to dump a output */
+       TDM_CAPTURE_CAPABILITY_LAYER     = (1 << 1), /**< The capture device supports to dump a layer */
+       TDM_CAPTURE_CAPABILITY_SCALE     = (1 << 4), /**< The capture device supports scale operation */
+       TDM_CAPTURE_CAPABILITY_TRANSFORM = (1 << 5), /**< The capture device supports transform operation */
+} tdm_capture_capability;
+
 /**
  * @brief The output change enumeration of #tdm_output_change_handler
  */
@@ -84,6 +155,30 @@ typedef enum {
        TDM_OUTPUT_CONN_STATUS_MODE_SETTED,  /**< output connected and setted a mode */
 } tdm_output_conn_status;
 
+/**
+ * @brief The output connection status enumeration
+ * @details bit compatible with the libdrm definitions.
+ */
+typedef enum {
+       TDM_OUTPUT_TYPE_Unknown,        /**< unknown */
+       TDM_OUTPUT_TYPE_VGA,            /**< VGA connection */
+       TDM_OUTPUT_TYPE_DVII,           /**< DVII connection */
+       TDM_OUTPUT_TYPE_DVID,           /**< DVID connection */
+       TDM_OUTPUT_TYPE_DVIA,           /**< DVIA connection */
+       TDM_OUTPUT_TYPE_Composite,      /**< Composite connection */
+       TDM_OUTPUT_TYPE_SVIDEO,         /**< SVIDEO connection */
+       TDM_OUTPUT_TYPE_LVDS,           /**< LVDS connection */
+       TDM_OUTPUT_TYPE_Component,      /**< Component connection */
+       TDM_OUTPUT_TYPE_9PinDIN,        /**< 9PinDIN connection */
+       TDM_OUTPUT_TYPE_DisplayPort,    /**< DisplayPort connection */
+       TDM_OUTPUT_TYPE_HDMIA,          /**< HDMIA connection */
+       TDM_OUTPUT_TYPE_HDMIB,          /**< HDMIB connection */
+       TDM_OUTPUT_TYPE_TV,             /**< TV connection */
+       TDM_OUTPUT_TYPE_eDP,            /**< eDP connection */
+       TDM_OUTPUT_TYPE_VIRTUAL,        /**< Virtual connection for WiFi Display */
+       TDM_OUTPUT_TYPE_DSI,            /**< DSI connection */
+} tdm_output_type;
+
 /**
  * @brief The DPMS enumeration
  * @details bit compatible with the libdrm definitions.
@@ -95,6 +190,41 @@ typedef enum {
        TDM_OUTPUT_DPMS_OFF,        /**< Off */
 } tdm_output_dpms;
 
+/**
+ * @brief The output mode type enumeration
+ * @details bit compatible with the libdrm definitions.
+ */
+typedef enum {
+       TDM_OUTPUT_MODE_TYPE_BUILTIN    = (1 << 0),
+       TDM_OUTPUT_MODE_TYPE_CLOCK_C    = ((1 << 1) | TDM_OUTPUT_MODE_TYPE_BUILTIN),
+       TDM_OUTPUT_MODE_TYPE_CRTC_C     = ((1 << 2) | TDM_OUTPUT_MODE_TYPE_BUILTIN),
+       TDM_OUTPUT_MODE_TYPE_PREFERRED  = (1 << 3),
+       TDM_OUTPUT_MODE_TYPE_DEFAULT    = (1 << 4),
+       TDM_OUTPUT_MODE_TYPE_USERDEF    = (1 << 5),
+       TDM_OUTPUT_MODE_TYPE_DRIVER     = (1 << 6),
+} tdm_output_mode_type;
+
+/**
+ * @brief The output mode flag enumeration
+ * @details bit compatible with the libdrm definitions.
+ */
+typedef enum {
+       TDM_OUTPUT_MODE_FLAG_PHSYNC     = (1 << 0),
+       TDM_OUTPUT_MODE_FLAG_NHSYNC     = (1 << 1),
+       TDM_OUTPUT_MODE_FLAG_PVSYNC     = (1 << 2),
+       TDM_OUTPUT_MODE_FLAG_NVSYNC     = (1 << 3),
+       TDM_OUTPUT_MODE_FLAG_INTERLACE  = (1 << 4),
+       TDM_OUTPUT_MODE_FLAG_DBLSCAN    = (1 << 5),
+       TDM_OUTPUT_MODE_FLAG_CSYNC      = (1 << 6),
+       TDM_OUTPUT_MODE_FLAG_PCSYNC     = (1 << 7),
+       TDM_OUTPUT_MODE_FLAG_NCSYNC     = (1 << 8),
+       TDM_OUTPUT_MODE_FLAG_HSKEW      = (1 << 9), /* hskew provided */
+       TDM_OUTPUT_MODE_FLAG_BCAST      = (1 << 10),
+       TDM_OUTPUT_MODE_FLAG_PIXMUX     = (1 << 11),
+       TDM_OUTPUT_MODE_FLAG_DBLCLK     = (1 << 12),
+       TDM_OUTPUT_MODE_FLAG_CLKDIV2    = (1 << 13),
+} tdm_output_mode_flag;
+
 /**
  * @brief The size structure
  */
index e98ad9f43af17eb2de0a515195cd579f3dd6adf0..d52698157f7d24800394d099f7a1ba221a78a43d 100644 (file)
@@ -144,6 +144,16 @@ tdm_error
 tdm_helper_capture_output(tdm_output *output, tbm_surface_h dst_buffer,
                                                  int x, int y, int w, int h,
                                                  tdm_helper_capture_handler func, void *data);
+
+/**
+ * @brief Fill the display information to the reply buffer as string.
+ * @param[in] dpy A display object
+ * @param[out] reply the string buffer to be filled by this function.
+ * @param[out] len the length of the reply buffer
+ */
+void
+tdm_helper_get_display_information(tdm_display *dpy, char *reply, int *len);
+
 #ifdef __cplusplus
 }
 #endif
index 69c27298ff0a4cd7577a7bcd70424bc731cc0a64..19abde501f74da9144a631f18e0f009726312327 100644 (file)
@@ -65,6 +65,7 @@ enum {
 
 void tdm_log_enable_dlog(unsigned int enable);
 void tdm_log_enable_debug(unsigned int enable);
+void tdm_log_set_debug_level(int level);
 void tdm_log_print(int level, const char *fmt, ...);
 
 #define TDM_DBG(fmt, args...) \
index 050dad84ab6f67e1db66f47b2c56952c820f44b8..607364672f356e7a2e989ef61098ae3f00eba44e 100644 (file)
@@ -59,135 +59,6 @@ extern "C" {
 
 #include <tdm_common.h>
 
-/**
- * @brief The transform enumeration(rotate, flip)
- */
-typedef enum {
-       TDM_TRANSFORM_NORMAL            = 0, /**< no transform */
-       TDM_TRANSFORM_90                = 1, /**< rotate 90 */
-       TDM_TRANSFORM_180               = 2, /**< rotate 180 */
-       TDM_TRANSFORM_270               = 3, /**< rotate 270 */
-       TDM_TRANSFORM_FLIPPED           = 4, /**< no rotate and horizontal flip */
-       TDM_TRANSFORM_FLIPPED_90        = 5, /**< rotate 90 and horizontal flip */
-       TDM_TRANSFORM_FLIPPED_180       = 6, /**< rotate 180 and horizontal flip */
-       TDM_TRANSFORM_FLIPPED_270       = 7, /**< rotate 270 and horizontal flip */
-} tdm_transform;
-
-/**
- * @brief The output connection status enumeration
- * @details bit compatible with the libdrm definitions.
- */
-typedef enum {
-       TDM_OUTPUT_TYPE_Unknown,        /**< unknown */
-       TDM_OUTPUT_TYPE_VGA,            /**< VGA connection */
-       TDM_OUTPUT_TYPE_DVII,           /**< DVII connection */
-       TDM_OUTPUT_TYPE_DVID,           /**< DVID connection */
-       TDM_OUTPUT_TYPE_DVIA,           /**< DVIA connection */
-       TDM_OUTPUT_TYPE_Composite,      /**< Composite connection */
-       TDM_OUTPUT_TYPE_SVIDEO,         /**< SVIDEO connection */
-       TDM_OUTPUT_TYPE_LVDS,           /**< LVDS connection */
-       TDM_OUTPUT_TYPE_Component,      /**< Component connection */
-       TDM_OUTPUT_TYPE_9PinDIN,        /**< 9PinDIN connection */
-       TDM_OUTPUT_TYPE_DisplayPort,    /**< DisplayPort connection */
-       TDM_OUTPUT_TYPE_HDMIA,          /**< HDMIA connection */
-       TDM_OUTPUT_TYPE_HDMIB,          /**< HDMIB connection */
-       TDM_OUTPUT_TYPE_TV,             /**< TV connection */
-       TDM_OUTPUT_TYPE_eDP,            /**< eDP connection */
-       TDM_OUTPUT_TYPE_VIRTUAL,        /**< Virtual connection for WiFi Display */
-       TDM_OUTPUT_TYPE_DSI,            /**< DSI connection */
-} tdm_output_type;
-
-/**
- * @brief The layer capability enumeration
- * @details
- * A layer can have one of CURSOR, PRIMARY and OVERLAY capability. And a layer
- * also can have one of GRAPHIC and VIDEO capability. And a layer also can have
- * SCALE and TRANSFORM capability.\n
- * @par Example
- * @code
- *  //For example
- *  capabilities = TDM_LAYER_CAPABILITY_PRIMARY | TDM_LAYER_CAPABILITY_GRAPHIC;
- *  capabilities = TDM_LAYER_CAPABILITY_OVERLAY | TDM_LAYER_CAPABILITY_GRAPHIC | TDM_LAYER_CAPABILITY_SCALE;
- *  capabilities = TDM_LAYER_CAPABILITY_OVERLAY | TDM_LAYER_CAPABILITY_GRAPHIC | TDM_LAYER_CAPABILITY_SCALE | TDM_LAYER_CAPABILITY_TRANSFORM;
- *  capabilities = TDM_LAYER_CAPABILITY_CURSOR | TDM_LAYER_CAPABILITY_GRAPHIC;
- *  capabilities = TDM_LAYER_CAPABILITY_OVERLAY | TDM_LAYER_CAPABILITY_VIDEO;
- * @endcode
- * @remark
- * - When a video plays, in most of cases, video buffers will be displayed to
- * a GRAPHIC layer after converting RGB buffers via PP. In this case, a backend
- * module doesn't need to offer VIDEO layer.
- * - But in case that s vendor wants to handle a video by their own way,
- * a backend module offer VIDEO layers. And a display server will pass a video
- * buffer to a VIDEO layer without converting.
- */
-typedef enum {
-       TDM_LAYER_CAPABILITY_CURSOR         = (1 << 0), /**< cursor */
-       TDM_LAYER_CAPABILITY_PRIMARY        = (1 << 1), /**< primary */
-       TDM_LAYER_CAPABILITY_OVERLAY        = (1 << 2), /**< overlay */
-       TDM_LAYER_CAPABILITY_GRAPHIC        = (1 << 4), /**< graphic */
-       TDM_LAYER_CAPABILITY_VIDEO          = (1 << 5), /**< video */
-       TDM_LAYER_CAPABILITY_SCALE          = (1 << 8), /**< if a layer has scale capability  */
-       TDM_LAYER_CAPABILITY_TRANSFORM      = (1 << 9), /**< if a layer has transform capability  */
-       TDM_LAYER_CAPABILITY_SCANOUT        = (1 << 10), /**< if a layer allows a scanout buffer only */
-       TDM_LAYER_CAPABILITY_RESEVED_MEMORY = (1 << 11), /**< if a layer allows a reserved buffer only */
-       TDM_LAYER_CAPABILITY_NO_CROP        = (1 << 12), /**< if a layer has no cropping capability */
-} tdm_layer_capability;
-
-/**
- * @brief The pp capability enumeration
- */
-typedef enum {
-       TDM_PP_CAPABILITY_SYNC           = (1 << 0), /**< The pp device supports synchronous operation */
-       TDM_PP_CAPABILITY_ASYNC          = (1 << 1), /**< The pp device supports asynchronous operation */
-       TDM_PP_CAPABILITY_SCALE          = (1 << 4), /**< The pp device supports scale operation */
-       TDM_PP_CAPABILITY_TRANSFORM      = (1 << 5), /**< The pp device supports transform operation */
-} tdm_pp_capability;
-
-/**
- * @brief The capture capability enumeration
- */
-typedef enum {
-       TDM_CAPTURE_CAPABILITY_OUTPUT    = (1 << 0), /**< The capture device supports to dump a output */
-       TDM_CAPTURE_CAPABILITY_LAYER     = (1 << 1), /**< The capture device supports to dump a layer */
-       TDM_CAPTURE_CAPABILITY_SCALE     = (1 << 4), /**< The capture device supports scale operation */
-       TDM_CAPTURE_CAPABILITY_TRANSFORM = (1 << 5), /**< The capture device supports transform operation */
-} tdm_capture_capability;
-
-/**
- * @brief The output mode type enumeration
- * @details bit compatible with the libdrm definitions.
- */
-typedef enum {
-       TDM_OUTPUT_MODE_TYPE_BUILTIN    = (1 << 0),
-       TDM_OUTPUT_MODE_TYPE_CLOCK_C    = ((1 << 1) | TDM_OUTPUT_MODE_TYPE_BUILTIN),
-       TDM_OUTPUT_MODE_TYPE_CRTC_C     = ((1 << 2) | TDM_OUTPUT_MODE_TYPE_BUILTIN),
-       TDM_OUTPUT_MODE_TYPE_PREFERRED  = (1 << 3),
-       TDM_OUTPUT_MODE_TYPE_DEFAULT    = (1 << 4),
-       TDM_OUTPUT_MODE_TYPE_USERDEF    = (1 << 5),
-       TDM_OUTPUT_MODE_TYPE_DRIVER     = (1 << 6),
-} tdm_output_mode_type;
-
-/**
- * @brief The output mode flag enumeration
- * @details bit compatible with the libdrm definitions.
- */
-typedef enum {
-       TDM_OUTPUT_MODE_FLAG_PHSYNC     = (1 << 0),
-       TDM_OUTPUT_MODE_FLAG_NHSYNC     = (1 << 1),
-       TDM_OUTPUT_MODE_FLAG_PVSYNC     = (1 << 2),
-       TDM_OUTPUT_MODE_FLAG_NVSYNC     = (1 << 3),
-       TDM_OUTPUT_MODE_FLAG_INTERLACE  = (1 << 4),
-       TDM_OUTPUT_MODE_FLAG_DBLSCAN    = (1 << 5),
-       TDM_OUTPUT_MODE_FLAG_CSYNC      = (1 << 6),
-       TDM_OUTPUT_MODE_FLAG_PCSYNC     = (1 << 7),
-       TDM_OUTPUT_MODE_FLAG_NCSYNC     = (1 << 8),
-       TDM_OUTPUT_MODE_FLAG_HSKEW      = (1 << 9), /* hskew provided */
-       TDM_OUTPUT_MODE_FLAG_BCAST      = (1 << 10),
-       TDM_OUTPUT_MODE_FLAG_PIXMUX     = (1 << 11),
-       TDM_OUTPUT_MODE_FLAG_DBLCLK     = (1 << 12),
-       TDM_OUTPUT_MODE_FLAG_CLKDIV2    = (1 << 13),
-} tdm_output_mode_flag;
-
 typedef enum {
        TDM_EVENT_LOOP_READABLE = (1 << 0),
        TDM_EVENT_LOOP_WRITABLE = (1 << 1),
index 2e6bf7c3c5c04cc41623e97219cde003e2007269..6e1472df642b972249ebdb64e24b8b3186ddaca1 100644 (file)
@@ -92,6 +92,7 @@ rm -f %{_unitdir_user}/default.target.wants/tdm-socket-user.path
 %defattr(-,root,root,-)
 %{TZ_SYS_RO_SHARE}/license/%{name}
 %{_libdir}/libtdm.so.*
+%{_bindir}/tdm-dbg
 %{_unitdir}/tdm-socket.path
 %{_unitdir}/tdm-socket.service
 %{_unitdir_user}/tdm-socket-user.path
@@ -126,6 +127,7 @@ rm -f %{_unitdir_user}/default.target.wants/tdm-socket-user.path
 
 %files tools
 %manifest %{name}.manifest
+%{_bindir}/tdm-test-server
 %{_bindir}/tdm-test-client
 
 %changelog
index cb161b5c2c93dad9575cfb933452894c12f313b1..e3389583802570716fad351fce9c30e712cc6def 100644 (file)
@@ -8,11 +8,19 @@
       TDM uses the wayland protocol to communicate between tdm client and tdm server.
         </description>
 
+        <event name="debug_done">
+            <arg name="message" type="string"/>
+        </event>
+
         <request name="create_output">
             <arg name="name" type="string" summary="output's name. 'primary' or 'default' can be used for default."/>
             <arg name="id" type="new_id" interface="wl_tdm_output"/>
         </request>
 
+        <request name="debug">
+            <arg name="options" type="string" summary="debug options"/>
+        </request>
+
     </interface>
 
     <interface name="wl_tdm_output" version="1">
index 900d3e27d2750c96f8916792cab557edcb124ff2..2af9638fa745d8bf33725dc1a72099727bd848c4 100644 (file)
@@ -22,4 +22,5 @@ libtdm_la_SOURCES = \
        tdm_display.c \
        tdm_pp.c \
        tdm_capture.c \
+       tdm_dbg_server.c \
        tdm.c
index 8a74ae280d57f7581741a1b71f57060654f9e67e..0bbd7a7ce1fdb727604f6ee671464d481ea9e469 100644 (file)
--- a/src/tdm.c
+++ b/src/tdm.c
@@ -386,7 +386,7 @@ _tdm_display_update_layer(tdm_private_display *private_display,
                private_layer = calloc(1, sizeof(tdm_private_layer));
                TDM_RETURN_VAL_IF_FAIL(private_layer != NULL, TDM_ERROR_OUT_OF_MEMORY);
 
-               LIST_ADD(&private_layer->link, &private_output->layer_list);
+               LIST_ADDTAIL(&private_layer->link, &private_output->layer_list);
                private_layer->private_display = private_display;
                private_layer->private_output = private_output;
                private_layer->layer_backend = layer_backend;
@@ -671,6 +671,7 @@ tdm_display_update(tdm_display *dpy)
 int tdm_debug_buffer;
 int tdm_debug_thread;
 int tdm_debug_mutex;
+int tdm_debug_dump;
 
 static tdm_private_display *g_private_display;
 static pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER;
@@ -678,41 +679,47 @@ static pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER;
 static tdm_error
 _tdm_display_check_module(tdm_backend_module *module)
 {
-       const char *name;
-       const char *vendor;
        int major, minor;
 
        TDM_INFO("TDM ABI version : %d.%d",
                         TDM_MAJOR_VERSION, TDM_MINOR_VERSION);
 
-       name = module->name ? module->name : "unknown";
-       vendor = module->vendor ? module->vendor : "unknown";
+       if (!module->name) {
+               TDM_ERR("TDM backend doesn't have name");
+               return TDM_ERROR_BAD_MODULE;
+       }
+
+       if (!module->vendor) {
+               TDM_ERR("TDM backend doesn't have vendor");
+               return TDM_ERROR_BAD_MODULE;
+       }
+
        major = TDM_BACKEND_GET_ABI_MAJOR(module->abi_version);
        minor = TDM_BACKEND_GET_ABI_MINOR(module->abi_version);
 
-       TDM_INFO("TDM module name: %s", name);
-       TDM_INFO("'%s' vendor: %s", name, vendor);
-       TDM_INFO("'%s' version: %d.%d", name, major, minor);
+       TDM_INFO("TDM module name: %s", module->name);
+       TDM_INFO("'%s' vendor: %s", module->name, module->vendor);
+       TDM_INFO("'%s' version: %d.%d", module->name, major, minor);
 
        if (major != TDM_MAJOR_VERSION) {
                TDM_ERR("'%s' major version mismatch, %d != %d",
-                               name, major, TDM_MAJOR_VERSION);
+                               module->name, major, TDM_MAJOR_VERSION);
                return TDM_ERROR_BAD_MODULE;
        }
 
        if (minor > TDM_MINOR_VERSION) {
                TDM_ERR("'%s' minor version(%d) is newer than %d",
-                               name, minor, TDM_MINOR_VERSION);
+                               module->name, minor, TDM_MINOR_VERSION);
                return TDM_ERROR_BAD_MODULE;
        }
 
        if (!module->init) {
-               TDM_ERR("'%s' doesn't have init function", name);
+               TDM_ERR("'%s' doesn't have init function", module->name);
                return TDM_ERROR_BAD_MODULE;
        }
 
        if (!module->deinit) {
-               TDM_ERR("'%s' doesn't have deinit function", name);
+               TDM_ERR("'%s' doesn't have deinit function", module->name);
                return TDM_ERROR_BAD_MODULE;
        }
 
@@ -898,6 +905,10 @@ tdm_display_init(tdm_error *error)
        if (debug && (strstr(debug, "1")))
                tdm_debug_buffer = 1;
 
+       debug = getenv("TDM_DEBUG_DUMP");
+       if (debug)
+               tdm_display_enable_dump(debug);
+
        debug = getenv("TDM_DEBUG_THREAD");
        if (debug && (strstr(debug, "1")))
                tdm_debug_thread = 1;
@@ -1038,3 +1049,42 @@ tdm_display_check_module_abi(tdm_private_display *private_display, int abimaj, i
        return 1;
 }
 
+INTERN void
+tdm_display_enable_debug(char *debug, int enable)
+{
+       if (!strncmp(debug, "TDM_DEBUG_BUFFER", 16))
+               tdm_debug_buffer = enable;
+       else if (!strncmp(debug, "TDM_DEBUG_THREAD", 16))
+               tdm_debug_thread = enable;
+       else if (!strncmp(debug, "TDM_DEBUG_MUTEX", 15))
+               tdm_debug_mutex = enable;
+}
+
+INTERN void
+tdm_display_enable_dump(const char *dump_str)
+{
+       char temp[1024];
+       char *arg;
+       char *end;
+       int flags = 0;
+
+       snprintf(temp, sizeof(temp), "%s", dump_str);
+       arg = strtok_r(temp, ",", &end);
+       while (arg) {
+               if (!strncmp(arg, "all", 3)) {
+                       flags = TDM_DUMP_FLAG_LAYER|TDM_DUMP_FLAG_PP|TDM_DUMP_FLAG_CAPTURE;
+                       break;
+               }
+               else if (!strncmp(arg, "layer", 5))
+                       flags |= TDM_DUMP_FLAG_LAYER;
+               else if (!strncmp(arg, "pp", 2))
+                       flags |= TDM_DUMP_FLAG_PP;
+               else if (!strncmp(arg, "capture", 7))
+                       flags |= TDM_DUMP_FLAG_CAPTURE;
+               else if (!strncmp(arg, "none", 4))
+                       flags = 0;
+               arg = strtok_r(NULL, ",", &end);
+       }
+
+       tdm_debug_dump = flags;
+}
index 8f562ab40b748e902e95586266124533e6475e40..cc79f629223e0a0d9b160cfa9ffffc5f88a4c6f4 100644 (file)
@@ -40,6 +40,7 @@
 #include "tdm.h"
 #include "tdm_backend.h"
 #include "tdm_private.h"
+#include "tdm_helper.h"
 
 #define CAPTURE_FUNC_ENTRY() \
        tdm_func_capture *func_capture; \
@@ -104,6 +105,13 @@ tdm_capture_cb_done(tdm_capture *capture_backend, tbm_surface_h buffer,
        if (private_capture->owner_tid != syscall(SYS_gettid))
                TDM_NEVER_GET_HERE();
 
+       if (tdm_debug_dump & TDM_DUMP_FLAG_CAPTURE) {
+               char str[TDM_PATH_LEN];
+               static int i;
+               snprintf(str, TDM_PATH_LEN, "capture_%03d", i++);
+               tdm_helper_dump_buffer_str(buffer, str);
+       }
+
        if (tdm_debug_buffer)
                TDM_INFO("capture(%p) done: %p", private_capture, buffer);
 
diff --git a/src/tdm_dbg_server.c b/src/tdm_dbg_server.c
new file mode 100644 (file)
index 0000000..76f895f
--- /dev/null
@@ -0,0 +1,409 @@
+/**************************************************************************
+ *
+ * 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.
+ *
+**************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "tdm.h"
+#include "tdm_private.h"
+#include "tdm_helper.h"
+#include "tdm_log.h"
+
+#define TDM_DBG_SERVER_ARGS_MAX                32
+
+static void _tdm_dbg_server_usage(char *app_name, char *reply, int *len);
+
+static void
+_tdm_dbg_server_query(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy)
+{
+       tdm_helper_get_display_information(dpy, reply, len);
+}
+
+static void
+_tdm_dbg_server_dpms(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy)
+{
+       tdm_output *output;
+       int output_idx, dpms_value;
+       char *arg;
+       char *end;
+       tdm_error ret;
+
+       if (argc < 3) {
+               _tdm_dbg_server_usage(argv[0], reply, len);
+               return;
+       }
+
+       arg = argv[2];
+       output_idx = strtol(arg, &end, 10);
+       if (*end != ':') {
+               TDM_SNPRINTF(reply, len, "failed: no onoff value\n");
+               return;
+       }
+
+       arg = end + 1;
+       dpms_value = strtol(arg, &end, 10);
+
+       output = tdm_display_get_output(dpy, output_idx, &ret);
+       TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE && output != NULL);
+
+       ret = tdm_output_set_dpms(output, dpms_value);
+       TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
+
+       TDM_SNPRINTF(reply, len, "done: DPMS %s\n", tdm_dpms_str(dpms_value));
+}
+
+static void
+_tdm_dbg_server_debug(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy)
+{
+       int value;
+       char *arg;
+       char *end;
+
+       if (argc < 3) {
+               _tdm_dbg_server_usage(argv[0], reply, len);
+               return;
+       }
+
+       arg = argv[2];
+       value = strtol(arg, &end, 10);
+
+       tdm_log_set_debug_level(value);
+
+       value = !!value;
+       tdm_log_enable_debug(value);
+
+       TDM_SNPRINTF(reply, len, "debug '%s'\n", (value) ? "on" : "off");
+
+       if (argc > 3) {
+               char temp[TDM_PATH_LEN];
+               char *arg;
+               char *end;
+
+               snprintf(temp, TDM_PATH_LEN, "%s", argv[3]);
+
+               arg = strtok_r(temp, TDM_DELIM, &end);
+               while (arg) {
+                       tdm_display_enable_debug(arg, value);
+                       if (value)
+                               TDM_SNPRINTF(reply, len, "debuging '%s'...\n", arg);
+                       arg = strtok_r(NULL, TDM_DELIM, &end);
+               }
+       }
+}
+
+static void
+_tdm_dbg_server_log_path(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy)
+{
+       static int old_stdout = -1;
+       char fd_name[TDM_PATH_LEN];
+       int  log_fd = -1;
+       FILE *log_fl;
+       char *path;
+
+       if (argc < 3) {
+               _tdm_dbg_server_usage(argv[0], reply, len);
+               return;
+       }
+
+       if (old_stdout == -1)
+               old_stdout = dup(STDOUT_FILENO);
+
+       path = argv[2];
+       TDM_DBG_RETURN_IF_FAIL(path != NULL);
+
+       tdm_log_enable_dlog(0);
+
+       if (!strncmp(path, "dlog", 4)) {
+               tdm_log_enable_dlog(1);
+               goto done;
+       } else if (!strncmp(path, "console", 7))
+               snprintf(fd_name, TDM_PATH_LEN, "/proc/%d/fd/1", pid);
+       else {
+               if (path[0] == '/')
+                       snprintf(fd_name, TDM_PATH_LEN, "%s", path);
+               else {
+                       if (cwd)
+                               snprintf(fd_name, TDM_PATH_LEN, "%s/%s", cwd, path);
+                       else
+                               snprintf(fd_name, TDM_PATH_LEN, "%s", path);
+               }
+       }
+
+       log_fl = fopen(fd_name, "a");
+       if (!log_fl) {
+               TDM_SNPRINTF(reply, len, "failed: open file(%s)\n", fd_name);
+               return;
+       }
+
+       fflush(stderr);
+       close(STDOUT_FILENO);
+
+       setvbuf(log_fl, NULL, _IOLBF, 512);
+       log_fd = fileno(log_fl);
+
+       dup2(log_fd, STDOUT_FILENO);
+       fclose(log_fl);
+done:
+       TDM_SNPRINTF(reply, len, "log path: '%s'\n", path);
+}
+
+static void
+_tdm_dbg_server_prop(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy)
+{
+       tdm_output *output;
+       tdm_output *layer = NULL;
+       int output_idx, layer_idx = -1;
+       int cnt, i, done = 0;
+       tdm_value value;
+       char temp[TDM_PATH_LEN];
+       char *prop_name;
+       char *arg;
+       char *end;
+       tdm_error ret;
+       const tdm_prop *props;
+
+       if (argc < 3) {
+               _tdm_dbg_server_usage(argv[0], reply, len);
+               return;
+       }
+
+       snprintf(temp, TDM_PATH_LEN, "%s", argv[2]);
+       arg = temp;
+
+       output_idx = strtol(arg, &end, 10);
+       if (*end == ',') {
+               arg = end + 1;
+               layer_idx = strtol(arg, &end, 10);
+       }
+
+       if (*end != ':') {
+               TDM_SNPRINTF(reply, len, "failed: no prop_name\n");
+               return;
+       }
+
+       arg = end + 1;
+       prop_name = strtok_r(arg, ",", &end);
+
+       if (*end == '\0') {
+               TDM_SNPRINTF(reply, len, "failed: no value\n");
+               return;
+       }
+
+       arg = strtok_r(NULL, TDM_DELIM, &end);
+       value.u32 = strtol(arg, &end, 10);
+
+       output = tdm_display_get_output(dpy, output_idx, &ret);
+       TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE && output != NULL);
+
+       if (layer_idx != -1) {
+               layer = tdm_output_get_layer(output, layer_idx, &ret);
+               TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE && layer != NULL);
+       }
+
+       if (layer) {
+               ret = tdm_layer_get_available_properties(layer, &props, &cnt);
+               TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
+
+               for (i = 0; i < cnt; i++) {
+                       if (!strncmp(props[i].name, prop_name, TDM_NAME_LEN)) {
+                               ret = tdm_layer_set_property(layer, props[i].id, value);
+                               TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
+                               done = 1;
+                               break;
+                       }
+               }
+       } else {
+               ret = tdm_output_get_available_properties(output, &props, &cnt);
+               TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
+
+               for (i = 0; i < cnt; i++) {
+                       if (!strncmp(props[i].name, prop_name, TDM_NAME_LEN)) {
+                               ret = tdm_output_set_property(output, props[i].id, value);
+                               TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
+                               done = 1;
+                               break;
+                       }
+               }
+       }
+
+       if (done)
+               TDM_SNPRINTF(reply, len, "done: %s:%d \n", prop_name, value.u32);
+       else
+               TDM_SNPRINTF(reply, len, "no '%s' propperty \n", prop_name);
+}
+
+static void
+_tdm_dbg_server_dump(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy)
+{
+       if (argc < 3) {
+               _tdm_dbg_server_usage(argv[0], reply, len);
+               return;
+       }
+
+       tdm_display_enable_dump((const char*)argv[2]);
+
+       TDM_SNPRINTF(reply, len, "%s done\n", argv[2]);
+}
+
+static struct {
+       const char *opt;
+       void (*func)(unsigned int pid, char *cwd, int argc, char *argv[], char *reply, int *len, tdm_display *dpy);
+       const char *desc;
+       const char *arg;
+       const char *ex;
+} option_proc[] = {
+       {
+               "info", _tdm_dbg_server_query,
+               "show tdm output, layer information", NULL, NULL
+       },
+       {
+               "dpms", _tdm_dbg_server_dpms,
+               "set output dpms", "<output_idx>:<dpms>", "0:3 or 0:0"
+       },
+       {
+               "debug", _tdm_dbg_server_debug,
+               "enable the debug level log",
+               "<enable>",
+               "0 or 1"
+       },
+       {
+               "log_path", _tdm_dbg_server_log_path,
+               "set the log path (console,dlog,filepath)",
+               "<path>",
+               "console"
+       },
+       {
+               "prop", _tdm_dbg_server_prop,
+               "set the property of a output or a layer",
+               "<output_idx>[,<layer_idx>]:<prop_name>,<value>",
+               NULL
+       },
+       {
+               "dump", _tdm_dbg_server_dump,
+               "dump buffers (type: layer, pp, capture, none)",
+               "<object_type1>[,<object_type2>[,...]]",
+               NULL
+       },
+};
+
+static void
+_tdm_dbg_server_usage(char *app_name, char *reply, int *len)
+{
+       int opt_size = sizeof(option_proc) / sizeof(option_proc[0]);
+       int i;
+
+       TDM_SNPRINTF(reply, len, "usage: %s \n\n", app_name);
+
+       for (i = 0; i < opt_size; i++) {
+               TDM_SNPRINTF(reply, len, "\t-%s\t%s\n", option_proc[i].opt, option_proc[i].desc);
+               if (option_proc[i].arg)
+                       TDM_SNPRINTF(reply, len, "\t\t  %s\n", option_proc[i].arg);
+               if (option_proc[i].ex)
+                       TDM_SNPRINTF(reply, len, "\t\t  ex) %s\n", option_proc[i].ex);
+               TDM_SNPRINTF(reply, len, "\n");
+       }
+}
+
+static void
+_tdm_dbg_server_command(unsigned int pid, char *cwd, tdm_display *dpy, int argc, char *argv[], char *reply, int *len)
+{
+       int opt_size = sizeof(option_proc) / sizeof(option_proc[0]);
+       int i;
+
+       if (argc < 2) {
+               _tdm_dbg_server_usage(argv[0], reply, len);
+               return;
+       }
+
+       for (i = 0; i < opt_size; i++) {
+               if (argv[1][0] == '-' && !strncmp(argv[1] + 1, option_proc[i].opt, 32)) {
+                       if (option_proc[i].func) {
+                               option_proc[i].func(pid, cwd, argc, argv, reply, len, dpy);
+                               return;
+                       } else {
+                               TDM_SNPRINTF(reply, len, "'%s' not implemented.\n", argv[1]);
+                               return;
+                       }
+               }
+       }
+
+       _tdm_dbg_server_usage(argv[0], reply, len);
+       return;
+}
+
+
+INTERN void
+tdm_dbg_server_command(tdm_display *dpy, const char *options, char *reply, int *len)
+{
+       unsigned int pid;
+       char cwd[1024];
+       int argc = 0;
+       char *argv[TDM_DBG_SERVER_ARGS_MAX] = {0,};
+       char temp[1024];
+       char *arg;
+       char *end = NULL, *e;
+
+       snprintf(temp, sizeof(temp), "%s", options);
+
+       arg = strtok_r(temp, " ", &end);
+       if (!arg) {
+               TDM_SNPRINTF(reply, len, "no pid for tdm-dbg");
+               return;
+       }
+       pid = strtol(arg, &e, 10);
+
+       arg = strtok_r(NULL, " ", &end);
+       if (!arg) {
+               TDM_SNPRINTF(reply, len, "no cwd for tdm-dbg");
+               return;
+       }
+       snprintf(cwd, sizeof(cwd), "%s", arg);
+
+       TDM_DBG("pid(%d) cwd(%s)", pid, cwd);
+
+       argv[argc] = strtok_r(NULL, " ", &end);
+       while (argv[argc]) {
+               argc++;
+               if (argc == TDM_DBG_SERVER_ARGS_MAX) {
+                       TDM_SNPRINTF(reply, len, "too many arguments for tdm-dbg");
+                       break;
+               }
+               argv[argc] = strtok_r(NULL, " ", &end);
+       }
+
+       _tdm_dbg_server_command(pid, cwd, dpy, argc, argv, reply, len);
+}
index fd07d00fe89d598153f744e98f5a4a187e541b41..fd4dff60e23a77bdcfbab98f80879c05d1f492a7 100644 (file)
@@ -355,6 +355,32 @@ tdm_display_handle_events(tdm_display *dpy)
        return ret;
 }
 
+EXTERN tdm_error
+tdm_display_get_backend_info(tdm_display *dpy, const char **name,
+                                                        const char **vendor, int *major, int *minor)
+{
+       tdm_backend_module *module_data;
+
+       DISPLAY_FUNC_ENTRY();
+
+       _pthread_mutex_lock(&private_display->lock);
+
+       module_data = private_display->module_data;
+
+       if (name)
+               *name = module_data->name;
+       if (vendor)
+               *vendor = module_data->vendor;
+       if (major)
+               *major = TDM_BACKEND_GET_ABI_MAJOR(module_data->abi_version);
+       if (minor)
+               *minor = TDM_BACKEND_GET_ABI_MINOR(module_data->abi_version);
+
+       _pthread_mutex_unlock(&private_display->lock);
+
+       return ret;
+}
+
 EXTERN tdm_pp *
 tdm_display_create_pp(tdm_display *dpy, tdm_error *error)
 {
@@ -1430,6 +1456,15 @@ tdm_layer_set_buffer(tdm_layer *layer, tbm_surface_h buffer)
 
        _pthread_mutex_lock(&private_display->lock);
 
+       if (tdm_debug_dump & TDM_DUMP_FLAG_LAYER &&
+               !(private_layer->caps.capabilities & TDM_LAYER_CAPABILITY_VIDEO)) {
+               char str[TDM_PATH_LEN];
+               static int i;
+               snprintf(str, TDM_PATH_LEN, "layer_%d_%d_%03d",
+                                private_output->pipe, private_layer->caps.zpos, i++);
+               tdm_helper_dump_buffer_str(buffer, str);
+       }
+
        func_layer = &private_display->func_layer;
 
        if (private_layer->usable)
@@ -1447,7 +1482,7 @@ tdm_layer_set_buffer(tdm_layer *layer, tbm_surface_h buffer)
        TDM_WARNING_IF_FAIL(ret == TDM_ERROR_NONE);
 
        /* dump buffer */
-       if (tdm_dump_enable)
+       if (tdm_dump_enable && !(private_layer->caps.capabilities & TDM_LAYER_CAPABILITY_VIDEO))
                _tdm_layer_dump_buffer(layer, buffer);
 
        if (ret == TDM_ERROR_NONE) {
index 500bba9e86122f43bc685d72f715bfb692786beb..44968060f2a0556387a2a326b435e50018e3d872 100644 (file)
@@ -379,6 +379,10 @@ _tdm_event_loop_timer_func(void *data)
 
        private_display = timer_source->private_display;
 
+       /* TDM event_loop function is actually for TDM backend module. When we call the
+        * backend's functions, we have to lock the mutex. TDM backend shouldn't consider
+        * mutex things.
+        */
        _pthread_mutex_lock(&private_display->lock);
        timer_source->func(timer_source->user_data);
        _pthread_mutex_unlock(&private_display->lock);
index 4172fe891eb450fd928f8845a71ca53ab7b8cc3f..b9ad2403d167ad45713a9854bb5fd3bac164f48e 100644 (file)
@@ -51,7 +51,7 @@
 
 #define PNG_DEPTH 8
 
-static const char *dump_prefix[2] = {"png", "yuv"};
+static const char *file_exts[2] = {"png", "yuv"};
 
 int tdm_dump_enable;
 
@@ -168,12 +168,41 @@ _tdm_helper_dump_png(const char *file, const void *data, int width,
        fclose(fp);
 }
 
+INTERN void
+tdm_helper_dump_buffer_str(tbm_surface_h buffer, const char *str)
+{
+       tbm_surface_info_s info;
+       const char *dir = "/tmp/dump-tdm";
+       const char *ext;
+       char file[TDM_PATH_LEN];
+       int ret, bw;
+
+       TDM_RETURN_IF_FAIL(buffer != NULL);
+       TDM_RETURN_IF_FAIL(str != NULL);
+
+       ret = tbm_surface_get_info(buffer, &info);
+       TDM_RETURN_IF_FAIL(ret == TBM_SURFACE_ERROR_NONE);
+
+       if (info.format == TBM_FORMAT_ARGB8888 || info.format == TBM_FORMAT_XRGB8888) {
+               ext = file_exts[0];
+               bw = info.planes[0].stride >> 2;
+       } else {
+               ext = file_exts[1];
+               bw = info.planes[0].stride;
+       }
+
+       snprintf(file, TDM_PATH_LEN, "%s/%c%c%c%c_%dx%d_%s.%s",
+                        dir, FOURCC_STR(info.format), bw, info.height, str, ext);
+
+       tdm_helper_dump_buffer(buffer, file);
+}
+
 EXTERN void
 tdm_helper_dump_buffer(tbm_surface_h buffer, const char *file)
 {
        tbm_surface_info_s info;
        int len, ret;
-       const char *prefix;
+       const char *ext;
 
        TDM_RETURN_IF_FAIL(buffer != NULL);
        TDM_RETURN_IF_FAIL(file != NULL);
@@ -183,11 +212,11 @@ tdm_helper_dump_buffer(tbm_surface_h buffer, const char *file)
 
        len = strnlen(file, 1024);
        if (info.format == TBM_FORMAT_ARGB8888 || info.format == TBM_FORMAT_XRGB8888)
-               prefix = dump_prefix[0];
+               ext = file_exts[0];
        else
-               prefix = dump_prefix[1];
+               ext = file_exts[1];
 
-       if (strncmp(file + (len - 3), prefix, 3)) {
+       if (strncmp(file + (len - 3), ext, 3)) {
                TDM_ERR("can't dump to '%s' file", file + (len - 3));
                tbm_surface_unmap(buffer);
                return;
@@ -462,3 +491,233 @@ tdm_helper_capture_output(tdm_output *output, tbm_surface_h dst_buffer,
        return TDM_ERROR_NONE;
 }
 
+EXTERN void
+tdm_helper_get_display_information(tdm_display *dpy, char *reply, int *len)
+{
+       const char *name, *vendor;
+       int major, minor;
+       tdm_error ret;
+       int i, count;
+       tdm_output *output;
+       const tdm_prop *props;
+       int min_w, min_h, max_w, max_h, preferred_align;
+       const tbm_format *formats;
+       tdm_display_capability display_caps;
+
+       ret = tdm_display_get_backend_info(dpy, &name, &vendor, &major, &minor);
+       TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
+
+       TDM_SNPRINTF(reply, len, "TDM backend name: %s\n", name);
+       TDM_SNPRINTF(reply, len, "TDM backend vendor: %s\n", vendor);
+       TDM_SNPRINTF(reply, len, "TDM backend version: %d.%d\n\n", major, minor);
+
+       ret =  tdm_display_get_output_count(dpy, &count);
+       TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
+
+       TDM_SNPRINTF(reply, len, "[Output information]\n");
+       TDM_SNPRINTF(reply, len, "-------------------------------------------------------------------------------------------\n");
+       TDM_SNPRINTF(reply, len, "idx   maker   model   name   type   status   dpms   subpix   prefer   min   max   phy\n");
+       TDM_SNPRINTF(reply, len, "-------------------------------------------------------------------------------------------\n");
+
+       for (i = 0; i < count; i++) {
+               /* idx  maker  model  name  type  status  dpms  subpix  prefer  min  max  phy */
+               const char *maker, *model, *name;
+               tdm_output_type type;
+               tdm_output_conn_status status;
+               unsigned int subpixel;
+               unsigned int mmWidth, mmHeight;
+               tdm_output_dpms dpms;
+               const tdm_output_mode *mode, *modes;
+               int j, cnt;
+
+               output = tdm_display_get_output(dpy, i, &ret);
+               TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
+               ret = tdm_output_get_model_info(output, &maker, &model, &name);
+               TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
+               ret = tdm_output_get_output_type(output, &type);
+               TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
+               ret = tdm_output_get_conn_status(output, &status);
+               TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
+               ret = tdm_output_get_dpms(output, &dpms);
+               TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
+               ret = tdm_output_get_subpixel(output, &subpixel);
+               TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
+               ret = tdm_output_get_available_size(output, &min_w, &min_h, &max_w, &max_h, &preferred_align);
+               TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
+               ret = tdm_output_get_physical_size(output, &mmWidth, &mmHeight);
+               TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
+
+               TDM_SNPRINTF(reply, len, "%d   %s   %s   %s   %s   %s   %s   %d   %d   %dx%d   %dx%d   %dx%d\n",
+                                        i, maker, model, name, tdm_conn_str(type), tdm_status_str(status),
+                                        tdm_dpms_str(dpms), subpixel, preferred_align,
+                                        min_w, min_h, max_w, max_h, mmWidth, mmHeight);
+
+               ret = tdm_output_get_mode(output, &mode);
+               TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
+
+               ret = tdm_output_get_available_modes(output, &modes, &cnt);
+               TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
+
+               TDM_SNPRINTF(reply, len, "\t%d modes:\n", cnt);
+
+               if (cnt > 0) {
+                       TDM_SNPRINTF(reply, len, "\t\tname refresh (Hz) hdisp hss hse htot vdisp vss vse vtot\n");
+                       for (j = 0; j < cnt; j++) {
+                               char *current = (mode == modes + j) ? "*" : " ";
+                               TDM_SNPRINTF(reply, len, "\t\t%s%s %d %d %d %d %d %d %d %d %d ",
+                                                        current,
+                                                        modes[j].name,
+                                                        modes[j].vrefresh,
+                                                        modes[j].hdisplay,
+                                                        modes[j].hsync_start,
+                                                        modes[j].hsync_end,
+                                                        modes[j].htotal,
+                                                        modes[j].vdisplay,
+                                                        modes[j].vsync_start,
+                                                        modes[j].vsync_end,
+                                                        modes[j].vtotal);
+                               tdm_mode_flag_str(modes[j].flags, &reply, len);
+                               TDM_SNPRINTF(reply, len, " ");
+                               tdm_mode_type_str(modes[j].type, &reply, len);
+                               TDM_SNPRINTF(reply, len, "\n");
+                       }
+               }
+
+               ret = tdm_output_get_available_properties(output, &props, &cnt);
+               TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
+
+               TDM_SNPRINTF(reply, len, "\t%d properties:\n", cnt);
+               if (cnt > 0) {
+                       TDM_SNPRINTF(reply, len, "\t\tname idx value\n");
+                       for (j = 0; j < cnt; j++) {
+                               tdm_value value;
+                               ret = tdm_output_get_property(output, props[j].id, &value);
+                               TDM_SNPRINTF(reply, len, "\t\t%s %d %d\n",
+                                                        props[j].name,
+                                                        props[j].id,
+                                                        value.u32);
+                       }
+               }
+               TDM_SNPRINTF(reply, len, "\n");
+       }
+
+       TDM_SNPRINTF(reply, len, "[Layer information]\n");
+       for (i = 0; i < count; i++) {
+               int j, cnt;
+
+               output = tdm_display_get_output(dpy, i, &ret);
+               TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
+
+               ret = tdm_output_get_layer_count(output, &cnt);
+               TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
+
+               if (cnt > 0) {
+                       TDM_SNPRINTF(reply, len, "-----------------------------------------------------\n");
+                       TDM_SNPRINTF(reply, len, "idx   output   zpos   buf   info   caps\n");
+                       TDM_SNPRINTF(reply, len, "-----------------------------------------------------\n");
+                       for (j = 0; j < cnt; j++) {
+                               tdm_layer *layer;
+                               tbm_surface_h buf;
+                               tdm_layer_capability layer_caps;
+                               int k, c, zpos;
+                               tdm_info_layer info;
+
+                               memset(&info, 0, sizeof info);
+
+                               layer = tdm_output_get_layer(output, j, &ret);
+                               TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
+                               ret = tdm_layer_get_capabilities(layer, &layer_caps);
+                               TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
+                               ret = tdm_layer_get_zpos(layer, &zpos);
+                               TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
+
+                               ret = tdm_layer_get_info(layer, &info);
+                               buf = tdm_layer_get_displaying_buffer(layer, &ret);
+
+                               if (info.src_config.format)
+                                       TDM_SNPRINTF(reply, len, "%d   %d   %d   %p   %c%c%c%c %dx%d (%d,%d %dx%d) (%d,%d %dx%d) trans(%d)   ",
+                                                                j, i, zpos, buf,
+                                                                FOURCC_STR(info.src_config.format), info.src_config.size.h, info.src_config.size.v,
+                                                                info.src_config.pos.x, info.src_config.pos.y, info.src_config.pos.w, info.src_config.pos.h,
+                                                                info.dst_pos.x, info.dst_pos.y, info.dst_pos.w, info.dst_pos.h,
+                                                                info.transform);
+                               else
+                                       TDM_SNPRINTF(reply, len, "%d   %d   %d   %p   %c%c%c%c %dx%d (%d,%d %dx%d) (%d,%d %dx%d) trans(%d)   ",
+                                                                j, i, zpos, buf,
+                                                                'N', 'O', 'N', 'E', info.src_config.size.h, info.src_config.size.v,
+                                                                info.src_config.pos.x, info.src_config.pos.y, info.src_config.pos.w, info.src_config.pos.h,
+                                                                info.dst_pos.x, info.dst_pos.y, info.dst_pos.w, info.dst_pos.h,
+                                                                info.transform);
+                               tdm_layer_caps_str(layer_caps, &reply, len);
+                               TDM_SNPRINTF(reply, len, "\n");
+
+                               ret = tdm_layer_get_available_properties(layer, &props, &c);
+                               TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
+                               TDM_SNPRINTF(reply, len, "\t%d properties:\n", c);
+                               if (c > 0) {
+                                       TDM_SNPRINTF(reply, len, "\t\tname idx value\n");
+                                       for (k = 0; k < c; k++) {
+                                               tdm_value value;
+                                               ret = tdm_layer_get_property(layer, props[k].id, &value);
+                                               TDM_SNPRINTF(reply, len, "\t\t%s %d %d\n",
+                                                                        props[k].name,
+                                                                        props[k].id,
+                                                                        value.u32);
+                                       }
+                               }
+
+                               ret = tdm_layer_get_available_formats(layer, &formats, &c);
+                               TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
+                               TDM_SNPRINTF(reply, len, "\tformats:");
+                               for (k = 0; k < c; k++)
+                                       TDM_SNPRINTF(reply, len, " %c%c%c%c", FOURCC_STR(formats[k]));
+                               TDM_SNPRINTF(reply, len, "\n");
+                       }
+               }
+       }
+
+       TDM_SNPRINTF(reply, len, "\n");
+
+       ret = tdm_display_get_capabilities(dpy, &display_caps);
+       TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
+
+       if (display_caps & TDM_DISPLAY_CAPABILITY_PP) {
+               tdm_pp_capability pp_caps;
+
+               ret = tdm_display_get_pp_capabilities(dpy, &pp_caps);
+               TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
+               ret = tdm_display_get_pp_available_formats(dpy, &formats, &count);
+               TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
+               ret = tdm_display_get_pp_available_size(dpy, &min_w, &min_h, &max_w, &max_h, &preferred_align);
+               TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
+
+               TDM_SNPRINTF(reply, len, "[PP information]\n");
+               TDM_SNPRINTF(reply, len, "caps: ");
+               tdm_pp_caps_str(pp_caps, &reply, len);
+               TDM_SNPRINTF(reply, len, "\n");
+               TDM_SNPRINTF(reply, len, "formats: ");
+               for (i = 0; i < count; i++)
+                       TDM_SNPRINTF(reply, len, " %c%c%c%c", FOURCC_STR(formats[i]));
+               TDM_SNPRINTF(reply, len, "\n");
+               TDM_SNPRINTF(reply, len, "size: min(%dx%d) max(%dx%d) preferred(%d)\n",
+                                        min_w, min_h, max_w, max_h, preferred_align);
+       }
+
+       if (display_caps & TDM_DISPLAY_CAPABILITY_CAPTURE) {
+               tdm_capture_capability capture_caps;
+
+               ret = tdm_display_get_capture_capabilities(dpy, &capture_caps);
+               TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
+               ret = tdm_display_get_catpure_available_formats(dpy, &formats, &count);
+               TDM_DBG_RETURN_IF_FAIL(ret == TDM_ERROR_NONE);
+
+               TDM_SNPRINTF(reply, len, "[Capture information]\n");
+               TDM_SNPRINTF(reply, len, "caps: ");
+               tdm_capture_caps_str(capture_caps, &reply, len);
+               TDM_SNPRINTF(reply, len, "\n");
+               TDM_SNPRINTF(reply, len, "formats: ");
+               for (i = 0; i < count; i++)
+                       TDM_SNPRINTF(reply, len, " %c%c%c%c", FOURCC_STR(formats[i]));
+               TDM_SNPRINTF(reply, len, "\n");
+       }
+}
index 3983c6816fe15bb1028d26e4d350016b3b16045e..d56267df2801fdc0dcf588e6c74ba34b9ee86e43 100644 (file)
 #include <sys/types.h>
 
 #include <tdm_common.h>
+#include <tbm_surface.h>
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+#define TDM_SERVER_REPLY_MSG_LEN       8192
+
 #undef EXTERN
 #undef DEPRECATED
 #undef INTERN
@@ -101,6 +104,12 @@ extern "C" {
                goto dst; \
        } \
 }
+#define TDM_EXIT_IF_FAIL(cond) { \
+       if (!(cond)) { \
+               TDM_ERR("'%s' failed", #cond); \
+               exit(0); \
+       } \
+}
 
 #define TDM_NEVER_GET_HERE() TDM_WRN("** NEVER GET HERE **")
 
@@ -113,12 +122,23 @@ extern "C" {
                } \
        } while (0)
 
+#define TDM_DBG_RETURN_IF_FAIL(cond) { \
+       if (!(cond))  { \
+               TDM_SNPRINTF(reply, len, "[%s %d] '%s' failed\n", __func__, __LINE__, #cond); \
+               return; \
+       } \
+}
+
 #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])
+#define IS_RGB(f)           ((f) == TBM_FORMAT_XRGB8888 || (f) == TBM_FORMAT_ARGB8888)
 
+/* don't using !,$,# */
+#define TDM_DELIM           "@^&*+-|,:~"
+#define TDM_ALIGN(a, b)     (((a) + ((b) - 1)) & ~((b) - 1))
 
 #define TDM_ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
 
@@ -144,7 +164,6 @@ static struct tdm_type_name tdm_dpms_names[] = {
        { TDM_OUTPUT_DPMS_SUSPEND, "suspend" },
        { TDM_OUTPUT_DPMS_OFF, "off" },
 };
-
 TDM_TYPE_NAME_FN(dpms)
 
 static struct tdm_type_name tdm_status_names[] = {
@@ -152,9 +171,121 @@ static struct tdm_type_name tdm_status_names[] = {
        { TDM_OUTPUT_CONN_STATUS_CONNECTED, "connected" },
        { TDM_OUTPUT_CONN_STATUS_MODE_SETTED, "mode_setted" },
 };
-
 TDM_TYPE_NAME_FN(status)
 
+static struct tdm_type_name tdm_conn_names[] = {
+       { TDM_OUTPUT_TYPE_Unknown, "Unknown" },
+       { TDM_OUTPUT_TYPE_VGA, "VGA" },
+       { TDM_OUTPUT_TYPE_DVII, "DVII" },
+       { TDM_OUTPUT_TYPE_DVID, "DVID" },
+       { TDM_OUTPUT_TYPE_DVIA, "DVIA" },
+       { TDM_OUTPUT_TYPE_Composite, "Composite" },
+       { TDM_OUTPUT_TYPE_SVIDEO, "SVIDEO" },
+       { TDM_OUTPUT_TYPE_LVDS, "LVDS" },
+       { TDM_OUTPUT_TYPE_Component, "Component" },
+       { TDM_OUTPUT_TYPE_9PinDIN, "9PinDIN" },
+       { TDM_OUTPUT_TYPE_DisplayPort, "DisplayPort" },
+       { TDM_OUTPUT_TYPE_HDMIA, "HDMIA" },
+       { TDM_OUTPUT_TYPE_HDMIB, "HDMIB" },
+       { TDM_OUTPUT_TYPE_TV, "TV" },
+       { TDM_OUTPUT_TYPE_eDP, "eDP" },
+       { TDM_OUTPUT_TYPE_VIRTUAL, "VIRTUAL" },
+       { TDM_OUTPUT_TYPE_DSI, "DSI" },
+};
+TDM_TYPE_NAME_FN(conn)
+
+
+#define TDM_BIT_NAME_FB(res)                                   \
+static inline const char * tdm_##res##_str(int type, char **reply, int *len)   \
+{                      \
+       unsigned int i;                                         \
+       const char *sep = "";                                   \
+       for (i = 0; i < TDM_ARRAY_SIZE(tdm_##res##_names); i++) {               \
+               if (type & (1 << i)) {                          \
+                       TDM_SNPRINTF(*reply, len, "%s%s", sep, tdm_##res##_names[i]);   \
+                       sep = ",";                              \
+               }                                               \
+       }                                                       \
+       return NULL;                                            \
+}
+
+static const char *tdm_mode_type_names[] = {
+       "builtin",
+       "clock_c",
+       "crtc_c",
+       "preferred",
+       "default",
+       "userdef",
+       "driver",
+};
+TDM_BIT_NAME_FB(mode_type)
+
+static const char *tdm_mode_flag_names[] = {
+       "phsync",
+       "nhsync",
+       "pvsync",
+       "nvsync",
+       "interlace",
+       "dblscan",
+       "csync",
+       "pcsync",
+       "ncsync",
+       "hskew",
+       "bcast",
+       "pixmux",
+       "dblclk",
+       "clkdiv2"
+};
+TDM_BIT_NAME_FB(mode_flag)
+
+static const char *tdm_layer_caps_names[] = {
+       "cursor",
+       "primary",
+       "overlay",
+       "",
+       "graphic",
+       "video",
+       "",
+       "",
+       "scale",
+       "transform",
+       "scanout",
+       "reserved",
+       "no_crop",
+};
+TDM_BIT_NAME_FB(layer_caps)
+
+static const char *tdm_pp_caps_names[] = {
+       "sync",
+       "async",
+       "scale",
+       "transform",
+};
+TDM_BIT_NAME_FB(pp_caps)
+
+static const char *tdm_capture_caps_names[] = {
+       "output",
+       "layer",
+       "scale",
+       "transform",
+};
+TDM_BIT_NAME_FB(capture_caps)
+
+static inline char*
+strtostr(char *buf, int len, char *str, char *delim)
+{
+       char *end;
+       end = strpbrk(str, delim);
+       if (end)
+               len = ((end - str + 1) < len) ? (end - str + 1) : len;
+       else {
+               int l = strlen(str);
+               len = ((l + 1) < len) ? (l + 1) : len;
+       }
+       snprintf(buf, len, "%s", str);
+       return str + len - 1;
+}
+
 #ifdef __cplusplus
 }
 #endif
index 17ea9df1e6ac8d3b107da606e5e1b458b1ba65d9..91a1239e09babb2ffef7eaa07010f1e117783221 100644 (file)
@@ -40,6 +40,7 @@
 #include "tdm.h"
 #include "tdm_backend.h"
 #include "tdm_private.h"
+#include "tdm_helper.h"
 
 typedef struct _tdm_pp_private_buffer {
        tbm_surface_h src;
@@ -136,6 +137,13 @@ tdm_pp_cb_done(tdm_pp *pp_backend, tbm_surface_h src, tbm_surface_h dst,
        if (private_pp->owner_tid != syscall(SYS_gettid))
                TDM_NEVER_GET_HERE();
 
+       if (tdm_debug_dump & TDM_DUMP_FLAG_PP) {
+               char str[TDM_PATH_LEN];
+               static int i;
+               snprintf(str, TDM_PATH_LEN, "pp_dst_%03d", i++);
+               tdm_helper_dump_buffer_str(dst, str);
+       }
+
        if (tdm_debug_buffer)
                TDM_INFO("pp(%p) done: src(%p) dst(%p)", private_pp, src, dst);
 
@@ -363,6 +371,13 @@ tdm_pp_attach(tdm_pp *pp, tbm_surface_h src, tbm_surface_h dst)
                }
        }
 
+       if (tdm_debug_dump & TDM_DUMP_FLAG_PP) {
+               char str[TDM_PATH_LEN];
+               static int i;
+               snprintf(str, TDM_PATH_LEN, "pp_src_%03d", i++);
+               tdm_helper_dump_buffer_str(src, str);
+       }
+
        pp_buffer = calloc(1, sizeof *pp_buffer);
        if (!pp_buffer) {
                _pthread_mutex_unlock(&private_display->lock);
index a9ad25e58f25db3e12cd5942a9adcd4223a0f7a8..b2b61e64f54d44b2f5be449a2c75d444bd400099 100644 (file)
@@ -76,6 +76,7 @@ extern "C" {
 extern int tdm_debug_buffer;
 extern int tdm_debug_mutex;
 extern int tdm_debug_thread;
+extern int tdm_debug_dump;
 
 #ifdef HAVE_TTRACE
 #include <ttrace.h>
@@ -91,6 +92,12 @@ typedef enum {
        TDM_CAPTURE_TARGET_LAYER,
 } tdm_capture_target;
 
+enum {
+       TDM_DUMP_FLAG_LAYER   = (1 << 0),
+       TDM_DUMP_FLAG_PP      = (1 << 1),
+       TDM_DUMP_FLAG_CAPTURE = (1 << 2),
+};
+
 typedef struct _tdm_private_display tdm_private_display;
 typedef struct _tdm_private_output tdm_private_output;
 typedef struct _tdm_private_layer tdm_private_layer;
@@ -446,6 +453,8 @@ tdm_server_init(tdm_private_loop *private_loop);
 void
 tdm_server_deinit(tdm_private_loop *private_loop);
 
+void
+tdm_helper_dump_buffer_str(tbm_surface_h buffer, const char *str);
 unsigned long
 tdm_helper_get_time_in_millis(void);
 unsigned long
@@ -513,7 +522,10 @@ static inline int TDM_MUTEX_IS_LOCKED(void)
 tdm_error
 tdm_display_update_output(tdm_private_display *private_display,
                                                  tdm_output *output_backend, int pipe);
-
+void
+tdm_display_enable_debug(char *debug, int enable);
+void
+tdm_display_enable_dump(const char *dump_str);
 
 /**
  * @brief The tdm vblank object
@@ -536,6 +548,9 @@ tdm_vblank_set_enable_fake(tdm_vblank *vblank, unsigned int enable_fake);
 tdm_error
 tdm_vblank_wait(tdm_vblank *vblank, unsigned int req_sec, unsigned int req_usec, unsigned int interval, tdm_vblank_handler func, void *user_data);
 
+void
+tdm_dbg_server_command(tdm_display *dpy, const char *options, char *reply, int *len);
+
 #ifdef __cplusplus
 }
 #endif
index 7c18228fdcfe1a867e52d2cc7b4c2698ca4afaae..a20984f41a7daea96d61abaf53c7c970f3a92b6f 100644 (file)
@@ -413,8 +413,22 @@ _tdm_server_cb_create_output(struct wl_client *client, struct wl_resource *resou
        wl_tdm_output_send_connection(output_resource, status);
 }
 
+static void
+_tdm_server_cb_debug(struct wl_client *client, struct wl_resource *resource, const char *options)
+{
+       tdm_private_server *private_server = wl_resource_get_user_data(resource);
+       tdm_private_loop *private_loop = private_server->private_loop;
+
+       char message[TDM_SERVER_REPLY_MSG_LEN];
+       int size = sizeof(message);
+
+       tdm_dbg_server_command(private_loop->dpy, options, message, &size);
+       wl_tdm_send_debug_done(resource, message);
+}
+
 static const struct wl_tdm_interface tdm_implementation = {
        _tdm_server_cb_create_output,
+       _tdm_server_cb_debug,
 };
 
 static void
index 05edfb585b3cae2d8abccedbcf1989ff4cfed932..2057e4a905c26a651a85d0cd8b58023080a665b1 100644 (file)
@@ -1,9 +1,23 @@
 bin_PROGRAMS = \
+       tdm-test-server \
        tdm-test-client
 
+#tdm-test-server
+tdm_test_server_SOURCES = \
+       buffers.c \
+       tdm_test_server.c
+tdm_test_server_LDFLAGS = ${LDFLAGS}
+tdm_test_server_CFLAGS = \
+       $(TDM_CFLAGS) \
+       -I$(top_srcdir)/include \
+       -I$(top_srcdir)/src
+tdm_test_server_LDADD = \
+       $(TDM_LIBS) \
+       $(top_builddir)/src/libtdm.la
+
+#tdm-test-cliet
 tdm_test_client_SOURCES = \
        tdm_test_client.c
-
 tdm_test_client_LDFLAGS = ${LDFLAGS}
 tdm_test_client_CFLAGS = \
        $(TDM_CFLAGS) \
diff --git a/tools/buffers.c b/tools/buffers.c
new file mode 100644 (file)
index 0000000..53ed615
--- /dev/null
@@ -0,0 +1,950 @@
+/*
+ * DRM based mode setting test program
+ * Copyright 2008 Tungsten Graphics
+ *   Jakob Bornecrantz <jakob@tungstengraphics.com>
+ * Copyright 2008 Intel Corporation
+ *   Jesse Barnes <jesse.barnes@intel.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, 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 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 <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <string.h>
+#include <time.h>
+#include <math.h>
+
+#include <tbm_bufmgr.h>
+#include <tbm_surface.h>
+
+#include <tdm_log.h>
+#include "tdm_macro.h"
+#include "buffers.h"
+
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+
+/* -----------------------------------------------------------------------------
+ * Formats
+ */
+
+struct color_component {
+       unsigned int length;
+       unsigned int offset;
+};
+
+struct rgb_info {
+       struct color_component red;
+       struct color_component green;
+       struct color_component blue;
+       struct color_component alpha;
+};
+
+enum yuv_order {
+       YUV_YCbCr = 1,
+       YUV_YCrCb = 2,
+       YUV_YC = 4,
+       YUV_CY = 8,
+};
+
+struct yuv_info {
+       enum yuv_order order;
+       unsigned int xsub;
+       unsigned int ysub;
+       unsigned int chroma_stride;
+};
+
+struct format_info {
+       unsigned int format;
+       const char *name;
+       const struct rgb_info rgb;
+       const struct yuv_info yuv;
+};
+
+#define MAKE_RGB_INFO(rl, ro, bl, bo, gl, go, al, ao) \
+       .rgb = { { (rl), (ro) }, { (bl), (bo) }, { (gl), (go) }, { (al), (ao) } }
+
+#define MAKE_YUV_INFO(order, xsub, ysub, chroma_stride) \
+       .yuv = { (order), (xsub), (ysub), (chroma_stride) }
+
+static const struct format_info format_info[] = {
+       /* YUV packed */
+       { TBM_FORMAT_UYVY, "UYVY", MAKE_YUV_INFO(YUV_YCbCr | YUV_CY, 2, 2, 2) },
+       { TBM_FORMAT_VYUY, "VYUY", MAKE_YUV_INFO(YUV_YCrCb | YUV_CY, 2, 2, 2) },
+       { TBM_FORMAT_YUYV, "YUYV", MAKE_YUV_INFO(YUV_YCbCr | YUV_YC, 2, 2, 2) },
+       { TBM_FORMAT_YVYU, "YVYU", MAKE_YUV_INFO(YUV_YCrCb | YUV_YC, 2, 2, 2) },
+       /* YUV semi-planar */
+       { TBM_FORMAT_NV12, "NV12", MAKE_YUV_INFO(YUV_YCbCr, 2, 2, 2) },
+       { TBM_FORMAT_NV21, "NV21", MAKE_YUV_INFO(YUV_YCrCb, 2, 2, 2) },
+       { TBM_FORMAT_NV16, "NV16", MAKE_YUV_INFO(YUV_YCbCr, 2, 1, 2) },
+       { TBM_FORMAT_NV61, "NV61", MAKE_YUV_INFO(YUV_YCrCb, 2, 1, 2) },
+       /* YUV planar */
+       { TBM_FORMAT_YUV420, "YU12", MAKE_YUV_INFO(YUV_YCbCr, 2, 2, 1) },
+       { TBM_FORMAT_YVU420, "YV12", MAKE_YUV_INFO(YUV_YCrCb, 2, 2, 1) },
+       /* RGB16 */
+       { TBM_FORMAT_ARGB4444, "AR12", MAKE_RGB_INFO(4, 8, 4, 4, 4, 0, 4, 12) },
+       { TBM_FORMAT_XRGB4444, "XR12", MAKE_RGB_INFO(4, 8, 4, 4, 4, 0, 0, 0) },
+       { TBM_FORMAT_ABGR4444, "AB12", MAKE_RGB_INFO(4, 0, 4, 4, 4, 8, 4, 12) },
+       { TBM_FORMAT_XBGR4444, "XB12", MAKE_RGB_INFO(4, 0, 4, 4, 4, 8, 0, 0) },
+       { TBM_FORMAT_RGBA4444, "RA12", MAKE_RGB_INFO(4, 12, 4, 8, 4, 4, 4, 0) },
+       { TBM_FORMAT_RGBX4444, "RX12", MAKE_RGB_INFO(4, 12, 4, 8, 4, 4, 0, 0) },
+       { TBM_FORMAT_BGRA4444, "BA12", MAKE_RGB_INFO(4, 4, 4, 8, 4, 12, 4, 0) },
+       { TBM_FORMAT_BGRX4444, "BX12", MAKE_RGB_INFO(4, 4, 4, 8, 4, 12, 0, 0) },
+       { TBM_FORMAT_ARGB1555, "AR15", MAKE_RGB_INFO(5, 10, 5, 5, 5, 0, 1, 15) },
+       { TBM_FORMAT_XRGB1555, "XR15", MAKE_RGB_INFO(5, 10, 5, 5, 5, 0, 0, 0) },
+       { TBM_FORMAT_ABGR1555, "AB15", MAKE_RGB_INFO(5, 0, 5, 5, 5, 10, 1, 15) },
+       { TBM_FORMAT_XBGR1555, "XB15", MAKE_RGB_INFO(5, 0, 5, 5, 5, 10, 0, 0) },
+       { TBM_FORMAT_RGBA5551, "RA15", MAKE_RGB_INFO(5, 11, 5, 6, 5, 1, 1, 0) },
+       { TBM_FORMAT_RGBX5551, "RX15", MAKE_RGB_INFO(5, 11, 5, 6, 5, 1, 0, 0) },
+       { TBM_FORMAT_BGRA5551, "BA15", MAKE_RGB_INFO(5, 1, 5, 6, 5, 11, 1, 0) },
+       { TBM_FORMAT_BGRX5551, "BX15", MAKE_RGB_INFO(5, 1, 5, 6, 5, 11, 0, 0) },
+       { TBM_FORMAT_RGB565, "RG16", MAKE_RGB_INFO(5, 11, 6, 5, 5, 0, 0, 0) },
+       { TBM_FORMAT_BGR565, "BG16", MAKE_RGB_INFO(5, 0, 6, 5, 5, 11, 0, 0) },
+       /* RGB24 */
+       { TBM_FORMAT_BGR888, "BG24", MAKE_RGB_INFO(8, 0, 8, 8, 8, 16, 0, 0) },
+       { TBM_FORMAT_RGB888, "RG24", MAKE_RGB_INFO(8, 16, 8, 8, 8, 0, 0, 0) },
+       /* RGB32 */
+       { TBM_FORMAT_ARGB8888, "AR24", MAKE_RGB_INFO(8, 16, 8, 8, 8, 0, 8, 24) },
+       { TBM_FORMAT_XRGB8888, "XR24", MAKE_RGB_INFO(8, 16, 8, 8, 8, 0, 0, 0) },
+       { TBM_FORMAT_ABGR8888, "AB24", MAKE_RGB_INFO(8, 0, 8, 8, 8, 16, 8, 24) },
+       { TBM_FORMAT_XBGR8888, "XB24", MAKE_RGB_INFO(8, 0, 8, 8, 8, 16, 0, 0) },
+       { TBM_FORMAT_RGBA8888, "RA24", MAKE_RGB_INFO(8, 24, 8, 16, 8, 8, 8, 0) },
+       { TBM_FORMAT_RGBX8888, "RX24", MAKE_RGB_INFO(8, 24, 8, 16, 8, 8, 0, 0) },
+       { TBM_FORMAT_BGRA8888, "BA24", MAKE_RGB_INFO(8, 8, 8, 16, 8, 24, 8, 0) },
+       { TBM_FORMAT_BGRX8888, "BX24", MAKE_RGB_INFO(8, 8, 8, 16, 8, 24, 0, 0) },
+       { TBM_FORMAT_ARGB2101010, "AR30", MAKE_RGB_INFO(10, 20, 10, 10, 10, 0, 2, 30) },
+       { TBM_FORMAT_XRGB2101010, "XR30", MAKE_RGB_INFO(10, 20, 10, 10, 10, 0, 0, 0) },
+       { TBM_FORMAT_ABGR2101010, "AB30", MAKE_RGB_INFO(10, 0, 10, 10, 10, 20, 2, 30) },
+       { TBM_FORMAT_XBGR2101010, "XB30", MAKE_RGB_INFO(10, 0, 10, 10, 10, 20, 0, 0) },
+       { TBM_FORMAT_RGBA1010102, "RA30", MAKE_RGB_INFO(10, 22, 10, 12, 10, 2, 2, 0) },
+       { TBM_FORMAT_RGBX1010102, "RX30", MAKE_RGB_INFO(10, 22, 10, 12, 10, 2, 0, 0) },
+       { TBM_FORMAT_BGRA1010102, "BA30", MAKE_RGB_INFO(10, 2, 10, 12, 10, 22, 2, 0) },
+       { TBM_FORMAT_BGRX1010102, "BX30", MAKE_RGB_INFO(10, 2, 10, 12, 10, 22, 0, 0) },
+};
+
+unsigned int format_fourcc(const char *name)
+{
+       unsigned int i;
+       for (i = 0; i < ARRAY_SIZE(format_info); i++) {
+               if (!strcmp(format_info[i].name, name))
+                       return format_info[i].format;
+       }
+       return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * Test patterns
+ */
+
+struct color_rgb24 {
+       unsigned int value: 24;
+} __attribute__((__packed__));
+
+struct color_yuv {
+       unsigned char y;
+       unsigned char u;
+       unsigned char v;
+};
+
+#define MAKE_YUV_601_Y(r, g, b) \
+       ((( 66 * (r) + 129 * (g) +  25 * (b) + 128) >> 8) + 16)
+#define MAKE_YUV_601_U(r, g, b) \
+       (((-38 * (r) -  74 * (g) + 112 * (b) + 128) >> 8) + 128)
+#define MAKE_YUV_601_V(r, g, b) \
+       (((112 * (r) -  94 * (g) -  18 * (b) + 128) >> 8) + 128)
+
+#define MAKE_YUV_601(r, g, b) \
+       { .y = MAKE_YUV_601_Y(r, g, b), \
+         .u = MAKE_YUV_601_U(r, g, b), \
+         .v = MAKE_YUV_601_V(r, g, b) }
+
+#define MAKE_RGBA(rgb, r, g, b, a) \
+       ((((r) >> (8 - (rgb)->red.length)) << (rgb)->red.offset) | \
+        (((g) >> (8 - (rgb)->green.length)) << (rgb)->green.offset) | \
+        (((b) >> (8 - (rgb)->blue.length)) << (rgb)->blue.offset) | \
+        (((a) >> (8 - (rgb)->alpha.length)) << (rgb)->alpha.offset))
+
+#define MAKE_RGB24(rgb, r, g, b) \
+       { .value = MAKE_RGBA(rgb, r, g, b, 0) }
+
+static void
+fill_smpte_yuv_planar(const struct yuv_info *yuv,
+                                         unsigned char *y_mem, unsigned char *u_mem,
+                                         unsigned char *v_mem, unsigned int width,
+                                         unsigned int height, unsigned int stride)
+{
+       const struct color_yuv colors_top[] = {
+               MAKE_YUV_601(191, 192, 192),    /* grey */
+               MAKE_YUV_601(192, 192, 0),      /* yellow */
+               MAKE_YUV_601(0, 192, 192),      /* cyan */
+               MAKE_YUV_601(0, 192, 0),        /* green */
+               MAKE_YUV_601(192, 0, 192),      /* magenta */
+               MAKE_YUV_601(192, 0, 0),        /* red */
+               MAKE_YUV_601(0, 0, 192),        /* blue */
+       };
+       const struct color_yuv colors_middle[] = {
+               MAKE_YUV_601(0, 0, 192),        /* blue */
+               MAKE_YUV_601(19, 19, 19),       /* black */
+               MAKE_YUV_601(192, 0, 192),      /* magenta */
+               MAKE_YUV_601(19, 19, 19),       /* black */
+               MAKE_YUV_601(0, 192, 192),      /* cyan */
+               MAKE_YUV_601(19, 19, 19),       /* black */
+               MAKE_YUV_601(192, 192, 192),    /* grey */
+       };
+       const struct color_yuv colors_bottom[] = {
+               MAKE_YUV_601(0, 33, 76),        /* in-phase */
+               MAKE_YUV_601(255, 255, 255),    /* super white */
+               MAKE_YUV_601(50, 0, 106),       /* quadrature */
+               MAKE_YUV_601(19, 19, 19),       /* black */
+               MAKE_YUV_601(9, 9, 9),          /* 3.5% */
+               MAKE_YUV_601(19, 19, 19),       /* 7.5% */
+               MAKE_YUV_601(29, 29, 29),       /* 11.5% */
+               MAKE_YUV_601(19, 19, 19),       /* black */
+       };
+       unsigned int cs = yuv->chroma_stride;
+       unsigned int xsub = yuv->xsub;
+       unsigned int ysub = yuv->ysub;
+       unsigned int x;
+       unsigned int y;
+
+       /* Luma */
+       for (y = 0; y < height * 6 / 9; ++y) {
+               for (x = 0; x < width; ++x)
+                       y_mem[x] = colors_top[x * 7 / width].y;
+               y_mem += stride;
+       }
+
+       for (; y < height * 7 / 9; ++y) {
+               for (x = 0; x < width; ++x)
+                       y_mem[x] = colors_middle[x * 7 / width].y;
+               y_mem += stride;
+       }
+
+       for (; y < height; ++y) {
+               for (x = 0; x < width * 5 / 7; ++x)
+                       y_mem[x] = colors_bottom[x * 4 / (width * 5 / 7)].y;
+               for (; x < width * 6 / 7; ++x)
+                       y_mem[x] = colors_bottom[(x - width * 5 / 7) * 3
+                                                                        / (width / 7) + 4].y;
+               for (; x < width; ++x)
+                       y_mem[x] = colors_bottom[7].y;
+               y_mem += stride;
+       }
+
+       /* Chroma */
+       for (y = 0; y < height / ysub * 6 / 9; ++y) {
+               for (x = 0; x < width; x += xsub) {
+                       u_mem[x * cs / xsub] = colors_top[x * 7 / width].u;
+                       v_mem[x * cs / xsub] = colors_top[x * 7 / width].v;
+               }
+               u_mem += stride * cs / xsub;
+               v_mem += stride * cs / xsub;
+       }
+
+       for (; y < height / ysub * 7 / 9; ++y) {
+               for (x = 0; x < width; x += xsub) {
+                       u_mem[x * cs / xsub] = colors_middle[x * 7 / width].u;
+                       v_mem[x * cs / xsub] = colors_middle[x * 7 / width].v;
+               }
+               u_mem += stride * cs / xsub;
+               v_mem += stride * cs / xsub;
+       }
+
+       for (; y < height / ysub; ++y) {
+               for (x = 0; x < width * 5 / 7; x += xsub) {
+                       u_mem[x * cs / xsub] =
+                               colors_bottom[x * 4 / (width * 5 / 7)].u;
+                       v_mem[x * cs / xsub] =
+                               colors_bottom[x * 4 / (width * 5 / 7)].v;
+               }
+               for (; x < width * 6 / 7; x += xsub) {
+                       u_mem[x * cs / xsub] = colors_bottom[(x - width * 5 / 7) *
+                                                                                                3 / (width / 7) + 4].u;
+                       v_mem[x * cs / xsub] = colors_bottom[(x - width * 5 / 7) *
+                                                                                                3 / (width / 7) + 4].v;
+               }
+               for (; x < width; x += xsub) {
+                       u_mem[x * cs / xsub] = colors_bottom[7].u;
+                       v_mem[x * cs / xsub] = colors_bottom[7].v;
+               }
+               u_mem += stride * cs / xsub;
+               v_mem += stride * cs / xsub;
+       }
+}
+
+static void
+fill_smpte_yuv_packed(const struct yuv_info *yuv, unsigned char *mem,
+                                         unsigned int width, unsigned int height,
+                                         unsigned int stride)
+{
+       const struct color_yuv colors_top[] = {
+               MAKE_YUV_601(191, 192, 192),    /* grey */
+               MAKE_YUV_601(192, 192, 0),      /* yellow */
+               MAKE_YUV_601(0, 192, 192),      /* cyan */
+               MAKE_YUV_601(0, 192, 0),        /* green */
+               MAKE_YUV_601(192, 0, 192),      /* magenta */
+               MAKE_YUV_601(192, 0, 0),        /* red */
+               MAKE_YUV_601(0, 0, 192),        /* blue */
+       };
+       const struct color_yuv colors_middle[] = {
+               MAKE_YUV_601(0, 0, 192),        /* blue */
+               MAKE_YUV_601(19, 19, 19),       /* black */
+               MAKE_YUV_601(192, 0, 192),      /* magenta */
+               MAKE_YUV_601(19, 19, 19),       /* black */
+               MAKE_YUV_601(0, 192, 192),      /* cyan */
+               MAKE_YUV_601(19, 19, 19),       /* black */
+               MAKE_YUV_601(192, 192, 192),    /* grey */
+       };
+       const struct color_yuv colors_bottom[] = {
+               MAKE_YUV_601(0, 33, 76),        /* in-phase */
+               MAKE_YUV_601(255, 255, 255),    /* super white */
+               MAKE_YUV_601(50, 0, 106),       /* quadrature */
+               MAKE_YUV_601(19, 19, 19),       /* black */
+               MAKE_YUV_601(9, 9, 9),          /* 3.5% */
+               MAKE_YUV_601(19, 19, 19),       /* 7.5% */
+               MAKE_YUV_601(29, 29, 29),       /* 11.5% */
+               MAKE_YUV_601(19, 19, 19),       /* black */
+       };
+       unsigned char *y_mem = (yuv->order & YUV_YC) ? mem : mem + 1;
+       unsigned char *c_mem = (yuv->order & YUV_CY) ? mem : mem + 1;
+       unsigned int u = (yuv->order & YUV_YCrCb) ? 2 : 0;
+       unsigned int v = (yuv->order & YUV_YCbCr) ? 2 : 0;
+       unsigned int x;
+       unsigned int y;
+
+       if (width < 8)
+               return;
+
+       /* Luma */
+       for (y = 0; y < height * 6 / 9; ++y) {
+               for (x = 0; x < width; ++x)
+                       y_mem[2 * x] = colors_top[x * 7 / width].y;
+               y_mem += stride;
+       }
+
+       for (; y < height * 7 / 9; ++y) {
+               for (x = 0; x < width; ++x)
+                       y_mem[2 * x] = colors_middle[x * 7 / width].y;
+               y_mem += stride;
+       }
+
+       for (; y < height; ++y) {
+               for (x = 0; x < width * 5 / 7; ++x)
+                       y_mem[2 * x] = colors_bottom[x * 4 / (width * 5 / 7)].y;
+               for (; x < width * 6 / 7; ++x)
+                       y_mem[2 * x] = colors_bottom[(x - width * 5 / 7) * 3
+                                                                                / (width / 7) + 4].y;
+               for (; x < width; ++x)
+                       y_mem[2 * x] = colors_bottom[7].y;
+               y_mem += stride;
+       }
+
+       /* Chroma */
+       for (y = 0; y < height * 6 / 9; ++y) {
+               for (x = 0; x < width; x += 2) {
+                       c_mem[2 * x + u] = colors_top[x * 7 / width].u;
+                       c_mem[2 * x + v] = colors_top[x * 7 / width].v;
+               }
+               c_mem += stride;
+       }
+
+       for (; y < height * 7 / 9; ++y) {
+               for (x = 0; x < width; x += 2) {
+                       c_mem[2 * x + u] = colors_middle[x * 7 / width].u;
+                       c_mem[2 * x + v] = colors_middle[x * 7 / width].v;
+               }
+               c_mem += stride;
+       }
+
+       for (; y < height; ++y) {
+               for (x = 0; x < width * 5 / 7; x += 2) {
+                       c_mem[2 * x + u] = colors_bottom[x * 4 / (width * 5 / 7)].u;
+                       c_mem[2 * x + v] = colors_bottom[x * 4 / (width * 5 / 7)].v;
+               }
+               for (; x < width * 6 / 7; x += 2) {
+                       c_mem[2 * x + u] = colors_bottom[(x - width * 5 / 7) *
+                                                                                        3 / (width / 7) + 4].u;
+                       c_mem[2 * x + v] = colors_bottom[(x - width * 5 / 7) *
+                                                                                        3 / (width / 7) + 4].v;
+               }
+               for (; x < width; x += 2) {
+                       c_mem[2 * x + u] = colors_bottom[7].u;
+                       c_mem[2 * x + v] = colors_bottom[7].v;
+               }
+               c_mem += stride;
+       }
+}
+
+static void
+fill_smpte_rgb16(const struct rgb_info *rgb, unsigned char *mem,
+                                unsigned int width, unsigned int height, unsigned int stride)
+{
+       const uint16_t colors_top[] = {
+               MAKE_RGBA(rgb, 192, 192, 192, 255),     /* grey */
+               MAKE_RGBA(rgb, 192, 192, 0, 255),       /* yellow */
+               MAKE_RGBA(rgb, 0, 192, 192, 255),       /* cyan */
+               MAKE_RGBA(rgb, 0, 192, 0, 255),         /* green */
+               MAKE_RGBA(rgb, 192, 0, 192, 255),       /* magenta */
+               MAKE_RGBA(rgb, 192, 0, 0, 255),         /* red */
+               MAKE_RGBA(rgb, 0, 0, 192, 255),         /* blue */
+       };
+       const uint16_t colors_middle[] = {
+               MAKE_RGBA(rgb, 0, 0, 192, 255),         /* blue */
+               MAKE_RGBA(rgb, 19, 19, 19, 255),        /* black */
+               MAKE_RGBA(rgb, 192, 0, 192, 255),       /* magenta */
+               MAKE_RGBA(rgb, 19, 19, 19, 255),        /* black */
+               MAKE_RGBA(rgb, 0, 192, 192, 255),       /* cyan */
+               MAKE_RGBA(rgb, 19, 19, 19, 255),        /* black */
+               MAKE_RGBA(rgb, 192, 192, 192, 255),     /* grey */
+       };
+       const uint16_t colors_bottom[] = {
+               MAKE_RGBA(rgb, 0, 33, 76, 255),         /* in-phase */
+               MAKE_RGBA(rgb, 255, 255, 255, 255),     /* super white */
+               MAKE_RGBA(rgb, 50, 0, 106, 255),        /* quadrature */
+               MAKE_RGBA(rgb, 19, 19, 19, 255),        /* black */
+               MAKE_RGBA(rgb, 9, 9, 9, 255),           /* 3.5% */
+               MAKE_RGBA(rgb, 19, 19, 19, 255),        /* 7.5% */
+               MAKE_RGBA(rgb, 29, 29, 29, 255),        /* 11.5% */
+               MAKE_RGBA(rgb, 19, 19, 19, 255),        /* black */
+       };
+       unsigned int x;
+       unsigned int y;
+
+       if (width < 8)
+               return;
+
+       for (y = 0; y < height * 6 / 9; ++y) {
+               for (x = 0; x < width; ++x)
+                       ((uint16_t *)mem)[x] = colors_top[x * 7 / width];
+               mem += stride;
+       }
+
+       for (; y < height * 7 / 9; ++y) {
+               for (x = 0; x < width; ++x)
+                       ((uint16_t *)mem)[x] = colors_middle[x * 7 / width];
+               mem += stride;
+       }
+
+       for (; y < height; ++y) {
+               for (x = 0; x < width * 5 / 7; ++x)
+                       ((uint16_t *)mem)[x] =
+                               colors_bottom[x * 4 / (width * 5 / 7)];
+               for (; x < width * 6 / 7; ++x)
+                       ((uint16_t *)mem)[x] =
+                               colors_bottom[(x - width * 5 / 7) * 3
+                                                         / (width / 7) + 4];
+               for (; x < width; ++x)
+                       ((uint16_t *)mem)[x] = colors_bottom[7];
+               mem += stride;
+       }
+}
+
+static void
+fill_smpte_rgb24(const struct rgb_info *rgb, void *mem,
+                                unsigned int width, unsigned int height, unsigned int stride)
+{
+       const struct color_rgb24 colors_top[] = {
+               MAKE_RGB24(rgb, 192, 192, 192), /* grey */
+               MAKE_RGB24(rgb, 192, 192, 0),   /* yellow */
+               MAKE_RGB24(rgb, 0, 192, 192),   /* cyan */
+               MAKE_RGB24(rgb, 0, 192, 0),     /* green */
+               MAKE_RGB24(rgb, 192, 0, 192),   /* magenta */
+               MAKE_RGB24(rgb, 192, 0, 0),     /* red */
+               MAKE_RGB24(rgb, 0, 0, 192),     /* blue */
+       };
+       const struct color_rgb24 colors_middle[] = {
+               MAKE_RGB24(rgb, 0, 0, 192),     /* blue */
+               MAKE_RGB24(rgb, 19, 19, 19),    /* black */
+               MAKE_RGB24(rgb, 192, 0, 192),   /* magenta */
+               MAKE_RGB24(rgb, 19, 19, 19),    /* black */
+               MAKE_RGB24(rgb, 0, 192, 192),   /* cyan */
+               MAKE_RGB24(rgb, 19, 19, 19),    /* black */
+               MAKE_RGB24(rgb, 192, 192, 192), /* grey */
+       };
+       const struct color_rgb24 colors_bottom[] = {
+               MAKE_RGB24(rgb, 0, 33, 76),     /* in-phase */
+               MAKE_RGB24(rgb, 255, 255, 255), /* super white */
+               MAKE_RGB24(rgb, 50, 0, 106),    /* quadrature */
+               MAKE_RGB24(rgb, 19, 19, 19),    /* black */
+               MAKE_RGB24(rgb, 9, 9, 9),       /* 3.5% */
+               MAKE_RGB24(rgb, 19, 19, 19),    /* 7.5% */
+               MAKE_RGB24(rgb, 29, 29, 29),    /* 11.5% */
+               MAKE_RGB24(rgb, 19, 19, 19),    /* black */
+       };
+       unsigned int x;
+       unsigned int y;
+
+       if (width < 8)
+               return;
+
+       for (y = 0; y < height * 6 / 9; ++y) {
+               for (x = 0; x < width; ++x)
+                       ((struct color_rgb24 *)mem)[x] =
+                               colors_top[x * 7 / width];
+               mem += stride;
+       }
+
+       for (; y < height * 7 / 9; ++y) {
+               for (x = 0; x < width; ++x)
+                       ((struct color_rgb24 *)mem)[x] =
+                               colors_middle[x * 7 / width];
+               mem += stride;
+       }
+
+       for (; y < height; ++y) {
+               for (x = 0; x < width * 5 / 7; ++x)
+                       ((struct color_rgb24 *)mem)[x] =
+                               colors_bottom[x * 4 / (width * 5 / 7)];
+               for (; x < width * 6 / 7; ++x)
+                       ((struct color_rgb24 *)mem)[x] =
+                               colors_bottom[(x - width * 5 / 7) * 3
+                                                         / (width / 7) + 4];
+               for (; x < width; ++x)
+                       ((struct color_rgb24 *)mem)[x] = colors_bottom[7];
+               mem += stride;
+       }
+}
+
+static void
+fill_smpte_rgb32(const struct rgb_info *rgb, unsigned char *mem,
+                                unsigned int width, unsigned int height, unsigned int stride)
+{
+       const uint32_t colors_top[] = {
+               MAKE_RGBA(rgb, 192, 192, 192, 255),     /* grey */
+               MAKE_RGBA(rgb, 192, 192, 0, 255),       /* yellow */
+               MAKE_RGBA(rgb, 0, 192, 192, 255),       /* cyan */
+               MAKE_RGBA(rgb, 0, 192, 0, 255),         /* green */
+               MAKE_RGBA(rgb, 192, 0, 192, 255),       /* magenta */
+               MAKE_RGBA(rgb, 192, 0, 0, 255),         /* red */
+               MAKE_RGBA(rgb, 0, 0, 192, 255),         /* blue */
+       };
+       const uint32_t colors_middle[] = {
+               MAKE_RGBA(rgb, 0, 0, 192, 255),         /* blue */
+               MAKE_RGBA(rgb, 19, 19, 19, 255),        /* black */
+               MAKE_RGBA(rgb, 192, 0, 192, 255),       /* magenta */
+               MAKE_RGBA(rgb, 19, 19, 19, 255),        /* black */
+               MAKE_RGBA(rgb, 0, 192, 192, 255),       /* cyan */
+               MAKE_RGBA(rgb, 19, 19, 19, 255),        /* black */
+               MAKE_RGBA(rgb, 192, 192, 192, 255),     /* grey */
+       };
+       const uint32_t colors_bottom[] = {
+               MAKE_RGBA(rgb, 0, 33, 76, 255),         /* in-phase */
+               MAKE_RGBA(rgb, 255, 255, 255, 255),     /* super white */
+               MAKE_RGBA(rgb, 50, 0, 106, 255),        /* quadrature */
+               MAKE_RGBA(rgb, 19, 19, 19, 255),        /* black */
+               MAKE_RGBA(rgb, 9, 9, 9, 255),           /* 3.5% */
+               MAKE_RGBA(rgb, 19, 19, 19, 255),        /* 7.5% */
+               MAKE_RGBA(rgb, 29, 29, 29, 255),        /* 11.5% */
+               MAKE_RGBA(rgb, 19, 19, 19, 255),        /* black */
+       };
+       unsigned int x;
+       unsigned int y;
+       unsigned int seed = time(NULL);;
+
+       if (width < 8)
+               return;
+
+       for (y = 0; y < height * 6 / 9; ++y) {
+               for (x = 0; x < width; ++x)
+                       ((uint32_t *)mem)[x] = colors_top[x * 7 / width];
+               mem += stride;
+       }
+
+       for (; y < height * 7 / 9; ++y) {
+               for (x = 0; x < width; ++x)
+                       ((uint32_t *)mem)[x] = colors_middle[x * 7 / width];
+               mem += stride;
+       }
+
+       for (; y < height; ++y) {
+               for (x = 0; x < width * 5 / 7; ++x)
+                       ((uint32_t *)mem)[x] =
+                               colors_bottom[x * 4 / (width * 5 / 7)];
+               for (; x < width * 6 / 7; ++x)
+                       ((uint32_t *)mem)[x] =
+                               colors_bottom[(x - width * 5 / 7) * 3
+                                                         / (width / 7) + 4];
+               for (; x < width; ++x) {
+                       ((uint32_t *)mem)[x] = (rand_r(&seed) % 2) ? MAKE_RGBA(rgb, 255, 255, 255, 255) : MAKE_RGBA(rgb, 0, 0, 0, 255);
+               }
+               mem += stride;
+       }
+}
+
+static void
+fill_smpte(const struct format_info *info, void *planes[3], unsigned int width,
+                  unsigned int height, unsigned int stride)
+{
+       unsigned char *u, *v;
+
+       switch (info->format) {
+       case TBM_FORMAT_UYVY:
+       case TBM_FORMAT_VYUY:
+       case TBM_FORMAT_YUYV:
+       case TBM_FORMAT_YVYU:
+               return fill_smpte_yuv_packed(&info->yuv, planes[0], width,
+                                                                        height, stride);
+
+       case TBM_FORMAT_NV12:
+       case TBM_FORMAT_NV21:
+       case TBM_FORMAT_NV16:
+       case TBM_FORMAT_NV61:
+               u = info->yuv.order & YUV_YCbCr ? planes[1] : planes[1] + 1;
+               v = info->yuv.order & YUV_YCrCb ? planes[1] : planes[1] + 1;
+               return fill_smpte_yuv_planar(&info->yuv, planes[0], u, v,
+                                                                        width, height, stride);
+
+       case TBM_FORMAT_YUV420:
+               return fill_smpte_yuv_planar(&info->yuv, planes[0], planes[1],
+                                                                        planes[2], width, height, stride);
+
+       case TBM_FORMAT_YVU420:
+               return fill_smpte_yuv_planar(&info->yuv, planes[0], planes[2],
+                                                                        planes[1], width, height, stride);
+
+       case TBM_FORMAT_ARGB4444:
+       case TBM_FORMAT_XRGB4444:
+       case TBM_FORMAT_ABGR4444:
+       case TBM_FORMAT_XBGR4444:
+       case TBM_FORMAT_RGBA4444:
+       case TBM_FORMAT_RGBX4444:
+       case TBM_FORMAT_BGRA4444:
+       case TBM_FORMAT_BGRX4444:
+       case TBM_FORMAT_RGB565:
+       case TBM_FORMAT_BGR565:
+       case TBM_FORMAT_ARGB1555:
+       case TBM_FORMAT_XRGB1555:
+       case TBM_FORMAT_ABGR1555:
+       case TBM_FORMAT_XBGR1555:
+       case TBM_FORMAT_RGBA5551:
+       case TBM_FORMAT_RGBX5551:
+       case TBM_FORMAT_BGRA5551:
+       case TBM_FORMAT_BGRX5551:
+               return fill_smpte_rgb16(&info->rgb, planes[0],
+                                                               width, height, stride);
+
+       case TBM_FORMAT_BGR888:
+       case TBM_FORMAT_RGB888:
+               return fill_smpte_rgb24(&info->rgb, planes[0],
+                                                               width, height, stride);
+       case TBM_FORMAT_ARGB8888:
+       case TBM_FORMAT_XRGB8888:
+       case TBM_FORMAT_ABGR8888:
+       case TBM_FORMAT_XBGR8888:
+       case TBM_FORMAT_RGBA8888:
+       case TBM_FORMAT_RGBX8888:
+       case TBM_FORMAT_BGRA8888:
+       case TBM_FORMAT_BGRX8888:
+       case TBM_FORMAT_ARGB2101010:
+       case TBM_FORMAT_XRGB2101010:
+       case TBM_FORMAT_ABGR2101010:
+       case TBM_FORMAT_XBGR2101010:
+       case TBM_FORMAT_RGBA1010102:
+       case TBM_FORMAT_RGBX1010102:
+       case TBM_FORMAT_BGRA1010102:
+       case TBM_FORMAT_BGRX1010102:
+               return fill_smpte_rgb32(&info->rgb, planes[0],
+                                                               width, height, stride);
+       }
+}
+
+static void
+fill_tiles_yuv_planar(const struct format_info *info,
+                                         unsigned char *y_mem, unsigned char *u_mem,
+                                         unsigned char *v_mem, unsigned int width,
+                                         unsigned int height, unsigned int stride)
+{
+       const struct yuv_info *yuv = &info->yuv;
+       unsigned int cs = yuv->chroma_stride;
+       unsigned int xsub = yuv->xsub;
+       unsigned int ysub = yuv->ysub;
+       unsigned int x;
+       unsigned int y;
+
+       for (y = 0; y < height; ++y) {
+               for (x = 0; x < width; ++x) {
+                       div_t d = div(x + y, width);
+                       uint32_t rgb32 = 0x00130502 * (d.quot >> 6)
+                                                        + 0x000a1120 * (d.rem >> 6);
+                       struct color_yuv color =
+                               MAKE_YUV_601((rgb32 >> 16) & 0xff,
+                                                        (rgb32 >> 8) & 0xff, rgb32 & 0xff);
+
+                       y_mem[x] = color.y;
+                       u_mem[x / xsub * cs] = color.u;
+                       v_mem[x / xsub * cs] = color.v;
+               }
+
+               y_mem += stride;
+               if ((y + 1) % ysub == 0) {
+                       u_mem += stride * cs / xsub;
+                       v_mem += stride * cs / xsub;
+               }
+       }
+}
+
+static void
+fill_tiles_yuv_packed(const struct format_info *info, unsigned char *mem,
+                                         unsigned int width, unsigned int height,
+                                         unsigned int stride)
+{
+       const struct yuv_info *yuv = &info->yuv;
+       unsigned char *y_mem = (yuv->order & YUV_YC) ? mem : mem + 1;
+       unsigned char *c_mem = (yuv->order & YUV_CY) ? mem : mem + 1;
+       unsigned int u = (yuv->order & YUV_YCrCb) ? 2 : 0;
+       unsigned int v = (yuv->order & YUV_YCbCr) ? 2 : 0;
+       unsigned int x;
+       unsigned int y;
+
+       for (y = 0; y < height; ++y) {
+               for (x = 0; x < width; x += 2) {
+                       div_t d = div(x + y, width);
+                       uint32_t rgb32 = 0x00130502 * (d.quot >> 6)
+                                                        + 0x000a1120 * (d.rem >> 6);
+                       struct color_yuv color =
+                               MAKE_YUV_601((rgb32 >> 16) & 0xff,
+                                                        (rgb32 >> 8) & 0xff, rgb32 & 0xff);
+
+                       y_mem[2 * x] = color.y;
+                       c_mem[2 * x + u] = color.u;
+                       y_mem[2 * x + 2] = color.y;
+                       c_mem[2 * x + v] = color.v;
+               }
+
+               y_mem += stride;
+               c_mem += stride;
+       }
+}
+
+static void
+fill_tiles_rgb16(const struct format_info *info, unsigned char *mem,
+                                unsigned int width, unsigned int height, unsigned int stride)
+{
+       const struct rgb_info *rgb = &info->rgb;
+       unsigned int x, y;
+
+       for (y = 0; y < height; ++y) {
+               for (x = 0; x < width; ++x) {
+                       div_t d = div(x + y, width);
+                       uint32_t rgb32 = 0x00130502 * (d.quot >> 6)
+                                                        + 0x000a1120 * (d.rem >> 6);
+                       uint16_t color =
+                               MAKE_RGBA(rgb, (rgb32 >> 16) & 0xff,
+                                                 (rgb32 >> 8) & 0xff, rgb32 & 0xff,
+                                                 255);
+
+                       ((uint16_t *)mem)[x] = color;
+               }
+               mem += stride;
+       }
+}
+
+static void
+fill_tiles_rgb24(const struct format_info *info, unsigned char *mem,
+                                unsigned int width, unsigned int height, unsigned int stride)
+{
+       const struct rgb_info *rgb = &info->rgb;
+       unsigned int x, y;
+
+       for (y = 0; y < height; ++y) {
+               for (x = 0; x < width; ++x) {
+                       div_t d = div(x + y, width);
+                       uint32_t rgb32 = 0x00130502 * (d.quot >> 6)
+                                                        + 0x000a1120 * (d.rem >> 6);
+                       struct color_rgb24 color =
+                               MAKE_RGB24(rgb, (rgb32 >> 16) & 0xff,
+                                                  (rgb32 >> 8) & 0xff, rgb32 & 0xff);
+
+                       ((struct color_rgb24 *)mem)[x] = color;
+               }
+               mem += stride;
+       }
+}
+
+static void
+fill_tiles_rgb32(const struct format_info *info, unsigned char *mem,
+                                unsigned int width, unsigned int height, unsigned int stride)
+{
+       const struct rgb_info *rgb = &info->rgb;
+       unsigned int x, y;
+
+       for (y = 0; y < height; ++y) {
+               for (x = 0; x < width; ++x) {
+                       div_t d = div(x + y, width);
+                       uint32_t rgb32 = 0x00130502 * (d.quot >> 6)
+                                                        + 0x000a1120 * (d.rem >> 6);
+                       uint32_t color =
+                               MAKE_RGBA(rgb, (rgb32 >> 16) & 0xff,
+                                                 (rgb32 >> 8) & 0xff, rgb32 & 0xff,
+                                                 255);
+
+                       ((uint32_t *)mem)[x] = color;
+               }
+               mem += stride;
+       }
+}
+
+static void
+fill_tiles(const struct format_info *info, void *planes[3], unsigned int width,
+                  unsigned int height, unsigned int stride)
+{
+       unsigned char *u, *v;
+
+       switch (info->format) {
+       case TBM_FORMAT_UYVY:
+       case TBM_FORMAT_VYUY:
+       case TBM_FORMAT_YUYV:
+       case TBM_FORMAT_YVYU:
+               return fill_tiles_yuv_packed(info, planes[0],
+                                                                        width, height, stride);
+
+       case TBM_FORMAT_NV12:
+       case TBM_FORMAT_NV21:
+       case TBM_FORMAT_NV16:
+       case TBM_FORMAT_NV61:
+               u = info->yuv.order & YUV_YCbCr ? planes[1] : planes[1] + 1;
+               v = info->yuv.order & YUV_YCrCb ? planes[1] : planes[1] + 1;
+               return fill_tiles_yuv_planar(info, planes[0], u, v,
+                                                                        width, height, stride);
+
+       case TBM_FORMAT_YUV420:
+               return fill_tiles_yuv_planar(info, planes[0], planes[1],
+                                                                        planes[2], width, height, stride);
+
+       case TBM_FORMAT_YVU420:
+               return fill_tiles_yuv_planar(info, planes[0], planes[2],
+                                                                        planes[1], width, height, stride);
+
+       case TBM_FORMAT_ARGB4444:
+       case TBM_FORMAT_XRGB4444:
+       case TBM_FORMAT_ABGR4444:
+       case TBM_FORMAT_XBGR4444:
+       case TBM_FORMAT_RGBA4444:
+       case TBM_FORMAT_RGBX4444:
+       case TBM_FORMAT_BGRA4444:
+       case TBM_FORMAT_BGRX4444:
+       case TBM_FORMAT_RGB565:
+       case TBM_FORMAT_BGR565:
+       case TBM_FORMAT_ARGB1555:
+       case TBM_FORMAT_XRGB1555:
+       case TBM_FORMAT_ABGR1555:
+       case TBM_FORMAT_XBGR1555:
+       case TBM_FORMAT_RGBA5551:
+       case TBM_FORMAT_RGBX5551:
+       case TBM_FORMAT_BGRA5551:
+       case TBM_FORMAT_BGRX5551:
+               return fill_tiles_rgb16(info, planes[0],
+                                                               width, height, stride);
+
+       case TBM_FORMAT_BGR888:
+       case TBM_FORMAT_RGB888:
+               return fill_tiles_rgb24(info, planes[0],
+                                                               width, height, stride);
+       case TBM_FORMAT_ARGB8888:
+       case TBM_FORMAT_XRGB8888:
+       case TBM_FORMAT_ABGR8888:
+       case TBM_FORMAT_XBGR8888:
+       case TBM_FORMAT_RGBA8888:
+       case TBM_FORMAT_RGBX8888:
+       case TBM_FORMAT_BGRA8888:
+       case TBM_FORMAT_BGRX8888:
+       case TBM_FORMAT_ARGB2101010:
+       case TBM_FORMAT_XRGB2101010:
+       case TBM_FORMAT_ABGR2101010:
+       case TBM_FORMAT_XBGR2101010:
+       case TBM_FORMAT_RGBA1010102:
+       case TBM_FORMAT_RGBX1010102:
+       case TBM_FORMAT_BGRA1010102:
+       case TBM_FORMAT_BGRX1010102:
+               return fill_tiles_rgb32(info, planes[0],
+                                                               width, height, stride);
+       }
+}
+
+static void
+fill_plain(const struct format_info *info, void *planes[3], unsigned int width,
+                  unsigned int height, unsigned int stride)
+{
+       memset(planes[0], 0x77, stride * height);
+}
+
+/*
+ * fill_pattern - Fill a buffer with a test pattern
+ * @format: Pixel format
+ * @pattern: Test pattern
+ * @buffer: Buffer memory
+ * @width: Width in pixels
+ * @height: Height in pixels
+ * @stride: Line stride (pitch) in bytes
+ *
+ * Fill the buffer with the test pattern specified by the pattern parameter.
+ * Supported formats vary depending on the selected pattern.
+ */
+static void
+fill_pattern(unsigned int format, enum fill_pattern pattern, void *planes[3],
+                        unsigned int width, unsigned int height, unsigned int stride)
+{
+       const struct format_info *info = NULL;
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(format_info); ++i) {
+               if (format_info[i].format == format) {
+                       info = &format_info[i];
+                       break;
+               }
+       }
+
+       if (info == NULL)
+               return;
+
+       switch (pattern) {
+       case PATTERN_TILES:
+               return fill_tiles(info, planes, width, height, stride);
+
+       case PATTERN_SMPTE:
+               return fill_smpte(info, planes, width, height, stride);
+
+       case PATTERN_PLAIN:
+               return fill_plain(info, planes, width, height, stride);
+
+       default:
+               printf("Error: unsupported test pattern %u.\n", pattern);
+               break;
+       }
+}
+
+void
+tdm_test_buffer_fill(tbm_surface_h buffer, int pattern)
+{
+       tbm_surface_info_s info;
+       void *plane[3];
+       int ret;
+
+       ret = tbm_surface_map(buffer, TBM_OPTION_WRITE, &info);
+       TDM_EXIT_IF_FAIL(ret == 0);
+
+       plane[0] = info.planes[0].ptr;
+       plane[1] = info.planes[1].ptr;
+       plane[2] = info.planes[2].ptr;
+       fill_pattern(info.format, pattern, plane, info.width, info.height, info.planes[0].stride);
+       tbm_surface_unmap(buffer);
+}
diff --git a/tools/buffers.h b/tools/buffers.h
new file mode 100644 (file)
index 0000000..55afd3d
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * DRM based mode setting test program
+ * Copyright 2008 Tungsten Graphics
+ *   Jakob Bornecrantz <jakob@tungstengraphics.com>
+ * Copyright 2008 Intel Corporation
+ *   Jesse Barnes <jesse.barnes@intel.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, 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 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.
+ */
+
+#ifndef __BUFFERS_H__
+#define __BUFFERS_H__
+
+enum fill_pattern {
+       PATTERN_TILES = 0,
+       PATTERN_PLAIN = 1,
+       PATTERN_SMPTE = 2,
+};
+
+void
+tdm_test_buffer_fill(tbm_surface_h buffer, int pattern);
+
+#endif
index 4a8e58399efb1c426f6767ab4071370b999c2470..ab322aa9a71b816e21529ac4d27090c4d497cd0b 100644 (file)
@@ -65,15 +65,15 @@ typedef struct _tdm_test_client {
 
 struct typestrings {
        int type;
-       char string[512];
+       const char *string;
 };
 
 struct optstrings {
        int  type;
-       char opt[512];
-       char desc[512];
-       char arg[512];
-       char ex[512];
+       const char *opt;
+       const char *desc;
+       const char *arg;
+       const char *ex;
 };
 
 enum {
@@ -90,26 +90,9 @@ static struct typestrings typestrs[] = {
 
 static struct optstrings optstrs[] = {
        {OPT_QRY, "qo", "output objects info", "<output_name>", "primary"},
-       {OPT_TST, "v", "vblank test", "<output_name>[,<sync>][@<fps>][#<interval>][+<offset>][*fake]", "primary,0@60#1+0*1"},
+       {OPT_TST, "v", "vblank test", "<output_name>[,<sync>][@<fps>][~<interval>][+<offset>][*fake]", "primary,0@60~1+0*1"},
 };
 
-#define DELIM "!@#^&*+-|,"
-
-static char*
-strtostr(char *buf, int len, char *str, char *delim)
-{
-       char *end;
-       end = strpbrk(str, delim);
-       if (end)
-               len = ((end - str + 1) < len) ? (end - str + 1) : len;
-       else {
-               int l = strlen(str);
-               len = ((l + 1) < len) ? (l + 1) : len;
-       }
-       snprintf(buf, len, "%s", str);
-       return str + len - 1;
-}
-
 static void
 usage(char *app_name)
 {
@@ -127,10 +110,13 @@ usage(char *app_name)
                                if (f == 1)
                                        printf(" %s options:\n\n", typestrs[t].string);
                                printf("\t-%s\t%s\n", optstrs[o].opt, optstrs[o].desc);
-                               printf("\t\t%s\n", optstrs[o].arg);
-                               printf("\t\tex) %s\n", optstrs[o].ex);
+                               if (optstrs[o].arg)
+                                       printf("\t\t  %s\n", optstrs[o].arg);
+                               if (optstrs[o].ex)
+                                       printf("\t\t  ex) %s\n", optstrs[o].ex);
                                f = 0;
                        }
+               printf("\n");
        }
 
        exit(0);
@@ -138,73 +124,68 @@ usage(char *app_name)
 
 //"<output_name>"
 static void
-parse_arg_qo(tdm_test_client *data, char *p)
+parse_arg_qo(tdm_test_client *data, char *arg)
 {
-       strtostr(data->args.output_name, 512, p, DELIM);
+       strtostr(data->args.output_name, 512, arg, TDM_DELIM);
 }
 
-//"<output_name>[,<sync>][@<fps>][#<interval>][+<offset>][*fake]"
+//"<output_name>[,<sync>][@<fps>][~<interval>][+<offset>][*fake]"
 static void
-parse_arg_v(tdm_test_client *data, char *p)
+parse_arg_v(tdm_test_client *data, char *arg)
 {
-       char *end = p;
+       char *end = arg;
 
-       end = strtostr(data->args.output_name, 512, p, DELIM);
+       end = strtostr(data->args.output_name, 512, arg, TDM_DELIM);
 
        if (*end == ',') {
-               p = end + 1;
-               data->args.sync = strtol(p, &end, 10);
+               arg = end + 1;
+               data->args.sync = strtol(arg, &end, 10);
        }
 
        if (*end == '@') {
-               p = end + 1;
-               data->args.fps = strtol(p, &end, 10);
+               arg = end + 1;
+               data->args.fps = strtol(arg, &end, 10);
        }
 
-       if (*end == '#') {
-               p = end + 1;
-               data->args.interval = strtol(p, &end, 10);
+       if (*end == '~') {
+               arg = end + 1;
+               data->args.interval = strtol(arg, &end, 10);
        }
 
        if (*end == '+' || *end == '-') {
-               p = end;
-               data->args.offset = strtol(p, &end, 10);
+               arg = end;
+               data->args.offset = strtol(arg, &end, 10);
        }
 
        if (*end == '*') {
-               p = end + 1;
-               data->args.enable_fake= strtol(p, &end, 10);
+               arg = end + 1;
+               data->args.enable_fake= strtol(arg, &end, 10);
        }
 }
 
 static void
 parse_args(tdm_test_client *data, int argc, char *argv[])
 {
-       int size = sizeof(optstrs) / sizeof(struct optstrings);
-       int i, j = 0;
+       int i;
 
-       if (argc < 2) {
+       if (argc < 3) {
                usage(argv[0]);
-               exit(1);
+               exit(0);
        }
 
        memset(data, 0, sizeof *data);
        data->args.interval = 1;
 
        for (i = 1; i < argc; i++) {
-               for (j = 0; j < size; j++) {
-                       if (!strncmp(argv[i]+1, "qo", 512)) {
-                               data->do_query = 1;
-                               parse_arg_qo(data, argv[++i]);
-                               break;
-                       } else if (!strncmp(argv[i]+1, "v", 512)) {
-                               data->do_vblank = 1;
-                               parse_arg_v(data, argv[++i]);
-                               break;
-                       } else {
-                               usage(argv[0]);
-                               exit(1);
-                       }
+               if (!strncmp(argv[i]+1, "qo", 2)) {
+                       data->do_query = 1;
+                       parse_arg_qo(data, argv[++i]);
+               } else if (!strncmp(argv[i]+1, "v", 1)) {
+                       data->do_vblank = 1;
+                       parse_arg_v(data, argv[++i]);
+               } else {
+                       usage(argv[0]);
+                       exit(0);
                }
        }
 }
@@ -232,12 +213,12 @@ _client_vblank_handler(tdm_client_vblank *vblank, tdm_error error, unsigned int
 
        if (error == TDM_ERROR_DPMS_OFF) {
                printf("exit: dpms off\n");
-               exit(1);
+               exit(0);
        }
 
        if (error != TDM_ERROR_NONE) {
                printf("exit: error(%d)\n", error);
-               exit(1);
+               exit(0);
        }
 
        cur = get_time_in_micros();
@@ -377,6 +358,17 @@ main(int argc, char *argv[])
        tdm_test_client *data = &ttc_data;
        tdm_error error;
 
+#if 1 /* for testing */
+       const char *xdg = (const char*)getenv("XDG_RUNTIME_DIR");
+       if (!xdg) {
+               char buf[32];
+               snprintf(buf, sizeof(buf), "/run");
+               int ret = setenv("XDG_RUNTIME_DIR", (const char*)buf, 1);
+               if (ret != 0)
+                       exit (0);
+       }
+#endif
+
        parse_args(data, argc, argv);
 
        printf("sync(%d) fps(%d) interval(%d) offset(%d) enable_fake(%d)\n",
diff --git a/tools/tdm_test_server.c b/tools/tdm_test_server.c
new file mode 100644 (file)
index 0000000..932e20d
--- /dev/null
@@ -0,0 +1,1345 @@
+/**************************************************************************
+ *
+ * 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.
+ *
+**************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <poll.h>
+#include <errno.h>
+#include <time.h>
+#include <stdint.h>
+
+#include <tbm_surface.h>
+#include <tbm_surface_internal.h>
+
+#include <tdm.h>
+#include <tdm_log.h>
+#include <tdm_list.h>
+#include <tdm_helper.h>
+#include <tdm_backend.h>
+
+#include "tdm_macro.h"
+#include "tdm_private.h"
+#include "buffers.h"
+
+////////////////////////////////////////////////////////////////////////////////
+struct typestrings {
+       int type;
+       const char *string;
+       const char *desc;
+};
+
+struct optstrings {
+       int  type;
+       const char *opt;
+       const char *desc;
+       const char *arg;
+       const char *ex;
+};
+
+enum {
+       OPT_QRY,
+       OPT_TST,
+       OPT_GEN,
+};
+
+static struct typestrings typestrs[] = {
+       {OPT_QRY, "Query",          NULL},
+       {OPT_TST, "Test",           NULL},
+       {OPT_GEN, "General",        NULL},
+};
+
+static struct optstrings optstrs[] = {
+       {
+               OPT_QRY, "q", "show tdm output, layer information",
+               NULL, NULL
+       },
+       {
+               OPT_TST, "a", "set all layer objects for all connected outputs",
+               NULL, NULL
+       },
+       {
+               OPT_TST, "o", "set a mode for a output object",
+               "<output_idx>@<mode>[&<refresh>]", "0@1920x1080"
+       },
+       {
+               OPT_TST, "l", "set a layer object",
+               "<layer_idx>[:<w>x<h>[+<x>+<y>][,<h>x<v>][@<format>]]~<w>x<h>[+<x>+<y>][*<transform>]", NULL
+       },
+       {
+               OPT_TST, "p", "set a PP object.\n\t\t'-l' is used to show the result on screen.",
+               "<w>x<h>[+<x>+<y>][,<h>x<v>][@<format>]~<w>x<h>[+<x>+<y>][,<h>x<v>][@<format>][*<transform>][&<fps>]", NULL
+       },
+       {
+               OPT_TST, "c", "catpure a output object or a layer object.\n\t\t'-l' is used to show the result on screen.",
+               "<output_idx>[,<layer_idx>]~<w>x<h>[+<x>+<y>][,<h>x<v>][@<format>][*<transform>]", NULL
+       },
+       {
+               OPT_GEN, "w", "set the property of a object",
+               "<prop_name>:<value>", NULL
+       },
+       {
+               OPT_GEN, "b", "set the fill(smtpe,tiles,plane) and framebuffer type(scanout,noncachable,wc)",
+               "<fill>[:<buf_flag>[,<buf_flag2>[,...]]]", NULL
+       },
+       {
+               OPT_GEN, "v", "update layers every vblank",
+               NULL, NULL
+       },
+};
+
+static void
+usage(char *app_name)
+{
+       int type_size = sizeof(typestrs) / sizeof(struct typestrings);
+       int opt_size = sizeof(optstrs) / sizeof(struct optstrings);
+       int t;
+
+       printf("usage: %s \n\n", app_name);
+
+       for (t = 0; t < type_size; t++) {
+               int o, f = 1;
+
+               for (o = 0; o < opt_size; o++)
+                       if (optstrs[o].type == typestrs[t].type) {
+                               if (f == 1)
+                                       printf(" %s options: %s\n\n", typestrs[t].string, (typestrs[t].desc) ? : "");
+                               printf("\t-%s\t%s\n", optstrs[o].opt, optstrs[o].desc);
+                               if (optstrs[o].arg)
+                                       printf("\t\t  %s\n", optstrs[o].arg);
+                               if (optstrs[o].ex)
+                                       printf("\t\t  ex) %s\n", optstrs[o].ex);
+                               f = 0;
+                       }
+               printf("\n");
+       }
+
+       exit(0);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+static const char *tdm_buf_flag_names[] = {
+       "scanout",
+       "noncachable",
+       "wc",
+};
+TDM_BIT_NAME_FB(buf_flag)
+
+#define print_size(s) \
+       printf("%dx%d", (s)->h, (s)->v)
+#define print_pos(p) \
+       printf("%dx%d+%d+%d", (p)->w, (p)->h, (p)->x, (p)->y)
+#define print_format(f) \
+       if (f) printf("%c%c%c%c", FOURCC_STR(f)); \
+       else printf("NONE")
+#define print_config(c) \
+       do { \
+               print_size(&(c)->size); \
+               printf(" "); \
+               print_pos(&(c)->pos); \
+               printf(" "); \
+               print_format((c)->format); \
+       } while (0)
+#define print_prop(w) \
+       printf("%s(%d)", (w)->name, ((w)->value).u32)
+
+typedef struct _tdm_test_server tdm_test_server;
+typedef struct _tdm_test_server_layer tdm_test_server_layer;
+typedef struct _tdm_test_server_capture tdm_test_server_capture;
+
+typedef struct _tdm_test_server_prop {
+       /* args */
+       char name[TDM_NAME_LEN];
+       tdm_value value;
+
+       /* variables for test */
+       struct list_head link;
+} tdm_test_server_prop;
+
+typedef struct _tdm_test_server_buffer {
+       /* variables for test */
+       tbm_surface_h buffer;
+       int in_use;
+       tdm_test_server_layer *l;
+
+       tdm_test_server_capture *c;
+       tdm_buffer_release_handler done;
+} tdm_test_server_buffer;
+
+typedef struct _tdm_test_server_output {
+       /* args */
+       int idx;
+       char mode[TDM_NAME_LEN];
+       int refresh;
+
+       /* variables for test */
+       struct list_head link;
+       struct list_head prop_list;
+       struct list_head layer_list;
+       tdm_test_server *data;
+       tdm_output *output;
+} tdm_test_server_output;
+
+typedef struct _tdm_test_server_pp {
+       /* args */
+       tdm_info_pp info;
+       int fps;
+
+       /* variables for test */
+       struct list_head link;
+       tdm_test_server *data;
+       tdm_test_server_layer *l;
+       tdm_pp *pp;
+       tdm_test_server_buffer *bufs[6];
+       int buf_idx;
+
+       tdm_event_loop_source *timer_source;
+} tdm_test_server_pp;
+
+struct _tdm_test_server_capture {
+       /* args */
+       int output_idx;
+       int layer_idx;
+       tdm_info_capture info;
+
+       /* variables for test */
+       struct list_head link;
+       tdm_test_server *data;
+       tdm_test_server_layer *l;
+       tdm_capture *capture;
+};
+
+struct _tdm_test_server_layer {
+       /* args */
+       int idx;
+       tdm_info_layer info;
+
+       /* variables for test */
+       struct list_head link;
+       struct list_head prop_list;
+       tdm_test_server *data;
+       tdm_test_server_output *o;
+       tdm_layer *layer;
+       int is_primary;
+       tdm_test_server_pp *owner_p;
+       tdm_test_server_capture *owner_c;
+       tdm_test_server_buffer *bufs[3];
+       int buf_idx;
+};
+
+struct _tdm_test_server {
+       /* args */
+       int do_query;
+       int do_all;
+       int do_vblank;
+       int bflags;
+       int b_fill;
+
+       /* variables for test */
+       struct list_head output_list;
+       struct list_head pp_list;
+       struct list_head capture_list;
+       tdm_display *display;
+};
+
+static void run_test(tdm_test_server *data);
+static void output_setup(tdm_test_server_output *o);
+static void layer_show_buffer(tdm_test_server_layer *l, tdm_test_server_buffer *b);
+static void capture_attach(tdm_test_server_capture *c, tdm_test_server_buffer *b);
+
+static char*
+parse_size(tdm_size *size, char *arg)
+{
+       char *end;
+       size->h = strtol(arg, &end, 10);
+       TDM_EXIT_IF_FAIL(*end == 'x');
+       arg = end + 1;
+       size->v = strtol(arg, &end, 10);
+       return end;
+}
+
+static char*
+parse_pos(tdm_pos *pos, char *arg)
+{
+       char *end;
+       pos->w = strtol(arg, &end, 10);
+       TDM_EXIT_IF_FAIL(*end == 'x');
+       arg = end + 1;
+       pos->h = strtol(arg, &end, 10);
+       if (*end == '+') {
+               arg = end + 1;
+               pos->x = strtol(arg, &end, 10);
+               TDM_EXIT_IF_FAIL(*end == '+');
+               arg = end + 1;
+               pos->y = strtol(arg, &end, 10);
+       }
+       return end;
+}
+
+static char*
+parse_config(tdm_info_config *config, char *arg)
+{
+       char *end;
+       end = parse_pos(&config->pos, arg);
+       if (*end == ',') {
+               arg = end + 1;
+               end = parse_size(&config->size, arg);
+       }
+       if (*end == '@') {
+               char temp[32];
+               arg = end + 1;
+               end = strtostr(temp, 32, arg, TDM_DELIM);
+               config->format = FOURCC_ID(temp);
+       }
+       return end;
+}
+
+static void
+parse_arg_o(tdm_test_server_output *o, char *arg)
+{
+       char *end;
+       TDM_EXIT_IF_FAIL(arg != NULL);
+       o->idx = strtol(arg, &end, 10);
+       TDM_EXIT_IF_FAIL(*end == '@');
+       arg = end + 1;
+       end = strtostr(o->mode, TDM_NAME_LEN, arg, TDM_DELIM);
+       if (*end == ',') {
+               arg = end + 1;
+               o->refresh = strtol(arg, &end, 10);
+       }
+}
+
+static void
+parse_arg_p(tdm_test_server_pp *p, char *arg)
+{
+       tdm_info_pp *pp_info = &p->info;
+       char *end;
+       TDM_EXIT_IF_FAIL(arg != NULL);
+       end = parse_config(&pp_info->src_config, arg);
+       TDM_EXIT_IF_FAIL(*end == '~');
+       arg = end + 1;
+       end = parse_config(&pp_info->dst_config, arg);
+       if (*end == '*') {
+               arg = end + 1;
+               pp_info->transform = strtol(arg, &end, 10);
+       }
+       if (*end == '&') {
+               arg = end + 1;
+               p->fps = strtol(arg, &end, 10);
+       }
+}
+
+static void
+parse_arg_c(tdm_test_server_capture *c, char *arg)
+{
+       tdm_info_capture *capture_info = &c->info;
+       char *end;
+       TDM_EXIT_IF_FAIL(arg != NULL);
+       c->output_idx = strtol(arg, &end, 10);
+       if (*end == ',') {
+               arg = end + 1;
+               c->layer_idx = strtol(arg, &end, 10);
+       }
+       TDM_EXIT_IF_FAIL(*end == '~');
+       arg = end + 1;
+       end = parse_config(&capture_info->dst_config, arg);
+       if (*end == '*') {
+               arg = end + 1;
+               capture_info->transform = strtol(arg, &end, 10);
+       }
+}
+
+static void
+parse_arg_l(tdm_test_server_layer *l, char *arg)
+{
+       tdm_info_layer *layer_info = &l->info;
+       char *end;
+       TDM_EXIT_IF_FAIL(arg != NULL);
+       l->idx = strtol(arg, &end, 10);
+       if (*end == ':') {
+               arg = end + 1;
+               end = parse_config(&layer_info->src_config, arg);
+       }
+       TDM_EXIT_IF_FAIL(*end == '~');
+       arg = end + 1;
+       end = parse_pos(&layer_info->dst_pos, arg);
+       if (*end == '*') {
+               arg = end + 1;
+               layer_info->transform = strtol(arg, &end, 10);
+       }
+}
+
+static void
+parse_arg_w(tdm_test_server_prop *w, char *arg)
+{
+       char *end;
+       TDM_EXIT_IF_FAIL(arg != NULL);
+       end = strtostr(w->name, TDM_PATH_LEN, arg, TDM_DELIM);
+       TDM_EXIT_IF_FAIL(*end == ':');
+       arg = end + 1;
+       w->value.u32 = strtol(arg, &end, 10);
+}
+
+static void
+parse_arg_b(tdm_test_server *data, char *arg)
+{
+       char *end = arg;
+       char temp[TDM_NAME_LEN] = {0,};
+       TDM_EXIT_IF_FAIL(arg != NULL);
+
+       end = strtostr(temp, 32, arg, TDM_DELIM);
+       if (!strncmp(temp, "smpte", 5))
+               data->b_fill = PATTERN_SMPTE;
+       else if (!strncmp(temp, "tiles", 5))
+               data->b_fill = PATTERN_TILES;
+       else if (!strncmp(temp, "plain", 5))
+               data->b_fill = PATTERN_PLAIN;
+       else {
+               printf("'%s': unknown flag\n", temp);
+               exit(0);
+       }
+
+       if (*arg == ':') {
+               data->bflags = 0;
+               arg = end + 1;
+               snprintf(temp, TDM_NAME_LEN, "%s", arg);
+               arg = strtok_r(temp, ",", &end);
+               while (arg) {
+                       if (!strncmp(arg, "default", 7))
+                               printf("Ignore '%s' flag\n", arg);
+                       else if (!strncmp(arg, "scanout", 7))
+                               data->bflags |= TBM_BO_SCANOUT;
+                       else if (!strncmp(arg, "noncachable", 11))
+                               data->bflags |= TBM_BO_NONCACHABLE;
+                       else if (!strncmp(arg, "wc", 2))
+                               data->bflags |= TBM_BO_WC;
+                       else {
+                               printf("'%s': unknown flag\n", arg);
+                               exit(0);
+                       }
+                       arg = strtok_r(NULL, ",", &end);
+               }
+       }
+}
+
+static void
+parse_args(tdm_test_server *data, int argc, char *argv[])
+{
+       tdm_test_server_output *o = NULL;
+       tdm_test_server_layer *l = NULL;
+       tdm_test_server_pp *p = NULL;
+       tdm_test_server_capture *c = NULL;
+       tdm_test_server_prop *w = NULL;
+       void *last_option = NULL;
+       void *last_object = NULL;
+       int i;
+
+       if (argc < 2) {
+               usage(argv[0]);
+               exit(0);
+       }
+
+       for (i = 1; i < argc; i++) {
+               if (!strncmp(argv[i] + 1, "q", 1)) {
+                       data->do_query = 1;
+                       return;
+               } else if (!strncmp(argv[i] + 1, "a", 1)) {
+                       data->do_all = 1;
+               } else if (!strncmp(argv[i] + 1, "o", 1)) {
+                       TDM_GOTO_IF_FAIL(data->do_all == 0, all);
+                       o = calloc(1, sizeof * o);
+                       TDM_EXIT_IF_FAIL(o != NULL);
+                       o->data = data;
+                       LIST_INITHEAD(&o->layer_list);
+                       LIST_INITHEAD(&o->prop_list);
+                       LIST_ADDTAIL(&o->link, &data->output_list);
+                       parse_arg_o(o, argv[++i]);
+                       last_option = o;
+                       last_object = o;
+               } else if (!strncmp(argv[i] + 1, "p", 1)) {
+                       TDM_GOTO_IF_FAIL(data->do_all == 0, all);
+                       p = calloc(1, sizeof * p);
+                       TDM_EXIT_IF_FAIL(p != NULL);
+                       p->data = data;
+                       p->fps = 30;
+                       LIST_ADDTAIL(&p->link, &data->pp_list);
+                       parse_arg_p(p, argv[++i]);
+                       last_option = p;
+                       last_object = o;
+               } else if (!strncmp(argv[i] + 1, "c", 1)) {
+                       TDM_GOTO_IF_FAIL(data->do_all == 0, all);
+                       c = calloc(1, sizeof * c);
+                       TDM_EXIT_IF_FAIL(c != NULL);
+                       c->data = data;
+                       c->output_idx = -1;
+                       c->layer_idx = -1;
+                       LIST_ADDTAIL(&c->link, &data->capture_list);
+                       parse_arg_c(c, argv[++i]);
+                       last_option = c;
+                       last_object = o;
+               } else if (!strncmp(argv[i] + 1, "l", 1)) {
+                       TDM_GOTO_IF_FAIL(data->do_all == 0, all);
+                       if (!o)
+                               goto no_output;
+                       l = calloc(1, sizeof * l);
+                       TDM_EXIT_IF_FAIL(l != NULL);
+                       LIST_INITHEAD(&l->prop_list);
+                       LIST_ADDTAIL(&l->link, &o->layer_list);
+                       l->data = data;
+                       l->o = o;
+                       parse_arg_l(l, argv[++i]);
+                       if (p && last_option == p) {
+                               p->l = l;
+                               l->owner_p = p;
+                       }
+                       else if (c && last_option == c) {
+                               c->l = l;
+                               l->owner_c = c;
+                       }
+                       last_object = o;
+               } else if (!strncmp(argv[i] + 1, "w", 1)) {
+                       TDM_GOTO_IF_FAIL(data->do_all == 0, all);
+                       if (!last_object)
+                               goto no_object;
+                       w = calloc(1, sizeof * w);
+                       TDM_EXIT_IF_FAIL(w != NULL);
+                       if (o && last_object == o)
+                               LIST_ADDTAIL(&w->link, &o->prop_list);
+                       else if (l && last_object == l)
+                               LIST_ADDTAIL(&w->link, &l->prop_list);
+                       parse_arg_w(w, argv[++i]);
+               } else if (!strncmp(argv[i] + 1, "b", 1)) {
+                       parse_arg_b(data, argv[++i]);
+               } else if (!strncmp(argv[i] + 1, "v", 1)) {
+                       data->do_vblank = 1;
+               } else {
+                       usage(argv[0]);
+                       exit(0);
+               }
+       }
+       return;
+no_output:
+       printf("Use '-o' to set a output first.\n");
+       exit(0);
+no_object:
+       printf("Use '-o' or '-l' or '-p' or '-c' to set a object first.\n");
+       exit(0);
+all:
+       printf("Can't use '-%s' with '-a'.\n", argv[i] + 1);
+       exit(0);
+}
+
+static void
+interpret_args(tdm_test_server *data)
+{
+       tdm_test_server_output *o = NULL;
+       tdm_test_server_layer *l = NULL;
+       tdm_error ret;
+
+       if (data->do_all) {
+               int i, output_count;
+
+               ret = tdm_display_get_output_count(data->display, &output_count);
+               TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
+
+               for (i = 0; i < output_count; i++) {
+                       tdm_output *output;
+                       int j, layer_count;
+
+                       o = calloc(1, sizeof * o);
+                       TDM_EXIT_IF_FAIL(o != NULL);
+                       o->data = data;
+                       LIST_INITHEAD(&o->layer_list);
+                       LIST_INITHEAD(&o->prop_list);
+                       LIST_ADDTAIL(&o->link, &data->output_list);
+                       o->idx = i;
+
+                       output = tdm_display_get_output(data->display, i, &ret);
+                       TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
+                       ret = tdm_output_get_layer_count(output, &layer_count);
+                       TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
+
+                       for (j = 0; j < layer_count; j++) {
+                               tdm_layer *layer;
+                               tdm_layer_capability capabilities;
+
+                               l = calloc(1, sizeof * l);
+                               TDM_EXIT_IF_FAIL(l != NULL);
+                               LIST_INITHEAD(&l->prop_list);
+                               LIST_ADDTAIL(&l->link, &o->layer_list);
+                               l->o = o;
+                               l->idx = j;
+
+                               layer = tdm_output_get_layer(output, j, &ret);
+                               TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
+                               ret = tdm_layer_get_capabilities(layer, &capabilities);
+                               TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
+
+                               if (capabilities & TDM_LAYER_CAPABILITY_PRIMARY)
+                                       l->is_primary = 1;
+                       }
+               }
+       }
+
+       /* fill layer information */
+       LIST_FOR_EACH_ENTRY(o, &data->output_list, link) {
+               tdm_output *output;
+               const tdm_output_mode *mode;
+               int minw, minh, maxw, maxh;
+               int layer_count, i = 1;
+
+               output_setup(o);
+
+               output = tdm_display_get_output(data->display, o->idx, &ret);
+               TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
+               ret = tdm_output_get_mode(output, &mode);
+               TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
+               ret = tdm_output_get_layer_count(output, &layer_count);
+               TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
+               ret = tdm_output_get_available_size(output, &minw, &minh, &maxw, &maxh, NULL);
+               TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
+
+               if (LIST_IS_EMPTY(&o->layer_list)) {
+                       ret = tdm_output_get_layer_count(output, &layer_count);
+                       TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
+
+                       for (i = 0; i < layer_count; i++) {
+                               tdm_layer *layer;
+                               tdm_layer_capability capabilities;
+
+                               layer = tdm_output_get_layer(output, i, &ret);
+                               TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
+                               ret = tdm_layer_get_capabilities(layer, &capabilities);
+                               TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
+
+                               if (!(capabilities & TDM_LAYER_CAPABILITY_PRIMARY))
+                                       continue;
+
+                               l = calloc(1, sizeof * l);
+                               TDM_EXIT_IF_FAIL(l != NULL);
+                               LIST_INITHEAD(&l->prop_list);
+                               LIST_ADDTAIL(&l->link, &o->layer_list);
+                               l->o = o;
+                               l->idx = i;
+                               l->is_primary = 1;
+                               l->info.src_config.pos.w = l->info.src_config.size.h = mode->hdisplay;
+                               l->info.src_config.pos.h = l->info.src_config.size.v = mode->vdisplay;
+                               l->info.dst_pos = l->info.src_config.pos;
+                       }
+               } else {
+                       LIST_FOR_EACH_ENTRY(l, &o->layer_list, link) {
+                               if (l->info.dst_pos.w == 0) {
+                                       TDM_EXIT_IF_FAIL(!l->owner_p && !l->owner_c);
+                                       if (l->is_primary) {
+                                               l->info.dst_pos.w = mode->hdisplay;
+                                               l->info.dst_pos.h = mode->vdisplay;
+                                       } else {
+                                               l->info.dst_pos.w = TDM_ALIGN(mode->hdisplay / 3, 2);
+                                               l->info.dst_pos.h = TDM_ALIGN(mode->vdisplay / 3, 2);
+                                               l->info.dst_pos.x = TDM_ALIGN(((mode->hdisplay / 3) / layer_count) * i, 2);
+                                               l->info.dst_pos.y = TDM_ALIGN(((mode->vdisplay / 3) / layer_count) * i, 2);
+                                               i++;
+                                       }
+                               }
+                               if (minw > 0 && minh > 0) {
+                                       TDM_EXIT_IF_FAIL(l->info.dst_pos.w >= minw);
+                                       TDM_EXIT_IF_FAIL(l->info.dst_pos.h >= minh);
+                               }
+                               if (maxw > 0 && maxh > 0) {
+                                       TDM_EXIT_IF_FAIL(l->info.dst_pos.w <= maxw);
+                                       TDM_EXIT_IF_FAIL(l->info.dst_pos.h <= maxh);
+                               }
+                               if (l->owner_p) {
+                                       l->info.src_config = l->owner_p->info.dst_config;
+                               } else if (l->owner_c) {
+                                       l->info.src_config = l->owner_c->info.dst_config;
+                               } else {
+                                       if (l->info.src_config.pos.w == 0) {
+                                               l->info.src_config.pos.w = l->info.dst_pos.w;
+                                               l->info.src_config.pos.h = l->info.dst_pos.h;
+                                       }
+                               }
+                       }
+               }
+       }
+}
+
+static void
+print_args(tdm_test_server *data)
+{
+       tdm_test_server_output *o = NULL;
+       tdm_test_server_layer *l = NULL;
+       tdm_test_server_pp *p = NULL;
+       tdm_test_server_capture *c = NULL;
+       tdm_test_server_prop *w = NULL;
+
+       if (data->do_query) {
+               printf("query\n");
+               return;
+       }
+       LIST_FOR_EACH_ENTRY(o, &data->output_list, link) {
+               printf("output %d: %s", o->idx, o->mode);
+               if (o->refresh > 0)
+                       printf(" %d\n", o->refresh);
+               else
+                       printf("\n");
+               if (!LIST_IS_EMPTY(&o->prop_list)) {
+                       printf("\tprops: ");
+                       LIST_FOR_EACH_ENTRY(w, &o->prop_list, link) {
+                               print_prop(w);
+                               printf(" ");
+                       }
+                       printf("\n");
+               }
+               LIST_FOR_EACH_ENTRY(l, &o->layer_list, link) {
+                       printf("\t");
+                       printf("layer %d: ", l->idx);
+                       print_config(&l->info.src_config);
+                       printf(" ! ");
+                       print_pos(&l->info.dst_pos);
+                       printf(" trans(%d)\n", l->info.transform);
+                       if (!LIST_IS_EMPTY(&l->prop_list)) {
+                               printf("\t\tprops: ");
+                               LIST_FOR_EACH_ENTRY(w, &l->prop_list, link) {
+                                       print_prop(w);
+                                       printf(" ");
+                               }
+                               printf("\n");
+                       }
+               }
+       }
+       LIST_FOR_EACH_ENTRY(p, &data->pp_list, link) {
+               printf("pp: ");
+               print_config(&p->info.src_config);
+               printf(" ! ");
+               print_config(&p->info.dst_config);
+               printf(" fps(%d) trans(%d)\n", p->fps, p->info.transform);
+               if (p->l)
+                       printf("\toutput_idx(%d) layer_idx(%d)\n", p->l->o->idx, p->l->idx);
+       }
+       LIST_FOR_EACH_ENTRY(c, &data->capture_list, link) {
+               printf("capture: o(%d) l(%d) ", c->output_idx, c->layer_idx);
+               print_config(&c->info.dst_config);
+               printf(" trans(%d)\n", c->info.transform);
+               if (c->l)
+                       printf("\toutput_idx(%d) layer_idx(%d)\n", c->l->o->idx, c->l->idx);
+       }
+       if (data->bflags != 0) {
+               printf("buffer: ");
+               char temp[256];
+               char *p = temp;
+               int len = sizeof temp;
+               tdm_buf_flag_str(data->bflags, &p, &len);
+               printf(" (%s)\n", temp);
+       }
+}
+
+static tdm_test_server tts_data;
+
+static void
+exit_test(int sig)
+{
+       tdm_test_server *data = &tts_data;
+       tdm_test_server_output *o = NULL, *oo = NULL;
+       tdm_test_server_layer *l = NULL, *ll = NULL;
+       tdm_test_server_pp *p = NULL, *pp = NULL;
+       tdm_test_server_capture *c = NULL, *cc = NULL;
+       tdm_test_server_prop *w = NULL, *ww = NULL;
+       int i;
+
+       printf("got signal: %d\n", sig);
+
+       LIST_FOR_EACH_ENTRY_SAFE(o, oo, &data->output_list, link) {
+               LIST_DEL(&o->link);
+
+               LIST_FOR_EACH_ENTRY_SAFE(l, ll, &o->layer_list, link) {
+                       LIST_DEL(&l->link);
+
+                       tdm_layer_unset_buffer(l->layer);
+
+                       LIST_FOR_EACH_ENTRY_SAFE(w, ww, &l->prop_list, link) {
+                               LIST_DEL(&w->link);
+                               free(w);
+                       }
+                       for (i = 0; i < TDM_ARRAY_SIZE(l->bufs); i++) {
+                               tbm_surface_destroy(l->bufs[i]->buffer);
+                               free(l->bufs[i]);
+                       }
+                       free(l);
+               }
+
+               tdm_output_commit(o->output, 0, NULL, NULL);
+
+               LIST_FOR_EACH_ENTRY_SAFE(w, ww, &o->prop_list, link) {
+                       LIST_DEL(&w->link);
+                       free(w);
+               }
+
+               free(o);
+       }
+
+
+       LIST_FOR_EACH_ENTRY_SAFE(p, pp, &data->pp_list, link) {
+               LIST_DEL(&p->link);
+
+               tdm_display_lock(data->display);
+               tdm_event_loop_source_remove(p->timer_source);
+               tdm_display_unlock(data->display);
+
+               tdm_pp_destroy(p->pp);
+               for (i = 0; i < TDM_ARRAY_SIZE(p->bufs); i++) {
+                       tbm_surface_destroy(p->bufs[i]->buffer);
+                       free(p->bufs[i]);
+               }
+               free(p);
+       }
+
+       LIST_FOR_EACH_ENTRY_SAFE(c, cc, &data->capture_list, link) {
+               LIST_DEL(&c->link);
+               tdm_capture_destroy(c->capture);
+               free(c);
+       }
+
+       if (data->display)
+               tdm_display_deinit(data->display);
+
+       exit(0);
+}
+
+int
+main(int argc, char *argv[])
+{
+       tdm_test_server *data = &tts_data;
+       char temp[TDM_SERVER_REPLY_MSG_LEN];
+       int len = sizeof temp;
+       tdm_error ret;
+
+       signal(SIGINT, exit_test);    /* 2 */
+       signal(SIGSEGV, exit_test);   /* 11 */
+       signal(SIGTERM, exit_test);   /* 15 */
+
+       memset(data, 0, sizeof * data);
+       LIST_INITHEAD(&data->output_list);
+       LIST_INITHEAD(&data->pp_list);
+       LIST_INITHEAD(&data->capture_list);
+
+       /* init value */
+       data->bflags = TBM_BO_SCANOUT;
+       data->b_fill = PATTERN_SMPTE;
+
+       data->display = tdm_display_init(&ret);
+       TDM_EXIT_IF_FAIL(data->display != NULL);
+
+       parse_args(data, argc, argv);
+       interpret_args(data);
+       print_args(data);
+
+       if (data->do_query) {
+               tdm_helper_get_display_information(data->display, temp, &len);
+               printf("%s", temp);
+               goto done;
+       }
+
+       run_test(data);
+
+done:
+       tdm_display_deinit(data->display);
+
+       return 0;
+}
+
+static void
+output_setup(tdm_test_server_output *o)
+{
+       tdm_test_server *data = o->data;
+       const tdm_output_mode *modes, *found = NULL, *best = NULL, *prefer = NULL;
+       tdm_test_server_prop *w = NULL;
+       const tdm_prop *props;
+       int i, count;
+       tdm_error ret;
+
+       o->output = tdm_display_get_output(data->display, o->idx, &ret);
+       TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
+
+       ret = tdm_output_get_available_modes(o->output, &modes, &count);
+       TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
+
+       for (i = 0; i < count; i++) {
+               if (!strncmp(o->mode, modes[i].name, TDM_NAME_LEN) && o->refresh == modes[i].vrefresh) {
+                       found = &modes[i];
+                       printf("found mode: %dx%d %d\n", found->hdisplay, found->vdisplay, found->vrefresh);
+                       break;
+               }
+               if (!best)
+                       best = &modes[i];
+               if (modes[i].flags & TDM_OUTPUT_MODE_TYPE_PREFERRED)
+                       prefer = &modes[i];
+       }
+       if (!found && prefer) {
+               found = prefer;
+               printf("found prefer mode: %dx%d %d\n", found->hdisplay, found->vdisplay, found->vrefresh);
+       }
+       if (!found && best) {
+               found = best;
+               printf("found best mode: %dx%d %d\n", found->hdisplay, found->vdisplay, found->vrefresh);
+       }
+
+       if (!found) {
+               printf("couldn't find any mode\n");
+               exit(0);
+       }
+
+       ret = tdm_output_set_mode(o->output, found);
+       TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
+
+       ret = tdm_output_get_available_properties(o->output, &props, &count);
+       TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
+
+       LIST_FOR_EACH_ENTRY(w, &o->prop_list, link) {
+               for (i = 0; i < count; i++) {
+                       if (strncmp(w->name, props[i].name, TDM_NAME_LEN))
+                               continue;
+                       ret = tdm_output_set_property(o->output, props[i].id, w->value);
+                       TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
+                       break;
+               }
+       }
+
+       /* DPMS on forcely at the first time. */
+       ret = tdm_output_set_dpms(o->output, TDM_OUTPUT_DPMS_ON);
+       TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
+}
+
+static tdm_test_server_buffer*
+layer_get_buffer(tdm_test_server_layer *l)
+{
+       int i, size = TDM_ARRAY_SIZE(l->bufs);
+       if (!l->bufs[0]) {
+               for (i = 0; i < size; i++) {
+                       int width = (l->info.src_config.size.h)?:l->info.src_config.pos.w;
+                       int height = (l->info.src_config.size.v)?:l->info.src_config.pos.h;
+                       unsigned int format = (l->info.src_config.format)?:TBM_FORMAT_ARGB8888;
+                       int flags = l->o->data->bflags;
+                       tdm_test_server_buffer *b = calloc(1, sizeof *b);
+                       TDM_EXIT_IF_FAIL(b != NULL);
+                       b->buffer = tbm_surface_internal_create_with_flags(width, height, format, flags);
+                       TDM_EXIT_IF_FAIL(b->buffer != NULL);
+                       l->bufs[i] = b;
+               }
+       }
+       for (i = 0; i < size; i++) {
+               if (!l->bufs[i]->in_use) {
+                       tdm_test_buffer_fill(l->bufs[i]->buffer, l->data->b_fill);
+                       return l->bufs[i];
+               }
+       }
+       printf("no available layer buffer.\n");
+       exit(0);
+}
+
+static void
+layer_cb_commit(tdm_output *output, unsigned int sequence,
+                               unsigned int tv_sec, unsigned int tv_usec,
+                               void *user_data)
+{
+       tdm_test_server_layer *l = user_data;
+       tdm_test_server_buffer *b = layer_get_buffer(l);
+
+       TDM_EXIT_IF_FAIL(b != NULL);
+       layer_show_buffer(l, b);
+}
+
+static void
+layer_cb_buffer_release(tbm_surface_h buffer, void *user_data)
+{
+       tdm_test_server_buffer *b = user_data;
+       b->in_use = 0;
+       tdm_buffer_remove_release_handler(b->buffer, layer_cb_buffer_release, b);
+       if (b->done)
+               b->done(buffer, user_data);
+}
+
+static void
+layer_show_buffer(tdm_test_server_layer *l, tdm_test_server_buffer *b)
+{
+       tdm_test_server *data = l->o->data;
+       tdm_error ret;
+
+       ret = tdm_layer_set_buffer(l->layer, b->buffer);
+       TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
+
+       b->in_use = 1;
+       tdm_buffer_add_release_handler(b->buffer, layer_cb_buffer_release, b);
+
+       if (data->do_vblank)
+               ret = tdm_output_commit(l->o->output, 0, layer_cb_commit, l);
+       else
+               ret = tdm_output_commit(l->o->output, 0, NULL, NULL);
+       TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
+
+       printf("show:\tl(%p) b(%p)\n", l, b);
+}
+
+static void
+layer_setup(tdm_test_server_layer *l, tdm_test_server_buffer *b)
+{
+       tdm_test_server_prop *w = NULL;
+       const tdm_prop *props;
+       int i, count;
+       tdm_error ret;
+       tbm_surface_info_s info;
+
+       l->layer = tdm_output_get_layer(l->o->output, l->idx, &ret);
+       TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
+
+       /* The size and format information should be same with buffer's */
+       tbm_surface_get_info(b->buffer, &info);
+       if (IS_RGB(info.format)) {
+               l->info.src_config.size.h = info.planes[0].stride >> 2;
+               l->info.src_config.size.v = info.height;
+       } else {
+               l->info.src_config.size.h = info.planes[0].stride;
+               l->info.src_config.size.v = info.height;
+       }
+       l->info.src_config.format = info.format;
+
+       ret = tdm_layer_set_info(l->layer, &l->info);
+       TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
+
+       ret = tdm_layer_get_available_properties(l->layer, &props, &count);
+       TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
+
+       LIST_FOR_EACH_ENTRY(w, &l->prop_list, link) {
+               for (i = 0; i < count; i++) {
+                       if (strncmp(w->name, props[i].name, TDM_NAME_LEN))
+                               continue;
+                       ret = tdm_layer_set_property(l->layer, props[i].id, w->value);
+                       TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
+                       break;
+               }
+       }
+}
+
+static tdm_test_server_buffer*
+pp_get_buffer(tdm_test_server_pp *p)
+{
+       int i, size = TDM_ARRAY_SIZE(p->bufs);
+       if (!p->bufs[0]) {
+               for (i = 0; i < size; i++) {
+                       int width = (p->info.src_config.size.h)?:p->info.src_config.pos.w;
+                       int height = (p->info.src_config.size.v)?:p->info.src_config.pos.h;
+                       unsigned int format = (p->info.src_config.format)?:TBM_FORMAT_ARGB8888;
+                       int flags = p->l->o->data->bflags;
+                       tdm_test_server_buffer *b = calloc(1, sizeof *b);
+                       TDM_EXIT_IF_FAIL(b != NULL);
+                       b->buffer = tbm_surface_internal_create_with_flags(width, height, format, flags);
+                       TDM_EXIT_IF_FAIL(b->buffer != NULL);
+                       p->bufs[i] = b;
+               }
+       }
+       for (i = 0; i < size; i++) {
+               if (!p->bufs[i]->in_use) {
+                       tdm_test_buffer_fill(p->bufs[i]->buffer, p->data->b_fill);
+                       return p->bufs[i];
+               }
+       }
+       printf("no available pp buffer.\n");
+       exit(0);
+}
+
+static void
+pp_cb_sb_release(tbm_surface_h buffer, void *user_data)
+{
+       tdm_test_server_buffer *b = user_data;
+       b->in_use = 0;
+       tdm_buffer_remove_release_handler(b->buffer, pp_cb_sb_release, b);
+}
+
+static void
+pp_cb_db_release(tbm_surface_h buffer, void *user_data)
+{
+       tdm_test_server_buffer *b = user_data;
+       b->in_use = 0;
+       tdm_buffer_remove_release_handler(b->buffer, pp_cb_db_release, b);
+       layer_show_buffer(b->l, b);
+}
+
+static void
+pp_convert_buffer(tdm_test_server_pp *p, tdm_test_server_buffer *sb, tdm_test_server_buffer *db)
+{
+       tdm_error ret;
+
+       ret = tdm_pp_attach(p->pp, sb->buffer, db->buffer);
+       TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
+
+       sb->in_use = db->in_use = 1;
+       db->l = p->l;
+       tdm_buffer_add_release_handler(sb->buffer, pp_cb_sb_release, sb);
+       tdm_buffer_add_release_handler(db->buffer, pp_cb_db_release, db);
+
+       ret = tdm_pp_commit(p->pp);
+       TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
+
+       printf("convt:\tp(%p) sb(%p) db(%p)\n", p, sb, db);
+}
+
+/* tdm_event_loop_xxx() function is not for the display server. It's for TDM
+ * backend module. I use them only for simulating the video play. When we call
+ * tdm_event_loop_xxx() outside of TDM backend module, we have to lock/unlock
+ * the TDM display. And when the callback function of tdm_event_loop_xxx() is
+ * called, the display has been already locked. So in this test application,
+ * we have to unlock/lock the display for testing.
+ */
+static tdm_error
+pp_cb_timeout(void *user_data)
+{
+       tdm_test_server_pp *p = user_data;
+       tdm_test_server *data = p->l->o->data;
+       tdm_test_server_buffer *sb, *db;
+       tdm_error ret;
+
+       tdm_display_unlock(data->display);
+
+       sb = pp_get_buffer(p);
+       TDM_EXIT_IF_FAIL(sb != NULL);
+       db = layer_get_buffer(p->l);
+       TDM_EXIT_IF_FAIL(db != NULL);
+
+       pp_convert_buffer(p, sb, db);
+
+       tdm_display_lock(data->display);
+       ret = tdm_event_loop_source_timer_update(p->timer_source, 1000 / p->fps);
+       tdm_display_unlock(data->display);
+       TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
+
+       tdm_display_lock(data->display);
+
+       return TDM_ERROR_NONE;
+}
+
+static void
+pp_setup(tdm_test_server_pp *p, tdm_test_server_buffer *sb, tdm_test_server_buffer *db)
+{
+       tdm_test_server *data = p->l->o->data;
+       tbm_surface_info_s info;
+       tdm_error ret;
+
+       p->pp = tdm_display_create_pp(data->display, &ret);
+       TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
+
+       /* The size and format information should be same with buffer's */
+       tbm_surface_get_info(sb->buffer, &info);
+       if (IS_RGB(info.format)) {
+               p->info.src_config.size.h = info.planes[0].stride >> 2;
+               p->info.src_config.size.v = info.height;
+       } else {
+               p->info.src_config.size.h = info.planes[0].stride;
+               p->info.src_config.size.v = info.height;
+       }
+       p->info.src_config.format = info.format;
+
+       /* The size and format information should be same with buffer's */
+       tbm_surface_get_info(db->buffer, &info);
+       if (IS_RGB(info.format)) {
+               p->info.dst_config.size.h = info.planes[0].stride >> 2;
+               p->info.dst_config.size.v = info.height;
+       } else {
+               p->info.dst_config.size.h = info.planes[0].stride;
+               p->info.dst_config.size.v = info.height;
+       }
+       p->info.dst_config.format = info.format;
+
+       ret = tdm_pp_set_info(p->pp, &p->info);
+       TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
+
+       layer_setup(p->l, db);
+
+       /* tdm_event_loop_xxx() function is not for the display server. It's for TDM
+        * backend module. I use them only for simulating the video play. When we call
+        * tdm_event_loop_xxx() outside of TDM backend module, we have to lock/unlock
+        * the TDM display. And when the callback function of tdm_event_loop_xxx() is
+        * called, the display has been already locked. So in this test application,
+        * we have to unlock/lock the display for testing.
+        */
+       tdm_display_lock(data->display);
+       p->timer_source = tdm_event_loop_add_timer_handler(data->display, pp_cb_timeout, p, &ret);
+       tdm_display_unlock(data->display);
+       TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
+
+       tdm_display_lock(data->display);
+       ret = tdm_event_loop_source_timer_update(p->timer_source, 1000 / p->fps);
+       tdm_display_unlock(data->display);
+       TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
+}
+
+static void
+capture_cb_buffer_done(tbm_surface_h buffer, void *user_data)
+{
+       tdm_test_server_buffer *b = user_data;
+       capture_attach(b->c, b);
+}
+
+static void
+capture_cb_buffer_release(tbm_surface_h buffer, void *user_data)
+{
+       tdm_test_server_buffer *b = user_data;
+       b->in_use = 0;
+       tdm_buffer_remove_release_handler(b->buffer, capture_cb_buffer_release, b);
+       b->done = capture_cb_buffer_done;
+       layer_show_buffer(b->l, b);
+}
+
+static void
+capture_attach(tdm_test_server_capture *c, tdm_test_server_buffer *b)
+{
+       tdm_error ret;
+
+       ret = tdm_capture_attach(c->capture, b->buffer);
+       TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
+
+       b->in_use = 1;
+       b->l = c->l;
+       b->c = c;
+       tdm_buffer_add_release_handler(b->buffer, capture_cb_buffer_release, b);
+       printf("capture:\tc(%p) b(%p)\n", c, b);
+
+       ret = tdm_capture_commit(c->capture);
+       TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
+}
+
+static void
+capture_setup(tdm_test_server_capture *c, tdm_test_server_buffer *b)
+{
+       tdm_test_server *data = c->l->o->data;
+       tdm_output *output;
+       tdm_layer *layer;
+       tbm_surface_info_s info;
+       tdm_error ret;
+
+       if (c->output_idx != -1 && c->layer_idx == -1) {
+               output = tdm_display_get_output(data->display, c->output_idx, &ret);
+               TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
+               c->capture = tdm_output_create_capture(output, &ret);
+               TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
+       } else if (c->output_idx != -1 && c->layer_idx != -1) {
+               output = tdm_display_get_output(data->display, c->output_idx, &ret);
+               TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
+               layer = tdm_output_get_layer(output, c->layer_idx, &ret);
+               TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
+               c->capture = tdm_layer_create_capture(layer, &ret);
+               TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
+       }
+
+       TDM_EXIT_IF_FAIL(c->capture != NULL);
+
+       /* The size and format information should be same with buffer's */
+       tbm_surface_get_info(b->buffer, &info);
+       if (IS_RGB(info.format)) {
+               c->info.dst_config.size.h = info.planes[0].stride >> 2;
+               c->info.dst_config.size.v = info.height;
+       } else {
+               c->info.dst_config.size.h = info.planes[0].stride;
+               c->info.dst_config.size.v = info.height;
+       }
+       c->info.dst_config.format = info.format;
+
+       ret = tdm_capture_set_info(c->capture, &c->info);
+       TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
+
+       layer_setup(c->l, b);
+}
+
+static void
+run_test(tdm_test_server *data)
+{
+       tdm_test_server_output *o = NULL;
+       tdm_test_server_layer *l = NULL;
+       tdm_test_server_pp *p = NULL;
+       tdm_test_server_capture *c = NULL;
+       tdm_display_capability caps;
+       tdm_error ret;
+
+       ret = tdm_display_get_capabilities(data->display, &caps);
+       TDM_EXIT_IF_FAIL(ret == TDM_ERROR_NONE);
+
+       LIST_FOR_EACH_ENTRY(o, &data->output_list, link) {
+               LIST_FOR_EACH_ENTRY(l, &o->layer_list, link) {
+                       if (!l->owner_p && !l->owner_c) {
+                               tdm_test_server_buffer *b;
+                               b = layer_get_buffer(l);
+                               layer_setup(l, b);
+                               layer_show_buffer(l, b);
+                       }
+               }
+       }
+
+       LIST_FOR_EACH_ENTRY(p, &data->pp_list, link) {
+               tdm_test_server_buffer *sb, *db;
+               TDM_GOTO_IF_FAIL(caps & TDM_DISPLAY_CAPABILITY_PP, no_pp);
+               sb = pp_get_buffer(p);
+               TDM_EXIT_IF_FAIL(sb != NULL);
+               db = layer_get_buffer(p->l);
+               TDM_EXIT_IF_FAIL(db != NULL);
+               pp_setup(p, sb, db);
+               pp_convert_buffer(p, sb, db);
+       }
+
+       LIST_FOR_EACH_ENTRY(c, &data->capture_list, link) {
+               TDM_GOTO_IF_FAIL(caps & TDM_DISPLAY_CAPABILITY_CAPTURE, no_capture);
+               tdm_test_server_buffer *b;
+               b = layer_get_buffer(c->l);
+               capture_setup(c, b);
+               capture_attach(c, b);
+               b = layer_get_buffer(c->l);
+               capture_attach(c, b);
+               b = layer_get_buffer(c->l);
+               capture_attach(c, b);
+       }
+
+       printf("enter test loop\n");
+
+       while (1)
+               tdm_display_handle_events(data->display);
+
+       return;
+no_pp:
+       printf("no PP capability\n");
+       exit(0);
+no_capture:
+       printf("no Capture capability\n");
+       exit(0);
+}