+##########################################################################
+### tdm-client library
+##########################################################################
libtdm_clientincludedir = ${includedir}
libtdm_clientinclude_HEADERS = \
tdm_client.h \
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
{
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);
--- /dev/null
+/**************************************************************************
+ *
+ * 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;
+}
#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;
_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")))
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
_tdm_log_check_env();
}
- if (level > 3 && !debug_enable)
+ if (level > debug_level)
return;
if (dlog_enable) {
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.
#endif
#define TDM_NAME_LEN 64
+#define TDM_PATH_LEN 1024
/**
* @file tdm_common.h
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
*/
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.
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
*/
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
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...) \
#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),
%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
%files tools
%manifest %{name}.manifest
+%{_bindir}/tdm-test-server
%{_bindir}/tdm-test-client
%changelog
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">
tdm_display.c \
tdm_pp.c \
tdm_capture.c \
+ tdm_dbg_server.c \
tdm.c
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;
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;
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;
}
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;
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;
+}
#include "tdm.h"
#include "tdm_backend.h"
#include "tdm_private.h"
+#include "tdm_helper.h"
#define CAPTURE_FUNC_ENTRY() \
tdm_func_capture *func_capture; \
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);
--- /dev/null
+/**************************************************************************
+ *
+ * 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);
+}
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)
{
_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)
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) {
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);
#define PNG_DEPTH 8
-static const char *dump_prefix[2] = {"png", "yuv"};
+static const char *file_exts[2] = {"png", "yuv"};
int tdm_dump_enable;
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);
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;
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");
+ }
+}
#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
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 **")
} \
} 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]))
{ TDM_OUTPUT_DPMS_SUSPEND, "suspend" },
{ TDM_OUTPUT_DPMS_OFF, "off" },
};
-
TDM_TYPE_NAME_FN(dpms)
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
#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;
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);
}
}
+ 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);
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>
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;
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
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
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
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
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) \
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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
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 {
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)
{
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);
//"<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);
}
}
}
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();
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",
--- /dev/null
+/**************************************************************************
+ *
+ * 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);
+}